@copilotkit/react-core 1.79.1 → 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.
- package/dist/{copilotkit-CD3uPUN3.mjs → copilotkit-BNLtgOyD.mjs} +1855 -221
- package/dist/copilotkit-BNLtgOyD.mjs.map +1 -0
- package/dist/{copilotkit-Yz8qXx00.d.mts → copilotkit-CWOSXhRO.d.mts} +277 -40
- package/dist/copilotkit-CWOSXhRO.d.mts.map +1 -0
- package/dist/{copilotkit-DEaA0Cat.cjs → copilotkit-DKICi3nC.cjs} +1843 -196
- package/dist/copilotkit-DKICi3nC.cjs.map +1 -0
- package/dist/{copilotkit-k7IYk2AN.d.cts → copilotkit-Dfw9HzO9.d.cts} +277 -40
- package/dist/copilotkit-Dfw9HzO9.d.cts.map +1 -0
- package/dist/index.cjs +15 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +15 -3
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +127 -16
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/context.d.cts +7 -0
- package/dist/v2/context.d.cts.map +1 -1
- package/dist/v2/context.d.mts +7 -0
- package/dist/v2/context.d.mts.map +1 -1
- package/dist/v2/headless.cjs +106 -16
- package/dist/v2/headless.cjs.map +1 -1
- package/dist/v2/headless.d.cts +20 -2
- package/dist/v2/headless.d.cts.map +1 -1
- package/dist/v2/headless.d.mts +20 -2
- package/dist/v2/headless.d.mts.map +1 -1
- package/dist/v2/headless.mjs +106 -16
- package/dist/v2/headless.mjs.map +1 -1
- package/dist/v2/index.cjs +3 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/index.umd.js +1858 -222
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +11 -8
- package/dist/copilotkit-CD3uPUN3.mjs.map +0 -1
- package/dist/copilotkit-DEaA0Cat.cjs.map +0 -1
- package/dist/copilotkit-Yz8qXx00.d.mts.map +0 -1
- package/dist/copilotkit-k7IYk2AN.d.cts.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";
|
|
2
|
+
import React, { Fragment, createContext, createElement, forwardRef, memo, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
|
|
3
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";
|
|
@@ -40,7 +41,7 @@ function shallowEqual(obj1, obj2) {
|
|
|
40
41
|
* Returns true only for plain JS objects (`{}`), excluding arrays, Dates,
|
|
41
42
|
* class instances, and other exotic objects that happen to have typeof "object".
|
|
42
43
|
*/
|
|
43
|
-
function isPlainObject(obj) {
|
|
44
|
+
function isPlainObject$1(obj) {
|
|
44
45
|
return obj !== null && typeof obj === "object" && Object.prototype.toString.call(obj) === "[object Object]";
|
|
45
46
|
}
|
|
46
47
|
/**
|
|
@@ -59,7 +60,7 @@ function isPlainObject(obj) {
|
|
|
59
60
|
function useShallowStableRef(value) {
|
|
60
61
|
const ref = useRef(value);
|
|
61
62
|
if (ref.current === value) return ref.current;
|
|
62
|
-
if (isPlainObject(ref.current) && isPlainObject(value)) {
|
|
63
|
+
if (isPlainObject$1(ref.current) && isPlainObject$1(value)) {
|
|
63
64
|
if (shallowEqual(ref.current, value)) return ref.current;
|
|
64
65
|
}
|
|
65
66
|
ref.current = value;
|
|
@@ -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
|
-
|
|
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 }) =>
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
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 =
|
|
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.
|
|
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
|
-
|
|
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
|
}];
|
|
@@ -3991,12 +4048,86 @@ function useRenderActivityMessage() {
|
|
|
3991
4048
|
}), [renderActivityMessage, findRenderer]);
|
|
3992
4049
|
}
|
|
3993
4050
|
|
|
4051
|
+
//#endregion
|
|
4052
|
+
//#region src/v2/hooks/tool-registration.ts
|
|
4053
|
+
/**
|
|
4054
|
+
* Deps comparison shared by `useFrontendTool` (and through it
|
|
4055
|
+
* `useHumanInTheLoop` and `useComponent`) and `useRenderTool`. Not part of the
|
|
4056
|
+
* public API.
|
|
4057
|
+
*/
|
|
4058
|
+
const EMPTY_DEPS$1 = [];
|
|
4059
|
+
function isPlainObject(value) {
|
|
4060
|
+
const proto = Object.getPrototypeOf(value);
|
|
4061
|
+
return proto === Object.prototype || proto === null;
|
|
4062
|
+
}
|
|
4063
|
+
/**
|
|
4064
|
+
* Plain data (primitives, plain objects, arrays, dates) compares by value.
|
|
4065
|
+
* Functions always compare equal: these hooks used to compare
|
|
4066
|
+
* `JSON.stringify(deps)`, which turns every function into `null`, and a
|
|
4067
|
+
* function that counted as changed would re-register on every render when it
|
|
4068
|
+
* is written inline (and loop in a component that also reads
|
|
4069
|
+
* `useRenderToolCall`). Everything else (class instances, maps, sets) compares
|
|
4070
|
+
* by identity. A cycle inside plain data is safe: a pair already being
|
|
4071
|
+
* compared counts as equal for that branch.
|
|
4072
|
+
*/
|
|
4073
|
+
function depEqual(a, b, seen) {
|
|
4074
|
+
if (Object.is(a, b)) return true;
|
|
4075
|
+
if (typeof a === "function" && typeof b === "function") return true;
|
|
4076
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
|
|
4077
|
+
if (a instanceof Date && b instanceof Date) return Object.is(a.getTime(), b.getTime());
|
|
4078
|
+
const aIsArray = Array.isArray(a);
|
|
4079
|
+
if (aIsArray !== Array.isArray(b)) return false;
|
|
4080
|
+
if (!aIsArray && !(isPlainObject(a) && isPlainObject(b))) return false;
|
|
4081
|
+
if (seen.get(a) === b) return true;
|
|
4082
|
+
seen.set(a, b);
|
|
4083
|
+
if (aIsArray) {
|
|
4084
|
+
const left = a;
|
|
4085
|
+
const right = b;
|
|
4086
|
+
if (left.length !== right.length) return false;
|
|
4087
|
+
for (let i = 0; i < left.length; i++) if (!depEqual(left[i], right[i], seen)) return false;
|
|
4088
|
+
return true;
|
|
4089
|
+
}
|
|
4090
|
+
const left = a;
|
|
4091
|
+
const right = b;
|
|
4092
|
+
const leftKeys = Object.keys(left);
|
|
4093
|
+
if (leftKeys.length !== Object.keys(right).length) return false;
|
|
4094
|
+
for (const key of leftKeys) {
|
|
4095
|
+
if (!Object.prototype.hasOwnProperty.call(right, key)) return false;
|
|
4096
|
+
if (!depEqual(left[key], right[key], seen)) return false;
|
|
4097
|
+
}
|
|
4098
|
+
return true;
|
|
4099
|
+
}
|
|
4100
|
+
/** Whether two deps arrays are equal. A change in length is always a change. */
|
|
4101
|
+
function depsEqual(prev, next) {
|
|
4102
|
+
if (prev.length !== next.length) return false;
|
|
4103
|
+
const seen = /* @__PURE__ */ new Map();
|
|
4104
|
+
for (let i = 0; i < prev.length; i++) if (!depEqual(prev[i], next[i], seen)) return false;
|
|
4105
|
+
return true;
|
|
4106
|
+
}
|
|
4107
|
+
/**
|
|
4108
|
+
* Turns a caller's `deps` array into a number that changes exactly when the
|
|
4109
|
+
* deps change, by the rules of {@link depsEqual}. Put the number, not the
|
|
4110
|
+
* array, in the registration effect's dependency list: that keeps the list a
|
|
4111
|
+
* constant length and never serializes a value.
|
|
4112
|
+
*/
|
|
4113
|
+
function useDepsVersion(deps) {
|
|
4114
|
+
const next = deps ?? EMPTY_DEPS$1;
|
|
4115
|
+
const ref = useRef({
|
|
4116
|
+
deps: next,
|
|
4117
|
+
version: 0
|
|
4118
|
+
});
|
|
4119
|
+
if (ref.current.deps !== next && !depsEqual(ref.current.deps, next)) ref.current = {
|
|
4120
|
+
deps: next,
|
|
4121
|
+
version: ref.current.version + 1
|
|
4122
|
+
};
|
|
4123
|
+
return ref.current.version;
|
|
4124
|
+
}
|
|
4125
|
+
|
|
3994
4126
|
//#endregion
|
|
3995
4127
|
//#region src/v2/hooks/use-frontend-tool.tsx
|
|
3996
|
-
const EMPTY_DEPS$2 = [];
|
|
3997
4128
|
function useFrontendTool(tool, deps) {
|
|
3998
4129
|
const { copilotkit } = useCopilotKit();
|
|
3999
|
-
const
|
|
4130
|
+
const depsVersion = useDepsVersion(deps);
|
|
4000
4131
|
useLayoutEffect(() => {
|
|
4001
4132
|
const name = tool.name;
|
|
4002
4133
|
if (copilotkit.getTool({
|
|
@@ -4020,14 +4151,14 @@ function useFrontendTool(tool, deps) {
|
|
|
4020
4151
|
tool.name,
|
|
4021
4152
|
tool.available,
|
|
4022
4153
|
copilotkit,
|
|
4023
|
-
|
|
4154
|
+
depsVersion,
|
|
4024
4155
|
JSON.stringify(tool.webmcp ?? null)
|
|
4025
4156
|
]);
|
|
4026
4157
|
}
|
|
4027
4158
|
|
|
4028
4159
|
//#endregion
|
|
4029
4160
|
//#region src/v2/hooks/use-frontend-tools.tsx
|
|
4030
|
-
const EMPTY_DEPS
|
|
4161
|
+
const EMPTY_DEPS = [];
|
|
4031
4162
|
const EMPTY_TOOLS = [];
|
|
4032
4163
|
/**
|
|
4033
4164
|
* Register a list of frontend tools whose length can change between renders.
|
|
@@ -4081,7 +4212,7 @@ const EMPTY_TOOLS = [];
|
|
|
4081
4212
|
function useFrontendTools(tools, deps) {
|
|
4082
4213
|
const { copilotkit } = useCopilotKit();
|
|
4083
4214
|
const toolList = tools ?? EMPTY_TOOLS;
|
|
4084
|
-
const extraDeps = deps ?? EMPTY_DEPS
|
|
4215
|
+
const extraDeps = deps ?? EMPTY_DEPS;
|
|
4085
4216
|
useLayoutEffect(() => {
|
|
4086
4217
|
const deduped = /* @__PURE__ */ new Map();
|
|
4087
4218
|
for (const tool of toolList) {
|
|
@@ -4192,7 +4323,6 @@ function useComponent(config, deps) {
|
|
|
4192
4323
|
|
|
4193
4324
|
//#endregion
|
|
4194
4325
|
//#region src/v2/hooks/use-render-tool.tsx
|
|
4195
|
-
const EMPTY_DEPS = [];
|
|
4196
4326
|
/**
|
|
4197
4327
|
* Registers a renderer entry in CopilotKit's `renderToolCalls` registry.
|
|
4198
4328
|
*
|
|
@@ -4236,7 +4366,7 @@ const EMPTY_DEPS = [];
|
|
|
4236
4366
|
*/
|
|
4237
4367
|
function useRenderTool(config, deps) {
|
|
4238
4368
|
const { copilotkit } = useCopilotKit();
|
|
4239
|
-
const
|
|
4369
|
+
const depsVersion = useDepsVersion(deps);
|
|
4240
4370
|
useEffect(() => {
|
|
4241
4371
|
const renderer = config.name === "*" && !config.parameters ? defineToolCallRenderer({
|
|
4242
4372
|
name: "*",
|
|
@@ -4244,7 +4374,8 @@ function useRenderTool(config, deps) {
|
|
|
4244
4374
|
...props,
|
|
4245
4375
|
parameters: props.args
|
|
4246
4376
|
}),
|
|
4247
|
-
...config.agentId ? { agentId: config.agentId } : {}
|
|
4377
|
+
...config.agentId ? { agentId: config.agentId } : {},
|
|
4378
|
+
group: config.group
|
|
4248
4379
|
}) : defineToolCallRenderer({
|
|
4249
4380
|
name: config.name,
|
|
4250
4381
|
args: config.parameters,
|
|
@@ -4262,16 +4393,395 @@ function useRenderTool(config, deps) {
|
|
|
4262
4393
|
parameters: props.args
|
|
4263
4394
|
});
|
|
4264
4395
|
},
|
|
4265
|
-
...config.agentId ? { agentId: config.agentId } : {}
|
|
4396
|
+
...config.agentId ? { agentId: config.agentId } : {},
|
|
4397
|
+
group: config.group
|
|
4266
4398
|
});
|
|
4267
4399
|
copilotkit.addHookRenderToolCall(renderer);
|
|
4268
4400
|
}, [
|
|
4269
4401
|
config.name,
|
|
4402
|
+
config.group,
|
|
4270
4403
|
copilotkit,
|
|
4271
|
-
|
|
4404
|
+
depsVersion
|
|
4272
4405
|
]);
|
|
4273
4406
|
}
|
|
4274
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
|
+
|
|
4275
4785
|
//#endregion
|
|
4276
4786
|
//#region src/v2/hooks/use-default-render-tool.tsx
|
|
4277
4787
|
/**
|
|
@@ -4355,7 +4865,8 @@ function useDefaultRenderTool(config, deps) {
|
|
|
4355
4865
|
const userRender = config?.render;
|
|
4356
4866
|
useRenderTool({
|
|
4357
4867
|
name: "*",
|
|
4358
|
-
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
|
|
4359
4870
|
}, deps);
|
|
4360
4871
|
}
|
|
4361
4872
|
/**
|
|
@@ -4376,9 +4887,23 @@ function safeStringifyForPre(value) {
|
|
|
4376
4887
|
}
|
|
4377
4888
|
}
|
|
4378
4889
|
function DefaultToolCallRenderer({ name, toolCallId, parameters, status, result }) {
|
|
4890
|
+
const group = useContext(ToolCallGroupContext);
|
|
4379
4891
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
4380
4892
|
const isActive = status === "inProgress" || status === "executing";
|
|
4381
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
|
+
});
|
|
4382
4907
|
const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
|
|
4383
4908
|
const dotClassName = isActive ? "cpk:bg-amber-500" : isComplete ? "cpk:bg-emerald-500" : "cpk:bg-zinc-400";
|
|
4384
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";
|
|
@@ -6075,38 +6600,227 @@ function useLearningContainersInCurrentThread({ learningContainers }) {
|
|
|
6075
6600
|
});
|
|
6076
6601
|
}
|
|
6077
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
|
+
|
|
6078
6738
|
//#endregion
|
|
6079
6739
|
//#region src/v2/components/chat/CopilotChatToolCallsView.tsx
|
|
6080
|
-
|
|
6740
|
+
const appearances = {
|
|
6741
|
+
grouped: "card",
|
|
6742
|
+
line: "line",
|
|
6743
|
+
stacked: "stack"
|
|
6744
|
+
};
|
|
6745
|
+
function CopilotChatToolCallsView({ message, messages = [], display: displayProp, group }) {
|
|
6081
6746
|
const renderToolCall = useRenderToolCall();
|
|
6747
|
+
const rendererNames = useToolCallRendererNames();
|
|
6082
6748
|
const { copilotkit } = useCopilotKit();
|
|
6083
6749
|
const subscribe = useCallback((onChange) => copilotkit.ɵsubscribeToLearningConfigured(onChange), [copilotkit]);
|
|
6084
6750
|
const getSnapshot = () => copilotkit.ɵlearningConfigured;
|
|
6085
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
|
+
]);
|
|
6086
6765
|
if (!message.toolCalls || message.toolCalls.length === 0) return null;
|
|
6087
|
-
|
|
6766
|
+
const renderCall = (entry) => {
|
|
6088
6767
|
const rendered = renderToolCall({
|
|
6089
|
-
toolCall,
|
|
6090
|
-
toolMessage:
|
|
6768
|
+
toolCall: entry.toolCall,
|
|
6769
|
+
toolMessage: entry.toolMessage
|
|
6091
6770
|
});
|
|
6092
|
-
if (rendered === null) return
|
|
6093
|
-
if (!learningConfigured) return rendered;
|
|
6771
|
+
if (rendered === null || !learningConfigured) return rendered;
|
|
6094
6772
|
return /* @__PURE__ */ jsx("div", {
|
|
6095
|
-
"data-tool-call-id": toolCall.id,
|
|
6773
|
+
"data-tool-call-id": entry.toolCall.id,
|
|
6096
6774
|
style: { display: "contents" },
|
|
6097
6775
|
children: rendered
|
|
6098
|
-
}
|
|
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);
|
|
6099
6813
|
}) });
|
|
6100
6814
|
}
|
|
6101
6815
|
|
|
6102
6816
|
//#endregion
|
|
6103
6817
|
//#region src/v2/components/chat/CopilotChatInspectorButton.tsx
|
|
6104
6818
|
let shortcutsHidden = false;
|
|
6105
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
6819
|
+
const listeners$1 = /* @__PURE__ */ new Set();
|
|
6106
6820
|
const subscribe = (listener) => {
|
|
6107
|
-
listeners.add(listener);
|
|
6821
|
+
listeners$1.add(listener);
|
|
6108
6822
|
return () => {
|
|
6109
|
-
listeners.delete(listener);
|
|
6823
|
+
listeners$1.delete(listener);
|
|
6110
6824
|
};
|
|
6111
6825
|
};
|
|
6112
6826
|
const getSnapshot = () => shortcutsHidden;
|
|
@@ -6116,7 +6830,7 @@ function useInspectorShortcutsHidden() {
|
|
|
6116
6830
|
}
|
|
6117
6831
|
function hideShortcuts() {
|
|
6118
6832
|
shortcutsHidden = true;
|
|
6119
|
-
listeners.forEach((listener) => listener());
|
|
6833
|
+
listeners$1.forEach((listener) => listener());
|
|
6120
6834
|
}
|
|
6121
6835
|
function InspectorKiteIcon({ className, ...props }) {
|
|
6122
6836
|
const id = useId();
|
|
@@ -6383,47 +7097,544 @@ function CopilotChatInspectorButton({ title, className, onClick, onPointerDown,
|
|
|
6383
7097
|
}
|
|
6384
7098
|
|
|
6385
7099
|
//#endregion
|
|
6386
|
-
//#region src/v2/components/
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
function BoundInspectorButton({ inspectorButton, messageId, openInspector, ...props }) {
|
|
6392
|
-
const chatConfiguration = useCopilotChatConfiguration();
|
|
6393
|
-
return renderSlot(inspectorButton, CopilotChatAssistantMessage.InspectorButton, {
|
|
6394
|
-
...props,
|
|
6395
|
-
onClick: () => openInspector({
|
|
6396
|
-
messageId,
|
|
6397
|
-
threadId: chatConfiguration?.threadId,
|
|
6398
|
-
agentId: chatConfiguration?.agentId
|
|
6399
|
-
})
|
|
7100
|
+
//#region src/v2/components/ui/popover.tsx
|
|
7101
|
+
function Popover({ ...props }) {
|
|
7102
|
+
return /* @__PURE__ */ jsx(PopoverPrimitive.Root, {
|
|
7103
|
+
"data-slot": "popover",
|
|
7104
|
+
...props
|
|
6400
7105
|
});
|
|
6401
7106
|
}
|
|
6402
|
-
function
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
|
|
6413
|
-
|
|
7107
|
+
function PopoverAnchor({ ...props }) {
|
|
7108
|
+
return /* @__PURE__ */ jsx(PopoverPrimitive.Anchor, {
|
|
7109
|
+
"data-slot": "popover-anchor",
|
|
7110
|
+
...props
|
|
7111
|
+
});
|
|
7112
|
+
}
|
|
7113
|
+
/**
|
|
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.
|
|
7116
|
+
*/
|
|
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
|
+
};
|
|
7173
|
+
}
|
|
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,
|
|
7196
|
+
messageId: message.id,
|
|
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, {
|
|
6414
7620
|
inspectorButton,
|
|
6415
7621
|
messageId: message.id,
|
|
6416
7622
|
openInspector
|
|
6417
7623
|
}) : /* @__PURE__ */ jsx(Fragment$1, {});
|
|
6418
|
-
const boundThumbsDownButton = renderSlot(thumbsDownButton, CopilotChatAssistantMessage.ThumbsDownButton, {
|
|
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
|
+
});
|
|
6419
7630
|
const boundReadAloudButton = renderSlot(readAloudButton, CopilotChatAssistantMessage.ReadAloudButton, { onClick: onReadAloud ? () => onReadAloud(message) : void 0 });
|
|
6420
7631
|
const boundRegenerateButton = renderSlot(regenerateButton, CopilotChatAssistantMessage.RegenerateButton, { onClick: onRegenerate ? () => onRegenerate(message) : void 0 });
|
|
6421
7632
|
const boundToolbar = renderSlot(toolbar, CopilotChatAssistantMessage.Toolbar, { children: /* @__PURE__ */ jsxs("div", {
|
|
6422
7633
|
className: "cpk:flex cpk:w-full cpk:items-center cpk:gap-1",
|
|
6423
7634
|
children: [
|
|
6424
7635
|
boundCopyButton,
|
|
6425
|
-
(onThumbsUp || thumbsUpButton) && boundThumbsUpButton,
|
|
6426
|
-
(onThumbsDown || thumbsDownButton) && boundThumbsDownButton,
|
|
7636
|
+
(onThumbsUp || thumbsUpButton || feedback) && boundThumbsUpButton,
|
|
7637
|
+
(onThumbsDown || thumbsDownButton || feedback) && boundThumbsDownButton,
|
|
6427
7638
|
(onReadAloud || readAloudButton) && boundReadAloudButton,
|
|
6428
7639
|
(onRegenerate || regenerateButton) && boundRegenerateButton,
|
|
6429
7640
|
additionalToolbarItems,
|
|
@@ -6437,11 +7648,31 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, o
|
|
|
6437
7648
|
const hasContent = !!(message.content && message.content.trim().length > 0);
|
|
6438
7649
|
const isLatestAssistantMessage = message.role === "assistant" && (isLatest ?? messages?.[messages.length - 1]?.id === message.id);
|
|
6439
7650
|
const shouldShowToolbar = toolbarVisible && (hasContent || showInspectorShortcut) && !(isRunning && isLatestAssistantMessage);
|
|
6440
|
-
|
|
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,
|
|
6441
7672
|
"data-copilotkit": true,
|
|
6442
7673
|
"data-message-id": message.id,
|
|
6443
7674
|
style: { display: "contents" },
|
|
6444
|
-
children: children({
|
|
7675
|
+
children: [children({
|
|
6445
7676
|
markdownRenderer: boundMarkdownRenderer,
|
|
6446
7677
|
toolbar: boundToolbar,
|
|
6447
7678
|
toolCallsView: boundToolCallsView,
|
|
@@ -6460,21 +7691,26 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, o
|
|
|
6460
7691
|
onRegenerate,
|
|
6461
7692
|
additionalToolbarItems,
|
|
6462
7693
|
toolbarVisible: shouldShowToolbar
|
|
6463
|
-
})
|
|
7694
|
+
}), feedbackComment]
|
|
6464
7695
|
});
|
|
6465
7696
|
return /* @__PURE__ */ jsxs("div", {
|
|
7697
|
+
ref: root,
|
|
6466
7698
|
"data-copilotkit": true,
|
|
6467
7699
|
"data-testid": "copilot-assistant-message",
|
|
6468
7700
|
className: twMerge("copilotKitMessage copilotKitAssistantMessage", className),
|
|
6469
7701
|
...props,
|
|
6470
7702
|
"data-message-id": message.id,
|
|
6471
7703
|
children: [
|
|
6472
|
-
/* @__PURE__ */ jsx(
|
|
6473
|
-
|
|
6474
|
-
children:
|
|
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
|
+
})
|
|
6475
7710
|
}),
|
|
6476
7711
|
boundToolCallsView,
|
|
6477
|
-
shouldShowToolbar && boundToolbar
|
|
7712
|
+
shouldShowToolbar && boundToolbar,
|
|
7713
|
+
feedbackComment
|
|
6478
7714
|
]
|
|
6479
7715
|
});
|
|
6480
7716
|
}
|
|
@@ -6490,20 +7726,27 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, o
|
|
|
6490
7726
|
...props
|
|
6491
7727
|
});
|
|
6492
7728
|
const ToolbarButton = _CopilotChatAssistantMessage.ToolbarButton = ({ title, tooltip, tooltipClassName, children, ...props }) => {
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
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
|
+
});
|
|
6507
7750
|
};
|
|
6508
7751
|
_CopilotChatAssistantMessage.CopyButton = ({ className, title, onClick, ...props }) => {
|
|
6509
7752
|
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
@@ -6542,7 +7785,10 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, o
|
|
|
6542
7785
|
"data-testid": "copilot-thumbs-up-button",
|
|
6543
7786
|
title: title || labels.assistantMessageToolbarThumbsUpLabel,
|
|
6544
7787
|
...props,
|
|
6545
|
-
children: /* @__PURE__ */ jsx(ThumbsUp, {
|
|
7788
|
+
children: /* @__PURE__ */ jsx(ThumbsUp, {
|
|
7789
|
+
className: "cpk:size-[18px]",
|
|
7790
|
+
fill: props["aria-pressed"] === true ? "currentColor" : "none"
|
|
7791
|
+
})
|
|
6546
7792
|
});
|
|
6547
7793
|
};
|
|
6548
7794
|
_CopilotChatAssistantMessage.ThumbsDownButton = ({ title, ...props }) => {
|
|
@@ -6551,7 +7797,45 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, o
|
|
|
6551
7797
|
"data-testid": "copilot-thumbs-down-button",
|
|
6552
7798
|
title: title || labels.assistantMessageToolbarThumbsDownLabel,
|
|
6553
7799
|
...props,
|
|
6554
|
-
children: /* @__PURE__ */ jsx(ThumbsDown, {
|
|
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
|
+
})]
|
|
6555
7839
|
});
|
|
6556
7840
|
};
|
|
6557
7841
|
_CopilotChatAssistantMessage.ReadAloudButton = ({ title, ...props }) => {
|
|
@@ -6579,6 +7863,7 @@ CopilotChatAssistantMessage.CopyButton.displayName = "CopilotChatAssistantMessag
|
|
|
6579
7863
|
CopilotChatAssistantMessage.InspectorButton.displayName = "CopilotChatAssistantMessage.InspectorButton";
|
|
6580
7864
|
CopilotChatAssistantMessage.ThumbsUpButton.displayName = "CopilotChatAssistantMessage.ThumbsUpButton";
|
|
6581
7865
|
CopilotChatAssistantMessage.ThumbsDownButton.displayName = "CopilotChatAssistantMessage.ThumbsDownButton";
|
|
7866
|
+
CopilotChatAssistantMessage.FeedbackComment.displayName = "CopilotChatAssistantMessage.FeedbackComment";
|
|
6582
7867
|
CopilotChatAssistantMessage.ReadAloudButton.displayName = "CopilotChatAssistantMessage.ReadAloudButton";
|
|
6583
7868
|
CopilotChatAssistantMessage.RegenerateButton.displayName = "CopilotChatAssistantMessage.RegenerateButton";
|
|
6584
7869
|
var CopilotChatAssistantMessage_default = CopilotChatAssistantMessage;
|
|
@@ -6884,6 +8169,7 @@ function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfB
|
|
|
6884
8169
|
});
|
|
6885
8170
|
};
|
|
6886
8171
|
_CopilotChatUserMessage.BranchNavigation = ({ className, currentBranch = 0, numberOfBranches = 1, onSwitchToBranch, message, ...props }) => {
|
|
8172
|
+
const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
|
|
6887
8173
|
if (!numberOfBranches || numberOfBranches <= 1 || !onSwitchToBranch) return null;
|
|
6888
8174
|
const canGoPrev = currentBranch > 0;
|
|
6889
8175
|
const canGoNext = currentBranch < numberOfBranches - 1;
|
|
@@ -6902,6 +8188,7 @@ function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfB
|
|
|
6902
8188
|
}),
|
|
6903
8189
|
disabled: !canGoPrev,
|
|
6904
8190
|
className: "cpk:h-6 cpk:w-6 cpk:p-0",
|
|
8191
|
+
"aria-label": labels.userMessageToolbarPreviousBranchLabel,
|
|
6905
8192
|
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "cpk:size-[20px]" })
|
|
6906
8193
|
}),
|
|
6907
8194
|
/* @__PURE__ */ jsxs("span", {
|
|
@@ -6922,6 +8209,7 @@ function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfB
|
|
|
6922
8209
|
}),
|
|
6923
8210
|
disabled: !canGoNext,
|
|
6924
8211
|
className: "cpk:h-6 cpk:w-6 cpk:p-0",
|
|
8212
|
+
"aria-label": labels.userMessageToolbarNextBranchLabel,
|
|
6925
8213
|
children: /* @__PURE__ */ jsx(ChevronRight, { className: "cpk:size-[20px]" })
|
|
6926
8214
|
})
|
|
6927
8215
|
]
|
|
@@ -6942,7 +8230,7 @@ var CopilotChatUserMessage_default = CopilotChatUserMessage;
|
|
|
6942
8230
|
/**
|
|
6943
8231
|
* Formats an elapsed duration (in seconds) to a human-readable string.
|
|
6944
8232
|
*/
|
|
6945
|
-
function formatDuration(seconds) {
|
|
8233
|
+
function formatDuration$1(seconds) {
|
|
6946
8234
|
if (seconds < 1) return "a few seconds";
|
|
6947
8235
|
if (seconds < 60) return `${Math.round(seconds)} seconds`;
|
|
6948
8236
|
const mins = Math.floor(seconds / 60);
|
|
@@ -6980,7 +8268,7 @@ function CopilotChatReasoningMessage({ message, messages, isRunning, isLatest: i
|
|
|
6980
8268
|
userToggledRef.current = true;
|
|
6981
8269
|
setIsOpen((prev) => !prev);
|
|
6982
8270
|
} : void 0;
|
|
6983
|
-
const label = isStreaming ? "Thinking…" : `Thought for ${formatDuration(elapsed)}`;
|
|
8271
|
+
const label = isStreaming ? "Thinking…" : `Thought for ${formatDuration$1(elapsed)}`;
|
|
6984
8272
|
const boundHeader = renderSlot(header, CopilotChatReasoningMessage.Header, {
|
|
6985
8273
|
isOpen,
|
|
6986
8274
|
label,
|
|
@@ -7202,6 +8490,71 @@ const ScrollElementContext = React.createContext(null);
|
|
|
7202
8490
|
*/
|
|
7203
8491
|
const ScrollPinnedContext = React.createContext(false);
|
|
7204
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
|
+
|
|
7205
8558
|
//#endregion
|
|
7206
8559
|
//#region src/v2/components/intelligence-indicator/IntelligenceIndicatorView.tsx
|
|
7207
8560
|
/**
|
|
@@ -7688,7 +9041,7 @@ function messageGroup(group) {
|
|
|
7688
9041
|
}
|
|
7689
9042
|
const GROUP_ROW_KEY_PREFIX = "copilotkit-group:";
|
|
7690
9043
|
const VIRTUALIZE_THRESHOLD = 50;
|
|
7691
|
-
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 }) {
|
|
7692
9045
|
const isPinnedToBottom = useContext(ScrollPinnedContext);
|
|
7693
9046
|
const renderCustomMessage = useRenderCustomMessages();
|
|
7694
9047
|
const { renderActivityMessage } = useRenderActivityMessage();
|
|
@@ -7729,6 +9082,100 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
7729
9082
|
transformedMessages
|
|
7730
9083
|
]);
|
|
7731
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
|
+
};
|
|
7732
9179
|
const transformDuplicateId = useMemo(() => {
|
|
7733
9180
|
if (process.env.NODE_ENV === "production" || !transformMessages && !groupMessages) return;
|
|
7734
9181
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -7794,6 +9241,18 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
7794
9241
|
const { Component: AssistantComponent, slotProps: assistantSlotProps } = useMemo(() => resolveSlotComponent(assistantMessage, CopilotChatAssistantMessage_default), [assistantMessage]);
|
|
7795
9242
|
const agentId = config?.agentId;
|
|
7796
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
|
+
]);
|
|
7797
9256
|
const assistantSlotPropsWithFeedback = useMemo(() => {
|
|
7798
9257
|
const onThumbsUp = assistantSlotProps?.onThumbsUp;
|
|
7799
9258
|
const onThumbsDown = assistantSlotProps?.onThumbsDown;
|
|
@@ -7860,7 +9319,7 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
7860
9319
|
measuredRef.current.total = total - (sizes.get(index) ?? 0) + height;
|
|
7861
9320
|
sizes.set(index, height);
|
|
7862
9321
|
}
|
|
7863
|
-
return height;
|
|
9322
|
+
return height > 0 ? height : measuredRef.current.sizes.get(index) ?? 100;
|
|
7864
9323
|
}, []);
|
|
7865
9324
|
const isPinnedToBottomRef = React.useRef(isPinnedToBottom);
|
|
7866
9325
|
const shouldAdjustScrollOnResize = React.useCallback((item, _delta, instance) => {
|
|
@@ -7870,7 +9329,7 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
7870
9329
|
}, []);
|
|
7871
9330
|
const virtualizer = useVirtualizer({
|
|
7872
9331
|
count: shouldVirtualize ? rows.length : 0,
|
|
7873
|
-
getScrollElement: () => scrollElement,
|
|
9332
|
+
getScrollElement: () => shouldVirtualize ? scrollElement : null,
|
|
7874
9333
|
estimateSize: estimateRowSize,
|
|
7875
9334
|
overscan: 5,
|
|
7876
9335
|
measureElement: measureRowElement,
|
|
@@ -7881,8 +9340,11 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
7881
9340
|
});
|
|
7882
9341
|
isPinnedToBottomRef.current = isPinnedToBottom;
|
|
7883
9342
|
virtualizer.shouldAdjustScrollPositionOnItemSizeChange = shouldAdjustScrollOnResize;
|
|
9343
|
+
const lastEndAlignedFirstMessageRef = React.useRef(void 0);
|
|
7884
9344
|
useLayoutEffect(() => {
|
|
7885
9345
|
if (!shouldVirtualize || !rows.length) return;
|
|
9346
|
+
if (lastEndAlignedFirstMessageRef.current === firstMessageId) return;
|
|
9347
|
+
lastEndAlignedFirstMessageRef.current = firstMessageId;
|
|
7886
9348
|
virtualizer.scrollToIndex(rows.length - 1, { align: "end" });
|
|
7887
9349
|
}, [shouldVirtualize, firstMessageId]);
|
|
7888
9350
|
const intelligenceTurnAnchors = useMemo(() => getIntelligenceTurnAnchors(deduplicatedMessages, renderedMessages), [deduplicatedMessages, renderedMessages]);
|
|
@@ -7890,6 +9352,8 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
7890
9352
|
const elements = [];
|
|
7891
9353
|
const stateSnapshot = renderCustomMessage ? getStateSnapshotForMessage(message.id) : void 0;
|
|
7892
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));
|
|
7893
9357
|
if (renderCustomMessage) elements.push(/* @__PURE__ */ jsx(MemoizedCustomMessage, {
|
|
7894
9358
|
message,
|
|
7895
9359
|
position: "before",
|
|
@@ -7913,14 +9377,20 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
7913
9377
|
message,
|
|
7914
9378
|
renderActivityMessage
|
|
7915
9379
|
}, rowKey));
|
|
7916
|
-
else if (message.role === "reasoning")
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
7920
|
-
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
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
|
+
}
|
|
7924
9394
|
if (renderCustomMessage) elements.push(/* @__PURE__ */ jsx(MemoizedCustomMessage, {
|
|
7925
9395
|
message,
|
|
7926
9396
|
position: "after",
|
|
@@ -7948,52 +9418,157 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
7948
9418
|
children: row.messages.flatMap(renderMessageBlock)
|
|
7949
9419
|
}, rowKey(row))];
|
|
7950
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
|
+
]);
|
|
7951
9511
|
const messageElements = shouldVirtualize ? [] : rows.flatMap(renderRow);
|
|
7952
|
-
if (children) return /* @__PURE__ */ jsx(
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
|
|
7958
|
-
|
|
7959
|
-
|
|
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
|
+
})
|
|
7960
9526
|
})
|
|
7961
9527
|
});
|
|
7962
9528
|
const lastMessage = renderedMessages[renderedMessages.length - 1];
|
|
7963
|
-
const showCursor = isRunning && lastMessage?.role !== "reasoning";
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
const row = rows[virtualItem.index];
|
|
7977
|
-
return /* @__PURE__ */ jsx("div", {
|
|
7978
|
-
"data-index": virtualItem.index,
|
|
7979
|
-
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", {
|
|
7980
9542
|
style: {
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
left: 0,
|
|
7984
|
-
width: "100%",
|
|
7985
|
-
transform: `translateY(${virtualItem.start}px)`
|
|
9543
|
+
height: virtualizer.getTotalSize(),
|
|
9544
|
+
position: "relative"
|
|
7986
9545
|
},
|
|
7987
|
-
children:
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
|
|
7992
|
-
|
|
7993
|
-
|
|
7994
|
-
|
|
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
|
+
]
|
|
7995
9570
|
})
|
|
7996
|
-
|
|
9571
|
+
})
|
|
7997
9572
|
});
|
|
7998
9573
|
}
|
|
7999
9574
|
CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
|
|
@@ -8378,6 +9953,16 @@ function DropOverlay() {
|
|
|
8378
9953
|
});
|
|
8379
9954
|
}
|
|
8380
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;
|
|
8381
9966
|
const [inputContainerEl, setInputContainerEl] = useState(null);
|
|
8382
9967
|
const [inputContainerHeight, setInputContainerHeight] = useState(0);
|
|
8383
9968
|
const [isResizing, setIsResizing] = useState(false);
|
|
@@ -8444,6 +10029,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
8444
10029
|
}) : null;
|
|
8445
10030
|
const BoundScrollView = renderSlot(scrollView, CopilotChatView.ScrollView, {
|
|
8446
10031
|
autoScroll,
|
|
10032
|
+
scrollThreadId,
|
|
8447
10033
|
inputContainerHeight,
|
|
8448
10034
|
isResizing,
|
|
8449
10035
|
children: /* @__PURE__ */ jsx("div", {
|
|
@@ -8539,12 +10125,102 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
8539
10125
|
});
|
|
8540
10126
|
}
|
|
8541
10127
|
(function(_CopilotChatView) {
|
|
8542
|
-
const ScrollContent = ({ children, scrollToBottomButton, feather, inputContainerHeight, isResizing }) => {
|
|
8543
|
-
const { isAtBottom, scrollToBottom, scrollRef, state } = useStickToBottomContext();
|
|
10128
|
+
const ScrollContent = ({ children, scrollToBottomButton, feather, inputContainerHeight, isResizing, scrollThreadId }) => {
|
|
10129
|
+
const { isAtBottom, scrollToBottom, stopScroll, scrollRef, state } = useStickToBottomContext();
|
|
8544
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;
|
|
8545
10135
|
useLayoutEffect(() => {
|
|
8546
10136
|
setScrollEl(scrollRef.current ?? null);
|
|
8547
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]);
|
|
8548
10224
|
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
8549
10225
|
return /* @__PURE__ */ jsx(ScrollElementContext.Provider, {
|
|
8550
10226
|
value: scrollEl,
|
|
@@ -8566,7 +10242,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
8566
10242
|
!isAtBottom && !isResizing && /* @__PURE__ */ jsx("div", {
|
|
8567
10243
|
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
8568
10244
|
style: { bottom: `${inputContainerHeight + SCROLL_BUTTON_OFFSET}px` },
|
|
8569
|
-
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () =>
|
|
10245
|
+
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => startBottomPin() })
|
|
8570
10246
|
})
|
|
8571
10247
|
] })
|
|
8572
10248
|
})
|
|
@@ -8614,7 +10290,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
8614
10290
|
})
|
|
8615
10291
|
});
|
|
8616
10292
|
};
|
|
8617
|
-
_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 }) => {
|
|
8618
10294
|
const mode = normalizeAutoScroll(autoScroll);
|
|
8619
10295
|
const [hasMounted, setHasMounted] = useState(false);
|
|
8620
10296
|
const scrollRef = useRef(null);
|
|
@@ -8703,6 +10379,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
8703
10379
|
initial: "smooth",
|
|
8704
10380
|
...props,
|
|
8705
10381
|
children: /* @__PURE__ */ jsx(ScrollContent, {
|
|
10382
|
+
scrollThreadId,
|
|
8706
10383
|
scrollToBottomButton,
|
|
8707
10384
|
feather,
|
|
8708
10385
|
inputContainerHeight,
|
|
@@ -8711,14 +10388,18 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
8711
10388
|
})
|
|
8712
10389
|
});
|
|
8713
10390
|
};
|
|
8714
|
-
_CopilotChatView.ScrollToBottomButton = ({ className, ...props }) =>
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
|
|
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
|
+
};
|
|
8722
10403
|
_CopilotChatView.Feather = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
8723
10404
|
className,
|
|
8724
10405
|
...props
|
|
@@ -10101,6 +11782,7 @@ function CopilotPopupViewInternal({ header, toggleButton, width, height, clickOu
|
|
|
10101
11782
|
if (containerRef.current?.contains(target)) return;
|
|
10102
11783
|
const toggleButton = document.querySelector("[data-slot='chat-toggle-button']");
|
|
10103
11784
|
if (toggleButton && toggleButton.contains(target)) return;
|
|
11785
|
+
if (target instanceof Element && target.closest("[data-copilotkit-popover]")) return;
|
|
10104
11786
|
setModalOpen?.(false);
|
|
10105
11787
|
};
|
|
10106
11788
|
document.addEventListener("pointerdown", handlePointerDown);
|
|
@@ -10611,62 +12293,14 @@ CopilotThreadsDrawer.displayName = "CopilotThreadsDrawer";
|
|
|
10611
12293
|
|
|
10612
12294
|
//#endregion
|
|
10613
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
|
+
*/
|
|
10614
12300
|
const WildcardToolCallRender = defineToolCallRenderer({
|
|
10615
12301
|
name: "*",
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
const statusString = String(status);
|
|
10619
|
-
return /* @__PURE__ */ jsx("div", {
|
|
10620
|
-
className: "cpk:mt-2 cpk:pb-2",
|
|
10621
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
10622
|
-
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",
|
|
10623
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
10624
|
-
className: "cpk:flex cpk:items-center cpk:justify-between cpk:gap-3 cpk:cursor-pointer",
|
|
10625
|
-
onClick: () => setIsExpanded(!isExpanded),
|
|
10626
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
10627
|
-
className: "cpk:flex cpk:items-center cpk:gap-2 cpk:min-w-0",
|
|
10628
|
-
children: [
|
|
10629
|
-
/* @__PURE__ */ jsx("svg", {
|
|
10630
|
-
className: `cpk:h-4 cpk:w-4 cpk:text-zinc-500 cpk:dark:text-zinc-400 cpk:transition-transform ${isExpanded ? "cpk:rotate-90" : ""}`,
|
|
10631
|
-
fill: "none",
|
|
10632
|
-
viewBox: "0 0 24 24",
|
|
10633
|
-
strokeWidth: 2,
|
|
10634
|
-
stroke: "currentColor",
|
|
10635
|
-
children: /* @__PURE__ */ jsx("path", {
|
|
10636
|
-
strokeLinecap: "round",
|
|
10637
|
-
strokeLinejoin: "round",
|
|
10638
|
-
d: "M8.25 4.5l7.5 7.5-7.5 7.5"
|
|
10639
|
-
})
|
|
10640
|
-
}),
|
|
10641
|
-
/* @__PURE__ */ jsx("span", { className: "cpk:inline-block cpk:h-2 cpk:w-2 cpk:rounded-full cpk:bg-blue-500" }),
|
|
10642
|
-
/* @__PURE__ */ jsx("span", {
|
|
10643
|
-
className: "cpk:truncate cpk:text-sm cpk:font-medium cpk:text-zinc-900 cpk:dark:text-zinc-100",
|
|
10644
|
-
children: name
|
|
10645
|
-
})
|
|
10646
|
-
]
|
|
10647
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
10648
|
-
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"}`,
|
|
10649
|
-
children: String(status)
|
|
10650
|
-
})]
|
|
10651
|
-
}), isExpanded && /* @__PURE__ */ jsxs("div", {
|
|
10652
|
-
className: "cpk:mt-3 cpk:grid cpk:gap-4",
|
|
10653
|
-
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
10654
|
-
className: "cpk:text-xs cpk:uppercase cpk:tracking-wide cpk:text-zinc-500 cpk:dark:text-zinc-400",
|
|
10655
|
-
children: "Arguments"
|
|
10656
|
-
}), /* @__PURE__ */ jsx("pre", {
|
|
10657
|
-
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",
|
|
10658
|
-
children: JSON.stringify(args ?? {}, null, 2)
|
|
10659
|
-
})] }), result !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
|
|
10660
|
-
className: "cpk:text-xs cpk:uppercase cpk:tracking-wide cpk:text-zinc-500 cpk:dark:text-zinc-400",
|
|
10661
|
-
children: "Result"
|
|
10662
|
-
}), /* @__PURE__ */ jsx("pre", {
|
|
10663
|
-
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",
|
|
10664
|
-
children: typeof result === "string" ? result : JSON.stringify(result, null, 2)
|
|
10665
|
-
})] })]
|
|
10666
|
-
})]
|
|
10667
|
-
})
|
|
10668
|
-
});
|
|
10669
|
-
}
|
|
12302
|
+
group: true,
|
|
12303
|
+
render: (props) => /* @__PURE__ */ jsx(DefaultToolCallRenderer, { ...adaptRendererProps(props) })
|
|
10670
12304
|
});
|
|
10671
12305
|
|
|
10672
12306
|
//#endregion
|
|
@@ -12849,5 +14483,5 @@ function validateProps(props) {
|
|
|
12849
14483
|
}
|
|
12850
14484
|
|
|
12851
14485
|
//#endregion
|
|
12852
|
-
export {
|
|
12853
|
-
//# sourceMappingURL=copilotkit-
|
|
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
|