fix(core): correlate streamed tool calls safely - #205
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughParallel streamed tool calls now preserve correlation metadata, assemble through validation, defer tool callbacks until successful completion, prevent execution after malformed streams, and retry only unpublished protocol errors. Documentation and changelog entries were updated. ChangesStream correlation and failure handling
Process documentation updates
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Provider as Stream provider
participant Generate as generate
participant Assembler as StreamMessageAssembler
participant Step as step
participant Soul as PythinkerSoul
Provider->>Generate: stream correlated tool-call fragments
Generate->>Assembler: assemble and validate fragments
Assembler-->>Generate: finalized message or protocol error
Generate->>Step: return result or error
Step->>Step: dispatch tools only after successful assembly
Soul->>Soul: retry only when output_published is false
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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 `@packages/pythinker-core/src/pythinker_core/_generate.py`:
- Around line 54-57: Update the tracing around chat_provider.generate and the
async stream loop to stop logging raw history, prompts, tool arguments, or
streamed part contents. Replace the history trace with safe metadata such as
item counts, and log only each received part’s type or other non-sensitive
structural metadata.
In
`@packages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_responses.py`:
- Around line 553-563: Update both function_call branches in openai_responses.py
to pass blank call_id values through instead of falling back to uuid.uuid4(),
allowing StreamMessageAssembler to assign the stable ID. Add a regression
covering an empty call_id in
packages/pythinker-core/tests/test_stream_tool_call_metadata.py at lines
315-352.
In `@packages/pythinker-core/src/pythinker_core/stream_message_assembler.py`:
- Around line 14-23: Remove None from _ALLOWED_TOOL_FINISH_REASONS so a
tool-call stream ending at clean EOF without a terminal reason fails closed.
Update packages/pythinker-core/tests/test_stream_message_assembler.py lines
158-168 to assert terminal_failure rather than successful finalization.
In `@packages/pythinker-core/tests/test_stream_tool_call_metadata.py`:
- Around line 315-352: Extend
test_openai_responses_uses_output_index_and_semantic_call_id with an empty
call_id scenario using two otherwise identical Responses streams. Collect both
streams and assert their final ToolCall IDs are identical, while preserving the
existing output_index and argument assertions.
- Around line 355-387: Extend the OpenAI Responses stream regression coverage
around OpenAIResponsesStreamedMessage to emit a ResponseErrorEvent after a
tool-call start, then assert generate() terminates before invoking on_tool_call.
Preserve the existing response/item ID assertions and use the stream’s
established terminal-error handling path.
🪄 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
Run ID: f03f2947-c25e-46c4-90f4-f04d3d2790ce
⛔ Files ignored due to path filters (2)
docs/en/release-notes/changelog.mdis excluded by!docs/**docs/superpowers/specs/2026-07-14-provider-stream-and-tool-execution-design.mdis excluded by!docs/**
📒 Files selected for processing (21)
AGENTS.mdCHANGELOG.mdpackages/pythinker-core/src/pythinker_core/__init__.pypackages/pythinker-core/src/pythinker_core/_generate.pypackages/pythinker-core/src/pythinker_core/chat_provider/__init__.pypackages/pythinker-core/src/pythinker_core/chat_provider/pythinker.pypackages/pythinker-core/src/pythinker_core/contrib/chat_provider/anthropic.pypackages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_legacy.pypackages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_responses.pypackages/pythinker-core/src/pythinker_core/message.pypackages/pythinker-core/src/pythinker_core/stream_message_assembler.pypackages/pythinker-core/tests/test_generate.pypackages/pythinker-core/tests/test_message.pypackages/pythinker-core/tests/test_step.pypackages/pythinker-core/tests/test_stream_message_assembler.pypackages/pythinker-core/tests/test_stream_tool_call_metadata.pyplips/plip-10-lsp-system.mdsrc/pythinker_code/soul/pythinkersoul.pytests/core/test_context.pytests/core/test_pythinkersoul_retry_recovery.pytests/core/test_wire_message.py
💤 Files with no reviewable changes (1)
- AGENTS.md
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_responses.py (1)
578-586: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winMake
ResponseErrorEventterminal.
ResponseErrorEventcan still be followed by a later terminal event, which overwrites"failed"and can let tool dispatch proceed. Stop consuming the stream after the error, and add a regression with a trailing completed event to keep the callback list empty.🤖 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 `@packages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_responses.py` around lines 578 - 586, Make ResponseErrorEvent terminal in the stream handling logic by stopping consumption immediately after setting _finish_reason to "failed", preventing later terminal events from overwriting the failure or dispatching tools. Add a regression in packages/pythinker-core/tests/test_stream_tool_call_metadata.py around the affected test to include a trailing completed event and assert the callback list remains empty.Source: Coding guidelines
🤖 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.
Outside diff comments:
In
`@packages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_responses.py`:
- Around line 578-586: Make ResponseErrorEvent terminal in the stream handling
logic by stopping consumption immediately after setting _finish_reason to
"failed", preventing later terminal events from overwriting the failure or
dispatching tools. Add a regression in
packages/pythinker-core/tests/test_stream_tool_call_metadata.py around the
affected test to include a trailing completed event and assert the callback list
remains empty.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 64e85701-1da1-46ba-9736-2a98cee672ed
📒 Files selected for processing (4)
packages/pythinker-core/src/pythinker_core/_generate.pypackages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_responses.pypackages/pythinker-core/tests/test_step.pypackages/pythinker-core/tests/test_stream_tool_call_metadata.py
Related Issue
None — maintainer-directed implementation from the approved provider stream/tool-execution design.
Description
ResponseErrorEventbefore tool callbacksVerification
make check-pythinker-coremake test-pythinker-core: 407 passed on the final review-fix commitmake check-pythinker-codemake test-pythinker-code: 6,938 unit tests passed; 65 e2e tests passedgit diff --checkNotes
ToolParseErrorChecklist
npm run syncfromdocs/.Summary by CodeRabbit