feat: add persistent task agent model setup#3442
Conversation
|
Warning Review limit reached
Next review available in: 13 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (36)
📝 WalkthroughWalkthroughTask agents now support persistent model/profile setup, explicit disabled mode, immutable inference provenance, automatic-update controls, setup identity in summary headers, setup editing sheets, synchronization safeguards, localization, and comprehensive tests. ChangesTask-agent setup and attribution
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 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.
Code Review
This pull request implements task-agent model identity, persistent setup, and report provenance. It introduces a typed AgentInferenceSetup to AgentConfig, adds immutable report provenance tracking, and provides a persistent setup sheet (AgentModelSheet) for configuring profiles, direct model overrides, and automatic updates. Feedback on the changes highlights a critical syntax error in tldr_section_part.dart where an invalid ? prefix is used, a logic issue in task_agent_execute.dart where typed setups incorrectly fall back to template models, and a potential crash in agent_model_sheet.dart caused by accessing ref after an asynchronous gap without checking if the widget is mounted.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
b0bae4e to
c4456f1
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3442 +/- ##
==========================================
- Coverage 99.27% 99.24% -0.03%
==========================================
Files 1695 1701 +6
Lines 121893 122701 +808
==========================================
+ Hits 121013 121780 +767
- Misses 880 921 +41
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/features/design_system/components/checkboxes/design_system_checkbox.dart (1)
20-36: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winReject non-positive
labelMaxLinesvalues. Guard the constructor so0or negative values never reachText.maxLines.🤖 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 `@lib/features/design_system/components/checkboxes/design_system_checkbox.dart` around lines 20 - 36, Update the DesignSystemCheckbox constructor assertion to require labelMaxLines, when provided, to be greater than zero, preventing non-positive values from reaching Text.maxLines while preserving the existing label and semanticsLabel validation.
🧹 Nitpick comments (5)
test/features/agents/workflow/wake_output_writer_test.dart (1)
214-243: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winAssert the complete provenance snapshot.
The test still passes if
runKey,threadId, provider identifiers/types, author, or runtime settings are lost. Comparedecodedwithprovenance, or assert every persisted field.🤖 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/features/agents/workflow/wake_output_writer_test.dart` around lines 214 - 243, Update the test “stamps immutable inference provenance on a written report” to verify the complete decoded provenance matches the original provenance, including runKey, threadId, provider model and serving identifiers/types, finalContentAuthor, and runtimeSettings, rather than checking only selected route names.test/features/agents/service/task_agent_service_test.dart (1)
1927-1969: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winExercise subscription restoration when enabling updates.
The test returns no task links and only verifies the runtime toggle, so it passes if subscription restoration is removed. Return one
AgentTaskLinkand verifyaddSubscription.🤖 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/features/agents/service/task_agent_service_test.dart` around lines 1927 - 1969, Strengthen the test around updateAutomaticUpdates by returning one AgentTaskLink from mockRepository.getLinksFrom and verifying mockOrchestrator.addSubscription is called for that task when automatic updates are enabled. Keep the existing runtime-toggle and no-pending-wake assertions, ensuring the test exercises subscription restoration rather than only the configuration update.lib/features/ai/model/resolved_profile.dart (1)
234-254: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAdd value equality to
ResolvedAgentSetupfor consistency and to avoid needless rebuilds.Unlike
ResolvedProfileandInferenceRouteFingerprintin this same file,ResolvedAgentSetupis@immutablebut has nooperator ==/hashCode. Since this type flows through a Riverpod provider consumed by UI (pertaskAgentResolvedSetupProviderin the detail-page tests), identity-only equality means every re-resolution is treated as "different" even when structurally identical, working against the stale-while-revalidate/no-flash goal described in the PR's implementation plan.♻️ Proposed equality implementation
class ResolvedAgentSetup { const ResolvedAgentSetup({ required this.status, this.profile, this.source, this.setupOrigin, this.brokenSelectionId, this.routeFingerprint, }); final AgentSetupResolutionStatus status; final ResolvedProfile? profile; final AgentSetupResolutionSource? source; final AgentInferenceSetupOrigin? setupOrigin; final String? brokenSelectionId; final InferenceRouteFingerprint? routeFingerprint; bool get canRun => status == AgentSetupResolutionStatus.resolved; bool get hasBrokenSelection => brokenSelectionId != null; + + `@override` + bool operator ==(Object other) => + identical(this, other) || + other is ResolvedAgentSetup && + status == other.status && + profile == other.profile && + source == other.source && + setupOrigin == other.setupOrigin && + brokenSelectionId == other.brokenSelectionId && + routeFingerprint == other.routeFingerprint; + + `@override` + int get hashCode => Object.hash( + status, + profile, + source, + setupOrigin, + brokenSelectionId, + routeFingerprint, + ); }🤖 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 `@lib/features/ai/model/resolved_profile.dart` around lines 234 - 254, Add value-based equality to the immutable ResolvedAgentSetup class, comparing status, profile, source, setupOrigin, brokenSelectionId, and routeFingerprint, and implement a matching hashCode. Keep the existing canRun and hasBrokenSelection behavior unchanged so structurally identical resolutions compare equal.test/features/agents/ui/task_agent_identity_region_test.dart (1)
1-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winNo coverage for the
brokenpresentation.All three tests cover
combined,split, anddisabled, but none exerciseTaskAgentIdentityPresentation.broken. A test asserting the visible text (taskAgentSetupBroken), the semantics label, and report-row visibility (whenreportRouteis set) for the broken state would have caught the two issues flagged intask_agent_identity_region.dart.🤖 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/features/agents/ui/task_agent_identity_region_test.dart` around lines 1 - 104, The widget tests cover combined, split, and disabled but omit TaskAgentIdentityPresentation.broken. Add a test using TaskAgentIdentityRegion with presentation set to broken and a reportRoute, then assert taskAgentSetupBroken is visible, the broken-state semantics label is present, and the report row is rendered.lib/l10n/app_localizations_de.dart (1)
8875-9024: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winInconsistent German terminology for "AI setup" across new strings.
The English source consistently uses "setup" for this concept, but the German translations alternate between "Einrichtung" and "Setup" for the same idea within the same feature: e.g.
taskAgentSetupTitle→ "Agent-Einrichtung",taskAgentNoAiSetup→ "Keine KI-Einrichtung",taskAgentDisableConfirmTitle→ "KI-Einrichtung ausschalten?" vs.taskAgentAutomaticUpdatesNeedsSetup→ "KI-Setup",taskAgentNoProfileSelected→ "Kein KI-Setup",taskAgentUseCategoryDefaultDescription→ "Setup der Kategorie". Since these strings appear together on the same agent-setup screens, the mixed wording will read as inconsistent to German users.Fix should be made in the
app_de.arbsource (pick one term, e.g. "Einrichtung", consistently) and regenerated viamake l10n, since this file is generated and must not be edited directly.🤖 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 `@lib/l10n/app_localizations_de.dart` around lines 8875 - 9024, Standardize the German translation for the AI setup concept across the related task-agent localization entries, using one term consistently (prefer “Einrichtung”). Update the corresponding app_de.arb source entries, including setup-related labels, descriptions, and messages, then regenerate the generated localization file with make l10n; do not edit app_localizations_de.dart directly.Source: Path instructions
🤖 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 `@lib/features/agents/service/task_agent_service.dart`:
- Around line 325-358: Wrap the read-modify-write sequence in
updateAutomaticUpdates with syncService.runInTransaction, including the agent
lookup, validation, copyWith update, and upsertEntity call. Preserve the
existing not-found and inference-setup validation, and use the transaction’s
current identity so concurrent config changes are not overwritten; keep runtime
orchestration and logging outside the transaction as appropriate.
In `@lib/features/agents/ui/agent_internals_body.dart`:
- Around line 301-346: Update the task-agent setup display around the setup and
route calculations in the agent internals body to branch on setup.status,
treating unavailable or broken setups as broken rather than as “No profile
selected.” Use taskAgentSetupBroken for the broken title/state while preserving
the existing profile route display for available setups and the current
interaction behavior.
In `@lib/features/agents/ui/ai_summary_card.dart`:
- Around line 483-487: Update the showCountdown condition in the AI summary card
to require inferenceAvailable in addition to the existing automatic-update,
running-state, remaining-time, and cancellation checks, preventing the timer
from rendering when onRunNow is unavailable.
In `@lib/features/agents/ui/task_agent_identity_region.dart`:
- Around line 34-68: Update the report-row condition in the task identity widget
to render _ReportIdentityRow whenever historical report attribution is
available, including broken and disabled presentations, rather than only for
split. Simplify its value selection so reportAttributionUnavailable and a
missing reportRoute consistently use the unavailable message, otherwise format
reportRoute, removing the redundant nested ternary.
- Around line 27-32: Update the semanticsLabel logic in the task agent identity
region to branch on the presentation state before checking currentIdentity,
using the broken-state message for broken presentations and retaining the
no-profile message only for disabled or unset presentations. Keep the existing
combined and setup semantics for valid identities unchanged.
In `@lib/features/agents/ui/task_agent_model_identity.dart`:
- Around line 85-93: Replace the hardcoded “via” text in
formatInferenceRouteIdentity with a required localized viaLabel parameter, and
use that label when composing the route identity. Update
_AgentModelSheetBodyState._profileRoute and every other call site to pass
context.messages.taskAgentRouteVia, add the corresponding taskAgentRouteVia ARB
entry to all locale files, and update the widget test expectation to use the
localized label.
In `@lib/features/agents/wake/wake_drain_engine.dart`:
- Around line 163-174: Update _wakeAllowedByCurrentPolicy to catch failures from
repository.getEntity(job.agentId), log the exception, and return true so policy
gating fails open without aborting the drain pass. Preserve the existing
entity-type check and taskAgentWakeAllowed behavior for successful lookups.
In `@lib/features/agents/wake/wake_orchestrator.dart`:
- Around line 305-320: Update enqueueManualWake to default omitted initiators to
WakeInitiator.user, ensuring explicit manual wakes such as creation, scheduled,
and transcription-complete requests bypass the automatic-updates disable gate.
Preserve explicitly supplied initiators, including automation and reanalysis,
and update only the relevant call path rather than changing
disableAutomaticUpdatesRuntime.
In `@lib/features/ai/util/known_models.dart`:
- Around line 86-90: Update the model-ID matching condition in the known-model
attribution logic to remove the provider namespace from IDs such as
“openai/o4-mini” and “openai/gpt-4.1” before applying the existing whisper,
gpt-, o1, o3, and o4 prefix checks. Preserve the current matching behavior for
unnamespaced IDs.
In `@lib/features/ai/util/profile_resolver.dart`:
- Around line 95-125: Update the profile resolution flow around
_resolveFromProfile and the thinkingModelOverrideId branch so the direct
override is applied before validating the base profile’s thinking route.
Preserve the base profile and resolve its skills and optional model slots when
available, even if its original thinking model is missing; only construct a
thinking-only ResolvedProfile when no usable base profile remains. Add a
regression test covering a missing base thinking model with a valid override and
optional slots.
In `@lib/features/sync/matrix/sync_event_processor_agent_handlers.dart`:
- Around line 199-224: Update the automatic-update restoration logic around
appliedIdentity and enableAutomaticUpdatesRuntime so every active agent with
automatic updates enabled and non-disabled inference clears the runtime-disabled
state, regardless of kind. Preserve the task_agent kind check only for
task-agent-specific wake subscription restoration or linking, while invoking
enableAutomaticUpdatesRuntime for all eligible agent kinds.
In `@test/features/agents/ui/agent_model_sheet_test.dart`:
- Around line 260-288: Update the test around openSheet and getCategoryById so
it returns a category-1 fixture whose default setup is absent, rather than null.
Keep the existing assertions for disabled mode and categorySnapshot origin,
ensuring the test exercises an existing category with no default.
---
Outside diff comments:
In
`@lib/features/design_system/components/checkboxes/design_system_checkbox.dart`:
- Around line 20-36: Update the DesignSystemCheckbox constructor assertion to
require labelMaxLines, when provided, to be greater than zero, preventing
non-positive values from reaching Text.maxLines while preserving the existing
label and semanticsLabel validation.
---
Nitpick comments:
In `@lib/features/ai/model/resolved_profile.dart`:
- Around line 234-254: Add value-based equality to the immutable
ResolvedAgentSetup class, comparing status, profile, source, setupOrigin,
brokenSelectionId, and routeFingerprint, and implement a matching hashCode. Keep
the existing canRun and hasBrokenSelection behavior unchanged so structurally
identical resolutions compare equal.
In `@lib/l10n/app_localizations_de.dart`:
- Around line 8875-9024: Standardize the German translation for the AI setup
concept across the related task-agent localization entries, using one term
consistently (prefer “Einrichtung”). Update the corresponding app_de.arb source
entries, including setup-related labels, descriptions, and messages, then
regenerate the generated localization file with make l10n; do not edit
app_localizations_de.dart directly.
In `@test/features/agents/service/task_agent_service_test.dart`:
- Around line 1927-1969: Strengthen the test around updateAutomaticUpdates by
returning one AgentTaskLink from mockRepository.getLinksFrom and verifying
mockOrchestrator.addSubscription is called for that task when automatic updates
are enabled. Keep the existing runtime-toggle and no-pending-wake assertions,
ensuring the test exercises subscription restoration rather than only the
configuration update.
In `@test/features/agents/ui/task_agent_identity_region_test.dart`:
- Around line 1-104: The widget tests cover combined, split, and disabled but
omit TaskAgentIdentityPresentation.broken. Add a test using
TaskAgentIdentityRegion with presentation set to broken and a reportRoute, then
assert taskAgentSetupBroken is visible, the broken-state semantics label is
present, and the report row is rendered.
In `@test/features/agents/workflow/wake_output_writer_test.dart`:
- Around line 214-243: Update the test “stamps immutable inference provenance on
a written report” to verify the complete decoded provenance matches the original
provenance, including runKey, threadId, provider model and serving
identifiers/types, finalContentAuthor, and runtimeSettings, rather than checking
only selected route names.
🪄 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: 91f9e844-d81d-4a47-99e0-0c4384e06eaa
📒 Files selected for processing (79)
CHANGELOG.mddocs/implementation_plans/2026-07-12_task_agent_model_selection.mdflatpak/com.matthiasn.lotti.metainfo.xmllib/features/agents/README.mdlib/features/agents/model/agent_automation_policy.dartlib/features/agents/model/agent_config.dartlib/features/agents/model/agent_config.freezed.dartlib/features/agents/model/agent_config.g.dartlib/features/agents/model/agent_enums.dartlib/features/agents/model/agent_report_provenance.dartlib/features/agents/service/task_agent_service.dartlib/features/agents/state/task_agent_model_providers.dartlib/features/agents/ui/agent_internals_body.dartlib/features/agents/ui/agent_model_sheet.dartlib/features/agents/ui/ai_summary_card.dartlib/features/agents/ui/ai_summary_card/assign_agent_cta_part.dartlib/features/agents/ui/ai_summary_card/tldr_section_part.dartlib/features/agents/ui/task_agent_identity_region.dartlib/features/agents/ui/task_agent_model_identity.dartlib/features/agents/wake/wake_batch_router.dartlib/features/agents/wake/wake_drain_engine.dartlib/features/agents/wake/wake_orchestrator.dartlib/features/agents/wake/wake_queue.dartlib/features/agents/workflow/task_agent_execute.dartlib/features/agents/workflow/task_agent_workflow.dartlib/features/agents/workflow/wake_output_writer.dartlib/features/ai/model/ai_config.dartlib/features/ai/model/ai_config.freezed.dartlib/features/ai/model/ai_config.g.dartlib/features/ai/model/resolved_profile.dartlib/features/ai/util/known_models.dartlib/features/ai/util/profile_resolver.dartlib/features/design_system/components/checkboxes/design_system_checkbox.dartlib/features/sync/matrix/sync_event_processor.dartlib/features/sync/matrix/sync_event_processor_agent_handlers.dartlib/l10n/app_cs.arblib/l10n/app_de.arblib/l10n/app_en.arblib/l10n/app_es.arblib/l10n/app_fr.arblib/l10n/app_localizations.dartlib/l10n/app_localizations_cs.dartlib/l10n/app_localizations_de.dartlib/l10n/app_localizations_en.dartlib/l10n/app_localizations_es.dartlib/l10n/app_localizations_fr.dartlib/l10n/app_localizations_ro.dartlib/l10n/app_ro.arblib/logic/create/task_agent_assignment.darttest/features/agents/model/agent_automation_policy_test.darttest/features/agents/model/agent_config_test.darttest/features/agents/model/agent_report_provenance_test.darttest/features/agents/service/task_agent_service_test.darttest/features/agents/state/task_agent_model_providers_test.darttest/features/agents/ui/agent_detail_page_test.darttest/features/agents/ui/agent_internals_body_test.darttest/features/agents/ui/agent_model_sheet_test.darttest/features/agents/ui/ai_summary_card/assign_agent_cta_part_test.darttest/features/agents/ui/ai_summary_card/test_bench.darttest/features/agents/ui/ai_summary_card/wake_test.darttest/features/agents/ui/task_agent_identity_region_test.darttest/features/agents/ui/task_agent_model_identity_test.darttest/features/agents/wake/wake_orchestrator_test.darttest/features/agents/wake/wake_orchestrator_test_helpers.darttest/features/agents/wake/wake_queue_test.darttest/features/agents/workflow/task_agent_workflow_test.darttest/features/agents/workflow/wake_output_writer_test.darttest/features/ai/model/ai_config_test.darttest/features/ai/model/resolved_profile_test.darttest/features/ai/util/known_models_test.darttest/features/ai/util/profile_resolver_test.darttest/features/daily_os_next/agents/service/day_agent_capture_service_test.darttest/features/daily_os_next/agents/state/day_agent_providers_test.darttest/features/design_system/components/checkboxes/design_system_checkbox_test.darttest/features/projects/ui/widgets/project_agent_report_card_test.darttest/features/sync/matrix/sync_event_processor_agent_handlers_test.darttest/features/tasks/ui/linked_tasks/linked_tasks_widget_actions_test.darttest/helpers/fallbacks.darttest/logic/create/create_entry_more_test.dart
What changed
Validation
fvm flutter analyze: zero findings.Summary by CodeRabbit