Skip to content

feat: configurable utility agent for auxiliary tasks#836

Open
pedramamini wants to merge 2 commits into
mainfrom
feat/835-utility-agent-setting
Open

feat: configurable utility agent for auxiliary tasks#836
pedramamini wants to merge 2 commits into
mainfrom
feat/835-utility-agent-setting

Conversation

@pedramamini
Copy link
Copy Markdown
Collaborator

@pedramamini pedramamini commented Apr 13, 2026

Summary

Closes #835

  • Adds utilityAgentId and utilityModelId settings so users can route lightweight auxiliary tasks (tab naming, context grooming) to a cheaper/faster agent instead of burning primary session tokens on housekeeping
  • When unset, behavior is unchanged (uses the session's own agent)
  • UI dropdown in Settings > General (right below "Automatic Tab Naming") populated from detected available agents, with optional model override text field

Files changed

  • src/shared/settingsMetadata.ts — new setting definitions
  • src/main/stores/defaults.ts — defaults (both null)
  • src/renderer/stores/settingsStore.ts — Zustand state, setters, and load logic
  • src/renderer/hooks/settings/useSettings.ts — hook interface
  • src/main/ipc/handlers/tabNaming.ts — resolves utility agent before spawning
  • src/main/ipc/handlers/context.ts — resolves utility agent for groomContext; added settingsStore dependency
  • src/main/utils/context-groomer.ts — accepts optional modelId and passes to buildAgentArgs
  • src/main/index.ts, src/main/ipc/handlers/index.ts — wire settingsStore to context handlers
  • src/renderer/components/Settings/tabs/GeneralTab.tsx — Utility Agent UI section
  • src/__tests__/main/ipc/handlers/tabNaming.test.ts — fix mock to return proper defaults

Test plan

  • All 22,451 existing tests pass (537 suites)
  • TypeScript type-check clean across all configs
  • ESLint clean (0 errors)
  • Manual: open Settings, verify Utility Agent dropdown shows detected agents
  • Manual: select a utility agent, send a message to a new tab, verify tab naming uses the selected agent
  • Manual: set model override, verify it's passed through to the agent
  • Manual: clear both fields, verify default behavior (session agent) is restored

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Utility Agent configuration in settings. Users can now designate a specific agent for auxiliary tasks with an optional model override. When configured, auxiliary operations use the selected utility agent instead of the default session agent.
  • Documentation

    • Normalized release notes formatting for improved readability.

… context grooming)

Closes #835

Adds utilityAgentId and utilityModelId settings so users can route
lightweight auxiliary tasks to a cheaper/faster agent instead of
burning primary session tokens on housekeeping work.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 13, 2026

📝 Walkthrough

Walkthrough

This PR implements a "Utility Agent" feature that lets users configure a separate agent and optional model for lightweight auxiliary tasks like tab naming and context summarization. Changes span settings metadata, defaults, both renderer and main process stores, IPC handler logic, UI components, and test mocks.

Changes

Cohort / File(s) Summary
Settings Configuration
src/shared/settingsMetadata.ts, src/main/stores/defaults.ts
Added utilityAgentId and utilityModelId settings metadata (both nullable strings, advanced category) and initialized both fields to null in defaults.
Renderer Settings Integration
src/renderer/stores/settingsStore.ts, src/renderer/hooks/settings/useSettings.ts, src/renderer/components/Settings/tabs/GeneralTab.tsx
Extended Zustand settings store and hook interface with utilityAgentId/utilityModelId properties and setters; added GeneralTab UI with agent detection dropdown and model input field.
IPC Handler Updates
src/main/ipc/handlers/context.ts, src/main/ipc/handlers/tabNaming.ts, src/main/ipc/handlers/index.ts, src/main/index.ts
Extended ContextHandlerDependencies to include settingsStore; updated both context and tabNaming handlers to resolve effectiveAgentType from utility setting, use for agent lookup/config overrides, and conditionally pass modelId; wired settings store through handler registration.
Core Utilities
src/main/utils/context-groomer.ts
Added optional modelId field to GroomContextOptions to support model ID override propagation through to agent argument building.
Test Updates
src/__tests__/main/ipc/handlers/tabNaming.test.ts
Refactored mockSettingsStore.get from simple mockReturnValue({}) to keyed mockImplementation returning conditional defaults for utility agent/model fields.
Documentation
docs/releases.md
Normalized release notes formatting by converting Windows-style line endings and restructuring bullet/heading layout into clean Markdown.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant UI as GeneralTab UI
    participant Store as Renderer Store
    participant IPC as IPC Handler
    participant MainStore as Main Settings Store
    participant AgentConfig as Agent Config Store
    participant Spawn as Agent Spawn

    User->>UI: Select Utility Agent + Model
    UI->>Store: Call setUtilityAgentId/setUtilityModelId
    Store->>Store: Update state + persist to window.maestro.settings

    Note over IPC,Spawn: Tab Naming / Context Grooming Flow
    IPC->>MainStore: Read utilityAgentId/utilityModelId
    MainStore-->>IPC: Return settings (or null)
    
    alt Utility Agent Set
        IPC->>IPC: effectiveAgentType = utilityAgentId
        IPC->>AgentConfig: Resolve agent via effectiveAgentType
    else Utility Agent Not Set
        IPC->>IPC: effectiveAgentType = sessionAgentType
        IPC->>AgentConfig: Resolve agent via effectiveAgentType
    end
    
    AgentConfig-->>IPC: Agent config + defaults
    IPC->>IPC: Pass utilityModelId as modelId (if set)
    IPC->>Spawn: buildAgentArgs(effectiveAgentType, modelId)
    Spawn-->>IPC: Ready to spawn auxiliary task agent
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A utility hops forth, lean and spry,
No Opus needed for a simple reply—
Tab names by Haiku, summaries so fleet,
While Llama thinks deep: cost-efficient and neat!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% 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 title accurately describes the main change: introducing a configurable utility agent feature for auxiliary tasks, which is the primary focus of all code changes.
Linked Issues check ✅ Passed The PR successfully implements all core requirements from #835: adds utilityAgentId/utilityModelId settings with defaults, updates handlers (tabNaming, context) to resolve the utility agent, provides UI in GeneralTab, respects SSH semantics, and includes test updates.
Out of Scope Changes check ✅ Passed All changes remain directly within scope: settings definitions, handler logic to resolve utility agents, renderer UI, and supporting infrastructure modifications. No unrelated changes detected.

✏️ 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 feat/835-utility-agent-setting

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 13, 2026

Greptile Summary

This PR adds utilityAgentId and utilityModelId settings to route lightweight auxiliary tasks (tab naming, context grooming) to a configurable agent instead of the session's own agent. The wiring through settings metadata, defaults, Zustand store, hooks, and the UI dropdown in GeneralTab is thorough. One bug exists in the context handler: session-level custom path, args, and env-vars are forwarded to the utility agent unchanged, which will invoke the wrong binary when the utility agent differs from the session agent and the session has custom overrides set.

Confidence Score: 4/5

Safe to merge after fixing the session-level custom config forwarding bug in context.ts.

One P1 logic defect: when a utility agent is configured and the session has custom path/args/env-vars set for a different agent type, the context groomer invokes the wrong binary. Tab naming is unaffected. Everything else — settings plumbing, UI, store, defaults, and tests — is correct and well-structured.

src/main/ipc/handlers/context.ts — lines 174–178, session overrides forwarded to utility agent.

Important Files Changed

Filename Overview
src/main/ipc/handlers/context.ts Resolves utility agent correctly, but session-level customPath/customArgs/customEnvVars are forwarded to the potentially different utility agent, which can cause the wrong binary to be invoked.
src/main/ipc/handlers/tabNaming.ts Utility agent resolution is correct; tab naming IPC does not expose custom path/args, so no forwarding issue applies here.
src/renderer/components/Settings/tabs/GeneralTab.tsx Adds a Utility Agent UI section with agent dropdown and conditional model override input; agent detection is guarded correctly with a one-shot load.
src/renderer/stores/settingsStore.ts State, setters, and load logic for utilityAgentId/utilityModelId follow existing patterns correctly.
src/main/utils/context-groomer.ts Adds optional modelId parameter and passes it to buildAgentArgs; resolvedCommand still uses sessionCustomPath
src/shared/settingsMetadata.ts Adds metadata entries for the two new settings; type declared as 'string' while default is null, consistent with other nullable string settings in the file.
src/tests/main/ipc/handlers/tabNaming.test.ts Mock updated to return proper defaults for the new utility agent settings keys, fixing the existing test to work with the new settingsStore.get calls.

Sequence Diagram

sequenceDiagram
    participant R as Renderer
    participant TN as tabNaming.ts (IPC)
    participant CTX as context.ts (IPC)
    participant SS as settingsStore
    participant CG as context-groomer.ts
    participant AD as AgentDetector
    participant PM as ProcessManager

    R->>TN: tabNaming:generateTabName(userMessage, agentType, cwd)
    TN->>SS: get('utilityAgentId')
    TN->>SS: get('utilityModelId')
    Note over TN: effectiveAgentType = utilityAgentId || agentType
    TN->>AD: getAgent(effectiveAgentType)
    TN->>PM: spawn(effectiveAgentType, args with modelId)

    R->>CTX: context:groomContext(projectRoot, agentType, prompt, options)
    CTX->>SS: get('utilityAgentId')
    CTX->>SS: get('utilityModelId')
    Note over CTX: effectiveAgentType = utilityAgentId || agentType
    CTX->>CG: groomContext({agentType: effectiveAgentType, modelId, sessionCustomPath, ...})
    CG->>AD: getAgent(effectiveAgentType)
    CG->>PM: spawn(resolvedCommand, resolvedArgs)
Loading

Comments Outside Diff (1)

  1. src/main/ipc/handlers/context.ts, line 174-178 (link)

    P1 Session-level overrides forwarded to a different utility agent

    When utilityAgentId is set to a different agent type, the session's customPath, customArgs, and customEnvVars are still passed through. In context-groomer.ts the command is resolved as sessionCustomPath || agent.command (line 218), so a session that has a custom path (e.g. /opt/custom-claude) will cause the utility agent (e.g. codex) to be invoked using the wrong binary. Similarly, sessionCustomArgs takes precedence over the utility agent's own configured args in applyAgentConfigOverrides.

