# How to Send Images as Attachments to Copilot SDK Sessions: Blob vs File Methods

> Learn how to send images as attachments to Copilot SDK sessions using blob or file methods. Understand base64 encoding and local path requirements for effective image sharing.

- Repository: [GitHub/copilot-sdk](https://github.com/github/copilot-sdk)
- Tags: how-to-guide
- Published: 2026-08-02

---

**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`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/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:

1. **Type Definition** – The `MessageOptions.attachments` field is defined in [`nodejs/src/types.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/types.ts) (lines 58-89), specifying the `blob` shape with `data`, `mimeType`, and optional `displayName`.

2. **Session Send** – When `session.send` receives an attachment, the SDK normalizes it into an internal `Attachment` object. The wire protocol schema resides in [`nodejs/src/generated/session-events.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/generated/session-events.ts) (lines 2750-2790).

3. **Vision Handling** – If the session's model capabilities include `vision: true`, the runtime generates an `image_url` content block containing a data URL formatted as `data:<mime>;base64,<data>`.

4. **Model Reception** – The LLM receives the image as part of the prompt (e.g., a `ChatCompletionMessageContentPartImageUrl` in 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:

```typescript
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`](https://github.com/github/copilot-sdk/blob/main/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:

```typescript
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`](https://github.com/github/copilot-sdk/blob/main/nodejs/test/e2e/session_config.e2e.test.ts) (lines 117-136).

### Dynamically Toggling Vision Capabilities

You can change vision support mid-session using `setModel`:

```typescript
// 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`](https://github.com/github/copilot-sdk/blob/main/nodejs/test/e2e/session_config.e2e.test.ts) (lines 31-45).

## Key Implementation Files

- **[`nodejs/src/types.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/types.ts)** – Defines the public API shape for `MessageOptions.attachments`, including the `blob` interface with `data`, `mimeType`, and `displayName` fields.

- **[`nodejs/src/generated/session-events.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/generated/session-events.ts)** – Contains the internal `Attachment` schema that dictates how the SDK serializes attachments for the wire protocol.

- **[`nodejs/test/e2e/session_config.e2e.test.ts`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/session.ts)** – Implements the core session logic that handles `send`, `sendAndWait`, `setModel`, and the conditional injection of `image_url` content 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: true` capability and automatically handle file reading and encoding.
- The SDK converts both attachment types into `image_url` content blocks that models receive as part of the conversation context.
- Vision capabilities can be toggled dynamically using `session.setModel` after session initialization.
- Reference [`nodejs/src/types.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/src/types.ts) for type definitions and [`nodejs/test/e2e/session_config.e2e.test.ts`](https://github.com/github/copilot-sdk/blob/main/nodejs/test/e2e/session_config.e2e.test.ts) for 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`](https://github.com/github/copilot-sdk/blob/main/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`](https://github.com/github/copilot-sdk/blob/main/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.