From 13a1748162cbe94c4640fff2f525b9978d9c9fe6 Mon Sep 17 00:00:00 2001 From: Markov Date: Fri, 13 Mar 2026 22:55:53 +0100 Subject: [PATCH] feat: slug change + streaming fix + specs --- src/components/AgentModal.tsx | 27 +++++++++++++++++++++++++-- src/components/ChatPanel.tsx | 10 +++++----- src/lib/api.ts | 1 + 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/components/AgentModal.tsx b/src/components/AgentModal.tsx index 9a0f3e4..33a0049 100644 --- a/src/components/AgentModal.tsx +++ b/src/components/AgentModal.tsx @@ -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) { - console.error(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) { /> +
+ + { 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 &&
{slugError}
} +
+
{streaming.thinking && ( -
+
- 💭 Размышления + 💭 Размышления ({streaming.thinking.length} символов)
- {streaming.thinking} + {streaming.thinking.length > 500 ? '…' + streaming.thinking.slice(-500) : streaming.thinking}
)} @@ -372,8 +372,8 @@ export default function ChatPanel({ chatId, projectId }: Props) { ))} )} - {streaming.text && ( -
{streaming.text}
+ {streaming.text && !streaming.tools.some(t => t.status === "running") && ( +
{streaming.text.length > 500 ? '…' + streaming.text.slice(-500) : streaming.text}
)} {!streaming.text && streaming.tools.length === 0 && !streaming.thinking && (
Думает...
diff --git a/src/lib/api.ts b/src/lib/api.ts index bff4b10..76b5482 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -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;