nolo-cli 0.30.0 → 0.31.0-alpha.1
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/{_executeModel-VBHHG7LT.js → _executeModel-K47XKKPU.js} +32 -31
- package/{action-FENWPT3C.js → action-HI3VRQLP.js} +7 -7
- package/{addContentAction-Z5S5ZQ7I.js → addContentAction-NCURJ6PK.js} +6 -6
- package/{addDialogAgentAction-VUNVD2XR.js → addDialogAgentAction-RCY4ECF4.js} +5 -5
- package/{agentDeleteCommand-LLGZXUYJ.js → agentDeleteCommand-7BBZCONG.js} +26 -25
- package/{agentEmailCommands-LC2FPN6G.js → agentEmailCommands-D6FAT5HM.js} +38 -37
- package/{agentListCommands-A6OBQ3QX.js → agentListCommands-YPNNMGSJ.js} +28 -27
- package/{agentMachineCommands-4O4Q5B5X.js → agentMachineCommands-VYRVSKUC.js} +26 -25
- package/{agentRecordCommands-W22RIQRV.js → agentRecordCommands-4J52H5NK.js} +37 -36
- package/{agentRunCommand-V4OBU4FB.js → agentRunCommand-LH4RA6FA.js} +38 -37
- package/{agentRunControl-AKBN2366.js → agentRunControl-SCIVRZWX.js} +9 -1
- package/{agentRuntimeLocal-I57YSGH4.js → agentRuntimeLocal-G7GK545E.js} +23 -22
- package/{agentSlice-3ZHY7RAO.js → agentSlice-4ZLEPC3M.js} +6 -6
- package/{appDeleteCommands-DJJF466K.js → appDeleteCommands-AOZED7QJ.js} +27 -26
- package/{appDeployCommands-WJZGIOEZ.js → appDeployCommands-XJY27BDS.js} +27 -26
- package/{appDeployStatusCommands-ICYXUJNO.js → appDeployStatusCommands-HKZYAPB2.js} +27 -26
- package/{appGetCommands-UOCWYJPV.js → appGetCommands-VXJLPRYI.js} +27 -26
- package/{appListCommands-EOKWTXPW.js → appListCommands-3LU6AB4G.js} +27 -26
- package/{authCommand-H5KE7K7K.js → authCommand-3GQR43KB.js} +5 -5
- package/{chunk-ZFTCLBEX.js → chunk-2IJAKBK2.js} +3 -1
- package/chunk-2K4NDPT5.js +1524 -0
- package/{chunk-SWOTB2TX.js → chunk-2MSOY7A5.js} +49 -33
- package/{chunk-W2YKDXT7.js → chunk-2YT3KLHX.js} +1 -1
- package/{chunk-HLG6GAUD.js → chunk-3IU7WEJD.js} +1 -1
- package/{chunk-Q24P6TUS.js → chunk-43EPBPZ2.js} +1 -1
- package/{chunk-3RIWR23B.js → chunk-4URO6HMS.js} +1 -1
- package/{chunk-UTQZ73QQ.js → chunk-5EDVWWE3.js} +1 -1
- package/{chunk-GVKTKT3O.js → chunk-5JQRISUS.js} +3 -3
- package/{chunk-GAGUBI42.js → chunk-5MVFYKBL.js} +5 -5
- package/{chunk-R5V5G73M.js → chunk-5RDLGLAP.js} +0 -1
- package/{chunk-4SAV7BD7.js → chunk-7KNERA53.js} +53 -15
- package/{chunk-MEUZFIAJ.js → chunk-7S54ZGF6.js} +2 -2
- package/{chunk-IZ3CBMD5.js → chunk-ATK5WJOA.js} +4 -4
- package/chunk-BGTUGS3T.js +702 -0
- package/{chunk-DI6MXJK5.js → chunk-C3NYMZTQ.js} +16 -14
- package/{chunk-HI7QZNWX.js → chunk-CPUZW54L.js} +4 -4
- package/{chunk-PJY5AH5A.js → chunk-DPR66GY6.js} +1 -1
- package/{chunk-MMCVBEAD.js → chunk-E2CFIWQR.js} +42 -32
- package/{chunk-YWGSCF37.js → chunk-E3APEOIM.js} +1 -1
- package/{chunk-UKC5HU2C.js → chunk-EATVNXFX.js} +7 -7
- package/{chunk-G5JHHUAK.js → chunk-F3MP7CP6.js} +1 -1
- package/{chunk-FS5TTXPS.js → chunk-FLYQAMF4.js} +3 -3
- package/{chunk-446VANPP.js → chunk-G5GVZAXF.js} +4 -4
- package/{chunk-KWKD3BCC.js → chunk-H6COXALE.js} +78 -27
- package/{chunk-56IUA7RU.js → chunk-K76HYM3O.js} +1 -1
- package/{chunk-DKRT67FG.js → chunk-KGEVMUMI.js} +3 -3
- package/{chunk-A4JDTA5T.js → chunk-LAXMH7JY.js} +6 -6
- package/{chunk-L3VQOVKK.js → chunk-LBEWOWVL.js} +4 -4
- package/{chunk-66O5MZYH.js → chunk-NEGMZP6Q.js} +1 -1
- package/{chunk-7CD24PU4.js → chunk-NMK2JHKM.js} +9 -7
- package/{chunk-QLV2GKU5.js → chunk-OT2AXEQD.js} +26 -5
- package/{chunk-CV6I4HBA.js → chunk-PTHDLIRB.js} +1 -1
- package/{chunk-2XM5KUNE.js → chunk-Q6L3O67D.js} +2 -2
- package/{chunk-G6VITLCZ.js → chunk-QHWPAW5M.js} +2 -2
- package/{chunk-KWCLUYGQ.js → chunk-QL6ELRVS.js} +1 -1
- package/chunk-RJ7KLCWY.js +5134 -0
- package/{chunk-T3Y5EMJS.js → chunk-SFWZUTCI.js} +1 -1
- package/{chunk-XD5NQEOH.js → chunk-UDA3ZYLW.js} +1 -1
- package/{chunk-YLADSPDU.js → chunk-V54H24CQ.js} +2 -2
- package/{chunk-SZ5CBYMZ.js → chunk-WEID4JLC.js} +2 -2
- package/{chunk-KW47OSRJ.js → chunk-WMH2G6XJ.js} +91 -179
- package/{chunk-4PWB7JRR.js → chunk-XFG3BAKN.js} +1 -0
- package/chunk-XGJ75KN2.js +7889 -0
- package/{chunk-OYK7PA5U.js → chunk-XPML3KYZ.js} +6 -6
- package/{chunk-TJYWZ3LO.js → chunk-YHGHADBQ.js} +2 -2
- package/{chunk-DCWBP2O7.js → chunk-YJZGAAVX.js} +14 -12
- package/{chunk-BOL2D2JW.js → chunk-ZJ2WITOO.js} +2 -2
- package/{chunk-DWQNDGO7.js → chunk-ZJH3LKEW.js} +2 -2
- package/{createAgentAutomationAction-3GMH6ORX.js → createAgentAutomationAction-AECD5YCU.js} +13 -12
- package/{createDialogAction-R5MCL4RE.js → createDialogAction-MZUC37CA.js} +14 -13
- package/{createPageAction-QYTG656R.js → createPageAction-KRTBWM2S.js} +13 -12
- package/{db-IPCJ43PW.js → db-6DPSJ6WT.js} +4 -2
- package/{dbSlice-OBV7VFCF.js → dbSlice-BBL3PEVW.js} +5 -5
- package/{deleteFile-AC45HYSM.js → deleteFile-RJTEPOT4.js} +3 -3
- package/{dialogCommands-NUQGIXVZ.js → dialogCommands-RFADXVV6.js} +27 -26
- package/{dialogSlice-CFDECXEU.js → dialogSlice-EWNZ2HFD.js} +12 -12
- package/{docCreateCommands-UNFCXB5N.js → docCreateCommands-ZHX6SX5M.js} +26 -25
- package/{docDeleteCommands-NG5IVKE5.js → docDeleteCommands-3EEM7ITO.js} +27 -26
- package/{docReadCommands-6J7MUUX6.js → docReadCommands-JOMLMZTC.js} +26 -25
- package/{docStore-MZZWJM4F.js → docStore-YKTKKH3N.js} +14 -13
- package/{docUpdateCommands-6AW3VZOX.js → docUpdateCommands-PGAYLKLC.js} +26 -25
- package/{getPricing-XQYSSVV6.js → getPricing-QO5TYNCK.js} +2 -2
- package/{handleSendMessageAction-IU2QNTLM.js → handleSendMessageAction-VX4CGWAJ.js} +12 -12
- package/index.js +63 -63
- package/{localDialogRead-P72W2U2R.js → localDialogRead-3DBXVYXS.js} +1 -1
- package/{machineCommands-Z2QEWTHZ.js → machineCommands-A2WFB37F.js} +36 -35
- package/{machineWsRunDispatch-SJTYHZHN.js → machineWsRunDispatch-E5R54UWZ.js} +36 -35
- package/package.json +1 -1
- package/{read-QK7ZRX6G.js → read-64OQDO3I.js} +3 -3
- package/{readDocTool-EYDMVRBL.js → readDocTool-MXM3T6PE.js} +1 -1
- package/{readlineWorkspace-EY3BPXIU.js → readlineWorkspace-S4A6UYVJ.js} +125 -79
- package/{removeDialogAgentAction-TBW3UZJW.js → removeDialogAgentAction-NEKVAMSH.js} +7 -7
- package/{runAgentClientLoop-N3YDLTMS.js → runAgentClientLoop-C6IIUQ36.js} +27 -26
- package/{setDialogExtraReferencesAction-Q3ANF2NR.js → setDialogExtraReferencesAction-WTOHQDIV.js} +6 -6
- package/{setPrimaryDialogAgentAction-FQ5R3EFJ.js → setPrimaryDialogAgentAction-LDJOYC4F.js} +7 -7
- package/{settingSlice-JKKV2T7O.js → settingSlice-4M37TN7V.js} +6 -6
- package/{skillDiscovery-I3QRA7NE.js → skillDiscovery-Y3HALY2U.js} +3 -3
- package/{spaceCommands-R6AEQNLG.js → spaceCommands-SKCMLOC6.js} +210 -28
- package/{spaceSlice-MCH7RLLP.js → spaceSlice-6VOPELQN.js} +13 -12
- package/{streamAgentChatTurn-Q4U2CVMI.js → streamAgentChatTurn-623CNKWF.js} +35 -32
- package/{switchDialogAgentAction-QQGVE4SL.js → switchDialogAgentAction-XVWGKR2Z.js} +5 -5
- package/{tableCommands-PRJNWN6Q.js → tableCommands-RJZ3V4TF.js} +1 -1
- package/{tools-Y3UBLLYW.js → tools-IN4B36PN.js} +21 -20
- package/{tuiSummaryLlmCaller-4474IBTI.js → tuiSummaryLlmCaller-SRZ4QQUP.js} +19 -5
- package/{updateDialogTitleAction-3J7GH67I.js → updateDialogTitleAction-4ABIVEYY.js} +18 -16
- package/chunk-OB6FBSH3.js +0 -47
- package/chunk-THTAR67C.js +0 -16338
- package/chunk-VSTUQGLT.js +0 -4937
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compactWhitespace
|
|
3
|
+
} from "./chunk-DWLEOOGR.js";
|
|
4
|
+
import {
|
|
5
|
+
addContentAction
|
|
6
|
+
} from "./chunk-V54H24CQ.js";
|
|
7
|
+
import {
|
|
8
|
+
upload
|
|
9
|
+
} from "./chunk-LAXMH7JY.js";
|
|
10
|
+
import {
|
|
11
|
+
getRuntimeServerContext
|
|
12
|
+
} from "./chunk-2IJAKBK2.js";
|
|
13
|
+
import {
|
|
14
|
+
API_ENDPOINTS
|
|
15
|
+
} from "./chunk-LCBAMY2M.js";
|
|
16
|
+
import {
|
|
17
|
+
normalizeServerOrigin
|
|
18
|
+
} from "./chunk-CF7PE763.js";
|
|
19
|
+
|
|
20
|
+
// packages/ai/context/tokenUtils.ts
|
|
21
|
+
var estimateTokenCount = (text) => {
|
|
22
|
+
if (!text) return 0;
|
|
23
|
+
const chineseChars = (text.match(/[\u4e00-\u9fa5\u3400-\u4dbf]/g) || []).length;
|
|
24
|
+
const otherChars = text.length - chineseChars;
|
|
25
|
+
return Math.ceil(chineseChars * 1.5 + otherChars * 0.25);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// packages/chat/dialog/actions/builtinDialogLlm.ts
|
|
29
|
+
var BASE_BUILTIN_DIALOG_LLM_CONFIG = {
|
|
30
|
+
apiSource: "platform",
|
|
31
|
+
useServerProxy: true
|
|
32
|
+
};
|
|
33
|
+
var BUILTIN_TITLE_LLM_CONFIG = {
|
|
34
|
+
...BASE_BUILTIN_DIALOG_LLM_CONFIG,
|
|
35
|
+
provider: "nolo",
|
|
36
|
+
id: "builtin-dialog-title-llm",
|
|
37
|
+
name: "Builtin Dialog Title LLM",
|
|
38
|
+
model: "deepseek-v4-flash",
|
|
39
|
+
prompt: "You are a title generator for chat history. \u4F60\u53EA\u505A\u4E00\u4EF6\u4E8B\uFF1A\u6839\u636E\u5BF9\u8BDD\u5185\u5BB9\u8F93\u51FA\u6700\u7EC8\u6807\u9898\u3002\u786C\u6027\u89C4\u5219\uFF1A1) \u53EA\u8F93\u51FA\u6807\u9898\u8FD9\u4E00\u884C\uFF1B\u4E25\u7981\u8F93\u51FA\u63A8\u7406\u3001\u5206\u6790\u3001\u6B65\u9AA4\u3001\u89E3\u91CA\u3001\u524D\u8A00\u3001\u540E\u8BB0\u3001\u7FFB\u8BD1\u3001\u81F4\u6B49\u6216\u4EFB\u4F55\u989D\u5916\u8BF4\u660E\u30022) \u4E0D\u8981\u56DE\u7B54\u7528\u6237\u8BF7\u6C42\uFF0C\u4E0D\u8981\u5199\u6458\u8981\uFF0C\u53EA\u7ED9\u6807\u9898\u7ED3\u679C\u30023) \u6807\u9898\u5C3D\u91CF\u77ED\uFF1A\u901A\u5E38 2-5 \u4E2A\u8BCD\uFF0C\u82F1\u6587\u4E0D\u8D85\u8FC7 6 \u4E2A\u8BCD\u30024) \u4F7F\u7528\u5BF9\u8BDD\u4E3B\u8BED\u8A00\uFF1B\u6DF7\u5408\u8BED\u8A00\u65F6\u4F18\u5148\u7528\u6237\u4E3B\u8981\u8BED\u8A00\u30025) \u4F18\u5148\u590D\u7528\u5BF9\u8BDD\u4E2D\u7684\u5177\u4F53\u4E3B\u9898\u8BCD\uFF0C\u907F\u514D issue\u3001help\u3001discussion\u3001analysis\u3001update \u8FD9\u7C7B\u7A7A\u6CDB\u8BCD\u30026) \u5FFD\u7565 tool JSON\u3001\u51FD\u6570\u540D\u3001branch label\u3001agent \u540D\u3001\u7CFB\u7EDF\u6307\u4EE4\u548C\u7F16\u6392\u75D5\u8FF9\uFF08\u5982 GPT\u3001Claude\u3001Gemini\uFF09\uFF1B\u6807\u9898\u8981\u843D\u5728\u7528\u6237\u771F\u6B63\u8BA8\u8BBA\u7684\u5BF9\u8C61\u6216\u51B3\u7B56\u4E0A\u30027) \u66F4\u504F\u597D\u201C\u5BF9\u8C61 + \u52A8\u4F5C/\u5224\u65AD\u201D\u7684\u77ED\u6807\u9898\uFF0C\u4F8B\u5982\u201CAI \u90AE\u4EF6\u52A9\u624B\u53D6\u820D\u201D\u201C\u4E1C\u4EAC\u56DB\u65E5\u6162\u65C5\u884C\u201D\u201C\u91CD\u590D\u6263\u8D39\u9000\u6B3E\u201D\u30028) \u7EAF\u6587\u672C\uFF0C\u4E0D\u8981\u9879\u76EE\u7B26\u53F7\u3001\u7F16\u53F7\u3001markdown\u3001emoji\u3002\u6700\u7EC8\u53EA\u8FD4\u56DE\u6807\u9898\u6587\u672C\u3002 Output only the title text."
|
|
40
|
+
};
|
|
41
|
+
var BUILTIN_SUMMARY_LLM_CONFIG = {
|
|
42
|
+
...BASE_BUILTIN_DIALOG_LLM_CONFIG,
|
|
43
|
+
provider: "nolo",
|
|
44
|
+
id: "builtin-dialog-summary-llm",
|
|
45
|
+
name: "Builtin Dialog Summary LLM",
|
|
46
|
+
model: "deepseek-v4-flash",
|
|
47
|
+
// @deprecated 用 COMPACTION_SUMMARY_SYSTEM_PROMPT(packages/ai/context/compactionShared.ts)。
|
|
48
|
+
// 生产代码已全部迁移;此旧两段式 prompt 仅被 scripts/probes/dialog 探针脚本使用,待探针迁移后删除。
|
|
49
|
+
prompt: "\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u5BF9\u8BDD\u8BB0\u5FC6\u52A9\u7406\u3002\u8BF7\u57FA\u4E8E\u3010\u73B0\u6709\u8BB0\u5FC6\u3011\u548C\u3010\u65B0\u589E\u5BF9\u8BDD\u3011\uFF0C\u8F93\u51FA\u4E00\u4EFD\u66F4\u65B0\u540E\u7684\u5BF9\u8BDD\u8BB0\u5FC6\u6863\u6848\u3002\u4E25\u683C\u53EA\u8F93\u51FA\u4E0B\u9762\u4E24\u90E8\u5206\uFF0C\u6807\u9898\u5FC5\u987B\u5B8C\u5168\u4E00\u81F4\uFF1A\n\u5173\u952E\u4E8B\u5B9E\u6863\u6848\n- ...\n\u5BF9\u8BDD\u5267\u60C5\u6458\u8981\n- ...\n\u8981\u6C42\uFF1A1) \u4F7F\u7528\u5BF9\u8BDD\u4E3B\u8BED\u8A00\uFF1B\u6DF7\u5408\u8BED\u8A00\u65F6\u4F18\u5148\u8DDF\u968F\u7528\u6237\u4E3B\u8981\u8BED\u8A00\uFF0C\u4E13\u6709\u540D\u8BCD\u4FDD\u7559\u539F\u6587\u30022) \u5173\u952E\u4E8B\u5B9E\u6863\u6848\u53EA\u4FDD\u7559\u4E4B\u540E\u7EE7\u7EED\u5BF9\u8BDD\u4ECD\u6709\u4EF7\u503C\u7684\u4FE1\u606F\uFF0C\u4F8B\u5982\u7528\u6237\u504F\u597D\u3001\u76EE\u6807\u3001\u7EA6\u675F\u3001\u6280\u672F\u6808\u3001\u786E\u5B9A\u7684\u6587\u4EF6\u540D/\u53D8\u91CF\u540D\u3001\u6838\u5FC3\u51B3\u7B56\u3001\u5F85\u529E\u4E8B\u9879\u30023) \u5BF9\u8BDD\u5267\u60C5\u6458\u8981\u5148\u6781\u7B80\u6982\u62EC\u65E7\u4E0A\u4E0B\u6587\uFF0C\u518D\u66F4\u8BE6\u7EC6\u8BB0\u5F55\u6700\u8FD1\u65B0\u589E\u7684\u8FDB\u5C55\u3001\u5206\u6B67\u3001\u7ED3\u8BBA\u548C\u4E0B\u4E00\u6B65\u30024) \u5FFD\u7565\u5BD2\u6684\u3001\u91CD\u590D\u5C1D\u8BD5\u3001\u5DF2\u653E\u5F03\u65B9\u6848\u548C\u65E0\u4EF7\u503C\u5E9F\u8BDD\u30025) \u4E0D\u8981\u7F16\u9020\u672A\u51FA\u73B0\u7684\u4FE1\u606F\uFF0C\u4E0D\u8981\u8F93\u51FA\u5F00\u573A\u767D\u3001\u7ED3\u675F\u8BED\u3001markdown \u4EE3\u7801\u5757\u6216\u989D\u5916\u7AE0\u8282\u3002"
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// packages/core/chat/messageContentSerialize.ts
|
|
53
|
+
var serializeMessageContent = (content, imagePlaceholder = "[\u56FE\u7247]") => {
|
|
54
|
+
if (typeof content === "string") {
|
|
55
|
+
return content.trim() || null;
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(content)) {
|
|
58
|
+
const fragments = [];
|
|
59
|
+
for (const part of content) {
|
|
60
|
+
if (!part || typeof part !== "object") continue;
|
|
61
|
+
if (part.type === "text" && typeof part.text === "string") {
|
|
62
|
+
const text = part.text.trim();
|
|
63
|
+
if (text) fragments.push(text);
|
|
64
|
+
} else if (part.type === "image_url") {
|
|
65
|
+
fragments.push(imagePlaceholder);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const joined = fragments.join("\n").trim();
|
|
69
|
+
return joined || null;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// packages/app/utils/imageUtils.ts
|
|
75
|
+
var BYTES_PER_MB = 1024 * 1024;
|
|
76
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
77
|
+
var parseDataUrl = (dataUrl) => {
|
|
78
|
+
const trimmed = dataUrl.trim();
|
|
79
|
+
const parts = trimmed.split(",");
|
|
80
|
+
if (parts.length < 2 || !parts[0] || !parts[1]) {
|
|
81
|
+
console.warn("[imageUtils] parseDataUrl: invalid data URL", {
|
|
82
|
+
hasHeader: !!parts[0],
|
|
83
|
+
hasBody: !!parts[1]
|
|
84
|
+
});
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const header = parts[0];
|
|
88
|
+
const base64 = parts[1];
|
|
89
|
+
const mimeMatch = header.match(/:(.*?);/);
|
|
90
|
+
const mime = mimeMatch?.[1];
|
|
91
|
+
if (!mime) {
|
|
92
|
+
console.warn("[imageUtils] parseDataUrl: cannot extract mime from", header);
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
return { mime, base64 };
|
|
96
|
+
};
|
|
97
|
+
function dataURLtoFile(dataUrl, filename) {
|
|
98
|
+
try {
|
|
99
|
+
const parsed = parseDataUrl(dataUrl);
|
|
100
|
+
if (!parsed) return null;
|
|
101
|
+
const { mime, base64 } = parsed;
|
|
102
|
+
const binaryString = atob(base64);
|
|
103
|
+
const length = binaryString.length;
|
|
104
|
+
const u8arr = new Uint8Array(length);
|
|
105
|
+
for (let i = 0; i < length; i++) {
|
|
106
|
+
u8arr[i] = binaryString.charCodeAt(i);
|
|
107
|
+
}
|
|
108
|
+
return new File([u8arr], filename, { type: mime });
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error("[imageUtils] Error converting data URL to File:", error);
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
var appendNoCacheQuery = (url) => {
|
|
115
|
+
const stamp = `_t=${Date.now()}`;
|
|
116
|
+
return url.includes("?") ? `${url}&${stamp}` : `${url}?${stamp}`;
|
|
117
|
+
};
|
|
118
|
+
var tryLoadImage = (url) => new Promise((resolve) => {
|
|
119
|
+
const img = new Image();
|
|
120
|
+
const cleanup = () => {
|
|
121
|
+
img.onload = null;
|
|
122
|
+
img.onerror = null;
|
|
123
|
+
};
|
|
124
|
+
img.onload = () => {
|
|
125
|
+
cleanup();
|
|
126
|
+
resolve(true);
|
|
127
|
+
};
|
|
128
|
+
img.onerror = () => {
|
|
129
|
+
cleanup();
|
|
130
|
+
resolve(false);
|
|
131
|
+
};
|
|
132
|
+
img.src = url;
|
|
133
|
+
});
|
|
134
|
+
var waitForFileReady = async (url, {
|
|
135
|
+
maxWaitMs = 4e3,
|
|
136
|
+
intervalMs = 250
|
|
137
|
+
} = {}) => {
|
|
138
|
+
const start = Date.now();
|
|
139
|
+
while (Date.now() - start < maxWaitMs) {
|
|
140
|
+
const tryUrl = appendNoCacheQuery(url);
|
|
141
|
+
const ok = await tryLoadImage(tryUrl);
|
|
142
|
+
if (ok) {
|
|
143
|
+
console.debug("[imageUtils] waitForFileReady: image loaded for", url);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
await sleep(intervalMs);
|
|
147
|
+
}
|
|
148
|
+
console.warn("[imageUtils] waitForFileReady: timeout for", url);
|
|
149
|
+
return false;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// packages/database/fileUrl.ts
|
|
153
|
+
var normalizeFileId = (fileId) => {
|
|
154
|
+
if (typeof fileId !== "string") return "";
|
|
155
|
+
return fileId.trim();
|
|
156
|
+
};
|
|
157
|
+
var buildDatabaseFileContentUrl = (serverOrigin, fileId) => {
|
|
158
|
+
const normalizedServer = normalizeServerOrigin(serverOrigin);
|
|
159
|
+
const normalizedFileId = normalizeFileId(fileId);
|
|
160
|
+
if (!normalizedServer || !normalizedFileId) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
return `${normalizedServer}${API_ENDPOINTS.DATABASE}/file/content/${normalizedFileId}`;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// packages/chat/messages/fileUrl.ts
|
|
167
|
+
var buildMessageFileContentUrl = (serverOrigin, fileId) => buildDatabaseFileContentUrl(serverOrigin, fileId);
|
|
168
|
+
|
|
169
|
+
// packages/chat/messages/imagePayloadPersistence.ts
|
|
170
|
+
var stripDurableImageInlinePayload = (part) => {
|
|
171
|
+
if (!part || typeof part !== "object") return part;
|
|
172
|
+
const { original_data_url: _originalDataUrl, ...withoutOriginalDataUrl } = part;
|
|
173
|
+
if (withoutOriginalDataUrl.type !== "image_url" || !withoutOriginalDataUrl.google_native || typeof withoutOriginalDataUrl.google_native !== "object") {
|
|
174
|
+
return withoutOriginalDataUrl;
|
|
175
|
+
}
|
|
176
|
+
const { google_native: _googleNative, ...durablePart } = withoutOriginalDataUrl;
|
|
177
|
+
return durablePart;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// packages/chat/messages/messageContent.ts
|
|
181
|
+
var isDataUrlImage = (url) => typeof url === "string" && url.startsWith("data:image");
|
|
182
|
+
var uploadGeneratedImageDataUrl = async (url, dialogId, messageId, index, dispatch, getState, options) => {
|
|
183
|
+
const fileName = `generated-image-${dialogId}-${messageId}-${index}.png`;
|
|
184
|
+
const file = dataURLtoFile(url, fileName);
|
|
185
|
+
if (!file) {
|
|
186
|
+
console.warn(
|
|
187
|
+
"[messageContent] dataURLtoFile failed, drop generated image inline payload"
|
|
188
|
+
);
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
const customKey = `generated-image-${dialogId}-${messageId}-${index}`;
|
|
192
|
+
let metadata;
|
|
193
|
+
try {
|
|
194
|
+
metadata = await dispatch(upload({ file, customKey })).unwrap();
|
|
195
|
+
} catch (err) {
|
|
196
|
+
console.warn(
|
|
197
|
+
"[messageContent] upload generated image failed, drop inline payload:",
|
|
198
|
+
err
|
|
199
|
+
);
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
const state = getState();
|
|
203
|
+
const { currentServer } = getRuntimeServerContext(state);
|
|
204
|
+
const fileId = metadata?.dbKey || metadata?.id;
|
|
205
|
+
if (!currentServer || !fileId) {
|
|
206
|
+
console.warn(
|
|
207
|
+
"[messageContent] missing currentServer or fileId, drop inline payload",
|
|
208
|
+
{ currentServer, fileId }
|
|
209
|
+
);
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
if (options?.spaceId) {
|
|
213
|
+
try {
|
|
214
|
+
const agentPrefix = options.agentName ? `[${options.agentName}] ` : "";
|
|
215
|
+
const title = `${agentPrefix}Generated Image ${index + 1}`;
|
|
216
|
+
await addContentAction({
|
|
217
|
+
spaceId: options.spaceId,
|
|
218
|
+
contentKey: fileId,
|
|
219
|
+
title,
|
|
220
|
+
type: "image" /* IMAGE */
|
|
221
|
+
}, { dispatch, getState });
|
|
222
|
+
console.log(`[messageContent] Saved generated image to space: ${options.spaceId}`);
|
|
223
|
+
} catch (err) {
|
|
224
|
+
console.error("[messageContent] Failed to save generated image to space:", err);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const imageUrl = buildMessageFileContentUrl(currentServer, fileId);
|
|
228
|
+
if (!imageUrl) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
const ready = await waitForFileReady(imageUrl);
|
|
232
|
+
if (!ready) {
|
|
233
|
+
console.warn(
|
|
234
|
+
"[messageContent] uploaded generated image not ready, drop inline payload:",
|
|
235
|
+
imageUrl
|
|
236
|
+
);
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
return imageUrl;
|
|
240
|
+
};
|
|
241
|
+
var normalizeAssistantContentBuffer = async (contentBuffer, dialogId, messageId, dispatch, getState, options) => {
|
|
242
|
+
if (!Array.isArray(contentBuffer) || contentBuffer.length === 0) {
|
|
243
|
+
return contentBuffer;
|
|
244
|
+
}
|
|
245
|
+
const updated = await Promise.all(
|
|
246
|
+
contentBuffer.map(async (part, index) => {
|
|
247
|
+
if (!part || part.type !== "image_url" || !part.image_url || !isDataUrlImage(part.image_url.url)) {
|
|
248
|
+
return part;
|
|
249
|
+
}
|
|
250
|
+
const newUrl = await uploadGeneratedImageDataUrl(
|
|
251
|
+
part.image_url.url,
|
|
252
|
+
dialogId,
|
|
253
|
+
messageId,
|
|
254
|
+
index,
|
|
255
|
+
dispatch,
|
|
256
|
+
getState,
|
|
257
|
+
options
|
|
258
|
+
);
|
|
259
|
+
if (!newUrl) {
|
|
260
|
+
return {
|
|
261
|
+
type: "text",
|
|
262
|
+
text: "[\u56FE\u7247\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u751F\u6210\u56FE\u7247]"
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
return stripDurableImageInlinePayload({
|
|
266
|
+
...part,
|
|
267
|
+
image_url: {
|
|
268
|
+
...part.image_url,
|
|
269
|
+
url: newUrl
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
})
|
|
273
|
+
);
|
|
274
|
+
return updated;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
// packages/ai/context/retention.ts
|
|
278
|
+
var SAFE_BUFFER_RATIO = 0.95;
|
|
279
|
+
var CACHE_FIRST_RETENTION_STRENGTH = 0.95;
|
|
280
|
+
var clamp = (v, min, max) => Math.min(max, Math.max(min, v));
|
|
281
|
+
var planContextUsage = (params) => {
|
|
282
|
+
const { contextWindow, summaryTokens, recentLoad } = params;
|
|
283
|
+
const safeWindowLimit = Math.floor(contextWindow * SAFE_BUFFER_RATIO);
|
|
284
|
+
const iq = CACHE_FIRST_RETENTION_STRENGTH;
|
|
285
|
+
const isLargeWindow = contextWindow >= 512e3;
|
|
286
|
+
const isSmallWindow = contextWindow <= 64e3;
|
|
287
|
+
let baseHistoryRatio;
|
|
288
|
+
if (isLargeWindow) {
|
|
289
|
+
baseHistoryRatio = 0.8 + 0.2 * iq;
|
|
290
|
+
} else if (isSmallWindow) {
|
|
291
|
+
baseHistoryRatio = 0.35 + 0.3 * iq;
|
|
292
|
+
} else {
|
|
293
|
+
baseHistoryRatio = 0.55 + 0.3 * iq;
|
|
294
|
+
}
|
|
295
|
+
let historyRatio = baseHistoryRatio;
|
|
296
|
+
switch (recentLoad) {
|
|
297
|
+
case "light": {
|
|
298
|
+
const maxRatio = isLargeWindow ? 1 : isSmallWindow ? 0.75 : 0.85;
|
|
299
|
+
historyRatio = clamp(historyRatio * 1.05, 0.3, maxRatio);
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
case "heavy": {
|
|
303
|
+
const maxRatio = isLargeWindow ? 0.98 : isSmallWindow ? 0.7 : 0.8;
|
|
304
|
+
const multiplier = isLargeWindow ? 0.98 : isSmallWindow ? 0.9 : 0.9;
|
|
305
|
+
historyRatio = clamp(historyRatio * multiplier, 0.3, maxRatio);
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
case "medium":
|
|
309
|
+
default: {
|
|
310
|
+
const maxRatio = isLargeWindow ? 1 : isSmallWindow ? 0.75 : 0.85;
|
|
311
|
+
historyRatio = clamp(historyRatio, 0.3, maxRatio);
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const historyBudget = Math.max(
|
|
316
|
+
0,
|
|
317
|
+
Math.floor(safeWindowLimit * historyRatio)
|
|
318
|
+
);
|
|
319
|
+
const minRawRatio = isSmallWindow ? 0.5 : isLargeWindow ? 0.2 : 0.3;
|
|
320
|
+
const rawMessageBudget = Math.max(
|
|
321
|
+
Math.floor(historyBudget * minRawRatio),
|
|
322
|
+
historyBudget - summaryTokens,
|
|
323
|
+
0
|
|
324
|
+
);
|
|
325
|
+
let minTailTokens;
|
|
326
|
+
if (recentLoad === "light") {
|
|
327
|
+
minTailTokens = Math.min(
|
|
328
|
+
Math.floor(safeWindowLimit * 0.3),
|
|
329
|
+
8e3
|
|
330
|
+
);
|
|
331
|
+
} else if (recentLoad === "heavy") {
|
|
332
|
+
minTailTokens = Math.max(
|
|
333
|
+
Math.floor(safeWindowLimit * 0.25),
|
|
334
|
+
16e3
|
|
335
|
+
);
|
|
336
|
+
} else {
|
|
337
|
+
minTailTokens = Math.floor(safeWindowLimit * 0.2);
|
|
338
|
+
}
|
|
339
|
+
return { historyBudget, rawMessageBudget, minTailTokens };
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// packages/ai/context/planCompression.ts
|
|
343
|
+
var MIN_COMPRESS_COUNT = 5;
|
|
344
|
+
var ACTIVE_SUMMARY_TAIL_KEEP_COUNT = 2;
|
|
345
|
+
var getMessageTokenCount = (msg) => {
|
|
346
|
+
const content = serializeMessageContent(msg.content) || "";
|
|
347
|
+
let tokens = estimateTokenCount(content);
|
|
348
|
+
if (Array.isArray(msg.tool_calls)) {
|
|
349
|
+
for (const call of msg.tool_calls) {
|
|
350
|
+
const fn = call?.function;
|
|
351
|
+
if (fn?.name) tokens += estimateTokenCount(fn.name);
|
|
352
|
+
const args = fn?.arguments;
|
|
353
|
+
if (args) {
|
|
354
|
+
tokens += estimateTokenCount(
|
|
355
|
+
typeof args === "string" ? args : JSON.stringify(args)
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return tokens;
|
|
361
|
+
};
|
|
362
|
+
var hasOpenEndedToolCall = (msg) => !!msg && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0;
|
|
363
|
+
var isActiveSummaryWorthDoing = (pendingTokens, contextWindow) => {
|
|
364
|
+
const minTokens = Math.min(
|
|
365
|
+
4e4,
|
|
366
|
+
Math.max(1e4, Math.floor(contextWindow * 0.05))
|
|
367
|
+
);
|
|
368
|
+
return pendingTokens >= minTokens;
|
|
369
|
+
};
|
|
370
|
+
var classifyConversationLoad = (msgs) => {
|
|
371
|
+
const N = 20;
|
|
372
|
+
if (!Array.isArray(msgs) || msgs.length === 0) return "light";
|
|
373
|
+
const tail = msgs.slice(-N);
|
|
374
|
+
const tokenSamples = tail.map(getMessageTokenCount);
|
|
375
|
+
if (tokenSamples.length === 0) return "light";
|
|
376
|
+
const sum = tokenSamples.reduce((acc, v) => acc + v, 0);
|
|
377
|
+
const avg = sum / tokenSamples.length;
|
|
378
|
+
const sorted = [...tokenSamples].sort((a, b) => a - b);
|
|
379
|
+
const p95 = sorted[Math.floor((sorted.length - 1) * 0.95)];
|
|
380
|
+
if (p95 < 200 && avg < 120) {
|
|
381
|
+
return "light";
|
|
382
|
+
}
|
|
383
|
+
if (p95 > 2e3 || avg > 1200) {
|
|
384
|
+
return "heavy";
|
|
385
|
+
}
|
|
386
|
+
return "medium";
|
|
387
|
+
};
|
|
388
|
+
var normalizeContextUsageRatio = (value) => {
|
|
389
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
|
|
390
|
+
const ratio = value > 1 ? value / 100 : value;
|
|
391
|
+
return ratio >= 0 && ratio <= 1 ? ratio : void 0;
|
|
392
|
+
};
|
|
393
|
+
var emptyPlan = (startIndex) => ({
|
|
394
|
+
shouldCompress: false,
|
|
395
|
+
compressCount: 0,
|
|
396
|
+
msgsToCompress: [],
|
|
397
|
+
msgsToKeep: [],
|
|
398
|
+
newSummarizedBeforeId: void 0,
|
|
399
|
+
startIndex
|
|
400
|
+
});
|
|
401
|
+
function findPendingMessages(allMsgs, summarizedBeforeId) {
|
|
402
|
+
let startIndex = 0;
|
|
403
|
+
if (summarizedBeforeId) {
|
|
404
|
+
const found = allMsgs.findIndex((m) => m.id === summarizedBeforeId);
|
|
405
|
+
if (found !== -1) startIndex = found + 1;
|
|
406
|
+
}
|
|
407
|
+
return { pendingMsgs: allMsgs.slice(startIndex), startIndex };
|
|
408
|
+
}
|
|
409
|
+
function shouldTriggerCompaction(args) {
|
|
410
|
+
const {
|
|
411
|
+
pendingTokens,
|
|
412
|
+
summaryTokens,
|
|
413
|
+
contextWindow,
|
|
414
|
+
historyBudget,
|
|
415
|
+
force,
|
|
416
|
+
reason,
|
|
417
|
+
realContextUsagePercent,
|
|
418
|
+
lastCompactedTokenCount,
|
|
419
|
+
lastMsg
|
|
420
|
+
} = args;
|
|
421
|
+
const totalUsed = summaryTokens + pendingTokens;
|
|
422
|
+
const usageRatio = normalizeContextUsageRatio(realContextUsagePercent);
|
|
423
|
+
let shouldTriggerByUsage = false;
|
|
424
|
+
if (usageRatio !== void 0) {
|
|
425
|
+
if (usageRatio >= 0.78) {
|
|
426
|
+
shouldTriggerByUsage = true;
|
|
427
|
+
} else if (usageRatio >= 0.65 && isActiveSummaryWorthDoing(pendingTokens, contextWindow)) {
|
|
428
|
+
shouldTriggerByUsage = true;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
if (totalUsed >= historyBudget) {
|
|
432
|
+
shouldTriggerByUsage = true;
|
|
433
|
+
}
|
|
434
|
+
if (typeof lastCompactedTokenCount === "number" && Number.isFinite(lastCompactedTokenCount) && lastCompactedTokenCount >= 0 && !force && !(usageRatio !== void 0 && usageRatio >= 0.78)) {
|
|
435
|
+
const minNewTokensToCompress = Math.min(4e4, Math.max(5e3, Math.floor(contextWindow * 0.03)));
|
|
436
|
+
if (totalUsed < lastCompactedTokenCount + minNewTokensToCompress) {
|
|
437
|
+
return { trigger: false, triggeredByRealUsage: false, shouldRunActiveSummary: false };
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
const shouldRunActiveSummary = force && reason === "manual" && !hasOpenEndedToolCall(lastMsg) && isActiveSummaryWorthDoing(pendingTokens, contextWindow);
|
|
441
|
+
const triggeredByRealUsage = usageRatio !== void 0 && shouldTriggerByUsage;
|
|
442
|
+
return { trigger: shouldTriggerByUsage || shouldRunActiveSummary, triggeredByRealUsage, shouldRunActiveSummary };
|
|
443
|
+
}
|
|
444
|
+
function calculateCompressCount(pendingMsgs, rawMessageBudget, opts) {
|
|
445
|
+
const { keepTailCount, totalUsed, historyBudget } = opts;
|
|
446
|
+
if (keepTailCount && totalUsed < historyBudget) {
|
|
447
|
+
return Math.max(0, pendingMsgs.length - ACTIVE_SUMMARY_TAIL_KEEP_COUNT);
|
|
448
|
+
}
|
|
449
|
+
let tokensToKeep = 0;
|
|
450
|
+
let keepCount = 0;
|
|
451
|
+
for (let i = pendingMsgs.length - 1; i >= 0; i--) {
|
|
452
|
+
const t = getMessageTokenCount(pendingMsgs[i]);
|
|
453
|
+
if (tokensToKeep + t > rawMessageBudget) break;
|
|
454
|
+
tokensToKeep += t;
|
|
455
|
+
keepCount++;
|
|
456
|
+
}
|
|
457
|
+
return pendingMsgs.length - keepCount;
|
|
458
|
+
}
|
|
459
|
+
function guardToolChainBoundary(pendingMsgs, compressCount) {
|
|
460
|
+
let count = compressCount;
|
|
461
|
+
while (count > 0 && count < pendingMsgs.length && pendingMsgs[count].role === "tool") {
|
|
462
|
+
count--;
|
|
463
|
+
}
|
|
464
|
+
if (count > 0) {
|
|
465
|
+
const lastCompressed = pendingMsgs[count - 1];
|
|
466
|
+
if (hasOpenEndedToolCall(lastCompressed)) {
|
|
467
|
+
count--;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return count;
|
|
471
|
+
}
|
|
472
|
+
function planCompression(input) {
|
|
473
|
+
const {
|
|
474
|
+
allMsgs,
|
|
475
|
+
summarizedBeforeId,
|
|
476
|
+
summary,
|
|
477
|
+
contextWindow,
|
|
478
|
+
force = false,
|
|
479
|
+
reason,
|
|
480
|
+
realContextUsagePercent
|
|
481
|
+
} = input;
|
|
482
|
+
const { pendingMsgs, startIndex } = findPendingMessages(allMsgs, summarizedBeforeId);
|
|
483
|
+
if (pendingMsgs.length === 0) return emptyPlan(startIndex);
|
|
484
|
+
const summaryTokens = estimateTokenCount(summary || "");
|
|
485
|
+
const pendingTokens = pendingMsgs.reduce((sum, msg) => sum + getMessageTokenCount(msg), 0);
|
|
486
|
+
const totalUsed = summaryTokens + pendingTokens;
|
|
487
|
+
const adjustedSummaryTokens = Math.max(summaryTokens, 1e3);
|
|
488
|
+
const recentLoad = classifyConversationLoad(pendingMsgs);
|
|
489
|
+
const { historyBudget, rawMessageBudget } = planContextUsage({
|
|
490
|
+
contextWindow,
|
|
491
|
+
summaryTokens: adjustedSummaryTokens,
|
|
492
|
+
recentLoad
|
|
493
|
+
});
|
|
494
|
+
const { trigger, triggeredByRealUsage, shouldRunActiveSummary } = shouldTriggerCompaction({
|
|
495
|
+
pendingTokens,
|
|
496
|
+
summaryTokens,
|
|
497
|
+
contextWindow,
|
|
498
|
+
historyBudget,
|
|
499
|
+
force,
|
|
500
|
+
reason,
|
|
501
|
+
realContextUsagePercent,
|
|
502
|
+
lastCompactedTokenCount: input.lastCompactedTokenCount,
|
|
503
|
+
lastMsg: pendingMsgs[pendingMsgs.length - 1]
|
|
504
|
+
});
|
|
505
|
+
if (!trigger) return emptyPlan(startIndex);
|
|
506
|
+
let compressCount = calculateCompressCount(pendingMsgs, rawMessageBudget, {
|
|
507
|
+
keepTailCount: shouldRunActiveSummary || triggeredByRealUsage,
|
|
508
|
+
totalUsed,
|
|
509
|
+
historyBudget
|
|
510
|
+
});
|
|
511
|
+
compressCount = guardToolChainBoundary(pendingMsgs, compressCount);
|
|
512
|
+
if (compressCount < MIN_COMPRESS_COUNT) return emptyPlan(startIndex);
|
|
513
|
+
const msgsToCompress = pendingMsgs.slice(0, compressCount);
|
|
514
|
+
const msgsToKeep = pendingMsgs.slice(compressCount);
|
|
515
|
+
const newSummarizedBeforeId = msgsToCompress[msgsToCompress.length - 1].id;
|
|
516
|
+
return {
|
|
517
|
+
shouldCompress: true,
|
|
518
|
+
compressCount,
|
|
519
|
+
msgsToCompress,
|
|
520
|
+
msgsToKeep,
|
|
521
|
+
newSummarizedBeforeId,
|
|
522
|
+
startIndex
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// packages/ai/context/compactionShared.ts
|
|
527
|
+
var COMPACTION_SUMMARY_SYSTEM_PROMPT = `\u4F60\u662F\u5BF9\u8BDD\u4E0A\u4E0B\u6587\u538B\u7F29\u5668\u3002\u6839\u636E\u3010\u73B0\u6709\u8BB0\u5FC6\u3011\u548C\u3010\u65B0\u589E\u5BF9\u8BDD\u3011\uFF0C\u8F93\u51FA\u53EF\u66FF\u4EE3\u539F\u59CB\u6D88\u606F\u7684\u4E8B\u5B9E\u6027\u8981\u70B9\uFF0C\u4F9B\u540E\u7EED\u5BF9\u8BDD\u76F4\u63A5\u4F7F\u7528\u3002
|
|
528
|
+
|
|
529
|
+
\u4E25\u683C\u53EA\u8F93\u51FA\u4E0B\u9762\u4E09\u90E8\u5206\uFF0C\u6807\u9898\u5FC5\u987B\u5B8C\u5168\u4E00\u81F4\uFF1A
|
|
530
|
+
\u5173\u952E\u4E8B\u5B9E\u6863\u6848
|
|
531
|
+
- ...
|
|
532
|
+
\u5BF9\u8BDD\u8FDB\u5C55\u4E0E\u5F85\u529E
|
|
533
|
+
- ...
|
|
534
|
+
\u6587\u4EF6\u64CD\u4F5C\u6E05\u5355
|
|
535
|
+
- ...
|
|
536
|
+
|
|
537
|
+
\u8981\u6C42\uFF1A
|
|
538
|
+
1) \u4F7F\u7528\u5BF9\u8BDD\u4E3B\u8BED\u8A00\uFF1B\u6DF7\u5408\u8BED\u8A00\u65F6\u4F18\u5148\u7528\u6237\u4E3B\u8981\u8BED\u8A00\uFF1B\u4E13\u6709\u540D\u8BCD\u3001\u6587\u4EF6\u8DEF\u5F84\u3001\u6807\u8BC6\u7B26\u3001\u547D\u4EE4\u4FDD\u7559\u539F\u6587\uFF0C\u4E0D\u8981\u7FFB\u8BD1\u6216\u8F6C\u8FF0\u3002
|
|
539
|
+
2) \u5173\u952E\u4E8B\u5B9E\u6863\u6848\u53EA\u4FDD\u7559\u4E4B\u540E\u7EE7\u7EED\u5BF9\u8BDD\u4ECD\u6709\u4EF7\u503C\u7684\u4FE1\u606F\uFF1A\u7528\u6237\u76EE\u6807/\u504F\u597D\u3001\u7EA6\u675F\u3001\u6280\u672F\u6808\u3001\u786E\u5B9A\u7684\u6587\u4EF6\u8DEF\u5F84\u3001\u6838\u5FC3\u51B3\u7B56\u3001\u672A\u5B8C\u6210\u5F85\u529E\u3002\u4FDD\u7559\u786E\u5207\u503C\uFF08\u7AEF\u53E3\u53F7\u3001\u7248\u672C\u53F7\u3001\u8DEF\u5F84\u3001\u53D8\u91CF\u540D\u3001\u9519\u8BEF\u4FE1\u606F\u539F\u6587\uFF09\uFF0C\u4E0D\u8981\u6982\u62EC\u6210"\u67D0\u4E2A\u7AEF\u53E3"\u6216"\u67D0\u4E2A\u6587\u4EF6"\u6216"\u67D0\u62A5\u9519"\u3002
|
|
540
|
+
3) \u5BF9\u8BDD\u8FDB\u5C55\u4E0E\u5F85\u529E\u4EE5\u7B2C\u4E00\u4EBA\u79F0\u7EED\u4F5C\u7B14\u8BB0\u7684\u53E3\u543B\u5199\uFF08"\u6211\u505A\u4E86\u2026""\u7528\u6237\u8981\u6C42\u2026""\u4E0B\u4E00\u6B65\u6211\u9700\u8981\u2026"\uFF09\uFF0C\u4E0D\u8981\u5199\u6210\u7B2C\u4E09\u65B9\u89C2\u5BDF\u62A5\u544A\u3002\u5148\u6781\u7B80\u6982\u62EC\u65E7\u4E0A\u4E0B\u6587\uFF0C\u518D\u66F4\u8BE6\u7EC6\u8BB0\u5F55\u6700\u8FD1\u8FDB\u5C55\u3001\u7ED3\u8BBA\u3001\u5206\u6B67\u4E0E\u4E0B\u4E00\u6B65\u3002\u5BF9\u4E8E\u58F0\u79F0\u5DF2\u5B8C\u6210\u4F46\u5C1A\u672A\u9A8C\u8BC1\u7684\u5DE5\u4F5C\uFF08\u5982\u5DE5\u5177\u8C03\u7528\u8FD4\u56DE\u6210\u529F\u4F46\u7ED3\u679C\u672A\u4EBA\u5DE5\u786E\u8BA4\uFF09\uFF0C\u660E\u786E\u6807\u6CE8"\uFF08\u5F85\u9A8C\u8BC1\uFF09"\u2014\u2014\u4E0D\u8981\u9ED8\u8BA4\u4FE1\u4EFB\u5DE5\u5177\u8FD4\u56DE\u503C\u3002
|
|
541
|
+
4) \u6587\u4EF6\u64CD\u4F5C\u6E05\u5355\uFF1A\u5217\u51FA\u672C\u6B21\u538B\u7F29\u8303\u56F4\u5185\u8BFB\u53D6\u3001\u5199\u5165\u3001\u7F16\u8F91\u8FC7\u7684\u6587\u4EF6\u8DEF\u5F84\u53CA\u64CD\u4F5C\u7C7B\u578B\uFF08\u5982: - \u8BFB\u53D6: path/to/file\uFF1B\u82E5\u672A\u6D89\u53CA\u6587\u4EF6\u64CD\u4F5C\u5199"\u65E0"\uFF09\u3002
|
|
542
|
+
5) \u5FFD\u7565\u5BD2\u6684\u3001\u91CD\u590D\u5C1D\u8BD5\u3001\u5DF2\u653E\u5F03\u65B9\u6848\u548C\u65E0\u4EF7\u503C\u5E9F\u8BDD\u3002
|
|
543
|
+
6) \u4E0D\u8981\u7F16\u9020\u672A\u51FA\u73B0\u7684\u4FE1\u606F\uFF1B\u4E0D\u8981\u5F00\u573A\u767D\u3001\u7ED3\u675F\u8BED\u3001markdown \u4EE3\u7801\u5757\u6216\u989D\u5916\u7AE0\u8282\uFF1B\u4E0D\u8981\u8C03\u7528\u4EFB\u4F55\u5DE5\u5177\u3002`;
|
|
544
|
+
function formatMessageContentFallback(msg) {
|
|
545
|
+
const content = serializeMessageContent(msg.content);
|
|
546
|
+
if (content) return content;
|
|
547
|
+
if (Array.isArray(msg.tool_calls)) {
|
|
548
|
+
return `[tool_calls:${msg.tool_calls.map((c) => c.function?.name).filter(Boolean).join(",")}]`;
|
|
549
|
+
}
|
|
550
|
+
return "[\u975E\u6587\u672C\u5185\u5BB9]";
|
|
551
|
+
}
|
|
552
|
+
function buildCompactionUserContent(args) {
|
|
553
|
+
const parts = [`\u3010\u73B0\u6709\u8BB0\u5FC6\u3011\uFF1A
|
|
554
|
+
${args.previousSummary || "(\u65E0)"}`];
|
|
555
|
+
if (args.fileOpsText !== void 0) {
|
|
556
|
+
parts.push(`\u3010\u6587\u4EF6\u64CD\u4F5C\u6E05\u5355\u3011\uFF1A
|
|
557
|
+
${args.fileOpsText || "\u65E0"}`);
|
|
558
|
+
}
|
|
559
|
+
parts.push(`\u3010\u65B0\u589E\u5BF9\u8BDD\u3011\uFF1A
|
|
560
|
+
${args.messagesText}`);
|
|
561
|
+
return parts.join("\n\n").trim();
|
|
562
|
+
}
|
|
563
|
+
function extractFileOperationsFromCalls(calls, resolveCanonicalName) {
|
|
564
|
+
const result = [];
|
|
565
|
+
const seen = /* @__PURE__ */ new Set();
|
|
566
|
+
const fileOperationByTool = {
|
|
567
|
+
readFile: "read",
|
|
568
|
+
writeFile: "write",
|
|
569
|
+
editFile: "edit"
|
|
570
|
+
};
|
|
571
|
+
for (const call of calls) {
|
|
572
|
+
const rawName = call.function?.name || call.name || "";
|
|
573
|
+
if (!rawName) continue;
|
|
574
|
+
const canonicalName = resolveCanonicalName(rawName);
|
|
575
|
+
const opType = fileOperationByTool[canonicalName];
|
|
576
|
+
if (!opType) continue;
|
|
577
|
+
let rawArgs = call.function?.arguments;
|
|
578
|
+
let parsedArgs = null;
|
|
579
|
+
if (typeof rawArgs === "string") {
|
|
580
|
+
try {
|
|
581
|
+
parsedArgs = JSON.parse(rawArgs);
|
|
582
|
+
} catch {
|
|
583
|
+
}
|
|
584
|
+
} else if (typeof rawArgs === "object" && rawArgs !== null) {
|
|
585
|
+
parsedArgs = rawArgs;
|
|
586
|
+
}
|
|
587
|
+
const path = parsedArgs?.path ?? parsedArgs?.filePath ?? parsedArgs?.file;
|
|
588
|
+
if (typeof path === "string" && path.trim()) {
|
|
589
|
+
const key = `${opType}:${path.trim()}`;
|
|
590
|
+
if (!seen.has(key)) {
|
|
591
|
+
seen.add(key);
|
|
592
|
+
result.push({ type: opType, path: path.trim() });
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return result;
|
|
597
|
+
}
|
|
598
|
+
function formatFileOperationsFromMessages(msgs, resolveCanonicalName) {
|
|
599
|
+
const allOps = [];
|
|
600
|
+
for (const msg of msgs) {
|
|
601
|
+
if (!Array.isArray(msg.tool_calls)) continue;
|
|
602
|
+
allOps.push(
|
|
603
|
+
...extractFileOperationsFromCalls(msg.tool_calls, resolveCanonicalName)
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
if (allOps.length === 0) return "\u65E0";
|
|
607
|
+
const typeLabelMap = {
|
|
608
|
+
read: "\u8BFB\u53D6",
|
|
609
|
+
write: "\u5199\u5165",
|
|
610
|
+
edit: "\u7F16\u8F91"
|
|
611
|
+
};
|
|
612
|
+
return allOps.map((op) => `- ${typeLabelMap[op.type]}: ${op.path}`).join("\n");
|
|
613
|
+
}
|
|
614
|
+
var TOOL_RESULT_TRUNCATE_CHARS = 4e3;
|
|
615
|
+
function truncateContentForSummary(role, content, maxChars = TOOL_RESULT_TRUNCATE_CHARS) {
|
|
616
|
+
if (role !== "tool" || content.length <= maxChars) return content;
|
|
617
|
+
const truncated = content.slice(0, maxChars);
|
|
618
|
+
const omitted = content.length - maxChars;
|
|
619
|
+
return `${truncated}
|
|
620
|
+
|
|
621
|
+
[... ${omitted} chars truncated ...]`;
|
|
622
|
+
}
|
|
623
|
+
function formatMessagesForSummaryWithTruncation(msgs, maxToolResultChars = TOOL_RESULT_TRUNCATE_CHARS) {
|
|
624
|
+
return msgs.map((msg) => {
|
|
625
|
+
const rawContent = serializeMessageContent(msg.content) || "";
|
|
626
|
+
const truncated = truncateContentForSummary(
|
|
627
|
+
msg.role,
|
|
628
|
+
rawContent,
|
|
629
|
+
maxToolResultChars
|
|
630
|
+
);
|
|
631
|
+
const text = truncated || formatMessageContentFallback(msg);
|
|
632
|
+
return `${msg.role}: ${text}`;
|
|
633
|
+
}).join("\n");
|
|
634
|
+
}
|
|
635
|
+
function buildCompactionMetrics(args) {
|
|
636
|
+
const {
|
|
637
|
+
reason,
|
|
638
|
+
previousSummary,
|
|
639
|
+
msgsToCompress,
|
|
640
|
+
msgsToKeep,
|
|
641
|
+
newSummary,
|
|
642
|
+
summaryUsage,
|
|
643
|
+
estimateTokens,
|
|
644
|
+
estimateMessageTokens
|
|
645
|
+
} = args;
|
|
646
|
+
return {
|
|
647
|
+
reason,
|
|
648
|
+
previousSummaryTokens: estimateTokens(previousSummary || ""),
|
|
649
|
+
compressedTokens: msgsToCompress.reduce((s, m) => s + estimateMessageTokens(m), 0),
|
|
650
|
+
retainedTokens: msgsToKeep.reduce((s, m) => s + estimateMessageTokens(m), 0),
|
|
651
|
+
newSummaryTokens: estimateTokens(newSummary || ""),
|
|
652
|
+
compressedCount: msgsToCompress.length,
|
|
653
|
+
retainedCount: msgsToKeep.length,
|
|
654
|
+
summaryUsage,
|
|
655
|
+
hadPreviousSummary: previousSummary.trim().length > 0
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
function buildCompactionMetricsFromPlan(args) {
|
|
659
|
+
return buildCompactionMetrics({
|
|
660
|
+
reason: args.reason,
|
|
661
|
+
previousSummary: args.previousSummary,
|
|
662
|
+
msgsToCompress: args.plan.msgsToCompress,
|
|
663
|
+
msgsToKeep: args.plan.msgsToKeep,
|
|
664
|
+
newSummary: args.newSummary,
|
|
665
|
+
summaryUsage: args.summaryUsage,
|
|
666
|
+
estimateTokens: estimateTokenCount,
|
|
667
|
+
estimateMessageTokens: getMessageTokenCount
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
function formatCompactionMetricsLog(metrics) {
|
|
671
|
+
const totalBefore = metrics.previousSummaryTokens + metrics.compressedTokens;
|
|
672
|
+
const totalAfter = metrics.newSummaryTokens + metrics.retainedTokens;
|
|
673
|
+
const ratio = totalBefore > 0 ? (totalAfter / totalBefore).toFixed(2) : "N/A";
|
|
674
|
+
const llmInfo = metrics.summaryUsage ? `, summary_llm_in=${metrics.summaryUsage.input_tokens ?? "?"} out=${metrics.summaryUsage.output_tokens ?? "?"}` : "";
|
|
675
|
+
return `[Compaction] reason=${metrics.reason} compressed=${metrics.compressedCount}->${metrics.retainedCount} msgs, tokens=${totalBefore}->${totalAfter} (ratio=${ratio})${llmInfo}`;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// packages/core/clipCompactText.ts
|
|
679
|
+
function clipCompactText(value, max, ellipsis = "...") {
|
|
680
|
+
const compact = compactWhitespace(value);
|
|
681
|
+
if (compact.length <= max) return compact;
|
|
682
|
+
if (max <= ellipsis.length) return compact.slice(0, max);
|
|
683
|
+
return `${compact.slice(0, max - ellipsis.length)}${ellipsis}`;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
export {
|
|
687
|
+
clipCompactText,
|
|
688
|
+
estimateTokenCount,
|
|
689
|
+
buildDatabaseFileContentUrl,
|
|
690
|
+
BUILTIN_TITLE_LLM_CONFIG,
|
|
691
|
+
BUILTIN_SUMMARY_LLM_CONFIG,
|
|
692
|
+
serializeMessageContent,
|
|
693
|
+
normalizeAssistantContentBuffer,
|
|
694
|
+
planContextUsage,
|
|
695
|
+
planCompression,
|
|
696
|
+
COMPACTION_SUMMARY_SYSTEM_PROMPT,
|
|
697
|
+
buildCompactionUserContent,
|
|
698
|
+
formatFileOperationsFromMessages,
|
|
699
|
+
formatMessagesForSummaryWithTruncation,
|
|
700
|
+
buildCompactionMetricsFromPlan,
|
|
701
|
+
formatCompactionMetricsLog
|
|
702
|
+
};
|