loops wizard: extract AutoProvisionCard to stay under 1250 lines
ci / gates (push) Successful in 6s
ci / frontend (push) Failing after 33s
ci / rust (push) Successful in 2m52s
ci / e2e (push) Skipped
ci / publish (push) Skipped

Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
Omar Sobh
2026-07-18 16:23:13 -07:00
co-authored by Claude Opus 4.7
parent 65b19b0fc5
commit 279d785f5b
2 changed files with 104 additions and 71 deletions
@@ -0,0 +1,93 @@
"use client";
import type { CSSProperties } from "react";
import type { AutoProvisionResponse } from "@/lib/api/research";
const mono =
"ui-monospace, SFMono-Regular, SF Mono, Menlo, Monaco, Consolas, monospace";
export function AutoProvisionCard({
autoTeam,
autoProvisioning,
autoProvisionError,
disabled,
onProvision,
hintStyle,
primaryBtn,
description,
}: {
autoTeam: AutoProvisionResponse | null;
autoProvisioning: boolean;
autoProvisionError: string | null;
disabled: boolean;
onProvision: () => void;
hintStyle: CSSProperties;
primaryBtn: CSSProperties;
description?: string;
}) {
return (
<div
style={{
padding: 12,
borderRadius: 8,
border: `1px solid ${autoTeam ? "rgba(95,208,138,.35)" : "rgba(94,200,216,.35)"}`,
background: autoTeam
? "rgba(95,208,138,.06)"
: "rgba(94,200,216,.06)",
display: "flex",
flexDirection: "column",
gap: 10,
}}
>
<span
style={{
fontFamily: mono,
fontSize: 12,
color: autoTeam ? "#83e6a5" : "#7cd6e0",
}}
>
{autoTeam
? `Team ready · ${autoTeam.agents.length} agents · ${autoTeam.topology_kind}`
: "No team yet? Auto-provision one from the task."}
</span>
{!autoTeam && (
<p style={hintStyle}>
{description ??
"We ask Claude Sonnet 5 to derive 3–5 roles from the task above, then create each agent + wire them in."}
</p>
)}
{autoTeam ? (
<div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
{autoTeam.agents.map((a) => (
<span
key={a.agent_id}
style={{
fontFamily: mono,
fontSize: 11,
padding: "3px 8px",
borderRadius: 999,
border: "1px solid rgba(255,255,255,.14)",
background: "rgba(255,255,255,.04)",
color: "#d7d7db",
}}
>
{a.role_slot} · {a.display_name}
</span>
))}
</div>
) : (
<button
type="button"
onClick={onProvision}
disabled={disabled}
style={{ ...primaryBtn, opacity: disabled ? 0.5 : 1 }}
>
{autoProvisioning ? "Provisioning…" : "Auto-provision team"}
</button>
)}
{autoProvisionError && (
<p style={{ ...hintStyle, color: "#ff8a7a" }}>{autoProvisionError}</p>
)}
</div>
);
}
@@ -27,6 +27,7 @@ import {
autoProvisionTeam, autoProvisionTeam,
type AutoProvisionResponse, type AutoProvisionResponse,
} from "@/lib/api/research"; } from "@/lib/api/research";
import { AutoProvisionCard } from "./AutoProvisionCard";
// Do NOT import @/lib/api/team here — it transitively pulls bearer.ts // Do NOT import @/lib/api/team here — it transitively pulls bearer.ts
// (next/headers, server-only) into the client bundle and breaks the // (next/headers, server-only) into the client bundle and breaks the
// production build. Call /api/team/claws with plain fetch instead. // production build. Call /api/team/claws with plain fetch instead.
@@ -706,77 +707,16 @@ export function LoopsWizard({
{step === 6 && ( {step === 6 && (
<div style={{ display: "flex", flexDirection: "column", gap: 14 }}> <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
<div <AutoProvisionCard
style={{ autoTeam={autoTeam}
padding: 12, autoProvisioning={autoProvisioning}
borderRadius: 8, autoProvisionError={autoProvisionError}
border: `1px solid ${autoTeam ? "rgba(95,208,138,.35)" : "rgba(94,200,216,.35)"}`, disabled={autoProvisioning || task.trim().length === 0}
background: autoTeam onProvision={runAutoProvision}
? "rgba(95,208,138,.06)" hintStyle={hintStyle}
: "rgba(94,200,216,.06)", primaryBtn={primaryBtn}
display: "flex", description="We ask Claude Sonnet 5 to derive 3–5 roles from the task above, then create each agent + wire them into this loop."
flexDirection: "column", />
gap: 10,
}}
>
<span
style={{
fontFamily: mono,
fontSize: 12,
color: autoTeam ? "#83e6a5" : "#7cd6e0",
}}
>
{autoTeam
? `Team ready · ${autoTeam.agents.length} agents · ${autoTeam.topology_kind}`
: "No team yet? Auto-provision one from the loop's task."}
</span>
{!autoTeam && (
<p style={hintStyle}>
We ask Claude Sonnet 5 to derive 3–5 roles from the task
above, then create each agent + wire them into this loop.
</p>
)}
{autoTeam ? (
<div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
{autoTeam.agents.map((a) => (
<span
key={a.agent_id}
style={{
fontFamily: mono,
fontSize: 11,
padding: "3px 8px",
borderRadius: 999,
border: "1px solid rgba(255,255,255,.14)",
background: "rgba(255,255,255,.04)",
color: "#d7d7db",
}}
>
{a.role_slot} · {a.display_name}
</span>
))}
</div>
) : (
<button
type="button"
onClick={runAutoProvision}
disabled={autoProvisioning || task.trim().length === 0}
style={{
...primaryBtn,
opacity:
autoProvisioning || task.trim().length === 0 ? 0.5 : 1,
}}
>
{autoProvisioning
? "Provisioning…"
: "Auto-provision team"}
</button>
)}
{autoProvisionError && (
<p style={{ ...hintStyle, color: "#ff8a7a" }}>
{autoProvisionError}
</p>
)}
</div>
{rosterAgents.length > 0 && !autoTeam ? ( {rosterAgents.length > 0 && !autoTeam ? (
<> <>