autosnippet 3.3.6 → 3.3.8

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 (275) hide show
  1. package/README.md +1 -0
  2. package/dashboard/dist/assets/icons-BMNb0V6L.js +1 -0
  3. package/dashboard/dist/assets/index-DHJ1Dj7u.css +1 -0
  4. package/dashboard/dist/assets/index-DV8biUkH.js +112 -0
  5. package/dashboard/dist/index.html +3 -3
  6. package/dist/bin/cli.js +8 -4
  7. package/dist/lib/agent/AgentRuntime.d.ts +2 -2
  8. package/dist/lib/agent/AgentRuntime.js +26 -18
  9. package/dist/lib/agent/core/ChatAgentPrompts.js +57 -21
  10. package/dist/lib/agent/core/LoopContext.d.ts +1 -0
  11. package/dist/lib/agent/core/ToolExecutionPipeline.js +13 -0
  12. package/dist/lib/agent/domain/ChatAgentTasks.js +4 -0
  13. package/dist/lib/agent/forced-summary.js +7 -2
  14. package/dist/lib/agent/memory/ActiveContext.d.ts +0 -2
  15. package/dist/lib/agent/memory/ActiveContext.js +0 -2
  16. package/dist/lib/agent/memory/MemoryEmbeddingStore.d.ts +49 -0
  17. package/dist/lib/agent/memory/MemoryEmbeddingStore.js +159 -0
  18. package/dist/lib/agent/memory/MemoryRetriever.d.ts +2 -0
  19. package/dist/lib/agent/memory/MemoryRetriever.js +25 -11
  20. package/dist/lib/agent/memory/MemoryStore.d.ts +8 -41
  21. package/dist/lib/agent/memory/MemoryStore.js +196 -261
  22. package/dist/lib/agent/memory/PersistentMemory.d.ts +2 -0
  23. package/dist/lib/agent/memory/PersistentMemory.js +4 -5
  24. package/dist/lib/agent/memory/SessionStore.d.ts +0 -2
  25. package/dist/lib/agent/memory/SessionStore.js +0 -2
  26. package/dist/lib/agent/tools/ast-graph.js +21 -19
  27. package/dist/lib/agent/tools/infrastructure.js +3 -2
  28. package/dist/lib/agent/tools/project-access.d.ts +2 -2
  29. package/dist/lib/agent/tools/project-access.js +5 -4
  30. package/dist/lib/bootstrap.js +2 -1
  31. package/dist/lib/cli/AiScanService.js +8 -21
  32. package/dist/lib/cli/KnowledgeSyncService.d.ts +7 -37
  33. package/dist/lib/cli/KnowledgeSyncService.js +23 -51
  34. package/dist/lib/core/ast/ProjectGraph.js +5 -27
  35. package/dist/lib/core/discovery/ConfigWatcher.d.ts +64 -0
  36. package/dist/lib/core/discovery/ConfigWatcher.js +336 -0
  37. package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +28 -0
  38. package/dist/lib/core/discovery/CustomConfigDiscoverer.js +1303 -0
  39. package/dist/lib/core/discovery/DiscovererPreference.d.ts +44 -0
  40. package/dist/lib/core/discovery/DiscovererPreference.js +141 -0
  41. package/dist/lib/core/discovery/DiscovererRegistry.d.ts +10 -1
  42. package/dist/lib/core/discovery/DiscovererRegistry.js +42 -2
  43. package/dist/lib/core/discovery/ProjectDiscoverer.d.ts +19 -0
  44. package/dist/lib/core/discovery/index.d.ts +2 -0
  45. package/dist/lib/core/discovery/index.js +4 -0
  46. package/dist/lib/core/discovery/parsers/CMakeParser.d.ts +32 -0
  47. package/dist/lib/core/discovery/parsers/CMakeParser.js +148 -0
  48. package/dist/lib/core/discovery/parsers/GradleDslParser.d.ts +43 -0
  49. package/dist/lib/core/discovery/parsers/GradleDslParser.js +171 -0
  50. package/dist/lib/core/discovery/parsers/JsonConfigParser.d.ts +45 -0
  51. package/dist/lib/core/discovery/parsers/JsonConfigParser.js +122 -0
  52. package/dist/lib/core/discovery/parsers/RubyDslParser.d.ts +49 -0
  53. package/dist/lib/core/discovery/parsers/RubyDslParser.js +282 -0
  54. package/dist/lib/core/discovery/parsers/StarlarkParser.d.ts +33 -0
  55. package/dist/lib/core/discovery/parsers/StarlarkParser.js +229 -0
  56. package/dist/lib/core/discovery/parsers/YamlConfigParser.d.ts +37 -0
  57. package/dist/lib/core/discovery/parsers/YamlConfigParser.js +212 -0
  58. package/dist/lib/domain/dimension/DimensionRegistry.d.ts +0 -2
  59. package/dist/lib/domain/dimension/DimensionRegistry.js +0 -2
  60. package/dist/lib/domain/dimension/DimensionSop.js +44 -33
  61. package/dist/lib/domain/dimension/UnifiedDimension.d.ts +0 -2
  62. package/dist/lib/domain/dimension/UnifiedDimension.js +0 -2
  63. package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +7 -1
  64. package/dist/lib/domain/knowledge/KnowledgeEntry.js +17 -3
  65. package/dist/lib/domain/knowledge/Lifecycle.d.ts +26 -0
  66. package/dist/lib/domain/knowledge/Lifecycle.js +42 -0
  67. package/dist/lib/domain/knowledge/index.d.ts +2 -1
  68. package/dist/lib/domain/knowledge/index.js +1 -1
  69. package/dist/lib/external/ai/AiProvider.d.ts +12 -0
  70. package/dist/lib/external/ai/AiProvider.js +24 -0
  71. package/dist/lib/external/ai/AiProviderManager.d.ts +101 -0
  72. package/dist/lib/external/ai/AiProviderManager.js +193 -0
  73. package/dist/lib/external/ai/providers/ClaudeProvider.js +11 -0
  74. package/dist/lib/external/ai/providers/GoogleGeminiProvider.js +18 -0
  75. package/dist/lib/external/ai/providers/MockProvider.d.ts +21 -3
  76. package/dist/lib/external/ai/providers/MockProvider.js +290 -14
  77. package/dist/lib/external/ai/providers/OpenAiProvider.js +16 -0
  78. package/dist/lib/external/lark/LarkTransport.d.ts +5 -1
  79. package/dist/lib/external/lark/LarkTransport.js +10 -2
  80. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.d.ts +2 -1
  81. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +102 -153
  82. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.d.ts +20 -0
  83. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.js +432 -0
  84. package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +49 -24
  85. package/dist/lib/external/mcp/handlers/bootstrap/refine.js +8 -0
  86. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +1 -1
  87. package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +41 -37
  88. package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +9 -0
  89. package/dist/lib/external/mcp/handlers/bootstrap-external.js +3 -1
  90. package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
  91. package/dist/lib/external/mcp/handlers/consolidated.js +2 -1
  92. package/dist/lib/external/mcp/handlers/dimension-complete-external.js +9 -4
  93. package/dist/lib/external/mcp/handlers/evolve-external.d.ts +1 -0
  94. package/dist/lib/external/mcp/handlers/evolve-external.js +18 -18
  95. package/dist/lib/external/mcp/handlers/guard.js +15 -24
  96. package/dist/lib/external/mcp/handlers/knowledge.js +5 -4
  97. package/dist/lib/external/mcp/handlers/panorama.js +9 -9
  98. package/dist/lib/external/mcp/handlers/rescan-external.js +7 -6
  99. package/dist/lib/external/mcp/handlers/rescan-internal.js +9 -5
  100. package/dist/lib/external/mcp/handlers/search.js +3 -1
  101. package/dist/lib/external/mcp/handlers/skill.js +4 -4
  102. package/dist/lib/external/mcp/handlers/structure.js +8 -12
  103. package/dist/lib/external/mcp/handlers/system.js +10 -34
  104. package/dist/lib/http/routes/ai.js +109 -30
  105. package/dist/lib/http/routes/candidates.js +11 -4
  106. package/dist/lib/http/routes/commands.js +10 -1
  107. package/dist/lib/http/routes/guardReport.js +3 -5
  108. package/dist/lib/http/routes/health.js +11 -0
  109. package/dist/lib/http/routes/modules.js +27 -0
  110. package/dist/lib/http/routes/panorama.js +12 -12
  111. package/dist/lib/http/routes/recipes.js +66 -8
  112. package/dist/lib/http/routes/remote.js +3 -13
  113. package/dist/lib/http/routes/search.js +11 -8
  114. package/dist/lib/http/utils/routeHelpers.js +2 -1
  115. package/dist/lib/infrastructure/audit/AuditLogger.d.ts +20 -3
  116. package/dist/lib/infrastructure/audit/AuditStore.d.ts +28 -29
  117. package/dist/lib/infrastructure/audit/AuditStore.js +81 -88
  118. package/dist/lib/infrastructure/database/drizzle/schema.d.ts +180 -2
  119. package/dist/lib/infrastructure/database/drizzle/schema.js +23 -3
  120. package/dist/lib/injection/ServiceContainer.d.ts +6 -5
  121. package/dist/lib/injection/ServiceContainer.js +18 -31
  122. package/dist/lib/injection/ServiceMap.d.ts +22 -0
  123. package/dist/lib/injection/modules/AiModule.d.ts +6 -9
  124. package/dist/lib/injection/modules/AiModule.js +82 -39
  125. package/dist/lib/injection/modules/AppModule.js +2 -1
  126. package/dist/lib/injection/modules/GuardModule.js +5 -5
  127. package/dist/lib/injection/modules/InfraModule.js +60 -0
  128. package/dist/lib/injection/modules/KnowledgeModule.js +86 -51
  129. package/dist/lib/injection/modules/PanoramaModule.js +16 -10
  130. package/dist/lib/injection/modules/VectorModule.js +3 -0
  131. package/dist/lib/repository/audit/AuditRepository.d.ts +107 -0
  132. package/dist/lib/repository/audit/AuditRepository.js +272 -0
  133. package/dist/lib/repository/base/RepositoryBase.d.ts +46 -0
  134. package/dist/lib/repository/base/RepositoryBase.js +32 -0
  135. package/dist/lib/repository/bootstrap/BootstrapRepository.d.ts +94 -0
  136. package/dist/lib/repository/bootstrap/BootstrapRepository.js +246 -0
  137. package/dist/lib/repository/code/CodeEntityRepository.d.ts +91 -0
  138. package/dist/lib/repository/code/CodeEntityRepository.js +361 -0
  139. package/dist/lib/repository/delivery/DeliveryRepoAdapter.d.ts +39 -0
  140. package/dist/lib/repository/delivery/DeliveryRepoAdapter.js +23 -0
  141. package/dist/lib/repository/evolution/LifecycleEventRepository.d.ts +51 -0
  142. package/dist/lib/repository/evolution/LifecycleEventRepository.js +119 -0
  143. package/dist/lib/repository/evolution/ProposalRepository.d.ts +9 -12
  144. package/dist/lib/repository/evolution/ProposalRepository.js +114 -57
  145. package/dist/lib/repository/guard/GuardViolationRepository.d.ts +104 -0
  146. package/dist/lib/repository/guard/GuardViolationRepository.js +217 -0
  147. package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.d.ts +129 -0
  148. package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.js +475 -0
  149. package/dist/lib/repository/knowledge/KnowledgeFileStore.d.ts +39 -0
  150. package/dist/lib/repository/knowledge/KnowledgeFileStore.js +12 -0
  151. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +295 -11
  152. package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +608 -13
  153. package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.d.ts +61 -0
  154. package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.js +156 -0
  155. package/dist/lib/repository/memory/MemoryRepository.d.ts +90 -0
  156. package/dist/lib/repository/memory/MemoryRepository.js +260 -0
  157. package/dist/lib/repository/search/SearchRepoAdapter.d.ts +92 -0
  158. package/dist/lib/repository/search/SearchRepoAdapter.js +124 -0
  159. package/dist/lib/repository/session/SessionRepository.d.ts +46 -0
  160. package/dist/lib/repository/session/SessionRepository.js +110 -0
  161. package/dist/lib/repository/sourceref/RecipeSourceRefRepository.d.ts +66 -0
  162. package/dist/lib/repository/sourceref/RecipeSourceRefRepository.js +182 -0
  163. package/dist/lib/repository/sync/SyncRepoAdapter.d.ts +58 -0
  164. package/dist/lib/repository/sync/SyncRepoAdapter.js +58 -0
  165. package/dist/lib/service/bootstrap/UiStartupTasks.js +5 -6
  166. package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +0 -1
  167. package/dist/lib/service/bootstrap/bootstrap-event-types.js +0 -1
  168. package/dist/lib/service/cleanup/CleanupService.d.ts +54 -7
  169. package/dist/lib/service/cleanup/CleanupService.js +291 -40
  170. package/dist/lib/service/delivery/CursorDeliveryPipeline.js +6 -8
  171. package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +4 -9
  172. package/dist/lib/service/evolution/ConsolidationAdvisor.js +34 -70
  173. package/dist/lib/service/evolution/ContentPatcher.d.ts +4 -12
  174. package/dist/lib/service/evolution/ContentPatcher.js +48 -19
  175. package/dist/lib/service/evolution/ContradictionDetector.d.ts +3 -7
  176. package/dist/lib/service/evolution/ContradictionDetector.js +17 -24
  177. package/dist/lib/service/evolution/DecayDetector.d.ts +10 -9
  178. package/dist/lib/service/evolution/DecayDetector.js +63 -57
  179. package/dist/lib/service/evolution/EnhancementSuggester.d.ts +3 -9
  180. package/dist/lib/service/evolution/EnhancementSuggester.js +42 -86
  181. package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +4 -4
  182. package/dist/lib/service/evolution/KnowledgeMetabolism.js +102 -71
  183. package/dist/lib/service/evolution/ProposalExecutor.d.ts +5 -12
  184. package/dist/lib/service/evolution/ProposalExecutor.js +64 -69
  185. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +9 -14
  186. package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +94 -155
  187. package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +4 -1
  188. package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +50 -49
  189. package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +3 -7
  190. package/dist/lib/service/evolution/RedundancyAnalyzer.js +15 -22
  191. package/dist/lib/service/evolution/StagingManager.d.ts +6 -15
  192. package/dist/lib/service/evolution/StagingManager.js +37 -95
  193. package/dist/lib/service/evolution/createSupersedeProposal.d.ts +1 -1
  194. package/dist/lib/service/evolution/createSupersedeProposal.js +7 -8
  195. package/dist/lib/service/guard/CoverageAnalyzer.d.ts +3 -7
  196. package/dist/lib/service/guard/CoverageAnalyzer.js +9 -11
  197. package/dist/lib/service/guard/GuardCheckEngine.d.ts +3 -0
  198. package/dist/lib/service/guard/GuardCheckEngine.js +14 -22
  199. package/dist/lib/service/guard/ReverseGuard.d.ts +4 -7
  200. package/dist/lib/service/guard/ReverseGuard.js +21 -31
  201. package/dist/lib/service/guard/ViolationsStore.d.ts +15 -21
  202. package/dist/lib/service/guard/ViolationsStore.js +75 -69
  203. package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +45 -63
  204. package/dist/lib/service/knowledge/CodeEntityGraph.js +418 -496
  205. package/dist/lib/service/knowledge/ConfidenceRouter.js +18 -9
  206. package/dist/lib/service/knowledge/KnowledgeFileWriter.d.ts +2 -1
  207. package/dist/lib/service/knowledge/KnowledgeGraphService.d.ts +18 -60
  208. package/dist/lib/service/knowledge/KnowledgeGraphService.js +58 -109
  209. package/dist/lib/service/knowledge/KnowledgeService.d.ts +15 -1
  210. package/dist/lib/service/knowledge/KnowledgeService.js +97 -46
  211. package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +0 -2
  212. package/dist/lib/service/knowledge/RecipeProductionGateway.js +0 -2
  213. package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +5 -13
  214. package/dist/lib/service/knowledge/SourceRefReconciler.js +58 -78
  215. package/dist/lib/service/module/ModuleService.js +10 -19
  216. package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +14 -3
  217. package/dist/lib/service/panorama/CouplingAnalyzer.js +137 -32
  218. package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +7 -4
  219. package/dist/lib/service/panorama/DimensionAnalyzer.js +94 -33
  220. package/dist/lib/service/panorama/LayerInferrer.d.ts +16 -1
  221. package/dist/lib/service/panorama/LayerInferrer.js +118 -1
  222. package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +14 -4
  223. package/dist/lib/service/panorama/ModuleDiscoverer.js +209 -61
  224. package/dist/lib/service/panorama/PanoramaAggregator.d.ts +15 -4
  225. package/dist/lib/service/panorama/PanoramaAggregator.js +128 -62
  226. package/dist/lib/service/panorama/PanoramaScanner.d.ts +5 -1
  227. package/dist/lib/service/panorama/PanoramaScanner.js +60 -31
  228. package/dist/lib/service/panorama/PanoramaService.d.ts +11 -8
  229. package/dist/lib/service/panorama/PanoramaService.js +49 -69
  230. package/dist/lib/service/panorama/PanoramaTypes.d.ts +41 -0
  231. package/dist/lib/service/panorama/RoleRefiner.d.ts +10 -5
  232. package/dist/lib/service/panorama/RoleRefiner.js +92 -282
  233. package/dist/lib/service/panorama/TechStackProfiler.d.ts +13 -0
  234. package/dist/lib/service/panorama/TechStackProfiler.js +79 -0
  235. package/dist/lib/service/quality/QualityScorer.d.ts +45 -26
  236. package/dist/lib/service/quality/QualityScorer.js +157 -83
  237. package/dist/lib/service/search/SearchEngine.d.ts +1 -0
  238. package/dist/lib/service/search/SearchEngine.js +32 -37
  239. package/dist/lib/service/signal/HitRecorder.js +5 -5
  240. package/dist/lib/service/skills/RuleRecallStrategy.js +7 -3
  241. package/dist/lib/service/skills/SignalCollector.d.ts +6 -8
  242. package/dist/lib/service/skills/SignalCollector.js +34 -60
  243. package/dist/lib/service/skills/SkillAdvisor.d.ts +7 -13
  244. package/dist/lib/service/skills/SkillAdvisor.js +30 -79
  245. package/dist/lib/service/vector/ContextualEnricher.d.ts +1 -0
  246. package/dist/lib/service/vector/ContextualEnricher.js +4 -0
  247. package/dist/lib/service/vector/SyncCoordinator.d.ts +3 -1
  248. package/dist/lib/service/vector/SyncCoordinator.js +25 -3
  249. package/dist/lib/service/vector/VectorService.d.ts +2 -0
  250. package/dist/lib/service/vector/VectorService.js +3 -0
  251. package/dist/lib/service/wiki/WikiGenerator.js +1 -1
  252. package/dist/lib/shared/LanguageProfiles.d.ts +109 -0
  253. package/dist/lib/shared/LanguageProfiles.js +939 -0
  254. package/dist/lib/shared/LanguageService.d.ts +6 -0
  255. package/dist/lib/shared/LanguageService.js +19 -0
  256. package/dist/lib/shared/constants.d.ts +19 -19
  257. package/dist/lib/shared/constants.js +10 -10
  258. package/dist/lib/shared/developer-identity.d.ts +18 -0
  259. package/dist/lib/shared/developer-identity.js +62 -0
  260. package/dist/lib/shared/schemas/http-requests.d.ts +8 -17
  261. package/dist/lib/shared/schemas/http-requests.js +9 -6
  262. package/dist/lib/shared/schemas/mcp-tools.d.ts +1 -1
  263. package/dist/lib/types/knowledge-wire.d.ts +1 -0
  264. package/dist/lib/types/project-snapshot-builder.d.ts +0 -1
  265. package/dist/lib/types/project-snapshot-builder.js +0 -1
  266. package/dist/lib/types/project-snapshot.d.ts +0 -1
  267. package/dist/lib/types/project-snapshot.js +0 -1
  268. package/dist/lib/types/snapshot-views.d.ts +0 -2
  269. package/dist/lib/types/snapshot-views.js +0 -1
  270. package/package.json +2 -1
  271. package/dashboard/dist/assets/icons-D1aVZYFW.js +0 -1
  272. package/dashboard/dist/assets/index-CxHOu8Hd.css +0 -1
  273. package/dashboard/dist/assets/index-DDdAOpYT.js +0 -128
  274. package/dist/lib/repository/base/BaseRepository.d.ts +0 -53
  275. package/dist/lib/repository/base/BaseRepository.js +0 -226
