@downcity/agent 1.1.199 → 1.1.202
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 +3 -7
- package/bin/agent/local/Agent.d.ts.map +1 -1
- package/bin/agent/local/Agent.js +14 -19
- package/bin/agent/local/Agent.js.map +1 -1
- package/bin/agent/local/services/{AgentSessionManager.d.ts → AgentSessions.d.ts} +12 -17
- package/bin/agent/local/services/AgentSessions.d.ts.map +1 -0
- package/bin/agent/local/services/{AgentSessionManager.js → AgentSessions.js} +11 -26
- package/bin/agent/local/services/AgentSessions.js.map +1 -0
- package/bin/agent/remote/RemoteAgent.d.ts +2 -9
- package/bin/agent/remote/RemoteAgent.d.ts.map +1 -1
- package/bin/agent/remote/RemoteAgent.js +40 -22
- package/bin/agent/remote/RemoteAgent.js.map +1 -1
- package/bin/agent/remote/RemoteSession.d.ts +5 -5
- package/bin/agent/remote/RemoteSession.d.ts.map +1 -1
- package/bin/agent/remote/RemoteSession.js +5 -3
- package/bin/agent/remote/RemoteSession.js.map +1 -1
- package/bin/agent/remote/RemoteTransport.d.ts +2 -2
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.d.ts +2 -2
- package/bin/agent/remote/transports/HttpRemoteAgentTransport.js +5 -5
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.d.ts +2 -2
- package/bin/agent/remote/transports/RpcRemoteAgentTransport.js +2 -2
- package/bin/executor/Executor.d.ts +7 -7
- package/bin/executor/Executor.d.ts.map +1 -1
- package/bin/executor/Executor.js +41 -33
- package/bin/executor/Executor.js.map +1 -1
- package/bin/executor/SessionRunScope.d.ts +1 -1
- package/bin/executor/SessionRunScope.d.ts.map +1 -1
- package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts +5 -5
- package/bin/executor/composer/compaction/SessionCompactionComposer.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.js.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts +4 -5
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.d.ts.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js +73 -40
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.js.map +1 -1
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionFileOperations.d.ts +27 -0
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionFileOperations.d.ts.map +1 -0
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionFileOperations.js +181 -0
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionFileOperations.js.map +1 -0
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionPrompts.d.ts +45 -0
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionPrompts.d.ts.map +1 -0
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionPrompts.js +144 -0
- package/bin/executor/composer/compaction/jsonl/JsonlSessionCompactionPrompts.js.map +1 -0
- package/bin/executor/composer/context/LocalSessionContextComposer.d.ts +3 -3
- package/bin/executor/composer/context/LocalSessionContextComposer.d.ts.map +1 -1
- package/bin/executor/composer/context/SessionContextComposer.d.ts +3 -3
- package/bin/executor/composer/context/SessionContextComposer.d.ts.map +1 -1
- package/bin/executor/composer/history/SessionHistoryComposer.d.ts +2 -2
- package/bin/executor/composer/history/SessionHistoryComposer.d.ts.map +1 -1
- package/bin/executor/composer/history/SessionHistoryWriter.d.ts +5 -5
- package/bin/executor/composer/history/SessionHistoryWriter.d.ts.map +1 -1
- package/bin/executor/composer/history/SessionHistoryWriter.js +6 -6
- package/bin/executor/composer/history/SessionHistoryWriter.js.map +1 -1
- package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.d.ts +2 -2
- package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.d.ts.map +1 -1
- package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.js +5 -4
- package/bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.js.map +1 -1
- package/bin/executor/core-engine/CoreEngineMessageState.d.ts +5 -5
- package/bin/executor/core-engine/CoreEngineMessageState.d.ts.map +1 -1
- package/bin/executor/core-engine/CoreEngineMessageState.js.map +1 -1
- package/bin/executor/core-engine/CoreEngineRunner.js.map +1 -1
- package/bin/executor/core-engine/CoreEngineSignals.d.ts +4 -4
- package/bin/executor/core-engine/CoreEngineSignals.d.ts.map +1 -1
- package/bin/executor/core-engine/CoreEngineSignals.js.map +1 -1
- package/bin/executor/core-engine/CoreEngineUiStreamCollector.d.ts +3 -3
- package/bin/executor/core-engine/CoreEngineUiStreamCollector.d.ts.map +1 -1
- package/bin/executor/core-engine/CoreEngineUiStreamCollector.js.map +1 -1
- package/bin/executor/messages/AssistantResultPersistence.d.ts +5 -5
- package/bin/executor/messages/AssistantResultPersistence.d.ts.map +1 -1
- package/bin/executor/messages/AssistantResultPersistence.js +1 -1
- package/bin/executor/messages/AssistantResultPersistence.js.map +1 -1
- package/bin/executor/messages/SessionAttachmentMapper.d.ts +3 -3
- package/bin/executor/messages/SessionAttachmentMapper.d.ts.map +1 -1
- package/bin/executor/messages/SessionAttachmentMapper.js.map +1 -1
- package/bin/executor/messages/SessionMessageCodec.d.ts +4 -4
- package/bin/executor/messages/SessionMessageCodec.d.ts.map +1 -1
- package/bin/executor/messages/SessionMessageCodec.js +5 -5
- package/bin/executor/messages/SessionMessageCodec.js.map +1 -1
- package/bin/executor/messages/SessionMessageLog.d.ts +3 -3
- package/bin/executor/messages/SessionMessageLog.d.ts.map +1 -1
- package/bin/executor/messages/SessionMessageLog.js.map +1 -1
- package/bin/executor/messages/SessionStepEventMapper.d.ts +2 -2
- package/bin/executor/messages/SessionStepEventMapper.d.ts.map +1 -1
- package/bin/executor/messages/SessionStepEventMapper.js.map +1 -1
- package/bin/executor/messages/UserVisibleText.d.ts +3 -3
- package/bin/executor/messages/UserVisibleText.d.ts.map +1 -1
- package/bin/executor/messages/UserVisibleText.js +3 -3
- package/bin/executor/messages/UserVisibleText.js.map +1 -1
- package/bin/executor/services/ExecutorInflightService.d.ts +2 -2
- package/bin/executor/services/ExecutorInflightService.d.ts.map +1 -1
- package/bin/executor/services/ExecutorInflightService.js +11 -7
- package/bin/executor/services/ExecutorInflightService.js.map +1 -1
- package/bin/executor/store/history/SessionHistoryStore.d.ts +30 -27
- package/bin/executor/store/history/SessionHistoryStore.d.ts.map +1 -1
- package/bin/executor/store/history/SessionHistoryStore.js +3 -3
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts +21 -20
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.d.ts.map +1 -1
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js +114 -72
- package/bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js.map +1 -1
- package/bin/executor/tools/plugin/PluginToolDefinition.d.ts +1 -7
- package/bin/executor/tools/plugin/PluginToolDefinition.d.ts.map +1 -1
- package/bin/executor/tools/plugin/PluginToolSchemas.d.ts +4 -6
- package/bin/executor/tools/plugin/PluginToolSchemas.d.ts.map +1 -1
- package/bin/executor/tools/plugin/PluginToolSchemas.js +24 -10
- package/bin/executor/tools/plugin/PluginToolSchemas.js.map +1 -1
- package/bin/executor/types/SessionRecords.d.ts +162 -0
- package/bin/executor/types/SessionRecords.d.ts.map +1 -0
- package/bin/executor/types/SessionRecords.js +52 -0
- package/bin/executor/types/SessionRecords.js.map +1 -0
- package/bin/executor/types/SessionRun.d.ts +3 -3
- package/bin/executor/types/SessionRun.d.ts.map +1 -1
- package/bin/index.d.ts +2 -2
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js.map +1 -1
- package/bin/rpc/Client.d.ts +5 -5
- package/bin/rpc/Client.js +4 -4
- package/bin/session/Session.d.ts +6 -6
- package/bin/session/Session.d.ts.map +1 -1
- package/bin/session/Session.js +8 -8
- package/bin/session/Session.js.map +1 -1
- package/bin/session/SessionTitle.d.ts +2 -2
- package/bin/session/SessionTitle.d.ts.map +1 -1
- package/bin/session/SessionTitle.js +5 -0
- package/bin/session/SessionTitle.js.map +1 -1
- package/bin/session/browse/Browse.d.ts +12 -12
- package/bin/session/browse/Browse.d.ts.map +1 -1
- package/bin/session/browse/Browse.js +37 -34
- package/bin/session/browse/Browse.js.map +1 -1
- package/bin/session/index.d.ts +1 -1
- package/bin/session/index.js +1 -1
- package/bin/session/runtime/SessionPromptRuntime.d.ts +3 -3
- package/bin/session/runtime/SessionPromptRuntime.d.ts.map +1 -1
- package/bin/session/services/SessionStateService.d.ts +11 -12
- package/bin/session/services/SessionStateService.d.ts.map +1 -1
- package/bin/session/services/SessionStateService.js +43 -69
- package/bin/session/services/SessionStateService.js.map +1 -1
- package/bin/session/services/SessionTurnService.js +3 -3
- package/bin/session/services/SessionTurnService.js.map +1 -1
- package/bin/session/services/SessionViewService.d.ts +4 -4
- package/bin/session/services/SessionViewService.d.ts.map +1 -1
- package/bin/session/services/SessionViewService.js +26 -36
- package/bin/session/services/SessionViewService.js.map +1 -1
- package/bin/session/storage/Persistence.d.ts +4 -4
- package/bin/session/storage/Persistence.d.ts.map +1 -1
- package/bin/session/storage/RuntimeSessionPort.d.ts +2 -2
- package/bin/session/storage/RuntimeSessionPort.d.ts.map +1 -1
- package/bin/session/storage/RuntimeSessionPort.js +4 -4
- package/bin/session/storage/RuntimeSessionPort.js.map +1 -1
- package/bin/types/agent/AgentTypes.d.ts +2 -2
- package/bin/types/agent/AgentTypes.d.ts.map +1 -1
- package/bin/types/agent/SessionActor.d.ts +11 -11
- package/bin/types/agent/SessionActor.d.ts.map +1 -1
- package/bin/types/agent/SessionTypes.d.ts +22 -22
- package/bin/types/agent/SessionTypes.d.ts.map +1 -1
- package/bin/types/executor/SessionRunContext.d.ts +7 -7
- package/bin/types/executor/SessionRunContext.d.ts.map +1 -1
- package/bin/types/rpc/RpcProtocol.d.ts +6 -6
- package/bin/types/runtime/agent/AgentContext.d.ts +7 -7
- package/bin/types/runtime/agent/AgentContext.d.ts.map +1 -1
- package/bin/types/sdk/AgentSessionAction.d.ts +26 -0
- package/bin/types/sdk/AgentSessionAction.d.ts.map +1 -0
- package/bin/types/sdk/AgentSessionAction.js +10 -0
- package/bin/types/sdk/AgentSessionAction.js.map +1 -0
- package/bin/types/sdk/AgentSessionEvent.d.ts +2 -2
- package/bin/types/sdk/AgentSessionEvent.d.ts.map +1 -1
- package/bin/types/sdk/AgentSessionTurn.d.ts +2 -2
- package/bin/types/sdk/AgentSessionTurn.d.ts.map +1 -1
- package/package.json +3 -3
- package/scripts/agent-ready.test.mjs +1 -1
- package/scripts/city-model-tool-loop.test.mjs +36 -4
- package/scripts/plugin-tool-bridge.test.mjs +13 -0
- package/scripts/session-action-message.test.mjs +199 -0
- package/scripts/session-compaction-prompts.test.mjs +97 -0
- package/scripts/session-history-archive.test.mjs +8 -8
- package/scripts/session-history-inflight.test.mjs +10 -10
- package/scripts/session-list-title.test.mjs +9 -9
- package/scripts/session-title-event.test.mjs +12 -10
- package/src/agent/local/Agent.ts +16 -22
- package/src/agent/local/services/{AgentSessionManager.ts → AgentSessions.ts} +16 -32
- package/src/agent/remote/RemoteAgent.ts +58 -23
- package/src/agent/remote/RemoteSession.ts +10 -8
- package/src/agent/remote/RemoteTransport.ts +5 -5
- package/src/agent/remote/transports/HttpRemoteAgentTransport.ts +10 -10
- package/src/agent/remote/transports/RpcRemoteAgentTransport.ts +6 -6
- package/src/executor/Executor.ts +51 -41
- package/src/executor/SessionRunScope.ts +1 -1
- package/src/executor/composer/compaction/SessionCompactionComposer.ts +5 -5
- package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionComposer.ts +1 -1
- package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionExecutor.ts +91 -52
- package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionFileOperations.ts +197 -0
- package/src/executor/composer/compaction/jsonl/JsonlSessionCompactionPrompts.ts +162 -0
- package/src/executor/composer/context/LocalSessionContextComposer.ts +5 -5
- package/src/executor/composer/context/SessionContextComposer.ts +5 -5
- package/src/executor/composer/history/SessionHistoryComposer.ts +2 -2
- package/src/executor/composer/history/SessionHistoryWriter.ts +10 -10
- package/src/executor/composer/history/jsonl/JsonlSessionHistoryComposer.ts +13 -10
- package/src/executor/core-engine/CoreEngineMessageState.ts +8 -8
- package/src/executor/core-engine/CoreEngineRunner.ts +7 -7
- package/src/executor/core-engine/CoreEngineSignals.ts +7 -7
- package/src/executor/core-engine/CoreEngineUiStreamCollector.ts +5 -5
- package/src/executor/messages/AssistantResultPersistence.ts +8 -8
- package/src/executor/messages/SessionAttachmentMapper.ts +11 -11
- package/src/executor/messages/SessionMessageCodec.ts +10 -10
- package/src/executor/messages/SessionMessageLog.ts +3 -3
- package/src/executor/messages/SessionStepEventMapper.ts +5 -5
- package/src/executor/messages/UserVisibleText.ts +9 -9
- package/src/executor/services/ExecutorInflightService.ts +13 -9
- package/src/executor/store/history/SessionHistoryStore.ts +32 -28
- package/src/executor/store/history/jsonl/JsonlSessionHistoryStore.ts +146 -95
- package/src/executor/tools/plugin/PluginToolSchemas.ts +24 -10
- package/src/executor/types/SessionRecords.ts +217 -0
- package/src/executor/types/SessionRun.ts +5 -5
- package/src/index.ts +9 -10
- package/src/rpc/Client.ts +9 -9
- package/src/session/Session.ts +10 -10
- package/src/session/SessionTitle.ts +7 -4
- package/src/session/browse/Browse.ts +66 -58
- package/src/session/index.ts +1 -1
- package/src/session/runtime/SessionPromptRuntime.ts +6 -6
- package/src/session/services/SessionStateService.ts +61 -86
- package/src/session/services/SessionTurnService.ts +7 -7
- package/src/session/services/SessionViewService.ts +35 -45
- package/src/session/storage/Persistence.ts +6 -6
- package/src/session/storage/RuntimeSessionPort.ts +6 -6
- package/src/types/agent/AgentTypes.ts +4 -4
- package/src/types/agent/SessionActor.ts +12 -12
- package/src/types/agent/SessionTypes.ts +22 -22
- package/src/types/executor/SessionRunContext.ts +12 -12
- package/src/types/rpc/RpcProtocol.ts +6 -6
- package/src/types/runtime/agent/AgentContext.ts +8 -8
- package/src/types/sdk/AgentSessionAction.ts +35 -0
- package/src/types/sdk/AgentSessionEvent.ts +2 -2
- package/src/types/sdk/AgentSessionTurn.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/bin/agent/local/services/AgentSessionManager.d.ts.map +0 -1
- package/bin/agent/local/services/AgentSessionManager.js.map +0 -1
- package/bin/executor/types/SessionMessages.d.ts +0 -118
- package/bin/executor/types/SessionMessages.d.ts.map +0 -1
- package/bin/executor/types/SessionMessages.js +0 -28
- package/bin/executor/types/SessionMessages.js.map +0 -1
- package/bin/types/sdk/AgentSessionOperation.d.ts +0 -99
- package/bin/types/sdk/AgentSessionOperation.d.ts.map +0 -1
- package/bin/types/sdk/AgentSessionOperation.js +0 -10
- package/bin/types/sdk/AgentSessionOperation.js.map +0 -1
- package/scripts/session-operation-message.test.mjs +0 -197
- package/src/executor/types/SessionMessages.ts +0 -148
- package/src/types/sdk/AgentSessionOperation.ts +0 -125
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 验证 action record 的持久化、模型输入过滤与 timeline 投影。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - action record 会作为 `type=action` item 写入 JSONL。
|
|
6
|
+
* - 同一个 action id 会被更新为一条历史记录,不拆成 running/completed 多条。
|
|
7
|
+
* - history composer 组装 LLM 输入时必须过滤 action record。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import test from "node:test";
|
|
11
|
+
import assert from "node:assert/strict";
|
|
12
|
+
import os from "node:os";
|
|
13
|
+
import path from "node:path";
|
|
14
|
+
import fs from "node:fs/promises";
|
|
15
|
+
|
|
16
|
+
import { JsonlSessionHistoryStore } from "../bin/executor/store/history/jsonl/JsonlSessionHistoryStore.js";
|
|
17
|
+
import { JsonlSessionHistoryComposer } from "../bin/executor/composer/history/jsonl/JsonlSessionHistoryComposer.js";
|
|
18
|
+
import { toSessionTimelineEvents } from "../bin/session/browse/Browse.js";
|
|
19
|
+
import { Agent } from "../bin/index.js";
|
|
20
|
+
|
|
21
|
+
test("action record is upserted but filtered from LLM history", async () => {
|
|
22
|
+
const root_path = await fs.mkdtemp(
|
|
23
|
+
path.join(os.tmpdir(), "downcity-agent-action-message-"),
|
|
24
|
+
);
|
|
25
|
+
const session_id = "action_session";
|
|
26
|
+
const store = new JsonlSessionHistoryStore({
|
|
27
|
+
rootPath: root_path,
|
|
28
|
+
agentId: "action_agent",
|
|
29
|
+
sessionId: session_id,
|
|
30
|
+
});
|
|
31
|
+
const composer = new JsonlSessionHistoryComposer({ store });
|
|
32
|
+
|
|
33
|
+
await store.write_record(
|
|
34
|
+
store.userText({
|
|
35
|
+
text: "hello",
|
|
36
|
+
metadata: { sessionId: session_id },
|
|
37
|
+
id: "u:1",
|
|
38
|
+
}),
|
|
39
|
+
);
|
|
40
|
+
await store.write_record(
|
|
41
|
+
store.action({
|
|
42
|
+
action: {
|
|
43
|
+
id: "action:1",
|
|
44
|
+
title: "Compacting session records",
|
|
45
|
+
state: "running",
|
|
46
|
+
turnId: "turn-1",
|
|
47
|
+
},
|
|
48
|
+
metadata: { sessionId: session_id },
|
|
49
|
+
}),
|
|
50
|
+
);
|
|
51
|
+
await store.write_record(
|
|
52
|
+
store.action({
|
|
53
|
+
action: {
|
|
54
|
+
id: "action:1",
|
|
55
|
+
title: "Session records compacted",
|
|
56
|
+
description: "Compacted earlier messages.",
|
|
57
|
+
state: "completed",
|
|
58
|
+
turnId: "turn-1",
|
|
59
|
+
},
|
|
60
|
+
metadata: { sessionId: session_id },
|
|
61
|
+
}),
|
|
62
|
+
);
|
|
63
|
+
await store.write_record(
|
|
64
|
+
store.assistantText({
|
|
65
|
+
text: "world",
|
|
66
|
+
metadata: { sessionId: session_id },
|
|
67
|
+
id: "a:1",
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const persisted_messages = await store.list_records();
|
|
72
|
+
assert.equal(persisted_messages.length, 3);
|
|
73
|
+
assert.equal(persisted_messages[1].type, "action");
|
|
74
|
+
assert.equal(persisted_messages[1].title, "Session records compacted");
|
|
75
|
+
assert.equal(persisted_messages[1].description, "Compacted earlier messages.");
|
|
76
|
+
assert.equal(persisted_messages[1].state, "completed");
|
|
77
|
+
|
|
78
|
+
const model_messages = await composer.prepare({
|
|
79
|
+
query: "",
|
|
80
|
+
tools: {},
|
|
81
|
+
system: [],
|
|
82
|
+
model: {},
|
|
83
|
+
retryCount: 0,
|
|
84
|
+
});
|
|
85
|
+
assert.deepEqual(
|
|
86
|
+
model_messages.map((message) => message.id),
|
|
87
|
+
["u:1", "a:1"],
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const timeline_events = toSessionTimelineEvents(persisted_messages[1]);
|
|
91
|
+
assert.equal(timeline_events.length, 1);
|
|
92
|
+
assert.equal(timeline_events[0].role, "action");
|
|
93
|
+
assert.equal(timeline_events[0].actionTitle, "Session records compacted");
|
|
94
|
+
assert.equal(timeline_events[0].actionDescription, "Compacted earlier messages.");
|
|
95
|
+
assert.equal(timeline_events[0].actionState, "completed");
|
|
96
|
+
assert.equal(
|
|
97
|
+
timeline_events[0].text,
|
|
98
|
+
"Session records compacted\nCompacted earlier messages.",
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("session.set persists and publishes model-switching actions", async () => {
|
|
103
|
+
const agent_path = await fs.mkdtemp(
|
|
104
|
+
path.join(os.tmpdir(), "downcity-agent-model-switching-"),
|
|
105
|
+
);
|
|
106
|
+
const agent = new Agent({
|
|
107
|
+
id: "model_switching_agent",
|
|
108
|
+
path: agent_path,
|
|
109
|
+
});
|
|
110
|
+
try {
|
|
111
|
+
const session = await agent.sessions.create({
|
|
112
|
+
sessionId: "model_switching_session",
|
|
113
|
+
});
|
|
114
|
+
const events = [];
|
|
115
|
+
const unsubscribe = session.subscribe((event) => {
|
|
116
|
+
if (event.type === "action") events.push(event);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await session.set({
|
|
120
|
+
model: {
|
|
121
|
+
modelId: "test-model",
|
|
122
|
+
provider: "test",
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
unsubscribe();
|
|
126
|
+
|
|
127
|
+
assert.deepEqual(
|
|
128
|
+
events.map((event) => `${event.title}:${event.state}`),
|
|
129
|
+
["Switching session model:running", "Session model switched:completed"],
|
|
130
|
+
);
|
|
131
|
+
assert.equal(new Set(events.map((event) => event.id)).size, 1);
|
|
132
|
+
|
|
133
|
+
const records = await session.records({ view: "timeline" });
|
|
134
|
+
const action_events = records.items.filter(
|
|
135
|
+
(item) => item.role === "action",
|
|
136
|
+
);
|
|
137
|
+
assert.deepEqual(
|
|
138
|
+
action_events.map((event) => `${event.actionTitle}:${event.actionState}`),
|
|
139
|
+
["Session model switched:completed"],
|
|
140
|
+
);
|
|
141
|
+
} finally {
|
|
142
|
+
await agent.dispose();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("session.fork persists and publishes history-forking actions on source session", async () => {
|
|
147
|
+
const agent_path = await fs.mkdtemp(
|
|
148
|
+
path.join(os.tmpdir(), "downcity-agent-history-forking-"),
|
|
149
|
+
);
|
|
150
|
+
const agent = new Agent({
|
|
151
|
+
id: "history_forking_agent",
|
|
152
|
+
path: agent_path,
|
|
153
|
+
});
|
|
154
|
+
try {
|
|
155
|
+
const session = await agent.sessions.create({
|
|
156
|
+
sessionId: "history_forking_session",
|
|
157
|
+
});
|
|
158
|
+
await session.set({
|
|
159
|
+
model: {
|
|
160
|
+
modelId: "fork-test-model",
|
|
161
|
+
provider: "test",
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
await session.append_user_message({ text: "source message" });
|
|
165
|
+
|
|
166
|
+
const events = [];
|
|
167
|
+
const unsubscribe = session.subscribe((event) => {
|
|
168
|
+
if (event.type === "action") {
|
|
169
|
+
events.push(event);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const forked = await session.fork();
|
|
173
|
+
unsubscribe();
|
|
174
|
+
|
|
175
|
+
assert.deepEqual(
|
|
176
|
+
events.map((event) => `${event.title}:${event.state}`),
|
|
177
|
+
["Forking session records:running", "Session records forked:completed"],
|
|
178
|
+
);
|
|
179
|
+
assert.equal(new Set(events.map((event) => event.id)).size, 1);
|
|
180
|
+
assert.notEqual(forked.id, session.id);
|
|
181
|
+
|
|
182
|
+
const source_records = await session.records({ view: "timeline" });
|
|
183
|
+
const source_fork_actions = source_records.items.filter(
|
|
184
|
+
(item) => item.role === "action" && item.actionTitle === "Session records forked",
|
|
185
|
+
);
|
|
186
|
+
assert.deepEqual(
|
|
187
|
+
source_fork_actions.map((event) => event.actionState),
|
|
188
|
+
["completed"],
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const forked_records = await forked.records({ view: "timeline" });
|
|
192
|
+
const forked_model_actions = forked_records.items.filter(
|
|
193
|
+
(item) => item.role === "action" && item.actionTitle === "Session model switched",
|
|
194
|
+
);
|
|
195
|
+
assert.equal(forked_model_actions.length, 1);
|
|
196
|
+
} finally {
|
|
197
|
+
await agent.dispose();
|
|
198
|
+
}
|
|
199
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file 验证 session compact prompt 与文件操作 XML 记录。
|
|
3
|
+
*
|
|
4
|
+
* 关键点(中文)
|
|
5
|
+
* - compact prompt 必须保持结构化摘要格式稳定。
|
|
6
|
+
* - 迭代更新 prompt 需要携带 previous-summary 标签。
|
|
7
|
+
* - 文件操作 XML 由本地解析追加,不依赖模型复述工具日志。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import test from "node:test";
|
|
11
|
+
import assert from "node:assert/strict";
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
SESSION_COMPACTION_SYSTEM_PROMPT,
|
|
15
|
+
append_session_compaction_file_operations,
|
|
16
|
+
build_initial_session_compaction_prompt,
|
|
17
|
+
build_turn_prefix_session_compaction_prompt,
|
|
18
|
+
build_update_session_compaction_prompt,
|
|
19
|
+
} from "../bin/executor/composer/compaction/jsonl/JsonlSessionCompactionPrompts.js";
|
|
20
|
+
import {
|
|
21
|
+
collect_session_compaction_file_operations,
|
|
22
|
+
format_session_compaction_file_operations,
|
|
23
|
+
} from "../bin/executor/composer/compaction/jsonl/JsonlSessionCompactionFileOperations.js";
|
|
24
|
+
|
|
25
|
+
test("session compaction prompts preserve structured formats", () => {
|
|
26
|
+
assert.match(
|
|
27
|
+
SESSION_COMPACTION_SYSTEM_PROMPT,
|
|
28
|
+
/Do NOT continue the conversation/,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const initial_prompt = build_initial_session_compaction_prompt({
|
|
32
|
+
conversation_text: "user: 请修改 packages/agent/src/foo.ts",
|
|
33
|
+
});
|
|
34
|
+
assert.match(initial_prompt, /## Goal/);
|
|
35
|
+
assert.match(initial_prompt, /## Constraints & Preferences/);
|
|
36
|
+
assert.match(initial_prompt, /## Critical Context/);
|
|
37
|
+
assert.match(
|
|
38
|
+
initial_prompt,
|
|
39
|
+
/Keep each section concise\. Preserve exact file paths/,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const update_prompt = build_update_session_compaction_prompt({
|
|
43
|
+
previous_summary: "## Goal\n旧目标",
|
|
44
|
+
new_conversation_text: "assistant: 已完成一部分",
|
|
45
|
+
});
|
|
46
|
+
assert.match(update_prompt, /<previous-summary>\n## Goal\n旧目标\n<\/previous-summary>/);
|
|
47
|
+
assert.match(update_prompt, /PRESERVE all existing information/);
|
|
48
|
+
assert.match(update_prompt, /## Next Steps/);
|
|
49
|
+
|
|
50
|
+
const prefix_prompt = build_turn_prefix_session_compaction_prompt({
|
|
51
|
+
prefix_text: "user: 这个 turn 太长",
|
|
52
|
+
});
|
|
53
|
+
assert.match(prefix_prompt, /## Original Request/);
|
|
54
|
+
assert.match(prefix_prompt, /## Context for Suffix/);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("session compaction file operations are appended as xml", () => {
|
|
58
|
+
const messages = [
|
|
59
|
+
{
|
|
60
|
+
id: "a:1",
|
|
61
|
+
role: "assistant",
|
|
62
|
+
parts: [
|
|
63
|
+
{
|
|
64
|
+
type: "tool-exec_command",
|
|
65
|
+
input: {
|
|
66
|
+
cmd: "sed -n '1,40p' packages/agent/src/foo.ts && rg -n compact packages/agent/src",
|
|
67
|
+
},
|
|
68
|
+
output: [
|
|
69
|
+
"*** Update File: packages/agent/src/bar.ts",
|
|
70
|
+
" M packages/agent/src/baz.ts",
|
|
71
|
+
].join("\n"),
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
const operations = collect_session_compaction_file_operations(messages);
|
|
78
|
+
assert.deepEqual(operations.read_files, [
|
|
79
|
+
"packages/agent/src",
|
|
80
|
+
"packages/agent/src/foo.ts",
|
|
81
|
+
]);
|
|
82
|
+
assert.deepEqual(operations.modified_files, [
|
|
83
|
+
"packages/agent/src/bar.ts",
|
|
84
|
+
"packages/agent/src/baz.ts",
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
const xml = format_session_compaction_file_operations(messages);
|
|
88
|
+
assert.match(xml, /<read-files>\npackages\/agent\/src/);
|
|
89
|
+
assert.match(xml, /<modified-files>\npackages\/agent\/src\/bar\.ts/);
|
|
90
|
+
|
|
91
|
+
const summary = append_session_compaction_file_operations({
|
|
92
|
+
summary: "## Goal\n完成 compact",
|
|
93
|
+
file_operations_xml: xml,
|
|
94
|
+
});
|
|
95
|
+
assert.match(summary, /## Goal\n完成 compact\n\n<read-files>/);
|
|
96
|
+
assert.match(summary, /<\/modified-files>$/);
|
|
97
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file 验证 session.
|
|
2
|
+
* @file 验证 session.records 的 compact archive 分层读取语义。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
5
|
* - compact summary 是模型上下文消息,但不应作为用户可见 history item 返回。
|
|
@@ -91,7 +91,7 @@ async function write_archive(file_path, session_id, messages) {
|
|
|
91
91
|
);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
test("session.
|
|
94
|
+
test("session.records hides compact summary and reads archive layers by archive_id", async () => {
|
|
95
95
|
const agent_path = await fs.mkdtemp(
|
|
96
96
|
path.join(os.tmpdir(), "downcity-agent-history-archive-"),
|
|
97
97
|
);
|
|
@@ -99,7 +99,7 @@ test("session.history hides compact summary and reads archive layers by archive_
|
|
|
99
99
|
id: "history_archive_agent",
|
|
100
100
|
path: agent_path,
|
|
101
101
|
});
|
|
102
|
-
const session = await agent.
|
|
102
|
+
const session = await agent.sessions.create({
|
|
103
103
|
sessionId: "history_archive_session",
|
|
104
104
|
});
|
|
105
105
|
|
|
@@ -131,7 +131,7 @@ test("session.history hides compact summary and reads archive layers by archive_
|
|
|
131
131
|
assistant_message(session.id, 2),
|
|
132
132
|
]);
|
|
133
133
|
|
|
134
|
-
const current_page = await session.
|
|
134
|
+
const current_page = await session.records({
|
|
135
135
|
limit: 1,
|
|
136
136
|
});
|
|
137
137
|
assert.equal(current_page.total, 2);
|
|
@@ -144,7 +144,7 @@ test("session.history hides compact summary and reads archive layers by archive_
|
|
|
144
144
|
["u:31"],
|
|
145
145
|
);
|
|
146
146
|
|
|
147
|
-
const next_current_page = await session.
|
|
147
|
+
const next_current_page = await session.records({
|
|
148
148
|
cursor: current_page.next_cursor,
|
|
149
149
|
});
|
|
150
150
|
assert.equal(next_current_page.has_more, false);
|
|
@@ -153,7 +153,7 @@ test("session.history hides compact summary and reads archive layers by archive_
|
|
|
153
153
|
["a:32"],
|
|
154
154
|
);
|
|
155
155
|
|
|
156
|
-
const previous_page = await session.
|
|
156
|
+
const previous_page = await session.records({
|
|
157
157
|
archive_id: current_page.previous_archive_id,
|
|
158
158
|
});
|
|
159
159
|
assert.equal(previous_page.archive_id, "compact-B");
|
|
@@ -164,7 +164,7 @@ test("session.history hides compact summary and reads archive layers by archive_
|
|
|
164
164
|
["u:16", "a:17"],
|
|
165
165
|
);
|
|
166
166
|
|
|
167
|
-
const oldest_page = await session.
|
|
167
|
+
const oldest_page = await session.records({
|
|
168
168
|
archive_id: previous_page.previous_archive_id,
|
|
169
169
|
});
|
|
170
170
|
assert.equal(oldest_page.archive_id, "compact-A");
|
|
@@ -174,7 +174,7 @@ test("session.history hides compact summary and reads archive layers by archive_
|
|
|
174
174
|
["u:1", "a:2"],
|
|
175
175
|
);
|
|
176
176
|
|
|
177
|
-
const timeline_page = await session.
|
|
177
|
+
const timeline_page = await session.records({
|
|
178
178
|
view: "timeline",
|
|
179
179
|
archive_id: "compact-B",
|
|
180
180
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file 验证 session
|
|
2
|
+
* @file 验证 session records 会把运行中的 assistant 收敛到 inflight 快照,并在完成后写回正式历史。
|
|
3
3
|
*
|
|
4
4
|
* 关键点(中文)
|
|
5
5
|
* - 直接覆盖 JSONL history store 的落盘语义,确保运行中不中断丢失过程。
|
|
@@ -41,7 +41,7 @@ test("JsonlSessionHistoryStore exposes inflight assistant during execution and f
|
|
|
41
41
|
sessionId: "session_test",
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
await store.
|
|
44
|
+
await store.write_record(
|
|
45
45
|
store.userText({
|
|
46
46
|
text: "write to document",
|
|
47
47
|
metadata: {
|
|
@@ -50,7 +50,7 @@ test("JsonlSessionHistoryStore exposes inflight assistant during execution and f
|
|
|
50
50
|
}),
|
|
51
51
|
);
|
|
52
52
|
|
|
53
|
-
await store.
|
|
53
|
+
await store.write_inflight(
|
|
54
54
|
create_assistant_message([
|
|
55
55
|
{ type: "step-start" },
|
|
56
56
|
{ type: "text", text: "Let me inspect the document.", state: "done" },
|
|
@@ -64,7 +64,7 @@ test("JsonlSessionHistoryStore exposes inflight assistant during execution and f
|
|
|
64
64
|
]),
|
|
65
65
|
);
|
|
66
66
|
|
|
67
|
-
const during_run = await store.
|
|
67
|
+
const during_run = await store.list_records();
|
|
68
68
|
assert.equal(during_run.length, 2);
|
|
69
69
|
assert.equal(during_run[1]?.role, "assistant");
|
|
70
70
|
assert.deepEqual(
|
|
@@ -72,13 +72,13 @@ test("JsonlSessionHistoryStore exposes inflight assistant during execution and f
|
|
|
72
72
|
["step-start", "text", "tool-exec_command"],
|
|
73
73
|
);
|
|
74
74
|
|
|
75
|
-
await store.
|
|
75
|
+
await store.finalize_inflight(
|
|
76
76
|
create_assistant_message([
|
|
77
77
|
{ type: "text", text: "Done writing.", state: "done" },
|
|
78
78
|
]),
|
|
79
79
|
);
|
|
80
80
|
|
|
81
|
-
const after_finish = await store.
|
|
81
|
+
const after_finish = await store.list_records();
|
|
82
82
|
assert.equal(after_finish.length, 2);
|
|
83
83
|
assert.deepEqual(
|
|
84
84
|
after_finish[1]?.parts.map((part) => part.type),
|
|
@@ -113,7 +113,7 @@ test("Appending a new user message flushes stale inflight assistant before the n
|
|
|
113
113
|
sessionId: "session_flush_test",
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
-
await store.
|
|
116
|
+
await store.write_record(
|
|
117
117
|
store.userText({
|
|
118
118
|
text: "first",
|
|
119
119
|
metadata: {
|
|
@@ -122,14 +122,14 @@ test("Appending a new user message flushes stale inflight assistant before the n
|
|
|
122
122
|
}),
|
|
123
123
|
);
|
|
124
124
|
|
|
125
|
-
await store.
|
|
125
|
+
await store.write_inflight(
|
|
126
126
|
create_assistant_message([
|
|
127
127
|
{ type: "step-start" },
|
|
128
128
|
{ type: "text", text: "partial assistant", state: "done" },
|
|
129
129
|
]),
|
|
130
130
|
);
|
|
131
131
|
|
|
132
|
-
await store.
|
|
132
|
+
await store.write_record(
|
|
133
133
|
store.userText({
|
|
134
134
|
text: "second",
|
|
135
135
|
metadata: {
|
|
@@ -138,7 +138,7 @@ test("Appending a new user message flushes stale inflight assistant before the n
|
|
|
138
138
|
}),
|
|
139
139
|
);
|
|
140
140
|
|
|
141
|
-
const messages = await store.
|
|
141
|
+
const messages = await store.list_records();
|
|
142
142
|
assert.equal(messages.length, 3);
|
|
143
143
|
assert.equal(messages[0]?.role, "user");
|
|
144
144
|
assert.equal(messages[1]?.role, "assistant");
|
|
@@ -54,12 +54,12 @@ async function create_agent_with_titled_session(input) {
|
|
|
54
54
|
path: agent_path,
|
|
55
55
|
model: create_mock_title_model(input.title),
|
|
56
56
|
});
|
|
57
|
-
const collection = agent.
|
|
58
|
-
const session = await collection.
|
|
57
|
+
const collection = agent.sessions;
|
|
58
|
+
const session = await collection.create({
|
|
59
59
|
sessionId: input.session_id,
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
await session.
|
|
62
|
+
await session.append_user_message({
|
|
63
63
|
text: input.first_user_text,
|
|
64
64
|
});
|
|
65
65
|
|
|
@@ -80,7 +80,7 @@ test("list_sessions returns persisted title from active session metadata", async
|
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
try {
|
|
83
|
-
const page = await collection.
|
|
83
|
+
const page = await collection.list();
|
|
84
84
|
|
|
85
85
|
assert.equal(page.total, 1);
|
|
86
86
|
assert.deepEqual(
|
|
@@ -93,7 +93,7 @@ test("list_sessions returns persisted title from active session metadata", async
|
|
|
93
93
|
{
|
|
94
94
|
sessionId: session.id,
|
|
95
95
|
title: "列表标题",
|
|
96
|
-
messageCount:
|
|
96
|
+
messageCount: 2,
|
|
97
97
|
},
|
|
98
98
|
],
|
|
99
99
|
);
|
|
@@ -112,12 +112,12 @@ test("archive_sessions returns title from archived session metadata", async () =
|
|
|
112
112
|
});
|
|
113
113
|
|
|
114
114
|
try {
|
|
115
|
-
await collection.
|
|
115
|
+
await collection.archive({
|
|
116
116
|
id: session.id,
|
|
117
117
|
});
|
|
118
118
|
|
|
119
|
-
const active_page = await collection.
|
|
120
|
-
const archived_page = await collection.
|
|
119
|
+
const active_page = await collection.list();
|
|
120
|
+
const archived_page = await collection.archived();
|
|
121
121
|
|
|
122
122
|
assert.equal(active_page.total, 0);
|
|
123
123
|
assert.equal(archived_page.total, 1);
|
|
@@ -131,7 +131,7 @@ test("archive_sessions returns title from archived session metadata", async () =
|
|
|
131
131
|
{
|
|
132
132
|
sessionId: session.id,
|
|
133
133
|
title: "归档标题",
|
|
134
|
-
messageCount:
|
|
134
|
+
messageCount: 2,
|
|
135
135
|
},
|
|
136
136
|
],
|
|
137
137
|
);
|
|
@@ -53,24 +53,25 @@ test("Session keeps title empty when no model is available", async () => {
|
|
|
53
53
|
id: "title_agent",
|
|
54
54
|
path: agent_path,
|
|
55
55
|
});
|
|
56
|
-
const session = await agent.
|
|
56
|
+
const session = await agent.sessions.create();
|
|
57
57
|
const events = [];
|
|
58
58
|
const unsubscribe = session.subscribe((event) => {
|
|
59
59
|
events.push(event);
|
|
60
60
|
});
|
|
61
61
|
|
|
62
62
|
try {
|
|
63
|
-
await session.
|
|
63
|
+
await session.append_user_message({
|
|
64
64
|
text: "Use shell tools to inspect the current workspace",
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
const title_event = events.find((event) => event.type === "session-title");
|
|
68
68
|
assert.equal(title_event, undefined);
|
|
69
69
|
|
|
70
|
-
const
|
|
71
|
-
assert.equal(
|
|
70
|
+
const records = await session.records();
|
|
71
|
+
assert.equal(records.session.title, undefined);
|
|
72
72
|
} finally {
|
|
73
73
|
unsubscribe();
|
|
74
|
+
await agent.dispose();
|
|
74
75
|
}
|
|
75
76
|
});
|
|
76
77
|
|
|
@@ -82,24 +83,24 @@ test("Session retries title generation after model becomes available", async ()
|
|
|
82
83
|
id: "title_retry_agent",
|
|
83
84
|
path: agent_path,
|
|
84
85
|
});
|
|
85
|
-
const session = await agent.
|
|
86
|
+
const session = await agent.sessions.create();
|
|
86
87
|
const events = [];
|
|
87
88
|
const unsubscribe = session.subscribe((event) => {
|
|
88
89
|
events.push(event);
|
|
89
90
|
});
|
|
90
91
|
|
|
91
92
|
try {
|
|
92
|
-
await session.
|
|
93
|
+
await session.append_user_message({
|
|
93
94
|
text: "Investigate flaky session title generation in the SDK",
|
|
94
95
|
});
|
|
95
96
|
|
|
96
|
-
const history_before_model = await session.
|
|
97
|
+
const history_before_model = await session.records();
|
|
97
98
|
assert.equal(history_before_model.session.title, undefined);
|
|
98
99
|
|
|
99
100
|
await session.set({
|
|
100
101
|
model: create_mock_title_model("排查 session 标题"),
|
|
101
102
|
});
|
|
102
|
-
await session.
|
|
103
|
+
await session.append_user_message({
|
|
103
104
|
text: "Need another prompt to trigger the retry path",
|
|
104
105
|
});
|
|
105
106
|
|
|
@@ -110,9 +111,10 @@ test("Session retries title generation after model becomes available", async ()
|
|
|
110
111
|
title: "排查 session 标题",
|
|
111
112
|
});
|
|
112
113
|
|
|
113
|
-
const
|
|
114
|
-
assert.equal(
|
|
114
|
+
const records = await session.records();
|
|
115
|
+
assert.equal(records.session.title, "排查 session 标题");
|
|
115
116
|
} finally {
|
|
116
117
|
unsubscribe();
|
|
118
|
+
await agent.dispose();
|
|
117
119
|
}
|
|
118
120
|
});
|
package/src/agent/local/Agent.ts
CHANGED
|
@@ -14,7 +14,7 @@ import type { AgentPlugins } from "@/plugin/types/Plugin.js";
|
|
|
14
14
|
import type {
|
|
15
15
|
AgentModel,
|
|
16
16
|
AgentOptions,
|
|
17
|
-
|
|
17
|
+
AgentSessions as AgentSessionsApi,
|
|
18
18
|
} from "@/types/agent/AgentTypes.js";
|
|
19
19
|
import type {
|
|
20
20
|
ShellApprovalMode,
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
AgentAssemblyService,
|
|
33
33
|
type AgentAssemblyResult,
|
|
34
34
|
} from "@/agent/local/services/AgentAssemblyService.js";
|
|
35
|
-
import {
|
|
35
|
+
import { AgentSessions as LocalAgentSessions } from "@/agent/local/services/AgentSessions.js";
|
|
36
36
|
import { AgentBackgroundService } from "@/agent/local/services/AgentBackgroundService.js";
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -43,6 +43,7 @@ export class Agent {
|
|
|
43
43
|
readonly path: string;
|
|
44
44
|
readonly tools: Record<string, Tool>;
|
|
45
45
|
readonly plugins: AgentPlugins;
|
|
46
|
+
readonly sessions: AgentSessionsApi;
|
|
46
47
|
|
|
47
48
|
private readonly logger: Logger;
|
|
48
49
|
private readonly agentContext: AgentContext;
|
|
@@ -51,7 +52,6 @@ export class Agent {
|
|
|
51
52
|
private readonly env: Record<string, string>;
|
|
52
53
|
private readonly defaultModel?: AgentModel;
|
|
53
54
|
private readonly SessionClass: AgentOptions["Session"];
|
|
54
|
-
private readonly sessionManager: AgentSessionManager;
|
|
55
55
|
private readonly backgroundService: AgentBackgroundService;
|
|
56
56
|
private readonly shell?: AgentOptions["shell"];
|
|
57
57
|
|
|
@@ -60,19 +60,19 @@ export class Agent {
|
|
|
60
60
|
constructor(options: AgentOptions) {
|
|
61
61
|
this.defaultModel = options.model;
|
|
62
62
|
this.SessionClass = options.Session;
|
|
63
|
-
let
|
|
63
|
+
let sessions_ref: LocalAgentSessions | null = null;
|
|
64
64
|
const assembly_service = new AgentAssemblyService({
|
|
65
65
|
options,
|
|
66
|
-
list_cached_sessions: () =>
|
|
66
|
+
list_cached_sessions: () => sessions_ref?.list_cached_sessions() || [],
|
|
67
67
|
get_session_port: (session_id) => {
|
|
68
|
-
if (!
|
|
69
|
-
throw new Error("Agent
|
|
68
|
+
if (!sessions_ref) {
|
|
69
|
+
throw new Error("Agent sessions are not initialized");
|
|
70
70
|
}
|
|
71
|
-
return
|
|
71
|
+
return sessions_ref.get_session_port(session_id);
|
|
72
72
|
},
|
|
73
73
|
resolve_session_model: async (session_id) => {
|
|
74
|
-
if (!
|
|
75
|
-
const session = await
|
|
74
|
+
if (!sessions_ref) return undefined;
|
|
75
|
+
const session = await sessions_ref.get(session_id);
|
|
76
76
|
return session.config.model;
|
|
77
77
|
},
|
|
78
78
|
});
|
|
@@ -96,8 +96,9 @@ export class Agent {
|
|
|
96
96
|
agent_context: this.agentContext,
|
|
97
97
|
get_shell: () => this.shell,
|
|
98
98
|
});
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
const sessions = this.create_sessions(assembly);
|
|
100
|
+
this.sessions = sessions;
|
|
101
|
+
sessions_ref = sessions;
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
/**
|
|
@@ -244,13 +245,6 @@ export class Agent {
|
|
|
244
245
|
return this.agentContext;
|
|
245
246
|
}
|
|
246
247
|
|
|
247
|
-
/**
|
|
248
|
-
* 返回当前 session collection 入口。
|
|
249
|
-
*/
|
|
250
|
-
session_collection(): AgentSessionCollection {
|
|
251
|
-
return this.sessionManager.get_session_collection();
|
|
252
|
-
}
|
|
253
|
-
|
|
254
248
|
/**
|
|
255
249
|
* 返回当前 agent 挂载的 Shell。
|
|
256
250
|
*/
|
|
@@ -258,10 +252,10 @@ export class Agent {
|
|
|
258
252
|
return this.shell;
|
|
259
253
|
}
|
|
260
254
|
|
|
261
|
-
private
|
|
255
|
+
private create_sessions(
|
|
262
256
|
assembly: AgentAssemblyResult,
|
|
263
|
-
):
|
|
264
|
-
return new
|
|
257
|
+
): LocalAgentSessions {
|
|
258
|
+
return new LocalAgentSessions({
|
|
265
259
|
agent_id: this.id || assembly.id,
|
|
266
260
|
project_root: this.path || assembly.path,
|
|
267
261
|
tools: this.tools || assembly.tools,
|