@downcity/agent 1.1.238 → 1.1.259

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 (578) hide show
  1. package/README.md +38 -45
  2. package/bin/agent/{local/Agent.d.ts → Agent.d.ts} +37 -27
  3. package/bin/agent/Agent.d.ts.map +1 -0
  4. package/bin/agent/Agent.js +211 -0
  5. package/bin/agent/Agent.js.map +1 -0
  6. package/bin/agent/AgentContext.d.ts +64 -0
  7. package/bin/agent/AgentContext.d.ts.map +1 -0
  8. package/bin/agent/AgentContext.js +53 -0
  9. package/bin/agent/AgentContext.js.map +1 -0
  10. package/bin/agent/{local/AgentInstructions.d.ts → AgentInstructions.d.ts} +1 -6
  11. package/bin/agent/AgentInstructions.d.ts.map +1 -0
  12. package/bin/agent/{local/AgentInstructions.js → AgentInstructions.js} +1 -10
  13. package/bin/agent/AgentInstructions.js.map +1 -0
  14. package/bin/{model/CityModelAdapter.d.ts → agent/AgentModel.d.ts} +3 -3
  15. package/bin/agent/AgentModel.d.ts.map +1 -0
  16. package/bin/{model/CityModelAdapter.js → agent/AgentModel.js} +11 -4
  17. package/bin/agent/AgentModel.js.map +1 -0
  18. package/bin/agent/{local/services/AgentSessions.d.ts → AgentSessions.d.ts} +30 -40
  19. package/bin/agent/AgentSessions.d.ts.map +1 -0
  20. package/bin/agent/{local/services/AgentSessions.js → AgentSessions.js} +62 -79
  21. package/bin/agent/AgentSessions.js.map +1 -0
  22. package/bin/agent/AgentState.d.ts +64 -0
  23. package/bin/agent/AgentState.d.ts.map +1 -0
  24. package/bin/agent/AgentState.js +118 -0
  25. package/bin/agent/AgentState.js.map +1 -0
  26. package/bin/config/Paths.d.ts +0 -43
  27. package/bin/config/Paths.d.ts.map +1 -1
  28. package/bin/config/Paths.js +0 -79
  29. package/bin/config/Paths.js.map +1 -1
  30. package/bin/config/ProjectSetup.d.ts.map +1 -0
  31. package/bin/{agent/local → config}/ProjectSetup.js +1 -1
  32. package/bin/config/ProjectSetup.js.map +1 -0
  33. package/bin/executor/Executor.d.ts +20 -86
  34. package/bin/executor/Executor.d.ts.map +1 -1
  35. package/bin/executor/Executor.js +109 -260
  36. package/bin/executor/Executor.js.map +1 -1
  37. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.d.ts +1 -1
  38. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.d.ts.map +1 -1
  39. package/bin/executor/composer/system/default/SystemDomain.d.ts +1 -1
  40. package/bin/executor/composer/system/default/SystemDomain.d.ts.map +1 -1
  41. package/bin/executor/composer/system/default/SystemDomain.js +4 -1
  42. package/bin/executor/composer/system/default/SystemDomain.js.map +1 -1
  43. package/bin/executor/composer/system/default/assets/core.prompt.d.ts +1 -1
  44. package/bin/executor/composer/system/default/assets/core.prompt.d.ts.map +1 -1
  45. package/bin/executor/composer/system/default/assets/core.prompt.js +1 -1
  46. package/bin/executor/composer/system/default/assets/core.prompt.js.map +1 -1
  47. package/bin/executor/core-engine/CoreEngineRunner.d.ts +7 -13
  48. package/bin/executor/core-engine/CoreEngineRunner.d.ts.map +1 -1
  49. package/bin/executor/core-engine/CoreEngineRunner.js +81 -34
  50. package/bin/executor/core-engine/CoreEngineRunner.js.map +1 -1
  51. package/bin/executor/services/ExecutorRecoveryPolicy.d.ts +6 -12
  52. package/bin/executor/services/ExecutorRecoveryPolicy.d.ts.map +1 -1
  53. package/bin/executor/services/ExecutorRecoveryPolicy.js +20 -6
  54. package/bin/executor/services/ExecutorRecoveryPolicy.js.map +1 -1
  55. package/bin/executor/tools/file/ReadImageToolBridge.d.ts +21 -0
  56. package/bin/executor/tools/file/ReadImageToolBridge.d.ts.map +1 -0
  57. package/bin/executor/tools/file/ReadImageToolBridge.js +69 -0
  58. package/bin/executor/tools/file/ReadImageToolBridge.js.map +1 -0
  59. package/bin/executor/tools/plugin/PluginToolBridge.d.ts.map +1 -1
  60. package/bin/executor/tools/plugin/PluginToolBridge.js +6 -5
  61. package/bin/executor/tools/plugin/PluginToolBridge.js.map +1 -1
  62. package/bin/executor/tools/plugin/PluginToolDefinition.d.ts.map +1 -1
  63. package/bin/executor/tools/plugin/PluginToolDefinition.js +15 -2
  64. package/bin/executor/tools/plugin/PluginToolDefinition.js.map +1 -1
  65. package/bin/executor/types/SessionHistoryMeta.d.ts +0 -2
  66. package/bin/executor/types/SessionHistoryMeta.d.ts.map +1 -1
  67. package/bin/index.d.ts +17 -21
  68. package/bin/index.d.ts.map +1 -1
  69. package/bin/index.js +9 -11
  70. package/bin/index.js.map +1 -1
  71. package/bin/plugin/core/ActionScheduleExecutor.d.ts +1 -1
  72. package/bin/plugin/core/ActionScheduleExecutor.d.ts.map +1 -1
  73. package/bin/plugin/core/ActionScheduleRuntime.d.ts +1 -1
  74. package/bin/plugin/core/ActionScheduleRuntime.d.ts.map +1 -1
  75. package/bin/plugin/core/BasePlugin.d.ts +4 -3
  76. package/bin/plugin/core/BasePlugin.d.ts.map +1 -1
  77. package/bin/plugin/core/BasePlugin.js.map +1 -1
  78. package/bin/plugin/core/HookRegistry.d.ts +5 -8
  79. package/bin/plugin/core/HookRegistry.d.ts.map +1 -1
  80. package/bin/plugin/core/HookRegistry.js +12 -12
  81. package/bin/plugin/core/HookRegistry.js.map +1 -1
  82. package/bin/plugin/core/PluginActionFactory.d.ts +6 -3
  83. package/bin/plugin/core/PluginActionFactory.d.ts.map +1 -1
  84. package/bin/plugin/core/PluginActionFactory.js.map +1 -1
  85. package/bin/plugin/core/PluginActionRunner.d.ts +1 -1
  86. package/bin/plugin/core/PluginActionRunner.d.ts.map +1 -1
  87. package/bin/plugin/core/PluginCatalog.d.ts +1 -1
  88. package/bin/plugin/core/PluginCatalog.d.ts.map +1 -1
  89. package/bin/plugin/core/PluginHttpRoutes.d.ts +1 -1
  90. package/bin/plugin/core/PluginHttpRoutes.d.ts.map +1 -1
  91. package/bin/plugin/core/PluginLocalExecution.d.ts +4 -5
  92. package/bin/plugin/core/PluginLocalExecution.d.ts.map +1 -1
  93. package/bin/plugin/core/PluginLocalExecution.js +4 -12
  94. package/bin/plugin/core/PluginLocalExecution.js.map +1 -1
  95. package/bin/plugin/core/PluginRegistry.d.ts +16 -12
  96. package/bin/plugin/core/PluginRegistry.d.ts.map +1 -1
  97. package/bin/plugin/core/PluginRegistry.js +43 -22
  98. package/bin/plugin/core/PluginRegistry.js.map +1 -1
  99. package/bin/plugin/core/PluginStateController.d.ts +1 -1
  100. package/bin/plugin/core/PluginStateController.d.ts.map +1 -1
  101. package/bin/{agent/remote → remote}/RemoteAgent.d.ts +4 -4
  102. package/bin/remote/RemoteAgent.d.ts.map +1 -0
  103. package/bin/{agent/remote → remote}/RemoteAgent.js +3 -3
  104. package/bin/remote/RemoteAgent.js.map +1 -0
  105. package/bin/{agent/remote → remote}/RemoteSession.d.ts +9 -11
  106. package/bin/remote/RemoteSession.d.ts.map +1 -0
  107. package/bin/{agent/remote → remote}/RemoteSession.js +3 -33
  108. package/bin/remote/RemoteSession.js.map +1 -0
  109. package/bin/{agent/remote → remote}/RemoteTransport.d.ts +7 -9
  110. package/bin/remote/RemoteTransport.d.ts.map +1 -0
  111. package/bin/remote/RemoteTransport.js.map +1 -0
  112. package/bin/{agent/remote → remote}/TransportFactory.d.ts +1 -1
  113. package/bin/remote/TransportFactory.d.ts.map +1 -0
  114. package/bin/{agent/remote → remote}/TransportFactory.js +2 -2
  115. package/bin/remote/TransportFactory.js.map +1 -0
  116. package/bin/{agent/remote → remote}/transports/HttpRemoteAgentTransport.d.ts +8 -9
  117. package/bin/remote/transports/HttpRemoteAgentTransport.d.ts.map +1 -0
  118. package/bin/{agent/remote → remote}/transports/HttpRemoteAgentTransport.js +0 -13
  119. package/bin/remote/transports/HttpRemoteAgentTransport.js.map +1 -0
  120. package/bin/{rpc/Client.d.ts → remote/transports/RpcClient.d.ts} +15 -22
  121. package/bin/remote/transports/RpcClient.d.ts.map +1 -0
  122. package/bin/{rpc/Client.js → remote/transports/RpcClient.js} +2 -13
  123. package/bin/remote/transports/RpcClient.js.map +1 -0
  124. package/bin/{agent/remote → remote}/transports/RpcRemoteAgentTransport.d.ts +8 -9
  125. package/bin/remote/transports/RpcRemoteAgentTransport.d.ts.map +1 -0
  126. package/bin/{agent/remote → remote}/transports/RpcRemoteAgentTransport.js +1 -4
  127. package/bin/remote/transports/RpcRemoteAgentTransport.js.map +1 -0
  128. package/bin/session/DefaultSessionComposer.d.ts +18 -0
  129. package/bin/session/DefaultSessionComposer.d.ts.map +1 -0
  130. package/bin/session/DefaultSessionComposer.js +62 -0
  131. package/bin/session/DefaultSessionComposer.js.map +1 -0
  132. package/bin/session/Session.d.ts +44 -33
  133. package/bin/session/Session.d.ts.map +1 -1
  134. package/bin/session/Session.js +440 -274
  135. package/bin/session/Session.js.map +1 -1
  136. package/bin/session/SessionMessages.d.ts +133 -0
  137. package/bin/session/SessionMessages.d.ts.map +1 -0
  138. package/bin/session/{recorder/SessionRecorder.js → SessionMessages.js} +247 -284
  139. package/bin/session/SessionMessages.js.map +1 -0
  140. package/bin/session/SessionQueue.d.ts +34 -0
  141. package/bin/session/SessionQueue.d.ts.map +1 -0
  142. package/bin/session/SessionQueue.js +60 -0
  143. package/bin/session/SessionQueue.js.map +1 -0
  144. package/bin/session/SessionState.d.ts +70 -0
  145. package/bin/session/SessionState.d.ts.map +1 -0
  146. package/bin/session/SessionState.js +267 -0
  147. package/bin/session/SessionState.js.map +1 -0
  148. package/bin/session/SessionSystem.d.ts +15 -0
  149. package/bin/session/SessionSystem.d.ts.map +1 -0
  150. package/bin/session/SessionSystem.js +95 -0
  151. package/bin/session/SessionSystem.js.map +1 -0
  152. package/bin/session/SessionTurn.d.ts +84 -0
  153. package/bin/session/SessionTurn.d.ts.map +1 -0
  154. package/bin/session/SessionTurn.js +588 -0
  155. package/bin/session/SessionTurn.js.map +1 -0
  156. package/bin/session/approval/SessionApprovalBroker.d.ts +48 -0
  157. package/bin/session/approval/SessionApprovalBroker.d.ts.map +1 -0
  158. package/bin/session/approval/SessionApprovalBroker.js +126 -0
  159. package/bin/session/approval/SessionApprovalBroker.js.map +1 -0
  160. package/bin/session/browse/Browse.d.ts.map +1 -1
  161. package/bin/session/browse/Browse.js +1 -4
  162. package/bin/session/browse/Browse.js.map +1 -1
  163. package/bin/session/{recorder → messages}/JsonlSessionMessageStore.d.ts.map +1 -1
  164. package/bin/session/{recorder → messages}/JsonlSessionMessageStore.js.map +1 -1
  165. package/bin/session/messages/SessionAssistantMessageWriter.d.ts +62 -0
  166. package/bin/session/messages/SessionAssistantMessageWriter.d.ts.map +1 -0
  167. package/bin/session/messages/SessionAssistantMessageWriter.js +287 -0
  168. package/bin/session/messages/SessionAssistantMessageWriter.js.map +1 -0
  169. package/bin/session/messages/SessionJsonValue.d.ts +10 -0
  170. package/bin/session/messages/SessionJsonValue.d.ts.map +1 -0
  171. package/bin/session/messages/SessionJsonValue.js +23 -0
  172. package/bin/session/messages/SessionJsonValue.js.map +1 -0
  173. package/bin/session/{recorder → messages}/SessionMessageCodec.d.ts +4 -1
  174. package/bin/session/messages/SessionMessageCodec.d.ts.map +1 -0
  175. package/bin/session/{recorder → messages}/SessionMessageCodec.js +33 -19
  176. package/bin/session/messages/SessionMessageCodec.js.map +1 -0
  177. package/bin/session/messages/SessionMessageCompaction.d.ts +22 -0
  178. package/bin/session/messages/SessionMessageCompaction.d.ts.map +1 -0
  179. package/bin/session/{recorder/SessionRecorderCompaction.js → messages/SessionMessageCompaction.js} +19 -51
  180. package/bin/session/messages/SessionMessageCompaction.js.map +1 -0
  181. package/bin/session/runtime/SessionEventHub.d.ts +1 -8
  182. package/bin/session/runtime/SessionEventHub.d.ts.map +1 -1
  183. package/bin/session/runtime/SessionEventHub.js +1 -6
  184. package/bin/session/runtime/SessionEventHub.js.map +1 -1
  185. package/bin/session/storage/Metadata.d.ts +23 -5
  186. package/bin/session/storage/Metadata.d.ts.map +1 -1
  187. package/bin/session/storage/Metadata.js +32 -29
  188. package/bin/session/storage/Metadata.js.map +1 -1
  189. package/bin/session/storage/RuntimeSessionPort.d.ts +5 -10
  190. package/bin/session/storage/RuntimeSessionPort.d.ts.map +1 -1
  191. package/bin/session/storage/RuntimeSessionPort.js +2 -4
  192. package/bin/session/storage/RuntimeSessionPort.js.map +1 -1
  193. package/bin/types/agent/AgentOptions.d.ts +6 -35
  194. package/bin/types/agent/AgentOptions.d.ts.map +1 -1
  195. package/bin/types/agent/AgentState.d.ts +28 -0
  196. package/bin/types/agent/AgentState.d.ts.map +1 -0
  197. package/bin/types/agent/AgentState.js +9 -0
  198. package/bin/types/agent/AgentState.js.map +1 -0
  199. package/bin/types/agent/SessionActor.d.ts +0 -2
  200. package/bin/types/agent/SessionActor.d.ts.map +1 -1
  201. package/bin/types/agent/SessionTypes.d.ts +5 -18
  202. package/bin/types/agent/SessionTypes.d.ts.map +1 -1
  203. package/bin/types/executor/SessionRunContext.d.ts +8 -2
  204. package/bin/types/executor/SessionRunContext.d.ts.map +1 -1
  205. package/bin/types/executor/SessionRunContext.js +1 -1
  206. package/bin/types/executor/SessionToolExecutionContext.d.ts +20 -0
  207. package/bin/types/executor/SessionToolExecutionContext.d.ts.map +1 -0
  208. package/bin/types/executor/SessionToolExecutionContext.js +10 -0
  209. package/bin/types/executor/SessionToolExecutionContext.js.map +1 -0
  210. package/bin/types/plugin/PluginAction.d.ts +10 -1
  211. package/bin/types/plugin/PluginAction.d.ts.map +1 -1
  212. package/bin/types/plugin/PluginCommand.d.ts +3 -11
  213. package/bin/types/plugin/PluginCommand.d.ts.map +1 -1
  214. package/bin/types/plugin/PluginConfig.d.ts +12 -0
  215. package/bin/types/plugin/PluginConfig.d.ts.map +1 -0
  216. package/bin/types/plugin/PluginConfig.js +5 -0
  217. package/bin/types/plugin/PluginConfig.js.map +1 -0
  218. package/bin/types/plugin/PluginDefinition.d.ts +10 -3
  219. package/bin/types/plugin/PluginDefinition.d.ts.map +1 -1
  220. package/bin/types/plugin/PluginHttp.d.ts +1 -1
  221. package/bin/types/plugin/PluginHttp.d.ts.map +1 -1
  222. package/bin/types/plugin/PluginRunContext.d.ts +26 -0
  223. package/bin/types/plugin/PluginRunContext.d.ts.map +1 -0
  224. package/bin/types/plugin/PluginRunContext.js +10 -0
  225. package/bin/types/plugin/PluginRunContext.js.map +1 -0
  226. package/bin/types/plugin/PluginRuntime.d.ts +9 -3
  227. package/bin/types/plugin/PluginRuntime.d.ts.map +1 -1
  228. package/bin/types/plugin/PluginToolRuntime.d.ts +11 -0
  229. package/bin/types/plugin/PluginToolRuntime.d.ts.map +1 -1
  230. package/bin/types/rpc/RpcProtocol.d.ts +1 -13
  231. package/bin/types/rpc/RpcProtocol.d.ts.map +1 -1
  232. package/bin/types/session/SessionApproval.d.ts +4 -38
  233. package/bin/types/session/SessionApproval.d.ts.map +1 -1
  234. package/bin/types/session/SessionApprovalBroker.d.ts +17 -0
  235. package/bin/types/session/SessionApprovalBroker.d.ts.map +1 -0
  236. package/bin/types/session/SessionApprovalBroker.js +7 -0
  237. package/bin/types/session/SessionApprovalBroker.js.map +1 -0
  238. package/bin/types/session/SessionComposer.d.ts +99 -0
  239. package/bin/types/session/SessionComposer.d.ts.map +1 -0
  240. package/bin/types/session/SessionComposer.js +8 -0
  241. package/bin/types/session/SessionComposer.js.map +1 -0
  242. package/bin/types/session/SessionLocalState.d.ts +6 -6
  243. package/bin/types/session/SessionLocalState.d.ts.map +1 -1
  244. package/bin/types/session/SessionLocalState.js +1 -1
  245. package/bin/types/session/SessionMessage.d.ts +3 -2
  246. package/bin/types/session/SessionMessage.d.ts.map +1 -1
  247. package/bin/types/session/SessionMessages.d.ts +115 -0
  248. package/bin/types/session/SessionMessages.d.ts.map +1 -0
  249. package/bin/types/session/SessionMessages.js +7 -0
  250. package/bin/types/session/SessionMessages.js.map +1 -0
  251. package/bin/types/session/SessionMutation.d.ts +1 -10
  252. package/bin/types/session/SessionMutation.d.ts.map +1 -1
  253. package/bin/types/session/SessionMutation.js.map +1 -1
  254. package/bin/types/session/SessionOptions.d.ts +8 -23
  255. package/bin/types/session/SessionOptions.d.ts.map +1 -1
  256. package/bin/types/session/SessionPort.d.ts +72 -0
  257. package/bin/types/session/SessionPort.d.ts.map +1 -0
  258. package/bin/types/session/SessionPort.js +9 -0
  259. package/bin/types/session/SessionPort.js.map +1 -0
  260. package/bin/types/session/SessionQueue.d.ts +104 -0
  261. package/bin/types/session/SessionQueue.d.ts.map +1 -0
  262. package/bin/types/session/SessionQueue.js +7 -0
  263. package/bin/types/session/SessionQueue.js.map +1 -0
  264. package/bin/types/session/SessionState.d.ts +43 -0
  265. package/bin/types/session/SessionState.d.ts.map +1 -0
  266. package/bin/types/session/SessionState.js +7 -0
  267. package/bin/types/session/SessionState.js.map +1 -0
  268. package/bin/types/session/SessionSystem.d.ts +26 -0
  269. package/bin/types/session/SessionSystem.d.ts.map +1 -0
  270. package/bin/types/session/SessionSystem.js +7 -0
  271. package/bin/types/session/SessionSystem.js.map +1 -0
  272. package/bin/types/session/SessionTool.d.ts +23 -0
  273. package/bin/types/session/SessionTool.d.ts.map +1 -0
  274. package/bin/types/session/SessionTool.js +7 -0
  275. package/bin/types/session/SessionTool.js.map +1 -0
  276. package/bin/types/session/SessionTurn.d.ts +52 -0
  277. package/bin/types/session/SessionTurn.d.ts.map +1 -0
  278. package/bin/types/session/SessionTurn.js +7 -0
  279. package/bin/types/session/SessionTurn.js.map +1 -0
  280. package/package.json +3 -3
  281. package/scripts/agent-env.test.mjs +4 -18
  282. package/scripts/agent-ready.test.mjs +33 -2
  283. package/scripts/agent-session-maintenance.test.mjs +52 -0
  284. package/scripts/city-model-tool-loop.test.mjs +3 -4
  285. package/scripts/core-engine-context-compaction.test.mjs +5 -22
  286. package/scripts/image-plugin-job.test.mjs +4 -6
  287. package/scripts/plugin-tool-bridge.test.mjs +44 -36
  288. package/scripts/read-image-tool-bridge.test.mjs +71 -0
  289. package/scripts/remote-session-reconnect.test.mjs +1 -34
  290. package/scripts/session-compaction-prompts.test.mjs +1 -49
  291. package/scripts/session-composer.test.mjs +163 -0
  292. package/scripts/session-config-turn-boundary.test.mjs +2 -5
  293. package/scripts/session-list-title.test.mjs +3 -2
  294. package/scripts/session-messages-error.test.mjs +57 -0
  295. package/scripts/{session-recorder.test.mjs → session-messages.test.mjs} +245 -93
  296. package/scripts/session-queue.test.mjs +64 -0
  297. package/scripts/session-shell-approval.test.mjs +171 -0
  298. package/scripts/session-system-blocks.test.mjs +10 -10
  299. package/scripts/session-title-event.test.mjs +1 -0
  300. package/src/agent/Agent.ts +241 -0
  301. package/src/agent/AgentContext.ts +92 -0
  302. package/src/agent/{local/AgentInstructions.ts → AgentInstructions.ts} +0 -11
  303. package/src/{model/CityModelAdapter.ts → agent/AgentModel.ts} +10 -3
  304. package/src/agent/{local/services/AgentSessions.ts → AgentSessions.ts} +81 -110
  305. package/src/agent/AgentState.ts +151 -0
  306. package/src/config/Paths.ts +0 -91
  307. package/src/executor/Executor.ts +180 -386
  308. package/src/executor/README.md +62 -86
  309. package/src/executor/composer/system/default/DefaultSessionSystemComposer.ts +1 -1
  310. package/src/executor/composer/system/default/SystemDomain.ts +4 -2
  311. package/src/executor/composer/system/default/assets/core.prompt.ts +1 -1
  312. package/src/executor/composer/system/default/assets/core.prompt.ts.txt +15 -2
  313. package/src/executor/core-engine/CoreEngineRunner.ts +95 -54
  314. package/src/executor/services/ExecutorRecoveryPolicy.ts +24 -19
  315. package/src/executor/tools/file/ReadImageToolBridge.ts +79 -0
  316. package/src/executor/tools/plugin/PluginToolBridge.ts +6 -8
  317. package/src/executor/tools/plugin/PluginToolDefinition.ts +23 -3
  318. package/src/executor/types/SessionHistoryMeta.ts +0 -2
  319. package/src/index.ts +34 -53
  320. package/src/plugin/core/ActionScheduleExecutor.ts +1 -1
  321. package/src/plugin/core/ActionScheduleRuntime.ts +1 -1
  322. package/src/plugin/core/BasePlugin.ts +7 -3
  323. package/src/plugin/core/HookRegistry.ts +15 -18
  324. package/src/plugin/core/PluginActionFactory.ts +9 -3
  325. package/src/plugin/core/PluginActionRunner.ts +1 -1
  326. package/src/plugin/core/PluginCatalog.ts +1 -1
  327. package/src/plugin/core/PluginHttpRoutes.ts +1 -1
  328. package/src/plugin/core/PluginLocalExecution.ts +11 -24
  329. package/src/plugin/core/PluginRegistry.ts +55 -32
  330. package/src/plugin/core/PluginStateController.ts +1 -1
  331. package/src/{agent/remote → remote}/RemoteAgent.ts +4 -4
  332. package/src/{agent/remote → remote}/RemoteSession.ts +2 -35
  333. package/src/{agent/remote → remote}/RemoteTransport.ts +0 -3
  334. package/src/{agent/remote → remote}/TransportFactory.ts +3 -3
  335. package/src/{agent/remote → remote}/transports/HttpRemoteAgentTransport.ts +1 -23
  336. package/src/{rpc/Client.ts → remote/transports/RpcClient.ts} +1 -19
  337. package/src/{agent/remote → remote}/transports/RpcRemoteAgentTransport.ts +2 -10
  338. package/src/session/DefaultSessionComposer.ts +79 -0
  339. package/src/session/Session.ts +496 -332
  340. package/src/session/{recorder/SessionRecorder.ts → SessionMessages.ts} +324 -428
  341. package/src/session/SessionQueue.ts +86 -0
  342. package/src/session/SessionState.ts +322 -0
  343. package/src/session/SessionSystem.ts +117 -0
  344. package/src/session/SessionTurn.ts +684 -0
  345. package/src/session/approval/SessionApprovalBroker.ts +164 -0
  346. package/src/session/browse/Browse.ts +1 -4
  347. package/src/session/messages/SessionAssistantMessageWriter.ts +345 -0
  348. package/src/session/messages/SessionJsonValue.ts +25 -0
  349. package/src/session/{recorder → messages}/SessionMessageCodec.ts +38 -20
  350. package/src/session/{recorder/SessionRecorderCompaction.ts → messages/SessionMessageCompaction.ts} +30 -69
  351. package/src/session/runtime/SessionEventHub.ts +1 -14
  352. package/src/session/storage/Metadata.ts +60 -34
  353. package/src/session/storage/RuntimeSessionPort.ts +7 -14
  354. package/src/types/agent/AgentOptions.ts +6 -38
  355. package/src/types/agent/AgentState.ts +33 -0
  356. package/src/types/agent/SessionActor.ts +0 -3
  357. package/src/types/agent/SessionTypes.ts +5 -18
  358. package/src/types/executor/SessionRunContext.ts +10 -2
  359. package/src/types/executor/SessionToolExecutionContext.ts +21 -0
  360. package/src/types/plugin/PluginAction.ts +10 -1
  361. package/src/types/plugin/PluginCommand.ts +3 -14
  362. package/src/types/plugin/PluginConfig.ts +13 -0
  363. package/src/types/plugin/PluginDefinition.ts +13 -6
  364. package/src/types/plugin/PluginHttp.ts +1 -1
  365. package/src/types/plugin/PluginRunContext.ts +31 -0
  366. package/src/types/plugin/PluginRuntime.ts +13 -6
  367. package/src/types/plugin/PluginToolRuntime.ts +13 -1
  368. package/src/types/rpc/RpcProtocol.ts +0 -14
  369. package/src/types/session/SessionApproval.ts +4 -43
  370. package/src/types/session/SessionApprovalBroker.ts +18 -0
  371. package/src/types/session/SessionComposer.ts +114 -0
  372. package/src/types/session/SessionLocalState.ts +6 -6
  373. package/src/types/session/SessionMessage.ts +3 -2
  374. package/src/types/session/SessionMessages.ts +127 -0
  375. package/src/types/session/SessionMutation.ts +0 -11
  376. package/src/types/session/SessionOptions.ts +8 -40
  377. package/src/types/session/SessionPort.ts +97 -0
  378. package/src/types/session/SessionQueue.ts +122 -0
  379. package/src/types/session/SessionState.ts +47 -0
  380. package/src/types/session/SessionSystem.ts +27 -0
  381. package/src/types/session/SessionTool.ts +25 -0
  382. package/src/types/session/SessionTurn.ts +56 -0
  383. package/tsconfig.tsbuildinfo +1 -1
  384. package/bin/agent/local/Agent.d.ts.map +0 -1
  385. package/bin/agent/local/Agent.js +0 -216
  386. package/bin/agent/local/Agent.js.map +0 -1
  387. package/bin/agent/local/AgentInstructions.d.ts.map +0 -1
  388. package/bin/agent/local/AgentInstructions.js.map +0 -1
  389. package/bin/agent/local/AgentPluginFactory.d.ts +0 -26
  390. package/bin/agent/local/AgentPluginFactory.d.ts.map +0 -1
  391. package/bin/agent/local/AgentPluginFactory.js +0 -33
  392. package/bin/agent/local/AgentPluginFactory.js.map +0 -1
  393. package/bin/agent/local/AgentRuntimeAssembly.d.ts +0 -10
  394. package/bin/agent/local/AgentRuntimeAssembly.d.ts.map +0 -1
  395. package/bin/agent/local/AgentRuntimeAssembly.js +0 -43
  396. package/bin/agent/local/AgentRuntimeAssembly.js.map +0 -1
  397. package/bin/agent/local/ProjectSetup.d.ts.map +0 -1
  398. package/bin/agent/local/ProjectSetup.js.map +0 -1
  399. package/bin/agent/local/services/AgentAssemblyService.d.ts +0 -105
  400. package/bin/agent/local/services/AgentAssemblyService.d.ts.map +0 -1
  401. package/bin/agent/local/services/AgentAssemblyService.js +0 -184
  402. package/bin/agent/local/services/AgentAssemblyService.js.map +0 -1
  403. package/bin/agent/local/services/AgentBackgroundService.d.ts +0 -55
  404. package/bin/agent/local/services/AgentBackgroundService.d.ts.map +0 -1
  405. package/bin/agent/local/services/AgentBackgroundService.js +0 -85
  406. package/bin/agent/local/services/AgentBackgroundService.js.map +0 -1
  407. package/bin/agent/local/services/AgentSessions.d.ts.map +0 -1
  408. package/bin/agent/local/services/AgentSessions.js.map +0 -1
  409. package/bin/agent/remote/RemoteAgent.d.ts.map +0 -1
  410. package/bin/agent/remote/RemoteAgent.js.map +0 -1
  411. package/bin/agent/remote/RemoteSession.d.ts.map +0 -1
  412. package/bin/agent/remote/RemoteSession.js.map +0 -1
  413. package/bin/agent/remote/RemoteTransport.d.ts.map +0 -1
  414. package/bin/agent/remote/RemoteTransport.js.map +0 -1
  415. package/bin/agent/remote/TransportFactory.d.ts.map +0 -1
  416. package/bin/agent/remote/TransportFactory.js.map +0 -1
  417. package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts.map +0 -1
  418. package/bin/agent/remote/transports/HttpRemoteAgentTransport.js.map +0 -1
  419. package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts.map +0 -1
  420. package/bin/agent/remote/transports/RpcRemoteAgentTransport.js.map +0 -1
  421. package/bin/executor/SessionRunScope.d.ts +0 -68
  422. package/bin/executor/SessionRunScope.d.ts.map +0 -1
  423. package/bin/executor/SessionRunScope.js +0 -96
  424. package/bin/executor/SessionRunScope.js.map +0 -1
  425. package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts +0 -74
  426. package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts.map +0 -1
  427. package/bin/executor/composer/compaction/SessionCompactionComposer.js +0 -9
  428. package/bin/executor/composer/compaction/SessionCompactionComposer.js.map +0 -1
  429. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.d.ts +0 -27
  430. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.d.ts.map +0 -1
  431. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js +0 -39
  432. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js.map +0 -1
  433. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts +0 -44
  434. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts.map +0 -1
  435. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js +0 -218
  436. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js.map +0 -1
  437. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionFileOperations.d.ts +0 -27
  438. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionFileOperations.d.ts.map +0 -1
  439. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionFileOperations.js +0 -181
  440. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionFileOperations.js.map +0 -1
  441. package/bin/executor/composer/context/LocalSessionContextComposer.d.ts +0 -50
  442. package/bin/executor/composer/context/LocalSessionContextComposer.d.ts.map +0 -1
  443. package/bin/executor/composer/context/LocalSessionContextComposer.js +0 -108
  444. package/bin/executor/composer/context/LocalSessionContextComposer.js.map +0 -1
  445. package/bin/executor/composer/context/SessionContextComposer.d.ts +0 -67
  446. package/bin/executor/composer/context/SessionContextComposer.d.ts.map +0 -1
  447. package/bin/executor/composer/context/SessionContextComposer.js +0 -9
  448. package/bin/executor/composer/context/SessionContextComposer.js.map +0 -1
  449. package/bin/executor/composer/history/SessionHistoryComposer.d.ts +0 -54
  450. package/bin/executor/composer/history/SessionHistoryComposer.d.ts.map +0 -1
  451. package/bin/executor/composer/history/SessionHistoryComposer.js +0 -10
  452. package/bin/executor/composer/history/SessionHistoryComposer.js.map +0 -1
  453. package/bin/executor/composer/history/SessionHistoryWriter.d.ts +0 -46
  454. package/bin/executor/composer/history/SessionHistoryWriter.d.ts.map +0 -1
  455. package/bin/executor/composer/history/SessionHistoryWriter.js +0 -65
  456. package/bin/executor/composer/history/SessionHistoryWriter.js.map +0 -1
  457. package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.d.ts +0 -35
  458. package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.d.ts.map +0 -1
  459. package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.js +0 -105
  460. package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.js.map +0 -1
  461. package/bin/executor/messages/AssistantResultPersistence.d.ts +0 -66
  462. package/bin/executor/messages/AssistantResultPersistence.d.ts.map +0 -1
  463. package/bin/executor/messages/AssistantResultPersistence.js +0 -44
  464. package/bin/executor/messages/AssistantResultPersistence.js.map +0 -1
  465. package/bin/executor/services/ExecutorInflightService.d.ts +0 -34
  466. package/bin/executor/services/ExecutorInflightService.d.ts.map +0 -1
  467. package/bin/executor/services/ExecutorInflightService.js +0 -73
  468. package/bin/executor/services/ExecutorInflightService.js.map +0 -1
  469. package/bin/executor/store/history/SessionHistoryStore.d.ts +0 -140
  470. package/bin/executor/store/history/SessionHistoryStore.d.ts.map +0 -1
  471. package/bin/executor/store/history/SessionHistoryStore.js +0 -10
  472. package/bin/executor/store/history/SessionHistoryStore.js.map +0 -1
  473. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts +0 -116
  474. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts.map +0 -1
  475. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +0 -709
  476. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +0 -1
  477. package/bin/executor/types/SessionHistoryPaths.d.ts +0 -34
  478. package/bin/executor/types/SessionHistoryPaths.d.ts.map +0 -1
  479. package/bin/executor/types/SessionHistoryPaths.js +0 -2
  480. package/bin/executor/types/SessionHistoryPaths.js.map +0 -1
  481. package/bin/model/CityModelAdapter.d.ts.map +0 -1
  482. package/bin/model/CityModelAdapter.js.map +0 -1
  483. package/bin/rpc/Client.d.ts.map +0 -1
  484. package/bin/rpc/Client.js.map +0 -1
  485. package/bin/session/SessionSystemBuilder.d.ts +0 -107
  486. package/bin/session/SessionSystemBuilder.d.ts.map +0 -1
  487. package/bin/session/SessionSystemBuilder.js +0 -148
  488. package/bin/session/SessionSystemBuilder.js.map +0 -1
  489. package/bin/session/recorder/SessionMessageCodec.d.ts.map +0 -1
  490. package/bin/session/recorder/SessionMessageCodec.js.map +0 -1
  491. package/bin/session/recorder/SessionRecorder.d.ts +0 -217
  492. package/bin/session/recorder/SessionRecorder.d.ts.map +0 -1
  493. package/bin/session/recorder/SessionRecorder.js.map +0 -1
  494. package/bin/session/recorder/SessionRecorderCompaction.d.ts +0 -18
  495. package/bin/session/recorder/SessionRecorderCompaction.d.ts.map +0 -1
  496. package/bin/session/recorder/SessionRecorderCompaction.js.map +0 -1
  497. package/bin/session/recorder/SessionRecorderHistoryStore.d.ts +0 -66
  498. package/bin/session/recorder/SessionRecorderHistoryStore.d.ts.map +0 -1
  499. package/bin/session/recorder/SessionRecorderHistoryStore.js +0 -190
  500. package/bin/session/recorder/SessionRecorderHistoryStore.js.map +0 -1
  501. package/bin/session/runtime/SessionPromptRuntime.d.ts +0 -112
  502. package/bin/session/runtime/SessionPromptRuntime.d.ts.map +0 -1
  503. package/bin/session/runtime/SessionPromptRuntime.js +0 -357
  504. package/bin/session/runtime/SessionPromptRuntime.js.map +0 -1
  505. package/bin/session/services/SessionStateService.d.ts +0 -187
  506. package/bin/session/services/SessionStateService.d.ts.map +0 -1
  507. package/bin/session/services/SessionStateService.js +0 -467
  508. package/bin/session/services/SessionStateService.js.map +0 -1
  509. package/bin/session/services/SessionTurnService.d.ts +0 -90
  510. package/bin/session/services/SessionTurnService.d.ts.map +0 -1
  511. package/bin/session/services/SessionTurnService.js +0 -293
  512. package/bin/session/services/SessionTurnService.js.map +0 -1
  513. package/bin/session/services/SessionViewService.d.ts +0 -114
  514. package/bin/session/services/SessionViewService.d.ts.map +0 -1
  515. package/bin/session/services/SessionViewService.js +0 -204
  516. package/bin/session/services/SessionViewService.js.map +0 -1
  517. package/bin/session/storage/Persistence.d.ts +0 -73
  518. package/bin/session/storage/Persistence.d.ts.map +0 -1
  519. package/bin/session/storage/Persistence.js +0 -63
  520. package/bin/session/storage/Persistence.js.map +0 -1
  521. package/bin/types/agent/AgentRuntimeAssembly.d.ts +0 -72
  522. package/bin/types/agent/AgentRuntimeAssembly.d.ts.map +0 -1
  523. package/bin/types/agent/AgentRuntimeAssembly.js +0 -10
  524. package/bin/types/agent/AgentRuntimeAssembly.js.map +0 -1
  525. package/bin/types/runtime/agent/AgentContext.d.ts +0 -306
  526. package/bin/types/runtime/agent/AgentContext.d.ts.map +0 -1
  527. package/bin/types/runtime/agent/AgentContext.js +0 -128
  528. package/bin/types/runtime/agent/AgentContext.js.map +0 -1
  529. package/bin/types/session/SessionComposerOptions.d.ts +0 -90
  530. package/bin/types/session/SessionComposerOptions.d.ts.map +0 -1
  531. package/bin/types/session/SessionComposerOptions.js +0 -10
  532. package/bin/types/session/SessionComposerOptions.js.map +0 -1
  533. package/bin/types/session/SessionQueueCommand.d.ts +0 -68
  534. package/bin/types/session/SessionQueueCommand.d.ts.map +0 -1
  535. package/bin/types/session/SessionQueueCommand.js +0 -10
  536. package/bin/types/session/SessionQueueCommand.js.map +0 -1
  537. package/scripts/session-action-message.test.mjs +0 -410
  538. package/scripts/session-compaction-context-window.test.mjs +0 -96
  539. package/scripts/session-history-inflight.test.mjs +0 -146
  540. package/scripts/session-history-writer-error.test.mjs +0 -57
  541. package/scripts/session-prompt-runtime.test.mjs +0 -390
  542. package/src/agent/local/Agent.ts +0 -250
  543. package/src/agent/local/AgentPluginFactory.ts +0 -51
  544. package/src/agent/local/AgentRuntimeAssembly.ts +0 -65
  545. package/src/agent/local/services/AgentAssemblyService.ts +0 -307
  546. package/src/agent/local/services/AgentBackgroundService.ts +0 -115
  547. package/src/executor/SessionRunScope.ts +0 -122
  548. package/src/executor/composer/compaction/SessionCompactionComposer.ts +0 -84
  549. package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.ts +0 -51
  550. package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.ts +0 -294
  551. package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionFileOperations.ts +0 -197
  552. package/src/executor/composer/context/LocalSessionContextComposer.ts +0 -175
  553. package/src/executor/composer/context/SessionContextComposer.ts +0 -83
  554. package/src/executor/composer/history/SessionHistoryComposer.ts +0 -62
  555. package/src/executor/composer/history/SessionHistoryWriter.ts +0 -100
  556. package/src/executor/composer/history/jsonl/JsonlSessionHistoryComposer.ts +0 -133
  557. package/src/executor/messages/AssistantResultPersistence.ts +0 -106
  558. package/src/executor/services/ExecutorInflightService.ts +0 -95
  559. package/src/executor/store/history/SessionHistoryStore.ts +0 -172
  560. package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +0 -879
  561. package/src/executor/types/SessionHistoryPaths.ts +0 -38
  562. package/src/session/SessionSystemBuilder.ts +0 -262
  563. package/src/session/recorder/SessionRecorderHistoryStore.ts +0 -256
  564. package/src/session/runtime/SessionPromptRuntime.ts +0 -518
  565. package/src/session/services/SessionStateService.ts +0 -628
  566. package/src/session/services/SessionTurnService.ts +0 -368
  567. package/src/session/services/SessionViewService.ts +0 -335
  568. package/src/session/storage/Persistence.ts +0 -137
  569. package/src/types/agent/AgentRuntimeAssembly.ts +0 -74
  570. package/src/types/runtime/agent/AgentContext.ts +0 -387
  571. package/src/types/session/SessionComposerOptions.ts +0 -107
  572. package/src/types/session/SessionQueueCommand.ts +0 -78
  573. /package/bin/{agent/local → config}/ProjectSetup.d.ts +0 -0
  574. /package/bin/{agent/remote → remote}/RemoteTransport.js +0 -0
  575. /package/bin/session/{recorder → messages}/JsonlSessionMessageStore.d.ts +0 -0
  576. /package/bin/session/{recorder → messages}/JsonlSessionMessageStore.js +0 -0
  577. /package/src/{agent/local → config}/ProjectSetup.ts +0 -0
  578. /package/src/session/{recorder → messages}/JsonlSessionMessageStore.ts +0 -0
