feat: add project-aware agent workspace
Generic Container CI/CD / test-build-publish (push) Successful in 2m9s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 2m39s

This commit is contained in:
2026-10-22 18:52:18 +08:00
parent c6a0e74e72
commit 2d8506fea0
191 changed files with 12373 additions and 3556 deletions
@@ -0,0 +1,73 @@
import { useState } from "react";
import { Check, Copy, LoaderCircle } from "lucide-react";
import { Badge } from "@/shared/ui/badge";
import { MessageAction, MessageActions } from "@/shared/ai-elements/message";
import type { AnswerUiPart } from "../answer-ui/contract";
export function AgentChatMessageHeader({
running,
interactive
}: {
running: boolean;
interactive: boolean;
}) {
if (!running && !interactive) return null;
return (
<div className="agent-chat-message-header">
{running ? (
<span
role="status"
className="ml-auto inline-flex items-center gap-1.5 text-[11px] text-muted-foreground"
>
<LoaderCircle size={12} className="motion-safe:animate-spin" aria-hidden="true" />
正在回复
</span>
) : interactive ? (
<Badge
variant="secondary"
className="ml-auto border-0 px-2 py-0.5 text-[10px] font-medium shadow-none"
>
交互回答
</Badge>
) : null}
</div>
);
}
export function AgentChatMessageActions({ parts }: { parts: AnswerUiPart[] }) {
const [copied, setCopied] = useState(false);
const [error, setError] = useState(false);
const text = parts
.map((part) => (part.type === "text" ? part.text : part.block.fallback_text))
.join("\n\n");
if (!text.trim()) return null;
return (
<MessageActions className="agent-chat-message-actions">
<MessageAction
tooltip={copied ? "回复已复制" : "复制回复"}
label={copied ? "回复已复制" : "复制回复"}
size="sm"
className="h-10 gap-1.5 px-2 text-[11px] font-normal shadow-none"
aria-label={copied ? "回复已复制" : "复制回复"}
onClick={async () => {
try {
await navigator.clipboard.writeText(text);
setCopied(true);
setError(false);
} catch {
setCopied(false);
setError(true);
}
}}
>
{copied ? <Check size={13} aria-hidden="true" /> : <Copy size={13} aria-hidden="true" />}
{copied ? "已复制" : "复制回复"}
</MessageAction>
<span role="status" className="text-[11px] text-muted-foreground">
{error ? "复制失败,请选择文字复制" : copied ? "已复制回复文字与交互内容摘要" : ""}
</span>
</MessageActions>
);
}