@cadraos/sdk 0.1.5 → 0.1.7
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/chat/index.cjs +1069 -34
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +221 -7
- package/dist/chat/index.d.ts +221 -7
- package/dist/chat/index.js +1069 -37
- package/dist/chat/index.js.map +1 -1
- package/dist/index.cjs +23 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -2
- package/dist/index.d.ts +54 -2
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/chat/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createContext,
|
|
2
|
-
import {
|
|
1
|
+
import { createContext, forwardRef, useState, useRef, useImperativeHandle, useCallback, useEffect, useMemo, useContext } from 'react';
|
|
2
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import ReactMarkdown from 'react-markdown';
|
|
4
4
|
import remarkGfm from 'remark-gfm';
|
|
5
5
|
|
|
@@ -1523,6 +1523,29 @@ var ToolsAPI = class extends BaseResourceAPI {
|
|
|
1523
1523
|
const idempotencyKey = generateIdempotencyKey();
|
|
1524
1524
|
return this.httpPost(`/${uuid}/execute`, { input }, { idempotencyKey });
|
|
1525
1525
|
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Execute a tool directly, bypassing the agent runtime.
|
|
1528
|
+
*
|
|
1529
|
+
* Enqueues the tool for async processing via BullMQ (no LLM, no ReAct loop).
|
|
1530
|
+
* Use SSE or polling with the returned executionId to get the result.
|
|
1531
|
+
*
|
|
1532
|
+
* @param request - Direct execution request
|
|
1533
|
+
* @returns Queued execution response with executionId for tracking
|
|
1534
|
+
*
|
|
1535
|
+
* @example
|
|
1536
|
+
* ```typescript
|
|
1537
|
+
* const result = await client.tools.executeDirect({
|
|
1538
|
+
* toolUuid: 'tool-uuid',
|
|
1539
|
+
* parameters: { prompt: 'Generate an image of a sunset' },
|
|
1540
|
+
* });
|
|
1541
|
+
* console.log(result.executionId); // Use for polling/SSE
|
|
1542
|
+
* console.log(result.status); // 'queued'
|
|
1543
|
+
* ```
|
|
1544
|
+
*/
|
|
1545
|
+
async executeDirect(request) {
|
|
1546
|
+
const idempotencyKey = generateIdempotencyKey();
|
|
1547
|
+
return this.httpPost("/execute-direct", request, { idempotencyKey });
|
|
1548
|
+
}
|
|
1526
1549
|
/**
|
|
1527
1550
|
* Validate input against tool schema
|
|
1528
1551
|
*
|
|
@@ -3191,8 +3214,9 @@ function useAgentChat(options) {
|
|
|
3191
3214
|
[adapter, handleExecutionLog, updateStreamingMessage, updateToolCall, handleClarification, handleComplete, handleError]
|
|
3192
3215
|
);
|
|
3193
3216
|
const sendMessage = useCallback(
|
|
3194
|
-
async (content) => {
|
|
3217
|
+
async (content, options2) => {
|
|
3195
3218
|
if (!content.trim()) return;
|
|
3219
|
+
const attachmentUuids = options2?.attachmentUuids;
|
|
3196
3220
|
lastMessageContentRef.current = content;
|
|
3197
3221
|
setIsLoading(true);
|
|
3198
3222
|
setError(null);
|
|
@@ -3223,7 +3247,8 @@ function useAgentChat(options) {
|
|
|
3223
3247
|
agentId,
|
|
3224
3248
|
teamId,
|
|
3225
3249
|
sessionId: currentSessionId ?? void 0,
|
|
3226
|
-
content: content.trim()
|
|
3250
|
+
content: content.trim(),
|
|
3251
|
+
attachmentUuids
|
|
3227
3252
|
});
|
|
3228
3253
|
console.log("[useAgentChat] Execution started:", result);
|
|
3229
3254
|
if (!currentSessionId && result.sessionId) {
|
|
@@ -3432,6 +3457,222 @@ function useAgentChat(options) {
|
|
|
3432
3457
|
loadSession
|
|
3433
3458
|
};
|
|
3434
3459
|
}
|
|
3460
|
+
|
|
3461
|
+
// src/chat/utils/compress-image.ts
|
|
3462
|
+
var DEFAULT_TARGET_SIZE_KB = 150;
|
|
3463
|
+
var MAX_DIMENSION = 1920;
|
|
3464
|
+
var QUALITY_START = 0.85;
|
|
3465
|
+
var QUALITY_STEP = 0.05;
|
|
3466
|
+
var QUALITY_MIN = 0.1;
|
|
3467
|
+
function loadImage(file) {
|
|
3468
|
+
return new Promise((resolve, reject) => {
|
|
3469
|
+
const img = new Image();
|
|
3470
|
+
const url = URL.createObjectURL(file);
|
|
3471
|
+
img.onload = () => {
|
|
3472
|
+
URL.revokeObjectURL(url);
|
|
3473
|
+
resolve(img);
|
|
3474
|
+
};
|
|
3475
|
+
img.onerror = () => {
|
|
3476
|
+
URL.revokeObjectURL(url);
|
|
3477
|
+
reject(new Error(`Failed to load image: ${file.name}`));
|
|
3478
|
+
};
|
|
3479
|
+
img.src = url;
|
|
3480
|
+
});
|
|
3481
|
+
}
|
|
3482
|
+
function getScaledDimensions(width, height, maxDim) {
|
|
3483
|
+
if (width <= maxDim && height <= maxDim) {
|
|
3484
|
+
return { width, height };
|
|
3485
|
+
}
|
|
3486
|
+
const ratio = Math.min(maxDim / width, maxDim / height);
|
|
3487
|
+
return {
|
|
3488
|
+
width: Math.round(width * ratio),
|
|
3489
|
+
height: Math.round(height * ratio)
|
|
3490
|
+
};
|
|
3491
|
+
}
|
|
3492
|
+
function canvasToBlob(img, width, height, format, quality) {
|
|
3493
|
+
return new Promise((resolve, reject) => {
|
|
3494
|
+
const canvas = document.createElement("canvas");
|
|
3495
|
+
canvas.width = width;
|
|
3496
|
+
canvas.height = height;
|
|
3497
|
+
const ctx = canvas.getContext("2d");
|
|
3498
|
+
if (!ctx) {
|
|
3499
|
+
reject(new Error("Failed to get canvas 2d context"));
|
|
3500
|
+
return;
|
|
3501
|
+
}
|
|
3502
|
+
ctx.drawImage(img, 0, 0, width, height);
|
|
3503
|
+
canvas.toBlob(
|
|
3504
|
+
(blob) => {
|
|
3505
|
+
if (!blob) {
|
|
3506
|
+
reject(new Error("Canvas toBlob returned null"));
|
|
3507
|
+
return;
|
|
3508
|
+
}
|
|
3509
|
+
resolve(blob);
|
|
3510
|
+
},
|
|
3511
|
+
format,
|
|
3512
|
+
quality
|
|
3513
|
+
);
|
|
3514
|
+
});
|
|
3515
|
+
}
|
|
3516
|
+
var webpSupported = null;
|
|
3517
|
+
function supportsWebP() {
|
|
3518
|
+
if (webpSupported !== null) return webpSupported;
|
|
3519
|
+
try {
|
|
3520
|
+
const canvas = document.createElement("canvas");
|
|
3521
|
+
canvas.width = 1;
|
|
3522
|
+
canvas.height = 1;
|
|
3523
|
+
webpSupported = canvas.toDataURL("image/webp").startsWith("data:image/webp");
|
|
3524
|
+
} catch {
|
|
3525
|
+
webpSupported = false;
|
|
3526
|
+
}
|
|
3527
|
+
return webpSupported;
|
|
3528
|
+
}
|
|
3529
|
+
function getOutputFormat(_originalType) {
|
|
3530
|
+
if (supportsWebP()) {
|
|
3531
|
+
return { mime: "image/webp", ext: ".webp" };
|
|
3532
|
+
}
|
|
3533
|
+
return { mime: "image/jpeg", ext: ".jpg" };
|
|
3534
|
+
}
|
|
3535
|
+
function replaceExtension(filename, newExt) {
|
|
3536
|
+
const dotIndex = filename.lastIndexOf(".");
|
|
3537
|
+
if (dotIndex === -1) return filename + newExt;
|
|
3538
|
+
return filename.substring(0, dotIndex) + newExt;
|
|
3539
|
+
}
|
|
3540
|
+
async function compressImage(file, targetSizeKB = DEFAULT_TARGET_SIZE_KB) {
|
|
3541
|
+
if (!file.type.startsWith("image/")) {
|
|
3542
|
+
return file;
|
|
3543
|
+
}
|
|
3544
|
+
if (file.type === "image/svg+xml") {
|
|
3545
|
+
return file;
|
|
3546
|
+
}
|
|
3547
|
+
if (file.type === "image/gif") {
|
|
3548
|
+
return file;
|
|
3549
|
+
}
|
|
3550
|
+
const targetBytes = targetSizeKB * 1024;
|
|
3551
|
+
if (file.size <= targetBytes) {
|
|
3552
|
+
return file;
|
|
3553
|
+
}
|
|
3554
|
+
const img = await loadImage(file);
|
|
3555
|
+
const { width, height } = getScaledDimensions(
|
|
3556
|
+
img.naturalWidth,
|
|
3557
|
+
img.naturalHeight,
|
|
3558
|
+
MAX_DIMENSION
|
|
3559
|
+
);
|
|
3560
|
+
const { mime, ext } = getOutputFormat(file.type);
|
|
3561
|
+
let quality = QUALITY_START;
|
|
3562
|
+
let blob = null;
|
|
3563
|
+
while (quality >= QUALITY_MIN) {
|
|
3564
|
+
blob = await canvasToBlob(img, width, height, mime, quality);
|
|
3565
|
+
if (blob.size <= targetBytes) {
|
|
3566
|
+
break;
|
|
3567
|
+
}
|
|
3568
|
+
quality -= QUALITY_STEP;
|
|
3569
|
+
}
|
|
3570
|
+
if (!blob) {
|
|
3571
|
+
blob = await canvasToBlob(img, width, height, mime, QUALITY_MIN);
|
|
3572
|
+
}
|
|
3573
|
+
if (blob.size >= file.size) {
|
|
3574
|
+
return file;
|
|
3575
|
+
}
|
|
3576
|
+
const newFilename = replaceExtension(file.name, ext);
|
|
3577
|
+
return new File([blob], newFilename, {
|
|
3578
|
+
type: mime,
|
|
3579
|
+
lastModified: Date.now()
|
|
3580
|
+
});
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
// src/chat/hooks/useFileAttachments.ts
|
|
3584
|
+
function useFileAttachments(options) {
|
|
3585
|
+
const { onUpload, onConfirmUpload, onSubmitUpload, onError, maxFiles = 10, maxTotalSizeMB = 100 } = options;
|
|
3586
|
+
const [files, setFiles] = useState([]);
|
|
3587
|
+
const filesRef = useRef(files);
|
|
3588
|
+
filesRef.current = files;
|
|
3589
|
+
const onFilesChange = useCallback((newFiles) => {
|
|
3590
|
+
filesRef.current = newFiles;
|
|
3591
|
+
setFiles(newFiles);
|
|
3592
|
+
}, []);
|
|
3593
|
+
const removeFile = useCallback((uuid) => {
|
|
3594
|
+
setFiles((prev) => {
|
|
3595
|
+
const file = prev.find((f) => f.uuid === uuid);
|
|
3596
|
+
if (file?.previewUrl) {
|
|
3597
|
+
URL.revokeObjectURL(file.previewUrl);
|
|
3598
|
+
}
|
|
3599
|
+
return prev.filter((f) => f.uuid !== uuid);
|
|
3600
|
+
});
|
|
3601
|
+
}, []);
|
|
3602
|
+
const getReadyUuids = useCallback(() => {
|
|
3603
|
+
return filesRef.current.filter((f) => f.status === "ready").map((f) => f.uuid);
|
|
3604
|
+
}, []);
|
|
3605
|
+
const getReadyUrls = useCallback(() => {
|
|
3606
|
+
return filesRef.current.filter((f) => f.status === "ready").map((f) => f.uuid);
|
|
3607
|
+
}, []);
|
|
3608
|
+
const prepareForSubmit = useCallback(async () => {
|
|
3609
|
+
const readyFiles = filesRef.current.filter((f) => f.status === "ready");
|
|
3610
|
+
console.log("[useFileAttachments] prepareForSubmit - readyFiles:", readyFiles.length, "hasSubmitUpload:", !!onSubmitUpload);
|
|
3611
|
+
if (readyFiles.length === 0) return [];
|
|
3612
|
+
if (!onSubmitUpload) {
|
|
3613
|
+
return readyFiles.map((f) => f.uuid);
|
|
3614
|
+
}
|
|
3615
|
+
const aiUuids = [];
|
|
3616
|
+
for (const attachment of readyFiles) {
|
|
3617
|
+
try {
|
|
3618
|
+
let fileToSend = attachment.file;
|
|
3619
|
+
if (attachment.category === "image") {
|
|
3620
|
+
try {
|
|
3621
|
+
fileToSend = await compressImage(attachment.file);
|
|
3622
|
+
} catch {
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
console.log("[useFileAttachments] Uploading to AI service:", attachment.file.name, "localUuid:", attachment.uuid.substring(0, 40));
|
|
3626
|
+
const aiUuid = await onSubmitUpload(
|
|
3627
|
+
fileToSend,
|
|
3628
|
+
attachment.uuid,
|
|
3629
|
+
{ filename: fileToSend.name, mimeType: fileToSend.type, size: fileToSend.size }
|
|
3630
|
+
);
|
|
3631
|
+
console.log("[useFileAttachments] AI service returned UUID:", aiUuid);
|
|
3632
|
+
aiUuids.push(aiUuid);
|
|
3633
|
+
} catch (err) {
|
|
3634
|
+
const msg = err instanceof Error ? err.message : "Submit upload failed";
|
|
3635
|
+
console.error("[useFileAttachments] Submit upload failed for:", attachment.file.name, msg);
|
|
3636
|
+
onError?.(msg);
|
|
3637
|
+
}
|
|
3638
|
+
}
|
|
3639
|
+
console.log("[useFileAttachments] prepareForSubmit result:", aiUuids);
|
|
3640
|
+
return aiUuids;
|
|
3641
|
+
}, [onSubmitUpload, onError]);
|
|
3642
|
+
const clear = useCallback(() => {
|
|
3643
|
+
for (const file of filesRef.current) {
|
|
3644
|
+
if (file.previewUrl) {
|
|
3645
|
+
URL.revokeObjectURL(file.previewUrl);
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
setFiles([]);
|
|
3649
|
+
}, []);
|
|
3650
|
+
const isUploading = files.some(
|
|
3651
|
+
(f) => f.status === "uploading" || f.status === "pending" || f.status === "processing"
|
|
3652
|
+
);
|
|
3653
|
+
const hasReadyFiles = files.some((f) => f.status === "ready");
|
|
3654
|
+
const dropZoneProps = {
|
|
3655
|
+
files,
|
|
3656
|
+
onFilesChange,
|
|
3657
|
+
onUpload,
|
|
3658
|
+
onConfirmUpload,
|
|
3659
|
+
onError,
|
|
3660
|
+
maxFiles,
|
|
3661
|
+
maxTotalSizeMB
|
|
3662
|
+
};
|
|
3663
|
+
return {
|
|
3664
|
+
files,
|
|
3665
|
+
dropZoneProps,
|
|
3666
|
+
removeFile,
|
|
3667
|
+
getReadyUuids,
|
|
3668
|
+
getReadyUrls,
|
|
3669
|
+
prepareForSubmit,
|
|
3670
|
+
clear,
|
|
3671
|
+
isUploading,
|
|
3672
|
+
hasReadyFiles,
|
|
3673
|
+
fileCount: files.length
|
|
3674
|
+
};
|
|
3675
|
+
}
|
|
3435
3676
|
function cn(...classes) {
|
|
3436
3677
|
return classes.filter(Boolean).join(" ");
|
|
3437
3678
|
}
|
|
@@ -4081,6 +4322,51 @@ function ChatContainer({
|
|
|
4081
4322
|
function cn3(...classes) {
|
|
4082
4323
|
return classes.filter(Boolean).join(" ");
|
|
4083
4324
|
}
|
|
4325
|
+
function formatFileSize(bytes) {
|
|
4326
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
4327
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
4328
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
4329
|
+
}
|
|
4330
|
+
function AttachmentChip({ attachment, onRemove }) {
|
|
4331
|
+
const isLoading = attachment.status === "uploading" || attachment.status === "pending" || attachment.status === "processing";
|
|
4332
|
+
const isError = attachment.status === "error" || attachment.status === "failed";
|
|
4333
|
+
return /* @__PURE__ */ jsxs(
|
|
4334
|
+
"div",
|
|
4335
|
+
{
|
|
4336
|
+
className: cn3(
|
|
4337
|
+
"inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs max-w-[180px]",
|
|
4338
|
+
isError ? "bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300 border border-red-200 dark:border-red-800" : "bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300 border border-gray-200 dark:border-gray-600"
|
|
4339
|
+
),
|
|
4340
|
+
children: [
|
|
4341
|
+
attachment.previewUrl && /* @__PURE__ */ jsx(
|
|
4342
|
+
"img",
|
|
4343
|
+
{
|
|
4344
|
+
src: attachment.previewUrl,
|
|
4345
|
+
alt: "",
|
|
4346
|
+
className: "w-5 h-5 rounded object-cover flex-shrink-0"
|
|
4347
|
+
}
|
|
4348
|
+
),
|
|
4349
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: attachment.file.name }),
|
|
4350
|
+
isLoading ? /* @__PURE__ */ jsx(LoadingSpinner, { className: "h-3 w-3 flex-shrink-0" }) : isError ? /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-red-500", title: attachment.error, children: "!" }) : /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-gray-400 dark:text-gray-500", children: formatFileSize(attachment.actualSize ?? attachment.file.size) }),
|
|
4351
|
+
/* @__PURE__ */ jsx(
|
|
4352
|
+
"button",
|
|
4353
|
+
{
|
|
4354
|
+
type: "button",
|
|
4355
|
+
onClick: (e) => {
|
|
4356
|
+
e.preventDefault();
|
|
4357
|
+
e.stopPropagation();
|
|
4358
|
+
onRemove(attachment.uuid);
|
|
4359
|
+
},
|
|
4360
|
+
className: "flex-shrink-0 p-0.5 rounded hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors",
|
|
4361
|
+
"aria-label": `Remove ${attachment.file.name}`,
|
|
4362
|
+
disabled: isLoading,
|
|
4363
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "h-3 w-3" })
|
|
4364
|
+
}
|
|
4365
|
+
)
|
|
4366
|
+
]
|
|
4367
|
+
}
|
|
4368
|
+
);
|
|
4369
|
+
}
|
|
4084
4370
|
function ChatInput({
|
|
4085
4371
|
onSend,
|
|
4086
4372
|
onStop,
|
|
@@ -4088,10 +4374,15 @@ function ChatInput({
|
|
|
4088
4374
|
disabled = false,
|
|
4089
4375
|
isLoading = false,
|
|
4090
4376
|
enableAttachments = false,
|
|
4377
|
+
attachments = [],
|
|
4378
|
+
onRemoveAttachment,
|
|
4379
|
+
dropZoneRef,
|
|
4380
|
+
isUploadingAttachments = false,
|
|
4091
4381
|
className
|
|
4092
4382
|
}) {
|
|
4093
4383
|
const [content, setContent] = useState("");
|
|
4094
4384
|
const textareaRef = useRef(null);
|
|
4385
|
+
const hasAttachments = enableAttachments && attachments.length > 0;
|
|
4095
4386
|
useEffect(() => {
|
|
4096
4387
|
const textarea = textareaRef.current;
|
|
4097
4388
|
if (textarea) {
|
|
@@ -4101,10 +4392,10 @@ function ChatInput({
|
|
|
4101
4392
|
}, [content]);
|
|
4102
4393
|
const handleSubmit = useCallback(async () => {
|
|
4103
4394
|
const trimmedContent = content.trim();
|
|
4104
|
-
if (!trimmedContent || disabled || isLoading) return;
|
|
4395
|
+
if (!trimmedContent && !hasAttachments || disabled || isLoading || isUploadingAttachments) return;
|
|
4105
4396
|
setContent("");
|
|
4106
4397
|
await onSend(trimmedContent);
|
|
4107
|
-
}, [content, disabled, isLoading, onSend]);
|
|
4398
|
+
}, [content, hasAttachments, disabled, isLoading, isUploadingAttachments, onSend]);
|
|
4108
4399
|
const handleKeyDown = useCallback(
|
|
4109
4400
|
(e) => {
|
|
4110
4401
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
@@ -4117,7 +4408,10 @@ function ChatInput({
|
|
|
4117
4408
|
const handleStopClick = useCallback(() => {
|
|
4118
4409
|
onStop?.();
|
|
4119
4410
|
}, [onStop]);
|
|
4120
|
-
const
|
|
4411
|
+
const handleAttachClick = useCallback(() => {
|
|
4412
|
+
dropZoneRef?.current?.openFileDialog();
|
|
4413
|
+
}, [dropZoneRef]);
|
|
4414
|
+
const canSend = (content.trim().length > 0 || hasAttachments) && !disabled && !isLoading && !isUploadingAttachments;
|
|
4121
4415
|
const showStopButton = isLoading && onStop;
|
|
4122
4416
|
return /* @__PURE__ */ jsxs(
|
|
4123
4417
|
"div",
|
|
@@ -4127,7 +4421,34 @@ function ChatInput({
|
|
|
4127
4421
|
className
|
|
4128
4422
|
),
|
|
4129
4423
|
children: [
|
|
4424
|
+
hasAttachments && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5 mb-2", children: attachments.map((attachment) => /* @__PURE__ */ jsx(
|
|
4425
|
+
AttachmentChip,
|
|
4426
|
+
{
|
|
4427
|
+
attachment,
|
|
4428
|
+
onRemove: onRemoveAttachment ?? (() => {
|
|
4429
|
+
})
|
|
4430
|
+
},
|
|
4431
|
+
attachment.uuid
|
|
4432
|
+
)) }),
|
|
4130
4433
|
/* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
|
|
4434
|
+
enableAttachments && /* @__PURE__ */ jsx(
|
|
4435
|
+
"button",
|
|
4436
|
+
{
|
|
4437
|
+
type: "button",
|
|
4438
|
+
onClick: handleAttachClick,
|
|
4439
|
+
disabled: disabled || isLoading,
|
|
4440
|
+
className: cn3(
|
|
4441
|
+
"flex-shrink-0 p-3 rounded-lg transition-colors",
|
|
4442
|
+
"text-gray-500 dark:text-gray-400",
|
|
4443
|
+
"hover:bg-gray-100 dark:hover:bg-gray-700",
|
|
4444
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
4445
|
+
"focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
|
4446
|
+
),
|
|
4447
|
+
"aria-label": "Attach files",
|
|
4448
|
+
title: "Attach files",
|
|
4449
|
+
children: /* @__PURE__ */ jsx(PaperclipIcon, { className: "h-5 w-5" })
|
|
4450
|
+
}
|
|
4451
|
+
),
|
|
4131
4452
|
/* @__PURE__ */ jsx("div", { className: "flex-1 relative", children: /* @__PURE__ */ jsx(
|
|
4132
4453
|
"textarea",
|
|
4133
4454
|
{
|
|
@@ -4135,7 +4456,7 @@ function ChatInput({
|
|
|
4135
4456
|
value: content,
|
|
4136
4457
|
onChange: (e) => setContent(e.target.value),
|
|
4137
4458
|
onKeyDown: handleKeyDown,
|
|
4138
|
-
placeholder,
|
|
4459
|
+
placeholder: hasAttachments && !content ? `${attachments.length} file${attachments.length > 1 ? "s" : ""} attached. Add a message or press Enter to send.` : placeholder,
|
|
4139
4460
|
disabled,
|
|
4140
4461
|
rows: 1,
|
|
4141
4462
|
className: cn3(
|
|
@@ -4185,9 +4506,664 @@ function ChatInput({
|
|
|
4185
4506
|
}
|
|
4186
4507
|
);
|
|
4187
4508
|
}
|
|
4509
|
+
function Upload({ className }) {
|
|
4510
|
+
return /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
4511
|
+
/* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
4512
|
+
/* @__PURE__ */ jsx("polyline", { points: "17 8 12 3 7 8" }),
|
|
4513
|
+
/* @__PURE__ */ jsx("line", { x1: "12", x2: "12", y1: "3", y2: "15" })
|
|
4514
|
+
] });
|
|
4515
|
+
}
|
|
4516
|
+
function X({ className }) {
|
|
4517
|
+
return /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
4518
|
+
/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
|
|
4519
|
+
/* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
|
|
4520
|
+
] });
|
|
4521
|
+
}
|
|
4522
|
+
function FileText({ className }) {
|
|
4523
|
+
return /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
4524
|
+
/* @__PURE__ */ jsx("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
|
|
4525
|
+
/* @__PURE__ */ jsx("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" }),
|
|
4526
|
+
/* @__PURE__ */ jsx("line", { x1: "16", x2: "8", y1: "13", y2: "13" }),
|
|
4527
|
+
/* @__PURE__ */ jsx("line", { x1: "16", x2: "8", y1: "17", y2: "17" }),
|
|
4528
|
+
/* @__PURE__ */ jsx("line", { x1: "10", x2: "8", y1: "9", y2: "9" })
|
|
4529
|
+
] });
|
|
4530
|
+
}
|
|
4531
|
+
function ImageIcon2({ className }) {
|
|
4532
|
+
return /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
4533
|
+
/* @__PURE__ */ jsx("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
|
|
4534
|
+
/* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "2" }),
|
|
4535
|
+
/* @__PURE__ */ jsx("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
|
|
4536
|
+
] });
|
|
4537
|
+
}
|
|
4538
|
+
function Music({ className }) {
|
|
4539
|
+
return /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
4540
|
+
/* @__PURE__ */ jsx("path", { d: "M9 18V5l12-2v13" }),
|
|
4541
|
+
/* @__PURE__ */ jsx("circle", { cx: "6", cy: "18", r: "3" }),
|
|
4542
|
+
/* @__PURE__ */ jsx("circle", { cx: "18", cy: "16", r: "3" })
|
|
4543
|
+
] });
|
|
4544
|
+
}
|
|
4545
|
+
function Loader2({ className }) {
|
|
4546
|
+
return /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
|
|
4547
|
+
}
|
|
4548
|
+
function FileIcon2({ className }) {
|
|
4549
|
+
return /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
4550
|
+
/* @__PURE__ */ jsx("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
|
|
4551
|
+
/* @__PURE__ */ jsx("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
|
|
4552
|
+
] });
|
|
4553
|
+
}
|
|
4554
|
+
function RotateCw({ className }) {
|
|
4555
|
+
return /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
4556
|
+
/* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" }),
|
|
4557
|
+
/* @__PURE__ */ jsx("path", { d: "M21 3v5h-5" })
|
|
4558
|
+
] });
|
|
4559
|
+
}
|
|
4188
4560
|
function cn4(...classes) {
|
|
4189
4561
|
return classes.filter(Boolean).join(" ");
|
|
4190
4562
|
}
|
|
4563
|
+
var SUPPORTED_TYPES = {
|
|
4564
|
+
document: {
|
|
4565
|
+
mimeTypes: [
|
|
4566
|
+
"application/pdf",
|
|
4567
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
4568
|
+
"application/msword",
|
|
4569
|
+
"text/plain",
|
|
4570
|
+
"text/markdown",
|
|
4571
|
+
"text/csv",
|
|
4572
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
4573
|
+
"application/vnd.ms-excel"
|
|
4574
|
+
],
|
|
4575
|
+
extensions: [
|
|
4576
|
+
".pdf",
|
|
4577
|
+
".docx",
|
|
4578
|
+
".doc",
|
|
4579
|
+
".txt",
|
|
4580
|
+
".md",
|
|
4581
|
+
".csv",
|
|
4582
|
+
".xlsx",
|
|
4583
|
+
".xls"
|
|
4584
|
+
],
|
|
4585
|
+
maxSizeMB: 25,
|
|
4586
|
+
label: "Documents"
|
|
4587
|
+
},
|
|
4588
|
+
image: {
|
|
4589
|
+
mimeTypes: [
|
|
4590
|
+
"image/png",
|
|
4591
|
+
"image/jpeg",
|
|
4592
|
+
"image/gif",
|
|
4593
|
+
"image/webp",
|
|
4594
|
+
"image/svg+xml"
|
|
4595
|
+
],
|
|
4596
|
+
extensions: [".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"],
|
|
4597
|
+
maxSizeMB: 10,
|
|
4598
|
+
label: "Images"
|
|
4599
|
+
},
|
|
4600
|
+
audio: {
|
|
4601
|
+
mimeTypes: [
|
|
4602
|
+
"audio/mpeg",
|
|
4603
|
+
"audio/wav",
|
|
4604
|
+
"audio/mp4",
|
|
4605
|
+
"audio/ogg",
|
|
4606
|
+
"audio/webm"
|
|
4607
|
+
],
|
|
4608
|
+
extensions: [".mp3", ".wav", ".m4a", ".ogg", ".webm"],
|
|
4609
|
+
maxSizeMB: 50,
|
|
4610
|
+
label: "Audio"
|
|
4611
|
+
}
|
|
4612
|
+
};
|
|
4613
|
+
var MAX_FILES_PER_DROP = 10;
|
|
4614
|
+
var MAX_TOTAL_SIZE_MB = 100;
|
|
4615
|
+
function categorizeFile(mimeType) {
|
|
4616
|
+
for (const [category, config] of Object.entries(SUPPORTED_TYPES)) {
|
|
4617
|
+
if (config.mimeTypes.includes(mimeType)) {
|
|
4618
|
+
return category;
|
|
4619
|
+
}
|
|
4620
|
+
}
|
|
4621
|
+
return null;
|
|
4622
|
+
}
|
|
4623
|
+
function validateFile(file) {
|
|
4624
|
+
const category = categorizeFile(file.type);
|
|
4625
|
+
if (!category) {
|
|
4626
|
+
return {
|
|
4627
|
+
valid: false,
|
|
4628
|
+
error: `Unsupported file type: ${file.type || file.name.split(".").pop()}`
|
|
4629
|
+
};
|
|
4630
|
+
}
|
|
4631
|
+
const config = SUPPORTED_TYPES[category];
|
|
4632
|
+
const maxSizeBytes = config.maxSizeMB * 1024 * 1024;
|
|
4633
|
+
if (file.size > maxSizeBytes) {
|
|
4634
|
+
return {
|
|
4635
|
+
valid: false,
|
|
4636
|
+
error: `${file.name} exceeds ${config.maxSizeMB}MB limit for ${config.label.toLowerCase()}`
|
|
4637
|
+
};
|
|
4638
|
+
}
|
|
4639
|
+
return { valid: true, category };
|
|
4640
|
+
}
|
|
4641
|
+
function formatFileSize2(bytes) {
|
|
4642
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
4643
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
4644
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
4645
|
+
}
|
|
4646
|
+
function getCategoryIcon(category) {
|
|
4647
|
+
switch (category) {
|
|
4648
|
+
case "document":
|
|
4649
|
+
return FileText;
|
|
4650
|
+
case "image":
|
|
4651
|
+
return ImageIcon2;
|
|
4652
|
+
case "audio":
|
|
4653
|
+
return Music;
|
|
4654
|
+
default:
|
|
4655
|
+
return FileIcon2;
|
|
4656
|
+
}
|
|
4657
|
+
}
|
|
4658
|
+
var FileDropZone = forwardRef(
|
|
4659
|
+
function FileDropZone2({
|
|
4660
|
+
onFilesChange,
|
|
4661
|
+
files,
|
|
4662
|
+
onUpload,
|
|
4663
|
+
onConfirmUpload,
|
|
4664
|
+
onError,
|
|
4665
|
+
maxFiles = MAX_FILES_PER_DROP,
|
|
4666
|
+
maxTotalSizeMB = MAX_TOTAL_SIZE_MB,
|
|
4667
|
+
disabled = false,
|
|
4668
|
+
className,
|
|
4669
|
+
accept,
|
|
4670
|
+
compact = false,
|
|
4671
|
+
children
|
|
4672
|
+
}, ref) {
|
|
4673
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
4674
|
+
const fileInputRef = useRef(null);
|
|
4675
|
+
const dropZoneRef = useRef(null);
|
|
4676
|
+
const dragCounter = useRef(0);
|
|
4677
|
+
useImperativeHandle(
|
|
4678
|
+
ref,
|
|
4679
|
+
() => ({
|
|
4680
|
+
openFileDialog: () => {
|
|
4681
|
+
if (!disabled) {
|
|
4682
|
+
fileInputRef.current?.click();
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
}),
|
|
4686
|
+
[disabled]
|
|
4687
|
+
);
|
|
4688
|
+
const currentTotalSize = files.reduce((sum, f) => sum + f.file.size, 0);
|
|
4689
|
+
const uploadFile = useCallback(
|
|
4690
|
+
async (file, _tempId) => {
|
|
4691
|
+
const result = await onUpload(file, {
|
|
4692
|
+
filename: file.name,
|
|
4693
|
+
mimeType: file.type,
|
|
4694
|
+
size: file.size
|
|
4695
|
+
});
|
|
4696
|
+
if (result.uploadUrl) {
|
|
4697
|
+
const uploadResponse = await fetch(result.uploadUrl, {
|
|
4698
|
+
method: "PUT",
|
|
4699
|
+
body: file,
|
|
4700
|
+
headers: { "Content-Type": file.type }
|
|
4701
|
+
});
|
|
4702
|
+
if (!uploadResponse.ok) {
|
|
4703
|
+
throw new Error(`Upload failed: ${uploadResponse.statusText}`);
|
|
4704
|
+
}
|
|
4705
|
+
}
|
|
4706
|
+
if (onConfirmUpload) {
|
|
4707
|
+
await onConfirmUpload(result.uuid);
|
|
4708
|
+
}
|
|
4709
|
+
return result.uuid;
|
|
4710
|
+
},
|
|
4711
|
+
[onUpload, onConfirmUpload]
|
|
4712
|
+
);
|
|
4713
|
+
const handleFiles = useCallback(
|
|
4714
|
+
async (selectedFiles) => {
|
|
4715
|
+
if (disabled) return;
|
|
4716
|
+
if (files.length + selectedFiles.length > maxFiles) {
|
|
4717
|
+
onError?.(`Maximum ${maxFiles} files allowed`);
|
|
4718
|
+
return;
|
|
4719
|
+
}
|
|
4720
|
+
const validFiles = [];
|
|
4721
|
+
let newTotalSize = currentTotalSize;
|
|
4722
|
+
for (const file of selectedFiles) {
|
|
4723
|
+
const validation = validateFile(file);
|
|
4724
|
+
if (!validation.valid) {
|
|
4725
|
+
onError?.(validation.error);
|
|
4726
|
+
continue;
|
|
4727
|
+
}
|
|
4728
|
+
newTotalSize += file.size;
|
|
4729
|
+
if (newTotalSize > maxTotalSizeMB * 1024 * 1024) {
|
|
4730
|
+
onError?.(`Total upload size exceeds ${maxTotalSizeMB}MB`);
|
|
4731
|
+
break;
|
|
4732
|
+
}
|
|
4733
|
+
validFiles.push({ file, category: validation.category });
|
|
4734
|
+
}
|
|
4735
|
+
if (validFiles.length === 0) return;
|
|
4736
|
+
const processedFiles = [];
|
|
4737
|
+
for (const entry of validFiles) {
|
|
4738
|
+
if (entry.category === "image") {
|
|
4739
|
+
try {
|
|
4740
|
+
const compressed = await compressImage(entry.file);
|
|
4741
|
+
processedFiles.push({ file: compressed, category: entry.category });
|
|
4742
|
+
} catch (err) {
|
|
4743
|
+
console.warn("Image compression failed, using original:", err);
|
|
4744
|
+
processedFiles.push(entry);
|
|
4745
|
+
}
|
|
4746
|
+
} else {
|
|
4747
|
+
processedFiles.push(entry);
|
|
4748
|
+
}
|
|
4749
|
+
}
|
|
4750
|
+
const newAttachments = processedFiles.map(
|
|
4751
|
+
({ file, category }) => {
|
|
4752
|
+
const tempId = `temp-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
4753
|
+
return {
|
|
4754
|
+
uuid: tempId,
|
|
4755
|
+
file,
|
|
4756
|
+
status: "pending",
|
|
4757
|
+
progress: 0,
|
|
4758
|
+
category,
|
|
4759
|
+
previewUrl: category === "image" ? URL.createObjectURL(file) : void 0
|
|
4760
|
+
};
|
|
4761
|
+
}
|
|
4762
|
+
);
|
|
4763
|
+
let currentFiles = [...files, ...newAttachments];
|
|
4764
|
+
onFilesChange(currentFiles);
|
|
4765
|
+
for (const attachment of newAttachments) {
|
|
4766
|
+
try {
|
|
4767
|
+
currentFiles = currentFiles.map(
|
|
4768
|
+
(f) => f.uuid === attachment.uuid ? { ...f, status: "uploading", progress: 10 } : f
|
|
4769
|
+
);
|
|
4770
|
+
onFilesChange(currentFiles);
|
|
4771
|
+
const realUuid = await uploadFile(attachment.file, attachment.uuid);
|
|
4772
|
+
currentFiles = currentFiles.map(
|
|
4773
|
+
(f) => f.uuid === attachment.uuid ? {
|
|
4774
|
+
...f,
|
|
4775
|
+
uuid: realUuid,
|
|
4776
|
+
status: "ready",
|
|
4777
|
+
progress: 100,
|
|
4778
|
+
hasThumbnail: f.category === "image"
|
|
4779
|
+
} : f
|
|
4780
|
+
);
|
|
4781
|
+
onFilesChange(currentFiles);
|
|
4782
|
+
} catch (error) {
|
|
4783
|
+
console.error("Upload error:", error);
|
|
4784
|
+
currentFiles = currentFiles.map(
|
|
4785
|
+
(f) => f.uuid === attachment.uuid ? {
|
|
4786
|
+
...f,
|
|
4787
|
+
status: "error",
|
|
4788
|
+
error: error instanceof Error ? error.message : "Upload failed"
|
|
4789
|
+
} : f
|
|
4790
|
+
);
|
|
4791
|
+
onFilesChange(currentFiles);
|
|
4792
|
+
onError?.(`Failed to upload ${attachment.file.name}`);
|
|
4793
|
+
}
|
|
4794
|
+
}
|
|
4795
|
+
},
|
|
4796
|
+
[
|
|
4797
|
+
disabled,
|
|
4798
|
+
files,
|
|
4799
|
+
maxFiles,
|
|
4800
|
+
currentTotalSize,
|
|
4801
|
+
maxTotalSizeMB,
|
|
4802
|
+
onFilesChange,
|
|
4803
|
+
uploadFile,
|
|
4804
|
+
onError
|
|
4805
|
+
]
|
|
4806
|
+
);
|
|
4807
|
+
const handleRemove = useCallback(
|
|
4808
|
+
(uuid) => {
|
|
4809
|
+
const file = files.find((f) => f.uuid === uuid);
|
|
4810
|
+
if (file?.previewUrl) {
|
|
4811
|
+
URL.revokeObjectURL(file.previewUrl);
|
|
4812
|
+
}
|
|
4813
|
+
onFilesChange(files.filter((f) => f.uuid !== uuid));
|
|
4814
|
+
},
|
|
4815
|
+
[files, onFilesChange]
|
|
4816
|
+
);
|
|
4817
|
+
const handleRetry = useCallback(
|
|
4818
|
+
async (uuid) => {
|
|
4819
|
+
const attachment = files.find((f) => f.uuid === uuid);
|
|
4820
|
+
if (!attachment || attachment.status !== "error") return;
|
|
4821
|
+
let currentFiles = files.map(
|
|
4822
|
+
(f) => f.uuid === uuid ? { ...f, status: "pending", progress: 0, error: void 0 } : f
|
|
4823
|
+
);
|
|
4824
|
+
onFilesChange(currentFiles);
|
|
4825
|
+
try {
|
|
4826
|
+
currentFiles = currentFiles.map(
|
|
4827
|
+
(f) => f.uuid === uuid ? { ...f, status: "uploading", progress: 10 } : f
|
|
4828
|
+
);
|
|
4829
|
+
onFilesChange(currentFiles);
|
|
4830
|
+
const realUuid = await uploadFile(attachment.file, uuid);
|
|
4831
|
+
currentFiles = currentFiles.map(
|
|
4832
|
+
(f) => f.uuid === uuid ? {
|
|
4833
|
+
...f,
|
|
4834
|
+
uuid: realUuid,
|
|
4835
|
+
status: "ready",
|
|
4836
|
+
progress: 100,
|
|
4837
|
+
hasThumbnail: f.category === "image"
|
|
4838
|
+
} : f
|
|
4839
|
+
);
|
|
4840
|
+
onFilesChange(currentFiles);
|
|
4841
|
+
} catch (error) {
|
|
4842
|
+
console.error("Retry upload error:", error);
|
|
4843
|
+
currentFiles = currentFiles.map(
|
|
4844
|
+
(f) => f.uuid === uuid ? {
|
|
4845
|
+
...f,
|
|
4846
|
+
status: "error",
|
|
4847
|
+
error: error instanceof Error ? error.message : "Upload failed"
|
|
4848
|
+
} : f
|
|
4849
|
+
);
|
|
4850
|
+
onFilesChange(currentFiles);
|
|
4851
|
+
onError?.(`Failed to upload ${attachment.file.name}`);
|
|
4852
|
+
}
|
|
4853
|
+
},
|
|
4854
|
+
[files, onFilesChange, uploadFile, onError]
|
|
4855
|
+
);
|
|
4856
|
+
const hasDraggedFiles = useCallback((e) => {
|
|
4857
|
+
if (e.dataTransfer.types) {
|
|
4858
|
+
for (const type of e.dataTransfer.types) {
|
|
4859
|
+
if (type === "Files") return true;
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
return false;
|
|
4863
|
+
}, []);
|
|
4864
|
+
const handleDragEnter = useCallback(
|
|
4865
|
+
(e) => {
|
|
4866
|
+
e.preventDefault();
|
|
4867
|
+
e.stopPropagation();
|
|
4868
|
+
if (!hasDraggedFiles(e)) return;
|
|
4869
|
+
dragCounter.current++;
|
|
4870
|
+
if (!disabled && dragCounter.current === 1) {
|
|
4871
|
+
setIsDragging(true);
|
|
4872
|
+
}
|
|
4873
|
+
},
|
|
4874
|
+
[disabled, hasDraggedFiles]
|
|
4875
|
+
);
|
|
4876
|
+
const handleDragOver = useCallback(
|
|
4877
|
+
(e) => {
|
|
4878
|
+
e.preventDefault();
|
|
4879
|
+
e.stopPropagation();
|
|
4880
|
+
if (hasDraggedFiles(e)) {
|
|
4881
|
+
e.dataTransfer.dropEffect = disabled ? "none" : "copy";
|
|
4882
|
+
}
|
|
4883
|
+
},
|
|
4884
|
+
[disabled, hasDraggedFiles]
|
|
4885
|
+
);
|
|
4886
|
+
const handleDragLeave = useCallback((e) => {
|
|
4887
|
+
e.preventDefault();
|
|
4888
|
+
e.stopPropagation();
|
|
4889
|
+
if (dragCounter.current > 0) {
|
|
4890
|
+
dragCounter.current--;
|
|
4891
|
+
if (dragCounter.current === 0) {
|
|
4892
|
+
setIsDragging(false);
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
4895
|
+
}, []);
|
|
4896
|
+
const handleDrop = useCallback(
|
|
4897
|
+
(e) => {
|
|
4898
|
+
e.preventDefault();
|
|
4899
|
+
e.stopPropagation();
|
|
4900
|
+
dragCounter.current = 0;
|
|
4901
|
+
setIsDragging(false);
|
|
4902
|
+
if (disabled) return;
|
|
4903
|
+
const droppedFiles = Array.from(e.dataTransfer.files);
|
|
4904
|
+
if (droppedFiles.length > 0) {
|
|
4905
|
+
handleFiles(droppedFiles);
|
|
4906
|
+
}
|
|
4907
|
+
},
|
|
4908
|
+
[handleFiles, disabled]
|
|
4909
|
+
);
|
|
4910
|
+
const handleFileSelect = useCallback(
|
|
4911
|
+
(e) => {
|
|
4912
|
+
const selectedFiles = e.target.files;
|
|
4913
|
+
if (selectedFiles) {
|
|
4914
|
+
handleFiles(Array.from(selectedFiles));
|
|
4915
|
+
}
|
|
4916
|
+
if (fileInputRef.current) {
|
|
4917
|
+
fileInputRef.current.value = "";
|
|
4918
|
+
}
|
|
4919
|
+
},
|
|
4920
|
+
[handleFiles]
|
|
4921
|
+
);
|
|
4922
|
+
const handleClick = useCallback(() => {
|
|
4923
|
+
if (!disabled) {
|
|
4924
|
+
fileInputRef.current?.click();
|
|
4925
|
+
}
|
|
4926
|
+
}, [disabled]);
|
|
4927
|
+
const checkDataTransferHasFiles = useCallback(
|
|
4928
|
+
(dataTransfer) => {
|
|
4929
|
+
if (!dataTransfer?.types) return false;
|
|
4930
|
+
for (let i = 0; i < dataTransfer.types.length; i++) {
|
|
4931
|
+
if (dataTransfer.types[i] === "Files") return true;
|
|
4932
|
+
}
|
|
4933
|
+
return false;
|
|
4934
|
+
},
|
|
4935
|
+
[]
|
|
4936
|
+
);
|
|
4937
|
+
useEffect(() => {
|
|
4938
|
+
if (!children || !dropZoneRef.current) return;
|
|
4939
|
+
const element = dropZoneRef.current;
|
|
4940
|
+
let enterCounter = 0;
|
|
4941
|
+
const handleDragEnterNative = (e) => {
|
|
4942
|
+
e.preventDefault();
|
|
4943
|
+
e.stopPropagation();
|
|
4944
|
+
if (!checkDataTransferHasFiles(e.dataTransfer)) return;
|
|
4945
|
+
enterCounter++;
|
|
4946
|
+
if (enterCounter === 1 && !disabled) {
|
|
4947
|
+
setIsDragging(true);
|
|
4948
|
+
}
|
|
4949
|
+
};
|
|
4950
|
+
const handleDragLeaveNative = (e) => {
|
|
4951
|
+
e.preventDefault();
|
|
4952
|
+
e.stopPropagation();
|
|
4953
|
+
if (!checkDataTransferHasFiles(e.dataTransfer)) return;
|
|
4954
|
+
enterCounter--;
|
|
4955
|
+
if (enterCounter <= 0) {
|
|
4956
|
+
enterCounter = 0;
|
|
4957
|
+
setIsDragging(false);
|
|
4958
|
+
}
|
|
4959
|
+
};
|
|
4960
|
+
const handleDragOverNative = (e) => {
|
|
4961
|
+
e.preventDefault();
|
|
4962
|
+
e.stopPropagation();
|
|
4963
|
+
if (checkDataTransferHasFiles(e.dataTransfer) && !disabled && e.dataTransfer) {
|
|
4964
|
+
e.dataTransfer.dropEffect = "copy";
|
|
4965
|
+
}
|
|
4966
|
+
};
|
|
4967
|
+
const handleDropNative = (e) => {
|
|
4968
|
+
e.preventDefault();
|
|
4969
|
+
e.stopPropagation();
|
|
4970
|
+
enterCounter = 0;
|
|
4971
|
+
setIsDragging(false);
|
|
4972
|
+
if (disabled) return;
|
|
4973
|
+
const droppedFiles = e.dataTransfer?.files;
|
|
4974
|
+
if (droppedFiles && droppedFiles.length > 0) {
|
|
4975
|
+
handleFiles(Array.from(droppedFiles));
|
|
4976
|
+
}
|
|
4977
|
+
};
|
|
4978
|
+
element.addEventListener("dragenter", handleDragEnterNative, true);
|
|
4979
|
+
element.addEventListener("dragleave", handleDragLeaveNative, true);
|
|
4980
|
+
element.addEventListener("dragover", handleDragOverNative, true);
|
|
4981
|
+
element.addEventListener("drop", handleDropNative, true);
|
|
4982
|
+
return () => {
|
|
4983
|
+
element.removeEventListener("dragenter", handleDragEnterNative, true);
|
|
4984
|
+
element.removeEventListener("dragleave", handleDragLeaveNative, true);
|
|
4985
|
+
element.removeEventListener("dragover", handleDragOverNative, true);
|
|
4986
|
+
element.removeEventListener("drop", handleDropNative, true);
|
|
4987
|
+
};
|
|
4988
|
+
}, [children, disabled, handleFiles, checkDataTransferHasFiles]);
|
|
4989
|
+
useEffect(() => {
|
|
4990
|
+
if (disabled) {
|
|
4991
|
+
dragCounter.current = 0;
|
|
4992
|
+
setIsDragging(false);
|
|
4993
|
+
}
|
|
4994
|
+
}, [disabled]);
|
|
4995
|
+
const acceptTypes = accept || Object.values(SUPPORTED_TYPES).flatMap((t) => [...t.mimeTypes, ...t.extensions]).join(",");
|
|
4996
|
+
const hasFiles = files.length > 0;
|
|
4997
|
+
const isUploading = files.some((f) => f.status === "uploading");
|
|
4998
|
+
if (children) {
|
|
4999
|
+
return /* @__PURE__ */ jsxs(
|
|
5000
|
+
"div",
|
|
5001
|
+
{
|
|
5002
|
+
ref: dropZoneRef,
|
|
5003
|
+
"data-dropzone": "wrapper",
|
|
5004
|
+
className: cn4("relative w-full h-full", className),
|
|
5005
|
+
style: { minHeight: "inherit" },
|
|
5006
|
+
children: [
|
|
5007
|
+
/* @__PURE__ */ jsx(
|
|
5008
|
+
"input",
|
|
5009
|
+
{
|
|
5010
|
+
ref: fileInputRef,
|
|
5011
|
+
type: "file",
|
|
5012
|
+
multiple: true,
|
|
5013
|
+
accept: acceptTypes,
|
|
5014
|
+
onChange: handleFileSelect,
|
|
5015
|
+
className: "hidden",
|
|
5016
|
+
disabled
|
|
5017
|
+
}
|
|
5018
|
+
),
|
|
5019
|
+
children,
|
|
5020
|
+
isDragging && !disabled && /* @__PURE__ */ jsx(
|
|
5021
|
+
"div",
|
|
5022
|
+
{
|
|
5023
|
+
className: "absolute inset-0 z-50 bg-primary/10 border-2 border-dashed border-primary rounded-xl flex flex-col items-center justify-center backdrop-blur-sm transition-opacity duration-200",
|
|
5024
|
+
style: { pointerEvents: "none" },
|
|
5025
|
+
children: /* @__PURE__ */ jsxs("div", { className: "bg-background/80 rounded-xl p-8 flex flex-col items-center shadow-lg", children: [
|
|
5026
|
+
/* @__PURE__ */ jsx(Upload, { className: "h-12 w-12 text-primary mb-4 animate-bounce" }),
|
|
5027
|
+
/* @__PURE__ */ jsx("p", { className: "text-lg font-medium text-primary", children: "Drop files here" }),
|
|
5028
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-2", children: "Documents, images, or audio files" })
|
|
5029
|
+
] })
|
|
5030
|
+
}
|
|
5031
|
+
)
|
|
5032
|
+
]
|
|
5033
|
+
}
|
|
5034
|
+
);
|
|
5035
|
+
}
|
|
5036
|
+
return /* @__PURE__ */ jsxs("div", { className: cn4("w-full", className), children: [
|
|
5037
|
+
/* @__PURE__ */ jsx(
|
|
5038
|
+
"input",
|
|
5039
|
+
{
|
|
5040
|
+
ref: fileInputRef,
|
|
5041
|
+
type: "file",
|
|
5042
|
+
multiple: true,
|
|
5043
|
+
accept: acceptTypes,
|
|
5044
|
+
onChange: handleFileSelect,
|
|
5045
|
+
className: "hidden",
|
|
5046
|
+
disabled
|
|
5047
|
+
}
|
|
5048
|
+
),
|
|
5049
|
+
/* @__PURE__ */ jsxs(
|
|
5050
|
+
"div",
|
|
5051
|
+
{
|
|
5052
|
+
onDragEnter: handleDragEnter,
|
|
5053
|
+
onDragOver: handleDragOver,
|
|
5054
|
+
onDragLeave: handleDragLeave,
|
|
5055
|
+
onDrop: handleDrop,
|
|
5056
|
+
onClick: handleClick,
|
|
5057
|
+
className: cn4(
|
|
5058
|
+
"relative rounded-lg border-2 border-dashed transition-all cursor-pointer",
|
|
5059
|
+
"flex flex-col items-center justify-center",
|
|
5060
|
+
compact ? "p-2 min-h-[60px]" : "p-4 min-h-[100px]",
|
|
5061
|
+
isDragging && !disabled ? "border-primary bg-primary/5" : "border-muted-foreground/25",
|
|
5062
|
+
disabled ? "opacity-50 cursor-not-allowed" : "hover:border-primary/50 hover:bg-muted/25"
|
|
5063
|
+
),
|
|
5064
|
+
children: [
|
|
5065
|
+
isUploading ? /* @__PURE__ */ jsx(
|
|
5066
|
+
Loader2,
|
|
5067
|
+
{
|
|
5068
|
+
className: cn4(
|
|
5069
|
+
"animate-spin text-muted-foreground",
|
|
5070
|
+
compact ? "h-5 w-5 mb-1" : "h-8 w-8 mb-2"
|
|
5071
|
+
)
|
|
5072
|
+
}
|
|
5073
|
+
) : /* @__PURE__ */ jsx(
|
|
5074
|
+
Upload,
|
|
5075
|
+
{
|
|
5076
|
+
className: cn4(
|
|
5077
|
+
"text-muted-foreground",
|
|
5078
|
+
compact ? "h-5 w-5 mb-1" : "h-8 w-8 mb-2"
|
|
5079
|
+
)
|
|
5080
|
+
}
|
|
5081
|
+
),
|
|
5082
|
+
/* @__PURE__ */ jsx(
|
|
5083
|
+
"p",
|
|
5084
|
+
{
|
|
5085
|
+
className: cn4(
|
|
5086
|
+
"font-medium text-center text-muted-foreground",
|
|
5087
|
+
compact ? "text-xs" : "text-sm"
|
|
5088
|
+
),
|
|
5089
|
+
children: isDragging ? "Drop files here" : isUploading ? "Uploading..." : "Click to upload or drag and drop"
|
|
5090
|
+
}
|
|
5091
|
+
),
|
|
5092
|
+
!compact && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground/70 text-center mt-1", children: "Documents, images, or audio files" })
|
|
5093
|
+
]
|
|
5094
|
+
}
|
|
5095
|
+
),
|
|
5096
|
+
hasFiles && /* @__PURE__ */ jsx("div", { className: cn4("space-y-2", compact ? "mt-2" : "mt-3"), children: files.map((attachment) => {
|
|
5097
|
+
const Icon = getCategoryIcon(attachment.category);
|
|
5098
|
+
const isError = attachment.status === "error";
|
|
5099
|
+
const isLoading = attachment.status === "uploading" || attachment.status === "processing";
|
|
5100
|
+
return /* @__PURE__ */ jsxs(
|
|
5101
|
+
"div",
|
|
5102
|
+
{
|
|
5103
|
+
className: cn4(
|
|
5104
|
+
"flex items-center gap-3 p-2 rounded-lg border",
|
|
5105
|
+
isError ? "border-destructive/50 bg-destructive/5" : "border-border bg-muted/25"
|
|
5106
|
+
),
|
|
5107
|
+
children: [
|
|
5108
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-shrink-0 w-10 h-10 rounded overflow-hidden bg-muted flex items-center justify-center", children: [
|
|
5109
|
+
attachment.previewUrl ? /* @__PURE__ */ jsx(
|
|
5110
|
+
"img",
|
|
5111
|
+
{
|
|
5112
|
+
src: attachment.previewUrl,
|
|
5113
|
+
alt: attachment.file.name,
|
|
5114
|
+
className: "w-full h-full object-cover"
|
|
5115
|
+
}
|
|
5116
|
+
) : /* @__PURE__ */ jsx(Icon, { className: "h-5 w-5 text-muted-foreground" }),
|
|
5117
|
+
isLoading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-background/80 flex items-center justify-center", children: /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) })
|
|
5118
|
+
] }),
|
|
5119
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
5120
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: attachment.file.name }),
|
|
5121
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
5122
|
+
formatFileSize2(attachment.file.size),
|
|
5123
|
+
isError && attachment.error && /* @__PURE__ */ jsx("span", { className: "text-destructive ml-2", children: attachment.error })
|
|
5124
|
+
] })
|
|
5125
|
+
] }),
|
|
5126
|
+
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: isLoading ? /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
5127
|
+
attachment.progress,
|
|
5128
|
+
"%"
|
|
5129
|
+
] }) : attachment.status === "ready" ? /* @__PURE__ */ jsx("span", { className: "text-xs text-green-600", children: "Ready" }) : null }),
|
|
5130
|
+
isError && /* @__PURE__ */ jsx(
|
|
5131
|
+
"button",
|
|
5132
|
+
{
|
|
5133
|
+
type: "button",
|
|
5134
|
+
className: "flex-shrink-0 h-8 w-8 inline-flex items-center justify-center rounded-md text-primary hover:bg-muted transition-colors",
|
|
5135
|
+
onClick: (e) => {
|
|
5136
|
+
e.stopPropagation();
|
|
5137
|
+
handleRetry(attachment.uuid);
|
|
5138
|
+
},
|
|
5139
|
+
title: "Retry upload",
|
|
5140
|
+
children: /* @__PURE__ */ jsx(RotateCw, { className: "h-4 w-4" })
|
|
5141
|
+
}
|
|
5142
|
+
),
|
|
5143
|
+
/* @__PURE__ */ jsx(
|
|
5144
|
+
"button",
|
|
5145
|
+
{
|
|
5146
|
+
type: "button",
|
|
5147
|
+
className: "flex-shrink-0 h-8 w-8 inline-flex items-center justify-center rounded-md hover:bg-muted transition-colors disabled:opacity-50",
|
|
5148
|
+
onClick: (e) => {
|
|
5149
|
+
e.stopPropagation();
|
|
5150
|
+
handleRemove(attachment.uuid);
|
|
5151
|
+
},
|
|
5152
|
+
disabled: isLoading,
|
|
5153
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
5154
|
+
}
|
|
5155
|
+
)
|
|
5156
|
+
]
|
|
5157
|
+
},
|
|
5158
|
+
attachment.uuid
|
|
5159
|
+
);
|
|
5160
|
+
}) })
|
|
5161
|
+
] });
|
|
5162
|
+
}
|
|
5163
|
+
);
|
|
5164
|
+
function cn5(...classes) {
|
|
5165
|
+
return classes.filter(Boolean).join(" ");
|
|
5166
|
+
}
|
|
4191
5167
|
function AskUserPrompt({
|
|
4192
5168
|
question,
|
|
4193
5169
|
options,
|
|
@@ -4221,7 +5197,7 @@ function AskUserPrompt({
|
|
|
4221
5197
|
return /* @__PURE__ */ jsxs(
|
|
4222
5198
|
"div",
|
|
4223
5199
|
{
|
|
4224
|
-
className:
|
|
5200
|
+
className: cn5(
|
|
4225
5201
|
"rounded-lg border p-4 space-y-3",
|
|
4226
5202
|
status === "waiting" ? "border-blue-200 bg-blue-50/50 dark:border-blue-800 dark:bg-blue-950/20" : "border-green-200 bg-green-50/50 dark:border-green-800 dark:bg-green-950/20",
|
|
4227
5203
|
className
|
|
@@ -4233,7 +5209,7 @@ function AskUserPrompt({
|
|
|
4233
5209
|
/* @__PURE__ */ jsx(
|
|
4234
5210
|
"span",
|
|
4235
5211
|
{
|
|
4236
|
-
className:
|
|
5212
|
+
className: cn5(
|
|
4237
5213
|
"ml-auto text-xs px-2 py-1 rounded-full font-medium",
|
|
4238
5214
|
status === "waiting" ? "bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300" : "bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300"
|
|
4239
5215
|
),
|
|
@@ -4248,7 +5224,7 @@ function AskUserPrompt({
|
|
|
4248
5224
|
type: "button",
|
|
4249
5225
|
onClick: () => handleOptionSelect(option),
|
|
4250
5226
|
disabled,
|
|
4251
|
-
className:
|
|
5227
|
+
className: cn5(
|
|
4252
5228
|
"px-3 py-1.5 text-sm rounded-md border transition-all",
|
|
4253
5229
|
selectedOption === option ? "bg-blue-600 text-white border-blue-600 hover:bg-blue-700" : "bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300",
|
|
4254
5230
|
disabled && "opacity-50 cursor-not-allowed"
|
|
@@ -4268,7 +5244,7 @@ function AskUserPrompt({
|
|
|
4268
5244
|
},
|
|
4269
5245
|
onKeyDown: handleKeyDown,
|
|
4270
5246
|
placeholder: options?.length ? "Or type a custom response..." : "Type your response...",
|
|
4271
|
-
className:
|
|
5247
|
+
className: cn5(
|
|
4272
5248
|
"flex-1 min-h-[60px] px-3 py-2 text-sm resize-none rounded-md border",
|
|
4273
5249
|
"border-gray-300 dark:border-gray-600",
|
|
4274
5250
|
"bg-white dark:bg-gray-800",
|
|
@@ -4286,7 +5262,7 @@ function AskUserPrompt({
|
|
|
4286
5262
|
type: "button",
|
|
4287
5263
|
onClick: handleSubmit,
|
|
4288
5264
|
disabled: isSubmitDisabled,
|
|
4289
|
-
className:
|
|
5265
|
+
className: cn5(
|
|
4290
5266
|
"self-end px-4 py-2 rounded-md text-white transition-colors",
|
|
4291
5267
|
"bg-blue-600 hover:bg-blue-700",
|
|
4292
5268
|
"disabled:opacity-50 disabled:cursor-not-allowed"
|
|
@@ -4307,7 +5283,7 @@ function AskUserPrompt({
|
|
|
4307
5283
|
}
|
|
4308
5284
|
);
|
|
4309
5285
|
}
|
|
4310
|
-
function
|
|
5286
|
+
function cn6(...classes) {
|
|
4311
5287
|
return classes.filter(Boolean).join(" ");
|
|
4312
5288
|
}
|
|
4313
5289
|
function MarkdownContent({
|
|
@@ -4368,7 +5344,7 @@ function MarkdownContent({
|
|
|
4368
5344
|
if (isCodeBlock) {
|
|
4369
5345
|
return /* @__PURE__ */ jsxs("div", { className: "relative my-2", children: [
|
|
4370
5346
|
language && /* @__PURE__ */ jsx("div", { className: "absolute top-0 right-0 px-2 py-1 text-xs font-mono text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-800 rounded-bl rounded-tr border-b border-l border-gray-200 dark:border-gray-700", children: language }),
|
|
4371
|
-
/* @__PURE__ */ jsx("pre", { className: "bg-gray-100 dark:bg-gray-800 rounded-lg p-4 overflow-x-auto text-sm", children: /* @__PURE__ */ jsx("code", { className:
|
|
5347
|
+
/* @__PURE__ */ jsx("pre", { className: "bg-gray-100 dark:bg-gray-800 rounded-lg p-4 overflow-x-auto text-sm", children: /* @__PURE__ */ jsx("code", { className: cn6("font-mono", codeClassName), ...props, children }) })
|
|
4372
5348
|
] });
|
|
4373
5349
|
}
|
|
4374
5350
|
return /* @__PURE__ */ jsx(
|
|
@@ -4415,7 +5391,7 @@ function MarkdownContent({
|
|
|
4415
5391
|
() => customComponents ? { ...defaultComponents, ...customComponents } : defaultComponents,
|
|
4416
5392
|
[defaultComponents, customComponents]
|
|
4417
5393
|
);
|
|
4418
|
-
return /* @__PURE__ */ jsx("div", { className:
|
|
5394
|
+
return /* @__PURE__ */ jsx("div", { className: cn6("prose prose-sm dark:prose-invert max-w-none", className), children: /* @__PURE__ */ jsx(
|
|
4419
5395
|
ReactMarkdown,
|
|
4420
5396
|
{
|
|
4421
5397
|
remarkPlugins: [remarkGfm],
|
|
@@ -4425,7 +5401,7 @@ function MarkdownContent({
|
|
|
4425
5401
|
}
|
|
4426
5402
|
) });
|
|
4427
5403
|
}
|
|
4428
|
-
function
|
|
5404
|
+
function cn7(...classes) {
|
|
4429
5405
|
return classes.filter(Boolean).join(" ");
|
|
4430
5406
|
}
|
|
4431
5407
|
function formatToolName(toolName) {
|
|
@@ -4573,7 +5549,7 @@ function ToolCallEntry({
|
|
|
4573
5549
|
return /* @__PURE__ */ jsxs(
|
|
4574
5550
|
"div",
|
|
4575
5551
|
{
|
|
4576
|
-
className:
|
|
5552
|
+
className: cn7(
|
|
4577
5553
|
"rounded-lg border text-sm",
|
|
4578
5554
|
statusColor,
|
|
4579
5555
|
className
|
|
@@ -4594,7 +5570,7 @@ function ToolCallEntry({
|
|
|
4594
5570
|
]
|
|
4595
5571
|
}
|
|
4596
5572
|
),
|
|
4597
|
-
hasImages && /* @__PURE__ */ jsx("div", { className: "px-3 pb-2", children: /* @__PURE__ */ jsx("div", { className:
|
|
5573
|
+
hasImages && /* @__PURE__ */ jsx("div", { className: "px-3 pb-2", children: /* @__PURE__ */ jsx("div", { className: cn7(
|
|
4598
5574
|
"grid gap-2",
|
|
4599
5575
|
resultImages.length === 1 ? "grid-cols-1" : "grid-cols-2"
|
|
4600
5576
|
), children: resultImages.map((img, idx) => {
|
|
@@ -4653,7 +5629,7 @@ function ToolCallEntry({
|
|
|
4653
5629
|
}
|
|
4654
5630
|
);
|
|
4655
5631
|
}
|
|
4656
|
-
function
|
|
5632
|
+
function cn8(...classes) {
|
|
4657
5633
|
return classes.filter(Boolean).join(" ");
|
|
4658
5634
|
}
|
|
4659
5635
|
function ChatMessage({
|
|
@@ -4675,7 +5651,7 @@ function ChatMessage({
|
|
|
4675
5651
|
return /* @__PURE__ */ jsxs(
|
|
4676
5652
|
"div",
|
|
4677
5653
|
{
|
|
4678
|
-
className:
|
|
5654
|
+
className: cn8(
|
|
4679
5655
|
"flex gap-3 p-4",
|
|
4680
5656
|
isUser ? "flex-row-reverse" : "flex-row",
|
|
4681
5657
|
className
|
|
@@ -4684,7 +5660,7 @@ function ChatMessage({
|
|
|
4684
5660
|
/* @__PURE__ */ jsx(
|
|
4685
5661
|
"div",
|
|
4686
5662
|
{
|
|
4687
|
-
className:
|
|
5663
|
+
className: cn8(
|
|
4688
5664
|
"flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center",
|
|
4689
5665
|
isUser ? "bg-blue-500 text-white" : "bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-300"
|
|
4690
5666
|
),
|
|
@@ -4694,7 +5670,7 @@ function ChatMessage({
|
|
|
4694
5670
|
/* @__PURE__ */ jsxs(
|
|
4695
5671
|
"div",
|
|
4696
5672
|
{
|
|
4697
|
-
className:
|
|
5673
|
+
className: cn8(
|
|
4698
5674
|
"flex-1 min-w-0 space-y-2",
|
|
4699
5675
|
isUser ? "text-right" : "text-left"
|
|
4700
5676
|
),
|
|
@@ -4702,7 +5678,7 @@ function ChatMessage({
|
|
|
4702
5678
|
/* @__PURE__ */ jsxs(
|
|
4703
5679
|
"div",
|
|
4704
5680
|
{
|
|
4705
|
-
className:
|
|
5681
|
+
className: cn8(
|
|
4706
5682
|
"flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400",
|
|
4707
5683
|
isUser ? "justify-end" : "justify-start"
|
|
4708
5684
|
),
|
|
@@ -4735,7 +5711,7 @@ function ChatMessage({
|
|
|
4735
5711
|
message.content && /* @__PURE__ */ jsx(
|
|
4736
5712
|
"div",
|
|
4737
5713
|
{
|
|
4738
|
-
className:
|
|
5714
|
+
className: cn8(
|
|
4739
5715
|
"rounded-lg p-3",
|
|
4740
5716
|
isUser ? "bg-blue-500 text-white" : "bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100"
|
|
4741
5717
|
),
|
|
@@ -4765,7 +5741,7 @@ function ChatMessage({
|
|
|
4765
5741
|
}
|
|
4766
5742
|
);
|
|
4767
5743
|
}
|
|
4768
|
-
function
|
|
5744
|
+
function cn9(...classes) {
|
|
4769
5745
|
return classes.filter(Boolean).join(" ");
|
|
4770
5746
|
}
|
|
4771
5747
|
function MessageList({
|
|
@@ -4795,7 +5771,7 @@ function MessageList({
|
|
|
4795
5771
|
"div",
|
|
4796
5772
|
{
|
|
4797
5773
|
ref: scrollRef,
|
|
4798
|
-
className:
|
|
5774
|
+
className: cn9(
|
|
4799
5775
|
"flex-1 overflow-y-auto",
|
|
4800
5776
|
className
|
|
4801
5777
|
),
|
|
@@ -4888,6 +5864,7 @@ function AgentChat({
|
|
|
4888
5864
|
isStreaming,
|
|
4889
5865
|
isLoadingHistory,
|
|
4890
5866
|
error,
|
|
5867
|
+
sessionId: currentSessionId,
|
|
4891
5868
|
clarification,
|
|
4892
5869
|
sendMessage,
|
|
4893
5870
|
respondToClarification,
|
|
@@ -4908,8 +5885,59 @@ function AgentChat({
|
|
|
4908
5885
|
onToolResult,
|
|
4909
5886
|
onClarification
|
|
4910
5887
|
});
|
|
5888
|
+
const dropZoneRef = useRef(null);
|
|
5889
|
+
const attachments = useFileAttachments({
|
|
5890
|
+
onUpload: enableAttachments && adapter ? async (_file, meta) => {
|
|
5891
|
+
const result = await adapter.getUploadUrl({
|
|
5892
|
+
sessionId: currentSessionId ?? "",
|
|
5893
|
+
...meta
|
|
5894
|
+
});
|
|
5895
|
+
return { uuid: result.attachmentUuid, uploadUrl: result.uploadUrl };
|
|
5896
|
+
} : async () => ({ uuid: "", uploadUrl: "" }),
|
|
5897
|
+
onConfirmUpload: enableAttachments && adapter ? (uuid) => adapter.confirmUpload(uuid) : void 0,
|
|
5898
|
+
onError: (msg) => {
|
|
5899
|
+
console.error("[AgentChat] Attachment error:", msg);
|
|
5900
|
+
}
|
|
5901
|
+
});
|
|
5902
|
+
const handleSend = useCallback(
|
|
5903
|
+
async (content) => {
|
|
5904
|
+
if (enableAttachments && attachments.hasReadyFiles) {
|
|
5905
|
+
const uuids = attachments.getReadyUuids();
|
|
5906
|
+
await sendMessage(content, { attachmentUuids: uuids });
|
|
5907
|
+
attachments.clear();
|
|
5908
|
+
} else {
|
|
5909
|
+
await sendMessage(content);
|
|
5910
|
+
}
|
|
5911
|
+
},
|
|
5912
|
+
[enableAttachments, attachments, sendMessage]
|
|
5913
|
+
);
|
|
4911
5914
|
return /* @__PURE__ */ jsxs(ChatContainer, { maxHeight, className, theme, children: [
|
|
4912
|
-
/* @__PURE__ */ jsx(
|
|
5915
|
+
enableAttachments ? /* @__PURE__ */ jsx(
|
|
5916
|
+
FileDropZone,
|
|
5917
|
+
{
|
|
5918
|
+
ref: dropZoneRef,
|
|
5919
|
+
...attachments.dropZoneProps,
|
|
5920
|
+
disabled: isLoading || !!clarification || isLoadingHistory,
|
|
5921
|
+
children: /* @__PURE__ */ jsx(
|
|
5922
|
+
MessageList,
|
|
5923
|
+
{
|
|
5924
|
+
messages,
|
|
5925
|
+
welcomeMessage,
|
|
5926
|
+
renderWelcome,
|
|
5927
|
+
isLoading,
|
|
5928
|
+
isStreaming,
|
|
5929
|
+
isLoadingHistory,
|
|
5930
|
+
enableMarkdown,
|
|
5931
|
+
showToolCalls,
|
|
5932
|
+
markdownComponents,
|
|
5933
|
+
markdownUrlTransform,
|
|
5934
|
+
markdownContentTransform,
|
|
5935
|
+
onImageClick,
|
|
5936
|
+
sendMessage: handleSend
|
|
5937
|
+
}
|
|
5938
|
+
)
|
|
5939
|
+
}
|
|
5940
|
+
) : /* @__PURE__ */ jsx(
|
|
4913
5941
|
MessageList,
|
|
4914
5942
|
{
|
|
4915
5943
|
messages,
|
|
@@ -4924,7 +5952,7 @@ function AgentChat({
|
|
|
4924
5952
|
markdownUrlTransform,
|
|
4925
5953
|
markdownContentTransform,
|
|
4926
5954
|
onImageClick,
|
|
4927
|
-
sendMessage
|
|
5955
|
+
sendMessage: handleSend
|
|
4928
5956
|
}
|
|
4929
5957
|
),
|
|
4930
5958
|
clarification && /* @__PURE__ */ jsx("div", { className: "border-t border-gray-200 dark:border-gray-700 p-4", children: /* @__PURE__ */ jsx(
|
|
@@ -4939,17 +5967,21 @@ function AgentChat({
|
|
|
4939
5967
|
/* @__PURE__ */ jsx(
|
|
4940
5968
|
ChatInput,
|
|
4941
5969
|
{
|
|
4942
|
-
onSend:
|
|
5970
|
+
onSend: handleSend,
|
|
4943
5971
|
onStop: isStreaming ? cancel : void 0,
|
|
4944
5972
|
placeholder,
|
|
4945
5973
|
disabled: !!clarification || isLoadingHistory,
|
|
4946
5974
|
isLoading,
|
|
4947
|
-
enableAttachments
|
|
5975
|
+
enableAttachments,
|
|
5976
|
+
attachments: enableAttachments ? attachments.files : void 0,
|
|
5977
|
+
onRemoveAttachment: enableAttachments ? attachments.removeFile : void 0,
|
|
5978
|
+
dropZoneRef: enableAttachments ? dropZoneRef : void 0,
|
|
5979
|
+
isUploadingAttachments: enableAttachments ? attachments.isUploading : void 0
|
|
4948
5980
|
}
|
|
4949
5981
|
)
|
|
4950
5982
|
] });
|
|
4951
5983
|
}
|
|
4952
|
-
function
|
|
5984
|
+
function cn10(...classes) {
|
|
4953
5985
|
return classes.filter(Boolean).join(" ");
|
|
4954
5986
|
}
|
|
4955
5987
|
function TodoList({
|
|
@@ -4978,7 +6010,7 @@ function TodoList({
|
|
|
4978
6010
|
return /* @__PURE__ */ jsxs(
|
|
4979
6011
|
"div",
|
|
4980
6012
|
{
|
|
4981
|
-
className:
|
|
6013
|
+
className: cn10(
|
|
4982
6014
|
"rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden",
|
|
4983
6015
|
className
|
|
4984
6016
|
),
|
|
@@ -4986,7 +6018,7 @@ function TodoList({
|
|
|
4986
6018
|
/* @__PURE__ */ jsxs(
|
|
4987
6019
|
"div",
|
|
4988
6020
|
{
|
|
4989
|
-
className:
|
|
6021
|
+
className: cn10(
|
|
4990
6022
|
"flex items-center gap-2 px-3 py-2 bg-gray-50 dark:bg-gray-800/50",
|
|
4991
6023
|
collapsible && "cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800"
|
|
4992
6024
|
),
|
|
@@ -5017,7 +6049,7 @@ function TodoList({
|
|
|
5017
6049
|
!isCollapsed && /* @__PURE__ */ jsx("ul", { className: "divide-y divide-gray-100 dark:divide-gray-700", children: todos.map((todo, idx) => /* @__PURE__ */ jsxs(
|
|
5018
6050
|
"li",
|
|
5019
6051
|
{
|
|
5020
|
-
className:
|
|
6052
|
+
className: cn10(
|
|
5021
6053
|
"px-3 py-2 flex items-start gap-2 text-sm",
|
|
5022
6054
|
todo.status === "in_progress" && "bg-blue-50/50 dark:bg-blue-950/20",
|
|
5023
6055
|
todo.status === "completed" && "opacity-60"
|
|
@@ -5027,7 +6059,7 @@ function TodoList({
|
|
|
5027
6059
|
/* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(
|
|
5028
6060
|
"p",
|
|
5029
6061
|
{
|
|
5030
|
-
className:
|
|
6062
|
+
className: cn10(
|
|
5031
6063
|
"text-gray-700 dark:text-gray-300",
|
|
5032
6064
|
todo.status === "completed" && "line-through"
|
|
5033
6065
|
),
|
|
@@ -5044,6 +6076,6 @@ function TodoList({
|
|
|
5044
6076
|
);
|
|
5045
6077
|
}
|
|
5046
6078
|
|
|
5047
|
-
export { AgentChat, AlertCircleIcon, AskUserPrompt, BotIcon, ChatConfigProvider, ChatContainer, ChatInput, ChatMessage, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, CircleIcon, ClockIcon, CodeIcon, CopyIcon, DatabaseIcon, DownloadIcon, ExternalLinkIcon, FileIcon, FileTextIcon, HelpCircleIcon, ImageIcon, ImagesIcon, ListTodoIcon, LoadingSpinner, MarkdownContent, Maximize2Icon, MessageCircleIcon, MessageList, Minimize2Icon, PaperclipIcon, SendIcon, SparklesIcon, StopCircleIcon, TodoList, ToolCallEntry, UserIcon, XIcon, ZoomInIcon, ZoomOutIcon, createDefaultAdapter, useAgentChat, useChatConfig, useChatConfigOptional, useExecutionStream };
|
|
6079
|
+
export { AgentChat, AlertCircleIcon, AskUserPrompt, BotIcon, ChatConfigProvider, ChatContainer, ChatInput, ChatMessage, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, CircleIcon, ClockIcon, CodeIcon, CopyIcon, DatabaseIcon, DownloadIcon, ExternalLinkIcon, FileDropZone, FileIcon, FileTextIcon, HelpCircleIcon, ImageIcon, ImagesIcon, ListTodoIcon, LoadingSpinner, MarkdownContent, Maximize2Icon, MessageCircleIcon, MessageList, Minimize2Icon, PaperclipIcon, SendIcon, SparklesIcon, StopCircleIcon, TodoList, ToolCallEntry, UserIcon, XIcon, ZoomInIcon, ZoomOutIcon, compressImage, createDefaultAdapter, useAgentChat, useChatConfig, useChatConfigOptional, useExecutionStream, useFileAttachments };
|
|
5048
6080
|
//# sourceMappingURL=index.js.map
|
|
5049
6081
|
//# sourceMappingURL=index.js.map
|