@agent-native/core 0.196.0 → 0.196.1-nightly-20260928200103

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.
Files changed (41) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/clips/actions/create-recording.ts +1 -1
  3. package/corpus/templates/clips/actions/lib/auto-title-candidates.ts +42 -0
  4. package/corpus/templates/clips/actions/lib/create-recording-schema.ts +1 -1
  5. package/corpus/templates/clips/actions/lib/transcript-text.ts +16 -0
  6. package/corpus/templates/clips/actions/list-ai-requests.ts +49 -31
  7. package/corpus/templates/clips/actions/list-recordings.ts +2 -4
  8. package/corpus/templates/clips/actions/list-transactional-email-ai-requests.ts +12 -6
  9. package/corpus/templates/clips/actions/regenerate-title.ts +4 -1
  10. package/corpus/templates/clips/actions/request-transcript.ts +1 -1
  11. package/corpus/templates/clips/actions/save-browser-transcript.ts +1 -1
  12. package/corpus/templates/clips/app/components/editable-recording-title.tsx +1 -1
  13. package/corpus/templates/clips/app/components/library/recording-card.tsx +1 -1
  14. package/corpus/templates/clips/app/hooks/use-auto-title.ts +194 -219
  15. package/corpus/templates/clips/app/routes/_app.r.$recordingId.tsx +2 -1
  16. package/corpus/templates/clips/app/routes/share.$shareId.tsx +1 -1
  17. package/corpus/templates/clips/server/lib/transactional-email-store.ts +42 -2
  18. package/corpus/templates/clips/shared/ai-request-status.ts +6 -0
  19. package/corpus/templates/clips/{actions/lib → shared}/title-source.ts +9 -2
  20. package/dist/agent/production-agent.js +2 -0
  21. package/dist/agent/run-manager.d.ts +2 -0
  22. package/dist/agent/run-manager.js +9 -2
  23. package/dist/agent/thread-data-builder.d.ts +1 -0
  24. package/dist/agent/thread-data-builder.js +148 -0
  25. package/dist/automation/index.d.ts +1 -1
  26. package/dist/chat-threads/store.d.ts +1 -0
  27. package/dist/chat-threads/store.js +244 -21
  28. package/dist/client/AgentKitAssistantChat.js +23 -12
  29. package/dist/client/chat/agentkit-agent-native.js +409 -8
  30. package/dist/client/chat/agentkit-protocol.js +3 -0
  31. package/dist/collab/awareness.d.ts +2 -2
  32. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  33. package/dist/notifications/routes.d.ts +3 -3
  34. package/dist/observability/routes.d.ts +2 -2
  35. package/dist/resources/handlers.d.ts +1 -1
  36. package/dist/server/agent-chat-plugin.d.ts +2 -0
  37. package/dist/server/agent-chat-plugin.js +12 -7
  38. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  39. package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
  40. package/dist/server/realtime-token.d.ts +1 -1
  41. package/package.json +1 -1
@@ -1,4 +1,5 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { hasActiveAgentRuns, } from "@agent-native/agentkit";
2
3
  import { AgentKitChat, AgentKitComposer, AgentApprovalPrompt, AgentMessageView, useAgentKit, useAgentKitControl, useAgentThread, } from "@agent-native/agentkit/react";
3
4
  import { AgentKitRoot } from "@agent-native/agentkit/react/root";
4
5
  import { AgentSuggestionBar, agentSuggestionPrompt, } from "@agent-native/toolkit/composer";
@@ -577,7 +578,7 @@ export const AgentKitAssistantChat = forwardRef(function AgentKitAssistantChat(p
577
578
  }, children: history ? (_jsx(AgentKitHistoryProvider, { history: history, children: _jsx(AgentKitDevCheckpointProvider, { apiUrl: props.apiUrl ?? agentNativePath("/_agent-native/agent-chat"), children: _jsx(AgentKitAssistantChatBody, { ...props, threadId: threadId, handoffSnapshot: handoffSnapshot, getThreadSnapshot: getThreadSnapshot, threadRestore: threadRestore, retryThreadRestore: retryThreadRestore, onThreadRestoreLoaded: onThreadRestoreLoaded, ref: ref }) }) })) : (_jsx(AgentKitDevCheckpointProvider, { apiUrl: props.apiUrl ?? agentNativePath("/_agent-native/agent-chat"), children: _jsx(AgentKitAssistantChatBody, { ...props, threadId: threadId, handoffSnapshot: handoffSnapshot, getThreadSnapshot: getThreadSnapshot, threadRestore: threadRestore, retryThreadRestore: retryThreadRestore, onThreadRestoreLoaded: onThreadRestoreLoaded, ref: ref }) })) }) }) }));
578
579
  });
579
580
  const AgentKitAssistantChatBody = forwardRef(function AgentKitAssistantChatBody(props, ref) {
580
- const { threadId, requestComposerFocus } = useAgentKit();
581
+ const { controller, threadId, requestComposerFocus } = useAgentKit();
581
582
  const control = useAgentKitControl(threadId);
582
583
  const thread = useAgentThread(threadId);
583
584
  const history = useOptionalAgentKitHistory();
@@ -701,7 +702,8 @@ const AgentKitAssistantChatBody = forwardRef(function AgentKitAssistantChatBody(
701
702
  const latestAssistant = useMemo(() => [...thread.messages]
702
703
  .reverse()
703
704
  .find((message) => message.role === "assistant"), [thread.messages]);
704
- const isRunning = thread.activeRunIds.length > 0;
705
+ const isRunning = hasActiveAgentRuns(thread);
706
+ const isThreadRunning = useCallback(() => hasActiveAgentRuns(controller.getThread(threadId)), [controller, threadId]);
705
707
  useEffect(() => {
706
708
  if (previousPrefillRevisionRef.current === prefillRevision)
707
709
  return;
@@ -1541,7 +1543,7 @@ const AgentKitAssistantChatBody = forwardRef(function AgentKitAssistantChatBody(
1541
1543
  thread.queuedMessages,
1542
1544
  threadId,
1543
1545
  ]);
1544
- const send = useCallback(async (text, images, options) => submit(text, [], [], { intent: isRunning ? "queued" : "immediate" }, {
1546
+ const send = useCallback(async (text, images, options) => submit(text, [], [], { intent: isThreadRunning() ? "queued" : "immediate" }, {
1545
1547
  ...options,
1546
1548
  attachments: [
1547
1549
  ...(options?.attachments ?? []),
@@ -1551,9 +1553,9 @@ const AgentKitAssistantChatBody = forwardRef(function AgentKitAssistantChatBody(
1551
1553
  url,
1552
1554
  })),
1553
1555
  ],
1554
- }), [isRunning, submit]);
1556
+ }), [isThreadRunning, submit]);
1555
1557
  const sendRecoveryMessage = useCallback(async (text, recoveryAction, images, attachments, references, recoveryOptions) => {
1556
- return submit(text, [], [], { intent: isRunning ? "queued" : "immediate" }, {
1558
+ return submit(text, [], [], { intent: isThreadRunning() ? "queued" : "immediate" }, {
1557
1559
  hideUserMessage: true,
1558
1560
  recoveryAction,
1559
1561
  recoveryReferences: references,
@@ -1567,7 +1569,7 @@ const AgentKitAssistantChatBody = forwardRef(function AgentKitAssistantChatBody(
1567
1569
  })),
1568
1570
  ],
1569
1571
  });
1570
- }, [isRunning, submit]);
1572
+ }, [isThreadRunning, submit]);
1571
1573
  const resumeIntegrationPrompt = useCallback((message) => {
1572
1574
  if (props.isActiveComposer === false)
1573
1575
  return;
@@ -1576,10 +1578,10 @@ const AgentKitAssistantChatBody = forwardRef(function AgentKitAssistantChatBody(
1576
1578
  });
1577
1579
  }, [props.isActiveComposer, props.tabId, send, threadId]);
1578
1580
  const submitSuggestion = useCallback((prompt) => void submit(prompt, [], [], {
1579
- intent: isRunning ? "queued" : "immediate",
1581
+ intent: isThreadRunning() ? "queued" : "immediate",
1580
1582
  }).catch((error) => {
1581
1583
  dispatchSetupRequiredEvent(error, props.tabId, threadId);
1582
- }), [isRunning, props.tabId, submit, threadId]);
1584
+ }), [isThreadRunning, props.tabId, submit, threadId]);
1583
1585
  const retryDeferredSubmission = useCallback(async () => {
1584
1586
  if (!deferredProviderSubmissionFailureId)
1585
1587
  return;
@@ -1659,7 +1661,7 @@ const AgentKitAssistantChatBody = forwardRef(function AgentKitAssistantChatBody(
1659
1661
  url,
1660
1662
  })),
1661
1663
  }),
1662
- isRunning: () => thread.activeRunIds.length > 0,
1664
+ isRunning: isThreadRunning,
1663
1665
  hasInFlightWork: () => Object.values(thread.tools).some((tool) => tool.status === "running") ||
1664
1666
  Object.values(thread.activities).some((activity) => activity.status === "running"),
1665
1667
  focusComposer: () => requestComposerFocus(threadId),
@@ -1787,6 +1789,7 @@ function AgentKitSelectionPill({ length, onClear, }) {
1787
1789
  }) }), _jsx("button", { type: "button", "aria-label": t("agentChat.selection.clear"), onClick: onClear, className: "flex h-4 w-4 items-center justify-center rounded text-muted-foreground hover:bg-accent/60 hover:text-foreground", children: _jsx(IconX, { size: 11, "aria-hidden": "true" }) })] }) }));
1788
1790
  }
1789
1791
  function AgentKitTranscript({ children, threadId }) {
1792
+ const { controller } = useAgentKit();
1790
1793
  const surface = useAgentKitSurface();
1791
1794
  const t = useT();
1792
1795
  const thread = useAgentThread(threadId);
@@ -1800,11 +1803,19 @@ function AgentKitTranscript({ children, threadId }) {
1800
1803
  browserTabId: surface.props.browserTabId,
1801
1804
  threadId,
1802
1805
  onSubmitMessage: async ({ message, context }) => {
1803
- await surface.onSubmit(appendAgentChatContextToMessage(message, context), [], [], { intent: surface.isRunning ? "queued" : "immediate" });
1806
+ await surface.onSubmit(appendAgentChatContextToMessage(message, context), [], [], {
1807
+ intent: hasActiveAgentRuns(controller.getThread(threadId))
1808
+ ? "queued"
1809
+ : "immediate",
1810
+ });
1804
1811
  return { delivered: true };
1805
1812
  },
1806
1813
  onSkipMessage: async ({ message, context }) => {
1807
- await surface.onSubmit(appendAgentChatContextToMessage(message, context), [], [], { intent: surface.isRunning ? "queued" : "immediate" });
1814
+ await surface.onSubmit(appendAgentChatContextToMessage(message, context), [], [], {
1815
+ intent: hasActiveAgentRuns(controller.getThread(threadId))
1816
+ ? "queued"
1817
+ : "immediate",
1818
+ });
1808
1819
  return { delivered: true };
1809
1820
  },
1810
1821
  });
@@ -2035,7 +2046,7 @@ function AgentKitMessageSupplement(props) {
2035
2046
  .join("\n");
2036
2047
  const integration = value.role === "assistant" &&
2037
2048
  value.status === "complete" &&
2038
- thread.activeRunIds.length === 0
2049
+ !hasActiveAgentRuns(thread)
2039
2050
  ? findMcpConnectionSuggestionIntegration({
2040
2051
  text,
2041
2052
  contextText,
@@ -1,4 +1,4 @@
1
- import { parseAgentThreadSnapshot } from "@agent-native/agentkit/protocol";
1
+ import { isAgentKitProtocolVersion, parseAgentThreadSnapshot, } from "@agent-native/agentkit/protocol";
2
2
  import { agentNativePath } from "../api-path.js";
3
3
  import { dispatchAgentChatRunning } from "../use-agent-chat-running-threads.js";
4
4
  import { appendChatThreadScopeParams, } from "../use-chat-threads.js";
@@ -285,6 +285,249 @@ function storedRepository(stored) {
285
285
  }
286
286
  return repository;
287
287
  }
288
+ function persistedError(value) {
289
+ const error = asRecord(value);
290
+ if (typeof error?.code !== "string" || typeof error.message !== "string") {
291
+ throw new TypeError("Agent chat run errors must include a code and message.");
292
+ }
293
+ const persisted = {
294
+ code: error.code.slice(0, 128),
295
+ message: error.message.slice(0, 2_048),
296
+ };
297
+ if (typeof error.retryable === "boolean") {
298
+ persisted.retryable = error.retryable;
299
+ }
300
+ if (typeof error.correlationId === "string") {
301
+ persisted.correlationId = error.correlationId.slice(0, 128);
302
+ }
303
+ if (error.code === "capability_unsupported" ||
304
+ error.code === "capability_unavailable") {
305
+ persisted.capability =
306
+ typeof error.capability === "string"
307
+ ? error.capability.slice(0, 128)
308
+ : "x-unknown";
309
+ persisted.retryable =
310
+ error.code === "capability_unsupported"
311
+ ? false
312
+ : typeof error.retryable === "boolean"
313
+ ? error.retryable
314
+ : false;
315
+ }
316
+ else if (error.code === "operation_unsupported") {
317
+ persisted.operation =
318
+ typeof error.operation === "string"
319
+ ? error.operation.slice(0, 128)
320
+ : "unknown";
321
+ persisted.retryable = false;
322
+ }
323
+ else if (error.code === "protocol_version_unsupported") {
324
+ persisted.supportedVersions = Array.isArray(error.supportedVersions)
325
+ ? error.supportedVersions.filter(isAgentKitProtocolVersion).slice(0, 32)
326
+ : [];
327
+ persisted.receivedVersions = Array.isArray(error.receivedVersions)
328
+ ? error.receivedVersions
329
+ .filter((version) => Number.isSafeInteger(version) && Number(version) > 0)
330
+ .slice(0, 32)
331
+ : [];
332
+ persisted.retryable = false;
333
+ }
334
+ return persisted;
335
+ }
336
+ function persistedAnnotation(annotation) {
337
+ return {
338
+ id: annotation.id,
339
+ kind: annotation.kind,
340
+ label: annotation.label,
341
+ ...(annotation.url ? { url: annotation.url } : {}),
342
+ ...(annotation.start !== undefined ? { start: annotation.start } : {}),
343
+ ...(annotation.end !== undefined ? { end: annotation.end } : {}),
344
+ };
345
+ }
346
+ function persistedAnnotations(annotations = [], messageIds) {
347
+ return annotations.flatMap(({ messageId, annotation }) => messageIds.has(messageId)
348
+ ? [{ messageId, annotation: persistedAnnotation(annotation) }]
349
+ : []);
350
+ }
351
+ function persistedFileUrl(url) {
352
+ return url && !/^\s*data:/i.test(url) ? url : undefined;
353
+ }
354
+ function persistedHistoryEvents(events = []) {
355
+ const sequenceByRun = new Map();
356
+ return events.flatMap((event) => {
357
+ const base = () => {
358
+ const sequence = (sequenceByRun.get(event.runId) ?? 0) + 1;
359
+ sequenceByRun.set(event.runId, sequence);
360
+ return {
361
+ id: event.id,
362
+ threadId: event.threadId,
363
+ runId: event.runId,
364
+ sequence,
365
+ occurredAt: event.occurredAt,
366
+ };
367
+ };
368
+ if (event.type === "run.started") {
369
+ return [{ ...base(), type: event.type }];
370
+ }
371
+ if (event.type === "run.completed" || event.type === "run.cancelled") {
372
+ return [{ ...base(), type: event.type }];
373
+ }
374
+ if (event.type === "run.failed") {
375
+ return [
376
+ { ...base(), type: event.type, error: persistedError(event.error) },
377
+ ];
378
+ }
379
+ if (event.type === "run.status") {
380
+ return [{ ...base(), type: event.type, status: event.status }];
381
+ }
382
+ if (event.type === "activity.started" ||
383
+ event.type === "activity.updated" ||
384
+ event.type === "activity.completed") {
385
+ const activity = event.activity;
386
+ return [
387
+ {
388
+ ...base(),
389
+ type: event.type,
390
+ activity: {
391
+ id: activity.id,
392
+ kind: activity.kind,
393
+ label: activity.label,
394
+ status: activity.status,
395
+ ...(activity.runId ? { runId: activity.runId } : {}),
396
+ ...(activity.agentId ? { agentId: activity.agentId } : {}),
397
+ ...(activity.startedAt ? { startedAt: activity.startedAt } : {}),
398
+ ...(activity.completedAt
399
+ ? { completedAt: activity.completedAt }
400
+ : {}),
401
+ },
402
+ },
403
+ ];
404
+ }
405
+ if (event.type === "message.completed" &&
406
+ event.message.role === "assistant") {
407
+ return [
408
+ {
409
+ ...base(),
410
+ type: event.type,
411
+ message: {
412
+ id: event.message.id,
413
+ role: event.message.role,
414
+ parts: event.message.parts.filter((part) => part.type === "text"),
415
+ ...(event.message.createdAt
416
+ ? { createdAt: event.message.createdAt }
417
+ : {}),
418
+ ...(event.message.status ? { status: event.message.status } : {}),
419
+ },
420
+ },
421
+ ];
422
+ }
423
+ return [];
424
+ });
425
+ }
426
+ function persistedMessages(messages) {
427
+ return messages.map((message) => ({
428
+ id: message.id,
429
+ role: message.role,
430
+ parts: message.parts.flatMap((part) => {
431
+ if (part.type === "text") {
432
+ return [
433
+ {
434
+ type: "text",
435
+ text: part.text,
436
+ ...(part.format ? { format: part.format } : {}),
437
+ },
438
+ ];
439
+ }
440
+ if (part.type === "citation") {
441
+ return [
442
+ {
443
+ type: "citation",
444
+ title: part.title,
445
+ ...(part.url ? { url: part.url } : {}),
446
+ ...(part.sourceId ? { sourceId: part.sourceId } : {}),
447
+ },
448
+ ];
449
+ }
450
+ if (part.type === "annotation") {
451
+ return [
452
+ {
453
+ type: "annotation",
454
+ annotation: persistedAnnotation(part.annotation),
455
+ },
456
+ ];
457
+ }
458
+ if (part.type === "file") {
459
+ const url = persistedFileUrl(part.url);
460
+ if (!url && !part.fileId)
461
+ return [];
462
+ return [
463
+ {
464
+ type: "file",
465
+ name: part.name,
466
+ ...(part.mediaType ? { mediaType: part.mediaType } : {}),
467
+ ...(url ? { url } : {}),
468
+ ...(part.fileId ? { fileId: part.fileId } : {}),
469
+ },
470
+ ];
471
+ }
472
+ return [];
473
+ }),
474
+ ...(message.createdAt ? { createdAt: message.createdAt } : {}),
475
+ ...(message.status ? { status: message.status } : {}),
476
+ ...(asRecord(message.metadata)?.hideUserMessage === true
477
+ ? { metadata: { hideUserMessage: true } }
478
+ : {}),
479
+ }));
480
+ }
481
+ function persistedActionWidgets(widgets = [], messageIds) {
482
+ return widgets.flatMap(({ messageId, widget }) => {
483
+ if (!messageIds.has(messageId))
484
+ return [];
485
+ const data = asRecord(widget.data);
486
+ if (typeof data?.toolCallId !== "string" ||
487
+ typeof data.toolName !== "string") {
488
+ return [];
489
+ }
490
+ const description = asRecord(widget.metadata)?.description;
491
+ return [
492
+ {
493
+ messageId,
494
+ widget: {
495
+ id: widget.id,
496
+ kind: widget.kind,
497
+ data: { toolCallId: data.toolCallId, toolName: data.toolName },
498
+ ...(widget.title ? { title: widget.title } : {}),
499
+ ...(typeof description === "string"
500
+ ? { metadata: { description } }
501
+ : {}),
502
+ },
503
+ },
504
+ ];
505
+ });
506
+ }
507
+ function persistedToolCalls(toolCalls = []) {
508
+ return toolCalls.flatMap((toolCall) => {
509
+ const serialized = JSON.stringify(toolCall);
510
+ if (serialized &&
511
+ new TextEncoder().encode(serialized).byteLength <= 64 * 1024) {
512
+ return [JSON.parse(serialized)];
513
+ }
514
+ return [
515
+ {
516
+ id: toolCall.id,
517
+ name: toolCall.name,
518
+ status: toolCall.status,
519
+ ...(toolCall.runId ? { runId: toolCall.runId } : {}),
520
+ ...(toolCall.messageId ? { messageId: toolCall.messageId } : {}),
521
+ metadata: {
522
+ agentKitSnapshot: {
523
+ toolCallResult: "omitted",
524
+ reason: serialized ? "size_limit" : "not_json",
525
+ },
526
+ },
527
+ },
528
+ ];
529
+ });
530
+ }
288
531
  function storedMessageId(value) {
289
532
  const outer = asRecord(value);
290
533
  const message = asRecord(outer?.message ?? outer);
@@ -452,6 +695,7 @@ export function createAgentNativeAgentKitTransport(options = {}) {
452
695
  const createdAt = timestamp(stored.createdAt, projectedAt);
453
696
  const updatedAt = timestamp(stored.updatedAt, createdAt);
454
697
  const repository = storedRepository(stored);
698
+ const storedMessageProjection = storedMessages(repository.messages, now, options.adapter?.textFormat);
455
699
  const queuedMessages = storedQueue(repository.queuedMessages, threadId, updatedAt);
456
700
  const agentKit = asRecord(repository.agentKit);
457
701
  const protocolSnapshot = agentKit
@@ -461,13 +705,17 @@ export function createAgentNativeAgentKitTransport(options = {}) {
461
705
  createdAt,
462
706
  updatedAt,
463
707
  metadata: asRecord(stored.metadata) ?? undefined,
464
- messages: agentKit.messages,
708
+ messages: Array.isArray(agentKit.messages)
709
+ ? agentKit.messages
710
+ : storedMessageProjection,
465
711
  events: agentKit.events,
466
712
  runs: agentKit.runs,
467
713
  activeRunIds: agentKit.activeRunIds,
714
+ suggestions: agentKit.suggestions,
468
715
  toolCalls: agentKit.toolCalls,
469
716
  activities: agentKit.activities,
470
717
  widgets: agentKit.widgets,
718
+ annotations: agentKit.annotations,
471
719
  })
472
720
  : undefined;
473
721
  const durableMessages = storedMessages(repository.messages, now, options.adapter?.textFormat);
@@ -475,14 +723,52 @@ export function createAgentNativeAgentKitTransport(options = {}) {
475
723
  ? reconcileDurableAssistantText(protocolSnapshot.messages, durableMessages, protocolSnapshot.events)
476
724
  : durableMessages;
477
725
  const actionWidgets = storedActionWidgets(repository.messages);
726
+ const canonicalToolCallMessageIds = new Map((protocolSnapshot?.toolCalls ?? []).flatMap((toolCall) => toolCall.messageId ? [[toolCall.id, toolCall.messageId]] : []));
727
+ const embeddedWidgetIds = new Set(messages.flatMap((message) => message.parts.flatMap((part) => part.type === "widget" ? [part.widget.id] : [])));
728
+ const persistedWidgetIds = new Set([
729
+ ...(protocolSnapshot?.widgets ?? []).map(({ widget }) => widget.id),
730
+ ...embeddedWidgetIds,
731
+ ]);
732
+ const messageIds = new Set(messages.map((message) => message.id));
733
+ const reconciledActionWidgets = actionWidgets.widgets.map(({ messageId, widget }) => {
734
+ const toolCallId = asRecord(widget.data)?.toolCallId;
735
+ const canonicalMessageId = typeof toolCallId === "string"
736
+ ? canonicalToolCallMessageIds.get(toolCallId)
737
+ : undefined;
738
+ return {
739
+ messageId: canonicalMessageId && messageIds.has(canonicalMessageId)
740
+ ? canonicalMessageId
741
+ : messageId,
742
+ widget,
743
+ };
744
+ });
745
+ const widgetMessageIds = new Set(reconciledActionWidgets
746
+ .filter(({ widget }) => !persistedWidgetIds.has(widget.id))
747
+ .map(({ messageId }) => messageId));
748
+ for (const message of storedMessageProjection) {
749
+ if (!widgetMessageIds.has(message.id) || messageIds.has(message.id)) {
750
+ continue;
751
+ }
752
+ messages.push({
753
+ ...message,
754
+ parts: message.parts.filter((part) => part.type !== "data"),
755
+ });
756
+ messageIds.add(message.id);
757
+ }
758
+ for (const { messageId, widget } of reconciledActionWidgets) {
759
+ if (!persistedWidgetIds.has(widget.id) && !messageIds.has(messageId)) {
760
+ throw new TypeError(`Action widget ${widget.id} references missing message ${messageId}.`);
761
+ }
762
+ }
478
763
  const toolCalls = new Map((protocolSnapshot?.toolCalls ?? []).map((toolCall) => [toolCall.id, toolCall]));
479
764
  for (const toolCall of actionWidgets.toolCalls) {
480
765
  if (!toolCalls.has(toolCall.id))
481
766
  toolCalls.set(toolCall.id, toolCall);
482
767
  }
483
768
  const widgets = new Map((protocolSnapshot?.widgets ?? []).map((widget) => [widget.widget.id, widget]));
484
- for (const widget of actionWidgets.widgets) {
485
- if (!widgets.has(widget.widget.id)) {
769
+ for (const widget of reconciledActionWidgets) {
770
+ if (!widgets.has(widget.widget.id) &&
771
+ !embeddedWidgetIds.has(widget.widget.id)) {
486
772
  widgets.set(widget.widget.id, widget);
487
773
  }
488
774
  }
@@ -499,9 +785,15 @@ export function createAgentNativeAgentKitTransport(options = {}) {
499
785
  ...(protocolSnapshot?.activeRunIds
500
786
  ? { activeRunIds: protocolSnapshot.activeRunIds }
501
787
  : {}),
788
+ ...(protocolSnapshot?.suggestions
789
+ ? { suggestions: protocolSnapshot.suggestions }
790
+ : {}),
502
791
  ...(protocolSnapshot?.activities
503
792
  ? { activities: protocolSnapshot.activities }
504
793
  : {}),
794
+ ...(protocolSnapshot?.annotations
795
+ ? { annotations: protocolSnapshot.annotations }
796
+ : {}),
505
797
  toolCalls: [...toolCalls.values()],
506
798
  widgets: [...widgets.values()],
507
799
  };
@@ -562,6 +854,78 @@ export function createAgentNativeAgentKitTransport(options = {}) {
562
854
  ],
563
855
  };
564
856
  }
857
+ async function persistThreadSnapshot(input) {
858
+ const stored = await fetchThread(input.threadId);
859
+ if (!stored) {
860
+ throw new Error(`Agent chat thread ${input.threadId} does not exist.`);
861
+ }
862
+ const repository = storedRepository(stored);
863
+ const previousAgentKit = asRecord(repository.agentKit) ?? {};
864
+ const compactEvents = persistedHistoryEvents(input.snapshot.events);
865
+ const compactRunIds = new Set(compactEvents.map((event) => event.runId));
866
+ const eventsById = new Map();
867
+ const previousEvents = Array.isArray(previousAgentKit.events)
868
+ ? previousAgentKit.events
869
+ : [];
870
+ for (const event of previousEvents) {
871
+ const record = asRecord(event);
872
+ if (typeof record?.id === "string" &&
873
+ typeof record.runId === "string" &&
874
+ !compactRunIds.has(record.runId)) {
875
+ eventsById.set(record.id, event);
876
+ }
877
+ }
878
+ for (const event of compactEvents) {
879
+ eventsById.set(event.id, event);
880
+ }
881
+ const runsById = new Map();
882
+ const previousRuns = Array.isArray(previousAgentKit.runs)
883
+ ? previousAgentKit.runs
884
+ : [];
885
+ for (const run of [...previousRuns, ...(input.snapshot.runs ?? [])]) {
886
+ const record = asRecord(run);
887
+ if (typeof record?.id === "string")
888
+ runsById.set(record.id, run);
889
+ }
890
+ const snapshotMessageIds = new Set(input.snapshot.messages.map((message) => message.id));
891
+ const annotations = input.snapshot.annotations ??
892
+ (Array.isArray(previousAgentKit.annotations)
893
+ ? previousAgentKit.annotations
894
+ : []);
895
+ const agentKit = {
896
+ ...previousAgentKit,
897
+ messages: persistedMessages(input.snapshot.messages),
898
+ widgets: persistedActionWidgets(input.snapshot.widgets, new Set(input.snapshot.messages.map((message) => message.id))),
899
+ toolCalls: persistedToolCalls(input.snapshot.toolCalls),
900
+ events: [...eventsById.values()],
901
+ runs: [...runsById.values()].map((run) => {
902
+ const record = asRecord(run);
903
+ return record && record.error !== undefined
904
+ ? { ...record, error: persistedError(record.error) }
905
+ : run;
906
+ }),
907
+ activeRunIds: input.snapshot.activeRunIds ?? [],
908
+ suggestions: input.snapshot.suggestions ?? previousAgentKit.suggestions,
909
+ annotations: persistedAnnotations(annotations, snapshotMessageIds),
910
+ };
911
+ const requestHeaders = await headers({ sessionId: input.threadId });
912
+ requestHeaders.set("content-type", "application/json");
913
+ const snapshotRepository = { ...repository };
914
+ delete snapshotRepository.queuedMessages;
915
+ const response = await fetcher(scopedThreadEndpoint(`${apiUrl}/threads/${encodeURIComponent(input.threadId)}`, options), {
916
+ method: "PUT",
917
+ headers: requestHeaders,
918
+ body: JSON.stringify({
919
+ threadData: JSON.stringify({ ...snapshotRepository, agentKit }),
920
+ title: input.snapshot.title ??
921
+ (typeof stored.title === "string" ? stored.title : ""),
922
+ preview: typeof stored.preview === "string" ? stored.preview : "",
923
+ messageCount: input.snapshot.messages.length,
924
+ }),
925
+ });
926
+ if (!response.ok)
927
+ throw await responseError(response);
928
+ }
565
929
  async function persistQueueMutation(threadId, mutation) {
566
930
  const requestHeaders = await headers({ sessionId: threadId });
567
931
  requestHeaders.set("content-type", "application/json");
@@ -641,6 +1005,7 @@ export function createAgentNativeAgentKitTransport(options = {}) {
641
1005
  },
642
1006
  operations: {
643
1007
  ...options.operations,
1008
+ persistThreadSnapshot: options.operations?.persistThreadSnapshot ?? persistThreadSnapshot,
644
1009
  getThread: async ({ threadId }) => {
645
1010
  const thread = await snapshot(threadId);
646
1011
  if (!thread)
@@ -741,23 +1106,59 @@ export function createAgentNativeAgentKitTransport(options = {}) {
741
1106
  let forkSource;
742
1107
  if (fromMessageId) {
743
1108
  const repository = storedRepository(source);
744
- if (!Array.isArray(repository.messages)) {
1109
+ const agentKit = asRecord(repository.agentKit);
1110
+ const sourceMessages = Array.isArray(agentKit?.messages)
1111
+ ? agentKit.messages
1112
+ : repository.messages;
1113
+ if (!Array.isArray(sourceMessages)) {
745
1114
  throw new Error("The Agent-Native thread cannot be forked from a message without durable history.");
746
1115
  }
747
- const throughIndex = repository.messages.findIndex((message) => storedMessageId(message) === fromMessageId);
1116
+ const throughIndex = sourceMessages.findIndex((message) => storedMessageId(message) === fromMessageId);
748
1117
  if (throughIndex < 0) {
749
1118
  throw new Error("Unknown message for fork: " + fromMessageId);
750
1119
  }
751
- const messages = repository.messages.slice(0, throughIndex + 1);
1120
+ const messages = sourceMessages.slice(0, throughIndex + 1);
1121
+ const retainedMessageIds = new Set(messages
1122
+ .map(storedMessageId)
1123
+ .filter((id) => Boolean(id)));
1124
+ const legacyMessages = Array.isArray(repository.messages)
1125
+ ? repository.messages.filter((message) => retainedMessageIds.has(storedMessageId(message) ?? ""))
1126
+ : undefined;
1127
+ const retainedAgentKit = agentKit && Array.isArray(agentKit.messages)
1128
+ ? {
1129
+ ...agentKit,
1130
+ messages,
1131
+ ...(Array.isArray(agentKit.widgets)
1132
+ ? {
1133
+ widgets: agentKit.widgets.filter((entry) => {
1134
+ const widget = asRecord(entry);
1135
+ return (typeof widget?.messageId === "string" &&
1136
+ retainedMessageIds.has(widget.messageId));
1137
+ }),
1138
+ }
1139
+ : {}),
1140
+ ...(Array.isArray(agentKit.toolCalls)
1141
+ ? {
1142
+ toolCalls: agentKit.toolCalls.filter((entry) => {
1143
+ const toolCall = asRecord(entry);
1144
+ return (typeof toolCall?.messageId !== "string" ||
1145
+ retainedMessageIds.has(toolCall.messageId));
1146
+ }),
1147
+ }
1148
+ : {}),
1149
+ }
1150
+ : undefined;
752
1151
  forkSource = {
753
1152
  threadData: JSON.stringify({
754
1153
  ...repository,
755
- messages,
1154
+ ...(legacyMessages ? { messages: legacyMessages } : {}),
1155
+ ...(retainedAgentKit ? { agentKit: retainedAgentKit } : {}),
756
1156
  queuedMessages: [],
757
1157
  }),
758
1158
  title: title ?? (typeof source.title === "string" ? source.title : ""),
759
1159
  preview: "",
760
1160
  messageCount: messages.length,
1161
+ fromMessageId,
761
1162
  };
762
1163
  }
763
1164
  const requestHeaders = await headers({ sessionId: threadId });
@@ -2610,6 +2610,9 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
2610
2610
  };
2611
2611
  }
2612
2612
  const hostOperations = options.operations;
2613
+ if (hostOperations?.persistThreadSnapshot) {
2614
+ transport.persistThreadSnapshot = hostOperations.persistThreadSnapshot;
2615
+ }
2613
2616
  if (hostOperations?.createThread) {
2614
2617
  transport.createThread = (input = {}, context) => {
2615
2618
  const metadata = mergeTrustedProtocolMetadata(options.metadata, input.metadata);
@@ -38,19 +38,19 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
38
38
  error: string;
39
39
  states?: undefined;
40
40
  } | {
41
- error?: undefined;
42
41
  states: {
43
42
  clientId: number;
44
43
  state: string;
45
44
  }[];
45
+ error?: undefined;
46
46
  }>>;
47
47
  export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
48
48
  error: string;
49
49
  users?: undefined;
50
50
  } | {
51
- error?: undefined;
52
51
  users: {
53
52
  clientId: number;
54
53
  lastSeen: number;
55
54
  }[];
55
+ error?: undefined;
56
56
  }>>;
@@ -42,8 +42,8 @@ declare const _default: import("../../action.js").ActionDefinition<{
42
42
  url: string;
43
43
  id: string;
44
44
  provider: string;
45
- configured?: undefined;
46
45
  error?: undefined;
46
+ configured?: undefined;
47
47
  } | {
48
48
  url?: undefined;
49
49
  id?: undefined;