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
+4 -3
View File
@@ -1,5 +1,5 @@
import { z } from "zod";
import { approvalRequestSchema, imageAttachmentSchema, llmApiSchema } from "./schemas.js";
import { approvalRequestSchema, imageAttachmentSchema, llmApiSchema, reportArtifactSchema } from "./schemas.js";
const baseShape = {
eventId: z.string(),
@@ -22,8 +22,9 @@ export const harnessEventSchema = z.discriminatedUnion("type", [
event("user.message", z.object({ messageId: z.string(), text: z.string(), attachmentIds: z.array(z.string()) }).strict()),
event("assistant.delta", z.object({ messageId: z.string(), delta: z.string() }).strict()),
event("assistant.completed", z.object({ messageId: z.string() }).strict()),
event("skill.requested", z.object({ name: z.string(), filePath: z.string(), toolCallId: z.string() }).strict()),
event("skill.loaded", z.object({ name: z.string(), filePath: z.string(), toolCallId: z.string() }).strict()),
event("skill.requested", z.object({ name: z.string(), filePath: z.string(), toolCallId: z.string().optional(), source: z.enum(["read", "command"]) }).strict()),
event("skill.loaded", z.object({ name: z.string(), filePath: z.string(), toolCallId: z.string().optional(), source: z.enum(["read", "command"]) }).strict()),
event("report.generated", z.object({ assistantMessageId: z.string(), artifact: reportArtifactSchema }).strict()),
event("tool.requested", toolBase),
event("tool.completed", z.object({ toolCallId: z.string(), toolName: z.string(), result: z.unknown().optional() }).strict()),
event("tool.failed", z.object({ toolCallId: z.string(), toolName: z.string(), error: z.string() }).strict()),
+14
View File
@@ -89,3 +89,17 @@ export const skillCatalogItemSchema = z.object({
diagnostics: z.array(skillDiagnosticSchema),
}).strict();
export type SkillCatalogItem = z.infer<typeof skillCatalogItemSchema>;
export const reportSegmentsSchema = z.object({
accountKey: z.string().regex(/^acct_[a-f0-9]{24}$/),
reportDate: z.iso.date(),
reportId: z.string().uuid(),
}).strict();
export const reportFormatSchema = z.enum(["png", "html", "json"]);
const reportUrl = z.string().regex(/^\/api\/reports\/acct_[a-f0-9]{24}\/\d{4}-\d{2}-\d{2}\/[a-f0-9-]{36}\/(png|html|json)$/);
export const reportArtifactSchema = reportSegmentsSchema.extend({
previewUrl: reportUrl.optional(),
downloads: z.object({ json: reportUrl, html: reportUrl, png: reportUrl.optional() }).strict(),
warning: z.object({ code: z.enum(["CHROME_UNAVAILABLE", "PNG_RENDER_FAILED", "PNG_TIMEOUT", "PNG_TRUNCATED"]), message: z.string().max(300) }).strict().optional(),
}).strict();
export type ReportArtifact = z.infer<typeof reportArtifactSchema>;
+10
View File
@@ -31,3 +31,13 @@ describe("shared boundary schemas", () => {
expect(apiErrorSchema.parse({ error: { code: "SESSION_NOT_FOUND", message: "Session not found", requestId: "req_1", details: {} } }).error.code).toBe("SESSION_NOT_FOUND");
});
});
it("accepts report metadata and rejects paths and malformed URL formats", () => {
const base = { eventId: "report", sessionId: "s", timestamp: new Date().toISOString(), sequence: 1, type: "report.generated" };
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, downloads: { json: `${url}/json`, html: `${url}/html` } };
expect(harnessEventSchema.safeParse({ ...base, payload: { assistantMessageId: "m", artifact } }).success).toBe(true);
expect(harnessEventSchema.safeParse({ ...base, payload: { assistantMessageId: "m", artifact: { ...artifact, absolutePath: "/private/report" } } }).success).toBe(false);
expect(harnessEventSchema.safeParse({ ...base, payload: { assistantMessageId: "m", artifact: { ...artifact, previewUrl: "https://evil.test/report.png" } } }).success).toBe(false);
});