From d3d6d80f4ae911a8c52c405326acb83d7e6caec7 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 10 Jan 2026 00:13:52 +0000 Subject: [PATCH] fix(agents): require raw for gateway config.apply (#566) (thanks @sircrumpet) --- CHANGELOG.md | 1 + src/agents/pi-tools.test.ts | 31 +++++++++++++++++++++++++++++++ src/agents/tools/gateway-tool.ts | 17 ++++++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7645f0e30..71253cc4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,6 +81,7 @@ - Agents: scrub unsupported JSON Schema keywords from tool schemas for Cloud Code Assist API compatibility. (#567) — thanks @erikpr1994 - Agents: sanitize Cloud Code Assist tool call IDs and detect format/quota errors for failover. (#544) — thanks @jeffersonwarrior - Agents: simplify session tool schemas for Gemini compatibility. (#599) — thanks @mcinteerj +- Agents: require `raw` for gateway `config.apply` tool calls while keeping schema 2020-12 compatible. (#566) — thanks @sircrumpet - Agents: add `session_status` agent tool for `/status`-equivalent status (incl. usage/cost) + per-session model overrides. — thanks @steipete - Auto-reply: preserve block reply ordering with timeout fallback for streaming. (#503) — thanks @joshp123 - Auto-reply: block reply ordering fix (duplicate PR superseded by #503). (#483) — thanks @AbhisekBasu1 diff --git a/src/agents/pi-tools.test.ts b/src/agents/pi-tools.test.ts index 108896468..8f34136af 100644 --- a/src/agents/pi-tools.test.ts +++ b/src/agents/pi-tools.test.ts @@ -31,6 +31,37 @@ describe("createClawdbotCodingTools", () => { expect(parameters.required ?? []).toContain("action"); }); + it("requires raw for gateway config.apply tool calls", () => { + const tools = createClawdbotCodingTools(); + const gateway = tools.find((tool) => tool.name === "gateway"); + expect(gateway).toBeDefined(); + + const parameters = gateway?.parameters as { + allOf?: Array>; + }; + const conditional = parameters.allOf?.find( + (entry) => "if" in entry && "then" in entry, + ) as + | { if?: Record; then?: Record } + | undefined; + + expect(conditional).toBeDefined(); + const thenRequired = conditional?.then?.required as string[] | undefined; + expect(thenRequired ?? []).toContain("raw"); + + const action = ( + conditional?.if?.properties as Record | undefined + )?.action as { const?: unknown; enum?: unknown[] } | undefined; + const values = new Set(); + if (typeof action?.const === "string") values.add(action.const); + if (Array.isArray(action?.enum)) { + for (const value of action.enum) { + if (typeof value === "string") values.add(value); + } + } + expect(values.has("config.apply")).toBe(true); + }); + it("flattens anyOf-of-literals to enum for provider compatibility", () => { const tools = createClawdbotCodingTools(); const browser = tools.find((tool) => tool.name === "browser"); diff --git a/src/agents/tools/gateway-tool.ts b/src/agents/tools/gateway-tool.ts index 337ed564f..60b7da983 100644 --- a/src/agents/tools/gateway-tool.ts +++ b/src/agents/tools/gateway-tool.ts @@ -30,12 +30,27 @@ const GatewayToolSchema = Type.Object({ gatewayUrl: Type.Optional(Type.String()), gatewayToken: Type.Optional(Type.String()), timeoutMs: Type.Optional(Type.Number()), - // config.apply, update.run + // config.apply raw: Type.Optional(Type.String()), + // config.apply, update.run sessionKey: Type.Optional(Type.String()), note: Type.Optional(Type.String()), restartDelayMs: Type.Optional(Type.Number()), }); +// Keep top-level object schemas while enforcing conditional requirements. +(GatewayToolSchema as typeof GatewayToolSchema & { allOf?: unknown[] }).allOf = + [ + { + if: { + properties: { + action: { const: "config.apply" }, + }, + required: ["action"], + }, + // biome-ignore lint/suspicious/noThenProperty: JSON Schema keyword. + then: { required: ["raw"] }, + }, + ]; export function createGatewayTool(opts?: { agentSessionKey?: string;