fix(core): explain why the provider blocked a compaction (#52664)

This commit is contained in:
Aiden Cline
2026-10-01 23:07:32 -05:00
committed by GitHub
Unverified
parent 840cd232a8
commit 64744ce034
4 changed files with 40 additions and 15 deletions
+2 -5
View File
@@ -32,7 +32,7 @@ import { SessionModelRequest } from "./model-request.js"
import { SessionProviderContext } from "./provider-context.js"
import { SessionRunnerRetry } from "./runner/retry.js"
import { toLLMMessages } from "./runner/to-llm-message.js"
import { toSessionError } from "./to-session-error.js"
import { contentFilterError, toSessionError } from "./to-session-error.js"
import { SessionUsage } from "./usage.js"
export type Settings = {
@@ -540,10 +540,7 @@ export const layer = Layer.effect(
message: "Compaction summary reached the output token limit",
})
case "content-filter":
return unusable({
type: "provider.content-filter",
message: "Compaction summary was blocked by the provider",
})
return unusable(contentFilterError("Compaction summary was blocked by the provider", event.reason))
default:
return Effect.succeed(streamed)
}
@@ -12,6 +12,7 @@ import { SessionSchema } from "../schema.js"
import { SessionError } from "@opencode/schema/session-error"
import { Money } from "@opencode/schema/money"
import { SessionUsage } from "../usage.js"
import { contentFilterError } from "../to-session-error.js"
import type { Tool } from "../../tool.js"
type Input = {
@@ -543,15 +544,7 @@ export const createLLMEventPublisher = (bus: Pick<Bus.Interface, "publish">, inp
}
if (event.reason.normalized === "content-filter") {
providerFailed = true
yield* failAssistant({
type: "provider.content-filter",
message: [
`Provider blocked the response${event.reason.category === undefined ? "" : ` (${event.reason.category})`}`,
event.reason.explanation,
]
.filter(Boolean)
.join(": "),
})
yield* failAssistant(contentFilterError("Provider blocked the response", event.reason))
return
}
return
+10 -1
View File
@@ -1,4 +1,4 @@
import { AIError, ToolFailure } from "@opencode/ai"
import { AIError, ToolFailure, type FinishReasonDetails } from "@opencode/ai"
import { Tool } from "@opencode/schema/tool"
import { SessionError } from "@opencode/schema/session-error"
import { Permission } from "../permission.js"
@@ -85,6 +85,15 @@ export function toSessionError(cause: unknown): SessionError.Error {
return { type: "unknown", message: cause instanceof Error ? cause.message : String(cause) }
}
export function contentFilterError(summary: string, reason: FinishReasonDetails): SessionError.Error {
return {
type: "provider.content-filter",
message: [reason.category === undefined ? summary : `${summary} (${reason.category})`, reason.explanation]
.filter(Boolean)
.join(": "),
}
}
function providerError(type: string, reason: AIError["reason"]): SessionError.Error {
const status = reason.http?.status
return {
+26
View File
@@ -2716,6 +2716,32 @@ describe("SessionRunnerLLM", () => {
)
})
scenario("explains a compaction blocked by the provider", function* (s) {
yield* s.llm.push(TestLLM.text("Earlier answer", "history"))
yield* s.runPrompt("Earlier question")
yield* s.llm.push(
TestLLM.complete({
reason: {
normalized: "content-filter",
raw: "refusal",
category: "cyber",
explanation: "This request was declined because it could enable cyber harm.",
},
}),
)
const compaction = yield* s.session.compact({ sessionID })
yield* s.resume
expect((yield* s.messages).find((message) => message.id === compaction.id)).toMatchObject({
status: "failed",
error: {
type: "provider.content-filter",
message:
"Compaction summary was blocked by the provider (cyber): This request was declined because it could enable cyber harm.",
},
})
})
for (const header of [false, true]) {
scenario(`stops compaction retries through the ${header ? "provider header" : "retry hook"}`, function* (s) {
yield* s.llm.push(TestLLM.text("Earlier answer", "history"))