* Prepare an image for vision models: detect media type, optionally * resize/compress with sharp, and return the prepared buffer. * * Wrapped in a `copilot.vfs.prepare_image` span so the external trace * shows exactly when an image read blocked the request on CPU-heavy * encode attempts. Attrib
( buffer: Buffer, claimedType: string )
| 89 | * dimension/quality chosen. |
| 90 | */ |
| 91 | async function prepareImageForVision( |
| 92 | buffer: Buffer, |
| 93 | claimedType: string |
| 94 | ): Promise<PreparedVisionImage | null> { |
| 95 | return getVfsTracer().startActiveSpan( |
| 96 | TraceSpan.CopilotVfsPrepareImage, |
| 97 | { |
| 98 | attributes: { |
| 99 | [TraceAttr.CopilotVfsInputBytes]: buffer.length, |
| 100 | [TraceAttr.CopilotVfsInputMediaTypeClaimed]: claimedType, |
| 101 | }, |
| 102 | }, |
| 103 | async (span) => { |
| 104 | try { |
| 105 | const mediaType = detectImageMime(buffer, claimedType) |
| 106 | span.setAttribute(TraceAttr.CopilotVfsInputMediaTypeDetected, mediaType) |
| 107 | |
| 108 | let sharpModule: typeof import('sharp') |
| 109 | try { |
| 110 | sharpModule = (await import('sharp')).default |
| 111 | } catch (err) { |
| 112 | logger.warn('Failed to load sharp for image preparation', { |
| 113 | mediaType, |
| 114 | error: toError(err).message, |
| 115 | }) |
| 116 | span.setAttribute(TraceAttr.CopilotVfsSharpLoadFailed, true) |
| 117 | const fitsWithoutSharp = buffer.length <= MAX_IMAGE_READ_BYTES |
| 118 | span.setAttribute( |
| 119 | TraceAttr.CopilotVfsOutcome, |
| 120 | fitsWithoutSharp ? 'passthrough_no_sharp' : 'rejected_no_sharp' |
| 121 | ) |
| 122 | return fitsWithoutSharp ? { buffer, mediaType, resized: false } : null |
| 123 | } |
| 124 | |
| 125 | let metadata: Awaited<ReturnType<ReturnType<typeof sharpModule>['metadata']>> |
| 126 | try { |
| 127 | metadata = await sharpModule(buffer, { limitInputPixels: false }).metadata() |
| 128 | } catch (err) { |
| 129 | logger.warn('Failed to read image metadata for VFS read', { |
| 130 | mediaType, |
| 131 | error: toError(err).message, |
| 132 | }) |
| 133 | span.setAttribute(TraceAttr.CopilotVfsMetadataFailed, true) |
| 134 | const fitsWithoutSharp = buffer.length <= MAX_IMAGE_READ_BYTES |
| 135 | span.setAttribute( |
| 136 | TraceAttr.CopilotVfsOutcome, |
| 137 | fitsWithoutSharp ? 'passthrough_no_metadata' : 'rejected_no_metadata' |
| 138 | ) |
| 139 | return fitsWithoutSharp ? { buffer, mediaType, resized: false } : null |
| 140 | } |
| 141 | |
| 142 | const width = metadata.width ?? 0 |
| 143 | const height = metadata.height ?? 0 |
| 144 | span.setAttributes({ |
| 145 | [TraceAttr.CopilotVfsInputWidth]: width, |
| 146 | [TraceAttr.CopilotVfsInputHeight]: height, |
| 147 | }) |
| 148 |
no test coverage detected