chatlab-cli 0.22.1 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-OC2W5Q5T.mjs → chunk-3MX7VF2B.mjs} +2 -2
- package/dist/chunk-5ADKYYNA.mjs +28 -0
- package/dist/chunk-5ADKYYNA.mjs.map +1 -0
- package/dist/{chunk-QRC3RSER.mjs → chunk-643S2N2U.mjs} +2 -2
- package/dist/{chunk-XPBPKH6B.mjs → chunk-D2BR3MFN.mjs} +107 -37
- package/dist/chunk-D2BR3MFN.mjs.map +1 -0
- package/dist/{chunk-6NB475AA.mjs → chunk-FJ35V3TE.mjs} +2 -17
- package/dist/chunk-FJ35V3TE.mjs.map +1 -0
- package/dist/{chunk-SQKT45MM.mjs → chunk-G7Q7EQ3V.mjs} +546 -84
- package/dist/chunk-G7Q7EQ3V.mjs.map +1 -0
- package/dist/{chunk-LZ3W6NS5.mjs → chunk-NTWDG52H.mjs} +66 -68
- package/dist/chunk-NTWDG52H.mjs.map +1 -0
- package/dist/{chunk-Z2LYMKCC.mjs → chunk-WTQ7LAZR.mjs} +2 -2
- package/dist/cli.mjs +4 -3
- package/dist/{http-O5P4BYXU.mjs → http-2DN3XOXO.mjs} +8 -7
- package/dist/{import-BDLL3DG7.mjs → import-LCBSBLYF.mjs} +4 -4
- package/dist/index.mjs +10 -9
- package/dist/{mcp-L2TPZFE7.mjs → mcp-AR7HBIK4.mjs} +8 -6
- package/dist/{mcp-L2TPZFE7.mjs.map → mcp-AR7HBIK4.mjs.map} +1 -1
- package/dist/service-WNEVPQ4N.mjs +258 -0
- package/dist/service-WNEVPQ4N.mjs.map +1 -0
- package/dist/{src-FVJL5ENA.mjs → src-EGXULYFQ.mjs} +2 -2
- package/dist/{stream-import-ZTEW3YVL.mjs → stream-import-QM5R5FDG.mjs} +3 -3
- package/dist/{update-checker-MQMQ6A4B.mjs → update-checker-JG5K67O2.mjs} +3 -2
- package/dist/{update-checker-MQMQ6A4B.mjs.map → update-checker-JG5K67O2.mjs.map} +1 -1
- package/dist-web/assets/{DebugToolsPanel-DkbsB6lr.css → DebugToolsPanel-D9O_4J04.css} +1 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-hp9Mjpub.js +161 -0
- package/dist-web/assets/{EChartWordcloud-Ubal_aYg.js → EChartWordcloud-Cenbzcyj.js} +1 -1
- package/dist-web/assets/MessageExportModal-CvocO88D.js +1 -0
- package/dist-web/assets/electron-DpE69lO4.js +1 -0
- package/dist-web/assets/electron-SyPZX9OU.js +1 -0
- package/dist-web/assets/{fetch-BS4SlQjA.js → fetch-B7OBmANJ.js} +1 -1
- package/dist-web/assets/{fetch-o5NJ2uWE.js → fetch-BikSxuED.js} +1 -1
- package/dist-web/assets/fetch-BwMZFwbF.js +1 -0
- package/dist-web/assets/fetch-CfTcWxqG.js +1 -0
- package/dist-web/assets/fetch-DTP8Q782.js +17 -0
- package/dist-web/assets/{fetch-W43zfemj.js → fetch-LBHcBBkv.js} +1 -1
- package/dist-web/assets/http-C741fIwb.js +1 -0
- package/dist-web/assets/index-B6dkyIiA.js +2 -0
- package/dist-web/assets/index-CALU1QPF.js +163 -0
- package/dist-web/assets/{index-DOwQB7In.js → index-CHkXbqMb.js} +1 -1
- package/dist-web/assets/{index-DSpvXged.css → index-CvuHOeoU.css} +1 -1
- package/dist-web/assets/{index-BE64tUWq.css → index-CxMP0DNd.css} +1 -1
- package/dist-web/assets/index-DOS5o2_H.js +7 -0
- package/dist-web/assets/{index-CbQMfheg.css → index-DuepdDzz.css} +1 -1
- package/dist-web/assets/index-niwrSprs.js +173 -0
- package/dist-web/assets/model-catalog-DUuKjIVU.js +1 -0
- package/dist-web/assets/{vendor-nuxt-ui-7OAuiz_i.js → vendor-nuxt-ui-CuCZ1aRl.js} +2 -2
- package/dist-web/assets/vendor-reka-ui-BrTYuIfH.js +11 -0
- package/dist-web/assets/{web-Cx5APyCN.js → web-DGd63PrV.js} +1 -1
- package/dist-web/index.html +4 -4
- package/package.json +1 -1
- package/dist/chunk-6NB475AA.mjs.map +0 -1
- package/dist/chunk-LZ3W6NS5.mjs.map +0 -1
- package/dist/chunk-SQKT45MM.mjs.map +0 -1
- package/dist/chunk-XPBPKH6B.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-CqacsKDU.js +0 -147
- package/dist-web/assets/MessageExportModal-D1GY6WSV.js +0 -1
- package/dist-web/assets/electron-8qi0d92j.js +0 -1
- package/dist-web/assets/electron-CsUM2O_Y.js +0 -1
- package/dist-web/assets/fetch-BOogCPfg.js +0 -1
- package/dist-web/assets/fetch-CclRWOHf.js +0 -1
- package/dist-web/assets/fetch-CxwnEEqk.js +0 -17
- package/dist-web/assets/http-CeXMt-Fv.js +0 -1
- package/dist-web/assets/index-CM29Kc4p.js +0 -173
- package/dist-web/assets/index-D183wYuz.js +0 -7
- package/dist-web/assets/index-DTxRy2FH.js +0 -163
- package/dist-web/assets/index-grds3iG-.js +0 -2
- package/dist-web/assets/vendor-reka-ui-CW2cIgMu.js +0 -11
- /package/dist/{chunk-OC2W5Q5T.mjs.map → chunk-3MX7VF2B.mjs.map} +0 -0
- /package/dist/{chunk-QRC3RSER.mjs.map → chunk-643S2N2U.mjs.map} +0 -0
- /package/dist/{chunk-Z2LYMKCC.mjs.map → chunk-WTQ7LAZR.mjs.map} +0 -0
- /package/dist/{http-O5P4BYXU.mjs.map → http-2DN3XOXO.mjs.map} +0 -0
- /package/dist/{import-BDLL3DG7.mjs.map → import-LCBSBLYF.mjs.map} +0 -0
- /package/dist/{src-FVJL5ENA.mjs.map → src-EGXULYFQ.mjs.map} +0 -0
- /package/dist/{stream-import-ZTEW3YVL.mjs.map → stream-import-QM5R5FDG.mjs.map} +0 -0
|
@@ -2022,6 +2022,25 @@ function getSessionSummaries(db, options) {
|
|
|
2022
2022
|
});
|
|
2023
2023
|
}
|
|
2024
2024
|
var DEFAULT_SESSION_GAP_THRESHOLD = 1800;
|
|
2025
|
+
function getSessionIndexStats(db) {
|
|
2026
|
+
let sessionCount = 0;
|
|
2027
|
+
if (hasTable(db, "chat_session")) {
|
|
2028
|
+
try {
|
|
2029
|
+
const row = db.prepare("SELECT COUNT(*) as count FROM chat_session").get();
|
|
2030
|
+
sessionCount = row?.count ?? 0;
|
|
2031
|
+
} catch {
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
let gapThreshold = DEFAULT_SESSION_GAP_THRESHOLD;
|
|
2035
|
+
try {
|
|
2036
|
+
const meta = db.prepare("SELECT session_gap_threshold FROM meta LIMIT 1").get();
|
|
2037
|
+
if (meta?.session_gap_threshold) {
|
|
2038
|
+
gapThreshold = meta.session_gap_threshold;
|
|
2039
|
+
}
|
|
2040
|
+
} catch {
|
|
2041
|
+
}
|
|
2042
|
+
return { sessionCount, hasIndex: sessionCount > 0, gapThreshold };
|
|
2043
|
+
}
|
|
2025
2044
|
function getChatSessionList(db) {
|
|
2026
2045
|
if (!hasTable(db, "chat_session")) return [];
|
|
2027
2046
|
try {
|
|
@@ -5774,6 +5793,138 @@ function needsStreamingThinkParsing(provider, _modelId) {
|
|
|
5774
5793
|
return provider === "minimax";
|
|
5775
5794
|
}
|
|
5776
5795
|
|
|
5796
|
+
// ../../packages/core/src/ai/thinking.ts
|
|
5797
|
+
var TYPE_LEVEL_MAP = {
|
|
5798
|
+
gpt5: {
|
|
5799
|
+
minimal: "minimal",
|
|
5800
|
+
low: "low",
|
|
5801
|
+
medium: "medium",
|
|
5802
|
+
high: "high"
|
|
5803
|
+
},
|
|
5804
|
+
gpt5_1: {
|
|
5805
|
+
off: "none",
|
|
5806
|
+
low: "low",
|
|
5807
|
+
medium: "medium",
|
|
5808
|
+
high: "high",
|
|
5809
|
+
xhigh: null
|
|
5810
|
+
},
|
|
5811
|
+
gpt5_2plus: {
|
|
5812
|
+
off: "none",
|
|
5813
|
+
minimal: "minimal",
|
|
5814
|
+
low: "low",
|
|
5815
|
+
medium: "medium",
|
|
5816
|
+
high: "high",
|
|
5817
|
+
xhigh: "xhigh"
|
|
5818
|
+
},
|
|
5819
|
+
grok: {
|
|
5820
|
+
minimal: null,
|
|
5821
|
+
low: "low",
|
|
5822
|
+
medium: null,
|
|
5823
|
+
high: "high",
|
|
5824
|
+
xhigh: null
|
|
5825
|
+
},
|
|
5826
|
+
kimi: {
|
|
5827
|
+
off: "none",
|
|
5828
|
+
auto: "auto",
|
|
5829
|
+
minimal: null,
|
|
5830
|
+
low: "low",
|
|
5831
|
+
medium: "medium",
|
|
5832
|
+
high: "high",
|
|
5833
|
+
xhigh: null
|
|
5834
|
+
},
|
|
5835
|
+
doubao: {
|
|
5836
|
+
off: null,
|
|
5837
|
+
auto: "auto",
|
|
5838
|
+
high: "high"
|
|
5839
|
+
},
|
|
5840
|
+
deepseek_hybrid: {
|
|
5841
|
+
off: null,
|
|
5842
|
+
auto: "auto",
|
|
5843
|
+
high: "high"
|
|
5844
|
+
}
|
|
5845
|
+
};
|
|
5846
|
+
var REASONING_FALLBACK_REGEX = /^(?!.*-non-reasoning\b)(o\d+(?:-[\w-]+)?|.*\b(?:reasoning|reasoner|thinking|think)\b.*|.*-[rR]\d+.*|.*\bqwq(?:-[\w-]+)?\b.*|.*\bhunyuan-t1(?:-[\w-]+)?\b.*|.*\bgrok-(?:3-mini|4|4-fast|build)(?:-[\w-]+)?\b.*)$/i;
|
|
5847
|
+
function classifyThinkingType(provider, modelId) {
|
|
5848
|
+
const id = modelId.toLowerCase();
|
|
5849
|
+
const prov = provider.toLowerCase();
|
|
5850
|
+
if (id.includes("-non-reasoning")) return "none";
|
|
5851
|
+
if (prov === "anthropic") return "none";
|
|
5852
|
+
if (prov === "gemini") {
|
|
5853
|
+
if (/gemini-(?:2\.5|3(?:\.\d+)?-(?:flash|pro)|flash-latest|pro-latest)/i.test(id)) return "gemini";
|
|
5854
|
+
return "none";
|
|
5855
|
+
}
|
|
5856
|
+
if (prov === "qwen" || /\bqwen|qwq/i.test(id)) return "qwen";
|
|
5857
|
+
if (/deepseek[_-]v([4-9]|\d{2,})/i.test(id) || /deepseek-ai\/deepseek-r1/i.test(id)) return "deepseek_v4";
|
|
5858
|
+
if (/deepseek[_-]chat|deepseek[_-]v3/i.test(id)) return "deepseek_hybrid";
|
|
5859
|
+
if (prov === "openai" || prov === "openai-compatible") {
|
|
5860
|
+
if (/gpt-5\.[2-9]|gpt-5\.[1-9]\d/.test(id)) return "gpt5_2plus";
|
|
5861
|
+
if (/gpt-5\.1/.test(id)) return "gpt5_1";
|
|
5862
|
+
if (/gpt-5/.test(id)) return "gpt5";
|
|
5863
|
+
if (/^o\d/.test(id)) return "o_series";
|
|
5864
|
+
}
|
|
5865
|
+
if (/^o\d/.test(id)) return "o_series";
|
|
5866
|
+
if (/\bgrok-(?:3-mini|4|4-fast|build)\b/i.test(id)) return "grok";
|
|
5867
|
+
if (/\bkimi-k(?:2-thinking|2\.[5-9]|[3-9])/i.test(id)) return "kimi";
|
|
5868
|
+
if (prov === "kimi" && /thinking/i.test(id)) return "kimi";
|
|
5869
|
+
if (/\bdoubao-.*seed/i.test(id) || prov === "doubao" && /seed/i.test(id)) return "doubao";
|
|
5870
|
+
if (/\bhunyuan-(?:t1|a13b)/i.test(id)) return "hunyuan";
|
|
5871
|
+
if (prov === "glm" || /\bglm-?(?:5|4\.[5-7]|z1|zero)/i.test(id)) return "qwen";
|
|
5872
|
+
if (prov === "siliconflow" && /r[1-9]/i.test(id)) return "deepseek_v4";
|
|
5873
|
+
if (prov === "openrouter") {
|
|
5874
|
+
if (/deepseek.*(v[4-9]|r\d)/i.test(id)) return "deepseek_v4";
|
|
5875
|
+
if (/deepseek[_-]?(chat|v3)/i.test(id)) return "deepseek_hybrid";
|
|
5876
|
+
if (/\bgrok-(?:3-mini|4|4-fast|build)\b/i.test(id)) return "grok";
|
|
5877
|
+
if (/\bkimi-k(?:2-thinking|2\.[5-9]|[3-9])/i.test(id)) return "kimi";
|
|
5878
|
+
if (REASONING_FALLBACK_REGEX.test(id)) return "default";
|
|
5879
|
+
return "none";
|
|
5880
|
+
}
|
|
5881
|
+
if (/\bmimo-v2/i.test(id)) return "deepseek_hybrid";
|
|
5882
|
+
if (/\bminimax-m[123]/i.test(id)) return "deepseek_hybrid";
|
|
5883
|
+
if (/\bseed-oss/i.test(id)) return "deepseek_hybrid";
|
|
5884
|
+
if (/\bbaichuan-m[23]/i.test(id)) return "default";
|
|
5885
|
+
if (/\bmagistral/i.test(id)) return "default";
|
|
5886
|
+
if (/\bmistral-small-2603/i.test(id)) return "default";
|
|
5887
|
+
if (/\bstep-(?:3|r1-v-mini)/i.test(id)) return "default";
|
|
5888
|
+
if (/\bgemma-?4/i.test(id)) return "default";
|
|
5889
|
+
if (/\bpangu-pro-moe/i.test(id)) return "default";
|
|
5890
|
+
if (/\bsonar-deep-research/i.test(id)) return "default";
|
|
5891
|
+
if (/\bring-(?:1t|mini|flash)/i.test(id)) return "default";
|
|
5892
|
+
if (/\bqwen|qwq/i.test(id)) return "qwen";
|
|
5893
|
+
if (/deepseek[_-]?r\d|deepseek[_-]?v[4-9]/i.test(id)) return "deepseek_v4";
|
|
5894
|
+
if (/^o\d/i.test(id)) return "o_series";
|
|
5895
|
+
if (REASONING_FALLBACK_REGEX.test(id)) return "default";
|
|
5896
|
+
return "none";
|
|
5897
|
+
}
|
|
5898
|
+
function isReasoningModel(provider, modelId) {
|
|
5899
|
+
return classifyThinkingType(provider, modelId) !== "none";
|
|
5900
|
+
}
|
|
5901
|
+
function getThinkingCompat(provider, modelId) {
|
|
5902
|
+
const type = classifyThinkingType(provider, modelId);
|
|
5903
|
+
if (type === "none") return {};
|
|
5904
|
+
if (type === "gemini") return {};
|
|
5905
|
+
if (type === "qwen" || type === "hunyuan") {
|
|
5906
|
+
return { thinkingFormat: "qwen" };
|
|
5907
|
+
}
|
|
5908
|
+
if (type === "deepseek_v4") {
|
|
5909
|
+
return {
|
|
5910
|
+
thinkingFormat: "deepseek",
|
|
5911
|
+
thinkingLevelMap: { high: "high", xhigh: "max", minimal: null, low: null, medium: null }
|
|
5912
|
+
};
|
|
5913
|
+
}
|
|
5914
|
+
if (type === "deepseek_hybrid") {
|
|
5915
|
+
return {
|
|
5916
|
+
thinkingFormat: "deepseek",
|
|
5917
|
+
thinkingLevelMap: { auto: "auto", high: "high", minimal: null, low: null, medium: null, xhigh: null }
|
|
5918
|
+
};
|
|
5919
|
+
}
|
|
5920
|
+
const compat = { supportsReasoningEffort: true };
|
|
5921
|
+
const levelMap = TYPE_LEVEL_MAP[type];
|
|
5922
|
+
if (levelMap) {
|
|
5923
|
+
compat.thinkingLevelMap = levelMap;
|
|
5924
|
+
}
|
|
5925
|
+
return compat;
|
|
5926
|
+
}
|
|
5927
|
+
|
|
5777
5928
|
// ../../packages/core/src/import/dedup.ts
|
|
5778
5929
|
function fnv1a64(input) {
|
|
5779
5930
|
let h0 = 2166136261;
|
|
@@ -11657,6 +11808,7 @@ var AIConversationManager = class {
|
|
|
11657
11808
|
id TEXT PRIMARY KEY,
|
|
11658
11809
|
session_id TEXT NOT NULL,
|
|
11659
11810
|
title TEXT,
|
|
11811
|
+
active_message_id TEXT,
|
|
11660
11812
|
created_at INTEGER NOT NULL,
|
|
11661
11813
|
updated_at INTEGER NOT NULL
|
|
11662
11814
|
);
|
|
@@ -11670,6 +11822,9 @@ var AIConversationManager = class {
|
|
|
11670
11822
|
data_keywords TEXT,
|
|
11671
11823
|
data_message_count INTEGER,
|
|
11672
11824
|
content_blocks TEXT,
|
|
11825
|
+
parent_id TEXT,
|
|
11826
|
+
sibling_group_id TEXT,
|
|
11827
|
+
branch_index INTEGER DEFAULT 0,
|
|
11673
11828
|
FOREIGN KEY(conversation_id) REFERENCES ai_conversation(id) ON DELETE CASCADE
|
|
11674
11829
|
);
|
|
11675
11830
|
|
|
@@ -11683,6 +11838,7 @@ var AIConversationManager = class {
|
|
|
11683
11838
|
try {
|
|
11684
11839
|
const messageTableInfo = db.pragma("table_info(ai_message)");
|
|
11685
11840
|
const messageColumns = messageTableInfo.map((col) => col.name);
|
|
11841
|
+
const needsMessageTreeBackfill = !messageColumns.includes("parent_id") || !messageColumns.includes("sibling_group_id") || !messageColumns.includes("branch_index");
|
|
11686
11842
|
if (!messageColumns.includes("content_blocks")) {
|
|
11687
11843
|
db.exec("ALTER TABLE ai_message ADD COLUMN content_blocks TEXT");
|
|
11688
11844
|
}
|
|
@@ -11692,18 +11848,149 @@ var AIConversationManager = class {
|
|
|
11692
11848
|
if (!messageColumns.includes("debug_context")) {
|
|
11693
11849
|
db.exec("ALTER TABLE ai_message ADD COLUMN debug_context TEXT");
|
|
11694
11850
|
}
|
|
11851
|
+
if (!messageColumns.includes("parent_id")) {
|
|
11852
|
+
db.exec("ALTER TABLE ai_message ADD COLUMN parent_id TEXT");
|
|
11853
|
+
}
|
|
11854
|
+
if (!messageColumns.includes("sibling_group_id")) {
|
|
11855
|
+
db.exec("ALTER TABLE ai_message ADD COLUMN sibling_group_id TEXT");
|
|
11856
|
+
}
|
|
11857
|
+
if (!messageColumns.includes("branch_index")) {
|
|
11858
|
+
db.exec("ALTER TABLE ai_message ADD COLUMN branch_index INTEGER DEFAULT 0");
|
|
11859
|
+
}
|
|
11695
11860
|
const convTableInfo = db.pragma("table_info(ai_conversation)");
|
|
11696
11861
|
const convColumns = convTableInfo.map((col) => col.name);
|
|
11862
|
+
const needsConversationBackfill = !convColumns.includes("active_message_id");
|
|
11697
11863
|
if (!convColumns.includes("assistant_id")) {
|
|
11698
11864
|
db.exec(`ALTER TABLE ai_conversation ADD COLUMN assistant_id TEXT DEFAULT '${DEFAULT_GENERAL_ID}'`);
|
|
11699
11865
|
}
|
|
11866
|
+
if (!convColumns.includes("active_message_id")) {
|
|
11867
|
+
db.exec("ALTER TABLE ai_conversation ADD COLUMN active_message_id TEXT");
|
|
11868
|
+
}
|
|
11869
|
+
if (needsMessageTreeBackfill || needsConversationBackfill || this.hasUnbackfilledMessageTree(db)) {
|
|
11870
|
+
this.backfillMessageTree(db);
|
|
11871
|
+
}
|
|
11872
|
+
db.exec(`
|
|
11873
|
+
CREATE INDEX IF NOT EXISTS idx_ai_message_parent ON ai_message(parent_id);
|
|
11874
|
+
CREATE INDEX IF NOT EXISTS idx_ai_message_sibling ON ai_message(sibling_group_id);
|
|
11875
|
+
`);
|
|
11700
11876
|
} catch (error) {
|
|
11701
11877
|
console.error("[AI DB Migration] Migration failed:", error);
|
|
11702
11878
|
}
|
|
11703
11879
|
}
|
|
11880
|
+
hasUnbackfilledMessageTree(db) {
|
|
11881
|
+
const row = db.prepare(
|
|
11882
|
+
`SELECT 1
|
|
11883
|
+
FROM ai_conversation c
|
|
11884
|
+
WHERE EXISTS (
|
|
11885
|
+
SELECT 1 FROM ai_message m
|
|
11886
|
+
WHERE m.conversation_id = c.id
|
|
11887
|
+
)
|
|
11888
|
+
AND (
|
|
11889
|
+
c.active_message_id IS NULL
|
|
11890
|
+
OR EXISTS (
|
|
11891
|
+
SELECT 1 FROM ai_message m
|
|
11892
|
+
WHERE m.conversation_id = c.id
|
|
11893
|
+
AND (m.sibling_group_id IS NULL OR m.branch_index IS NULL)
|
|
11894
|
+
)
|
|
11895
|
+
)
|
|
11896
|
+
LIMIT 1`
|
|
11897
|
+
).get();
|
|
11898
|
+
return !!row;
|
|
11899
|
+
}
|
|
11900
|
+
backfillMessageTree(db) {
|
|
11901
|
+
const conversations = db.prepare("SELECT id FROM ai_conversation").all();
|
|
11902
|
+
const updateMessage = db.prepare(
|
|
11903
|
+
"UPDATE ai_message SET parent_id = ?, sibling_group_id = COALESCE(sibling_group_id, ?), branch_index = COALESCE(branch_index, 0) WHERE id = ?"
|
|
11904
|
+
);
|
|
11905
|
+
const updateConversation = db.prepare("UPDATE ai_conversation SET active_message_id = ? WHERE id = ?");
|
|
11906
|
+
const tx = db.transaction(() => {
|
|
11907
|
+
for (const conversation of conversations) {
|
|
11908
|
+
const messages = db.prepare(
|
|
11909
|
+
`SELECT id, parent_id as parentId, sibling_group_id as siblingGroupId
|
|
11910
|
+
FROM ai_message WHERE conversation_id = ? ORDER BY timestamp ASC, id ASC`
|
|
11911
|
+
).all(conversation.id);
|
|
11912
|
+
let previousId = null;
|
|
11913
|
+
for (const message of messages) {
|
|
11914
|
+
const parentId = message.parentId === void 0 ? previousId : message.parentId ?? previousId;
|
|
11915
|
+
updateMessage.run(parentId, message.siblingGroupId ?? message.id, message.id);
|
|
11916
|
+
previousId = message.id;
|
|
11917
|
+
}
|
|
11918
|
+
const conversationRow = db.prepare("SELECT active_message_id as activeMessageId FROM ai_conversation WHERE id = ?").get(conversation.id);
|
|
11919
|
+
if (!conversationRow?.activeMessageId && previousId) {
|
|
11920
|
+
updateConversation.run(previousId, conversation.id);
|
|
11921
|
+
}
|
|
11922
|
+
}
|
|
11923
|
+
});
|
|
11924
|
+
tx();
|
|
11925
|
+
}
|
|
11704
11926
|
generateId(prefix) {
|
|
11705
11927
|
return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
11706
11928
|
}
|
|
11929
|
+
parseMessageRow(row) {
|
|
11930
|
+
return {
|
|
11931
|
+
id: row.id,
|
|
11932
|
+
conversationId: row.conversationId,
|
|
11933
|
+
role: row.role,
|
|
11934
|
+
content: row.content,
|
|
11935
|
+
timestamp: row.timestamp,
|
|
11936
|
+
parentId: row.parentId ?? null,
|
|
11937
|
+
dataKeywords: row.dataKeywords ? JSON.parse(row.dataKeywords) : void 0,
|
|
11938
|
+
dataMessageCount: row.dataMessageCount ?? void 0,
|
|
11939
|
+
contentBlocks: row.contentBlocks ? JSON.parse(row.contentBlocks) : void 0,
|
|
11940
|
+
tokenUsage: row.tokenUsage ? JSON.parse(row.tokenUsage) : void 0
|
|
11941
|
+
};
|
|
11942
|
+
}
|
|
11943
|
+
getMessageRow(messageId) {
|
|
11944
|
+
const db = this.getDb();
|
|
11945
|
+
const row = db.prepare(
|
|
11946
|
+
`SELECT id, conversation_id as conversationId, role, content, timestamp,
|
|
11947
|
+
parent_id as parentId, sibling_group_id as siblingGroupId, branch_index as branchIndex,
|
|
11948
|
+
data_keywords as dataKeywords, data_message_count as dataMessageCount,
|
|
11949
|
+
content_blocks as contentBlocks, token_usage as tokenUsage
|
|
11950
|
+
FROM ai_message WHERE id = ?`
|
|
11951
|
+
).get(messageId);
|
|
11952
|
+
return row ?? null;
|
|
11953
|
+
}
|
|
11954
|
+
getActiveMessageId(conversationId) {
|
|
11955
|
+
const db = this.getDb();
|
|
11956
|
+
const row = db.prepare("SELECT active_message_id as activeMessageId FROM ai_conversation WHERE id = ?").get(conversationId);
|
|
11957
|
+
if (row?.activeMessageId) {
|
|
11958
|
+
const activeExists = db.prepare("SELECT 1 FROM ai_message WHERE id = ?").get(row.activeMessageId);
|
|
11959
|
+
if (activeExists) return row.activeMessageId;
|
|
11960
|
+
}
|
|
11961
|
+
const fallback = db.prepare("SELECT id FROM ai_message WHERE conversation_id = ? ORDER BY timestamp DESC, id DESC LIMIT 1").get(conversationId);
|
|
11962
|
+
if (fallback?.id) {
|
|
11963
|
+
db.prepare("UPDATE ai_conversation SET active_message_id = ? WHERE id = ?").run(fallback.id, conversationId);
|
|
11964
|
+
return fallback.id;
|
|
11965
|
+
}
|
|
11966
|
+
return null;
|
|
11967
|
+
}
|
|
11968
|
+
getAllMessageRows(conversationId) {
|
|
11969
|
+
return this.getDb().prepare(
|
|
11970
|
+
`SELECT id, conversation_id as conversationId, role, content, timestamp,
|
|
11971
|
+
parent_id as parentId, sibling_group_id as siblingGroupId, branch_index as branchIndex,
|
|
11972
|
+
data_keywords as dataKeywords, data_message_count as dataMessageCount,
|
|
11973
|
+
content_blocks as contentBlocks, token_usage as tokenUsage
|
|
11974
|
+
FROM ai_message WHERE conversation_id = ? ORDER BY timestamp ASC, id ASC`
|
|
11975
|
+
).all(conversationId);
|
|
11976
|
+
}
|
|
11977
|
+
getActivePathRows(conversationId, leafMessageId) {
|
|
11978
|
+
if (leafMessageId === null) return [];
|
|
11979
|
+
const allRows = this.getAllMessageRows(conversationId);
|
|
11980
|
+
if (allRows.length === 0) return [];
|
|
11981
|
+
const rowMap = new Map(allRows.map((row) => [row.id, row]));
|
|
11982
|
+
let currentId = leafMessageId ?? this.getActiveMessageId(conversationId);
|
|
11983
|
+
const path37 = [];
|
|
11984
|
+
const seen = /* @__PURE__ */ new Set();
|
|
11985
|
+
while (currentId && !seen.has(currentId)) {
|
|
11986
|
+
seen.add(currentId);
|
|
11987
|
+
const row = rowMap.get(currentId);
|
|
11988
|
+
if (!row) break;
|
|
11989
|
+
path37.push(row);
|
|
11990
|
+
currentId = row.parentId;
|
|
11991
|
+
}
|
|
11992
|
+
return path37.length > 0 ? path37.reverse() : allRows;
|
|
11993
|
+
}
|
|
11707
11994
|
// ==================== 生命周期 ====================
|
|
11708
11995
|
close() {
|
|
11709
11996
|
if (this.db) {
|
|
@@ -11766,7 +12053,7 @@ var AIConversationManager = class {
|
|
|
11766
12053
|
`INSERT INTO ai_conversation (id, session_id, title, assistant_id, created_at, updated_at)
|
|
11767
12054
|
VALUES (?, ?, ?, ?, ?, ?)`
|
|
11768
12055
|
).run(id, sessionId, title || null, assistantId, now, now);
|
|
11769
|
-
return { id, sessionId, title: title || null, assistantId, createdAt: now, updatedAt: now };
|
|
12056
|
+
return { id, sessionId, title: title || null, assistantId, activeMessageId: null, createdAt: now, updatedAt: now };
|
|
11770
12057
|
}
|
|
11771
12058
|
getConversationCountsBySession() {
|
|
11772
12059
|
const result = /* @__PURE__ */ new Map();
|
|
@@ -11784,6 +12071,7 @@ var AIConversationManager = class {
|
|
|
11784
12071
|
const db = this.getDb();
|
|
11785
12072
|
return db.prepare(
|
|
11786
12073
|
`SELECT id, session_id as sessionId, title, assistant_id as assistantId,
|
|
12074
|
+
active_message_id as activeMessageId,
|
|
11787
12075
|
created_at as createdAt, updated_at as updatedAt
|
|
11788
12076
|
FROM ai_conversation WHERE session_id = ? ORDER BY updated_at DESC`
|
|
11789
12077
|
).all(sessionId);
|
|
@@ -11792,6 +12080,7 @@ var AIConversationManager = class {
|
|
|
11792
12080
|
const db = this.getDb();
|
|
11793
12081
|
const row = db.prepare(
|
|
11794
12082
|
`SELECT id, session_id as sessionId, title, assistant_id as assistantId,
|
|
12083
|
+
active_message_id as activeMessageId,
|
|
11795
12084
|
created_at as createdAt, updated_at as updatedAt
|
|
11796
12085
|
FROM ai_conversation WHERE id = ?`
|
|
11797
12086
|
).get(conversationId);
|
|
@@ -11814,13 +12103,19 @@ var AIConversationManager = class {
|
|
|
11814
12103
|
const db = this.getDb();
|
|
11815
12104
|
const now = Math.floor(Date.now() / 1e3);
|
|
11816
12105
|
const id = this.generateId("msg");
|
|
12106
|
+
const parentId = this.getActiveMessageId(conversationId);
|
|
12107
|
+
const siblingGroupId = id;
|
|
12108
|
+
const branchIndex = 0;
|
|
11817
12109
|
const pendingDebug = role === "assistant" ? this.pendingDebugContextMap.get(conversationId) : void 0;
|
|
11818
12110
|
if (pendingDebug) {
|
|
11819
12111
|
this.pendingDebugContextMap.delete(conversationId);
|
|
11820
12112
|
}
|
|
11821
12113
|
db.prepare(
|
|
11822
|
-
`INSERT INTO ai_message (
|
|
11823
|
-
|
|
12114
|
+
`INSERT INTO ai_message (
|
|
12115
|
+
id, conversation_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12116
|
+
content_blocks, token_usage, debug_context, parent_id, sibling_group_id, branch_index
|
|
12117
|
+
)
|
|
12118
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
11824
12119
|
).run(
|
|
11825
12120
|
id,
|
|
11826
12121
|
conversationId,
|
|
@@ -11831,15 +12126,23 @@ var AIConversationManager = class {
|
|
|
11831
12126
|
dataMessageCount ?? null,
|
|
11832
12127
|
contentBlocks ? JSON.stringify(contentBlocks) : null,
|
|
11833
12128
|
tokenUsage ? JSON.stringify(tokenUsage) : null,
|
|
11834
|
-
pendingDebug ?? null
|
|
12129
|
+
pendingDebug ?? null,
|
|
12130
|
+
parentId,
|
|
12131
|
+
siblingGroupId,
|
|
12132
|
+
branchIndex
|
|
12133
|
+
);
|
|
12134
|
+
db.prepare("UPDATE ai_conversation SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
|
|
12135
|
+
id,
|
|
12136
|
+
now,
|
|
12137
|
+
conversationId
|
|
11835
12138
|
);
|
|
11836
|
-
db.prepare("UPDATE ai_conversation SET updated_at = ? WHERE id = ?").run(now, conversationId);
|
|
11837
12139
|
return {
|
|
11838
12140
|
id,
|
|
11839
12141
|
conversationId,
|
|
11840
12142
|
role,
|
|
11841
12143
|
content,
|
|
11842
12144
|
timestamp: now,
|
|
12145
|
+
parentId,
|
|
11843
12146
|
dataKeywords,
|
|
11844
12147
|
dataMessageCount,
|
|
11845
12148
|
contentBlocks,
|
|
@@ -11847,40 +12150,181 @@ var AIConversationManager = class {
|
|
|
11847
12150
|
};
|
|
11848
12151
|
}
|
|
11849
12152
|
getMessages(conversationId) {
|
|
11850
|
-
|
|
11851
|
-
const rows = db.prepare(
|
|
11852
|
-
`SELECT id, conversation_id as conversationId, role, content, timestamp,
|
|
11853
|
-
data_keywords as dataKeywords, data_message_count as dataMessageCount,
|
|
11854
|
-
content_blocks as contentBlocks, token_usage as tokenUsage
|
|
11855
|
-
FROM ai_message WHERE conversation_id = ? ORDER BY timestamp ASC`
|
|
11856
|
-
).all(conversationId);
|
|
11857
|
-
return rows.map((row) => ({
|
|
11858
|
-
id: row.id,
|
|
11859
|
-
conversationId: row.conversationId,
|
|
11860
|
-
role: row.role,
|
|
11861
|
-
content: row.content,
|
|
11862
|
-
timestamp: row.timestamp,
|
|
11863
|
-
dataKeywords: row.dataKeywords ? JSON.parse(row.dataKeywords) : void 0,
|
|
11864
|
-
dataMessageCount: row.dataMessageCount ?? void 0,
|
|
11865
|
-
contentBlocks: row.contentBlocks ? JSON.parse(row.contentBlocks) : void 0,
|
|
11866
|
-
tokenUsage: row.tokenUsage ? JSON.parse(row.tokenUsage) : void 0
|
|
11867
|
-
}));
|
|
12153
|
+
return this.getActivePathRows(conversationId).map((row) => this.parseMessageRow(row));
|
|
11868
12154
|
}
|
|
11869
12155
|
deleteMessage(messageId) {
|
|
11870
12156
|
const db = this.getDb();
|
|
11871
12157
|
const result = db.prepare("DELETE FROM ai_message WHERE id = ?").run(messageId);
|
|
11872
12158
|
return result.changes > 0;
|
|
11873
12159
|
}
|
|
11874
|
-
|
|
12160
|
+
deleteMessagesFrom(conversationId, messageId) {
|
|
11875
12161
|
const db = this.getDb();
|
|
11876
|
-
const
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
12162
|
+
const target = this.getMessageRow(messageId);
|
|
12163
|
+
if (!target || target.conversationId !== conversationId) {
|
|
12164
|
+
throw new Error("Message not found in conversation");
|
|
12165
|
+
}
|
|
12166
|
+
const activePath = this.getActivePathRows(conversationId);
|
|
12167
|
+
const targetIndex = activePath.findIndex((row) => row.id === messageId);
|
|
12168
|
+
if (targetIndex < 0) {
|
|
12169
|
+
throw new Error("Message not on active path");
|
|
12170
|
+
}
|
|
12171
|
+
const idsToDelete = activePath.slice(targetIndex).map((row) => row.id);
|
|
12172
|
+
const placeholders = idsToDelete.map(() => "?").join(", ");
|
|
12173
|
+
db.prepare(`DELETE FROM ai_message WHERE id IN (${placeholders})`).run(...idsToDelete);
|
|
12174
|
+
const newLeafId = targetIndex > 0 ? activePath[targetIndex - 1].id : null;
|
|
12175
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
12176
|
+
db.prepare("UPDATE ai_conversation SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
|
|
12177
|
+
newLeafId,
|
|
12178
|
+
now,
|
|
12179
|
+
conversationId
|
|
12180
|
+
);
|
|
12181
|
+
}
|
|
12182
|
+
forkConversation(sourceConversationId, upToMessageId, title) {
|
|
12183
|
+
const db = this.getDb();
|
|
12184
|
+
const source = this.getConversation(sourceConversationId);
|
|
12185
|
+
if (!source) {
|
|
12186
|
+
throw new Error("Source conversation not found");
|
|
12187
|
+
}
|
|
12188
|
+
const activePath = this.getActivePathRows(sourceConversationId);
|
|
12189
|
+
const cutIndex = activePath.findIndex((row) => row.id === upToMessageId);
|
|
12190
|
+
if (cutIndex < 0) {
|
|
12191
|
+
throw new Error("Message not on active path");
|
|
12192
|
+
}
|
|
12193
|
+
const messagesToCopy = activePath.slice(0, cutIndex + 1);
|
|
12194
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
12195
|
+
const newConvId = this.generateId("conv");
|
|
12196
|
+
const forkTitle = title || `${source.title || "Untitled"} (fork)`;
|
|
12197
|
+
db.prepare(
|
|
12198
|
+
`INSERT INTO ai_conversation (id, session_id, title, assistant_id, active_message_id, created_at, updated_at)
|
|
12199
|
+
VALUES (?, ?, ?, ?, NULL, ?, ?)`
|
|
12200
|
+
).run(newConvId, source.sessionId, forkTitle, source.assistantId, now, now);
|
|
12201
|
+
const idMap = /* @__PURE__ */ new Map();
|
|
12202
|
+
let lastNewId = null;
|
|
12203
|
+
for (const row of messagesToCopy) {
|
|
12204
|
+
const newMsgId = this.generateId("msg");
|
|
12205
|
+
idMap.set(row.id, newMsgId);
|
|
12206
|
+
const newParentId = row.parentId ? idMap.get(row.parentId) ?? null : null;
|
|
12207
|
+
db.prepare(
|
|
12208
|
+
`INSERT INTO ai_message (
|
|
12209
|
+
id, conversation_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12210
|
+
content_blocks, token_usage, debug_context, parent_id, sibling_group_id, branch_index
|
|
12211
|
+
)
|
|
12212
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, 0)`
|
|
12213
|
+
).run(
|
|
12214
|
+
newMsgId,
|
|
12215
|
+
newConvId,
|
|
12216
|
+
row.role,
|
|
12217
|
+
row.content,
|
|
12218
|
+
row.timestamp,
|
|
12219
|
+
row.dataKeywords,
|
|
12220
|
+
row.dataMessageCount,
|
|
12221
|
+
row.contentBlocks,
|
|
12222
|
+
row.tokenUsage,
|
|
12223
|
+
newParentId,
|
|
12224
|
+
newMsgId
|
|
12225
|
+
);
|
|
12226
|
+
lastNewId = newMsgId;
|
|
12227
|
+
}
|
|
12228
|
+
if (lastNewId) {
|
|
12229
|
+
db.prepare("UPDATE ai_conversation SET active_message_id = ? WHERE id = ?").run(lastNewId, newConvId);
|
|
12230
|
+
}
|
|
12231
|
+
return {
|
|
12232
|
+
id: newConvId,
|
|
12233
|
+
sessionId: source.sessionId,
|
|
12234
|
+
title: forkTitle,
|
|
12235
|
+
assistantId: source.assistantId,
|
|
12236
|
+
activeMessageId: lastNewId,
|
|
12237
|
+
createdAt: now,
|
|
12238
|
+
updatedAt: now
|
|
12239
|
+
};
|
|
12240
|
+
}
|
|
12241
|
+
updateMessageContent(messageId, newContent) {
|
|
12242
|
+
const db = this.getDb();
|
|
12243
|
+
const result = db.prepare("UPDATE ai_message SET content = ? WHERE id = ?").run(newContent, messageId);
|
|
12244
|
+
if (result.changes === 0) throw new Error("Message not found");
|
|
12245
|
+
}
|
|
12246
|
+
deleteAndRelinkMessage(conversationId, messageId) {
|
|
12247
|
+
const db = this.getDb();
|
|
12248
|
+
const target = this.getMessageRow(messageId);
|
|
12249
|
+
if (!target || target.conversationId !== conversationId) {
|
|
12250
|
+
throw new Error("Message not found in conversation");
|
|
12251
|
+
}
|
|
12252
|
+
db.prepare("UPDATE ai_message SET parent_id = ? WHERE parent_id = ? AND conversation_id = ?").run(
|
|
12253
|
+
target.parentId,
|
|
12254
|
+
messageId,
|
|
12255
|
+
conversationId
|
|
12256
|
+
);
|
|
12257
|
+
const conv = this.getConversation(conversationId);
|
|
12258
|
+
if (conv?.activeMessageId === messageId) {
|
|
12259
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
12260
|
+
db.prepare("UPDATE ai_conversation SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
|
|
12261
|
+
target.parentId,
|
|
12262
|
+
now,
|
|
12263
|
+
conversationId
|
|
12264
|
+
);
|
|
12265
|
+
}
|
|
12266
|
+
db.prepare("DELETE FROM ai_message WHERE id = ?").run(messageId);
|
|
12267
|
+
}
|
|
12268
|
+
insertMessageAfter(conversationId, afterMessageId, role, content, contentBlocks, tokenUsage) {
|
|
12269
|
+
const db = this.getDb();
|
|
12270
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
12271
|
+
const id = this.generateId("msg");
|
|
12272
|
+
const pendingDebug = role === "assistant" ? this.pendingDebugContextMap.get(conversationId) : void 0;
|
|
12273
|
+
if (pendingDebug) {
|
|
12274
|
+
this.pendingDebugContextMap.delete(conversationId);
|
|
12275
|
+
}
|
|
12276
|
+
const childRow = db.prepare("SELECT id FROM ai_message WHERE parent_id = ? AND conversation_id = ? LIMIT 1").get(afterMessageId, conversationId);
|
|
12277
|
+
db.prepare(
|
|
12278
|
+
`INSERT INTO ai_message (
|
|
12279
|
+
id, conversation_id, role, content, timestamp, data_keywords, data_message_count,
|
|
12280
|
+
content_blocks, token_usage, debug_context, parent_id, sibling_group_id, branch_index
|
|
12281
|
+
)
|
|
12282
|
+
VALUES (?, ?, ?, ?, ?, NULL, NULL, ?, ?, ?, ?, ?, 0)`
|
|
12283
|
+
).run(
|
|
12284
|
+
id,
|
|
12285
|
+
conversationId,
|
|
12286
|
+
role,
|
|
12287
|
+
content,
|
|
12288
|
+
now,
|
|
12289
|
+
contentBlocks ? JSON.stringify(contentBlocks) : null,
|
|
12290
|
+
tokenUsage ? JSON.stringify(tokenUsage) : null,
|
|
12291
|
+
pendingDebug ?? null,
|
|
12292
|
+
afterMessageId,
|
|
12293
|
+
id
|
|
12294
|
+
);
|
|
12295
|
+
if (childRow) {
|
|
12296
|
+
db.prepare("UPDATE ai_message SET parent_id = ? WHERE id = ?").run(id, childRow.id);
|
|
12297
|
+
db.prepare("UPDATE ai_conversation SET updated_at = ? WHERE id = ?").run(now, conversationId);
|
|
12298
|
+
} else {
|
|
12299
|
+
db.prepare("UPDATE ai_conversation SET active_message_id = ?, updated_at = ? WHERE id = ?").run(
|
|
12300
|
+
id,
|
|
12301
|
+
now,
|
|
12302
|
+
conversationId
|
|
12303
|
+
);
|
|
12304
|
+
}
|
|
12305
|
+
return {
|
|
12306
|
+
id,
|
|
12307
|
+
conversationId,
|
|
12308
|
+
role,
|
|
12309
|
+
content,
|
|
12310
|
+
timestamp: now,
|
|
12311
|
+
parentId: afterMessageId,
|
|
12312
|
+
contentBlocks,
|
|
12313
|
+
tokenUsage
|
|
12314
|
+
};
|
|
12315
|
+
}
|
|
12316
|
+
getConversationTokenUsage(conversationId) {
|
|
12317
|
+
const rows = this.getActivePathRows(conversationId);
|
|
12318
|
+
const result = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
12319
|
+
for (const row of rows) {
|
|
12320
|
+
if (row.tokenUsage) {
|
|
12321
|
+
const usage = JSON.parse(row.tokenUsage);
|
|
12322
|
+
result.promptTokens += usage.promptTokens;
|
|
12323
|
+
result.completionTokens += usage.completionTokens;
|
|
12324
|
+
result.totalTokens += usage.totalTokens;
|
|
12325
|
+
}
|
|
12326
|
+
}
|
|
12327
|
+
return result;
|
|
11884
12328
|
}
|
|
11885
12329
|
// ==================== Debug context ====================
|
|
11886
12330
|
setPendingDebugContext(conversationId, debugContext) {
|
|
@@ -11896,8 +12340,8 @@ var AIConversationManager = class {
|
|
|
11896
12340
|
return result.changes;
|
|
11897
12341
|
}
|
|
11898
12342
|
// ==================== Agent 专用 ====================
|
|
11899
|
-
getHistoryForAgent(conversationId, maxMessages) {
|
|
11900
|
-
const messages = this.
|
|
12343
|
+
getHistoryForAgent(conversationId, maxMessages, leafMessageId) {
|
|
12344
|
+
const messages = this.getActivePathRows(conversationId, leafMessageId).map((row) => this.parseMessageRow(row));
|
|
11901
12345
|
const validMessages = messages.filter(
|
|
11902
12346
|
(m) => (m.role === "user" || m.role === "assistant" || m.role === "summary") && m.content?.trim()
|
|
11903
12347
|
);
|
|
@@ -11940,8 +12384,6 @@ var AIConversationManager = class {
|
|
|
11940
12384
|
}
|
|
11941
12385
|
// ==================== Summary / 压缩专用 ====================
|
|
11942
12386
|
addSummaryMessage(conversationId, content, meta) {
|
|
11943
|
-
const db = this.getDb();
|
|
11944
|
-
db.prepare("DELETE FROM ai_message WHERE conversation_id = ? AND role = 'summary'").run(conversationId);
|
|
11945
12387
|
const contentBlocks = [
|
|
11946
12388
|
{
|
|
11947
12389
|
type: "summary_meta",
|
|
@@ -11952,60 +12394,27 @@ var AIConversationManager = class {
|
|
|
11952
12394
|
return this.addMessage(conversationId, "summary", content, void 0, void 0, contentBlocks);
|
|
11953
12395
|
}
|
|
11954
12396
|
getLatestSummary(conversationId) {
|
|
11955
|
-
const
|
|
11956
|
-
|
|
11957
|
-
`SELECT id, conversation_id as conversationId, role, content, timestamp,
|
|
11958
|
-
data_keywords as dataKeywords, data_message_count as dataMessageCount,
|
|
11959
|
-
content_blocks as contentBlocks
|
|
11960
|
-
FROM ai_message WHERE conversation_id = ? AND role = 'summary'
|
|
11961
|
-
ORDER BY timestamp DESC LIMIT 1`
|
|
11962
|
-
).get(conversationId);
|
|
11963
|
-
if (!row) return null;
|
|
11964
|
-
return {
|
|
11965
|
-
id: row.id,
|
|
11966
|
-
conversationId: row.conversationId,
|
|
11967
|
-
role: row.role,
|
|
11968
|
-
content: row.content,
|
|
11969
|
-
timestamp: row.timestamp,
|
|
11970
|
-
dataKeywords: row.dataKeywords ? JSON.parse(row.dataKeywords) : void 0,
|
|
11971
|
-
dataMessageCount: row.dataMessageCount ?? void 0,
|
|
11972
|
-
contentBlocks: row.contentBlocks ? JSON.parse(row.contentBlocks) : void 0
|
|
11973
|
-
};
|
|
12397
|
+
const row = [...this.getActivePathRows(conversationId)].reverse().find((message) => message.role === "summary");
|
|
12398
|
+
return row ? this.parseMessageRow(row) : null;
|
|
11974
12399
|
}
|
|
11975
12400
|
getMessagesAfterSummary(conversationId, summaryTimestamp) {
|
|
11976
|
-
|
|
11977
|
-
const rows = db.prepare(
|
|
11978
|
-
`SELECT role, content, timestamp FROM ai_message
|
|
11979
|
-
WHERE conversation_id = ? AND timestamp > ? AND role IN ('user', 'assistant')
|
|
11980
|
-
ORDER BY timestamp ASC`
|
|
11981
|
-
).all(conversationId, summaryTimestamp);
|
|
11982
|
-
return rows.map((r) => ({ role: r.role, content: r.content, timestamp: r.timestamp }));
|
|
12401
|
+
return this.getActivePathRows(conversationId).filter((row) => row.timestamp > summaryTimestamp && (row.role === "user" || row.role === "assistant")).map((row) => ({ role: row.role, content: row.content, timestamp: row.timestamp }));
|
|
11983
12402
|
}
|
|
11984
12403
|
getAllUserAssistantMessages(conversationId) {
|
|
11985
|
-
|
|
11986
|
-
const rows = db.prepare(
|
|
11987
|
-
`SELECT role, content, timestamp FROM ai_message
|
|
11988
|
-
WHERE conversation_id = ? AND role IN ('user', 'assistant')
|
|
11989
|
-
ORDER BY timestamp ASC`
|
|
11990
|
-
).all(conversationId);
|
|
11991
|
-
return rows.map((r) => ({ role: r.role, content: r.content, timestamp: r.timestamp }));
|
|
12404
|
+
return this.getActivePathRows(conversationId).filter((row) => row.role === "user" || row.role === "assistant").map((row) => ({ role: row.role, content: row.content, timestamp: row.timestamp }));
|
|
11992
12405
|
}
|
|
11993
12406
|
getMessageCountAfterSummary(conversationId) {
|
|
11994
12407
|
const summary = this.getLatestSummary(conversationId);
|
|
11995
12408
|
if (!summary) {
|
|
11996
|
-
|
|
11997
|
-
const row2 = db2.prepare("SELECT COUNT(*) as count FROM ai_message WHERE conversation_id = ? AND role IN ('user', 'assistant')").get(conversationId);
|
|
11998
|
-
return row2.count;
|
|
12409
|
+
return this.getActivePathRows(conversationId).filter((row) => row.role === "user" || row.role === "assistant").length;
|
|
11999
12410
|
}
|
|
12000
12411
|
const metaBlock = summary.contentBlocks?.find(
|
|
12001
12412
|
(b) => b.type === "summary_meta"
|
|
12002
12413
|
);
|
|
12003
12414
|
const boundary = metaBlock?.bufferBoundaryTimestamp ?? summary.timestamp;
|
|
12004
|
-
|
|
12005
|
-
|
|
12006
|
-
|
|
12007
|
-
).get(conversationId, boundary);
|
|
12008
|
-
return row.count;
|
|
12415
|
+
return this.getActivePathRows(conversationId).filter(
|
|
12416
|
+
(row) => row.timestamp >= boundary && (row.role === "user" || row.role === "assistant")
|
|
12417
|
+
).length;
|
|
12009
12418
|
}
|
|
12010
12419
|
};
|
|
12011
12420
|
|
|
@@ -13177,7 +13586,8 @@ function applyPreprocessingPipeline(options) {
|
|
|
13177
13586
|
// ../../packages/node-runtime/src/ai/agent/core.ts
|
|
13178
13587
|
import { Agent as PiAgentCore } from "@earendil-works/pi-agent-core";
|
|
13179
13588
|
import {
|
|
13180
|
-
streamSimple as defaultStreamSimple
|
|
13589
|
+
streamSimple as defaultStreamSimple,
|
|
13590
|
+
clampThinkingLevel
|
|
13181
13591
|
} from "@earendil-works/pi-ai";
|
|
13182
13592
|
function createEmptyPiUsage() {
|
|
13183
13593
|
return {
|
|
@@ -13241,11 +13651,34 @@ async function runAgentCore(options) {
|
|
|
13241
13651
|
if (abortSignal?.aborted) {
|
|
13242
13652
|
return { usage: totalUsage, finalMessages: [], toolsUsed: [], toolRounds: 0 };
|
|
13243
13653
|
}
|
|
13654
|
+
const isDefault = !options.thinkingLevel || options.thinkingLevel === "default";
|
|
13655
|
+
const effectiveModel = isDefault ? { ...piModel, reasoning: false, compat: void 0, thinkingLevelMap: void 0 } : piModel;
|
|
13656
|
+
const resolvedThinkingLevel = (() => {
|
|
13657
|
+
if (isDefault) return "off";
|
|
13658
|
+
const level = options.thinkingLevel;
|
|
13659
|
+
if (level === "auto") {
|
|
13660
|
+
if (!piModel.reasoning) return "off";
|
|
13661
|
+
const compat = piModel.compat;
|
|
13662
|
+
if (compat?.thinkingFormat) return "high";
|
|
13663
|
+
if (piModel.thinkingLevelMap) return "high";
|
|
13664
|
+
return void 0;
|
|
13665
|
+
}
|
|
13666
|
+
return clampThinkingLevel(piModel, level);
|
|
13667
|
+
})();
|
|
13668
|
+
const finalThinkingLevel = resolvedThinkingLevel ?? (piModel.reasoning ? void 0 : "off");
|
|
13669
|
+
console.debug("[agent-core] thinkingLevel resolution:", {
|
|
13670
|
+
input: options.thinkingLevel,
|
|
13671
|
+
modelId: piModel.id,
|
|
13672
|
+
modelReasoning: effectiveModel.reasoning,
|
|
13673
|
+
isDefault,
|
|
13674
|
+
resolved: resolvedThinkingLevel,
|
|
13675
|
+
final: finalThinkingLevel
|
|
13676
|
+
});
|
|
13244
13677
|
const coreAgent = new PiAgentCore({
|
|
13245
13678
|
initialState: {
|
|
13246
13679
|
systemPrompt,
|
|
13247
|
-
model:
|
|
13248
|
-
thinkingLevel:
|
|
13680
|
+
model: effectiveModel,
|
|
13681
|
+
thinkingLevel: finalThinkingLevel,
|
|
13249
13682
|
tools: maxToolRounds > 0 ? tools : [],
|
|
13250
13683
|
messages: toPiHistoryMessages(history)
|
|
13251
13684
|
},
|
|
@@ -15388,6 +15821,20 @@ var BUILTIN_PROVIDER_API = {
|
|
|
15388
15821
|
gemini: "google-generative-ai",
|
|
15389
15822
|
anthropic: "anthropic-messages"
|
|
15390
15823
|
};
|
|
15824
|
+
function inferReasoning(provider, modelId, modelDef) {
|
|
15825
|
+
const reasoning = modelDef?.capabilities.includes("reasoning") || !modelDef?.builtin && isReasoningModel(provider, modelId);
|
|
15826
|
+
if (!reasoning) return { reasoning: false, compat: void 0 };
|
|
15827
|
+
const thinkingCompat = getThinkingCompat(provider, modelId);
|
|
15828
|
+
if (Object.keys(thinkingCompat).length === 0) {
|
|
15829
|
+
return { reasoning: true, compat: void 0 };
|
|
15830
|
+
}
|
|
15831
|
+
const { thinkingLevelMap, ...compatFields } = thinkingCompat;
|
|
15832
|
+
return {
|
|
15833
|
+
reasoning: true,
|
|
15834
|
+
compat: Object.keys(compatFields).length > 0 ? compatFields : void 0,
|
|
15835
|
+
thinkingLevelMap
|
|
15836
|
+
};
|
|
15837
|
+
}
|
|
15391
15838
|
function buildPiModel(config, options) {
|
|
15392
15839
|
const providerDef = BUILTIN_PROVIDERS.find((p) => p.id === config.provider);
|
|
15393
15840
|
const baseUrl = config.baseUrl || providerDef?.defaultBaseUrl || "";
|
|
@@ -15403,7 +15850,7 @@ function buildPiModel(config, options) {
|
|
|
15403
15850
|
api: "google-generative-ai",
|
|
15404
15851
|
provider: "google",
|
|
15405
15852
|
baseUrl,
|
|
15406
|
-
reasoning:
|
|
15853
|
+
reasoning: isReasoningModel(config.provider, modelId),
|
|
15407
15854
|
input: ["text"],
|
|
15408
15855
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
15409
15856
|
contextWindow,
|
|
@@ -15425,6 +15872,7 @@ function buildPiModel(config, options) {
|
|
|
15425
15872
|
};
|
|
15426
15873
|
}
|
|
15427
15874
|
const resolvedBaseUrl = config.provider === "openai-compatible" && (apiFormat === "openai-completions" || apiFormat === "openai-responses") ? normalizeOpenAICompatibleBaseUrl(baseUrl) : baseUrl;
|
|
15875
|
+
const { reasoning, compat, thinkingLevelMap } = inferReasoning(config.provider, modelId, modelDef);
|
|
15428
15876
|
return {
|
|
15429
15877
|
id: modelId,
|
|
15430
15878
|
name: modelId,
|
|
@@ -15432,12 +15880,13 @@ function buildPiModel(config, options) {
|
|
|
15432
15880
|
provider: config.provider,
|
|
15433
15881
|
baseUrl: resolvedBaseUrl,
|
|
15434
15882
|
headers: options?.headers,
|
|
15435
|
-
reasoning
|
|
15883
|
+
reasoning,
|
|
15884
|
+
thinkingLevelMap,
|
|
15436
15885
|
input: ["text"],
|
|
15437
15886
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
15438
15887
|
contextWindow,
|
|
15439
15888
|
maxTokens: config.maxTokens ?? 4096,
|
|
15440
|
-
compat
|
|
15889
|
+
compat
|
|
15441
15890
|
};
|
|
15442
15891
|
}
|
|
15443
15892
|
|
|
@@ -18804,6 +19253,7 @@ __export(session_index_service_exports, {
|
|
|
18804
19253
|
clearIndex: () => clearIndex,
|
|
18805
19254
|
generateIncrementalIndex: () => generateIncrementalIndex,
|
|
18806
19255
|
generateIndex: () => generateIndex,
|
|
19256
|
+
getAllIndexStats: () => getAllIndexStats,
|
|
18807
19257
|
getFtsStatus: () => getFtsStatus,
|
|
18808
19258
|
rebuildFts: () => rebuildFts,
|
|
18809
19259
|
searchFts: () => searchFts
|
|
@@ -18832,6 +19282,18 @@ function rebuildFts(adapter, sessionId) {
|
|
|
18832
19282
|
const db = adapter.ensureWritable(sessionId);
|
|
18833
19283
|
return rebuildFtsIndex(db);
|
|
18834
19284
|
}
|
|
19285
|
+
function getAllIndexStats(adapter) {
|
|
19286
|
+
const ids = adapter.listSessionIds();
|
|
19287
|
+
return ids.map((sessionId) => {
|
|
19288
|
+
try {
|
|
19289
|
+
const db = adapter.ensureReadonly(sessionId);
|
|
19290
|
+
const stats = getSessionIndexStats(db);
|
|
19291
|
+
return { sessionId, hasIndex: stats.hasIndex, sessionCount: stats.sessionCount };
|
|
19292
|
+
} catch {
|
|
19293
|
+
return { sessionId, hasIndex: false, sessionCount: 0 };
|
|
19294
|
+
}
|
|
19295
|
+
});
|
|
19296
|
+
}
|
|
18835
19297
|
|
|
18836
19298
|
// ../../packages/node-runtime/src/services/summary-service.ts
|
|
18837
19299
|
var summary_service_exports = {};
|
|
@@ -19201,4 +19663,4 @@ export {
|
|
|
19201
19663
|
export_service_exports,
|
|
19202
19664
|
createDatabaseManagerAdapter
|
|
19203
19665
|
};
|
|
19204
|
-
//# sourceMappingURL=chunk-
|
|
19666
|
+
//# sourceMappingURL=chunk-G7Q7EQ3V.mjs.map
|