diff --git a/CHANGELOG.md b/CHANGELOG.md index ea155db21..b7c1f0845 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - Sandbox: add `agent.sandbox.workspaceAccess` (`none`/`ro`/`rw`) to control agent workspace visibility inside the container; `ro` hard-disables `write`/`edit`. - Routing: allow per-agent sandbox overrides (including `workspaceAccess` and `sandbox.tools`) plus per-agent tool policies in multi-agent configs. Thanks @pasogott for PR #380. - Tools: add Telegram/WhatsApp reaction tools (with per-provider gating). Thanks @zats for PR #353. +- Tools: flatten literal-union schemas for Claude on Vertex AI. Thanks @carlulsoe for PR #409. - Tools: unify reaction removal semantics across Discord/Slack/Telegram/WhatsApp and allow WhatsApp reaction routing across accounts. - Gateway/CLI: add daemon runtime selection (Node recommended; Bun optional) and document WhatsApp/Baileys Bun WebSocket instability on reconnect. - CLI: add `clawdbot docs` live docs search with pretty output. diff --git a/README.md b/README.md index d15bd5680..a6623a632 100644 --- a/README.md +++ b/README.md @@ -454,5 +454,5 @@ Thanks to all clawtributors: adamgall jalehman jarvis-medmatic mneves75 regenrek tobiasbischoff MSch obviyus dbhurley Asleep123 Iamadig imfing kitze nachoiacovino VACInc cash-echo-bot claude kiranjd pcty-nextgen-service-account minghinmatthewlam ngutman onutc oswalpalash snopoke ManuelHettich loukotal hugobarauna AbhisekBasu1 emanuelst dantelex erikpr1994 antons RandyVentures - reeltimeapps fcatuhe maxsumrall + reeltimeapps fcatuhe maxsumrall carlulsoe

diff --git a/src/agents/pi-tools.test.ts b/src/agents/pi-tools.test.ts index 566e85659..d805eff0c 100644 --- a/src/agents/pi-tools.test.ts +++ b/src/agents/pi-tools.test.ts @@ -31,6 +31,39 @@ describe("createClawdbotCodingTools", () => { expect(parameters.required ?? []).toContain("action"); }); + it("flattens anyOf-of-literals to enum for provider compatibility", () => { + const tools = createClawdbotCodingTools(); + const browser = tools.find((tool) => tool.name === "browser"); + expect(browser).toBeDefined(); + + const parameters = browser?.parameters as { + properties?: Record; + }; + const action = parameters.properties?.action as + | { + type?: unknown; + enum?: unknown[]; + anyOf?: unknown[]; + } + | undefined; + + expect(action?.type).toBe("string"); + expect(action?.anyOf).toBeUndefined(); + expect(Array.isArray(action?.enum)).toBe(true); + expect(action?.enum).toContain("act"); + + const format = parameters.properties?.format as + | { + type?: unknown; + enum?: unknown[]; + anyOf?: unknown[]; + } + | undefined; + expect(format?.type).toBe("string"); + expect(format?.anyOf).toBeUndefined(); + expect(format?.enum).toEqual(["aria", "ai"]); + }); + it("preserves action enums in normalized schemas", () => { const tools = createClawdbotCodingTools(); const toolNames = ["browser", "canvas", "nodes", "cron", "gateway"]; diff --git a/src/agents/tools/browser-tool.ts b/src/agents/tools/browser-tool.ts index 12adc177a..6e997a1ae 100644 --- a/src/agents/tools/browser-tool.ts +++ b/src/agents/tools/browser-tool.ts @@ -28,25 +28,29 @@ import { readStringParam, } from "./common.js"; +const BROWSER_ACT_KINDS = [ + "click", + "type", + "press", + "hover", + "drag", + "select", + "fill", + "resize", + "wait", + "evaluate", + "close", +] as const; + +type BrowserActKind = (typeof BROWSER_ACT_KINDS)[number]; + // NOTE: Using a flattened object schema instead of Type.Union([Type.Object(...), ...]) // because Claude API on Vertex AI rejects nested anyOf schemas as invalid JSON Schema. // The discriminator (kind) determines which properties are relevant; runtime validates. const BrowserActSchema = Type.Object({ - kind: Type.Unsafe({ + kind: Type.Unsafe({ type: "string", - enum: [ - "click", - "type", - "press", - "hover", - "drag", - "select", - "fill", - "resize", - "wait", - "evaluate", - "close", - ], + enum: [...BROWSER_ACT_KINDS], }), // Common fields targetId: Type.Optional(Type.String()), @@ -67,7 +71,9 @@ const BrowserActSchema = Type.Object({ // select values: Type.Optional(Type.Array(Type.String())), // fill - use permissive array of objects - fields: Type.Optional(Type.Array(Type.Object({}, { additionalProperties: true }))), + fields: Type.Optional( + Type.Array(Type.Object({}, { additionalProperties: true })), + ), // resize width: Type.Optional(Type.Number()), height: Type.Optional(Type.Number()),