Skip to content

feat: acp model select#1366

Merged
zerob13 merged 5 commits intodevfrom
codex/acp-model_select
Mar 20, 2026
Merged

feat: acp model select#1366
zerob13 merged 5 commits intodevfrom
codex/acp-model_select

Conversation

@zerob13
Copy link
Collaborator

@zerob13 zerob13 commented Mar 20, 2026

Summary by CodeRabbit

  • New Features

    • Chat status bar now shows ACP session configuration options inline (limited) and in an advanced settings popover; session-level config can be read and updated once a draft is ready.
    • Renderer listens for a config-ready event to switch from process to session settings smoothly.
  • Improvements

    • Unified process/session config caching and warmer startup flow for more reliable ACP state.
    • Updated ACP protocol integration for improved compatibility.
  • Tests

    • Added coverage for ACP config flows and renderer behavior.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

This PR introduces ACP Session Config Options—a feature for managing configuration state across ACP agent processes and sessions. It upgrades the SDK dependency (0.5.1 → 0.16.1), adds config state normalization utilities, extends process and session managers to track and synchronize config state, introduces presenter APIs for reading/writing session options, updates the renderer to display inline config controls and a settings panel, and emits a new SESSION_CONFIG_OPTIONS_READY event. Config state is separated into process-level (warmup) and session-level caches with fallback logic.

Changes

Cohort / File(s) Summary
Documentation
docs/specs/acp-session-config-options/plan.md, docs/specs/acp-session-config-options/spec.md, docs/specs/acp-session-config-options/tasks.md
New specification, implementation plan, and task checklist documenting ACP Session Config Options design, phased rollout, UI behavior, and test coverage requirements.
SDK Dependency
package.json
Updated @agentclientprotocol/sdk from ^0.5.1 to ^0.16.1; temporary reordering of dev dependencies with no net version change.
Core Events
src/main/events.ts, src/renderer/src/events.ts
Added new workspace event ACP_WORKSPACE_EVENTS.SESSION_CONFIG_OPTIONS_READY ('acp-workspace:session-config-options-ready') and formatting adjustment to SESSION_COMMANDS_READY.
ACP Config State Utilities
src/main/presenter/agentPresenter/acp/acpConfigState.ts
New module providing config state creation, normalization (from SDK configOptions or legacy models/modes), lookup, and update utilities; includes helpers for deriving mode state and normalizing option shapes.
ACP Schema Import Paths
src/main/presenter/agentPresenter/acp/acpCapabilities.ts, src/main/presenter/agentPresenter/acp/acpContentMapper.ts, src/main/presenter/agentPresenter/acp/acpFsHandler.ts, src/main/presenter/agentPresenter/acp/acpMessageFormatter.ts, src/main/presenter/agentPresenter/acp/acpTerminalManager.ts, src/main/presenter/agentPresenter/acp/mcpConfigConverter.ts, src/main/presenter/agentPresenter/acp/mcpTransportFilter.ts, test/main/presenter/acpMcpPassthrough.test.ts
Updated schema type import path from @agentclientprotocol/sdk/dist/schema.js to @agentclientprotocol/sdk/dist/schema/index.js across ACP modules.
ACP Process Manager
src/main/presenter/agentPresenter/acp/acpProcessManager.ts
Extended AcpProcessHandle with configState; replaced mode-fetching logic with config-state fetching; added caches for config state and mode snapshots; introduced updateBoundProcessConfigState() and getProcessConfigState() APIs; enhanced renderer notifications with config-ready events; updated warmup to normalize config from SDK and seed handles.
ACP Session Manager
src/main/presenter/agentPresenter/acp/acpSessionManager.ts
Extended AcpSessionRecord with configState; refactored session initialization to normalize and persist config state; updated mode-setting to synchronize config state back to process handle.
ACP Provider & Index
src/main/presenter/agentPresenter/acp/index.ts, src/main/presenter/llmProviderPresenter/providers/acpProvider.ts
Added compatibility wrapper setSessionModelCompat; introduced handleSessionUpdate() config state persistence and readiness emission; added getProcessConfigOptions() and session-scoped getSessionConfigOptions()/setSessionConfigOption() methods; loosened workdir parameter from required to optional; updated mode-setting flow to delegate to config-option write when applicable. Re-exported new config state utilities.
LLM Provider Presenter
src/main/presenter/llmProviderPresenter/index.ts
Made workdir optional in warmupAcpProcess() and getAcpProcessModes(); added new methods getAcpProcessConfigOptions(), getAcpSessionConfigOptions(), and setAcpSessionConfigOption() returning/throwing based on provider availability.
New Agent Presenter
src/main/presenter/newAgentPresenter/index.ts
Added ACP config option APIs: getAcpSessionConfigOptions() and setAcpSessionConfigOption(); refactored ACP eligibility checks with shared isAcpBackedSession() helper.
Session Presenter
src/main/presenter/sessionPresenter/index.ts
Made workdir optional in warmupAcpProcess() and getAcpProcessModes().
Presenter Type Definitions
src/shared/types/presenters/llmprovider.presenter.d.ts, src/shared/types/presenters/legacy.presenters.d.ts, src/shared/types/presenters/new-agent.presenter.d.ts, src/shared/types/presenters/session.presenter.d.ts, src/shared/types/presenters/index.d.ts
Added AcpConfigOptionValue, AcpConfigOption, AcpConfigState type definitions; made workdir optional across process/mode methods; added new session-scoped config read/write signatures.
Renderer Component
src/renderer/src/components/chat/ChatStatusBar.vue
Added ACP-specific UI: model badge, inline config option popovers (up to 3 select-type options), and gear popover for remaining options; introduced acpConfigState cache and async loading/updating logic; wired SESSION_CONFIG_OPTIONS_READY IPC listener; added acpDraftSessionId prop; gated model popover when ACP active/draft session exists; hid permission-mode dropdown for ACP.
Renderer Page
src/renderer/src/pages/NewThreadPage.vue
Passed acpDraftSessionId prop to ChatStatusBar.
Main Tests
test/main/presenter/acpProvider.test.ts, test/main/presenter/agentPresenter/acp/acpProcessManager.test.ts, test/main/presenter/llmProviderPresenter/acpContentMapper.test.ts
Added config state fixture helpers; extended prepareSession setup and assertions for config-ready emission; added coverage for getProcessConfigOptions(), setSessionConfigOption() flows; added cache-fallback tests for config/mode retrieval; updated content mapper tests for config_option_update handling.
Renderer Tests
test/main/presenter/newAgentPresenter/newAgentPresenter.test.ts, test/renderer/components/ChatStatusBar.test.ts
Extended mocks for LLM provider config methods and new environment tables; added ACP session config option test cases; significantly expanded ChatStatusBar tests covering ACP badge rendering, inline config warmup, cache isolation, overflow behavior, and session-level option updates.

Sequence Diagram(s)

sequenceDiagram
    participant Renderer as Renderer<br/>(ChatStatusBar)
    participant Presenter as Presenter<br/>(LLMProviderPresenter)
    participant ProcMgr as ProcessManager
    participant Provider as ACP Provider
    participant SDK as ACP SDK<br/>(Agent)
    
    Note over Renderer,SDK: Process Warmup & Config State Initialization
    
    Renderer->>Presenter: warmupAcpProcess(agentId, workdir?)
    Presenter->>Provider: warmupProcess(agentId, workdir?)
    Provider->>SDK: initialize() / connect
    SDK-->>Provider: configOptions, models, modes
    Provider->>ProcMgr: Handle creation with configState
    ProcMgr->>ProcMgr: normalizeAcpConfigState(configOptions)
    ProcMgr->>ProcMgr: cache configState by agent
    ProcMgr-->>Provider: handle.configState populated
    Provider-->>Presenter: warmup complete
    Presenter-->>Renderer: warmup done
    
    Renderer->>Presenter: getAcpProcessConfigOptions(agentId, workdir?)
    Presenter->>ProcMgr: getProcessConfigState(agentId, workdir?)
    ProcMgr-->>Presenter: cached configState
    Presenter-->>Renderer: configState displayed