@@ -0,0 +1,193 @@
1
+ /**
2
+ * AiProviderManager — 统一 AI 提供商管理器(切面层)
3
+ *
4
+ * 设计目标:
5
+ * 1. 唯一权威: 当前 AI Provider 的唯一管理入口,所有读取/切换集中在此
6
+ * 2. AOP 切面: Token 追踪回调随 Provider 切换自动重新挂载,无需外部干预
7
+ * 3. 热切换: switchProvider() 一次调用 → Token AOP + Embedding fallback + DI 级联清理 + 事件通知
8
+ * 4. 模式查询: isMock / isReady 集中管理,消除散落的 name === 'mock' 判断
9
+ * 5. 事件驱动: 注册监听器,切换时自动回调(Realtime 广播、SearchEngine 重建等)
10
+ *
11
+ * 集成方式:
12
+ * - 由 AiModule.initialize() 创建并注入 DI 容器
13
+ * - ServiceContainer.reloadAiProvider() 委托 manager.switchProvider()
14
+ * - 消费者通过 container.get('aiProviderManager') 获取
15
+ * - DI 数据管道: switchProvider() 通过回调同步 singletons 中的 provider 引用
16
+ */
17
+ import Logger from '#infra/logging/Logger.js';
18
+ // ── Manager ────────────────────────────────────────────
19
+ export class AiProviderManager {
20
+ #provider;
21
+ #embedProvider = null;
22
+ #tokenRecorder = null;
23
+ #listeners = new Set();
24
+ #logger = Logger.getInstance();
25
+ /** DI 容器注入: 清除 AI 依赖 singleton 的回调 */
26
+ #clearDependents = null;
27
+ /** DI 容器注入: Embedding fallback 初始化器 */
28
+ #embedFallbackInit = null;
29
+ /** DI 数据管道: 切换时同步 singletons 中的 provider 引用(供 DI 工厂函数读取) */
30
+ #syncToDi = null;
31
+ constructor(initialProvider) {
32
+ this.#provider = initialProvider;
33
+ this.#wireTokenTracking();
34
+ }
35
+ // ═══════════════════════════════════════════════════════
36
+ // 读取接口
37
+ // ═══════════════════════════════════════════════════════
38
+ /** 当前 AI Provider (只读) */
39
+ get provider() {
40
+ return this.#provider;
41
+ }
42
+ /** 当前 Embedding Provider (优先 fallback,回退到主 provider) */
43
+ get embedProvider() {
44
+ return this.#embedProvider ?? this.#provider;
45
+ }
46
+ /** 原始 Embedding fallback (可能为 null) */
47
+ get rawEmbedProvider() {
48
+ return this.#embedProvider;
49
+ }
50
+ /** 是否处于 Mock 模式 */
51
+ get isMock() {
52
+ return this.#provider.name === 'mock';
53
+ }
54
+ /** provider 是否可用于 AI 操作(非 mock) */
55
+ get isReady() {
56
+ return !!this.#provider && !this.isMock;
57
+ }
58
+ /** 当前 provider 名称 */
59
+ get name() {
60
+ return this.#provider.name;
61
+ }
62
+ /** 当前模型 */
63
+ get model() {
64
+ return this.#provider.model;
65
+ }
66
+ /** 结构化信息快照 */
67
+ get info() {
68
+ return {
69
+ name: this.#provider.name,
70
+ model: this.#provider.model,
71
+ isMock: this.isMock,
72
+ supportsEmbedding: typeof this.#provider.supportsEmbedding === 'function' &&
73
+ this.#provider.supportsEmbedding(),
74
+ };
75
+ }
76
+ // ═══════════════════════════════════════════════════════
77
+ // 热切换 — 唯一的全局切换入口
78
+ // ═══════════════════════════════════════════════════════
79
+ /**
80
+ * 切换 AI Provider — 原子操作
81
+ *
82
+ * 自动处理:
83
+ * 1. Token 追踪 AOP 重新挂载
84
+ * 2. Embedding fallback 重建
85
+ * 3. DI 数据管道同步(singletons.aiProvider)
86
+ * 4. DI 容器中的 AI 依赖 singleton 级联清除
87
+ * 5. 监听器回调通知
88
+ */
89
+ switchProvider(newProvider) {
90
+ const prev = this.info;
91
+ // 1. 替换核心引用
92
+ this.#provider = newProvider;
93
+ // 2. AOP: 重新挂载 Token 追踪
94
+ this.#wireTokenTracking();
95
+ // 3. Embedding fallback 重建
96
+ this.#embedProvider = null;
97
+ if (this.#embedFallbackInit) {
98
+ this.#embedProvider = this.#embedFallbackInit(newProvider);
99
+ }
100
+ // 4. DI 数据管道同步
101
+ this.#syncToDi?.(this.#provider, this.#embedProvider);
102
+ // 5. 清除 DI 容器中的依赖 singleton
103
+ const clearedSingletons = this.#clearDependents?.() ?? [];
104
+ const result = {
105
+ previous: prev,
106
+ current: this.info,
107
+ clearedSingletons,
108
+ };
109
+ // 6. 通知监听器
110
+ for (const fn of this.#listeners) {
111
+ try {
112
+ fn(result);
113
+ }
114
+ catch {
115
+ /* listener should not break switching */
116
+ }
117
+ }
118
+ this.#logger.info('[AiProviderManager] Provider switched', {
119
+ from: `${prev.name}/${prev.model}`,
120
+ to: `${result.current.name}/${result.current.model}`,
121
+ mock: result.current.isMock,
122
+ cleared: clearedSingletons,
123
+ });
124
+ return result;
125
+ }
126
+ // ═══════════════════════════════════════════════════════
127
+ // Embedding 管理
128
+ // ═══════════════════════════════════════════════════════
129
+ /** 手动设置 Embedding fallback provider */
130
+ setEmbedProvider(ep) {
131
+ this.#embedProvider = ep;
132
+ }
133
+ // ═══════════════════════════════════════════════════════
134
+ // AOP: Token 追踪
135
+ // ═══════════════════════════════════════════════════════
136
+ /** 注入 TokenRecorder (延迟绑定,避免循环依赖) */
137
+ setTokenRecorder(recorder) {
138
+ this.#tokenRecorder = recorder;
139
+ this.#wireTokenTracking();
140
+ }
141
+ /**
142
+ * 在当前 provider 上安装 _onTokenUsage 回调
143
+ * 每次 provider.chat() / chatWithTools() 等调用后自动触发
144
+ */
145
+ #wireTokenTracking() {
146
+ const p = this.#provider;
147
+ if (!p || typeof p !== 'object') {
148
+ return;
149
+ }
150
+ p._onTokenUsage = (usage) => {
151
+ if (!this.#tokenRecorder) {
152
+ return;
153
+ }
154
+ try {
155
+ this.#tokenRecorder.record({
156
+ source: usage.source || 'provider',
157
+ provider: p.name ?? undefined,
158
+ model: p.model ?? undefined,
159
+ inputTokens: usage.inputTokens || 0,
160
+ outputTokens: usage.outputTokens || 0,
161
+ });
162
+ }
163
+ catch {
164
+ /* token tracking never breaks execution */
165
+ }
166
+ };
167
+ }
168
+ // ═══════════════════════════════════════════════════════
169
+ // 事件
170
+ // ═══════════════════════════════════════════════════════
171
+ /** 注册切换监听器,返回取消注册函数 */
172
+ onSwitch(fn) {
173
+ this.#listeners.add(fn);
174
+ return () => {
175
+ this.#listeners.delete(fn);
176
+ };
177
+ }
178
+ // ═══════════════════════════════════════════════════════
179
+ // DI 绑定 (仅 ServiceContainer / AiModule 调用)
180
+ // ═══════════════════════════════════════════════════════
181
+ /** 注入 DI 容器的级联清理回调 */
182
+ _bindDependentClearer(fn) {
183
+ this.#clearDependents = fn;
184
+ }
185
+ /** 注入 Embedding Fallback 初始化器 */
186
+ _bindEmbedFallbackInit(fn) {
187
+ this.#embedFallbackInit = fn;
188
+ }
189
+ /** 注入 DI 数据管道同步回调(切换时更新 singletons 中的 provider 引用) */
190
+ _bindDiSync(fn) {
191
+ this.#syncToDi = fn;
192
+ }
193
+ }
@@ -36,7 +36,18 @@ export class ClaudeProvider extends AiProvider {
36
36
  max_tokens: maxTokens,
37
37
  temperature,
38
38
  };
39
+ if (context.systemPrompt) {
40
+ body.system = context.systemPrompt;
41
+ }
39
42
  const data = await this._post(`${CLAUDE_BASE}/messages`, body);
43
+ // 提取 token 用量
44
+ if (data?.usage) {
45
+ this._emitTokenUsage({
46
+ inputTokens: data.usage.input_tokens || 0,
47
+ outputTokens: data.usage.output_tokens || 0,
48
+ totalTokens: (data.usage.input_tokens || 0) + (data.usage.output_tokens || 0),
49
+ });
50
+ }
40
51
  const textBlock = (data?.content || []).find((c) => c.type === 'text');
41
52
  return textBlock?.text || '';
42
53
  }
@@ -50,6 +50,15 @@ export class GoogleGeminiProvider extends AiProvider {
50
50
  }
51
51
  const url = `${GEMINI_BASE}/models/${this.model}:generateContent?key=${this.apiKey}`;
52
52
  const data = await this._post(url, body);
53
+ // 提取 token 用量
54
+ if (data?.usageMetadata) {
55
+ this._emitTokenUsage({
56
+ inputTokens: data.usageMetadata.promptTokenCount || 0,
57
+ outputTokens: data.usageMetadata.candidatesTokenCount || 0,
58
+ totalTokens: (data.usageMetadata.promptTokenCount || 0) +
59
+ (data.usageMetadata.candidatesTokenCount || 0),
60
+ });
61
+ }
53
62
  return data?.candidates?.[0]?.content?.parts?.[0]?.text || '';
