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:
@@ -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)
|
||||
|
||||
91
tests/fixtures/spark_failing_turn_shape.json
vendored
Normal file
91
tests/fixtures/spark_failing_turn_shape.json
vendored
Normal 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]"
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user