@meetsmore-oss/use-ai-client 1.15.0 → 1.16.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/bundled.js +68 -41
- package/dist/bundled.js.map +1 -1
- package/dist/index.d.ts +63 -13
- package/dist/index.js +68 -41
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -668,24 +668,40 @@ interface FileAttachment {
|
|
|
668
668
|
transformedContent?: string;
|
|
669
669
|
}
|
|
670
670
|
/**
|
|
671
|
-
*
|
|
672
|
-
*
|
|
671
|
+
* Result of preparing a file for send.
|
|
672
|
+
*
|
|
673
|
+
* Only one of the two is returned:
|
|
674
|
+
* - `{ url }`: a directly usable url (an inline base64 data URL, or a remote url).
|
|
675
|
+
* The bytes travel along with the message.
|
|
676
|
+
* - `{ ref }`: a pointer into persistent storage (e.g. an S3 key). The bytes stay in
|
|
677
|
+
* storage; only the ref travels with the message and is kept in history. It is
|
|
678
|
+
* resolved on the server before being passed to the model.
|
|
679
|
+
*
|
|
680
|
+
* A backend may also return a bare `string`, which is treated as `{ url: string }`
|
|
681
|
+
* (for backward compatibility with backends written against the older signature).
|
|
682
|
+
*/
|
|
683
|
+
type FileUploadResult = {
|
|
684
|
+
url: string;
|
|
685
|
+
} | {
|
|
686
|
+
ref: string;
|
|
687
|
+
};
|
|
688
|
+
/**
|
|
689
|
+
* Interface for an abstract file upload backend.
|
|
690
|
+
* Converts a File object into a sendable reference at send time.
|
|
673
691
|
*
|
|
674
692
|
* Implementations:
|
|
675
|
-
* - EmbedFileUploadBackend:
|
|
676
|
-
* - S3FileUploadBackend:
|
|
693
|
+
* - EmbedFileUploadBackend: converts to a base64 data URL (built-in)
|
|
694
|
+
* - S3FileUploadBackend: uploads to storage and returns a `ref` (future)
|
|
677
695
|
*/
|
|
678
696
|
interface FileUploadBackend {
|
|
679
697
|
/**
|
|
680
|
-
* Prepare file
|
|
681
|
-
* Called at send time - converts File to URL.
|
|
698
|
+
* Prepare a file to send to the AI. Called at send time.
|
|
682
699
|
*
|
|
683
700
|
* @param file - The File object to prepare
|
|
684
|
-
* @returns
|
|
685
|
-
*
|
|
686
|
-
* - For S3: public URL after upload
|
|
701
|
+
* @returns A {@link FileUploadResult} (`{ url }` or `{ ref }`), or a bare url string
|
|
702
|
+
* for backward compatibility (treated as `{ url }`).
|
|
687
703
|
*/
|
|
688
|
-
prepareForSend(file: File): Promise<string>;
|
|
704
|
+
prepareForSend(file: File): Promise<string | FileUploadResult>;
|
|
689
705
|
}
|
|
690
706
|
/**
|
|
691
707
|
* Context provided to file transformers.
|
|
@@ -773,6 +789,14 @@ interface FileUploadConfig {
|
|
|
773
789
|
* before being sent to the AI.
|
|
774
790
|
*/
|
|
775
791
|
transformers?: FileTransformerMap;
|
|
792
|
+
/**
|
|
793
|
+
* Maximum number of attachments allowed per message.
|
|
794
|
+
* Enforced at attach time; files beyond the limit are rejected with an error.
|
|
795
|
+
* The value is the host's policy (e.g. set it below the AI provider's per-message
|
|
796
|
+
* limit). use-ai only exposes the knob and assumes no default. When undefined, the
|
|
797
|
+
* number of attachments is not limited.
|
|
798
|
+
*/
|
|
799
|
+
maxAttachments?: number;
|
|
776
800
|
}
|
|
777
801
|
|
|
778
802
|
/**
|
|
@@ -811,11 +835,35 @@ interface PersistedTransformedFileContent {
|
|
|
811
835
|
text: string;
|
|
812
836
|
originalFile: PersistedFileMetadata;
|
|
813
837
|
}
|
|
838
|
+
/**
|
|
839
|
+
* Ref-backed attachment content part for persisted messages.
|
|
840
|
+
*
|
|
841
|
+
* Unlike {@link PersistedFileContent} (metadata only, discarded on reload), this part
|
|
842
|
+
* holds a `ref` into persistent storage (e.g. an S3 key). This lets attachments be
|
|
843
|
+
* re-sent to the AI even after a page reload. The actual bytes live in storage rather
|
|
844
|
+
* than localStorage, and the ref is resolved on the host before the next run.
|
|
845
|
+
*
|
|
846
|
+
* Covers both image and non-image attachments in a single type (the persistence layer
|
|
847
|
+
* does not split them: display is identical, and the re-send tag is derived from
|
|
848
|
+
* `mimeType`). On reload it is read two ways: as a name/size chip for display, and as a
|
|
849
|
+
* re-sendable `{ type: 'image_ref' | 'file_ref', ref }` wire part (see `messageConversion.ts`).
|
|
850
|
+
*/
|
|
851
|
+
interface PersistedAttachmentRefContent {
|
|
852
|
+
type: 'attachment_ref';
|
|
853
|
+
/** Ref into persistent storage (e.g. an S3 key). Never expires. */
|
|
854
|
+
ref: string;
|
|
855
|
+
/** Original file name (for display). */
|
|
856
|
+
name: string;
|
|
857
|
+
/** MIME type, e.g. 'image/jpeg' | 'application/pdf'. Decides whether to re-send as image or file. */
|
|
858
|
+
mimeType: string;
|
|
859
|
+
/** Byte size after client-side resize (for display). */
|
|
860
|
+
size: number;
|
|
861
|
+
}
|
|
814
862
|
/**
|
|
815
863
|
* Content part for persisted messages.
|
|
816
|
-
*
|
|
864
|
+
* One of: text, file metadata, transformed file content, or a ref-backed attachment.
|
|
817
865
|
*/
|
|
818
|
-
type PersistedContentPart = PersistedTextContent | PersistedFileContent | PersistedTransformedFileContent;
|
|
866
|
+
type PersistedContentPart = PersistedTextContent | PersistedFileContent | PersistedTransformedFileContent | PersistedAttachmentRefContent;
|
|
819
867
|
/**
|
|
820
868
|
* Content that can be persisted.
|
|
821
869
|
* Simple string for text-only messages, or array for multimodal content.
|
|
@@ -1200,6 +1248,8 @@ declare const defaultStrings: {
|
|
|
1200
1248
|
fileSizeError: string;
|
|
1201
1249
|
/** File type error (use {type} placeholder) */
|
|
1202
1250
|
fileTypeError: string;
|
|
1251
|
+
/** Error when too many files are attached (use {max} placeholder) */
|
|
1252
|
+
maxAttachmentsError: string;
|
|
1203
1253
|
};
|
|
1204
1254
|
floatingButton: {
|
|
1205
1255
|
/** Floating button title when connected */
|
|
@@ -2638,4 +2688,4 @@ interface UseDropdownStateOptions {
|
|
|
2638
2688
|
*/
|
|
2639
2689
|
declare function useDropdownState(options?: UseDropdownStateOptions): UseDropdownStateReturn;
|
|
2640
2690
|
|
|
2641
|
-
export { type AgentContextValue, type Chat, type ChatContextValue, type ChatMetadata, type ChatPanelProps, type ChatRepository, CloseButton, type CommandContextValue, type CommandRepository, type CreateChatOptions, type CreateCommandOptions, DEFAULT_MAX_FILE_SIZE, type DefinedTool, type DropZoneProps, EmbedFileUploadBackend, type EnabledFeatures, type ExecutingToolDisplay, type FileAttachment, type FileProcessingState, type FileProcessingStatus, type FileTransformer, type FileTransformerContext, type FileTransformerMap, type FileUploadBackend, type FileUploadConfig, type FloatingButtonProps, type InlineSaveProps, type ListChatsOptions, type ListCommandsOptions, LocalStorageChatRepository, LocalStorageCommandRepository, type Message, type PendingToolApproval, type PersistedContentPart, type PersistedFileContent, type PersistedFileMetadata, type PersistedMessage, type PersistedMessageContent, type PersistedTextContent, type ProcessAttachmentsConfig, type PromptsContextValue, type RegisterToolsOptions, type SavedCommand, type SendMessageOptions, type SubmitMode, type ToolExecutionContext, type ToolOptions, type ToolRegistryContextValue, type ToolsDefinition, type TriggerWorkflowOptions, UseAIChat, UseAIChatPanel, type UseAIChatPanelProps, type UseAIChatPanelStrings, type UseAIChatPanelTheme, type UseAIChatProps, UseAIClient, type UseAIConfig, type UseAIContextValue, UseAIFloatingButton, UseAIFloatingChatWrapper, type UseAIOptions, UseAIProvider, type UseAIProviderProps, type UseAIResult, type UseAIStrings, type UseAITheme, type UseAIWorkflowResult, type UseAgentSelectionOptions, type UseAgentSelectionReturn, type UseChatManagementOptions, type UseChatManagementReturn, type UseCommandManagementOptions, type UseCommandManagementReturn, type UseDropdownStateOptions, type UseDropdownStateReturn, type UseFeedbackOptions, type UseFeedbackReturn, type UseFileUploadOptions, type UseFileUploadReturn, type UseMessageQueueOptions, type UseMessageQueueReturn, type UsePromptStateOptions, type UsePromptStateReturn, type UseServerEventsOptions, type UseServerEventsReturn, type UseSlashCommandsOptions, type UseSlashCommandsReturn, type UseToolSystemOptions, type UseToolSystemReturn, type WorkflowProgress, clearTransformationCache, convertToolsToDefinitions, defaultStrings, defaultTheme, defineTool, executeDefinedTool, findTransformerPattern, generateChatId, generateCommandId, generateMessageId, matchesMimeType, processAttachments, useAI, useAIContext, useAIWorkflow, useAgentSelection, useChatManagement, useCommandManagement, useDropdownState, useFeedback, useFileUpload, useMessageQueue, usePromptState, useServerEvents, useSlashCommands, useStableTools, useStrings, useTheme, useToolSystem, validateCommandName };
|
|
2691
|
+
export { type AgentContextValue, type Chat, type ChatContextValue, type ChatMetadata, type ChatPanelProps, type ChatRepository, CloseButton, type CommandContextValue, type CommandRepository, type CreateChatOptions, type CreateCommandOptions, DEFAULT_MAX_FILE_SIZE, type DefinedTool, type DropZoneProps, EmbedFileUploadBackend, type EnabledFeatures, type ExecutingToolDisplay, type FileAttachment, type FileProcessingState, type FileProcessingStatus, type FileTransformer, type FileTransformerContext, type FileTransformerMap, type FileUploadBackend, type FileUploadConfig, type FileUploadResult, type FloatingButtonProps, type InlineSaveProps, type ListChatsOptions, type ListCommandsOptions, LocalStorageChatRepository, LocalStorageCommandRepository, type Message, type PendingToolApproval, type PersistedAttachmentRefContent, type PersistedContentPart, type PersistedFileContent, type PersistedFileMetadata, type PersistedMessage, type PersistedMessageContent, type PersistedTextContent, type PersistedTransformedFileContent, type ProcessAttachmentsConfig, type PromptsContextValue, type RegisterToolsOptions, type SavedCommand, type SendMessageOptions, type SubmitMode, type ToolExecutionContext, type ToolOptions, type ToolRegistryContextValue, type ToolsDefinition, type TriggerWorkflowOptions, UseAIChat, UseAIChatPanel, type UseAIChatPanelProps, type UseAIChatPanelStrings, type UseAIChatPanelTheme, type UseAIChatProps, UseAIClient, type UseAIConfig, type UseAIContextValue, UseAIFloatingButton, UseAIFloatingChatWrapper, type UseAIOptions, UseAIProvider, type UseAIProviderProps, type UseAIResult, type UseAIStrings, type UseAITheme, type UseAIWorkflowResult, type UseAgentSelectionOptions, type UseAgentSelectionReturn, type UseChatManagementOptions, type UseChatManagementReturn, type UseCommandManagementOptions, type UseCommandManagementReturn, type UseDropdownStateOptions, type UseDropdownStateReturn, type UseFeedbackOptions, type UseFeedbackReturn, type UseFileUploadOptions, type UseFileUploadReturn, type UseMessageQueueOptions, type UseMessageQueueReturn, type UsePromptStateOptions, type UsePromptStateReturn, type UseServerEventsOptions, type UseServerEventsReturn, type UseSlashCommandsOptions, type UseSlashCommandsReturn, type UseToolSystemOptions, type UseToolSystemReturn, type WorkflowProgress, clearTransformationCache, convertToolsToDefinitions, defaultStrings, defaultTheme, defineTool, executeDefinedTool, findTransformerPattern, generateChatId, generateCommandId, generateMessageId, matchesMimeType, processAttachments, useAI, useAIContext, useAIWorkflow, useAgentSelection, useChatManagement, useCommandManagement, useDropdownState, useFeedback, useFileUpload, useMessageQueue, usePromptState, useServerEvents, useSlashCommands, useStableTools, useStrings, useTheme, useToolSystem, validateCommandName };
|
package/dist/index.js
CHANGED
|
@@ -56,7 +56,9 @@ var defaultStrings = {
|
|
|
56
56
|
/** File size error (use {filename} and {maxSize} placeholders) */
|
|
57
57
|
fileSizeError: 'File "{filename}" exceeds {maxSize}MB limit',
|
|
58
58
|
/** File type error (use {type} placeholder) */
|
|
59
|
-
fileTypeError: 'File type "{type}" is not accepted'
|
|
59
|
+
fileTypeError: 'File type "{type}" is not accepted',
|
|
60
|
+
/** Error when too many files are attached (use {max} placeholder) */
|
|
61
|
+
maxAttachmentsError: "You can attach at most {max} files per message"
|
|
60
62
|
},
|
|
61
63
|
// Floating button
|
|
62
64
|
floatingButton: {
|
|
@@ -1405,6 +1407,9 @@ async function getTransformedContent(files, transformer, context, onProgress) {
|
|
|
1405
1407
|
transformationCache.set(cacheKey, results);
|
|
1406
1408
|
return results;
|
|
1407
1409
|
}
|
|
1410
|
+
function normalizeUploadResult(result) {
|
|
1411
|
+
return typeof result === "string" ? { url: result } : result;
|
|
1412
|
+
}
|
|
1408
1413
|
async function toContentPart(attachment, backend) {
|
|
1409
1414
|
if (attachment.transformedContent !== void 0) {
|
|
1410
1415
|
return {
|
|
@@ -1417,16 +1422,12 @@ async function toContentPart(attachment, backend) {
|
|
|
1417
1422
|
}
|
|
1418
1423
|
};
|
|
1419
1424
|
}
|
|
1420
|
-
const
|
|
1421
|
-
|
|
1422
|
-
|
|
1425
|
+
const result = normalizeUploadResult(await backend.prepareForSend(attachment.file));
|
|
1426
|
+
const isImage = attachment.file.type.startsWith("image/");
|
|
1427
|
+
if ("ref" in result) {
|
|
1428
|
+
return isImage ? { type: "image_ref", ref: result.ref } : { type: "file_ref", ref: result.ref, mimeType: attachment.file.type, name: attachment.file.name };
|
|
1423
1429
|
}
|
|
1424
|
-
return {
|
|
1425
|
-
type: "file",
|
|
1426
|
-
url,
|
|
1427
|
-
mimeType: attachment.file.type,
|
|
1428
|
-
name: attachment.file.name
|
|
1429
|
-
};
|
|
1430
|
+
return isImage ? { type: "image_url", url: result.url } : { type: "file_url", url: result.url, mimeType: attachment.file.type, name: attachment.file.name };
|
|
1430
1431
|
}
|
|
1431
1432
|
async function processAttachments(attachments, config) {
|
|
1432
1433
|
const { getCurrentChat, backend = new EmbedFileUploadBackend(), transformers = {}, onFileProgress } = config;
|
|
@@ -1529,7 +1530,12 @@ function useFileUpload({
|
|
|
1529
1530
|
const enabled = config !== void 0;
|
|
1530
1531
|
const maxFileSize = config?.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
1531
1532
|
const acceptedTypes = config?.acceptedTypes;
|
|
1533
|
+
const maxAttachments = config?.maxAttachments;
|
|
1532
1534
|
const transformers = config?.transformers;
|
|
1535
|
+
const attachmentsRef = useRef3(attachments);
|
|
1536
|
+
useEffect3(() => {
|
|
1537
|
+
attachmentsRef.current = attachments;
|
|
1538
|
+
}, [attachments]);
|
|
1533
1539
|
useEffect3(() => {
|
|
1534
1540
|
if (fileError) {
|
|
1535
1541
|
const timer = setTimeout(() => setFileError(null), 3e3);
|
|
@@ -1565,7 +1571,13 @@ function useFileUpload({
|
|
|
1565
1571
|
}, [getCurrentChat, transformers]);
|
|
1566
1572
|
const handleFiles = useCallback2(async (files) => {
|
|
1567
1573
|
const fileArray = Array.from(files);
|
|
1574
|
+
let currentCount = attachmentsRef.current.length;
|
|
1568
1575
|
for (const file of fileArray) {
|
|
1576
|
+
if (maxAttachments !== void 0 && currentCount >= maxAttachments) {
|
|
1577
|
+
const errorMsg = strings.fileUpload.maxAttachmentsError.replace("{max}", String(maxAttachments));
|
|
1578
|
+
setFileError(errorMsg);
|
|
1579
|
+
break;
|
|
1580
|
+
}
|
|
1569
1581
|
if (file.size > maxFileSize) {
|
|
1570
1582
|
const errorMsg = strings.fileUpload.fileSizeError.replace("{filename}", file.name).replace("{maxSize}", String(Math.round(maxFileSize / (1024 * 1024))));
|
|
1571
1583
|
setFileError(errorMsg);
|
|
@@ -1584,14 +1596,17 @@ function useFileUpload({
|
|
|
1584
1596
|
preview
|
|
1585
1597
|
};
|
|
1586
1598
|
setAttachments((prev) => [...prev, attachment]);
|
|
1599
|
+
attachmentsRef.current = [...attachmentsRef.current, attachment];
|
|
1600
|
+
currentCount++;
|
|
1587
1601
|
const transformerKey = findTransformerPattern(file.type, transformers);
|
|
1588
1602
|
if (transformerKey) {
|
|
1589
1603
|
runTransformer(attachmentId, file, transformerKey);
|
|
1590
1604
|
}
|
|
1591
1605
|
}
|
|
1592
|
-
}, [maxFileSize, acceptedTypes, strings, transformers, runTransformer]);
|
|
1606
|
+
}, [maxFileSize, acceptedTypes, maxAttachments, strings, transformers, runTransformer]);
|
|
1593
1607
|
const removeAttachment = useCallback2((id) => {
|
|
1594
1608
|
setAttachments((prev) => prev.filter((a) => a.id !== id));
|
|
1609
|
+
attachmentsRef.current = attachmentsRef.current.filter((a) => a.id !== id);
|
|
1595
1610
|
setProcessingState((prev) => {
|
|
1596
1611
|
const next = new Map(prev);
|
|
1597
1612
|
next.delete(id);
|
|
@@ -1600,6 +1615,7 @@ function useFileUpload({
|
|
|
1600
1615
|
}, []);
|
|
1601
1616
|
const clearAttachments = useCallback2(() => {
|
|
1602
1617
|
setAttachments([]);
|
|
1618
|
+
attachmentsRef.current = [];
|
|
1603
1619
|
setProcessingState(/* @__PURE__ */ new Map());
|
|
1604
1620
|
}, []);
|
|
1605
1621
|
const openFilePicker = useCallback2(() => {
|
|
@@ -2170,7 +2186,16 @@ function FeedbackButton({ type, isSelected, onClick, selectedColor, unselectedCo
|
|
|
2170
2186
|
);
|
|
2171
2187
|
}
|
|
2172
2188
|
function hasFileContent(content) {
|
|
2173
|
-
return Array.isArray(content) && content.some((part) => part.type === "file");
|
|
2189
|
+
return Array.isArray(content) && content.some((part) => part.type === "file" || part.type === "attachment_ref");
|
|
2190
|
+
}
|
|
2191
|
+
function fileChipInfo(part) {
|
|
2192
|
+
if (part.type === "file") {
|
|
2193
|
+
return { name: part.file.name, size: part.file.size };
|
|
2194
|
+
}
|
|
2195
|
+
if (part.type === "attachment_ref") {
|
|
2196
|
+
return { name: part.name, size: part.size };
|
|
2197
|
+
}
|
|
2198
|
+
return null;
|
|
2174
2199
|
}
|
|
2175
2200
|
function UseAIChatPanel({
|
|
2176
2201
|
onSendMessage,
|
|
@@ -2843,14 +2868,10 @@ function UseAIChatPanel({
|
|
|
2843
2868
|
wordWrap: "break-word"
|
|
2844
2869
|
},
|
|
2845
2870
|
children: [
|
|
2846
|
-
message.role === "user" && hasFileContent(message.content) && /* @__PURE__ */ jsx12("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px", marginBottom: "8px" }, children: message.content.
|
|
2847
|
-
|
|
2848
|
-
{
|
|
2849
|
-
|
|
2850
|
-
size: part.file.size
|
|
2851
|
-
},
|
|
2852
|
-
idx
|
|
2853
|
-
)) }),
|
|
2871
|
+
message.role === "user" && hasFileContent(message.content) && /* @__PURE__ */ jsx12("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px", marginBottom: "8px" }, children: message.content.flatMap((part, idx) => {
|
|
2872
|
+
const info = fileChipInfo(part);
|
|
2873
|
+
return info ? [/* @__PURE__ */ jsx12(FilePlaceholder, { name: info.name, size: info.size }, idx)] : [];
|
|
2874
|
+
}) }),
|
|
2854
2875
|
message.role === "assistant" ? /* @__PURE__ */ jsxs9(Fragment, { children: [
|
|
2855
2876
|
message.reasoningParts && message.reasoningParts.length > 0 && /* @__PURE__ */ jsx12(
|
|
2856
2877
|
Reasoning,
|
|
@@ -3669,31 +3690,13 @@ var UseAIClient = class {
|
|
|
3669
3690
|
async sendPrompt(prompt, multimodalContent, forwardedProps) {
|
|
3670
3691
|
let messageContent = prompt;
|
|
3671
3692
|
if (multimodalContent && multimodalContent.length > 0) {
|
|
3672
|
-
messageContent = multimodalContent
|
|
3673
|
-
if (part.type === "text") {
|
|
3674
|
-
return { type: "text", text: part.text };
|
|
3675
|
-
} else if (part.type === "image") {
|
|
3676
|
-
return { type: "image", url: part.url };
|
|
3677
|
-
} else if (part.type === "file") {
|
|
3678
|
-
return {
|
|
3679
|
-
type: "file",
|
|
3680
|
-
url: part.url,
|
|
3681
|
-
mimeType: part.mimeType
|
|
3682
|
-
};
|
|
3683
|
-
} else {
|
|
3684
|
-
return {
|
|
3685
|
-
type: "transformed_file",
|
|
3686
|
-
text: part.text,
|
|
3687
|
-
originalFile: part.originalFile
|
|
3688
|
-
};
|
|
3689
|
-
}
|
|
3690
|
-
});
|
|
3693
|
+
messageContent = multimodalContent;
|
|
3691
3694
|
}
|
|
3692
3695
|
const userMessage = {
|
|
3693
3696
|
id: uuidv42(),
|
|
3694
3697
|
role: "user",
|
|
3698
|
+
// @ag-ui/core declares Message.content as `string`; the wire also carries MultimodalContent[].
|
|
3695
3699
|
content: messageContent
|
|
3696
|
-
// Type cast needed for Message type compatibility
|
|
3697
3700
|
};
|
|
3698
3701
|
this._messages.push(userMessage);
|
|
3699
3702
|
const runId = uuidv42();
|
|
@@ -4391,6 +4394,7 @@ function buildPersistedParts(message, attachments, fileContent) {
|
|
|
4391
4394
|
parts.push({ type: "text", text: message });
|
|
4392
4395
|
}
|
|
4393
4396
|
const transformedByKey = /* @__PURE__ */ new Map();
|
|
4397
|
+
const nonTransformedParts = [];
|
|
4394
4398
|
for (const part of fileContent) {
|
|
4395
4399
|
if (part.type === "transformed_file") {
|
|
4396
4400
|
const key = `${part.originalFile.name}:${part.originalFile.size}:${part.originalFile.mimeType}`;
|
|
@@ -4400,6 +4404,8 @@ function buildPersistedParts(message, attachments, fileContent) {
|
|
|
4400
4404
|
} else {
|
|
4401
4405
|
transformedByKey.set(key, [part]);
|
|
4402
4406
|
}
|
|
4407
|
+
} else {
|
|
4408
|
+
nonTransformedParts.push(part);
|
|
4403
4409
|
}
|
|
4404
4410
|
}
|
|
4405
4411
|
for (const attachment of attachments) {
|
|
@@ -4411,6 +4417,18 @@ function buildPersistedParts(message, attachments, fileContent) {
|
|
|
4411
4417
|
text: transformed.text,
|
|
4412
4418
|
originalFile: transformed.originalFile
|
|
4413
4419
|
});
|
|
4420
|
+
continue;
|
|
4421
|
+
}
|
|
4422
|
+
const part = nonTransformedParts.shift();
|
|
4423
|
+
const ref = part && (part.type === "image_ref" || part.type === "file_ref") ? part.ref : void 0;
|
|
4424
|
+
if (ref) {
|
|
4425
|
+
parts.push({
|
|
4426
|
+
type: "attachment_ref",
|
|
4427
|
+
ref,
|
|
4428
|
+
name: attachment.file.name,
|
|
4429
|
+
mimeType: attachment.file.type,
|
|
4430
|
+
size: attachment.file.size
|
|
4431
|
+
});
|
|
4414
4432
|
} else {
|
|
4415
4433
|
parts.push({
|
|
4416
4434
|
type: "file",
|
|
@@ -4463,9 +4481,18 @@ function transformMessagesToClientFormat(persistedMessages) {
|
|
|
4463
4481
|
${p.text}`
|
|
4464
4482
|
}];
|
|
4465
4483
|
}
|
|
4484
|
+
if (p.type === "attachment_ref") {
|
|
4485
|
+
return [
|
|
4486
|
+
p.mimeType.startsWith("image/") ? { type: "image_ref", ref: p.ref } : { type: "file_ref", ref: p.ref, mimeType: p.mimeType, name: p.name }
|
|
4487
|
+
];
|
|
4488
|
+
}
|
|
4466
4489
|
return [];
|
|
4467
4490
|
});
|
|
4468
|
-
return {
|
|
4491
|
+
return {
|
|
4492
|
+
id: msg.id,
|
|
4493
|
+
role: "user",
|
|
4494
|
+
content: parts
|
|
4495
|
+
};
|
|
4469
4496
|
}
|
|
4470
4497
|
}
|
|
4471
4498
|
});
|