fix: suppress tool-call finish_reason planning content#162
fix: suppress tool-call finish_reason planning content#1620xCheetah1 wants to merge 2 commits intoBlockRunAI:mainfrom
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughProxy tests and implementation were updated to treat upstream responses that use Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/proxy.tool-forwarding.test.ts (1)
290-341: Consider adding streaming coverage for the new edge case.This non-streaming test verifies
finish_reason: "tool_calls"without atool_callsarray suppressesmessage.content. The streaming path insrc/proxy.ts(line 5072,endsWithToolCalls) handles the same edge case but isn't covered — adding a mirror SSE test would guard against regressions where planning prose leaks throughdelta.contenteven when the upstream only signals the tool-call turn viafinish_reason.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/proxy.tool-forwarding.test.ts` around lines 290 - 341, Add a streaming (SSE) test in src/proxy.tool-forwarding.test.ts that mirrors the existing non-streaming case: configure upstreamResponse to stream events where the final event has finish_reason: "tool_calls" but no tool_calls array, and assert that the proxy's SSE stream does not emit planning prose in delta.content (use the same request body with tools and model as the non-streaming test), read the SSE events until the stream ends and verify no non-empty assistant delta.content was forwarded and the final finish_reason sent to the client indicates tool_calls; focus on exercising the streaming branch handled by the endsWithToolCalls logic in src/proxy.ts so planning prose doesn't leak via streamed delta.content.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/proxy.tool-forwarding.test.ts`:
- Around line 290-341: Add a streaming (SSE) test in
src/proxy.tool-forwarding.test.ts that mirrors the existing non-streaming case:
configure upstreamResponse to stream events where the final event has
finish_reason: "tool_calls" but no tool_calls array, and assert that the proxy's
SSE stream does not emit planning prose in delta.content (use the same request
body with tools and model as the non-streaming test), read the SSE events until
the stream ends and verify no non-empty assistant delta.content was forwarded
and the final finish_reason sent to the client indicates tool_calls; focus on
exercising the streaming branch handled by the endsWithToolCalls logic in
src/proxy.ts so planning prose doesn't leak via streamed delta.content.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3de9a43a-6db3-4af0-bb99-5bae409ccea9
📒 Files selected for processing (2)
src/proxy.tool-forwarding.test.tssrc/proxy.ts
Thanks @0xCheetah1 — follow-up to #161. Some providers (observed on Moonshot Kimi K2.6 via OpenClaw Telegram) mark a turn with finish_reason: "tool_calls" without exposing the tool_calls array at the same inspection point, so the #161 gate (tool_calls.length > 0) let planning prose slip through. Broadens the gate to `endsWithToolCalls || toolCalls.length > 0` in both the non-streaming JSON path and the SSE emission path. Rebased onto v0.12.165's dedup/cache-isolation fix — changes auto-merged; the second "style: format" commit was dropped (prettier already applied upstream). The original PR branch's dedup-test conflict was resolved by keeping both the dedup-isolation test and the new finish_reason test.
…path Parallels the non-streaming test added in #162. The SSE emission path got the same endsWithToolCalls gate; this ensures a future refactor can't silently re-introduce the planning-prose leak there.
…ly path (#162) - fix: gate on endsWithToolCalls || toolCalls.length > 0 so planning prose is suppressed even when upstream marks finish_reason: "tool_calls" without exposing the tool_calls array at the same inspection point (thanks @0xCheetah1) - test: add SSE streaming regression test for the finish_reason-only case
|
Landed on main as 4f2b85b (rebased on v0.12.165's cache-isolation fix to resolve a minor test-file conflict, contributor authorship preserved). Credited in v0.12.166. Thanks for the quick follow-up! |
Summary
Why a follow-up PR
PR #161 fixed the common case where providers leaked planning text alongside tool_calls. Live testing uncovered one more structural edge case: some upstreams can mark the turn with finish_reason: "tool_calls" before the tool_calls array is visible at the same inspection point. In that case, planning content could still slip through. This PR hardens that remaining path.
Testing
Summary by CodeRabbit
Bug Fixes
Tests