diff --git a/CHANGELOG.md b/CHANGELOG.md index 996dd8f9b3f..7094e0a0e4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Docs: https://docs.openclaw.ai - Exec approvals/display: escape raw control characters (including newline and carriage return) in the shared and macOS approval-prompt command sanitizers, so trailing command payloads no longer render on hidden extra lines in the approval UI. (#68198) - OpenAI Codex/OAuth + Pi: keep imported Codex CLI OAuth bootstrap, Pi auth export, and runtime overlay handling aligned so Codex sessions survive refresh and health checks without leaking transient CLI state into saved auth files. Thanks @vincentkoc. - Agents/TTS: report failed speech synthesis as a real tool error so unconfigured providers no longer feed successful TTS failure output back into agent loops. (#67980) Thanks @lawrence3699. +- Gateway/wake: allow unknown properties on wake payloads so external senders like Paperclip can attach opaque metadata without failing schema validation. (#68355) Thanks @kagura-agent. ## 2026.4.15 diff --git a/src/gateway/protocol/index.test.ts b/src/gateway/protocol/index.test.ts index 97a97e6cbf1..184b714215f 100644 --- a/src/gateway/protocol/index.test.ts +++ b/src/gateway/protocol/index.test.ts @@ -1,7 +1,7 @@ import type { ErrorObject } from "ajv"; import { describe, expect, it } from "vitest"; import { TALK_TEST_PROVIDER_ID } from "../../test-utils/talk-test-provider.js"; -import { formatValidationErrors, validateTalkConfigResult } from "./index.js"; +import { formatValidationErrors, validateTalkConfigResult, validateWakeParams } from "./index.js"; const makeError = (overrides: Partial): ErrorObject => ({ keyword: "type", @@ -113,3 +113,35 @@ describe("validateTalkConfigResult", () => { ).toBe(false); }); }); + +describe("validateWakeParams", () => { + it("accepts valid wake params", () => { + expect(validateWakeParams({ mode: "now", text: "hello" })).toBe(true); + expect(validateWakeParams({ mode: "next-heartbeat", text: "remind me" })).toBe(true); + }); + + it("rejects missing required fields", () => { + expect(validateWakeParams({ mode: "now" })).toBe(false); + expect(validateWakeParams({ text: "hello" })).toBe(false); + expect(validateWakeParams({})).toBe(false); + }); + + it("accepts unknown properties for forward compatibility", () => { + expect( + validateWakeParams({ + mode: "now", + text: "hello", + paperclip: { version: "2026.416.0", source: "wake" }, + }), + ).toBe(true); + + expect( + validateWakeParams({ + mode: "next-heartbeat", + text: "check back", + unknownFutureField: 42, + anotherExtra: true, + }), + ).toBe(true); + }); +}); diff --git a/src/gateway/protocol/schema/agent.ts b/src/gateway/protocol/schema/agent.ts index fbfe2be37b5..22fe3816602 100644 --- a/src/gateway/protocol/schema/agent.ts +++ b/src/gateway/protocol/schema/agent.ts @@ -196,5 +196,5 @@ export const WakeParamsSchema = Type.Object( mode: Type.Union([Type.Literal("now"), Type.Literal("next-heartbeat")]), text: NonEmptyString, }, - { additionalProperties: false }, + { additionalProperties: true }, // external wake senders may attach opaque metadata );