@zooique/memora 2.0.3 → 3.0.1

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 (588) hide show
  1. package/CHANGELOG.md +1037 -0
  2. package/README.en.md +305 -272
  3. package/README.md +303 -260
  4. package/config.example.json +43 -0
  5. package/dist/agent/agent.d.ts +376 -408
  6. package/dist/agent/agent.d.ts.map +1 -1
  7. package/dist/agent/agent.js +1166 -926
  8. package/dist/agent/agent.js.map +1 -1
  9. package/dist/agent/assembler.d.ts +105 -43
  10. package/dist/agent/assembler.d.ts.map +1 -1
  11. package/dist/agent/assembler.js +543 -75
  12. package/dist/agent/assembler.js.map +1 -1
  13. package/dist/agent/budget.d.ts +131 -0
  14. package/dist/agent/budget.d.ts.map +1 -0
  15. package/dist/agent/budget.js +128 -0
  16. package/dist/agent/budget.js.map +1 -0
  17. package/dist/agent/builtinToolHandlers.d.ts +225 -38
  18. package/dist/agent/builtinToolHandlers.d.ts.map +1 -1
  19. package/dist/agent/builtinToolHandlers.js +748 -132
  20. package/dist/agent/builtinToolHandlers.js.map +1 -1
  21. package/dist/agent/builtinTools.d.ts +198 -7
  22. package/dist/agent/builtinTools.d.ts.map +1 -1
  23. package/dist/agent/builtinTools.js +646 -14
  24. package/dist/agent/builtinTools.js.map +1 -1
  25. package/dist/agent/compaction.d.ts +93 -0
  26. package/dist/agent/compaction.d.ts.map +1 -0
  27. package/dist/agent/compaction.js +192 -0
  28. package/dist/agent/compaction.js.map +1 -0
  29. package/dist/agent/constants.d.ts +137 -20
  30. package/dist/agent/constants.d.ts.map +1 -1
  31. package/dist/agent/constants.js +152 -20
  32. package/dist/agent/constants.js.map +1 -1
  33. package/dist/agent/contextManager.d.ts +119 -77
  34. package/dist/agent/contextManager.d.ts.map +1 -1
  35. package/dist/agent/contextManager.js +192 -135
  36. package/dist/agent/contextManager.js.map +1 -1
  37. package/dist/agent/contextPreparer.d.ts +78 -0
  38. package/dist/agent/contextPreparer.d.ts.map +1 -0
  39. package/dist/agent/contextPreparer.js +128 -0
  40. package/dist/agent/contextPreparer.js.map +1 -0
  41. package/dist/agent/duplicateInterceptor.d.ts +67 -0
  42. package/dist/agent/duplicateInterceptor.d.ts.map +1 -0
  43. package/dist/agent/duplicateInterceptor.js +82 -0
  44. package/dist/agent/duplicateInterceptor.js.map +1 -0
  45. package/dist/agent/guardRail.d.ts +166 -0
  46. package/dist/agent/guardRail.d.ts.map +1 -0
  47. package/dist/agent/guardRail.js +333 -0
  48. package/dist/agent/guardRail.js.map +1 -0
  49. package/dist/agent/loop.d.ts +716 -295
  50. package/dist/agent/loop.d.ts.map +1 -1
  51. package/dist/agent/loop.js +2178 -664
  52. package/dist/agent/loop.js.map +1 -1
  53. package/dist/agent/managers/archiveCoordinator.d.ts +14 -171
  54. package/dist/agent/managers/archiveCoordinator.d.ts.map +1 -1
  55. package/dist/agent/managers/archiveCoordinator.js +19 -287
  56. package/dist/agent/managers/archiveCoordinator.js.map +1 -1
  57. package/dist/agent/managers/chatLockManager.d.ts +20 -88
  58. package/dist/agent/managers/chatLockManager.d.ts.map +1 -1
  59. package/dist/agent/managers/chatLockManager.js +31 -103
  60. package/dist/agent/managers/chatLockManager.js.map +1 -1
  61. package/dist/agent/managers/dedupManager.d.ts +31 -115
  62. package/dist/agent/managers/dedupManager.d.ts.map +1 -1
  63. package/dist/agent/managers/dedupManager.js +48 -136
  64. package/dist/agent/managers/dedupManager.js.map +1 -1
  65. package/dist/agent/managers/goalConsistencyChecker.d.ts +42 -0
  66. package/dist/agent/managers/goalConsistencyChecker.d.ts.map +1 -0
  67. package/dist/agent/managers/goalConsistencyChecker.js +178 -0
  68. package/dist/agent/managers/goalConsistencyChecker.js.map +1 -0
  69. package/dist/agent/managers/llmCaller.d.ts +124 -0
  70. package/dist/agent/managers/llmCaller.d.ts.map +1 -0
  71. package/dist/agent/managers/llmCaller.js +417 -0
  72. package/dist/agent/managers/llmCaller.js.map +1 -0
  73. package/dist/agent/managers/llmJudgeHelper.d.ts +8 -25
  74. package/dist/agent/managers/llmJudgeHelper.d.ts.map +1 -1
  75. package/dist/agent/managers/llmJudgeHelper.js +7 -24
  76. package/dist/agent/managers/llmJudgeHelper.js.map +1 -1
  77. package/dist/agent/managers/loopMetrics.d.ts +58 -0
  78. package/dist/agent/managers/loopMetrics.d.ts.map +1 -0
  79. package/dist/agent/managers/loopMetrics.js +68 -0
  80. package/dist/agent/managers/loopMetrics.js.map +1 -0
  81. package/dist/agent/managers/memoryAdvisor.d.ts +27 -120
  82. package/dist/agent/managers/memoryAdvisor.d.ts.map +1 -1
  83. package/dist/agent/managers/memoryAdvisor.js +85 -207
  84. package/dist/agent/managers/memoryAdvisor.js.map +1 -1
  85. package/dist/agent/managers/memoryGovernance.d.ts +10 -42
  86. package/dist/agent/managers/memoryGovernance.d.ts.map +1 -1
  87. package/dist/agent/managers/memoryGovernance.js +19 -36
  88. package/dist/agent/managers/memoryGovernance.js.map +1 -1
  89. package/dist/agent/managers/memoryInspector.d.ts +59 -268
  90. package/dist/agent/managers/memoryInspector.d.ts.map +1 -1
  91. package/dist/agent/managers/memoryInspector.js +91 -442
  92. package/dist/agent/managers/memoryInspector.js.map +1 -1
  93. package/dist/agent/managers/roundSummaryGenerator.d.ts +56 -0
  94. package/dist/agent/managers/roundSummaryGenerator.d.ts.map +1 -0
  95. package/dist/agent/managers/roundSummaryGenerator.js +201 -0
  96. package/dist/agent/managers/roundSummaryGenerator.js.map +1 -0
  97. package/dist/agent/managers/sessionArchiver.d.ts +19 -68
  98. package/dist/agent/managers/sessionArchiver.d.ts.map +1 -1
  99. package/dist/agent/managers/sessionArchiver.js +76 -147
  100. package/dist/agent/managers/sessionArchiver.js.map +1 -1
  101. package/dist/agent/managers/sessionManager.d.ts +286 -57
  102. package/dist/agent/managers/sessionManager.d.ts.map +1 -1
  103. package/dist/agent/managers/sessionManager.js +846 -85
  104. package/dist/agent/managers/sessionManager.js.map +1 -1
  105. package/dist/agent/managers/sessionNamer.d.ts +35 -0
  106. package/dist/agent/managers/sessionNamer.d.ts.map +1 -0
  107. package/dist/agent/managers/sessionNamer.js +104 -0
  108. package/dist/agent/managers/sessionNamer.js.map +1 -0
  109. package/dist/agent/managers/streamAccumulator.d.ts +8 -33
  110. package/dist/agent/managers/streamAccumulator.d.ts.map +1 -1
  111. package/dist/agent/managers/streamAccumulator.js +4 -29
  112. package/dist/agent/managers/streamAccumulator.js.map +1 -1
  113. package/dist/agent/managers/textPolishManager.d.ts +8 -44
  114. package/dist/agent/managers/textPolishManager.d.ts.map +1 -1
  115. package/dist/agent/managers/textPolishManager.js +9 -41
  116. package/dist/agent/managers/textPolishManager.js.map +1 -1
  117. package/dist/agent/managers/toolCallHelpers.d.ts +105 -0
  118. package/dist/agent/managers/toolCallHelpers.d.ts.map +1 -0
  119. package/dist/agent/managers/toolCallHelpers.js +161 -0
  120. package/dist/agent/managers/toolCallHelpers.js.map +1 -0
  121. package/dist/agent/managers/workProjection.d.ts +55 -100
  122. package/dist/agent/managers/workProjection.d.ts.map +1 -1
  123. package/dist/agent/managers/workProjection.js +164 -268
  124. package/dist/agent/managers/workProjection.js.map +1 -1
  125. package/dist/agent/messageHistory.d.ts +134 -84
  126. package/dist/agent/messageHistory.d.ts.map +1 -1
  127. package/dist/agent/messageHistory.js +419 -133
  128. package/dist/agent/messageHistory.js.map +1 -1
  129. package/dist/agent/needsPlanning.d.ts +28 -0
  130. package/dist/agent/needsPlanning.d.ts.map +1 -0
  131. package/dist/agent/needsPlanning.js +68 -0
  132. package/dist/agent/needsPlanning.js.map +1 -0
  133. package/dist/agent/seed/index.d.ts +11 -0
  134. package/dist/agent/seed/index.d.ts.map +1 -0
  135. package/dist/agent/seed/index.js +10 -0
  136. package/dist/agent/seed/index.js.map +1 -0
  137. package/dist/agent/seed/orchestrator.d.ts +83 -0
  138. package/dist/agent/seed/orchestrator.d.ts.map +1 -0
  139. package/dist/agent/seed/orchestrator.js +260 -0
  140. package/dist/agent/seed/orchestrator.js.map +1 -0
  141. package/dist/agent/seed/prepare.d.ts +49 -0
  142. package/dist/agent/seed/prepare.d.ts.map +1 -0
  143. package/dist/agent/seed/prepare.js +107 -0
  144. package/dist/agent/seed/prepare.js.map +1 -0
  145. package/dist/agent/seed/types.d.ts +115 -0
  146. package/dist/agent/seed/types.d.ts.map +1 -0
  147. package/dist/agent/seed/types.js +15 -0
  148. package/dist/agent/seed/types.js.map +1 -0
  149. package/dist/agent/sessionStateMachine.d.ts +78 -0
  150. package/dist/agent/sessionStateMachine.d.ts.map +1 -0
  151. package/dist/agent/sessionStateMachine.js +182 -0
  152. package/dist/agent/sessionStateMachine.js.map +1 -0
  153. package/dist/agent/taskTableRenderer.d.ts +51 -0
  154. package/dist/agent/taskTableRenderer.d.ts.map +1 -0
  155. package/dist/agent/taskTableRenderer.js +115 -0
  156. package/dist/agent/taskTableRenderer.js.map +1 -0
  157. package/dist/agent/toolExecutor.d.ts +236 -10
  158. package/dist/agent/toolExecutor.d.ts.map +1 -1
  159. package/dist/agent/toolExecutor.js +932 -21
  160. package/dist/agent/toolExecutor.js.map +1 -1
  161. package/dist/agent/toolLedger.d.ts +120 -0
  162. package/dist/agent/toolLedger.d.ts.map +1 -0
  163. package/dist/agent/toolLedger.js +149 -0
  164. package/dist/agent/toolLedger.js.map +1 -0
  165. package/dist/agent/toolResultCache.d.ts +134 -0
  166. package/dist/agent/toolResultCache.d.ts.map +1 -0
  167. package/dist/agent/toolResultCache.js +243 -0
  168. package/dist/agent/toolResultCache.js.map +1 -0
  169. package/dist/agent/toolResultOffload.d.ts +59 -0
  170. package/dist/agent/toolResultOffload.d.ts.map +1 -0
  171. package/dist/agent/toolResultOffload.js +70 -0
  172. package/dist/agent/toolResultOffload.js.map +1 -0
  173. package/dist/agent/toolRunner.d.ts +59 -0
  174. package/dist/agent/toolRunner.d.ts.map +1 -0
  175. package/dist/agent/toolRunner.js +147 -0
  176. package/dist/agent/toolRunner.js.map +1 -0
  177. package/dist/agent/tracer.d.ts +99 -107
  178. package/dist/agent/tracer.d.ts.map +1 -1
  179. package/dist/agent/tracer.js +24 -69
  180. package/dist/agent/tracer.js.map +1 -1
  181. package/dist/agent/types.d.ts +510 -169
  182. package/dist/agent/types.d.ts.map +1 -1
  183. package/dist/agent/types.js +2 -51
  184. package/dist/agent/types.js.map +1 -1
  185. package/dist/code-exec/codeExecutionProvider.d.ts +16 -0
  186. package/dist/code-exec/codeExecutionProvider.d.ts.map +1 -0
  187. package/dist/code-exec/codeExecutionProvider.js +57 -0
  188. package/dist/code-exec/codeExecutionProvider.js.map +1 -0
  189. package/dist/code-exec/types.d.ts +37 -0
  190. package/dist/code-exec/types.d.ts.map +1 -0
  191. package/dist/code-exec/types.js +12 -0
  192. package/dist/code-exec/types.js.map +1 -0
  193. package/dist/config/expandEnvVars.d.ts +22 -0
  194. package/dist/config/expandEnvVars.d.ts.map +1 -0
  195. package/dist/config/expandEnvVars.js +38 -0
  196. package/dist/config/expandEnvVars.js.map +1 -0
  197. package/dist/config/loader.d.ts +27 -98
  198. package/dist/config/loader.d.ts.map +1 -1
  199. package/dist/config/loader.js +110 -223
  200. package/dist/config/loader.js.map +1 -1
  201. package/dist/index.d.ts +67 -77
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js +90 -69
  204. package/dist/index.js.map +1 -1
  205. package/dist/llm/abortSignal.d.ts +2 -3
  206. package/dist/llm/abortSignal.d.ts.map +1 -1
  207. package/dist/llm/abortSignal.js +2 -3
  208. package/dist/llm/abortSignal.js.map +1 -1
  209. package/dist/llm/factory.d.ts +22 -32
  210. package/dist/llm/factory.d.ts.map +1 -1
  211. package/dist/llm/factory.js +29 -46
  212. package/dist/llm/factory.js.map +1 -1
  213. package/dist/llm/openaiCompatible.d.ts +25 -40
  214. package/dist/llm/openaiCompatible.d.ts.map +1 -1
  215. package/dist/llm/openaiCompatible.js +179 -120
  216. package/dist/llm/openaiCompatible.js.map +1 -1
  217. package/dist/llm/provider.d.ts +29 -42
  218. package/dist/llm/provider.d.ts.map +1 -1
  219. package/dist/llm/provider.js +11 -10
  220. package/dist/llm/provider.js.map +1 -1
  221. package/dist/llm/types.d.ts +54 -11
  222. package/dist/llm/types.d.ts.map +1 -1
  223. package/dist/llm/types.js +0 -5
  224. package/dist/llm/types.js.map +1 -1
  225. package/dist/logging/logger.d.ts +8 -31
  226. package/dist/logging/logger.d.ts.map +1 -1
  227. package/dist/logging/logger.js +28 -215
  228. package/dist/logging/logger.js.map +1 -1
  229. package/dist/logging/loggerInterface.d.ts +9 -8
  230. package/dist/logging/loggerInterface.d.ts.map +1 -1
  231. package/dist/memory/gcService.d.ts +164 -0
  232. package/dist/memory/gcService.d.ts.map +1 -0
  233. package/dist/memory/gcService.js +215 -0
  234. package/dist/memory/gcService.js.map +1 -0
  235. package/dist/memory/governance.d.ts +11 -44
  236. package/dist/memory/governance.d.ts.map +1 -1
  237. package/dist/memory/governance.js +11 -64
  238. package/dist/memory/governance.js.map +1 -1
  239. package/dist/memory/inMemoryRoundStore.d.ts +124 -0
  240. package/dist/memory/inMemoryRoundStore.d.ts.map +1 -0
  241. package/dist/memory/inMemoryRoundStore.js +216 -0
  242. package/dist/memory/inMemoryRoundStore.js.map +1 -0
  243. package/dist/memory/inMemorySessionStore.d.ts +92 -0
  244. package/dist/memory/inMemorySessionStore.d.ts.map +1 -0
  245. package/dist/memory/inMemorySessionStore.js +219 -0
  246. package/dist/memory/inMemorySessionStore.js.map +1 -0
  247. package/dist/memory/inMemorySessionViewLoader.d.ts +89 -0
  248. package/dist/memory/inMemorySessionViewLoader.d.ts.map +1 -0
  249. package/dist/memory/inMemorySessionViewLoader.js +183 -0
  250. package/dist/memory/inMemorySessionViewLoader.js.map +1 -0
  251. package/dist/memory/inMemoryStorage.d.ts +25 -175
  252. package/dist/memory/inMemoryStorage.d.ts.map +1 -1
  253. package/dist/memory/inMemoryStorage.js +32 -221
  254. package/dist/memory/inMemoryStorage.js.map +1 -1
  255. package/dist/memory/keywordsTouch.d.ts +20 -0
  256. package/dist/memory/keywordsTouch.d.ts.map +1 -0
  257. package/dist/memory/keywordsTouch.js +25 -0
  258. package/dist/memory/keywordsTouch.js.map +1 -0
  259. package/dist/memory/lockManager.d.ts +2 -2
  260. package/dist/memory/lockManager.d.ts.map +1 -1
  261. package/dist/memory/lockManager.js +6 -8
  262. package/dist/memory/lockManager.js.map +1 -1
  263. package/dist/memory/projectManager.d.ts +30 -129
  264. package/dist/memory/projectManager.d.ts.map +1 -1
  265. package/dist/memory/projectManager.js +39 -189
  266. package/dist/memory/projectManager.js.map +1 -1
  267. package/dist/memory/projectRegistry.d.ts +14 -62
  268. package/dist/memory/projectRegistry.d.ts.map +1 -1
  269. package/dist/memory/projectRegistry.js +27 -111
  270. package/dist/memory/projectRegistry.js.map +1 -1
  271. package/dist/memory/roundStore.d.ts +629 -0
  272. package/dist/memory/roundStore.d.ts.map +1 -0
  273. package/dist/memory/roundStore.js +116 -0
  274. package/dist/memory/roundStore.js.map +1 -0
  275. package/dist/memory/sessionStore.d.ts +70 -61
  276. package/dist/memory/sessionStore.d.ts.map +1 -1
  277. package/dist/memory/sessionStore.js +23 -1
  278. package/dist/memory/sessionStore.js.map +1 -1
  279. package/dist/memory/sessionViewLoader.d.ts +141 -0
  280. package/dist/memory/sessionViewLoader.d.ts.map +1 -0
  281. package/dist/memory/sessionViewLoader.js +65 -0
  282. package/dist/memory/sessionViewLoader.js.map +1 -0
  283. package/dist/memory/sourceValidation.d.ts +10 -12
  284. package/dist/memory/sourceValidation.d.ts.map +1 -1
  285. package/dist/memory/sourceValidation.js +16 -32
  286. package/dist/memory/sourceValidation.js.map +1 -1
  287. package/dist/memory/storageInterface.d.ts +44 -150
  288. package/dist/memory/storageInterface.d.ts.map +1 -1
  289. package/dist/memory/types.d.ts +65 -164
  290. package/dist/memory/types.d.ts.map +1 -1
  291. package/dist/memory/types.js +81 -83
  292. package/dist/memory/types.js.map +1 -1
  293. package/dist/project-search/projectSearchProvider.d.ts +29 -0
  294. package/dist/project-search/projectSearchProvider.d.ts.map +1 -0
  295. package/dist/project-search/projectSearchProvider.js +57 -0
  296. package/dist/project-search/projectSearchProvider.js.map +1 -0
  297. package/dist/project-search/terms.d.ts +14 -0
  298. package/dist/project-search/terms.d.ts.map +1 -0
  299. package/dist/project-search/terms.js +68 -0
  300. package/dist/project-search/terms.js.map +1 -0
  301. package/dist/project-search/types.d.ts +139 -0
  302. package/dist/project-search/types.d.ts.map +1 -0
  303. package/dist/project-search/types.js +8 -0
  304. package/dist/project-search/types.js.map +1 -0
  305. package/dist/role-pack/capabilityMap.d.ts +28 -0
  306. package/dist/role-pack/capabilityMap.d.ts.map +1 -0
  307. package/dist/role-pack/capabilityMap.js +56 -0
  308. package/dist/role-pack/capabilityMap.js.map +1 -0
  309. package/dist/role-pack/constants.d.ts +21 -0
  310. package/dist/role-pack/constants.d.ts.map +1 -0
  311. package/dist/role-pack/constants.js +21 -0
  312. package/dist/role-pack/constants.js.map +1 -0
  313. package/dist/role-pack/rolePackManager.d.ts +269 -0
  314. package/dist/role-pack/rolePackManager.d.ts.map +1 -0
  315. package/dist/role-pack/rolePackManager.js +1082 -0
  316. package/dist/role-pack/rolePackManager.js.map +1 -0
  317. package/dist/role-pack/strategyKeys.d.ts +100 -0
  318. package/dist/role-pack/strategyKeys.d.ts.map +1 -0
  319. package/dist/role-pack/strategyKeys.js +184 -0
  320. package/dist/role-pack/strategyKeys.js.map +1 -0
  321. package/dist/role-pack/strategyResolver.d.ts +109 -0
  322. package/dist/role-pack/strategyResolver.d.ts.map +1 -0
  323. package/dist/role-pack/strategyResolver.js +304 -0
  324. package/dist/role-pack/strategyResolver.js.map +1 -0
  325. package/dist/role-pack/types.d.ts +237 -0
  326. package/dist/role-pack/types.d.ts.map +1 -0
  327. package/dist/role-pack/types.js +8 -0
  328. package/dist/role-pack/types.js.map +1 -0
  329. package/dist/role-pack/validator.d.ts +38 -0
  330. package/dist/role-pack/validator.d.ts.map +1 -0
  331. package/dist/role-pack/validator.js +436 -0
  332. package/dist/role-pack/validator.js.map +1 -0
  333. package/dist/security/pathGuard.d.ts +69 -72
  334. package/dist/security/pathGuard.d.ts.map +1 -1
  335. package/dist/security/pathGuard.js +151 -131
  336. package/dist/security/pathGuard.js.map +1 -1
  337. package/dist/skill/skillLayer3.d.ts +91 -0
  338. package/dist/skill/skillLayer3.d.ts.map +1 -0
  339. package/dist/skill/skillLayer3.js +104 -0
  340. package/dist/skill/skillLayer3.js.map +1 -0
  341. package/dist/skill/skillManager.d.ts +136 -19
  342. package/dist/skill/skillManager.d.ts.map +1 -1
  343. package/dist/skill/skillManager.js +312 -61
  344. package/dist/skill/skillManager.js.map +1 -1
  345. package/dist/skill/skillScriptRunner.d.ts +97 -0
  346. package/dist/skill/skillScriptRunner.d.ts.map +1 -0
  347. package/dist/skill/skillScriptRunner.js +271 -0
  348. package/dist/skill/skillScriptRunner.js.map +1 -0
  349. package/dist/skill/types.d.ts +73 -16
  350. package/dist/skill/types.d.ts.map +1 -1
  351. package/dist/skill/types.js +5 -1
  352. package/dist/skill/types.js.map +1 -1
  353. package/dist/utils/array.d.ts +5 -6
  354. package/dist/utils/array.d.ts.map +1 -1
  355. package/dist/utils/array.js +6 -6
  356. package/dist/utils/array.js.map +1 -1
  357. package/dist/utils/atomicWrite.d.ts +8 -0
  358. package/dist/utils/atomicWrite.d.ts.map +1 -0
  359. package/dist/utils/atomicWrite.js +31 -0
  360. package/dist/utils/atomicWrite.js.map +1 -0
  361. package/dist/utils/backgroundTask.d.ts +38 -0
  362. package/dist/utils/backgroundTask.d.ts.map +1 -0
  363. package/dist/utils/backgroundTask.js +117 -0
  364. package/dist/utils/backgroundTask.js.map +1 -0
  365. package/dist/utils/configResourceManager.d.ts +40 -72
  366. package/dist/utils/configResourceManager.d.ts.map +1 -1
  367. package/dist/utils/configResourceManager.js +78 -76
  368. package/dist/utils/configResourceManager.js.map +1 -1
  369. package/dist/utils/errors.d.ts +44 -69
  370. package/dist/utils/errors.d.ts.map +1 -1
  371. package/dist/utils/errors.js +54 -71
  372. package/dist/utils/errors.js.map +1 -1
  373. package/dist/utils/eventEmitter.d.ts +104 -103
  374. package/dist/utils/eventEmitter.d.ts.map +1 -1
  375. package/dist/utils/eventEmitter.js +37 -45
  376. package/dist/utils/eventEmitter.js.map +1 -1
  377. package/dist/utils/fileSafe.d.ts +20 -0
  378. package/dist/utils/fileSafe.d.ts.map +1 -0
  379. package/dist/utils/fileSafe.js +56 -0
  380. package/dist/utils/fileSafe.js.map +1 -0
  381. package/dist/utils/frontmatter.d.ts +2 -3
  382. package/dist/utils/frontmatter.d.ts.map +1 -1
  383. package/dist/utils/frontmatter.js +2 -3
  384. package/dist/utils/frontmatter.js.map +1 -1
  385. package/dist/utils/hash.d.ts +12 -0
  386. package/dist/utils/hash.d.ts.map +1 -0
  387. package/dist/utils/hash.js +27 -0
  388. package/dist/utils/hash.js.map +1 -0
  389. package/dist/utils/http.d.ts +17 -0
  390. package/dist/utils/http.d.ts.map +1 -0
  391. package/dist/utils/http.js +29 -0
  392. package/dist/utils/http.js.map +1 -0
  393. package/dist/utils/json.d.ts +1 -1
  394. package/dist/utils/json.js +1 -1
  395. package/dist/utils/math.d.ts +25 -3
  396. package/dist/utils/math.d.ts.map +1 -1
  397. package/dist/utils/math.js +32 -16
  398. package/dist/utils/math.js.map +1 -1
  399. package/dist/utils/objects.d.ts +2 -3
  400. package/dist/utils/objects.d.ts.map +1 -1
  401. package/dist/utils/objects.js +2 -3
  402. package/dist/utils/objects.js.map +1 -1
  403. package/dist/utils/recallDefaults.d.ts +16 -0
  404. package/dist/utils/recallDefaults.d.ts.map +1 -0
  405. package/dist/utils/recallDefaults.js +16 -0
  406. package/dist/utils/recallDefaults.js.map +1 -0
  407. package/dist/utils/safeTimer.d.ts +8 -36
  408. package/dist/utils/safeTimer.d.ts.map +1 -1
  409. package/dist/utils/safeTimer.js +9 -37
  410. package/dist/utils/safeTimer.js.map +1 -1
  411. package/dist/utils/scanner.d.ts +97 -17
  412. package/dist/utils/scanner.d.ts.map +1 -1
  413. package/dist/utils/scanner.js +269 -47
  414. package/dist/utils/scanner.js.map +1 -1
  415. package/dist/utils/segmenter.d.ts +20 -19
  416. package/dist/utils/segmenter.d.ts.map +1 -1
  417. package/dist/utils/segmenter.js +230 -97
  418. package/dist/utils/segmenter.js.map +1 -1
  419. package/dist/utils/strings.d.ts +15 -32
  420. package/dist/utils/strings.d.ts.map +1 -1
  421. package/dist/utils/strings.js +25 -44
  422. package/dist/utils/strings.js.map +1 -1
  423. package/dist/utils/time.d.ts +37 -0
  424. package/dist/utils/time.d.ts.map +1 -1
  425. package/dist/utils/time.js +56 -0
  426. package/dist/utils/time.js.map +1 -1
  427. package/dist/utils/toError.d.ts +13 -1
  428. package/dist/utils/toError.d.ts.map +1 -1
  429. package/dist/utils/toError.js +18 -1
  430. package/dist/utils/toError.js.map +1 -1
  431. package/dist/web-fetch/fetchWebFetchProvider.d.ts +14 -0
  432. package/dist/web-fetch/fetchWebFetchProvider.d.ts.map +1 -0
  433. package/dist/web-fetch/fetchWebFetchProvider.js +69 -0
  434. package/dist/web-fetch/fetchWebFetchProvider.js.map +1 -0
  435. package/dist/web-fetch/types.d.ts +30 -0
  436. package/dist/web-fetch/types.d.ts.map +1 -0
  437. package/dist/web-fetch/types.js +7 -0
  438. package/dist/web-fetch/types.js.map +1 -0
  439. package/dist/web-fetch/webFetchProvider.d.ts +10 -0
  440. package/dist/web-fetch/webFetchProvider.d.ts.map +1 -0
  441. package/dist/web-fetch/webFetchProvider.js +28 -0
  442. package/dist/web-fetch/webFetchProvider.js.map +1 -0
  443. package/dist/web-search/fetchWebSearchProvider.d.ts +27 -0
  444. package/dist/web-search/fetchWebSearchProvider.d.ts.map +1 -0
  445. package/dist/web-search/fetchWebSearchProvider.js +199 -0
  446. package/dist/web-search/fetchWebSearchProvider.js.map +1 -0
  447. package/dist/web-search/types.d.ts +46 -0
  448. package/dist/web-search/types.d.ts.map +1 -0
  449. package/dist/web-search/types.js +2 -0
  450. package/dist/{persona → web-search}/types.js.map +1 -1
  451. package/dist/web-search/webSearchProvider.d.ts +10 -0
  452. package/dist/web-search/webSearchProvider.d.ts.map +1 -0
  453. package/dist/web-search/webSearchProvider.js +30 -0
  454. package/dist/web-search/webSearchProvider.js.map +1 -0
  455. package/docs/architecture/role-pack-authoring-guide.md +243 -0
  456. package/docs/architecture/role-pack-spec.md +767 -0
  457. package/docs/memora-api-reference.md +416 -476
  458. package/docs/memora-/346/216/245/345/205/245/346/214/207/345/215/227.md +841 -806
  459. package/docs/role-pack-/345/274/200/346/224/276/351/224/256/346/214/207/345/215/227.md +148 -0
  460. package/package.json +105 -100
  461. package/role-packs/README.md +41 -0
  462. package/role-packs/memora/345/212/251/346/211/213/manifest.json +12 -0
  463. package/role-packs/memora/345/212/251/346/211/213/persona.md +12 -0
  464. package/role-packs/memora/345/212/251/346/211/213/rules.md +4 -0
  465. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/manifest.json +44 -0
  466. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/persona.md +46 -0
  467. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/rules.md +15 -0
  468. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/character-sheet.md +34 -0
  469. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/core-extractor.md +37 -0
  470. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/craft-review.md +69 -0
  471. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/dialogue-craft.md +45 -0
  472. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/emotion-wave.md +46 -0
  473. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/empathy-craft.md +79 -0
  474. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/foreshadow.md +29 -0
  475. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/hotspot-mapping.md +121 -0
  476. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/idea-lever.md +42 -0
  477. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/logline-craft.md +47 -0
  478. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/longform-guard.md +64 -0
  479. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/need-finder.md +40 -0
  480. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/outline-expand.md +46 -0
  481. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/pacing-hook.md +34 -0
  482. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/polish-method.md +113 -0
  483. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/pov-discipline.md +79 -0
  484. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/project-init/SKILL.md +112 -0
  485. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/project-init/scripts/init-novel-project.mjs +441 -0
  486. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/relationship-web.md +47 -0
  487. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/scene-craft.md +46 -0
  488. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/story-bible.md +60 -0
  489. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/story-structure.md +36 -0
  490. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/style-weaver.md +109 -0
  491. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/three-layer-check.md +27 -0
  492. package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/world-builder.md +41 -0
  493. package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/manifest.json +48 -0
  494. package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/persona.md +73 -0
  495. package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/rules.md +19 -0
  496. package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/skills/api-doc-writer.md +40 -0
  497. package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/skills/doc-planner.md +42 -0
  498. package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/skills/nutrient-search.md +28 -0
  499. package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/skills/seed-finder.md +28 -0
  500. package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/skills/ssot-audit.md +34 -0
  501. package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/skills/style-guide.md +40 -0
  502. package/dist/agent/guardrail.d.ts +0 -49
  503. package/dist/agent/guardrail.d.ts.map +0 -1
  504. package/dist/agent/guardrail.js +0 -59
  505. package/dist/agent/guardrail.js.map +0 -1
  506. package/dist/agent/managers/autoConfigRefiner.d.ts +0 -39
  507. package/dist/agent/managers/autoConfigRefiner.d.ts.map +0 -1
  508. package/dist/agent/managers/autoConfigRefiner.js +0 -146
  509. package/dist/agent/managers/autoConfigRefiner.js.map +0 -1
  510. package/dist/agent/managers/configManager.d.ts +0 -209
  511. package/dist/agent/managers/configManager.d.ts.map +0 -1
  512. package/dist/agent/managers/configManager.js +0 -331
  513. package/dist/agent/managers/configManager.js.map +0 -1
  514. package/dist/agent/managers/insightExtractor.d.ts +0 -139
  515. package/dist/agent/managers/insightExtractor.d.ts.map +0 -1
  516. package/dist/agent/managers/insightExtractor.js +0 -401
  517. package/dist/agent/managers/insightExtractor.js.map +0 -1
  518. package/dist/agent/managers/memoryDecayScheduler.d.ts +0 -239
  519. package/dist/agent/managers/memoryDecayScheduler.d.ts.map +0 -1
  520. package/dist/agent/managers/memoryDecayScheduler.js +0 -413
  521. package/dist/agent/managers/memoryDecayScheduler.js.map +0 -1
  522. package/dist/agent/managers/relationBuilder.d.ts +0 -131
  523. package/dist/agent/managers/relationBuilder.d.ts.map +0 -1
  524. package/dist/agent/managers/relationBuilder.js +0 -192
  525. package/dist/agent/managers/relationBuilder.js.map +0 -1
  526. package/dist/agent/personaMatcher.d.ts +0 -29
  527. package/dist/agent/personaMatcher.d.ts.map +0 -1
  528. package/dist/agent/personaMatcher.js +0 -60
  529. package/dist/agent/personaMatcher.js.map +0 -1
  530. package/dist/agent/userFactExtractor.d.ts +0 -25
  531. package/dist/agent/userFactExtractor.d.ts.map +0 -1
  532. package/dist/agent/userFactExtractor.js +0 -88
  533. package/dist/agent/userFactExtractor.js.map +0 -1
  534. package/dist/eval/evalRunner.d.ts +0 -94
  535. package/dist/eval/evalRunner.d.ts.map +0 -1
  536. package/dist/eval/evalRunner.js +0 -141
  537. package/dist/eval/evalRunner.js.map +0 -1
  538. package/dist/eval/evalTypes.d.ts +0 -148
  539. package/dist/eval/evalTypes.d.ts.map +0 -1
  540. package/dist/eval/evalTypes.js +0 -118
  541. package/dist/eval/evalTypes.js.map +0 -1
  542. package/dist/eval/scenarios.d.ts +0 -33
  543. package/dist/eval/scenarios.d.ts.map +0 -1
  544. package/dist/eval/scenarios.js +0 -109
  545. package/dist/eval/scenarios.js.map +0 -1
  546. package/dist/llm/embedding.d.ts +0 -79
  547. package/dist/llm/embedding.d.ts.map +0 -1
  548. package/dist/llm/embedding.js +0 -184
  549. package/dist/llm/embedding.js.map +0 -1
  550. package/dist/memory/hybridMerge.d.ts +0 -50
  551. package/dist/memory/hybridMerge.d.ts.map +0 -1
  552. package/dist/memory/hybridMerge.js +0 -51
  553. package/dist/memory/hybridMerge.js.map +0 -1
  554. package/dist/memory/inMemoryRelationStore.d.ts +0 -58
  555. package/dist/memory/inMemoryRelationStore.d.ts.map +0 -1
  556. package/dist/memory/inMemoryRelationStore.js +0 -80
  557. package/dist/memory/inMemoryRelationStore.js.map +0 -1
  558. package/dist/memory/loader.d.ts +0 -51
  559. package/dist/memory/loader.d.ts.map +0 -1
  560. package/dist/memory/loader.js +0 -100
  561. package/dist/memory/loader.js.map +0 -1
  562. package/dist/memory/recall.d.ts +0 -82
  563. package/dist/memory/recall.d.ts.map +0 -1
  564. package/dist/memory/recall.js +0 -157
  565. package/dist/memory/recall.js.map +0 -1
  566. package/dist/memory/relationStore.d.ts +0 -95
  567. package/dist/memory/relationStore.d.ts.map +0 -1
  568. package/dist/memory/relationStore.js +0 -2
  569. package/dist/memory/relationStore.js.map +0 -1
  570. package/dist/memory/store.d.ts +0 -71
  571. package/dist/memory/store.d.ts.map +0 -1
  572. package/dist/memory/store.js +0 -199
  573. package/dist/memory/store.js.map +0 -1
  574. package/dist/memory/userProfile.d.ts +0 -180
  575. package/dist/memory/userProfile.d.ts.map +0 -1
  576. package/dist/memory/userProfile.js +0 -381
  577. package/dist/memory/userProfile.js.map +0 -1
  578. package/dist/memory/vectorStore.d.ts +0 -179
  579. package/dist/memory/vectorStore.d.ts.map +0 -1
  580. package/dist/memory/vectorStore.js +0 -284
  581. package/dist/memory/vectorStore.js.map +0 -1
  582. package/dist/persona/personaManager.d.ts +0 -109
  583. package/dist/persona/personaManager.d.ts.map +0 -1
  584. package/dist/persona/personaManager.js +0 -315
  585. package/dist/persona/personaManager.js.map +0 -1
  586. package/dist/persona/types.d.ts +0 -32
  587. package/dist/persona/types.d.ts.map +0 -1
  588. package/dist/persona/types.js +0 -5
@@ -1,130 +1,146 @@
1
+ import { isRoundSettled } from '../memory/roundStore.js';
2
+ import { LOOP_CONSTANTS } from '../agent/constants.js';
1
3
  import { logger } from '../logging/logger.js';
2
4
  import { configError } from '../utils/errors.js';
3
5
  import { safeSetTimeout } from '../utils/safeTimer.js';
4
6
  import { nowIso, todayDate } from '../utils/time.js';
5
- /**
6
- * 消息历史类
7
- */
7
+ /** 消息历史类 */
8
8
  export class MessageHistory {
9
9
  sessionStore;
10
+ roundStore;
10
11
  /** 当前日期 YYYY-MM-DD */
11
12
  currentDate;
12
13
  /** 当前会话标识(不含日期前缀) */
13
14
  currentSession;
14
- /**
15
- * 挂起的归档企划集合,Agent.close() 等待它们完成
16
- * 容纳 Promise<void>(fire-and-forget 内部)
17
- */
15
+ /** 挂起的 fire-and-forget 归档集合,Agent.close() 等待其完成 */
18
16
  pendingArchives = new Set();
17
+ /** Round-based 模式下当前轮次的 pending Round 缓存(roundId → Round) */
18
+ pendingRounds = new Map();
19
19
  constructor(
20
- /**
21
- * 会话存储(可选)
22
- * 注入后,消息会持久化到宿主提供的存储实现。
23
- * 不注入则仅在内存中保存(AgentLoop.messages[])。
24
- */
25
- sessionStore, initialDate, initialSession = 'main') {
20
+ /** 会话存储(可选);注入则持久化,否则仅在内存保存(AgentLoop.messages[]) */
21
+ sessionStore, initialDate, initialSession = 'main',
22
+ /** 问答闭环存储(可选);注入则启用 round-based 模式(消息内容唯一真相源) */
23
+ roundStore) {
26
24
  this.sessionStore = sessionStore;
25
+ this.roundStore = roundStore;
27
26
  this.currentDate = initialDate ?? todayDate();
28
27
  this.currentSession = initialSession;
29
28
  }
30
- /**
31
- * 获取当前会话名(日期-会话组合名)
32
- */
29
+ /** 当前会话名(date-session 组合名) */
33
30
  get currentSessionName() {
34
31
  return `${this.currentDate}-${this.currentSession}`;
35
32
  }
36
- /** 获取当前日期 YYYY-MM-DD(只读,供 agent 层使用) */
33
+ /** 当前日期 YYYY-MM-DD */
37
34
  get currentDateValue() {
38
35
  return this.currentDate;
39
36
  }
40
- /** 获取当前会话标识(只读,供 agent 层使用) */
37
+ /** 当前会话标识 */
41
38
  get currentSessionValue() {
42
39
  return this.currentSession;
43
40
  }
44
41
  /**
45
- * 获取当前会话标识
42
+ * 当前会话第一条轮次的 roundId(会话起点背景,互斥排除用)。
43
+ * 装配时若第一条不在最近轮内(长会话),完整对话层显式补入第一条,其 roundId 须计入 exclude
44
+ * 避免其摘要被二次召回。
46
45
  */
46
+ getFirstRoundId() {
47
+ if (!this.sessionStore)
48
+ return null;
49
+ try {
50
+ const messages = this.sessionStore.loadMessages(this.currentDate, this.currentSession);
51
+ for (const m of messages) {
52
+ if (m.roundId)
53
+ return m.roundId;
54
+ }
55
+ return null;
56
+ }
57
+ catch (err) {
58
+ logger.warn({ err }, '获取首轮 roundId 失败,跳过互斥排除');
59
+ return null;
60
+ }
61
+ }
62
+ /** 当前会话标识 */
47
63
  get session() {
48
64
  return this.currentSession;
49
65
  }
50
- /**
51
- * 切换会话
52
- * @param newSession - 新会话标识
53
- * @returns 新会话的全名
54
- */
66
+ /** 切换会话,返回新会话全名 */
55
67
  switchSession(newSession) {
56
68
  this.currentSession = newSession;
69
+ // 清空 pending rounds(会话切换后旧 pending round 不再有效)
70
+ this.pendingRounds.clear();
57
71
  return this.currentSessionName;
58
72
  }
59
73
  /**
60
- * 自动生成分支名
61
- *
62
- * 算法:扫描已存在会话,找到以 sourceSession-b 为前缀的最大序号,+1
63
- *
64
- * @param sourceSession - 源会话标识
65
- * @returns 自动生成的分支名(如 "main-b1")
74
+ * 自动生成会话名(平等普通会话命名,无分叉标记)。
75
+ * 使用时间戳生成唯一名称,实际应委托给 SessionNamer 生成有意义的标题。
66
76
  */
67
- autoBranchName(sourceSession) {
77
+ generateSessionName() {
78
+ return `session-${Date.now().toString(36)}`;
79
+ }
80
+ /**
81
+ * 获取当前会话的 Round ID 列表(单一 round-based 路径)
82
+ */
83
+ getCurrentRoundIds() {
68
84
  if (!this.sessionStore)
69
- return `${sourceSession}-b1`;
70
- const allSessions = this.sessionStore.listSessions();
71
- const prefix = `${sourceSession}-b`;
72
- // 提取匹配前缀的序号
73
- const existingNumbers = [];
74
- for (const fullSession of allSessions) {
75
- // fullSession 格式:YYYY-MM-DD-session
76
- const parts = fullSession.split('-');
77
- if (parts.length >= 4) {
78
- const sessionPart = parts.slice(3).join('-');
79
- if (sessionPart.startsWith(prefix)) {
80
- const numStr = sessionPart.slice(prefix.length);
81
- const num = parseInt(numStr, 10);
82
- if (!isNaN(num)) {
83
- existingNumbers.push(num);
84
- }
85
- }
86
- }
87
- }
88
- const nextNumber = existingNumbers.length > 0 ? Math.max(...existingNumbers) + 1 : 1;
89
- return `${prefix}${nextNumber}`;
85
+ return [];
86
+ const sessionId = this.currentSessionName;
87
+ return this.sessionStore.getRoundIds(sessionId);
88
+ }
89
+ /**
90
+ * 获取当前会话的元数据
91
+ */
92
+ getCurrentSessionMeta() {
93
+ if (!this.sessionStore)
94
+ return undefined;
95
+ const getMetaFn = this.sessionStore.getSessionMeta;
96
+ if (!getMetaFn)
97
+ return undefined;
98
+ return getMetaFn.call(this.sessionStore, this.currentSessionName);
90
99
  }
91
100
  /**
92
- * 分叉当前会话
101
+ * 从指定 Round 位置分叉会话(唯一分叉方式,round-based)
93
102
  *
94
- * 流程:
95
- * 1. 从 sessionStore 加载当前会话全部消息
96
- * 2. 生成唯一新会话名
97
- * 3. 通过 sessionStore.copySession() 复制到新会话
98
- * 4. switchSession() 切换当前会话标识到新会话
103
+ * 核心操作:复制 Round ID 列表(指针复制,不复制数据)
104
+ * 新会话是完全平等的普通会话,无特殊标记。
99
105
  *
100
- * @param targetSession - 自定义目标会话名(可选,不传则自动生成)
101
- * @returns 分叉结果
102
- * @throws 若 sessionStore 未注入、copySession 未实现或当前会话无消息
106
+ * @param roundId - 分叉点的 Round ID(必须存在于当前会话)
107
+ * @param targetSession - 可选,自定义新会话名;不传则自动生成
108
+ * @returns 分叉结果(含新会话 ID 和 roundIds)
109
+ * @throws 会话不存在 / Round 不存在 / 对话繁忙时抛错
103
110
  */
104
- forkSession(targetSession) {
111
+ forkSession(roundId, targetSession) {
105
112
  if (!this.sessionStore) {
106
113
  throw configError('无法分叉会话', 'ISessionStore 未注入', [
107
114
  '在创建 Agent 时注入 sessionStore 参数',
108
115
  ]);
109
116
  }
110
- if (!this.sessionStore.copySession) {
111
- throw configError('无法分叉会话', 'ISessionStore.copySession 未实现', [
112
- '升级宿主项目的 ISessionStore 实现,添加 copySession() 方法',
113
- ]);
117
+ const store = this.sessionStore;
118
+ // 1. 获取当前会话元数据
119
+ const currentSession = this.getCurrentSessionMeta();
120
+ if (!currentSession) {
121
+ throw configError('无法分叉会话', '当前会话不存在', ['确认当前会话是否已正确创建']);
122
+ }
123
+ // 2. 获取 Round ID 列表
124
+ const currentRoundIds = this.getCurrentRoundIds();
125
+ if (!currentRoundIds.length) {
126
+ throw configError('无法分叉会话', '当前会话无问答闭环', ['先进行一些对话后再尝试分叉']);
114
127
  }
115
- const sourceDate = this.currentDate;
116
- const sourceSession = this.currentSession;
117
- // 加载源会话消息
118
- const messages = this.sessionStore.loadMessages(sourceDate, sourceSession);
119
- if (messages.length === 0) {
120
- throw configError('无法分叉会话', '当前会话无消息', ['先进行一些对话后再尝试分叉']);
128
+ // 3. 定位分叉点(不传 roundId 则默认使用最后一个)
129
+ const effectiveRoundId = roundId ?? currentRoundIds[currentRoundIds.length - 1];
130
+ const forkIdx = currentRoundIds.indexOf(effectiveRoundId);
131
+ if (forkIdx === -1) {
132
+ throw configError('无法分叉会话', `Round 不存在于当前会话: ${effectiveRoundId}`, [
133
+ '确认分叉点是当前会话中的问答闭环',
134
+ ]);
121
135
  }
122
- // 生成目标会话名
136
+ // 4. 截取到分叉点的 ID 列表(包含分叉点)
137
+ const newRoundIds = currentRoundIds.slice(0, forkIdx + 1);
138
+ // 5. 生成新会话名(平等普通会话,无分叉标记)
123
139
  let newSession;
124
140
  if (targetSession) {
125
- // 检查目标会话在当天是否已存在
141
+ // 检查目标会话当天是否已存在
126
142
  const targetFullName = `${todayDate()}-${targetSession}`;
127
- const existingSessions = this.sessionStore.listSessions();
143
+ const existingSessions = store.listSessions();
128
144
  if (existingSessions.includes(targetFullName)) {
129
145
  throw configError('无法分叉会话', `当天会话 "${targetSession}" 已存在`, [
130
146
  '使用不同的名称,或不传参数自动生成',
@@ -133,73 +149,323 @@ export class MessageHistory {
133
149
  newSession = targetSession;
134
150
  }
135
151
  else {
136
- newSession = this.autoBranchName(sourceSession);
152
+ newSession = this.generateSessionName();
153
+ }
154
+ // 6. 创建新会话(Round ID 列表 + 引用计数增加)
155
+ const newSessionId = `${todayDate()}-${newSession}`;
156
+ // 设置 Round ID 列表(唯一 round-based 路径)
157
+ store.setRoundIds(newSessionId, newRoundIds);
158
+ // 保存会话元数据
159
+ store.updateSessionMeta(newSessionId, {
160
+ createdAt: new Date().toISOString(),
161
+ });
162
+ // 7. 增加引用计数(新会话引用这些 Round)
163
+ for (const id of newRoundIds) {
164
+ this.roundStore?.incrementRef(id);
137
165
  }
138
- // 计算目标日期
139
- const targetDate = todayDate();
140
- // 原子复制消息
141
- this.sessionStore.copySession(sourceDate, sourceSession, targetDate, newSession);
142
- // 切换当前会话到新分支
166
+ // 8. 切换到新会话(同步日期锚点为今天:分叉键 = todayDate()-newSession,
167
+ // 切换身份必须与建键一致,防跨天后 currentDate 停在源会话旧日期导致写入错位)
168
+ this.currentDate = todayDate();
143
169
  this.switchSession(newSession);
144
- logger.info({ from: sourceSession, to: newSession, messageCount: messages.length }, '会话分叉完成');
145
- return { newSession, date: targetDate, messages };
170
+ logger.info({ from: currentSession.sessionId, to: newSession, roundCount: newRoundIds.length }, '会话分叉完成');
171
+ return { newSession, date: todayDate(), roundIds: newRoundIds };
146
172
  }
147
173
  /**
148
- * 追加 user 消息到当前会话
149
- * 失败不抛出(消息持久化失败不应阻塞对话)
174
+ * 追加 user 消息到当前会话(持久化失败不抛出,不阻塞对话)。
150
175
  *
151
- * 日期使用 todayDate() 动态获取,而非缓存的 this.currentDate,
152
- * 确保跨日后消息写入当天目录。
176
+ * Round-based 路径:roundStore 注入且 roundId 存在时,创建 pending Round
177
+ * 写入 RoundStore(refCount=0,未完成不登记会话)。**仅 complete 才 appendRoundId**——
178
+ * 崩溃残留的 pending 轮是孤儿(refCount=0),可由 GC 清理,不污染会话视图。
179
+ *
180
+ * 交互输入:opts.interactive 为真且 roundId 对应轮已存在(prepare 建 pending 或
181
+ * 暂停已完成轮)时,不再创建/覆盖新轮——按序追加到该轮 interactiveInputs,保问答闭环不分裂。
182
+ *
183
+ * @param content 用户输入内容
184
+ * @param roundId 闭环节点轮次 ID(可选,交互输入必须携带 = appendUser 的 head roundId)
185
+ * @param opts 交互输入选项(interactive=是否交互归属;kind=折叠块类型文案;
186
+ * question/options=该回答所对的 ask_user 提问原文与候选选项,随回答一并持久化)
153
187
  */
154
- async appendUser(content) {
188
+ async appendUser(content, roundId, opts) {
155
189
  const message = {
156
190
  role: 'user',
157
191
  content,
158
192
  timestamp: nowIso(),
193
+ ...(roundId ? { roundId } : {}),
159
194
  };
160
- // 使用 ISessionStore 持久化(如果已注入)
161
- if (this.sessionStore) {
195
+ // 会话日期锚点不随输入漂移:currentDate 由显式加载/新建决定,跨天续聊沿用原会话日期
196
+ // Round-based 路径:roundStore 注入且有 roundId 时写入
197
+ if (roundId && this.roundStore) {
162
198
  try {
163
- // 动态获取当天日期,避免跨日后写入旧日期目录
164
- this.sessionStore.appendMessage(todayDate(), this.currentSession, message);
199
+ // 交互输入:同一问答闭环内续写(不新建/不覆盖轮),防闭环节点被交互输入分裂
200
+ if (opts?.interactive) {
201
+ const existing = this.roundStore.getById(roundId) ?? this.pendingRounds.get(roundId);
202
+ if (existing) {
203
+ const input = {
204
+ id: `msg-${roundId}-input-${(existing.interactiveInputs?.length ?? 0) + 1}`,
205
+ role: 'user',
206
+ content,
207
+ timestamp: message.timestamp,
208
+ kind: opts.kind ?? 'supplement',
209
+ // 提问原文/选项随回答落盘(question-answer 携带;supplement/缺省不落,旧数据向后兼容)
210
+ ...(opts.question ? { question: opts.question } : {}),
211
+ ...(opts.options && opts.options.length > 0 ? { options: opts.options } : {}),
212
+ };
213
+ const updated = {
214
+ ...existing,
215
+ interactiveInputs: [...(existing.interactiveInputs ?? []), input],
216
+ };
217
+ this.roundStore.save(updated);
218
+ this.pendingRounds.set(roundId, updated);
219
+ logger.debug({ roundId, kind: input.kind }, 'appendUser: 交互输入归属问答闭环');
220
+ return;
221
+ }
222
+ // 轮不存在(异常兜底):降级为普通 pending Round(内容不丢失,GC 兜底)
223
+ logger.warn({ roundId }, 'appendUser: 交互输入对应轮缺失,降级为新建 pending Round');
224
+ }
225
+ const pendingRound = {
226
+ id: roundId,
227
+ userMessage: {
228
+ id: `msg-${roundId}-user`,
229
+ role: 'user',
230
+ content,
231
+ timestamp: message.timestamp,
232
+ },
233
+ status: 'pending',
234
+ createdAt: message.timestamp,
235
+ // 未完成轮不被任何会话引用(complete 时 incrementRef + appendRoundId)
236
+ refCount: 0,
237
+ };
238
+ this.roundStore.save(pendingRound);
239
+ this.pendingRounds.set(roundId, pendingRound);
240
+ logger.debug({ roundId }, 'appendUser: Round-based pending Round created');
165
241
  }
166
242
  catch (err) {
167
- logger.warn({ err, session: this.currentSessionName }, 'appendUser: 会话持久化失败');
243
+ logger.warn({ err, roundId }, 'appendUser: Round-based 写入失败');
168
244
  }
169
245
  }
170
246
  logger.debug({ role: message.role, session: this.currentSessionName }, 'appendUser');
171
247
  }
172
248
  /**
173
- * 追加 assistant 消息到当前会话
174
- * 失败不抛出
249
+ * 追加裁决证据到在途 Round(悬案取证轨;持久化失败不抛出,不阻塞对话)。
250
+ *
251
+ * 挂载模式与 interactiveInputs 逐字同构:不新建/不覆盖轮,按序追加到该轮 `evidence`。
252
+ * **必须同步 pendingRounds**——否则收场 appendAssistant/appendInterrupted 以旧缓存对象
253
+ * 覆盖落盘,证据被静默丢弃(突变点:漏 set 即丢证据)。
254
+ * 轮缺失(异常兜底):warn 后丢弃——证据缺失不伪造第二轨道补写。
175
255
  *
176
- * 日期使用 todayDate() 动态获取,确保跨日后消息写入当天目录。
256
+ * @param roundId 闭环节点轮次 ID
257
+ * @param ev 裁决证据事件(空响应 / 台账替身回显个案证据)
177
258
  */
178
- async appendAssistant(content) {
259
+ async appendEvidence(roundId, ev) {
260
+ if (!this.roundStore)
261
+ return;
262
+ try {
263
+ const existing = this.roundStore.getById(roundId) ?? this.pendingRounds.get(roundId);
264
+ if (!existing) {
265
+ logger.warn({ roundId, type: ev.type }, 'appendEvidence: 对应轮缺失,证据丢弃');
266
+ return;
267
+ }
268
+ const updated = { ...existing, evidence: [...(existing.evidence ?? []), ev] };
269
+ this.roundStore.save(updated);
270
+ this.pendingRounds.set(roundId, updated);
271
+ logger.debug({ roundId, type: ev.type }, 'appendEvidence: 裁决证据归属问答闭环');
272
+ }
273
+ catch (err) {
274
+ logger.warn({ err, roundId }, 'appendEvidence: 写入失败');
275
+ }
276
+ }
277
+ /**
278
+ * 追加 assistant 消息到当前会话(持久化失败不抛出)。
279
+ *
280
+ * Round-based 路径:完成 pending Round 时**才登记会话引用**——
281
+ * incrementRef(refCount 0→1)+ appendRoundId。pending 缓存丢失(跨重启)时从
282
+ * RoundStore 取回补全;Round 不存在(异常兜底)时创建独立 complete Round 并登记,
283
+ * 保证用户消息不丢失。
284
+ *
285
+ * 闭环节点续写:同一 roundId 已存在 assistantMessage(跨暂停-续跑:
286
+ * 暂停轮已把 ask_user 提问/中断半截落为 assistantMessage)时,旧段入 assistantLog,
287
+ * assistantMessage 恒为末段(最终回答)——问答闭环不因续跑分裂新轮,且前序 LLM
288
+ * 文本(如主动提问)不丢失。
289
+ */
290
+ async appendAssistant(content, roundId) {
179
291
  if (!content.trim())
180
292
  return;
181
293
  const message = {
182
294
  role: 'assistant',
183
295
  content,
184
296
  timestamp: nowIso(),
297
+ ...(roundId ? { roundId } : {}),
185
298
  };
186
- // 使用 ISessionStore 持久化(如果已注入)
187
- if (this.sessionStore) {
188
- try {
189
- // 动态获取当天日期,避免跨日后写入旧日期目录
190
- this.sessionStore.appendMessage(todayDate(), this.currentSession, message);
299
+ // 会话日期锚点不随输入漂移(同 appendUser 上方注释)
300
+ // Round-based 路径:roundStore 注入且有 roundId 时完成 pending Round
301
+ if (roundId && this.roundStore) {
302
+ let completed = null;
303
+ // 统一取现有轮:优先 pending 缓存(prepare 新建后未完成),否则 RoundStore(跨重启 / 暂停已完成轮)
304
+ const existing = this.pendingRounds.get(roundId) ?? this.roundStore.getById(roundId) ?? null;
305
+ if (existing) {
306
+ // 旧 assistant 段入 assistantLog(仅当已存在 assistantMessage 时产生,普通单段轮零冗余)
307
+ const assistantLog = existing.assistantLog
308
+ ? [...existing.assistantLog]
309
+ : existing.assistantMessage
310
+ ? []
311
+ : undefined;
312
+ if (existing.assistantMessage)
313
+ assistantLog.push(existing.assistantMessage);
314
+ completed = {
315
+ ...existing,
316
+ assistantMessage: {
317
+ id: `msg-${roundId}-assistant`,
318
+ role: 'assistant',
319
+ content,
320
+ timestamp: message.timestamp,
321
+ },
322
+ assistantLog: assistantLog && assistantLog.length > 0 ? assistantLog : undefined,
323
+ status: 'complete',
324
+ completedAt: message.timestamp,
325
+ };
326
+ this.pendingRounds.delete(roundId);
191
327
  }
192
- catch (err) {
193
- logger.warn({ err, session: this.currentSessionName }, 'appendAssistant: 会话持久化失败');
328
+ else {
329
+ logger.warn({ roundId }, 'appendAssistant: Round not found in RoundStore');
330
+ }
331
+ if (completed) {
332
+ this.roundStore.save(completed);
333
+ // 首次收场才登记会话引用(refCount 0→1 + 列表登记),崩溃残留 pending 保持孤儿可由 GC 清理。
334
+ // 续写同一闭环节点(assistantLog:跨暂停-续跑多次 appendAssistant 到同一 roundId)不重复登记——
335
+ // 否则 roundIds 同 id 重复堆叠、refCount 虚增,会话视图出现「一个问答闭环多次登记」
336
+ // 判据 = isRoundSettled(非自写 'complete'):已是终态(含 interrupted)就不得再登记一次
337
+ const isReappend = existing !== null && existing !== undefined && isRoundSettled(existing.status);
338
+ if (!isReappend) {
339
+ this.roundStore.incrementRef(roundId);
340
+ const sessionId = this.currentSessionName;
341
+ try {
342
+ this.sessionStore?.appendRoundId(sessionId, roundId);
343
+ }
344
+ catch (err) {
345
+ logger.warn({ err, sessionId, roundId }, 'appendAssistant: appendRoundId 失败');
346
+ }
347
+ }
348
+ else {
349
+ logger.debug({ roundId, status: existing?.status }, 'appendAssistant: 闭环节点续写段但不重复登记会话引用');
350
+ }
351
+ logger.debug({ roundId }, 'appendAssistant: Round-based Round completed');
352
+ }
353
+ else {
354
+ // Round 不存在(异常兜底):独立 complete Round,不让用户消息丢失
355
+ const fallback = {
356
+ id: roundId,
357
+ userMessage: {
358
+ id: `msg-${roundId}-user`,
359
+ role: 'user',
360
+ content: '<历史消息>',
361
+ timestamp: message.timestamp,
362
+ },
363
+ assistantMessage: {
364
+ id: `msg-${roundId}-assistant`,
365
+ role: 'assistant',
366
+ content,
367
+ timestamp: message.timestamp,
368
+ },
369
+ status: 'complete',
370
+ createdAt: message.timestamp,
371
+ completedAt: message.timestamp,
372
+ refCount: 1,
373
+ };
374
+ this.roundStore.save(fallback);
375
+ try {
376
+ this.sessionStore.appendRoundId(this.currentSessionName, roundId);
377
+ }
378
+ catch (err) {
379
+ logger.warn({ err, roundId }, 'appendAssistant: 兜底 appendRoundId 失败');
380
+ }
194
381
  }
195
382
  }
196
383
  logger.debug({ role: message.role, session: this.currentSessionName }, 'appendAssistant');
197
384
  }
198
385
  /**
199
- * 列出所有会话标识
386
+ * 中断轮收场:把「未正常完成」的轮升级为正常 stop turn 并入会话。
387
+ *
388
+ * 语义定案(step-atomic-persistence.md §一·五):崩溃残留轮(pending/error + refCount=0 + 有已
389
+ * 落盘 processEvents)= 等同于用户点「停止」的正常 turn——可删、入会话 roundIds、作后续上下文,
390
+ * **不是**半成品草稿/孤儿。宿主经 `IRoundStore.listInterruptedRecent` 打捞后再调本方法完成
391
+ * 「升级登记」,恢复为普通 turn 渲染无需特殊草稿卡。
392
+ *
393
+ * **两个调用时机**:
394
+ * 1. 崩溃/断电后重启——宿主 `chatPanel.upgradeInterruptedRounds` 打捞后调用;
395
+ * 2. **运行期非正常收场**——`seed/orchestrator.act()` 在中断(用户取消/超时)与失败
396
+ * (LLM/网络错误)两条路径上就地调用(SSOT 收口,见该处注释)。运行期即收尾可避免
397
+ * 留下 pending 孤儿轮、须等下次重启才打捞(LLM 4xx 中断的长任务轮即此类)。
398
+ * 依据 = `memory/roundStore.ts` RoundStatus 文档「运行时失败不翻状态机,一律按中断处理」。
399
+ *
400
+ * 收场约定与 appendAssistant 同一真理源(refCount 0→1 + appendRoundId + status interrupted +
401
+ * completedAt + isReappend 防重复登记,两处终态判据同为 `isRoundSettled`),Round schema /
402
+ * 存储格式不变;
403
+ * **有意不直接复用 appendAssistant**,两处差异:
404
+ * - appendAssistant 顶层跳过空内容 → 无文本中断轮无法收场;本方法允许多段「即使无
405
+ * assistantMessage 总结也按 stop 语义收场」(§一·五验收口径)。
406
+ * - 中断标记统一追加默认文案(LOOP_CONSTANTS.DEFAULT_INTERRUPTED_MARK),与运行期两条
407
+ * 中断收场路径(loop 流式中断 / orchestrator 历史写入)的默认降级同源(SSOT)。
408
+ *
409
+ * 幂等:已收场(complete / interrupted 终态)的轮再调直接返回(宿主打捞与运行期收尾可能对同一轮各触发一次)。
200
410
  *
201
- * @returns 会话标识列表(格式:YYYY-MM-DD-session),未注入 ISessionStore 则返回空
411
+ * @param roundId 待收场轮 ID(须已存在于 RoundStore 或本实例 pendingRounds;缺失仅记日志不抛错,防御性降级)
412
+ * @param opts.content 已产出的助手文本(运行期由 consumeExecutionStream 累积;宿主打捞时
413
+ * 从 processEvents 的 narrate 内容拼接派生)。缺省/空则**不写** assistantMessage,
414
+ * 仍按 stop 语义收场
415
+ * @param opts.interruptedMark 中断标记(缺省用 LOOP_CONSTANTS.DEFAULT_INTERRUPTED_MARK)
202
416
  */
417
+ async appendInterrupted(roundId, opts) {
418
+ if (!roundId || !this.roundStore)
419
+ return;
420
+ try {
421
+ // 统一取现有轮:优先 pending 缓存(同实例未重启),否则 RoundStore(崩溃重启后的常态)
422
+ const existing = this.pendingRounds.get(roundId) ?? this.roundStore.getById(roundId) ?? null;
423
+ if (!existing) {
424
+ logger.warn({ roundId }, 'appendInterrupted: Round 未找到,跳过升级');
425
+ return;
426
+ }
427
+ // 已收场(幂等重跑 / 防御):complete / interrupted 均为终态(正常完成 或 中断收场),
428
+ // 不再二次登记会话引用,防止 roundIds 重复堆叠、refCount 虚增(判据 SSOT = isRoundSettled)
429
+ if (isRoundSettled(existing.status)) {
430
+ logger.debug({ roundId, status: existing.status }, 'appendInterrupted: 轮已收场,跳过重复升级');
431
+ return;
432
+ }
433
+ // 有恢复文本才写 assistantMessage(§一·五:无 assistantMessage 总结也按 stop 语义收场)
434
+ const content = opts?.content?.trim() ?? '';
435
+ const completed = {
436
+ // 展开保留 userMessage / interactiveInputs / processEvents(宿主 step 检查点已落盘)等原字段
437
+ ...existing,
438
+ ...(content
439
+ ? {
440
+ assistantMessage: {
441
+ id: `msg-${roundId}-assistant`,
442
+ role: 'assistant',
443
+ content: content + (opts?.interruptedMark ?? LOOP_CONSTANTS.DEFAULT_INTERRUPTED_MARK),
444
+ timestamp: nowIso(),
445
+ },
446
+ }
447
+ : {}),
448
+ status: 'interrupted',
449
+ completedAt: nowIso(),
450
+ };
451
+ this.pendingRounds.delete(roundId);
452
+ this.roundStore.save(completed);
453
+ // 收场登记:与 appendAssistant 同一约定——refCount 0→1 + 会话 roundIds 追加
454
+ this.roundStore.incrementRef(roundId);
455
+ const sessionId = this.currentSessionName;
456
+ try {
457
+ this.sessionStore?.appendRoundId(sessionId, roundId);
458
+ }
459
+ catch (err) {
460
+ logger.warn({ err, sessionId, roundId }, 'appendInterrupted: appendRoundId 失败');
461
+ }
462
+ logger.info({ roundId, sessionId, hasAssistant: content.length > 0 }, 'appendInterrupted: 崩溃残留轮升级为正常 stop turn');
463
+ }
464
+ catch (err) {
465
+ logger.warn({ err, roundId }, 'appendInterrupted: 中断轮升级失败');
466
+ }
467
+ }
468
+ /** 列出所有会话标识(YYYY-MM-DD-session);未注入 ISessionStore 返回空 */
203
469
  async listAllSessions() {
204
470
  if (!this.sessionStore) {
205
471
  logger.debug({ hasSessionStore: false }, 'listAllSessions: ISessionStore 未注入,返回空数组');
@@ -207,16 +473,8 @@ export class MessageHistory {
207
473
  }
208
474
  return this.sessionStore.listSessions();
209
475
  }
210
- /**
211
- * 从会话存储恢复历史消息
212
- * 用于重启后恢复之前的对话
213
- *
214
- * @param date - 会话日期 YYYY-MM-DD
215
- * @param session - 会话标识
216
- * @returns 会话中的消息列表,未注入 ISessionStore 则返回空数组
217
- */
476
+ /** 恢复会话历史并同步当前会话到指定 date/session(保持状态一致);未注入 ISessionStore 返回空 */
218
477
  async loadSessionMessages(date, session) {
219
- // 更新当前会话为请求的会话(保持状态一致)
220
478
  this.currentDate = date;
221
479
  this.currentSession = session;
222
480
  if (!this.sessionStore) {
@@ -228,9 +486,44 @@ export class MessageHistory {
228
486
  return messages;
229
487
  }
230
488
  /**
231
- * 把外部 fire-and-forget 归档注册到 pendingArchives
232
- * 供 Agent.chat() 触发 signal 归档时使用
489
+ * 从 Round ID 列表加载会话消息(round-based 模式)
490
+ *
491
+ * 将 Round ID 列表展开为扁平的 SessionMessage[],
492
+ * 供 AgentLoop 加载上下文使用。
493
+ *
494
+ * @param roundIds - Round ID 列表
495
+ * @returns 展开后的消息列表(user + assistant 成对)
233
496
  */
497
+ loadRoundBasedMessages(roundIds) {
498
+ if (!this.roundStore || !roundIds.length)
499
+ return [];
500
+ const messages = [];
501
+ for (const roundId of roundIds) {
502
+ const round = this.roundStore.getById(roundId);
503
+ if (!round) {
504
+ logger.warn({ roundId }, 'loadRoundBasedMessages: Round 不存在,跳过');
505
+ continue;
506
+ }
507
+ // User message
508
+ messages.push({
509
+ role: round.userMessage.role,
510
+ content: round.userMessage.content,
511
+ roundId: round.id,
512
+ timestamp: round.userMessage.timestamp,
513
+ });
514
+ // Assistant message(如果存在)
515
+ if (round.assistantMessage) {
516
+ messages.push({
517
+ role: round.assistantMessage.role,
518
+ content: round.assistantMessage.content,
519
+ roundId: round.id,
520
+ timestamp: round.assistantMessage.timestamp,
521
+ });
522
+ }
523
+ }
524
+ return messages;
525
+ }
526
+ /** 注册外部 fire-and-forget 归档到 pendingArchives,供 Agent.chat() 触发 signal 归档时使用 */
234
527
  registerPendingArchive(p) {
235
528
  this.pendingArchives.add(p);
236
529
  p.finally(() => {
@@ -238,33 +531,26 @@ export class MessageHistory {
238
531
  });
239
532
  }
240
533
  /**
241
- * 等待所有挂起的归档完成(Agent.close() 时调用)
242
- * 防止 fire-and-forget 还在写 SQLite 时 db 已被 close
243
- *
244
- * 重要:会捕获**等待期间新加入**的归档(解决 init() → archiveMissingSessions() 的 race)
245
- * 实现:用 50ms 间隔轮询检查新加入的 promise,直到所有归档完成或超时
246
- *
247
- * @param timeoutMs 单次等待超时(默认 5000ms)
248
- * @returns 是否所有归档都完成(false 表示有超时)
534
+ * 等待所有挂起归档完成(Agent.close() 时调用),防止归档写入时存储已被关闭。
535
+ * 会捕获等待期间新加入的归档(解决 init() → archiveMissingSessions() 的 race);
536
+ * 50ms 轮询直到全部完成或超时。
537
+ * @returns 是否全部完成(false = 超时)
249
538
  */
250
539
  async awaitPendingArchives(timeoutMs = 5000) {
251
- // 快速路径:无挂起任务时立即返回(避免空轮询浪费 5s)
540
+ // 无挂起任务立即返回,避免空轮询耗时
252
541
  if (this.pendingArchives.size === 0)
253
542
  return true;
254
543
  const deadline = Date.now() + timeoutMs;
255
544
  while (Date.now() < deadline) {
256
545
  const current = Array.from(this.pendingArchives);
257
- if (current.length === 0) {
258
- // 所有归档已完成
259
- return true;
260
- }
261
- // 有挂起任务 → 等所有 settle
546
+ if (current.length === 0)
547
+ return true; // 所有归档已完成
548
+ // 有挂起任务 → 等所有 settle 或到超时
262
549
  const timeout = new Promise((resolve) => safeSetTimeout(resolve, Math.max(50, deadline - Date.now())));
263
550
  await Promise.race([Promise.allSettled(current), timeout]);
264
- // 如果所有都清空了 → 完成
551
+ // 等待期间可能新加入归档,未清空则下一轮继续等
265
552
  if (this.pendingArchives.size === 0)
266
553
  return true;
267
- // 还有挂起的(可能在等待期间新加入)→ 下一轮继续等
268
554
  }
269
555
  return this.pendingArchives.size === 0;
270
556
  }