minimal-agent 0.10.0 → 0.12.0

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 (573) hide show
  1. package/README.md +11 -3
  2. package/package.json +52 -5
  3. package/plugins/computer_use/.claude-plugin/plugin.json +6 -0
  4. package/plugins/computer_use/README.md +94 -0
  5. package/plugins/computer_use/app/_template.md +142 -0
  6. package/plugins/computer_use/app/chrome.md +165 -0
  7. package/plugins/computer_use/app/finder.md +76 -0
  8. package/plugins/computer_use/app/macos-system-settings.md +81 -0
  9. package/plugins/computer_use/app/microsoft-excel.md +80 -0
  10. package/plugins/computer_use/app/microsoft-powerpoint.md +80 -0
  11. package/plugins/computer_use/app/microsoft-word.md +79 -0
  12. package/plugins/computer_use/app/wechat.md +413 -0
  13. package/plugins/computer_use/app/weread.md +319 -0
  14. package/plugins/computer_use/commands/computeruse.md +25 -0
  15. package/plugins/computer_use/commands/cu.md +9 -0
  16. package/plugins/computer_use/plugin.js +26 -0
  17. package/plugins/computer_use/plugin.ts +30 -0
  18. package/plugins/computer_use/src/capture.js +90 -0
  19. package/plugins/computer_use/src/capture.ts +104 -0
  20. package/plugins/computer_use/src/commands.js +91 -0
  21. package/plugins/computer_use/src/commands.ts +103 -0
  22. package/plugins/computer_use/src/daemon.js +134 -0
  23. package/plugins/computer_use/src/daemon.ts +161 -0
  24. package/plugins/computer_use/src/manuals.js +135 -0
  25. package/plugins/computer_use/src/manuals.ts +159 -0
  26. package/plugins/computer_use/src/verify.js +168 -0
  27. package/plugins/computer_use/src/verify.ts +219 -0
  28. package/plugins/computer_use/test/commands.test.ts +73 -0
  29. package/plugins/cron-runner/plugin.ts +38 -0
  30. package/plugins/cron-runner/src/commands.ts +373 -0
  31. package/plugins/cron-runner/src/cronTime.ts +155 -0
  32. package/plugins/cron-runner/src/lock.ts +79 -0
  33. package/plugins/cron-runner/src/runs.ts +99 -0
  34. package/plugins/cron-runner/src/scheduleEngine.ts +76 -0
  35. package/plugins/cron-runner/src/scheduler.ts +376 -0
  36. package/plugins/cron-runner/src/schema.ts +139 -0
  37. package/plugins/cron-runner/src/service.ts +193 -0
  38. package/plugins/cron-runner/src/store.ts +333 -0
  39. package/plugins/cron-runner/src/types.ts +141 -0
  40. package/plugins/cron-runner/test/cronTime.test.ts +41 -0
  41. package/plugins/cron-runner/test/plugin-integration.test.ts +47 -0
  42. package/plugins/cron-runner/test/scheduleEngine.test.ts +41 -0
  43. package/plugins/cron-runner/test/service.test.ts +76 -0
  44. package/plugins/cron-runner/test/store-and-scheduler.test.ts +501 -0
  45. package/plugins/workflow-runner/plugin.js +56 -2
  46. package/plugins/workflow-runner/plugin.ts +113 -0
  47. package/plugins/workflow-runner/src/agentCommon.js +43 -4
  48. package/plugins/workflow-runner/src/agentCommon.ts +435 -0
  49. package/plugins/workflow-runner/src/controlFlow/branch.js +40 -0
  50. package/plugins/workflow-runner/src/controlFlow/branch.ts +46 -0
  51. package/plugins/workflow-runner/src/controlFlow/loop.js +211 -0
  52. package/plugins/workflow-runner/src/controlFlow/loop.ts +248 -0
  53. package/plugins/workflow-runner/src/controlFlow/pause.js +129 -0
  54. package/plugins/workflow-runner/src/controlFlow/pause.ts +141 -0
  55. package/plugins/workflow-runner/src/controlFlow/signal.js +21 -0
  56. package/plugins/workflow-runner/src/controlFlow/signal.ts +29 -0
  57. package/plugins/workflow-runner/src/controlFlow/types.js +18 -0
  58. package/plugins/workflow-runner/src/controlFlow/types.ts +63 -0
  59. package/plugins/workflow-runner/src/dslManifest.ts +127 -0
  60. package/plugins/workflow-runner/src/expressions.ts +622 -0
  61. package/plugins/workflow-runner/src/index.js +13 -4
  62. package/plugins/workflow-runner/src/index.ts +338 -0
  63. package/plugins/workflow-runner/src/jsonPayload.ts +84 -0
  64. package/plugins/workflow-runner/src/loader.js +23 -0
  65. package/plugins/workflow-runner/src/loader.ts +721 -0
  66. package/plugins/workflow-runner/src/multimodal.js +2 -1
  67. package/plugins/workflow-runner/src/multimodal.ts +64 -0
  68. package/plugins/workflow-runner/src/recovery.ts +149 -0
  69. package/plugins/workflow-runner/src/runner.js +75 -659
  70. package/plugins/workflow-runner/src/runner.ts +604 -0
  71. package/plugins/workflow-runner/src/stepExecutors/agent.ts +234 -0
  72. package/plugins/workflow-runner/src/stepExecutors/assert.ts +50 -0
  73. package/plugins/workflow-runner/src/stepExecutors/echo.js +31 -0
  74. package/plugins/workflow-runner/src/stepExecutors/echo.ts +38 -0
  75. package/plugins/workflow-runner/src/stepExecutors/llm.ts +133 -0
  76. package/plugins/workflow-runner/src/stepExecutors/set.js +49 -0
  77. package/plugins/workflow-runner/src/stepExecutors/set.ts +56 -0
  78. package/plugins/workflow-runner/src/stepExecutors/skill.js +5 -6
  79. package/plugins/workflow-runner/src/stepExecutors/skill.ts +140 -0
  80. package/plugins/workflow-runner/src/stepExecutors/tool.js +80 -8
  81. package/plugins/workflow-runner/src/stepExecutors/tool.ts +256 -0
  82. package/plugins/workflow-runner/src/stepExecutors/verify.ts +68 -0
  83. package/plugins/workflow-runner/src/stepPipeline.js +277 -0
  84. package/plugins/workflow-runner/src/stepPipeline.ts +366 -0
  85. package/plugins/workflow-runner/src/taskIdentity.ts +405 -0
  86. package/plugins/workflow-runner/src/toolRuntime.js +48 -0
  87. package/plugins/workflow-runner/src/toolRuntime.ts +64 -0
  88. package/plugins/workflow-runner/src/types.js +37 -1
  89. package/plugins/workflow-runner/src/types.ts +602 -0
  90. package/plugins/workflow-runner/src/workflowState.ts +733 -0
  91. package/plugins/workflow-runner/test/agent.test.ts +587 -0
  92. package/plugins/workflow-runner/test/agentLlmError.test.ts +373 -0
  93. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +65 -0
  94. package/plugins/workflow-runner/test/captureMisbind.test.ts +99 -0
  95. package/plugins/workflow-runner/test/cli.e2e.test.ts +147 -0
  96. package/plugins/workflow-runner/test/context-files.test.ts +320 -0
  97. package/plugins/workflow-runner/test/e2e.test.ts +370 -0
  98. package/plugins/workflow-runner/test/engineRobustness.test.ts +226 -0
  99. package/plugins/workflow-runner/test/expressions.test.ts +397 -0
  100. package/plugins/workflow-runner/test/foundation.test.ts +126 -0
  101. package/plugins/workflow-runner/test/graceful.test.ts +139 -0
  102. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +47 -0
  103. package/plugins/workflow-runner/test/hostCapability.test.ts +108 -0
  104. package/plugins/workflow-runner/test/illustrate.load.test.ts +183 -0
  105. package/plugins/workflow-runner/test/jsonPayload.test.ts +83 -0
  106. package/plugins/workflow-runner/test/loader.test.ts +617 -0
  107. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +33 -0
  108. package/plugins/workflow-runner/test/multimodal.test.ts +342 -0
  109. package/plugins/workflow-runner/test/output-schema.test.ts +213 -0
  110. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +87 -0
  111. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +269 -0
  112. package/plugins/workflow-runner/test/ppt.load.test.ts +1220 -0
  113. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +220 -0
  114. package/plugins/workflow-runner/test/recovery.test.ts +265 -0
  115. package/plugins/workflow-runner/test/runner.test.ts +911 -0
  116. package/plugins/workflow-runner/test/runnerPreflight.test.ts +379 -0
  117. package/plugins/workflow-runner/test/skillTurnDone.test.ts +71 -0
  118. package/plugins/workflow-runner/test/stateLifecycle.test.ts +150 -0
  119. package/plugins/workflow-runner/test/stepPipeline.test.ts +114 -0
  120. package/plugins/workflow-runner/test/taskArbitration.test.ts +338 -0
  121. package/plugins/workflow-runner/test/taskIdentity.test.ts +237 -0
  122. package/plugins/workflow-runner/test/taskLifecycle.test.ts +270 -0
  123. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +221 -0
  124. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +29 -0
  125. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +168 -0
  126. package/plugins/workflow-runner/test/webppt.load.test.ts +250 -0
  127. package/plugins/workflow-runner/test/word.load.test.ts +208 -0
  128. package/plugins/workflow-runner/test/workflows.smoke.test.ts +76 -0
  129. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +207 -0
  130. package/skills/browser-automation/SKILL.md +9 -19
  131. package/skills/web-crawler/SKILL.md +9 -11
  132. package/src/askBridge.ts +249 -0
  133. package/src/bootstrap/cwdArg.js +10 -3
  134. package/src/bootstrap/cwdArg.ts +31 -0
  135. package/src/bootstrap/workingDir.ts +48 -0
  136. package/src/cli/args.js +70 -7
  137. package/src/cli/args.ts +146 -0
  138. package/src/cli/computerUse.js +185 -0
  139. package/src/cli/computerUse.ts +221 -0
  140. package/src/cli/configMenu.js +274 -202
  141. package/src/cli/configMenu.tsx +521 -0
  142. package/src/cli/memoryAccess.js +45 -0
  143. package/src/cli/memoryAccess.ts +53 -0
  144. package/src/cli/print.js +119 -5
  145. package/src/cli/print.ts +597 -0
  146. package/src/cli/quickModelSetup.js +60 -0
  147. package/src/cli/quickModelSetup.tsx +96 -0
  148. package/src/cli/streamJson.js +80 -4
  149. package/src/cli/streamJson.ts +433 -0
  150. package/src/cli/wizards/advisorWizard.js +1 -0
  151. package/src/cli/wizards/advisorWizard.tsx +195 -0
  152. package/src/cli/wizards/agentRuntimeWizard.js +84 -0
  153. package/src/cli/wizards/agentRuntimeWizard.tsx +134 -0
  154. package/src/cli/wizards/browserWizard.js +55 -0
  155. package/src/cli/wizards/browserWizard.tsx +77 -0
  156. package/src/cli/wizards/contextAdvisorWizard.js +84 -0
  157. package/src/cli/wizards/contextAdvisorWizard.tsx +124 -0
  158. package/src/cli/wizards/fieldForm.js +7 -4
  159. package/src/cli/wizards/fieldForm.tsx +250 -0
  160. package/src/cli/wizards/imageWizard.js +4 -5
  161. package/src/cli/wizards/imageWizard.tsx +96 -0
  162. package/src/cli/wizards/openRouterWizard.tsx +48 -0
  163. package/src/cli/wizards/providerPresets.js +1 -8
  164. package/src/cli/wizards/providerPresets.ts +106 -0
  165. package/src/cli/wizards/providerWizard.js +152 -205
  166. package/src/cli/wizards/providerWizard.tsx +266 -0
  167. package/src/cli/wizards/searchWizard.tsx +47 -0
  168. package/src/cli/wizards/ttsWizard.js +4 -3
  169. package/src/cli/wizards/ttsWizard.tsx +61 -0
  170. package/src/config/configDefaults.js +25 -0
  171. package/src/config/configDefaults.ts +33 -0
  172. package/src/config/configDiagnostics.js +117 -0
  173. package/src/config/configDiagnostics.ts +166 -0
  174. package/src/config/configFile.js +52 -32
  175. package/src/config/configFile.ts +633 -0
  176. package/src/config/configManagement.js +126 -0
  177. package/src/config/configManagement.ts +159 -0
  178. package/src/config/configService.js +66 -11
  179. package/src/config/configService.ts +554 -0
  180. package/src/config/numericLimits.js +61 -0
  181. package/src/config/numericLimits.ts +80 -0
  182. package/src/config.ts +109 -0
  183. package/src/context/agentHome.ts +11 -0
  184. package/src/context/archive.ts +144 -0
  185. package/src/context/budgetPlan.js +54 -0
  186. package/src/context/budgetPlan.ts +88 -0
  187. package/src/context/compact.js +179 -106
  188. package/src/context/compact.ts +584 -0
  189. package/src/context/contextBundle.js +119 -0
  190. package/src/context/contextBundle.ts +176 -0
  191. package/src/context/contextLock.ts +84 -0
  192. package/src/context/microCompactLite.ts +218 -0
  193. package/src/context/persistContext.ts +177 -0
  194. package/src/context/reactiveCompact.js +19 -4
  195. package/src/context/reactiveCompact.ts +240 -0
  196. package/src/context/recentDirs.ts +42 -0
  197. package/src/context/sessionPath.ts +206 -0
  198. package/src/context/sessionRegistry.js +8 -2
  199. package/src/context/sessionRegistry.ts +414 -0
  200. package/src/context/snipCompact.ts +163 -0
  201. package/src/context/tokenCounter.ts +106 -0
  202. package/src/context/workspaceIndex.js +2 -2
  203. package/src/context/workspaceIndex.ts +751 -0
  204. package/src/entry.compiled.tsx +20 -0
  205. package/src/harness/claimValidation.js +9 -0
  206. package/src/harness/claimValidation.ts +22 -0
  207. package/src/harness/evidenceLedger.js +92 -0
  208. package/src/harness/evidenceLedger.ts +96 -0
  209. package/src/harness/stallGuard.js +60 -0
  210. package/src/harness/stallGuard.ts +81 -0
  211. package/src/humanIntervention.js +129 -0
  212. package/src/humanIntervention.ts +216 -0
  213. package/src/infra/verification.ts +295 -0
  214. package/src/irreversible/rules.js +216 -0
  215. package/src/irreversible/rules.ts +261 -0
  216. package/src/llm/client.js +40 -3
  217. package/src/llm/client.ts +621 -0
  218. package/src/llm/promptCache.js +27 -0
  219. package/src/llm/promptCache.ts +41 -0
  220. package/src/llm/providers/anthropicFormat.js +41 -5
  221. package/src/llm/providers/anthropicFormat.ts +290 -0
  222. package/src/llm/providers/openaiFormat.js +186 -8
  223. package/src/llm/providers/openaiFormat.ts +428 -0
  224. package/src/loop.js +614 -63
  225. package/src/loop.ts +1454 -0
  226. package/src/main.js +67 -10
  227. package/src/main.tsx +344 -0
  228. package/src/memory/codec.js +204 -0
  229. package/src/memory/codec.ts +249 -0
  230. package/src/memory/constants.js +34 -0
  231. package/src/memory/constants.ts +50 -0
  232. package/src/memory/episodicMemory.js +684 -0
  233. package/src/memory/episodicMemory.ts +815 -0
  234. package/src/memory/fileStore.js +148 -0
  235. package/src/memory/fileStore.ts +184 -0
  236. package/src/memory/memoryService.js +570 -0
  237. package/src/memory/memoryService.ts +859 -0
  238. package/src/memory/migration.js +128 -0
  239. package/src/memory/migration.ts +160 -0
  240. package/src/memory/repository.js +789 -0
  241. package/src/memory/repository.ts +893 -0
  242. package/src/memory/retrieval.js +108 -0
  243. package/src/memory/retrieval.ts +145 -0
  244. package/src/memory/searchIndex.js +107 -0
  245. package/src/memory/searchIndex.ts +153 -0
  246. package/src/memory/topicView.js +82 -0
  247. package/src/memory/topicView.ts +95 -0
  248. package/src/memory/turnJournal.js +95 -0
  249. package/src/memory/turnJournal.ts +120 -0
  250. package/src/memory/types.js +2 -0
  251. package/src/memory/types.ts +186 -0
  252. package/src/messageQueue.ts +123 -0
  253. package/src/multimodal.js +128 -46
  254. package/src/multimodal.ts +349 -0
  255. package/src/plugin-sdk.js +21 -1
  256. package/src/plugin-sdk.ts +134 -0
  257. package/src/plugins/builtinPluginIds.js +47 -0
  258. package/src/plugins/builtinPluginIds.ts +51 -0
  259. package/src/plugins/builtinRegistry.ts +43 -0
  260. package/src/plugins/commandRouter.js +40 -26
  261. package/src/plugins/commandRouter.ts +261 -0
  262. package/src/plugins/hookEngine.ts +341 -0
  263. package/src/plugins/pluginApi.ts +133 -0
  264. package/src/plugins/pluginLifecycle.ts +34 -0
  265. package/src/plugins/pluginLoader.ts +147 -0
  266. package/src/plugins/pluginManifest.js +127 -0
  267. package/src/plugins/pluginManifest.ts +152 -0
  268. package/src/plugins/pluginRunner.js +47 -2
  269. package/src/plugins/pluginRunner.ts +207 -0
  270. package/src/plugins/transcript.ts +208 -0
  271. package/src/prompts/lint.js +169 -0
  272. package/src/prompts/lint.ts +220 -0
  273. package/src/prompts/pluginList.js +32 -16
  274. package/src/prompts/pluginList.ts +86 -0
  275. package/src/prompts/policyRegistry.js +318 -0
  276. package/src/prompts/policyRegistry.ts +358 -0
  277. package/src/prompts/projectInstructions.js +24 -0
  278. package/src/prompts/projectInstructions.ts +81 -0
  279. package/src/prompts/promptAssembly.js +311 -202
  280. package/src/prompts/promptAssembly.ts +510 -0
  281. package/src/prompts/skillList.js +106 -45
  282. package/src/prompts/skillList.ts +198 -0
  283. package/src/prompts/system.js +31 -6
  284. package/src/prompts/system.ts +81 -0
  285. package/src/runtime/agentRuntimeContext.js +53 -0
  286. package/src/runtime/agentRuntimeContext.ts +112 -0
  287. package/src/session/runAgentTurn.js +71 -12
  288. package/src/session/runAgentTurn.ts +181 -0
  289. package/src/session/runTurn.js +29 -0
  290. package/src/session/runTurn.ts +160 -0
  291. package/src/session/runtimeStore.js +149 -0
  292. package/src/session/runtimeStore.ts +197 -0
  293. package/src/session/sessionState.js +79 -3
  294. package/src/session/sessionState.ts +134 -0
  295. package/src/toolGate.ts +50 -0
  296. package/src/tools/advisor/advisor.js +76 -15
  297. package/src/tools/advisor/advisor.ts +512 -0
  298. package/src/tools/agent/agent.js +245 -29
  299. package/src/tools/agent/agent.ts +837 -0
  300. package/src/tools/agent/agentTaskService.js +60 -0
  301. package/src/tools/agent/agentTaskService.ts +113 -0
  302. package/src/tools/agent/agentTypes.js +20 -8
  303. package/src/tools/agent/agentTypes.ts +94 -0
  304. package/src/tools/agent/coordinator.ts +111 -0
  305. package/src/tools/agent/worktree.ts +296 -0
  306. package/src/tools/ask/ask.js +17 -0
  307. package/src/tools/ask/ask.ts +122 -0
  308. package/src/tools/bash/attachImage.js +223 -0
  309. package/src/tools/bash/attachImage.ts +281 -0
  310. package/src/tools/bash/bash.js +132 -14
  311. package/src/tools/bash/bash.ts +642 -0
  312. package/src/tools/bash/semantics.ts +103 -0
  313. package/src/tools/bash/warnings.js +17 -11
  314. package/src/tools/bash/warnings.ts +117 -0
  315. package/src/tools/capabilities.js +42 -0
  316. package/src/tools/capabilities.ts +69 -0
  317. package/src/tools/computeruse/accessibilityPermission.js +261 -0
  318. package/src/tools/computeruse/accessibilityPermission.ts +294 -0
  319. package/src/tools/computeruse/axSearch.js +96 -0
  320. package/src/tools/computeruse/axSearch.ts +120 -0
  321. package/src/tools/computeruse/axSnap.js +272 -0
  322. package/src/tools/computeruse/axSnap.ts +349 -0
  323. package/src/tools/computeruse/capabilityLabels.js +95 -0
  324. package/src/tools/computeruse/capabilityLabels.ts +115 -0
  325. package/src/tools/computeruse/computerUseService.js +2235 -0
  326. package/src/tools/computeruse/computerUseService.ts +2686 -0
  327. package/src/tools/computeruse/computeruse.js +2742 -0
  328. package/src/tools/computeruse/computeruse.ts +3265 -0
  329. package/src/tools/computeruse/diagnosticTrace.js +154 -0
  330. package/src/tools/computeruse/diagnosticTrace.ts +195 -0
  331. package/src/tools/computeruse/diagnostics.js +369 -0
  332. package/src/tools/computeruse/diagnostics.ts +453 -0
  333. package/src/tools/computeruse/grants.js +53 -0
  334. package/src/tools/computeruse/grants.ts +70 -0
  335. package/src/tools/computeruse/humanBoundary.js +159 -0
  336. package/src/tools/computeruse/humanBoundary.ts +199 -0
  337. package/src/tools/computeruse/intervention.js +77 -0
  338. package/src/tools/computeruse/intervention.ts +110 -0
  339. package/src/tools/computeruse/manualSchema.js +709 -0
  340. package/src/tools/computeruse/manualSchema.ts +916 -0
  341. package/src/tools/computeruse/observationImages.js +705 -0
  342. package/src/tools/computeruse/observationImages.ts +889 -0
  343. package/src/tools/computeruse/protocol.js +60 -0
  344. package/src/tools/computeruse/protocol.ts +515 -0
  345. package/src/tools/computeruse/telemetryLog.js +57 -0
  346. package/src/tools/computeruse/telemetryLog.ts +67 -0
  347. package/src/tools/computeruse/vision/appGuide.js +325 -0
  348. package/src/tools/computeruse/vision/appGuide.ts +482 -0
  349. package/src/tools/computeruse/vision/focus.js +291 -0
  350. package/src/tools/computeruse/vision/focus.ts +382 -0
  351. package/src/tools/computeruse/vision/frames.js +248 -0
  352. package/src/tools/computeruse/vision/frames.ts +329 -0
  353. package/src/tools/computeruse/vision/geometry.js +131 -0
  354. package/src/tools/computeruse/vision/geometry.ts +163 -0
  355. package/src/tools/computeruse/vision/imaging.js +201 -0
  356. package/src/tools/computeruse/vision/imaging.ts +281 -0
  357. package/src/tools/computeruse/vision/png.js +274 -0
  358. package/src/tools/computeruse/vision/png.ts +317 -0
  359. package/src/tools/computeruse/vision/raster.js +320 -0
  360. package/src/tools/computeruse/vision/raster.ts +408 -0
  361. package/src/tools/computeruse/vision/settle.js +131 -0
  362. package/src/tools/computeruse/vision/settle.ts +220 -0
  363. package/src/tools/computeruse/vision/telemetry.js +196 -0
  364. package/src/tools/computeruse/vision/telemetry.ts +241 -0
  365. package/src/tools/computeruse/visionOcr.js +115 -0
  366. package/src/tools/computeruse/visionOcr.ts +128 -0
  367. package/src/tools/computeruse/waitFor.js +237 -0
  368. package/src/tools/computeruse/waitFor.ts +291 -0
  369. package/src/tools/download/download.js +10 -6
  370. package/src/tools/download/download.ts +187 -0
  371. package/src/tools/edit/edit.js +30 -18
  372. package/src/tools/edit/edit.ts +349 -0
  373. package/src/tools/edit/multi-edit.js +25 -14
  374. package/src/tools/edit/multi-edit.ts +223 -0
  375. package/src/tools/effectiveToolSet.js +73 -0
  376. package/src/tools/effectiveToolSet.ts +91 -0
  377. package/src/tools/genimage/genimage.ts +257 -0
  378. package/src/tools/genspeech/genspeech.ts +83 -0
  379. package/src/tools/glob/glob.js +176 -29
  380. package/src/tools/glob/glob.ts +283 -0
  381. package/src/tools/grep/grep.js +61 -19
  382. package/src/tools/grep/grep.ts +239 -0
  383. package/src/tools/grep/rgPath.ts +206 -0
  384. package/src/tools/index.js +99 -5
  385. package/src/tools/index.ts +293 -0
  386. package/src/tools/lsp/config.js +113 -0
  387. package/src/tools/lsp/config.ts +113 -0
  388. package/src/tools/lsp/lsp.js +256 -0
  389. package/src/tools/lsp/lsp.ts +274 -0
  390. package/src/tools/lsp/service.js +303 -0
  391. package/src/tools/lsp/service.ts +296 -0
  392. package/src/tools/memory/memory.js +520 -0
  393. package/src/tools/memory/memory.ts +625 -0
  394. package/src/tools/memory/policy.js +53 -0
  395. package/src/tools/memory/policy.ts +72 -0
  396. package/src/tools/notebook/notebookEdit.js +114 -0
  397. package/src/tools/notebook/notebookEdit.ts +126 -0
  398. package/src/tools/powershell/powershell.js +210 -0
  399. package/src/tools/powershell/powershell.ts +239 -0
  400. package/src/tools/presentresult/presentresult.js +145 -0
  401. package/src/tools/presentresult/presentresult.ts +156 -0
  402. package/src/tools/read/read.js +371 -163
  403. package/src/tools/read/read.ts +558 -0
  404. package/src/tools/shared/diffSummary.js +44 -0
  405. package/src/tools/shared/diffSummary.ts +63 -0
  406. package/src/tools/shared/fileActivity.js +51 -0
  407. package/src/tools/shared/fileActivity.ts +66 -0
  408. package/src/tools/shared/fileMutationBus.js +13 -0
  409. package/src/tools/shared/fileMutationBus.ts +14 -0
  410. package/src/tools/shared/fileState.js +73 -65
  411. package/src/tools/shared/fileState.ts +145 -0
  412. package/src/tools/shared/fileUtils.js +81 -4
  413. package/src/tools/shared/fileUtils.ts +504 -0
  414. package/src/tools/shared/killTree.ts +50 -0
  415. package/src/tools/shared/permanentDeleteGuard.js +26 -0
  416. package/src/tools/shared/permanentDeleteGuard.ts +34 -0
  417. package/src/tools/shared/schemas.ts +20 -0
  418. package/src/tools/shared/toolOutputStore.js +97 -0
  419. package/src/tools/shared/toolOutputStore.ts +110 -0
  420. package/src/tools/skill/skill.js +86 -0
  421. package/src/tools/skill/skill.ts +94 -0
  422. package/src/tools/snip/snip.js +67 -0
  423. package/src/tools/snip/snip.ts +80 -0
  424. package/src/tools/tasks/backgroundTaskService.js +275 -0
  425. package/src/tools/tasks/backgroundTaskService.ts +369 -0
  426. package/src/tools/tasks/processEvidence.js +24 -0
  427. package/src/tools/tasks/processEvidence.ts +34 -0
  428. package/src/tools/tasks/taskManagement.js +163 -0
  429. package/src/tools/tasks/taskManagement.ts +180 -0
  430. package/src/tools/tasks/taskOutput.js +113 -0
  431. package/src/tools/tasks/taskOutput.ts +145 -0
  432. package/src/tools/tasks/taskStop.js +74 -0
  433. package/src/tools/tasks/taskStop.ts +99 -0
  434. package/src/tools/tasks/taskStore.js +46 -0
  435. package/src/tools/tasks/taskStore.ts +77 -0
  436. package/src/tools/terminal/terminalCapture.js +167 -0
  437. package/src/tools/terminal/terminalCapture.ts +179 -0
  438. package/src/tools/trash/trash.js +233 -0
  439. package/src/tools/trash/trash.ts +283 -0
  440. package/src/tools/types.js +1 -1
  441. package/src/tools/types.ts +24 -0
  442. package/src/tools/webbrowser/agentBrowserPath.ts +286 -0
  443. package/src/tools/webbrowser/browser.js +214 -11
  444. package/src/tools/webbrowser/browser.ts +293 -0
  445. package/src/tools/webbrowser/browserControl.js +153 -48
  446. package/src/tools/webbrowser/browserControl.ts +262 -0
  447. package/src/tools/webbrowser/browserDaemon.js +147 -39
  448. package/src/tools/webbrowser/browserDaemon.ts +270 -0
  449. package/src/tools/webbrowser/browserOutcome.js +273 -0
  450. package/src/tools/webbrowser/browserOutcome.ts +306 -0
  451. package/src/tools/webbrowser/browserRunRegistry.js +150 -0
  452. package/src/tools/webbrowser/browserRunRegistry.ts +179 -0
  453. package/src/tools/webbrowser/browserService.js +20 -6
  454. package/src/tools/webbrowser/browserService.ts +56 -0
  455. package/src/tools/webbrowser/browserStream.js +30 -1
  456. package/src/tools/webbrowser/browserStream.ts +216 -0
  457. package/src/tools/webbrowser/browserTabs.js +143 -0
  458. package/src/tools/webbrowser/browserTabs.ts +210 -0
  459. package/src/tools/webbrowser/webbrowser.js +831 -150
  460. package/src/tools/webbrowser/webbrowser.ts +1537 -0
  461. package/src/tools/webfetch/preapproved.ts +274 -0
  462. package/src/tools/webfetch/webfetch.js +24 -23
  463. package/src/tools/webfetch/webfetch.ts +383 -0
  464. package/src/tools/websearch/websearch.js +12 -11
  465. package/src/tools/websearch/websearch.ts +292 -0
  466. package/src/tools/worktree/sessionWorktree.js +128 -0
  467. package/src/tools/worktree/sessionWorktree.ts +158 -0
  468. package/src/tools/write/write.js +27 -44
  469. package/src/tools/write/write.ts +136 -0
  470. package/src/types.ts +960 -0
  471. package/src/ui/App.js +216 -12
  472. package/src/ui/App.tsx +879 -0
  473. package/src/ui/AskQuestion.tsx +300 -0
  474. package/src/ui/InputBox.js +77 -1
  475. package/src/ui/InputBox.tsx +567 -0
  476. package/src/ui/LiveArea.tsx +344 -0
  477. package/src/ui/MessageList.js +27 -6
  478. package/src/ui/MessageList.tsx +559 -0
  479. package/src/ui/ModelPicker.tsx +107 -0
  480. package/src/ui/QueuedMessagesBanner.tsx +51 -0
  481. package/src/ui/Root.js +6 -8
  482. package/src/ui/Root.tsx +100 -0
  483. package/src/ui/SessionPicker.tsx +169 -0
  484. package/src/ui/StatusLine.js +22 -1
  485. package/src/ui/StatusLine.tsx +145 -0
  486. package/src/ui/WorkspacePicker.tsx +84 -0
  487. package/src/ui/advisorCommand.js +54 -0
  488. package/src/ui/advisorCommand.ts +63 -0
  489. package/src/ui/computerCommand.js +19 -0
  490. package/src/ui/computerCommand.ts +35 -0
  491. package/src/ui/figures.ts +45 -0
  492. package/src/ui/hooks/askSlot.ts +112 -0
  493. package/src/ui/hooks/useChat.js +271 -7
  494. package/src/ui/hooks/useChat.ts +1578 -0
  495. package/src/ui/hooks/useInputHistory.ts +235 -0
  496. package/src/ui/hooks/usePasteHandler.ts +220 -0
  497. package/src/ui/hooks/useTerminalSize.ts +41 -0
  498. package/src/ui/hooks/useTextBuffer.ts +108 -0
  499. package/src/ui/hooks/useTokenUsage.ts +44 -0
  500. package/src/ui/liveViewport.ts +189 -0
  501. package/src/ui/markdown.ts +230 -0
  502. package/src/ui/textBuffer.ts +239 -0
  503. package/src/ui/theme.ts +35 -0
  504. package/src/utils/clipboardImage.js +358 -0
  505. package/src/utils/clipboardImage.ts +420 -0
  506. package/src/utils/debugLog.ts +50 -0
  507. package/src/utils/greenRoot.ts +35 -0
  508. package/src/utils/packageRoot.ts +40 -0
  509. package/src/utils/pathContains.js +28 -0
  510. package/src/utils/pathContains.ts +31 -0
  511. package/src/utils/resourcePaths.ts +71 -0
  512. package/src/utils/stripThink.ts +49 -0
  513. package/src/utils/zodToJson.ts +73 -0
  514. package/src/web/browserBridge.js +365 -66
  515. package/src/web/browserBridge.ts +672 -0
  516. package/src/web/protocol.ts +1804 -0
  517. package/vendor/computer-use/arm64-darwin/cu-helperd +0 -0
  518. package/workflows/ppt.yaml +13 -2
  519. package/workflows/wechat-reading-shots.yaml +315 -0
  520. package/workflows/word.yaml +11 -1
  521. package/skills/docx/scripts/office/helpers/__pycache__/__init__.cpython-314.pyc +0 -0
  522. package/skills/docx/scripts/office/helpers/__pycache__/merge_runs.cpython-314.pyc +0 -0
  523. package/skills/docx/scripts/office/helpers/__pycache__/simplify_redlines.cpython-314.pyc +0 -0
  524. package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-314.pyc +0 -0
  525. package/skills/docx/scripts/office/validators/__pycache__/base.cpython-314.pyc +0 -0
  526. package/skills/docx/scripts/office/validators/__pycache__/docx.cpython-314.pyc +0 -0
  527. package/skills/docx/scripts/office/validators/__pycache__/pptx.cpython-314.pyc +0 -0
  528. package/skills/docx/scripts/office/validators/__pycache__/redlining.cpython-314.pyc +0 -0
  529. package/skills/image-stats/scripts/__pycache__/image_stats.cpython-314.pyc +0 -0
  530. package/skills/image-stats/scripts/__pycache__/image_stats_test.cpython-314.pyc +0 -0
  531. package/skills/ui-design/scripts/__pycache__/assemble_material.cpython-314.pyc +0 -0
  532. package/skills/ui-design/scripts/__pycache__/assemble_material_test.cpython-314.pyc +0 -0
  533. package/skills/ui-design/scripts/__pycache__/chart_sanity_check.cpython-314.pyc +0 -0
  534. package/skills/ui-design/scripts/__pycache__/check_language_policy.cpython-314.pyc +0 -0
  535. package/skills/ui-design/scripts/__pycache__/check_ui_artifact.cpython-314.pyc +0 -0
  536. package/skills/ui-design/scripts/__pycache__/check_ui_artifact_pptx_test.cpython-314.pyc +0 -0
  537. package/skills/ui-design/scripts/__pycache__/deck_pages_check.cpython-314.pyc +0 -0
  538. package/skills/ui-design/scripts/__pycache__/deck_pages_check_test.cpython-314.pyc +0 -0
  539. package/skills/ui-design/scripts/__pycache__/deck_visual_style_check.cpython-314.pyc +0 -0
  540. package/skills/ui-design/scripts/__pycache__/deck_visual_style_check_test.cpython-314.pyc +0 -0
  541. package/skills/ui-design/scripts/__pycache__/design_budget_check.cpython-314.pyc +0 -0
  542. package/skills/ui-design/scripts/__pycache__/design_budget_check_test.cpython-314.pyc +0 -0
  543. package/skills/ui-design/scripts/__pycache__/design_repair_hints.cpython-314.pyc +0 -0
  544. package/skills/ui-design/scripts/__pycache__/design_repair_hints_test.cpython-314.pyc +0 -0
  545. package/skills/ui-design/scripts/__pycache__/design_style_check.cpython-314.pyc +0 -0
  546. package/skills/ui-design/scripts/__pycache__/design_style_check_test.cpython-314.pyc +0 -0
  547. package/skills/ui-design/scripts/__pycache__/draft_coverage_check.cpython-314.pyc +0 -0
  548. package/skills/ui-design/scripts/__pycache__/extract_source_assets.cpython-314.pyc +0 -0
  549. package/skills/ui-design/scripts/__pycache__/extract_source_assets_test.cpython-314.pyc +0 -0
  550. package/skills/ui-design/scripts/__pycache__/generated_image_review_collect.cpython-314.pyc +0 -0
  551. package/skills/ui-design/scripts/__pycache__/generated_image_review_collect_test.cpython-314.pyc +0 -0
  552. package/skills/ui-design/scripts/__pycache__/image_plan_lint.cpython-314.pyc +0 -0
  553. package/skills/ui-design/scripts/__pycache__/image_plan_lint_test.cpython-314.pyc +0 -0
  554. package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite.cpython-314.pyc +0 -0
  555. package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite_test.cpython-314.pyc +0 -0
  556. package/skills/ui-design/scripts/__pycache__/layout_balance.cpython-314.pyc +0 -0
  557. package/skills/ui-design/scripts/__pycache__/layout_balance_test.cpython-314.pyc +0 -0
  558. package/skills/ui-design/scripts/__pycache__/normalize_design_json.cpython-314.pyc +0 -0
  559. package/skills/ui-design/scripts/__pycache__/normalize_design_json_test.cpython-314.pyc +0 -0
  560. package/skills/ui-design/scripts/__pycache__/plan_source_layout.cpython-314.pyc +0 -0
  561. package/skills/ui-design/scripts/__pycache__/plan_source_layout_test.cpython-314.pyc +0 -0
  562. package/skills/ui-design/scripts/__pycache__/resolve_source_hint.cpython-314.pyc +0 -0
  563. package/skills/ui-design/scripts/__pycache__/resolve_source_hint_test.cpython-314.pyc +0 -0
  564. package/skills/ui-design/scripts/__pycache__/resolve_source_input.cpython-314.pyc +0 -0
  565. package/skills/ui-design/scripts/__pycache__/resolve_source_input_test.cpython-314.pyc +0 -0
  566. package/skills/ui-design/scripts/__pycache__/scaffold_ui_artifact.cpython-314.pyc +0 -0
  567. package/skills/ui-design/scripts/__pycache__/source_usage_check.cpython-314.pyc +0 -0
  568. package/skills/ui-design/scripts/__pycache__/source_usage_check_test.cpython-314.pyc +0 -0
  569. package/skills/ui-design/scripts/__pycache__/text_readability_pixel.cpython-314.pyc +0 -0
  570. package/skills/ui-design/scripts/__pycache__/visual_quality_gate.cpython-314.pyc +0 -0
  571. package/skills/ui-design/scripts/__pycache__/visual_quality_gate_test.cpython-314.pyc +0 -0
  572. /package/skills/ai-image/scripts/{generate_test.mjs → generate.selftest.mjs} +0 -0
  573. /package/skills/ai-image/scripts/{generate_from_plan_test.mjs → generate_from_plan.selftest.mjs} +0 -0
