@downcity/agent 1.1.430 → 1.1.437

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 (488) hide show
  1. package/README.md +13 -11
  2. package/bin/agent/Agent.d.ts +3 -3
  3. package/bin/agent/Agent.d.ts.map +1 -1
  4. package/bin/agent/Agent.js +38 -8
  5. package/bin/agent/Agent.js.map +1 -1
  6. package/bin/agent/AgentInstructions.js +2 -2
  7. package/bin/agent/AgentInstructions.js.map +1 -1
  8. package/bin/agent/AgentMemoryStorage.d.ts.map +1 -1
  9. package/bin/agent/AgentMemoryStorage.js +1 -0
  10. package/bin/agent/AgentMemoryStorage.js.map +1 -1
  11. package/bin/agent/AgentSessions.d.ts +5 -1
  12. package/bin/agent/AgentSessions.d.ts.map +1 -1
  13. package/bin/agent/AgentSessions.js +17 -9
  14. package/bin/agent/AgentSessions.js.map +1 -1
  15. package/bin/executor/Executor.d.ts +9 -27
  16. package/bin/executor/Executor.d.ts.map +1 -1
  17. package/bin/executor/Executor.js +32 -127
  18. package/bin/executor/Executor.js.map +1 -1
  19. package/bin/executor/composer/system/default/SystemPromptAssets.d.ts +0 -4
  20. package/bin/executor/composer/system/default/SystemPromptAssets.d.ts.map +1 -1
  21. package/bin/executor/composer/system/default/SystemPromptAssets.js +0 -5
  22. package/bin/executor/composer/system/default/SystemPromptAssets.js.map +1 -1
  23. package/bin/executor/core-engine/CoreEngineContextCompaction.d.ts +3 -9
  24. package/bin/executor/core-engine/CoreEngineContextCompaction.d.ts.map +1 -1
  25. package/bin/executor/core-engine/CoreEngineContextCompaction.js +4 -130
  26. package/bin/executor/core-engine/CoreEngineContextCompaction.js.map +1 -1
  27. package/bin/executor/core-engine/CoreEngineRunner.d.ts +3 -30
  28. package/bin/executor/core-engine/CoreEngineRunner.d.ts.map +1 -1
  29. package/bin/executor/core-engine/CoreEngineRunner.js +38 -194
  30. package/bin/executor/core-engine/CoreEngineRunner.js.map +1 -1
  31. package/bin/executor/core-engine/CoreEngineSignals.d.ts +6 -6
  32. package/bin/executor/core-engine/CoreEngineSignals.d.ts.map +1 -1
  33. package/bin/executor/core-engine/CoreEngineSignals.js +1 -1
  34. package/bin/executor/core-engine/CoreEngineSignals.js.map +1 -1
  35. package/bin/executor/messages/SessionAttachmentMapper.d.ts +2 -2
  36. package/bin/executor/messages/SessionAttachmentMapper.d.ts.map +1 -1
  37. package/bin/executor/messages/SessionAttachmentMapper.js.map +1 -1
  38. package/bin/executor/messages/SessionMessageLog.d.ts +3 -3
  39. package/bin/executor/messages/SessionMessageLog.d.ts.map +1 -1
  40. package/bin/executor/messages/SessionMessageLog.js.map +1 -1
  41. package/bin/executor/messages/SessionModelMessages.d.ts +0 -3
  42. package/bin/executor/messages/SessionModelMessages.d.ts.map +1 -1
  43. package/bin/executor/messages/SessionModelMessages.js +80 -97
  44. package/bin/executor/messages/SessionModelMessages.js.map +1 -1
  45. package/bin/executor/model/ModelStepRunner.d.ts +2 -6
  46. package/bin/executor/model/ModelStepRunner.d.ts.map +1 -1
  47. package/bin/executor/model/ModelStepRunner.js +0 -28
  48. package/bin/executor/model/ModelStepRunner.js.map +1 -1
  49. package/bin/executor/services/ExecutorRecoveryPolicy.d.ts +7 -64
  50. package/bin/executor/services/ExecutorRecoveryPolicy.d.ts.map +1 -1
  51. package/bin/executor/services/ExecutorRecoveryPolicy.js +29 -45
  52. package/bin/executor/services/ExecutorRecoveryPolicy.js.map +1 -1
  53. package/bin/executor/types/SessionHistoryMeta.d.ts +1 -3
  54. package/bin/executor/types/SessionHistoryMeta.d.ts.map +1 -1
  55. package/bin/executor/types/SessionHistoryMeta.js +1 -1
  56. package/bin/index.d.ts +9 -13
  57. package/bin/index.d.ts.map +1 -1
  58. package/bin/index.js +2 -4
  59. package/bin/index.js.map +1 -1
  60. package/bin/session/DefaultSessionComposer.d.ts +13 -7
  61. package/bin/session/DefaultSessionComposer.d.ts.map +1 -1
  62. package/bin/session/DefaultSessionComposer.js +26 -21
  63. package/bin/session/DefaultSessionComposer.js.map +1 -1
  64. package/bin/session/Session.d.ts +12 -19
  65. package/bin/session/Session.d.ts.map +1 -1
  66. package/bin/session/Session.js +70 -202
  67. package/bin/session/Session.js.map +1 -1
  68. package/bin/session/SessionComposition.d.ts +0 -2
  69. package/bin/session/SessionComposition.d.ts.map +1 -1
  70. package/bin/session/SessionComposition.js +30 -54
  71. package/bin/session/SessionComposition.js.map +1 -1
  72. package/bin/session/SessionLoop.d.ts +17 -16
  73. package/bin/session/SessionLoop.d.ts.map +1 -1
  74. package/bin/session/SessionLoop.js +217 -320
  75. package/bin/session/SessionLoop.js.map +1 -1
  76. package/bin/session/SessionMessages.d.ts +52 -44
  77. package/bin/session/SessionMessages.d.ts.map +1 -1
  78. package/bin/session/SessionMessages.js +285 -187
  79. package/bin/session/SessionMessages.js.map +1 -1
  80. package/bin/session/SessionQueue.d.ts +1 -1
  81. package/bin/session/SessionQueue.d.ts.map +1 -1
  82. package/bin/session/SessionQueue.js +2 -1
  83. package/bin/session/SessionQueue.js.map +1 -1
  84. package/bin/session/SessionState.d.ts +3 -7
  85. package/bin/session/SessionState.d.ts.map +1 -1
  86. package/bin/session/SessionState.js +50 -89
  87. package/bin/session/SessionState.js.map +1 -1
  88. package/bin/session/SessionSystem.d.ts +5 -1
  89. package/bin/session/SessionSystem.d.ts.map +1 -1
  90. package/bin/session/SessionSystem.js +40 -0
  91. package/bin/session/SessionSystem.js.map +1 -1
  92. package/bin/session/SessionTitle.d.ts +3 -3
  93. package/bin/session/SessionTitle.d.ts.map +1 -1
  94. package/bin/session/SessionTitle.js +2 -2
  95. package/bin/session/browse/Browse.d.ts +32 -46
  96. package/bin/session/browse/Browse.d.ts.map +1 -1
  97. package/bin/session/browse/Browse.js +104 -360
  98. package/bin/session/browse/Browse.js.map +1 -1
  99. package/bin/session/browse/SessionMessageTimeline.d.ts.map +1 -1
  100. package/bin/session/browse/SessionMessageTimeline.js +61 -37
  101. package/bin/session/browse/SessionMessageTimeline.js.map +1 -1
  102. package/bin/session/composer/policies/AdaptivePartContextPolicy.d.ts +35 -0
  103. package/bin/session/composer/policies/AdaptivePartContextPolicy.d.ts.map +1 -0
  104. package/bin/session/composer/policies/AdaptivePartContextPolicy.js +256 -0
  105. package/bin/session/composer/policies/AdaptivePartContextPolicy.js.map +1 -0
  106. package/bin/session/composer/policies/FullHistoryContextPolicy.d.ts +24 -0
  107. package/bin/session/composer/policies/FullHistoryContextPolicy.d.ts.map +1 -0
  108. package/bin/session/composer/policies/FullHistoryContextPolicy.js +31 -0
  109. package/bin/session/composer/policies/FullHistoryContextPolicy.js.map +1 -0
  110. package/bin/session/composer/policies/SessionSummaryPrompts.d.ts +16 -0
  111. package/bin/session/composer/policies/SessionSummaryPrompts.d.ts.map +1 -0
  112. package/bin/session/composer/policies/SessionSummaryPrompts.js +32 -0
  113. package/bin/session/composer/policies/SessionSummaryPrompts.js.map +1 -0
  114. package/bin/session/execution/SessionAssistantOutputAdapter.d.ts +15 -4
  115. package/bin/session/execution/SessionAssistantOutputAdapter.d.ts.map +1 -1
  116. package/bin/session/execution/SessionAssistantOutputAdapter.js +7 -3
  117. package/bin/session/execution/SessionAssistantOutputAdapter.js.map +1 -1
  118. package/bin/session/messages/{SessionActionMessageWriter.d.ts → SessionAgentActionPartWriter.d.ts} +7 -7
  119. package/bin/session/messages/SessionAgentActionPartWriter.d.ts.map +1 -0
  120. package/bin/session/messages/{SessionActionMessageWriter.js → SessionAgentActionPartWriter.js} +7 -7
  121. package/bin/session/messages/SessionAgentActionPartWriter.js.map +1 -0
  122. package/bin/session/messages/SessionAgentContent.d.ts +10 -0
  123. package/bin/session/messages/SessionAgentContent.d.ts.map +1 -0
  124. package/bin/session/messages/SessionAgentContent.js +44 -0
  125. package/bin/session/messages/SessionAgentContent.js.map +1 -0
  126. package/bin/session/messages/SessionAgentMessageState.d.ts +50 -0
  127. package/bin/session/messages/SessionAgentMessageState.d.ts.map +1 -0
  128. package/bin/session/messages/SessionAgentMessageState.js +283 -0
  129. package/bin/session/messages/SessionAgentMessageState.js.map +1 -0
  130. package/bin/session/messages/{SessionAssistantMessageWriter.d.ts → SessionAgentMessageWriter.d.ts} +22 -8
  131. package/bin/session/messages/SessionAgentMessageWriter.d.ts.map +1 -0
  132. package/bin/session/messages/{SessionAssistantMessageWriter.js → SessionAgentMessageWriter.js} +54 -42
  133. package/bin/session/messages/SessionAgentMessageWriter.js.map +1 -0
  134. package/bin/session/messages/SessionForkMessageFiles.d.ts +11 -0
  135. package/bin/session/messages/SessionForkMessageFiles.d.ts.map +1 -1
  136. package/bin/session/messages/SessionForkMessageFiles.js +8 -2
  137. package/bin/session/messages/SessionForkMessageFiles.js.map +1 -1
  138. package/bin/session/messages/SessionMessageInteractionWriter.d.ts +6 -6
  139. package/bin/session/messages/SessionMessageInteractionWriter.d.ts.map +1 -1
  140. package/bin/session/messages/SessionMessageInteractionWriter.js +4 -4
  141. package/bin/session/messages/SessionMessageInteractionWriter.js.map +1 -1
  142. package/bin/session/messages/SessionMessageText.d.ts +3 -3
  143. package/bin/session/messages/SessionMessageText.d.ts.map +1 -1
  144. package/bin/session/messages/SessionMessageText.js +0 -2
  145. package/bin/session/messages/SessionMessageText.js.map +1 -1
  146. package/bin/session/messages/SessionTurnFileDiffData.d.ts +3 -3
  147. package/bin/session/messages/SessionTurnFileDiffData.d.ts.map +1 -1
  148. package/bin/session/messages/SessionTurnFileDiffData.js.map +1 -1
  149. package/bin/session/messages/SessionUserMessage.d.ts +3 -3
  150. package/bin/session/messages/SessionUserMessage.d.ts.map +1 -1
  151. package/bin/session/messages/SessionUserMessage.js +6 -3
  152. package/bin/session/messages/SessionUserMessage.js.map +1 -1
  153. package/bin/session/preview/SessionMessagePreview.d.ts.map +1 -1
  154. package/bin/session/preview/SessionMessagePreview.js +25 -9
  155. package/bin/session/preview/SessionMessagePreview.js.map +1 -1
  156. package/bin/session/runtime/SessionTurnCompletion.d.ts +15 -0
  157. package/bin/session/runtime/SessionTurnCompletion.d.ts.map +1 -0
  158. package/bin/session/runtime/SessionTurnCompletion.js +126 -0
  159. package/bin/session/runtime/SessionTurnCompletion.js.map +1 -0
  160. package/bin/session/runtime/SessionTurnContext.d.ts.map +1 -1
  161. package/bin/session/runtime/SessionTurnContext.js +14 -19
  162. package/bin/session/runtime/SessionTurnContext.js.map +1 -1
  163. package/bin/session/runtime/SessionTurnFileDiff.d.ts +12 -0
  164. package/bin/session/runtime/SessionTurnFileDiff.d.ts.map +1 -0
  165. package/bin/session/runtime/SessionTurnFileDiff.js +71 -0
  166. package/bin/session/runtime/SessionTurnFileDiff.js.map +1 -0
  167. package/bin/session/storage/LocalSessionDataStore.d.ts +6 -41
  168. package/bin/session/storage/LocalSessionDataStore.d.ts.map +1 -1
  169. package/bin/session/storage/LocalSessionDataStore.js +19 -101
  170. package/bin/session/storage/LocalSessionDataStore.js.map +1 -1
  171. package/bin/session/storage/LocalSessionStore.d.ts +13 -5
  172. package/bin/session/storage/LocalSessionStore.d.ts.map +1 -1
  173. package/bin/session/storage/LocalSessionStore.js +153 -30
  174. package/bin/session/storage/LocalSessionStore.js.map +1 -1
  175. package/bin/session/storage/LocalStorePaths.d.ts +4 -16
  176. package/bin/session/storage/LocalStorePaths.d.ts.map +1 -1
  177. package/bin/session/storage/LocalStorePaths.js +7 -31
  178. package/bin/session/storage/LocalStorePaths.js.map +1 -1
  179. package/bin/session/storage/Metadata.d.ts +4 -4
  180. package/bin/session/storage/Metadata.d.ts.map +1 -1
  181. package/bin/session/storage/Metadata.js +3 -11
  182. package/bin/session/storage/Metadata.js.map +1 -1
  183. package/bin/session/storage/RuntimeSessionPort.d.ts +4 -4
  184. package/bin/session/storage/RuntimeSessionPort.d.ts.map +1 -1
  185. package/bin/session/storage/RuntimeSessionPort.js +3 -3
  186. package/bin/session/storage/RuntimeSessionPort.js.map +1 -1
  187. package/bin/session/storage/SessionStorageCodec.d.ts +59 -0
  188. package/bin/session/storage/SessionStorageCodec.d.ts.map +1 -0
  189. package/bin/session/storage/SessionStorageCodec.js +331 -0
  190. package/bin/session/storage/SessionStorageCodec.js.map +1 -0
  191. package/bin/session/storage/SessionStorageSchema.d.ts +11 -0
  192. package/bin/session/storage/SessionStorageSchema.d.ts.map +1 -0
  193. package/bin/session/storage/SessionStorageSchema.js +131 -0
  194. package/bin/session/storage/SessionStorageSchema.js.map +1 -0
  195. package/bin/session/storage/SqliteSessionStorage.d.ts +120 -0
  196. package/bin/session/storage/SqliteSessionStorage.d.ts.map +1 -0
  197. package/bin/session/storage/SqliteSessionStorage.js +581 -0
  198. package/bin/session/storage/SqliteSessionStorage.js.map +1 -0
  199. package/bin/tools/ask/AskQuestionsTool.d.ts.map +1 -1
  200. package/bin/tools/ask/AskQuestionsTool.js +3 -1
  201. package/bin/tools/ask/AskQuestionsTool.js.map +1 -1
  202. package/bin/types/action/ActionResult.d.ts +9 -9
  203. package/bin/types/action/ActionResult.d.ts.map +1 -1
  204. package/bin/types/action/ActionResult.js +1 -1
  205. package/bin/types/agent/AgentOptions.d.ts +10 -0
  206. package/bin/types/agent/AgentOptions.d.ts.map +1 -1
  207. package/bin/types/agent/AgentStorage.d.ts +3 -1
  208. package/bin/types/agent/AgentStorage.d.ts.map +1 -1
  209. package/bin/types/agent/SessionActor.d.ts +0 -9
  210. package/bin/types/agent/SessionActor.d.ts.map +1 -1
  211. package/bin/types/agent/SessionTypes.d.ts +5 -5
  212. package/bin/types/agent/SessionTypes.d.ts.map +1 -1
  213. package/bin/types/executor/SessionAssistantOutput.d.ts +15 -4
  214. package/bin/types/executor/SessionAssistantOutput.d.ts.map +1 -1
  215. package/bin/types/executor/SessionTurnContext.d.ts +17 -19
  216. package/bin/types/executor/SessionTurnContext.d.ts.map +1 -1
  217. package/bin/types/sdk/AgentSessionAction.d.ts +1 -1
  218. package/bin/types/sdk/AgentSessionAction.js +1 -1
  219. package/bin/types/sdk/AgentSessionPrompt.d.ts +14 -5
  220. package/bin/types/sdk/AgentSessionPrompt.d.ts.map +1 -1
  221. package/bin/types/sdk/AgentSessionPrompt.js +1 -1
  222. package/bin/types/sdk/AgentSessionPrompt.js.map +1 -1
  223. package/bin/types/session/AdaptivePartContextPolicy.d.ts +31 -0
  224. package/bin/types/session/AdaptivePartContextPolicy.d.ts.map +1 -0
  225. package/bin/types/session/AdaptivePartContextPolicy.js +7 -0
  226. package/bin/types/session/AdaptivePartContextPolicy.js.map +1 -0
  227. package/bin/types/session/{SessionAssistantMessageState.d.ts → SessionAgentMessageState.d.ts} +7 -7
  228. package/bin/types/session/SessionAgentMessageState.d.ts.map +1 -0
  229. package/bin/types/session/{SessionAssistantMessageState.js → SessionAgentMessageState.js} +1 -1
  230. package/bin/types/session/SessionAgentMessageState.js.map +1 -0
  231. package/bin/types/session/SessionCommand.d.ts +19 -7
  232. package/bin/types/session/SessionCommand.d.ts.map +1 -1
  233. package/bin/types/session/SessionComposer.d.ts +43 -43
  234. package/bin/types/session/SessionComposer.d.ts.map +1 -1
  235. package/bin/types/session/SessionComposer.js +2 -2
  236. package/bin/types/session/SessionComposition.d.ts +2 -5
  237. package/bin/types/session/SessionComposition.d.ts.map +1 -1
  238. package/bin/types/session/SessionContextPolicy.d.ts +70 -0
  239. package/bin/types/session/SessionContextPolicy.d.ts.map +1 -0
  240. package/bin/types/session/SessionContextPolicy.js +8 -0
  241. package/bin/types/session/SessionContextPolicy.js.map +1 -0
  242. package/bin/types/session/SessionExecution.d.ts +5 -32
  243. package/bin/types/session/SessionExecution.d.ts.map +1 -1
  244. package/bin/types/session/SessionLoop.d.ts +3 -5
  245. package/bin/types/session/SessionLoop.d.ts.map +1 -1
  246. package/bin/types/session/SessionMessages.d.ts +18 -28
  247. package/bin/types/session/SessionMessages.d.ts.map +1 -1
  248. package/bin/types/session/SessionOptions.d.ts +5 -5
  249. package/bin/types/session/SessionOptions.d.ts.map +1 -1
  250. package/bin/types/session/SessionPort.d.ts +8 -9
  251. package/bin/types/session/SessionPort.d.ts.map +1 -1
  252. package/bin/types/session/SessionState.d.ts +2 -5
  253. package/bin/types/session/SessionState.d.ts.map +1 -1
  254. package/bin/types/session/SessionSystem.d.ts +14 -0
  255. package/bin/types/session/SessionSystem.d.ts.map +1 -1
  256. package/bin/types/session/SessionTool.d.ts +2 -2
  257. package/bin/types/session/SessionTool.d.ts.map +1 -1
  258. package/bin/types/session/SessionTurnCompletion.d.ts +23 -0
  259. package/bin/types/session/SessionTurnCompletion.d.ts.map +1 -0
  260. package/bin/types/session/SessionTurnCompletion.js +8 -0
  261. package/bin/types/session/SessionTurnCompletion.js.map +1 -0
  262. package/bin/types/session/SessionTurnFileDiff.d.ts +42 -0
  263. package/bin/types/session/SessionTurnFileDiff.d.ts.map +1 -0
  264. package/bin/types/session/SessionTurnFileDiff.js +8 -0
  265. package/bin/types/session/SessionTurnFileDiff.js.map +1 -0
  266. package/bin/types/store/LocalStore.d.ts +6 -13
  267. package/bin/types/store/LocalStore.d.ts.map +1 -1
  268. package/bin/types/store/LocalStore.js +1 -1
  269. package/bin/types/store/SessionStorage.d.ts +103 -0
  270. package/bin/types/store/SessionStorage.d.ts.map +1 -0
  271. package/bin/types/store/SessionStorage.js +8 -0
  272. package/bin/types/store/SessionStorage.js.map +1 -0
  273. package/bin/types/store/SessionStore.d.ts +5 -3
  274. package/bin/types/store/SessionStore.d.ts.map +1 -1
  275. package/package.json +2 -2
  276. package/scripts/core-engine-context-compaction.test.mjs +96 -219
  277. package/scripts/core-engine-model-stream.test.mjs +2 -4
  278. package/scripts/executor-failure-result.test.mjs +14 -17
  279. package/scripts/session-agent-message-part-order.test.mjs +63 -0
  280. package/scripts/session-initialization.test.mjs +141 -0
  281. package/scripts/session-message-timeline.test.mjs +5 -6
  282. package/scripts/session-messages-error-part.test.mjs +175 -0
  283. package/scripts/session-messages-error.test.mjs +47 -6
  284. package/scripts/session-prompt-idempotency.test.mjs +91 -0
  285. package/scripts/session-queue.test.mjs +13 -12
  286. package/scripts/session-storage-sqlite.test.mjs +209 -0
  287. package/scripts/session-turn-context.test.mjs +21 -33
  288. package/src/agent/Agent.ts +48 -12
  289. package/src/agent/AgentInstructions.ts +2 -2
  290. package/src/agent/AgentMemoryStorage.ts +1 -0
  291. package/src/agent/AgentSessions.ts +31 -12
  292. package/src/executor/Executor.ts +47 -184
  293. package/src/executor/README.md +12 -13
  294. package/src/executor/composer/system/default/SystemPromptAssets.ts +0 -6
  295. package/src/executor/core-engine/CoreEngineContextCompaction.ts +3 -135
  296. package/src/executor/core-engine/CoreEngineRunner.ts +51 -273
  297. package/src/executor/core-engine/CoreEngineSignals.ts +9 -9
  298. package/src/executor/messages/SessionAttachmentMapper.ts +4 -4
  299. package/src/executor/messages/SessionMessageLog.ts +3 -3
  300. package/src/executor/messages/SessionModelMessages.ts +85 -103
  301. package/src/executor/model/ModelStepRunner.ts +9 -41
  302. package/src/executor/services/ExecutorRecoveryPolicy.ts +34 -127
  303. package/src/executor/types/SessionHistoryMeta.ts +1 -3
  304. package/src/index.ts +39 -47
  305. package/src/session/DefaultSessionComposer.ts +33 -30
  306. package/src/session/Session.ts +96 -227
  307. package/src/session/SessionComposition.ts +28 -65
  308. package/src/session/SessionLoop.ts +267 -370
  309. package/src/session/SessionMessages.ts +363 -242
  310. package/src/session/SessionQueue.ts +3 -2
  311. package/src/session/SessionState.ts +55 -101
  312. package/src/session/SessionSystem.ts +51 -1
  313. package/src/session/SessionTitle.ts +4 -4
  314. package/src/session/browse/Browse.ts +182 -468
  315. package/src/session/browse/SessionMessageTimeline.ts +63 -38
  316. package/src/session/composer/policies/AdaptivePartContextPolicy.ts +307 -0
  317. package/src/session/composer/policies/FullHistoryContextPolicy.ts +36 -0
  318. package/src/session/composer/policies/SessionSummaryPrompts.ts +42 -0
  319. package/src/session/execution/SessionAssistantOutputAdapter.ts +25 -11
  320. package/src/session/messages/{SessionActionMessageWriter.ts → SessionAgentActionPartWriter.ts} +8 -8
  321. package/src/session/messages/SessionAgentContent.ts +56 -0
  322. package/src/session/messages/SessionAgentMessageState.ts +378 -0
  323. package/src/session/messages/{SessionAssistantMessageWriter.ts → SessionAgentMessageWriter.ts} +89 -60
  324. package/src/session/messages/SessionForkMessageFiles.ts +25 -1
  325. package/src/session/messages/SessionMessageInteractionWriter.ts +19 -19
  326. package/src/session/messages/SessionMessageText.ts +3 -4
  327. package/src/session/messages/SessionTurnFileDiffData.ts +3 -3
  328. package/src/session/messages/SessionUserMessage.ts +10 -7
  329. package/src/session/preview/SessionMessagePreview.ts +26 -9
  330. package/src/session/runtime/SessionTurnCompletion.ts +159 -0
  331. package/src/session/runtime/SessionTurnContext.ts +20 -21
  332. package/src/session/runtime/SessionTurnFileDiff.ts +105 -0
  333. package/src/session/storage/LocalSessionDataStore.ts +27 -176
  334. package/src/session/storage/LocalSessionStore.ts +170 -38
  335. package/src/session/storage/LocalStorePaths.ts +14 -86
  336. package/src/session/storage/Metadata.ts +4 -13
  337. package/src/session/storage/RuntimeSessionPort.ts +7 -7
  338. package/src/session/storage/SessionStorageCodec.ts +465 -0
  339. package/src/session/storage/SessionStorageSchema.ts +132 -0
  340. package/src/session/storage/SqliteSessionStorage.ts +776 -0
  341. package/src/tools/ask/AskQuestionsTool.ts +3 -1
  342. package/src/types/action/ActionResult.ts +10 -10
  343. package/src/types/agent/AgentOptions.ts +11 -0
  344. package/src/types/agent/AgentStorage.ts +3 -1
  345. package/src/types/agent/SessionActor.ts +0 -10
  346. package/src/types/agent/SessionTypes.ts +5 -5
  347. package/src/types/executor/SessionAssistantOutput.ts +15 -4
  348. package/src/types/executor/SessionTurnContext.ts +25 -22
  349. package/src/types/sdk/AgentSessionAction.ts +1 -1
  350. package/src/types/sdk/AgentSessionPrompt.ts +15 -5
  351. package/src/types/session/AdaptivePartContextPolicy.ts +37 -0
  352. package/src/types/session/{SessionAssistantMessageState.ts → SessionAgentMessageState.ts} +6 -6
  353. package/src/types/session/SessionCommand.ts +21 -7
  354. package/src/types/session/SessionComposer.ts +48 -48
  355. package/src/types/session/SessionComposition.ts +2 -5
  356. package/src/types/session/SessionContextPolicy.ts +77 -0
  357. package/src/types/session/SessionExecution.ts +11 -36
  358. package/src/types/session/SessionLoop.ts +3 -8
  359. package/src/types/session/SessionMessages.ts +19 -29
  360. package/src/types/session/SessionOptions.ts +5 -5
  361. package/src/types/session/SessionPort.ts +10 -10
  362. package/src/types/session/SessionState.ts +2 -5
  363. package/src/types/session/SessionSystem.ts +19 -0
  364. package/src/types/session/SessionTool.ts +2 -2
  365. package/src/types/session/SessionTurnCompletion.ts +24 -0
  366. package/src/types/session/SessionTurnFileDiff.ts +44 -0
  367. package/src/types/store/LocalStore.ts +6 -14
  368. package/src/types/store/SessionStorage.ts +121 -0
  369. package/src/types/store/SessionStore.ts +6 -3
  370. package/tsconfig.tsbuildinfo +1 -1
  371. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionPrompts.d.ts +0 -45
  372. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionPrompts.d.ts.map +0 -1
  373. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionPrompts.js +0 -144
  374. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionPrompts.js.map +0 -1
  375. package/bin/executor/composer/system/SessionSystemComposer.d.ts +0 -23
  376. package/bin/executor/composer/system/SessionSystemComposer.d.ts.map +0 -1
  377. package/bin/executor/composer/system/SessionSystemComposer.js +0 -9
  378. package/bin/executor/composer/system/SessionSystemComposer.js.map +0 -1
  379. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.d.ts +0 -43
  380. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.d.ts.map +0 -1
  381. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.js +0 -42
  382. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.js.map +0 -1
  383. package/bin/executor/composer/system/default/PromptRenderer.d.ts +0 -35
  384. package/bin/executor/composer/system/default/PromptRenderer.d.ts.map +0 -1
  385. package/bin/executor/composer/system/default/PromptRenderer.js +0 -23
  386. package/bin/executor/composer/system/default/PromptRenderer.js.map +0 -1
  387. package/bin/executor/composer/system/default/SystemDomain.d.ts +0 -151
  388. package/bin/executor/composer/system/default/SystemDomain.d.ts.map +0 -1
  389. package/bin/executor/composer/system/default/SystemDomain.js +0 -162
  390. package/bin/executor/composer/system/default/SystemDomain.js.map +0 -1
  391. package/bin/executor/composer/system/default/assets/task.prompt.d.ts +0 -7
  392. package/bin/executor/composer/system/default/assets/task.prompt.d.ts.map +0 -1
  393. package/bin/executor/composer/system/default/assets/task.prompt.js +0 -8
  394. package/bin/executor/composer/system/default/assets/task.prompt.js.map +0 -1
  395. package/bin/executor/composer/system/default/variables/GeoContext.d.ts +0 -14
  396. package/bin/executor/composer/system/default/variables/GeoContext.d.ts.map +0 -1
  397. package/bin/executor/composer/system/default/variables/GeoContext.js +0 -150
  398. package/bin/executor/composer/system/default/variables/GeoContext.js.map +0 -1
  399. package/bin/executor/composer/system/default/variables/PromptTypes.d.ts +0 -36
  400. package/bin/executor/composer/system/default/variables/PromptTypes.d.ts.map +0 -1
  401. package/bin/executor/composer/system/default/variables/PromptTypes.js +0 -9
  402. package/bin/executor/composer/system/default/variables/PromptTypes.js.map +0 -1
  403. package/bin/executor/composer/system/default/variables/VariableReplacer.d.ts +0 -61
  404. package/bin/executor/composer/system/default/variables/VariableReplacer.d.ts.map +0 -1
  405. package/bin/executor/composer/system/default/variables/VariableReplacer.js +0 -93
  406. package/bin/executor/composer/system/default/variables/VariableReplacer.js.map +0 -1
  407. package/bin/executor/core-engine/CoreEngineMessageState.d.ts +0 -63
  408. package/bin/executor/core-engine/CoreEngineMessageState.d.ts.map +0 -1
  409. package/bin/executor/core-engine/CoreEngineMessageState.js +0 -81
  410. package/bin/executor/core-engine/CoreEngineMessageState.js.map +0 -1
  411. package/bin/session/SessionCommand.d.ts +0 -24
  412. package/bin/session/SessionCommand.d.ts.map +0 -1
  413. package/bin/session/SessionCommand.js +0 -35
  414. package/bin/session/SessionCommand.js.map +0 -1
  415. package/bin/session/messages/SessionActionMessageWriter.d.ts.map +0 -1
  416. package/bin/session/messages/SessionActionMessageWriter.js.map +0 -1
  417. package/bin/session/messages/SessionAssistantMessageState.d.ts +0 -49
  418. package/bin/session/messages/SessionAssistantMessageState.d.ts.map +0 -1
  419. package/bin/session/messages/SessionAssistantMessageState.js +0 -296
  420. package/bin/session/messages/SessionAssistantMessageState.js.map +0 -1
  421. package/bin/session/messages/SessionAssistantMessageWriter.d.ts.map +0 -1
  422. package/bin/session/messages/SessionAssistantMessageWriter.js.map +0 -1
  423. package/bin/session/messages/SessionMessageCompaction.d.ts +0 -29
  424. package/bin/session/messages/SessionMessageCompaction.d.ts.map +0 -1
  425. package/bin/session/messages/SessionMessageCompaction.js +0 -128
  426. package/bin/session/messages/SessionMessageCompaction.js.map +0 -1
  427. package/bin/session/runtime/SessionCompactOperation.d.ts +0 -29
  428. package/bin/session/runtime/SessionCompactOperation.d.ts.map +0 -1
  429. package/bin/session/runtime/SessionCompactOperation.js +0 -66
  430. package/bin/session/runtime/SessionCompactOperation.js.map +0 -1
  431. package/bin/session/runtime/SessionHistoryCompaction.d.ts +0 -22
  432. package/bin/session/runtime/SessionHistoryCompaction.d.ts.map +0 -1
  433. package/bin/session/runtime/SessionHistoryCompaction.js +0 -31
  434. package/bin/session/runtime/SessionHistoryCompaction.js.map +0 -1
  435. package/bin/session/storage/JsonlSessionMessageStore.d.ts +0 -77
  436. package/bin/session/storage/JsonlSessionMessageStore.d.ts.map +0 -1
  437. package/bin/session/storage/JsonlSessionMessageStore.js +0 -419
  438. package/bin/session/storage/JsonlSessionMessageStore.js.map +0 -1
  439. package/bin/session/storage/SessionMessageStoreFactory.d.ts +0 -12
  440. package/bin/session/storage/SessionMessageStoreFactory.d.ts.map +0 -1
  441. package/bin/session/storage/SessionMessageStoreFactory.js +0 -13
  442. package/bin/session/storage/SessionMessageStoreFactory.js.map +0 -1
  443. package/bin/types/common/Template.d.ts +0 -9
  444. package/bin/types/common/Template.d.ts.map +0 -1
  445. package/bin/types/common/Template.js +0 -9
  446. package/bin/types/common/Template.js.map +0 -1
  447. package/bin/types/sdk/AgentSessionCompact.d.ts +0 -30
  448. package/bin/types/sdk/AgentSessionCompact.d.ts.map +0 -1
  449. package/bin/types/sdk/AgentSessionCompact.js +0 -8
  450. package/bin/types/sdk/AgentSessionCompact.js.map +0 -1
  451. package/bin/types/session/SessionAssistantMessageState.d.ts.map +0 -1
  452. package/bin/types/session/SessionAssistantMessageState.js.map +0 -1
  453. package/bin/types/session/SessionSegment.d.ts +0 -57
  454. package/bin/types/session/SessionSegment.d.ts.map +0 -1
  455. package/bin/types/session/SessionSegment.js +0 -8
  456. package/bin/types/session/SessionSegment.js.map +0 -1
  457. package/bin/types/store/SessionDataStore.d.ts +0 -88
  458. package/bin/types/store/SessionDataStore.d.ts.map +0 -1
  459. package/bin/types/store/SessionDataStore.js +0 -9
  460. package/bin/types/store/SessionDataStore.js.map +0 -1
  461. package/bin/utils/Template.d.ts +0 -17
  462. package/bin/utils/Template.d.ts.map +0 -1
  463. package/bin/utils/Template.js +0 -24
  464. package/bin/utils/Template.js.map +0 -1
  465. package/scripts/session-compaction-prompts.test.mjs +0 -49
  466. package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionPrompts.ts +0 -162
  467. package/src/executor/composer/system/SessionSystemComposer.ts +0 -25
  468. package/src/executor/composer/system/default/DefaultSessionSystemComposer.ts +0 -76
  469. package/src/executor/composer/system/default/PromptRenderer.ts +0 -52
  470. package/src/executor/composer/system/default/SystemDomain.ts +0 -301
  471. package/src/executor/composer/system/default/assets/task.prompt.ts +0 -9
  472. package/src/executor/composer/system/default/assets/task.prompt.ts.txt +0 -33
  473. package/src/executor/composer/system/default/variables/GeoContext.ts +0 -180
  474. package/src/executor/composer/system/default/variables/PromptTypes.ts +0 -37
  475. package/src/executor/composer/system/default/variables/VariableReplacer.ts +0 -154
  476. package/src/executor/core-engine/CoreEngineMessageState.ts +0 -117
  477. package/src/session/SessionCommand.ts +0 -42
  478. package/src/session/messages/SessionAssistantMessageState.ts +0 -392
  479. package/src/session/messages/SessionMessageCompaction.ts +0 -160
  480. package/src/session/runtime/SessionCompactOperation.ts +0 -93
  481. package/src/session/runtime/SessionHistoryCompaction.ts +0 -45
  482. package/src/session/storage/JsonlSessionMessageStore.ts +0 -513
  483. package/src/session/storage/SessionMessageStoreFactory.ts +0 -18
  484. package/src/types/common/Template.ts +0 -9
  485. package/src/types/sdk/AgentSessionCompact.ts +0 -32
  486. package/src/types/session/SessionSegment.ts +0 -62
  487. package/src/types/store/SessionDataStore.ts +0 -113
  488. package/src/utils/Template.ts +0 -28
