@copilotkit/react-core 1.79.2-canary.1792172552 → 1.80.0

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 (42) hide show
  1. package/dist/{copilotkit-DcENKLnJ.mjs → copilotkit-BNLtgOyD.mjs} +1783 -238
  2. package/dist/copilotkit-BNLtgOyD.mjs.map +1 -0
  3. package/dist/{copilotkit-kcYN96tM.d.mts → copilotkit-CWOSXhRO.d.mts} +278 -41
  4. package/dist/copilotkit-CWOSXhRO.d.mts.map +1 -0
  5. package/dist/{copilotkit-ConxFSB2.cjs → copilotkit-DKICi3nC.cjs} +1764 -206
  6. package/dist/copilotkit-DKICi3nC.cjs.map +1 -0
  7. package/dist/{copilotkit-BA0vyDds.d.cts → copilotkit-Dfw9HzO9.d.cts} +278 -41
  8. package/dist/copilotkit-Dfw9HzO9.d.cts.map +1 -0
  9. package/dist/index.cjs +15 -3
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +1 -1
  12. package/dist/index.d.cts.map +1 -1
  13. package/dist/index.d.mts +1 -1
  14. package/dist/index.d.mts.map +1 -1
  15. package/dist/index.mjs +15 -3
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/index.umd.js +48 -11
  18. package/dist/index.umd.js.map +1 -1
  19. package/dist/v2/context.d.cts +7 -0
  20. package/dist/v2/context.d.cts.map +1 -1
  21. package/dist/v2/context.d.mts +7 -0
  22. package/dist/v2/context.d.mts.map +1 -1
  23. package/dist/v2/headless.cjs +23 -6
  24. package/dist/v2/headless.cjs.map +1 -1
  25. package/dist/v2/headless.d.cts +20 -2
  26. package/dist/v2/headless.d.cts.map +1 -1
  27. package/dist/v2/headless.d.mts +20 -2
  28. package/dist/v2/headless.d.mts.map +1 -1
  29. package/dist/v2/headless.mjs +23 -6
  30. package/dist/v2/headless.mjs.map +1 -1
  31. package/dist/v2/index.cjs +3 -7
  32. package/dist/v2/index.css +1 -1
  33. package/dist/v2/index.d.cts +2 -2
  34. package/dist/v2/index.d.mts +2 -2
  35. package/dist/v2/index.mjs +2 -2
  36. package/dist/v2/index.umd.js +1756 -215
  37. package/dist/v2/index.umd.js.map +1 -1
  38. package/package.json +14 -11
  39. package/dist/copilotkit-BA0vyDds.d.cts.map +0 -1
  40. package/dist/copilotkit-ConxFSB2.cjs.map +0 -1
  41. package/dist/copilotkit-DcENKLnJ.mjs.map +0 -1
  42. package/dist/copilotkit-kcYN96tM.d.mts.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import * as React$1 from "react";
2
- import React, { createContext, createElement, forwardRef, memo, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
3
- import { AgentRegistry, AgentThreadLockedError, ContextStore, CopilotKitCore, CopilotKitCore as CopilotKitCore$1, CopilotKitCoreErrorCode, CopilotKitCoreErrorCode as CopilotKitCoreErrorCode$1, CopilotKitCoreRuntimeConnectionStatus, CopilotKitCoreRuntimeConnectionStatus as CopilotKitCoreRuntimeConnectionStatus$1, CopilotKitHeaderResolutionError, INSPECTOR_THREAD_BRIDGE_PLUGIN_ID, IntelligenceAgent, IntelligenceReplayFailedError, MEMORY_ERROR_REGISTRY, MemoryError, ProxiedCopilotRuntimeAgent, ProxiedCopilotRuntimeAgent as ProxiedCopilotRuntimeAgent$1, RunHandler, StateManager, SuggestionEngine, ToolCallStatus, ToolCallStatus as ToolCallStatus$1, WebMCPRegistry, completePartialMarkdown, createActionGroup, createEffect, createInspectorThreadRequestId, createReducer, createSelector, createStore, emitInspectorActiveThread, emitInspectorActiveThread as emitInspectorActiveThread$1, emitInspectorStopViewing, emitInspectorViewThread, emitInspectorViewThreadResult, emitInspectorViewThreadResult as emitInspectorViewThreadResult$1, empty, ensureObjectArgs, getWebMCPModelContext, isAbortError, isInspectorThreadBridgeEnabled, isInspectorThreadBridgeEnabled as isInspectorThreadBridgeEnabled$1, isRunCompletionAware, isRunCompletionAware as isRunCompletionAware$1, ofType, on, onInspectorActiveThread, onInspectorStopViewing, onInspectorStopViewing as onInspectorStopViewing$1, onInspectorViewThread, onInspectorViewThread as onInspectorViewThread$1, onInspectorViewThreadResult, parseToolArguments, props, select, ɵCOPILOTKIT_FEATURES, ɵInterruptState, ɵInterruptState as ɵInterruptState$1, ɵMAX_SOCKET_RETRIES, ɵRUNTIME_PROBE_TIMEOUT_MS, ɵTHREAD_REQUEST_TIMEOUT_MS, ɵcreateMemoryStore, ɵcreateThreadSelectors, ɵcreateThreadStore, ɵcreateThreadStore as ɵcreateThreadStore$1, ɵisCopilotKitFeature, ɵisHttpAgent, ɵisHttpAgent as ɵisHttpAgent$1, ɵisRetryableMemoryStatus, ɵjoinPhoenixChannel$, ɵmapMemoryMetadataEvent, ɵmemoryAdapterEvents, ɵmemoryDomainEvents, ɵmemoryReducer, ɵmemoryRestEvents, ɵobservePhoenixEvent$, ɵobservePhoenixJoinOutcome$, ɵobservePhoenixSocketHealth$, ɵobservePhoenixSocketSignals$, ɵphoenixChannel$, ɵphoenixSocket$, ɵselectFetchMoreError, ɵselectFetchMoreError as ɵselectFetchMoreError$1, ɵselectHasNextPage, ɵselectHasNextPage as ɵselectHasNextPage$1, ɵselectIsFetchingNextPage, ɵselectIsFetchingNextPage as ɵselectIsFetchingNextPage$1, ɵselectIsMutating, ɵselectIsMutating as ɵselectIsMutating$1, ɵselectMemories, ɵselectMemories as ɵselectMemories$1, ɵselectMemoriesAvailable, ɵselectMemoriesAvailable as ɵselectMemoriesAvailable$1, ɵselectMemoriesError, ɵselectMemoriesError as ɵselectMemoriesError$1, ɵselectMemoriesIsLoading, ɵselectMemoriesIsLoading as ɵselectMemoriesIsLoading$1, ɵselectMemoriesIsMutating, ɵselectMemoriesRealtimeStatus, ɵselectMemoriesRealtimeStatus as ɵselectMemoriesRealtimeStatus$1, ɵselectThreads, ɵselectThreads as ɵselectThreads$1, ɵselectThreadsError, ɵselectThreadsError as ɵselectThreadsError$1, ɵselectThreadsIsLoading, ɵselectThreadsIsLoading as ɵselectThreadsIsLoading$1, ɵthreadAdapterEvents, ɵwithHeaderDefaults, ɵwithHeaderDefaults as ɵwithHeaderDefaults$1 } from "@copilotkit/core";
2
+ import React, { Fragment, createContext, createElement, forwardRef, memo, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
3
+ import { AgentRegistry, AgentThreadLockedError, ContextStore, CopilotKitCore, CopilotKitCore as CopilotKitCore$1, CopilotKitCoreErrorCode, CopilotKitCoreErrorCode as CopilotKitCoreErrorCode$1, CopilotKitCoreRuntimeConnectionStatus, CopilotKitCoreRuntimeConnectionStatus as CopilotKitCoreRuntimeConnectionStatus$1, CopilotKitHeaderResolutionError, INSPECTOR_THREAD_BRIDGE_PLUGIN_ID, IntelligenceAgent, MEMORY_ERROR_REGISTRY, MemoryError, ProxiedCopilotRuntimeAgent, ProxiedCopilotRuntimeAgent as ProxiedCopilotRuntimeAgent$1, RunHandler, StateManager, SuggestionEngine, ToolCallStatus, ToolCallStatus as ToolCallStatus$1, WebMCPRegistry, completePartialMarkdown, createActionGroup, createEffect, createInspectorThreadRequestId, createReducer, createSelector, createStore, emitInspectorActiveThread, emitInspectorActiveThread as emitInspectorActiveThread$1, emitInspectorStopViewing, emitInspectorViewThread, emitInspectorViewThreadResult, emitInspectorViewThreadResult as emitInspectorViewThreadResult$1, empty, ensureObjectArgs, getWebMCPModelContext, isAbortError, isInspectorThreadBridgeEnabled, isInspectorThreadBridgeEnabled as isInspectorThreadBridgeEnabled$1, isRunCompletionAware, isRunCompletionAware as isRunCompletionAware$1, ofType, on, onInspectorActiveThread, onInspectorStopViewing, onInspectorStopViewing as onInspectorStopViewing$1, onInspectorViewThread, onInspectorViewThread as onInspectorViewThread$1, onInspectorViewThreadResult, parseToolArguments, props, select, ɵCOPILOTKIT_FEATURES, ɵInterruptState, ɵInterruptState as ɵInterruptState$1, ɵMAX_SOCKET_RETRIES, ɵRUNTIME_PROBE_TIMEOUT_MS, ɵTHREAD_REQUEST_TIMEOUT_MS, ɵcreateMemoryStore, ɵcreateThreadSelectors, ɵcreateThreadStore, ɵcreateThreadStore as ɵcreateThreadStore$1, ɵisCopilotKitFeature, ɵisHttpAgent, ɵisHttpAgent as ɵisHttpAgent$1, ɵisRetryableMemoryStatus, ɵjoinPhoenixChannel$, ɵmapMemoryMetadataEvent, ɵmemoryAdapterEvents, ɵmemoryDomainEvents, ɵmemoryReducer, ɵmemoryRestEvents, ɵobservePhoenixEvent$, ɵobservePhoenixJoinOutcome$, ɵobservePhoenixSocketHealth$, ɵobservePhoenixSocketSignals$, ɵphoenixChannel$, ɵphoenixSocket$, ɵselectFetchMoreError, ɵselectFetchMoreError as ɵselectFetchMoreError$1, ɵselectHasNextPage, ɵselectHasNextPage as ɵselectHasNextPage$1, ɵselectIsFetchingNextPage, ɵselectIsFetchingNextPage as ɵselectIsFetchingNextPage$1, ɵselectIsMutating, ɵselectIsMutating as ɵselectIsMutating$1, ɵselectMemories, ɵselectMemories as ɵselectMemories$1, ɵselectMemoriesAvailable, ɵselectMemoriesAvailable as ɵselectMemoriesAvailable$1, ɵselectMemoriesError, ɵselectMemoriesError as ɵselectMemoriesError$1, ɵselectMemoriesIsLoading, ɵselectMemoriesIsLoading as ɵselectMemoriesIsLoading$1, ɵselectMemoriesIsMutating, ɵselectMemoriesRealtimeStatus, ɵselectMemoriesRealtimeStatus as ɵselectMemoriesRealtimeStatus$1, ɵselectThreads, ɵselectThreads as ɵselectThreads$1, ɵselectThreadsError, ɵselectThreadsError as ɵselectThreadsError$1, ɵselectThreadsIsLoading, ɵselectThreadsIsLoading as ɵselectThreadsIsLoading$1, ɵthreadAdapterEvents, ɵwithHeaderDefaults, ɵwithHeaderDefaults as ɵwithHeaderDefaults$1 } from "@copilotkit/core";
4
4
  import { ACTIVITY_HISTORY_METADATA, AGUIConnectNotImplementedError as AGUIConnectNotImplementedError$1, AGUIError, AGUI_METADATA_KEY, AbstractAgent as AbstractAgent$1, BackwardCompatibility_0_0_39, BackwardCompatibility_0_0_45, BackwardCompatibility_0_0_57, CompatibilityBoundary, DebugLogger, EventType, FilterToolCallsMiddleware, FunctionMiddleware, HttpAgent, Middleware, PROTOCOL_VERSION, aggregateTokenUsage, authoritativeActivityTypes, buildResumeArray, compactEvents, contentHasMedia, contentToText as contentToText$1, convertToLegacyEvents, createDebugLogger, defaultApplyEvents, enforceEvents, enforceOutgoingInput, getRunOutcome, isInterruptExpired, isRecognizedEvent, mergeMetadata, omitOptionalNulls, parseProtoStream, parseSSEStream, randomUUID, randomUUID as randomUUID$2, resolveAgentDebugConfig, resolveDebugLogger, runHttpRequest, structuredClone_, tokenUsageFromAiSdkUsage, tokenUsageFromLangChainMetadata, transformChunks, transformHttpEventStream, verifyEvents, withAuthoritativeActivityTypes } from "@ag-ui/client";
5
5
  import { ActivityDeltaEventSchema, ActivityMessageSchema, ActivitySnapshotEventSchema, AddOperationSchema, AgentCapabilitiesSchema, AssistantMessageSchema, AttributableSchema, AudioInputContentSchema, AudioInputPartSchema, AudioPartSchema, BaseEventSchema, BaseMessageSchema, ContentPartSchema, ContextSchema, CopyOperationSchema, CustomEventSchema, DataSourceSchema, DeveloperMessageSchema, DocumentInputContentSchema, DocumentInputPartSchema, DocumentPartSchema, EventSchema, EventSchemas, EventTypeSchema, ExecutionCapabilitiesSchema, FileSourceSchema, FunctionCallSchema, HumanInTheLoopCapabilitiesSchema, IdentityCapabilitiesSchema, ImageInputContentSchema, ImageInputPartSchema, ImagePartSchema, InputContentDataSourceSchema, InputContentSchema, InputContentSourceSchema, InputContentUrlSourceSchema, InterruptSchema, JsonPatchOperationSchema, JsonPatchSchema, JsonPointerSchema, MessageSchema, MessagesSnapshotEventSchema, MetadataSchema, MoveOperationSchema, MultiAgentCapabilitiesSchema, MultimodalCapabilitiesSchema, MultimodalInputCapabilitiesSchema, MultimodalOutputCapabilitiesSchema, OptionalMetadataSchema, OutputCapabilitiesSchema, PartSourceSchema, RawEventSchema, ReasoningCapabilitiesSchema, ReasoningEncryptedValueEventSchema, ReasoningEncryptedValueSubtypeSchema, ReasoningEndEventSchema, ReasoningMessageChunkEventSchema, ReasoningMessageContentEventSchema, ReasoningMessageEndEventSchema, ReasoningMessageSchema, ReasoningMessageStartEventSchema, ReasoningStartEventSchema, RemoveOperationSchema, ReplaceOperationSchema, ResumeEntrySchema, RoleSchema, RunAgentInputSchema, RunErrorEventSchema, RunFinishedCancelledOutcomeSchema, RunFinishedEventSchema, RunFinishedInterruptOutcomeSchema, RunFinishedOutcomeSchema, RunFinishedSuccessOutcomeSchema, RunStartedEventSchema, StateCapabilitiesSchema, StateDeltaEventSchema, StateSchema, StateSnapshotEventSchema, StepFinishedEventSchema, StepStartedEventSchema, SubagentErrorEventSchema, SubagentFinishedEventSchema, SubagentFinishedOutcomeSchema, SubagentFinishedSuccessOutcomeSchema, SubagentFinishedSuspendedOutcomeSchema, SubagentInfoSchema, SubagentRunIdSchema, SubagentStartedEventSchema, SystemMessageSchema, TestOperationSchema, TextInputContentSchema, TextMessageChunkEventSchema, TextMessageContentEventSchema, TextMessageEndEventSchema, TextMessageRoleSchema, TextMessageStartEventSchema, TextPartSchema, TokenUsageSchema, ToolCallArgsEventSchema, ToolCallChunkEventSchema, ToolCallEndEventSchema, ToolCallResultEventSchema, ToolCallSchema, ToolCallStartEventSchema, ToolMessageSchema, ToolSchema, ToolsCapabilitiesSchema, TransportCapabilitiesSchema, UrlSourceSchema, UserMessageSchema, VideoInputContentSchema, VideoInputPartSchema, VideoPartSchema } from "@ag-ui/core/schemas";
6
6
  import { extendTailwindMerge, twMerge } from "tailwind-merge";
7
- import { ArrowUp, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronRightIcon, Copy, Edit, EyeOff, Loader2, MessageCircle, Mic, PanelLeftOpen, Play, Plus, RefreshCw, Square, ThumbsDown, ThumbsUp, Upload, Volume2, Wrench, X } from "lucide-react";
7
+ import { ArrowUp, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronRightIcon, Circle, Copy, Edit, EyeOff, Loader2, MessageCircle, Mic, PanelLeftOpen, Play, Plus, RefreshCw, Square, ThumbsDown, ThumbsUp, Upload, Volume2, Wrench, X } from "lucide-react";
8
8
  import { A2UI_DEFAULT_DESIGN_GUIDELINES, A2UI_DEFAULT_GENERATION_GUIDELINES, COPILOT_CLOUD_API_URL, COPILOT_CLOUD_CHAT_URL, COPILOT_CLOUD_PUBLIC_API_KEY_HEADER, ConfigurationError, CopilotKitAgentDiscoveryError, CopilotKitApiDiscoveryError, CopilotKitError, CopilotKitErrorCode, CopilotKitLowLevelError, CopilotKitRemoteEndpointDiscoveryError, DEFAULT_AGENT_ID, ErrorVisibility, GENERATE_SANDBOXED_UI_DESCRIPTION, MissingPublicApiKeyError, Severity, TranscriptionErrorCode, TranscriptionErrorCode as TranscriptionErrorCode$1, commitRowKeyStore, copyToClipboard, createAttachmentContent, createLicenseContextValue, createRowKeyStore, dataToUUID, exceedsMaxSize, formatFileSize, generateVideoThumbnail, getDocumentIcon, getModalityFromMimeType, getSourceUrl, matchesAcceptFilter, parseJson, partialJSONParse, randomId, randomUUID as randomUUID$1, readFileAsBase64, resolveRowRenderKeysById, schemaToJsonSchema, shouldEnableInspector } from "@copilotkit/shared";
9
9
  import { CopilotKitAgentIdContext, CopilotKitContext, LicenseContext, useCopilotKit, useCopilotKit as useCopilotKit$1, useDefaultAgentId, useLicenseContext, useLicenseContext as useLicenseContext$1 } from "@copilotkit/react-core/v2/context";
10
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -19,6 +19,7 @@ import { z } from "zod";
19
19
  import { MCPAppsActivityContentSchema, MCPAppsActivityType, ɵrunMcpFollowUp } from "@copilotkit/mcp-apps-renderer/activity";
20
20
  import { A2UIProvider, A2UIRenderer, A2UI_SCHEMA_CONTEXT_DESCRIPTION, Catalog, DEFAULT_SURFACE_ID, ROOT_COMPONENT_ID, buildCatalogContextValue, extractCatalogComponentSchemas, filterCatalog, initializeDefaultCatalog, injectStyles, useA2UIActions, useA2UIError, viewerTheme } from "@copilotkit/a2ui-renderer";
21
21
  import { zodToJsonSchema } from "zod-to-json-schema";
22
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
22
23
  import { createPortal, flushSync } from "react-dom";
23
24
  import { useVirtualizer } from "@tanstack/react-virtual";
24
25
  import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
@@ -75,6 +76,8 @@ const CopilotChatDefaultLabels = {
75
76
  chatInputToolbarFinishTranscribeButtonLabel: "Finish",
76
77
  chatInputToolbarAddButtonLabel: "Add attachments",
77
78
  chatInputToolbarToolsButtonLabel: "Tools",
79
+ chatInputToolbarSendButtonLabel: "Send message",
80
+ chatInputToolbarStopButtonLabel: "Stop",
78
81
  assistantMessageToolbarCopyCodeLabel: "Copy",
79
82
  assistantMessageToolbarCopyCodeCopiedLabel: "Copied",
80
83
  assistantMessageToolbarCopyMessageLabel: "Copy",
@@ -87,13 +90,18 @@ const CopilotChatDefaultLabels = {
87
90
  assistantMessageToolbarInspectorHideDescription: "Until you reload this page",
88
91
  assistantMessageToolbarThumbsUpLabel: "Good response",
89
92
  assistantMessageToolbarThumbsDownLabel: "Bad response",
93
+ assistantMessageFeedbackCommentPlaceholder: "Add a comment (optional)",
94
+ assistantMessageFeedbackCommentSubmitLabel: "Send comment",
90
95
  assistantMessageToolbarReadAloudLabel: "Read aloud",
91
96
  assistantMessageToolbarRegenerateLabel: "Regenerate",
92
97
  userMessageToolbarCopyMessageLabel: "Copy",
93
98
  userMessageToolbarEditMessageLabel: "Edit",
99
+ userMessageToolbarPreviousBranchLabel: "Previous branch",
100
+ userMessageToolbarNextBranchLabel: "Next branch",
94
101
  chatDisclaimerText: "AI can make mistakes. Please verify important information.",
95
102
  chatToggleOpenLabel: "Open chat",
96
103
  chatToggleCloseLabel: "Close chat",
104
+ chatScrollToBottomLabel: "Scroll to bottom",
97
105
  modalHeaderTitle: "CopilotKit Chat",
98
106
  welcomeMessageText: "How can I help you today?"
99
107
  };
@@ -805,6 +813,11 @@ function renderSlot(slot, DefaultComponent, props) {
805
813
  //#region src/v2/components/chat/CopilotChatInput.tsx
806
814
  const SLASH_MENU_MAX_VISIBLE_ITEMS = 5;
807
815
  const SLASH_MENU_ITEM_HEIGHT_PX = 40;
816
+ /**
817
+ * The chat composer: a text area with the add-menu, voice and send/stop
818
+ * buttons, and a slash-command menu that lists `toolsMenu` items once the text
819
+ * starts with "/".
820
+ */
808
821
  function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning = false, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, onAddFile, onChange, value, toolsMenu, autoFocus = false, positioning = "static", keyboardHeight = 0, containerRef, showDisclaimer, bottomAnchored = false, textArea, sendButton, startTranscribeButton, cancelTranscribeButton, finishTranscribeButton, addMenuButton, audioRecorder, disclaimer, children, className, ...props }) {
809
822
  const isControlled = value !== void 0;
810
823
  const [internalValue, setInternalValue] = useState(() => value ?? "");
@@ -1024,10 +1037,12 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
1024
1037
  send();
1025
1038
  };
1026
1039
  const BoundAudioRecorder = renderSlot(audioRecorder, CopilotChatAudioRecorder, { ref: audioRecorderRef });
1040
+ const showsStop = isProcessing && canStop;
1027
1041
  const BoundSendButton = renderSlot(sendButton, CopilotChatInput.SendButton, {
1028
1042
  onClick: handleSendButtonClick,
1029
1043
  disabled: isProcessing ? !canStop : !canSend,
1030
- children: isProcessing && canStop ? /* @__PURE__ */ jsx(Square, { className: "cpk:size-[18px] cpk:fill-current" }) : void 0
1044
+ "aria-label": showsStop ? labels.chatInputToolbarStopButtonLabel : labels.chatInputToolbarSendButtonLabel,
1045
+ children: showsStop ? /* @__PURE__ */ jsx(Square, { className: "cpk:size-[18px] cpk:fill-current" }) : void 0
1031
1046
  });
1032
1047
  const BoundStartTranscribeButton = renderSlot(startTranscribeButton, CopilotChatInput.StartTranscribeButton, { onClick: onStartTranscribe });
1033
1048
  const BoundCancelTranscribeButton = renderSlot(cancelTranscribeButton, CopilotChatInput.CancelTranscribeButton, { onClick: onCancelTranscribe });
@@ -1339,18 +1354,22 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
1339
1354
  });
