Skip to content

fix(responses): handle positional tool declarations in middleware - #558

Merged
Menci merged 34 commits into
mainfrom
feat/responses-additional-tool-middleware
Sep 30, 2026
Merged

Menci merged 34 commits into
mainfrom
feat/responses-additional-tool-middleware

Conversation

@Menci

@Menci Menci commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Responses clients can declare tools in top-level tools, input-carried additional_tools.tools, and tool_search_output.tools. Middleware must recognize every declaration carrier when activating hosted tools, validating configuration, resolving names, applying tool choices, and filtering unsupported provider tools.

Collect declarations across these carriers and rewrite hosted web search and image generation inside their original input items. Preserve item order, IDs, metadata, and the top-level response echo. Validate original declaration paths before rewriting arrays; keep forced and allowed-tool selectors and empty-tools normalization aligned with the remaining tools. Apply Copilot image-generation filtering throughout all carriers.

The OpenAI Responses reference permits these tool carriers, and the tool search guide describes positional loading. Codex emits them in its Lite request builder and client tool search.

Test Plan

  • Run the Responses, tool mapping, and Copilot filtering suites on the synchronized branch: 712 tests across 33 files pass.
  • Verify 32 live HTTP scenarios using Copilot gpt-6-luna and Microsoft Web IQ configuration copied into isolated local SQLite: declaration carriers, tool choices, aliases, collisions, filters, validation paths, streaming, and replay.
  • Pass all repository verification checks in CI on the synchronized head.

Natural-language probes may initially emit response_length, which the configured search adapter rejects in-band; successful searches are counted only after real results are returned. Controlled carrier probes prescribe search_query to isolate declaration behavior. Runtime state and usage writes remain local, and no OAuth refresh token is imported or used.

Collect tool definitions from top-level tools, additional_tools, and tool_search_output in declaration order. Rewrite hosted tools inside their original input items, preserve the top-level response echo, and keep validation paths tied to the source item.

Apply the same inventory to empty-tool normalization and Copilot image-generation filtering. Cover web search and image generation dispatch, response echo, collisions, and input-carrier validation.
…onal-tool-middleware

# Conflicts:
#	packages/gateway/__tests__/data-plane/chat/openai-responses/interceptors/server-tool-shim_test.ts
#	packages/gateway/src/data-plane/chat/openai-responses/interceptors/server-tool-shim.ts
Copilot filters image-generation declarations from every Responses tool carrier. Keep allowed_tools consistent with that filter, retaining other selectors and dropping the choice when none survive.
Keep an unchanged allowed_tools choice intact when the Copilot image-generation filter removes no selector.
Scope the vendor probe evidence to the tested web-search cases and describe response.tools restoration as a local rule for top-level replacements.
When Copilot strips the only allowed hosted selector, choose none for auto mode. Preserve an empty required allowlist so the unsatisfiable request fails instead of enabling unrelated tools.
Prepare each server-tool registration against the original request so earlier deduplication cannot shift later validation paths. Apply prepared rewrites afterward in registration order.
When Copilot removes a forced image-generation declaration but other tools remain, set tool_choice to none so the former forced choice cannot enable a different tool.
@Menci
Menci marked this pull request as ready for review September 29, 2026 22:48
Describe the duplicate-tool selection as a local shim rule and retain the OpenAI image-generation reference. Remove citations to this repository's prior pull requests from the affected comments.
Live Copilot and Web IQ probes exposed a continuation deadlock: billing metadata resolves only after its event stream is consumed. Read each continuation stream first, then accumulate its billed usage. Cover all tool declaration carriers with deferred metadata across three turns.
Use one stream-consumption boundary for every hosted-tool turn. Read billing metadata after iterator completion or cancellation, retaining observed usage when a stream fails. Verify failed first and continuation turns preserve both the stream error and accumulated cost.
Successful live search requests exposed negative TTFT samples when a later model dispatch replaced the start time paired with the already-observed first output. Preserve the completed timing pair while allowing pre-output retries and candidate failover to reset their anchors. Cover continuation timing and retain existing retry/failover checks.
Live Copilot and Web IQ probes exposed a continuation deadlock: billing metadata resolves only after its event stream is consumed. Read each continuation stream first, then accumulate its billed usage. Cover all tool declaration carriers with deferred metadata across three turns.
Use one stream-consumption boundary for every hosted-tool turn. Read billing metadata after iterator completion or cancellation, retaining observed usage when a stream fails. Verify failed first and continuation turns preserve both the stream error and accumulated cost.
…itional-tool-middleware

