dsh-deepseek-web-login 0.6.0 → 0.6.2
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 +98 -0
- package/lib/index.js +114 -11
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,104 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循大致语义化版本;日期为本地时间。
|
|
4
4
|
|
|
5
|
+
## 0.6.2 — 2026-09-27
|
|
6
|
+
|
|
7
|
+
> 长尾工具压成**一行**:`` `签名` — 首句 ``。目录再瘦一圈,能力依然一个不少。
|
|
8
|
+
|
|
9
|
+
### 改进
|
|
10
|
+
|
|
11
|
+
- **长尾工具改成一行格式**,并拆出独立的 `## Other tools` 小节:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
## Available tools
|
|
15
|
+
### pwsh
|
|
16
|
+
<完整描述>
|
|
17
|
+
pwsh(command: string, description: string)
|
|
18
|
+
command: …
|
|
19
|
+
description: …
|
|
20
|
+
|
|
21
|
+
## Other tools
|
|
22
|
+
|
|
23
|
+
Call these the same way. Parameter names and types are in the parentheses.
|
|
24
|
+
|
|
25
|
+
- `job_list(limit?: number)` — 列出后台任务
|
|
26
|
+
- `web_search(queries: string[])` — 联网搜索
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
这是抄 cuckoo 的(它的 `getFormattedJsApiForPrompt` 对每个工具就是 `` 1. `read(path)` — 读取文件 ``):
|
|
30
|
+
**名字 / 签名 / 一句话三样都在,但只占一行** —— 长尾工具的价值就是"让模型知道它存在、怎么传参"。
|
|
31
|
+
- 那句话取**首句**(到第一个句末点)而不是开头若干字,上限 160 字符:描述的第一句才是"这工具干什么"。
|
|
32
|
+
|
|
33
|
+
### 实测收益(13 个真实 DSH 工具定义)
|
|
34
|
+
|
|
35
|
+
| 版本 | 目录长度 | 累计省 |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| 0.5.3(JSON + 完整描述) | 18,217 | — |
|
|
38
|
+
| 0.6.0(签名 + 完整描述) | 14,815 | 19% |
|
|
39
|
+
| 0.6.1(分级:长尾 240 字) | 11,000+ | 42% |
|
|
40
|
+
| **0.6.2(长尾一行)** | **9,024** | **50%** |
|
|
41
|
+
|
|
42
|
+
按 61 个工具(50,942 字符)外推,约 **省 2.5 万字符 ≈ 6,000 token / 每轮上下文**,
|
|
43
|
+
**零额外请求**、**工具一个不少**。
|
|
44
|
+
|
|
45
|
+
### 说明
|
|
46
|
+
|
|
47
|
+
- ⚠️ **这是 head 的变化**:重启 DSH 后**第一个任务会全量重发一次**,之后照常。
|
|
48
|
+
- 🔴 **渲染顺序变了**:以前是"按 DSH 下发的原序",现在是**分组**(核心在前、长尾在后),
|
|
49
|
+
各组**内部**仍保持原序。所以目录里工具的排列与之前不同。
|
|
50
|
+
- 长尾工具丢的是「遇错怎么办」那类长指引;核心工具(真正常用的)一个字没动。
|
|
51
|
+
- 调整名单:改 `src/protocol.ts` 的 `CORE_TOOLS` 集合 —— 那是唯一的开关。
|
|
52
|
+
|
|
53
|
+
## 0.6.1 — 2026-09-27
|
|
54
|
+
|
|
55
|
+
> 工具目录按「用不用得上」分级:常用的给完整说明,长尾的只留一句话。**能力一个不少。**
|
|
56
|
+
|
|
57
|
+
### 改进
|
|
58
|
+
|
|
59
|
+
- **工具描述分两级下发**。0.6.0 把参数从 JSON 换成签名之后,目录里最大的一块变成了
|
|
60
|
+
**工具级描述**(13 个真实工具实测:描述 10,369 字符 vs 参数段 7,588)。现在:
|
|
61
|
+
- **核心工具** —— `pwsh` / `bash` / `run_code` / `read` / `write` / `edit` / `grep` / `glob` /
|
|
62
|
+
`ls` / `todo_write` / `skill` / `present` / `ask_user_question`:描述按 3200 字符完整保留,参数说明也在;
|
|
63
|
+
- **长尾工具** —— 描述压到 240 字符,且**不输出参数说明**。
|
|
64
|
+
- ⚠️ **两级都保留工具名与参数签名** ⇒ 模型照样能调用长尾工具,只是看不到长篇说明。
|
|
65
|
+
**这不是「禁用工具」**,不会出现「要用的工具看不见」。
|
|
66
|
+
|
|
67
|
+
### 为什么这么分(实测依据)
|
|
68
|
+
|
|
69
|
+
扫最近 8 个会话的 **826 次真实工具调用**:
|
|
70
|
+
|
|
71
|
+
| 工具 | 次数 | 占比 |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| pwsh | 230 | 27.8% |
|
|
74
|
+
| run_code | 206 | 24.9% |
|
|
75
|
+
| edit | 140 | 16.9% |
|
|
76
|
+
| read | 80 | 9.7% |
|
|
77
|
+
| write | 66 | 8.0% |
|
|
78
|
+
| bash | 46 | 5.6% |
|
|
79
|
+
| 其余(grep/glob/present/skill/todo_write…) | 58 | 7.1% |
|
|
80
|
+
|
|
81
|
+
**覆盖 90% 的调用只需要 6 个工具**,而 DSH 每轮下发 **61 个**。剩下的那些
|
|
82
|
+
(jobs / goal / ralph / workflow / web / subagent 系列…)在这 8 个会话里**一次都没被调用过**,
|
|
83
|
+
却每个都在每一轮的上下文里占几百字符。
|
|
84
|
+
|
|
85
|
+
### 实测收益(13 个真实 DSH 工具定义)
|
|
86
|
+
|
|
87
|
+
| 版本 | 目录长度 | 累计省 |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| 0.5.3(JSON + 完整描述) | 18,217 | — |
|
|
90
|
+
| 0.6.0(签名 + 完整描述) | 14,815 | 19% |
|
|
91
|
+
| **0.6.1(分级)** | **10,544** | **42%** |
|
|
92
|
+
|
|
93
|
+
按 61 个工具(50,942 字符)外推,约 **省 2.1 万字符 ≈ 5,000 token / 每轮上下文**,
|
|
94
|
+
而且**零额外请求**。
|
|
95
|
+
|
|
96
|
+
### 说明
|
|
97
|
+
|
|
98
|
+
- ⚠️ **这是 head 的变化**:重启 DSH 后**第一个任务会全量重发一次**,之后照常。
|
|
99
|
+
- 长尾工具丢的是「遇错怎么办」那类长指引;**真正常用的工具一个字没动**。
|
|
100
|
+
- 想调整名单:改 `src/protocol.ts` 里的 `CORE_TOOLS` 集合 —— 那是唯一的开关。
|
|
101
|
+
哪天真觉得某个工具"看不懂了",把它加进去重新构建即可。
|
|
102
|
+
|
|
5
103
|
## 0.6.0 — 2026-09-27
|
|
6
104
|
|
|
7
105
|
> 工具目录改用**紧凑类型签名**下发,不再给模型贴原始 JSON。
|
package/lib/index.js
CHANGED
|
@@ -3325,6 +3325,65 @@ function staleAuthMessage(auth) {
|
|
|
3325
3325
|
*/
|
|
3326
3326
|
const MAX_DESCRIPTION_CHARS = 3200;
|
|
3327
3327
|
/**
|
|
3328
|
+
* 「核心工具」白名单 —— 只有它们值得在**每轮上下文**里都带上完整描述。
|
|
3329
|
+
*
|
|
3330
|
+
* 依据(2026-09-27 实测):扫最近 8 个会话的 **826 次真实工具调用**,
|
|
3331
|
+
* pwsh 27.8% / run_code 24.9% / edit 16.9% / read 9.7% / write 8.0% / bash 5.6%
|
|
3332
|
+
* ⇒ **覆盖 90% 的调用只需要这几个**。
|
|
3333
|
+
* 其余 50 多个工具(jobs / goal / ralph / workflow / web / subagent / cordis_*…)
|
|
3334
|
+
* 在那 8 个会话里**一次都没被调用过**,却每个都在每轮上下文里占几百字符。
|
|
3335
|
+
*
|
|
3336
|
+
* ⚠️ 分级只压**说明文字**:工具名与参数签名字字不少 ⇒ 模型照样能调用它们,
|
|
3337
|
+
* 只是看不到长篇说明("遇错怎么办"那类指引只对常用工具才值得每轮都带着)。
|
|
3338
|
+
* 要调整就把名字增删进这个集合 —— 这是唯一的开关。
|
|
3339
|
+
*/
|
|
3340
|
+
const CORE_TOOLS = /* @__PURE__ */ new Set([
|
|
3341
|
+
"pwsh",
|
|
3342
|
+
"bash",
|
|
3343
|
+
"run_code",
|
|
3344
|
+
"read",
|
|
3345
|
+
"write",
|
|
3346
|
+
"edit",
|
|
3347
|
+
"grep",
|
|
3348
|
+
"glob",
|
|
3349
|
+
"ls",
|
|
3350
|
+
"todo_write",
|
|
3351
|
+
"skill",
|
|
3352
|
+
"present",
|
|
3353
|
+
"ask_user_question"
|
|
3354
|
+
]);
|
|
3355
|
+
/**
|
|
3356
|
+
* 长尾工具「一行说明」里那句话的上限。
|
|
3357
|
+
*
|
|
3358
|
+
* 长尾工具只占**一行**:`` `name(签名)` — 首句 ``(抄 cuckoo 的 `getFormattedJsApiForPrompt`,
|
|
3359
|
+
* 它对每个工具就是 `` 1. `read(path)` — 读取文件 ``)。
|
|
3360
|
+
* 取**首句**而不是开头 160 字 —— 描述的第一句才是"这工具干什么",后面的多是用法细节。
|
|
3361
|
+
*/
|
|
3362
|
+
const MAX_TAIL_DESCRIPTION_CHARS = 160;
|
|
3363
|
+
/** 工具是否属于核心组(决定描述给多长、要不要带参数说明)。 */
|
|
3364
|
+
function isCoreTool(name) {
|
|
3365
|
+
return CORE_TOOLS.has(String(name ?? ""));
|
|
3366
|
+
}
|
|
3367
|
+
/** 取描述的首句(到第一个句末点),再按上限截断。 */
|
|
3368
|
+
function tailSentence(text) {
|
|
3369
|
+
const flat = text.replace(/\s+/g, " ").trim();
|
|
3370
|
+
const stop = flat.search(/\.(\s|$)/);
|
|
3371
|
+
return truncate(stop >= 0 ? flat.slice(0, stop + 1) : flat, MAX_TAIL_DESCRIPTION_CHARS);
|
|
3372
|
+
}
|
|
3373
|
+
/**
|
|
3374
|
+
* 长尾工具的**一行**形式:`` `name(签名)` — 首句 ``。
|
|
3375
|
+
*
|
|
3376
|
+
* 名字、签名、一句话三样都在,但只占一行 —— 长尾工具的价值就是"让模型知道它存在、怎么传参"。
|
|
3377
|
+
* ⚠️ 签名认不出来时(`buildToolSignature` 返回 null)不冒险拼一行,只给名字 + 首句,
|
|
3378
|
+
* 让模型知道有这个工具、但不会照着残缺签名瞎传参(它会被兜底文案要求去问用户)。
|
|
3379
|
+
*/
|
|
3380
|
+
function formatTailTool(tool) {
|
|
3381
|
+
const sentence = tailSentence(String(tool.description ?? ""));
|
|
3382
|
+
const signature = buildToolSignature(tool, false);
|
|
3383
|
+
if (signature === null) return `\`${tool.name}\` — ${sentence}`;
|
|
3384
|
+
return `\`${signature.replace(/\s+/g, " ").trim()}\` — ${sentence}`;
|
|
3385
|
+
}
|
|
3386
|
+
/**
|
|
3328
3387
|
* 工具目录(一节)的总预算。
|
|
3329
3388
|
*
|
|
3330
3389
|
* 2026-09-12 从 24_000 提到 56_000。理由:实测 DSH 下发 61 个工具、不截描述时共需
|
|
@@ -3557,8 +3616,11 @@ function renderParamType(schema, depth) {
|
|
|
3557
3616
|
*
|
|
3558
3617
|
* ⚠️ 返回 `null` = "这份 parameters 不敢降级",调用方必须回退到原始 JSON:
|
|
3559
3618
|
* 宁可多花字符,也不能让模型看不见参数。
|
|
3619
|
+
*
|
|
3620
|
+
* @param withParamDocs 是否附上每个参数的说明。核心工具传 `true`,长尾工具传 `false`
|
|
3621
|
+
* —— 签名里已经有参数名、类型、必填性,那是模型写出正确 arguments 的**最小信息集**。
|
|
3560
3622
|
*/
|
|
3561
|
-
function buildToolSignature(tool) {
|
|
3623
|
+
function buildToolSignature(tool, withParamDocs = true) {
|
|
3562
3624
|
try {
|
|
3563
3625
|
const node = asRecord(tool.parameters);
|
|
3564
3626
|
if (!node) return `${tool.name}()`;
|
|
@@ -3567,7 +3629,7 @@ function buildToolSignature(tool) {
|
|
|
3567
3629
|
const args = renderParamMap(map, wrapped && Array.isArray(node.required) ? node.required.filter((key) => typeof key === "string") : [], 1);
|
|
3568
3630
|
if (args.length === 0) return Object.keys(node).length === 0 ? `${tool.name}()` : null;
|
|
3569
3631
|
const lines = [`${tool.name}(${args.join(", ")})`];
|
|
3570
|
-
for (const [name, def] of Object.entries(map)) {
|
|
3632
|
+
if (withParamDocs) for (const [name, def] of Object.entries(map)) {
|
|
3571
3633
|
const description = paramDescription(def);
|
|
3572
3634
|
if (description) lines.push(` ${name}: ${truncate(description, MAX_PARAM_DESC_CHARS)}`);
|
|
3573
3635
|
}
|
|
@@ -3579,16 +3641,35 @@ function buildToolSignature(tool) {
|
|
|
3579
3641
|
/**
|
|
3580
3642
|
* 渲染工具目录。
|
|
3581
3643
|
*
|
|
3582
|
-
*
|
|
3583
|
-
*
|
|
3644
|
+
* 结构(0.6.2):
|
|
3645
|
+
*
|
|
3646
|
+
* ## Available tools ← 核心工具:一段一个(`### 名字` / 完整描述 / 紧凑签名 / 参数说明)
|
|
3647
|
+
* ## Other tools ← 长尾工具:**一行一个** —— `` - `name(签名)` — 首句 ``
|
|
3648
|
+
*
|
|
3649
|
+
* 长尾用一行格式是抄 cuckoo 的(它的 `getFormattedJsApiForPrompt` 对每个工具就是
|
|
3650
|
+
* `` 1. `read(path)` — 读取文件 ``):同样三样信息(名字 / 签名 / 一句话),
|
|
3651
|
+
* 三行能装下的,一行就够 —— 而 61 个工具里有 48 个是长尾。
|
|
3652
|
+
*
|
|
3653
|
+
* ⚠️ **两级都保留工具名与参数签名** ⇒ 模型照样能调用长尾工具,只是看不到长篇说明。
|
|
3584
3654
|
*/
|
|
3585
3655
|
function buildToolSection(tools, maxChars = MAX_TOOLS_SECTION_CHARS) {
|
|
3586
3656
|
if (!tools || tools.length === 0) return "";
|
|
3587
3657
|
const parts = ["", "## Available tools"];
|
|
3588
3658
|
let budget = Math.max(0, Math.min(MAX_TOOLS_SECTION_CHARS, maxChars));
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3659
|
+
const coreTools = tools.filter((tool) => isCoreTool(tool?.name));
|
|
3660
|
+
const tailTools = tools.filter((tool) => !isCoreTool(tool?.name));
|
|
3661
|
+
/**
|
|
3662
|
+
* 预算用尽时的兜底:**必须把剩下的工具名说出来**,并明确要求别猜参数。
|
|
3663
|
+
* 旧写法只有一句 "(remaining tools omitted for length)",模型连"还有哪些工具存在"
|
|
3664
|
+
* 都不知道,只能盲猜名字和参数 —— 实测 61 个工具里 26 个就是这样静默消失的。
|
|
3665
|
+
*/
|
|
3666
|
+
const omittedNotice = (rest) => {
|
|
3667
|
+
const names = rest.map((item) => String(item?.name ?? "")).filter(Boolean);
|
|
3668
|
+
return `\n(⚠️ The following ${names.length} tools are NOT described above (omitted for length): ${names.join(", ")}. If you need one of them, ask the user for its exact parameters — do NOT guess them.)`;
|
|
3669
|
+
};
|
|
3670
|
+
for (let index = 0; index < coreTools.length; index += 1) {
|
|
3671
|
+
const tool = coreTools[index];
|
|
3672
|
+
const signature = buildToolSignature(tool, true);
|
|
3592
3673
|
let parametersText = signature ?? "";
|
|
3593
3674
|
if (signature === null) {
|
|
3594
3675
|
let schemaText = "";
|
|
@@ -3606,13 +3687,35 @@ function buildToolSection(tools, maxChars = MAX_TOOLS_SECTION_CHARS) {
|
|
|
3606
3687
|
parametersText
|
|
3607
3688
|
].join("\n");
|
|
3608
3689
|
if (budget - block.length < 0) {
|
|
3609
|
-
|
|
3610
|
-
parts.
|
|
3611
|
-
break;
|
|
3690
|
+
parts.push(omittedNotice([...coreTools.slice(index), ...tailTools]));
|
|
3691
|
+
return parts.join("\n");
|
|
3612
3692
|
}
|
|
3613
3693
|
budget -= block.length;
|
|
3614
3694
|
parts.push(block);
|
|
3615
3695
|
}
|
|
3696
|
+
if (tailTools.length > 0) {
|
|
3697
|
+
const header = [
|
|
3698
|
+
"",
|
|
3699
|
+
"## Other tools",
|
|
3700
|
+
"",
|
|
3701
|
+
"Call these the same way. Parameter names and types are in the parentheses."
|
|
3702
|
+
].join("\n");
|
|
3703
|
+
if (budget - header.length < 0) {
|
|
3704
|
+
parts.push(omittedNotice(tailTools));
|
|
3705
|
+
return parts.join("\n");
|
|
3706
|
+
}
|
|
3707
|
+
budget -= header.length;
|
|
3708
|
+
parts.push(header);
|
|
3709
|
+
for (let index = 0; index < tailTools.length; index += 1) {
|
|
3710
|
+
const line = `- ${formatTailTool(tailTools[index])}`;
|
|
3711
|
+
if (budget - line.length < 0) {
|
|
3712
|
+
parts.push(omittedNotice(tailTools.slice(index)));
|
|
3713
|
+
break;
|
|
3714
|
+
}
|
|
3715
|
+
budget -= line.length;
|
|
3716
|
+
parts.push(line);
|
|
3717
|
+
}
|
|
3718
|
+
}
|
|
3616
3719
|
return parts.join("\n");
|
|
3617
3720
|
}
|
|
3618
3721
|
function flattenText(blocks, out = []) {
|
|
@@ -8791,7 +8894,7 @@ async function checkForUpdate(current, fetchImpl) {
|
|
|
8791
8894
|
* 兜底常量与 package.json 的一致性由 `tests/check-smoke.mjs` 守着,不会漂。
|
|
8792
8895
|
*/
|
|
8793
8896
|
/** 与 package.json 保持一致的兜底版本(由测试保证不会漂)。 */
|
|
8794
|
-
const FALLBACK_VERSION = "0.6.
|
|
8897
|
+
const FALLBACK_VERSION = "0.6.2";
|
|
8795
8898
|
let cached;
|
|
8796
8899
|
/** 本插件版本(如 `0.1.26`)。 */
|
|
8797
8900
|
function pluginVersion() {
|