@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
@@ -0,0 +1,776 @@
1
+ /**
2
+ * 单个 Session 的 SQLite 持久化实现。
3
+ *
4
+ * 本模块拥有数据库连接和事务;Message 领域只接收聚合对象,不感知 messages 与
5
+ * message_parts 的关系结构。Composer 只能通过带 namespace 的派生存储操作自己的表。
6
+ */
7
+
8
+ import path from "node:path";
9
+ import { DatabaseSync, type SQLInputValue } from "node:sqlite";
10
+ import type {
11
+ SessionAgentInteractionPart,
12
+ SessionAgentMessage,
13
+ SessionAgentMessagePart,
14
+ SessionMessage,
15
+ SessionOrigin,
16
+ SessionUserMessage,
17
+ } from "@downcity/type";
18
+ import { restore_session_origin } from "@downcity/type";
19
+ import type { FileSystem, StorageDatabaseLocation } from "@downcity/type";
20
+ import type { SessionHistoryMeta } from "@/executor/types/SessionHistoryMeta.js";
21
+ import { normalize_session_metadata, resolve_system_timezone } from "@/session/storage/Metadata.js";
22
+ import { resolve_session_message_preview } from "@/session/preview/SessionMessagePreview.js";
23
+ import {
24
+ decode_session_message,
25
+ encode_session_message_row,
26
+ encode_session_part_row,
27
+ type SessionMessagePartRow,
28
+ type SessionMessageRow,
29
+ } from "@/session/storage/SessionStorageCodec.js";
30
+ import {
31
+ SESSION_STORAGE_SCHEMA_SQL,
32
+ SESSION_STORAGE_SCHEMA_VERSION,
33
+ } from "@/session/storage/SessionStorageSchema.js";
34
+ import type {
35
+ SessionComposerStorage,
36
+ SessionComposerStorageTransaction,
37
+ SessionMessageCreateState,
38
+ SessionMessageStorageStats,
39
+ SessionMessageUpdate,
40
+ SessionStorage,
41
+ SessionStorageValue,
42
+ } from "@/types/store/SessionStorage.js";
43
+ import type { SessionAttachmentStore } from "@/types/store/SessionAttachmentStore.js";
44
+
45
+ /** SQLite SessionStorage 构造参数。 */
46
+ export interface SqliteSessionStorageOptions {
47
+ /** 当前 Session 的稳定标识。 */
48
+ session_id: string;
49
+ /** 当前 Session 所属 Agent。 */
50
+ agent_id: string;
51
+ /** 当前 Session 绑定的 Workspace。 */
52
+ workspace_id?: string;
53
+ /** 当前 Session 的不可变来源。 */
54
+ origin: SessionOrigin;
55
+ /** 数据库文件路径;内存模式只用于诊断和附件目录定位。 */
56
+ database_path: string;
57
+ /** 使用本地文件或进程内数据库。 */
58
+ database_location: StorageDatabaseLocation;
59
+ /** 当前 Agent 私有文件能力。 */
60
+ files: FileSystem;
61
+ /** 当前 Session 的附件存储。 */
62
+ attachments: SessionAttachmentStore;
63
+ }
64
+
65
+ /** 单个 Session 的 SQLite 存储。 */
66
+ export class SqliteSessionStorage implements SessionStorage {
67
+ readonly session_id: string;
68
+ readonly origin: SessionOrigin;
69
+ readonly attachments: SessionAttachmentStore;
70
+
71
+ private readonly agent_id: string;
72
+ private readonly workspace_id?: string;
73
+ private readonly database_path: string;
74
+ private readonly database_location: StorageDatabaseLocation;
75
+ private readonly files: FileSystem;
76
+ private database: DatabaseSync | null = null;
77
+ private initialize_promise: Promise<void> | null = null;
78
+ private disposed = false;
79
+
80
+ constructor(options: SqliteSessionStorageOptions) {
81
+ this.session_id = String(options.session_id || "").trim();
82
+ this.agent_id = String(options.agent_id || "").trim();
83
+ this.workspace_id = String(options.workspace_id || "").trim() || undefined;
84
+ this.origin = structuredClone(options.origin);
85
+ this.database_path = path.resolve(options.database_path);
86
+ this.database_location = options.database_location;
87
+ this.files = options.files;
88
+ this.attachments = options.attachments;
89
+ if (!this.session_id || !this.agent_id) {
90
+ throw new Error("SqliteSessionStorage requires session_id and agent_id");
91
+ }
92
+ }
93
+
94
+ /** 初始化数据库 schema 并校验 Session 身份。 */
95
+ async initialize(): Promise<void> {
96
+ if (!this.initialize_promise) this.initialize_promise = this.initialize_storage();
97
+ const initialize_promise = this.initialize_promise;
98
+ try {
99
+ await initialize_promise;
100
+ } catch (error) {
101
+ if (this.initialize_promise === initialize_promise) this.initialize_promise = null;
102
+ throw error;
103
+ }
104
+ }
105
+
106
+ /** 读取当前 Session metadata 投影。 */
107
+ async read_metadata(): Promise<SessionHistoryMeta> {
108
+ await this.initialize();
109
+ const row = this.require_database().prepare(`
110
+ SELECT session_id, agent_id, workspace_id, origin, timezone, title,
111
+ model_label, approval_mode, message_count, preview_text,
112
+ created_at, updated_at
113
+ FROM session_state WHERE singleton_id = 1
114
+ `).get() as SessionStateRow | undefined;
115
+ if (!row) throw new Error(`Session state does not exist: ${this.session_id}`);
116
+ return normalize_session_metadata({
117
+ v: 2,
118
+ session_id: row.session_id,
119
+ agent_id: row.agent_id,
120
+ ...(row.workspace_id ? { workspace_id: row.workspace_id } : {}),
121
+ origin: restore_session_origin(JSON.parse(row.origin), this.origin.type),
122
+ timezone: row.timezone,
123
+ ...(row.title ? { title: row.title } : {}),
124
+ ...(row.model_label ? { model_label: row.model_label } : {}),
125
+ ...(row.approval_mode ? { approval_mode: row.approval_mode } : {}),
126
+ message_count: row.message_count,
127
+ ...(row.preview_text ? { preview_text: row.preview_text } : {}),
128
+ created_at: row.created_at,
129
+ updated_at: row.updated_at,
130
+ }, this.session_id, this.agent_id, this.origin, row.workspace_id || undefined);
131
+ }
132
+
133
+ /** 原子覆盖 configured metadata,同时保持数据库身份不变量。 */
134
+ async write_metadata(metadata: SessionHistoryMeta): Promise<void> {
135
+ await this.initialize();
136
+ const normalized = normalize_session_metadata(
137
+ metadata,
138
+ this.session_id,
139
+ this.agent_id,
140
+ this.origin,
141
+ metadata.workspace_id,
142
+ );
143
+ this.run_transaction(() => {
144
+ const result = this.require_database().prepare(`
145
+ UPDATE session_state SET
146
+ workspace_id = ?, timezone = ?, title = ?, model_label = ?,
147
+ approval_mode = ?,
148
+ revision = revision + 1, updated_at = ?
149
+ WHERE singleton_id = 1 AND session_id = ? AND agent_id = ? AND origin = ?
150
+ `).run(
151
+ normalized.workspace_id ?? null,
152
+ normalized.timezone ?? resolve_system_timezone(),
153
+ normalized.title ?? null,
154
+ normalized.model_label ?? null,
155
+ normalized.approval_mode ?? null,
156
+ normalized.updated_at,
157
+ this.session_id,
158
+ this.agent_id,
159
+ JSON.stringify(this.origin),
160
+ );
161
+ if (result.changes !== 1) throw new Error(`Session identity mismatch: ${this.session_id}`);
162
+ });
163
+ }
164
+
165
+ /** 判断是否存在显式 system snapshot。 */
166
+ async has_instruction(): Promise<boolean> {
167
+ return (await this.read_instruction()) !== null;
168
+ }
169
+
170
+ /** 读取显式 system snapshot。 */
171
+ async read_instruction(): Promise<string | null> {
172
+ await this.initialize();
173
+ const row = this.require_database().prepare(
174
+ "SELECT system_snapshot FROM session_state WHERE singleton_id = 1",
175
+ ).get() as { system_snapshot: string | null } | undefined;
176
+ return row?.system_snapshot ?? null;
177
+ }
178
+
179
+ /** 原子写入显式 system snapshot。 */
180
+ async write_instruction(instruction: string): Promise<void> {
181
+ await this.initialize();
182
+ const value = String(instruction || "").trim();
183
+ if (!value) throw new Error("Session system snapshot cannot be empty");
184
+ this.run_transaction(() => {
185
+ this.require_database().prepare(`
186
+ UPDATE session_state
187
+ SET system_snapshot = ?, revision = revision + 1, updated_at = ?
188
+ WHERE singleton_id = 1
189
+ `).run(value, Date.now());
190
+ });
191
+ }
192
+
193
+ /** 读取全部 Message 聚合。 */
194
+ async list_messages(): Promise<SessionMessage[]> {
195
+ await this.initialize();
196
+ const rows = this.require_database().prepare(
197
+ "SELECT * FROM messages ORDER BY sequence ASC",
198
+ ).all() as unknown as SessionMessageRow[];
199
+ return this.read_aggregates(rows);
200
+ }
201
+
202
+ /** 读取指定 Message 聚合。 */
203
+ async read_message(message_id: string): Promise<SessionMessage | null> {
204
+ await this.initialize();
205
+ const row = this.require_database().prepare(
206
+ "SELECT * FROM messages WHERE message_id = ?",
207
+ ).get(message_id) as unknown as SessionMessageRow | undefined;
208
+ return row ? this.read_aggregates([row])[0] ?? null : null;
209
+ }
210
+
211
+ /** 只读取标题生成所需的最早一条 User Message。 */
212
+ async read_first_user_message(): Promise<SessionUserMessage | null> {
213
+ await this.initialize();
214
+ const row = this.require_database().prepare(
215
+ "SELECT * FROM messages WHERE role = 'user' ORDER BY sequence ASC LIMIT 1",
216
+ ).get() as unknown as SessionMessageRow | undefined;
217
+ if (!row) return null;
218
+ const message = this.read_aggregates([row])[0];
219
+ return message?.role === "user" ? message : null;
220
+ }
221
+
222
+ /** 分配全局 sequence 并创建完整 Message 聚合。 */
223
+ async create_message(
224
+ build_message: (state: SessionMessageCreateState) => SessionMessage,
225
+ ): Promise<SessionMessage> {
226
+ await this.initialize();
227
+ return this.run_transaction(() => {
228
+ const sequence_row = this.require_database().prepare(
229
+ "SELECT COALESCE(MAX(sequence), 0) + 1 AS next_sequence FROM messages",
230
+ ).get() as { next_sequence: number };
231
+ const message = build_message({
232
+ message_sequence: sequence_row.next_sequence,
233
+ });
234
+ this.validate_new_message(message, sequence_row.next_sequence);
235
+ this.insert_message_unsafe(message);
236
+ this.update_message_projection_unsafe(message, true);
237
+ return structuredClone(message);
238
+ });
239
+ }
240
+
241
+ /** 原子更新 Message envelope,并只写入调用方声明变化的 Part。 */
242
+ async update_message(input: SessionMessageUpdate): Promise<void> {
243
+ await this.initialize();
244
+ this.run_transaction(() => {
245
+ this.validate_message_update_unsafe(input);
246
+ this.update_message_envelope_unsafe(input.message, input.expected_revision);
247
+ for (const part of input.changed_parts) {
248
+ this.upsert_part_unsafe(input.message, part);
249
+ }
250
+ this.update_message_projection_unsafe(input.message, false);
251
+ });
252
+ }
253
+
254
+ /** 按 Message sequence 向前分页并返回升序聚合。 */
255
+ async list_message_page(input?: {
256
+ before_sequence?: number;
257
+ limit?: number;
258
+ include_internal?: boolean;
259
+ }): Promise<SessionMessage[]> {
260
+ await this.initialize();
261
+ const limit = Math.min(Math.max(input?.limit ?? 50, 1), 201);
262
+ const before_sequence = input?.before_sequence;
263
+ const include_internal = input?.include_internal === true;
264
+ const rows = this.require_database().prepare(`
265
+ SELECT * FROM messages
266
+ WHERE (? = 1 OR visibility = 'visible')
267
+ AND (? IS NULL OR sequence < ?)
268
+ ORDER BY sequence DESC
269
+ LIMIT ?
270
+ `).all(
271
+ include_internal ? 1 : 0,
272
+ before_sequence ?? null,
273
+ before_sequence ?? null,
274
+ limit,
275
+ );
276
+ return this.read_aggregates((rows as unknown as SessionMessageRow[]).reverse());
277
+ }
278
+
279
+ /** 只读取上次进程中断后需要收口的 Agent Message。 */
280
+ async list_recoverable_agent_messages(): Promise<SessionAgentMessage[]> {
281
+ await this.initialize();
282
+ const rows = this.require_database().prepare(`
283
+ SELECT messages.*
284
+ FROM messages
285
+ WHERE messages.role = 'agent'
286
+ AND messages.state = 'streaming'
287
+ ORDER BY messages.sequence ASC
288
+ `).all() as unknown as SessionMessageRow[];
289
+ return this.read_aggregates(rows).filter(
290
+ (message): message is SessionAgentMessage => message.role === "agent",
291
+ );
292
+ }
293
+
294
+ /** 读取指定 Turn 或整个 Session 的最后一条 Agent Message。 */
295
+ async read_latest_agent_message(turn_id?: string): Promise<SessionAgentMessage | null> {
296
+ await this.initialize();
297
+ const row = turn_id
298
+ ? this.require_database().prepare(`
299
+ SELECT * FROM messages
300
+ WHERE role = 'agent' AND turn_id = ?
301
+ ORDER BY sequence DESC LIMIT 1
302
+ `).get(turn_id)
303
+ : this.require_database().prepare(`
304
+ SELECT * FROM messages
305
+ WHERE role = 'agent'
306
+ ORDER BY sequence DESC LIMIT 1
307
+ `).get();
308
+ const message = row
309
+ ? this.read_aggregates([row as unknown as SessionMessageRow])[0] ?? null
310
+ : null;
311
+ return message?.role === "agent" ? message : null;
312
+ }
313
+
314
+ /** 读取当前 Message 数量、数据库大小与最新 Message。 */
315
+ async message_stats(): Promise<SessionMessageStorageStats> {
316
+ await this.initialize();
317
+ const count_row = this.require_database().prepare(
318
+ "SELECT message_count FROM session_state WHERE singleton_id = 1",
319
+ ).get() as { message_count: number };
320
+ const latest_row = this.require_database().prepare(
321
+ "SELECT * FROM messages ORDER BY sequence DESC LIMIT 1",
322
+ ).get() as unknown as SessionMessageRow | undefined;
323
+ const storage_bytes = this.database_location.type === "file"
324
+ ? await this.files.file_size(this.database_path).catch(() => 0)
325
+ : 0;
326
+ return {
327
+ message_count: count_row.message_count,
328
+ storage_bytes,
329
+ latest_message: latest_row ? this.read_aggregates([latest_row])[0] ?? null : null,
330
+ };
331
+ }
332
+
333
+ /** 清空 Message;外键负责同步删除 Part 与正确关联的派生数据。 */
334
+ async clear_messages(): Promise<void> {
335
+ await this.initialize();
336
+ this.run_transaction(() => {
337
+ this.require_database().exec("DELETE FROM messages");
338
+ this.require_database().prepare(`
339
+ UPDATE session_state SET
340
+ message_count = 0, preview_text = NULL,
341
+ revision = revision + 1, updated_at = ?
342
+ WHERE singleton_id = 1
343
+ `).run(Date.now());
344
+ });
345
+ }
346
+
347
+ /** 创建只允许当前 namespace 派生表的 Composer 存储。 */
348
+ composer_storage(namespace: string): SessionComposerStorage {
349
+ const normalized_namespace = normalize_composer_namespace(namespace);
350
+ const table_prefix = `composer_${normalized_namespace}_`;
351
+ return {
352
+ list_messages: async () => await this.list_messages(),
353
+ transaction: async <T>(operation: (transaction: SessionComposerStorageTransaction) => T) => {
354
+ await this.initialize();
355
+ return this.run_transaction(() => operation({
356
+ execute: (sql, parameters) => {
357
+ assert_policy_sql(sql, table_prefix);
358
+ this.run_statement(sql, parameters);
359
+ },
360
+ get: <TRow>(sql: string, parameters?: readonly SessionStorageValue[]) => {
361
+ assert_policy_sql(sql, table_prefix);
362
+ return (this.get_statement(sql, parameters) as TRow | undefined) ?? null;
363
+ },
364
+ all: <TRow>(sql: string, parameters?: readonly SessionStorageValue[]) => {
365
+ assert_policy_sql(sql, table_prefix);
366
+ return this.all_statement(sql, parameters) as TRow[];
367
+ },
368
+ }));
369
+ },
370
+ };
371
+ }
372
+
373
+ /** 关闭 SQLite 连接。 */
374
+ async dispose(): Promise<void> {
375
+ if (this.disposed) return;
376
+ this.disposed = true;
377
+ const database = this.database;
378
+ this.database = null;
379
+ if (database) database.close();
380
+ }
381
+
382
+ /** 执行一次完整初始化。 */
383
+ private async initialize_storage(): Promise<void> {
384
+ if (this.disposed) throw new Error(`SessionStorage is disposed: ${this.session_id}`);
385
+ if (this.database_location.type === "file") {
386
+ await this.files.ensure_directory(path.dirname(this.database_path));
387
+ }
388
+ const database = new DatabaseSync(
389
+ this.database_location.type === "file" ? this.database_path : ":memory:",
390
+ );
391
+ this.database = database;
392
+ try {
393
+ database.exec("PRAGMA foreign_keys = ON; PRAGMA busy_timeout = 5000;");
394
+ if (this.database_location.type === "file") {
395
+ database.exec("PRAGMA journal_mode = WAL; PRAGMA synchronous = NORMAL;");
396
+ }
397
+ const version = Number(database.prepare("PRAGMA user_version").get()?.user_version ?? 0);
398
+ if (version > SESSION_STORAGE_SCHEMA_VERSION) {
399
+ throw new Error(`Unsupported Session schema version: ${String(version)}`);
400
+ }
401
+ if (version > 0 && version < SESSION_STORAGE_SCHEMA_VERSION) {
402
+ throw new Error(
403
+ `Session schema version ${String(version)} requires the external migration script`,
404
+ );
405
+ }
406
+ database.exec(SESSION_STORAGE_SCHEMA_SQL);
407
+ database.exec(`PRAGMA user_version = ${String(SESSION_STORAGE_SCHEMA_VERSION)}`);
408
+ this.initialize_identity_unsafe();
409
+ } catch (error) {
410
+ if (this.database === database) this.database = null;
411
+ try {
412
+ database.close();
413
+ } catch {
414
+ // 初始化错误优先;关闭失败不覆盖真正原因。
415
+ }
416
+ throw error;
417
+ }
418
+ }
419
+
420
+ /** 创建或验证 Session 唯一状态行。 */
421
+ private initialize_identity_unsafe(): void {
422
+ this.run_transaction(() => {
423
+ const database = this.require_database();
424
+ const current = database.prepare(
425
+ "SELECT session_id, agent_id, workspace_id, origin FROM session_state WHERE singleton_id = 1",
426
+ ).get() as Pick<SessionStateRow, "session_id" | "agent_id" | "workspace_id" | "origin"> | undefined;
427
+ if (!current) {
428
+ const created_at = Date.now();
429
+ database.prepare(`
430
+ INSERT INTO session_state (
431
+ singleton_id, session_id, agent_id, workspace_id, origin, timezone,
432
+ message_count, revision, created_at, updated_at
433
+ ) VALUES (1, ?, ?, ?, ?, ?, 0, 1, ?, ?)
434
+ `).run(
435
+ this.session_id,
436
+ this.agent_id,
437
+ this.workspace_id ?? null,
438
+ JSON.stringify(this.origin),
439
+ resolve_system_timezone(),
440
+ created_at,
441
+ created_at,
442
+ );
443
+ return;
444
+ }
445
+ if (
446
+ current.session_id !== this.session_id ||
447
+ current.agent_id !== this.agent_id ||
448
+ current.origin !== JSON.stringify(this.origin)
449
+ ) {
450
+ throw new Error(`Session identity mismatch: ${this.session_id}`);
451
+ }
452
+ });
453
+ }
454
+
455
+ /** 批量读取 Message rows 对应的所有 Parts 并组装聚合。 */
456
+ private read_aggregates(rows: readonly SessionMessageRow[]): SessionMessage[] {
457
+ if (rows.length === 0) return [];
458
+ const placeholders = rows.map(() => "?").join(", ");
459
+ const part_rows = this.require_database().prepare(`
460
+ SELECT * FROM message_parts
461
+ WHERE message_id IN (${placeholders})
462
+ ORDER BY message_id ASC, sequence ASC
463
+ `).all(...rows.map((row) => row.message_id)) as unknown as SessionMessagePartRow[];
464
+ const parts_by_message = new Map<string, SessionMessagePartRow[]>();
465
+ for (const part of part_rows) {
466
+ const parts = parts_by_message.get(part.message_id) || [];
467
+ parts.push(part);
468
+ parts_by_message.set(part.message_id, parts);
469
+ }
470
+ return rows.map((row) => decode_session_message(
471
+ row,
472
+ parts_by_message.get(row.message_id) || [],
473
+ this.session_id,
474
+ ));
475
+ }
476
+
477
+ /** 插入 Message envelope 与全部 Parts。 */
478
+ private insert_message_unsafe(message: SessionMessage): void {
479
+ const row = encode_session_message_row(message);
480
+ this.require_database().prepare(`
481
+ INSERT INTO messages (
482
+ message_id, turn_id, sequence, revision, role, state,
483
+ visibility, origin_session_id, origin_message_id, origin_turn_id,
484
+ created_at, updated_at
485
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
486
+ `).run(
487
+ row.message_id, row.turn_id, row.sequence, row.revision, row.role,
488
+ row.state, row.visibility, row.origin_session_id,
489
+ row.origin_message_id, row.origin_turn_id, row.created_at, row.updated_at,
490
+ );
491
+ for (const part of message.parts) this.insert_part_unsafe(message, part);
492
+ }
493
+
494
+ /** 使用 revision 乐观锁更新 Message envelope。 */
495
+ private update_message_envelope_unsafe(
496
+ message: SessionMessage,
497
+ expected_revision: number,
498
+ ): void {
499
+ const row = encode_session_message_row(message);
500
+ const result = this.require_database().prepare(`
501
+ UPDATE messages SET
502
+ turn_id = ?, revision = ?, state = ?, visibility = ?,
503
+ updated_at = ?
504
+ WHERE message_id = ? AND revision = ? AND role = ? AND sequence = ?
505
+ `).run(
506
+ row.turn_id, row.revision, row.state, row.visibility,
507
+ row.updated_at, row.message_id, expected_revision, row.role, row.sequence,
508
+ );
509
+ if (result.changes !== 1) {
510
+ throw new Error(`Session Message revision conflict: ${message.message_id}`);
511
+ }
512
+ }
513
+
514
+ /** 插入或替换单个明确变化的 Part,不扫描同 Message 的其他 Part。 */
515
+ private upsert_part_unsafe(
516
+ message: SessionMessage,
517
+ part: SessionMessage["parts"][number],
518
+ ): void {
519
+ const row = encode_session_part_row(message, part);
520
+ const result = this.require_database().prepare(`
521
+ INSERT INTO message_parts (
522
+ part_id, message_id, sequence, step_id, type, content, created_at, updated_at
523
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
524
+ ON CONFLICT(part_id) DO UPDATE SET
525
+ sequence = excluded.sequence,
526
+ step_id = excluded.step_id,
527
+ type = excluded.type,
528
+ content = excluded.content,
529
+ updated_at = excluded.updated_at
530
+ WHERE message_parts.message_id = excluded.message_id
531
+ `).run(
532
+ row.part_id, row.message_id, row.sequence, row.step_id,
533
+ row.type, row.content, row.created_at, row.updated_at,
534
+ );
535
+ if (result.changes !== 1) {
536
+ throw new Error(`Session Part belongs to another Message: ${part.part_id}`);
537
+ }
538
+ }
539
+
540
+ /** 插入一个领域 Part。 */
541
+ private insert_part_unsafe(
542
+ message: SessionMessage,
543
+ part: SessionMessage["parts"][number],
544
+ ): void {
545
+ this.insert_part_row_unsafe(encode_session_part_row(message, part));
546
+ }
547
+
548
+ /** 插入已经编码的 Part row。 */
549
+ private insert_part_row_unsafe(row: SessionMessagePartRow): void {
550
+ this.require_database().prepare(`
551
+ INSERT INTO message_parts (
552
+ part_id, message_id, sequence, step_id, type, content, created_at, updated_at
553
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
554
+ `).run(
555
+ row.part_id, row.message_id, row.sequence, row.step_id,
556
+ row.type, row.content, row.created_at, row.updated_at,
557
+ );
558
+ }
559
+
560
+ /** 以当前已知 Message 增量维护列表投影,不反查完整历史。 */
561
+ private update_message_projection_unsafe(
562
+ message: SessionMessage,
563
+ created: boolean,
564
+ ): void {
565
+ if (!created && message.role === "agent" && message.state === "streaming") {
566
+ return;
567
+ }
568
+ const preview_text = resolve_session_message_preview(message).trim().slice(0, 180);
569
+ this.require_database().prepare(`
570
+ UPDATE session_state SET
571
+ message_count = message_count + ?,
572
+ preview_text = CASE
573
+ WHEN (SELECT MAX(sequence) FROM messages) = ? THEN ?
574
+ ELSE preview_text
575
+ END,
576
+ revision = revision + 1, updated_at = ?
577
+ WHERE singleton_id = 1
578
+ `).run(
579
+ created ? 1 : 0,
580
+ message.sequence,
581
+ preview_text || null,
582
+ message.updated_at,
583
+ );
584
+ }
585
+
586
+ /** 校验新 Message 身份、顺序和 Part 结构。 */
587
+ private validate_new_message(message: SessionMessage, next_sequence: number): void {
588
+ if (message.session_id !== this.session_id) throw new Error("Session Message session_id mismatch");
589
+ if (message.sequence !== next_sequence || message.revision !== 1) {
590
+ throw new Error("New Session Message requires the next sequence and revision 1");
591
+ }
592
+ this.validate_parts(message);
593
+ }
594
+
595
+ /** 只读取 envelope,校验定向更新没有改变聚合身份。 */
596
+ private validate_message_update_unsafe(input: SessionMessageUpdate): void {
597
+ const message = input.message;
598
+ const current = this.require_database().prepare(
599
+ "SELECT * FROM messages WHERE message_id = ?",
600
+ ).get(message.message_id) as unknown as SessionMessageRow | undefined;
601
+ if (!current) throw new Error(`Session Message not found: ${message.message_id}`);
602
+ if (
603
+ message.session_id !== this.session_id ||
604
+ message.sequence !== current.sequence ||
605
+ message.role !== current.role ||
606
+ current.revision !== input.expected_revision ||
607
+ message.revision !== input.expected_revision + 1 ||
608
+ message.created_at !== current.created_at ||
609
+ message.origin?.session_id !== (current.origin_session_id ?? undefined) ||
610
+ message.origin?.message_id !== (current.origin_message_id ?? undefined) ||
611
+ message.origin?.turn_id !== (current.origin_turn_id ?? undefined)
612
+ ) {
613
+ if (current.revision !== input.expected_revision) {
614
+ throw new Error(`Session Message revision conflict: ${message.message_id}`);
615
+ }
616
+ throw new Error(`Session Message update changed immutable identity: ${message.message_id}`);
617
+ }
618
+ this.validate_parts(message);
619
+ const message_parts = new Map<string, SessionMessage["parts"][number]>();
620
+ for (const part of message.parts) message_parts.set(part.part_id, part);
621
+ const changed_ids = new Set<string>();
622
+ for (const part of input.changed_parts) {
623
+ if (
624
+ changed_ids.has(part.part_id) ||
625
+ JSON.stringify(message_parts.get(part.part_id)) !== JSON.stringify(part)
626
+ ) {
627
+ throw new Error(`Invalid changed Session Part: ${part.part_id}`);
628
+ }
629
+ changed_ids.add(part.part_id);
630
+ }
631
+ }
632
+
633
+ /** 校验 Part identity、类型和连续顺序。 */
634
+ private validate_parts(message: SessionMessage): void {
635
+ const ids = new Set<string>();
636
+ for (let index = 0; index < message.parts.length; index += 1) {
637
+ const part = message.parts[index];
638
+ if (!part.part_id || ids.has(part.part_id) || part.sequence !== index + 1) {
639
+ throw new Error(`Invalid Session Part identity or sequence: ${part.part_id || "unknown"}`);
640
+ }
641
+ ids.add(part.part_id);
642
+ const user_type = part.type === "text" || part.type === "context" || part.type === "file" || part.type === "data";
643
+ if (message.role === "user" && !user_type) {
644
+ throw new Error(`User Message cannot contain ${part.type} Part`);
645
+ }
646
+ }
647
+ if (message.role !== "agent") return;
648
+ const has_non_terminal_part = message.parts.some((part) => {
649
+ if (part.type === "text" || part.type === "reasoning") {
650
+ return part.state === "streaming";
651
+ }
652
+ if (part.type === "tool") {
653
+ return part.state !== "completed" && part.state !== "failed";
654
+ }
655
+ if (part.type === "interaction") return part.status === "pending";
656
+ if (part.type === "action") return part.state === "running";
657
+ return false;
658
+ });
659
+ if (has_non_terminal_part && message.state !== "streaming") {
660
+ throw new Error(
661
+ `Non-terminal Agent Part requires a streaming Message: ${message.message_id}`,
662
+ );
663
+ }
664
+ }
665
+
666
+ /** 在当前连接上执行短同步事务。 */
667
+ private run_transaction<T>(operation: () => T): T {
668
+ const database = this.require_database();
669
+ database.exec("BEGIN IMMEDIATE");
670
+ try {
671
+ const result = operation();
672
+ database.exec("COMMIT");
673
+ return result;
674
+ } catch (error) {
675
+ try {
676
+ database.exec("ROLLBACK");
677
+ } catch {
678
+ // 原始事务错误优先,ROLLBACK 失败由 SQLite 下次打开时恢复。
679
+ }
680
+ throw error;
681
+ }
682
+ }
683
+
684
+ /** 执行带参数 SQL。 */
685
+ private run_statement(sql: string, parameters?: readonly SessionStorageValue[]): void {
686
+ this.require_database().prepare(sql).run(...to_sql_values(parameters));
687
+ }
688
+
689
+ /** 读取一条带参数 SQL。 */
690
+ private get_statement(sql: string, parameters?: readonly SessionStorageValue[]): unknown {
691
+ return this.require_database().prepare(sql).get(...to_sql_values(parameters));
692
+ }
693
+
694
+ /** 读取多条带参数 SQL。 */
695
+ private all_statement(sql: string, parameters?: readonly SessionStorageValue[]): unknown[] {
696
+ return this.require_database().prepare(sql).all(...to_sql_values(parameters));
697
+ }
698
+
699
+ /** 返回已经初始化且尚未释放的数据库连接。 */
700
+ private require_database(): DatabaseSync {
701
+ if (this.disposed) throw new Error(`SessionStorage is disposed: ${this.session_id}`);
702
+ if (!this.database) throw new Error(`SessionStorage is not initialized: ${this.session_id}`);
703
+ return this.database;
704
+ }
705
+ }
706
+
707
+ /** session_state 查询行。 */
708
+ interface SessionStateRow {
709
+ /** Session 标识。 */
710
+ session_id: string;
711
+ /** Agent 标识。 */
712
+ agent_id: string;
713
+ /** Workspace 标识。 */
714
+ workspace_id: string | null;
715
+ /** JSON 编码的 Session 来源。 */
716
+ origin: string;
717
+ /** Session 时区。 */
718
+ timezone: string;
719
+ /** Session 标题。 */
720
+ title: string | null;
721
+ /** 当前配置模型标签。 */
722
+ model_label: string | null;
723
+ /** Shell 审批模式。 */
724
+ approval_mode: "ask" | "always-allow" | null;
725
+ /** Message 数量投影。 */
726
+ message_count: number;
727
+ /** Session 列表预览。 */
728
+ preview_text: string | null;
729
+ /** Session 创建时间。 */
730
+ created_at: number;
731
+ /** Session 更新时间。 */
732
+ updated_at: number;
733
+ }
734
+
735
+ /** 校验 Composer 派生表 namespace。 */
736
+ function normalize_composer_namespace(value: string): string {
737
+ const namespace = String(value || "").trim();
738
+ if (!/^[a-z][a-z0-9_]*$/u.test(namespace)) {
739
+ throw new Error("Composer storage namespace must use lowercase snake_case");
740
+ }
741
+ return namespace;
742
+ }
743
+
744
+ /** 限制派生 SQL 的写目标,避免内置 Policy 修改 canonical 表。 */
745
+ function assert_policy_sql(sql: string, table_prefix: string): void {
746
+ const source = String(sql || "").trim();
747
+ if (!source) throw new Error("Composer storage SQL cannot be empty");
748
+ if (
749
+ /\b(?:ATTACH|DETACH|VACUUM|PRAGMA|REINDEX|ANALYZE|ALTER)\b/iu.test(source) ||
750
+ /\bCREATE\s+(?:UNIQUE\s+)?INDEX\b/iu.test(source) ||
751
+ /\bCREATE\s+TRIGGER\b/iu.test(source) ||
752
+ /\bDROP\s+(?:INDEX|TRIGGER)\b/iu.test(source)
753
+ ) {
754
+ throw new Error("Composer Policy cannot execute database control statements");
755
+ }
756
+ const mutation_targets = [
757
+ ...source.matchAll(/\bCREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?\s+([a-zA-Z_][a-zA-Z0-9_]*)/giu),
758
+ ...source.matchAll(/\bINSERT(?:\s+OR\s+(?:ROLLBACK|ABORT|REPLACE|FAIL|IGNORE))?\s+INTO\s+([a-zA-Z_][a-zA-Z0-9_]*)/giu),
759
+ ...source.matchAll(/\bREPLACE\s+INTO\s+([a-zA-Z_][a-zA-Z0-9_]*)/giu),
760
+ ...source.matchAll(/\bUPDATE(?:\s+OR\s+(?:ROLLBACK|ABORT|REPLACE|FAIL|IGNORE))?\s+([a-zA-Z_][a-zA-Z0-9_]*)/giu),
761
+ ...source.matchAll(/\bDELETE\s+FROM\s+([a-zA-Z_][a-zA-Z0-9_]*)/giu),
762
+ ...source.matchAll(/\bDROP\s+TABLE(?:\s+IF\s+EXISTS)?\s+([a-zA-Z_][a-zA-Z0-9_]*)/giu),
763
+ ].map((match) => match[1] || "");
764
+ const mutates_database = /\b(?:CREATE|INSERT|REPLACE|UPDATE|DELETE|DROP|ALTER)\b/iu.test(source);
765
+ if (mutates_database && mutation_targets.length === 0) {
766
+ throw new Error("Composer Policy SQL mutation is not supported");
767
+ }
768
+ if (mutation_targets.some((table_name) => !table_name.startsWith(table_prefix))) {
769
+ throw new Error(`Composer Policy can only mutate ${table_prefix}* tables`);
770
+ }
771
+ }
772
+
773
+ /** 把领域 SQL 标量转换为 node:sqlite 参数。 */
774
+ function to_sql_values(values?: readonly SessionStorageValue[]): SQLInputValue[] {
775
+ return (values || []).map((value) => value as SQLInputValue);
776
+ }