@crazyhappyone/dsh-tui 0.1.0-alpha.30 → 0.1.0-alpha.34

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/cordis.patch.yml CHANGED
@@ -82,6 +82,16 @@
82
82
  - id: tui-startup
83
83
  name: "@deepseek-ai/dsh-tui/startup"
84
84
 
85
+ # Zero-config official OpenAI/Anthropic routes. They register
86
+ # openai-official / anthropic-official so they do not collide with the
87
+ # dormant llm-pi-ai catalog keys openai / anthropic that the Web Models
88
+ # page already owns.
89
+ - id: llm-openai
90
+ name: "@deepseek-ai/dsh-llm-openai"
91
+
92
+ - id: llm-anthropic
93
+ name: "@deepseek-ai/dsh-llm-anthropic"
94
+
85
95
  # Reads its task from the ordinary tuiStartup provider.
86
96
  - id: tui-runtime
87
97
  name: "@deepseek-ai/dsh-tui"
package/dist/index.js CHANGED
@@ -9712,6 +9712,7 @@ var ONBOARDING_TITLE = "\u9996\u6B21\u8BBE\u7F6E";
9712
9712
  var FOOTNOTE2 = "\u2191\u2193/jk \u9009\u62E9 \xB7 Enter \u7F16\u8F91 \xB7 e \u5BFC\u51FA \xB7 r \u91CD\u8F7D \xB7 Esc \u5173\u95ED";
9713
9713
  var EDIT_FOOTNOTE = "Enter \u5E94\u7528 \xB7 Esc \u53D6\u6D88";
9714
9714
  var ONBOARDING_FOOTNOTE = "Enter \u4FDD\u5B58 \xB7 Esc \u8DF3\u8FC7";
9715
+ var DISCOVERY_BUSY = "\u6B63\u5728\u83B7\u53D6\u6A21\u578B\u5217\u8868\u2026";
9715
9716
  var SETTINGS_WINDOW = 8;
9716
9717
  var MARKER_COLS = 2;
9717
9718
  var VALUE_GAP = 2;
@@ -9754,15 +9755,15 @@ function fieldRow(label, value, selected, columns, required = false) {
9754
9755
  ...fittedValue === "" ? [] : [styled(fittedValue, selected ? "fg" : "fgDim")]
9755
9756
  ];
9756
9757
  }
9757
- function computeSettingsWindow(maxRows, totalRows, errorReason) {
9758
- if (maxRows === void 0) return SETTINGS_WINDOW;
9758
+ function computeSettingsWindow(maxRows, totalRows, errorReason, busy = false) {
9759
+ if (maxRows === void 0) return busy ? Math.max(1, SETTINGS_WINDOW - 1) : SETTINGS_WINDOW;
9759
9760
  let errorLines = 0;
9760
9761
  if (errorReason === EMPTY_TABLE_REASON2) {
9761
9762
  errorLines = 1;
9762
9763
  } else if (errorReason !== void 0) {
9763
9764
  errorLines = 2;
9764
9765
  }
9765
- const fixedOverhead = 2 + errorLines;
9766
+ const fixedOverhead = 2 + errorLines + (busy ? 1 : 0);
9766
9767
  const available = Math.max(1, maxRows - fixedOverhead);
9767
9768
  if (totalRows <= available) {
9768
9769
  return totalRows;
@@ -9775,6 +9776,7 @@ function SettingsPane({
9775
9776
  editing,
9776
9777
  onboarding,
9777
9778
  updateError,
9779
+ busy,
9778
9780
  locale,
9779
9781
  maxRows
9780
9782
  }) {
@@ -9787,7 +9789,7 @@ function SettingsPane({
9787
9789
  } else if (editing) {
9788
9790
  footnote = EDIT_FOOTNOTE;
9789
9791
  }
9790
- const windowLimit = computeSettingsWindow(maxRows, rows.length, errorReason);
9792
+ const windowLimit = computeSettingsWindow(maxRows, rows.length, errorReason, busy === true);
9791
9793
  const size = Math.min(windowLimit, rows.length);
9792
9794
  const start = rows.length <= size ? 0 : Math.min(
9793
9795
  Math.max(0, selectedIndex - Math.floor(size / 2)),
@@ -9822,6 +9824,7 @@ function SettingsPane({
9822
9824
  ),
9823
9825
  errorReason === EMPTY_TABLE_REASON2 ? null : renderLine(FAIL_NEXT2, "fgDim")
9824
9826
  ] }),
9827
+ busy === true ? renderLine(DISCOVERY_BUSY, "fgDim") : null,
9825
9828
  renderLine(footnote, "fgDim")
9826
9829
  ] });
9827
9830
  }
