惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
J
Java Code Geeks
小众软件
小众软件
Jina AI
Jina AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Hugging Face - Blog
Hugging Face - Blog
Stack Overflow Blog
Stack Overflow Blog
Blog — PlanetScale
Blog — PlanetScale
C
Check Point Blog
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - Franky
Apple Machine Learning Research
Apple Machine Learning Research
G
Google Developers Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The GitHub Blog
The GitHub Blog
腾讯CDC
T
The Blog of Author Tim Ferriss
大猫的无限游戏
大猫的无限游戏
量子位
M
MIT News - Artificial intelligence
Last Week in AI
Last Week in AI
L
LangChain Blog

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix: honor configured media timeouts · openclaw/openclaw@...
steipete · 2026-05-12 · via Recent Commits to openclaw:main
Original file line numberDiff line numberDiff line change

@@ -59,6 +59,7 @@ Docs: https://docs.openclaw.ai

5959
6060

### Fixes

6161
62+

- Media generation: honor configured music and video generation timeouts when tool calls omit `timeoutMs`, matching image generation behavior. (#80687)

6263

- Plugins/update: include beta-channel fallback details in plugin update outcomes when `@beta` is unavailable and OpenClaw uses the recorded default/latest plugin spec, making mixed beta/latest plugin cohorts visible in update summaries. Fixes #80689. Thanks @BKF-Gitty.

6364

- Control UI/performance: scope Nodes polling to the active Nodes tab, debounce stale session-list reconciliation, and bound chat-side session refreshes so long-running dashboards avoid background reload churn. Thanks @BunsDev.

6465

- Plugins/channels: explain bundled channel entry files that reach the legacy plugin loader as setup-runtime loader mismatches instead of generic missing-register failures. Thanks @chinar-amrutkar.

Original file line numberDiff line numberDiff line change

@@ -161,7 +161,7 @@ Direct generation example:

161161

Output format hint when the provider supports it.

162162

</ParamField>

163163

<ParamField path="filename" type="string">Output filename hint.</ParamField>

164-

<ParamField path="timeoutMs" type="number">Optional provider request timeout in milliseconds. Values below 10000ms are raised to 10000ms and reported in the tool result.</ParamField>

164+

<ParamField path="timeoutMs" type="number">Optional provider request timeout in milliseconds. When omitted, OpenClaw uses `agents.defaults.musicGenerationModel.timeoutMs` if configured. Values below 10000ms are raised to 10000ms and reported in the tool result.</ParamField>

165165
166166

<Note>

167167

Not all providers support all parameters. OpenClaw still validates hard

Original file line numberDiff line numberDiff line change

@@ -223,7 +223,7 @@ dimensions). Providers that do not declare it surface the value via

223223

</ParamField>

224224

<ParamField path="model" type="string">Provider/model override (e.g. `runway/gen4.5`).</ParamField>

225225

<ParamField path="filename" type="string">Output filename hint.</ParamField>

226-

<ParamField path="timeoutMs" type="number">Optional provider operation timeout in milliseconds.</ParamField>

226+

<ParamField path="timeoutMs" type="number">Optional provider operation timeout in milliseconds. When omitted, OpenClaw uses `agents.defaults.videoGenerationModel.timeoutMs` if configured.</ParamField>

227227

<ParamField path="providerOptions" type="object">

228228

Provider-specific options as a JSON object (e.g. `{"seed": 42, "draft": true}`).

229229

Providers that declare a typed schema validate the keys and types; unknown

Original file line numberDiff line numberDiff line change

@@ -408,6 +408,57 @@ describe("createMusicGenerateTool", () => {

408408

});

409409

});

410410
411+