54
63
  });
55
64
  }
@@ -306,6 +315,15 @@ export class GoogleGeminiProvider extends AiProvider {
306
315
  }
307
316
  const url = `${GEMINI_BASE}/models/${this.model}:generateContent?key=${this.apiKey}`;
308
317
  const data = await this._post(url, body);
318
+ // 提取 token 用量
319
+ if (data?.usageMetadata) {
320
+ this._emitTokenUsage({
321
+ inputTokens: data.usageMetadata.promptTokenCount || 0,
322
+ outputTokens: data.usageMetadata.candidatesTokenCount || 0,
323
+ totalTokens: (data.usageMetadata.promptTokenCount || 0) +
324
+ (data.usageMetadata.candidatesTokenCount || 0),
325
+ });
326
+ }
309
327
  const text = data?.candidates?.[0]?.content?.parts?.[0]?.text || '';
310
328
  if (!text) {
311
329
  return null;
@@ -1,8 +1,23 @@
1
1
  /**
2
- * MockProvider - 测试用 AI 提供商
3
- * 返回固定/随机数据,不发网络请求
2
+ * MockProvider Smart Mock AI 提供商
3
+ *
4
+ * 不发网络请求,但根据 prompt 内容智能匹配场景,返回符合格式的仿真响应。
5
+ * 用于让用户在没有 API Key 的情况下体验 AutoSnippet 完整工作流。
6
+ *
7
+ * 智能匹配场景:
8
+ * 1. probe / ping → "pong"
9
+ * 2. 重复度检测 (DUPLICATE/SIMILAR/UNIQUE) → "UNIQUE"
10
+ * 3. 对话压缩总结 → 从消息中提取关键词
11
+ * 4. 代码上下文化 (<chunk>) → 从代码提取函数/类名
12
+ * 5. 候选润色 (JSON 9字段) → 原样回传输入字段
13
+ * 6. 维度摘要 (dimensionDigest) → 模板化 JSON
14
+ * 7. 风格检查建议 → 空数组
15
+ * 8. Agent 路由分类 → functionCall classify_intent
16
+ * 9. 通用 fallback → 语义化占位文本
17
+ *
18
+ * 模拟延迟: 50-200ms 随机延迟,营造 "AI 思考" 体验
4
19
  */
5
- import { AiProvider, type AiProviderConfig, type ChatContext } from '../AiProvider.js';
20
+ import { AiProvider, type AiProviderConfig, type ChatContext, type ChatWithToolsOptions, type ChatWithToolsResult, type StructuredOutputOptions } from '../AiProvider.js';
6
21
  interface MockResponses {
7
22
  chat?: string;
8
23
  summarize?: Record<string, unknown>;
@@ -19,8 +34,11 @@ export declare class MockProvider extends AiProvider {
19
34
  responses?: MockResponses;
20
35
  });
21
36
  chat(prompt: string, context?: ChatContext): Promise<string>;
37
+ chatWithTools(prompt: string, opts?: ChatWithToolsOptions): Promise<ChatWithToolsResult>;
38
+ chatWithStructuredOutput(prompt: string, opts?: StructuredOutputOptions): Promise<unknown>;
22
39
  summarize(code: string): Promise<Record<string, unknown>>;
23
40
  embed(text: string | string[]): Promise<number[] | number[][]>;
41
+ probe(): Promise<boolean>;
24
42
  /** 获取调用日志(测试断言用) */
25
43
  getCalls(): CallLogEntry[];
26
44
  /** 重置调用记录 */
@@ -1,47 +1,323 @@
1
1
  /**
2
- * MockProvider - 测试用 AI 提供商
3
- * 返回固定/随机数据,不发网络请求
2
+ * MockProvider Smart Mock AI 提供商
3
+ *
4
+ * 不发网络请求,但根据 prompt 内容智能匹配场景,返回符合格式的仿真响应。
5
+ * 用于让用户在没有 API Key 的情况下体验 AutoSnippet 完整工作流。
6
+ *
7
+ * 智能匹配场景:
8
+ * 1. probe / ping → "pong"
9
+ * 2. 重复度检测 (DUPLICATE/SIMILAR/UNIQUE) → "UNIQUE"
10
+ * 3. 对话压缩总结 → 从消息中提取关键词
11
+ * 4. 代码上下文化 (<chunk>) → 从代码提取函数/类名
12
+ * 5. 候选润色 (JSON 9字段) → 原样回传输入字段
13
+ * 6. 维度摘要 (dimensionDigest) → 模板化 JSON
14
+ * 7. 风格检查建议 → 空数组
15
+ * 8. Agent 路由分类 → functionCall classify_intent
16
+ * 9. 通用 fallback → 语义化占位文本
17
+ *
18
+ * 模拟延迟: 50-200ms 随机延迟,营造 "AI 思考" 体验
4
19
  */
5
- import { AiProvider } from '../AiProvider.js';
20
+ import { AiProvider, } from '../AiProvider.js';
21
+ // ── 工具函数 ──────────────────────────────────────────────
22
+ /** 模拟延迟 (50-200ms) */
23
+ function mockDelay() {
24
+ const ms = 50 + Math.floor(Math.random() * 150);
25
+ return new Promise((resolve) => setTimeout(resolve, ms));
26
+ }
27
+ /** 模拟 token 用量 */
28
+ function mockUsage(prompt, response) {
29
+ return {
30
+ inputTokens: Math.ceil(prompt.length / 4),
31
+ outputTokens: Math.ceil(response.length / 4),
32
+ totalTokens: Math.ceil(prompt.length / 4) + Math.ceil(response.length / 4),
33
+ };
34
+ }
35
+ /** 从代码片段中提取函数/类/结构名称 */
36
+ function extractCodeSymbols(code) {
37
+ const symbols = [];
38
+ // Swift/TS class/struct/protocol/enum
39
+ for (const m of code.matchAll(/(?:class|struct|protocol|enum|interface|type)\s+(\w+)/g)) {
40
+ symbols.push(m[1]);
41
+ }
42
+ // func/function
43
+ for (const m of code.matchAll(/(?:func|function)\s+(\w+)/g)) {
44
+ symbols.push(m[1]);
45
+ }
46
+ // property patterns
47
+ for (const m of code.matchAll(/(?:let|var|const)\s+(\w+)/g)) {
48
+ if (m[1].length > 3) {
49
+ symbols.push(m[1]);
50
+ }
51
+ }
52
+ return [...new Set(symbols)].slice(0, 8);
53
+ }
54
+ /** 从 prompt 中尝试提取 JSON 输入(用于润色回传) */
55
+ function extractJsonFromPrompt(prompt) {
56
+ try {
57
+ const match = prompt.match(/\{[\s\S]*?"description"[\s\S]*?\}/);
58
+ if (match) {
59
+ return JSON.parse(match[0]);
60
+ }
61
+ }
62
+ catch {
63
+ /* parse failed */
64
+ }
65
+ return null;
66
+ }
67
+ // ── MockProvider ─────────────────────────────────────────
6
68
  export class MockProvider extends AiProvider {
7
69
  callLog;
8
70
  responses;
9
71
  constructor(config = {}) {
10
72
  super(config);
11
73
  this.name = 'mock';
12
- this.model = 'mock-model';
74
+ this.model = 'mock-smart';
13
75
  this.responses = config.responses || {};
14
76
  this.callLog = [];
15
77
  }
78
+ // ── 核心: chat() 智能路由 ──────────────────────────────
16
79
  async chat(prompt, context = {}) {
17
- this.callLog.push({ method: 'chat', prompt, context });
80
+ this.callLog.push({ method: 'chat', prompt: prompt.slice(0, 200), context });
81
+ await mockDelay();
82
+ // 0. 用户注入的固定响应(单元测试用)
18
83
  if (this.responses.chat) {
19
84
  return this.responses.chat;
20
85
  }
21
- return `Mock response for: ${prompt.slice(0, 80)}`;
86
+ const p = prompt.toLowerCase();
87
+ // 1. Probe / ping
88
+ if (p === 'ping' || p.includes('ping')) {
89
+ return 'pong';
90
+ }
91
+ // 2. 重复度检测 — "请回答: DUPLICATE / SIMILAR / UNIQUE"
92
+ if (p.includes('duplicate') && p.includes('similar') && p.includes('unique')) {
93
+ return 'UNIQUE';
94
+ }
95
+ // 3. 对话压缩总结 — "请用 2-3 句话总结"
96
+ if (p.includes('总结以下对话') || p.includes('summarize the following')) {
97
+ const lines = prompt
98
+ .split('\n')
99
+ .filter((l) => l.startsWith('[user]') || l.startsWith('[assistant]'));
100
+ const topics = lines
101
+ .slice(0, 3)
102
+ .map((l) => l.slice(0, 60))
103
+ .join(';');
104
+ return `[Mock 摘要] 对话涉及: ${topics || '项目开发相关讨论'}。用户和助手讨论了代码实现和架构设计。`;
105
+ }
106
+ // 4. 代码上下文化 — <chunk>...</chunk>
107
+ if (p.includes('<chunk>')) {
108
+ const chunkMatch = prompt.match(/<chunk>([\s\S]*?)<\/chunk>/);
109
+ if (chunkMatch) {
110
+ const symbols = extractCodeSymbols(chunkMatch[1]);
111
+ if (symbols.length > 0) {
112
+ return `This chunk defines ${symbols.slice(0, 3).join(', ')} which handles ${symbols.length > 3 ? symbols.slice(3, 5).join(' and ') : 'core logic'} in the module.`;
113
+ }
114
+ return 'This chunk contains utility code for the module.';
115
+ }
116
+ }
117
+ // 5. 候选润色 — "知识库条目润色助手" + JSON 输出
118
+ if (p.includes('知识库条目润色') || p.includes('润色助手')) {
119
+ const existing = extractJsonFromPrompt(prompt);
120
+ if (existing) {
121
+ return JSON.stringify(existing);
122
+ }
123
+ return JSON.stringify({
124
+ description: '[Mock] 保持原内容不变',
125
+ pattern: '',
126
+ markdown: '',
127
+ rationale: '',
128
+ tags: [],
129
+ confidence: 0.8,
130
+ aiInsight: null,
131
+ agentNotes: null,
132
+ relations: {},
133
+ });
134
+ }
135
+ // 6. 维度摘要 — "dimensionDigest"
136
+ if (p.includes('dimensiondigest') || p.includes('dimension digest')) {
137
+ const dimMatch = prompt.match(/维度[::]\s*["']?(\w[\w-]+)/i) ||
138
+ prompt.match(/dimension[::]\s*["']?(\w[\w-]+)/i);
139
+ const dimId = dimMatch?.[1] || 'unknown';
140
+ const countMatch = prompt.match(/提交了\s*(\d+)\s*个候选/);
141
+ const count = countMatch ? parseInt(countMatch[1], 10) : 3;
142
+ return `\`\`\`json
143
+ ${JSON.stringify({
144
+ dimensionDigest: {
145
+ summary: `[Mock] ${dimId} 维度分析完成,基于项目代码结构生成了 ${count} 个候选知识。`,
146
+ candidateCount: count,
147
+ keyFindings: ['项目采用模块化架构设计', '发现多个核心设计模式', '代码风格整体一致'],
148
+ crossRefs: {},
149
+ gaps: ['部分模块缺少充分的文档注释'],
150
+ remainingTasks: [],
151
+ },
152
+ }, null, 2)}
153
+ \`\`\``;
154
+ }
155
+ // 7. 风格检查建议 — "violation" + "suggestion"
156
+ if (p.includes('violation') && p.includes('suggestion')) {
157
+ return '[]';
158
+ }
159
+ // 8. 分析报告 — "Markdown 格式" + "代码分析报告"
160
+ if (p.includes('代码分析报告') || p.includes('分析报告')) {
161
+ const symbols = extractCodeSymbols(prompt);
162
+ return `## Mock 代码分析报告
163
+
164
+ ### 核心发现
165
+
166
+ 1. **模块结构**: 项目采用分层架构,${symbols.length > 0 ? `核心类型包括 ${symbols.slice(0, 3).join('、')}` : '各模块职责清晰'}
167
+ 2. **设计模式**: 广泛使用协议/接口抽象和依赖注入
168
+ 3. **代码质量**: 类型安全处理规范,错误处理完善
169
+
170
+ ### 文件分析
171
+
172
+ 分析的文件展现了良好的代码组织,模块间通过明确的接口通信。
173
+
174
+ > ⚠️ 此报告由 Mock AI 生成,仅包含模板化分析结果。`;
175
+ }
176
+ // 9. 通用 fallback — 语义化占位
177
+ const symbols = extractCodeSymbols(prompt);
178
+ const topic = symbols.length > 0
179
+ ? `关于 ${symbols.slice(0, 3).join('、')} 的分析`
180
+ : `对 ${prompt.slice(0, 40).replace(/\n/g, ' ')} 的回复`;
181
+ return `[Mock AI] ${topic}。此响应由 Mock 模式生成,非真实 AI 分析结果。`;
182
+ }
183
+ // ── chatWithTools() — 智能函数调用模拟 ─────────────────
184
+ async chatWithTools(prompt, opts = {}) {
185
+ this.callLog.push({
186
+ method: 'chatWithTools',
187
+ prompt: prompt.slice(0, 200),
188
+ toolChoice: opts.toolChoice,
189
+ });
190
+ await mockDelay();
191
+ const schemas = (opts.toolSchemas || []);
192
+ const schemaNames = schemas.map((s) => s.name);
193
+ // toolChoice='none' → 纯文本回复(维度摘要、最终总结等)
194
+ if (opts.toolChoice === 'none') {
195
+ const text = await this.chat(prompt, {
196
+ systemPrompt: opts.systemPrompt,
197
+ temperature: opts.temperature,
198
+ maxTokens: opts.maxTokens,
199
+ });
200
+ return { text, functionCalls: null, usage: mockUsage(prompt, text) };
201
+ }
202
+ // Agent 路由分类 — classify_intent tool
203
+ if (schemaNames.includes('classify_intent')) {
204
+ const response = JSON.stringify({ type: 'general', confidence: 0.9 });
205
+ return {
206
+ text: null,
207
+ functionCalls: [
208
+ {
209
+ id: `mock-fc-${Date.now()}`,
210
+ name: 'classify_intent',
211
+ args: { type: 'general', confidence: 0.9 },
212
+ },
213
+ ],
214
+ usage: mockUsage(prompt, response),
215
+ };
216
+ }
217
+ // 有 tool schemas → 返回文本(让 AgentRuntime 的文本解析处理)
218
+ // Mock 不模拟复杂的多步工具调用链 — bootstrap 走 lightweight pipeline
219
+ if (schemas.length > 0) {
220
+ const text = `[Mock] 我已完成对项目代码的分析。基于代码结构,发现了几个关键的设计模式和架构约定。
221
+
222
+ 以下是主要发现:
223
+ 1. 项目采用模块化分层架构
224
+ 2. 核心模块使用依赖注入模式
225
+ 3. 错误处理遵循统一的类型安全约定
226
+
227
+ > 此分析由 Mock AI 生成,结果基于模板。切换到真实 AI Provider 可获得深度项目分析。`;
228
+ return { text, functionCalls: null, usage: mockUsage(prompt, text) };
229
+ }
230
+ // 无 tools → 纯文本
231
+ const text = await this.chat(prompt, {
232
+ systemPrompt: opts.systemPrompt,
233
+ temperature: opts.temperature,
234
+ maxTokens: opts.maxTokens,
235
+ });
236
+ return { text, functionCalls: null, usage: mockUsage(prompt, text) };
22
237
  }
238
+ // ── chatWithStructuredOutput() — 结构化 JSON 模拟 ──────
239
+ async chatWithStructuredOutput(prompt, opts = {}) {
240
+ this.callLog.push({ method: 'chatWithStructuredOutput', prompt: prompt.slice(0, 200) });
241
+ await mockDelay();
242
+ const p = prompt.toLowerCase();
243
+ // 候选润色 → 尝试回传 prompt 中的 JSON
244
+ if (p.includes('润色') || p.includes('refine')) {
245
+ const existing = extractJsonFromPrompt(prompt);
246
+ if (existing) {
247
+ return existing;
248
+ }
249
+ return {
250
+ description: '[Mock] 保持原内容',
251
+ pattern: '',
252
+ markdown: '',
253
+ rationale: '',
254
+ tags: [],
255
+ confidence: 0.8,
256
+ aiInsight: null,
257
+ agentNotes: null,
258
+ relations: {},
259
+ };
260
+ }
261
+ // 风格检查 → 空数组
262
+ if (opts.openChar === '[' || p.includes('violation')) {
263
+ return [];
264
+ }
265
+ // 通用 → 尝试从 prompt 中提取已有 JSON,否则返回空对象
266
+ const existing = extractJsonFromPrompt(prompt);
267
+ return existing || {};
268
+ }
269
+ // ── summarize() — 代码摘要 ─────────────────────────────
23
270
  async summarize(code) {
24
271
  this.callLog.push({ method: 'summarize', code: code?.slice(0, 80) });
272
+ await mockDelay();
25
273
  if (this.responses.summarize) {
26
274
  return this.responses.summarize;
27
275
  }
276
+ const symbols = extractCodeSymbols(code || '');
277
+ const lang = code?.includes('func ')
278
+ ? 'swift'
279
+ : code?.includes('function ')
280
+ ? 'typescript'
281
+ : code?.includes('def ')
282
+ ? 'python'
283
+ : 'unknown';
28
284
  return {
29
- title: 'Mock Summary',
30
- description: `Summary of ${code?.length || 0} chars`,
31
- language: 'unknown',
32
- patterns: [],
33
- keyAPIs: [],
285
+ title: symbols.length > 0 ? `${symbols[0]} 模块` : 'Mock Summary',
286
+ description: symbols.length > 0
287
+ ? `定义了 ${symbols.slice(0, 3).join('')} 等 ${symbols.length} 个核心类型`
288
+ : `Summary of ${code?.length || 0} chars`,
289
+ language: lang,
290
+ patterns: symbols.slice(0, 3).map((s) => `${s} pattern`),
291
+ keyAPIs: symbols.slice(0, 4),
34
292
  };
35
293
  }
294
+ // ── embed() — 确定性伪向量 ─────────────────────────────
36
295
  async embed(text) {
37
296
  this.callLog.push({ method: 'embed', text: Array.isArray(text) ? text.length : 1 });
297
+ // 使用基于内容的确定性哈希生成向量(相似文本产生相似向量)
38
298
  const dim = 768;
39
- const makeVector = () => Array.from({ length: dim }, () => Math.random() * 2 - 1);
299
+ const makeVector = (input) => {
300
+ let hash = 0;
301
+ for (let i = 0; i < input.length; i++) {
302
+ hash = ((hash << 5) - hash + input.charCodeAt(i)) | 0;
303
+ }
304
+ return Array.from({ length: dim }, (_, i) => {
305
+ // 基于 hash + 位置的伪随机,范围 [-1, 1]
306
+ const x = Math.sin(hash * 0.001 + i * 0.7127) * 43758.5453;
307
+ return (x - Math.floor(x)) * 2 - 1;
308
+ });
309
+ };
40
310
  if (Array.isArray(text)) {
41
- return text.map(() => makeVector());
311
+ return text.map((t) => makeVector(t));
42
312
  }
43
- return makeVector();
313
+ return makeVector(text);
314
+ }
315
+ // ── probe() — 连接检测 ────────────────────────────────
316
+ async probe() {
317
+ this.callLog.push({ method: 'probe' });
318
+ return true;
44
319
  }
320
+ // ── 辅助方法 ──────────────────────────────────────────
45
321
  /** 获取调用日志(测试断言用) */
46
322
  getCalls() {
47
323
  return this.callLog;
@@ -42,6 +42,14 @@ export class OpenAiProvider extends AiProvider {
42
42
  max_tokens: maxTokens,
43
43
  };
44
44
  const data = await this._post(`${this.baseUrl}/chat/completions`, body);
45
+ // 提取 token 用量
46
+ if (data?.usage) {
47
+ this._emitTokenUsage({
48
+ inputTokens: data.usage.prompt_tokens || 0,
49
+ outputTokens: data.usage.completion_tokens || 0,
50
+ totalTokens: data.usage.total_tokens || 0,
51
+ });
52
+ }
45
53
  return data?.choices?.[0]?.message?.content || '';
46
54
  });
47
55
  }
@@ -197,6 +205,14 @@ export class OpenAiProvider extends AiProvider {
197
205
  response_format: { type: 'json_object' },
198
206
  };
199
207
  const data = await this._post(`${this.baseUrl}/chat/completions`, body);
208
+ // 提取 token 用量
209
+ if (data?.usage) {
210
+ this._emitTokenUsage({
211
+ inputTokens: data.usage.prompt_tokens || 0,
212
+ outputTokens: data.usage.completion_tokens || 0,
213
+ totalTokens: data.usage.total_tokens || 0,
214
+ });
215
+ }
200
216
  const text = data?.choices?.[0]?.message?.content || '';
201
217
  if (!text) {
202
218
  return null;
@@ -21,6 +21,10 @@ import type { AgentRuntime } from '#agent/AgentRuntime.js';
21
21
  interface AgentFactory {
22
22
  createLark(opts: RuntimeOverrides): AgentRuntime;
23
23
  createRemoteExec(opts: RuntimeOverrides): AgentRuntime;
24
+ getAiProviderInfo(): {
25
+ name: string;
26
+ model?: string;
27
+ };
24
28
  }
25
29
  interface RuntimeOverrides {
26
30
  lang?: string;
@@ -34,7 +38,7 @@ interface ProgressEvent {
34
38
  interface LarkTransportConfig {
35
39
  agentFactory: AgentFactory;
36
40
  replyFn: (messageId: string, text: string) => Promise<void>;
37
- sendFn: (text: string) => Promise<void | boolean>;
41
+ sendFn: (text: string) => Promise<undefined | boolean>;
38
42
  sendImageFn?: (caption: string) => Promise<{
39
43
  success: boolean;
40
44
  message: string;