feat(swads): add daily image report workflow

This commit is contained in:
Jeffrey Wu
2026-09-07 11:34:00 +08:00
parent f39f6ac881
commit 5c61371d7e
38 changed files with 2537 additions and 52 deletions
+22 -2
View File
@@ -1,4 +1,4 @@
import { mkdtemp, mkdir, readFile, stat } from "node:fs/promises";
import { mkdtemp, mkdir, readFile, stat, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { describe, expect, it, vi } from "vitest";
@@ -45,7 +45,7 @@ async function setup(supportsImages = true) {
const events = new InMemoryEventStore(); const attachments = new FileAttachmentStore(sessionsRoot); const models = new InMemoryModelConnectionStore({}); const factory = new FakeFactory(supportsImages);
const registry = new InMemorySessionRegistry(sessionsRoot, events, attachments, models, catalog, factory, 500, 5_000);
const session = await registry.create(); await registry.configureModel(session.sessionId, { providerId: "fake", api: "openai-responses", apiKey: "test-secret", modelId: "fake-model", supportsImages });
return { root, sessionsRoot, events, attachments, models, factory, registry, session };
return { root, sessionsRoot, events, attachments, models, catalog, factory, registry, session };
}
describe("session lifecycle", () => {
@@ -80,6 +80,26 @@ describe("session lifecycle", () => {
it("derives skill requested/loaded callbacks with the same toolCallId", async () => {
const context = await setup(); await context.registry.send(context.session.sessionId, { text: "hello", attachmentIds: [] }); const skill = { name: "ads-analysis", description: "x", source: "project", filePath: ".agents/skills/ads-analysis/SKILL.md", canonicalPath: "/tmp/SKILL.md", diagnostics: [] }; context.factory.input?.skillRequested(skill, "read_1"); context.factory.input?.skillLoaded(skill, "read_1"); const skillEvents = context.events.listAfter(context.session.sessionId).events.filter((event) => event.type.startsWith("skill.")); expect(skillEvents.map((event) => event.type)).toEqual(["skill.requested", "skill.loaded"]); context.factory.port.complete();
});
it("preserves Slash user text and emits command activation without a fake toolCallId", async () => {
const context = await setup(); const dir = path.join(context.root, ".agents/skills/swads-daily-report"); await mkdir(dir); await writeFile(path.join(dir, "SKILL.md"), "---\nname: swads-daily-report\ndescription: report\ndisable-model-invocation: true\n---\nINVOKED BODY");
await context.catalog.reload();
const prompt = vi.spyOn(context.factory.port, "prompt"); const original = "/swads-daily-report account=demo date=2026-09-06";
await context.registry.send(context.session.sessionId, { text: original, attachmentIds: [] });
await vi.waitFor(() => expect(prompt).toHaveBeenCalled()); expect(prompt.mock.calls[0]![0]).toContain("<skill name="); expect(prompt.mock.calls[0]![0]).toContain("account=demo date=2026-09-06");
const events = context.events.listAfter(context.session.sessionId).events; expect(events.find((e) => e.type === "user.message")?.payload).toMatchObject({ text: original });
const activations = events.filter((e) => e.type === "skill.loaded" || e.type === "skill.requested"); expect(activations).toHaveLength(2); for (const e of activations) { expect(e.payload.source).toBe("command"); expect(e.payload.toolCallId).toBeUndefined(); }
context.factory.port.complete();
});
it("emits only report metadata on completion and preserves classified tool failures", async () => {
const context = await setup(false); await context.registry.send(context.session.sessionId, { text: "report", attachmentIds: [] });
const accountKey = "acct_0123456789abcdef01234567", reportDate = "2026-09-06", reportId = "12345678-1234-4234-8234-123456789abc"; const url = `/api/reports/${accountKey}/${reportDate}/${reportId}`;
const artifact = { accountKey, reportDate, reportId, previewUrl: `${url}/png`, downloads: { png: `${url}/png`, html: `${url}/html`, json: `${url}/json` } };
context.factory.port.emit({ type: "tool_execution_end", toolCallId: "render", toolName: "render_swads_daily_report", isError: false, result: { content: [{ type: "text", text: "/private/SHOULD_NOT_LEAK full report body" }], details: artifact } });
context.factory.port.emit({ type: "tool_execution_end", toolCallId: "whoami", toolName: "swads_cli", isError: true, result: { content: [{ type: "text", text: "SWADS_AUTH_FAILED" }] } });
const events = context.events.listAfter(context.session.sessionId).events; const generated = events.find((e) => e.type === "report.generated"); expect(generated?.payload).toMatchObject({ assistantMessageId: context.session.currentRun!.assistantMessageId, artifact }); expect(JSON.stringify(events)).not.toContain("SHOULD_NOT_LEAK"); expect(events.find((e) => e.type === "tool.failed")?.payload).toMatchObject({ error: "SWADS_AUTH_FAILED" }); context.factory.port.complete();
});
});
describe("multimodal session path", () => {