@arcote.tech/arc-chat 0.7.18 → 0.7.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -7
- package/src/react/chat-component.tsx +41 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcote.tech/arc-chat",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.19",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Chat module with AI integration for Arc framework",
|
|
7
7
|
"main": "./src/index.ts",
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
"type-check": "tsc --noEmit"
|
|
11
11
|
},
|
|
12
12
|
"peerDependencies": {
|
|
13
|
-
"@arcote.tech/arc": "^0.7.
|
|
14
|
-
"@arcote.tech/arc-ai": "^0.7.
|
|
15
|
-
"@arcote.tech/arc-ai-voice": "^0.7.
|
|
16
|
-
"@arcote.tech/arc-auth": "^0.7.
|
|
17
|
-
"@arcote.tech/arc-ds": "^0.7.
|
|
18
|
-
"@arcote.tech/platform": "^0.7.
|
|
13
|
+
"@arcote.tech/arc": "^0.7.19",
|
|
14
|
+
"@arcote.tech/arc-ai": "^0.7.19",
|
|
15
|
+
"@arcote.tech/arc-ai-voice": "^0.7.19",
|
|
16
|
+
"@arcote.tech/arc-auth": "^0.7.19",
|
|
17
|
+
"@arcote.tech/arc-ds": "^0.7.19",
|
|
18
|
+
"@arcote.tech/platform": "^0.7.19",
|
|
19
19
|
"lucide-react": ">=0.400.0",
|
|
20
20
|
"react": ">=18.0.0",
|
|
21
21
|
"typescript": "^5.0.0"
|
|
@@ -340,6 +340,47 @@ export function createChatComponent(
|
|
|
340
340
|
return () => clearTimeout(timer);
|
|
341
341
|
}, [isStreaming, activeGeneratingMessageId, scopeId]);
|
|
342
342
|
|
|
343
|
+
// ─── Backstop: merge interactive-tool answers regardless of isStreaming ──
|
|
344
|
+
// Answering an interactive tool (askQuestions) creates a `tool_result` row
|
|
345
|
+
// AND starts a new assistant turn — so `isStreaming` flips back to true and
|
|
346
|
+
// the global rebuild guard freezes the whole timeline. Without this, the
|
|
347
|
+
// answered question stays in input-view ("Odpowiedz na pytania" + the
|
|
348
|
+
// questions) instead of the answer-view, until that next turn ends — and on
|
|
349
|
+
// prod its SSE `done` is often lost (the turn finalizes after the DB
|
|
350
|
+
// projection that nulls `activeGeneratingMessageId` aborts the stream), so
|
|
351
|
+
// it never catches up. This flips any `calling` tool block to answer-view
|
|
352
|
+
// the moment its `tool_result` lands in the DB, bypassing the guard.
|
|
353
|
+
useEffect(() => {
|
|
354
|
+
if (!historyData) return;
|
|
355
|
+
const resultMap = new Map<string, { content: string; isError?: boolean }>();
|
|
356
|
+
for (const msg of historyData) {
|
|
357
|
+
if (msg.role === "tool_result" && msg.toolCallId) {
|
|
358
|
+
resultMap.set(msg.toolCallId, {
|
|
359
|
+
content: msg.content,
|
|
360
|
+
isError: msg.isError,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (resultMap.size === 0) return;
|
|
365
|
+
setTimeline((prev) => {
|
|
366
|
+
let changed = false;
|
|
367
|
+
const next = prev.map((t) => {
|
|
368
|
+
if (t.type !== "tool" || !t.calling) return t;
|
|
369
|
+
const r = resultMap.get(t.toolCallId);
|
|
370
|
+
if (!r) return t;
|
|
371
|
+
changed = true;
|
|
372
|
+
return {
|
|
373
|
+
...t,
|
|
374
|
+
calling: false,
|
|
375
|
+
status: (r.isError ? "error" : "complete") as ToolStatus,
|
|
376
|
+
result: tryParseJson(r.content),
|
|
377
|
+
error: r.isError ? r.content : undefined,
|
|
378
|
+
};
|
|
379
|
+
});
|
|
380
|
+
return changed ? next : prev;
|
|
381
|
+
});
|
|
382
|
+
}, [historySig]);
|
|
383
|
+
|
|
343
384
|
// ─── SSE event processing ───────────────────────────────────
|
|
344
385
|
const processEventRef = useRef<((event: ChatStreamEvent) => void) | null>(null);
|
|
345
386
|
const processEvent = useCallback(
|