Skip to content

fix(opencode-go): route muse-spark-1.3-contributor over Responses with Zen Go tool-surface guards - #1

Closed
guhcostan wants to merge 1 commit into
devfrom
fix/muse-spark-1-3-zen-go-compat
Closed

fix(opencode-go): route muse-spark-1.3-contributor over Responses with Zen Go tool-surface guards#1
guhcostan wants to merge 1 commit into
devfrom
fix/muse-spark-1-3-zen-go-compat

Conversation

@guhcostan

Copy link
Copy Markdown
Owner

Summary

Makes opencode-go/muse-spark-1.3-contributor usable through the proxy (it 400/500'd on every Codex request before):

  • Registry (src/providers/registry.ts): route 1.3 over openai-responses (probed 2026-09-02: /chat/completions -> upstream 500, /responses -> 200), declare its real effort ladder (none..xhigh, no max rung per the gateway error message), and map Codex max -> xhigh so default-max callers stop taking a gateway 400.
  • Adapter (src/adapters/openai-responses.ts): generalize the 1.2-only Muse Spark guards to 1.3 via a shared isMuseSparkGatewayModel predicate (matches bare or provider/-namespaced ids), and add two outbound-only guards for limits Zen Go enforces but OpenAI tolerates in practice here:
    • drop function/custom declarations with names > 64 chars (Codex MCP tools reach 67 chars; whole turn 400'd otherwise),
    • drop function declarations with cyclic local $ref schemas (Recursive JSON schemas are not currently supported; diamond $refs sharing one $defs entry are kept). A tool_choice naming a dropped tool falls back to auto.
  • Tests: extend tests/muse-spark-web-search-compat.test.ts (1.3 strip, registry wire default, name-length drop/keep/additional_tools/tool_choice, cyclic-drop/diamond-keep/scoping).

Out of scope on purpose: context-window / modality claims for 1.3 (unverified), and the unrelated Codex-CLI websocket UX.

Verification

  • bun test tests/muse-spark-web-search-compat.test.ts — 13 pass, 0 fail (6 new assertions failed before the source change = RED, pass after).
  • bun run typecheck — clean.
  • bun run privacy:scan — passed (new logs emit counts + dropped tool names only, no bodies/keys).
  • bun run test:changed — 14071 pass / 11 skip / 1 fail; the single failure (codex-shim.test.ts lease-fd timing) passes isolated both with and without this change, so it reads as load flakiness, not a regression.
  • Live end-to-end against a local proxy running this branch: codex exec with opencode-go/muse-spark-1.3-contributor and -1.2-contributor return OK (previously 500/400), gpt-5.6-sol still OK, and a real shell-tool round trip on 1.3 completes.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed. (No user-facing config surface changes; behavior fix only.)
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults. (No auth/credential paths touched; drops are outbound-only declaration filters.)

@guhcostan

Copy link
Copy Markdown
Owner Author

Opened against the fork by mistake; superseded by lidge-jun#3312.

@guhcostan guhcostan closed this Sep 2, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T23:27:32.244591Z 1c4c994 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1c4c9946bd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (!node.$ref.startsWith("#/") && node.$ref !== "#" && node.$ref !== "#/") return false;
const target = lookupLocalJsonPointer(root, node.$ref);
if (target === undefined) return false;
return visit(target, [...stack, node.$ref]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Bound the local-reference walk

For a Muse request with a long but acyclic local $ref chain—for example, thousands of shallow $defs entries that each reference the next—visit recurses once per reference without any depth or node budget. Such JSON remains shallow enough to parse and serialize, but this walk can exhaust Bun's call stack before the upstream request is built, turning a caller-controlled tool schema into a failed request or process crash. Use the bounded/iterative schema-walk pattern already employed by the other adapter schema normalizers.

Useful? React with 👍 / 👎.

Comment on lines +1985 to +1988
function isMuseSparkGatewayModel(modelId: unknown): boolean {
const normalized = typeof modelId === "string" ? modelId.trim().toLowerCase() : "";
const base = normalized.includes("/") ? normalized.split("/").pop() ?? normalized : normalized;
return base === "muse-spark-1.2-contributor" || base === "muse-spark-1.3-contributor";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep Zen Go guards scoped to Zen Go

This predicate checks only the model ID, while its callers run for every noncanonical Responses provider. Consequently, a custom provider serving muse-spark-1.2-contributor or muse-spark-1.3-contributor at a different gateway will also lose long-named and recursive-schema tools even if that gateway accepts them; the restriction was only established for the Zen Go destination. Pass the provider into this guard and require the Zen Go base URL before mutating the tool surface.

AGENTS.md reference: src/AGENTS.md:L19-L19

Useful? React with 👍 / 👎.

Comment on lines +2074 to +2075
if (isPlainObject(next.tool_choice) && typeof next.tool_choice.name === "string" && dropped.has(next.tool_choice.name)) {
next = { ...next, tool_choice: "auto" };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reconcile allowed_tools after dropping declarations

When the caller uses an allowed_tools selector, the removed function name is nested under tool_choice.tools[], so this direct .name check does nothing; the identical check in the recursive-schema filter has the same problem. The outgoing request therefore retains a selector for an omitted tool—and for the length case still contains the rejected over-64-character name—so Zen Go can return the same 400 this guard was intended to prevent. Reconcile both direct and allowed_tools choices, preserving remaining entries and refusing a required choice when none remain.

AGENTS.md reference: src/AGENTS.md:L19-L19

Useful? React with 👍 / 👎.

}
if (dropped.size > 0) {
// eslint-disable-next-line no-console
console.warn(`[opencodex] muse-spark: dropped ${dropped.size} tool(s) with recursive schemas rejected by Zen Go: ${[...dropped].join(", ")}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not log caller-supplied tool names

Whenever a recursive schema is dropped, this warning writes the exact caller-controlled tool.name field from the request body into persistent process/service logs. MCP tool names can contain server, workspace, tenant, or account-derived identifiers, so this violates the repository's prohibition on logging request-body/account data; emit only the count or use the existing redacted diagnostic mechanism.

AGENTS.md reference: AGENTS.md:L345-L346

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant