Skip to content

fix: streaming robustness — OpenAI parsing, error detection, reasoning content#3015

Open
TheArchitectit wants to merge 7 commits into
ultraworkers:mainfrom
TheArchitectit:feat/streaming-robustness-v2
Open

fix: streaming robustness — OpenAI parsing, error detection, reasoning content#3015
TheArchitectit wants to merge 7 commits into
ultraworkers:mainfrom
TheArchitectit:feat/streaming-robustness-v2

Conversation

@TheArchitectit
Copy link
Copy Markdown

Summary

Shared streaming and response parsing robustness fixes that are prerequisites for several feature PRs.

Changes

Commit Change
612e9ef Bounds check in compact boundary loop
5bb3b56 Make delta field optional in ChunkChoice
4a63485 Support reasoning_content and thinking fields in streaming
c99a8c6 Detect raw JSON errors in streaming path
2caecc3 Detect HTML responses in streaming path
3b4e08f Add install script for rebuild and link
54015b8 Make id field optional in OpenAI response parsing

Why this PR exists

These fixes were developed alongside the LSP, provider wizard, and project rules features. Extracting them into a standalone base PR:

  • Makes downstream feature PRs smaller and focused
  • Allows upstream review of general streaming fixes independently
  • Prevents duplicate cherry-picked commits across multiple feature branches

Impact

  • Enables use of reasoning models that return thinking content
  • Prevents crashes on malformed OpenAI responses (missing id, delta)
  • Handles transient gateway errors that return HTML or raw JSON

Test plan

  • Verify streaming with Claude reasoning/thinking models
  • Verify OpenAI-compatible providers that omit id or delta
  • Verify graceful handling of HTML error pages from gateways
  • Verify compact boundary bounds check with edge-case inputs

TheArchitectit and others added 7 commits May 10, 2026 21:42
When preserve_recent_messages == 0, raw_keep_from equals messages.len(),
causing index out of bounds when accessing session.messages[k].

Added k >= session.messages.len() check to prevent panic.

Reason: Compaction with preserve_recent_messages=0 triggered OOB access
when checking for tool-use/tool-result pair preservation at boundary.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The final streaming chunk from some providers contains only finish_reason
and usage, with no delta field. Made it optional to prevent parse errors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Some providers (GLM, DeepSeek) emit reasoning tokens in `reasoning_content`
or nested `thinking.content` fields instead of `content`. Added support
for these fields so reasoning models work correctly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When a provider returns a JSON error (e.g., {"error":{"message":"..."}})
without SSE framing (no "data:" prefix), the SSE parser was silently
ignoring it and hanging. Now detects and surfaces these errors.

Also handles HTML responses that lack SSE framing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When a provider returns HTML (e.g., error page, wrong endpoint) instead
of JSON in an SSE stream, provide a clear error message instead of
hanging or failing with a cryptic parse error.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds scripts/install.sh that builds the release binary and links it
to ~/.local/bin/claw. Run after code changes to update the CLI.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Some OpenAI-compatible providers (e.g., GLM-5) omit the `id` field in
streaming and non-streaming responses. Adding #[serde(default)] allows
the parser to accept these responses instead of failing with
"missing field `id`".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant