Skip to content

feat(cli): enable /remember, /forget, /dream in ACP mode#4819

Merged
doudouOUC merged 6 commits into
daemon_mode_b_mainfrom
feat/slash-commands-acp-mode-v2
Jun 6, 2026
Merged

feat(cli): enable /remember, /forget, /dream in ACP mode#4819
doudouOUC merged 6 commits into
daemon_mode_b_mainfrom
feat/slash-commands-acp-mode-v2

Conversation

@doudouOUC

@doudouOUC doudouOUC commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • What changed: Enable /remember, /forget, /dream slash commands in ACP mode by adding supportedModes: ['interactive', 'acp'] declarations, plus error handling and config guards.
  • Why it changed: Web-shell clients couldn't invoke these memory commands because filterCommandsForMode('acp') excluded them (defaulted to ['interactive'] only).
  • Reviewer focus: dreamCommand.ts conditional eager recordDream logic (ACP fire-and-forget vs interactive onComplete).

Validation

  • Commands run:
    npx vitest run packages/cli/src/ui/commands/dreamCommand.test.ts packages/cli/src/ui/commands/forgetCommand.test.ts packages/cli/src/ui/commands/rememberCommand.test.ts packages/cli/src/services/commandUtils.test.ts
  • Prompts / inputs used: N/A (unit tests only; command handlers are invoked by ACP session, not directly by user prompt)
  • Expected result: All 15 tests pass; commands appear in filterCommandsForMode('acp') results
  • Observed result: 15/15 tests pass, type check clean
  • Quickest reviewer verification path: Run the test command above; verify supportedModes includes 'acp' in each command file
  • Evidence: CI coverage report on PR

Scope / Risk

  • Main risk or tradeoff: /dream's writeDreamManualRun is fire-and-forget in ACP mode — if it fails silently, auto-dream scheduler may not know a manual dream ran (acceptable for dedup timing)
  • Not covered / not validated: E2E integration test with a running daemon + web-shell client invoking these commands via HTTP
  • Breaking changes / migration notes: None — additive change only

Testing Matrix

🍏 🪟 🐧
npm run ⚠️ ⚠️
npx N/A N/A N/A
Docker N/A N/A N/A
Podman N/A N/A N/A
Seatbelt N/A N/A N/A

Testing matrix notes:

  • Only unit tests involved; no platform-specific behavior in this change

Linked Issues / Bugs

Refs #4514

Re-targeting of #4811 (incorrectly merged to main and reverted). Same code, correct base branch (daemon_mode_b_main).

🤖 Generated with Qwen Code

doudouOUC added 3 commits June 6, 2026 09:34
These three memory-related slash commands return `submit_prompt` or
`message` action types which are fully supported by the ACP session
handler. Adding `acp` to their `supportedModes` allows web-shell
clients to invoke them via `POST /session/:id/prompt` passthrough.

Changes:
- /remember: add supportedModes (zero handler changes needed)
- /forget: add supportedModes + wrap memory manager calls in try-catch
  so filesystem/model errors surface as user-friendly messages instead
  of raw JSON-RPC errors
- /dream: add supportedModes + document that onComplete callback
  (dream metadata tracking) is not invoked in ACP mode

Known limitation: /dream's onComplete (writeDreamManualRun) is silently
skipped in ACP — the auto-dream scheduler may not know a manual dream
already ran. Accepted because eagerly calling it would record completion
before consolidation actually finishes.

Refs #4514
…ertions

- Call writeDreamManualRun eagerly before returning submit_prompt so
  auto-dream dedup works correctly in ACP mode (timestamp is slightly
  early but acceptable for scheduler min_hours check)
- Switch supportedModes test assertions from toContain to toEqual per
  codebase convention (catches accidental mode additions)

Refs #4514
- dreamCommand: add try-catch for error resilience in ACP; make eager
  writeDreamManualRun conditional on executionMode === 'acp' to avoid
  double-write in interactive mode and cancel-semantics regression
- rememberCommand: add explicit if (!config) guard (consistency with
  dream/forget; avoids silent fallthrough in ACP)
- Add config:null test for rememberCommand
- Split dream test into interactive (no eager write) vs ACP (eager write)

Refs #4514
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

@/tmp/stage-1.md

@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

📋 Review Summary

This PR enables /remember, /forget, and /dream slash commands in ACP (web-shell) mode by adding supportedModes: ['interactive', 'acp'] declarations and improving error handling. The changes are well-tested with comprehensive unit tests covering both success and error paths. Overall, this is a solid, focused PR that addresses the mode-filtering gap identified in the original issue.

🔍 General Feedback

  • Positive: The PR correctly identifies and fixes the root cause—commands were excluded from ACP mode due to missing supportedModes declarations rather than any fundamental incompatibility.
  • Positive: Error handling improvements (try-catch wrappers) make these commands more robust in both interactive and ACP modes.
  • Positive: Test coverage is comprehensive, including mode-specific behavior tests and error scenarios.
  • Pattern: The try-catch pattern applied to /forget and /dream handlers is consistent and follows established error-handling conventions in the codebase.
  • Design: The conditional writeDreamManualRun logic based on executionMode is a thoughtful solution to avoid double-writing in interactive mode while ensuring ACP mode records metadata eagerly.

🎯 Specific Feedback

🟢 Medium

  • File: dreamCommand.ts:48-52 - The inner try-catch around recordDream() in ACP mode silently swallows all errors with only a comment. While the intent (best-effort recording) is valid, consider adding debug logging so failures can be diagnosed in production:

    } catch (error) {
      // Best-effort: dream dedup recording must not block prompt submission.
      // TODO: Add debug logging when logger is available in this context
    }
  • File: rememberCommand.ts:34-40 - The explicit if (!config) guard is marked as "for consistency" in the PR description, but this is actually a correctness fix. The original code used optional chaining (config?.getManagedAutoMemoryEnabled()) which would return false when config is null, potentially causing a crash on config.getProjectRoot(). This change is correct and should be highlighted as a bug fix, not just consistency.

🔵 Low

  • File: dreamCommand.test.ts:27 - The test "submits a consolidation prompt in interactive mode without eager metadata write" verifies writeDreamManualRun is not called, but doesn't explicitly verify that onComplete is the function that would call it. Consider adding a test that invokes result.onComplete?.() and asserts writeDreamManualRun is called after.

  • File: forgetCommand.ts:58 - The error message template uses {{message}} interpolation, but the i18n key 'Failed to process /forget: {{message}}' may not exist in translation files yet. Verify that this key is added to the i18n resource files or use a fallback pattern.

  • File: dreamCommand.ts:62 - Same i18n concern as above for 'Failed to process /dream: {{message}}'.

  • File: dreamCommand.ts:20 - The action function signature doesn't explicitly type the context parameter. For consistency with rememberCommand.ts:23, consider adding the type annotation:

    action: async (context: CommandContext) => {

✅ Highlights

  • Test Coverage: The new test cases for ACP mode behavior (dreamCommand.test.ts:63-87) are excellent—they verify the eager vs. deferred writeDreamManualRun behavior based on execution mode.
  • Error Handling: The try-catch wrappers in /forget and /dream prevent raw JSON-RPC errors from leaking to users, improving UX significantly.
  • Focused Scope: This PR stays tightly focused on enabling ACP mode support without introducing unrelated changes or abstractions.
  • Re-targeting: Properly re-targeting the PR from the incorrect main branch to daemon_mode_b_main shows good attention to merge strategy.

@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.

PR description doesn't follow the pull request template — see my comment above for details. Please update the description to match the template structure.

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 enables the /remember, /forget, and /dream slash commands to run in ACP (web-shell) mode by explicitly declaring ACP support, and improves UX in ACP by converting thrown errors into clearer, user-facing command error messages.

Changes:

  • Allow /remember, /forget, /dream to be discoverable/executable in ACP mode via supportedModes: ['interactive', 'acp'].
  • Add defensive error handling in /forget and /dream so failures are surfaced as readable command errors.
  • Adjust /dream bookkeeping to record manual dream runs eagerly in ACP (where onComplete is not invoked), and add targeted unit tests for these behaviors.

Reviewed changes

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

Show a summary per file
File Description
packages/cli/src/ui/commands/rememberCommand.ts Adds ACP support and a consistent !config guard; keeps managed/non-managed memory flows.
packages/cli/src/ui/commands/rememberCommand.test.ts Adds coverage for argument validation, missing config, managed vs non-managed behavior, and ACP support declaration.
packages/cli/src/ui/commands/forgetCommand.ts Adds ACP support and wraps memory-manager operations in try/catch to return user-friendly failures.
packages/cli/src/ui/commands/forgetCommand.test.ts Adds coverage for argument validation, missing config, success/fallback, error handling, and ACP support declaration.
packages/cli/src/ui/commands/dreamCommand.ts Adds ACP support, wraps prompt construction in try/catch, and records dream metadata eagerly in ACP.
packages/cli/src/ui/commands/dreamCommand.test.ts Extends coverage for ACP support declaration, missing config, interactive vs ACP metadata write behavior.

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

Comment thread packages/cli/src/ui/commands/dreamCommand.ts Outdated
Without argumentHint, ACP clients advertise these commands as taking no
input, so users can't provide the required text argument.

Refs #4514
Comment thread packages/cli/src/ui/commands/dreamCommand.ts
Comment thread packages/cli/src/ui/commands/dreamCommand.test.ts

@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.

Incremental review at 843b82d — new commit adds argumentHint to /remember and /forget for the ACP command palette. Clean, safe additions. ✅

Previous round suggestions (fire-and-forget observability, test coverage) at 7940f31 remain unresolved and visible in the thread above.

— qwen3.7-max via Qwen Code /review

…n test

- ACP mode returns without onComplete (eliminates double-execution risk
  if someone later propagates onComplete in handleCommandResult)
- Add test for writeDreamManualRun rejection (verifies .catch prevents
  unhandled promise rejection)
- Add return value + no-onComplete assertions to ACP test

Refs #4514
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Review response round 3 — 6221642

Comment Action Detail
dreamCommand.ts:50 — fire-and-forget concerns + double-execution risk Fixed Split ACP/interactive return paths; ACP returns without onComplete
dreamCommand.test.ts:83 — missing rejection test + return assertion Fixed Added rejection test + return value + no-onComplete assertions

@wenshao

wenshao commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator

✅ Local Verification Report — PR #4819

feat(cli): enable /remember, /forget, /dream in ACP mode

Environment

  • macOS Darwin 25.4.0, Node.js v22.17.0, npm workspaces monorepo
  • Branch: feat/slash-commands-acp-mode-v2daemon_mode_b_main
  • Verified commits up to: 6221642 (split ACP/interactive return paths in dreamCommand)

Build Verification

Step Result
npm run build (full monorepo) ✅ PASS (EXIT_CODE=0)
tsc --build (type-check) ✅ PASS (EXIT_CODE=0, errors are pre-existing stale .d.ts refs)

Test Results

Suite Result Details
dreamCommand.test.ts ✅ 6/6 passed ACP mode, interactive mode, rejection, supportedModes
forgetCommand.test.ts ✅ 5/5 passed Empty arg, null config, success, no-match, error handling, supportedModes
rememberCommand.test.ts ✅ 5/5 passed Empty arg, null config, managed memory, QWEN.md fallback, supportedModes
CLI full suite ✅ PASS 7 failures all pre-existing (see below)

Pre-existing Failures (NOT introduced by this PR)

Test File Failures Cause
acpAgent.test.ts 2 Workspace snapshot shape mismatch (DaemonWorkspaceService, PR #4563 scope)
userStartupWarnings.test.ts 1 Directory check error handling (unrelated)
useGeminiStream.test.tsx 1 handleFinishedEvent message assertion (unrelated)
*.test.js duplicates 3 Stale compiled .js files picked up by vitest glob (local env artifact)

None of the failing tests are in files modified by this PR.

Review Issues — All Addressed

Issue Fix Commit
Fire-and-forget recordDream() to avoid blocking prompt 7940f31
Add argumentHint to /remember and /forget for ACP palette 843b82d
Split ACP/interactive return paths in dreamCommand + rejection test 6221642

Code Review Summary

  • dreamCommand.ts: Clean separation — ACP mode uses fire-and-forget recordDream().catch(() => {}) returning submit_prompt without onComplete; interactive mode defers to onComplete callback. Error boundary wraps entire action.
  • forgetCommand.ts: Added supportedModes, argumentHint, and try/catch error handling. No behavioral changes to the forget logic itself.
  • rememberCommand.ts: Added supportedModes, argumentHint, and config null guard. Simplified managed-memory path by removing unnecessary conditional.
  • All 3 commands declare supportedModes: ['interactive', 'acp'] and tests verify this.

Verdict

✅ PASS — All 16 command tests pass, no regressions introduced, review feedback addressed across 3 fix commits.


Verified by wenshao

content: prompt,
onComplete: recordDream,
};
} catch (error) {

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.

[Suggestion] The catch branch (lines 57–65) added by this PR has no test coverage. The existing ACP error test (dreamCommand.test.ts:91) mocks writeDreamManualRun to reject, but that promise runs outside this try/catch via the detached .catch(() => {}) — so it never exercises this catch block. A synchronous throw from buildConsolidationPrompt (e.g., corrupted memory index) or any of the Storage/getAutoMemoryRoot calls would hit this path with zero test verification.

Suggested change
} catch (error) {
} catch (error) {
return {
type: 'message',
messageType: 'error',
content: t('Failed to process /dream: {{message}}', {
message: error instanceof Error ? error.message : String(error),
}),
};
}
},
};

Suggested test:

it('returns error when buildConsolidationPrompt throws', async () => {
  const context = createMockCommandContext({
    services: {
      config: {
        getProjectRoot: vi.fn().mockReturnValue(path.join('tmp', 'p')),
        getMemoryManager: vi.fn().mockReturnValue({
          buildConsolidationPrompt: vi.fn().mockImplementation(() => {
            throw new Error('corrupted memory index');
          }),
        }),
        getSessionId: vi.fn().mockReturnValue('session-1'),
      },
    },
  });
  const result = await dreamCommand.action?.(context, '');
  expect(result).toEqual({
    type: 'message',
    messageType: 'error',
    content: expect.stringContaining('corrupted memory index'),
  });
});

— qwen3.7-max via Qwen Code /review

const result = rememberCommand.action?.(context, 'user prefers dark mode');
expect(result).toMatchObject({
type: 'submit_prompt',
content: expect.stringContaining('user prefers dark mode'),

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.

[Suggestion] The managed-memory test only verifies the user fact ('user prefers dark mode') appears in the prompt, but does not verify the dirHint — the memory directory path from getAutoMemoryRoot() that is the key behavioral difference between the managed-memory and QWEN.md-fallback paths. A bug that drops dirHint from the prompt would pass this test.

Suggested change
content: expect.stringContaining('user prefers dark mode'),
const result = rememberCommand.action?.(context, 'user prefers dark mode');
expect(result).toMatchObject({
type: 'submit_prompt',
content: expect.stringMatching(/user prefers dark mode.*\.qwen\/memory|\.qwen\/memory.*user prefers dark mode/s),
});

Or split into two assertions:

expect(result).toMatchObject({
  type: 'submit_prompt',
  content: expect.stringContaining('user prefers dark mode'),
});
expect((result as any).content).toContain('.qwen/memory');

— qwen3.7-max via Qwen Code /review

@yiliang114 yiliang114 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

@doudouOUC doudouOUC enabled auto-merge (squash) June 6, 2026 09:57
@doudouOUC doudouOUC dismissed qwen-code-ci-bot’s stale review June 6, 2026 09:59

Alreay have 2 approve.3ks

@doudouOUC doudouOUC merged commit 15794aa into daemon_mode_b_main Jun 6, 2026
9 checks passed
@doudouOUC doudouOUC deleted the feat/slash-commands-acp-mode-v2 branch June 6, 2026 09:59
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.

5 participants