/** * March Agent SDK - Attachment Client * Port of Python march_agent/attachment_client.py */ import { APIException } from './exceptions.js' import { AttachmentInfoSchema, type AttachmentInfo } from './types.js' /** * Re-export AttachmentInfo for convenience */ export { type AttachmentInfo } from './types.js' /** * Create AttachmentInfo from API data */ export function createAttachmentInfo(data: Record): AttachmentInfo { return AttachmentInfoSchema.parse({ url: data.url, filename: data.filename || data.file_name, contentType: data.content_type || data.contentType, size: data.size, fileType: data.file_type || data.fileType, }) } /** * HTTP client for downloading attachments. */ export class AttachmentClient { private readonly baseUrl: string constructor(baseUrl: string) { this.baseUrl = baseUrl.replace(/\/$/, '') } /** * Build full URL for an attachment. */ private buildUrl(attachmentUrl: string): string { // If already absolute URL, use as-is if (attachmentUrl.startsWith('http://') || attachmentUrl.startsWith('https://')) { return attachmentUrl } // Otherwise, prepend base URL return `${this.baseUrl}${attachmentUrl.startsWith('/') ? '' : '/'}${attachmentUrl}` } /** * Download attachment as bytes (Buffer). */ async download(url: string): Promise { const fullUrl = this.buildUrl(url) try { const response = await fetch(fullUrl) if (!response.ok) { throw new APIException(`Failed to download attachment: ${response.status}`, response.status) } const arrayBuffer = await response.arrayBuffer() return Buffer.from(arrayBuffer) } catch (error) { if (error instanceof APIException) throw error throw new APIException(`Failed to download attachment: ${error}`) } } /** * Download attachment as base64 string. * Useful for LLM vision APIs. */ async downloadAsBase64(url: string): Promise { const buffer = await this.download(url) return buffer.toString('base64') } }