fix(agent): centralize Subagent capability policy#1982
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThis PR moves subagent availability to Agent-level capability resolution with normalized slots, cache keys, migration, and fail-closed behavior. It removes Session-level ChangesSubagent capability policy
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
test/main/presenter/sessionApplication/runtimeIntegration.test.ts (1)
814-815: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert that the resolved configuration is applied.
These assertions only prove that the resolver methods were called; a regression that calls them and ignores the returned subagent configuration would still pass. Add an assertion against the created session’s capability or exposed tool state.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/main/presenter/sessionApplication/runtimeIntegration.test.ts` around lines 814 - 815, Strengthen the session creation test around configPresenter.getAgentType and resolveDeepChatAgentConfig by asserting that the resolved subagent configuration is applied to the created session. Verify the session’s capability or exposed tool state reflects the resolved configuration, rather than only checking that the resolver methods were invoked.src/shared/lib/deepchatSubagents.ts (2)
194-202: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueRemove redundant slot normalization.
normalizeDeepChatSubagentConfigalready normalizes thesubagentsarray internally. You can check its length directly instead of unnecessarily passing it throughnormalizeDeepChatSubagentSlotsa second time.♻️ Proposed refactor
export const assertDeepChatSubagentConfigInvariant = (config: DeepChatAgentConfig): void => { const normalized = normalizeDeepChatSubagentConfig(config) if ( normalized.subagentEnabled !== false && - normalizeDeepChatSubagentSlots(normalized.subagents).length === 0 + (!normalized.subagents || normalized.subagents.length === 0) ) { throw new Error('Enabled DeepChat Subagents require at least one valid slot.') } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/lib/deepchatSubagents.ts` around lines 194 - 202, In assertDeepChatSubagentConfigInvariant, remove the second normalizeDeepChatSubagentSlots call and check the length of normalized.subagents directly, preserving the existing enabled-state condition and error behavior.
169-171: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueRemove redundant array mapping.
normalizeDeepChatSubagentSlotsalready returns a freshly allocated array populated with newly created slot objects. The.map((slot) => ({ ...slot }))step is unnecessary becauseArray.prototype.sort()only reorders the array in place and does not mutate the objects themselves.♻️ Proposed refactor
- const slots = normalizeDeepChatSubagentSlots(input.slots) - .map((slot) => ({ ...slot })) - .sort(compareSubagentSlots) + const slots = normalizeDeepChatSubagentSlots(input.slots).sort(compareSubagentSlots)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/shared/lib/deepchatSubagents.ts` around lines 169 - 171, Remove the redundant `.map((slot) => ({ ...slot }))` from the `normalizeDeepChatSubagentSlots(input.slots)` pipeline before `sort(compareSubagentSlots)`. Keep sorting the freshly normalized array with `compareSubagentSlots`, relying on `normalizeDeepChatSubagentSlots` for array and slot-object allocation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/presenter/agentRuntimePresenter/toolResolver.ts`:
- Around line 243-252: Fail closed when deepchat agent configuration cannot be
read: in src/main/presenter/agentRuntimePresenter/toolResolver.ts lines 243-252,
update the rejection branch around resolveCapability to return unavailable
subagent capability rather than deriving it from null; in
src/main/presenter/index.ts lines 332-358, handle rejected
resolveDeepChatAgentConfig within resolveConversationSessionInfo using the same
safe fallback so the error does not bubble as an unhandled failure.
---
Nitpick comments:
In `@src/shared/lib/deepchatSubagents.ts`:
- Around line 194-202: In assertDeepChatSubagentConfigInvariant, remove the
second normalizeDeepChatSubagentSlots call and check the length of
normalized.subagents directly, preserving the existing enabled-state condition
and error behavior.
- Around line 169-171: Remove the redundant `.map((slot) => ({ ...slot }))` from
the `normalizeDeepChatSubagentSlots(input.slots)` pipeline before
`sort(compareSubagentSlots)`. Keep sorting the freshly normalized array with
`compareSubagentSlots`, relying on `normalizeDeepChatSubagentSlots` for array
and slot-object allocation.
In `@test/main/presenter/sessionApplication/runtimeIntegration.test.ts`:
- Around line 814-815: Strengthen the session creation test around
configPresenter.getAgentType and resolveDeepChatAgentConfig by asserting that
the resolved subagent configuration is applied to the created session. Verify
the session’s capability or exposed tool state reflects the resolved
configuration, rather than only checking that the resolver methods were invoked.
🪄 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: a4f976b5-41a3-486c-97cc-7410ae7c95c6
📒 Files selected for processing (91)
docs/architecture/session-application-coordinators/spec.mddocs/architecture/session-management.mddocs/architecture/subagent-capability-policy/plan.mddocs/architecture/subagent-capability-policy/spec.mddocs/architecture/subagent-capability-policy/tasks.mddocs/architecture/tool-system.mdsrc/main/agent/deepchat/deepChatAgentRepository.tssrc/main/agent/shared/appSessionService.tssrc/main/presenter/agentRuntimePresenter/toolResolver.tssrc/main/presenter/configPresenter/index.tssrc/main/presenter/configPresenter/systemPromptHelper.tssrc/main/presenter/cronJobs/runSessionStarter.tssrc/main/presenter/index.tssrc/main/presenter/sessionApplication/agentAssignmentCoordinator.tssrc/main/presenter/sessionApplication/agentAssignmentPolicy.tssrc/main/presenter/sessionApplication/lifecycleCoordinator.tssrc/main/presenter/sessionApplication/ports.tssrc/main/presenter/sqlitePresenter/tables/newSessions.tssrc/main/presenter/toolPresenter/agentTools/agentToolManager.tssrc/main/presenter/toolPresenter/agentTools/subagentOrchestratorTool.tssrc/main/presenter/toolPresenter/index.tssrc/main/presenter/toolPresenter/runtimePorts.tssrc/main/routes/debug/createMockChatSession.tssrc/main/routes/index.tssrc/renderer/api/SessionClient.tssrc/renderer/settings/components/DeepChatAgentsSettings.vuesrc/renderer/src/components/chat-input/McpIndicator.vuesrc/renderer/src/components/chat/ChatStatusBar.vuesrc/renderer/src/i18n/da-DK/settings.jsonsrc/renderer/src/i18n/de-DE/settings.jsonsrc/renderer/src/i18n/en-US/settings.jsonsrc/renderer/src/i18n/es-ES/settings.jsonsrc/renderer/src/i18n/fa-IR/settings.jsonsrc/renderer/src/i18n/fr-FR/settings.jsonsrc/renderer/src/i18n/he-IL/settings.jsonsrc/renderer/src/i18n/id-ID/settings.jsonsrc/renderer/src/i18n/it-IT/settings.jsonsrc/renderer/src/i18n/ja-JP/settings.jsonsrc/renderer/src/i18n/ko-KR/settings.jsonsrc/renderer/src/i18n/ms-MY/settings.jsonsrc/renderer/src/i18n/pl-PL/settings.jsonsrc/renderer/src/i18n/pt-BR/settings.jsonsrc/renderer/src/i18n/ru-RU/settings.jsonsrc/renderer/src/i18n/tr-TR/settings.jsonsrc/renderer/src/i18n/vi-VN/settings.jsonsrc/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/zh-HK/settings.jsonsrc/renderer/src/i18n/zh-TW/settings.jsonsrc/renderer/src/pages/NewThreadPage.vuesrc/renderer/src/stores/ui/draft.tssrc/renderer/src/stores/ui/session.tssrc/shared/agentTools.tssrc/shared/contracts/common.tssrc/shared/contracts/routes.tssrc/shared/contracts/routes/sessions.routes.tssrc/shared/lib/deepchatSubagents.tssrc/shared/types/agent-interface.d.tssrc/shared/types/presenters/tool.presenter.d.tstest/main/agent/deepchat/deepChatAgentRepository.test.tstest/main/agent/shared/appSessionService.test.tstest/main/presenter/agentRuntimePresenter/agentRuntimePresenter.test.tstest/main/presenter/agentRuntimePresenter/toolResolver.test.tstest/main/presenter/configPresenter/deprecatedProviderCleanup.test.tstest/main/presenter/configPresenter/systemPromptHelper.test.tstest/main/presenter/cronJobRunSessionStarter.test.tstest/main/presenter/exporter/agentSessionExporter.test.tstest/main/presenter/remoteControlPresenter/remoteConversationRunner.test.tstest/main/presenter/sessionApplication/agentAssignmentCoordinator.test.tstest/main/presenter/sessionApplication/agentAssignmentPolicy.test.tstest/main/presenter/sessionApplication/lifecycleCoordinator.test.tstest/main/presenter/sessionApplication/lifecycleDeletionTransaction.test.tstest/main/presenter/sessionApplication/projectionCoordinator.test.tstest/main/presenter/sessionApplication/runtimeIntegration.test.tstest/main/presenter/sessionApplication/sessionApplication.integration.test.tstest/main/presenter/sessionApplication/turnCoordinator.test.tstest/main/presenter/sqlitePresenter/newSessionsTable.test.tstest/main/presenter/toolPresenter/agentTools/agentMemoryTools.test.tstest/main/presenter/toolPresenter/agentTools/agentTapeTools.test.tstest/main/presenter/toolPresenter/agentTools/agentToolManagerSettings.test.tstest/main/presenter/toolPresenter/agentTools/subagentOrchestratorTool.test.tstest/main/presenter/toolPresenter/toolPresenter.test.tstest/main/routes/chatService.test.tstest/main/routes/contracts.test.tstest/main/routes/dispatcher.test.tstest/main/shared/deepchatSubagents.test.tstest/renderer/components/ChatStatusBar.test.tstest/renderer/components/DeepChatAgentsSettings.test.tstest/renderer/components/McpIndicator.test.tstest/renderer/components/NewThreadPage.onboarding.test.tstest/renderer/stores/memoryActivityStore.test.tstest/renderer/stores/sessionStore.test.ts
💤 Files with no reviewable changes (22)
- test/main/presenter/remoteControlPresenter/remoteConversationRunner.test.ts
- test/main/presenter/exporter/agentSessionExporter.test.ts
- test/main/presenter/sessionApplication/turnCoordinator.test.ts
- test/main/routes/chatService.test.ts
- test/main/presenter/sessionApplication/lifecycleDeletionTransaction.test.ts
- test/main/presenter/sessionApplication/projectionCoordinator.test.ts
- test/renderer/components/NewThreadPage.onboarding.test.ts
- src/main/presenter/cronJobs/runSessionStarter.ts
- test/renderer/stores/memoryActivityStore.test.ts
- src/main/routes/index.ts
- test/main/presenter/cronJobRunSessionStarter.test.ts
- src/main/agent/shared/appSessionService.ts
- src/renderer/src/stores/ui/draft.ts
- test/renderer/stores/sessionStore.test.ts
- src/shared/contracts/routes/sessions.routes.ts
- test/main/routes/dispatcher.test.ts
- src/renderer/src/pages/NewThreadPage.vue
- src/renderer/src/components/chat/ChatStatusBar.vue
- src/renderer/src/stores/ui/session.ts
- src/shared/contracts/routes.ts
- src/shared/contracts/common.ts
- src/renderer/api/SessionClient.ts
Summary
Centralize Subagent availability around the DeepChat Agent policy and remove the conflicting Session-level toggle.
The Agent configuration is now the single persisted policy source. Subagents are enabled by default for the built-in DeepChat Agent, while the model decides whether delegation is appropriate for each request.
Problem
Subagent availability previously depended on several independent states:
subagentEnabledsubagent_enabledThese states could disagree, causing the UI to show Subagents as enabled while the model did not receive
subagent_orchestrator.Changes
new_sessions.subagent_enabledcolumn for database compatibility while no longer using it for authorization.subagent_orchestratoragainst MCP tool shadowing.Summary by CodeRabbit