Skip to content

fix(daemon): enable auto-title generation for ACP sessions#4836

Merged
chiga0 merged 1 commit into
daemon_mode_b_mainfrom
fix/daemon-auto-title
Jun 8, 2026
Merged

fix(daemon): enable auto-title generation for ACP sessions#4836
chiga0 merged 1 commit into
daemon_mode_b_mainfrom
fix/daemon-auto-title

Conversation

@chiga0

@chiga0 chiga0 commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Allow ACP (daemon) sessions to auto-generate session titles after the first assistant reply, matching the existing behavior of interactive TUI sessions. The fix relaxes a single guard in maybeTriggerAutoTitle() from if (!isInteractive()) return to if (!isInteractive() && !getExperimentalZedIntegration()) return, so daemon sessions are no longer treated as headless one-shot CLI runs.

Why it's needed

The isInteractive() guard was originally added to prevent headless CLI runs (qwen -p "...") from wasting fast-model tokens on a session title nobody would see. However, the ACP child process is spawned with pipe stdio (process.stdin.isTTY === false), which causes isInteractive() to return false for ALL daemon sessions — not just headless ones. As a result, every daemon session (Web Chat, IDE extension, Channel) shows truncated raw prompt text in the session list instead of a semantically meaningful title.

Mode isInteractive() getExperimentalZedIntegration() Auto-title before After
TUI (terminal) true false works works
Daemon (ACP) false true broken fixed
Headless CLI false false blocked blocked

Reviewer Test Plan

How to verify

  1. Confirm guard logic: in chatRecordingService.ts:955-965, verify the condition !isInteractive() && !getExperimentalZedIntegration() correctly skips only headless CLI mode.
  2. Run npx vitest run packages/core/src/services/chatRecordingService.autoTitle.test.ts — all 17 tests pass (15 existing + 2 new).
  3. The two new tests cover: (a) ACP mode triggers auto-title despite isInteractive() === false; (b) headless CLI mode (non-interactive + non-ACP) still blocks.

Evidence (Before & After)

Non-UI change — unit tests only.

Before: maybeTriggerAutoTitle returns early for any non-interactive config, including ACP.
After: maybeTriggerAutoTitle proceeds for ACP sessions (getExperimentalZedIntegration() === true).

Tested on

OS Status
🍏 macOS
🪟 Windows N/A
🐧 Linux N/A

Risk & Scope

  • Main risk or tradeoff: ACP sessions now consume one fast-model call (~130 tokens) per new session for title generation. This matches TUI behavior and is bounded by AUTO_TITLE_ATTEMPT_CAP = 3.
  • Not validated / out of scope: The generated title is written to JSONL only — no SSE push to connected clients. Session list refresh is needed to see the new title (same as TUI).
  • Breaking changes / migration notes: None.

Linked Issues

None — discovered during daemon session lifecycle analysis.

中文说明

本 PR 做了什么

允许 ACP(daemon)会话在第一个 assistant 回复后自动生成会话标题,与交互式 TUI 会话的现有行为一致。修复方式是将 maybeTriggerAutoTitle() 中的守卫条件从 if (!isInteractive()) return 放宽为 if (!isInteractive() && !getExperimentalZedIntegration()) return,使 daemon 会话不再被当作一次性无头 CLI 运行。

为什么需要

isInteractive() 守卫最初是为了防止无头 CLI 运行(qwen -p "...")在不会被看到的会话标题上浪费 fast model token。但 ACP 子进程通过 pipe stdio 启动(process.stdin.isTTY === false),导致所有 daemon 会话的 isInteractive() 返回 false——不仅仅是无头运行。结果是所有 daemon 会话(Web Chat、IDE 扩展、Channel)在会话列表中显示截断的原始 prompt 文本,而非语义化的标题。

风险与范围

  • 主要风险:ACP 会话现在每个新会话消耗一次 fast model 调用(~130 tokens)。与 TUI 行为一致,受 AUTO_TITLE_ATTEMPT_CAP = 3 限制。
  • 未验证/超出范围:生成的标题仅写入 JSONL,不通过 SSE 推送到已连接的客户端。需要刷新会话列表才能看到新标题(与 TUI 相同)。
  • 无破坏性变更。

🤖 Generated with Qwen Code

The automatic session title generation was silently disabled for all
daemon sessions. The guard in `maybeTriggerAutoTitle` checks
`config.isInteractive()`, which returns false for the ACP child process
because it is spawned with pipe stdio (`process.stdin.isTTY === false`).

This guard was originally added to prevent headless one-shot CLI runs
(`qwen -p "do something"`) from wasting fast-model tokens on a title
that no one would ever see. However, daemon sessions are long-lived and
user-resumable — they appear in the session list and benefit from
semantically meaningful titles.

The fix allows ACP mode (`config.getExperimentalZedIntegration()`) to
bypass the `isInteractive()` check while still blocking true headless
CLI runs. After this change, the first assistant reply in a daemon
session will trigger LLM-based title generation (3-7 words, sentence
case) using the configured fast model, just as it does for interactive
TUI sessions.

Generated with AI

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR @chiga0!

