@downcity/agent 1.1.189 → 1.1.196
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.map +1 -1
- package/bin/agent/local/Agent.js +5 -2
- package/bin/agent/local/Agent.js.map +1 -1
- package/bin/agent/local/services/AgentAssemblyService.d.ts.map +1 -1
- package/bin/agent/local/services/AgentAssemblyService.js +2 -2
- package/bin/agent/local/services/AgentAssemblyService.js.map +1 -1
- package/bin/agent/local/services/AgentSessionManager.d.ts +5 -0
- package/bin/agent/local/services/AgentSessionManager.d.ts.map +1 -1
- package/bin/agent/local/services/AgentSessionManager.js +3 -0
- package/bin/agent/local/services/AgentSessionManager.js.map +1 -1
- package/bin/executor/Executor.d.ts +4 -0
- package/bin/executor/Executor.d.ts.map +1 -1
- package/bin/executor/Executor.js +40 -1
- package/bin/executor/Executor.js.map +1 -1
- package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts +9 -0
- package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js +1 -0
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts +2 -0
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js +49 -5
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js.map +1 -1
- package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.d.ts +1 -1
- package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.d.ts.map +1 -1
- package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.js +2 -0
- package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.js.map +1 -1
- package/bin/executor/messages/SessionMessageCodec.d.ts +1 -1
- package/bin/executor/messages/SessionMessageCodec.d.ts.map +1 -1
- package/bin/executor/messages/SessionMessageCodec.js +6 -1
- package/bin/executor/messages/SessionMessageCodec.js.map +1 -1
- package/bin/executor/store/history/SessionHistoryStore.d.ts +22 -0
- package/bin/executor/store/history/SessionHistoryStore.d.ts.map +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts +7 -0
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts.map +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +53 -0
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +1 -1
- package/bin/executor/tools/plugin/PluginToolBridge.d.ts +4 -8
- package/bin/executor/tools/plugin/PluginToolBridge.d.ts.map +1 -1
- package/bin/executor/tools/plugin/PluginToolBridge.js +6 -21
- package/bin/executor/tools/plugin/PluginToolBridge.js.map +1 -1
- package/bin/executor/tools/plugin/PluginToolDefinition.d.ts +7 -19
- package/bin/executor/tools/plugin/PluginToolDefinition.d.ts.map +1 -1
- package/bin/executor/tools/plugin/PluginToolDefinition.js +29 -18
- package/bin/executor/tools/plugin/PluginToolDefinition.js.map +1 -1
- package/bin/executor/types/SessionMessages.d.ts +15 -2
- package/bin/executor/types/SessionMessages.d.ts.map +1 -1
- package/bin/executor/types/SessionMessages.js +9 -1
- package/bin/executor/types/SessionMessages.js.map +1 -1
- package/bin/index.d.ts +1 -0
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js.map +1 -1
- package/bin/plugin/core/PluginRegistry.d.ts.map +1 -1
- package/bin/plugin/core/PluginRegistry.js +0 -4
- package/bin/plugin/core/PluginRegistry.js.map +1 -1
- package/bin/session/browse/Browse.d.ts.map +1 -1
- package/bin/session/browse/Browse.js +22 -0
- package/bin/session/browse/Browse.js.map +1 -1
- package/bin/session/services/SessionStateService.d.ts +21 -1
- package/bin/session/services/SessionStateService.d.ts.map +1 -1
- package/bin/session/services/SessionStateService.js +101 -11
- package/bin/session/services/SessionStateService.js.map +1 -1
- package/bin/session/services/SessionTurnService.d.ts.map +1 -1
- package/bin/session/services/SessionTurnService.js +9 -0
- package/bin/session/services/SessionTurnService.js.map +1 -1
- package/bin/session/services/SessionViewService.d.ts.map +1 -1
- package/bin/session/services/SessionViewService.js +42 -8
- package/bin/session/services/SessionViewService.js.map +1 -1
- package/bin/types/agent/SessionTypes.d.ts +22 -1
- package/bin/types/agent/SessionTypes.d.ts.map +1 -1
- package/bin/types/executor/SessionRunContext.d.ts +10 -0
- package/bin/types/executor/SessionRunContext.d.ts.map +1 -1
- package/bin/types/plugin/PluginToolRuntime.d.ts +75 -0
- package/bin/types/plugin/PluginToolRuntime.d.ts.map +1 -0
- package/bin/types/plugin/PluginToolRuntime.js +9 -0
- package/bin/types/plugin/PluginToolRuntime.js.map +1 -0
- package/bin/types/sdk/AgentSessionEvent.d.ts +2 -1
- package/bin/types/sdk/AgentSessionEvent.d.ts.map +1 -1
- package/bin/types/sdk/AgentSessionOperation.d.ts +99 -0
- package/bin/types/sdk/AgentSessionOperation.d.ts.map +1 -0
- package/bin/types/sdk/AgentSessionOperation.js +10 -0
- package/bin/types/sdk/AgentSessionOperation.js.map +1 -0
- package/package.json +3 -3
- package/scripts/agent-ready.test.mjs +168 -0
- package/scripts/plugin-tool-bridge.test.mjs +114 -10
- package/scripts/session-operation-message.test.mjs +182 -0
- package/src/agent/local/Agent.ts +5 -2
- package/src/agent/local/services/AgentAssemblyService.ts +2 -3
- package/src/agent/local/services/AgentSessionManager.ts +8 -0
- package/src/executor/Executor.ts +49 -1
- package/src/executor/composer/compaction/SessionCompactionComposer.ts +10 -0
- package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.ts +1 -0
- package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.ts +64 -5
- package/src/executor/composer/history/jsonl/JsonlSessionHistoryComposer.ts +5 -1
- package/src/executor/messages/SessionMessageCodec.ts +11 -2
- package/src/executor/store/history/SessionHistoryStore.ts +27 -0
- package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +66 -0
- package/src/executor/tools/plugin/PluginToolBridge.ts +10 -26
- package/src/executor/tools/plugin/PluginToolDefinition.ts +39 -22
- package/src/executor/types/SessionMessages.ts +26 -2
- package/src/index.ts +7 -0
- package/src/plugin/core/PluginRegistry.ts +0 -4
- package/src/session/browse/Browse.ts +24 -0
- package/src/session/services/SessionStateService.ts +125 -11
- package/src/session/services/SessionTurnService.ts +8 -0
- package/src/session/services/SessionViewService.ts +47 -10
- package/src/types/agent/SessionTypes.ts +22 -1
- package/src/types/executor/SessionRunContext.ts +20 -0
- package/src/types/plugin/PluginToolRuntime.ts +86 -0
- package/src/types/sdk/AgentSessionEvent.ts +2 -0
- package/src/types/sdk/AgentSessionOperation.ts +125 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -28,8 +28,7 @@ import {
|
|
|
28
28
|
createAgentPluginConfigRuntime,
|
|
29
29
|
} from "@/agent/local/AgentRuntimeAssembly.js";
|
|
30
30
|
import {
|
|
31
|
-
|
|
32
|
-
setPluginToolRuntime,
|
|
31
|
+
createPluginTools,
|
|
33
32
|
} from "@executor/tools/plugin/PluginToolDefinition.js";
|
|
34
33
|
import type { AgentManagedSession } from "@/types/agent/AgentTypes.js";
|
|
35
34
|
import type { SessionPort } from "@/types/runtime/agent/AgentContext.js";
|
|
@@ -183,6 +182,7 @@ export class AgentAssemblyService {
|
|
|
183
182
|
});
|
|
184
183
|
const plugins = plugin_registry;
|
|
185
184
|
if (this.should_register_plugin_call_tool(plugin_instances)) {
|
|
185
|
+
const plugin_tools = createPluginTools({ plugins });
|
|
186
186
|
tools.plugin_read = tools.plugin_read || plugin_tools.plugin_read;
|
|
187
187
|
tools.plugin_call = tools.plugin_call || plugin_tools.plugin_call;
|
|
188
188
|
}
|
|
@@ -228,7 +228,6 @@ export class AgentAssemblyService {
|
|
|
228
228
|
});
|
|
229
229
|
Object.assign(tools, shell.tools);
|
|
230
230
|
}
|
|
231
|
-
setPluginToolRuntime(plugins);
|
|
232
231
|
|
|
233
232
|
return {
|
|
234
233
|
id,
|
|
@@ -87,6 +87,11 @@ type AgentSessionManagerOptions = {
|
|
|
87
87
|
*/
|
|
88
88
|
plugin_instances: Map<string, Plugin>;
|
|
89
89
|
|
|
90
|
+
/**
|
|
91
|
+
* 等待当前 Agent 后台能力启动完成。
|
|
92
|
+
*/
|
|
93
|
+
ensure_agent_ready: () => Promise<void>;
|
|
94
|
+
|
|
90
95
|
/**
|
|
91
96
|
* 当前默认模型实例。
|
|
92
97
|
*/
|
|
@@ -109,6 +114,7 @@ export class AgentSessionManager {
|
|
|
109
114
|
private readonly get_agent_context: AgentSessionManagerOptions["get_agent_context"];
|
|
110
115
|
private readonly get_instruction: AgentSessionManagerOptions["get_instruction"];
|
|
111
116
|
private readonly plugin_instances: Map<string, Plugin>;
|
|
117
|
+
private readonly ensure_agent_ready: AgentSessionManagerOptions["ensure_agent_ready"];
|
|
112
118
|
private readonly default_model?: AgentModel;
|
|
113
119
|
private readonly SessionClass: AgentSessionConstructor;
|
|
114
120
|
private readonly sessions_by_id = new Map<string, AgentManagedSession>();
|
|
@@ -123,6 +129,7 @@ export class AgentSessionManager {
|
|
|
123
129
|
this.get_agent_context = options.get_agent_context;
|
|
124
130
|
this.get_instruction = options.get_instruction;
|
|
125
131
|
this.plugin_instances = options.plugin_instances;
|
|
132
|
+
this.ensure_agent_ready = options.ensure_agent_ready;
|
|
126
133
|
this.default_model = options.default_model;
|
|
127
134
|
this.SessionClass = options.SessionClass || Session;
|
|
128
135
|
this.session_collection = {
|
|
@@ -350,6 +357,7 @@ export class AgentSessionManager {
|
|
|
350
357
|
getManagedPluginSystemBlocks: async () => [],
|
|
351
358
|
getPluginSystemBlocks: async () => await this.load_plugin_system_blocks(),
|
|
352
359
|
ensureConfigured: async (session) => {
|
|
360
|
+
await this.ensure_agent_ready();
|
|
353
361
|
await this.apply_session_defaults(session);
|
|
354
362
|
},
|
|
355
363
|
});
|
package/src/executor/Executor.ts
CHANGED
|
@@ -22,11 +22,13 @@ import type { SessionContextComposer } from "@executor/composer/context/SessionC
|
|
|
22
22
|
import type { SessionSystemComposer } from "@executor/composer/system/SessionSystemComposer.js";
|
|
23
23
|
import { ExecutorInflightService } from "@executor/services/ExecutorInflightService.js";
|
|
24
24
|
import { ExecutorRecoveryPolicy } from "@executor/services/ExecutorRecoveryPolicy.js";
|
|
25
|
+
import { generateId } from "@/utils/Id.js";
|
|
25
26
|
import type { Logger } from "@/utils/logger/Logger.js";
|
|
26
27
|
import type { JsonObject } from "@/types/common/Json.js";
|
|
27
28
|
import type { SessionMessageV1 } from "@/executor/types/SessionMessages.js";
|
|
28
29
|
import type { SessionExecutor } from "@/executor/types/SessionExecutor.js";
|
|
29
30
|
import type { SessionRunContext } from "@/types/executor/SessionRunContext.js";
|
|
31
|
+
import type { AgentSessionOperationRecord } from "@/types/sdk/AgentSessionOperation.js";
|
|
30
32
|
import type {
|
|
31
33
|
SessionExecuteInput,
|
|
32
34
|
SessionRunResult,
|
|
@@ -360,6 +362,7 @@ export class Executor implements SessionExecutor {
|
|
|
360
362
|
const composed_context = await this.contextComposer.compose(run_context);
|
|
361
363
|
const tools = this.bind_run_scope_to_tools(composed_context.tools, run_context);
|
|
362
364
|
const system = await this.systemComposer.resolve(run_context);
|
|
365
|
+
let compaction_operation_id = "";
|
|
363
366
|
|
|
364
367
|
try {
|
|
365
368
|
if (retry_count > 0) {
|
|
@@ -368,13 +371,33 @@ export class Executor implements SessionExecutor {
|
|
|
368
371
|
});
|
|
369
372
|
}
|
|
370
373
|
|
|
374
|
+
const emit_compaction_operation = async (
|
|
375
|
+
operation: AgentSessionOperationRecord,
|
|
376
|
+
): Promise<void> => {
|
|
377
|
+
if (operation.status === "started") {
|
|
378
|
+
compaction_operation_id = operation.operationId;
|
|
379
|
+
}
|
|
380
|
+
await this.emitOperation(run_context, operation);
|
|
381
|
+
};
|
|
382
|
+
|
|
371
383
|
await this.compactionComposer.run({
|
|
372
384
|
historyStore: this.historyStore,
|
|
373
385
|
model,
|
|
374
386
|
system,
|
|
375
387
|
retryCount: retry_count,
|
|
388
|
+
onOperation: emit_compaction_operation,
|
|
389
|
+
});
|
|
390
|
+
} catch (error) {
|
|
391
|
+
await this.emitOperation(run_context, {
|
|
392
|
+
operationId:
|
|
393
|
+
compaction_operation_id ||
|
|
394
|
+
`compacting:${this.sessionId}:failed:${Date.now()}:${generateId()}`,
|
|
395
|
+
name: "compacting",
|
|
396
|
+
status: "failed",
|
|
397
|
+
label: "Session history compact failed",
|
|
398
|
+
error: error instanceof Error ? error.message : String(error),
|
|
399
|
+
visible: false,
|
|
376
400
|
});
|
|
377
|
-
} catch {
|
|
378
401
|
// 压缩失败不阻断主流程,继续使用当前历史消息执行。
|
|
379
402
|
}
|
|
380
403
|
|
|
@@ -469,6 +492,9 @@ export class Executor implements SessionExecutor {
|
|
|
469
492
|
...(typeof input?.onUiMessageChunkCallback === "function"
|
|
470
493
|
? { onUiMessageChunkCallback: input.onUiMessageChunkCallback }
|
|
471
494
|
: {}),
|
|
495
|
+
...(typeof input?.onOperationCallback === "function"
|
|
496
|
+
? { onOperationCallback: input.onOperationCallback }
|
|
497
|
+
: {}),
|
|
472
498
|
...(input?.abortSignal ? { abortSignal: input.abortSignal } : {}),
|
|
473
499
|
injectedUserMessages: Array.isArray(input?.injectedUserMessages)
|
|
474
500
|
? [...input.injectedUserMessages]
|
|
@@ -484,6 +510,28 @@ export class Executor implements SessionExecutor {
|
|
|
484
510
|
};
|
|
485
511
|
}
|
|
486
512
|
|
|
513
|
+
/**
|
|
514
|
+
* 发布一次 session operation。
|
|
515
|
+
*/
|
|
516
|
+
private async emitOperation(
|
|
517
|
+
run_context: SessionRunContext,
|
|
518
|
+
operation: AgentSessionOperationRecord,
|
|
519
|
+
): Promise<void> {
|
|
520
|
+
if (typeof run_context.onOperationCallback !== "function") return;
|
|
521
|
+
const operation_id =
|
|
522
|
+
String(operation.operationId || "").trim() ||
|
|
523
|
+
`operation:${this.sessionId}:${Date.now()}:${generateId()}`;
|
|
524
|
+
await run_context.onOperationCallback({
|
|
525
|
+
type: "operation",
|
|
526
|
+
sessionId: run_context.sessionId || this.sessionId,
|
|
527
|
+
...operation,
|
|
528
|
+
operationId: operation_id,
|
|
529
|
+
...(run_context.turnId && !operation.turnId
|
|
530
|
+
? { turnId: run_context.turnId }
|
|
531
|
+
: {}),
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
|
|
487
535
|
/**
|
|
488
536
|
* 读取当前 session 模型。
|
|
489
537
|
*/
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import type { LanguageModel, SystemModelMessage } from "ai";
|
|
10
10
|
import type { SessionHistoryStore } from "@/executor/store/history/SessionHistoryStore.js";
|
|
11
|
+
import type { AgentSessionOperationRecord } from "@/types/sdk/AgentSessionOperation.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* compaction Composer 执行输入。
|
|
@@ -32,6 +33,15 @@ export type SessionCompactionInput = {
|
|
|
32
33
|
* 当前重试次数(由 Executor 递增)。
|
|
33
34
|
*/
|
|
34
35
|
retryCount: number;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 可选 operation 发布回调。
|
|
39
|
+
*
|
|
40
|
+
* 说明(中文)
|
|
41
|
+
* - 默认 compaction Composer 可在真正开始压缩时发布 `compacting`。
|
|
42
|
+
* - 回调由上层 Session 负责转成订阅事件与 operation message。
|
|
43
|
+
*/
|
|
44
|
+
onOperation?: (operation: AgentSessionOperationRecord) => Promise<void>;
|
|
35
45
|
};
|
|
36
46
|
|
|
37
47
|
/**
|
|
@@ -79,6 +79,7 @@ export class JsonlSessionCompactionComposer implements SessionCompactionComposer
|
|
|
79
79
|
maxInputTokensApprox: policy.maxInputTokensApprox,
|
|
80
80
|
archiveOnCompact: policy.archiveOnCompact,
|
|
81
81
|
compactRatio: policy.compactRatio,
|
|
82
|
+
...(input.onOperation ? { onOperation: input.onOperation } : {}),
|
|
82
83
|
});
|
|
83
84
|
}
|
|
84
85
|
|
|
@@ -21,7 +21,9 @@ import type {
|
|
|
21
21
|
SessionMessageV1,
|
|
22
22
|
SessionMetadataV1,
|
|
23
23
|
} from "@/executor/types/SessionMessages.js";
|
|
24
|
+
import { isSessionOperationMessage } from "@/executor/types/SessionMessages.js";
|
|
24
25
|
import type { SessionHistoryMetaV1 } from "@/executor/types/SessionHistoryMeta.js";
|
|
26
|
+
import type { AgentSessionOperationRecord } from "@/types/sdk/AgentSessionOperation.js";
|
|
25
27
|
|
|
26
28
|
export type SessionCompactParams = {
|
|
27
29
|
model: LanguageModel;
|
|
@@ -30,6 +32,7 @@ export type SessionCompactParams = {
|
|
|
30
32
|
maxInputTokensApprox: number;
|
|
31
33
|
archiveOnCompact: boolean;
|
|
32
34
|
compactRatio: number;
|
|
35
|
+
onOperation?: (operation: AgentSessionOperationRecord) => Promise<void>;
|
|
33
36
|
};
|
|
34
37
|
|
|
35
38
|
type SessionCompactDeps = {
|
|
@@ -60,6 +63,19 @@ export async function compactSessionMessagesIfNeeded(
|
|
|
60
63
|
params: SessionCompactParams,
|
|
61
64
|
): Promise<{ compacted: boolean; reason?: string }> {
|
|
62
65
|
const logger = getLogger(deps.rootPath, "info");
|
|
66
|
+
const operation_id = `compacting:${deps.sessionId}:${Date.now()}:${generateId()}`;
|
|
67
|
+
let operation_started = false;
|
|
68
|
+
|
|
69
|
+
const publish_operation = async (
|
|
70
|
+
operation: Omit<AgentSessionOperationRecord, "operationId" | "name">,
|
|
71
|
+
): Promise<void> => {
|
|
72
|
+
if (typeof params.onOperation !== "function") return;
|
|
73
|
+
await params.onOperation({
|
|
74
|
+
operationId: operation_id,
|
|
75
|
+
name: "compacting",
|
|
76
|
+
...operation,
|
|
77
|
+
});
|
|
78
|
+
};
|
|
63
79
|
|
|
64
80
|
// 算法阶段(中文)
|
|
65
81
|
// phase 1:snapshot(短锁)
|
|
@@ -68,7 +84,9 @@ export async function compactSessionMessagesIfNeeded(
|
|
|
68
84
|
let snapshot: SessionMessageV1[] = [];
|
|
69
85
|
let snapshotTailId = "";
|
|
70
86
|
await deps.withWriteLock(async () => {
|
|
71
|
-
snapshot = await deps.loadAll()
|
|
87
|
+
snapshot = (await deps.loadAll()).filter(
|
|
88
|
+
(message) => !isSessionOperationMessage(message),
|
|
89
|
+
);
|
|
72
90
|
snapshotTailId =
|
|
73
91
|
snapshot.length > 0
|
|
74
92
|
? String(snapshot[snapshot.length - 1].id || "")
|
|
@@ -100,6 +118,13 @@ export async function compactSessionMessagesIfNeeded(
|
|
|
100
118
|
const older = snapshot.slice(0, compactCount);
|
|
101
119
|
if (older.length === 0) return { compacted: false, reason: "nothing_to_compact" };
|
|
102
120
|
|
|
121
|
+
operation_started = true;
|
|
122
|
+
await publish_operation({
|
|
123
|
+
status: "started",
|
|
124
|
+
label: "Compacting session history",
|
|
125
|
+
progress: 0,
|
|
126
|
+
});
|
|
127
|
+
|
|
103
128
|
const olderTextAll = extractPlainTextFromMessages(older);
|
|
104
129
|
const maxOlderChars = 24_000;
|
|
105
130
|
const olderText =
|
|
@@ -138,6 +163,12 @@ export async function compactSessionMessagesIfNeeded(
|
|
|
138
163
|
},
|
|
139
164
|
);
|
|
140
165
|
summary = "(系统自动压缩:摘要生成失败,已丢弃更早历史,仅保留最近对话。)";
|
|
166
|
+
await publish_operation({
|
|
167
|
+
status: "progress",
|
|
168
|
+
label: "Compacting session history",
|
|
169
|
+
reason: "summary_fallback",
|
|
170
|
+
progress: 0.5,
|
|
171
|
+
});
|
|
141
172
|
}
|
|
142
173
|
|
|
143
174
|
const fromId = String(older[0]?.id || "");
|
|
@@ -159,10 +190,20 @@ export async function compactSessionMessagesIfNeeded(
|
|
|
159
190
|
// snapshotTailId 用于 debug,不作为强一致性依赖。
|
|
160
191
|
void snapshotTailId;
|
|
161
192
|
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
193
|
+
const current_model_messages = current.filter(
|
|
194
|
+
(message) => !isSessionOperationMessage(message),
|
|
195
|
+
);
|
|
196
|
+
const currentCompactCount = resolveCompactCount(
|
|
197
|
+
current_model_messages.length,
|
|
198
|
+
compactRatio,
|
|
199
|
+
);
|
|
200
|
+
const currentOlder = current_model_messages.slice(0, currentCompactCount);
|
|
165
201
|
if (currentOlder.length === 0) return;
|
|
202
|
+
const compacted_ids = new Set(
|
|
203
|
+
currentOlder
|
|
204
|
+
.map((message) => String(message.id || "").trim())
|
|
205
|
+
.filter(Boolean),
|
|
206
|
+
);
|
|
166
207
|
|
|
167
208
|
if (params.archiveOnCompact) {
|
|
168
209
|
const archivePath = path.join(
|
|
@@ -181,7 +222,13 @@ export async function compactSessionMessagesIfNeeded(
|
|
|
181
222
|
);
|
|
182
223
|
}
|
|
183
224
|
|
|
184
|
-
const next = [
|
|
225
|
+
const next = [
|
|
226
|
+
summaryMsg,
|
|
227
|
+
...current.filter((message) => {
|
|
228
|
+
const id = String(message.id || "").trim();
|
|
229
|
+
return !id || !compacted_ids.has(id);
|
|
230
|
+
}),
|
|
231
|
+
];
|
|
185
232
|
|
|
186
233
|
const messagesPath = deps.getMessagesFilePath();
|
|
187
234
|
const tmp = messagesPath + ".tmp";
|
|
@@ -195,6 +242,18 @@ export async function compactSessionMessagesIfNeeded(
|
|
|
195
242
|
});
|
|
196
243
|
});
|
|
197
244
|
|
|
245
|
+
if (operation_started) {
|
|
246
|
+
await publish_operation({
|
|
247
|
+
status: "finished",
|
|
248
|
+
label: "Session history compacted",
|
|
249
|
+
progress: 1,
|
|
250
|
+
result: {
|
|
251
|
+
archiveId,
|
|
252
|
+
compactedCount: older.length,
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
198
257
|
return { compacted: true };
|
|
199
258
|
}
|
|
200
259
|
|
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { Tool } from "ai";
|
|
11
|
-
import
|
|
11
|
+
import {
|
|
12
|
+
isSessionOperationMessage,
|
|
13
|
+
type SessionMessageV1,
|
|
14
|
+
} from "@/executor/types/SessionMessages.js";
|
|
12
15
|
import type { SessionHistoryStore } from "@/executor/store/history/SessionHistoryStore.js";
|
|
13
16
|
import type {
|
|
14
17
|
SessionHistoryComposer,
|
|
@@ -91,6 +94,7 @@ export class JsonlSessionHistoryComposer implements SessionHistoryComposer {
|
|
|
91
94
|
parts,
|
|
92
95
|
};
|
|
93
96
|
})
|
|
97
|
+
.filter((message) => !isSessionOperationMessage(message))
|
|
94
98
|
.filter((message) => Array.isArray(message.parts) && message.parts.length > 0);
|
|
95
99
|
}
|
|
96
100
|
|
|
@@ -14,7 +14,10 @@ import {
|
|
|
14
14
|
type Tool,
|
|
15
15
|
type ToolSet,
|
|
16
16
|
} from "ai";
|
|
17
|
-
import
|
|
17
|
+
import {
|
|
18
|
+
isSessionOperationMessage,
|
|
19
|
+
type SessionMessageV1,
|
|
20
|
+
} from "@/executor/types/SessionMessages.js";
|
|
18
21
|
import {
|
|
19
22
|
hydrateFileUrlPartsForModel,
|
|
20
23
|
injectFilePartsFromAttachments,
|
|
@@ -77,9 +80,15 @@ export async function toModelMessages(
|
|
|
77
80
|
// 空输入快速返回,避免调用转换器的额外开销。
|
|
78
81
|
if (!Array.isArray(messages) || messages.length === 0) return [];
|
|
79
82
|
|
|
83
|
+
// operation message 只服务前端时间线,不能传入模型。
|
|
84
|
+
const model_messages = messages.filter(
|
|
85
|
+
(message) => !isSessionOperationMessage(message),
|
|
86
|
+
);
|
|
87
|
+
if (model_messages.length === 0) return [];
|
|
88
|
+
|
|
80
89
|
// 第一步(中文):在 user 消息上注入 file parts(多模态附件)。
|
|
81
90
|
const enrichedMessages = await injectFilePartsFromAttachments(
|
|
82
|
-
|
|
91
|
+
model_messages,
|
|
83
92
|
projectRoot,
|
|
84
93
|
);
|
|
85
94
|
|
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
SessionMetadataV1,
|
|
14
14
|
} from "@/executor/types/SessionMessages.js";
|
|
15
15
|
import type { SessionSystemMessage } from "@/executor/types/SessionPrompts.js";
|
|
16
|
+
import type { AgentSessionOperationRecord } from "@/types/sdk/AgentSessionOperation.js";
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* compact 输入参数。
|
|
@@ -47,6 +48,11 @@ export type SessionHistoryCompactInput = {
|
|
|
47
48
|
* 前段压缩比例(0-1)。
|
|
48
49
|
*/
|
|
49
50
|
compactRatio: number;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 可选 operation 发布回调。
|
|
54
|
+
*/
|
|
55
|
+
onOperation?: (operation: AgentSessionOperationRecord) => Promise<void>;
|
|
50
56
|
};
|
|
51
57
|
|
|
52
58
|
/**
|
|
@@ -157,4 +163,25 @@ export interface SessionHistoryStore {
|
|
|
157
163
|
*/
|
|
158
164
|
source?: "egress" | "compact";
|
|
159
165
|
}): SessionMessageV1;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 构造 operation 消息。
|
|
169
|
+
*/
|
|
170
|
+
operation(input: {
|
|
171
|
+
/**
|
|
172
|
+
* 当前 operation 结构化记录。
|
|
173
|
+
*/
|
|
174
|
+
operation: AgentSessionOperationRecord;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* 消息元信息(除 schema 字段、kind、source 与 operation 字段)。
|
|
178
|
+
*/
|
|
179
|
+
metadata: Omit<SessionMetadataV1, "v" | "ts" | "kind" | "source" | "operation"> &
|
|
180
|
+
Partial<Pick<SessionMetadataV1, "ts">>;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 可选消息 ID(默认自动生成)。
|
|
184
|
+
*/
|
|
185
|
+
id?: string;
|
|
186
|
+
}): SessionMessageV1;
|
|
160
187
|
}
|
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
SessionMessageV1,
|
|
22
22
|
SessionMetadataV1,
|
|
23
23
|
} from "@/executor/types/SessionMessages.js";
|
|
24
|
+
import type { AgentSessionOperationRecord } from "@/types/sdk/AgentSessionOperation.js";
|
|
24
25
|
import type { SessionSystemMessage } from "@/executor/types/SessionPrompts.js";
|
|
25
26
|
import type { SessionHistoryMetaV1 } from "@/executor/types/SessionHistoryMeta.js";
|
|
26
27
|
import type { SessionHistoryPathOverrides } from "@/executor/types/SessionHistoryPaths.js";
|
|
@@ -435,6 +436,44 @@ export class JsonlSessionHistoryStore implements SessionHistoryStore {
|
|
|
435
436
|
return system.filter((item) => item && typeof item === "object");
|
|
436
437
|
}
|
|
437
438
|
|
|
439
|
+
private normalizeOperation(
|
|
440
|
+
operation: AgentSessionOperationRecord,
|
|
441
|
+
): AgentSessionOperationRecord {
|
|
442
|
+
const operation_id = String(operation.operationId || "").trim() || generateId();
|
|
443
|
+
const name = String(operation.name || "").trim() || "operation";
|
|
444
|
+
const status = String(operation.status || "").trim();
|
|
445
|
+
const normalized_status: AgentSessionOperationRecord["status"] =
|
|
446
|
+
status === "started" ||
|
|
447
|
+
status === "progress" ||
|
|
448
|
+
status === "finished" ||
|
|
449
|
+
status === "skipped" ||
|
|
450
|
+
status === "failed"
|
|
451
|
+
? status
|
|
452
|
+
: "progress";
|
|
453
|
+
return {
|
|
454
|
+
operationId: operation_id,
|
|
455
|
+
name,
|
|
456
|
+
status: normalized_status,
|
|
457
|
+
...(typeof operation.turnId === "string" && operation.turnId.trim()
|
|
458
|
+
? { turnId: operation.turnId.trim() }
|
|
459
|
+
: {}),
|
|
460
|
+
...(typeof operation.label === "string" && operation.label.trim()
|
|
461
|
+
? { label: operation.label.trim() }
|
|
462
|
+
: {}),
|
|
463
|
+
...(typeof operation.reason === "string" && operation.reason.trim()
|
|
464
|
+
? { reason: operation.reason.trim() }
|
|
465
|
+
: {}),
|
|
466
|
+
...(typeof operation.progress === "number" && Number.isFinite(operation.progress)
|
|
467
|
+
? { progress: Math.max(0, Math.min(1, operation.progress)) }
|
|
468
|
+
: {}),
|
|
469
|
+
...(operation.result !== undefined ? { result: operation.result } : {}),
|
|
470
|
+
...(typeof operation.error === "string" && operation.error.trim()
|
|
471
|
+
? { error: operation.error.trim() }
|
|
472
|
+
: {}),
|
|
473
|
+
...(operation.visible === false ? { visible: false } : {}),
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
|
|
438
477
|
async compact(input: SessionHistoryCompactInput): Promise<{
|
|
439
478
|
compacted: boolean;
|
|
440
479
|
reason?: string;
|
|
@@ -471,6 +510,7 @@ export class JsonlSessionHistoryStore implements SessionHistoryStore {
|
|
|
471
510
|
maxInputTokensApprox: input.maxInputTokensApprox,
|
|
472
511
|
archiveOnCompact: input.archiveOnCompact,
|
|
473
512
|
compactRatio: input.compactRatio,
|
|
513
|
+
...(input.onOperation ? { onOperation: input.onOperation } : {}),
|
|
474
514
|
},
|
|
475
515
|
);
|
|
476
516
|
}
|
|
@@ -633,4 +673,30 @@ export class JsonlSessionHistoryStore implements SessionHistoryStore {
|
|
|
633
673
|
parts: [{ type: "text", text: String(input.text ?? "") }],
|
|
634
674
|
};
|
|
635
675
|
}
|
|
676
|
+
|
|
677
|
+
operation(input: {
|
|
678
|
+
operation: AgentSessionOperationRecord;
|
|
679
|
+
metadata: Omit<SessionMetadataV1, "v" | "ts" | "kind" | "source" | "operation"> &
|
|
680
|
+
Partial<Pick<SessionMetadataV1, "ts">>;
|
|
681
|
+
id?: string;
|
|
682
|
+
}): SessionMessageV1 {
|
|
683
|
+
const operation = this.normalizeOperation(input.operation);
|
|
684
|
+
const label = String(
|
|
685
|
+
operation.label || `${operation.name}: ${operation.status}`,
|
|
686
|
+
).trim();
|
|
687
|
+
const { ts, ...metadata } = input.metadata;
|
|
688
|
+
return {
|
|
689
|
+
id: input.id || `op:${this.sessionId}:${operation.operationId}:${generateId()}`,
|
|
690
|
+
role: "assistant",
|
|
691
|
+
metadata: {
|
|
692
|
+
v: 1,
|
|
693
|
+
ts: typeof ts === "number" ? ts : Date.now(),
|
|
694
|
+
...metadata,
|
|
695
|
+
source: "operation",
|
|
696
|
+
kind: "operation",
|
|
697
|
+
operation,
|
|
698
|
+
},
|
|
699
|
+
parts: [{ type: "text", text: label }],
|
|
700
|
+
};
|
|
701
|
+
}
|
|
636
702
|
}
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import type { FileUIPart } from "ai";
|
|
12
12
|
import type { JsonObject, JsonValue } from "@/types/common/Json.js";
|
|
13
|
-
import type { AgentPlugins } from "@/plugin/types/Plugin.js";
|
|
14
13
|
import type {
|
|
15
14
|
PluginCallInput,
|
|
16
15
|
PluginCallToolFileResult,
|
|
@@ -18,6 +17,10 @@ import type {
|
|
|
18
17
|
PluginReadInput,
|
|
19
18
|
PluginReadToolResult,
|
|
20
19
|
} from "@/executor/tools/plugin/types/PluginTool.js";
|
|
20
|
+
import type {
|
|
21
|
+
InvokePluginCallToolOptions,
|
|
22
|
+
InvokePluginReadToolOptions,
|
|
23
|
+
} from "@/types/plugin/PluginToolRuntime.js";
|
|
21
24
|
import {
|
|
22
25
|
materializeAssistantFileParts,
|
|
23
26
|
resolveAgentFilePath,
|
|
@@ -27,25 +30,6 @@ import {
|
|
|
27
30
|
getSessionRunContext,
|
|
28
31
|
} from "@executor/SessionRunScope.js";
|
|
29
32
|
|
|
30
|
-
let plugin_tool_runtime: AgentPlugins | null = null;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* 注入 plugin tool 运行时。
|
|
34
|
-
*/
|
|
35
|
-
export function setPluginToolRuntime(next: AgentPlugins): void {
|
|
36
|
-
plugin_tool_runtime = next;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* 读取已注入的 plugin tool 运行时。
|
|
41
|
-
*/
|
|
42
|
-
function require_plugin_tool_runtime(): AgentPlugins {
|
|
43
|
-
if (plugin_tool_runtime) return plugin_tool_runtime;
|
|
44
|
-
throw new Error(
|
|
45
|
-
"Plugin tool runtime is not initialized. Ensure agent assembly completed before using plugin_call.",
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
33
|
/**
|
|
50
34
|
* 判断值是否为普通对象。
|
|
51
35
|
*/
|
|
@@ -126,8 +110,9 @@ function summarize_action_data(data: JsonValue | undefined): JsonObject | undefi
|
|
|
126
110
|
* 调用 plugin action 并桥接最终 assistant file parts。
|
|
127
111
|
*/
|
|
128
112
|
export async function invokePluginCallTool(
|
|
129
|
-
|
|
113
|
+
params: InvokePluginCallToolOptions,
|
|
130
114
|
): Promise<PluginCallToolResult> {
|
|
115
|
+
const input: PluginCallInput = params.input;
|
|
131
116
|
const plugin = String(input.plugin || "").trim();
|
|
132
117
|
const action = String(input.action || "").trim();
|
|
133
118
|
const payload = to_json_object(input.payload ?? {}) ?? {};
|
|
@@ -153,8 +138,7 @@ export async function invokePluginCallTool(
|
|
|
153
138
|
}
|
|
154
139
|
|
|
155
140
|
try {
|
|
156
|
-
const
|
|
157
|
-
const result = await runtime.runAction({
|
|
141
|
+
const result = await params.plugins.runAction({
|
|
158
142
|
plugin,
|
|
159
143
|
action,
|
|
160
144
|
payload,
|
|
@@ -203,11 +187,11 @@ export async function invokePluginCallTool(
|
|
|
203
187
|
* 读取 plugin / action metadata。
|
|
204
188
|
*/
|
|
205
189
|
export async function invokePluginReadTool(
|
|
206
|
-
|
|
190
|
+
params: InvokePluginReadToolOptions,
|
|
207
191
|
): Promise<PluginReadToolResult> {
|
|
192
|
+
const input: PluginReadInput = params.input;
|
|
208
193
|
try {
|
|
209
|
-
const
|
|
210
|
-
const data = runtime.read({
|
|
194
|
+
const data = params.plugins.read({
|
|
211
195
|
plugin: typeof input.plugin === "string" ? input.plugin : undefined,
|
|
212
196
|
action: typeof input.action === "string" ? input.action : undefined,
|
|
213
197
|
});
|
|
@@ -12,42 +12,59 @@ import type {
|
|
|
12
12
|
PluginCallInput,
|
|
13
13
|
PluginReadInput,
|
|
14
14
|
} from "@/executor/tools/plugin/types/PluginTool.js";
|
|
15
|
+
import type {
|
|
16
|
+
AgentPluginTools,
|
|
17
|
+
CreatePluginToolsOptions,
|
|
18
|
+
} from "@/types/plugin/PluginToolRuntime.js";
|
|
15
19
|
import {
|
|
16
20
|
invokePluginCallTool,
|
|
17
21
|
invokePluginReadTool,
|
|
18
|
-
setPluginToolRuntime,
|
|
19
22
|
} from "./PluginToolBridge.js";
|
|
20
23
|
import {
|
|
21
24
|
plugin_call_input_schema,
|
|
22
25
|
plugin_read_input_schema,
|
|
23
26
|
} from "./PluginToolSchemas.js";
|
|
24
27
|
|
|
25
|
-
export { setPluginToolRuntime } from "./PluginToolBridge.js";
|
|
26
|
-
|
|
27
28
|
/**
|
|
28
|
-
* `plugin_call
|
|
29
|
+
* 创建 `plugin_call`:调用当前 Agent 已注册 plugin action。
|
|
29
30
|
*/
|
|
30
|
-
export
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
export function createPluginCallTool(options: CreatePluginToolsOptions) {
|
|
32
|
+
return tool({
|
|
33
|
+
description:
|
|
34
|
+
"Call a registered agent plugin action. Use plugin_read first when you need the action list, input schema, or examples. Generated files may be attached to the final assistant message automatically.",
|
|
35
|
+
inputSchema: plugin_call_input_schema,
|
|
36
|
+
execute: async (input) =>
|
|
37
|
+
await invokePluginCallTool({
|
|
38
|
+
plugins: options.plugins,
|
|
39
|
+
input: input as PluginCallInput,
|
|
40
|
+
}),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
36
43
|
|
|
37
44
|
/**
|
|
38
|
-
* `plugin_read
|
|
45
|
+
* 创建 `plugin_read`:读取当前 Agent 已注册 plugin / action metadata。
|
|
39
46
|
*/
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
export function createPluginReadTool(options: CreatePluginToolsOptions) {
|
|
48
|
+
return tool({
|
|
49
|
+
description:
|
|
50
|
+
"Read registered agent plugin metadata, including action names, descriptions, input schemas, and examples. Use this before plugin_call when the payload shape is unclear.",
|
|
51
|
+
inputSchema: plugin_read_input_schema,
|
|
52
|
+
execute: async (input) =>
|
|
53
|
+
await invokePluginReadTool({
|
|
54
|
+
plugins: options.plugins,
|
|
55
|
+
input: input as PluginReadInput,
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
46
59
|
|
|
47
60
|
/**
|
|
48
|
-
* Plugin
|
|
61
|
+
* 创建当前 Agent 专属 Plugin 工具集合。
|
|
49
62
|
*/
|
|
50
|
-
export
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
63
|
+
export function createPluginTools(
|
|
64
|
+
options: CreatePluginToolsOptions,
|
|
65
|
+
): AgentPluginTools {
|
|
66
|
+
return {
|
|
67
|
+
plugin_call: createPluginCallTool(options),
|
|
68
|
+
plugin_read: createPluginReadTool(options),
|
|
69
|
+
};
|
|
70
|
+
}
|