@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
@@ -7,8 +7,9 @@
7
7
  * - Queue 由 Session 持有;这里不解释配置种类,只执行出队 Command。
8
8
  */
9
9
 
10
+ import { createHash } from "node:crypto";
10
11
  import { nanoid } from "nanoid";
11
- import type { SessionMessage, SessionUserMessage } from "@downcity/type";
12
+ import type { SessionAgentMessage, SessionUserMessage } from "@downcity/type";
12
13
  import type { SessionActionEvent } from "@downcity/type";
13
14
  import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
14
15
  import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
@@ -18,7 +19,6 @@ import type {
18
19
  } from "@/types/sdk/AgentSessionTurn.js";
19
20
  import { is_agent_session_prompt_input_empty } from "@/types/sdk/AgentSessionPrompt.js";
20
21
  import type {
21
- SessionCompactHistory,
22
22
  SessionExecutor,
23
23
  SessionTurnExecutionResult,
24
24
  } from "@/types/session/SessionExecution.js";
@@ -26,31 +26,37 @@ import type { SessionTurnContext } from "@/types/executor/SessionTurnContext.js"
26
26
  import { create_session_turn_context } from "@/session/runtime/SessionTurnContext.js";
27
27
  import { SessionEventHub } from "@/session/runtime/SessionEventHub.js";
28
28
  import { SessionState } from "@/session/SessionState.js";
29
- import { SessionMessages } from "@/session/SessionMessages.js";
29
+ import {
30
+ normalize_session_user_parts,
31
+ SessionMessages,
32
+ } from "@/session/SessionMessages.js";
30
33
  import type { ShellApprovalGateway } from "@downcity/type";
31
34
  import type {
32
35
  SessionInteractionLifecycle,
33
36
  SessionInteractionPort,
34
37
  } from "@downcity/type";
35
38
  import { SessionAssistantOutputAdapter } from "@/session/execution/SessionAssistantOutputAdapter.js";
36
- import type { SessionAssistantOutput } from "@/types/executor/SessionAssistantOutput.js";
37
39
  import { SessionQueue } from "@/session/SessionQueue.js";
38
- import { SessionCommand } from "@/session/SessionCommand.js";
40
+ import { extract_session_message_text } from "@/session/messages/SessionMessageText.js";
39
41
  import type {
40
42
  ActiveSessionTurnState,
41
43
  SessionDeferred,
42
44
  SessionLoopOptions,
43
45
  } from "@/types/session/SessionLoop.js";
44
- import type { SessionCommandCompletion } from "@/types/session/SessionCommand.js";
45
- import { SESSION_TURN_FILE_DIFF_DATA_TYPE } from "@/session/messages/SessionTurnFileDiffData.js";
46
- import {
47
- build_session_turn_file_diff,
48
- build_session_turn_file_diff_summary,
49
- } from "@/session/messages/SessionTurnFileDiffBuilder.js";
50
- import { SESSION_HOOK_POINTS } from "@/session/SessionHookPoints.js";
51
- import type { SessionTurnCommittedHookValue } from "@downcity/type";
52
- import type { JsonValue } from "@downcity/type";
46
+ import type {
47
+ SessionCommand,
48
+ SessionCommandCompletion,
49
+ } from "@/types/session/SessionCommand.js";
53
50
  import { create_session_model_request_warning } from "@/session/runtime/SessionModelRequestWarning.js";
51
+ import {
52
+ complete_session_turn,
53
+ fail_session_turn,
54
+ } from "@/session/runtime/SessionTurnCompletion.js";
55
+ import {
56
+ append_session_turn_file_diff,
57
+ publish_session_turn_file_diff,
58
+ } from "@/session/runtime/SessionTurnFileDiff.js";
59
+ import type { SessionTurnCompletionOptions } from "@/types/session/SessionTurnCompletion.js";
54
60
 
55
61
  const TURN_STOPPED_MESSAGE = "Turn stopped";
56
62
  const QUEUED_PROMPT_CANCELLED_MESSAGE =
@@ -64,7 +70,7 @@ export class SessionLoop {
64
70
  private readonly session_origin: SessionLoopOptions["session_origin"];
65
71
  private readonly workspace_path: string;
66
72
  private readonly executor: SessionExecutor;
67
- private readonly compact_history_handler: SessionCompactHistory;
73
+ private readonly maintain_context: SessionLoopOptions["maintain_context"];
68
74
  private readonly state: SessionState;
69
75
  private readonly messages: SessionMessages;
70
76
  private readonly events: SessionEventHub;
@@ -76,14 +82,15 @@ export class SessionLoop {
76
82
  private pending_prompt_count = 0;
77
83
  private processing_promise: Promise<void> | null = null;
78
84
  private active_turn: ActiveSessionTurnState | null = null;
79
- private checkpoint_merged_messages: SessionUserMessage[] | null = null;
85
+ /** 尚未完成 canonical 接收的幂等 Prompt,防止进程内并发重复入队。 */
86
+ private readonly pending_request_handles = new Map<string, Promise<AgentSessionTurnHandle>>();
80
87
 
81
88
  constructor(options: SessionLoopOptions) {
82
89
  this.session_id = String(options.session_id || "").trim();
83
90
  this.session_origin = options.session_origin;
84
91
  this.workspace_path = String(options.workspace_path || "").trim();
85
92
  this.executor = options.executor;
86
- this.compact_history_handler = options.compact_history;
93
+ this.maintain_context = options.maintain_context;
87
94
  this.state = options.state;
88
95
  this.messages = options.messages;
89
96
  this.events = options.events;
@@ -107,21 +114,67 @@ export class SessionLoop {
107
114
  throw new Error("session.prompt requires a non-empty query");
108
115
  }
109
116
  await this.state.ensure_runnable();
117
+ const request_identity = resolve_prompt_request_identity(this.session_id, input.request_id);
118
+ if (!request_identity) return await this.enqueue_prompt(input);
119
+ const pending_handle = this.pending_request_handles.get(request_identity.turn_id);
120
+ if (pending_handle) return await pending_handle;
121
+ const operation = this.prompt_with_identity(input, request_identity);
122
+ this.pending_request_handles.set(request_identity.turn_id, operation);
123
+ try {
124
+ return await operation;
125
+ } finally {
126
+ if (this.pending_request_handles.get(request_identity.turn_id) === operation) {
127
+ this.pending_request_handles.delete(request_identity.turn_id);
128
+ }
129
+ }
130
+ }
131
+
132
+ /** 解析已有幂等结果,或把同一个稳定 Prompt 加入队列。 */
133
+ private async prompt_with_identity(
134
+ input: AgentSessionPromptInput,
135
+ request_identity: PromptRequestIdentity,
136
+ ): Promise<AgentSessionTurnHandle> {
137
+ const existing_handle = await this.resolve_idempotent_prompt(request_identity);
138
+ if (existing_handle) return existing_handle;
139
+ const persisted_message = this.messages.get_message(request_identity.message_id);
140
+ return await this.enqueue_prompt(input, request_identity, persisted_message?.role === "user"
141
+ ? persisted_message
142
+ : undefined);
143
+ }
144
+
145
+ /** 把一个已校验的 Prompt 加入 Session FIFO。 */
146
+ private async enqueue_prompt(
147
+ input: AgentSessionPromptInput,
148
+ request_identity?: PromptRequestIdentity,
149
+ persisted_message?: SessionUserMessage,
150
+ ): Promise<AgentSessionTurnHandle> {
110
151
  const deferred_handle = create_deferred<AgentSessionTurnHandle>();
111
152
  this.pending_prompt_count += 1;
112
- this.queue.enqueue_command(new SessionCommand({
153
+ this.enqueue_command({
154
+ kind: "prompt",
155
+ ...(request_identity ? { turn_id: request_identity.turn_id } : {}),
113
156
  execute: async () => {
114
- await this.execute_prompt_command(input, deferred_handle);
157
+ await this.execute_prompt_command(
158
+ input,
159
+ deferred_handle,
160
+ request_identity?.message_id,
161
+ persisted_message,
162
+ );
115
163
  },
116
164
  cancel: () => {
117
165
  this.pending_prompt_count = Math.max(0, this.pending_prompt_count - 1);
118
166
  this.resolve_cancelled_prompt(deferred_handle);
119
167
  },
120
- }));
121
- this.ensure_processing();
168
+ });
122
169
  return await deferred_handle.promise;
123
170
  }
124
171
 
172
+ /** 追加 Command,并确保空闲 Session 也会主动消费维护操作。 */
173
+ enqueue_command(command: SessionCommand): void {
174
+ this.queue.enqueue_command(command);
175
+ this.ensure_processing();
176
+ }
177
+
125
178
  /**
126
179
  * 判断是否存在等待并入下一 Session step 的 prompt。
127
180
  */
@@ -154,7 +207,7 @@ export class SessionLoop {
154
207
  * - Session 会用它阻止内部 direct execution 与 actor 模式并发混用。
155
208
  */
156
209
  is_active(): boolean {
157
- return this.processing_promise !== null || this.has_pending_prompt();
210
+ return this.processing_promise !== null || this.has_pending_command();
158
211
  }
159
212
 
160
213
  /**
@@ -186,15 +239,22 @@ export class SessionLoop {
186
239
  if (this.processing_promise) return;
187
240
  this.processing_promise = this.process_loop().finally(() => {
188
241
  this.processing_promise = null;
189
- if (this.has_pending_prompt()) {
242
+ if (this.has_pending_command()) {
190
243
  this.ensure_processing();
191
244
  }
192
245
  });
193
246
  }
194
247
 
195
248
  private async process_loop(): Promise<void> {
196
- while (this.has_pending_prompt()) {
197
- const turn_id = `turn:${this.session_id}:${Date.now()}:${nanoid(6)}`;
249
+ while (this.has_pending_command()) {
250
+ const command = this.queue.take_next();
251
+ if (!command) return;
252
+ if (command.kind === "maintenance") {
253
+ await this.execute_maintenance_command(command);
254
+ continue;
255
+ }
256
+
257
+ const turn_id = command.turn_id || `turn:${this.session_id}:${Date.now()}:${nanoid(6)}`;
198
258
  const active_turn = create_active_session_turn_state(turn_id);
199
259
  this.active_turn = active_turn;
200
260
  active_turn.turn_context = this.create_turn_context(active_turn);
@@ -208,20 +268,26 @@ export class SessionLoop {
208
268
  created_at: Date.now(),
209
269
  });
210
270
 
211
- while (this.active_turn === active_turn) {
212
- const command = this.queue.take_next();
213
- if (!command) {
214
- await this.fail_active_turn(
215
- active_turn,
216
- new Error("Session Queue lost its pending Prompt Command"),
217
- );
218
- break;
219
- }
220
- try {
221
- await this.execute_command(command);
222
- } catch (error) {
223
- await this.fail_active_turn(active_turn, error);
224
- }
271
+ try {
272
+ await this.execute_command(command);
273
+ } catch (error) {
274
+ await this.fail_active_turn(active_turn, error);
275
+ }
276
+ }
277
+ }
278
+
279
+ /** 在没有 Active Turn 时执行 Session 级维护命令。 */
280
+ private async execute_maintenance_command(command: SessionCommand): Promise<void> {
281
+ try {
282
+ await this.execute_command(command);
283
+ } catch (error) {
284
+ try {
285
+ await this.logger.log("warn", "[agent] session maintenance command failed", {
286
+ session_id: this.session_id,
287
+ error: error instanceof Error ? error.message : String(error),
288
+ });
289
+ } catch {
290
+ // Maintenance Command 已经失败,日志失败不能阻止后续 Command 继续执行。
225
291
  }
226
292
  }
227
293
  }
@@ -233,35 +299,26 @@ export class SessionLoop {
233
299
  /**
234
300
  * 在下一 Session step 检查点按入队顺序提交配置并持久化 steer。
235
301
  */
236
- private async drain_queued_inputs(
237
- active_turn: ActiveSessionTurnState,
238
- ): Promise<SessionUserMessage[]> {
302
+ private async drain_queued_inputs(): Promise<void> {
239
303
  const drained = this.queue.drain();
240
- if (drained.length <= 0) return [];
241
- const merged: SessionUserMessage[] = [];
242
- this.checkpoint_merged_messages = merged;
304
+ if (drained.length <= 0) return;
243
305
 
244
- try {
245
- for (let index = 0; index < drained.length; index += 1) {
246
- const command = drained[index];
247
- try {
248
- await this.execute_command(command);
249
- } catch {
250
- // Prompt 持久化失败时恢复尚未处理的对象;Action 自己负责失败观测。
251
- this.queue.restore_front(drained.slice(index));
252
- break;
253
- }
306
+ for (let index = 0; index < drained.length; index += 1) {
307
+ const command = drained[index];
308
+ try {
309
+ await this.execute_command(command);
310
+ } catch {
311
+ // Prompt 持久化失败时恢复尚未处理的对象;Action 自己负责失败观测。
312
+ this.queue.restore_front(drained.slice(index));
313
+ break;
254
314
  }
255
- } finally {
256
- this.checkpoint_merged_messages = null;
257
315
  }
258
-
259
- return merged;
260
316
  }
261
317
 
262
318
  /** 执行 Command,并尽力持久化其声明的 canonical 完成信息。 */
263
319
  private async execute_command(command: SessionCommand): Promise<void> {
264
- const completion = await command.execute();
320
+ await command.execute();
321
+ const completion = command.completion;
265
322
  if (!completion) return;
266
323
  await this.persist_command_completion(completion);
267
324
  }
@@ -270,12 +327,12 @@ export class SessionLoop {
270
327
  private async persist_command_completion(
271
328
  completion: SessionCommandCompletion,
272
329
  ): Promise<void> {
273
- const turn_id = this.require_active_turn().turn_id;
330
+ const turn_id = this.current_turn_id();
274
331
  try {
275
332
  await this.persist_action_event({
276
333
  action_id: completion.id,
277
334
  action_type: "command",
278
- turn_id,
335
+ ...(turn_id ? { turn_id } : {}),
279
336
  title: completion.title,
280
337
  ...(completion.description
281
338
  ? { description: completion.description }
@@ -297,58 +354,22 @@ export class SessionLoop {
297
354
  }
298
355
  }
299
356
 
300
- /** 在当前 Turn 上执行一次显式历史压缩。 */
301
- async compact_history(
302
- compact_id: string,
303
- ): ReturnType<SessionCompactHistory> {
304
- const turn_id = this.require_active_turn().turn_id;
305
- const result = await this.compact_history_handler({ turn_id });
306
- if (
307
- result.compacted &&
308
- this.active_turn?.turn_context
309
- ) {
310
- this.require_active_turn().history_reload_requested = true;
311
- }
312
- if (result.reason === "nothing_to_compact") {
313
- try {
314
- await this.persist_action_event({
315
- action_id: compact_id,
316
- action_type: "history-compaction",
317
- turn_id,
318
- title: "Session messages already compact",
319
- description: "The Session has no active messages to compact.",
320
- status: "completed",
321
- });
322
- } catch (error) {
323
- try {
324
- await this.logger.log("warn", "[agent] compact result persistence failed", {
325
- session_id: this.session_id,
326
- compact_id,
327
- error: error instanceof Error ? error.message : String(error),
328
- });
329
- } catch {
330
- // 领域结果已经确定,Action 与日志失败都不能把成功压缩改写为失败。
331
- }
332
- }
333
- }
334
- return result;
335
- }
336
-
337
357
  /** 执行一个出队 Prompt;首条 Prompt 启动 Turn,后续 Prompt 作为 steer 合并。 */
338
358
  private async execute_prompt_command(
339
359
  input: AgentSessionPromptInput,
340
360
  deferred_handle: SessionDeferred<AgentSessionTurnHandle>,
361
+ message_id?: string,
362
+ persisted_message?: SessionUserMessage,
341
363
  ): Promise<void> {
342
364
  const active_turn = this.require_active_turn();
343
365
  if (active_turn.prompt_started) {
344
366
  const message = await this.persist_prompt_message(
345
367
  input,
346
368
  active_turn.turn_id,
347
- "steer",
348
369
  );
370
+ active_turn.turn_context?.input.observe_user_message(message);
349
371
  this.pending_prompt_count = Math.max(0, this.pending_prompt_count - 1);
350
372
  deferred_handle.resolve(create_turn_handle(active_turn));
351
- this.checkpoint_merged_messages?.push(message);
352
373
  return;
353
374
  }
354
375
 
@@ -356,15 +377,25 @@ export class SessionLoop {
356
377
  this.pending_prompt_count = Math.max(0, this.pending_prompt_count - 1);
357
378
  let handle_resolved = false;
358
379
  try {
359
- await this.persist_prompt_message(input, active_turn.turn_id, "prompt");
380
+ const message = persisted_message || await this.persist_prompt_message(
381
+ input,
382
+ active_turn.turn_id,
383
+ message_id,
384
+ );
385
+ active_turn.turn_context?.input.observe_user_message(message);
360
386
  // 只有 canonical user message 已经写入 Session 后,调用方才认为输入被接收。
361
387
  deferred_handle.resolve(create_turn_handle(active_turn));
362
388
  handle_resolved = true;
363
389
  const result = await this.execute_prompt_turn({
364
390
  active_turn,
365
- prompt_input: input,
366
391
  });
367
- await this.finish_active_turn(active_turn, result);
392
+ const final_result = await complete_session_turn(
393
+ this.turn_completion_options(),
394
+ active_turn,
395
+ result,
396
+ );
397
+ if (this.active_turn === active_turn) this.active_turn = null;
398
+ active_turn.deferred_finished.resolve(final_result);
368
399
  } catch (error) {
369
400
  // 持久化失败时仍兑现句柄,让调用方可以观察到失败的 Turn,而不是永久等待。
370
401
  if (!handle_resolved) deferred_handle.resolve(create_turn_handle(active_turn));
@@ -378,89 +409,18 @@ export class SessionLoop {
378
409
  throw new Error("Session Command requires an active Turn");
379
410
  }
380
411
 
381
- /** Executor 结果结束当前 Active Turn。 */
382
- private async finish_active_turn(
383
- active_turn: ActiveSessionTurnState,
384
- result: SessionTurnExecutionResult,
385
- ): Promise<void> {
386
- const stopped = active_turn.turn_context?.lifecycle.abort_signal.aborted === true;
387
- const final_result: AgentSessionTurnResult = {
388
- turn_id: active_turn.turn_id,
389
- text: result.text,
390
- success: stopped ? false : result.success,
391
- ...(stopped
392
- ? { error: TURN_STOPPED_MESSAGE }
393
- : result.error ? { error: result.error } : {}),
394
- };
395
- active_turn.result = final_result;
396
- this.events.publish({
397
- mutation_id: nanoid(),
398
- variant: "turn",
399
- type: "finish",
400
- session_id: this.session_id,
401
- turn_id: active_turn.turn_id,
402
- status: stopped ? "stopped" : final_result.success ? "completed" : "failed",
403
- created_at: Date.now(),
404
- text: final_result.text,
405
- ...(final_result.error ? { error: final_result.error } : {}),
406
- });
407
- await this.notify_turn_committed(
408
- active_turn,
409
- stopped ? "stopped" : final_result.success ? "completed" : "failed",
410
- );
411
- await this.dispose_turn_context(active_turn);
412
- active_turn.deferred_finished.resolve(final_result);
413
- if (this.active_turn === active_turn) this.active_turn = null;
414
- }
415
-
416
- /** 以失败结果结束当前 Active Turn,并尽力持久化 Error Message。 */
412
+ /** 以失败结果结束当前 Active Turn,并尽力持久化包含 Error Part 的 Agent Message。 */
417
413
  private async fail_active_turn(
418
414
  active_turn: ActiveSessionTurnState,
419
415
  error: unknown,
420
416
  ): Promise<void> {
421
- if (active_turn.result) return;
422
- const stopped = active_turn.turn_context?.lifecycle.abort_signal.aborted === true;
423
- const message = stopped
424
- ? TURN_STOPPED_MESSAGE
425
- : error instanceof Error ? error.message : String(error);
426
- const final_result: AgentSessionTurnResult = {
427
- turn_id: active_turn.turn_id,
428
- text: "",
429
- success: false,
430
- error: message,
431
- };
432
- active_turn.result = final_result;
433
- if (message !== TURN_STOPPED_MESSAGE) {
434
- try {
435
- await this.messages.append_error_message({
436
- scope: "turn",
437
- turn_id: active_turn.turn_id,
438
- code: "turn_execution_failed",
439
- message,
440
- recoverable: true,
441
- });
442
- } catch {
443
- // Error Message 写入失败不能阻止 Turn Handle 收口。
444
- }
445
- }
446
- this.events.publish({
447
- mutation_id: nanoid(),
448
- variant: "turn",
449
- type: "finish",
450
- session_id: this.session_id,
451
- turn_id: active_turn.turn_id,
452
- status: stopped ? "stopped" : "failed",
453
- created_at: Date.now(),
454
- text: "",
455
- error: message,
456
- });
457
- await this.notify_turn_committed(
417
+ const final_result = await fail_session_turn(
418
+ this.turn_completion_options(),
458
419
  active_turn,
459
- stopped ? "stopped" : "failed",
420
+ error,
460
421
  );
461
- await this.dispose_turn_context(active_turn);
462
- active_turn.deferred_finished.resolve(final_result);
463
422
  if (this.active_turn === active_turn) this.active_turn = null;
423
+ active_turn.deferred_finished.resolve(final_result);
464
424
  }
465
425
 
466
426
  /** 为一条尚未执行的 Prompt 创建可观测取消结果。 */
@@ -503,7 +463,6 @@ export class SessionLoop {
503
463
  /** 执行一个 Turn 内的模型与 Tool Step Loop。 */
504
464
  private async execute_prompt_turn(input: {
505
465
  active_turn: ActiveSessionTurnState;
506
- prompt_input: AgentSessionPromptInput;
507
466
  }): Promise<{
508
467
  text: string;
509
468
  success: boolean;
@@ -514,45 +473,34 @@ export class SessionLoop {
514
473
  if (!turn_context || !assistant_output) {
515
474
  throw new Error("Active Session Turn requires an initialized context");
516
475
  }
517
- const query = input.prompt_input.query;
518
- const executor_query = typeof query === "string"
519
- ? query
520
- : query
521
- .flatMap((part) => part.type === "text" ? [part.text] : [])
522
- .join("\n")
523
- .trim();
524
476
  let result: SessionTurnExecutionResult;
525
477
  try {
526
- result = await this.executor.execute({
527
- query: executor_query,
528
- turn_context,
529
- });
478
+ result = await this.executor.execute({ turn_context });
530
479
  } catch (error) {
531
- await this.append_turn_file_diff(
532
- input.active_turn.turn_id,
533
- turn_context,
534
- assistant_output,
535
- );
536
- try {
537
- await assistant_output.finish({
538
- status: turn_context.lifecycle.abort_signal.aborted ? "stopped" : "failed",
539
- error: error instanceof Error ? error.message : String(error),
540
- });
541
- } catch (finish_error) {
542
- await this.log_file_diff_warning(
543
- input.active_turn.turn_id,
544
- "failed to close Assistant output after execution error",
545
- finish_error,
546
- );
547
- }
548
- throw error;
480
+ result = {
481
+ text: "",
482
+ success: false,
483
+ error: error instanceof Error ? error.message : String(error),
484
+ };
549
485
  }
550
486
 
551
- await this.append_turn_file_diff(
552
- input.active_turn.turn_id,
487
+ if (!result.success && !turn_context.lifecycle.abort_signal.aborted && result.error) {
488
+ await assistant_output.append_error({
489
+ scope: "turn",
490
+ code: "turn_execution_failed",
491
+ message: result.error,
492
+ recoverable: true,
493
+ });
494
+ }
495
+
496
+ await append_session_turn_file_diff({
497
+ session_id: this.session_id,
498
+ turn_id: input.active_turn.turn_id,
499
+ workspace_path: this.workspace_path,
553
500
  turn_context,
554
501
  assistant_output,
555
- );
502
+ logger: this.logger,
503
+ });
556
504
 
557
505
  await assistant_output.finish({
558
506
  status: turn_context.lifecycle.abort_signal.aborted
@@ -563,24 +511,8 @@ export class SessionLoop {
563
511
  ...(result.error ? { error: result.error } : {}),
564
512
  });
565
513
 
566
- if (!result.success && !turn_context.lifecycle.abort_signal.aborted && result.error) {
567
- await this.messages.append_error_message({
568
- scope: "turn",
569
- turn_id: input.active_turn.turn_id,
570
- code: "turn_execution_failed",
571
- message: result.error,
572
- recoverable: true,
573
- });
574
- }
575
- await this.state.touch_metadata();
576
- const deferred_count = await this.messages.append_deferred_user_messages(
577
- result.deferred_persisted_user_messages,
578
- );
579
- if (deferred_count > 0) await this.state.touch_metadata();
580
514
  if (result.compact_required) {
581
- await this.compact_history_handler({
582
- turn_id: input.active_turn.turn_id,
583
- });
515
+ await this.maintain_context();
584
516
  }
585
517
  return {
586
518
  text: result.text,
@@ -589,56 +521,6 @@ export class SessionLoop {
589
521
  };
590
522
  }
591
523
 
592
- /** 把当前 Turn 成功的结构化文件修改写入 canonical Assistant data part。 */
593
- private async append_turn_file_diff(
594
- turn_id: string,
595
- turn_context: SessionTurnContext,
596
- assistant_output: SessionAssistantOutput,
597
- ): Promise<void> {
598
- try {
599
- const file_diff = build_session_turn_file_diff(
600
- this.workspace_path,
601
- turn_context.effects.snapshot(),
602
- );
603
- if (!file_diff) return;
604
- await assistant_output.append_result_parts([{
605
- type: "data",
606
- data_type: SESSION_TURN_FILE_DIFF_DATA_TYPE,
607
- data_id: `turn-file-diff:${turn_id}`,
608
- data: {
609
- files: file_diff.files.map((file) => ({
610
- file: file.file,
611
- status: file.status,
612
- additions: file.additions,
613
- deletions: file.deletions,
614
- patch: file.patch,
615
- })),
616
- additions: file_diff.additions,
617
- deletions: file_diff.deletions,
618
- },
619
- }]);
620
- } catch (error) {
621
- await this.log_file_diff_warning(turn_id, "failed to persist structured file edits", error);
622
- }
623
- }
624
-
625
- /** 文件修改展示属于辅助观测能力,失败不能改变 Turn 结果。 */
626
- private async log_file_diff_warning(
627
- turn_id: string,
628
- message: string,
629
- error: unknown,
630
- ): Promise<void> {
631
- try {
632
- await this.logger.log("warn", `[agent] ${message}`, {
633
- session_id: this.session_id,
634
- turn_id,
635
- error: error instanceof Error ? error.message : String(error),
636
- });
637
- } catch {
638
- // 文件编辑观测失败不影响 canonical 对话执行。
639
- }
640
- }
641
-
642
524
  /** 在 Turn 创建时建立其唯一执行上下文和 Assistant 输出端口。 */
643
525
  private create_turn_context(
644
526
  active_turn: ActiveSessionTurnState,
@@ -652,45 +534,33 @@ export class SessionLoop {
652
534
  session_id: this.session_id,
653
535
  session_origin: this.session_origin,
654
536
  project_root: this.workspace_path,
655
- merge_step_input: async () => {
656
- const merged = await this.drain_queued_inputs(active_turn);
657
- if (merged.length > 0) await assistant_output.close_current_message();
658
- return merged;
537
+ commit_step_input: async () => {
538
+ const had_pending_prompt = this.has_pending_prompt();
539
+ await this.drain_queued_inputs();
540
+ if (had_pending_prompt) await assistant_output.close_current_message();
659
541
  },
660
- has_pending_step_input: () => this.has_pending_prompt(),
661
- consume_history_reload: () => {
662
- const requested = active_turn.history_reload_requested;
663
- active_turn.history_reload_requested = false;
664
- return requested;
542
+ append_internal_user_message: async (parts) => {
543
+ const message = await this.messages.append_user_message({
544
+ turn_id: active_turn.turn_id,
545
+ visibility: "internal",
546
+ parts: normalize_session_user_parts([...parts]),
547
+ });
548
+ active_turn.turn_context?.input.observe_user_message(message);
549
+ return message;
665
550
  },
551
+ has_pending_step_input: () => this.has_pending_prompt(),
666
552
  assistant_output,
667
553
  shell_approval_gateway: this.shell_approval_gateway,
668
554
  interactions: this.interactions,
669
555
  on_effects_changed: (effects) => {
670
- // Thinking 状态行的文件改动是辅助观测,失败不影响 Turn 结果。
671
- try {
672
- const summary = build_session_turn_file_diff_summary(
673
- this.workspace_path,
674
- effects,
675
- );
676
- if (summary.files_count === 0) return;
677
- this.events.publish({
678
- mutation_id: nanoid(),
679
- variant: "file_diff",
680
- session_id: this.session_id,
681
- turn_id: active_turn.turn_id,
682
- created_at: Date.now(),
683
- files_count: summary.files_count,
684
- additions: summary.additions,
685
- deletions: summary.deletions,
686
- });
687
- } catch (error) {
688
- void this.log_file_diff_warning(
689
- active_turn.turn_id,
690
- "failed to publish live file edit summary",
691
- error,
692
- );
693
- }
556
+ publish_session_turn_file_diff({
557
+ session_id: this.session_id,
558
+ turn_id: active_turn.turn_id,
559
+ workspace_path: this.workspace_path,
560
+ effects,
561
+ publish: (mutation) => this.events.publish(mutation),
562
+ logger: this.logger,
563
+ });
694
564
  },
695
565
  publish_action: async (event) => {
696
566
  await this.persist_action_event(event);
@@ -709,80 +579,52 @@ export class SessionLoop {
709
579
  private async persist_prompt_message(
710
580
  prompt: AgentSessionPromptInput,
711
581
  turn_id: string,
712
- input_type: "prompt" | "steer",
582
+ message_id?: string,
713
583
  ): Promise<SessionUserMessage> {
714
584
  const message = await this.messages.append_prompt_message({
715
585
  project_root: this.workspace_path,
716
586
  prompt,
717
587
  turn_id,
718
- input_type,
588
+ ...(message_id ? { message_id } : {}),
719
589
  });
720
- this.state.touch_metadata_in_background();
721
590
  this.state.schedule_title_generation();
722
591
  return message;
723
592
  }
724
593
 
594
+ /** 解析已经持久化或仍在执行的幂等 Prompt。 */
595
+ private async resolve_idempotent_prompt(
596
+ identity: PromptRequestIdentity,
597
+ ): Promise<AgentSessionTurnHandle | null> {
598
+ const existing_message = this.messages.get_message(identity.message_id);
599
+ if (!existing_message) return null;
600
+ if (existing_message.role !== "user" || existing_message.turn_id !== identity.turn_id) {
601
+ throw new Error("Session prompt request identity conflicts with canonical history");
602
+ }
603
+ if (this.active_turn?.turn_id === identity.turn_id) {
604
+ return create_turn_handle(this.active_turn);
605
+ }
606
+ const agent_message = await this.messages.read_latest_agent_message(identity.turn_id);
607
+ if (!agent_message || agent_message.state === "streaming") return null;
608
+ return create_completed_turn_handle(to_persisted_turn_result(identity.turn_id, agent_message));
609
+ }
610
+
725
611
  /** 持久化 Executor Action,并同步刷新 Session metadata。 */
726
612
  private async persist_action_event(
727
613
  event: SessionActionEvent,
728
614
  options?: { publish_mutation?: boolean },
729
615
  ): Promise<void> {
730
616
  await this.messages.persist_action(event, options);
731
- await this.state.touch_metadata();
732
617
  }
733
618
 
734
- /** Turn 生命周期所有者尽力释放其唯一 Context。 */
735
- private async dispose_turn_context(
736
- active_turn: ActiveSessionTurnState,
737
- ): Promise<void> {
738
- try {
739
- await active_turn.turn_context?.lifecycle.dispose();
740
- } catch (error) {
741
- try {
742
- await this.logger.log("warn", "[agent] turn context disposal failed", {
743
- session_id: this.session_id,
744
- turn_id: active_turn.turn_id,
745
- error: error instanceof Error ? error.message : String(error),
746
- });
747
- } catch {
748
- // Context 已进入释放流程,日志失败不能阻止 Turn Handle 收口。
749
- }
750
- }
751
- }
752
-
753
- /** 在释放当前 lease 前触发现有 Plugin effect point。 */
754
- private async notify_turn_committed(
755
- active_turn: ActiveSessionTurnState,
756
- status: SessionTurnCommittedHookValue["status"],
757
- ): Promise<void> {
758
- const extensions = active_turn.turn_context?.step.hooks;
759
- if (!extensions) return;
760
- try {
761
- const messages = (await this.messages.list_history_messages())
762
- .filter((message) => message.turn_id === active_turn.turn_id)
763
- .map((message) => structuredClone(message));
764
- const value: SessionTurnCommittedHookValue = {
765
- session_id: this.session_id,
766
- turn_id: active_turn.turn_id,
767
- status,
768
- messages: messages as SessionMessage[],
769
- };
770
- await extensions.effect(
771
- SESSION_HOOK_POINTS.turn_committed,
772
- value as unknown as JsonValue,
773
- );
774
- } catch (error) {
775
- try {
776
- await this.logger.log("warn", "[agent] session plugin effect failed", {
777
- session_id: this.session_id,
778
- turn_id: active_turn.turn_id,
779
- point_name: SESSION_HOOK_POINTS.turn_committed,
780
- error: error instanceof Error ? error.message : String(error),
781
- });
782
- } catch {
783
- // Plugin effect 不改变已经确定的 Turn 结果。
784
- }
785
- }
619
+ /** Turn 收口领域函数投影稳定依赖。 */
620
+ private turn_completion_options(): SessionTurnCompletionOptions {
621
+ return {
622
+ session_id: this.session_id,
623
+ messages: this.messages,
624
+ events: this.events,
625
+ logger: this.logger,
626
+ stopped_message: TURN_STOPPED_MESSAGE,
627
+ };
786
628
  }
787
629
  }
788
630
 
@@ -805,7 +647,6 @@ function create_active_session_turn_state(
805
647
  result: null,
806
648
  deferred_finished: create_deferred<AgentSessionTurnResult>(),
807
649
  turn_context: null,
808
- history_reload_requested: false,
809
650
  prompt_started: false,
810
651
  };
811
652
  }
@@ -821,3 +662,59 @@ function create_turn_handle(
821
662
  finished: active_turn.deferred_finished.promise,
822
663
  };
823
664
  }
665
+
666
+ /** 幂等 Prompt 在 canonical history 中使用的稳定身份。 */
667
+ interface PromptRequestIdentity {
668
+ /** 稳定 User Message ID。 */
669
+ message_id: string;
670
+ /** 稳定 Turn ID。 */
671
+ turn_id: string;
672
+ }
673
+
674
+ /** 把调用方业务键映射为不暴露原值的 Session 内稳定身份。 */
675
+ function resolve_prompt_request_identity(
676
+ session_id: string,
677
+ request_id_input: string | undefined,
678
+ ): PromptRequestIdentity | null {
679
+ const request_id = String(request_id_input || "").trim();
680
+ if (!request_id) return null;
681
+ if (request_id.length > 512) {
682
+ throw new Error("session.prompt request_id must not exceed 512 characters");
683
+ }
684
+ const digest = createHash("sha256")
685
+ .update(session_id)
686
+ .update("\u0000")
687
+ .update(request_id)
688
+ .digest("hex");
689
+ return {
690
+ message_id: `user-request:${digest}`,
691
+ turn_id: `turn-request:${digest}`,
692
+ };
693
+ }
694
+
695
+ /** 从已完成的 canonical Agent Message 恢复 Turn 结果。 */
696
+ function to_persisted_turn_result(
697
+ turn_id: string,
698
+ message: SessionAgentMessage,
699
+ ): AgentSessionTurnResult {
700
+ const error_part = [...message.parts].reverse().find((part) => part.type === "error");
701
+ const error = error_part?.type === "error" ? error_part.message : undefined;
702
+ const success = !error;
703
+ return {
704
+ turn_id,
705
+ text: extract_session_message_text(message),
706
+ success,
707
+ ...(!success ? { error } : {}),
708
+ };
709
+ }
710
+
711
+ /** 为已经持久化完成的 Turn 创建立即兑现的句柄。 */
712
+ function create_completed_turn_handle(
713
+ result: AgentSessionTurnResult,
714
+ ): AgentSessionTurnHandle {
715
+ return {
716
+ id: result.turn_id,
717
+ result,
718
+ finished: Promise.resolve(result),
719
+ };
720
+ }