Repository navigation
fix(translate): resolve redeclared Responses tools to their latest declaration - #714
Merged
Merged
Conversation
Remove the request-count ceiling from output IR construction and Chat event routing while requiring sequential valid indexes. Verify that every upstream choice is retained and skipped indexes still fail.
Replace fluent protocol subpaths with named root translators returning plain trips or input failures. Keep request builders and event adapters intact while containing expected input exceptions at public operations. Consume translation failures at gateway attempt and payload boundaries, and encode rewritten JSON errors at the transport boundary. Preserve the current model context and remote-image loader requirements for the pairwise request backend. Validate named translation and gateway suites, owning TypeScript projects, and changed lint targets.
Keep refusals on assistant history and use role-specific content contracts in translation and provider consumers. Preserve retained refusal text when compaction restates history as input content.
Split native replay coordination into reader, writer, and coordinator owners. Distinguish native input turns, read and emitted reference states, text fragments, content-reference tags, and the transport codec without changing replay wire behavior. Preserve the pairwise request replay signature and reasoning warnings. Keep native output-to-input normalization and Gemini target slots, and move converter assertions to their protocol owners. Validated 38 named test files (307 tests), translate typecheck, and touched-file ESLint. Production HMAC/CBOR sidecar bytes, digests, selected references, restored turns, and native converter outputs match the main baseline for literal, astral, and unpaired-surrogate fixtures.
Restate recognized upstream errors through source-owned converters before and during streams. Preserve independent error classifications, nullable code and param values, envelope metadata, and one merged provider extension container. Use the same recognized context-overflow decision for Gemini HTTP and body codes. Keep unknown response bytes untouched and propagate unexpected parser failures with their original error and cause. Validate 322 tests in 19 named files, changed-file ESLint, and the translate and gateway TypeScript projects.
Separate output construction, records, accumulation, lifecycle and path operations. Name output model types explicitly and share JSON and text-range shapes through their owners. Move protocol fixtures and assertions out of output IR tests. Let unit queues own their links and remove dead builder and path-query APIs. Preserve configured choice limits and native SSE, error and sidecar behavior. Validate with 612 focused tests, 67 baseline differential probes, 39 logical correspondences, scoped lint and the owning TypeScript project.
Normalize HTTP and streaming error envelopes through the same metadata merge. Preserve outer request identifiers and trace fields in the existing extension container while retaining error-level collision priority. Distinguish event transport fields from native error payloads so canonical payloads retain their original reference and classification when no envelope data remains. Validate 324 tests in 19 named files, ESLint on all four changed files, and the translate and gateway TypeScript projects.
Use directional events modules and read/write entrypoints for the seven native output adapters, and mirror those owners in their tests. Move the unchanged source writer options shape to its shared owner. Finish schema phantom, absent-string and type-equality names so the input work has no remaining output-only naming migration. Preserve native behavior with 622 named tests, 67 controlled main/final wire and replay probes, 66 runtime/declaration/test-body correspondences, 98 scoped lint targets and the translate TypeScript project.
Unify recursive and assistant-turn restoration through RestoreResult.value while retaining the pairwise request boundary's native turn wrapper. Centralize the four protocols' existing digest material projection and version dispatch in shared digest factories. Preserve synchronous projector failures and skip projection for unsupported versions. Validated 38 named test files (309 tests), translate typecheck, and 14 touched-file lint targets. Production HMAC/CBOR bytes and restored native values match main; all four protocol digest projections and version behavior also match main.
Retain the lossless error fields in existing output assertions after their ownership migration. Order imports at the combined output and replay owners without changing runtime behavior.
Apply the accepted reader/writer, digest material ownership, and text placement comments at their replay owners. Verify unchanged compiler-token and directive streams for all four files, scoped lint, translate typecheck, named replay tests, and production byte and source digest invariance.
Read source requests into immutable input concepts and compose target writers with lazy authenticated native replay. Preserve complete tool declarations, logical call identity, request controls and media references across all public routes.\n\nRemove pairwise request conversion and carry the resolved Gemini model in the formal source request. Keep prerequisite output lifecycle, error projection and signed replay behavior intact.
Preserve sparse namespace provenance coverage with logical IR call kinds. Align restored native call names and Responses error assertions with the final request allocation and prerequisite error contracts.
Keep output validation diagnostics, type refinements and reviewed comments with their output owner. Preserve configured choice limits and gap filling while narrowing relative paths to strings and explicit path arrays. Give completion-aware JSON parsing its own module and mirrored tests. Reuse the existing structural record guard from the JSON owner in native writers. Retain the reviewed sentinel and write-validation rationale. Validate 625 tests in 43 named files, 68 controlled main/final differential probes, 89 runtime/declaration/test correspondences, 101 scoped lint targets and the translate TypeScript project. Track diagnostic terminology changes explicitly while comparing complete wire, digest and native replay values.
Move each source protocol's error converters into as-source/error.ts so HTTP error restatement and SSE output share the focused error owner. Preserve the extracted implementation byte for byte. Align six existing error expectations in three test files with retained upstream details and independent classifications. Validate 376 tests in 22 named files, all 17 changed TypeScript lint targets, and the translate and gateway TypeScript projects.
Preserve the param and code supplied by raw translation input failures in Messages and GenerateContent error envelopes. Omit absent details and keep the rejecting candidate performance context intact. Keep protocol error results precise and validate both detail envelopes, the named translation boundary suites, and gateway TypeScript checks.
Port the reviewed capture, error telemetry, and Responses attempt explanations to their public-boundary owners. Remove redundant dispatcher and assertion narration and update the dashboard capture reference.
Apply reviewed input-reader, target-writer and request regression comments from the complete feature snapshot. Preserve finalized prerequisite error, replay and output ownership.
…claration Codex declares a namespace in top-level `tools`, again in an `additional_tools` input item, and once more after each compaction. The Responses source flattened every inventory into IR tools verbatim, so a captured Codex request translated to Anthropic Messages carried 89 tools with only 70 unique names and the upstream refused it with 400. The Responses source now collapses repeated callable identities (type, namespace, name) to the latest declaration, which is the caller's current statement of the tool, placed in the slot of the first so the declared prefix stays stable for prompt caching. Group selectors expand over the resolved declarations, so they no longer yield duplicates. IR tools now carry each callable identity once, and name allocation refuses a request that repeats one rather than emitting duplicate names a target wire rejects.
Integrate the landed translation prerequisites and later main updates without replaying their squashed history. Preserve the input IR leaf delta and place target-request preparation under composition, where its restored-turn state belongs.
Emit max_tokens beside max_completion_tokens for every translated Chat request so OpenAI's replacement spelling and compatible upstreams that still read the legacy spelling receive the same ceiling. Preserve null and zero explicitly and cover all Chat-target source routes.
Keep URLs and file_data strings exact in the input IR, including data URL parameters and non-base64 forms. Parse data URLs only at a target that needs inline bytes, preserve stated media types, and invent a generic MIME type only where the target requires one.
Represent top-level source instructions separately from inline system and developer messages so target hoisting cannot merge their roles or positions. Preserve explicitly empty Chat assistant arrays and Gemini thought turns instead of deleting their conversation boundaries.
Represent user, system and developer history as messages with explicit roles while keeping top-level instructions distinct. Carry nullable OpenAI controls through the IR, normalize ProtoJSON nulls as unset, preserve separate refusal values, and avoid empty namespace-description prefixes.
Reject deferred and programmatic tools from every Responses inventory, refuse namespace selector extensions, and preserve each source protocol's established orphan-choice behavior. Avoid synthesizing a Messages parallel-tool choice when no declarations exist.
Map Messages document results into formal IR files, retain unmodeled structured blocks as opaque JSON, preserve JSON null function arguments, and carry server-tool errors through the shared incomplete/is_error result state.
Remove source-side call identities from restored turns and reserve their native wire names without rewriting them. Allocate call/result IDs before wire names, and pair legacy Chat calls only with the unique id-less result stating the same function name before modern matching.
Stop translating includeThoughts into an upstream reasoning-summary request. Record complete target reasoning for sidecar replay while emitting plaintext thought text only when the Gemini source requested it, using a separate visible digest so authenticated replay retains the original reasoning.
Pin the restored no-tool choice behavior and distinguish malformed argument fallback from valid non-object JSON arguments after the input IR fixes.
Make reasoning-output fixtures request Gemini thought plaintext explicitly, assert restored turns remain target-native, retain ProtoJSON null arguments, and update gateway instruction expectations after the finalized IR behavior.
Keep historical roles and empty turns intact, preserve nullable schema fields and required tool choices at the correct target boundaries, and associate legacy Chat results before modern calls.\n\nRepresent Messages documents formally in tool results, move data URL decoding to its target owner, and remove restored-turn name reservations and duplicate Gemini visibility state.
Treat ProtoJSON null message fields as unset, preserve text-only content documents as formal files, and let distinct legacy function calls match their named results.\n\nSimplify the Responses instruction projection and remove the remaining stale prompt and strict-state wording.
Preserve text-block boundaries without changing transport-fragment concatenation, retain nullable Responses controls and immutable request snapshots, and constrain generated Responses call IDs at the target.\n\nKeep leading Messages system content hoisted, order tool results legally, drop foreign encrypted reasoning, and carry Gemini function-response media through formal IR parts.
Use a truly unrepresentable content document in input-error coverage, assert the single Gemini accumulator, and encode the final decisions for foreign encrypted reasoning and inline historical role messages.
Remove the unsupported input-IR block distinction and restore direct text-part concatenation. The previous change inferred desired behavior from main without a user decision.
Keep top-level instructions distinct from historical role messages, preserve readable reasoning beside opaque encrypted data, and remove speculative request snapshots.\n\nDrop the implementation-coupled Gemini accumulator test.
Represent Messages documents separately from files, retain content-backed text and image sequences, and project unsupported document semantics through provenance tags.\n\nRestore native Messages documents, emit tagged Responses content, and lift Chat tool-result files and documents alongside images.
Remove comments that restate field names and types, retaining only cross-protocol invariants and non-obvious representation decisions.
Annotate every input IR type and field with the source protocols that can populate it, matching the compact coverage style used by output IR.
Remove redundant validation and indirection while preserving request projections. Correct protocol coverage annotations and current translation ownership notes.
Carry document metadata and nested attributes through input IR, projecting citation and cache controls where supported. Preserve unrecognized custom tool formats until target writing and return an input error when they cannot be translated.
Clear stale namespaces when a Chat tool call changes its name, and apply the updated identity before a delayed call ID opens the Responses item.
Cover function and custom calls when names or namespaces change across added, done, and terminal snapshots.
…onses-tool-redeclaration
Menci
marked this pull request as ready for review
November 13, 2026 08:28
…declaration # Conflicts: # packages/translate/__tests__/composition/request/tool-names_test.ts # packages/translate/__tests__/protocols/openai-responses/as-source/allowed-tools_test.ts # packages/translate/src/composition/request/tool-names.ts # packages/translate/src/ir/input/types.ts # packages/translate/src/protocols/openai-responses/as-source/input-to.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Codex declares the same namespaces in top-level
tools, again in anadditional_toolsinput item, and once more after each compaction. The Responses source flattened every inventory into IR tools verbatim, so a captured Codex request routed to Anthropic Messages carried 89 tools with only 70 unique names, and the upstream refused it with 400invalid_body(duplicate tool names).Change
namespace) selectors inallowed_toolsexpand over the resolved declarations, so they no longer produce duplicate selectors.allocateToolNamesrefuses a request that repeats one instead of emitting duplicate names a target wire rejects.Replaying the captured request through the fix yields 70 tools, 70 unique.
Test Plan
allowed-tools_test.ts(Chat Completions and Messages targets) andcomposition/request/tool-names_test.tsfail without the change and pass with it.allowed-tools,composition/request/tool-names,as-source/input-to,as-source/programmatic-tooling,openai-responses/round-trip-request,pairs/openai-responses-to-anthropic-messages-request,pairs/input-controls-request,call-association.tsc --noEmitfor translate and ESLint on the changed files are clean.