diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index 813fe49f325d..eefc8c579dd7 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -34,6 +34,7 @@ import { MessageTable, PartTable, SessionTable } from "@opencode-ai/core/session import { ProviderError } from "@/provider/error" import { iife } from "@/util/iife" import { errorMessage } from "@/util/error" +import { isContextOverflow } from "@opencode-ai/llm" import { isMedia } from "@/util/media" import type { SystemError } from "bun" import type { Provider } from "@/provider/provider" @@ -713,8 +714,16 @@ export function fromError( }, { cause: e }, ).toObject() - case e instanceof Error: - return new NamedError.Unknown({ message: errorMessage(e) }, { cause: e }).toObject() + case e instanceof Error: { + const msg = errorMessage(e) + if (isContextOverflow(msg)) { + return new ContextOverflowError( + { message: msg, responseBody: msg }, + { cause: e }, + ).toObject() + } + return new NamedError.Unknown({ message: msg }, { cause: e }).toObject() + } default: try { const parsed = ProviderError.parseStreamError(e) diff --git a/packages/opencode/test/session/message-v2.test.ts b/packages/opencode/test/session/message-v2.test.ts index 1de84c9dd95b..5743c2269dcb 100644 --- a/packages/opencode/test/session/message-v2.test.ts +++ b/packages/opencode/test/session/message-v2.test.ts @@ -1487,6 +1487,28 @@ describe("session.message-v2.fromError", () => { expect(SessionV1.ContextOverflowError.isInstance(result)).toBe(true) }) + test("detects context overflow from generic Error messages", () => { + const cases = [ + "prompt is too long: 213462 tokens > 200000 maximum", + "Your input exceeds the context window of this model", + "The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)", + "Please reduce the length of the messages or completion", + "This model's maximum context length is 8192 tokens", + ] + + cases.forEach((message) => { + const error = new Error(message) + const result = MessageV2.fromError(error, { providerID }) + expect(SessionV1.ContextOverflowError.isInstance(result)).toBe(true) + }) + }) + + test("does not classify generic non-overflow Error as context overflow", () => { + const result = MessageV2.fromError(new Error("Network connection lost."), { providerID }) + expect(SessionV1.ContextOverflowError.isInstance(result)).toBe(false) + expect(result.name).toBe("UnknownError") + }) + test("does not classify 429 no body as context overflow", () => { const result = MessageV2.fromError( new APICallError({