codesesh 1.0.8 → 1.0.10
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/README.md +19 -0
- package/dist/{chunk-YLXHGL4S.js → chunk-2LXZFMSH.js} +28 -2
- package/dist/{chunk-YLXHGL4S.js.map → chunk-2LXZFMSH.js.map} +1 -1
- package/dist/{chunk-L4G3LE7I.js → chunk-543OWZIC.js} +2 -2
- package/dist/{chunk-DHQPM5FF.js → chunk-56FKVL5K.js} +5 -5
- package/dist/{chunk-V3HKVTIO.js → chunk-CYZ6OC6J.js} +2 -2
- package/dist/{chunk-KVTLNX7V.js → chunk-DWY4HWVI.js} +2 -2
- package/dist/{chunk-AGUAXTKC.js → chunk-R6QKSHPH.js} +2 -2
- package/dist/{chunk-RBCCNCDO.js → chunk-WRVILHZR.js} +1059 -26
- package/dist/chunk-WRVILHZR.js.map +1 -0
- package/dist/{discovery-KEZQU6RL.js → discovery-NTMSA6UE.js} +5 -5
- package/dist/index.js +36 -9
- package/dist/index.js.map +1 -1
- package/dist/project-identity-worker.js +4 -4
- package/dist/scan-refresh-worker.js +6 -6
- package/dist/search-index-worker.js +6 -6
- package/dist/session-detail-worker.js +6 -6
- package/dist/smart-tag-worker.js +3 -3
- package/dist/web/assets/CustomTimeWindowDialog-CGPvUFkc.js +1 -0
- package/dist/web/assets/DetailLanding-D1FLK4EW.js +1 -0
- package/dist/web/assets/{InteractiveReceipt-Bsj37HtN.js → InteractiveReceipt-C7FJhzdv.js} +1 -1
- package/dist/web/assets/OverviewScreen-DX7F_6dH.js +1 -0
- package/dist/web/assets/{PrismHighlighter-DWS6Nx_X.js → PrismHighlighter-DZ2CWVc0.js} +1 -1
- package/dist/web/assets/Projects-B_7w5TDw.js +1 -0
- package/dist/web/assets/{SearchResultsPanel-BAManMmt.js → SearchResultsPanel-BMBhKuPS.js} +1 -1
- package/dist/web/assets/SessionDetail-wJYzzF0i.js +53 -0
- package/dist/web/assets/index-BXhaumu7.css +1 -0
- package/dist/web/assets/index-DUcpWdzX.js +1423 -0
- package/dist/web/assets/{panel-DcOuALYX.js → panel-B-5dVddJ.js} +1 -1
- package/dist/web/assets/session-indexes-3LjxBYNe.js +4 -0
- package/dist/web/assets/utils-BuYa9y6l.js +1 -0
- package/dist/web/icon/agent/cherrystudio.svg +7 -0
- package/dist/web/icon/agent/deepchat.LICENSE.txt +206 -0
- package/dist/web/icon/agent/deepchat.svg +6 -0
- package/dist/web/icon/agent/minimax-code.svg +1 -0
- package/dist/web/index.html +5 -192
- package/package.json +3 -3
- package/dist/chunk-RBCCNCDO.js.map +0 -1
- package/dist/web/assets/CustomTimeWindowDialog-z5xtqkBF.js +0 -1
- package/dist/web/assets/DetailLanding-CpV0jLmT.js +0 -1
- package/dist/web/assets/OverviewScreen-B9qZqEQA.js +0 -1
- package/dist/web/assets/Projects-oY3KCgS4.js +0 -1
- package/dist/web/assets/SessionDetail-KSgkmLV7.js +0 -53
- package/dist/web/assets/index-BSLHxV0w.css +0 -1
- package/dist/web/assets/index-DNw59Qsn.js +0 -1423
- package/dist/web/assets/session-indexes-DKukxoe1.js +0 -4
- package/dist/web/assets/utils-Dk_44zMo.js +0 -1
- /package/dist/{chunk-L4G3LE7I.js.map → chunk-543OWZIC.js.map} +0 -0
- /package/dist/{chunk-DHQPM5FF.js.map → chunk-56FKVL5K.js.map} +0 -0
- /package/dist/{chunk-V3HKVTIO.js.map → chunk-CYZ6OC6J.js.map} +0 -0
- /package/dist/{chunk-KVTLNX7V.js.map → chunk-DWY4HWVI.js.map} +0 -0
- /package/dist/{chunk-AGUAXTKC.js.map → chunk-R6QKSHPH.js.map} +0 -0
- /package/dist/{discovery-KEZQU6RL.js.map → discovery-NTMSA6UE.js.map} +0 -0
|
@@ -32,14 +32,14 @@ import {
|
|
|
32
32
|
reportFieldMismatch,
|
|
33
33
|
resolveSessionTitle,
|
|
34
34
|
safeParseJsonRecord
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-2LXZFMSH.js";
|
|
36
36
|
|
|
37
|
-
// ../core/dist/chunk-
|
|
37
|
+
// ../core/dist/chunk-XW3NUJH2.mjs
|
|
38
38
|
import { statSync } from "fs";
|
|
39
39
|
import { readdirSync, statSync as statSync2 } from "fs";
|
|
40
40
|
import { join } from "path";
|
|
41
41
|
import { existsSync as existsSync2, readFileSync, statSync as statSync3 } from "fs";
|
|
42
|
-
import { join as join3, basename, dirname } from "path";
|
|
42
|
+
import { join as join3, basename, dirname, isAbsolute as isAbsolute2, relative, sep } from "path";
|
|
43
43
|
import { existsSync } from "fs";
|
|
44
44
|
import { homedir, platform } from "os";
|
|
45
45
|
import { isAbsolute, join as join2, resolve } from "path";
|
|
@@ -68,6 +68,15 @@ import * as zlib from "zlib";
|
|
|
68
68
|
import { createHash as createHash2 } from "crypto";
|
|
69
69
|
import { readFileSync as readFileSync8 } from "fs";
|
|
70
70
|
import { join as join13 } from "path";
|
|
71
|
+
import { createHash as createHash3 } from "crypto";
|
|
72
|
+
import { homedir as homedir4, platform as platform4 } from "os";
|
|
73
|
+
import { join as join15 } from "path";
|
|
74
|
+
import { createHash as createHash4 } from "crypto";
|
|
75
|
+
import { homedir as homedir5, platform as platform5 } from "os";
|
|
76
|
+
import { join as join16 } from "path";
|
|
77
|
+
import { createHash as createHash5 } from "crypto";
|
|
78
|
+
import { homedir as homedir6 } from "os";
|
|
79
|
+
import { join as join17 } from "path";
|
|
71
80
|
function fingerprintMatches(ref, cached) {
|
|
72
81
|
return typeof cached?.sourceFingerprint === "string" && cached.sourceFingerprint === ref.fingerprint;
|
|
73
82
|
}
|
|
@@ -913,9 +922,9 @@ var ClaudeRecordConverter = class {
|
|
|
913
922
|
if (partType !== "tool_use") continue;
|
|
914
923
|
const toolCallId = String(part["id"] ?? "").trim();
|
|
915
924
|
const subagentId = childSessionIdByToolUseId.get(toolCallId);
|
|
916
|
-
const
|
|
925
|
+
const toolPart3 = this.buildToolPart(part, timestampMs);
|
|
917
926
|
const message = builder.appendToolCall(
|
|
918
|
-
|
|
927
|
+
toolPart3,
|
|
919
928
|
{ id: uuid, timestampMs, agent: "claude", subagentId, model },
|
|
920
929
|
{ modeOnCreate: "tool" }
|
|
921
930
|
);
|
|
@@ -1423,6 +1432,16 @@ var ClaudeCodeAgent = class extends SingleFileSessionSource {
|
|
|
1423
1432
|
}
|
|
1424
1433
|
return false;
|
|
1425
1434
|
}
|
|
1435
|
+
filterCachedSessions(sessions) {
|
|
1436
|
+
const basePath = this.basePath ?? this.findBasePath();
|
|
1437
|
+
if (!basePath) return sessions;
|
|
1438
|
+
return sessions.filter((session) => {
|
|
1439
|
+
const sourcePath = this.sessionMetaMap.get(session.reference.sessionId)?.sourcePath;
|
|
1440
|
+
if (!sourcePath) return true;
|
|
1441
|
+
const path = relative(basePath, sourcePath);
|
|
1442
|
+
return path !== ".." && !path.startsWith(`..${sep}`) && !isAbsolute2(path);
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1426
1445
|
listSessionSources(options) {
|
|
1427
1446
|
if (!this.basePath) return [];
|
|
1428
1447
|
const projectDirs = this.listProjectDirs();
|
|
@@ -2421,12 +2440,12 @@ var KimiUsageAccumulator = class {
|
|
|
2421
2440
|
totalCost = 0;
|
|
2422
2441
|
applyContextRecord(record) {
|
|
2423
2442
|
if (record.role !== "_usage") return;
|
|
2424
|
-
const
|
|
2425
|
-
if (
|
|
2443
|
+
const tokenCount3 = asNumber(record.token_count);
|
|
2444
|
+
if (tokenCount3 === void 0) {
|
|
2426
2445
|
reportFieldMismatch("kimi", "usage.token_count");
|
|
2427
2446
|
return;
|
|
2428
2447
|
}
|
|
2429
|
-
this.stats.total_tokens =
|
|
2448
|
+
this.stats.total_tokens = tokenCount3;
|
|
2430
2449
|
}
|
|
2431
2450
|
applyWireRecord(record) {
|
|
2432
2451
|
if (this.usesWireTotalFallback) this.applyContextRecord(record);
|
|
@@ -2843,7 +2862,7 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2843
2862
|
const rawArgs = function_.arguments;
|
|
2844
2863
|
const normalizedArgs = normalizeToolArguments(rawArgs);
|
|
2845
2864
|
const buffer = typeof rawArgs === "string" && typeof normalizedArgs !== "string" ? rawArgs : null;
|
|
2846
|
-
const
|
|
2865
|
+
const toolPart3 = {
|
|
2847
2866
|
type: "tool",
|
|
2848
2867
|
tool: toolName,
|
|
2849
2868
|
callID: callId,
|
|
@@ -2852,7 +2871,7 @@ var KimiAgent = class extends FileSystemSessionSource {
|
|
|
2852
2871
|
time_created: timestampMs
|
|
2853
2872
|
};
|
|
2854
2873
|
builder.appendToolCall(
|
|
2855
|
-
|
|
2874
|
+
toolPart3,
|
|
2856
2875
|
{ id: `wire-${seq}`, timestampMs, agent: "kimi" },
|
|
2857
2876
|
{ markModeAsTool: true, target: "current" }
|
|
2858
2877
|
);
|
|
@@ -4176,7 +4195,7 @@ var CodexRecordConverter = class {
|
|
|
4176
4195
|
if (!name) return;
|
|
4177
4196
|
const toolIdentity = resolveToolIdentity(name, payload["namespace"]);
|
|
4178
4197
|
const arguments_ = normalizeToolArguments(payload["arguments"]);
|
|
4179
|
-
const
|
|
4198
|
+
const toolPart3 = {
|
|
4180
4199
|
type: "tool",
|
|
4181
4200
|
tool: toolIdentity.tool,
|
|
4182
4201
|
callID: callId,
|
|
@@ -4190,7 +4209,7 @@ var CodexRecordConverter = class {
|
|
|
4190
4209
|
time_created: timestampMs
|
|
4191
4210
|
};
|
|
4192
4211
|
transcript.appendToolCall(
|
|
4193
|
-
|
|
4212
|
+
toolPart3,
|
|
4194
4213
|
{ id: "", timestampMs, agent: "codex", model: activeModel },
|
|
4195
4214
|
{ markModeAsTool: true }
|
|
4196
4215
|
);
|
|
@@ -4222,7 +4241,7 @@ var CodexRecordConverter = class {
|
|
|
4222
4241
|
const toolIdentity = resolveToolIdentity(name, payload["namespace"]);
|
|
4223
4242
|
const rawInput = payload["input"];
|
|
4224
4243
|
const normalizedInput = normalizeCustomToolArguments(name, rawInput);
|
|
4225
|
-
const
|
|
4244
|
+
const toolPart3 = {
|
|
4226
4245
|
type: "tool",
|
|
4227
4246
|
tool: toolIdentity.tool,
|
|
4228
4247
|
callID: callId,
|
|
@@ -4236,7 +4255,7 @@ var CodexRecordConverter = class {
|
|
|
4236
4255
|
time_created: timestampMs
|
|
4237
4256
|
};
|
|
4238
4257
|
transcript.appendToolCall(
|
|
4239
|
-
|
|
4258
|
+
toolPart3,
|
|
4240
4259
|
{ id: "", timestampMs, agent: "codex", model: activeModel },
|
|
4241
4260
|
{ markModeAsTool: true }
|
|
4242
4261
|
);
|
|
@@ -4253,7 +4272,7 @@ var CodexRecordConverter = class {
|
|
|
4253
4272
|
const { name, namespace } = splitExecToolName(call.name);
|
|
4254
4273
|
const toolIdentity = resolveToolIdentity(name, namespace);
|
|
4255
4274
|
const arguments_ = name === "apply_patch" ? parseApplyPatchInput(getExecPatchText(call.args)) : call.args;
|
|
4256
|
-
const
|
|
4275
|
+
const toolPart3 = {
|
|
4257
4276
|
type: "tool",
|
|
4258
4277
|
tool: toolIdentity.tool,
|
|
4259
4278
|
callID: callId,
|
|
@@ -4267,7 +4286,7 @@ var CodexRecordConverter = class {
|
|
|
4267
4286
|
time_created: timestampMs
|
|
4268
4287
|
};
|
|
4269
4288
|
transcript.appendToolCall(
|
|
4270
|
-
|
|
4289
|
+
toolPart3,
|
|
4271
4290
|
{ id: "", timestampMs, agent: "codex", model: activeModel },
|
|
4272
4291
|
{ markModeAsTool: true }
|
|
4273
4292
|
);
|
|
@@ -5109,7 +5128,7 @@ function parseBubbleRow(value) {
|
|
|
5109
5128
|
const record = safeParseJsonRecord(value);
|
|
5110
5129
|
if (!record) return null;
|
|
5111
5130
|
const timingInfo = asRecord(record.timingInfo);
|
|
5112
|
-
const
|
|
5131
|
+
const tokenCount3 = asRecord(record.tokenCount);
|
|
5113
5132
|
const modelInfo = asRecord(record.modelInfo);
|
|
5114
5133
|
const toolFormerData = asRecord(record.toolFormerData);
|
|
5115
5134
|
return {
|
|
@@ -5133,9 +5152,9 @@ function parseBubbleRow(value) {
|
|
|
5133
5152
|
),
|
|
5134
5153
|
clientEndTime: narrowNumber("bubble.timingInfo.clientEndTime", timingInfo.clientEndTime)
|
|
5135
5154
|
} : void 0,
|
|
5136
|
-
tokenCount:
|
|
5137
|
-
inputTokens: narrowNumber("bubble.tokenCount.inputTokens",
|
|
5138
|
-
outputTokens: narrowNumber("bubble.tokenCount.outputTokens",
|
|
5155
|
+
tokenCount: tokenCount3 ? {
|
|
5156
|
+
inputTokens: narrowNumber("bubble.tokenCount.inputTokens", tokenCount3.inputTokens),
|
|
5157
|
+
outputTokens: narrowNumber("bubble.tokenCount.outputTokens", tokenCount3.outputTokens)
|
|
5139
5158
|
} : void 0,
|
|
5140
5159
|
modelInfo: modelInfo ? { modelName: narrowString("bubble.modelInfo.modelName", modelInfo.modelName) } : void 0,
|
|
5141
5160
|
toolFormerData: toolFormerData ? {
|
|
@@ -5717,9 +5736,9 @@ var CursorAgent = class extends DatabaseSessionSource {
|
|
|
5717
5736
|
parts.push({ type: "text", text, time_created: timestampMs });
|
|
5718
5737
|
}
|
|
5719
5738
|
if (bubble.toolFormerData) {
|
|
5720
|
-
const
|
|
5721
|
-
if (
|
|
5722
|
-
parts.push(
|
|
5739
|
+
const toolPart3 = this.convertToolFormerData(bubble.toolFormerData, timestampMs);
|
|
5740
|
+
if (toolPart3) {
|
|
5741
|
+
parts.push(toolPart3);
|
|
5723
5742
|
}
|
|
5724
5743
|
}
|
|
5725
5744
|
if (parts.length === 0) continue;
|
|
@@ -6193,7 +6212,7 @@ var PiAgent = class extends SingleFileSessionSource {
|
|
|
6193
6212
|
if (type === "toolCall") {
|
|
6194
6213
|
const callId = String(item["id"] ?? "").trim();
|
|
6195
6214
|
const toolName = String(item["name"] ?? "").trim() || "tool";
|
|
6196
|
-
const
|
|
6215
|
+
const toolPart3 = {
|
|
6197
6216
|
type: "tool",
|
|
6198
6217
|
tool: toolName,
|
|
6199
6218
|
title: `Tool: ${toolName}`,
|
|
@@ -6204,7 +6223,7 @@ var PiAgent = class extends SingleFileSessionSource {
|
|
|
6204
6223
|
input: item["arguments"] ?? {}
|
|
6205
6224
|
}
|
|
6206
6225
|
};
|
|
6207
|
-
parts.push(
|
|
6226
|
+
parts.push(toolPart3);
|
|
6208
6227
|
}
|
|
6209
6228
|
}
|
|
6210
6229
|
return parts;
|
|
@@ -8305,7 +8324,1013 @@ function isMissingDirectory(error) {
|
|
|
8305
8324
|
const code = error.code;
|
|
8306
8325
|
return code === "ENOENT" || code === "ENOTDIR";
|
|
8307
8326
|
}
|
|
8327
|
+
function parseDeepChatJson(value) {
|
|
8328
|
+
if (typeof value !== "string") return value;
|
|
8329
|
+
try {
|
|
8330
|
+
return JSON.parse(value);
|
|
8331
|
+
} catch {
|
|
8332
|
+
return value;
|
|
8333
|
+
}
|
|
8334
|
+
}
|
|
8335
|
+
function deepChatTokens(metadata) {
|
|
8336
|
+
const input = asNumber(metadata.inputTokens);
|
|
8337
|
+
const output = asNumber(metadata.outputTokens);
|
|
8338
|
+
if (input === void 0 && output === void 0) return void 0;
|
|
8339
|
+
const cacheRead = Math.max(0, asNumber(metadata.cachedInputTokens) ?? 0);
|
|
8340
|
+
const cacheCreate = Math.max(0, asNumber(metadata.cacheWriteInputTokens) ?? 0);
|
|
8341
|
+
return {
|
|
8342
|
+
input: Math.max(0, input ?? 0),
|
|
8343
|
+
output: Math.max(0, output ?? 0),
|
|
8344
|
+
cache_read: Math.min(cacheRead, Math.max(0, input ?? 0)),
|
|
8345
|
+
cache_create: Math.min(cacheCreate, Math.max(0, (input ?? 0) - cacheRead))
|
|
8346
|
+
};
|
|
8347
|
+
}
|
|
8348
|
+
function deepChatAssistantPart(block) {
|
|
8349
|
+
const time_created = asNumber(block.timestamp);
|
|
8350
|
+
const content = asString(block.content);
|
|
8351
|
+
if (block.type === "tool_call") {
|
|
8352
|
+
const tool = asRecord(block.tool_call);
|
|
8353
|
+
if (!tool) return null;
|
|
8354
|
+
const status = block.status === "pending" || block.status === "loading" ? "running" : block.status === "error" || block.status === "denied" ? "error" : "completed";
|
|
8355
|
+
const output = parseDeepChatJson(tool.response);
|
|
8356
|
+
return {
|
|
8357
|
+
type: "tool",
|
|
8358
|
+
tool: asString(tool.name) ?? "unknown",
|
|
8359
|
+
callID: asString(tool.id),
|
|
8360
|
+
time_created,
|
|
8361
|
+
state: {
|
|
8362
|
+
status,
|
|
8363
|
+
input: parseDeepChatJson(tool.params),
|
|
8364
|
+
output,
|
|
8365
|
+
error: status === "error" ? output ?? content : void 0,
|
|
8366
|
+
metadata: asRecord(block.extra)
|
|
8367
|
+
}
|
|
8368
|
+
};
|
|
8369
|
+
}
|
|
8370
|
+
if (block.type === "image") {
|
|
8371
|
+
const image = asRecord(block.image_data);
|
|
8372
|
+
const data = asString(image?.data);
|
|
8373
|
+
const mime = asString(image?.mimeType);
|
|
8374
|
+
if (data && mime) return { type: "image", data, mime_type: mime, time_created };
|
|
8375
|
+
}
|
|
8376
|
+
if (!content) return null;
|
|
8377
|
+
return {
|
|
8378
|
+
type: block.type === "reasoning_content" ? "reasoning" : "text",
|
|
8379
|
+
text: content,
|
|
8380
|
+
time_created
|
|
8381
|
+
};
|
|
8382
|
+
}
|
|
8383
|
+
function deepChatStoredBlockPart(row) {
|
|
8384
|
+
const extra = asRecord(parseDeepChatJson(row.extra_json));
|
|
8385
|
+
return deepChatAssistantPart({
|
|
8386
|
+
type: row.block_type,
|
|
8387
|
+
content: row.text_content,
|
|
8388
|
+
status: row.status,
|
|
8389
|
+
timestamp: extra?.timestamp ?? row.updated_at,
|
|
8390
|
+
extra: extra?.extra,
|
|
8391
|
+
tool_call: {
|
|
8392
|
+
id: row.tool_call_id,
|
|
8393
|
+
name: row.tool_name,
|
|
8394
|
+
params: row.tool_params,
|
|
8395
|
+
response: row.tool_response
|
|
8396
|
+
},
|
|
8397
|
+
image_data: { data: extra?.imageData, mimeType: row.image_mime_type }
|
|
8398
|
+
});
|
|
8399
|
+
}
|
|
8400
|
+
function deepChatUserParts(content) {
|
|
8401
|
+
const parts = [];
|
|
8402
|
+
const text = asString(content.text);
|
|
8403
|
+
if (text) parts.push({ type: "text", text });
|
|
8404
|
+
for (const file of asArray(content.files) ?? []) {
|
|
8405
|
+
const record = asRecord(file);
|
|
8406
|
+
const path = asString(record?.path);
|
|
8407
|
+
const name = asString(record?.name);
|
|
8408
|
+
if (path || name) parts.push({ type: "text", text: `Attachment: ${path ?? name}` });
|
|
8409
|
+
}
|
|
8410
|
+
for (const link of asArray(content.links) ?? []) {
|
|
8411
|
+
if (typeof link === "string") parts.push({ type: "text", text: link });
|
|
8412
|
+
}
|
|
8413
|
+
return parts;
|
|
8414
|
+
}
|
|
8415
|
+
function deepChatRawParts(role, content) {
|
|
8416
|
+
const parsed = parseDeepChatJson(content);
|
|
8417
|
+
if (role === "user") {
|
|
8418
|
+
const user = asRecord(parsed);
|
|
8419
|
+
if (user) return deepChatUserParts(user);
|
|
8420
|
+
}
|
|
8421
|
+
if (Array.isArray(parsed)) {
|
|
8422
|
+
const parts = [];
|
|
8423
|
+
for (const value of parsed) {
|
|
8424
|
+
const block = asRecord(value);
|
|
8425
|
+
const part = block ? deepChatAssistantPart(block) : null;
|
|
8426
|
+
if (part) parts.push(part);
|
|
8427
|
+
}
|
|
8428
|
+
return parts;
|
|
8429
|
+
}
|
|
8430
|
+
return typeof parsed === "string" && parsed ? [{ type: "text", text: parsed }] : [];
|
|
8431
|
+
}
|
|
8432
|
+
var AGENT_METADATA11 = getAgentCatalogEntry("deepchat");
|
|
8433
|
+
function resolveDeepChatDataRoot() {
|
|
8434
|
+
const configured = readEnvPath("DEEPCHAT_USER_DATA_DIR");
|
|
8435
|
+
if (configured) return configured;
|
|
8436
|
+
if (platform4() === "darwin") return join15(homedir4(), "Library", "Application Support", "DeepChat");
|
|
8437
|
+
if (platform4() === "win32") {
|
|
8438
|
+
return join15(readEnvPath("APPDATA") ?? join15(homedir4(), "AppData", "Roaming"), "DeepChat");
|
|
8439
|
+
}
|
|
8440
|
+
return join15(readEnvPath("XDG_CONFIG_HOME") ?? join15(homedir4(), ".config"), "DeepChat");
|
|
8441
|
+
}
|
|
8442
|
+
function accumulateUsage(session, row) {
|
|
8443
|
+
const model = asString(row.model) ?? session.model;
|
|
8444
|
+
const provider = asString(row.provider) ?? session.provider;
|
|
8445
|
+
const tokens = deepChatTokens(row);
|
|
8446
|
+
if (!tokens && asNumber(row.totalTokens) === void 0) return;
|
|
8447
|
+
const input = tokens?.input ?? 0;
|
|
8448
|
+
const output = tokens?.output ?? 0;
|
|
8449
|
+
const total = Math.max(0, asNumber(row.totalTokens) ?? input + output);
|
|
8450
|
+
const { result: estimate, unpricedModels } = capturePricingMisses(
|
|
8451
|
+
() => estimateTokenCost(model, tokens)
|
|
8452
|
+
);
|
|
8453
|
+
for (const missing of unpricedModels) session.unpricedModels.add(missing);
|
|
8454
|
+
const cost = estimate ?? 0;
|
|
8455
|
+
const stats = session.head.stats;
|
|
8456
|
+
stats.total_input_tokens += input;
|
|
8457
|
+
stats.total_output_tokens += output;
|
|
8458
|
+
stats.total_tokens = (stats.total_tokens ?? 0) + total;
|
|
8459
|
+
stats.total_cache_read_tokens = (stats.total_cache_read_tokens ?? 0) + (tokens?.cache_read ?? 0);
|
|
8460
|
+
stats.total_cache_create_tokens = (stats.total_cache_create_tokens ?? 0) + (tokens?.cache_create ?? 0);
|
|
8461
|
+
stats.total_cost += cost;
|
|
8462
|
+
if (cost > 0) stats.cost_source = "estimated";
|
|
8463
|
+
if (model && total > 0) {
|
|
8464
|
+
const usage = session.head.model_usage ??= /* @__PURE__ */ Object.create(null);
|
|
8465
|
+
usage[model] = (usage[model] ?? 0) + total;
|
|
8466
|
+
}
|
|
8467
|
+
const messageId = asString(row.message_id);
|
|
8468
|
+
if (!messageId) return;
|
|
8469
|
+
const previous = session.messageUsage.get(messageId);
|
|
8470
|
+
session.messageUsage.set(messageId, {
|
|
8471
|
+
model,
|
|
8472
|
+
provider,
|
|
8473
|
+
cost: (previous?.cost ?? 0) + cost,
|
|
8474
|
+
tokens: {
|
|
8475
|
+
input: (previous?.tokens.input ?? 0) + input,
|
|
8476
|
+
output: (previous?.tokens.output ?? 0) + output,
|
|
8477
|
+
cache_read: (previous?.tokens.cache_read ?? 0) + (tokens?.cache_read ?? 0),
|
|
8478
|
+
cache_create: (previous?.tokens.cache_create ?? 0) + (tokens?.cache_create ?? 0)
|
|
8479
|
+
}
|
|
8480
|
+
});
|
|
8481
|
+
}
|
|
8482
|
+
var DeepChatAgent = class extends DatabaseSessionSource {
|
|
8483
|
+
name = AGENT_METADATA11.name;
|
|
8484
|
+
displayName = AGENT_METADATA11.displayName;
|
|
8485
|
+
sourceRoot;
|
|
8486
|
+
constructor(options = {}) {
|
|
8487
|
+
super();
|
|
8488
|
+
this.sourceRoot = options.sourceRoot ?? resolveDeepChatDataRoot();
|
|
8489
|
+
}
|
|
8490
|
+
getDatabasePath() {
|
|
8491
|
+
return firstExisting(join15(this.sourceRoot, "app_db", "agent.db"));
|
|
8492
|
+
}
|
|
8493
|
+
isAvailable() {
|
|
8494
|
+
return isSqliteAvailable() && this.getDatabasePath() !== null;
|
|
8495
|
+
}
|
|
8496
|
+
getSessionWatchPlan() {
|
|
8497
|
+
return {
|
|
8498
|
+
status: "supported",
|
|
8499
|
+
targets: [{ root: this.sourceRoot, path: join15(this.sourceRoot, "app_db", "agent.db") }]
|
|
8500
|
+
};
|
|
8501
|
+
}
|
|
8502
|
+
readDatabase(read) {
|
|
8503
|
+
const path = this.getDatabasePath();
|
|
8504
|
+
if (!path) throw new Error("DeepChat agent.db is missing");
|
|
8505
|
+
return this.scanStep("reading unencrypted DeepChat agent.db", path, () => {
|
|
8506
|
+
const db = openDbReadOnly(path);
|
|
8507
|
+
if (!db)
|
|
8508
|
+
throw new Error("Cannot open DeepChat agent.db; only unencrypted databases are supported");
|
|
8509
|
+
try {
|
|
8510
|
+
return db.transaction(() => read(db))();
|
|
8511
|
+
} finally {
|
|
8512
|
+
db.close();
|
|
8513
|
+
}
|
|
8514
|
+
});
|
|
8515
|
+
}
|
|
8516
|
+
scan(options) {
|
|
8517
|
+
if (!this.getDatabasePath()) return [];
|
|
8518
|
+
return this.readDatabase((db) => {
|
|
8519
|
+
const projections = this.readProjections(db);
|
|
8520
|
+
const selected = /* @__PURE__ */ new Set();
|
|
8521
|
+
const children = /* @__PURE__ */ new Map();
|
|
8522
|
+
for (const [id, projection] of projections) {
|
|
8523
|
+
const parent = projection.head.parent_reference?.sessionId;
|
|
8524
|
+
if (parent && projections.has(parent)) {
|
|
8525
|
+
const siblings = children.get(parent) ?? [];
|
|
8526
|
+
siblings.push(id);
|
|
8527
|
+
children.set(parent, siblings);
|
|
8528
|
+
} else if (matchesScanWindow(projection.head.time_updated ?? projection.head.time_created, options)) {
|
|
8529
|
+
selected.add(id);
|
|
8530
|
+
}
|
|
8531
|
+
}
|
|
8532
|
+
if (options?.includeRelatedSessions !== false) {
|
|
8533
|
+
for (const id of selected) {
|
|
8534
|
+
for (const child of children.get(id) ?? []) selected.add(child);
|
|
8535
|
+
}
|
|
8536
|
+
}
|
|
8537
|
+
const sessions = [];
|
|
8538
|
+
for (const id of selected) {
|
|
8539
|
+
const projection = projections.get(id);
|
|
8540
|
+
if (projection.head.stats.message_count === 0) continue;
|
|
8541
|
+
this.rememberSession(id, {
|
|
8542
|
+
sourceFingerprint: projection.signature.digest("hex"),
|
|
8543
|
+
headParserVersion: "deepchat-v1",
|
|
8544
|
+
unpricedModels: [...projection.unpricedModels]
|
|
8545
|
+
});
|
|
8546
|
+
sessions.push(projection.head);
|
|
8547
|
+
}
|
|
8548
|
+
sessions.sort(
|
|
8549
|
+
(left, right) => (right.time_updated ?? 0) - (left.time_updated ?? 0) || left.reference.sessionId.localeCompare(right.reference.sessionId)
|
|
8550
|
+
);
|
|
8551
|
+
options?.onProgress?.({
|
|
8552
|
+
total: selected.size,
|
|
8553
|
+
processed: selected.size,
|
|
8554
|
+
sessions: sessions.length
|
|
8555
|
+
});
|
|
8556
|
+
return sessions;
|
|
8557
|
+
});
|
|
8558
|
+
}
|
|
8559
|
+
readProjections(db, sessionId) {
|
|
8560
|
+
const filter = sessionId ? "AND s.id = ?" : "";
|
|
8561
|
+
const bindings = sessionId ? [sessionId] : [];
|
|
8562
|
+
const projections = /* @__PURE__ */ new Map();
|
|
8563
|
+
const sessions = db.prepare(`
|
|
8564
|
+
SELECT s.id, s.agent_id, s.title, s.project_dir, s.parent_session_id,
|
|
8565
|
+
s.created_at, s.updated_at, s.revision, d.model_id, d.provider_id
|
|
8566
|
+
FROM new_sessions s LEFT JOIN deepchat_sessions d ON d.id = s.id
|
|
8567
|
+
WHERE s.is_draft = 0 ${filter}
|
|
8568
|
+
ORDER BY s.id
|
|
8569
|
+
`).iterate(...bindings);
|
|
8570
|
+
for (const row of sessions) {
|
|
8571
|
+
const id = String(row.id);
|
|
8572
|
+
const parent = asString(row.parent_session_id);
|
|
8573
|
+
projections.set(id, {
|
|
8574
|
+
head: {
|
|
8575
|
+
...this.sessionIdentity(id),
|
|
8576
|
+
title: resolveSessionTitle(asString(row.title), null, null),
|
|
8577
|
+
directory: asString(row.project_dir) ?? "",
|
|
8578
|
+
parent_reference: parent ? { agentName: this.name, sessionId: parent } : void 0,
|
|
8579
|
+
time_created: Number(row.created_at),
|
|
8580
|
+
time_updated: Number(row.updated_at),
|
|
8581
|
+
stats: { message_count: 0, total_input_tokens: 0, total_output_tokens: 0, total_cost: 0 }
|
|
8582
|
+
},
|
|
8583
|
+
agentId: String(row.agent_id),
|
|
8584
|
+
model: asString(row.model_id) ?? null,
|
|
8585
|
+
provider: asString(row.provider_id) ?? null,
|
|
8586
|
+
signature: createHash3("sha256").update(JSON.stringify(row)),
|
|
8587
|
+
unpricedModels: /* @__PURE__ */ new Set(),
|
|
8588
|
+
messageUsage: /* @__PURE__ */ new Map()
|
|
8589
|
+
});
|
|
8590
|
+
}
|
|
8591
|
+
const usageRows = db.prepare(`
|
|
8592
|
+
SELECT u.session_id, u.message_id, u.usage_id, u.created_at, u.updated_at,
|
|
8593
|
+
u.model_id AS model, u.provider_id AS provider,
|
|
8594
|
+
u.input_tokens AS inputTokens, u.output_tokens AS outputTokens,
|
|
8595
|
+
u.total_tokens AS totalTokens, u.cached_input_tokens AS cachedInputTokens,
|
|
8596
|
+
u.cache_write_input_tokens AS cacheWriteInputTokens
|
|
8597
|
+
FROM deepchat_usage_stats u JOIN new_sessions s ON s.id = u.session_id
|
|
8598
|
+
WHERE s.is_draft = 0 ${filter}
|
|
8599
|
+
ORDER BY u.session_id, u.usage_id
|
|
8600
|
+
`).iterate(...bindings);
|
|
8601
|
+
for (const row of usageRows) {
|
|
8602
|
+
const projection = projections.get(String(row.session_id));
|
|
8603
|
+
accumulateUsage(projection, row);
|
|
8604
|
+
projection.signature.update(JSON.stringify(row));
|
|
8605
|
+
projection.head.time_updated = Math.max(
|
|
8606
|
+
projection.head.time_updated ?? 0,
|
|
8607
|
+
Number(row.created_at)
|
|
8608
|
+
);
|
|
8609
|
+
}
|
|
8610
|
+
const messageRows = db.prepare(`
|
|
8611
|
+
SELECT m.id, m.session_id, m.order_seq, m.role, m.status, m.metadata, m.updated_at
|
|
8612
|
+
FROM deepchat_messages m JOIN new_sessions s ON s.id = m.session_id
|
|
8613
|
+
WHERE s.is_draft = 0 ${filter}
|
|
8614
|
+
ORDER BY m.session_id, m.order_seq, m.id
|
|
8615
|
+
`).iterate(...bindings);
|
|
8616
|
+
for (const row of messageRows) {
|
|
8617
|
+
const projection = projections.get(String(row.session_id));
|
|
8618
|
+
projection.signature.update(JSON.stringify(row));
|
|
8619
|
+
projection.head.stats.message_count += 1;
|
|
8620
|
+
projection.head.time_updated = Math.max(
|
|
8621
|
+
projection.head.time_updated ?? 0,
|
|
8622
|
+
Number(row.updated_at)
|
|
8623
|
+
);
|
|
8624
|
+
const metadata = asRecord(parseDeepChatJson(row.metadata));
|
|
8625
|
+
if (row.role === "assistant" && metadata && !projection.messageUsage.has(String(row.id))) {
|
|
8626
|
+
accumulateUsage(projection, { ...metadata, message_id: row.id });
|
|
8627
|
+
}
|
|
8628
|
+
}
|
|
8629
|
+
const blockActivity = db.prepare(`
|
|
8630
|
+
SELECT m.session_id, COUNT(*) AS block_count, MAX(b.updated_at) AS updated_at,
|
|
8631
|
+
SUM(b.updated_at) AS block_revision
|
|
8632
|
+
FROM deepchat_assistant_blocks b
|
|
8633
|
+
JOIN deepchat_messages m ON m.id = b.message_id
|
|
8634
|
+
JOIN new_sessions s ON s.id = m.session_id
|
|
8635
|
+
WHERE s.is_draft = 0 ${filter}
|
|
8636
|
+
GROUP BY m.session_id ORDER BY m.session_id
|
|
8637
|
+
`).iterate(...bindings);
|
|
8638
|
+
for (const row of blockActivity) {
|
|
8639
|
+
const projection = projections.get(String(row.session_id));
|
|
8640
|
+
projection.signature.update(JSON.stringify(row));
|
|
8641
|
+
projection.head.time_updated = Math.max(
|
|
8642
|
+
projection.head.time_updated ?? 0,
|
|
8643
|
+
Number(row.updated_at)
|
|
8644
|
+
);
|
|
8645
|
+
}
|
|
8646
|
+
return projections;
|
|
8647
|
+
}
|
|
8648
|
+
getSessionData(sessionId) {
|
|
8649
|
+
return this.readDatabase((db) => {
|
|
8650
|
+
const projection = this.readProjections(db, sessionId).get(sessionId);
|
|
8651
|
+
if (!projection) throw new Error(`DeepChat session not found: ${sessionId}`);
|
|
8652
|
+
const partsByMessage = this.readStructuredParts(db, sessionId);
|
|
8653
|
+
const rows = db.prepare(`
|
|
8654
|
+
SELECT id, role, content, metadata, status, created_at, updated_at
|
|
8655
|
+
FROM deepchat_messages WHERE session_id = ? ORDER BY order_seq, id
|
|
8656
|
+
`).iterate(sessionId);
|
|
8657
|
+
const messages = [];
|
|
8658
|
+
for (const row of rows) {
|
|
8659
|
+
if (row.role !== "user" && row.role !== "assistant") continue;
|
|
8660
|
+
const id = String(row.id);
|
|
8661
|
+
const metadata = asRecord(parseDeepChatJson(row.metadata));
|
|
8662
|
+
const usage = projection.messageUsage.get(id);
|
|
8663
|
+
messages.push({
|
|
8664
|
+
id,
|
|
8665
|
+
role: row.role,
|
|
8666
|
+
agent: row.role === "assistant" ? projection.agentId : void 0,
|
|
8667
|
+
time_created: Number(row.created_at),
|
|
8668
|
+
time_completed: row.status === "pending" ? void 0 : Number(row.updated_at),
|
|
8669
|
+
model: usage?.model ?? asString(metadata?.model) ?? projection.model,
|
|
8670
|
+
provider: usage?.provider ?? asString(metadata?.provider) ?? projection.provider,
|
|
8671
|
+
tokens: usage?.tokens,
|
|
8672
|
+
cost: usage?.cost,
|
|
8673
|
+
cost_source: usage && usage.cost > 0 ? "estimated" : void 0,
|
|
8674
|
+
parts: partsByMessage.get(id) ?? deepChatRawParts(row.role, String(row.content))
|
|
8675
|
+
});
|
|
8676
|
+
}
|
|
8677
|
+
return { ...projection.head, messages };
|
|
8678
|
+
});
|
|
8679
|
+
}
|
|
8680
|
+
readStructuredParts(db, sessionId) {
|
|
8681
|
+
const parts = /* @__PURE__ */ new Map();
|
|
8682
|
+
const blocks = db.prepare(`
|
|
8683
|
+
SELECT b.* FROM deepchat_assistant_blocks b
|
|
8684
|
+
JOIN deepchat_messages m ON m.id = b.message_id
|
|
8685
|
+
WHERE m.session_id = ? ORDER BY b.message_id, b.block_index
|
|
8686
|
+
`).iterate(sessionId);
|
|
8687
|
+
for (const block of blocks) {
|
|
8688
|
+
const id = String(block.message_id);
|
|
8689
|
+
const messageParts = parts.get(id) ?? [];
|
|
8690
|
+
const part = deepChatStoredBlockPart(block);
|
|
8691
|
+
if (part) messageParts.push(part);
|
|
8692
|
+
parts.set(id, messageParts);
|
|
8693
|
+
}
|
|
8694
|
+
const users = db.prepare(`
|
|
8695
|
+
SELECT u.message_id, u.text FROM deepchat_user_messages u
|
|
8696
|
+
JOIN deepchat_messages m ON m.id = u.message_id WHERE m.session_id = ?
|
|
8697
|
+
`).iterate(sessionId);
|
|
8698
|
+
for (const user of users) parts.set(String(user.message_id), deepChatUserParts(user));
|
|
8699
|
+
const attachments = db.prepare(`
|
|
8700
|
+
SELECT f.message_id, f.path, f.name FROM deepchat_user_message_files f
|
|
8701
|
+
JOIN deepchat_messages m ON m.id = f.message_id
|
|
8702
|
+
WHERE m.session_id = ? ORDER BY f.message_id, f.ordinal
|
|
8703
|
+
`).iterate(sessionId);
|
|
8704
|
+
for (const attachment of attachments) {
|
|
8705
|
+
parts.get(String(attachment.message_id))?.push(...deepChatUserParts({ files: [attachment] }));
|
|
8706
|
+
}
|
|
8707
|
+
const links = db.prepare(`
|
|
8708
|
+
SELECT l.message_id, l.url FROM deepchat_user_message_links l
|
|
8709
|
+
JOIN deepchat_messages m ON m.id = l.message_id
|
|
8710
|
+
WHERE m.session_id = ? ORDER BY l.message_id, l.ordinal
|
|
8711
|
+
`).iterate(sessionId);
|
|
8712
|
+
for (const link of links)
|
|
8713
|
+
parts.get(String(link.message_id))?.push(...deepChatUserParts({ links: [link.url] }));
|
|
8714
|
+
return parts;
|
|
8715
|
+
}
|
|
8716
|
+
};
|
|
8717
|
+
function jsonRecord(value) {
|
|
8718
|
+
return asRecord(typeof value === "string" ? JSON.parse(value) : value);
|
|
8719
|
+
}
|
|
8720
|
+
function nonnegative(value) {
|
|
8721
|
+
return Math.max(0, asNumber(value) ?? 0);
|
|
8722
|
+
}
|
|
8723
|
+
function tokensFromStats(stats) {
|
|
8724
|
+
if (!stats) return void 0;
|
|
8725
|
+
const input = asRecord(stats.inputTokenDetails);
|
|
8726
|
+
const output = asRecord(stats.outputTokenDetails);
|
|
8727
|
+
return {
|
|
8728
|
+
input: asNumber(stats.inputTokens) ?? nonnegative(input?.noCacheTokens) + nonnegative(input?.cacheReadTokens) + nonnegative(input?.cacheWriteTokens),
|
|
8729
|
+
output: asNumber(stats.outputTokens) ?? nonnegative(output?.textTokens) + nonnegative(output?.reasoningTokens),
|
|
8730
|
+
cache_read: nonnegative(input?.cacheReadTokens),
|
|
8731
|
+
cache_create: nonnegative(input?.cacheWriteTokens),
|
|
8732
|
+
reasoning: nonnegative(output?.reasoningTokens)
|
|
8733
|
+
};
|
|
8734
|
+
}
|
|
8735
|
+
function messageCost(stats, model, tokens) {
|
|
8736
|
+
const costs = (asArray(stats?.costs) ?? []).flatMap((value) => {
|
|
8737
|
+
const cost2 = asRecord(value);
|
|
8738
|
+
return cost2 ? [cost2] : [];
|
|
8739
|
+
});
|
|
8740
|
+
if (costs.length > 0 && costs.every((cost2) => cost2.currency === "USD")) {
|
|
8741
|
+
return {
|
|
8742
|
+
cost: costs.reduce((sum, cost2) => sum + nonnegative(cost2.amount), 0),
|
|
8743
|
+
costSource: costs.some((cost2) => nonnegative(cost2.computedRequestCount) > 0) ? "estimated" : "recorded"
|
|
8744
|
+
};
|
|
8745
|
+
}
|
|
8746
|
+
const cost = estimateTokenCost(model, tokens ? { ...tokens, reasoning: 0 } : void 0);
|
|
8747
|
+
return {
|
|
8748
|
+
cost: cost ?? void 0,
|
|
8749
|
+
costSource: cost === null ? void 0 : "estimated"
|
|
8750
|
+
};
|
|
8751
|
+
}
|
|
8752
|
+
function convertPart(part) {
|
|
8753
|
+
const type = asString(part.type);
|
|
8754
|
+
const text = asString(part.text);
|
|
8755
|
+
if ((type === "text" || type === "reasoning") && text) return { type, text };
|
|
8756
|
+
if (type === "dynamic-tool" || type?.startsWith("tool-")) {
|
|
8757
|
+
const state = asString(part.state);
|
|
8758
|
+
const failed = state === "output-error" || state === "output-denied";
|
|
8759
|
+
return {
|
|
8760
|
+
type: "tool",
|
|
8761
|
+
tool: asString(part.toolName) ?? (type === "dynamic-tool" ? "unknown" : type.slice(5)),
|
|
8762
|
+
callID: asString(part.toolCallId),
|
|
8763
|
+
title: asString(part.title),
|
|
8764
|
+
state: {
|
|
8765
|
+
status: failed ? "error" : state === "output-available" ? "completed" : "running",
|
|
8766
|
+
input: part.input,
|
|
8767
|
+
output: part.output,
|
|
8768
|
+
error: failed ? part.errorText ?? "Tool execution failed" : void 0,
|
|
8769
|
+
metadata: part.providerMetadata
|
|
8770
|
+
}
|
|
8771
|
+
};
|
|
8772
|
+
}
|
|
8773
|
+
if (type === "file") {
|
|
8774
|
+
const url = asString(part.url);
|
|
8775
|
+
const mime = asString(part.mediaType);
|
|
8776
|
+
if (url && mime?.startsWith("image/")) return { type: "image", url, mime_type: mime };
|
|
8777
|
+
const label = asString(part.filename) ?? url;
|
|
8778
|
+
return label ? { type: "text", text: `Attachment: ${label}` } : null;
|
|
8779
|
+
}
|
|
8780
|
+
const data = asRecord(part.data);
|
|
8781
|
+
if (type === "data-error") {
|
|
8782
|
+
const message = asString(data?.message);
|
|
8783
|
+
return message ? { type: "text", text: message } : null;
|
|
8784
|
+
}
|
|
8785
|
+
if (type === "data-compact" || type === "data-code" || type === "data-translation") {
|
|
8786
|
+
const content = asString(data?.content);
|
|
8787
|
+
return content ? { type: "text", text: content } : null;
|
|
8788
|
+
}
|
|
8789
|
+
return null;
|
|
8790
|
+
}
|
|
8791
|
+
function cherryStudioTranscript(rows) {
|
|
8792
|
+
const builder = new TranscriptBuilder();
|
|
8793
|
+
const modelUsage = /* @__PURE__ */ Object.create(null);
|
|
8794
|
+
let totalTokens = 0;
|
|
8795
|
+
for (const row of rows) {
|
|
8796
|
+
if (row.role !== "user" && row.role !== "assistant") continue;
|
|
8797
|
+
const data = jsonRecord(row.data);
|
|
8798
|
+
const snapshot = jsonRecord(row.message_snapshot);
|
|
8799
|
+
const modelSnapshot = asRecord(snapshot?.model);
|
|
8800
|
+
const uniqueModel = asString(row.model_id);
|
|
8801
|
+
const separator = uniqueModel?.indexOf("::") ?? -1;
|
|
8802
|
+
const model = asString(modelSnapshot?.id) ?? (separator >= 0 ? uniqueModel?.slice(separator + 2) : uniqueModel);
|
|
8803
|
+
const provider = asString(modelSnapshot?.provider) ?? (separator >= 0 ? uniqueModel?.slice(0, separator) : void 0);
|
|
8804
|
+
const stats = row.role === "assistant" ? jsonRecord(row.stats) : void 0;
|
|
8805
|
+
const tokens = tokensFromStats(stats);
|
|
8806
|
+
const total = nonnegative(stats?.totalTokens ?? (tokens?.input ?? 0) + (tokens?.output ?? 0));
|
|
8807
|
+
totalTokens += total;
|
|
8808
|
+
if (model && total > 0) modelUsage[model] = (modelUsage[model] ?? 0) + total;
|
|
8809
|
+
const message = builder.appendMessage({
|
|
8810
|
+
id: String(row.id),
|
|
8811
|
+
role: row.role,
|
|
8812
|
+
timestampMs: Number(row.created_at),
|
|
8813
|
+
agent: asString(snapshot?.name),
|
|
8814
|
+
model,
|
|
8815
|
+
provider,
|
|
8816
|
+
tokens,
|
|
8817
|
+
...messageCost(stats, model, tokens),
|
|
8818
|
+
parts: (asArray(data?.parts) ?? []).flatMap((value) => {
|
|
8819
|
+
const part = asRecord(value);
|
|
8820
|
+
const converted = part ? convertPart(part) : null;
|
|
8821
|
+
return converted ? [converted] : [];
|
|
8822
|
+
})
|
|
8823
|
+
});
|
|
8824
|
+
if (row.status !== "pending") message.time_completed = Number(row.updated_at);
|
|
8825
|
+
}
|
|
8826
|
+
const transcript = builder.finish();
|
|
8827
|
+
return {
|
|
8828
|
+
...transcript,
|
|
8829
|
+
stats: { ...transcript.stats, total_tokens: totalTokens },
|
|
8830
|
+
modelUsage
|
|
8831
|
+
};
|
|
8832
|
+
}
|
|
8833
|
+
var AGENT_METADATA12 = getAgentCatalogEntry("cherrystudio");
|
|
8834
|
+
function resolveCherryStudioDataRoot() {
|
|
8835
|
+
const configured = readEnvPath("CHERRYSTUDIO_USER_DATA_DIR");
|
|
8836
|
+
if (configured) return configured;
|
|
8837
|
+
if (platform5() === "darwin")
|
|
8838
|
+
return join16(homedir5(), "Library", "Application Support", "CherryStudio");
|
|
8839
|
+
if (platform5() === "win32") {
|
|
8840
|
+
return join16(readEnvPath("APPDATA") ?? join16(homedir5(), "AppData", "Roaming"), "CherryStudio");
|
|
8841
|
+
}
|
|
8842
|
+
return join16(readEnvPath("XDG_CONFIG_HOME") ?? join16(homedir5(), ".config"), "CherryStudio");
|
|
8843
|
+
}
|
|
8844
|
+
function liveRows(db, table, alias) {
|
|
8845
|
+
const columns = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
8846
|
+
return columns.some((column) => column.name === "deleted_at") ? `${alias}.deleted_at IS NULL` : "1 = 1";
|
|
8847
|
+
}
|
|
8848
|
+
function activeBranch(rows, activeId) {
|
|
8849
|
+
const byId = new Map(rows.map((row) => [String(row.id), row]));
|
|
8850
|
+
const selected = [];
|
|
8851
|
+
const visited = /* @__PURE__ */ new Set();
|
|
8852
|
+
let id = asString(activeId);
|
|
8853
|
+
while (id) {
|
|
8854
|
+
if (visited.has(id)) throw new Error("Cherry Studio message branch contains a cycle");
|
|
8855
|
+
visited.add(id);
|
|
8856
|
+
const row = byId.get(id);
|
|
8857
|
+
if (!row) break;
|
|
8858
|
+
selected.push(row);
|
|
8859
|
+
id = asString(row.parent_id);
|
|
8860
|
+
}
|
|
8861
|
+
return selected.reverse();
|
|
8862
|
+
}
|
|
8863
|
+
var CherryStudioAgent = class extends DatabaseSessionSource {
|
|
8864
|
+
name = AGENT_METADATA12.name;
|
|
8865
|
+
displayName = AGENT_METADATA12.displayName;
|
|
8866
|
+
sourceRoot;
|
|
8867
|
+
constructor(options = {}) {
|
|
8868
|
+
super();
|
|
8869
|
+
this.sourceRoot = options.sourceRoot ?? resolveCherryStudioDataRoot();
|
|
8870
|
+
}
|
|
8871
|
+
getDatabasePath() {
|
|
8872
|
+
return firstExisting(join16(this.sourceRoot, "Data", "cherrystudio.sqlite"));
|
|
8873
|
+
}
|
|
8874
|
+
isAvailable() {
|
|
8875
|
+
return isSqliteAvailable() && this.getDatabasePath() !== null;
|
|
8876
|
+
}
|
|
8877
|
+
getSessionWatchPlan() {
|
|
8878
|
+
return {
|
|
8879
|
+
status: "supported",
|
|
8880
|
+
targets: [
|
|
8881
|
+
{ root: this.sourceRoot, path: join16(this.sourceRoot, "Data", "cherrystudio.sqlite") }
|
|
8882
|
+
]
|
|
8883
|
+
};
|
|
8884
|
+
}
|
|
8885
|
+
readDatabase(read) {
|
|
8886
|
+
const path = this.getDatabasePath();
|
|
8887
|
+
if (!path) throw new Error("Cherry Studio 2.x cherrystudio.sqlite is missing");
|
|
8888
|
+
return this.scanStep("reading Cherry Studio 2.x cherrystudio.sqlite", path, () => {
|
|
8889
|
+
const db = openDbReadOnly(path);
|
|
8890
|
+
if (!db) throw new Error("Cannot open Cherry Studio database");
|
|
8891
|
+
try {
|
|
8892
|
+
return db.transaction(() => read(db))();
|
|
8893
|
+
} finally {
|
|
8894
|
+
db.close();
|
|
8895
|
+
}
|
|
8896
|
+
});
|
|
8897
|
+
}
|
|
8898
|
+
scan(options) {
|
|
8899
|
+
if (!this.getDatabasePath()) return [];
|
|
8900
|
+
return this.readDatabase((db) => {
|
|
8901
|
+
const sessions = [];
|
|
8902
|
+
for (const kind of ["agent", "topic"]) {
|
|
8903
|
+
for (const projection of this.readConversations(db, kind)) {
|
|
8904
|
+
const { messages: _messages, ...head } = projection.session;
|
|
8905
|
+
if (!head.stats.message_count || !matchesScanWindow(head.time_updated ?? head.time_created, options))
|
|
8906
|
+
continue;
|
|
8907
|
+
this.rememberSession(head.reference.sessionId, {
|
|
8908
|
+
sourceFingerprint: projection.fingerprint,
|
|
8909
|
+
headParserVersion: "cherrystudio-v1",
|
|
8910
|
+
unpricedModels: projection.unpricedModels
|
|
8911
|
+
});
|
|
8912
|
+
sessions.push(head);
|
|
8913
|
+
}
|
|
8914
|
+
}
|
|
8915
|
+
sessions.sort(
|
|
8916
|
+
(left, right) => (right.time_updated ?? 0) - (left.time_updated ?? 0) || left.reference.sessionId.localeCompare(right.reference.sessionId)
|
|
8917
|
+
);
|
|
8918
|
+
options?.onProgress?.({
|
|
8919
|
+
total: sessions.length,
|
|
8920
|
+
processed: sessions.length,
|
|
8921
|
+
sessions: sessions.length
|
|
8922
|
+
});
|
|
8923
|
+
return sessions;
|
|
8924
|
+
});
|
|
8925
|
+
}
|
|
8926
|
+
getSessionData(sessionId) {
|
|
8927
|
+
const separator = sessionId.indexOf(":");
|
|
8928
|
+
const kind = sessionId.slice(0, separator);
|
|
8929
|
+
const id = sessionId.slice(separator + 1);
|
|
8930
|
+
if (kind !== "agent" && kind !== "topic" || !id)
|
|
8931
|
+
throw new Error(`Invalid Cherry Studio session: ${sessionId}`);
|
|
8932
|
+
return this.readDatabase((db) => {
|
|
8933
|
+
for (const projection of this.readConversations(db, kind, id)) return projection.session;
|
|
8934
|
+
throw new Error(`Cherry Studio session not found: ${sessionId}`);
|
|
8935
|
+
});
|
|
8936
|
+
}
|
|
8937
|
+
*readConversations(db, kind, id) {
|
|
8938
|
+
const table = kind === "agent" ? "agent_session" : "topic";
|
|
8939
|
+
const messageTable = kind === "agent" ? "agent_session_message" : "message";
|
|
8940
|
+
const foreignKey = kind === "agent" ? "session_id" : "topic_id";
|
|
8941
|
+
const filter = `${liveRows(db, table, "s")} ${id ? "AND s.id = ?" : ""}`;
|
|
8942
|
+
const bindings = id ? [id] : [];
|
|
8943
|
+
const headers = db.prepare(`
|
|
8944
|
+
SELECT s.id, s.name, s.created_at, s.updated_at, s.last_activity_at,
|
|
8945
|
+
${kind === "agent" ? "w.path AS directory, NULL AS active_node_id" : "NULL AS directory, s.active_node_id"}
|
|
8946
|
+
FROM ${table} s ${kind === "agent" ? "LEFT JOIN agent_workspace w ON w.id = s.workspace_id" : ""}
|
|
8947
|
+
WHERE ${filter}
|
|
8948
|
+
`).all(...bindings);
|
|
8949
|
+
const byId = new Map(headers.map((row) => [String(row.id), row]));
|
|
8950
|
+
const messages = db.prepare(`
|
|
8951
|
+
SELECT m.id, m.${foreignKey} AS conversation_id, m.role, m.data, m.stats,
|
|
8952
|
+
m.model_id, m.message_snapshot, m.status, m.created_at, m.updated_at,
|
|
8953
|
+
${kind === "topic" ? "m.parent_id" : "NULL AS parent_id"}
|
|
8954
|
+
FROM ${messageTable} m JOIN ${table} s ON s.id = m.${foreignKey}
|
|
8955
|
+
WHERE ${filter} AND ${liveRows(db, messageTable, "m")}
|
|
8956
|
+
ORDER BY m.${foreignKey}, m.created_at, m.id
|
|
8957
|
+
`).iterate(...bindings);
|
|
8958
|
+
let currentId;
|
|
8959
|
+
let rows = [];
|
|
8960
|
+
for (const row of messages) {
|
|
8961
|
+
const nextId = String(row.conversation_id);
|
|
8962
|
+
if (currentId !== void 0 && nextId !== currentId) {
|
|
8963
|
+
yield this.projectConversation(kind, byId.get(currentId), rows);
|
|
8964
|
+
rows = [];
|
|
8965
|
+
}
|
|
8966
|
+
currentId = nextId;
|
|
8967
|
+
rows.push(row);
|
|
8968
|
+
}
|
|
8969
|
+
if (currentId !== void 0) yield this.projectConversation(kind, byId.get(currentId), rows);
|
|
8970
|
+
}
|
|
8971
|
+
projectConversation(kind, row, rows) {
|
|
8972
|
+
const selected = kind === "topic" ? activeBranch(rows, row.active_node_id) : rows;
|
|
8973
|
+
const { result: transcript, unpricedModels } = capturePricingMisses(
|
|
8974
|
+
() => cherryStudioTranscript(selected)
|
|
8975
|
+
);
|
|
8976
|
+
const signature = createHash4("sha256").update(JSON.stringify(row));
|
|
8977
|
+
for (const message of selected) signature.update(JSON.stringify(message));
|
|
8978
|
+
const session = {
|
|
8979
|
+
...this.sessionIdentity(`${kind}:${row.id}`),
|
|
8980
|
+
title: resolveSessionTitle(
|
|
8981
|
+
asString(row.name),
|
|
8982
|
+
firstUserMessageTitle(transcript.messages),
|
|
8983
|
+
"Cherry Studio"
|
|
8984
|
+
),
|
|
8985
|
+
directory: asString(row.directory) || this.sourceRoot,
|
|
8986
|
+
time_created: Number(row.created_at),
|
|
8987
|
+
time_updated: Number(row.last_activity_at),
|
|
8988
|
+
stats: transcript.stats,
|
|
8989
|
+
model_usage: transcript.modelUsage,
|
|
8990
|
+
messages: transcript.messages
|
|
8991
|
+
};
|
|
8992
|
+
return { session, fingerprint: signature.digest("hex"), unpricedModels };
|
|
8993
|
+
}
|
|
8994
|
+
};
|
|
8995
|
+
function parseToolJson(value) {
|
|
8996
|
+
if (typeof value !== "string") return value;
|
|
8997
|
+
try {
|
|
8998
|
+
return JSON.parse(value);
|
|
8999
|
+
} catch {
|
|
9000
|
+
return value;
|
|
9001
|
+
}
|
|
9002
|
+
}
|
|
9003
|
+
function toolPart2(value) {
|
|
9004
|
+
const call = asRecord(value);
|
|
9005
|
+
if (!call) return null;
|
|
9006
|
+
const tool = asString(call.tool_name);
|
|
9007
|
+
if (!tool) return null;
|
|
9008
|
+
const input = parseToolJson(call.tool_call_args);
|
|
9009
|
+
const output = parseToolJson(call.tool_call_result_data);
|
|
9010
|
+
const result = asRecord(output);
|
|
9011
|
+
const failed = call.tool_call_status === 3 || result?.isError === true || result?.error != null;
|
|
9012
|
+
return {
|
|
9013
|
+
type: "tool",
|
|
9014
|
+
tool,
|
|
9015
|
+
callID: asString(call.tool_call_id),
|
|
9016
|
+
state: {
|
|
9017
|
+
status: failed ? "error" : call.tool_call_status === 2 ? "completed" : "running",
|
|
9018
|
+
input,
|
|
9019
|
+
output,
|
|
9020
|
+
error: failed ? result?.error ?? result?.text ?? output : void 0,
|
|
9021
|
+
metadata: {
|
|
9022
|
+
...asRecord(result?.details),
|
|
9023
|
+
minimax_status: call.tool_call_status
|
|
9024
|
+
}
|
|
9025
|
+
}
|
|
9026
|
+
};
|
|
9027
|
+
}
|
|
9028
|
+
function attachmentPart(value) {
|
|
9029
|
+
const attachment = asRecord(value);
|
|
9030
|
+
if (!attachment) return null;
|
|
9031
|
+
const path = asString(attachment.file_path) ?? asString(attachment.desktop_path);
|
|
9032
|
+
const mime = asString(attachment.mime_type);
|
|
9033
|
+
const name = path ?? asString(attachment.file_name) ?? asString(attachment.asset_id) ?? asString(attachment.url);
|
|
9034
|
+
return name ? { type: "text", text: `Attachment: ${name}${mime ? ` (${mime})` : ""}` } : null;
|
|
9035
|
+
}
|
|
9036
|
+
var EVENT_LABELS = {
|
|
9037
|
+
compaction_start: "Context compaction started",
|
|
9038
|
+
compaction: "Context compacted",
|
|
9039
|
+
compaction_failed: "Context compaction failed",
|
|
9040
|
+
review_start: "Review started",
|
|
9041
|
+
review_result: "Review result",
|
|
9042
|
+
review_failed: "Review failed",
|
|
9043
|
+
review_aborted: "Review aborted",
|
|
9044
|
+
review_interrupted: "Review interrupted"
|
|
9045
|
+
};
|
|
9046
|
+
var AUTOMATED_SOURCES = /* @__PURE__ */ new Set(["cron", "thread-goal", "team", "background-task", "system"]);
|
|
9047
|
+
function miniMaxMessage(row, agent) {
|
|
9048
|
+
const data = asRecord(JSON.parse(String(row.data_json)));
|
|
9049
|
+
const id = asString(row.msg_id);
|
|
9050
|
+
if (!data || !id || data.msg_id !== id) throw new Error("Invalid MiniMax display message");
|
|
9051
|
+
const role = row.role ?? data.role ?? "assistant";
|
|
9052
|
+
if (role !== "user" && role !== "assistant") throw new Error(`Invalid MiniMax role: ${role}`);
|
|
9053
|
+
const kind = asString(data.kind);
|
|
9054
|
+
const parts = [];
|
|
9055
|
+
if (kind) parts.push({ type: "text", text: EVENT_LABELS[kind] ?? `Event: ${kind}` });
|
|
9056
|
+
const thinking = asString(data.thinking_content);
|
|
9057
|
+
if (thinking) parts.push({ type: "reasoning", text: thinking });
|
|
9058
|
+
const text = asString(data.msg_content);
|
|
9059
|
+
if (text) parts.push({ type: "text", text });
|
|
9060
|
+
for (const value of Array.isArray(data.attachments) ? data.attachments : []) {
|
|
9061
|
+
const part = attachmentPart(value);
|
|
9062
|
+
if (part) parts.push(part);
|
|
9063
|
+
}
|
|
9064
|
+
const children = /* @__PURE__ */ new Set();
|
|
9065
|
+
for (const value of Array.isArray(data.tool_calls) ? data.tool_calls : []) {
|
|
9066
|
+
const part = toolPart2(value);
|
|
9067
|
+
if (!part) continue;
|
|
9068
|
+
parts.push(part);
|
|
9069
|
+
if (part.tool === "task" || part.tool.startsWith("task_")) {
|
|
9070
|
+
const metadata = asRecord(part.state.metadata);
|
|
9071
|
+
const child = asString(metadata?.sub_session_id) ?? asString(metadata?.session_id);
|
|
9072
|
+
if (child) children.add(child);
|
|
9073
|
+
}
|
|
9074
|
+
}
|
|
9075
|
+
const error = asString(data.error);
|
|
9076
|
+
if (error) parts.push({ type: "text", text: error });
|
|
9077
|
+
const timestamp = asNumber(row.created_at_ms) ?? asNumber(data.timestamp) ?? 0;
|
|
9078
|
+
return {
|
|
9079
|
+
id,
|
|
9080
|
+
role,
|
|
9081
|
+
agent: role === "assistant" ? agent : void 0,
|
|
9082
|
+
time_created: timestamp,
|
|
9083
|
+
time_completed: data.finish_reason ? timestamp : void 0,
|
|
9084
|
+
mode: kind,
|
|
9085
|
+
automated: role === "user" && (Boolean(kind) || AUTOMATED_SOURCES.has(String(row.source))) ? true : void 0,
|
|
9086
|
+
subagent_id: children.size === 1 ? children.values().next().value : void 0,
|
|
9087
|
+
parts
|
|
9088
|
+
};
|
|
9089
|
+
}
|
|
9090
|
+
function tokenCount2(value) {
|
|
9091
|
+
return Math.max(0, asNumber(value) ?? 0);
|
|
9092
|
+
}
|
|
9093
|
+
function miniMaxUsage(row) {
|
|
9094
|
+
const model = asString(row.model) || void 0;
|
|
9095
|
+
const tokens = {
|
|
9096
|
+
input: tokenCount2(row.input_tokens),
|
|
9097
|
+
output: tokenCount2(row.output_tokens),
|
|
9098
|
+
reasoning: tokenCount2(row.reasoning_tokens),
|
|
9099
|
+
cache_read: tokenCount2(row.cache_read_tokens),
|
|
9100
|
+
cache_create: tokenCount2(row.cache_write_tokens)
|
|
9101
|
+
};
|
|
9102
|
+
const recorded = asNumber(row.cost_usd);
|
|
9103
|
+
const cost = recorded !== void 0 && recorded >= 0 ? recorded : estimateTokenCost(model, tokens);
|
|
9104
|
+
return {
|
|
9105
|
+
turnId: asString(row.turn_id),
|
|
9106
|
+
model,
|
|
9107
|
+
time: tokenCount2(row.ts),
|
|
9108
|
+
tokens,
|
|
9109
|
+
total: Object.values(tokens).reduce((sum, value) => sum + value, 0),
|
|
9110
|
+
cost: cost ?? 0,
|
|
9111
|
+
costSource: recorded !== void 0 && recorded >= 0 ? "recorded" : cost !== null ? "estimated" : void 0
|
|
9112
|
+
};
|
|
9113
|
+
}
|
|
9114
|
+
function attachMiniMaxUsage(message, usages) {
|
|
9115
|
+
const models = new Set(usages.map((usage) => usage.model));
|
|
9116
|
+
if (models.size !== 1) return;
|
|
9117
|
+
message.model = usages[0]?.model;
|
|
9118
|
+
message.tokens = {};
|
|
9119
|
+
message.cost = 0;
|
|
9120
|
+
for (const usage of usages) {
|
|
9121
|
+
for (const key of ["input", "output", "reasoning", "cache_read", "cache_create"]) {
|
|
9122
|
+
message.tokens[key] = (message.tokens[key] ?? 0) + (usage.tokens[key] ?? 0);
|
|
9123
|
+
}
|
|
9124
|
+
message.cost += usage.cost;
|
|
9125
|
+
if (usage.costSource === "estimated" || !message.cost_source)
|
|
9126
|
+
message.cost_source = usage.costSource;
|
|
9127
|
+
}
|
|
9128
|
+
}
|
|
9129
|
+
var AGENT_METADATA13 = getAgentCatalogEntry("minimax-code");
|
|
9130
|
+
var DATABASE_PATH = join17("v2", "sqlite", "runtime-state.sqlite");
|
|
9131
|
+
var SESSION_FILTER = "(s.visibility <> 'hidden' OR s.parent_session_id IS NOT NULL) AND s.session_kind NOT IN ('peek', 'cron', 'channel')";
|
|
9132
|
+
function dataRoots() {
|
|
9133
|
+
const configured = readEnvPath("MINIMAX_DATA_DIR") ?? readEnvPath("MAVIS_DATA_DIR");
|
|
9134
|
+
return configured ? [configured] : [join17(homedir6(), ".minimax"), join17(homedir6(), ".minimax-code")];
|
|
9135
|
+
}
|
|
9136
|
+
function resolveMiniMaxCodeDataRoot() {
|
|
9137
|
+
const roots = dataRoots();
|
|
9138
|
+
return roots.find((root) => firstExisting(join17(root, DATABASE_PATH))) ?? roots[0];
|
|
9139
|
+
}
|
|
9140
|
+
var MiniMaxCodeAgent = class extends DatabaseSessionSource {
|
|
9141
|
+
name = AGENT_METADATA13.name;
|
|
9142
|
+
displayName = AGENT_METADATA13.displayName;
|
|
9143
|
+
roots;
|
|
9144
|
+
constructor(options = {}) {
|
|
9145
|
+
super();
|
|
9146
|
+
this.roots = options.sourceRoot ? [options.sourceRoot] : dataRoots();
|
|
9147
|
+
}
|
|
9148
|
+
getDatabasePath() {
|
|
9149
|
+
return firstExisting(...this.roots.map((root) => join17(root, DATABASE_PATH)));
|
|
9150
|
+
}
|
|
9151
|
+
isAvailable() {
|
|
9152
|
+
return isSqliteAvailable() && this.getDatabasePath() !== null;
|
|
9153
|
+
}
|
|
9154
|
+
getSessionWatchPlan() {
|
|
9155
|
+
return {
|
|
9156
|
+
status: "supported",
|
|
9157
|
+
targets: this.roots.flatMap(
|
|
9158
|
+
(root) => ["", "-wal", "-journal"].map((suffix) => ({
|
|
9159
|
+
path: `${join17(root, DATABASE_PATH)}${suffix}`,
|
|
9160
|
+
pollForChanges: true
|
|
9161
|
+
}))
|
|
9162
|
+
)
|
|
9163
|
+
};
|
|
9164
|
+
}
|
|
9165
|
+
readDatabase(read) {
|
|
9166
|
+
const path = this.getDatabasePath();
|
|
9167
|
+
if (!path) throw new Error("MiniMax Code runtime-state.sqlite is missing");
|
|
9168
|
+
return this.scanStep("reading MiniMax Code 0.4.12 sessions", path, () => {
|
|
9169
|
+
const db = openDbReadOnly(path);
|
|
9170
|
+
if (!db) throw new Error("Cannot open MiniMax Code database");
|
|
9171
|
+
try {
|
|
9172
|
+
return db.transaction(() => read(db))();
|
|
9173
|
+
} finally {
|
|
9174
|
+
db.close();
|
|
9175
|
+
}
|
|
9176
|
+
});
|
|
9177
|
+
}
|
|
9178
|
+
scan(options) {
|
|
9179
|
+
if (!this.getDatabasePath()) return [];
|
|
9180
|
+
return this.readDatabase((db) => {
|
|
9181
|
+
const projections = this.readProjections(db);
|
|
9182
|
+
const selected = /* @__PURE__ */ new Set();
|
|
9183
|
+
const children = /* @__PURE__ */ new Map();
|
|
9184
|
+
for (const [id, { head }] of projections) {
|
|
9185
|
+
const parent = head.parent_reference?.sessionId;
|
|
9186
|
+
if (parent && projections.has(parent)) {
|
|
9187
|
+
const siblings = children.get(parent) ?? [];
|
|
9188
|
+
siblings.push(id);
|
|
9189
|
+
children.set(parent, siblings);
|
|
9190
|
+
} else if (matchesScanWindow(head.time_updated ?? head.time_created, options)) {
|
|
9191
|
+
selected.add(id);
|
|
9192
|
+
}
|
|
9193
|
+
}
|
|
9194
|
+
if (options?.includeRelatedSessions !== false) {
|
|
9195
|
+
for (const id of selected) {
|
|
9196
|
+
for (const child of children.get(id) ?? []) selected.add(child);
|
|
9197
|
+
}
|
|
9198
|
+
}
|
|
9199
|
+
const sessions = [];
|
|
9200
|
+
for (const id of selected) {
|
|
9201
|
+
const projection = projections.get(id);
|
|
9202
|
+
if (!projection.head.stats.message_count) continue;
|
|
9203
|
+
this.rememberSession(id, {
|
|
9204
|
+
sourceFingerprint: projection.signature.digest("hex"),
|
|
9205
|
+
headParserVersion: "minimax-code-v1",
|
|
9206
|
+
unpricedModels: [...projection.unpricedModels]
|
|
9207
|
+
});
|
|
9208
|
+
sessions.push(projection.head);
|
|
9209
|
+
}
|
|
9210
|
+
sessions.sort(
|
|
9211
|
+
(left, right) => (right.time_updated ?? 0) - (left.time_updated ?? 0) || left.reference.sessionId.localeCompare(right.reference.sessionId)
|
|
9212
|
+
);
|
|
9213
|
+
options?.onProgress?.({
|
|
9214
|
+
total: selected.size,
|
|
9215
|
+
processed: selected.size,
|
|
9216
|
+
sessions: sessions.length
|
|
9217
|
+
});
|
|
9218
|
+
return sessions;
|
|
9219
|
+
});
|
|
9220
|
+
}
|
|
9221
|
+
getSessionData(sessionId) {
|
|
9222
|
+
return this.readDatabase((db) => {
|
|
9223
|
+
const projection = this.readProjections(db, sessionId).get(sessionId);
|
|
9224
|
+
if (!projection) throw new Error(`MiniMax Code session not found: ${sessionId}`);
|
|
9225
|
+
for (const [turnId, usage] of projection.usageByTurn) {
|
|
9226
|
+
const message = projection.lastAssistantByTurn.get(turnId);
|
|
9227
|
+
if (message) attachMiniMaxUsage(message, usage);
|
|
9228
|
+
}
|
|
9229
|
+
return { ...projection.head, messages: projection.messages };
|
|
9230
|
+
});
|
|
9231
|
+
}
|
|
9232
|
+
readProjections(db, sessionId) {
|
|
9233
|
+
const filter = `${SESSION_FILTER}${sessionId ? " AND s.session_id = ?" : ""}`;
|
|
9234
|
+
const bindings = sessionId ? [sessionId] : [];
|
|
9235
|
+
const projections = /* @__PURE__ */ new Map();
|
|
9236
|
+
const sessions = db.prepare(`
|
|
9237
|
+
SELECT s.session_id, s.columnar_version, s.title, s.workspace_dir, s.parent_session_id,
|
|
9238
|
+
s.created_at_ms, s.updated_at_ms, s.agent_name, s.status, s.archived, s.extra_data_json
|
|
9239
|
+
FROM local_runtime_sessions s WHERE ${filter} ORDER BY s.session_id
|
|
9240
|
+
`).iterate(...bindings);
|
|
9241
|
+
for (const row of sessions) {
|
|
9242
|
+
if (row.columnar_version !== 3)
|
|
9243
|
+
throw new Error("Unsupported MiniMax session columnar version");
|
|
9244
|
+
const id = String(row.session_id);
|
|
9245
|
+
const parent = asString(row.parent_session_id);
|
|
9246
|
+
projections.set(id, {
|
|
9247
|
+
head: {
|
|
9248
|
+
...this.sessionIdentity(id),
|
|
9249
|
+
title: asString(row.title) ?? "",
|
|
9250
|
+
directory: asString(row.workspace_dir) ?? "",
|
|
9251
|
+
parent_reference: parent && parent !== id ? { agentName: this.name, sessionId: parent } : void 0,
|
|
9252
|
+
time_created: Number(row.created_at_ms ?? row.updated_at_ms),
|
|
9253
|
+
time_updated: Number(row.updated_at_ms),
|
|
9254
|
+
stats: { message_count: 0, total_input_tokens: 0, total_output_tokens: 0, total_cost: 0 }
|
|
9255
|
+
},
|
|
9256
|
+
agent: asString(row.agent_name) ?? this.displayName,
|
|
9257
|
+
signature: createHash5("sha256").update(JSON.stringify(row)),
|
|
9258
|
+
unpricedModels: /* @__PURE__ */ new Set(),
|
|
9259
|
+
messages: [],
|
|
9260
|
+
lastAssistantByTurn: /* @__PURE__ */ new Map(),
|
|
9261
|
+
usageByTurn: /* @__PURE__ */ new Map()
|
|
9262
|
+
});
|
|
9263
|
+
}
|
|
9264
|
+
const messages = db.prepare(`
|
|
9265
|
+
SELECT m.id, m.session_id, m.msg_id, m.role, m.turn_id, m.source, m.created_at_ms, m.data_json
|
|
9266
|
+
FROM local_runtime_message_rows m JOIN local_runtime_sessions s ON s.session_id = m.session_id
|
|
9267
|
+
WHERE ${filter} ORDER BY m.session_id, m.id
|
|
9268
|
+
`).iterate(...bindings);
|
|
9269
|
+
for (const row of messages) {
|
|
9270
|
+
const projection = projections.get(String(row.session_id));
|
|
9271
|
+
projection.signature.update(JSON.stringify(row));
|
|
9272
|
+
const message = miniMaxMessage(row, projection.agent);
|
|
9273
|
+
projection.head.stats.message_count += 1;
|
|
9274
|
+
projection.head.time_updated = Math.max(
|
|
9275
|
+
projection.head.time_updated ?? 0,
|
|
9276
|
+
message.time_created
|
|
9277
|
+
);
|
|
9278
|
+
if (message.role === "user" && !message.automated && !projection.firstUserText) {
|
|
9279
|
+
projection.firstUserText = message.parts.find((part) => part.type === "text")?.text;
|
|
9280
|
+
}
|
|
9281
|
+
if (sessionId) {
|
|
9282
|
+
projection.messages.push(message);
|
|
9283
|
+
const turnId = asString(row.turn_id);
|
|
9284
|
+
if (turnId && message.role === "assistant" && !message.mode)
|
|
9285
|
+
projection.lastAssistantByTurn.set(turnId, message);
|
|
9286
|
+
}
|
|
9287
|
+
}
|
|
9288
|
+
const usages = db.prepare(`
|
|
9289
|
+
SELECT u.id, u.session_id, u.turn_id, u.model, u.ts, u.input_tokens, u.output_tokens,
|
|
9290
|
+
u.reasoning_tokens, u.cache_read_tokens, u.cache_write_tokens, u.cost_usd
|
|
9291
|
+
FROM local_runtime_token_usage u JOIN local_runtime_sessions s ON s.session_id = u.session_id
|
|
9292
|
+
WHERE ${filter} ORDER BY u.session_id, u.id
|
|
9293
|
+
`).iterate(...bindings);
|
|
9294
|
+
for (const row of usages) {
|
|
9295
|
+
const projection = projections.get(String(row.session_id));
|
|
9296
|
+
projection.signature.update(JSON.stringify(row));
|
|
9297
|
+
const { result: usage, unpricedModels } = capturePricingMisses(() => miniMaxUsage(row));
|
|
9298
|
+
for (const model of unpricedModels) projection.unpricedModels.add(model);
|
|
9299
|
+
const stats = projection.head.stats;
|
|
9300
|
+
stats.total_input_tokens += usage.tokens.input ?? 0;
|
|
9301
|
+
stats.total_output_tokens += usage.tokens.output ?? 0;
|
|
9302
|
+
stats.total_tokens = (stats.total_tokens ?? 0) + usage.total;
|
|
9303
|
+
stats.total_cache_read_tokens = (stats.total_cache_read_tokens ?? 0) + (usage.tokens.cache_read ?? 0);
|
|
9304
|
+
stats.total_cache_create_tokens = (stats.total_cache_create_tokens ?? 0) + (usage.tokens.cache_create ?? 0);
|
|
9305
|
+
stats.total_cost += usage.cost;
|
|
9306
|
+
if (usage.costSource === "estimated" || !stats.cost_source)
|
|
9307
|
+
stats.cost_source = usage.costSource;
|
|
9308
|
+
if (usage.model) {
|
|
9309
|
+
const modelUsage = projection.head.model_usage ??= /* @__PURE__ */ Object.create(null);
|
|
9310
|
+
modelUsage[usage.model] = (modelUsage[usage.model] ?? 0) + usage.total;
|
|
9311
|
+
}
|
|
9312
|
+
projection.head.time_updated = Math.max(projection.head.time_updated ?? 0, usage.time);
|
|
9313
|
+
if (sessionId && usage.turnId) {
|
|
9314
|
+
const turnUsage = projection.usageByTurn.get(usage.turnId) ?? [];
|
|
9315
|
+
turnUsage.push(usage);
|
|
9316
|
+
projection.usageByTurn.set(usage.turnId, turnUsage);
|
|
9317
|
+
}
|
|
9318
|
+
}
|
|
9319
|
+
for (const projection of projections.values()) {
|
|
9320
|
+
projection.head.title = resolveSessionTitle(
|
|
9321
|
+
projection.head.title,
|
|
9322
|
+
projection.firstUserText ?? null,
|
|
9323
|
+
null
|
|
9324
|
+
);
|
|
9325
|
+
}
|
|
9326
|
+
return projections;
|
|
9327
|
+
}
|
|
9328
|
+
};
|
|
8308
9329
|
var RUNTIME_REGISTRATIONS = {
|
|
9330
|
+
"minimax-code": {
|
|
9331
|
+
create: () => new MiniMaxCodeAgent(),
|
|
9332
|
+
resolveDataRoot: resolveMiniMaxCodeDataRoot
|
|
9333
|
+
},
|
|
8309
9334
|
claudecode: {
|
|
8310
9335
|
create: () => new ClaudeCodeAgent(),
|
|
8311
9336
|
resolveDataRoot: resolveClaudeCodeDataRoot
|
|
@@ -8345,6 +9370,14 @@ var RUNTIME_REGISTRATIONS = {
|
|
|
8345
9370
|
dsh: {
|
|
8346
9371
|
create: () => new DshAgent(),
|
|
8347
9372
|
resolveDataRoot: resolveDshDataRoot
|
|
9373
|
+
},
|
|
9374
|
+
deepchat: {
|
|
9375
|
+
create: () => new DeepChatAgent(),
|
|
9376
|
+
resolveDataRoot: resolveDeepChatDataRoot
|
|
9377
|
+
},
|
|
9378
|
+
cherrystudio: {
|
|
9379
|
+
create: () => new CherryStudioAgent(),
|
|
9380
|
+
resolveDataRoot: resolveCherryStudioDataRoot
|
|
8348
9381
|
}
|
|
8349
9382
|
};
|
|
8350
9383
|
var AGENT_REGISTRATIONS = Object.freeze(
|
|
@@ -8387,4 +9420,4 @@ export {
|
|
|
8387
9420
|
createRegisteredAgents,
|
|
8388
9421
|
getAgentInfoMap
|
|
8389
9422
|
};
|
|
8390
|
-
//# sourceMappingURL=chunk-
|
|
9423
|
+
//# sourceMappingURL=chunk-WRVILHZR.js.map
|