@yourgpt/copilot-sdk 0.1.1 → 1.0.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/{thread-CLmfwine.d.ts → ThreadManager-BCVt-_k_.d.cts} +376 -223
- package/dist/{thread-CLmfwine.d.cts → ThreadManager-BjC15mh8.d.ts} +376 -223
- package/dist/{chunk-IH7WXWX4.cjs → chunk-42YQ4ATO.cjs} +889 -2
- package/dist/chunk-42YQ4ATO.cjs.map +1 -0
- package/dist/{chunk-R452HH3J.cjs → chunk-BN75ZW24.cjs} +455 -26
- package/dist/chunk-BN75ZW24.cjs.map +1 -0
- package/dist/{chunk-QWQELTEB.js → chunk-QSEGNATZ.js} +882 -3
- package/dist/chunk-QSEGNATZ.js.map +1 -0
- package/dist/{chunk-FO75W5UI.js → chunk-XAVZZVUL.js} +428 -4
- package/dist/chunk-XAVZZVUL.js.map +1 -0
- package/dist/core/index.cjs +99 -71
- package/dist/core/index.d.cts +4 -4
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +1 -1
- package/dist/react/index.cjs +66 -34
- package/dist/react/index.d.cts +371 -5
- package/dist/react/index.d.ts +371 -5
- package/dist/react/index.js +2 -2
- package/dist/{tools-eeJ5iEC4.d.ts → types-BtAaOV07.d.cts} +367 -1
- package/dist/{tools-eeJ5iEC4.d.cts → types-BtAaOV07.d.ts} +367 -1
- package/dist/ui/index.cjs +1703 -467
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +333 -38
- package/dist/ui/index.d.ts +333 -38
- package/dist/ui/index.js +1699 -467
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-FO75W5UI.js.map +0 -1
- package/dist/chunk-IH7WXWX4.cjs.map +0 -1
- package/dist/chunk-QWQELTEB.js.map +0 -1
- package/dist/chunk-R452HH3J.cjs.map +0 -1
package/dist/ui/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useCopilot } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
import { useCopilot, useThreadManager } from '../chunk-XAVZZVUL.js';
|
|
2
|
+
import { createServerAdapter } from '../chunk-QSEGNATZ.js';
|
|
3
3
|
import { clsx } from 'clsx';
|
|
4
4
|
import { twMerge } from 'tailwind-merge';
|
|
5
5
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
@@ -16,6 +16,7 @@ import { useStickToBottomContext, StickToBottom as StickToBottom$1 } from 'use-s
|
|
|
16
16
|
import { Tooltip as Tooltip$1 } from '@base-ui/react/tooltip';
|
|
17
17
|
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
|
18
18
|
import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
|
|
19
|
+
import { Popover as Popover$1 } from '@base-ui/react/popover';
|
|
19
20
|
|
|
20
21
|
function cn(...inputs) {
|
|
21
22
|
return twMerge(clsx(inputs));
|
|
@@ -865,12 +866,13 @@ var MessageAvatar = ({
|
|
|
865
866
|
src,
|
|
866
867
|
alt,
|
|
867
868
|
fallback,
|
|
869
|
+
fallbackIcon,
|
|
868
870
|
delayMs,
|
|
869
871
|
className
|
|
870
872
|
}) => {
|
|
871
873
|
return /* @__PURE__ */ jsxs(Avatar, { className: cn("size-7 shrink-0", className), children: [
|
|
872
874
|
/* @__PURE__ */ jsx(AvatarImage, { src, alt }),
|
|
873
|
-
|
|
875
|
+
/* @__PURE__ */ jsx(AvatarFallback, { delayMs, children: fallbackIcon || fallback })
|
|
874
876
|
] });
|
|
875
877
|
};
|
|
876
878
|
var proseSizeMap = {
|
|
@@ -1904,6 +1906,27 @@ function AlertTriangleIcon({ className }) {
|
|
|
1904
1906
|
}
|
|
1905
1907
|
);
|
|
1906
1908
|
}
|
|
1909
|
+
function ArrowUpRightIcon({ className }) {
|
|
1910
|
+
return /* @__PURE__ */ jsxs(
|
|
1911
|
+
"svg",
|
|
1912
|
+
{
|
|
1913
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1914
|
+
width: "24",
|
|
1915
|
+
height: "24",
|
|
1916
|
+
viewBox: "0 0 24 24",
|
|
1917
|
+
fill: "none",
|
|
1918
|
+
stroke: "currentColor",
|
|
1919
|
+
strokeWidth: "2",
|
|
1920
|
+
strokeLinecap: "round",
|
|
1921
|
+
strokeLinejoin: "round",
|
|
1922
|
+
className,
|
|
1923
|
+
children: [
|
|
1924
|
+
/* @__PURE__ */ jsx("path", { d: "M7 7h10v10" }),
|
|
1925
|
+
/* @__PURE__ */ jsx("path", { d: "M7 17 17 7" })
|
|
1926
|
+
]
|
|
1927
|
+
}
|
|
1928
|
+
);
|
|
1929
|
+
}
|
|
1907
1930
|
var ConfirmationContext = React8.createContext(null);
|
|
1908
1931
|
function useConfirmationContext() {
|
|
1909
1932
|
const context = React8.useContext(ConfirmationContext);
|
|
@@ -2976,173 +2999,722 @@ function SimpleModelSelector({
|
|
|
2976
2999
|
}
|
|
2977
3000
|
);
|
|
2978
3001
|
}
|
|
2979
|
-
function
|
|
2980
|
-
return /* @__PURE__ */
|
|
2981
|
-
|
|
3002
|
+
function Popover({ children, open, defaultOpen, onOpenChange }) {
|
|
3003
|
+
return /* @__PURE__ */ jsx(
|
|
3004
|
+
Popover$1.Root,
|
|
3005
|
+
{
|
|
3006
|
+
open,
|
|
3007
|
+
defaultOpen,
|
|
3008
|
+
onOpenChange,
|
|
3009
|
+
children
|
|
3010
|
+
}
|
|
3011
|
+
);
|
|
3012
|
+
}
|
|
3013
|
+
function PopoverTrigger({
|
|
3014
|
+
children,
|
|
3015
|
+
asChild,
|
|
3016
|
+
className,
|
|
3017
|
+
...props
|
|
3018
|
+
}) {
|
|
3019
|
+
if (asChild && React8.isValidElement(children)) {
|
|
3020
|
+
return /* @__PURE__ */ jsx(Popover$1.Trigger, { render: children, className, ...props });
|
|
3021
|
+
}
|
|
3022
|
+
return /* @__PURE__ */ jsx(Popover$1.Trigger, { className, ...props, children });
|
|
3023
|
+
}
|
|
3024
|
+
function PopoverContent({
|
|
3025
|
+
children,
|
|
3026
|
+
className,
|
|
3027
|
+
side = "bottom",
|
|
3028
|
+
align = "start",
|
|
3029
|
+
sideOffset = 4
|
|
3030
|
+
}) {
|
|
3031
|
+
return /* @__PURE__ */ jsx(Popover$1.Portal, { children: /* @__PURE__ */ jsx(Popover$1.Positioner, { side, align, sideOffset, children: /* @__PURE__ */ jsx(
|
|
3032
|
+
Popover$1.Popup,
|
|
2982
3033
|
{
|
|
2983
3034
|
className: cn(
|
|
2984
|
-
"
|
|
3035
|
+
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none",
|
|
3036
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
3037
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
3038
|
+
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
3039
|
+
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
|
|
3040
|
+
"data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
2985
3041
|
className
|
|
2986
3042
|
),
|
|
3043
|
+
children
|
|
3044
|
+
}
|
|
3045
|
+
) }) });
|
|
3046
|
+
}
|
|
3047
|
+
function formatDate(date) {
|
|
3048
|
+
const now = /* @__PURE__ */ new Date();
|
|
3049
|
+
const diff = now.getTime() - date.getTime();
|
|
3050
|
+
if (diff < 60 * 1e3) {
|
|
3051
|
+
return "Just now";
|
|
3052
|
+
}
|
|
3053
|
+
if (diff < 60 * 60 * 1e3) {
|
|
3054
|
+
const mins = Math.floor(diff / (60 * 1e3));
|
|
3055
|
+
return `${mins}m ago`;
|
|
3056
|
+
}
|
|
3057
|
+
if (diff < 24 * 60 * 60 * 1e3) {
|
|
3058
|
+
const hours = Math.floor(diff / (60 * 60 * 1e3));
|
|
3059
|
+
return `${hours}h ago`;
|
|
3060
|
+
}
|
|
3061
|
+
if (diff < 7 * 24 * 60 * 60 * 1e3) {
|
|
3062
|
+
const days = Math.floor(diff / (24 * 60 * 60 * 1e3));
|
|
3063
|
+
return `${days}d ago`;
|
|
3064
|
+
}
|
|
3065
|
+
return date.toLocaleDateString();
|
|
3066
|
+
}
|
|
3067
|
+
function ChevronIcon({ className }) {
|
|
3068
|
+
return /* @__PURE__ */ jsx(
|
|
3069
|
+
"svg",
|
|
3070
|
+
{
|
|
3071
|
+
className: cn("w-4 h-4", className),
|
|
3072
|
+
fill: "none",
|
|
3073
|
+
viewBox: "0 0 24 24",
|
|
3074
|
+
stroke: "currentColor",
|
|
3075
|
+
strokeWidth: 2,
|
|
3076
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" })
|
|
3077
|
+
}
|
|
3078
|
+
);
|
|
3079
|
+
}
|
|
3080
|
+
function PlusIcon2({ className }) {
|
|
3081
|
+
return /* @__PURE__ */ jsx(
|
|
3082
|
+
"svg",
|
|
3083
|
+
{
|
|
3084
|
+
className: cn("w-4 h-4", className),
|
|
3085
|
+
fill: "none",
|
|
3086
|
+
viewBox: "0 0 24 24",
|
|
3087
|
+
stroke: "currentColor",
|
|
3088
|
+
strokeWidth: 2,
|
|
3089
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" })
|
|
3090
|
+
}
|
|
3091
|
+
);
|
|
3092
|
+
}
|
|
3093
|
+
function CheckIcon2({ className }) {
|
|
3094
|
+
return /* @__PURE__ */ jsx(
|
|
3095
|
+
"svg",
|
|
3096
|
+
{
|
|
3097
|
+
className: cn("w-4 h-4", className),
|
|
3098
|
+
fill: "none",
|
|
3099
|
+
viewBox: "0 0 24 24",
|
|
3100
|
+
stroke: "currentColor",
|
|
3101
|
+
strokeWidth: 2,
|
|
3102
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" })
|
|
3103
|
+
}
|
|
3104
|
+
);
|
|
3105
|
+
}
|
|
3106
|
+
function TrashIcon({ className }) {
|
|
3107
|
+
return /* @__PURE__ */ jsxs(
|
|
3108
|
+
"svg",
|
|
3109
|
+
{
|
|
3110
|
+
className: cn("w-4 h-4", className),
|
|
3111
|
+
fill: "none",
|
|
3112
|
+
viewBox: "0 0 24 24",
|
|
3113
|
+
stroke: "currentColor",
|
|
3114
|
+
strokeWidth: 2,
|
|
2987
3115
|
children: [
|
|
2988
|
-
/* @__PURE__ */ jsx("
|
|
2989
|
-
|
|
2990
|
-
"
|
|
3116
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 6h18" }),
|
|
3117
|
+
/* @__PURE__ */ jsx(
|
|
3118
|
+
"path",
|
|
2991
3119
|
{
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
3120
|
+
strokeLinecap: "round",
|
|
3121
|
+
strokeLinejoin: "round",
|
|
3122
|
+
d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"
|
|
3123
|
+
}
|
|
3124
|
+
),
|
|
3125
|
+
/* @__PURE__ */ jsx(
|
|
3126
|
+
"path",
|
|
3127
|
+
{
|
|
3128
|
+
strokeLinecap: "round",
|
|
3129
|
+
strokeLinejoin: "round",
|
|
3130
|
+
d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"
|
|
2997
3131
|
}
|
|
2998
3132
|
)
|
|
2999
3133
|
]
|
|
3000
3134
|
}
|
|
3001
3135
|
);
|
|
3002
3136
|
}
|
|
3003
|
-
function
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
}
|
|
3020
|
-
function DefaultMessage({
|
|
3021
|
-
message,
|
|
3022
|
-
userAvatar,
|
|
3023
|
-
assistantAvatar,
|
|
3024
|
-
showUserAvatar = false,
|
|
3025
|
-
userMessageClassName,
|
|
3026
|
-
assistantMessageClassName,
|
|
3027
|
-
size = "sm",
|
|
3028
|
-
isLastMessage = false,
|
|
3029
|
-
isLoading = false,
|
|
3030
|
-
registeredTools,
|
|
3031
|
-
toolRenderers,
|
|
3032
|
-
onApproveToolExecution,
|
|
3033
|
-
onRejectToolExecution,
|
|
3034
|
-
showFollowUps = true,
|
|
3035
|
-
onFollowUpClick,
|
|
3036
|
-
followUpClassName,
|
|
3037
|
-
followUpButtonClassName
|
|
3137
|
+
function ThreadPicker({
|
|
3138
|
+
value,
|
|
3139
|
+
threads,
|
|
3140
|
+
onSelect,
|
|
3141
|
+
onDeleteThread,
|
|
3142
|
+
onNewThread,
|
|
3143
|
+
placeholder = "Select conversation...",
|
|
3144
|
+
newThreadLabel = "New conversation",
|
|
3145
|
+
disabled = false,
|
|
3146
|
+
loading = false,
|
|
3147
|
+
size = "md",
|
|
3148
|
+
className,
|
|
3149
|
+
buttonClassName,
|
|
3150
|
+
dropdownClassName,
|
|
3151
|
+
itemClassName,
|
|
3152
|
+
newButtonClassName
|
|
3038
3153
|
}) {
|
|
3039
|
-
const
|
|
3040
|
-
const
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3154
|
+
const [isOpen, setIsOpen] = React8.useState(false);
|
|
3155
|
+
const selectedThread = React8.useMemo(() => {
|
|
3156
|
+
if (!value) return null;
|
|
3157
|
+
return threads.find((t) => t.id === value) ?? null;
|
|
3158
|
+
}, [value, threads]);
|
|
3159
|
+
const handleSelect = (threadId) => {
|
|
3160
|
+
onSelect?.(threadId);
|
|
3161
|
+
setIsOpen(false);
|
|
3162
|
+
};
|
|
3163
|
+
const handleNewThread = () => {
|
|
3164
|
+
onNewThread?.();
|
|
3165
|
+
setIsOpen(false);
|
|
3166
|
+
};
|
|
3167
|
+
return /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
|
|
3168
|
+
/* @__PURE__ */ jsxs(
|
|
3169
|
+
PopoverTrigger,
|
|
3052
3170
|
{
|
|
3171
|
+
disabled: disabled || loading,
|
|
3053
3172
|
className: cn(
|
|
3054
|
-
"flex gap-
|
|
3055
|
-
|
|
3173
|
+
"flex items-center gap-1 w-full",
|
|
3174
|
+
disabled && "opacity-50 cursor-not-allowed",
|
|
3175
|
+
className,
|
|
3176
|
+
buttonClassName
|
|
3056
3177
|
),
|
|
3057
3178
|
children: [
|
|
3058
|
-
/* @__PURE__ */
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
{
|
|
3062
|
-
className: cn(
|
|
3063
|
-
"rounded-lg px-4 py-2 bg-primary text-primary-foreground",
|
|
3064
|
-
userMessageClassName
|
|
3065
|
-
),
|
|
3066
|
-
size,
|
|
3067
|
-
children: message.content
|
|
3068
|
-
}
|
|
3069
|
-
),
|
|
3070
|
-
hasAttachments && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2 justify-end", children: message.attachments.map((attachment, index) => /* @__PURE__ */ jsx(AttachmentPreview, { attachment }, index)) })
|
|
3071
|
-
] }),
|
|
3072
|
-
showUserAvatar && /* @__PURE__ */ jsx(
|
|
3073
|
-
MessageAvatar,
|
|
3179
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 text-xs ", children: loading ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Loading..." }) : selectedThread ? /* @__PURE__ */ jsx("span", { className: "truncate font-medium text-muted-foreground hover:text-foreground", children: selectedThread.title || "Untitled conversation" }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }) }),
|
|
3180
|
+
/* @__PURE__ */ jsx(
|
|
3181
|
+
ChevronIcon,
|
|
3074
3182
|
{
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3183
|
+
className: cn(
|
|
3184
|
+
"flex-shrink-0 size-3 text-muted-foreground transition-transform",
|
|
3185
|
+
isOpen && "rotate-180"
|
|
3186
|
+
)
|
|
3078
3187
|
}
|
|
3079
3188
|
)
|
|
3080
3189
|
]
|
|
3081
3190
|
}
|
|
3082
|
-
);
|
|
3083
|
-
}
|
|
3084
|
-
const pendingApprovalTools = message.toolExecutions?.filter(
|
|
3085
|
-
(exec) => exec.approvalStatus === "required"
|
|
3086
|
-
);
|
|
3087
|
-
const completedTools = message.toolExecutions?.filter(
|
|
3088
|
-
(exec) => exec.approvalStatus !== "required"
|
|
3089
|
-
);
|
|
3090
|
-
const hasCustomRender = (toolName) => {
|
|
3091
|
-
if (toolRenderers?.[toolName]) return true;
|
|
3092
|
-
const toolDef = registeredTools?.find((t) => t.name === toolName);
|
|
3093
|
-
if (toolDef?.render) return true;
|
|
3094
|
-
return false;
|
|
3095
|
-
};
|
|
3096
|
-
const toolsWithCustomRender = completedTools?.filter(
|
|
3097
|
-
(exec) => hasCustomRender(exec.name)
|
|
3098
|
-
);
|
|
3099
|
-
const toolsWithoutCustomRender = completedTools?.filter(
|
|
3100
|
-
(exec) => !hasCustomRender(exec.name)
|
|
3101
|
-
);
|
|
3102
|
-
const toolSteps = toolsWithoutCustomRender?.map((exec) => ({
|
|
3103
|
-
id: exec.id,
|
|
3104
|
-
name: exec.name,
|
|
3105
|
-
args: exec.args,
|
|
3106
|
-
status: exec.status,
|
|
3107
|
-
result: exec.result,
|
|
3108
|
-
error: exec.error
|
|
3109
|
-
}));
|
|
3110
|
-
return /* @__PURE__ */ jsxs(Message, { className: "flex gap-2", children: [
|
|
3111
|
-
/* @__PURE__ */ jsx(
|
|
3112
|
-
MessageAvatar,
|
|
3113
|
-
{
|
|
3114
|
-
src: assistantAvatar.src || "",
|
|
3115
|
-
alt: "Assistant",
|
|
3116
|
-
fallback: assistantAvatar.fallback,
|
|
3117
|
-
className: "bg-primary text-primary-foreground"
|
|
3118
|
-
}
|
|
3119
3191
|
),
|
|
3120
|
-
/* @__PURE__ */ jsxs(
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3192
|
+
/* @__PURE__ */ jsxs(
|
|
3193
|
+
PopoverContent,
|
|
3194
|
+
{
|
|
3195
|
+
align: "start",
|
|
3196
|
+
className: cn(
|
|
3197
|
+
"w-[var(--anchor-width)] min-w-[250px] p-0 max-h-[300px] overflow-auto",
|
|
3198
|
+
dropdownClassName
|
|
3199
|
+
),
|
|
3200
|
+
children: [
|
|
3201
|
+
onNewThread && /* @__PURE__ */ jsxs(
|
|
3202
|
+
"button",
|
|
3203
|
+
{
|
|
3204
|
+
type: "button",
|
|
3205
|
+
onClick: handleNewThread,
|
|
3206
|
+
className: cn(
|
|
3207
|
+
"flex items-center gap-2 w-full px-2.5 py-1.5 text-left",
|
|
3208
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
3209
|
+
"focus:bg-accent focus:text-accent-foreground focus:outline-none",
|
|
3210
|
+
"border-b",
|
|
3211
|
+
newButtonClassName
|
|
3212
|
+
),
|
|
3213
|
+
children: [
|
|
3214
|
+
/* @__PURE__ */ jsx(PlusIcon2, { className: "text-primary size-3" }),
|
|
3215
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-xs", children: newThreadLabel })
|
|
3216
|
+
]
|
|
3217
|
+
}
|
|
3135
3218
|
),
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3219
|
+
threads.length > 0 ? threads.map((thread) => /* @__PURE__ */ jsxs(
|
|
3220
|
+
"div",
|
|
3221
|
+
{
|
|
3222
|
+
className: cn(
|
|
3223
|
+
"group flex items-center gap-1 w-full px-2.5 py-1.5",
|
|
3224
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
3225
|
+
"focus-within:bg-accent focus-within:text-accent-foreground",
|
|
3226
|
+
value === thread.id && "bg-accent",
|
|
3227
|
+
itemClassName
|
|
3228
|
+
),
|
|
3229
|
+
children: [
|
|
3230
|
+
/* @__PURE__ */ jsxs(
|
|
3231
|
+
"button",
|
|
3232
|
+
{
|
|
3233
|
+
type: "button",
|
|
3234
|
+
onClick: () => handleSelect(thread.id),
|
|
3235
|
+
className: "flex-1 flex flex-col gap-0.5 text-left focus:outline-none min-w-0",
|
|
3236
|
+
children: [
|
|
3237
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
3238
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-xs truncate", children: thread.title || "Untitled conversation" }),
|
|
3239
|
+
value === thread.id && /* @__PURE__ */ jsx(CheckIcon2, { className: "flex-shrink-0 text-primary size-3" })
|
|
3240
|
+
] }),
|
|
3241
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
|
|
3242
|
+
thread.preview && /* @__PURE__ */ jsx("span", { className: "truncate max-w-[180px]", children: thread.preview }),
|
|
3243
|
+
thread.preview && thread.updatedAt && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: "\xB7" }),
|
|
3244
|
+
thread.updatedAt && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: formatDate(thread.updatedAt) })
|
|
3245
|
+
] })
|
|
3246
|
+
]
|
|
3247
|
+
}
|
|
3248
|
+
),
|
|
3249
|
+
onDeleteThread && /* @__PURE__ */ jsx(
|
|
3250
|
+
"button",
|
|
3251
|
+
{
|
|
3252
|
+
type: "button",
|
|
3253
|
+
onClick: (e) => {
|
|
3254
|
+
e.stopPropagation();
|
|
3255
|
+
onDeleteThread(thread.id);
|
|
3256
|
+
},
|
|
3257
|
+
className: "flex-shrink-0 p-1 rounded opacity-0 group-hover:opacity-100 text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-all focus:opacity-100 focus:outline-none",
|
|
3258
|
+
"aria-label": "Delete thread",
|
|
3259
|
+
children: /* @__PURE__ */ jsx(TrashIcon, { className: "size-3" })
|
|
3260
|
+
}
|
|
3261
|
+
)
|
|
3262
|
+
]
|
|
3263
|
+
},
|
|
3264
|
+
thread.id
|
|
3265
|
+
)) : /* @__PURE__ */ jsx("div", { className: "px-2.5 py-3 text-center text-xs text-muted-foreground", children: "No conversations yet" })
|
|
3266
|
+
]
|
|
3267
|
+
}
|
|
3268
|
+
)
|
|
3269
|
+
] });
|
|
3270
|
+
}
|
|
3271
|
+
function formatDate2(date) {
|
|
3272
|
+
const now = /* @__PURE__ */ new Date();
|
|
3273
|
+
const diff = now.getTime() - date.getTime();
|
|
3274
|
+
if (diff < 60 * 1e3) {
|
|
3275
|
+
return "Just now";
|
|
3276
|
+
}
|
|
3277
|
+
if (diff < 60 * 60 * 1e3) {
|
|
3278
|
+
const mins = Math.floor(diff / (60 * 1e3));
|
|
3279
|
+
return `${mins}m ago`;
|
|
3280
|
+
}
|
|
3281
|
+
if (diff < 24 * 60 * 60 * 1e3) {
|
|
3282
|
+
const hours = Math.floor(diff / (60 * 60 * 1e3));
|
|
3283
|
+
return `${hours}h ago`;
|
|
3284
|
+
}
|
|
3285
|
+
if (diff < 7 * 24 * 60 * 60 * 1e3) {
|
|
3286
|
+
const days = Math.floor(diff / (24 * 60 * 60 * 1e3));
|
|
3287
|
+
return `${days}d ago`;
|
|
3288
|
+
}
|
|
3289
|
+
return date.toLocaleDateString();
|
|
3290
|
+
}
|
|
3291
|
+
function TrashIcon2({ className }) {
|
|
3292
|
+
return /* @__PURE__ */ jsx(
|
|
3293
|
+
"svg",
|
|
3294
|
+
{
|
|
3295
|
+
className: cn("w-4 h-4", className),
|
|
3296
|
+
fill: "none",
|
|
3297
|
+
viewBox: "0 0 24 24",
|
|
3298
|
+
stroke: "currentColor",
|
|
3299
|
+
strokeWidth: 2,
|
|
3300
|
+
children: /* @__PURE__ */ jsx(
|
|
3301
|
+
"path",
|
|
3302
|
+
{
|
|
3303
|
+
strokeLinecap: "round",
|
|
3304
|
+
strokeLinejoin: "round",
|
|
3305
|
+
d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
3306
|
+
}
|
|
3307
|
+
)
|
|
3308
|
+
}
|
|
3309
|
+
);
|
|
3310
|
+
}
|
|
3311
|
+
function PlusIcon3({ className }) {
|
|
3312
|
+
return /* @__PURE__ */ jsx(
|
|
3313
|
+
"svg",
|
|
3314
|
+
{
|
|
3315
|
+
className: cn("w-4 h-4", className),
|
|
3316
|
+
fill: "none",
|
|
3317
|
+
viewBox: "0 0 24 24",
|
|
3318
|
+
stroke: "currentColor",
|
|
3319
|
+
strokeWidth: 2,
|
|
3320
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" })
|
|
3321
|
+
}
|
|
3322
|
+
);
|
|
3323
|
+
}
|
|
3324
|
+
function MessageIcon({ className }) {
|
|
3325
|
+
return /* @__PURE__ */ jsx(
|
|
3326
|
+
"svg",
|
|
3327
|
+
{
|
|
3328
|
+
className: cn("w-4 h-4", className),
|
|
3329
|
+
fill: "none",
|
|
3330
|
+
viewBox: "0 0 24 24",
|
|
3331
|
+
stroke: "currentColor",
|
|
3332
|
+
strokeWidth: 2,
|
|
3333
|
+
children: /* @__PURE__ */ jsx(
|
|
3334
|
+
"path",
|
|
3335
|
+
{
|
|
3336
|
+
strokeLinecap: "round",
|
|
3337
|
+
strokeLinejoin: "round",
|
|
3338
|
+
d: "M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
|
|
3339
|
+
}
|
|
3340
|
+
)
|
|
3341
|
+
}
|
|
3342
|
+
);
|
|
3343
|
+
}
|
|
3344
|
+
function ThreadCardSkeleton() {
|
|
3345
|
+
return /* @__PURE__ */ jsx("div", { className: "p-3 rounded-lg border bg-card animate-pulse", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
3346
|
+
/* @__PURE__ */ jsx("div", { className: "w-8 h-8 rounded-full bg-muted" }),
|
|
3347
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-2", children: [
|
|
3348
|
+
/* @__PURE__ */ jsx("div", { className: "h-4 w-3/4 bg-muted rounded" }),
|
|
3349
|
+
/* @__PURE__ */ jsx("div", { className: "h-3 w-1/2 bg-muted rounded" })
|
|
3350
|
+
] })
|
|
3351
|
+
] }) });
|
|
3352
|
+
}
|
|
3353
|
+
function ThreadCard({
|
|
3354
|
+
thread,
|
|
3355
|
+
selected = false,
|
|
3356
|
+
onClick,
|
|
3357
|
+
onDelete,
|
|
3358
|
+
showDelete = true,
|
|
3359
|
+
className
|
|
3360
|
+
}) {
|
|
3361
|
+
const [isHovered, setIsHovered] = React8.useState(false);
|
|
3362
|
+
const handleDelete = (e) => {
|
|
3363
|
+
e.stopPropagation();
|
|
3364
|
+
onDelete?.();
|
|
3365
|
+
};
|
|
3366
|
+
return /* @__PURE__ */ jsx(
|
|
3367
|
+
"button",
|
|
3368
|
+
{
|
|
3369
|
+
type: "button",
|
|
3370
|
+
onClick,
|
|
3371
|
+
onMouseEnter: () => setIsHovered(true),
|
|
3372
|
+
onMouseLeave: () => setIsHovered(false),
|
|
3373
|
+
className: cn(
|
|
3374
|
+
"w-full p-3 rounded-lg border bg-card text-left transition-colors",
|
|
3375
|
+
"hover:bg-accent hover:border-accent-foreground/20",
|
|
3376
|
+
"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
3377
|
+
selected && "bg-accent border-primary/50",
|
|
3378
|
+
className
|
|
3379
|
+
),
|
|
3380
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
3381
|
+
/* @__PURE__ */ jsx(
|
|
3382
|
+
"div",
|
|
3383
|
+
{
|
|
3384
|
+
className: cn(
|
|
3385
|
+
"flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center",
|
|
3386
|
+
selected ? "bg-primary/10 text-primary" : "bg-muted text-muted-foreground"
|
|
3387
|
+
),
|
|
3388
|
+
children: /* @__PURE__ */ jsx(MessageIcon, {})
|
|
3389
|
+
}
|
|
3390
|
+
),
|
|
3391
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
3392
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
3393
|
+
/* @__PURE__ */ jsx("h3", { className: "font-medium text-sm truncate", children: thread.title || "Untitled conversation" }),
|
|
3394
|
+
showDelete && isHovered && onDelete && /* @__PURE__ */ jsx(
|
|
3395
|
+
"button",
|
|
3396
|
+
{
|
|
3397
|
+
type: "button",
|
|
3398
|
+
onClick: handleDelete,
|
|
3399
|
+
className: cn(
|
|
3400
|
+
"flex-shrink-0 p-1 rounded",
|
|
3401
|
+
"hover:bg-destructive/10 hover:text-destructive",
|
|
3402
|
+
"focus:outline-none focus:ring-2 focus:ring-destructive"
|
|
3403
|
+
),
|
|
3404
|
+
"aria-label": "Delete conversation",
|
|
3405
|
+
children: /* @__PURE__ */ jsx(TrashIcon2, { className: "w-3.5 h-3.5" })
|
|
3406
|
+
}
|
|
3407
|
+
)
|
|
3408
|
+
] }),
|
|
3409
|
+
thread.preview && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate mt-0.5", children: thread.preview }),
|
|
3410
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-1 text-xs text-muted-foreground", children: [
|
|
3411
|
+
thread.messageCount !== void 0 && thread.messageCount > 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
3412
|
+
thread.messageCount,
|
|
3413
|
+
" messages"
|
|
3414
|
+
] }),
|
|
3415
|
+
thread.messageCount !== void 0 && thread.messageCount > 0 && thread.updatedAt && /* @__PURE__ */ jsx("span", { children: "\xB7" }),
|
|
3416
|
+
thread.updatedAt && /* @__PURE__ */ jsx("span", { children: formatDate2(thread.updatedAt) })
|
|
3417
|
+
] })
|
|
3418
|
+
] })
|
|
3419
|
+
] })
|
|
3420
|
+
}
|
|
3421
|
+
);
|
|
3422
|
+
}
|
|
3423
|
+
function ThreadList({
|
|
3424
|
+
threads,
|
|
3425
|
+
selectedId,
|
|
3426
|
+
onSelect,
|
|
3427
|
+
onDelete,
|
|
3428
|
+
onNewThread,
|
|
3429
|
+
newThreadLabel = "New conversation",
|
|
3430
|
+
loading = false,
|
|
3431
|
+
emptyText = "No conversations yet",
|
|
3432
|
+
showDelete = true,
|
|
3433
|
+
className
|
|
3434
|
+
}) {
|
|
3435
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
|
|
3436
|
+
onNewThread && /* @__PURE__ */ jsxs(
|
|
3437
|
+
"button",
|
|
3438
|
+
{
|
|
3439
|
+
type: "button",
|
|
3440
|
+
onClick: onNewThread,
|
|
3441
|
+
className: cn(
|
|
3442
|
+
"flex items-center gap-2 p-3 rounded-lg border border-dashed",
|
|
3443
|
+
"hover:bg-accent hover:border-accent-foreground/20",
|
|
3444
|
+
"focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
3445
|
+
"transition-colors"
|
|
3446
|
+
),
|
|
3447
|
+
children: [
|
|
3448
|
+
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0 w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center", children: /* @__PURE__ */ jsx(PlusIcon3, { className: "text-primary" }) }),
|
|
3449
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-sm", children: newThreadLabel })
|
|
3450
|
+
]
|
|
3451
|
+
}
|
|
3452
|
+
),
|
|
3453
|
+
loading && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3454
|
+
/* @__PURE__ */ jsx(ThreadCardSkeleton, {}),
|
|
3455
|
+
/* @__PURE__ */ jsx(ThreadCardSkeleton, {}),
|
|
3456
|
+
/* @__PURE__ */ jsx(ThreadCardSkeleton, {})
|
|
3457
|
+
] }),
|
|
3458
|
+
!loading && threads.length > 0 && threads.map((thread) => /* @__PURE__ */ jsx(
|
|
3459
|
+
ThreadCard,
|
|
3460
|
+
{
|
|
3461
|
+
thread,
|
|
3462
|
+
selected: selectedId === thread.id,
|
|
3463
|
+
onClick: () => onSelect?.(thread.id),
|
|
3464
|
+
onDelete: () => onDelete?.(thread.id),
|
|
3465
|
+
showDelete
|
|
3466
|
+
},
|
|
3467
|
+
thread.id
|
|
3468
|
+
)),
|
|
3469
|
+
!loading && threads.length === 0 && /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground", children: emptyText })
|
|
3470
|
+
] });
|
|
3471
|
+
}
|
|
3472
|
+
var CopilotSDKLogo = (props) => /* @__PURE__ */ jsxs(
|
|
3473
|
+
"svg",
|
|
3474
|
+
{
|
|
3475
|
+
width: props.width || 170,
|
|
3476
|
+
height: props.height || 170,
|
|
3477
|
+
viewBox: "0 0 170 170",
|
|
3478
|
+
fill: "none",
|
|
3479
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3480
|
+
...props,
|
|
3481
|
+
className: cn("w-auto h-[30px]", props.className),
|
|
3482
|
+
children: [
|
|
3483
|
+
/* @__PURE__ */ jsx(
|
|
3484
|
+
"path",
|
|
3485
|
+
{
|
|
3486
|
+
opacity: 0.4,
|
|
3487
|
+
d: "M108.379 0C111.143 0 113.538 1.91574 114.146 4.61243L118.392 23.4631C121.492 37.2253 132.239 47.9726 146.001 51.0727L164.852 55.319C167.549 55.9265 169.465 58.3218 169.465 61.0861C169.465 63.8504 167.549 66.2457 164.852 66.8532L146.001 71.0995C132.239 74.1995 121.492 84.9467 118.392 98.7088L114.146 117.56C113.538 120.257 111.143 122.172 108.379 122.172C105.614 122.172 103.219 120.257 102.611 117.56L98.3651 98.7088C95.2651 84.9467 84.5179 74.1995 70.7558 71.0995L51.9049 66.8532C49.2082 66.2457 47.2924 63.8504 47.2924 61.0861C47.2924 58.3218 49.2082 55.9265 51.9049 55.319L70.7558 51.0727C84.5179 47.9726 95.2651 37.2253 98.3651 23.4631L102.611 4.61243C103.219 1.91574 105.614 0 108.379 0Z",
|
|
3488
|
+
fill: "#6352FF"
|
|
3489
|
+
}
|
|
3490
|
+
),
|
|
3491
|
+
/* @__PURE__ */ jsx(
|
|
3492
|
+
"path",
|
|
3493
|
+
{
|
|
3494
|
+
d: "M45.3219 78.8207C48.0863 78.8207 50.4816 80.736 51.089 83.4333L54.1221 96.8982C56.1931 106.092 63.3728 113.272 72.5663 115.342L86.0313 118.375C88.7285 118.983 90.6439 121.378 90.6439 124.143C90.6439 126.907 88.7285 129.302 86.0313 129.91L72.5663 132.943C63.3728 135.014 56.1931 142.193 54.1221 151.387L51.089 164.852C50.4816 167.549 48.0863 169.465 45.3219 169.465C42.5576 169.465 40.1623 167.549 39.5549 164.852L36.5218 151.387C34.4507 142.193 27.271 135.014 18.0772 132.943L4.61243 129.91C1.91574 129.302 0 126.907 0 124.143C0 121.378 1.91574 118.983 4.61243 118.375L18.0772 115.342C27.271 113.272 34.4507 106.092 36.5218 96.8982L39.5549 83.4333C40.1623 80.736 42.5576 78.8207 45.3219 78.8207Z",
|
|
3495
|
+
fill: "#523FFF"
|
|
3496
|
+
}
|
|
3497
|
+
),
|
|
3498
|
+
/* @__PURE__ */ jsx(
|
|
3499
|
+
"line",
|
|
3500
|
+
{
|
|
3501
|
+
x1: 137.266,
|
|
3502
|
+
y1: 162.316,
|
|
3503
|
+
x2: 83.1281,
|
|
3504
|
+
y2: 162.316,
|
|
3505
|
+
stroke: "currentColor",
|
|
3506
|
+
strokeWidth: 11.8231
|
|
3507
|
+
}
|
|
3508
|
+
),
|
|
3509
|
+
/* @__PURE__ */ jsx(
|
|
3510
|
+
"line",
|
|
3511
|
+
{
|
|
3512
|
+
x1: 160.188,
|
|
3513
|
+
y1: 162.316,
|
|
3514
|
+
x2: 140.811,
|
|
3515
|
+
y2: 162.316,
|
|
3516
|
+
stroke: "currentColor",
|
|
3517
|
+
strokeOpacity: 0.26,
|
|
3518
|
+
strokeWidth: 11.8231
|
|
3519
|
+
}
|
|
3520
|
+
)
|
|
3521
|
+
]
|
|
3522
|
+
}
|
|
3523
|
+
);
|
|
3524
|
+
var copilot_sdk_logo_default = CopilotSDKLogo;
|
|
3525
|
+
var DEFAULT_NAME = "AI Copilot";
|
|
3526
|
+
function ChatHeader({
|
|
3527
|
+
logo,
|
|
3528
|
+
name,
|
|
3529
|
+
title,
|
|
3530
|
+
threadPicker,
|
|
3531
|
+
onClose,
|
|
3532
|
+
className
|
|
3533
|
+
}) {
|
|
3534
|
+
const displayName = name || title || DEFAULT_NAME;
|
|
3535
|
+
const showDefaultLogo = logo === void 0;
|
|
3536
|
+
const showCustomLogo = typeof logo === "string" && logo.length > 0;
|
|
3537
|
+
return /* @__PURE__ */ jsx(
|
|
3538
|
+
"div",
|
|
3539
|
+
{
|
|
3540
|
+
className: cn(
|
|
3541
|
+
"flex flex-col border-b border-border bg-background",
|
|
3542
|
+
className
|
|
3543
|
+
),
|
|
3544
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2", children: [
|
|
3545
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 shrink-0", children: [
|
|
3546
|
+
showDefaultLogo && /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "h-6 w-auto" }),
|
|
3547
|
+
showCustomLogo && /* @__PURE__ */ jsx(
|
|
3548
|
+
"img",
|
|
3549
|
+
{
|
|
3550
|
+
src: logo,
|
|
3551
|
+
alt: displayName,
|
|
3552
|
+
className: "size-6 rounded-md object-contain"
|
|
3553
|
+
}
|
|
3554
|
+
),
|
|
3555
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3556
|
+
/* @__PURE__ */ jsx("div", { className: "font-semibold text-foreground text-sm mb-0.5", children: displayName }),
|
|
3557
|
+
threadPicker && /* @__PURE__ */ jsx("div", { className: "", children: threadPicker })
|
|
3558
|
+
] })
|
|
3559
|
+
] }),
|
|
3560
|
+
onClose && /* @__PURE__ */ jsx(
|
|
3561
|
+
"button",
|
|
3562
|
+
{
|
|
3563
|
+
type: "button",
|
|
3564
|
+
onClick: onClose,
|
|
3565
|
+
className: "rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
3566
|
+
"aria-label": "Close chat",
|
|
3567
|
+
children: /* @__PURE__ */ jsx(CloseIcon, { className: "h-5 w-5" })
|
|
3568
|
+
}
|
|
3569
|
+
)
|
|
3570
|
+
] })
|
|
3571
|
+
}
|
|
3572
|
+
);
|
|
3573
|
+
}
|
|
3574
|
+
function Suggestions({
|
|
3575
|
+
suggestions,
|
|
3576
|
+
onSuggestionClick,
|
|
3577
|
+
className
|
|
3578
|
+
}) {
|
|
3579
|
+
if (!suggestions.length) return null;
|
|
3580
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex flex-wrap gap-2 px-4 py-2", className), children: suggestions.map((suggestion, index) => /* @__PURE__ */ jsx(
|
|
3581
|
+
"button",
|
|
3582
|
+
{
|
|
3583
|
+
type: "button",
|
|
3584
|
+
onClick: () => onSuggestionClick?.(suggestion),
|
|
3585
|
+
className: "inline-flex items-center rounded-full border bg-background px-3 py-1.5 text-sm transition-colors hover:bg-muted",
|
|
3586
|
+
children: suggestion
|
|
3587
|
+
},
|
|
3588
|
+
index
|
|
3589
|
+
)) });
|
|
3590
|
+
}
|
|
3591
|
+
function DefaultMessage({
|
|
3592
|
+
message,
|
|
3593
|
+
userAvatar,
|
|
3594
|
+
assistantAvatar,
|
|
3595
|
+
showUserAvatar = false,
|
|
3596
|
+
userMessageClassName,
|
|
3597
|
+
assistantMessageClassName,
|
|
3598
|
+
size = "sm",
|
|
3599
|
+
isLastMessage = false,
|
|
3600
|
+
isLoading = false,
|
|
3601
|
+
registeredTools,
|
|
3602
|
+
toolRenderers,
|
|
3603
|
+
onApproveToolExecution,
|
|
3604
|
+
onRejectToolExecution,
|
|
3605
|
+
showFollowUps = true,
|
|
3606
|
+
onFollowUpClick,
|
|
3607
|
+
followUpClassName,
|
|
3608
|
+
followUpButtonClassName
|
|
3609
|
+
}) {
|
|
3610
|
+
const isUser = message.role === "user";
|
|
3611
|
+
const isStreaming = isLastMessage && isLoading;
|
|
3612
|
+
const { cleanContent, followUps } = React8.useMemo(() => {
|
|
3613
|
+
if (isUser || !message.content) {
|
|
3614
|
+
return { cleanContent: message.content, followUps: [] };
|
|
3615
|
+
}
|
|
3616
|
+
return parseFollowUps(message.content);
|
|
3617
|
+
}, [message.content, isUser]);
|
|
3618
|
+
const shouldShowFollowUps = showFollowUps && !isUser && isLastMessage && !isLoading && followUps.length > 0 && onFollowUpClick;
|
|
3619
|
+
if (isUser) {
|
|
3620
|
+
const hasAttachments = message.attachments && message.attachments.length > 0;
|
|
3621
|
+
return /* @__PURE__ */ jsxs(
|
|
3622
|
+
Message,
|
|
3623
|
+
{
|
|
3624
|
+
className: cn(
|
|
3625
|
+
"flex gap-2",
|
|
3626
|
+
showUserAvatar ? "justify-end" : "justify-end"
|
|
3627
|
+
),
|
|
3628
|
+
children: [
|
|
3629
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end max-w-[80%]", children: [
|
|
3630
|
+
message.content && /* @__PURE__ */ jsx(
|
|
3631
|
+
MessageContent,
|
|
3632
|
+
{
|
|
3633
|
+
className: cn(
|
|
3634
|
+
"rounded-lg px-4 py-2 bg-primary text-primary-foreground",
|
|
3635
|
+
userMessageClassName
|
|
3636
|
+
),
|
|
3637
|
+
size,
|
|
3638
|
+
children: message.content
|
|
3639
|
+
}
|
|
3640
|
+
),
|
|
3641
|
+
hasAttachments && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2 justify-end", children: message.attachments.map((attachment, index) => /* @__PURE__ */ jsx(AttachmentPreview, { attachment }, index)) })
|
|
3642
|
+
] }),
|
|
3643
|
+
showUserAvatar && /* @__PURE__ */ jsx(
|
|
3644
|
+
MessageAvatar,
|
|
3645
|
+
{
|
|
3646
|
+
src: userAvatar.src || "",
|
|
3647
|
+
alt: "User",
|
|
3648
|
+
fallback: userAvatar.fallback
|
|
3649
|
+
}
|
|
3650
|
+
)
|
|
3651
|
+
]
|
|
3652
|
+
}
|
|
3653
|
+
);
|
|
3654
|
+
}
|
|
3655
|
+
const pendingApprovalTools = message.toolExecutions?.filter(
|
|
3656
|
+
(exec) => exec.approvalStatus === "required"
|
|
3657
|
+
);
|
|
3658
|
+
const completedTools = message.toolExecutions?.filter(
|
|
3659
|
+
(exec) => exec.approvalStatus !== "required"
|
|
3660
|
+
);
|
|
3661
|
+
const hasCustomRender = (toolName) => {
|
|
3662
|
+
if (toolRenderers?.[toolName]) return true;
|
|
3663
|
+
const toolDef = registeredTools?.find((t) => t.name === toolName);
|
|
3664
|
+
if (toolDef?.render) return true;
|
|
3665
|
+
return false;
|
|
3666
|
+
};
|
|
3667
|
+
const toolsWithCustomRender = completedTools?.filter(
|
|
3668
|
+
(exec) => hasCustomRender(exec.name)
|
|
3669
|
+
);
|
|
3670
|
+
const toolsWithoutCustomRender = completedTools?.filter(
|
|
3671
|
+
(exec) => !hasCustomRender(exec.name)
|
|
3672
|
+
);
|
|
3673
|
+
const toolSteps = toolsWithoutCustomRender?.map((exec) => ({
|
|
3674
|
+
id: exec.id,
|
|
3675
|
+
name: exec.name,
|
|
3676
|
+
args: exec.args,
|
|
3677
|
+
status: exec.status,
|
|
3678
|
+
result: exec.result,
|
|
3679
|
+
error: exec.error
|
|
3680
|
+
}));
|
|
3681
|
+
return /* @__PURE__ */ jsxs(Message, { className: "flex gap-2", children: [
|
|
3682
|
+
/* @__PURE__ */ jsx(
|
|
3683
|
+
MessageAvatar,
|
|
3684
|
+
{
|
|
3685
|
+
src: assistantAvatar.src || "",
|
|
3686
|
+
alt: "Assistant",
|
|
3687
|
+
fallback: assistantAvatar.fallback,
|
|
3688
|
+
fallbackIcon: !assistantAvatar.src ? /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "size-5" }) : void 0,
|
|
3689
|
+
className: "bg-background"
|
|
3690
|
+
}
|
|
3691
|
+
),
|
|
3692
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 max-w-[80%]", children: [
|
|
3693
|
+
message.thinking && /* @__PURE__ */ jsx(
|
|
3694
|
+
SimpleReasoning,
|
|
3695
|
+
{
|
|
3696
|
+
content: message.thinking,
|
|
3697
|
+
isStreaming,
|
|
3698
|
+
className: "mb-2"
|
|
3699
|
+
}
|
|
3700
|
+
),
|
|
3701
|
+
cleanContent?.trim() && /* @__PURE__ */ jsx(
|
|
3702
|
+
MessageContent,
|
|
3703
|
+
{
|
|
3704
|
+
className: cn(
|
|
3705
|
+
"rounded-lg px-4 py-2 bg-muted",
|
|
3706
|
+
assistantMessageClassName
|
|
3707
|
+
),
|
|
3708
|
+
markdown: true,
|
|
3709
|
+
size,
|
|
3710
|
+
children: cleanContent
|
|
3711
|
+
}
|
|
3712
|
+
),
|
|
3713
|
+
toolsWithCustomRender && toolsWithCustomRender.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-2 space-y-2", children: toolsWithCustomRender.map((exec) => {
|
|
3714
|
+
const Renderer = toolRenderers?.[exec.name];
|
|
3715
|
+
if (Renderer) {
|
|
3716
|
+
return /* @__PURE__ */ jsx(
|
|
3717
|
+
Renderer,
|
|
3146
3718
|
{
|
|
3147
3719
|
execution: {
|
|
3148
3720
|
id: exec.id,
|
|
@@ -3213,125 +3785,465 @@ function DefaultMessage({
|
|
|
3213
3785
|
const output = toolDef.render(renderProps);
|
|
3214
3786
|
return /* @__PURE__ */ jsx(React8.Fragment, { children: output }, tool.id);
|
|
3215
3787
|
}
|
|
3216
|
-
return /* @__PURE__ */ jsx(
|
|
3217
|
-
PermissionConfirmation,
|
|
3788
|
+
return /* @__PURE__ */ jsx(
|
|
3789
|
+
PermissionConfirmation,
|
|
3790
|
+
{
|
|
3791
|
+
state: "pending",
|
|
3792
|
+
toolName: tool.name,
|
|
3793
|
+
message: tool.approvalMessage || `This tool wants to execute. Do you approve?`,
|
|
3794
|
+
onApprove: (permissionLevel) => onApproveToolExecution?.(
|
|
3795
|
+
tool.id,
|
|
3796
|
+
void 0,
|
|
3797
|
+
permissionLevel
|
|
3798
|
+
),
|
|
3799
|
+
onReject: (permissionLevel) => onRejectToolExecution?.(tool.id, void 0, permissionLevel)
|
|
3800
|
+
},
|
|
3801
|
+
tool.id
|
|
3802
|
+
);
|
|
3803
|
+
}) }),
|
|
3804
|
+
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: message.attachments.map((attachment, index) => /* @__PURE__ */ jsx(AttachmentPreview, { attachment }, index)) }),
|
|
3805
|
+
shouldShowFollowUps && /* @__PURE__ */ jsx(
|
|
3806
|
+
FollowUpQuestions,
|
|
3807
|
+
{
|
|
3808
|
+
questions: followUps,
|
|
3809
|
+
onSelect: onFollowUpClick,
|
|
3810
|
+
className: followUpClassName,
|
|
3811
|
+
buttonClassName: followUpButtonClassName
|
|
3812
|
+
}
|
|
3813
|
+
)
|
|
3814
|
+
] })
|
|
3815
|
+
] });
|
|
3816
|
+
}
|
|
3817
|
+
function AttachmentPreview({ attachment }) {
|
|
3818
|
+
const [expanded, setExpanded] = React8.useState(false);
|
|
3819
|
+
if (attachment.type !== "image") {
|
|
3820
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-lg border bg-muted/50 px-3 py-2 text-sm", children: [
|
|
3821
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: attachment.type }),
|
|
3822
|
+
/* @__PURE__ */ jsx("span", { children: attachment.filename || "Attachment" })
|
|
3823
|
+
] });
|
|
3824
|
+
}
|
|
3825
|
+
let src;
|
|
3826
|
+
if (attachment.url) {
|
|
3827
|
+
src = attachment.url;
|
|
3828
|
+
} else if (attachment.data) {
|
|
3829
|
+
src = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType};base64,${attachment.data}`;
|
|
3830
|
+
} else {
|
|
3831
|
+
return null;
|
|
3832
|
+
}
|
|
3833
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3834
|
+
/* @__PURE__ */ jsx(
|
|
3835
|
+
"button",
|
|
3836
|
+
{
|
|
3837
|
+
type: "button",
|
|
3838
|
+
onClick: () => setExpanded(true),
|
|
3839
|
+
className: "relative rounded-lg overflow-hidden border bg-muted/50 hover:opacity-90 transition-opacity",
|
|
3840
|
+
children: /* @__PURE__ */ jsx(
|
|
3841
|
+
"img",
|
|
3842
|
+
{
|
|
3843
|
+
src,
|
|
3844
|
+
alt: attachment.filename || "Image",
|
|
3845
|
+
className: "max-w-[200px] max-h-[150px] object-cover"
|
|
3846
|
+
}
|
|
3847
|
+
)
|
|
3848
|
+
}
|
|
3849
|
+
),
|
|
3850
|
+
expanded && /* @__PURE__ */ jsx(
|
|
3851
|
+
"div",
|
|
3852
|
+
{
|
|
3853
|
+
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/80",
|
|
3854
|
+
onClick: () => setExpanded(false),
|
|
3855
|
+
children: /* @__PURE__ */ jsxs("div", { className: "relative max-w-[90vw] max-h-[90vh]", children: [
|
|
3856
|
+
/* @__PURE__ */ jsx(
|
|
3857
|
+
"img",
|
|
3858
|
+
{
|
|
3859
|
+
src,
|
|
3860
|
+
alt: attachment.filename || "Image (expanded)",
|
|
3861
|
+
className: "max-w-full max-h-full object-contain rounded-lg"
|
|
3862
|
+
}
|
|
3863
|
+
),
|
|
3864
|
+
/* @__PURE__ */ jsx(
|
|
3865
|
+
"button",
|
|
3866
|
+
{
|
|
3867
|
+
type: "button",
|
|
3868
|
+
className: "absolute top-2 right-2 bg-white/90 rounded-full p-2 hover:bg-white transition-colors",
|
|
3869
|
+
onClick: (e) => {
|
|
3870
|
+
e.stopPropagation();
|
|
3871
|
+
setExpanded(false);
|
|
3872
|
+
},
|
|
3873
|
+
children: /* @__PURE__ */ jsx(
|
|
3874
|
+
"svg",
|
|
3875
|
+
{
|
|
3876
|
+
className: "w-4 h-4",
|
|
3877
|
+
fill: "none",
|
|
3878
|
+
viewBox: "0 0 24 24",
|
|
3879
|
+
stroke: "currentColor",
|
|
3880
|
+
strokeWidth: 2,
|
|
3881
|
+
children: /* @__PURE__ */ jsx(
|
|
3882
|
+
"path",
|
|
3883
|
+
{
|
|
3884
|
+
strokeLinecap: "round",
|
|
3885
|
+
strokeLinejoin: "round",
|
|
3886
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
3887
|
+
}
|
|
3888
|
+
)
|
|
3889
|
+
}
|
|
3890
|
+
)
|
|
3891
|
+
}
|
|
3892
|
+
)
|
|
3893
|
+
] })
|
|
3894
|
+
}
|
|
3895
|
+
)
|
|
3896
|
+
] });
|
|
3897
|
+
}
|
|
3898
|
+
var DEFAULT_MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
3899
|
+
var DEFAULT_ALLOWED_TYPES = ["image/*", "application/pdf"];
|
|
3900
|
+
var DEFAULT_TITLE = "How can I help you today?";
|
|
3901
|
+
var DEFAULT_SUBTITLE = "Ask anything and get it done.";
|
|
3902
|
+
var DEFAULT_SUGGESTIONS_LABEL = "Try AI Copilot";
|
|
3903
|
+
var DEFAULT_RECENT_CHATS_LABEL = "Recent chats";
|
|
3904
|
+
var DEFAULT_MAX_RECENT_CHATS = 3;
|
|
3905
|
+
var DEFAULT_VIEW_MORE_LABEL = "View more..";
|
|
3906
|
+
function getAttachmentType(mimeType) {
|
|
3907
|
+
if (mimeType.startsWith("image/")) return "image";
|
|
3908
|
+
if (mimeType.startsWith("audio/")) return "audio";
|
|
3909
|
+
if (mimeType.startsWith("video/")) return "video";
|
|
3910
|
+
return "file";
|
|
3911
|
+
}
|
|
3912
|
+
function fileToBase64(file) {
|
|
3913
|
+
return new Promise((resolve, reject) => {
|
|
3914
|
+
const reader = new FileReader();
|
|
3915
|
+
reader.onload = () => {
|
|
3916
|
+
if (typeof reader.result === "string") {
|
|
3917
|
+
resolve(reader.result);
|
|
3918
|
+
} else {
|
|
3919
|
+
reject(new Error("Failed to read file"));
|
|
3920
|
+
}
|
|
3921
|
+
};
|
|
3922
|
+
reader.onerror = () => reject(new Error("Failed to read file"));
|
|
3923
|
+
reader.readAsDataURL(file);
|
|
3924
|
+
});
|
|
3925
|
+
}
|
|
3926
|
+
function generateAttachmentId() {
|
|
3927
|
+
return `att_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
3928
|
+
}
|
|
3929
|
+
function ChatWelcome({
|
|
3930
|
+
config,
|
|
3931
|
+
suggestions = [],
|
|
3932
|
+
recentThreads = [],
|
|
3933
|
+
onSendMessage,
|
|
3934
|
+
onSelectThread,
|
|
3935
|
+
onDeleteThread,
|
|
3936
|
+
onViewMoreThreads,
|
|
3937
|
+
isLoading = false,
|
|
3938
|
+
onStop,
|
|
3939
|
+
placeholder = "Type a message...",
|
|
3940
|
+
attachmentsEnabled = true,
|
|
3941
|
+
attachmentsDisabledTooltip = "Attachments not supported by this model",
|
|
3942
|
+
maxFileSize = DEFAULT_MAX_FILE_SIZE,
|
|
3943
|
+
allowedFileTypes = DEFAULT_ALLOWED_TYPES,
|
|
3944
|
+
processAttachment: processAttachmentProp,
|
|
3945
|
+
classNames = {}
|
|
3946
|
+
}) {
|
|
3947
|
+
const [input, setInput] = useState("");
|
|
3948
|
+
const [pendingAttachments, setPendingAttachments] = useState([]);
|
|
3949
|
+
const fileInputRef = useRef(null);
|
|
3950
|
+
const fileInputId = useId();
|
|
3951
|
+
const title = config?.title ?? DEFAULT_TITLE;
|
|
3952
|
+
const subtitle = config?.subtitle ?? DEFAULT_SUBTITLE;
|
|
3953
|
+
const logo = config?.logo;
|
|
3954
|
+
const suggestionsLabel = config?.suggestionsLabel ?? DEFAULT_SUGGESTIONS_LABEL;
|
|
3955
|
+
const showRecentChats = config?.showRecentChats ?? true;
|
|
3956
|
+
config?.recentChatsLabel ?? DEFAULT_RECENT_CHATS_LABEL;
|
|
3957
|
+
const maxRecentChats = config?.maxRecentChats ?? DEFAULT_MAX_RECENT_CHATS;
|
|
3958
|
+
config?.viewMoreLabel ?? DEFAULT_VIEW_MORE_LABEL;
|
|
3959
|
+
const isFileTypeAllowed = useCallback(
|
|
3960
|
+
(file) => {
|
|
3961
|
+
for (const type of allowedFileTypes) {
|
|
3962
|
+
if (type.endsWith("/*")) {
|
|
3963
|
+
const category = type.slice(0, -2);
|
|
3964
|
+
if (file.type.startsWith(category + "/")) return true;
|
|
3965
|
+
} else if (file.type === type) {
|
|
3966
|
+
return true;
|
|
3967
|
+
}
|
|
3968
|
+
}
|
|
3969
|
+
return false;
|
|
3970
|
+
},
|
|
3971
|
+
[allowedFileTypes]
|
|
3972
|
+
);
|
|
3973
|
+
const handleFileSelect = useCallback(
|
|
3974
|
+
async (files) => {
|
|
3975
|
+
if (!files || !attachmentsEnabled) return;
|
|
3976
|
+
for (const file of Array.from(files)) {
|
|
3977
|
+
if (file.size > maxFileSize) {
|
|
3978
|
+
const sizeMB = (maxFileSize / (1024 * 1024)).toFixed(0);
|
|
3979
|
+
console.warn(`File ${file.name} exceeds ${sizeMB}MB limit`);
|
|
3980
|
+
continue;
|
|
3981
|
+
}
|
|
3982
|
+
if (!isFileTypeAllowed(file)) {
|
|
3983
|
+
console.warn(`File type ${file.type} is not allowed`);
|
|
3984
|
+
continue;
|
|
3985
|
+
}
|
|
3986
|
+
const id = generateAttachmentId();
|
|
3987
|
+
const previewUrl = URL.createObjectURL(file);
|
|
3988
|
+
setPendingAttachments((prev) => [
|
|
3989
|
+
...prev,
|
|
3990
|
+
{
|
|
3991
|
+
id,
|
|
3992
|
+
file,
|
|
3993
|
+
previewUrl,
|
|
3994
|
+
attachment: {
|
|
3995
|
+
type: getAttachmentType(file.type),
|
|
3996
|
+
data: "",
|
|
3997
|
+
mimeType: file.type,
|
|
3998
|
+
filename: file.name
|
|
3999
|
+
},
|
|
4000
|
+
status: "processing"
|
|
4001
|
+
}
|
|
4002
|
+
]);
|
|
4003
|
+
try {
|
|
4004
|
+
let attachment;
|
|
4005
|
+
if (processAttachmentProp) {
|
|
4006
|
+
attachment = await processAttachmentProp(file);
|
|
4007
|
+
} else {
|
|
4008
|
+
const data = await fileToBase64(file);
|
|
4009
|
+
attachment = {
|
|
4010
|
+
type: getAttachmentType(file.type),
|
|
4011
|
+
data,
|
|
4012
|
+
mimeType: file.type,
|
|
4013
|
+
filename: file.name
|
|
4014
|
+
};
|
|
4015
|
+
}
|
|
4016
|
+
setPendingAttachments(
|
|
4017
|
+
(prev) => prev.map(
|
|
4018
|
+
(att) => att.id === id ? { ...att, status: "ready", attachment } : att
|
|
4019
|
+
)
|
|
4020
|
+
);
|
|
4021
|
+
} catch (error) {
|
|
4022
|
+
setPendingAttachments(
|
|
4023
|
+
(prev) => prev.map(
|
|
4024
|
+
(att) => att.id === id ? {
|
|
4025
|
+
...att,
|
|
4026
|
+
status: "error",
|
|
4027
|
+
error: "Failed to process file"
|
|
4028
|
+
} : att
|
|
4029
|
+
)
|
|
4030
|
+
);
|
|
4031
|
+
}
|
|
4032
|
+
}
|
|
4033
|
+
},
|
|
4034
|
+
[attachmentsEnabled, maxFileSize, isFileTypeAllowed, processAttachmentProp]
|
|
4035
|
+
);
|
|
4036
|
+
const handleInputChange = useCallback(
|
|
4037
|
+
(e) => {
|
|
4038
|
+
handleFileSelect(e.target.files);
|
|
4039
|
+
if (fileInputRef.current) {
|
|
4040
|
+
fileInputRef.current.value = "";
|
|
4041
|
+
}
|
|
4042
|
+
},
|
|
4043
|
+
[handleFileSelect]
|
|
4044
|
+
);
|
|
4045
|
+
const removePendingAttachment = useCallback((id) => {
|
|
4046
|
+
setPendingAttachments((prev) => {
|
|
4047
|
+
const att = prev.find((a) => a.id === id);
|
|
4048
|
+
if (att) {
|
|
4049
|
+
URL.revokeObjectURL(att.previewUrl);
|
|
4050
|
+
}
|
|
4051
|
+
return prev.filter((a) => a.id !== id);
|
|
4052
|
+
});
|
|
4053
|
+
}, []);
|
|
4054
|
+
const handleSubmit = useCallback(() => {
|
|
4055
|
+
const hasContent = input.trim();
|
|
4056
|
+
const hasAttachments = pendingAttachments.some(
|
|
4057
|
+
(att) => att.status === "ready"
|
|
4058
|
+
);
|
|
4059
|
+
if (!hasContent && !hasAttachments || isLoading) return;
|
|
4060
|
+
const attachments = pendingAttachments.filter((att) => att.status === "ready").map((att) => att.attachment);
|
|
4061
|
+
onSendMessage(input, attachments.length > 0 ? attachments : void 0);
|
|
4062
|
+
pendingAttachments.forEach((att) => URL.revokeObjectURL(att.previewUrl));
|
|
4063
|
+
setPendingAttachments([]);
|
|
4064
|
+
setInput("");
|
|
4065
|
+
}, [input, isLoading, onSendMessage, pendingAttachments]);
|
|
4066
|
+
const handleSuggestionClick = useCallback(
|
|
4067
|
+
(suggestion) => {
|
|
4068
|
+
onSendMessage(suggestion);
|
|
4069
|
+
},
|
|
4070
|
+
[onSendMessage]
|
|
4071
|
+
);
|
|
4072
|
+
const acceptString = allowedFileTypes.join(",");
|
|
4073
|
+
showRecentChats ? recentThreads.slice(0, maxRecentChats) : [];
|
|
4074
|
+
recentThreads.length > maxRecentChats;
|
|
4075
|
+
return /* @__PURE__ */ jsxs(
|
|
4076
|
+
"div",
|
|
4077
|
+
{
|
|
4078
|
+
className: cn(
|
|
4079
|
+
"flex flex-1 flex-col items-center justify-center px-4 py-8 overflow-auto",
|
|
4080
|
+
classNames.root
|
|
4081
|
+
),
|
|
4082
|
+
children: [
|
|
4083
|
+
/* @__PURE__ */ jsxs(
|
|
4084
|
+
"div",
|
|
3218
4085
|
{
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
onApprove: (permissionLevel) => onApproveToolExecution?.(
|
|
3223
|
-
tool.id,
|
|
3224
|
-
void 0,
|
|
3225
|
-
permissionLevel
|
|
4086
|
+
className: cn(
|
|
4087
|
+
"flex flex-col items-center text-center mb-8",
|
|
4088
|
+
classNames.hero
|
|
3226
4089
|
),
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
buttonClassName: followUpButtonClassName
|
|
3240
|
-
}
|
|
3241
|
-
)
|
|
3242
|
-
] })
|
|
3243
|
-
] });
|
|
3244
|
-
}
|
|
3245
|
-
function AttachmentPreview({ attachment }) {
|
|
3246
|
-
const [expanded, setExpanded] = React8.useState(false);
|
|
3247
|
-
if (attachment.type !== "image") {
|
|
3248
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-lg border bg-muted/50 px-3 py-2 text-sm", children: [
|
|
3249
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: attachment.type }),
|
|
3250
|
-
/* @__PURE__ */ jsx("span", { children: attachment.filename || "Attachment" })
|
|
3251
|
-
] });
|
|
3252
|
-
}
|
|
3253
|
-
let src;
|
|
3254
|
-
if (attachment.url) {
|
|
3255
|
-
src = attachment.url;
|
|
3256
|
-
} else if (attachment.data) {
|
|
3257
|
-
src = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType};base64,${attachment.data}`;
|
|
3258
|
-
} else {
|
|
3259
|
-
return null;
|
|
3260
|
-
}
|
|
3261
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3262
|
-
/* @__PURE__ */ jsx(
|
|
3263
|
-
"button",
|
|
3264
|
-
{
|
|
3265
|
-
type: "button",
|
|
3266
|
-
onClick: () => setExpanded(true),
|
|
3267
|
-
className: "relative rounded-lg overflow-hidden border bg-muted/50 hover:opacity-90 transition-opacity",
|
|
3268
|
-
children: /* @__PURE__ */ jsx(
|
|
3269
|
-
"img",
|
|
3270
|
-
{
|
|
3271
|
-
src,
|
|
3272
|
-
alt: attachment.filename || "Image",
|
|
3273
|
-
className: "max-w-[200px] max-h-[150px] object-cover"
|
|
4090
|
+
children: [
|
|
4091
|
+
logo ? /* @__PURE__ */ jsx(
|
|
4092
|
+
"img",
|
|
4093
|
+
{
|
|
4094
|
+
src: logo,
|
|
4095
|
+
alt: "Logo",
|
|
4096
|
+
className: "size-12 rounded-lg object-contain mb-4"
|
|
4097
|
+
}
|
|
4098
|
+
) : /* @__PURE__ */ jsx("div", { className: "mb-4", children: /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "h-12 w-auto" }) }),
|
|
4099
|
+
/* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold text-foreground mb-2", children: title }),
|
|
4100
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: subtitle })
|
|
4101
|
+
]
|
|
3274
4102
|
}
|
|
3275
|
-
)
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
"
|
|
3286
|
-
|
|
3287
|
-
src,
|
|
3288
|
-
alt: attachment.filename || "Image (expanded)",
|
|
3289
|
-
className: "max-w-full max-h-full object-contain rounded-lg"
|
|
3290
|
-
}
|
|
3291
|
-
),
|
|
3292
|
-
/* @__PURE__ */ jsx(
|
|
3293
|
-
"button",
|
|
3294
|
-
{
|
|
3295
|
-
type: "button",
|
|
3296
|
-
className: "absolute top-2 right-2 bg-white/90 rounded-full p-2 hover:bg-white transition-colors",
|
|
3297
|
-
onClick: (e) => {
|
|
3298
|
-
e.stopPropagation();
|
|
3299
|
-
setExpanded(false);
|
|
3300
|
-
},
|
|
3301
|
-
children: /* @__PURE__ */ jsx(
|
|
4103
|
+
),
|
|
4104
|
+
/* @__PURE__ */ jsxs("div", { className: cn("w-full max-w-lg mb-6", classNames.input), children: [
|
|
4105
|
+
pendingAttachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 p-2 mb-2 bg-muted/30 rounded-lg", children: pendingAttachments.map((att) => /* @__PURE__ */ jsxs("div", { className: "relative group", children: [
|
|
4106
|
+
att.attachment.type === "image" ? /* @__PURE__ */ jsx(
|
|
4107
|
+
"img",
|
|
4108
|
+
{
|
|
4109
|
+
src: att.previewUrl,
|
|
4110
|
+
alt: att.file.name,
|
|
4111
|
+
className: "w-16 h-16 object-cover rounded-lg border"
|
|
4112
|
+
}
|
|
4113
|
+
) : /* @__PURE__ */ jsxs("div", { className: "w-16 h-16 bg-muted rounded-lg border flex flex-col items-center justify-center p-1", children: [
|
|
4114
|
+
/* @__PURE__ */ jsx(
|
|
3302
4115
|
"svg",
|
|
3303
4116
|
{
|
|
3304
|
-
className: "w-
|
|
4117
|
+
className: "w-6 h-6 text-muted-foreground",
|
|
3305
4118
|
fill: "none",
|
|
3306
4119
|
viewBox: "0 0 24 24",
|
|
3307
4120
|
stroke: "currentColor",
|
|
3308
|
-
strokeWidth: 2,
|
|
3309
4121
|
children: /* @__PURE__ */ jsx(
|
|
3310
4122
|
"path",
|
|
3311
4123
|
{
|
|
3312
4124
|
strokeLinecap: "round",
|
|
3313
4125
|
strokeLinejoin: "round",
|
|
3314
|
-
|
|
4126
|
+
strokeWidth: 1.5,
|
|
4127
|
+
d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
3315
4128
|
}
|
|
3316
4129
|
)
|
|
3317
4130
|
}
|
|
3318
|
-
)
|
|
4131
|
+
),
|
|
4132
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground truncate w-full text-center mt-1", children: att.file.name.length > 10 ? att.file.name.slice(0, 8) + "..." : att.file.name })
|
|
4133
|
+
] }),
|
|
4134
|
+
att.status === "processing" && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-background/80 rounded-lg flex items-center justify-center", children: /* @__PURE__ */ jsx(Loader, { variant: "dots", size: "sm" }) }),
|
|
4135
|
+
att.status === "error" && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-destructive/20 rounded-lg flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "text-destructive text-xs", children: "Error" }) }),
|
|
4136
|
+
/* @__PURE__ */ jsx(
|
|
4137
|
+
"button",
|
|
4138
|
+
{
|
|
4139
|
+
onClick: () => removePendingAttachment(att.id),
|
|
4140
|
+
className: "absolute -top-1.5 -right-1.5 bg-destructive text-destructive-foreground rounded-full p-0.5 opacity-0 group-hover:opacity-100 transition-opacity",
|
|
4141
|
+
type: "button",
|
|
4142
|
+
children: /* @__PURE__ */ jsx(XIcon2, { className: "w-3 h-3" })
|
|
4143
|
+
}
|
|
4144
|
+
)
|
|
4145
|
+
] }, att.id)) }),
|
|
4146
|
+
/* @__PURE__ */ jsxs(
|
|
4147
|
+
PromptInput,
|
|
4148
|
+
{
|
|
4149
|
+
value: input,
|
|
4150
|
+
onValueChange: setInput,
|
|
4151
|
+
isLoading,
|
|
4152
|
+
onSubmit: handleSubmit,
|
|
4153
|
+
children: [
|
|
4154
|
+
/* @__PURE__ */ jsx(PromptInputTextarea, { placeholder }),
|
|
4155
|
+
/* @__PURE__ */ jsxs(PromptInputActions, { className: "flex justify-between", children: [
|
|
4156
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
4157
|
+
PromptInputAction,
|
|
4158
|
+
{
|
|
4159
|
+
tooltip: attachmentsEnabled ? "Attach files" : attachmentsDisabledTooltip,
|
|
4160
|
+
children: /* @__PURE__ */ jsxs(
|
|
4161
|
+
"label",
|
|
4162
|
+
{
|
|
4163
|
+
htmlFor: fileInputId,
|
|
4164
|
+
className: cn(
|
|
4165
|
+
"flex h-8 w-8 items-center justify-center rounded-2xl",
|
|
4166
|
+
attachmentsEnabled ? "hover:bg-secondary-foreground/10 cursor-pointer" : "opacity-50 cursor-not-allowed"
|
|
4167
|
+
),
|
|
4168
|
+
children: [
|
|
4169
|
+
/* @__PURE__ */ jsx(
|
|
4170
|
+
"input",
|
|
4171
|
+
{
|
|
4172
|
+
ref: fileInputRef,
|
|
4173
|
+
type: "file",
|
|
4174
|
+
multiple: true,
|
|
4175
|
+
accept: acceptString,
|
|
4176
|
+
onChange: handleInputChange,
|
|
4177
|
+
className: "hidden",
|
|
4178
|
+
id: fileInputId,
|
|
4179
|
+
disabled: !attachmentsEnabled
|
|
4180
|
+
}
|
|
4181
|
+
),
|
|
4182
|
+
/* @__PURE__ */ jsx(PlusIcon, { className: "text-primary size-5" })
|
|
4183
|
+
]
|
|
4184
|
+
}
|
|
4185
|
+
)
|
|
4186
|
+
}
|
|
4187
|
+
) }),
|
|
4188
|
+
/* @__PURE__ */ jsx(PromptInputAction, { tooltip: isLoading ? "Stop" : "Send", children: isLoading ? /* @__PURE__ */ jsx(
|
|
4189
|
+
Button,
|
|
4190
|
+
{
|
|
4191
|
+
size: "sm",
|
|
4192
|
+
variant: "destructive",
|
|
4193
|
+
className: "rounded-full size-9",
|
|
4194
|
+
onClick: onStop,
|
|
4195
|
+
children: /* @__PURE__ */ jsx(StopIcon, { className: "h-4 w-4" })
|
|
4196
|
+
}
|
|
4197
|
+
) : /* @__PURE__ */ jsx(
|
|
4198
|
+
Button,
|
|
4199
|
+
{
|
|
4200
|
+
size: "sm",
|
|
4201
|
+
className: "rounded-full size-9",
|
|
4202
|
+
onClick: handleSubmit,
|
|
4203
|
+
disabled: !input.trim() && !pendingAttachments.some((att) => att.status === "ready"),
|
|
4204
|
+
children: /* @__PURE__ */ jsx(ArrowUpIcon, { className: "h-4 w-4" })
|
|
4205
|
+
}
|
|
4206
|
+
) })
|
|
4207
|
+
] })
|
|
4208
|
+
]
|
|
3319
4209
|
}
|
|
3320
4210
|
)
|
|
3321
|
-
] })
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
4211
|
+
] }),
|
|
4212
|
+
suggestions.length > 0 && /* @__PURE__ */ jsxs(
|
|
4213
|
+
"div",
|
|
4214
|
+
{
|
|
4215
|
+
className: cn("w-full max-w-lg mb-6 px-3", classNames.suggestions),
|
|
4216
|
+
children: [
|
|
4217
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground mb-2", children: suggestionsLabel }),
|
|
4218
|
+
/* @__PURE__ */ jsx("div", { className: "", children: suggestions.map((suggestion, index) => /* @__PURE__ */ jsxs(
|
|
4219
|
+
"button",
|
|
4220
|
+
{
|
|
4221
|
+
type: "button",
|
|
4222
|
+
onClick: () => handleSuggestionClick(suggestion),
|
|
4223
|
+
className: "group w-full cursor-pointer font-medium text-left py-2 text-sm hover:text-foreground text-foreground/70 transition-colors flex items-center gap-2",
|
|
4224
|
+
children: [
|
|
4225
|
+
/* @__PURE__ */ jsx("span", { children: suggestion }),
|
|
4226
|
+
/* @__PURE__ */ jsx(ArrowUpRightIcon, { className: "size-4 opacity-0 translate-y-1 group-hover:opacity-[0.6] group-hover:translate-y-0 transition-all duration-200" })
|
|
4227
|
+
]
|
|
4228
|
+
},
|
|
4229
|
+
index
|
|
4230
|
+
)) })
|
|
4231
|
+
]
|
|
4232
|
+
}
|
|
4233
|
+
)
|
|
4234
|
+
]
|
|
4235
|
+
}
|
|
4236
|
+
);
|
|
3325
4237
|
}
|
|
3326
|
-
var
|
|
3327
|
-
var
|
|
3328
|
-
function
|
|
4238
|
+
var DEFAULT_MAX_FILE_SIZE2 = 5 * 1024 * 1024;
|
|
4239
|
+
var DEFAULT_ALLOWED_TYPES2 = ["image/*", "application/pdf"];
|
|
4240
|
+
function getAttachmentType2(mimeType) {
|
|
3329
4241
|
if (mimeType.startsWith("image/")) return "image";
|
|
3330
4242
|
if (mimeType.startsWith("audio/")) return "audio";
|
|
3331
4243
|
if (mimeType.startsWith("video/")) return "video";
|
|
3332
4244
|
return "file";
|
|
3333
4245
|
}
|
|
3334
|
-
function
|
|
4246
|
+
function fileToBase642(file) {
|
|
3335
4247
|
return new Promise((resolve, reject) => {
|
|
3336
4248
|
const reader = new FileReader();
|
|
3337
4249
|
reader.onload = () => {
|
|
@@ -3345,7 +4257,7 @@ function fileToBase64(file) {
|
|
|
3345
4257
|
reader.readAsDataURL(file);
|
|
3346
4258
|
});
|
|
3347
4259
|
}
|
|
3348
|
-
function
|
|
4260
|
+
function generateAttachmentId2() {
|
|
3349
4261
|
return `att_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
3350
4262
|
}
|
|
3351
4263
|
function Chat({
|
|
@@ -3360,6 +4272,11 @@ function Chat({
|
|
|
3360
4272
|
title,
|
|
3361
4273
|
// Header
|
|
3362
4274
|
showHeader = false,
|
|
4275
|
+
header,
|
|
4276
|
+
threadPicker,
|
|
4277
|
+
// Deprecated header props (backwards compat)
|
|
4278
|
+
logo,
|
|
4279
|
+
name,
|
|
3363
4280
|
onClose,
|
|
3364
4281
|
// Appearance
|
|
3365
4282
|
showPoweredBy = true,
|
|
@@ -3369,14 +4286,20 @@ function Chat({
|
|
|
3369
4286
|
loaderVariant = "typing",
|
|
3370
4287
|
fontSize = "sm",
|
|
3371
4288
|
// Attachments
|
|
3372
|
-
maxFileSize =
|
|
3373
|
-
allowedFileTypes =
|
|
4289
|
+
maxFileSize = DEFAULT_MAX_FILE_SIZE2,
|
|
4290
|
+
allowedFileTypes = DEFAULT_ALLOWED_TYPES2,
|
|
3374
4291
|
attachmentsEnabled = true,
|
|
3375
4292
|
attachmentsDisabledTooltip = "Attachments not supported by this model",
|
|
3376
4293
|
processAttachment: processAttachmentProp,
|
|
3377
4294
|
// Suggestions
|
|
3378
4295
|
suggestions = [],
|
|
3379
4296
|
onSuggestionClick,
|
|
4297
|
+
// Welcome Screen
|
|
4298
|
+
welcome,
|
|
4299
|
+
recentThreads = [],
|
|
4300
|
+
onSelectThread,
|
|
4301
|
+
onDeleteThread,
|
|
4302
|
+
onViewMoreThreads,
|
|
3380
4303
|
// Tool Executions
|
|
3381
4304
|
isProcessing = false,
|
|
3382
4305
|
registeredTools,
|
|
@@ -3427,7 +4350,7 @@ function Chat({
|
|
|
3427
4350
|
console.warn(`File type ${file.type} is not allowed`);
|
|
3428
4351
|
continue;
|
|
3429
4352
|
}
|
|
3430
|
-
const id =
|
|
4353
|
+
const id = generateAttachmentId2();
|
|
3431
4354
|
const previewUrl = URL.createObjectURL(file);
|
|
3432
4355
|
setPendingAttachments((prev) => [
|
|
3433
4356
|
...prev,
|
|
@@ -3436,7 +4359,7 @@ function Chat({
|
|
|
3436
4359
|
file,
|
|
3437
4360
|
previewUrl,
|
|
3438
4361
|
attachment: {
|
|
3439
|
-
type:
|
|
4362
|
+
type: getAttachmentType2(file.type),
|
|
3440
4363
|
data: "",
|
|
3441
4364
|
mimeType: file.type,
|
|
3442
4365
|
filename: file.name
|
|
@@ -3449,9 +4372,9 @@ function Chat({
|
|
|
3449
4372
|
if (processAttachmentProp) {
|
|
3450
4373
|
attachment = await processAttachmentProp(file);
|
|
3451
4374
|
} else {
|
|
3452
|
-
const data = await
|
|
4375
|
+
const data = await fileToBase642(file);
|
|
3453
4376
|
attachment = {
|
|
3454
|
-
type:
|
|
4377
|
+
type: getAttachmentType2(file.type),
|
|
3455
4378
|
data,
|
|
3456
4379
|
mimeType: file.type,
|
|
3457
4380
|
filename: file.name
|
|
@@ -3544,6 +4467,8 @@ function Chat({
|
|
|
3544
4467
|
[onSuggestionClick, onSendMessage]
|
|
3545
4468
|
);
|
|
3546
4469
|
const acceptString = allowedFileTypes.join(",");
|
|
4470
|
+
const showWelcome = messages.length === 0 && welcome !== false;
|
|
4471
|
+
const welcomeConfig = typeof welcome === "object" ? welcome : void 0;
|
|
3547
4472
|
return /* @__PURE__ */ jsxs(
|
|
3548
4473
|
"div",
|
|
3549
4474
|
{
|
|
@@ -3560,240 +4485,275 @@ function Chat({
|
|
|
3560
4485
|
showHeader && (renderHeader ? renderHeader() : /* @__PURE__ */ jsx(
|
|
3561
4486
|
ChatHeader,
|
|
3562
4487
|
{
|
|
4488
|
+
logo: header?.logo ?? logo,
|
|
4489
|
+
name: header?.name ?? name,
|
|
3563
4490
|
title,
|
|
3564
|
-
|
|
4491
|
+
threadPicker,
|
|
4492
|
+
onClose: header?.onClose ?? onClose,
|
|
3565
4493
|
className: classNames.header
|
|
3566
4494
|
}
|
|
3567
4495
|
)),
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
}
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
4496
|
+
showWelcome ? (
|
|
4497
|
+
/* Welcome Screen (centered input) */
|
|
4498
|
+
/* @__PURE__ */ jsx(
|
|
4499
|
+
ChatWelcome,
|
|
4500
|
+
{
|
|
4501
|
+
config: welcomeConfig,
|
|
4502
|
+
suggestions,
|
|
4503
|
+
recentThreads,
|
|
4504
|
+
onSendMessage: (msg, attachments) => onSendMessage?.(msg, attachments),
|
|
4505
|
+
onSelectThread,
|
|
4506
|
+
onDeleteThread,
|
|
4507
|
+
onViewMoreThreads,
|
|
4508
|
+
isLoading,
|
|
4509
|
+
onStop,
|
|
4510
|
+
placeholder,
|
|
4511
|
+
attachmentsEnabled,
|
|
4512
|
+
attachmentsDisabledTooltip,
|
|
4513
|
+
maxFileSize,
|
|
4514
|
+
allowedFileTypes,
|
|
4515
|
+
processAttachment: processAttachmentProp
|
|
4516
|
+
}
|
|
4517
|
+
)
|
|
4518
|
+
) : (
|
|
4519
|
+
/* Normal Chat UI (messages + input at bottom) */
|
|
4520
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4521
|
+
/* @__PURE__ */ jsxs(
|
|
4522
|
+
ChatContainerRoot,
|
|
4523
|
+
{
|
|
4524
|
+
className: cn("relative flex-1", classNames.container),
|
|
4525
|
+
children: [
|
|
4526
|
+
/* @__PURE__ */ jsxs(
|
|
4527
|
+
ChatContainerContent,
|
|
4528
|
+
{
|
|
4529
|
+
className: cn("gap-4 p-4", classNames.messageList),
|
|
4530
|
+
children: [
|
|
4531
|
+
messages.length === 0 && /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-muted-foreground", children: welcomeMessage || "Send a message to start the conversation" }),
|
|
4532
|
+
messages.map((message, index) => {
|
|
4533
|
+
const isLastMessage = index === messages.length - 1;
|
|
4534
|
+
const isEmptyAssistant = message.role === "assistant" && !message.content?.trim();
|
|
4535
|
+
const hasToolCalls = message.tool_calls && message.tool_calls.length > 0;
|
|
4536
|
+
const hasToolExecutions = message.toolExecutions && message.toolExecutions.length > 0;
|
|
4537
|
+
const hasPendingApprovals = message.toolExecutions?.some(
|
|
4538
|
+
(exec) => exec.approvalStatus === "required"
|
|
4539
|
+
);
|
|
4540
|
+
if (isEmptyAssistant) {
|
|
4541
|
+
if (hasToolCalls || hasToolExecutions) ; else if (isLastMessage && hasPendingApprovals) ; else if (isLastMessage && isLoading && !isProcessing) {
|
|
4542
|
+
return /* @__PURE__ */ jsxs(Message, { className: "flex gap-2", children: [
|
|
4543
|
+
/* @__PURE__ */ jsx(
|
|
4544
|
+
MessageAvatar,
|
|
4545
|
+
{
|
|
4546
|
+
src: assistantAvatar.src || "",
|
|
4547
|
+
alt: "Assistant",
|
|
4548
|
+
fallback: assistantAvatar.fallback,
|
|
4549
|
+
fallbackIcon: !assistantAvatar.src ? /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "size-5" }) : void 0,
|
|
4550
|
+
className: "bg-background"
|
|
4551
|
+
}
|
|
4552
|
+
),
|
|
4553
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-lg bg-muted px-4 py-2", children: /* @__PURE__ */ jsx(Loader, { variant: loaderVariant, size: "sm" }) })
|
|
4554
|
+
] }, message.id);
|
|
4555
|
+
} else {
|
|
4556
|
+
return null;
|
|
4557
|
+
}
|
|
4558
|
+
}
|
|
4559
|
+
const savedExecutions = message.metadata?.toolExecutions;
|
|
4560
|
+
const messageToolExecutions = message.toolExecutions || savedExecutions;
|
|
4561
|
+
const messageWithExecutions = messageToolExecutions ? { ...message, toolExecutions: messageToolExecutions } : message;
|
|
4562
|
+
const handleFollowUpClick = (question) => {
|
|
4563
|
+
if (onSuggestionClick) {
|
|
4564
|
+
onSuggestionClick(question);
|
|
4565
|
+
} else {
|
|
4566
|
+
onSendMessage?.(question);
|
|
4567
|
+
}
|
|
4568
|
+
};
|
|
4569
|
+
return renderMessage ? /* @__PURE__ */ jsx(React8__default.Fragment, { children: renderMessage(messageWithExecutions, index) }, message.id) : /* @__PURE__ */ jsx(
|
|
4570
|
+
DefaultMessage,
|
|
4571
|
+
{
|
|
4572
|
+
message: messageWithExecutions,
|
|
4573
|
+
userAvatar,
|
|
4574
|
+
assistantAvatar,
|
|
4575
|
+
showUserAvatar,
|
|
4576
|
+
userMessageClassName: classNames.userMessage,
|
|
4577
|
+
assistantMessageClassName: classNames.assistantMessage,
|
|
4578
|
+
size: fontSize,
|
|
4579
|
+
isLastMessage,
|
|
4580
|
+
isLoading,
|
|
4581
|
+
registeredTools,
|
|
4582
|
+
toolRenderers,
|
|
4583
|
+
onApproveToolExecution,
|
|
4584
|
+
onRejectToolExecution,
|
|
4585
|
+
showFollowUps,
|
|
4586
|
+
onFollowUpClick: handleFollowUpClick,
|
|
4587
|
+
followUpClassName,
|
|
4588
|
+
followUpButtonClassName
|
|
4589
|
+
},
|
|
4590
|
+
message.id
|
|
4591
|
+
);
|
|
4592
|
+
}),
|
|
4593
|
+
isProcessing && /* @__PURE__ */ jsxs(Message, { className: "flex gap-2", children: [
|
|
3658
4594
|
/* @__PURE__ */ jsx(
|
|
3659
4595
|
MessageAvatar,
|
|
3660
4596
|
{
|
|
3661
4597
|
src: assistantAvatar?.src || "",
|
|
3662
4598
|
alt: "Assistant",
|
|
3663
4599
|
fallback: assistantAvatar?.fallback || "AI",
|
|
3664
|
-
className: "
|
|
4600
|
+
fallbackIcon: !assistantAvatar?.src ? /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "size-5" }) : void 0,
|
|
4601
|
+
className: "bg-background"
|
|
3665
4602
|
}
|
|
3666
4603
|
),
|
|
3667
|
-
/* @__PURE__ */
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
src: att.previewUrl,
|
|
3694
|
-
alt: att.file.name,
|
|
3695
|
-
className: "w-16 h-16 object-cover rounded-lg border"
|
|
3696
|
-
}
|
|
3697
|
-
) : /* @__PURE__ */ jsxs("div", { className: "w-16 h-16 bg-muted rounded-lg border flex flex-col items-center justify-center p-1", children: [
|
|
3698
|
-
/* @__PURE__ */ jsx(
|
|
3699
|
-
"svg",
|
|
3700
|
-
{
|
|
3701
|
-
className: "w-6 h-6 text-muted-foreground",
|
|
3702
|
-
fill: "none",
|
|
3703
|
-
viewBox: "0 0 24 24",
|
|
3704
|
-
stroke: "currentColor",
|
|
3705
|
-
children: /* @__PURE__ */ jsx(
|
|
3706
|
-
"path",
|
|
3707
|
-
{
|
|
3708
|
-
strokeLinecap: "round",
|
|
3709
|
-
strokeLinejoin: "round",
|
|
3710
|
-
strokeWidth: 1.5,
|
|
3711
|
-
d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
4604
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-muted px-4 py-2 flex items-center gap-2", children: [
|
|
4605
|
+
/* @__PURE__ */ jsx(Loader, { variant: "dots", size: "sm" }),
|
|
4606
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Continuing..." })
|
|
4607
|
+
] })
|
|
4608
|
+
] }),
|
|
4609
|
+
isLoading && !isProcessing && (() => {
|
|
4610
|
+
const lastMessage = messages[messages.length - 1];
|
|
4611
|
+
if (lastMessage?.role === "user") {
|
|
4612
|
+
return /* @__PURE__ */ jsxs(Message, { className: "flex gap-2", children: [
|
|
4613
|
+
/* @__PURE__ */ jsx(
|
|
4614
|
+
MessageAvatar,
|
|
4615
|
+
{
|
|
4616
|
+
src: assistantAvatar?.src || "",
|
|
4617
|
+
alt: "Assistant",
|
|
4618
|
+
fallback: assistantAvatar?.fallback || "AI",
|
|
4619
|
+
fallbackIcon: !assistantAvatar?.src ? /* @__PURE__ */ jsx(copilot_sdk_logo_default, { className: "size-5" }) : void 0,
|
|
4620
|
+
className: "bg-background"
|
|
4621
|
+
}
|
|
4622
|
+
),
|
|
4623
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-lg bg-muted px-4 py-2", children: /* @__PURE__ */ jsx(Loader, { variant: loaderVariant, size: "sm" }) })
|
|
4624
|
+
] });
|
|
4625
|
+
}
|
|
4626
|
+
return null;
|
|
4627
|
+
})(),
|
|
4628
|
+
/* @__PURE__ */ jsx(ChatContainerScrollAnchor, {})
|
|
4629
|
+
]
|
|
3712
4630
|
}
|
|
3713
|
-
)
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
/* @__PURE__ */ jsx(
|
|
3721
|
-
"button",
|
|
4631
|
+
),
|
|
4632
|
+
/* @__PURE__ */ jsx("div", { className: "absolute right-4 bottom-4", children: /* @__PURE__ */ jsx(ScrollButton, { className: "shadow-sm" }) })
|
|
4633
|
+
]
|
|
4634
|
+
}
|
|
4635
|
+
),
|
|
4636
|
+
suggestions.length > 0 && !isLoading && /* @__PURE__ */ jsx(
|
|
4637
|
+
Suggestions,
|
|
3722
4638
|
{
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
children: /* @__PURE__ */ jsx(XIcon2, { className: "w-3 h-3" })
|
|
4639
|
+
suggestions,
|
|
4640
|
+
onSuggestionClick: handleSuggestionClick,
|
|
4641
|
+
className: classNames.suggestions
|
|
3727
4642
|
}
|
|
3728
|
-
)
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
3742
|
-
PromptInputAction,
|
|
4643
|
+
),
|
|
4644
|
+
renderInput ? renderInput() : /* @__PURE__ */ jsxs("div", { className: cn("p-2 pt-0", classNames.input), children: [
|
|
4645
|
+
pendingAttachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 p-2 mb-2 bg-muted/30 rounded-lg", children: pendingAttachments.map((att) => /* @__PURE__ */ jsxs("div", { className: "relative group", children: [
|
|
4646
|
+
att.attachment.type === "image" ? /* @__PURE__ */ jsx(
|
|
4647
|
+
"img",
|
|
4648
|
+
{
|
|
4649
|
+
src: att.previewUrl,
|
|
4650
|
+
alt: att.file.name,
|
|
4651
|
+
className: "w-16 h-16 object-cover rounded-lg border"
|
|
4652
|
+
}
|
|
4653
|
+
) : /* @__PURE__ */ jsxs("div", { className: "w-16 h-16 bg-muted rounded-lg border flex flex-col items-center justify-center p-1", children: [
|
|
4654
|
+
/* @__PURE__ */ jsx(
|
|
4655
|
+
"svg",
|
|
3743
4656
|
{
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
4657
|
+
className: "w-6 h-6 text-muted-foreground",
|
|
4658
|
+
fill: "none",
|
|
4659
|
+
viewBox: "0 0 24 24",
|
|
4660
|
+
stroke: "currentColor",
|
|
4661
|
+
children: /* @__PURE__ */ jsx(
|
|
4662
|
+
"path",
|
|
3747
4663
|
{
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
),
|
|
3753
|
-
children: [
|
|
3754
|
-
/* @__PURE__ */ jsx(
|
|
3755
|
-
"input",
|
|
3756
|
-
{
|
|
3757
|
-
ref: fileInputRef,
|
|
3758
|
-
type: "file",
|
|
3759
|
-
multiple: true,
|
|
3760
|
-
accept: acceptString,
|
|
3761
|
-
onChange: handleInputChange,
|
|
3762
|
-
className: "hidden",
|
|
3763
|
-
id: fileInputId,
|
|
3764
|
-
disabled: !attachmentsEnabled
|
|
3765
|
-
}
|
|
3766
|
-
),
|
|
3767
|
-
/* @__PURE__ */ jsx(PlusIcon, { className: "text-primary size-5" })
|
|
3768
|
-
]
|
|
4664
|
+
strokeLinecap: "round",
|
|
4665
|
+
strokeLinejoin: "round",
|
|
4666
|
+
strokeWidth: 1.5,
|
|
4667
|
+
d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
3769
4668
|
}
|
|
3770
4669
|
)
|
|
3771
4670
|
}
|
|
3772
|
-
)
|
|
3773
|
-
/* @__PURE__ */ jsx(
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
4671
|
+
),
|
|
4672
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground truncate w-full text-center mt-1", children: att.file.name.length > 10 ? att.file.name.slice(0, 8) + "..." : att.file.name })
|
|
4673
|
+
] }),
|
|
4674
|
+
att.status === "processing" && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-background/80 rounded-lg flex items-center justify-center", children: /* @__PURE__ */ jsx(Loader, { variant: "dots", size: "sm" }) }),
|
|
4675
|
+
att.status === "error" && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-destructive/20 rounded-lg flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "text-destructive text-xs", children: "Error" }) }),
|
|
4676
|
+
/* @__PURE__ */ jsx(
|
|
4677
|
+
"button",
|
|
4678
|
+
{
|
|
4679
|
+
onClick: () => removePendingAttachment(att.id),
|
|
4680
|
+
className: "absolute -top-1.5 -right-1.5 bg-destructive text-destructive-foreground rounded-full p-0.5 opacity-0 group-hover:opacity-100 transition-opacity",
|
|
4681
|
+
type: "button",
|
|
4682
|
+
children: /* @__PURE__ */ jsx(XIcon2, { className: "w-3 h-3" })
|
|
4683
|
+
}
|
|
4684
|
+
)
|
|
4685
|
+
] }, att.id)) }),
|
|
4686
|
+
/* @__PURE__ */ jsxs(
|
|
4687
|
+
PromptInput,
|
|
4688
|
+
{
|
|
4689
|
+
value: input,
|
|
4690
|
+
onValueChange: setInput,
|
|
4691
|
+
isLoading,
|
|
4692
|
+
onSubmit: handleSubmit,
|
|
4693
|
+
className: "",
|
|
4694
|
+
children: [
|
|
4695
|
+
/* @__PURE__ */ jsx(PromptInputTextarea, { placeholder }),
|
|
4696
|
+
/* @__PURE__ */ jsxs(PromptInputActions, { className: "flex justify-between", children: [
|
|
4697
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
4698
|
+
PromptInputAction,
|
|
4699
|
+
{
|
|
4700
|
+
tooltip: attachmentsEnabled ? "Attach files" : attachmentsDisabledTooltip,
|
|
4701
|
+
children: /* @__PURE__ */ jsxs(
|
|
4702
|
+
"label",
|
|
4703
|
+
{
|
|
4704
|
+
htmlFor: fileInputId,
|
|
4705
|
+
className: cn(
|
|
4706
|
+
"flex h-8 w-8 items-center justify-center rounded-2xl",
|
|
4707
|
+
attachmentsEnabled ? "hover:bg-secondary-foreground/10 cursor-pointer" : "opacity-50 cursor-not-allowed"
|
|
4708
|
+
),
|
|
4709
|
+
children: [
|
|
4710
|
+
/* @__PURE__ */ jsx(
|
|
4711
|
+
"input",
|
|
4712
|
+
{
|
|
4713
|
+
ref: fileInputRef,
|
|
4714
|
+
type: "file",
|
|
4715
|
+
multiple: true,
|
|
4716
|
+
accept: acceptString,
|
|
4717
|
+
onChange: handleInputChange,
|
|
4718
|
+
className: "hidden",
|
|
4719
|
+
id: fileInputId,
|
|
4720
|
+
disabled: !attachmentsEnabled
|
|
4721
|
+
}
|
|
4722
|
+
),
|
|
4723
|
+
/* @__PURE__ */ jsx(PlusIcon, { className: "text-primary size-5" })
|
|
4724
|
+
]
|
|
4725
|
+
}
|
|
4726
|
+
)
|
|
4727
|
+
}
|
|
4728
|
+
) }),
|
|
4729
|
+
/* @__PURE__ */ jsx(PromptInputAction, { tooltip: isLoading ? "Stop" : "Send", children: isLoading ? /* @__PURE__ */ jsx(
|
|
4730
|
+
Button,
|
|
4731
|
+
{
|
|
4732
|
+
size: "sm",
|
|
4733
|
+
variant: "destructive",
|
|
4734
|
+
className: "rounded-full size-9",
|
|
4735
|
+
onClick: onStop,
|
|
4736
|
+
children: /* @__PURE__ */ jsx(StopIcon, { className: "h-4 w-4" })
|
|
4737
|
+
}
|
|
4738
|
+
) : /* @__PURE__ */ jsx(
|
|
4739
|
+
Button,
|
|
4740
|
+
{
|
|
4741
|
+
size: "sm",
|
|
4742
|
+
className: "rounded-full size-9",
|
|
4743
|
+
onClick: handleSubmit,
|
|
4744
|
+
disabled: !input.trim() && !pendingAttachments.some(
|
|
4745
|
+
(att) => att.status === "ready"
|
|
4746
|
+
),
|
|
4747
|
+
children: /* @__PURE__ */ jsx(ArrowUpIcon, { className: "h-4 w-4" })
|
|
4748
|
+
}
|
|
4749
|
+
) })
|
|
4750
|
+
] })
|
|
4751
|
+
]
|
|
4752
|
+
}
|
|
4753
|
+
)
|
|
4754
|
+
] })
|
|
4755
|
+
] })
|
|
4756
|
+
)
|
|
3797
4757
|
]
|
|
3798
4758
|
}
|
|
3799
4759
|
);
|
|
@@ -3919,7 +4879,229 @@ function ToolExecutionMessage({
|
|
|
3919
4879
|
] })
|
|
3920
4880
|
] });
|
|
3921
4881
|
}
|
|
4882
|
+
function useInternalThreadManager(config = {}) {
|
|
4883
|
+
const {
|
|
4884
|
+
adapter,
|
|
4885
|
+
saveDebounce = 1e3,
|
|
4886
|
+
autoRestoreLastThread = true,
|
|
4887
|
+
onThreadChange
|
|
4888
|
+
} = config;
|
|
4889
|
+
const threadManagerConfig = {
|
|
4890
|
+
adapter,
|
|
4891
|
+
saveDebounce,
|
|
4892
|
+
autoRestoreLastThread
|
|
4893
|
+
};
|
|
4894
|
+
const threadManager = useThreadManager(threadManagerConfig);
|
|
4895
|
+
const {
|
|
4896
|
+
currentThread,
|
|
4897
|
+
currentThreadId,
|
|
4898
|
+
createThread,
|
|
4899
|
+
switchThread,
|
|
4900
|
+
updateCurrentThread,
|
|
4901
|
+
clearCurrentThread,
|
|
4902
|
+
refreshThreads
|
|
4903
|
+
} = threadManager;
|
|
4904
|
+
const { messages, setMessages, status, isLoading } = useCopilot();
|
|
4905
|
+
const isLoadingMessagesRef = useRef(false);
|
|
4906
|
+
const savingToThreadRef = useRef(null);
|
|
4907
|
+
const lastSavedSnapshotRef = useRef("");
|
|
4908
|
+
const hasInitializedRef = useRef(false);
|
|
4909
|
+
const getMessageSnapshot = useCallback((msgs) => {
|
|
4910
|
+
return msgs.map((m) => {
|
|
4911
|
+
const contentPreview = (m.content ?? "").slice(0, 20);
|
|
4912
|
+
return `${m.id}:${contentPreview}:${m.content?.length ?? 0}`;
|
|
4913
|
+
}).join("|");
|
|
4914
|
+
}, []);
|
|
4915
|
+
const convertToCore = useCallback((msgs) => {
|
|
4916
|
+
return msgs.map((m) => ({
|
|
4917
|
+
id: m.id,
|
|
4918
|
+
role: m.role,
|
|
4919
|
+
content: m.content,
|
|
4920
|
+
created_at: m.createdAt,
|
|
4921
|
+
tool_calls: m.toolCalls,
|
|
4922
|
+
tool_call_id: m.toolCallId,
|
|
4923
|
+
metadata: {
|
|
4924
|
+
attachments: m.attachments,
|
|
4925
|
+
thinking: m.thinking
|
|
4926
|
+
}
|
|
4927
|
+
}));
|
|
4928
|
+
}, []);
|
|
4929
|
+
const handleSwitchThread = useCallback(
|
|
4930
|
+
async (threadId) => {
|
|
4931
|
+
isLoadingMessagesRef.current = true;
|
|
4932
|
+
const thread = await switchThread(threadId);
|
|
4933
|
+
if (thread?.messages) {
|
|
4934
|
+
const uiMessages = thread.messages.map((m) => ({
|
|
4935
|
+
id: m.id,
|
|
4936
|
+
role: m.role,
|
|
4937
|
+
content: m.content ?? "",
|
|
4938
|
+
createdAt: m.created_at ?? /* @__PURE__ */ new Date(),
|
|
4939
|
+
toolCalls: m.tool_calls,
|
|
4940
|
+
toolCallId: m.tool_call_id,
|
|
4941
|
+
attachments: m.metadata?.attachments
|
|
4942
|
+
}));
|
|
4943
|
+
lastSavedSnapshotRef.current = getMessageSnapshot(uiMessages);
|
|
4944
|
+
savingToThreadRef.current = threadId;
|
|
4945
|
+
setMessages(uiMessages);
|
|
4946
|
+
} else {
|
|
4947
|
+
lastSavedSnapshotRef.current = "";
|
|
4948
|
+
savingToThreadRef.current = threadId;
|
|
4949
|
+
setMessages([]);
|
|
4950
|
+
}
|
|
4951
|
+
onThreadChange?.(threadId);
|
|
4952
|
+
requestAnimationFrame(() => {
|
|
4953
|
+
isLoadingMessagesRef.current = false;
|
|
4954
|
+
});
|
|
4955
|
+
},
|
|
4956
|
+
[switchThread, setMessages, getMessageSnapshot, onThreadChange]
|
|
4957
|
+
);
|
|
4958
|
+
const handleNewThread = useCallback(async () => {
|
|
4959
|
+
isLoadingMessagesRef.current = true;
|
|
4960
|
+
clearCurrentThread();
|
|
4961
|
+
lastSavedSnapshotRef.current = "";
|
|
4962
|
+
savingToThreadRef.current = null;
|
|
4963
|
+
setMessages([]);
|
|
4964
|
+
onThreadChange?.(null);
|
|
4965
|
+
requestAnimationFrame(() => {
|
|
4966
|
+
isLoadingMessagesRef.current = false;
|
|
4967
|
+
});
|
|
4968
|
+
}, [clearCurrentThread, setMessages, onThreadChange]);
|
|
4969
|
+
useEffect(() => {
|
|
4970
|
+
if (hasInitializedRef.current || !currentThread) {
|
|
4971
|
+
return;
|
|
4972
|
+
}
|
|
4973
|
+
hasInitializedRef.current = true;
|
|
4974
|
+
isLoadingMessagesRef.current = true;
|
|
4975
|
+
if (currentThread.messages && currentThread.messages.length > 0) {
|
|
4976
|
+
const uiMessages = currentThread.messages.map((m) => ({
|
|
4977
|
+
id: m.id,
|
|
4978
|
+
role: m.role,
|
|
4979
|
+
content: m.content ?? "",
|
|
4980
|
+
createdAt: m.created_at ?? /* @__PURE__ */ new Date(),
|
|
4981
|
+
toolCalls: m.tool_calls,
|
|
4982
|
+
toolCallId: m.tool_call_id,
|
|
4983
|
+
attachments: m.metadata?.attachments
|
|
4984
|
+
}));
|
|
4985
|
+
lastSavedSnapshotRef.current = getMessageSnapshot(uiMessages);
|
|
4986
|
+
savingToThreadRef.current = currentThread.id;
|
|
4987
|
+
setMessages(uiMessages);
|
|
4988
|
+
} else {
|
|
4989
|
+
lastSavedSnapshotRef.current = "";
|
|
4990
|
+
savingToThreadRef.current = currentThread.id;
|
|
4991
|
+
}
|
|
4992
|
+
onThreadChange?.(currentThread.id);
|
|
4993
|
+
requestAnimationFrame(() => {
|
|
4994
|
+
isLoadingMessagesRef.current = false;
|
|
4995
|
+
});
|
|
4996
|
+
}, [currentThread, setMessages, getMessageSnapshot, onThreadChange]);
|
|
4997
|
+
useEffect(() => {
|
|
4998
|
+
if (isLoadingMessagesRef.current) {
|
|
4999
|
+
return;
|
|
5000
|
+
}
|
|
5001
|
+
if (status === "streaming" || status === "submitted") {
|
|
5002
|
+
return;
|
|
5003
|
+
}
|
|
5004
|
+
if (messages.length === 0) {
|
|
5005
|
+
return;
|
|
5006
|
+
}
|
|
5007
|
+
const currentSnapshot = getMessageSnapshot(messages);
|
|
5008
|
+
if (currentSnapshot === lastSavedSnapshotRef.current) {
|
|
5009
|
+
return;
|
|
5010
|
+
}
|
|
5011
|
+
const coreMessages = convertToCore(messages);
|
|
5012
|
+
if (!currentThreadId && !savingToThreadRef.current) {
|
|
5013
|
+
savingToThreadRef.current = "creating";
|
|
5014
|
+
createThread({ messages: coreMessages }).then((thread) => {
|
|
5015
|
+
lastSavedSnapshotRef.current = currentSnapshot;
|
|
5016
|
+
savingToThreadRef.current = thread.id;
|
|
5017
|
+
onThreadChange?.(thread.id);
|
|
5018
|
+
});
|
|
5019
|
+
return;
|
|
5020
|
+
}
|
|
5021
|
+
if (savingToThreadRef.current && savingToThreadRef.current !== currentThreadId) {
|
|
5022
|
+
return;
|
|
5023
|
+
}
|
|
5024
|
+
updateCurrentThread({ messages: coreMessages });
|
|
5025
|
+
lastSavedSnapshotRef.current = currentSnapshot;
|
|
5026
|
+
}, [
|
|
5027
|
+
messages,
|
|
5028
|
+
currentThreadId,
|
|
5029
|
+
status,
|
|
5030
|
+
updateCurrentThread,
|
|
5031
|
+
createThread,
|
|
5032
|
+
refreshThreads,
|
|
5033
|
+
getMessageSnapshot,
|
|
5034
|
+
convertToCore,
|
|
5035
|
+
onThreadChange
|
|
5036
|
+
]);
|
|
5037
|
+
const isBusy = isLoading || status === "streaming" || status === "submitted";
|
|
5038
|
+
return {
|
|
5039
|
+
threadManager,
|
|
5040
|
+
handleSwitchThread,
|
|
5041
|
+
handleNewThread,
|
|
5042
|
+
isBusy
|
|
5043
|
+
};
|
|
5044
|
+
}
|
|
5045
|
+
function parsePersistenceConfig(persistence, onThreadChange) {
|
|
5046
|
+
if (!persistence) {
|
|
5047
|
+
return void 0;
|
|
5048
|
+
}
|
|
5049
|
+
if (persistence === true) {
|
|
5050
|
+
return {
|
|
5051
|
+
onThreadChange,
|
|
5052
|
+
autoRestoreLastThread: true
|
|
5053
|
+
};
|
|
5054
|
+
}
|
|
5055
|
+
if ("type" in persistence) {
|
|
5056
|
+
switch (persistence.type) {
|
|
5057
|
+
case "local":
|
|
5058
|
+
return {
|
|
5059
|
+
saveDebounce: persistence.saveDebounce,
|
|
5060
|
+
autoRestoreLastThread: persistence.autoRestoreLastThread ?? true,
|
|
5061
|
+
onThreadChange
|
|
5062
|
+
};
|
|
5063
|
+
case "server":
|
|
5064
|
+
return {
|
|
5065
|
+
adapter: createServerAdapter({
|
|
5066
|
+
endpoint: persistence.endpoint,
|
|
5067
|
+
headers: persistence.headers
|
|
5068
|
+
}),
|
|
5069
|
+
saveDebounce: persistence.saveDebounce,
|
|
5070
|
+
autoRestoreLastThread: persistence.autoRestoreLastThread ?? true,
|
|
5071
|
+
onThreadChange
|
|
5072
|
+
};
|
|
5073
|
+
case "cloud":
|
|
5074
|
+
console.warn(
|
|
5075
|
+
"[Copilot SDK] Cloud persistence is not yet implemented. Falling back to localStorage."
|
|
5076
|
+
);
|
|
5077
|
+
return {
|
|
5078
|
+
onThreadChange,
|
|
5079
|
+
autoRestoreLastThread: true
|
|
5080
|
+
};
|
|
5081
|
+
}
|
|
5082
|
+
}
|
|
5083
|
+
const legacyConfig = persistence;
|
|
5084
|
+
return {
|
|
5085
|
+
adapter: legacyConfig.adapter,
|
|
5086
|
+
saveDebounce: legacyConfig.saveDebounce,
|
|
5087
|
+
autoRestoreLastThread: legacyConfig.autoRestoreLastThread ?? true,
|
|
5088
|
+
onThreadChange
|
|
5089
|
+
};
|
|
5090
|
+
}
|
|
3922
5091
|
function CopilotChat(props) {
|
|
5092
|
+
const {
|
|
5093
|
+
persistence,
|
|
5094
|
+
showThreadPicker = false,
|
|
5095
|
+
onThreadChange,
|
|
5096
|
+
classNames,
|
|
5097
|
+
header,
|
|
5098
|
+
...chatProps
|
|
5099
|
+
} = props;
|
|
5100
|
+
const persistenceConfig = parsePersistenceConfig(persistence, onThreadChange);
|
|
5101
|
+
const threadManagerResult = useInternalThreadManager(
|
|
5102
|
+
persistenceConfig ?? { autoRestoreLastThread: false }
|
|
5103
|
+
);
|
|
5104
|
+
const isPersistenceEnabled = !!persistence;
|
|
3923
5105
|
const {
|
|
3924
5106
|
messages,
|
|
3925
5107
|
isLoading,
|
|
@@ -4019,7 +5201,7 @@ function CopilotChat(props) {
|
|
|
4019
5201
|
toolExecutions: messageToolExecutions
|
|
4020
5202
|
};
|
|
4021
5203
|
});
|
|
4022
|
-
const suggestions = visibleMessages.length === 0 &&
|
|
5204
|
+
const suggestions = visibleMessages.length === 0 && chatProps.suggestions?.length ? chatProps.suggestions : [];
|
|
4023
5205
|
const lastMessage = messages[messages.length - 1];
|
|
4024
5206
|
const isInToolFlow = lastMessage?.role === "assistant" && lastMessage.toolCalls?.length;
|
|
4025
5207
|
let isProcessingToolResults = false;
|
|
@@ -4040,20 +5222,70 @@ function CopilotChat(props) {
|
|
|
4040
5222
|
);
|
|
4041
5223
|
isProcessingToolResults = hasCompletedTools && !hasExecutingTools;
|
|
4042
5224
|
}
|
|
5225
|
+
const chatClassNames = classNames ? {
|
|
5226
|
+
root: classNames.root,
|
|
5227
|
+
header: classNames.header,
|
|
5228
|
+
container: classNames.container,
|
|
5229
|
+
messageList: classNames.messageList,
|
|
5230
|
+
userMessage: classNames.userMessage,
|
|
5231
|
+
assistantMessage: classNames.assistantMessage,
|
|
5232
|
+
input: classNames.input,
|
|
5233
|
+
suggestions: classNames.suggestions,
|
|
5234
|
+
footer: classNames.footer
|
|
5235
|
+
} : void 0;
|
|
5236
|
+
const { threadManager, handleSwitchThread, handleNewThread, isBusy } = threadManagerResult;
|
|
5237
|
+
const handleDeleteThread = React8__default.useCallback(
|
|
5238
|
+
(threadId) => {
|
|
5239
|
+
const isCurrentThread = threadManager.currentThreadId === threadId;
|
|
5240
|
+
threadManager.deleteThread(threadId);
|
|
5241
|
+
if (isCurrentThread) {
|
|
5242
|
+
handleNewThread();
|
|
5243
|
+
}
|
|
5244
|
+
},
|
|
5245
|
+
[threadManager, handleNewThread]
|
|
5246
|
+
);
|
|
5247
|
+
const threadPickerElement = isPersistenceEnabled && showThreadPicker ? /* @__PURE__ */ jsx(
|
|
5248
|
+
ThreadPicker,
|
|
5249
|
+
{
|
|
5250
|
+
value: threadManager.currentThreadId,
|
|
5251
|
+
threads: threadManager.threads,
|
|
5252
|
+
onSelect: handleSwitchThread,
|
|
5253
|
+
onDeleteThread: handleDeleteThread,
|
|
5254
|
+
onNewThread: handleNewThread,
|
|
5255
|
+
loading: threadManager.isLoading,
|
|
5256
|
+
disabled: isBusy,
|
|
5257
|
+
size: "sm",
|
|
5258
|
+
className: classNames?.threadPicker,
|
|
5259
|
+
buttonClassName: classNames?.threadPickerButton,
|
|
5260
|
+
dropdownClassName: classNames?.threadPickerDropdown,
|
|
5261
|
+
itemClassName: classNames?.threadPickerItem,
|
|
5262
|
+
newButtonClassName: classNames?.threadPickerNewButton
|
|
5263
|
+
}
|
|
5264
|
+
) : void 0;
|
|
5265
|
+
const shouldShowHeader = !!header || showThreadPicker || chatProps.showHeader;
|
|
5266
|
+
const useCustomHeader = chatProps.renderHeader && !header && !showThreadPicker;
|
|
4043
5267
|
return /* @__PURE__ */ jsx(
|
|
4044
5268
|
Chat,
|
|
4045
5269
|
{
|
|
4046
|
-
...
|
|
5270
|
+
...chatProps,
|
|
4047
5271
|
messages: visibleMessages,
|
|
4048
5272
|
onSendMessage: sendMessage,
|
|
4049
5273
|
onStop: stop,
|
|
4050
5274
|
isLoading,
|
|
4051
|
-
showPoweredBy:
|
|
5275
|
+
showPoweredBy: chatProps.showPoweredBy ?? true,
|
|
4052
5276
|
suggestions,
|
|
4053
5277
|
isProcessing: isProcessingToolResults,
|
|
4054
5278
|
onApproveToolExecution: approveToolExecution,
|
|
4055
5279
|
onRejectToolExecution: rejectToolExecution,
|
|
4056
|
-
registeredTools
|
|
5280
|
+
registeredTools,
|
|
5281
|
+
classNames: chatClassNames,
|
|
5282
|
+
header,
|
|
5283
|
+
threadPicker: threadPickerElement,
|
|
5284
|
+
showHeader: shouldShowHeader,
|
|
5285
|
+
renderHeader: useCustomHeader ? chatProps.renderHeader : void 0,
|
|
5286
|
+
recentThreads: isPersistenceEnabled ? threadManager.threads : void 0,
|
|
5287
|
+
onSelectThread: isPersistenceEnabled ? handleSwitchThread : void 0,
|
|
5288
|
+
onDeleteThread: isPersistenceEnabled ? handleDeleteThread : void 0
|
|
4057
5289
|
}
|
|
4058
5290
|
);
|
|
4059
5291
|
}
|
|
@@ -4104,6 +5336,6 @@ function PoweredBy({ className, showLogo = true }) {
|
|
|
4104
5336
|
);
|
|
4105
5337
|
}
|
|
4106
5338
|
|
|
4107
|
-
export { AlertTriangleIcon, BotIcon, Button, CapabilityBadge, CapabilityList, Chat, ChatContainerContent, ChatContainerRoot, ChatContainerScrollAnchor, CheckIcon, ChevronDownIcon2 as ChevronDownIcon, ChevronUpIcon, CloseIcon, CodeBlock, CompactPermissionConfirmation, Confirmation, ConfirmationActions, ConfirmationApproved, ConfirmationMessage, ConfirmationPending, ConfirmationRejected, ConnectedChat, CopilotChat, CopilotUIProvider, CopyIcon, DEFAULT_PERMISSION_OPTIONS, DevLogger, FeedbackBar, FollowUpQuestions, InlineToolSteps, Loader, Markdown, MessageAvatar, MessageContent, Message as MessagePrimitive, ModelSelector, PermissionConfirmation, PoweredBy, PromptInput, PromptInputAction, PromptInputActions, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, RefreshIcon, ScrollButton, SendIcon, SimpleConfirmation, SimpleModelSelector, SimpleReasoning, Source, SourceContent, SourceTrigger, StopIcon, ThumbsDownIcon2 as ThumbsDownIcon, ThumbsUpIcon2 as ThumbsUpIcon, ToolExecutionMessage, ToolStep, ToolSteps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserIcon, XIcon2 as XIcon, cn, parseFollowUps, useChatContainer, useCopilotUI };
|
|
5339
|
+
export { AlertTriangleIcon, BotIcon, Button, CapabilityBadge, CapabilityList, Chat, ChatContainerContent, ChatContainerRoot, ChatContainerScrollAnchor, ChatWelcome, CheckIcon, ChevronDownIcon2 as ChevronDownIcon, ChevronUpIcon, CloseIcon, CodeBlock, CompactPermissionConfirmation, Confirmation, ConfirmationActions, ConfirmationApproved, ConfirmationMessage, ConfirmationPending, ConfirmationRejected, ConnectedChat, CopilotChat, CopilotUIProvider, CopyIcon, DEFAULT_PERMISSION_OPTIONS, DevLogger, FeedbackBar, FollowUpQuestions, InlineToolSteps, Loader, Markdown, MessageAvatar, MessageContent, Message as MessagePrimitive, ModelSelector, PermissionConfirmation, PoweredBy, PromptInput, PromptInputAction, PromptInputActions, PromptInputTextarea, Reasoning, ReasoningContent, ReasoningTrigger, RefreshIcon, ScrollButton, SendIcon, SimpleConfirmation, SimpleModelSelector, SimpleReasoning, Source, SourceContent, SourceTrigger, StopIcon, ThreadCard, ThreadList, ThreadPicker, ThumbsDownIcon2 as ThumbsDownIcon, ThumbsUpIcon2 as ThumbsUpIcon, ToolExecutionMessage, ToolStep, ToolSteps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserIcon, XIcon2 as XIcon, cn, parseFollowUps, useChatContainer, useCopilotUI };
|
|
4108
5340
|
//# sourceMappingURL=index.js.map
|
|
4109
5341
|
//# sourceMappingURL=index.js.map
|