Skip to content

fix(core): respect enableManagedAutoMemory in memory availability - #6941

Merged
wenshao merged 1 commit into
QwenLM:mainfrom
han-dreamer:fix/managed-memory-availability-gate
Jul 18, 2026
Merged

wenshao merged 1 commit into
QwenLM:mainfrom
han-dreamer:fix/managed-memory-availability-gate

Conversation

@han-dreamer

Copy link
Copy Markdown
Contributor

What this PR does

Makes managed-memory availability respect the existing memory.enableManagedAutoMemory setting. When managed auto-memory is disabled, isManagedMemoryAvailable() now returns false, so the # auto memory system-prompt block and related managed-memory surfaces stay aligned with the user's setting.

Why it's needed

Fixes #6936. Before this change, enableManagedAutoMemory: false disabled managed-memory operations but still allowed the 7-9 KB # auto memory instruction block to be injected into the system prompt. That meant users who explicitly disabled auto-memory to save context still paid the prompt cost for capabilities the model could not use.

Reviewer Test Plan

How to verify

Review the updated isManagedMemoryAvailable() gate and the config regression coverage. The focused test now verifies both that isManagedMemoryAvailable() returns false when enableManagedAutoMemory is disabled and that refreshHierarchicalMemory() still keeps project memory while omitting the # auto memory block without reading the auto-memory index.

Evidence (Before & After)

N/A — non-UI config behavior covered by unit tests.

Tested on

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

Environment (optional)

npm --workspace @qwen-code/qwen-code-core test -- src/config/config.test.ts → 1 file passed, 396 tests passed. npm --workspace @qwen-code/qwen-code-core run typecheck → passed.

Risk & Scope

  • Main risk or tradeoff: isManagedMemoryAvailable() also gates managed-memory commands and surfaces, so disabling memory.enableManagedAutoMemory now hides those surfaces consistently with the operation gate.
  • Not validated / out of scope: No new setting is introduced; this does not add a separate prompt-only strip option.
  • Breaking changes / migration notes: No migration required. This intentionally preserves the existing bare-mode behavior and avoids broadening safe-mode semantics by not replacing the gate with getManagedAutoMemoryEnabled().

Linked Issues

Fixes #6936

中文说明

What this PR does

让 managed memory 的可用性判断尊重现有的 memory.enableManagedAutoMemory 设置。当 managed auto-memory 被关闭时,isManagedMemoryAvailable() 现在会返回 false,因此 # auto memory system prompt 块以及相关 managed-memory 入口会和用户设置保持一致。

Why it's needed

修复 #6936。此前 enableManagedAutoMemory: false 会禁用 managed-memory 操作,但仍允许 7-9 KB 的 # auto memory 指令块注入 system prompt。这意味着用户即使明确关闭 auto-memory 来节省上下文,仍然要为模型无法使用的能力支付 prompt 成本。

Reviewer Test Plan

How to verify

检查更新后的 isManagedMemoryAvailable() 门控和 config 回归测试。聚焦测试现在同时验证:当 enableManagedAutoMemory 被关闭时,isManagedMemoryAvailable() 返回 false;并且 refreshHierarchicalMemory() 仍保留项目 memory,但不会注入 # auto memory 块,也不会读取 auto-memory index。

Evidence (Before & After)

N/A — 这是非 UI 配置行为,由单元测试覆盖。

Tested on

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

Environment (optional)

npm --workspace @qwen-code/qwen-code-core test -- src/config/config.test.ts → 1 个测试文件通过,396 个测试通过。npm --workspace @qwen-code/qwen-code-core run typecheck → 通过。

Risk & Scope

  • Main risk or tradeoff: isManagedMemoryAvailable() 也会门控 managed-memory 命令和界面入口,因此关闭 memory.enableManagedAutoMemory 后这些入口会与操作门控保持一致地隐藏。
  • Not validated / out of scope: 没有新增设置;本 PR 不提供单独的 prompt-only strip 选项。
  • Breaking changes / migration notes: 不需要迁移。本 PR 有意保留现有 bare mode 行为,并且没有直接替换为 getManagedAutoMemoryEnabled(),避免顺手扩大 safe mode 语义。

Linked Issues

Fixes #6936

@wenshao

wenshao commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Local build & real-E2E verification report (merge reference)

Verified at head 0a6bece5 (merge-base 35c91864) in an isolated detached worktree with a real npm ci and the actual built CLI on macOS. Before every drive, the gate implementation inside the built artifact was grep-verified (return !this.getBareMode() on the base build vs return this.enableManagedAutoMemory && !this.getBareMode() on the PR build), so each side of the A/B ran the code it claims to.

Verdict: LGTM — the fix works exactly as described end-to-end, no regression found. Two behavioral notes below for maintainer awareness (neither is a blocker).

1. Wire-level A/B — system prompt actually sent to the model

Drove the built CLI (node packages/cli/dist/index.js -p "hello", isolated $HOME, pre-seeded settings) against a local OpenAI-compatible capture server and parsed the system message of every captured POST /chat/completions body:

# Build Settings # auto memory block System prompt size
s1 merge-base enableManagedAutoMemory: false 🔴 still injected (5,302 chars) — the #6936 bug 30,428 chars
s2 PR head enableManagedAutoMemory: false 🟢 gone 25,119 chars (Δ −5,309 ≈ 5.2 KB)
s3 PR head defaults (setting omitted) 🟢 present — no regression 30,422 chars
s4 PR head false + enableTeamMemory: true + QWEN_CODE_MEMORY_TEAM=1 block and team section gone 25,119 chars
s5 merge-base false + enableTeamMemory: true + QWEN_CODE_MEMORY_TEAM=1 block + team index injected (6,379 chars) 31,505 chars

Project QWEN.md content survived in all scenarios (marker string retained), matching the PR's focused test at the wire level. The ~5.2 KB delta is with an empty memory store; populated stores (cf. s5's 6,379-char block with a team index) are consistent with the 7–9 KB reported in #6936.

wire capture A/B

2. TUI surface A/B — real built TUI via pty

With the setting off, the merge-base build still offered /dream and /forget in the slash-command menu (their operations would have failed — the surface/ops mismatch). On the PR build both are hidden, and a control run with default settings keeps them:

TUI slash-command surface A/B

3. Tests & typecheck (isolated worktree, real install)

  • core src/config/config.test.ts: 396/396 (includes the new regression test + the flipped expectation) — matches the PR author's run.
  • cli gated surfaces (rememberCommand, BuiltinCommandLoader, MemoryDialog): 34/34.
  • core src/memory/ full suite: 419 passed, 5 failed — all 5 are pre-existing local-machine artifacts, proven by re-running the same files at merge-base in the same worktree (fails identically: 4 failed | 3 passed): refresh.test.ts ×4 (macOS-only /var → /private/var tmpdir-symlink artifact; those tests mock isManagedMemoryAvailable, so they never touch the changed gate) and memoryLifecycle.integration.test.ts ×1 (real ~/.qwen/memories floods the recall prompt budget; the test lacks HOME isolation). Linux CI is unaffected by either class.
  • tsc --noEmit (core): clean.

tests & typecheck

4. Call-site audit & behavioral notes

All 8 production call sites of isManagedMemoryAvailable() were reviewed: system-prompt assembly (core/config.ts:2839), recall prefetch (core/client.ts:1992 — already double-gated with getManagedAutoMemoryEnabled(), no change), managed remember (memory/remember.ts:154), refresh-after-write (memory/refresh.ts:156), /remember prompt choice (rememberCommand.ts:46), MemoryDialog.tsx:177, BuiltinCommandLoader.ts:150 (/dream, /forget), and 4 ACP daemon methods (acpAgent.ts:6001/6022/6113/6190). The ACP surfaces flip consistently: workspaceMemoryRememberAvailability reports available: false and remember/forget/dream throw managed_memory_unavailable, which consumers already handle via the availability endpoint.

Two things worth knowing when merging:

  1. Team memory rides on the same gate (s4 vs s5 above). The entire team-memory block — prompt section, index rebuild, git sync — is nested inside if (isManagedMemoryAvailable()) in refreshHierarchicalMemory, so enableManagedAutoMemory: false now also suppresses team memory even with memory.enableTeamMemory: true (verified with the env override forced on). Defensible — team memory is a tier of managed memory and its recall was already ops-gated — but the two settings are nominally independent, so flagging it.
  2. Safe mode now effectively strips the block too. The CLI wiring (packages/cli/src/config/config.ts:2188) already passes enableManagedAutoMemory: false under safe mode, so after this PR safe mode also loses the prompt block, /dream, /forget and the ACP surfaces (previously availability stayed true in safe mode while ops were off). This closes the same mismatch class for safe mode — the PR's "avoids broadening safe-mode semantics" claim is accurate at the core gate, and the CLI wiring is what carries it over.

Also for the record: the CI precheck flag (prompt_injection:system_prompt) appears to fire because the diff touches system-prompt assembly; the 2-file diff contains no injected instructions.

Environment

macOS (Darwin 24.6), isolated detached worktree at 0a6bece5, real npm ci (prepare build), capture server + pty drivers, per-scenario isolated $HOME.

中文版本(Chinese version)

本地构建与真实 E2E 验证报告(合并参考)

在隔离的 detached worktree 中于 head 0a6bece5(merge-base 35c91864)完成验证:真实 npm ci + 实际构建产物 CLI(macOS)。每次驱动前都用 grep 确认了构建产物内的门控实现(base 构建为 return !this.getBareMode(),PR 构建为 return this.enableManagedAutoMemory && !this.getBareMode()),确保 A/B 两侧运行的确实是各自声称的代码。

结论:LGTM —— 修复端到端完全符合描述,未发现回归。 下面有两条行为备注供合并时参考(均不是阻塞项)。

1. Wire 层 A/B —— 实际发送给模型的 system prompt

用隔离 $HOME + 预置 settings 驱动构建产物 CLI(node packages/cli/dist/index.js -p "hello"),指向本地 OpenAI 兼容捕获服务器,解析每个捕获到的 POST /chat/completions 请求体中的 system message:

# 构建 设置 # auto memory 块 system prompt 大小
s1 merge-base enableManagedAutoMemory: false 🔴 仍被注入(5,302 字符)—— 即 #6936 的 bug 30,428 字符
s2 PR head enableManagedAutoMemory: false 🟢 已移除 25,119 字符(Δ −5,309 ≈ 5.2 KB)
s3 PR head 默认(未设置) 🟢 存在 —— 无回归 30,422 字符
s4 PR head false + enableTeamMemory: true + QWEN_CODE_MEMORY_TEAM=1 块和 team 段均消失 25,119 字符
s5 merge-base false + enableTeamMemory: true + QWEN_CODE_MEMORY_TEAM=1 块 + team 索引均注入(6,379 字符) 31,505 字符

所有场景中项目 QWEN.md 内容都保留(标记字符串在场),与 PR 的聚焦单测在 wire 层一致。~5.2 KB 差值是空 memory store 的情况;有内容的 store(参见 s5 含 team 索引的 6,379 字符块)与 #6936 报告的 7–9 KB 一致。

2. TUI 界面 A/B —— 通过 pty 驱动真实构建的 TUI

设置关闭时,merge-base 构建的斜杠命令菜单仍会展示 /dream 和 /forget(但其操作会失败 —— 即界面/操作不一致)。PR 构建下两者均被隐藏;默认设置的对照组则保留它们(见上方截图 2)。

3. 测试与 typecheck(隔离 worktree,真实安装)

  • core src/config/config.test.ts:396/396(含新增回归测试和翻转的预期)—— 与 PR 作者的运行结果一致。
  • cli 受门控界面(rememberCommand、BuiltinCommandLoader、MemoryDialog):34/34。
  • core src/memory/ 全套:419 通过,5 失败 —— 全部为本机预先存在的环境伪影,已通过在同一 worktree 切到 merge-base 重跑同文件证明(失败完全一致:4 failed | 3 passed):refresh.test.ts ×4(macOS 独有的 /var → /private/var tmpdir 符号链接伪影;这些测试 mock 了 isManagedMemoryAvailable,根本不经过本 PR 改动的门控)和 memoryLifecycle.integration.test.ts ×1(真实 ~/.qwen/memories 撑爆 recall prompt 预算;该测试缺少 HOME 隔离)。两类问题均不影响 Linux CI。
  • tsc --noEmit(core):通过。

4. 调用面审计与行为备注

审计了 isManagedMemoryAvailable() 的全部 8 处生产调用:system prompt 组装(core/config.ts:2839)、recall 预取(core/client.ts:1992 —— 本就与 getManagedAutoMemoryEnabled() 双重门控,无变化)、managed remember(memory/remember.ts:154)、写后刷新(memory/refresh.ts:156)、/remember 提示词选择(rememberCommand.ts:46)、MemoryDialog.tsx:177、BuiltinCommandLoader.ts:150(/dream、/forget)以及 4 个 ACP daemon 方法(acpAgent.ts:6001/6022/6113/6190)。ACP 面表现一致:workspaceMemoryRememberAvailability 返回 available: false,remember/forget/dream 抛出 managed_memory_unavailable,消费方本就通过可用性端点处理。

合并时值得了解的两点:

  1. Team memory 与该门控绑定(见上表 s4 与 s5)。team-memory 的整个逻辑块 —— prompt 段、索引重建、git 同步 —— 都嵌套在 refreshHierarchicalMemory 的 if (isManagedMemoryAvailable()) 内,因此 enableManagedAutoMemory: false 现在会连带压制 team memory,即使 memory.enableTeamMemory: true(已用强制环境变量验证)。可以自洽 —— team memory 本就是 managed memory 的一层,其 recall 早已被操作门控 —— 但两个设置名义上是独立的,故予以标注。
  2. Safe mode 实际上也会剥离该块。 CLI 接线层(packages/cli/src/config/config.ts:2188)在 safe mode 下本就传入 enableManagedAutoMemory: false,所以本 PR 之后 safe mode 也会失去 prompt 块、/dream、/forget 和 ACP 面(此前 safe mode 下 availability 保持 true 而操作被禁用)。这实际上把同类不一致在 safe mode 下也修掉了 —— PR 所述"不扩大 safe-mode 语义"在 core 门控层面准确,是 CLI 接线把效果带了过去。

另外说明:CI precheck 标记(prompt_injection:system_prompt)应是因为 diff 触及 system prompt 组装路径而触发;这个 2 文件的 diff 中不含任何注入指令。

环境

macOS(Darwin 24.6),隔离 detached worktree @ 0a6bece5,真实 npm ci(prepare 构建),捕获服务器 + pty 驱动,每场景独立 $HOME。

@wenshao

wenshao commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@wenshao

wenshao commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Maintainer E2E Verification (macOS)

Ran a real CLI E2E test on macOS to verify this PR before merging.

Test Method

Built the PR branch (npm run build && npm run bundle), then ran the bundled CLI against a mock OpenAI server with --openai-logging to capture the actual system prompt sent to the API. Compared two runs:

  1. Default (memory.enableManagedAutoMemory unset → true)
  2. Disabled (memory.enableManagedAutoMemory: false in user settings.json)

Results

enableManagedAutoMemory = true enableManagedAutoMemory = false
System prompt size 45,440 chars 40,729 chars
# auto memory block present ✅ Yes ❌ No
Managed memory ops Enabled Disabled

Context savings: 4,711 chars (~1,178 tokens) per request when disabled.

Unit Tests

✓ src/config/config.test.ts (396 tests) — all passed

The 4 PR-specific tests (including the new refreshHierarchicalMemory should omit managed auto-memory prompt when disabled and the updated returns false when enableManagedAutoMemory is false) all pass.

Screenshot

PR #6941 E2E Result

Verdict

✅ PASS — The one-line change in isManagedMemoryAvailable() correctly gates the # auto memory system prompt block. When enableManagedAutoMemory is false, the block is fully removed from the system prompt, saving ~4.7 KB of context per request. Project memory (QWEN.md/AGENTS.md) is still loaded normally.


中文:维护者 E2E 验证(macOS)

在 macOS 上运行了真实 CLI E2E 测试,验证本 PR 的行为。

测试方法

构建 PR 分支(npm run build && npm run bundle),然后用 mock OpenAI server + --openai-logging 运行打包后的 CLI,捕获发送给 API 的实际 system prompt。对比两次运行:

  1. 默认(memory.enableManagedAutoMemory 未设置 → true)
  2. 禁用(用户 settings.json 中设置 memory.enableManagedAutoMemory: false)

结果

enableManagedAutoMemory = true enableManagedAutoMemory = false
System prompt 大小 45,440 字符 40,729 字符
# auto memory 块存在 ✅ 是 ❌ 否
Managed memory 操作 启用 禁用

禁用后每次请求节省上下文:4,711 字符(约 1,178 tokens)

单元测试

✓ src/config/config.test.ts (396 tests) — 全部通过

4 个 PR 相关测试(包括新增的 refreshHierarchicalMemory should omit managed auto-memory prompt when disabled 和更新的 returns false when enableManagedAutoMemory is false)全部通过。

截图

PR #6941 E2E 结果

结论

✅ 通过 — isManagedMemoryAvailable() 的一行修改正确地门控了 # auto memory system prompt 块。当 enableManagedAutoMemory 为 false 时,该块从 system prompt 中完全移除,每次请求节省约 4.7 KB 上下文。项目 memory(QWEN.md/AGENTS.md)仍正常加载。

@wenshao
wenshao added this pull request to the merge queue Jul 18, 2026
Merged via the queue into QwenLM:main with commit 826688c Jul 18, 2026
43 checks passed
@han-dreamer
han-dreamer deleted the fix/managed-memory-availability-gate branch July 20, 2026 08:22
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.

isManagedMemoryAvailable() ignores enableManagedAutoMemory setting, wasting 7-9 KB of context

2 participants