@downcity/agent 1.1.79 → 1.1.81

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 (173) hide show
  1. package/README.md +1 -1
  2. package/bin/agent/local/Agent.d.ts +8 -121
  3. package/bin/agent/local/Agent.d.ts.map +1 -1
  4. package/bin/agent/local/Agent.js +63 -381
  5. package/bin/agent/local/Agent.js.map +1 -1
  6. package/bin/agent/local/AgentRuntimeFactory.d.ts +2 -2
  7. package/bin/agent/local/AgentRuntimeFactory.d.ts.map +1 -1
  8. package/bin/agent/local/AgentRuntimeFactory.js +2 -23
  9. package/bin/agent/local/AgentRuntimeFactory.js.map +1 -1
  10. package/bin/agent/local/services/AgentAssemblyService.d.ts +112 -0
  11. package/bin/agent/local/services/AgentAssemblyService.d.ts.map +1 -0
  12. package/bin/agent/local/services/AgentAssemblyService.js +135 -0
  13. package/bin/agent/local/services/AgentAssemblyService.js.map +1 -0
  14. package/bin/agent/local/services/AgentLifecycleService.d.ts +59 -0
  15. package/bin/agent/local/services/AgentLifecycleService.d.ts.map +1 -0
  16. package/bin/agent/local/services/AgentLifecycleService.js +136 -0
  17. package/bin/agent/local/services/AgentLifecycleService.js.map +1 -0
  18. package/bin/agent/local/services/AgentSessionManager.d.ts +106 -0
  19. package/bin/agent/local/services/AgentSessionManager.d.ts.map +1 -0
  20. package/bin/agent/local/services/AgentSessionManager.js +182 -0
  21. package/bin/agent/local/services/AgentSessionManager.js.map +1 -0
  22. package/bin/executor/Executor.d.ts +7 -24
  23. package/bin/executor/Executor.d.ts.map +1 -1
  24. package/bin/executor/Executor.js +73 -361
  25. package/bin/executor/Executor.js.map +1 -1
  26. package/bin/executor/SessionRunScope.d.ts +18 -34
  27. package/bin/executor/SessionRunScope.d.ts.map +1 -1
  28. package/bin/executor/SessionRunScope.js +42 -28
  29. package/bin/executor/SessionRunScope.js.map +1 -1
  30. package/bin/executor/composer/context/LocalSessionContextComposer.d.ts +5 -3
  31. package/bin/executor/composer/context/LocalSessionContextComposer.d.ts.map +1 -1
  32. package/bin/executor/composer/context/LocalSessionContextComposer.js +11 -18
  33. package/bin/executor/composer/context/LocalSessionContextComposer.js.map +1 -1
  34. package/bin/executor/composer/context/SessionContextComposer.d.ts +8 -3
  35. package/bin/executor/composer/context/SessionContextComposer.d.ts.map +1 -1
  36. package/bin/executor/composer/system/SessionSystemComposer.d.ts +2 -1
  37. package/bin/executor/composer/system/SessionSystemComposer.d.ts.map +1 -1
  38. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.d.ts +2 -1
  39. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.d.ts.map +1 -1
  40. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.js +2 -4
  41. package/bin/executor/composer/system/default/DefaultSessionSystemComposer.js.map +1 -1
  42. package/bin/executor/core-engine/CoreEngineRunner.d.ts +62 -0
  43. package/bin/executor/core-engine/CoreEngineRunner.d.ts.map +1 -0
  44. package/bin/executor/core-engine/CoreEngineRunner.js +309 -0
  45. package/bin/executor/core-engine/CoreEngineRunner.js.map +1 -0
  46. package/bin/executor/core-engine/CoreEngineUiStreamCollector.d.ts +5 -0
  47. package/bin/executor/core-engine/CoreEngineUiStreamCollector.d.ts.map +1 -1
  48. package/bin/executor/core-engine/CoreEngineUiStreamCollector.js +2 -4
  49. package/bin/executor/core-engine/CoreEngineUiStreamCollector.js.map +1 -1
  50. package/bin/executor/services/ExecutorInflightService.d.ts +39 -0
  51. package/bin/executor/services/ExecutorInflightService.d.ts.map +1 -0
  52. package/bin/executor/services/ExecutorInflightService.js +75 -0
  53. package/bin/executor/services/ExecutorInflightService.js.map +1 -0
  54. package/bin/executor/services/ExecutorRecoveryPolicy.d.ts +103 -0
  55. package/bin/executor/services/ExecutorRecoveryPolicy.d.ts.map +1 -0
  56. package/bin/executor/services/ExecutorRecoveryPolicy.js +87 -0
  57. package/bin/executor/services/ExecutorRecoveryPolicy.js.map +1 -0
  58. package/bin/executor/tools/plugin/PluginToolBridge.d.ts +19 -0
  59. package/bin/executor/tools/plugin/PluginToolBridge.d.ts.map +1 -0
  60. package/bin/executor/tools/plugin/PluginToolBridge.js +143 -0
  61. package/bin/executor/tools/plugin/PluginToolBridge.js.map +1 -0
  62. package/bin/executor/tools/plugin/PluginToolDefinition.d.ts +32 -0
  63. package/bin/executor/tools/plugin/PluginToolDefinition.d.ts.map +1 -0
  64. package/bin/executor/tools/plugin/PluginToolDefinition.js +27 -0
  65. package/bin/executor/tools/plugin/PluginToolDefinition.js.map +1 -0
  66. package/bin/executor/tools/plugin/PluginToolSchemas.d.ts +14 -0
  67. package/bin/executor/tools/plugin/PluginToolSchemas.d.ts.map +1 -0
  68. package/bin/executor/tools/plugin/PluginToolSchemas.js +19 -0
  69. package/bin/executor/tools/plugin/PluginToolSchemas.js.map +1 -0
  70. package/bin/executor/tools/plugin/types/PluginTool.d.ts +39 -0
  71. package/bin/executor/tools/plugin/types/PluginTool.d.ts.map +1 -0
  72. package/bin/executor/tools/plugin/types/PluginTool.js +9 -0
  73. package/bin/executor/tools/plugin/types/PluginTool.js.map +1 -0
  74. package/bin/executor/tools/shell/ShellToolBridge.js +3 -3
  75. package/bin/executor/tools/shell/ShellToolBridge.js.map +1 -1
  76. package/bin/executor/types/SessionRun.d.ts +18 -0
  77. package/bin/executor/types/SessionRun.d.ts.map +1 -1
  78. package/bin/index.d.ts +10 -1
  79. package/bin/index.d.ts.map +1 -1
  80. package/bin/index.js +3 -0
  81. package/bin/index.js.map +1 -1
  82. package/bin/plugin/core/BasePlugin.d.ts +2 -2
  83. package/bin/plugin/core/BasePlugin.d.ts.map +1 -1
  84. package/bin/plugin/core/BasePlugin.js.map +1 -1
  85. package/bin/plugin/core/ImagePlugin.d.ts +56 -0
  86. package/bin/plugin/core/ImagePlugin.d.ts.map +1 -0
  87. package/bin/plugin/core/ImagePlugin.js +109 -0
  88. package/bin/plugin/core/ImagePlugin.js.map +1 -0
  89. package/bin/session/Session.d.ts +14 -83
  90. package/bin/session/Session.d.ts.map +1 -1
  91. package/bin/session/Session.js +139 -362
  92. package/bin/session/Session.js.map +1 -1
  93. package/bin/session/SessionSystemBuilder.d.ts +2 -1
  94. package/bin/session/SessionSystemBuilder.d.ts.map +1 -1
  95. package/bin/session/SessionSystemBuilder.js +2 -3
  96. package/bin/session/SessionSystemBuilder.js.map +1 -1
  97. package/bin/session/services/SessionStateService.d.ts +132 -0
  98. package/bin/session/services/SessionStateService.d.ts.map +1 -0
  99. package/bin/session/services/SessionStateService.js +242 -0
  100. package/bin/session/services/SessionStateService.js.map +1 -0
  101. package/bin/session/services/SessionTurnService.d.ts +66 -0
  102. package/bin/session/services/SessionTurnService.d.ts.map +1 -0
  103. package/bin/session/services/SessionTurnService.js +137 -0
  104. package/bin/session/services/SessionTurnService.js.map +1 -0
  105. package/bin/session/services/SessionViewService.d.ts +105 -0
  106. package/bin/session/services/SessionViewService.d.ts.map +1 -0
  107. package/bin/session/services/SessionViewService.js +184 -0
  108. package/bin/session/services/SessionViewService.js.map +1 -0
  109. package/bin/types/agent/AgentOptions.d.ts +18 -0
  110. package/bin/types/agent/AgentOptions.d.ts.map +1 -1
  111. package/bin/types/agent/AgentTypes.d.ts +3 -1
  112. package/bin/types/agent/AgentTypes.d.ts.map +1 -1
  113. package/bin/types/agent/SessionTypes.d.ts.map +1 -1
  114. package/bin/types/executor/SessionRunContext.d.ts +66 -0
  115. package/bin/types/executor/SessionRunContext.d.ts.map +1 -0
  116. package/bin/types/executor/SessionRunContext.js +10 -0
  117. package/bin/types/executor/SessionRunContext.js.map +1 -0
  118. package/bin/types/plugin/ImagePlugin.d.ts +94 -0
  119. package/bin/types/plugin/ImagePlugin.d.ts.map +1 -0
  120. package/bin/types/plugin/ImagePlugin.js +10 -0
  121. package/bin/types/plugin/ImagePlugin.js.map +1 -0
  122. package/bin/types/session/SessionComposerOptions.d.ts +90 -0
  123. package/bin/types/session/SessionComposerOptions.d.ts.map +1 -0
  124. package/bin/types/session/SessionComposerOptions.js +10 -0
  125. package/bin/types/session/SessionComposerOptions.js.map +1 -0
  126. package/bin/types/session/SessionLocalState.d.ts +35 -0
  127. package/bin/types/session/SessionLocalState.d.ts.map +1 -0
  128. package/bin/types/session/SessionLocalState.js +10 -0
  129. package/bin/types/session/SessionLocalState.js.map +1 -0
  130. package/bin/types/session/SessionOptions.d.ts +85 -0
  131. package/bin/types/session/SessionOptions.d.ts.map +1 -0
  132. package/bin/types/session/SessionOptions.js +10 -0
  133. package/bin/types/session/SessionOptions.js.map +1 -0
  134. package/package.json +1 -1
  135. package/src/agent/local/Agent.ts +74 -433
  136. package/src/agent/local/AgentRuntimeFactory.ts +4 -25
  137. package/src/agent/local/services/AgentAssemblyService.ts +268 -0
  138. package/src/agent/local/services/AgentLifecycleService.ts +187 -0
  139. package/src/agent/local/services/AgentSessionManager.ts +291 -0
  140. package/src/executor/Executor.ts +103 -441
  141. package/src/executor/README.md +4 -4
  142. package/src/executor/SessionRunScope.ts +47 -71
  143. package/src/executor/composer/context/LocalSessionContextComposer.ts +24 -20
  144. package/src/executor/composer/context/SessionContextComposer.ts +13 -3
  145. package/src/executor/composer/system/SessionSystemComposer.ts +2 -1
  146. package/src/executor/composer/system/default/DefaultSessionSystemComposer.ts +3 -4
  147. package/src/executor/core-engine/CoreEngineRunner.ts +433 -0
  148. package/src/executor/core-engine/CoreEngineUiStreamCollector.ts +7 -5
  149. package/src/executor/services/ExecutorInflightService.ts +101 -0
  150. package/src/executor/services/ExecutorRecoveryPolicy.ts +213 -0
  151. package/src/executor/tools/plugin/PluginToolBridge.ts +161 -0
  152. package/src/executor/tools/plugin/PluginToolDefinition.ts +32 -0
  153. package/src/executor/tools/plugin/PluginToolSchemas.ts +20 -0
  154. package/src/executor/tools/plugin/types/PluginTool.ts +41 -0
  155. package/src/executor/tools/shell/ShellToolBridge.ts +3 -3
  156. package/src/executor/types/SessionRun.ts +20 -0
  157. package/src/index.ts +33 -0
  158. package/src/plugin/core/BasePlugin.ts +2 -2
  159. package/src/plugin/core/ImagePlugin.ts +128 -0
  160. package/src/session/Session.ts +178 -485
  161. package/src/session/SessionSystemBuilder.ts +3 -3
  162. package/src/session/services/SessionStateService.ts +341 -0
  163. package/src/session/services/SessionTurnService.ts +202 -0
  164. package/src/session/services/SessionViewService.ts +301 -0
  165. package/src/types/agent/AgentOptions.ts +25 -0
  166. package/src/types/agent/AgentTypes.ts +10 -0
  167. package/src/types/agent/SessionTypes.ts +1 -0
  168. package/src/types/executor/SessionRunContext.ts +76 -0
  169. package/src/types/plugin/ImagePlugin.ts +103 -0
  170. package/src/types/session/SessionComposerOptions.ts +107 -0
  171. package/src/types/session/SessionLocalState.ts +40 -0
  172. package/src/types/session/SessionOptions.ts +99 -0
  173. package/tsconfig.tsbuildinfo +1 -1
@@ -3,124 +3,55 @@
3
3
  *
4
4
  * 关键点(中文)
5
5
  * - 面向 `new Agent(...)` 的本地会话使用场景。
6
- * - 统一收口消息落盘、session 级模型配置、prompt/subscribe/fork 等高层 API
6
+ * - 对外保留稳定 Session facade,把状态、turn、view 逻辑下沉到独立 service
7
7
  * - 内部继续复用 `Executor` / `JsonlSessionHistoryStore` / Composer 体系。
8
8
  */
9
9
 
10
- import { nanoid } from "nanoid";
11
- import type { Tool } from "ai";
12
10
  import { Executor } from "@executor/Executor.js";
11
+ import type { Tool } from "ai";
13
12
  import { JsonlSessionHistoryComposer } from "@executor/composer/history/jsonl/JsonlSessionHistoryComposer.js";
14
13
  import { JsonlSessionHistoryStore } from "@/executor/store/history/jsonl/JsonlSessionHistoryStore.js";
15
- import { extractTextFromUiMessage } from "@/executor/messages/UIMessageTransformer.js";
16
14
  import type {
17
15
  AgentSession,
18
- AgentSessionHistoryInput,
19
- AgentSessionHistoryPage,
20
16
  AgentSessionConfigSnapshot,
21
17
  AgentSessionForkInput,
18
+ AgentSessionHistoryInput,
19
+ AgentSessionHistoryPage,
22
20
  AgentSessionInfo,
23
21
  AgentSessionSetInput,
24
22
  AgentSessionSystemBlock,
25
23
  AgentSessionSystemSnapshot,
26
24
  } from "@/types/agent/AgentTypes.js";
27
- import type { SessionMessageV1 } from "@/executor/types/SessionMessages.js";
28
- import {
29
- buildSessionSystemBlocks,
30
- SessionSystemBuilder,
31
- } from "@/session/SessionSystemBuilder.js";
32
- import {
33
- buildSessionHistoryPage,
34
- buildSessionInfo,
35
- patchSessionModelLabel,
36
- readSessionMetadata,
37
- resolveSystemTimezone,
38
- writeSessionMetadata,
39
- } from "@/session/index.js";
40
25
  import {
41
26
  getSdkAgentSessionArchiveDirPath,
42
27
  getSdkAgentSessionDirPath,
43
28
  getSdkAgentSessionInflightPath,
29
+ resolveSystemTimezone,
30
+ createRuntimeSessionPort,
44
31
  } from "@/session/index.js";
32
+ import { SessionSystemBuilder } from "@/session/SessionSystemBuilder.js";
45
33
  import type { SessionPort } from "@/types/runtime/agent/AgentContext.js";
46
- import {
47
- mapAgentEventToSessionEvent,
48
- mapUiMessageChunkToAgentEvent,
49
- } from "@/session/SessionEventMapper.js";
50
- import {
51
- persistSdkAssistantResult,
52
- touchSessionMetadata,
53
- } from "@/session/index.js";
54
- import { createRuntimeSessionPort } from "@/session/index.js";
55
- import { drainDeferredPersistedUserMessages } from "@executor/SessionRunScope.js";
56
34
  import type {
57
35
  AgentSessionSubscriber,
58
36
  AgentSessionUnsubscribe,
59
37
  } from "@/types/sdk/AgentSessionEvent.js";
60
38
  import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js";
61
39
  import type { AgentSessionTurnHandle } from "@/types/sdk/AgentSessionTurn.js";
62
- import type { SessionUserMessageV1 } from "@/executor/types/SessionMessages.js";
63
40
  import { SessionEventHub } from "@/session/runtime/SessionEventHub.js";
64
- import { SessionPromptRuntime } from "@/session/runtime/SessionPromptRuntime.js";
65
- import {
66
- inferAgentModelLabel,
67
- normalizeAgentModel,
68
- } from "@/model/CityModelAdapter.js";
69
- import { ensureSessionTitle } from "@/session/SessionTitle.js";
70
-
71
- type SessionOptions = {
72
- /**
73
- * 当前 agent 稳定标识。
74
- */
75
- agentId: string;
76
-
77
- /**
78
- * 当前项目根目录。
79
- */
80
- projectRoot: string;
81
-
82
- /**
83
- * 当前 sessionId。
84
- */
85
- sessionId: string;
86
-
87
- /**
88
- * 当前 agent 默认工具集合。
89
- */
90
- tools: Record<string, Tool>;
91
-
92
- /**
93
- * 统一日志器。
94
- */
95
- logger: {
96
- info(message: string, details?: Record<string, unknown>): void;
97
- warn(message: string, details?: Record<string, unknown>): void;
98
- };
99
-
100
- /**
101
- * 读取当前 SDK 调用方传入的 instruction system blocks。
102
- */
103
- getInstructionSystemBlocks: () => AgentSessionSystemBlock[];
104
-
105
- /**
106
- * 读取当前 agent 显式注入的受托管 plugin system blocks。
107
- */
108
- getManagedPluginSystemBlocks: () => Promise<AgentSessionSystemBlock[]>;
109
-
110
- /**
111
- * 读取当前 agent 显式注册 plugin 的 system blocks。
112
- */
113
- getPluginSystemBlocks: () => Promise<AgentSessionSystemBlock[]>;
114
-
115
- /**
116
- * 在执行前确保当前 session 已完成宿主侧默认配置。
117
- *
118
- * 关键点(中文)
119
- * - 这里通常由 `Agent` 注入,用于补齐默认 model 等一次性装配。
120
- * - 所有执行入口都应通过这里兜底,避免只在 SDK `agent.createSession()` / `agent.getSession()` 链路上做配置。
121
- */
122
- ensureConfigured?: (session: Session) => Promise<void>;
123
- };
41
+ import { SessionStateService } from "@/session/services/SessionStateService.js";
42
+ import { SessionTurnService } from "@/session/services/SessionTurnService.js";
43
+ import { SessionViewService } from "@/session/services/SessionViewService.js";
44
+ import type { SessionLocalState } from "@/types/session/SessionLocalState.js";
45
+ import type {
46
+ SessionComposerFactoryContext,
47
+ SessionComposerInput,
48
+ SessionComposerOptions,
49
+ } from "@/types/session/SessionComposerOptions.js";
50
+ import type { SessionCompactionComposer } from "@/executor/composer/compaction/SessionCompactionComposer.js";
51
+ import type { SessionContextComposer } from "@/executor/composer/context/SessionContextComposer.js";
52
+ import type { SessionHistoryComposer } from "@/executor/composer/history/SessionHistoryComposer.js";
53
+ import type { SessionSystemComposer } from "@/executor/composer/system/SessionSystemComposer.js";
54
+ import type { SessionOptions } from "@/types/session/SessionOptions.js";
124
55
 
125
56
  /**
126
57
  * SDK 本地 Session。
@@ -136,16 +67,15 @@ export class Session implements AgentSession {
136
67
  private readonly getManagedPluginSystemBlocks: SessionOptions["getManagedPluginSystemBlocks"];
137
68
  private readonly getPluginSystemBlocks: SessionOptions["getPluginSystemBlocks"];
138
69
  private readonly ensureConfiguredHook?: SessionOptions["ensureConfigured"];
70
+ private readonly composers?: SessionComposerOptions;
139
71
  private readonly historyStore: JsonlSessionHistoryStore;
140
- private readonly historyComposer: JsonlSessionHistoryComposer;
72
+ private readonly historyComposer: SessionHistoryComposer;
141
73
  private readonly executor: Executor;
142
74
  private readonly eventHub = new SessionEventHub();
143
- private readonly promptRuntime: SessionPromptRuntime;
144
- private sessionConfig: AgentSessionConfigSnapshot = {};
145
- private createdAt = Date.now();
146
- private timezone = resolveSystemTimezone();
147
- private initializePromise: Promise<this> | null = null;
148
- private ensureConfiguredPromise: Promise<void> | null = null;
75
+ private readonly localState: SessionLocalState;
76
+ private readonly stateService: SessionStateService;
77
+ private readonly turnService: SessionTurnService;
78
+ private readonly viewService: SessionViewService<Session>;
149
79
  private runtimePort: SessionPort | null = null;
150
80
 
151
81
  constructor(options: SessionOptions) {
@@ -158,6 +88,7 @@ export class Session implements AgentSession {
158
88
  this.getManagedPluginSystemBlocks = options.getManagedPluginSystemBlocks;
159
89
  this.getPluginSystemBlocks = options.getPluginSystemBlocks;
160
90
  this.ensureConfiguredHook = options.ensureConfigured;
91
+ this.composers = options.composers;
161
92
  if (!this.id) {
162
93
  throw new Error("Session requires a non-empty sessionId");
163
94
  }
@@ -168,21 +99,21 @@ export class Session implements AgentSession {
168
99
  throw new Error("Session requires a non-empty projectRoot");
169
100
  }
170
101
 
171
- const sessionDirPath = getSdkAgentSessionDirPath(
102
+ const session_dir_path = getSdkAgentSessionDirPath(
172
103
  this.projectRoot,
173
104
  this.agentId,
174
105
  this.id,
175
106
  );
176
- const messagesDirPath = `${sessionDirPath}/messages`;
107
+ const messages_dir_path = `${session_dir_path}/messages`;
177
108
  this.historyStore = new JsonlSessionHistoryStore({
178
109
  rootPath: this.projectRoot,
179
110
  agentId: this.agentId,
180
111
  sessionId: this.id,
181
112
  paths: {
182
- sessionDirPath,
183
- messagesDirPath,
184
- messagesFilePath: `${messagesDirPath}/messages.jsonl`,
185
- metaFilePath: `${messagesDirPath}/meta.json`,
113
+ sessionDirPath: session_dir_path,
114
+ messagesDirPath: messages_dir_path,
115
+ messagesFilePath: `${messages_dir_path}/messages.jsonl`,
116
+ metaFilePath: `${messages_dir_path}/meta.json`,
186
117
  archiveDirPath: getSdkAgentSessionArchiveDirPath(
187
118
  this.projectRoot,
188
119
  this.agentId,
@@ -195,255 +126,186 @@ export class Session implements AgentSession {
195
126
  ),
196
127
  },
197
128
  });
198
- this.historyComposer = new JsonlSessionHistoryComposer({
199
- store: this.historyStore,
200
- });
201
-
129
+ this.localState = {
130
+ sessionConfig: {},
131
+ createdAt: Date.now(),
132
+ timezone: resolveSystemTimezone(),
133
+ initializePromise: null,
134
+ ensureConfiguredPromise: null,
135
+ };
136
+ const composer_context = this.create_composer_context();
137
+ this.historyComposer = this.resolve_composer(
138
+ this.composers?.historyComposer,
139
+ composer_context,
140
+ () =>
141
+ new JsonlSessionHistoryComposer({
142
+ store: this.historyStore,
143
+ }),
144
+ );
145
+ const system_composer = this.resolve_composer(
146
+ this.composers?.systemComposer,
147
+ composer_context,
148
+ () =>
149
+ new SessionSystemBuilder({
150
+ agentId: this.agentId,
151
+ projectRoot: this.projectRoot,
152
+ getSessionCreatedAt: () => this.localState.createdAt,
153
+ getSessionTimezone: () => this.localState.timezone,
154
+ getInstructionSystemBlocks: this.getInstructionSystemBlocks,
155
+ getManagedPluginSystemBlocks: this.getManagedPluginSystemBlocks,
156
+ getPluginSystemBlocks: this.getPluginSystemBlocks,
157
+ }),
158
+ );
159
+ const context_composer = this.resolve_optional_composer<
160
+ SessionContextComposer
161
+ >(this.composers?.contextComposer, composer_context);
162
+ const compaction_composer = this.resolve_optional_composer<
163
+ SessionCompactionComposer
164
+ >(this.composers?.compactionComposer, composer_context);
202
165
  this.executor = new Executor({
203
166
  sessionId: this.id,
204
167
  historyStore: this.historyStore,
205
168
  historyComposer: this.historyComposer,
206
- getModel: () => this.sessionConfig.model,
169
+ getModel: () => this.localState.sessionConfig.model,
207
170
  logger: this.logger as never,
208
- systemComposer: new SessionSystemBuilder({
209
- agentId: this.agentId,
210
- projectRoot: this.projectRoot,
211
- getSessionCreatedAt: () => this.createdAt,
212
- getSessionTimezone: () => this.timezone,
213
- getInstructionSystemBlocks: this.getInstructionSystemBlocks,
214
- getManagedPluginSystemBlocks: this.getManagedPluginSystemBlocks,
215
- getPluginSystemBlocks: this.getPluginSystemBlocks,
216
- }),
171
+ systemComposer: system_composer,
217
172
  getTools: () => this.tools,
173
+ ...(context_composer ? { contextComposer: context_composer } : {}),
174
+ ...(compaction_composer
175
+ ? { compactionComposer: compaction_composer }
176
+ : {}),
218
177
  });
219
- this.promptRuntime = new SessionPromptRuntime({
220
- sessionId: this.id,
221
- publish: (event) => {
178
+ this.stateService = new SessionStateService({
179
+ agent_id: this.agentId,
180
+ project_root: this.projectRoot,
181
+ session_id: this.id,
182
+ history_store: this.historyStore,
183
+ executor: this.executor,
184
+ state: this.localState,
185
+ ensure_configured_hook: this.ensureConfiguredHook
186
+ ? async () => {
187
+ await this.ensureConfiguredHook?.(this);
188
+ }
189
+ : undefined,
190
+ publish_event: (event) => {
222
191
  this.eventHub.publish(event);
223
192
  },
224
- createAndPersistUserMessage: async (input) => {
225
- return await this.createAndPersistUserPromptMessage(input);
226
- },
227
- executeTurn: async ({ turnId, promptInput, onStepMerge }) => {
228
- return await this.executePromptTurn({
229
- turnId,
230
- promptInput,
231
- onStepMerge,
232
- });
193
+ });
194
+ this.turnService = new SessionTurnService({
195
+ session_id: this.id,
196
+ executor: this.executor,
197
+ state_service: this.stateService,
198
+ event_hub: this.eventHub,
199
+ });
200
+ this.viewService = new SessionViewService<Session>({
201
+ agent_id: this.agentId,
202
+ project_root: this.projectRoot,
203
+ session_id: this.id,
204
+ history_store: this.historyStore,
205
+ state_service: this.stateService,
206
+ is_executing: () => this.isExecuting(),
207
+ get_instruction_system_blocks: this.getInstructionSystemBlocks,
208
+ get_managed_plugin_system_blocks: this.getManagedPluginSystemBlocks,
209
+ get_plugin_system_blocks: this.getPluginSystemBlocks,
210
+ ...(this.composers?.systemComposer
211
+ ? { custom_system_composer: system_composer }
212
+ : {}),
213
+ create_fork_session: async (session_id) => {
214
+ const session = this.createChildSession(session_id);
215
+ await session.initialize();
216
+ return {
217
+ session,
218
+ history_store: session.historyStore,
219
+ state_service: session.stateService,
220
+ };
233
221
  },
234
222
  });
235
223
  }
236
224
 
237
225
  /**
238
- * 初始化当前 session 的 meta 信息与内存配置。
226
+ * 初始化当前 session
239
227
  */
240
228
  async initialize(): Promise<this> {
241
- if (this.initializePromise) {
242
- return await this.initializePromise;
243
- }
244
- this.initializePromise = (async () => {
245
- const metadata = await readSessionMetadata({
246
- projectRoot: this.projectRoot,
247
- agentId: this.agentId,
248
- sessionId: this.id,
249
- });
250
- const createdAt =
251
- typeof metadata.createdAt === "number" ? metadata.createdAt : Date.now();
252
- const timezone =
253
- typeof metadata.timezone === "string" && metadata.timezone.trim()
254
- ? metadata.timezone.trim()
255
- : resolveSystemTimezone();
256
- await writeSessionMetadata({
257
- projectRoot: this.projectRoot,
258
- agentId: this.agentId,
259
- sessionId: this.id,
260
- meta: {
261
- ...metadata,
262
- agentId: this.agentId,
263
- createdAt,
264
- timezone,
265
- },
266
- });
267
- this.createdAt = createdAt;
268
- this.timezone = timezone;
269
- this.sessionConfig = {
270
- ...(metadata.modelLabel
271
- ? { modelLabel: metadata.modelLabel }
272
- : {}),
273
- };
274
- return this;
275
- })();
276
- return await this.initializePromise;
229
+ await this.stateService.initialize();
230
+ return this;
277
231
  }
278
232
 
279
233
  /**
280
234
  * 读取当前 session 配置快照。
281
235
  */
282
236
  get config(): AgentSessionConfigSnapshot {
283
- return {
284
- ...this.sessionConfig,
285
- };
237
+ return this.stateService.get_config();
286
238
  }
287
239
 
288
240
  /**
289
241
  * 写入当前 session 默认配置。
290
242
  */
291
243
  async set(input: AgentSessionSetInput): Promise<void> {
292
- if (input.model) {
293
- this.sessionConfig.model = normalizeAgentModel(input.model);
294
- this.sessionConfig.modelLabel = inferAgentModelLabel(input.model);
295
- this.executor.clearExecutor();
296
- }
297
- await patchSessionModelLabel({
298
- projectRoot: this.projectRoot,
299
- agentId: this.agentId,
300
- sessionId: this.id,
301
- model: this.sessionConfig.model,
302
- });
244
+ await this.stateService.set(input);
303
245
  }
304
246
 
305
247
  /**
306
248
  * 追加一条新的 Session prompt。
307
- *
308
- * 关键点(中文)
309
- * - 这是 Session actor 模型下唯一的输入入口。
310
- * - 首条输入、运行中补充输入、排到下一轮的输入,调用方式完全一致。
311
249
  */
312
250
  async prompt(input: AgentSessionPromptInput): Promise<AgentSessionTurnHandle> {
313
- const query = String(input.query || "").trim();
314
- if (!query) {
315
- throw new Error("session.prompt requires a non-empty query");
316
- }
317
- await this.ensureRunnable();
318
- return await this.promptRuntime.prompt({
319
- query,
320
- });
251
+ return await this.turnService.prompt(input);
321
252
  }
322
253
 
323
254
  /**
324
255
  * 订阅当前 Session 的未来事件。
325
- *
326
- * 关键点(中文)
327
- * - 只广播订阅之后产生的事件。
328
- * - 不做历史回放;历史仍通过 `history()` 读取。
329
256
  */
330
257
  subscribe(subscriber: AgentSessionSubscriber): AgentSessionUnsubscribe {
331
- return this.eventHub.subscribe(subscriber);
258
+ return this.turnService.subscribe(subscriber);
332
259
  }
333
260
 
334
261
  /**
335
262
  * 追加一条 user 文本消息。
336
263
  */
