refactor(tui): drop the TUI-local auto-title; titles come from the session-title service

Master's log-backed session-title capability already titles sessions durably
(deterministic fallback in the spine, optional model providers). Remove the
TUI's own autoTitle generation — the latch, prompt, cap, and llm stream call —
and keep the terminal rename: the TUI folds the logged title on mount and sets
'<session title> — <configured title>' on every accepted session/title event.
The tui-agent example and the scripted PTY fixture mount
session-title-first-message-llm so titles stay model-made; the scripted
adapter's tool-less branch now answers that provider's auxiliary request.

See .agents/notes/implemented/simplification/2026-07-22-tui-titles-from-session-title-service.md
This commit is contained in:
Turtle
2026-07-22 15:01:54 +08:00
parent f1f35ccaef
commit 2a9f248594
19 changed files with 144 additions and 327 deletions

View File

@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
2026-07-22-tui-titles-from-session-title-service.md: b54b99647230255cf241415f94aa21b2630c44cd
2026-07-22-tui-titles-from-session-title-service.zh.md: 67cc3332f0694887d5af0d71997d140b74669f46

View File

@@ -0,0 +1,25 @@
# Agent Note: TUI titles come from the session-title service
Status: implemented
English | [中文](2026-07-22-tui-titles-from-session-title-service.zh.md)
## Problem
Two model-title implementations coexisted after the tui-staging line merged onto master. The TUI carried its own `autoTitle` feature: a fire-and-forget `ctx.llm.stream` call after the first user message that set the terminal window title via OSC 0, with a one-shot latch, its own prompt, its own 40-character cap, and its own resume re-derivation ([auto-title Agent Note](../feature/2026-07-21-tui-auto-pane-title.md), [default-on Agent Note](../feature/2026-07-21-tui-auto-title-default-on.md)). Master had meanwhile landed [log-backed session titles](../feature/2026-07-21-log-backed-session-titles.md): a `sessionTitle` capability whose accepted revisions are durable `session/title` events, with a deterministic fallback and optional model providers. The TUI already consumed `session/title` for its header subtitle and window title, so a session could be titled twice by different strategies, and the TUI's process-local title was invisible to every other consumer (ACP, resume listings, forks).
## Decision
The TUI-local generation is removed; the session-title service is the one title source. `TuiConfig.autoTitle`, the latch, the abort controller, the title prompt, and `titleLine` are gone from `dsh-tui`. The terminal rename stays: the TUI folds the latest logged title on mount (`foldSessionTitle`), renders it as the banner subtitle, and sets the terminal window title to `<session title> — <configured title>` on every accepted `session/title` event — including resumed sessions, whose titles now replay from the log instead of being re-generated.
Model-made titles are a composition choice: `examples/tui-agent/cordis.yml` (and the scripted PTY fixture) mount `@deepseek-ai/dsh-session-title-first-message-llm`, which inherits the main request's route and replaces the spine's deterministic fallback with a short model summary. Deployments without the provider keep the fallback title from `dsh-agent-spine-demo`'s bundled `SessionTitleService`.
## Alternatives considered
**Keep both, letting the logged title win.** This was the first merge resolution: auto-title owned the whole window title until a logged `session/title` arrived in suffix form. It preserved behavior but doubled the model calls on every fresh session and left the TUI's title unobservable in the log, violating model-visible ⟺ logged in spirit and splitting the title contract across two owners.
**Port auto-title's prompt and cap into the service as a third provider.** The first-message-llm provider already exists with the same cadence, a reviewed prompt contract, durable request records, and supersession fencing; a second near-identical provider would be pure duplication.
## Consequences
One title pipeline: durable, replayable, visible to every consumer, and fenced against stale completions by the service. The TUI sheds ~90 lines and its `llm`-streaming path. The cost is that a title now requires the provider plugin in the composition for model quality — a leaf choice, not a TUI default — and the terminal title changes shape from the bare model summary to the suffixed `<title> — <product>` form the log-backed path always used. The superseded auto-title Agent Notes carry pointers here.

View File

@@ -0,0 +1,25 @@
# Agent Note: TUI 标题来自 session-title 服务
Status: implemented
[English](2026-07-22-tui-titles-from-session-title-service.md) | 中文
## 问题
tui-staging 分支合入 master 后,两套模型标题实现并存。TUI 自带 `autoTitle` 特性:在首条用户消息后发起一次 fire-and-forget 的 `ctx.llm.stream` 调用,通过 OSC 0 设置终端窗口标题,带有一次性闩锁、自己的提示词、自己的 40 字符截断和自己的恢复重推导([auto-title Agent Note](../feature/2026-07-21-tui-auto-pane-title.md)、[default-on Agent Note](../feature/2026-07-21-tui-auto-title-default-on.md))。而 master 已落地[日志承载的会话标题](../feature/2026-07-21-log-backed-session-titles.md):一个 `sessionTitle` 能力,其被接受的修订是持久的 `session/title` 事件,带确定性回退和可选的模型 provider。TUI 已经消费 `session/title` 作为横幅副标题和窗口标题,于是一个会话可能被两种策略各标题一次,且 TUI 的进程本地标题对其他所有消费者(ACP、恢复列表、fork)不可见。
## 决策
移除 TUI 本地生成;session-title 服务是唯一的标题来源。`TuiConfig.autoTitle`、闩锁、abort controller、标题提示词和 `titleLine` 全部从 `dsh-tui` 删除。终端重命名保留:TUI 在挂载时折叠最新的已记录标题(`foldSessionTitle`),将其渲染为横幅副标题,并在每个被接受的 `session/title` 事件上把终端窗口标题设为 `<会话标题> — <配置标题>` —— 包括恢复的会话,其标题现在从日志回放而不是重新生成。
模型生成的标题是组合选择:`examples/tui-agent/cordis.yml`(以及脚本化 PTY fixture)挂载 `@deepseek-ai/dsh-session-title-first-message-llm`,它继承主请求的确切路由,用简短的模型摘要替换 spine 的确定性回退。未挂载该 provider 的部署保留 `dsh-agent-spine-demo` 内置 `SessionTitleService` 的回退标题。
## 备选方案
**两者并存,已记录标题胜出。** 这是第一版合并决议:auto-title 独占整个窗口标题,直到已记录的 `session/title` 以后缀形式到达。它保留了行为,但每个新会话产生双倍模型调用,且 TUI 的标题在日志中不可观察,实质上违反 model-visible ⟺ logged,并把标题契约拆给两个所有者。
**把 auto-title 的提示词和截断移植为服务的第三个 provider。** first-message-llm provider 已经存在,节奏相同,且有经过评审的提示词契约、持久的请求记录和替换围栏;再造一个近乎相同的 provider 纯属重复。
## 影响
标题管线归一:持久、可回放、对所有消费者可见,并由服务对过期完成设防。TUI 削减约 90 行及其 `llm` 流式路径。代价是模型质量的标题现在需要在组合中挂载 provider 插件 —— 这是叶配置选择,不是 TUI 默认值 —— 且终端标题形状从裸模型摘要变为日志路径一贯使用的 `<标题> — <产品>` 后缀形式。被取代的 auto-title Agent Note 携带指向本文的指针。