Skip to content

fix(xai-responses): strip enum values containing '/' from tool schemas#28021

Closed
Slimydog21 wants to merge 1 commit into
NousResearch:mainfrom
Slimydog21:slimydog/fix-xai-responses-slash-enum
Closed

fix(xai-responses): strip enum values containing '/' from tool schemas#28021
Slimydog21 wants to merge 1 commit into
NousResearch:mainfrom
Slimydog21:slimydog/fix-xai-responses-slash-enum

Conversation

@Slimydog21

Copy link
Copy Markdown
Contributor

Summary

xAI's /v1/responses and /v1/chat/completions reject tool schemas whose enum values contain a forward slash with a generic HTTP 400 Invalid arguments passed to the model. — emitted as the first SSE frame on the streaming path, surfacing as _StreamErrorEvent and then retry-exhaustion in run_agent.py. The schema compiler trips on the / character regardless of where it appears in the enum value.

This is hit most commonly by MCP-derived tools whose enum lists HuggingFace model IDs (Qwen/Qwen3.5-0.8B, openai/gpt-oss-20b) or owner/name environment identifiers — e.g. the prime-cli lab MCP server's mcp_prime_lab_train_model tool.

Adds a strip_slash_enum sanitizer that mirrors the existing strip_pattern_and_format and is wired up at the same is_xai_responses call site in agent/chat_completion_helpers.py.

Reproduction

Captured the live failure by spying on the request body sent to https://api.x.ai/v1/responses, isolating the single offending tool from a 40-tool request, and bisecting the schema keyword against the live API:

all 40 tools                                       -> 400
each tool individually except mcp_prime_lab_train_model -> 200
mcp_prime_lab_train_model alone                    -> 400
^ same tool with enum: ["foo","bar"]               -> 200
^ same tool with enum: ["Qwen/...","openai/..."]   -> 400

Replayed the captured 78 KB body against the live API with the new sanitizer applied: ✅ 200, real response.

