How to Send Images as Attachments to Copilot SDK Sessions: Blob vs File Methods
You can send images to Copilot SDK sessions using either blob attachments for base64-encoded data or file attachments for local image paths, with the latter requiring the vision: true capability flag.
The GitHub Copilot SDK provides native support for multimodal conversations by allowing you to attach images directly to session.send or session.sendAndWait calls. Whether you need to transmit dynamically generated pixels or reference existing files on disk, the SDK handles the encoding and transmission automatically according to the type definitions in nodejs/src/types.ts.
Supported Attachment Types for Images
The SDK recognizes two distinct attachment strategies for image data. Your choice depends on whether the image exists as a file or as raw data in memory.
Blob Attachments
blob attachments embed base64-encoded image data directly in the request payload. According to the type definitions in nodejs/src/types.ts (lines 58-89), a blob attachment requires data (the base64 string), mimeType (such as image/png or image/jpeg), and an optional displayName for UI rendering.
This approach is optimal for small images generated programmatically or when you want to avoid filesystem I/O. The SDK passes the MIME type to the transport layer, which encodes the data as an image_url part for the model.
File Attachments with Vision
file attachments reference images by their filesystem path. To use this method, you must enable vision capabilities when creating the session by setting modelCapabilities: { supports: { vision: true } } in the session configuration.
When vision is enabled, the SDK reads the specified file, base64-encodes it automatically, and injects an image_url content block into the conversation. This method is ideal for large files that benefit from the SDK's streaming efficiency.
Architectural Flow: How Images Reach the Model
Understanding the internal processing helps debug attachment issues. The flow follows four distinct stages implemented in the github/copilot-sdk repository:
-
Type Definition – The
MessageOptions.attachmentsfield is defined innodejs/src/types.ts(lines 58-89), specifying theblobshape withdata,mimeType, and optionaldisplayName. -
Session Send – When
session.sendreceives an attachment, the SDK normalizes it into an internalAttachmentobject. The wire protocol schema resides innodejs/src/generated/session-events.ts(lines 2750-2790). -
Vision Handling – If the session's model capabilities include
vision: true, the runtime generates animage_urlcontent block containing a data URL formatted asdata:<mime>;base64,<data>. -
Model Reception – The LLM receives the image as part of the prompt (e.g., a
ChatCompletionMessageContentPartImageUrlin OpenAI format), and the SDK returns the response as usual.
Code Examples
Sending a Base64-Encoded Image as a Blob
Use this pattern when you have image data already loaded in memory or generated on-the-fly:
import { CopilotClient, approveAll } from "copilot-sdk";
const client = new CopilotClient();
const session = await client.createSession({ onPermissionRequest: approveAll });
await session.sendAndWait({
prompt: "What color is this pixel? Reply in one word.",
attachments: [
{
type: "blob",
data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
mimeType: "image/png",
displayName: "pixel.png",
},
],
});
await session.disconnect();
This example corresponds to the blob attachment test in nodejs/test/e2e/session_config.e2e.test.ts (lines 65-82).
Attaching a Local Image File with Vision Enabled
Use this approach when referencing existing files on disk:
import { CopilotClient, approveAll } from "copilot-sdk";
import { writeFile, join } from "fs/promises";
const client = new CopilotClient();
const workDir = "/tmp/myproject";
await writeFile(join(workDir, "photo.png"), Buffer.from(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
"base64"
));
const session = await client.createSession({
onPermissionRequest: approveAll,
modelCapabilities: { supports: { vision: true } },
});
await session.sendAndWait({
prompt: "Describe the image content",
attachments: [{ type: "file", path: join(workDir, "photo.png") }],
});
await session.disconnect();
This implementation is verified in nodejs/test/e2e/session_config.e2e.test.ts (lines 117-136).
Dynamically Toggling Vision Capabilities
You can change vision support mid-session using setModel:
// Start with vision disabled
let session = await client.createSession({
onPermissionRequest: approveAll,
modelCapabilities: { supports: { vision: false } },
});
await session.sendAndWait({ prompt: "Explain this text." });
// Enable vision later
await session.setModel("claude-sonnet-4.5", {
modelCapabilities: { supports: { vision: true } },
});
await session.sendAndWait({
prompt: "Look at the attached picture and tell me what you see",
attachments: [{ type: "file", path: "./cat.png" }],
});
This pattern is demonstrated in nodejs/test/e2e/session_config.e2e.test.ts (lines 31-45).
Key Implementation Files
-
nodejs/src/types.ts– Defines the public API shape forMessageOptions.attachments, including theblobinterface withdata,mimeType, anddisplayNamefields. -
nodejs/src/generated/session-events.ts– Contains the internalAttachmentschema that dictates how the SDK serializes attachments for the wire protocol. -
nodejs/test/e2e/session_config.e2e.test.ts– Provides verified usage patterns for both blob and vision-enabled file attachments, ensuring images correctly forward to the model. -
nodejs/src/session.ts– Implements the core session logic that handlessend,sendAndWait,setModel, and the conditional injection ofimage_urlcontent blocks based on vision flags.
Summary
- Blob attachments require base64-encoded data and a MIME type, making them ideal for in-memory images.
- File attachments require the
vision: truecapability and automatically handle file reading and encoding. - The SDK converts both attachment types into
image_urlcontent blocks that models receive as part of the conversation context. - Vision capabilities can be toggled dynamically using
session.setModelafter session initialization. - Reference
nodejs/src/types.tsfor type definitions andnodejs/test/e2e/session_config.e2e.test.tsfor working examples.
Frequently Asked Questions
What MIME types are supported for blob attachments?
The SDK accepts any standard image MIME type (such as image/png, image/jpeg, or image/webp) in the mimeType field of a blob attachment. The transport layer passes this value directly to the model provider when constructing the data URL, so compatibility depends on the specific LLM's supported formats.
Do I need to base64-encode images manually when using file attachments?
No. When using type: "file" attachments with vision enabled, the SDK automatically reads the file from disk and base64-encodes it before transmission. You only need to provide the filesystem path; the encoding happens internally in the session implementation.
Can I switch vision capabilities after creating a session?
Yes. You can dynamically enable or disable vision by calling session.setModel() with updated modelCapabilities. This allows you to start with text-only processing and enable image analysis later without creating a new session instance, as shown in the test cases at nodejs/test/e2e/session_config.e2e.test.ts.
What is the maximum image size supported?
While the SDK itself does not enforce strict size limits in nodejs/src/types.ts, practical limits depend on the underlying model provider's API constraints and the transport layer's payload size restrictions. For large images, use file attachments rather than blob to leverage the SDK's streaming capabilities and avoid memory overhead from base64 string expansion.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →