diff --git a/CHANGELOG.md b/CHANGELOG.md index d735f89d153..c4e5865af64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ Docs: https://docs.openclaw.ai - Browser/Extension relay init: dedupe concurrent same-port relay startup with shared in-flight initialization promises so callers await one startup lifecycle and receive consistent success/failure results. Landed from contributor PR #21277 by @HOYALIM. (Related #20688) - Browser/Extension relay shutdown: flush pending extension-request timers/rejections during relay `stop()` before socket/server teardown so in-flight extension waits do not survive shutdown windows. Landed from contributor PR #24142 by @kevinWangSheng. - Browser/Extension relay reconnect resilience: keep CDP clients alive across brief MV3 extension disconnect windows, wait briefly for extension reconnect before failing in-flight CDP commands, and only tear down relay target/client state after reconnect grace expires. Landed from contributor PR #27617 by @davidemanuelDEV. +- Browser/Fill relay + CLI parity: accept `act.fill` fields without explicit `type` by defaulting missing/empty `type` to `text` in both browser relay route parsing and `openclaw browser fill` CLI field parsing, so relay calls no longer fail when the model omits field type metadata. Landed from contributor PR #27662 by @Uface11. (#27296) Thanks @Uface11. - Browser/Route decode hardening: guard malformed percent-encoding in relay target action routes and browser route-param decoding so crafted `%` paths return `400` instead of crashing/unhandled URI decode failures. Landed from contributor PR #11880 by @Yida-Dev. - Feishu/Permission error dispatch: merge sender-name permission notices into the main inbound dispatch so one user message produces one agent turn/reply (instead of a duplicate permission-notice turn), with regression coverage. (#27381) thanks @byungsker. - Feishu/Inbound message metadata: include inbound `message_id` in `BodyForAgent` on a dedicated metadata line so agents can reliably correlate and act on media/message operations that require message IDs, with regression coverage. (#27253) thanks @xss925175263. diff --git a/src/cli/browser-cli-actions-input/shared.test.ts b/src/cli/browser-cli-actions-input/shared.test.ts new file mode 100644 index 00000000000..553fd90fbef --- /dev/null +++ b/src/cli/browser-cli-actions-input/shared.test.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from "vitest"; +import { readFields } from "./shared.js"; + +describe("readFields", () => { + it("defaults missing type to text", async () => { + await expect(readFields({ fields: '[{"ref":"7","value":"world"}]' })).resolves.toEqual([ + { ref: "7", type: "text", value: "world" }, + ]); + }); + + it("requires ref", async () => { + await expect(readFields({ fields: '[{"type":"textbox","value":"world"}]' })).rejects.toThrow( + "fields[0] must include ref", + ); + }); +}); diff --git a/src/cli/browser-cli-actions-input/shared.ts b/src/cli/browser-cli-actions-input/shared.ts index c3a68aa0bab..69e1ddd8b57 100644 --- a/src/cli/browser-cli-actions-input/shared.ts +++ b/src/cli/browser-cli-actions-input/shared.ts @@ -70,18 +70,19 @@ export async function readFields(opts: { const rec = entry as Record; const ref = typeof rec.ref === "string" ? rec.ref.trim() : ""; const type = typeof rec.type === "string" ? rec.type.trim() : ""; - if (!ref || !type) { - throw new Error(`fields[${index}] must include ref and type`); + if (!ref) { + throw new Error(`fields[${index}] must include ref`); } + const resolvedType = type || "text"; if ( typeof rec.value === "string" || typeof rec.value === "number" || typeof rec.value === "boolean" ) { - return { ref, type, value: rec.value }; + return { ref, type: resolvedType, value: rec.value }; } if (rec.value === undefined || rec.value === null) { - return { ref, type }; + return { ref, type: resolvedType }; } throw new Error(`fields[${index}].value must be string, number, boolean, or null`); });