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.
Files changed (113) hide show
  1. package/bin/cli.js +6 -5
  2. package/dashboard/dist/assets/index-BTAsOZv2.js +128 -0
  3. package/dashboard/dist/assets/index-C_72Ct98.css +1 -0
  4. package/dashboard/dist/index.html +2 -2
  5. package/lib/cli/AiScanService.js +23 -26
  6. package/lib/cli/SetupService.js +1 -1
  7. package/lib/core/AstAnalyzer.js +1 -1
  8. package/lib/core/discovery/index.js +2 -2
  9. package/lib/external/ai/AiProvider.js +66 -172
  10. package/lib/external/ai/providers/GoogleGeminiProvider.js +23 -1
  11. package/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +1 -1
  12. package/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.js +3 -3
  13. package/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +1 -1
  14. package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +1 -1
  15. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +8 -8
  16. package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +1 -1
  17. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +287 -204
  18. package/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +7 -6
  19. package/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.js +1 -1
  20. package/lib/external/mcp/handlers/bootstrap-internal.js +2 -2
  21. package/lib/external/mcp/handlers/dimension-complete-external.js +6 -6
  22. package/lib/http/HttpServer.js +1 -1
  23. package/lib/http/middleware/requestLogger.js +1 -0
  24. package/lib/http/routes/ai.js +240 -35
  25. package/lib/http/routes/candidates.js +2 -3
  26. package/lib/http/routes/extract.js +13 -11
  27. package/lib/http/routes/modules.js +2 -2
  28. package/lib/http/routes/recipes.js +9 -5
  29. package/lib/http/routes/remote.js +134 -255
  30. package/lib/http/routes/violations.js +0 -54
  31. package/lib/http/utils/sse-sessions.js +1 -1
  32. package/lib/infrastructure/logging/Logger.js +5 -4
  33. package/lib/infrastructure/monitoring/PerformanceMonitor.js +3 -2
  34. package/lib/injection/ServiceContainer.js +64 -17
  35. package/lib/platform/ScreenCaptureService.js +177 -0
  36. package/lib/platform/ios/routes/spm.js +2 -2
  37. package/lib/service/agent/AgentEventBus.js +207 -0
  38. package/lib/service/agent/AgentFactory.js +490 -0
  39. package/lib/service/agent/AgentMessage.js +240 -0
  40. package/lib/service/agent/AgentRouter.js +228 -0
  41. package/lib/service/agent/AgentRuntime.js +1016 -0
  42. package/lib/service/agent/AgentState.js +217 -0
  43. package/lib/service/agent/IntentClassifier.js +331 -0
  44. package/lib/service/agent/LarkTransport.js +389 -0
  45. package/lib/service/agent/capabilities.js +408 -0
  46. package/lib/service/{chat → agent/context}/ContextWindow.js +37 -12
  47. package/lib/service/{chat → agent/context}/ExplorationTracker.js +25 -14
  48. package/lib/service/{chat → agent/core}/ChatAgentPrompts.js +1 -1
  49. package/lib/service/agent/core/LoopContext.js +170 -0
  50. package/lib/service/agent/core/MessageAdapter.js +223 -0
  51. package/lib/service/agent/core/ToolExecutionPipeline.js +376 -0
  52. package/lib/service/{chat → agent/domain}/ChatAgentTasks.js +19 -98
  53. package/lib/service/{chat → agent/domain}/EpisodicConsolidator.js +7 -7
  54. package/lib/service/{chat → agent/domain}/EvidenceCollector.js +4 -2
  55. package/lib/service/{chat/AnalystAgent.js → agent/domain/insight-analyst.js} +37 -172
  56. package/lib/service/{chat/HandoffProtocol.js → agent/domain/insight-gate.js} +85 -135
  57. package/lib/service/agent/domain/insight-producer.js +267 -0
  58. package/lib/service/agent/domain/scan-prompts.js +105 -0
  59. package/lib/service/agent/forced-summary.js +266 -0
  60. package/lib/service/agent/index.js +91 -0
  61. package/lib/service/{chat → agent}/memory/MemoryCoordinator.js +7 -7
  62. package/lib/service/{chat/ProjectSemanticMemory.js → agent/memory/PersistentMemory.js} +359 -89
  63. package/lib/service/{chat → agent}/memory/SessionStore.js +1 -1
  64. package/lib/service/{chat → agent}/memory/index.js +1 -1
  65. package/lib/service/agent/policies.js +442 -0
  66. package/lib/service/agent/presets.js +303 -0
  67. package/lib/service/agent/strategies.js +717 -0
  68. package/lib/service/{chat → agent/tools}/ToolRegistry.js +3 -3
  69. package/lib/service/agent/tools/ai-analysis.js +75 -0
  70. package/lib/service/{chat → agent}/tools/composite.js +2 -1
  71. package/lib/service/{chat → agent}/tools/guard.js +1 -121
  72. package/lib/service/{chat → agent}/tools/index.js +27 -21
  73. package/lib/service/{chat → agent}/tools/infrastructure.js +1 -1
  74. package/lib/service/agent/tools/knowledge-graph.js +112 -0
  75. package/lib/service/agent/tools/scan-recipe.js +189 -0
  76. package/lib/service/agent/tools/system-interaction.js +476 -0
  77. package/lib/service/automation/DirectiveDetector.js +0 -1
  78. package/lib/service/automation/FileWatcher.js +0 -8
  79. package/lib/service/automation/handlers/CreateHandler.js +7 -3
  80. package/lib/service/automation/handlers/DraftHandler.js +7 -6
  81. package/lib/service/module/ModuleService.js +40 -73
  82. package/lib/service/skills/SignalCollector.js +26 -19
  83. package/lib/service/snippet/codecs/VSCodeCodec.js +1 -1
  84. package/lib/shared/FieldSpec.js +1 -1
  85. package/lib/shared/StyleGuide.js +1 -1
  86. package/package.json +4 -1
  87. package/resources/native-ui/screenshot.swift +228 -0
  88. package/dashboard/dist/assets/index-D5jiDBQG.css +0 -1
  89. package/dashboard/dist/assets/index-e5OKj-Ni.js +0 -128
  90. package/lib/core/discovery/SpmDiscoverer.js +0 -5
  91. package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +0 -750
  92. package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +0 -277
  93. package/lib/http/routes/spm.js +0 -5
  94. package/lib/infrastructure/external/XcodeAutomation.js +0 -15
  95. package/lib/service/chat/ChatAgent.js +0 -1602
  96. package/lib/service/chat/Memory.js +0 -161
  97. package/lib/service/chat/ProducerAgent.js +0 -431
  98. package/lib/service/chat/ReasoningTrace.js +0 -523
  99. package/lib/service/chat/TaskPipeline.js +0 -357
  100. package/lib/service/chat/WorkingMemory.js +0 -359
  101. package/lib/service/chat/memory/PersistentMemory.js +0 -450
  102. package/lib/service/chat/tools/ai-analysis.js +0 -267
  103. package/lib/service/chat/tools/knowledge-graph.js +0 -234
  104. package/lib/service/chat/tools.js +0 -18
  105. package/lib/service/snippet/PlaceholderConverter.js +0 -5
  106. package/lib/service/snippet/codecs/XcodeCodec.js +0 -5
  107. /package/lib/service/{chat → agent}/ConversationStore.js +0 -0
  108. /package/lib/service/{chat → agent}/memory/ActiveContext.js +0 -0
  109. /package/lib/service/{chat → agent}/tools/_shared.js +0 -0
  110. /package/lib/service/{chat → agent}/tools/ast-graph.js +0 -0
  111. /package/lib/service/{chat → agent}/tools/lifecycle.js +0 -0
  112. /package/lib/service/{chat → agent}/tools/project-access.js +0 -0
  113. /package/lib/service/{chat → agent}/tools/query.js +0 -0
