Skip to content

Custom Agents Not Registered When System Prompt Exceeds Token Limit #322

@yakirbenaliz

Description

@yakirbenaliz

Bug Report: Custom Agents Not Registered When System Prompt Exceeds Token Limit

Summary

Custom agents defined in ClaudeAgentOptions are silently ignored by ClaudeSDKClient when the prompt is too large. The init message only shows default Cursor agents instead of the custom agents, with no error or warning about token limits being exceeded.

Environment

  • Package: claude-agent-sdk v0.1.6
  • Python: 3.13.7
  • OS: macOS (darwin 24.4.0)

Expected Behavior

When providing custom agents via ClaudeAgentOptions:

  1. Custom agents should appear in the init message agents array
  2. OR an error/warning should be raised if the system prompt + agent definitions exceed token limits
  3. Token limit constraints should be documented
'agents': ['general-purpose', 'statusline-setup', 'Explore', 'Plan', 'custom_agent', ...]

Actual Behavior

When the system prompt is large:

  1. Custom agents are silently ignored - no error or warning
  2. Init message only contains default Cursor agents:
'agents': ['general-purpose', 'statusline-setup', 'Explore', 'Plan']
  1. The Task tool cannot delegate to custom agents and falls back to subagent_type='general-purpose'
  2. No indication that token limits were exceeded

Minimal Reproducible Example

Working: Small System Prompt

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from claude_agent_sdk.types import AgentDefinition

agents = {
    "custom_agent": AgentDefinition(
        description="A custom specialist agent",
        prompt="You are a custom agent.",
        tools=["Read", "Write"],
        model="sonnet",
    ),
}

# Small system prompt - works fine
options = ClaudeAgentOptions(
    system_prompt="You are an orchestrator. Delegate tasks to custom_agent.",
    model="claude-sonnet-4-5-20250929",
    allowed_tools=["Task", "Read", "Write"],
    agents=agents  # ✅ This works - agents appear in init message
)

async with ClaudeSDKClient(options=options) as client:
    await client.query("Test query")
    async for message in client.receive_response():
        if hasattr(message, 'subtype') and message.subtype == 'init':
            print(message.data.get('agents'))
            # Output: ['general-purpose', ..., 'custom_agent'] ✅

Broken: Large System Prompt (Exceeds Token Limit)

from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from claude_agent_sdk.types import AgentDefinition

agents = {
    "custom_agent": AgentDefinition(
        description="A custom specialist agent",
        prompt="You are a custom agent.",
        tools=["Read", "Write"],
        model="sonnet",
    ),
}

# Large system prompt (e.g., >8K tokens with detailed instructions)
large_prompt = """
You are an orchestrator agent.

[... extensive instructions ...]
[... detailed workflow descriptions ...]
[... multiple sections of guidance ...]
[... examples and edge cases ...]

# This prompt is several thousand tokens
""" * 1000  # Simulate large prompt

options = ClaudeAgentOptions(
    system_prompt=large_prompt,
    model="claude-sonnet-4-5-20250929",
    allowed_tools=["Task", "Read", "Write"],
    agents=agents  # ❌ Silently ignored due to token limit!
)

async with ClaudeSDKClient(options=options) as client:
    await client.query("Test query")
    async for message in client.receive_response():
        if hasattr(message, 'subtype') and message.subtype == 'init':
            print(message.data.get('agents'))
            # Output: ['general-purpose', 'statusline-setup', 'Explore', 'Plan'] ❌
            # custom_agent is missing! No error or warning!

Investigation Findings

  1. Internal logging confirms agents are passed correctly:

    logger.info(f"agents dict: {list(agents.keys())}")
    # Output: ['custom_agent', 'another_agent', ...]
    
    logger.info(f"options.agents: {list(options.agents.keys())}")
    # Output: ['custom_agent', 'another_agent', ...]
  2. But init message shows only defaults:

    {'subtype': 'init', 'data': {..., 'agents': ['general-purpose', 'statusline-setup', 'Explore', 'Plan'], ...}}
  3. Consequence: The Task tool cannot delegate to custom agents and falls back to:

    Task(description="...", subagent_type="general-purpose")  # Wrong!
    # Instead of:
    Task(description="...", agent="custom_agent")  # Correct!

Suspected Root Cause

The SDK appears to have an undocumented token limit for the combined system prompt + agent definitions. When this limit is exceeded:

  1. Silent Truncation: Custom agents are silently dropped without any error or warning
  2. No Validation: The SDK doesn't validate or warn about token limits before initialization
  3. Unclear Limits: Documentation doesn't specify:
    • What the token limit is for system prompts
    • Whether agent definitions count toward this limit
    • How the limit is calculated
  4. No Error Handling: Users have no way to know their agents were ignored until runtime behavior is incorrect

Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingplannedThe issue is planned and will be resolved. Claude should never use this label, only humans.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions