feat: slug change + streaming fix + specs

This commit is contained in:
Markov 2026-03-13 22:55:53 +01:00
parent 79541d133a
commit 13a1748162
3 changed files with 31 additions and 7 deletions

View File

@ -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

View File

@ -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>

View File

@ -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>;