@@ -6,7 +6,7 @@ import assert from "node:assert/strict";
6
6
  import test from "node:test";
7
7
  import { to_session_message_timeline_events } from "../bin/index.js";
8
8
 
9
- test("Session timeline preserves assistant text and tool order", () => {
9
+ test("Session timeline preserves Agent text and tool order", () => {
10
10
  const message = {
11
11
  message_id: "assistant-1",
12
12
  session_id: "session-1",
@@ -16,9 +16,8 @@ test("Session timeline preserves assistant text and tool order", () => {
16
16
  visibility: "visible",
17
17
  created_at: 10,
18
18
  updated_at: 20,
19
- type: "assistant",
20
- kind: "normal",
21
- status: "completed",
19
+ role: "agent",
20
+ state: "done",
22
21
  parts: [
23
22
  {
24
23
  part_id: "text-1",
@@ -49,10 +48,10 @@ test("Session timeline preserves assistant text and tool order", () => {
49
48
 
50
49
  const events = to_session_message_timeline_events(message);
51
50
  assert.deepEqual(events.map((event) => event.role), [
52
- "assistant",
51
+ "agent",
53
52
  "tool-call",
54
53
  "tool-result",
55
- "assistant",
54
+ "agent",
56
55
  ]);
57
56
  assert.deepEqual(events.map((event) => event.id), [
58
57
  "assistant-1:0",
@@ -0,0 +1,175 @@
1
+ /**
2
+ * @file 验证 SessionMessages 将 Error 归入当前 Turn 的 Agent Message,而非无条件新建消息。
3
+ */
4
+
5
+ import assert from "node:assert/strict";
6
+ import test from "node:test";
7
+ import { SessionMessages } from "../bin/session/SessionMessages.js";
8
+
9
+ /** 创建支持聚合创建和 expected revision 更新的最小内存 SessionStorage。 */
10
+ function create_fixture(initial_messages = []) {
11
+ let stored_messages = structuredClone(initial_messages);
12
+ let update_count = 0;
13
+ const publications = [];
14
+ const store = {
15
+ initialize: async () => {},
16
+ list_messages: async () => structuredClone(stored_messages),
17
+ list_recoverable_agent_messages: async () => structuredClone(
18
+ stored_messages.filter((message) =>
19
+ message.role === "agent" && message.state === "streaming"
20
+ ),
21
+ ),
22
+ read_message: async (message_id) => structuredClone(
23
+ stored_messages.find((message) => message.message_id === message_id) ?? null,
24
+ ),
25
+ read_latest_agent_message: async (turn_id) => structuredClone(
26
+ stored_messages
27
+ .filter((message) =>
28
+ message.role === "agent" && (!turn_id || message.turn_id === turn_id)
29
+ )
30
+ .sort((left, right) => right.sequence - left.sequence)[0] ?? null,
31
+ ),
32
+ message_stats: async () => ({ message_count: stored_messages.length, storage_bytes: 0, latest_message: structuredClone(stored_messages.at(-1) ?? null) }),
33
+ create_message: async (build_message) => {
34
+ const message = build_message({
35
+ message_sequence: next_message_sequence(stored_messages),
36
+ });
37
+ stored_messages.push(structuredClone(message));
38
+ return structuredClone(message);
39
+ },
40
+ update_message: async ({ message, expected_revision }) => {
41
+ update_count += 1;
42
+ const index = stored_messages.findIndex(
43
+ (candidate) => candidate.message_id === message.message_id,
44
+ );
45
+ const current = stored_messages[index];
46
+ if (!current || current.revision !== expected_revision) throw new Error("revision conflict");
47
+ stored_messages[index] = structuredClone(message);
48
+ },
49
+ };
50
+ const messages = new SessionMessages({
51
+ session_id: "session-1",
52
+ store,
53
+ publish: (mutation) => publications.push(mutation),
54
+ });
55
+ return {
56
+ messages,
57
+ publications,
58
+ read_active: () => structuredClone(stored_messages.filter((message) => message.role !== "agent" || message.state !== "streaming")),
59
+ read_draft: () => structuredClone(stored_messages.find((message) => message.role === "agent" && message.state === "streaming") ?? null),
60
+ get_update_count: () => update_count,
61
+ };
62
+ }
63
+
64
+ test("Model delta 只更新运行投影,Step 完成时才持久化一次", async () => {
65
+ const fixture = create_fixture();
66
+ await fixture.messages.initialize();
67
+ const writer = await fixture.messages.open_agent_message({ turn_id: "turn-1" });
68
+ await writer.begin_step();
69
+ await writer.apply_model_event({ type: "text_start", content_id: "text-1" });
70
+ await writer.apply_model_event({ type: "text_delta", content_id: "text-1", delta: "你" });
71
+ await writer.apply_model_event({ type: "text_delta", content_id: "text-1", delta: "好" });
72
+ await writer.apply_model_event({ type: "text_finish", content_id: "text-1" });
73
+
74
+ assert.equal(fixture.get_update_count(), 0);
75
+ assert.equal(fixture.read_draft().parts.length, 0);
76
+ assert.equal(fixture.messages.get_message(writer.message_id).parts[0].text, "你好");
77
+
78
+ await writer.finish_step([{
79
+ part_id: "collector-text-1",
80
+ sequence: 1,
81
+ type: "text",
82
+ text: "你好",
83
+ state: "done",
84
+ }]);
85
+
86
+ assert.equal(fixture.get_update_count(), 1);
87
+ assert.equal(fixture.read_draft().parts[0].text, "你好");
88
+ });
89
+
90
+ /** 返回下一条顶层 Message sequence。 */
91
+ function next_message_sequence(messages) {
92
+ return messages
93
+ .reduce((maximum, message) => Math.max(maximum, message.sequence), 0) + 1;
94
+ }
95
+
96
+ /** 创建一条已完成的 canonical Agent Message。 */
97
+ function create_completed_agent_message() {
98
+ return {
99
+ message_id: "agent-1",
100
+ session_id: "session-1",
101
+ turn_id: "turn-1",
102
+ sequence: 1,
103
+ revision: 1,
104
+ visibility: "visible",
105
+ created_at: 1,
106
+ updated_at: 1,
107
+ role: "agent",
108
+ state: "done",
109
+ parts: [{ part_id: "text-1", sequence: 1, type: "text", text: "处理中", state: "done" }],
110
+ };
111
+ }
112
+
113
+ /** 创建标准 Turn Error 输入。 */
114
+ function create_error_input() {
115
+ return {
116
+ scope: "turn",
117
+ turn_id: "turn-1",
118
+ code: "turn_execution_failed",
119
+ message: "执行失败",
120
+ recoverable: true,
121
+ };
122
+ }
123
+
124
+ test("已有流式 Agent Message 时 Error 追加到同一草稿", async () => {
125
+ const fixture = create_fixture();
126
+ await fixture.messages.initialize();
127
+ const writer = await fixture.messages.open_agent_message({ turn_id: "turn-1" });
128
+ await writer.append_result_parts([{ type: "text", text: "处理中" }]);
129
+ const message_id = writer.message_id;
130
+
131
+ const result = await fixture.messages.append_error_part(create_error_input());
132
+
133
+ assert.equal(result.message_id, message_id);
134
+ assert.equal(fixture.read_active().length, 0);
135
+ assert.deepEqual(fixture.read_draft().parts.map((part) => part.type), ["text", "error"]);
136
+ assert.deepEqual(fixture.read_draft().parts.map((part) => part.sequence), [1, 2]);
137
+ });
138
+
139
+ test("已有已完成 Agent Message 时 Error 作为同 Message 的新 revision 追加", async () => {
140
+ const original = create_completed_agent_message();
141
+ const fixture = create_fixture([original]);
142
+ await fixture.messages.initialize();
143
+
144
+ const result = await fixture.messages.append_error_part(create_error_input());
145
+
146
+ assert.equal(result.message_id, original.message_id);
147
+ assert.equal(fixture.read_active().length, 1);
148
+ assert.deepEqual(result.parts.map((part) => part.type), ["text", "error"]);
149
+ assert.deepEqual(result.parts.map((part) => part.sequence), [1, 2]);
150
+ assert.equal(result.revision, 2);
151
+ assert.equal(result.state, "done");
152
+ });
153
+
154
+ test("同 Turn 同错误码重复追加保持幂等", async () => {
155
+ const fixture = create_fixture([create_completed_agent_message()]);
156
+ await fixture.messages.initialize();
157
+ const first = await fixture.messages.append_error_part(create_error_input());
158
+ const second = await fixture.messages.append_error_part(create_error_input());
159
+
160
+ assert.equal(second.message_id, first.message_id);
161
+ assert.equal(second.revision, first.revision);
162
+ assert.equal(second.parts.filter((part) => part.type === "error").length, 1);
163
+ });
164
+
165
+ test("Turn 尚无 Agent Message 时才创建仅含 Error 的 Agent Message", async () => {
166
+ const fixture = create_fixture();
167
+ await fixture.messages.initialize();
168
+
169
+ const result = await fixture.messages.append_error_part(create_error_input());
170
+
171
+ assert.equal(result.role, "agent");
172
+ assert.equal(result.state, "done");
173
+ assert.deepEqual(result.parts.map((part) => part.type), ["error"]);
174
+ assert.equal(fixture.read_active().length, 1);
175
+ });
@@ -12,6 +12,7 @@ function create_messages(store) {
12
12
  store: {
13
13
  initialize: async () => {},
14
14
  list_messages: async () => [],
15
+ list_recoverable_agent_messages: async () => [],
15
16
  ...store,
16
17
  },
17
18
  publish: () => {},
@@ -20,7 +21,7 @@ function create_messages(store) {
20
21
 
21
22
  test("append_user_message 透传 Store 写入失败", async () => {
22
23
  const messages = create_messages({
23
- append_message: async () => {
24
+ create_message: async () => {
24
25
  throw new Error("disk full");
25
26
  },
26
27
  });
@@ -28,29 +29,69 @@ test("append_user_message 透传 Store 写入失败", async () => {
28
29
  await assert.rejects(
29
30
  messages.append_user_message({
30
31
  turn_id: "turn-1",
31
- input_type: "prompt",
32
32
  parts: [{
33
33
  part_id: "text-1",
34
34
  type: "text",
35
35
  text: "hello",
36
- state: "done",
37
36
  }],
38
37
  }),
39
38
  /disk full/,
40
39
  );
41
40
  });
42
41
 
43
- test("open_assistant_message 透传草稿写入失败", async () => {
42
+ test("open_agent_message 透传草稿写入失败", async () => {
44
43
  const messages = create_messages({
45
- create_assistant_message: async () => {
44
+ create_message: async () => {
46
45
  throw new Error("disk full");
47
46
  },
48
47
  });
49
48
  await messages.initialize();
50
49
  await assert.rejects(
51
- messages.open_assistant_message({
50
+ messages.open_agent_message({
52
51
  turn_id: "turn-1",
53
52
  }),
54
53
  /disk full/,
55
54
  );
56
55
  });
56
+
57
+ test("SessionMessages 并发初始化只执行一次 Store 恢复", async () => {
58
+ let initialize_count = 0;
59
+ let list_count = 0;
60
+ let release_initialize;
61
+ const initialize_gate = new Promise((resolve) => {
62
+ release_initialize = resolve;
63
+ });
64
+ const messages = create_messages({
65
+ initialize: async () => {
66
+ initialize_count += 1;
67
+ await initialize_gate;
68
+ },
69
+ list_recoverable_agent_messages: async () => {
70
+ list_count += 1;
71
+ return [];
72
+ },
73
+ });
74
+
75
+ const first = messages.initialize();
76
+ const second = messages.initialize();
77
+ await Promise.resolve();
78
+ assert.equal(initialize_count, 1);
79
+
80
+ release_initialize();
81
+ await Promise.all([first, second]);
82
+ assert.equal(list_count, 1);
83
+ });
84
+
85
+ test("SessionMessages 初始化失败后允许重试", async () => {
86
+ let initialize_count = 0;
87
+ const messages = create_messages({
88
+ initialize: async () => {
89
+ initialize_count += 1;
90
+ if (initialize_count === 1) throw new Error("restore failed");
91
+ },
92
+ });
93
+
94
+ await assert.rejects(messages.initialize(), /restore failed/);
95
+ await messages.initialize();
96
+ assert.equal(initialize_count, 2);
97
+ });
@@ -0,0 +1,91 @@
1
+ /**
2
+ * @file 验证 Session Prompt 可以从 canonical Message 恢复同一业务请求的完成结果。
3
+ */
4
+
5
+ import { createHash } from "node:crypto";
6
+ import assert from "node:assert/strict";
7
+ import test from "node:test";
8
+ import { SessionLoop } from "../bin/session/SessionLoop.js";
9
+ import { SessionQueue } from "../bin/session/SessionQueue.js";
10
+
11
+ /** 创建只覆盖已完成幂等请求读取路径的最小 SessionLoop。 */
12
+ function create_loop(request_id) {
13
+ const session_id = "idempotent-session";
14
+ const digest = createHash("sha256")
15
+ .update(session_id)
16
+ .update("\u0000")
17
+ .update(request_id)
18
+ .digest("hex");
19
+ const turn_id = `turn-request:${digest}`;
20
+ const user_message = {
21
+ message_id: `user-request:${digest}`,
22
+ session_id,
23
+ turn_id,
24
+ sequence: 1,
25
+ revision: 1,
26
+ visibility: "visible",
27
+ created_at: 1,
28
+ updated_at: 1,
29
+ role: "user",
30
+ parts: [{ part_id: "user-part", sequence: 1, type: "text", text: "hello" }],
31
+ };
32
+ const agent_message = {
33
+ message_id: "agent-result",
34
+ session_id,
35
+ turn_id,
36
+ sequence: 2,
37
+ revision: 1,
38
+ visibility: "visible",
39
+ created_at: 2,
40
+ updated_at: 2,
41
+ role: "agent",
42
+ state: "done",
43
+ parts: [{ part_id: "agent-part", sequence: 1, type: "text", text: "world", state: "done" }],
44
+ };
45
+ let execute_count = 0;
46
+ const loop = new SessionLoop({
47
+ session_id,
48
+ session_origin: { type: "chat" },
49
+ workspace_path: "/tmp/downcity-idempotent-prompt",
50
+ executor: {
51
+ execute: async () => {
52
+ execute_count += 1;
53
+ return { text: "unexpected", success: true };
54
+ },
55
+ },
56
+ maintain_context: async () => {},
57
+ state: { ensure_runnable: async () => {} },
58
+ messages: {
59
+ get_message: (message_id) => message_id === user_message.message_id
60
+ ? user_message
61
+ : undefined,
62
+ read_latest_agent_message: async (requested_turn_id) => requested_turn_id === turn_id
63
+ ? agent_message
64
+ : null,
65
+ },
66
+ events: { publish: () => {} },
67
+ logger: { log: async () => {} },
68
+ queue: new SessionQueue(),
69
+ interactions: { cancel_all: async () => {} },
70
+ shell_approval_gateway: {},
71
+ });
72
+ return { loop, turn_id, get_execute_count: () => execute_count };
73
+ }
74
+
75
+ test("相同 request_id 直接恢复原 Turn 结果且不重复执行", async () => {
76
+ const request_id = "inbound_123";
77
+ const { loop, turn_id, get_execute_count } = create_loop(request_id);
78
+
79
+ const first = await loop.prompt({ query: "hello", request_id });
80
+ const second = await loop.prompt({ query: "hello", request_id });
81
+
82
+ assert.equal(first.id, turn_id);
83
+ assert.equal(second.id, turn_id);
84
+ assert.deepEqual(await first.finished, {
85
+ turn_id,
86
+ text: "world",
87
+ success: true,
88
+ });
89
+ assert.deepEqual(await second.finished, await first.finished);
90
+ assert.equal(get_execute_count(), 0);
91
+ });
@@ -1,19 +1,19 @@
1
1
  /**
2
- * @file 验证 SessionQueue 只保存具体 Command 对象并维护确定的 FIFO 顺序。
2
+ * @file 验证 SessionQueue 只保存最小 Command 数据并维护确定的 FIFO 顺序。
3
3
  */
4
4
 
5
5
  import assert from "node:assert/strict";
6
6
  import test from "node:test";
7
7
  import { SessionQueue } from "../bin/session/SessionQueue.js";
8
- import { SessionCommand } from "../bin/session/SessionCommand.js";
9
8
 
10
9
  function create_command(name, executed, cancel) {
11
- return new SessionCommand({
10
+ return {
11
+ kind: cancel ? "prompt" : "maintenance",
12
12
  execute: async () => {
13
13
  executed.push(name);
14
14
  },
15
15
  ...(cancel ? { cancel } : {}),
16
- });
16
+ };
17
17
  }
18
18
 
19
19
  test("SessionQueue 按 FIFO 返回具体 Command 对象", async () => {
@@ -79,21 +79,22 @@ test("SessionQueue 可以把未处理 Command 恢复到队列头部", async () =
79
79
  assert.deepEqual(executed, ["head", "middle", "tail"]);
80
80
  });
81
81
 
82
- test("SessionCommand 成功执行后返回可选的持久化完成信息", async () => {
82
+ test("SessionQueue 保留 Command 的类别与完成信息", async () => {
83
+ const queue = new SessionQueue();
83
84
  const completion = {
84
85
  type: "action",
85
86
  id: "config-completed",
86
87
  title: "Configuration updated",
87
88
  description: "The next step uses the new configuration.",
88
89
  };
89
- const command = new SessionCommand({
90
+ const command = {
91
+ kind: "maintenance",
90
92
  execute: async () => {},
91
93
  completion,
92
- });
93
- const silent_command = new SessionCommand({
94
- execute: async () => {},
95
- });
94
+ };
95
+ queue.enqueue_command(command);
96
96
 
97
- assert.deepEqual(await command.execute(), completion);
98
- assert.equal(await silent_command.execute(), undefined);
97
+ assert.equal(queue.take_next(), command);
98
+ assert.equal(command.kind, "maintenance");
99
+ assert.deepEqual(command.completion, completion);
99
100
  });
@@ -0,0 +1,209 @@
1
+ /** @file 验证 SessionStorage 的 SQLite 事务、投影、恢复与 Policy 隔离边界。 */
2
+
3
+ import assert from "node:assert/strict";
4
+ import fs from "node:fs/promises";
5
+ import os from "node:os";
6
+ import path from "node:path";
7
+ import { DatabaseSync } from "node:sqlite";
8
+ import test from "node:test";
9
+ import { SqliteSessionStorage } from "../bin/session/storage/SqliteSessionStorage.js";
10
+
11
+ /** 创建测试用文件系统协议。 */
12
+ function create_files() {
13
+ return {
14
+ ensure_directory: async (directory_path) => await fs.mkdir(directory_path, { recursive: true }),
15
+ file_size: async (file_path) => (await fs.stat(file_path)).size,
16
+ };
17
+ }
18
+
19
+ /** 创建一个文件型 SessionStorage。 */
20
+ async function create_storage(directory_path, options = {}) {
21
+ const storage = new SqliteSessionStorage({
22
+ session_id: options.session_id || "session-1",
23
+ agent_id: options.agent_id || "agent-1",
24
+ workspace_id: "workspace-1",
25
+ origin: { type: "chat" },
26
+ database_path: path.join(directory_path, "session.db"),
27
+ database_location: { type: "file" },
28
+ files: create_files(),
29
+ attachments: {},
30
+ });
31
+ await storage.initialize();
32
+ return storage;
33
+ }
34
+
35
+ /** 创建一条 User Message。 */
36
+ function create_user_message(state) {
37
+ return {
38
+ message_id: "user-1",
39
+ session_id: "session-1",
40
+ turn_id: "turn-1",
41
+ sequence: state.message_sequence,
42
+ revision: 1,
43
+ role: "user",
44
+ visibility: "visible",
45
+ created_at: 10,
46
+ updated_at: 10,
47
+ parts: [{ part_id: "part-user-1", sequence: 1, type: "text", text: "你好" }],
48
+ };
49
+ }
50
+
51
+ test("Message 与 Part 分表原子保存并刷新列表投影", async () => {
52
+ const directory_path = await fs.mkdtemp(path.join(os.tmpdir(), "downcity-session-storage-"));
53
+ const storage = await create_storage(directory_path);
54
+ const created = await storage.create_message(create_user_message);
55
+ assert.equal(created.role, "user");
56
+ const metadata = await storage.read_metadata();
57
+ assert.equal(metadata.message_count, 1);
58
+ assert.equal(metadata.preview_text, "你好");
59
+
60
+ const database = new DatabaseSync(path.join(directory_path, "session.db"), { readOnly: true });
61
+ try {
62
+ const message = database.prepare("SELECT role, state FROM messages").get();
63
+ assert.deepEqual({ ...message }, { role: "user", state: null });
64
+ const part = database.prepare("SELECT type, content FROM message_parts").get();
65
+ assert.equal(part.type, "text");
66
+ assert.deepEqual(Object.keys(JSON.parse(part.content)).sort(), ["text"]);
67
+ } finally {
68
+ database.close();
69
+ }
70
+
71
+ await assert.rejects(storage.update_message({
72
+ message: { ...created, revision: 3 },
73
+ expected_revision: 2,
74
+ changed_parts: [],
75
+ }), /revision conflict/);
76
+ const updated = {
77
+ ...created,
78
+ revision: 2,
79
+ updated_at: 20,
80
+ parts: [{ ...created.parts[0], text: "你好,SQLite" }],
81
+ };
82
+ await storage.update_message({
83
+ message: updated,
84
+ expected_revision: 1,
85
+ changed_parts: updated.parts,
86
+ });
87
+ assert.equal(updated.parts[0].text, "你好,SQLite");
88
+ assert.equal((await storage.read_metadata()).preview_text, "你好,SQLite");
89
+ await storage.dispose();
90
+ });
91
+
92
+ test("Storage 只查询中断状态,不擅自解释领域恢复语义", async () => {
93
+ const directory_path = await fs.mkdtemp(path.join(os.tmpdir(), "downcity-session-storage-"));
94
+ const storage = await create_storage(directory_path);
95
+ await storage.create_message((state) => ({
96
+ message_id: "agent-1",
97
+ session_id: "session-1",
98
+ turn_id: "turn-1",
99
+ sequence: state.message_sequence,
100
+ revision: 1,
101
+ role: "agent",
102
+ state: "streaming",
103
+ visibility: "visible",
104
+ created_at: 10,
105
+ updated_at: 10,
106
+ parts: [
107
+ { part_id: "text-1", sequence: 1, step_id: "step-1", type: "text", text: "部分输出", state: "streaming" },
108
+ { part_id: "tool-1", sequence: 2, step_id: "step-1", type: "tool", tool_call_id: "call-1", tool_name: "read", state: "running" },
109
+ { part_id: "action-1", sequence: 3, type: "action", action_id: "action-1", action_type: "test", state: "running", title: "测试" },
110
+ ],
111
+ }));
112
+ await storage.dispose();
113
+
114
+ const reopened = await create_storage(directory_path);
115
+ const [message] = await reopened.list_recoverable_agent_messages();
116
+ assert.equal(message.state, "streaming");
117
+ assert.equal(message.parts[0].state, "streaming");
118
+ assert.equal(message.parts[1].state, "running");
119
+ assert.equal(message.parts[2].state, "running");
120
+ assert.equal((await reopened.read_metadata()).preview_text, "部分输出");
121
+ await reopened.dispose();
122
+ });
123
+
124
+ test("Composer Policy 只能写自己的派生 namespace,clear 触发 FK 清理", async () => {
125
+ const directory_path = await fs.mkdtemp(path.join(os.tmpdir(), "downcity-session-storage-"));
126
+ const storage = await create_storage(directory_path);
127
+ await storage.create_message(create_user_message);
128
+ const policy = storage.composer_storage("sequence");
129
+ await policy.transaction((transaction) => {
130
+ transaction.execute("CREATE TABLE composer_sequence_test (message_id TEXT REFERENCES messages(message_id) ON DELETE CASCADE)");
131
+ transaction.execute("INSERT INTO composer_sequence_test (message_id) VALUES (?)", ["user-1"]);
132
+ });
133
+ await assert.rejects(policy.transaction((transaction) => transaction.execute("UPDATE messages SET visibility = 'internal'")), /can only mutate/);
134
+ await assert.rejects(policy.transaction((transaction) => transaction.execute("ALTER TABLE messages ADD COLUMN invalid TEXT")), /cannot execute database control/);
135
+ await assert.rejects(
136
+ policy.transaction((transaction) => transaction.execute(
137
+ "CREATE INDEX composer_sequence_messages_index ON messages(sequence)",
138
+ )),
139
+ /cannot execute database control/,
140
+ );
141
+ await storage.clear_messages();
142
+ assert.equal(await policy.transaction((transaction) => transaction.get("SELECT COUNT(*) AS count FROM composer_sequence_test")).then((row) => row.count), 0);
143
+ assert.equal((await storage.read_metadata()).preview_text, undefined);
144
+ await storage.dispose();
145
+ });
146
+
147
+ test("初始化失败会关闭连接并允许同一实例重试", async () => {
148
+ const directory_path = await fs.mkdtemp(path.join(os.tmpdir(), "downcity-session-storage-"));
149
+ const database_path = path.join(directory_path, "session.db");
150
+ const database = new DatabaseSync(database_path);
151
+ database.exec("PRAGMA user_version = 99");
152
+ database.close();
153
+ const storage = new SqliteSessionStorage({
154
+ session_id: "session-1",
155
+ agent_id: "agent-1",
156
+ origin: { type: "chat" },
157
+ database_path,
158
+ database_location: { type: "file" },
159
+ files: create_files(),
160
+ attachments: {},
161
+ });
162
+ await assert.rejects(storage.initialize(), /Unsupported Session schema version/);
163
+ const repair = new DatabaseSync(database_path);
164
+ repair.exec("PRAGMA user_version = 0");
165
+ repair.close();
166
+ await storage.initialize();
167
+ assert.equal((await storage.read_metadata()).session_id, "session-1");
168
+ await storage.dispose();
169
+ });
170
+
171
+ test("旧 SQLite schema 必须由外部脚本迁移", async () => {
172
+ const directory_path = await fs.mkdtemp(path.join(os.tmpdir(), "downcity-session-storage-"));
173
+ const database_path = path.join(directory_path, "session.db");
174
+ const database = new DatabaseSync(database_path);
175
+ database.exec("PRAGMA user_version = 1");
176
+ database.close();
177
+ const storage = new SqliteSessionStorage({
178
+ session_id: "session-1",
179
+ agent_id: "agent-1",
180
+ origin: { type: "chat" },
181
+ database_path,
182
+ database_location: { type: "file" },
183
+ files: create_files(),
184
+ attachments: {},
185
+ });
186
+ await assert.rejects(storage.initialize(), /requires the external migration script/);
187
+ await storage.dispose();
188
+ });
189
+
190
+ test("Codec 在损坏的 Part 内容进入领域层前失败", async () => {
191
+ const directory_path = await fs.mkdtemp(path.join(os.tmpdir(), "downcity-session-storage-"));
192
+ const database_path = path.join(directory_path, "session.db");
193
+ const storage = await create_storage(directory_path);
194
+ await storage.create_message(create_user_message);
195
+ await storage.dispose();
196
+
197
+ const database = new DatabaseSync(database_path);
198
+ database.prepare(
199
+ "UPDATE message_parts SET content = ? WHERE part_id = ?",
200
+ ).run(JSON.stringify({ text: 42 }), "part-user-1");
201
+ database.close();
202
+
203
+ const reopened = await create_storage(directory_path);
204
+ await assert.rejects(
205
+ reopened.list_messages(),
206
+ /Invalid persisted Session Part part-user-1.*text must be a string/,
207
+ );
208
+ await reopened.dispose();
209
+ });