diff --git a/packages/opencode/src/effect/runner.ts b/packages/opencode/src/effect/runner.ts index 9fa55230c..89c3a844a 100644 --- a/packages/opencode/src/effect/runner.ts +++ b/packages/opencode/src/effect/runner.ts @@ -19,6 +19,7 @@ interface RunHandle { interface ShellHandle { id: number ready: Deferred.Deferred + cancelled: Deferred.Deferred fiber: Fiber.Fiber } @@ -99,7 +100,12 @@ export const make = ( }), ).pipe(Effect.flatten) - const stopShell = (shell: ShellHandle) => Fiber.interrupt(shell.fiber) + const stopShell = (shell: ShellHandle) => + Effect.gen(function* () { + yield* awaitShellReady(shell) + yield* Deferred.succeed(shell.cancelled, undefined).pipe(Effect.asVoid) + yield* Fiber.interrupt(shell.fiber) + }) const awaitShellReady = (shell: ShellHandle) => Deferred.await(shell.ready).pipe(Effect.raceFirst(Fiber.await(shell.fiber).pipe(Effect.asVoid)), Effect.ignore) @@ -149,18 +155,28 @@ export const make = ( } yield* busy const id = next() + const cancelled = yield* Deferred.make() const ready = options?.ready ?? (yield* Deferred.make().pipe( Effect.tap((ready) => Deferred.succeed(ready, undefined)), )) const fiber = yield* work.pipe(Effect.ensuring(finishShell(id)), Effect.forkChild) - const shell = { id, ready, fiber } satisfies ShellHandle + const shell = { id, ready, cancelled, fiber } satisfies ShellHandle return [ Effect.gen(function* () { const exit = yield* Fiber.await(fiber) if (Exit.isSuccess(exit)) return exit.value - if (Cause.hasInterruptsOnly(exit.cause) && onInterrupt) return yield* onInterrupt + if ( + Cause.hasInterruptsOnly(exit.cause) || + ((yield* Deferred.isDone(cancelled)) && + Cause.hasInterrupts(exit.cause) && + !Cause.hasFails(exit.cause) && + !Cause.hasDies(exit.cause)) + ) { + if (onInterrupt) return yield* onInterrupt + return yield* Effect.die(new Cancelled()) + } return yield* Effect.failCause(exit.cause) }), { _tag: "Shell", shell }, @@ -184,7 +200,6 @@ export const make = ( case "Shell": return [ Effect.gen(function* () { - yield* awaitShellReady(st.shell) yield* stopShell(st.shell) yield* idleIfCurrent() }), @@ -193,9 +208,8 @@ export const make = ( case "ShellThenRun": return [ Effect.gen(function* () { - yield* Deferred.fail(st.run.done, new Cancelled()).pipe(Effect.asVoid) - yield* awaitShellReady(st.shell) yield* stopShell(st.shell) + yield* Deferred.fail(st.run.done, new Cancelled()).pipe(Effect.asVoid) yield* idleIfCurrent() }), { _tag: "Idle" } as const, diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index 0e20d4f75..bb8e08f09 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -37,8 +37,8 @@ const PRUNE_PROTECTED_TOOLS = ["skill"] const DEFAULT_TAIL_TURNS = 2 const MIN_PRESERVE_RECENT_TOKENS = 2_000 const MAX_PRESERVE_RECENT_TOKENS = 8_000 -const SUMMARY_TEMPLATE = `Output exactly this Markdown structure and keep the section order unchanged: ---- +const SUMMARY_TEMPLATE = `Output exactly the Markdown structure shown inside