it("uses configured timeoutMs for music generation and lets calls override it", async () => {

412+

vi.spyOn(musicGenerationRuntime, "generateMusic").mockResolvedValue({

413+

provider: "google",

414+

model: "lyria-3-clip-preview",

415+

attempts: [],

416+

ignoredOverrides: [],

417+

tracks: [

418+

{

419+

buffer: Buffer.from("music-bytes"),

420+

mimeType: "audio/mpeg",

421+

fileName: "night-drive.mp3",

422+

},

423+

],

424+

});

425+

vi.spyOn(mediaStore, "saveMediaBuffer").mockResolvedValue({

426+

path: "/tmp/generated-night-drive.mp3",

427+

id: "generated-night-drive.mp3",

428+

size: 11,

429+

contentType: "audio/mpeg",

430+

});

431+
432+

const tool = createMusicGenerateTool({

433+

config: asConfig({

434+

agents: {

435+

defaults: {

436+

musicGenerationModel: {

437+

primary: "google/lyria-3-clip-preview",

438+

timeoutMs: 180_000,

439+

},

440+

},

441+

},

442+

}),

443+

});

444+

if (!tool) {

445+

throw new Error("expected music_generate tool");

446+

}

447+
448+

const defaultResult = await tool.execute("call-timeout-default", {

449+

prompt: "night-drive synthwave",

450+

});

451+

const overrideResult = await tool.execute("call-timeout-override", {

452+

prompt: "night-drive synthwave",

453+

timeoutMs: 12_345,

454+

});

455+
456+

expect(generateMusicOptions(0).timeoutMs).toBe(180_000);

457+

expect(generateMusicOptions(1).timeoutMs).toBe(12_345);

458+

expect(detailsOf(defaultResult).timeoutMs).toBe(180_000);

459+

expect(detailsOf(overrideResult).timeoutMs).toBe(12_345);

460+

});

461+
411462