@@ -0,0 +1,376 @@
1
+ /**
2
+ * ToolExecutionPipeline — 工具执行的中间件管道
3
+ *
4
+ * 将 reactLoop 中 ~120 行的工具执行逻辑拆分为独立中间件:
5
+ * before → execute → after
6
+ *
7
+ * 每个中间件负责一个横切关注点:
8
+ * 1. EventBusPublisher — 事件发布
9
+ * 2. ProgressEmitter — 进度回调
10
+ * 3. SafetyGate — SafetyPolicy 安全拦截
11
+ * 4. CacheCheck — MemoryCoordinator 缓存命中
12
+ * 5. ObservationRecord — 记忆记录
13
+ * 6. TrackerSignal — ExplorationTracker 信号收集
14
+ * 7. TraceRecord — ActiveContext 推理链记录
15
+ * 8. SubmitDedup — 提交去重
16
+ *
17
+ * @module core/ToolExecutionPipeline
18
+ */
19
+
20
+ import { SafetyPolicy } from '../policies.js';
21
+
22
+ /**
23
+ * @typedef {Object} ToolCall
24
+ * @property {string} name — 工具名称
25
+ * @property {Object} args — 工具参数
26
+ * @property {string} id — 调用 ID
27
+ */
28
+
29
+ /**
30
+ * @typedef {Object} ToolExecContext
31
+ * @property {import('../AgentRuntime.js').AgentRuntime} runtime — 运行时实例
32
+ * @property {import('./LoopContext.js').LoopContext} loopCtx — 循环上下文
33
+ * @property {number} iteration — 当前迭代次数
34
+ */
35
+
36
+ /**
37
+ * @typedef {Object} ToolMetadata
38
+ * @property {boolean} cacheHit — 是否缓存命中
39
+ * @property {boolean} blocked — 是否被安全策略拦截
40
+ * @property {boolean} isNew — 是否为新信息 (ExplorationTracker)
41
+ * @property {number} durationMs — 执行耗时
42
+ */
43
+
44
+ /**
45
+ * @typedef {Object} ToolMiddleware
46
+ * @property {string} name — 中间件名称
47
+ * @property {Function} [before] — 前置钩子: (call, ctx, metadata) => { blocked?, result? } | void
48
+ * @property {Function} [after] — 后置钩子: (call, result, ctx, metadata) => void
49
+ */
50
+
51
+ export class ToolExecutionPipeline {
52
+ /** @type {ToolMiddleware[]} */
53
+ #middlewares = [];
54
+
55
+ /**
56
+ * 注册中间件
57
+ * @param {ToolMiddleware} middleware
58
+ * @returns {this}
59
+ */
60
+ use(middleware) {
61
+ this.#middlewares.push(middleware);
62
+ return this;
63
+ }
64
+
65
+ /**
66
+ * 执行单个工具调用
67
+ *
68
+ * 执行流:
69
+ * 1. 依次调用 before 钩子 — 任一返回 blocked/result 则短路
70
+ * 2. 实际执行工具 (toolRegistry.execute)
71
+ * 3. 依次调用 after 钩子
72
+ *
73
+ * @param {ToolCall} call — { name, args, id }
74
+ * @param {ToolExecContext} context — { runtime, loopCtx, iteration }
75
+ * @returns {Promise<{ result: *, metadata: ToolMetadata }>}
76
+ */
77
+ async execute(call, context) {
78
+ let toolResult = null;
79
+ const metadata = { cacheHit: false, blocked: false, isNew: false, durationMs: 0 };
80
+
81
+ // ── before 阶段 ──
82
+ for (const mw of this.#middlewares) {
83
+ if (mw.before) {
84
+ const verdict = await mw.before(call, context, metadata);
85
+ if (verdict?.blocked) {
86
+ toolResult = verdict.result;
87
+ metadata.blocked = true;
88
+ break;
89
+ }
90
+ if (verdict?.result !== undefined) {
91
+ toolResult = verdict.result;
92
+ metadata.cacheHit = true;
93
+ break;
94
+ }
95
+ }
96
+ }
97
+
98
+ // ── execute 阶段 ──
99
+ if (toolResult === null) {
100
+ const t0 = Date.now();
101
+ try {
102
+ const { runtime, loopCtx } = context;
103
+ const safetyPolicy = runtime.policies.get?.(SafetyPolicy) || null;
104
+ toolResult = await runtime.toolRegistry.execute(call.name, call.args, {
105
+ agentId: runtime.id,
106
+ source: loopCtx.source || runtime.presetName,
107
+ container: runtime.container,
108
+ safetyPolicy,
109
+ projectRoot: runtime.projectRoot,
110
+ fileCache: runtime.fileCache,
111
+ lang: runtime.lang,
112
+ logger: runtime.logger || null,
113
+ aiProvider: runtime.aiProvider || null,
114
+ // ── bootstrap 维度上下文 (从 sharedState 透传) ──
115
+ _submittedTitles: loopCtx.sharedState?.submittedTitles || null,
116
+ _submittedPatterns: loopCtx.sharedState?.submittedPatterns || null,
117
+ _sharedState: loopCtx.sharedState || null,
118
+ _dimensionMeta: loopCtx.sharedState?._dimensionMeta || null,
119
+ _projectLanguage: loopCtx.sharedState?._projectLanguage || null,
120
+ _memoryCoordinator: loopCtx.memoryCoordinator || null,
121
+ _dimensionScopeId: loopCtx.sharedState?._dimensionScopeId || null,
122
+ _currentRound: loopCtx.iteration || 0,
123
+ });
124
+ } catch (err) {
125
+ toolResult = { error: err.message };
126
+ }
127
+ metadata.durationMs = Date.now() - t0;
128
+ }
129
+
130
+ // ── after 阶段 ──
131
+ for (const mw of this.#middlewares) {
132
+ if (mw.after) {
133
+ await mw.after(call, toolResult, context, metadata);
134
+ }
135
+ }
136
+
137
+ return { result: toolResult, metadata };
138
+ }
139
+ }
140
+
141
+ // ─────────────────────────────────────────────
142
+ // 预置中间件
143
+ // ─────────────────────────────────────────────
144
+
145
+ /**
146
+ * AllowlistGate — 工具白名单守卫
147
+ *
148
+ * 防止 LLM hallucinate 不在当前 capability 允许列表中的工具调用。
149
+ * 从 LoopContext.toolSchemas 中提取允许的工具名列表,
150
+ * 拒绝不在列表中的调用(返回 error 提示)。
151
+ *
152
+ * before: 如果工具不在白名单中则短路返回 error
153
+ */
154
+ export const allowlistGate = {
155
+ name: 'allowlistGate',
156
+ before(call, ctx) {
157
+ const schemas = ctx.loopCtx?.toolSchemas;
158
+ // 如果没有 schema 列表(全工具模式),跳过检查
159
+ if (!schemas || schemas.length === 0) return;
160
+
161
+ const allowedNames = new Set(schemas.map(s => s.name || s.function?.name));
162
+ if (!allowedNames.has(call.name)) {
163
+ ctx.runtime.logger.warn(
164
+ `[ToolPipeline] ⛔ Tool "${call.name}" not in allowlist — blocked (hallucinated call)`
165
+ );
166
+ return {
167
+ blocked: true,
168
+ result: {
169
+ error: `工具 "${call.name}" 不可用。当前可用工具: ${[...allowedNames].slice(0, 5).join(', ')}${allowedNames.size > 5 ? '...' : ''}`,
170
+ },
171
+ };
172
+ }
173
+ },
174
+ };
175
+
176
+ /**
177
+ * SafetyGate — SafetyPolicy 安全拦截
178
+ *
179
+ * before: 如果策略拒绝则短路返回 error
180
+ */
181
+ export const safetyGate = {
182
+ name: 'safetyGate',
183
+ before(call, ctx) {
184
+ const check = ctx.runtime.policies.validateToolCall(call.name, call.args);
185
+ if (!check.ok) {
186
+ ctx.runtime.logger.warn(
187
+ `[ToolPipeline] Tool blocked by Policy: ${call.name} — ${check.reason}`
188
+ );
189
+ return { blocked: true, result: { error: check.reason } };
190
+ }
191
+ },
192
+ };
193
+
194
+ /**
195
+ * CacheCheck — MemoryCoordinator 缓存命中
196
+ *
197
+ * before: 如果缓存命中则短路返回缓存值
198
+ */
199
+ export const cacheCheck = {
200
+ name: 'cacheCheck',
201
+ before(call, ctx) {
202
+ const mc = ctx.loopCtx.memoryCoordinator;
203
+ if (!mc) return;
204
+ const cached = mc.getCachedResult?.(call.name, call.args);
205
+ if (cached !== null && cached !== undefined) {
206
+ ctx.runtime.logger.info(
207
+ `[ToolPipeline] 🔧 CACHE HIT: ${call.name} → skipped execution`
208
+ );
209
+ return { result: cached };
210
+ }
211
+ },
212
+ };
213
+
214
+ /**
215
+ * ObservationRecord — MemoryCoordinator 观察记录
216
+ *
217
+ * after: 记录工具执行观察
218
+ */
219
+ export const observationRecord = {
220
+ name: 'observationRecord',
221
+ after(call, result, ctx, meta) {
222
+ ctx.loopCtx.memoryCoordinator?.recordObservation?.(
223
+ call.name, call.args, result, ctx.iteration, meta.cacheHit
224
+ );
225
+ },
226
+ };
227
+
228
+ /**
229
+ * TrackerSignal — ExplorationTracker 信号收集
230
+ *
231
+ * after: 记录工具调用信号,更新 isNew 标记
232
+ */
233
+ export const trackerSignal = {
234
+ name: 'trackerSignal',
235
+ after(call, result, ctx, meta) {
236
+ if (ctx.loopCtx.tracker) {
237
+ const r = ctx.loopCtx.tracker.recordToolCall(call.name, call.args, result);
238
+ meta.isNew = r.isNew;
239
+ }
240
+ },
241
+ };
242
+
243
+ /**
244
+ * TraceRecord — ActiveContext 推理链记录
245
+ *
246
+ * after: 记录 Action + Observation 到推理链
247
+ */
248
+ export const traceRecord = {
249
+ name: 'traceRecord',
250
+ after(call, result, ctx, meta) {
251
+ ctx.loopCtx.trace?.recordToolCall(call.name, call.args, result, meta.isNew);
252
+ },
253
+ };
254
+
255
+ /**
256
+ * SubmitDedup — 提交去重
257
+ *
258
+ * after: 检查并标记重复提交 (修改 metadata)
259
+ */
260
+ export const submitDedup = {
261
+ name: 'submitDedup',
262
+ after(call, result, ctx, meta) {
263
+ const { sharedState } = ctx.loopCtx;
264
+ if (!sharedState) return;
265
+ if (call.name !== 'submit_knowledge' && call.name !== 'submit_with_check') return;
266
+
267
+ const title = call.args?.title || call.args?.category || '';
268
+ const isRejected = typeof result === 'object' && result?.status === 'rejected';
269
+ const isError = typeof result === 'object' && (result?.error || result?.status === 'error');
270
+
271
+ if (!isRejected && !isError && sharedState.submittedTitles) {
272
+ const normalizedTitle = title.toLowerCase().trim();
273
+ if (sharedState.submittedTitles.has(normalizedTitle)) {
274
+ meta.dedupMessage = `⚠ 重复提交: "${title}" 已存在。`;
275
+ ctx.runtime.logger.info(`[ToolPipeline] 🔁 duplicate: "${title}"`);
276
+ } else {
277
+ sharedState.submittedTitles.add(normalizedTitle);
278
+ // 模式指纹去重
279
+ const pattern = call.args?.content?.pattern || '';
280
+ if (pattern.length >= 30 && sharedState.submittedPatterns) {
281
+ const fp = pattern
282
+ .replace(/\/\/[^\n]*/g, '')
283
+ .replace(/\/\*[\s\S]*?\*\//g, '')
284
+ .replace(/[\s]+/g, '')
285
+ .toLowerCase()
286
+ .slice(0, 200);
287
+ if (fp.length >= 20) {
288
+ sharedState.submittedPatterns.add(fp);
289
+ }
290
+ }
291
+ meta.isSubmit = true;
292
+ }
293
+ }
294
+ },
295
+ };
296
+
297
+ /**
298
+ * ProgressEmitter — 进度回调 (可选,需 runtime.emitProgress 为 public)
299
+ *
300
+ * NOTE: 默认管道不包含此中间件,因为 tool_end 事件需要 resultStr.length,
301
+ * 而 resultStr 在管道外部计算。由 #processToolCalls 直接处理。
302
+ */
303
+ export const progressEmitter = {
304
+ name: 'progressEmitter',
305
+ before(call, ctx) {
306
+ ctx.runtime.emitProgress?.('tool_call', { tool: call.name, args: call.args });
307
+ },
308
+ after(call, result, ctx, meta) {
309
+ ctx.runtime.emitProgress?.('tool_end', {
310
+ tool: call.name,
311
+ duration: meta.durationMs,
312
+ status: result?.error ? 'error' : 'ok',
313
+ error: result?.error || undefined,
314
+ });
315
+ },
316
+ };
317
+
318
+ /**
319
+ * EventBusPublisher — EventBus 事件发布 (可选)
320
+ *
321
+ * NOTE: 默认管道不包含此中间件。由 #processToolCalls 直接处理,
322
+ * 与原始 reactLoop 保持完全一致的事件顺序。
323
+ */
324
+ export const eventBusPublisher = {
325
+ name: 'eventBusPublisher',
326
+ before(call, ctx) {
327
+ if (ctx.runtime.bus?.publish) {
328
+ ctx.runtime.bus.publish('tool:call:start', {
329
+ agentId: ctx.runtime.id,
330
+ tool: call.name,
331
+ }, { source: ctx.runtime.id });
332
+ }
333
+ },
334
+ after(call, result, ctx, meta) {
335
+ if (ctx.runtime.bus?.publish) {
336
+ ctx.runtime.bus.publish('tool:call:end', {
337
+ agentId: ctx.runtime.id,
338
+ tool: call.name,
339
+ durationMs: meta.durationMs,
340
+ success: !result?.error,
341
+ }, { source: ctx.runtime.id });
342
+ }
343
+ },
344
+ };
345
+
346
+ // ─────────────────────────────────────────────
347
+ // Factory helper
348
+ // ─────────────────────────────────────────────
349
+
350
+ /**
351
+ * 创建预配置的工具执行管道
352
+ *
353
+ * 中间件顺序:
354
+ * 1. safetyGate (安全拦截 — 可短路)
355
+ * 2. cacheCheck (缓存检查 — 可短路)
356
+ * 3. observationRecord (记忆记录)
357
+ * 4. trackerSignal (信号收集)
358
+ * 5. traceRecord (推理链)
359
+ * 6. submitDedup (提交去重)
360
+ *
361
+ * NOTE: eventBusPublisher 和 progressEmitter 不在默认管道中,
362
+ * 由 #processToolCalls 直接处理,以保持与原始 reactLoop 完全一致的事件顺序
363
+ * (progress_end 需要 resultStr.length,在管道外计算)。
364
+ *
365
+ * @returns {ToolExecutionPipeline}
366
+ */
367
+ export function createToolPipeline() {
368
+ return new ToolExecutionPipeline()
369
+ .use(allowlistGate)
370
+ .use(safetyGate)
371
+ .use(cacheCheck)
372
+ .use(observationRecord)
373
+ .use(trackerSignal)
374
+ .use(traceRecord)
375
+ .use(submitDedup);
376
+ }
@@ -1,8 +1,8 @@
1
1
  /**
2
- * ChatAgentTasks — ChatAgent 预定义任务方法(从 ChatAgent.js 提取)
2
+ * ChatAgentTasks — Agent 预定义任务方法
3
3
  *
4
- * 每个任务接收 context 对象: { executeTool, aiProvider, container, logger }
5
- * - executeTool(toolName, params) — 执行指定工具
4
+ * 每个任务接收 context 对象: { invokeAgent, aiProvider, container, logger }
5
+ * - invokeAgent(toolName, params) — 直接执行工具 handler(纯数据工具)
6
6
  * - aiProvider — AI Provider 实例
7
7
  * - container — ServiceContainer
8
8
  * - logger — Logger 实例
@@ -14,10 +14,10 @@
14
14
  * 2. 顺便返回质量评估建议
15
15
  */
16
16
  export async function taskCheckAndSubmit(context, { candidate, projectRoot }) {
17
- const { executeTool, aiProvider } = context;
17
+ const { invokeAgent, aiProvider } = context;
18
18
 
19
19
  // Step 1: 查重
20
- const duplicates = await executeTool('check_duplicate', {
20
+ const duplicates = await invokeAgent('check_duplicate', {
21
21
  candidate,
22
22
  projectRoot,
23
23
  threshold: 0.5,
@@ -61,102 +61,23 @@ ${highSim.map((s) => `- ${s.title} (相似度: ${s.similarity})`).join('\n')}
61
61
 
62
62
  /**
63
63
  * 任务: 批量发现 Recipe 间的知识图谱关系
64
- * 遍历所有 Recipe,两两分析可能的关系
64
+ * 委托给 AgentFactory.scanKnowledge (Agent 多轮推理)
65
65
  */
66
66
  export async function taskDiscoverAllRelations(context, { batchSize = 20 } = {}) {
67
- const { executeTool, aiProvider, container, logger } = context;
68
-
69
- const knowledgeService = container.get('knowledgeService');
70
- if (!knowledgeService) {
71
- throw new Error('KnowledgeService 不可用');
72
- }
73
-
74
- if (!aiProvider) {
75
- throw new Error('AI Provider 未配置,请先设置 API Key');
76
- }
77
-
78
- // 获取所有活跃知识条目
79
- const { items = [], data = [] } = await knowledgeService.list(
80
- { lifecycle: 'active' },
81
- { page: 1, pageSize: 500 }
82
- );
83
- const recipes = items.length > 0 ? items : data;
84
- if (recipes.length < 2) {
85
- return {
86
- discovered: 0,
87
- totalPairs: 0,
88
- message: `只有 ${recipes.length} 条 Recipe,至少需要 2 条`,
89
- };
90
- }
91
-
92
- // 按 batch 分组分析
93
- const pairs = [];
94
- for (let i = 0; i < recipes.length; i++) {
95
- for (let j = i + 1; j < recipes.length; j++) {
96
- pairs.push([recipes[i], recipes[j]]);
97
- }
98
- }
99
-
100
- let discovered = 0;
101
- const results = [];
102
- let batchErrors = 0;
103
-
104
- // 分批处理,单批失败不终止整体
105
- for (let b = 0; b < pairs.length; b += batchSize) {
106
- const batch = pairs.slice(b, b + batchSize);
107
- try {
108
- const result = await executeTool('discover_relations', {
109
- recipePairs: batch.map(([a, b]) => ({
110
- a: {
111
- id: a.id,
112
- title: a.title,
113
- category: a.category,
114
- language: a.language,
115
- code: String(a.content || a.code || '').substring(0, 500),
116
- },
117
- b: {
118
- id: b.id,
119
- title: b.title,
120
- category: b.category,
121
- language: b.language,
122
- code: String(b.content || b.code || '').substring(0, 500),
123
- },
124
- })),
125
- });
126
-
127
- if (result.error) {
128
- batchErrors++;
129
- logger.warn(
130
- `[DiscoverRelations] Batch ${Math.floor(b / batchSize) + 1} error: ${result.error}`
131
- );
132
- continue;
133
- }
134
- if (result.relations) {
135
- discovered += result.relations.length;
136
- results.push(...result.relations);
137
- }
138
- } catch (err) {
139
- batchErrors++;
140
- logger.warn(
141
- `[DiscoverRelations] Batch ${Math.floor(b / batchSize) + 1} threw: ${err.message}`
142
- );
143
- }
144
- }
145
-
146
- return {
147
- discovered,
148
- totalPairs: pairs.length,
149
- totalBatches: Math.ceil(pairs.length / batchSize),
150
- batchErrors,
151
- relations: results,
152
- };
67
+ const { container } = context;
68
+ const agentFactory = container.get('agentFactory');
69
+ return agentFactory.scanKnowledge({
70
+ label: 'knowledge-graph',
71
+ files: [],
72
+ task: 'relations',
73
+ });
153
74
  }
154
75
 
155
76
  /**
156
77
  * 任务: 批量 AI 补全候选语义字段
157
78
  */
158
79
  export async function taskFullEnrich(context, { status = 'pending', maxCount = 50 } = {}) {
159
- const { executeTool, container } = context;
80
+ const { invokeAgent, container } = context;
160
81
 
161
82
  const knowledgeService = container.get('knowledgeService');
162
83
 
@@ -179,7 +100,7 @@ export async function taskFullEnrich(context, { status = 'pending', maxCount = 5
179
100
  return { enriched: 0, message: 'All candidates already enriched' };
180
101
  }
181
102
 
182
- const result = await executeTool('enrich_candidate', {
103
+ const result = await invokeAgent('enrich_candidate', {
183
104
  candidateIds: needEnrich.map((c) => c.id).slice(0, 20),
184
105
  });
185
106
 
@@ -191,7 +112,7 @@ export async function taskFullEnrich(context, { status = 'pending', maxCount = 5
191
112
  * 对活跃 Recipe 逐个评分,返回低于阈值的列表
192
113
  */
193
114
  export async function taskQualityAudit(context, { threshold = 0.6, maxCount = 100 } = {}) {
194
- const { executeTool, container } = context;
115
+ const { invokeAgent, container } = context;
195
116
 
196
117
  const knowledgeService = container.get('knowledgeService');
197
118
 
@@ -208,7 +129,7 @@ export async function taskQualityAudit(context, { threshold = 0.6, maxCount = 10
208
129
  const gradeDistribution = { A: 0, B: 0, C: 0, D: 0, F: 0 };
209
130
 
210
131
  for (const recipe of recipes) {
211
- const scoreResult = await executeTool('quality_score', { recipe });
132
+ const scoreResult = await invokeAgent('quality_score', { recipe });
212
133
  if (scoreResult.grade) {
213
134
  gradeDistribution[scoreResult.grade] = (gradeDistribution[scoreResult.grade] || 0) + 1;
214
135
  }
@@ -239,14 +160,14 @@ export async function taskQualityAudit(context, { threshold = 0.6, maxCount = 10
239
160
  * 对代码运行全部 Guard 规则 + 生成修复建议
240
161
  */
241
162
  export async function taskGuardFullScan(context, { code, language, filePath } = {}) {
242
- const { executeTool, aiProvider } = context;
163
+ const { invokeAgent, aiProvider } = context;
243
164
 
244
165
  if (!code) {
245
166
  return { error: 'code is required' };
246
167
  }
247
168
 
248
169
  // Step 1: 静态检查
249
- const checkResult = await executeTool('guard_check_code', {
170
+ const checkResult = await invokeAgent('guard_check_code', {
250
171
  code,
251
172
  language: language || 'unknown',
252
173
  scope: 'project',
@@ -2,18 +2,18 @@
2
2
  * EpisodicConsolidator — Episodic → Semantic 固化引擎
3
3
  *
4
4
  * Bootstrap 完成后,将 SessionStore (Tier 2) 中的维度分析结果
5
- * 提炼为结构化记忆,固化到 ProjectSemanticMemory (Tier 3)。
5
+ * 提炼为结构化记忆,固化到 PersistentMemory (Tier 3)。
6
6
  *
7
7
  * 固化策略 (规则化,无需额外 AI 调用):
8
8
  * 1. 从每个维度的 findings 提取 fact 记忆
9
9
  * 2. 从 Tier Reflections 的 crossDimensionPatterns 提取 insight 记忆
10
10
  * 3. 从 analysisText 中提取项目级别事实 (正则匹配)
11
- * 4. 使用 ProjectSemanticMemory.consolidate() 进行去重和合并
11
+ * 4. 使用 PersistentMemory.consolidate() 进行去重和合并
12
12
  *
13
13
  * @module EpisodicConsolidator
14
14
  */
15
15
 
16
- import Logger from '../../infrastructure/logging/Logger.js';
16
+ import Logger from '../../../infrastructure/logging/Logger.js';
17
17
 
18
18
  // ──────────────────────────────────────────────────────────────
19
19
  // 正则: 从分析文本中提取陈述性知识
@@ -57,14 +57,14 @@ const INSIGHT_PATTERNS = [
57
57
  // ──────────────────────────────────────────────────────────────
58
58
 
59
59
  export class EpisodicConsolidator {
60
- /** @type {import('./ProjectSemanticMemory.js').ProjectSemanticMemory} */
60
+ /** @type {import('../memory/PersistentMemory.js').PersistentMemory} */
61
61
  #semanticMemory;
62
62
 
63
63
  /** @type {import('../../infrastructure/logging/Logger.js').default} */
64
64
  #logger;
65
65
 
66
66
  /**
67
- * @param {import('./ProjectSemanticMemory.js').ProjectSemanticMemory} semanticMemory
67
+ * @param {import('../memory/PersistentMemory.js').PersistentMemory} semanticMemory
68
68
  * @param {object} [opts]
69
69
  * @param {object} [opts.logger]
70
70
  */
@@ -74,9 +74,9 @@ export class EpisodicConsolidator {
74
74
  }
75
75
 
76
76
  /**
77
- * 执行固化: SessionStore → ProjectSemanticMemory
77
+ * 执行固化: SessionStore → PersistentMemory
78
78
  *
79
- * @param {import('./memory/SessionStore.js').SessionStore} sessionStore
79
+ * @param {import('../memory/SessionStore.js').SessionStore} sessionStore
80
80
  * @param {object} [opts]
81
81
  * @param {string} [opts.bootstrapSession] — Bootstrap session ID
82
82
  * @param {boolean} [opts.clearPrevious=false] — 是否先清除旧的 bootstrap 记忆
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * EvidenceCollector.js — 从 Analyst 工具调用中收集结构化证据
3
3
  *
4
- * HandoffProtocol v2 核心组件: 将 Analyst toolCall 序列转化为
5
- * 类型化的证据地图、探索日志和负空间信号,供 Producer 直接引用。
4
+ * Bootstrap 质量门控核心组件: 将 Analyst 阶段的 toolCall 序列转化为
5
+ * 类型化的证据地图、探索日志和负空间信号,供 Producer 阶段直接引用。
6
+ *
7
+ * 被 bootstrap-gate.js (buildAnalysisArtifact) 调用。
6
8
  *
7
9
  * 设计原则:
8
10
  * - 不保留原始工具返回值 (体积过大)