// Agent 内核、本地服务和网页共用的类型。只有类型,没有运行时代码。 export type ToolCall = { id: string; type: 'function'; function: { name: string; arguments: string }; }; export type Message = | { role: 'system'; content: string } | { role: 'user'; content: string } | { role: 'assistant'; content: string; tool_calls?: ToolCall[] } | { role: 'tool'; tool_call_id: string; content: string }; export type AssistantMessage = Extract; export type ToolSpec = { type: 'function'; function: { name: string; description: string; parameters: Record }; }; export type Usage = { prompt_tokens: number; completion_tokens: number; total_tokens: number; cached_tokens?: number; reasoning_tokens?: number; }; // 收件箱里的一条:用户消息、后台命令完成通知、问题答复,三种来源走同一个入口。 export type InboxKind = 'user' | 'job_done' | 'question_reply'; export type InboxItem = { id: string; kind: InboxKind; content: string; // 进入历史时作为 user 消息的正文 ref?: string; // 关联的 job_id 或 question_id }; export type QuestionMode = 'blocking' | 'async'; export type LevelInfo = { id: number; name: string; title: string; adds: string; watch: string; tools: string[]; defaultTask: string; source: { file: string; anchor: string }[]; }; // 一次运行的完整记录就是这些事件。网页的实时视图、逐步查看和导出的回放都从它还原。 export type TraceEvent = { seq: number; t: number } & TraceBody; export type TraceBody = | { type: 'run.start'; runId: string; level: number; model: string; baseURL: string; tools: ToolSpec[]; startedAt: number; } | { type: 'history.append'; index: number; message: Message; origin?: { inboxId: string; kind: InboxKind; ref?: string }; } | { type: 'inbox.push'; item: InboxItem } | { type: 'inbox.deliver'; ids: string[] } | { type: 'model.start'; n: number; messageCount: number } | { type: 'model.delta'; n: number; content?: string; reasoning?: string } | { type: 'model.end'; n: number; message: AssistantMessage; reasoning: string; usage: Usage | null; finishReason: string | null; ttftMs: number | null; } | { type: 'model.error'; n: number; error: string } | { type: 'tool.start'; callId: string; name: string; args: unknown; n: number } | { type: 'tool.output'; callId: string; chunk: string } | { type: 'tool.end'; callId: string; result: string } | { type: 'job.start'; jobId: string; callId: string; command: string } | { type: 'job.output'; jobId: string; chunk: string } | { type: 'job.end'; jobId: string; exitCode: number | null; durationMs: number } | { type: 'question.ask'; questionId: string; callId: string; mode: QuestionMode; question: string; options: string[]; } | { type: 'question.answer'; questionId: string; answer: string } | { type: 'workspace.diff'; diff: string } | { type: 'guard.forged'; n: number; tag: string } | { type: 'run.stop'; reason: 'stopped' | 'error'; error?: string }; export type RunRecording = { runId: string; level: number; task: string; startedAt: number; events: TraceEvent[]; };