Repository navigation
fix(opencode-zen): align free-tier v2 fingerprint with PR #4860 - #1
Conversation
Reviewer's GuidePorts the OpenCode Free-tier v2 fingerprint changes into the Zen executor while retaining its existing endpoints, centralizing canonical tool handling, updating client/session headers, and adding focused unit tests for the new request shape. Sequence diagram for OpenCode Zen request fingerprintingsequenceDiagram
participant Client
participant ZenExecutor as OpenCodeZenExecutor
participant Fingerprint as applyFingerprintTools
participant ZenAPI as OpenCodeZenAPI
Client->>ZenExecutor: prepareRequestHeaders()
ZenExecutor->>ZenExecutor: resolve session
ZenExecutor-->>Client: User-Agent, client, project, session headers
Client->>ZenExecutor: transformRequestBody(body, model)
ZenExecutor->>ZenExecutor: set stream=true
alt Chat Completions
ZenExecutor->>Fingerprint: applyFingerprintTools(body, false)
else Responses
ZenExecutor->>Fingerprint: applyFingerprintTools(body, true)
end
ZenExecutor->>ZenAPI: request with canonical fingerprint tools
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="open-sse/executors/opencode-zen.js" line_range="233" />
<code_context>
if (out && typeof out === "object") out.stream = true;
if (!isResponsesModel(model || body?.model)) {
- ensureChatFingerprintTools(out);
+ if (out && typeof out === "object") applyFingerprintTools(out, false);
return out;
}
</code_context>
<issue_to_address>
**Retries lose tool-name aliases**
When a Zen request with a conflicting caller `read` or `shell` tool receives a retryable response before succeeding, the first transform renames the caller’s conflicting `read` or `shell` tool and records the alias map. A retry transforms that already-mutated body, finds no conflict, and replaces the recorded map with an empty one; the final response then exposes the alias instead of the caller’s tool name.
Preserve the original alias map across retries, or make retries transform a fresh copy of the original request body.
Also at `open-sse/executors/opencode-zen.js:259`.
</issue_to_address>
### Comment 2
<location path="tests/unit/opencode-session.test.js" line_range="355" />
<code_context>
+ });
+ expect(chat.stream).toBe(true);
+ expect(chat.tools.map((t) => t.function?.name)).toEqual(["read_client", "read", "shell"]);
+ expect(chat.tools[1].function.parameters.required).toEqual(["path"]);
+ expect(chat.messages[0].role).toBe("system");
+
</code_context>
<issue_to_address>
**Broken tool schemas pass fingerprint test**
When an emitted `read` tool retains `required: ["path"]` but has an incorrect description or other schema fields, the Zen fingerprint test checks only that the appended `read` tool requires `path`; a wrong description or other incorrect schema fields still pass both endpoint checks, so the test reports broken fingerprints as verbatim.
Assert the complete expected canonical definitions for the appended `read` and `shell` tools on both endpoint paths.
Also at `tests/unit/opencode-session.test.js:365`.
</issue_to_address>Sourcery assessment
Needs a human reviewer. 2 findings to address first, and requests that lack a qualifying downstream user-agent now claim the v2 CLI identity and send additional session-affinity headers, which could change how the upstream free-tier gate grants access or routes sessions. Reverting stops future requests from using that fingerprint, but cannot undo upstream requests already accepted or routed under it.
Blocking findings: open-sse/executors/opencode-zen.js:233, tests/unit/opencode-session.test.js:355
| if (out && typeof out === "object") out.stream = true; | ||
| if (!isResponsesModel(model || body?.model)) { | ||
| ensureChatFingerprintTools(out); | ||
| if (out && typeof out === "object") applyFingerprintTools(out, false); |
There was a problem hiding this comment.
🟡 Medium · Retries lose tool-name aliases
When a Zen request with a conflicting caller read or shell tool receives a retryable response before succeeding, the first transform renames the caller’s conflicting read or shell tool and records the alias map. A retry transforms that already-mutated body, finds no conflict, and replaces the recorded map with an empty one; the final response then exposes the alias instead of the caller’s tool name.
Preserve the original alias map across retries, or make retries transform a fresh copy of the original request body.
Also at open-sse/executors/opencode-zen.js:259.
Prompt for AI agents
In `open-sse/executors/opencode-zen.js` at line 233:
**Retries lose tool-name aliases**
When a Zen request with a conflicting caller `read` or `shell` tool receives a retryable response before succeeding, the first transform renames the caller’s conflicting `read` or `shell` tool and records the alias map. A retry transforms that already-mutated body, finds no conflict, and replaces the recorded map with an empty one; the final response then exposes the alias instead of the caller’s tool name.
Preserve the original alias map across retries, or make retries transform a fresh copy of the original request body.
Also at `open-sse/executors/opencode-zen.js:259`.| }); | ||
| expect(chat.stream).toBe(true); | ||
| expect(chat.tools.map((t) => t.function?.name)).toEqual(["read_client", "read", "shell"]); | ||
| expect(chat.tools[1].function.parameters.required).toEqual(["path"]); |
There was a problem hiding this comment.
🟡 Medium · Broken tool schemas pass fingerprint test
When an emitted read tool retains required: ["path"] but has an incorrect description or other schema fields, the Zen fingerprint test checks only that the appended read tool requires path; a wrong description or other incorrect schema fields still pass both endpoint checks, so the test reports broken fingerprints as verbatim.
Assert the complete expected canonical definitions for the appended read and shell tools on both endpoint paths.
Also at tests/unit/opencode-session.test.js:365.
Prompt for AI agents
In `tests/unit/opencode-session.test.js` at line 355:
**Broken tool schemas pass fingerprint test**
When an emitted `read` tool retains `required: ["path"]` but has an incorrect description or other schema fields, the Zen fingerprint test checks only that the appended `read` tool requires `path`; a wrong description or other incorrect schema fields still pass both endpoint checks, so the test reports broken fingerprints as verbatim.
Assert the complete expected canonical definitions for the appended `read` and `shell` tools on both endpoint paths.
Also at `tests/unit/opencode-session.test.js:365`.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7158dd61fe
ℹ️ 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 (out && typeof out === "object") out.stream = true; | ||
| if (!isResponsesModel(model || body?.model)) { | ||
| ensureChatFingerprintTools(out); | ||
| if (out && typeof out === "object") applyFingerprintTools(out, false); |
There was a problem hiding this comment.
Retain alias mapping when the base transform clones the request
When a Zen chat request targets a Kimi or DeepSeek model and declares a caller tool named read or shell, super.transformRequest runs the reasoning injector and returns a new body object. This call records the fingerprint alias map only on out, but chatCore later retrieves it exclusively from the original translatedBody; consequently an upstream read_client/shell_client call is returned to the client without restoration to its declared tool name, preventing the client from dispatching the tool or submitting a matching follow-up result. Record the map on the original request as well, or have the handler read it from the transformed body.
Useful? React with 👍 / 👎.
Summary
Ports the relevant changes from decolua/9router#4860 onto this fork's existing
devbranch, which already contains the OpenCode Free v2 implementation from the decolua#4842 line.Changes
OpenCodeZenExecutorwith the OpenCode v2 User-Agent format, using this fork's current2.0.29version.x-opencode-clienttocliand addx-opencode-project,x-session-affinity, andx-session-idwhile mirroring the same session value across session headers.bash/glob/grep/readstub tool declarations with shared canonicalread/shellfingerprint handling for Chat Completions and Responses.Scope
Keeps the existing Zen
/zen/v1endpoints unchanged; this patch ports the Zen executor changes from decolua#4860 and does not reapply the overlapping decolua#4806/decolua#4840/decolua#4842 patches.Validation
Unit tests have been added. CI results should be checked before merging.
Summary by Sourcery
Align OpenCode Zen with the v2 free-tier client fingerprint while preserving existing Zen endpoints.
Bug Fixes:
Enhancements:
Build:
Tests: