test(responses): cover real failing-turn shape from #103483

Fixture by @cristianbdev (content-redacted replay of the failing turn):
no invented blank carrier, every reasoning followed by its
function_call, all five call/output pairings preserved.
This commit is contained in:
actualrat1984
2026-09-16 01:08:07 -03:00
committed by Teknium
parent 1c7bc44eda
commit f33624c58a
2 changed files with 123 additions and 0 deletions

View File

@@ -4,6 +4,9 @@ Regression investigation for #103483: synthetic Muse tool-loop A/B reproduction.
Also covers #75202: the lone-reasoning follower must be non-empty for strict
Responses-compatible providers that reject "" with 400.
"""
import json
from pathlib import Path
import pytest
from agent.codex_responses_adapter import _chat_messages_to_responses_input
@@ -29,3 +32,32 @@ def test_reasoning_without_tool_keeps_nonempty_following_item():
'encrypted_content': 'synthetic-encrypted-fixture', 'summary': []}],
}])
assert items[-1] == {'role': 'assistant', 'content': ' '}
def test_failing_turn_fixture_emits_no_invented_carrier():
"""Real failing-turn shape from #103483 (fixture by @cristianbdev, see
https://gist.github.com/cristianbdev/6036f7aa3838935adfaeb9b6800f7450 —
3 reasoning+tool assistant rows, 5 tool calls/outputs, content redacted).
The adapter must invent no blank carrier, must keep every reasoning item
directly followed by a function_call, and must preserve all call/output
pairings.
"""
fixture_path = (
Path(__file__).resolve().parent.parent
/ "fixtures" / "spark_failing_turn_shape.json"
)
messages = json.loads(fixture_path.read_text(encoding="utf-8"))
items = _chat_messages_to_responses_input(messages)
assert {"role": "assistant", "content": ""} not in items
for i, item in enumerate(items):
if item.get("type") == "reasoning":
# Reasoning items may cluster; the next non-reasoning item after
# each of them must be the function_call that follows it — never
# an invented blank assistant message.
nxt = next(it for it in items[i + 1:] if it.get("type") != "reasoning")
assert nxt.get("type") == "function_call"
calls = [item["call_id"] for item in items if item.get("type") == "function_call"]
outputs = [item["call_id"] for item in items if item.get("type") == "function_call_output"]
assert len(calls) == 5
assert sorted(calls) == sorted(outputs)

View File

@@ -0,0 +1,91 @@
[
{
"role": "user",
"content": "Investigate the installed 'agy' CLI and summarize its version and capabilities in one report."
},
{
"role": "assistant",
"content": "",
"codex_reasoning_items": [
{"type": "reasoning", "id": "rs_fixture_01", "summary": [{"type": "summary_text", "text": "Batched three tool calls to inspect the CLI."}], "encrypted_content": "synthetic-encrypted-content-placeholder-0001-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},
{"type": "reasoning", "id": "rs_fixture_02", "summary": [], "encrypted_content": "synthetic-encrypted-content-placeholder-0002-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"}
],
"tool_calls": [
{
"id": "call_fixture_01",
"call_id": "call_fixture_01",
"type": "function",
"function": {"name": "terminal", "arguments": "{\"command\": \"which agy; agy --version\"}"}
}
]
},
{
"role": "tool",
"tool_call_id": "call_fixture_01",
"content": "[tool output elided — 11,269 chars in the original failing run]"
},
{
"role": "assistant",
"content": "",
"codex_reasoning_items": [
{"type": "reasoning", "id": "rs_fixture_03", "summary": [], "encrypted_content": "synthetic-encrypted-content-placeholder-0003-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"},
{"type": "reasoning", "id": "rs_fixture_04", "summary": [], "encrypted_content": "synthetic-encrypted-content-placeholder-0004-DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"}
],
"tool_calls": [
{
"id": "call_fixture_02",
"call_id": "call_fixture_02",
"type": "function",
"function": {"name": "terminal", "arguments": "{\"command\": \"agy agent --help\"}"}
}
]
},
{
"role": "tool",
"tool_call_id": "call_fixture_02",
"content": "[tool output elided — 3,169 chars in the original failing run]"
},
{
"role": "assistant",
"content": "",
"codex_reasoning_items": [
{"type": "reasoning", "id": "rs_fixture_05", "summary": [], "encrypted_content": "synthetic-encrypted-content-placeholder-0005-EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"}
],
"tool_calls": [
{
"id": "call_fixture_03",
"call_id": "call_fixture_03",
"type": "function",
"function": {"name": "terminal", "arguments": "{\"command\": \"agy mcp --help\"}"}
},
{
"id": "call_fixture_04",
"call_id": "call_fixture_04",
"type": "function",
"function": {"name": "terminal", "arguments": "{\"command\": \"agy changelog | head -40\"}"}
},
{
"id": "call_fixture_05",
"call_id": "call_fixture_05",
"type": "function",
"function": {"name": "terminal", "arguments": "{\"command\": \"ls ~/.config/agy/ 2>&1 || true\"}"}
}
]
},
{
"role": "tool",
"tool_call_id": "call_fixture_03",
"content": "[tool output elided — 1,494 chars in the original failing run]"
},
{
"role": "tool",
"tool_call_id": "call_fixture_04",
"content": "[tool output elided — 32,686 chars in the original failing run]"
},
{
"role": "tool",
"tool_call_id": "call_fixture_05",
"content": "[tool output elided — 598 chars in the original failing run]"
}
]