autosnippet 3.2.7 → 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 (147) hide show
  1. package/bin/cli.js +13 -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 +26 -29
  6. package/lib/cli/SetupService.js +1 -1
  7. package/lib/core/AstAnalyzer.js +27 -5
  8. package/lib/core/analysis/CallEdgeResolver.js +402 -0
  9. package/lib/core/analysis/CallGraphAnalyzer.js +367 -0
  10. package/lib/core/analysis/CallSiteExtractor.js +629 -0
  11. package/lib/core/analysis/DataFlowInferrer.js +57 -0
  12. package/lib/core/analysis/ImportPathResolver.js +189 -0
  13. package/lib/core/analysis/ImportRecord.js +105 -0
  14. package/lib/core/analysis/SymbolTableBuilder.js +211 -0
  15. package/lib/core/ast/ProjectGraph.js +8 -0
  16. package/lib/core/ast/lang-dart.js +352 -5
  17. package/lib/core/ast/lang-go.js +212 -10
  18. package/lib/core/ast/lang-java.js +205 -1
  19. package/lib/core/ast/lang-kotlin.js +330 -1
  20. package/lib/core/ast/lang-python.js +31 -2
  21. package/lib/core/ast/lang-rust.js +284 -3
  22. package/lib/core/ast/lang-swift.js +180 -1
  23. package/lib/core/ast/lang-typescript.js +290 -1
  24. package/lib/core/discovery/index.js +2 -2
  25. package/lib/external/ai/AiProvider.js +66 -172
  26. package/lib/external/ai/providers/GoogleGeminiProvider.js +23 -1
  27. package/lib/external/mcp/McpServer.js +1 -0
  28. package/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +1 -1
  29. package/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.js +3 -3
  30. package/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +22 -1
  31. package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +1 -1
  32. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +2 -1
  33. package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +8 -8
  34. package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +1 -1
  35. package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +311 -162
  36. package/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +102 -7
  37. package/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.js +1 -1
  38. package/lib/external/mcp/handlers/bootstrap-external.js +9 -2
  39. package/lib/external/mcp/handlers/bootstrap-internal.js +19 -8
  40. package/lib/external/mcp/handlers/consolidated.js +9 -0
  41. package/lib/external/mcp/handlers/dimension-complete-external.js +6 -6
  42. package/lib/external/mcp/handlers/guard.js +3 -3
  43. package/lib/external/mcp/handlers/structure.js +62 -0
  44. package/lib/external/mcp/handlers/wiki-external.js +66 -3
  45. package/lib/external/mcp/tools.js +36 -1
  46. package/lib/http/HttpServer.js +1 -1
  47. package/lib/http/middleware/requestLogger.js +1 -0
  48. package/lib/http/routes/ai.js +240 -35
  49. package/lib/http/routes/candidates.js +2 -3
  50. package/lib/http/routes/extract.js +13 -11
  51. package/lib/http/routes/modules.js +2 -2
  52. package/lib/http/routes/recipes.js +9 -5
  53. package/lib/http/routes/remote.js +149 -270
  54. package/lib/http/routes/violations.js +0 -54
  55. package/lib/http/utils/sse-sessions.js +1 -1
  56. package/lib/infrastructure/logging/Logger.js +5 -4
  57. package/lib/infrastructure/monitoring/PerformanceMonitor.js +3 -2
  58. package/lib/injection/ServiceContainer.js +70 -28
  59. package/lib/platform/ScreenCaptureService.js +177 -0
  60. package/lib/platform/ios/index.js +2 -2
  61. package/lib/platform/ios/routes/spm.js +2 -2
  62. package/lib/platform/ios/spm/PackageSwiftParser.js +14 -3
  63. package/lib/platform/ios/spm/SpmDiscoverer.js +123 -17
  64. package/lib/platform/ios/spm/{SpmService.js → SpmHelper.js} +43 -675
  65. package/lib/platform/ios/xcode/XcodeWriteUtils.js +1 -1
  66. package/lib/service/agent/AgentEventBus.js +207 -0
  67. package/lib/service/agent/AgentFactory.js +490 -0
  68. package/lib/service/agent/AgentMessage.js +240 -0
  69. package/lib/service/agent/AgentRouter.js +228 -0
  70. package/lib/service/agent/AgentRuntime.js +1016 -0
  71. package/lib/service/agent/AgentState.js +217 -0
  72. package/lib/service/agent/IntentClassifier.js +331 -0
  73. package/lib/service/agent/LarkTransport.js +389 -0
  74. package/lib/service/agent/capabilities.js +408 -0
  75. package/lib/service/{chat → agent/context}/ContextWindow.js +37 -12
  76. package/lib/service/{chat → agent/context}/ExplorationTracker.js +77 -22
  77. package/lib/service/{chat → agent/core}/ChatAgentPrompts.js +14 -2
  78. package/lib/service/agent/core/LoopContext.js +170 -0
  79. package/lib/service/agent/core/MessageAdapter.js +223 -0
  80. package/lib/service/agent/core/ToolExecutionPipeline.js +376 -0
  81. package/lib/service/{chat → agent/domain}/ChatAgentTasks.js +19 -98
  82. package/lib/service/{chat → agent/domain}/EpisodicConsolidator.js +7 -7
  83. package/lib/service/{chat → agent/domain}/EvidenceCollector.js +4 -2
  84. package/lib/service/{chat/AnalystAgent.js → agent/domain/insight-analyst.js} +37 -172
  85. package/lib/service/{chat/HandoffProtocol.js → agent/domain/insight-gate.js} +91 -123
  86. package/lib/service/agent/domain/insight-producer.js +267 -0
  87. package/lib/service/agent/domain/scan-prompts.js +105 -0
  88. package/lib/service/agent/forced-summary.js +266 -0
  89. package/lib/service/agent/index.js +91 -0
  90. package/lib/service/{chat → agent}/memory/ActiveContext.js +3 -1
  91. package/lib/service/{chat → agent}/memory/MemoryCoordinator.js +7 -7
  92. package/lib/service/{chat/ProjectSemanticMemory.js → agent/memory/PersistentMemory.js} +359 -89
  93. package/lib/service/{chat → agent}/memory/SessionStore.js +5 -4
  94. package/lib/service/{chat → agent}/memory/index.js +1 -1
  95. package/lib/service/agent/policies.js +442 -0
  96. package/lib/service/agent/presets.js +303 -0
  97. package/lib/service/agent/strategies.js +717 -0
  98. package/lib/service/{chat → agent/tools}/ToolRegistry.js +3 -3
  99. package/lib/service/agent/tools/ai-analysis.js +75 -0
  100. package/lib/service/{chat → agent}/tools/ast-graph.js +229 -32
  101. package/lib/service/{chat → agent}/tools/composite.js +2 -1
  102. package/lib/service/{chat → agent}/tools/guard.js +1 -121
  103. package/lib/service/{chat → agent}/tools/index.js +33 -22
  104. package/lib/service/{chat → agent}/tools/infrastructure.js +6 -1
  105. package/lib/service/agent/tools/knowledge-graph.js +112 -0
  106. package/lib/service/agent/tools/scan-recipe.js +189 -0
  107. package/lib/service/agent/tools/system-interaction.js +476 -0
  108. package/lib/service/automation/DirectiveDetector.js +0 -1
  109. package/lib/service/automation/FileWatcher.js +0 -8
  110. package/lib/service/automation/handlers/CreateHandler.js +7 -3
  111. package/lib/service/automation/handlers/DraftHandler.js +7 -6
  112. package/lib/service/cursor/CursorDeliveryPipeline.js +167 -1
  113. package/lib/service/knowledge/CodeEntityGraph.js +327 -2
  114. package/lib/service/knowledge/KnowledgeService.js +5 -1
  115. package/lib/service/module/ModuleService.js +49 -73
  116. package/lib/service/skills/SignalCollector.js +26 -19
  117. package/lib/service/snippet/codecs/VSCodeCodec.js +1 -1
  118. package/lib/service/wiki/WikiGenerator.js +1 -1
  119. package/lib/shared/FieldSpec.js +1 -1
  120. package/lib/shared/PathGuard.js +1 -1
  121. package/lib/shared/StyleGuide.js +1 -1
  122. package/package.json +4 -1
  123. package/resources/native-ui/screenshot.swift +228 -0
  124. package/dashboard/dist/assets/index-BaGY7kJI.css +0 -1
  125. package/dashboard/dist/assets/index-DfHY_3ln.js +0 -128
  126. package/lib/core/discovery/SpmDiscoverer.js +0 -5
  127. package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +0 -749
  128. package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +0 -277
  129. package/lib/http/routes/spm.js +0 -5
  130. package/lib/infrastructure/external/XcodeAutomation.js +0 -15
  131. package/lib/service/chat/ChatAgent.js +0 -1602
  132. package/lib/service/chat/Memory.js +0 -161
  133. package/lib/service/chat/ProducerAgent.js +0 -431
  134. package/lib/service/chat/ReasoningTrace.js +0 -523
  135. package/lib/service/chat/TaskPipeline.js +0 -357
  136. package/lib/service/chat/WorkingMemory.js +0 -357
  137. package/lib/service/chat/memory/PersistentMemory.js +0 -450
  138. package/lib/service/chat/tools/ai-analysis.js +0 -267
  139. package/lib/service/chat/tools/knowledge-graph.js +0 -234
  140. package/lib/service/chat/tools.js +0 -18
  141. package/lib/service/snippet/PlaceholderConverter.js +0 -5
  142. package/lib/service/snippet/codecs/XcodeCodec.js +0 -5
  143. /package/lib/service/{chat → agent}/ConversationStore.js +0 -0
  144. /package/lib/service/{chat → agent}/tools/_shared.js +0 -0
  145. /package/lib/service/{chat → agent}/tools/lifecycle.js +0 -0
  146. /package/lib/service/{chat → agent}/tools/project-access.js +0 -0
  147. /package/lib/service/{chat → agent}/tools/query.js +0 -0
@@ -9,6 +9,18 @@ import express from 'express';
9
9
  import { createProvider } from '../../external/ai/AiFactory.js';
10
10
  import Logger from '../../infrastructure/logging/Logger.js';
11
11
  import { getServiceContainer } from '../../injection/ServiceContainer.js';
12
+ import { AgentMessage, Channel } from '../../service/agent/AgentMessage.js';
13
+ import { PRESETS } from '../../service/agent/presets.js';
14
+ import { ContextWindow } from '../../service/agent/context/ContextWindow.js';
15
+ import { ConversationStore } from '../../service/agent/ConversationStore.js';
16
+ import { buildProjectBriefing, cleanFinalAnswer } from '../../service/agent/core/ChatAgentPrompts.js';
17
+ import {
18
+ taskCheckAndSubmit,
19
+ taskDiscoverAllRelations,
20
+ taskFullEnrich,
21
+ taskQualityAudit,
22
+ taskGuardFullScan,
23
+ } from '../../service/agent/domain/ChatAgentTasks.js';
12
24
  import { ValidationError } from '../../shared/errors/index.js';
13
25
  import { asyncHandler } from '../middleware/errorHandler.js';
14
26
  import { createStreamSession, getStreamSession } from '../utils/sse-sessions.js';
@@ -16,10 +28,9 @@ import { createStreamSession, getStreamSession } from '../utils/sse-sessions.js'
16
28
  const router = express.Router();