@@ -1,17 +1,20 @@
1
1
  /**
2
- * SessionRecorder:Session Message 的唯一持久化与发布入口。
2
+ * SessionMessages:Session Message 的唯一领域入口。
3
3
  *
4
4
  * 完整 Message 与 Assistant 草稿先持久化,成功后再发布实时 Mutation。
5
+ * 同一 Assistant Message 的流式、审批与关闭操作共享一条写队列,保证 revision
6
+ * 从最新快照严格递增。
5
7
  */
6
8
 
7
- import type { UIMessage, UIMessageChunk } from "ai";
9
+ import type { UIMessage } from "ai";
8
10
  import { generateId } from "@/utils/Id.js";
9
- import { JsonlSessionMessageStore } from "@/session/recorder/JsonlSessionMessageStore.js";
10
- import type { JsonObject, JsonValue } from "@/types/common/Json.js";
11
+ import { SessionAssistantMessageWriter } from "@/session/messages/SessionAssistantMessageWriter.js";
12
+ import { to_session_json_value } from "@/session/messages/SessionJsonValue.js";
13
+ import { JsonlSessionMessageStore } from "@/session/messages/JsonlSessionMessageStore.js";
14
+ import type { JsonObject } from "@/types/common/Json.js";
11
15
  import type {
12
16
  ListSessionMessagesInput,
13
17
  SessionActionMessage,
14
- SessionAssistantFilePart,
15
18
  SessionAssistantMessage,
16
19
  SessionAssistantMessagePart,
17
20
  SessionAssistantToolPart,
@@ -30,104 +33,49 @@ import type {
30
33
  SessionMessageStorageStats,
31
34
  SessionSegmentSummary,
32
35
  } from "@/types/session/SessionSegment.js";
33
-
34
- /** SessionRecorder 构造参数。 */
35
- export interface SessionRecorderOptions {
36
- /** 当前 Session 标识。 */
37
- session_id: string;
38
- /** Message 快照 store。 */
39
- store: JsonlSessionMessageStore;
40
- /** 持久化成功后的实时 Mutation 发布函数。 */
41
- publish: (mutation: SessionMutation) => void;
42
- }
43
-
44
- /** User Message 创建参数。 */
45
- export interface AppendSessionUserMessageInput {
46
- /** 当前输入所属 turn。 */
47
- turn_id: string;
48
- /** 普通 prompt 或 steering 输入。 */
49
- input_type: "prompt" | "steer";
50
- /** User 结构化 parts。 */
51
- parts: SessionUserMessagePart[];
52
- /** 可选指定 Message ID,通常由 Recorder 生成。 */
53
- message_id?: string;
54
- /** 默认展示范围。 */
55
- visibility?: "visible" | "internal";
56
- }
57
-
58
- /** Assistant Message 创建参数。 */
59
- export interface OpenSessionAssistantMessageInput {
60
- /** 当前 assistant 所属 turn。 */
61
- turn_id: string;
62
- /** 当前 assistant 在 turn 内的 segment 序号。 */
63
- segment_index: number;
64
- /** 普通 assistant 或 compact summary。 */
65
- kind?: "normal" | "summary";
66
- /** 默认展示范围。 */
67
- visibility?: "visible" | "internal";
68
- /** 可选指定 Message ID。 */
69
- message_id?: string;
70
- /** Summary 已覆盖到的来源 Message。 */
71
- summary_through_message_id?: string;
72
- }
73
-
74
- /** 已完成 Assistant Message 直接写入参数。 */
75
- export interface AppendCompletedAssistantMessageInput {
76
- /** Assistant 所属 turn。 */
77
- turn_id?: string;
78
- /** Assistant 完整 parts。 */
79
- parts: SessionAssistantMessagePart[];
80
- /** 普通 assistant 或 compact summary。 */
81
- kind?: "normal" | "summary";
82
- /** 默认展示范围。 */
83
- visibility?: "visible" | "internal";
84
- /** Summary 已覆盖到的来源 Message。 */
85
- summary_through_message_id?: string;
86
- }
87
-
88
- /** Action Message 创建参数。 */
89
- export interface OpenSessionActionMessageInput {
90
- /** 可选稳定 Message ID;业务 action 生命周期使用该值定位。 */
91
- message_id?: string;
92
- /** Action 所属 turn。 */
93
- turn_id?: string;
94
- /** Action 业务类型。 */
95
- action_type: string;
96
- /** Action 标题。 */
97
- title: string;
98
- /** Action 描述。 */
99
- description?: string;
100
- /** Action 附加数据。 */
101
- data?: JsonObject;
102
- }
103
-
104
- /** Error Message 创建参数。 */
105
- export interface AppendSessionErrorMessageInput {
106
- /** 错误影响范围。 */
107
- scope: "session" | "turn";
108
- /** 错误所属 turn。 */
109
- turn_id?: string;
110
- /** 稳定错误码。 */
111
- code: string;
112
- /** 用户可见错误文本。 */
113
- message: string;
114
- /** 是否允许恢复。 */
115
- recoverable: boolean;
116
- }
36
+ import type { SessionStreamingToolLocation } from "@/types/session/SessionTool.js";
37
+ import type { SessionApproval } from "@/types/session/SessionApproval.js";
38
+ import type {
39
+ SessionActionRecordV1,
40
+ SessionRecordV1,
41
+ SessionUserMessageV1,
42
+ } from "@/executor/types/SessionRecords.js";
43
+ import { is_session_action_record } from "@/executor/types/SessionRecords.js";
44
+ import {
45
+ from_ui_assistant_parts,
46
+ from_ui_user_parts,
47
+ to_executor_ui_message,
48
+ } from "@/session/messages/SessionMessageCodec.js";
49
+ import { hydrateUserPromptFileParts } from "@executor/messages/SessionAttachmentMapper.js";
50
+ import type {
51
+ AppendCompletedAssistantMessageInput,
52
+ AppendExternalSessionAssistantMessageInput,
53
+ AppendExternalSessionUserMessageInput,
54
+ AppendSessionErrorMessageInput,
55
+ AppendSessionPromptMessageInput,
56
+ AppendSessionUserMessageInput,
57
+ OpenSessionActionMessageInput,
58
+ OpenSessionAssistantMessageInput,
59
+ SessionMessagesOptions,
60
+ } from "@/types/session/SessionMessages.js";
61
+
62
+ export { SessionAssistantMessageWriter } from "@/session/messages/SessionAssistantMessageWriter.js";
117
63
 
118
64
  /** 唯一 Session Message 写入服务。 */
119
- export class SessionRecorder {
65
+ export class SessionMessages {
120
66
  readonly session_id: string;
121
67
  private readonly store: JsonlSessionMessageStore;
122
- private readonly publish: SessionRecorderOptions["publish"];
68
+ private readonly publish: SessionMessagesOptions["publish"];
123
69
  private readonly messages_by_id = new Map<string, SessionMessage>();
70
+ /** 按 Assistant Message 隔离的完整写事务链。 */
71
+ private readonly assistant_write_chains = new Map<string, Promise<void>>();
124
72
  private initialized = false;
125
73
 
126
- constructor(options: SessionRecorderOptions) {
74
+ constructor(options: SessionMessagesOptions) {
127
75
  this.session_id = String(options.session_id || "").trim();
128
76
  this.store = options.store;
129
77
  this.publish = options.publish;
130
- if (!this.session_id) throw new Error("SessionRecorder requires session_id");
78
+ if (!this.session_id) throw new Error("SessionMessages requires session_id");
131
79
  }
132
80
 
133
81
  /** 恢复已有 Message,并收口进程中断遗留的运行状态。 */
@@ -224,6 +172,160 @@ export class SessionRecorder {
224
172
  return this.get_message(writer.message_id) as SessionAssistantMessage;
225
173
  }
226
174
 
175
+ /** 把内部 Executor Record 收口为 canonical Session Message。 */
176
+ async append_record(record: SessionRecordV1): Promise<void> {
177
+ if (is_session_action_record(record)) {
178
+ const action = record as SessionActionRecordV1;
179
+ const existing = this.get_message(action.id);
180
+ if (existing?.type === "action") {
181
+ if (action.state !== "running") {
182
+ await this.update_action_message(action.id, action.state, {
183
+ title: action.title,
184
+ description: action.description,
185
+ });
186
+ }
187
+ return;
188
+ }
189
+ const writer = await this.open_action_message({
190
+ message_id: action.id,
191
+ turn_id: action.metadata.turnId,
192
+ action_type: String(action.id || "").split(":")[0] || "action",
193
+ title: action.title,
194
+ description: action.description,
195
+ });
196
+ if (action.state === "completed") await writer.complete();
197
+ if (action.state === "failed") {
198
+ await writer.fail(action.description || action.title);
199
+ }
200
+ return;
201
+ }
202
+
203
+ const turn_id = String(
204
+ record.metadata?.turnId || `external:${this.session_id}:${generateId()}`,
205
+ );
206
+ if (record.role === "user") {
207
+ await this.append_user_message({
208
+ turn_id,
209
+ input_type:
210
+ record.metadata?.extra?.inputType === "steer" ? "steer" : "prompt",
211
+ parts: from_ui_user_parts(record.parts),
212
+ });
213
+ return;
214
+ }
215
+ await this.append_completed_assistant_message({
216
+ turn_id,
217
+ parts: from_ui_assistant_parts(record.parts),
218
+ visibility:
219
+ record.metadata?.extra?.visibility === "internal"
220
+ ? "internal"
221
+ : "visible",
222
+ kind: record.metadata?.kind === "summary" ? "summary" : "normal",
223
+ });
224
+ }
225
+
226
+ /** 把公开 Session API 的 User 输入转换为 canonical Message 并持久化。 */
227
+ async append_external_user_message(
228
+ input: AppendExternalSessionUserMessageInput,
229
+ ): Promise<boolean> {
230
+ const parts = input.message && "role" in input.message
231
+ ? from_ui_user_parts(input.message.parts)
232
+ : [{
233
+ part_id: `external-user-text:${Date.now()}`,
234
+ type: "text" as const,
235
+ text: String(input.text || "").trim(),
236
+ state: "done" as const,
237
+ }];
238
+ if (parts.length === 0) return false;
239
+ await this.append_user_message({
240
+ turn_id: `external:${this.session_id}:${Date.now()}`,
241
+ input_type: "prompt",
242
+ parts,
243
+ });
244
+ return true;
245
+ }
246
+
247
+ /** 把公开 Session API 的 Assistant 输入转换为 canonical Message 并持久化。 */
248
+ async append_external_assistant_message(
249
+ input: AppendExternalSessionAssistantMessageInput,
250
+ ): Promise<boolean> {
251
+ const parts = input.message && "role" in input.message
252
+ ? from_ui_assistant_parts(input.message.parts)
253
+ : [{
254
+ part_id: `external-assistant-text:${Date.now()}`,
255
+ sequence: 1,
256
+ type: "text" as const,
257
+ text: String(input.fallback_text || "").trim(),
258
+ state: "done" as const,
259
+ }];
260
+ if (parts.length === 0) return false;
261
+ await this.append_completed_assistant_message({ parts });
262
+ return true;
263
+ }
264
+
265
+ /** 把 Session prompt 转换为 canonical User Message 并持久化。 */
266
+ async append_prompt_message(
267
+ input: AppendSessionPromptMessageInput,
268
+ ): Promise<SessionUserMessageV1> {
269
+ const query = input.prompt.query;
270
+ const ui_parts = typeof query === "string"
271
+ ? [{ type: "text" as const, text: query.trim() }]
272
+ : await hydrateUserPromptFileParts(
273
+ Array.isArray(query) ? query : [],
274
+ input.project_root,
275
+ );
276
+ const canonical = await this.append_user_message({
277
+ turn_id: input.turn_id,
278
+ input_type: input.input_type,
279
+ parts: normalize_session_user_parts(ui_parts),
280
+ });
281
+ return to_executor_ui_message(canonical) as SessionUserMessageV1;
282
+ }
283
+
284
+ /** 持久化 Executor 在本轮延迟产生的 User Message。 */
285
+ async append_deferred_user_messages(
286
+ deferred_messages?: SessionUserMessageV1[],
287
+ ): Promise<number> {
288
+ const messages = Array.isArray(deferred_messages)
289
+ ? deferred_messages
290
+ : [];
291
+ for (const message of messages) {
292
+ await this.append_user_message({
293
+ turn_id: String(
294
+ message.metadata?.turnId ||
295
+ `deferred:${this.session_id}:${Date.now()}`,
296
+ ),
297
+ input_type: "steer",
298
+ parts: from_ui_user_parts(message.parts),
299
+ });
300
+ }
301
+ return messages.length;
302
+ }
303
+
304
+ /** 按稳定 Action ID 创建或更新 canonical Action Message。 */
305
+ async persist_action_record(event: SessionActionRecordV1): Promise<void> {
306
+ const existing = this.get_message(event.id);
307
+ if (!existing) {
308
+ const writer = await this.open_action_message({
309
+ message_id: event.id,
310
+ turn_id: event.metadata.turnId,
311
+ action_type: infer_action_type(event.id),
312
+ title: event.title,
313
+ description: event.description,
314
+ });
315
+ if (event.state === "completed") await writer.complete();
316
+ if (event.state === "failed") {
317
+ await writer.fail(event.description || event.title);
318
+ }
319
+ return;
320
+ }
321
+ if (existing.type === "action" && event.state !== "running") {
322
+ await this.update_action_message(event.id, event.state, {
323
+ title: event.title,
324
+ description: event.description,
325
+ });
326
+ }
327
+ }
328
+
227
329
  /** 创建 running Action Message。 */
228
330
  async open_action_message(
229
331
  input: OpenSessionActionMessageInput,
@@ -416,6 +518,18 @@ export class SessionRecorder {
416
518
  delta: string,
417
519
  ): Promise<void> {
418
520
  if (!delta) return;
521
+ await this.enqueue_assistant_write(message_id, async () => {
522
+ await this.append_assistant_delta_serialized(message_id, part_id, type, delta);
523
+ });
524
+ }
525
+
526
+ /** 在 Assistant 写队列内追加文本 delta。 */
527
+ private async append_assistant_delta_serialized(
528
+ message_id: string,
529
+ part_id: string,
530
+ type: "text" | "reasoning",
531
+ delta: string,
532
+ ): Promise<void> {
419
533
  const current = require_message([...this.messages_by_id.values()], message_id, "assistant");
420
534
  require_streaming_assistant(current);
421
535
  const part = current.parts.find((item) => item.part_id === part_id);
@@ -453,6 +567,16 @@ export class SessionRecorder {
453
567
  async update_assistant_part(
454
568
  message_id: string,
455
569
  part: SessionAssistantMessagePart,
570
+ ): Promise<void> {
571
+ await this.enqueue_assistant_write(message_id, async () => {
572
+ await this.update_assistant_part_serialized(message_id, part);
573
+ });
574
+ }
575
+
576
+ /** 在 Assistant 写队列内提交完整 Part 快照。 */
577
+ private async update_assistant_part_serialized(
578
+ message_id: string,
579
+ part: SessionAssistantMessagePart,
456
580
  ): Promise<void> {
457
581
  const current = require_message([...this.messages_by_id.values()], message_id, "assistant");
458
582
  require_streaming_assistant(current);
@@ -490,6 +614,16 @@ export class SessionRecorder {
490
614
  async complete_assistant_message(
491
615
  message_id: string,
492
616
  status: "completed" | "stopped" | "failed",
617
+ ): Promise<void> {
618
+ await this.enqueue_assistant_write(message_id, async () => {
619
+ await this.complete_assistant_message_serialized(message_id, status);
620
+ });
621
+ }
622
+
623
+ /** 在 Assistant 写队列内关闭草稿并写入 Active。 */
624
+ private async complete_assistant_message_serialized(
625
+ message_id: string,
626
+ status: "completed" | "stopped" | "failed",
493
627
  ): Promise<void> {
494
628
  const current = require_message([...this.messages_by_id.values()], message_id, "assistant");
495
629
  require_streaming_assistant(current);
@@ -509,42 +643,11 @@ export class SessionRecorder {
509
643
  this.accept_message(message);
510
644
  }
511
645
 
512
- /** @internal 将 Shell Runtime 审批请求更新到当前 Tool Part。 */
513
- async require_tool_approval(input: {
514
- tool_call_id: string;
515
- approval_id: string;
516
- }): Promise<void> {
517
- const tool = this.find_streaming_tool(input.tool_call_id);
518
- await this.update_assistant_part(tool.message_id, {
519
- ...tool.part,
520
- state: "approval-required",
521
- approval_id: input.approval_id,
522
- });
523
- }
524
-
525
- /** @internal 将审批结果更新到当前 Tool Part。 */
526
- async resolve_tool_approval(input: {
527
- tool_call_id: string;
528
- approval_id: string;
529
- decision: "approved" | "denied" | "expired";
530
- }): Promise<void> {
531
- const tool = this.find_streaming_tool(input.tool_call_id);
532
- if (tool.part.approval_id && tool.part.approval_id !== input.approval_id) {
533
- throw new Error(`Tool approval identity mismatch: ${input.approval_id}`);
534
- }
535
- await this.update_assistant_part(tool.message_id, {
536
- ...tool.part,
537
- state: input.decision === "approved" ? "running" : "failed",
538
- ...(input.decision === "approved"
539
- ? {}
540
- : { error: input.decision === "expired" ? "Approval expired" : "Approval denied" }),
541
- });
542
- }
543
-
544
646
  private async create_message(
545
647
  factory: (sequence: number, created_at: number) => SessionMessage,
546
648
  draft = false,
547
649
  ): Promise<SessionMessage> {
650
+ await this.ensure_initialized();
548
651
  if (draft) {
549
652
  const message = await this.store.create_assistant_message((state) => {
550
653
  const candidate = factory(state.message_sequence, Date.now());
@@ -563,10 +666,8 @@ export class SessionRecorder {
563
666
  return message;
564
667
  }
565
668
 
566
- private find_streaming_tool(tool_call_id: string): {
567
- message_id: string;
568
- part: SessionAssistantToolPart;
569
- } {
669
+ /** 读取当前流式 Assistant 中的指定 Tool Part。 */
670
+ find_streaming_tool(tool_call_id: string): SessionStreamingToolLocation | undefined {
570
671
  for (const message of this.messages_by_id.values()) {
571
672
  if (message.type !== "assistant" || message.status !== "streaming") continue;
572
673
  const part = message.parts.find(
@@ -575,6 +676,89 @@ export class SessionRecorder {
575
676
  );
576
677
  if (part) return { message_id: message.message_id, part };
577
678
  }
679
+ return undefined;
680
+ }
681
+
682
+ /** 把完整审批请求写入对应的流式 Tool Part。 */
683
+ async request_tool_approval(approval: SessionApproval): Promise<void> {
684
+ const { message_id } = this.require_streaming_tool(approval.tool_call_id);
685
+ await this.enqueue_assistant_write(message_id, async () => {
686
+ const tool = this.require_streaming_tool(approval.tool_call_id);
687
+ if (tool.message_id !== message_id) {
688
+ throw new Error(`Tool Assistant Message changed: ${approval.tool_call_id}`);
689
+ }
690
+ if (tool.part.state !== "ready") {
691
+ throw new Error(
692
+ `Tool approval requires ready input: ${approval.tool_call_id} (${tool.part.state})`,
693
+ );
694
+ }
695
+ await this.update_assistant_part_serialized(message_id, {
696
+ ...tool.part,
697
+ state: "approval-required",
698
+ approval,
699
+ });
700
+ });
701
+ }
702
+
703
+ /** 在 Tool 恢复执行前提交审批决定对应的 Part 状态。 */
704
+ async resolve_tool_approval(input: {
705
+ /** 当前审批请求标识。 */
706
+ approval_id: string;
707
+ /** 当前审批最终决定。 */
708
+ decision: "approved" | "denied" | "expired";
709
+ /** 当前审批关联的 Tool Call。 */
710
+ tool_call_id: string;
711
+ }): Promise<void> {
712
+ const { message_id } = this.require_streaming_tool(input.tool_call_id);
713
+ await this.enqueue_assistant_write(message_id, async () => {
714
+ const tool = this.require_streaming_tool(input.tool_call_id);
715
+ if (tool.message_id !== message_id) {
716
+ throw new Error(`Tool Assistant Message changed: ${input.tool_call_id}`);
717
+ }
718
+ if (tool.part.approval?.approval_id !== input.approval_id) {
719
+ throw new Error(`Tool approval identity mismatch: ${input.approval_id}`);
720
+ }
721
+ await this.update_assistant_part_serialized(message_id, {
722
+ ...tool.part,
723
+ state: input.decision === "approved" ? "running" : "failed",
724
+ ...(input.decision === "approved"
725
+ ? {}
726
+ : {
727
+ error:
728
+ input.decision === "expired"
729
+ ? "Approval expired"
730
+ : "Approval denied",
731
+ }),
732
+ });
733
+ });
734
+ }
735
+
736
+ /**
737
+ * 串行执行同一 Assistant Message 的完整写事务。
738
+ *
739
+ * 失败事务不会阻塞后续写入;链尾仅用于排序,真实错误仍返回给调用方。
740
+ */
741
+ private async enqueue_assistant_write<T>(
742
+ message_id: string,
743
+ operation: () => Promise<T>,
744
+ ): Promise<T> {
745
+ const previous = this.assistant_write_chains.get(message_id) || Promise.resolve();
746
+ const result = previous.then(operation, operation);
747
+ const chain = result.then(() => undefined, () => undefined);
748
+ this.assistant_write_chains.set(message_id, chain);
749
+ try {
750
+ return await result;
751
+ } finally {
752
+ if (this.assistant_write_chains.get(message_id) === chain) {
753
+ this.assistant_write_chains.delete(message_id);
754
+ }
755
+ }
756
+ }
757
+
758
+ /** 查找当前流式 Assistant 中的 Tool Part,否则抛出明确错误。 */
759
+ private require_streaming_tool(tool_call_id: string): SessionStreamingToolLocation {
760
+ const tool = this.find_streaming_tool(tool_call_id);
761
+ if (tool) return tool;
578
762
  throw new Error(`Streaming Tool Part not found: ${tool_call_id}`);
579
763
  }
580
764
 
@@ -609,311 +793,28 @@ export class SessionRecorder {
609
793
  }
610
794
 
611
795
  }
612
-
613
- /** 单个 Assistant segment 的流式 writer。 */
614
- export class SessionAssistantMessageWriter {
615
- readonly message_id: string;
616
- private readonly recorder: SessionRecorder;
617
- private readonly pending_text_parts = new Map<string, "text" | "reasoning">();
618
- private readonly active_text_part_ids = new Map<string, string>();
619
- private closed = false;
620
-
621
- constructor(recorder: SessionRecorder, message_id: string) {
622
- this.recorder = recorder;
623
- this.message_id = message_id;
624
- }
625
-
626
- /** 应用一个原始 AI SDK UI chunk。 */
627
- async apply_chunk(chunk: UIMessageChunk): Promise<void> {
628
- if (this.closed) throw new Error("Assistant Message writer is closed");
629
- const current = this.current_message();
630
- switch (chunk.type) {
631
- case "text-start":
632
- case "reasoning-start": {
633
- const type = chunk.type === "text-start" ? "text" : "reasoning";
634
- const part_id = this.resolve_text_part_id(type, chunk.id);
635
- if (!current.parts.some((part) => part.part_id === part_id)) {
636
- this.pending_text_parts.set(part_id, type);
637
- }
638
- return;
639
- }
640
- case "text-delta":
641
- case "reasoning-delta": {
642
- const type = chunk.type === "text-delta" ? "text" : "reasoning";
643
- const part_id = this.resolve_text_part_id(type, chunk.id);
644
- await this.ensure_text_part(part_id, type);
645
- await this.recorder.append_assistant_delta(
646
- this.message_id,
647
- part_id,
648
- type,
649
- chunk.delta,
650
- );
651
- return;
652
- }
653
- case "text-end":
654
- case "reasoning-end": {
655
- const type = chunk.type === "text-end" ? "text" : "reasoning";
656
- const source_part_id = this.source_text_part_id(type, chunk.id);
657
- const part_id = this.active_text_part_ids.get(source_part_id);
658
- if (!part_id) return;
659
- const part = current.parts.find((item) => item.part_id === part_id);
660
- if (part?.type === "text" || part?.type === "reasoning") {
661
- await this.upsert_part({ ...part, state: "done" });
662
- } else {
663
- this.pending_text_parts.delete(part_id);
664
- }
665
- this.active_text_part_ids.delete(source_part_id);
666
- return;
667
- }
668
- case "tool-input-start":
669
- await this.upsert_tool(chunk.toolCallId, {
670
- tool_name: chunk.toolName,
671
- state: "input-streaming",
672
- input_text: "",
673
- });
674
- return;
675
- case "tool-input-delta": {
676
- const tool = this.find_tool(chunk.toolCallId);
677
- await this.upsert_tool(chunk.toolCallId, {
678
- tool_name: tool?.tool_name || "unknown",
679
- state: "input-streaming",
680
- input_text: `${tool?.input_text || ""}${chunk.inputTextDelta}`,
681
- });
682
- return;
683
- }
684
- case "tool-input-available":
685
- await this.upsert_tool(chunk.toolCallId, {
686
- tool_name: chunk.toolName,
687
- state: "ready",
688
- input: to_json_value(chunk.input),
689
- });
690
- return;
691
- case "tool-input-error":
692
- await this.upsert_tool(chunk.toolCallId, {
693
- tool_name: chunk.toolName,
694
- state: "failed",
695
- input: to_json_value(chunk.input),
696
- error: chunk.errorText,
697
- });
698
- return;
699
- case "tool-approval-request": {
700
- const tool = this.find_tool(chunk.toolCallId);
701
- await this.upsert_tool(chunk.toolCallId, {
702
- tool_name: tool?.tool_name || "unknown",
703
- state: "approval-required",
704
- approval_id: chunk.approvalId,
705
- });
706
- return;
707
- }
708
- case "tool-output-available": {
709
- const tool = this.find_tool(chunk.toolCallId);
710
- await this.upsert_tool(chunk.toolCallId, {
711
- tool_name: tool?.tool_name || "unknown",
712
- state: "completed",
713
- output: to_json_value(chunk.output),
714
- });
715
- return;
716
- }
717
- case "tool-output-error":
718
- case "tool-output-denied": {
719
- const tool = this.find_tool(chunk.toolCallId);
720
- await this.upsert_tool(chunk.toolCallId, {
721
- tool_name: tool?.tool_name || "unknown",
722
- state: "failed",
723
- error:
724
- chunk.type === "tool-output-error"
725
- ? chunk.errorText
726
- : "Tool output denied",
727
- });
728
- return;
729
- }
730
- case "file":
731
- await this.append_file_part({
732
- media_type: chunk.mediaType,
733
- url: chunk.url,
734
- });
735
- return;
736
- default:
737
- return;
738
- }
739
- }
740
-
741
- /** 写入一个完整 Assistant part。 */
742
- async upsert_part(part: SessionAssistantMessagePart): Promise<void> {
743
- await this.recorder.update_assistant_part(this.message_id, part);
744
- }
745
-
746
- /**
747
- * 把最终结果中的文件补入当前 Assistant,并对流式已写入文件去重。
748
- */
749
- async append_file_part(
750
- input: Pick<SessionAssistantFilePart, "filename" | "media_type" | "url">,
751
- ): Promise<void> {
752
- const filename = String(input.filename || "").trim();
753
- const current = this.current_message();
754
- const existing = current.parts.find(
755
- (part) =>
756
- part.type === "file" &&
757
- part.url === input.url &&
758
- part.media_type === input.media_type,
759
- );
760
- if (existing?.type === "file") {
761
- if (filename && String(existing.filename || "").trim() !== filename) {
762
- await this.upsert_part({ ...existing, filename });
763
- }
764
- return;
765
- }
766
- await this.upsert_part({
767
- part_id: `file:${generateId()}`,
768
- sequence: this.next_part_sequence(),
769
- type: "file",
770
- media_type: input.media_type,
771
- url: input.url,
772
- ...(filename ? { filename } : {}),
773
- });
774
- }
775
-
776
- /** 当前实现逐 chunk 等待落盘,因此 flush 在返回时天然完成。 */
777
- async flush(): Promise<void> {}
778
-
779
- /** 正常完成当前 assistant segment。 */
780
- async complete(): Promise<void> {
781
- await this.close("completed");
782
- }
783
-
784
- /** 停止当前 assistant segment,并保留已有 parts。 */
785
- async stop(): Promise<void> {
786
- await this.close("stopped");
787
- }
788
-
789
- /** 以失败状态关闭当前 assistant segment。 */
790
- async fail(_error: unknown): Promise<void> {
791
- await this.close("failed");
792
- }
793
-
794
- private current_message(): SessionAssistantMessage {
795
- const message = this.recorder.get_message(this.message_id);
796
- if (!message || message.type !== "assistant") {
797
- throw new Error(`Assistant Message not found: ${this.message_id}`);
798
- }
799
- return message;
800
- }
801
-
802
- private find_tool(tool_call_id: string): SessionAssistantToolPart | undefined {
803
- return this.current_message().parts.find(
804
- (part): part is SessionAssistantToolPart =>
805
- part.type === "tool" && part.tool_call_id === tool_call_id,
806
- );
807
- }
808
-
809
- private next_part_sequence(): number {
810
- return this.current_message().parts.reduce(
811
- (value, part) => Math.max(value, part.sequence + 1),
812
- 1,
813
- );
814
- }
815
-
816
- /**
817
- * 把 AI SDK 当前 stream 内的临时 chunk ID 映射为 Message 内唯一 Part ID。
818
- *
819
- * AI SDK 会在不同 `streamText()` 调用中重复使用 `txt-0`、`reasoning-0`
820
- * 等 ID,因此这些 ID 只能用于关联当前尚未结束的文本片段。
821
- */
822
- private resolve_text_part_id(
823
- type: "text" | "reasoning",
824
- chunk_id: string,
825
- ): string {
826
- const source_part_id = this.source_text_part_id(type, chunk_id);
827
- const active_part_id = this.active_text_part_ids.get(source_part_id);
828
- if (active_part_id) return active_part_id;
829
- const part_id = `${type}:${generateId()}`;
830
- this.active_text_part_ids.set(source_part_id, part_id);
831
- return part_id;
832
- }
833
-
834
- /** 构造当前流片段使用的临时关联键。 */
835
- private source_text_part_id(
836
- type: "text" | "reasoning",
837
- chunk_id: string,
838
- ): string {
839
- return `${type}:${chunk_id}`;
840
- }
841
-
842
- /** 在首个有效 Delta 到达时才固定文本 Part 的真实顺序。 */
843
- private async ensure_text_part(
844
- part_id: string,
845
- type: "text" | "reasoning",
846
- ): Promise<void> {
847
- const existing = this.current_message().parts.find(
848
- (part) => part.part_id === part_id,
849
- );
850
- if (existing) {
851
- if (existing.type !== type) {
852
- throw new Error(`Assistant Part type changed: ${part_id}`);
853
- }
854
- return;
855
- }
856
- const pending_type = this.pending_text_parts.get(part_id);
857
- if (pending_type && pending_type !== type) {
858
- throw new Error(`Assistant pending Part type changed: ${part_id}`);
859
- }
860
- await this.upsert_part({
861
- part_id,
862
- sequence: this.next_part_sequence(),
863
- type,
864
- text: "",
865
- state: "streaming",
866
- });
867
- this.pending_text_parts.delete(part_id);
868
- }
869
-
870
- private async upsert_tool(
871
- tool_call_id: string,
872
- changes: Pick<SessionAssistantToolPart, "tool_name" | "state"> &
873
- Partial<Omit<SessionAssistantToolPart, "part_id" | "type" | "tool_call_id" | "tool_name" | "state">>,
874
- ): Promise<void> {
875
- const current = this.find_tool(tool_call_id);
876
- await this.upsert_part({
877
- ...(current || {}),
878
- part_id: `tool:${tool_call_id}`,
879
- sequence: current?.sequence || this.next_part_sequence(),
880
- type: "tool",
881
- tool_call_id,
882
- ...changes,
883
- });
884
- }
885
-
886
- private async close(status: "completed" | "stopped" | "failed"): Promise<void> {
887
- if (this.closed) return;
888
- this.pending_text_parts.clear();
889
- this.active_text_part_ids.clear();
890
- await this.recorder.complete_assistant_message(this.message_id, status);
891
- this.closed = true;
892
- }
893
- }
894
-
895
796
  /** 单个 Action Message 的生命周期 writer。 */
896
797
  export class SessionActionMessageWriter {
897
798
  readonly message_id: string;
898
- private readonly recorder: SessionRecorder;
799
+ private readonly messages: SessionMessages;
899
800
  private closed = false;
900
801
 
901
- constructor(recorder: SessionRecorder, message_id: string) {
902
- this.recorder = recorder;
802
+ constructor(messages: SessionMessages, message_id: string) {
803
+ this.messages = messages;
903
804
  this.message_id = message_id;
904
805
  }
905
806
 
906
807
  /** 把 Action 更新为 completed。 */
907
808
  async complete(input?: { title?: string; description?: string; data?: JsonObject }): Promise<void> {
908
809
  if (this.closed) return;
909
- await this.recorder.update_action_message(this.message_id, "completed", input);
810
+ await this.messages.update_action_message(this.message_id, "completed", input);
910
811
  this.closed = true;
911
812
  }
912
813
 
913
814
  /** 把 Action 更新为 failed。 */
914
815
  async fail(error: unknown): Promise<void> {
915
816
  if (this.closed) return;
916
- await this.recorder.update_action_message(this.message_id, "failed", {
817
+ await this.messages.update_action_message(this.message_id, "failed", {
917
818
  description: error instanceof Error ? error.message : String(error),
918
819
  });
919
820
  this.closed = true;
@@ -950,7 +851,7 @@ export function normalize_session_user_parts(
950
851
  part_id: `user-data:${index + 1}`,
951
852
  type: "data",
952
853
  data_type: String(candidate.type),
953
- data: to_json_value(candidate.data),
854
+ data: to_session_json_value(candidate.data),
954
855
  }];
955
856
  }
956
857
  return [];
@@ -981,16 +882,6 @@ function require_streaming_assistant(
981
882
  return message;
982
883
  }
983
884
 
984
- function to_json_value(input: unknown): JsonValue {
985
- if (input === undefined || input === null) return null;
986
- if (typeof input === "string" || typeof input === "number" || typeof input === "boolean") return input;
987
- try {
988
- return JSON.parse(JSON.stringify(input)) as JsonValue;
989
- } catch {
990
- return String(input);
991
- }
992
- }
993
-
994
885
  function resolve_import_id(map: Map<string, string>, source_id: string, prefix: string): string {
995
886
  const existing = map.get(source_id);
996
887
  if (existing) return existing;
@@ -999,6 +890,11 @@ function resolve_import_id(map: Map<string, string>, source_id: string, prefix:
999
890
  return created;
1000
891
  }
1001
892
 
893
+ /** 从 Action Message ID 提取稳定业务类型。 */
894
+ function infer_action_type(message_id: string): string {
895
+ return String(message_id || "").split(":")[0] || "action";
896
+ }
897
+
1002
898
  /** 按真实 Message sequence 升序排序。 */
1003
899
  function compare_message_sequence(left: SessionMessage, right: SessionMessage): number {
1004
900
  return left.sequence - right.sequence;