@epoch-agent/tui 1.1.0 → 2.0.0

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 (3) hide show
  1. package/README.md +31 -29
  2. package/dist/index.js +6 -2
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -68,24 +68,24 @@ web 也用同一份。⚠️ **别在模块级调 `t()`**:插槽是 `renderApp
68
68
 
69
69
  ## 结构
70
70
 
71
- | 目录 / 文件 | 内容 |
72
- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
73
- | `app.tsx` | 根组件:`<Static>` 历史 + 限高 pending + 底栏 + 全局键位 |
74
- | `render.tsx` | `renderApp()`——provider 树 + ink render options |
75
- | `contexts/` | app / config / session / streaming / ui-state 五个 context |
76
- | `components/` | banner、history-item、input-box、status-bar、suggestions、toast、thinking-indicator、shortcuts-help |
77
- | `components/dialogs/` | tool-confirmation(审批)、plan-confirmation、command-palette、file-palette、search-palette(Ctrl+R)、rewind-picker(Esc Esc)、picker(单选 / 多选 / 自由输入)、select-list |
78
- | `components/messages/` | 按类型分发的消息渲染:user / model / diff / error / warning / info / hint |
79
- | `commands/` | 斜杠命令:`builtin.ts` / `session.ts` / `inspect.ts` / `workspace.ts` / `rewind.ts` / `plugins.ts` + `parse.ts` + `prefix.ts` + `types.ts`(`HostActions` 契约) |
80
- | `hooks/` | `use-agent-run.ts`(跑一轮 + 中断)、`use-slash-commands.ts`、`use-rewind.ts`(面板 + Esc Esc 窗口)、`use-question.ts`(结构化提问逐个走完)。⚠️ 2026-09-29 起,某一问带 `page`(插件在本机起的一张页)时副标题末尾补一句地址 —— **终端画不出 iframe,所以一行分支都不开**(选项是必填的,照常答得动;判据在 `use-question.ts` 那一处) |
81
- | `keybindings/` | 键位层(方案 31):`actions.ts` / `parser.ts`(ink 的 Key → chord)/ `defaults.ts`(默认表 = 原来的硬编码)/ `resolver.ts` / `use-keybinding.ts` / `sequences.ts` + `use-key-sequences.ts`(序列) |
82
- | `vim/` | Vim 模式(方案 31 PR-3):`motions.ts`(`w` / `$` / `f,` 落在哪)+ `machine.ts`(`(state, key) → (state, edits)` 纯状态机)+ `use-vim.ts`(React 外壳,只存 ref / 喂渲染) |
83
- | `streaming/` | 工具调用与 artifact 的展示格式化 |
84
- | `text/` | `ops.ts` 多行 buffer 的纯状态迁移 + `use-text-buffer.ts` React 外壳 |
85
- | `markdown/` | Markdown 解析、行内样式、代码高亮(lowlight) |
86
- | `theme/` | 语义色 + 颜色工具 |
87
- | `types/` | 消息 / 状态类型、`checkpoint-types.ts`(core 那几个回退类型的结构性镜像)、`host-info.ts`(宿主算好的展示形状) |
88
- | `debug.ts` | debug 日志 |
71
+ | 目录 / 文件 | 内容 |
72
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
73
+ | `app.tsx` | 根组件:`<Static>` 历史 + 限高 pending + 底栏 + 全局键位 |
74
+ | `render.tsx` | `renderApp()`——provider 树 + ink render options |
75
+ | `contexts/` | app / config / session / streaming / ui-state 五个 context |
76
+ | `components/` | banner、history-item、input-box、status-bar、suggestions、toast、thinking-indicator、shortcuts-help |
77
+ | `components/dialogs/` | tool-confirmation(审批)、plan-confirmation、command-palette、file-palette、search-palette(Ctrl+R)、rewind-picker(Esc Esc)、picker(单选 / 多选 / 自由输入)、select-list |
78
+ | `components/messages/` | 按类型分发的消息渲染:user / model / diff / error / warning / info / hint |
79
+ | `commands/` | 斜杠命令:`builtin.ts` / `session.ts` / `inspect.ts` / `workspace.ts` / `rewind.ts` / `plugins.ts` + `parse.ts` + `prefix.ts` + `types.ts`(`HostActions` 契约) |
80
+ | `hooks/` | `use-agent-run.ts`(跑一轮 + 中断)、`use-slash-commands.ts`、`use-rewind.ts`(面板 + Esc Esc 窗口)、`use-question.ts`(结构化提问逐个走完)。⚠️ 2026-09-29 起,某一问带 `page`(插件在本机起的一张页)时副标题末尾补一句地址 —— **终端画不出 iframe,所以不开新组件**。2026-10-15 起带 `page` 的那一问可以没有选项:那时副标题换成「选项在这个页面里 …」,列表里只剩「其他…」,并且一律按单选走(判据在 `use-question.ts` 那一处) |
81
+ | `keybindings/` | 键位层(方案 31):`actions.ts` / `parser.ts`(ink 的 Key → chord)/ `defaults.ts`(默认表 = 原来的硬编码)/ `resolver.ts` / `use-keybinding.ts` / `sequences.ts` + `use-key-sequences.ts`(序列) |
82
+ | `vim/` | Vim 模式(方案 31 PR-3):`motions.ts`(`w` / `$` / `f,` 落在哪)+ `machine.ts`(`(state, key) → (state, edits)` 纯状态机)+ `use-vim.ts`(React 外壳,只存 ref / 喂渲染) |
83
+ | `streaming/` | 工具调用与 artifact 的展示格式化 |
84
+ | `text/` | `ops.ts` 多行 buffer 的纯状态迁移 + `use-text-buffer.ts` React 外壳 |
85
+ | `markdown/` | Markdown 解析、行内样式、代码高亮(lowlight) |
86
+ | `theme/` | 语义色 + 颜色工具 |
87
+ | `types/` | 消息 / 状态类型、`checkpoint-types.ts`(core 那几个回退类型的结构性镜像)、`host-info.ts`(宿主算好的展示形状) |
88
+ | `debug.ts` | debug 日志 |
89
89
 
90
90
  ## 布局约束(改这里之前先读)
91
91
 
@@ -207,25 +207,25 @@ Ink 的 `log-update` **只能擦除它上一帧写过的行数**。一旦动态
207
207
 
208
208
  ```
