Skip to content

[Other] preserve Chat Completions tool result order - #3395

Closed
j-luwierski wants to merge 1 commit into
Niko1221:mainfrom
j-luwierski:codex/chat-tool-results-main-20261020
Closed

j-luwierski wants to merge 1 commit into
Niko1221:mainfrom
j-luwierski:codex/chat-tool-results-main-20261020

Conversation

@j-luwierski

Copy link
Copy Markdown
Contributor

Problem and result

When an OpenAI Chat Completions request contains multiple tool calls and the client returns their tool results in a different order, the serving layer drops the call IDs before rendering the prompt. The model then sees anonymous results in arrival order, even when the results belong to calls with the same function name. The fix restores the call order for complete, unambiguous result runs before removing the temporary IDs.

Related discussion

This follows the closed tracker-reset submission #2952. The new branch is based on current main; the v0.2.0-beta tag is an ancestor of the base revision.

Approach

The Chat Completions conversion retains call IDs only while normalizing a request. It reorders a result run only when call and result IDs are nonempty unique strings with matching sets and counts. Missing, duplicate, unknown, or incomplete IDs keep their received order. IDs are removed before prompt rendering. No engine, template, Anthropic, Responses, or default behavior changes.

Validation

Environment: Linux, Python 3.12.14, dependencies from the repository's pinned requirements.txt.

Passed:

  • Reproduction on unmodified main at 5bda973: /tmp/strata-pr2952-venv/bin/python -m unittest serve.test_chat_tool_results -q ran 7 tests and reproduced 4 failures, including reversed same-function results and the HTTP-to-engine prompt order.
  • Fixed revision 7b87be6: /tmp/strata-pr2952-venv/bin/python -m unittest serve.test_chat_tool_results serve.test_frontend serve.test_server serve.test_responses -q ran 415 tests; OK (skipped=1) in 128.991 seconds.
  • git diff --cached --check passed before commit.

Failed:

  • None on the fixed revision.

Not run:

  • GPU/model inference and CUDA, HIP, SYCL, or Metal builds. This change touches only Python serving code and its tests.

Limits

Only complete, unambiguous tool-result runs are reordered. Incomplete or ambiguous histories preserve their incoming order.

Niko1221 pushed a commit that referenced this pull request Oct 27, 2026
… answer (#3395)

When one assistant message made several tool calls and the client returned the results in another order, the call ids were dropped before the
prompt was rendered, so the model saw anonymous results in the wrong order. The ids are now kept while the request is normalized; a run of
results is reordered to the call order only when the call ids and result ids are non-empty unique strings with matching sets. Anything else
(missing, duplicate, unknown or incomplete ids) keeps the received order, and the ids never reach the template. Ported from PR #3395 by
j-luwierski with its seven tests (serve/test_chat_tool_results.py); the hunk was merged by hand beside require_messages.
@Niko1221

Copy link
Copy Markdown
Owner

Thanks. Confirmed that call ids are dropped before the prompt is rendered. Under review for 0.2.7.

Release: https://github.com/Niko1221/Strata/releases/tag/v0.2.7

MistVVK added a commit to MistVVK/XeStrata that referenced this pull request Oct 30, 2026
1 つの assistant の発言が複数のツールを呼び、クライアントが結果を別の順で返したとき、呼び出しの id は
テンプレートに渡す前に捨てられ、モデルは名前のない結果を違う順で見ていた。要求を直す間は id を保ち、
呼び出しと結果の id が空でない重複のない文字列で集合が一致するときだけ、結果の並びを呼び出しの順に
直す。それ以外(id が無い・重複・不明・欠け)は受けた順のままで、id はテンプレートに渡さない。upstream Niko1221#3395。
ruc1j added a commit to ruc1j/XeStrata-890M that referenced this pull request Oct 31, 2026
…の 1)

serve の変更
- 宣言していない名前の tool call を文のまま返すとき、その名前を strata_rejected_tool_calls で答えに添え、/metrics/prometheus で数える(upstream 805ebe1、Niko1221#3796)
- 名前空間つきの tool は namespace=member、namespace_member、member だけの綴りでも受け、`__` を `_` に潰した綴りも宣言した tool として読む(upstream fd8d37e、805ebe17b、Niko1221#3972)
- Chat Completions の tool の結果を、答えた call の順に並べ直す(upstream 11237f8、Niko1221#3395)
- message のない chat の要求は 400 にする(upstream 8a3ca07)
- --host :: で IPv6 で待ち受ける(upstream eba3106、Niko1221#3212)
- /v1/responses の max_output_tokens は 0 と -1 を上限なしとして受け、答えに timings を付ける(upstream 9c2d35d、a0fc88abd、Niko1221#4036、Niko1221#3291)
- response_format の repair_latex_escapes で、LaTeX のエスケープで壊れた JSON を直してから検査する(upstream 2cc6ea1、Niko1221#2893)
- 1 トークンの答えには decode の速さを出さない(upstream 5d5c26d)
- elastic な画像エンコーダーが起動できなければ 503 を返す(upstream 092c7d1、Niko1221#2435)
- lifeline の識別は子プロセスの開始時刻にし、sampler は壊れた source に耐える(upstream b3db5a1、Niko1221#3590、Niko1221#3407)
- web ページ: 答えを追うのは読み手が離れていないあいだだけ(upstream 89a68d8)、広い窓を使い狭い画面に収める(upstream ad1a310、Niko1221#3176)

setup の変更
- cmake と ninja は venv のものを先に取り、CMakeLists.txt が求める 3.24 より古い cmake は使わない(upstream 5bfce4b、Niko1221#3822)
- 別の generator で configure された build フォルダーは作り直す(upstream bf994ca、Niko1221#4038)
- ダウンロードの長さが取れなければ公開されている大きさを使う(upstream a1d2fd7、Niko1221#2287)
- 2 分データが来ないダウンロードは止まっていると言う(upstream ed0c893、Niko1221#3567)
- --rope-scale は有限で 1 以上の値だけ受ける(upstream a332cc9、Niko1221#3393)
- pip の記録はどの OS が書いたかを覚え、別の OS の記録は信じない(upstream fb3bae2、Niko1221#3634)

tools の変更
- gguf_reader.py はヘッダーの読みに上限を置き、壊れた metadata を ValueError にする(upstream 409f246、Niko1221#2288、Niko1221#1919)
- strata_bench.py は amd-smi しかない ROCm 7 以降でも AMD のカードの名前を書く(upstream c471588、Niko1221#3630)
- calibrate.py は計測の途中でエンジンが落ちても、その候補だけを落として続ける(upstream 41188ec、Niko1221#3317)
- chat.py は端末で fenced code block に色を付ける(upstream 3e81173、PR Niko1221#1895)
- 試験: llama.cpp の gguf-py がなければ test_iq_pack は skip、ほか試験の穴 3 つ(upstream 5b14fe2、Niko1221#3236)

fork に合わせて変えたこと: upstream の docs/DETAILS.md の差分は取らず、文書は別に書く。logprobs(upstream 9ea0449)は fork にすでにあり、allowed_token_ids は見送り。Control(strata_control)に依る setup の変更と、fork にない機能(presets の警告、Delete a model、queue timeout の badge)は取らない。
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.

2 participants