autosnippet 3.2.8 → 3.2.9
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/bin/cli.js +6 -5
- package/dashboard/dist/assets/index-BTAsOZv2.js +128 -0
- package/dashboard/dist/assets/index-C_72Ct98.css +1 -0
- package/dashboard/dist/index.html +2 -2
- package/lib/cli/AiScanService.js +23 -26
- package/lib/cli/SetupService.js +1 -1
- package/lib/core/AstAnalyzer.js +1 -1
- package/lib/core/discovery/index.js +2 -2
- package/lib/external/ai/AiProvider.js +66 -172
- package/lib/external/ai/providers/GoogleGeminiProvider.js +23 -1
- package/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.js +3 -3
- package/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +8 -8
- package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +287 -204
- package/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +7 -6
- package/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.js +1 -1
- package/lib/external/mcp/handlers/bootstrap-internal.js +2 -2
- package/lib/external/mcp/handlers/dimension-complete-external.js +6 -6
- package/lib/http/HttpServer.js +1 -1
- package/lib/http/middleware/requestLogger.js +1 -0
- package/lib/http/routes/ai.js +240 -35
- package/lib/http/routes/candidates.js +2 -3
- package/lib/http/routes/extract.js +13 -11
- package/lib/http/routes/modules.js +2 -2
- package/lib/http/routes/recipes.js +9 -5
- package/lib/http/routes/remote.js +134 -255
- package/lib/http/routes/violations.js +0 -54
- package/lib/http/utils/sse-sessions.js +1 -1
- package/lib/infrastructure/logging/Logger.js +5 -4
- package/lib/infrastructure/monitoring/PerformanceMonitor.js +3 -2
- package/lib/injection/ServiceContainer.js +64 -17
- package/lib/platform/ScreenCaptureService.js +177 -0
- package/lib/platform/ios/routes/spm.js +2 -2
- package/lib/service/agent/AgentEventBus.js +207 -0
- package/lib/service/agent/AgentFactory.js +490 -0
- package/lib/service/agent/AgentMessage.js +240 -0
- package/lib/service/agent/AgentRouter.js +228 -0
- package/lib/service/agent/AgentRuntime.js +1016 -0
- package/lib/service/agent/AgentState.js +217 -0
- package/lib/service/agent/IntentClassifier.js +331 -0
- package/lib/service/agent/LarkTransport.js +389 -0
- package/lib/service/agent/capabilities.js +408 -0
- package/lib/service/{chat → agent/context}/ContextWindow.js +37 -12
- package/lib/service/{chat → agent/context}/ExplorationTracker.js +25 -14
- package/lib/service/{chat → agent/core}/ChatAgentPrompts.js +1 -1
- package/lib/service/agent/core/LoopContext.js +170 -0
- package/lib/service/agent/core/MessageAdapter.js +223 -0
- package/lib/service/agent/core/ToolExecutionPipeline.js +376 -0
- package/lib/service/{chat → agent/domain}/ChatAgentTasks.js +19 -98
- package/lib/service/{chat → agent/domain}/EpisodicConsolidator.js +7 -7
- package/lib/service/{chat → agent/domain}/EvidenceCollector.js +4 -2
- package/lib/service/{chat/AnalystAgent.js → agent/domain/insight-analyst.js} +37 -172
- package/lib/service/{chat/HandoffProtocol.js → agent/domain/insight-gate.js} +85 -135
- package/lib/service/agent/domain/insight-producer.js +267 -0
- package/lib/service/agent/domain/scan-prompts.js +105 -0
- package/lib/service/agent/forced-summary.js +266 -0
- package/lib/service/agent/index.js +91 -0
- package/lib/service/{chat → agent}/memory/MemoryCoordinator.js +7 -7
- package/lib/service/{chat/ProjectSemanticMemory.js → agent/memory/PersistentMemory.js} +359 -89
- package/lib/service/{chat → agent}/memory/SessionStore.js +1 -1
- package/lib/service/{chat → agent}/memory/index.js +1 -1
- package/lib/service/agent/policies.js +442 -0
- package/lib/service/agent/presets.js +303 -0
- package/lib/service/agent/strategies.js +717 -0
- package/lib/service/{chat → agent/tools}/ToolRegistry.js +3 -3
- package/lib/service/agent/tools/ai-analysis.js +75 -0
- package/lib/service/{chat → agent}/tools/composite.js +2 -1
- package/lib/service/{chat → agent}/tools/guard.js +1 -121
- package/lib/service/{chat → agent}/tools/index.js +27 -21
- package/lib/service/{chat → agent}/tools/infrastructure.js +1 -1
- package/lib/service/agent/tools/knowledge-graph.js +112 -0
- package/lib/service/agent/tools/scan-recipe.js +189 -0
- package/lib/service/agent/tools/system-interaction.js +476 -0
- package/lib/service/automation/DirectiveDetector.js +0 -1
- package/lib/service/automation/FileWatcher.js +0 -8
- package/lib/service/automation/handlers/CreateHandler.js +7 -3
- package/lib/service/automation/handlers/DraftHandler.js +7 -6
- package/lib/service/module/ModuleService.js +40 -73
- package/lib/service/skills/SignalCollector.js +26 -19
- package/lib/service/snippet/codecs/VSCodeCodec.js +1 -1
- package/lib/shared/FieldSpec.js +1 -1
- package/lib/shared/StyleGuide.js +1 -1
- package/package.json +4 -1
- package/resources/native-ui/screenshot.swift +228 -0
- package/dashboard/dist/assets/index-D5jiDBQG.css +0 -1
- package/dashboard/dist/assets/index-e5OKj-Ni.js +0 -128
- package/lib/core/discovery/SpmDiscoverer.js +0 -5
- package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +0 -750
- package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +0 -277
- package/lib/http/routes/spm.js +0 -5
- package/lib/infrastructure/external/XcodeAutomation.js +0 -15
- package/lib/service/chat/ChatAgent.js +0 -1602
- package/lib/service/chat/Memory.js +0 -161
- package/lib/service/chat/ProducerAgent.js +0 -431
- package/lib/service/chat/ReasoningTrace.js +0 -523
- package/lib/service/chat/TaskPipeline.js +0 -357
- package/lib/service/chat/WorkingMemory.js +0 -359
- package/lib/service/chat/memory/PersistentMemory.js +0 -450
- package/lib/service/chat/tools/ai-analysis.js +0 -267
- package/lib/service/chat/tools/knowledge-graph.js +0 -234
- package/lib/service/chat/tools.js +0 -18
- package/lib/service/snippet/PlaceholderConverter.js +0 -5
- package/lib/service/snippet/codecs/XcodeCodec.js +0 -5
- /package/lib/service/{chat → agent}/ConversationStore.js +0 -0
- /package/lib/service/{chat → agent}/memory/ActiveContext.js +0 -0
- /package/lib/service/{chat → agent}/tools/_shared.js +0 -0
- /package/lib/service/{chat → agent}/tools/ast-graph.js +0 -0
- /package/lib/service/{chat → agent}/tools/lifecycle.js +0 -0
- /package/lib/service/{chat → agent}/tools/project-access.js +0 -0
- /package/lib/service/{chat → agent}/tools/query.js +0 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capabilities — 可组合的 Agent 技能模块
|
|
3
|
+
*
|
|
4
|
+
* 核心思想: Agent 的能力不由"类型"决定,而由加载了哪些 Capability 模块决定。
|
|
5
|
+
*
|
|
6
|
+
* 每个 Capability 提供:
|
|
7
|
+
* 1. promptFragment — 系统提示词片段 (告诉 LLM 它能做什么)
|
|
8
|
+
* 2. tools — 工具白名单 (该能力需要哪些工具)
|
|
9
|
+
* 3. hooks — 生命周期钩子 (可选的前/后处理)
|
|
10
|
+
*
|
|
11
|
+
* 组合示例:
|
|
12
|
+
* - 用户聊天 = Conversation + CodeAnalysis
|
|
13
|
+
* - 冷启动分析 = CodeAnalysis + KnowledgeProduction
|
|
14
|
+
* - 飞书远程执行 = Conversation + SystemInteraction
|
|
15
|
+
* - 智能全能 = Conversation + CodeAnalysis + KnowledgeProduction + SystemInteraction
|
|
16
|
+
*
|
|
17
|
+
* 这就是为什么"飞书聊天"和"前端聊天"是同一个概念:
|
|
18
|
+
* 它们加载相同的 Capability,只是到达方式 (Transport) 不同。
|
|
19
|
+
*
|
|
20
|
+
* @module capabilities
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import fs from 'node:fs';
|
|
24
|
+
import path from 'node:path';
|
|
25
|
+
import { fileURLToPath } from 'node:url';
|
|
26
|
+
|
|
27
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
|
|
29
|
+
// ─── Base Capability ─────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Capability 基类 — 所有技能模块的抽象接口
|
|
33
|
+
*/
|
|
34
|
+
export class Capability {
|
|
35
|
+
/** @type {string} 能力名称 */
|
|
36
|
+
get name() { throw new Error('Subclass must implement name'); }
|
|
37
|
+
|
|
38
|
+
/** @type {string} 系统提示词片段 */
|
|
39
|
+
get promptFragment() { throw new Error('Subclass must implement promptFragment'); }
|
|
40
|
+
|
|
41
|
+
/** @type {string[]} 工具白名单 */
|
|
42
|
+
get tools() { return []; }
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 构建 prompt 时调用,可注入动态上下文
|
|
46
|
+
* @param {Object} context — { message, memory, projectBriefing, lang, ... }
|
|
47
|
+
* @returns {string|null} 额外的 prompt 片段
|
|
48
|
+
*/
|
|
49
|
+
buildContext(_context) { return null; }
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 每轮 ReAct 步骤前的钩子
|
|
53
|
+
* @param {Object} stepState — 当前步骤状态
|
|
54
|
+
*/
|
|
55
|
+
onBeforeStep(_stepState) {}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 每轮 ReAct 步骤后的钩子
|
|
59
|
+
* @param {Object} stepResult — 步骤结果
|
|
60
|
+
*/
|
|
61
|
+
onAfterStep(_stepResult) {}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ─── Conversation — 对话能力 ─────────────────────
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 对话能力: 多轮问答、知识检索、记忆管理
|
|
68
|
+
*
|
|
69
|
+
* 核心工具: 知识库搜索、语义搜索
|
|
70
|
+
* 用于: 用户聊天、飞书聊天、任何需要对话的场景
|
|
71
|
+
*/
|
|
72
|
+
export class Conversation extends Capability {
|
|
73
|
+
#memoryCoordinator;
|
|
74
|
+
#soulContent;
|
|
75
|
+
#projectBriefing;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {Object} [opts]
|
|
79
|
+
* @param {Object} [opts.memoryCoordinator] — MemoryCoordinator 实例
|
|
80
|
+
* @param {string} [opts.soulPath] — SOUL.md 路径
|
|
81
|
+
* @param {string} [opts.projectBriefing] — 项目概况文本
|
|
82
|
+
*/
|
|
83
|
+
constructor(opts = {}) {
|
|
84
|
+
super();
|
|
85
|
+
this.#memoryCoordinator = opts.memoryCoordinator || null;
|
|
86
|
+
this.#projectBriefing = opts.projectBriefing || null;
|
|
87
|
+
|
|
88
|
+
// 加载 SOUL.md (人格定义)
|
|
89
|
+
const soulPath = opts.soulPath || path.resolve(__dirname, '../../..', 'SOUL.md');
|
|
90
|
+
try {
|
|
91
|
+
this.#soulContent = fs.existsSync(soulPath) ? fs.readFileSync(soulPath, 'utf-8').trim() : null;
|
|
92
|
+
} catch { this.#soulContent = null; }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get name() { return 'conversation'; }
|
|
96
|
+
|
|
97
|
+
get promptFragment() {
|
|
98
|
+
return `## 对话能力
|
|
99
|
+
你是 AutoSnippet 知识管理助手。
|
|
100
|
+
|
|
101
|
+
行为规则:
|
|
102
|
+
1. 回答问题时优先从知识库搜索相关知识
|
|
103
|
+
2. 用户要求编辑/创建知识时,通过工具完成
|
|
104
|
+
3. 每轮至少调用一个工具获取信息(除非纯闲聊)
|
|
105
|
+
4. 保持对话连贯性,引用之前的上下文`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get tools() {
|
|
109
|
+
return [
|
|
110
|
+
// 知识检索 (内部 ToolRegistry 名称)
|
|
111
|
+
'search_knowledge',
|
|
112
|
+
'search_recipes',
|
|
113
|
+
'get_recipe_detail',
|
|
114
|
+
'get_related_recipes',
|
|
115
|
+
// 语义搜索
|
|
116
|
+
'semantic_search_code',
|
|
117
|
+
// 知识管理
|
|
118
|
+
'submit_knowledge',
|
|
119
|
+
'knowledge_overview',
|
|
120
|
+
// 项目统计
|
|
121
|
+
'get_project_stats',
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
buildContext(context) {
|
|
126
|
+
const parts = [];
|
|
127
|
+
|
|
128
|
+
// SOUL.md 人格注入
|
|
129
|
+
if (this.#soulContent) {
|
|
130
|
+
parts.push(this.#soulContent);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 项目概况 (优先用 context 传入的, 回退到构造器注入的)
|
|
134
|
+
const briefing = context.projectBriefing || this.#projectBriefing;
|
|
135
|
+
if (briefing) {
|
|
136
|
+
parts.push(`## 项目概况\n${briefing}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 记忆注入
|
|
140
|
+
if (this.#memoryCoordinator) {
|
|
141
|
+
try {
|
|
142
|
+
const memoryContext = this.#memoryCoordinator.buildPromptInjection(
|
|
143
|
+
context.memoryMode || 'user'
|
|
144
|
+
);
|
|
145
|
+
if (memoryContext) parts.push(`## 记忆上下文\n${memoryContext}`);
|
|
146
|
+
} catch { /* non-critical */ }
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return parts.length > 0 ? parts.join('\n\n') : null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
onAfterStep(stepResult) {
|
|
153
|
+
// 缓存工具结果到记忆
|
|
154
|
+
if (this.#memoryCoordinator && stepResult.toolCalls?.length > 0) {
|
|
155
|
+
try {
|
|
156
|
+
for (const tc of stepResult.toolCalls) {
|
|
157
|
+
this.#memoryCoordinator.cacheToolResult?.(tc.tool, tc.args, tc.result);
|
|
158
|
+
}
|
|
159
|
+
} catch { /* non-critical */ }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ─── CodeAnalysis — 代码分析能力 ─────────────────
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 代码分析能力: AST 解析、代码搜索、结构理解
|
|
168
|
+
*
|
|
169
|
+
* 核心工具: AST 工具集 + 文件读取 + 代码搜索
|
|
170
|
+
* 用于: 用户聊天中的代码问题、冷启动分析、目标扫描
|
|
171
|
+
*/
|
|
172
|
+
export class CodeAnalysis extends Capability {
|
|
173
|
+
|
|
174
|
+
get name() { return 'code_analysis'; }
|
|
175
|
+
|
|
176
|
+
get promptFragment() {
|
|
177
|
+
return `## 代码分析能力
|
|
178
|
+
你是高级软件架构师,可以深度分析代码结构。
|
|
179
|
+
|
|
180
|
+
分析策略:
|
|
181
|
+
| 阶段 | 目标 |
|
|
182
|
+
|------|------|
|
|
183
|
+
| 全局扫描 | get_project_overview + list_project_structure |
|
|
184
|
+
| 结构化探索 | get_class_hierarchy / search_project_code 批量搜索 |
|
|
185
|
+
| 深度验证 | read_project_file 阅读关键实现 |
|
|
186
|
+
| 输出总结 | 停止工具调用,输出分析 |
|
|
187
|
+
|
|
188
|
+
关键规则:
|
|
189
|
+
- 批量搜索: search_project_code({ patterns: [...] })
|
|
190
|
+
- 批量读文件: read_project_file({ filePaths: [...] })
|
|
191
|
+
- 不要重复搜索相同关键词
|
|
192
|
+
- 输出时包含具体文件路径和代码位置`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
get tools() {
|
|
196
|
+
return [
|
|
197
|
+
// AST 结构
|
|
198
|
+
'get_project_overview', 'get_class_hierarchy', 'get_class_info',
|
|
199
|
+
'get_protocol_info', 'get_method_overrides', 'get_category_map',
|
|
200
|
+
// 搜索与读取
|
|
201
|
+
'search_project_code', 'read_project_file', 'list_project_structure',
|
|
202
|
+
'get_file_summary', 'semantic_search_code',
|
|
203
|
+
// 图谱
|
|
204
|
+
'query_code_graph',
|
|
205
|
+
// 探索追踪
|
|
206
|
+
'get_previous_analysis', 'note_finding', 'get_previous_evidence',
|
|
207
|
+
];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ─── KnowledgeProduction — 知识生产能力 ─────────
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* 知识生产能力: 将分析结果转化为结构化知识候选
|
|
215
|
+
*
|
|
216
|
+
* 核心工具: 知识提交 + Guard 检查
|
|
217
|
+
* 用于: 冷启动提交、扫描后提交、用户主动创建知识
|
|
218
|
+
*/
|
|
219
|
+
export class KnowledgeProduction extends Capability {
|
|
220
|
+
|
|
221
|
+
get name() { return 'knowledge_production'; }
|
|
222
|
+
|
|
223
|
+
get promptFragment() {
|
|
224
|
+
return `## 知识生产能力
|
|
225
|
+
你是知识管理专家,将代码分析转化为结构化知识候选。
|
|
226
|
+
|
|
227
|
+
每个候选必须有:
|
|
228
|
+
1. 清晰的标题 (使用项目真实类名/模块名)
|
|
229
|
+
2. 项目特写风格的正文 (content.markdown)
|
|
230
|
+
3. 相关文件路径
|
|
231
|
+
4. 正确的 kind (rule / pattern / fact)
|
|
232
|
+
5. 完整的 Cursor 交付字段
|
|
233
|
+
|
|
234
|
+
工作流:
|
|
235
|
+
1. 识别分析中的知识点
|
|
236
|
+
2. read_project_file 获取代码片段 (如需)
|
|
237
|
+
3. submit_knowledge 或 submit_with_check 提交
|
|
238
|
+
4. 提交优先于完美 — 文件读取失败时用已有信息直接提交`;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
get tools() {
|
|
242
|
+
return [
|
|
243
|
+
'submit_knowledge', 'submit_with_check',
|
|
244
|
+
'read_project_file', // 获取代码片段用于知识正文
|
|
245
|
+
'guard_check_code', // 提交前质量检查
|
|
246
|
+
'validate_candidate', // 校验候选质量
|
|
247
|
+
];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ─── SystemInteraction — 系统交互能力 ────────────
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* 系统交互能力: 终端命令执行、文件写入、环境探测、项目探索
|
|
255
|
+
*
|
|
256
|
+
* 核心工具: 终端执行 + 文件写入 + 环境信息 + 项目读取
|
|
257
|
+
* 用于: 飞书远程执行、自动化脚本、任何需要操作本地系统的场景
|
|
258
|
+
*
|
|
259
|
+
* ⚙️ 安全设计 (3 层防护):
|
|
260
|
+
* 1. 工具层: run_safe_command / write_project_file 内置硬编码黑名单
|
|
261
|
+
* 2. Policy 层: SafetyPolicy.checkCommand() / checkFilePath() 动态拦截
|
|
262
|
+
* 3. Runtime 层: reactLoop 工具执行前自动调用 PolicyEngine.validateToolCall()
|
|
263
|
+
*
|
|
264
|
+
* ⚠️ 该能力通常搭配 SafetyPolicy 使用
|
|
265
|
+
*/
|
|
266
|
+
export class SystemInteraction extends Capability {
|
|
267
|
+
#projectRoot;
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @param {Object} [opts]
|
|
271
|
+
* @param {string} [opts.projectRoot] — 项目根目录 (限制操作范围)
|
|
272
|
+
*/
|
|
273
|
+
constructor(opts = {}) {
|
|
274
|
+
super();
|
|
275
|
+
this.#projectRoot = opts.projectRoot || process.cwd();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
get name() { return 'system_interaction'; }
|
|
279
|
+
|
|
280
|
+
get promptFragment() {
|
|
281
|
+
return `## 系统交互能力
|
|
282
|
+
你可以在本地环境中执行终端命令、写入文件、探索项目。
|
|
283
|
+
|
|
284
|
+
能力:
|
|
285
|
+
1. **终端命令**: run_safe_command 执行 shell 命令 (git, npm, ls, grep 等)
|
|
286
|
+
2. **文件写入**: write_project_file 创建/覆盖项目内文件
|
|
287
|
+
3. **环境探测**: get_environment_info 获取 OS/Node/Git/项目信息
|
|
288
|
+
4. **项目探索**: 搜索代码、读取文件、列出目录结构
|
|
289
|
+
|
|
290
|
+
安全规则:
|
|
291
|
+
- 所有操作限制在项目目录 (${this.#projectRoot}) 内
|
|
292
|
+
- 危险命令 (sudo, rm -rf /, shutdown 等) 被自动拦截
|
|
293
|
+
- 受保护文件 (.git/, node_modules/, .env) 不可写入
|
|
294
|
+
- SafetyPolicy 可进一步约束可执行命令和可访问路径
|
|
295
|
+
|
|
296
|
+
最佳实践:
|
|
297
|
+
- 执行命令前先 get_environment_info 了解环境
|
|
298
|
+
- git 命令用于查看状态、diff、log,不建议执行 push/commit
|
|
299
|
+
- 需要管道/重定向时用 sh -c "命令" 包装
|
|
300
|
+
|
|
301
|
+
项目路径: ${this.#projectRoot}`;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
get tools() {
|
|
305
|
+
return [
|
|
306
|
+
// 终端执行
|
|
307
|
+
'run_safe_command',
|
|
308
|
+
// 文件写入
|
|
309
|
+
'write_project_file',
|
|
310
|
+
// 环境探测
|
|
311
|
+
'get_environment_info',
|
|
312
|
+
// 项目探索 (只读)
|
|
313
|
+
'search_project_code',
|
|
314
|
+
'read_project_file',
|
|
315
|
+
'list_project_structure',
|
|
316
|
+
'get_project_overview',
|
|
317
|
+
'get_file_summary',
|
|
318
|
+
];
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// ─── ScanProduction — 扫描知识生产能力 ─────────
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* 扫描知识生产能力: 将分析结果转化为标准 Recipe
|
|
326
|
+
*
|
|
327
|
+
* 与冷启动 KnowledgeProduction 的区别:
|
|
328
|
+
* - 使用 collect_scan_recipe 工具(内存收集,不入库)
|
|
329
|
+
* - 冷启动用 submit_knowledge(直接入库)
|
|
330
|
+
* - 字段 schema 完全一致 — 产出质量相同
|
|
331
|
+
*
|
|
332
|
+
* 用于: scanKnowledge produce 阶段
|
|
333
|
+
*/
|
|
334
|
+
export class ScanProduction extends Capability {
|
|
335
|
+
|
|
336
|
+
get name() { return 'scan_production'; }
|
|
337
|
+
|
|
338
|
+
get promptFragment() {
|
|
339
|
+
return `## 知识生产能力
|
|
340
|
+
你是知识管理专家,将代码分析转化为结构化知识候选。
|
|
341
|
+
|
|
342
|
+
每个候选必须有:
|
|
343
|
+
1. 清晰的标题 (使用项目真实类名/模块名)
|
|
344
|
+
2. 项目特写风格的正文 (content.markdown ≥200字)
|
|
345
|
+
3. 设计原理说明 (content.rationale)
|
|
346
|
+
4. 相关文件路径 (reasoning.sources)
|
|
347
|
+
5. 正确的 kind (rule / pattern / fact)
|
|
348
|
+
6. 完整的 Cursor 交付字段 (trigger, doClause, whenClause 等)
|
|
349
|
+
|
|
350
|
+
工作流:
|
|
351
|
+
1. 识别分析中的知识点
|
|
352
|
+
2. read_project_file 获取代码片段 (如需)
|
|
353
|
+
3. collect_scan_recipe 逐个提交每个知识点
|
|
354
|
+
4. 每个独立模式/发现单独提交 — 不要合并`;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
get tools() {
|
|
358
|
+
return [
|
|
359
|
+
'collect_scan_recipe', // 扫描专用 Recipe 收集
|
|
360
|
+
'read_project_file', // 获取代码片段
|
|
361
|
+
];
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// ─── Capability 注册表 ─────────────────────────
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* 所有内置 Capability 的注册表
|
|
369
|
+
*
|
|
370
|
+
* 用于按名称查找和实例化:
|
|
371
|
+
* const cap = CapabilityRegistry.create('conversation', { memoryCoordinator });
|
|
372
|
+
*/
|
|
373
|
+
export const CapabilityRegistry = {
|
|
374
|
+
/** @type {Map<string, typeof Capability>} */
|
|
375
|
+
_registry: new Map([
|
|
376
|
+
['conversation', Conversation],
|
|
377
|
+
['code_analysis', CodeAnalysis],
|
|
378
|
+
['knowledge_production', KnowledgeProduction],
|
|
379
|
+
['scan_production', ScanProduction],
|
|
380
|
+
['system_interaction', SystemInteraction],
|
|
381
|
+
]),
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* 按名称创建 Capability 实例
|
|
385
|
+
* @param {string} name
|
|
386
|
+
* @param {Object} [opts]
|
|
387
|
+
* @returns {Capability}
|
|
388
|
+
*/
|
|
389
|
+
create(name, opts = {}) {
|
|
390
|
+
const Cls = this._registry.get(name);
|
|
391
|
+
if (!Cls) throw new Error(`Unknown capability: ${name}`);
|
|
392
|
+
return new Cls(opts);
|
|
393
|
+
},
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* 注册自定义 Capability
|
|
397
|
+
* @param {string} name
|
|
398
|
+
* @param {typeof Capability} cls
|
|
399
|
+
*/
|
|
400
|
+
register(name, cls) {
|
|
401
|
+
this._registry.set(name, cls);
|
|
402
|
+
},
|
|
403
|
+
|
|
404
|
+
/** 所有注册名 */
|
|
405
|
+
get names() { return [...this._registry.keys()]; },
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
export default { Capability, Conversation, CodeAnalysis, KnowledgeProduction, SystemInteraction, CapabilityRegistry };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ContextWindow —
|
|
2
|
+
* ContextWindow — Agent 的上下文窗口管理器
|
|
3
3
|
*
|
|
4
4
|
* 业界最佳实践:
|
|
5
5
|
* - OpenAI Compaction: 阈值触发自动压缩,保留关键上下文
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
* @module ContextWindow
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import Logger from '
|
|
25
|
-
import { estimateTokensFast } from '
|
|
24
|
+
import Logger from '../../../infrastructure/logging/Logger.js';
|
|
25
|
+
import { estimateTokensFast } from '../../../shared/token-utils.js';
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* 一组相关消息的原子单元:
|
|
@@ -439,18 +439,43 @@ export class ContextWindow {
|
|
|
439
439
|
resetToPromptOnly() {
|
|
440
440
|
if (this.#messages.length > 1) {
|
|
441
441
|
// 提取所有已提交候选
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
442
|
+
this.#extractCompactedSubmits(1);
|
|
443
|
+
this.#messages.length = 1;
|
|
444
|
+
this.#compactionLog.push(`RESET: cleared all messages except prompt`);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Pipeline 阶段隔离 — 清空全部消息。
|
|
450
|
+
*
|
|
451
|
+
* 用于 PipelineStrategy 在阶段间重置 ContextWindow:
|
|
452
|
+
* analyze → (reset) → produce
|
|
453
|
+
*
|
|
454
|
+
* reactLoop 会将新阶段的 prompt 追加为 messages[0],
|
|
455
|
+
* systemPrompt 通过 chatWithTools 参数独立传递,不受影响。
|
|
456
|
+
*
|
|
457
|
+
* 保留 compactedSubmits 以支持跨阶段提交去重。
|
|
458
|
+
*/
|
|
459
|
+
resetForNewStage() {
|
|
460
|
+
this.#extractCompactedSubmits(0);
|
|
461
|
+
this.#messages = [];
|
|
462
|
+
this.#compactionLog.push('RESET_STAGE: cleared all messages for new pipeline stage');
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* 从消息中提取已提交候选到 compactedSubmits
|
|
467
|
+
* @param {number} fromIdx — 从哪个索引开始扫描
|
|
468
|
+
*/
|
|
469
|
+
#extractCompactedSubmits(fromIdx) {
|
|
470
|
+
for (let i = fromIdx; i < this.#messages.length; i++) {
|
|
471
|
+
const m = this.#messages[i];
|
|
472
|
+
if (m.role === 'assistant' && m.toolCalls) {
|
|
473
|
+
for (const tc of m.toolCalls) {
|
|
474
|
+
if (tc.name === 'submit_knowledge' || tc.name === 'submit_with_check') {
|
|
475
|
+
this.#compactedSubmits.add(tc.args?.title || tc.args?.category || 'untitled');
|
|
449
476
|
}
|
|
450
477
|
}
|
|
451
478
|
}
|
|
452
|
-
this.#messages.length = 1;
|
|
453
|
-
this.#compactionLog.push(`RESET: cleared all messages except prompt`);
|
|
454
479
|
}
|
|
455
480
|
}
|
|
456
481
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 合并了三个原本各自为政的系统:
|
|
5
5
|
* 1. PhaseRouter (ContextWindow.js) — 阶段状态机
|
|
6
|
-
* 2. 探索进度追踪 (
|
|
6
|
+
* 2. 探索进度追踪 (原内联逻辑) — 信息增量检测
|
|
7
7
|
* 3. ReasoningLayer 行为控制部分 — 反思/规划/停滞 nudge
|
|
8
8
|
*
|
|
9
9
|
* 职责:
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* @module ExplorationTracker
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import Logger from '
|
|
24
|
+
import Logger from '../../../infrastructure/logging/Logger.js';
|
|
25
25
|
|
|
26
26
|
// ─── 常量 ──────────────────────────────────────────────
|
|
27
27
|
|
|
@@ -43,7 +43,7 @@ const DEFAULT_CONVERGENCE_STALE_THRESHOLD = 3;
|
|
|
43
43
|
// ─── 内置策略 ────────────────────────────────────────────
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* Bootstrap
|
|
46
|
+
* Bootstrap 策略(有 submit 阶段)
|
|
47
47
|
* @param {boolean} isSkillOnly — skill-only 维度跳过 PRODUCE 阶段
|
|
48
48
|
* @returns {object} 策略配置
|
|
49
49
|
*/
|
|
@@ -234,7 +234,18 @@ export class ExplorationTracker {
|
|
|
234
234
|
*/
|
|
235
235
|
constructor(strategy, budget) {
|
|
236
236
|
this.#strategy = strategy;
|
|
237
|
-
|
|
237
|
+
// 合并默认值: PipelineStrategy 创建 per-stage tracker 时,
|
|
238
|
+
// budget 可能仅含 maxIterations/temperature (来自 stage.budget),
|
|
239
|
+
// 需要补全 tracker 所需的 searchBudget、maxSubmits 等字段。
|
|
240
|
+
this.#budget = {
|
|
241
|
+
maxIterations: 24,
|
|
242
|
+
searchBudget: 18,
|
|
243
|
+
searchBudgetGrace: 10,
|
|
244
|
+
maxSubmits: 10,
|
|
245
|
+
softSubmitLimit: 8,
|
|
246
|
+
idleRoundsToExit: 3,
|
|
247
|
+
...budget,
|
|
248
|
+
};
|
|
238
249
|
this.#phase = strategy.phases[0];
|
|
239
250
|
this.#logger = Logger.getInstance();
|
|
240
251
|
}
|
|
@@ -243,7 +254,7 @@ export class ExplorationTracker {
|
|
|
243
254
|
|
|
244
255
|
/**
|
|
245
256
|
* 根据调用参数解析应使用的策略
|
|
246
|
-
* @param {object} opts —
|
|
257
|
+
* @param {object} opts — AgentRuntime execute 的选项
|
|
247
258
|
* @param {object} budget — 预算配置
|
|
248
259
|
* @returns {ExplorationTracker|null} — User 模式返回 null
|
|
249
260
|
*/
|
|
@@ -336,7 +347,7 @@ export class ExplorationTracker {
|
|
|
336
347
|
* 4. reflection — 周期反思 / 停滞反思
|
|
337
348
|
* 5. planning — 首轮规划 / 偏差重规划
|
|
338
349
|
*
|
|
339
|
-
* @param {import('
|
|
350
|
+
* @param {import('../memory/ActiveContext.js').ActiveContext} trace — 推理链(供反思用)
|
|
340
351
|
* @returns {{ type: string, text: string }|null}
|
|
341
352
|
*/
|
|
342
353
|
getNudge(trace) {
|
|
@@ -459,7 +470,7 @@ export class ExplorationTracker {
|
|
|
459
470
|
|
|
460
471
|
/**
|
|
461
472
|
* 记录一次工具调用结果,更新内部指标
|
|
462
|
-
*
|
|
473
|
+
* 替代原内联的 ~120 行 if-else 逻辑
|
|
463
474
|
*
|
|
464
475
|
* @param {string} toolName
|
|
465
476
|
* @param {object} args
|
|
@@ -470,8 +481,8 @@ export class ExplorationTracker {
|
|
|
470
481
|
this.#metrics.totalToolCalls++;
|
|
471
482
|
const isNew = this.#detectNewInfo(toolName, args, result);
|
|
472
483
|
|
|
473
|
-
// Submit
|
|
474
|
-
if (toolName === 'submit_knowledge' || toolName === 'submit_with_check') {
|
|
484
|
+
// Submit 追踪(只记成功提交)— 含 scan 阶段的 collect_scan_recipe
|
|
485
|
+
if (toolName === 'submit_knowledge' || toolName === 'submit_with_check' || toolName === 'collect_scan_recipe') {
|
|
475
486
|
const status = typeof result === 'object' ? result?.status : 'ok';
|
|
476
487
|
const isRejected = status === 'rejected';
|
|
477
488
|
const isError = status === 'error';
|
|
@@ -662,7 +673,7 @@ export class ExplorationTracker {
|
|
|
662
673
|
|
|
663
674
|
/**
|
|
664
675
|
* 检测工具调用是否产生了新信息
|
|
665
|
-
*
|
|
676
|
+
* 合并了原内联的探索追踪 + ReasoningLayer.buildObservationMeta 的逻辑
|
|
666
677
|
*
|
|
667
678
|
* @param {string} toolName
|
|
668
679
|
* @param {object} args
|
|
@@ -961,7 +972,7 @@ export class ExplorationTracker {
|
|
|
961
972
|
|
|
962
973
|
/**
|
|
963
974
|
* 检查是否需要触发反思 + 生成反思 nudge
|
|
964
|
-
* @param {import('
|
|
975
|
+
* @param {import('../memory/ActiveContext.js').ActiveContext} trace
|
|
965
976
|
* @returns {{ type: string, text: string }|null}
|
|
966
977
|
* @private
|
|
967
978
|
*/
|
|
@@ -1039,7 +1050,7 @@ export class ExplorationTracker {
|
|
|
1039
1050
|
|
|
1040
1051
|
/**
|
|
1041
1052
|
* 检查是否需要触发规划 + 生成规划 nudge
|
|
1042
|
-
* @param {import('
|
|
1053
|
+
* @param {import('../memory/ActiveContext.js').ActiveContext} trace
|
|
1043
1054
|
* @returns {{ type: string, text: string }|null}
|
|
1044
1055
|
* @private
|
|
1045
1056
|
*/
|
|
@@ -1140,7 +1151,7 @@ export class ExplorationTracker {
|
|
|
1140
1151
|
* 更新计划进度(从 ReasoningLayer 迁入)
|
|
1141
1152
|
* 将本轮工具调用与 plan 步骤进行模糊匹配
|
|
1142
1153
|
*
|
|
1143
|
-
* @param {import('
|
|
1154
|
+
* @param {import('../memory/ActiveContext.js').ActiveContext} trace
|
|
1144
1155
|
*/
|
|
1145
1156
|
updatePlanProgress(trace) {
|
|
1146
1157
|
if (!this.#strategy.enablePlanning) return;
|
|
@@ -1242,7 +1253,7 @@ export class ExplorationTracker {
|
|
|
1242
1253
|
|
|
1243
1254
|
/**
|
|
1244
1255
|
* 推理质量评分
|
|
1245
|
-
* @param {import('
|
|
1256
|
+
* @param {import('../memory/ActiveContext.js').ActiveContext} trace
|
|
1246
1257
|
* @returns {{ score: number, breakdown: object }}
|
|
1247
1258
|
*/
|
|
1248
1259
|
getQualityMetrics(trace) {
|