@gendive/chatllm 0.21.9 → 0.22.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.
@@ -1060,6 +1060,12 @@ interface ChatUIProps {
1060
1060
  * @Todo vibecode - 새 URL 반환 시 img.src 갱신 + contentParts url 업데이트, null 반환 시 기본 에러 처리 (#13)
1061
1061
  */
1062
1062
  onImageError?: (url: string, fileName?: string) => Promise<string | null>;
1063
+ /**
1064
+ * @description 첨부 파일 업로드 콜백 (File → URL 변환)
1065
+ * @Todo vibecode - autoConvertBase64 대신 File 객체를 직접 업로드하여 URL로 전달
1066
+ * base64 이중 변환(File→base64→File→업로드) 제거, 메모리 ~33% 절감
1067
+ */
1068
+ fileUploader?: (file: File) => Promise<string>;
1063
1069
  /**
1064
1070
  * @description Thinking 블록 표시 여부
1065
1071
  * @Todo vibecode - AI 추론 과정 표시 (기본: true)
@@ -1953,6 +1959,11 @@ interface UseChatUIOptions {
1953
1959
  * @Todo vibecode - 새 URL 반환 시 img.src 갱신, null 반환 시 기본 에러 처리 (#13)
1954
1960
  */
1955
1961
  onImageError?: (url: string, fileName?: string) => Promise<string | null>;
1962
+ /**
1963
+ * @description 첨부 파일 업로드 콜백 (File → URL 변환)
1964
+ * @Todo vibecode - autoConvertBase64 대신 File 객체를 직접 업로드하여 URL로 전달
1965
+ */
1966
+ fileUploader?: (file: File) => Promise<string>;
1956
1967
  /**
1957
1968
  * @description 외부 스토리지 사용 여부
1958
1969
  * @Todo vibecode - true 시 localStorage 대신 콜백 사용
@@ -1060,6 +1060,12 @@ interface ChatUIProps {
1060
1060
  * @Todo vibecode - 새 URL 반환 시 img.src 갱신 + contentParts url 업데이트, null 반환 시 기본 에러 처리 (#13)
1061
1061
  */
1062
1062
  onImageError?: (url: string, fileName?: string) => Promise<string | null>;
1063
+ /**
1064
+ * @description 첨부 파일 업로드 콜백 (File → URL 변환)
1065
+ * @Todo vibecode - autoConvertBase64 대신 File 객체를 직접 업로드하여 URL로 전달
1066
+ * base64 이중 변환(File→base64→File→업로드) 제거, 메모리 ~33% 절감
1067
+ */
1068
+ fileUploader?: (file: File) => Promise<string>;
1063
1069
  /**
1064
1070
  * @description Thinking 블록 표시 여부
1065
1071
  * @Todo vibecode - AI 추론 과정 표시 (기본: true)
@@ -1953,6 +1959,11 @@ interface UseChatUIOptions {
1953
1959
  * @Todo vibecode - 새 URL 반환 시 img.src 갱신, null 반환 시 기본 에러 처리 (#13)
1954
1960
  */
1955
1961
  onImageError?: (url: string, fileName?: string) => Promise<string | null>;
1962
+ /**
1963
+ * @description 첨부 파일 업로드 콜백 (File → URL 변환)
1964
+ * @Todo vibecode - autoConvertBase64 대신 File 객체를 직접 업로드하여 URL로 전달
1965
+ */
1966
+ fileUploader?: (file: File) => Promise<string>;
1956
1967
  /**
1957
1968
  * @description 외부 스토리지 사용 여부
1958
1969
  * @Todo vibecode - true 시 localStorage 대신 콜백 사용
@@ -2269,6 +2269,16 @@ var convertAttachmentsToBase64 = async (attachments) => Promise.all(
2269
2269
  size: att.size
2270
2270
  }))
2271
2271
  );
2272
+ var convertAttachmentsWithUploader = async (attachments, uploader) => Promise.all(
2273
+ attachments.map(async (att) => ({
2274
+ name: att.name,
2275
+ mimeType: att.mimeType,
2276
+ base64: "",
2277
+ url: await uploader(att.file),
2278
+ size: att.size,
2279
+ source: "uploader"
2280
+ }))
2281
+ );
2272
2282
  var findPreviousResultImage = (messages) => {
2273
2283
  for (let i = messages.length - 1; i >= 0; i--) {
2274
2284
  const msg = messages[i];
@@ -2330,6 +2340,8 @@ var useChatUI = (options) => {
2330
2340
  // Image upload
2331
2341
  onUploadImage,
2332
2342
  onImageError,
2343
+ // File upload
2344
+ fileUploader,
2333
2345
  // External storage options
2334
2346
  useExternalStorage = false,
2335
2347
  startWithNewSession = false,
@@ -2437,6 +2449,7 @@ var useChatUI = (options) => {
2437
2449
  const onLoadModelsRef = (0, import_react6.useRef)(onLoadModels);
2438
2450
  const onUploadImageRef = (0, import_react6.useRef)(onUploadImage);
2439
2451
  const onImageErrorRef = (0, import_react6.useRef)(onImageError);
2452
+ const fileUploaderRef = (0, import_react6.useRef)(fileUploader);
2440
2453
  const globalMemoryRef = (0, import_react6.useRef)(null);
2441
2454
  (0, import_react6.useEffect)(() => {
2442
2455
  onSendMessageRef.current = onSendMessage;
@@ -2458,6 +2471,7 @@ var useChatUI = (options) => {
2458
2471
  onSessionContextChangeRef.current = onSessionContextChange;
2459
2472
  onUploadImageRef.current = onUploadImage;
2460
2473
  onImageErrorRef.current = onImageError;
2474
+ fileUploaderRef.current = fileUploader;
2461
2475
  onLoadModelsRef.current = onLoadModels;
2462
2476
  });
2463
2477
  const abortControllersRef = (0, import_react6.useRef)(/* @__PURE__ */ new Map());
@@ -3645,7 +3659,7 @@ ${finalContent}`;
3645
3659
  })
3646
3660
  );
3647
3661
  try {
3648
- const filesToPass = skillConfig.autoConvertBase64 ? await convertAttachmentsToBase64(matchedFiles) : matchedFiles;
3662
+ const filesToPass = fileUploaderRef.current ? await convertAttachmentsWithUploader(matchedFiles, fileUploaderRef.current) : skillConfig.autoConvertBase64 ? await convertAttachmentsToBase64(matchedFiles) : matchedFiles;
3649
3663
  const result = await skillConfig.execute({ files: filesToPass, userMessage: finalContent });
3650
3664
  const attachResultType = result.metadata?.type || result.metadata?.resultType || "text";
3651
3665
  const toolResultPart = {
@@ -3703,7 +3717,12 @@ ${finalContent}`;
3703
3717
  const hasUserText = finalContent.trim().length > 0;
3704
3718
  if (hasImageAttachments && hasUserText) {
3705
3719
  const imageAttachments = currentAttachments.filter((a) => a.type === "image");
3706
- pendingAttachmentDataRef.current = await convertAttachmentsToBase64(imageAttachments);
3720
+ try {
3721
+ pendingAttachmentDataRef.current = fileUploaderRef.current ? await convertAttachmentsWithUploader(imageAttachments, fileUploaderRef.current) : await convertAttachmentsToBase64(imageAttachments);
3722
+ } catch (err) {
3723
+ console.error("[chatllm] pendingAttachment conversion failed:", err);
3724
+ pendingAttachmentDataRef.current = null;
3725
+ }
3707
3726
  } else {
3708
3727
  pendingAttachmentDataRef.current = null;
3709
3728
  }
@@ -3851,7 +3870,9 @@ ${attachmentContext}
3851
3870
  }
3852
3871
  }
3853
3872
  } else if (attachmentResults.length === 0 && pendingAttachmentDataRef.current !== null) {
3854
- const isReferenceImage = pendingAttachmentDataRef.current.some((d) => d.url && !d.base64);
3873
+ const isReferenceImage = pendingAttachmentDataRef.current.some(
3874
+ (d) => d.url && !d.base64 && d.source !== "uploader"
3875
+ );
3855
3876
  if (isReferenceImage) {
3856
3877
  chatMessages.push({
3857
3878
  role: "user",
@@ -15162,7 +15183,9 @@ var ChatUIWithHook = ({
15162
15183
  onAnalyzePatterns,
15163
15184
  // Image upload
15164
15185
  onUploadImage,
15165
- onImageError
15186
+ onImageError,
15187
+ // File upload
15188
+ fileUploader
15166
15189
  }) => {
15167
15190
  const hookOptions = {
15168
15191
  models,
@@ -15213,7 +15236,9 @@ var ChatUIWithHook = ({
15213
15236
  onAnalyzePatterns,
15214
15237
  // Image upload
15215
15238
  onUploadImage,
15216
- onImageError
15239
+ onImageError,
15240
+ // File upload
15241
+ fileUploader
15217
15242
  };
15218
15243
  const state = useChatUI(hookOptions);
15219
15244
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ImageErrorContext.Provider, { value: onImageError || null, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(