@@ -11832,10 +11835,10 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search, timeline = { o
11832
11835
  renaming: state.renaming
11833
11836
  };
11834
11837
  }
11835
- if (commandMode && (key === "j" || keyInfo.downArrow || key === "k" || keyInfo.upArrow)) {
11838
+ if (commandMode && (keyInfo.downArrow || keyInfo.upArrow)) {
11836
11839
  const query = state.commandQuery ?? state.text.slice(1);
11837
11840
  const count = filterCommands(commands, query).length;
11838
- const delta = key === "j" || keyInfo.downArrow ? 1 : -1;
11841
+ const delta = keyInfo.downArrow ? 1 : -1;
11839
11842
  return {
11840
11843
  kind: "dispatch",
11841
11844
  action: { kind: "none" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crazyhappyone/dsh-tui",
3
- "version": "0.1.0-alpha.30",
3
+ "version": "0.1.0-alpha.34",
4
4
  "description": "Source-runtime launcher for the DeepSeek Harness terminal interface",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/tui/README.md CHANGED
@@ -23,6 +23,7 @@ The deepseek-tui profile bundle and runtime plugin lets a user run the interacti
23
23
  -----
24
24
 
25
25
  <a id="use-this-package"></a>
26
+
26
27
  ## Use this package
27
28
 
28
29
  ### Configuration
@@ -43,7 +44,8 @@ Reasoning is hidden by default. Ctrl+O or `/reasoning` shows the complete dim re
43
44
 
44
45
  ### Contract
45
46
 
46
- - The runtime owns the live Agent handle, session projection and session-directory state; the render package receives only the controller interface. The top-bar title is a folded `session/title` except a `fallback` title that coexists with a human user message; before a provider or rename title the loop shows the compact mount name `DeepSeek · deepseek-tui`. Directory rows still use the first-human-message fallback. An empty idle window paints the generated official FishLogo, `DeepSeek`, and `有什么可以帮忙的` in the conversation column. The environment selects half-block, full-block, ASCII, or plain output independently of color; `brandAnimation` stores `auto | on | off`, and every input, history, overlay, resize, completion, or unmount stop clears the one-shot reveal timer. The runtime answers `approval/request` for that live agent and calls `next()` for every other agent: `y`/`a` resolve `'allowed-once'`, `n`/`d`/Esc resolve `'rejected'`, and abort (including Ctrl+C cancelling generation) resolves `'cancelled'` via the request signal. Policy `'never'` is decided by the host before this listener runs, so no ApprovalPane appears. Ctrl+E flips the current window's tool-card fold (`toolCardsExpanded`; no session event). Empty `/permission` opens the preset overlay; parameterized `/permission <name>` runs `ctx.commands.execute`. Empty `/settings` opens the settings overlay on every top-level `describe()` field (including `llm-deepseek · models` and `llm-pi-ai · providers` as JSON); Enter apply writes the selected field through `ctx.settings.update`. Browse `e` reports `prepareDocument()` and `r` rereads rows (`✓ 已重载设置`). Empty `/resume` opens the session list. `/reload` is a local command: it flushes the live session, unmounts, disposes that session, then spawns a replacement Node with the same launcher flags plus `--resume <id>`, dropping the original task positional so the first message is not sent again. Overlay `r` only rereads settings rows. Idle boot with no configured `DEEPSEEK_API_KEY` opens `首次设置`; Enter saves through `ctx.credentials.set` and then opens the model pane. Esc skips without opening it. The `tui` section owns `colorTier`, `submitOnEnter` (Enter inserts a newline when false), `notify` (`off | attention | every-turn`, default `attention`), `notifyQuietInputSeconds` (non-negative integer, default 10), `brandAnimation` (shown as `自动 / 开启 / 关闭`), `scrollbar` (boolean, default `true`), `reasoning` and `statusDetails` (booleans, default `false`), `locale` (`zh-CN | en-US`, default `zh-CN`), and the validated `renderPolicy` described above. A `user-questions/request` waterfall listener is registered in the current runtime-root Agent scope; it delegates foreign and child requests with `next()`, while accepted requests paint `AskUserPane`, bind abort/replacement/disposal to one cleanup, and notify exactly once at admission. ↑↓/jk move the highlight, and digit then Enter returns the original option label. The slash directory includes each command's `description`.
47
+ - The runtime owns the live Agent handle, session projection and session-directory state; the render package receives only the controller interface. The top-bar title is a folded `session/title` except a `fallback` title that coexists with a human user message; before a provider or rename title the loop shows the compact mount name `DeepSeek · deepseek-tui`. Directory rows still use the first-human-message fallback. An empty idle window paints the generated official FishLogo, `DeepSeek`, and `有什么可以帮忙的` in the conversation column. The environment selects half-block, full-block, ASCII, or plain output independently of color; `brandAnimation` stores `auto | on | off`, and every input, history, overlay, resize, completion, or unmount stop clears the one-shot reveal timer. The runtime answers `approval/request` for that live agent and calls `next()` for every other agent: `y`/`a` resolve `'allowed-once'`, `n`/`d`/Esc resolve `'rejected'`, and abort (including Ctrl+C cancelling generation) resolves `'cancelled'` via the request signal. Policy `'never'` is decided by the host before this listener runs, so no ApprovalPane appears. Ctrl+E flips the current window's tool-card fold (`toolCardsExpanded`; no session event). Empty `/permission` opens the preset overlay; parameterized `/permission <name>` runs `ctx.commands.execute`. Empty `/settings` opens the settings overlay on every top-level `describe()` field (`llm-deepseek · models`; `llm-pi-ai · providers` opens a structured form — a directory name, template index 1–4, single-line `名称 端点 [模型[,模型…]]`, or multi-line `name= baseURL= models= api=`; existing routes expand into child rows for `api` / `baseURL` / `apiKeyEnv` / `displayName` / `models`); Enter apply writes the selected field through `ctx.settings.update`. An empty `models=` line, the literal `auto` in either form, the two-token `名称 端点` form, and an existing route's `providers.<route>.models` row typed as `auto` all defer model assembly to `ctx.llm.discoverModels`; the overlay shows `正在获取模型列表…` while the request is in flight, and any refusal or empty reply is painted on the ✗ pair without writing settings — a 401/403 without a stored credential appends `请先使用 /key 配置 API key`. Browse `e` reports `prepareDocument()` and `r` rereads rows (`✓ 已重载设置`). Empty `/resume` opens the session list. `/reload` is a local command: it flushes the live session, unmounts, disposes that session, then spawns a replacement Node with the same launcher flags plus `--resume <id>`, dropping the original task positional so the first message is not sent again. Overlay `r` only rereads settings rows. Idle boot with no configured `DEEPSEEK_API_KEY` opens `首次设置`; Enter saves through `ctx.credentials.set` and then opens the model pane. Esc skips without opening it. The `tui` section owns `colorTier`, `submitOnEnter` (Enter inserts a newline when false), `notify` (`off | attention | every-turn`, default `attention`), `notifyQuietInputSeconds` (non-negative integer, default 10), `brandAnimation` (shown as `自动 / 开启 / 关闭`), `scrollbar` (boolean, default `true`), `reasoning` and `statusDetails` (booleans, default `false`), `locale` (`zh-CN | en-US`, default `zh-CN`), and the validated `renderPolicy` described above. A `user-questions/request` waterfall listener is registered in the current runtime-root Agent scope; it delegates foreign and child requests with `next()`, while accepted requests paint `AskUserPane`, bind abort/replacement/disposal to one cleanup, and notify exactly once at admission. ↑↓/jk move the highlight, and digit then Enter returns the original option label. The slash directory includes each command's `description`.
48
+ - A referenced `apiKeyEnv` name also gets its own settings row (`凭据 · NAME`) after the declared fields; Enter there stores the secret through `ctx.credentials.set` and keeps the pane open. Typing a literal key into an `apiKeyEnv` field is refused with the command to run instead (`请用 /key NAME <密钥> 配置该变量`), and `/key NAME` accepts a named credential from the command line.
47
49
  - `g s` toggles the persisted session directory when the composer buffer is exactly `g`; `/resume` opens the same list and does not close it. Rows with equal folded titles append a stable shortest-unique session-id hint inline; rows with unique titles remain unchanged. Left/right move the composer caret one grapheme. ↑/k shift the conversation toward older rows and ↓/j return toward live; arrows scroll even with composer text, while j/k insert when the buffer is not empty. A detached conversation always shows `↓ 底部 · End/G`, adding the unseen-row count when new output arrives. The mouse wheel uses the same direction as ↑/k on the conversation and as j/k on list panes, moves `scroll.wheelRows` physical rows per report, and combines reports from one stdin chunk into one net request. Ctrl+N starts a new session, and directory actions switch, rename or delete sessions through the owned services. Delete calls the persistence service, which rejects live, reserved, or borrowed identities and removes derived projection-cache state after durable deletion.
48
50
  - The terminal, fallback titles, and `/export` Markdown include only direct human `user/message` events (`source.kind === 'user'`) plus assistant replies. Durable model context from agent instructions, plugins, and skill catalogs is intentionally absent from this human transcript.
49
51
  - Ctrl+K search requests `literal-substring` matching from `ctx.sessionQuery` and filters to `user`/`assistant` transcript roles, so a query such as `回复` finds visible `只回复` text without surfacing injected model context; other service callers retain the default token-phrase mode and complete semantic corpus.
@@ -66,6 +68,7 @@ Reasoning is hidden by default. Ctrl+O or `/reasoning` shows the complete dim re
66
68
  -----
67
69
 
68
70
  <a id="understand-the-implementation"></a>
71
+
69
72
  ## Understand the implementation
70
73
 
71
74
  <details>
@@ -78,6 +81,7 @@ Reasoning is hidden by default. Ctrl+O or `/reasoning` shows the complete dim re
78
81
  -----
79
82
 
80
83
  <a id="further-exploration"></a>
84
+
81
85
  ## Further Exploration
82
86
 
83
87
  - [TUI package map](../README.md) — terminal runtime and renderer ownership.
@@ -88,6 +92,7 @@ Reasoning is hidden by default. Ctrl+O or `/reasoning` shows the complete dim re
88
92
  -----
89
93
 
90
94
  <a id="model-experience"></a>
95
+
91
96
  ## Model Experience
92
97
 
93
98
  ### Terminal application request
@@ -116,6 +121,7 @@ New turns append through the Agent's normal request construction; resuming recon
116
121
  - **Draft FIFO is process-local** — later-turn drafts are not crash-recovered; only messages handed to the Agent inbox or appended to the session log have durable ownership.
117
122
 
118
123
  <a id="dev-note"></a>
124
+
119
125
  ### Dev Note
120
126
 
121
127
  <details>
package/tui/README.zh.md CHANGED
@@ -23,6 +23,7 @@ deepseek-tui 的 profile bundle(配置包)与运行时插件让用户在 `ds
23
23
  -----
24
24
 
25
25
  <a id="use-this-package"></a>
26
+
26
27
  ## 使用本包
27
28
 
28
29
  ### 配置
@@ -43,7 +44,8 @@ bundle patch 从 `tuiStartup` 读取可选的 `task` 首条消息种子、可选
43
44
 
44
45
  ### 约定
45
46
 
46
- - 运行时拥有 live Agent 句柄、会话投影和会话目录状态;渲染包只接收 controller 接口。顶栏标题是已折叠的 `session/title`,但与人类用户消息并存的 `fallback` 标题除外;在出现 provider 或重命名标题之前循环显示紧凑挂载名 `DeepSeek · deepseek-tui`。目录行仍使用第一条人类消息作为回退。空闲无消息时,对话列绘制生成的官方 FishLogo、`DeepSeek` 与 `有什么可以帮忙的`。环境独立于颜色选择 half-block、full-block、ASCII 或纯字标输出;`brandAnimation` 保存 `auto | on | off`,任何输入、历史、覆盖层、resize、播放完成或卸载 stop 都会清除一次性 reveal timer。运行时只为已绑定的 live agent 回答 `approval/request`,其他 agent 调用 `next()`。`y`/`a` 得到 `'allowed-once'`,`n`/`d`/Esc 得到 `'rejected'`,中止(含 Ctrl+C 停止生成)经请求 signal 得到 `'cancelled'`。策略 `'never'` 由 host 在该 listener 之前决定,因此不会出现 ApprovalPane。Ctrl+E 翻转当前窗口的工具卡折叠(`toolCardsExpanded`;不写 session 事件)。空 `/permission` 打开预设覆盖层;带参 `/permission <name>` 走 `ctx.commands.execute`。空 `/settings` 打开设置覆盖层,列出 `describe()` 的每个顶层字段(含 JSON 编辑的 `llm-deepseek · models` 与 `llm-pi-ai · providers`);Enter 应用经 `ctx.settings.update` 写入所选字段。浏览态 `e` 报告 `prepareDocument()`,`r` 重读行(`✓ 已重载设置`)。空 `/resume` 打开会话列表。`/reload` 是本地命令:flush 当前会话、卸载终端、dispose 该会话,再以相同启动器标志加上 `--resume <id>` 拉起新的 Node,并丢掉原来的任务位置参数,以免首条消息再发一次。覆盖层上的 `r` 只重读设置行。空闲启动且未配置 `DEEPSEEK_API_KEY` 时打开 `首次设置`;Enter 经 `ctx.credentials.set` 保存后打开模型面板,Esc 跳过且不打开。`tui` 分节拥有 `colorTier`、`submitOnEnter`(为 false 时 Enter 插入换行)、`notify`(`off | attention | every-turn`,默认 `attention`)、`notifyQuietInputSeconds`(非负整数,默认 10)、`brandAnimation`(显示为 `自动 / 开启 / 关闭`)、`scrollbar`(布尔值,默认 `true`)、`reasoning` 与 `statusDetails`(布尔值,默认 `false`)、`locale`(`zh-CN | en-US`,默认 `zh-CN`)以及上文所述已验证的 `renderPolicy`。当前 runtime root Agent 的 scope 注册 `user-questions/request` waterfall listener;它用 `next()` 委托外部 root 与 child 请求,被接纳的请求则绘制 `AskUserPane`,把中止、Agent 替换与释放归并到同一清理,并只在准入时通知一次。↑↓/jk 移动高亮,数字键再 Enter 返回选项的原始 label。斜杠目录包含每条命令的 `description`。
47
+ - 运行时拥有 live Agent 句柄、会话投影和会话目录状态;渲染包只接收 controller 接口。顶栏标题是已折叠的 `session/title`,但与人类用户消息并存的 `fallback` 标题除外;在出现 provider 或重命名标题之前循环显示紧凑挂载名 `DeepSeek · deepseek-tui`。目录行仍使用第一条人类消息作为回退。空闲无消息时,对话列绘制生成的官方 FishLogo、`DeepSeek` 与 `有什么可以帮忙的`。环境独立于颜色选择 half-block、full-block、ASCII 或纯字标输出;`brandAnimation` 保存 `auto | on | off`,任何输入、历史、覆盖层、resize、播放完成或卸载 stop 都会清除一次性 reveal timer。运行时只为已绑定的 live agent 回答 `approval/request`,其他 agent 调用 `next()`。`y`/`a` 得到 `'allowed-once'`,`n`/`d`/Esc 得到 `'rejected'`,中止(含 Ctrl+C 停止生成)经请求 signal 得到 `'cancelled'`。策略 `'never'` 由 host 在该 listener 之前决定,因此不会出现 ApprovalPane。Ctrl+E 翻转当前窗口的工具卡折叠(`toolCardsExpanded`;不写 session 事件)。空 `/permission` 打开预设覆盖层;带参 `/permission <name>` 走 `ctx.commands.execute`。空 `/settings` 打开设置覆盖层,列出 `describe()` 的每个顶层字段(`llm-deepseek · models`;`llm-pi-ai · providers` 打开一个结构化表单——目录名、模板序号 1–4、单行 `名称 端点 [模型[,模型…]]`,或多行 `name= baseURL= models= api=`;已有路由展开为 `api` / `baseURL` / `apiKeyEnv` / `displayName` / `models` 的子行);Enter 应用经 `ctx.settings.update` 写入所选字段。`models=` 留空、任一表单中的字面量 `auto`、两 token 的 `名称 端点` 形式,以及已有路由 `providers.<route>.models` 行被填成 `auto` 时,都把模型列表组装交给 `ctx.llm.discoverModels`;面板在请求进行中显示 `正在获取模型列表…`,任何拒绝或空响应都画在 ✗ 行上且不写任何设置——未存凭据时的 401/403 会追加 `请先使用 /key 配置 API key`。浏览态 `e` 报告 `prepareDocument()`,`r` 重读行(`✓ 已重载设置`)。空 `/resume` 打开会话列表。`/reload` 是本地命令:flush 当前会话、卸载终端、dispose 该会话,再以相同启动器标志加上 `--resume <id>` 拉起新的 Node,并丢掉原来的任务位置参数,以免首条消息再发一次。覆盖层上的 `r` 只重读设置行。空闲启动且未配置 `DEEPSEEK_API_KEY` 时打开 `首次设置`;Enter 经 `ctx.credentials.set` 保存后打开模型面板,Esc 跳过且不打开。`tui` 分节拥有 `colorTier`、`submitOnEnter`(为 false 时 Enter 插入换行)、`notify`(`off | attention | every-turn`,默认 `attention`)、`notifyQuietInputSeconds`(非负整数,默认 10)、`brandAnimation`(显示为 `自动 / 开启 / 关闭`)、`scrollbar`(布尔值,默认 `true`)、`reasoning` 与 `statusDetails`(布尔值,默认 `false`)、`locale`(`zh-CN | en-US`,默认 `zh-CN`)以及上文所述已验证的 `renderPolicy`。当前 runtime root Agent 的 scope 注册 `user-questions/request` waterfall listener;它用 `next()` 委托外部 root 与 child 请求,被接纳的请求则绘制 `AskUserPane`,把中止、Agent 替换与释放归并到同一清理,并只在准入时通知一次。↑↓/jk 移动高亮,数字键再 Enter 返回选项的原始 label。斜杠目录包含每条命令的 `description`。
48
+ - 被引用的 `apiKeyEnv` 名称会在已声明字段之后各自获得一行设置行(`凭据 · NAME`);在该行回车,经 `ctx.credentials.set` 存储密钥并保持面板打开。向 `apiKeyEnv` 字段输入真实密钥会被拒绝,并给出应改用的命令(`请用 /key NAME <密钥> 配置该变量`);`/key NAME` 可从命令行接受命名凭据。
47
49
  - `g s` 在组合器缓冲恰好为 `g` 时切换已持久化的会话目录;`/resume` 打开同一列表且不会关掉已打开的列表。折叠标题相同的行会在行内追加稳定的最短唯一 session-id 提示;标题唯一的行保持不变。左右方向键按字素移动组合器 caret。↑/k 把对话移向更旧的行,↓/j 回到 live 边缘;有输入时方向键仍滚动,j/k 则插入字母。对话脱离底部时始终显示 `↓ 底部 · End/G`,有新输出时还会添加未读行数。鼠标滚轮在对话上与 ↑/k 同向,在列表面板上与 j/k 同向;每个报告移动 `scroll.wheelRows` 个物理行,同一 stdin 数据块内的报告合并为一个净请求。Ctrl+N 新建会话,目录动作通过所拥有的服务切换、重命名或删除会话。删除调用 persistence 服务;该服务拒绝 live、已预留或已借用的身份,并在持久删除后移除派生的投影缓存状态。
48
50
  - 终端、回退标题和 `/export` Markdown 只包含直接人类输入的 `user/message` 事件(`source.kind === 'user'`)与 assistant 回复。来自 agent 指令、插件和 skill 目录的持久模型上下文有意不进入这份人类 transcript(文本记录)。
49
51
  - Ctrl+K 搜索向 `ctx.sessionQuery` 请求 `literal-substring` 匹配,并过滤到 `user`/`assistant` transcript 角色,因此查询 `回复` 可以找到可见的 `只回复` 文本,同时不会显示注入的模型上下文;其他服务调用方仍保持默认的 token-phrase 模式与完整语义语料库。
@@ -66,6 +68,7 @@ bundle patch 从 `tuiStartup` 读取可选的 `task` 首条消息种子、可选
66
68
  -----
67
69
 
68
70
  <a id="understand-the-implementation"></a>
71
+
69
72
  ## 理解实现
70
73
 
71
74
  <details>
@@ -78,6 +81,7 @@ bundle patch 从 `tuiStartup` 读取可选的 `task` 首条消息种子、可选
78
81
  -----
79
82
 
80
83
  <a id="further-exploration"></a>
84
+
81
85
  ## 进一步探索
82
86
 
83
87
  - [TUI 包映射](../README.zh.md) — 终端运行时与渲染器所有权。
@@ -88,6 +92,7 @@ bundle patch 从 `tuiStartup` 读取可选的 `task` 首条消息种子、可选
88
92
  -----
89
93
 
90
94
  <a id="model-experience"></a>
95
+
91
96
  ## 模型体验
92
97
 
93
98
  ### 终端应用请求
@@ -116,6 +121,7 @@ profile 的系统提示词标识终端界面,运行时通过常规 Agent API
116
121
  - **Draft FIFO 仅在进程内存在** — 后续轮次 draft 不参与崩溃恢复;只有已移交 Agent inbox 或已追加到会话日志的消息具有持久所有权。
117
122
 
118
123
  <a id="dev-note"></a>
124
+
119
125
  ### 开发备注
120
126
 
121
127
  <details>
@@ -82,6 +82,16 @@
82
82
  - id: tui-startup
83
83
  name: "@deepseek-ai/dsh-tui/startup"
84
84
 
85
+ # Zero-config official OpenAI/Anthropic routes. They register
86
+ # openai-official / anthropic-official so they do not collide with the
87
+ # dormant llm-pi-ai catalog keys openai / anthropic that the Web Models
88
+ # page already owns.
89
+ - id: llm-openai
90
+ name: "@deepseek-ai/dsh-llm-openai"
91
+
92
+ - id: llm-anthropic
93
+ name: "@deepseek-ai/dsh-llm-anthropic"
94
+
85
95
  # Reads its task from the ordinary tuiStartup provider.
86
96
  - id: tui-runtime
87
97
  name: "@deepseek-ai/dsh-tui"