From bc8eb74b82c9ce700769ae6181bfaa6d7e0bbd90 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Fri, 27 Mar 2026 02:50:03 +0100 Subject: [PATCH] fix(ai): detect Ollama overflow errors closes #2626 --- packages/ai/CHANGELOG.md | 4 +++ packages/ai/src/utils/overflow.ts | 8 +++--- packages/ai/test/overflow.test.ts | 42 ++++++++++++++++++++++++++++++ packages/coding-agent/CHANGELOG.md | 4 +++ 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 packages/ai/test/overflow.test.ts diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 2e5548bc..8903d63a 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed context overflow detection to recognize Ollama error responses like `prompt too long; exceeded max context length ...`, so callers can trigger compaction and retry instead of surfacing the raw overflow error ([#2626](https://github.com/badlogic/pi-mono/issues/2626)) + ## [0.63.0] - 2026-03-27 ### Breaking Changes diff --git a/packages/ai/src/utils/overflow.ts b/packages/ai/src/utils/overflow.ts index c6f4696e..968d9da8 100644 --- a/packages/ai/src/utils/overflow.ts +++ b/packages/ai/src/utils/overflow.ts @@ -22,7 +22,7 @@ import type { AssistantMessage } from "../types.js"; * - Cerebras: Returns "400/413 status code (no body)" - handled separately below * - Mistral: "Prompt contains X tokens ... too large for model with Y maximum context length" * - z.ai: Does NOT error, accepts overflow silently - handled via usage.input > contextWindow - * - Ollama: Silently truncates input - not detectable via error message + * - Ollama: Some deployments truncate silently, others return errors like "prompt too long; exceeded max context length by X tokens" */ const OVERFLOW_PATTERNS = [ /prompt is too long/i, // Anthropic @@ -39,6 +39,7 @@ const OVERFLOW_PATTERNS = [ /exceeded model token limit/i, // Kimi For Coding /too large for model with \d+ maximum context length/i, // Mistral /model_context_window_exceeded/i, // z.ai non-standard finish_reason surfaced as error text + /prompt too long; exceeded (?:max )?context length/i, // Ollama explicit overflow error /context[_ ]length[_ ]exceeded/i, // Generic fallback /too many tokens/i, // Generic fallback /token limit exceeded/i, // Generic fallback @@ -71,8 +72,9 @@ const OVERFLOW_PATTERNS = [ * **Unreliable detection:** * - z.ai: Sometimes accepts overflow silently (detectable via usage.input > contextWindow), * sometimes returns rate limit errors. Pass contextWindow param to detect silent overflow. - * - Ollama: Silently truncates input without error. Cannot be detected via this function. - * The response will have usage.input < expected, but we don't know the expected value. + * - Ollama: May truncate input silently for some setups, but may also return explicit + * overflow errors that match the patterns above. Silent truncation still cannot be + * detected here because we do not know the expected token count. * * ## Custom Providers * diff --git a/packages/ai/test/overflow.test.ts b/packages/ai/test/overflow.test.ts new file mode 100644 index 00000000..214cb123 --- /dev/null +++ b/packages/ai/test/overflow.test.ts @@ -0,0 +1,42 @@ +import { describe, expect, it } from "vitest"; +import type { AssistantMessage } from "../src/types.js"; +import { isContextOverflow } from "../src/utils/overflow.js"; + +function createErrorMessage(errorMessage: string): AssistantMessage { + return { + role: "assistant", + content: [], + api: "openai-completions", + provider: "ollama", + model: "qwen3.5:35b", + usage: { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, + totalTokens: 0, + cost: { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, + total: 0, + }, + }, + stopReason: "error", + errorMessage, + timestamp: Date.now(), + }; +} + +describe("isContextOverflow", () => { + it("detects explicit Ollama prompt-too-long errors", () => { + const message = createErrorMessage("400 `prompt too long; exceeded max context length by 100918 tokens`"); + expect(isContextOverflow(message, 32768)).toBe(true); + }); + + it("does not treat generic non-overflow Ollama errors as overflow", () => { + const message = createErrorMessage("500 `model runner crashed unexpectedly`"); + expect(isContextOverflow(message, 32768)).toBe(false); + }); +}); diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 8ed999be..73c1e732 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed auto-compaction overflow recovery for Ollama models when the backend returns explicit `prompt too long; exceeded max context length ...` errors instead of silently truncating input ([#2626](https://github.com/badlogic/pi-mono/issues/2626)) + ## [0.63.0] - 2026-03-27 ### Breaking Changes