Repository navigation
Conversation
|
Field data point, and a rebase in case it saves time. RTX 5090 Laptop 24 GB, Ubuntu, Strata v0.2.9 / engine 0.1.55 built from source with this PR applied. Live v0.2.10 still needs it, and the branch now conflicts. The conflicts are small: the |
A client may send tool_result blocks in the order its tools finished, and Claude Code does for parallel calls. The ids were dropped here, so a result landed on the wrong call with no error. Chat's reorder pass now runs here too, on tool_use_id. A request already in order, or with incomplete or ambiguous ids, renders as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W53iURzvDQMjnYemag8uvv
b669ca1 to
771f714
Compare
|
Thank you, @Tsury, for the run on the 5090 and for the rebase. I rebased the branch onto current Passed (mock engine, no GPU): Failed: Not run: the rebased branch on a real engine. Written with an AI agent (Claude Code), which also ran the steps above. |
Problem and result
On
/v1/messages, Strata droppedtool_use_idand renderedtool_resultblocks in the order they arrived. The templates pair results with calls by position. So when a client sent results in a different order from the calls, each result landed on the wrong call, with no error. When both calls use the same tool, the model cannot tell them apart.A listed client hits this. Claude Code 2.1.316 sends results in the order its tools finish. With two parallel Grep calls against a local mock of
/v1/messages:[toolu_B_fast, toolu_A_slow], call order[toolu_A_slow, toolu_B_fast], in 3 of 3 runs.The Anthropic docs allow this order and say how to pair results (parallel tool use):
Before and after, on the captured Claude Code request. The calls are slow Grep, then fast Grep:
1:FASTFILE(the fast result) first, thenNo files found.No files foundfirst, then1:FASTFILE, which is call order.Related discussion
Approach
Chat already has a reorder pass,
_order_chat_tool_results. This change gives it the ids on the Anthropic path and calls it there. The helper itself is not changed./v1/messages/count_tokensuses the same converter. On the captured request it returned 51508 tokens on both the base and the branch, because only the order moves.Validation
Revision: b669ca1 on base c62d5e3. Linux, Python 3.12.3. MockEngine, except the real-engine check, which comes first below.
Passed:
Real engine: RTX 5080 16 GB, engine 0.1.55 from release v0.2.9, Qwen3.8 IQ3_S, context 65536,
anthropicSDK 2.3.0, non-stream, thinking off, temperature 0. A two-callget_weatherround trip, Paris then Tokyo, with invented temperatures that change every run and a different sky per city. An answer counts as swapped when each city has the other's temperature.On the branch, the model made both calls itself in all 8 runs. On the base it did so in 7 of 8. In reversed run 0 it made only the Paris call, so that assistant turn was constructed, with both calls. That run still swapped. Base and branch ran in separate server sessions.
python -m unittest serve.test_anthropic_tool_results: 10 tests, OK. The same file on c62d5e3: 6 of the 10 tests fail. unittest reportsfailures=7because the HTTP test has a non-stream and a stream subtest. The tests cover both templates by direct render and non-stream and stream over HTTP.Base against branch over HTTP, using a local script that is not in the repo. It compares status, content type, normalized body and the prompt the engine received. 12 requests, each sent non-stream and stream, so 24 variants:
/v1/messageswith text, system, thinking on and off, tools, ordered results, ordered results with text, incomplete results and an unknown id;/v1/chat/completionswith text and ordered results; and one reversed request.anthropicSDK 2.3.0 sending reversed results to a MockEngine server, using a local script: on the branch, non-stream and stream both reach the engine in call order. On the base, both stay reversed.Replay of the captured Claude Code request, using a local script: HTTP 200 on the default template, with the before and after shown above. The DeepSeek template, rendered directly from the converted messages and not through the server, gives the same before and after.
Failed:
Ran 479 tests:
FAILED (failures=1, skipped=1). The one failure isserve.test_server.GpuChoice.test_hip_ordinal:AssertionError: '0,1' != '1,0'. That test alone fails the same way on c62d5e3.Not run:
Limits
🤖 Generated with Claude Code
https://claude.ai/code/session_01W53iURzvDQMjnYemag8uvv