Design notes

  • Drops the whole enum keyword when any value contains /. Keeping a partial enum (slashless values only) would still 400 because xAI's failure is all-or-nothing on the keyword. The field description still reaches the model, so the prompting hint is preserved.
  • Walks both schema shapes. Handles OpenAI-format ({"function": {"parameters": …}}) and Responses-format ({"name": …, "parameters": …}) tool entries.
  • Ignores non-string enum values (integer/boolean enums can't contain /).
  • Idempotent — second pass is a no-op.

Test plan

  • 9 new unit tests covering: HF-style IDs, slashless enums preserved, partial-match → whole-enum stripped, Responses-format tools, anyOf recursion, idempotency, empty/None inputs, non-string enum values.
  • Full tests/tools/test_schema_sanitizer.py suite passes (40/40).
  • End-to-end: hermes chat -q '…' with provider: xai-oauth, model: grok-4.3, and the prime_lab MCP server enabled — fails on main with Invalid arguments, succeeds on this branch.

Files changed

  • tools/schema_sanitizer.py — new strip_slash_enum(tools) -> (tools, count) function.
  • agent/chat_completion_helpers.py — chains the new sanitizer alongside strip_pattern_and_format in the is_xai_responses branch.
  • tests/tools/test_schema_sanitizer.py — 9 new tests.

xAI's /v1/responses and /v1/chat/completions reject tool schemas whose
enum values contain a forward slash with a generic HTTP 400 "Invalid
arguments passed to the model." before any token is emitted — the
schema compiler appears to trip on the '/' character regardless of where
it appears.

Most commonly hit by MCP-derived tools whose enum lists HuggingFace IDs
("Qwen/Qwen3.5-0.8B", "openai/gpt-oss-20b") or owner/name environment
identifiers. Reproduces against the live API; verified by isolating the
single offending tool from a 40-tool request body and bisecting the
schema keyword:

  enum: ["foo", "bar"]                       -> 200
  enum: ["Qwen/...", "openai/..."]           -> 400

Mirrors the existing strip_pattern_and_format sanitizer wired up at the
codex_responses code path for is_xai_responses. The new strip_slash_enum
walks tool parameters and drops the entire enum keyword when any value
contains '/' — keeping it partial would still 400 since xAI's failure is
all-or-nothing on the enum. The field description still reaches the
model so the prompting hint is preserved.

Adds 9 unit tests covering: HF-style IDs, slashless enums (preserved),
partial-match (whole-enum stripped), Responses-format (no `function`
wrapper), anyOf recursion, idempotency, empty/None inputs, and
non-string enum values.
@Slimydog21 Slimydog21 closed this May 18, 2026
@Slimydog21 Slimydog21 reopened this May 18, 2026
@Slimydog21

Copy link
Copy Markdown
Contributor Author

I am a vibe coder and code may be bad; have mercy with me.

Just found out that my PrimeIntellect stuff had some conflicts with the XAI integration.

Hope this is useful to someone ...

@alt-glitch alt-glitch added type/bug Something isn't working provider/xai xAI (Grok) comp/agent Core agent loop, run_agent.py, prompt builder tool/mcp MCP client and OAuth P3 Low — cosmetic, nice to have labels May 18, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #27907 — same fix (strip slash-containing enum values from tool schemas for xAI Responses). #27907 was triaged earlier and covers the same code paths.

@Slimydog21

Copy link
Copy Markdown
Contributor Author

Duplicate of #27907 — same fix (strip slash-containing enum values from tool schemas for xAI Responses). #27907 was triaged earlier and covers the same code paths.

Do I close this PR then? New to this ...

teknium1 pushed a commit that referenced this pull request May 18, 2026
xAI's /v1/responses and /v1/chat/completions endpoints reject tool schemas
whose enum values contain a forward slash with a generic HTTP 400 'Invalid
arguments passed to the model.' before any token is emitted — the schema
compiler trips on the '/' character regardless of where it appears.

Most commonly hit by MCP-derived tools whose enum lists HuggingFace model
IDs ('Qwen/Qwen3.5-0.8B', 'openai/gpt-oss-20b') or owner/name environment
identifiers.

Mirrors the existing strip_pattern_and_format sanitizer (PR for #27197).
The new strip_slash_enum walks tool parameters and drops the entire enum
keyword when any value contains '/' — keeping it partial would still 400
since xAI's failure is all-or-nothing on the enum. The field description
still reaches the model so the prompting hint is preserved.

Wired in at both code paths for parity:
  - agent/chat_completion_helpers.py (main agent xAI Responses path)
  - agent/auxiliary_client.py (aux client xAI Responses path, matching
    the same parity guarantee 2fae8fb established for pattern/format)

Salvaged from #28021 by @Slimydog21 — contributor's branch was severely
stale (would have reverted ~5000 LOC across azure/kanban/i18n); fix
re-applied surgically on current main with their sanitizer + 9 tests
preserved verbatim. Author noreply email used (original was a Mac
hostname leak).
@teknium1

Copy link
Copy Markdown
Contributor

Salvaged via #28122 — same severely-stale-branch situation as #27911/#28003 (would have reverted ~5000 LOC unrelated). Sanitizer + 9 tests preserved verbatim, plus wired in the auxiliary_client.py parity path the verdict noted was missing. You remain the commit author (used noreply email — your original commit leaked a Mac hostname). Thanks!

Lillard01 pushed a commit to Lillard01/hermes-agent that referenced this pull request May 21, 2026
xAI's /v1/responses and /v1/chat/completions endpoints reject tool schemas
whose enum values contain a forward slash with a generic HTTP 400 'Invalid
arguments passed to the model.' before any token is emitted — the schema
compiler trips on the '/' character regardless of where it appears.

Most commonly hit by MCP-derived tools whose enum lists HuggingFace model
IDs ('Qwen/Qwen3.5-0.8B', 'openai/gpt-oss-20b') or owner/name environment
identifiers.

Mirrors the existing strip_pattern_and_format sanitizer (PR for NousResearch#27197).
The new strip_slash_enum walks tool parameters and drops the entire enum
keyword when any value contains '/' — keeping it partial would still 400
since xAI's failure is all-or-nothing on the enum. The field description
still reaches the model so the prompting hint is preserved.

Wired in at both code paths for parity:
  - agent/chat_completion_helpers.py (main agent xAI Responses path)
  - agent/auxiliary_client.py (aux client xAI Responses path, matching
    the same parity guarantee 2fae8fb established for pattern/format)

Salvaged from NousResearch#28021 by @Slimydog21 — contributor's branch was severely
stale (would have reverted ~5000 LOC across azure/kanban/i18n); fix
re-applied surgically on current main with their sanitizer + 9 tests
preserved verbatim. Author noreply email used (original was a Mac
hostname leak).
Mucky010 pushed a commit to Mucky010/hermes-agent that referenced this pull request May 24, 2026
xAI's /v1/responses and /v1/chat/completions endpoints reject tool schemas
whose enum values contain a forward slash with a generic HTTP 400 'Invalid
arguments passed to the model.' before any token is emitted — the schema
compiler trips on the '/' character regardless of where it appears.

Most commonly hit by MCP-derived tools whose enum lists HuggingFace model
IDs ('Qwen/Qwen3.5-0.8B', 'openai/gpt-oss-20b') or owner/name environment
identifiers.

Mirrors the existing strip_pattern_and_format sanitizer (PR for NousResearch#27197).
The new strip_slash_enum walks tool parameters and drops the entire enum
keyword when any value contains '/' — keeping it partial would still 400
since xAI's failure is all-or-nothing on the enum. The field description
still reaches the model so the prompting hint is preserved.

Wired in at both code paths for parity:
  - agent/chat_completion_helpers.py (main agent xAI Responses path)
  - agent/auxiliary_client.py (aux client xAI Responses path, matching
    the same parity guarantee 2fae8fb established for pattern/format)

Salvaged from NousResearch#28021 by @Slimydog21 — contributor's branch was severely
stale (would have reverted ~5000 LOC across azure/kanban/i18n); fix
re-applied surgically on current main with their sanitizer + 9 tests
preserved verbatim. Author noreply email used (original was a Mac
hostname leak).
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
xAI's /v1/responses and /v1/chat/completions endpoints reject tool schemas
whose enum values contain a forward slash with a generic HTTP 400 'Invalid
arguments passed to the model.' before any token is emitted — the schema
compiler trips on the '/' character regardless of where it appears.

Most commonly hit by MCP-derived tools whose enum lists HuggingFace model
IDs ('Qwen/Qwen3.5-0.8B', 'openai/gpt-oss-20b') or owner/name environment
identifiers.

Mirrors the existing strip_pattern_and_format sanitizer (PR for NousResearch#27197).
The new strip_slash_enum walks tool parameters and drops the entire enum
keyword when any value contains '/' — keeping it partial would still 400
since xAI's failure is all-or-nothing on the enum. The field description
still reaches the model so the prompting hint is preserved.

Wired in at both code paths for parity:
  - agent/chat_completion_helpers.py (main agent xAI Responses path)
  - agent/auxiliary_client.py (aux client xAI Responses path, matching
    the same parity guarantee 2fae8fb established for pattern/format)

Salvaged from NousResearch#28021 by @Slimydog21 — contributor's branch was severely
stale (would have reverted ~5000 LOC across azure/kanban/i18n); fix
re-applied surgically on current main with their sanitizer + 9 tests
preserved verbatim. Author noreply email used (original was a Mac
hostname leak).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent loop, run_agent.py, prompt builder P3 Low — cosmetic, nice to have provider/xai xAI (Grok) tool/mcp MCP client and OAuth type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants