
Deepagents Setup Configuration
- 26 installs
- 100 repo stars
- Updated February 17, 2026
- lubu-labs/langchain-agent-skills
Helps with ai & agent building tasks.
About
deepagents-setup-configuration is a Claude Code skill in the AI & Agent Building category.
- deepagents-setup-configuration
- AI & Agent Building
- AI-coding skill
Deepagents Setup Configuration by the numbers
- 26 all-time installs (skills.sh)
- Ranked #9,702 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/lubu-labs/langchain-agent-skills --skill deepagents-setup-configurationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 26 |
|---|---|
| repo stars | ★ 100 |
| Last updated | February 17, 2026 |
| Repository | lubu-labs/langchain-agent-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Deep Agents Setup and Configuration
Deep Agents are an agent harness on top of LangChain + LangGraph with built-in planning, filesystem context management, and subagent delegation.
Use This Skill When
- You need a Deep Agent quickly (Python or JavaScript).
- You need subagents, filesystem-backed context, planning (
write_todos), or long-term memory patterns. - You need migration guidance from older
create_react_agentflows. - You need to scaffold a starter project with repository scripts.
- You need to statically validate an
agent.py/agent.js/agent.tsconfig. - You need safety checks before open-sourcing Deep Agents examples/templates.
Tooling In This Skill
scripts/init_deep_agent_project.py: scaffolds Python/JS projects with templates.scripts/validate_deep_agent_config.py: static checks for Deep Agent config quality.references/deep-agents-reference.md: detailed API, middleware, backends, migration, troubleshooting.assets/templates/deep-agent-simple/: minimal Python starter template.assets/examples/basic-deep-agent/: richer Python example.
Recommended Workflow
1. Decide if Deep Agents is the right abstraction. 2. Scaffold with init_deep_agent_project.py (Python or JS). 3. Customize tools, prompt, backend, subagents, and persistence. 4. Run validate_deep_agent_config.py. 5. Use references/deep-agents-reference.md for advanced configuration. 6. Run the generated project and verify traces/behavior.
Choose The Right Abstraction
| Need | Deep Agents | LangChain create_agent | LangGraph |
|---|---|---|---|
| Built-in planning/filesystem/subagents | ✅ Best fit | ⚠️ Manual middleware setup | ❌ Manual graph design |
| Fast path for complex multi-step tasks | ✅ | ⚠️ | ⚠️ |
| Fully custom graph topology | ❌ | ❌ | ✅ Best fit |
| Minimal/simple agent (1-3 steps) | ⚠️ Overhead | ✅ Best fit | ⚠️ |
Initialize A Project
Use repo-local scripts and prefer uv run.
# Python simple template
uv run skills/deepagents-setup-configuration/scripts/init_deep_agent_project.py my-agent --language python --template simple --path skills/
# Python with subagents
uv run skills/deepagents-setup-configuration/scripts/init_deep_agent_project.py my-agent --language python --template with-subagents --path skills/
# Python CLI-config template (memory/checkpointer toggles)
uv run skills/deepagents-setup-configuration/scripts/init_deep_agent_project.py my-agent --language python --template cli-config --path skills/
# JavaScript template
uv run skills/deepagents-setup-configuration/scripts/init_deep_agent_project.py my-agent --language javascript --template simple --path skills/Templates currently supported by the script:
simplewith-subagentscli-config
Generated outputs include:
agent.pyoragent.jstools/example_tools.pyortools/example_tools.js.env.exampleREADME.md.gitignorepyproject.toml(Python) orpackage.json(JavaScript)
Validate Agent Configuration
Run static validation before shipping examples/templates:
uv run skills/deepagents-setup-configuration/scripts/validate_deep_agent_config.py path/to/agent.py
uv run skills/deepagents-setup-configuration/scripts/validate_deep_agent_config.py path/to/agent.js
uv run skills/deepagents-setup-configuration/scripts/validate_deep_agent_config.py path/to/agent.tsValidator behavior:
- Errors on missing agent calls or invalid file types.
- Warns on risky/weak configs (missing prompt, odd backend usage, deprecated models).
- Supports dynamic config patterns (
create_deep_agent(**kwargs),createDeepAgent(config)), with warning that some static checks are skipped. - Validates HITL style:
interrupt_on/interruptOnshould be mapping/object, and requires checkpointer.
Current Deep Agents Defaults (Verified)
Default middleware includes: 1. TodoListMiddleware 2. FilesystemMiddleware 3. SubAgentMiddleware 4. SummarizationMiddleware 5. AnthropicPromptCachingMiddleware 6. PatchToolCallsMiddleware
Conditionally added middleware:
MemoryMiddlewarewhenmemoryis setSkillsMiddlewarewhenskillsis setHumanInTheLoopMiddlewarewheninterrupt_on/interruptOnis set
Core Configuration Patterns
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-5-20250929", # string or model object
tools=[...],
system_prompt="...",
subagents=[...], # optional delegation specialists
middleware=[...], # optional custom middleware
store=store, # needed for StoreBackend patterns
backend=backend_factory, # State/Store/Filesystem/Composite
checkpointer=checkpointer # required for HITL interrupts
)Backend guidance:
StateBackend(default): thread-scoped, ephemeral.StoreBackend: persistent files via LangGraph store (requiresstore=).CompositeBackend: route prefixes (common/memories/->StoreBackend).FilesystemBackend: direct disk access; use carefully, prefervirtual_mode=Truewithroot_dir.
HITL And Persistence
If using human approval interrupts:
- Python: use
interrupt_on={...} - JavaScript: use
interruptOn={...} - Always provide a checkpointer (
InMemorySaver,MemorySaver, Sqlite/Postgres saver, etc.)
Migration Guidance
langgraph.prebuilt.create_react_agentis deprecated in LangGraph v1.- For standard agents, prefer
langchain.agents.create_agent. - For harness capabilities (planning/filesystem/subagents), use
deepagents.create_deep_agent/createDeepAgent.
Versioning Note
deepagentsis currently a pre-1.0 package, so minor-version upgrades may include API changes.- Re-validate generated templates and examples when bumping
deepagentsversions.
Open-Source Safety Checklist
Before publishing this skill:
- Ensure no real secrets are committed (
.env.examplemust stay placeholder-only). - Remove generated artifacts like
__pycache__/and*.pycfrom skill folders. - Avoid absolute local paths in code/examples.
- Keep provider credentials in environment variables only.
- Re-run validator on all shipped
agent.py/agent.jstemplates.
Troubleshooting Quick Hits
- Model/tool-call errors: verify tool-calling model and provider credentials.
- Files not persisting: confirm
StoreBackendroute +store=wiring. - HITL not interrupting: verify interrupt mapping/object and checkpointer.
- Too much overhead for simple tasks: use
create_agentor plain LangGraph.
Resources
references/deep-agents-reference.mdfor detailed API and migration patterns.assets/templates/deep-agent-simple/for minimal template files.assets/examples/basic-deep-agent/for a fuller runnable example.- Python docs: https://docs.langchain.com/oss/python/deepagents/overview
- JavaScript docs: https://docs.langchain.com/oss/javascript/deepagents/overview
- LangGraph v1 migration: https://docs.langchain.com/oss/python/migrate/langgraph-v1
#!/usr/bin/env python3
"""
Basic Deep Agent Example
A working end-to-end example demonstrating:
- Agent creation with create_deep_agent()
- Custom tool definition and usage
- Message-based invocation
- Automatic middleware (todos, filesystem, subagents)
"""
import os
from typing import Optional
from deepagents import create_deep_agent
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
from dotenv import load_dotenv
load_dotenv()
# Define custom tools
@tool
def get_weather(city: str, units: str = "fahrenheit") -> str:
"""
Get current weather for a city.
Args:
city: Name of the city
units: Temperature units (fahrenheit or celsius)
Returns:
Weather information as a string
"""
# In a real implementation, this would call a weather API
weather_data = {
"san francisco": {"temp": 72, "condition": "Sunny"},
"new york": {"temp": 68, "condition": "Cloudy"},
"london": {"temp": 59, "condition": "Rainy"},
"tokyo": {"temp": 75, "condition": "Clear"},
}
city_lower = city.lower()
if city_lower in weather_data:
data = weather_data[city_lower]
temp = data["temp"]
if units == "celsius":
temp = round((temp - 32) * 5/9)
unit_symbol = "°C"
else:
unit_symbol = "°F"
return f"Weather in {city}: {data['condition']}, {temp}{unit_symbol}"
else:
return f"Weather data not available for {city}"
@tool
def calculate(expression: str) -> str:
"""
Evaluate a mathematical expression.
Args:
expression: Mathematical expression to evaluate (e.g., "2 + 2", "10 * 5")
Returns:
Result of the calculation
"""
try:
# Safe evaluation of mathematical expressions
# In production, use a proper math parser library
allowed_chars = set("0123456789+-*/()., ")
if not all(c in allowed_chars for c in expression):
return "Error: Expression contains invalid characters"
result = eval(expression, {"__builtins__": {}}, {})
return f"Result: {result}"
except Exception as e:
return f"Error evaluating expression: {str(e)}"
@tool
def search_documentation(topic: str, language: Optional[str] = None) -> str:
"""
Search programming documentation.
Args:
topic: Topic to search for (e.g., "async/await", "list comprehension")
language: Programming language (e.g., "python", "javascript")
Returns:
Documentation summary
"""
# In a real implementation, this would search actual documentation
docs = {
"async/await": {
"python": "Async/await in Python allows you to write asynchronous code using async def and await keywords.",
"javascript": "Async/await in JavaScript provides a cleaner syntax for working with Promises."
},
"list comprehension": {
"python": "List comprehensions provide a concise way to create lists: [x**2 for x in range(10)]"
},
"destructuring": {
"javascript": "Destructuring allows unpacking values from arrays or properties from objects: const { name, age } = person;"
}
}
topic_lower = topic.lower()
if topic_lower in docs:
if language and language.lower() in docs[topic_lower]:
return f"Documentation for '{topic}' in {language}:\n\n{docs[topic_lower][language.lower()]}"
else:
# Return first available documentation
lang, doc = next(iter(docs[topic_lower].items()))
return f"Documentation for '{topic}' ({lang}):\n\n{doc}"
else:
return f"No documentation found for '{topic}'"
# Create the Deep Agent
agent = create_deep_agent(
model=ChatAnthropic(
model="claude-sonnet-4-5-20250929",
temperature=0.7,
api_key=os.getenv("ANTHROPIC_API_KEY")
),
tools=[get_weather, calculate, search_documentation],
system_prompt="""You are a helpful AI assistant with access to various tools.
Available tools:
- get_weather: Get current weather for any city
- calculate: Evaluate mathematical expressions
- search_documentation: Search programming documentation
You also have automatic middleware providing:
- write_todos: Break down complex tasks into subtasks
- read_file/write_file: Read and write files for managing information
- task: Delegate work to subagents (when configured)
When the user asks a question:
1. Determine which tools are needed
2. Use the tools to gather information
3. Provide a clear, helpful response
For complex multi-step tasks, use the write_todos tool to break them down.""",
)
def run_example(query: str) -> str:
"""
Run a single query against the agent.
Args:
query: User query to process
Returns:
Agent's response
"""
result = agent.invoke({
"messages": [
{
"role": "user",
"content": query
}
]
})
# Extract the final message content
return result["messages"][-1].content
def interactive_mode():
"""Run the agent in interactive mode."""
print("=== Basic Deep Agent - Interactive Mode ===")
print("Ask me anything! (Type 'exit' to quit)\n")
while True:
try:
query = input("You: ").strip()
if query.lower() in ["exit", "quit", "q"]:
print("Goodbye!")
break
if not query:
continue
print("\nAgent: ", end="", flush=True)
response = run_example(query)
print(response)
print()
except KeyboardInterrupt:
print("\n\nGoodbye!")
break
except Exception as e:
print(f"\nError: {e}\n")
if __name__ == "__main__":
import sys
# Check if API key is set
if not os.getenv("ANTHROPIC_API_KEY"):
print("Error: ANTHROPIC_API_KEY environment variable not set")
print("Set it with: export ANTHROPIC_API_KEY='your-key-here'")
print("Or add it to a .env file in this directory.")
sys.exit(1)
# If arguments provided, run single query
if len(sys.argv) > 1:
query = " ".join(sys.argv[1:])
print(f"Query: {query}\n")
response = run_example(query)
print(f"Response: {response}")
else:
# Otherwise, run example queries
print("=== Basic Deep Agent Examples ===\n")
# Example 1: Simple tool usage
print("Example 1: Weather Query")
print("-" * 50)
response = run_example("What's the weather like in San Francisco?")
print(response)
print()
# Example 2: Calculation
print("Example 2: Mathematical Calculation")
print("-" * 50)
response = run_example("Calculate 15 * 23 + 47")
print(response)
print()
# Example 3: Documentation search
print("Example 3: Documentation Search")
print("-" * 50)
response = run_example("How do async/await work in Python?")
print(response)
print()
# Example 4: Multiple tools
print("Example 4: Multiple Tools")
print("-" * 50)
response = run_example(
"What's the weather in Tokyo and New York? "
"Also calculate what 20% of 150 is."
)
print(response)
print()
# Offer interactive mode
print("\nWould you like to try interactive mode? (y/n): ", end="", flush=True)
choice = input().strip().lower()
if choice == "y":
print()
interactive_mode()
Basic Deep Agent Example
Minimal working Deep Agent example in Python.
Files
agent.py: Python example
Setup
Install dependencies (latest compatible ecosystem packages):
uv init
uv add deepagents langchain langgraph langchain-anthropic python-dotenv
uv syncSet your model provider key:
export ANTHROPIC_API_KEY="your-key-here"
# or
export OPENAI_API_KEY="your-key-here"Optional LangSmith tracing:
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="your-langsmith-key"
export LANGSMITH_PROJECT="basic-deep-agent"Run
uv run agent.pyNotes
- The example demonstrates custom tools, message-based invocation, and interactive mode.
- It uses Anthropic model configuration and requires valid credentials.
# LLM provider API key (required for this template)
ANTHROPIC_API_KEY=your-anthropic-api-key-here
# Optional if you switch models/providers
OPENAI_API_KEY=your-openai-api-key-here
# LangSmith tracing (optional)
LANGSMITH_TRACING=true
LANGSMITH_API_KEY=your-langsmith-api-key-here
LANGSMITH_PROJECT=deep-agent-simple
#!/usr/bin/env python3
"""
Simple Deep Agent Example
A basic Deep Agent with minimal configuration, demonstrating core functionality
with automatic middleware (todos, filesystem, subagents).
"""
import os
from deepagents import create_deep_agent
from dotenv import load_dotenv
from langchain_anthropic import ChatAnthropic
# Load values from .env if present.
load_dotenv()
def get_weather(city: str) -> str:
"""
Get current weather for a city.
Args:
city: Name of the city
Returns:
Weather information as a string
"""
# In production, call a real weather API
return f"Weather in {city}: Sunny, 72°F"
def search_web(query: str) -> str:
"""
Search the web for information.
Args:
query: Search query
Returns:
Search results as a string
"""
# In production, call a real search API
return f"Search results for '{query}': [Example results...]"
# Create Deep Agent with automatic middleware
agent = create_deep_agent(
model=ChatAnthropic(model="claude-sonnet-4-5-20250929"),
tools=[get_weather, search_web],
system_prompt="""You are a helpful AI assistant with access to weather and search tools.
For complex tasks, break them down using the write_todos tool.
Use the filesystem tools (read_file, write_file) to manage large amounts of information.
Delegate specialized tasks to subagents using the task tool when appropriate.""",
)
if __name__ == "__main__":
if not os.getenv("ANTHROPIC_API_KEY") and not os.getenv("OPENAI_API_KEY"):
print("Error: ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable not set")
print("Set it in .env or export it in your shell before running.")
raise SystemExit(1)
# Example usage
result = agent.invoke({
"messages": [
{
"role": "user",
"content": "What's the weather in San Francisco? Also search for the latest tech news."
}
]
})
print("\n=== Agent Response ===")
print(result["messages"][-1].content)
[project]
name = "deep-agent-simple"
version = "0.1.0"
description = "Simple Deep Agent example"
requires-python = ">=3.11"
dependencies = [
"deepagents>=0.4.0",
"langchain>=1.0.0",
"langgraph>=1.0.0",
"langchain-anthropic>=0.3.0",
"python-dotenv>=1.0.0",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.uv]
dev-dependencies = [
"pytest>=8.0.0",
"pytest-asyncio>=0.23.0",
]
Simple Deep Agent
A minimal Deep Agent setup with built-in planning, filesystem, and subagent capabilities.
Features
- ✅ Automatic task planning with
write_todostool - ✅ Filesystem context management with
ls,read_file,write_file,edit_file - ✅ Subagent delegation with
tasktool - ✅ Custom tools (weather, search)
Setup
1. Install dependencies:
uv sync2. Configure environment:
cp .env.example .env
# Edit .env and add your API keys3. Run the agent:
uv run agent.pyProject Structure
.
├── agent.py # Main agent definition
├── pyproject.toml # Dependencies
├── .env.example # Environment template
└── README.md # This fileCustomization
Add Custom Tools
def my_custom_tool(arg: str) -> str:
"""Tool description."""
return result
agent = create_deep_agent(
model=model,
tools=[get_weather, search_web, my_custom_tool], # Add your tool
system_prompt="...",
)Configure Middleware
from langchain.agents.middleware import TodoListMiddleware
from deepagents.middleware.filesystem import FilesystemMiddleware
agent = create_deep_agent(
model=model,
tools=tools,
middleware=[
TodoListMiddleware(system_prompt="Custom planning instructions"),
FilesystemMiddleware(),
# SubAgentMiddleware omitted - no subagents
],
)Add Persistence
from langgraph.checkpoint.memory import InMemorySaver
agent = create_deep_agent(
model=model,
tools=tools,
checkpointer=InMemorySaver(), # Add checkpointing
)
# Use with thread_id for multi-turn conversations
result = agent.invoke(
{"messages": [...]},
config={"configurable": {"thread_id": "user-123"}},
)Next Steps
- Add more tools for your use case
- Configure persistence with checkpointers
- Set up long-term memory with Memory Store
- Deploy with LangSmith (see langsmith-deployment skill)
Deep Agents Reference
Comprehensive reference for Deep Agents configuration, middleware, backends, and migration patterns.
create_deep_agent API
Essential Parameters
from deepagents import create_deep_agent
agent = create_deep_agent(
model="claude-sonnet-4-5-20250929", # Tool-calling model
tools=[tool1, tool2], # Optional custom tools
system_prompt="Instructions", # Optional custom system prompt
middleware=[...], # Optional custom middleware
subagents=[...], # Optional specialist subagents
store=memory_store, # Optional long-term store
checkpointer=checkpointer, # Optional thread persistence
backend=backend_fn, # Optional filesystem backend
)Returns: CompiledStateGraph compatible with LangGraph streaming, persistence, and Studio tooling.
Key Parameters
model: Model string (includingprovider:modelformat) or chat model objecttools: List of functions/tools available to the agentsystem_prompt: Instructions layered on top of Deep Agents defaultsmiddleware: Additional middleware hookssubagents: Specialist subagents for delegation/context isolationstore: LangGraph store for cross-thread memorycheckpointer: Checkpointer for thread-level state persistencebackend: Filesystem backend factory/object (state, store, local disk, or composite)
Default Middleware
Deep Agents includes these middleware by default:
1. TodoListMiddleware (planning with write_todos) 2. FilesystemMiddleware (ls, read_file, write_file, edit_file) 3. SubAgentMiddleware (delegation via task) 4. SummarizationMiddleware (history compression) 5. AnthropicPromptCachingMiddleware (prompt caching) 6. PatchToolCallsMiddleware (tool-call correction)
Conditional middleware:
MemoryMiddlewarewhenmemoryis providedSkillsMiddlewarewhenskillsis providedHumanInTheLoopMiddlewarewheninterrupt_onis provided
Custom Middleware Example
from langchain.tools import tool
from langchain.agents.middleware import wrap_tool_call
from deepagents import create_deep_agent
@tool
def get_weather(city: str) -> str:
"""Get weather in a city."""
return f"The weather in {city} is sunny."
@wrap_tool_call
def log_tool_calls(request, handler):
print(f"Tool call: {request.name}")
return handler(request)
agent = create_deep_agent(
tools=[get_weather],
middleware=[log_tool_calls],
)Backends
StateBackend (default)
- Files live in graph state
- Ephemeral per thread
StoreBackend
- Files live in LangGraph store
- Persistent across threads
- Requires passing
store=tocreate_deep_agent
FilesystemBackend
- Uses local disk
- Use
virtual_mode=Truewithroot_dirfor path restrictions - Use cautiously in production-exposed environments
CompositeBackend
- Routes path prefixes to different backends (common pattern:
/memories/persistent, everything else ephemeral)
from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
agent = create_deep_agent(
store=store,
backend=lambda rt: CompositeBackend(
default=StateBackend(rt),
routes={"/memories/": StoreBackend(rt)},
),
)Checkpointers and Persistence
For short-term memory/thread persistence, pass a checkpointer and invoke with a thread_id:
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import InMemorySaver
agent = create_deep_agent(
model="claude-sonnet-4-5-20250929",
checkpointer=InMemorySaver(),
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "Hello"}]},
config={"configurable": {"thread_id": "demo-thread"}},
)Migration Patterns
LangChain create_agent -> create_deep_agent
# Before
from langchain.agents import create_agent
agent = create_agent(model=model, tools=tools, system_prompt=prompt)
# After
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, tools=tools, system_prompt=prompt)Legacy create_react_agent
langgraph.prebuilt.create_react_agent is deprecated in LangGraph v1. Prefer langchain.agents.create_agent or deepagents.create_deep_agent depending on whether you want the Deep Agents harness.
Supervisor Graph -> Built-in Subagents
agent = create_deep_agent(
model="claude-sonnet-4-5-20250929",
subagents=[
{"name": "researcher", "description": "Research specialist", "tools": [...], "system_prompt": "..."},
{"name": "coder", "description": "Code specialist", "tools": [...], "system_prompt": "..."},
],
)Common Patterns
Minimal Agent
agent = create_deep_agent(
model="claude-sonnet-4-5-20250929",
tools=[my_tool],
)Persistent Checkpoints
from langgraph.checkpoint.sqlite import SqliteSaver
agent = create_deep_agent(
model="claude-sonnet-4-5-20250929",
checkpointer=SqliteSaver.from_conn_string("checkpoints.db"),
)Human-in-the-Loop
agent = create_deep_agent(
model="claude-sonnet-4-5-20250929",
checkpointer=checkpointer,
interrupt_on={
"write_file": True,
"edit_file": True,
"read_file": False,
},
)Troubleshooting
Model/tool-calling issues
- Use a tool-calling-capable model
- Prefer explicit model identifiers (including
provider:modelformat)
Filesystem behavior is unexpected
- Confirm backend choice (
StateBackend,StoreBackend,FilesystemBackend, orCompositeBackend) - If using
StoreBackend, verifystore=is configured
Subagent delegation is weak
- Improve subagent descriptions/system prompts
- Ensure subagents have the right specialized tools
Performance overhead
- Deep Agents adds harness overhead by design
- For very simple flows, consider plain LangChain/LangGraph agents
See Also
- Deep Agents Overview (Python)
- Customize Deep Agents (Python)
- Deep Agents Backends (Python)
- Deep Agents Overview (JavaScript)
- langgraph-project-setup
- langgraph-agent-patterns
- langsmith-deployment
node_modules/
#!/usr/bin/env python3
"""
Initialize a new Deep Agent project with proper structure and configuration.
Usage:
uv run init_deep_agent_project.py <project-name> [options]
Fallback:
python3 init_deep_agent_project.py <project-name> [options]
Options:
--language LANG Language: python or javascript (default: python)
--template TEMPLATE Template: simple, with-subagents, or cli-config (default: simple)
--path PATH Output directory (default: current directory)
"""
import argparse
import json
import sys
from pathlib import Path
from typing import Literal
def create_directory_structure(
project_path: Path,
language: Literal["python", "javascript"]
) -> None:
"""Create the Deep Agent project directory structure."""
# Create main directory
project_path.mkdir(parents=True, exist_ok=True)
# Create subdirectories
(project_path / "tools").mkdir(exist_ok=True)
if language == "python":
# Create __init__.py files for Python package
(project_path / "__init__.py").write_text("")
(project_path / "tools" / "__init__.py").write_text("")
def create_agent_file(
project_path: Path,
language: Literal["python", "javascript"],
template: Literal["simple", "with-subagents", "cli-config"]
) -> None:
"""Create the main agent file based on language and template."""
if language == "python":
if template == "simple":
content = get_simple_python_template()
elif template == "with-subagents":
content = get_subagents_python_template()
else: # cli-config
content = get_cli_config_python_template()
file_path = project_path / "agent.py"
else: # javascript
if template == "simple":
content = get_simple_javascript_template()
elif template == "with-subagents":
content = get_subagents_javascript_template()
else: # cli-config
content = get_cli_config_javascript_template()
file_path = project_path / "agent.js"
file_path.write_text(content)
def create_tools_file(
project_path: Path,
language: Literal["python", "javascript"]
) -> None:
"""Create example tools file."""
if language == "python":
content = '''"""Example tools for the Deep Agent."""
from langchain_core.tools import tool
@tool
def search_web(query: str) -> str:
"""Search the web for information.
Args:
query: The search query
Returns:
Search results as a string
"""
# TODO: Implement actual web search
return f"Search results for: {query}"
@tool
def calculate(expression: str) -> str:
"""Perform a mathematical calculation.
Args:
expression: The mathematical expression to evaluate
Returns:
The result of the calculation
"""
try:
result = eval(expression, {"__builtins__": {}}, {})
return str(result)
except Exception as e:
return f"Error: {str(e)}"
# List of all tools
tools = [search_web, calculate]
'''
file_path = project_path / "tools" / "example_tools.py"
else: # javascript
content = '''/**
* Example tools for the Deep Agent.
*/
export function searchWeb(query) {
// TODO: Implement actual web search
return `Search results for: ${query}`;
}
export function calculate(expression) {
try {
// WARNING: eval is dangerous in production - use a proper math parser
const result = eval(expression);
return String(result);
} catch (e) {
return `Error: ${e.message}`;
}
}
// List of all tools
export const tools = [searchWeb, calculate];
'''
file_path = project_path / "tools" / "example_tools.js"
file_path.write_text(content)
def create_env_file(project_path: Path) -> None:
"""Create .env.example file with common environment variables."""
content = """# LangSmith Configuration (optional - for tracing and monitoring)
# LANGSMITH_API_KEY=your-api-key-here
# LANGSMITH_TRACING=true
# LANGSMITH_PROJECT=your-project-name
# LLM Provider API Keys (uncomment the one you need)
# OPENAI_API_KEY=your-openai-api-key-here
# ANTHROPIC_API_KEY=your-anthropic-api-key-here
# GOOGLE_API_KEY=your-google-api-key-here
# Other API Keys
# TAVILY_API_KEY=your-tavily-api-key-here
"""
(project_path / ".env.example").write_text(content)
def create_readme(
project_path: Path,
project_name: str,
language: Literal["python", "javascript"],
template: Literal["simple", "with-subagents", "cli-config"]
) -> None:
"""Create README.md file."""
if language == "python":
setup_commands = """## Setup
1. Create a virtual environment:
```bash
uv venv --python=3.12
# or: python3 -m venv venv
```
2. Activate the environment:
```bash
source .venv/bin/activate
# or: source venv/bin/activate
```
3. Install dependencies:
```bash
uv sync
# or: pip install -e .
```
4. Configure environment variables:
```bash
cp .env.example .env
# Edit .env with your API keys
```
5. Run the agent:
```bash
uv run agent.py
# or: python3 agent.py
```"""
else:
setup_commands = """## Setup
1. Install dependencies:
```bash
npm install deepagents langchain @langchain/core @langchain/langgraph
```
2. Configure environment variables:
```bash
cp .env.example .env
# Edit .env with your API keys
```
3. Run the agent:
```bash
node agent.js
```"""
template_description = {
"simple": "A simple Deep Agent with basic tools",
"with-subagents": "A Deep Agent with subagent delegation capabilities",
"cli-config": "A Deep Agent configured for CLI-style usage"
}
content = f"""# {project_name}
{template_description[template]}
{setup_commands}
## Project Structure
- `agent.{('py' if language == 'python' else 'js')}` - Main Deep Agent implementation
- `tools/` - Custom tools for the agent
- `.env.example` - Environment variable template
## Documentation
- [Deep Agents Documentation](https://docs.langchain.com/oss/{'python' if language == 'python' else 'javascript'}/deepagents/overview)
- [LangChain Documentation](https://docs.langchain.com/)
## Next Steps
1. Customize the system prompt in `agent.{('py' if language == 'python' else 'js')}`
2. Add your own tools in the `tools/` directory
3. Configure middleware and backends as needed
4. Test with various inputs and scenarios
"""
(project_path / "README.md").write_text(content)
def create_pyproject_toml(project_path: Path, project_name: str) -> None:
"""Create pyproject.toml for Python projects."""
package_name = project_name.replace("-", "_")
content = f"""[project]
name = "{package_name}"
version = "0.1.0"
description = "Deep Agent application"
requires-python = ">=3.11"
dependencies = [
"deepagents",
"langchain",
"langchain-core",
"langgraph",
]
[project.optional-dependencies]
openai = ["langchain-openai"]
anthropic = ["langchain-anthropic"]
google = ["langchain-google-genai"]
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
"""
(project_path / "pyproject.toml").write_text(content)
def create_package_json(project_path: Path, project_name: str) -> None:
"""Create package.json for JavaScript projects."""
config = {
"name": project_name,
"version": "0.1.0",
"description": "Deep Agent application",
"type": "module",
"main": "agent.js",
"scripts": {
"start": "node agent.js"
},
"dependencies": {
"deepagents": "^0.1.0",
"langchain": "^1.0.0",
"@langchain/core": "^1.0.0",
"@langchain/langgraph": "^1.0.0"
}
}
(project_path / "package.json").write_text(json.dumps(config, indent=2) + "\n")
def create_gitignore(project_path: Path, language: Literal["python", "javascript"]) -> None:
"""Create .gitignore file."""
if language == "python":
content = """# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
dist/
*.egg-info/
.venv
venv/
env/
# Environment variables
.env
.env.local
# IDE
.vscode/
.idea/
*.swp
*~
"""
else:
content = """# Node
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Environment variables
.env
.env.local
# IDE
.vscode/
.idea/
*.swp
*~
"""
(project_path / ".gitignore").write_text(content)
def get_simple_python_template() -> str:
"""Get simple Python Deep Agent template."""
return '''"""Simple Deep Agent implementation."""
from deepagents import create_deep_agent
from tools.example_tools import tools
def main():
"""Initialize and run the Deep Agent."""
# Create agent with automatic middleware (todos, filesystem, subagents)
agent = create_deep_agent(
model="claude-sonnet-4-5-20250929", # or "openai:gpt-5", etc.
tools=tools,
system_prompt="""You are a helpful AI assistant powered by Deep Agents.
You have access to tools that help you search the web and perform calculations.
Break down complex tasks into steps using your built-in planning capabilities.""",
debug=True,
)
# Example invocation
result = agent.invoke({
"messages": [{"role": "user", "content": "What is the weather in San Francisco?"}]
})
print("\\nAgent response:")
print(result["messages"][-1].content)
if __name__ == "__main__":
main()
'''
def get_subagents_python_template() -> str:
"""Get Python Deep Agent template with subagents."""
return '''"""Deep Agent with subagent delegation."""
from deepagents import create_deep_agent
from tools.example_tools import tools
def main():
"""Initialize and run the Deep Agent with subagents."""
# Define subagents for specialized tasks
subagents = [
{
"name": "researcher",
"description": "Research specialist for finding information",
"tools": [tools[0]], # search_web tool
"system_prompt": "You are a research expert. Find accurate information.",
},
{
"name": "calculator",
"description": "Math specialist for calculations",
"tools": [tools[1]], # calculate tool
"system_prompt": "You are a math expert. Perform precise calculations.",
},
]
# Create supervisor agent with subagents
agent = create_deep_agent(
model="claude-sonnet-4-5-20250929",
tools=[], # Supervisor has no direct tools, only delegates
subagents=subagents,
system_prompt="""You are a supervisor AI that coordinates specialized subagents.
When you receive a task:
1. Analyze what type of work is needed
2. Delegate to the appropriate subagent using the 'task' tool
3. Review the results and provide a comprehensive response
Available subagents:
- researcher: For finding information
- calculator: For mathematical calculations""",
debug=True,
)
# Example invocation
result = agent.invoke({
"messages": [{
"role": "user",
"content": "Find the population of Tokyo and calculate how many buses would be needed if each bus holds 50 people."
}]
})
print("\\nAgent response:")
print(result["messages"][-1].content)
if __name__ == "__main__":
main()
'''
def get_cli_config_python_template() -> str:
"""Get Python Deep Agent template with CLI configuration."""
return '''"""Deep Agent with CLI-style configuration."""
import argparse
from deepagents import create_deep_agent
from deepagents.backends import StateBackend, StoreBackend, CompositeBackend
from langgraph.store.memory import InMemoryStore
from langgraph.checkpoint.memory import InMemorySaver
from tools.example_tools import tools
def create_agent(
model: str = "claude-sonnet-4-5-20250929",
use_memory: bool = False,
use_checkpointer: bool = False,
debug: bool = False
):
"""Create a Deep Agent with configurable options."""
kwargs = {
"model": model,
"tools": tools,
"system_prompt": "You are a helpful AI assistant with planning capabilities.",
"debug": debug,
}
# Add memory store if requested
if use_memory:
store = InMemoryStore()
kwargs["store"] = store
kwargs["backend"] = lambda rt: CompositeBackend(
default=StateBackend(rt),
routes={"/memories/": StoreBackend(rt)}
)
# Add checkpointer if requested
if use_checkpointer:
kwargs["checkpointer"] = InMemorySaver()
return create_deep_agent(**kwargs)
def main():
"""CLI entry point."""
parser = argparse.ArgumentParser(description="Run Deep Agent with configuration")
parser.add_argument(
"--model",
default="claude-sonnet-4-5-20250929",
help="Model to use (default: claude-sonnet-4-5-20250929)"
)
parser.add_argument(
"--memory",
action="store_true",
help="Enable long-term memory store"
)
parser.add_argument(
"--checkpointer",
action="store_true",
help="Enable state checkpointing"
)
parser.add_argument(
"--debug",
action="store_true",
help="Enable debug mode"
)
parser.add_argument(
"query",
nargs="?",
default="Hello! What can you help me with?",
help="Query to send to the agent"
)
args = parser.parse_args()
# Create agent with configuration
agent = create_agent(
model=args.model,
use_memory=args.memory,
use_checkpointer=args.checkpointer,
debug=args.debug
)
# Run query
config = {}
if args.checkpointer:
config["configurable"] = {"thread_id": "default"}
result = agent.invoke(
{"messages": [{"role": "user", "content": args.query}]},
config=config
)
print("\\nAgent response:")
print(result["messages"][-1].content)
if __name__ == "__main__":
main()
'''
def get_simple_javascript_template() -> str:
"""Get simple JavaScript Deep Agent template."""
return '''/**
* Simple Deep Agent implementation.
*/
import { createDeepAgent } from "deepagents";
import { tools } from "./tools/example_tools.js";
async function main() {
// Create agent with automatic middleware (todos, filesystem, subagents)
const agent = await createDeepAgent({
model: "claude-sonnet-4-5-20250929", // or "openai:gpt-5", etc.
tools: tools,
systemPrompt: `You are a helpful AI assistant powered by Deep Agents.
You have access to tools that help you search the web and perform calculations.
Break down complex tasks into steps using your built-in planning capabilities.`,
debug: true,
});
// Example invocation
const result = await agent.invoke({
messages: [{ role: "user", content: "What is the weather in San Francisco?" }],
});
console.log("\\nAgent response:");
console.log(result.messages[result.messages.length - 1].content);
}
main().catch(console.error);
'''
def get_subagents_javascript_template() -> str:
"""Get JavaScript Deep Agent template with subagents."""
return '''/**
* Deep Agent with subagent delegation.
*/
import { createDeepAgent } from "deepagents";
import { tools } from "./tools/example_tools.js";
async function main() {
// Define subagents for specialized tasks
const subagents = [
{
name: "researcher",
description: "Research specialist for finding information",
tools: [tools[0]], // searchWeb tool
systemPrompt: "You are a research expert. Find accurate information.",
},
{
name: "calculator",
description: "Math specialist for calculations",
tools: [tools[1]], // calculate tool
systemPrompt: "You are a math expert. Perform precise calculations.",
},
];
// Create supervisor agent with subagents
const agent = await createDeepAgent({
model: "claude-sonnet-4-5-20250929",
tools: [], // Supervisor has no direct tools, only delegates
subagents: subagents,
systemPrompt: `You are a supervisor AI that coordinates specialized subagents.
When you receive a task:
1. Analyze what type of work is needed
2. Delegate to the appropriate subagent using the 'task' tool
3. Review the results and provide a comprehensive response
Available subagents:
- researcher: For finding information
- calculator: For mathematical calculations`,
debug: true,
});
// Example invocation
const result = await agent.invoke({
messages: [
{
role: "user",
content:
"Find the population of Tokyo and calculate how many buses would be needed if each bus holds 50 people.",
},
],
});
console.log("\\nAgent response:");
console.log(result.messages[result.messages.length - 1].content);
}
main().catch(console.error);
'''
def get_cli_config_javascript_template() -> str:
"""Get JavaScript Deep Agent template with CLI configuration."""
return '''/**
* Deep Agent with CLI-style configuration.
*/
import { createDeepAgent, StateBackend, StoreBackend, CompositeBackend } from "deepagents";
import { InMemoryStore, MemorySaver } from "@langchain/langgraph";
import { tools } from "./tools/example_tools.js";
async function createAgent(options = {}) {
const {
model = "claude-sonnet-4-5-20250929",
useMemory = false,
useCheckpointer = false,
debug = false,
} = options;
const config = {
model,
tools,
systemPrompt: "You are a helpful AI assistant with planning capabilities.",
debug,
};
// Add memory store if requested
if (useMemory) {
const store = new InMemoryStore();
config.store = store;
config.backend = (rt) =>
new CompositeBackend(
new StateBackend(rt),
{ "/memories/": new StoreBackend(rt) },
);
}
// Add checkpointer if requested
if (useCheckpointer) {
config.checkpointer = new MemorySaver();
}
return await createDeepAgent(config);
}
async function main() {
// Parse command line arguments
const args = process.argv.slice(2);
const options = {
model: "claude-sonnet-4-5-20250929",
useMemory: args.includes("--memory"),
useCheckpointer: args.includes("--checkpointer"),
debug: args.includes("--debug"),
};
// Get query (everything after flags)
const query = args.filter((arg) => !arg.startsWith("--")).join(" ") ||
"Hello! What can you help me with?";
// Create agent with configuration
const agent = await createAgent(options);
// Run query
const config = {};
if (options.useCheckpointer) {
config.configurable = { thread_id: "default" };
}
const result = await agent.invoke(
{ messages: [{ role: "user", content: query }] },
config
);
console.log("\\nAgent response:");
console.log(result.messages[result.messages.length - 1].content);
}
main().catch(console.error);
'''
def main():
parser = argparse.ArgumentParser(
description="Initialize a new Deep Agent project"
)
parser.add_argument(
"project_name",
help="Name of the project (e.g., my-deep-agent)"
)
parser.add_argument(
"--language",
choices=["python", "javascript"],
default="python",
help="Programming language (default: python)"
)
parser.add_argument(
"--template",
choices=["simple", "with-subagents", "cli-config"],
default="simple",
help="Project template (default: simple)"
)
parser.add_argument(
"--path",
default=".",
help="Output directory (default: current directory)"
)
args = parser.parse_args()
# Create project directory
base_path = Path(args.path).resolve()
project_path = base_path / args.project_name
if project_path.exists():
print(f"❌ Error: Directory {project_path} already exists")
sys.exit(1)
print(f"🚀 Initializing Deep Agent project: {args.project_name}")
print(f" Language: {args.language}")
print(f" Template: {args.template}")
print(f" Location: {project_path}")
print()
try:
# Create all files and directories
create_directory_structure(project_path, args.language)
create_agent_file(project_path, args.language, args.template)
create_tools_file(project_path, args.language)
create_env_file(project_path)
create_readme(project_path, args.project_name, args.language, args.template)
create_gitignore(project_path, args.language)
if args.language == "python":
create_pyproject_toml(project_path, args.project_name)
else:
create_package_json(project_path, args.project_name)
print("✅ Created project structure")
print("✅ Created agent file")
print("✅ Created example tools")
print("✅ Created .env.example")
print("✅ Created README.md")
print("✅ Created .gitignore")
print(f"✅ Created {'pyproject.toml' if args.language == 'python' else 'package.json'}")
print()
print("📦 Next steps:")
print(f" 1. cd {args.project_name}")
if args.language == "python":
print(" 2. Create a virtual environment: uv venv --python=3.12")
print(" 3. Activate it: source .venv/bin/activate")
print(" 4. Install dependencies: uv sync")
else:
print(" 2. Install dependencies: npm install")
print(" 5. Copy .env.example to .env and configure API keys")
print(f" 6. Run the agent: {'uv run agent.py' if args.language == 'python' else 'node agent.js'}")
print()
print("🎯 Happy building!")
except Exception as e:
print(f"❌ Error creating project: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Validate Deep Agent configuration by parsing agent files.
Usage:
uv run validate_deep_agent_config.py <agent_file_path>
Fallback:
python3 validate_deep_agent_config.py <agent_file_path>
Validates:
- Model parameter exists and is valid
- Tools are properly formatted
- Middleware configuration is correct
- Backend configuration is valid
- System prompt is provided
"""
import argparse
import ast
import re
import sys
from pathlib import Path
from typing import List, Dict, Any, Optional
class DeepAgentValidator:
"""Validator for Deep Agent configuration."""
# Known valid model prefixes
VALID_MODEL_PREFIXES = [
"openai:",
"anthropic:",
"google_genai:",
"google:",
"bedrock:",
"azure_openai:",
"mistralai:",
"ollama:",
"groq:",
"cohere:",
"xai:",
"gpt-",
"claude-",
"gemini-",
"command-",
"mistral-",
]
def __init__(self, agent_path: Path):
self.agent_path = agent_path
self.errors: List[str] = []
self.warnings: List[str] = []
self.content: Optional[str] = None
self.found_agents: List[Dict[str, Any]] = []
def validate(self) -> bool:
"""Run all validation checks. Returns True if valid."""
if not self._load_file():
return False
if self.agent_path.suffix == ".py":
self._validate_python()
elif self.agent_path.suffix in {".js", ".ts"}:
self._validate_javascript()
else:
self.errors.append(
f"Unsupported file type: {self.agent_path.suffix}. "
"Expected .py, .js, or .ts"
)
return False
return len(self.errors) == 0
def _load_file(self) -> bool:
"""Load and read the agent file."""
if not self.agent_path.exists():
self.errors.append(f"File not found: {self.agent_path}")
return False
try:
self.content = self.agent_path.read_text()
return True
except Exception as e:
self.errors.append(f"Failed to read file: {e}")
return False
def _validate_python(self):
"""Validate Python Deep Agent file."""
# Check for import
if "from deepagents import create_deep_agent" not in self.content:
self.warnings.append(
"Missing 'from deepagents import create_deep_agent' import"
)
# Parse AST to find create_deep_agent calls
try:
tree = ast.parse(self.content)
self._find_deep_agent_calls_python(tree)
except SyntaxError as e:
self.errors.append(f"Python syntax error: {e}")
return
if not self.found_agents:
self.errors.append("No create_deep_agent() calls found in file")
return
# Validate each agent configuration
for i, agent_config in enumerate(self.found_agents):
agent_num = f"Agent #{i+1}" if len(self.found_agents) > 1 else "Agent"
self._validate_agent_config(agent_config, agent_num)
def _validate_javascript(self):
"""Validate JavaScript Deep Agent file."""
# Check for import
if "createDeepAgent" not in self.content:
self.warnings.append(
"Missing 'createDeepAgent' import from deepagents"
)
# Use regex to find createDeepAgent calls (basic parsing)
pattern = r"createDeepAgent\s*\(\s*\{([^}]*(?:\{[^}]*\}[^}]*)*)\}\s*\)"
matches = re.finditer(pattern, self.content, re.DOTALL)
for match in matches:
config_text = match.group(1)
agent_config = self._parse_javascript_config(config_text)
self.found_agents.append(agent_config)
# Fallback: detect calls with dynamic config (e.g. createDeepAgent(config))
if not self.found_agents:
dynamic_calls = list(re.finditer(r"createDeepAgent\s*\(", self.content))
for _ in dynamic_calls:
self.found_agents.append({"<dynamic_config>": True})
if not self.found_agents:
self.errors.append("No createDeepAgent() calls found in file")
return
# Validate each agent configuration
for i, agent_config in enumerate(self.found_agents):
agent_num = f"Agent #{i+1}" if len(self.found_agents) > 1 else "Agent"
self._validate_agent_config(agent_config, agent_num)
def _find_deep_agent_calls_python(self, tree: ast.AST):
"""Find all create_deep_agent calls in Python AST."""
for node in ast.walk(tree):
if isinstance(node, ast.Call):
# Check if it's a call to create_deep_agent
if (isinstance(node.func, ast.Name) and
node.func.id == "create_deep_agent"):
config = self._extract_python_config(node)
self.found_agents.append(config)
def _extract_python_config(self, call_node: ast.Call) -> Dict[str, Any]:
"""Extract configuration from Python create_deep_agent call."""
config = {}
# Extract keyword arguments
for keyword in call_node.keywords:
if keyword.arg:
config[keyword.arg] = self._ast_to_value(keyword.value)
else:
# Handles create_deep_agent(**kwargs)
config["<kwargs_unpack>"] = True
return config
def _ast_to_value(self, node: ast.AST) -> Any:
"""Convert AST node to Python value (simplified)."""
if isinstance(node, ast.Constant):
return node.value
elif isinstance(node, ast.Str): # Python 3.7 compatibility
return node.s
elif isinstance(node, ast.Num): # Python 3.7 compatibility
return node.n
elif isinstance(node, ast.List):
return [self._ast_to_value(elem) for elem in node.elts]
elif isinstance(node, ast.Dict):
return {
self._ast_to_value(k): self._ast_to_value(v)
for k, v in zip(node.keys, node.values)
}
elif isinstance(node, ast.Name):
return f"<variable: {node.id}>"
elif isinstance(node, ast.Call):
return "<function_call>"
elif isinstance(node, ast.Lambda):
return "<lambda>"
else:
return "<complex_expression>"
def _parse_javascript_config(self, config_text: str) -> Dict[str, Any]:
"""Parse JavaScript object configuration (simplified)."""
config = {}
# Extract simple key-value pairs
# This is a simplified parser - won't handle all cases
lines = config_text.split("\n")
for line in lines:
line = line.strip()
if not line or line.startswith("//"):
continue
# Match: key: value,
match = re.match(r"(\w+)\s*:\s*(.+?),?\s*$", line)
if match:
key = match.group(1)
value = match.group(2).rstrip(",")
# Try to parse value
if value.startswith('"') or value.startswith("'"):
config[key] = value.strip('"\'')
elif value == "true":
config[key] = True
elif value == "false":
config[key] = False
elif value.startswith("["):
config[key] = "<array>"
elif value.startswith("{"):
config[key] = "<object>"
else:
config[key] = value
return config
def _validate_agent_config(self, config: Dict[str, Any], agent_num: str):
"""Validate a single agent configuration."""
has_dynamic_config = bool(
config.get("<kwargs_unpack>") or config.get("<dynamic_config>")
)
if has_dynamic_config:
self.warnings.append(
f"{agent_num}: Dynamic config detected - some static checks were skipped"
)
# Check for model
if "model" not in config:
if has_dynamic_config:
self.warnings.append(
f"{agent_num}: Could not statically verify required 'model' parameter"
)
else:
self.errors.append(f"{agent_num}: Missing required 'model' parameter")
else:
model_value = config["model"]
if isinstance(model_value, str):
self._validate_model_name(model_value, agent_num)
else:
self.warnings.append(
f"{agent_num}: Model is a variable/expression: {model_value}"
)
# Check for tools
if "tools" in config:
tools_value = config["tools"]
if tools_value == "[]" or tools_value == "<array>":
self.warnings.append(
f"{agent_num}: Tools array appears empty - agent may have limited functionality"
)
elif isinstance(tools_value, str) and tools_value.startswith("<"):
# It's a variable reference, which is fine
pass
else:
if not has_dynamic_config:
self.warnings.append(
f"{agent_num}: No 'tools' parameter - agent will only have middleware tools"
)
# Check for system_prompt or systemPrompt
has_prompt = (
"system_prompt" in config
or "systemPrompt" in config
or "system" in config
)
if not has_prompt and not has_dynamic_config:
self.warnings.append(
f"{agent_num}: No system prompt provided - agent may lack clear instructions"
)
# Check middleware configuration
if "middleware" in config:
middleware_value = config["middleware"]
if isinstance(middleware_value, str) and not middleware_value.startswith("<"):
self.warnings.append(
f"{agent_num}: Custom middleware detected - ensure it's properly configured"
)
# Check backend configuration
if "backend" in config:
backend_value = config["backend"]
if backend_value not in ["<lambda>", "<function_call>", "<complex_expression>"]:
self.warnings.append(
f"{agent_num}: Backend should typically be a lambda/function: {backend_value}"
)
# Check subagents
if "subagents" in config:
subagents_value = config["subagents"]
if subagents_value in ["[]", "<array>"]:
self.warnings.append(
f"{agent_num}: Subagents parameter present but appears empty"
)
# Check store configuration
if "store" in config and "backend" not in config:
self.warnings.append(
f"{agent_num}: 'store' provided without custom 'backend' - "
"consider using StoreBackend for persistence"
)
# Check human-in-the-loop interrupt config
interrupt_key = None
if "interrupt_on" in config:
interrupt_key = "interrupt_on"
elif "interruptOn" in config:
interrupt_key = "interruptOn"
if interrupt_key:
interrupt_value = config[interrupt_key]
if isinstance(interrupt_value, list):
self.warnings.append(
f"{agent_num}: '{interrupt_key}' should be a tool-name mapping (dict/object), not a list"
)
elif isinstance(interrupt_value, str) and not (
interrupt_value == "<object>" or interrupt_value.startswith("<variable:")
):
self.warnings.append(
f"{agent_num}: '{interrupt_key}' should be a mapping of tool names to interrupt settings"
)
if "checkpointer" not in config:
self.warnings.append(
f"{agent_num}: '{interrupt_key}' is configured without 'checkpointer' - interruptions require persistence"
)
def _validate_model_name(self, model: str, agent_num: str):
"""Validate model name."""
# Check if it's a known model prefix or provider:model identifier
has_provider_prefix = ":" in model and not model.startswith(":") and not model.endswith(":")
is_valid = has_provider_prefix or any(
model.startswith(prefix) for prefix in self.VALID_MODEL_PREFIXES
)
if not is_valid:
self.warnings.append(
f"{agent_num}: Unknown model name '{model}' - "
f"expected model starting with: {', '.join(self.VALID_MODEL_PREFIXES)}"
)
# Check for deprecated or old models
deprecated_patterns = [
("gpt-3.5-turbo-0301", "Use a current tool-calling model such as gpt-4.1+"),
("text-davinci-003", "Use a current chat model such as gpt-4.1+"),
("claude-2", "Use a current Claude 3.5/4+ model"),
]
for pattern, suggestion in deprecated_patterns:
if pattern in model:
self.warnings.append(
f"{agent_num}: Model '{model}' may be deprecated. {suggestion}"
)
def print_results(self):
"""Print validation results."""
print(f"📋 Validation Report for: {self.agent_path.name}\n")
if self.found_agents:
print(f"✅ Found {len(self.found_agents)} Deep Agent configuration(s)\n")
if self.errors:
print("❌ Errors:\n")
for error in self.errors:
print(f" ERROR: {error}")
print()
if self.warnings:
print("⚠️ Warnings:\n")
for warning in self.warnings:
print(f" WARNING: {warning}")
print()
if not self.errors and not self.warnings:
print("✅ Configuration is valid! No issues found.")
elif not self.errors:
print("✅ Configuration is valid (with warnings)")
else:
print("❌ Configuration has errors and needs fixes")
return not self.errors
def main():
parser = argparse.ArgumentParser(
description="Validate Deep Agent configuration file"
)
parser.add_argument(
"agent_file_path",
help="Path to agent.py, agent.js, or agent.ts file"
)
args = parser.parse_args()
agent_path = Path(args.agent_file_path).resolve()
print(f"🔍 Validating Deep Agent configuration...\n")
validator = DeepAgentValidator(agent_path)
is_valid = validator.validate()
validator.print_results()
sys.exit(0 if is_valid else 1)
if __name__ == "__main__":
main()