fix(computer-svc): stream для завершенных задач + Timeweb env vars

- Исправлен Stream() в computer.go: для completed/failed/cancelled задач
  сразу отправляется финальное событие и канал закрывается (ранее
  соединение зависало с socket hang up)
- Добавлены TIMEWEB_* переменные в docker-compose.yml для computer-svc
  (LLM через Timeweb Cloud AI для России)
- UI компоненты webui обновлены

Made-with: Cursor
This commit is contained in:
home
2026-02-27 05:17:42 +03:00
parent 06fe57c765
commit 120fbbaafb
19 changed files with 391 additions and 126 deletions

View File

@@ -84,6 +84,59 @@ export function useChat(options: UseChatOptions = {}) {
}
break;
case 'block':
// Handle new block format from agent-svc
if (event.block && typeof event.block === 'object') {
const block = event.block as { type: string; data: unknown };
if (block.type === 'text' && typeof block.data === 'string') {
fullContent = block.data;
setMessages((prev) =>
prev.map((m) =>
m.id === assistantMessage.id
? { ...m, content: fullContent }
: m
)
);
} else if (block.type === 'widget' && block.data) {
const widget = block.data as Widget;
collectedWidgets.push(widget);
setWidgets([...collectedWidgets]);
}
}
break;
case 'textChunk':
// Handle streaming text chunks
if (event.chunk && typeof event.chunk === 'string') {
fullContent += event.chunk;
setMessages((prev) =>
prev.map((m) =>
m.id === assistantMessage.id
? { ...m, content: fullContent }
: m
)
);
}
break;
case 'updateBlock':
// Handle block updates (final text)
if (event.patch && Array.isArray(event.patch)) {
for (const p of event.patch) {
if (p.op === 'replace' && p.path === '/data' && typeof p.value === 'string') {
fullContent = p.value;
setMessages((prev) =>
prev.map((m) =>
m.id === assistantMessage.id
? { ...m, content: fullContent }
: m
)
);
}
}
}
break;
case 'sources':
if (event.data && Array.isArray(event.data)) {
const sources = event.data as Array<{
@@ -112,6 +165,10 @@ export function useChat(options: UseChatOptions = {}) {
}
break;
case 'researchComplete':
// Research phase complete, text generation starting
break;
case 'messageEnd':
setMessages((prev) =>
prev.map((m) =>