@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
@@ -32,6 +32,7 @@ import type {
32
32
  import { to_session_action_record } from "@/executor/types/SessionRecords.js";
33
33
  import type { SessionExecutor } from "@/executor/types/SessionExecutor.js";
34
34
  import type { SessionRunContext } from "@/types/executor/SessionRunContext.js";
35
+ import type { AgentPluginExecutionRuntime } from "@/types/plugin/PluginRuntime.js";
35
36
  import type {
36
37
  SessionExecuteInput,
37
38
  SessionRunResult,
@@ -61,6 +62,11 @@ type ExecutorOptions = {
61
62
  */
62
63
  getModel: () => LanguageModel | undefined;
63
64
 
65
+ /**
66
+ * 读取当前 session 模型支持的总上下文窗口长度。
67
+ */
68
+ get_model_context_window?: () => number | undefined;
69
+
64
70
  /**
65
71
  * 统一日志器。
66
72
  */
@@ -81,6 +87,17 @@ type ExecutorOptions = {
81
87
  */
82
88
  getTools: () => Record<string, Tool>;
83
89
 
90
+ /**
91
+ * 读取当前 Session effective Agent env。
92
+ */
93
+ getEnv: () => Record<string, string>;
94
+
95
+ /** 读取当前 Session effective Agent instruction 文本。 */
96
+ get_systems?: () => string[];
97
+
98
+ /** 创建当前 Session effective Plugin 执行视图。 */
99
+ get_plugins?: () => AgentPluginExecutionRuntime;
100
+
84
101
  /**
85
102
  * 可选自定义 context Composer。
86
103
  */
@@ -100,6 +117,10 @@ export class Executor implements SessionExecutor {
100
117
  private readonly historyComposer: SessionHistoryComposer;
101
118
  private readonly historyStore: SessionHistoryStore;
102
119
  private readonly getModel: ExecutorOptions["getModel"];
120
+ private readonly getEnv: ExecutorOptions["getEnv"];
121
+ private readonly get_systems: ExecutorOptions["get_systems"];
122
+ private readonly get_plugins: ExecutorOptions["get_plugins"];
123
+ private readonly get_model_context_window?: ExecutorOptions["get_model_context_window"];
103
124
  private readonly logger: Logger;
104
125
  private readonly compactionComposer: SessionCompactionComposer;
105
126
  private readonly systemComposer: SessionSystemComposer;
@@ -122,6 +143,10 @@ export class Executor implements SessionExecutor {
122
143
  this.historyStore = options.historyStore;
123
144
  this.historyComposer = options.historyComposer;
124
145
  this.getModel = options.getModel;
146
+ this.getEnv = options.getEnv;
147
+ this.get_systems = options.get_systems;
148
+ this.get_plugins = options.get_plugins;
149
+ this.get_model_context_window = options.get_model_context_window;
125
150
  this.logger = options.logger;
126
151
  this.compactionComposer =
127
152
  options.compactionComposer || new JsonlSessionCompactionComposer();
@@ -317,6 +342,7 @@ export class Executor implements SessionExecutor {
317
342
  );
318
343
  return result;
319
344
  } finally {
345
+ await this.release_step_plugins(run_context);
320
346
  this.recovery_policy.reset_run_state();
321
347
  if (this.abort_controller === abort_controller) {
322
348
  this.abort_controller = null;
@@ -339,6 +365,7 @@ export class Executor implements SessionExecutor {
339
365
  throw new Error("Executor.run requires historyComposer.sessionId");
340
366
  }
341
367
 
368
+ await this.refresh_step_runtime(run_context);
342
369
  const composed_context = await this.contextComposer.compose(run_context);
343
370
  const tools = this.bind_run_scope_to_tools(composed_context.tools, run_context);
344
371
  const system = await this.systemComposer.resolve(run_context);
@@ -359,14 +386,19 @@ export class Executor implements SessionExecutor {
359
386
  }
360
387
  await this.emitAction(run_context, action);
361
388
  };
389
+ const context_window = this.get_model_context_window?.();
362
390
 
363
- await this.compactionComposer.run({
364
- historyStore: this.historyStore,
365
- model,
366
- system,
367
- retryCount: retry_count,
368
- onAction: emit_compaction_action,
369
- });
391
+ if (retry_count > 0) {
392
+ await this.compactionComposer.run({
393
+ historyStore: this.historyStore,
394
+ model,
395
+ ...(context_window !== undefined ? { context_window } : {}),
396
+ system,
397
+ retryCount: retry_count,
398
+ force: true,
399
+ onAction: emit_compaction_action,
400
+ });
401
+ }
370
402
  } catch (error) {
371
403
  await this.emitAction(run_context, {
372
404
  type: "action",
@@ -413,9 +445,122 @@ export class Executor implements SessionExecutor {
413
445
  execute_input: input,
414
446
  model,
415
447
  run_context,
448
+ resolve_step_inputs: async () =>
449
+ await this.resolve_step_inputs(run_context),
416
450
  });
417
451
  }
418
452
 
453
+ /**
454
+ * 在 Assistant writer 完成后归档当前 canonical 历史。
455
+ *
456
+ * 关键点(中文):持久化 compact 不能发生在流式 Assistant 草稿仍打开时,
457
+ * 因此由 SessionTurnService 在 writer complete/fail 之后显式调用。
458
+ */
459
+ async compact_history(run_context: SessionRunContext): Promise<{
460
+ compacted: boolean;
461
+ reason?: string;
462
+ }> {
463
+ let compaction_action_id = "";
464
+ try {
465
+ await this.refresh_step_runtime(run_context);
466
+ const model = this.resolveModelOrThrow();
467
+ const system = await this.systemComposer.resolve(run_context);
468
+ const emit_compaction_action = async (
469
+ action: SessionActionRecordV1,
470
+ ): Promise<void> => {
471
+ if (action.state === "running") compaction_action_id = action.id;
472
+ await this.emitAction(run_context, action);
473
+ };
474
+ const context_window = this.get_model_context_window?.();
475
+ return await this.compactionComposer.run({
476
+ historyStore: this.historyStore,
477
+ model,
478
+ ...(context_window !== undefined ? { context_window } : {}),
479
+ system,
480
+ retryCount: 0,
481
+ force: true,
482
+ onAction: emit_compaction_action,
483
+ });
484
+ } catch (error) {
485
+ await this.emitAction(run_context, {
486
+ type: "action",
487
+ id:
488
+ compaction_action_id ||
489
+ `compacting:${this.sessionId}:failed:${Date.now()}:${generateId()}`,
490
+ title: "Session records compact failed",
491
+ description: error instanceof Error ? error.message : String(error),
492
+ state: "failed",
493
+ metadata: {
494
+ v: 1,
495
+ ts: Date.now(),
496
+ sessionId: this.sessionId,
497
+ },
498
+ });
499
+ return { compacted: false, reason: "compact_failed" };
500
+ } finally {
501
+ await this.release_step_plugins(run_context);
502
+ }
503
+ }
504
+
505
+ /**
506
+ * 解析下一 Session step 实际使用的运行配置。
507
+ *
508
+ * 关键点(中文)
509
+ * - 调用方必须先提交 Session 统一输入队列,再调用本方法。
510
+ * - 每次调用只读取一次 model、system 与 tools,并把它们传给同一个 `streamText()`。
511
+ */
512
+ private async resolve_step_inputs(run_context: SessionRunContext): Promise<{
513
+ model: LanguageModel;
514
+ system: SessionExecuteInput["system"];
515
+ tools: SessionExecuteInput["tools"];
516
+ context_window?: number;
517
+ }> {
518
+ await this.refresh_step_runtime(run_context);
519
+ const composed_context = await this.contextComposer.compose(run_context);
520
+ const context_window = this.get_model_context_window?.();
521
+ return {
522
+ model: this.resolveModelOrThrow(),
523
+ system: await this.systemComposer.resolve(run_context),
524
+ tools: this.bind_run_scope_to_tools(
525
+ composed_context.tools,
526
+ run_context,
527
+ ),
528
+ ...(context_window !== undefined ? { context_window } : {}),
529
+ };
530
+ }
531
+
532
+ /**
533
+ * 刷新当前 Session step 的 effective Agent 运行视图。
534
+ */
535
+ private async refresh_step_runtime(
536
+ run_context: SessionRunContext,
537
+ ): Promise<void> {
538
+ await this.release_step_plugins(run_context);
539
+ run_context.agentEnv = Object.freeze({ ...this.getEnv() });
540
+ if (this.get_systems) {
541
+ run_context.agentSystems = Object.freeze([...this.get_systems()]);
542
+ } else {
543
+ delete run_context.agentSystems;
544
+ }
545
+ if (this.get_plugins) {
546
+ run_context.agentPlugins = this.get_plugins().acquire();
547
+ } else {
548
+ delete run_context.agentPlugins;
549
+ }
550
+ }
551
+
552
+ /**
553
+ * 释放当前 Session step 持有的 Plugin execution lease。
554
+ */
555
+ private async release_step_plugins(
556
+ run_context: SessionRunContext,
557
+ ): Promise<void> {
558
+ const plugins = run_context.agentPlugins;
559
+ if (!plugins) return;
560
+ delete run_context.agentPlugins;
561
+ await plugins.release();
562
+ }
563
+
419
564
  /**
420
565
  * 为所有 tool 的 execute callback 绑定 ShellRunScope。
421
566
  *
@@ -446,6 +591,9 @@ export class Executor implements SessionExecutor {
446
591
  run_context: {
447
592
  ...(session_id ? { session_id } : {}),
448
593
  ...(turn_id ? { turn_id } : {}),
594
+ ...(run_context.agentEnv
595
+ ? { env: run_context.agentEnv }
596
+ : {}),
449
597
  },
450
598
  },
451
599
  async () => await original_execute(args, options),
@@ -470,6 +618,12 @@ export class Executor implements SessionExecutor {
470
618
  ...(typeof input?.onStepCallback === "function"
471
619
  ? { onStepCallback: input.onStepCallback }
472
620
  : {}),
621
+ ...(typeof input?.hasPendingStepInput === "function"
622
+ ? { hasPendingStepInput: input.hasPendingStepInput }
623
+ : {}),
624
+ ...(typeof input?.consume_history_reload === "function"
625
+ ? { consume_history_reload: input.consume_history_reload }
626
+ : {}),
473
627
  ...(typeof input?.onAssistantStepCallback === "function"
474
628
  ? { onAssistantStepCallback: input.onAssistantStepCallback }
475
629
  : {}),
@@ -24,6 +24,11 @@ export type SessionCompactionInput = {
24
24
  */
25
25
  model: LanguageModel;
26
26
 
27
+ /**
28
+ * 当前模型支持的总上下文窗口长度,单位为 token。
29
+ */
30
+ context_window?: number;
31
+
27
32
  /**
28
33
  * 当前轮 system messages。
29
34
  */
@@ -42,6 +47,13 @@ export type SessionCompactionInput = {
42
47
  * - 回调由上层 Session 负责转成订阅事件与 action record。
43
48
  */
44
49
  onAction?: (action: SessionActionRecordV1) => Promise<void>;
50
+
51
+ /**
52
+ * 是否明确要求持久化 deep compact。
53
+ *
54
+ * 普通模型调用不应因为历史字符数量而触发 compact;仅 usage 反馈或超限恢复会设置此值。
55
+ */
56
+ force?: boolean;
45
57
  };
46
58
 
47
59
  /**
@@ -11,74 +11,23 @@ import type {
11
11
  SessionCompactionInput,
12
12
  } from "@executor/composer/compaction/SessionCompactionComposer.js";
13
13
 
14
- type JsonlSessionCompactionComposerOptions = {
15
- keepLastMessages?: number;
16
- maxInputTokensApprox?: number;
17
- archiveOnCompact?: boolean;
18
- compactRatio?: number;
19
- };
20
-
21
14
  /**
22
15
  * JsonlSessionCompactionComposer 默认实现。
23
16
  */
24
17
  export class JsonlSessionCompactionComposer implements SessionCompactionComposer {
25
18
  readonly name = "summary_compaction_composer";
26
- private readonly options: JsonlSessionCompactionComposerOptions;
27
-
28
- constructor(options?: JsonlSessionCompactionComposerOptions) {
29
- this.options = options || {};
30
- }
31
-
32
- private resolvePolicy(retryCount: number): {
33
- keepLastMessages: number;
34
- maxInputTokensApprox: number;
35
- archiveOnCompact: boolean;
36
- compactRatio: number;
37
- } {
38
- const baseKeepLastMessages =
39
- typeof this.options.keepLastMessages === "number"
40
- ? Math.max(6, Math.min(5000, Math.floor(this.options.keepLastMessages)))
41
- : 30;
42
- const baseMaxInputTokensApprox =
43
- typeof this.options.maxInputTokensApprox === "number"
44
- ? Math.max(2000, Math.min(200_000, Math.floor(this.options.maxInputTokensApprox)))
45
- : 128000;
46
- const retryFactor = Math.max(1, Math.pow(2, retryCount));
47
- const keepLastMessages = Math.max(6, Math.floor(baseKeepLastMessages / retryFactor));
48
- const maxInputTokensApprox = Math.max(
49
- 2000,
50
- Math.floor(baseMaxInputTokensApprox / retryFactor),
51
- );
52
- const archiveOnCompact =
53
- this.options.archiveOnCompact === undefined
54
- ? true
55
- : Boolean(this.options.archiveOnCompact);
56
- const compactRatioRaw =
57
- typeof this.options.compactRatio === "number" &&
58
- Number.isFinite(this.options.compactRatio)
59
- ? this.options.compactRatio
60
- : 0.5;
61
- const compactRatio = Math.max(0.1, Math.min(0.9, compactRatioRaw));
62
- return {
63
- keepLastMessages,
64
- maxInputTokensApprox,
65
- archiveOnCompact,
66
- compactRatio,
67
- };
68
- }
69
19
 
70
20
  async run(input: SessionCompactionInput): Promise<{
71
21
  compacted: boolean;
72
22
  reason?: string;
73
23
  }> {
74
- const policy = this.resolvePolicy(input.retryCount);
24
+ if (!input.force && input.retryCount <= 0) {
25
+ return { compacted: false, reason: "not_requested" };
26
+ }
75
27
  return await input.historyStore.compact({
76
28
  model: input.model,
77
29
  system: input.system,
78
- keepLastMessages: policy.keepLastMessages,
79
- maxInputTokensApprox: policy.maxInputTokensApprox,
80
- archiveOnCompact: policy.archiveOnCompact,
81
- compactRatio: policy.compactRatio,
30
+ force: true,
82
31
  ...(input.onAction ? { onAction: input.onAction } : {}),
83
32
  });
84
33
  }
@@ -37,10 +37,8 @@ import { format_session_compaction_file_operations } from "@executor/composer/co
37
37
  export type SessionCompactParams = {
38
38
  model: LanguageModel;
39
39
  system: Array<SystemModelMessage>;
40
- keepLastMessages: number;
41
- maxInputTokensApprox: number;
42
40
  archiveOnCompact: boolean;
43
- compactRatio: number;
41
+ force?: boolean;
44
42
  onAction?: (action: SessionActionRecordV1) => Promise<void>;
45
43
  };
46
44
 
@@ -104,29 +102,15 @@ export async function compactSessionMessagesIfNeeded(
104
102
  : "";
105
103
  });
106
104
 
107
- if (snapshot.length < 4) {
108
- return { compacted: false, reason: "small_messages" };
105
+ if (snapshot.length === 0) {
106
+ return { compacted: false, reason: "nothing_to_compact" };
109
107
  }
110
-
111
- const systemText = (params.system || [])
112
- .map((m) => String(m.content ?? ""))
113
- .join("\n\n");
114
- // 关键点(中文):session messages 现在可能包含 tool parts / output,必须把它们计入预算估算,否则会低估 token。
115
- let messagesJson = "";
116
- try {
117
- messagesJson = JSON.stringify(snapshot);
118
- } catch {
119
- messagesJson = "";
120
- }
121
- const est = estimateTokensApproxFromText(systemText + "\n\n" + messagesJson);
122
- if (est <= params.maxInputTokensApprox) {
123
- return { compacted: false, reason: "under_budget" };
108
+ if (!params.force) {
109
+ return { compacted: false, reason: "not_requested" };
124
110
  }
125
111
 
126
- // 关键点(中文):触发 compact 后,优先压缩“最早一段消息”,默认比例 50%。
127
- const compactRatio = normalizeCompactRatio(params.compactRatio);
128
- const compactCount = resolveCompactCount(snapshot.length, compactRatio);
129
- const older = snapshot.slice(0, compactCount);
112
+ // 关键点(中文):明确 compact 时归档全部当前模型历史,避免单条巨大 assistant 永远留在 Active。
113
+ const older = snapshot;
130
114
  if (older.length === 0) return { compacted: false, reason: "nothing_to_compact" };
131
115
 
132
116
  action_started = true;
@@ -215,11 +199,7 @@ export async function compactSessionMessagesIfNeeded(
215
199
  const current_model_messages = current.filter(
216
200
  is_session_message_record,
217
201
  );
218
- const currentCompactCount = resolveCompactCount(
219
- current_model_messages.length,
220
- compactRatio,
221
- );
222
- const currentOlder = current_model_messages.slice(0, currentCompactCount);
202
+ const currentOlder = current_model_messages;
223
203
  if (currentOlder.length === 0) return;
224
204
  const compacted_ids = new Set(
225
205
  currentOlder
@@ -271,44 +251,6 @@ export async function compactSessionMessagesIfNeeded(
271
251
  return { compacted: true };
272
252
  }
273
253
 
274
- /**
275
- * 归一化压缩比例。
276
- *
277
- * 关键点(中文)
278
- * - 仅允许 0.1~0.9,避免“几乎不压缩”或“几乎全压缩”。
279
- */
280
- function normalizeCompactRatio(value: number): number {
281
- if (!Number.isFinite(value)) return 0.5;
282
- return Math.max(0.1, Math.min(0.9, value));
283
- }
284
-
285
- /**
286
- * 按比例计算前段压缩条数。
287
- *
288
- * 关键点(中文)
289
- * - 至少压缩 1 条;
290
- * - 至少保留 1 条未压缩消息。
291
- */
292
- function resolveCompactCount(total: number, ratio: number): number {
293
- const n = Math.max(0, Math.floor(total));
294
- if (n <= 1) return 0;
295
- const raw = Math.floor(n * ratio);
296
- return Math.max(1, Math.min(n - 1, raw));
297
- }
298
-
299
- /**
300
- * 近似 token 估算。
301
- *
302
- * 算法说明(中文)
303
- * - 这里使用经验近似,不追求精确 tokenizer 一致性。
304
- * - 目标是为 compact 提供保守预算,宁可略高估也不要低估。
305
- */
306
- function estimateTokensApproxFromText(text: string): number {
307
- const t = String(text || "");
308
- // 经验值:英文 ~4 chars/token;中文更接近 1-2 chars/token。这里用保守的 3 chars/token。
309
- return Math.ceil(t.length / 3);
310
- }
311
-
312
254
  /**
313
255
  * 从 UIMessage 提取可摘要的纯文本。
314
256
  *