@downcity/agent 1.1.232 → 1.1.237
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.
- package/bin/agent/local/Agent.d.ts +1 -1
- package/bin/agent/local/Agent.js +2 -2
- package/bin/agent/local/Agent.js.map +1 -1
- package/bin/agent/local/services/AgentSessions.d.ts +4 -4
- package/bin/agent/local/services/AgentSessions.d.ts.map +1 -1
- package/bin/agent/local/services/AgentSessions.js +8 -8
- package/bin/agent/local/services/AgentSessions.js.map +1 -1
- package/bin/agent/remote/RemoteSession.d.ts +2 -0
- package/bin/agent/remote/RemoteSession.d.ts.map +1 -1
- package/bin/agent/remote/RemoteSession.js +4 -0
- package/bin/agent/remote/RemoteSession.js.map +1 -1
- package/bin/agent/remote/RemoteTransport.d.ts +2 -0
- package/bin/agent/remote/RemoteTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts +1 -0
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.js +11 -0
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.js.map +1 -1
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts +1 -0
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.js +3 -0
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.js.map +1 -1
- package/bin/executor/Executor.d.ts +20 -2
- package/bin/executor/Executor.d.ts.map +1 -1
- package/bin/executor/Executor.js +102 -18
- package/bin/executor/Executor.js.map +1 -1
- package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts +6 -0
- package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.d.ts +0 -9
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js +4 -38
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts +1 -3
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js +7 -59
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js.map +1 -1
- package/bin/executor/core-engine/CoreEngineContextCompaction.d.ts +38 -0
- package/bin/executor/core-engine/CoreEngineContextCompaction.d.ts.map +1 -0
- package/bin/executor/core-engine/CoreEngineContextCompaction.js +392 -0
- package/bin/executor/core-engine/CoreEngineContextCompaction.js.map +1 -0
- package/bin/executor/core-engine/CoreEngineMessageState.d.ts +15 -0
- package/bin/executor/core-engine/CoreEngineMessageState.d.ts.map +1 -1
- package/bin/executor/core-engine/CoreEngineMessageState.js +20 -0
- package/bin/executor/core-engine/CoreEngineMessageState.js.map +1 -1
- package/bin/executor/core-engine/CoreEngineRunner.d.ts +9 -5
- package/bin/executor/core-engine/CoreEngineRunner.d.ts.map +1 -1
- package/bin/executor/core-engine/CoreEngineRunner.js +146 -35
- package/bin/executor/core-engine/CoreEngineRunner.js.map +1 -1
- package/bin/executor/store/history/SessionHistoryStore.d.ts +4 -10
- package/bin/executor/store/history/SessionHistoryStore.d.ts.map +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts.map +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +1 -3
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +1 -1
- package/bin/executor/types/SessionRun.d.ts +8 -0
- package/bin/executor/types/SessionRun.d.ts.map +1 -1
- package/bin/index.d.ts +1 -1
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +1 -1
- package/bin/index.js.map +1 -1
- package/bin/plugin/core/PluginLocalExecution.js +3 -3
- package/bin/plugin/core/PluginLocalExecution.js.map +1 -1
- package/bin/plugin/core/PluginRegistry.d.ts +20 -2
- package/bin/plugin/core/PluginRegistry.d.ts.map +1 -1
- package/bin/plugin/core/PluginRegistry.js +100 -3
- package/bin/plugin/core/PluginRegistry.js.map +1 -1
- package/bin/rpc/Client.d.ts +6 -4
- package/bin/rpc/Client.d.ts.map +1 -1
- package/bin/rpc/Client.js +11 -0
- package/bin/rpc/Client.js.map +1 -1
- package/bin/session/Session.d.ts +7 -3
- package/bin/session/Session.d.ts.map +1 -1
- package/bin/session/Session.js +26 -19
- package/bin/session/Session.js.map +1 -1
- package/bin/session/SessionSystemBuilder.d.ts.map +1 -1
- package/bin/session/SessionSystemBuilder.js +3 -1
- package/bin/session/SessionSystemBuilder.js.map +1 -1
- package/bin/session/recorder/SessionRecorderCompaction.d.ts.map +1 -1
- package/bin/session/recorder/SessionRecorderCompaction.js +102 -60
- package/bin/session/recorder/SessionRecorderCompaction.js.map +1 -1
- package/bin/session/runtime/SessionPromptRuntime.d.ts +11 -7
- package/bin/session/runtime/SessionPromptRuntime.d.ts.map +1 -1
- package/bin/session/runtime/SessionPromptRuntime.js +22 -24
- package/bin/session/runtime/SessionPromptRuntime.js.map +1 -1
- package/bin/session/services/SessionStateService.d.ts +10 -6
- package/bin/session/services/SessionStateService.d.ts.map +1 -1
- package/bin/session/services/SessionStateService.js +29 -20
- package/bin/session/services/SessionStateService.js.map +1 -1
- package/bin/session/services/SessionTurnService.d.ts +13 -3
- package/bin/session/services/SessionTurnService.d.ts.map +1 -1
- package/bin/session/services/SessionTurnService.js +90 -7
- package/bin/session/services/SessionTurnService.js.map +1 -1
- package/bin/types/agent/SessionActor.d.ts +8 -0
- package/bin/types/agent/SessionActor.d.ts.map +1 -1
- package/bin/types/executor/SessionRunContext.d.ts +16 -8
- package/bin/types/executor/SessionRunContext.d.ts.map +1 -1
- package/bin/types/plugin/PluginRuntime.d.ts +36 -4
- package/bin/types/plugin/PluginRuntime.d.ts.map +1 -1
- package/bin/types/plugin/PluginState.d.ts +10 -0
- package/bin/types/plugin/PluginState.d.ts.map +1 -1
- package/bin/types/rpc/RpcProtocol.d.ts +21 -0
- package/bin/types/rpc/RpcProtocol.d.ts.map +1 -1
- package/bin/types/runtime/agent/AgentContext.d.ts +2 -2
- package/bin/types/runtime/agent/AgentContext.js +1 -1
- package/bin/types/session/SessionLocalState.d.ts +2 -2
- package/bin/types/session/SessionOptions.d.ts +5 -5
- package/bin/types/session/SessionOptions.d.ts.map +1 -1
- package/bin/types/session/SessionQueueCommand.d.ts +68 -0
- package/bin/types/session/SessionQueueCommand.d.ts.map +1 -0
- package/bin/types/session/SessionQueueCommand.js +10 -0
- package/bin/types/session/SessionQueueCommand.js.map +1 -0
- package/bin/utils/logger/Logger.d.ts +7 -9
- package/bin/utils/logger/Logger.d.ts.map +1 -1
- package/bin/utils/logger/Logger.js +11 -9
- package/bin/utils/logger/Logger.js.map +1 -1
- package/package.json +3 -3
- package/scripts/core-engine-context-compaction.test.mjs +411 -0
- package/scripts/logger-isolation.test.mjs +55 -0
- package/scripts/multi-agent-plugin-isolation.test.mjs +289 -0
- package/scripts/plugin-tool-bridge.test.mjs +52 -0
- package/scripts/remote-session-reconnect.test.mjs +18 -0
- package/scripts/session-compaction-context-window.test.mjs +27 -26
- package/scripts/session-config-turn-boundary.test.mjs +80 -26
- package/scripts/session-prompt-runtime.test.mjs +23 -15
- package/scripts/session-recorder.test.mjs +15 -24
- package/src/agent/local/Agent.ts +2 -2
- package/src/agent/local/services/AgentSessions.ts +10 -10
- package/src/agent/remote/RemoteSession.ts +5 -0
- package/src/agent/remote/RemoteTransport.ts +2 -0
- package/src/agent/remote/transports/HttpRemoteAgentTransport.ts +15 -0
- package/src/agent/remote/transports/RpcRemoteAgentTransport.ts +4 -0
- package/src/executor/Executor.ts +111 -19
- package/src/executor/composer/compaction/SessionCompactionComposer.ts +7 -0
- package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.ts +4 -57
- package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.ts +8 -66
- package/src/executor/core-engine/CoreEngineContextCompaction.ts +477 -0
- package/src/executor/core-engine/CoreEngineMessageState.ts +29 -0
- package/src/executor/core-engine/CoreEngineRunner.ts +200 -48
- package/src/executor/store/history/SessionHistoryStore.ts +4 -12
- package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +1 -3
- package/src/executor/types/SessionRun.ts +9 -0
- package/src/index.ts +1 -1
- package/src/plugin/core/PluginLocalExecution.ts +3 -3
- package/src/plugin/core/PluginRegistry.ts +116 -3
- package/src/rpc/Client.ts +15 -2
- package/src/session/Session.ts +28 -20
- package/src/session/SessionSystemBuilder.ts +4 -1
- package/src/session/recorder/SessionRecorderCompaction.ts +113 -65
- package/src/session/runtime/SessionPromptRuntime.ts +31 -46
- package/src/session/services/SessionStateService.ts +34 -25
- package/src/session/services/SessionTurnService.ts +97 -8
- package/src/types/agent/SessionActor.ts +9 -0
- package/src/types/executor/SessionRunContext.ts +17 -8
- package/src/types/plugin/PluginRuntime.ts +38 -4
- package/src/types/plugin/PluginState.ts +10 -0
- package/src/types/rpc/RpcProtocol.ts +23 -0
- package/src/types/runtime/agent/AgentContext.ts +2 -2
- package/src/types/session/SessionLocalState.ts +2 -2
- package/src/types/session/SessionOptions.ts +6 -6
- package/src/types/session/SessionQueueCommand.ts +78 -0
- package/src/utils/logger/Logger.ts +10 -10
- package/tsconfig.tsbuildinfo +1 -1
- package/bin/types/session/SessionConfigMutation.d.ts +0 -68
- package/bin/types/session/SessionConfigMutation.d.ts.map +0 -1
- package/bin/types/session/SessionConfigMutation.js +0 -10
- package/bin/types/session/SessionConfigMutation.js.map +0 -1
- package/src/types/session/SessionConfigMutation.ts +0 -78
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
* - 保持失败返回结构稳定,避免对外 Session 行为变化。
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
streamText,
|
|
12
|
+
type FileUIPart,
|
|
13
|
+
type LanguageModel,
|
|
14
|
+
type StepResult,
|
|
15
|
+
type Tool,
|
|
16
|
+
} from "ai";
|
|
11
17
|
import { buildOpenAIResponsesProviderOptions } from "@executor/messages/SessionMessageCodec.js";
|
|
12
18
|
import { logAssistantMessageNow } from "@executor/messages/SessionMessageLog.js";
|
|
13
19
|
import {
|
|
@@ -33,6 +39,11 @@ import {
|
|
|
33
39
|
} from "@executor/core-engine/CoreEngineError.js";
|
|
34
40
|
import { collectFinalAssistantMessageFromUiStream } from "@executor/core-engine/CoreEngineUiStreamCollector.js";
|
|
35
41
|
import { CoreEngineMessageState } from "@executor/core-engine/CoreEngineMessageState.js";
|
|
42
|
+
import {
|
|
43
|
+
deep_compact_model_messages,
|
|
44
|
+
resolve_model_usage_ratio,
|
|
45
|
+
should_compact_after_usage,
|
|
46
|
+
} from "@executor/core-engine/CoreEngineContextCompaction.js";
|
|
36
47
|
import type { Logger } from "@/utils/logger/Logger.js";
|
|
37
48
|
import type { SessionHistoryStore } from "@/executor/store/history/SessionHistoryStore.js";
|
|
38
49
|
import type { SessionContextComposer } from "@executor/composer/context/SessionContextComposer.js";
|
|
@@ -48,6 +59,9 @@ import type {
|
|
|
48
59
|
|
|
49
60
|
const TURN_STOPPED_MESSAGE = "Turn stopped";
|
|
50
61
|
|
|
62
|
+
/** Provider context-length error 在当前 step 内最多压缩重试三次。 */
|
|
63
|
+
const MAX_CONTEXT_ERROR_COMPACTION_RETRIES = 3;
|
|
64
|
+
|
|
51
65
|
/**
|
|
52
66
|
* 生成 file part 去重 key。
|
|
53
67
|
*/
|
|
@@ -127,15 +141,17 @@ interface CoreEngineRunInput {
|
|
|
127
141
|
run_context: SessionRunContext;
|
|
128
142
|
|
|
129
143
|
/**
|
|
130
|
-
*
|
|
144
|
+
* 在统一输入队列提交后解析当前 Session step 的 effective 配置。
|
|
131
145
|
*/
|
|
132
|
-
|
|
133
|
-
/**
|
|
146
|
+
resolve_step_inputs: () => Promise<{
|
|
147
|
+
/** 当前 Session step 使用的模型。 */
|
|
134
148
|
model: LanguageModel;
|
|
135
|
-
/**
|
|
149
|
+
/** 当前 Session step 使用的 system messages。 */
|
|
136
150
|
system: SessionExecuteInput["system"];
|
|
137
|
-
/**
|
|
151
|
+
/** 当前 Session step 使用的工具集合。 */
|
|
138
152
|
tools: SessionExecuteInput["tools"];
|
|
153
|
+
/** 当前 Session step 模型支持的总上下文窗口长度。 */
|
|
154
|
+
context_window?: number;
|
|
139
155
|
}>;
|
|
140
156
|
}
|
|
141
157
|
|
|
@@ -148,6 +164,9 @@ export class CoreEngineRunner {
|
|
|
148
164
|
private readonly logger: Logger;
|
|
149
165
|
private readonly should_compact_on_error: CoreEngineRunnerOptions["should_compact_on_error"];
|
|
150
166
|
|
|
167
|
+
/** 最近一次已经通过真实 usage 验收的持久化 Summary 标识。 */
|
|
168
|
+
private validated_compaction_summary_id = "";
|
|
169
|
+
|
|
151
170
|
constructor(options: CoreEngineRunnerOptions) {
|
|
152
171
|
this.history_store = options.history_store;
|
|
153
172
|
this.context_composer = options.context_composer;
|
|
@@ -167,6 +186,7 @@ export class CoreEngineRunner {
|
|
|
167
186
|
let tools = input.execute_input.tools;
|
|
168
187
|
let last_observed_stream_error: unknown = undefined;
|
|
169
188
|
let final_assistant_ui_message: SessionMessageRecordV1 | null = null;
|
|
189
|
+
let compact_required = false;
|
|
170
190
|
|
|
171
191
|
try {
|
|
172
192
|
const message_state = await CoreEngineMessageState.create({
|
|
@@ -174,6 +194,9 @@ export class CoreEngineRunner {
|
|
|
174
194
|
tools,
|
|
175
195
|
projectRoot: input.run_context.projectRoot,
|
|
176
196
|
});
|
|
197
|
+
let persisted_compaction_summary_id = resolve_compaction_summary_id(
|
|
198
|
+
input.execute_input.messages,
|
|
199
|
+
);
|
|
177
200
|
|
|
178
201
|
const append_merged_user_messages = (messages: SessionRecordV1[]) =>
|
|
179
202
|
message_state.appendMergedUserMessages(messages);
|
|
@@ -200,7 +223,7 @@ export class CoreEngineRunner {
|
|
|
200
223
|
await context_composer_on_step_finish(step_result);
|
|
201
224
|
};
|
|
202
225
|
|
|
203
|
-
const
|
|
226
|
+
const prepare_step_inputs = this.context_composer.createPrepareStepHandler({
|
|
204
227
|
system,
|
|
205
228
|
appendMergedUserMessages: append_merged_user_messages,
|
|
206
229
|
runContext: input.run_context,
|
|
@@ -208,58 +231,169 @@ export class CoreEngineRunner {
|
|
|
208
231
|
|
|
209
232
|
let text_only_continuation_count = 0;
|
|
210
233
|
let incomplete_response_recovery_count = 0;
|
|
234
|
+
let context_error_compaction_retries = 0;
|
|
235
|
+
let compact_pending = false;
|
|
236
|
+
let compact_validation_pending = Boolean(
|
|
237
|
+
persisted_compaction_summary_id &&
|
|
238
|
+
persisted_compaction_summary_id !==
|
|
239
|
+
this.validated_compaction_summary_id,
|
|
240
|
+
);
|
|
241
|
+
let compact_depth = 0;
|
|
211
242
|
|
|
212
243
|
while (step_count < MAX_TOOL_LOOP_STEPS) {
|
|
213
|
-
// 关键点(中文):steer
|
|
214
|
-
//
|
|
215
|
-
await
|
|
216
|
-
const
|
|
217
|
-
system = Array.isArray(
|
|
218
|
-
tools =
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
...summarizeStreamError(error),
|
|
232
|
-
});
|
|
233
|
-
},
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
const step_assistant_ui_message =
|
|
237
|
-
await collectFinalAssistantMessageFromUiStream({
|
|
238
|
-
result,
|
|
244
|
+
// 关键点(中文):steer 与 command 在同一个 Session step 检查点执行。
|
|
245
|
+
// 当前流与 tool callback 保持原执行视图,下一 step 再统一读取 effective 配置。
|
|
246
|
+
await prepare_step_inputs({ messages: [] });
|
|
247
|
+
const step_inputs = await input.resolve_step_inputs();
|
|
248
|
+
system = Array.isArray(step_inputs.system) ? step_inputs.system : [];
|
|
249
|
+
tools = step_inputs.tools;
|
|
250
|
+
if (input.run_context.consume_history_reload?.()) {
|
|
251
|
+
const canonical_records = await this.history_store.list_records();
|
|
252
|
+
await message_state.replace_session_messages(canonical_records, tools);
|
|
253
|
+
persisted_compaction_summary_id = resolve_compaction_summary_id(
|
|
254
|
+
canonical_records,
|
|
255
|
+
);
|
|
256
|
+
compact_validation_pending = Boolean(
|
|
257
|
+
persisted_compaction_summary_id &&
|
|
258
|
+
persisted_compaction_summary_id !==
|
|
259
|
+
this.validated_compaction_summary_id,
|
|
260
|
+
);
|
|
261
|
+
await this.logger.log("info", "[agent] context.history_reloaded", {
|
|
239
262
|
sessionId: session_id,
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
263
|
+
recordCount: canonical_records.length,
|
|
264
|
+
compactionSummaryId: persisted_compaction_summary_id || undefined,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
if (compact_pending) {
|
|
268
|
+
const previous_message_count = message_state.modelMessages.length;
|
|
269
|
+
message_state.replace_model_messages(
|
|
270
|
+
deep_compact_model_messages(
|
|
271
|
+
message_state.modelMessages,
|
|
272
|
+
compact_depth,
|
|
273
|
+
),
|
|
274
|
+
);
|
|
275
|
+
compact_depth += 1;
|
|
276
|
+
compact_pending = false;
|
|
277
|
+
compact_validation_pending = true;
|
|
278
|
+
compact_required = true;
|
|
279
|
+
await this.logger.log("info", "[agent] context.compacted", {
|
|
280
|
+
sessionId: session_id,
|
|
281
|
+
reason: "usage_threshold",
|
|
282
|
+
compactDepth: compact_depth,
|
|
283
|
+
previousMessageCount: previous_message_count,
|
|
284
|
+
nextMessageCount: message_state.modelMessages.length,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
last_observed_stream_error = undefined;
|
|
289
|
+
let step_assistant_ui_message: SessionMessageRecordV1;
|
|
290
|
+
let executed_steps: StepResult<Record<string, Tool>>[];
|
|
291
|
+
try {
|
|
292
|
+
const result = streamText({
|
|
293
|
+
model: step_inputs.model,
|
|
294
|
+
system,
|
|
295
|
+
onStepFinish: on_step_finish,
|
|
296
|
+
messages: message_state.modelMessages,
|
|
297
|
+
tools,
|
|
247
298
|
abortSignal: input.run_context.abortSignal,
|
|
299
|
+
providerOptions: buildOpenAIResponsesProviderOptions(),
|
|
300
|
+
onError: async ({ error }) => {
|
|
301
|
+
last_observed_stream_error = error;
|
|
302
|
+
await this.logger.log("error", "[agent] stream.error", {
|
|
303
|
+
sessionId: session_id,
|
|
304
|
+
...summarizeStreamError(error),
|
|
305
|
+
});
|
|
306
|
+
},
|
|
248
307
|
});
|
|
249
308
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
309
|
+
step_assistant_ui_message =
|
|
310
|
+
await collectFinalAssistantMessageFromUiStream({
|
|
311
|
+
result,
|
|
312
|
+
sessionId: session_id,
|
|
313
|
+
logger: this.logger,
|
|
314
|
+
buildFallbackAssistantMessage: (text) =>
|
|
315
|
+
this.context_composer.buildFallbackAssistantMessage(
|
|
316
|
+
text,
|
|
317
|
+
input.run_context,
|
|
318
|
+
),
|
|
319
|
+
onUiMessageChunkCallback: input.run_context.onUiMessageChunkCallback,
|
|
320
|
+
abortSignal: input.run_context.abortSignal,
|
|
321
|
+
});
|
|
254
322
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
323
|
+
final_assistant_ui_message = mergeAssistantUiMessages(
|
|
324
|
+
final_assistant_ui_message,
|
|
325
|
+
step_assistant_ui_message,
|
|
326
|
+
);
|
|
258
327
|
|
|
259
|
-
|
|
328
|
+
// 关键点(中文):先保存本 step 已收敛的 assistant 消息,再等待 steps。
|
|
329
|
+
// stop/abort 时 `result.steps` 可能抛错,但当前已经生成的文本仍应沉淀。
|
|
330
|
+
message_state.appendRuntimeSessionMessage(step_assistant_ui_message);
|
|
331
|
+
executed_steps = await result.steps;
|
|
332
|
+
} catch (error) {
|
|
333
|
+
const compact_error = this.should_compact_on_error(error)
|
|
334
|
+
? error
|
|
335
|
+
: last_observed_stream_error;
|
|
336
|
+
if (
|
|
337
|
+
this.should_compact_on_error(compact_error) &&
|
|
338
|
+
context_error_compaction_retries <
|
|
339
|
+
MAX_CONTEXT_ERROR_COMPACTION_RETRIES
|
|
340
|
+
) {
|
|
341
|
+
context_error_compaction_retries += 1;
|
|
342
|
+
const previous_message_count = message_state.modelMessages.length;
|
|
343
|
+
message_state.replace_model_messages(
|
|
344
|
+
deep_compact_model_messages(
|
|
345
|
+
message_state.modelMessages,
|
|
346
|
+
compact_depth,
|
|
347
|
+
),
|
|
348
|
+
);
|
|
349
|
+
compact_depth += 1;
|
|
350
|
+
compact_pending = false;
|
|
351
|
+
compact_validation_pending = true;
|
|
352
|
+
compact_required = true;
|
|
353
|
+
await this.logger.log("warn", "[agent] context.compacted", {
|
|
354
|
+
sessionId: session_id,
|
|
355
|
+
reason: "provider_context_error",
|
|
356
|
+
retryCount: context_error_compaction_retries,
|
|
357
|
+
compactDepth: compact_depth,
|
|
358
|
+
previousMessageCount: previous_message_count,
|
|
359
|
+
nextMessageCount: message_state.modelMessages.length,
|
|
360
|
+
...summarizeStreamError(compact_error),
|
|
361
|
+
});
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
throw error;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
context_error_compaction_retries = 0;
|
|
260
368
|
const last_step = executed_steps[executed_steps.length - 1];
|
|
261
369
|
if (!last_step) break;
|
|
262
370
|
|
|
371
|
+
const usage_ratio = resolve_model_usage_ratio(
|
|
372
|
+
last_step.usage,
|
|
373
|
+
step_inputs.context_window,
|
|
374
|
+
);
|
|
375
|
+
if (usage_ratio !== null) {
|
|
376
|
+
const validating_compaction = compact_validation_pending;
|
|
377
|
+
compact_pending = should_compact_after_usage(
|
|
378
|
+
usage_ratio,
|
|
379
|
+
validating_compaction,
|
|
380
|
+
);
|
|
381
|
+
compact_validation_pending = false;
|
|
382
|
+
if (validating_compaction && persisted_compaction_summary_id) {
|
|
383
|
+
this.validated_compaction_summary_id =
|
|
384
|
+
persisted_compaction_summary_id;
|
|
385
|
+
}
|
|
386
|
+
if (compact_pending) compact_required = true;
|
|
387
|
+
await this.logger.log("info", "[agent] context.usage", {
|
|
388
|
+
sessionId: session_id,
|
|
389
|
+
stepIndex: step_count,
|
|
390
|
+
usageRatio: usage_ratio,
|
|
391
|
+
contextWindow: step_inputs.context_window,
|
|
392
|
+
validatingCompaction: validating_compaction,
|
|
393
|
+
compactPending: compact_pending,
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
|
|
263
397
|
const incomplete_response = detectIncompleteResponse({
|
|
264
398
|
stepResult: last_step,
|
|
265
399
|
assistantMessage: step_assistant_ui_message,
|
|
@@ -424,6 +558,7 @@ export class CoreEngineRunner {
|
|
|
424
558
|
return {
|
|
425
559
|
success: true,
|
|
426
560
|
assistantMessage: final_message,
|
|
561
|
+
...(compact_required ? { compact_required: true } : {}),
|
|
427
562
|
deferredPersistedUserMessages: [
|
|
428
563
|
...input.run_context.deferredPersistedUserMessages,
|
|
429
564
|
],
|
|
@@ -444,6 +579,7 @@ export class CoreEngineRunner {
|
|
|
444
579
|
success: false,
|
|
445
580
|
error: error_text,
|
|
446
581
|
...(stopped_message ? { assistantMessage: stopped_message } : {}),
|
|
582
|
+
...(compact_required ? { compact_required: true } : {}),
|
|
447
583
|
deferredPersistedUserMessages: [
|
|
448
584
|
...input.run_context.deferredPersistedUserMessages,
|
|
449
585
|
],
|
|
@@ -470,6 +606,7 @@ export class CoreEngineRunner {
|
|
|
470
606
|
`Execution failed: ${error_text}`,
|
|
471
607
|
input.run_context,
|
|
472
608
|
),
|
|
609
|
+
...(compact_required ? { compact_required: true } : {}),
|
|
473
610
|
deferredPersistedUserMessages: [
|
|
474
611
|
...input.run_context.deferredPersistedUserMessages,
|
|
475
612
|
],
|
|
@@ -477,3 +614,18 @@ export class CoreEngineRunner {
|
|
|
477
614
|
}
|
|
478
615
|
}
|
|
479
616
|
}
|
|
617
|
+
|
|
618
|
+
/** 读取当前模型上下文中最新的持久化 compact Summary 标识。 */
|
|
619
|
+
function resolve_compaction_summary_id(messages: SessionRecordV1[]): string {
|
|
620
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
621
|
+
const message = messages[index];
|
|
622
|
+
if (!("role" in message) || message.role !== "assistant") continue;
|
|
623
|
+
if (
|
|
624
|
+
message.metadata?.source === "compact" &&
|
|
625
|
+
message.metadata.kind === "summary"
|
|
626
|
+
) {
|
|
627
|
+
return String(message.id || "").trim();
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return "";
|
|
631
|
+
}
|
|
@@ -30,19 +30,11 @@ export type SessionHistoryCompactInput = {
|
|
|
30
30
|
system: SessionSystemMessage[];
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 输入 token 近似上限。
|
|
39
|
-
*/
|
|
40
|
-
maxInputTokensApprox: number;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* 前段压缩比例(0-1)。
|
|
33
|
+
* 是否明确要求本次执行持久化 deep compact。
|
|
34
|
+
*
|
|
35
|
+
* 真实 usage 触发与内存消息折叠由 CoreEngine 决定;Store 只负责归档已经完成的历史。
|
|
44
36
|
*/
|
|
45
|
-
|
|
37
|
+
force?: boolean;
|
|
46
38
|
|
|
47
39
|
/**
|
|
48
40
|
* 可选 action 发布回调。
|
|
@@ -665,10 +665,8 @@ export class JsonlSessionHistoryStore implements SessionHistoryStore {
|
|
|
665
665
|
{
|
|
666
666
|
model: input.model,
|
|
667
667
|
system: this.normalizeSystem(input.system),
|
|
668
|
-
keepLastMessages: input.keepLastMessages,
|
|
669
|
-
maxInputTokensApprox: input.maxInputTokensApprox,
|
|
670
668
|
archiveOnCompact: false,
|
|
671
|
-
|
|
669
|
+
force: input.force,
|
|
672
670
|
...(input.onAction ? { onAction: input.onAction } : {}),
|
|
673
671
|
},
|
|
674
672
|
);
|
|
@@ -112,6 +112,15 @@ export interface SessionRunResult {
|
|
|
112
112
|
* - 为保证消息顺序稳定,统一在 assistant 结果落盘后再由外层 Session 持久化。
|
|
113
113
|
*/
|
|
114
114
|
deferredPersistedUserMessages?: SessionUserMessageV1[];
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 本轮结束后是否需要把已完成的 canonical 历史持久化压缩。
|
|
118
|
+
*
|
|
119
|
+
* 关键点(中文)
|
|
120
|
+
* - 真实 usage 达到 95% 或本轮已经执行过内存 compact 时为 true。
|
|
121
|
+
* - 上层必须等 Assistant writer 收口后再执行,避免压缩流式草稿。
|
|
122
|
+
*/
|
|
123
|
+
compact_required?: boolean;
|
|
115
124
|
}
|
|
116
125
|
|
|
117
126
|
/**
|
package/src/index.ts
CHANGED
|
@@ -247,7 +247,7 @@ export {
|
|
|
247
247
|
export { assertProjectExecutionTarget } from "./config/ExecutionBinding.js";
|
|
248
248
|
|
|
249
249
|
// 日志
|
|
250
|
-
export { getLogger,
|
|
250
|
+
export { getLogger, type Logger } from "./utils/logger/Logger.js";
|
|
251
251
|
export { generateId } from "./utils/Id.js";
|
|
252
252
|
export {
|
|
253
253
|
formatDateTimeInTimezone,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import path from "node:path";
|
|
11
|
-
import {
|
|
11
|
+
import { getLogger } from "@/utils/logger/Logger.js";
|
|
12
12
|
import { resolve_agent_env } from "@/config/AgentEnv.js";
|
|
13
13
|
import { findPluginByName } from "@/plugin/core/PluginCatalog.js";
|
|
14
14
|
import {
|
|
@@ -45,12 +45,12 @@ export function createLocalPluginCommandContext(
|
|
|
45
45
|
: input.config;
|
|
46
46
|
const agent_id = String(config.id || "").trim() || path.basename(rootPath) || "agent";
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
const logger = getLogger(rootPath);
|
|
49
49
|
|
|
50
50
|
return {
|
|
51
51
|
cwd: rootPath,
|
|
52
52
|
rootPath,
|
|
53
|
-
logger
|
|
53
|
+
logger,
|
|
54
54
|
config,
|
|
55
55
|
env,
|
|
56
56
|
paths: createAgentPathRuntime(
|
|
@@ -13,6 +13,7 @@ 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,
|
|
16
17
|
AgentPluginExecutionRuntime,
|
|
17
18
|
PluginAvailability,
|
|
18
19
|
PluginActionReadView,
|
|
@@ -46,6 +47,9 @@ function create_record(plugin: Plugin): PluginRuntimeRecord {
|
|
|
46
47
|
updated_at: current_time,
|
|
47
48
|
chain: Promise.resolve(),
|
|
48
49
|
lifecycle_started: false,
|
|
50
|
+
active_execution_leases: 0,
|
|
51
|
+
retired: false,
|
|
52
|
+
retirement_started: false,
|
|
49
53
|
};
|
|
50
54
|
}
|
|
51
55
|
|
|
@@ -102,6 +106,8 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
102
106
|
|
|
103
107
|
private readonly records = new Map<string, PluginRuntimeRecord>();
|
|
104
108
|
|
|
109
|
+
private readonly retired_records = new Set<PluginRuntimeRecord>();
|
|
110
|
+
|
|
105
111
|
private change_listener?: (input: {
|
|
106
112
|
/** 当前修改是注册还是卸载。 */
|
|
107
113
|
type: "register" | "unregister";
|
|
@@ -183,7 +189,12 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
183
189
|
}
|
|
184
190
|
|
|
185
191
|
/**
|
|
186
|
-
* 卸载指定 plugin。
|
|
192
|
+
* 从 configured registry 卸载指定 plugin。
|
|
193
|
+
*
|
|
194
|
+
* 关键点(中文)
|
|
195
|
+
* - configured registry、hooks 与直接调用入口立即移除。
|
|
196
|
+
* - lifecycle.stop 等当前活跃 Session step 的 execution lease 全部释放后执行。
|
|
197
|
+
* - 该方法返回配置修改结果,不等待仍在运行的 step 结束。
|
|
187
198
|
*/
|
|
188
199
|
async unregister(pluginName: string): Promise<boolean> {
|
|
189
200
|
const key = normalize_plugin_name(pluginName);
|
|
@@ -191,10 +202,10 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
191
202
|
const record = this.records.get(key);
|
|
192
203
|
if (!record) return false;
|
|
193
204
|
|
|
194
|
-
await this.stop_record(record);
|
|
195
205
|
this.unregister_hooks(key);
|
|
196
206
|
this.records.delete(key);
|
|
197
207
|
this.pluginInstances.delete(key);
|
|
208
|
+
this.retire_record(record);
|
|
198
209
|
this.change_listener?.({ type: "unregister", plugin_name: key });
|
|
199
210
|
return true;
|
|
200
211
|
}
|
|
@@ -222,6 +233,10 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
222
233
|
for (const name of Array.from(this.records.keys())) {
|
|
223
234
|
await this.unregister(name);
|
|
224
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);
|
|
225
240
|
}
|
|
226
241
|
|
|
227
242
|
/**
|
|
@@ -616,7 +631,7 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
616
631
|
}
|
|
617
632
|
|
|
618
633
|
/**
|
|
619
|
-
* 创建当前 configured registry
|
|
634
|
+
* 创建当前 configured registry 的 Session step 执行视图。
|
|
620
635
|
*/
|
|
621
636
|
execution_view(): AgentPluginExecutionRuntime {
|
|
622
637
|
const records = new Map(this.records);
|
|
@@ -626,6 +641,104 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
626
641
|
await this.run_action_from_records(records, params),
|
|
627
642
|
systemBlocks: async () =>
|
|
628
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
|
+
},
|
|
629
690
|
};
|
|
630
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
|
+
}
|
|
631
744
|
}
|
package/src/rpc/Client.ts
CHANGED
|
@@ -50,6 +50,7 @@ import type { AgentSessionPromptInput } from "@/types/sdk/AgentSessionPrompt.js"
|
|
|
50
50
|
import type {
|
|
51
51
|
RpcClientEndpoint,
|
|
52
52
|
RpcClientFrame,
|
|
53
|
+
RpcInternalStatus,
|
|
53
54
|
RpcRequest,
|
|
54
55
|
RpcSessionSubscription,
|
|
55
56
|
RpcSystemPromptPayload,
|
|
@@ -217,6 +218,18 @@ export class RpcClient {
|
|
|
217
218
|
return data.result;
|
|
218
219
|
}
|
|
219
220
|
|
|
221
|
+
/**
|
|
222
|
+
* 把一次显式历史压缩加入远程 Session 的有序输入队列。
|
|
223
|
+
*/
|
|
224
|
+
async compact_session(session_id: string): Promise<void> {
|
|
225
|
+
await this.request<{ queued: true }>({
|
|
226
|
+
method: "sdk.sessions.compact",
|
|
227
|
+
params: {
|
|
228
|
+
sessionId: session_id,
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
220
233
|
/**
|
|
221
234
|
* 读取 session records。
|
|
222
235
|
*/
|
|
@@ -344,8 +357,8 @@ export class RpcClient {
|
|
|
344
357
|
/**
|
|
345
358
|
* 读取 Agent 内部状态。
|
|
346
359
|
*/
|
|
347
|
-
async get_internal_status(): Promise<
|
|
348
|
-
return await this.request<
|
|
360
|
+
async get_internal_status(): Promise<RpcInternalStatus> {
|
|
361
|
+
return await this.request<RpcInternalStatus>({
|
|
349
362
|
method: "internal.status.get",
|
|
350
363
|
});
|
|
351
364
|
}
|