@downcity/agent 1.1.208 → 1.1.210

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 (262) hide show
  1. package/bin/agent/local/Agent.d.ts +3 -3
  2. package/bin/agent/local/Agent.d.ts.map +1 -1
  3. package/bin/agent/local/Agent.js +0 -3
  4. package/bin/agent/local/Agent.js.map +1 -1
  5. package/bin/agent/local/AgentInstructions.d.ts +1 -1
  6. package/bin/agent/local/AgentInstructions.d.ts.map +1 -1
  7. package/bin/agent/local/services/AgentAssemblyService.d.ts +3 -8
  8. package/bin/agent/local/services/AgentAssemblyService.d.ts.map +1 -1
  9. package/bin/agent/local/services/AgentAssemblyService.js +0 -1
  10. package/bin/agent/local/services/AgentAssemblyService.js.map +1 -1
  11. package/bin/agent/local/services/AgentSessions.d.ts +5 -7
  12. package/bin/agent/local/services/AgentSessions.d.ts.map +1 -1
  13. package/bin/agent/local/services/AgentSessions.js +2 -3
  14. package/bin/agent/local/services/AgentSessions.js.map +1 -1
  15. package/bin/agent/remote/RemoteAgent.d.ts +3 -1
  16. package/bin/agent/remote/RemoteAgent.d.ts.map +1 -1
  17. package/bin/agent/remote/RemoteAgent.js.map +1 -1
  18. package/bin/agent/remote/RemoteSession.d.ts +10 -1
  19. package/bin/agent/remote/RemoteSession.d.ts.map +1 -1
  20. package/bin/agent/remote/RemoteSession.js +18 -0
  21. package/bin/agent/remote/RemoteSession.js.map +1 -1
  22. package/bin/agent/remote/RemoteTransport.d.ts +5 -1
  23. package/bin/agent/remote/RemoteTransport.d.ts.map +1 -1
  24. package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts +4 -1
  25. package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts.map +1 -1
  26. package/bin/agent/remote/transports/HttpRemoteAgentTransport.js +7 -0
  27. package/bin/agent/remote/transports/HttpRemoteAgentTransport.js.map +1 -1
  28. package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts +4 -1
  29. package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts.map +1 -1
  30. package/bin/agent/remote/transports/RpcRemoteAgentTransport.js +1 -0
  31. package/bin/agent/remote/transports/RpcRemoteAgentTransport.js.map +1 -1
  32. package/bin/executor/Executor.d.ts +0 -16
  33. package/bin/executor/Executor.d.ts.map +1 -1
  34. package/bin/executor/Executor.js +0 -16
  35. package/bin/executor/Executor.js.map +1 -1
  36. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts +1 -3
  37. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts.map +1 -1
  38. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js +1 -5
  39. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js.map +1 -1
  40. package/bin/executor/composer/history/SessionHistoryWriter.d.ts +0 -10
  41. package/bin/executor/composer/history/SessionHistoryWriter.d.ts.map +1 -1
  42. package/bin/executor/composer/history/SessionHistoryWriter.js +31 -61
  43. package/bin/executor/composer/history/SessionHistoryWriter.js.map +1 -1
  44. package/bin/executor/messages/AssistantFileResource.d.ts.map +1 -1
  45. package/bin/executor/messages/AssistantFileResource.js +58 -15
  46. package/bin/executor/messages/AssistantFileResource.js.map +1 -1
  47. package/bin/executor/services/ExecutorInflightService.d.ts +0 -5
  48. package/bin/executor/services/ExecutorInflightService.d.ts.map +1 -1
  49. package/bin/executor/services/ExecutorInflightService.js +0 -6
  50. package/bin/executor/services/ExecutorInflightService.js.map +1 -1
  51. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts +4 -0
  52. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts.map +1 -1
  53. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +115 -3
  54. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +1 -1
  55. package/bin/executor/types/SessionHistoryMeta.d.ts +6 -0
  56. package/bin/executor/types/SessionHistoryMeta.d.ts.map +1 -1
  57. package/bin/index.d.ts +38 -6
  58. package/bin/index.d.ts.map +1 -1
  59. package/bin/index.js +14 -1
  60. package/bin/index.js.map +1 -1
  61. package/bin/plugin/core/ActionScheduleExecutor.js +1 -1
  62. package/bin/plugin/core/ActionScheduleExecutor.js.map +1 -1
  63. package/bin/plugin/core/BasePlugin.d.ts +7 -9
  64. package/bin/plugin/core/BasePlugin.d.ts.map +1 -1
  65. package/bin/plugin/core/BasePlugin.js +1 -14
  66. package/bin/plugin/core/BasePlugin.js.map +1 -1
  67. package/bin/plugin/core/HookRegistry.d.ts +1 -1
  68. package/bin/plugin/core/HookRegistry.d.ts.map +1 -1
  69. package/bin/plugin/core/PluginActionFactory.d.ts +1 -5
  70. package/bin/plugin/core/PluginActionFactory.d.ts.map +1 -1
  71. package/bin/plugin/core/PluginActionFactory.js +0 -3
  72. package/bin/plugin/core/PluginActionFactory.js.map +1 -1
  73. package/bin/plugin/core/PluginActionRunner.d.ts +6 -4
  74. package/bin/plugin/core/PluginActionRunner.d.ts.map +1 -1
  75. package/bin/plugin/core/PluginActionRunner.js +2 -2
  76. package/bin/plugin/core/PluginActionRunner.js.map +1 -1
  77. package/bin/plugin/core/PluginCatalog.d.ts +2 -1
  78. package/bin/plugin/core/PluginCatalog.d.ts.map +1 -1
  79. package/bin/plugin/core/PluginCatalog.js.map +1 -1
  80. package/bin/plugin/core/PluginCommand.d.ts +1 -1
  81. package/bin/plugin/core/PluginCommand.d.ts.map +1 -1
  82. package/bin/plugin/core/PluginCommand.js.map +1 -1
  83. package/bin/plugin/core/PluginHttpRoutes.d.ts +1 -1
  84. package/bin/plugin/core/PluginHttpRoutes.d.ts.map +1 -1
  85. package/bin/plugin/core/PluginLocalExecution.d.ts +4 -1
  86. package/bin/plugin/core/PluginLocalExecution.d.ts.map +1 -1
  87. package/bin/plugin/core/PluginLocalExecution.js +0 -1
  88. package/bin/plugin/core/PluginLocalExecution.js.map +1 -1
  89. package/bin/plugin/core/PluginRegistry.d.ts +4 -2
  90. package/bin/plugin/core/PluginRegistry.d.ts.map +1 -1
  91. package/bin/plugin/core/PluginRegistry.js +7 -6
  92. package/bin/plugin/core/PluginRegistry.js.map +1 -1
  93. package/bin/plugin/core/PluginStateController.d.ts +7 -27
  94. package/bin/plugin/core/PluginStateController.d.ts.map +1 -1
  95. package/bin/plugin/core/PluginStateController.js +5 -39
  96. package/bin/plugin/core/PluginStateController.js.map +1 -1
  97. package/bin/plugin/types/PluginApi.d.ts +3 -79
  98. package/bin/plugin/types/PluginApi.d.ts.map +1 -1
  99. package/bin/rpc/Client.d.ts +11 -6
  100. package/bin/rpc/Client.d.ts.map +1 -1
  101. package/bin/rpc/Client.js +2 -0
  102. package/bin/rpc/Client.js.map +1 -1
  103. package/bin/session/Session.d.ts +2 -5
  104. package/bin/session/Session.d.ts.map +1 -1
  105. package/bin/session/Session.js +3 -16
  106. package/bin/session/Session.js.map +1 -1
  107. package/bin/session/SessionSystemBuilder.d.ts +1 -1
  108. package/bin/session/SessionSystemBuilder.d.ts.map +1 -1
  109. package/bin/session/browse/Browse.d.ts +4 -6
  110. package/bin/session/browse/Browse.d.ts.map +1 -1
  111. package/bin/session/browse/Browse.js +71 -71
  112. package/bin/session/browse/Browse.js.map +1 -1
  113. package/bin/session/preview/SessionMessagePreview.d.ts +13 -0
  114. package/bin/session/preview/SessionMessagePreview.d.ts.map +1 -0
  115. package/bin/session/preview/SessionMessagePreview.js +61 -0
  116. package/bin/session/preview/SessionMessagePreview.js.map +1 -0
  117. package/bin/session/services/SessionStateService.d.ts +1 -1
  118. package/bin/session/services/SessionStateService.d.ts.map +1 -1
  119. package/bin/session/services/SessionStateService.js +2 -2
  120. package/bin/session/services/SessionStateService.js.map +1 -1
  121. package/bin/session/services/SessionViewService.d.ts +2 -1
  122. package/bin/session/services/SessionViewService.d.ts.map +1 -1
  123. package/bin/session/services/SessionViewService.js +4 -1
  124. package/bin/session/services/SessionViewService.js.map +1 -1
  125. package/bin/session/storage/Metadata.d.ts.map +1 -1
  126. package/bin/session/storage/Metadata.js +23 -0
  127. package/bin/session/storage/Metadata.js.map +1 -1
  128. package/bin/session/storage/Persistence.d.ts +1 -1
  129. package/bin/session/storage/Persistence.d.ts.map +1 -1
  130. package/bin/session/storage/RuntimeSessionPort.d.ts +0 -12
  131. package/bin/session/storage/RuntimeSessionPort.d.ts.map +1 -1
  132. package/bin/session/storage/RuntimeSessionPort.js +0 -8
  133. package/bin/session/storage/RuntimeSessionPort.js.map +1 -1
  134. package/bin/types/plugin/PluginAction.d.ts +0 -10
  135. package/bin/types/plugin/PluginAction.d.ts.map +1 -1
  136. package/bin/types/plugin/PluginCommand.d.ts +2 -3
  137. package/bin/types/plugin/PluginCommand.d.ts.map +1 -1
  138. package/bin/types/plugin/PluginControl.d.ts +74 -0
  139. package/bin/types/plugin/PluginControl.d.ts.map +1 -0
  140. package/bin/types/plugin/PluginControl.js +9 -0
  141. package/bin/types/plugin/PluginControl.js.map +1 -0
  142. package/bin/types/plugin/PluginDefinition.d.ts +1 -1
  143. package/bin/types/plugin/PluginDefinition.d.ts.map +1 -1
  144. package/bin/types/plugin/PluginRuntime.d.ts +1 -3
  145. package/bin/types/plugin/PluginRuntime.d.ts.map +1 -1
  146. package/bin/types/plugin/PluginState.d.ts +3 -16
  147. package/bin/types/plugin/PluginState.d.ts.map +1 -1
  148. package/bin/types/rpc/RpcProtocol.d.ts +3 -3
  149. package/bin/types/rpc/RpcProtocol.d.ts.map +1 -1
  150. package/bin/types/runtime/agent/AgentContext.d.ts +1 -9
  151. package/bin/types/runtime/agent/AgentContext.d.ts.map +1 -1
  152. package/bin/types/runtime/agent/AgentContext.js.map +1 -1
  153. package/bin/types/session/SessionLocalState.d.ts +1 -1
  154. package/bin/types/session/SessionLocalState.d.ts.map +1 -1
  155. package/package.json +4 -7
  156. package/scripts/agent-ready.test.mjs +38 -0
  157. package/scripts/assistant-file-resource.test.mjs +39 -0
  158. package/scripts/city-model-tool-loop.test.mjs +18 -30
  159. package/scripts/image-plugin-job.test.mjs +13 -13
  160. package/scripts/plugin-tool-bridge.test.mjs +2 -3
  161. package/scripts/remote-session-reconnect.test.mjs +67 -0
  162. package/scripts/session-history-writer-error.test.mjs +57 -0
  163. package/scripts/session-list-title.test.mjs +114 -23
  164. package/src/agent/local/Agent.ts +4 -10
  165. package/src/agent/local/AgentInstructions.ts +1 -1
  166. package/src/agent/local/services/AgentAssemblyService.ts +3 -9
  167. package/src/agent/local/services/AgentSessions.ts +8 -15
  168. package/src/agent/remote/RemoteAgent.ts +5 -4
  169. package/src/agent/remote/RemoteSession.ts +21 -2
  170. package/src/agent/remote/RemoteTransport.ts +6 -2
  171. package/src/agent/remote/transports/HttpRemoteAgentTransport.ts +13 -3
  172. package/src/agent/remote/transports/RpcRemoteAgentTransport.ts +6 -2
  173. package/src/executor/Executor.ts +0 -23
  174. package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.ts +2 -8
  175. package/src/executor/composer/history/SessionHistoryWriter.ts +33 -64
  176. package/src/executor/messages/AssistantFileResource.ts +61 -17
  177. package/src/executor/services/ExecutorInflightService.ts +0 -10
  178. package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +130 -4
  179. package/src/executor/types/SessionHistoryMeta.ts +6 -0
  180. package/src/index.ts +100 -29
  181. package/src/plugin/core/ActionScheduleExecutor.ts +1 -1
  182. package/src/plugin/core/BasePlugin.ts +8 -22
  183. package/src/plugin/core/HookRegistry.ts +1 -1
  184. package/src/plugin/core/PluginActionFactory.ts +1 -8
  185. package/src/plugin/core/PluginActionRunner.ts +8 -11
  186. package/src/plugin/core/PluginCatalog.ts +2 -5
  187. package/src/plugin/core/PluginCommand.ts +2 -1
  188. package/src/plugin/core/PluginHttpRoutes.ts +1 -1
  189. package/src/plugin/core/PluginLocalExecution.ts +4 -7
  190. package/src/plugin/core/PluginRegistry.ts +10 -10
  191. package/src/plugin/core/PluginStateController.ts +12 -60
  192. package/src/plugin/types/PluginApi.ts +6 -81
  193. package/src/rpc/Client.ts +22 -16
  194. package/src/session/Session.ts +5 -21
  195. package/src/session/SessionSystemBuilder.ts +1 -1
  196. package/src/session/browse/Browse.ts +103 -84
  197. package/src/session/preview/SessionMessagePreview.ts +75 -0
  198. package/src/session/services/SessionStateService.ts +3 -4
  199. package/src/session/services/SessionViewService.ts +6 -6
  200. package/src/session/storage/Metadata.ts +26 -0
  201. package/src/session/storage/Persistence.ts +1 -1
  202. package/src/session/storage/RuntimeSessionPort.ts +0 -20
  203. package/src/types/plugin/PluginAction.ts +0 -10
  204. package/src/types/plugin/PluginCommand.ts +2 -3
  205. package/src/types/plugin/PluginControl.ts +80 -0
  206. package/src/types/plugin/PluginDefinition.ts +1 -1
  207. package/src/types/plugin/PluginRuntime.ts +1 -3
  208. package/src/types/plugin/PluginState.ts +3 -20
  209. package/src/types/rpc/RpcProtocol.ts +4 -4
  210. package/src/types/runtime/agent/AgentContext.ts +1 -9
  211. package/src/types/session/SessionLocalState.ts +1 -1
  212. package/tsconfig.tsbuildinfo +1 -1
  213. package/bin/config/DowncitySchema.d.ts +0 -20
  214. package/bin/config/DowncitySchema.d.ts.map +0 -1
  215. package/bin/config/DowncitySchema.js +0 -160
  216. package/bin/config/DowncitySchema.js.map +0 -1
  217. package/bin/plugin/core/Activation.d.ts +0 -18
  218. package/bin/plugin/core/Activation.d.ts.map +0 -1
  219. package/bin/plugin/core/Activation.js +0 -21
  220. package/bin/plugin/core/Activation.js.map +0 -1
  221. package/bin/plugin/core/Manager.d.ts +0 -7
  222. package/bin/plugin/core/Manager.d.ts.map +0 -1
  223. package/bin/plugin/core/Manager.js +0 -6
  224. package/bin/plugin/core/Manager.js.map +0 -1
  225. package/bin/plugin/types/Plugin.d.ts +0 -15
  226. package/bin/plugin/types/Plugin.d.ts.map +0 -1
  227. package/bin/plugin/types/Plugin.js +0 -9
  228. package/bin/plugin/types/Plugin.js.map +0 -1
  229. package/bin/plugin/types/PluginLifecycle.d.ts +0 -34
  230. package/bin/plugin/types/PluginLifecycle.d.ts.map +0 -1
  231. package/bin/plugin/types/PluginLifecycle.js +0 -9
  232. package/bin/plugin/types/PluginLifecycle.js.map +0 -1
  233. package/bin/plugin/types/PluginState.d.ts +0 -5
  234. package/bin/plugin/types/PluginState.d.ts.map +0 -1
  235. package/bin/plugin/types/PluginState.js +0 -5
  236. package/bin/plugin/types/PluginState.js.map +0 -1
  237. package/bin/plugin/types/Plugins.d.ts +0 -61
  238. package/bin/plugin/types/Plugins.d.ts.map +0 -1
  239. package/bin/plugin/types/Plugins.js +0 -5
  240. package/bin/plugin/types/Plugins.js.map +0 -1
  241. package/bin/session/index.d.ts +0 -15
  242. package/bin/session/index.d.ts.map +0 -1
  243. package/bin/session/index.js +0 -15
  244. package/bin/session/index.js.map +0 -1
  245. package/bin/types/agent/AgentTypes.d.ts +0 -18
  246. package/bin/types/agent/AgentTypes.d.ts.map +0 -1
  247. package/bin/types/agent/AgentTypes.js +0 -10
  248. package/bin/types/agent/AgentTypes.js.map +0 -1
  249. package/bin/utils/logger/Format.d.ts +0 -11
  250. package/bin/utils/logger/Format.d.ts.map +0 -1
  251. package/bin/utils/logger/Format.js +0 -10
  252. package/bin/utils/logger/Format.js.map +0 -1
  253. package/src/config/DowncitySchema.ts +0 -175
  254. package/src/plugin/core/Activation.ts +0 -26
  255. package/src/plugin/core/Manager.ts +0 -17
  256. package/src/plugin/types/Plugin.ts +0 -63
  257. package/src/plugin/types/PluginLifecycle.ts +0 -35
  258. package/src/plugin/types/PluginState.ts +0 -12
  259. package/src/plugin/types/Plugins.ts +0 -67
  260. package/src/session/index.ts +0 -57
  261. package/src/types/agent/AgentTypes.ts +0 -58
  262. package/src/utils/logger/Format.ts +0 -15
@@ -19,28 +19,37 @@ import { Agent } from "../bin/index.js";
19
19
  function create_mock_title_model(title_text) {
20
20
  return new MockLanguageModelV3({
21
21
  modelId: "mock-session-list-title-model",
22
- doGenerate: async () => ({
23
- content: [
24
- {
25
- type: "text",
26
- text: title_text,
27
- },
28
- ],
29
- finishReason: "stop",
30
- usage: {
31
- inputTokens: {
32
- total: 0,
33
- noCache: 0,
34
- cacheRead: 0,
35
- cacheWrite: 0,
22
+ doStream: async () => ({
23
+ stream: new ReadableStream({
24
+ start(controller) {
25
+ controller.enqueue({ type: "stream-start", warnings: [] });
26
+ controller.enqueue({ type: "text-start", id: "title" });
27
+ controller.enqueue({
28
+ type: "text-delta",
29
+ id: "title",
30
+ delta: title_text,
31
+ });
32
+ controller.enqueue({ type: "text-end", id: "title" });
33
+ controller.enqueue({
34
+ type: "finish",
35
+ finishReason: { unified: "stop", raw: "stop" },
36
+ usage: {
37
+ inputTokens: {
38
+ total: 0,
39
+ noCache: 0,
40
+ cacheRead: 0,
41
+ cacheWrite: 0,
42
+ },
43
+ outputTokens: {
44
+ total: 0,
45
+ text: 0,
46
+ reasoning: 0,
47
+ },
48
+ },
49
+ });
50
+ controller.close();
36
51
  },
37
- outputTokens: {
38
- total: 0,
39
- text: 0,
40
- reasoning: 0,
41
- },
42
- },
43
- warnings: [],
52
+ }),
44
53
  }),
45
54
  });
46
55
  }
@@ -81,8 +90,38 @@ test("list_sessions returns persisted title from active session metadata", async
81
90
 
82
91
  try {
83
92
  const page = await collection.list();
93
+ const meta = JSON.parse(
94
+ await fs.readFile(
95
+ path.join(
96
+ agent.path,
97
+ ".downcity",
98
+ "agents",
99
+ encodeURIComponent(agent.id),
100
+ "sessions",
101
+ encodeURIComponent(session.id),
102
+ "messages",
103
+ "meta.json",
104
+ ),
105
+ "utf8",
106
+ ),
107
+ );
84
108
 
85
109
  assert.equal(page.total, 1);
110
+ assert.equal(meta.messageCount, 1);
111
+ assert.equal(meta.previewText, "Need the session list to show the generated title");
112
+ const history_stat = await fs.stat(
113
+ path.join(
114
+ agent.path,
115
+ ".downcity",
116
+ "agents",
117
+ encodeURIComponent(agent.id),
118
+ "sessions",
119
+ encodeURIComponent(session.id),
120
+ "messages",
121
+ "messages.jsonl",
122
+ ),
123
+ );
124
+ assert.equal(meta.historyBytes, history_stat.size);
86
125
  assert.deepEqual(
87
126
  page.items.map((item) => ({
88
127
  sessionId: item.sessionId,
@@ -93,7 +132,7 @@ test("list_sessions returns persisted title from active session metadata", async
93
132
  {
94
133
  sessionId: session.id,
95
134
  title: "列表标题",
96
- messageCount: 2,
135
+ messageCount: 1,
97
136
  },
98
137
  ],
99
138
  );
@@ -102,6 +141,58 @@ test("list_sessions returns persisted title from active session metadata", async
102
141
  }
103
142
  });
104
143
 
144
+ test("list_sessions rebuilds stale metadata after external history changes", async () => {
145
+ const { agent, collection, session } = await create_agent_with_titled_session({
146
+ tmp_prefix: "downcity-agent-session-summary-repair-",
147
+ agent_id: "summary_repair_agent",
148
+ session_id: "summary_repair_session",
149
+ title: "摘要修复",
150
+ first_user_text: "Initial history",
151
+ });
152
+ const messages_dir = path.join(
153
+ agent.path,
154
+ ".downcity",
155
+ "agents",
156
+ encodeURIComponent(agent.id),
157
+ "sessions",
158
+ encodeURIComponent(session.id),
159
+ "messages",
160
+ );
161
+ const messages_path = path.join(messages_dir, "messages.jsonl");
162
+ const meta_path = path.join(messages_dir, "meta.json");
163
+
164
+ try {
165
+ await fs.appendFile(
166
+ messages_path,
167
+ `${JSON.stringify({
168
+ id: "external_assistant",
169
+ role: "assistant",
170
+ metadata: {
171
+ v: 1,
172
+ ts: Date.now(),
173
+ sessionId: session.id,
174
+ source: "egress",
175
+ kind: "normal",
176
+ },
177
+ parts: [{ type: "text", text: "Externally appended history" }],
178
+ })}\n`,
179
+ "utf8",
180
+ );
181
+
182
+ const page = await collection.list();
183
+ const repaired_meta = JSON.parse(await fs.readFile(meta_path, "utf8"));
184
+ const history_stat = await fs.stat(messages_path);
185
+
186
+ assert.equal(page.items[0].messageCount, 2);
187
+ assert.equal(page.items[0].previewText, "Externally appended history");
188
+ assert.equal(repaired_meta.messageCount, 2);
189
+ assert.equal(repaired_meta.previewText, "Externally appended history");
190
+ assert.equal(repaired_meta.historyBytes, history_stat.size);
191
+ } finally {
192
+ await agent.dispose();
193
+ }
194
+ });
195
+
105
196
  test("archive_sessions returns title from archived session metadata", async () => {
106
197
  const { agent, collection, session } = await create_agent_with_titled_session({
107
198
  tmp_prefix: "downcity-agent-archive-list-title-",
@@ -131,7 +222,7 @@ test("archive_sessions returns title from archived session metadata", async () =
131
222
  {
132
223
  sessionId: session.id,
133
224
  title: "归档标题",
134
- messageCount: 2,
225
+ messageCount: 1,
135
226
  },
136
227
  ],
137
228
  );
@@ -10,12 +10,10 @@
10
10
  import type { Tool } from "ai";
11
11
  import type { AgentContext } from "@/types/runtime/agent/AgentContext.js";
12
12
  import type { DowncityConfig } from "@/types/config/DowncityConfig.js";
13
- import type { AgentPlugins } from "@/plugin/types/Plugin.js";
14
- import type {
15
- AgentModel,
16
- AgentOptions,
17
- AgentSessions as AgentSessionsApi,
18
- } from "@/types/agent/AgentTypes.js";
13
+ import type { AgentPlugins } from "@/types/plugin/PluginRuntime.js";
14
+ import type { AgentModel } from "@/model/CityModelAdapter.js";
15
+ import type { AgentOptions } from "@/types/agent/AgentOptions.js";
16
+ import type { AgentSessions as AgentSessionsApi } from "@/types/agent/SessionActor.js";
19
17
  import type {
20
18
  ShellApprovalMode,
21
19
  ShellApprovalDecisionResult,
@@ -25,7 +23,6 @@ import type {
25
23
  ShellApprovalView,
26
24
  Shell,
27
25
  } from "@downcity/shell";
28
- import { PluginRegistry } from "@/plugin/core/PluginRegistry.js";
29
26
  import { Logger } from "@/utils/logger/Logger.js";
30
27
  import { normalizeInstructionInput } from "@/agent/local/AgentInstructions.js";
31
28
  import {
@@ -47,7 +44,6 @@ export class Agent {
47
44
 
48
45
  private readonly logger: Logger;
49
46
  private readonly agentContext: AgentContext;
50
- private readonly pluginRegistry: PluginRegistry;
51
47
  private readonly config: DowncityConfig;
52
48
  private readonly env: Record<string, string>;
53
49
  private readonly defaultModel?: AgentModel;
@@ -84,7 +80,6 @@ export class Agent {
84
80
  this.plugins = assembly.plugins;
85
81
  this.logger = assembly.logger;
86
82
  this.agentContext = assembly.agent_context;
87
- this.pluginRegistry = assembly.plugin_registry;
88
83
  this.config = assembly.config;
89
84
  this.env = assembly.env;
90
85
  this.instruction = assembly.instruction;
@@ -262,7 +257,6 @@ export class Agent {
262
257
  logger: this.logger || assembly.logger,
263
258
  get_agent_context: () => this.agentContext ?? assembly.agent_context,
264
259
  get_instruction: () => this.instruction,
265
- plugin_instances: assembly.plugin_instances,
266
260
  ensure_agent_ready: async () => {
267
261
  await this.backgroundService.ready();
268
262
  },
@@ -8,7 +8,7 @@
8
8
  */
9
9
 
10
10
  import type { DowncityConfig } from "@/types/config/DowncityConfig.js";
11
- import type { AgentSessionSystemBlock } from "@/types/agent/AgentTypes.js";
11
+ import type { AgentSessionSystemBlock } from "@/types/agent/SessionTypes.js";
12
12
  import { DEFAULT_SHIP_PROMPTS } from "@executor/composer/system/default/SystemDomain.js";
13
13
 
14
14
  /**
@@ -11,8 +11,8 @@ import type { LanguageModel, Tool } from "ai";
11
11
  import type { Plugin } from "@/types/plugin/PluginDefinition.js";
12
12
  import { AgentContext } from "@/types/runtime/agent/AgentContext.js";
13
13
  import type { DowncityConfig } from "@/types/config/DowncityConfig.js";
14
- import type { AgentPlugins } from "@/plugin/types/Plugin.js";
15
- import type { AgentOptions } from "@/types/agent/AgentTypes.js";
14
+ import type { AgentPlugins } from "@/types/plugin/PluginRuntime.js";
15
+ import type { AgentOptions } from "@/types/agent/AgentOptions.js";
16
16
  import { Logger } from "@/utils/logger/Logger.js";
17
17
  import { loadDowncityConfig, resolveAgentEnv } from "@/config/Config.js";
18
18
  import { PluginRegistry } from "@/plugin/core/PluginRegistry.js";
@@ -30,7 +30,7 @@ import {
30
30
  import {
31
31
  createPluginTools,
32
32
  } from "@executor/tools/plugin/PluginToolDefinition.js";
33
- import type { AgentManagedSession } from "@/types/agent/AgentTypes.js";
33
+ import type { AgentManagedSession } from "@/types/session/SessionOptions.js";
34
34
  import type { SessionPort } from "@/types/runtime/agent/AgentContext.js";
35
35
  import type { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
36
36
 
@@ -102,11 +102,6 @@ export interface AgentAssemblyResult {
102
102
  */
103
103
  plugin_instances: Map<string, Plugin>;
104
104
 
105
- /**
106
- * 当前 plugin 注册表。
107
- */
108
- plugin_registry: PluginRegistry;
109
-
110
105
  /**
111
106
  * 当前 agent plugin 调用面。
112
107
  */
@@ -238,7 +233,6 @@ export class AgentAssemblyService {
238
233
  instruction,
239
234
  config,
240
235
  plugin_instances,
241
- plugin_registry,
242
236
  plugins,
243
237
  agent_context: agent_context!,
244
238
  ...(shell ? { shell } : {}),
@@ -19,25 +19,25 @@ import type {
19
19
  AgentArchiveSessionsResult,
20
20
  AgentCleanArchiveResult,
21
21
  AgentListSessionsInput,
22
- AgentManagedSession,
23
- AgentModel,
24
- AgentSession,
25
- AgentSessions as AgentSessionsApi,
26
- AgentSessionConstructor,
27
22
  AgentSessionSummaryPage,
28
23
  AgentSessionSystemBlock,
29
- } from "@/types/agent/AgentTypes.js";
24
+ } from "@/types/agent/SessionTypes.js";
25
+ import type { AgentModel } from "@/model/CityModelAdapter.js";
26
+ import type { AgentSessionConstructor } from "@/types/agent/AgentOptions.js";
27
+ import type { AgentSession, AgentSessions as AgentSessionsApi } from "@/types/agent/SessionActor.js";
28
+ import type { AgentManagedSession } from "@/types/session/SessionOptions.js";
30
29
  import { Session } from "@/session/Session.js";
31
30
  import {
32
31
  getSdkAgentArchivedSessionDirPath,
33
32
  getSdkAgentArchivedSessionsDirPath,
34
33
  getSdkAgentSessionDirPath,
34
+ } from "@/session/storage/Paths.js";
35
+ import {
35
36
  listArchivedAgentSessionSummaryPage,
36
37
  listAgentSessionSummaryPage,
37
- } from "@/session/index.js";
38
+ } from "@/session/browse/Browse.js";
38
39
  import type { AgentContext } from "@/types/runtime/agent/AgentContext.js";
39
40
  import type { SessionPort } from "@/types/runtime/agent/AgentContext.js";
40
- import type { Plugin } from "@/types/plugin/PluginDefinition.js";
41
41
  import { createInstructionSystemBlocks } from "@/agent/local/AgentInstructions.js";
42
42
 
43
43
  function decodeMaybe(input: string): string {
@@ -82,11 +82,6 @@ type AgentSessionsOptions = {
82
82
  */
83
83
  get_instruction: () => string[];
84
84
 
85
- /**
86
- * 当前 plugin 实例集合。
87
- */
88
- plugin_instances: Map<string, Plugin>;
89
-
90
85
  /**
91
86
  * 等待当前 Agent 后台能力启动完成。
92
87
  */
@@ -113,7 +108,6 @@ export class AgentSessions implements AgentSessionsApi<AgentSession> {
113
108
  private readonly logger: Logger;
114
109
  private readonly get_agent_context: AgentSessionsOptions["get_agent_context"];
115
110
  private readonly get_instruction: AgentSessionsOptions["get_instruction"];
116
- private readonly plugin_instances: Map<string, Plugin>;
117
111
  private readonly ensure_agent_ready: AgentSessionsOptions["ensure_agent_ready"];
118
112
  private readonly default_model?: AgentModel;
119
113
  private readonly SessionClass: AgentSessionConstructor;
@@ -127,7 +121,6 @@ export class AgentSessions implements AgentSessionsApi<AgentSession> {
127
121
  this.logger = options.logger;
128
122
  this.get_agent_context = options.get_agent_context;
129
123
  this.get_instruction = options.get_instruction;
130
- this.plugin_instances = options.plugin_instances;
131
124
  this.ensure_agent_ready = options.ensure_agent_ready;
132
125
  this.default_model = options.default_model;
133
126
  this.SessionClass = options.SessionClass || Session;
@@ -16,12 +16,13 @@ import type {
16
16
  AgentCreateSessionInput,
17
17
  AgentListSessionsInput,
18
18
  AgentSessionSummaryPage,
19
- AgentSessions,
19
+ } from "@/types/agent/SessionTypes.js";
20
+ import type { AgentSessions, RemoteAgentSession } from "@/types/agent/SessionActor.js";
21
+ import type { RemoteAgentOptions } from "@/types/agent/RemoteAgentOptions.js";
22
+ import type {
20
23
  RemoteAgentPluginActionInput,
21
24
  RemoteAgentPluginActionResult,
22
- RemoteAgentOptions,
23
- RemoteAgentSession,
24
- } from "@/types/agent/AgentTypes.js";
25
+ } from "@/types/agent/RemoteAgentPluginAction.js";
25
26
  import type {
26
27
  ShellApprovalMode,
27
28
  ShellApprovalDecisionResult,
@@ -14,8 +14,8 @@ import type {
14
14
  AgentSessionInfo,
15
15
  AgentSessionSetInput,
16
16
  AgentSessionSystemSnapshot,
17
- RemoteAgentSession,
18
- } from "@/types/agent/AgentTypes.js";
17
+ } from "@/types/agent/SessionTypes.js";
18
+ import type { RemoteAgentSession } from "@/types/agent/SessionActor.js";
19
19
  import { isAgentSessionPromptInputEmpty } from "@/types/sdk/AgentSessionPrompt.js";
20
20
  import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
21
21
  import type {
@@ -171,6 +171,9 @@ export class RemoteSession implements RemoteAgentSession {
171
171
  on_event: (event) => {
172
172
  this.handle_event(event);
173
173
  },
174
+ on_close: (error) => {
175
+ this.handle_event_pump_closed(error);
176
+ },
174
177
  });
175
178
  this.event_pump_running = true;
176
179
  if (!resolved_ready) {
@@ -211,6 +214,22 @@ export class RemoteSession implements RemoteAgentSession {
211
214
  this.event_hub.publish(event);
212
215
  }
213
216
 
217
+ /**
218
+ * 收口底层事件连接断开后的运行态。
219
+ *
220
+ * 关键点(中文)
221
+ * - 连接已经结束时必须清除 running 标记,后续 prompt 才会重新订阅。
222
+ * - 当前未完成 turn 立即失败,避免调用侧永久等待 finished。
223
+ */
224
+ private handle_event_pump_closed(error?: unknown): void {
225
+ this.event_subscription = null;
226
+ this.event_pump_running = false;
227
+ const message = error instanceof Error
228
+ ? error.message
229
+ : String(error || "Remote session events connection closed");
230
+ this.fail_pending_turns(message);
231
+ }
232
+
214
233
  private ensure_turn_lifecycle(turn_id: string): RemoteTurnLifecycle {
215
234
  const cached = this.turns_by_id.get(turn_id);
216
235
  if (cached) return cached;
@@ -20,12 +20,14 @@ import type {
20
20
  AgentSessionInfo,
21
21
  AgentSessionSummaryPage,
22
22
  AgentSessionSystemSnapshot,
23
- AgentSessionStopResult,
23
+ } from "@/types/agent/SessionTypes.js";
24
+ import type {
24
25
  RemoteAgentPluginActionInput,
25
26
  RemoteAgentPluginActionResult,
26
- } from "@/types/agent/AgentTypes.js";
27
+ } from "@/types/agent/RemoteAgentPluginAction.js";
27
28
  import type { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
28
29
  import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
30
+ import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
29
31
  import type {
30
32
  ShellApprovalMode,
31
33
  ShellApprovalDecisionResult,
@@ -61,6 +63,8 @@ export type RemoteSessionTransport = {
61
63
  session_id: string;
62
64
  on_ready: () => void;
63
65
  on_event: (event: AgentSessionEvent) => void;
66
+ /** 底层事件连接结束后的通知;主动关闭不触发。 */
67
+ on_close: (error?: unknown) => void;
64
68
  }): Promise<TransportSubscription>;
65
69
  /** 读取 history。 */
66
70
  records(
@@ -20,12 +20,14 @@ import type {
20
20
  AgentSessionInfo,
21
21
  AgentSessionSummaryPage,
22
22
  AgentSessionSystemSnapshot,
23
- AgentSessionStopResult,
23
+ } from "@/types/agent/SessionTypes.js";
24
+ import type {
24
25
  RemoteAgentPluginActionInput,
25
26
  RemoteAgentPluginActionResult,
26
- } from "@/types/agent/AgentTypes.js";
27
+ } from "@/types/agent/RemoteAgentPluginAction.js";
27
28
  import type { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
28
29
  import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
30
+ import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
29
31
  import type {
30
32
  RemoteAgentTransport,
31
33
  TransportSubscription,
@@ -145,6 +147,7 @@ export class HttpRemoteAgentTransport implements RemoteAgentTransport {
145
147
  session_id: string;
146
148
  on_ready: () => void;
147
149
  on_event: (event: AgentSessionEvent) => void;
150
+ on_close: (error?: unknown) => void;
148
151
  }): Promise<TransportSubscription> {
149
152
  const abort_controller = new AbortController();
150
153
  let resolve_ready!: () => void;
@@ -175,6 +178,10 @@ export class HttpRemoteAgentTransport implements RemoteAgentTransport {
175
178
  reject_ready(error);
176
179
  },
177
180
  on_event: params.on_event,
181
+ }).then((error) => {
182
+ if (!abort_controller.signal.aborted) {
183
+ params.on_close(error);
184
+ }
178
185
  });
179
186
  await ready_promise;
180
187
  return {
@@ -495,11 +502,12 @@ async function consume_http_event_stream(params: {
495
502
  on_ready: () => void;
496
503
  on_ready_error: (error: unknown) => void;
497
504
  on_event: (event: AgentSessionEvent) => void;
498
- }): Promise<void> {
505
+ }): Promise<unknown | undefined> {
499
506
  const decoder = new TextDecoder();
500
507
  const reader = params.body.getReader();
501
508
  let buffered = "";
502
509
  let ready_resolved = false;
510
+ let close_error: unknown;
503
511
 
504
512
  try {
505
513
  while (true) {
@@ -546,6 +554,7 @@ async function consume_http_event_stream(params: {
546
554
  });
547
555
  }
548
556
  } catch (error) {
557
+ close_error = error;
549
558
  if (!params.abort_controller.signal.aborted) {
550
559
  if (!ready_resolved) {
551
560
  params.on_ready_error(error);
@@ -562,6 +571,7 @@ async function consume_http_event_stream(params: {
562
571
  // ignore
563
572
  }
564
573
  }
574
+ return close_error;
565
575
  }
566
576
 
567
577
  function extract_error_message(payload: unknown): string {
@@ -20,12 +20,14 @@ import type {
20
20
  AgentSessionInfo,
21
21
  AgentSessionSummaryPage,
22
22
  AgentSessionSystemSnapshot,
23
- AgentSessionStopResult,
23
+ } from "@/types/agent/SessionTypes.js";
24
+ import type {
24
25
  RemoteAgentPluginActionInput,
25
26
  RemoteAgentPluginActionResult,
26
- } from "@/types/agent/AgentTypes.js";
27
+ } from "@/types/agent/RemoteAgentPluginAction.js";
27
28
  import type { AgentSessionEvent } from "@/types/sdk/AgentSessionEvent.js";
28
29
  import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
30
+ import type { AgentSessionStopResult } from "@/types/sdk/AgentSessionStop.js";
29
31
  import { RpcClient, parse_rpc_url } from "@/rpc/Client.js";
30
32
  import type {
31
33
  RemoteAgentTransport,
@@ -76,11 +78,13 @@ export class RpcRemoteAgentTransport implements RemoteAgentTransport {
76
78
  session_id: string;
77
79
  on_ready: () => void;
78
80
  on_event: (event: AgentSessionEvent) => void;
81
+ on_close: (error?: unknown) => void;
79
82
  }): Promise<TransportSubscription> {
80
83
  const subscription = await this.client.subscribe_session({
81
84
  session_id: params.session_id,
82
85
  on_ready: params.on_ready,
83
86
  on_event: params.on_event,
87
+ on_close: params.on_close,
84
88
  });
85
89
  return {
86
90
  close: async () => {
@@ -86,10 +86,6 @@ type ExecutorOptions = {
86
86
  */
87
87
  contextComposer?: SessionContextComposer;
88
88
 
89
- /**
90
- * session 更新后的异步回调。
91
- */
92
- runAfterSessionUpdated?: (sessionId: string) => Promise<void>;
93
89
  };
94
90
 
95
91
  /**
@@ -139,13 +135,10 @@ export class Executor implements SessionExecutor {
139
135
  this.historyWriter = new SessionHistoryWriter({
140
136
  sessionId,
141
137
  getHistoryStore: () => this.getHistoryStore(),
142
- runAfterSessionUpdated: options.runAfterSessionUpdated,
143
138
  });
144
139
  this.inflight_service = new ExecutorInflightService({
145
140
  session_id: this.sessionId,
146
141
  history_store: this.historyStore,
147
- run_after_session_updated_async: async () =>
148
- await this.afterSessionUpdatedAsync(),
149
142
  });
150
143
  this.recovery_policy = new ExecutorRecoveryPolicy({
151
144
  compaction_composer: this.compactionComposer,
@@ -196,22 +189,6 @@ export class Executor implements SessionExecutor {
196
189
  return this;
197
190
  }
198
191
 
199
- /**
200
- * 清理当前 session 的执行器运行态。
201
- *
202
- * 关键点(中文)
203
- * - 当前 Executor 不缓存模型实例,模型每轮 run 都从 `getModel()` 读取。
204
- * - history 是事实源,不应随着执行态一起丢失。
205
- */
206
- clearExecutor(): void {}
207
-
208
- /**
209
- * 触发 session 更新后的异步回调。
210
- */
211
- async afterSessionUpdatedAsync(): Promise<void> {
212
- await this.historyWriter.afterSessionUpdatedAsync();
213
- }
214
-
215
192
  /**
216
193
  * 追加一条 user 消息。
217
194
  */
@@ -26,7 +26,6 @@ import type {
26
26
  import {
27
27
  is_session_message_record,
28
28
  } from "@/executor/types/SessionRecords.js";
29
- import type { SessionHistoryMetaV1 } from "@/executor/types/SessionHistoryMeta.js";
30
29
  import {
31
30
  append_session_compaction_file_operations,
32
31
  build_initial_session_compaction_prompt,
@@ -57,8 +56,7 @@ type SessionCompactDeps = {
57
56
  }) => SessionRecordV1;
58
57
  getArchiveDirPath: () => string;
59
58
  getMessagesFilePath: () => string;
60
- readMetaUnsafe: () => Promise<SessionHistoryMetaV1>;
61
- writeMetaUnsafe: (next: SessionHistoryMetaV1) => Promise<void>;
59
+ writeHistorySummaryUnsafe: (records: SessionRecordV1[]) => Promise<void>;
62
60
  };
63
61
 
64
62
  /**
@@ -259,11 +257,7 @@ export async function compactSessionMessagesIfNeeded(
259
257
  await fs.writeFile(tmp, next.map((m) => JSON.stringify(m)).join("\n") + "\n", "utf8");
260
258
  await fs.move(tmp, messagesPath, { overwrite: true });
261
259
 
262
- const prevMeta = await deps.readMetaUnsafe();
263
- await deps.writeMetaUnsafe({
264
- ...prevMeta,
265
- updatedAt: Date.now(),
266
- });
260
+ await deps.writeHistorySummaryUnsafe(next);
267
261
  });
268
262
 
269
263
  if (action_started) {