@copilotz/chat-adapter 0.9.30 → 0.9.32
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/dist/index.js +65 -11
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1605,15 +1605,36 @@ var prepareHydratedMessages = async (rawMessages, options = {}) => {
|
|
|
1605
1605
|
};
|
|
1606
1606
|
};
|
|
1607
1607
|
|
|
1608
|
+
// src/streamEvents.ts
|
|
1609
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1610
|
+
var hasValues = (value) => Array.isArray(value) && value.length > 0;
|
|
1611
|
+
var getStreamEventPayload = (event) => {
|
|
1612
|
+
if (!isRecord2(event)) return event;
|
|
1613
|
+
return "payload" in event ? event.payload : event;
|
|
1614
|
+
};
|
|
1615
|
+
var isTerminalEmptyLlmResultEvent = (event) => {
|
|
1616
|
+
if (!isRecord2(event) || event.type !== "LLM_RESULT") return false;
|
|
1617
|
+
const payload = getStreamEventPayload(event);
|
|
1618
|
+
if (!isRecord2(payload)) return false;
|
|
1619
|
+
if (payload.answer !== "") return false;
|
|
1620
|
+
if (payload.finishReason === "tool_calls") return false;
|
|
1621
|
+
if (hasValues(payload.toolCalls)) return false;
|
|
1622
|
+
const metadata = isRecord2(event.metadata) ? event.metadata : {};
|
|
1623
|
+
const routing = isRecord2(metadata.routing) ? metadata.routing : {};
|
|
1624
|
+
if (hasValues(routing.routeTo) || hasValues(routing.askTo)) return false;
|
|
1625
|
+
if (hasValues(metadata.targetQueue)) return false;
|
|
1626
|
+
return true;
|
|
1627
|
+
};
|
|
1628
|
+
|
|
1608
1629
|
// src/useCopilotzChat.ts
|
|
1609
1630
|
var nowTs = () => Date.now();
|
|
1610
1631
|
var generateId = () => globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
1611
1632
|
var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError" || typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
|
|
1612
|
-
var getEventPayload = (event) => event
|
|
1633
|
+
var getEventPayload = (event) => getStreamEventPayload(event);
|
|
1613
1634
|
var getEventSenderType = (payload) => payload?.senderType || payload?.sender?.type;
|
|
1614
|
-
var
|
|
1635
|
+
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1615
1636
|
var normalizeThreadTag = (value) => {
|
|
1616
|
-
if (!
|
|
1637
|
+
if (!isRecord3(value)) return null;
|
|
1617
1638
|
const id = typeof value.id === "string" ? value.id.trim() : "";
|
|
1618
1639
|
const name = typeof value.name === "string" ? value.name.trim() : "";
|
|
1619
1640
|
const color = typeof value.color === "string" && value.color.trim() ? value.color.trim() : void 0;
|
|
@@ -1621,7 +1642,7 @@ var normalizeThreadTag = (value) => {
|
|
|
1621
1642
|
return color ? { id, name, color } : { id, name };
|
|
1622
1643
|
};
|
|
1623
1644
|
var getThreadTagsFromMetadata = (metadata) => {
|
|
1624
|
-
if (!
|
|
1645
|
+
if (!isRecord3(metadata) || !isRecord3(metadata.public)) return [];
|
|
1625
1646
|
const tags = metadata.public.tags;
|
|
1626
1647
|
if (!Array.isArray(tags)) return [];
|
|
1627
1648
|
return tags.map(normalizeThreadTag).filter((tag) => !!tag);
|
|
@@ -1629,7 +1650,7 @@ var getThreadTagsFromMetadata = (metadata) => {
|
|
|
1629
1650
|
var patchMetadataPublicTags = (metadata, tags) => ({
|
|
1630
1651
|
...metadata ?? {},
|
|
1631
1652
|
public: {
|
|
1632
|
-
...
|
|
1653
|
+
...isRecord3(metadata?.public) ? metadata.public : {},
|
|
1633
1654
|
tags
|
|
1634
1655
|
}
|
|
1635
1656
|
});
|
|
@@ -1732,6 +1753,9 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
1732
1753
|
const userContextSeedRef = useRef2(userContextSeed);
|
|
1733
1754
|
const messagePageInfoRef = useRef2(messagePageInfo);
|
|
1734
1755
|
const isLoadingOlderMessagesRef = useRef2(isLoadingOlderMessages);
|
|
1756
|
+
const isStreamingRef = useRef2(isStreaming);
|
|
1757
|
+
const threadActivityStatusRef = useRef2(threadActivityStatus);
|
|
1758
|
+
const isRecoveringStreamRef = useRef2(isRecoveringStream);
|
|
1735
1759
|
const senderOptionsRef = useRef2({
|
|
1736
1760
|
agents: agentOptions,
|
|
1737
1761
|
user: userId ? { id: userId, name: userName, avatarUrl: userAvatar } : null,
|
|
@@ -1749,6 +1773,9 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
1749
1773
|
userContextSeedRef.current = userContextSeed;
|
|
1750
1774
|
messagePageInfoRef.current = messagePageInfo;
|
|
1751
1775
|
isLoadingOlderMessagesRef.current = isLoadingOlderMessages;
|
|
1776
|
+
isStreamingRef.current = isStreaming;
|
|
1777
|
+
threadActivityStatusRef.current = threadActivityStatus;
|
|
1778
|
+
isRecoveringStreamRef.current = isRecoveringStream;
|
|
1752
1779
|
senderOptionsRef.current = {
|
|
1753
1780
|
agents: agentOptions,
|
|
1754
1781
|
user: userId ? { id: userId, name: userName, avatarUrl: userAvatar } : null,
|
|
@@ -2293,11 +2320,16 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2293
2320
|
async (params) => {
|
|
2294
2321
|
let currentAssistantId = params.assistantMessageId ?? generateId();
|
|
2295
2322
|
let currentAssistantSender = params.assistantSender;
|
|
2323
|
+
const streamOwnerThreadId = currentThreadIdRef.current;
|
|
2324
|
+
const streamOwnerThreadExternalId = params.threadExternalId ?? currentThreadExternalIdRef.current;
|
|
2325
|
+
const streamStillOwnsVisibleThread = () => streamOwnerThreadId ? currentThreadIdRef.current === streamOwnerThreadId : !streamOwnerThreadExternalId || currentThreadExternalIdRef.current === streamOwnerThreadExternalId || currentThreadIdRef.current === streamOwnerThreadExternalId;
|
|
2296
2326
|
params.onBeforeStart?.(currentAssistantId);
|
|
2297
2327
|
let hasStreamProgress = false;
|
|
2298
2328
|
const updateStreamingMessage = (partial, opts) => {
|
|
2329
|
+
if (!streamStillOwnsVisibleThread()) return;
|
|
2299
2330
|
if (partial && partial.length > 0) {
|
|
2300
2331
|
hasStreamProgress = true;
|
|
2332
|
+
setIsRecoveringStream(false);
|
|
2301
2333
|
}
|
|
2302
2334
|
const isReasoning = opts?.isReasoning ?? false;
|
|
2303
2335
|
const nextSender = opts?.agent ? resolveAgentSender(opts.agent, senderOptionsRef.current) : currentAssistantSender;
|
|
@@ -2356,6 +2388,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2356
2388
|
});
|
|
2357
2389
|
};
|
|
2358
2390
|
const finalizeCurrentAssistantBubble = () => {
|
|
2391
|
+
if (!streamStillOwnsVisibleThread()) return;
|
|
2359
2392
|
setMessages((prev) => {
|
|
2360
2393
|
const idx = prev.findIndex((m) => m.id === currentAssistantId);
|
|
2361
2394
|
if (idx < 0) return prev;
|
|
@@ -2368,6 +2401,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2368
2401
|
};
|
|
2369
2402
|
const curThreadId = currentThreadIdRef.current;
|
|
2370
2403
|
const applyLiveToolResultUpdate = (update) => {
|
|
2404
|
+
if (!streamStillOwnsVisibleThread()) return;
|
|
2371
2405
|
let matched = false;
|
|
2372
2406
|
setMessages((prev) => {
|
|
2373
2407
|
const next = applyToolResultUpdateToMessages(prev, update, {
|
|
@@ -2382,6 +2416,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2382
2416
|
}
|
|
2383
2417
|
};
|
|
2384
2418
|
const finalizeActiveAssistantTurn = (finalAnswer) => {
|
|
2419
|
+
if (!streamStillOwnsVisibleThread()) return;
|
|
2385
2420
|
setMessages((prev) => {
|
|
2386
2421
|
const currentIdx = prev.findIndex((message2) => message2.id === currentAssistantId && message2.role === "assistant");
|
|
2387
2422
|
const fallbackIdx = currentIdx >= 0 ? currentIdx : (() => {
|
|
@@ -2429,12 +2464,14 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2429
2464
|
return null;
|
|
2430
2465
|
};
|
|
2431
2466
|
const abortController = new AbortController();
|
|
2432
|
-
|
|
2467
|
+
if (!params.preserveActiveRun) {
|
|
2468
|
+
abortControllerRef.current?.abort();
|
|
2469
|
+
recoveryPollGenerationRef.current += 1;
|
|
2470
|
+
setIsRecoveringStream(false);
|
|
2471
|
+
}
|
|
2433
2472
|
abortControllerRef.current = abortController;
|
|
2434
2473
|
stopRequestedRef.current = false;
|
|
2435
|
-
recoveryPollGenerationRef.current += 1;
|
|
2436
2474
|
setThreadActivityStatus("running");
|
|
2437
|
-
setIsRecoveringStream(false);
|
|
2438
2475
|
setIsStreaming(true);
|
|
2439
2476
|
liveToolUpdatesRef.current = [];
|
|
2440
2477
|
let streamError = null;
|
|
@@ -2488,6 +2525,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2488
2525
|
agent: raw?.payload?.agent ?? raw?.agent ?? null
|
|
2489
2526
|
}),
|
|
2490
2527
|
onMessageEvent: async (event) => {
|
|
2528
|
+
if (!streamStillOwnsVisibleThread()) return;
|
|
2491
2529
|
const intercepted = applyEventInterceptor(event);
|
|
2492
2530
|
if (intercepted?.handled) {
|
|
2493
2531
|
return;
|
|
@@ -2502,6 +2540,9 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2502
2540
|
if (type === "LLM_RESULT") {
|
|
2503
2541
|
const finalAnswer = typeof payload?.answer === "string" ? payload.answer : void 0;
|
|
2504
2542
|
finalizeActiveAssistantTurn(finalAnswer);
|
|
2543
|
+
if (isTerminalEmptyLlmResultEvent(event)) {
|
|
2544
|
+
finalizeStreamingPlaceholders();
|
|
2545
|
+
}
|
|
2505
2546
|
return;
|
|
2506
2547
|
}
|
|
2507
2548
|
if (type === "MESSAGE" || type === "NEW_MESSAGE") {
|
|
@@ -2596,6 +2637,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2596
2637
|
handleStreamMessageEvent(event);
|
|
2597
2638
|
},
|
|
2598
2639
|
onAssetEvent: async (payload) => {
|
|
2640
|
+
if (!streamStillOwnsVisibleThread()) return;
|
|
2599
2641
|
const intercepted = applyEventInterceptor({
|
|
2600
2642
|
type: "ASSET_CREATED",
|
|
2601
2643
|
payload
|
|
@@ -2615,7 +2657,7 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2615
2657
|
}
|
|
2616
2658
|
const wasStopped = stopRequestedRef.current || abortController.signal.aborted || isAbortError(streamError);
|
|
2617
2659
|
let recoveryStarted = false;
|
|
2618
|
-
if (!wasStopped) {
|
|
2660
|
+
if (!wasStopped && streamStillOwnsVisibleThread()) {
|
|
2619
2661
|
try {
|
|
2620
2662
|
const activityThreadId = await resolveActivityThreadId();
|
|
2621
2663
|
if (activityThreadId) {
|
|
@@ -2635,7 +2677,12 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2635
2677
|
}
|
|
2636
2678
|
}
|
|
2637
2679
|
}
|
|
2638
|
-
abortControllerRef.current
|
|
2680
|
+
if (abortControllerRef.current === abortController) {
|
|
2681
|
+
abortControllerRef.current = null;
|
|
2682
|
+
}
|
|
2683
|
+
if (!streamStillOwnsVisibleThread()) {
|
|
2684
|
+
return currentAssistantId;
|
|
2685
|
+
}
|
|
2639
2686
|
if (recoveryStarted) {
|
|
2640
2687
|
return currentAssistantId;
|
|
2641
2688
|
}
|
|
@@ -2654,6 +2701,8 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2654
2701
|
const timestamp = nowTs();
|
|
2655
2702
|
const curThreadId = currentThreadIdRef.current;
|
|
2656
2703
|
const curThreadExtId = currentThreadExternalIdRef.current;
|
|
2704
|
+
const sendOwnerThreadId = curThreadId;
|
|
2705
|
+
const preserveActiveRun = threadActivityStatusRef.current === "running" || isRecoveringStreamRef.current || isStreamingRef.current;
|
|
2657
2706
|
const existingThreadId = curThreadId ?? void 0;
|
|
2658
2707
|
const extMap = threadExternalIdMapRef.current;
|
|
2659
2708
|
const isPlaceholderThread = existingThreadId ? extMap[existingThreadId] === existingThreadId : false;
|
|
@@ -2668,6 +2717,8 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2668
2717
|
setCurrentThreadExternalId(effectiveThreadExternalId ?? null);
|
|
2669
2718
|
}
|
|
2670
2719
|
const conversationKey = threadIdForSend ?? effectiveThreadExternalId;
|
|
2720
|
+
const sendOwnerThreadExternalId = effectiveThreadExternalId ?? curThreadExtId;
|
|
2721
|
+
const stillShowingSendOwnerThread = () => sendOwnerThreadId ? currentThreadIdRef.current === sendOwnerThreadId : !sendOwnerThreadExternalId || currentThreadExternalIdRef.current === sendOwnerThreadExternalId || currentThreadIdRef.current === sendOwnerThreadExternalId;
|
|
2671
2722
|
const currentMetadata = threadMetadataMapRef.current[conversationKey];
|
|
2672
2723
|
const pendingTitle = currentMetadata?.pendingTitle;
|
|
2673
2724
|
const userMessage = {
|
|
@@ -2727,11 +2778,14 @@ function useCopilotz({ userId, userName, userAvatar, assistantName, agentOptions
|
|
|
2727
2778
|
agentName: preferredAgentRef.current,
|
|
2728
2779
|
assistantMessageId: assistantPlaceholder.id,
|
|
2729
2780
|
assistantSender,
|
|
2781
|
+
preserveActiveRun,
|
|
2730
2782
|
// Include pending title for new threads
|
|
2731
2783
|
threadMetadata: pendingTitle ? { name: pendingTitle } : void 0
|
|
2732
2784
|
});
|
|
2733
2785
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
2734
|
-
|
|
2786
|
+
if (stillShowingSendOwnerThread()) {
|
|
2787
|
+
await fetchAndSetThreadsState(userId, effectiveThreadExternalId ?? existingThreadId ?? null);
|
|
2788
|
+
}
|
|
2735
2789
|
} catch (error) {
|
|
2736
2790
|
if (isAbortError(error)) return;
|
|
2737
2791
|
console.error("Error sending Copilotz message", error);
|