1340
1355
  }
1341
1356
  (function(_CopilotChatInput) {
1342
- _CopilotChatInput.SendButton = ({ className, children, ...props }) => /* @__PURE__ */ jsx("div", {
1343
- className: "cpk:mr-[10px]",
1344
- children: /* @__PURE__ */ jsx(Button, {
1345
- type: "button",
1346
- "data-testid": "copilot-send-button",
1347
- variant: "chatInputToolbarPrimary",
1348
- size: "chatInputToolbarIcon",
1349
- className,
1350
- ...props,
1351
- children: children ?? /* @__PURE__ */ jsx(ArrowUp, { className: "cpk:size-[18px]" })
1352
- })
1353
- });
1357
+ _CopilotChatInput.SendButton = ({ className, children, ...props }) => {
1358
+ const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
1359
+ return /* @__PURE__ */ jsx("div", {
1360
+ className: "cpk:mr-[10px]",
1361
+ children: /* @__PURE__ */ jsx(Button, {
1362
+ type: "button",
1363
+ "data-testid": "copilot-send-button",
1364
+ variant: "chatInputToolbarPrimary",
1365
+ size: "chatInputToolbarIcon",
1366
+ className,
1367
+ "aria-label": labels.chatInputToolbarSendButtonLabel,
1368
+ ...props,
1369
+ children: children ?? /* @__PURE__ */ jsx(ArrowUp, { className: "cpk:size-[18px]" })
1370
+ })
1371
+ });
1372
+ };
1354
1373
  const ToolbarButton = _CopilotChatInput.ToolbarButton = ({ icon, labelKey, defaultClassName, className, ...props }) => {
1355
1374
  const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
1356
1375
  return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
@@ -1360,6 +1379,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
1360
1379
  variant: "chatInputToolbarSecondary",
1361
1380
  size: "chatInputToolbarIcon",
1362
1381
  className: twMerge(defaultClassName, className),
1382
+ "aria-label": labels[labelKey],
1363
1383
  ...props,
1364
1384
  children: icon
1365
1385
  })
@@ -1430,6 +1450,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
1430
1450
  size: "chatInputToolbarIcon",
1431
1451
  className: twMerge("cpk:ml-1", className),
1432
1452
  disabled: isDisabled,
1453
+ "aria-label": labels.chatInputToolbarAddButtonLabel,
1433
1454
  ...props,
1434
1455
  children: /* @__PURE__ */ jsx(Plus, { className: "cpk:size-[20px]" })
1435
1456
  });
@@ -1579,6 +1600,32 @@ function warnAboutUnrenderedToolCalls(toolNames, registered, alreadyWarned) {
1579
1600
  }
1580
1601
  }
1581
1602
  /**
1603
+ * The tool-call renderers registered on the provider, kept current.
1604
+ * @internal
1605
+ */
1606
+ function useToolCallRenderers() {
1607
+ const { copilotkit } = useCopilotKit();
1608
+ return useSyncExternalStore((callback) => copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
1609
+ }
1610
+ /**
1611
+ * Which tool names have a renderer of their own, whether a wildcard (`"*"`)
1612
+ * renderer is registered, and which of them opted into grouping.
1613
+ * @internal
1614
+ */
1615
+ function useToolCallRendererNames() {
1616
+ const renderers = useToolCallRenderers();
1617
+ return useMemo(() => {
1618
+ const named = renderers.filter((rc) => rc.name !== "*");
1619
+ const wildcards = renderers.filter((rc) => rc.name === "*");
1620
+ return {
1621
+ named: new Set(named.map((rc) => rc.name)),
1622
+ groupedNames: new Set(named.filter((rc) => rc.group).map((rc) => rc.name)),
1623
+ wildcard: wildcards.length > 0,
1624
+ wildcardGroups: wildcards.some((rc) => rc.group)
1625
+ };
1626
+ }, [renderers]);
1627
+ }
1628
+ /**
1582
1629
  * Hook that returns a function to render tool calls based on the render functions
1583
1630
  * defined in CopilotKitProvider.
1584
1631
  *
@@ -1589,9 +1636,7 @@ function useRenderToolCall() {
1589
1636
  const agentId = useCopilotChatConfiguration()?.agentId ?? DEFAULT_AGENT_ID;
1590
1637
  const unrenderedToolNames = useRef(/* @__PURE__ */ new Set());
1591
1638
  const warnedToolNames = useRef(/* @__PURE__ */ new Set());
1592
- const renderToolCalls = useSyncExternalStore((callback) => {
1593
- return copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe;
1594
- }, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
1639
+ const renderToolCalls = useToolCallRenderers();
1595
1640
  const renderToolCall = useCallback(({ toolCall, toolMessage }) => {
1596
1641
  const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
1597
1642
  const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*");
@@ -1626,7 +1671,7 @@ function useRenderToolCall() {
1626
1671
 
1627
1672
  //#endregion
1628
1673
  //#region package.json
1629
- var version = "1.79.2-canary.1792172552";
1674
+ var version = "1.80.0";
1630
1675
 
1631
1676
  //#endregion
1632
1677
  //#region src/v2/components/CopilotKitInspector.tsx
@@ -1862,7 +1907,7 @@ function InlineFeatureWarning({ featureName }) {
1862
1907
  * Fetches resource content on-demand via proxied MCP requests. The React shell
1863
1908
  * owns the iframe; `bindMcpApp` owns the protocol.
1864
1909
  */
1865
- const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, message, agent }) {
1910
+ const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, message, agent, allowSameOriginFallback }) {
1866
1911
  const { copilotkit } = useCopilotKit$1();
1867
1912
  const messageId = message?.id;
1868
1913
  const containerRef = useRef(null);
@@ -1912,6 +1957,7 @@ const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, mess
1912
1957
  getAgent: () => agentRef.current,
1913
1958
  host: copilotkit,
1914
1959
  messageId,
1960
+ options: { allowSameOriginFallback },
1915
1961
  hooks: {
1916
1962
  onResource: (resource) => {
1917
1963
  if (!mounted) return;
@@ -1953,6 +1999,7 @@ const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, mess
1953
1999
  agent,
1954
2000
  copilotkit,
1955
2001
  messageId,
2002
+ allowSameOriginFallback,
1956
2003
  content.resourceUri,
1957
2004
  content.serverHash,
1958
2005
  content.serverId
@@ -3167,7 +3214,8 @@ function defineToolCallRenderer(def) {
3167
3214
  name: def.name,
3168
3215
  args: argsSchema,
3169
3216
  render: def.render,
3170
- ...def.agentId ? { agentId: def.agentId } : {}
3217
+ ...def.agentId ? { agentId: def.agentId } : {},
3218
+ ...def.group ? { group: true } : {}
3171
3219
  };
3172
3220
  }
3173
3221
 
@@ -3383,6 +3431,11 @@ const DEFAULT_DESIGN_SKILL = `When generating UI with generateSandboxedUi, follo
3383
3431
  - Use CSS Grid or Flexbox for layout. Ensure the UI looks good at any width.
3384
3432
  - Minimal transitions (150ms) for hover/focus states only. No decorative animations.
3385
3433
  - Keep the UI focused and dense — avoid excessive padding. Use compact spacing (8–12px gaps, 10–14px padding in controls).`;
3434
+ /** The MCP Apps renderer with `mcpApps.allowSameOriginFallback` applied. */
3435
+ const SameOriginMCPAppsActivityRenderer = (props) => /* @__PURE__ */ jsx(MCPAppsActivityRenderer, {
3436
+ ...props,
3437
+ allowSameOriginFallback: true
3438
+ });
3386
3439
  const DEFAULT_LEARNING = Object.freeze({});
3387
3440
  function toLearningConfig(learning) {
3388
3441
  if (learning === true) return DEFAULT_LEARNING;
@@ -3399,7 +3452,8 @@ function useStableArrayProp(prop, warningMessage, isMeaningfulChange) {
3399
3452
  }, [value, warningMessage]);
3400
3453
  return value;
3401
3454
  }
3402
- const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY_HEADERS, credentials, messageFilter, publicApiKey, publicLicenseKey, licenseToken, properties = EMPTY_PROPERTIES, agents__unsafe_dev_only: agents = EMPTY_AGENTS, selfManagedAgents = EMPTY_AGENTS, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, openGenerativeUI, enableInspector, agentId, showIntelligenceIndicator = true, useSingleEndpoint, onError, a2ui, defaultThrottleMs, debug, learning }) => {
3455
+ /** Provide a shared core instance and synchronize runtime, tool, and UI configuration. */
3456
+ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY_HEADERS, credentials, messageFilter, publicApiKey, publicLicenseKey, licenseToken, properties = EMPTY_PROPERTIES, agents__unsafe_dev_only: agents = EMPTY_AGENTS, selfManagedAgents = EMPTY_AGENTS, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, openGenerativeUI, enableInspector, agentId, showIntelligenceIndicator = true, useSingleEndpoint, onError, a2ui, mcpApps, defaultThrottleMs, debug, learning }) => {
3403
3457
  const learningConfig = useMemo(() => toLearningConfig(learning), [learning]);
3404
3458
  const [shouldRenderInspector, setShouldRenderInspector] = useState(false);
3405
3459
  const [inspectorVisible, setInspectorVisible] = useState(false);
@@ -3456,11 +3510,12 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
3456
3510
  const core = copilotkitRef.current;
3457
3511
  return filterCatalog(rawCatalog, (name) => core ? core.isCatalogComponentEnabled(name) : true);
3458
3512
  }, [rawCatalog, catalogToggleVersion]);
3513
+ const mcpAppsAllowSameOrigin = mcpApps?.allowSameOriginFallback === true;
3459
3514
  const builtInActivityRenderers = useMemo(() => {
3460
3515
  const renderers = [{
3461
3516
  activityType: MCPAppsActivityType,
3462
3517
  content: MCPAppsActivityContentSchema,
3463
- render: MCPAppsActivityRenderer
3518
+ render: mcpAppsAllowSameOrigin ? SameOriginMCPAppsActivityRenderer : MCPAppsActivityRenderer
3464
3519
  }];
3465
3520
  if (openGenUIActive) renderers.push({
3466
3521
  activityType: OpenGenerativeUIActivityType,
@@ -3478,7 +3533,8 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
3478
3533
  a2uiActive,
3479
3534
  openGenUIActive,
3480
3535
  a2ui,
3481
- filteredCatalog
3536
+ filteredCatalog,
3537
+ mcpAppsAllowSameOrigin
3482
3538
  ]);
3483
3539
  const allActivityRenderers = useMemo(() => {
3484
3540
  return [...renderActivityMessagesList, ...builtInActivityRenderers];
@@ -3586,6 +3642,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
3586
3642
  description: GENERATE_SANDBOXED_UI_DESCRIPTION,
3587
3643
  parameters: GenerateSandboxedUiArgsSchema,
3588
3644
  handler: async () => "UI generated",
3645
+ reconnectBehavior: "resume-pending",
3589
3646
  followUp: true,
3590
3647
  render: OpenGenerativeUIToolRenderer
3591
3648
  }];
@@ -4317,7 +4374,8 @@ function useRenderTool(config, deps) {
4317
4374
  ...props,
4318
4375
  parameters: props.args
4319
4376
  }),
4320
- ...config.agentId ? { agentId: config.agentId } : {}
4377
+ ...config.agentId ? { agentId: config.agentId } : {},
4378
+ group: config.group
4321
4379
  }) : defineToolCallRenderer({
4322
4380
  name: config.name,
4323
4381
  args: config.parameters,
@@ -4335,16 +4393,395 @@ function useRenderTool(config, deps) {
4335
4393
  parameters: props.args
4336
4394
  });
4337
4395
  },
4338
- ...config.agentId ? { agentId: config.agentId } : {}
4396
+ ...config.agentId ? { agentId: config.agentId } : {},
4397
+ group: config.group
4339
4398
  });
4340
4399
  copilotkit.addHookRenderToolCall(renderer);
4341
4400
  }, [
4342
4401
  config.name,
4402
+ config.group,
4343
4403
  copilotkit,
4344
4404
  depsVersion
4345
4405
  ]);
4346
4406
  }
4347
4407
 
4408
+ //#endregion
4409
+ //#region src/v2/components/chat/CopilotChatToolCallGroup.tsx
4410
+ /**
4411
+ * Set by a group around the calls it shows, so CopilotKit's built-in tool card
4412
+ * draws itself as a compact row that fits the group instead of a card.
4413
+ * @internal
4414
+ */
4415
+ const ToolCallGroupContext = createContext(null);
4416
+ /**
4417
+ * A call without a result is running only while the group is active: once
4418
+ * the run has moved on or ended, its result is never coming.
4419
+ */
4420
+ const entryStatus = ({ toolMessage }, active) => toolMessage ? toolMessage.error ? "failed" : "done" : active ? "running" : "stopped";
4421
+ /** @internal */
4422
+ const statusLabels = {
4423
+ running: "Running",
4424
+ done: "Done",
4425
+ failed: "Failed",
4426
+ stopped: "Stopped"
4427
+ };
4428
+ /** The first non-empty string argument: usually a command, path or query. */
4429
+ function argumentPreview(parameters) {
4430
+ if (!parameters || typeof parameters !== "object") return void 0;
4431
+ return Object.values(parameters).find((v) => typeof v === "string" && v.trim().length > 0)?.replace(/\s+/g, " ");
4432
+ }
4433
+ const entryPreview = (entry) => argumentPreview(partialJSONParse(entry.toolCall.function.arguments));
4434
+ /** "run_command ×2, read_file" */
4435
+ function toolNames(calls) {
4436
+ const counts = /* @__PURE__ */ new Map();
4437
+ for (const { toolCall } of calls) {
4438
+ const name = toolCall.function.name;
4439
+ counts.set(name, (counts.get(name) ?? 0) + 1);
4440
+ }
4441
+ return [...counts].map(([name, count]) => count > 1 ? `${name} ×${count}` : name).join(", ");
4442
+ }
4443
+ const pluralize = (count, noun) => `${count} ${noun}${count === 1 ? "" : "s"}`;
4444
+ /**
4445
+ * Height transition between closed and its content's height. Closed content
4446
+ * stays mounted (so its state survives) but is inert.
4447
+ * @internal
4448
+ */
4449
+ function Collapsible({ open, id, className, children }) {
4450
+ const ref = useRef(null);
4451
+ useLayoutEffect(() => {
4452
+ ref.current?.toggleAttribute("inert", !open);
4453
+ }, [open]);
4454
+ return /* @__PURE__ */ jsx("div", {
4455
+ ref,
4456
+ id,
4457
+ className: twMerge("cpk:grid cpk:transition-[grid-template-rows] cpk:duration-300 cpk:ease-[cubic-bezier(0.16,1,0.3,1)] cpk:motion-reduce:transition-none", className),
4458
+ style: { gridTemplateRows: open ? "1fr" : "0fr" },
4459
+ children: /* @__PURE__ */ jsx("div", {
4460
+ className: "cpk:min-h-0 cpk:overflow-hidden",
4461
+ children
4462
+ })
4463
+ });
4464
+ }
4465
+ function StatusIcon({ status, className }) {
4466
+ const Icon = {
4467
+ running: Loader2,
4468
+ done: Check,
4469
+ failed: X,
4470
+ stopped: Circle
4471
+ }[status];
4472
+ return /* @__PURE__ */ jsx(Icon, {
4473
+ "aria-hidden": "true",
4474
+ className: twMerge("cpk:size-3.5 cpk:shrink-0 cpk:text-muted-foreground", status === "running" && "cpk:animate-spin", status === "failed" && "cpk:text-destructive", className)
4475
+ });
4476
+ }
4477
+ function Chevron({ open, className }) {
4478
+ return /* @__PURE__ */ jsx(ChevronRight, {
4479
+ "aria-hidden": "true",
4480
+ className: twMerge("cpk:size-3.5 cpk:shrink-0 cpk:transition-transform cpk:duration-200", open && "cpk:rotate-90", className)
4481
+ });
4482
+ }
4483
+ function FailedCount({ calls }) {
4484
+ const failed = calls.filter((call) => call.toolMessage?.error).length;
4485
+ if (!failed) return null;
4486
+ return /* @__PURE__ */ jsxs("span", {
4487
+ className: "cpk:shrink-0 cpk:text-destructive",
4488
+ children: [failed, " failed"]
4489
+ });
4490
+ }
4491
+ /**
4492
+ * Guarded JSON.stringify for the payload blocks. A circular reference would
4493
+ * otherwise crash the entire React tree on render.
4494
+ */
4495
+ function stringifyPayload(value) {
4496
+ if (typeof value === "string") return value;
4497
+ try {
4498
+ return JSON.stringify(value, null, 2);
4499
+ } catch (err) {
4500
+ console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload; falling back to String():", err);
4501
+ try {
4502
+ return String(value);
4503
+ } catch {
4504
+ return "[unserializable]";
4505
+ }
4506
+ }
4507
+ }
4508
+ function Payload({ label, value }) {
4509
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
4510
+ className: "cpk:text-[11px] cpk:font-medium cpk:uppercase cpk:tracking-wide cpk:text-muted-foreground",
4511
+ children: label
4512
+ }), /* @__PURE__ */ jsx("pre", {
4513
+ className: "cpk:m-0 cpk:mt-1.5 cpk:max-h-[200px] cpk:overflow-auto cpk:rounded-lg cpk:bg-muted cpk:p-2.5 cpk:font-mono cpk:text-xs cpk:leading-relaxed cpk:text-foreground cpk:whitespace-pre-wrap cpk:break-words",
4514
+ children: stringifyPayload(value)
4515
+ })] });
4516
+ }
4517
+ /**
4518
+ * A tool call's arguments and, once it has one, its result.
4519
+ * @internal
4520
+ */
4521
+ function ToolCallPayloads({ parameters, result, className }) {
4522
+ return /* @__PURE__ */ jsxs("div", {
4523
+ className: twMerge("cpk:grid cpk:gap-3", className),
4524
+ children: [/* @__PURE__ */ jsx(Payload, {
4525
+ label: "Arguments",
4526
+ value: parameters ?? {}
4527
+ }), result !== void 0 && /* @__PURE__ */ jsx(Payload, {
4528
+ label: "Result",
4529
+ value: result
4530
+ })]
4531
+ });
4532
+ }
4533
+ /**
4534
+ * The built-in tool card drawn as a row inside a group: status, name and main
4535
+ * argument, opening to the payloads.
4536
+ * @internal
4537
+ */
4538
+ function ToolCallRow({ name, parameters, result, status, appearance, className, ...props }) {
4539
+ const [open, setOpen] = useState(false);
4540
+ const detailsId = useId();
4541
+ const preview = argumentPreview(parameters);
4542
+ const line = appearance === "line";
4543
+ return /* @__PURE__ */ jsxs("div", {
4544
+ "data-copilotkit": true,
4545
+ className: twMerge(!line && "cpk:border-t cpk:border-border", className),
4546
+ ...props,
4547
+ children: [/* @__PURE__ */ jsxs("button", {
4548
+ type: "button",
4549
+ "aria-expanded": open,
4550
+ "aria-controls": detailsId,
4551
+ onClick: () => setOpen((value) => !value),
4552
+ className: twMerge("cpk:group/row cpk:m-0 cpk:flex cpk:min-w-0 cpk:cursor-pointer cpk:items-center cpk:gap-2 cpk:border-none cpk:bg-transparent cpk:text-left cpk:text-[13px] cpk:text-inherit cpk:transition-colors cpk:hover:bg-accent/60 cpk:focus-visible:outline-2 cpk:focus-visible:-outline-offset-2 cpk:focus-visible:outline-ring", line ? "cpk:-mx-1.5 cpk:w-[calc(100%+0.75rem)] cpk:rounded-md cpk:px-1.5 cpk:py-1" : "cpk:w-full cpk:px-3.5 cpk:py-2"),
4553
+ children: [
4554
+ /* @__PURE__ */ jsx(StatusIcon, { status }),
4555
+ /* @__PURE__ */ jsx("span", {
4556
+ "data-testid": "copilot-tool-render-name",
4557
+ className: twMerge("cpk:shrink-0 cpk:font-mono cpk:text-[13px] cpk:font-medium cpk:text-foreground", status === "running" && "cpk-shimmer"),
4558
+ children: name
4559
+ }),
4560
+ preview && /* @__PURE__ */ jsx("span", {
4561
+ className: "cpk:min-w-0 cpk:truncate cpk:font-mono cpk:text-[13px] cpk:text-muted-foreground",
4562
+ children: preview
4563
+ }),
4564
+ /* @__PURE__ */ jsx("span", {
4565
+ "data-testid": "copilot-tool-render-status",
4566
+ className: "cpk:sr-only",
4567
+ children: statusLabels[status]
4568
+ }),
4569
+ /* @__PURE__ */ jsx(Chevron, {
4570
+ open,
4571
+ className: twMerge("cpk:ml-auto cpk:text-muted-foreground", !open && "cpk:opacity-0 cpk:group-hover/row:opacity-100 cpk:group-focus-visible/row:opacity-100")
4572
+ })
4573
+ ]
4574
+ }), /* @__PURE__ */ jsx(Collapsible, {
4575
+ open,
4576
+ id: detailsId,
4577
+ children: /* @__PURE__ */ jsx(ToolCallPayloads, {
4578
+ parameters,
4579
+ result,
4580
+ className: line ? "cpk:mt-1 cpk:mb-2 cpk:ml-5.5" : "cpk:px-3.5 cpk:pt-1 cpk:pb-3"
4581
+ })
4582
+ })]
4583
+ });
4584
+ }
4585
+ /**
4586
+ * Tool calls made in a row, collapsed into one summary. While a call runs the
4587
+ * summary names it ("Running read_file src/app.ts"); once they're all done it
4588
+ * reads "Used 3 tools" and opens to the calls.
4589
+ *
4590
+ * Each call is drawn by its registered renderer. CopilotKit's built-in card
4591
+ * (`useDefaultRenderTool`) draws a compact row inside the card and line
4592
+ * appearances; a custom wildcard renderer draws whatever it draws.
4593
+ */
4594
+ function CopilotChatToolCallGroup({ calls, renderCall, appearance = "card", isActive = false, className, ...props }) {
4595
+ const [open, setOpen] = useState(false);
4596
+ const bodyId = useId();
4597
+ const latest = calls[calls.length - 1];
4598
+ if (!latest) return null;
4599
+ const current = isActive ? calls.find((call) => !call.toolMessage) ?? latest : void 0;
4600
+ const preview = current ? entryPreview(current) : void 0;
4601
+ const done = calls.filter((call) => call.toolMessage).length;
4602
+ const statuses = calls.map((call) => entryStatus(call, isActive));
4603
+ const failedIds = new Set(calls.filter((_, index) => statuses[index] === "failed").map((call) => call.toolCall.id));
4604
+ const status = current ? "running" : failedIds.size > 0 ? "failed" : statuses.includes("stopped") ? "stopped" : "done";
4605
+ const rows = (rowAppearance) => /* @__PURE__ */ jsx(ToolCallGroupContext.Provider, {
4606
+ value: {
4607
+ appearance: rowAppearance,
4608
+ failedIds,
4609
+ active: isActive
4610
+ },
4611
+ children: calls.map((call) => /* @__PURE__ */ jsx(React.Fragment, { children: renderCall(call) }, call.toolCall.id))
4612
+ });
4613
+ const groupProps = {
4614
+ "data-copilotkit": true,
4615
+ "data-testid": "copilot-tool-call-group",
4616
+ "data-appearance": appearance,
4617
+ "data-state": status,
4618
+ ...props
4619
+ };
4620
+ const runningLabel = current && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
4621
+ className: "cpk:shrink-0 cpk:font-medium cpk-shimmer",
4622
+ children: ["Running ", current.toolCall.function.name]
4623
+ }), preview && /* @__PURE__ */ jsx("span", {
4624
+ className: "cpk:min-w-0 cpk:truncate cpk:font-mono cpk:text-xs cpk:opacity-70",
4625
+ children: preview
4626
+ })] });
4627
+ if (appearance === "line") {
4628
+ if (calls.length === 1 && !current) return /* @__PURE__ */ jsx("div", {
4629
+ ...groupProps,
4630
+ className: twMerge("cpk:my-2", className),
4631
+ children: /* @__PURE__ */ jsx(ToolCallGroupContext.Provider, {
4632
+ value: {
4633
+ appearance: "line",
4634
+ failedIds,
4635
+ active: isActive
4636
+ },
4637
+ children: renderCall(latest)
4638
+ })
4639
+ });
4640
+ return /* @__PURE__ */ jsxs("div", {
4641
+ ...groupProps,
4642
+ className: twMerge("cpk:my-3", className),
4643
+ children: [/* @__PURE__ */ jsxs("button", {
4644
+ type: "button",
4645
+ "aria-expanded": open,
4646
+ "aria-controls": bodyId,
4647
+ onClick: () => setOpen((value) => !value),
4648
+ className: "cpk:m-0 cpk:inline-flex cpk:max-w-full cpk:min-w-0 cpk:cursor-pointer cpk:items-center cpk:gap-1.5 cpk:rounded-md cpk:border-none cpk:bg-transparent cpk:p-0 cpk:py-0.5 cpk:text-sm cpk:text-muted-foreground cpk:transition-colors cpk:hover:text-foreground cpk:focus-visible:outline-2 cpk:focus-visible:outline-ring",
4649
+ children: [runningLabel || /* @__PURE__ */ jsxs(Fragment$1, { children: [
4650
+ /* @__PURE__ */ jsxs("span", {
4651
+ className: "cpk:shrink-0 cpk:font-medium",
4652
+ children: ["Used ", pluralize(calls.length, "tool")]
4653
+ }),
4654
+ /* @__PURE__ */ jsx("span", {
4655
+ className: "cpk:min-w-0 cpk:truncate cpk:font-mono cpk:text-xs cpk:opacity-70",
4656
+ children: toolNames(calls)
4657
+ }),
4658
+ /* @__PURE__ */ jsx(FailedCount, { calls })
4659
+ ] }), /* @__PURE__ */ jsx(Chevron, { open })]
4660
+ }), /* @__PURE__ */ jsx(Collapsible, {
4661
+ open,
4662
+ id: bodyId,
4663
+ children: /* @__PURE__ */ jsx("div", {
4664
+ className: "cpk:mt-1 cpk:ml-1 cpk:border-l-2 cpk:border-border cpk:py-0.5 cpk:pl-3",
4665
+ children: rows("line")
4666
+ })
4667
+ })]
4668
+ });
4669
+ }
4670
+ if (appearance === "stack") {
4671
+ if (calls.length === 1) return /* @__PURE__ */ jsx("div", {
4672
+ ...groupProps,
4673
+ className: twMerge("cpk:py-1", className),
4674
+ children: renderCall(latest)
4675
+ });
4676
+ const behind = open ? 0 : Math.min(calls.length - 1, 2);
4677
+ const layer = "cpk:rounded-xl cpk:border cpk:border-border cpk:bg-card cpk:text-card-foreground";
4678
+ const latestStatus = entryStatus(latest, isActive);
4679
+ const latestPreview = entryPreview(latest);
4680
+ return /* @__PURE__ */ jsxs("div", {
4681
+ ...groupProps,
4682
+ className: twMerge("cpk:my-3", className),
4683
+ style: {
4684
+ paddingBottom: behind * 6,
4685
+ ...props.style
4686
+ },
4687
+ children: [/* @__PURE__ */ jsxs("div", {
4688
+ className: "cpk:relative cpk:isolate",
4689
+ children: [Array.from({ length: behind }, (_, index) => /* @__PURE__ */ jsx("div", {
4690
+ "aria-hidden": "true",
4691
+ className: twMerge(layer, "cpk:absolute cpk:inset-0"),
4692
+ style: {
4693
+ transform: `translateY(${(index + 1) * 6}px) scaleX(${1 - (index + 1) * .045})`,
4694
+ zIndex: -1 - index,
4695
+ opacity: 1 - (index + 1) * .28
4696
+ }
4697
+ }, index)), /* @__PURE__ */ jsx("button", {
4698
+ type: "button",
4699
+ "aria-expanded": open,
4700
+ "aria-controls": open ? bodyId : void 0,
4701
+ onClick: () => setOpen((value) => !value),
4702
+ className: twMerge("cpk:relative cpk:m-0 cpk:flex cpk:min-w-0 cpk:cursor-pointer cpk:items-center cpk:text-left cpk:transition-colors cpk:focus-visible:outline-2 cpk:focus-visible:outline-ring", open ? "cpk:mb-1 cpk:gap-1.5 cpk:rounded-md cpk:border-none cpk:bg-transparent cpk:p-0 cpk:py-0.5 cpk:text-xs cpk:text-muted-foreground cpk:hover:text-foreground" : twMerge(layer, "cpk:w-full cpk:gap-2 cpk:px-3.5 cpk:py-2.5 cpk:text-[13px] cpk:shadow-[0_1px_2px_rgb(0_0_0/0.04)] cpk:hover:bg-accent")),
4703
+ children: open ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
4704
+ pluralize(calls.length, "tool call"),
4705
+ /* @__PURE__ */ jsx(FailedCount, { calls }),
4706
+ /* @__PURE__ */ jsx(Chevron, {
4707
+ open: true,
4708
+ className: "cpk:-rotate-90"
4709
+ }),
4710
+ "Collapse"
4711
+ ] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
4712
+ className: "cpk:flex cpk:min-w-0 cpk:flex-1 cpk:items-center cpk:gap-2 cpk:animate-[cpk-stack-drop_260ms_cubic-bezier(0.16,1,0.3,1)] cpk:motion-reduce:animate-none",
4713
+ children: [
4714
+ /* @__PURE__ */ jsx(StatusIcon, { status: latestStatus }),
4715
+ /* @__PURE__ */ jsx("span", {
4716
+ className: twMerge("cpk:shrink-0 cpk:font-mono cpk:font-medium cpk:text-foreground", latestStatus === "running" && "cpk-shimmer"),
4717
+ children: latest.toolCall.function.name
4718
+ }),
4719
+ latestPreview && /* @__PURE__ */ jsx("span", {
4720
+ className: "cpk:min-w-0 cpk:truncate cpk:font-mono cpk:text-muted-foreground",
4721
+ children: latestPreview
4722
+ })
4723
+ ]
4724
+ }, latest.toolCall.id), /* @__PURE__ */ jsxs("span", {
4725
+ className: "cpk:ml-2 cpk:inline-flex cpk:shrink-0 cpk:items-center cpk:gap-2 cpk:text-xs cpk:text-muted-foreground",
4726
+ children: [
4727
+ /* @__PURE__ */ jsx(FailedCount, { calls }),
4728
+ /* @__PURE__ */ jsx("span", {
4729
+ className: "cpk:tabular-nums",
4730
+ children: pluralize(calls.length, "call")
4731
+ }),
4732
+ /* @__PURE__ */ jsx(Chevron, {
4733
+ open: false,
4734
+ className: "cpk:rotate-90"
4735
+ })
4736
+ ]
4737
+ })] })
4738
+ })]
4739
+ }), open && /* @__PURE__ */ jsx("div", {
4740
+ id: bodyId,
4741
+ className: "cpk:[&>*]:animate-[cpk-stack-fan_300ms_cubic-bezier(0.16,1,0.3,1)_both] cpk:motion-reduce:[&>*]:animate-none",
4742
+ children: calls.map((call) => /* @__PURE__ */ jsx(React.Fragment, { children: renderCall(call) }, call.toolCall.id))
4743
+ })]
4744
+ });
4745
+ }
4746
+ if (calls.length === 1) return /* @__PURE__ */ jsx("div", {
4747
+ ...groupProps,
4748
+ className: twMerge("cpk:py-1", className),
4749
+ children: renderCall(latest)
4750
+ });
4751
+ return /* @__PURE__ */ jsxs("div", {
4752
+ ...groupProps,
4753
+ className: twMerge("cpk:my-3 cpk:overflow-hidden cpk:rounded-xl cpk:border cpk:border-border cpk:bg-card cpk:text-card-foreground", className),
4754
+ children: [/* @__PURE__ */ jsxs("button", {
4755
+ type: "button",
4756
+ "aria-expanded": open,
4757
+ "aria-controls": bodyId,
4758
+ onClick: () => setOpen((value) => !value),
4759
+ className: "cpk:m-0 cpk:flex cpk:w-full cpk:min-w-0 cpk:cursor-pointer cpk:items-center cpk:gap-2.5 cpk:border-none cpk:bg-transparent cpk:px-3.5 cpk:py-2.5 cpk:text-left cpk:text-[13px] cpk:text-inherit cpk:transition-colors cpk:hover:bg-accent/60 cpk:focus-visible:outline-2 cpk:focus-visible:-outline-offset-2 cpk:focus-visible:outline-ring",
4760
+ children: [
4761
+ /* @__PURE__ */ jsx(StatusIcon, { status }),
4762
+ runningLabel || /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
4763
+ className: "cpk:shrink-0 cpk:font-medium cpk:text-foreground",
4764
+ children: ["Used ", pluralize(calls.length, "tool")]
4765
+ }), /* @__PURE__ */ jsx("span", {
4766
+ className: "cpk:min-w-0 cpk:truncate cpk:font-mono cpk:text-xs cpk:text-muted-foreground",
4767
+ children: toolNames(calls)
4768
+ })] }),
4769
+ /* @__PURE__ */ jsxs("span", {
4770
+ className: "cpk:ml-auto cpk:flex cpk:shrink-0 cpk:items-center cpk:gap-2 cpk:pl-2 cpk:text-xs cpk:text-muted-foreground",
4771
+ children: [status === "failed" ? /* @__PURE__ */ jsx(FailedCount, { calls }) : /* @__PURE__ */ jsx("span", {
4772
+ className: "cpk:tabular-nums",
4773
+ children: status === "running" ? `${done} done` : statusLabels[status]
4774
+ }), /* @__PURE__ */ jsx(Chevron, { open })]
4775
+ })
4776
+ ]
4777
+ }), /* @__PURE__ */ jsx(Collapsible, {
4778
+ open,
4779
+ id: bodyId,
4780
+ children: /* @__PURE__ */ jsx("div", { children: rows("card") })
4781
+ })]
4782
+ });
4783
+ }
4784
+
4348
4785
  //#endregion
4349
4786
  //#region src/v2/hooks/use-default-render-tool.tsx
4350
4787
  /**
@@ -4428,7 +4865,8 @@ function useDefaultRenderTool(config, deps) {
4428
4865
  const userRender = config?.render;
4429
4866
  useRenderTool({
4430
4867
  name: "*",
4431
- render: userRender ? (raw) => userRender(adaptRendererProps(raw)) : (raw) => /* @__PURE__ */ jsx(DefaultToolCallRenderer, { ...adaptRendererProps(raw) })
4868
+ render: userRender ? (raw) => userRender(adaptRendererProps(raw)) : (raw) => /* @__PURE__ */ jsx(DefaultToolCallRenderer, { ...adaptRendererProps(raw) }),
4869
+ group: userRender ? config?.group === true : true
4432
4870
  }, deps);
4433
4871
  }
4434
4872
  /**
@@ -4449,9 +4887,23 @@ function safeStringifyForPre(value) {
4449
4887
  }
4450
4888
  }
4451
4889
  function DefaultToolCallRenderer({ name, toolCallId, parameters, status, result }) {
4890
+ const group = useContext(ToolCallGroupContext);
4452
4891
  const [isExpanded, setIsExpanded] = useState(false);
4453
4892
  const isActive = status === "inProgress" || status === "executing";
4454
4893
  const isComplete = status === "complete";
4894
+ if (group) return /* @__PURE__ */ jsx(ToolCallRow, {
4895
+ "data-testid": "copilot-tool-render",
4896
+ "data-tool-name": name,
4897
+ "data-tool-call-id": toolCallId,
4898
+ "data-status": status,
4899
+ "data-args": safeStringifyForAttr(parameters),
4900
+ "data-result": safeStringifyForAttr(result),
4901
+ name,
4902
+ parameters,
4903
+ result,
4904
+ status: isComplete ? group.failedIds.has(toolCallId) ? "failed" : "done" : group.active ? "running" : "stopped",
4905
+ appearance: group.appearance
4906
+ });
4455
4907
  const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
4456
4908
  const dotClassName = isActive ? "cpk:bg-amber-500" : isComplete ? "cpk:bg-emerald-500" : "cpk:bg-zinc-400";
4457
4909
  const badgeClassName = isActive ? "cpk:bg-amber-100 cpk:text-amber-800 cpk:dark:bg-amber-500/15 cpk:dark:text-amber-400" : isComplete ? "cpk:bg-emerald-100 cpk:text-emerald-800 cpk:dark:bg-emerald-500/15 cpk:dark:text-emerald-400" : "cpk:bg-zinc-100 cpk:text-zinc-800 cpk:dark:bg-zinc-700/40 cpk:dark:text-zinc-300";
@@ -6148,38 +6600,227 @@ function useLearningContainersInCurrentThread({ learningContainers }) {
6148
6600
  });
6149
6601
  }
6150
6602
 
6603
+ //#endregion
6604
+ //#region src/v2/components/chat/tool-call-display-context.ts
6605
+ /** @internal */
6606
+ const ToolCallDisplayContext = createContext(null);
6607
+
6608
+ //#endregion
6609
+ //#region src/v2/components/chat/tool-call-layout.ts
6610
+ function contentLength(content) {
6611
+ return typeof content === "string" ? content.length : JSON.stringify(content ?? "").length;
6612
+ }
6613
+ const entrySignature = ({ toolCall, toolMessage }) => [
6614
+ toolCall.id,
6615
+ toolCall.function.name,
6616
+ toolCall.function.arguments.length,
6617
+ toolMessage ? `${contentLength(toolMessage.content)}${toolMessage.error ? "!" : ""}` : "-"
6618
+ ].join(":");
6619
+ function signatureOf(segments) {
6620
+ return segments.map((segment) => segment.kind === "call" ? `c(${entrySignature(segment.call)})` : `g${segment.trailing ? "*" : ""}(${segment.calls.map(entrySignature).join(",")})`).join("|");
6621
+ }
6622
+ /** Index of tool results by the call they answer. */
6623
+ function getToolResults(messages) {
6624
+ const results = /* @__PURE__ */ new Map();
6625
+ for (const message of messages) if (message.role === "tool") results.set(message.toolCallId, message);
6626
+ return results;
6627
+ }
6628
+ /**
6629
+ * Lays out the tool calls of every assistant message in `rendered`.
6630
+ *
6631
+ * Calls drawn by a renderer that opted into grouping join the group that's
6632
+ * open; anything else that shows between them closes it: assistant text, a
6633
+ * user, reasoning or activity message, or a call drawn by any other renderer. A group belongs to
6634
+ * the message where it starts, so later messages whose calls joined it render
6635
+ * no tool calls themselves.
6636
+ *
6637
+ * @param rendered - The messages as the chat renders them, in order.
6638
+ * @param all - Every message, for finding tool results (a transform may hide them).
6639
+ * @param renderers - The registered renderers.
6640
+ */
6641
+ function getToolCallLayouts(rendered, all, renderers) {
6642
+ const results = getToolResults(all);
6643
+ const layouts = /* @__PURE__ */ new Map();
6644
+ let open;
6645
+ for (const message of rendered) {
6646
+ if (message.role === "tool") continue;
6647
+ if (message.role !== "assistant") {
6648
+ open = void 0;
6649
+ continue;
6650
+ }
6651
+ if (typeof message.content === "string" && message.content.trim()) open = void 0;
6652
+ const segments = [];
6653
+ layouts.set(message.id, segments);
6654
+ const toolCalls = /* @__PURE__ */ new Map();
6655
+ for (const toolCall of message.toolCalls ?? []) toolCalls.set(toolCall.id, toolCall);
6656
+ for (const toolCall of toolCalls.values()) {
6657
+ const entry = {
6658
+ toolCall,
6659
+ toolMessage: results.get(toolCall.id)
6660
+ };
6661
+ const name = toolCall.function.name;
6662
+ const named = renderers.named.has(name);
6663
+ const rendered = named || renderers.wildcard;
6664
+ const groups = named ? renderers.groupedNames.has(name) : renderers.wildcardGroups;
6665
+ if (!rendered || !groups) {
6666
+ if (rendered) open = void 0;
6667
+ segments.push({
6668
+ kind: "call",
6669
+ id: toolCall.id,
6670
+ call: entry,
6671
+ rendered
6672
+ });
6673
+ } else if (open) open.calls.push(entry);
6674
+ else {
6675
+ open = {
6676
+ kind: "group",
6677
+ id: toolCall.id,
6678
+ calls: [entry],
6679
+ trailing: false
6680
+ };
6681
+ segments.push(open);
6682
+ }
6683
+ }
6684
+ }
6685
+ if (open) open.trailing = true;
6686
+ const layout = /* @__PURE__ */ new Map();
6687
+ for (const [id, segments] of layouts) layout.set(id, {
6688
+ segments,
6689
+ signature: signatureOf(segments)
6690
+ });
6691
+ return layout;
6692
+ }
6693
+ /**
6694
+ * Finds the working phase of every reply in `rendered`: its messages up to the
6695
+ * last one that calls a tool. Text in there was narration; what follows is the
6696
+ * reply itself. Replies that called no tools are omitted, except the latest,
6697
+ * which may be about to.
6698
+ */
6699
+ function getTurnWork(rendered, layouts) {
6700
+ const turns = /* @__PURE__ */ new Map();
6701
+ let start = 0;
6702
+ while (start < rendered.length) {
6703
+ let end = start;
6704
+ while (end < rendered.length && rendered[end].role !== "user") end++;
6705
+ const key = start > 0 ? rendered[start - 1].id : "start";
6706
+ const visible = rendered.slice(start, end).filter((message) => message.role !== "tool");
6707
+ const isLatest = end === rendered.length;
6708
+ const calls = [];
6709
+ for (const message of visible) for (const segment of layouts.get(message.id)?.segments ?? []) if (segment.kind === "group") calls.push(...segment.calls);
6710
+ else if (segment.rendered) calls.push(segment.call);
6711
+ const shown = new Set(calls.map((entry) => entry.toolCall.id));
6712
+ let lastWork = -1;
6713
+ visible.forEach((message, index) => {
6714
+ if (message.role === "assistant" && message.toolCalls?.some((call) => shown.has(call.id))) lastWork = index;
6715
+ });
6716
+ const first = visible[0];
6717
+ if (first && (calls.length > 0 || isLatest)) {
6718
+ let lastAssistant = -1;
6719
+ visible.forEach((message, index) => {
6720
+ if (message.role === "assistant") lastAssistant = index;
6721
+ });
6722
+ const replyText = visible[lastAssistant]?.content;
6723
+ const endsWithWork = lastAssistant >= 0 && lastAssistant <= lastWork && typeof replyText === "string" && replyText.trim().length > 0;
6724
+ turns.set(key, {
6725
+ key,
6726
+ firstMessageId: first.id,
6727
+ workMessageIds: new Set(visible.slice(0, lastWork + 1).map((message) => message.id)),
6728
+ replyTextMessageId: endsWithWork ? visible[lastAssistant].id : void 0,
6729
+ calls,
6730
+ isLatest
6731
+ });
6732
+ }
6733
+ start = end + 1;
6734
+ }
6735
+ return turns;
6736
+ }
6737
+
6151
6738
  //#endregion
6152
6739
  //#region src/v2/components/chat/CopilotChatToolCallsView.tsx
6153
- function CopilotChatToolCallsView({ message, messages = [] }) {
6740
+ const appearances = {
6741
+ grouped: "card",
6742
+ line: "line",
6743
+ stacked: "stack"
6744
+ };
6745
+ function CopilotChatToolCallsView({ message, messages = [], display: displayProp, group }) {
6154
6746
  const renderToolCall = useRenderToolCall();
6747
+ const rendererNames = useToolCallRendererNames();
6155
6748
  const { copilotkit } = useCopilotKit();
6156
6749
  const subscribe = useCallback((onChange) => copilotkit.ɵsubscribeToLearningConfigured(onChange), [copilotkit]);
6157
6750
  const getSnapshot = () => copilotkit.ɵlearningConfigured;
6158
6751
  const learningConfigured = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
6752
+ const context = useContext(ToolCallDisplayContext);
6753
+ const display = displayProp ?? context?.display ?? "grouped";
6754
+ const viewLayout = context?.layouts.get(message.id);
6755
+ const layout = useMemo(() => {
6756
+ if (display === "separate") return void 0;
6757
+ return viewLayout ?? getToolCallLayouts([message], messages, rendererNames).get(message.id);
6758
+ }, [
6759
+ display,
6760
+ viewLayout,
6761
+ message,
6762
+ messages,
6763
+ rendererNames
6764
+ ]);
6159
6765
  if (!message.toolCalls || message.toolCalls.length === 0) return null;
6160
- return /* @__PURE__ */ jsx(Fragment$1, { children: message.toolCalls.map((toolCall) => {
6766
+ const renderCall = (entry) => {
6161
6767
  const rendered = renderToolCall({
6162
- toolCall,
6163
- toolMessage: messages.find((m) => m.role === "tool" && m.toolCallId === toolCall.id)
6768
+ toolCall: entry.toolCall,
6769
+ toolMessage: entry.toolMessage
6164
6770
  });
6165
- if (rendered === null) return null;
6166
- if (!learningConfigured) return rendered;
6771
+ if (rendered === null || !learningConfigured) return rendered;
6167
6772
  return /* @__PURE__ */ jsx("div", {
6168
- "data-tool-call-id": toolCall.id,
6773
+ "data-tool-call-id": entry.toolCall.id,
6169
6774
  style: { display: "contents" },
6170
6775
  children: rendered
6171
- }, toolCall.id);
6776
+ });
6777
+ };
6778
+ if (!layout) return /* @__PURE__ */ jsx(Fragment$1, { children: message.toolCalls.map((toolCall) => {
6779
+ const toolMessage = messages.find((m) => m.role === "tool" && m.toolCallId === toolCall.id);
6780
+ return /* @__PURE__ */ jsx(React.Fragment, { children: renderCall({
6781
+ toolCall,
6782
+ toolMessage
6783
+ }) }, toolCall.id);
6784
+ }) });
6785
+ const workOpen = context?.workOpen.get(message.id);
6786
+ const groupActive = (trailing) => trailing && (context ? context.isRunning : true);
6787
+ return /* @__PURE__ */ jsx(Fragment$1, { children: layout.segments.map((segment) => {
6788
+ if (segment.kind === "call") return /* @__PURE__ */ jsx(React.Fragment, { children: renderCall(segment.call) }, segment.id);
6789
+ if (display === "turn") {
6790
+ const failedIds = new Set(segment.calls.filter((call) => call.toolMessage?.error).map((call) => call.toolCall.id));
6791
+ return /* @__PURE__ */ jsx(Collapsible, {
6792
+ open: workOpen ?? true,
6793
+ className: "cpk:-mx-2",
6794
+ children: /* @__PURE__ */ jsx("div", {
6795
+ className: "cpk:px-2 cpk:py-1.5",
6796
+ children: /* @__PURE__ */ jsx(ToolCallGroupContext.Provider, {
6797
+ value: {
6798
+ appearance: "line",
6799
+ failedIds,
6800
+ active: groupActive(segment.trailing)
6801
+ },
6802
+ children: segment.calls.map((call) => /* @__PURE__ */ jsx(React.Fragment, { children: renderCall(call) }, call.toolCall.id))
6803
+ })
6804
+ })
6805
+ }, segment.id);
6806
+ }
6807
+ return /* @__PURE__ */ jsx(React.Fragment, { children: renderSlot(group, CopilotChatToolCallGroup, {
6808
+ calls: segment.calls,
6809
+ renderCall,
6810
+ appearance: appearances[display] ?? "card",
6811
+ isActive: groupActive(segment.trailing)
6812
+ }) }, segment.id);
6172
6813
  }) });
6173
6814
  }
6174
6815
 
6175
6816
  //#endregion
6176
6817
  //#region src/v2/components/chat/CopilotChatInspectorButton.tsx
6177
6818
  let shortcutsHidden = false;
6178
- const listeners = /* @__PURE__ */ new Set();
6819
+ const listeners$1 = /* @__PURE__ */ new Set();
6179
6820
  const subscribe = (listener) => {
6180
- listeners.add(listener);
6821
+ listeners$1.add(listener);
6181
6822
  return () => {
6182
- listeners.delete(listener);
6823
+ listeners$1.delete(listener);
6183
6824
  };
6184
6825
  };
6185
6826
  const getSnapshot = () => shortcutsHidden;
@@ -6189,7 +6830,7 @@ function useInspectorShortcutsHidden() {
6189
6830
  }
6190
6831
  function hideShortcuts() {
6191
6832
  shortcutsHidden = true;
6192
- listeners.forEach((listener) => listener());
6833
+ listeners$1.forEach((listener) => listener());
6193
6834
  }
6194
6835
  function InspectorKiteIcon({ className, ...props }) {
6195
6836
  const id = useId();
@@ -6456,47 +7097,544 @@ function CopilotChatInspectorButton({ title, className, onClick, onPointerDown,
6456
7097
  }
6457
7098
 
6458
7099
  //#endregion
6459
- //#region src/v2/components/chat/CopilotChatAssistantMessage.tsx
7100
+ //#region src/v2/components/ui/popover.tsx
7101
+ function Popover({ ...props }) {
7102
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Root, {
7103
+ "data-slot": "popover",
7104
+ ...props
7105
+ });
7106
+ }
7107
+ function PopoverAnchor({ ...props }) {
7108
+ return /* @__PURE__ */ jsx(PopoverPrimitive.Anchor, {
7109
+ "data-slot": "popover-anchor",
7110
+ ...props
7111
+ });
7112
+ }
6460
7113
  /**
6461
- * Binds the Inspector action to the active chat without making the full
6462
- * assistant message subscribe to chat configuration changes.
7114
+ * Popover content in a portal, so it floats over the page instead of taking
7115
+ * room in the layout, with the CopilotKit style scope on it.
6463
7116
  */
6464
- function BoundInspectorButton({ inspectorButton, messageId, openInspector, ...props }) {
6465
- const chatConfiguration = useCopilotChatConfiguration();
6466
- return renderSlot(inspectorButton, CopilotChatAssistantMessage.InspectorButton, {
6467
- ...props,
6468
- onClick: () => openInspector({
6469
- messageId,
6470
- threadId: chatConfiguration?.threadId,
6471
- agentId: chatConfiguration?.agentId
6472
- })
6473
- });
7117
+ const PopoverContent = React$1.forwardRef(({ className, align = "start", sideOffset = 6, ...props }, ref) => /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(PopoverPrimitive.Content, {
7118
+ ref,
7119
+ "data-copilotkit": true,
7120
+ "data-copilotkit-popover": true,
7121
+ "data-slot": "popover-content",
7122
+ align,
7123
+ sideOffset,
7124
+ className: cn("cpk:z-50 cpk:outline-none cpk:data-[state=open]:animate-in cpk:data-[state=open]:fade-in-0 cpk:data-[state=open]:zoom-in-95 cpk:data-[side=bottom]:slide-in-from-top-1 cpk:data-[side=top]:slide-in-from-bottom-1", className),
7125
+ ...props
7126
+ }) }));
7127
+ PopoverContent.displayName = "PopoverContent";
7128
+
7129
+ //#endregion
7130
+ //#region src/v2/lib/message-feedback.ts
7131
+ /** Trajectory event name for a rating of one assistant message. */
7132
+ const MESSAGE_FEEDBACK_EVENT_NAME = "message.feedback";
7133
+ /** Longest comment kept, in characters; the rest is cut so the event stays small. */
7134
+ const MESSAGE_FEEDBACK_MAX_COMMENT_LENGTH = 1e3;
7135
+ /** Longest excerpt of the rated response sent with the rating, in characters. */
7136
+ const RESPONSE_EXCERPT_LENGTH = 500;
7137
+ const ratings = /* @__PURE__ */ new Map();
7138
+ const listeners = /* @__PURE__ */ new Map();
7139
+ const threadKey = (agentId, threadId) => JSON.stringify([agentId, threadId]);
7140
+ const messageKey = (agentId, threadId, messageId) => JSON.stringify([
7141
+ agentId,
7142
+ threadId,
7143
+ messageId
7144
+ ]);
7145
+ /** Cuts `text` to `max` characters without splitting a surrogate pair. */
7146
+ const clip = (text, max) => {
7147
+ const characters = Array.from(text);
7148
+ return characters.length > max ? characters.slice(0, max).join("") : text;
7149
+ };
7150
+ /** The comment as kept and sent: trimmed and capped, or none. */
7151
+ const normalizeComment = (comment) => {
7152
+ if (typeof comment !== "string") return void 0;
7153
+ const text = clip(comment.trim(), MESSAGE_FEEDBACK_MAX_COMMENT_LENGTH);
7154
+ return text === "" ? void 0 : text;
7155
+ };
7156
+ /** The rating this page gave one message, if any. */
7157
+ function getMessageFeedback(agentId, threadId, messageId) {
7158
+ return ratings.get(messageKey(agentId, threadId, messageId));
7159
+ }
7160
+ /** Calls `listener` whenever a rating in this Thread changes. */
7161
+ function subscribeToMessageFeedback(agentId, threadId, listener) {
7162
+ const key = threadKey(agentId, threadId);
7163
+ let set = listeners.get(key);
7164
+ if (set === void 0) {
7165
+ set = /* @__PURE__ */ new Set();
7166
+ listeners.set(key, set);
7167
+ }
7168
+ set.add(listener);
7169
+ return () => {
7170
+ set.delete(listener);
7171
+ if (set.size === 0) listeners.delete(key);
7172
+ };
6474
7173
  }
6475
- function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, onThumbsUp, onThumbsDown, onReadAloud, onRegenerate, additionalToolbarItems, toolbarVisible = true, markdownRenderer, toolbar, copyButton, inspectorButton, thumbsUpButton, thumbsDownButton, readAloudButton, regenerateButton, toolCallsView, children, className, ...props }) {
6476
- useKatexStyles();
6477
- const { isInspectorEnabled, openInspector } = useCopilotKitInspector();
6478
- const shortcutsHidden = useInspectorShortcutsHidden();
6479
- const showInspectorShortcut = isInspectorEnabled && !shortcutsHidden;
6480
- const boundMarkdownRenderer = renderSlot(markdownRenderer, CopilotChatAssistantMessage.MarkdownRenderer, { content: message.content || "" });
6481
- const boundCopyButton = renderSlot(copyButton, CopilotChatAssistantMessage.CopyButton, { onClick: async () => {
6482
- if (message.content) return await copyToClipboard(message.content);
6483
- return false;
6484
- } });
6485
- const boundThumbsUpButton = renderSlot(thumbsUpButton, CopilotChatAssistantMessage.ThumbsUpButton, { onClick: onThumbsUp ? () => onThumbsUp(message) : void 0 });
6486
- const boundInspectorButton = showInspectorShortcut ? /* @__PURE__ */ jsx(BoundInspectorButton, {
6487
- inspectorButton,
7174
+ /**
7175
+ * Sets (or, with `null`, clears) this page's rating of one message and sends
7176
+ * it to the active Trajectory. Every change is a new event; the newest event
7177
+ * for a `feedbackId` is the current one. Like any Trajectory event, a change
7178
+ * made while no Trajectory captures, for example during a reconnect, is not
7179
+ * sent; the page still shows it.
7180
+ */
7181
+ function setMessageFeedback(params) {
7182
+ const { copilotkit, agentId, threadId, message } = params;
7183
+ const comment = normalizeComment(params.feedback?.comment);
7184
+ const feedback = params.feedback && {
7185
+ rating: params.feedback.rating,
7186
+ ...comment ? { comment } : {}
7187
+ };
7188
+ const key = messageKey(agentId, threadId, message.id);
7189
+ if (feedback) ratings.set(key, feedback);
7190
+ else ratings.delete(key);
7191
+ for (const listener of listeners.get(threadKey(agentId, threadId)) ?? []) listener();
7192
+ const runId = copilotkit.getRunIdForMessage(agentId, threadId, message.id);
7193
+ copilotkit.emitTrajectoryEvent(MESSAGE_FEEDBACK_EVENT_NAME, {
7194
+ feedbackId: `${threadId}:${message.id}`,
7195
+ threadId,
6488
7196
  messageId: message.id,
6489
- openInspector
6490
- }) : /* @__PURE__ */ jsx(Fragment$1, {});
6491
- const boundThumbsDownButton = renderSlot(thumbsDownButton, CopilotChatAssistantMessage.ThumbsDownButton, { onClick: onThumbsDown ? () => onThumbsDown(message) : void 0 });
6492
- const boundReadAloudButton = renderSlot(readAloudButton, CopilotChatAssistantMessage.ReadAloudButton, { onClick: onReadAloud ? () => onReadAloud(message) : void 0 });
6493
- const boundRegenerateButton = renderSlot(regenerateButton, CopilotChatAssistantMessage.RegenerateButton, { onClick: onRegenerate ? () => onRegenerate(message) : void 0 });
6494
- const boundToolbar = renderSlot(toolbar, CopilotChatAssistantMessage.Toolbar, { children: /* @__PURE__ */ jsxs("div", {
6495
- className: "cpk:flex cpk:w-full cpk:items-center cpk:gap-1",
7197
+ agentId,
7198
+ ...runId ? { runId } : {},
7199
+ rating: feedback?.rating ?? null,
7200
+ ...feedback?.comment ? { comment: feedback.comment } : {},
7201
+ ...copilotkit.ɵlearningCapturesAgentText ? { response: clip(message.content ?? "", RESPONSE_EXCERPT_LENGTH) } : {}
7202
+ });
7203
+ }
7204
+
7205
+ //#endregion
7206
+ //#region src/v2/components/chat/message-feedback.tsx
7207
+ /**
7208
+ * Set by the message view while Learning is on for this chat. Assistant
7209
+ * messages without it show thumbs only when the app passes its own handlers
7210
+ * or thumb slots.
7211
+ */
7212
+ const MessageFeedbackScopeContext = createContext(null);
7213
+ const capturedCores = /* @__PURE__ */ new WeakSet();
7214
+ const rememberCapture = (copilotkit) => {
7215
+ if (capturedCores.has(copilotkit)) return;
7216
+ capturedCores.add(copilotkit);
7217
+ const unsubscribe = copilotkit.ɵsubscribeToLearningConfigured(() => {
7218
+ if (copilotkit.ɵlearningConfigured) return;
7219
+ capturedCores.delete(copilotkit);
7220
+ unsubscribe();
7221
+ });
7222
+ };
7223
+ /**
7224
+ * Whether the thumbs record feedback for Learning. True once a Trajectory of
7225
+ * this Core has started and as long as Learning stays configured, also while
7226
+ * capture reconnects or is stopped, so the buttons do not flicker. Ratings
7227
+ * given meanwhile still show but, like any Trajectory event, are not
7228
+ * sent. A capture that never starts (for example without a license) leaves it
7229
+ * false.
7230
+ */
7231
+ function useLearningFeedbackEnabled(copilotkit) {
7232
+ const configured = useSyncExternalStore(useCallback((onChange) => copilotkit.ɵsubscribeToLearningConfigured(onChange), [copilotkit]), () => copilotkit.ɵlearningConfigured, () => false);
7233
+ const capturing = useSyncExternalStore(useCallback((onChange) => copilotkit.subscribe({ onTrajectoryChanged: onChange }).unsubscribe, [copilotkit]), () => copilotkit.trajectoryId !== null, () => false);
7234
+ useEffect(() => {
7235
+ if (capturing) rememberCapture(copilotkit);
7236
+ }, [capturing, copilotkit]);
7237
+ return configured && (capturing || capturedCores.has(copilotkit));
7238
+ }
7239
+ const noSubscription = () => () => {};
7240
+ /** Feedback controls for `message`, or `null` when this chat collects none. */
7241
+ function useMessageFeedback(message) {
7242
+ const scope = useContext(MessageFeedbackScopeContext);
7243
+ const subscribe = useCallback((onChange) => scope ? subscribeToMessageFeedback(scope.agentId, scope.threadId, onChange) : noSubscription(), [scope]);
7244
+ const getSnapshot = () => scope ? getMessageFeedback(scope.agentId, scope.threadId, message.id) : void 0;
7245
+ const feedback = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
7246
+ if (!scope) return null;
7247
+ const save = (next) => setMessageFeedback({
7248
+ ...scope,
7249
+ message,
7250
+ feedback: next
7251
+ });
7252
+ return {
7253
+ feedback,
7254
+ rate: (rating) => {
7255
+ if (feedback?.rating !== rating) save({ rating });
7256
+ },
7257
+ clear: () => {
7258
+ if (feedback) save(null);
7259
+ },
7260
+ comment: (comment) => {
7261
+ if (feedback) save({
7262
+ rating: feedback.rating,
7263
+ comment
7264
+ });
7265
+ }
7266
+ };
7267
+ }
7268
+ /**
7269
+ * How long the pointer may be away from the rating and its comment before the
7270
+ * comment closes: enough to cross the gap between them, short enough that
7271
+ * passing over a rating does not leave it open.
7272
+ */
7273
+ const FEEDBACK_COMMENT_CLOSE_DELAY_MS = 150;
7274
+ /**
7275
+ * Drives the comment popover of a rated message.
7276
+ *
7277
+ * It opens when a rating is given and whenever the pointer or keyboard focus
7278
+ * reaches the chosen thumb, with the saved comment in the field. It closes by
7279
+ * itself shortly after the pointer leaves the thumb and the popover, unless
7280
+ * focus is in the field: then it stays until focus moves away, Enter, or
7281
+ * Escape. Closing saves a changed comment; Escape, a click on a thumb, and
7282
+ * removing the rating discard it.
7283
+ */
7284
+ function useFeedbackComment(controls) {
7285
+ const [open, setOpen] = useState(false);
7286
+ const [draft, setDraft] = useState("");
7287
+ const [focusRequest, setFocusRequest] = useState(0);
7288
+ const inputRef = useRef(null);
7289
+ const timer = useRef(void 0);
7290
+ const editing = useRef(false);
7291
+ const focusWaiting = useRef(false);
7292
+ const pointerOver = useRef(false);
7293
+ const returning = useRef(false);
7294
+ const latest = useRef({
7295
+ controls,
7296
+ draft,
7297
+ open
7298
+ });
7299
+ latest.current = {
7300
+ ...latest.current,
7301
+ controls,
7302
+ draft,
7303
+ open
7304
+ };
7305
+ const takeFocusRequest = useCallback(() => {
7306
+ const waiting = focusWaiting.current;
7307
+ focusWaiting.current = false;
7308
+ return waiting;
7309
+ }, []);
7310
+ const cancelClose = useCallback(() => {
7311
+ if (timer.current === void 0) return;
7312
+ clearTimeout(timer.current);
7313
+ timer.current = void 0;
7314
+ }, []);
7315
+ useEffect(() => cancelClose, [cancelClose]);
7316
+ const savedComment = useCallback(() => latest.current.controls?.feedback?.comment ?? "", []);
7317
+ useEffect(() => () => {
7318
+ const { open: wasOpen, controls: current, draft: text } = latest.current;
7319
+ if (wasOpen && current?.feedback && text.trim() !== savedComment()) current.comment(text);
7320
+ }, []);
7321
+ const close = useCallback(({ save = true } = {}) => {
7322
+ cancelClose();
7323
+ focusWaiting.current = false;
7324
+ pointerOver.current = false;
7325
+ if (!latest.current.open) return;
7326
+ const current = latest.current.controls;
7327
+ if (save && current?.feedback && latest.current.draft.trim() !== savedComment()) current.comment(latest.current.draft);
7328
+ editing.current = false;
7329
+ latest.current = {
7330
+ ...latest.current,
7331
+ open: false
7332
+ };
7333
+ setOpen(false);
7334
+ }, [cancelClose, savedComment]);
7335
+ const show = ({ comment, focus }) => {
7336
+ cancelClose();
7337
+ latest.current = {
7338
+ ...latest.current,
7339
+ open: true,
7340
+ draft: comment
7341
+ };
7342
+ setDraft(comment);
7343
+ if (focus) {
7344
+ focusWaiting.current = true;
7345
+ setFocusRequest((request) => request + 1);
7346
+ }
7347
+ setOpen(true);
7348
+ };
7349
+ return {
7350
+ open,
7351
+ draft,
7352
+ setDraft,
7353
+ focusRequest,
7354
+ takeFocusRequest,
7355
+ inputRef,
7356
+ show,
7357
+ enter: (via = "focus") => {
7358
+ cancelClose();
7359
+ if (via === "pointer") pointerOver.current = true;
7360
+ if (returning.current) return;
7361
+ if (!latest.current.open && latest.current.controls?.feedback) show({
7362
+ comment: savedComment(),
7363
+ focus: false
7364
+ });
7365
+ },
7366
+ leave: (via = "focus") => {
7367
+ if (via === "pointer") pointerOver.current = false;
7368
+ else if (pointerOver.current) return;
7369
+ cancelClose();
7370
+ timer.current = setTimeout(() => {
7371
+ timer.current = void 0;
7372
+ if (!editing.current) close();
7373
+ }, FEEDBACK_COMMENT_CLOSE_DELAY_MS);
7374
+ },
7375
+ setEditing: (value) => {
7376
+ editing.current = value;
7377
+ },
7378
+ close,
7379
+ returnFocus: (target) => {
7380
+ returning.current = true;
7381
+ try {
7382
+ target?.focus();
7383
+ } finally {
7384
+ returning.current = false;
7385
+ }
7386
+ }
7387
+ };
7388
+ }
7389
+
7390
+ //#endregion
7391
+ //#region src/v2/components/chat/CopilotChatAssistantMessage.tsx
7392
+ /**
7393
+ * In the `"turn"` tool-call display, text in a reply's working phase was
7394
+ * narration: it fades to muted once a call follows it, and folds away with the
7395
+ * rest of the work when the reply is done. The wrapper is there for every
7396
+ * message in that display, so text that turns into narration keeps its node
7397
+ * (and its place) rather than remounting.
7398
+ */
7399
+ function WorkText({ messageId, children }) {
7400
+ const context = useContext(ToolCallDisplayContext);
7401
+ if (context?.display !== "turn") return children;
7402
+ const open = context.workTextOpen.get(messageId);
7403
+ return /* @__PURE__ */ jsx(Collapsible, {
7404
+ open: open ?? true,
7405
+ className: "cpk:-mx-2",
7406
+ children: /* @__PURE__ */ jsx("div", {
7407
+ className: "cpk:px-2",
7408
+ "data-work-text": open === void 0 ? "reply" : "narration",
7409
+ children
7410
+ })
7411
+ });
7412
+ }
7413
+ /**
7414
+ * Binds the Inspector action to the active chat without making the full
7415
+ * assistant message subscribe to chat configuration changes.
7416
+ */
7417
+ function BoundInspectorButton({ inspectorButton, messageId, openInspector, ...props }) {
7418
+ const chatConfiguration = useCopilotChatConfiguration();
7419
+ return renderSlot(inspectorButton, CopilotChatAssistantMessage.InspectorButton, {
7420
+ ...props,
7421
+ onClick: () => openInspector({
7422
+ messageId,
7423
+ threadId: chatConfiguration?.threadId,
7424
+ agentId: chatConfiguration?.agentId
7425
+ })
7426
+ });
7427
+ }
7428
+ /** Whether focus came from the keyboard; a pointer click also focuses buttons. */
7429
+ function isFocusVisible(element) {
7430
+ try {
7431
+ return element.matches(":focus-visible");
7432
+ } catch {
7433
+ return false;
7434
+ }
7435
+ }
7436
+ const HIDDEN_TOO = {
7437
+ checkVisibilityCSS: true,
7438
+ visibilityProperty: true
7439
+ };
7440
+ const FOCUSABLE = [
7441
+ "a[href]",
7442
+ "button:not([disabled])",
7443
+ "input:not([disabled])",
7444
+ "select:not([disabled])",
7445
+ "textarea:not([disabled])",
7446
+ "[tabindex]"
7447
+ ].map((selector) => `${selector}:not([tabindex="-1"]):not([data-radix-focus-guard])`).join(", ");
7448
+ /** Approximately the element Tab reaches after `element`, outside `skip`. */
7449
+ function nextFocusable(element, skip) {
7450
+ const all = Array.from(element.ownerDocument.querySelectorAll(FOCUSABLE)).filter((candidate) => candidate === element || !skip?.contains(candidate) && !candidate.closest("[hidden], [inert]"));
7451
+ const index = all.indexOf(element);
7452
+ return index === -1 ? null : all[index + 1] ?? null;
7453
+ }
7454
+ /**
7455
+ * The comment popover of a rated message, pointing at the chosen thumb. Kept
7456
+ * apart so only it, not the whole message, follows chat configuration.
7457
+ *
7458
+ * The popover lives in a portal, so it keeps keyboard order by hand: Shift+Tab
7459
+ * from its start returns to the thumb, Tab from its end moves on to the
7460
+ * control after the thumb, and Enter or Escape inside it returns to the thumb.
7461
+ */
7462
+ function FeedbackCommentPopover({ feedbackComment, comment, savedComment, rating, anchor, messageId }) {
7463
+ const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
7464
+ const contentRef = useRef(null);
7465
+ const focusInside = () => contentRef.current?.contains(document.activeElement) ?? false;
7466
+ const { focusRequest, takeFocusRequest, inputRef } = comment;
7467
+ const focusField = useCallback(() => {
7468
+ if (inputRef.current && takeFocusRequest()) inputRef.current.focus();
7469
+ }, [inputRef, takeFocusRequest]);
7470
+ useEffect(() => focusField(), [focusRequest, focusField]);
7471
+ /** Whether `target` is a thumb of this message, whose click decides itself. */
7472
+ const isOwnThumb = (target) => {
7473
+ return (target instanceof Element ? target.closest("[data-copilotkit-rating]") : null)?.closest("[data-message-id]")?.getAttribute("data-message-id") === messageId;
7474
+ };
7475
+ return /* @__PURE__ */ jsxs(Popover, {
7476
+ open: comment.open,
7477
+ onOpenChange: (open) => {
7478
+ if (!open) comment.close();
7479
+ },
7480
+ children: [/* @__PURE__ */ jsx(PopoverAnchor, { virtualRef: anchor }), /* @__PURE__ */ jsx(PopoverContent, {
7481
+ ref: contentRef,
7482
+ side: "bottom",
7483
+ collisionPadding: 8,
7484
+ hideWhenDetached: true,
7485
+ "aria-label": labels.assistantMessageFeedbackCommentPlaceholder,
7486
+ "data-copilotkit-ignore": true,
7487
+ onOpenAutoFocus: (event) => {
7488
+ event.preventDefault();
7489
+ focusField();
7490
+ },
7491
+ onCloseAutoFocus: (event) => event.preventDefault(),
7492
+ onInteractOutside: (event) => {
7493
+ if (isOwnThumb(event.target)) event.preventDefault();
7494
+ },
7495
+ onEscapeKeyDown: (event) => {
7496
+ const returnFocus = focusInside();
7497
+ if (returnFocus) event.stopPropagation();
7498
+ comment.close({ save: false });
7499
+ if (returnFocus) comment.returnFocus(anchor.current);
7500
+ },
7501
+ onKeyDown: (event) => {
7502
+ if (event.key !== "Tab") return;
7503
+ const focusables = Array.from(contentRef.current?.querySelectorAll(FOCUSABLE) ?? []);
7504
+ if (!(event.shiftKey ? document.activeElement === focusables[0] : document.activeElement === focusables[focusables.length - 1]) || !anchor.current?.isConnected) return;
7505
+ event.preventDefault();
7506
+ const target = event.shiftKey ? anchor.current : nextFocusable(anchor.current, contentRef.current) ?? anchor.current;
7507
+ comment.close();
7508
+ if (target === anchor.current) comment.returnFocus(target);
7509
+ else target.focus();
7510
+ },
7511
+ onPointerEnter: () => comment.enter("pointer"),
7512
+ onPointerLeave: () => comment.leave("pointer"),
7513
+ className: "cpk:z-[1300]",
7514
+ children: /* @__PURE__ */ jsx(Fragment, { children: renderSlot(feedbackComment, CopilotChatAssistantMessage.FeedbackComment, {
7515
+ value: comment.draft,
7516
+ savedComment,
7517
+ inputRef: comment.inputRef,
7518
+ onChange: comment.setDraft,
7519
+ onSubmit: () => {
7520
+ comment.close();
7521
+ comment.returnFocus(anchor.current);
7522
+ },
7523
+ onEditingChange: comment.setEditing,
7524
+ onLeave: (next) => {
7525
+ if (next && (contentRef.current?.contains(next) || isOwnThumb(next))) return;
7526
+ comment.leave();
7527
+ }
7528
+ }) }, rating)
7529
+ })]
7530
+ });
7531
+ }
7532
+ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, onThumbsUp, onThumbsDown, onReadAloud, onRegenerate, additionalToolbarItems, toolbarVisible = true, markdownRenderer, toolbar, copyButton, inspectorButton, thumbsUpButton, thumbsDownButton, readAloudButton, regenerateButton, feedbackComment: feedbackCommentSlot, toolCallsView, children, className, ...props }) {
7533
+ useKatexStyles();
7534
+ const { isInspectorEnabled, openInspector } = useCopilotKitInspector();
7535
+ const shortcutsHidden = useInspectorShortcutsHidden();
7536
+ const showInspectorShortcut = isInspectorEnabled && !shortcutsHidden;
7537
+ const feedback = useMessageFeedback(message);
7538
+ const comment = useFeedbackComment(feedback);
7539
+ const rating = feedback?.feedback?.rating;
7540
+ const root = useRef(null);
7541
+ const commentAnchor = useRef(null);
7542
+ const commentRating = useRef(rating);
7543
+ useLayoutEffect(() => {
7544
+ if (comment.open && !commentAnchor.current?.isConnected && rating) commentAnchor.current = root.current?.querySelector(`[data-copilotkit-rating="${rating}"]`) ?? root.current?.querySelector("button[aria-pressed=\"true\"]") ?? null;
7545
+ });
7546
+ /**
7547
+ * Thumbs are toggles: a new rating is saved and opens its comment, and
7548
+ * clicking the chosen thumb again removes the rating. A keyboard click
7549
+ * (`detail` 0) moves focus into the comment, as there is no pointer.
7550
+ * Custom thumb slots may call `onClick` without an event.
7551
+ *
7552
+ * @returns Whether the app's handler should run: true for a new rating and
7553
+ * whenever this chat does not record ratings, false when one is removed.
7554
+ */
7555
+ const rate = (value, event) => {
7556
+ if (!feedback) return true;
7557
+ if (rating === value) {
7558
+ comment.close({ save: false });
7559
+ feedback.clear();
7560
+ return false;
7561
+ }
7562
+ feedback.rate(value);
7563
+ commentRating.current = value;
7564
+ commentAnchor.current = event?.currentTarget ?? null;
7565
+ comment.show({
7566
+ comment: "",
7567
+ focus: event?.detail === 0
7568
+ });
7569
+ return true;
7570
+ };
7571
+ /** Props that let the chosen thumb open and point at its comment. */
7572
+ const thumbFeedbackProps = (value) => {
7573
+ if (!feedback) return {};
7574
+ const thumb = { "data-copilotkit-rating": value };
7575
+ if (rating !== value) return {
7576
+ ...thumb,
7577
+ "aria-pressed": false
7578
+ };
7579
+ const enter = (target, via) => {
7580
+ if (!comment.open) commentRating.current = value;
7581
+ commentAnchor.current = target;
7582
+ comment.enter(via);
7583
+ };
7584
+ return {
7585
+ ...thumb,
7586
+ "aria-pressed": true,
7587
+ "aria-haspopup": "dialog",
7588
+ "aria-expanded": comment.open,
7589
+ onPointerEnter: (event) => {
7590
+ if (event.pointerType !== "touch") enter(event.currentTarget, "pointer");
7591
+ },
7592
+ onPointerLeave: (event) => {
7593
+ if (event.pointerType !== "touch") comment.leave("pointer");
7594
+ },
7595
+ onFocus: (event) => {
7596
+ if (isFocusVisible(event.currentTarget)) enter(event.currentTarget, "focus");
7597
+ },
7598
+ onBlur: () => comment.leave(),
7599
+ onKeyDown: (event) => {
7600
+ const input = comment.inputRef.current;
7601
+ if (event.key === "Tab" && !event.shiftKey && comment.open && input && input.checkVisibility?.(HIDDEN_TOO) !== false) {
7602
+ event.preventDefault();
7603
+ input.focus();
7604
+ }
7605
+ }
7606
+ };
7607
+ };
7608
+ const boundMarkdownRenderer = renderSlot(markdownRenderer, CopilotChatAssistantMessage.MarkdownRenderer, { content: message.content || "" });
7609
+ const boundCopyButton = renderSlot(copyButton, CopilotChatAssistantMessage.CopyButton, { onClick: async () => {
7610
+ if (message.content) return await copyToClipboard(message.content);
7611
+ return false;
7612
+ } });
7613
+ const boundThumbsUpButton = renderSlot(thumbsUpButton, CopilotChatAssistantMessage.ThumbsUpButton, {
7614
+ onClick: onThumbsUp || feedback ? (event) => {
7615
+ if (rate("up", event)) onThumbsUp?.(message);
7616
+ } : void 0,
7617
+ ...thumbFeedbackProps("up")
7618
+ });
7619
+ const boundInspectorButton = showInspectorShortcut ? /* @__PURE__ */ jsx(BoundInspectorButton, {
7620
+ inspectorButton,
7621
+ messageId: message.id,
7622
+ openInspector
7623
+ }) : /* @__PURE__ */ jsx(Fragment$1, {});
7624
+ const boundThumbsDownButton = renderSlot(thumbsDownButton, CopilotChatAssistantMessage.ThumbsDownButton, {
7625
+ onClick: onThumbsDown || feedback ? (event) => {
7626
+ if (rate("down", event)) onThumbsDown?.(message);
7627
+ } : void 0,
7628
+ ...thumbFeedbackProps("down")
7629
+ });
7630
+ const boundReadAloudButton = renderSlot(readAloudButton, CopilotChatAssistantMessage.ReadAloudButton, { onClick: onReadAloud ? () => onReadAloud(message) : void 0 });
7631
+ const boundRegenerateButton = renderSlot(regenerateButton, CopilotChatAssistantMessage.RegenerateButton, { onClick: onRegenerate ? () => onRegenerate(message) : void 0 });
7632
+ const boundToolbar = renderSlot(toolbar, CopilotChatAssistantMessage.Toolbar, { children: /* @__PURE__ */ jsxs("div", {
7633
+ className: "cpk:flex cpk:w-full cpk:items-center cpk:gap-1",
6496
7634
  children: [
6497
7635
  boundCopyButton,
6498
- (onThumbsUp || thumbsUpButton) && boundThumbsUpButton,
6499
- (onThumbsDown || thumbsDownButton) && boundThumbsDownButton,
7636
+ (onThumbsUp || thumbsUpButton || feedback) && boundThumbsUpButton,
7637
+ (onThumbsDown || thumbsDownButton || feedback) && boundThumbsDownButton,
6500
7638
  (onReadAloud || readAloudButton) && boundReadAloudButton,
6501
7639
  (onRegenerate || regenerateButton) && boundRegenerateButton,
6502
7640
  additionalToolbarItems,
@@ -6510,11 +7648,31 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, o
6510
7648
  const hasContent = !!(message.content && message.content.trim().length > 0);
6511
7649
  const isLatestAssistantMessage = message.role === "assistant" && (isLatest ?? messages?.[messages.length - 1]?.id === message.id);
6512
7650
  const shouldShowToolbar = toolbarVisible && (hasContent || showInspectorShortcut) && !(isRunning && isLatestAssistantMessage);
6513
- if (children) return /* @__PURE__ */ jsx("div", {
7651
+ const { open: commentOpen, close: closeComment } = comment;
7652
+ useEffect(() => {
7653
+ if (!commentOpen) return;
7654
+ if (rating !== commentRating.current) closeComment({ save: false });
7655
+ else if (!shouldShowToolbar) closeComment();
7656
+ }, [
7657
+ commentOpen,
7658
+ shouldShowToolbar,
7659
+ rating,
7660
+ closeComment
7661
+ ]);
7662
+ const feedbackComment = feedback?.feedback && shouldShowToolbar && /* @__PURE__ */ jsx(FeedbackCommentPopover, {
7663
+ feedbackComment: feedbackCommentSlot,
7664
+ comment,
7665
+ savedComment: feedback.feedback.comment ?? "",
7666
+ rating: feedback.feedback.rating,
7667
+ anchor: commentAnchor,
7668
+ messageId: message.id
7669
+ });
7670
+ if (children) return /* @__PURE__ */ jsxs("div", {
7671
+ ref: root,
6514
7672
  "data-copilotkit": true,
6515
7673
  "data-message-id": message.id,
6516
7674
  style: { display: "contents" },
6517
- children: children({
7675
+ children: [children({
6518
7676
  markdownRenderer: boundMarkdownRenderer,
6519
7677
  toolbar: boundToolbar,
6520
7678
  toolCallsView: boundToolCallsView,
@@ -6533,21 +7691,26 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, o
6533
7691
  onRegenerate,
6534
7692
  additionalToolbarItems,
6535
7693
  toolbarVisible: shouldShowToolbar
6536
- })
7694
+ }), feedbackComment]
6537
7695
  });
6538
7696
  return /* @__PURE__ */ jsxs("div", {
7697
+ ref: root,
6539
7698
  "data-copilotkit": true,
6540
7699
  "data-testid": "copilot-assistant-message",
6541
7700
  className: twMerge("copilotKitMessage copilotKitAssistantMessage", className),
6542
7701
  ...props,
6543
7702
  "data-message-id": message.id,
6544
7703
  children: [
6545
- /* @__PURE__ */ jsx("div", {
6546
- className: "cpk:prose cpk:max-w-full cpk:break-words cpk:dark:prose-invert",
6547
- children: boundMarkdownRenderer
7704
+ /* @__PURE__ */ jsx(WorkText, {
7705
+ messageId: message.id,
7706
+ children: /* @__PURE__ */ jsx("div", {
7707
+ className: "cpk:prose cpk:max-w-full cpk:break-words cpk:dark:prose-invert",
7708
+ children: boundMarkdownRenderer
7709
+ })
6548
7710
  }),
6549
7711
  boundToolCallsView,
6550
- shouldShowToolbar && boundToolbar
7712
+ shouldShowToolbar && boundToolbar,
7713
+ feedbackComment
6551
7714
  ]
6552
7715
  });
6553
7716
  }
@@ -6563,20 +7726,27 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, o
6563
7726
  ...props
6564
7727
  });
6565
7728
  const ToolbarButton = _CopilotChatAssistantMessage.ToolbarButton = ({ title, tooltip, tooltipClassName, children, ...props }) => {
6566
- return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
6567
- asChild: true,
6568
- children: /* @__PURE__ */ jsx(Button, {
6569
- type: "button",
6570
- variant: "assistantMessageToolbarButton",
6571
- "aria-label": title,
6572
- ...props,
6573
- children
6574
- })
6575
- }), /* @__PURE__ */ jsx(TooltipContent, {
6576
- side: "bottom",
6577
- className: tooltipClassName,
6578
- children: tooltip ?? /* @__PURE__ */ jsx("p", { children: title })
6579
- })] });
7729
+ const [tooltipOpen, setTooltipOpen] = useState(false);
7730
+ const popupOpen = props["aria-expanded"] === true;
7731
+ if (popupOpen && tooltipOpen) setTooltipOpen(false);
7732
+ return /* @__PURE__ */ jsxs(Tooltip, {
7733
+ open: tooltipOpen && !popupOpen,
7734
+ onOpenChange: (open) => setTooltipOpen(open && !popupOpen),
7735
+ children: [/* @__PURE__ */ jsx(TooltipTrigger, {
7736
+ asChild: true,
7737
+ children: /* @__PURE__ */ jsx(Button, {
7738
+ type: "button",
7739
+ variant: "assistantMessageToolbarButton",
7740
+ "aria-label": title,
7741
+ ...props,
7742
+ children
7743
+ })
7744
+ }), /* @__PURE__ */ jsx(TooltipContent, {
7745
+ side: "bottom",
7746
+ className: tooltipClassName,
7747
+ children: tooltip ?? /* @__PURE__ */ jsx("p", { children: title })
7748
+ })]
7749
+ });
6580
7750
  };
6581
7751
  _CopilotChatAssistantMessage.CopyButton = ({ className, title, onClick, ...props }) => {
6582
7752
  const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
@@ -6615,7 +7785,10 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, o
6615
7785
  "data-testid": "copilot-thumbs-up-button",
6616
7786
  title: title || labels.assistantMessageToolbarThumbsUpLabel,
6617
7787
  ...props,
6618
- children: /* @__PURE__ */ jsx(ThumbsUp, { className: "cpk:size-[18px]" })
7788
+ children: /* @__PURE__ */ jsx(ThumbsUp, {
7789
+ className: "cpk:size-[18px]",
7790
+ fill: props["aria-pressed"] === true ? "currentColor" : "none"
7791
+ })
6619
7792
  });
6620
7793
  };
6621
7794
  _CopilotChatAssistantMessage.ThumbsDownButton = ({ title, ...props }) => {
@@ -6624,7 +7797,45 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, o
6624
7797
  "data-testid": "copilot-thumbs-down-button",
6625
7798
  title: title || labels.assistantMessageToolbarThumbsDownLabel,
6626
7799
  ...props,
6627
- children: /* @__PURE__ */ jsx(ThumbsDown, { className: "cpk:size-[18px]" })
7800
+ children: /* @__PURE__ */ jsx(ThumbsDown, {
7801
+ className: "cpk:size-[18px]",
7802
+ fill: props["aria-pressed"] === true ? "currentColor" : "none"
7803
+ })
7804
+ });
7805
+ };
7806
+ _CopilotChatAssistantMessage.FeedbackComment = ({ value, savedComment, inputRef, onChange, onSubmit, onEditingChange, onLeave, className }) => {
7807
+ const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
7808
+ const changed = value.trim() !== savedComment;
7809
+ return /* @__PURE__ */ jsxs("form", {
7810
+ "data-testid": "copilot-feedback-comment",
7811
+ className: twMerge("cpk:flex cpk:w-80 cpk:max-w-[calc(100vw-1rem)] cpk:items-center cpk:gap-1 cpk:rounded-full cpk:border cpk:border-border cpk:bg-background cpk:py-0.5 cpk:pl-3 cpk:pr-0.5 cpk:text-sm cpk:shadow-md", className),
7812
+ onSubmit: (event) => {
7813
+ event.preventDefault();
7814
+ onSubmit();
7815
+ },
7816
+ onFocus: () => onEditingChange?.(true),
7817
+ onBlur: (event) => {
7818
+ const next = event.relatedTarget instanceof Element ? event.relatedTarget : null;
7819
+ if (event.currentTarget.contains(next)) return;
7820
+ if (typeof document !== "undefined" && !document.hasFocus()) return;
7821
+ onEditingChange?.(false);
7822
+ onLeave?.(next);
7823
+ },
7824
+ children: [/* @__PURE__ */ jsx("input", {
7825
+ ref: inputRef,
7826
+ value,
7827
+ maxLength: MESSAGE_FEEDBACK_MAX_COMMENT_LENGTH,
7828
+ onChange: (event) => onChange(event.target.value),
7829
+ placeholder: labels.assistantMessageFeedbackCommentPlaceholder,
7830
+ "aria-label": labels.assistantMessageFeedbackCommentPlaceholder,
7831
+ className: "cpk:min-w-0 cpk:flex-1 cpk:bg-transparent cpk:py-1 cpk:text-foreground cpk:outline-none cpk:placeholder:text-muted-foreground"
7832
+ }), changed && /* @__PURE__ */ jsx(Button, {
7833
+ type: "submit",
7834
+ variant: "assistantMessageToolbarButton",
7835
+ "aria-label": labels.assistantMessageFeedbackCommentSubmitLabel,
7836
+ title: labels.assistantMessageFeedbackCommentSubmitLabel,
7837
+ children: /* @__PURE__ */ jsx(ArrowUp, { className: "cpk:size-[16px]" })
7838
+ })]
6628
7839
  });
6629
7840
  };
6630
7841
  _CopilotChatAssistantMessage.ReadAloudButton = ({ title, ...props }) => {
@@ -6652,6 +7863,7 @@ CopilotChatAssistantMessage.CopyButton.displayName = "CopilotChatAssistantMessag
6652
7863
  CopilotChatAssistantMessage.InspectorButton.displayName = "CopilotChatAssistantMessage.InspectorButton";
6653
7864
  CopilotChatAssistantMessage.ThumbsUpButton.displayName = "CopilotChatAssistantMessage.ThumbsUpButton";
6654
7865
  CopilotChatAssistantMessage.ThumbsDownButton.displayName = "CopilotChatAssistantMessage.ThumbsDownButton";
7866
+ CopilotChatAssistantMessage.FeedbackComment.displayName = "CopilotChatAssistantMessage.FeedbackComment";
6655
7867
  CopilotChatAssistantMessage.ReadAloudButton.displayName = "CopilotChatAssistantMessage.ReadAloudButton";
6656
7868
  CopilotChatAssistantMessage.RegenerateButton.displayName = "CopilotChatAssistantMessage.RegenerateButton";
6657
7869
  var CopilotChatAssistantMessage_default = CopilotChatAssistantMessage;
@@ -6957,6 +8169,7 @@ function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfB
6957
8169
  });
6958
8170
  };
6959
8171
  _CopilotChatUserMessage.BranchNavigation = ({ className, currentBranch = 0, numberOfBranches = 1, onSwitchToBranch, message, ...props }) => {
8172
+ const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
6960
8173
  if (!numberOfBranches || numberOfBranches <= 1 || !onSwitchToBranch) return null;
6961
8174
  const canGoPrev = currentBranch > 0;
6962
8175
  const canGoNext = currentBranch < numberOfBranches - 1;
@@ -6975,6 +8188,7 @@ function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfB
6975
8188
  }),
6976
8189
  disabled: !canGoPrev,
6977
8190
  className: "cpk:h-6 cpk:w-6 cpk:p-0",
8191
+ "aria-label": labels.userMessageToolbarPreviousBranchLabel,
6978
8192
  children: /* @__PURE__ */ jsx(ChevronLeft, { className: "cpk:size-[20px]" })
6979
8193
  }),
6980
8194
  /* @__PURE__ */ jsxs("span", {
@@ -6995,6 +8209,7 @@ function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfB
6995
8209
  }),
6996
8210
  disabled: !canGoNext,
6997
8211
  className: "cpk:h-6 cpk:w-6 cpk:p-0",
8212
+ "aria-label": labels.userMessageToolbarNextBranchLabel,
6998
8213
  children: /* @__PURE__ */ jsx(ChevronRight, { className: "cpk:size-[20px]" })
6999
8214
  })
7000
8215
  ]
@@ -7015,7 +8230,7 @@ var CopilotChatUserMessage_default = CopilotChatUserMessage;
7015
8230
  /**
7016
8231
  * Formats an elapsed duration (in seconds) to a human-readable string.
7017
8232
  */
7018
- function formatDuration(seconds) {
8233
+ function formatDuration$1(seconds) {
7019
8234
  if (seconds < 1) return "a few seconds";
7020
8235
  if (seconds < 60) return `${Math.round(seconds)} seconds`;
7021
8236
  const mins = Math.floor(seconds / 60);
@@ -7053,7 +8268,7 @@ function CopilotChatReasoningMessage({ message, messages, isRunning, isLatest: i
7053
8268
  userToggledRef.current = true;
7054
8269
  setIsOpen((prev) => !prev);
7055
8270
  } : void 0;
7056
- const label = isStreaming ? "Thinking…" : `Thought for ${formatDuration(elapsed)}`;
8271
+ const label = isStreaming ? "Thinking…" : `Thought for ${formatDuration$1(elapsed)}`;
7057
8272
  const boundHeader = renderSlot(header, CopilotChatReasoningMessage.Header, {
7058
8273
  isOpen,
7059
8274
  label,
@@ -7275,6 +8490,71 @@ const ScrollElementContext = React.createContext(null);
7275
8490
  */
7276
8491
  const ScrollPinnedContext = React.createContext(false);
7277
8492
 
8493
+ //#endregion
8494
+ //#region src/v2/components/chat/CopilotChatWorkSummary.tsx
8495
+ /** "45s", "1m 5s", "2m". Used for the live timer and the final duration. */
8496
+ function formatDuration(ms) {
8497
+ const seconds = Math.max(0, Math.floor(ms / 1e3));
8498
+ if (seconds < 60) return `${seconds}s`;
8499
+ const minutes = Math.floor(seconds / 60);
8500
+ const rest = seconds % 60;
8501
+ return rest ? `${minutes}m ${rest}s` : `${minutes}m`;
8502
+ }
8503
+ /** Re-renders every second while `active`, returning the current time. */
8504
+ function useNow(active) {
8505
+ const [now, setNow] = useState(() => Date.now());
8506
+ useEffect(() => {
8507
+ if (!active) return;
8508
+ setNow(Date.now());
8509
+ const timer = setInterval(() => setNow(Date.now()), 1e3);
8510
+ return () => clearInterval(timer);
8511
+ }, [active]);
8512
+ return now;
8513
+ }
8514
+ /**
8515
+ * The line at the top of a reply in the `"turn"` tool-call display. While the
8516
+ * agent works it reads "Working 4s"; once the reply is done it reads "Worked
8517
+ * for 9s · 7 tools" and toggles the work it folded away.
8518
+ */
8519
+ function CopilotChatWorkSummary({ isWorking, isOpen, calls, elapsedMs, workingSince, className, ...props }) {
8520
+ const now = useNow(isWorking);
8521
+ const failed = calls.filter((call) => call.toolMessage?.error).length;
8522
+ const liveMs = elapsedMs !== void 0 && workingSince !== void 0 ? elapsedMs + Math.max(0, now - workingSince) : void 0;
8523
+ const duration = elapsedMs !== void 0 ? formatDuration(Math.max(1e3, elapsedMs)) : void 0;
8524
+ return /* @__PURE__ */ jsxs("button", {
8525
+ type: "button",
8526
+ "data-copilotkit": true,
8527
+ "data-testid": "copilot-work-summary",
8528
+ "data-state": isWorking ? "working" : "done",
8529
+ "aria-expanded": isOpen,
8530
+ className: twMerge("cpk:m-0 cpk:inline-flex cpk:max-w-full cpk:cursor-pointer cpk:items-center cpk:gap-1.5 cpk:rounded-md cpk:border-none cpk:bg-transparent cpk:p-0 cpk:py-0.5 cpk:text-sm cpk:text-muted-foreground cpk:transition-colors cpk:hover:text-foreground cpk:focus-visible:outline-2 cpk:focus-visible:outline-ring", className),
8531
+ ...props,
8532
+ children: [isWorking ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
8533
+ className: "cpk:font-medium cpk-shimmer",
8534
+ children: "Working"
8535
+ }), liveMs !== void 0 && /* @__PURE__ */ jsx("span", {
8536
+ className: "cpk:text-xs cpk:tabular-nums cpk:opacity-70",
8537
+ children: formatDuration(liveMs)
8538
+ })] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
8539
+ /* @__PURE__ */ jsx("span", {
8540
+ className: "cpk:font-medium",
8541
+ children: duration ? `Worked for ${duration}` : `Used ${pluralize(calls.length, "tool")}`
8542
+ }),
8543
+ duration && /* @__PURE__ */ jsx("span", {
8544
+ className: "cpk:text-xs cpk:opacity-70",
8545
+ children: pluralize(calls.length, "tool")
8546
+ }),
8547
+ failed > 0 && /* @__PURE__ */ jsxs("span", {
8548
+ className: "cpk:text-destructive",
8549
+ children: [failed, " failed"]
8550
+ })
8551
+ ] }), /* @__PURE__ */ jsx(ChevronRight, {
8552
+ "aria-hidden": "true",
8553
+ className: twMerge("cpk:size-3.5 cpk:shrink-0 cpk:transition-transform cpk:duration-200", isOpen && "cpk:rotate-90")
8554
+ })]
8555
+ });
8556
+ }
8557
+
7278
8558
  //#endregion
7279
8559
  //#region src/v2/components/intelligence-indicator/IntelligenceIndicatorView.tsx
7280
8560
  /**
@@ -7761,7 +9041,7 @@ function messageGroup(group) {
7761
9041
  }
7762
9042
  const GROUP_ROW_KEY_PREFIX = "copilotkit-group:";
7763
9043
  const VIRTUALIZE_THRESHOLD = 50;
7764
- function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, intelligenceIndicator, isRunning = false, transformMessages, groupMessages, children, className, ...props }) {
9044
+ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, intelligenceIndicator, workSummary, isRunning = false, transformMessages, groupMessages, messageFeedback = true, toolCallDisplay = "grouped", children, className, ...props }) {
7765
9045
  const isPinnedToBottom = useContext(ScrollPinnedContext);
7766
9046
  const renderCustomMessage = useRenderCustomMessages();
7767
9047
  const { renderActivityMessage } = useRenderActivityMessage();
@@ -7802,6 +9082,100 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7802
9082
  transformedMessages
7803
9083
  ]);
7804
9084
  const latestRenderedId = renderedMessages[renderedMessages.length - 1]?.id;
9085
+ const rendererNames = useToolCallRendererNames();
9086
+ const toolCallLayouts = useMemo(() => toolCallDisplay === "separate" ? /* @__PURE__ */ new Map() : getToolCallLayouts(renderedMessages, messages, rendererNames), [
9087
+ toolCallDisplay,
9088
+ renderedMessages,
9089
+ messages,
9090
+ rendererNames
9091
+ ]);
9092
+ const turnWork = useMemo(() => toolCallDisplay === "turn" ? getTurnWork(renderedMessages, toolCallLayouts) : void 0, [
9093
+ toolCallDisplay,
9094
+ renderedMessages,
9095
+ toolCallLayouts
9096
+ ]);
9097
+ const turnByFirstMessage = useMemo(() => {
9098
+ const byFirst = /* @__PURE__ */ new Map();
9099
+ for (const turn of turnWork?.values() ?? []) byFirst.set(turn.firstMessageId, turn);
9100
+ return byFirst;
9101
+ }, [turnWork]);
9102
+ let latestTurnKey = "start";
9103
+ for (let i = renderedMessages.length - 1; i >= 0; i--) if (renderedMessages[i].role === "user") {
9104
+ latestTurnKey = renderedMessages[i].id;
9105
+ break;
9106
+ }
9107
+ const isWorkingOn = (turnKey) => isRunning && turnKey === latestTurnKey;
9108
+ const [toggledTurns, setToggledTurns] = useState(() => /* @__PURE__ */ new Map());
9109
+ const isWorkOpen = (turnKey) => toggledTurns.get(turnKey) ?? isWorkingOn(turnKey);
9110
+ const workTimesRef = useRef(/* @__PURE__ */ new Map());
9111
+ if (toolCallDisplay === "turn") {
9112
+ const now = Date.now();
9113
+ const workTimes = workTimesRef.current;
9114
+ if (isRunning) {
9115
+ const times = workTimes.get(latestTurnKey);
9116
+ if (times) times.workingSince ??= now;
9117
+ else if (renderedMessages[renderedMessages.length - 1]?.role === "user") workTimes.set(latestTurnKey, {
9118
+ elapsedMs: 0,
9119
+ workingSince: now
9120
+ });
9121
+ } else for (const times of workTimes.values()) {
9122
+ if (times.workingSince === void 0) continue;
9123
+ times.elapsedMs += now - times.workingSince;
9124
+ times.workingSince = void 0;
9125
+ }
9126
+ }
9127
+ const { workOpen, workTextOpen } = useMemo(() => {
9128
+ const open = /* @__PURE__ */ new Map();
9129
+ const textOpen = /* @__PURE__ */ new Map();
9130
+ for (const turn of turnWork?.values() ?? []) {
9131
+ const turnOpen = toggledTurns.get(turn.key) ?? (isRunning && turn.key === latestTurnKey);
9132
+ for (const id of turn.workMessageIds) {
9133
+ open.set(id, turnOpen);
9134
+ if (id !== turn.replyTextMessageId) textOpen.set(id, turnOpen);
9135
+ }
9136
+ }
9137
+ return {
9138
+ workOpen: open,
9139
+ workTextOpen: textOpen
9140
+ };
9141
+ }, [
9142
+ turnWork,
9143
+ toggledTurns,
9144
+ isRunning,
9145
+ latestTurnKey
9146
+ ]);
9147
+ const toolCallDisplayContext = useMemo(() => ({
9148
+ display: toolCallDisplay,
9149
+ isRunning,
9150
+ layouts: toolCallLayouts,
9151
+ workOpen,
9152
+ workTextOpen
9153
+ }), [
9154
+ toolCallDisplay,
9155
+ isRunning,
9156
+ toolCallLayouts,
9157
+ workOpen,
9158
+ workTextOpen
9159
+ ]);
9160
+ const renderWorkSummary = (turnKey, calls) => {
9161
+ const working = isWorkingOn(turnKey);
9162
+ const open = isWorkOpen(turnKey);
9163
+ const times = workTimesRef.current.get(turnKey);
9164
+ return /* @__PURE__ */ jsx(Collapsible, {
9165
+ open: working || calls.length > 0,
9166
+ children: /* @__PURE__ */ jsx("div", {
9167
+ className: "cpk:pt-1 cpk:pb-2",
9168
+ children: renderSlot(workSummary, CopilotChatWorkSummary, {
9169
+ isWorking: working,
9170
+ isOpen: open,
9171
+ calls,
9172
+ elapsedMs: times?.elapsedMs,
9173
+ workingSince: times?.workingSince,
9174
+ onClick: () => setToggledTurns((toggled) => new Map(toggled).set(turnKey, !open))
9175
+ })
9176
+ })
9177
+ }, `work-summary-${turnKey}`);
9178
+ };
7805
9179
  const transformDuplicateId = useMemo(() => {
7806
9180
  if (process.env.NODE_ENV === "production" || !transformMessages && !groupMessages) return;
7807
9181
  const seen = /* @__PURE__ */ new Set();
@@ -7839,8 +9213,6 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7839
9213
  commitRowKeyStore(rowKeyStore, renderedMessages);
7840
9214
  }, [rowKeyStore, renderedMessages]);
7841
9215
  const stableGroupKey = (key) => rowRenderKeys.get(key) ?? key;
7842
- const rowKey = (row) => row.type === "group" ? `${GROUP_ROW_KEY_PREFIX}${stableGroupKey(row.key)}` : rowRenderKeys.get(row.message.id) ?? row.message.id;
7843
- const rowKeys = useMemo(() => rows.map(rowKey), [rows, rowRenderKeys]);
7844
9216
  const groupStateRef = useRef(/* @__PURE__ */ new Map());
7845
9217
  const groupSettersRef = useRef(/* @__PURE__ */ new Map());
7846
9218
  const groupStateThreadRef = useRef(config?.threadId);
@@ -7869,6 +9241,18 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7869
9241
  const { Component: AssistantComponent, slotProps: assistantSlotProps } = useMemo(() => resolveSlotComponent(assistantMessage, CopilotChatAssistantMessage_default), [assistantMessage]);
7870
9242
  const agentId = config?.agentId;
7871
9243
  const threadId = config?.threadId;
9244
+ const learningFeedbackEnabled = useLearningFeedbackEnabled(copilotkit);
9245
+ const feedbackScope = useMemo(() => messageFeedback && learningFeedbackEnabled && agentId !== void 0 && threadId !== void 0 ? {
9246
+ copilotkit,
9247
+ agentId,
9248
+ threadId
9249
+ } : null, [
9250
+ messageFeedback,
9251
+ learningFeedbackEnabled,
9252
+ copilotkit,
9253
+ agentId,
9254
+ threadId
9255
+ ]);
7872
9256
  const assistantSlotPropsWithFeedback = useMemo(() => {
7873
9257
  const onThumbsUp = assistantSlotProps?.onThumbsUp;
7874
9258
  const onThumbsDown = assistantSlotProps?.onThumbsDown;
@@ -7914,8 +9298,6 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7914
9298
  total: 0,
7915
9299
  sizes: /* @__PURE__ */ new Map()
7916
9300
  });
7917
- const rowKeysRef = React.useRef(rowKeys);
7918
- rowKeysRef.current = rowKeys;
7919
9301
  const firstMessageId = deduplicatedMessages[0]?.id;
7920
9302
  const measuredThreadRef = React.useRef(firstMessageId);
7921
9303
  if (measuredThreadRef.current !== firstMessageId) {
@@ -7925,16 +9307,6 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7925
9307
  sizes: /* @__PURE__ */ new Map()
7926
9308
  };
7927
9309
  }
7928
- const measuredKeysRef = React.useRef(rowKeys);
7929
- if (measuredKeysRef.current !== rowKeys) {
7930
- measuredKeysRef.current = rowKeys;
7931
- const live = new Set(rowKeys);
7932
- const measured = measuredRef.current;
7933
- for (const [key, height] of measured.sizes) if (!live.has(key)) {
7934
- measured.sizes.delete(key);
7935
- measured.total -= height;
7936
- }
7937
- }
7938
9310
  const estimateRowSize = React.useCallback(() => {
7939
9311
  const { total, sizes } = measuredRef.current;
7940
9312
  return sizes.size > 0 ? Math.max(1, Math.round(total / sizes.size)) : 100;
@@ -7942,15 +9314,13 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7942
9314
  const measureRowElement = React.useCallback((el) => {
7943
9315
  const height = el?.getBoundingClientRect().height ?? 0;
7944
9316
  const index = Number(el?.dataset?.index);
7945
- const key = Number.isInteger(index) ? rowKeysRef.current[index] : void 0;
7946
- if (height > 0 && key !== void 0) {
9317
+ if (height > 0 && Number.isInteger(index)) {
7947
9318
  const { total, sizes } = measuredRef.current;
7948
- measuredRef.current.total = total - (sizes.get(key) ?? 0) + height;
7949
- sizes.set(key, height);
9319
+ measuredRef.current.total = total - (sizes.get(index) ?? 0) + height;
9320
+ sizes.set(index, height);
7950
9321
  }
7951
- return height;
9322
+ return height > 0 ? height : measuredRef.current.sizes.get(index) ?? 100;
7952
9323
  }, []);
7953
- const getRowKey = React.useCallback((index) => rowKeys[index] ?? index, [rowKeys]);
7954
9324
  const isPinnedToBottomRef = React.useRef(isPinnedToBottom);
7955
9325
  const shouldAdjustScrollOnResize = React.useCallback((item, _delta, instance) => {
7956
9326
  if (isPinnedToBottomRef.current) return false;
@@ -7959,9 +9329,8 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7959
9329
  }, []);
7960
9330
  const virtualizer = useVirtualizer({
7961
9331
  count: shouldVirtualize ? rows.length : 0,
7962
- getScrollElement: () => scrollElement,
9332
+ getScrollElement: () => shouldVirtualize ? scrollElement : null,
7963
9333
  estimateSize: estimateRowSize,
7964
- getItemKey: getRowKey,
7965
9334
  overscan: 5,
7966
9335
  measureElement: measureRowElement,
7967
9336
  initialRect: {
@@ -7971,8 +9340,11 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7971
9340
  });
7972
9341
  isPinnedToBottomRef.current = isPinnedToBottom;
7973
9342
  virtualizer.shouldAdjustScrollPositionOnItemSizeChange = shouldAdjustScrollOnResize;
9343
+ const lastEndAlignedFirstMessageRef = React.useRef(void 0);
7974
9344
  useLayoutEffect(() => {
7975
9345
  if (!shouldVirtualize || !rows.length) return;
9346
+ if (lastEndAlignedFirstMessageRef.current === firstMessageId) return;
9347
+ lastEndAlignedFirstMessageRef.current = firstMessageId;
7976
9348
  virtualizer.scrollToIndex(rows.length - 1, { align: "end" });
7977
9349
  }, [shouldVirtualize, firstMessageId]);
7978
9350
  const intelligenceTurnAnchors = useMemo(() => getIntelligenceTurnAnchors(deduplicatedMessages, renderedMessages), [deduplicatedMessages, renderedMessages]);
@@ -7980,6 +9352,8 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7980
9352
  const elements = [];
7981
9353
  const stateSnapshot = renderCustomMessage ? getStateSnapshotForMessage(message.id) : void 0;
7982
9354
  const rowKey = rowRenderKeys.get(message.id) ?? message.id;
9355
+ const turn = turnByFirstMessage.get(message.id);
9356
+ if (turn) elements.push(renderWorkSummary(turn.key, turn.calls));
7983
9357
  if (renderCustomMessage) elements.push(/* @__PURE__ */ jsx(MemoizedCustomMessage, {
7984
9358
  message,
7985
9359
  position: "before",
@@ -8003,14 +9377,20 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
8003
9377
  message,
8004
9378
  renderActivityMessage
8005
9379
  }, rowKey));
8006
- else if (message.role === "reasoning") elements.push(/* @__PURE__ */ jsx(MemoizedReasoningMessage, {
8007
- message,
8008
- messages,
8009
- isRunning,
8010
- isLatest: message.id === latestRenderedId,
8011
- ReasoningMessageComponent: ReasoningComponent,
8012
- slotProps: reasoningSlotProps
8013
- }, rowKey));
9380
+ else if (message.role === "reasoning") {
9381
+ const reasoning = /* @__PURE__ */ jsx(MemoizedReasoningMessage, {
9382
+ message,
9383
+ messages,
9384
+ isRunning,
9385
+ isLatest: message.id === latestRenderedId,
9386
+ ReasoningMessageComponent: ReasoningComponent,
9387
+ slotProps: reasoningSlotProps
9388
+ }, rowKey);
9389
+ elements.push(toolCallDisplay === "turn" ? /* @__PURE__ */ jsx(Collapsible, {
9390
+ open: workOpen.get(message.id) ?? true,
9391
+ children: reasoning
9392
+ }, rowKey) : reasoning);
9393
+ }
8014
9394
  if (renderCustomMessage) elements.push(/* @__PURE__ */ jsx(MemoizedCustomMessage, {
8015
9395
  message,
8016
9396
  position: "after",
@@ -8025,6 +9405,7 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
8025
9405
  }, `intelligence-${intelligenceTurnId}`));
8026
9406
  return elements.filter(Boolean);
8027
9407
  };
9408
+ const rowKey = (row) => row.type === "group" ? `${GROUP_ROW_KEY_PREFIX}${stableGroupKey(row.key)}` : rowRenderKeys.get(row.message.id) ?? row.message.id;
8028
9409
  const renderRow = (row) => {
8029
9410
  if (row.type === "message") return renderMessageBlock(row.message);
8030
9411
  const Wrapper = row.wrapper;
@@ -8037,52 +9418,157 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
8037
9418
  children: row.messages.flatMap(renderMessageBlock)
8038
9419
  }, rowKey(row))];
8039
9420
  };
9421
+ const rowKeysRef = useRef([]);
9422
+ rowKeysRef.current = rows.map(rowKey);
9423
+ const virtualModeRef = useRef(shouldVirtualize);
9424
+ virtualModeRef.current = shouldVirtualize;
9425
+ useEffect(() => {
9426
+ const element = scrollElementFromCtx;
9427
+ if (!element) return;
9428
+ let anchor = null;
9429
+ let suspended = false;
9430
+ let frame = 0;
9431
+ const visibleRows = () => Array.from(element.querySelectorAll("[data-scroll-anchor]"));
9432
+ const remember = () => {
9433
+ if (suspended || element.clientHeight === 0 || !virtualModeRef.current) return;
9434
+ if (isPinnedToBottomRef.current) {
9435
+ anchor = null;
9436
+ return;
9437
+ }
9438
+ const viewport = element.getBoundingClientRect();
9439
+ const row = visibleRows().find((row) => {
9440
+ const bounds = row.getBoundingClientRect();
9441
+ return bounds.bottom > viewport.top && bounds.top < viewport.bottom;
9442
+ });
9443
+ if (row) anchor = {
9444
+ key: row.dataset.scrollAnchor,
9445
+ offset: row.getBoundingClientRect().top - viewport.top
9446
+ };
9447
+ };
9448
+ const observer = new ResizeObserver(() => {
9449
+ if (element.clientHeight === 0) {
9450
+ suspended = true;
9451
+ cancelAnimationFrame(frame);
9452
+ return;
9453
+ }
9454
+ if (!suspended || !anchor) {
9455
+ suspended = false;
9456
+ remember();
9457
+ return;
9458
+ }
9459
+ let attempts = 0;
9460
+ let stableFrames = 0;
9461
+ const restore = () => {
9462
+ if (!anchor || element.clientHeight === 0) return;
9463
+ const index = rowKeysRef.current.indexOf(anchor.key);
9464
+ if (index < 0) {
9465
+ anchor = null;
9466
+ suspended = false;
9467
+ return;
9468
+ }
9469
+ const row = visibleRows().find((row) => row.dataset.scrollAnchor === anchor.key);
9470
+ if (row) {
9471
+ const delta = row.getBoundingClientRect().top - element.getBoundingClientRect().top - anchor.offset;
9472
+ element.scrollTop += delta;
9473
+ stableFrames = Math.abs(delta) < 1 ? stableFrames + 1 : 0;
9474
+ } else {
9475
+ const offset = virtualizer.getOffsetForIndex(index, "start")?.[0];
9476
+ if (offset !== void 0) virtualizer.scrollToOffset(offset - anchor.offset);
9477
+ stableFrames = 0;
9478
+ }
9479
+ if (++attempts < 60 && stableFrames < 3) frame = requestAnimationFrame(restore);
9480
+ else {
9481
+ suspended = false;
9482
+ remember();
9483
+ }
9484
+ };
9485
+ frame = requestAnimationFrame(restore);
9486
+ });
9487
+ const interrupt = () => {
9488
+ cancelAnimationFrame(frame);
9489
+ anchor = null;
9490
+ suspended = false;
9491
+ };
9492
+ element.addEventListener("scroll", remember, { passive: true });
9493
+ element.addEventListener("wheel", interrupt, { passive: true });
9494
+ element.addEventListener("touchstart", interrupt, { passive: true });
9495
+ element.addEventListener("keydown", interrupt);
9496
+ observer.observe(element);
9497
+ remember();
9498
+ return () => {
9499
+ cancelAnimationFrame(frame);
9500
+ observer.disconnect();
9501
+ element.removeEventListener("scroll", remember);
9502
+ element.removeEventListener("wheel", interrupt);
9503
+ element.removeEventListener("touchstart", interrupt);
9504
+ element.removeEventListener("keydown", interrupt);
9505
+ };
9506
+ }, [
9507
+ scrollElementFromCtx,
9508
+ virtualizer,
9509
+ firstMessageId
9510
+ ]);
8040
9511
  const messageElements = shouldVirtualize ? [] : rows.flatMap(renderRow);
8041
- if (children) return /* @__PURE__ */ jsx("div", {
8042
- "data-copilotkit": true,
8043
- style: { display: "contents" },
8044
- children: children({
8045
- messageElements,
8046
- messages,
8047
- isRunning,
8048
- interruptElement
9512
+ if (children) return /* @__PURE__ */ jsx(MessageFeedbackScopeContext.Provider, {
9513
+ value: feedbackScope,
9514
+ children: /* @__PURE__ */ jsx(ToolCallDisplayContext.Provider, {
9515
+ value: toolCallDisplayContext,
9516
+ children: /* @__PURE__ */ jsx("div", {
9517
+ "data-copilotkit": true,
9518
+ style: { display: "contents" },
9519
+ children: children({
9520
+ messageElements,
9521
+ messages,
9522
+ isRunning,
9523
+ interruptElement
9524
+ })
9525
+ })
8049
9526
  })
8050
9527
  });
8051
9528
  const lastMessage = renderedMessages[renderedMessages.length - 1];
8052
- const showCursor = isRunning && lastMessage?.role !== "reasoning";
8053
- return /* @__PURE__ */ jsxs("div", {
8054
- "data-copilotkit": true,
8055
- "data-testid": "copilot-message-list",
8056
- className: twMerge("copilotKitMessages cpk:flex cpk:flex-col", className),
8057
- ...props,
8058
- children: [
8059
- shouldVirtualize ? /* @__PURE__ */ jsx("div", {
8060
- style: {
8061
- height: virtualizer.getTotalSize(),
8062
- position: "relative"
8063
- },
8064
- children: virtualizer.getVirtualItems().map((virtualItem) => {
8065
- const row = rows[virtualItem.index];
8066
- return /* @__PURE__ */ jsx("div", {
8067
- "data-index": virtualItem.index,
8068
- ref: virtualizer.measureElement,
9529
+ const showCursor = isRunning && lastMessage?.role !== "reasoning" && toolCallDisplay !== "turn";
9530
+ const pendingWorkSummary = toolCallDisplay === "turn" && isRunning && lastMessage?.role === "user";
9531
+ return /* @__PURE__ */ jsx(MessageFeedbackScopeContext.Provider, {
9532
+ value: feedbackScope,
9533
+ children: /* @__PURE__ */ jsx(ToolCallDisplayContext.Provider, {
9534
+ value: toolCallDisplayContext,
9535
+ children: /* @__PURE__ */ jsxs("div", {
9536
+ "data-copilotkit": true,
9537
+ "data-testid": "copilot-message-list",
9538
+ className: twMerge("copilotKitMessages cpk:flex cpk:flex-col", className),
9539
+ ...props,
9540
+ children: [
9541
+ shouldVirtualize ? /* @__PURE__ */ jsx("div", {
8069
9542
  style: {
8070
- position: "absolute",
8071
- top: 0,
8072
- left: 0,
8073
- width: "100%",
8074
- transform: `translateY(${virtualItem.start}px)`
9543
+ height: virtualizer.getTotalSize(),
9544
+ position: "relative"
8075
9545
  },
8076
- children: renderRow(row)
8077
- }, rowKey(row));
8078
- })
8079
- }) : messageElements,
8080
- interruptElement,
8081
- showCursor && /* @__PURE__ */ jsx("div", {
8082
- className: "cpk:mt-2",
8083
- children: renderSlot(cursor, CopilotChatMessageView.Cursor, {})
9546
+ children: virtualizer.getVirtualItems().map((virtualItem) => {
9547
+ const row = rows[virtualItem.index];
9548
+ return /* @__PURE__ */ jsx("div", {
9549
+ "data-index": virtualItem.index,
9550
+ "data-scroll-anchor": rowKey(row),
9551
+ ref: virtualizer.measureElement,
9552
+ style: {
9553
+ position: "absolute",
9554
+ top: 0,
9555
+ left: 0,
9556
+ width: "100%",
9557
+ transform: `translateY(${virtualItem.start}px)`
9558
+ },
9559
+ children: renderRow(row)
9560
+ }, rowKey(row));
9561
+ })
9562
+ }) : messageElements,
9563
+ interruptElement,
9564
+ pendingWorkSummary && renderWorkSummary(latestTurnKey, []),
9565
+ showCursor && /* @__PURE__ */ jsx("div", {
9566
+ className: "cpk:mt-2",
9567
+ children: renderSlot(cursor, CopilotChatMessageView.Cursor, {})
9568
+ })
9569
+ ]
8084
9570
  })
8085
- ]
9571
+ })
8086
9572
  });
8087
9573
  }
8088
9574
  CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
@@ -8467,6 +9953,16 @@ function DropOverlay() {
8467
9953
  });
8468
9954
  }
8469
9955
  function CopilotChatView({ messageView, input, scrollView, suggestionView, welcomeScreen, messages = [], autoScroll = true, isRunning = false, suggestions, suggestionLoadingIndexes, onSelectSuggestion, onSubmitMessage, onStop, inputMode, inputValue, onInputChange, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, attachments, onRemoveAttachment, onAddFile, dragOver, onDragOver, onDragLeave, onDrop, isConnecting = false, hasExplicitThreadId = false, disclaimer, intelligenceIndicator, children, className, ...props }) {
9956
+ const configuredThreadId = useCopilotChatConfiguration()?.threadId;
9957
+ const [fallbackThreadId, setFallbackThreadId] = useState(messages[0]?.id);
9958
+ const previousMessageIds = useRef(/* @__PURE__ */ new Set());
9959
+ useEffect(() => {
9960
+ if (messages.length === 0) return;
9961
+ const overlaps = messages.some((message) => previousMessageIds.current.has(message.id));
9962
+ previousMessageIds.current = new Set(messages.map((message) => message.id));
9963
+ if (!overlaps) setFallbackThreadId(messages[0].id);
9964
+ }, [messages]);
9965
+ const scrollThreadId = configuredThreadId ?? fallbackThreadId;
8470
9966
  const [inputContainerEl, setInputContainerEl] = useState(null);
8471
9967
  const [inputContainerHeight, setInputContainerHeight] = useState(0);
8472
9968
  const [isResizing, setIsResizing] = useState(false);
@@ -8533,6 +10029,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
8533
10029
  }) : null;
8534
10030
  const BoundScrollView = renderSlot(scrollView, CopilotChatView.ScrollView, {
8535
10031
  autoScroll,
10032
+ scrollThreadId,
8536
10033
  inputContainerHeight,
8537
10034
  isResizing,
8538
10035
  children: /* @__PURE__ */ jsx("div", {
@@ -8628,12 +10125,102 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
8628
10125
  });
8629
10126
  }
8630
10127
  (function(_CopilotChatView) {
8631
- const ScrollContent = ({ children, scrollToBottomButton, feather, inputContainerHeight, isResizing }) => {
8632
- const { isAtBottom, scrollToBottom, scrollRef, state } = useStickToBottomContext();
10128
+ const ScrollContent = ({ children, scrollToBottomButton, feather, inputContainerHeight, isResizing, scrollThreadId }) => {
10129
+ const { isAtBottom, scrollToBottom, stopScroll, scrollRef, state } = useStickToBottomContext();
8633
10130
  const [scrollEl, setScrollEl] = useState(null);
10131
+ const readingOffsetRef = useRef(null);
10132
+ const pinIntentRef = useRef(false);
10133
+ const stateRef = useRef(state);
10134
+ stateRef.current = state;
8634
10135
  useLayoutEffect(() => {
8635
10136
  setScrollEl(scrollRef.current ?? null);
8636
10137
  }, []);
10138
+ useEffect(() => {
10139
+ if (!scrollEl) return;
10140
+ let hidden = false;
10141
+ let resumeBottom = false;
10142
+ let pendingFrame = 0;
10143
+ let resumeFrame = 0;
10144
+ let settleFrame = 0;
10145
+ readingOffsetRef.current = null;
10146
+ const rememberScroll = () => {
10147
+ if (hidden || scrollEl.clientHeight === 0) return;
10148
+ if (resumeBottom) {
10149
+ readingOffsetRef.current = null;
10150
+ return;
10151
+ }
10152
+ if (pinIntentRef.current) if (stateRef.current.escapedFromLock) pinIntentRef.current = false;
10153
+ else {
10154
+ readingOffsetRef.current = null;
10155
+ if (!stateRef.current.isNearBottom) return;
10156
+ pinIntentRef.current = false;
10157
+ }
10158
+ readingOffsetRef.current = !stateRef.current.isAtBottom && (stateRef.current.escapedFromLock || !stateRef.current.isNearBottom) ? scrollEl.scrollTop : null;
10159
+ };
10160
+ const onScroll = () => {
10161
+ rememberScroll();
10162
+ cancelAnimationFrame(pendingFrame);
10163
+ pendingFrame = requestAnimationFrame(rememberScroll);
10164
+ };
10165
+ const onWheel = (event) => {
10166
+ if (event.deltaY < 0) {
10167
+ pinIntentRef.current = false;
10168
+ resumeBottom = false;
10169
+ }
10170
+ };
10171
+ const resizeObserver = new ResizeObserver(() => {
10172
+ if (scrollEl.clientHeight === 0) {
10173
+ hidden = true;
10174
+ resumeBottom = pinIntentRef.current || readingOffsetRef.current === null;
10175
+ if (!resumeBottom) stopScroll();
10176
+ } else if (hidden) {
10177
+ hidden = false;
10178
+ if (resumeBottom) {
10179
+ stopScroll();
10180
+ resumeFrame = requestAnimationFrame(() => {
10181
+ settleFrame = requestAnimationFrame(() => {
10182
+ if (scrollEl.clientHeight > 0 && resumeBottom) {
10183
+ resumeBottom = false;
10184
+ pinIntentRef.current = true;
10185
+ scrollToBottom({ animation: "instant" });
10186
+ }
10187
+ });
10188
+ });
10189
+ } else if (readingOffsetRef.current !== null) {
10190
+ stopScroll();
10191
+ scrollEl.scrollTop = readingOffsetRef.current;
10192
+ }
10193
+ }
10194
+ });
10195
+ rememberScroll();
10196
+ scrollEl.addEventListener("scroll", onScroll);
10197
+ scrollEl.addEventListener("wheel", onWheel, { passive: true });
10198
+ resizeObserver.observe(scrollEl);
10199
+ return () => {
10200
+ scrollEl.removeEventListener("scroll", onScroll);
10201
+ scrollEl.removeEventListener("wheel", onWheel);
10202
+ cancelAnimationFrame(pendingFrame);
10203
+ cancelAnimationFrame(resumeFrame);
10204
+ cancelAnimationFrame(settleFrame);
10205
+ resizeObserver.disconnect();
10206
+ };
10207
+ }, [
10208
+ scrollEl,
10209
+ scrollToBottom,
10210
+ stopScroll,
10211
+ scrollThreadId
10212
+ ]);
10213
+ const startBottomPin = useCallback((instant = false) => {
10214
+ readingOffsetRef.current = null;
10215
+ pinIntentRef.current = true;
10216
+ scrollToBottom(instant ? { animation: "instant" } : void 0);
10217
+ }, [scrollToBottom]);
10218
+ const previousScrollThreadId = useRef(scrollThreadId);
10219
+ useEffect(() => {
10220
+ if (previousScrollThreadId.current === scrollThreadId) return;
10221
+ previousScrollThreadId.current = scrollThreadId;
10222
+ startBottomPin(true);
10223
+ }, [scrollThreadId, startBottomPin]);
8637
10224
  const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
8638
10225
  return /* @__PURE__ */ jsx(ScrollElementContext.Provider, {
8639
10226
  value: scrollEl,
@@ -8655,7 +10242,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
8655
10242
  !isAtBottom && !isResizing && /* @__PURE__ */ jsx("div", {
8656
10243
  className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
8657
10244
  style: { bottom: `${inputContainerHeight + SCROLL_BUTTON_OFFSET}px` },
8658
- children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
10245
+ children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => startBottomPin() })
8659
10246
  })
8660
10247
  ] })
8661
10248
  })
@@ -8703,7 +10290,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
8703
10290
  })
8704
10291
  });
8705
10292
  };
8706
- _CopilotChatView.ScrollView = ({ children, autoScroll = "pin-to-bottom", scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
10293
+ _CopilotChatView.ScrollView = ({ children, autoScroll = "pin-to-bottom", scrollThreadId, scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
8707
10294
  const mode = normalizeAutoScroll(autoScroll);
8708
10295
  const [hasMounted, setHasMounted] = useState(false);
8709
10296
  const scrollRef = useRef(null);
@@ -8792,6 +10379,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
8792
10379
  initial: "smooth",
8793
10380
  ...props,
8794
10381
  children: /* @__PURE__ */ jsx(ScrollContent, {
10382
+ scrollThreadId,
8795
10383
  scrollToBottomButton,
8796
10384
  feather,
8797
10385
  inputContainerHeight,
@@ -8800,14 +10388,18 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
8800
10388
  })
8801
10389
  });
8802
10390
  };
8803
- _CopilotChatView.ScrollToBottomButton = ({ className, ...props }) => /* @__PURE__ */ jsx(Button, {
8804
- "data-testid": "copilot-scroll-to-bottom",
8805
- variant: "outline",
8806
- size: "sm",
8807
- className: twMerge("cpk:rounded-full cpk:w-10 cpk:h-10 cpk:p-0 cpk:pointer-events-auto", "cpk:bg-white cpk:dark:bg-gray-900", "cpk:shadow-lg cpk:border cpk:border-gray-200 cpk:dark:border-gray-700", "cpk:hover:bg-gray-50 cpk:dark:hover:bg-gray-800", "cpk:flex cpk:items-center cpk:justify-center cpk:cursor-pointer", className),
8808
- ...props,
8809
- children: /* @__PURE__ */ jsx(ChevronDown, { className: "cpk:w-4 cpk:h-4 cpk:text-gray-600 cpk:dark:text-white" })
8810
- });
10391
+ _CopilotChatView.ScrollToBottomButton = ({ className, ...props }) => {
10392
+ const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
10393
+ return /* @__PURE__ */ jsx(Button, {
10394
+ "data-testid": "copilot-scroll-to-bottom",
10395
+ variant: "outline",
10396
+ size: "sm",
10397
+ className: twMerge("cpk:rounded-full cpk:w-10 cpk:h-10 cpk:p-0 cpk:pointer-events-auto", "cpk:bg-white cpk:dark:bg-gray-900", "cpk:shadow-lg cpk:border cpk:border-gray-200 cpk:dark:border-gray-700", "cpk:hover:bg-gray-50 cpk:dark:hover:bg-gray-800", "cpk:flex cpk:items-center cpk:justify-center cpk:cursor-pointer", className),
10398
+ "aria-label": labels.chatScrollToBottomLabel,
10399
+ ...props,
10400
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "cpk:w-4 cpk:h-4 cpk:text-gray-600 cpk:dark:text-white" })
10401
+ });
10402
+ };
8811
10403
  _CopilotChatView.Feather = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
8812
10404
  className,
8813
10405
  ...props
@@ -10190,6 +11782,7 @@ function CopilotPopupViewInternal({ header, toggleButton, width, height, clickOu
10190
11782
  if (containerRef.current?.contains(target)) return;
10191
11783
  const toggleButton = document.querySelector("[data-slot='chat-toggle-button']");
10192
11784
  if (toggleButton && toggleButton.contains(target)) return;
11785
+ if (target instanceof Element && target.closest("[data-copilotkit-popover]")) return;
10193
11786
  setModalOpen?.(false);
10194
11787
  };
10195
11788
  document.addEventListener("pointerdown", handlePointerDown);
@@ -10700,62 +12293,14 @@ CopilotThreadsDrawer.displayName = "CopilotThreadsDrawer";
10700
12293
 
10701
12294
  //#endregion
10702
12295
  //#region src/v2/components/WildcardToolCallRender.tsx
12296
+ /**
12297
+ * Catch-all (`"*"`) tool-call renderer that shows CopilotKit's default
12298
+ * tool-call card for any tool without a dedicated renderer.
12299
+ */
10703
12300
  const WildcardToolCallRender = defineToolCallRenderer({
10704
12301
  name: "*",
10705
- render: ({ args, result, name, status }) => {
10706
- const [isExpanded, setIsExpanded] = useState(false);
10707
- const statusString = String(status);
10708
- return /* @__PURE__ */ jsx("div", {
10709
- className: "cpk:mt-2 cpk:pb-2",
10710
- children: /* @__PURE__ */ jsxs("div", {
10711
- className: "cpk:rounded-xl cpk:border cpk:border-zinc-200/60 cpk:dark:border-zinc-800/60 cpk:bg-white/70 cpk:dark:bg-zinc-900/50 cpk:shadow-sm cpk:backdrop-blur cpk:p-4",
10712
- children: [/* @__PURE__ */ jsxs("div", {
10713
- className: "cpk:flex cpk:items-center cpk:justify-between cpk:gap-3 cpk:cursor-pointer",
10714
- onClick: () => setIsExpanded(!isExpanded),
10715
- children: [/* @__PURE__ */ jsxs("div", {
10716
- className: "cpk:flex cpk:items-center cpk:gap-2 cpk:min-w-0",
10717
- children: [
10718
- /* @__PURE__ */ jsx("svg", {
10719
- className: `cpk:h-4 cpk:w-4 cpk:text-zinc-500 cpk:dark:text-zinc-400 cpk:transition-transform ${isExpanded ? "cpk:rotate-90" : ""}`,
10720
- fill: "none",
10721
- viewBox: "0 0 24 24",
10722
- strokeWidth: 2,
10723
- stroke: "currentColor",
10724
- children: /* @__PURE__ */ jsx("path", {
10725
- strokeLinecap: "round",
10726
- strokeLinejoin: "round",
10727
- d: "M8.25 4.5l7.5 7.5-7.5 7.5"
10728
- })
10729
- }),
10730
- /* @__PURE__ */ jsx("span", { className: "cpk:inline-block cpk:h-2 cpk:w-2 cpk:rounded-full cpk:bg-blue-500" }),
10731
- /* @__PURE__ */ jsx("span", {
10732
- className: "cpk:truncate cpk:text-sm cpk:font-medium cpk:text-zinc-900 cpk:dark:text-zinc-100",
10733
- children: name
10734
- })
10735
- ]
10736
- }), /* @__PURE__ */ jsx("span", {
10737
- className: `cpk:inline-flex cpk:items-center cpk:rounded-full cpk:px-2 cpk:py-1 cpk:text-xs cpk:font-medium ${statusString === "inProgress" || statusString === "executing" ? "cpk:bg-amber-100 cpk:text-amber-800 cpk:dark:bg-amber-500/15 cpk:dark:text-amber-400" : statusString === "complete" ? "cpk:bg-emerald-100 cpk:text-emerald-800 cpk:dark:bg-emerald-500/15 cpk:dark:text-emerald-400" : "cpk:bg-zinc-100 cpk:text-zinc-800 cpk:dark:bg-zinc-700/40 cpk:dark:text-zinc-300"}`,
10738
- children: String(status)
10739
- })]
10740
- }), isExpanded && /* @__PURE__ */ jsxs("div", {
10741
- className: "cpk:mt-3 cpk:grid cpk:gap-4",
10742
- children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
10743
- className: "cpk:text-xs cpk:uppercase cpk:tracking-wide cpk:text-zinc-500 cpk:dark:text-zinc-400",
10744
- children: "Arguments"
10745
- }), /* @__PURE__ */ jsx("pre", {
10746
- className: "cpk:mt-2 cpk:max-h-64 cpk:overflow-auto cpk:rounded-md cpk:bg-zinc-50 cpk:dark:bg-zinc-800/60 cpk:p-3 cpk:text-xs cpk:leading-relaxed cpk:text-zinc-800 cpk:dark:text-zinc-200 cpk:whitespace-pre-wrap cpk:break-words",
10747
- children: JSON.stringify(args ?? {}, null, 2)
10748
- })] }), result !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
10749
- className: "cpk:text-xs cpk:uppercase cpk:tracking-wide cpk:text-zinc-500 cpk:dark:text-zinc-400",
10750
- children: "Result"
10751
- }), /* @__PURE__ */ jsx("pre", {
10752
- className: "cpk:mt-2 cpk:max-h-64 cpk:overflow-auto cpk:rounded-md cpk:bg-zinc-50 cpk:dark:bg-zinc-800/60 cpk:p-3 cpk:text-xs cpk:leading-relaxed cpk:text-zinc-800 cpk:dark:text-zinc-200 cpk:whitespace-pre-wrap cpk:break-words",
10753
- children: typeof result === "string" ? result : JSON.stringify(result, null, 2)
10754
- })] })]
10755
- })]
10756
- })
10757
- });
10758
- }
12302
+ group: true,
12303
+ render: (props) => /* @__PURE__ */ jsx(DefaultToolCallRenderer, { ...adaptRendererProps(props) })
10759
12304
  });
10760
12305
 
10761
12306
  //#endregion
@@ -12938,5 +14483,5 @@ function validateProps(props) {
12938
14483
  }
12939
14484
 
12940
14485
  //#endregion
12941
- export { useConfigureSuggestions as $, ɵselectMemoriesIsLoading$1 as $a, mergeMetadata as $i, MoveOperationSchema as $n, TextMessageContentEventSchema as $r, AudioPartSchema as $t, CopilotChatMessageView as A, ɵcreateThreadStore$1 as Aa, createActionGroup as Ai, HttpAgent as An, RunFinishedSuccessOutcomeSchema as Ar, CopilotKitInspector as At, CopilotChatUserMessage_default as B, ɵobservePhoenixEvent$ as Ba, emitInspectorViewThread as Bi, InputContentUrlSourceSchema as Bn, SubagentErrorEventSchema as Br, AGUI_METADATA_KEY as Bt, CopilotModalHeader as C, ɵCOPILOTKIT_FEATURES as Ca, authoritativeActivityTypes as Ci, EventType as Cn, RoleSchema as Cr, OpenGenerativeUIToolRenderer as Ct, CopilotChat as D, ɵTHREAD_REQUEST_TIMEOUT_MS as Da, contentHasMedia as Di, FilterToolCallsMiddleware as Dn, RunFinishedEventSchema as Dr, MCPAppsActivityRenderer as Dt, DefaultOpenIcon as E, ɵRUNTIME_PROBE_TIMEOUT_MS as Ea, completePartialMarkdown as Ei, FileSourceSchema as En, RunFinishedCancelledOutcomeSchema as Er, MCPAppsActivityContentSchema as Et, getIntelligenceTurnAnchors as F, ɵmapMemoryMetadataEvent as Fa, createSelector as Fi, ImageInputPartSchema as Fn, StateManager as Fr, CopilotChatConfigurationProvider as Ft, useLearningContainers as G, ɵphoenixSocket$ as Ga, ensureObjectArgs as Gi, JsonPatchSchema as Gn, SubagentInfoSchema as Gr, AddOperationSchema as Gt, CopilotChatAssistantMessage_default as H, ɵobservePhoenixSocketHealth$ as Ha, empty as Hi, IntelligenceReplayFailedError as Hn, SubagentFinishedOutcomeSchema as Hr, ActivityDeltaEventSchema as Ht, IntelligenceIndicatorView as I, ɵmemoryAdapterEvents as Ia, createStore as Ii, ImagePartSchema as In, StateSchema as Ir, useCopilotChatConfiguration as It, useLearnFromUserAction as J, ɵselectIsFetchingNextPage$1 as Ja, isAbortError as Ji, MemoryError as Jn, SuggestionEngine as Jr, AgentThreadLockedError as Jt, useAttachments as K, ɵselectFetchMoreError$1 as Ka, getRunOutcome as Ki, JsonPointerSchema as Kn, SubagentRunIdSchema as Kr, AgentCapabilitiesSchema as Kt, CopilotChatSuggestionView as L, ɵmemoryDomainEvents as La, defaultApplyEvents as Li, InputContentDataSourceSchema as Ln, StateSnapshotEventSchema as Lr, ACTIVITY_HISTORY_METADATA as Lt, messageRow as M, ɵisHttpAgent$1 as Ma, createEffect as Mi, INSPECTOR_THREAD_BRIDGE_PLUGIN_ID as Mn, RunStartedEventSchema as Mr, CopilotChatInput_default as Mt, INTELLIGENCE_TURN_HEAD as N, ɵisRetryableMemoryStatus as Na, createInspectorThreadRequestId as Ni, IdentityCapabilitiesSchema as Nn, StateCapabilitiesSchema as Nr, AudioRecorderError as Nt, CopilotChatView_default as O, ɵcreateMemoryStore as Oa, contentToText$1 as Oi, FunctionCallSchema as On, RunFinishedInterruptOutcomeSchema as Or, MCPAppsActivityType as Ot, IntelligenceIndicator as P, ɵjoinPhoenixChannel$ as Pa, createReducer as Pi, ImageInputContentSchema as Pn, StateDeltaEventSchema as Pr, CopilotChatAudioRecorder as Pt, INTERRUPT_EVENT_NAME as Q, ɵselectMemoriesError$1 as Qa, isRunCompletionAware$1 as Qi, Middleware as Qn, TextMessageChunkEventSchema as Qr, AudioInputPartSchema as Qt, CopilotChatSuggestionPill as R, ɵmemoryReducer as Ra, emitInspectorActiveThread$1 as Ri, InputContentSchema as Rn, StepFinishedEventSchema as Rr, AGUIConnectNotImplementedError$1 as Rt, CopilotSidebarView as S, withAuthoritativeActivityTypes as Sa, aggregateTokenUsage as Si, EventSchemas as Sn, ResumeEntrySchema as Sr, OpenGenerativeUIContentSchema as St, DefaultCloseIcon as T, ɵMAX_SOCKET_RETRIES as Ta, compactEvents as Ti, ExecutionCapabilitiesSchema as Tn, RunErrorEventSchema as Tr, useSandboxFunctions as Tt, CopilotChatToolCallsView as U, ɵobservePhoenixSocketSignals$ as Ua, enforceEvents as Ui, InterruptSchema as Un, SubagentFinishedSuccessOutcomeSchema as Ur, ActivityMessageSchema as Ut, CopilotChatAttachmentRenderer as V, ɵobservePhoenixJoinOutcome$ as Va, emitInspectorViewThreadResult$1 as Vi, IntelligenceAgent as Vn, SubagentFinishedEventSchema as Vr, AbstractAgent$1 as Vt, useLearningContainersInCurrentThread as W, ɵphoenixChannel$ as Wa, enforceOutgoingInput as Wi, JsonPatchOperationSchema as Wn, SubagentFinishedSuspendedOutcomeSchema as Wr, ActivitySnapshotEventSchema as Wt, useThreads$1 as X, ɵselectMemories$1 as Xa, isInterruptExpired as Xi, MessagesSnapshotEventSchema as Xn, TestOperationSchema as Xr, AttributableSchema as Xt, useMemories as Y, ɵselectIsMutating$1 as Ya, isInspectorThreadBridgeEnabled$1 as Yi, MessageSchema as Yn, SystemMessageSchema as Yr, AssistantMessageSchema as Yt, useInterrupt as Z, ɵselectMemoriesAvailable$1 as Za, isRecognizedEvent as Zi, MetadataSchema as Zn, TextInputContentSchema as Zr, AudioInputContentSchema as Zt, WildcardToolCallRender as _, tokenUsageFromAiSdkUsage as _a, UserMessageSchema as _i, DeveloperMessageSchema as _n, ReasoningMessageSchema as _r, defineToolCallRenderer as _t, ThreadsProvider as a, onInspectorViewThread$1 as aa, ToolCallArgsEventSchema as ai, CompatibilityBoundary as an, ɵthreadAdapterEvents as ao, OutputCapabilitiesSchema as ar, useHumanInTheLoop as at, CopilotSidebar as b, transformHttpEventStream as ba, VideoPartSchema as bi, DocumentPartSchema as bn, RemoveOperationSchema as br, OpenGenerativeUIActivityRenderer as bt, CoAgentStateRendersProvider as c, parseSSEStream as ca, ToolCallResultEventSchema as ci, ContextStore as cn, ProxiedCopilotRuntimeAgent$1 as cr, useComponent as ct, shouldShowDevConsole as d, randomUUID$2 as da, ToolCallStatus$1 as di, CopilotKitCoreRuntimeConnectionStatus$1 as dn, ReasoningEncryptedValueEventSchema as dr, useRenderActivityMessage as dt, ofType as ea, TextMessageEndEventSchema as ei, BackwardCompatibility_0_0_39 as en, ɵselectMemoriesIsMutating as eo, MultiAgentCapabilitiesSchema as er, useSuggestions as et, useToast as f, resolveAgentDebugConfig as fa, ToolMessageSchema as fi, CopilotKitHeaderResolutionError as fn, ReasoningEncryptedValueSubtypeSchema as fr, useRenderCustomMessages as ft, useCopilotContext as g, structuredClone_ as ga, UrlSourceSchema as gi, DebugLogger as gn, ReasoningMessageEndEventSchema as gr, CopilotKitCoreReact as gt, CopilotContext as h, select as ha, TransportCapabilitiesSchema as hi, DataSourceSchema as hn, ReasoningMessageContentEventSchema as hr, useLicenseContext$1 as ht, ThreadsContext as i, onInspectorStopViewing$1 as ia, TokenUsageSchema as ii, BaseMessageSchema as in, ɵselectThreadsIsLoading$1 as io, OptionalMetadataSchema as ir, useAgent as it, messageGroup as j, ɵisCopilotKitFeature as ja, createDebugLogger as ji, HumanInTheLoopCapabilitiesSchema as jn, RunHandler as jr, useRenderToolCall as jt, CopilotChatAttachmentQueue as k, ɵcreateThreadSelectors as ka, convertToLegacyEvents as ki, FunctionMiddleware as kn, RunFinishedOutcomeSchema as kr, ɵrunMcpFollowUp as kt, useCoAgentStateRenders as l, parseToolArguments as la, ToolCallSchema as li, CopilotKitCore$1 as ln, RawEventSchema as lr, useFrontendTools as lt, useCopilotMessagesContext as m, runHttpRequest as ma, ToolsCapabilitiesSchema as mi, CustomEventSchema as mn, ReasoningMessageChunkEventSchema as mr, useCopilotKit$1 as mt, defaultCopilotContextCategories as n, on as na, TextMessageStartEventSchema as ni, BackwardCompatibility_0_0_57 as nn, ɵselectThreads$1 as no, MultimodalInputCapabilitiesSchema as nr, useCapabilities as nt, useThreads as o, onInspectorViewThreadResult as oa, ToolCallChunkEventSchema as oi, ContentPartSchema as on, ɵwithHeaderDefaults$1 as oo, PROTOCOL_VERSION as or, useDefaultRenderTool as ot, CopilotMessagesContext as p, resolveDebugLogger as pa, ToolSchema as pi, CopyOperationSchema as pn, ReasoningEndEventSchema as pr, CopilotKitProvider as pt, useLearnFromUserActionInCurrentThread as q, ɵselectHasNextPage$1 as qa, getWebMCPModelContext as qi, MEMORY_ERROR_REGISTRY as qn, SubagentStartedEventSchema as qr, AgentRegistry as qt, CoAgentStateRenderBridge as r, onInspectorActiveThread as ra, TextPartSchema as ri, BaseEventSchema as rn, ɵselectThreadsError$1 as ro, MultimodalOutputCapabilitiesSchema as rr, UseAgentUpdate as rt, CoAgentStateRendersContext as s, parseProtoStream as sa, ToolCallEndEventSchema as si, ContextSchema as sn, PartSourceSchema as sr, useRenderTool as st, CopilotKit as t, omitOptionalNulls as ta, TextMessageRoleSchema as ti, BackwardCompatibility_0_0_45 as tn, ɵselectMemoriesRealtimeStatus$1 as to, MultimodalCapabilitiesSchema as tr, useAgentContext as tt, useAsyncCallback as u, props as ua, ToolCallStartEventSchema as ui, CopilotKitCoreErrorCode$1 as un, ReasoningCapabilitiesSchema as ur, useFrontendTool as ut, CopilotThreadsDrawer as v, tokenUsageFromLangChainMetadata as va, VideoInputContentSchema as vi, DocumentInputContentSchema as vn, ReasoningMessageStartEventSchema as vr, createA2UIMessageRenderer as vt, CopilotChatToggleButton as w, ɵInterruptState$1 as wa, buildResumeArray as wi, EventTypeSchema as wn, RunAgentInputSchema as wr, SandboxFunctionsContext as wt, CopilotPopupView as x, verifyEvents as xa, WebMCPRegistry as xi, EventSchema as xn, ReplaceOperationSchema as xr, OpenGenerativeUIActivityType as xt, CopilotPopup as y, transformChunks as ya, VideoInputPartSchema as yi, DocumentInputPartSchema as yn, ReasoningStartEventSchema as yr, GenerateSandboxedUiArgsSchema as yt, CopilotChatReasoningMessage_default as z, ɵmemoryRestEvents as za, emitInspectorStopViewing as zi, InputContentSourceSchema as zn, StepStartedEventSchema as zr, AGUIError as zt };
12942
- //# sourceMappingURL=copilotkit-DcENKLnJ.mjs.map
14486
+ export { INTERRUPT_EVENT_NAME as $, ɵselectMemoriesError$1 as $a, isRunCompletionAware$1 as $i, Middleware as $n, TextMessageChunkEventSchema as $r, AudioInputContentSchema as $t, CopilotChatMessageView as A, ɵcreateThreadSelectors as Aa, convertToLegacyEvents as Ai, FunctionCallSchema as An, RunFinishedOutcomeSchema as Ar, MCPAppsActivityType as At, CopilotChatReasoningMessage_default as B, ɵmemoryRestEvents as Ba, emitInspectorStopViewing as Bi, InputContentSchema as Bn, StepStartedEventSchema as Br, AGUIConnectNotImplementedError$1 as Bt, CopilotModalHeader as C, withAuthoritativeActivityTypes as Ca, aggregateTokenUsage as Ci, EventSchema as Cn, ResumeEntrySchema as Cr, OpenGenerativeUIActivityType as Ct, CopilotChat as D, ɵRUNTIME_PROBE_TIMEOUT_MS as Da, completePartialMarkdown as Di, ExecutionCapabilitiesSchema as Dn, RunFinishedCancelledOutcomeSchema as Dr, useSandboxFunctions as Dt, DefaultOpenIcon as E, ɵMAX_SOCKET_RETRIES as Ea, compactEvents as Ei, EventTypeSchema as En, RunErrorEventSchema as Er, SandboxFunctionsContext as Et, getIntelligenceTurnAnchors as F, ɵjoinPhoenixChannel$ as Fa, createReducer as Fi, IdentityCapabilitiesSchema as Fn, StateDeltaEventSchema as Fr, AudioRecorderError as Ft, useLearningContainersInCurrentThread as G, ɵphoenixChannel$ as Ga, enforceOutgoingInput as Gi, JsonPatchOperationSchema as Gn, SubagentFinishedSuspendedOutcomeSchema as Gr, ActivityMessageSchema as Gt, CopilotChatAttachmentRenderer as H, ɵobservePhoenixJoinOutcome$ as Ha, emitInspectorViewThreadResult$1 as Hi, InputContentUrlSourceSchema as Hn, SubagentFinishedEventSchema as Hr, AGUI_METADATA_KEY as Ht, IntelligenceIndicatorView as I, ɵmapMemoryMetadataEvent as Ia, createSelector as Ii, ImageInputContentSchema as In, StateManager as Ir, CopilotChatAudioRecorder as It, useLearnFromUserActionInCurrentThread as J, ɵselectHasNextPage$1 as Ja, getWebMCPModelContext as Ji, MEMORY_ERROR_REGISTRY as Jn, SubagentStartedEventSchema as Jr, AgentCapabilitiesSchema as Jt, useLearningContainers as K, ɵphoenixSocket$ as Ka, ensureObjectArgs as Ki, JsonPatchSchema as Kn, SubagentInfoSchema as Kr, ActivitySnapshotEventSchema as Kt, CopilotChatWorkSummary as L, ɵmemoryAdapterEvents as La, createStore as Li, ImageInputPartSchema as Ln, StateSchema as Lr, CopilotChatConfigurationProvider as Lt, messageRow as M, ɵisCopilotKitFeature as Ma, createDebugLogger as Mi, HttpAgent as Mn, RunHandler as Mr, CopilotKitInspector as Mt, INTELLIGENCE_TURN_HEAD as N, ɵisHttpAgent$1 as Na, createEffect as Ni, HumanInTheLoopCapabilitiesSchema as Nn, RunStartedEventSchema as Nr, useRenderToolCall as Nt, CopilotChatView_default as O, ɵTHREAD_REQUEST_TIMEOUT_MS as Oa, contentHasMedia as Oi, FileSourceSchema as On, RunFinishedEventSchema as Or, MCPAppsActivityContentSchema as Ot, IntelligenceIndicator as P, ɵisRetryableMemoryStatus as Pa, createInspectorThreadRequestId as Pi, INSPECTOR_THREAD_BRIDGE_PLUGIN_ID as Pn, StateCapabilitiesSchema as Pr, CopilotChatInput_default as Pt, useInterrupt as Q, ɵselectMemoriesAvailable$1 as Qa, isRecognizedEvent as Qi, MetadataSchema as Qn, TextInputContentSchema as Qr, AttributableSchema as Qt, CopilotChatSuggestionView as R, ɵmemoryDomainEvents as Ra, defaultApplyEvents as Ri, ImagePartSchema as Rn, StateSnapshotEventSchema as Rr, useCopilotChatConfiguration as Rt, CopilotSidebarView as S, verifyEvents as Sa, WebMCPRegistry as Si, DocumentPartSchema as Sn, ReplaceOperationSchema as Sr, OpenGenerativeUIActivityRenderer as St, DefaultCloseIcon as T, ɵInterruptState$1 as Ta, buildResumeArray as Ti, EventType as Tn, RunAgentInputSchema as Tr, OpenGenerativeUIToolRenderer as Tt, CopilotChatAssistantMessage_default as U, ɵobservePhoenixSocketHealth$ as Ua, empty as Ui, IntelligenceAgent as Un, SubagentFinishedOutcomeSchema as Ur, AbstractAgent$1 as Ut, CopilotChatUserMessage_default as V, ɵobservePhoenixEvent$ as Va, emitInspectorViewThread as Vi, InputContentSourceSchema as Vn, SubagentErrorEventSchema as Vr, AGUIError as Vt, CopilotChatToolCallsView as W, ɵobservePhoenixSocketSignals$ as Wa, enforceEvents as Wi, InterruptSchema as Wn, SubagentFinishedSuccessOutcomeSchema as Wr, ActivityDeltaEventSchema as Wt, useMemories as X, ɵselectIsMutating$1 as Xa, isInspectorThreadBridgeEnabled$1 as Xi, MessageSchema as Xn, SystemMessageSchema as Xr, AgentThreadLockedError as Xt, useLearnFromUserAction as Y, ɵselectIsFetchingNextPage$1 as Ya, isAbortError as Yi, MemoryError as Yn, SuggestionEngine as Yr, AgentRegistry as Yt, useThreads$1 as Z, ɵselectMemories$1 as Za, isInterruptExpired as Zi, MessagesSnapshotEventSchema as Zn, TestOperationSchema as Zr, AssistantMessageSchema as Zt, WildcardToolCallRender as _, structuredClone_ as _a, UrlSourceSchema as _i, DataSourceSchema as _n, ReasoningMessageEndEventSchema as _r, useLicenseContext$1 as _t, ThreadsProvider as a, onInspectorStopViewing$1 as aa, TokenUsageSchema as ai, BaseEventSchema as an, ɵselectThreadsIsLoading$1 as ao, OptionalMetadataSchema as ar, useAgent as at, CopilotSidebar as b, transformChunks as ba, VideoInputPartSchema as bi, DocumentInputContentSchema as bn, ReasoningStartEventSchema as br, createA2UIMessageRenderer as bt, CoAgentStateRendersProvider as c, parseProtoStream as ca, ToolCallEndEventSchema as ci, ContentPartSchema as cn, PartSourceSchema as cr, CopilotChatToolCallGroup as ct, shouldShowDevConsole as d, props as da, ToolCallStartEventSchema as di, CopilotKitCore$1 as dn, ReasoningCapabilitiesSchema as dr, useFrontendTools as dt, mergeMetadata as ea, TextMessageContentEventSchema as ei, AudioInputPartSchema as en, ɵselectMemoriesIsLoading$1 as eo, MoveOperationSchema as er, useConfigureSuggestions as et, useToast as f, randomUUID$2 as fa, ToolCallStatus$1 as fi, CopilotKitCoreErrorCode$1 as fn, ReasoningEncryptedValueEventSchema as fr, useFrontendTool as ft, useCopilotContext as g, select as ga, TransportCapabilitiesSchema as gi, CustomEventSchema as gn, ReasoningMessageContentEventSchema as gr, useCopilotKit$1 as gt, CopilotContext as h, runHttpRequest as ha, ToolsCapabilitiesSchema as hi, CopyOperationSchema as hn, ReasoningMessageChunkEventSchema as hr, CopilotKitProvider as ht, ThreadsContext as i, onInspectorActiveThread as ia, TextPartSchema as ii, BackwardCompatibility_0_0_57 as in, ɵselectThreadsError$1 as io, MultimodalOutputCapabilitiesSchema as ir, UseAgentUpdate as it, messageGroup as j, ɵcreateThreadStore$1 as ja, createActionGroup as ji, FunctionMiddleware as jn, RunFinishedSuccessOutcomeSchema as jr, ɵrunMcpFollowUp as jt, CopilotChatAttachmentQueue as k, ɵcreateMemoryStore as ka, contentToText$1 as ki, FilterToolCallsMiddleware as kn, RunFinishedInterruptOutcomeSchema as kr, MCPAppsActivityRenderer as kt, useCoAgentStateRenders as l, parseSSEStream as la, ToolCallResultEventSchema as li, ContextSchema as ln, ProxiedCopilotRuntimeAgent$1 as lr, useRenderTool as lt, useCopilotMessagesContext as m, resolveDebugLogger as ma, ToolSchema as mi, CopilotKitHeaderResolutionError as mn, ReasoningEndEventSchema as mr, useRenderCustomMessages as mt, defaultCopilotContextCategories as n, omitOptionalNulls as na, TextMessageRoleSchema as ni, BackwardCompatibility_0_0_39 as nn, ɵselectMemoriesRealtimeStatus$1 as no, MultimodalCapabilitiesSchema as nr, useAgentContext as nt, useThreads as o, onInspectorViewThread$1 as oa, ToolCallArgsEventSchema as oi, BaseMessageSchema as on, ɵthreadAdapterEvents as oo, OutputCapabilitiesSchema as or, useHumanInTheLoop as ot, CopilotMessagesContext as p, resolveAgentDebugConfig as pa, ToolMessageSchema as pi, CopilotKitCoreRuntimeConnectionStatus$1 as pn, ReasoningEncryptedValueSubtypeSchema as pr, useRenderActivityMessage as pt, useAttachments as q, ɵselectFetchMoreError$1 as qa, getRunOutcome as qi, JsonPointerSchema as qn, SubagentRunIdSchema as qr, AddOperationSchema as qt, CoAgentStateRenderBridge as r, on as ra, TextMessageStartEventSchema as ri, BackwardCompatibility_0_0_45 as rn, ɵselectThreads$1 as ro, MultimodalInputCapabilitiesSchema as rr, useCapabilities as rt, CoAgentStateRendersContext as s, onInspectorViewThreadResult as sa, ToolCallChunkEventSchema as si, CompatibilityBoundary as sn, ɵwithHeaderDefaults$1 as so, PROTOCOL_VERSION as sr, useDefaultRenderTool as st, CopilotKit as t, ofType as ta, TextMessageEndEventSchema as ti, AudioPartSchema as tn, ɵselectMemoriesIsMutating as to, MultiAgentCapabilitiesSchema as tr, useSuggestions as tt, useAsyncCallback as u, parseToolArguments as ua, ToolCallSchema as ui, ContextStore as un, RawEventSchema as ur, useComponent as ut, CopilotThreadsDrawer as v, tokenUsageFromAiSdkUsage as va, UserMessageSchema as vi, DebugLogger as vn, ReasoningMessageSchema as vr, CopilotKitCoreReact as vt, CopilotChatToggleButton as w, ɵCOPILOTKIT_FEATURES as wa, authoritativeActivityTypes as wi, EventSchemas as wn, RoleSchema as wr, OpenGenerativeUIContentSchema as wt, CopilotPopupView as x, transformHttpEventStream as xa, VideoPartSchema as xi, DocumentInputPartSchema as xn, RemoveOperationSchema as xr, GenerateSandboxedUiArgsSchema as xt, CopilotPopup as y, tokenUsageFromLangChainMetadata as ya, VideoInputContentSchema as yi, DeveloperMessageSchema as yn, ReasoningMessageStartEventSchema as yr, defineToolCallRenderer as yt, CopilotChatSuggestionPill as z, ɵmemoryReducer as za, emitInspectorActiveThread$1 as zi, InputContentDataSourceSchema as zn, StepFinishedEventSchema as zr, ACTIVITY_HISTORY_METADATA as zt };
14487
+ //# sourceMappingURL=copilotkit-BNLtgOyD.mjs.map