Repository navigation
[Bug]: Flattened tool names exceed 64-char gateway limits (Command Code 400: "name must be at most 64 characters, got 66") #4679
Description
Client or integration
opencodex 2.55.0 (@bitkyc08/opencodex, Docker node:22-slim) running as the Responses→Chat translation proxy in front of the Command Code provider (api.commandcode.ai, openai-chat adapter). Client: Codex Desktop / codex-cli 0.153.x.
Summary
When a Codex client declares many MCP/app tools, namespace-tool-compat flattens namespaced tools to <namespace>__<name> for chat gateways. Some strict gateways cap function names at 64 characters. Command Code's AI gateway rejects the whole request before inference:
{"error":{"message":"`name` must be at most 64 characters, got 66","type":"invalid_request_error"}}The 66-char name in that gateway error is mcp__codex_apps__codex_document_control___execute_document_command. Other real offenders (Codex Desktop built-in app tools — the user cannot exclude them from the bundle):
mcp__codex_apps__codex_document_control___get_document_tool_schemas(67)mcp__codex_apps__safety_settings___prepare_parental_control_update(65)
This bites exactly on Responses-Lite catalogs (use_responses_lite: true), where the client bundles every declared tool into the additional_tools input item — there is no way to shrink the surface from config.
Reproduction
- Run opencodex 2.55.0 behind any client with the standard Codex Desktop tool set, routed to Command Code.
- Send any turn with
use_responses_lite: true. - → 400
name must be at most 64 characters, got 66from the gateway; the turn fails.
Suggested fix
A bounded, deterministic, reversible alias at the single point where wire names are produced — namespacedToolName() / dottedToolName() in src/types/tools.ts — so declarations, history replay, toolNsMap/declaredToolNames (built in server/responses/collaboration.ts) and the undeclared-tool guard all stay consistent, and provider echoes restore to the native {namespace, name} automatically:
// alias = flat.slice(0, 64 - 13) + "_" + sha256(`${ns ?? ""}\0${name}\0${attempt}`).slice(0, 12)- stable across restarts (digest of the native identity, not declaration order);
- collision-safe loop (claimed-alias set,
attemptbump); - no dotted spelling for a bounded alias (it is already at the limit);
- restore falls out for free because the bridge keys
toolNsMapby the same function's output.
Precedent: codex-router special-cases exactly this as BOUNDED_TOOL_NAME_PROVIDERS = {"commandcode", "commandcode-messages"} with BOUNDED_TOOL_NAME_LENGTH = 64 (src/chat-tool-surface.mjs + deterministic truncate+digest aliases in src/namespace-relay.mjs).
Version
opencodex 2.55.0 (@bitkyc08/opencodex npm).
Operating system
Linux (Docker, node:22-slim) for the proxy; macOS 26 arm64 for the Codex client.
A PR implementing the suggested fix is up and validated in production: #4715. A long-name tool round-trips (function_call returns with namespace: "mcp__codex_apps__safety_settings" restored), and a meta/muse-spark-1.3 root session spawned a deepseek-v4.1-flash subagent end-to-end through Command Code.
Activity
github-actions commentedon Sep 15, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
[-]Flattened tool names can exceed 64-char gateway limits (Command Code 400: "name must be at most 64 characters, got 66")[/-][+][Bug]: Flattened tool names exceed 64-char gateway limits (Command Code 400: "name must be at most 64 characters, got 66")[/+]lidge-jun commentedon Sep 15, 2026
리뷰 · 우선순위 70 / 80
이 이슈는 Codex Desktop / Responses-Lite 가 MCP·앱 도구를 많이 실어 보낼 때, OpenCodex 가 이름공간 도구를
<namespace>__<name>로 납작하게 만든 뒤 Command Code(api.commandcode.ai, openai-chat 어댑터) 게이트웨이로 넘기면 함수 이름 길이 상한 64자를 넘겨 HTTP 400 이 난다는 실사용 버그다. 본문에 나온 예시는 전부 Codex 내장 앱 도구이고 사용자가 카탈로그에서 빼기 어렵다. 예:mcp__codex_apps__codex_document_control___get_document_tool_schemas(67자). 재현 조건은use_responses_lite: true와 표준 Desktop 도구 묶음이면 충분하고, 보고 버전이 2.55.0 이어도 지금dev(HEAD3ea88f3db, 패키지 2.56.0) 에서도 같은 납작화 경로가 그대로다.현재
dev를 보면 비슷한 문제는 이미 한 경로만 막혀 있다. #4422 가 머지한src/responses/muse-tool-name-alias.ts는 64자·문자셋 제한에 맞춰 충돌 없는 해시 별칭을 만들고 왕복 복원까지 한다. 그런데 게이트는isMetaAiResponsesDestination이라 호스트가api.meta.ai일 때만 켜진다. Command Code 프리셋(commandcode→https://api.commandcode.ai/provider/v1, adapteropenai-chat) 은 그 게이트 밖이라 #4422 혜택을 받지 못한다. 와이어 이름은 여전히src/types/tools.ts의namespacedToolName/dottedToolName과src/responses/namespace-tool-compat.ts· openai-chattool-schema.ts가 그대로 길게 만든다.작성자 제안(네이티브 정체성 해시 + 선언·히스토리·
toolNsMap일관 별칭)은 방향이 맞다. 다만 전역으로namespacedToolName자체를 무조건 자르면 Meta Muse 전용 복원 맵·Kiro 정규화·점(.) 별칭 계약과 어긋날 수 있다. 더 안전한 축은 (1) muse 별칭 모듈을 “64자 제한 게이트웨이” 공통 레이어로 일반화하고 Command Code /commandcode호스트를 포함시키거나, (2) openai-chat outbound 한곳에 provider 플래그로 같은 플랜을 거는 것이다. 본문에 “PR이 올라와 프로덕션 검증됐다”고 적혀 있으나 이 저장소 open PR 목록과 #4679 타임라인에는 연결된 PR 번호가 없다. 포크 PR이면 여기로 링크해 달라는 상태다. types.ts/config.ts 스플릿·godfile facade 와는 무관해서 close-don't-rebase 대상이 아니다.라인 / 경로 수준:
라인 30–32 (
src/types/tools.tsnamespacedToolName) - 길이 상한 없이namespace__name만 만든다. Chat 게이트웨이 64자 거절의 직접 입력이다라인 41–43 (
dottedToolName) - 점 별칭도 같은 길이 문제를 공유한다. 전역 truncate 를 넣으면 별칭 이중 등록을 조심해야 한다라인 16–21 · 245+ (
src/responses/muse-tool-name-alias.ts) - #4422 해결책이 이미 있다. 게이트가api.meta.ai전용이라 Command Code 에 안 닿는다라인 330–331 (
src/adapters/openai-responses/passthrough.ts) - Responses passthrough 에서만 muse rewrite 호출. openai-chat Command Code 경로는 여기 안 탄다경로
src/providers/registry/entries-extended.tsid: "commandcode"- adapteropenai-chat, baseUrlapi.commandcode.ai/provider/v1. 이슈 재현 프리셋과 일치한다경로
src/adapters/openai-chat/tool-schema.ts- 선언 시namespacedToolName을 그대로 name 필드에 넣는다. 별칭 플랜이 없다면 66자 이름이 그대로 나간다메인테이너의 판단이 필요한 지점
namespacedToolName전역에 넣을지(작성자 제안) vs outbound 어댑터에서만 넣을지(기존 fix(responses): alias tool names over 64 chars for Meta Muse wire compatibility #4422 패턴)additional_tools전체 번들 축소(설정으로 줄이기)는 우회일 뿐 근본 수정이 아니다 — 제품 방향으로 둘지너의 추천
이슈는 유효하고 우선순위 높게 둔다. 먼저 작성자에게 이 레포 PR 링크를 요청하고, 없으면 #4422 의
muse-tool-name-alias패턴을 Command Code(api.commandcode.ai/commandcodeopenai-chat)까지 확장하는 단일 수정 PR을 받는 쪽을 권한다.namespacedToolName전역 truncate 는 다른 프로바이더 계약을 깨기 쉬우니 기본안으로 두지 말 것. 중복 이슈·types/config 무효화로 닫을 대상이 아니다. PR이 오면 선언·히스토리 리플레이·undeclared-tool 가드·복원 맵이 한 플랜을 쓰는지와 66→≤64 왕복 회귀 테스트만 확인하면 된다.이 댓글은 grok-bot이 작성했습니다
fix: collapse duplicate tool choice alias for bounded names (lidge-ju…
HulianBuligon commentedon Sep 15, 2026
The PR is up: #4715 (fork PR from
HulianBuligon:fix/bounded-tool-wire-names→dev, 2 commits).On the design question (global bound in
namespacedToolNamevs the #4422 muse-alias pattern gated per provider): I went with the single-point bound deliberately, for two reasons:namelimit is 64. A flattened name over 64 is already invalid on the most common strict consumer, so bounding it at the name-producing function matches the format's contract rather than any one provider's policy.buildToolBridgeMaps, the undeclared-tool guard and history replay — five surfaces — whilebuildToolBridgeMapskeys the restore map by this same function's output, so restoration stays free of extra plumbing.On the interaction with #4422's
muse-tool-name-alias: in the Meta destination path my bound runs first, so that module now sees ≤64 names — strictly less work, no contract change. If you still prefer provider-gating, I'm happy to rework #4715 along those lines.Since the review: pushed 8f6fa49 collapsing the duplicate
toolChoiceAliasesentry for bounded aliases ([alias, alias] → [alias]) with a regression test — suite is now 5 pass / 0 fail.HulianBuligon commentedon Sep 15, 2026
Production datapoint from the same setup (opencodex behind a routing proxy → Command Code,
meta/muse-spark-1.3as the root model on the v2 surface) that strengthens the case for widening the #4422 bare/dotted echo acceptance to thecommandcodedestination:Observed live today — during a root turn that spawned two subagents (
deepseek-v4.1-flash+muse-spark-1.3), Command Code's muse echoed the spawn tool call with the bare name:The declared wire names on that request were the flattened forms (
collaboration__spawn_agent, plus the unambiguous dotted aliascollaboration.spawn_agent). The guard's fail-closed rejection killed the stream mid-turn, the Codex client showed "Reconnecting 1/5" and re-sent the whole turn; the retry succeeded (both subagents completed). So it self-heals, but every occurrence costs a full round-trip plus a re-send of the entire context.This matches the exact quirk
muse-tool-name-alias.ts(#4422) exists for — the muse family dropping/altering the namespace spelling on echo — currently gated toapi.meta.aidestinations only, whilecommandcode(api.commandcode.ai, openai-chat) goes through the strict guard.Two candidate shapes, in increasing scope:
collectAmbiguousDottedAliases/buildToolBridgeMaps— bare names are only claimed forfunctions-namespace children today).muse-tool-name-alias's destination gate to includeapi.commandcode.ai/ thecommandcodeprovider id.Happy to fold either into #4715 as a follow-up commit or split it into a second PR — your call on the preferred shape.
fix: two-way wire-name claims and registry cap for bounded aliases
fix: accept unambiguous bare tool-name echoes for namespaced tools (l…
fix: accept unambiguous bare tool-name echoes for namespaced tools (l…
fix: accept unambiguous bare tool-name echoes for namespaced tools (l…
Merge pull request #4774 from lidge-jun/codex/pw5-bounded-tool-wire-n…
lidge-jun commentedon Sep 16, 2026
Landed via #4774 at 6151ff4
fix(openai-chat): bound flattened tool wire names for strict gateways (…
fix(responses): keep the selector identity alias while fencing the de…
fix(openai-chat): bound flattened tool wire names for strict gateways (…
Merge pull request lidge-jun#4774 from lidge-jun/codex/pw5-bounded-to…