Skip to content

Commit 0a645c0

Browse files
committed
Auto-merge upstream openclaw/openclaw
2 parents 8d5f168 + 68fcd85 commit 0a645c0

11 files changed

Lines changed: 160 additions & 27 deletions

.vscode/settings.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,5 @@
1717
"typescript.preferences.importModuleSpecifierEnding": "js",
1818
"typescript.reportStyleChecksAsWarnings": false,
1919
"typescript.updateImportsOnFileMove.enabled": "always",
20-
"typescript.tsdk": "node_modules/typescript/lib",
21-
"typescript.experimental.useTsgo": true
20+
"typescript.tsdk": "node_modules/typescript/lib"
2221
}

extensions/video-generation-providers.live.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,9 @@ function expectBufferedVideo(
157157
if (!video?.buffer) {
158158
throw new Error("expected generated video buffer");
159159
}
160-
expect(video.buffer.byteLength).toBeGreaterThan(1024);
161-
return video;
160+
const { buffer, mimeType, fileName } = video;
161+
expect(buffer.byteLength).toBeGreaterThan(1024);
162+
return { buffer, mimeType, fileName };
162163
}
163164

164165
describeLive("video generation provider live", () => {

scripts/lib/local-heavy-check-runtime.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,9 @@ function readLocalCheckMode(env) {
245245
if (raw === "full" || raw === "fast") {
246246
return "full";
247247
}
248-
return "auto";
248+
// Keep local heavy checks conservative by default. Developers can still opt
249+
// into full-speed runs explicitly with OPENCLAW_LOCAL_CHECK_MODE=full.
250+
return "throttled";
249251
}
250252

251253
function resolveHostResources(hostResources) {

src/config/schema.base.generated.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8866,6 +8866,18 @@ export const GENERATED_BASE_CONFIG_SCHEMA: BaseConfigSchemaResponse = {
88668866
description:
88678867
"Maximum number of concurrent media understanding operations per turn across image, audio, and video tasks. Lower this in resource-constrained deployments to prevent CPU/network saturation.",
88688868
},
8869+
asyncCompletion: {
8870+
type: "object",
8871+
properties: {
8872+
directSend: {
8873+
type: "boolean",
8874+
title: "Async Media Completion Direct Send",
8875+
description:
8876+
"Enable direct channel sends for completed async music/video generation tasks instead of relying on the requester session wake path. Default off so detached media completion keeps the legacy model-delivery flow unless you opt in.",
8877+
},
8878+
},
8879+
additionalProperties: false,
8880+
},
88698881
image: {
88708882
type: "object",
88718883
properties: {

src/plugins/runtime/runtime-task-test-harness.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { vi } from "vitest";
22
import {
3+
resetTaskRegistryControlRuntimeForTests,
34
resetTaskRegistryDeliveryRuntimeForTests,
45
resetTaskRegistryForTests,
6+
setTaskRegistryControlRuntimeForTests,
57
setTaskRegistryDeliveryRuntimeForTests,
68
} from "../../tasks/runtime-internal.js";
79
import { resetTaskFlowRegistryForTests } from "../../tasks/task-flow-runtime-internal.js";
@@ -12,13 +14,6 @@ const runtimeTaskMocks = vi.hoisted(() => ({
1214
killSubagentRunAdminMock: vi.fn(),
1315
}));
1416

15-
vi.mock("../../tasks/task-registry-control.runtime.js", () => ({
16-
getAcpSessionManager: () => ({
17-
cancelSession: runtimeTaskMocks.cancelSessionMock,
18-
}),
19-
killSubagentRunAdmin: (params: unknown) => runtimeTaskMocks.killSubagentRunAdminMock(params),
20-
}));
21-
2217
export function getRuntimeTaskMocks() {
2318
return runtimeTaskMocks;
2419
}
@@ -27,11 +22,18 @@ export function installRuntimeTaskDeliveryMock(): void {
2722
setTaskRegistryDeliveryRuntimeForTests({
2823
sendMessage: runtimeTaskMocks.sendMessageMock,
2924
});
25+
setTaskRegistryControlRuntimeForTests({
26+
getAcpSessionManager: () => ({
27+
cancelSession: runtimeTaskMocks.cancelSessionMock,
28+
}),
29+
killSubagentRunAdmin: (params: unknown) => runtimeTaskMocks.killSubagentRunAdminMock(params),
30+
});
3031
}
3132

3233
export function resetRuntimeTaskTestState(
3334
taskRegistryOptions?: Parameters<typeof resetTaskRegistryForTests>[0],
3435
): void {
36+
resetTaskRegistryControlRuntimeForTests();
3537
resetTaskRegistryDeliveryRuntimeForTests();
3638
resetTaskRegistryForTests(taskRegistryOptions);
3739
resetTaskFlowRegistryForTests({ persist: false });

src/tasks/runtime-internal.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export {
33
createTaskRecord,
44
deleteTaskRecordById,
55
ensureTaskRegistryReady,
6+
resetTaskRegistryControlRuntimeForTests,
67
findLatestTaskForOwnerKey,
78
findLatestTaskForFlowId,
89
findLatestTaskForRelatedSessionKey,
@@ -25,6 +26,7 @@ export {
2526
resolveTaskForLookupToken,
2627
resetTaskRegistryForTests,
2728
isParentFlowLinkError,
29+
setTaskRegistryControlRuntimeForTests,
2830
setTaskRegistryDeliveryRuntimeForTests,
2931
setTaskCleanupAfterById,
3032
setTaskProgressById,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import os from "node:os";
2+
import path from "node:path";
3+
import { describe, expect, it } from "vitest";
4+
import { resolveTaskStateDir } from "./task-registry.paths.js";
5+
6+
describe("task registry paths", () => {
7+
it("uses the Vitest worker id to shard test state dirs", () => {
8+
expect(
9+
resolveTaskStateDir({
10+
VITEST: "true",
11+
VITEST_POOL_ID: "7",
12+
} as NodeJS.ProcessEnv),
13+
).toBe(path.join(os.tmpdir(), "openclaw-test-state", `${process.pid}-7`));
14+
});
15+
16+
it("prefers explicit state dir overrides over Vitest sharding", () => {
17+
expect(
18+
resolveTaskStateDir({
19+
OPENCLAW_STATE_DIR: "/tmp/openclaw-custom-state",
20+
VITEST: "true",
21+
VITEST_POOL_ID: "7",
22+
} as NodeJS.ProcessEnv),
23+
).toBe("/tmp/openclaw-custom-state");
24+
});
25+
});

src/tasks/task-registry.paths.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os from "node:os";
22
import path from "node:path";
3+
import { isMainThread, threadId } from "node:worker_threads";
34
import { resolveStateDir } from "../config/paths.js";
45

56
export function resolveTaskStateDir(env: NodeJS.ProcessEnv = process.env): string {
@@ -8,7 +9,14 @@ export function resolveTaskStateDir(env: NodeJS.ProcessEnv = process.env): strin
89
return resolveStateDir(env);
910
}
1011
if (env.VITEST || env.NODE_ENV === "test") {
11-
return path.join(os.tmpdir(), "openclaw-test-state", String(process.pid));
12+
const workerIdRaw = env.VITEST_WORKER_ID ?? env.VITEST_POOL_ID ?? "";
13+
const workerId = Number.parseInt(workerIdRaw, 10);
14+
const shardSuffix = Number.isFinite(workerId)
15+
? `${process.pid}-${workerId}`
16+
: isMainThread
17+
? String(process.pid)
18+
: `${process.pid}-${threadId}`;
19+
return path.join(os.tmpdir(), "openclaw-test-state", shardSuffix);
1220
}
1321
return resolveStateDir(env);
1422
}

src/tasks/task-registry.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,26 @@ type TaskRegistryDeliveryRuntime = Pick<
6363
typeof import("./task-registry-delivery-runtime.js"),
6464
"sendMessage"
6565
>;
66+
type TaskRegistryControlRuntime = {
67+
getAcpSessionManager: () => Pick<
68+
ReturnType<(typeof import("./task-registry-control.runtime.js"))["getAcpSessionManager"]>,
69+
"cancelSession"
70+
>;
71+
killSubagentRunAdmin: (typeof import("./task-registry-control.runtime.js"))["killSubagentRunAdmin"];
72+
};
6673
const TASK_REGISTRY_DELIVERY_RUNTIME_OVERRIDE_KEY = Symbol.for(
6774
"openclaw.taskRegistry.deliveryRuntimeOverride",
6875
);
69-
type TaskRegistryGlobalWithDeliveryOverride = typeof globalThis & {
76+
const TASK_REGISTRY_CONTROL_RUNTIME_OVERRIDE_KEY = Symbol.for(
77+
"openclaw.taskRegistry.controlRuntimeOverride",
78+
);
79+
type TaskRegistryGlobalWithRuntimeOverrides = typeof globalThis & {
7080
[TASK_REGISTRY_DELIVERY_RUNTIME_OVERRIDE_KEY]?: TaskRegistryDeliveryRuntime | null;
81+
[TASK_REGISTRY_CONTROL_RUNTIME_OVERRIDE_KEY]?: TaskRegistryControlRuntime | null;
7182
};
7283
let deliveryRuntimePromise: Promise<typeof import("./task-registry-delivery-runtime.js")> | null =
7384
null;
74-
let controlRuntimePromise: Promise<typeof import("./task-registry-control.runtime.js")> | null =
75-
null;
85+
let controlRuntimePromise: Promise<TaskRegistryControlRuntime> | null = null;
7686

7787
type TaskDeliveryOwner = {
7888
sessionKey?: string;
@@ -368,7 +378,7 @@ function appendTaskEvent(event: {
368378
}
369379

370380
function loadTaskRegistryDeliveryRuntime() {
371-
const deliveryRuntimeOverride = (globalThis as TaskRegistryGlobalWithDeliveryOverride)[
381+
const deliveryRuntimeOverride = (globalThis as TaskRegistryGlobalWithRuntimeOverrides)[
372382
TASK_REGISTRY_DELIVERY_RUNTIME_OVERRIDE_KEY
373383
];
374384
if (deliveryRuntimeOverride) {
@@ -379,6 +389,12 @@ function loadTaskRegistryDeliveryRuntime() {
379389
}
380390

381391
function loadTaskRegistryControlRuntime() {
392+
const controlRuntimeOverride = (globalThis as TaskRegistryGlobalWithRuntimeOverrides)[
393+
TASK_REGISTRY_CONTROL_RUNTIME_OVERRIDE_KEY
394+
];
395+
if (controlRuntimeOverride) {
396+
return Promise.resolve(controlRuntimeOverride);
397+
}
382398
// Registry reads happen far more often than task cancellation, so keep the ACP/subagent
383399
// control graph off the default import path until a cancellation flow actually needs it.
384400
controlRuntimePromise ??= import("./task-registry-control.runtime.js");
@@ -1964,15 +1980,29 @@ export function resetTaskRegistryForTests(opts?: { persist?: boolean }) {
19641980
}
19651981

19661982
export function resetTaskRegistryDeliveryRuntimeForTests() {
1967-
(globalThis as TaskRegistryGlobalWithDeliveryOverride)[
1983+
(globalThis as TaskRegistryGlobalWithRuntimeOverrides)[
19681984
TASK_REGISTRY_DELIVERY_RUNTIME_OVERRIDE_KEY
19691985
] = null;
19701986
deliveryRuntimePromise = null;
19711987
}
19721988

19731989
export function setTaskRegistryDeliveryRuntimeForTests(runtime: TaskRegistryDeliveryRuntime): void {
1974-
(globalThis as TaskRegistryGlobalWithDeliveryOverride)[
1990+
(globalThis as TaskRegistryGlobalWithRuntimeOverrides)[
19751991
TASK_REGISTRY_DELIVERY_RUNTIME_OVERRIDE_KEY
19761992
] = runtime;
19771993
deliveryRuntimePromise = null;
19781994
}
1995+
1996+
export function resetTaskRegistryControlRuntimeForTests() {
1997+
(globalThis as TaskRegistryGlobalWithRuntimeOverrides)[
1998+
TASK_REGISTRY_CONTROL_RUNTIME_OVERRIDE_KEY
1999+
] = null;
2000+
controlRuntimePromise = null;
2001+
}
2002+
2003+
export function setTaskRegistryControlRuntimeForTests(runtime: TaskRegistryControlRuntime): void {
2004+
(globalThis as TaskRegistryGlobalWithRuntimeOverrides)[
2005+
TASK_REGISTRY_CONTROL_RUNTIME_OVERRIDE_KEY
2006+
] = runtime;
2007+
controlRuntimePromise = null;
2008+
}

test/scripts/ci-node-test-plan.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => {
77

88
expect(shards).not.toHaveLength(0);
99
expect(shards.map((shard) => shard.checkName)).toEqual(
10-
shards.map((shard) => `checks-node-core-test-${shard.shardName}`),
10+
shards.map((shard) =>
11+
shard.shardName.startsWith("core-unit-")
12+
? `checks-node-core-${shard.shardName.slice("core-unit-".length)}`
13+
: `checks-node-${shard.shardName}`,
14+
),
1115
);
1216
});
1317

0 commit comments

Comments
 (0)