104 lines
2.9 KiB
TypeScript
104 lines
2.9 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import { useState } from "react";
|
||
|
|
import { AlertTriangle, Bot, Loader2 } from "lucide-react";
|
||
|
|
|
||
|
|
import { agentBuilderStub, type AgentBuilderAdapter } from "./agent-builder";
|
||
|
|
import { WorkspaceComposer } from "./workspace-composer";
|
||
|
|
|
||
|
|
export type AgentLibraryStatus =
|
||
|
|
| { status: "loading" }
|
||
|
|
| { status: "empty" }
|
||
|
|
| { status: "error"; message: string };
|
||
|
|
|
||
|
|
export function AgentLibraryState({ state }: { state: AgentLibraryStatus }) {
|
||
|
|
if (state.status === "loading") {
|
||
|
|
return (
|
||
|
|
<p role="status" className="flex items-center gap-2">
|
||
|
|
<Loader2 className="size-4 animate-spin" aria-hidden="true" />
|
||
|
|
Loading agents…
|
||
|
|
</p>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
if (state.status === "error") {
|
||
|
|
return (
|
||
|
|
<p role="alert" className="flex items-center gap-2 text-destructive">
|
||
|
|
<AlertTriangle className="size-4" aria-hidden="true" />
|
||
|
|
{state.message}
|
||
|
|
</p>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
return (
|
||
|
|
<div className="space-y-2 text-center">
|
||
|
|
<Bot className="mx-auto size-8 text-primary" aria-hidden="true" />
|
||
|
|
<h3 className="font-medium">No reusable agents yet</h3>
|
||
|
|
<p className="text-sm text-muted-foreground">
|
||
|
|
Agent creation and the workspace library are coming soon. You can draft
|
||
|
|
instructions below; nothing will be created or sent to Chat.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function AgentsMode({
|
||
|
|
workspaceSlug,
|
||
|
|
active,
|
||
|
|
builder = agentBuilderStub,
|
||
|
|
libraryState = { status: "empty" },
|
||
|
|
}: {
|
||
|
|
workspaceSlug: string;
|
||
|
|
active: boolean;
|
||
|
|
builder?: AgentBuilderAdapter;
|
||
|
|
libraryState?: AgentLibraryStatus;
|
||
|
|
}) {
|
||
|
|
const [input, setInput] = useState("");
|
||
|
|
const [notice, setNotice] = useState<string | null>(null);
|
||
|
|
const [busy, setBusy] = useState(false);
|
||
|
|
|
||
|
|
async function submitBuilderRequest() {
|
||
|
|
setBusy(true);
|
||
|
|
try {
|
||
|
|
const result = await builder({ workspaceSlug, prompt: input.trim() });
|
||
|
|
setNotice(result.message);
|
||
|
|
} catch {
|
||
|
|
setNotice(
|
||
|
|
"Builder unavailable. Your draft has been kept; please try again later.",
|
||
|
|
);
|
||
|
|
} finally {
|
||
|
|
setBusy(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="flex h-full min-h-0 flex-col">
|
||
|
|
<div className="min-h-0 flex-1 overflow-y-auto">
|
||
|
|
<section
|
||
|
|
aria-label="Agent library"
|
||
|
|
className="mx-auto max-w-3xl space-y-6 px-4 py-6"
|
||
|
|
>
|
||
|
|
<h2 className="text-lg font-semibold">Agent library</h2>
|
||
|
|
<AgentLibraryState state={libraryState} />
|
||
|
|
{notice && (
|
||
|
|
<p
|
||
|
|
role="status"
|
||
|
|
className="rounded-lg border p-3 text-sm text-muted-foreground"
|
||
|
|
>
|
||
|
|
{notice}
|
||
|
|
</p>
|
||
|
|
)}
|
||
|
|
</section>
|
||
|
|
</div>
|
||
|
|
<WorkspaceComposer
|
||
|
|
mode="agents"
|
||
|
|
active={active}
|
||
|
|
input={input}
|
||
|
|
onInputChange={setInput}
|
||
|
|
busy={busy}
|
||
|
|
onSubmit={() => {
|
||
|
|
void submitBuilderRequest();
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|