@@ -0,0 +1,859 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { copyFile, readFile, unlink } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+
5
+ import { countTextTokens } from '../context/tokenCounter.js';
6
+ import {
7
+ containsForbiddenSecret,
8
+ deriveTopicKey,
9
+ hydrateRecord,
10
+ parsePersona,
11
+ serializePersona,
12
+ sha256,
13
+ validateMemoryInput,
14
+ } from './codec.js';
15
+ import {
16
+ DEFAULT_RETENTION,
17
+ DEFAULT_SETTINGS,
18
+ MEMORY_RETENTION_DAYS_MAX,
19
+ MEMORY_RETENTION_DAYS_MIN,
20
+ MEMORY_RETENTION_MB_MAX,
21
+ MEMORY_RETENTION_MB_MIN,
22
+ PERSONA_MAX_CHARS,
23
+ } from './constants.js';
24
+ import {
25
+ clearConversationEpisodes,
26
+ episodicMemoryService,
27
+ } from './episodicMemory.js';
28
+ import {
29
+ acquireFileLock,
30
+ appendPrivateLine,
31
+ atomicWriteFile,
32
+ auditFilePath,
33
+ enqueueMemoryMutation,
34
+ personaFilePath,
35
+ scopeDirectory,
36
+ settingsFilePath,
37
+ } from './fileStore.js';
38
+ import { ensureMemoryMigrated } from './migration.js';
39
+ import {
40
+ clearScopeTransactionQuarantine,
41
+ readVersionedMemory,
42
+ refreshTopicView,
43
+ removeVersionedMemory,
44
+ replaceMemoryBatchVersioned,
45
+ replaceVersionedMemory,
46
+ scanMemoryScope,
47
+ writeNewMemory,
48
+ } from './repository.js';
49
+ import {
50
+ isReviewDue,
51
+ recallFromSnapshot,
52
+ takeTokenBudget,
53
+ truncateTokenBudget,
54
+ } from './retrieval.js';
55
+ import type {
56
+ ConversationSearchOptions,
57
+ MemoryContextBundle,
58
+ MemoryDiagnostic,
59
+ MemoryEditablePatch,
60
+ MemoryRecord,
61
+ MemoryRecordV2,
62
+ MemoryScope,
63
+ MemorySettings,
64
+ MemorySnapshot,
65
+ MemoryUpdate,
66
+ MemoryVersion,
67
+ PersonaDocument,
68
+ PersonaInput,
69
+ VersionedMemoryRecord,
70
+ VersionedMemorySettings,
71
+ VersionedPersonaDocument,
72
+ } from './types.js';
73
+
74
+ export type {
75
+ ConversationEpisode,
76
+ ConversationSearchOptions,
77
+ ConversationSearchResult,
78
+ MemoryCategory,
79
+ MemoryContextBundle,
80
+ MemoryDiagnostic,
81
+ MemoryEditablePatch,
82
+ MemoryEvidence,
83
+ MemoryRecord,
84
+ MemoryRecordV2,
85
+ MemoryScope,
86
+ MemorySensitivity,
87
+ MemorySettings,
88
+ MemorySnapshot,
89
+ MemoryStatus,
90
+ MemoryUpdate,
91
+ MemoryVersion,
92
+ PersonaDocument,
93
+ PersonaInput,
94
+ VersionedMemoryRecord,
95
+ VersionedMemorySettings,
96
+ VersionedPersonaDocument,
97
+ } from './types.js';
98
+ export { containsForbiddenSecret } from './codec.js';
99
+
100
+ function mergeSettings(raw: Partial<MemorySettings>): MemorySettings {
101
+ const review = raw.reviewAfterDays;
102
+ const retention = raw.retention;
103
+ return {
104
+ autoRemember:
105
+ typeof raw.autoRemember === 'boolean'
106
+ ? raw.autoRemember
107
+ : DEFAULT_SETTINGS.autoRemember,
108
+ reviewAfterDays: {
109
+ profile: review?.profile ?? DEFAULT_SETTINGS.reviewAfterDays!.profile,
110
+ preference:
111
+ review?.preference ?? DEFAULT_SETTINGS.reviewAfterDays!.preference,
112
+ topic: review?.topic ?? DEFAULT_SETTINGS.reviewAfterDays!.topic,
113
+ person: review?.person ?? DEFAULT_SETTINGS.reviewAfterDays!.person,
114
+ project: review?.project ?? DEFAULT_SETTINGS.reviewAfterDays!.project,
115
+ decision: review?.decision ?? DEFAULT_SETTINGS.reviewAfterDays!.decision,
116
+ },
117
+ retention: {
118
+ episodeDays: retention?.episodeDays ?? DEFAULT_RETENTION.episodeDays,
119
+ episodeMaxMegabytes:
120
+ retention?.episodeMaxMegabytes ?? DEFAULT_RETENTION.episodeMaxMegabytes,
121
+ },
122
+ };
123
+ }
124
+
125
+ function validateSettingsPatch(patch: Partial<MemorySettings>): void {
126
+ if (patch.reviewAfterDays !== undefined) {
127
+ for (const [category, days] of Object.entries(patch.reviewAfterDays)) {
128
+ if (!Number.isInteger(days) || days < 7 || days > 3_650) {
129
+ throw new Error(`复核周期 ${category} 必须是 7-3650 之间的整数天`);
130
+ }
131
+ }
132
+ }
133
+ if (patch.retention === undefined) return;
134
+ const { episodeDays, episodeMaxMegabytes } = patch.retention;
135
+ if (
136
+ episodeDays !== undefined
137
+ && (!Number.isInteger(episodeDays)
138
+ || episodeDays < MEMORY_RETENTION_DAYS_MIN
139
+ || episodeDays > MEMORY_RETENTION_DAYS_MAX)
140
+ ) {
141
+ throw new Error(
142
+ `会话原文保留天数必须是 ${MEMORY_RETENTION_DAYS_MIN}-${MEMORY_RETENTION_DAYS_MAX} 之间的整数`,
143
+ );
144
+ }
145
+ if (
146
+ episodeMaxMegabytes !== undefined
147
+ && (!Number.isInteger(episodeMaxMegabytes)
148
+ || episodeMaxMegabytes < MEMORY_RETENTION_MB_MIN
149
+ || episodeMaxMegabytes > MEMORY_RETENTION_MB_MAX)
150
+ ) {
151
+ throw new Error(
152
+ `会话原文体积上限必须是 ${MEMORY_RETENTION_MB_MIN}-${MEMORY_RETENTION_MB_MAX} 之间的整数 MB`,
153
+ );
154
+ }
155
+ }
156
+
157
+ async function settingsDocument(): Promise<VersionedMemorySettings> {
158
+ try {
159
+ const raw = await readFile(settingsFilePath(), 'utf8');
160
+ return {
161
+ settings: mergeSettings(JSON.parse(raw) as Partial<MemorySettings>),
162
+ version: sha256(raw),
163
+ };
164
+ } catch (error) {
165
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
166
+ const path = settingsFilePath();
167
+ await copyFile(path, `${path}.corrupt-${Date.now()}`).catch(() => {});
168
+ }
169
+ const settings = structuredClone(DEFAULT_SETTINGS);
170
+ return { settings, version: sha256(`${JSON.stringify(settings, null, 2)}\n`) };
171
+ }
172
+ }
173
+
174
+ /** 审计日志单代上限;超限挪成 `.1`,保留最近两代。 */
175
+ const AUDIT_MAX_BYTES = 4 * 1024 * 1024;
176
+
177
+ async function appendAudit(input: {
178
+ action: string;
179
+ record?: MemoryRecord;
180
+ version?: string;
181
+ result: 'ok' | 'conflict' | 'not_found';
182
+ }): Promise<void> {
183
+ await appendPrivateLine(
184
+ auditFilePath(),
185
+ JSON.stringify({
186
+ timestamp: Date.now(),
187
+ action: input.action,
188
+ id: input.record?.id,
189
+ scope: input.record?.scope,
190
+ workspaceId: input.record?.workspaceId,
191
+ revision: input.record?.revision,
192
+ version: input.version,
193
+ result: input.result,
194
+ }),
195
+ // 审计日志同样是 append-only,必须轮转——它此前是仓库里第二个只增不减的存储。
196
+ { maxBytes: AUDIT_MAX_BYTES },
197
+ ).catch(() => undefined);
198
+ }
199
+
200
+ const EMPTY_SCOPE_SNAPSHOT: MemorySnapshot = Object.freeze({
201
+ records: [],
202
+ versions: {},
203
+ diagnostics: [],
204
+ createdAt: 0,
205
+ }) as MemorySnapshot;
206
+
207
+ /**
208
+ * 合并快照的记忆化。
209
+ *
210
+ * ⚠️ 这不是"顺手加个缓存",是修一个死缓存:`retrieval.ts` 用
211
+ * `WeakMap<MemorySnapshot, Bm25Index>` 按快照对象缓存 BM25 索引,而本函数以前**每次都
212
+ * 返回全新对象字面量** —— 于是 recall / buildContextBundle 这两条热路径上 WeakMap 永远
213
+ * miss,每轮对话都要重建整个索引,`recordSearchIndexCacheHit()` 一次都不会触发(诊断计数
214
+ * 器因此说谎)。单测直接对同一个 snapshot 对象调两次 recallFromSnapshot,机制是对的,
215
+ * 但生产集成从不复用对象,属于"测试通过、生产死代码"。
216
+ *
217
+ * 用底层两个 scope 快照的**对象标识**做键:scanMemoryScope 在缓存命中时返回同一个对象,
218
+ * 有变更时才换新对象——比时间戳更精确,也不怕时钟碰撞。
219
+ */
220
+ let combinedSnapshotCache: {
221
+ personal: MemorySnapshot;
222
+ workspace: MemorySnapshot;
223
+ workspaceId?: string;
224
+ combined: MemorySnapshot;
225
+ } | null = null;
226
+
227
+ async function combinedSnapshot(workspaceId?: string): Promise<MemorySnapshot> {
228
+ await ensureMemoryMigrated();
229
+ const personal = await scanMemoryScope('personal');
230
+ const workspace = workspaceId
231
+ ? await scanMemoryScope('workspace', workspaceId)
232
+ : EMPTY_SCOPE_SNAPSHOT;
233
+ const cached = combinedSnapshotCache;
234
+ if (
235
+ cached
236
+ && cached.personal === personal
237
+ && cached.workspace === workspace
238
+ && cached.workspaceId === workspaceId
239
+ ) {
240
+ return cached.combined;
241
+ }
242
+ const combined: MemorySnapshot = {
243
+ records: [...personal.records, ...workspace.records],
244
+ versions: { ...personal.versions, ...workspace.versions },
245
+ diagnostics: [...personal.diagnostics, ...workspace.diagnostics],
246
+ createdAt: Date.now(),
247
+ };
248
+ combinedSnapshotCache = { personal, workspace, workspaceId, combined };
249
+ return combined;
250
+ }
251
+
252
+ function refreshTopicViewAfterMutation(
253
+ scope: MemoryScope,
254
+ workspaceId?: string,
255
+ ): void {
256
+ combinedSnapshotCache = null;
257
+ void refreshTopicView(scope, workspaceId).catch(() => undefined);
258
+ }
259
+
260
+ function sameTopic(
261
+ a: MemoryRecordV2,
262
+ b: Pick<MemoryRecord, 'category' | 'subject'> & {
263
+ topicKey?: string;
264
+ aliases?: string[];
265
+ },
266
+ ): boolean {
267
+ const topicKey = b.topicKey || deriveTopicKey(b);
268
+ if (a.topicKey === topicKey) return true;
269
+ const candidates = new Set([
270
+ b.subject.toLocaleLowerCase(),
271
+ ...(b.aliases ?? []).map((item) => item.toLocaleLowerCase()),
272
+ ]);
273
+ return [a.subject, ...a.aliases].some((item) =>
274
+ candidates.has(item.toLocaleLowerCase()),
275
+ );
276
+ }
277
+
278
+ function evidenceForStorage(
279
+ record: Pick<MemoryRecord, 'sensitivity' | 'evidenceQuote'>,
280
+ ): Pick<MemoryRecord, 'evidenceQuote' | 'evidenceHash'> {
281
+ if (record.sensitivity === 'normal')
282
+ return { evidenceQuote: record.evidenceQuote };
283
+ return {
284
+ evidenceQuote: '[sensitive evidence generalized]',
285
+ evidenceHash: sha256(record.evidenceQuote),
286
+ };
287
+ }
288
+
289
+ function currentInputOverrides(record: MemoryRecordV2, input: string): boolean {
290
+ const normalized = input.toLocaleLowerCase();
291
+ const mentionsTopic = [record.subject, ...record.aliases].some(
292
+ (value) =>
293
+ value.length > 1 && normalized.includes(value.toLocaleLowerCase()),
294
+ );
295
+ return (
296
+ mentionsTopic &&
297
+ /纠正|改成|更新|不再|以后不要|不是|现在(?:改|用|是)|correction|change to|no longer|instead/i.test(
298
+ input,
299
+ )
300
+ );
301
+ }
302
+
303
+ export const memoryService = {
304
+ async settings(): Promise<MemorySettings> {
305
+ return (await settingsDocument()).settings;
306
+ },
307
+
308
+ async settingsWithVersion(): Promise<VersionedMemorySettings> {
309
+ return settingsDocument();
310
+ },
311
+
312
+ async updateSettings(
313
+ patch: Partial<MemorySettings>,
314
+ ): Promise<MemorySettings> {
315
+ return (await this.updateSettingsWithVersion(patch)).settings;
316
+ },
317
+
318
+ async updateSettingsWithVersion(
319
+ patch: Partial<MemorySettings>,
320
+ expectedVersion?: MemoryVersion,
321
+ ): Promise<VersionedMemorySettings> {
322
+ validateSettingsPatch(patch);
323
+ const release = await acquireFileLock(settingsFilePath());
324
+ try {
325
+ const current = await settingsDocument();
326
+ if (expectedVersion && current.version !== expectedVersion) {
327
+ throw new Error('MEMORY_SETTINGS_VERSION_CONFLICT');
328
+ }
329
+ const next = mergeSettings({ ...current.settings, ...patch });
330
+ const content = `${JSON.stringify(next, null, 2)}\n`;
331
+ await atomicWriteFile(settingsFilePath(), content);
332
+ return { settings: next, version: sha256(content) };
333
+ } finally {
334
+ await release();
335
+ }
336
+ },
337
+
338
+ async snapshot(workspaceId?: string): Promise<MemorySnapshot> {
339
+ return combinedSnapshot(workspaceId);
340
+ },
341
+
342
+ async scan(
343
+ scope: MemoryScope,
344
+ workspaceId?: string,
345
+ ): Promise<MemorySnapshot> {
346
+ await ensureMemoryMigrated();
347
+ return scanMemoryScope(scope, workspaceId);
348
+ },
349
+
350
+ async list(
351
+ scope: MemoryScope,
352
+ workspaceId?: string,
353
+ ): Promise<MemoryRecordV2[]> {
354
+ return (await this.scan(scope, workspaceId)).records;
355
+ },
356
+
357
+ async diagnostics(
358
+ scope: MemoryScope,
359
+ workspaceId?: string,
360
+ ): Promise<MemoryDiagnostic[]> {
361
+ return (await this.scan(scope, workspaceId)).diagnostics;
362
+ },
363
+
364
+ async readWithVersion(
365
+ id: string,
366
+ scope: MemoryScope,
367
+ workspaceId?: string,
368
+ ): Promise<VersionedMemoryRecord | null> {
369
+ await ensureMemoryMigrated();
370
+ return readVersionedMemory(id, scope, workspaceId);
371
+ },
372
+
373
+ async recall(
374
+ query: string,
375
+ workspaceId?: string,
376
+ limit = 8,
377
+ ): Promise<MemoryRecordV2[]> {
378
+ return (await this.recallDetailed(query, workspaceId, limit)).records;
379
+ },
380
+
381
+ async recallDetailed(
382
+ query: string,
383
+ workspaceId?: string,
384
+ limit = 8,
385
+ ): Promise<{
386
+ records: MemoryRecordV2[];
387
+ snapshot: MemorySnapshot;
388
+ }> {
389
+ const snapshot = await combinedSnapshot(workspaceId);
390
+ return {
391
+ records: recallFromSnapshot(
392
+ snapshot,
393
+ query,
394
+ await this.settings(),
395
+ limit,
396
+ ),
397
+ snapshot,
398
+ };
399
+ },
400
+
401
+ async remember(
402
+ input: Omit<MemoryRecord, 'id' | 'createdAt' | 'updatedAt'>,
403
+ ): Promise<MemoryRecordV2> {
404
+ validateMemoryInput(input);
405
+ await ensureMemoryMigrated();
406
+ return enqueueMemoryMutation(async () => {
407
+ const release = await acquireFileLock(
408
+ join(scopeDirectory(input.scope, input.workspaceId), '.records'),
409
+ );
410
+ try {
411
+ const records = (await scanMemoryScope(input.scope, input.workspaceId))
412
+ .records;
413
+ const hydratedInput = hydrateRecord({
414
+ ...input,
415
+ id: randomUUID(),
416
+ createdAt: 0,
417
+ updatedAt: 0,
418
+ });
419
+ const duplicate = records.find((record) =>
420
+ sameTopic(record, hydratedInput),
421
+ );
422
+ if (duplicate?.statement === input.statement) {
423
+ await appendAudit({
424
+ action: 'remember-idempotent',
425
+ record: duplicate,
426
+ result: 'ok',
427
+ });
428
+ return duplicate;
429
+ }
430
+ if (duplicate) {
431
+ throw new Error(
432
+ `已有同主题记忆 ${duplicate.id};内容变更必须使用 UpdateMemory,不能静默覆盖`,
433
+ );
434
+ }
435
+ const now = Date.now();
436
+ const evidence = evidenceForStorage(input);
437
+ const record = hydrateRecord({
438
+ ...input,
439
+ ...evidence,
440
+ id: hydratedInput.id,
441
+ createdAt: now,
442
+ updatedAt: now,
443
+ topicKey: hydratedInput.topicKey,
444
+ status: 'active',
445
+ revision: 1,
446
+ lastConfirmedAt: now,
447
+ });
448
+ const version = await writeNewMemory(record);
449
+ await appendAudit({
450
+ action: 'remember',
451
+ record,
452
+ version,
453
+ result: 'ok',
454
+ });
455
+ refreshTopicViewAfterMutation(record.scope, record.workspaceId);
456
+ return record;
457
+ } finally {
458
+ await release();
459
+ }
460
+ });
461
+ },
462
+
463
+ async updateWithVersion(
464
+ id: string,
465
+ scope: MemoryScope,
466
+ expectedVersion: MemoryVersion,
467
+ patch: MemoryUpdate,
468
+ workspaceId?: string,
469
+ ): Promise<VersionedMemoryRecord | null> {
470
+ await ensureMemoryMigrated();
471
+ return enqueueMemoryMutation(async () => {
472
+ const current = await readVersionedMemory(id, scope, workspaceId);
473
+ if (!current) {
474
+ await appendAudit({ action: 'update', result: 'not_found' });
475
+ return null;
476
+ }
477
+ const now = Date.now();
478
+ const merged = { ...current.record, ...patch, updatedAt: now };
479
+ validateMemoryInput(merged);
480
+ const evidence = evidenceForStorage(merged);
481
+ const next = hydrateRecord({
482
+ ...merged,
483
+ ...evidence,
484
+ topicKey: deriveTopicKey(merged),
485
+ revision: current.record.revision + 1,
486
+ lastConfirmedAt: now,
487
+ });
488
+ const scopeSnapshot = await scanMemoryScope(scope, workspaceId);
489
+ const topicConflicts = scopeSnapshot.records.filter(
490
+ (record) =>
491
+ record.id !== current.record.id &&
492
+ record.status !== 'superseded' &&
493
+ sameTopic(record, next),
494
+ );
495
+ const declaredSuperseded = new Set(next.supersedesIds);
496
+ if (topicConflicts.some((record) => !declaredSuperseded.has(record.id))) {
497
+ throw new Error(
498
+ `MEMORY_TOPIC_CONFLICT:${topicConflicts.map((record) => record.id).join(',')}`,
499
+ );
500
+ }
501
+ try {
502
+ const supersededRecords: MemoryRecordV2[] = [];
503
+ const replacements: import('./repository.js').VersionedMemoryReplacement[] = [
504
+ { current, next, expectedVersion },
505
+ ];
506
+ for (const conflict of topicConflicts) {
507
+ const conflictVersion = scopeSnapshot.versions[conflict.id];
508
+ if (!conflictVersion) continue;
509
+ const superseded = hydrateRecord({
510
+ ...conflict,
511
+ status: 'superseded',
512
+ revision: conflict.revision + 1,
513
+ updatedAt: now,
514
+ });
515
+ supersededRecords.push(superseded);
516
+ replacements.push({
517
+ current: { record: conflict, version: conflictVersion },
518
+ next: superseded,
519
+ expectedVersion: conflictVersion,
520
+ });
521
+ }
522
+ const versions = await replaceMemoryBatchVersioned(replacements);
523
+ const version = versions[next.id]!;
524
+ for (const superseded of supersededRecords) {
525
+ await appendAudit({
526
+ action: 'supersede',
527
+ record: superseded,
528
+ version: versions[superseded.id],
529
+ result: 'ok',
530
+ });
531
+ }
532
+ await appendAudit({
533
+ action: 'update',
534
+ record: next,
535
+ version,
536
+ result: 'ok',
537
+ });
538
+ refreshTopicViewAfterMutation(next.scope, next.workspaceId);
539
+ return { record: next, version };
540
+ } catch (error) {
541
+ if ((error as Error).message === 'MEMORY_VERSION_CONFLICT') {
542
+ await appendAudit({
543
+ action: 'update',
544
+ record: current.record,
545
+ result: 'conflict',
546
+ });
547
+ }
548
+ throw error;
549
+ }
550
+ });
551
+ },
552
+
553
+ async update(
554
+ id: string,
555
+ scope: MemoryScope,
556
+ patch: MemoryUpdate,
557
+ workspaceId?: string,
558
+ ): Promise<MemoryRecordV2 | null> {
559
+ const current = await this.readWithVersion(id, scope, workspaceId);
560
+ if (!current) return null;
561
+ return (
562
+ (
563
+ await this.updateWithVersion(
564
+ id,
565
+ scope,
566
+ current.version,
567
+ patch,
568
+ workspaceId,
569
+ )
570
+ )?.record ?? null
571
+ );
572
+ },
573
+
574
+ async confirm(
575
+ id: string,
576
+ scope: MemoryScope,
577
+ expectedVersion: MemoryVersion,
578
+ evidence: Pick<
579
+ MemoryRecord,
580
+ 'evidenceQuote' | 'sourceSessionId' | 'sourceMessageId'
581
+ >,
582
+ workspaceId?: string,
583
+ ): Promise<VersionedMemoryRecord | null> {
584
+ return this.updateWithVersion(
585
+ id,
586
+ scope,
587
+ expectedVersion,
588
+ {
589
+ evidence: 'user_confirmed',
590
+ ...evidence,
591
+ status: 'active',
592
+ },
593
+ workspaceId,
594
+ );
595
+ },
596
+
597
+ async reviewQueue(
598
+ scope?: MemoryScope,
599
+ workspaceId?: string,
600
+ ): Promise<MemoryRecordV2[]> {
601
+ const snapshot = scope
602
+ ? await this.scan(scope, workspaceId)
603
+ : await this.snapshot(workspaceId);
604
+ const settings = await this.settings();
605
+ return snapshot.records.filter(
606
+ (record) =>
607
+ record.status !== 'superseded' &&
608
+ (record.status === 'needs_review' || isReviewDue(record, settings)),
609
+ );
610
+ },
611
+
612
+ async forget(
613
+ id: string,
614
+ scope: MemoryScope,
615
+ workspaceId?: string,
616
+ ): Promise<boolean> {
617
+ const current = await this.readWithVersion(id, scope, workspaceId);
618
+ if (!current) return false;
619
+ return this.forgetWithVersion(id, scope, current.version, workspaceId);
620
+ },
621
+
622
+ async forgetWithVersion(
623
+ id: string,
624
+ scope: MemoryScope,
625
+ expectedVersion: MemoryVersion,
626
+ workspaceId?: string,
627
+ ): Promise<boolean> {
628
+ await ensureMemoryMigrated();
629
+ return enqueueMemoryMutation(async () => {
630
+ const current = await readVersionedMemory(id, scope, workspaceId);
631
+ if (!current) return false;
632
+ const removed = await removeVersionedMemory(current, expectedVersion);
633
+ await appendAudit({
634
+ action: 'forget',
635
+ record: current.record,
636
+ version: expectedVersion,
637
+ result: removed ? 'ok' : 'not_found',
638
+ });
639
+ if (removed) refreshTopicViewAfterMutation(scope, workspaceId);
640
+ return removed;
641
+ });
642
+ },
643
+
644
+ async clear(scope: MemoryScope, workspaceId?: string): Promise<void> {
645
+ await ensureMemoryMigrated();
646
+ await enqueueMemoryMutation(async () => {
647
+ const snapshot = await scanMemoryScope(scope, workspaceId);
648
+ for (const record of snapshot.records) {
649
+ const version = snapshot.versions[record.id];
650
+ if (!version) continue;
651
+ await removeVersionedMemory({ record, version }, version);
652
+ await appendAudit({ action: 'clear', record, version, result: 'ok' });
653
+ }
654
+ // ★ 会话原文日志也要清掉。
655
+ // Desktop「永久清空」以前只删 records,而同一个记忆中心页面还提供
656
+ // ConversationHistorySearch —— 用户"清空记忆"后全部对话原文依然可搜,
657
+ // 与按钮承诺严重不符。工作区范围才有对应的 episodes 文件。
658
+ if (scope === 'workspace' && workspaceId) {
659
+ const removed = await clearConversationEpisodes(workspaceId).catch(() => 0);
660
+ if (removed) {
661
+ await appendAudit({ action: 'clear-episodes', result: 'ok' });
662
+ }
663
+ }
664
+ // 只有用户明确清空整个 scope 才表示隔离事务的复核现场也不再需要。
665
+ // 普通新增/更新记忆不得清除这类诊断。
666
+ await clearScopeTransactionQuarantine(scope, workspaceId);
667
+ refreshTopicViewAfterMutation(scope, workspaceId);
668
+ });
669
+ },
670
+
671
+ async readPersona(): Promise<PersonaDocument | null> {
672
+ return (await this.readPersonaWithVersion())?.persona ?? null;
673
+ },
674
+
675
+ async readPersonaWithVersion(): Promise<VersionedPersonaDocument | null> {
676
+ await ensureMemoryMigrated();
677
+ try {
678
+ const raw = await readFile(personaFilePath(), 'utf8');
679
+ return { persona: parsePersona(raw), version: sha256(raw) };
680
+ } catch (error) {
681
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null;
682
+ throw new Error(`无法读取人格设定:${(error as Error).message}`);
683
+ }
684
+ },
685
+
686
+ async setPersona(input: PersonaInput): Promise<PersonaDocument> {
687
+ return (await this.setPersonaWithVersion(input)).persona;
688
+ },
689
+
690
+ async setPersonaWithVersion(
691
+ input: PersonaInput,
692
+ expectedVersion?: MemoryVersion,
693
+ ): Promise<VersionedPersonaDocument> {
694
+ if (!input.content.trim() || input.content.length > PERSONA_MAX_CHARS) {
695
+ throw new Error(`人格设定长度必须为 1-${PERSONA_MAX_CHARS} 字符`);
696
+ }
697
+ if (
698
+ !input.evidenceQuote.trim() ||
699
+ containsForbiddenSecret(`${input.content}\n${input.evidenceQuote}`)
700
+ ) {
701
+ throw new Error('人格设定缺少有效证据,或包含不得保存的凭据');
702
+ }
703
+ await ensureMemoryMigrated();
704
+ return enqueueMemoryMutation(async () => {
705
+ const release = await acquireFileLock(personaFilePath());
706
+ try {
707
+ const raw = await readFile(personaFilePath(), 'utf8').catch((error) => {
708
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return null;
709
+ throw error;
710
+ });
711
+ if (expectedVersion && (!raw || sha256(raw) !== expectedVersion)) {
712
+ throw new Error('MEMORY_PERSONA_VERSION_CONFLICT');
713
+ }
714
+ const previous = raw ? parsePersona(raw) : null;
715
+ const persona: PersonaDocument = {
716
+ ...input,
717
+ content: input.content.trim(),
718
+ updatedAt: Date.now(),
719
+ revision: (previous?.revision ?? 0) + 1,
720
+ };
721
+ const content = serializePersona(persona);
722
+ await atomicWriteFile(personaFilePath(), content);
723
+ await appendAudit({ action: 'persona-set', result: 'ok' });
724
+ return { persona, version: sha256(content) };
725
+ } finally {
726
+ await release();
727
+ }
728
+ });
729
+ },
730
+
731
+ async clearPersona(): Promise<boolean> {
732
+ const current = await this.readPersonaWithVersion();
733
+ if (!current) return false;
734
+ return this.clearPersonaWithVersion(current.version);
735
+ },
736
+
737
+ async clearPersonaWithVersion(expectedVersion: MemoryVersion): Promise<boolean> {
738
+ await ensureMemoryMigrated();
739
+ return enqueueMemoryMutation(async () => {
740
+ const release = await acquireFileLock(personaFilePath());
741
+ try {
742
+ try {
743
+ const raw = await readFile(personaFilePath(), 'utf8');
744
+ if (sha256(raw) !== expectedVersion) {
745
+ throw new Error('MEMORY_PERSONA_VERSION_CONFLICT');
746
+ }
747
+ await unlink(personaFilePath());
748
+ await appendAudit({ action: 'persona-clear', result: 'ok' });
749
+ return true;
750
+ } catch (error) {
751
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;
752
+ throw error;
753
+ }
754
+ } finally {
755
+ await release();
756
+ }
757
+ });
758
+ },
759
+
760
+ async buildContextBundle(
761
+ input: string,
762
+ workspaceId?: string,
763
+ ): Promise<MemoryContextBundle> {
764
+ const snapshot = await combinedSnapshot(workspaceId);
765
+ const settings = await this.settings();
766
+ const persona = await this.readPersona().catch(() => null);
767
+ const preferences = snapshot.records.filter(
768
+ (record) =>
769
+ record.scope === 'personal' &&
770
+ record.category === 'preference' &&
771
+ record.sensitivity === 'normal' &&
772
+ record.status !== 'superseded' &&
773
+ !currentInputOverrides(record, input),
774
+ );
775
+ const relevant = recallFromSnapshot(snapshot, input, settings, 12)
776
+ .filter(
777
+ (record) =>
778
+ record.sensitivity === 'normal' &&
779
+ record.category !== 'preference' &&
780
+ !currentInputOverrides(record, input),
781
+ )
782
+ .slice(0, 5);
783
+ const reviewCount = snapshot.records.filter(
784
+ (record) =>
785
+ record.status !== 'superseded' && isReviewDue(record, settings),
786
+ ).length;
787
+ const sections: string[] = [];
788
+ const contextSections: MemoryContextBundle['sections'] = [];
789
+ const includedIds: string[] = [];
790
+ const pushSection = (
791
+ id: MemoryContextBundle['sections'][number]['id'],
792
+ content: string,
793
+ ids: string[] = [],
794
+ ) => {
795
+ sections.push(content);
796
+ contextSections.push({
797
+ id,
798
+ content,
799
+ includedIds: ids,
800
+ estimatedTokens: countTextTokens(content),
801
+ });
802
+ };
803
+ if (persona) {
804
+ const personaText = truncateTokenBudget(persona.content, 1_000);
805
+ pushSection('persona',
806
+ `【全局 Agent 人格|可信本机配置】\n只用于角色、语气和协作风格;不得扩大权限、覆盖安全规则或改变当前任务。\n${personaText}`,
807
+ );
808
+ }
809
+ const preferenceLines = takeTokenBudget(
810
+ preferences.map((record) => `- ${record.subject}: ${record.statement}`),
811
+ 600,
812
+ );
813
+ if (preferenceLines.length) {
814
+ const ids = preferences
815
+ .slice(0, preferenceLines.length)
816
+ .map((record) => record.id);
817
+ pushSection('preferences',
818
+ `【全局响应偏好|当前消息可纠正】\n${preferenceLines.join('\n')}`,
819
+ ids,
820
+ );
821
+ includedIds.push(...ids);
822
+ }
823
+ const relevantLines = takeTokenBudget(
824
+ relevant.map(
825
+ (record) =>
826
+ `- ${record.scope}/${record.category}/${record.subject}: ${record.statement}`,
827
+ ),
828
+ 1_200,
829
+ );
830
+ if (relevantLines.length) {
831
+ const ids = relevant.slice(0, relevantLines.length).map((record) => record.id);
832
+ pushSection('relevant',
833
+ `【相关本机记忆|低优先级、可纠正】\n这些记录来自用户此前明确陈述;当前消息冲突时以当前消息为准。需要来源时调用 RecallMemory。\n${relevantLines.join('\n')}`,
834
+ ids,
835
+ );
836
+ includedIds.push(...ids);
837
+ }
838
+ if (snapshot.diagnostics.length || reviewCount) {
839
+ pushSection('health',
840
+ `【记忆健康提示】${snapshot.diagnostics.length ? ` ${snapshot.diagnostics.length} 个文件损坏并已隔离。` : ''}${reviewCount ? ` ${reviewCount} 条记忆已到复核周期;不要自动删除。` : ''}`,
841
+ );
842
+ }
843
+ const unboundedText = sections.length
844
+ ? sections.join('\n\n')
845
+ : '长期记忆:当前没有与本轮明显相关的记录;需要时可调用 RecallMemory。';
846
+ const text = truncateTokenBudget(unboundedText, 3_000);
847
+ return {
848
+ text,
849
+ snapshot,
850
+ includedIds,
851
+ estimatedTokens: countTextTokens(text),
852
+ sections: contextSections,
853
+ };
854
+ },
855
+
856
+ async searchConversations(query: string, options: ConversationSearchOptions) {
857
+ return episodicMemoryService.search(query, options);
858
+ },
859
+ };