# Conflicts:
#	packages/gateway/__tests__/data-plane/chat/openai-responses/interceptors/server-tool-shim_test.ts
@Menci
Menci marked this pull request as draft September 30, 2026 05:35
@Menci
Menci changed the base branch from main to fix/responses-billing-metadata September 30, 2026 05:35
@Menci
Menci changed the base branch from fix/responses-billing-metadata to main September 30, 2026 07:44
…onal-tool-middleware

# Conflicts:
#	packages/gateway/__tests__/data-plane/chat/openai-responses/interceptors/server-tool-shim_test.ts
@Menci
Menci marked this pull request as ready for review September 30, 2026 07:54
@Menci
Menci merged commit 659f185 into main Sep 30, 2026
8 checks passed
yyyr-p added a commit to yyyr-p/Floway that referenced this pull request Oct 4, 2026
Integrates upstream commits e286553..c7e4d78:
- refactor(responses): lower agent_message in a request middleware (Menci#576)
- fix(claude-code): update subscription request defaults (Menci#571)
- fix(compaction): use the context compaction shim by default (Menci#572)
- fix(codex): derive quota expiry from exhausted windows (Menci#570)
- fix(tls): support IP-literal certificate identities (Menci#569)
- fix(web-search): resolve the OpenAI search passthrough lazily (Menci#568)
- fix(provider-codex): update stable client identity for newer models (Menci#567)
- fix(provider-codex): preserve Responses Lite wire semantics (Menci#543)
- feat(web): adopt the blue Floway logo (Menci#563)
- feat(codex): show and redeem ChatGPT reset cards (Menci#528)
- fix(responses): answer Codex WebSocket prewarms locally (Menci#552)
- fix(responses): handle positional tool declarations in middleware (Menci#558)
- fix(gateway): preserve first-token timing across tool continuations (Menci#561)
- fix(responses): consume hosted-tool streams before billing metadata (Menci#560)
- fix(codex): restore output omitted from terminal snapshots (Menci#551)
- fix(codex): preserve model catalog context windows (Menci#559)
- fix(web): disable inactive upstream disclosure (Menci#534)
- fix(translate): isolate translated request payloads (Menci#557)
- feat(models): support Claude Sonnet 5.5 (Menci#555)
- feat(models): support GPT-6.1 Sol (Menci#553)
- fix(web): allow imported credentials on upstream creation (Menci#556)
- fix(gateway): preserve hosted tool selection across aliases and continuations (Menci#549)
- fix(translate): restore Responses callable identities (Menci#547)
- perf(translate): bound namespace tool name allocation work (Menci#548)
- fix(translate): preserve namespace descriptions on child tools (Menci#545)
- feat(requests): show each request's time to first token (Menci#550)
- fix(translate): reject ambiguous flat callable kinds (Menci#542)
- fix(gateway): preserve client tool identity in hosted dispatch (Menci#538)
- fix(web): mask credential headers in request record exports (Menci#539)

Conflict resolutions:
- upstreams/access-control.tsx: keep the fork's parameterized title,
  description, and error props (title/description ?? defaults, plus
  defaultOpen/revealOn) alongside upstream Menci#534's disclosureDisabled={!override}.
- upstreams/access-control_test.tsx: union the Control helper to accept both
  error and initialOverride, and keep both Menci#534's disabled-disclosure case and
  the fork's validation-error cases.
- control-plane/routes.ts: union the schemas.ts named imports -- the fork's
  OAuth2 admin bodies plus upstream Menci#528's codexRateLimitResetCreditsBody and
  codexRateLimitResetConsumeBody; both sides' route blocks merged cleanly.
- requests/ttft_test.tsx (Menci#550): pass the fork's required exchangeStreams={[]}
  to the RequestDetailPanel cases that construct it with no collected streams.

Verified with pnpm run verify (typegen, lint, typecheck, 611 test files /
6644 tests, test:installers, check:agents-md, check:generated-assets,
check:verify-parity, build:web).
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