209
209
  /model 看当前模型 / provider / 凭据 / 窗口
210
- /model gpt-4o 同一家换个模型
211
- /model anthropic/claude-opus-4-6 provider 和模型一起换
210
+ /model @my-relay 换到「我的模型」里那一条(端点 / key 跟着它走)
212
211
  /model --reset 回到配置里那个
213
212
  ```
214
213
 
215
214
  **换模型不清空上下文**——那正是它的用处(对着同一段对话换个更强或更便宜的脑子)。
216
215
  代价是新模型得接得住已经积累的东西,所以有三道前置检查,任何一道不过就**一个字段都不动**:
217
216
 
218
- | 拦住的情况 | 为什么 |
219
- | ------------------------ | ------------------------------------------------------- |
220
- | 目标 provider 没凭据 | 请求根本发不出去,理由里点名该设哪个环境变量 |
221
- | 会话里有图片,新模型不认 | 下一轮把带图历史发出去必然 400,而 400 是**已经计费**的 |
222
- | 已用上下文超过新窗口 | 同上。先 `/clear` 或换个大窗口的模型 |
217
+ | 拦住的情况 | 为什么 |
218
+ | ------------------------ | ---------------------------------------------------------- |
219
+ | 目标那一条没有 key | 请求根本发不出去,理由里点名是哪一条(去设置页给它填一把) |
220
+ | 会话里有图片,新模型不认 | 下一轮把带图历史发出去必然 400,而 400 是**已经计费**的 |
221
+ | 已用上下文超过新窗口 | 同上。先 `/clear` 或换个大窗口的模型 |
223
222
 
224
223
  装得下但已经很挤、或者新模型不支持工具调用,则是**换成 + 出声**(warning),不拦。
225
224
 
226
225
  判据全在 core 的 `evaluateSelection`,TUI 只负责把结果念出来 —— 拒绝的理由逐字透传,
227
- 不在 TUI 里重编一句。`provider/model` 的解析走 protocol 的 `parseModelRef`,
228
- 所以 `meta-llama/Llama-3.3-70B-Instruct-Turbo` 这种**模型名里自带斜杠**的能正确识别。
226
+ 不在 TUI 里重编一句。取值只认 `@<id>`(「我的模型」里的一条),解析走 protocol 的
227
+ `parseModelRef` —— **2.0.0 起裸模型名 / `<provider>/<model>` 一律报「看不懂」**,
228
+ 那一轮仍跑在当前模型上。加条目用设置页或 `epoch model`。
229
229
 
230
230
  > ⚠️ 已知边界(PR-2 复核后仍在):自动压缩的预算仍是**启动时**那个模型的窗口,
231
231
  > 换到小窗口模型后压缩不会跟着提前触发 —— 这正是上面第三道检查直接拒绝而不是
@@ -241,8 +241,10 @@ Ink 的 `log-update` **只能擦除它上一帧写过的行数**。一旦动态
241
241
  - **命令 frontmatter 的 `model:`** —— 一条自定义命令可以声明自己用哪个模型
242
242
  (`model: utility` 解析成配置里的工具模型),**只在那一轮生效,收尾无条件还原**。
243
243
  Esc 中断走的是生成器的 `return()`,还原照样发生
244
- - **降级** —— 主模型报 404 / 模型不可用时,引擎按
245
- 「`--fallback-model`(同 provider)→ 内置默认 → 换 provider」的顺序往下试。
244
+ - **降级** —— 主模型这个落点没救了就换 `fallback.model` 指向的那一条(2.0.0 起
245
+ 只有这一级,条目自带端点,可以跨家)。404 / 模型不存在、401/403 / key 被拒、
246
+ 402 / 额度耗尽**当场换**;429 / 5xx / 超时那一类先在原地把重试预算跑完,**耗尽
247
+ 再换**(2026-10-16 起 —— 在那之前这一族一次都降不到)。
246
248
  下一轮又会**从你选的那个模型重新起步**:降级是这一次请求的事,不改你的选择
247
249
 
248
250
  同一个模型**连续三次**把请求拖垮,本会话就不再自动用它了,并在那一轮结束时给一条
package/dist/index.js CHANGED
@@ -4589,7 +4589,10 @@ function useQuestion({ prompt }) {
4589
4589
  i: stepRef.current + 1,
4590
4590
  n: questions.length
4591
4591
  })} \xB7 ${current.header}` : current.header;
4592
- const subtitle2 = current.page ? `${head} \xB7 ${t("tui.question.page_hint", { url: current.page.url })}` : head;
4592
+ const pageOnly = current.options.length === 0;
4593
+ const subtitle2 = current.page ? `${head} \xB7 ${t(pageOnly ? "tui.question.page_only_hint" : "tui.question.page_hint", {
4594
+ url: current.page.url
4595
+ })}` : head;
4593
4596
  const base = {
4594
4597
  title: current.question,
4595
4598
  subtitle: subtitle2,
@@ -4601,7 +4604,7 @@ function useQuestion({ prompt }) {
4601
4604
  allowFreeInput: true,
4602
4605
  onCancel: () => settle({}, true)
4603
4606
  };
4604
- const picker = current.multiSelect ? { ...base, multiSelect: true, onPick: pick } : { ...base, onPick: pick };
4607
+ const picker = current.multiSelect && !pageOnly ? { ...base, multiSelect: true, onPick: pick } : { ...base, onPick: pick };
4605
4608
  return { picker, step: step2 };
4606
4609
  }
4607
4610
  // src/hooks/use-rewind.ts
@@ -5575,6 +5578,7 @@ function switchModel(ctx, arg) {
5575
5578
  ctx.push({
5576
5579
  type: "info",
5577
5580
  text: t("tui.model.switched", {
5581
+ entry: selection.entry,
5578
5582
  provider: selection.provider,
5579
5583
  model: selection.model,
5580
5584
  k: (contextLength / 1e3).toFixed(0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epoch-agent/tui",
3
- "version": "1.1.0",
3
+ "version": "2.0.0",
4
4
  "private": false,
5
5
  "description": "epoch-agent Ink TUI 界面",
6
6
  "repository": {
@@ -29,8 +29,8 @@
29
29
  "mnemonist": "0",
30
30
  "string-width": "8",
31
31
  "strip-ansi": "7",
32
- "@epoch-agent/protocol": "1.1.0",
33
- "@epoch-agent/view": "1.1.0"
32
+ "@epoch-agent/protocol": "2.0.0",
33
+ "@epoch-agent/view": "2.0.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^26.1.2",