fix(session): cancel subtask child sessions (#25798)

This commit is contained in:
Kit Langton
2026-05-04 22:36:06 -04:00
committed by GitHub
parent 39c88f9afb
commit 75d141b574
4 changed files with 339 additions and 247 deletions

View File

@@ -1,6 +1,5 @@
import path from "path"
import os from "os"
import z from "zod"
import * as EffectZod from "@/util/effect-zod"
import { SessionID, MessageID, PartID } from "./schema"
import { MessageV2 } from "./message-v2"
@@ -121,9 +120,8 @@ export const layer = Layer.effect(
return yield* EffectBridge.make()
})
const ops = Effect.fn("SessionPrompt.ops")(function* () {
const run = yield* runner()
return {
cancel: (sessionID: SessionID) => run.fork(cancel(sessionID)),
cancel: (sessionID: SessionID) => cancel(sessionID),
resolvePromptParts: (template: string) => resolvePromptParts(template),
prompt: (input: PromptInput) => prompt(input),
} satisfies TaskPromptOps

View File

@@ -6,10 +6,11 @@ import { MessageV2 } from "../session/message-v2"
import { Agent } from "../agent/agent"
import type { SessionPrompt } from "../session/prompt"
import { Config } from "@/config/config"
import { Effect, Schema } from "effect"
import { Effect, Exit, Schema } from "effect"
import { EffectBridge } from "@/effect/bridge"
export interface TaskPromptOps {
cancel(sessionID: SessionID): void
cancel(sessionID: SessionID): Effect.Effect<void>
resolvePromptParts(template: string): Effect.Effect<SessionPrompt.PromptInput["parts"]>
prompt(input: SessionPrompt.PromptInput): Effect.Effect<MessageV2.WithParts>
}
@@ -118,16 +119,18 @@ export const TaskTool = Tool.define(
const ops = ctx.extra?.promptOps as TaskPromptOps
if (!ops) return yield* Effect.fail(new Error("TaskTool requires promptOps in ctx.extra"))
const runCancel = yield* EffectBridge.make()
const messageID = MessageID.ascending()
const cancel = ops.cancel(nextSession.id)
function cancel() {
ops.cancel(nextSession.id)
function onAbort() {
runCancel.fork(cancel)
}
return yield* Effect.acquireUseRelease(
Effect.sync(() => {
ctx.abort.addEventListener("abort", cancel)
ctx.abort.addEventListener("abort", onAbort)
}),
() =>
Effect.gen(function* () {
@@ -163,10 +166,16 @@ export const TaskTool = Tool.define(
].join("\n"),
}
}),
() =>
Effect.sync(() => {
ctx.abort.removeEventListener("abort", cancel)
}),
(_, exit) =>
Effect.gen(function* () {
if (Exit.hasInterrupts(exit)) yield* cancel
}).pipe(
Effect.ensuring(
Effect.sync(() => {
ctx.abort.removeEventListener("abort", onAbort)
}),
),
),
)
})