dsh-loadout 0.12.6 → 0.13.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/CHANGELOG.md +32 -0
- package/README.en.md +39 -3
- package/README.md +44 -4
- package/client.js +434 -32
- package/index.js +216 -4
- package/package.json +3 -2
- package/scripts/client-smoke.mjs +303 -10
- package/scripts/selftest.mjs +150 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
「装备栏」是一个 DeepSeek Harness 插件:给每个对话选一套工具(套装),只把用得上的工具投给模型。
|
|
4
4
|
|
|
5
|
+
## 0.13.1
|
|
6
|
+
|
|
7
|
+
- 只改文档:README(中英)删掉从讨论过程里带进来的内容——为什么某句话放在底部而不是悬停里、某个 `span` 的透明度如何叠加、上一版修错了什么、0.4.0 那次崩溃的来龙去脉。留下的仍然是有用的那部分:缓存按前缀命中所以切换的代价跟着上下文长度走、行上为什么报 token 而不是钱、价格是估算、`auto` 标记与草稿的语义、链接安装与拷贝安装的区别。行为与 0.13.0 完全相同。
|
|
8
|
+
|
|
9
|
+
## 0.13.0
|
|
10
|
+
|
|
11
|
+
- **默认套装是「借来的」,不是「选过的」**:新建对话时宿主会把当时的默认套装写进这个对话的绑定,于是它看起来像用户自己选的——之后在设置页把默认改掉,欢迎区仍然显示旧套装(而列表里 `全部(默认)` 已经打上标记、却没有勾),两张嘴说两套话。现在这类绑定带 `auto` 标记(落盘),读取时不算「已选」,胶囊显示当前默认;欢迎区发现「借来的套装 ≠ 现在的默认」时发一次 `bind { follow: true }` 让宿主补上(不写草稿、仍是借来的),所以下一次改默认它还会跟着走。第一轮对话结束后标记消失,绑定才真正属于这个对话。设置页改默认本身仍然不碰任何对话——这条承诺没有变。
|
|
12
|
+
- **空白对话一律以胶囊为准**:补请求挂在「这个屏幕还没发过消息」上,而不是「这个对话没有绑定」——旧版本写进去的绑定是真的,按后者判断永远不会触发。因此本次升级前创建的对话,只要还没发出第一条消息,下次打开欢迎区就会被纠正到当前默认;已发过消息的对话仍然各用各的。
|
|
13
|
+
- 顺带修掉:`GET /dsh-loadout/state` 的兜底分支自己算了一遍 `bound`,绕过了上面的判断(欢迎区没有 agent 时走的正是这条)。
|
|
14
|
+
- **每行改成报「这套装进多少工具」**:行右边的 `≈¥0.2x` 换成 `≈3.1k tokens`。钱只跟对话长度有关,换哪一套都是同一个数,摆在每一行上看不出差别;真正有差别的是「这一套往提示词里放多少工具定义」。`全部` / `仅内置` 两行同样带数(前者是全部工具,后者只有内置)。钱只保留在底部那一行。
|
|
15
|
+
- **底部账单加粗**:`本对话上下文(约 150k tokens),下一条未命中价≈¥0.23,之后恢复至缓存价。` 现在是 600 字重、正文色——11px 灰色时它读起来像上面提醒的脚注。
|
|
16
|
+
- **默认标记移到名字后面**:标题栏菜单里 `全部(默认)`、`idea(默认)`,不再单独一列「默认」。
|
|
17
|
+
- **设置页两张底座卡片补 token 数**:`全部` 与 `仅内置` 现在和套装卡片一样写 `≈2.4k tokens` / `≈1.6k tokens`(宿主新增 `baseTokens` 字段,按各自工具表估算)。
|
|
18
|
+
- **设置页标题与说明并成一行**:`新对话默认套装只影响新建对话` 是一个文本节点、同一字号同一颜色、中间没有间隙(原来拆成两个 `span`,第二段自带 0.6 透明度,叠加标题的 0.6 后比标题更淡,看起来像换了字体;flex 还留了 8px 间隔)。下一行再补「当前对话在「装备栏」切换;新建时也可选套装。」
|
|
19
|
+
- **新会话选择器也给默认套装打标**:列表里的 `全部` / `仅内置` / 每套套装都按标题栏的规则在名字后标 `(默认)`;胶囊本身保持 `选择对话套装:X`,不标默认。折叠的分组仍会显示那一组里的默认套装(否则空白屏幕上会答成「什么都没选」)。
|
|
20
|
+
- 清理:`switchPrice()`(带 20k 门槛的行标签报价)随行报价一起删除,只留 `switchCost()` 供底部账单使用。
|
|
21
|
+
- **加挂写清「已在对话中 / 插件总数」**:分组标题从 `加挂(1)` 改成 `加挂(1/5)`;「全部」底座下六个插件都在对话里,于是读作 `6/6`,而不是 `0/6`。悬停提示只保留加挂的语义(「在当前选择上临时加开插件,不新建套装。已经包含的插件不能再加。」)。
|
|
22
|
+
- **保存与启用分成两个按钮**:对话页「+ 新建套装」底部现在是 `保存`(只存起来,当前对话继续用原来的工具)与 `保存并启用`(存下来并立刻切过去)。`保存并启用` 的说明用原生 `title`——浮层气泡被菜单自己的滚动容器裁掉,等于没有提示。设置页的 `保存` 永远只是保存——那里不切换当前对话。
|
|
23
|
+
- **对话页底部加一条重要提醒**:建议新建对话时直接选好套装;中途切换会按未命中价重算一次、之后恢复;长对话影响大、短对话基本无影响,空闲 / 刚压缩 / 重启后切换无影响。
|
|
24
|
+
- **设置页删掉「切换一次大概多贵」**:设置页管全局,不该讨论某一条对话的价格,这节连同两个价格输入一起移除(报价按 ¥2 / ¥0.5 每百万 token 估算)。页面顶部改成「设置页不绑定具体会话,上面的数字来自最近活跃的那个对话」。
|
|
25
|
+
- 测试:`client-smoke` 断言「每行报工具 token」「默认标记跟在名字后」「底部账单加粗」「两张底座卡片有 token 数」「设置页标题与说明同行」「加挂计数为 已在对话中/总数」「全部底座下 加挂 满格(2/2)」「任何一行都不重复底部那句话」「保存与保存并启用是两个动作、且只保存那条不调用 `applyBase`」,并给 fixture 补 `baseTokens`。
|
|
26
|
+
|
|
5
27
|
## 0.12.6
|
|
6
28
|
|
|
7
29
|
- **发布流水线失败的那次补上**:0.12.5 的 `npm publish --provenance` 在 sigstore 里报了 `TLOG_CREATE_ENTRY_ERROR (409) an equivalent entry already exists in the transparency log`——包本身没进 registry(`latest` 仍是 0.12.4),是可信日志去重把这一版挡了下来。`publish.yml` 现在多两层兜底:先看这个版本是不是其实已经到 registry 了(到了就算成功),否则去掉 `--provenance` 再发一次,并留下 warning;正常路径仍然带 provenance。
|
|
@@ -37,6 +59,16 @@ ull,日志里留一行说明。回归断言: binding to a deleted kit falls
|
|
|
37
59
|
- **修卡死**:编辑(覆盖保存)、重命名或删除一个正在被对话使用的套装时,宿主会遍历「正在用它的对话」并逐个重新套用工具;这个遍历边改边往 `Map` 里重写条目,迭代器被塞回一个已经走过的键,于是永远走不完——表现是界面点下去没有任何反应、进程占满一个核。现在遍历快照(`[...state]`),编辑与删除都会立刻返回。
|
|
38
60
|
- 测试补齐验收表:`selftest` 新增「同名不同大小写/空格被拒绝」「预置名不能被用户套装占用」「连续改默认不影响已有对话」「删除套装报告并释放全部绑定」「删除默认套装同时清空默认」「改名不动绑定」「写盘不留临时文件」「预置也能当默认」八项断言;`client-smoke` 的预置夹具改为随包发布的五套(仅聊天 / 编程用 / 查找资料 / 项目梳理 / 写作)。
|
|
39
61
|
|
|
62
|
+
## 0.13.0(2026-11-03)
|
|
63
|
+
|
|
64
|
+
- **切换套装的代价写在切换的地方**:标题栏菜单里每套不活动的套装,右边多一个 `≈¥0.2x`,状态行也带上当前上下文大小(`· 上下文 ~150k`)。这个数不是估的:宿主读 `contextPressure` 会话投影的 `projectedTokens`(提供方报告的上一次请求规模 + 之后新增的表面增量),随 `/dsh-loadout/state` 一起下发;投影缺失时整块提示自动消失。上下文不到 20k 时不显示任何数字——短对话里这笔钱是噪声。价格是两个可改的数(未命中 / 命中,元每百万 token,默认 2 / 0.5),存在浏览器 `localStorage`,设置页新增「切换一次大概多贵」一节;价格只影响估算,不影响切换本身。
|
|
65
|
+
- **选默认不在这里**:对话页菜单只管这一条对话——可以切换、可以新建套装,但不提供「把新对话默认改成这套」。这件事是全局决定,留在 设置 → 装备栏(`kit_set_default` 与设置页每张卡的「设为默认」)。一个菜单同时改「这条对话用什么」和「以后所有对话用什么」,是两种作用域混在一起。
|
|
66
|
+
- **三个入口各管一段**:设置页管全局(默认套装、新建 / 编辑 / 删除套装);新对话的胶囊只管这条还没开始的对话(选哪套,不碰默认、不建也不改);对话页菜单只管当前对话(切换、新建)。越界的那几处是这一版顺手修掉的 bug。
|
|
67
|
+
- **新建对话时就能选套装**:空白对话的输入框工具行里、`标准模式`选择栏右侧(插槽 `conversation.input.right`,`order: -10`)多一个 `选择对话套装 <当前选择> ▾` 小胶囊。确认句不常驻:鼠标停上去显示「这个新对话会用「X」套装」,选过后显示「这个对话会用「X」套装,下一条消息生效」。点开是向上浮出的折叠列表——`全部` / `仅内置` / `预设套装` / `我的套装`,后两组默认折叠并带数量;浮层最高 320px 内部滚动,展开子组也不会把页面撑长,点外面自动收起。胶囊上的名字就是「这个对话实际会用哪套」:设过默认显示默认套装,否则显示「全部」。选中的那套动的是这条对话自己的绑定,不改「新对话默认套装」。这是唯一真正免费的切换:此时还没有 agent,没有任何请求前缀被建起来。发出第一条消息后整个胶囊不再出现,宿主没有该插槽时也不出现。`@dsh` 只是内部值,界面上一律显示「仅内置」。
|
|
68
|
+
- **未发送的选择是草稿,而且是落盘的草稿**:宿主新增 `bind` / `release` 两个动作。欢迎界面上选的那套先记进绑定(agent 一出现就应用),同时写进 `loadout.json` 的 `drafts: { <sessionId>: 套装名 }`;`/dsh-loadout/state` 返回 `live` / `draft` / `bound` 三个字段,选择器每次「首次看到」这个会话时,若读到上一轮留下的草稿,会先 `release` 掉再显示——所以没发消息就离开,下次进来和 DSH 自己把模式重置回「标准模式」一样,回到默认套装。跑完一整轮(`turn/end`)或会话被销毁(`session/disposed`)时草稿标记消失,此后它就是这条对话的固定套装。草稿标记原先只在宿主内存里:重启后标记没了、绑定却被当成用户决定读回来,于是新对话显示了上一次选的那套——现在标记落盘,重启不会把草稿洗成决定。
|
|
69
|
+
- **选择器跟着设置走**:胶囊只在挂载时读一次状态,所以在设置页改完默认、回到欢迎区,它仍显示挂载那一刻的默认套装。现在它同时监听 `dsh-loadout:changed` 与窗口 `focus`,与标题栏菜单同一套刷新来源。
|
|
70
|
+
- 测试:`client-smoke` 覆盖欢迎区选择器的 chip 与折叠列表、默认高亮、全部/未选的区分、点选只发 `{action:'bind'}`、`inject` 交来 `sessionId`、发过消息后不渲染,以及三条作用域断言——对话页菜单里不再有 `下次对话` / `设为默认`,选择器不出现「新建套装 / 编辑 / 删除 / 设为默认」,设置页仍能选默认;另有状态行报上下文大小、不活动套装报价、活动套装不报价、5k 上下文不显示。`selftest` 的假宿主补上 `sessionProjections` 与 `bind` / `release` 流程,断言覆盖「没有采样 → `tokens: null`」「有采样 → 取 `contextPressure`」「没有 token meter 仍应答」「不存在的套装 404」「无 agent 先记绑定、agent 出现即应用」「`bind ''` 表示全部」「草稿标记落盘」「release 之后 store 里不留痕」「有 agent 的欢迎页仍报 `draft`」「`turn/end` 把草稿转成正式绑定」「`session/disposed` 带走草稿」。
|
|
71
|
+
|
|
40
72
|
## 未发布
|
|
41
73
|
|
|
42
74
|
- 修 `kit_list`:返回值里带 `note`,但输出 schema 没有声明它,宿主按 schema 校验,于是这个工具**每次调用都直接失败**(`kit_list returned invalid output: "note" is not a declared property`)。现在 `note` 是合法字段,渲染时也会在套装名后显示备注;`selftest` 新增断言 `kit_list declares every field it returns`,防止返回值与 schema 再次漂移。
|
package/README.en.md
CHANGED
|
@@ -47,9 +47,9 @@ Without the dsh CLI you can use `scripts/install.ps1`: it creates the junction l
|
|
|
47
47
|
|
|
48
48
|
Restart the app afterwards: host plugins have no hot reload, and the UI needs at least a refresh.
|
|
49
49
|
|
|
50
|
-
###
|
|
50
|
+
### Link installs, not copies
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
A **link** install, not a copy. A copy lands in the profile and keeps running the old bundle after the source changes — that is how 0.4.0 broke startup. A link cannot drift, and `preflight` reports whether the install has.
|
|
53
53
|
|
|
54
54
|
### Self-checks
|
|
55
55
|
|
|
@@ -65,7 +65,7 @@ node scripts/client-smoke.mjs # browser bundle: menu and settings panel render
|
|
|
65
65
|
- **Settings → Loadout**: manage kits, edit notes, choose the new-conversation default.
|
|
66
66
|
- `/kit <name>`: switch from the message box.
|
|
67
67
|
|
|
68
|
-
Settings has no conversation of its own, so it only decides *where new conversations start* —
|
|
68
|
+
Settings has no conversation of its own, so it only decides *where new conversations start* — the page says so at the top ("设置页不绑定具体会话,上面的数字来自最近活跃的那个对话。"): the token ledger describes the most recently active conversation, and the default kit only affects conversations created after the change. Use the header menu to switch a single conversation, and the new-conversation pill to pick a kit for one that has not started yet. In the default list, `All` / `Built-in only` and kits are the same kind of card: each can copy its switch command or be set as default. **My kits** starts collapsed and shows only the current default, with the same + New kit action right under it; open it to see the rest. A saved kit can be **edited** on its card: the form opens under that card, and you either overwrite it (conversations already using it switch immediately) or save as a new kit.
|
|
69
69
|
|
|
70
70
|
### Shipped presets (five, read-only)
|
|
71
71
|
Five read-only presets. Editing one forks it into one of your kits.
|
|
@@ -107,6 +107,42 @@ This conversation keeps 18 tools · about 1.1k tokens · All is about 3.0k · th
|
|
|
107
107
|
|
|
108
108
|
Each kit card also carries its own estimate (`≈1.1k tokens`). The number is an **estimate**: each tool definition (name, description, parameter schema) is serialised and divided by 3.5 characters per token, covering only the tool list — not conversation history, the system prompt, or prompt-cache behaviour. The UI labels it "estimate" for that reason. The kept side is measured from the schemas the runtime actually sends; the "All" side comes from the tool layer's definition table.
|
|
109
109
|
|
|
110
|
+
## What a switch costs
|
|
111
|
+
|
|
112
|
+
Switching is not free. The request prefix is ordered system prompt → tool definitions → history → this turn's input, and the prompt cache matches on that prefix: change the tool definitions and everything after them is billed again at the miss price. So the **cost scales with context length, the benefit with the number of turns**:
|
|
113
|
+
|
|
114
|
+
- Pick at the start: it costs almost nothing and saves on every turn after.
|
|
115
|
+
- Switch mid-conversation at 150k tokens: roughly one full-context miss (¥0.2 on this machine), paid back slowly by the ~1.9k saved per turn.
|
|
116
|
+
- After a long idle gap, a restart, or a compaction: the cache is cold anyway, so a switch there is nearly free.
|
|
117
|
+
|
|
118
|
+
Each row states **how many tokens of tool definitions it would put in the prompt** (`≈3.1k tokens`; `全部` is `≈5.6k tokens`, `仅内置` `≈4.1k tokens`), and a kit that new conversations start from is marked after its name (`全部(默认)`, `idea(默认)`); the status line carries `· context ~150k`. The rows do not quote money: any switch invalidates the same stretch of history, so the number is identical on every row and only hides what actually differs — how much tool table each choice installs. Money appears once, bold, under the reminder in the footer:
|
|
119
|
+
|
|
120
|
+
> 本对话上下文(约 150k tokens),下一条未命中价≈¥0.23,之后恢复至缓存价。
|
|
121
|
+
|
|
122
|
+
The number comes from the host token meter's `contextPressure` projection (the provider-reported size of the last request plus whatever the surface has grown by since), not from guessing at the session file. The ¥2 / ¥0.5 per million tokens (miss / hit) are fixed estimates: they only feed the hint, and no setting changes what a switch does. The settings page's `全部` and `仅内置` cards state their token counts too, like every kit card.
|
|
123
|
+
|
|
124
|
+
The `加挂` group counts `in this conversation / plugins there are at all` (e.g. `加挂(1/5)`), so under the `全部` base it reads `6/6`: all six plugins are already in, and there is nothing left to attach. Its tooltip only explains the verb ("在当前选择上临时加开插件,不新建套装。已经包含的插件不能再加。"); the bill is stated once, at the bottom.
|
|
125
|
+
|
|
126
|
+
The last line of the conversation menu's footer is the one that matters most: **pick the right kit when you start a conversation**. Switching mid-conversation changes the tool list and the next message is billed at the miss price once, then back to the cached price. Costly on long conversations, negligible on short ones — and essentially free after an idle gap, a compaction, or a restart.
|
|
127
|
+
|
|
128
|
+
Configuring is not the same as using: in the conversation menu, "+ 新建套装" offers **保存** (store it, keep the current tools) and **保存并启用** (store it and switch to it — the hover text says the next message is billed once at the miss price). "保存" in Settings only ever saves.
|
|
129
|
+
|
|
130
|
+
Choosing the default kit is not a conversation-level action. It lives in Settings → 装备栏 (the "设为默认" button on each card), and it only changes what *new* conversations start from — this conversation keeps its kit and its cache.
|
|
131
|
+
|
|
132
|
+
Three surfaces, three scopes: **Settings** owns the global half (the default kit, creating / editing / deleting kits); **the new-conversation pill** owns only the conversation that has not started yet (which kit, no default, no create/edit); **the conversation menu** owns only the current conversation (switch, create a kit).
|
|
133
|
+
|
|
134
|
+
## Picking a kit for a new conversation
|
|
135
|
+
|
|
136
|
+
A blank conversation's composer tool row, immediately to the right of the 标准模式 selector, carries a small `选择对话套装 <current pick> ▾` pill. Hovering says "这个新对话会用「X」套装"; after a pick it reads "这个对话会用「X」套装,下一条消息生效". Opening it shows a folded list that floats upward — `全部`, `仅内置`, `预设套装`, `我的套装` — where the two kit groups start collapsed and list their entries only when opened. The name on the pill is the answer to "which kit will this conversation actually use": the default kit when one is set, otherwise `全部`. The pick takes effect from the first message, and the whole pill disappears once the conversation has one.
|
|
137
|
+
|
|
138
|
+
This is the one switch that is genuinely free: there is no agent yet, so no request prefix exists and the tool definitions cannot invalidate anything. Picking here is cheaper than switching after the first message.
|
|
139
|
+
|
|
140
|
+
The pick binds this conversation only; it does not change the default for new conversations — that still lives in Settings. On a host without this slot (an older DSH), the row simply does not appear and nothing else changes.
|
|
141
|
+
|
|
142
|
+
A pick made before the first message is a **draft**: leave the screen without sending anything (switch to another conversation, reload the page) and it is discarded, so the next new conversation starts at the default again — the same reset the host applies to its own mode. The marker is stored in `loadout.json` under `drafts`, so restarting DSH cannot turn "the kit I clicked once on the welcome screen" into a decision for that conversation. Once a message has actually run, the kit becomes this conversation's fixed binding.
|
|
143
|
+
|
|
144
|
+
The pill follows Settings: change the default kit and the welcome screen shows the new one without reopening the conversation. What it shows is the default, not "what was chosen here": a binding written from a default at creation time is marked `auto` in `loadout.json` and never counts as this conversation's pick, so moving the default from `idea` to `全部` answers `全部` on a new screen. While the borrowed kit still differs from the default, the welcome screen asks the host to catch up (`bind { follow: true }`) — still a loan, still free, and still no draft. The first finished turn clears the marker and the kit belongs to the conversation from then on. Changing the default never rewrites an existing conversation.
|
|
145
|
+
|
|
110
146
|
## Files
|
|
111
147
|
|
|
112
148
|
- Kit data: `~/.dsh/loadout.json` (schema-versioned; the older `~/.dsh/plugin-kits.json` is read once, then left behind).
|
package/README.md
CHANGED
|
@@ -48,9 +48,9 @@ plugin_manager action=install_bundle target=<本目录绝对路径>
|
|
|
48
48
|
|
|
49
49
|
装完重启应用:宿主插件没有热重载,界面至少刷新一次。
|
|
50
50
|
|
|
51
|
-
###
|
|
51
|
+
### 链接安装,不要拷贝
|
|
52
52
|
|
|
53
|
-
0.4.0
|
|
53
|
+
拷贝安装会把文件复制进 profile,之后源码再改,profile 里仍是旧副本,启动时跑的也是旧 bundle——0.4.0 的启动崩溃就是这样产生的。链接安装(junction)没有这个问题,`preflight` 会检查副本来是否漂移。
|
|
54
54
|
|
|
55
55
|
自检:
|
|
56
56
|
|
|
@@ -66,7 +66,9 @@ node scripts/client-smoke.mjs # 浏览器 bundle:菜单与设置页渲染
|
|
|
66
66
|
- 设置 → 装备栏:管理套装、改备注、选新对话默认套装。
|
|
67
67
|
- `/kit <名字>`:在对话里直接切换。
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
设置页只管「新对话从哪套开始」,不切换当前对话。当前对话在标题栏「装备栏」里切,还没开始的对话可以直接在欢迎区选。页面顶部有一行说明:「设置页不绑定具体会话,上面的数字来自最近活跃的那个对话。」
|
|
70
|
+
|
|
71
|
+
「新对话默认套装」列表里,「全部 / 仅内置」与套装是同一种卡片:都能「复制切换命令」或「设为默认」。「我的套装」默认折叠,只显示当前默认的那一个(这一行下面始终留着「+ 新建套装」),点开才列出全部。已保存的套装可以在卡片上「编辑」:改动在那张卡片下面展开,可选「覆盖保存」(正在用它的对话立刻按新工具集走)或「另存为新套装」。
|
|
70
72
|
|
|
71
73
|
### 预置套装(五套,只读)
|
|
72
74
|
|
|
@@ -97,7 +99,9 @@ node scripts/client-smoke.mjs # 浏览器 bundle:菜单与设置页渲染
|
|
|
97
99
|
`null` 就是「全部」。规则:
|
|
98
100
|
|
|
99
101
|
- 对话第一次出现时写入一次:有新默认就记默认,从别的对话分叉出来就继承父对话,升级前就存在的旧对话记 `null`(保持当时的实际状态)。
|
|
100
|
-
-
|
|
102
|
+
- 由默认写下的绑定同时记进 `auto`,读取时不算「这个对话选过它」,胶囊显示当前默认;第一轮对话结束后标记消失,绑定才真正属于这个对话。
|
|
103
|
+
- 只要对话还没发出第一条消息,欢迎区以胶囊为准:胶囊显示什么,下一条消息就用什么;不一致时由宿主把工具集对齐(不写草稿,仍算「借来的」)。
|
|
104
|
+
- 只有显式切换(标题栏、`/kit`、`kit_apply`、`kit_assign`)才改绑定,显式选择会清掉 `auto` 标记。
|
|
101
105
|
- 改「新对话默认套装」只影响之后新建的对话,已有对话各自保留。
|
|
102
106
|
- 子代理不记录绑定:它的父对话已经决定了它能看见什么。
|
|
103
107
|
|
|
@@ -125,6 +129,42 @@ node scripts/client-smoke.mjs # 浏览器 bundle:菜单与设置页渲染
|
|
|
125
129
|
|
|
126
130
|
每个套装卡片也标着自己的估价(`≈1.1k tokens`)。算法是**估算**:把每个工具的定义(名字、说明、参数 schema)序列化后除以 3.5 字符/token,只算工具清单这一段——不含对话历史、系统提示或模型缓存的影响。界面上都写了「估算」,不要拿它当账单。「当前对话保留」这一侧直接量的是运行时真正投给模型的 schema,「全部」那一侧来自工具层的定义表。
|
|
127
131
|
|
|
132
|
+
## 切换的代价
|
|
133
|
+
|
|
134
|
+
换套装不是免费的。请求前缀的固定顺序是「系统提示 → 工具定义 → 历史消息 → 本轮输入」,缓存按前缀命中;工具定义一变,它后面那一整段历史在下一个请求里就要按未命中价重算一遍。所以**代价按上下文长度算,收益按轮数算**:
|
|
135
|
+
|
|
136
|
+
- 开场就选好:几乎不花钱,而且之后每轮都省。
|
|
137
|
+
- 15 万 token 的对话中途切一次:约等于「整段上下文未命中一次」的钱(本机实测 ¥0.2 量级),之后要靠每轮省下的那 1.9k 慢慢还。
|
|
138
|
+
- 空闲很久、刚重启、刚压缩过:缓存本来已经冷了,这时候切基本免费。
|
|
139
|
+
|
|
140
|
+
菜单里每一行右边显示的是**这一行会往提示词里放多少工具定义**(`≈3.1k tokens`、`全部` 是 `≈5.6k tokens`、`仅内置` 是 `≈4.1k tokens`),套装的默认标记跟在名字后面(`全部(默认)`、`idea(默认)`);状态行带 `· 上下文 ~150k`。行上不写钱:换任何一套,被作废的都是同一段历史,那个数字对每一行都一样,区别在「这套装进多少工具」。钱只在**菜单底部「重要提醒」下面那一行**出现,加粗:
|
|
141
|
+
|
|
142
|
+
> 本对话上下文(约 150k tokens),下一条未命中价≈¥0.23,之后恢复至缓存价。
|
|
143
|
+
|
|
144
|
+
这个数字来自宿主 token meter 的 `contextPressure` 投影(提供方报告的上一次请求规模,加上之后新增的表面增量)。价格按 ¥2 / ¥0.5 每百万 token(未命中 / 命中)估算——只用于提示,不影响切换本身。设置页里 `全部` 与 `仅内置` 两张卡片也写着各自的 token 数,和套装卡片一样。
|
|
145
|
+
|
|
146
|
+
`加挂` 分组的数量写成 `已在对话中 / 插件总数`(例如 `加挂(1/5)`)——所以在「全部」底座下它是 `6/6`:六个插件都已经在对话里,没有可再加的。分组标题的悬停提示只说加挂的语义(「在当前选择上临时加开插件,不新建套装。已经包含的插件不能再加。」),账在底部那一行。
|
|
147
|
+
|
|
148
|
+
对话页菜单底部那段说明的最后一条是**重要提醒**:建议新建对话时就直接选好套装;对话中途切换会改变插件清单,下一条消息按未命中价重算一次,之后恢复。长对话影响较大,短对话基本无影响;空闲很久、刚压缩过、刚重启之后再切,基本免费。
|
|
149
|
+
|
|
150
|
+
选默认套装不在对话页——它属于全局决定,在 设置 → 装备栏 里改(每张卡片的「设为默认」),改完之后新建的对话从这套开始,当前对话不受影响,也不会触发任何重算。
|
|
151
|
+
|
|
152
|
+
三个入口各管一段,互不越界:**设置页**管全局(默认套装、新建 / 编辑 / 删除套装);**新对话的胶囊**只管这一条还没开始的对话(选哪套,不碰默认,也不建不改);**对话页菜单**只管当前对话(切换、新建套装)。
|
|
153
|
+
|
|
154
|
+
在对话页「+ 新建套装」里配好之后有两个按钮:**保存**(只存起来,当前对话继续用它原来的工具)和**保存并启用**(存下来并立刻切过去——这会改变插件清单,悬停提示会说明下一条消息要按未命中价重算一次)。设置页里的「保存」永远只是保存,那里不切换当前对话。
|
|
155
|
+
|
|
156
|
+
## 新建对话时选套装
|
|
157
|
+
|
|
158
|
+
空白对话的输入框工具行里、`标准模式`选择栏右侧,多一个 `选择对话套装 <当前选择> ▾` 的小胶囊。鼠标停上去显示「这个新对话会用「X」套装」;选过之后显示「这个对话会用「X」套装,下一条消息生效」。点开是一个向上浮出的折叠列表:`全部`、`仅内置`、`预设套装`、`我的套装`——后两组默认收起,点开才列出条目;收起时仍会显示「当前默认的那一套」(名字后面标 `(默认)`,与标题栏一致)。列表里的 `全部` / `仅内置` / 每套套装都按标题栏的规则标 `(默认)`;胶囊本身不标,它说的是「这个对话实际用哪套」。设过默认就显示那套,没设过就显示「全部」。选中的那套从第一条消息起生效;发出第一条消息后整个胶囊不再出现。
|
|
159
|
+
|
|
160
|
+
这是唯一真正免费的切换——此时还没有 agent,也就没有任何请求前缀被建起来,工具定义怎么写都不影响缓存。所以在这里挑,比发完第一条消息再切便宜。
|
|
161
|
+
|
|
162
|
+
选择只绑在当前这条对话上,不动「新对话默认套装」;想改默认仍然去设置页。如果宿主版本没有这个插槽(比如更早的 DSH),这一行不会出现,其余功能不受影响。
|
|
163
|
+
|
|
164
|
+
还没有发出第一条消息就离开这个新对话(点了别的对话、或刷新页面),这个选择会被当作**草稿**丢掉:下次再进新对话回到默认套装,和 DSH 自己把模式重置回「标准模式」是同一件事。草稿标记存在 `loadout.json` 的 `drafts` 里,所以重启 DSH 不会把「上次随手选的」误当成这条对话的决定。真正发过一条消息之后,它才成为这个对话的固定套装。
|
|
165
|
+
|
|
166
|
+
在设置里改了默认套装,回到欢迎区显示的就是新的默认,不需要重新打开对话。
|
|
167
|
+
|
|
128
168
|
## 文件
|
|
129
169
|
|
|
130
170
|
- 套装与绑定:`~/.dsh/loadout.json`(`schema: 2`;`kits` 是你的套装,`assignments` 是每个对话的绑定,`defaultKit` 是新对话默认值)。
|