Skip to content

fix(automations): resolve agent presets live from host instead of snapshot#4481

Merged
saddlepaddle merged 6 commits into
mainfrom
fix-preset-dispatch-logic
May 13, 2026
Merged

fix(automations): resolve agent presets live from host instead of snapshot#4481
saddlepaddle merged 6 commits into
mainfrom
fix-preset-dispatch-logic

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented May 13, 2026

Summary

Automation dispatch was reading a ResolvedAgentConfig snapshot stored on the row at create time, sourced from the desktop's local v1 settings (electronTrpc.settings.getAgentPresets). That source is disjoint from the v2 host service's host_agent_configs table that Settings → Agents now reads and writes, so v2 preset edits silently never reached automation runs.

This PR replaces the snapshot with an agent id and delegates to the host's agents.run over the relay. The host resolves the current HostAgentConfig from its own DB (instance id first, then presetId fallback) and launches chat (agent === "superset") or terminal with the live command/args/env. Edits in v2 settings now take effect on the next run, with no client-side snapshot to drift.

What changed

  • DB (packages/db): replace automations.agent_config jsonb with agent text not null. Migration 0051 adds the column, backfills from agent_config->>'id', flips NOT NULL, then drops the old column.
  • Dispatcher (packages/trpc/src/router/automation/dispatch.ts): single agents.run call via relayMutation instead of branching on kind and building shell commands server-side. Chat session rows now created host-side by runChatAgent.
  • API surface (tRPC schema, SDK, CLI, MCP): rename agentConfigagent end-to-end; drop the AgentConfig type.
  • Renderer: AgentPicker and AgentCell source from useV2AgentChoices(useHostUrl(hostId)). CreateAutomationDialog and AutomationDetailSidebar pass targetHostId and submit agent: <id>.

Migration notes

Existing rows backfill to the slug their snapshot used (claude, codex), which falls through the host's resolveHostAgentConfig presetId path → lowest-displayOrder matching host_agent_configs row on the target host. New automations created via the picker pin to a HostAgentConfig.id (UUID) directly.

Edge case: a user who has deleted every stock claude/codex row in host_agent_configs (only custom agents remain) will see their pre-migration automations throw No host agent config matching '<slug>' on next fire. They re-pick the agent on the detail page to fix it.

Bonus

Chat-kind automations used to land with title = automation.name ("Daily standup digest" repeated forever). Now the chat runtime auto-titles from the first user message (generateTitleFromMessage in packages/chat/src/server/trpc/utils/runtime/runtime.ts:523), so each run gets a title summarizing its prompt content.

Test plan

  • bun run typecheck and bun run lint clean (verified locally).
  • Migration applies on Neon dev branch; existing rows backfill, no NULLs (verified: 56 rows, 0 NULL).
  • Edit a label/command in Settings → Agents; open New automation → picker reflects the edit.
  • Create an automation, confirm the persisted agent column is a host-agent UUID (not a slug).
  • Run now on the new automation; the host launches with the edited command (proves live resolve).
  • Run now on a pre-migration row (slug fallback path) → still launches.
  • Run now with the superset agent → chat session created host-side, auto-title lands.

Summary by cubic

Fixes automations using stale agent snapshots by resolving agents live on the host at run time. Replaces the stored agent_config snapshot with an agent id and dispatches via agents.run, so edits in Settings → Agents take effect on the next run.

  • Refactors

    • DB: replace automations.agent_config with agent text; migration 0051 backfills from agent_config->>'id'.
    • Dispatcher: single agents.run call over the relay; remove server-side command building and chat-session writes. Host resolves current config by instance id or presetId (including superset) and launches chat/terminal.
    • API surface + docs: rename agentConfigagent across tRPC, SDK, CLI, and MCP; remove the AgentConfig type. CLI: --agent accepts host agent UUID, presetId, or superset; drop --agent-config-file.
    • Renderer: AgentPicker/AgentCell source from useV2AgentChoices(useHostUrl(hostId)); creation/update flows pass targetHostId and persist the agent id. When changing an auto-routed automation, also set targetHostId to the picker's host to avoid cross-host UUID mismatches. Add label/icon fallback via getPresetById from @superset/shared/host-agent-presets when host data is unavailable; split template prefill to avoid clobbering user edits as host agents load.
  • Migration

    • Backfills existing rows to preset slugs (e.g., claude, codex), defaulting to claude via COALESCE when the snapshot id is missing. Guarded with IF [NOT] EXISTS checks and wraps the backfill in a DO $$ ... EXECUTE ... $$ block for safe re-apply.
    • Edge case: if a host has no stock row for a slug, pre-migration automations error with “No host agent config matching ''”. Re-pick the agent to fix.
    • Run migration 0051; no other action required.

Written for commit e26c8ef. Summary will update on new commits.

Summary by CodeRabbit

  • Refactor
    • Automation agent selection now uses simple agent identifiers (host agent id, presetId, or superset) instead of embedded agent configuration objects
    • Agent picker and agent display are host-scoped for more accurate labels and icons
  • CLI
    • automations create/update unify --agent to accept host agent id, presetId, or superset; removed config-file option
  • Database
    • Automations now store an agent field (backfilled) and remove the old agent config column
  • SDK / API
    • Public automation types and tool schemas replaced agentConfig with agent
  • Documentation
    • CLI, SDK, and spec docs updated to reflect the new agent field and flag behavior

Review Change Stack

…pshot

Automation dispatch was reading a `ResolvedAgentConfig` snapshot stored on
the row at create time, sourced from the desktop's local v1 settings
(`electronTrpc.settings.getAgentPresets`). That source is disjoint from
the v2 host service's `host_agent_configs` table that `Settings → Agents`
now reads and writes, so v2 preset edits silently never reached runs.

Replace the snapshot with an `agent` id and delegate to the host's
`agents.run` over the relay. The host resolves the current
`HostAgentConfig` from its own DB (instance id first, then `presetId`
fallback) and launches chat (`agent === "superset"`) or terminal with
the live command/args/env. Edits in v2 settings now apply on the next
run, with no client-side snapshot to drift.

- DB: replace `automations.agent_config jsonb` with `agent text not null`;
  migration backfills from `agent_config->>'id'` before dropping.
- tRPC/SDK/CLI/MCP: rename `agentConfig` -> `agent` end-to-end; drop the
  `AgentConfig` type.
- Renderer: `AgentPicker` and `AgentCell` now source from
  `useV2AgentChoices(useHostUrl(hostId))`. `CreateAutomationDialog` and
  `AutomationDetailSidebar` pass `targetHostId` and submit `agent: <id>`.
- Dispatcher: single `agents.run` call via `relayMutation`; chat session
  rows are now created host-side by `runChatAgent`.

Existing rows backfill to preset slugs (`claude`/`codex`) which fall
through the host's `resolveHostAgentConfig` presetId path; new
automations created via the picker pin to the host-agent instance UUID.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

📝 Walkthrough

Walkthrough

The PR replaces the structured automation agentConfig with a simple agent string across database schema, backend validation and routers, dispatch orchestration, public SDK types, MCP tool contracts, CLI commands and docs, and desktop UI components so the agent identifier flows as text system-wide.

Changes

Agent field modernization

Layer / File(s) Summary
Database schema and migration
packages/db/drizzle/0051_replace_automation_agent_config_with_agent_id.sql, packages/db/drizzle/meta/_journal.json, packages/db/src/schema/schema.ts
Drizzle migration adds agent text column to automations, backfills from agent_config->>'id' (empty->NULL, default 'claude'), makes agent NOT NULL, and drops agent_config. Journal and schema imports updated.
TRPC validation schemas
packages/trpc/src/router/automation/schema.ts
Replace agentConfig schema with agent: string (1–200 chars) and update createAutomationSchema/updateAutomationSchema and inferred input types.
TRPC router create and update
packages/trpc/src/router/automation/automation.ts
Create/update mutations set agent from input.agent and merge updates via input.agent ?? existing.agent.
Automation dispatch orchestration
packages/trpc/src/router/automation/dispatch.ts
Unify dispatch to runAgentOnHost relay call; add AgentRunResult union and update automation_runs with session kind and the appropriate session id fields.
Public SDK API types
packages/sdk/src/client.ts, packages/sdk/src/index.ts, packages/sdk/src/resources/automations.ts, packages/sdk/src/resources/index.ts
Remove AgentConfig interface/re-exports. AutomationSummary, AutomationCreateParams, and AutomationUpdateParams use agent: string instead of agentConfig.
MCP tool contracts
packages/mcp-v2/src/tools/automations/create.ts, packages/mcp-v2/src/tools/automations/update.ts
Tool input schemas replace agentConfig object with agent string and update descriptions to accept host agent UUID, presetId (claude/codex), or 'superset'.
CLI automation commands & spec/docs
packages/cli/src/commands/automations/create/command.ts, packages/cli/src/commands/automations/list/command.ts, packages/cli/src/commands/automations/update/command.ts, apps/docs/content/docs/cli/cli-reference.mdx, packages/cli/CLI_SPEC_TARGET.md, apps/docs/content/docs/sdk/reference.mdx
CLI create/update now send agent string; agentConfigFile option removed; --agent help text updated. CLI spec and docs updated to use agent. Listing uses row.agent.
Desktop UI agent components
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AgentCell/AgentCell.tsx, apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AgentPicker/AgentPicker.tsx
AgentCell accepts hostId and resolves label/icon via useHostUrl + useV2AgentChoices with preset fallbacks. AgentPicker accepts optional hostId, sources host-scoped agents, and renders icons via agent.iconId ?? agent.id with dark-theme handling and preset fallbacks.
Desktop UI automation create and detail
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx, apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/components/AutomationDetailSidebar/AutomationDetailSidebar.tsx, apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx, apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/NavigationControls/components/HistoryDropdown/HistoryDropdown.tsx
CreateAutomationDialog tracks agent id state, derives selectedAgent from host agents, limits template prefill to scalar fields and sets agent when host agents available, and sends agent: selectedAgent.id on create. AutomationDetailSidebar binds AgentPicker to automation.agent and updates agent via mutation. page.tsx passes automation.agent and host ID to AgentCell. HistoryDropdown queries automations.agent.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 Hops with glee,
Agent strings hop so free—
Config objects fade,
Simple IDs parade,
Through the code, light and spry! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% 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 reflects the main change: switching from snapshot agent presets to live resolution from the host.
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.
Description check ✅ Passed PR description comprehensively covers changes, migration strategy, and test plan with clear technical details.

✏️ 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 fix-preset-dispatch-logic

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.

@capy-ai
Copy link
Copy Markdown

capy-ai Bot commented May 13, 2026

Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 13, 2026

Greptile Summary

This PR replaces the snapshotted ResolvedAgentConfig blob stored on each automation row with a simple agent text field (UUID or presetId) and delegates agent resolution to the host's agents.run relay call at dispatch time. This fixes a long-standing drift where v2 settings edits never reached running automations.

  • DB migration (0051): Drops agent_config jsonb, adds agent text not null, backfilling from the JSON id key. The new dispatcher passes agent straight to the host relay and removes all client-side branching on kind.
  • Renderer/UI: AgentPicker and AgentCell now fetch live agent choices from the target host via useV2AgentChoices(hostUrl) rather than reading local v1 settings; CreateAutomationDialog and AutomationDetailSidebar pass targetHostId so the picker scopes its list to the correct host.
  • API surface: agentConfigagent renamed end-to-end across tRPC schema, SDK types, CLI, and MCP tools; the AgentConfig/ResolvedAgentConfig types and all related loading helpers are removed.

Confidence Score: 3/5

The migration and automations list view have two issues that should be addressed before shipping to production.

The migration's backfill has no fallback for rows where the JSON extraction returns NULL; if any such row exists the NOT NULL step aborts the migration and blocks the deploy. Separately, the automations list passes automation.targetHostId ?? null to AgentCell with no localHostId fallback, so any automation that lacks a pinned host will display a raw ID string instead of a human-readable agent name. The dispatcher simplification and the rest of the API rename are clean and well-structured.

The migration SQL and automations/page.tsx need attention; the rest of the changeset is straightforward.

Important Files Changed

Filename Overview
packages/db/drizzle/0051_replace_automation_agent_config_with_agent_id.sql 4-step migration (add → backfill → NOT NULL → drop) with no COALESCE fallback in the backfill; any row without a valid agent_config.id would cause the NOT NULL step to fail.
packages/trpc/src/router/automation/dispatch.ts Dispatcher simplified cleanly: single relayMutation to agents.run replaces the old branching on agent kind; workspace creation and run-row bookkeeping are unchanged.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx AgentCell now receives targetHostId directly; automations with no pinned host pass null, causing the agent label to fall back to the raw agentId (regression vs. old snapshot label).
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx Agent state migrated from hardcoded "claude" to live hostAgents[0] default; fallback effect works correctly but can briefly clear the selection during host-switch transitions.
packages/trpc/src/router/automation/schema.ts agentSchema (string, 1–200 chars) cleanly replaces the old complex AgentConfig object schema for both create and update inputs.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AgentCell/AgentCell.tsx Switches from prop-passed label to live host resolution; gracefully falls back to raw agentId when host is unavailable, though UUID IDs will be unreadable in that state.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AgentPicker/AgentPicker.tsx Cleanly switched to useV2AgentChoices for live host-scoped choices; iconId fallback to agent.id preserves icon resolution for both presets and custom agents.
packages/db/src/schema/schema.ts automations table updated to agent text().notNull(), consistent with the migration; no other schema concerns.
packages/sdk/src/resources/automations.ts SDK types updated correctly: AutomationSummary.agent replaces agentConfig, create/update params align with new schema.
packages/cli/src/commands/automations/create/command.ts Removes loadAgentConfigFromFile and resolveDefaultAgentConfig helpers; --agent flag now passes through directly as a string, and --agentConfigFile is dropped.

Sequence Diagram

sequenceDiagram
    participant Cron as Cron/runNow
    participant Dispatch as dispatchAutomation
    participant DB as Neon DB (automations)
    participant Relay as Relay → Host
    participant Host as Host (agents.run)

    Cron->>Dispatch: "{ automation.agent, scheduledFor }"
    Dispatch->>DB: "INSERT automation_run (status=dispatching)"
    Dispatch->>Relay: workspaces.create (if no v2WorkspaceId)
    Relay-->>Dispatch: "{ workspaceId }"
    Dispatch->>Relay: "agents.run({ workspaceId, agent, prompt })"
    Relay->>Host: resolveHostAgentConfig(agent)
    Host-->>Relay: launch terminal/chat session
    Relay-->>Dispatch: "{ kind, sessionId }"
    Dispatch->>DB: "UPDATE automation_run (status=dispatched, sessionId)"
Loading
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
packages/db/drizzle/0051_replace_automation_agent_config_with_agent_id.sql:2
No COALESCE fallback in the backfill means any row whose `agent_config` is NULL (or whose JSON blob lacks an `id` key) will leave `agent` as NULL after the UPDATE, and the subsequent `ALTER COLUMN … SET NOT NULL` will fail with a constraint-violation error, aborting the migration. Even if production data is clean today, a defensive fallback costs nothing and prevents a silent deploy failure.

```suggestion
UPDATE "automations" SET "agent" = COALESCE("agent_config" ->> 'id', 'claude') WHERE "agent" IS NULL;--> statement-breakpoint
```

### Issue 2 of 3
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx:481-484
**Agent label missing for automations without a pinned host**

`AgentCell` receives `hostId={automation.targetHostId ?? null}`, but automations created before this PR (and CLI-created ones) typically have `targetHostId = null`. With a null `hostId`, `useHostUrl` returns no URL, `useV2AgentChoices` returns `[]`, `match` is undefined, and the cell falls back to rendering the raw `agentId`. For backfilled slug values ("claude", "codex") this is readable but unstyled; for any UUID-format agent IDs it shows the raw UUID. The `AutomationDetailSidebar` handles this correctly by falling back to `localHostId` — the same pattern should be applied here.

### Issue 3 of 3
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx:76-80
**Agent selection cleared during transient `hostAgents` reload**

When the user switches the target host (via `DevicePicker`), `hostAgents` briefly becomes `[]` while the new host's agents are fetched. During that window the guard `hostAgents.some((option) => option.id === agent)` fails (empty list), `fallback` evaluates to `null`, and `setAgent(null)` fires — clearing the in-progress selection. The picker then shows empty and the Create button becomes disabled until the load settles. Using a stable "previous value" pattern (e.g. keeping the old agent until the new list loads and then applying the fallback only if the list is non-empty) would avoid the flash.

Reviews (1): Last reviewed commit: "fix(automations): resolve agent presets ..." | Re-trigger Greptile

@@ -0,0 +1,4 @@
ALTER TABLE "automations" ADD COLUMN "agent" text;--> statement-breakpoint
UPDATE "automations" SET "agent" = "agent_config" ->> 'id' WHERE "agent" IS NULL;--> statement-breakpoint
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.

P1 No COALESCE fallback in the backfill means any row whose agent_config is NULL (or whose JSON blob lacks an id key) will leave agent as NULL after the UPDATE, and the subsequent ALTER COLUMN … SET NOT NULL will fail with a constraint-violation error, aborting the migration. Even if production data is clean today, a defensive fallback costs nothing and prevents a silent deploy failure.

Suggested change
UPDATE "automations" SET "agent" = "agent_config" ->> 'id' WHERE "agent" IS NULL;--> statement-breakpoint
UPDATE "automations" SET "agent" = COALESCE("agent_config" ->> 'id', 'claude') WHERE "agent" IS NULL;--> statement-breakpoint
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/db/drizzle/0051_replace_automation_agent_config_with_agent_id.sql
Line: 2

Comment:
No COALESCE fallback in the backfill means any row whose `agent_config` is NULL (or whose JSON blob lacks an `id` key) will leave `agent` as NULL after the UPDATE, and the subsequent `ALTER COLUMN … SET NOT NULL` will fail with a constraint-violation error, aborting the migration. Even if production data is clean today, a defensive fallback costs nothing and prevents a silent deploy failure.

```suggestion
UPDATE "automations" SET "agent" = COALESCE("agent_config" ->> 'id', 'claude') WHERE "agent" IS NULL;--> statement-breakpoint
```

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

Comment on lines 481 to +484

<span className="min-w-0 text-xs text-muted-foreground">
<AgentCell
agentId={automation.agentConfig.id}
label={automation.agentConfig.label}
agentId={automation.agent}
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.

P1 Agent label missing for automations without a pinned host

AgentCell receives hostId={automation.targetHostId ?? null}, but automations created before this PR (and CLI-created ones) typically have targetHostId = null. With a null hostId, useHostUrl returns no URL, useV2AgentChoices returns [], match is undefined, and the cell falls back to rendering the raw agentId. For backfilled slug values ("claude", "codex") this is readable but unstyled; for any UUID-format agent IDs it shows the raw UUID. The AutomationDetailSidebar handles this correctly by falling back to localHostId — the same pattern should be applied here.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx
Line: 481-484

Comment:
**Agent label missing for automations without a pinned host**

`AgentCell` receives `hostId={automation.targetHostId ?? null}`, but automations created before this PR (and CLI-created ones) typically have `targetHostId = null`. With a null `hostId`, `useHostUrl` returns no URL, `useV2AgentChoices` returns `[]`, `match` is undefined, and the cell falls back to rendering the raw `agentId`. For backfilled slug values ("claude", "codex") this is readable but unstyled; for any UUID-format agent IDs it shows the raw UUID. The `AutomationDetailSidebar` handles this correctly by falling back to `localHostId` — the same pattern should be applied here.

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

Comment on lines +76 to +80
useEffect(() => {
if (agent && hostAgents.some((option) => option.id === agent)) return;
const fallback = hostAgents[0]?.id ?? null;
if (fallback !== agent) setAgent(fallback);
}, [agent, hostAgents]);
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.

P2 Agent selection cleared during transient hostAgents reload

When the user switches the target host (via DevicePicker), hostAgents briefly becomes [] while the new host's agents are fetched. During that window the guard hostAgents.some((option) => option.id === agent) fails (empty list), fallback evaluates to null, and setAgent(null) fires — clearing the in-progress selection. The picker then shows empty and the Create button becomes disabled until the load settles. Using a stable "previous value" pattern (e.g. keeping the old agent until the new list loads and then applying the fallback only if the list is non-empty) would avoid the flash.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx
Line: 76-80

Comment:
**Agent selection cleared during transient `hostAgents` reload**

When the user switches the target host (via `DevicePicker`), `hostAgents` briefly becomes `[]` while the new host's agents are fetched. During that window the guard `hostAgents.some((option) => option.id === agent)` fails (empty list), `fallback` evaluates to `null`, and `setAgent(null)` fires — clearing the in-progress selection. The picker then shows empty and the Create button becomes disabled until the load settles. Using a stable "previous value" pattern (e.g. keeping the old agent until the new list loads and then applying the fallback only if the list is non-empty) would avoid the flash.

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

Mirrors the API change. Drops the dead `--agent-config-file` flag from
the CLI reference and the matching `agentConfig` field from the SDK
example. CLI_SPEC_TARGET aligned with the shipped surface.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 13, 2026

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

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

🧹 Nitpick comments (2)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx (1)

274-279: 💤 Low value

Consider making AgentPicker accept nullable value.

Using agent ?? "" as a sentinel for "no selection" works but is implicit. The empty string won't match any agent, but it would be clearer if AgentPicker explicitly accepted value: string | null and handled null as "no selection" internally.

Alternative approach

Update AgentPicker props to accept value: string | null, then simplify the call site:

 <AgentPicker
   className="w-[100px]"
   hostId={targetHostId}
-  value={agent ?? ""}
+  value={agent}
   onChange={setAgent}
 />

And in AgentPicker.tsx:

 interface AgentPickerProps {
   hostId: string | null | undefined;
-  value: string;
+  value: string | null;
   onChange: (next: string) => void;
   className?: string;
 }
🤖 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
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx`
around lines 274 - 279, Update AgentPicker to accept a nullable value type so
callers can pass null instead of using an empty-string sentinel; change its prop
signature to value: string | null and ensure the component treats null as "no
selection" internally (e.g., renders placeholder and maps selections to string
or null onChange). Then simplify this call site by passing value={agent} (and
keep onChange={setAgent}, hostId={targetHostId}) so the agent state can be null
when nothing is selected; ensure AgentPicker’s onChange still emits string |
null to match setAgent.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AgentPicker/AgentPicker.tsx (1)

24-87: ⚡ Quick win

Consider showing a disabled state when no agents are available.

When hostId is null or useV2AgentChoices returns an empty array, the picker shows "Select agent" but the dropdown only contains "Configure agents…". This could be confusing. Consider disabling the picker or showing a helper message when agents.length === 0.

🎨 Suggested enhancement
 export function AgentPicker({
 	hostId,
 	value,
 	onChange,
 	className,
 }: AgentPickerProps) {
 	const navigate = useNavigate();
 	const hostUrl = useHostUrl(hostId);
 	const { agents } = useV2AgentChoices(hostUrl);
 	const isDark = useIsDarkTheme();
 	const selectedAgent = agents.find((agent) => agent.id === value);
 	const selectedIcon = selectedAgent
 		? getPresetIcon(selectedAgent.iconId ?? selectedAgent.id, isDark)
 		: null;
 
 	return (
 		<DropdownMenu>
 			<DropdownMenuTrigger asChild>
 				<PickerTrigger
+					disabled={agents.length === 0}
 					className={className}
 					icon={
 						selectedIcon ? (
 							<img
 								src={selectedIcon}
 								alt=""
 								className="size-3.5 shrink-0 object-contain"
 							/>
 						) : (
 							<LuCpu className="size-4 shrink-0" />
 						)
 					}
-					label={selectedAgent?.label ?? "Select agent"}
+					label={
+						agents.length === 0
+							? "No agents available"
+							: (selectedAgent?.label ?? "Select agent")
+					}
 				/>
 			</DropdownMenuTrigger>
🤖 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
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AgentPicker/AgentPicker.tsx`
around lines 24 - 87, AgentPicker currently shows "Select agent" but the
dropdown only contains "Configure agents…" when there are no agents; update
AgentPicker to detect when agents.length === 0 or hostId is null and render a
disabled state: pass a disabled prop to PickerTrigger/DropdownMenuTrigger (or
render a visually disabled trigger) and change the label to "No agents
available" (or similar), and inside DropdownMenuContent render a non-selectable
helper item like "No agents found" (use a disabled DropdownMenuItem or
aria-disabled) above the "Configure agents…" entry so users understand why
selection is unavailable; also ensure onSelect isn't called for the helper and
keep accessibility attributes (aria-disabled/role) consistent.
🤖 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/trpc/src/router/automation/automation.ts`:
- Around line 271-272: The code is allowing targetHostId to be null when storing
HostAgentConfig.id (see the agent and targetHostId fields), which causes
dispatch to forward the UUID to the wrong host; enforce a non-null targetHostId
by validating input.targetHostId and rejecting or throwing when it's missing for
create/update paths that persist HostAgentConfig.id (adjust the handlers that
set agent: input.agent, targetHostId: input.targetHostId ?? null and the similar
block around the other occurrence), and update any request/validation schema to
require targetHostId so the stored config always contains a concrete host UUID.

In `@packages/trpc/src/router/automation/schema.ts`:
- Line 4: The agentSchema currently allows whitespace-only strings because
z.string().min(1) checks length without trimming; update agentSchema to call
.trim() before applying .min(1). Specifically, change the schema definition for
agentSchema (z.string()) to include .trim() and keep the existing bounds (e.g.,
.trim().min(1).max(200)) so leading/trailing whitespace is removed before
validation.

---

Nitpick comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AgentPicker/AgentPicker.tsx`:
- Around line 24-87: AgentPicker currently shows "Select agent" but the dropdown
only contains "Configure agents…" when there are no agents; update AgentPicker
to detect when agents.length === 0 or hostId is null and render a disabled
state: pass a disabled prop to PickerTrigger/DropdownMenuTrigger (or render a
visually disabled trigger) and change the label to "No agents available" (or
similar), and inside DropdownMenuContent render a non-selectable helper item
like "No agents found" (use a disabled DropdownMenuItem or aria-disabled) above
the "Configure agents…" entry so users understand why selection is unavailable;
also ensure onSelect isn't called for the helper and keep accessibility
attributes (aria-disabled/role) consistent.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx`:
- Around line 274-279: Update AgentPicker to accept a nullable value type so
callers can pass null instead of using an empty-string sentinel; change its prop
signature to value: string | null and ensure the component treats null as "no
selection" internally (e.g., renders placeholder and maps selections to string
or null onChange). Then simplify this call site by passing value={agent} (and
keep onChange={setAgent}, hostId={targetHostId}) so the agent state can be null
when nothing is selected; ensure AgentPicker’s onChange still emits string |
null to match setAgent.
🪄 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: 69f6e3de-e9c4-4e77-92d2-abce35570fa6

📥 Commits

Reviewing files that changed from the base of the PR and between 3b3c4f2 and 6bf5697.

📒 Files selected for processing (22)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/components/AutomationDetailSidebar/AutomationDetailSidebar.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AgentCell/AgentCell.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/AgentPicker/AgentPicker.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/NavigationControls/components/HistoryDropdown/HistoryDropdown.tsx
  • packages/cli/src/commands/automations/create/command.ts
  • packages/cli/src/commands/automations/list/command.ts
  • packages/cli/src/commands/automations/update/command.ts
  • packages/db/drizzle/0051_replace_automation_agent_config_with_agent_id.sql
  • packages/db/drizzle/meta/0051_snapshot.json
  • packages/db/drizzle/meta/_journal.json
  • packages/db/src/schema/schema.ts
  • packages/mcp-v2/src/tools/automations/create.ts
  • packages/mcp-v2/src/tools/automations/update.ts
  • packages/sdk/src/client.ts
  • packages/sdk/src/index.ts
  • packages/sdk/src/resources/automations.ts
  • packages/sdk/src/resources/index.ts
  • packages/trpc/src/router/automation/automation.ts
  • packages/trpc/src/router/automation/dispatch.ts
  • packages/trpc/src/router/automation/schema.ts
💤 Files with no reviewable changes (3)
  • packages/sdk/src/index.ts
  • packages/sdk/src/resources/index.ts
  • packages/sdk/src/client.ts

Comment on lines +271 to 272
agent: input.agent,
targetHostId: input.targetHostId ?? null,
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

Require targetHostId when storing a host-agent UUID.

New automations now store HostAgentConfig.id values, but create/update still allow targetHostId to be null. When that happens, dispatch falls back to the first accessible online host and forwards the UUID there, which makes host-side agent resolution fail as soon as the config belongs to a different host.

Suggested guard
+function isUuidLike(value: string): boolean {
+	return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
+}
+
 create: protectedProcedure
 	.input(createAutomationSchema)
 	.mutation(async ({ ctx, input }) => {
+		if (isUuidLike(input.agent) && !input.targetHostId) {
+			throw new TRPCError({
+				code: "BAD_REQUEST",
+				message: "targetHostId is required when agent is a host agent id",
+			});
+		}
+
 		const { organizationId, subscription } =
 			await requireActiveOrgMembershipWithSubscription(ctx);
 		requirePaidSubscription(subscription);
@@
 update: protectedProcedure
 	.input(updateAutomationSchema)
 	.mutation(async ({ ctx, input }) => {
 		const organizationId = await requireActiveOrgMembership(ctx);
 		const existing = await getAutomationForUser(
 			ctx.session.user.id,
 			organizationId,
 			input.id,
 		);
+		const nextAgent = input.agent ?? existing.agent;
+		const nextTargetHostId =
+			input.targetHostId === undefined
+				? existing.targetHostId
+				: input.targetHostId;
+		if (isUuidLike(nextAgent) && !nextTargetHostId) {
+			throw new TRPCError({
+				code: "BAD_REQUEST",
+				message: "targetHostId is required when agent is a host agent id",
+			});
+		}
 
 		if (input.targetHostId !== undefined && input.targetHostId !== null) {
 			await verifyHostAccess(

Also applies to: 345-349

🤖 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/trpc/src/router/automation/automation.ts` around lines 271 - 272,
The code is allowing targetHostId to be null when storing HostAgentConfig.id
(see the agent and targetHostId fields), which causes dispatch to forward the
UUID to the wrong host; enforce a non-null targetHostId by validating
input.targetHostId and rejecting or throwing when it's missing for create/update
paths that persist HostAgentConfig.id (adjust the handlers that set agent:
input.agent, targetHostId: input.targetHostId ?? null and the similar block
around the other occurrence), and update any request/validation schema to
require targetHostId so the stored config always contains a concrete host UUID.

kind: z.enum(["terminal", "chat"]),
})
.passthrough() as unknown as z.ZodType<ResolvedAgentConfig>;
const agentSchema = z.string().min(1).max(200);
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

🧩 Analysis chain

🏁 Script executed:

# First, let's check the file structure and see the schema file
cd packages/trpc/src/router/automation/ 2>/dev/null && ls -la || echo "Path not found, listing repository structure..."

Repository: superset-sh/superset

Length of output: 621


🏁 Script executed:

# Find the schema file
find . -name "schema.ts" -path "*/automation/*" | head -20

Repository: superset-sh/superset

Length of output: 112


🏁 Script executed:

# Read the schema file to understand the context
cat packages/trpc/src/router/automation/schema.ts | head -60

Repository: superset-sh/superset

Length of output: 1724


🏁 Script executed:

# Check if there are any Biome lint issues in this file
fd "biome" 2>/dev/null || echo "Checking for biome configuration..."

Repository: superset-sh/superset

Length of output: 76


🏁 Script executed:

# Check Zod version and test the validation behavior
cd . && cat package.json | grep -A 2 '"zod"'

Repository: superset-sh/superset

Length of output: 46


🏁 Script executed:

# Create a quick test to validate Zod's behavior with whitespace
cat > /tmp/test_zod.mjs << 'EOF'
import { z } from 'zod';

const schema = z.string().min(1).max(200);
const schemaWithTrim = z.string().trim().min(1).max(200);

// Test whitespace-only string
const whitespaceStr = "   ";

console.log("Testing: '   ' (3 spaces)");
try {
  const result = schema.parse(whitespaceStr);
  console.log("Original schema (.min(1)): PASSES - value:", JSON.stringify(result));
} catch (e) {
  console.log("Original schema (.min(1)): FAILS");
}

try {
  const result = schemaWithTrim.parse(whitespaceStr);
  console.log("With .trim(): PASSES - value:", JSON.stringify(result));
} catch (e) {
  console.log("With .trim(): FAILS -", e.errors[0].message);
}

// Test single character
const singleChar = "a";
console.log("\nTesting: 'a'");
try {
  const result = schema.parse(singleChar);
  console.log("Original schema: PASSES");
} catch (e) {
  console.log("Original schema: FAILS");
}
EOF

# Check if we can run this
node /tmp/test_zod.mjs 2>&1 || echo "Node test not available in sandbox"

Repository: superset-sh/superset

Length of output: 1090


🏁 Script executed:

# Check for Biome lint in the file
rg "TODO|FIXME|any" packages/trpc/src/router/automation/schema.ts

Repository: superset-sh/superset

Length of output: 46


🏁 Script executed:

# Look at the biome config to understand lint rules
cat biome.jsonc | head -100

Repository: superset-sh/superset

Length of output: 1581


🏁 Script executed:

# Check if there are any Biome lint overrides for packages/trpc
rg "packages/trpc" biome.jsonc

Repository: superset-sh/superset

Length of output: 46


🏁 Script executed:

# Check the actual usage of agentSchema to confirm it's reused as described
rg "agentSchema" packages/trpc/src/router/automation/schema.ts

Repository: superset-sh/superset

Length of output: 166


🏁 Script executed:

# Verify Zod string.min() documentation from web to confirm whitespace behavior
web_search
Zod z.string().min(1) whitespace validation behavior

Repository: superset-sh/superset

Length of output: 253


🌐 Web query:

Zod z.string().min(1) whitespace validation behavior trim

💡 Result:

Answer: z.string.trim only trims leading/trailing whitespace (it does not remove whitespace inside the string). Zod also applies.min(1) to the resulting string after transforms, so “spaces-only” inputs will fail.min(1) only if you trim first. If you want “trim + min 1” behavior: const schema = z.string.trim.min(1) This is the common pattern discussed in Zod issues (e.g., z.string.trim.min(1,...)). [1] If you want to remove ALL whitespace characters (spaces/tabs/newlines inside the string too), you need a transform (or preprocess) that deletes internal whitespace, then validate the non-empty result. One approach is transform + pipe: z.string.transform(value => value.replace(/\s+/g, '')).pipe(z.string.min(1, { message: 'This field is required' })) This is explicitly suggested as the way to remove all whitespace before additional validations. [2] Zod’s docs also list z.string.trim as a string transform that trims whitespace. [3]

Citations:


🏁 Script executed:

# Verify the exact line numbers and context one more time for precision
sed -n '1,45p' packages/trpc/src/router/automation/schema.ts | cat -n

Repository: superset-sh/superset

Length of output: 1563


Trim agent before the non-empty check.

z.string().min(1) accepts whitespace-only strings like " " since Zod applies .min() to string length without trimming by default. Callers can persist an unusable agent identifier that only fails later at dispatch time. Use .trim() to remove leading and trailing whitespace before validation.

Suggested fix
-const agentSchema = z.string().min(1).max(200);
+const agentSchema = z.string().trim().min(1).max(200);
📝 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
const agentSchema = z.string().min(1).max(200);
const agentSchema = z.string().trim().min(1).max(200);
🤖 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/trpc/src/router/automation/schema.ts` at line 4, The agentSchema
currently allows whitespace-only strings because z.string().min(1) checks length
without trimming; update agentSchema to call .trim() before applying .min(1).
Specifically, change the schema definition for agentSchema (z.string()) to
include .trim() and keep the existing bounds (e.g., .trim().min(1).max(200)) so
leading/trailing whitespace is removed before validation.

Greptile flagged that the original 0051 had no fallback if any row's
`agent_config->>'id'` returned NULL — that would trip the NOT NULL step
and abort the deploy. Worked clean on dev (56/56 rows had id), but
defends against a stray row in prod.

Also wrap every statement in `IF [NOT] EXISTS` / EXISTS-guards so a
re-apply against a partially-migrated branch is a no-op (the
information_schema check on the UPDATE prevents it from referencing
agent_config after the column has already been dropped).
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 (3)
apps/docs/content/docs/cli/cli-reference.mdx (2)

883-883: 💤 Low value

Consider adding context for the 'superset' value.

The update command description omits the "for built-in chat" explanation that appears in the create command (line 852). While brevity is reasonable for update commands, adding this context would help users who read the update docs first.

🤖 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 `@apps/docs/content/docs/cli/cli-reference.mdx` at line 883, Update the flag
description for the "--agent <agent>" entry so it includes the same "for
built-in chat" context used in the create command; specifically modify the
object with key flag: "--agent <agent>" (description currently "New host agent
presetId, instance UUID, or 'superset'.") to append or revise the text to
mention that 'superset' is for the built-in chat, mirroring the create command
wording for consistency.

852-852: ⚡ Quick win

Improve consistency and discoverability of preset IDs.

Two minor improvements:

  1. Formatting consistency: The default value claude should be formatted consistently with 'superset'. Consider: Default: 'claude'.

  2. Preset discovery: Users may not know what preset IDs are valid beyond the examples. Consider adding a note directing them to superset agents list --local to discover configured agents.

🤖 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 `@apps/docs/content/docs/cli/cli-reference.mdx` at line 852, Update the
"--agent <agent>" flag entry so the default value is formatted consistently as
'claude' (match the existing quoting for 'superset') and append a short note
about preset discovery pointing users to run "superset agents list --local" to
see configured preset IDs; update the flag description string (the object with
key flag: "--agent <agent>") to include "Default: 'claude'." and add a trailing
sentence like "Use `superset agents list --local` to discover configured preset
IDs." so users can find valid presets.
packages/cli/CLI_SPEC_TARGET.md (1)

605-606: ⚡ Quick win

Consider adding guidance on discovering valid preset IDs.

The flag description mentions "Host agent presetId" as an option, but users may not know what preset IDs are available. Consider adding a reference to help users discover them, such as:

To see available preset IDs on a host, use superset agents list --host <id>.

Additionally, for consistency with the special literal value superset (backtick-formatted), consider formatting the default value claude the same way: `claude`.

🤖 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/CLI_SPEC_TARGET.md` around lines 605 - 606, Update the `--agent
<agent>` flag description to (1) include a short hint on how to discover valid
host agent preset IDs (e.g., reference a command like "use superset agents list
--host <id> to view available preset IDs") and (2) format the default value
`claude` with backticks to match the existing `superset` literal; edit the text
for the `--agent <agent>` flag in the CLI spec to incorporate both changes and
keep the wording concise.
🤖 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 `@apps/docs/content/docs/cli/cli-reference.mdx`:
- Line 883: Update the flag description for the "--agent <agent>" entry so it
includes the same "for built-in chat" context used in the create command;
specifically modify the object with key flag: "--agent <agent>" (description
currently "New host agent presetId, instance UUID, or 'superset'.") to append or
revise the text to mention that 'superset' is for the built-in chat, mirroring
the create command wording for consistency.
- Line 852: Update the "--agent <agent>" flag entry so the default value is
formatted consistently as 'claude' (match the existing quoting for 'superset')
and append a short note about preset discovery pointing users to run "superset
agents list --local" to see configured preset IDs; update the flag description
string (the object with key flag: "--agent <agent>") to include "Default:
'claude'." and add a trailing sentence like "Use `superset agents list --local`
to discover configured preset IDs." so users can find valid presets.

In `@packages/cli/CLI_SPEC_TARGET.md`:
- Around line 605-606: Update the `--agent <agent>` flag description to (1)
include a short hint on how to discover valid host agent preset IDs (e.g.,
reference a command like "use superset agents list --host <id> to view available
preset IDs") and (2) format the default value `claude` with backticks to match
the existing `superset` literal; edit the text for the `--agent <agent>` flag in
the CLI spec to incorporate both changes and keep the wording concise.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 39acb1a1-eafe-4594-beaf-9af148f3b9e0

📥 Commits

Reviewing files that changed from the base of the PR and between 6bf5697 and d1bf4c8.

📒 Files selected for processing (4)
  • apps/docs/content/docs/cli/cli-reference.mdx
  • apps/docs/content/docs/sdk/reference.mdx
  • packages/cli/CLI_SPEC_TARGET.md
  • packages/db/drizzle/0051_replace_automation_agent_config_with_agent_id.sql
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/db/drizzle/0051_replace_automation_agent_config_with_agent_id.sql

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/db/drizzle/0051_replace_automation_agent_config_with_agent_id.sql">

<violation number="1" location="packages/db/drizzle/0051_replace_automation_agent_config_with_agent_id.sql:2">
P2: The `EXISTS` guard does not make this update safe when `agent_config` is absent; the statement can still fail before execution because it directly references the dropped column.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Comment thread packages/db/drizzle/0051_replace_automation_agent_config_with_agent_id.sql Outdated
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 22 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx:485">
P2: Auto-targeted automations are resolved against the viewer’s local host when rendering `AgentCell`, which can show incorrect agent labels/icons compared to the actual dispatch host.</violation>
</file>

<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/components/AutomationDetailSidebar/AutomationDetailSidebar.tsx">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/components/AutomationDetailSidebar/AutomationDetailSidebar.tsx:152">
P1: Selecting an agent now stores a host-specific agent ID but does not persist the selected host, so runs can be dispatched to a different host where that ID does not exist.</violation>
</file>

<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx:104">
P2: Template prefill can run repeatedly when agent choices refresh, because `applyTemplate` depends on `hostAgents`; that can reset user-edited form fields while the dialog is open.

(Based on your team's feedback about narrowing React effect dependencies to required fields.) [FEEDBACK_USED]</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

agentId={automation.agentConfig.id}
label={automation.agentConfig.label}
agentId={automation.agent}
hostId={automation.targetHostId ?? null}
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.

P2: Auto-targeted automations are resolved against the viewer’s local host when rendering AgentCell, which can show incorrect agent labels/icons compared to the actual dispatch host.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx, line 485:

<comment>Auto-targeted automations are resolved against the viewer’s local host when rendering `AgentCell`, which can show incorrect agent labels/icons compared to the actual dispatch host.</comment>

<file context>
@@ -481,8 +481,8 @@ function AutomationsPage() {
-												agentId={automation.agentConfig.id}
-												label={automation.agentConfig.label}
+												agentId={automation.agent}
+												hostId={automation.targetHostId ?? null}
 											/>
 										</span>
</file context>

… fallback

The Team scope tab on the automations page lists teammates' automations,
which usually pin `targetHostId` to a host the current user has no tRPC
access to. `useV2AgentChoices(hostUrl)` returns empty for those, and the
old fallback showed the raw `agent` id (e.g. "claude") in the cell.

Fall through to `getPresetById` from `@superset/shared/host-agent-presets`
when the host query has no match. Resolves to the seeded label for any
presetId-shaped agent value (`claude` -> "Claude", `codex` -> "Codex",
etc.), which is the 99% case. Custom non-preset agents pinned to a
cross-host automation still show the raw id, but that's rare.

Apply the same fallback in `AgentPicker` so the trigger label is sensible
before the host query lands and for the same cross-host edge case.
- Sidebar: when changing the agent on an auto-routed automation, also
  persist `targetHostId` to the host the picker was scoped against.
  Otherwise a host-specific instance UUID could be written to a row that
  dispatches to a different online host, which wouldn't have that id.
  (cubic P1)

- Migration: wrap the backfill UPDATE in a `DO $$ ... EXECUTE ... $$`
  block so the `agent_config ->> 'id'` reference isn't parsed when
  re-applying the migration against a DB where the column has already
  been dropped. The earlier `EXISTS (information_schema)` guard avoided
  execution but not parse-time validation. (cubic P2)

- CreateAutomationDialog: split the template prefill into a one-shot
  scalar-fields effect (refs-tracked) and a separate agent-matching
  effect that runs only when `hostAgents` first resolves. Stops the
  whole prefill from re-firing and clobbering user edits when the
  agent-list query refreshes mid-session. (cubic P2)
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx:96">
P2: Template selection from the gallery no longer applies the template’s preferred agent, causing automations to run with the wrong agent.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Comment on lines 96 to 100
const applyTemplate = useCallback((template: AutomationTemplate) => {
setName(template.name);
setPrompt(template.prompt);
if (template.agentType) setAgentType(template.agentType);
if (template.rrule) setRrule(template.rrule);
}, []);
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.

P2: Template selection from the gallery no longer applies the template’s preferred agent, causing automations to run with the wrong agent.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/components/CreateAutomationDialog/CreateAutomationDialog.tsx, line 96:

<comment>Template selection from the gallery no longer applies the template’s preferred agent, causing automations to run with the wrong agent.</comment>

<file context>
@@ -87,30 +87,44 @@ export function CreateAutomationDialog({
+	const appliedTemplateRef = useRef<AutomationTemplate | null>(null);
+	const appliedAgentForTemplateRef = useRef<AutomationTemplate | null>(null);
+
+	const applyTemplate = useCallback((template: AutomationTemplate) => {
+		setName(template.name);
+		setPrompt(template.prompt);
</file context>
Suggested change
const applyTemplate = useCallback((template: AutomationTemplate) => {
setName(template.name);
setPrompt(template.prompt);
if (template.agentType) setAgentType(template.agentType);
if (template.rrule) setRrule(template.rrule);
}, []);
const applyTemplate = useCallback(
(template: AutomationTemplate) => {
setName(template.name);
setPrompt(template.prompt);
if (template.agentType) {
const match = hostAgents.find(
(option) =>
option.id === template.agentType ||
option.iconId === template.agentType,
);
if (match) setAgent(match.id);
}
if (template.rrule) setRrule(template.rrule);
},
[hostAgents],
);

Tip: Review your code locally with the cubic CLI to iterate faster.

@saddlepaddle saddlepaddle merged commit 56892a2 into main May 13, 2026
16 of 17 checks passed
This was referenced May 13, 2026
saddlepaddle added a commit that referenced this pull request May 13, 2026
Changes since alpha.9:

- workspaces.list accepts `projectId`, `projectName`, and `search` to
  filter the listing — matches the desktop list view. (#4455)
- chore(deps): pin exact dev versions (`bun-types` 1.3.11, `typescript`
  5.9.3). (#4436)
- BREAKING: `automations.create` / `automations.update` /
  `AutomationSummary` rename `agentConfig` -> `agent` (string id of a
  host agent instance or preset, e.g. `claude`, `codex`, `superset`).
  The `AgentConfig` type is removed from the public surface. The host
  now resolves the live agent config on every run, so client-side
  snapshots no longer drift from `Settings → Agents` edits. (#4481)

After merge: `cd packages/sdk && bun run build && cd dist && npm publish --access public`.
saddlepaddle added a commit that referenced this pull request May 13, 2026
Changes since v0.2.15:

- workspaces: `superset workspaces list` table now shows the workspace
  ID column. (#4463)
- docs: VHS demo walkthrough recording added under `packages/cli/demo/`.
  (#4461)
- auth: `superset auth login --api-key sk_live_…` stores an API key at
  `~/.superset/config.json` instead of running the OAuth flow; `whoami`
  and `logout` updated to recognize stored keys. (#4472)
- hosts: `superset hosts list` shows `local` for the host machine you're
  invoking from, distinct from `online`/`no`. (#4476)
- automations: `--agent` is now the host agent instance/preset id (e.g.
  `claude`, `codex`, `superset`) and is resolved live from the host on
  every run. The `--agent-config-file` flag is removed; create/update
  rename `agentConfig` -> `agent` end-to-end. (#4481)

Push cli-v0.2.16 after this lands to fire the release pipeline.
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