Agents SDK

Vault resolution

Every run ends up with an ordered array of vault_ids baked into its JWT. The relay walks five layers top-down; the first non-empty layer wins.

For the concept of a vault and how credentials are injected, see Credential vaults.

Vault resolution decision flow: session vaultIds → externalUserId metadata lookup → agent config vaultIds → workspace default vault → no vaults (request runs unauthenticated).

Stacking vaults

When more than one vault is attached, the proxy walks them in the order you pass. Common pattern: a user's personal vault first, the team's shared vault as fallback.

server.ts
await client.threads.run({
  agent: "my-agent",
  sandboxId: "sbx_123",
  vaultIds: [userVaultId, teamVaultId],
  messages,
})

// First-match-wins by host pattern:
//   userVaultId is checked first for every outbound host
//   teamVaultId fills any gaps the user vault doesn't cover
Multi-vault resolution: when vaultIds contains [aliceVault, teamVault], api.github.com and mcp.notion.com resolve to Alice's credentials; mcp.linear.app (no match in Alice's vault) falls through to the team vault.

Multi-tenant agents

For agents that serve multiple end users, tag each user's vault with metadata.external_user_id and pass externalUserId on the run. The relay finds the matching vault automatically.

server.ts
await client.threads.run({
  agent: "support-agent",
  sandboxId: "sbx_123",
  externalUserId: "usr_123",
  messages,
})

// Relay looks up vaults where:
//   metadata.external_user_id === "usr_123"
Multi-tenant pattern: one shared agent definition serves three sessions (usr_alice, usr_bob, usr_carol), each resolved to the user's own vault via metadata.external_user_id lookup. Same agent, same MCP server, different real credential per end user.
⚠️ Warning — Metadata is returned in clear on GET responses. Do not store tokens, passwords, API keys, or client secrets in metadata.

More resources