Skip to content

fix(auxiliary): route Codex Responses path through shared converter (#5709)#41714

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-703737c0
Jun 8, 2026
Merged

fix(auxiliary): route Codex Responses path through shared converter (#5709)#41714
teknium1 merged 1 commit into
mainfrom
hermes/hermes-703737c0

Conversation

@teknium1

@teknium1 teknium1 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Auxiliary Codex Responses calls no longer crash with HTTP 400: Invalid value: 'tool' when replaying session history that contains tool results.

Root cause: agent/auxiliary_client.py::_CodexCompletionsAdapter.create() maintained its own chat→Responses conversion loop that forwarded every non-system message's role verbatim into Responses input[]. When flush_memories() / context compression replayed real session history (assistant tool_calls + role="tool" results), those tool messages leaked into the request and the Responses API rejected them. The main agent transport already converts tool history correctly — the auxiliary path was a second, divergent converter.

Changes

  • agent/auxiliary_client.py: route _CodexCompletionsAdapter.create() through the shared _chat_messages_to_responses_input() (the same converter agent/transports/codex.py uses). Assistant tool calls → function_call items, tool results → function_call_output items with a valid call_id. The async adapter delegates to this sync path, so it's covered too. Single conversion path = no future drift (the issue's explicit scope).
  • tests/agent/test_auxiliary_client.py: regression tests — tool history never leaks role=tool, becomes function_call/function_call_output with matching call_id; plain-text history still works; system → instructions.
  • scripts/release.py: AUTHOR_MAP entry for the contributor.

Validation

Before After
role="tool" in Responses input[] yes → HTTP 400 none
tool result encoding raw role=tool function_call_output + call_id
assistant tool_call encoding dropped/raw function_call + call_id

Targeted: 49 Codex auxiliary tests pass (incl. 2 new regression tests). E2E: fed realistic system+user+assistant(tool_calls)+tool+assistant history through the adapter, captured the responses.create payload, confirmed no role=tool and correct function_call/function_call_output items.

Closes #5709. Salvages the approach from #5711 (@ProgramCaiCai, issue author) — reimplemented on current main to reuse the existing canonical converter in agent/codex_responses_adapter.py rather than introducing a new module. Co-authored credit preserved.

Infographic

responses-api-tool-role-fix

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent loop, run_agent.py, prompt builder provider/openai OpenAI / Codex Responses API codex labels Jun 8, 2026
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-703737c0 vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 10067 on HEAD, 10067 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 5221 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

…5709)

The auxiliary Codex adapter maintained its own chat->Responses conversion
loop that forwarded every non-system message's role verbatim into
Responses input[]. When flush_memories()/compression replayed session
history containing assistant tool_calls + role=tool results, those tool
messages leaked into the request and the Responses API rejected them with
HTTP 400: Invalid value: 'tool'.

Route _CodexCompletionsAdapter.create() through the same shared converter
the main agent transport uses (_chat_messages_to_responses_input), so tool
calls become function_call items and tool results become function_call_output
items with a valid call_id. Single conversion path means no future drift.

Also remove the now-dead _convert_content_for_responses() helper — its only
caller was the private conversion loop this change deletes.

Co-authored-by: ProgramCaiCai <techxacm@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex comp/agent Core agent loop, run_agent.py, prompt builder P2 Medium — degraded but workaround exists provider/openai OpenAI / Codex Responses API type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Responses API paths should never replay tool messages with role=tool

2 participants