Skip to content

feat(studio-cp,oab-mcp,src-tauri): add deploy_provision_agent (studio#128) - #129

Merged
brettchien merged 2 commits into
mainfrom
feat/deploy-provision-agent-128
Aug 29, 2026
Merged

feat(studio-cp,oab-mcp,src-tauri): add deploy_provision_agent (studio#128)#129
brettchien merged 2 commits into
mainfrom
feat/deploy-provision-agent-128

Conversation

@brettchien

@brettchien brettchien commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Summary

First slice of #128 — backend capability only. Adds a new provisioning path for the New Fleet wizard's vendor/chat-platform/ACP flow, bypassing the compose library (template ⊕ overlay) entirely. Purely additive: the existing deploy_provision/compose-library path is completely untouched.

Revised after Brett's review: config.toml is now rendered server-side from structured fields, not assembled as text on the console and passed through — this file can also be produced by an admin agent calling the same MCP tool directly (not through Studio's UI), so the actual rendering logic has to be a single source of truth both callers go through, not duplicated client-side.

Change (all 3 layers)

  • studio-cp: provision_agent / provision_agent_k8s take an AgentWizardInput (api_key, chat_platform, chat_bot_token, chat_channel_secret) instead of raw config_toml bytes. New generate_agent_config() renders the actual TOML text server-side — the structured-input counterpart of oabctl create's generate_config, generalized from Discord-only to discord/telegram/line. New provision_agent_secrets() stores the secret-bearing fields in the same oab/{namespace}/{name} Secrets Manager convention oabctl create already uses for the Discord token (a separate secret from feat(oabctl,studio-cp): enable ACP by default on Studio-deployed agents #127's ACP auth key — different delivery mechanism, config-level [secrets.refs]/aws-sm:// vs. container-level env var injection). k8s deploys refuse a non-empty chat_platform: confirmed k8s_driver.rs's build_deployment injects no AWS credentials into the pod, so config.toml's aws-sm:// secret resolution has nothing to authenticate with at runtime — refusing up front beats deploying something that silently fails inside the container. ACP-only k8s deploys are unaffected. Otherwise unchanged from the original slice: same create-vs-redeploy branch, same pre_seed hook injection, same bundle upload sequence as provision_from_library[_k8s], deliberately duplicated rather than shared-refactored for the same reason provision_from_library_k8s's own doc comment already gives.
  • oab-mcp: deploy_provision_agent tool schema updated to the structured fields; t_provision_agent builds an AgentWizardInput from args and dispatches. Tool-count test still 18 (only the schema changed, not the tool list).
  • src-tauri: bridge command signature updated to match.

Known gap, flagged not hidden: api_key is captured and stored as a secret but not yet wired into config.toml — which env var a given vendor's CLI actually expects its API key under needs vendor-specific research this round didn't do. Documented in the struct/tool schema rather than fabricating a config key nothing reads.

Verification

  • Not locally compiled — same pre-existing aws-sdk-ec2 OOM limitation as every other Rust PR this week; src-tauri additionally can't be checked at all in this sandbox (no macOS system libs).
  • Every new function mirrors an already-working sibling closely (provision_from_library/provision_from_library_k8s for the studio-cp shape; oabctl create's generate_config/store_secret for the TOML-rendering and secret-storage patterns) — hand-verified line by line against them.
  • CI's build-test/bundle-macos jobs are the real gate here.
  • Nothing in this PR is reachable from the UI yet — console wiring is a separate follow-up PR.

Ref #128.

🤖 Generated with Claude Code

…#128)

New Fleet wizard direction (Brett, this thread): drop the compose-library
Template/Overlay model, replace with a vendor + chat-platform + ACP flow
that composes config.toml directly. Confirmed earlier (#128 investigation)
that provision_manifest/provision_k8s don't require a Bundle produced by
compose_named — a hand-built Bundle{image_tag, files} works identically.

This PR adds the backend capability only (all 3 layers: MCP tool, Tauri
bridge, studio-cp core) — purely additive, doesn't touch the existing
deploy_provision/compose-library path at all. Console wiring (replacing
the Template/Overlay UI with the new wizard) is a separate follow-up PR.

- studio-cp: provision_agent / provision_agent_k8s — near-duplicates of
  provision_from_library[_k8s] from "resolve the bucket" onward (same
  create-vs-redeploy branch, same pre_seed hook injection, same bundle
  upload), except the Bundle's config.toml comes from the caller directly
  instead of studio_compose::compose_named(library, template, overlay).
  Deliberate duplication over a shared refactor, matching the tradeoff
  provision_from_library_k8s's own doc comment already made for the same
  reason (avoid risking the already-landed functions' shape).
- oab-mcp: new deploy_provision_agent tool (config_toml + image + name,
  same provider/context/expected_principal/fleet/cluster args as
  deploy_provision minus library/template/overlay), dispatches to the new
  studio-cp functions. Tool-count test updated (17 -> 18).
- src-tauri: deploy_provision_agent bridge command, mirroring
  deploy_provision's shape, registered in generate_handler!.

Ref #128.
…rver-side

Brett's catch: this form's output is ultimately a config.toml for the
created agent, and that file can also be produced by an admin agent
calling the same tool directly (not through Studio's UI) — for those to
stay in sync, the actual TOML-rendering logic can't live in the console
(TypeScript), it has to be the single server-side source of truth both
callers go through.

deploy_provision_agent's config_toml:string param is replaced with
structured fields (api_key, chat_platform, chat_bot_token,
chat_channel_secret) — studio-cp's new generate_agent_config() renders the
actual text (the structured-input counterpart of oabctl create's
generate_config, generalized from Discord-only to discord/telegram/line).
Any caller sending the same fields — the wizard or a future admin agent —
gets byte-identical config.toml by construction, not by convention.

provision_agent_secrets() stores the secret-bearing fields in the same
oab/{namespace}/{name} Secrets Manager convention oabctl create already
uses for the Discord token — a separate secret from #127's ACP auth key,
since these feed config.toml's [secrets.refs]/${secrets.x} (openab's own
resolution, aws-sm:// only) while the ACP key is a container-level env var
injected via spec.secrets, a different delivery path entirely.

k8s deploys refuse a non-empty chat_platform rather than silently
deploying something broken: config.toml's secret resolution only
understands aws-sm://, and k8s_driver.rs's build_deployment injects no AWS
credentials into the pod at all (confirmed by reading it) — so a k8s pod
has no way to actually resolve that URI at runtime. ACP-only k8s deploys
are unaffected (already-working, different mechanism).

api_key is captured/stored but not yet wired into config.toml — which env
var a given vendor's CLI expects it under needs vendor-specific research
this round didn't do. Flagged in the tool schema and struct doc comment
rather than fabricating a config key nothing reads.

Ref #128.
@brettchien
brettchien merged commit 871e6ce into main Aug 29, 2026
2 checks passed
@brettchien
brettchien deleted the feat/deploy-provision-agent-128 branch August 29, 2026 08:20
brettchien added a commit that referenced this pull request Aug 29, 2026
…write (studio#128) (#132)

Replaces the Template/Overlay compose-library step (empty on every fresh
install by design, blocking the whole deploy flow — the original #119
screenshot that started this) with the vendor + chat platform + ACP flow
confirmed with Brett across #128's design thread.

## Console (items 1-5 of the runbook, shipped together — all fields live
on the same new Step 2 screen)

- Vendor <select>: Claude/codex/agy/cursor/kiro. "agy" is only the display
  label — the option value is "antigravity" (the GHCR image variant /
  Dockerfile.package build-target name resolve_vendor_image_tags expects).
- Image tag: pre-filled from resolve_vendor_image_tags (#131) — Stable if
  GHCR confirms it exists, else Beta (pre-beta-<vendor>), else left for
  manual entry. Always editable — no lookup failure blocks the field.
- API key (optional): captured, stored as a secret server-side; not yet
  wired into config.toml (documented gap from #129, unchanged here).
- Chat platform (optional, default none — "use ACP directly"):
  Discord/Telegram/LINE, reveals the right token field(s) per platform.
  k8s deploys refuse a non-empty selection both client-side (clean
  validation message) and server-side (#129's existing refusal) — config.toml
  secret resolution needs AWS credentials a k8s pod doesn't have.
- Enable ACP checkbox: default checked, forced off + disabled for
  vendor=agy (its bridge bypasses openab-gateway's /acp route entirely).
- Agent name: pre-filled with a random Greek god name, shuffle button to
  re-roll, still freely editable.
- No separate "Preview bundle" step anymore — fill in the fields, Deploy.

## Backend: acp_enabled made caller-controlled (was hardcoded true in #127)

#127 hardcoded `acp_enabled: Some(true)` inside build_default_manifest /
build_default_k8s_manifest with no way for a caller to turn it off — fine
when nothing exposed a toggle, not fine once the wizard has an actual
checkbox (needed for the agy case above). Both functions, and
AgentWizardInput, now take `acp_enabled: bool` explicitly:
- studio-cp: build_default_manifest/build_default_k8s_manifest gained an
  `acp_enabled: bool` param — only generates the ACP auth secret when true.
  provision_from_library[_k8s] (the older compose-library path, unrelated
  to this wizard) pass `true` at their call sites, preserving #127's
  original unconditional-on behavior there unchanged.
- oab-mcp: deploy_provision_agent's schema gained `acp_enabled: boolean`,
  defaulting to true when the caller omits it (same default #127 had,
  now explicit and overridable instead of baked in).
- src-tauri: bridge command threads the new param through.

Ref #128.
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