Skip to content
196 changes: 196 additions & 0 deletions apps/docs/content/docs/en/integrations/managed_agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,200 @@ Open a Claude Platform Managed Agent session and return the assistant response a
| `inputTokens` | number | Cumulative input tokens for the session. |
| `outputTokens` | number | Cumulative output tokens for the session. |

### `managed_agent_create_session`

Create a Claude Platform Managed Agent session and return its id without waiting for a reply.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `agent` | string | Yes | Managed-agent id inside the linked Claude workspace. |
| `environment` | string | Yes | Environment id inside the linked Claude workspace. |
| `environmentType` | string | No | Environment execution model hint \('cloud' \| 'self_hosted'\). |
| `userMessage` | string | No | Optional first message; seeds initial_events and starts the agent immediately. |
| `vaults` | array | No | Zero or more vault ids for MCP tool auth. |
| `vaultsAck` | boolean | No | Acknowledgement that the author may use the attached vaults. |
| `memoryStoreId` | string | No | Optional Agent Memory Store id. |
| `memoryAccess` | string | No | Memory store access mode: 'read_write' \(default\) or 'read_only'. |
| `memoryInstructions` | string | No | Per-attachment guidance for how the agent should use the memory store. |
| `files` | array | No | File attachments \(cloud envs only\), as \[\{fileId, mountPath?\}\]. |
| `sessionParameters` | object | No | Key/value session metadata forwarded to the session. |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | Anthropic session id \(sesn_...\). |
| `started` | boolean | True when a first message was seeded, so the agent is already running. |

### `managed_agent_send_message`

Send a user message to an existing Claude Platform Managed Agent session.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `userMessage` | string | Yes | The user message to send to the session. |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | The session the message was sent to. |
| `sent` | boolean | True when the event was accepted by the API. |

### `managed_agent_get_session`

Read a Managed Agent session: status, stop reason, token usage, metadata, and any tool calls awaiting approval.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | The session that was read. |
| `status` | string | Session status — 'idle', 'running', 'rescheduling', or 'terminated'. |
| `stopReason` | string | Why the session last stopped, e.g. 'end_turn' or 'requires_action'. |
| `requiresAction` | boolean | True when the session is waiting on a tool confirmation or custom tool result. If this is true while pendingTools is empty, the session is blocked but the API named no blocking events — surface it rather than treating the session as done. |
| `pendingTools` | json | Blocking tool calls — \[\{id, eventType, kind, name, input\}\]. Route by kind: 'confirmation' ids go to Respond To Tool Confirmation, 'custom_tool_result' ids go to Respond To Custom Tool. |
| `metadata` | json | Session metadata. |
| `title` | string | Session title. |
| `inputTokens` | number | Cumulative input tokens. |
| `outputTokens` | number | Cumulative output tokens. |

### `managed_agent_list_events`

Read a Managed Agent session's event history and the agent's reply text.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `eventTypes` | array | No | Optional event-type filter, e.g. \['agent.message'\]. Omit to return every event. |
| `limit` | number | No | Maximum events to return, keeping the most recent \(default 500\). |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | The session that was read. |
| `events` | json | Session events, oldest first. |
| `count` | number | Number of events returned. |
| `assistantText` | string | Concatenated text of every persisted agent.message, in order. |
| `truncated` | boolean | True when the limit was hit and older events were dropped. |

### `managed_agent_update_session`

Update a Managed Agent session's title or metadata.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `title` | string | No | New session title. |
| `sessionParameters` | object | No | Replacement metadata map \(replaces all stored metadata, not merged\). Leaving it empty leaves the stored metadata unchanged — use clearMetadata to remove it. |
| `clearMetadata` | boolean | No | Removes all of the session's stored metadata. Overrides any map supplied above. |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | The session that was updated. |
| `updated` | boolean | True when the update was accepted. |
| `metadata` | json | Metadata after the update. |
| `title` | string | Title after the update. |

### `managed_agent_interrupt_session`

Stop a running Managed Agent session; it stays usable afterwards.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | The session that was interrupted. |
| `interrupted` | boolean | True when the interrupt was accepted. |

### `managed_agent_respond_tool_confirmation`

Allow or deny the tool calls a Managed Agent session is waiting on before it can continue.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `toolUseIds` | array | Yes | Blocking tool-use EVENT ids, from Get Session pendingTools\[\].id where kind is 'confirmation' \(not toolu_ ids\). |
| `decision` | string | Yes | 'allow' to let the tools run, or 'deny' to reject them. |
| `denyMessage` | string | No | Reason surfaced to the agent. Only sent when the decision is deny. |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | The session that was answered. |
| `decision` | string | The decision applied — 'allow' or 'deny'. |
| `confirmedToolUseIds` | json | The tool-use event ids that were answered. |

### `managed_agent_respond_custom_tool`

Return the result of a custom tool a Managed Agent session is waiting on so it can continue.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `customToolUseId` | string | Yes | The custom tool-use EVENT id being answered, from Get Session pendingTools\[\].id where kind is 'custom_tool_result'. |
| `result` | string | Yes | The tool's output, returned to the agent as text. |
| `isError` | boolean | No | Mark the result as a failure so the agent can adjust its approach. |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | The session that was answered. |
| `answeredToolUseId` | string | The custom tool-use event id that was answered. |

### `managed_agent_archive_session`

Archive a Managed Agent session, preserving its history. Not reversible.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | The session that was archived. |
| `archived` | boolean | True when the archive was accepted. |

### `managed_agent_delete_session`

Permanently delete a Managed Agent session, its events, and its sandbox. Not reversible.

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sessionId` | string | The session that was deleted. |
| `deleted` | boolean | True when the delete was accepted. |


174 changes: 174 additions & 0 deletions apps/sim/blocks/blocks/managed_agent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/**
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
import { evaluateSubBlockCondition } from '@/lib/workflows/subblocks/visibility'
import { ManagedAgentBlock } from '@/blocks/blocks/managed_agent'

const subBlockById = (id: string) => {
const config = ManagedAgentBlock.subBlocks.find((sub) => sub.id === id)
if (!config) throw new Error(`No sub-block '${id}' on the Managed Agent block`)
return config
}

/** Mirrors how the editor and serializer evaluate visibility: raw stored values. */
const isVisible = (id: string, values: Record<string, unknown>) =>
evaluateSubBlockCondition(subBlockById(id).condition, values)

const selectTool = (params: Record<string, unknown>) =>
ManagedAgentBlock.tools.config?.tool?.(params as never)

/**
* The block gained an operation selector after it shipped. Blocks saved before
* that have NO stored `operation` value, so these tests pin the promise that
* they keep behaving — and looking — exactly as they did.
*/
describe('Managed Agent block — legacy blocks without a stored operation', () => {
const legacyValues = {
credential: 'cred-1',
agent: 'agent_1',
environment: 'env_1',
environmentType: 'cloud',
userMessage: 'do the thing',
}

it('resolves to the run-session tool', () => {
expect(selectTool(legacyValues)).toBe('managed_agent_run_session')
})

it('resolves to the run-session tool when operation is explicitly absent', () => {
expect(selectTool({})).toBe('managed_agent_run_session')
expect(selectTool({ operation: undefined })).toBe('managed_agent_run_session')
expect(selectTool({ operation: null })).toBe('managed_agent_run_session')
})

it.each(['agent', 'environment', 'environmentType', 'userMessage'])(
'keeps the %s field visible',
(id) => {
expect(isVisible(id, legacyValues)).toBe(true)
}
)

it('keeps cloud-only fields visible', () => {
expect(isVisible('memoryStoreId', legacyValues)).toBe(true)
expect(isVisible('files', legacyValues)).toBe(true)
expect(isVisible('sessionParameters', legacyValues)).toBe(true)
})

it('still hides cloud-only fields on a self-hosted legacy block', () => {
const selfHosted = { ...legacyValues, environmentType: 'self_hosted' }
expect(isVisible('memoryStoreId', selfHosted)).toBe(false)
expect(isVisible('files', selfHosted)).toBe(false)
// Metadata applies to both environment models.
expect(isVisible('sessionParameters', selfHosted)).toBe(true)
})

it('does not show session-targeting fields', () => {
expect(isVisible('sessionId', legacyValues)).toBe(false)
expect(isVisible('toolUseIds', legacyValues)).toBe(false)
})

it('keeps the legacy run-session output shape as the fallback', () => {
expect(Object.keys(ManagedAgentBlock.outputs)).toEqual(
expect.arrayContaining(['content', 'sessionId', 'inputTokens', 'outputTokens'])
)
})
})

describe('Managed Agent block — operation routing', () => {
it.each([
['run_session', 'managed_agent_run_session'],
['create_session', 'managed_agent_create_session'],
['send_message', 'managed_agent_send_message'],
['get_session', 'managed_agent_get_session'],
['list_events', 'managed_agent_list_events'],
['update_session', 'managed_agent_update_session'],
['interrupt_session', 'managed_agent_interrupt_session'],
['respond_tool_confirmation', 'managed_agent_respond_tool_confirmation'],
['respond_custom_tool', 'managed_agent_respond_custom_tool'],
['archive_session', 'managed_agent_archive_session'],
['delete_session', 'managed_agent_delete_session'],
])('maps %s to %s', (operation, toolId) => {
expect(selectTool({ operation })).toBe(toolId)
})

it('falls back to run session for an unknown operation', () => {
expect(selectTool({ operation: 'not_a_real_operation' })).toBe('managed_agent_run_session')
})

it('declares every mapped tool in tools.access', () => {
const operations = subBlockById('operation').options as Array<{ id: string }>
for (const { id } of operations) {
expect(ManagedAgentBlock.tools.access).toContain(selectTool({ operation: id }))
}
})
})

describe('Managed Agent block — per-operation field visibility', () => {
it('shows the session id for operations that target an existing session', () => {
for (const operation of [
'send_message',
'get_session',
'list_events',
'update_session',
'interrupt_session',
'respond_tool_confirmation',
'respond_custom_tool',
'archive_session',
'delete_session',
]) {
expect(isVisible('sessionId', { operation })).toBe(true)
}
})

it('hides the agent and environment pickers once a session exists', () => {
expect(isVisible('agent', { operation: 'send_message' })).toBe(false)
expect(isVisible('environment', { operation: 'get_session' })).toBe(false)
expect(isVisible('environmentType', { operation: 'archive_session' })).toBe(false)
})

it('shows the user message for the three operations that send one', () => {
expect(isVisible('userMessage', { operation: 'run_session' })).toBe(true)
expect(isVisible('userMessage', { operation: 'create_session' })).toBe(true)
expect(isVisible('userMessage', { operation: 'send_message' })).toBe(true)
expect(isVisible('userMessage', { operation: 'get_session' })).toBe(false)
})

it('makes the user message optional only for create session', () => {
const required = subBlockById('userMessage').required
expect(evaluateSubBlockCondition(required as never, { operation: 'create_session' })).toBe(
false
)
expect(evaluateSubBlockCondition(required as never, { operation: 'send_message' })).toBe(true)
expect(evaluateSubBlockCondition(required as never, { operation: 'run_session' })).toBe(true)
// A legacy block has no stored operation and must stay required.
expect(evaluateSubBlockCondition(required as never, {})).toBe(true)
})

it('reveals the deny reason only when denying a tool confirmation', () => {
expect(
isVisible('denyMessage', { operation: 'respond_tool_confirmation', decision: 'deny' })
).toBe(true)
expect(
isVisible('denyMessage', { operation: 'respond_tool_confirmation', decision: 'allow' })
).toBe(false)
expect(isVisible('denyMessage', { operation: 'send_message', decision: 'deny' })).toBe(false)
})

it('separates confirmation fields from custom-tool-result fields', () => {
// A confirmation cannot unblock a custom tool, so the two operations must
// not share inputs — otherwise a workflow can silently answer the wrong way.
expect(isVisible('toolUseIds', { operation: 'respond_tool_confirmation' })).toBe(true)
expect(isVisible('toolUseIds', { operation: 'respond_custom_tool' })).toBe(false)
expect(isVisible('customToolUseId', { operation: 'respond_custom_tool' })).toBe(true)
expect(isVisible('customToolUseId', { operation: 'respond_tool_confirmation' })).toBe(false)
expect(isVisible('result', { operation: 'respond_custom_tool' })).toBe(true)
expect(isVisible('decision', { operation: 'respond_custom_tool' })).toBe(false)
})

it('shows metadata for update session but not the agent config fields', () => {
expect(isVisible('sessionParameters', { operation: 'update_session' })).toBe(true)
expect(isVisible('title', { operation: 'update_session' })).toBe(true)
expect(isVisible('vaults', { operation: 'update_session' })).toBe(false)
})
})
Binary file modified apps/sim/blocks/blocks/managed_agent.ts
Binary file not shown.
Loading
Loading