95 lines
3.5 KiB
TypeScript
95 lines
3.5 KiB
TypeScript
import { LoaderCircle, Sparkles } from "lucide-react";
|
|
import { useState } from "react";
|
|
import { useNavigate } from "react-router";
|
|
import { toast } from "sonner";
|
|
import { useCreateAgentRun } from "~/api/agent.ts";
|
|
import { FormField } from "~/components/console/form-field.tsx";
|
|
import { consolePath } from "~/components/console/nav.ts";
|
|
import { Button } from "~/components/ui/button.tsx";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "~/components/ui/dialog.tsx";
|
|
import { Textarea } from "~/components/ui/textarea.tsx";
|
|
import { errorMessage } from "~/lib/api.ts";
|
|
|
|
// 用对话起草巡检:用户一句话描述需求 → 发起智能体对话(起草巡检 Skill)→ 智能体建成未启用的巡检,
|
|
// 对话里给「检查并启用」卡片,用户在计划页检查、修改后启用。
|
|
|
|
const EXAMPLES = [
|
|
"每天早上 9 点前看看有没有失败或卡住的下载,有就写成待处理",
|
|
"每隔 6 小时检查一下站点登录有没有失效",
|
|
"每周汇报一次订阅追更情况和缺集",
|
|
];
|
|
|
|
export function DraftCheckDialog({ open, onOpenChange }: { open: boolean; onOpenChange: (o: boolean) => void }) {
|
|
const [text, setText] = useState("");
|
|
const create = useCreateAgentRun();
|
|
const navigate = useNavigate();
|
|
const submit = async () => {
|
|
const need = text.trim();
|
|
if (need.length < 4) return;
|
|
try {
|
|
const run = await create.mutateAsync({ goal: `帮我起草一个巡检:${need}` });
|
|
onOpenChange(false);
|
|
navigate(consolePath("agent", run.id));
|
|
} catch (err) {
|
|
toast.error(errorMessage(err, "发起对话失败"));
|
|
}
|
|
};
|
|
return (
|
|
<Dialog open={open} onOpenChange={(o) => !create.isPending && onOpenChange(o)}>
|
|
<DialogContent className="sm:max-w-lg">
|
|
<DialogHeader>
|
|
<DialogTitle>用对话起草巡检</DialogTitle>
|
|
<DialogDescription>
|
|
说说想定期检查什么、多久一次。智能体会建一个未启用的巡检,你检查后再启用。
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<form
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
void submit();
|
|
}}
|
|
>
|
|
<FormField label="需求" htmlFor="draft-need" required>
|
|
<Textarea
|
|
id="draft-need"
|
|
rows={4}
|
|
autoFocus
|
|
value={text}
|
|
placeholder={EXAMPLES[0]}
|
|
onChange={(e) => setText(e.target.value)}
|
|
/>
|
|
</FormField>
|
|
<div className="mb-3 flex flex-wrap gap-1.5">
|
|
{EXAMPLES.map((x) => (
|
|
<button
|
|
key={x}
|
|
type="button"
|
|
onClick={() => setText(x)}
|
|
className="rounded-full border border-border/70 px-2.5 py-1 text-left text-meta text-muted-foreground transition-colors hover:border-foreground/40 hover:text-foreground"
|
|
>
|
|
{x}
|
|
</button>
|
|
))}
|
|
</div>
|
|
<DialogFooter>
|
|
<Button type="button" variant="ghost" onClick={() => onOpenChange(false)} disabled={create.isPending}>
|
|
取消
|
|
</Button>
|
|
<Button type="submit" disabled={create.isPending || text.trim().length < 4}>
|
|
{create.isPending ? <LoaderCircle className="animate-spin" /> : <Sparkles />}
|
|
开始起草
|
|
</Button>
|
|
</DialogFooter>
|
|
</form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|