it("starts background generation and wakes the session with MEDIA lines", async () => {

412463

taskExecutorMocks.createRunningTaskRun.mockReturnValue({

413464

taskId: "task-123",

Original file line numberDiff line numberDiff line change

@@ -638,7 +638,8 @@ export function createMusicGenerateTool(options?: {

638638

});

639639

const format = normalizeOutputFormat(readStringParam(args, "format"));

640640

const filename = readStringParam(args, "filename");

641-

const requestedTimeoutMs = readGenerationTimeoutMs(args);

641+

const requestedTimeoutMs =

642+

readGenerationTimeoutMs(args) ?? musicGenerationModelConfig.timeoutMs;

642643

const timeout = normalizeMusicGenerationTimeoutMs(requestedTimeoutMs);

643644

const timeoutMs = timeout.timeoutMs;

644645

const imageInputs = normalizeReferenceImageInputs(args);

Original file line numberDiff line numberDiff line change

@@ -361,6 +361,45 @@ describe("createVideoGenerateTool", () => {

361361

expect(taskExecutorMocks.completeTaskRunByRunId).not.toHaveBeenCalled();

362362

});

363363
364+

it("uses configured timeoutMs for video generation and lets calls override it", async () => {

365+

mockVideoPluginProvider();

366+

const generateSpy = mockSavedVideoResult();

367+

const tool = createVideoGenerateTool({

368+

config: asConfig({

369+

agents: {

370+

defaults: {

371+

videoGenerationModel: {

372+

primary: "video-plugin/vid-v1",

373+

timeoutMs: 180_000,

374+

},

375+

},

376+

},

377+

}),

378+

});

379+

if (!tool) {

380+

throw new Error("expected video_generate tool");

381+

}

382+
383+

const defaultResult = await tool.execute("call-timeout-default", {

384+

prompt: "friendly lobster surfing",

385+

});

386+

vi.spyOn(mediaStore, "saveMediaBuffer").mockResolvedValueOnce({

387+

path: "/tmp/out-override.mp4",

388+

id: "out-override.mp4",

389+

size: 11,

390+

contentType: "video/mp4",

391+

});

392+

const overrideResult = await tool.execute("call-timeout-override", {

393+

prompt: "friendly lobster surfing",

394+

timeoutMs: 12_345,

395+

});

396+
397+

expect((firstMockCallArg(generateSpy) as { timeoutMs?: number }).timeoutMs).toBe(180_000);

398+

expect((generateSpy.mock.calls[1]?.[0] as { timeoutMs?: number }).timeoutMs).toBe(12_345);

399+

expect(resultDetails(defaultResult).timeoutMs).toBe(180_000);

400+

expect(resultDetails(overrideResult).timeoutMs).toBe(12_345);

401+

});

402+
364403

it("uses the video media cap when mediaMaxMb is not configured", async () => {

365404

vi.spyOn(videoGenerationRuntime, "generateVideo").mockResolvedValue({

366405

provider: "qwen",

Original file line numberDiff line numberDiff line change

@@ -866,7 +866,7 @@ export function createVideoGenerateTool(options?: {

866866

});

867867

const audio = readBooleanToolParam(args, "audio");

868868

const watermark = readBooleanToolParam(args, "watermark");

869-

const timeoutMs = readGenerationTimeoutMs(args);

869+

const timeoutMs = readGenerationTimeoutMs(args) ?? videoGenerationModelConfig.timeoutMs;

870870

// providerOptions must be a plain object. Arrays are objects in JS, so

871871

// exclude them explicitly — a bogus call like `providerOptions: ["seed", 42]`

872872

// would otherwise be cast to `Record<string, unknown>` with numeric-string

Original file line numberDiff line numberDiff line change

@@ -85,6 +85,36 @@ describe("music-generation runtime", () => {

8585

]);

8686

});

8787
88+

it("uses configured music-generation timeout when call omits timeoutMs", async () => {

89+

let seenTimeoutMs: number | undefined;

90+

providers = [

91+

{

92+

id: "music-plugin",

93+

capabilities: {},

94+

async generateMusic(req: { timeoutMs?: number }) {

95+

seenTimeoutMs = req.timeoutMs;

96+

return {

97+

tracks: [{ buffer: Buffer.from("mp3-bytes"), mimeType: "audio/mpeg" }],

98+

model: "track-v1",

99+

};

100+

},

101+

},

102+

];

103+
104+

await runGenerateMusic({

105+

cfg: {

106+

agents: {

107+

defaults: {

108+

musicGenerationModel: { primary: "music-plugin/track-v1", timeoutMs: 300_000 },

109+

},

110+

},

111+

} as OpenClawConfig,

112+

prompt: "play a synth line",

113+

});

114+
115+

expect(seenTimeoutMs).toBe(300_000);

116+

});

117+
88118

it("does not list providers when explicit config disables auto provider fallback", async () => {

89119

const provider: MusicGenerationProvider = {

90120

id: "music-plugin",

Original file line numberDiff line numberDiff line change

@@ -1,4 +1,5 @@

11

import type { FallbackAttempt } from "../agents/model-fallback.types.js";

2+

import { resolveAgentModelTimeoutMsValue } from "../config/model-input.js";

23

import type { OpenClawConfig } from "../config/types.openclaw.js";

34

import { createSubsystemLogger } from "../logging/subsystem.js";

45

import {

@@ -40,6 +41,9 @@ export async function generateMusic(

4041

const getProvider = deps.getProvider ?? getMusicGenerationProvider;

4142

const listProviders = deps.listProviders ?? listMusicGenerationProviders;

4243

const logger = deps.log ?? log;

44+

const timeoutMs =

45+

params.timeoutMs ??

46+

resolveAgentModelTimeoutMsValue(params.cfg.agents?.defaults?.musicGenerationModel);

4347

const candidates = resolveCapabilityModelCandidates({

4448

cfg: params.cfg,

4549

modelConfig: params.cfg.agents?.defaults?.musicGenerationModel,

@@ -99,7 +103,7 @@ export async function generateMusic(

99103

durationSeconds: sanitized.durationSeconds,

100104

format: sanitized.format,

101105

inputImages: params.inputImages,

102-

...(params.timeoutMs !== undefined ? { timeoutMs: params.timeoutMs } : {}),

106+

...(timeoutMs !== undefined ? { timeoutMs } : {}),

103107

});

104108

if (!Array.isArray(result.tracks) || result.tracks.length === 0) {

105109

throw new Error("Music generation provider returned no tracks.");

Original file line numberDiff line numberDiff line change

@@ -117,6 +117,36 @@ describe("video-generation runtime", () => {

117117

]);

118118

});

119119
120+

it("uses configured video-generation timeout when call omits timeoutMs", async () => {

121+

let seenTimeoutMs: number | undefined;

122+

providers = [

123+

{

124+

id: "video-plugin",

125+

capabilities: {},

126+

async generateVideo(req: { timeoutMs?: number }) {

127+

seenTimeoutMs = req.timeoutMs;

128+

return {

129+

videos: [{ buffer: Buffer.from("mp4-bytes"), mimeType: "video/mp4" }],

130+

model: "vid-v1",

131+

};

132+

},

133+

},

134+

];

135+
136+

await runGenerateVideo({

137+

cfg: {

138+

agents: {

139+

defaults: {

140+

videoGenerationModel: { primary: "video-plugin/vid-v1", timeoutMs: 300_000 },

141+

},

142+

},

143+

} as OpenClawConfig,

144+

prompt: "animate a cat",

145+

});

146+
147+

expect(seenTimeoutMs).toBe(300_000);

148+

});

149+
120150

it("does not list providers when explicit config disables auto provider fallback", async () => {

121151

const provider: VideoGenerationProvider = {

122152

id: "video-plugin",