Bug
truncateMessages() (proxy.ts ~L1152) slices conversation messages with conversationMsgs.slice(-maxConversation). This can split an assistant message containing tool_calls from its corresponding tool role response, causing downstream API 400 errors:
Anthropic: tool_use block without matching tool_result
OpenAI: tool_calls referenced but tool response missing
Steps to reproduce
Build a conversation with 200+ messages where a tool_calls assistant message and its tool response straddle the truncation boundary
Send it through ClawRouter
Observe 400 error from the upstream provider
Expected behavior
Truncation should never split a tool_call/tool_result pair. If one side of the pair falls within the kept window, the other side should be included as well.
Suggested fix
After slicing, scan the boundary:
If the first kept message has role: "tool", walk backwards to include its parent assistant message
If the last dropped message has tool_calls, include its corresponding tool responses
Bug
truncateMessages() (proxy.ts ~L1152) slices conversation messages with conversationMsgs.slice(-maxConversation). This can split an assistant message containing tool_calls from its corresponding tool role response, causing downstream API 400 errors:
Anthropic: tool_use block without matching tool_result
OpenAI: tool_calls referenced but tool response missing
Steps to reproduce
Build a conversation with 200+ messages where a tool_calls assistant message and its tool response straddle the truncation boundary
Send it through ClawRouter
Observe 400 error from the upstream provider
Expected behavior
Truncation should never split a tool_call/tool_result pair. If one side of the pair falls within the kept window, the other side should be included as well.
Suggested fix
After slicing, scan the boundary:
If the first kept message has role: "tool", walk backwards to include its parent assistant message
If the last dropped message has tool_calls, include its corresponding tool responses