From e339038cc0edea5e8ac8f8d94fafd1d6845a0e50 Mon Sep 17 00:00:00 2001 From: qiziAI <532901708@qq.com> Date: Sat, 11 Apr 2026 18:12:09 +0800 Subject: [PATCH] =?UTF-8?q?Fix:=20Sync=20asyncCompletion=20config=20in=20z?= =?UTF-8?q?od-schema.ts=20to=20resolve=20"Unrecog=E2=80=A6=20(#63618)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merged via squash. Prepared head SHA: dcce839c071c0a40b82611b15be51fdffdedf3e0 Co-authored-by: qiziAI <17017936+qiziAI@users.noreply.github.com> Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com> Reviewed-by: @altaywtf --- CHANGELOG.md | 1 + src/config/config.schema-regressions.test.ts | 13 +++++++++++++ src/config/zod-schema.core.ts | 17 +++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f38844028a4..7839f94d97a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -150,6 +150,7 @@ Docs: https://docs.openclaw.ai - Browser/security: reject strict-policy hostname navigation unless the hostname is an explicit allowlist exception or IP literal, and route CDP HTTP discovery through the pinned SSRF fetch path. (#64367) Thanks @eleqtrizit. - Models/vLLM: ignore empty `tool_calls` arrays from reasoning-model OpenAI-compatible replies, reset false `toolUse` stop reasons when no actual tool calls were parsed, and stop sending `tool_choice` unless tools are present so vLLM reasoning responses no longer hang indefinitely. (#61197, #61534) Thanks @balajisiva. - Heartbeat/scheduling: spread interval heartbeats across stable per-agent phases derived from gateway identity, so provider traffic is distributed more uniformly across the configured interval instead of clustering around startup-relative times. (#64560) Thanks @odysseus0. +- Config/media: accept `tools.media.asyncCompletion.directSend` in strict config validation so gateways no longer reject the generated-schema-backed async media completion setting at startup. (#63618) Thanks @qiziAI. ## 2026.4.9 diff --git a/src/config/config.schema-regressions.test.ts b/src/config/config.schema-regressions.test.ts index 8a8b004b9e2..305a9fdd0b7 100644 --- a/src/config/config.schema-regressions.test.ts +++ b/src/config/config.schema-regressions.test.ts @@ -253,6 +253,19 @@ describe("config schema regressions", () => { expect(res.ok).toBe(false); }); + it("accepts tools.media.asyncCompletion.directSend", () => { + const res = validateConfigObject({ + tools: { + media: { + asyncCompletion: { + directSend: true, + }, + }, + }, + }); + + expect(res.ok).toBe(true); + }); it("accepts discovery.wideArea.domain for unicast DNS-SD", () => { const res = validateConfigObject({ discovery: { diff --git a/src/config/zod-schema.core.ts b/src/config/zod-schema.core.ts index 4e36f047105..20c21760412 100644 --- a/src/config/zod-schema.core.ts +++ b/src/config/zod-schema.core.ts @@ -9,6 +9,7 @@ import { import { normalizeStringEntries } from "../shared/string-normalization.js"; import type { ModelCompatConfig } from "./types.models.js"; import { MODEL_APIS } from "./types.models.js"; +import type { MediaToolsConfig } from "./types.tools.js"; import { createAllowDenyChannelRulesSchema } from "./zod-schema.allowdeny.js"; import { sensitive } from "./zod-schema.sensitive.js"; @@ -772,6 +773,12 @@ export const ToolsMediaSchema = z .object({ models: z.array(MediaUnderstandingModelSchema).optional(), concurrency: z.number().int().positive().optional(), + asyncCompletion: z + .object({ + directSend: z.boolean().optional(), + }) + .strict() + .optional(), image: ToolsMediaUnderstandingSchema.optional(), audio: ToolsMediaUnderstandingSchema.optional(), video: ToolsMediaUnderstandingSchema.optional(), @@ -779,6 +786,16 @@ export const ToolsMediaSchema = z .strict() .optional(); +type ToolsMediaConfigFromSchema = NonNullable>; +type _ToolsMediaAsyncCompletionSchemaAssignableToType = AssertAssignable< + ToolsMediaConfigFromSchema["asyncCompletion"], + MediaToolsConfig["asyncCompletion"] +>; +type _ToolsMediaAsyncCompletionTypeAssignableToSchema = AssertAssignable< + MediaToolsConfig["asyncCompletion"], + ToolsMediaConfigFromSchema["asyncCompletion"] +>; + export const LinkModelSchema = z .object({ type: z.literal("cli").optional(),