Template: The PR uses custom headings (Background, Summary, etc.) instead of the template sections. Notably missing: Reviewer Test Plan (How to verify + Evidence), Tested on table, Risk & Scope, Linked Issues, and the Chinese translation. The content in Background/Summary is solid, but a reviewer needs the structured test plan to verify efficiently. Could you update the body to match the template?

On direction: solid bug fix. Daemon sessions are long-lived and resumable, so skipping auto-title is a real gap. The isInteractive() guard was designed for one-shot CLI runs, and ACP sessions legitimately bypass that assumption. Claude Code's CHANGELOG has related session-title fixes (e.g. "Fixed session title being generated from plugin monitor output"), confirming this is an active concern across agent CLIs. ✅

On approach: minimal and well-scoped. The fix is a single condition relaxation — !isInteractive() && !getExperimentalZedIntegration() — which preserves the original intent (don't waste tokens on throwaway sessions) while carving out the daemon case. The truth table in the PR body makes the logic easy to verify. 2 tests covering the new branch + the preserved guard. Nothing to cut. ✅

Template is the only blocker — once that's fixed, moving on to code review. 🔍

中文说明

感谢贡献 @chiga0

模板: PR 使用了自定义标题(Background、Summary 等),而非模板要求的章节。缺少:Reviewer Test Plan(How to verify + Evidence)、Tested on 表格、Risk & Scope、Linked Issues,以及中文翻译。Background/Summary 的内容本身不错,但审查者需要结构化的测试计划来高效验证。能否按模板更新 PR 描述?

方向:合理的 bug 修复。Daemon 会话是长期存在且可恢复的,跳过自动标题确实是一个真实的缺口。isInteractive() 守卫是为一次性 CLI 运行设计的,ACP 会话合理地绕过了这个假设。Claude Code 的 CHANGELOG 也有相关的会话标题修复,确认这是 agent CLI 的共同关注点。✅

方案:最小化且范围合理。修复是一个单一的条件放宽——!isInteractive() && !getExperimentalZedIntegration()——保留了原始意图(不在一次性会话上浪费 token),同时为 daemon 场景开了口子。PR 描述中的真值表让逻辑一目了然。2 个测试覆盖新分支和保留的守卫。没有多余的部分。✅

模板是唯一的阻塞项——修复后进入代码审查。🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @chiga0!

Template: The PR uses custom headings (Background, Summary, etc.) instead of the template sections. Notably missing: Reviewer Test Plan (How to verify + Evidence), Tested on table, Risk & Scope, Linked Issues, and the Chinese translation. The content in Background/Summary is solid, but a reviewer needs the structured test plan to verify efficiently. Could you update the body to match the template?

On direction: solid bug fix. Daemon sessions are long-lived and resumable, so skipping auto-title is a real gap. The isInteractive() guard was designed for one-shot CLI runs, and ACP sessions legitimately bypass that assumption. Claude Code's CHANGELOG has related session-title fixes (e.g. "Fixed session title being generated from plugin monitor output"), confirming this is an active concern across agent CLIs. ✅

On approach: minimal and well-scoped. The fix is a single condition relaxation — !isInteractive() && !getExperimentalZedIntegration() — which preserves the original intent (don't waste tokens on throwaway sessions) while carving out the daemon case. The truth table in the PR body makes the logic easy to verify. 2 tests covering the new branch + the preserved guard. Nothing to cut. ✅

Template is the only blocker — once that's fixed, moving on to code review. 🔍

中文说明

感谢贡献 @chiga0

模板: PR 使用了自定义标题(Background、Summary 等),而非模板要求的章节。缺少:Reviewer Test Plan(How to verify + Evidence)、Tested on 表格、Risk & Scope、Linked Issues,以及中文翻译。Background/Summary 的内容本身不错,但审查者需要结构化的测试计划来高效验证。能否按模板更新 PR 描述?

方向:合理的 bug 修复。Daemon 会话是长期存在且可恢复的,跳过自动标题确实是一个真实的缺口。isInteractive() 守卫是为一次性 CLI 运行设计的,ACP 会话合理地绕过了这个假设。Claude Code 的 CHANGELOG 也有相关的会话标题修复,确认这是 agent CLI 的共同关注点。✅

方案:最小化且范围合理。修复是一个单一的条件放宽——!isInteractive() && !getExperimentalZedIntegration()——保留了原始意图(不在一次性会话上浪费 token),同时为 daemon 场景开了口子。PR 描述中的真值表让逻辑一目了然。2 个测试覆盖新分支和保留的守卫。没有多余的部分。✅

模板是唯一的阻塞项——修复后进入代码审查。🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found. LGTM! ✅ Downgraded from Approve to Comment: CI still running. — qwen3.7-max via Qwen Code /review

@chiga0 chiga0 requested review from doudouOUC and wenshao June 8, 2026 05:14
@yiliang114

Copy link
Copy Markdown
Collaborator

@qwen-code /review

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found. LGTM! ✅ — qwen3.7-max via Qwen Code /review

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found. LGTM! ✅ — qwen3.7-max via Qwen Code /review

@chiga0 chiga0 merged commit d9025d0 into daemon_mode_b_main Jun 8, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants