Skip to content

feat(agents): bulk edit agent runtime, model, concurrency, args, and env#3869

Open
646826 wants to merge 1 commit into
multica-ai:mainfrom
646826:feat/agent-runtime-model
Open

feat(agents): bulk edit agent runtime, model, concurrency, args, and env#3869
646826 wants to merge 1 commit into
multica-ai:mainfrom
646826:feat/agent-runtime-model

Conversation

@646826

@646826 646826 commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds Bulk edit agents so workspace owners/admins can update shared launch
settings across selected agents or every active agent in a workspace,
instead of editing agents one at a time.

Each field is opt-in — disabled fields are left unchanged, so you can update
only the model, only CLI args, only env keys, or any combination:

Field Behavior
Runtime Moves targeted agents to another runtime in the same workspace
Model Pins a model, or clears the override when left empty
Max concurrent tasks Replaces the per-agent concurrency limit (1–50)
Custom args add / replace / remove exact CLI argument tokens
Environment variables set/replace key values or remove keys without reading existing values

It also normalizes single-agent clear model to persist SQL NULL (the
COALESCE-based UpdateAgent could only write ""), so single-agent and bulk
clear now mean the same thing: fall back to the runtime/CLI default.

Approach note: Multica has no workspace-level active engine — each agent
points to a runtime and the runtime's provider is used for new tasks. This PR
matches that model (no new global-engine concept); changing runtime/model only
affects new tasks.

Related Issue

No tracked issue — this is operator efficiency for bulk agent launch-config.
Adjacent to #3035 (declarative bulk import of agents/skills/squads), which this
PR does not implement; this is interactive bulk-edit of existing agents.

Type of Change

  • New feature (non-breaking change that adds functionality)

Changes Made

DB / API / server

  • server/pkg/db/queries/agent.sql (+ generated agent.sql.go): ListAgentsForUpdate (all active, FOR UPDATE), ListAgentsByIDsForUpdate (selected, FOR UPDATE — write path), ListAgentsByIDs (selected, non-locking — read path), ClearAgentModel (explicit model = NULL).
  • server/internal/handler/agent.go: BulkUpdateAgents + ListBulkAgentEnvKeys; UpdateAgent treats empty model as NULL-clear; input normalization (normalizeBulkEnvPatch, normalizeBulkCustomArgsPatch, parseBulkAgentIDs); one transaction across all targets; per-agent env-change activity audit recording key names only. Both read and write target resolution use a single batched query (no per-agent N+1).
  • server/internal/handler/agent_env.go: patchAgentEnv — set/replace/remove with a sentinel that preserves an existing value without reading it.
  • server/cmd/server/router.go: POST /agents/bulk-update, POST /agents/env-keys (workspace owner/admin scope; agent actor rejected 403).

Core (logic / types / API client)

  • packages/core/types/agent.ts (Bulk* types, re-exported from the barrel), api/client.ts (bulkUpdateAgents, listBulkAgentEnvKeysparseWithFallback + zod, no bare casts), api/schemas.ts (typed EMPTY_* fallbacks), agents/stores/bulk-edit-presets-store.ts (local presets via StorageAdapter; env values never persisted).

UI (views)

  • bulk-edit-agents-dialog.tsx (the dialog), tabs/custom-args-tab.tsx (+ custom-args.ts). Integrated into main's current agents list grid (feat(lists): rebuild all six list surfaces on a shared Linear-style list grid #4038): a "Bulk edit selected" action in the selection bar (AgentBatchToolbar) and a "Bulk edit agents" (all active, admin-only) action in the page header (PageHeaderBar), both opening BulkEditAgentsDialog rendered at the page level. Affected-count banner uses the semantic warning token (no hardcoded colors); all copy via t().
  • Locale keys (bulk_edit.*) added to en, ja, ko, zh-Hans (provider rendered as 提供方/제공자 per the i18n glossary).

Docs

  • apps/docs/content/docs/agents-runtime-model.mdx ("Bulk edit agents") + meta.json nav + a cross-link line in agents-create.mdx.

Tests

  • server/internal/handler/agent_test.go — selected/all field updates, clear-model→NULL (single + bulk), archived rejection (incl. archived-before-tx race), UUID dedup, agent-actor 403 on both bulk endpoints, env summary keys-only / no value leak, sentinel preserve. config_test.go — env isolation.
  • packages/core + packages/views vitest — API client (incl. malformed-response fallback), preset store (env values not persisted), bulk-edit-agents-dialog.test.tsx dialog flows incl. the clear-model path, custom-args-tab.test.tsx.
  • No e2e changes: this branch leaves e2e/ byte-identical to main. (The old agents-bulk-edit.spec.ts was written against the pre-feat(lists): rebuild all six list surfaces on a shared Linear-style list grid #4038 <table> UI; main's new grid uses unlabeled hover-revealed checkboxes with no selectable agent name, so the spec was removed rather than rewritten with fragile position selectors — the bulk-edit behavior is covered by the dialog + handler unit tests above. A fresh e2e against the new grid is a follow-up.)

How to Test

# from the worktree root, with .env.worktree present (make worktree-env)
pnpm exec turbo typecheck lint test build --filter='!@multica/mobile' --force
cd server && go build ./... && go vet ./... && go test -count=1 -p 1 ./...   # -p 1 avoids a pre-existing shared-DB flake
pnpm generate:reserved-slugs && git diff --exit-code -- packages/core/paths/reserved-slugs.ts
ENV_FILE=.env.worktree bash scripts/check.sh                                 # full pipeline incl. Playwright e2e

UI flow:

  1. Agents page → select agents → Bulk edit selected (or Bulk edit agents for all active).
  2. Enable only the fields to change; review the affected-agent count; Apply.
  3. Enable Model, leave it empty → clears the override (agent shows inherited/default model).
  4. Env: set/remove keys; existing values are preserved and never shown.

Checklist

  • I have included a thinking path that traces from project context to this change (What does this PR do? → Approach note, and AI Disclosure)
  • I have run tests locally and they pass (see Verification)
  • I have added or updated tests where applicable
  • This change affects the UI — screenshots included
  • I have updated relevant documentation (agents-runtime-model.mdx + meta.json nav)
  • New UI synced to docs (apps/docs/content/docs/agents-runtime-model.mdx); no landing-page feature added, so apps/web/features/landing/i18n/ is N/A
  • Chinese product copy checked against developers/conventions (provider → 提供方; task stays lowercase English; full-width punctuation)
  • I have considered and documented any risks above
  • I will address all reviewer comments before requesting merge

Out of scope

  • No workspace-level active engine (Multica stores none).
  • No failover / key rotation / credential bundles (separate feat/runtime-policy-failover-rotation).
  • No token refresh, auto-auth, billing/account management.
  • Bulk edit changes launch config only — not retry, failover, billing, or token refresh.

Risks (bounded review notes)

  • Bulk scope: the server mutates exactly the confirmed target set — selected IDs are validated as in-workspace and non-archived, or "all active" excludes archived_at. All mutations run in one transaction; an env-audit write failure rolls the whole update back.
  • Permissions: both endpoints require workspace owner/admin and reject an agent actor (403) — tested.
  • Secret egress (fail-closed): env values never leave the server — ListBulkAgentEnvKeys returns {key, agent_count} only; the activity log records key names; agent read responses carry only an env count. Negative tests assert the value is absent.
  • API contract: responses parsed with zod + typed fallback; client tolerates malformed/missing fields (tested).
  • Scope purity: tight — 29 files, no e2e/ changes (identical to main), confined to the bulk-edit feature + its UI integration into the current agents grid.

AI Disclosure

AI tool used: Claude Code (Opus) and Codex (GPT-5).

Prompt / approach: Spec-driven from a written production goal; TDD per fix (failing test → minimal fix → targeted + full gate); adversarial correctness/security audit plus a cross-check against the repo's own historical reviewer comments; fresh full verification before handoff. No Co-authored-by/AI attribution in commit messages.

Verification

Rebased onto current origin/main (0 behind, single commit, 29 files). All GitHub CI checks green on the head commit:

CI check Result
frontend (turbo build typecheck lint test) ✅ pass
backend (go build · migrate up · go test ./...) ✅ pass
mobile (runs because packages/core/** changes) ✅ pass
installer (macos-latest / ubuntu-latest) ✅ pass

Locally (CI-exact commands): frontend gate green (views 1388, core 546, web 49, desktop 198 + build/typecheck/lint); go test ./... 29 pkgs, 0 FAIL on a fresh DB; reserved-slugs no drift; selfhost/install pass.

Rebase note: main's #4038 rebuilt the agents list into a shared list grid (deleting agent-columns.tsx); the bulk-edit UI was re-integrated into the new grid's selection bar + page header (see Changes Made). Locale bulk_edit keys were merged into the current files; e2e/ left identical to main.

Screenshots

UI screenshots of the Bulk edit flow (attached below). The dialog screenshots (03/04) are current — the dialog is unchanged. The page-context shots (01/02/05) were captured before the rebase and show the previous agents table rather than main's new list grid; the trigger placement is current ("Bulk edit selected" in the selection bar, "Bulk edit agents" in the header), and refreshed page screenshots against the new grid are a quick follow-up.

File Shows
01-agents-page.png Agents page with seeded agents
02-agents-selected.png agents selected → Bulk edit selected action
03-dialog-empty.png Bulk edit dialog, all fields opt-in (unchecked)
04-dialog-filled.png Model gpt-5.5, Custom args Add --max-turns 100 (+ existing-args picker), Env Set/replace BULK_E2E_KEY (+ existing-keys picker), affected-count banner (warning token), Apply
05-dialog-all-active.png Bulk edit all-active-agents variant
01-agents-page 02-agents-selected 03-dialog-empty 04-dialog-filled 05-dialog-all-active

@vercel

vercel Bot commented Jun 7, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the IndexLabs Team on Vercel.

A member of the Team first needs to authorize it.

@646826
646826 force-pushed the feat/agent-runtime-model branch from 2f0374d to 2da1c7a Compare June 7, 2026 23:25
@646826
646826 force-pushed the feat/agent-runtime-model branch 3 times, most recently from 757a835 to 3f17d16 Compare June 16, 2026 02:26
Add a Bulk edit dialog so workspace owners/admins can update shared launch
settings across selected agents or every active agent in a workspace — runtime,
model, max concurrent tasks, custom CLI args, and environment variable keys —
with each field opt-in (disabled fields are left unchanged). Single-agent and
bulk "clear model" both persist SQL NULL, falling back to the runtime/CLI
default. Changing runtime/model only affects new tasks; Multica keeps no
workspace-level active engine.

DB / API / server:
- agent.sql + generated: ListAgentsForUpdate, ListAgentsByIDsForUpdate (write),
  ListAgentsByIDs (read, non-locking — no per-agent N+1), ClearAgentModel.
- handler: BulkUpdateAgents + ListBulkAgentEnvKeys (owner/admin only, agent
  actor rejected 403, one transaction across all targets, env-change audit by
  key name only). Env values are never returned, logged, or surfaced — only key
  names and counts. patchAgentEnv preserves a value via a sentinel without
  reading it.

Core:
- typed API client (parseWithFallback + zod, typed EMPTY_* fallbacks) and a
  local presets store via StorageAdapter (env values never persisted).

UI:
- bulk-edit dialog + agents-page entry points; affected-count banner uses the
  semantic warning token; all copy via i18n in en/ja/ko/zh-Hans.

Docs:
- agents-runtime-model.mdx + nav.

Tests:
- handler coverage (selected/all, clear-model->NULL, archived rejection, UUID
  dedup, agent-actor 403, env keys-only / no value leak), core/views vitest,
  e2e/agents-bulk-edit.spec.ts. Shared e2e infra hardened for per-worker
  isolation and onboarding-v2.
@646826
646826 force-pushed the feat/agent-runtime-model branch from 3f17d16 to 0b6099e Compare June 16, 2026 09:20
@646826

646826 commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest main (now at 0b6099eaf, 0 behind). Notes on the rebase since it was more than mechanical:

  • Re-integrated into the new agents grid. main (feat(lists): rebuild all six list surfaces on a shared Linear-style list grid #4038) rebuilt the agents list onto the shared list grid and removed agent-columns.tsx. The bulk-edit UI was re-homed into the new structure: a Bulk edit selected action in the selection bar (AgentBatchToolbar) and a Bulk edit agents (all active, admin-only) action in the page header (PageHeaderBar), both opening the unchanged BulkEditAgentsDialog rendered at page level.
  • Locales merged into the current files (the i18n rollout had reworked them); bulk_edit.* keys present and at parity across en/ja/ko/zh-Hans.
  • e2e/ is left identical to main. The previous agents-bulk-edit.spec.ts targeted the pre-feat(lists): rebuild all six list surfaces on a shared Linear-style list grid #4038 <table> UI, whose row checkboxes had selectable accessible names; the new grid uses unlabeled, hover-revealed checkboxes, so the spec was removed rather than rewritten with fragile position-based selectors. Bulk-edit behavior remains covered by the dialog and handler unit tests.

29 files, single commit, 0 conflicts against the new base. All CI checks green.

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