zapmyco 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,47 +1,62 @@
1
- # ai-typescript-starter
1
+ # zapmyco
2
2
 
3
- [![CI](https://github.com/shenjingnan/ai-typescript-starter/actions/workflows/ci.yml/badge.svg)](https://github.com/shenjingnan/ai-typescript-starter/actions/workflows/ci.yml)
4
- [![npm version](https://img.shields.io/npm/v/ai-typescript-starter.svg)](https://www.npmjs.com/package/ai-typescript-starter)
3
+ [![CI](https://github.com/shenjingnan/zapmyco/actions/workflows/ci.yml/badge.svg)](https://github.com/shenjingnan/zapmyco/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/zapmyco.svg)](https://www.npmjs.com/package/zapmyco)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
- AI 原生的 TypeScript 启动模板,专为 AI 辅助开发时代打造。
7
+ AI 原生并行任务编排系统 -- AI 总管 (Personal AI Chief of Staff)。
8
8
 
9
9
  ## 特性
10
10
 
11
- - **现代技术栈**: TypeScript + Node.js 24+ + pnpm
12
- - **构建工具**: tsdown - 基于 rolldown 的 TypeScript 打包器
13
- - **测试框架**: Vitest - Vite 原生测试框架
14
- - **代码质量**: Biome (Lint + Format) + cspell (拼写检查)
15
- - **Git 工作流**: Husky + lint-staged + release-it
16
- - **AI 集成**: 内置 CLAUDE.md .claude/ 目录配置
17
- - **CI/CD**: GitHub Actions 自动化测试和发布
11
+ - **Agent 协议**: 统一的 `IAgent` / `IStreamingAgent` 接口,支持请求-响应 + 流式事件双通道模式
12
+ - **任务编排**: 目标分解、子任务依赖图、并行执行与结果聚合
13
+ - **Agent 运行时**: 基于 pi-agent-core 的适配层,支持 LLM 驱动的 Agent 创建与工具桥接
14
+ - **LLM 集成**: Provider 抽象、结构化输出、Token 用量追踪
15
+ - **交互式 REPL**: 基于 pi-tui 的终端界面,支持命令注册、历史记录、自定义编辑器
16
+ - **CLI 工具链**: `run` 直接执行目标、`agents` 查看注册 Agent、`config` 管理配置
17
+ - **配置系统**: cosmiconfig 驱动,支持多级配置覆盖
18
+ - **基础设施**: 事件总线、统一错误体系、结构化日志
18
19
 
19
20
  ## 快速开始
20
21
 
21
- ### 使用模板
22
-
23
- 点击仓库页面的 "Use this template" 按钮创建新项目。
24
-
25
22
  ### 安装
26
23
 
27
24
  ```bash
28
25
  # 克隆项目
29
- git clone https://github.com/your-username/your-project.git
30
- cd your-project
26
+ git clone https://github.com/shenjingnan/zapmyco.git
27
+ cd zapmyco
31
28
 
32
29
  # 安装依赖
33
30
  pnpm install
34
31
  ```
35
32
 
33
+ ### 使用
34
+
35
+ ```bash
36
+ # 构建项目
37
+ pnpm run build
38
+
39
+ # 进入交互式 REPL 模式
40
+ pnpm run start
41
+ # 或直接运行 CLI
42
+ zapmyco
43
+
44
+ # 直接执行单次目标(非交互模式)
45
+ zapmyco run "重构用户认证模块"
46
+
47
+ # 列出可用 Agent
48
+ zapmyco agents
49
+
50
+ # 显示版本号
51
+ zapmyco version
52
+ ```
53
+
36
54
  ### 开发
37
55
 
38
56
  ```bash
39
- # 开发模式
57
+ # 开发模式 (watch)
40
58
  pnpm run dev
41
59
 
42
- # 构建
43
- pnpm run build
44
-
45
60
  # 测试
46
61
  pnpm run test
47
62
 
@@ -58,16 +73,27 @@ pnpm run check
58
73
  ## 项目结构
59
74
 
60
75
  ```
61
- ai-typescript-starter/
62
- ├── .claude/ # Claude Code 配置
76
+ zapmyco/
77
+ ├── .agents/ # AI Agent 配置 (.claude 符号链接指向此目录)
63
78
  │ ├── commands/ # Slash 命令
64
79
  │ └── skills/ # 技能定义
65
80
  ├── .github/ # GitHub 配置
66
- ├── workflows/ # CI/CD 工作流
67
- │ └── ISSUE_TEMPLATE/ # Issue 模板
81
+ └── workflows/ # CI/CD 工作流
68
82
  ├── docs/ # 文档
69
83
  ├── examples/ # 示例代码
70
- ├── src/ # 源代码
84
+ ├── src/
85
+ │ ├── cli/ # CLI 入口 & REPL 交互界面
86
+ │ │ └── repl/ # REPL 核心:命令注册、会话、渲染、历史、编辑器
87
+ │ ├── config/ # 配置加载与默认值
88
+ │ ├── core/ # 核心领域模型
89
+ │ │ ├── agent-runtime/# Agent 运行时 (pi-agent-core 适配层)
90
+ │ │ ├── aggregator/ # 结果聚合
91
+ │ │ ├── intent/ # 目标与意图
92
+ │ │ ├── result/ # 任务结果
93
+ │ │ └── task/ # 子任务与依赖图
94
+ │ ├── infra/ # 基础设施:常量、错误、事件总线、日志
95
+ │ ├── llm/ # LLM Provider 抽象 & Token 追踪
96
+ │ ├── protocol/ # Agent 协议接口定义
71
97
  │ └── __tests__/ # 测试文件
72
98
  ├── AGENTS.md # AI Agent 配置
73
99
  └── dist/ # 构建产物
@@ -79,6 +105,7 @@ ai-typescript-starter/
79
105
  |------|------|
80
106
  | `pnpm run build` | 构建项目 |
81
107
  | `pnpm run dev` | 开发模式 (watch) |
108
+ | `pnpm run start` | 启动 CLI (REPL 模式) |
82
109
  | `pnpm run test` | 运行测试 |
83
110
  | `pnpm run test:watch` | 测试监听模式 |
84
111
  | `pnpm run test:coverage` | 测试覆盖率报告 |
@@ -87,7 +114,7 @@ ai-typescript-starter/
87
114
  | `pnpm run format` | 格式化代码 |
88
115
  | `pnpm run typecheck` | TypeScript 类型检查 |
89
116
  | `pnpm run check` | 完整检查 (typecheck + lint) |
90
- | `pnpm run check:fix` | 检查并修复 |
117
+ | `pnpm run check:fix` | 检查并自动修复 |
91
118
  | `pnpm run spellcheck` | 拼写检查 |
92
119
  | `pnpm run release` | 创建发布 |
93
120
  | `pnpm run release:beta` | 发布 beta 预发布版本 |
@@ -96,18 +123,85 @@ ai-typescript-starter/
96
123
  | `pnpm run release:minor` | 直接发布 minor 版本 |
97
124
  | `pnpm run release:major` | 直接发布 major 版本 |
98
125
 
126
+ ## 公共 API
127
+
128
+ ### 核心导出
129
+
130
+ ```typescript
131
+ import {
132
+ VERSION,
133
+ APP_NAME,
134
+ // 配置
135
+ loadConfig,
136
+ DEFAULT_CONFIG,
137
+ type ZapmycoConfig,
138
+ // Agent 运行时
139
+ createLlmBasedAgent,
140
+ createToolsFromCapabilities,
141
+ createToolFromCapability,
142
+ adaptAgentEvent,
143
+ createEventBridgeListener,
144
+ dispatchToEventBus,
145
+ LlmBasedAgent,
146
+ // LLM
147
+ CostTracker,
148
+ costTracker,
149
+ // 基础设施
150
+ eventBus,
151
+ Logger,
152
+ logger,
153
+ ZapmycoError,
154
+ } from 'zapmyco';
155
+ ```
156
+
157
+ ### Protocol 层类型
158
+
159
+ ```typescript
160
+ import type {
161
+ IAgent,
162
+ IStreamingAgent,
163
+ AgentExecuteRequest,
164
+ AgentExecuteOptions,
165
+ AgentStatus,
166
+ Capability,
167
+ CapabilityCategory,
168
+ Goal,
169
+ SubTask,
170
+ TaskGraph,
171
+ TaskResult,
172
+ FinalResult,
173
+ TokenUsage,
174
+ } from 'zapmyco';
175
+
176
+ // 或单独导入协议层
177
+ import type { IAgent, IStreamingAgent } from 'zapmyco/protocol';
178
+ ```
179
+
180
+ ### 核心领域类型
181
+
182
+ | 模块 | 关键类型 | 说明 |
183
+ |------|---------|------|
184
+ | `protocol/agent` | `IAgent`, `IStreamingAgent` | Agent 统一接口 |
185
+ | `core/intent` | `Goal`, `GoalType`, `GoalConstraints` | 目标与意图定义 |
186
+ | `core/task` | `SubTask`, `TaskGraph`, `TaskStatus` | 子任务与依赖图 |
187
+ | `core/result` | `TaskResult`, `FinalResult`, `TokenUsage` | 执行结果与用量 |
188
+ | `core/aggregator` | `ProgressEvent`, `ProgressPayload` | 进度事件 |
189
+ | `core/agent-runtime` | `AgentRuntimeConfig`, `ToolRegistration` | 运行时配置 |
190
+ | `llm/types` | `ChatMessage`, `LlmResponse`, `StructuredOutputSchema` | LLM 交互类型 |
191
+ | `config/types` | `ZapmycoConfig` | 应用配置 |
192
+
99
193
  ## AI 辅助开发
100
194
 
101
195
  本项目专为 AI 辅助开发设计,内置了完善的 AI 工程约束:
102
196
 
103
- ### CLAUDE.md
197
+ ### AGENTS.md / CLAUDE.md
104
198
 
105
199
  为 Claude Code 提供项目上下文和开发规范。
106
200
 
107
- ### .claude/ 目录
201
+ ### .agents/ 目录
108
202
 
109
- - `commands/` - 自定义 Slash 命令 (`/build`, `/test`, `/lint`, `/typecheck`, `/spellcheck`, `/release`, `/commit-push-pr`)
110
- - `skills/` - 项目技能定义 (`resolve-git-conflicts`, `fix-audit`, `project-context`, `update-readme`)
203
+ - `commands/` - 自定义 Slash 命令 (`/build`, `/test`, `/lint`, `/typecheck`, `/release`, `/commit-push-pr`)
204
+ - `skills/` - 项目技能定义 (`update-readme`, `resolve-git-conflicts`, `project-context` )
111
205
 
112
206
  ## 代码风格
113
207
 
@@ -146,4 +240,4 @@ pnpm run release
146
240
 
147
241
  ## 许可证
148
242
 
149
- [MIT](LICENSE) © 2026 shenjingnan
243
+ [MIT](LICENSE) © 2026 shenjingnan
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { E as __VERSION__, T as APP_NAME, h as createLlmBasedAgent, o as logger, t as loadConfig, w as eventBus } from "../loader-D1dTKHK4.mjs";
2
+ import { E as __VERSION__, T as APP_NAME, h as createLlmBasedAgent, o as logger, t as loadConfig, w as eventBus } from "../loader-BVZ993Oq.mjs";
3
3
  import chalk, { Chalk } from "chalk";
4
4
  import { Command } from "commander";
5
5
  import { getModel } from "@mariozechner/pi-ai";
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { C as dispatchToEventBus, E as __VERSION__, S as createEventBridgeListener, _ as createToolFromCapability, a as Logger, b as toAgentTools, c as DecomposeError, d as SchedulerError, f as ZapmycoError, g as createRequestFromSubTask, h as createLlmBasedAgent, i as costTracker, l as IntentError, m as LlmBasedAgent, n as DEFAULT_CONFIG, o as logger, p as ZapmycoErrorCode, r as CostTracker, s as AgentError, t as loadConfig, u as LlmError, v as createToolsFromCapabilities, w as eventBus, x as adaptAgentEvent, y as toAgentTool } from "./loader-D1dTKHK4.mjs";
1
+ import { C as dispatchToEventBus, E as __VERSION__, S as createEventBridgeListener, _ as createToolFromCapability, a as Logger, b as toAgentTools, c as DecomposeError, d as SchedulerError, f as ZapmycoError, g as createRequestFromSubTask, h as createLlmBasedAgent, i as costTracker, l as IntentError, m as LlmBasedAgent, n as DEFAULT_CONFIG, o as logger, p as ZapmycoErrorCode, r as CostTracker, s as AgentError, t as loadConfig, u as LlmError, v as createToolsFromCapabilities, w as eventBus, x as adaptAgentEvent, y as toAgentTool } from "./loader-BVZ993Oq.mjs";
2
2
 
3
3
  //#region src/index.ts
4
4
  /**
@@ -939,7 +939,7 @@ async function ensureHomeConfig() {
939
939
  if (existsSync(HOME_CONFIG_PATH)) return;
940
940
  const dir = join(homedir(), ".zapmyco");
941
941
  if (!existsSync(dir)) await mkdir(dir, { recursive: true });
942
- await writeFile(HOME_CONFIG_PATH, JSON.stringify({ llm: {
942
+ await writeFile(HOME_CONFIG_PATH, `${JSON.stringify({ llm: {
943
943
  defaultModel: "anthropic/claude-sonnet-4-20250514",
944
944
  models: {
945
945
  "anthropic/claude-sonnet-4-20250514": {
@@ -961,7 +961,7 @@ async function ensureHomeConfig() {
961
961
  maxTokens: 8192,
962
962
  temperature: .7
963
963
  }
964
- } }, null, 2) + "\n", "utf-8");
964
+ } }, null, 2)}\n`, "utf-8");
965
965
  logger.info("已创建默认配置文件", { filepath: HOME_CONFIG_PATH });
966
966
  }
967
967
  /**
@@ -1027,4 +1027,4 @@ async function loadConfig(configPath) {
1027
1027
 
1028
1028
  //#endregion
1029
1029
  export { dispatchToEventBus as C, __VERSION__ as E, createEventBridgeListener as S, APP_NAME as T, createToolFromCapability as _, Logger as a, toAgentTools as b, DecomposeError as c, SchedulerError as d, ZapmycoError as f, createRequestFromSubTask as g, createLlmBasedAgent as h, costTracker as i, IntentError as l, LlmBasedAgent as m, DEFAULT_CONFIG as n, logger as o, ZapmycoErrorCode as p, CostTracker as r, AgentError as s, loadConfig as t, LlmError as u, createToolsFromCapabilities as v, eventBus as w, adaptAgentEvent as x, toAgentTool as y };
1030
- //# sourceMappingURL=loader-D1dTKHK4.mjs.map
1030
+ //# sourceMappingURL=loader-BVZ993Oq.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader-BVZ993Oq.mjs","names":["EventEmitter","PiAgent"],"sources":["../src/infra/constants.ts","../src/infra/event-bus.ts","../src/core/agent-runtime/event-bridge.ts","../src/core/agent-runtime/tool-bridge.ts","../src/core/agent-runtime/agent-adapter.ts","../src/infra/errors.ts","../src/infra/logger.ts","../src/llm/cost-tracker.ts","../src/config/defaults.ts","../src/config/loader.ts"],"sourcesContent":["/**\n * zapmyco 全局常量定义\n */\n\n/** 应用名称 */\nexport const APP_NAME = 'zapmyco';\n\n/** 应用版本(由构建时注入,默认为 dev) */\nexport const __VERSION__ = '0.0.0-dev';\n\n/** 默认最大并行任务数 */\nexport const DEFAULT_MAX_PARALLELISM = 5;\n\n/** 默认单个 Agent 最大并发数 */\nexport const DEFAULT_MAX_PER_AGENT = 3;\n\n/** 默认任务超时时间(毫秒)- 30 分钟 */\nexport const DEFAULT_TASK_TIMEOUT = 30 * 60 * 1000;\n\n/** 默认最大重试次数 */\nexport const DEFAULT_MAX_RETRIES = 3;\n\n/** 重试基础延迟(毫秒) */\nexport const RETRY_BASE_DELAY = 1000;\n\n/** 最大重试延迟(毫秒)- 30s */\nexport const RETRY_MAX_DELAY = 30_000;\n\n/** 进度事件环形缓冲区大小 */\nexport const PROGRESS_RING_BUFFER_SIZE = 1000;\n\n/** 会话存储目录名 */\nexport const SESSION_DIR_NAME = '.zapmyco';\n\n/** 配置文件名列表(按优先级搜索) */\nexport const CONFIG_FILE_NAMES = [\n 'zapmyco.config.ts',\n 'zapmyco.config.js',\n 'zapmyco.config.mjs',\n 'zapmyco.config.cjs',\n 'zapmyco.config.json',\n '.zapmycorc',\n '.zapmycorc.json',\n '.zapmycorc.ts',\n '.zapmycorc.js',\n] as const;\n","/**\n * zapmyco 事件总线\n *\n * 基于 EventEmitter3 的类型安全事件总线,\n * 用于模块间解耦通信。\n *\n * 内部事件命名规范:`module:action`\n * 例如:`task:started`, `agent:progress`, `goal:completed`\n */\n\nimport { EventEmitter } from 'eventemitter3';\n\n/** 事件映射类型 */\ninterface EventMap {\n // Goal 生命周期\n 'goal:submitted': { goalId: string; rawInput: string };\n 'goal:intent-resolved': { goalId: string };\n 'goal:decomposed': { goalId: string; taskCount: number };\n 'goal:completed': { goalId: string; result: unknown };\n 'goal:failed': { goalId: string; error: Error };\n\n // Task 生命周期\n 'task:scheduled': { taskId: string; agentId: string };\n 'task:started': { taskId: string; agentId: string };\n 'task:progress': { taskId: string; percent: number; message?: string };\n 'task:output': { taskId: string; text: string };\n 'task:completed': { taskId: string; result: unknown };\n 'task:failed': { taskId: string; error: Error; retryable: boolean };\n 'task:retrying': { taskId: string; attempt: number; maxRetries: number };\n 'task:cancelled': { taskId: string };\n\n // Agent 生命周期\n 'agent:registered': { agentId: string };\n 'agent:unregistered': { agentId: string };\n 'agent:online': { agentId: string };\n 'agent:offline': { agentId: string };\n\n // 系统\n 'system:shutdown': { reason?: string };\n}\n\n/**\n * 全局事件总线实例\n *\n * 使用方式:\n * ```typescript\n * import { eventBus } from '@/infra/event-bus';\n *\n * eventBus.on('task:started', ({ taskId, agentId }) => {\n * console.log(`任务 ${taskId} 已在 ${agentId} 上启动`);\n * });\n *\n * eventBus.emit('task:started', { taskId: 'abc', agentId: 'code-1' });\n * ```\n */\nexport const eventBus = new EventEmitter<EventMap>();\n\n/** 事件映射类型导出(用于创建独立实例的场景) */\nexport type { EventMap };\nexport { EventEmitter };\n","/**\n * Event Bridge — AgentEvent ↔ eventBus 桥接\n *\n * 将 pi-agent-core 的 Agent 生命周期事件转换为\n * zapmyco 全局事件总线(eventBus)的事件格式。\n *\n * @module core/agent-runtime/event-bridge\n */\n\nimport type { AgentEvent } from '@mariozechner/pi-agent-core';\nimport { eventBus } from '@/infra/event-bus';\nimport type { AdaptedAgentEvent } from './types';\n\n// ============ 事件转换 ============\n\n/**\n * 将 pi-agent-core AgentEvent 转换为 zapmyco 适配事件\n *\n * @param agentEvent - pi-agent-core 原始事件\n * @param taskId - 关联的任务 ID\n * @param agentId - Agent 标识\n * @returns 适配后的事件,无法识别的返回 null\n */\nexport function adaptAgentEvent(\n agentEvent: AgentEvent,\n taskId: string,\n agentId: string\n): AdaptedAgentEvent | null {\n switch (agentEvent.type) {\n case 'agent_start':\n return { type: 'agent:start', taskId, agentId };\n\n case 'agent_end':\n return { type: 'agent:end', taskId, agentId };\n\n case 'turn_start':\n return { type: 'turn:start', taskId };\n\n case 'turn_end':\n return { type: 'turn:end', taskId };\n\n case 'message_start':\n return {\n type: 'message:start',\n taskId,\n textPreview: extractTextContent(agentEvent.message).slice(0, 100),\n };\n\n case 'message_update': {\n const delta = extractDelta(agentEvent.assistantMessageEvent);\n return {\n type: 'message:update',\n taskId,\n delta,\n };\n }\n\n case 'message_end':\n return {\n type: 'message:end',\n taskId,\n fullMessage: extractTextContent(agentEvent.message),\n };\n\n case 'tool_execution_start':\n return {\n type: 'tool:start',\n taskId,\n toolName: agentEvent.toolName ?? 'unknown',\n toolCallId: agentEvent.toolCallId,\n };\n\n case 'tool_execution_update':\n return {\n type: 'tool:update',\n taskId,\n toolName: agentEvent.toolName ?? 'unknown',\n };\n\n case 'tool_execution_end':\n return {\n type: 'tool:end',\n taskId,\n toolName: agentEvent.toolName ?? 'unknown',\n toolCallId: agentEvent.toolCallId,\n success: !agentEvent.isError,\n };\n\n default:\n // 忽略未知事件类型\n return null;\n }\n}\n\n// ============ 辅助函数 ============\n\n/**\n * 从 AgentMessage 中提取文本内容\n */\nfunction extractTextContent(message: unknown): string {\n if (!message || typeof message !== 'object') return '';\n const msg = message as Record<string, unknown>;\n if (typeof msg.content === 'string') return msg.content;\n if (Array.isArray(msg.content)) {\n return msg.content\n .filter(\n (block): block is { type: string; text?: string } =>\n typeof block === 'object' && block !== null && block.type === 'text'\n )\n .map((block) => block.text ?? '')\n .join('');\n }\n return '';\n}\n\n/**\n * 从 AssistantMessageEvent 中提取 delta 文本\n */\nfunction extractDelta(event: unknown): string {\n if (!event || typeof event !== 'object') return '';\n const evt = event as Record<string, unknown>;\n if (typeof evt.delta === 'string') return evt.delta;\n // 尝试从 type 字段判断\n if (evt.type === 'text_delta' && typeof evt.text_delta === 'string') {\n return evt.text_delta;\n }\n return '';\n}\n\n// ============ 事件分发 ============\n\n/**\n * 将适配后的事件分发到 zapmyco eventBus\n *\n * 映射规则:\n * - agent:start/end → agent:online/offline(带 taskId 上下文)\n * - turn:start/end → task:started/task:progress\n * - message:* → task:output\n * - tool:* → task:progress(含工具信息)\n *\n * @param event - 适配后的事件\n */\nexport function dispatchToEventBus(event: AdaptedAgentEvent): void {\n switch (event.type) {\n case 'agent:start':\n eventBus.emit('agent:online', { agentId: event.agentId });\n break;\n\n case 'agent:end':\n eventBus.emit('task:completed', {\n taskId: event.taskId,\n result: {},\n });\n break;\n\n case 'turn:start':\n eventBus.emit('task:started', {\n taskId: event.taskId,\n agentId: '',\n });\n break;\n\n case 'turn:end':\n eventBus.emit('task:progress', {\n taskId: event.taskId,\n percent: 100,\n message: 'Turn completed',\n });\n break;\n\n case 'message:start':\n case 'message:update':\n case 'message:end': {\n const text =\n event.type === 'message:update'\n ? event.delta\n : event.type === 'message:end'\n ? event.fullMessage\n : `[开始生成] ${event.textPreview}`;\n if (text) {\n eventBus.emit('task:output', { taskId: event.taskId, text });\n }\n break;\n }\n\n case 'tool:start':\n eventBus.emit('task:progress', {\n taskId: event.taskId,\n percent: 0,\n message: `执行工具: ${event.toolName}`,\n });\n break;\n\n case 'tool:update':\n eventBus.emit('task:progress', {\n taskId: event.taskId,\n percent: undefined,\n message: `${event.toolName} 更新中`,\n });\n break;\n\n case 'tool:end':\n eventBus.emit('task:progress', {\n taskId: event.taskId,\n percent: 100,\n message: `工具 ${event.toolName} ${event.success ? '完成' : '失败'}`,\n });\n break;\n\n case 'error':\n eventBus.emit('task:failed', {\n taskId: event.taskId,\n error: event.error,\n retryable: false,\n });\n break;\n }\n}\n\n// ============ 订阅桥接器 ============\n\n/**\n * 创建 Agent 事件订阅桥接器\n *\n * 返回一个订阅函数,可直接传给 pi-agent-core Agent.subscribe()。\n * 所有 Agent 事件会自动转换并分发到 zapmyco eventBus。\n *\n * @param taskId - 关联的任务 ID\n * @param agentId - Agent 标识\n * @returns 事件监听函数\n */\nexport function createEventBridgeListener(\n taskId: string,\n agentId: string\n): (event: AgentEvent, signal: AbortSignal) => void {\n return (agentEvent: AgentEvent): void => {\n const adapted = adaptAgentEvent(agentEvent, taskId, agentId);\n if (adapted) {\n dispatchToEventBus(adapted);\n }\n };\n}\n","/**\n * Tool Bridge — Capability → AgentTool 映射\n *\n * 将 zapmyco 的能力声明(Capability)转换为\n * pi-agent-core 可执行的工具定义(AgentTool)。\n *\n * @module core/agent-runtime/tool-bridge\n */\n\nimport type { AgentTool, AgentToolResult } from '@mariozechner/pi-agent-core';\nimport type { Static, TSchema } from 'typebox';\nimport type { Capability } from '@/protocol/capability';\n\n// ============ 类型定义 ============\n\n/**\n * 工具执行函数签名\n *\n * 符合 pi-agent-core AgentTool.execute 的契约。\n */\nexport type ToolExecuteFn<TParameters extends TSchema = TSchema> = (\n toolCallId: string,\n params: Static<TParameters>,\n signal?: AbortSignal,\n onUpdate?: (partialResult: AgentToolResult<unknown>) => void\n) => Promise<AgentToolResult<unknown>>;\n\n/**\n * 工具注册信息\n *\n * 用于描述一个可被 Agent 调用的具体工具。\n */\nexport interface ToolRegistration {\n /** 工具唯一标识(对应 pi-ai Tool.name) */\n id: string;\n /** 显示名称(用于 UI 展示,对应 AgentTool.label) */\n label: string;\n /** 工具描述(帮助 LLM 理解何时调用此工具) */\n description: string;\n /** 参数 Schema(TypeBox 格式,用于参数校验和 LLM 理解) */\n parameters?: TSchema;\n /** 执行函数 */\n execute: ToolExecuteFn;\n /** 执行模式:顺序或并行 */\n executionMode?: 'sequential' | 'parallel';\n}\n\n// ============ 核心映射函数 ============\n\n/**\n * 将单个 ToolRegistration 转换为 pi-agent-core 的 AgentTool\n *\n * @param registration - 工具注册信息\n * @returns pi-agent-core AgentTool 实例\n */\nexport function toAgentTool(registration: ToolRegistration): AgentTool {\n // AgentTool 要求 parameters 必须提供(TSchema 类型)\n // 当注册时未指定参数 schema,使用空对象 schema 作为默认\n const tool: AgentTool = {\n name: registration.id,\n description: registration.description,\n label: registration.label,\n parameters: registration.parameters ?? { type: 'object' as const, properties: {} },\n execute: registration.execute,\n ...(registration.executionMode != null ? { executionMode: registration.executionMode } : {}),\n };\n\n return tool;\n}\n\n/**\n * 将工具注册列表批量转换为 AgentTool 数组\n *\n * @param registrations - 工具注册列表\n * @returns AgentTool 数组\n */\nexport function toAgentTools(registrations: ToolRegistration[]): AgentTool[] {\n return registrations.map(toAgentTool);\n}\n\n/**\n * 基于 Capability 创建默认工具注册模板\n *\n * 此函数提供从 Capability 到 ToolRegistration 的基础映射。\n * 实际的 execute 函数需要由调用方根据具体能力注入。\n *\n * @param capability - 能力声明\n * @param execute - 执行函数(必须由调用方提供)\n * @returns ToolRegistration\n */\nexport function createToolFromCapability(\n capability: Capability,\n execute: ToolExecuteFn\n): ToolRegistration {\n return {\n id: capability.id,\n label: capability.name,\n description: capability.description,\n execute,\n };\n}\n\n/**\n * 基于多个 Capability 批量创建工具注册模板\n *\n * @param capabilities - 能力声明列表\n * @param executorFactory - 根据 Capability 生成执行函数的工厂\n * @returns ToolRegistration 数组\n */\nexport function createToolsFromCapabilities(\n capabilities: Capability[],\n executorFactory: (capability: Capability) => ToolExecuteFn\n): ToolRegistration[] {\n return capabilities.map((cap) => createToolFromCapability(cap, executorFactory(cap)));\n}\n","/**\n * Agent Adapter — IAgent → pi-agent-core.Agent 适配器\n *\n * 将 pi-agent-core 的有状态 Agent 封装为 zapmyco 的 IAgent 接口实现。\n * 这是 agent-runtime 层的核心集成点。\n *\n * @module core/agent-runtime/agent-adapter\n */\n\nimport { EventEmitter } from 'node:events';\nimport { Agent as PiAgent } from '@mariozechner/pi-agent-core';\nimport type { TaskResult } from '@/core/result/types';\nimport type {\n AgentExecuteRequest,\n AgentHealthStatus,\n AgentStatus,\n IStreamingAgent,\n} from '@/protocol/agent';\nimport type { Capability } from '@/protocol/capability';\nimport { createEventBridgeListener } from './event-bridge';\nimport { type ToolRegistration, toAgentTools } from './tool-bridge';\nimport type { AgentAdapterOptions, AgentRuntimeConfig } from './types';\n\n// ============ 默认配置 ============\n\nconst DEFAULT_RUNTIME_CONFIG: Required<AgentRuntimeConfig> = {\n enabled: true,\n toolExecution: 'sequential',\n maxTurns: 50,\n thinkingLevel: 'medium',\n};\n\n// ============ LlmBasedAgent 实现 ============\n\n/**\n * 基于 pi-agent-core 的 LLM 驱动 Agent 实现\n *\n * 将 zapmyco 的 IAgent 接口适配到 pi-agent-core 的 Agent 类,\n * 实现完整的 Agent 生命周期管理:\n * - execute(): 通过 Agent.prompt() 发起任务\n * - cancel(): 通过 Agent.abort() 中止执行\n * - healthCheck(): 检查 Agent 内部状态\n * - 流式事件: 通过 EventEmitter + EventBridge 双通道输出\n */\nexport class LlmBasedAgent extends EventEmitter implements IStreamingAgent {\n readonly EVENT_PROGRESS = 'progress' as const;\n readonly EVENT_OUTPUT = 'output' as const;\n readonly EVENT_ERROR = 'error' as const;\n\n // ============ IAgent 契约 ============\n\n readonly agentId: string;\n readonly displayName: string;\n readonly capabilities: readonly Capability[];\n\n // ============ 内部状态 ============\n\n private inner: PiAgent;\n private config: Required<AgentRuntimeConfig>;\n private toolRegistrations: ToolRegistration[] = [];\n private _currentLoad = 0;\n\n constructor(options: AgentAdapterOptions) {\n super();\n\n this.agentId = options.agentId;\n this.displayName = options.displayName;\n this.capabilities = options.capabilities;\n this.config = { ...DEFAULT_RUNTIME_CONFIG, ...options.runtimeConfig };\n\n // 创建 pi-agent-core Agent 实例\n this.inner = new PiAgent({\n toolExecution: this.config.toolExecution,\n });\n }\n\n // ============ 属性访问器 ============\n\n get status(): AgentStatus {\n if (!this.config.enabled) return 'offline';\n if (this._currentLoad > 0) return 'busy';\n return 'online';\n }\n\n get currentLoad(): number {\n return this._currentLoad;\n }\n\n /**\n * 访问内部 pi-agent-core Agent 实例(仅限高级用法)\n *\n * @internal 仅供测试和高级集成使用\n */\n get innerAgent(): PiAgent {\n return this.inner;\n }\n\n // ============ 工具注册 ============\n\n /**\n * 注册工具到 Agent\n *\n * @param tools - 工具注册列表\n */\n registerTools(tools: ToolRegistration[]): void {\n this.toolRegistrations.push(...tools);\n const agentTools = toAgentTools(tools);\n // 通过 state.tools 设置(AgentState 的 tools 是 getter/setter)\n this.inner.state.tools = [...this.inner.state.tools, ...agentTools];\n }\n\n /**\n * 清除所有已注册的工具\n */\n clearTools(): void {\n this.toolRegistrations = [];\n this.inner.state.tools = [];\n }\n\n // ============ IAgent 核心方法 ============\n\n /**\n * 执行任务\n *\n * 将 AgentExecuteRequest 转换为 pi-agent-core Agent 的 prompt 调用:\n * 1. 构建执行上下文(任务描述 + 上游结果)\n * 2. 设置系统提示词\n * 3. 绑定事件桥接到 eventBus + EventEmitter\n * 4. 调用 Agent.prompt() 并等待完成\n * 5. 提取结果并组装为 TaskResult\n */\n async execute(request: AgentExecuteRequest): Promise<TaskResult> {\n const startTime = Date.now();\n this._currentLoad++;\n const cleanupFns: (() => void)[] = [];\n\n try {\n // 构建系统提示词并设置到 Agent 状态\n this.inner.state.systemPrompt = this.buildSystemPrompt(request);\n\n // 绑定事件桥接(带 taskId),收集清理函数用于后续移除\n cleanupFns.push(\n this.inner.subscribe(createEventBridgeListener(request.taskId, this.agentId))\n );\n\n // 同时监听并转发到本地的 EventEmitter(支持 IStreamingAgent)\n cleanupFns.push(\n this.inner.subscribe((event) => {\n if (event.type === 'message_update') {\n const delta = extractDeltaFromEvent(event);\n if (delta) {\n this.emit(this.EVENT_OUTPUT, {\n taskId: request.taskId,\n text: delta,\n });\n }\n }\n if (event.type === 'tool_execution_start') {\n this.emit(this.EVENT_PROGRESS, {\n taskId: request.taskId,\n percent: 0,\n message: `执行工具: ${event.toolName}`,\n });\n }\n if (event.type === 'tool_execution_end') {\n this.emit(this.EVENT_PROGRESS, {\n taskId: request.taskId,\n percent: 100,\n message: `工具 ${event.toolName} 完成`,\n });\n }\n if (event.type === 'agent_end') {\n this.emit(this.EVENT_PROGRESS, {\n taskId: request.taskId,\n percent: 100,\n message: '任务完成',\n });\n }\n })\n );\n\n // 执行 prompt\n await this.inner.prompt(request.taskDescription);\n\n // 等待 Agent 进入空闲状态\n await this.inner.waitForIdle();\n\n // 提取结果\n const result = this.extractTaskResult(request.taskId, startTime);\n\n return result;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n\n // 发送错误事件\n this.emit(this.EVENT_ERROR, { taskId: request.taskId, error: err });\n\n return {\n taskId: request.taskId,\n status: 'failure',\n output: null,\n artifacts: [],\n duration: Date.now() - startTime,\n tokenUsage: {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n error: {\n code: 'AGENT_EXECUTION_FAILED',\n message: err.message,\n retryable: false,\n details: { stack: err.stack },\n },\n };\n } finally {\n // 清理本次执行的事件订阅(防止复用 Agent 实例时监听器累积)\n for (const fn of cleanupFns) {\n fn();\n }\n this._currentLoad--;\n }\n }\n\n /**\n * 取消正在执行的任务\n */\n async cancel(taskId: string): Promise<void> {\n this.inner.abort();\n this.emit(this.EVENT_PROGRESS, {\n taskId,\n percent: -1,\n message: '任务已取消',\n });\n }\n\n /**\n * 健康检查\n */\n async healthCheck(): Promise<AgentHealthStatus> {\n const startTime = Date.now();\n try {\n // 检查内部 Agent 状态是否可访问\n const state = this.inner.state;\n const latencyMs = Date.now() - startTime;\n\n return {\n 是否健康: this.config.enabled && !state.isStreaming,\n latencyMs,\n version: `pi-agent-core@${this.getPkgVersion()}`,\n details: {\n isStreaming: state.isStreaming,\n messagesCount: state.messages.length,\n toolsCount: state.tools.length,\n currentLoad: this._currentLoad,\n },\n };\n } catch {\n return {\n 是否健康: false,\n latencyMs: Date.now() - startTime,\n version: 'unknown',\n details: { error: 'Health check failed' },\n };\n }\n }\n\n // ============ 辅助方法 ============\n\n /**\n * 构建系统提示词\n */\n private buildSystemPrompt(request: AgentExecuteRequest): string {\n const parts: string[] = [\n `你是 ${this.displayName},一个专业的 AI 助手。`,\n `你的能力包括:${this.capabilities.map((c) => c.name).join('、')}。`,\n ];\n\n if (request.upstreamResults?.length) {\n parts.push(\n '\\n## 上游任务结果\\n',\n ...request.upstreamResults.map((r, i) => `[上游任务 ${i + 1}] ${JSON.stringify(r.output)}`)\n );\n }\n\n if (request.workdir) {\n parts.push(`\\n## 工作目录\\n${request.workdir}`);\n }\n\n return parts.join('\\n');\n }\n\n /**\n * 从 Agent 状态中提取 TaskResult\n */\n private extractTaskResult(taskId: string, startTime: number): TaskResult {\n const state = this.inner.state;\n const duration = Date.now() - startTime;\n\n // 从消息历史中提取最后的 assistant 回复作为 output\n const lastAssistantMessage = [...state.messages].reverse().find((m) => m.role === 'assistant');\n\n const output = lastAssistantMessage ? extractTextFromMessage(lastAssistantMessage) : null;\n\n return {\n taskId,\n status: 'success',\n output,\n artifacts: [],\n duration,\n tokenUsage: {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n };\n }\n\n /**\n * 获取 pi-agent-core 包版本号\n */\n private getPkgVersion(): string {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const pkg = require('@mariozechner/pi-agent-core/package.json');\n return pkg.version ?? 'unknown';\n } catch {\n return 'unknown';\n }\n }\n}\n\n// ============ 工厂函数 ============\n\n/**\n * 创建 LlmBasedAgent 实例的工厂函数\n *\n * @param options - 适配器选项\n * @returns 配置好的 LlmBasedAgent 实例\n */\nexport function createLlmBasedAgent(options: AgentAdapterOptions): LlmBasedAgent {\n return new LlmBasedAgent(options);\n}\n\n/**\n * 从 SubTask 创建 Agent 执行请求\n *\n * 将 zapmyco 的 SubTask 转换为 AgentExecuteRequest 格式。\n *\n * @param subTask - 子任务定义\n * @param workdir - 项目工作目录\n * @param options - 执行选项\n * @returns AgentExecuteRequest\n */\nexport function createRequestFromSubTask(\n subTask: import('@/core/task/types').SubTask,\n workdir: string,\n options?: Partial<AgentExecuteRequest['options']>\n): AgentExecuteRequest {\n return {\n taskId: subTask.id,\n taskDescription: subTask.description,\n workdir,\n options: {\n timeout: 300_000, // 默认 5 分钟超时\n verbose: false,\n ...options,\n },\n };\n}\n\n// ============ 辅助函数 ============\n\n/**\n * 从 AgentMessage 中提取文本内容\n */\nfunction extractTextFromMessage(message: unknown): string | null {\n if (!message || typeof message !== 'object') return null;\n const msg = message as Record<string, unknown>;\n if (typeof msg.content === 'string') return msg.content;\n if (Array.isArray(msg.content)) {\n return msg.content\n .filter(\n (block): block is { type: string; text?: string } =>\n typeof block === 'object' && block !== null && block.type === 'text'\n )\n .map((block) => block.text ?? '')\n .join('');\n }\n return null;\n}\n\n/**\n * 从 message_update 事件中提取 delta 文本\n */\nfunction extractDeltaFromEvent(event: {\n type: 'message_update';\n message: unknown;\n assistantMessageEvent: unknown;\n}): string | null {\n const evt = event.assistantMessageEvent as Record<string, unknown> | null;\n if (!evt || typeof evt !== 'object') return null;\n if (typeof evt.delta === 'string') return evt.delta;\n if (\n evt.type === 'text_delta' &&\n typeof (evt as Record<string, unknown>).text_delta === 'string'\n ) {\n return (evt as Record<string, unknown>).text_delta as string;\n }\n return null;\n}\n","/**\n * zapmyco 统一错误类型\n *\n * 所有模块应使用或继承这些错误类型,确保错误信息一致且可追踪。\n */\n\n/** 错误码枚举 */\nexport enum ZapmycoErrorCode {\n // 意图理解相关\n INTENT_PARSE_FAILED = 'INTENT_PARSE_FAILED',\n INTENT_LOW_CONFIDENCE = 'INTENT_LOW_CONFIDENCE',\n\n // 任务拆分相关\n DECOMPOSE_FAILED = 'DECOMPOSE_FAILED',\n DECOMPOSE_INVALID_GRAPH = 'DECOMPOSE_INVALID_GRAPH',\n\n // 调度相关\n SCHEDULER_NO_AVAILABLE_AGENT = 'SCHEDULER_NO_AVAILABLE_AGENT',\n SCHEDULER_CAPABILITY_MISMATCH = 'SCHEDULER_CAPABILITY_MISMATCH',\n SCHEDULER_TASK_TIMEOUT = 'SCHEDULER_TASK_TIMEOUT',\n\n // Agent 相关\n AGENT_NOT_FOUND = 'AGENT_NOT_FOUND',\n AGENT_OFFLINE = 'AGENT_OFFLINE',\n AGENT_EXECUTION_FAILED = 'AGENT_EXECUTION_FAILED',\n AGENT_HEALTH_CHECK_FAILED = 'AGENT_HEALTH_CHECK_FAILED',\n\n // 配置相关\n CONFIG_LOAD_FAILED = 'CONFIG_LOAD_FAILED',\n CONFIG_INVALID = 'CONFIG_INVALID',\n\n // LLM 相关\n LLM_API_ERROR = 'LLM_API_ERROR',\n LLM_RATE_LIMITED = 'LLM_RATE_LIMITED',\n LLM_QUOTA_EXCEEDED = 'LLM_QUOTA_EXCEEDED',\n\n // 通用\n UNKNOWN = 'UNKNOWN',\n INTERNAL_ERROR = 'INTERNAL_ERROR',\n}\n\n/**\n * zapmyco 基础错误类\n *\n * 所有业务错误都应继承此类,提供结构化的错误信息。\n */\nexport class ZapmycoError extends Error {\n /** 错误码 */\n readonly code: ZapmycoErrorCode;\n /** 额外的上下文信息 */\n readonly context?: Record<string, unknown>;\n\n constructor(code: ZapmycoErrorCode, message: string, context?: Record<string, unknown>) {\n super(message);\n this.name = 'ZapmycoError';\n this.code = code;\n Object.assign(this, context !== undefined ? { context } : {});\n\n // 保持正确的原型链(ES5+ 兼容)\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n /** 转换为可序列化的对象 */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n context: this.context,\n stack: this.stack,\n };\n }\n}\n\n/** 意图理解错误 */\nexport class IntentError extends ZapmycoError {\n constructor(\n code: ZapmycoErrorCode.INTENT_PARSE_FAILED | ZapmycoErrorCode.INTENT_LOW_CONFIDENCE,\n message: string,\n context?: Record<string, unknown>\n ) {\n super(code, message, context);\n this.name = 'IntentError';\n }\n}\n\n/** 任务拆分错误 */\nexport class DecomposeError extends ZapmycoError {\n constructor(\n code: ZapmycoErrorCode.DECOMPOSE_FAILED | ZapmycoErrorCode.DECOMPOSE_INVALID_GRAPH,\n message: string,\n context?: Record<string, unknown>\n ) {\n super(code, message, context);\n this.name = 'DecomposeError';\n }\n}\n\n/** 调度错误 */\nexport class SchedulerError extends ZapmycoError {\n constructor(\n code:\n | ZapmycoErrorCode.SCHEDULER_NO_AVAILABLE_AGENT\n | ZapmycoErrorCode.SCHEDULER_CAPABILITY_MISMATCH\n | ZapmycoErrorCode.SCHEDULER_TASK_TIMEOUT,\n message: string,\n context?: Record<string, unknown>\n ) {\n super(code, message, context);\n this.name = 'SchedulerError';\n }\n}\n\n/** Agent 执行错误 */\nexport class AgentError extends ZapmycoError {\n constructor(\n code:\n | ZapmycoErrorCode.AGENT_NOT_FOUND\n | ZapmycoErrorCode.AGENT_OFFLINE\n | ZapmycoErrorCode.AGENT_EXECUTION_FAILED\n | ZapmycoErrorCode.AGENT_HEALTH_CHECK_FAILED,\n message: string,\n context?: Record<string, unknown>\n ) {\n super(code, message, context);\n this.name = 'AgentError';\n }\n}\n\n/** LLM 调用错误 */\nexport class LlmError extends ZapmycoError {\n constructor(\n code:\n | ZapmycoErrorCode.LLM_API_ERROR\n | ZapmycoErrorCode.LLM_RATE_LIMITED\n | ZapmycoErrorCode.LLM_QUOTA_EXCEEDED,\n message: string,\n context?: Record<string, unknown>\n ) {\n super(code, message, context);\n this.name = 'LlmError';\n }\n}\n","/**\n * zapmyco 日志系统\n *\n * 提供结构化的日志输出,支持不同级别和格式化。\n */\n\nimport { ZapmycoError } from '@/infra/errors';\n\n/** 日志级别 */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/** 日志条目 */\nexport interface LogEntry {\n level: LogLevel;\n message: string;\n timestamp: string;\n context?: Record<string, unknown>;\n error?: Error;\n}\n\n/** 级别对应的标签(用于终端输出) */\nconst LEVEL_LABELS: Record<LogLevel, string> = {\n debug: 'DBG',\n info: 'INF',\n warn: 'WRN',\n error: 'ERR',\n};\n\n/** 级别权重(用于过滤) */\nconst LEVEL_WEIGHTS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\n/**\n * Logger 实例\n */\nclass Logger {\n private minLevel: LogLevel;\n private entries: LogEntry[] = [];\n\n constructor(minLevel: LogLevel = 'info') {\n this.minLevel = minLevel;\n }\n\n /** 设置日志级别 */\n setLevel(level: LogLevel): void {\n this.minLevel = level;\n }\n\n /** 创建带前缀的子 logger */\n child(prefix: string): Logger {\n const child = new Logger(this.minLevel);\n const originalLog = child.log.bind(child);\n child.log = (\n level: LogLevel,\n message: string,\n context?: Record<string, unknown>,\n error?: Error\n ) => {\n originalLog(level, `[${prefix}] ${message}`, context, error);\n };\n return child;\n }\n\n /** 核心日志方法 */\n log(level: LogLevel, message: string, context?: Record<string, unknown>, error?: Error): void {\n if (LEVEL_WEIGHTS[level] < LEVEL_WEIGHTS[this.minLevel]) {\n return;\n }\n\n const entry: LogEntry = {\n level,\n message,\n timestamp: new Date().toISOString(),\n ...(context !== undefined ? { context } : {}),\n ...(error !== undefined ? { error } : {}),\n };\n\n this.entries.push(entry);\n\n // 终端输出格式\n const timestamp = entry.timestamp.replace('T', ' ').slice(0, 19);\n const label = LEVEL_LABELS[level];\n let output = `${timestamp} [${label}] ${message}`;\n\n if (entry.context && Object.keys(entry.context).length > 0) {\n output += ` ${JSON.stringify(entry.context)}`;\n }\n\n if (error instanceof ZapmycoError) {\n output += ` (${error.code}) ${error.message}`;\n } else if (error) {\n output += ` ${error.message}`;\n }\n\n const stream = level === 'error' ? process.stderr : process.stdout;\n stream.write(`${output}\\n`);\n }\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.log('debug', message, context);\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.log('info', message, context);\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.log('warn', message, context);\n }\n\n error(message: string, context?: Record<string, unknown>, error?: Error): void {\n this.log('error', message, context, error);\n }\n\n /** 获取所有日志条目 */\n getEntries(): LogEntry[] {\n return [...this.entries];\n }\n\n /** 清空日志条目 */\n clear(): void {\n this.entries = [];\n }\n}\n\n/** 全局默认 logger 实例 */\nexport const logger = new Logger();\n\nexport { Logger };\n","/**\n * Token / Cost 追踪器\n *\n * 实时跟踪所有 LLM 调用的 Token 消耗和预估费用,\n * 用于成本控制和用户展示。\n */\n\nimport type { TokenUsage } from '@/core/result/types';\nimport { logger } from '@/infra/logger';\n\n/** 模型定价信息(每百万 token 的美元价格) */\ninterface ModelPricing {\n inputPricePer1M: number;\n outputPricePer1M: number;\n}\n\n/** 已知模型的定价表 */\nconst MODEL_PRICING: Record<string, ModelPricing> = {\n // Anthropic Claude\n 'claude-haiku-4-5-20251001': { inputPricePer1M: 0.8, outputPricePer1M: 4 },\n 'claude-sonnet-4-20250514': { inputPricePer1M: 3, outputPricePer1M: 15 },\n 'claude-opus-4-20250514': { inputPricePer1M: 15, outputPricePer1M: 75 },\n\n // OpenAI\n 'gpt-4o': { inputPricePer1M: 2.5, outputPricePer1M: 10 },\n 'gpt-4o-mini': { inputPricePer1M: 0.15, outputPricePer1M: 0.6 },\n};\n\n/**\n * CostTracker 实例\n *\n * 使用方式:\n * ```typescript\n * import { costTracker } from '@/llm/cost-tracker';\n *\n * costTracker.record({ inputTokens: 1000, outputTokens: 500 }, 'claude-sonnet-4');\n * const summary = costTracker.getSummary();\n * console.log(`总花费: $${summary.totalCostUsd}`);\n * ```\n */\nexport class CostTracker {\n private records: Array<{ usage: TokenUsage; model: string; timestamp: number }> = [];\n\n /** 记录一次 LLM 调用的 Token 消耗 */\n record(usage: Omit<TokenUsage, 'estimatedCostUsd'>, model: string): void {\n const pricing = MODEL_PRICING[model] ?? { inputPricePer1M: 0, outputPricePer1M: 0 };\n const estimatedCostUsd =\n (usage.inputTokens / 1_000_000) * pricing.inputPricePer1M +\n (usage.outputTokens / 1_000_000) * pricing.outputPricePer1M;\n\n const fullUsage: TokenUsage = {\n ...usage,\n totalTokens: usage.inputTokens + usage.outputTokens,\n estimatedCostUsd,\n };\n\n this.records.push({\n usage: fullUsage,\n model,\n timestamp: Date.now(),\n });\n\n logger.debug('Token 消耗记录', {\n model,\n tokens: fullUsage.totalTokens,\n cost: `$${estimatedCostUsd.toFixed(4)}`,\n });\n }\n\n /** 获取累计摘要 */\n getSummary(): {\n totalInputTokens: number;\n totalOutputTokens: number;\n totalTokens: number;\n totalCostUsd: number;\n callCount: number;\n } {\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCostUsd = 0;\n\n for (const record of this.records) {\n totalInputTokens += record.usage.inputTokens;\n totalOutputTokens += record.usage.outputTokens;\n totalCostUsd += record.usage.estimatedCostUsd;\n }\n\n return {\n totalInputTokens,\n totalOutputTokens,\n totalTokens: totalInputTokens + totalOutputTokens,\n totalCostUsd,\n callCount: this.records.length,\n };\n }\n\n /** 重置所有记录 */\n reset(): void {\n this.records = [];\n }\n\n /** 获取记录数 */\n get count(): number {\n return this.records.length;\n }\n}\n\n/** 全局默认 CostTracker 实例 */\nexport const costTracker = new CostTracker();\n","/**\n * zapmyco 默认配置\n *\n * 当用户未提供配置时,使用这些默认值。\n */\n\nimport type { ZapmycoConfig } from '@/config/types';\n\n/** 默认配置 */\nexport const DEFAULT_CONFIG: ZapmycoConfig = {\n llm: {\n defaultModel: 'anthropic/claude-sonnet-4-20250514',\n models: {\n 'anthropic/claude-sonnet-4-20250514': {\n provider: 'anthropic',\n modelId: 'claude-sonnet-4-20250514',\n description: 'Anthropic Claude Sonnet 4 - 均衡模型,日常使用推荐',\n },\n },\n providers: {\n anthropic: {\n // biome-ignore lint/suspicious/noTemplateCurlyInString: 环境变量引用语法\n apiKey: '${ANTHROPIC_API_KEY}',\n },\n },\n defaults: {\n maxTokens: 8192,\n temperature: 0.7,\n },\n },\n scheduler: {\n maxConcurrency: 5,\n maxPerAgent: 3,\n taskTimeoutMs: 30 * 60 * 1000, // 30 分钟\n maxRetries: 3,\n retryBaseDelayMs: 1000,\n },\n agents: [\n { id: 'code-agent', enabled: true },\n { id: 'security-scanner', enabled: true },\n { id: 'research-agent', enabled: true },\n { id: 'planning-agent', enabled: true },\n ],\n cli: {\n color: true,\n debug: false,\n outputFormat: 'text',\n },\n};\n","/**\n * zapmyco 配置加载器\n *\n * 使用 cosmiconfig 搜索并加载配置文件。\n * 支持多路径搜索,包括用户家目录 ~/.zapmyco/zapmyco.json。\n */\n\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { type CosmiconfigResult, cosmiconfig } from 'cosmiconfig';\nimport { DEFAULT_CONFIG } from '@/config/defaults';\nimport type { ZapmycoConfig } from '@/config/types';\nimport { logger } from '@/infra/logger';\n\n// cosmiconfig 的 explorer 名称\nconst EXPLORER_NAME = 'zapmyco';\n\n/** 用户家目录配置路径 */\nconst HOME_CONFIG_PATH = join(homedir(), '.zapmyco', 'zapmyco.json');\n\n/**\n * 解析配置值中的环境变量引用\n *\n * 支持语法:${ENV_VAR_NAME}\n * 未定义的环境变量会被替换为空字符串\n */\nfunction resolveEnvVars(value: unknown): unknown {\n if (typeof value === 'string') {\n return value.replace(/\\$\\{(\\w+)\\}/g, (_match, varName) => {\n return process.env[varName] ?? '';\n });\n }\n\n if (Array.isArray(value)) {\n return value.map(resolveEnvVars);\n }\n\n if (value !== null && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n result[key] = resolveEnvVars(val);\n }\n return result;\n }\n\n return value;\n}\n\n/**\n * 深度合并两个对象\n */\nfunction deepMerge<T>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key of Object.keys(source) as Array<keyof T & string>) {\n const sourceValue = source[key as keyof T];\n const targetValue = (target as Record<string, unknown>)[key];\n\n if (\n sourceValue !== undefined &&\n typeof sourceValue === 'object' &&\n sourceValue !== null &&\n !Array.isArray(sourceValue) &&\n typeof targetValue === 'object' &&\n targetValue !== null &&\n !Array.isArray(targetValue)\n ) {\n (result as Record<string, unknown>)[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>\n );\n } else if (sourceValue !== undefined) {\n (result as Record<string, unknown>)[key] = sourceValue;\n }\n }\n\n return result;\n}\n\n/**\n * 确保家目录配置文件存在,不存在则创建模板\n */\nasync function ensureHomeConfig(): Promise<void> {\n if (existsSync(HOME_CONFIG_PATH)) {\n return;\n }\n\n const dir = join(homedir(), '.zapmyco');\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n\n const template: Record<string, unknown> = {\n llm: {\n defaultModel: 'anthropic/claude-sonnet-4-20250514',\n models: {\n 'anthropic/claude-sonnet-4-20250514': {\n provider: 'anthropic',\n modelId: 'claude-sonnet-4-20250514',\n description: 'Anthropic Claude Sonnet 4 - 均衡模型,日常使用推荐',\n },\n 'openai/gpt-4o': {\n provider: 'openai',\n modelId: 'gpt-4o',\n description: 'OpenAI GPT-4o - 多功能模型',\n },\n },\n providers: {\n anthropic: {\n // biome-ignore lint/suspicious/noTemplateCurlyInString: 环境变量引用语法\n apiKey: '${ANTHROPIC_API_KEY}',\n },\n openai: {\n // biome-ignore lint/suspicious/noTemplateCurlyInString: 环境变量引用语法\n apiKey: '${OPENAI_API_KEY}',\n },\n },\n defaults: {\n maxTokens: 8192,\n temperature: 0.7,\n },\n },\n };\n\n await writeFile(HOME_CONFIG_PATH, `${JSON.stringify(template, null, 2)}\\n`, 'utf-8');\n logger.info('已创建默认配置文件', { filepath: HOME_CONFIG_PATH });\n}\n\n/**\n * 尝试从家目录加载配置\n */\nasync function tryLoadHomeConfig(): Promise<CosmiconfigResult | null> {\n try {\n if (!existsSync(HOME_CONFIG_PATH)) {\n await ensureHomeConfig();\n }\n\n const content = await readFile(HOME_CONFIG_PATH, 'utf-8');\n const config = JSON.parse(content);\n\n return {\n config: resolveEnvVars(config),\n filepath: HOME_CONFIG_PATH,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * 加载 zapmyco 配置\n *\n * 搜索优先级:\n * 1. 显式指定的 configPath\n * 2. 项目级配置文件(cosmiconfig 默认搜索)\n * 3. 用户家目录 ~/.zapmyco/zapmyco.json\n * 4. 默认值\n *\n * @param configPath - 可选的显式配置文件路径\n * @returns 合并后的完整配置(用户配置 + 默认值深度合并)\n */\nexport async function loadConfig(configPath?: string): Promise<ZapmycoConfig> {\n // 如果显式指定了路径,直接加载\n if (configPath) {\n const explorer = cosmiconfig(EXPLORER_NAME);\n try {\n const result = await explorer.load(configPath);\n if (!result?.config) {\n logger.debug('指定路径未找到配置,使用默认配置');\n return { ...DEFAULT_CONFIG };\n }\n\n logger.info('已加载配置文件', { filepath: result.filepath });\n return deepMerge(DEFAULT_CONFIG, resolveEnvVars(result.config) as Partial<ZapmycoConfig>);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.warn('配置加载失败,使用默认配置', { error: message });\n return { ...DEFAULT_CONFIG };\n }\n }\n\n // 1. 先尝试 cosmiconfig 默认搜索(项目级配置)\n const explorer = cosmiconfig(EXPLORER_NAME);\n let result: CosmiconfigResult | null = null;\n\n try {\n result = await explorer.search();\n } catch {\n // cosmiconfig search 失败时静默处理\n }\n\n // 2. 如果没找到项目级配置,尝试家目录配置\n if (!result?.config) {\n const homeResult = await tryLoadHomeConfig();\n if (homeResult?.config) {\n result = homeResult;\n }\n }\n\n if (!result?.config) {\n logger.debug('未找到配置文件,使用默认配置');\n return { ...DEFAULT_CONFIG };\n }\n\n logger.info('已加载配置文件', { filepath: result.filepath });\n\n // 深度合并:用户配置覆盖默认值\n return deepMerge(DEFAULT_CONFIG, result.config as Partial<ZapmycoConfig>);\n}\n\n/** 导出家目录配置路径,供外部使用 */\nexport { HOME_CONFIG_PATH };\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zapmyco",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "AI 原生并行任务编排系统 -- AI 总管 (Personal AI Chief of Staff)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",
@@ -1 +0,0 @@
1
- {"version":3,"file":"loader-D1dTKHK4.mjs","names":["EventEmitter","PiAgent"],"sources":["../src/infra/constants.ts","../src/infra/event-bus.ts","../src/core/agent-runtime/event-bridge.ts","../src/core/agent-runtime/tool-bridge.ts","../src/core/agent-runtime/agent-adapter.ts","../src/infra/errors.ts","../src/infra/logger.ts","../src/llm/cost-tracker.ts","../src/config/defaults.ts","../src/config/loader.ts"],"sourcesContent":["/**\n * zapmyco 全局常量定义\n */\n\n/** 应用名称 */\nexport const APP_NAME = 'zapmyco';\n\n/** 应用版本(由构建时注入,默认为 dev) */\nexport const __VERSION__ = '0.0.0-dev';\n\n/** 默认最大并行任务数 */\nexport const DEFAULT_MAX_PARALLELISM = 5;\n\n/** 默认单个 Agent 最大并发数 */\nexport const DEFAULT_MAX_PER_AGENT = 3;\n\n/** 默认任务超时时间(毫秒)- 30 分钟 */\nexport const DEFAULT_TASK_TIMEOUT = 30 * 60 * 1000;\n\n/** 默认最大重试次数 */\nexport const DEFAULT_MAX_RETRIES = 3;\n\n/** 重试基础延迟(毫秒) */\nexport const RETRY_BASE_DELAY = 1000;\n\n/** 最大重试延迟(毫秒)- 30s */\nexport const RETRY_MAX_DELAY = 30_000;\n\n/** 进度事件环形缓冲区大小 */\nexport const PROGRESS_RING_BUFFER_SIZE = 1000;\n\n/** 会话存储目录名 */\nexport const SESSION_DIR_NAME = '.zapmyco';\n\n/** 配置文件名列表(按优先级搜索) */\nexport const CONFIG_FILE_NAMES = [\n 'zapmyco.config.ts',\n 'zapmyco.config.js',\n 'zapmyco.config.mjs',\n 'zapmyco.config.cjs',\n 'zapmyco.config.json',\n '.zapmycorc',\n '.zapmycorc.json',\n '.zapmycorc.ts',\n '.zapmycorc.js',\n] as const;\n","/**\n * zapmyco 事件总线\n *\n * 基于 EventEmitter3 的类型安全事件总线,\n * 用于模块间解耦通信。\n *\n * 内部事件命名规范:`module:action`\n * 例如:`task:started`, `agent:progress`, `goal:completed`\n */\n\nimport { EventEmitter } from 'eventemitter3';\n\n/** 事件映射类型 */\ninterface EventMap {\n // Goal 生命周期\n 'goal:submitted': { goalId: string; rawInput: string };\n 'goal:intent-resolved': { goalId: string };\n 'goal:decomposed': { goalId: string; taskCount: number };\n 'goal:completed': { goalId: string; result: unknown };\n 'goal:failed': { goalId: string; error: Error };\n\n // Task 生命周期\n 'task:scheduled': { taskId: string; agentId: string };\n 'task:started': { taskId: string; agentId: string };\n 'task:progress': { taskId: string; percent: number; message?: string };\n 'task:output': { taskId: string; text: string };\n 'task:completed': { taskId: string; result: unknown };\n 'task:failed': { taskId: string; error: Error; retryable: boolean };\n 'task:retrying': { taskId: string; attempt: number; maxRetries: number };\n 'task:cancelled': { taskId: string };\n\n // Agent 生命周期\n 'agent:registered': { agentId: string };\n 'agent:unregistered': { agentId: string };\n 'agent:online': { agentId: string };\n 'agent:offline': { agentId: string };\n\n // 系统\n 'system:shutdown': { reason?: string };\n}\n\n/**\n * 全局事件总线实例\n *\n * 使用方式:\n * ```typescript\n * import { eventBus } from '@/infra/event-bus';\n *\n * eventBus.on('task:started', ({ taskId, agentId }) => {\n * console.log(`任务 ${taskId} 已在 ${agentId} 上启动`);\n * });\n *\n * eventBus.emit('task:started', { taskId: 'abc', agentId: 'code-1' });\n * ```\n */\nexport const eventBus = new EventEmitter<EventMap>();\n\n/** 事件映射类型导出(用于创建独立实例的场景) */\nexport type { EventMap };\nexport { EventEmitter };\n","/**\n * Event Bridge — AgentEvent ↔ eventBus 桥接\n *\n * 将 pi-agent-core 的 Agent 生命周期事件转换为\n * zapmyco 全局事件总线(eventBus)的事件格式。\n *\n * @module core/agent-runtime/event-bridge\n */\n\nimport type { AgentEvent } from '@mariozechner/pi-agent-core';\nimport { eventBus } from '@/infra/event-bus';\nimport type { AdaptedAgentEvent } from './types';\n\n// ============ 事件转换 ============\n\n/**\n * 将 pi-agent-core AgentEvent 转换为 zapmyco 适配事件\n *\n * @param agentEvent - pi-agent-core 原始事件\n * @param taskId - 关联的任务 ID\n * @param agentId - Agent 标识\n * @returns 适配后的事件,无法识别的返回 null\n */\nexport function adaptAgentEvent(\n agentEvent: AgentEvent,\n taskId: string,\n agentId: string\n): AdaptedAgentEvent | null {\n switch (agentEvent.type) {\n case 'agent_start':\n return { type: 'agent:start', taskId, agentId };\n\n case 'agent_end':\n return { type: 'agent:end', taskId, agentId };\n\n case 'turn_start':\n return { type: 'turn:start', taskId };\n\n case 'turn_end':\n return { type: 'turn:end', taskId };\n\n case 'message_start':\n return {\n type: 'message:start',\n taskId,\n textPreview: extractTextContent(agentEvent.message).slice(0, 100),\n };\n\n case 'message_update': {\n const delta = extractDelta(agentEvent.assistantMessageEvent);\n return {\n type: 'message:update',\n taskId,\n delta,\n };\n }\n\n case 'message_end':\n return {\n type: 'message:end',\n taskId,\n fullMessage: extractTextContent(agentEvent.message),\n };\n\n case 'tool_execution_start':\n return {\n type: 'tool:start',\n taskId,\n toolName: agentEvent.toolName ?? 'unknown',\n toolCallId: agentEvent.toolCallId,\n };\n\n case 'tool_execution_update':\n return {\n type: 'tool:update',\n taskId,\n toolName: agentEvent.toolName ?? 'unknown',\n };\n\n case 'tool_execution_end':\n return {\n type: 'tool:end',\n taskId,\n toolName: agentEvent.toolName ?? 'unknown',\n toolCallId: agentEvent.toolCallId,\n success: !agentEvent.isError,\n };\n\n default:\n // 忽略未知事件类型\n return null;\n }\n}\n\n// ============ 辅助函数 ============\n\n/**\n * 从 AgentMessage 中提取文本内容\n */\nfunction extractTextContent(message: unknown): string {\n if (!message || typeof message !== 'object') return '';\n const msg = message as Record<string, unknown>;\n if (typeof msg.content === 'string') return msg.content;\n if (Array.isArray(msg.content)) {\n return msg.content\n .filter(\n (block): block is { type: string; text?: string } =>\n typeof block === 'object' && block !== null && block.type === 'text'\n )\n .map((block) => block.text ?? '')\n .join('');\n }\n return '';\n}\n\n/**\n * 从 AssistantMessageEvent 中提取 delta 文本\n */\nfunction extractDelta(event: unknown): string {\n if (!event || typeof event !== 'object') return '';\n const evt = event as Record<string, unknown>;\n if (typeof evt.delta === 'string') return evt.delta;\n // 尝试从 type 字段判断\n if (evt.type === 'text_delta' && typeof evt.text_delta === 'string') {\n return evt.text_delta;\n }\n return '';\n}\n\n// ============ 事件分发 ============\n\n/**\n * 将适配后的事件分发到 zapmyco eventBus\n *\n * 映射规则:\n * - agent:start/end → agent:online/offline(带 taskId 上下文)\n * - turn:start/end → task:started/task:progress\n * - message:* → task:output\n * - tool:* → task:progress(含工具信息)\n *\n * @param event - 适配后的事件\n */\nexport function dispatchToEventBus(event: AdaptedAgentEvent): void {\n switch (event.type) {\n case 'agent:start':\n eventBus.emit('agent:online', { agentId: event.agentId });\n break;\n\n case 'agent:end':\n eventBus.emit('task:completed', {\n taskId: event.taskId,\n result: {},\n });\n break;\n\n case 'turn:start':\n eventBus.emit('task:started', {\n taskId: event.taskId,\n agentId: '',\n });\n break;\n\n case 'turn:end':\n eventBus.emit('task:progress', {\n taskId: event.taskId,\n percent: 100,\n message: 'Turn completed',\n });\n break;\n\n case 'message:start':\n case 'message:update':\n case 'message:end': {\n const text =\n event.type === 'message:update'\n ? event.delta\n : event.type === 'message:end'\n ? event.fullMessage\n : `[开始生成] ${event.textPreview}`;\n if (text) {\n eventBus.emit('task:output', { taskId: event.taskId, text });\n }\n break;\n }\n\n case 'tool:start':\n eventBus.emit('task:progress', {\n taskId: event.taskId,\n percent: 0,\n message: `执行工具: ${event.toolName}`,\n });\n break;\n\n case 'tool:update':\n eventBus.emit('task:progress', {\n taskId: event.taskId,\n percent: undefined,\n message: `${event.toolName} 更新中`,\n });\n break;\n\n case 'tool:end':\n eventBus.emit('task:progress', {\n taskId: event.taskId,\n percent: 100,\n message: `工具 ${event.toolName} ${event.success ? '完成' : '失败'}`,\n });\n break;\n\n case 'error':\n eventBus.emit('task:failed', {\n taskId: event.taskId,\n error: event.error,\n retryable: false,\n });\n break;\n }\n}\n\n// ============ 订阅桥接器 ============\n\n/**\n * 创建 Agent 事件订阅桥接器\n *\n * 返回一个订阅函数,可直接传给 pi-agent-core Agent.subscribe()。\n * 所有 Agent 事件会自动转换并分发到 zapmyco eventBus。\n *\n * @param taskId - 关联的任务 ID\n * @param agentId - Agent 标识\n * @returns 事件监听函数\n */\nexport function createEventBridgeListener(\n taskId: string,\n agentId: string\n): (event: AgentEvent, signal: AbortSignal) => void {\n return (agentEvent: AgentEvent): void => {\n const adapted = adaptAgentEvent(agentEvent, taskId, agentId);\n if (adapted) {\n dispatchToEventBus(adapted);\n }\n };\n}\n","/**\n * Tool Bridge — Capability → AgentTool 映射\n *\n * 将 zapmyco 的能力声明(Capability)转换为\n * pi-agent-core 可执行的工具定义(AgentTool)。\n *\n * @module core/agent-runtime/tool-bridge\n */\n\nimport type { AgentTool, AgentToolResult } from '@mariozechner/pi-agent-core';\nimport type { Static, TSchema } from 'typebox';\nimport type { Capability } from '@/protocol/capability';\n\n// ============ 类型定义 ============\n\n/**\n * 工具执行函数签名\n *\n * 符合 pi-agent-core AgentTool.execute 的契约。\n */\nexport type ToolExecuteFn<TParameters extends TSchema = TSchema> = (\n toolCallId: string,\n params: Static<TParameters>,\n signal?: AbortSignal,\n onUpdate?: (partialResult: AgentToolResult<unknown>) => void\n) => Promise<AgentToolResult<unknown>>;\n\n/**\n * 工具注册信息\n *\n * 用于描述一个可被 Agent 调用的具体工具。\n */\nexport interface ToolRegistration {\n /** 工具唯一标识(对应 pi-ai Tool.name) */\n id: string;\n /** 显示名称(用于 UI 展示,对应 AgentTool.label) */\n label: string;\n /** 工具描述(帮助 LLM 理解何时调用此工具) */\n description: string;\n /** 参数 Schema(TypeBox 格式,用于参数校验和 LLM 理解) */\n parameters?: TSchema;\n /** 执行函数 */\n execute: ToolExecuteFn;\n /** 执行模式:顺序或并行 */\n executionMode?: 'sequential' | 'parallel';\n}\n\n// ============ 核心映射函数 ============\n\n/**\n * 将单个 ToolRegistration 转换为 pi-agent-core 的 AgentTool\n *\n * @param registration - 工具注册信息\n * @returns pi-agent-core AgentTool 实例\n */\nexport function toAgentTool(registration: ToolRegistration): AgentTool {\n // AgentTool 要求 parameters 必须提供(TSchema 类型)\n // 当注册时未指定参数 schema,使用空对象 schema 作为默认\n const tool: AgentTool = {\n name: registration.id,\n description: registration.description,\n label: registration.label,\n parameters: registration.parameters ?? { type: 'object' as const, properties: {} },\n execute: registration.execute,\n ...(registration.executionMode != null ? { executionMode: registration.executionMode } : {}),\n };\n\n return tool;\n}\n\n/**\n * 将工具注册列表批量转换为 AgentTool 数组\n *\n * @param registrations - 工具注册列表\n * @returns AgentTool 数组\n */\nexport function toAgentTools(registrations: ToolRegistration[]): AgentTool[] {\n return registrations.map(toAgentTool);\n}\n\n/**\n * 基于 Capability 创建默认工具注册模板\n *\n * 此函数提供从 Capability 到 ToolRegistration 的基础映射。\n * 实际的 execute 函数需要由调用方根据具体能力注入。\n *\n * @param capability - 能力声明\n * @param execute - 执行函数(必须由调用方提供)\n * @returns ToolRegistration\n */\nexport function createToolFromCapability(\n capability: Capability,\n execute: ToolExecuteFn\n): ToolRegistration {\n return {\n id: capability.id,\n label: capability.name,\n description: capability.description,\n execute,\n };\n}\n\n/**\n * 基于多个 Capability 批量创建工具注册模板\n *\n * @param capabilities - 能力声明列表\n * @param executorFactory - 根据 Capability 生成执行函数的工厂\n * @returns ToolRegistration 数组\n */\nexport function createToolsFromCapabilities(\n capabilities: Capability[],\n executorFactory: (capability: Capability) => ToolExecuteFn\n): ToolRegistration[] {\n return capabilities.map((cap) => createToolFromCapability(cap, executorFactory(cap)));\n}\n","/**\n * Agent Adapter — IAgent → pi-agent-core.Agent 适配器\n *\n * 将 pi-agent-core 的有状态 Agent 封装为 zapmyco 的 IAgent 接口实现。\n * 这是 agent-runtime 层的核心集成点。\n *\n * @module core/agent-runtime/agent-adapter\n */\n\nimport { EventEmitter } from 'node:events';\nimport { Agent as PiAgent } from '@mariozechner/pi-agent-core';\nimport type { TaskResult } from '@/core/result/types';\nimport type {\n AgentExecuteRequest,\n AgentHealthStatus,\n AgentStatus,\n IStreamingAgent,\n} from '@/protocol/agent';\nimport type { Capability } from '@/protocol/capability';\nimport { createEventBridgeListener } from './event-bridge';\nimport { type ToolRegistration, toAgentTools } from './tool-bridge';\nimport type { AgentAdapterOptions, AgentRuntimeConfig } from './types';\n\n// ============ 默认配置 ============\n\nconst DEFAULT_RUNTIME_CONFIG: Required<AgentRuntimeConfig> = {\n enabled: true,\n toolExecution: 'sequential',\n maxTurns: 50,\n thinkingLevel: 'medium',\n};\n\n// ============ LlmBasedAgent 实现 ============\n\n/**\n * 基于 pi-agent-core 的 LLM 驱动 Agent 实现\n *\n * 将 zapmyco 的 IAgent 接口适配到 pi-agent-core 的 Agent 类,\n * 实现完整的 Agent 生命周期管理:\n * - execute(): 通过 Agent.prompt() 发起任务\n * - cancel(): 通过 Agent.abort() 中止执行\n * - healthCheck(): 检查 Agent 内部状态\n * - 流式事件: 通过 EventEmitter + EventBridge 双通道输出\n */\nexport class LlmBasedAgent extends EventEmitter implements IStreamingAgent {\n readonly EVENT_PROGRESS = 'progress' as const;\n readonly EVENT_OUTPUT = 'output' as const;\n readonly EVENT_ERROR = 'error' as const;\n\n // ============ IAgent 契约 ============\n\n readonly agentId: string;\n readonly displayName: string;\n readonly capabilities: readonly Capability[];\n\n // ============ 内部状态 ============\n\n private inner: PiAgent;\n private config: Required<AgentRuntimeConfig>;\n private toolRegistrations: ToolRegistration[] = [];\n private _currentLoad = 0;\n\n constructor(options: AgentAdapterOptions) {\n super();\n\n this.agentId = options.agentId;\n this.displayName = options.displayName;\n this.capabilities = options.capabilities;\n this.config = { ...DEFAULT_RUNTIME_CONFIG, ...options.runtimeConfig };\n\n // 创建 pi-agent-core Agent 实例\n this.inner = new PiAgent({\n toolExecution: this.config.toolExecution,\n });\n }\n\n // ============ 属性访问器 ============\n\n get status(): AgentStatus {\n if (!this.config.enabled) return 'offline';\n if (this._currentLoad > 0) return 'busy';\n return 'online';\n }\n\n get currentLoad(): number {\n return this._currentLoad;\n }\n\n /**\n * 访问内部 pi-agent-core Agent 实例(仅限高级用法)\n *\n * @internal 仅供测试和高级集成使用\n */\n get innerAgent(): PiAgent {\n return this.inner;\n }\n\n // ============ 工具注册 ============\n\n /**\n * 注册工具到 Agent\n *\n * @param tools - 工具注册列表\n */\n registerTools(tools: ToolRegistration[]): void {\n this.toolRegistrations.push(...tools);\n const agentTools = toAgentTools(tools);\n // 通过 state.tools 设置(AgentState 的 tools 是 getter/setter)\n this.inner.state.tools = [...this.inner.state.tools, ...agentTools];\n }\n\n /**\n * 清除所有已注册的工具\n */\n clearTools(): void {\n this.toolRegistrations = [];\n this.inner.state.tools = [];\n }\n\n // ============ IAgent 核心方法 ============\n\n /**\n * 执行任务\n *\n * 将 AgentExecuteRequest 转换为 pi-agent-core Agent 的 prompt 调用:\n * 1. 构建执行上下文(任务描述 + 上游结果)\n * 2. 设置系统提示词\n * 3. 绑定事件桥接到 eventBus + EventEmitter\n * 4. 调用 Agent.prompt() 并等待完成\n * 5. 提取结果并组装为 TaskResult\n */\n async execute(request: AgentExecuteRequest): Promise<TaskResult> {\n const startTime = Date.now();\n this._currentLoad++;\n const cleanupFns: (() => void)[] = [];\n\n try {\n // 构建系统提示词并设置到 Agent 状态\n this.inner.state.systemPrompt = this.buildSystemPrompt(request);\n\n // 绑定事件桥接(带 taskId),收集清理函数用于后续移除\n cleanupFns.push(\n this.inner.subscribe(createEventBridgeListener(request.taskId, this.agentId)),\n );\n\n // 同时监听并转发到本地的 EventEmitter(支持 IStreamingAgent)\n cleanupFns.push(\n this.inner.subscribe((event) => {\n if (event.type === 'message_update') {\n const delta = extractDeltaFromEvent(event);\n if (delta) {\n this.emit(this.EVENT_OUTPUT, {\n taskId: request.taskId,\n text: delta,\n });\n }\n }\n if (event.type === 'tool_execution_start') {\n this.emit(this.EVENT_PROGRESS, {\n taskId: request.taskId,\n percent: 0,\n message: `执行工具: ${event.toolName}`,\n });\n }\n if (event.type === 'tool_execution_end') {\n this.emit(this.EVENT_PROGRESS, {\n taskId: request.taskId,\n percent: 100,\n message: `工具 ${event.toolName} 完成`,\n });\n }\n if (event.type === 'agent_end') {\n this.emit(this.EVENT_PROGRESS, {\n taskId: request.taskId,\n percent: 100,\n message: '任务完成',\n });\n }\n }),\n );\n\n // 执行 prompt\n await this.inner.prompt(request.taskDescription);\n\n // 等待 Agent 进入空闲状态\n await this.inner.waitForIdle();\n\n // 提取结果\n const result = this.extractTaskResult(request.taskId, startTime);\n\n return result;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n\n // 发送错误事件\n this.emit(this.EVENT_ERROR, { taskId: request.taskId, error: err });\n\n return {\n taskId: request.taskId,\n status: 'failure',\n output: null,\n artifacts: [],\n duration: Date.now() - startTime,\n tokenUsage: {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n error: {\n code: 'AGENT_EXECUTION_FAILED',\n message: err.message,\n retryable: false,\n details: { stack: err.stack },\n },\n };\n } finally {\n // 清理本次执行的事件订阅(防止复用 Agent 实例时监听器累积)\n for (const fn of cleanupFns) {\n fn();\n }\n this._currentLoad--;\n }\n }\n\n /**\n * 取消正在执行的任务\n */\n async cancel(taskId: string): Promise<void> {\n this.inner.abort();\n this.emit(this.EVENT_PROGRESS, {\n taskId,\n percent: -1,\n message: '任务已取消',\n });\n }\n\n /**\n * 健康检查\n */\n async healthCheck(): Promise<AgentHealthStatus> {\n const startTime = Date.now();\n try {\n // 检查内部 Agent 状态是否可访问\n const state = this.inner.state;\n const latencyMs = Date.now() - startTime;\n\n return {\n 是否健康: this.config.enabled && !state.isStreaming,\n latencyMs,\n version: `pi-agent-core@${this.getPkgVersion()}`,\n details: {\n isStreaming: state.isStreaming,\n messagesCount: state.messages.length,\n toolsCount: state.tools.length,\n currentLoad: this._currentLoad,\n },\n };\n } catch {\n return {\n 是否健康: false,\n latencyMs: Date.now() - startTime,\n version: 'unknown',\n details: { error: 'Health check failed' },\n };\n }\n }\n\n // ============ 辅助方法 ============\n\n /**\n * 构建系统提示词\n */\n private buildSystemPrompt(request: AgentExecuteRequest): string {\n const parts: string[] = [\n `你是 ${this.displayName},一个专业的 AI 助手。`,\n `你的能力包括:${this.capabilities.map((c) => c.name).join('、')}。`,\n ];\n\n if (request.upstreamResults?.length) {\n parts.push(\n '\\n## 上游任务结果\\n',\n ...request.upstreamResults.map((r, i) => `[上游任务 ${i + 1}] ${JSON.stringify(r.output)}`)\n );\n }\n\n if (request.workdir) {\n parts.push(`\\n## 工作目录\\n${request.workdir}`);\n }\n\n return parts.join('\\n');\n }\n\n /**\n * 从 Agent 状态中提取 TaskResult\n */\n private extractTaskResult(taskId: string, startTime: number): TaskResult {\n const state = this.inner.state;\n const duration = Date.now() - startTime;\n\n // 从消息历史中提取最后的 assistant 回复作为 output\n const lastAssistantMessage = [...state.messages].reverse().find((m) => m.role === 'assistant');\n\n const output = lastAssistantMessage ? extractTextFromMessage(lastAssistantMessage) : null;\n\n return {\n taskId,\n status: 'success',\n output,\n artifacts: [],\n duration,\n tokenUsage: {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n estimatedCostUsd: 0,\n },\n };\n }\n\n /**\n * 获取 pi-agent-core 包版本号\n */\n private getPkgVersion(): string {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const pkg = require('@mariozechner/pi-agent-core/package.json');\n return pkg.version ?? 'unknown';\n } catch {\n return 'unknown';\n }\n }\n}\n\n// ============ 工厂函数 ============\n\n/**\n * 创建 LlmBasedAgent 实例的工厂函数\n *\n * @param options - 适配器选项\n * @returns 配置好的 LlmBasedAgent 实例\n */\nexport function createLlmBasedAgent(options: AgentAdapterOptions): LlmBasedAgent {\n return new LlmBasedAgent(options);\n}\n\n/**\n * 从 SubTask 创建 Agent 执行请求\n *\n * 将 zapmyco 的 SubTask 转换为 AgentExecuteRequest 格式。\n *\n * @param subTask - 子任务定义\n * @param workdir - 项目工作目录\n * @param options - 执行选项\n * @returns AgentExecuteRequest\n */\nexport function createRequestFromSubTask(\n subTask: import('@/core/task/types').SubTask,\n workdir: string,\n options?: Partial<AgentExecuteRequest['options']>\n): AgentExecuteRequest {\n return {\n taskId: subTask.id,\n taskDescription: subTask.description,\n workdir,\n options: {\n timeout: 300_000, // 默认 5 分钟超时\n verbose: false,\n ...options,\n },\n };\n}\n\n// ============ 辅助函数 ============\n\n/**\n * 从 AgentMessage 中提取文本内容\n */\nfunction extractTextFromMessage(message: unknown): string | null {\n if (!message || typeof message !== 'object') return null;\n const msg = message as Record<string, unknown>;\n if (typeof msg.content === 'string') return msg.content;\n if (Array.isArray(msg.content)) {\n return msg.content\n .filter(\n (block): block is { type: string; text?: string } =>\n typeof block === 'object' && block !== null && block.type === 'text'\n )\n .map((block) => block.text ?? '')\n .join('');\n }\n return null;\n}\n\n/**\n * 从 message_update 事件中提取 delta 文本\n */\nfunction extractDeltaFromEvent(event: {\n type: 'message_update';\n message: unknown;\n assistantMessageEvent: unknown;\n}): string | null {\n const evt = event.assistantMessageEvent as Record<string, unknown> | null;\n if (!evt || typeof evt !== 'object') return null;\n if (typeof evt.delta === 'string') return evt.delta;\n if (\n evt.type === 'text_delta' &&\n typeof (evt as Record<string, unknown>).text_delta === 'string'\n ) {\n return (evt as Record<string, unknown>).text_delta as string;\n }\n return null;\n}\n","/**\n * zapmyco 统一错误类型\n *\n * 所有模块应使用或继承这些错误类型,确保错误信息一致且可追踪。\n */\n\n/** 错误码枚举 */\nexport enum ZapmycoErrorCode {\n // 意图理解相关\n INTENT_PARSE_FAILED = 'INTENT_PARSE_FAILED',\n INTENT_LOW_CONFIDENCE = 'INTENT_LOW_CONFIDENCE',\n\n // 任务拆分相关\n DECOMPOSE_FAILED = 'DECOMPOSE_FAILED',\n DECOMPOSE_INVALID_GRAPH = 'DECOMPOSE_INVALID_GRAPH',\n\n // 调度相关\n SCHEDULER_NO_AVAILABLE_AGENT = 'SCHEDULER_NO_AVAILABLE_AGENT',\n SCHEDULER_CAPABILITY_MISMATCH = 'SCHEDULER_CAPABILITY_MISMATCH',\n SCHEDULER_TASK_TIMEOUT = 'SCHEDULER_TASK_TIMEOUT',\n\n // Agent 相关\n AGENT_NOT_FOUND = 'AGENT_NOT_FOUND',\n AGENT_OFFLINE = 'AGENT_OFFLINE',\n AGENT_EXECUTION_FAILED = 'AGENT_EXECUTION_FAILED',\n AGENT_HEALTH_CHECK_FAILED = 'AGENT_HEALTH_CHECK_FAILED',\n\n // 配置相关\n CONFIG_LOAD_FAILED = 'CONFIG_LOAD_FAILED',\n CONFIG_INVALID = 'CONFIG_INVALID',\n\n // LLM 相关\n LLM_API_ERROR = 'LLM_API_ERROR',\n LLM_RATE_LIMITED = 'LLM_RATE_LIMITED',\n LLM_QUOTA_EXCEEDED = 'LLM_QUOTA_EXCEEDED',\n\n // 通用\n UNKNOWN = 'UNKNOWN',\n INTERNAL_ERROR = 'INTERNAL_ERROR',\n}\n\n/**\n * zapmyco 基础错误类\n *\n * 所有业务错误都应继承此类,提供结构化的错误信息。\n */\nexport class ZapmycoError extends Error {\n /** 错误码 */\n readonly code: ZapmycoErrorCode;\n /** 额外的上下文信息 */\n readonly context?: Record<string, unknown>;\n\n constructor(code: ZapmycoErrorCode, message: string, context?: Record<string, unknown>) {\n super(message);\n this.name = 'ZapmycoError';\n this.code = code;\n Object.assign(this, context !== undefined ? { context } : {});\n\n // 保持正确的原型链(ES5+ 兼容)\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n /** 转换为可序列化的对象 */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n context: this.context,\n stack: this.stack,\n };\n }\n}\n\n/** 意图理解错误 */\nexport class IntentError extends ZapmycoError {\n constructor(\n code: ZapmycoErrorCode.INTENT_PARSE_FAILED | ZapmycoErrorCode.INTENT_LOW_CONFIDENCE,\n message: string,\n context?: Record<string, unknown>\n ) {\n super(code, message, context);\n this.name = 'IntentError';\n }\n}\n\n/** 任务拆分错误 */\nexport class DecomposeError extends ZapmycoError {\n constructor(\n code: ZapmycoErrorCode.DECOMPOSE_FAILED | ZapmycoErrorCode.DECOMPOSE_INVALID_GRAPH,\n message: string,\n context?: Record<string, unknown>\n ) {\n super(code, message, context);\n this.name = 'DecomposeError';\n }\n}\n\n/** 调度错误 */\nexport class SchedulerError extends ZapmycoError {\n constructor(\n code:\n | ZapmycoErrorCode.SCHEDULER_NO_AVAILABLE_AGENT\n | ZapmycoErrorCode.SCHEDULER_CAPABILITY_MISMATCH\n | ZapmycoErrorCode.SCHEDULER_TASK_TIMEOUT,\n message: string,\n context?: Record<string, unknown>\n ) {\n super(code, message, context);\n this.name = 'SchedulerError';\n }\n}\n\n/** Agent 执行错误 */\nexport class AgentError extends ZapmycoError {\n constructor(\n code:\n | ZapmycoErrorCode.AGENT_NOT_FOUND\n | ZapmycoErrorCode.AGENT_OFFLINE\n | ZapmycoErrorCode.AGENT_EXECUTION_FAILED\n | ZapmycoErrorCode.AGENT_HEALTH_CHECK_FAILED,\n message: string,\n context?: Record<string, unknown>\n ) {\n super(code, message, context);\n this.name = 'AgentError';\n }\n}\n\n/** LLM 调用错误 */\nexport class LlmError extends ZapmycoError {\n constructor(\n code:\n | ZapmycoErrorCode.LLM_API_ERROR\n | ZapmycoErrorCode.LLM_RATE_LIMITED\n | ZapmycoErrorCode.LLM_QUOTA_EXCEEDED,\n message: string,\n context?: Record<string, unknown>\n ) {\n super(code, message, context);\n this.name = 'LlmError';\n }\n}\n","/**\n * zapmyco 日志系统\n *\n * 提供结构化的日志输出,支持不同级别和格式化。\n */\n\nimport { ZapmycoError } from '@/infra/errors';\n\n/** 日志级别 */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/** 日志条目 */\nexport interface LogEntry {\n level: LogLevel;\n message: string;\n timestamp: string;\n context?: Record<string, unknown>;\n error?: Error;\n}\n\n/** 级别对应的标签(用于终端输出) */\nconst LEVEL_LABELS: Record<LogLevel, string> = {\n debug: 'DBG',\n info: 'INF',\n warn: 'WRN',\n error: 'ERR',\n};\n\n/** 级别权重(用于过滤) */\nconst LEVEL_WEIGHTS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\n/**\n * Logger 实例\n */\nclass Logger {\n private minLevel: LogLevel;\n private entries: LogEntry[] = [];\n\n constructor(minLevel: LogLevel = 'info') {\n this.minLevel = minLevel;\n }\n\n /** 设置日志级别 */\n setLevel(level: LogLevel): void {\n this.minLevel = level;\n }\n\n /** 创建带前缀的子 logger */\n child(prefix: string): Logger {\n const child = new Logger(this.minLevel);\n const originalLog = child.log.bind(child);\n child.log = (\n level: LogLevel,\n message: string,\n context?: Record<string, unknown>,\n error?: Error\n ) => {\n originalLog(level, `[${prefix}] ${message}`, context, error);\n };\n return child;\n }\n\n /** 核心日志方法 */\n log(level: LogLevel, message: string, context?: Record<string, unknown>, error?: Error): void {\n if (LEVEL_WEIGHTS[level] < LEVEL_WEIGHTS[this.minLevel]) {\n return;\n }\n\n const entry: LogEntry = {\n level,\n message,\n timestamp: new Date().toISOString(),\n ...(context !== undefined ? { context } : {}),\n ...(error !== undefined ? { error } : {}),\n };\n\n this.entries.push(entry);\n\n // 终端输出格式\n const timestamp = entry.timestamp.replace('T', ' ').slice(0, 19);\n const label = LEVEL_LABELS[level];\n let output = `${timestamp} [${label}] ${message}`;\n\n if (entry.context && Object.keys(entry.context).length > 0) {\n output += ` ${JSON.stringify(entry.context)}`;\n }\n\n if (error instanceof ZapmycoError) {\n output += ` (${error.code}) ${error.message}`;\n } else if (error) {\n output += ` ${error.message}`;\n }\n\n const stream = level === 'error' ? process.stderr : process.stdout;\n stream.write(`${output}\\n`);\n }\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.log('debug', message, context);\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.log('info', message, context);\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.log('warn', message, context);\n }\n\n error(message: string, context?: Record<string, unknown>, error?: Error): void {\n this.log('error', message, context, error);\n }\n\n /** 获取所有日志条目 */\n getEntries(): LogEntry[] {\n return [...this.entries];\n }\n\n /** 清空日志条目 */\n clear(): void {\n this.entries = [];\n }\n}\n\n/** 全局默认 logger 实例 */\nexport const logger = new Logger();\n\nexport { Logger };\n","/**\n * Token / Cost 追踪器\n *\n * 实时跟踪所有 LLM 调用的 Token 消耗和预估费用,\n * 用于成本控制和用户展示。\n */\n\nimport type { TokenUsage } from '@/core/result/types';\nimport { logger } from '@/infra/logger';\n\n/** 模型定价信息(每百万 token 的美元价格) */\ninterface ModelPricing {\n inputPricePer1M: number;\n outputPricePer1M: number;\n}\n\n/** 已知模型的定价表 */\nconst MODEL_PRICING: Record<string, ModelPricing> = {\n // Anthropic Claude\n 'claude-haiku-4-5-20251001': { inputPricePer1M: 0.8, outputPricePer1M: 4 },\n 'claude-sonnet-4-20250514': { inputPricePer1M: 3, outputPricePer1M: 15 },\n 'claude-opus-4-20250514': { inputPricePer1M: 15, outputPricePer1M: 75 },\n\n // OpenAI\n 'gpt-4o': { inputPricePer1M: 2.5, outputPricePer1M: 10 },\n 'gpt-4o-mini': { inputPricePer1M: 0.15, outputPricePer1M: 0.6 },\n};\n\n/**\n * CostTracker 实例\n *\n * 使用方式:\n * ```typescript\n * import { costTracker } from '@/llm/cost-tracker';\n *\n * costTracker.record({ inputTokens: 1000, outputTokens: 500 }, 'claude-sonnet-4');\n * const summary = costTracker.getSummary();\n * console.log(`总花费: $${summary.totalCostUsd}`);\n * ```\n */\nexport class CostTracker {\n private records: Array<{ usage: TokenUsage; model: string; timestamp: number }> = [];\n\n /** 记录一次 LLM 调用的 Token 消耗 */\n record(usage: Omit<TokenUsage, 'estimatedCostUsd'>, model: string): void {\n const pricing = MODEL_PRICING[model] ?? { inputPricePer1M: 0, outputPricePer1M: 0 };\n const estimatedCostUsd =\n (usage.inputTokens / 1_000_000) * pricing.inputPricePer1M +\n (usage.outputTokens / 1_000_000) * pricing.outputPricePer1M;\n\n const fullUsage: TokenUsage = {\n ...usage,\n totalTokens: usage.inputTokens + usage.outputTokens,\n estimatedCostUsd,\n };\n\n this.records.push({\n usage: fullUsage,\n model,\n timestamp: Date.now(),\n });\n\n logger.debug('Token 消耗记录', {\n model,\n tokens: fullUsage.totalTokens,\n cost: `$${estimatedCostUsd.toFixed(4)}`,\n });\n }\n\n /** 获取累计摘要 */\n getSummary(): {\n totalInputTokens: number;\n totalOutputTokens: number;\n totalTokens: number;\n totalCostUsd: number;\n callCount: number;\n } {\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCostUsd = 0;\n\n for (const record of this.records) {\n totalInputTokens += record.usage.inputTokens;\n totalOutputTokens += record.usage.outputTokens;\n totalCostUsd += record.usage.estimatedCostUsd;\n }\n\n return {\n totalInputTokens,\n totalOutputTokens,\n totalTokens: totalInputTokens + totalOutputTokens,\n totalCostUsd,\n callCount: this.records.length,\n };\n }\n\n /** 重置所有记录 */\n reset(): void {\n this.records = [];\n }\n\n /** 获取记录数 */\n get count(): number {\n return this.records.length;\n }\n}\n\n/** 全局默认 CostTracker 实例 */\nexport const costTracker = new CostTracker();\n","/**\n * zapmyco 默认配置\n *\n * 当用户未提供配置时,使用这些默认值。\n */\n\nimport type { ZapmycoConfig } from '@/config/types';\n\n/** 默认配置 */\nexport const DEFAULT_CONFIG: ZapmycoConfig = {\n llm: {\n defaultModel: 'anthropic/claude-sonnet-4-20250514',\n models: {\n 'anthropic/claude-sonnet-4-20250514': {\n provider: 'anthropic',\n modelId: 'claude-sonnet-4-20250514',\n description: 'Anthropic Claude Sonnet 4 - 均衡模型,日常使用推荐',\n },\n },\n providers: {\n anthropic: {\n // biome-ignore lint/suspicious/noTemplateCurlyInString: 环境变量引用语法\n apiKey: '${ANTHROPIC_API_KEY}',\n },\n },\n defaults: {\n maxTokens: 8192,\n temperature: 0.7,\n },\n },\n scheduler: {\n maxConcurrency: 5,\n maxPerAgent: 3,\n taskTimeoutMs: 30 * 60 * 1000, // 30 分钟\n maxRetries: 3,\n retryBaseDelayMs: 1000,\n },\n agents: [\n { id: 'code-agent', enabled: true },\n { id: 'security-scanner', enabled: true },\n { id: 'research-agent', enabled: true },\n { id: 'planning-agent', enabled: true },\n ],\n cli: {\n color: true,\n debug: false,\n outputFormat: 'text',\n },\n};\n","/**\n * zapmyco 配置加载器\n *\n * 使用 cosmiconfig 搜索并加载配置文件。\n * 支持多路径搜索,包括用户家目录 ~/.zapmyco/zapmyco.json。\n */\n\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { type CosmiconfigResult, cosmiconfig } from 'cosmiconfig';\nimport { DEFAULT_CONFIG } from '@/config/defaults';\nimport type { ZapmycoConfig } from '@/config/types';\nimport { logger } from '@/infra/logger';\n\n// cosmiconfig 的 explorer 名称\nconst EXPLORER_NAME = 'zapmyco';\n\n/** 用户家目录配置路径 */\nconst HOME_CONFIG_PATH = join(homedir(), '.zapmyco', 'zapmyco.json');\n\n/**\n * 解析配置值中的环境变量引用\n *\n * 支持语法:${ENV_VAR_NAME}\n * 未定义的环境变量会被替换为空字符串\n */\nfunction resolveEnvVars(value: unknown): unknown {\n if (typeof value === 'string') {\n return value.replace(/\\$\\{(\\w+)\\}/g, (_match, varName) => {\n return process.env[varName] ?? '';\n });\n }\n\n if (Array.isArray(value)) {\n return value.map(resolveEnvVars);\n }\n\n if (value !== null && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n result[key] = resolveEnvVars(val);\n }\n return result;\n }\n\n return value;\n}\n\n/**\n * 深度合并两个对象\n */\nfunction deepMerge<T>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key of Object.keys(source) as Array<keyof T & string>) {\n const sourceValue = source[key as keyof T];\n const targetValue = (target as Record<string, unknown>)[key];\n\n if (\n sourceValue !== undefined &&\n typeof sourceValue === 'object' &&\n sourceValue !== null &&\n !Array.isArray(sourceValue) &&\n typeof targetValue === 'object' &&\n targetValue !== null &&\n !Array.isArray(targetValue)\n ) {\n (result as Record<string, unknown>)[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>\n );\n } else if (sourceValue !== undefined) {\n (result as Record<string, unknown>)[key] = sourceValue;\n }\n }\n\n return result;\n}\n\n/**\n * 确保家目录配置文件存在,不存在则创建模板\n */\nasync function ensureHomeConfig(): Promise<void> {\n if (existsSync(HOME_CONFIG_PATH)) {\n return;\n }\n\n const dir = join(homedir(), '.zapmyco');\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n\n const template: Record<string, unknown> = {\n llm: {\n defaultModel: 'anthropic/claude-sonnet-4-20250514',\n models: {\n 'anthropic/claude-sonnet-4-20250514': {\n provider: 'anthropic',\n modelId: 'claude-sonnet-4-20250514',\n description: 'Anthropic Claude Sonnet 4 - 均衡模型,日常使用推荐',\n },\n 'openai/gpt-4o': {\n provider: 'openai',\n modelId: 'gpt-4o',\n description: 'OpenAI GPT-4o - 多功能模型',\n },\n },\n providers: {\n anthropic: {\n // biome-ignore lint/suspicious/noTemplateCurlyInString: 环境变量引用语法\n apiKey: '${ANTHROPIC_API_KEY}',\n },\n openai: {\n // biome-ignore lint/suspicious/noTemplateCurlyInString: 环境变量引用语法\n apiKey: '${OPENAI_API_KEY}',\n },\n },\n defaults: {\n maxTokens: 8192,\n temperature: 0.7,\n },\n },\n };\n\n await writeFile(HOME_CONFIG_PATH, JSON.stringify(template, null, 2) + '\\n', 'utf-8');\n logger.info('已创建默认配置文件', { filepath: HOME_CONFIG_PATH });\n}\n\n/**\n * 尝试从家目录加载配置\n */\nasync function tryLoadHomeConfig(): Promise<CosmiconfigResult | null> {\n try {\n if (!existsSync(HOME_CONFIG_PATH)) {\n await ensureHomeConfig();\n }\n\n const content = await readFile(HOME_CONFIG_PATH, 'utf-8');\n const config = JSON.parse(content);\n\n return {\n config: resolveEnvVars(config),\n filepath: HOME_CONFIG_PATH,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * 加载 zapmyco 配置\n *\n * 搜索优先级:\n * 1. 显式指定的 configPath\n * 2. 项目级配置文件(cosmiconfig 默认搜索)\n * 3. 用户家目录 ~/.zapmyco/zapmyco.json\n * 4. 默认值\n *\n * @param configPath - 可选的显式配置文件路径\n * @returns 合并后的完整配置(用户配置 + 默认值深度合并)\n */\nexport async function loadConfig(configPath?: string): Promise<ZapmycoConfig> {\n // 如果显式指定了路径,直接加载\n if (configPath) {\n const explorer = cosmiconfig(EXPLORER_NAME);\n try {\n const result = await explorer.load(configPath);\n if (!result?.config) {\n logger.debug('指定路径未找到配置,使用默认配置');\n return { ...DEFAULT_CONFIG };\n }\n\n logger.info('已加载配置文件', { filepath: result.filepath });\n return deepMerge(DEFAULT_CONFIG, resolveEnvVars(result.config) as Partial<ZapmycoConfig>);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.warn('配置加载失败,使用默认配置', { error: message });\n return { ...DEFAULT_CONFIG };\n }\n }\n\n // 1. 先尝试 cosmiconfig 默认搜索(项目级配置)\n const explorer = cosmiconfig(EXPLORER_NAME);\n let result: CosmiconfigResult | null = null;\n\n try {\n result = await explorer.search();\n } catch {\n // cosmiconfig search 失败时静默处理\n }\n\n // 2. 如果没找到项目级配置,尝试家目录配置\n if (!result?.config) {\n const homeResult = await tryLoadHomeConfig();\n if (homeResult?.config) {\n result = homeResult;\n }\n }\n\n if (!result?.config) {\n logger.debug('未找到配置文件,使用默认配置');\n return { ...DEFAULT_CONFIG };\n }\n\n logger.info('已加载配置文件', { filepath: result.filepath });\n\n // 深度合并:用户配置覆盖默认值\n return deepMerge(DEFAULT_CONFIG, result.config as Partial<ZapmycoConfig>);\n}\n\n/** 导出家目录配置路径,供外部使用 */\nexport { HOME_CONFIG_PATH };\n"],"mappings":"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"}