Skip to content

fix: preserve optional tool parameters across Responses and Codex tra… - #4069

Closed
felixfoertsch wants to merge 1 commit into
decolua:masterfrom
felixfoertsch:fix/responses-optional-tool-params
Closed

felixfoertsch wants to merge 1 commit into
decolua:masterfrom
felixfoertsch:fix/responses-optional-tool-params

Conversation

@felixfoertsch

@felixfoertsch felixfoertsch commented Sep 14, 2026 •

Copy link
Copy Markdown

Summary

Preserve Chat Completions function-tool optionality when routing through Responses, including Codex (cx/*). This targets the OpenCode v2 subagent.sessionID failure: omitting the argument creates a child, while supplying it requests a resume.

Two concrete defects found in 0.5.75

  1. open-sse/translator/request/openai-responses.js already preserves parameters.required, but forwards an omitted function.strict as undefined. JSON serialization removes that field. Chat Completions is non-strict by default, whereas Responses can normalize omitted strictness into strict mode, making optional fields required.
  2. open-sse/executors/codex.js::normalizeCodexTools rebuilds each function declaration and discards strict, including explicit false and true. A translator-only fix is therefore insufficient for cx/*.

OpenAI documentation: https://developers.openai.com/api/docs/guides/function-calling#strict-mode

The user-reported direct-versus-routed OpenCode result is consistent with these defects. This PR does not claim a live reproduction of model behavior or OpenCode child creation.

Changes

  • Emit strict: tool.function.strict ?? false when translating Chat Completions function declarations.
  • Capture and restore strictness while rebuilding Codex function tools.
  • Default nested Chat-shaped tools reaching the executor to non-strict, while retaining the existing defaults for native flat Responses tools.
  • Leave parameter schemas and existing required arrays unchanged; do not derive required fields from property names or silently repair explicitly strict schemas.
  • Do not inject, remove, or replace sessionID in returned arguments. Legitimate resume IDs remain intact.

Regression coverage

Adds tests/unit/openai-responses-optional-params.test.js with 26 cases covering:

  • Optional sessionID; absent and empty required; nested objects, arrays, unions, and definitions; parameter-less functions.
  • Explicit strict values, Chat default handling, native Responses defaults, and nested Chat tool normalization.
  • Serialized outbound tool declarations, idempotence, input-schema preservation, and hosted/custom/namespaced tools.
  • Replayed arguments and synthetic streamed arguments, both fragmented deltas and done-only payloads, for omitted and supplied child IDs.

The synthetic streaming fixtures verify transport fidelity, not actual model argument selection or OpenCode execution.

Validation performed

In the available offline environment, the same 26 test assertions were run using Node 22's native test runner against the fetched production translator/executor source and the extracted production response-conversion function. External I/O and unrelated provider configuration dependencies were replaced by isolated adapters; helper behavior was copied from the inspected source.

Version Passed Failed
Original 0.5.75 8 18
Translator change alone 8 18
Both changes 26 0

node --check and git diff --check passed. Final GitHub blob hashes match the locally validated files.

Not run: the normal Vitest dependency graph, full repository suite/build, live Codex inference, or the OpenCode acceptance probe. Dependencies could not be installed in this environment. This PR remains a draft pending normal integration validation.

From a full checkout with dependencies installed, run:

cd tests
npm test -- unit/openai-responses-optional-params.test.js

Live acceptance still required

Using OpenCode v2 2.0.3, rerun the original identical probe through 9router/cx/gpt-5.6-sol after building and deploying this branch. Retain the direct-provider control.

  • Captured final provider request has strict: false for the translated subagent function, and its original required array does not include sessionID.
  • The new-child call's captured rawInput lacks sessionID entirely, not merely null or an empty string.
  • A real child session is created; the output contains its returned session ID and ROUTED-SUBAGENT-OK.
  • An explicit valid child sessionID can still resume that child.

No changes to OpenCode's parent/child validation are proposed. No automatic merge, deployment, or upstream issue/PR is included.

…nslation

Default translated Chat Completions function tools to strict:false without
rewriting their parameters or required arrays. Preserve strict through
Codex tool normalization, which previously discarded even explicit values.
Keep native Responses defaults and explicit strict:true requests intact.

Add 26 regression cases for optional sessionID, absent/empty/nested required,
strict handling, normalization idempotence, and streamed/replayed arguments.
Live OpenCode subagent acceptance remains to be verified.
Copilot AI lite review requested due to automatic review settings September 14, 2026 21:50

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

paopaonyapi-creator pushed a commit to paopaonyapi-creator/9router that referenced this pull request Sep 14, 2026
Port five still-open decolua PRs onto v0.5.75: drop Claude <think> tags
from OpenAI content (decolua#4063), keep Responses tool-output images as images
(decolua#4058), preserve optional tool params / Chat strict:false (decolua#4069), skip
account cooldown on request-scoped 4xx (decolua#4059), and declare Cline Solar
Pro/LongCat before the o-series globs (decolua#4064). Also pin in-range patch
deps (next 16.3.5, jose, marked, undici, …) and drop the stale 20127
comment in CLAUDE.md.

Targeted suite 55/55; regression gate still clean (22 known fails).
Primexz added a commit to Primexz/9router that referenced this pull request Sep 15, 2026
Merge upstream pull request decolua#4069 so optional function-tool parameters remain optional across Responses-to-Chat and Codex translation paths.

The change defaults translated Chat Completions tools to strict false without rewriting schemas, preserves explicit strict values through Codex normalization, and keeps native Responses behavior intact. It also adds focused regression coverage for required fields, nested schemas, normalization, and streamed or replayed arguments.

Verification performed: 39 related Vitest assertions passed across the new optional-parameter suite and existing Codex normalization and Responses custom-tool suites, npm run build completed successfully with Next.js 16.3.5, and git diff --check completed successfully.
@forggy0113

forggy0113 commented Sep 23, 2026 •

Copy link
Copy Markdown

Hi, just following up on this PR. I’m experiencing the same issue, and I’ve tested this PR locally — the fix works for me.
Would it be possible to review and merge this when you have a chance? This fix would really help with my use case. Thanks!

Tested this patch on 9router v0.5.86 with OpenCode v2.0.15 via the Codex/Responses route. Before the patch, creating a subagent failed with Subagent session not found: ses_invalid; after rebuilding and running the patched image, creating a new subagent succeeds.

@felixfoertsch felixfoertsch closed this by deleting the head repository Oct 1, 2026
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.

3 participants