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.
Files changed (108) hide show
  1. package/{_executeModel-VBHHG7LT.js → _executeModel-K47XKKPU.js} +32 -31
  2. package/{action-FENWPT3C.js → action-HI3VRQLP.js} +7 -7
  3. package/{addContentAction-Z5S5ZQ7I.js → addContentAction-NCURJ6PK.js} +6 -6
  4. package/{addDialogAgentAction-VUNVD2XR.js → addDialogAgentAction-RCY4ECF4.js} +5 -5
  5. package/{agentDeleteCommand-LLGZXUYJ.js → agentDeleteCommand-7BBZCONG.js} +26 -25
  6. package/{agentEmailCommands-LC2FPN6G.js → agentEmailCommands-D6FAT5HM.js} +38 -37
  7. package/{agentListCommands-A6OBQ3QX.js → agentListCommands-YPNNMGSJ.js} +28 -27
  8. package/{agentMachineCommands-4O4Q5B5X.js → agentMachineCommands-VYRVSKUC.js} +26 -25
  9. package/{agentRecordCommands-W22RIQRV.js → agentRecordCommands-4J52H5NK.js} +37 -36
  10. package/{agentRunCommand-V4OBU4FB.js → agentRunCommand-LH4RA6FA.js} +38 -37
  11. package/{agentRunControl-AKBN2366.js → agentRunControl-SCIVRZWX.js} +9 -1
  12. package/{agentRuntimeLocal-I57YSGH4.js → agentRuntimeLocal-G7GK545E.js} +23 -22
  13. package/{agentSlice-3ZHY7RAO.js → agentSlice-4ZLEPC3M.js} +6 -6
  14. package/{appDeleteCommands-DJJF466K.js → appDeleteCommands-AOZED7QJ.js} +27 -26
  15. package/{appDeployCommands-WJZGIOEZ.js → appDeployCommands-XJY27BDS.js} +27 -26
  16. package/{appDeployStatusCommands-ICYXUJNO.js → appDeployStatusCommands-HKZYAPB2.js} +27 -26
  17. package/{appGetCommands-UOCWYJPV.js → appGetCommands-VXJLPRYI.js} +27 -26
  18. package/{appListCommands-EOKWTXPW.js → appListCommands-3LU6AB4G.js} +27 -26
  19. package/{authCommand-H5KE7K7K.js → authCommand-3GQR43KB.js} +5 -5
  20. package/{chunk-ZFTCLBEX.js → chunk-2IJAKBK2.js} +3 -1
  21. package/chunk-2K4NDPT5.js +1524 -0
  22. package/{chunk-SWOTB2TX.js → chunk-2MSOY7A5.js} +49 -33
  23. package/{chunk-W2YKDXT7.js → chunk-2YT3KLHX.js} +1 -1
  24. package/{chunk-HLG6GAUD.js → chunk-3IU7WEJD.js} +1 -1
  25. package/{chunk-Q24P6TUS.js → chunk-43EPBPZ2.js} +1 -1
  26. package/{chunk-3RIWR23B.js → chunk-4URO6HMS.js} +1 -1
  27. package/{chunk-UTQZ73QQ.js → chunk-5EDVWWE3.js} +1 -1
  28. package/{chunk-GVKTKT3O.js → chunk-5JQRISUS.js} +3 -3
  29. package/{chunk-GAGUBI42.js → chunk-5MVFYKBL.js} +5 -5
  30. package/{chunk-R5V5G73M.js → chunk-5RDLGLAP.js} +0 -1
  31. package/{chunk-4SAV7BD7.js → chunk-7KNERA53.js} +53 -15
  32. package/{chunk-MEUZFIAJ.js → chunk-7S54ZGF6.js} +2 -2
  33. package/{chunk-IZ3CBMD5.js → chunk-ATK5WJOA.js} +4 -4
  34. package/chunk-BGTUGS3T.js +702 -0
  35. package/{chunk-DI6MXJK5.js → chunk-C3NYMZTQ.js} +16 -14
  36. package/{chunk-HI7QZNWX.js → chunk-CPUZW54L.js} +4 -4
  37. package/{chunk-PJY5AH5A.js → chunk-DPR66GY6.js} +1 -1
  38. package/{chunk-MMCVBEAD.js → chunk-E2CFIWQR.js} +42 -32
  39. package/{chunk-YWGSCF37.js → chunk-E3APEOIM.js} +1 -1
  40. package/{chunk-UKC5HU2C.js → chunk-EATVNXFX.js} +7 -7
  41. package/{chunk-G5JHHUAK.js → chunk-F3MP7CP6.js} +1 -1
  42. package/{chunk-FS5TTXPS.js → chunk-FLYQAMF4.js} +3 -3
  43. package/{chunk-446VANPP.js → chunk-G5GVZAXF.js} +4 -4
  44. package/{chunk-KWKD3BCC.js → chunk-H6COXALE.js} +78 -27
  45. package/{chunk-56IUA7RU.js → chunk-K76HYM3O.js} +1 -1
  46. package/{chunk-DKRT67FG.js → chunk-KGEVMUMI.js} +3 -3
  47. package/{chunk-A4JDTA5T.js → chunk-LAXMH7JY.js} +6 -6
  48. package/{chunk-L3VQOVKK.js → chunk-LBEWOWVL.js} +4 -4
  49. package/{chunk-66O5MZYH.js → chunk-NEGMZP6Q.js} +1 -1
  50. package/{chunk-7CD24PU4.js → chunk-NMK2JHKM.js} +9 -7
  51. package/{chunk-QLV2GKU5.js → chunk-OT2AXEQD.js} +26 -5
  52. package/{chunk-CV6I4HBA.js → chunk-PTHDLIRB.js} +1 -1
  53. package/{chunk-2XM5KUNE.js → chunk-Q6L3O67D.js} +2 -2
  54. package/{chunk-G6VITLCZ.js → chunk-QHWPAW5M.js} +2 -2
  55. package/{chunk-KWCLUYGQ.js → chunk-QL6ELRVS.js} +1 -1
  56. package/chunk-RJ7KLCWY.js +5134 -0
  57. package/{chunk-T3Y5EMJS.js → chunk-SFWZUTCI.js} +1 -1
  58. package/{chunk-XD5NQEOH.js → chunk-UDA3ZYLW.js} +1 -1
  59. package/{chunk-YLADSPDU.js → chunk-V54H24CQ.js} +2 -2
  60. package/{chunk-SZ5CBYMZ.js → chunk-WEID4JLC.js} +2 -2
  61. package/{chunk-KW47OSRJ.js → chunk-WMH2G6XJ.js} +91 -179
  62. package/{chunk-4PWB7JRR.js → chunk-XFG3BAKN.js} +1 -0
  63. package/chunk-XGJ75KN2.js +7889 -0
  64. package/{chunk-OYK7PA5U.js → chunk-XPML3KYZ.js} +6 -6
  65. package/{chunk-TJYWZ3LO.js → chunk-YHGHADBQ.js} +2 -2
  66. package/{chunk-DCWBP2O7.js → chunk-YJZGAAVX.js} +14 -12
  67. package/{chunk-BOL2D2JW.js → chunk-ZJ2WITOO.js} +2 -2
  68. package/{chunk-DWQNDGO7.js → chunk-ZJH3LKEW.js} +2 -2
  69. package/{createAgentAutomationAction-3GMH6ORX.js → createAgentAutomationAction-AECD5YCU.js} +13 -12
  70. package/{createDialogAction-R5MCL4RE.js → createDialogAction-MZUC37CA.js} +14 -13
  71. package/{createPageAction-QYTG656R.js → createPageAction-KRTBWM2S.js} +13 -12
  72. package/{db-IPCJ43PW.js → db-6DPSJ6WT.js} +4 -2
  73. package/{dbSlice-OBV7VFCF.js → dbSlice-BBL3PEVW.js} +5 -5
  74. package/{deleteFile-AC45HYSM.js → deleteFile-RJTEPOT4.js} +3 -3
  75. package/{dialogCommands-NUQGIXVZ.js → dialogCommands-RFADXVV6.js} +27 -26
  76. package/{dialogSlice-CFDECXEU.js → dialogSlice-EWNZ2HFD.js} +12 -12
  77. package/{docCreateCommands-UNFCXB5N.js → docCreateCommands-ZHX6SX5M.js} +26 -25
  78. package/{docDeleteCommands-NG5IVKE5.js → docDeleteCommands-3EEM7ITO.js} +27 -26
  79. package/{docReadCommands-6J7MUUX6.js → docReadCommands-JOMLMZTC.js} +26 -25
  80. package/{docStore-MZZWJM4F.js → docStore-YKTKKH3N.js} +14 -13
  81. package/{docUpdateCommands-6AW3VZOX.js → docUpdateCommands-PGAYLKLC.js} +26 -25
  82. package/{getPricing-XQYSSVV6.js → getPricing-QO5TYNCK.js} +2 -2
  83. package/{handleSendMessageAction-IU2QNTLM.js → handleSendMessageAction-VX4CGWAJ.js} +12 -12
  84. package/index.js +63 -63
  85. package/{localDialogRead-P72W2U2R.js → localDialogRead-3DBXVYXS.js} +1 -1
  86. package/{machineCommands-Z2QEWTHZ.js → machineCommands-A2WFB37F.js} +36 -35
  87. package/{machineWsRunDispatch-SJTYHZHN.js → machineWsRunDispatch-E5R54UWZ.js} +36 -35
  88. package/package.json +1 -1
  89. package/{read-QK7ZRX6G.js → read-64OQDO3I.js} +3 -3
  90. package/{readDocTool-EYDMVRBL.js → readDocTool-MXM3T6PE.js} +1 -1
  91. package/{readlineWorkspace-EY3BPXIU.js → readlineWorkspace-S4A6UYVJ.js} +125 -79
  92. package/{removeDialogAgentAction-TBW3UZJW.js → removeDialogAgentAction-NEKVAMSH.js} +7 -7
  93. package/{runAgentClientLoop-N3YDLTMS.js → runAgentClientLoop-C6IIUQ36.js} +27 -26
  94. package/{setDialogExtraReferencesAction-Q3ANF2NR.js → setDialogExtraReferencesAction-WTOHQDIV.js} +6 -6
  95. package/{setPrimaryDialogAgentAction-FQ5R3EFJ.js → setPrimaryDialogAgentAction-LDJOYC4F.js} +7 -7
  96. package/{settingSlice-JKKV2T7O.js → settingSlice-4M37TN7V.js} +6 -6
  97. package/{skillDiscovery-I3QRA7NE.js → skillDiscovery-Y3HALY2U.js} +3 -3
  98. package/{spaceCommands-R6AEQNLG.js → spaceCommands-SKCMLOC6.js} +210 -28
  99. package/{spaceSlice-MCH7RLLP.js → spaceSlice-6VOPELQN.js} +13 -12
  100. package/{streamAgentChatTurn-Q4U2CVMI.js → streamAgentChatTurn-623CNKWF.js} +35 -32
  101. package/{switchDialogAgentAction-QQGVE4SL.js → switchDialogAgentAction-XVWGKR2Z.js} +5 -5
  102. package/{tableCommands-PRJNWN6Q.js → tableCommands-RJZ3V4TF.js} +1 -1
  103. package/{tools-Y3UBLLYW.js → tools-IN4B36PN.js} +21 -20
  104. package/{tuiSummaryLlmCaller-4474IBTI.js → tuiSummaryLlmCaller-SRZ4QQUP.js} +19 -5
  105. package/{updateDialogTitleAction-3J7GH67I.js → updateDialogTitleAction-4ABIVEYY.js} +18 -16
  106. package/chunk-OB6FBSH3.js +0 -47
  107. package/chunk-THTAR67C.js +0 -16338
  108. 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
+ };