import type {SuperagentMediaActionContext, SuperagentMediaAttachment} from '../../types'; import type { SuperagentAttachmentPickerAdapters, SuperagentAttachmentPickerMode, SuperagentNativeMediaItem, } from './useSuperagentAttachmentPicker'; import { getExtension, getMimeType, getUploadName, validateNativeAttachment, } from './attachmentFileUtils'; const MAX_ATTACHMENTS = 10; const IMAGE_EXTENSIONS = new Set(['.jpg', '.jpeg', '.png', '.webp']); export async function pickAndUploadAttachments({ authToken, baseUrl, context, mode, nativeAdapters, onUploadStart, }: { authToken: string; baseUrl: string; context: SuperagentMediaActionContext; mode: SuperagentAttachmentPickerMode; nativeAdapters: SuperagentAttachmentPickerAdapters; onUploadStart?: (count: number) => void; }) { const items = await nativeAdapters.pickNativeMedia(mode); const uploadItems = (items ?? []).filter((item) => Boolean(item?.uri || item?.uploadUri)).slice(0, MAX_ATTACHMENTS); if (!uploadItems.length) { return []; } onUploadStart?.(uploadItems.length); const attachments: SuperagentMediaAttachment[] = []; for (const [index, item] of uploadItems.entries()) { attachments.push(await uploadNativeItem({authToken, baseUrl, agentId: context.agentId, index, item})); } return attachments; } export function getAttachmentPickerErrorMessage(error: unknown) { if (error instanceof Error && error.message) { return error.message; } const candidate = error as {message?: unknown} | null; return typeof candidate?.message === 'string' && candidate.message ? candidate.message : 'Failed to attach the selected file.'; } async function uploadNativeItem({ agentId, authToken, baseUrl, index, item, }: { agentId: string; authToken: string; baseUrl: string; index: number; item: SuperagentNativeMediaItem; }) { const uri = item.uploadUri ?? item.uri; if (!uri) { throw new Error('The selected file does not have a readable local URI.'); } const name = getUploadName(item, index); const extension = getExtension(name); validateNativeAttachment(item, name, extension); const formData = new FormData(); formData.append('file', { name, type: getMimeType(item, extension), uri, } as unknown as Blob); const response = await fetch(`${normalizeBaseUrl(baseUrl)}/api/files/apps/${encodeURIComponent(agentId)}/upload`, { body: formData, headers: { Authorization: `Bearer ${authToken}`, 'X-Client-Platform': 'mobile_native', }, method: 'POST', }); const parsed = await response.json().catch(() => null); const body = parsed && typeof parsed === 'object' ? parsed : {}; if (!response.ok || typeof body.url !== 'string') { throw new Error(body.message || body.detail || 'Upload failed.'); } return { kind: IMAGE_EXTENSIONS.has(extension) ? 'image' : 'file', mimeType: getMimeType(item, extension), name, previewUri: item.thumbnailUri ?? item.previewUri ?? item.uri, url: body.url, } satisfies SuperagentMediaAttachment; } function normalizeBaseUrl(url: string) { return url.trim().replace(/\/+$/, ''); }