@shareai-lab/kode-sdk 2.7.1 → 2.7.2
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/dist/core/agent/breakpoint-manager.js +36 -0
- package/dist/core/agent/message-queue.js +57 -0
- package/dist/core/agent/permission-manager.js +32 -0
- package/dist/core/agent/todo-manager.js +91 -0
- package/dist/core/agent/tool-runner.js +45 -0
- package/dist/core/agent.js +2035 -0
- package/dist/core/config.js +2 -0
- package/dist/core/context-manager.js +241 -0
- package/dist/core/errors.js +49 -0
- package/dist/core/events.js +329 -0
- package/dist/core/file-pool.d.ts +2 -0
- package/dist/core/file-pool.js +125 -0
- package/dist/core/hooks.js +71 -0
- package/dist/core/permission-modes.js +61 -0
- package/dist/core/pool.js +301 -0
- package/dist/core/room.js +57 -0
- package/dist/core/scheduler.js +58 -0
- package/dist/core/skills/index.js +20 -0
- package/dist/core/skills/management-manager.js +557 -0
- package/dist/core/skills/manager.js +243 -0
- package/dist/core/skills/operation-queue.js +113 -0
- package/dist/core/skills/sandbox-file-manager.js +183 -0
- package/dist/core/skills/types.js +9 -0
- package/dist/core/skills/xml-generator.js +70 -0
- package/dist/core/template.js +35 -0
- package/dist/core/time-bridge.js +100 -0
- package/dist/core/todo.js +89 -0
- package/dist/core/types.js +3 -0
- package/dist/index.js +148 -60461
- package/dist/infra/db/postgres/postgres-store.js +1073 -0
- package/dist/infra/db/sqlite/sqlite-store.js +800 -0
- package/dist/infra/e2b/e2b-fs.js +128 -0
- package/dist/infra/e2b/e2b-sandbox.js +156 -0
- package/dist/infra/e2b/e2b-template.js +105 -0
- package/dist/infra/e2b/index.js +9 -0
- package/dist/infra/e2b/types.js +2 -0
- package/dist/infra/provider.js +67 -0
- package/dist/infra/providers/anthropic.js +308 -0
- package/dist/infra/providers/core/errors.js +353 -0
- package/dist/infra/providers/core/fork.js +418 -0
- package/dist/infra/providers/core/index.js +76 -0
- package/dist/infra/providers/core/logger.js +191 -0
- package/dist/infra/providers/core/retry.js +189 -0
- package/dist/infra/providers/core/usage.js +376 -0
- package/dist/infra/providers/gemini.js +493 -0
- package/dist/infra/providers/index.js +83 -0
- package/dist/infra/providers/openai.js +662 -0
- package/dist/infra/providers/types.js +20 -0
- package/dist/infra/providers/utils.js +400 -0
- package/dist/infra/sandbox-factory.js +30 -0
- package/dist/infra/sandbox.js +243 -0
- package/dist/infra/store/factory.js +80 -0
- package/dist/infra/store/index.js +26 -0
- package/dist/infra/store/json-store.js +606 -0
- package/dist/infra/store/types.js +2 -0
- package/dist/infra/store.js +29 -0
- package/dist/tools/bash_kill/index.js +35 -0
- package/dist/tools/bash_kill/prompt.js +14 -0
- package/dist/tools/bash_logs/index.js +40 -0
- package/dist/tools/bash_logs/prompt.js +14 -0
- package/dist/tools/bash_run/index.js +61 -0
- package/dist/tools/bash_run/prompt.js +18 -0
- package/dist/tools/builtin.js +26 -0
- package/dist/tools/define.js +214 -0
- package/dist/tools/fs_edit/index.js +62 -0
- package/dist/tools/fs_edit/prompt.js +15 -0
- package/dist/tools/fs_glob/index.js +40 -0
- package/dist/tools/fs_glob/prompt.js +15 -0
- package/dist/tools/fs_grep/index.js +66 -0
- package/dist/tools/fs_grep/prompt.js +16 -0
- package/dist/tools/fs_multi_edit/index.js +106 -0
- package/dist/tools/fs_multi_edit/prompt.js +16 -0
- package/dist/tools/fs_read/index.js +40 -0
- package/dist/tools/fs_read/prompt.js +16 -0
- package/dist/tools/fs_write/index.js +40 -0
- package/dist/tools/fs_write/prompt.js +15 -0
- package/dist/tools/index.js +61 -0
- package/dist/tools/mcp.js +185 -0
- package/dist/tools/registry.js +26 -0
- package/dist/tools/scripts.js +205 -0
- package/dist/tools/skills.js +115 -0
- package/dist/tools/task_run/index.js +58 -0
- package/dist/tools/task_run/prompt.js +25 -0
- package/dist/tools/todo_read/index.js +29 -0
- package/dist/tools/todo_read/prompt.js +18 -0
- package/dist/tools/todo_write/index.js +42 -0
- package/dist/tools/todo_write/prompt.js +23 -0
- package/dist/tools/tool.js +211 -0
- package/dist/tools/toolkit.js +98 -0
- package/dist/tools/type-inference.js +207 -0
- package/dist/utils/agent-id.js +28 -0
- package/dist/utils/logger.js +44 -0
- package/dist/utils/session-id.js +64 -0
- package/package.json +7 -38
- package/dist/index.js.map +0 -7
- package/dist/index.mjs +0 -60385
- package/dist/index.mjs.map +0 -7
|
@@ -0,0 +1,800 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.SqliteStore = void 0;
|
|
40
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
41
|
+
const store_1 = require("../../store");
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const pathModule = __importStar(require("path"));
|
|
44
|
+
/**
|
|
45
|
+
* SqliteStore 实现
|
|
46
|
+
*
|
|
47
|
+
* 混合存储策略:
|
|
48
|
+
* - 数据库:AgentInfo, Messages, ToolCallRecords, Snapshots(支持查询)
|
|
49
|
+
* - 文件系统:Events, Todos, History, MediaCache(高频写入)
|
|
50
|
+
*/
|
|
51
|
+
class SqliteStore {
|
|
52
|
+
constructor(dbPath, fileStoreBaseDir) {
|
|
53
|
+
// 指标追踪
|
|
54
|
+
this.metrics = {
|
|
55
|
+
saves: 0,
|
|
56
|
+
loads: 0,
|
|
57
|
+
queries: 0,
|
|
58
|
+
deletes: 0,
|
|
59
|
+
latencies: []
|
|
60
|
+
};
|
|
61
|
+
// 内存锁(单进程场景)
|
|
62
|
+
this.locks = new Map();
|
|
63
|
+
this.dbPath = dbPath;
|
|
64
|
+
this.db = new better_sqlite3_1.default(dbPath);
|
|
65
|
+
this.fileStore = new store_1.JSONStore(fileStoreBaseDir || pathModule.dirname(dbPath));
|
|
66
|
+
this.initialize();
|
|
67
|
+
}
|
|
68
|
+
// ========== 数据库初始化 ==========
|
|
69
|
+
initialize() {
|
|
70
|
+
this.createTables();
|
|
71
|
+
this.createIndexes();
|
|
72
|
+
}
|
|
73
|
+
createTables() {
|
|
74
|
+
// 表 1: agents - Agent 元信息
|
|
75
|
+
this.db.exec(`
|
|
76
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
77
|
+
agent_id TEXT PRIMARY KEY,
|
|
78
|
+
template_id TEXT NOT NULL,
|
|
79
|
+
created_at TEXT NOT NULL,
|
|
80
|
+
config_version TEXT NOT NULL,
|
|
81
|
+
lineage TEXT NOT NULL,
|
|
82
|
+
message_count INTEGER NOT NULL DEFAULT 0,
|
|
83
|
+
last_sfp_index INTEGER NOT NULL DEFAULT -1,
|
|
84
|
+
last_bookmark TEXT,
|
|
85
|
+
breakpoint TEXT,
|
|
86
|
+
metadata TEXT NOT NULL
|
|
87
|
+
);
|
|
88
|
+
`);
|
|
89
|
+
// 表 2: messages - 对话消息
|
|
90
|
+
this.db.exec(`
|
|
91
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
92
|
+
id TEXT PRIMARY KEY,
|
|
93
|
+
agent_id TEXT NOT NULL,
|
|
94
|
+
role TEXT NOT NULL,
|
|
95
|
+
content TEXT NOT NULL,
|
|
96
|
+
seq INTEGER NOT NULL,
|
|
97
|
+
metadata TEXT,
|
|
98
|
+
created_at INTEGER NOT NULL,
|
|
99
|
+
FOREIGN KEY (agent_id) REFERENCES agents(agent_id) ON DELETE CASCADE
|
|
100
|
+
);
|
|
101
|
+
`);
|
|
102
|
+
// 表 3: tool_calls - 工具调用记录
|
|
103
|
+
this.db.exec(`
|
|
104
|
+
CREATE TABLE IF NOT EXISTS tool_calls (
|
|
105
|
+
id TEXT PRIMARY KEY,
|
|
106
|
+
agent_id TEXT NOT NULL,
|
|
107
|
+
name TEXT NOT NULL,
|
|
108
|
+
input TEXT NOT NULL,
|
|
109
|
+
state TEXT NOT NULL,
|
|
110
|
+
approval TEXT NOT NULL,
|
|
111
|
+
result TEXT,
|
|
112
|
+
error TEXT,
|
|
113
|
+
is_error INTEGER DEFAULT 0,
|
|
114
|
+
started_at INTEGER,
|
|
115
|
+
completed_at INTEGER,
|
|
116
|
+
duration_ms INTEGER,
|
|
117
|
+
created_at INTEGER NOT NULL,
|
|
118
|
+
updated_at INTEGER NOT NULL,
|
|
119
|
+
audit_trail TEXT NOT NULL,
|
|
120
|
+
FOREIGN KEY (agent_id) REFERENCES agents(agent_id) ON DELETE CASCADE
|
|
121
|
+
);
|
|
122
|
+
`);
|
|
123
|
+
// 表 4: snapshots - 快照
|
|
124
|
+
this.db.exec(`
|
|
125
|
+
CREATE TABLE IF NOT EXISTS snapshots (
|
|
126
|
+
agent_id TEXT NOT NULL,
|
|
127
|
+
snapshot_id TEXT NOT NULL,
|
|
128
|
+
messages TEXT NOT NULL,
|
|
129
|
+
last_sfp_index INTEGER NOT NULL,
|
|
130
|
+
last_bookmark TEXT NOT NULL,
|
|
131
|
+
created_at TEXT NOT NULL,
|
|
132
|
+
metadata TEXT,
|
|
133
|
+
PRIMARY KEY (agent_id, snapshot_id),
|
|
134
|
+
FOREIGN KEY (agent_id) REFERENCES agents(agent_id) ON DELETE CASCADE
|
|
135
|
+
);
|
|
136
|
+
`);
|
|
137
|
+
}
|
|
138
|
+
createIndexes() {
|
|
139
|
+
// agents 索引
|
|
140
|
+
this.db.exec(`
|
|
141
|
+
CREATE INDEX IF NOT EXISTS idx_agents_template_id ON agents(template_id);
|
|
142
|
+
CREATE INDEX IF NOT EXISTS idx_agents_created_at ON agents(created_at);
|
|
143
|
+
`);
|
|
144
|
+
// messages 索引
|
|
145
|
+
this.db.exec(`
|
|
146
|
+
CREATE INDEX IF NOT EXISTS idx_messages_agent_id ON messages(agent_id);
|
|
147
|
+
CREATE INDEX IF NOT EXISTS idx_messages_role ON messages(role);
|
|
148
|
+
CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(created_at DESC);
|
|
149
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_messages_agent_seq ON messages(agent_id, seq);
|
|
150
|
+
`);
|
|
151
|
+
// tool_calls 索引
|
|
152
|
+
this.db.exec(`
|
|
153
|
+
CREATE INDEX IF NOT EXISTS idx_tool_calls_agent_id ON tool_calls(agent_id);
|
|
154
|
+
CREATE INDEX IF NOT EXISTS idx_tool_calls_name ON tool_calls(name);
|
|
155
|
+
CREATE INDEX IF NOT EXISTS idx_tool_calls_state ON tool_calls(state);
|
|
156
|
+
CREATE INDEX IF NOT EXISTS idx_tool_calls_created_at ON tool_calls(created_at DESC);
|
|
157
|
+
`);
|
|
158
|
+
// snapshots 索引
|
|
159
|
+
this.db.exec(`
|
|
160
|
+
CREATE INDEX IF NOT EXISTS idx_snapshots_agent_id ON snapshots(agent_id);
|
|
161
|
+
CREATE INDEX IF NOT EXISTS idx_snapshots_created_at ON snapshots(created_at DESC);
|
|
162
|
+
`);
|
|
163
|
+
}
|
|
164
|
+
// ========== 运行时状态管理(数据库) ==========
|
|
165
|
+
async saveMessages(agentId, messages) {
|
|
166
|
+
const saveMessagesTransaction = this.db.transaction(() => {
|
|
167
|
+
// 1. 删除旧消息
|
|
168
|
+
this.db.prepare('DELETE FROM messages WHERE agent_id = ?').run(agentId);
|
|
169
|
+
// 2. 批量插入新消息
|
|
170
|
+
const insertStmt = this.db.prepare(`
|
|
171
|
+
INSERT INTO messages (
|
|
172
|
+
id, agent_id, role, content, seq, metadata, created_at
|
|
173
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
174
|
+
`);
|
|
175
|
+
messages.forEach((msg, index) => {
|
|
176
|
+
const id = this.generateMessageId();
|
|
177
|
+
insertStmt.run(id, agentId, msg.role, JSON.stringify(msg.content), index, // seq: array index
|
|
178
|
+
msg.metadata ? JSON.stringify(msg.metadata) : null, Date.now());
|
|
179
|
+
});
|
|
180
|
+
// 3. 更新 agents 表的 message_count
|
|
181
|
+
this.db.prepare(`
|
|
182
|
+
UPDATE agents
|
|
183
|
+
SET message_count = ?
|
|
184
|
+
WHERE agent_id = ?
|
|
185
|
+
`).run(messages.length, agentId);
|
|
186
|
+
});
|
|
187
|
+
saveMessagesTransaction();
|
|
188
|
+
}
|
|
189
|
+
async loadMessages(agentId) {
|
|
190
|
+
const rows = this.db.prepare(`
|
|
191
|
+
SELECT role, content, metadata
|
|
192
|
+
FROM messages
|
|
193
|
+
WHERE agent_id = ?
|
|
194
|
+
ORDER BY seq ASC
|
|
195
|
+
`).all(agentId);
|
|
196
|
+
return rows.map(row => ({
|
|
197
|
+
role: row.role,
|
|
198
|
+
content: JSON.parse(row.content),
|
|
199
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : undefined
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
generateMessageId() {
|
|
203
|
+
return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
204
|
+
}
|
|
205
|
+
async saveToolCallRecords(agentId, records) {
|
|
206
|
+
const saveToolCallsTransaction = this.db.transaction(() => {
|
|
207
|
+
// 1. 删除旧记录
|
|
208
|
+
this.db.prepare('DELETE FROM tool_calls WHERE agent_id = ?').run(agentId);
|
|
209
|
+
// 2. 批量插入新记录
|
|
210
|
+
const insertStmt = this.db.prepare(`
|
|
211
|
+
INSERT INTO tool_calls (
|
|
212
|
+
id, agent_id, name, input, state, approval,
|
|
213
|
+
result, error, is_error,
|
|
214
|
+
started_at, completed_at, duration_ms,
|
|
215
|
+
created_at, updated_at, audit_trail
|
|
216
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
217
|
+
`);
|
|
218
|
+
records.forEach(record => {
|
|
219
|
+
insertStmt.run(record.id, agentId, record.name, JSON.stringify(record.input), record.state, JSON.stringify(record.approval), record.result ? JSON.stringify(record.result) : null, record.error || null, record.isError ? 1 : 0, record.startedAt || null, record.completedAt || null, record.durationMs || null, record.createdAt, record.updatedAt, JSON.stringify(record.auditTrail));
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
saveToolCallsTransaction();
|
|
223
|
+
}
|
|
224
|
+
async loadToolCallRecords(agentId) {
|
|
225
|
+
const rows = this.db.prepare(`
|
|
226
|
+
SELECT id, name, input, state, approval,
|
|
227
|
+
result, error, is_error,
|
|
228
|
+
started_at, completed_at, duration_ms,
|
|
229
|
+
created_at, updated_at, audit_trail
|
|
230
|
+
FROM tool_calls
|
|
231
|
+
WHERE agent_id = ?
|
|
232
|
+
ORDER BY created_at ASC
|
|
233
|
+
`).all(agentId);
|
|
234
|
+
return rows.map(row => ({
|
|
235
|
+
id: row.id,
|
|
236
|
+
name: row.name,
|
|
237
|
+
input: JSON.parse(row.input),
|
|
238
|
+
state: row.state,
|
|
239
|
+
approval: JSON.parse(row.approval),
|
|
240
|
+
result: row.result ? JSON.parse(row.result) : undefined,
|
|
241
|
+
error: row.error || undefined,
|
|
242
|
+
isError: row.is_error === 1,
|
|
243
|
+
startedAt: row.started_at || undefined,
|
|
244
|
+
completedAt: row.completed_at || undefined,
|
|
245
|
+
durationMs: row.duration_ms || undefined,
|
|
246
|
+
createdAt: row.created_at,
|
|
247
|
+
updatedAt: row.updated_at,
|
|
248
|
+
auditTrail: JSON.parse(row.audit_trail)
|
|
249
|
+
}));
|
|
250
|
+
}
|
|
251
|
+
// ========== 事件流管理(文件系统) ==========
|
|
252
|
+
async saveTodos(agentId, snapshot) {
|
|
253
|
+
return this.fileStore.saveTodos(agentId, snapshot);
|
|
254
|
+
}
|
|
255
|
+
async loadTodos(agentId) {
|
|
256
|
+
return this.fileStore.loadTodos(agentId);
|
|
257
|
+
}
|
|
258
|
+
async appendEvent(agentId, timeline) {
|
|
259
|
+
return this.fileStore.appendEvent(agentId, timeline);
|
|
260
|
+
}
|
|
261
|
+
async *readEvents(agentId, opts) {
|
|
262
|
+
yield* this.fileStore.readEvents(agentId, opts);
|
|
263
|
+
}
|
|
264
|
+
// ========== 历史与压缩管理(文件系统) ==========
|
|
265
|
+
async saveHistoryWindow(agentId, window) {
|
|
266
|
+
return this.fileStore.saveHistoryWindow(agentId, window);
|
|
267
|
+
}
|
|
268
|
+
async loadHistoryWindows(agentId) {
|
|
269
|
+
return this.fileStore.loadHistoryWindows(agentId);
|
|
270
|
+
}
|
|
271
|
+
async saveCompressionRecord(agentId, record) {
|
|
272
|
+
return this.fileStore.saveCompressionRecord(agentId, record);
|
|
273
|
+
}
|
|
274
|
+
async loadCompressionRecords(agentId) {
|
|
275
|
+
return this.fileStore.loadCompressionRecords(agentId);
|
|
276
|
+
}
|
|
277
|
+
async saveRecoveredFile(agentId, file) {
|
|
278
|
+
return this.fileStore.saveRecoveredFile(agentId, file);
|
|
279
|
+
}
|
|
280
|
+
async loadRecoveredFiles(agentId) {
|
|
281
|
+
return this.fileStore.loadRecoveredFiles(agentId);
|
|
282
|
+
}
|
|
283
|
+
// ========== 多模态缓存管理(文件系统) ==========
|
|
284
|
+
async saveMediaCache(agentId, records) {
|
|
285
|
+
return this.fileStore.saveMediaCache(agentId, records);
|
|
286
|
+
}
|
|
287
|
+
async loadMediaCache(agentId) {
|
|
288
|
+
return this.fileStore.loadMediaCache(agentId);
|
|
289
|
+
}
|
|
290
|
+
// ========== 快照管理(数据库) ==========
|
|
291
|
+
async saveSnapshot(agentId, snapshot) {
|
|
292
|
+
const stmt = this.db.prepare(`
|
|
293
|
+
INSERT OR REPLACE INTO snapshots (
|
|
294
|
+
agent_id, snapshot_id, messages, last_sfp_index,
|
|
295
|
+
last_bookmark, created_at, metadata
|
|
296
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
297
|
+
`);
|
|
298
|
+
stmt.run(agentId, snapshot.id, JSON.stringify(snapshot.messages), snapshot.lastSfpIndex, JSON.stringify(snapshot.lastBookmark), snapshot.createdAt, snapshot.metadata ? JSON.stringify(snapshot.metadata) : null);
|
|
299
|
+
}
|
|
300
|
+
async loadSnapshot(agentId, snapshotId) {
|
|
301
|
+
const row = this.db.prepare(`
|
|
302
|
+
SELECT snapshot_id, messages, last_sfp_index,
|
|
303
|
+
last_bookmark, created_at, metadata
|
|
304
|
+
FROM snapshots
|
|
305
|
+
WHERE agent_id = ? AND snapshot_id = ?
|
|
306
|
+
`).get(agentId, snapshotId);
|
|
307
|
+
if (!row) {
|
|
308
|
+
return undefined;
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
id: row.snapshot_id,
|
|
312
|
+
messages: JSON.parse(row.messages),
|
|
313
|
+
lastSfpIndex: row.last_sfp_index,
|
|
314
|
+
lastBookmark: JSON.parse(row.last_bookmark),
|
|
315
|
+
createdAt: row.created_at,
|
|
316
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : undefined
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
async listSnapshots(agentId) {
|
|
320
|
+
const rows = this.db.prepare(`
|
|
321
|
+
SELECT snapshot_id, messages, last_sfp_index,
|
|
322
|
+
last_bookmark, created_at, metadata
|
|
323
|
+
FROM snapshots
|
|
324
|
+
WHERE agent_id = ?
|
|
325
|
+
ORDER BY created_at DESC
|
|
326
|
+
`).all(agentId);
|
|
327
|
+
return rows.map(row => ({
|
|
328
|
+
id: row.snapshot_id,
|
|
329
|
+
messages: JSON.parse(row.messages),
|
|
330
|
+
lastSfpIndex: row.last_sfp_index,
|
|
331
|
+
lastBookmark: JSON.parse(row.last_bookmark),
|
|
332
|
+
createdAt: row.created_at,
|
|
333
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : undefined
|
|
334
|
+
}));
|
|
335
|
+
}
|
|
336
|
+
// ========== 元数据管理(数据库) ==========
|
|
337
|
+
async saveInfo(agentId, info) {
|
|
338
|
+
const stmt = this.db.prepare(`
|
|
339
|
+
INSERT OR REPLACE INTO agents (
|
|
340
|
+
agent_id, template_id, created_at, config_version,
|
|
341
|
+
lineage, message_count, last_sfp_index, last_bookmark,
|
|
342
|
+
breakpoint, metadata
|
|
343
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
344
|
+
`);
|
|
345
|
+
stmt.run(info.agentId, info.templateId, info.createdAt, info.configVersion, JSON.stringify(info.lineage), info.messageCount, info.lastSfpIndex, info.lastBookmark ? JSON.stringify(info.lastBookmark) : null, info.breakpoint || null, JSON.stringify(info.metadata));
|
|
346
|
+
}
|
|
347
|
+
async loadInfo(agentId) {
|
|
348
|
+
const row = this.db.prepare(`
|
|
349
|
+
SELECT agent_id, template_id, created_at, config_version,
|
|
350
|
+
lineage, message_count, last_sfp_index, last_bookmark,
|
|
351
|
+
breakpoint, metadata
|
|
352
|
+
FROM agents
|
|
353
|
+
WHERE agent_id = ?
|
|
354
|
+
`).get(agentId);
|
|
355
|
+
if (!row) {
|
|
356
|
+
return undefined;
|
|
357
|
+
}
|
|
358
|
+
const info = {
|
|
359
|
+
agentId: row.agent_id,
|
|
360
|
+
templateId: row.template_id,
|
|
361
|
+
createdAt: row.created_at,
|
|
362
|
+
configVersion: row.config_version,
|
|
363
|
+
lineage: JSON.parse(row.lineage),
|
|
364
|
+
messageCount: row.message_count,
|
|
365
|
+
lastSfpIndex: row.last_sfp_index,
|
|
366
|
+
lastBookmark: row.last_bookmark ? JSON.parse(row.last_bookmark) : undefined,
|
|
367
|
+
metadata: JSON.parse(row.metadata)
|
|
368
|
+
};
|
|
369
|
+
// Restore breakpoint to AgentInfo if present
|
|
370
|
+
if (row.breakpoint) {
|
|
371
|
+
info.breakpoint = row.breakpoint;
|
|
372
|
+
}
|
|
373
|
+
return info;
|
|
374
|
+
}
|
|
375
|
+
// ========== 生命周期管理 ==========
|
|
376
|
+
async exists(agentId) {
|
|
377
|
+
const row = this.db.prepare('SELECT 1 FROM agents WHERE agent_id = ?').get(agentId);
|
|
378
|
+
return !!row;
|
|
379
|
+
}
|
|
380
|
+
async delete(agentId) {
|
|
381
|
+
// 删除数据库记录(级联删除)
|
|
382
|
+
this.db.prepare('DELETE FROM agents WHERE agent_id = ?').run(agentId);
|
|
383
|
+
// 删除文件系统数据
|
|
384
|
+
await this.fileStore.delete(agentId);
|
|
385
|
+
}
|
|
386
|
+
async list(prefix) {
|
|
387
|
+
const sql = prefix
|
|
388
|
+
? 'SELECT agent_id FROM agents WHERE agent_id LIKE ? ORDER BY created_at DESC'
|
|
389
|
+
: 'SELECT agent_id FROM agents ORDER BY created_at DESC';
|
|
390
|
+
const params = prefix ? [`${prefix}%`] : [];
|
|
391
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
392
|
+
return rows.map(row => row.agent_id);
|
|
393
|
+
}
|
|
394
|
+
// ========== QueryableStore 接口实现 ==========
|
|
395
|
+
async querySessions(filters) {
|
|
396
|
+
let sql = `
|
|
397
|
+
SELECT agent_id, template_id, created_at, message_count,
|
|
398
|
+
last_sfp_index, breakpoint
|
|
399
|
+
FROM agents
|
|
400
|
+
WHERE 1=1
|
|
401
|
+
`;
|
|
402
|
+
const params = [];
|
|
403
|
+
if (filters.agentId) {
|
|
404
|
+
sql += ' AND agent_id = ?';
|
|
405
|
+
params.push(filters.agentId);
|
|
406
|
+
}
|
|
407
|
+
if (filters.templateId) {
|
|
408
|
+
sql += ' AND template_id = ?';
|
|
409
|
+
params.push(filters.templateId);
|
|
410
|
+
}
|
|
411
|
+
if (filters.startDate) {
|
|
412
|
+
sql += ' AND created_at >= ?';
|
|
413
|
+
params.push(new Date(filters.startDate).toISOString());
|
|
414
|
+
}
|
|
415
|
+
if (filters.endDate) {
|
|
416
|
+
sql += ' AND created_at <= ?';
|
|
417
|
+
params.push(new Date(filters.endDate).toISOString());
|
|
418
|
+
}
|
|
419
|
+
// Sorting
|
|
420
|
+
const sortBy = filters.sortBy || 'created_at';
|
|
421
|
+
const sortOrder = filters.sortOrder || 'desc';
|
|
422
|
+
sql += ` ORDER BY ${sortBy} ${sortOrder.toUpperCase()}`;
|
|
423
|
+
// Pagination
|
|
424
|
+
if (filters.limit) {
|
|
425
|
+
sql += ' LIMIT ?';
|
|
426
|
+
params.push(filters.limit);
|
|
427
|
+
if (filters.offset) {
|
|
428
|
+
sql += ' OFFSET ?';
|
|
429
|
+
params.push(filters.offset);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
433
|
+
return rows.map(row => ({
|
|
434
|
+
agentId: row.agent_id,
|
|
435
|
+
templateId: row.template_id,
|
|
436
|
+
createdAt: row.created_at,
|
|
437
|
+
messageCount: row.message_count,
|
|
438
|
+
lastSfpIndex: row.last_sfp_index,
|
|
439
|
+
breakpoint: row.breakpoint
|
|
440
|
+
}));
|
|
441
|
+
}
|
|
442
|
+
async queryMessages(filters) {
|
|
443
|
+
let sql = 'SELECT role, content, metadata FROM messages WHERE 1=1';
|
|
444
|
+
const params = [];
|
|
445
|
+
if (filters.agentId) {
|
|
446
|
+
sql += ' AND agent_id = ?';
|
|
447
|
+
params.push(filters.agentId);
|
|
448
|
+
}
|
|
449
|
+
if (filters.role) {
|
|
450
|
+
sql += ' AND role = ?';
|
|
451
|
+
params.push(filters.role);
|
|
452
|
+
}
|
|
453
|
+
if (filters.startDate) {
|
|
454
|
+
sql += ' AND created_at >= ?';
|
|
455
|
+
params.push(filters.startDate);
|
|
456
|
+
}
|
|
457
|
+
if (filters.endDate) {
|
|
458
|
+
sql += ' AND created_at <= ?';
|
|
459
|
+
params.push(filters.endDate);
|
|
460
|
+
}
|
|
461
|
+
sql += ' ORDER BY created_at DESC';
|
|
462
|
+
if (filters.limit) {
|
|
463
|
+
sql += ' LIMIT ?';
|
|
464
|
+
params.push(filters.limit);
|
|
465
|
+
if (filters.offset) {
|
|
466
|
+
sql += ' OFFSET ?';
|
|
467
|
+
params.push(filters.offset);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
471
|
+
return rows.map(row => ({
|
|
472
|
+
role: row.role,
|
|
473
|
+
content: JSON.parse(row.content),
|
|
474
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : undefined
|
|
475
|
+
}));
|
|
476
|
+
}
|
|
477
|
+
async queryToolCalls(filters) {
|
|
478
|
+
let sql = `
|
|
479
|
+
SELECT id, name, input, state, approval,
|
|
480
|
+
result, error, is_error,
|
|
481
|
+
started_at, completed_at, duration_ms,
|
|
482
|
+
created_at, updated_at, audit_trail
|
|
483
|
+
FROM tool_calls
|
|
484
|
+
WHERE 1=1
|
|
485
|
+
`;
|
|
486
|
+
const params = [];
|
|
487
|
+
if (filters.agentId) {
|
|
488
|
+
sql += ' AND agent_id = ?';
|
|
489
|
+
params.push(filters.agentId);
|
|
490
|
+
}
|
|
491
|
+
if (filters.toolName) {
|
|
492
|
+
sql += ' AND name = ?';
|
|
493
|
+
params.push(filters.toolName);
|
|
494
|
+
}
|
|
495
|
+
if (filters.state) {
|
|
496
|
+
sql += ' AND state = ?';
|
|
497
|
+
params.push(filters.state);
|
|
498
|
+
}
|
|
499
|
+
if (filters.startDate) {
|
|
500
|
+
sql += ' AND created_at >= ?';
|
|
501
|
+
params.push(filters.startDate);
|
|
502
|
+
}
|
|
503
|
+
if (filters.endDate) {
|
|
504
|
+
sql += ' AND created_at <= ?';
|
|
505
|
+
params.push(filters.endDate);
|
|
506
|
+
}
|
|
507
|
+
sql += ' ORDER BY created_at DESC';
|
|
508
|
+
if (filters.limit) {
|
|
509
|
+
sql += ' LIMIT ?';
|
|
510
|
+
params.push(filters.limit);
|
|
511
|
+
if (filters.offset) {
|
|
512
|
+
sql += ' OFFSET ?';
|
|
513
|
+
params.push(filters.offset);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
517
|
+
return rows.map(row => ({
|
|
518
|
+
id: row.id,
|
|
519
|
+
name: row.name,
|
|
520
|
+
input: JSON.parse(row.input),
|
|
521
|
+
state: row.state,
|
|
522
|
+
approval: JSON.parse(row.approval),
|
|
523
|
+
result: row.result ? JSON.parse(row.result) : undefined,
|
|
524
|
+
error: row.error || undefined,
|
|
525
|
+
isError: row.is_error === 1,
|
|
526
|
+
startedAt: row.started_at || undefined,
|
|
527
|
+
completedAt: row.completed_at || undefined,
|
|
528
|
+
durationMs: row.duration_ms || undefined,
|
|
529
|
+
createdAt: row.created_at,
|
|
530
|
+
updatedAt: row.updated_at,
|
|
531
|
+
auditTrail: JSON.parse(row.audit_trail)
|
|
532
|
+
}));
|
|
533
|
+
}
|
|
534
|
+
async aggregateStats(agentId) {
|
|
535
|
+
// Total messages
|
|
536
|
+
const messageStats = this.db.prepare(`
|
|
537
|
+
SELECT COUNT(*) as total FROM messages WHERE agent_id = ?
|
|
538
|
+
`).get(agentId);
|
|
539
|
+
// Total tool calls
|
|
540
|
+
const toolCallStats = this.db.prepare(`
|
|
541
|
+
SELECT COUNT(*) as total FROM tool_calls WHERE agent_id = ?
|
|
542
|
+
`).get(agentId);
|
|
543
|
+
// Total snapshots
|
|
544
|
+
const snapshotStats = this.db.prepare(`
|
|
545
|
+
SELECT COUNT(*) as total FROM snapshots WHERE agent_id = ?
|
|
546
|
+
`).get(agentId);
|
|
547
|
+
// Tool calls by name
|
|
548
|
+
const toolCallsByName = this.db.prepare(`
|
|
549
|
+
SELECT name, COUNT(*) as count
|
|
550
|
+
FROM tool_calls
|
|
551
|
+
WHERE agent_id = ?
|
|
552
|
+
GROUP BY name
|
|
553
|
+
`).all(agentId);
|
|
554
|
+
// Tool calls by state
|
|
555
|
+
const toolCallsByState = this.db.prepare(`
|
|
556
|
+
SELECT state, COUNT(*) as count
|
|
557
|
+
FROM tool_calls
|
|
558
|
+
WHERE agent_id = ?
|
|
559
|
+
GROUP BY state
|
|
560
|
+
`).all(agentId);
|
|
561
|
+
return {
|
|
562
|
+
totalMessages: messageStats.total,
|
|
563
|
+
totalToolCalls: toolCallStats.total,
|
|
564
|
+
totalSnapshots: snapshotStats.total,
|
|
565
|
+
avgMessagesPerSession: messageStats.total, // Single agent, so avg = total
|
|
566
|
+
toolCallsByName: toolCallsByName.reduce((acc, row) => {
|
|
567
|
+
acc[row.name] = row.count;
|
|
568
|
+
return acc;
|
|
569
|
+
}, {}),
|
|
570
|
+
toolCallsByState: toolCallsByState.reduce((acc, row) => {
|
|
571
|
+
acc[row.state] = row.count;
|
|
572
|
+
return acc;
|
|
573
|
+
}, {})
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
// ========== ExtendedStore 高级功能 ==========
|
|
577
|
+
/**
|
|
578
|
+
* 健康检查
|
|
579
|
+
*/
|
|
580
|
+
async healthCheck() {
|
|
581
|
+
const checkedAt = Date.now();
|
|
582
|
+
let dbConnected = false;
|
|
583
|
+
let dbLatencyMs;
|
|
584
|
+
let fsWritable = false;
|
|
585
|
+
// 检查数据库连接
|
|
586
|
+
try {
|
|
587
|
+
const start = Date.now();
|
|
588
|
+
this.db.prepare('SELECT 1').get();
|
|
589
|
+
dbConnected = true;
|
|
590
|
+
dbLatencyMs = Date.now() - start;
|
|
591
|
+
}
|
|
592
|
+
catch (error) {
|
|
593
|
+
dbConnected = false;
|
|
594
|
+
}
|
|
595
|
+
// 检查文件系统
|
|
596
|
+
try {
|
|
597
|
+
const baseDir = this.fileStore.baseDir;
|
|
598
|
+
// 确保目录存在
|
|
599
|
+
if (!fs.existsSync(baseDir)) {
|
|
600
|
+
fs.mkdirSync(baseDir, { recursive: true });
|
|
601
|
+
}
|
|
602
|
+
const testFile = pathModule.join(baseDir, '.health-check');
|
|
603
|
+
fs.writeFileSync(testFile, 'ok');
|
|
604
|
+
fs.unlinkSync(testFile);
|
|
605
|
+
fsWritable = true;
|
|
606
|
+
}
|
|
607
|
+
catch (error) {
|
|
608
|
+
fsWritable = false;
|
|
609
|
+
}
|
|
610
|
+
return {
|
|
611
|
+
healthy: dbConnected && fsWritable,
|
|
612
|
+
database: {
|
|
613
|
+
connected: dbConnected,
|
|
614
|
+
latencyMs: dbLatencyMs
|
|
615
|
+
},
|
|
616
|
+
fileSystem: {
|
|
617
|
+
writable: fsWritable
|
|
618
|
+
},
|
|
619
|
+
checkedAt
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* 一致性检查
|
|
624
|
+
*/
|
|
625
|
+
async checkConsistency(agentId) {
|
|
626
|
+
const issues = [];
|
|
627
|
+
const checkedAt = Date.now();
|
|
628
|
+
// 检查 Agent 是否存在于数据库
|
|
629
|
+
const dbExists = await this.exists(agentId);
|
|
630
|
+
if (!dbExists) {
|
|
631
|
+
issues.push(`Agent ${agentId} 不存在于数据库中`);
|
|
632
|
+
return { consistent: false, issues, checkedAt };
|
|
633
|
+
}
|
|
634
|
+
// 检查消息数量一致性
|
|
635
|
+
const info = await this.loadInfo(agentId);
|
|
636
|
+
const messages = await this.loadMessages(agentId);
|
|
637
|
+
if (info && info.messageCount !== messages.length) {
|
|
638
|
+
issues.push(`消息数量不一致: info.messageCount=${info.messageCount}, 实际消息数=${messages.length}`);
|
|
639
|
+
}
|
|
640
|
+
// 检查工具调用记录
|
|
641
|
+
const toolCalls = await this.loadToolCallRecords(agentId);
|
|
642
|
+
for (const call of toolCalls) {
|
|
643
|
+
if (!call.id || !call.name) {
|
|
644
|
+
issues.push(`工具调用记录缺少必要字段: ${JSON.stringify(call)}`);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return {
|
|
648
|
+
consistent: issues.length === 0,
|
|
649
|
+
issues,
|
|
650
|
+
checkedAt
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* 获取指标统计
|
|
655
|
+
*/
|
|
656
|
+
async getMetrics() {
|
|
657
|
+
// 获取存储统计
|
|
658
|
+
const agentCount = this.db.prepare('SELECT COUNT(*) as count FROM agents').get();
|
|
659
|
+
const messageCount = this.db.prepare('SELECT COUNT(*) as count FROM messages').get();
|
|
660
|
+
const toolCallCount = this.db.prepare('SELECT COUNT(*) as count FROM tool_calls').get();
|
|
661
|
+
// 获取数据库文件大小
|
|
662
|
+
let dbSizeBytes;
|
|
663
|
+
try {
|
|
664
|
+
const stats = fs.statSync(this.dbPath);
|
|
665
|
+
dbSizeBytes = stats.size;
|
|
666
|
+
}
|
|
667
|
+
catch {
|
|
668
|
+
// 忽略
|
|
669
|
+
}
|
|
670
|
+
// 计算性能指标
|
|
671
|
+
const latencies = this.metrics.latencies;
|
|
672
|
+
const avgLatencyMs = latencies.length > 0
|
|
673
|
+
? latencies.reduce((a, b) => a + b, 0) / latencies.length
|
|
674
|
+
: 0;
|
|
675
|
+
const maxLatencyMs = latencies.length > 0 ? Math.max(...latencies) : 0;
|
|
676
|
+
const minLatencyMs = latencies.length > 0 ? Math.min(...latencies) : 0;
|
|
677
|
+
return {
|
|
678
|
+
operations: {
|
|
679
|
+
saves: this.metrics.saves,
|
|
680
|
+
loads: this.metrics.loads,
|
|
681
|
+
queries: this.metrics.queries,
|
|
682
|
+
deletes: this.metrics.deletes
|
|
683
|
+
},
|
|
684
|
+
performance: {
|
|
685
|
+
avgLatencyMs,
|
|
686
|
+
maxLatencyMs,
|
|
687
|
+
minLatencyMs
|
|
688
|
+
},
|
|
689
|
+
storage: {
|
|
690
|
+
totalAgents: agentCount.count,
|
|
691
|
+
totalMessages: messageCount.count,
|
|
692
|
+
totalToolCalls: toolCallCount.count,
|
|
693
|
+
dbSizeBytes
|
|
694
|
+
},
|
|
695
|
+
collectedAt: Date.now()
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* 获取分布式锁
|
|
700
|
+
* SQLite 使用内存锁(仅单进程有效)
|
|
701
|
+
* 注意:对于多进程场景,建议使用 PostgreSQL
|
|
702
|
+
*/
|
|
703
|
+
async acquireAgentLock(agentId, timeoutMs = 30000) {
|
|
704
|
+
// 检查是否已有锁
|
|
705
|
+
if (this.locks.has(agentId)) {
|
|
706
|
+
throw new Error(`无法获取 Agent ${agentId} 的锁,已被当前进程占用`);
|
|
707
|
+
}
|
|
708
|
+
// 创建锁
|
|
709
|
+
let resolveRelease;
|
|
710
|
+
const lockPromise = new Promise(resolve => {
|
|
711
|
+
resolveRelease = resolve;
|
|
712
|
+
});
|
|
713
|
+
const timeoutId = setTimeout(() => {
|
|
714
|
+
this.locks.delete(agentId);
|
|
715
|
+
resolveRelease();
|
|
716
|
+
}, timeoutMs);
|
|
717
|
+
this.locks.set(agentId, { resolve: resolveRelease, timeout: timeoutId });
|
|
718
|
+
// 返回释放函数
|
|
719
|
+
return async () => {
|
|
720
|
+
const lock = this.locks.get(agentId);
|
|
721
|
+
if (lock) {
|
|
722
|
+
clearTimeout(lock.timeout);
|
|
723
|
+
this.locks.delete(agentId);
|
|
724
|
+
lock.resolve();
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* 批量 Fork Agent
|
|
730
|
+
*/
|
|
731
|
+
async batchFork(agentId, count) {
|
|
732
|
+
// 加载源 Agent 数据
|
|
733
|
+
const sourceInfo = await this.loadInfo(agentId);
|
|
734
|
+
if (!sourceInfo) {
|
|
735
|
+
throw new Error(`源 Agent ${agentId} 不存在`);
|
|
736
|
+
}
|
|
737
|
+
const sourceMessages = await this.loadMessages(agentId);
|
|
738
|
+
const sourceToolCalls = await this.loadToolCallRecords(agentId);
|
|
739
|
+
const newAgentIds = [];
|
|
740
|
+
// 使用事务批量创建
|
|
741
|
+
const transaction = this.db.transaction(() => {
|
|
742
|
+
for (let i = 0; i < count; i++) {
|
|
743
|
+
const newAgentId = this.generateAgentId();
|
|
744
|
+
newAgentIds.push(newAgentId);
|
|
745
|
+
// 创建新 Agent Info
|
|
746
|
+
const newInfo = {
|
|
747
|
+
...sourceInfo,
|
|
748
|
+
agentId: newAgentId,
|
|
749
|
+
createdAt: new Date().toISOString(),
|
|
750
|
+
lineage: [...sourceInfo.lineage, agentId]
|
|
751
|
+
};
|
|
752
|
+
// 插入 Agent Info
|
|
753
|
+
this.db.prepare(`
|
|
754
|
+
INSERT INTO agents (
|
|
755
|
+
agent_id, template_id, created_at, config_version,
|
|
756
|
+
lineage, message_count, last_sfp_index, last_bookmark,
|
|
757
|
+
breakpoint, metadata
|
|
758
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
759
|
+
`).run(newInfo.agentId, newInfo.templateId, newInfo.createdAt, newInfo.configVersion, JSON.stringify(newInfo.lineage), newInfo.messageCount, newInfo.lastSfpIndex, newInfo.lastBookmark ? JSON.stringify(newInfo.lastBookmark) : null, newInfo.breakpoint || null, JSON.stringify(newInfo.metadata));
|
|
760
|
+
// 复制消息
|
|
761
|
+
for (let index = 0; index < sourceMessages.length; index++) {
|
|
762
|
+
const msg = sourceMessages[index];
|
|
763
|
+
this.db.prepare(`
|
|
764
|
+
INSERT INTO messages (
|
|
765
|
+
id, agent_id, role, content, seq, metadata, created_at
|
|
766
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
767
|
+
`).run(this.generateMessageId(), newAgentId, msg.role, JSON.stringify(msg.content), index, msg.metadata ? JSON.stringify(msg.metadata) : null, Date.now());
|
|
768
|
+
}
|
|
769
|
+
// 复制工具调用记录
|
|
770
|
+
for (const record of sourceToolCalls) {
|
|
771
|
+
this.db.prepare(`
|
|
772
|
+
INSERT INTO tool_calls (
|
|
773
|
+
id, agent_id, name, input, state, approval,
|
|
774
|
+
result, error, is_error,
|
|
775
|
+
started_at, completed_at, duration_ms,
|
|
776
|
+
created_at, updated_at, audit_trail
|
|
777
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
778
|
+
`).run(`${record.id}_fork_${i}`, newAgentId, record.name, JSON.stringify(record.input), record.state, JSON.stringify(record.approval), record.result ? JSON.stringify(record.result) : null, record.error || null, record.isError ? 1 : 0, record.startedAt || null, record.completedAt || null, record.durationMs || null, record.createdAt, record.updatedAt, JSON.stringify(record.auditTrail));
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
transaction();
|
|
783
|
+
return newAgentIds;
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* 关闭数据库连接
|
|
787
|
+
*/
|
|
788
|
+
async close() {
|
|
789
|
+
this.db.close();
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* 生成 Agent ID
|
|
793
|
+
*/
|
|
794
|
+
generateAgentId() {
|
|
795
|
+
const timestamp = Date.now().toString(36);
|
|
796
|
+
const random = Math.random().toString(36).substring(2, 18);
|
|
797
|
+
return `agt-${timestamp}${random}`;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
exports.SqliteStore = SqliteStore;
|