@downcity/agent 1.1.228 → 1.1.232
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 +6 -1
- package/bin/agent/local/Agent.d.ts.map +1 -1
- package/bin/agent/local/Agent.js +30 -3
- package/bin/agent/local/Agent.js.map +1 -1
- package/bin/agent/local/services/AgentSessions.d.ts +23 -0
- package/bin/agent/local/services/AgentSessions.d.ts.map +1 -1
- package/bin/agent/local/services/AgentSessions.js +44 -0
- package/bin/agent/local/services/AgentSessions.js.map +1 -1
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts.map +1 -1
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.js +0 -7
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.js.map +1 -1
- package/bin/executor/Executor.d.ts +25 -0
- package/bin/executor/Executor.d.ts.map +1 -1
- package/bin/executor/Executor.js +36 -0
- package/bin/executor/Executor.js.map +1 -1
- package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts +4 -0
- package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.d.ts +0 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js +15 -11
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js.map +1 -1
- package/bin/executor/core-engine/CoreEngineRunner.d.ts +11 -0
- package/bin/executor/core-engine/CoreEngineRunner.d.ts.map +1 -1
- package/bin/executor/core-engine/CoreEngineRunner.js +12 -8
- package/bin/executor/core-engine/CoreEngineRunner.js.map +1 -1
- package/bin/executor/store/history/SessionHistoryStore.d.ts +3 -13
- package/bin/executor/store/history/SessionHistoryStore.d.ts.map +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +1 -1
- package/bin/executor/tools/plugin/PluginToolBridge.d.ts.map +1 -1
- package/bin/executor/tools/plugin/PluginToolBridge.js +4 -2
- package/bin/executor/tools/plugin/PluginToolBridge.js.map +1 -1
- package/bin/index.d.ts +2 -1
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +1 -1
- package/bin/index.js.map +1 -1
- package/bin/model/CityModelAdapter.d.ts +6 -0
- package/bin/model/CityModelAdapter.d.ts.map +1 -1
- package/bin/model/CityModelAdapter.js +13 -0
- package/bin/model/CityModelAdapter.js.map +1 -1
- package/bin/plugin/core/PluginRegistry.d.ts +22 -1
- package/bin/plugin/core/PluginRegistry.d.ts.map +1 -1
- package/bin/plugin/core/PluginRegistry.js +46 -4
- package/bin/plugin/core/PluginRegistry.js.map +1 -1
- package/bin/session/Session.d.ts +11 -1
- package/bin/session/Session.d.ts.map +1 -1
- package/bin/session/Session.js +76 -11
- package/bin/session/Session.js.map +1 -1
- package/bin/session/browse/Browse.d.ts +0 -8
- package/bin/session/browse/Browse.d.ts.map +1 -1
- package/bin/session/browse/Browse.js +72 -57
- package/bin/session/browse/Browse.js.map +1 -1
- package/bin/session/recorder/JsonlSessionMessageStore.d.ts +69 -16
- package/bin/session/recorder/JsonlSessionMessageStore.d.ts.map +1 -1
- package/bin/session/recorder/JsonlSessionMessageStore.js +283 -60
- package/bin/session/recorder/JsonlSessionMessageStore.js.map +1 -1
- package/bin/session/recorder/SessionRecorder.d.ts +20 -2
- package/bin/session/recorder/SessionRecorder.d.ts.map +1 -1
- package/bin/session/recorder/SessionRecorder.js +91 -46
- package/bin/session/recorder/SessionRecorder.js.map +1 -1
- package/bin/session/recorder/SessionRecorderCompaction.d.ts +3 -3
- package/bin/session/recorder/SessionRecorderCompaction.d.ts.map +1 -1
- package/bin/session/recorder/SessionRecorderCompaction.js +50 -62
- package/bin/session/recorder/SessionRecorderCompaction.js.map +1 -1
- package/bin/session/recorder/SessionRecorderHistoryStore.d.ts +2 -2
- package/bin/session/recorder/SessionRecorderHistoryStore.d.ts.map +1 -1
- package/bin/session/recorder/SessionRecorderHistoryStore.js +31 -36
- package/bin/session/recorder/SessionRecorderHistoryStore.js.map +1 -1
- package/bin/session/runtime/SessionPromptRuntime.d.ts +17 -1
- package/bin/session/runtime/SessionPromptRuntime.d.ts.map +1 -1
- package/bin/session/runtime/SessionPromptRuntime.js +67 -8
- package/bin/session/runtime/SessionPromptRuntime.js.map +1 -1
- package/bin/session/services/SessionStateService.d.ts +15 -1
- package/bin/session/services/SessionStateService.d.ts.map +1 -1
- package/bin/session/services/SessionStateService.js +60 -39
- package/bin/session/services/SessionStateService.js.map +1 -1
- package/bin/session/services/SessionTurnService.d.ts +5 -0
- package/bin/session/services/SessionTurnService.d.ts.map +1 -1
- package/bin/session/services/SessionTurnService.js +17 -3
- package/bin/session/services/SessionTurnService.js.map +1 -1
- package/bin/session/services/SessionViewService.d.ts +1 -5
- package/bin/session/services/SessionViewService.d.ts.map +1 -1
- package/bin/session/services/SessionViewService.js +4 -34
- package/bin/session/services/SessionViewService.js.map +1 -1
- package/bin/session/storage/Paths.d.ts +3 -15
- package/bin/session/storage/Paths.d.ts.map +1 -1
- package/bin/session/storage/Paths.js +5 -21
- package/bin/session/storage/Paths.js.map +1 -1
- package/bin/types/agent/SessionTypes.d.ts +2 -24
- package/bin/types/agent/SessionTypes.d.ts.map +1 -1
- package/bin/types/executor/SessionRunContext.d.ts +21 -0
- package/bin/types/executor/SessionRunContext.d.ts.map +1 -1
- package/bin/types/plugin/PluginRuntime.d.ts +25 -0
- package/bin/types/plugin/PluginRuntime.d.ts.map +1 -1
- package/bin/types/runtime/agent/AgentContext.d.ts +17 -5
- package/bin/types/runtime/agent/AgentContext.d.ts.map +1 -1
- package/bin/types/runtime/agent/AgentContext.js +29 -6
- package/bin/types/runtime/agent/AgentContext.js.map +1 -1
- package/bin/types/session/SessionConfigMutation.d.ts +68 -0
- package/bin/types/session/SessionConfigMutation.d.ts.map +1 -0
- package/bin/types/session/SessionConfigMutation.js +10 -0
- package/bin/types/session/SessionConfigMutation.js.map +1 -0
- package/bin/types/session/SessionLocalState.d.ts +8 -0
- package/bin/types/session/SessionLocalState.d.ts.map +1 -1
- package/bin/types/session/SessionMessage.d.ts +16 -12
- package/bin/types/session/SessionMessage.d.ts.map +1 -1
- package/bin/types/session/SessionMutation.d.ts +1 -1
- package/bin/types/session/SessionMutation.js +1 -1
- package/bin/types/session/SessionOptions.d.ts +16 -0
- package/bin/types/session/SessionOptions.d.ts.map +1 -1
- package/bin/types/session/SessionSegment.d.ts +57 -0
- package/bin/types/session/SessionSegment.d.ts.map +1 -0
- package/bin/types/session/SessionSegment.js +8 -0
- package/bin/types/session/SessionSegment.js.map +1 -0
- package/package.json +3 -3
- package/scripts/city-model-tool-loop.test.mjs +32 -0
- package/scripts/session-action-message.test.mjs +59 -13
- package/scripts/session-compaction-context-window.test.mjs +95 -0
- package/scripts/session-config-turn-boundary.test.mjs +224 -0
- package/scripts/session-list-title.test.mjs +21 -3
- package/scripts/session-prompt-runtime.test.mjs +85 -0
- package/scripts/session-recorder.test.mjs +340 -11
- package/src/agent/local/Agent.ts +34 -3
- package/src/agent/local/services/AgentSessions.ts +61 -0
- package/src/agent/remote/transports/HttpRemoteAgentTransport.ts +0 -5
- package/src/executor/Executor.ts +62 -0
- package/src/executor/composer/compaction/SessionCompactionComposer.ts +5 -0
- package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.ts +16 -14
- package/src/executor/core-engine/CoreEngineRunner.ts +24 -8
- package/src/executor/store/history/SessionHistoryStore.ts +3 -14
- package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +1 -1
- package/src/executor/tools/plugin/PluginToolBridge.ts +4 -2
- package/src/index.ts +8 -0
- package/src/model/CityModelAdapter.ts +15 -0
- package/src/plugin/core/PluginRegistry.ts +72 -4
- package/src/session/Session.ts +89 -11
- package/src/session/browse/Browse.ts +73 -69
- package/src/session/recorder/JsonlSessionMessageStore.ts +378 -60
- package/src/session/recorder/SessionRecorder.ts +116 -49
- package/src/session/recorder/SessionRecorderCompaction.ts +55 -80
- package/src/session/recorder/SessionRecorderHistoryStore.ts +29 -49
- package/src/session/runtime/SessionPromptRuntime.ts +100 -9
- package/src/session/services/SessionStateService.ts +79 -44
- package/src/session/services/SessionTurnService.ts +19 -3
- package/src/session/services/SessionViewService.ts +4 -50
- package/src/session/storage/Paths.ts +5 -38
- package/src/types/agent/SessionTypes.ts +2 -24
- package/src/types/executor/SessionRunContext.ts +25 -0
- package/src/types/plugin/PluginRuntime.ts +27 -0
- package/src/types/runtime/agent/AgentContext.ts +32 -7
- package/src/types/session/SessionConfigMutation.ts +78 -0
- package/src/types/session/SessionLocalState.ts +9 -0
- package/src/types/session/SessionMessage.ts +16 -12
- package/src/types/session/SessionMutation.ts +1 -1
- package/src/types/session/SessionOptions.ts +21 -0
- package/src/types/session/SessionSegment.ts +62 -0
- package/tsconfig.tsbuildinfo +1 -1
package/src/executor/Executor.ts
CHANGED
|
@@ -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();
|
|
@@ -359,10 +384,12 @@ export class Executor implements SessionExecutor {
|
|
|
359
384
|
}
|
|
360
385
|
await this.emitAction(run_context, action);
|
|
361
386
|
};
|
|
387
|
+
const context_window = this.get_model_context_window?.();
|
|
362
388
|
|
|
363
389
|
await this.compactionComposer.run({
|
|
364
390
|
historyStore: this.historyStore,
|
|
365
391
|
model,
|
|
392
|
+
...(context_window !== undefined ? { context_window } : {}),
|
|
366
393
|
system,
|
|
367
394
|
retryCount: retry_count,
|
|
368
395
|
onAction: emit_compaction_action,
|
|
@@ -413,9 +440,41 @@ export class Executor implements SessionExecutor {
|
|
|
413
440
|
execute_input: input,
|
|
414
441
|
model,
|
|
415
442
|
run_context,
|
|
443
|
+
resolve_model_turn: async () =>
|
|
444
|
+
await this.resolve_model_turn(run_context),
|
|
416
445
|
});
|
|
417
446
|
}
|
|
418
447
|
|
|
448
|
+
/**
|
|
449
|
+
* 解析下一次 provider 请求实际使用的运行配置。
|
|
450
|
+
*
|
|
451
|
+
* 关键点(中文)
|
|
452
|
+
* - 调用方必须先提交 Session 统一输入队列,再调用本方法。
|
|
453
|
+
* - 每次调用只读取一次 model、system 与 tools,并把它们传给同一个 `streamText()`。
|
|
454
|
+
*/
|
|
455
|
+
private async resolve_model_turn(run_context: SessionRunContext): Promise<{
|
|
456
|
+
model: LanguageModel;
|
|
457
|
+
system: SessionExecuteInput["system"];
|
|
458
|
+
tools: SessionExecuteInput["tools"];
|
|
459
|
+
}> {
|
|
460
|
+
run_context.agentEnv = Object.freeze({ ...this.getEnv() });
|
|
461
|
+
if (this.get_systems) {
|
|
462
|
+
run_context.agentSystems = Object.freeze([...this.get_systems()]);
|
|
463
|
+
}
|
|
464
|
+
if (this.get_plugins) {
|
|
465
|
+
run_context.agentPlugins = this.get_plugins();
|
|
466
|
+
}
|
|
467
|
+
const composed_context = await this.contextComposer.compose(run_context);
|
|
468
|
+
return {
|
|
469
|
+
model: this.resolveModelOrThrow(),
|
|
470
|
+
system: await this.systemComposer.resolve(run_context),
|
|
471
|
+
tools: this.bind_run_scope_to_tools(
|
|
472
|
+
composed_context.tools,
|
|
473
|
+
run_context,
|
|
474
|
+
),
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
419
478
|
/**
|
|
420
479
|
* 为所有 tool 的 execute callback 绑定 ShellRunScope。
|
|
421
480
|
*
|
|
@@ -446,6 +505,9 @@ export class Executor implements SessionExecutor {
|
|
|
446
505
|
run_context: {
|
|
447
506
|
...(session_id ? { session_id } : {}),
|
|
448
507
|
...(turn_id ? { turn_id } : {}),
|
|
508
|
+
...(run_context.agentEnv
|
|
509
|
+
? { env: run_context.agentEnv }
|
|
510
|
+
: {}),
|
|
449
511
|
},
|
|
450
512
|
},
|
|
451
513
|
async () => await original_execute(args, options),
|
|
@@ -14,7 +14,6 @@ import type {
|
|
|
14
14
|
type JsonlSessionCompactionComposerOptions = {
|
|
15
15
|
keepLastMessages?: number;
|
|
16
16
|
maxInputTokensApprox?: number;
|
|
17
|
-
archiveOnCompact?: boolean;
|
|
18
17
|
compactRatio?: number;
|
|
19
18
|
};
|
|
20
19
|
|
|
@@ -29,30 +28,35 @@ export class JsonlSessionCompactionComposer implements SessionCompactionComposer
|
|
|
29
28
|
this.options = options || {};
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
private resolvePolicy(retryCount: number): {
|
|
31
|
+
private resolvePolicy(retryCount: number, context_window?: number): {
|
|
33
32
|
keepLastMessages: number;
|
|
34
33
|
maxInputTokensApprox: number;
|
|
35
|
-
archiveOnCompact: boolean;
|
|
36
34
|
compactRatio: number;
|
|
37
35
|
} {
|
|
38
36
|
const baseKeepLastMessages =
|
|
39
37
|
typeof this.options.keepLastMessages === "number"
|
|
40
38
|
? Math.max(6, Math.min(5000, Math.floor(this.options.keepLastMessages)))
|
|
41
39
|
: 30;
|
|
42
|
-
const
|
|
40
|
+
const configured_max_input_tokens =
|
|
43
41
|
typeof this.options.maxInputTokensApprox === "number"
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
&& Number.isFinite(this.options.maxInputTokensApprox)
|
|
43
|
+
? Math.max(2000, Math.floor(this.options.maxInputTokensApprox))
|
|
44
|
+
: undefined;
|
|
45
|
+
const model_context_window =
|
|
46
|
+
Number.isSafeInteger(context_window) && Number(context_window) > 0
|
|
47
|
+
? Number(context_window)
|
|
48
|
+
: undefined;
|
|
49
|
+
const baseMaxInputTokensApprox = configured_max_input_tokens
|
|
50
|
+
?? (model_context_window !== undefined
|
|
51
|
+
? Math.max(1, Math.floor(model_context_window * 0.8))
|
|
52
|
+
: 128000);
|
|
46
53
|
const retryFactor = Math.max(1, Math.pow(2, retryCount));
|
|
47
54
|
const keepLastMessages = Math.max(6, Math.floor(baseKeepLastMessages / retryFactor));
|
|
55
|
+
const minimum_input_tokens = Math.min(2000, baseMaxInputTokensApprox);
|
|
48
56
|
const maxInputTokensApprox = Math.max(
|
|
49
|
-
|
|
57
|
+
minimum_input_tokens,
|
|
50
58
|
Math.floor(baseMaxInputTokensApprox / retryFactor),
|
|
51
59
|
);
|
|
52
|
-
const archiveOnCompact =
|
|
53
|
-
this.options.archiveOnCompact === undefined
|
|
54
|
-
? true
|
|
55
|
-
: Boolean(this.options.archiveOnCompact);
|
|
56
60
|
const compactRatioRaw =
|
|
57
61
|
typeof this.options.compactRatio === "number" &&
|
|
58
62
|
Number.isFinite(this.options.compactRatio)
|
|
@@ -62,7 +66,6 @@ export class JsonlSessionCompactionComposer implements SessionCompactionComposer
|
|
|
62
66
|
return {
|
|
63
67
|
keepLastMessages,
|
|
64
68
|
maxInputTokensApprox,
|
|
65
|
-
archiveOnCompact,
|
|
66
69
|
compactRatio,
|
|
67
70
|
};
|
|
68
71
|
}
|
|
@@ -71,13 +74,12 @@ export class JsonlSessionCompactionComposer implements SessionCompactionComposer
|
|
|
71
74
|
compacted: boolean;
|
|
72
75
|
reason?: string;
|
|
73
76
|
}> {
|
|
74
|
-
const policy = this.resolvePolicy(input.retryCount);
|
|
77
|
+
const policy = this.resolvePolicy(input.retryCount, input.context_window);
|
|
75
78
|
return await input.historyStore.compact({
|
|
76
79
|
model: input.model,
|
|
77
80
|
system: input.system,
|
|
78
81
|
keepLastMessages: policy.keepLastMessages,
|
|
79
82
|
maxInputTokensApprox: policy.maxInputTokensApprox,
|
|
80
|
-
archiveOnCompact: policy.archiveOnCompact,
|
|
81
83
|
compactRatio: policy.compactRatio,
|
|
82
84
|
...(input.onAction ? { onAction: input.onAction } : {}),
|
|
83
85
|
});
|
|
@@ -125,6 +125,18 @@ interface CoreEngineRunInput {
|
|
|
125
125
|
* 当前显式运行上下文。
|
|
126
126
|
*/
|
|
127
127
|
run_context: SessionRunContext;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 在统一输入队列提交后解析当前模型 turn 的 effective 配置。
|
|
131
|
+
*/
|
|
132
|
+
resolve_model_turn: () => Promise<{
|
|
133
|
+
/** 当前模型 turn 使用的模型。 */
|
|
134
|
+
model: LanguageModel;
|
|
135
|
+
/** 当前模型 turn 使用的 system messages。 */
|
|
136
|
+
system: SessionExecuteInput["system"];
|
|
137
|
+
/** 当前模型 turn 使用的工具集合。 */
|
|
138
|
+
tools: SessionExecuteInput["tools"];
|
|
139
|
+
}>;
|
|
128
140
|
}
|
|
129
141
|
|
|
130
142
|
/**
|
|
@@ -149,10 +161,10 @@ export class CoreEngineRunner {
|
|
|
149
161
|
async run(input: CoreEngineRunInput): Promise<SessionRunResult> {
|
|
150
162
|
const start_time = Date.now();
|
|
151
163
|
const session_id = String(this.history_store.sessionId || "").trim();
|
|
152
|
-
|
|
164
|
+
let system = Array.isArray(input.execute_input.system)
|
|
153
165
|
? input.execute_input.system
|
|
154
166
|
: [];
|
|
155
|
-
|
|
167
|
+
let tools = input.execute_input.tools;
|
|
156
168
|
let last_observed_stream_error: unknown = undefined;
|
|
157
169
|
let final_assistant_ui_message: SessionMessageRecordV1 | null = null;
|
|
158
170
|
|
|
@@ -188,7 +200,7 @@ export class CoreEngineRunner {
|
|
|
188
200
|
await context_composer_on_step_finish(step_result);
|
|
189
201
|
};
|
|
190
202
|
|
|
191
|
-
const
|
|
203
|
+
const prepare_model_turn_inputs = this.context_composer.createPrepareStepHandler({
|
|
192
204
|
system,
|
|
193
205
|
appendMergedUserMessages: append_merged_user_messages,
|
|
194
206
|
runContext: input.run_context,
|
|
@@ -198,11 +210,16 @@ export class CoreEngineRunner {
|
|
|
198
210
|
let incomplete_response_recovery_count = 0;
|
|
199
211
|
|
|
200
212
|
while (step_count < MAX_TOOL_LOOP_STEPS) {
|
|
213
|
+
// 关键点(中文):steer 与配置 mutation 必须在选择 model/system/tools 前提交。
|
|
214
|
+
// 这样运行中写入的配置只影响下一次 provider 请求,不会改变当前流或 tool callback。
|
|
215
|
+
await prepare_model_turn_inputs({ messages: [] });
|
|
216
|
+
const model_turn = await input.resolve_model_turn();
|
|
217
|
+
system = Array.isArray(model_turn.system) ? model_turn.system : [];
|
|
218
|
+
tools = model_turn.tools;
|
|
201
219
|
const result = streamText({
|
|
202
|
-
model:
|
|
220
|
+
model: model_turn.model,
|
|
203
221
|
system,
|
|
204
222
|
onStepFinish: on_step_finish,
|
|
205
|
-
prepareStep: prepare_step,
|
|
206
223
|
messages: message_state.modelMessages,
|
|
207
224
|
tools,
|
|
208
225
|
abortSignal: input.run_context.abortSignal,
|
|
@@ -350,9 +367,8 @@ export class CoreEngineRunner {
|
|
|
350
367
|
}
|
|
351
368
|
|
|
352
369
|
// 关键点(中文):stop 前做 tail merge,覆盖最后一个 step 后才入队的新 user 消息。
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
? tail_prepared.messages.length
|
|
370
|
+
const tail_merged_message_count = input.run_context.hasPendingStepInput?.()
|
|
371
|
+
? 1
|
|
356
372
|
: 0;
|
|
357
373
|
if (
|
|
358
374
|
shouldContinueForTailMergedUserMessages({
|
|
@@ -39,11 +39,6 @@ export type SessionHistoryCompactInput = {
|
|
|
39
39
|
*/
|
|
40
40
|
maxInputTokensApprox: number;
|
|
41
41
|
|
|
42
|
-
/**
|
|
43
|
-
* compact 时是否归档旧消息。
|
|
44
|
-
*/
|
|
45
|
-
archiveOnCompact: boolean;
|
|
46
|
-
|
|
47
42
|
/**
|
|
48
43
|
* 前段压缩比例(0-1)。
|
|
49
44
|
*/
|
|
@@ -88,19 +83,13 @@ export interface SessionHistoryStore {
|
|
|
88
83
|
*/
|
|
89
84
|
finalize_inflight(message?: SessionRecordV1 | null): Promise<void>;
|
|
90
85
|
|
|
91
|
-
/**
|
|
92
|
-
* 读取完整 session records。
|
|
93
|
-
*/
|
|
86
|
+
/** 读取当前模型上下文所需的 session records。 */
|
|
94
87
|
list_records(): Promise<SessionRecordV1[]>;
|
|
95
88
|
|
|
96
|
-
/**
|
|
97
|
-
* 读取 session record 区间 [start, end)。
|
|
98
|
-
*/
|
|
89
|
+
/** 读取当前模型上下文 record 区间 [start, end)。 */
|
|
99
90
|
slice_records(start: number, end: number): Promise<SessionRecordV1[]>;
|
|
100
91
|
|
|
101
|
-
/**
|
|
102
|
-
* 读取 session record 总条数。
|
|
103
|
-
*/
|
|
92
|
+
/** 读取当前模型上下文 record 总条数。 */
|
|
104
93
|
record_count(): Promise<number>;
|
|
105
94
|
|
|
106
95
|
/**
|
|
@@ -667,7 +667,7 @@ export class JsonlSessionHistoryStore implements SessionHistoryStore {
|
|
|
667
667
|
system: this.normalizeSystem(input.system),
|
|
668
668
|
keepLastMessages: input.keepLastMessages,
|
|
669
669
|
maxInputTokensApprox: input.maxInputTokensApprox,
|
|
670
|
-
archiveOnCompact:
|
|
670
|
+
archiveOnCompact: false,
|
|
671
671
|
compactRatio: input.compactRatio,
|
|
672
672
|
...(input.onAction ? { onAction: input.onAction } : {}),
|
|
673
673
|
},
|
|
@@ -138,7 +138,8 @@ export async function invokePluginCallTool(
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
try {
|
|
141
|
-
const
|
|
141
|
+
const plugins = getSessionRunContext()?.agentPlugins || params.plugins;
|
|
142
|
+
const result = await plugins.runAction({
|
|
142
143
|
plugin,
|
|
143
144
|
action,
|
|
144
145
|
payload,
|
|
@@ -191,7 +192,8 @@ export async function invokePluginReadTool(
|
|
|
191
192
|
): Promise<PluginReadToolResult> {
|
|
192
193
|
const input: PluginReadInput = params.input;
|
|
193
194
|
try {
|
|
194
|
-
const
|
|
195
|
+
const plugins = getSessionRunContext()?.agentPlugins || params.plugins;
|
|
196
|
+
const data = plugins.read({
|
|
195
197
|
plugin: typeof input.plugin === "string" ? input.plugin : undefined,
|
|
196
198
|
action: typeof input.action === "string" ? input.action : undefined,
|
|
197
199
|
});
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type { SessionOptions } from "./types/session/SessionOptions.js";
|
|
|
15
15
|
export {
|
|
16
16
|
inferAgentModelLabel,
|
|
17
17
|
normalizeAgentModel,
|
|
18
|
+
read_agent_model_context_window,
|
|
18
19
|
} from "./model/CityModelAdapter.js";
|
|
19
20
|
export type { AgentModel } from "./model/CityModelAdapter.js";
|
|
20
21
|
export type {
|
|
@@ -48,6 +49,13 @@ export type {
|
|
|
48
49
|
SessionUserMessage,
|
|
49
50
|
SessionUserMessagePart,
|
|
50
51
|
} from "./types/session/SessionMessage.js";
|
|
52
|
+
export type {
|
|
53
|
+
SessionContextSnapshot,
|
|
54
|
+
SessionMessageStorageStats,
|
|
55
|
+
SessionSegmentRange,
|
|
56
|
+
SessionSegmentSnapshot,
|
|
57
|
+
SessionSegmentSummary,
|
|
58
|
+
} from "./types/session/SessionSegment.js";
|
|
51
59
|
export {
|
|
52
60
|
is_session_mutation,
|
|
53
61
|
} from "./types/session/SessionMutation.js";
|
|
@@ -44,6 +44,21 @@ export function normalizeAgentModel(model: AgentModel): LanguageModel {
|
|
|
44
44
|
return model;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* 从 Agent 模型输入读取已声明的上下文窗口。
|
|
49
|
+
*
|
|
50
|
+
* 只有 CityModel 携带可信的模型目录元数据;普通 AI SDK LanguageModel 未声明时返回空。
|
|
51
|
+
*/
|
|
52
|
+
export function read_agent_model_context_window(
|
|
53
|
+
model: AgentModel | undefined,
|
|
54
|
+
): number | undefined {
|
|
55
|
+
if (!model || !isCityModel(model)) return undefined;
|
|
56
|
+
const context_window = model.context_window;
|
|
57
|
+
return Number.isSafeInteger(context_window) && Number(context_window) > 0
|
|
58
|
+
? Number(context_window)
|
|
59
|
+
: undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
47
62
|
/**
|
|
48
63
|
* 从 Agent 模型输入推导展示标签。
|
|
49
64
|
*/
|
|
@@ -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
|
+
AgentPluginExecutionRuntime,
|
|
16
17
|
PluginAvailability,
|
|
17
18
|
PluginActionReadView,
|
|
18
19
|
PluginReadView,
|
|
@@ -101,6 +102,13 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
101
102
|
|
|
102
103
|
private readonly records = new Map<string, PluginRuntimeRecord>();
|
|
103
104
|
|
|
105
|
+
private change_listener?: (input: {
|
|
106
|
+
/** 当前修改是注册还是卸载。 */
|
|
107
|
+
type: "register" | "unregister";
|
|
108
|
+
/** 当前修改的 plugin 名称。 */
|
|
109
|
+
plugin_name: string;
|
|
110
|
+
}) => void;
|
|
111
|
+
|
|
104
112
|
constructor(params: {
|
|
105
113
|
contextResolver: ContextResolver;
|
|
106
114
|
hookRegistry: HookRegistry;
|
|
@@ -111,6 +119,13 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
111
119
|
this.pluginInstances = params.pluginInstances;
|
|
112
120
|
}
|
|
113
121
|
|
|
122
|
+
/**
|
|
123
|
+
* 设置 Agent 内部配置修改监听器。
|
|
124
|
+
*/
|
|
125
|
+
set_change_listener(listener: PluginRegistry["change_listener"]): void {
|
|
126
|
+
this.change_listener = listener;
|
|
127
|
+
}
|
|
128
|
+
|
|
114
129
|
/**
|
|
115
130
|
* 注册单个 plugin。
|
|
116
131
|
*
|
|
@@ -134,6 +149,7 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
134
149
|
|
|
135
150
|
try {
|
|
136
151
|
await this.start_record(record);
|
|
152
|
+
this.change_listener?.({ type: "register", plugin_name: key });
|
|
137
153
|
return to_plugin_snapshot(record);
|
|
138
154
|
} catch (error) {
|
|
139
155
|
this.unregister_hooks(key);
|
|
@@ -179,6 +195,7 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
179
195
|
this.unregister_hooks(key);
|
|
180
196
|
this.records.delete(key);
|
|
181
197
|
this.pluginInstances.delete(key);
|
|
198
|
+
this.change_listener?.({ type: "unregister", plugin_name: key });
|
|
182
199
|
return true;
|
|
183
200
|
}
|
|
184
201
|
|
|
@@ -381,11 +398,25 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
381
398
|
plugin?: string;
|
|
382
399
|
action?: string;
|
|
383
400
|
}): PluginReadView | { plugins: PluginView[] } {
|
|
401
|
+
return this.read_from_records(this.records, params);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* 从指定记录视图读取 plugin/action metadata。
|
|
406
|
+
*/
|
|
407
|
+
private read_from_records(
|
|
408
|
+
records: ReadonlyMap<string, PluginRuntimeRecord>,
|
|
409
|
+
params: { plugin?: string; action?: string },
|
|
410
|
+
): PluginReadView | { plugins: PluginView[] } {
|
|
384
411
|
const pluginName = normalize_plugin_name(params.plugin || "");
|
|
385
412
|
if (!pluginName) {
|
|
386
|
-
return {
|
|
413
|
+
return {
|
|
414
|
+
plugins: Array.from(records.values())
|
|
415
|
+
.map((record) => toPluginView(record.plugin))
|
|
416
|
+
.sort((left, right) => left.name.localeCompare(right.name)),
|
|
417
|
+
};
|
|
387
418
|
}
|
|
388
|
-
const plugin =
|
|
419
|
+
const plugin = records.get(pluginName)?.plugin || null;
|
|
389
420
|
if (!plugin) {
|
|
390
421
|
return {
|
|
391
422
|
name: pluginName,
|
|
@@ -470,8 +501,22 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
470
501
|
action: string;
|
|
471
502
|
payload?: JsonValue;
|
|
472
503
|
}): Promise<PluginActionResult<JsonValue>> {
|
|
504
|
+
return await this.run_action_from_records(this.records, params);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* 从指定记录视图运行 plugin action。
|
|
509
|
+
*/
|
|
510
|
+
private async run_action_from_records(
|
|
511
|
+
records: ReadonlyMap<string, PluginRuntimeRecord>,
|
|
512
|
+
params: {
|
|
513
|
+
plugin: string;
|
|
514
|
+
action: string;
|
|
515
|
+
payload?: JsonValue;
|
|
516
|
+
},
|
|
517
|
+
): Promise<PluginActionResult<JsonValue>> {
|
|
473
518
|
const key = normalize_plugin_name(params.plugin);
|
|
474
|
-
const record =
|
|
519
|
+
const record = records.get(key);
|
|
475
520
|
if (!record) {
|
|
476
521
|
return {
|
|
477
522
|
success: false,
|
|
@@ -536,9 +581,18 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
536
581
|
* 读取当前生效的 plugin system blocks。
|
|
537
582
|
*/
|
|
538
583
|
async systemBlocks(): Promise<AgentSessionSystemBlock[]> {
|
|
584
|
+
return await this.system_blocks_from_records(this.records);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* 从指定记录视图解析 plugin system blocks。
|
|
589
|
+
*/
|
|
590
|
+
private async system_blocks_from_records(
|
|
591
|
+
records: ReadonlyMap<string, PluginRuntimeRecord>,
|
|
592
|
+
): Promise<AgentSessionSystemBlock[]> {
|
|
539
593
|
const context = this.contextResolver();
|
|
540
594
|
const out: AgentSessionSystemBlock[] = [];
|
|
541
|
-
for (const record of
|
|
595
|
+
for (const record of records.values()) {
|
|
542
596
|
const plugin = record.plugin;
|
|
543
597
|
if (record.state !== "ready") continue;
|
|
544
598
|
if (typeof plugin.system !== "function") continue;
|
|
@@ -560,4 +614,18 @@ export class PluginRegistry implements AgentPlugins {
|
|
|
560
614
|
}
|
|
561
615
|
return out;
|
|
562
616
|
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* 创建当前 configured registry 的模型 turn 执行视图。
|
|
620
|
+
*/
|
|
621
|
+
execution_view(): AgentPluginExecutionRuntime {
|
|
622
|
+
const records = new Map(this.records);
|
|
623
|
+
return {
|
|
624
|
+
read: (params) => this.read_from_records(records, params),
|
|
625
|
+
runAction: async (params) =>
|
|
626
|
+
await this.run_action_from_records(records, params),
|
|
627
|
+
systemBlocks: async () =>
|
|
628
|
+
await this.system_blocks_from_records(records),
|
|
629
|
+
};
|
|
630
|
+
}
|
|
563
631
|
}
|