@copilotz/chat-adapter 0.1.22 → 0.1.24

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.d.ts CHANGED
@@ -130,10 +130,9 @@ type RestMessage = {
130
130
  updatedAt?: string;
131
131
  };
132
132
  type StreamCallbacks = {
133
- /**
134
- * `text` = non-reasoning token stream; `reasoningText` = accumulated reasoning when the backend sets `payload.isReasoning`.
135
- */
136
- onToken?: (text: string, isComplete: boolean, raw?: any, reasoningText?: string) => void;
133
+ onToken?: (token: string, isComplete: boolean, raw?: any, options?: {
134
+ isReasoning?: boolean;
135
+ }) => void;
137
136
  onMessageEvent?: (payload: any) => void;
138
137
  onAssetEvent?: (payload: any) => void;
139
138
  signal?: AbortSignal;
package/dist/index.js CHANGED
@@ -431,9 +431,8 @@ async function runCopilotzStream(options) {
431
431
  switch (eventType) {
432
432
  case "TOKEN": {
433
433
  const inner = payload2?.payload ?? payload2;
434
- const chunk = typeof inner?.token === "string" ? inner.token : typeof payload2?.token === "string" ? payload2.token : "";
434
+ const chunk = typeof inner?.token === "string" ? inner.token : "";
435
435
  const isReasoning = Boolean(inner?.isReasoning);
436
- const isComplete = Boolean(inner?.isComplete ?? payload2?.isComplete);
437
436
  if (chunk) {
438
437
  if (isReasoning) {
439
438
  aggregatedReasoning = appendChunk(aggregatedReasoning, chunk);
@@ -441,8 +440,10 @@ async function runCopilotzStream(options) {
441
440
  aggregatedText = appendChunk(aggregatedText, chunk);
442
441
  }
443
442
  }
443
+ const isComplete = Boolean(inner?.isComplete);
444
444
  if (chunk || isComplete) {
445
- onToken?.(aggregatedText, isComplete, payload2, aggregatedReasoning);
445
+ const tokenText = isReasoning ? aggregatedReasoning : aggregatedText;
446
+ onToken?.(tokenText, isComplete, payload2, { isReasoning });
446
447
  }
447
448
  break;
448
449
  }
@@ -803,23 +804,6 @@ var generateId = () => globalThis.crypto?.randomUUID?.() ?? `id-${Date.now()}-${
803
804
  var isAbortError = (error) => error instanceof DOMException && error.name === "AbortError" || typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
804
805
  var getEventPayload = (event) => event?.payload ?? event;
805
806
  var getEventSenderType = (payload) => payload?.senderType || payload?.sender?.type;
806
- var hasToolCallsInPayload = (payload) => {
807
- if (!payload || typeof payload !== "object") return false;
808
- const p = payload;
809
- if (Array.isArray(p.toolCalls) && p.toolCalls.length > 0) return true;
810
- const meta = p.metadata;
811
- if (!meta || typeof meta !== "object" || Array.isArray(meta)) return false;
812
- const m = meta.toolCalls;
813
- return Array.isArray(m) && m.length > 0;
814
- };
815
- var isAgentToolOnlyPlaceholderPayload = (payload) => {
816
- if (!payload || typeof payload !== "object") return false;
817
- const p = payload;
818
- if (getEventSenderType(p) !== "agent") return false;
819
- const content = typeof p.content === "string" ? p.content : "";
820
- if (content.trim().length > 0) return false;
821
- return hasToolCallsInPayload(p);
822
- };
823
807
  var hasVisibleAssistantOutput = (message) => {
824
808
  if (message.role !== "assistant") return false;
825
809
  if (typeof message.content === "string" && message.content.trim().length > 0) return true;
@@ -854,29 +838,16 @@ var extractToolCallsFromServerMessage = (msg) => {
854
838
  const metadataToolCalls = Array.isArray(metadata?.toolCalls) ? metadata.toolCalls : [];
855
839
  const usedMetadataIndexes = /* @__PURE__ */ new Set();
856
840
  const parsed = [];
857
- const candidateToolLabel = (c) => {
858
- if (typeof c.name === "string") return c.name;
859
- const t = c.tool && typeof c.tool === "object" && c.tool !== null && !Array.isArray(c.tool) ? c.tool : void 0;
860
- if (typeof t?.name === "string") return t.name;
861
- if (typeof t?.id === "string") return t.id;
862
- return void 0;
863
- };
864
841
  const findMatchingMetadataIndex = (toolCall) => {
865
842
  const id = typeof toolCall.id === "string" ? toolCall.id : void 0;
866
- const nested = toolCall.tool && typeof toolCall.tool === "object" && toolCall.tool !== null && !Array.isArray(toolCall.tool) ? toolCall.tool : void 0;
867
- const name = (typeof toolCall.name === "string" ? toolCall.name : void 0) || (typeof nested?.name === "string" ? nested.name : void 0) || (typeof nested?.id === "string" ? nested.id : void 0);
843
+ const name = typeof toolCall.name === "string" ? toolCall.name : void 0;
868
844
  const byId = id ? metadataToolCalls.findIndex((candidate, idx) => !usedMetadataIndexes.has(idx) && candidate?.id === id) : -1;
869
845
  if (byId >= 0) return byId;
870
- return name ? metadataToolCalls.findIndex((candidate, idx) => {
871
- if (usedMetadataIndexes.has(idx)) return false;
872
- const label = candidateToolLabel(candidate);
873
- return label === name;
874
- }) : -1;
846
+ return name ? metadataToolCalls.findIndex((candidate, idx) => !usedMetadataIndexes.has(idx) && candidate?.name === name) : -1;
875
847
  };
876
848
  const parseToolCall = (primary, secondary) => {
877
- const nestedTool = primary && typeof primary.tool === "object" && primary.tool !== null && !Array.isArray(primary.tool) ? primary.tool : void 0;
878
849
  const id = typeof primary.id === "string" ? primary.id : typeof secondary?.id === "string" ? secondary.id : void 0;
879
- const name = typeof primary.name === "string" ? primary.name : (typeof nestedTool?.name === "string" ? nestedTool.name : typeof nestedTool?.id === "string" ? nestedTool.id : void 0) ?? (typeof secondary?.name === "string" ? secondary.name : "tool");
850
+ const name = typeof primary.name === "string" ? primary.name : typeof secondary?.name === "string" ? secondary.name : "tool";
880
851
  const argsRaw = primary.args ?? primary.arguments ?? secondary?.args ?? secondary?.arguments;
881
852
  const result = primary.output !== void 0 ? primary.output : primary.result !== void 0 ? primary.result : secondary?.output !== void 0 ? secondary.output : secondary?.result;
882
853
  const status = normalizeToolStatus(primary.status ?? secondary?.status);
@@ -898,17 +869,7 @@ var extractToolCallsFromServerMessage = (msg) => {
898
869
  if (usedMetadataIndexes.has(index)) return;
899
870
  parsed.push(parseToolCall(toolCall));
900
871
  });
901
- const seenIds = /* @__PURE__ */ new Set();
902
- const deduped = [];
903
- for (const p of parsed) {
904
- const id = p.id;
905
- if (typeof id === "string" && id.length > 0) {
906
- if (seenIds.has(id)) continue;
907
- seenIds.add(id);
908
- }
909
- deduped.push(p);
910
- }
911
- return deduped;
872
+ return parsed;
912
873
  };
913
874
  var extractToolResultUpdateFromMessage = (msg) => {
914
875
  if (msg.senderType !== "tool") return null;
@@ -1146,11 +1107,6 @@ function useCopilotz({
1146
1107
  return;
1147
1108
  }
1148
1109
  if (senderType === "agent" && typeof payload.content === "string") {
1149
- const trimmedContent = payload.content.trim();
1150
- const hasToolCalls = hasToolCallsInPayload(payload);
1151
- if (!trimmedContent && hasToolCalls) {
1152
- return;
1153
- }
1154
1110
  setMessages((prev) => {
1155
1111
  const next = [...prev];
1156
1112
  for (let i = next.length - 1; i >= 0; i--) {
@@ -1160,6 +1116,7 @@ function useCopilotz({
1160
1116
  return next;
1161
1117
  }
1162
1118
  }
1119
+ const trimmedContent = payload.content.trim();
1163
1120
  if (!trimmedContent) {
1164
1121
  return prev;
1165
1122
  }
@@ -1413,60 +1370,57 @@ function useCopilotz({
1413
1370
  params.onBeforeStart?.(currentAssistantId);
1414
1371
  let hasStreamProgress = false;
1415
1372
  let pendingStartNewAssistantBubble = false;
1416
- const updateStreamingMessage = (partial, _isComplete, _raw, reasoningPartial) => {
1373
+ const updateStreamingMessage = (partial, opts) => {
1417
1374
  if (partial && partial.length > 0) {
1418
1375
  hasStreamProgress = true;
1419
1376
  }
1420
- if (reasoningPartial !== void 0 && reasoningPartial.length > 0) {
1421
- hasStreamProgress = true;
1422
- }
1423
1377
  const nextStreaming = true;
1424
1378
  const nextComplete = false;
1379
+ const isReasoning = opts?.isReasoning ?? false;
1380
+ const applyUpdate = (msg) => {
1381
+ if (isReasoning) {
1382
+ return { ...msg, reasoning: partial, isReasoningStreaming: true, isStreaming: nextStreaming, isComplete: nextComplete };
1383
+ }
1384
+ const reasoningPatch = msg.reasoning ? { isReasoningStreaming: false } : {};
1385
+ return { ...msg, content: partial, ...reasoningPatch, isStreaming: nextStreaming, isComplete: nextComplete };
1386
+ };
1425
1387
  setMessages((prev) => {
1426
- const patch = (msg) => ({
1427
- ...msg,
1428
- content: partial,
1429
- ...reasoningPartial !== void 0 ? { reasoning: reasoningPartial } : {},
1430
- isStreaming: nextStreaming,
1431
- isComplete: nextComplete
1432
- });
1433
1388
  const idx = prev.findIndex((m) => m.id === currentAssistantId);
1434
1389
  if (idx >= 0 && prev[idx].role === "assistant" && prev[idx].isStreaming) {
1435
1390
  const msg = prev[idx];
1436
- if (msg.content === partial && (msg.reasoning ?? "") === (reasoningPartial ?? "") && msg.isStreaming === nextStreaming && msg.isComplete === nextComplete) {
1391
+ const next = applyUpdate(msg);
1392
+ if (msg.content === next.content && msg.reasoning === next.reasoning && msg.isReasoningStreaming === next.isReasoningStreaming && msg.isStreaming === next.isStreaming && msg.isComplete === next.isComplete) {
1437
1393
  return prev;
1438
1394
  }
1439
1395
  const updated = [...prev];
1440
- updated[idx] = patch(msg);
1396
+ updated[idx] = next;
1441
1397
  return updated;
1442
1398
  }
1443
1399
  const last = prev[prev.length - 1];
1444
1400
  if (last && last.role === "assistant" && last.isStreaming) {
1445
1401
  currentAssistantId = last.id;
1446
1402
  pendingStartNewAssistantBubble = false;
1447
- if (last.content === partial && (last.reasoning ?? "") === (reasoningPartial ?? "") && last.isStreaming === nextStreaming && last.isComplete === nextComplete) {
1403
+ const next = applyUpdate(last);
1404
+ if (last.content === next.content && last.reasoning === next.reasoning && last.isReasoningStreaming === next.isReasoningStreaming && last.isStreaming === next.isStreaming && last.isComplete === next.isComplete) {
1448
1405
  return prev;
1449
1406
  }
1450
1407
  const updated = [...prev];
1451
- updated[prev.length - 1] = patch(last);
1408
+ updated[prev.length - 1] = next;
1452
1409
  return updated;
1453
1410
  }
1454
1411
  if (pendingStartNewAssistantBubble || !prev.length || (prev[prev.length - 1].role !== "assistant" || !prev[prev.length - 1].isStreaming)) {
1455
1412
  const newId = generateId();
1456
1413
  currentAssistantId = newId;
1457
1414
  pendingStartNewAssistantBubble = false;
1458
- return [
1459
- ...prev,
1460
- {
1461
- id: newId,
1462
- role: "assistant",
1463
- content: partial,
1464
- ...reasoningPartial !== void 0 ? { reasoning: reasoningPartial } : {},
1465
- timestamp: nowTs(),
1466
- isStreaming: nextStreaming,
1467
- isComplete: nextComplete
1468
- }
1469
- ];
1415
+ const base = {
1416
+ id: newId,
1417
+ role: "assistant",
1418
+ content: "",
1419
+ timestamp: nowTs(),
1420
+ isStreaming: nextStreaming,
1421
+ isComplete: nextComplete
1422
+ };
1423
+ return [...prev, applyUpdate(base)];
1470
1424
  }
1471
1425
  return prev;
1472
1426
  });
@@ -1489,21 +1443,37 @@ function useCopilotz({
1489
1443
  const payload = event?.payload ?? event;
1490
1444
  if (type === "TOOL_CALL") {
1491
1445
  const metadata = payload?.metadata ?? {};
1492
- const tc = payload?.toolCall ?? payload?.call ?? metadata.call;
1493
- const nestedTool = tc && typeof tc.tool === "object" && tc.tool !== null && !Array.isArray(tc.tool) ? tc.tool : void 0;
1494
- const toolName = (typeof nestedTool?.name === "string" ? nestedTool.name : void 0) || (typeof nestedTool?.id === "string" ? nestedTool.id : void 0) || (typeof payload.name === "string" ? payload.name : void 0) || metadata.toolName || "tool";
1446
+ const tc = payload?.toolCall ?? void 0;
1447
+ const tcTool = tc?.tool ?? void 0;
1448
+ const call = payload?.call ?? metadata?.call;
1449
+ const func = call?.function ?? payload?.function;
1450
+ const toolName = tcTool?.name || func?.name || payload?.name || call?.name || metadata.toolName || metadata.tool || "tool";
1495
1451
  let argsObj = {};
1496
- const argsRaw = tc?.args ?? payload?.args ?? metadata.args;
1497
- if (typeof argsRaw === "string") {
1452
+ const possibleArgs = [
1453
+ tc?.args,
1454
+ func?.arguments,
1455
+ payload?.args,
1456
+ call?.arguments,
1457
+ metadata?.args,
1458
+ metadata?.arguments
1459
+ ];
1460
+ for (const candidate of possibleArgs) {
1461
+ if (candidate === void 0 || candidate === null) continue;
1498
1462
  try {
1499
- argsObj = JSON.parse(argsRaw);
1463
+ if (typeof candidate === "string") {
1464
+ argsObj = JSON.parse(candidate);
1465
+ break;
1466
+ }
1467
+ if (typeof candidate === "object") {
1468
+ argsObj = candidate;
1469
+ break;
1470
+ }
1500
1471
  } catch {
1501
1472
  }
1502
- } else if (argsRaw && typeof argsRaw === "object" && !Array.isArray(argsRaw)) {
1503
- argsObj = argsRaw;
1504
1473
  }
1505
- const callId = (typeof tc?.id === "string" ? tc.id : void 0) || (typeof payload.id === "string" ? payload.id : void 0) || generateId();
1506
- const statusVal = "running";
1474
+ const output = (tc?.output !== void 0 ? tc.output : void 0) ?? (metadata?.output !== void 0 ? metadata.output : void 0) ?? (payload?.output !== void 0 ? payload.output : void 0);
1475
+ const callId = tc?.id || call?.id || func?.id || payload?.id || generateId();
1476
+ const statusVal = tc?.status || payload?.status || event?.status || "pending";
1507
1477
  return {
1508
1478
  id: generateId(),
1509
1479
  threadId: curThreadId ?? "",
@@ -1513,6 +1483,7 @@ function useCopilotz({
1513
1483
  id: callId,
1514
1484
  name: toolName,
1515
1485
  args: argsObj,
1486
+ output,
1516
1487
  status: statusVal
1517
1488
  }]
1518
1489
  };
@@ -1591,9 +1562,7 @@ function useCopilotz({
1591
1562
  toolCalls: params.toolCalls,
1592
1563
  selectedAgent: params.agentName ?? preferredAgentRef.current ?? null,
1593
1564
  getRequestHeaders,
1594
- onToken: (token, isComplete, raw, reasoning) => {
1595
- updateStreamingMessage(token, isComplete, raw, reasoning);
1596
- },
1565
+ onToken: (token, _isComplete, _raw, opts) => updateStreamingMessage(token, opts),
1597
1566
  onMessageEvent: async (event) => {
1598
1567
  const intercepted = applyEventInterceptor(event);
1599
1568
  if (intercepted?.handled) {
@@ -1603,9 +1572,6 @@ function useCopilotz({
1603
1572
  const payload = getEventPayload(event);
1604
1573
  if (type === "MESSAGE" || type === "NEW_MESSAGE") {
1605
1574
  const senderType = getEventSenderType(payload);
1606
- if (senderType === "agent" && hasStreamProgress) {
1607
- return;
1608
- }
1609
1575
  if (senderType === "tool") {
1610
1576
  const metadata = payload?.metadata ?? {};
1611
1577
  const toolCallsArray = metadata?.toolCalls;
@@ -1615,16 +1581,8 @@ function useCopilotz({
1615
1581
  }
1616
1582
  processToolOutput(metadata);
1617
1583
  const toolCallId = toolCallData.id;
1618
- const nestedTool = toolCallData.tool;
1619
- const toolCallName = toolCallData.name || (typeof nestedTool?.name === "string" ? nestedTool.name : void 0) || (typeof nestedTool?.id === "string" ? nestedTool.id : void 0);
1620
- const toolResultRaw = toolCallData.output || payload?.content;
1621
- const toolResult = typeof toolResultRaw === "string" ? (() => {
1622
- try {
1623
- return JSON.parse(toolResultRaw);
1624
- } catch {
1625
- return toolResultRaw;
1626
- }
1627
- })() : toolResultRaw;
1584
+ const toolCallName = toolCallData.name;
1585
+ const toolResult = toolCallData.output || payload?.content;
1628
1586
  const toolStatus = toolCallData.status || "completed";
1629
1587
  const isFailed = toolStatus === "failed" || toolCallData?.error;
1630
1588
  setMessages((prev) => {
@@ -1663,7 +1621,7 @@ function useCopilotz({
1663
1621
  return;
1664
1622
  }
1665
1623
  handleStreamMessageEvent(event);
1666
- if (senderType === "agent" && !isAgentToolOnlyPlaceholderPayload(payload)) {
1624
+ if (senderType === "agent") {
1667
1625
  currentAssistantId = generateId();
1668
1626
  pendingStartNewAssistantBubble = true;
1669
1627
  }
@@ -1676,27 +1634,20 @@ function useCopilotz({
1676
1634
  if (!toolCall) return;
1677
1635
  setMessages(
1678
1636
  (prev) => (() => {
1679
- const appendToolCall = (msg) => {
1680
- const existing = Array.isArray(msg.toolCalls) ? msg.toolCalls : [];
1681
- const id = toolCall.id ?? generateId();
1682
- if (existing.some((t) => t.id === id)) {
1683
- return msg;
1684
- }
1685
- return {
1686
- ...msg,
1687
- toolCalls: [
1688
- ...existing,
1689
- {
1690
- id,
1691
- name: toolCall.name ?? "tool",
1692
- arguments: toolCall.args ?? toolCall.arguments ?? {},
1693
- result: toolCall.output,
1694
- status: toolCall.status ?? "running",
1695
- startTime: Date.now()
1696
- }
1697
- ]
1698
- };
1699
- };
1637
+ const appendToolCall = (msg) => ({
1638
+ ...msg,
1639
+ toolCalls: [
1640
+ ...Array.isArray(msg.toolCalls) ? msg.toolCalls : [],
1641
+ {
1642
+ id: toolCall.id ?? generateId(),
1643
+ name: toolCall.name ?? "tool",
1644
+ arguments: toolCall.args ?? toolCall.arguments ?? {},
1645
+ result: toolCall.output,
1646
+ status: toolCall.status ?? "running",
1647
+ startTime: Date.now()
1648
+ }
1649
+ ]
1650
+ });
1700
1651
  const currentIdx = prev.findIndex((message) => message.id === currentAssistantId && message.role === "assistant" && message.isStreaming);
1701
1652
  if (currentIdx >= 0) {
1702
1653
  const next = [...prev];
@@ -1708,7 +1659,7 @@ function useCopilotz({
1708
1659
  return next;
1709
1660
  }
1710
1661
  const last = prev[prev.length - 1];
1711
- if (last?.role === "assistant" && last.isStreaming) {
1662
+ if (!pendingStartNewAssistantBubble && last?.role === "assistant" && last.isStreaming) {
1712
1663
  currentAssistantId = last.id;
1713
1664
  const next = [...prev];
1714
1665
  next[prev.length - 1] = appendToolCall({
@@ -1735,6 +1686,7 @@ function useCopilotz({
1735
1686
  })()
1736
1687
  );
1737
1688
  hasStreamProgress = true;
1689
+ pendingStartNewAssistantBubble = true;
1738
1690
  return;
1739
1691
  }
1740
1692
  const sm = await toServerMessageFromEvent(event);
@@ -1793,10 +1745,8 @@ function useCopilotz({
1793
1745
  effectiveThreadExternalId = generateId();
1794
1746
  }
1795
1747
  setCurrentThreadExternalId(effectiveThreadExternalId);
1796
- currentThreadExternalIdRef.current = effectiveThreadExternalId;
1797
1748
  } else if (curThreadExtId !== (effectiveThreadExternalId ?? null)) {
1798
1749
  setCurrentThreadExternalId(effectiveThreadExternalId ?? null);
1799
- currentThreadExternalIdRef.current = effectiveThreadExternalId ?? null;
1800
1750
  }
1801
1751
  const conversationKey = threadIdForSend ?? effectiveThreadExternalId;
1802
1752
  const currentMetadata = threadMetadataMapRef.current[conversationKey];
@@ -1830,13 +1780,6 @@ function useCopilotz({
1830
1780
  setThreads((prev) => [newThread, ...prev]);
1831
1781
  setThreadMetadataMap((prev) => ({ ...prev, [conversationKey]: {} }));
1832
1782
  setThreadExternalIdMap((prev) => ({ ...prev, [conversationKey]: effectiveThreadExternalId ?? null }));
1833
- setCurrentThreadId(conversationKey);
1834
- currentThreadIdRef.current = conversationKey;
1835
- threadsRef.current = [newThread, ...threadsRef.current];
1836
- threadExternalIdMapRef.current = {
1837
- ...threadExternalIdMapRef.current,
1838
- [conversationKey]: effectiveThreadExternalId ?? null
1839
- };
1840
1783
  }
1841
1784
  try {
1842
1785
  await sendCopilotzMessage({