Files
openclaw/src/tasks/task-status-access.test.ts
Peter Lee cab8040b14 fix(cron): preserve cron context in session entry for async completion wakes (#101078)
* fix(cron): preserve cron context in session entry for async completion wakes (#99919)

Persist bootstrapContextRunKind on the session entry after cron agent
runs, and restore provider/model/thinking/runKind from the session
entry into directAgentParams when an async completion wake (e.g. media
generation) resumes a cron session.

Before this fix, async completion wakes lost the original cron run
context and fell back to account defaults, causing multi-step cron tasks
to silently dead-end after the first async media generation call.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(cron): authorize model override on trusted in-process dispatch for cron context restoration

* fix(cron): persist bootstrapContextRunKind on base session entry for async completion wakes

* fix(cron): route async completion wake to base cron session key instead of ephemeral run key

When the cron run-key fallback fires, record the base cron key as
effectiveSessionKey so deliverDirectSubagentAnnounce can route the
agent call to the persisted session row with its transcript and task
context instead of starting a fresh turn (#99919).

* fix(cron): add bootstrapContextRunKind to session entry slot keys and declare loadRequesterSessionEntry return type

* fix(cron): rebase onto upstream main, restore upstream agent-command behavior while keeping bootstrapContextRunKind persistence

* fix(cron): persist bootstrapContextRunKind from a pre-mutation snapshot to produce a real delta

* fix(cron): move pre-mutation snapshot inside guard so initialEntry is non-optional

* fix(cron): preserve async media continuation context

Co-authored-by: Peter Lee <li.xialong@xydigit.com>

* fix(cron): retain continuation after base cleanup

* test(gateway): complete agent scope mock

* test(gateway): preserve agent scope exports

* test(cron): persist mocked session mutations

* test(cron): model persisted session fixtures

* fix(agents): snapshot cron continuation retries

* fix(cron): harden async continuation settlement

* test(cron): control continuation recovery clock

* fix(gateway): narrow continuation model row

* chore(changelog): defer cron continuation note

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 03:07:30 +01:00

74 lines
2.5 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
import {
clearGeneratedMediaTaskActivity,
registerGeneratedMediaTaskActivity,
resetGeneratedMediaTaskActivityForTests,
} from "./generated-media-task-activity.js";
import {
getGeneratedMediaTaskIdsForSessionKey,
hasNewGeneratedMediaTaskForSessionKey,
hasPendingGeneratedMediaTaskForSessionKey,
} from "./task-status-access.js";
const mocks = vi.hoisted(() => ({ listTaskRecords: vi.fn() }));
vi.mock("./task-registry.js", () => ({
findTaskByRunId: vi.fn(),
getTaskById: vi.fn(),
listTaskRecords: mocks.listTaskRecords,
listTasksForAgentId: vi.fn(),
listTasksForSessionKey: vi.fn(),
}));
describe("generated media task snapshots", () => {
const sessionKey = "agent:main:cron:job:run:run-id";
beforeEach(() => {
resetGeneratedMediaTaskActivityForTests();
mocks.listTaskRecords.mockReset();
});
it("detects only media admitted by the current exact-run attempt", () => {
const tasks = [
{
taskId: "old-image",
taskKind: "image_generation",
requesterSessionKey: sessionKey,
ownerKey: sessionKey,
},
];
mocks.listTaskRecords.mockImplementation(() => tasks);
const before = getGeneratedMediaTaskIdsForSessionKey(sessionKey);
expect(hasNewGeneratedMediaTaskForSessionKey(sessionKey, before)).toBe(false);
tasks.push({
taskId: "new-video",
taskKind: "video_generation",
requesterSessionKey: sessionKey,
ownerKey: sessionKey,
});
expect(hasNewGeneratedMediaTaskForSessionKey(sessionKey, before)).toBe(true);
});
it("does not apply exact-run replay guards to descendant sessions", () => {
mocks.listTaskRecords.mockReturnValue([]);
expect(getGeneratedMediaTaskIdsForSessionKey(`${sessionKey}:subagent:worker`)).toEqual(
new Set(),
);
expect(mocks.listTaskRecords).not.toHaveBeenCalled();
});
it("tracks active media when a detached runtime does not mirror core tasks", () => {
mocks.listTaskRecords.mockReturnValue([]);
const before = getGeneratedMediaTaskIdsForSessionKey(sessionKey);
registerGeneratedMediaTaskActivity("tool:image_generate:run-1", sessionKey);
expect(hasNewGeneratedMediaTaskForSessionKey(sessionKey, before)).toBe(true);
expect(hasPendingGeneratedMediaTaskForSessionKey(sessionKey)).toBe(true);
clearGeneratedMediaTaskActivity("tool:image_generate:run-1");
expect(hasNewGeneratedMediaTaskForSessionKey(sessionKey, before)).toBe(true);
expect(hasPendingGeneratedMediaTaskForSessionKey(sessionKey)).toBe(false);
});
});