diff --git a/packages/core/src/session/runner/llm.ts b/packages/core/src/session/runner/llm.ts index 2cd77beb0716..2532f6b5af1d 100644 --- a/packages/core/src/session/runner/llm.ts +++ b/packages/core/src/session/runner/llm.ts @@ -16,6 +16,7 @@ import { EventV2 } from "../../event" import { Location } from "../../location" import { ModelV2 } from "../../model" import { ProviderV2 } from "../../provider" +import { PermissionV2 } from "../../permission" import { QuestionV2 } from "../../question" import { SystemContext } from "../../system-context/index" import { SystemContextRegistry } from "../../system-context/registry" @@ -136,9 +137,15 @@ export const layer = Layer.effect( const awaitToolFibers = (fibers: FiberSet.FiberSet) => Effect.raceFirst(FiberSet.join(fibers), FiberSet.awaitEmpty(fibers)) - // Match V1: dismissing a question halts the loop instead of becoming model-facing tool output. - const isQuestionRejected = (cause: Cause.Cause) => - cause.reasons.some((reason) => Cause.isDieReason(reason) && reason.defect instanceof QuestionV2.RejectedError) + // Match V1: dismissing a question or permission prompt halts the loop instead of becoming model-facing tool output. + const isHalted = (cause: Cause.Cause) => + cause.reasons.some( + (reason) => + Cause.isDieReason(reason) && + (reason.defect instanceof QuestionV2.RejectedError || + reason.defect instanceof PermissionV2.RejectedError || + reason.defect instanceof PermissionV2.CorrectedError), + ) type TurnTransition = // Automatic compaction completed; rebuild the request from compacted history. @@ -283,7 +290,7 @@ export const layer = Layer.effect( } if (stream._tag === "Failure" && Cause.hasInterrupts(stream.cause)) yield* FiberSet.clear(toolFibers) const settled = yield* restore(awaitToolFibers(toolFibers)).pipe(Effect.exit) - if (settled._tag === "Failure" && isQuestionRejected(settled.cause)) { + if (settled._tag === "Failure" && isHalted(settled.cause)) { yield* FiberSet.clear(toolFibers) yield* withPublication(publisher.failUnsettledTools("Tool execution interrupted")) return yield* Effect.interrupt diff --git a/packages/opencode/src/session/processor.ts b/packages/opencode/src/session/processor.ts index 2554315908ce..8e8d6c977643 100644 --- a/packages/opencode/src/session/processor.ts +++ b/packages/opencode/src/session/processor.ts @@ -238,7 +238,11 @@ export const layer = Layer.effect( time: { start: match.part.state.time.start, end: Date.now() }, }, }) - if (error instanceof PermissionV1.RejectedError || error instanceof Question.RejectedError) { + if ( + error instanceof PermissionV1.RejectedError || + error instanceof PermissionV1.CorrectedError || + error instanceof Question.RejectedError + ) { ctx.blocked = ctx.shouldBreak } yield* settleToolCall(toolCallID)