337
264
  async appendUserMessage(input: {
338
- /**
339
- * 需要写入的用户文本。
340
- */
341
265
  text: string;
342
266
  }): Promise<void> {
343
- await this.executor.appendUserMessage({
267
+ await this.stateService.append_user_message({
344
268
  text: String(input.text || "").trim(),
345
269
  });
346
- await this.ensureTitleFromHistory({ generate: true });
347
- await this.touchMetadata();
348
270
  }
349
271
 
350
272
  /**
351
273
  * 追加一条 assistant 文本消息。
352
274
  */
353
275
  async appendAssistantMessage(input: {
354
- /**
355
- * 需要写入的 assistant 文本。
356
- */
357
276
  text: string;
358
277
  }): Promise<void> {
359
- await this.executor.appendAssistantMessage({
278
+ await this.stateService.append_assistant_message({
360
279
  fallbackText: String(input.text || "").trim(),
361
280
  });
362
- await this.touchMetadata();
363
281
  }
364
282
 
365
283
  /**
366
284
  * 读取当前 session 详情。
367
285
  */
368
286
  async getInfo(): Promise<AgentSessionInfo> {
369
- const [metadata, messages] = await Promise.all([
370
- readSessionMetadata({
371
- projectRoot: this.projectRoot,
372
- agentId: this.agentId,
373
- sessionId: this.id,
374
- }),
375
- this.historyStore.list(),
376
- ]);
377
- const metadataWithTitle = metadata.title
378
- ? metadata
379
- : await ensureSessionTitle({
380
- projectRoot: this.projectRoot,
381
- agentId: this.agentId,
382
- sessionId: this.id,
383
- messages,
384
- });
385
- return buildSessionInfo({
386
- projectRoot: this.projectRoot,
387
- agentId: this.agentId,
388
- sessionId: this.id,
389
- metadata: metadataWithTitle,
390
- messages,
391
- executing: this.isExecuting(),
392
- });
287
+ return await this.viewService.get_info();
393
288
  }
394
289
 
395
290
  /**
396
291
  * 读取当前 session 历史分页。
397
292
  */
398
293
  async history(input?: AgentSessionHistoryInput): Promise<AgentSessionHistoryPage> {
399
- const [session, messages] = await Promise.all([
400
- this.getInfo(),
401
- this.historyStore.list(),
402
- ]);
403
- return buildSessionHistoryPage({
404
- session,
405
- messages,
406
- input,
407
- });
294
+ return await this.viewService.history(input);
408
295
  }
409
296
 
410
297
  /**
411
- * 读取当前 session 生效的 system prompt 文本集合。
412
- *
413
- * 关键点(中文)
414
- * - 返回内容与实际 run 时使用的 SDK system composer 同源。
415
- * - 包含 instruction/core、受托管 plugin system、显式注册 plugin system 与 session 上下文。
416
- * - 返回结构化快照,不把 system prompt 写入会话历史。
298
+ * 读取当前 session 生效的 system 快照。
417
299
  */
418
300
  async system(): Promise<AgentSessionSystemSnapshot> {
419
- const blocks = await buildSessionSystemBlocks({
420
- agentId: this.agentId,
421
- projectRoot: this.projectRoot,
422
- sessionId: this.id,
423
- createdAt: this.createdAt,
424
- timezone: this.timezone,
425
- getInstructionSystemBlocks: this.getInstructionSystemBlocks,
426
- getManagedPluginSystemBlocks: this.getManagedPluginSystemBlocks,
427
- getPluginSystemBlocks: this.getPluginSystemBlocks,
428
- });
429
- return {
430
- sessionId: this.id,
431
- session: {
432
- agentId: this.agentId,
433
- sessionId: this.id,
434
- projectRoot: this.projectRoot,
435
- createdAt: new Date(this.createdAt).toISOString(),
436
- timezone: this.timezone,
437
- },
438
- blocks,
439
- };
301
+ return await this.viewService.system();
440
302
  }
441
303
 
442
304
  /**
443
305
  * 返回当前 session 是否正在执行。
444
306
  */
445
307
  isExecuting(): boolean {
446
- return this.promptRuntime.isActive() || this.executor.isExecuting();
308
+ return this.turnService.is_prompt_runtime_active() || this.executor.isExecuting();
447
309
  }
448
310
 
449
311
  /**
@@ -457,48 +319,7 @@ export class Session implements AgentSession {
457
319
  * 从当前 session 创建一个分叉会话。
458
320
  */
459
321
  async fork(input?: AgentSessionForkInput | string): Promise<Session> {
460
- const messageId =
461
- typeof input === "string"
462
- ? String(input || "").trim() || undefined
463
- : String(input?.messageId || "").trim() || undefined;
464
- const messages = await this.historyStore.list();
465
- const forkMessages =
466
- !messageId
467
- ? messages
468
- : (() => {
469
- const targetIndex = messages.findIndex(
470
- (message) => String(message.id || "").trim() === messageId,
471
- );
472
- if (targetIndex < 0) {
473
- throw new Error(
474
- `Cannot fork session "${this.id}": messageId "${messageId}" not found.`,
475
- );
476
- }
477
- return messages.slice(0, targetIndex + 1);
478
- })();
479
-
480
- const forked = new Session({
481
- agentId: this.agentId,
482
- projectRoot: this.projectRoot,
483
- sessionId: `fork-${Date.now()}-${nanoid(8)}`,
484
- tools: this.tools,
485
- logger: this.logger,
486
- getInstructionSystemBlocks: this.getInstructionSystemBlocks,
487
- getManagedPluginSystemBlocks: this.getManagedPluginSystemBlocks,
488
- getPluginSystemBlocks: this.getPluginSystemBlocks,
489
- });
490
- await forked.initialize();
491
- if (this.sessionConfig.model) {
492
- await forked.set({
493
- model: this.sessionConfig.model,
494
- });
495
- }
496
- for (const message of forkMessages) {
497
- await forked.historyStore.append(message);
498
- }
499
- await forked.ensureTitleFromHistory({ generate: true });
500
- await forked.touchMetadata();
501
- return forked;
322
+ return await this.viewService.fork(input);
502
323
  }
503
324
 
504
325
  /**
@@ -509,25 +330,19 @@ export class Session implements AgentSession {
509
330
  this.runtimePort = createRuntimeSessionPort({
510
331
  sessionId: this.id,
511
332
  getExecutor: () => this.executor.getExecutor(),
512
- prompt: async (input) => {
513
- return await this.prompt(input);
514
- },
515
- subscribe: (subscriber) => {
516
- return this.subscribe(subscriber);
517
- },
333
+ prompt: async (input) => await this.prompt(input),
334
+ subscribe: (subscriber) => this.subscribe(subscriber),
518
335
  clearExecutor: () => {
519
336
  this.executor.clearExecutor();
520
337
  },
521
338
  afterSessionUpdatedAsync: async () => {
522
339
  await this.executor.afterSessionUpdatedAsync();
523
340
  },
524
- appendUserMessage: async (messageParams) => {
525
- await this.executor.appendUserMessage(messageParams);
526
- await this.ensureTitleFromHistory({ generate: true });
527
- await this.touchMetadata();
341
+ appendUserMessage: async (message_params) => {
342
+ await this.stateService.append_user_message(message_params);
528
343
  },
529
- appendAssistantMessage: async (messageParams) => {
530
- await this.executor.appendAssistantMessage(messageParams);
344
+ appendAssistantMessage: async (message_params) => {
345
+ await this.stateService.append_assistant_message(message_params);
531
346
  },
532
347
  isExecuting: () => this.isExecuting(),
533
348
  historyStore: this.historyStore,
@@ -535,7 +350,7 @@ export class Session implements AgentSession {
535
350
  await this.ensureReadyForExecution();
536
351
  },
537
352
  touchMetadata: async () => {
538
- await this.touchMetadata();
353
+ await this.stateService.touch_metadata();
539
354
  },
540
355
  });
541
356
  return this.runtimePort;
@@ -545,180 +360,58 @@ export class Session implements AgentSession {
545
360
  * 在执行前确保 session 已完成初始化与宿主装配。
546
361
  */
547
362
  async ensureReadyForExecution(): Promise<void> {
548
- await this.initialize();
549
- if (this.ensureConfiguredPromise) {
550
- await this.ensureConfiguredPromise;
551
- return;
552
- }
553
- this.ensureConfiguredPromise = (async () => {
554
- if (!this.ensureConfiguredHook) return;
555
- await this.ensureConfiguredHook(this);
556
- })();
557
- try {
558
- await this.ensureConfiguredPromise;
559
- } catch (error) {
560
- this.ensureConfiguredPromise = null;
561
- throw error;
562
- }
563
- }
564
-
565
- private async ensureRunnable(): Promise<void> {
566
- await this.ensureReadyForExecution();
567
- if (!this.sessionConfig.model) {
568
- throw new Error(
569
- `Session "${this.id}" requires a configured model. Pass model to new Agent({ model }) or call session.set({ model }) first.`,
570
- );
571
- }
572
- }
573
-
574
- private async touchMetadata(): Promise<void> {
575
- await touchSessionMetadata({
576
- projectRoot: this.projectRoot,
577
- agentId: this.agentId,
578
- sessionId: this.id,
579
- sessionConfig: this.sessionConfig,
580
- });
363
+ await this.stateService.ensure_ready_for_execution();
581
364
  }
582
365
 
583
- private async ensureTitleFromHistory(input?: {
584
- /**
585
- * 是否允许调用模型生成标题。
586
- */
587
- generate?: boolean;
588
- }): Promise<void> {
589
- const messages = await this.historyStore.list();
590
- const beforeMetadata = await readSessionMetadata({
591
- projectRoot: this.projectRoot,
366
+ private createChildSession(session_id: string): Session {
367
+ return new Session({
592
368
  agentId: this.agentId,
593
- sessionId: this.id,
594
- });
595
- const beforeTitle = String(beforeMetadata.title || "").trim();
596
- const nextMetadata = await ensureSessionTitle({
597
369
  projectRoot: this.projectRoot,
598
- agentId: this.agentId,
599
- sessionId: this.id,
600
- messages,
601
- ...(input?.generate ? { model: this.sessionConfig.model } : {}),
602
- generate: input?.generate === true,
603
- });
604
- const nextTitle = String(nextMetadata.title || "").trim();
605
- if (!nextTitle || nextTitle === beforeTitle) return;
606
- this.eventHub.publish({
607
- type: "session-title",
608
- sessionId: this.id,
609
- title: nextTitle,
370
+ sessionId: session_id,
371
+ tools: this.tools,
372
+ logger: this.logger,
373
+ getInstructionSystemBlocks: this.getInstructionSystemBlocks,
374
+ getManagedPluginSystemBlocks: this.getManagedPluginSystemBlocks,
375
+ getPluginSystemBlocks: this.getPluginSystemBlocks,
376
+ composers: this.composers,
610
377
  });
611
378
  }
612
379
 
613
- private async persistAssistantResult(
614
- assistantMessage: SessionMessageV1,
615
- ): Promise<void> {
616
- await persistSdkAssistantResult({
617
- projectRoot: this.projectRoot,
380
+ private create_composer_context(): SessionComposerFactoryContext {
381
+ return {
618
382
  agentId: this.agentId,
383
+ projectRoot: this.projectRoot,
619
384
  sessionId: this.id,
620
- sessionConfig: this.sessionConfig,
621
- executor: this.executor,
622
- assistantMessage,
623
- });
624
- }
625
-
626
- private async createAndPersistUserPromptMessage(
627
- input: AgentSessionPromptInput,
628
- ): Promise<SessionUserMessageV1> {
629
- const message = this.historyStore.userText({
630
- text: String(input.query || "").trim(),
631
- metadata: {
632
- sessionId: this.id,
633
- },
634
- }) as SessionUserMessageV1;
635
- await this.executor.appendUserMessage({
636
- message,
637
- });
638
- await this.ensureTitleFromHistory({ generate: true });
639
- await this.touchMetadata();
640
- return message;
385
+ historyStore: this.historyStore,
386
+ getTools: () => this.tools,
387
+ getInstructionSystemBlocks: this.getInstructionSystemBlocks,
388
+ getManagedPluginSystemBlocks: this.getManagedPluginSystemBlocks,
389
+ getPluginSystemBlocks: this.getPluginSystemBlocks,
390
+ getSessionCreatedAt: () => this.localState.createdAt,
391
+ getSessionTimezone: () => this.localState.timezone,
392
+ };
641
393
  }
642
394
 
643
- private async executePromptTurn(input: {
644
- turnId: string;
645
- promptInput: AgentSessionPromptInput;
646
- onStepMerge: () => Promise<SessionUserMessageV1[]>;
647
- }): Promise<{
648
- text: string;
649
- success: boolean;
650
- assistantMessage: SessionMessageV1;
651
- error?: string;
652
- }> {
653
- const toolNameByCallId = new Map<string, string>();
654
- const result = await this.executor.run({
655
- query: input.promptInput.query,
656
- onStepCallback: input.onStepMerge,
657
- onAssistantStepCallback: async (step) => {
658
- this.eventHub.publish({
659
- type: "assistant-step",
660
- turnId: input.turnId,
661
- text: step.text,
662
- stepIndex: step.stepIndex,
663
- ...(step.visibility ? { visibility: step.visibility } : {}),
664
- });
665
- },
666
- onUiMessageChunkCallback: async (chunk) => {
667
- if (chunk.type === "tool-input-start") {
668
- toolNameByCallId.set(chunk.toolCallId, chunk.toolName);
669
- return;
670
- }
671
- const event = mapUiMessageChunkToAgentEvent(chunk);
672
- if (!event) return;
673
- const resolvedEvent =
674
- (
675
- event.type === "tool-result" ||
676
- event.type === "tool-error"
677
- ) &&
678
- event.toolName === "unknown"
679
- ? {
680
- ...event,
681
- toolName:
682
- toolNameByCallId.get(event.toolCallId) || event.toolName,
683
- }
684
- : event;
685
- if (
686
- resolvedEvent.type === "tool-call" ||
687
- resolvedEvent.type === "tool-error"
688
- ) {
689
- toolNameByCallId.set(
690
- resolvedEvent.toolCallId,
691
- resolvedEvent.toolName,
692
- );
693
- }
694
- const sessionEvent = mapAgentEventToSessionEvent({
695
- event: resolvedEvent,
696
- turnId: input.turnId,
697
- });
698
- if (sessionEvent) {
699
- this.eventHub.publish(sessionEvent);
700
- }
701
- },
702
- });
703
- await this.persistAssistantResult(result.assistantMessage);
704
- await this.persistDeferredUserMessages();
705
- return {
706
- text: extractTextFromUiMessage(result.assistantMessage),
707
- success: result.success,
708
- assistantMessage: result.assistantMessage,
709
- ...(result.error ? { error: result.error } : {}),
710
- };
395
+ private resolve_composer<TComposer>(
396
+ input: SessionComposerInput<TComposer> | undefined,
397
+ context: SessionComposerFactoryContext,
398
+ create_default: () => TComposer,
399
+ ): TComposer {
400
+ const composer = this.resolve_optional_composer(input, context);
401
+ return composer || create_default();
711
402
  }
712
403
 
713
- private async persistDeferredUserMessages(): Promise<void> {
714
- const deferredMessages = drainDeferredPersistedUserMessages(this.id);
715
- for (const message of deferredMessages) {
716
- await this.executor.appendUserMessage({
717
- message,
718
- });
719
- }
720
- if (deferredMessages.length > 0) {
721
- await this.touchMetadata();
404
+ private resolve_optional_composer<TComposer>(
405
+ input: SessionComposerInput<TComposer> | undefined,
406
+ context: SessionComposerFactoryContext,
407
+ ): TComposer | undefined {
408
+ if (!input) return undefined;
409
+ if (typeof input === "function") {
410
+ const create_composer = input as (
411
+ context: SessionComposerFactoryContext,
412
+ ) => TComposer;
413
+ return create_composer(context);
722
414
  }
415
+ return input;
723
416
  }
724
417
  }