SDK_TOOLS_BLOCKED in Letta SDK Sessions: Why Interactive Tools Are Restricted

SDK_TOOLS_BLOCKED is a constant array defined in the Letta Code SDK that explicitly prohibits AskUserQuestion, EnterPlanMode, and ExitPlanMode from executing during autonomous background sessions to prevent process hangs and ensure deterministic, non-interactive execution.

In the letta-ai/claude-subconscious repository, the Letta Code SDK imposes strict constraints on which client-side tools can run in automated environments. The SDK_TOOLS_BLOCKED constant serves as a critical safety mechanism that filters out interactive capabilities when Subconscious agents operate in fire-and-forget SDK sessions.

What Is SDK_TOOLS_BLOCKED?

Defined in scripts/conversation_utils.ts, SDK_TOOLS_BLOCKED is an exported constant containing the exact names of tools that are categorically disallowed in SDK contexts.

// scripts/conversation_utils.ts
export const SDK_TOOLS_BLOCKED = [
  'AskUserQuestion',
  'EnterPlanMode',
  'ExitPlanMode',
];

The same list is hardcoded in the background worker initialization logic within scripts/send_worker_sdk.ts, ensuring consistency across the SDK surface:

// scripts/send_worker_sdk.ts
const blockedTools = ['AskUserQuestion', 'EnterPlanMode', 'ExitPlanMode'];

Why These Tools Are Restricted in SDK Sessions

SDK sessions are designed as deterministic, non-interactive execution environments launched via detached processes (npx tsx send_worker_sdk.ts <payload>). The three blocked tools violate this architectural constraint by requiring human intervention or UI interaction.

AskUserQuestion: The Interactive Input Problem

AskUserQuestion prompts the user for interactive input (e.g., "What should I do next?"). SDK sessions run as background workers without a user interface or event loop for human interaction. Allowing this tool would cause the worker to block indefinitely, creating a deadlock scenario on headless servers.

EnterPlanMode and ExitPlanMode: The Supervision Requirement

EnterPlanMode switches the agent into a planning state where it generates multi-step plans that expect user or supervising UI review. ExitPlanMode ends this state and returns to normal conversation flow.

These modes are designed for supervised workflows where a human reviews generated plans. In autonomous SDK sessions, no such supervision exists, so allowing EnterPlanMode without oversight would leave the agent in an unsupported state. Blocking both tools guarantees the SDK never enters plan mode, maintaining predictable execution flow.

How SDK Tool Restrictions Are Implemented

The restriction mechanism operates at the session initialization layer. When send_worker_sdk.ts creates an SDK session, it constructs a sessionOptions object that explicitly sets disallowedTools to the blocked list (see lines 46-53 in scripts/send_worker_sdk.ts).

In read-only mode, the SDK applies an additional filter, allowing only a curated subset of safe tools: Read, Grep, Glob, web_search, and fetch_webpage. All other tools—including the blocked ones—are filtered out regardless of the permission mode selected.

This dual-layer approach ensures that:

  1. Safety and resource control prevent runaway processes or deadlocks
  2. Permission model enforcement guarantees that even if a session is compromised, interactive tools cannot execute

Working with SDK_TOOLS_BLOCKED in Your Code

Checking Tool Permissions

Use the exported constant to validate tool eligibility before invoking SDK methods:

import { SDK_TOOLS_BLOCKED } from './conversation_utils.js';

function isToolAllowed(toolName: string, mode: 'read-only' | 'full' | 'off'): boolean {
  if (mode === 'off') return false;            // no client-side tools at all
  if (SDK_TOOLS_BLOCKED.includes(toolName)) return false;
  // additional logic for read-only vs full can be added here
  return true;
}

Overriding the Block List (Advanced)

If you must enable a blocked tool in a controlled environment with UI supervision, manually construct the sessionOptions object:

import { resumeSession } from '@letta-ai/letta-code-sdk';

const allowedTools = ['Read', 'Grep', 'Glob', 'web_search', 'fetch_webpage', 'AskUserQuestion'];
const session = resumeSession(conversationId, {
  allowedTools,
  disallowedTools: [],                 // empty to avoid double-blocking
  permissionMode: 'bypassPermissions',
});

Warning: Enabling a blocked tool removes the safety guard and may cause the worker to hang waiting for user input that will never arrive.

Summary

  • SDK_TOOLS_BLOCKED is defined in scripts/conversation_utils.ts and lists AskUserQuestion, EnterPlanMode, and ExitPlanMode as prohibited tools
  • These tools are restricted because SDK sessions are fire-and-forget background processes without UI capabilities or human supervision
  • The block list is enforced in scripts/send_worker_sdk.ts via the sessionOptions.disallowedTools parameter during session initialization
  • Read-only mode further restricts tools to a safe subset (Read, Grep, Glob, web_search, fetch_webpage)
  • Developers can check against the constant programmatically, though overriding the restrictions risks deadlocks and is not recommended for production environments

Frequently Asked Questions

What specific tools are included in SDK_TOOLS_BLOCKED?

The constant contains exactly three tools: AskUserQuestion, EnterPlanMode, and ExitPlanMode. These represent all client-side tools in the Letta Code SDK that require interactive user input or supervised planning workflows.

Why does AskUserQuestion cause problems in SDK sessions?

SDK sessions execute as detached background processes launched via npx tsx send_worker_sdk.ts. There is no attached terminal or UI event loop to receive user input. Invoking AskUserQuestion would trigger a prompt that waits indefinitely for a response that cannot arrive, effectively deadlocking the worker process.

Where is the blocked tool list actually enforced in the codebase?

The list is defined in scripts/conversation_utils.ts and applied in scripts/send_worker_sdk.ts. Specifically, lines 46-53 in the worker script construct the sessionOptions object that passes the disallowedTools array to the SDK session constructor, creating the runtime enforcement boundary.

Can I override SDK_TOOLS_BLOCKED to enable interactive tools in my application?

Yes, by manually constructing sessionOptions with permissionMode: 'bypassPermissions' and an empty disallowedTools array, you can enable blocked tools. However, this is only safe if you have implemented a custom UI wrapper to handle the interactive prompts. Without such infrastructure, the SDK session will hang indefinitely, making this approach unsuitable for headless or automated deployments.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →