dsh-codearts 1.2.12 → 1.2.13

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/CHANGELOG.md CHANGED
@@ -3,6 +3,20 @@
3
3
  本文件记录本插件的重要改动。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
4
4
  版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
5
5
 
6
+ ## [1.2.13] - 2026-11-09
7
+
8
+ ### 修复
9
+
10
+ - **带图的请求不再被误判「上下文放不下」**:图片在请求里是 `data:image/...;base64,...`
11
+ 字面量,旧的估算按字符数折算,一张 400 KB 的 A4 页渲染图会被算成十几万 token
12
+ (真实视觉编码器只要一两千),8 张图就能把 1M 窗口假性撑爆,上游一次请求都没发出,
13
+ 用户只看到「请新建会话」。现在图片按像素面积估:只读图片头(PNG IHDR / JPEG SOF /
14
+ GIF)拿宽高,按 28×28 块折算并钳在 85~8000,读不出尺寸时退回 1600;文本仍按原规则,
15
+ `role` / `tool_calls` 等结构化字段也照旧。感谢 [@rachel1028-blip](https://github.com/rachel1028-blip)
16
+ 的 [PR #6](https://github.com/elegant01/dsh-codearts/pull/6)。
17
+ - **`pnpm build` 在含空格的路径下不再挂**:`scripts/wrap-client.mjs` 改用
18
+ `fileURLToPath` 取路径,工作目录里的空格不会再被编码成 `%20` 让最后一步找不到产物。
19
+
6
20
  ## [1.2.12] - 2026-11-09
7
21
 
8
22
  ### 变更
package/lib/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { G as codeartsAccountsPath, H as CodeArtsAccountStore, f as fetchCallerIdentity, i as discoverModels, n as CodeArtsUsageTracker, r as codeartsUsagePath, t as CODEARTS_VERSION, z as isBenefitModel } from "./version-BWaXmzeW.mjs";
2
+ import { G as codeartsAccountsPath, H as CodeArtsAccountStore, f as fetchCallerIdentity, i as discoverModels, n as CodeArtsUsageTracker, r as codeartsUsagePath, t as CODEARTS_VERSION, z as isBenefitModel } from "./version-E5iTxpWh.mjs";
3
3
  import { existsSync, statSync } from "node:fs";
4
4
  //#region src/bin.ts
5
5
  /**
@@ -72,98 +72,98 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
72
72
  document.head.appendChild(tag);
73
73
  }
74
74
  var CodeArtsPluginCard_module_css_default = {
75
- "balanceMeta": "xoziZG_balanceMeta",
76
- "statSub": "xoziZG_statSub",
75
+ "modelSpec": "xoziZG_modelSpec",
76
+ "sectionHead": "xoziZG_sectionHead",
77
+ "heatLegend": "xoziZG_heatLegend",
78
+ "heatLegendChip": "xoziZG_heatLegendChip",
77
79
  "usageTipRow": "xoziZG_usageTipRow",
80
+ "heatAxisSlot": "xoziZG_heatAxisSlot",
81
+ "accountToolbar": "xoziZG_accountToolbar",
82
+ "heatGrid": "xoziZG_heatGrid",
78
83
  "sectionLabel": "xoziZG_sectionLabel",
79
- "statusLine": "xoziZG_statusLine",
80
- "statValue": "xoziZG_statValue",
81
- "doctorRow": "xoziZG_doctorRow",
82
- "usageBar": "xoziZG_usageBar",
83
- "choices": "xoziZG_choices",
84
+ "actions": "xoziZG_actions",
85
+ "modelTrack": "xoziZG_modelTrack",
86
+ "body": "xoziZG_body",
84
87
  "claimAllRow": "xoziZG_claimAllRow",
85
- "balanceRow": "xoziZG_balanceRow",
86
- "usageTipName": "xoziZG_usageTipName",
87
- "modelTokens": "xoziZG_modelTokens",
88
- "fieldLabel": "xoziZG_fieldLabel",
89
- "modelFill": "xoziZG_modelFill",
90
- "heatCell": "xoziZG_heatCell",
91
- "skeleton": "xoziZG_skeleton",
92
- "section": "xoziZG_section",
93
- "meta": "xoziZG_meta",
94
88
  "creditBlock": "xoziZG_creditBlock",
95
- "modelRequests": "xoziZG_modelRequests",
96
- "field": "xoziZG_field",
97
- "balance": "xoziZG_balance",
98
- "accountCard": "xoziZG_accountCard",
99
89
  "avatar": "xoziZG_avatar",
100
- "heatHours": "xoziZG_heatHours",
101
- "name": "xoziZG_name",
102
- "accountToggleLabel": "xoziZG_accountToggleLabel",
103
- "manualSummary": "xoziZG_manualSummary",
104
- "manual": "xoziZG_manual",
105
- "heatAxisSlot": "xoziZG_heatAxisSlot",
106
- "manualForm": "xoziZG_manualForm",
90
+ "expiryLabel": "xoziZG_expiryLabel",
107
91
  "creditRows": "xoziZG_creditRows",
92
+ "statSub": "xoziZG_statSub",
93
+ "usageBar": "xoziZG_usageBar",
94
+ "link": "xoziZG_link",
108
95
  "expiryRow": "xoziZG_expiryRow",
109
96
  "modelRow": "xoziZG_modelRow",
110
- "area": "xoziZG_area",
111
- "updated": "xoziZG_updated",
112
- "body": "xoziZG_body",
113
- "accountEntry": "xoziZG_accountEntry",
114
- "accountInfo": "xoziZG_accountInfo",
115
- "heatWeekday": "xoziZG_heatWeekday",
116
- "accountRow": "xoziZG_accountRow",
117
- "heatLegendChip": "xoziZG_heatLegendChip",
118
- "modelSpec": "xoziZG_modelSpec",
119
- "tabPanel": "xoziZG_tabPanel",
120
- "modelChart": "xoziZG_modelChart",
121
- "accountToggle": "xoziZG_accountToggle",
122
- "usageTipSep": "xoziZG_usageTipSep",
123
- "count": "xoziZG_count",
97
+ "modelFill": "xoziZG_modelFill",
98
+ "heatHours": "xoziZG_heatHours",
124
99
  "trendTip": "xoziZG_trendTip",
125
- "tabs": "xoziZG_tabs",
126
- "heatAxis": "xoziZG_heatAxis",
127
- "doctorName": "xoziZG_doctorName",
128
- "accountToolbar": "xoziZG_accountToolbar",
129
- "hint": "xoziZG_hint",
130
- "link": "xoziZG_link",
131
- "header": "xoziZG_header",
132
- "heatHourCell": "xoziZG_heatHourCell",
133
- "statLabel": "xoziZG_statLabel",
134
- "desc": "xoziZG_desc",
135
- "usageFill": "xoziZG_usageFill",
136
- "headText": "xoziZG_headText",
137
- "barFill": "xoziZG_barFill",
138
- "actions": "xoziZG_actions",
139
- "modelName": "xoziZG_modelName",
100
+ "skeleton": "xoziZG_skeleton",
140
101
  "skeletonRow": "xoziZG_skeletonRow",
141
- "check": "xoziZG_check",
142
- "accountRowActions": "xoziZG_accountRowActions",
143
- "choiceRow": "xoziZG_choiceRow",
144
- "skeletonBreath": "xoziZG_skeletonBreath",
102
+ "section": "xoziZG_section",
145
103
  "doctorList": "xoziZG_doctorList",
146
- "bar": "xoziZG_bar",
104
+ "doctorRow": "xoziZG_doctorRow",
147
105
  "balanceUnit": "xoziZG_balanceUnit",
106
+ "name": "xoziZG_name",
107
+ "statLabel": "xoziZG_statLabel",
108
+ "check": "xoziZG_check",
109
+ "accountRow": "xoziZG_accountRow",
110
+ "manualSummary": "xoziZG_manualSummary",
111
+ "skeletonBreath": "xoziZG_skeletonBreath",
112
+ "manual": "xoziZG_manual",
113
+ "accountToggle": "xoziZG_accountToggle",
114
+ "usageTipName": "xoziZG_usageTipName",
115
+ "modelShare": "xoziZG_modelShare",
116
+ "choices": "xoziZG_choices",
117
+ "statGrid": "xoziZG_statGrid",
118
+ "danger": "xoziZG_danger",
119
+ "accountName": "xoziZG_accountName",
120
+ "barFill": "xoziZG_barFill",
121
+ "header": "xoziZG_header",
148
122
  "accountHint": "xoziZG_accountHint",
149
- "modelTrack": "xoziZG_modelTrack",
150
- "heatLegend": "xoziZG_heatLegend",
123
+ "creditHint": "xoziZG_creditHint",
151
124
  "card": "xoziZG_card",
152
- "creditLink": "xoziZG_creditLink",
153
- "modelShare": "xoziZG_modelShare",
154
- "expiryLabel": "xoziZG_expiryLabel",
125
+ "creditRow": "xoziZG_creditRow",
126
+ "accountNameRow": "xoziZG_accountNameRow",
127
+ "modelChart": "xoziZG_modelChart",
128
+ "usageTipSep": "xoziZG_usageTipSep",
129
+ "modelName": "xoziZG_modelName",
130
+ "heatHourCell": "xoziZG_heatHourCell",
155
131
  "creditFooter": "xoziZG_creditFooter",
156
- "accountName": "xoziZG_accountName",
157
- "sectionHead": "xoziZG_sectionHead",
132
+ "error": "xoziZG_error",
133
+ "accountCard": "xoziZG_accountCard",
134
+ "field": "xoziZG_field",
135
+ "accountInfo": "xoziZG_accountInfo",
136
+ "creditLink": "xoziZG_creditLink",
137
+ "count": "xoziZG_count",
138
+ "modelRequests": "xoziZG_modelRequests",
139
+ "heatCell": "xoziZG_heatCell",
140
+ "tabPanel": "xoziZG_tabPanel",
141
+ "statValue": "xoziZG_statValue",
142
+ "balanceMeta": "xoziZG_balanceMeta",
158
143
  "usageTip": "xoziZG_usageTip",
144
+ "heatAxis": "xoziZG_heatAxis",
145
+ "choiceRow": "xoziZG_choiceRow",
146
+ "accountToggleLabel": "xoziZG_accountToggleLabel",
147
+ "area": "xoziZG_area",
148
+ "balance": "xoziZG_balance",
149
+ "meta": "xoziZG_meta",
150
+ "modelTokens": "xoziZG_modelTokens",
151
+ "balanceRow": "xoziZG_balanceRow",
152
+ "statusLine": "xoziZG_statusLine",
153
+ "bar": "xoziZG_bar",
154
+ "headText": "xoziZG_headText",
155
+ "hint": "xoziZG_hint",
156
+ "desc": "xoziZG_desc",
157
+ "usageFill": "xoziZG_usageFill",
158
+ "fieldLabel": "xoziZG_fieldLabel",
159
+ "doctorName": "xoziZG_doctorName",
160
+ "accountEntry": "xoziZG_accountEntry",
161
+ "tabs": "xoziZG_tabs",
162
+ "heatWeekday": "xoziZG_heatWeekday",
163
+ "manualForm": "xoziZG_manualForm",
159
164
  "statCard": "xoziZG_statCard",
160
- "heatGrid": "xoziZG_heatGrid",
161
- "error": "xoziZG_error",
162
- "accountNameRow": "xoziZG_accountNameRow",
163
- "creditRow": "xoziZG_creditRow",
164
- "creditHint": "xoziZG_creditHint",
165
- "danger": "xoziZG_danger",
166
- "statGrid": "xoziZG_statGrid"
165
+ "updated": "xoziZG_updated",
166
+ "accountRowActions": "xoziZG_accountRowActions"
167
167
  };
168
168
  //#endregion
169
169
  //#region src/client/CodeArtsPluginCard.tsx
@@ -2676,14 +2676,14 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
2676
2676
  document.head.appendChild(tag);
2677
2677
  }
2678
2678
  var CodeArtsPanel_module_css_default = {
2679
- "title": "Z66cgG_title",
2680
- "page": "Z66cgG_page",
2681
- "body": "Z66cgG_body",
2682
2679
  "desc": "Z66cgG_desc",
2683
- "icon": "Z66cgG_icon",
2680
+ "head": "Z66cgG_head",
2684
2681
  "back": "Z66cgG_back",
2682
+ "icon": "Z66cgG_icon",
2685
2683
  "backCaret": "Z66cgG_backCaret",
2686
- "head": "Z66cgG_head"
2684
+ "title": "Z66cgG_title",
2685
+ "page": "Z66cgG_page",
2686
+ "body": "Z66cgG_body"
2687
2687
  };
2688
2688
  //#endregion
2689
2689
  //#region src/client/CodeArtsPanel.tsx
package/lib/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as signedGet, B as markModelUnavailable, C as isTpmLimit, D as pickDailyWelfareCampaign, E as modelUnavailableReasonText, F as creditRatioLabel, G as codeartsAccountsPath, H as CodeArtsAccountStore, I as filterEnabledModels, J as startLogin, K as codeartsAuthPath, L as forgetModelUnavailable, M as CodeArtsCatalog, N as FALLBACK_CODEARTS_MODELS, O as prepareChatBody, P as clearBenefitBlocked, R as isBenefitBlocked, S as isQueueableRate, T as maxTokensCeilingFor, U as CodeArtsCredentialStore, V as modelUnavailableReason, W as MANUAL_ACCOUNT_ID, _ as isConcurrencyCap, a as refreshCatalog, b as isNotMultimodal, c as chatStream, d as degradeTokenCeiling, f as fetchCallerIdentity, g as firstFrameError, h as fetchWelfareCampaigns, i as discoverModels, j as upstreamErrorMessage, k as rateLimitFrame, l as claimDailyWelfare, m as fetchQueueStatus, n as CodeArtsUsageTracker, o as SNAP_HOST, p as fetchModels, q as credentialFromOAuth, r as codeartsUsagePath, s as canonicalModel, t as CODEARTS_VERSION, u as clearQueueStatus, v as isIamTokenError, w as isWelfareClaimedStatus, x as isParamInvalidFrame, y as isModelNotAccessible, z as isBenefitModel } from "./version-BWaXmzeW.mjs";
1
+ import { A as signedGet, B as markModelUnavailable, C as isTpmLimit, D as pickDailyWelfareCampaign, E as modelUnavailableReasonText, F as creditRatioLabel, G as codeartsAccountsPath, H as CodeArtsAccountStore, I as filterEnabledModels, J as startLogin, K as codeartsAuthPath, L as forgetModelUnavailable, M as CodeArtsCatalog, N as FALLBACK_CODEARTS_MODELS, O as prepareChatBody, P as clearBenefitBlocked, R as isBenefitBlocked, S as isQueueableRate, T as maxTokensCeilingFor, U as CodeArtsCredentialStore, V as modelUnavailableReason, W as MANUAL_ACCOUNT_ID, _ as isConcurrencyCap, a as refreshCatalog, b as isNotMultimodal, c as chatStream, d as degradeTokenCeiling, f as fetchCallerIdentity, g as firstFrameError, h as fetchWelfareCampaigns, i as discoverModels, j as upstreamErrorMessage, k as rateLimitFrame, l as claimDailyWelfare, m as fetchQueueStatus, n as CodeArtsUsageTracker, o as SNAP_HOST, p as fetchModels, q as credentialFromOAuth, r as codeartsUsagePath, s as canonicalModel, t as CODEARTS_VERSION, u as clearQueueStatus, v as isIamTokenError, w as isWelfareClaimedStatus, x as isParamInvalidFrame, y as isModelNotAccessible, z as isBenefitModel } from "./version-E5iTxpWh.mjs";
2
2
  import { i as lazyApi, r as createProvider } from "./models-CgKCibpk.mjs";
3
3
  import z from "@deepseek-ai/schemastery";
4
4
  import { randomBytes, timingSafeEqual } from "node:crypto";
@@ -1382,6 +1382,8 @@ var upstream_exports = /* @__PURE__ */ __exportAll({
1382
1382
  claimDailyWelfare: () => claimDailyWelfare,
1383
1383
  clearQueueStatus: () => clearQueueStatus,
1384
1384
  degradeTokenCeiling: () => degradeTokenCeiling,
1385
+ estimateImageTokens: () => estimateImageTokens,
1386
+ estimatePromptTokens: () => estimatePromptTokens,
1385
1387
  estimateTokens: () => estimateTokens,
1386
1388
  fetchCallerIdentity: () => fetchCallerIdentity,
1387
1389
  fetchModels: () => fetchModels,
@@ -1523,10 +1525,13 @@ function degradeTokenCeiling(id) {
1523
1525
  return next;
1524
1526
  }
1525
1527
  /**
1526
- * 粗估一段文本占多少 token:CJK 每字约 1,其余每 4 字符约 1。
1528
+ * 粗估一段**文本**占多少 token:CJK 每字约 1,其余每 4 字符约 1。
1527
1529
  *
1528
1530
  * 只要保守就够用 —— 它的用途是「在我们这边就把装不下的情况判掉」,
1529
1531
  * 而不是精确计费(上游不会告诉我们超没超,只会回一句参数非法)。
1532
+ *
1533
+ * **不要拿它去量带图的 content。** 图片在请求里是 base64 字面量,按字符折算会
1534
+ * 虚报两个数量级;整条 prompt 的估算走 `estimatePromptTokens`。
1530
1535
  */
1531
1536
  function estimateTokens(text) {
1532
1537
  let cjk = 0;
@@ -1536,6 +1541,126 @@ function estimateTokens(text) {
1536
1541
  }
1537
1542
  return Math.ceil(cjk + (text.length - cjk) / 4);
1538
1543
  }
1544
+ /** 单张图 token 的下限/上限:防止极端尺寸把整个估算拉飞。 */
1545
+ const IMAGE_TOKEN_MIN = 85;
1546
+ const IMAGE_TOKEN_MAX = 8e3;
1547
+ /**
1548
+ * 视觉编码器把图切成 28×28 的块,每块约 1 token —— 所以图片的代价随**像素面积**
1549
+ * 走,和它在请求里编码成多少字符无关。
1550
+ */
1551
+ const IMAGE_PATCH_AREA = 784;
1552
+ /** 读不出图片尺寸时的保守兜底(≈ 一张 1024×1024)。 */
1553
+ const IMAGE_TOKEN_FALLBACK = 1600;
1554
+ /** 解析图片头最多解码这么多 base64 字符(≈72 KB):够覆盖 PNG IHDR 与 JPEG 的 SOF。 */
1555
+ const IMAGE_HEAD_BASE64_CHARS = 98304;
1556
+ function clamp(value, min, max) {
1557
+ return Math.min(max, Math.max(min, value));
1558
+ }
1559
+ function be32(bytes, offset) {
1560
+ return (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
1561
+ }
1562
+ /** 从图片头读宽高(不解码像素)。认不出格式返回 undefined。 */
1563
+ function imageDimensions(bytes) {
1564
+ if (bytes.length >= 24 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) return {
1565
+ width: be32(bytes, 16),
1566
+ height: be32(bytes, 20)
1567
+ };
1568
+ if (bytes.length >= 10 && bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70) return {
1569
+ width: bytes[6] | bytes[7] << 8,
1570
+ height: bytes[8] | bytes[9] << 8
1571
+ };
1572
+ if (bytes.length >= 4 && bytes[0] === 255 && bytes[1] === 216) {
1573
+ let i = 2;
1574
+ while (i + 9 < bytes.length) {
1575
+ if (bytes[i] !== 255) {
1576
+ i += 1;
1577
+ continue;
1578
+ }
1579
+ const marker = bytes[i + 1];
1580
+ if (marker === 216 || marker === 1 || marker >= 208 && marker <= 215) {
1581
+ i += 2;
1582
+ continue;
1583
+ }
1584
+ const length = bytes[i + 2] << 8 | bytes[i + 3];
1585
+ if (length <= 0) break;
1586
+ if (marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204) return {
1587
+ height: bytes[i + 5] << 8 | bytes[i + 6],
1588
+ width: bytes[i + 7] << 8 | bytes[i + 8]
1589
+ };
1590
+ i += 2 + length;
1591
+ }
1592
+ }
1593
+ }
1594
+ /**
1595
+ * 一张 `data:image/...;base64,...` 占多少 token。
1596
+ *
1597
+ * **不能拿 estimateTokens 去量 base64。** 一张 400 KB 的 A4 页渲染图 base64 后约
1598
+ * 55 万字符,按「4 字符 1 token」会算成 13.7 万 token —— 比真实视觉编码器的读数
1599
+ * 大两个数量级(同一张图通常 1~3 千)。后果是宿主那边上下文还很空、插件这边已经
1600
+ * 报「上下文放不下」,用户只看到一句让他新建会话的错,实际上一次都没发出去。
1601
+ *
1602
+ * 所以图片单独走面积估算:读图片头拿宽高,按 28×28 的块数折算。
1603
+ */
1604
+ function estimateImageTokens(url) {
1605
+ const comma = url.indexOf(",");
1606
+ if (comma === -1 || !/^data:image\//i.test(url.slice(0, comma))) return IMAGE_TOKEN_FALLBACK;
1607
+ const base64 = url.slice(comma + 1, comma + 1 + IMAGE_HEAD_BASE64_CHARS);
1608
+ let bytes;
1609
+ try {
1610
+ bytes = new Uint8Array(Buffer.from(base64, "base64"));
1611
+ } catch {
1612
+ return IMAGE_TOKEN_FALLBACK;
1613
+ }
1614
+ const size = imageDimensions(bytes);
1615
+ if (!size || size.width <= 0 || size.height <= 0) return IMAGE_TOKEN_FALLBACK;
1616
+ return clamp(Math.ceil(size.width * size.height / IMAGE_PATCH_AREA), IMAGE_TOKEN_MIN, IMAGE_TOKEN_MAX);
1617
+ }
1618
+ /** 一条消息 content 的 token 数:文本走 estimateTokens,图片走面积估算。 */
1619
+ function estimateContentTokens(content) {
1620
+ if (typeof content === "string") return estimateTokens(content);
1621
+ if (content === void 0 || content === null) return 0;
1622
+ if (!Array.isArray(content)) return estimateTokens(JSON.stringify(content));
1623
+ let total = 0;
1624
+ for (const part of content) {
1625
+ if (!part || typeof part !== "object") {
1626
+ total += estimateTokens(JSON.stringify(part ?? ""));
1627
+ continue;
1628
+ }
1629
+ const block = part;
1630
+ if (block.type === "image_url") {
1631
+ const image = block.image_url;
1632
+ const url = typeof image === "string" ? image : typeof image?.url === "string" ? image.url : "";
1633
+ total += estimateImageTokens(url);
1634
+ continue;
1635
+ }
1636
+ if (block.type === "text" && typeof block.text === "string") {
1637
+ total += estimateTokens(block.text);
1638
+ continue;
1639
+ }
1640
+ total += estimateTokens(JSON.stringify(block));
1641
+ }
1642
+ return total;
1643
+ }
1644
+ /**
1645
+ * 整个 prompt 的 token 数(messages + tools)。
1646
+ *
1647
+ * 逐条走 `estimateContentTokens`,而不是 `estimateTokens(JSON.stringify(messages))`:
1648
+ * 后者会把图片的 base64 当成正文去量,一条带图的请求就能虚报出几十万 token。
1649
+ * 非 content 的结构化字段(role / tool_calls / tool_call_id / name)照旧按 JSON 量。
1650
+ */
1651
+ function estimatePromptTokens(messages, tools) {
1652
+ let total = 0;
1653
+ if (Array.isArray(messages)) for (const message of messages) {
1654
+ if (!message || typeof message !== "object") continue;
1655
+ const record = message;
1656
+ total += estimateContentTokens(record.content);
1657
+ const { content: _content, ...rest } = record;
1658
+ if (Object.keys(rest).length > 0) total += estimateTokens(JSON.stringify(rest));
1659
+ }
1660
+ else if (messages !== void 0) total += estimateTokens(JSON.stringify(messages));
1661
+ if (tools !== void 0) total += estimateTokens(JSON.stringify(tools));
1662
+ return total;
1663
+ }
1539
1664
  /** 上游要求 chat_id 为 32 位小写十六进制。 */
1540
1665
  const CHAT_ID_RE = /^[0-9a-f]{32}$/;
1541
1666
  /** 稳定地把消息内容序列化成锚点文本(字符串原样,多模态数组走 JSON)。 */
@@ -1638,7 +1763,7 @@ function prepareChatBody(rawJson, contextWindow = 0) {
1638
1763
  if (typeof body.max_tokens === "number") {
1639
1764
  let maxTokens = Math.min(body.max_tokens, ceiling);
1640
1765
  if (contextWindow > 0) {
1641
- const promptTokens = estimateTokens(`${JSON.stringify(body.messages ?? "")}${JSON.stringify(body.tools ?? "")}`);
1766
+ const promptTokens = estimatePromptTokens(body.messages, body.tools);
1642
1767
  const room = contextWindow - promptTokens - PROMPT_ESTIMATE_MARGIN;
1643
1768
  if (room < MIN_USEFUL_OUTPUT_TOKENS) {
1644
1769
  body.max_tokens = maxTokens;
@@ -3213,6 +3338,6 @@ function percentileOf(buckets, ratio) {
3213
3338
  }
3214
3339
  //#endregion
3215
3340
  //#region src/version.ts
3216
- const CODEARTS_VERSION = "1.2.12";
3341
+ const CODEARTS_VERSION = "1.2.13";
3217
3342
  //#endregion
3218
3343
  export { signedGet as A, markModelUnavailable as B, isTpmLimit as C, pickDailyWelfareCampaign as D, modelUnavailableReasonText as E, creditRatioLabel as F, codeartsAccountsPath as G, CodeArtsAccountStore as H, filterEnabledModels as I, startLogin as J, codeartsAuthPath as K, forgetModelUnavailable as L, CodeArtsCatalog as M, FALLBACK_CODEARTS_MODELS as N, prepareChatBody as O, clearBenefitBlocked as P, isBenefitBlocked as R, isQueueableRate as S, maxTokensCeilingFor as T, CodeArtsCredentialStore as U, modelUnavailableReason as V, MANUAL_ACCOUNT_ID as W, isConcurrencyCap as _, refreshCatalog as a, isNotMultimodal as b, chatStream as c, degradeTokenCeiling as d, fetchCallerIdentity as f, firstFrameError as g, fetchWelfareCampaigns as h, discoverModels as i, upstreamErrorMessage as j, rateLimitFrame as k, claimDailyWelfare as l, fetchQueueStatus as m, CodeArtsUsageTracker as n, SNAP_HOST as o, fetchModels as p, credentialFromOAuth as q, codeartsUsagePath as r, canonicalModel as s, CODEARTS_VERSION as t, clearQueueStatus as u, isIamTokenError as v, isWelfareClaimedStatus as w, isParamInvalidFrame as x, isModelNotAccessible as y, isBenefitModel as z };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dsh-codearts",
3
3
  "displayName": "DSH CodeArts Connect",
4
4
  "description": "把华为云 CodeArts 接入 DeepSeek Harness —— 内置 OAuth2 登录(PKCE + DPoP),登录后即可在 DSH 对话窗口使用 CodeArts 的模型。",
5
- "version": "1.2.12",
5
+ "version": "1.2.13",
6
6
  "packageManager": "pnpm@11.24.0",
7
7
  "author": "elegant01",
8
8
  "keywords": [