Skip to content

fix(anthropic): complete AgentRouter streams that end before terminal frames - #896

Closed
Yuxin-Qiao wants to merge 1 commit into
lidge-jun:devfrom
Yuxin-Qiao:codex/agentrouter-eof-tolerance
Closed

fix(anthropic): complete AgentRouter streams that end before terminal frames#896
Yuxin-Qiao wants to merge 1 commit into
lidge-jun:devfrom
Yuxin-Qiao:codex/agentrouter-eof-tolerance

Conversation

@Yuxin-Qiao

@Yuxin-Qiao Yuxin-Qiao commented Aug 2, 2026

Copy link
Copy Markdown

Summary

Closes #658: AgentRouter's Anthropic-compatible endpoint can close the stream before content_block_stop, message_delta, and message_stop. The Anthropic adapter previously treated every such EOF as a fatal truncation and discarded otherwise valid text and complete tool-call arguments.

This PR implements the accepted provider-compatibility feature as an explicit capability (anthropicEofTolerance, default off) rather than a hard-coded hostname branch:

  • Streaming: with the capability enabled, an EOF may complete only when visible text was received or an open tool call has complete JSON-object arguments. Incomplete tool JSON, no usable content, and transport failure before usable content remain truncation errors with the exact previous message. Strict providers keep the previous behavior unchanged.
  • Non-streaming: with the capability enabled, malformed concatenated tool input such as {}{"value":42} is repaired to the last valid JSON object ({"value":42}) instead of being discarded to {}. The strict path is unchanged.
  • Tool IDs: missing or blank tool_use.id keeps the existing stable synthesized-id path (anthropic adapter: baseUrl ending in /v1/messages doubles the path, input_json_delta is not scoped to tool_use, and Anthropic-compatible relays need tool-call quirk tolerance #765), now pinned by a regression test for this provider.
  • Registry: the AgentRouter row in src/providers/free-directory.ts declares the capability.

Repro (wire shape)

message_start
content_block_start (text)
content_block_delta (text_delta "visible")
EOF

Before: upstream stream ended before message_stop — possible truncation, visible text lost. After (with anthropicEofTolerance: true): text preserved and the stream completes with done.

Tests

  • New tests/anthropic-eof-tolerance.test.ts (8 cases): text EOF on/off, complete/incomplete tool EOF, no-content EOF, synthesized tool id, non-stream concatenation on/off, directory row capability.
  • bun run typecheck passes.
  • Focused suites (anthropic-compatible-stream.test.ts, provider-registry-parity.test.ts, zhipu-bigmodel-provider.test.ts) pass.
  • Full suite compared against a clean dev baseline in the same environment: baseline has pre-existing failing tests (GUI/network-dependent, unrelated to this change); this branch introduces no additional failures, and the 4 flaky WP040 probe tests that were branch-only pass in isolation.
  • No live AgentRouter endpoint was available, so the tests pin wire behavior only; strict default behavior is covered by the negative tests.

Docs

  • providers.md configuration table row added in English plus ja/ko/ru/zh-cn locales.

Summary by CodeRabbit

  • New Features
    • Added an optional provider setting to tolerate early termination of Anthropic-compatible streams when complete text or tool input has been received.
    • Added limited repair for malformed non-streaming tool arguments when enabled.
    • Enabled this capability for the AgentRouter provider.
  • Bug Fixes
    • Incomplete or empty streams continue to report truncation errors by default.
  • Documentation
    • Documented the new setting across supported languages.

@github-actions github-actions Bot added the bug Something isn't working label Aug 2, 2026
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds anthropicEofTolerance for Anthropic-compatible providers. The adapter accepts qualifying early EOFs with visible text or complete tool JSON, repairs bounded malformed non-stream tool input, and keeps strict truncation behavior by default. AgentRouter enables the option.

Changes

Anthropic EOF tolerance

Layer / File(s) Summary
Configuration contract and documentation
src/types.ts, docs-site/src/content/docs/.../reference/configuration/providers.md
Adds optional anthropicEofTolerance?: boolean. Documentation states that the option is disabled by default and applies only to qualifying early stream termination.
Adapter EOF and tool-input handling
src/adapters/anthropic.ts
Tracks visible text, validates complete tool JSON at EOF, preserves truncation errors for incomplete or empty streams, and enables bounded malformed-JSON repair when configured.
Provider capability wiring and regression coverage
src/providers/free-directory.ts, tests/anthropic-eof-tolerance.test.ts
Adds the capability metadata, enables it for AgentRouter, and tests text EOF, tool JSON EOF, strict mode, incomplete output, synthesized IDs, non-stream input, and provider metadata.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AgentRouter
  participant AnthropicAdapter
  participant ToolInputParser
  participant OpenCodexClient
  AgentRouter->>AnthropicAdapter: stream content and tool JSON deltas
  AgentRouter-->>AnthropicAdapter: EOF before message_stop
  AnthropicAdapter->>ToolInputParser: validate accumulated tool input
  ToolInputParser-->>AnthropicAdapter: complete JSON object or invalid input
  AnthropicAdapter->>OpenCodexClient: completion or truncation error
Loading

Possibly related PRs

Suggested reviewers: ingwannu, lidge-jun, wibias

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the Anthropic AgentRouter EOF compatibility fix, which is the primary change in the pull request.
Linked Issues check ✅ Passed The changes satisfy issue #658 by adding gated EOF tolerance, valid tool JSON handling, synthesized IDs, input repair, strict defaults, tests, and AgentRouter registration.
Out of Scope Changes check ✅ Passed The implementation, tests, provider metadata, types, and localized documentation all directly support the AgentRouter compatibility requirements in issue #658.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs-site/src/content/docs/reference/configuration/providers.md`:
- Line 94: Update the Anthropic Messages streaming documentation in the adapters
reference to list the supported SSE lifecycle events: message_start,
content_block_start, content_block_delta, content_block_stop, message_delta,
message_stop, and error. Document that strict EOF handling fails truncated
streams, while anthropicEofTolerance permits early completion only after visible
text or complete JSON-object tool input; incomplete or contentless streams must
still fail.

In `@src/adapters/anthropic.ts`:
- Around line 992-1010: Track completed tool calls separately from
currentToolCallId in the EOF handling around the Anthropic stream flow, and
allow early completion only for visible non-empty text or open tool arguments
that parse to a non-null, non-array JSON object; update
src/adapters/anthropic.ts lines 992-1010 accordingly, while preserving
already-emitted tool_call_end state. In src/adapters/anthropic.ts lines 892-894,
set sawVisibleText only when the text delta is non-empty. Add coverage in
tests/anthropic-eof-tolerance.test.ts lines 57-104 for pre-EOF tool closure,
missing or non-object tool JSON, and empty text deltas.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 62830ced-ce24-4509-9437-6fda3989d238

📥 Commits

Reviewing files that changed from the base of the PR and between f9b9440 and 6c7494f.

📒 Files selected for processing (9)
  • docs-site/src/content/docs/ja/reference/configuration/providers.md
  • docs-site/src/content/docs/ko/reference/configuration/providers.md
  • docs-site/src/content/docs/reference/configuration/providers.md
  • docs-site/src/content/docs/ru/reference/configuration/providers.md
  • docs-site/src/content/docs/zh-cn/reference/configuration/providers.md
  • src/adapters/anthropic.ts
  • src/providers/free-directory.ts
  • src/types.ts
  • tests/anthropic-eof-tolerance.test.ts

| `thinkingBudgetModels?` | `string[]` | Chat models using integer `thinking_budget`; effort maps to a budget fraction. |
| `noVisionModels?` | `string[]` | Text-only models sent through the vision sidecar; matching tolerates an Ollama `:size` tag. |
| `escapeBuiltinToolNames?` | `boolean` | Escape built-in tool names for Anthropic-compatible gateways and restore them in returned calls. |
| `anthropicEofTolerance?` | `boolean` | Let an Anthropic-compatible gateway complete a stream that ends before `message_stop`, only when visible text or a complete JSON-object tool input was received. Off by default. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 5 'Anthropic|Messages API|message_stop|content_block_stop|SSE|EOF|tool JSON' \
  docs-site/src/content/docs/reference/adapters.md

Repository: lidge-jun/opencodex

Length of output: 3674


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- adapter documentation ---'
cat -n docs-site/src/content/docs/reference/adapters.md | sed -n '54,72p'

printf '%s\n' '--- provider reference ---'
cat -n docs-site/src/content/docs/reference/configuration/providers.md | sed -n '86,100p'

printf '%s\n' '--- anthropicEofTolerance references ---'
rg -n -C 4 'anthropicEofTolerance|message_stop|content_block_stop|input_json_delta' \
  --glob '!node_modules' --glob '!dist' --glob '!build' .

printf '%s\n' '--- candidate Anthropic adapter files ---'
fd -i 'anthropic' . --type f | head -80

Repository: lidge-jun/opencodex

Length of output: 50378


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Anthropic parser event cases ---'
sed -n '850,1020p' src/adapters/anthropic.ts

printf '%s\n' '--- adapter documentation context ---'
cat -n docs-site/src/content/docs/reference/adapters.md | sed -n '54,70p'

printf '%s\n' '--- required documentation terms ---'
python3 - <<'PY'
from pathlib import Path

doc = Path("docs-site/src/content/docs/reference/adapters.md").read_text()
terms = [
    "Messages API",
    "message_start",
    "content_block_start",
    "content_block_delta",
    "content_block_stop",
    "message_delta",
    "message_stop",
    "error",
    "anthropicEofTolerance",
    "strict",
    "truncation",
    "complete JSON",
]
for term in terms:
    print(f"{term}: {'present' if term in doc else 'missing'}")
PY

Repository: lidge-jun/opencodex

Length of output: 11037


Document Anthropic Messages streaming and EOF behavior.

docs-site/src/content/docs/reference/adapters.md:54-66 omits the supported SSE lifecycle events and anthropicEofTolerance behavior. Document message_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop, and error. State that strict EOF handling fails on truncation, while enabled tolerance allows early completion only after visible text or complete JSON-object tool input; incomplete or contentless streams remain errors.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs-site/src/content/docs/reference/configuration/providers.md` at line 94,
Update the Anthropic Messages streaming documentation in the adapters reference
to list the supported SSE lifecycle events: message_start, content_block_start,
content_block_delta, content_block_stop, message_delta, message_stop, and error.
Document that strict EOF handling fails truncated streams, while
anthropicEofTolerance permits early completion only after visible text or
complete JSON-object tool input; incomplete or contentless streams must still
fail.

Source: Path instructions

Comment thread src/adapters/anthropic.ts
Comment on lines +992 to +1010
} else if (provider.anthropicEofTolerance === true) {
// AgentRouter-style compatibility profile (#658): the upstream can close the stream
// after valid content without terminal frames. Complete only when visible text was
// received or an open tool call has complete JSON-object arguments; everything else
// (incomplete tool JSON, no usable content, transport failure) stays a truncation
// error, matching the strict default.
if (currentToolCallId) {
if (streamedToolArgumentsParse(currentToolCallJson)) {
budget.closeCall(currentToolCallId);
currentToolCallId = "";
yield { type: "tool_call_end" };
yield* emitDone();
} else {
yield { type: "error", message: "upstream stream ended before message_stop — possible truncation" };
}
} else if (sawVisibleText) {
yield* emitDone();
} else {
yield { type: "error", message: "upstream stream ended before message_stop — possible truncation" };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Implement the documented EOF completion predicate.

A valid tool call that receives content_block_stop clears currentToolCallId before Line 1007. The EOF path then reports truncation even though it already emitted tool_call_end. Conversely, streamedToolArgumentsParse("") returns true and also accepts arrays, scalars, and null, so an open tool call without a complete JSON object can incorrectly complete. An empty text_delta also sets sawVisibleText at Line 893.

  • src/adapters/anthropic.ts#L992-L1010: Track completed tool calls separately. At EOF, accept an open tool call only if its trimmed arguments parse to a non-null, non-array JSON object.
  • src/adapters/anthropic.ts#L892-L894: Set the visible-text state only for non-empty text.
  • tests/anthropic-eof-tolerance.test.ts#L57-L104: Add cases for a tool call closed before EOF, missing or non-object tool JSON, and an empty text delta.

Based on PR objectives, only visible text or a complete JSON object may permit early completion.

📍 Affects 2 files
  • src/adapters/anthropic.ts#L992-L1010 (this comment)
  • src/adapters/anthropic.ts#L892-L894
  • tests/anthropic-eof-tolerance.test.ts#L57-L104
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/adapters/anthropic.ts` around lines 992 - 1010, Track completed tool
calls separately from currentToolCallId in the EOF handling around the Anthropic
stream flow, and allow early completion only for visible non-empty text or open
tool arguments that parse to a non-null, non-array JSON object; update
src/adapters/anthropic.ts lines 992-1010 accordingly, while preserving
already-emitted tool_call_end state. In src/adapters/anthropic.ts lines 892-894,
set sawVisibleText only when the text delta is non-empty. Add coverage in
tests/anthropic-eof-tolerance.test.ts lines 57-104 for pre-EOF tool closure,
missing or non-object tool JSON, and empty text deltas.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6c7494f64c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

bytez: openAi("https://api.bytez.com/models/v2/openai/v1", "https://bytez.com", { verification: "unverified", lastVerified: undefined, documentationUrl: "https://docs.bytez.com/", discovery: "static", liveModels: false, models: ["meta-llama/Llama-3.3-70B-Instruct", "mistralai/Mistral-7B-Instruct-v0.3", "Qwen/Qwen2.5-72B-Instruct"], note: "The recurring-credit classification is retained from the requested catalog, but the current reset terms could not be independently verified." }),
"nous-research": openAi("https://inference-api.nousresearch.com/v1", "https://portal.nousresearch.com", { discovery: "static", liveModels: false, models: ["Hermes-4-405B", "Hermes-4-70B"] }),
agentrouter: { baseUrl: "https://agentrouter.org", dashboardUrl: "https://agentrouter.org", adapter: "anthropic", authKind: "key", supportLevel: "experimental", verification: "primary", modelsUrl: "https://agentrouter.org/v1/models", lastVerified: LAST_VERIFIED, discovery: "live", liveModels: true },
agentrouter: { baseUrl: "https://agentrouter.org", dashboardUrl: "https://agentrouter.org", adapter: "anthropic", authKind: "key", supportLevel: "experimental", verification: "primary", modelsUrl: "https://agentrouter.org/v1/models", lastVerified: LAST_VERIFIED, discovery: "live", liveModels: true, anthropicEofTolerance: true },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Wire AgentRouter tolerance into the runtime provider flow

For existing AgentRouter configurations that do not manually add anthropicEofTolerance, this metadata never enables the new behavior: a repo-wide search shows FREE_PROVIDER_DIRECTORY is consumed only by tests, and tests/provider-registry-parity.test.ts:814-830 explicitly keeps it isolated from runtime providers. Because routedProviderConfig() reads the canonical registry and user config instead, AgentRouter streams still use the strict default and report truncation. Add the capability to the canonical provider/derivation flow or otherwise persist it into the actual provider configuration.

AGENTS.md reference: src/AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

Comment thread src/adapters/anthropic.ts
Comment on lines +1007 to +1008
} else if (sawVisibleText) {
yield* emitDone();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Accept completed tool blocks when only message_stop is missing

When a tool-only AgentRouter stream sends valid arguments and content_block_stop but then closes before message_delta/message_stop, the normal block-stop handling has already cleared currentToolCallId; this branch therefore falls through to the truncation error because no text was emitted. This is a cleaner and more complete tool call than the open-tool case accepted above, yet the advertised tolerance still rejects it. Track that a usable tool call completed and allow that state to reach emitDone().

AGENTS.md reference: src/AGENTS.md:L19-L19

Useful? React with 👍 / 👎.

Comment thread src/adapters/anthropic.ts
Comment on lines +999 to +1003
if (streamedToolArgumentsParse(currentToolCallJson)) {
budget.closeCall(currentToolCallId);
currentToolCallId = "";
yield { type: "tool_call_end" };
yield* emitDone();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Stop after a translator-budget terminal error

When a tolerant stream exceeds the translator budget after opening a tool call, the catch at lines 966-974 emits translation_buffer_limit but execution continues here; if the overflow happened before the fragment was retained, the empty argument buffer is considered valid and the adapter subsequently emits tool_call_end and done. Direct or unguarded consumers therefore receive a successful terminal after a terminal error, potentially completing an empty tool call. Record the failure or return immediately after emitting the budget error so EOF tolerance cannot run.

AGENTS.md reference: src/AGENTS.md:L19-L19

Useful? React with 👍 / 👎.

Comment thread src/adapters/anthropic.ts
const delta = data.delta as Record<string, unknown> | undefined;
if (!delta) break;
if (delta.type === "text_delta" && typeof delta.text === "string") {
sawVisibleText = true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not count empty text deltas as visible output

If a tolerant gateway emits text_delta with text: "" and then closes, this assignment marks the response usable and the EOF branch returns done with an empty answer. That contradicts the stated requirement that EOF without usable content remain a truncation error. Set sawVisibleText only when the delta actually contains visible content.

AGENTS.md reference: src/AGENTS.md:L19-L19

Useful? React with 👍 / 👎.

Comment thread src/adapters/anthropic.ts
Comment on lines +1007 to +1008
} else if (sawVisibleText) {
yield* emitDone();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject EOF after malformed SSE records

When a tolerant stream emits valid text and its next SSE record is truncated or contains malformed JSON, the parse failure at lines 858-863 is only debug-dropped, so this branch treats the ensuing EOF as clean and emits done; for example, a cut-off second text_delta silently loses that text while completing the response. Track whether any malformed record was dropped and keep EOF strict in that state rather than accepting a demonstrably damaged stream.

AGENTS.md reference: src/AGENTS.md:L19-L19

Useful? React with 👍 / 👎.

Comment thread src/adapters/anthropic.ts
Comment on lines +294 to +298
for (let i = opens.length - 1; i >= 0 && tried < maxCandidates; i--, tried++) {
const candidate = input.slice(opens[i]);
try {
const parsed = JSON.parse(candidate) as unknown;
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return candidate;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restrict repair candidates to top-level concatenated objects

When the final concatenated object is itself truncated but ends with a complete nested object, scanning every opening brace accepts that nested value as the repaired tool arguments. For example, {}{"outer":{"value":42} is converted to {"value":42} and emitted as a completed tool call even though the second top-level object never closed. Parse top-level object boundaries with string/escape awareness so nested fragments from incomplete payloads cannot become executable arguments.

AGENTS.md reference: src/AGENTS.md:L19-L19

Useful? React with 👍 / 👎.

Comment thread src/adapters/anthropic.ts
Comment on lines +294 to +295
for (let i = opens.length - 1; i >= 0 && tried < maxCandidates; i--, tried++) {
const candidate = input.slice(opens[i]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bound the size scanned by JSON repair

When a tolerant non-stream response contains a large malformed tool-input string with many braces, each of up to 32 suffix candidates is a near-full copy that JSON.parse scans synchronously, followed by up to 32 more prefix parses; the initial loop also retains every brace offset. A 4 MiB all-{ input already spends roughly half a second in this path, and inputs near the 32 MiB translator limit can block Bun's event loop for several seconds per request. Cap the repairable input size or replace the repeated suffix parsing with a single bounded top-level scan.

Useful? React with 👍 / 👎.

Comment thread src/adapters/anthropic.ts
// (incomplete tool JSON, no usable content, transport failure) stays a truncation
// error, matching the strict default.
if (currentToolCallId) {
if (streamedToolArgumentsParse(currentToolCallJson)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require streamed tool arguments to be a JSON object

When a tolerant tool stream ends with a syntactically valid scalar or array such as null, 42, or [], streamedToolArgumentsParse() returns true and this branch emits tool_call_end followed by done. The capability contract and documentation require a complete JSON object, so these values should remain truncation/protocol errors instead of becoming completed function calls. Validate that the parsed result is non-null, object-shaped, and not an array before accepting EOF.

AGENTS.md reference: src/AGENTS.md:L19-L19

Useful? React with 👍 / 👎.

| `thinkingBudgetModels?` | `string[]` | Chat models using integer `thinking_budget`; effort maps to a budget fraction. |
| `noVisionModels?` | `string[]` | Text-only models sent through the vision sidecar; matching tolerates an Ollama `:size` tag. |
| `escapeBuiltinToolNames?` | `boolean` | Escape built-in tool names for Anthropic-compatible gateways and restore them in returned calls. |
| `anthropicEofTolerance?` | `boolean` | Let an Anthropic-compatible gateway complete a stream that ends before `message_stop`, only when visible text or a complete JSON-object tool input was received. Off by default. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Document the non-stream repair controlled by this option

When an operator enables anthropicEofTolerance, parseResponse() also changes non-stream behavior by extracting a JSON object from malformed string-valued tool input, but this row—and the matching translated rows—describes only early stream completion. Users therefore cannot tell that the option can alter and complete tool calls on ordinary non-stream requests. Document the repair behavior in every locale or separate it behind a configuration key whose scope matches the documented EOF behavior.

AGENTS.md reference: docs-site/AGENTS.md:L7-L10

Useful? React with 👍 / 👎.

@lidge-jun

Copy link
Copy Markdown
Owner

Landed in #892 as 538d755 (authorship preserved), with three review folds on top: the repair scan is now backward/lastIndexOf with no offset arrays plus an exact UTF-8 byte cap (surrogate-safe), only non-empty text authorizes tolerant completion, and a budget overflow returns as the single terminal event (9794e24, d8b707e, daf7069). One honest note: FREE_PROVIDER_DIRECTORY is currently consumed by tests only, so the AgentRouter row declaration is inert metadata — the capability activates via the provider config flag, matching your explicit-capability design. Closing as superseded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants