-
Notifications
You must be signed in to change notification settings - Fork 670
feat(remote-control): improve ACP agent alias resolution and add work… #1694
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # Plan | ||
|
|
||
| ## Implementation Approach | ||
| - Treat `resolveAcpAgentAlias` strictly as an *equivalence-matching* helper. Never let an alias-flattened id leak out as a stored or returned `defaultAgentId`. | ||
| - Rewrite `sanitizeDefaultAgentId` so it locates the matching `enabledAgent` (using alias for equivalence) and returns that agent's **own** id — i.e. the id the renderer's `availableAgents` will contain. | ||
| - Promote `resolveAcpAgentAlias` and `ACP_LEGACY_AGENT_ID_ALIASES` to `src/shared/utils/acpAgentAlias.ts` so renderer code can reuse the exact same alias table that main relies on. `src/main/presenter/configPresenter/acpRegistryConstants.ts` re-exports them to keep all current `import` sites working. | ||
| - Patch `defaultAgentOptions` in `RemoteSettings.vue` to recognise an alias-equivalent agent and use its real id instead of unshifting a bare-id ghost option. | ||
|
|
||
| ## Affected Interfaces | ||
| - `sanitizeDefaultAgentId(channel, candidate)` — internal to `RemoteControlPresenter`. Return type unchanged (`Promise<string>`); semantics tightened to "return one of the SQLite agent ids, or the channel default". | ||
| - New module `src/shared/utils/acpAgentAlias.ts` exporting `ACP_LEGACY_AGENT_ID_ALIASES` and `resolveAcpAgentAlias`. | ||
| - `src/main/presenter/configPresenter/acpRegistryConstants.ts` becomes a thin re-export for the alias pieces; the rest of its constants stay co-located. | ||
|
|
||
| ## Data Flow | ||
| 1. Renderer Select emits real SQLite agent id → `updateXxxDefaultAgentId(value)` writes it into `xxxSettings.value.defaultAgentId`. | ||
| 2. `persistChannelSettings` calls `saveXxxSettings`. Main `sanitizeDefaultAgentId` matches via alias but returns the *real* enabledAgent id and writes that into `bindingStore`. | ||
| 3. `getXxxSettings` returns the same real id. `syncXxxFields(saved)` overwrites the renderer state with the same id the user picked → no flicker. | ||
| 4. For legacy bindings whose stored id is an alias-table key, `sanitizeDefaultAgentId` translates it into the real id during the next get/save, and the renderer's `defaultAgentOptions` resolves it via alias-equivalence so the Select stays bound to the canonical option instead of fabricating a ghost row. | ||
|
|
||
| ## Compatibility | ||
| - All existing `acpRegistryConstants` import sites continue to compile via re-export. | ||
| - Existing alias-equivalent behavior preserved: a candidate that maps via the alias table to an enabled agent is still considered a match. | ||
| - No data migrations. Bindings carrying historical alias-key ids self-heal on first sanitize call. | ||
|
|
||
| ## Test Strategy | ||
| - New main-side unit test: `sanitizeDefaultAgentId` returns the SQLite agent id for (a) exact-match candidate, (b) alias-key candidate against an alias-value agent, and (c) alias-value candidate against an alias-key agent. Falls back to channel default only when no alias-equivalent agent exists. | ||
| - New renderer-side unit test: `defaultAgentOptions` returned to the Select reconciles a legacy `currentAgentId` to the corresponding modern entry without inserting a ghost row. | ||
| - Run `pnpm run typecheck`, `pnpm run lint`, `pnpm run format`, `pnpm run i18n` (no new strings — runs as a no-op confirmation per repo guideline). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # Remote ACP Default Agent Flicker | ||
|
|
||
| ## User Need | ||
| Users who pick an ACP agent in `Settings → Remote → <channel> → Default Agent` must see their selection persist instead of silently flicking back to a non-ACP agent. | ||
|
|
||
| ## Goal | ||
| Stop `RemoteControlPresenter.sanitizeDefaultAgentId` from returning an alias-flattened id that the renderer cannot map back to a real `availableAgents` entry. | ||
|
|
||
| ## Acceptance Criteria | ||
| - Selecting any ACP agent (registry-sourced or manually created) in any of the five remote channel settings (Telegram, Feishu, QQ Bot, Discord, Weixin iLink) keeps the selection after `syncXxxFields(saved)` runs. | ||
| - The persisted `defaultAgentId` always matches an `agent.id` returned by `agentSessionPresenter.getAgents()` (i.e. the SQLite-stored id), never a virtual alias-only id. | ||
| - Legacy bindings whose persisted `defaultAgentId` uses an alias-table key (e.g. `claude-code-acp` from older builds) get reconciled to the matching modern agent on first save/load instead of orphaning the Select control. | ||
| - Renderer falls back to a stable id when the binding refers to an agent that no longer exists, without producing a bare-id "ghost" option. | ||
|
|
||
| ## Constraints | ||
| - No SQLite schema or stored-id migration. Keep `AgentRepository.syncRegistryAgents` / `createManualAcpAgent` insertion ids as-is. | ||
| - No IPC contract changes. `saveXxxSettings` input/output shapes stay the same. | ||
| - Reuse the existing `resolveAcpAgentAlias` helper rather than introducing parallel mapping logic. The helper itself can move to `src/shared/` but its semantics must not change. | ||
|
|
||
| ## Non-Goals | ||
| - Adding inline "ACP requires a project directory" UX hint to the agent picker (separate follow-up). | ||
| - Reworking `agentSessionPresenter.getAgentType` alias handling — that layer is already correct and should not change. | ||
| - Migrating historical agent ids stored in chat sessions or LLM provider configs. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # Tasks | ||
|
|
||
| - [x] Move `ACP_LEGACY_AGENT_ID_ALIASES` and `resolveAcpAgentAlias` into `src/shared/utils/acpAgentAlias.ts`; re-export from `src/main/presenter/configPresenter/acpRegistryConstants.ts`. | ||
| - [x] Rewrite `sanitizeDefaultAgentId` to return the SQLite agent's own id (alias used only for matching). | ||
| - [x] Patch `RemoteSettings.vue` `defaultAgentOptions` to alias-reconcile a legacy `currentAgentId` to the canonical option. | ||
| - [x] Add main-side unit tests covering the four sanitize outcomes (exact / alias-key / alias-value / no-match). | ||
| - [x] Add renderer-side unit test covering `defaultAgentOptions` legacy-id reconciliation. | ||
| - [x] Run formatting, i18n generation, lint, typecheck, and the new tests. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.