@downcity/agent 1.1.228 → 1.1.236

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 (221) hide show
  1. package/bin/agent/local/Agent.d.ts +6 -1
  2. package/bin/agent/local/Agent.d.ts.map +1 -1
  3. package/bin/agent/local/Agent.js +30 -3
  4. package/bin/agent/local/Agent.js.map +1 -1
  5. package/bin/agent/local/services/AgentSessions.d.ts +23 -0
  6. package/bin/agent/local/services/AgentSessions.d.ts.map +1 -1
  7. package/bin/agent/local/services/AgentSessions.js +44 -0
  8. package/bin/agent/local/services/AgentSessions.js.map +1 -1
  9. package/bin/agent/remote/RemoteSession.d.ts +2 -0
  10. package/bin/agent/remote/RemoteSession.d.ts.map +1 -1
  11. package/bin/agent/remote/RemoteSession.js +4 -0
  12. package/bin/agent/remote/RemoteSession.js.map +1 -1
  13. package/bin/agent/remote/RemoteTransport.d.ts +2 -0
  14. package/bin/agent/remote/RemoteTransport.d.ts.map +1 -1
  15. package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts +1 -0
  16. package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts.map +1 -1
  17. package/bin/agent/remote/transports/HttpRemoteAgentTransport.js +11 -7
  18. package/bin/agent/remote/transports/HttpRemoteAgentTransport.js.map +1 -1
  19. package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts +1 -0
  20. package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts.map +1 -1
  21. package/bin/agent/remote/transports/RpcRemoteAgentTransport.js +3 -0
  22. package/bin/agent/remote/transports/RpcRemoteAgentTransport.js.map +1 -1
  23. package/bin/executor/Executor.d.ts +43 -0
  24. package/bin/executor/Executor.d.ts.map +1 -1
  25. package/bin/executor/Executor.js +127 -7
  26. package/bin/executor/Executor.js.map +1 -1
  27. package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts +10 -0
  28. package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts.map +1 -1
  29. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.d.ts +0 -10
  30. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.d.ts.map +1 -1
  31. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js +4 -34
  32. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js.map +1 -1
  33. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts +1 -3
  34. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts.map +1 -1
  35. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js +7 -59
  36. package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js.map +1 -1
  37. package/bin/executor/core-engine/CoreEngineContextCompaction.d.ts +38 -0
  38. package/bin/executor/core-engine/CoreEngineContextCompaction.d.ts.map +1 -0
  39. package/bin/executor/core-engine/CoreEngineContextCompaction.js +392 -0
  40. package/bin/executor/core-engine/CoreEngineContextCompaction.js.map +1 -0
  41. package/bin/executor/core-engine/CoreEngineMessageState.d.ts +15 -0
  42. package/bin/executor/core-engine/CoreEngineMessageState.d.ts.map +1 -1
  43. package/bin/executor/core-engine/CoreEngineMessageState.js +20 -0
  44. package/bin/executor/core-engine/CoreEngineMessageState.js.map +1 -1
  45. package/bin/executor/core-engine/CoreEngineRunner.d.ts +15 -0
  46. package/bin/executor/core-engine/CoreEngineRunner.d.ts.map +1 -1
  47. package/bin/executor/core-engine/CoreEngineRunner.js +150 -35
  48. package/bin/executor/core-engine/CoreEngineRunner.js.map +1 -1
  49. package/bin/executor/store/history/SessionHistoryStore.d.ts +7 -23
  50. package/bin/executor/store/history/SessionHistoryStore.d.ts.map +1 -1
  51. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts.map +1 -1
  52. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +2 -4
  53. package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +1 -1
  54. package/bin/executor/tools/plugin/PluginToolBridge.d.ts.map +1 -1
  55. package/bin/executor/tools/plugin/PluginToolBridge.js +4 -2
  56. package/bin/executor/tools/plugin/PluginToolBridge.js.map +1 -1
  57. package/bin/executor/types/SessionRun.d.ts +8 -0
  58. package/bin/executor/types/SessionRun.d.ts.map +1 -1
  59. package/bin/index.d.ts +3 -2
  60. package/bin/index.d.ts.map +1 -1
  61. package/bin/index.js +2 -2
  62. package/bin/index.js.map +1 -1
  63. package/bin/model/CityModelAdapter.d.ts +6 -0
  64. package/bin/model/CityModelAdapter.d.ts.map +1 -1
  65. package/bin/model/CityModelAdapter.js +13 -0
  66. package/bin/model/CityModelAdapter.js.map +1 -1
  67. package/bin/plugin/core/PluginLocalExecution.js +3 -3
  68. package/bin/plugin/core/PluginLocalExecution.js.map +1 -1
  69. package/bin/plugin/core/PluginRegistry.d.ts +41 -2
  70. package/bin/plugin/core/PluginRegistry.d.ts.map +1 -1
  71. package/bin/plugin/core/PluginRegistry.js +145 -6
  72. package/bin/plugin/core/PluginRegistry.js.map +1 -1
  73. package/bin/rpc/Client.d.ts +4 -0
  74. package/bin/rpc/Client.d.ts.map +1 -1
  75. package/bin/rpc/Client.js +11 -0
  76. package/bin/rpc/Client.js.map +1 -1
  77. package/bin/session/Session.d.ts +15 -1
  78. package/bin/session/Session.d.ts.map +1 -1
  79. package/bin/session/Session.js +83 -11
  80. package/bin/session/Session.js.map +1 -1
  81. package/bin/session/SessionSystemBuilder.d.ts.map +1 -1
  82. package/bin/session/SessionSystemBuilder.js +3 -1
  83. package/bin/session/SessionSystemBuilder.js.map +1 -1
  84. package/bin/session/browse/Browse.d.ts +0 -8
  85. package/bin/session/browse/Browse.d.ts.map +1 -1
  86. package/bin/session/browse/Browse.js +72 -57
  87. package/bin/session/browse/Browse.js.map +1 -1
  88. package/bin/session/recorder/JsonlSessionMessageStore.d.ts +69 -16
  89. package/bin/session/recorder/JsonlSessionMessageStore.d.ts.map +1 -1
  90. package/bin/session/recorder/JsonlSessionMessageStore.js +283 -60
  91. package/bin/session/recorder/JsonlSessionMessageStore.js.map +1 -1
  92. package/bin/session/recorder/SessionRecorder.d.ts +20 -2
  93. package/bin/session/recorder/SessionRecorder.d.ts.map +1 -1
  94. package/bin/session/recorder/SessionRecorder.js +91 -46
  95. package/bin/session/recorder/SessionRecorder.js.map +1 -1
  96. package/bin/session/recorder/SessionRecorderCompaction.d.ts +3 -3
  97. package/bin/session/recorder/SessionRecorderCompaction.d.ts.map +1 -1
  98. package/bin/session/recorder/SessionRecorderCompaction.js +118 -88
  99. package/bin/session/recorder/SessionRecorderCompaction.js.map +1 -1
  100. package/bin/session/recorder/SessionRecorderHistoryStore.d.ts +2 -2
  101. package/bin/session/recorder/SessionRecorderHistoryStore.d.ts.map +1 -1
  102. package/bin/session/recorder/SessionRecorderHistoryStore.js +31 -36
  103. package/bin/session/recorder/SessionRecorderHistoryStore.js.map +1 -1
  104. package/bin/session/runtime/SessionPromptRuntime.d.ts +21 -1
  105. package/bin/session/runtime/SessionPromptRuntime.d.ts.map +1 -1
  106. package/bin/session/runtime/SessionPromptRuntime.js +65 -8
  107. package/bin/session/runtime/SessionPromptRuntime.js.map +1 -1
  108. package/bin/session/services/SessionStateService.d.ts +19 -1
  109. package/bin/session/services/SessionStateService.d.ts.map +1 -1
  110. package/bin/session/services/SessionStateService.js +70 -40
  111. package/bin/session/services/SessionStateService.js.map +1 -1
  112. package/bin/session/services/SessionTurnService.d.ts +15 -0
  113. package/bin/session/services/SessionTurnService.d.ts.map +1 -1
  114. package/bin/session/services/SessionTurnService.js +104 -7
  115. package/bin/session/services/SessionTurnService.js.map +1 -1
  116. package/bin/session/services/SessionViewService.d.ts +1 -5
  117. package/bin/session/services/SessionViewService.d.ts.map +1 -1
  118. package/bin/session/services/SessionViewService.js +4 -34
  119. package/bin/session/services/SessionViewService.js.map +1 -1
  120. package/bin/session/storage/Paths.d.ts +3 -15
  121. package/bin/session/storage/Paths.d.ts.map +1 -1
  122. package/bin/session/storage/Paths.js +5 -21
  123. package/bin/session/storage/Paths.js.map +1 -1
  124. package/bin/types/agent/SessionActor.d.ts +8 -0
  125. package/bin/types/agent/SessionActor.d.ts.map +1 -1
  126. package/bin/types/agent/SessionTypes.d.ts +2 -24
  127. package/bin/types/agent/SessionTypes.d.ts.map +1 -1
  128. package/bin/types/executor/SessionRunContext.d.ts +29 -0
  129. package/bin/types/executor/SessionRunContext.d.ts.map +1 -1
  130. package/bin/types/plugin/PluginRuntime.d.ts +59 -2
  131. package/bin/types/plugin/PluginRuntime.d.ts.map +1 -1
  132. package/bin/types/plugin/PluginState.d.ts +10 -0
  133. package/bin/types/plugin/PluginState.d.ts.map +1 -1
  134. package/bin/types/rpc/RpcProtocol.d.ts +10 -0
  135. package/bin/types/rpc/RpcProtocol.d.ts.map +1 -1
  136. package/bin/types/runtime/agent/AgentContext.d.ts +17 -5
  137. package/bin/types/runtime/agent/AgentContext.d.ts.map +1 -1
  138. package/bin/types/runtime/agent/AgentContext.js +29 -6
  139. package/bin/types/runtime/agent/AgentContext.js.map +1 -1
  140. package/bin/types/session/SessionLocalState.d.ts +8 -0
  141. package/bin/types/session/SessionLocalState.d.ts.map +1 -1
  142. package/bin/types/session/SessionMessage.d.ts +16 -12
  143. package/bin/types/session/SessionMessage.d.ts.map +1 -1
  144. package/bin/types/session/SessionMutation.d.ts +1 -1
  145. package/bin/types/session/SessionMutation.js +1 -1
  146. package/bin/types/session/SessionOptions.d.ts +16 -0
  147. package/bin/types/session/SessionOptions.d.ts.map +1 -1
  148. package/bin/types/session/SessionQueueCommand.d.ts +68 -0
  149. package/bin/types/session/SessionQueueCommand.d.ts.map +1 -0
  150. package/bin/types/session/SessionQueueCommand.js +10 -0
  151. package/bin/types/session/SessionQueueCommand.js.map +1 -0
  152. package/bin/types/session/SessionSegment.d.ts +57 -0
  153. package/bin/types/session/SessionSegment.d.ts.map +1 -0
  154. package/bin/types/session/SessionSegment.js +8 -0
  155. package/bin/types/session/SessionSegment.js.map +1 -0
  156. package/bin/utils/logger/Logger.d.ts +7 -9
  157. package/bin/utils/logger/Logger.d.ts.map +1 -1
  158. package/bin/utils/logger/Logger.js +11 -9
  159. package/bin/utils/logger/Logger.js.map +1 -1
  160. package/package.json +3 -3
  161. package/scripts/city-model-tool-loop.test.mjs +32 -0
  162. package/scripts/core-engine-context-compaction.test.mjs +411 -0
  163. package/scripts/logger-isolation.test.mjs +55 -0
  164. package/scripts/multi-agent-plugin-isolation.test.mjs +289 -0
  165. package/scripts/plugin-tool-bridge.test.mjs +52 -0
  166. package/scripts/remote-session-reconnect.test.mjs +18 -0
  167. package/scripts/session-action-message.test.mjs +59 -13
  168. package/scripts/session-compaction-context-window.test.mjs +96 -0
  169. package/scripts/session-config-turn-boundary.test.mjs +278 -0
  170. package/scripts/session-list-title.test.mjs +21 -3
  171. package/scripts/session-prompt-runtime.test.mjs +93 -0
  172. package/scripts/session-recorder.test.mjs +335 -15
  173. package/src/agent/local/Agent.ts +34 -3
  174. package/src/agent/local/services/AgentSessions.ts +61 -0
  175. package/src/agent/remote/RemoteSession.ts +5 -0
  176. package/src/agent/remote/RemoteTransport.ts +2 -0
  177. package/src/agent/remote/transports/HttpRemoteAgentTransport.ts +15 -5
  178. package/src/agent/remote/transports/RpcRemoteAgentTransport.ts +4 -0
  179. package/src/executor/Executor.ts +161 -7
  180. package/src/executor/composer/compaction/SessionCompactionComposer.ts +12 -0
  181. package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.ts +4 -55
  182. package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.ts +8 -66
  183. package/src/executor/core-engine/CoreEngineContextCompaction.ts +477 -0
  184. package/src/executor/core-engine/CoreEngineMessageState.ts +29 -0
  185. package/src/executor/core-engine/CoreEngineRunner.ts +211 -43
  186. package/src/executor/store/history/SessionHistoryStore.ts +7 -26
  187. package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +2 -4
  188. package/src/executor/tools/plugin/PluginToolBridge.ts +4 -2
  189. package/src/executor/types/SessionRun.ts +9 -0
  190. package/src/index.ts +9 -1
  191. package/src/model/CityModelAdapter.ts +15 -0
  192. package/src/plugin/core/PluginLocalExecution.ts +3 -3
  193. package/src/plugin/core/PluginRegistry.ts +187 -6
  194. package/src/rpc/Client.ts +12 -0
  195. package/src/session/Session.ts +97 -11
  196. package/src/session/SessionSystemBuilder.ts +4 -1
  197. package/src/session/browse/Browse.ts +73 -69
  198. package/src/session/recorder/JsonlSessionMessageStore.ts +378 -60
  199. package/src/session/recorder/SessionRecorder.ts +116 -49
  200. package/src/session/recorder/SessionRecorderCompaction.ts +131 -108
  201. package/src/session/recorder/SessionRecorderHistoryStore.ts +29 -49
  202. package/src/session/runtime/SessionPromptRuntime.ts +86 -10
  203. package/src/session/services/SessionStateService.ts +89 -45
  204. package/src/session/services/SessionTurnService.ts +112 -7
  205. package/src/session/services/SessionViewService.ts +4 -50
  206. package/src/session/storage/Paths.ts +5 -38
  207. package/src/types/agent/SessionActor.ts +9 -0
  208. package/src/types/agent/SessionTypes.ts +2 -24
  209. package/src/types/executor/SessionRunContext.ts +34 -0
  210. package/src/types/plugin/PluginRuntime.ts +63 -2
  211. package/src/types/plugin/PluginState.ts +10 -0
  212. package/src/types/rpc/RpcProtocol.ts +11 -0
  213. package/src/types/runtime/agent/AgentContext.ts +32 -7
  214. package/src/types/session/SessionLocalState.ts +9 -0
  215. package/src/types/session/SessionMessage.ts +16 -12
  216. package/src/types/session/SessionMutation.ts +1 -1
  217. package/src/types/session/SessionOptions.ts +21 -0
  218. package/src/types/session/SessionQueueCommand.ts +78 -0
  219. package/src/types/session/SessionSegment.ts +62 -0
  220. package/src/utils/logger/Logger.ts +10 -10
  221. package/tsconfig.tsbuildinfo +1 -1
@@ -13,6 +13,8 @@ import type { Plugin } from "@/types/plugin/PluginDefinition.js";
13
13
  import type { PluginActionResult } from "@/types/plugin/PluginAction.js";
14
14
  import type {
15
15
  AgentPlugins,
16
+ AgentPluginExecutionLease,
17
+ AgentPluginExecutionRuntime,
16
18
  PluginAvailability,
17
19
  PluginActionReadView,
18
20
  PluginReadView,
@@ -45,6 +47,9 @@ function create_record(plugin: Plugin): PluginRuntimeRecord {
45
47
  updated_at: current_time,
46
48
  chain: Promise.resolve(),
47
49
  lifecycle_started: false,
50
+ active_execution_leases: 0,
51
+ retired: false,
52
+ retirement_started: false,
48
53
  };
49
54
  }
50
55
 
@@ -101,6 +106,15 @@ export class PluginRegistry implements AgentPlugins {
101
106
 
102
107
  private readonly records = new Map<string, PluginRuntimeRecord>();
103
108
 
109
+ private readonly retired_records = new Set<PluginRuntimeRecord>();
110
+
111
+ private change_listener?: (input: {
112
+ /** 当前修改是注册还是卸载。 */
113
+ type: "register" | "unregister";
114
+ /** 当前修改的 plugin 名称。 */
115
+ plugin_name: string;
116
+ }) => void;
117
+
104
118
  constructor(params: {
105
119
  contextResolver: ContextResolver;
106
120
  hookRegistry: HookRegistry;
@@ -111,6 +125,13 @@ export class PluginRegistry implements AgentPlugins {
111
125
  this.pluginInstances = params.pluginInstances;
112
126
  }
113
127
 
128
+ /**
129
+ * 设置 Agent 内部配置修改监听器。
130
+ */
131
+ set_change_listener(listener: PluginRegistry["change_listener"]): void {
132
+ this.change_listener = listener;
133
+ }
134
+
114
135
  /**
115
136
  * 注册单个 plugin。
116
137
  *
@@ -134,6 +155,7 @@ export class PluginRegistry implements AgentPlugins {
134
155
 
135
156
  try {
136
157
  await this.start_record(record);
158
+ this.change_listener?.({ type: "register", plugin_name: key });
137
159
  return to_plugin_snapshot(record);
138
160
  } catch (error) {
139
161
  this.unregister_hooks(key);
@@ -167,7 +189,12 @@ export class PluginRegistry implements AgentPlugins {
167
189
  }
168
190
 
169
191
  /**
170
- * 卸载指定 plugin。
192
+ * 从 configured registry 卸载指定 plugin。
193
+ *
194
+ * 关键点(中文)
195
+ * - configured registry、hooks 与直接调用入口立即移除。
196
+ * - lifecycle.stop 等当前活跃 Session step 的 execution lease 全部释放后执行。
197
+ * - 该方法返回配置修改结果,不等待仍在运行的 step 结束。
171
198
  */
172
199
  async unregister(pluginName: string): Promise<boolean> {
173
200
  const key = normalize_plugin_name(pluginName);
@@ -175,10 +202,11 @@ export class PluginRegistry implements AgentPlugins {
175
202
  const record = this.records.get(key);
176
203
  if (!record) return false;
177
204
 
178
- await this.stop_record(record);
179
205
  this.unregister_hooks(key);
180
206
  this.records.delete(key);
181
207
  this.pluginInstances.delete(key);
208
+ this.retire_record(record);
209
+ this.change_listener?.({ type: "unregister", plugin_name: key });
182
210
  return true;
183
211
  }
184
212
 
@@ -205,6 +233,10 @@ export class PluginRegistry implements AgentPlugins {
205
233
  for (const name of Array.from(this.records.keys())) {
206
234
  await this.unregister(name);
207
235
  }
236
+ const retirements = Array.from(this.retired_records)
237
+ .map((record) => record.retirement_promise)
238
+ .filter((promise): promise is Promise<void> => Boolean(promise));
239
+ await Promise.all(retirements);
208
240
  }
209
241
 
210
242
  /**
@@ -381,11 +413,25 @@ export class PluginRegistry implements AgentPlugins {
381
413
  plugin?: string;
382
414
  action?: string;
383
415
  }): PluginReadView | { plugins: PluginView[] } {
416
+ return this.read_from_records(this.records, params);
417
+ }
418
+
419
+ /**
420
+ * 从指定记录视图读取 plugin/action metadata。
421
+ */
422
+ private read_from_records(
423
+ records: ReadonlyMap<string, PluginRuntimeRecord>,
424
+ params: { plugin?: string; action?: string },
425
+ ): PluginReadView | { plugins: PluginView[] } {
384
426
  const pluginName = normalize_plugin_name(params.plugin || "");
385
427
  if (!pluginName) {
386
- return { plugins: this.list() };
428
+ return {
429
+ plugins: Array.from(records.values())
430
+ .map((record) => toPluginView(record.plugin))
431
+ .sort((left, right) => left.name.localeCompare(right.name)),
432
+ };
387
433
  }
388
- const plugin = this.get(pluginName);
434
+ const plugin = records.get(pluginName)?.plugin || null;
389
435
  if (!plugin) {
390
436
  return {
391
437
  name: pluginName,
@@ -470,8 +516,22 @@ export class PluginRegistry implements AgentPlugins {
470
516
  action: string;
471
517
  payload?: JsonValue;
472
518
  }): Promise<PluginActionResult<JsonValue>> {
519
+ return await this.run_action_from_records(this.records, params);
520
+ }
521
+
522
+ /**
523
+ * 从指定记录视图运行 plugin action。
524
+ */
525
+ private async run_action_from_records(
526
+ records: ReadonlyMap<string, PluginRuntimeRecord>,
527
+ params: {
528
+ plugin: string;
529
+ action: string;
530
+ payload?: JsonValue;
531
+ },
532
+ ): Promise<PluginActionResult<JsonValue>> {
473
533
  const key = normalize_plugin_name(params.plugin);
474
- const record = this.records.get(key);
534
+ const record = records.get(key);
475
535
  if (!record) {
476
536
  return {
477
537
  success: false,
@@ -536,9 +596,18 @@ export class PluginRegistry implements AgentPlugins {
536
596
  * 读取当前生效的 plugin system blocks。
537
597
  */
538
598
  async systemBlocks(): Promise<AgentSessionSystemBlock[]> {
599
+ return await this.system_blocks_from_records(this.records);
600
+ }
601
+
602
+ /**
603
+ * 从指定记录视图解析 plugin system blocks。
604
+ */
605
+ private async system_blocks_from_records(
606
+ records: ReadonlyMap<string, PluginRuntimeRecord>,
607
+ ): Promise<AgentSessionSystemBlock[]> {
539
608
  const context = this.contextResolver();
540
609
  const out: AgentSessionSystemBlock[] = [];
541
- for (const record of this.records.values()) {
610
+ for (const record of records.values()) {
542
611
  const plugin = record.plugin;
543
612
  if (record.state !== "ready") continue;
544
613
  if (typeof plugin.system !== "function") continue;
@@ -560,4 +629,116 @@ export class PluginRegistry implements AgentPlugins {
560
629
  }
561
630
  return out;
562
631
  }
632
+
633
+ /**
634
+ * 创建当前 configured registry 的 Session step 执行视图。
635
+ */
636
+ execution_view(): AgentPluginExecutionRuntime {
637
+ const records = new Map(this.records);
638
+ return {
639
+ read: (params) => this.read_from_records(records, params),
640
+ runAction: async (params) =>
641
+ await this.run_action_from_records(records, params),
642
+ systemBlocks: async () =>
643
+ await this.system_blocks_from_records(records),
644
+ acquire: () => this.acquire_execution_view(records),
645
+ };
646
+ }
647
+
648
+ /**
649
+ * 为单次 Session step 获取 Plugin execution lease。
650
+ */
651
+ private acquire_execution_view(
652
+ records: ReadonlyMap<string, PluginRuntimeRecord>,
653
+ ): AgentPluginExecutionLease {
654
+ const leased_records = new Map<string, PluginRuntimeRecord>();
655
+ for (const [name, record] of records) {
656
+ if (
657
+ record.retired ||
658
+ record.state !== "ready" ||
659
+ !record.lifecycle_started
660
+ ) {
661
+ continue;
662
+ }
663
+ record.active_execution_leases += 1;
664
+ leased_records.set(name, record);
665
+ }
666
+
667
+ let released = false;
668
+ return {
669
+ read: (params) => this.read_from_records(leased_records, params),
670
+ runAction: async (params) =>
671
+ await this.run_action_from_records(leased_records, params),
672
+ systemBlocks: async () =>
673
+ await this.system_blocks_from_records(leased_records),
674
+ release: async () => {
675
+ if (released) return;
676
+ released = true;
677
+ const retirements: Promise<void>[] = [];
678
+ for (const record of leased_records.values()) {
679
+ record.active_execution_leases = Math.max(
680
+ 0,
681
+ record.active_execution_leases - 1,
682
+ );
683
+ this.try_finalize_retired_record(record);
684
+ if (record.retired && record.retirement_promise) {
685
+ retirements.push(record.retirement_promise);
686
+ }
687
+ }
688
+ await Promise.all(retirements);
689
+ },
690
+ };
691
+ }
692
+
693
+ /**
694
+ * 把已移出 configured registry 的 Plugin 标记为等待释放。
695
+ */
696
+ private retire_record(record: PluginRuntimeRecord): void {
697
+ if (record.retired) return;
698
+ record.retired = true;
699
+ let resolve_retirement!: () => void;
700
+ record.retirement_promise = new Promise<void>((resolve) => {
701
+ resolve_retirement = resolve;
702
+ });
703
+ record.resolve_retirement = resolve_retirement;
704
+ this.retired_records.add(record);
705
+ this.try_finalize_retired_record(record);
706
+ }
707
+
708
+ /**
709
+ * 在最后一个 execution lease 释放后停止退休 Plugin。
710
+ */
711
+ private try_finalize_retired_record(record: PluginRuntimeRecord): void {
712
+ if (
713
+ !record.retired ||
714
+ record.retirement_started ||
715
+ record.active_execution_leases > 0
716
+ ) {
717
+ return;
718
+ }
719
+ record.retirement_started = true;
720
+ void (async () => {
721
+ try {
722
+ await this.stop_record(record);
723
+ } catch (error) {
724
+ update_record_state(record, "error", String(error));
725
+ try {
726
+ await this.contextResolver().logger.log(
727
+ "error",
728
+ "[plugin] lifecycle.stop failed after execution release",
729
+ {
730
+ plugin: record.plugin.name,
731
+ error: String(error),
732
+ },
733
+ );
734
+ } catch {
735
+ // 退休清理不能因日志失败再次中断。
736
+ }
737
+ } finally {
738
+ this.retired_records.delete(record);
739
+ record.resolve_retirement?.();
740
+ delete record.resolve_retirement;
741
+ }
742
+ })();
743
+ }
563
744
  }
package/src/rpc/Client.ts CHANGED
@@ -217,6 +217,18 @@ export class RpcClient {
217
217
  return data.result;
218
218
  }
219
219
 
220
+ /**
221
+ * 把一次显式历史压缩加入远程 Session 的有序输入队列。
222
+ */
223
+ async compact_session(session_id: string): Promise<void> {
224
+ await this.request<{ queued: true }>({
225
+ method: "sdk.sessions.compact",
226
+ params: {
227
+ sessionId: session_id,
228
+ },
229
+ });
230
+ }
231
+
220
232
  /**
221
233
  * 读取 session records。
222
234
  */
@@ -4,7 +4,7 @@
4
4
  * 关键点(中文)
5
5
  * - 面向 `new Agent(...)` 的本地会话使用场景。
6
6
  * - 对外保留稳定 Session facade,把状态、turn、view 逻辑下沉到独立 service。
7
- * - 内部继续复用 `Executor` / `JsonlSessionHistoryStore` / Composer 体系。
7
+ * - 内部使用 `SessionRecorder` 统一管理 Active、Segment 与流式 Assistant 草稿。
8
8
  */
9
9
 
10
10
  import { Executor } from "@executor/Executor.js";
@@ -55,6 +55,7 @@ import { SessionStateService } from "@/session/services/SessionStateService.js";
55
55
  import { SessionTurnService } from "@/session/services/SessionTurnService.js";
56
56
  import { SessionViewService } from "@/session/services/SessionViewService.js";
57
57
  import type { SessionLocalState } from "@/types/session/SessionLocalState.js";
58
+ import type { AgentSessionCommand } from "@/types/session/SessionQueueCommand.js";
58
59
  import type {
59
60
  SessionComposerFactoryContext,
60
61
  SessionComposerInput,
@@ -65,6 +66,7 @@ import type { SessionContextComposer } from "@/executor/composer/context/Session
65
66
  import type { SessionHistoryComposer } from "@/executor/composer/history/SessionHistoryComposer.js";
66
67
  import type { SessionSystemComposer } from "@/executor/composer/system/SessionSystemComposer.js";
67
68
  import type { SessionOptions } from "@/types/session/SessionOptions.js";
69
+ import type { AgentPluginExecutionRuntime } from "@/types/plugin/PluginRuntime.js";
68
70
 
69
71
  /**
70
72
  * SDK 本地 Session。
@@ -92,6 +94,11 @@ export class Session implements AgentSession {
92
94
  private readonly set_approval_mode_hook: SessionOptions["set_approval_mode"];
93
95
  private readonly resolve_approval_hook: SessionOptions["resolve_approval"];
94
96
  private readonly localState: SessionLocalState;
97
+ private readonly getAgentEnv: SessionOptions["getAgentEnv"];
98
+ private readonly get_agent_plugins: SessionOptions["get_agent_plugins"];
99
+ private effective_instruction_system_blocks: AgentSessionSystemBlock[];
100
+ private effective_agent_env: Record<string, string>;
101
+ private effective_agent_plugins: AgentPluginExecutionRuntime;
95
102
  private readonly stateService: SessionStateService;
96
103
  private readonly turnService: SessionTurnService;
97
104
  private readonly viewService: SessionViewService<this>;
@@ -104,6 +111,13 @@ export class Session implements AgentSession {
104
111
  this.tools = options.tools;
105
112
  this.logger = options.logger;
106
113
  this.getInstructionSystemBlocks = options.getInstructionSystemBlocks;
114
+ this.getAgentEnv = options.getAgentEnv;
115
+ this.get_agent_plugins = options.get_agent_plugins;
116
+ this.effective_instruction_system_blocks = options
117
+ .getInstructionSystemBlocks()
118
+ .map((block) => ({ ...block }));
119
+ this.effective_agent_env = { ...options.getAgentEnv() };
120
+ this.effective_agent_plugins = options.get_agent_plugins();
107
121
  this.getManagedPluginSystemBlocks = options.getManagedPluginSystemBlocks;
108
122
  this.getPluginSystemBlocks = options.getPluginSystemBlocks;
109
123
  this.ensureConfiguredHook = options.ensureConfigured;
@@ -187,9 +201,11 @@ export class Session implements AgentSession {
187
201
  state_service: this.stateService,
188
202
  logger: this.logger,
189
203
  is_executing: () => this.isExecuting(),
190
- get_instruction_system_blocks: this.getInstructionSystemBlocks,
204
+ get_instruction_system_blocks: () =>
205
+ this.effective_instruction_system_blocks.map((block) => ({ ...block })),
191
206
  get_managed_plugin_system_blocks: this.getManagedPluginSystemBlocks,
192
- get_plugin_system_blocks: this.getPluginSystemBlocks,
207
+ get_plugin_system_blocks: async () =>
208
+ await this.effective_agent_plugins.systemBlocks(),
193
209
  ...(this.composers?.systemComposer
194
210
  ? { custom_system_composer: system_composer }
195
211
  : {}),
@@ -226,7 +242,10 @@ export class Session implements AgentSession {
226
242
  * 写入当前 session 默认配置。
227
243
  */
228
244
  async set(input: AgentSessionSetInput): Promise<void> {
229
- await this.stateService.set(input);
245
+ const configured = await this.stateService.set(input);
246
+ if (configured.command) {
247
+ this.turnService.enqueue_command(configured.command);
248
+ }
230
249
  }
231
250
 
232
251
  /**
@@ -243,6 +262,55 @@ export class Session implements AgentSession {
243
262
  return await this.turnService.stop();
244
263
  }
245
264
 
265
+ /**
266
+ * 把一次显式历史压缩加入当前 Session 的有序输入队列。
267
+ */
268
+ async compact(): Promise<void> {
269
+ await this.turnService.compact();
270
+ }
271
+
272
+ /**
273
+ * 把 Agent configured state command 加入当前 Session 的统一输入队列。
274
+ */
275
+ enqueue_agent_command(command: AgentSessionCommand): void {
276
+ this.turnService.enqueue_command({
277
+ type: "command",
278
+ command_id: command.command_id,
279
+ scope: "agent",
280
+ execute: async ({ turn_id }) => {
281
+ if (command.type === "instruction") {
282
+ this.effective_instruction_system_blocks = command
283
+ .instruction_blocks
284
+ .map((block) => ({ ...block }));
285
+ await this.stateService.emit_config_action_event({
286
+ id: `agent-instruction:${this.id}:${command.command_id}`,
287
+ title: "Agent instruction updated",
288
+ state: "completed",
289
+ turnId: turn_id,
290
+ });
291
+ return;
292
+ }
293
+ if (command.type === "env") {
294
+ this.effective_agent_env = { ...command.env };
295
+ await this.stateService.emit_config_action_event({
296
+ id: `agent-env:${this.id}:${command.command_id}`,
297
+ title: "Agent environment updated",
298
+ state: "completed",
299
+ turnId: turn_id,
300
+ });
301
+ return;
302
+ }
303
+ this.effective_agent_plugins = command.plugins;
304
+ await this.stateService.emit_config_action_event({
305
+ id: `agent-plugins:${this.id}:${command.command_id}`,
306
+ title: command.title,
307
+ state: "completed",
308
+ turnId: turn_id,
309
+ });
310
+ },
311
+ });
312
+ }
313
+
246
314
  /**
247
315
  * 订阅当前 Session 的未来事件。
248
316
  */
@@ -388,8 +456,11 @@ export class Session implements AgentSession {
388
456
  tools: this.tools,
389
457
  logger: this.logger,
390
458
  getInstructionSystemBlocks: this.getInstructionSystemBlocks,
459
+ getAgentEnv: this.getAgentEnv,
460
+ get_agent_plugins: this.get_agent_plugins,
391
461
  getManagedPluginSystemBlocks: this.getManagedPluginSystemBlocks,
392
- getPluginSystemBlocks: this.getPluginSystemBlocks,
462
+ getPluginSystemBlocks: async () =>
463
+ await this.effective_agent_plugins.systemBlocks(),
393
464
  ensureConfigured: this.ensureConfiguredHook,
394
465
  composers: this.composers,
395
466
  list_approvals: this.list_approvals,
@@ -422,7 +493,7 @@ export class Session implements AgentSession {
422
493
  const messages_dir_path = `${session_dir_path}/messages`;
423
494
  return new JsonlSessionMessageStore({
424
495
  session_id: this.id,
425
- file_path: `${messages_dir_path}/messages.jsonl`,
496
+ file_path: `${messages_dir_path}/active.jsonl`,
426
497
  assistant_message_file_path: getSdkAgentSessionAssistantMessagePath(
427
498
  this.projectRoot,
428
499
  this.agentId,
@@ -441,6 +512,7 @@ export class Session implements AgentSession {
441
512
  private create_local_state(): SessionLocalState {
442
513
  return {
443
514
  sessionConfig: {},
515
+ effective_session_config: {},
444
516
  createdAt: Date.now(),
445
517
  timezone: resolveSystemTimezone(),
446
518
  initializePromise: null,
@@ -455,9 +527,11 @@ export class Session implements AgentSession {
455
527
  sessionId: this.id,
456
528
  historyStore: this.historyStore,
457
529
  getTools: () => this.tools,
458
- getInstructionSystemBlocks: this.getInstructionSystemBlocks,
530
+ getInstructionSystemBlocks: () =>
531
+ this.effective_instruction_system_blocks.map((block) => ({ ...block })),
459
532
  getManagedPluginSystemBlocks: this.getManagedPluginSystemBlocks,
460
- getPluginSystemBlocks: this.getPluginSystemBlocks,
533
+ getPluginSystemBlocks: async () =>
534
+ await this.effective_agent_plugins.systemBlocks(),
461
535
  getSessionCreatedAt: () => this.localState.createdAt,
462
536
  getSessionTimezone: () => this.localState.timezone,
463
537
  };
@@ -482,9 +556,11 @@ export class Session implements AgentSession {
482
556
  projectRoot: this.projectRoot,
483
557
  getSessionCreatedAt: () => this.localState.createdAt,
484
558
  getSessionTimezone: () => this.localState.timezone,
485
- getInstructionSystemBlocks: this.getInstructionSystemBlocks,
559
+ getInstructionSystemBlocks: () =>
560
+ this.effective_instruction_system_blocks.map((block) => ({ ...block })),
486
561
  getManagedPluginSystemBlocks: this.getManagedPluginSystemBlocks,
487
- getPluginSystemBlocks: this.getPluginSystemBlocks,
562
+ getPluginSystemBlocks: async () =>
563
+ await this.effective_agent_plugins.systemBlocks(),
488
564
  }),
489
565
  );
490
566
  }
@@ -516,10 +592,20 @@ export class Session implements AgentSession {
516
592
  sessionId: this.id,
517
593
  historyStore: this.historyStore,
518
594
  historyComposer: this.historyComposer,
519
- getModel: () => this.localState.sessionConfig.model,
595
+ getModel: () =>
596
+ this.localState.effective_session_config.model ||
597
+ this.localState.sessionConfig.model,
598
+ get_model_context_window: () =>
599
+ this.localState.effective_session_config.model
600
+ ? this.localState.effective_session_config.model_context_window
601
+ : this.localState.sessionConfig.model_context_window,
520
602
  logger: this.logger,
521
603
  systemComposer: system_composer,
522
604
  getTools: () => this.tools,
605
+ getEnv: () => ({ ...this.effective_agent_env }),
606
+ get_systems: () =>
607
+ this.effective_instruction_system_blocks.map((block) => block.content),
608
+ get_plugins: () => this.effective_agent_plugins,
523
609
  ...(context_composer ? { contextComposer: context_composer } : {}),
524
610
  ...(compaction_composer
525
611
  ? { compactionComposer: compaction_composer }
@@ -253,7 +253,10 @@ export class SessionSystemBuilder implements SessionSystemComposer {
253
253
  timezone: this.getSessionTimezone(),
254
254
  getInstructionSystemBlocks: this.getInstructionSystemBlocks,
255
255
  getManagedPluginSystemBlocks: this.getManagedPluginSystemBlocks,
256
- getPluginSystemBlocks: this.getPluginSystemBlocks,
256
+ getPluginSystemBlocks: async () =>
257
+ run_context.agentPlugins
258
+ ? await run_context.agentPlugins.systemBlocks()
259
+ : await this.getPluginSystemBlocks(),
257
260
  });
258
261
  }
259
262
  }