87 lines
2.5 KiB
TypeScript
87 lines
2.5 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { A2ATaskManager } from "../../src/lib/a2a/taskManager.ts";
|
|
import { executeA2ATaskWithState } from "../../src/lib/a2a/taskExecution.ts";
|
|
|
|
const managers = [];
|
|
|
|
function createManager(ttlMinutes = 5) {
|
|
const manager = new A2ATaskManager(ttlMinutes);
|
|
managers.push(manager);
|
|
return manager;
|
|
}
|
|
|
|
test.afterEach(() => {
|
|
while (managers.length > 0) {
|
|
managers.pop()?.destroy();
|
|
}
|
|
});
|
|
|
|
test("completed task remains completed when queried after expiration", () => {
|
|
const tm = createManager();
|
|
const task = tm.createTask({
|
|
skill: "smart-routing",
|
|
messages: [{ role: "user", content: "hello" }],
|
|
});
|
|
|
|
tm.updateTask(task.id, "working");
|
|
tm.updateTask(task.id, "completed", [{ type: "text", content: "done" }]);
|
|
task.expiresAt = new Date(Date.now() - 1_000).toISOString();
|
|
|
|
assert.doesNotThrow(() => tm.getTask(task.id));
|
|
const loaded = tm.getTask(task.id);
|
|
assert.equal(loaded?.state, "completed");
|
|
});
|
|
|
|
test("stream execution marks task as failed when handler throws", async () => {
|
|
const tm = createManager();
|
|
const task = tm.createTask({
|
|
skill: "smart-routing",
|
|
messages: [{ role: "user", content: "trigger error" }],
|
|
});
|
|
|
|
tm.updateTask(task.id, "working");
|
|
|
|
await assert.rejects(
|
|
() =>
|
|
executeA2ATaskWithState(tm, task, async () => {
|
|
throw new Error("upstream failure");
|
|
}),
|
|
/upstream failure/
|
|
);
|
|
|
|
const loaded = tm.getTask(task.id);
|
|
assert.equal(loaded?.state, "failed");
|
|
assert.deepEqual(loaded?.artifacts.at(-1), { type: "error", content: "upstream failure" });
|
|
});
|
|
|
|
test("expired submitted task transitions to failed without throwing", () => {
|
|
const tm = createManager();
|
|
const task = tm.createTask({
|
|
skill: "smart-routing",
|
|
messages: [{ role: "user", content: "hello" }],
|
|
});
|
|
task.expiresAt = new Date(Date.now() - 1_000).toISOString();
|
|
|
|
assert.doesNotThrow(() => tm.getTask(task.id));
|
|
const loaded = tm.getTask(task.id);
|
|
assert.equal(loaded?.state, "failed");
|
|
});
|
|
|
|
test("cleanup keeps cancelled tasks as cancelled", () => {
|
|
const tm = createManager();
|
|
const task = tm.createTask({
|
|
skill: "smart-routing",
|
|
messages: [{ role: "user", content: "cancel me" }],
|
|
});
|
|
tm.updateTask(task.id, "cancelled");
|
|
task.expiresAt = new Date(Date.now() - 1_000).toISOString();
|
|
|
|
// private in TS only; callable at runtime for regression test
|
|
tm.cleanupExpired();
|
|
|
|
const loaded = tm.getTask(task.id);
|
|
assert.equal(loaded?.state, "cancelled");
|
|
});
|