Reviews (1): Last reviewed commit: "chore: fix pre-existing prettier formatt..." | Re-trigger Greptile

Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/releases.md`:
- Line 153: Fix the grammar in the release note sentence that currently reads
"You will received (configurable) warnings at 60% and 80% context consumption
with a hint to compact" by changing "received" to "receive" so the sentence
reads "...You will receive (configurable) warnings at 60% and 80% context
consumption with a hint to compact"; update the same sentence text in
docs/releases.md (the context-management release note line) accordingly.
- Line 74: In the "Document Graphs" sentence that currently reads "Launch from
file preview or from the FIle tree panel," fix the typo by changing "FIle tree
panel" to "File tree panel" so the phrase reads "Launch from file preview or
from the File tree panel."
- Line 20: The heading "Major 0.15.x Additions" is using an H1 marker ("#")
inside the "## v0.15.x" section which breaks hierarchy; change the line
containing "Major 0.15.x Additions" from "# Major 0.15.x Additions" to a nested
heading such as "### Major 0.15.x Additions" (or "### Major 0.15.x Additions")
to restore proper section nesting under "## v0.15.x".
- Line 80: Update the heading text "# Smaller Changes in 014.x" to the correct
level and version by replacing the leading "#" with the appropriate heading
level (e.g., "## Smaller Changes in 0.14.x") and fix the typo "014.x" to
"0.14.x" so the heading reads "## Smaller Changes in 0.14.x".

In `@src/renderer/components/Settings/tabs/GeneralTab.tsx`:
- Around line 180-182: Replace the empty .catch handler in the agent detection
promise inside GeneralTab (the anonymous .catch block currently swallowing
errors) with logic that calls the Sentry utility (import captureException or
captureMessage from src/utils/sentry.ts) to report the error with context (e.g.,
"Agent detection failed in GeneralTab") and then re-throw the error for
unexpected failures; ensure the catch still handles known/expected cases (e.g.,
ignore a specific benign error) but otherwise reports via
captureException(caughtError) before throwing so Sentry can observe the failure.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ce8186b9-3e2d-409b-b5d6-d1a6a3fe2077

📥 Commits

Reviewing files that changed from the base of the PR and between 94ccdf8 and 3f52a56.

📒 Files selected for processing (12)
  • docs/releases.md
  • src/__tests__/main/ipc/handlers/tabNaming.test.ts
  • src/main/index.ts
  • src/main/ipc/handlers/context.ts
  • src/main/ipc/handlers/index.ts
  • src/main/ipc/handlers/tabNaming.ts
  • src/main/stores/defaults.ts
  • src/main/utils/context-groomer.ts
  • src/renderer/components/Settings/tabs/GeneralTab.tsx
  • src/renderer/hooks/settings/useSettings.ts
  • src/renderer/stores/settingsStore.ts
  • src/shared/settingsMetadata.ts

Comment thread docs/releases.md
- **Group chat participant management:** Remove button on participant cards lets you remove stale or unwanted participants from a group chat
- **Batch resume/abort:** New controls in the right panel for resuming or aborting batch operations
- **Default worktree directory:** Worktree configuration now defaults to the parent of the agent's working directory instead of blank
# Major 0.15.x Additions
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use a nested heading level here (not H1).

Line 20 resets to # inside a ## v0.15.x section, which breaks document hierarchy/navigation. Use ### (or ### Major 0.15.x Additions) instead.

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

In `@docs/releases.md` at line 20, The heading "Major 0.15.x Additions" is using
an H1 marker ("#") inside the "## v0.15.x" section which breaks hierarchy;
change the line containing "Major 0.15.x Additions" from "# Major 0.15.x
Additions" to a nested heading such as "### Major 0.15.x Additions" (or "###
Major 0.15.x Additions") to restore proper section nesting under "## v0.15.x".

Comment thread docs/releases.md

The major contributions to 0.14.x remain:

🗄️ Document Graphs. Launch from file preview or from the FIle tree panel. Explore relationships between Markdown documents that contain links between documents and to URLs.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo in “FIle tree panel”.

Line 74 should be “File tree panel”.

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

In `@docs/releases.md` at line 74, In the "Document Graphs" sentence that
currently reads "Launch from file preview or from the FIle tree panel," fix the
typo by changing "FIle tree panel" to "File tree panel" so the phrase reads
"Launch from file preview or from the File tree panel."

Comment thread docs/releases.md

🧙‍♂️ Added an in-tab wizard for generating Auto Run Playbooks via `/wizard` or a new button in the Auto Run panel.

# Smaller Changes in 014.x
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Correct heading level and version typo.

Line 80 should not be #, and “014.x” appears to be a typo for “0.14.x”.

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

In `@docs/releases.md` at line 80, Update the heading text "# Smaller Changes in
014.x" to the correct level and version by replacing the leading "#" with the
appropriate heading level (e.g., "## Smaller Changes in 0.14.x") and fix the
typo "014.x" to "0.14.x" so the heading reads "## Smaller Changes in 0.14.x".

Comment thread docs/releases.md

## Context Management Tools

📖 Added context management options from tab right-click menu. You can now compress, merge, and transfer contexts between agents. You will received (configurable) warnings at 60% and 80% context consumption with a hint to compact.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix grammar in context-management description.

Line 153 says “You will received”; this should be “You will receive”.

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

In `@docs/releases.md` at line 153, Fix the grammar in the release note sentence
that currently reads "You will received (configurable) warnings at 60% and 80%
context consumption with a hint to compact" by changing "received" to "receive"
so the sentence reads "...You will receive (configurable) warnings at 60% and
80% context consumption with a hint to compact"; update the same sentence text
in docs/releases.md (the context-management release note line) accordingly.

Comment on lines +180 to +182
.catch(() => {
// Silently fail - dropdown will just be empty
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Do not silently swallow agent detection failures.

The empty .catch() hides unexpected failures and drops observability for this settings flow.

Suggested fix
+import { captureException } from '../../../../utils/sentry';
...
-			.catch(() => {
-				// Silently fail - dropdown will just be empty
-			});
+			.catch((error) => {
+				if (cancelled) return;
+				captureException(error instanceof Error ? error : new Error(String(error)));
+			});

As per coding guidelines: "Do not silently swallow errors... For unexpected errors, re-throw them to allow Sentry to capture them. Use Sentry utilities (captureException, captureMessage) from src/utils/sentry.ts for explicit error reporting with context."

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

In `@src/renderer/components/Settings/tabs/GeneralTab.tsx` around lines 180 - 182,
Replace the empty .catch handler in the agent detection promise inside
GeneralTab (the anonymous .catch block currently swallowing errors) with logic
that calls the Sentry utility (import captureException or captureMessage from
src/utils/sentry.ts) to report the error with context (e.g., "Agent detection
failed in GeneralTab") and then re-throw the error for unexpected failures;
ensure the catch still handles known/expected cases (e.g., ignore a specific
benign error) but otherwise reports via captureException(caughtError) before
throwing so Sentry can observe the failure.

@scriptease
Copy link
Copy Markdown

Looks great!

Copy link
Copy Markdown
Contributor

@chr1syy chr1syy left a comment

Choose a reason for hiding this comment

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

Took a fresh look at this in the context of where main is now. The concept and core wiring are solid — clean effectiveAgentType indirection through tabNaming.ts and context.ts, modelId only flowing when utilityAgentId is set, defaults of null preserving existing behavior, SSH/custom-config passthrough intact. The new UI section in GeneralTab.tsx matches the surrounding pattern.

That said, I think there are four things to address before this can merge cleanly:

Blockers

  1. docs/releases.md is hand-edited. The branch's second commit (3f52a562e — chore: fix pre-existing prettier formatting in releases.md) reformats the file (+254/-240). CLAUDE.md explicitly says "docs/releases.md is generated/updated automatically during release pressing. Never modify it manually — even when shipping user-facing changes that would seem to warrant a release note entry. The release tooling handles it." Worth reverting that commit so the diff stays scoped to the utility-agent feature.

  2. No settingsMetadata.ts entries for the new settings. src/shared/settingsMetadata.ts has landed on main since this PR branched (it's the source of truth used by maestro-cli settings list/get/set). utilityAgentId and utilityModelId get added to defaults.ts and the Zustand store but not to the metadata registry, so they'll be invisible to the CLI and to LLM context that reads the registry. Each needs an entry with description, type, default, and a category (integrations feels right).

  3. Stale base — ~32 release-merges behind main. Merge base is at 94ccdf843 (v0.16.9-RC). The conflict surface goes well past the utility-agent feature; settingsStore.ts, useSettings.ts, main/index.ts, and GeneralTab.tsx have all moved on substantially. Rebase is going to be material.

  4. Probably wants rc as the base, not main. Per the standing branching policy (also called out on #1072), features bake on rc first. If retargeted to rc, this also needs:

    • An entry in src/renderer/components/Settings/searchableSettings.ts (only exists on rc)
    • data-setting-id="utilityAgentId" / data-setting-id="utilityModelId" markers on the rendered controls in GeneralTab.tsx so settings search can find them

Non-blocking

  1. No test for the utility-agent code path. The change to tabNaming.test.ts is a mock fix-up that returns null defaults — i.e. it asserts the baseline behavior didn't break. Worth adding at least one case that sets utilityAgentId (and optionally utilityModelId) and asserts the alternate agent is detected/spawned and modelId flows through to buildAgentArgs. Same for context.ts groom.

  2. SSH + utility-agent interaction is unspecified. When a session is on SSH and the user picks a local utility agent (or vice versa), the session's sshRemoteConfig is still passed through. Probably fine as a first cut, but worth a comment in the handler pinning down the chosen semantics so this doesn't drift later.

Concept-approved — happy to re-review once the four blockers are cleared.

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.

Feature: Configurable Utility Agent for Auxiliary Tasks (Tab Naming, Summaries, Toasts)**

3 participants