Compare commits
2 commits
dev
...
fix/v2-hea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d79daa2ca | ||
|
|
8bb211ebfd |
13 changed files with 240 additions and 89 deletions
|
|
@ -111,6 +111,9 @@ export class LocationServiceMap extends LayerMap.Service<LocationServiceMap>()("
|
||||||
LLMClient.layer.pipe(Layer.provide(RequestExecutor.defaultLayer)),
|
LLMClient.layer.pipe(Layer.provide(RequestExecutor.defaultLayer)),
|
||||||
FetchHttpClient.layer,
|
FetchHttpClient.layer,
|
||||||
ToolOutputStore.defaultCleanupLayer,
|
ToolOutputStore.defaultCleanupLayer,
|
||||||
ApplicationTools.layer,
|
|
||||||
],
|
],
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
|
export namespace LocationServiceMap {
|
||||||
|
export const defaultLayer = LocationServiceMap.layer.pipe(Layer.provide(ApplicationTools.layer))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,11 @@ import { ApplicationTools } from "../tool/application-tools"
|
||||||
import { Session } from "./session"
|
import { Session } from "./session"
|
||||||
import { Tool } from "./tool"
|
import { Tool } from "./tool"
|
||||||
|
|
||||||
|
export interface HostConfig {
|
||||||
|
/** Tool names that this host cannot service. They are omitted from prompts and rejected at execution. */
|
||||||
|
readonly unavailableTools?: ReadonlyArray<string>
|
||||||
|
}
|
||||||
|
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
readonly sessions: Session.Interface
|
readonly sessions: Session.Interface
|
||||||
readonly tools: Tool.Service
|
readonly tools: Tool.Service
|
||||||
|
|
@ -32,7 +37,6 @@ class SessionModelValidation extends Context.Service<
|
||||||
}
|
}
|
||||||
>()("@opencode/public/OpenCode/SessionModelValidation") {}
|
>()("@opencode/public/OpenCode/SessionModelValidation") {}
|
||||||
|
|
||||||
const LocationServicesLayer = LocationServiceMap.layer
|
|
||||||
const SessionModelValidationLayer = Layer.effect(
|
const SessionModelValidationLayer = Layer.effect(
|
||||||
SessionModelValidation,
|
SessionModelValidation,
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
|
|
@ -77,54 +81,59 @@ const SessionsLayer = Layer.merge(
|
||||||
Layer.orDie,
|
Layer.orDie,
|
||||||
),
|
),
|
||||||
SessionModelValidationLayer,
|
SessionModelValidationLayer,
|
||||||
).pipe(Layer.provide(LocationServicesLayer))
|
)
|
||||||
const ApplicationToolsLayer = ApplicationTools.layer
|
|
||||||
|
|
||||||
// TODO: Accept explicit storage so tests and embeddings can select disposable or application-owned persistence.
|
// TODO: Accept explicit storage so tests and embeddings can select disposable or application-owned persistence.
|
||||||
export const layer = Layer.effect(
|
export const layerWithHostConfig = (config: HostConfig) => {
|
||||||
Service,
|
const applicationTools = ApplicationTools.layerWithUnavailable(new Set(config.unavailableTools ?? []))
|
||||||
Effect.gen(function* () {
|
const locations = LocationServiceMap.layer.pipe(Layer.provide(applicationTools))
|
||||||
const sessions = yield* SessionV2.Service
|
const sessions = SessionsLayer.pipe(Layer.provide(locations))
|
||||||
const tools = yield* ApplicationTools.Service
|
return Layer.effect(
|
||||||
const validation = yield* SessionModelValidation
|
Service,
|
||||||
return Service.of({
|
Effect.gen(function* () {
|
||||||
tools: { attach: tools.attach },
|
const sessions = yield* SessionV2.Service
|
||||||
sessions: {
|
const tools = yield* ApplicationTools.Service
|
||||||
create: (input) =>
|
const validation = yield* SessionModelValidation
|
||||||
sessions.create({
|
return Service.of({
|
||||||
id: input.id,
|
tools: { attach: tools.attach },
|
||||||
agent: input.agent,
|
sessions: {
|
||||||
model: input.model,
|
create: (input) =>
|
||||||
location: input.location,
|
sessions.create({
|
||||||
|
id: input.id,
|
||||||
|
agent: input.agent,
|
||||||
|
model: input.model,
|
||||||
|
location: input.location,
|
||||||
|
}),
|
||||||
|
get: sessions.get,
|
||||||
|
list: sessions.list,
|
||||||
|
switchModel: Effect.fn("OpenCode.sessions.switchModel")(function* (input) {
|
||||||
|
const session = yield* sessions.get(input.sessionID)
|
||||||
|
yield* validation.validate({ ...input, location: session.location })
|
||||||
|
yield* sessions.switchModel(input)
|
||||||
}),
|
}),
|
||||||
get: sessions.get,
|
interrupt: sessions.interrupt,
|
||||||
list: sessions.list,
|
prompt: (input) =>
|
||||||
switchModel: Effect.fn("OpenCode.sessions.switchModel")(function* (input) {
|
sessions.prompt({
|
||||||
const session = yield* sessions.get(input.sessionID)
|
id: input.id,
|
||||||
yield* validation.validate({ ...input, location: session.location })
|
sessionID: input.sessionID,
|
||||||
yield* sessions.switchModel(input)
|
prompt: input.prompt,
|
||||||
}),
|
delivery: input.delivery,
|
||||||
interrupt: sessions.interrupt,
|
}),
|
||||||
prompt: (input) =>
|
messages: (input) =>
|
||||||
sessions.prompt({
|
sessions.messages({
|
||||||
id: input.id,
|
sessionID: input.sessionID,
|
||||||
sessionID: input.sessionID,
|
limit: input.limit,
|
||||||
prompt: input.prompt,
|
order: input.order,
|
||||||
delivery: input.delivery,
|
cursor: input.cursor,
|
||||||
}),
|
}),
|
||||||
messages: (input) =>
|
message: (input) => sessions.message({ sessionID: input.sessionID, messageID: input.messageID }),
|
||||||
sessions.messages({
|
context: sessions.context,
|
||||||
sessionID: input.sessionID,
|
events: (input) => sessions.events({ sessionID: input.sessionID, after: input.after }),
|
||||||
limit: input.limit,
|
},
|
||||||
order: input.order,
|
})
|
||||||
cursor: input.cursor,
|
}),
|
||||||
}),
|
).pipe(Layer.provide(Layer.merge(applicationTools, sessions)))
|
||||||
message: (input) => sessions.message({ sessionID: input.sessionID, messageID: input.messageID }),
|
}
|
||||||
context: sessions.context,
|
|
||||||
events: (input) => sessions.events({ sessionID: input.sessionID, after: input.after }),
|
export const layer = layerWithHostConfig({})
|
||||||
},
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
).pipe(Layer.provide(Layer.merge(ApplicationToolsLayer, SessionsLayer)))
|
|
||||||
|
|
||||||
// TODO: Add OpenCode.create(...) as the Promise facade over the same native API semantics.
|
// TODO: Add OpenCode.create(...) as the Promise facade over the same native API semantics.
|
||||||
|
|
|
||||||
|
|
@ -16,36 +16,41 @@ type Editor = {
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
readonly attach: (tools: Readonly<Record<string, NativeTool.Any>>) => Effect.Effect<void, never, Scope.Scope>
|
readonly attach: (tools: Readonly<Record<string, NativeTool.Any>>) => Effect.Effect<void, never, Scope.Scope>
|
||||||
readonly entries: () => ReadonlyMap<string, NativeTool.Any>
|
readonly entries: () => ReadonlyMap<string, NativeTool.Any>
|
||||||
|
readonly isAvailable: (name: string) => boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Service extends Context.Service<Service, Interface>()("@opencode/ApplicationTools") {}
|
export class Service extends Context.Service<Service, Interface>()("@opencode/ApplicationTools") {}
|
||||||
|
|
||||||
enableMapSet()
|
enableMapSet()
|
||||||
|
|
||||||
export const layer = Layer.effect(
|
export const layerWithUnavailable = (unavailable: ReadonlySet<string>) =>
|
||||||
Service,
|
Layer.effect(
|
||||||
Effect.gen(function* () {
|
Service,
|
||||||
const state = State.create<Data, Editor>({
|
Effect.gen(function* () {
|
||||||
initial: () => ({ entries: new Map() }),
|
const state = State.create<Data, Editor>({
|
||||||
editor: (draft) => ({
|
initial: () => ({ entries: new Map() }),
|
||||||
set: (name, tool) => {
|
editor: (draft) => ({
|
||||||
draft.entries.set(
|
set: (name, tool) => {
|
||||||
name,
|
draft.entries.set(
|
||||||
castDraft(tool) as typeof draft.entries extends Map<string, infer Value> ? Value : never,
|
name,
|
||||||
)
|
castDraft(tool) as typeof draft.entries extends Map<string, infer Value> ? Value : never,
|
||||||
},
|
)
|
||||||
}),
|
},
|
||||||
})
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
return Service.of({
|
return Service.of({
|
||||||
attach: Effect.fn("ApplicationTools.attach")(function* (tools) {
|
attach: Effect.fn("ApplicationTools.attach")(function* (tools) {
|
||||||
const entries = Object.entries(tools)
|
const entries = Object.entries(tools)
|
||||||
const transform = yield* state.transform()
|
const transform = yield* state.transform()
|
||||||
yield* transform((editor) => {
|
yield* transform((editor) => {
|
||||||
for (const [name, tool] of entries) editor.set(name, tool)
|
for (const [name, tool] of entries) editor.set(name, tool)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
entries: () => state.get().entries,
|
entries: () => state.get().entries,
|
||||||
})
|
isAvailable: (name) => !unavailable.has(name),
|
||||||
}),
|
})
|
||||||
)
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
export const layer = layerWithUnavailable(new Set())
|
||||||
|
|
|
||||||
|
|
@ -115,15 +115,20 @@ export const layer = Layer.effect(
|
||||||
})
|
})
|
||||||
|
|
||||||
const definitions = Effect.fn("ToolRegistry.definitions")(function* () {
|
const definitions = Effect.fn("ToolRegistry.definitions")(function* () {
|
||||||
const tools = new Map(Array.from(state.get().entries, ([name, entry]) => [name, entry.tool] as const))
|
const tools = new Map(
|
||||||
|
Array.from(state.get().entries, ([name, entry]) => [name, entry.tool] as const).filter(([name]) =>
|
||||||
|
applications.isAvailable(name),
|
||||||
|
),
|
||||||
|
)
|
||||||
// Location tools own their names. Application tools fill otherwise-unclaimed names.
|
// Location tools own their names. Application tools fill otherwise-unclaimed names.
|
||||||
for (const [name, tool] of applications.entries()) {
|
for (const [name, tool] of applications.entries()) {
|
||||||
if (!tools.has(name)) tools.set(name, tool.definition)
|
if (applications.isAvailable(name) && !tools.has(name)) tools.set(name, tool.definition)
|
||||||
}
|
}
|
||||||
return Tool.toDefinitions(Object.fromEntries(tools))
|
return Tool.toDefinitions(Object.fromEntries(tools))
|
||||||
})
|
})
|
||||||
|
|
||||||
const entry = (name: string): Entry | undefined => {
|
const entry = (name: string): Entry | undefined => {
|
||||||
|
if (!applications.isAvailable(name)) return
|
||||||
const local = state.get().entries.get(name)
|
const local = state.get().entries.get(name)
|
||||||
if (local !== undefined) return local
|
if (local !== undefined) return local
|
||||||
const tool = applications.entries().get(name)
|
const tool = applications.entries().get(name)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,13 @@ const registry = ToolRegistry.layer.pipe(
|
||||||
Layer.provide(ToolOutputStore.defaultLayer),
|
Layer.provide(ToolOutputStore.defaultLayer),
|
||||||
)
|
)
|
||||||
const it = testEffect(Layer.mergeAll(applications, registry))
|
const it = testEffect(Layer.mergeAll(applications, registry))
|
||||||
|
const unavailableApplications = ApplicationTools.layerWithUnavailable(new Set(["question"]))
|
||||||
|
const unavailableRegistry = ToolRegistry.layer.pipe(
|
||||||
|
Layer.provide(permission),
|
||||||
|
Layer.provide(unavailableApplications),
|
||||||
|
Layer.provide(ToolOutputStore.defaultLayer),
|
||||||
|
)
|
||||||
|
const unavailableIt = testEffect(Layer.mergeAll(unavailableApplications, unavailableRegistry))
|
||||||
|
|
||||||
const sessionID = SessionV2.ID.make("ses_application_tool")
|
const sessionID = SessionV2.ID.make("ses_application_tool")
|
||||||
const contextual = (contexts: Tool.Context[]) =>
|
const contextual = (contexts: Tool.Context[]) =>
|
||||||
|
|
@ -186,4 +193,20 @@ describe("ApplicationTools", () => {
|
||||||
expect(applicationContexts).toEqual([])
|
expect(applicationContexts).toEqual([])
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
unavailableIt.effect("omits and rejects tools the host cannot service", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const registry = yield* ToolRegistry.Service
|
||||||
|
const transform = yield* registry.transform()
|
||||||
|
yield* transform((editor) => editor.set("question", { tool: contextual([]).definition }))
|
||||||
|
|
||||||
|
expect(yield* registry.definitions()).toEqual([])
|
||||||
|
expect(
|
||||||
|
yield* registry.execute({
|
||||||
|
sessionID,
|
||||||
|
call: { type: "tool-call", id: "call-stale-question", name: "question", input: { query: "Continue?" } },
|
||||||
|
}),
|
||||||
|
).toEqual({ type: "error", value: "Unknown tool: question" })
|
||||||
|
}),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ const it = testEffect(
|
||||||
Layer.merge(
|
Layer.merge(
|
||||||
applicationTools,
|
applicationTools,
|
||||||
LocationServiceMap.layer.pipe(
|
LocationServiceMap.layer.pipe(
|
||||||
|
Layer.provide(applicationTools),
|
||||||
Layer.provide(
|
Layer.provide(
|
||||||
Layer.mergeAll(
|
Layer.mergeAll(
|
||||||
Project.defaultLayer,
|
Project.defaultLayer,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import {
|
||||||
LLMEvent,
|
LLMEvent,
|
||||||
Model,
|
Model,
|
||||||
Tool,
|
Tool,
|
||||||
|
ToolFailure,
|
||||||
TransportReason,
|
TransportReason,
|
||||||
InvalidRequestReason,
|
InvalidRequestReason,
|
||||||
type LLMClientShape,
|
type LLMClientShape,
|
||||||
|
|
@ -112,6 +113,7 @@ const recoveryModel = Model.make({
|
||||||
})
|
})
|
||||||
const authorizations: ToolRegistry.AuthorizeInput[] = []
|
const authorizations: ToolRegistry.AuthorizeInput[] = []
|
||||||
const executions: string[] = []
|
const executions: string[] = []
|
||||||
|
let denyEcho = false
|
||||||
const permission = Layer.succeed(
|
const permission = Layer.succeed(
|
||||||
PermissionV2.Service,
|
PermissionV2.Service,
|
||||||
PermissionV2.Service.of({
|
PermissionV2.Service.of({
|
||||||
|
|
@ -135,9 +137,18 @@ const echo = Layer.effectDiscard(
|
||||||
registry.contribute((editor) => {
|
registry.contribute((editor) => {
|
||||||
;(editor.set("echo", {
|
;(editor.set("echo", {
|
||||||
authorize: (input) =>
|
authorize: (input) =>
|
||||||
Effect.sync(() => {
|
denyEcho
|
||||||
authorizations.push(input)
|
? Effect.fail(
|
||||||
}),
|
new ToolFailure({
|
||||||
|
message: "Permission denied",
|
||||||
|
error: new PermissionV2.DeniedError({
|
||||||
|
rules: [{ action: "echo", resource: "*", effect: "deny" }],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
: Effect.sync(() => {
|
||||||
|
authorizations.push(input)
|
||||||
|
}),
|
||||||
tool: Tool.make({
|
tool: Tool.make({
|
||||||
description: "Echo text",
|
description: "Echo text",
|
||||||
parameters: Schema.Struct({ text: Schema.String }),
|
parameters: Schema.Struct({ text: Schema.String }),
|
||||||
|
|
@ -1809,6 +1820,100 @@ describe("SessionRunnerLLM", () => {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.effect("continues after a permission is denied without awaiting a responder", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
yield* setup
|
||||||
|
const session = yield* SessionV2.Service
|
||||||
|
yield* session.prompt({ sessionID, prompt: new Prompt({ text: "Try the denied tool" }), resume: false })
|
||||||
|
|
||||||
|
requests.length = 0
|
||||||
|
executions.length = 0
|
||||||
|
denyEcho = true
|
||||||
|
responses = [
|
||||||
|
[
|
||||||
|
LLMEvent.stepStart({ index: 0 }),
|
||||||
|
LLMEvent.toolCall({ id: "call-denied", name: "echo", input: { text: "blocked" } }),
|
||||||
|
LLMEvent.stepFinish({ index: 0, reason: "tool-calls" }),
|
||||||
|
LLMEvent.finish({ reason: "tool-calls" }),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
LLMEvent.stepStart({ index: 0 }),
|
||||||
|
LLMEvent.textStart({ id: "text-after-denial" }),
|
||||||
|
LLMEvent.textDelta({ id: "text-after-denial", text: "Permission denied" }),
|
||||||
|
LLMEvent.textEnd({ id: "text-after-denial" }),
|
||||||
|
LLMEvent.stepFinish({ index: 0, reason: "stop" }),
|
||||||
|
LLMEvent.finish({ reason: "stop" }),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
yield* session.resume(sessionID).pipe(Effect.ensuring(Effect.sync(() => (denyEcho = false))))
|
||||||
|
|
||||||
|
expect(requests).toHaveLength(2)
|
||||||
|
expect(requests[1]?.messages.map((message) => message.role)).toEqual(["user", "assistant", "tool"])
|
||||||
|
expect(executions).toEqual([])
|
||||||
|
expect(yield* session.context(sessionID)).toMatchObject([
|
||||||
|
{ type: "user", text: "Try the denied tool" },
|
||||||
|
{
|
||||||
|
type: "assistant",
|
||||||
|
finish: "tool-calls",
|
||||||
|
content: [{ type: "tool", id: "call-denied", name: "echo", state: { status: "error" } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "assistant",
|
||||||
|
finish: "stop",
|
||||||
|
content: [{ type: "text", id: "text-after-denial", text: "Permission denied" }],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it.effect("settles a stale unavailable question call and continues without a pending request", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
yield* setup
|
||||||
|
const session = yield* SessionV2.Service
|
||||||
|
const question = yield* QuestionV2.Service
|
||||||
|
yield* session.prompt({ sessionID, prompt: new Prompt({ text: "Do not wait for a question" }), resume: false })
|
||||||
|
|
||||||
|
requests.length = 0
|
||||||
|
responses = [
|
||||||
|
[
|
||||||
|
LLMEvent.stepStart({ index: 0 }),
|
||||||
|
LLMEvent.toolCall({ id: "call-stale-question", name: "question", input: { questions: [] } }),
|
||||||
|
LLMEvent.stepFinish({ index: 0, reason: "tool-calls" }),
|
||||||
|
LLMEvent.finish({ reason: "tool-calls" }),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
LLMEvent.stepStart({ index: 0 }),
|
||||||
|
LLMEvent.textStart({ id: "text-after-question" }),
|
||||||
|
LLMEvent.textDelta({ id: "text-after-question", text: "Continued" }),
|
||||||
|
LLMEvent.textEnd({ id: "text-after-question" }),
|
||||||
|
LLMEvent.stepFinish({ index: 0, reason: "stop" }),
|
||||||
|
LLMEvent.finish({ reason: "stop" }),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
yield* session.resume(sessionID)
|
||||||
|
|
||||||
|
expect(requests).toHaveLength(2)
|
||||||
|
expect(requests[0]?.tools.map((tool) => tool.name)).not.toContain("question")
|
||||||
|
expect(yield* question.list()).toEqual([])
|
||||||
|
expect(yield* session.context(sessionID)).toMatchObject([
|
||||||
|
{ type: "user", text: "Do not wait for a question" },
|
||||||
|
{
|
||||||
|
type: "assistant",
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "tool",
|
||||||
|
id: "call-stale-question",
|
||||||
|
state: { status: "error", error: { message: "Unknown tool: question" } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ type: "assistant", content: [{ type: "text", id: "text-after-question", text: "Continued" }] },
|
||||||
|
])
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
it.effect("reloads a model switch before a tool-driven continuation turn", () =>
|
it.effect("reloads a model switch before a tool-driven continuation turn", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
yield* setup
|
yield* setup
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { cmd } from "../cmd"
|
||||||
const filesystem = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
|
const filesystem = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
|
||||||
effect.pipe(
|
effect.pipe(
|
||||||
Effect.provide(LocationServiceMap.get({ directory: AbsolutePath.make(process.cwd()) })),
|
Effect.provide(LocationServiceMap.get({ directory: AbsolutePath.make(process.cwd()) })),
|
||||||
Effect.provide(LocationServiceMap.layer),
|
Effect.provide(LocationServiceMap.defaultLayer),
|
||||||
)
|
)
|
||||||
|
|
||||||
const FileSearchCommand = effectCmd({
|
const FileSearchCommand = effectCmd({
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,6 @@ export const V2Command = effectCmd({
|
||||||
directory: AbsolutePath.make(process.cwd()),
|
directory: AbsolutePath.make(process.cwd()),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
Effect.provide(LocationServiceMap.layer),
|
Effect.provide(LocationServiceMap.defaultLayer),
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -91,4 +91,4 @@ export const fileHandlers = HttpApiBuilder.group(InstanceHttpApi, "file", (handl
|
||||||
.handle("content", content)
|
.handle("content", content)
|
||||||
.handle("status", status)
|
.handle("status", status)
|
||||||
}),
|
}),
|
||||||
).pipe(Layer.provide(LocationServiceMap.layer))
|
).pipe(Layer.provide(LocationServiceMap.defaultLayer))
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ export const ptyHandlers = HttpApiBuilder.group(InstanceHttpApi, "pty", (handler
|
||||||
.handle("remove", remove)
|
.handle("remove", remove)
|
||||||
.handle("connectToken", connectToken)
|
.handle("connectToken", connectToken)
|
||||||
}),
|
}),
|
||||||
).pipe(Layer.provide(LocationServiceMap.layer))
|
).pipe(Layer.provide(LocationServiceMap.defaultLayer))
|
||||||
|
|
||||||
export const ptyConnectHandlers = HttpApiBuilder.group(PtyConnectApi, "pty-connect", (handlers) =>
|
export const ptyConnectHandlers = HttpApiBuilder.group(PtyConnectApi, "pty-connect", (handlers) =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
|
|
@ -255,4 +255,4 @@ export const ptyConnectHandlers = HttpApiBuilder.group(PtyConnectApi, "pty-conne
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
).pipe(Layer.provide(LocationServiceMap.layer))
|
).pipe(Layer.provide(LocationServiceMap.defaultLayer))
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import { SessionStore } from "@opencode-ai/core/session/store"
|
||||||
const routedSessions = SessionV2.layer.pipe(
|
const routedSessions = SessionV2.layer.pipe(
|
||||||
Layer.provide(SessionProjector.layer),
|
Layer.provide(SessionProjector.layer),
|
||||||
Layer.provide(SessionExecutionLocal.layer),
|
Layer.provide(SessionExecutionLocal.layer),
|
||||||
Layer.provide(LocationServiceMap.layer),
|
Layer.provide(LocationServiceMap.defaultLayer),
|
||||||
Layer.provide(SessionStore.layer),
|
Layer.provide(SessionStore.layer),
|
||||||
Layer.provide(EventV2.layer),
|
Layer.provide(EventV2.layer),
|
||||||
Layer.provide(Database.defaultLayer),
|
Layer.provide(Database.defaultLayer),
|
||||||
|
|
@ -51,7 +51,7 @@ export const v2Handlers = Layer.mergeAll(
|
||||||
sessionQuestionHandlers,
|
sessionQuestionHandlers,
|
||||||
).pipe(
|
).pipe(
|
||||||
Layer.provide(v2LocationLayer),
|
Layer.provide(v2LocationLayer),
|
||||||
Layer.provide(LocationServiceMap.layer),
|
Layer.provide(LocationServiceMap.defaultLayer),
|
||||||
Layer.provide(PermissionSaved.layer),
|
Layer.provide(PermissionSaved.layer),
|
||||||
Layer.provide(routedSessions),
|
Layer.provide(routedSessions),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ export function createRoutes(password?: string) {
|
||||||
? ServerAuth.Config.layer({ username: "opencode", password: Option.some(password) })
|
? ServerAuth.Config.layer({ username: "opencode", password: Option.some(password) })
|
||||||
: ServerAuth.Config.defaultLayer,
|
: ServerAuth.Config.defaultLayer,
|
||||||
),
|
),
|
||||||
Layer.provide(LocationServiceMap.layer),
|
Layer.provide(LocationServiceMap.defaultLayer),
|
||||||
Layer.provide(PermissionSaved.layer),
|
Layer.provide(PermissionSaved.layer),
|
||||||
Layer.provide(SessionV2.defaultLayer),
|
Layer.provide(SessionV2.defaultLayer),
|
||||||
Layer.provide(Database.defaultLayer),
|
Layer.provide(Database.defaultLayer),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue