feat: slug change + streaming fix + specs
This commit is contained in:
parent
79541d133a
commit
13a1748162
@ -11,6 +11,8 @@ interface Props {
|
||||
|
||||
export default function AgentModal({ agent, onClose, onUpdated }: Props) {
|
||||
const [name, setName] = useState(agent.name);
|
||||
const [slug, setSlug] = useState(agent.slug);
|
||||
const [slugError, setSlugError] = useState("");
|
||||
const [capabilities, setCapabilities] = useState(
|
||||
agent.agent_config?.capabilities?.join(", ") || ""
|
||||
);
|
||||
@ -34,8 +36,14 @@ export default function AgentModal({ agent, onClose, onUpdated }: Props) {
|
||||
setSaving(true);
|
||||
try {
|
||||
const caps = capabilities.split(",").map((c) => c.trim()).filter(Boolean);
|
||||
const trimmedSlug = slug.trim().toLowerCase().replace(/[^a-z0-9_-]/g, '');
|
||||
if (!trimmedSlug) {
|
||||
setSlugError("Slug не может быть пустым");
|
||||
return;
|
||||
}
|
||||
const updated = await updateMember(agent.id, {
|
||||
name: name.trim(),
|
||||
slug: trimmedSlug !== agent.slug ? trimmedSlug : undefined,
|
||||
agent_config: {
|
||||
capabilities: caps,
|
||||
labels: agentLabels,
|
||||
@ -47,8 +55,12 @@ export default function AgentModal({ agent, onClose, onUpdated }: Props) {
|
||||
});
|
||||
onUpdated(updated);
|
||||
onClose();
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
if (e?.response?.status === 409) {
|
||||
setSlugError("Этот slug уже занят");
|
||||
} else {
|
||||
console.error(e);
|
||||
}
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
@ -114,6 +126,17 @@ export default function AgentModal({ agent, onClose, onUpdated }: Props) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm text-[var(--muted)] mb-1">Slug</label>
|
||||
<input
|
||||
value={slug}
|
||||
onChange={(e) => { setSlug(e.target.value); setSlugError(""); }}
|
||||
className={`w-full px-3 py-2 bg-[var(--bg)] border rounded-lg outline-none text-sm ${slugError ? 'border-red-500' : 'border-[var(--border)] focus:border-[var(--accent)]'}`}
|
||||
placeholder="agent-slug"
|
||||
/>
|
||||
{slugError && <div className="text-xs text-red-400 mt-1">{slugError}</div>}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm text-[var(--muted)] mb-1">Capabilities</label>
|
||||
<input
|
||||
|
||||
@ -354,12 +354,12 @@ export default function ChatPanel({ chatId, projectId }: Props) {
|
||||
<span className="animate-pulse">●</span>
|
||||
</div>
|
||||
{streaming.thinking && (
|
||||
<details className="ml-5 mb-1" open>
|
||||
<details className="ml-5 mb-1">
|
||||
<summary className="text-xs text-[var(--muted)] cursor-pointer hover:text-[var(--fg)]">
|
||||
💭 Размышления
|
||||
💭 Размышления ({streaming.thinking.length} символов)
|
||||
</summary>
|
||||
<div className="mt-1 text-xs text-[var(--muted)] whitespace-pre-wrap bg-white/5 rounded p-2 max-h-[200px] overflow-y-auto">
|
||||
{streaming.thinking}
|
||||
{streaming.thinking.length > 500 ? '…' + streaming.thinking.slice(-500) : streaming.thinking}
|
||||
</div>
|
||||
</details>
|
||||
)}
|
||||
@ -372,8 +372,8 @@ export default function ChatPanel({ chatId, projectId }: Props) {
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{streaming.text && (
|
||||
<div className="ml-5 whitespace-pre-wrap">{streaming.text}</div>
|
||||
{streaming.text && !streaming.tools.some(t => t.status === "running") && (
|
||||
<div className="ml-5 whitespace-pre-wrap">{streaming.text.length > 500 ? '…' + streaming.text.slice(-500) : streaming.text}</div>
|
||||
)}
|
||||
{!streaming.text && streaming.tools.length === 0 && !streaming.thinking && (
|
||||
<div className="ml-5 text-[var(--muted)] italic">Думает...</div>
|
||||
|
||||
@ -316,6 +316,7 @@ export async function createMember(data: {
|
||||
|
||||
export async function updateMember(memberId: string, data: {
|
||||
name?: string;
|
||||
slug?: string;
|
||||
role?: string;
|
||||
status?: string;
|
||||
agent_config?: Partial<AgentConfig>;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user