codesesh 1.0.8 → 1.0.9
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 +16 -0
- package/dist/{chunk-L4G3LE7I.js → chunk-5YY675UR.js} +2 -2
- package/dist/{chunk-DHQPM5FF.js → chunk-CIMPLUT6.js} +5 -5
- package/dist/{chunk-YLXHGL4S.js → chunk-MOZLVHCC.js} +20 -2
- package/dist/{chunk-YLXHGL4S.js.map → chunk-MOZLVHCC.js.map} +1 -1
- package/dist/{chunk-V3HKVTIO.js → chunk-QFG33PKR.js} +2 -2
- package/dist/{chunk-KVTLNX7V.js → chunk-RDTQ2WPR.js} +2 -2
- package/dist/{chunk-RBCCNCDO.js → chunk-ZDH2BKQK.js} +696 -4
- package/dist/chunk-ZDH2BKQK.js.map +1 -0
- package/dist/{chunk-AGUAXTKC.js → chunk-ZLU7ODBV.js} +2 -2
- package/dist/{discovery-KEZQU6RL.js → discovery-MS2ZSMZ5.js} +5 -5
- package/dist/index.js +8 -8
- 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-Dgb2Qg8H.js +1 -0
- package/dist/web/assets/{InteractiveReceipt-Bsj37HtN.js → InteractiveReceipt-SckXLiPB.js} +1 -1
- package/dist/web/assets/OverviewScreen-D44AMeDu.js +1 -0
- package/dist/web/assets/{PrismHighlighter-DWS6Nx_X.js → PrismHighlighter-D7JLjKja.js} +1 -1
- package/dist/web/assets/Projects-DVHOqH2Z.js +1 -0
- package/dist/web/assets/{SearchResultsPanel-BAManMmt.js → SearchResultsPanel-B1WEw9Q5.js} +1 -1
- package/dist/web/assets/SessionDetail-J00I4QfE.js +53 -0
- package/dist/web/assets/index-BIpTq_7T.js +1423 -0
- package/dist/web/assets/index-BXhaumu7.css +1 -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/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-5YY675UR.js.map} +0 -0
- /package/dist/{chunk-DHQPM5FF.js.map → chunk-CIMPLUT6.js.map} +0 -0
- /package/dist/{chunk-V3HKVTIO.js.map → chunk-QFG33PKR.js.map} +0 -0
- /package/dist/{chunk-KVTLNX7V.js.map → chunk-RDTQ2WPR.js.map} +0 -0
- /package/dist/{chunk-AGUAXTKC.js.map → chunk-ZLU7ODBV.js.map} +0 -0
- /package/dist/{discovery-KEZQU6RL.js.map → discovery-MS2ZSMZ5.js.map} +0 -0
|
@@ -32,14 +32,14 @@ import {
|
|
|
32
32
|
reportFieldMismatch,
|
|
33
33
|
resolveSessionTitle,
|
|
34
34
|
safeParseJsonRecord
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-MOZLVHCC.js";
|
|
36
36
|
|
|
37
|
-
// ../core/dist/chunk-
|
|
37
|
+
// ../core/dist/chunk-SJU7QB6Z.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,12 @@ 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";
|
|
71
77
|
function fingerprintMatches(ref, cached) {
|
|
72
78
|
return typeof cached?.sourceFingerprint === "string" && cached.sourceFingerprint === ref.fingerprint;
|
|
73
79
|
}
|
|
@@ -1423,6 +1429,16 @@ var ClaudeCodeAgent = class extends SingleFileSessionSource {
|
|
|
1423
1429
|
}
|
|
1424
1430
|
return false;
|
|
1425
1431
|
}
|
|
1432
|
+
filterCachedSessions(sessions) {
|
|
1433
|
+
const basePath = this.basePath ?? this.findBasePath();
|
|
1434
|
+
if (!basePath) return sessions;
|
|
1435
|
+
return sessions.filter((session) => {
|
|
1436
|
+
const sourcePath = this.sessionMetaMap.get(session.reference.sessionId)?.sourcePath;
|
|
1437
|
+
if (!sourcePath) return true;
|
|
1438
|
+
const path = relative(basePath, sourcePath);
|
|
1439
|
+
return path !== ".." && !path.startsWith(`..${sep}`) && !isAbsolute2(path);
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1426
1442
|
listSessionSources(options) {
|
|
1427
1443
|
if (!this.basePath) return [];
|
|
1428
1444
|
const projectDirs = this.listProjectDirs();
|
|
@@ -8305,6 +8321,674 @@ function isMissingDirectory(error) {
|
|
|
8305
8321
|
const code = error.code;
|
|
8306
8322
|
return code === "ENOENT" || code === "ENOTDIR";
|
|
8307
8323
|
}
|
|
8324
|
+
function parseDeepChatJson(value) {
|
|
8325
|
+
if (typeof value !== "string") return value;
|
|
8326
|
+
try {
|
|
8327
|
+
return JSON.parse(value);
|
|
8328
|
+
} catch {
|
|
8329
|
+
return value;
|
|
8330
|
+
}
|
|
8331
|
+
}
|
|
8332
|
+
function deepChatTokens(metadata) {
|
|
8333
|
+
const input = asNumber(metadata.inputTokens);
|
|
8334
|
+
const output = asNumber(metadata.outputTokens);
|
|
8335
|
+
if (input === void 0 && output === void 0) return void 0;
|
|
8336
|
+
const cacheRead = Math.max(0, asNumber(metadata.cachedInputTokens) ?? 0);
|
|
8337
|
+
const cacheCreate = Math.max(0, asNumber(metadata.cacheWriteInputTokens) ?? 0);
|
|
8338
|
+
return {
|
|
8339
|
+
input: Math.max(0, input ?? 0),
|
|
8340
|
+
output: Math.max(0, output ?? 0),
|
|
8341
|
+
cache_read: Math.min(cacheRead, Math.max(0, input ?? 0)),
|
|
8342
|
+
cache_create: Math.min(cacheCreate, Math.max(0, (input ?? 0) - cacheRead))
|
|
8343
|
+
};
|
|
8344
|
+
}
|
|
8345
|
+
function deepChatAssistantPart(block) {
|
|
8346
|
+
const time_created = asNumber(block.timestamp);
|
|
8347
|
+
const content = asString(block.content);
|
|
8348
|
+
if (block.type === "tool_call") {
|
|
8349
|
+
const tool = asRecord(block.tool_call);
|
|
8350
|
+
if (!tool) return null;
|
|
8351
|
+
const status = block.status === "pending" || block.status === "loading" ? "running" : block.status === "error" || block.status === "denied" ? "error" : "completed";
|
|
8352
|
+
const output = parseDeepChatJson(tool.response);
|
|
8353
|
+
return {
|
|
8354
|
+
type: "tool",
|
|
8355
|
+
tool: asString(tool.name) ?? "unknown",
|
|
8356
|
+
callID: asString(tool.id),
|
|
8357
|
+
time_created,
|
|
8358
|
+
state: {
|
|
8359
|
+
status,
|
|
8360
|
+
input: parseDeepChatJson(tool.params),
|
|
8361
|
+
output,
|
|
8362
|
+
error: status === "error" ? output ?? content : void 0,
|
|
8363
|
+
metadata: asRecord(block.extra)
|
|
8364
|
+
}
|
|
8365
|
+
};
|
|
8366
|
+
}
|
|
8367
|
+
if (block.type === "image") {
|
|
8368
|
+
const image = asRecord(block.image_data);
|
|
8369
|
+
const data = asString(image?.data);
|
|
8370
|
+
const mime = asString(image?.mimeType);
|
|
8371
|
+
if (data && mime) return { type: "image", data, mime_type: mime, time_created };
|
|
8372
|
+
}
|
|
8373
|
+
if (!content) return null;
|
|
8374
|
+
return {
|
|
8375
|
+
type: block.type === "reasoning_content" ? "reasoning" : "text",
|
|
8376
|
+
text: content,
|
|
8377
|
+
time_created
|
|
8378
|
+
};
|
|
8379
|
+
}
|
|
8380
|
+
function deepChatStoredBlockPart(row) {
|
|
8381
|
+
const extra = asRecord(parseDeepChatJson(row.extra_json));
|
|
8382
|
+
return deepChatAssistantPart({
|
|
8383
|
+
type: row.block_type,
|
|
8384
|
+
content: row.text_content,
|
|
8385
|
+
status: row.status,
|
|
8386
|
+
timestamp: extra?.timestamp ?? row.updated_at,
|
|
8387
|
+
extra: extra?.extra,
|
|
8388
|
+
tool_call: {
|
|
8389
|
+
id: row.tool_call_id,
|
|
8390
|
+
name: row.tool_name,
|
|
8391
|
+
params: row.tool_params,
|
|
8392
|
+
response: row.tool_response
|
|
8393
|
+
},
|
|
8394
|
+
image_data: { data: extra?.imageData, mimeType: row.image_mime_type }
|
|
8395
|
+
});
|
|
8396
|
+
}
|
|
8397
|
+
function deepChatUserParts(content) {
|
|
8398
|
+
const parts = [];
|
|
8399
|
+
const text = asString(content.text);
|
|
8400
|
+
if (text) parts.push({ type: "text", text });
|
|
8401
|
+
for (const file of asArray(content.files) ?? []) {
|
|
8402
|
+
const record = asRecord(file);
|
|
8403
|
+
const path = asString(record?.path);
|
|
8404
|
+
const name = asString(record?.name);
|
|
8405
|
+
if (path || name) parts.push({ type: "text", text: `Attachment: ${path ?? name}` });
|
|
8406
|
+
}
|
|
8407
|
+
for (const link of asArray(content.links) ?? []) {
|
|
8408
|
+
if (typeof link === "string") parts.push({ type: "text", text: link });
|
|
8409
|
+
}
|
|
8410
|
+
return parts;
|
|
8411
|
+
}
|
|
8412
|
+
function deepChatRawParts(role, content) {
|
|
8413
|
+
const parsed = parseDeepChatJson(content);
|
|
8414
|
+
if (role === "user") {
|
|
8415
|
+
const user = asRecord(parsed);
|
|
8416
|
+
if (user) return deepChatUserParts(user);
|
|
8417
|
+
}
|
|
8418
|
+
if (Array.isArray(parsed)) {
|
|
8419
|
+
const parts = [];
|
|
8420
|
+
for (const value of parsed) {
|
|
8421
|
+
const block = asRecord(value);
|
|
8422
|
+
const part = block ? deepChatAssistantPart(block) : null;
|
|
8423
|
+
if (part) parts.push(part);
|
|
8424
|
+
}
|
|
8425
|
+
return parts;
|
|
8426
|
+
}
|
|
8427
|
+
return typeof parsed === "string" && parsed ? [{ type: "text", text: parsed }] : [];
|
|
8428
|
+
}
|
|
8429
|
+
var AGENT_METADATA11 = getAgentCatalogEntry("deepchat");
|
|
8430
|
+
function resolveDeepChatDataRoot() {
|
|
8431
|
+
const configured = readEnvPath("DEEPCHAT_USER_DATA_DIR");
|
|
8432
|
+
if (configured) return configured;
|
|
8433
|
+
if (platform4() === "darwin") return join15(homedir4(), "Library", "Application Support", "DeepChat");
|
|
8434
|
+
if (platform4() === "win32") {
|
|
8435
|
+
return join15(readEnvPath("APPDATA") ?? join15(homedir4(), "AppData", "Roaming"), "DeepChat");
|
|
8436
|
+
}
|
|
8437
|
+
return join15(readEnvPath("XDG_CONFIG_HOME") ?? join15(homedir4(), ".config"), "DeepChat");
|
|
8438
|
+
}
|
|
8439
|
+
function accumulateUsage(session, row) {
|
|
8440
|
+
const model = asString(row.model) ?? session.model;
|
|
8441
|
+
const provider = asString(row.provider) ?? session.provider;
|
|
8442
|
+
const tokens = deepChatTokens(row);
|
|
8443
|
+
if (!tokens && asNumber(row.totalTokens) === void 0) return;
|
|
8444
|
+
const input = tokens?.input ?? 0;
|
|
8445
|
+
const output = tokens?.output ?? 0;
|
|
8446
|
+
const total = Math.max(0, asNumber(row.totalTokens) ?? input + output);
|
|
8447
|
+
const { result: estimate, unpricedModels } = capturePricingMisses(
|
|
8448
|
+
() => estimateTokenCost(model, tokens)
|
|
8449
|
+
);
|
|
8450
|
+
for (const missing of unpricedModels) session.unpricedModels.add(missing);
|
|
8451
|
+
const cost = estimate ?? 0;
|
|
8452
|
+
const stats = session.head.stats;
|
|
8453
|
+
stats.total_input_tokens += input;
|
|
8454
|
+
stats.total_output_tokens += output;
|
|
8455
|
+
stats.total_tokens = (stats.total_tokens ?? 0) + total;
|
|
8456
|
+
stats.total_cache_read_tokens = (stats.total_cache_read_tokens ?? 0) + (tokens?.cache_read ?? 0);
|
|
8457
|
+
stats.total_cache_create_tokens = (stats.total_cache_create_tokens ?? 0) + (tokens?.cache_create ?? 0);
|
|
8458
|
+
stats.total_cost += cost;
|
|
8459
|
+
if (cost > 0) stats.cost_source = "estimated";
|
|
8460
|
+
if (model && total > 0) {
|
|
8461
|
+
const usage = session.head.model_usage ??= /* @__PURE__ */ Object.create(null);
|
|
8462
|
+
usage[model] = (usage[model] ?? 0) + total;
|
|
8463
|
+
}
|
|
8464
|
+
const messageId = asString(row.message_id);
|
|
8465
|
+
if (!messageId) return;
|
|
8466
|
+
const previous = session.messageUsage.get(messageId);
|
|
8467
|
+
session.messageUsage.set(messageId, {
|
|
8468
|
+
model,
|
|
8469
|
+
provider,
|
|
8470
|
+
cost: (previous?.cost ?? 0) + cost,
|
|
8471
|
+
tokens: {
|
|
8472
|
+
input: (previous?.tokens.input ?? 0) + input,
|
|
8473
|
+
output: (previous?.tokens.output ?? 0) + output,
|
|
8474
|
+
cache_read: (previous?.tokens.cache_read ?? 0) + (tokens?.cache_read ?? 0),
|
|
8475
|
+
cache_create: (previous?.tokens.cache_create ?? 0) + (tokens?.cache_create ?? 0)
|
|
8476
|
+
}
|
|
8477
|
+
});
|
|
8478
|
+
}
|
|
8479
|
+
var DeepChatAgent = class extends DatabaseSessionSource {
|
|
8480
|
+
name = AGENT_METADATA11.name;
|
|
8481
|
+
displayName = AGENT_METADATA11.displayName;
|
|
8482
|
+
sourceRoot;
|
|
8483
|
+
constructor(options = {}) {
|
|
8484
|
+
super();
|
|
8485
|
+
this.sourceRoot = options.sourceRoot ?? resolveDeepChatDataRoot();
|
|
8486
|
+
}
|
|
8487
|
+
getDatabasePath() {
|
|
8488
|
+
return firstExisting(join15(this.sourceRoot, "app_db", "agent.db"));
|
|
8489
|
+
}
|
|
8490
|
+
isAvailable() {
|
|
8491
|
+
return isSqliteAvailable() && this.getDatabasePath() !== null;
|
|
8492
|
+
}
|
|
8493
|
+
getSessionWatchPlan() {
|
|
8494
|
+
return {
|
|
8495
|
+
status: "supported",
|
|
8496
|
+
targets: [{ root: this.sourceRoot, path: join15(this.sourceRoot, "app_db", "agent.db") }]
|
|
8497
|
+
};
|
|
8498
|
+
}
|
|
8499
|
+
readDatabase(read) {
|
|
8500
|
+
const path = this.getDatabasePath();
|
|
8501
|
+
if (!path) throw new Error("DeepChat agent.db is missing");
|
|
8502
|
+
return this.scanStep("reading unencrypted DeepChat agent.db", path, () => {
|
|
8503
|
+
const db = openDbReadOnly(path);
|
|
8504
|
+
if (!db)
|
|
8505
|
+
throw new Error("Cannot open DeepChat agent.db; only unencrypted databases are supported");
|
|
8506
|
+
try {
|
|
8507
|
+
return db.transaction(() => read(db))();
|
|
8508
|
+
} finally {
|
|
8509
|
+
db.close();
|
|
8510
|
+
}
|
|
8511
|
+
});
|
|
8512
|
+
}
|
|
8513
|
+
scan(options) {
|
|
8514
|
+
if (!this.getDatabasePath()) return [];
|
|
8515
|
+
return this.readDatabase((db) => {
|
|
8516
|
+
const projections = this.readProjections(db);
|
|
8517
|
+
const selected = /* @__PURE__ */ new Set();
|
|
8518
|
+
const children = /* @__PURE__ */ new Map();
|
|
8519
|
+
for (const [id, projection] of projections) {
|
|
8520
|
+
const parent = projection.head.parent_reference?.sessionId;
|
|
8521
|
+
if (parent && projections.has(parent)) {
|
|
8522
|
+
const siblings = children.get(parent) ?? [];
|
|
8523
|
+
siblings.push(id);
|
|
8524
|
+
children.set(parent, siblings);
|
|
8525
|
+
} else if (matchesScanWindow(projection.head.time_updated ?? projection.head.time_created, options)) {
|
|
8526
|
+
selected.add(id);
|
|
8527
|
+
}
|
|
8528
|
+
}
|
|
8529
|
+
if (options?.includeRelatedSessions !== false) {
|
|
8530
|
+
for (const id of selected) {
|
|
8531
|
+
for (const child of children.get(id) ?? []) selected.add(child);
|
|
8532
|
+
}
|
|
8533
|
+
}
|
|
8534
|
+
const sessions = [];
|
|
8535
|
+
for (const id of selected) {
|
|
8536
|
+
const projection = projections.get(id);
|
|
8537
|
+
if (projection.head.stats.message_count === 0) continue;
|
|
8538
|
+
this.rememberSession(id, {
|
|
8539
|
+
sourceFingerprint: projection.signature.digest("hex"),
|
|
8540
|
+
headParserVersion: "deepchat-v1",
|
|
8541
|
+
unpricedModels: [...projection.unpricedModels]
|
|
8542
|
+
});
|
|
8543
|
+
sessions.push(projection.head);
|
|
8544
|
+
}
|
|
8545
|
+
sessions.sort(
|
|
8546
|
+
(left, right) => (right.time_updated ?? 0) - (left.time_updated ?? 0) || left.reference.sessionId.localeCompare(right.reference.sessionId)
|
|
8547
|
+
);
|
|
8548
|
+
options?.onProgress?.({
|
|
8549
|
+
total: selected.size,
|
|
8550
|
+
processed: selected.size,
|
|
8551
|
+
sessions: sessions.length
|
|
8552
|
+
});
|
|
8553
|
+
return sessions;
|
|
8554
|
+
});
|
|
8555
|
+
}
|
|
8556
|
+
readProjections(db, sessionId) {
|
|
8557
|
+
const filter = sessionId ? "AND s.id = ?" : "";
|
|
8558
|
+
const bindings = sessionId ? [sessionId] : [];
|
|
8559
|
+
const projections = /* @__PURE__ */ new Map();
|
|
8560
|
+
const sessions = db.prepare(`
|
|
8561
|
+
SELECT s.id, s.agent_id, s.title, s.project_dir, s.parent_session_id,
|
|
8562
|
+
s.created_at, s.updated_at, s.revision, d.model_id, d.provider_id
|
|
8563
|
+
FROM new_sessions s LEFT JOIN deepchat_sessions d ON d.id = s.id
|
|
8564
|
+
WHERE s.is_draft = 0 ${filter}
|
|
8565
|
+
ORDER BY s.id
|
|
8566
|
+
`).iterate(...bindings);
|
|
8567
|
+
for (const row of sessions) {
|
|
8568
|
+
const id = String(row.id);
|
|
8569
|
+
const parent = asString(row.parent_session_id);
|
|
8570
|
+
projections.set(id, {
|
|
8571
|
+
head: {
|
|
8572
|
+
...this.sessionIdentity(id),
|
|
8573
|
+
title: resolveSessionTitle(asString(row.title), null, null),
|
|
8574
|
+
directory: asString(row.project_dir) ?? "",
|
|
8575
|
+
parent_reference: parent ? { agentName: this.name, sessionId: parent } : void 0,
|
|
8576
|
+
time_created: Number(row.created_at),
|
|
8577
|
+
time_updated: Number(row.updated_at),
|
|
8578
|
+
stats: { message_count: 0, total_input_tokens: 0, total_output_tokens: 0, total_cost: 0 }
|
|
8579
|
+
},
|
|
8580
|
+
agentId: String(row.agent_id),
|
|
8581
|
+
model: asString(row.model_id) ?? null,
|
|
8582
|
+
provider: asString(row.provider_id) ?? null,
|
|
8583
|
+
signature: createHash3("sha256").update(JSON.stringify(row)),
|
|
8584
|
+
unpricedModels: /* @__PURE__ */ new Set(),
|
|
8585
|
+
messageUsage: /* @__PURE__ */ new Map()
|
|
8586
|
+
});
|
|
8587
|
+
}
|
|
8588
|
+
const usageRows = db.prepare(`
|
|
8589
|
+
SELECT u.session_id, u.message_id, u.usage_id, u.created_at, u.updated_at,
|
|
8590
|
+
u.model_id AS model, u.provider_id AS provider,
|
|
8591
|
+
u.input_tokens AS inputTokens, u.output_tokens AS outputTokens,
|
|
8592
|
+
u.total_tokens AS totalTokens, u.cached_input_tokens AS cachedInputTokens,
|
|
8593
|
+
u.cache_write_input_tokens AS cacheWriteInputTokens
|
|
8594
|
+
FROM deepchat_usage_stats u JOIN new_sessions s ON s.id = u.session_id
|
|
8595
|
+
WHERE s.is_draft = 0 ${filter}
|
|
8596
|
+
ORDER BY u.session_id, u.usage_id
|
|
8597
|
+
`).iterate(...bindings);
|
|
8598
|
+
for (const row of usageRows) {
|
|
8599
|
+
const projection = projections.get(String(row.session_id));
|
|
8600
|
+
accumulateUsage(projection, row);
|
|
8601
|
+
projection.signature.update(JSON.stringify(row));
|
|
8602
|
+
projection.head.time_updated = Math.max(
|
|
8603
|
+
projection.head.time_updated ?? 0,
|
|
8604
|
+
Number(row.created_at)
|
|
8605
|
+
);
|
|
8606
|
+
}
|
|
8607
|
+
const messageRows = db.prepare(`
|
|
8608
|
+
SELECT m.id, m.session_id, m.order_seq, m.role, m.status, m.metadata, m.updated_at
|
|
8609
|
+
FROM deepchat_messages m JOIN new_sessions s ON s.id = m.session_id
|
|
8610
|
+
WHERE s.is_draft = 0 ${filter}
|
|
8611
|
+
ORDER BY m.session_id, m.order_seq, m.id
|
|
8612
|
+
`).iterate(...bindings);
|
|
8613
|
+
for (const row of messageRows) {
|
|
8614
|
+
const projection = projections.get(String(row.session_id));
|
|
8615
|
+
projection.signature.update(JSON.stringify(row));
|
|
8616
|
+
projection.head.stats.message_count += 1;
|
|
8617
|
+
projection.head.time_updated = Math.max(
|
|
8618
|
+
projection.head.time_updated ?? 0,
|
|
8619
|
+
Number(row.updated_at)
|
|
8620
|
+
);
|
|
8621
|
+
const metadata = asRecord(parseDeepChatJson(row.metadata));
|
|
8622
|
+
if (row.role === "assistant" && metadata && !projection.messageUsage.has(String(row.id))) {
|
|
8623
|
+
accumulateUsage(projection, { ...metadata, message_id: row.id });
|
|
8624
|
+
}
|
|
8625
|
+
}
|
|
8626
|
+
const blockActivity = db.prepare(`
|
|
8627
|
+
SELECT m.session_id, COUNT(*) AS block_count, MAX(b.updated_at) AS updated_at,
|
|
8628
|
+
SUM(b.updated_at) AS block_revision
|
|
8629
|
+
FROM deepchat_assistant_blocks b
|
|
8630
|
+
JOIN deepchat_messages m ON m.id = b.message_id
|
|
8631
|
+
JOIN new_sessions s ON s.id = m.session_id
|
|
8632
|
+
WHERE s.is_draft = 0 ${filter}
|
|
8633
|
+
GROUP BY m.session_id ORDER BY m.session_id
|
|
8634
|
+
`).iterate(...bindings);
|
|
8635
|
+
for (const row of blockActivity) {
|
|
8636
|
+
const projection = projections.get(String(row.session_id));
|
|
8637
|
+
projection.signature.update(JSON.stringify(row));
|
|
8638
|
+
projection.head.time_updated = Math.max(
|
|
8639
|
+
projection.head.time_updated ?? 0,
|
|
8640
|
+
Number(row.updated_at)
|
|
8641
|
+
);
|
|
8642
|
+
}
|
|
8643
|
+
return projections;
|
|
8644
|
+
}
|
|
8645
|
+
getSessionData(sessionId) {
|
|
8646
|
+
return this.readDatabase((db) => {
|
|
8647
|
+
const projection = this.readProjections(db, sessionId).get(sessionId);
|
|
8648
|
+
if (!projection) throw new Error(`DeepChat session not found: ${sessionId}`);
|
|
8649
|
+
const partsByMessage = this.readStructuredParts(db, sessionId);
|
|
8650
|
+
const rows = db.prepare(`
|
|
8651
|
+
SELECT id, role, content, metadata, status, created_at, updated_at
|
|
8652
|
+
FROM deepchat_messages WHERE session_id = ? ORDER BY order_seq, id
|
|
8653
|
+
`).iterate(sessionId);
|
|
8654
|
+
const messages = [];
|
|
8655
|
+
for (const row of rows) {
|
|
8656
|
+
if (row.role !== "user" && row.role !== "assistant") continue;
|
|
8657
|
+
const id = String(row.id);
|
|
8658
|
+
const metadata = asRecord(parseDeepChatJson(row.metadata));
|
|
8659
|
+
const usage = projection.messageUsage.get(id);
|
|
8660
|
+
messages.push({
|
|
8661
|
+
id,
|
|
8662
|
+
role: row.role,
|
|
8663
|
+
agent: row.role === "assistant" ? projection.agentId : void 0,
|
|
8664
|
+
time_created: Number(row.created_at),
|
|
8665
|
+
time_completed: row.status === "pending" ? void 0 : Number(row.updated_at),
|
|
8666
|
+
model: usage?.model ?? asString(metadata?.model) ?? projection.model,
|
|
8667
|
+
provider: usage?.provider ?? asString(metadata?.provider) ?? projection.provider,
|
|
8668
|
+
tokens: usage?.tokens,
|
|
8669
|
+
cost: usage?.cost,
|
|
8670
|
+
cost_source: usage && usage.cost > 0 ? "estimated" : void 0,
|
|
8671
|
+
parts: partsByMessage.get(id) ?? deepChatRawParts(row.role, String(row.content))
|
|
8672
|
+
});
|
|
8673
|
+
}
|
|
8674
|
+
return { ...projection.head, messages };
|
|
8675
|
+
});
|
|
8676
|
+
}
|
|
8677
|
+
readStructuredParts(db, sessionId) {
|
|
8678
|
+
const parts = /* @__PURE__ */ new Map();
|
|
8679
|
+
const blocks = db.prepare(`
|
|
8680
|
+
SELECT b.* FROM deepchat_assistant_blocks b
|
|
8681
|
+
JOIN deepchat_messages m ON m.id = b.message_id
|
|
8682
|
+
WHERE m.session_id = ? ORDER BY b.message_id, b.block_index
|
|
8683
|
+
`).iterate(sessionId);
|
|
8684
|
+
for (const block of blocks) {
|
|
8685
|
+
const id = String(block.message_id);
|
|
8686
|
+
const messageParts = parts.get(id) ?? [];
|
|
8687
|
+
const part = deepChatStoredBlockPart(block);
|
|
8688
|
+
if (part) messageParts.push(part);
|
|
8689
|
+
parts.set(id, messageParts);
|
|
8690
|
+
}
|
|
8691
|
+
const users = db.prepare(`
|
|
8692
|
+
SELECT u.message_id, u.text FROM deepchat_user_messages u
|
|
8693
|
+
JOIN deepchat_messages m ON m.id = u.message_id WHERE m.session_id = ?
|
|
8694
|
+
`).iterate(sessionId);
|
|
8695
|
+
for (const user of users) parts.set(String(user.message_id), deepChatUserParts(user));
|
|
8696
|
+
const attachments = db.prepare(`
|
|
8697
|
+
SELECT f.message_id, f.path, f.name FROM deepchat_user_message_files f
|
|
8698
|
+
JOIN deepchat_messages m ON m.id = f.message_id
|
|
8699
|
+
WHERE m.session_id = ? ORDER BY f.message_id, f.ordinal
|
|
8700
|
+
`).iterate(sessionId);
|
|
8701
|
+
for (const attachment of attachments) {
|
|
8702
|
+
parts.get(String(attachment.message_id))?.push(...deepChatUserParts({ files: [attachment] }));
|
|
8703
|
+
}
|
|
8704
|
+
const links = db.prepare(`
|
|
8705
|
+
SELECT l.message_id, l.url FROM deepchat_user_message_links l
|
|
8706
|
+
JOIN deepchat_messages m ON m.id = l.message_id
|
|
8707
|
+
WHERE m.session_id = ? ORDER BY l.message_id, l.ordinal
|
|
8708
|
+
`).iterate(sessionId);
|
|
8709
|
+
for (const link of links)
|
|
8710
|
+
parts.get(String(link.message_id))?.push(...deepChatUserParts({ links: [link.url] }));
|
|
8711
|
+
return parts;
|
|
8712
|
+
}
|
|
8713
|
+
};
|
|
8714
|
+
function jsonRecord(value) {
|
|
8715
|
+
return asRecord(typeof value === "string" ? JSON.parse(value) : value);
|
|
8716
|
+
}
|
|
8717
|
+
function nonnegative(value) {
|
|
8718
|
+
return Math.max(0, asNumber(value) ?? 0);
|
|
8719
|
+
}
|
|
8720
|
+
function tokensFromStats(stats) {
|
|
8721
|
+
if (!stats) return void 0;
|
|
8722
|
+
const input = asRecord(stats.inputTokenDetails);
|
|
8723
|
+
const output = asRecord(stats.outputTokenDetails);
|
|
8724
|
+
return {
|
|
8725
|
+
input: asNumber(stats.inputTokens) ?? nonnegative(input?.noCacheTokens) + nonnegative(input?.cacheReadTokens) + nonnegative(input?.cacheWriteTokens),
|
|
8726
|
+
output: asNumber(stats.outputTokens) ?? nonnegative(output?.textTokens) + nonnegative(output?.reasoningTokens),
|
|
8727
|
+
cache_read: nonnegative(input?.cacheReadTokens),
|
|
8728
|
+
cache_create: nonnegative(input?.cacheWriteTokens),
|
|
8729
|
+
reasoning: nonnegative(output?.reasoningTokens)
|
|
8730
|
+
};
|
|
8731
|
+
}
|
|
8732
|
+
function messageCost(stats, model, tokens) {
|
|
8733
|
+
const costs = (asArray(stats?.costs) ?? []).flatMap((value) => {
|
|
8734
|
+
const cost2 = asRecord(value);
|
|
8735
|
+
return cost2 ? [cost2] : [];
|
|
8736
|
+
});
|
|
8737
|
+
if (costs.length > 0 && costs.every((cost2) => cost2.currency === "USD")) {
|
|
8738
|
+
return {
|
|
8739
|
+
cost: costs.reduce((sum, cost2) => sum + nonnegative(cost2.amount), 0),
|
|
8740
|
+
costSource: costs.some((cost2) => nonnegative(cost2.computedRequestCount) > 0) ? "estimated" : "recorded"
|
|
8741
|
+
};
|
|
8742
|
+
}
|
|
8743
|
+
const cost = estimateTokenCost(model, tokens ? { ...tokens, reasoning: 0 } : void 0);
|
|
8744
|
+
return {
|
|
8745
|
+
cost: cost ?? void 0,
|
|
8746
|
+
costSource: cost === null ? void 0 : "estimated"
|
|
8747
|
+
};
|
|
8748
|
+
}
|
|
8749
|
+
function convertPart(part) {
|
|
8750
|
+
const type = asString(part.type);
|
|
8751
|
+
const text = asString(part.text);
|
|
8752
|
+
if ((type === "text" || type === "reasoning") && text) return { type, text };
|
|
8753
|
+
if (type === "dynamic-tool" || type?.startsWith("tool-")) {
|
|
8754
|
+
const state = asString(part.state);
|
|
8755
|
+
const failed = state === "output-error" || state === "output-denied";
|
|
8756
|
+
return {
|
|
8757
|
+
type: "tool",
|
|
8758
|
+
tool: asString(part.toolName) ?? (type === "dynamic-tool" ? "unknown" : type.slice(5)),
|
|
8759
|
+
callID: asString(part.toolCallId),
|
|
8760
|
+
title: asString(part.title),
|
|
8761
|
+
state: {
|
|
8762
|
+
status: failed ? "error" : state === "output-available" ? "completed" : "running",
|
|
8763
|
+
input: part.input,
|
|
8764
|
+
output: part.output,
|
|
8765
|
+
error: failed ? part.errorText ?? "Tool execution failed" : void 0,
|
|
8766
|
+
metadata: part.providerMetadata
|
|
8767
|
+
}
|
|
8768
|
+
};
|
|
8769
|
+
}
|
|
8770
|
+
if (type === "file") {
|
|
8771
|
+
const url = asString(part.url);
|
|
8772
|
+
const mime = asString(part.mediaType);
|
|
8773
|
+
if (url && mime?.startsWith("image/")) return { type: "image", url, mime_type: mime };
|
|
8774
|
+
const label = asString(part.filename) ?? url;
|
|
8775
|
+
return label ? { type: "text", text: `Attachment: ${label}` } : null;
|
|
8776
|
+
}
|
|
8777
|
+
const data = asRecord(part.data);
|
|
8778
|
+
if (type === "data-error") {
|
|
8779
|
+
const message = asString(data?.message);
|
|
8780
|
+
return message ? { type: "text", text: message } : null;
|
|
8781
|
+
}
|
|
8782
|
+
if (type === "data-compact" || type === "data-code" || type === "data-translation") {
|
|
8783
|
+
const content = asString(data?.content);
|
|
8784
|
+
return content ? { type: "text", text: content } : null;
|
|
8785
|
+
}
|
|
8786
|
+
return null;
|
|
8787
|
+
}
|
|
8788
|
+
function cherryStudioTranscript(rows) {
|
|
8789
|
+
const builder = new TranscriptBuilder();
|
|
8790
|
+
const modelUsage = /* @__PURE__ */ Object.create(null);
|
|
8791
|
+
let totalTokens = 0;
|
|
8792
|
+
for (const row of rows) {
|
|
8793
|
+
if (row.role !== "user" && row.role !== "assistant") continue;
|
|
8794
|
+
const data = jsonRecord(row.data);
|
|
8795
|
+
const snapshot = jsonRecord(row.message_snapshot);
|
|
8796
|
+
const modelSnapshot = asRecord(snapshot?.model);
|
|
8797
|
+
const uniqueModel = asString(row.model_id);
|
|
8798
|
+
const separator = uniqueModel?.indexOf("::") ?? -1;
|
|
8799
|
+
const model = asString(modelSnapshot?.id) ?? (separator >= 0 ? uniqueModel?.slice(separator + 2) : uniqueModel);
|
|
8800
|
+
const provider = asString(modelSnapshot?.provider) ?? (separator >= 0 ? uniqueModel?.slice(0, separator) : void 0);
|
|
8801
|
+
const stats = row.role === "assistant" ? jsonRecord(row.stats) : void 0;
|
|
8802
|
+
const tokens = tokensFromStats(stats);
|
|
8803
|
+
const total = nonnegative(stats?.totalTokens ?? (tokens?.input ?? 0) + (tokens?.output ?? 0));
|
|
8804
|
+
totalTokens += total;
|
|
8805
|
+
if (model && total > 0) modelUsage[model] = (modelUsage[model] ?? 0) + total;
|
|
8806
|
+
const message = builder.appendMessage({
|
|
8807
|
+
id: String(row.id),
|
|
8808
|
+
role: row.role,
|
|
8809
|
+
timestampMs: Number(row.created_at),
|
|
8810
|
+
agent: asString(snapshot?.name),
|
|
8811
|
+
model,
|
|
8812
|
+
provider,
|
|
8813
|
+
tokens,
|
|
8814
|
+
...messageCost(stats, model, tokens),
|
|
8815
|
+
parts: (asArray(data?.parts) ?? []).flatMap((value) => {
|
|
8816
|
+
const part = asRecord(value);
|
|
8817
|
+
const converted = part ? convertPart(part) : null;
|
|
8818
|
+
return converted ? [converted] : [];
|
|
8819
|
+
})
|
|
8820
|
+
});
|
|
8821
|
+
if (row.status !== "pending") message.time_completed = Number(row.updated_at);
|
|
8822
|
+
}
|
|
8823
|
+
const transcript = builder.finish();
|
|
8824
|
+
return {
|
|
8825
|
+
...transcript,
|
|
8826
|
+
stats: { ...transcript.stats, total_tokens: totalTokens },
|
|
8827
|
+
modelUsage
|
|
8828
|
+
};
|
|
8829
|
+
}
|
|
8830
|
+
var AGENT_METADATA12 = getAgentCatalogEntry("cherrystudio");
|
|
8831
|
+
function resolveCherryStudioDataRoot() {
|
|
8832
|
+
const configured = readEnvPath("CHERRYSTUDIO_USER_DATA_DIR");
|
|
8833
|
+
if (configured) return configured;
|
|
8834
|
+
if (platform5() === "darwin")
|
|
8835
|
+
return join16(homedir5(), "Library", "Application Support", "CherryStudio");
|
|
8836
|
+
if (platform5() === "win32") {
|
|
8837
|
+
return join16(readEnvPath("APPDATA") ?? join16(homedir5(), "AppData", "Roaming"), "CherryStudio");
|
|
8838
|
+
}
|
|
8839
|
+
return join16(readEnvPath("XDG_CONFIG_HOME") ?? join16(homedir5(), ".config"), "CherryStudio");
|
|
8840
|
+
}
|
|
8841
|
+
function liveRows(db, table, alias) {
|
|
8842
|
+
const columns = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
8843
|
+
return columns.some((column) => column.name === "deleted_at") ? `${alias}.deleted_at IS NULL` : "1 = 1";
|
|
8844
|
+
}
|
|
8845
|
+
function activeBranch(rows, activeId) {
|
|
8846
|
+
const byId = new Map(rows.map((row) => [String(row.id), row]));
|
|
8847
|
+
const selected = [];
|
|
8848
|
+
const visited = /* @__PURE__ */ new Set();
|
|
8849
|
+
let id = asString(activeId);
|
|
8850
|
+
while (id) {
|
|
8851
|
+
if (visited.has(id)) throw new Error("Cherry Studio message branch contains a cycle");
|
|
8852
|
+
visited.add(id);
|
|
8853
|
+
const row = byId.get(id);
|
|
8854
|
+
if (!row) break;
|
|
8855
|
+
selected.push(row);
|
|
8856
|
+
id = asString(row.parent_id);
|
|
8857
|
+
}
|
|
8858
|
+
return selected.reverse();
|
|
8859
|
+
}
|
|
8860
|
+
var CherryStudioAgent = class extends DatabaseSessionSource {
|
|
8861
|
+
name = AGENT_METADATA12.name;
|
|
8862
|
+
displayName = AGENT_METADATA12.displayName;
|
|
8863
|
+
sourceRoot;
|
|
8864
|
+
constructor(options = {}) {
|
|
8865
|
+
super();
|
|
8866
|
+
this.sourceRoot = options.sourceRoot ?? resolveCherryStudioDataRoot();
|
|
8867
|
+
}
|
|
8868
|
+
getDatabasePath() {
|
|
8869
|
+
return firstExisting(join16(this.sourceRoot, "Data", "cherrystudio.sqlite"));
|
|
8870
|
+
}
|
|
8871
|
+
isAvailable() {
|
|
8872
|
+
return isSqliteAvailable() && this.getDatabasePath() !== null;
|
|
8873
|
+
}
|
|
8874
|
+
getSessionWatchPlan() {
|
|
8875
|
+
return {
|
|
8876
|
+
status: "supported",
|
|
8877
|
+
targets: [
|
|
8878
|
+
{ root: this.sourceRoot, path: join16(this.sourceRoot, "Data", "cherrystudio.sqlite") }
|
|
8879
|
+
]
|
|
8880
|
+
};
|
|
8881
|
+
}
|
|
8882
|
+
readDatabase(read) {
|
|
8883
|
+
const path = this.getDatabasePath();
|
|
8884
|
+
if (!path) throw new Error("Cherry Studio 2.x cherrystudio.sqlite is missing");
|
|
8885
|
+
return this.scanStep("reading Cherry Studio 2.x cherrystudio.sqlite", path, () => {
|
|
8886
|
+
const db = openDbReadOnly(path);
|
|
8887
|
+
if (!db) throw new Error("Cannot open Cherry Studio database");
|
|
8888
|
+
try {
|
|
8889
|
+
return db.transaction(() => read(db))();
|
|
8890
|
+
} finally {
|
|
8891
|
+
db.close();
|
|
8892
|
+
}
|
|
8893
|
+
});
|
|
8894
|
+
}
|
|
8895
|
+
scan(options) {
|
|
8896
|
+
if (!this.getDatabasePath()) return [];
|
|
8897
|
+
return this.readDatabase((db) => {
|
|
8898
|
+
const sessions = [];
|
|
8899
|
+
for (const kind of ["agent", "topic"]) {
|
|
8900
|
+
for (const projection of this.readConversations(db, kind)) {
|
|
8901
|
+
const { messages: _messages, ...head } = projection.session;
|
|
8902
|
+
if (!head.stats.message_count || !matchesScanWindow(head.time_updated ?? head.time_created, options))
|
|
8903
|
+
continue;
|
|
8904
|
+
this.rememberSession(head.reference.sessionId, {
|
|
8905
|
+
sourceFingerprint: projection.fingerprint,
|
|
8906
|
+
headParserVersion: "cherrystudio-v1",
|
|
8907
|
+
unpricedModels: projection.unpricedModels
|
|
8908
|
+
});
|
|
8909
|
+
sessions.push(head);
|
|
8910
|
+
}
|
|
8911
|
+
}
|
|
8912
|
+
sessions.sort(
|
|
8913
|
+
(left, right) => (right.time_updated ?? 0) - (left.time_updated ?? 0) || left.reference.sessionId.localeCompare(right.reference.sessionId)
|
|
8914
|
+
);
|
|
8915
|
+
options?.onProgress?.({
|
|
8916
|
+
total: sessions.length,
|
|
8917
|
+
processed: sessions.length,
|
|
8918
|
+
sessions: sessions.length
|
|
8919
|
+
});
|
|
8920
|
+
return sessions;
|
|
8921
|
+
});
|
|
8922
|
+
}
|
|
8923
|
+
getSessionData(sessionId) {
|
|
8924
|
+
const separator = sessionId.indexOf(":");
|
|
8925
|
+
const kind = sessionId.slice(0, separator);
|
|
8926
|
+
const id = sessionId.slice(separator + 1);
|
|
8927
|
+
if (kind !== "agent" && kind !== "topic" || !id)
|
|
8928
|
+
throw new Error(`Invalid Cherry Studio session: ${sessionId}`);
|
|
8929
|
+
return this.readDatabase((db) => {
|
|
8930
|
+
for (const projection of this.readConversations(db, kind, id)) return projection.session;
|
|
8931
|
+
throw new Error(`Cherry Studio session not found: ${sessionId}`);
|
|
8932
|
+
});
|
|
8933
|
+
}
|
|
8934
|
+
*readConversations(db, kind, id) {
|
|
8935
|
+
const table = kind === "agent" ? "agent_session" : "topic";
|
|
8936
|
+
const messageTable = kind === "agent" ? "agent_session_message" : "message";
|
|
8937
|
+
const foreignKey = kind === "agent" ? "session_id" : "topic_id";
|
|
8938
|
+
const filter = `${liveRows(db, table, "s")} ${id ? "AND s.id = ?" : ""}`;
|
|
8939
|
+
const bindings = id ? [id] : [];
|
|
8940
|
+
const headers = db.prepare(`
|
|
8941
|
+
SELECT s.id, s.name, s.created_at, s.updated_at, s.last_activity_at,
|
|
8942
|
+
${kind === "agent" ? "w.path AS directory, NULL AS active_node_id" : "NULL AS directory, s.active_node_id"}
|
|
8943
|
+
FROM ${table} s ${kind === "agent" ? "LEFT JOIN agent_workspace w ON w.id = s.workspace_id" : ""}
|
|
8944
|
+
WHERE ${filter}
|
|
8945
|
+
`).all(...bindings);
|
|
8946
|
+
const byId = new Map(headers.map((row) => [String(row.id), row]));
|
|
8947
|
+
const messages = db.prepare(`
|
|
8948
|
+
SELECT m.id, m.${foreignKey} AS conversation_id, m.role, m.data, m.stats,
|
|
8949
|
+
m.model_id, m.message_snapshot, m.status, m.created_at, m.updated_at,
|
|
8950
|
+
${kind === "topic" ? "m.parent_id" : "NULL AS parent_id"}
|
|
8951
|
+
FROM ${messageTable} m JOIN ${table} s ON s.id = m.${foreignKey}
|
|
8952
|
+
WHERE ${filter} AND ${liveRows(db, messageTable, "m")}
|
|
8953
|
+
ORDER BY m.${foreignKey}, m.created_at, m.id
|
|
8954
|
+
`).iterate(...bindings);
|
|
8955
|
+
let currentId;
|
|
8956
|
+
let rows = [];
|
|
8957
|
+
for (const row of messages) {
|
|
8958
|
+
const nextId = String(row.conversation_id);
|
|
8959
|
+
if (currentId !== void 0 && nextId !== currentId) {
|
|
8960
|
+
yield this.projectConversation(kind, byId.get(currentId), rows);
|
|
8961
|
+
rows = [];
|
|
8962
|
+
}
|
|
8963
|
+
currentId = nextId;
|
|
8964
|
+
rows.push(row);
|
|
8965
|
+
}
|
|
8966
|
+
if (currentId !== void 0) yield this.projectConversation(kind, byId.get(currentId), rows);
|
|
8967
|
+
}
|
|
8968
|
+
projectConversation(kind, row, rows) {
|
|
8969
|
+
const selected = kind === "topic" ? activeBranch(rows, row.active_node_id) : rows;
|
|
8970
|
+
const { result: transcript, unpricedModels } = capturePricingMisses(
|
|
8971
|
+
() => cherryStudioTranscript(selected)
|
|
8972
|
+
);
|
|
8973
|
+
const signature = createHash4("sha256").update(JSON.stringify(row));
|
|
8974
|
+
for (const message of selected) signature.update(JSON.stringify(message));
|
|
8975
|
+
const session = {
|
|
8976
|
+
...this.sessionIdentity(`${kind}:${row.id}`),
|
|
8977
|
+
title: resolveSessionTitle(
|
|
8978
|
+
asString(row.name),
|
|
8979
|
+
firstUserMessageTitle(transcript.messages),
|
|
8980
|
+
"Cherry Studio"
|
|
8981
|
+
),
|
|
8982
|
+
directory: asString(row.directory) || this.sourceRoot,
|
|
8983
|
+
time_created: Number(row.created_at),
|
|
8984
|
+
time_updated: Number(row.last_activity_at),
|
|
8985
|
+
stats: transcript.stats,
|
|
8986
|
+
model_usage: transcript.modelUsage,
|
|
8987
|
+
messages: transcript.messages
|
|
8988
|
+
};
|
|
8989
|
+
return { session, fingerprint: signature.digest("hex"), unpricedModels };
|
|
8990
|
+
}
|
|
8991
|
+
};
|
|
8308
8992
|
var RUNTIME_REGISTRATIONS = {
|
|
8309
8993
|
claudecode: {
|
|
8310
8994
|
create: () => new ClaudeCodeAgent(),
|
|
@@ -8345,6 +9029,14 @@ var RUNTIME_REGISTRATIONS = {
|
|
|
8345
9029
|
dsh: {
|
|
8346
9030
|
create: () => new DshAgent(),
|
|
8347
9031
|
resolveDataRoot: resolveDshDataRoot
|
|
9032
|
+
},
|
|
9033
|
+
deepchat: {
|
|
9034
|
+
create: () => new DeepChatAgent(),
|
|
9035
|
+
resolveDataRoot: resolveDeepChatDataRoot
|
|
9036
|
+
},
|
|
9037
|
+
cherrystudio: {
|
|
9038
|
+
create: () => new CherryStudioAgent(),
|
|
9039
|
+
resolveDataRoot: resolveCherryStudioDataRoot
|
|
8348
9040
|
}
|
|
8349
9041
|
};
|
|
8350
9042
|
var AGENT_REGISTRATIONS = Object.freeze(
|
|
@@ -8387,4 +9079,4 @@ export {
|
|
|
8387
9079
|
createRegisteredAgents,
|
|
8388
9080
|
getAgentInfoMap
|
|
8389
9081
|
};
|
|
8390
|
-
//# sourceMappingURL=chunk-
|
|
9082
|
+
//# sourceMappingURL=chunk-ZDH2BKQK.js.map
|