17
29
  const logger = Logger.getInstance();
18
30
 
19
- /** 获取 ChatAgent 实例(统一 AI 入口) */
20
- function getChatAgent() {
21
- const container = getServiceContainer();
22
- return container.get('chatAgent');
31
+ /** 获取 DI 容器 */
32
+ function getContainer() {
33
+ return getServiceContainer();
23
34
  }
24
35
 
25
36
  // ═══════════════════════════════════════════════════════
@@ -33,8 +44,8 @@ function getChatAgent() {
33
44
  router.get(
34
45
  '/lang',
35
46
  asyncHandler(async (req, res) => {
36
- const chatAgent = getChatAgent();
37
- res.json({ success: true, data: { lang: chatAgent.getLang() || 'zh' } });
47
+ const container = getContainer();
48
+ res.json({ success: true, data: { lang: container.getLang() || 'zh' } });
38
49
  })
39
50
  );
40
51
 
@@ -49,8 +60,8 @@ router.post(
49
60
  if (lang !== 'zh' && lang !== 'en') {
50
61
  throw new ValidationError('lang must be "zh" or "en"');
51
62
  }
52
- const chatAgent = getChatAgent();
53
- chatAgent.setLang(lang);
63
+ const container = getContainer();
64
+ container.setLang(lang);
54
65
  logger.info(`UI language preference updated to "${lang}"`);
55
66
  res.json({ success: true, data: { lang } });
56
67
  })
@@ -168,8 +179,13 @@ router.post(
168
179
  throw new ValidationError('code is required');
169
180
  }
170
181
 
171
- const chatAgent = getChatAgent();
172
- const result = await chatAgent.executeTool('summarize_code', { code, language });
182
+ const container = getContainer();
183
+ const factory = container.get('agentFactory');
184
+ const result = await factory.scanKnowledge({
185
+ label: 'code',
186
+ files: [{ name: 'code', content: code, language }],
187
+ task: 'summarize',
188
+ });
173
189
 
174
190
  if (result?.error) {
175
191
  throw new ValidationError(result.error);
@@ -196,8 +212,9 @@ router.post(
196
212
  }
197
213
 
198
214
  try {
199
- const chatAgent = getChatAgent();
200
- const result = await chatAgent.executeTool('ai_translate', { summary, usageGuide });
215
+ const container = getContainer();
216
+ const factory = container.get('agentFactory');
217
+ const result = await factory.translateToEnglish(summary, usageGuide);
201
218
 
202
219
  if (result?.error) {
203
220
  // AI 不可用,降级返回原文
@@ -224,26 +241,123 @@ router.post(
224
241
  /**
225
242
  * POST /api/v1/ai/chat
226
243
  * AI 对话(RAG 模式,结合项目知识库)
244
+ *
245
+ * 增强特性 (Engine Migration):
246
+ * - 对话持久化 (ConversationStore)
247
+ * - ContextWindow 上下文窗口管理
248
+ * - Token 用量持久化
249
+ * - 项目概况注入 (buildProjectBriefing)
250
+ * - SSE 流式最终回答 (text:start/delta/end)
251
+ * - MemoryCoordinator 记忆提取
227
252
  */
228
253
  router.post(
229
254
  '/chat',
230
255
  asyncHandler(async (req, res) => {
231
- const { prompt, history = [], lang } = req.body;
256
+ const { prompt, history = [], lang, conversationId } = req.body;
232
257
 
233
258
  if (!prompt) {
234
259
  throw new ValidationError('prompt is required');
235
260
  }
236
261
 
237
- const chatAgent = getChatAgent();
238
- const result = await chatAgent.execute(prompt, { history, lang });
262
+ const container = getContainer();
263
+ const factory = container.get('agentFactory');
264
+
265
+ // ── 对话持久化: 从 ConversationStore 加载历史 ──
266
+ let convStore = null;
267
+ let effectiveHistory = history;
268
+ let effectiveConvId = conversationId || null;
269
+ try {
270
+ const projectRoot = container.get('projectRoot') || process.cwd();
271
+ convStore = new ConversationStore(projectRoot);
272
+ if (effectiveConvId) {
273
+ effectiveHistory = convStore.load(effectiveConvId);
274
+ convStore.append(effectiveConvId, { role: 'user', content: prompt });
275
+ } else {
276
+ effectiveConvId = convStore.create({ category: 'user', title: prompt.slice(0, 50) });
277
+ convStore.append(effectiveConvId, { role: 'user', content: prompt });
278
+ }
279
+ } catch {
280
+ /* ConversationStore 不可用时静默降级 */
281
+ }
282
+
283
+ // ── 项目概况刷新 ──
284
+ let projectBriefing = '';
285
+ try {
286
+ projectBriefing = await buildProjectBriefing({ container });
287
+ } catch { /* 静默降级 */ }
288
+
289
+ // ── 创建 ContextWindow ──
290
+ const contextWindow = factory.createContextWindow({ isSystem: false });
291
+
292
+ // ── 创建 Runtime 并注入 onProgress ──
293
+ const message = AgentMessage.fromHttp(req);
294
+ // 加载持久化历史到 message
295
+ if (effectiveHistory.length > 0) {
296
+ message.history = effectiveHistory;
297
+ }
298
+
299
+ const runtime = factory.createChat({
300
+ lang,
301
+ onProgress: (event) => {
302
+ // SSE 流式进度 (如果前端通过 SSE 建立了连接)
303
+ try {
304
+ const sessionId = req.body.sseSessionId;
305
+ if (sessionId) {
306
+ const session = getStreamSession(sessionId);
307
+ if (session) session.send(event);
308
+ }
309
+ } catch { /* SSE 不可用时静默 */ }
310
+ },
311
+ });
312
+ const result = await runtime.execute(message);
313
+
314
+ // ── 持久化 assistant 回复 ──
315
+ if (convStore && effectiveConvId && result.reply) {
316
+ try {
317
+ convStore.append(effectiveConvId, { role: 'assistant', content: result.reply });
318
+ } catch { /* 静默降级 */ }
319
+ }
320
+
321
+ // ── MemoryCoordinator: 提取记忆 ──
322
+ try {
323
+ const memoryCoordinator = container.get('memoryCoordinator');
324
+ if (memoryCoordinator) {
325
+ memoryCoordinator.extractFromConversation?.(prompt, result.reply, 'user');
326
+ }
327
+ } catch { /* 静默降级 */ }
328
+
329
+ // ── Token 用量持久化 ──
330
+ try {
331
+ const tokenStore = container.get('tokenUsageStore');
332
+ if (tokenStore && result.tokenUsage) {
333
+ const aiProvider = container.singletons?.aiProvider;
334
+ tokenStore.record({
335
+ source: 'user',
336
+ dimension: null,
337
+ provider: aiProvider?.name || null,
338
+ model: aiProvider?.model || null,
339
+ inputTokens: result.tokenUsage.input || 0,
340
+ outputTokens: result.tokenUsage.output || 0,
341
+ durationMs: result.durationMs || 0,
342
+ toolCalls: result.toolCalls?.length || 0,
343
+ sessionId: effectiveConvId,
344
+ });
345
+ // 通知前端 token 用量变化
346
+ try {
347
+ const realtime = container.get('realtimeService');
348
+ realtime?.broadcastTokenUsageUpdated?.();
349
+ } catch { /* optional */ }
350
+ }
351
+ } catch { /* token logging should never break execution */ }
239
352
 
240
353
  res.json({
241
354
  success: true,
242
355
  data: {
243
356
  reply: result.reply,
244
- hasContext: result.hasContext,
245
357
  toolCalls: result.toolCalls,
246
- reasoningQuality: result.reasoningQuality || null,
358
+ iterations: result.iterations || null,
359
+ conversationId: effectiveConvId,
360
+ tokenUsage: result.tokenUsage || null,
247
361
  },
248
362
  });
249
363
  })
@@ -263,8 +377,9 @@ router.post(
263
377
  throw new ValidationError('tool name is required');
264
378
  }
265
379
 
266
- const chatAgent = getChatAgent();
267
- const result = await chatAgent.executeTool(tool, params);
380
+ const container = getContainer();
381
+ const factory = container.get('agentFactory');
382
+ const result = await factory.invokeAgent(tool, params);
268
383
 
269
384
  res.json({ success: true, data: result });
270
385
  })
@@ -274,7 +389,19 @@ router.post(
274
389
  * POST /api/v1/ai/agent/task
275
390
  * 执行预定义任务流(查重提交 / 批量关系发现 / 批量补全)
276
391
  * Body: { task: string, params: object }
392
+ *
393
+ * 支持两种任务类型:
394
+ * 1. ToolRegistry 注册的工具 (直接通过 toolName 调用)
395
+ * 2. ChatAgentTasks 的 5 个预定义 DAG 任务
277
396
  */
397
+ const DAG_TASK_HANDLERS = {
398
+ check_and_submit: taskCheckAndSubmit,
399
+ discover_all_relations: taskDiscoverAllRelations,
400
+ full_enrich: taskFullEnrich,
401
+ quality_audit: taskQualityAudit,
402
+ guard_full_scan: taskGuardFullScan,
403
+ };
404
+
278
405
  router.post(
279
406
  '/agent/task',
280
407
  asyncHandler(async (req, res) => {
@@ -284,8 +411,25 @@ router.post(
284
411
  throw new ValidationError('task name is required');
285
412
  }
286
413
 
287
- const chatAgent = getChatAgent();
288
- const result = await chatAgent.runTask(task, params);
414
+ const container = getContainer();
415
+ const factory = container.get('agentFactory');
416
+
417
+ // 优先尝试 DAG 任务
418
+ const dagHandler = DAG_TASK_HANDLERS[task];
419
+ if (dagHandler) {
420
+ const aiProvider = container.singletons?.aiProvider;
421
+ const taskContext = {
422
+ invokeAgent: (name, p) => factory.invokeAgent(name, p),
423
+ aiProvider,
424
+ container,
425
+ logger,
426
+ };
427
+ const result = await dagHandler(taskContext, params);
428
+ return res.json({ success: true, data: result });
429
+ }
430
+
431
+ // 回退到 Agent 工具执行
432
+ const result = await factory.invokeAgent(task, params);
289
433
 
290
434
  res.json({ success: true, data: result });
291
435
  })
@@ -298,8 +442,29 @@ router.post(
298
442
  router.get(
299
443
  '/agent/capabilities',
300
444
  asyncHandler(async (req, res) => {
301
- const chatAgent = getChatAgent();
302
- res.json({ success: true, data: chatAgent.getCapabilities() });
445
+ const container = getContainer();
446
+ const toolRegistry = container.get('toolRegistry');
447
+ const tools = toolRegistry.getToolSchemas();
448
+ const presets = Object.entries(PRESETS).map(([name, p]) => ({
449
+ name,
450
+ description: p.description,
451
+ capabilities: p.capabilities,
452
+ strategy: p.strategy?.type || 'single',
453
+ }));
454
+ res.json({
455
+ success: true,
456
+ data: {
457
+ tools,
458
+ presets,
459
+ tasks: [
460
+ { name: 'check_and_submit', description: '提交候选前自动查重 + 质量预评' },
461
+ { name: 'discover_all_relations', description: '批量发现 Recipe 之间的知识图谱关系' },
462
+ { name: 'full_enrich', description: '批量 AI 语义补全候选字段' },
463
+ { name: 'quality_audit', description: '批量质量审计全部 Recipe,标记低分项' },
464
+ { name: 'guard_full_scan', description: '用全部 Guard 规则扫描指定代码,生成完整报告' },
465
+ ],
466
+ },
467
+ });
303
468
  })
304
469
  );
305
470
 
@@ -511,7 +676,7 @@ router.post(
511
676
 
512
677
  /**
513
678
  * POST /api/v1/ai/chat/stream
514
- * 启动 AI 对话流 — 创建 session,后台执行 ChatAgent,立即返回 sessionId
679
+ * 启动 AI 对话流 — 创建 session,后台执行 AgentRuntime,立即返回 sessionId
515
680
  *
516
681
  * 客户端拿到 sessionId 后通过 GET /chat/events/:sessionId (EventSource) 消费事件
517
682
  *
@@ -537,27 +702,67 @@ router.post(
537
702
  throw new ValidationError('prompt is required');
538
703
  }
539
704
 
540
- const chatAgent = getChatAgent();
705
+ const container = getContainer();
706
+ const factory = container.get('agentFactory');
541
707
  const session = createStreamSession('chat');
542
708
 
543
709
  logger.debug('SSE session created', { sessionId: session.sessionId });
544
710
 
545
- // 立即返回 sessionId(不等待 ChatAgent 执行)
711
+ // 立即返回 sessionId(不等待 Agent 执行)
546
712
  res.json({ success: true, sessionId: session.sessionId });
547
713
 
548
- // 后台执行 ChatAgent — 事件通过 session.send() 缓冲
549
- chatAgent
550
- .execute(prompt, {
551
- history,
552
- lang,
553
- onProgress: (event) => session.send(event),
554
- })
714
+ // AgentMessage 构建
715
+ const message = new AgentMessage({
716
+ content: prompt,
717
+ channel: Channel.HTTP,
718
+ session: { id: session.sessionId, history },
719
+ sender: { id: req.ip || 'http-user', type: 'user' },
720
+ metadata: { lang, stream: true },
721
+ });
722
+
723
+ // 创建 Runtime — 挂载 onProgress 回调映射到 SSE 事件
724
+ const runtime = factory.createChat({
725
+ lang,
726
+ onProgress: (event) => {
727
+ // 将 AgentRuntime 内部事件映射到前端 SSE 协议
728
+ switch (event.type) {
729
+ case 'thinking':
730
+ session.send({ type: 'step:start', step: event.iteration, maxSteps: event.maxIterations, phase: 'thinking' });
731
+ break;
732
+ case 'tool_call':
733
+ session.send({ type: 'tool:start', tool: event.tool, args: event.args });
734
+ break;
735
+ case 'tool_end':
736
+ session.send({
737
+ type: 'tool:end',
738
+ tool: event.tool,
739
+ status: event.status,
740
+ resultSize: event.resultSize,
741
+ duration: event.duration,
742
+ error: event.error,
743
+ });
744
+ break;
745
+ default:
746
+ session.send(event);
747
+ }
748
+ },
749
+ });
750
+
751
+ // 后台执行 AgentRuntime
752
+ runtime
753
+ .execute(message)
555
754
  .then((result) => {
556
- // text:start/delta/end 已由 ChatAgent.execute() 内部通过 onProgress 发送
755
+ // 发送最终文本
756
+ if (result.reply) {
757
+ const textId = `text_${Date.now()}`;
758
+ session.send({ type: 'text:start', id: textId, role: 'assistant' });
759
+ session.send({ type: 'text:delta', id: textId, delta: result.reply });
760
+ session.send({ type: 'text:end', id: textId });
761
+ }
557
762
  session.end({
558
763
  text: result.reply,
559
764
  toolCalls: result.toolCalls || [],
560
- hasContext: result.hasContext || false,
765
+ iterations: result.iterations || 0,
561
766
  });
562
767
  logger.debug('SSE session completed', {
563
768
  sessionId: session.sessionId,
@@ -75,10 +75,9 @@ router.post(
75
75
  // 获取用户语言偏好
76
76
  let lang = 'en';
77
77
  try {
78
- const chatAgent = container.get('chatAgent');
79
- lang = chatAgent?.getLang?.() || 'en';
78
+ lang = container.getLang?.() || 'en';
80
79
  } catch {
81
- /* chatAgent not available */
80
+ /* lang not available */
82
81
  }
83
82
  enriched = await aiProvider.enrichCandidates(candidates, { lang });
84
83
  } catch (err) {
@@ -17,7 +17,7 @@ const logger = Logger.getInstance();
17
17
  /**
18
18
  * POST /api/v1/extract/path
19
19
  * 从文件路径提取代码片段
20
- * 管线: RecipeParser(MD解析) → AI 提取(ChatAgent) → 原始兜底
20
+ * 管线: RecipeParser(MD解析) → AI 提取(AgentRuntime) → 原始兜底
21
21
  */
22
22
  router.post(
23
23
  '/path',
@@ -55,14 +55,15 @@ router.post(
55
55
  !items[0].frontmatter?.title;
56
56
 
57
57
  if (isRawFallback) {
58
- // 3. 尝试 ChatAgent AI 提取
58
+ // 3. 尝试 AI 提取
59
59
  try {
60
- const chatAgent = container.get('chatAgent');
60
+ const agentFactory = container.get('agentFactory');
61
61
  const file = items[0];
62
62
  const fileName = basename(relativePath); // 保留扩展名: BDMineViewController.m
63
- const aiResult = await chatAgent.executeTool('extract_recipes', {
64
- targetName: fileName,
63
+ const aiResult = await agentFactory.scanKnowledge({
64
+ label: fileName,
65
65
  files: [{ name: fileName, content: file.code || '' }],
66
+ task: 'extract',
66
67
  comprehensive: true,
67
68
  });
68
69
 
@@ -102,7 +103,7 @@ router.post(
102
103
  /**
103
104
  * POST /api/v1/extract/text
104
105
  * 从文本内容提取代码片段(剪贴板等)
105
- * 管线: RecipeParser(MD解析) → AI 提取(ChatAgent) → 基础兜底
106
+ * 管线: RecipeParser(MD解析) → AI 提取(AgentRuntime) → 基础兜底
106
107
  */
107
108
  router.post(
108
109
  '/text',
@@ -138,18 +139,19 @@ router.post(
138
139
  });
139
140
  }
140
141
 
141
- // 2. Recipe MD 解析失败 → 尝试 ChatAgent AI 提取
142
+ // 2. Recipe MD 解析失败 → 尝试 AI 提取
142
143
  try {
143
- const chatAgent = container.get('chatAgent');
144
- if (chatAgent) {
144
+ const agentFactory = container.get('agentFactory');
145
+ if (agentFactory) {
145
146
  const lang =
146
147
  language ||
147
148
  (relativePath ? LanguageService.inferLang(relativePath) || 'unknown' : 'unknown');
148
149
  const ext = LanguageService.extForLang(lang) || '.txt';
149
150
  const fileName = relativePath ? basename(relativePath) : `clipboard${ext}`;
150
- const aiResult = await chatAgent.executeTool('extract_recipes', {
151
- targetName: fileName,
151
+ const aiResult = await agentFactory.scanKnowledge({
152
+ label: fileName,
152
153
  files: [{ name: fileName, content: text }],
154
+ task: 'extract',
153
155
  comprehensive: true,
154
156
  });
155
157
 
@@ -531,11 +531,11 @@ router.post(
531
531
  const { maxFiles, skipGuard, contentMaxLines } = req.body || {};
532
532
 
533
533
  const container = getServiceContainer();
534
- const chatAgent = container.get('chatAgent');
534
+ const agentFactory = container.get('agentFactory');
535
535
 
536
536
  logger.info('Bootstrap cold start initiated (ModuleService path)');
537
537
 
538
- const bootstrapResult = await chatAgent.executeTool('bootstrap_knowledge', {
538
+ const bootstrapResult = await agentFactory.bootstrapKnowledge({
539
539
  maxFiles: maxFiles || 500,
540
540
  skipGuard: skipGuard || false,
541
541
  contentMaxLines: contentMaxLines || 120,
@@ -70,15 +70,15 @@ router.post(
70
70
  });
71
71
  }
72
72
 
73
- // 检查 ChatAgent 是否可用
73
+ // 检查 ToolRegistry 是否可用
74
74
  const container = getServiceContainer();
75
- let chatAgent;
75
+ let agentFactory;
76
76
  try {
77
- chatAgent = container.get('chatAgent');
77
+ agentFactory = container.get('agentFactory');
78
78
  } catch {
79
79
  return res.json({
80
80
  success: true,
81
- data: { status: 'error', error: 'ChatAgent 不可用,请检查 AI Provider 配置' },
81
+ data: { status: 'error', error: 'AgentFactory 不可用,请检查 AI Provider 配置' },
82
82
  });
83
83
  }
84
84
 
@@ -111,7 +111,11 @@ router.post(
111
111
  // 异步执行,不 await
112
112
  (async () => {
113
113
  try {
114
- const result = await chatAgent.runTask('discover_all_relations', { batchSize });
114
+ const result = await agentFactory.scanKnowledge({
115
+ label: 'knowledge-graph',
116
+ files: [],
117
+ task: 'relations',
118
+ });
115
119
  discoverTask.status = 'done';
116
120
  discoverTask.finishedAt = new Date().toISOString();
117
121
  discoverTask.discovered = result.discovered || 0;