mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-04 23:19:52 +00:00
refactor(core): document task result correlation boundary
This commit is contained in:
parent
73be8f7658
commit
dc02446ff4
2 changed files with 28 additions and 30 deletions
|
|
@ -50,8 +50,9 @@ export const make = Effect.fn("TaskTool.make")(function* (
|
|||
model: agent.model ?? parent.model,
|
||||
})
|
||||
|
||||
// TODO: Replace this fresh-child composition with Session.run, preserving admission/execution
|
||||
// separation while returning the assistant response after the admitted boundary.
|
||||
// TODO: Replace this fresh-child-only composition once Session execution exposes a bounded
|
||||
// activity/result identity. An admission ID alone cannot correlate a response when one drain
|
||||
// processes later queued work.
|
||||
const run = Effect.gen(function* () {
|
||||
yield* sessions.prompt({
|
||||
sessionID: child.id,
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@ describe("TaskTool", () => {
|
|||
const inputs: Parameters<SessionV2.Interface["prompt"]>[0][] = []
|
||||
let resumed = 0
|
||||
const sessions = mockSessions({
|
||||
prompt: (input) => {
|
||||
inputs.push(input)
|
||||
return Effect.succeed(admission(input))
|
||||
prompt: (value) => {
|
||||
inputs.push(value)
|
||||
return Effect.succeed(admission(value))
|
||||
},
|
||||
resume: () => Effect.sync(() => resumed++),
|
||||
})
|
||||
|
|
@ -90,8 +90,6 @@ describe("TaskTool", () => {
|
|||
created = true
|
||||
return child
|
||||
}),
|
||||
prompt: (input) => Effect.succeed(admission(input)),
|
||||
resume: () => Effect.void,
|
||||
})
|
||||
const tool = yield* TaskTool.make(sessions, () => Effect.succeed(undefined))
|
||||
|
||||
|
|
@ -102,24 +100,6 @@ describe("TaskTool", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.live("interrupts the child when foreground waiting is interrupted", () =>
|
||||
Effect.gen(function* () {
|
||||
const resumed = yield* Deferred.make<void>()
|
||||
const interrupts: SessionV2.ID[] = []
|
||||
const sessions = mockSessions({
|
||||
prompt: (input) => Effect.succeed(admission(input)),
|
||||
resume: () => Deferred.succeed(resumed, undefined).pipe(Effect.andThen(Effect.never)),
|
||||
interrupt: (sessionID) => Effect.sync(() => interrupts.push(sessionID)),
|
||||
})
|
||||
const tool = yield* TaskTool.make(sessions, resolveAgent)
|
||||
const fiber = yield* execute(tool, input, "call_task_interrupt").pipe(Effect.forkChild)
|
||||
|
||||
yield* Deferred.await(resumed)
|
||||
yield* Fiber.interrupt(fiber)
|
||||
expect(interrupts).toEqual([childID])
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("does not notify the parent when background work is interrupted", () =>
|
||||
Effect.gen(function* () {
|
||||
let notified = false
|
||||
|
|
@ -140,17 +120,34 @@ describe("TaskTool", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.live("interrupts the child when foreground waiting is interrupted", () =>
|
||||
Effect.gen(function* () {
|
||||
const resumed = yield* Deferred.make<void>()
|
||||
const interrupts: SessionV2.ID[] = []
|
||||
const sessions = mockSessions({
|
||||
resume: () => Deferred.succeed(resumed, undefined).pipe(Effect.andThen(Effect.never)),
|
||||
interrupt: (sessionID) => Effect.sync(() => interrupts.push(sessionID)),
|
||||
})
|
||||
const tool = yield* TaskTool.make(sessions, resolveAgent)
|
||||
const fiber = yield* execute(tool, input, "call_task_interrupt").pipe(Effect.forkChild)
|
||||
|
||||
yield* Deferred.await(resumed)
|
||||
yield* Fiber.interrupt(fiber)
|
||||
expect(interrupts).toEqual([childID])
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("returns before background completion and steers the result into the parent", () =>
|
||||
Effect.gen(function* () {
|
||||
const gate = yield* Deferred.make<void>()
|
||||
const notified = yield* Deferred.make<Parameters<SessionV2.Interface["prompt"]>[0]>()
|
||||
const inputs: Parameters<SessionV2.Interface["prompt"]>[0][] = []
|
||||
const sessions = mockSessions({
|
||||
prompt: (input) => {
|
||||
inputs.push(input)
|
||||
return input.sessionID === parentID
|
||||
? Deferred.succeed(notified, input).pipe(Effect.as(admission(input)))
|
||||
: Effect.succeed(admission(input))
|
||||
prompt: (value) => {
|
||||
inputs.push(value)
|
||||
return value.sessionID === parentID
|
||||
? Deferred.succeed(notified, value).pipe(Effect.as(admission(value)))
|
||||
: Effect.succeed(admission(value))
|
||||
},
|
||||
resume: () => Deferred.await(gate),
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue