# Changelog - Apr 28, 2026

**Documentation:** https://docs.composio.dev/docs/changelog/2026/04/28

## SDKs: `link()` matches `initiate()` for the multi-connection guard

TypeScript and Python `connectedAccounts.link()` now refuse to create a second active connection on the same auth config unless `allowMultiple` / `allow_multiple` is set, mirroring `initiate()`. Patch releases.

`composio.connectedAccounts.link()` (TypeScript) and `composio.connected_accounts.link()` (Python) now match the multi-connection guard that `initiate()` already had. With Composio-managed redirectable-OAuth callers being [migrated off `POST /api/v3/connected_accounts` onto `POST /api/v3/connected_accounts/link`](/docs/changelog/2026/04/24), the guard moves with them — so the migration doesn't quietly drop the duplicate-connection check.

> **Behavior change**

Before: `link()` would happily create a second `ACTIVE` connection for the same `(user_id, auth_config_id)` pair without checking for an existing `ACTIVE` connection first.

After: `link()` first calls `connectedAccounts.list({ userIds, authConfigIds, statuses: ['ACTIVE'] })`. If any active connection exists, `link()` throws `ComposioMultipleConnectedAccountsError` unless the caller passes `allowMultiple: true` (TypeScript) / `allow_multiple=True` (Python).

## SDK versions (patch releases)

| Package                     | Previous | This release |
| --------------------------- | -------- | ------------ |
| TypeScript `@composio/core` | v0.8.0   | **v0.8.1**   |
| Python `composio`           | v0.12.0  | **v0.12.1**  |

## Migration

Most callers don't need to do anything — `link()` raised an unrelated error or succeeded by accident in the duplicate-connection case before, and now raises a typed error you can handle. Two scenarios that need attention:

**1. You intentionally create multiple connections per `(user, auth_config)`** — for example, two Gmail accounts for the same user. Opt in:

**Python:**

```python
connection_request = composio.connected_accounts.link(
    user_id="user_123",
    auth_config_id="ac_xxx",
    alias="work-gmail",
    allow_multiple=True,
)
```

**TypeScript:**

```typescript
import { Composio } from '@composio/core';
const composio = new Composio({ apiKey: process.env.COMPOSIO_API_KEY! });
const connectionRequest = await composio.connectedAccounts.link(
  'user_123',
  'ac_xxx',
  { alias: 'work-gmail', allowMultiple: true },
);
```

Pair with a session-level `multiAccount` / `multi_account` config so the agent can disambiguate at execution time. See [Managing multiple connected accounts](/docs/managing-multiple-connected-accounts) for the session shape.

**2. You're migrating from `initiate()` to `link()`** as part of the [Composio-managed OAuth migration](/docs/changelog/2026/04/24). Pass `allow_multiple` / `allowMultiple` through unchanged — same flag name, same default (`False`), same exception (`ComposioMultipleConnectedAccountsError`).

## Why

The migration changelog moves callers off `connected_accounts/create` onto `/link`. `initiate()` had `allow_multiple` and the duplicate-connection check; `link()` didn't. Without this fix, every customer who migrates would silently lose the guard and start creating duplicate `ACTIVE` connections on auth configs that were never meant to hold more than one. This release closes that gap.

---

## SDKs add sandbox compute tier for Tool Router workbench

TypeScript and Python SDKs gain `workbench.sandboxSize` / `workbench.sandbox_size` to pick the workbench sandbox tier (standard, medium, large, xlarge). Patch releases.

The Composio SDKs now let you pick the compute tier of the [workbench](/docs/workbench) sandbox when creating a Tool Router session. Heavier code execution and larger in-memory data benefit from a bigger sandbox.

| Tier       | vCPU | RAM  |
| ---------- | ---- | ---- |
| `standard` | 1    | 1 GB |
| `medium`   | 2    | 2 GB |
| `large`    | 4    | 4 GB |
| `xlarge`   | 8    | 8 GB |

The field is optional and defaults to `standard` server-side when omitted, so existing code keeps working unchanged.

> **Pricing:** Sandboxes are not billed today. Composio plans to begin billing for sandbox usage soon (metered by tier and runtime). Pick a tier that matches your workload — but expect future pricing to track actual usage.

## SDK versions (patch releases)

| Package                     | Previous | This release |
| --------------------------- | -------- | ------------ |
| TypeScript `@composio/core` | v0.8.0   | **v0.8.1**   |
| Python `composio`           | v0.12.0  | **v0.12.1**  |

## Usage

**TypeScript** (camelCase on the SDK surface):

```typescript
import { Composio } from '@composio/core';
const composio = new Composio({ apiKey: process.env.COMPOSIO_API_KEY! });

const session = await composio.create('user_123', {
  workbench: {
    enable: true,
    sandboxSize: 'large',
  },
});
```

The `SandboxSize` literal type and `SandboxSizeSchema` zod enum are exported from `@composio/core`.

**Python** (snake\_case throughout):

```python
session = composio.create(
    user_id="user_123",
    workbench={
        "sandbox_size": "large",
    },
)
```

The `SandboxSize` literal alias is available at `composio.core.models.tool_router.SandboxSize`.

## Updating an existing session

Calling `session.update()` (or the equivalent `PATCH /api/v3/tool_router/sessions/{id}`) with a different `sandbox_size` recreates the sandbox on next access. The sandbox's in-memory filesystem state is lost, but the persistent `/mnt/files/` mount survives the restart.

See [Configuring Sessions → Sandbox compute tier](/docs/configuring-sessions#sandbox-compute-tier) for the full reference.

---