Skip to content

perf(agent): refresh acp agents incrementally - #1579

Merged
zerob13 merged 1 commit into
codex/p1-selectable-model-sourcefrom
codex/p3-incremental-agent-refresh
Apr 30, 2026
Merged

perf(agent): refresh acp agents incrementally#1579
zerob13 merged 1 commit into
codex/p1-selectable-model-sourcefrom
codex/p3-incremental-agent-refresh

Conversation

@zhangmo8

@zhangmo8 zhangmo8 commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add a scoped config.listAgents route so the renderer can refresh only the ACP agents that actually changed
  • propagate optional agentIds through the ACP agents changed event for incremental renderer updates
  • switch the agent store from unconditional full refetches to targeted ACP upserts/removals with a full-refresh fallback for unscoped changes

Testing

  • not run (per request)

Summary by CodeRabbit

  • New Features

    • Added ability to query and filter agents by type and specific IDs.
    • Agent change events now include targeted agent identifiers for more precise tracking.
  • Improvements

    • Agent synchronization now responds to configuration changes with targeted updates instead of full list refreshes, improving performance.
    • Enhanced agent selection consistency when agents are removed or disabled.

@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The PR enhances agent change notifications by introducing optional agent ID tracking to enable incremental updates. A new configListAgentsRoute API filters agents by type and IDs. The agent store now syncs selectively when receiving scoped change notifications instead of performing full refreshes.

Changes

Cohort / File(s) Summary
Agent change event system
src/main/presenter/configPresenter/index.ts, src/main/routes/legacyTypedEventBridge.ts, src/shared/contracts/events/config.events.ts
notifyAcpAgentsChanged now accepts optional agentIds, forwarded through the event chain; publishAgentsChanged and the CONFIG_EVENTS.AGENTS_CHANGED listener updated to pass agentIds in event payload.
Config route & contract
src/shared/contracts/routes/config.routes.ts, src/main/routes/configRouteHandler.ts, src/shared/contracts/routes.ts
New configListAgentsRoute contract defined with input schema for agentType and ids filters; route handler implemented to retrieve and filter agents by type and membership; contract added to catalog.
Config client API
src/renderer/api/ConfigClient.ts
New listAgents(input?: { agentType?: 'deepchat' \| 'acp'; ids?: string[] }) method added; onAgentsChanged listener payload updated to include optional agentIds field.
Agent store synchronization
src/renderer/src/stores/ui/agent.ts
Replaced model-change-driven refresh with config-driven agent synchronization; added refreshAgentsByType and refreshAgentsByIds methods for granular updates; helper functions for agent type resolution and selection consistency.
Test coverage
test/renderer/stores/agentStore.test.ts
New test suite verifying incremental agent refresh logic: scoped updates with agentIds, proper filtering, deletion handling, and fallback behavior when change scope is undefined.

Sequence Diagram(s)

sequenceDiagram
    participant Agent Install/Repair Flow
    participant Presenter as Config Presenter
    participant Bridge as Event Bridge
    participant ConfigClient
    participant AgentStore as Agent Store

    Agent Install/Repair Flow->>Presenter: notifyAcpAgentsChanged(agentIds)
    Presenter->>Presenter: Emit CONFIG_EVENTS.AGENTS_CHANGED<br/>with { agentIds }
    Presenter->>Bridge: EVENT_EMITTER (CONFIG_EVENTS.AGENTS_CHANGED)
    Bridge->>ConfigClient: publishAgentsChanged(payload.agentIds)
    ConfigClient->>ConfigClient: Emit onAgentsChanged event<br/>with { agentIds, ... }
    ConfigClient->>AgentStore: listener callback<br/>with agentIds
    
    alt Scoped Change (agentIds provided)
        AgentStore->>ConfigClient: listAgents({ agentType: 'acp', ids: agentIds })
        ConfigClient-->>AgentStore: Filtered agent list
        AgentStore->>AgentStore: Merge/update agents<br/>for specific IDs
    else Full Change (no agentIds)
        AgentStore->>AgentStore: Full agent refresh
    end
    
    AgentStore->>AgentStore: Update store.agents<br/>Sync selectedAgentId
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The changes span multiple interrelated components with mixed complexity: straightforward event payload additions, a new filtering route, and moderate logic additions in the agent store for incremental synchronization. The heterogeneity of edits across the event system, routing layer, and client API demands separate reasoning per file, though no single file contains dense logic.

Poem

🐰 Oh, what joy when agents change with grace!
No longer broadcasts flood the whole place—
Now IDs tell us who's updated here,
The store refreshes, crystal-clear.
Incremental updates, oh what a treat,
Makes the config system complete! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'perf(agent): refresh acp agents incrementally' directly and clearly describes the main objective: implementing incremental refresh for ACP agents instead of full refetches, which is the primary focus across all changed files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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/p3-incremental-agent-refresh

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
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
test/renderer/stores/agentStore.test.ts (1)

1-1: ⚡ Quick win

Place this suite in a path that mirrors stores/ui/agent.ts

Given the tested source path includes stores/ui, consider moving this suite to a mirrored location under test/renderer/** (for example, under test/renderer/stores/ui/...) to stay consistent with repository test-layout rules.

As per coding guidelines, “Vitest test suites should mirror the source structure under test/main/** and test/renderer/**”.

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

In `@test/renderer/stores/agentStore.test.ts` at line 1, The test suite currently
in test/renderer/stores/agentStore.test.ts should be relocated so its path
mirrors the source module stores/ui/agent.ts; move the file into a corresponding
test/renderer/stores/ui/ directory (e.g.,
test/renderer/stores/ui/agentStore.test.ts) and update any imports or
test-runner references accordingly so the suite aligns with the repository
convention that Vitest tests mirror source layout.
🤖 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/stores/ui/agent.ts`:
- Around line 138-139: The error assignment uses a hard-coded English string
(error.value = `Failed to refresh ${agentType} agents: ${e}`) — replace it with
a vue-i18n key lookup from the i18n module (e.g., use the t() function from
useI18n or the project i18n helper) and pass agentType and error text as
interpolation params; also update the similar hard-coded string at the other
occurrence (lines around the second error assignment referenced) to use the same
i18n key(s) located in src/renderer/src/i18n so all user-facing messages come
from i18n instead of inline text.

In `@src/shared/contracts/routes/config.routes.ts`:
- Around line 424-426: The schema allows ids:
z.array(z.string().min(1)).optional() which accepts an empty array and causes
the Set filter to return zero agents; change the schema for the ids field
(symbol "ids") to forbid empty arrays (e.g., use Zod's nonempty/ .min(1) on the
array type) or coerce an empty array to undefined so that an absent/unscoped
request is represented as undefined instead of []—update the schema where "ids"
is defined to either z.array(z.string().min(1)).nonempty().optional() or add a
transform/refine that converts [] -> undefined to prevent accidental “return
none” behavior.

In `@test/renderer/stores/agentStore.test.ts`:
- Around line 100-103: The assertion for configClient.listAgents should also
assert the call count to ensure the scoped refresh is the only call; update the
tests around the expect(configClient.listAgents).toHaveBeenCalledWith(...) at
the shown location (and the similar one around lines 131-134) to either assert
toHaveBeenCalledTimes(1) before/after the toHaveBeenCalledWith or replace with
toHaveBeenNthCalledWith(1, { agentType: 'acp', ids: ['acp-1'] }) so the test
fails if any extra unscoped/full listAgents calls occur.

---

Nitpick comments:
In `@test/renderer/stores/agentStore.test.ts`:
- Line 1: The test suite currently in test/renderer/stores/agentStore.test.ts
should be relocated so its path mirrors the source module stores/ui/agent.ts;
move the file into a corresponding test/renderer/stores/ui/ directory (e.g.,
test/renderer/stores/ui/agentStore.test.ts) and update any imports or
test-runner references accordingly so the suite aligns with the repository
convention that Vitest tests mirror source layout.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0a9a738a-9204-4bf0-b658-42f142b5e6ee

📥 Commits

Reviewing files that changed from the base of the PR and between 41d3f6d and 40d687b.

📒 Files selected for processing (9)
  • src/main/presenter/configPresenter/index.ts
  • src/main/routes/config/configRouteHandler.ts
  • src/main/routes/legacyTypedEventBridge.ts
  • src/renderer/api/ConfigClient.ts
  • src/renderer/src/stores/ui/agent.ts
  • src/shared/contracts/events/config.events.ts
  • src/shared/contracts/routes.ts
  • src/shared/contracts/routes/config.routes.ts
  • test/renderer/stores/agentStore.test.ts

Comment on lines +138 to +139
error.value = `Failed to refresh ${agentType} agents: ${e}`
}

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace hard-coded refresh error strings with i18n keys

These new error messages are user-facing and should come from vue-i18n keys instead of inline English text.

As per coding guidelines src/renderer/src/**/*.{vue,ts,tsx}: All user-facing strings must use vue-i18n keys located in src/renderer/src/i18n.

Also applies to: 158-159

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

In `@src/renderer/src/stores/ui/agent.ts` around lines 138 - 139, The error
assignment uses a hard-coded English string (error.value = `Failed to refresh
${agentType} agents: ${e}`) — replace it with a vue-i18n key lookup from the
i18n module (e.g., use the t() function from useI18n or the project i18n helper)
and pass agentType and error text as interpolation params; also update the
similar hard-coded string at the other occurrence (lines around the second error
assignment referenced) to use the same i18n key(s) located in
src/renderer/src/i18n so all user-facing messages come from i18n instead of
inline text.

Comment on lines +424 to +426
ids: z.array(z.string().min(1)).optional()
})
.default({}),

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard against empty ids to avoid accidental “return none” behavior

ids: [] currently parses, and the handler-side Set filter will return zero agents. If empty means “unscoped”, this can produce accidental data drops in callers.

Suggested schema hardening
-      ids: z.array(z.string().min(1)).optional()
+      ids: z.array(z.string().min(1)).min(1).optional()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/shared/contracts/routes/config.routes.ts` around lines 424 - 426, The
schema allows ids: z.array(z.string().min(1)).optional() which accepts an empty
array and causes the Set filter to return zero agents; change the schema for the
ids field (symbol "ids") to forbid empty arrays (e.g., use Zod's nonempty/
.min(1) on the array type) or coerce an empty array to undefined so that an
absent/unscoped request is represented as undefined instead of []—update the
schema where "ids" is defined to either
z.array(z.string().min(1)).nonempty().optional() or add a transform/refine that
converts [] -> undefined to prevent accidental “return none” behavior.

Comment on lines +100 to +103
expect(configClient.listAgents).toHaveBeenCalledWith({
agentType: 'acp',
ids: ['acp-1']
})

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Strengthen scoped-refresh assertions to avoid false positives

These checks should also assert call count. toHaveBeenCalledWith(...) still passes if an extra unscoped/full listAgents call happens, which weakens the “incremental only” guarantee.

Proposed test hardening
-    expect(configClient.listAgents).toHaveBeenCalledWith({
+    expect(configClient.listAgents).toHaveBeenCalledTimes(1)
+    expect(configClient.listAgents).toHaveBeenCalledWith({
       agentType: 'acp',
       ids: ['acp-1']
     })

...

-    expect(configClient.listAgents).toHaveBeenCalledWith({
+    expect(configClient.listAgents).toHaveBeenCalledTimes(1)
+    expect(configClient.listAgents).toHaveBeenCalledWith({
       agentType: 'acp',
       ids: ['acp-2']
     })

Also applies to: 131-134

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

In `@test/renderer/stores/agentStore.test.ts` around lines 100 - 103, The
assertion for configClient.listAgents should also assert the call count to
ensure the scoped refresh is the only call; update the tests around the
expect(configClient.listAgents).toHaveBeenCalledWith(...) at the shown location
(and the similar one around lines 131-134) to either assert
toHaveBeenCalledTimes(1) before/after the toHaveBeenCalledWith or replace with
toHaveBeenNthCalledWith(1, { agentType: 'acp', ids: ['acp-1'] }) so the test
fails if any extra unscoped/full listAgents calls occur.

@zerob13
zerob13 changed the base branch from dev to codex/p1-selectable-model-source April 30, 2026 13:48
@zerob13
zerob13 merged commit aab31a4 into codex/p1-selectable-model-source Apr 30, 2026
3 checks passed
zerob13 added a commit that referenced this pull request Apr 30, 2026
* refactor(model): derive selectable model source

* refactor(model): unify selection resolver (#1576)

* refactor(chat): split acp status bar state (#1578)

* refactor(model): unify selection resolver

* refactor(chat): extract acp status bar state

* perf(agent): refresh acp agents incrementally (#1579)

* fix(provider): gc removed model state (#1577)

* fix: address pr review feedback

---------

Co-authored-by: zerob13 <zerob13@gmail.com>
@zhangmo8
zhangmo8 deleted the codex/p3-incremental-agent-refresh branch May 12, 2026 07:51
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.

2 participants