Initial Daily Campaign Agent release

This commit is contained in:
joliehill294-hue
2026-09-16 21:00:13 +08:00
commit 14fc94b3f0
86 changed files with 10766 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
{
"name": "@agent-studio/shared",
"version": "0.1.0",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": { ".": { "types": "./dist/index.d.ts", "default": "./dist/index.js" } },
"scripts": { "build": "tsc -p tsconfig.json", "typecheck": "tsc -p tsconfig.json --noEmit" },
"dependencies": { "zod": "latest" }
}
+126
View File
@@ -0,0 +1,126 @@
import { z } from "zod";
export const modelApiSchema = z.enum(["openai-responses", "openai-completions", "anthropic-messages"]);
export const modelConnectionInputSchema = z.object({
providerId: z.string().trim().min(1).max(80).regex(/^[a-zA-Z0-9._-]+$/),
api: modelApiSchema,
baseUrl: z.string().trim().url().max(2048).optional(),
apiKey: z.string().min(1).max(8192).optional(),
modelId: z.string().trim().min(1).max(160),
displayName: z.string().trim().min(1).max(160).optional(),
supportsImages: z.boolean(),
contextWindow: z.number().int().min(1024).max(10_000_000).optional(),
maxTokens: z.number().int().min(1).max(1_000_000).optional()
}).strict();
export type ModelConnectionInput = z.infer<typeof modelConnectionInputSchema>;
export const redactedModelConnectionSchema = z.object({
source: z.enum(["session", "environment", "persistent", "missing"]), configured: z.boolean(),
providerId: z.string().optional(), api: modelApiSchema.optional(), baseUrl: z.string().optional(),
modelId: z.string().optional(), displayName: z.string().optional(), supportsImages: z.boolean().optional(), keyHint: z.string().optional()
});
export type RedactedModelConnection = z.infer<typeof redactedModelConnectionSchema>;
export const accountKpiSchema = z.object({
metric: z.string().trim().min(1).max(120),
role: z.enum(["primary", "secondary", "guardrail"]),
formula: z.string().trim().min(1).max(500),
direction: z.enum(["lower", "higher", "range"]),
target: z.string().trim().min(1).max(120),
scope: z.string().trim().min(1).max(200),
maturityRule: z.string().trim().min(1).max(500),
attribution: z.string().trim().max(500).optional(),
minimumSample: z.string().trim().max(500).optional()
}).strict();
export const pacingCardSchema = z.object({
enabled: z.boolean(), targetValue: z.string().trim().max(120).optional(), currency: z.string().trim().max(32).optional(),
scope: z.string().trim().max(200).optional(), period: z.string().trim().max(120).optional(),
targetType: z.enum(["minimum", "desired", "cap", "range"]).optional(), allocationRule: z.string().trim().max(1000).optional()
}).strict().superRefine((value, ctx) => {
if (!value.enabled) return;
for (const key of ["targetValue", "currency", "scope", "period", "targetType"] as const) if (!value[key]) ctx.addIssue({ code: "custom", path: [key], message: "启用消耗判断时必填" });
});
export const accountProfileSchema = z.object({
accountName: z.string().trim().min(1).max(120),
analysisDatePolicy: z.enum(["yesterday", "latest_complete"]),
retentionLagDays: z.number().int().min(0).max(30),
kpis: z.array(accountKpiSchema).min(1).max(12),
pacing: pacingCardSchema,
minimumSampleRule: z.string().trim().max(1000).optional(),
budgetAdjustmentRule: z.string().trim().max(1000).optional(),
standardTestBudget: z.string().trim().max(500).optional(),
timezone: z.string().trim().max(120).optional(),
platformConstraints: z.string().trim().max(1000).optional()
}).strict();
export type AccountProfile = z.infer<typeof accountProfileSchema>;
export const messageInputSchema = z.object({
text: z.string().max(100_000).default(""),
attachmentIds: z.array(z.string().regex(/^att_[a-zA-Z0-9_-]+$/)).max(16).default([])
}).strict().superRefine((value, ctx) => {
if (!value.text.trim() && value.attachmentIds.length === 0) ctx.addIssue({ code: "custom", message: "Text or attachment is required" });
});
export type MessageInput = z.infer<typeof messageInputSchema>;
export const imageAttachmentSchema = z.object({
attachmentId: z.string(), sessionId: z.string(), name: z.string(),
kind: z.literal("image"),
mediaType: z.enum(["image/jpeg", "image/png", "image/webp"]),
byteSize: z.number().int().nonnegative(), width: z.number().int().positive(), height: z.number().int().positive(), status: z.literal("ready")
});
export type ImageAttachment = z.infer<typeof imageAttachmentSchema>;
export const spreadsheetAttachmentSchema = z.object({
attachmentId: z.string(), sessionId: z.string(), name: z.string(),
kind: z.literal("spreadsheet"),
mediaType: z.enum(["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "text/csv", "text/tab-separated-values"]),
byteSize: z.number().int().nonnegative(), status: z.literal("ready")
});
export type SpreadsheetAttachment = z.infer<typeof spreadsheetAttachmentSchema>;
export const attachmentSchema = z.discriminatedUnion("kind", [imageAttachmentSchema, spreadsheetAttachmentSchema]);
export type Attachment = z.infer<typeof attachmentSchema>;
export const reportArtifactSchema = z.object({
name: z.string().regex(/^\d{4}-\d{2}-\d{2}-campaign-triage\.docx$/), mediaType: z.literal("application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
byteSize: z.number().int().positive(), downloadUrl: z.string().startsWith("/api/sessions/")
});
export type ReportArtifact = z.infer<typeof reportArtifactSchema>;
export const approvalRequestSchema = z.object({
approvalId: z.string(), sessionId: z.string(), runId: z.string(), toolCallId: z.string(), toolName: z.string(),
arguments: z.unknown(), riskLevel: z.enum(["low", "medium", "high"]), createdAt: z.string().datetime(), expiresAt: z.string().datetime(),
status: z.enum(["pending", "approved", "denied", "expired", "cancelled"])
});
export type ApprovalRequest = z.infer<typeof approvalRequestSchema>;
const base = { eventId: z.string(), sessionId: z.string(), runId: z.string().optional(), timestamp: z.string().datetime(), sequence: z.number().int().positive() };
const event = <T extends string, S extends z.ZodType>(type: T, payload: S) => z.object({ ...base, type: z.literal(type), payload });
const toolBase = z.object({ toolCallId: z.string(), toolName: z.string(), arguments: z.unknown().optional(), result: z.unknown().optional(), error: z.string().optional() });
const approvalResolution = z.object({ approvalId: z.string(), toolCallId: z.string(), decision: z.enum(["approved", "denied", "expired", "cancelled"]) });
export const harnessEventSchema = z.discriminatedUnion("type", [
event("session.started", z.object({ cwd: z.string() })), event("session.ended", z.object({ reason: z.string() })),
event("user.message", z.object({ text: z.string(), attachmentIds: z.array(z.string()) })),
event("assistant.delta", z.object({ messageId: z.string(), delta: z.string() })), event("assistant.completed", z.object({ messageId: z.string(), text: z.string().optional() })),
event("skill.requested", z.object({ name: z.string(), toolCallId: z.string() })), event("skill.loaded", z.object({ name: z.string(), toolCallId: z.string() })),
event("tool.requested", toolBase), event("tool.completed", toolBase), event("tool.failed", toolBase),
event("approval.required", approvalRequestSchema), event("approval.resolved", approvalResolution),
event("attachment.uploaded", z.union([imageAttachmentSchema.omit({ sessionId: true }), spreadsheetAttachmentSchema.omit({ sessionId: true })])), event("attachment.rejected", z.object({ name: z.string().optional(), reason: z.string() })),
event("artifact.ready", reportArtifactSchema), event("artifact.failed", z.object({ code: z.string(), message: z.string() })),
event("model.configured", redactedModelConnectionSchema), event("model.validation_failed", z.object({ reason: z.string() })),
event("run.started", z.object({ runId: z.string() })), event("run.cancelled", z.object({ reason: z.enum(["user", "timeout", "session_deleted"]) })),
event("run.completed", z.object({ runId: z.string() })), event("run.failed", z.object({ code: z.string(), message: z.string() }))
]);
export type HarnessEvent = z.infer<typeof harnessEventSchema>;
export type HarnessEventType = HarnessEvent["type"];
export type EventInput<T extends HarnessEventType = HarnessEventType> = Omit<Extract<HarnessEvent, { type: T }>, "eventId" | "timestamp" | "sequence" | "sessionId">;
export const apiErrorSchema = z.object({ error: z.object({ code: z.string(), message: z.string(), requestId: z.string(), details: z.record(z.string(), z.unknown()).default({}) }) });
export type ApiError = z.infer<typeof apiErrorSchema>;
export type SkillDiagnostic = { level: "warning" | "error"; message: string };
export type SkillCatalogEntry = { name: string; description: string; source: string; filePath: string; diagnostics: SkillDiagnostic[] };
export type ApprovalDecision = "approved" | "denied" | "expired" | "cancelled";
export type ApprovalResolution = { request: ApprovalRequest; decision: ApprovalDecision };
export const DAILY_REPORT_PROMPT = "请使用内置的 daily-campaign-triage Skill 分析我上传的广告报表,生成中文日报,给出关键指标、异常和行动建议,并生成可下载的 Word 版本。若缺少 Skill 规定的必填信息,请先一次性向我澄清。";
+9
View File
@@ -0,0 +1,9 @@
import { describe, expect, it } from "vitest";
import { apiErrorSchema, harnessEventSchema, messageInputSchema, modelConnectionInputSchema } from "../src/index.js";
describe("shared schemas", () => {
it("parses a discriminated HarnessEvent", () => expect(harnessEventSchema.parse({ eventId: "e1", sessionId: "s1", timestamp: new Date().toISOString(), sequence: 1, type: "run.started", payload: { runId: "r1" } }).type).toBe("run.started"));
it("strictly validates model config", () => expect(() => modelConnectionInputSchema.parse({ providerId: "openai", api: "bad", modelId: "x", supportsImages: false })).toThrow());
it("requires text or attachment", () => expect(() => messageInputSchema.parse({ text: "", attachmentIds: [] })).toThrow());
it("parses unified errors", () => expect(apiErrorSchema.parse({ error: { code: "X", message: "safe", requestId: "req_1", details: {} } }).error.code).toBe("X"));
});
+5
View File
@@ -0,0 +1,5 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": { "outDir": "dist", "rootDir": "src", "declaration": true },
"include": ["src"]
}