Loading
sequenceDiagram
    participant Renderer as Renderer<br/>(ChatStatusBar)
    participant NewAgent as NewAgentPresenter
    participant Presenter as LLMProviderPresenter
    participant Provider as ACP Provider
    participant SessMgr as SessionManager
    participant SDK as ACP SDK<br/>(Session)
    
    Note over Renderer,SDK: Session Creation & Config State Binding
    
    Renderer->>NewAgent: setAcpSessionConfigOption(sessionId, configId, value)
    NewAgent->>Presenter: setAcpSessionConfigOption(conversationId, configId, value)
    Presenter->>Provider: setSessionConfigOption(conversationId, configId, value)
    Provider->>SessMgr: session lookup
    SessMgr->>SDK: connection.setSessionConfigOption({configId, value})
    SDK-->>SessMgr: response with updated configOptions
    SessMgr->>SessMgr: normalizeAcpConfigState(configOptions)
    SessMgr->>SessMgr: session.configState = normalized
    SessMgr->>SessMgr: update process.configState from session
    SessMgr-->>Provider: session updated
    Provider->>Provider: emit SESSION_CONFIG_OPTIONS_READY
    Provider-->>Presenter: configState (normalized response)
    Presenter-->>NewAgent: configState
    NewAgent-->>Renderer: updated configState displayed
Loading
sequenceDiagram
    participant SDK as ACP SDK<br/>(Agent)
    participant Provider as ACP Provider
    participant ProcMgr as ProcessManager
    participant EventBus as EventBus
    participant Renderer as Renderer<br/>(ChatStatusBar)
    
    Note over SDK,Renderer: Config Option Update via Protocol
    
    SDK->>Provider: emit sessionUpdate<br/>(config_option_update)
    Provider->>Provider: mapper.map(sessionUpdate)
    Provider->>Provider: handleConfigOptionUpdate()<br/>normalizeAcpConfigState()
    Provider->>Provider: mapped.configState set
    Provider->>ProcMgr: updateBoundProcessConfigState(configState)
    ProcMgr->>ProcMgr: handle.configState = updated
    ProcMgr->>EventBus: sendToRenderer<br/>(SESSION_CONFIG_OPTIONS_READY)
    EventBus-->>Renderer: IPC event payload
    Renderer->>Renderer: acpConfigState = payload.configState
    Renderer->>Renderer: UI re-renders with new values
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 Hops along with config cheer
Config state is crystal clear!
Sessions sip from warmup's brew,
Options flow both tried and true.
Ready signals bloom and shine—
ACP paths now intertwine! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'feat: acp model select' is vague and does not clearly convey the scope of changes, which include session config options, configuration state management, and substantial renderer UI updates beyond just model selection. Consider a more specific title like 'feat: ACP session config options' or 'feat: unified ACP configuration management' to better reflect the comprehensive nature of the implementation.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/acp-model_select
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@zerob13 zerob13 marked this pull request as ready for review March 20, 2026 04:30
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: db913616ab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/presenter/agentPresenter/acp/acpSessionManager.ts (1)

423-437: ⚠️ Potential issue | 🔴 Critical

Don’t overwrite the server-reported mode before the session RPC runs.

Lines 423-437 replace the response/default mode with handle.currentModeId and immediately write that into configState. createSession() later uses currentModeId !== session.currentModeId to decide whether it still needs to call setSessionMode(), so this makes the comparison false and the RPC is skipped. The ACP session can stay on the old mode while local state says the preferred mode is active.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/presenter/agentPresenter/acp/acpSessionManager.ts` around lines 423
- 437, The code is prematurely persisting the local preferred mode
(handle.currentModeId) into configState, which prevents createSession() from
detecting a mode change and calling setSessionMode(); instead, compute
currentModeId for UI selection only (using handle.currentModeId as
preferredMode) but do not call updateAcpConfigStateValue with the preferred
mode. Only update configState when the server/response/default mode
(responseModeId or availableModes fallback) is chosen or after the session RPC
confirms the mode change; keep handle.currentModeId (or a new preferredMode
variable) separate from the value written via updateAcpConfigStateValue, and
reference getAcpConfigOptionByCategory and updateAcpConfigStateValue when
updating configState only with the server/response-determined mode.
🧹 Nitpick comments (2)
src/main/presenter/newAgentPresenter/index.ts (1)

1117-1128: Consider reusing isAcpBackedSession in other ACP checks to avoid logic drift.
You now have a solid central predicate; applying it in other provider-detection branches (e.g., message/delete paths) would reduce duplication and future divergence risk.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/presenter/newAgentPresenter/index.ts` around lines 1117 - 1128,
Centralize provider-detection by replacing duplicated ACP-check logic in other
code paths (e.g., message/delete handlers) with calls to the existing
isAcpBackedSession(sessionId, agentId). Locate places where code re-fetches
agent state or queries configPresenter.getAcpAgents() to infer providerId and
instead call this.isAcpBackedSession(sessionId, agentId) (after resolving the
same agentId/ sessionId inputs there); ensure those branches remove their local
providerId derivation and use the boolean result to decide ACP-specific behavior
so all ACP-detection uses the single predicate isAcpBackedSession.
src/main/presenter/llmProviderPresenter/providers/acpProvider.ts (1)

929-945: Avoid double-emitting SESSION_CONFIG_OPTIONS_READY.

updateBoundProcessConfigState() and updateBoundProcessMode() already notify the renderer in acpProcessManager.ts. Re-emitting here sends the same bound-session payload twice, which doubles IPC traffic and renderer refreshes for every config change. Keep a single emitter on the bound-session update path.

Also applies to: 1289-1294, 1434-1449

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/presenter/llmProviderPresenter/providers/acpProvider.ts` around
lines 929 - 945, The code is double-emitting SESSION_CONFIG_OPTIONS_READY from
acpProvider.ts after calling this.processManager.updateBoundProcessConfigState
and updateBoundProcessMode; remove the local calls to
emitSessionConfigOptionsReady (the ones immediately after
updateBoundProcessConfigState/updateBoundProcessMode) so only the notifications
originating from acpProcessManager.ts/processManager are sent; update the three
occurrences referenced (around the blocks calling updateBoundProcessConfigState
and updateBoundProcessMode at the shown ranges) to rely on the processManager's
own emitter and keep the warning/log behavior but delete the duplicate
emitSessionConfigOptionsReady calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/presenter/agentPresenter/acp/acpProcessManager.ts`:
- Around line 1114-1133: syncAgentCache currently keys caches by agentId only
which allows cross-workspace leakage; update it to use the same workspace-scoped
key used by warmups (e.g., `${handle.agentId}::${handle.workdir}` or similar)
when reading/writing latestConfigStates and latestModeSnapshots so
getProcessModes()/getProcessConfigState() return workspace-correct data, and
when both availableModes and currentModeId are empty remove (delete) the
corresponding entry from latestModeSnapshots to avoid returning stale fallback
snapshots; adjust any references in syncAgentCache, latestConfigStates, and
latestModeSnapshots to use that compound key.

In `@src/main/presenter/agentPresenter/acp/acpSessionManager.ts`:
- Around line 356-357: The code currently blindly replaces handle.configState
with normalizeAcpConfigState(...) and clears the warmup cache even when
loadSession()/newSession() return no config payload, which wipes warmup-only ACP
options; change the logic in acpSessionManager so after calling
normalizeAcpConfigState(...) you only assign to handle.configState (and clear
the warmup cache) if the normalized result contains actual config data (e.g.,
non-empty models, modes, or configOptions) — otherwise keep the existing
handle.configState and do not clear the warmup cache; use comparisons against
createEmptyAcpConfigState('legacy') or an explicit hasAnyConfig check to decide
whether to overwrite, and apply this guard wherever normalizeAcpConfigState(...)
is used (references: handle.configState, createEmptyAcpConfigState,
normalizeAcpConfigState, loadSession, newSession, warmup cache handling).

In `@src/main/presenter/llmProviderPresenter/providers/acpProvider.ts`:
- Around line 1398-1413: The current code replaces the entire session snapshot
by calling normalizeAcpConfigState({ configOptions: response.configOptions }),
which discards legacy sections like models/modes; instead, merge
response.configOptions into the existing session.configState prior to
normalizing so legacy entries are preserved. Update the block around
session.connection.setSessionConfigOption (the code that sets response and
computes nextConfigState) to compute a mergedConfigOptions = {
...session.configState.configOptions, ...response.configOptions } (or otherwise
merge deep if needed) and then call normalizeAcpConfigState({ configOptions:
mergedConfigOptions }) (or pass the merged snapshot) and assign that to
nextConfigState so you don't drop previously synthesized models/modes.

In `@src/renderer/src/components/chat/ChatStatusBar.vue`:
- Around line 802-803: The panel is becoming writable as soon as
activeAcpSessionId is non-null while acpConfigState still holds the previous
session snapshot; update the readiness check and fetch flow so writes are
blocked until the session-scoped config finishes loading. Concretely, change the
computed acpConfigReadOnly to also require a "config loaded" condition (e.g., a
new acpConfigLoaded ref or compare acpConfigState.sessionId ===
activeAcpSessionId.value), set acpConfigLoaded = false (or clear acpConfigState)
immediately when activeAcpSessionId changes, then set acpConfigLoaded = true
only after getAcpSessionConfigOptions() resolves and updates acpConfigState;
ensure any submit logic checks the same loaded flag before allowing writes.
- Around line 761-799: The cache currently keys ACP config by agent only
(acpConfigCacheByAgent via acpConfigCacheKey) causing cross-workspace leaks;
change the cache key to include workspace (use acpWorkspacePath) so keys are
like `${agentId}::${workspace}` (update acpConfigCacheKey/acpConfigRequestKey
logic accordingly), update getCachedAcpConfigState and setCachedAcpConfigState
to accept/compute the combined agent+workspace key (or a single requestKey) and
store/lookup from acpConfigCacheByAgent using that composite key, and finally
update the SESSION_CONFIG_OPTIONS_READY event handler to verify the
workspace/workdir matches the cached requestKey before accepting/applying the
config to avoid applying a config warmed for a different folder.

---

Outside diff comments:
In `@src/main/presenter/agentPresenter/acp/acpSessionManager.ts`:
- Around line 423-437: The code is prematurely persisting the local preferred
mode (handle.currentModeId) into configState, which prevents createSession()
from detecting a mode change and calling setSessionMode(); instead, compute
currentModeId for UI selection only (using handle.currentModeId as
preferredMode) but do not call updateAcpConfigStateValue with the preferred
mode. Only update configState when the server/response/default mode
(responseModeId or availableModes fallback) is chosen or after the session RPC
confirms the mode change; keep handle.currentModeId (or a new preferredMode
variable) separate from the value written via updateAcpConfigStateValue, and
reference getAcpConfigOptionByCategory and updateAcpConfigStateValue when
updating configState only with the server/response-determined mode.

---

Nitpick comments:
In `@src/main/presenter/llmProviderPresenter/providers/acpProvider.ts`:
- Around line 929-945: The code is double-emitting SESSION_CONFIG_OPTIONS_READY
from acpProvider.ts after calling
this.processManager.updateBoundProcessConfigState and updateBoundProcessMode;
remove the local calls to emitSessionConfigOptionsReady (the ones immediately
after updateBoundProcessConfigState/updateBoundProcessMode) so only the
notifications originating from acpProcessManager.ts/processManager are sent;
update the three occurrences referenced (around the blocks calling
updateBoundProcessConfigState and updateBoundProcessMode at the shown ranges) to
rely on the processManager's own emitter and keep the warning/log behavior but
delete the duplicate emitSessionConfigOptionsReady calls.

In `@src/main/presenter/newAgentPresenter/index.ts`:
- Around line 1117-1128: Centralize provider-detection by replacing duplicated
ACP-check logic in other code paths (e.g., message/delete handlers) with calls
to the existing isAcpBackedSession(sessionId, agentId). Locate places where code
re-fetches agent state or queries configPresenter.getAcpAgents() to infer
providerId and instead call this.isAcpBackedSession(sessionId, agentId) (after
resolving the same agentId/ sessionId inputs there); ensure those branches
remove their local providerId derivation and use the boolean result to decide
ACP-specific behavior so all ACP-detection uses the single predicate
isAcpBackedSession.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e934f42f-67ff-4652-812d-bea1b7bf6484

📥 Commits

Reviewing files that changed from the base of the PR and between ed5ccf4 and db91361.

📒 Files selected for processing (34)
  • docs/specs/acp-session-config-options/plan.md
  • docs/specs/acp-session-config-options/spec.md
  • docs/specs/acp-session-config-options/tasks.md
  • package.json
  • src/main/events.ts
  • src/main/presenter/agentPresenter/acp/acpCapabilities.ts
  • src/main/presenter/agentPresenter/acp/acpConfigState.ts
  • src/main/presenter/agentPresenter/acp/acpContentMapper.ts
  • src/main/presenter/agentPresenter/acp/acpFsHandler.ts
  • src/main/presenter/agentPresenter/acp/acpMessageFormatter.ts
  • src/main/presenter/agentPresenter/acp/acpProcessManager.ts
  • src/main/presenter/agentPresenter/acp/acpSessionManager.ts
  • src/main/presenter/agentPresenter/acp/acpTerminalManager.ts
  • src/main/presenter/agentPresenter/acp/index.ts
  • src/main/presenter/agentPresenter/acp/mcpConfigConverter.ts
  • src/main/presenter/agentPresenter/acp/mcpTransportFilter.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/main/presenter/llmProviderPresenter/providers/acpProvider.ts
  • src/main/presenter/newAgentPresenter/index.ts
  • src/main/presenter/sessionPresenter/index.ts
  • src/renderer/src/components/chat/ChatStatusBar.vue
  • src/renderer/src/events.ts
  • src/renderer/src/pages/NewThreadPage.vue
  • src/shared/types/presenters/index.d.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
  • src/shared/types/presenters/llmprovider.presenter.d.ts
  • src/shared/types/presenters/new-agent.presenter.d.ts
  • src/shared/types/presenters/session.presenter.d.ts
  • test/main/presenter/acpMcpPassthrough.test.ts
  • test/main/presenter/acpProvider.test.ts
  • test/main/presenter/agentPresenter/acp/acpProcessManager.test.ts
  • test/main/presenter/llmProviderPresenter/acpContentMapper.test.ts
  • test/main/presenter/newAgentPresenter/newAgentPresenter.test.ts
  • test/renderer/components/ChatStatusBar.test.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/presenter/agentPresenter/acp/acpSessionManager.ts (1)

430-444: ⚠️ Potential issue | 🟠 Major

Don't collapse the preferred mode and the session's actual mode during initialization.

Lines 430-444 seed currentModeId from handle.currentModeId, write that value back into configState, and return it as session.currentModeId before the ACP session has actually been switched. When createSession() reaches Line 231, the comparison is already false, so setSessionMode() is skipped and local state can claim the preferred mode is active while the server is still on the response/default mode. Keep the response-reported mode in the returned session state, and only use the warmup preference as the desired mode to apply afterward.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/presenter/agentPresenter/acp/acpSessionManager.ts` around lines 430
- 444, The code is seeding and persisting the preferred mode
(handle.currentModeId) as the session's active mode before the server confirms
the switch; instead, keep the server-reported mode (responseModeId /
responseModeState) as the session's currentModeId during initialization and
treat handle.currentModeId only as the desired/warmup mode to apply later.
Concretely: set currentModeId = responseModeId ?? availableModes?.[0]?.id (do
not default to handle.currentModeId), avoid calling
updateAcpConfigStateValue(configState, modeOption.id, currentModeId) with the
preferred mode during session creation, and only update configState /
session.currentModeId after setSessionMode() succeeds (or when the server
reports the new mode); use a separate variable like desiredMode =
handle.currentModeId to carry the warmup preference until confirmed.
♻️ Duplicate comments (2)
src/main/presenter/agentPresenter/acp/acpConfigState.ts (1)

115-131: ⚠️ Potential issue | 🟠 Major

Don't make configOptions mutually exclusive with legacy models / modes.

The early return on Line 116 drops the synthesized legacy model/mode options whenever a session payload also includes regular configOptions. loadSession() / newSession() can therefore initialize configState without ACP model/mode controls, even though the same response still carries legacy models / modes. Merge the legacy options when those categories are missing instead of returning only the modern branch.

💡 Suggested merge
 export const normalizeAcpConfigState = (input: NormalizableConfigStateInput): AcpConfigState => {
+  const legacyOptions = [buildLegacyModelOption(input.models), buildLegacyModeOption(input.modes)].filter(
+    (option): option is AcpConfigOption => Boolean(option)
+  )
+
   if (input.configOptions !== undefined && input.configOptions !== null) {
+    const options = input.configOptions.map(normalizeConfigOption)
+    const categories = new Set(
+      options.map((option) => option.category).filter((category): category is string => Boolean(category))
+    )
+
     return {
       source: 'configOptions',
-      options: input.configOptions.map(normalizeConfigOption)
+      options: [
+        ...legacyOptions.filter((option) => !option.category || !categories.has(option.category)),
+        ...options
+      ]
     }
   }
 
-  const options = [buildLegacyModelOption(input.models), buildLegacyModeOption(input.modes)].filter(
-    (option): option is AcpConfigOption => Boolean(option)
-  )
+  const options = legacyOptions
 
   return {
     source: 'legacy',
     options
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/presenter/agentPresenter/acp/acpConfigState.ts` around lines 115 -
131, normalizeAcpConfigState currently returns early when input.configOptions
exists, which drops synthesized legacy options built by buildLegacyModelOption
and buildLegacyModeOption and causes ACP model/mode controls to be lost; change
normalizeAcpConfigState to always merge legacy options with normalized
configOptions instead of returning immediately: call
buildLegacyModelOption(input.models) and buildLegacyModeOption(input.modes),
filter and include any resulting AcpConfigOption(s), then append or prepend the
normalized input.configOptions.map(normalizeConfigOption) so the returned
AcpConfigState.options contains both modern and synthesized legacy options
(ensure the function still sets source appropriately, e.g., 'configOptions' when
configOptions present but include legacy options too); update any callers such
as loadSession/newSession if they rely on exclusive behavior.
src/renderer/src/components/chat/ChatStatusBar.vue (1)

762-800: ⚠️ Potential issue | 🟠 Major

Scope the ACP config cache and ready events by request key, not just agent.

acpConfigRequestKey is workspace-aware, but Lines 785-799 still read/write acpConfigCacheByAgent with only agentId, and Lines 1856-1864 still accept any process-level SESSION_CONFIG_OPTIONS_READY for that agent. Reusing the same ACP agent in two folders can therefore hydrate the second workspace with the first workspace's config, or keep stale options after a failed warmup. Use the same composite key/workdir check for cache lookups, writes, and event acceptance.

Also applies to: 1834-1865

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/src/components/chat/ChatStatusBar.vue` around lines 762 - 800,
The ACP cache and event acceptance must be keyed by the composite request key
(acpConfigRequestKey) not just agentId: update getCachedAcpConfigState and
setCachedAcpConfigState to take a requestKey (string|null|undefined) and
read/write acpConfigCacheByAgent using that composite key (use
acpConfigRequestKey.value where caller previously passed activeAcpAgentId), and
update the SESSION_CONFIG_OPTIONS_READY handler(s) (references around lines
~1834-1865) to validate the incoming event's requestKey equals the current
acpConfigRequestKey.value before hydrating or accepting options so
workspace-aware configs aren’t mixed across folders or stale after warmup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/renderer/src/components/chat/ChatStatusBar.vue`:
- Around line 46-66: The UI is rendering raw option IDs (entry.value and
option.currentValue) instead of their human labels; update the template in
ChatStatusBar.vue to display entry.label (and the selected option's label)
wherever values are shown while keeping comparisons and data attributes using
entry.value and option.currentValue; specifically, change the button text from
"{{ entry.value }}" to the label (use entry.label) and ensure any trigger/menu
places that currently render entry.value or option.currentValue use the
corresponding entry.label for display while leaving :data-value,
:data-option-id, disabled checks, class comparisons and the
onAcpSelectOption(option.id, entry.value) call unchanged so behavior still
matches by ID.

---

Outside diff comments:
In `@src/main/presenter/agentPresenter/acp/acpSessionManager.ts`:
- Around line 430-444: The code is seeding and persisting the preferred mode
(handle.currentModeId) as the session's active mode before the server confirms
the switch; instead, keep the server-reported mode (responseModeId /
responseModeState) as the session's currentModeId during initialization and
treat handle.currentModeId only as the desired/warmup mode to apply later.
Concretely: set currentModeId = responseModeId ?? availableModes?.[0]?.id (do
not default to handle.currentModeId), avoid calling
updateAcpConfigStateValue(configState, modeOption.id, currentModeId) with the
preferred mode during session creation, and only update configState /
session.currentModeId after setSessionMode() succeeds (or when the server
reports the new mode); use a separate variable like desiredMode =
handle.currentModeId to carry the warmup preference until confirmed.

---

Duplicate comments:
In `@src/main/presenter/agentPresenter/acp/acpConfigState.ts`:
- Around line 115-131: normalizeAcpConfigState currently returns early when
input.configOptions exists, which drops synthesized legacy options built by
buildLegacyModelOption and buildLegacyModeOption and causes ACP model/mode
controls to be lost; change normalizeAcpConfigState to always merge legacy
options with normalized configOptions instead of returning immediately: call
buildLegacyModelOption(input.models) and buildLegacyModeOption(input.modes),
filter and include any resulting AcpConfigOption(s), then append or prepend the
normalized input.configOptions.map(normalizeConfigOption) so the returned
AcpConfigState.options contains both modern and synthesized legacy options
(ensure the function still sets source appropriately, e.g., 'configOptions' when
configOptions present but include legacy options too); update any callers such
as loadSession/newSession if they rely on exclusive behavior.

In `@src/renderer/src/components/chat/ChatStatusBar.vue`:
- Around line 762-800: The ACP cache and event acceptance must be keyed by the
composite request key (acpConfigRequestKey) not just agentId: update
getCachedAcpConfigState and setCachedAcpConfigState to take a requestKey
(string|null|undefined) and read/write acpConfigCacheByAgent using that
composite key (use acpConfigRequestKey.value where caller previously passed
activeAcpAgentId), and update the SESSION_CONFIG_OPTIONS_READY handler(s)
(references around lines ~1834-1865) to validate the incoming event's requestKey
equals the current acpConfigRequestKey.value before hydrating or accepting
options so workspace-aware configs aren’t mixed across folders or stale after
warmup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ea227e75-7499-4417-91be-b9ea34ac2723

📥 Commits

Reviewing files that changed from the base of the PR and between db91361 and 1d48958.

📒 Files selected for processing (8)
  • src/main/presenter/agentPresenter/acp/acpConfigState.ts
  • src/main/presenter/agentPresenter/acp/acpSessionManager.ts
  • src/main/presenter/agentPresenter/acp/index.ts
  • src/main/presenter/llmProviderPresenter/providers/acpProvider.ts
  • src/renderer/src/components/chat/ChatStatusBar.vue
  • test/main/presenter/acpMcpPassthrough.test.ts
  • test/main/presenter/acpProvider.test.ts
  • test/renderer/components/ChatStatusBar.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/main/presenter/agentPresenter/acp/index.ts
  • test/main/presenter/acpProvider.test.ts
  • test/main/presenter/acpMcpPassthrough.test.ts
  • test/renderer/components/ChatStatusBar.test.ts

@zerob13 zerob13 merged commit 0766d4b into dev Mar 20, 2026
3 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.

1 participant