Skip to content

feat(agents): add agents list and demote presets to UI configuration#4097

Merged
saddlepaddle merged 2 commits intomainfrom
feat/cli-agents-list
May 5, 2026
Merged

feat(agents): add agents list and demote presets to UI configuration#4097
saddlepaddle merged 2 commits intomainfrom
feat/cli-agents-list

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented May 5, 2026

Summary

Adds superset agents list for the CLI/SDK/MCP and reshapes how the host service exposes terminal-agent presets.

Why this design. The host service was exposing two parallel concepts as runtime data: configured rows (hostAgentConfigs) and a hardcoded preset catalog (AGENT_PRESETS). The catalog isn't actually data — it's static configuration that ships with the host-service binary, version-locked to whatever desktop release the user has installed. Treating it as a runtime API resource forced the desktop detail view to fetch the catalog separately just to render row descriptions, made add validate presetId against an enum that blocks truly custom agents, and bloated the CLI/SDK/MCP with a parallel listPresets surface.

Changes

Shared:

  • New packages/shared/src/host-agent-presets.ts exporting HOST_AGENT_PRESETS and HostAgentPreset (V2 host-service preset list, moved out of the host service so the desktop renderer can import it directly). Named distinctly from V1's AgentPresetField / AgentPresetOverride types in packages/shared/src/agent-settings.ts — the V1 desktop agent settings system is untouched.

Host service (packages/host-service/src/trpc/router/settings/agent-configs.ts):

  • Drop settings.agentConfigs.listPresets procedure entirely.
  • Drop presetIdSchema enum validation. add now accepts { label, command, args, promptTransport, promptArgs, env, presetId? } — the full launch row. presetId is free-form metadata used by clients for icon/description lookup, defaulting to "custom" when omitted. Truly custom agents are now possible at the API level.
  • Seed list (getDefaultSeedPresets) imported from @superset/shared/host-agent-presets. listPresets exporter on the host-service settings barrel removed.

Desktop (apps/desktop/...V2AgentsSettings/...):

  • V2AgentsSettings.tsx no longer fetches listPresets. Reads the bundled HOST_AGENT_PRESETS const from shared and builds the description map locally. addMutation sends the full row body (preset minus description).
  • AgentsSettingsSidebar typed against HostAgentPreset from shared. Picker click hands the full preset object up to the parent.
  • AgentDetail.tsx switches PromptTransport import from @superset/host-service/settings@superset/shared/agent-prompt-launch.

CLI:

  • New superset agents list command (packages/cli/src/commands/agents/list/command.ts) with --host <id> / --local (mutually exclusive). Returns configured rows; columns LABEL | PRESET | COMMAND | ID. No --presets flag — the catalog isn't runtime data.

SDK:

  • New Agents resource exposing list({ hostId }) and run({ workspaceId, agent, prompt, attachmentIds? }, { hostId? }). run resolves the host via the cloud workspace lookup when hostId is omitted, matching the CLI ergonomics.

MCP:

  • New agents_list tool. New hostServiceQuery GET helper in packages/mcp-v2/src/host-service-client.ts (the existing helper only handled mutations).

Out of scope

  • "Custom agent" form in the desktop picker (UI for entering a label/command/args/env). API supports it now; UI lands in a follow-up.
  • agents add in the CLI / SDK / MCP for headless custom installs.
  • Unifying the V1 (packages/shared/src/builtin-terminal-agents.ts) and V2 (packages/shared/src/host-agent-presets.ts) catalogs into one. The codebase had two parallel preset lists for the same 9 agents in different shapes before this PR; merging them is a separate refactor.

Verification

  • bun run lint and bun run typecheck (turbo, full repo) clean.
  • bun test src/trpc/router/settings/agent-configs.test.ts in packages/host-service — 21 pass, including new "accepts a fully custom row" and "preserves an arbitrary presetId tag" cases.
  • bun run build in packages/sdk clean.
  • CLI smoke against the local host:
$ superset agents list --local
LABEL    PRESET   COMMAND  ID
Claude   claude   claude   c554d6ef-...
Amp      amp      amp      a50f1972-...
Codex    codex    codex    3781a5f2-...
Gemini   gemini   gemini   950b578c-...
Copilot  copilot  copilot  15eb453e-...

$ superset agents list --local --presets
Error: Unknown option: --presets

$ superset agents list
Error: Target host required
Hint: Pass --local for this machine, or --host <id> for a specific host.

Test plan

  • Repo-wide lint + typecheck clean
  • host-service agent-configs.test.ts rewritten for new add shape and passing
  • SDK builds clean
  • CLI agents list --local prints configured rows
  • --presets flag is gone (errors with "Unknown option")
  • Desktop end-to-end: open Settings → Agents, add Claude (existing preset), add a row via API with presetId: "custom", verify icon fallback and description fallback render correctly. Left for the next reviewer with a desktop checkout.

Summary by CodeRabbit

  • New Features

    • New CLI command to list agents configured on a host (renders a table of agent rows).
    • SDK adds agent management APIs for listing and running agents.
    • MCP tooling registered for agent discovery and execution.
  • User-facing Changes

    • Agent settings now use a centralized host preset catalog.
    • Adding agents accepts full host-config payloads; desktop UI now passes full preset objects when adding.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 5, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Add end-to-end agent support: shared host presets, host-service agent-config schema and endpoints, MCP host-call refactor and new tools (agents_list), SDK Agents resource, CLI agents list command, desktop settings UI updates, and tests adapted for the new add flow.

Changes

Agent List / Run (single cohesive change DAG)

Layer / File(s) Summary
Shared preset types & data
packages/shared/src/host-agent-presets.ts, packages/shared/package.json
Introduce HostAgentPreset and HOST_AGENT_PRESETS; export subpath ./host-agent-presets; import PromptTransport from shared prompt-launch package.
Host service router data shape
packages/host-service/src/trpc/router/settings/agent-configs.ts, packages/host-service/src/trpc/router/settings/index.ts
Remove listPresets; add HostAgentConfig interface and addInputSchema; add now accepts full launch payload (label, command, args, promptTransport, promptArgs, env, optional presetId) and returns HostAgentConfig; update transformations to use HostAgentPreset.
Host-service client transport
packages/mcp-v2/src/host-service-client.ts
Replace previous mutation helper with unified hostServiceCall<TOutput>(options, procedure, method, input?); support "query" (GET with encoded input) and "mutation" (POST JSON); simplify error handling and remove timeout/AbortController and HostServiceCallError.
MCP tool wiring
packages/mcp-v2/src/tools/agents/list.ts, packages/mcp-v2/src/tools/agents/run.ts, packages/mcp-v2/src/tools/workspaces/create.ts, packages/mcp-v2/src/tools/workspaces/delete.ts, packages/mcp-v2/src/tools/register.ts
Add agents_list tool (calls settings.agentConfigs.list via hostServiceCall(..., "query")); update existing tools (agents_run, workspace create/delete) to call hostServiceCall(..., "mutation"); register new tool in registrars.
SDK resource & client surface
packages/sdk/src/resources/agents.ts, packages/sdk/src/resources/index.ts, packages/sdk/src/client.ts, packages/sdk/src/index.ts
Add Agents API resource with list (host query to settings.agentConfigs.list) and run (resolve hostId/workspace then host mutation agents.run); export HostAgentConfig, request/response types, PromptTransport; attach agents property and static alias to Superset client.
CLI command & meta
packages/cli/src/commands/agents/list/command.ts, packages/cli/src/commands/agents/meta.ts
Add agents list CLI command with --host/--local options; validates organizationId (throws CLIError if missing), resolves and authenticates host target, and queries settings.agentConfigs.list to render table; update agents meta description to "Manage and run agents".
Desktop settings UI
apps/desktop/src/renderer/.../V2AgentsSettings.tsx, .../AgentsSettingsSidebar.tsx, .../AgentDetail/AgentDetail.tsx, .../useV2AgentConfigs/*.ts, .../PresetEditorDialog.tsx
Switch to static HOST_AGENT_PRESETS (clone for immutability), build DESCRIPTION_BY_PRESET_ID, compute addablePresets, update prop types to HostAgentConfig/HostAgentPreset, and change add flow to pass full preset object (description stripped) to add mutation; update various components to the new HostAgentConfig type.
Tests
packages/host-service/src/trpc/router/settings/agent-configs.test.ts
Replace hardcoded presets with presetBody() using getPresetById(); extend add() tests to assert full-config insertion, allow duplicate presetId with distinct ids, accept fully custom rows (default presetId = "custom"), preserve arbitrary presetId, and validate empty label/command; update reset seed usage.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI / MCP Tool
    participant SDK as SDK Client (Agents)
    participant Host as Host Service (TRPC)
    participant Desktop as Desktop UI

    CLI->>SDK: Agents.list(hostId, orgId)
    SDK->>Host: GET /trpc/settings.agentConfigs.list?input=...  (host query)
    Host-->>SDK: HostAgentConfig[]
    SDK-->>CLI: AgentListResponse

    Desktop->>Desktop: load HOST_AGENT_PRESETS, build map
    Desktop->>SDK: Agents.run(workspaceId, agent, prompt, orgId)
    SDK->>Host: GET /trpc/v2Workspace.getFromHost?input=...  (resolve host/workspace)
    Host-->>SDK: workspace (with hostId)
    SDK->>Host: POST /trpc/agents.run  (mutation with body)
    Host-->>SDK: AgentRunResult
    SDK-->>Desktop: sessionId, label
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰
I hopped from presets into code,
Made agents list and run in mode,
CLI, SDK, host all sing—
Presets shared, and changes spring.
Hippity-hop, the deploys go!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% 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
Title check ✅ Passed The title accurately describes the main changes: adding agents list functionality and moving preset configuration from runtime API to UI layer.
Description check ✅ Passed The PR description is comprehensive, covering the rationale, specific changes across all affected modules, out-of-scope items, and verification steps.
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 feat/cli-agents-list

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 May 5, 2026

Greptile Summary

  • Adds superset agents list command with --host/--local (mutually exclusive, required) and --presets flags, reusing existing requireHostTarget/resolveHostTarget helpers consistently with other commands.
  • Display mode (3-column preset layout vs. 4-column agent layout) is derived from the shape of the returned data rather than the options.presets flag; an empty preset result will render with wrong headers.
  • meta.ts description updated to "Manage and run agents" to cover the new subcommand.

Confidence Score: 4/5

Safe to merge; the only issue is a display edge case with empty preset results.

P2-only finding: display headers are wrong when --presets returns an empty list, but this doesn't affect correctness of the data or the common case. Core routing and auth logic mirrors existing commands.

packages/cli/src/commands/agents/list/command.ts — display mode-detection heuristic

Important Files Changed

Filename Overview
packages/cli/src/commands/agents/list/command.ts New command wiring requireHostTarget/resolveHostTarget correctly; display mode detection inferred from data shape rather than options flag, causing wrong headers for empty preset results.
packages/cli/src/commands/agents/meta.ts Trivial description update to 'Manage and run agents' to reflect the new list subcommand.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as agents list command
    participant HT as requireHostTarget / resolveHostTarget
    participant HS as Host Service (tRPC)

    User->>CLI: superset agents list [--local|--host id] [--presets]
    CLI->>CLI: check organizationId
    CLI->>HT: requireHostTarget({ host, local })
    HT-->>CLI: hostId (or throw CLIError)
    CLI->>HT: resolveHostTarget({ hostId, orgId, jwt })
    HT-->>CLI: ResolvedHostTarget (local or remote client)
    alt --presets flag
        CLI->>HS: settings.agentConfigs.listPresets.query()
        HS-->>CLI: [{ label, presetId, command }]
    else no --presets flag
        CLI->>HS: settings.agentConfigs.list.query()
        HS-->>CLI: [{ label, presetId, command, id }]
    end
    CLI->>User: table output
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/cli/src/commands/agents/list/command.ts:15-26
**Fragile preset-mode detection in `display`**

`isPresetMode` is inferred from the absence of an `id` field in the first row rather than from the `options.presets` flag, which is not forwarded to `display`. This works today because the two tRPC procedures return differently-shaped objects, but it silently breaks in two edge cases: (1) `--presets` is passed and the server returns an empty list → `isPresetMode` is `false` → the 4-column table (including the "ID" header) is rendered instead of the correct 3-column preset table; (2) if the presets schema ever gains an `id` field, both branches would render the same 4-column layout.

Consider passing mode intent explicitly (e.g. a tagged union `{ kind: "presets"; rows: … } | { kind: "agents"; rows: … }`) or moving the column selection into the `run` handler's return value so `display` doesn't have to reverse-engineer it.

Reviews (1): Last reviewed commit: "feat(cli/agents): add agents list comman..." | Re-trigger Greptile

Comment on lines +15 to +26
const rows = (data ?? []) as Record<string, unknown>[];
const isPresetMode = rows.length > 0 && !("id" in rows[0]!);
return isPresetMode
? table(
rows,
["label", "presetId", "command"],
["LABEL", "PRESET", "COMMAND"],
)
: table(
rows,
["label", "presetId", "command", "id"],
["LABEL", "PRESET", "COMMAND", "ID"],
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Fragile preset-mode detection in display

isPresetMode is inferred from the absence of an id field in the first row rather than from the options.presets flag, which is not forwarded to display. This works today because the two tRPC procedures return differently-shaped objects, but it silently breaks in two edge cases: (1) --presets is passed and the server returns an empty list → isPresetMode is false → the 4-column table (including the "ID" header) is rendered instead of the correct 3-column preset table; (2) if the presets schema ever gains an id field, both branches would render the same 4-column layout.

Consider passing mode intent explicitly (e.g. a tagged union { kind: "presets"; rows: … } | { kind: "agents"; rows: … }) or moving the column selection into the run handler's return value so display doesn't have to reverse-engineer it.

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/cli/src/commands/agents/list/command.ts
Line: 15-26

Comment:
**Fragile preset-mode detection in `display`**

`isPresetMode` is inferred from the absence of an `id` field in the first row rather than from the `options.presets` flag, which is not forwarded to `display`. This works today because the two tRPC procedures return differently-shaped objects, but it silently breaks in two edge cases: (1) `--presets` is passed and the server returns an empty list → `isPresetMode` is `false` → the 4-column table (including the "ID" header) is rendered instead of the correct 3-column preset table; (2) if the presets schema ever gains an `id` field, both branches would render the same 4-column layout.

Consider passing mode intent explicitly (e.g. a tagged union `{ kind: "presets"; rows: … } | { kind: "agents"; rows: … }`) or moving the column selection into the `run` handler's return value so `display` doesn't have to reverse-engineer it.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
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

🤖 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 `@packages/cli/src/commands/agents/list/command.ts`:
- Around line 15-27: The column selection currently infers preset mode from
rows[0] (isPresetMode) which breaks for empty results; instead propagate the
--presets flag from the command's run into the display logic and use that
boolean to decide columns: modify the command's run to pass a explicit
isPresetMode (e.g., derived from options.presets) into the display/table chooser
and update the display code that currently computes isPresetMode from rows to
use that passed boolean when present, keeping the fallback to the original
shape-based check only if the flag is undefined.
🪄 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: 19e66c93-faff-48f7-9e25-1884acaa3ef2

📥 Commits

Reviewing files that changed from the base of the PR and between 1bb6688 and 71df8e0.

📒 Files selected for processing (2)
  • packages/cli/src/commands/agents/list/command.ts
  • packages/cli/src/commands/agents/meta.ts

Comment on lines +15 to +27
const rows = (data ?? []) as Record<string, unknown>[];
const isPresetMode = rows.length > 0 && !("id" in rows[0]!);
return isPresetMode
? table(
rows,
["label", "presetId", "command"],
["LABEL", "PRESET", "COMMAND"],
)
: table(
rows,
["label", "presetId", "command", "id"],
["LABEL", "PRESET", "COMMAND", "ID"],
);
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

Use the --presets flag to drive columns; current shape-based inference is wrong for empty results.

On Line 16, mode is inferred from rows[0]. If --presets returns [], the command falls back to configured-agent headers (ID column), so output no longer reflects the selected mode.

Proposed fix (carry mode from run to display)
 export default command({
@@
-	display: (data) => {
-		const rows = (data ?? []) as Record<string, unknown>[];
-		const isPresetMode = rows.length > 0 && !("id" in rows[0]!);
+	display: (data) => {
+		const payload = (data ?? {
+			rows: [],
+			isPresetMode: false,
+		}) as { rows: Record<string, unknown>[]; isPresetMode: boolean };
+		const { rows, isPresetMode } = payload;
 		return isPresetMode
@@
 	run: async ({ ctx, options }) => {
@@
-		if (options.presets) {
-			return target.client.settings.agentConfigs.listPresets.query();
-		}
-		return target.client.settings.agentConfigs.list.query();
+		if (options.presets) {
+			const rows = await target.client.settings.agentConfigs.listPresets.query();
+			return { rows, isPresetMode: true };
+		}
+		const rows = await target.client.settings.agentConfigs.list.query();
+		return { rows, isPresetMode: false };
 	},
 });
🤖 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 `@packages/cli/src/commands/agents/list/command.ts` around lines 15 - 27, The
column selection currently infers preset mode from rows[0] (isPresetMode) which
breaks for empty results; instead propagate the --presets flag from the
command's run into the display logic and use that boolean to decide columns:
modify the command's run to pass a explicit isPresetMode (e.g., derived from
options.presets) into the display/table chooser and update the display code that
currently computes isPresetMode from rows to use that passed boolean when
present, keeping the fallback to the original shape-based check only if the flag
is undefined.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@saddlepaddle saddlepaddle changed the title feat(cli/agents): add agents list command feat(agents): add list/listPresets to CLI, SDK, and MCP May 5, 2026
Copy link
Copy Markdown
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.

🧹 Nitpick comments (1)
packages/mcp-v2/src/host-service-client.ts (1)

124-155: ⚡ Quick win

Extract shared tRPC response decode/error handling to avoid drift

hostServiceQuery now duplicates the same JSON parse/envelope validation/deserialization branch already present in hostServiceMutation. Pulling this into a shared helper would reduce divergence risk when relay error handling evolves.

Refactor sketch
+function decodeTrpcData<TOutput>(
+  rawBody: string,
+  responseStatus: number,
+  hostId: string,
+  procedure: string,
+): TOutput {
+  type TrpcEnvelope = { result?: { data?: unknown } };
+  let parsed: TrpcEnvelope;
+  try {
+    parsed = JSON.parse(rawBody) as TrpcEnvelope;
+  } catch {
+    throw new HostServiceCallError(
+      `invalid JSON from relay: ${rawBody.slice(0, 200)}`,
+      responseStatus,
+      rawBody,
+    );
+  }
+  const data = parsed.result?.data;
+  if (data === undefined || data === null) {
+    throw new HostServiceCallError(
+      `Malformed response from host ${hostId} for ${procedure}`,
+      responseStatus,
+      rawBody,
+    );
+  }
+  return SuperJSON.deserialize(
+    data as Parameters<typeof SuperJSON.deserialize>[0],
+  ) as TOutput;
+}
🤖 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 `@packages/mcp-v2/src/host-service-client.ts` around lines 124 - 155,
hostServiceQuery duplicates the JSON parse/envelope validation/deserialization
logic that's also in hostServiceMutation; extract that shared logic into a
single helper (e.g., parseTrpcEnvelope or decodeTrpcResponse) that takes
rawBody, response.status, options.hostId, procedure and returns the deserialized
data or throws HostServiceCallError with the same messages (including
describeRelayFailure usage for non-ok responses and JSON parse/ malformed
response messages), then replace the inlined blocks in both hostServiceQuery and
hostServiceMutation to call the new helper and return SuperJSON.deserialize(...)
on the helper result.
🤖 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.

Nitpick comments:
In `@packages/mcp-v2/src/host-service-client.ts`:
- Around line 124-155: hostServiceQuery duplicates the JSON parse/envelope
validation/deserialization logic that's also in hostServiceMutation; extract
that shared logic into a single helper (e.g., parseTrpcEnvelope or
decodeTrpcResponse) that takes rawBody, response.status, options.hostId,
procedure and returns the deserialized data or throws HostServiceCallError with
the same messages (including describeRelayFailure usage for non-ok responses and
JSON parse/ malformed response messages), then replace the inlined blocks in
both hostServiceQuery and hostServiceMutation to call the new helper and return
SuperJSON.deserialize(...) on the helper result.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1da44cdc-32df-43b3-a993-1638c45ab839

📥 Commits

Reviewing files that changed from the base of the PR and between 71df8e0 and 95b0db0.

📒 Files selected for processing (8)
  • packages/mcp-v2/src/host-service-client.ts
  • packages/mcp-v2/src/tools/agents/list.ts
  • packages/mcp-v2/src/tools/agents/list_presets.ts
  • packages/mcp-v2/src/tools/register.ts
  • packages/sdk/src/client.ts
  • packages/sdk/src/index.ts
  • packages/sdk/src/resources/agents.ts
  • packages/sdk/src/resources/index.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/sdk/src/index.ts

@saddlepaddle saddlepaddle force-pushed the feat/cli-agents-list branch from 95b0db0 to e732061 Compare May 5, 2026 20:08
@saddlepaddle saddlepaddle changed the title feat(agents): add list/listPresets to CLI, SDK, and MCP feat(agents): add agents list and demote presets to UI configuration May 5, 2026
Copy link
Copy Markdown
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: 2

Caution

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

⚠️ Outside diff range comments (1)
packages/host-service/src/trpc/router/settings/agent-configs.ts (1)

157-206: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

settings.agentConfigs.listPresets is missing from the router surface.

The settings router no longer exposes a listPresets query, but the PR objective calls out preset listing via this route (--presets/MCP presets tooling). This is a runtime contract break (procedure not found) for those consumers.

Suggested patch
 import {
+	HOST_AGENT_PRESETS,
 	getDefaultSeedPresets,
 	type HostAgentPreset,
 } from "@superset/shared/host-agent-presets";

 export const agentConfigsRouter = router({
+	listPresets: protectedProcedure.query(() =>
+		HOST_AGENT_PRESETS.map((preset) => ({
+			...preset,
+			args: [...preset.args],
+			promptArgs: [...preset.promptArgs],
+			env: { ...preset.env },
+		})),
+	),
+
 	/**
 	 * List configured host agents in persisted order. Seeds bundled defaults
 	 * on first call when no configs exist.
 	 */
 	list: protectedProcedure.query(({ ctx }) => {
🤖 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 `@packages/host-service/src/trpc/router/settings/agent-configs.ts` around lines
157 - 206, The router dropped the listPresets procedure — re-add a
protectedProcedure named listPresets to agentConfigsRouter so callers can list
bundled presets; implement it to return the same preset data used when seeding
defaults (e.g. reuse seedDefaultsIfEmpty or the helper that constructs bundled
presets) and ensure its output shape matches the consumers' expectation (the
same toOutput/DTO structure or a dedicated preset output). Reference:
agentConfigsRouter, listPresets, seedDefaultsIfEmpty, toOutput.
🤖 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 `@packages/cli/src/commands/agents/list/command.ts`:
- Around line 7-16: Add a new boolean option "presets" to the command's options
(alongside host and local), ensure run reads that flag and calls
settings.agentConfigs.listPresets when presets is true (falling back to
settings.agentConfigs.list otherwise), and pass the explicit presets mode into
display so it does not infer mode from results; update display/table invocation
to use columns ["label","presetId","command"] with headers
["LABEL","PRESET","COMMAND"] when presets is true (omit "id"), and keep the
existing four-column display when presets is false.

In `@packages/sdk/src/resources/agents.ts`:
- Around line 13-31: The Agents SDK class is missing a listPresets() method to
mirror server API parity; add a new public method Agents.listPresets(params:
AgentListParams, options?: RequestOptions) that calls this._requireOrgId() then
returns this._client.hostQuery<AgentListResponse>(params.hostId,
"settings.agentConfigs.listPresets", undefined, options) (following the existing
list() pattern) so SDK consumers can retrieve the preset catalog; ensure the new
method name is Agents.listPresets and matches the hostQuery namespace
"settings.agentConfigs.listPresets".

---

Outside diff comments:
In `@packages/host-service/src/trpc/router/settings/agent-configs.ts`:
- Around line 157-206: The router dropped the listPresets procedure — re-add a
protectedProcedure named listPresets to agentConfigsRouter so callers can list
bundled presets; implement it to return the same preset data used when seeding
defaults (e.g. reuse seedDefaultsIfEmpty or the helper that constructs bundled
presets) and ensure its output shape matches the consumers' expectation (the
same toOutput/DTO structure or a dedicated preset output). Reference:
agentConfigsRouter, listPresets, seedDefaultsIfEmpty, toOutput.
🪄 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: c0cc5edf-f8e4-479e-8c90-5e085656d822

📥 Commits

Reviewing files that changed from the base of the PR and between 95b0db0 and e732061.

📒 Files selected for processing (17)
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/V2AgentsSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/components/AgentDetail/AgentDetail.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/components/AgentsSettingsSidebar/AgentsSettingsSidebar.tsx
  • packages/cli/src/commands/agents/list/command.ts
  • packages/cli/src/commands/agents/meta.ts
  • packages/host-service/src/trpc/router/settings/agent-configs.test.ts
  • packages/host-service/src/trpc/router/settings/agent-configs.ts
  • packages/host-service/src/trpc/router/settings/index.ts
  • packages/mcp-v2/src/host-service-client.ts
  • packages/mcp-v2/src/tools/agents/list.ts
  • packages/mcp-v2/src/tools/register.ts
  • packages/sdk/src/client.ts
  • packages/sdk/src/index.ts
  • packages/sdk/src/resources/agents.ts
  • packages/sdk/src/resources/index.ts
  • packages/shared/package.json
  • packages/shared/src/host-agent-presets.ts
💤 Files with no reviewable changes (1)
  • packages/host-service/src/trpc/router/settings/index.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/cli/src/commands/agents/meta.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/components/AgentDetail/AgentDetail.tsx
  • packages/sdk/src/client.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/mcp-v2/src/tools/agents/list.ts
  • packages/mcp-v2/src/tools/register.ts
  • packages/mcp-v2/src/host-service-client.ts

Comment on lines +7 to +16
options: {
host: string().desc("Target host machineId"),
local: boolean().desc("Target this machine"),
},
display: (data) =>
table(
(data ?? []) as Record<string, unknown>[],
["label", "presetId", "command", "id"],
["LABEL", "PRESET", "COMMAND", "ID"],
),
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

--presets / listPresets flag is absent — contradicts the PR objective.

The PR description explicitly specifies that superset agents list --presets should switch to settings.agentConfigs.listPresets with columns LABEL | PRESET | COMMAND (no ID column). The current implementation only exposes settings.agentConfigs.list and has no --presets option at all.

The previous commit included a --presets flag but contained a bug where preset mode was inferred from rows[0], which broke on empty results. The current commit resolves the bug by removing the feature entirely. If --presets is intentionally deferred, please note it in the PR; otherwise the flag needs to be reinstated with the mode flag propagated explicitly from run to display.

💡 Proposed fix to reinstate --presets with explicit mode propagation
 export default command({
 	description: "List agents configured on a host",
 	options: {
 		host: string().desc("Target host machineId"),
 		local: boolean().desc("Target this machine"),
+		presets: boolean().desc("List available agent presets"),
 	},
-	display: (data) =>
-		table(
-			(data ?? []) as Record<string, unknown>[],
-			["label", "presetId", "command", "id"],
-			["LABEL", "PRESET", "COMMAND", "ID"],
-		),
+	display: (data) => {
+		const payload = (data ?? { rows: [], isPresetMode: false }) as {
+			rows: Record<string, unknown>[];
+			isPresetMode: boolean;
+		};
+		return payload.isPresetMode
+			? table(payload.rows, ["label", "presetId", "command"], ["LABEL", "PRESET", "COMMAND"])
+			: table(payload.rows, ["label", "presetId", "command", "id"], ["LABEL", "PRESET", "COMMAND", "ID"]);
+	},
 	run: async ({ ctx, options }) => {
 		// ... existing organizationId guard and host resolution ...

-		return target.client.settings.agentConfigs.list.query();
+		if (options.presets) {
+			const rows = await target.client.settings.agentConfigs.listPresets.query();
+			return { rows, isPresetMode: true };
+		}
+		const rows = await target.client.settings.agentConfigs.list.query();
+		return { rows, isPresetMode: false };
 	},
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
options: {
host: string().desc("Target host machineId"),
local: boolean().desc("Target this machine"),
},
display: (data) =>
table(
(data ?? []) as Record<string, unknown>[],
["label", "presetId", "command", "id"],
["LABEL", "PRESET", "COMMAND", "ID"],
),
export default command({
description: "List agents configured on a host",
options: {
host: string().desc("Target host machineId"),
local: boolean().desc("Target this machine"),
presets: boolean().desc("List available agent presets"),
},
display: (data) => {
const payload = (data ?? { rows: [], isPresetMode: false }) as {
rows: Record<string, unknown>[];
isPresetMode: boolean;
};
return payload.isPresetMode
? table(payload.rows, ["label", "presetId", "command"], ["LABEL", "PRESET", "COMMAND"])
: table(payload.rows, ["label", "presetId", "command", "id"], ["LABEL", "PRESET", "COMMAND", "ID"]);
},
run: async ({ ctx, options }) => {
// ... existing organizationId guard and host resolution ...
if (options.presets) {
const rows = await target.client.settings.agentConfigs.listPresets.query();
return { rows, isPresetMode: true };
}
const rows = await target.client.settings.agentConfigs.list.query();
return { rows, isPresetMode: false };
},
});
🤖 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 `@packages/cli/src/commands/agents/list/command.ts` around lines 7 - 16, Add a
new boolean option "presets" to the command's options (alongside host and
local), ensure run reads that flag and calls settings.agentConfigs.listPresets
when presets is true (falling back to settings.agentConfigs.list otherwise), and
pass the explicit presets mode into display so it does not infer mode from
results; update display/table invocation to use columns
["label","presetId","command"] with headers ["LABEL","PRESET","COMMAND"] when
presets is true (omit "id"), and keep the existing four-column display when
presets is false.

Comment on lines +13 to +31
export class Agents extends APIResource {
/**
* List agents configured on a host — the rows that drive the agent picker
* inside workspaces, in persisted display order. Includes user edits to
* label/command/args/env. First call on a fresh host seeds bundled
* defaults.
*
* Mirrors `superset agents list --host <id>`.
*/
list(params: AgentListParams, options?: RequestOptions) {
this._requireOrgId();
return this._client.hostQuery<AgentListResponse>(
params.hostId,
"settings.agentConfigs.list",
undefined,
options,
);
}

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

SDK Agents resource is missing listPresets() API parity.

This class exposes list() and run() only, but the PR objective includes SDK preset catalog listing. Without listPresets(), SDK consumers can’t access the same preset-list feature exposed in other surfaces.

Suggested patch
 export class Agents extends APIResource {
@@
 	list(params: AgentListParams, options?: RequestOptions) {
 		this._requireOrgId();
 		return this._client.hostQuery<AgentListResponse>(
 			params.hostId,
 			"settings.agentConfigs.list",
 			undefined,
 			options,
 		);
 	}
+
+	listPresets(params: AgentListPresetsParams, options?: RequestOptions) {
+		this._requireOrgId();
+		return this._client.hostQuery<AgentListPresetsResponse>(
+			params.hostId,
+			"settings.agentConfigs.listPresets",
+			undefined,
+			options,
+		);
+	}
@@
 export interface AgentListParams {
 	/** Host machineId to query (see `hosts.list()`). */
 	hostId: string;
 }
+
+export interface AgentPreset {
+	presetId: string;
+	label: string;
+	description: string;
+	command: string;
+	args: string[];
+	promptTransport: PromptTransport;
+	promptArgs: string[];
+	env: Record<string, string>;
+}
+
+export interface AgentListPresetsParams {
+	hostId: string;
+}
+
+export type AgentListPresetsResponse = Array<AgentPreset>;
@@
 	export type {
 		HostAgentConfig,
 		AgentListResponse,
 		AgentListParams,
+		AgentPreset,
+		AgentListPresetsParams,
+		AgentListPresetsResponse,
 		AgentRunParams,
 		AgentRunResult,
 		PromptTransport,
 	};
 }

Also applies to: 92-129

🤖 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 `@packages/sdk/src/resources/agents.ts` around lines 13 - 31, The Agents SDK
class is missing a listPresets() method to mirror server API parity; add a new
public method Agents.listPresets(params: AgentListParams, options?:
RequestOptions) that calls this._requireOrgId() then returns
this._client.hostQuery<AgentListResponse>(params.hostId,
"settings.agentConfigs.listPresets", undefined, options) (following the existing
list() pattern) so SDK consumers can retrieve the preset catalog; ensure the new
method name is Agents.listPresets and matches the hostQuery namespace
"settings.agentConfigs.listPresets".

@saddlepaddle saddlepaddle force-pushed the feat/cli-agents-list branch from e732061 to 5ba5a49 Compare May 5, 2026 20:30
Copy link
Copy Markdown
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: 2

🤖 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 `@packages/mcp-v2/src/host-service-client.ts`:
- Around line 40-44: The unified fetch call (the response = await fetch(url, {
... })) no longer uses a timeout so host relay requests can hang indefinitely;
restore support for the timeoutMs option by creating an AbortSignal (preferably
using AbortSignal.timeout(timeoutMs) if available, falling back to an
AbortController with setTimeout) and pass it as signal to the fetch call, ensure
the signal is aborted on timeout and that the thrown error propagates so callers
can handle timeouts (update the code that constructs headers/body/method around
response = await fetch(...) to include signal and preserve existing behavior).
- Around line 35-38: In the mutation branch where you currently do
headers["content-type"] = "application/json"; body =
JSON.stringify(SuperJSON.serialize(input)); guard against serializing undefined
by only setting the content-type and body when input is actually provided (e.g.
if (typeof input !== "undefined") { headers["content-type"] =
"application/json"; body = JSON.stringify(SuperJSON.serialize(input)); }).
Reference the existing use of SuperJSON.serialize(input) and the mutation branch
logic to locate where to add the check so void/omitted inputs produce no JSON
body.
🪄 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: e2bb27ee-c513-4eae-aea7-e8373c56239a

📥 Commits

Reviewing files that changed from the base of the PR and between e732061 and 5ba5a49.

📒 Files selected for processing (20)
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/V2AgentsSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/components/AgentDetail/AgentDetail.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/components/AgentsSettingsSidebar/AgentsSettingsSidebar.tsx
  • packages/cli/src/commands/agents/list/command.ts
  • packages/cli/src/commands/agents/meta.ts
  • packages/host-service/src/trpc/router/settings/agent-configs.test.ts
  • packages/host-service/src/trpc/router/settings/agent-configs.ts
  • packages/host-service/src/trpc/router/settings/index.ts
  • packages/mcp-v2/src/host-service-client.ts
  • packages/mcp-v2/src/tools/agents/list.ts
  • packages/mcp-v2/src/tools/agents/run.ts
  • packages/mcp-v2/src/tools/register.ts
  • packages/mcp-v2/src/tools/workspaces/create.ts
  • packages/mcp-v2/src/tools/workspaces/delete.ts
  • packages/sdk/src/client.ts
  • packages/sdk/src/index.ts
  • packages/sdk/src/resources/agents.ts
  • packages/sdk/src/resources/index.ts
  • packages/shared/package.json
  • packages/shared/src/host-agent-presets.ts
💤 Files with no reviewable changes (1)
  • packages/host-service/src/trpc/router/settings/index.ts
✅ Files skipped from review due to trivial changes (4)
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/components/AgentDetail/AgentDetail.tsx
  • packages/sdk/src/client.ts
  • packages/cli/src/commands/agents/meta.ts
  • packages/sdk/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/sdk/src/resources/index.ts
  • packages/cli/src/commands/agents/list/command.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/V2AgentsSettings.tsx
  • packages/host-service/src/trpc/router/settings/agent-configs.test.ts
  • packages/sdk/src/resources/agents.ts
  • packages/mcp-v2/src/tools/register.ts

Comment on lines +35 to 38
} else {
headers["content-type"] = "application/json";
body = JSON.stringify(SuperJSON.serialize(input));
}
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 serializing undefined in the mutation branch

When input is omitted (allowed by input?: unknown), SuperJSON.serialize(undefined) is called unconditionally. The resulting JSON body ({} after JSON.stringify drops the undefined json field) will surprise any future mutation procedure that accepts void/no input, and will likely produce a cryptic TRPC validation error.

🛡️ Proposed fix
  } else {
    headers["content-type"] = "application/json";
-   body = JSON.stringify(SuperJSON.serialize(input));
+   if (input !== undefined) {
+     body = JSON.stringify(SuperJSON.serialize(input));
+   }
  }
🤖 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 `@packages/mcp-v2/src/host-service-client.ts` around lines 35 - 38, In the
mutation branch where you currently do headers["content-type"] =
"application/json"; body = JSON.stringify(SuperJSON.serialize(input)); guard
against serializing undefined by only setting the content-type and body when
input is actually provided (e.g. if (typeof input !== "undefined") {
headers["content-type"] = "application/json"; body =
JSON.stringify(SuperJSON.serialize(input)); }). Reference the existing use of
SuperJSON.serialize(input) and the mutation branch logic to locate where to add
the check so void/omitted inputs produce no JSON body.

Comment on lines +40 to +44
const response = await fetch(url, {
method: method === "query" ? "GET" : "POST",
headers,
body,
});
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

Missing fetch timeout leaves MCP tool calls exposed to indefinite hangs

The previous implementation accepted a timeoutMs option and wired it to an AbortController. The new unified function removes this entirely, meaning a slow or unresponsive host relay will stall the MCP tool call forever — blocking the AI session with no recovery path.

AbortSignal.timeout() returns an AbortSignal that automatically aborts after a specified time, throwing a TimeoutError on expiry. Node.js was the first runtime to add support for AbortSignal.timeout(), backported to the v16 Active LTS release line.

⏱️ Proposed fix
+const DEFAULT_TIMEOUT_MS = 30_000;

 export interface HostServiceCallOptions {
   relayUrl: string;
   organizationId: string;
   hostId: string;
   jwt: string;
+  timeoutMs?: number;
 }

 ...

  const response = await fetch(url, {
    method: method === "query" ? "GET" : "POST",
    headers,
    body,
+   signal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS),
  });
🤖 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 `@packages/mcp-v2/src/host-service-client.ts` around lines 40 - 44, The unified
fetch call (the response = await fetch(url, { ... })) no longer uses a timeout
so host relay requests can hang indefinitely; restore support for the timeoutMs
option by creating an AbortSignal (preferably using
AbortSignal.timeout(timeoutMs) if available, falling back to an AbortController
with setTimeout) and pass it as signal to the fetch call, ensure the signal is
aborted on timeout and that the thrown error propagates so callers can handle
timeouts (update the code that constructs headers/body/method around response =
await fetch(...) to include signal and preserve existing behavior).

Adds `superset agents list` for the CLI/SDK/MCP and reshapes how the
host service exposes terminal-agent presets.

**Why.** The host service was exposing two parallel concepts as runtime
data: configured rows (`hostAgentConfigs`) and a hardcoded preset
catalog (`AGENT_PRESETS`). The catalog isn't actually data — it's
static configuration that ships with the host-service binary, version-
locked to whatever desktop release the user has installed. Treating it
as a runtime API resource forced the desktop detail view to fetch the
catalog separately just to render row descriptions, made `add` validate
`presetId` against an enum that blocks truly custom agents, and bloated
the CLI/SDK/MCP with a parallel `listPresets` surface.

**Changes.**
- Move `AGENT_PRESETS` (V2 host-service preset list) from the host
  service into `packages/shared/src/host-agent-presets.ts` as
  `HOST_AGENT_PRESETS` / `HostAgentPreset` (named distinctly from V1's
  `AgentPresetField` / `AgentPresetOverride` types in the V1 desktop
  agent settings system, which is untouched).
- Drop `settings.agentConfigs.listPresets` from the host service. The
  desktop V2 agents picker now reads the bundled const directly.
- Reshape `settings.agentConfigs.add` to accept the full launch row
  (`{ label, command, args, promptTransport, promptArgs, env,
  presetId? }`). `presetId` is now free-form metadata used by the
  client for icon and description lookup, defaulting to `"custom"`
  when omitted. Truly custom agents are now possible at the API level.
- Add `superset agents list` for configured rows (no `--presets` flag —
  the catalog isn't runtime data).
- Add `Agents` resource to the SDK (`agents.list`, `agents.run` —
  routes the run through the cloud workspace lookup like the CLI does).
- Add `agents_list` MCP tool, plus a new `hostServiceQuery` GET helper
  in `packages/mcp-v2/src/host-service-client.ts` (the existing helper
  only handled mutations).

**Out of scope.** "Custom agent" form in the desktop picker (UI to enter
a label/command/args/env), `agents add` in the CLI/SDK/MCP for headless
custom installs, and unifying the V1 (`BUILTIN_TERMINAL_AGENTS`) and V2
(`HOST_AGENT_PRESETS`) catalogs into one. Those each deserve their own
PR.

**Verification.**
- `bun run lint` and `bun run typecheck` (turbo, full repo) clean.
- `bun test packages/host-service/src/trpc/router/settings/agent-configs.test.ts` — 21 pass, including the new "accepts a fully custom row" and "preserves an arbitrary presetId tag" cases.
- `bun run build` in `packages/sdk` clean.
- `superset agents list --local` prints the configured-row table.
- `superset agents list --local --presets` errors with "Unknown option".
# Conflicts:
#	apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/V2AgentsSettings.tsx
#	packages/mcp-v2/src/host-service-client.ts
Copy link
Copy Markdown
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.

♻️ Duplicate comments (1)
packages/mcp-v2/src/host-service-client.ts (1)

4-9: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reintroduce a timeout on relay calls.

fetch no longer has any abort path here, so a wedged relay/host can hang agents_run, agents_list, workspaces_create, and workspaces_delete indefinitely. Please restore timeoutMs on HostServiceCallOptions and pass a signal into fetch; verify the target runtime before choosing AbortSignal.timeout() versus an AbortController fallback.

Also applies to: 40-44

🤖 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 `@packages/mcp-v2/src/host-service-client.ts` around lines 4 - 9, The
HostServiceCallOptions interface lost timeout support causing fetch calls in
HostServiceClient paths (e.g., agents_run, agents_list, workspaces_create,
workspaces_delete) to hang; restore a numeric timeoutMs on
HostServiceCallOptions, create an AbortSignal for each call and pass it into
fetch via the signal option, and detect the environment to use
AbortSignal.timeout(timeoutMs) when available or fall back to creating an
AbortController and setTimeout to abort after timeoutMs, ensuring you clear the
timer when the request finishes.
🧹 Nitpick comments (1)
packages/host-service/src/trpc/router/settings/agent-configs.ts (1)

173-206: 💤 Low value

Optional: wrap insert + read-back in a transaction.

The add mutation issues an INSERT followed by a separate SELECT to read the row back. Other procedures in this file (reorder, resetToDefaults) intentionally use ctx.db.transaction to avoid intermediate observable states. While SQLite's default isolation makes this safe in practice for a freshly-inserted UUID, wrapping the two statements in a single transaction would make the pattern consistent with the rest of the router and is cheap to do.

🤖 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 `@packages/host-service/src/trpc/router/settings/agent-configs.ts` around lines
173 - 206, The add mutation currently does an insert then a separate select;
wrap those two operations in a single ctx.db.transaction to match other
procedures (like reorder and resetToDefaults) and avoid intermediate observable
states: inside the transaction call perform
ctx.db.insert(...).values({...}).run(), then
ctx.db.select().from(hostAgentConfigs).where(eq(hostAgentConfigs.id, id)).get(),
check for created and throw the same TRPCError if missing, and finally return
toOutput(created); keep existing use of listOrdered, randomUUID, and the
hostAgentConfigs identifiers unchanged.
🤖 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.

Duplicate comments:
In `@packages/mcp-v2/src/host-service-client.ts`:
- Around line 4-9: The HostServiceCallOptions interface lost timeout support
causing fetch calls in HostServiceClient paths (e.g., agents_run, agents_list,
workspaces_create, workspaces_delete) to hang; restore a numeric timeoutMs on
HostServiceCallOptions, create an AbortSignal for each call and pass it into
fetch via the signal option, and detect the environment to use
AbortSignal.timeout(timeoutMs) when available or fall back to creating an
AbortController and setTimeout to abort after timeoutMs, ensuring you clear the
timer when the request finishes.

---

Nitpick comments:
In `@packages/host-service/src/trpc/router/settings/agent-configs.ts`:
- Around line 173-206: The add mutation currently does an insert then a separate
select; wrap those two operations in a single ctx.db.transaction to match other
procedures (like reorder and resetToDefaults) and avoid intermediate observable
states: inside the transaction call perform
ctx.db.insert(...).values({...}).run(), then
ctx.db.select().from(hostAgentConfigs).where(eq(hostAgentConfigs.id, id)).get(),
check for created and throw the same TRPCError if missing, and finally return
toOutput(created); keep existing use of listOrdered, randomUUID, and the
hostAgentConfigs identifiers unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4b14299f-6fef-413e-84ca-b3c9b3929a59

📥 Commits

Reviewing files that changed from the base of the PR and between 5ba5a49 and 3aca0f4.

📒 Files selected for processing (22)
  • apps/desktop/src/renderer/hooks/useV2AgentConfigs/useV2AgentConfigs.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/V2AgentsSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/components/AgentDetail/AgentDetail.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/agents/components/V2AgentsSettings/components/AgentsSettingsSidebar/AgentsSettingsSidebar.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetsSection/components/PresetEditorDialog/PresetEditorDialog.tsx
  • packages/cli/src/commands/agents/list/command.ts
  • packages/cli/src/commands/agents/meta.ts
  • packages/host-service/src/trpc/router/settings/agent-configs.test.ts
  • packages/host-service/src/trpc/router/settings/agent-configs.ts
  • packages/host-service/src/trpc/router/settings/index.ts
  • packages/mcp-v2/src/host-service-client.ts
  • packages/mcp-v2/src/tools/agents/list.ts
  • packages/mcp-v2/src/tools/agents/run.ts
  • packages/mcp-v2/src/tools/register.ts
  • packages/mcp-v2/src/tools/workspaces/create.ts
  • packages/mcp-v2/src/tools/workspaces/delete.ts
  • packages/sdk/src/client.ts
  • packages/sdk/src/index.ts
  • packages/sdk/src/resources/agents.ts
  • packages/sdk/src/resources/index.ts
  • packages/shared/package.json
  • packages/shared/src/host-agent-presets.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/mcp-v2/src/tools/register.ts
  • packages/cli/src/commands/agents/list/command.ts
  • packages/sdk/src/resources/agents.ts

@saddlepaddle saddlepaddle merged commit fd82381 into main May 5, 2026
17 checks passed
@saddlepaddle saddlepaddle mentioned this pull request May 5, 2026
3 tasks
saddlepaddle added a commit that referenced this pull request May 5, 2026
Changes since v0.2.8:

- `superset agents list` (and demoted "presets" to a UI-only concept).
  CLI now reads canonical agents from host-service. (#4097)
- Host-service: refresh stale OAuth access tokens on remote workspace
  ops instead of failing the request. (#4106)
- Host-service: workspace.create now adopts an existing worktree at any
  path, not just the canonical one. (#4096)
- Host-service: AI workspace naming times out after 5s and falls back
  to a deterministic name. (#4102)

Push cli-v0.2.9 after this lands to fire the release pipeline.
saddlepaddle added a commit that referenced this pull request May 5, 2026
…4111)

Catches the docs and skill up to PR #4097 (which added `superset agents
list`, the SDK `Agents` resource, and the `agents_list` MCP tool, and
demoted listPresets to a static UI const).

- skills/superset/SKILL.md: drop the `superset agents list --local --presets` line — that flag was removed when the catalog stopped being a runtime API resource.
- apps/docs/content/docs/cli/cli-reference.mdx: add a new `### agents` section with `superset agents list` and `superset agents run` Command blocks (the run command was never documented).
- apps/docs/content/docs/mcp.mdx: add a new `### Agents` table row covering `agents_list` and `agents_run`; remove the spurious `projects_create` row (no such MCP tool exists in `register.ts`).
- apps/docs/content/docs/sdk/reference.mdx: drop the stale `**TODO**` Callout in `workspaces.create` that claimed the SDK sends a minimal `agentConfig: { id: 'claude', kind: 'terminal' }`. The SDK now uses the v2 host-service launch shape directly. Add a new `## agents` section documenting `client.agents.list` and `client.agents.run`.
- apps/docs/content/docs/sdk/advanced.mdx: drop the same stale `**TODO**` Callout above the Sentry recipe.

Style notes for the new entries: CLI Command `output` blocks use inline structural literals (matches `hosts list` / `workspaces list`), MCP table descriptions are terse single-clauses (matches `tasks_*` / `workspaces_*`).
saddlepaddle added a commit that referenced this pull request May 6, 2026
…4097)

Adds `superset agents list` for the CLI/SDK/MCP and reshapes how the
host service exposes terminal-agent presets.

**Why.** The host service was exposing two parallel concepts as runtime
data: configured rows (`hostAgentConfigs`) and a hardcoded preset
catalog (`AGENT_PRESETS`). The catalog isn't actually data — it's
static configuration that ships with the host-service binary, version-
locked to whatever desktop release the user has installed. Treating it
as a runtime API resource forced the desktop detail view to fetch the
catalog separately just to render row descriptions, made `add` validate
`presetId` against an enum that blocks truly custom agents, and bloated
the CLI/SDK/MCP with a parallel `listPresets` surface.

**Changes.**
- Move `AGENT_PRESETS` (V2 host-service preset list) from the host
  service into `packages/shared/src/host-agent-presets.ts` as
  `HOST_AGENT_PRESETS` / `HostAgentPreset` (named distinctly from V1's
  `AgentPresetField` / `AgentPresetOverride` types in the V1 desktop
  agent settings system, which is untouched).
- Drop `settings.agentConfigs.listPresets` from the host service. The
  desktop V2 agents picker now reads the bundled const directly.
- Reshape `settings.agentConfigs.add` to accept the full launch row
  (`{ label, command, args, promptTransport, promptArgs, env,
  presetId? }`). `presetId` is now free-form metadata used by the
  client for icon and description lookup, defaulting to `"custom"`
  when omitted. Truly custom agents are now possible at the API level.
- Add `superset agents list` for configured rows (no `--presets` flag —
  the catalog isn't runtime data).
- Add `Agents` resource to the SDK (`agents.list`, `agents.run` —
  routes the run through the cloud workspace lookup like the CLI does).
- Add `agents_list` MCP tool, plus a new `hostServiceQuery` GET helper
  in `packages/mcp-v2/src/host-service-client.ts` (the existing helper
  only handled mutations).

**Out of scope.** "Custom agent" form in the desktop picker (UI to enter
a label/command/args/env), `agents add` in the CLI/SDK/MCP for headless
custom installs, and unifying the V1 (`BUILTIN_TERMINAL_AGENTS`) and V2
(`HOST_AGENT_PRESETS`) catalogs into one. Those each deserve their own
PR.

**Verification.**
- `bun run lint` and `bun run typecheck` (turbo, full repo) clean.
- `bun test packages/host-service/src/trpc/router/settings/agent-configs.test.ts` — 21 pass, including the new "accepts a fully custom row" and "preserves an arbitrary presetId tag" cases.
- `bun run build` in `packages/sdk` clean.
- `superset agents list --local` prints the configured-row table.
- `superset agents list --local --presets` errors with "Unknown option".
saddlepaddle added a commit that referenced this pull request May 6, 2026
Changes since v0.2.8:

- `superset agents list` (and demoted "presets" to a UI-only concept).
  CLI now reads canonical agents from host-service. (#4097)
- Host-service: refresh stale OAuth access tokens on remote workspace
  ops instead of failing the request. (#4106)
- Host-service: workspace.create now adopts an existing worktree at any
  path, not just the canonical one. (#4096)
- Host-service: AI workspace naming times out after 5s and falls back
  to a deterministic name. (#4102)

Push cli-v0.2.9 after this lands to fire the release pipeline.
saddlepaddle added a commit that referenced this pull request May 6, 2026
…4111)

Catches the docs and skill up to PR #4097 (which added `superset agents
list`, the SDK `Agents` resource, and the `agents_list` MCP tool, and
demoted listPresets to a static UI const).

- skills/superset/SKILL.md: drop the `superset agents list --local --presets` line — that flag was removed when the catalog stopped being a runtime API resource.
- apps/docs/content/docs/cli/cli-reference.mdx: add a new `### agents` section with `superset agents list` and `superset agents run` Command blocks (the run command was never documented).
- apps/docs/content/docs/mcp.mdx: add a new `### Agents` table row covering `agents_list` and `agents_run`; remove the spurious `projects_create` row (no such MCP tool exists in `register.ts`).
- apps/docs/content/docs/sdk/reference.mdx: drop the stale `**TODO**` Callout in `workspaces.create` that claimed the SDK sends a minimal `agentConfig: { id: 'claude', kind: 'terminal' }`. The SDK now uses the v2 host-service launch shape directly. Add a new `## agents` section documenting `client.agents.list` and `client.agents.run`.
- apps/docs/content/docs/sdk/advanced.mdx: drop the same stale `**TODO**` Callout above the Sentry recipe.

Style notes for the new entries: CLI Command `output` blocks use inline structural literals (matches `hosts list` / `workspaces list`), MCP table descriptions are terse single-clauses (matches `tasks_*` / `workspaces_*`).
@Kitenite Kitenite deleted the feat/cli-agents-list branch May 6, 2026 04:50
@saddlepaddle saddlepaddle mentioned this pull request May 7, 2026
3 tasks
saddlepaddle added a commit that referenced this pull request May 7, 2026
npm has alpha.6 as the most recent published; alpha.7 was bumped in
71bf008 but never `npm publish`-ed. Skip alpha.7 on the registry
and ship the current repo state as alpha.8.

Changes since alpha.6:

- workspaces.create adopts the canonical host-service shape (#3893)
- automations.list accepts --name filter (#3952)
- automations.prompt split into automations.prompt.get / .set (#3959)
- agents.list (presets demoted to UI-only configuration) (#4097)
- agents.run / workspaces.create gain `superset-chat` agent + `kind`
  discriminator on launch results (terminal vs chat) (#4116)
- type adjustments for v2 workspace render path (#4141)
- redact x-api-key in debug-log header dumps (#3956, was alpha.7)

After merge: `cd packages/sdk && bun run build && cd dist && npm publish --access public`.
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