fix(gateway): /v1/responses tool schema should use flat Responses API format#57166
Conversation
Greptile SummaryThis PR correctly fixes the However, two tests in
These tests need to be updated to the flat Responses API format before merging. Confidence Score: 4/5Safe to merge after fixing two stale test cases in the CreateResponseBody Schema block that still use the old wrapped format. The schema and HTTP normalization changes are correct and well-motivated. The only concrete defects are two test cases that were not updated alongside the schema change and will produce test failures on CI. These must be fixed before merging. src/gateway/openresponses-parity.test.ts — the 'should validate request with client tools' and 'should validate complete turn-based tool flow' tests still use the wrapped format.
|
| Filename | Overview |
|---|---|
| src/gateway/open-responses.schema.ts | FunctionToolDefinitionSchema correctly updated from Chat Completions wrapped format to flat Responses API format; adds optional strict field; .strict() modifier preserved to reject unknown keys. |
| src/gateway/openresponses-http.ts | extractClientTools now correctly normalizes the flat Responses API format to the internal ClientToolDefinition wrapped format; downstream applyToolChoice and agent pipeline remain unaffected. |
| src/gateway/openresponses-parity.test.ts | The Schema Validation block is correctly updated to flat format, but two tests in the CreateResponseBody Schema block still use the old wrapped format and will fail on CI. |
Comments Outside Diff (2)
-
src/gateway/openresponses-parity.test.ts, line 185-215 (link)Stale wrapped-format tools will cause this test to fail
This test still passes the old Chat Completions wrapped format (
function: { name, ... }) inside thetoolsarray and assertsresult.success === true. However,CreateResponseBodySchemanow delegates toToolDefinitionSchema→FunctionToolDefinitionSchema, which uses.strict()and only accepts the flat format (name,description,parametersat the top level). Sending{ type: "function", function: { ... } }will be rejected, so this test will fail after the PR is merged.The same stale format also appears at lines 243–255 inside the
"should validate complete turn-based tool flow"test.Both need to be updated to the flat Responses API format — for example:
Prompt To Fix With AI
This is a comment left during a code review. Path: src/gateway/openresponses-parity.test.ts Line: 185-215 Comment: **Stale wrapped-format tools will cause this test to fail** This test still passes the old Chat Completions wrapped format (`function: { name, ... }`) inside the `tools` array and asserts `result.success === true`. However, `CreateResponseBodySchema` now delegates to `ToolDefinitionSchema` → `FunctionToolDefinitionSchema`, which uses `.strict()` and only accepts the flat format (`name`, `description`, `parameters` at the top level). Sending `{ type: "function", function: { ... } }` will be rejected, so this test will fail after the PR is merged. The same stale format also appears at lines 243–255 inside the `"should validate complete turn-based tool flow"` test. Both need to be updated to the flat Responses API format — for example: How can I resolve this? If you propose a fix, please make it concise.
-
src/gateway/openresponses-parity.test.ts, line 233-255 (link)Stale wrapped-format tools in turn-based flow test
The
turn1Requesthere still uses the wrapped{ type: "function", function: { ... } }format and assertsturn1Result.success === true. With the new strict flat schema this will fail. Thetoolsarray needs to be updated to the flat Responses API format, matching the fix applied everywhere else.Prompt To Fix With AI
This is a comment left during a code review. Path: src/gateway/openresponses-parity.test.ts Line: 233-255 Comment: **Stale wrapped-format tools in turn-based flow test** The `turn1Request` here still uses the wrapped `{ type: "function", function: { ... } }` format and asserts `turn1Result.success === true`. With the new strict flat schema this will fail. The `tools` array needs to be updated to the flat Responses API format, matching the fix applied everywhere else. How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/gateway/openresponses-parity.test.ts
Line: 185-215
Comment:
**Stale wrapped-format tools will cause this test to fail**
This test still passes the old Chat Completions wrapped format (`function: { name, ... }`) inside the `tools` array and asserts `result.success === true`. However, `CreateResponseBodySchema` now delegates to `ToolDefinitionSchema` → `FunctionToolDefinitionSchema`, which uses `.strict()` and only accepts the flat format (`name`, `description`, `parameters` at the top level). Sending `{ type: "function", function: { ... } }` will be rejected, so this test will fail after the PR is merged.
The same stale format also appears at lines 243–255 inside the `"should validate complete turn-based tool flow"` test.
Both need to be updated to the flat Responses API format — for example:
```suggestion
it("should validate request with client tools", async () => {
const validRequest = {
model: "claude-sonnet-4-20250514",
input: [
{
type: "message" as const,
role: "user" as const,
content: "What's the weather?",
},
],
tools: [
{
type: "function" as const,
name: "get_weather",
description: "Get weather for a location",
parameters: {
type: "object",
properties: {
location: { type: "string" },
},
required: ["location"],
},
},
],
};
const result = CreateResponseBodySchema.safeParse(validRequest);
expect(result.success).toBe(true);
});
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: src/gateway/openresponses-parity.test.ts
Line: 233-255
Comment:
**Stale wrapped-format tools in turn-based flow test**
The `turn1Request` here still uses the wrapped `{ type: "function", function: { ... } }` format and asserts `turn1Result.success === true`. With the new strict flat schema this will fail. The `tools` array needs to be updated to the flat Responses API format, matching the fix applied everywhere else.
```suggestion
const turn1Request = {
model: "claude-sonnet-4-20250514",
input: [
{
type: "message" as const,
role: "user" as const,
content: "What's the weather in San Francisco?",
},
],
tools: [
{
type: "function" as const,
name: "get_weather",
description: "Get weather for a location",
},
],
};
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "gateway: fix /v1/responses tool schema t..." | Re-trigger Greptile
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c4707711a1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
Fixed — updated the two stale test cases in the |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e1d44f0d34
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
Addressed the P2: added |
|
Codex Review: Didn't find any major issues. Nice work! ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
@greptile , are you good with the updated code as well? |
|
Yes, looks solid. The boundary layer is clean:
The separation between API surface (flat) and internal representation (wrapped) is exactly where it should be. Good fix. |
Gateway + Client Configuration DetailsFor anyone wanting to reproduce the Codex CLI → OpenClaw → local model setup: OpenClaw gateway config ( {
gateway: {
port: 18789,
bind: "lan",
auth: { mode: "token", token: "<token>" },
http: {
endpoints: {
chatCompletions: { enabled: true },
responses: { enabled: true }
}
}
},
models: {
mode: "replace",
providers: {
"local-vllm": {
baseUrl: "http://10.15.0.166:8000/v1",
apiKey: "local-only-key",
api: "openai-completions",
models: [{
id: "qwen35-397b",
name: "Qwen3.5-397B-NVFP4",
api: "openai-completions",
reasoning: true,
input: ["text", "image"],
contextWindow: 500000,
maxTokens: 32768,
compat: { supportsDeveloperRole: false, supportsUsageInStreaming: true }
}]
}
}
}
}Codex CLI config ( model = "openclaw"
model_provider = "openclaw-local"
[model_providers.openclaw-local]
name = "OpenClaw Gateway"
base_url = "http://<gateway-host>:18789/v1"
wire_api = "responses"
env_key = "OPENCLAW_TOKEN"
[model_providers.openclaw-local.http_headers]
"x-openclaw-scopes" = "operator.write"The |
Local Testing EvidenceTested the fix end-to-end on a self-hosted OpenClaw v2026.3.28 instance (Ubuntu 24.04, Qwen3.5-397B via vLLM): 1. curl — flat Responses API format (success)curl -s http://localhost:18789/v1/responses \
-H "Authorization: Bearer <token>" \
-H "x-openclaw-scopes: operator.write" \
-H "Content-Type: application/json" \
-d '{"model":"openclaw","input":"Use the crpc_respond tool to say hello","stream":false,
"tools":[{"type":"function","name":"crpc_respond","description":"Send a response",
"parameters":{"type":"object","properties":{"content":{"type":"string"},"done":{"type":"boolean"}},"required":["content","done"]}}]}'Result: HTTP 200, agent returned 2. OpenAI Codex CLI — connected and workingConfigured Codex CLI v0.117.0 with Result: Codex successfully connected, delegated its tools via the flat Responses API format, and the agent correctly answered the query. Token usage: 42,387 tokens routed through Qwen3.5-397B. 3. Wrapped format correctly rejectedAfter the patch, sending the old Chat Completions wrapped format ( Tested with the monkey-patched compiled bundle on the installed npm module; the same source changes are in this PR. |
|
Regarding the automated review feedback: Re: Re: test fixture consistency — All tool definitions in both The failing CI checks ( |
|
Investigated the CI failures — none are related to this PR:
This PR only touches |
4c6be64 to
7244494
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0d9018c821
ℹ️ 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".
| name: tool.name, | ||
| description: tool.description, | ||
| parameters: tool.parameters, | ||
| strict: tool.strict, |
There was a problem hiding this comment.
Preserve strict through hosted tool conversion
extractClientTools now accepts and forwards tools[].strict, but this value is still dropped before the model request is built: toClientToolDefinitions only maps name/label/description/parameters and never carries strict into the ToolDefinition objects (src/agents/pi-tool-definition-adapter.ts:185-189). With this commit, requests that include {"type":"function","name":"...","strict":true} now parse successfully instead of failing validation, yet strict argument enforcement is silently disabled downstream. That is a behavior regression for spec-compliant clients relying on strict tool schemas.
Useful? React with 👍 / 👎.
… format (openclaw#57166) * gateway: fix /v1/responses tool schema to use flat Responses API format * gateway: fix remaining stale wrapped-format tools in parity tests * gateway: propagate strict flag through extractClientTools normalization * fix(gateway): cover responses tool boundary * Delete docs/internal/vincentkoc/2026-03-30-pr-57166-responses-tool-schema-followup.md --------- Co-authored-by: Michel Belleau <[email protected]> Co-authored-by: Vincent Koc <[email protected]>
… format (openclaw#57166) * gateway: fix /v1/responses tool schema to use flat Responses API format * gateway: fix remaining stale wrapped-format tools in parity tests * gateway: propagate strict flag through extractClientTools normalization * fix(gateway): cover responses tool boundary * Delete docs/internal/vincentkoc/2026-03-30-pr-57166-responses-tool-schema-followup.md --------- Co-authored-by: Michel Belleau <[email protected]> Co-authored-by: Vincent Koc <[email protected]>
… format (openclaw#57166) * gateway: fix /v1/responses tool schema to use flat Responses API format * gateway: fix remaining stale wrapped-format tools in parity tests * gateway: propagate strict flag through extractClientTools normalization * fix(gateway): cover responses tool boundary * Delete docs/internal/vincentkoc/2026-03-30-pr-57166-responses-tool-schema-followup.md --------- Co-authored-by: Michel Belleau <[email protected]> Co-authored-by: Vincent Koc <[email protected]>
… format (openclaw#57166) * gateway: fix /v1/responses tool schema to use flat Responses API format * gateway: fix remaining stale wrapped-format tools in parity tests * gateway: propagate strict flag through extractClientTools normalization * fix(gateway): cover responses tool boundary * Delete docs/internal/vincentkoc/2026-03-30-pr-57166-responses-tool-schema-followup.md --------- Co-authored-by: Michel Belleau <[email protected]> Co-authored-by: Vincent Koc <[email protected]>
… format (openclaw#57166) * gateway: fix /v1/responses tool schema to use flat Responses API format * gateway: fix remaining stale wrapped-format tools in parity tests * gateway: propagate strict flag through extractClientTools normalization * fix(gateway): cover responses tool boundary * Delete docs/internal/vincentkoc/2026-03-30-pr-57166-responses-tool-schema-followup.md --------- Co-authored-by: Michel Belleau <[email protected]> Co-authored-by: Vincent Koc <[email protected]>
… format (openclaw#57166) * gateway: fix /v1/responses tool schema to use flat Responses API format * gateway: fix remaining stale wrapped-format tools in parity tests * gateway: propagate strict flag through extractClientTools normalization * fix(gateway): cover responses tool boundary * Delete docs/internal/vincentkoc/2026-03-30-pr-57166-responses-tool-schema-followup.md --------- Co-authored-by: Michel Belleau <[email protected]> Co-authored-by: Vincent Koc <[email protected]>
… format (openclaw#57166) * gateway: fix /v1/responses tool schema to use flat Responses API format * gateway: fix remaining stale wrapped-format tools in parity tests * gateway: propagate strict flag through extractClientTools normalization * fix(gateway): cover responses tool boundary * Delete docs/internal/vincentkoc/2026-03-30-pr-57166-responses-tool-schema-followup.md --------- Co-authored-by: Michel Belleau <[email protected]> Co-authored-by: Vincent Koc <[email protected]>
… format (openclaw#57166) * gateway: fix /v1/responses tool schema to use flat Responses API format * gateway: fix remaining stale wrapped-format tools in parity tests * gateway: propagate strict flag through extractClientTools normalization * fix(gateway): cover responses tool boundary * Delete docs/internal/vincentkoc/2026-03-30-pr-57166-responses-tool-schema-followup.md --------- Co-authored-by: Michel Belleau <[email protected]> Co-authored-by: Vincent Koc <[email protected]>
… format (openclaw#57166) * gateway: fix /v1/responses tool schema to use flat Responses API format * gateway: fix remaining stale wrapped-format tools in parity tests * gateway: propagate strict flag through extractClientTools normalization * fix(gateway): cover responses tool boundary * Delete docs/internal/vincentkoc/2026-03-30-pr-57166-responses-tool-schema-followup.md --------- Co-authored-by: Michel Belleau <[email protected]> Co-authored-by: Vincent Koc <[email protected]>
Summary
/v1/responsesendpoint validates tool definitions using the Chat Completions wrapped format (function: {...}) and.strict(), but the Responses API spec uses a flat format ({type, name, description, parameters}at top level). Any compliant Responses API client (e.g. OpenAI Codex CLI) fails withtools.0.function: Invalid input: expected object, received undefined.FunctionToolDefinitionSchemanow uses the flat Responses API shape.extractClientToolsnormalizes the flat format to the internalClientToolDefinitionwrapped format before passing to the agent pipeline.ClientToolDefinitiontype and all downstream agent code remain on the wrapped format — only the HTTP boundary layer changed.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause / Regression History (if applicable)
open-responses.schema.tsFunctionToolDefinitionSchemawas written with the Chat Completions tool format (function: { name, ... }wrapper) instead of the Responses API flat format (name,description,parametersat top level alongsidetype). The.strict()Zod modifier then rejects any top-level keys not in the schema, causing the flat-format tools from spec-compliant clients to fail validation.Regression Test Plan (if applicable)
src/gateway/openresponses-parity.test.ts— updated to test the flat format and to explicitly assert the wrapped format is rejected{type, name, description, parameters}parses successfully; wrapped{type, function: {...}}failsToolDefinitionSchemaUser-visible / Behavior Changes
Any client sending tools to
/v1/responsesmust now use the flat Responses API format:{"type": "function", "name": "my_tool", "description": "...", "parameters": {...}}The previously "working" workaround of sending the Chat Completions wrapped format (
function: {...}) now correctly fails.Diagram (if applicable)
Security Impact (required)
Repro + Verification
Environment
Steps
responses: { enabled: true }andx-openclaw-scopes: operator.write/v1/responseswithtools: [{"type":"function","name":"crpc_respond",...}](flat format)tools.0.function: Invalid input: expected object, received undefinedfunction_callfor the toolExpected
HTTP 200 with
function_calloutput items for the provided tools.Actual (before fix)
HTTP 422 with
tools.0.function: Invalid input: expected object, received undefined.Evidence
openresponses-parity.test.ts) now tests both the valid flat format and explicit rejection of the wrapped formatHuman Verification (required)
codex exec) successfully connects and delegates toolstool_choice: {type:"function", name:"..."}— that is inToolChoiceSchemawhich is a separate schema and unchangedCompatibility / Migration
{"type":"function","function":{...}}to/v1/responsesto use{"type":"function","name":"...","description":"...","parameters":{...}}Risks and Mitigations