Skip to content

fix(daemon): Handle settings reload events outside transcript - #6407

Merged
wenshao merged 1 commit into
QwenLM:mainfrom
doudouOUC:codex/fix-settings-reload-event-log
Jul 6, 2026
Merged

fix(daemon): Handle settings reload events outside transcript#6407
wenshao merged 1 commit into
QwenLM:mainfrom
doudouOUC:codex/fix-settings-reload-event-log

Conversation

@doudouOUC

Copy link
Copy Markdown
Collaborator

What this PR does

This PR treats daemon settings reload notifications as structured workspace settings refresh signals instead of unknown debug transcript entries, so reload metadata no longer appears as a chat message in web shell sessions. It also emits a concise debug log for reload diagnostics with the changed settings keys, environment key names, child reload status, refreshed or skipped sessions, and reload errors when present.

Why it's needed

When daemon reloads were broadcast to active sessions, the UI layer did not recognize the reload event and rendered the raw event payload into the conversation transcript. That made operational reload noise visible to users and still did not give developers a clean log line for troubleshooting reload behavior.

Reviewer Test Plan

How to verify

Trigger a daemon settings reload while a web shell session is open. The transcript should not show a settings_reloaded (unrecognized daemon event) system/debug message, settings-dependent UI state should refresh through the workspace settings signal, and browser DevTools should show a [DaemonSessionProvider] settings reloaded: debug entry containing only diagnostic key names and session status fields.

Run cd packages/sdk-typescript && npx vitest run test/unit/daemonUi.test.ts --testNamePattern "settings_reloaded" and expect one focused test to pass. Run cd packages/webui && npx vitest run src/daemon/session/DaemonSessionProvider.test.tsx --testNamePattern "logs settings reloads" and expect one focused test to pass. Run npm run build and npm run typecheck from the repository root and expect both commands to exit successfully.

Evidence (Before & After)

Before: a daemon settings reload could appear in the web shell transcript as settings_reloaded (unrecognized daemon event) with the reload payload. After: the same reload is normalized as a workspace settings refresh signal, is omitted from the transcript, and is available as a concise debug log for troubleshooting.

Tested on

OS Status
🍏 macOS ✅ tested
🪟 Windows ⚠️ not tested
🐧 Linux ⚠️ not tested

Environment (optional)

Node.js v22.22.3, npm 10.9.8, local repository build and unit test commands.

Risk & Scope

  • Main risk or tradeoff: Reload diagnostics now go to browser debug logging rather than the chat transcript, so operators need DevTools or collected console logs to inspect them.
  • Not validated / out of scope: Manual browser reload testing on Windows and Linux was not performed locally.
  • Breaking changes / migration notes: None.

Linked Issues

N/A

中文说明

What this PR does

这个 PR 将 daemon settings reload 通知处理为结构化的 workspace settings refresh signal,而不是未知 debug transcript 条目,因此 reload 元数据不再作为 web shell 会话中的聊天消息展示。同时,它会为 reload 排障输出一条简洁的 debug log,包含变更的 settings key、环境变量 key 名、child reload 状态、刷新或跳过的 session,以及存在时的 reload 错误。

Why it's needed

daemon reload 广播到活跃 session 后,UI 层之前没有识别 reload 事件,于是会把原始事件 payload 渲染进会话 transcript。这会让用户看到运维 reload 噪声,同时也没有给开发者提供一条清晰的日志来排查 reload 行为。

Reviewer Test Plan

How to verify

在 web shell session 打开时触发 daemon settings reload。transcript 中不应该再出现 settings_reloaded (unrecognized daemon event) system/debug 消息,依赖 settings 的 UI 状态应该通过 workspace settings signal 刷新,并且浏览器 DevTools 中应该出现 [DaemonSessionProvider] settings reloaded: debug 记录,其中只包含诊断用的 key 名和 session 状态字段。

运行 cd packages/sdk-typescript && npx vitest run test/unit/daemonUi.test.ts --testNamePattern "settings_reloaded",预期一个 focused test 通过。运行 cd packages/webui && npx vitest run src/daemon/session/DaemonSessionProvider.test.tsx --testNamePattern "logs settings reloads",预期一个 focused test 通过。从仓库根目录运行 npm run buildnpm run typecheck,预期两个命令都成功退出。

Evidence (Before & After)

Before:daemon settings reload 可能作为 settings_reloaded (unrecognized daemon event) 连同 reload payload 一起出现在 web shell transcript 中。After:同一个 reload 会被归一化为 workspace settings refresh signal,不再进入 transcript,并且会作为简洁 debug log 供排障使用。

Tested on

OS Status
🍏 macOS ✅ tested
🪟 Windows ⚠️ not tested
🐧 Linux ⚠️ not tested

Environment (optional)

Node.js v22.22.3,npm 10.9.8,本地仓库 build 和 unit test 命令。

Risk & Scope

  • Main risk or tradeoff:reload 诊断信息现在输出到浏览器 debug log,而不是聊天 transcript,因此运维人员需要通过 DevTools 或采集到的 console log 查看。
  • Not validated / out of scope:没有在本地手动验证 Windows 和 Linux 浏览器场景。
  • Breaking changes / migration notes:无。

Linked Issues

N/A

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@doudouOUC
doudouOUC marked this pull request as ready for review July 6, 2026 16:23
Copilot AI review requested due to automatic review settings July 6, 2026 16:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the daemon event → UI event normalization path so settings_reloaded is treated as a structured workspace settings refresh signal (rather than an unknown/debug transcript entry), and adds a targeted browser debug log to aid reload diagnostics in WebUI sessions.

Changes:

  • Normalize settings_reloaded into workspace.settings.changed (scope workspace) in the TypeScript SDK normalizer.
  • Add WebUI-side debug logging for settings_reloaded with sanitized key-name metadata (no values).
  • Add unit tests to ensure reloads bump the settings signal and do not inject debug transcript blocks.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
packages/webui/src/daemon/session/DaemonSessionProvider.tsx Logs settings_reloaded metadata via console.debug and ensures normalization happens without transcript noise.
packages/webui/src/daemon/session/DaemonSessionProvider.test.tsx Adds a test asserting settings reloads trigger a settings signal + debug log without creating transcript debug blocks.
packages/sdk-typescript/src/daemon/ui/normalizer.ts Normalizes settings_reloaded into a workspace settings change signal event.
packages/sdk-typescript/test/unit/daemonUi.test.ts Adds coverage verifying settings_reloaded produces a settings refresh signal and no debug UI event.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +2095 to +2119
await renderWithProvider(<Harness />, { autoConnect: true });
await act(async () => {
await flushPromises();
});

expect(signals?.settingsVersion).toBe(1);
expect(blocks).not.toContainEqual(
expect.objectContaining({
kind: 'debug',
text: expect.stringContaining(
'settings_reloaded (unrecognized daemon event)',
) as string,
}),
);
expect(debug).toHaveBeenCalledWith(
'[DaemonSessionProvider] settings reloaded:',
expect.objectContaining({
childReloaded: true,
changedKeys: ['env', 'hooks'],
env: { updatedKeys: ['OPENAI_API_KEY'], removedKeys: [] },
sessionsRefreshed: ['session-1'],
sessionsSkipped: [],
}),
);
debug.mockRestore();
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: observed bug — the daemon emits settings_reloaded events, but the normalizer's switch has no case for it, so they fall through to the default handler and appear in the transcript as settings_reloaded (unrecognized daemon event): { ... }. The before/after description is clear: reload noise was visible to users in the web shell transcript.

Direction: aligned. Mapping settings_reloadedworkspace.settings.changed is the natural fit — the transcript reducer already no-ops on that event type, and the session provider's settingsVersion counter increments correctly. Same pattern as settings_changed.

Size: 69 production logic lines (normalizer +21, provider +48), 82 test lines (sdk +27, webui +55). Not a core-module path (packages/sdk-typescript/ and packages/webui/), and well under any threshold.

Approach: scope feels right — two surgical changes that directly address the problem. The logging helpers in the provider (getSettingsReloadLogData, getSettingsReloadEnvLog, getStringArray) are a bit more elaborate than a one-liner console.debug, but they produce structured diagnostic output consistent with how other daemon events are handled. Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:已观测到的 bug — daemon 会发出 settings_reloaded 事件,但 normalizer 的 switch 没有对应 case,导致事件落入 default 处理器,在 transcript 中显示为 settings_reloaded (unrecognized daemon event): { ... }。before/after 描述清晰:reload 噪声在 web shell transcript 中对用户可见。

方向:对齐。将 settings_reloaded 映射到 workspace.settings.changed 是自然的选择 — transcript reducer 已经对该事件类型做 no-op,session provider 的 settingsVersion 计数器也能正确递增。与 settings_changed 的模式一致。

规模:69 行生产逻辑(normalizer +21,provider +48),82 行测试(sdk +27,webui +55)。不涉及核心模块路径,远低于任何阈值。

方案:范围合理 — 两处精准修改直接解决问题。provider 中的日志辅助函数比一行 console.debug 更详细,但它们产生的结构化诊断输出与其他 daemon 事件的处理方式一致。进入代码审查 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

Independent proposal before reading the diff: I would have added a case 'settings_reloaded' to the normalizer switch, mapped it to workspace.settings.changed (same shape as settings_changed), and added a console.debug for diagnostics. That's essentially what this PR does.

The implementation is clean and correct:

  • Normalizer (normalizer.ts): new normalizeSettingsReloaded mirrors the normalizeSettingsChanged pattern — maps to workspace.settings.changed with key: 'settings_reloaded' and scope: 'workspace'. The transcript reducer already no-ops on that event type, so the event is silently consumed. The isRecord guard correctly falls back to a debug entry for malformed payloads.
  • Provider (DaemonSessionProvider.tsx): logSettingsReloadEvent runs before normalization and emits structured console.debug output. The helper functions (getSettingsReloadLogData, getSettingsReloadEnvLog, getStringArray) reuse existing module-level getString and isRecord — no new imports needed. The settingsVersion counter increments correctly because workspace.settings.changed events feed the settings accumulator.
  • Tests: both new tests verify the key behaviors — correct event type mapping, no debug block in transcript, and structured console output.

No critical issues found. No AGENTS.md violations.

Testing

Unit tests (PR branch in worktree):

sdk-typescript/daemonUi.test.ts:  252 passed (252 total)
webui/DaemonSessionProvider.test.tsx:  136 passed (136 total)

Focused tests for settings_reloaded both pass. Full suites show no regressions.

Build + typecheck: both pass clean.

tmux E2E: not applicable for this change. The behavior being fixed — daemon event normalization in the web shell UI — runs in the browser, not the terminal CLI. There's no way to trigger a settings_reloaded daemon event from a CLI prompt in tmux. Attempted smoke test showed tsx is unavailable on this runner, but the build via npm run build succeeded, confirming the PR compiles correctly.

$ npm run dev -- -p 'print hello world'
Failed to start dev server: spawn tsx ENOENT

The relevant verification is the unit test suite, which comprehensively covers the normalizer switch, the transcript filter, and the session provider's event handling.

中文说明

代码审查

读 diff 前的独立方案:在 normalizer switch 中添加 case 'settings_reloaded',映射到 workspace.settings.changed(与 settings_changed 同构),加 console.debug 做诊断。PR 的做法与此基本一致。

实现干净且正确:

  • Normalizer:新增 normalizeSettingsReloaded 复用 normalizeSettingsChanged 的模式 — 映射为 workspace.settings.changedkey: 'settings_reloaded'scope: 'workspace'。transcript reducer 已对该事件类型做 no-op,所以事件被静默消费。isRecord 守卫对畸形 payload 正确回退到 debug 条目。
  • ProviderlogSettingsReloadEvent 在 normalization 前运行,输出结构化 console.debug。辅助函数复用模块内已有的 getStringisRecord — 无需新 import。settingsVersion 计数器因 workspace.settings.changed 事件正确递增。
  • 测试:两个新测试验证了关键行为 — 正确的事件类型映射、transcript 中无 debug block、结构化 console 输出。

无关键问题,无 AGENTS.md 违规。

测试

单元测试(worktree 中的 PR 分支):

sdk-typescript/daemonUi.test.ts:  252 passed (252 total)
webui/DaemonSessionProvider.test.tsx:  136 passed (136 total)

settings_reloaded 聚焦测试均通过。完整套件无回归。

Build + typecheck: 均通过。

tmux E2E: 不适用。被修复的行为 — web shell UI 中的 daemon 事件归一化 — 运行在浏览器中,而非终端 CLI。无法通过 tmux 中的 CLI 触发 settings_reloaded daemon 事件。相关验证由单元测试套件全面覆盖。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

This is a clean, focused bug fix. The daemon was emitting settings_reloaded events that the normalizer didn't handle, causing raw event payloads to leak into the web shell transcript as debug entries. The fix adds the missing case to the normalizer switch and provides structured diagnostic logging — exactly what the problem calls for, nothing more.

The implementation matches what I'd write independently. It follows the existing normalizeSettingsChanged pattern, reuses module-level helpers, and the transcript reducer already handles the output event type correctly. 69 production lines across two files, 82 test lines, all passing. Build and typecheck clean.

The one caveat is tmux E2E testing — the change lives in the browser-based web shell, not the terminal CLI, so daemon event normalization can't be exercised from a tmux session. The unit test coverage is thorough though: 252 SDK normalizer tests and 136 provider tests, including focused assertions for the new behavior.

Approving. ✅

中文说明

这是一个干净、聚焦的 bug fix。daemon 发出的 settings_reloaded 事件未被 normalizer 处理,导致原始事件 payload 以 debug 条目的形式泄漏到 web shell transcript 中。修复方案在 normalizer switch 中添加了缺失的 case,并提供了结构化诊断日志 — 恰好解决问题,没有多余内容。

实现与我独立方案一致。复用了已有的 normalizeSettingsChanged 模式和模块级辅助函数,transcript reducer 已正确处理输出事件类型。两个文件 69 行生产代码,82 行测试,全部通过。Build 和 typecheck 干净。

唯一的限制是 tmux E2E 测试 — 变更在浏览器端 web shell 中,而非终端 CLI,因此无法通过 tmux 会话触发 daemon 事件归一化。但单元测试覆盖全面:252 个 SDK normalizer 测试和 136 个 provider 测试,包含针对新行为的聚焦断言。

批准合并。✅

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.

LGTM, looks ready to ship. ✅

@doudouOUC doudouOUC self-assigned this Jul 6, 2026
@doudouOUC
doudouOUC requested review from wenshao and yiliang114 July 6, 2026 16:39

@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 review findings. Downgraded from Approve to Comment: CI still running.

— 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

@wenshao
wenshao added this pull request to the merge queue Jul 6, 2026
Merged via the queue into QwenLM:main with commit d56bd1d Jul 6, 2026
72 checks passed
@doudouOUC
doudouOUC deleted the codex/fix-settings-reload-event-log branch July 7, 2026 13:52
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