From 8a6785f51feb23a0feafc5827fc4662c3365d71f Mon Sep 17 00:00:00 2001 From: Vincil Bishop Date: Tue, 19 Aug 2025 20:51:12 -0500 Subject: [PATCH] Complete ConfigLoader documentation system with cache removal Comprehensive ConfigLoader documentation implementation: New Documentation Files: - docs/experimental/README.md - Experimental features overview - docs/experimental/config-loader/overview.md - Complete system overview with schema validation - docs/experimental/config-loader/agent-config.md - Agent configuration comprehensive guide - docs/experimental/config-loader/graph-config.md - Graph configuration with nodes, edges, conditions - docs/experimental/config-loader/swarm-config.md - Swarm configuration with multi-agent coordination - docs/experimental/config-loader/tool-config.md - Tool configuration with multi-agent tools - docs/experimental/config-loader/structured-output.md - Structured output configuration guide Documentation Features: - Complete schema validation ecosystem with IDE integration (VSCode, IntelliJ, Vim) - Top-level key requirements enforced across all configurations - Advanced features: conditions, structured output, nested configurations - Real-world examples and comprehensive troubleshooting guides - Cache-free architecture documentation (simplified API without caching complexity) Schema Validation Integration: - Global VSCode Settings approach for seamless IDE integration - Real-time validation and autocompletion support - JSON Schema system preventing configuration errors - Consistent developer experience across all configuration types Configuration Coverage: - Agent configurations with model, tools, structured output - Graph configurations with nodes, edges, entry points, conditions - Swarm configurations with multi-agent coordination - Tool configurations including Agent-as-Tool, Swarm-as-Tool, Graph-as-Tool - Advanced patterns: nested configurations, parameter substitution, complex workflows Navigation and Structure: - Updated mkdocs.yml with experimental section under User Guide - Clear navigation hierarchy for all ConfigLoader documentation - Cross-references between related configuration types - Progressive complexity from basic to advanced examples Production Ready: - 100% accurate examples that work with current implementation - All configurations use proper top-level keys (agent:, graph:, swarm:, tools:) - Comprehensive error handling and troubleshooting guidance - Best practices for configuration management and validation This documentation system provides world-class developer experience for the complete ConfigLoader ecosystem with schema validation, IDE integration, and simplified cache-free architecture. --- docs/experimental/README.md | 187 ++ .../config-loader/agent-config.md | 1120 ++++++++++++ .../config-loader/graph-config.md | 1278 ++++++++++++++ docs/experimental/config-loader/overview.md | 485 ++++++ .../config-loader/structured-output.md | 1287 ++++++++++++++ .../config-loader/swarm-config.md | 941 ++++++++++ .../experimental/config-loader/tool-config.md | 1531 +++++++++++++++++ .../concepts/model-providers/cohere.md | 2 +- .../deploy/deploy_to_bedrock_agentcore.md | 131 +- .../observability-evaluation/traces.md | 2 +- mkdocs.yml | 9 + 11 files changed, 6908 insertions(+), 65 deletions(-) create mode 100644 docs/experimental/README.md create mode 100644 docs/experimental/config-loader/agent-config.md create mode 100644 docs/experimental/config-loader/graph-config.md create mode 100644 docs/experimental/config-loader/overview.md create mode 100644 docs/experimental/config-loader/structured-output.md create mode 100644 docs/experimental/config-loader/swarm-config.md create mode 100644 docs/experimental/config-loader/tool-config.md diff --git a/docs/experimental/README.md b/docs/experimental/README.md new file mode 100644 index 00000000..30b36671 --- /dev/null +++ b/docs/experimental/README.md @@ -0,0 +1,187 @@ +# Experimental Features + +## What are Experimental Features? + +Experimental features in Strands Agents are cutting-edge capabilities that are: +- In active development and testing +- Subject to breaking changes +- Available for early feedback and evaluation +- Not recommended for production use without careful consideration + +## Current Experimental Features + +### Configuration Loaders +Declarative configuration for agents, tools, swarms, and graphs with comprehensive schema validation and IDE integration support. + +**Key Features:** +- **Schema Validation**: Comprehensive JSON Schema validation with IDE integration +- **IDE Support**: VSCode, IntelliJ, Vim autocompletion and real-time validation +- **Type Safety**: Enforced structure and types without restrictive constraints +- **Nested Configurations**: Support for agents-as-tools, graphs-as-tools, swarms-as-tools +- **Error Prevention**: Catch configuration errors before runtime + +**Configuration Types:** +- **Agent Configuration**: Single agents with tools, structured output, and advanced features +- **Graph Configuration**: Multi-agent workflows with nodes, edges, and conditions +- **Swarm Configuration**: Collaborative agent teams with autonomous coordination +- **Tool Configuration**: Standalone tool definitions and agent-as-tool patterns + +## Using Experimental Features + +### Installation +```bash +# Experimental features are included in the main SDK +pip install strands-agents +``` + +### Enabling Experimental Features +```python +from strands.experimental.config_loader import AgentConfigLoader + +# All configurations require top-level keys for schema validation +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a helpful assistant.", + "tools": [{"name": "calculator"}] + } +} + +loader = AgentConfigLoader() +agent = loader.load_agent(config) +``` + +### IDE Integration Setup + +**Global VSCode Settings:** +```json +{ + "yaml.schemas": { + "https://strandsagents.com/schemas/config/v1": "*.strands.yml" + } +} +``` + +## Configuration Examples + +### Agent Configuration +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a helpful assistant.", + "tools": [ + {"name": "calculator"}, + { + "name": "research_assistant", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Research: {topic}" + }, + "input_schema": { + "type": "object", + "properties": { + "topic": {"type": "string"} + }, + "required": ["topic"] + } + } + ] + } +} +``` + +### Graph Configuration +```python +config = { + "graph": { + "nodes": [ + { + "node_id": "classifier", + "type": "agent", + "config": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Classify the input." + } + }, + { + "node_id": "processor", + "type": "agent", + "config": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Process the classified input." + } + } + ], + "edges": [ + { + "from_node": "classifier", + "to_node": "processor", + "condition": { + "type": "expression", + "expression": "state.results.get('classifier', {}).get('status') == 'complete'" + } + } + ], + "entry_points": ["classifier"] + } +} +``` + +### Swarm Configuration +```python +config = { + "swarm": { + "max_handoffs": 20, + "agents": [ + { + "name": "researcher", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a research specialist." + }, + { + "name": "writer", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a writing specialist." + } + ] + } +} +``` + +## Schema Validation Benefits + +### For Developers +- **Real-time Validation**: Catch errors as you type in your IDE +- **Autocompletion**: Get suggestions for configuration properties +- **Type Safety**: Ensure correct data types and structure +- **Documentation**: Schema serves as living documentation + +### For Teams +- **Consistency**: Enforced structure across all configurations +- **Error Prevention**: Reduce runtime configuration errors +- **Collaboration**: Clear configuration contracts between team members +- **Maintenance**: Easier to update and maintain complex configurations + +## Stability and Support + +- **API Stability**: Experimental APIs may change between releases +- **Documentation**: May be incomplete or subject to updates +- **Support**: Community support through GitHub issues +- **Schema Validation**: Production-ready validation system with comprehensive IDE support + +## Feedback and Contributions + +We encourage feedback on experimental features: +- [GitHub Issues](https://github.com/strands-agents/sdk-python/issues) +- [Discussions](https://github.com/strands-agents/sdk-python/discussions) +- [Contributing Guide](https://github.com/strands-agents/sdk-python/blob/main/CONTRIBUTING.md) + +## Next Steps + +- [Configuration Loaders Overview](config-loader/overview.md) - Comprehensive guide to configuration loaders +- [Agent Configuration](config-loader/agent-config.md) - Detailed agent configuration options +- [Graph Configuration](config-loader/graph-config.md) - Multi-agent workflow configuration +- [Swarm Configuration](config-loader/swarm-config.md) - Collaborative agent team configuration +- [Tool Configuration](config-loader/tool-config.md) - Tool loading and agent-as-tool patterns +- [Structured Output](config-loader/structured-output.md) - Structured data extraction configuration diff --git a/docs/experimental/config-loader/agent-config.md b/docs/experimental/config-loader/agent-config.md new file mode 100644 index 00000000..2b028fae --- /dev/null +++ b/docs/experimental/config-loader/agent-config.md @@ -0,0 +1,1120 @@ +# Agent Configuration Loading + +The Agent Configuration Loader enables you to create and configure Strands Agents using Python dictionaries. This approach provides a programmatic way to define agent behavior, making it easier to manage complex agent configurations, build configuration management systems, and dynamically create agents at runtime. + +**Note**: This is an experimental feature that provides programmatic configuration loading through dictionaries. For file-based configuration (YAML/JSON), use the main Agent constructor's `config` parameter. + +## Quick Start + +### Using Dictionary Configuration + +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +# Create configuration dictionary +config = { + "agent": { + "model": { + "type": "bedrock", + "model_id": "us.amazon.nova-pro-v1:0", + "temperature": 0.7, + "streaming": True + }, + "system_prompt": "You are a helpful AI assistant specialized in data analysis.", + "tools": [ + {"name": "calculator"}, + {"name": "web_search", "module": "my_tools.search"} + ], + "agent_id": "data_analyst", + "name": "Data Analysis Assistant", + "description": "An AI assistant that helps with data analysis tasks" + } +} + +# Load the agent using AgentConfigLoader +loader = AgentConfigLoader() +agent = loader.load_agent(config) + +# Use the agent +response = agent("What is 15 * 23?") +``` + +### Simple Configuration + +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +# Minimal configuration +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a helpful assistant.", + "tools": [{"name": "calculator"}] + } +} + +loader = AgentConfigLoader() +agent = loader.load_agent(config) +``` + +## Schema Validation + +The ConfigLoader includes comprehensive schema validation for agents: + +- **IDE Integration**: VSCode, IntelliJ, Vim support with autocompletion +- **Error Prevention**: Catch configuration errors before runtime +- **Type Safety**: Enforced structure and types +- **Documentation**: Schema serves as living documentation + +### Global VSCode Settings +Add to your `settings.json`: +```json +{ + "yaml.schemas": { + "https://strandsagents.com/schemas/config/v1": "*.strands.yml" + } +} +``` + +## Configuration Schema + +### Basic Configuration + +```python +# Minimal configuration +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a helpful assistant." + } +} +``` + +### Complete Configuration + +```python +# Complete agent configuration example +config = { + "agent": { + "model": { + "type": "bedrock", + "model_id": "us.amazon.nova-pro-v1:0", + "region": "us-west-2", + "temperature": 0.7, + "max_tokens": 4096, + "streaming": True + }, + "system_prompt": """You are a specialized AI assistant for software development. +You help developers write, debug, and optimize code.""", + "tools": [ + {"name": "file_reader"}, + {"name": "code_analyzer", "module": "dev_tools.analyzer"}, + { + "name": "documentation_agent", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Generate clear documentation for {code_type} code: {code_content}", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "code_type": { + "type": "string", + "description": "Type of code (Python, JavaScript, etc.)" + }, + "code_content": { + "type": "string", + "description": "The code to document" + } + }, + "required": ["code_type", "code_content"] + }, + "prompt": "Generate clear documentation for {code_type} code: {code_content}" + } + ], + "messages": [ + { + "role": "user", + "content": [{"text": "Hello, I need help with my Python project."}] + }, + { + "role": "assistant", + "content": [{"text": "I'd be happy to help with your Python project! What specific aspect would you like assistance with?"}] + } + ], + "agent_id": "dev_assistant", + "name": "Development Assistant", + "description": "AI assistant specialized in software development tasks", + "callback_handler": "printing", + "conversation_manager": { + "type": "sliding_window", + "window_size": 50, + "should_truncate_results": True + }, + "record_direct_tool_call": True, + "load_tools_from_directory": False, + "trace_attributes": { + "environment": "production", + "version": "1.0.0" + }, + "state": { + "current_project": None, + "preferred_language": "python", + "debug_mode": False + } + } +} +``` + +## Configuration Options + +### Model Configuration + +#### Simple Model (String) +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0" + } +} +``` + +#### Detailed Model Configuration +```python +config = { + "agent": { + "model": { + "type": "bedrock", # Currently only 'bedrock' is supported + "model_id": "us.amazon.nova-pro-v1:0", + "region": "us-west-2", + "temperature": 0.7, + "max_tokens": 4096, + "streaming": True + } + } +} +``` + +### Tools Configuration + +#### Simple Tool References +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "tools": [ + {"name": "calculator"}, + {"name": "web_search"} + ] + } +} +``` + +#### Tools with Module Paths +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "tools": [ + {"name": "custom_tool", "module": "my_package.tools"}, + {"name": "file_processor", "module": "utils.file_tools"} + ] + } +} +``` + +#### Agent-as-Tool Configuration +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a coordinator that uses specialized tools.", + "tools": [ + { + "name": "research_assistant", + "description": "Specialized agent for research tasks", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Research the topic: {topic} and provide {detail_level} information", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "topic": { + "type": "string", + "description": "The research topic" + }, + "detail_level": { + "type": "string", + "enum": ["brief", "detailed", "comprehensive"], + "default": "detailed" + } + }, + "required": ["topic"] + } + } + ] + } +} +``` + +### Messages Configuration + +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a helpful assistant.", + "messages": [ + { + "role": "user", + "content": [{"text": "Hello!"}] + }, + { + "role": "assistant", + "content": [{"text": "Hello! How can I help you today?"}] + } + ] + } +} +``` + +### Advanced Configuration Options + +#### Conversation Manager +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "conversation_manager": { + "type": "sliding_window", + "window_size": 20, + "should_truncate_results": True + } + } +} +``` + +#### Callback Handler +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "callback_handler": "printing" # or custom callback configuration + } +} +``` + +#### State Management +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "state": { + "user_preferences": {}, + "session_data": {}, + "context": {} + } + } +} +``` + +## Structured Output Configuration + +Configure agents to return structured data using Pydantic models: + +```python +config = { + "schemas": [ + { + "name": "UserProfile", + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "User's full name" + }, + "email": { + "type": "string", + "format": "email", + "description": "User's email address" + }, + "age": { + "type": "integer", + "minimum": 0, + "description": "User's age" + } + }, + "required": ["name", "email"] + } + } + ], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Extract user information from text.", + "structured_output": "UserProfile" + } +} + +# Load agent with structured output +loader = AgentConfigLoader() +agent = loader.load_agent(config) + +# Use structured output +result = agent.structured_output("Extract info: John Doe, 30 years old, john@example.com") +print(f"Name: {result.name}") +print(f"Email: {result.email}") +print(f"Age: {result.age}") + +# Or use the convenience method +result = agent.extract_userprofile("Extract info: Jane Smith, jane@example.com") +``` + +### Serialization +```python +# Load from config +agent = loader.load_agent(config) + +# Serialize back to config +serialized_config = loader.serialize_agent(agent) +``` + +## Error Handling + +The AgentConfigLoader provides comprehensive error handling: + +```python +try: + agent = loader.load_agent(invalid_config) +except ValueError as e: + print(f"Configuration error: {e}") +except ImportError as e: + print(f"Missing dependency: {e}") +``` + +Common error scenarios: +- **Missing required fields**: Clear messages about required configuration +- **Invalid model configuration**: Specific guidance for model setup +- **Tool loading errors**: Helpful messages for missing or invalid tools +- **Schema validation errors**: Real-time validation with IDE integration + +## Best Practices + +1. **Use Schema Validation**: Enable IDE integration for better development experience +2. **Structure Tools**: Organize complex tool configurations with clear naming +3. **Test Configurations**: Validate configurations against the schema before deployment +4. **Document Custom Agents**: Provide clear documentation for agent-as-tool configurations + +## Advanced Examples + +### Multi-Tool Agent with Nested Agents +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a project manager coordinating specialized team members.", + "tools": [ + { + "name": "code_reviewer", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Review code for quality and best practices: {code}" + }, + "input_schema": { + "type": "object", + "properties": { + "code": {"type": "string", "description": "Code to review"} + }, + "required": ["code"] + } + }, + { + "name": "documentation_writer", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Write documentation for: {feature}" + }, + "input_schema": { + "type": "object", + "properties": { + "feature": {"type": "string", "description": "Feature to document"} + }, + "required": ["feature"] + } + } + ] + } +} +``` + +### Agent with Complex State Management +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a customer service agent with access to user history.", + "state": { + "user_id": None, + "conversation_history": [], + "user_preferences": {}, + "current_issue": None + }, + "conversation_manager": { + "type": "sliding_window", + "window_size": 30, + "should_truncate_results": False + }, + "tools": [ + {"name": "user_lookup", "module": "customer_tools.lookup"}, + {"name": "order_status", "module": "customer_tools.orders"} + ] + } +} +``` + +## Next Steps + +- [Structured Output Configuration](structured-output.md) - Detailed structured output setup +- [Tool Configuration](tool-config.md) - Advanced tool loading patterns +- [Graph Configuration](graph-config.md) - Multi-agent workflow configuration +- [Swarm Configuration](swarm-config.md) - Collaborative agent team configuration + "type": "string", + "description": "The code to document" + } + }, + "required": ["code_type", "code_content"] + }, + "prompt": "Generate clear documentation for {code_type} code: {code_content}" + } + ], + "messages": [ + { + "role": "user", + "content": [{"text": "Hello, I need help with my Python project."}] + }, + { + "role": "assistant", + "content": [{"text": "I'd be happy to help with your Python project! What specific aspect would you like assistance with?"}] + } + ], + "agent_id": "dev_assistant", + "name": "Development Assistant", + "description": "AI assistant specialized in software development tasks", + "callback_handler": "printing", + "conversation_manager": { + "type": "sliding_window", + "window_size": 50, + "should_truncate_results": True + }, + "record_direct_tool_call": True, + "load_tools_from_directory": False, + "trace_attributes": { + "environment": "production", + "version": "1.0.0" + }, + "state": { + "current_project": None, + "preferred_language": "python", + "debug_mode": False + } +} +``` + +## Configuration Options + +### Model Configuration + +#### Simple Model (String) +```python +config = { + "model": "us.amazon.nova-pro-v1:0" +} +``` + +#### Detailed Model Configuration +```python +config = { + "model": { + "type": "bedrock", # Currently only 'bedrock' is supported + "model_id": "us.amazon.nova-pro-v1:0", + "region": "us-west-2", + "temperature": 0.7, + "max_tokens": 4096, + "streaming": True + } +} +``` + +### Tools Configuration + +#### Simple Tool References +```python +config = { + "tools": [ + {"name": "calculator"}, + {"name": "web_search"} + ] +} +``` + +#### Tools with Module Paths +```python +config = { + "tools": [ + {"name": "custom_tool", "module": "my_package.tools"}, + {"name": "file_processor", "module": "utils.file_tools"} + ] +} +``` + +#### Agent-as-Tool Configuration +```python +config = { + "tools": [ + { + "name": "research_assistant", + "description": "Specialized agent for research tasks", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Research the topic: {topic} and provide {detail_level} information", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "topic": { + "type": "string", + "description": "Research topic" + }, + "detail_level": { + "type": "string", + "description": "Level of detail (brief, detailed, comprehensive)", + "default": "detailed" + } + }, + "required": ["topic"] + }, + "prompt": "Research the topic: {topic} and provide {detail_level} information" + } + ] +} +``` + +### Messages Configuration + +Pre-populate conversation history: + +```python +config = { + "messages": [ + { + "role": "user", + "content": [{"text": "What can you help me with?"}] + }, + { + "role": "assistant", + "content": [{"text": "I can help you with data analysis, code review, and documentation."}] + }, + { + "role": "user", + "content": [{"text": "Great! Let's start with some data analysis."}] + } + ] +} +``` + +### Callback Handler Configuration + +```python +# Default printing handler +config = {"callback_handler": "printing"} + +# Null handler (no output) +config = {"callback_handler": "null"} + +# Detailed configuration +config = { + "callback_handler": { + "type": "printing" # or 'null' + } +} +``` + +### Conversation Manager Configuration + +```python +config = { + "conversation_manager": { + "type": "sliding_window", + "window_size": 40, # Number of messages to keep + "should_truncate_results": True + } +} +``` + +### Agent State Configuration + +```python +config = { + "state": { + "user_preferences": { + "language": "python", + "verbosity": "detailed" + }, + "session_data": { + "project_context": "web_application", + "last_action": "code_review" + } + } +} +``` + +## Using AgentConfigLoader + +### Basic Usage + +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +# Create configuration +config = { + "model": { + "type": "bedrock", + "model_id": "us.amazon.nova-pro-v1:0", + "temperature": 0.8 + }, + "system_prompt": "You are a creative writing assistant.", + "tools": [ + {"name": "thesaurus"}, + {"name": "grammar_check"} + ], + "agent_id": "writer_bot", + "name": "Creative Writer" +} + +# Load agent using AgentConfigLoader +loader = AgentConfigLoader() +agent = loader.load_agent(config) + +# Use the agent +response = agent("Help me write a story about space exploration") +``` + +### Serializing Agents + +```python +from strands import Agent +from strands.experimental.config_loader.agent import AgentConfigLoader + +# Create agent programmatically +agent = Agent( + model="us.amazon.nova-pro-v1:0", + system_prompt="You are a helpful assistant.", + tools=[calculator, web_search], + agent_id="my_agent", + name="Helper Bot" +) + +# Serialize to configuration +loader = AgentConfigLoader() +config = loader.serialize_agent(agent) + +# The config can now be saved, modified, or used to recreate the agent +print(config) +# Output: +# { +# 'model': 'us.amazon.nova-pro-v1:0', +# 'system_prompt': 'You are a helpful assistant.', +# 'tools': [{'name': 'calculator'}, {'name': 'web_search'}], +# 'agent_id': 'my_agent', +# 'name': 'Helper Bot' +# } +``` + +## Advanced Examples + +### Multi-Agent System Configuration + +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +# Coordinator agent configuration +coordinator_config = { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You coordinate tasks between specialized agents.", + "tools": [ + { + "name": "data_analyst", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Analyze the data: {data} and provide insights", + "tools": [ + {"name": "pandas_analyzer"}, + {"name": "visualization_tool"} + ] + }, + "input_schema": { + "type": "object", + "properties": { + "data": { + "type": "string", + "description": "Data to analyze" + } + }, + "required": ["data"] + } + }, + { + "name": "report_writer", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Write a {report_type} report based on: {analysis_results}", + "tools": [{"name": "document_formatter"}] + }, + "input_schema": { + "type": "object", + "properties": { + "report_type": { + "type": "string", + "description": "Type of report (summary, detailed, executive)", + "default": "summary" + }, + "analysis_results": { + "type": "string", + "description": "Results from data analysis" + } + }, + "required": ["analysis_results"] + } + } + ], + "agent_id": "coordinator", + "name": "Task Coordinator" +} + +loader = AgentConfigLoader() +coordinator_agent = loader.load_agent(coordinator_config) +``` + +### Environment-Specific Configuration + +```python +import os +from strands.experimental.config_loader.agent import AgentConfigLoader + +def get_environment_config(): + env = os.getenv("ENVIRONMENT", "development") + + base_config = { + "system_prompt": "You are a helpful assistant.", + "tools": [{"name": "calculator"}] + } + + if env == "development": + return { + **base_config, + "model": { + "type": "bedrock", + "model_id": "us.amazon.nova-lite-v1:0", # Faster, cheaper model for dev + "temperature": 0.5 + }, + "callback_handler": "printing", # Verbose output for debugging + "trace_attributes": { + "environment": "development", + "debug": True + }, + "load_tools_from_directory": True # Auto-reload tools during development + } + elif env == "production": + return { + **base_config, + "model": { + "type": "bedrock", + "model_id": "us.amazon.nova-pro-v1:0", # More capable model for production + "temperature": 0.3 + }, + "callback_handler": "null", # Minimal output in production + "trace_attributes": { + "environment": "production", + "version": "2.1.0" + }, + "conversation_manager": { + "type": "sliding_window", + "window_size": 100 # Larger context window for production + } + } + else: + raise ValueError(f"Unknown environment: {env}") + +# Load environment-specific configuration +config = get_environment_config() +loader = AgentConfigLoader() +agent = loader.load_agent(config) +``` + +### Template-Based Agent Tools + +```python +code_reviewer_config = { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a code review coordinator.", + "tools": [ + { + "name": "code_reviewer", + "description": "Reviews code and provides feedback", + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": """Review the following {language} code for: +- Code quality and best practices +- Potential bugs or issues +- Performance considerations +- Security concerns + +Focus level: {focus_level} + +Code to review: +{code}""", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "language": { + "type": "string", + "description": "Programming language" + }, + "code": { + "type": "string", + "description": "Code to review" + }, + "focus_level": { + "type": "string", + "description": "Review focus (quick, thorough, security)", + "default": "thorough" + } + }, + "required": ["language", "code"] + } + } + ] +} + +loader = AgentConfigLoader() +agent = loader.load_agent(code_reviewer_config) +``` + +## Error Handling + +The AgentConfigLoader provides clear error messages for common issues: + +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +loader = AgentConfigLoader() + +try: + # Invalid configuration + invalid_config = { + "model": {"type": "unsupported_model"}, # Invalid model type + "tools": [{"name": "nonexistent_tool"}] # Tool that doesn't exist + } + agent = loader.load_agent(invalid_config) +except ValueError as e: + print(f"Configuration error: {e}") +except ImportError as e: + print(f"Tool import error: {e}") + +try: + # Missing required configuration + incomplete_config = { + "tools": [{"module": "some_module"}] # Missing 'name' field + } + agent = loader.load_agent(incomplete_config) +except ValueError as e: + print(f"Missing required field: {e}") +``` + +Common configuration errors: +- Missing required fields (tool names, agent configurations) +- Invalid model types or configurations +- Tool loading failures (missing modules, invalid tool definitions) +- Invalid agent-as-tool configurations (missing agent config, invalid input schemas) +- Circular dependencies in agent-as-tool hierarchies + +## Best Practices + +### 1. Use Descriptive Configuration Structure + +```python +# Good: Clear, well-structured configuration +config = { + "model": { + "type": "bedrock", + "model_id": "us.amazon.nova-pro-v1:0", + "temperature": 0.7 + }, + "system_prompt": "You are a specialized data analysis assistant.", + "tools": [ + {"name": "pandas_analyzer", "module": "data_tools.pandas"}, + {"name": "visualization_tool", "module": "data_tools.viz"} + ], + "agent_id": "data_analyst_v2", + "name": "Data Analysis Assistant", + "description": "Specialized agent for data analysis tasks" +} +``` + +### 2. Environment Separation + +```python +def create_agent_config(environment="development"): + base_config = { + "system_prompt": "You are a helpful assistant.", + "tools": [{"name": "calculator"}] + } + + env_configs = { + "development": { + "model": "us.amazon.nova-lite-v1:0", + "callback_handler": "printing", + "load_tools_from_directory": True + }, + "production": { + "model": "us.amazon.nova-pro-v1:0", + "callback_handler": "null", + "conversation_manager": { + "type": "sliding_window", + "window_size": 100 + } + } + } + + return {**base_config, **env_configs.get(environment, {})} +``` + +### 3. Modular Tool Definitions + +```python +# Define reusable tool configurations +COMMON_TOOLS = { + "calculator": {"name": "calculator"}, + "web_search": {"name": "web_search", "module": "search_tools"}, + "file_reader": {"name": "file_reader", "module": "file_tools"} +} + +ANALYSIS_TOOLS = { + "data_analyzer": { + "name": "data_analyzer", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Analyze: {data}", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "data": {"type": "string", "description": "Data to analyze"} + }, + "required": ["data"] + } + } +} + +# Compose configurations +analyst_config = { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a data analyst.", + "tools": [ + COMMON_TOOLS["calculator"], + COMMON_TOOLS["file_reader"], + ANALYSIS_TOOLS["data_analyzer"] + ] +} +``` + +### 4. Configuration Validation + +```python +def validate_agent_config(config): + """Validate agent configuration before loading.""" + required_fields = ["model", "system_prompt"] + + for field in required_fields: + if field not in config: + raise ValueError(f"Missing required field: {field}") + + # Validate tools configuration + if "tools" in config: + for tool in config["tools"]: + if isinstance(tool, dict): + if "name" not in tool: + raise ValueError("Tool configuration must include 'name' field") + if "agent" in tool and "input_schema" not in tool: + print(f"Warning: Agent tool '{tool['name']}' missing input_schema") + + return True + +# Use validation +config = {...} +if validate_agent_config(config): + loader = AgentConfigLoader() + agent = loader.load_agent(config) +``` + +### 5. Caching Strategy + +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +# Use a single loader instance with caching +loader = AgentConfigLoader() + +# Cache frequently used agents +common_configs = { + "analyst": {...}, + "writer": {...}, + "reviewer": {...} +} + +agents = {} +for name, config in common_configs.items(): + agents[name] = loader.load_agent(config) +``` + +## Migration from Direct Agent Construction + +If you have existing agents created directly, you can serialize them to configuration format: + +```python +from strands import Agent +from strands.experimental.config_loader.agent import AgentConfigLoader + +# Existing agent +agent = Agent( + model="us.amazon.nova-pro-v1:0", + system_prompt="You are a helpful assistant.", + tools=[calculator, web_search], + agent_id="helper_bot", + name="Helper Assistant" +) + +# Serialize to configuration +loader = AgentConfigLoader() +config = loader.serialize_agent(agent) + +# Save configuration for later use +import json +with open("agent_config.json", "w") as f: + json.dump(config, f, indent=2) + +# Later, load from configuration +with open("agent_config.json", "r") as f: + saved_config = json.load(f) + +recreated_agent = loader.load_agent(saved_config) +``` + +This enables a gradual migration from direct agent construction to configuration-based agent definitions, providing better maintainability and version control for complex agent systems. diff --git a/docs/experimental/config-loader/graph-config.md b/docs/experimental/config-loader/graph-config.md new file mode 100644 index 00000000..4a1e5d8a --- /dev/null +++ b/docs/experimental/config-loader/graph-config.md @@ -0,0 +1,1278 @@ +# GraphConfigLoader + +The GraphConfigLoader enables serialization and deserialization of Strands `Graph` instances to/from dictionary configurations, supporting persistence, version control, and dynamic graph construction. This implementation allows complex multi-agent workflows to be defined programmatically and managed as configuration. + +**Note**: This is an experimental feature that provides programmatic graph configuration loading through dictionaries. For file-based configuration, use the main Graph constructor's `config` parameter. + +## Overview + +The GraphConfigLoader provides functionality to: +- Load graphs from dictionary configurations +- Serialize existing graphs to dictionary configurations +- Support all graph elements: nodes, edges, entry points, and conditions +- Maintain referential integrity between graph components +- Enable dynamic graph construction from configuration +- Support all condition types through a unified `type` field discriminator + +## Quick Start + +### Using GraphConfigLoader + +```python +from strands.experimental.config_loader.graph import GraphConfigLoader + +# Define graph configuration +config = { + "graph": { + "graph_id": "research_workflow", + "name": "Research Team Workflow", + "description": "Processes research requests through specialized team members", + "nodes": [ + { + "node_id": "classifier", + "type": "agent", + "config": { + "name": "classifier", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a request classifier.", + "tools": [] + } + }, + { + "node_id": "processor", + "type": "agent", + "config": { + "name": "processor", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a request processor.", + "tools": [] + } + } + ], + "edges": [ + { + "from_node": "classifier", + "to_node": "processor", + "condition": { + "type": "expression", + "expression": "state.results.get('classifier', {}).get('status') == 'completed'" + } + } + ], + "entry_points": ["classifier"], + "max_node_executions": 100, + "execution_timeout": 300.0, + "node_timeout": 30.0, + "reset_on_revisit": False + } +} + +loader = GraphConfigLoader() +graph = loader.load_graph(config) + +# Execute the graph +result = graph("Analyze the impact of remote work on productivity") +``` + +### File-Based Configuration (Use Main Constructors) + +For loading from YAML/JSON files, use the main constructors instead: + +```python +from strands.multiagent import GraphBuilder + +# Load from YAML file and customize (not GraphConfigLoader) +builder = GraphBuilder.from_config('workflow.yml') + +# Add custom nodes or modify configuration +builder.add_node(custom_agent, "custom_processor") +builder.set_max_node_executions(100) + +# Build final graph +graph = builder.build() +``` + +## Schema Validation + +The ConfigLoader includes comprehensive schema validation for graphs: + +- **IDE Integration**: VSCode, IntelliJ, Vim support with autocompletion +- **Error Prevention**: Catch configuration errors before runtime +- **Type Safety**: Enforced structure and types +- **Documentation**: Schema serves as living documentation + +### Global VSCode Settings +Add to your `settings.json`: +```json +{ + "yaml.schemas": { + "https://strandsagents.com/schemas/config/v1": "*.strands.yml" + } +} +``` + +## Configuration Schema + +### Basic Graph Structure + +```python +config = { + "graph": { + "nodes": [ + { + "node_id": "agent1", + "type": "agent", + "config": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a helpful agent." + } + } + ], + "edges": [], + "entry_points": ["agent1"] + } +} +``` + +### Complete Graph Configuration + +```python +config = { + "graph": { + "graph_id": "complex_workflow", + "name": "Complex Multi-Agent Workflow", + "description": "A sophisticated workflow with multiple agent types and conditions", + "max_node_executions": 100, + "execution_timeout": 600.0, + "node_timeout": 60.0, + "reset_on_revisit": False, + "nodes": [ + { + "node_id": "classifier", + "type": "agent", + "config": { + "name": "classifier", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a request classifier. Analyze the input and categorize it.", + "tools": [ + {"name": "text_analyzer", "module": "analysis_tools.text"} + ] + } + }, + { + "node_id": "technical_processor", + "type": "agent", + "config": { + "name": "technical_processor", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a technical specialist. Handle technical queries with expertise.", + "tools": [ + {"name": "code_analyzer", "module": "dev_tools.analyzer"}, + {"name": "documentation_search", "module": "search_tools.docs"} + ] + } + }, + { + "node_id": "general_processor", + "type": "agent", + "config": { + "name": "general_processor", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a general assistant. Handle general queries helpfully.", + "tools": [ + {"name": "web_search", "module": "search_tools.web"} + ] + } + }, + { + "node_id": "quality_checker", + "type": "agent", + "config": { + "name": "quality_checker", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a quality checker. Review responses for accuracy and completeness." + } + } + ], + "edges": [ + { + "from_node": "classifier", + "to_node": "technical_processor", + "condition": { + "type": "expression", + "expression": "state.results.get('classifier', {}).get('category') == 'technical'" + } + }, + { + "from_node": "classifier", + "to_node": "general_processor", + "condition": { + "type": "expression", + "expression": "state.results.get('classifier', {}).get('category') == 'general'" + } + }, + { + "from_node": "technical_processor", + "to_node": "quality_checker", + "condition": { + "type": "expression", + "expression": "state.results.get('technical_processor', {}).get('status') == 'completed'" + } + }, + { + "from_node": "general_processor", + "to_node": "quality_checker", + "condition": { + "type": "expression", + "expression": "state.results.get('general_processor', {}).get('status') == 'completed'" + } + } + ], + "entry_points": ["classifier"], + "metadata": { + "version": "1.0.0", + "created_by": "workflow_designer", + "tags": ["classification", "processing", "quality_control"] + } + } +} +``` + +## Node Configuration + +### Agent Nodes + +```python +{ + "node_id": "data_processor", + "type": "agent", + "config": { + # Full agent configuration (as supported by AgentConfigLoader) + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a data processing expert.", + "tools": [ + {"name": "pandas_analyzer", "module": "data_tools.pandas"} + ], + "conversation_manager": { + "type": "sliding_window", + "window_size": 20 + } + } +} +``` + +### Swarm Nodes + +```python +{ + "node_id": "research_team", + "type": "swarm", + "config": { + # Full swarm configuration (as supported by SwarmConfigLoader) + "max_handoffs": 15, + "agents": [ + { + "name": "researcher", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a research specialist." + }, + { + "name": "analyst", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a data analyst." + } + ] + } +} +``` + +### Graph Nodes (Nested Graphs) + +```python +{ + "node_id": "sub_workflow", + "type": "graph", + "config": { + # Full graph configuration (nested GraphConfigLoader) + "nodes": [ + { + "node_id": "sub_agent1", + "type": "agent", + "config": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a sub-workflow agent." + } + } + ], + "edges": [], + "entry_points": ["sub_agent1"] + } +} +``` + +## Edge Conditions + +### Expression Conditions + +```python +{ + "from_node": "classifier", + "to_node": "processor", + "condition": { + "type": "expression", + "expression": "state.results.get('classifier', {}).get('confidence') > 0.8", + "description": "Route to processor if classification confidence is high" + } +} +``` + +### Rule Conditions + +```python +{ + "from_node": "validator", + "to_node": "processor", + "condition": { + "type": "rule", + "rules": [ + { + "field": "results.validator.status", + "operator": "equals", + "value": "valid" + }, + { + "field": "results.validator.confidence", + "operator": "greater_than", + "value": 0.7 + } + ], + "logic": "and", + "description": "Route if validation passes with high confidence" + } +} +``` + +### Function Conditions + +```python +{ + "from_node": "analyzer", + "to_node": "processor", + "condition": { + "type": "function", + "module": "workflow_conditions", + "function": "should_process", + "timeout": 5.0, + "default": False, + "description": "Custom function to determine processing eligibility" + } +} +``` + +### Composite Conditions + +```python +{ + "from_node": "multi_checker", + "to_node": "final_processor", + "condition": { + "type": "composite", + "logic": "and", + "conditions": [ + { + "type": "expression", + "expression": "state.execution_count < 10" + }, + { + "type": "rule", + "rules": [ + { + "field": "results.multi_checker.status", + "operator": "equals", + "value": "ready" + } + ] + } + ], + "description": "Complex condition combining multiple checks" + } +} +``` + +## Graph Execution Parameters + +### Timeout Configuration + +```python +config = { + "graph": { + "execution_timeout": 600.0, # Total graph execution timeout (10 minutes) + "node_timeout": 60.0, # Individual node timeout (1 minute) + "max_node_executions": 100, # Maximum total node executions + "reset_on_revisit": False, # Whether to reset node state on revisit + # ... rest of configuration + } +} +``` + +### Entry Points + +```python +config = { + "graph": { + "entry_points": ["classifier", "validator"], # Multiple entry points + # ... rest of configuration + } +} +``` + +### Using Cache Keys + +```python +loader = GraphConfigLoader() + +# Load with cache key +graph1 = loader.load_graph(config) +graph2 = loader.load_graph(config) # Returns cached instance + +``` + +### Serialization + +```python +# Load from config +graph = loader.load_graph(config) + +# Serialize back to config +serialized_config = loader.serialize_graph(graph) +``` + +## Error Handling + +The GraphConfigLoader provides comprehensive error handling: + +```python +try: + graph = loader.load_graph(invalid_config) +except ValueError as e: + print(f"Configuration error: {e}") +except ImportError as e: + print(f"Missing dependency: {e}") +``` + +Common error scenarios: +- **Missing required fields**: Clear messages about required graph components +- **Invalid node references**: Validation of edge node references +- **Circular dependencies**: Detection and reporting of circular graph structures +- **Condition validation errors**: Specific guidance for condition configuration + +## Advanced Examples + +### Multi-Stage Processing Pipeline + +```python +config = { + "graph": { + "graph_id": "document_processing_pipeline", + "name": "Document Processing Pipeline", + "nodes": [ + { + "node_id": "document_classifier", + "type": "agent", + "config": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Classify documents by type and priority.", + "tools": [{"name": "document_analyzer"}] + } + }, + { + "node_id": "high_priority_processor", + "type": "swarm", + "config": { + "max_handoffs": 10, + "agents": [ + { + "name": "urgent_handler", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Handle urgent documents with priority." + }, + { + "name": "quality_reviewer", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Review urgent document processing." + } + ] + } + }, + { + "node_id": "standard_processor", + "type": "agent", + "config": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Process standard documents efficiently." + } + }, + { + "node_id": "final_reviewer", + "type": "agent", + "config": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Final review and quality check." + } + } + ], + "edges": [ + { + "from_node": "document_classifier", + "to_node": "high_priority_processor", + "condition": { + "type": "expression", + "expression": "state.results.get('document_classifier', {}).get('priority') == 'high'" + } + }, + { + "from_node": "document_classifier", + "to_node": "standard_processor", + "condition": { + "type": "expression", + "expression": "state.results.get('document_classifier', {}).get('priority') == 'standard'" + } + }, + { + "from_node": "high_priority_processor", + "to_node": "final_reviewer" + }, + { + "from_node": "standard_processor", + "to_node": "final_reviewer" + } + ], + "entry_points": ["document_classifier"], + "max_node_executions": 50, + "execution_timeout": 900.0, + "node_timeout": 120.0 + } +} +``` + +### Conditional Workflow with Loops + +```python +config = { + "graph": { + "graph_id": "iterative_refinement", + "name": "Iterative Content Refinement", + "nodes": [ + { + "node_id": "content_generator", + "type": "agent", + "config": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Generate content based on requirements." + } + }, + { + "node_id": "quality_evaluator", + "type": "agent", + "config": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Evaluate content quality and suggest improvements." + } + }, + { + "node_id": "content_refiner", + "type": "agent", + "config": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Refine content based on feedback." + } + }, + { + "node_id": "final_approver", + "type": "agent", + "config": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Final approval and formatting." + } + } + ], + "edges": [ + { + "from_node": "content_generator", + "to_node": "quality_evaluator" + }, + { + "from_node": "quality_evaluator", + "to_node": "content_refiner", + "condition": { + "type": "composite", + "logic": "and", + "conditions": [ + { + "type": "expression", + "expression": "state.results.get('quality_evaluator', {}).get('needs_refinement') == True" + }, + { + "type": "expression", + "expression": "state.execution_count < 5" + } + ] + } + }, + { + "from_node": "content_refiner", + "to_node": "quality_evaluator" + }, + { + "from_node": "quality_evaluator", + "to_node": "final_approver", + "condition": { + "type": "expression", + "expression": "state.results.get('quality_evaluator', {}).get('approved') == True" + } + } + ], + "entry_points": ["content_generator"], + "max_node_executions": 20, + "reset_on_revisit": True + } +} +``` + +## Best Practices + +1. **Use Schema Validation**: Enable IDE integration for better development experience +2. **Design Clear Node IDs**: Use descriptive, unique identifiers for all nodes +3. **Structure Conditions**: Write clear, testable conditions with good descriptions +4. **Manage Complexity**: Break complex workflows into smaller, manageable graphs +5. **Test Workflows**: Validate graph configurations and test execution paths +6. **Document Workflows**: Use metadata and descriptions to document graph purpose + +## Next Steps + +- [Agent Configuration](agent-config.md) - Detailed agent configuration for graph nodes +- [Swarm Configuration](swarm-config.md) - Swarm configuration for graph nodes +- [Tool Configuration](tool-config.md) - Tool configuration for graph agents +- [Structured Output](structured-output.md) - Structured output for graph agents + +#### Swarm Nodes + +```yaml +nodes: + - node_id: "research_team" + type: "swarm" + config: + # Full swarm configuration (as supported by SwarmConfigLoader) + max_handoffs: 10 + agents: + - name: "researcher1" + model: "us.amazon.nova-lite-v1:0" + system_prompt: "You are a researcher." + - name: "researcher2" + model: "us.amazon.nova-lite-v1:0" + system_prompt: "You are an analyst." +``` + +#### Nested Graph Nodes + +```yaml +nodes: + - node_id: "sub_workflow" + type: "graph" + config: + nodes: [...] + edges: [...] + entry_points: [...] +``` + +#### Reference Nodes (Future Enhancement) + +```yaml +nodes: + - node_id: "data_processor" + type: "agent" + reference: "my_agents.data_processor" # String identifier for lookup +``` + +### Condition Types + +The GraphConfigLoader supports multiple condition types through a unified `type` field discriminator: + +#### 1. Expression Conditions (`type: "expression"`) + +Use string expressions evaluated against the GraphState: + +```yaml +condition: + type: "expression" + expression: "state.results.get('validator', {}).get('status') == 'success'" + description: "Check if validation was successful" + default: false +``` + +#### 2. Rule-Based Conditions (`type: "rule"`) + +Define conditions using structured rules for common patterns: + +```yaml +condition: + type: "rule" + rules: + - field: "results.validator.status" + operator: "equals" + value: "success" + - field: "results.validator.confidence" + operator: "greater_than" + value: 0.8 + logic: "and" # or "or" + description: "Successful validation with high confidence" +``` + +**Supported Operators:** +- `equals`, `not_equals` +- `greater_than`, `less_than`, `greater_equal`, `less_equal` +- `contains`, `starts_with`, `ends_with` +- `regex_match` + +#### 3. Function Reference Conditions (`type: "function"`) + +Reference functions by module path and function name: + +```yaml +condition: + type: "function" + module: "workflow.conditions" + function: "is_technical" + description: "Checks if request is technical" + timeout: 5.0 + default: false +``` + +**Implementation Pattern:** +```python +# In workflow/conditions.py +def is_technical(state: GraphState) -> bool: + classifier_result = state.results.get("classifier") + if not classifier_result: + return False + result_text = str(classifier_result.result) + return "technical" in result_text.lower() +``` + +#### 4. Lambda Conditions (`type: "lambda"`) + +Simple lambda expressions for basic conditions: + +```yaml +condition: + type: "lambda" + expression: "lambda state: 'technical' in str(state.results.get('classifier', {}).get('result', '')).lower()" + description: "Check for technical classification" + timeout: 2.0 +``` + +#### 5. Template Conditions (`type: "template"`) + +Pre-defined condition templates for common patterns: + +```yaml +condition: + type: "template" + template: "node_result_contains" + parameters: + node_id: "classifier" + search_text: "technical" + case_sensitive: false + description: "Check if classifier result contains 'technical'" +``` + +**Available Templates:** +- `node_result_contains`: Check if node result contains text +- `node_execution_time_under`: Check if node execution time is under threshold +- `node_status_equals`: Check if node status equals expected value +- `execution_count_under`: Check if execution count is under threshold + +#### 6. Composite Conditions (`type: "composite"`) + +Combine multiple conditions with logical operators: + +```yaml +condition: + type: "composite" + logic: "and" # "and", "or", "not" + conditions: + - type: "function" + module: "conditions" + function: "is_valid" + - type: "expression" + expression: "state.execution_count < 10" + description: "Valid data and under execution limit" +``` + +## Complete Examples + +### Example 1: Basic Sequential Processing + +```yaml +# basic_processing_graph.yaml +graph_id: "research_team_workflow" +name: "Research Team Workflow" +description: "Processes research requests through specialized team members" + +nodes: + - node_id: "team_lead" + type: "agent" + config: + name: "coordinator" + system_prompt: "You are a research team leader coordinating specialists." + model: "us.amazon.nova-pro-v1:0" + + - node_id: "analyst" + type: "agent" + config: + name: "data_analyst" + system_prompt: "You are a data analyst providing detailed analysis." + model: "us.amazon.nova-lite-v1:0" + + - node_id: "expert" + type: "agent" + config: + name: "domain_expert" + system_prompt: "You are a domain expert providing specialized insights." + model: "us.amazon.nova-lite-v1:0" + +edges: + - from_node: "team_lead" + to_node: "analyst" + condition: null + + - from_node: "team_lead" + to_node: "expert" + condition: null + +entry_points: + - "team_lead" + +max_node_executions: null +execution_timeout: null +node_timeout: null +reset_on_revisit: false + +metadata: + version: "1.0.0" + created_by: "tutorial_example" + tags: ["research", "analysis", "coordination"] +``` + +### Example 2: Conditional Branching + +```yaml +# conditional_branching_graph.yaml +graph_id: "classification_workflow" +name: "Classification and Routing Workflow" +description: "Classifies requests and routes to appropriate specialists" + +nodes: + - node_id: "classifier" + type: "agent" + config: + name: "classifier" + system_prompt: "You are an agent responsible for classification of the report request, return only Technical or Business classification." + model: "us.amazon.nova-lite-v1:0" + + - node_id: "technical_report" + type: "agent" + config: + name: "technical_expert" + system_prompt: "You are a technical expert that focuses on providing short summary from technical perspective" + model: "us.amazon.nova-pro-v1:0" + + - node_id: "business_report" + type: "agent" + config: + name: "business_expert" + system_prompt: "You are a business expert that focuses on providing short summary from business perspective" + model: "us.amazon.nova-pro-v1:0" + +edges: + - from_node: "classifier" + to_node: "technical_report" + condition: + type: "function" + module: "workflow.conditions" + function: "is_technical" + description: "Route to technical expert if classified as technical" + + - from_node: "classifier" + to_node: "business_report" + condition: + type: "function" + module: "workflow.conditions" + function: "is_business" + description: "Route to business expert if classified as business" + +entry_points: + - "classifier" + +max_node_executions: 10 +execution_timeout: 60.0 +node_timeout: 30.0 +reset_on_revisit: false +``` + +### Example 3: Complex Multi-Agent Pipeline + +```yaml +# complex_pipeline_graph.yaml +graph_id: "data_processing_pipeline" +name: "Data Processing Pipeline" +description: "Comprehensive data processing through validation, analysis, and reporting" + +nodes: + - node_id: "input_validator" + type: "agent" + config: + model: "us.amazon.nova-lite-v1:0" + system_prompt: "Validate incoming data for completeness and format." + tools: + - name: "data_validator" + + - node_id: "data_analyzer" + type: "agent" + reference: "my_agents.analyzer" # String reference to existing agent + + - node_id: "report_generator" + type: "swarm" + config: + agents: + - name: "summary_writer" + config: + system_prompt: "Generate executive summaries" + model: "us.amazon.nova-lite-v1:0" + - name: "chart_generator" + config: + system_prompt: "Create data visualizations" + model: "us.amazon.nova-lite-v1:0" + tools: + - name: "matplotlib_tool" + + - node_id: "quality_checker" + type: "agent" + config: + model: "us.amazon.nova-pro-v1:0" + system_prompt: "Review and validate the quality of generated reports." + + - node_id: "error_handler" + type: "agent" + config: + model: "us.amazon.nova-lite-v1:0" + system_prompt: "Handle and log processing errors with recovery suggestions." + +edges: + # Validation flow + - from_node: "input_validator" + to_node: "data_analyzer" + condition: + type: "function" + module: "workflow.conditions" + function: "is_data_valid" + description: "Proceed if data validation passes" + + - from_node: "input_validator" + to_node: "error_handler" + condition: + type: "function" + module: "workflow.conditions" + function: "is_data_invalid" + description: "Handle validation failures" + + # Analysis flow + - from_node: "data_analyzer" + to_node: "report_generator" + condition: + type: "expression" + expression: "state.results.get('data_analyzer', {}).get('status') == 'completed'" + description: "Generate report when analysis is complete" + + - from_node: "data_analyzer" + to_node: "error_handler" + condition: + type: "rule" + rules: + - field: "results.data_analyzer.status" + operator: "equals" + value: "error" + description: "Handle analysis errors" + + # Quality control flow + - from_node: "report_generator" + to_node: "quality_checker" + condition: + type: "composite" + logic: "and" + conditions: + - type: "expression" + expression: "state.results.get('report_generator', {}).get('status') == 'completed'" + - type: "template" + template: "node_execution_time_under" + parameters: + node_id: "report_generator" + max_time_ms: 30000 + description: "Quality check if report generation completed successfully and quickly" + +entry_points: + - "input_validator" + +# Execution limits +max_node_executions: 50 +execution_timeout: 300.0 +node_timeout: 60.0 +reset_on_revisit: true + +metadata: + version: "2.1.0" + created_by: "data_team" + tags: ["data_processing", "validation", "reporting", "quality_control"] + environment: "production" +``` + +## API Reference + +### GraphConfigLoader Class + +```python +class GraphConfigLoader: + def __init__(self, + agent_loader: Optional[AgentConfigLoader] = None, + swarm_loader: Optional[SwarmConfigLoader] = None) + def load_graph(self, config: Dict[str, Any], cache_key: Optional[str] = None) -> Graph + def serialize_graph(self, graph: Graph) -> Dict[str, Any] + def clear_cache(self) -> None + def get_available_graphs(self) -> List[str] +``` + +#### Methods + +**`load_graph(config)`** +- Load a Graph from YAML configuration (loaded as dictionary) +- `config`: Dictionary containing graph configuration +- `cache_key`: Optional key for caching the loaded graph +- Returns: Graph instance configured according to the provided dictionary +- Raises: `ValueError` if configuration is invalid, `ImportError` if models/tools cannot be imported + +**`serialize_graph(graph)`** +- Serialize a Graph instance to YAML-compatible dictionary configuration +- `graph`: Graph instance to serialize +- Returns: Dictionary containing the graph's configuration that can be saved as YAML +- Note: Condition serialization is complex and may require manual reconstruction + +**`clear_cache()`** +- Clear the internal graph cache +- Useful for memory management in long-running applications + +**`get_available_graphs()`** +- Get list of cached graph keys +- Returns: List of cached graph keys + +### ConditionRegistry Class + +```python +class ConditionRegistry: + def load_condition(self, config: Dict[str, Any]) -> Callable[[GraphState], bool] +``` + +The ConditionRegistry handles all condition types through type-based dispatch and provides security features like expression sanitization and module access validation. + +## Usage Examples + +### Loading from YAML File + +```python +from strands.experimental.config_loader.graph import GraphConfigLoader +import yaml + +# Load configuration +with open('workflow.yml', 'r') as f: + config = yaml.safe_load(f) + +loader = GraphConfigLoader() +graph = loader.load_graph(config) + +# Execute the graph +result = graph("Analyze the impact of remote work on employee productivity") + +# Access results +print(f"Total nodes: {result.total_nodes}") +print(f"Completed nodes: {result.completed_nodes}") +print(f"Execution order: {[node.node_id for node in result.execution_order]}") +``` + +### Dynamic Graph Construction + +```python +def create_classification_workflow(enable_technical: bool = True, enable_business: bool = True): + """Create a classification workflow with configurable branches.""" + + base_config = { + "graph_id": "dynamic_classifier", + "nodes": [ + { + "node_id": "classifier", + "type": "agent", + "config": { + "system_prompt": "Classify the request as Technical or Business", + "model": "us.amazon.nova-lite-v1:0" + } + } + ], + "edges": [], + "entry_points": ["classifier"] + } + + # Add technical branch if enabled + if enable_technical: + base_config["nodes"].append({ + "node_id": "technical_processor", + "type": "agent", + "config": { + "system_prompt": "Process technical requests", + "model": "us.amazon.nova-pro-v1:0" + } + }) + base_config["edges"].append({ + "from_node": "classifier", + "to_node": "technical_processor", + "condition": { + "type": "function", + "module": "conditions", + "function": "is_technical" + } + }) + + # Add business branch if enabled + if enable_business: + base_config["nodes"].append({ + "node_id": "business_processor", + "type": "agent", + "config": { + "system_prompt": "Process business requests", + "model": "us.amazon.nova-pro-v1:0" + } + }) + base_config["edges"].append({ + "from_node": "classifier", + "to_node": "business_processor", + "condition": { + "type": "function", + "module": "conditions", + "function": "is_business" + } + }) + + return GraphConfigLoader().load_graph(base_config) + +# Create different workflow variants +tech_only_workflow = create_classification_workflow(enable_business=False) +full_workflow = create_classification_workflow() +``` + +### Integration with GraphBuilder + +```python +from strands.multiagent import GraphBuilder + +# Load base configuration and customize +builder = GraphBuilder.from_config("base_workflow.yaml") + +# Add custom nodes or modify configuration +builder.add_node(custom_agent, "custom_processor") +builder.add_edge("data_analyzer", "custom_processor") +builder.set_max_node_executions(50) + +# Build final graph +graph = builder.build() +``` + +## Security Considerations + +The GraphConfigLoader implements several security measures: + +1. **Module Access Control**: Only allowed modules can be imported for function conditions +2. **Expression Sanitization**: Dangerous patterns are blocked in expressions and lambdas +3. **Length Limits**: Expressions have maximum length limits to prevent abuse +4. **Timeout Protection**: Condition evaluation can be wrapped with timeouts +5. **Safe Evaluation**: Restricted execution environments with limited builtins + +```python +# Security configuration +registry = ConditionRegistry() +registry.allowed_modules = ["conditions", "workflow.conditions"] +registry.max_expression_length = 500 +registry.evaluation_timeout = 5.0 +``` + +## Best Practices + +1. **Use Descriptive Node IDs**: Node IDs should clearly indicate their purpose +2. **Organize Conditions**: Group related condition functions in dedicated modules +3. **Validate Configurations**: Test configurations with simple inputs before production +4. **Use Templates**: Leverage condition templates for common patterns +5. **Document Conditions**: Include descriptions for all conditions +6. **Version Control**: Store YAML configurations in version control +7. **Environment-Specific Configs**: Use different configurations for different environments +8. **Monitor Performance**: Set appropriate timeouts and execution limits +9. **Cache Frequently Used Graphs**: Use cache keys for graphs loaded multiple times +10. **Security First**: Validate all condition functions and expressions + +## Troubleshooting + +### Common Issues + +**Configuration Validation Errors** +```python +# Error: Graph configuration must include 'nodes' field +# Solution: Ensure your config has required fields +config = { + "nodes": [...], # Required + "edges": [...], # Required + "entry_points": [...] # Required +} +``` + +**Condition Loading Failures** +```python +# Error: Cannot load condition function module.function +# Solution: Ensure module is in allowed list and function exists +condition = { + "type": "function", + "module": "conditions", # Must be in allowed_modules + "function": "is_valid" # Must exist in module +} +``` + +**Node Reference Issues** +```python +# Error: Edge references unknown from_node +# Solution: Ensure all edge references point to existing nodes +edges = [ + { + "from_node": "classifier", # Must exist in nodes + "to_node": "processor" # Must exist in nodes + } +] +``` + +### Performance Tips + +2. **Optimize Conditions**: Use simple expressions and avoid complex computations +3. **Set Timeouts**: Configure appropriate timeouts for condition evaluation +4. **Minimize Config Size**: Only include non-default values in configurations +5. **Batch Operations**: Load multiple graphs with the same GraphConfigLoader instance + +### Integration Notes + +- **AgentConfigLoader Integration**: GraphConfigLoader automatically uses AgentConfigLoader for agent nodes +- **SwarmConfigLoader Integration**: GraphConfigLoader automatically uses SwarmConfigLoader for swarm nodes +- **Circular Import Avoidance**: Uses lazy loading to prevent circular import issues +- **Error Handling**: Provides clear error messages for debugging configuration issues +- **Backward Compatibility**: Designed to work with existing Graph and GraphBuilder patterns diff --git a/docs/experimental/config-loader/overview.md b/docs/experimental/config-loader/overview.md new file mode 100644 index 00000000..890b9bb8 --- /dev/null +++ b/docs/experimental/config-loader/overview.md @@ -0,0 +1,485 @@ +# Configuration Loaders Overview + +## Introduction + +**Note**: This is an experimental feature that provides programmatic configuration loading through Python dictionaries. For file-based configuration (YAML/JSON), use the main constructors' `config` parameter. + +Configuration loaders enable programmatic, dictionary-driven definition of agents, tools, swarms, and graphs. This approach provides: + +- **Dynamic Configuration**: Create configurations programmatically at runtime +- **Configuration Management**: Build configuration management systems +- **Serialization/Deserialization**: Convert between objects and dictionary representations +- **Caching**: Efficient reuse of configured components +- **Schema Validation**: Comprehensive validation with IDE integration support + +## Supported Configuration Format + +Configuration loaders work exclusively with Python dictionaries with required top-level keys for programmatic use: + +### Python Dictionary Configuration + +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a helpful assistant.", + "tools": [{"name": "calculator"}] + } +} + +loader = AgentConfigLoader() +agent = loader.load_agent(config) +``` + +### File-Based Configuration (Use Main Constructors) + +For loading from YAML/JSON files, use the main constructors instead: + +```python +from strands import Agent +from strands.multiagent import Swarm + +# File-based loading (not config loaders) +agent = Agent(config="config.yml") +swarm = Swarm(config="swarm.yml") +``` + +## Schema Validation + +The ConfigLoader includes comprehensive schema validation: + +- **IDE Integration**: VSCode, IntelliJ, Vim support with autocompletion +- **Error Prevention**: Catch configuration errors before runtime +- **Type Safety**: Enforced structure and types +- **Documentation**: Schema serves as living documentation + +## IDE Integration + +### Global VSCode Settings +Add to your `settings.json`: +```json +{ + "yaml.schemas": { + "https://strandsagents.com/schemas/config/v1": "*.strands.yml" + } +} +``` + +### Other IDEs +- **IntelliJ/PyCharm**: Built-in YAML plugin with schema support +- **Vim/Neovim**: Use `coc-yaml` or similar LSP plugins + +## Configuration Schema + +All configuration loaders follow consistent patterns: +- Dictionary-based configuration with required top-level keys +- Comprehensive schema validation +- Validation and error handling +- Caching and performance optimization +- Programmatic configuration management + +## Supported Configuration Types + +### Agent Configuration +Define individual agents with models, prompts, tools, and behavior settings using `AgentConfigLoader`. + +### Tool Configuration +Configure tools from Python functions, external modules, or multi-agent configurations using `ToolConfigLoader`. + +### Swarm Configuration +Define multi-agent swarms with specialized roles and coordination patterns using `SwarmConfigLoader`. + +### Graph Configuration +Create complex multi-agent workflows with conditional routing and dependencies using `GraphConfigLoader`. + +## Quick Start Examples + +### Basic Agent Configuration + +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a helpful customer service agent.", + "tools": [ + {"name": "calculator"}, + {"name": "web_search", "module": "my_tools.search"} + ] + } +} + +loader = AgentConfigLoader() +agent = loader.load_agent(config) +response = agent("Help me calculate my order total") +``` + +### Multi-Agent Swarm Configuration + +```python +from strands.experimental.config_loader.swarm import SwarmConfigLoader + +config = { + "swarm": { + "max_handoffs": 20, + "agents": [ + { + "name": "research_agent", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a research specialist." + }, + { + "name": "creative_agent", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a creative writing specialist." + } + ] + } +} + +loader = SwarmConfigLoader() +swarm = loader.load_swarm(config) +result = swarm("Create a blog post about AI") +``` + +### Graph Workflow Configuration + +```python +from strands.experimental.config_loader.graph import GraphConfigLoader + +config = { + "graph": { + "nodes": [ + { + "node_id": "classifier", + "type": "agent", + "config": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a request classifier." + } + }, + { + "node_id": "processor", + "type": "agent", + "config": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a request processor." + } + } + ], + "edges": [ + { + "from_node": "classifier", + "to_node": "processor", + "condition": { + "type": "expression", + "expression": "state.results.get('classifier', {}).get('status') == 'completed'" + } + } + ], + "entry_points": ["classifier"] + } +} + +loader = GraphConfigLoader() +graph = loader.load_graph(config) +result = graph("Process this request") +``` + +## Configuration Structure Requirements + +### Top-Level Keys +All configurations must use the appropriate top-level key: + +- **Agent configurations**: `{"agent": {...}}` +- **Graph configurations**: `{"graph": {...}}` +- **Swarm configurations**: `{"swarm": {...}}` +- **Tool configurations**: `{"tools": [...]}` + +### Nested Configurations +When using agents, graphs, or swarms as tools, they maintain their required structure: + +```python +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a coordinator.", + "tools": [ + { + "name": "research_assistant", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a research specialist." + } + } + ] + } +} +``` + +## Advanced Features + +### Structured Output +Configure agents to return structured data using Pydantic models: + +```python +config = { + "schemas": [ + { + "name": "UserProfile", + "schema": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "email": {"type": "string"} + }, + "required": ["name", "email"] + } + } + ], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Extract user information from text.", + "structured_output": "UserProfile" + } +} +``` + +### Serialization +Convert existing objects back to configuration dictionaries: + +```python +# Load from config +agent = loader.load_agent(config) + +# Serialize back to config +serialized_config = loader.serialize_agent(agent) +``` + +## Error Handling + +The configuration loaders provide comprehensive error handling: + +- **Validation Errors**: Clear messages for invalid configurations +- **Type Errors**: Specific guidance for incorrect data types +- **Missing Dependencies**: Helpful messages for missing tools or models +- **Schema Validation**: Real-time validation with IDE integration + +## Best Practices + +1. **Use Schema Validation**: Enable IDE integration for better development experience +2. **Structure Configurations**: Organize complex configurations with clear naming +3. **Test Configurations**: Validate configurations against the schema before deployment +4. **Document Custom Tools**: Provide clear documentation for custom tool configurations + +## Next Steps + +- [Agent Configuration](agent-config.md) - Detailed agent configuration options +- [Graph Configuration](graph-config.md) - Multi-agent workflow configuration +- [Swarm Configuration](swarm-config.md) - Collaborative agent team configuration +- [Tool Configuration](tool-config.md) - Tool loading and agent-as-tool patterns +- [Structured Output](structured-output.md) - Structured data extraction configuration + }, + { + "name": "creative_agent", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a creative solution generator." + } + ] +} + +loader = SwarmConfigLoader() +swarm = loader.load_swarm(config) +result = swarm("Create a blog post about AI") +``` + +## Migration from Programmatic Approach + +### Before (Direct Instantiation) +```python +from strands import Agent +from strands_tools import calculator, web_search + +agent = Agent( + model="us.amazon.nova-pro-v1:0", + system_prompt="You are a helpful assistant.", + tools=[calculator, web_search] +) +``` + +### After (Configuration-Driven) +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +config = { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a helpful assistant.", + "tools": [ + {"name": "calculator"}, + {"name": "web_search"} + ] +} + +loader = AgentConfigLoader() +agent = loader.load_agent(config) +``` + +--- + +## Available Configuration Loaders + +### AgentConfigLoader +Loads and serializes Strands Agent instances via dictionary configurations. Supports model configuration, tool loading, structured output, and advanced agent features. + +**Key Methods:** +- `load_agent(config)` - Load agent from dictionary configuration +- `serialize_agent(agent)` - Serialize agent to dictionary configuration + +### ToolConfigLoader +Loads AgentTool instances via string identifiers or multi-agent configurations. Supports @tool decorated functions, module-based tools, and Agent-as-Tool functionality. + +**Key Methods:** +- `load_tool(tool, module_path=None)` - Load tool by identifier or configuration +- `load_tools(identifiers)` - Load multiple tools +- `get_available_tools(module_path=None)` - Get list of available tool identifiers + +### SwarmConfigLoader +Loads and serializes Strands Swarm instances via dictionary configurations. Leverages AgentConfigLoader for agent management and adds swarm-specific configuration. + +**Key Methods:** +- `load_swarm(config)` - Load swarm from dictionary configuration +- `serialize_swarm(swarm)` - Serialize swarm to dictionary configuration +- `load_agents(agents_config)` - Load multiple agents from configuration + +### GraphConfigLoader +Loads and serializes Strands Graph instances via dictionary configurations. Supports nodes, edges, entry points, and condition configurations. + +**Key Methods:** +- `load_graph(config)` - Load graph from dictionary configuration +- `serialize_graph(graph)` - Serialize graph to dictionary configuration + +--- + +## Future: Constructor Integration + +**Note**: This section documents a future enhancement that would integrate configuration loading directly into the main constructors for improved API fluidity and developer experience. + +### Enhanced Constructor Interface + +The future implementation would extend the main constructors (`Agent()`, `Graph()`, and `Swarm()`) with a `config` parameter, enabling seamless configuration-driven initialization alongside traditional programmatic instantiation. + +#### Agent Constructor Enhancement + +```python +from strands import Agent + +# File-based configuration +agent = Agent(config="agent_config.yaml") +agent = Agent(config="agent_config.json") + +# Dictionary-based configuration +agent = Agent(config={ + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a helpful assistant.", + "tools": [{"name": "calculator"}] +}) + +# Hybrid approach - config with parameter overrides +agent = Agent( + config="base_config.yaml", + model="us.amazon.nova-lite-v1:0", # Override config model + system_prompt="Custom prompt" # Override config prompt +) +``` + +#### Swarm Constructor Enhancement + +```python +from strands.multiagent import Swarm + +# File-based configuration +swarm = Swarm(config="swarm_config.yaml") + +# Dictionary-based configuration +swarm = Swarm(config={ + "max_handoffs": 15, + "agents": [ + { + "name": "researcher", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a research specialist." + } + ] +}) + +# Parameter override capability +swarm = Swarm( + config="base_swarm.yaml", + max_handoffs=25, # Override config value + execution_timeout=1200.0 +) +``` + +#### Graph Constructor Enhancement + +```python +from strands.multiagent import Graph + +# File-based configuration via GraphBuilder +graph = Graph.from_config("graph_config.yaml").build() + +# Dictionary-based configuration +graph = Graph.from_config({ + "nodes": [ + { + "id": "analyzer", + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Analyze the input data." + } + } + ], + "edges": [ + {"from": "analyzer", "to": "reporter"} + ], + "entry_points": ["analyzer"] +}).build() +``` + +### API Fluidity Advantages + +#### Unified Interface +- **Consistent Experience**: Single constructor interface supports both programmatic and configuration-driven approaches +- **Seamless Migration**: Easy transition from code-based to config-based initialization without changing the fundamental API +- **Reduced Learning Curve**: Developers familiar with the main constructors can immediately use configuration features + +#### Flexible Configuration Management +- **Parameter Override**: Config provides defaults while explicit parameters override specific values +- **Environment Adaptation**: Same codebase can use different configurations for development, staging, and production +- **Dynamic Configuration**: Runtime configuration selection based on conditions or user input + +#### Enhanced Developer Experience +- **Reduced Boilerplate**: Configuration files eliminate repetitive parameter specification +- **Better Maintainability**: Centralized configuration management separate from application logic +- **Version Control Friendly**: Configuration changes tracked separately from code changes +- **IDE Support**: Full IntelliSense and type checking for both config and parameter approaches + +#### Backward Compatibility +- **Zero Breaking Changes**: Existing code continues to work unchanged +- **Gradual Adoption**: Teams can migrate to configuration-driven approach incrementally +- **Interoperability**: Mix and match approaches within the same application + +### Implementation Benefits + +The enhanced constructor approach provides superior API fluidity by: + +1. **Eliminating Context Switching**: Developers stay within familiar constructor patterns rather than learning separate loader classes +2. **Reducing Import Complexity**: No need to import and manage separate config loader classes +3. **Maintaining Type Safety**: Full type hints and validation for both configuration and parameter approaches +4. **Enabling Hybrid Workflows**: Seamless combination of configuration defaults with runtime parameter overrides +5. **Preserving Existing Patterns**: All current usage patterns remain valid while adding new capabilities + +This approach represents the natural evolution of the Strands Agents API, providing maximum flexibility while maintaining the simplicity and elegance that developers expect from the framework. diff --git a/docs/experimental/config-loader/structured-output.md b/docs/experimental/config-loader/structured-output.md new file mode 100644 index 00000000..e223fc61 --- /dev/null +++ b/docs/experimental/config-loader/structured-output.md @@ -0,0 +1,1287 @@ +# Structured Output Configuration + +This document provides comprehensive guidance on configuring structured output for agents using dictionary configurations. The structured output feature allows you to define Pydantic models declaratively and have agents automatically return structured data instead of plain text. + +**Note**: This is an experimental feature that provides programmatic structured output configuration through dictionaries. For file-based configuration, use the main Agent constructor's `config` parameter. + +## Overview + +Structured output configuration enables you to: + +- Define output schemas using JSON Schema syntax in dictionary configurations +- Reference existing Pydantic models from your codebase +- Load schemas from external JSON/YAML files +- Configure validation and error handling behavior +- Create reusable schema libraries across multiple agents + +## Schema Validation + +The ConfigLoader includes comprehensive schema validation for structured output: + +- **IDE Integration**: VSCode, IntelliJ, Vim support with autocompletion +- **Error Prevention**: Catch configuration errors before runtime +- **Type Safety**: Enforced structure and types +- **Documentation**: Schema serves as living documentation + +### Global VSCode Settings +Add to your `settings.json`: +```json +{ + "yaml.schemas": { + "https://strandsagents.com/schemas/config/v1": "*.strands.yml" + } +} +``` + +## Quick Start + +### Basic Configuration + +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +# Define configuration with schema +config = { + "schemas": [ + { + "name": "UserProfile", + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "User's full name" + }, + "email": { + "type": "string", + "format": "email", + "description": "User's email address" + }, + "age": { + "type": "integer", + "minimum": 0, + "description": "User's age" + } + }, + "required": ["name", "email"] + } + } + ], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Extract user information from text.", + "structured_output": "UserProfile" + } +} + +# Load agent with structured output +loader = AgentConfigLoader() +agent = loader.load_agent(config) + +# Use structured output +result = agent.structured_output("Extract info: John Doe, 30 years old, john@example.com") +print(f"Name: {result.name}") +print(f"Email: {result.email}") +print(f"Age: {result.age}") + +# Or use the convenience method +result = agent.extract_userprofile("Extract info: Jane Smith, jane@example.com") +``` + +## Schema Definition Methods + +### 1. Inline Schema Definition + +Define schemas directly in your configuration using JSON Schema syntax: + +```python +config = { + "schemas": [ + { + "name": "ProductInfo", + "description": "Product information schema", + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Product name" + }, + "price": { + "type": "number", + "minimum": 0, + "description": "Product price in USD" + }, + "category": { + "type": "string", + "enum": ["electronics", "clothing", "books", "home"], + "description": "Product category" + }, + "in_stock": { + "type": "boolean", + "description": "Whether product is in stock" + }, + "tags": { + "type": "array", + "items": {"type": "string"}, + "description": "Product tags" + } + }, + "required": ["name", "price", "category"] + } + } + ], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Extract product information from descriptions.", + "structured_output": "ProductInfo" + } +} +``` + +### 2. External Schema Files + +Load schemas from external JSON or YAML files: + +```python +import tempfile +import yaml + +# Create external schema file +schema_dict = { + "type": "object", + "properties": { + "company": {"type": "string"}, + "revenue": {"type": "number", "minimum": 0}, + "employees": {"type": "integer", "minimum": 1} + }, + "required": ["company", "revenue"] +} + +with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: + yaml.dump(schema_dict, f) + schema_file_path = f.name + +# Reference external schema file +config = { + "schemas": [ + { + "name": "CompanyInfo", + "schema_file": schema_file_path + } + ], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Extract company information from text.", + "structured_output": "CompanyInfo" + } +} +``` + +### 3. Python Class References + +Reference existing Pydantic models from your codebase: + +```python +# Define a Pydantic model in your code +from pydantic import BaseModel +from typing import Optional + +class BusinessModel(BaseModel): + company_name: str + revenue: Optional[float] = None + industry: Optional[str] = None + +# Reference the Python class +config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Extract business information from text.", + "structured_output": "tests.strands.experimental.config_loader.agent.test_agent_config_loader_structured_output.BusinessModel" + } +} +``` + +## Detailed Structured Output Configuration + +### Simple Schema Reference + +```python +config = { + "schemas": [ + { + "name": "ContactInfo", + "schema": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "phone": {"type": "string"}, + "email": {"type": "string", "format": "email"} + }, + "required": ["name"] + } + } + ], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Extract contact information.", + "structured_output": "ContactInfo" # Simple reference + } +} +``` + +### Detailed Configuration with Validation Settings + +```python +config = { + "schemas": [ + { + "name": "CustomerData", + "schema": { + "type": "object", + "properties": { + "customer_id": {"type": "string"}, + "name": {"type": "string"}, + "email": {"type": "string", "format": "email"}, + "purchase_history": { + "type": "array", + "items": { + "type": "object", + "properties": { + "product": {"type": "string"}, + "amount": {"type": "number"}, + "date": {"type": "string", "format": "date"} + } + } + } + }, + "required": ["customer_id", "name", "email"] + } + } + ], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Extract comprehensive customer data.", + "structured_output": { + "schema": "CustomerData", + "validation": { + "strict": True, + "allow_extra_fields": False + }, + "error_handling": { + "retry_on_validation_error": True, + "max_retries": 3 + } + } + } +} +``` + +## Global Schema Defaults + +Configure default settings for all structured output operations: + +```python +config = { + "schemas": [ + { + "name": "TaskResult", + "schema": { + "type": "object", + "properties": { + "status": {"type": "string", "enum": ["success", "failure", "pending"]}, + "result": {"type": "string"}, + "confidence": {"type": "number", "minimum": 0, "maximum": 1} + }, + "required": ["status", "result"] + } + } + ], + "structured_output_defaults": { + "validation": { + "strict": False, + "allow_extra_fields": True + }, + "error_handling": { + "retry_on_validation_error": False, + "max_retries": 1 + } + }, + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Process tasks and return structured results.", + "structured_output": { + "schema": "TaskResult", + "validation": { + "strict": True # Override default + } + # error_handling will use defaults + } + } +} +``` + +## Complex Schema Examples + +### Nested Object Schema + +```python +config = { + "schemas": [ + { + "name": "OrderDetails", + "schema": { + "type": "object", + "properties": { + "order_id": {"type": "string"}, + "customer": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "email": {"type": "string", "format": "email"}, + "address": { + "type": "object", + "properties": { + "street": {"type": "string"}, + "city": {"type": "string"}, + "zip_code": {"type": "string"}, + "country": {"type": "string"} + }, + "required": ["street", "city", "country"] + } + }, + "required": ["name", "email"] + }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "product_id": {"type": "string"}, + "name": {"type": "string"}, + "quantity": {"type": "integer", "minimum": 1}, + "price": {"type": "number", "minimum": 0} + }, + "required": ["product_id", "name", "quantity", "price"] + } + }, + "total_amount": {"type": "number", "minimum": 0}, + "order_date": {"type": "string", "format": "date-time"} + }, + "required": ["order_id", "customer", "items", "total_amount"] + } + } + ], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Extract complete order information from order confirmations.", + "structured_output": "OrderDetails" + } +} +``` + +### Multiple Schema Configuration + +```python +config = { + "schemas": [ + { + "name": "PersonInfo", + "schema": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "age": {"type": "integer", "minimum": 0}, + "occupation": {"type": "string"} + }, + "required": ["name"] + } + }, + { + "name": "CompanyInfo", + "schema": { + "type": "object", + "properties": { + "company_name": {"type": "string"}, + "industry": {"type": "string"}, + "employee_count": {"type": "integer", "minimum": 1} + }, + "required": ["company_name"] + } + }, + { + "name": "ContactEvent", + "schema": { + "type": "object", + "properties": { + "event_type": {"type": "string", "enum": ["meeting", "call", "email"]}, + "participants": { + "type": "array", + "items": {"$ref": "#/schemas/PersonInfo"} + }, + "companies": { + "type": "array", + "items": {"$ref": "#/schemas/CompanyInfo"} + }, + "date": {"type": "string", "format": "date"}, + "notes": {"type": "string"} + }, + "required": ["event_type", "date"] + } + } + ], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Extract information about business contacts and events.", + "structured_output": "ContactEvent" + } +} +``` + +## Usage Patterns + +### Method-based Access + +```python +# Load agent with structured output +agent = loader.load_agent(config) + +# Use the structured_output method +result = agent.structured_output("Extract user data: Alice Johnson, alice@example.com, 28 years old") + +# Use auto-generated convenience methods +result = agent.extract_userprofile("Extract user data: Bob Smith, bob@example.com") +result = agent.extract_contactinfo("Contact: Carol Davis, carol@company.com, (555) 123-4567") +``` + +### Validation and Error Handling + +```python +config = { + "schemas": [ + { + "name": "StrictSchema", + "schema": { + "type": "object", + "properties": { + "required_field": {"type": "string"}, + "optional_field": {"type": "integer"} + }, + "required": ["required_field"], + "additionalProperties": False + } + } + ], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Extract data with strict validation.", + "structured_output": { + "schema": "StrictSchema", + "validation": { + "strict": True, + "allow_extra_fields": False + }, + "error_handling": { + "retry_on_validation_error": True, + "max_retries": 2 + } + } + } +} + +# The agent will retry up to 2 times if validation fails +try: + result = agent.structured_output("Extract: some incomplete data") +except ValidationError as e: + print(f"Validation failed after retries: {e}") +``` + +## Advanced Examples + +### Multi-Agent Structured Output Pipeline + +```python +# Schema shared across multiple agents +shared_schemas = [ + { + "name": "DocumentMetadata", + "schema": { + "type": "object", + "properties": { + "title": {"type": "string"}, + "author": {"type": "string"}, + "date": {"type": "string", "format": "date"}, + "category": {"type": "string"}, + "keywords": {"type": "array", "items": {"type": "string"}}, + "summary": {"type": "string"} + }, + "required": ["title", "category"] + } + }, + { + "name": "ContentAnalysis", + "schema": { + "type": "object", + "properties": { + "sentiment": {"type": "string", "enum": ["positive", "negative", "neutral"]}, + "topics": {"type": "array", "items": {"type": "string"}}, + "complexity_score": {"type": "number", "minimum": 0, "maximum": 10}, + "readability_grade": {"type": "integer", "minimum": 1, "maximum": 20} + }, + "required": ["sentiment", "topics"] + } + } +] + +# Document metadata extractor +metadata_extractor_config = { + "schemas": shared_schemas, + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Extract metadata from documents.", + "structured_output": "DocumentMetadata" + } +} + +# Content analyzer +content_analyzer_config = { + "schemas": shared_schemas, + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Analyze document content for sentiment and topics.", + "structured_output": "ContentAnalysis" + } +} + +# Load both agents +metadata_agent = loader.load_agent(metadata_extractor_config) +analysis_agent = loader.load_agent(content_analyzer_config) + +# Use in pipeline +document_text = "Sample document content..." +metadata = metadata_agent.structured_output(document_text) +analysis = analysis_agent.structured_output(document_text) + +print(f"Document: {metadata.title}") +print(f"Sentiment: {analysis.sentiment}") +print(f"Topics: {', '.join(analysis.topics)}") +``` + +### Dynamic Schema Generation + +```python +def create_extraction_config(fields): + """Create a structured output config for dynamic field extraction""" + properties = {} + required = [] + + for field_name, field_config in fields.items(): + properties[field_name] = { + "type": field_config.get("type", "string"), + "description": field_config.get("description", f"The {field_name} field") + } + + if field_config.get("required", False): + required.append(field_name) + + # Add additional constraints + if "enum" in field_config: + properties[field_name]["enum"] = field_config["enum"] + if "minimum" in field_config: + properties[field_name]["minimum"] = field_config["minimum"] + if "maximum" in field_config: + properties[field_name]["maximum"] = field_config["maximum"] + + schema_name = "DynamicExtraction" + + return { + "schemas": [ + { + "name": schema_name, + "schema": { + "type": "object", + "properties": properties, + "required": required + } + } + ], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": f"Extract the following fields: {', '.join(fields.keys())}", + "structured_output": schema_name + } + } + +# Define fields dynamically +product_fields = { + "name": {"type": "string", "required": True}, + "price": {"type": "number", "minimum": 0, "required": True}, + "rating": {"type": "number", "minimum": 1, "maximum": 5}, + "category": {"type": "string", "enum": ["electronics", "books", "clothing"], "required": True} +} + +# Create and use dynamic config +product_config = create_extraction_config(product_fields) +product_agent = loader.load_agent(product_config) + +result = product_agent.structured_output("iPhone 15 Pro - $999, rated 4.5 stars, electronics category") +print(f"Product: {result.name}, Price: ${result.price}, Rating: {result.rating}") +``` + +### Conditional Structured Output + +```python +def create_adaptive_agent(output_format="simple"): + """Create agent with different structured output based on format""" + + if output_format == "simple": + schema = { + "name": "SimpleResult", + "schema": { + "type": "object", + "properties": { + "answer": {"type": "string"}, + "confidence": {"type": "number", "minimum": 0, "maximum": 1} + }, + "required": ["answer"] + } + } + elif output_format == "detailed": + schema = { + "name": "DetailedResult", + "schema": { + "type": "object", + "properties": { + "answer": {"type": "string"}, + "reasoning": {"type": "string"}, + "confidence": {"type": "number", "minimum": 0, "maximum": 1}, + "sources": {"type": "array", "items": {"type": "string"}}, + "alternatives": {"type": "array", "items": {"type": "string"}} + }, + "required": ["answer", "reasoning", "confidence"] + } + } + else: # comprehensive + schema = { + "name": "ComprehensiveResult", + "schema": { + "type": "object", + "properties": { + "answer": {"type": "string"}, + "reasoning": {"type": "string"}, + "confidence": {"type": "number", "minimum": 0, "maximum": 1}, + "sources": {"type": "array", "items": {"type": "string"}}, + "alternatives": {"type": "array", "items": {"type": "string"}}, + "methodology": {"type": "string"}, + "limitations": {"type": "array", "items": {"type": "string"}}, + "follow_up_questions": {"type": "array", "items": {"type": "string"}} + }, + "required": ["answer", "reasoning", "confidence", "methodology"] + } + } + + return { + "schemas": [schema], + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": f"Provide {output_format} analysis with structured output.", + "structured_output": schema["name"] + } + } + +# Create different agents based on output needs +simple_agent = loader.load_agent(create_adaptive_agent("simple")) +detailed_agent = loader.load_agent(create_adaptive_agent("detailed")) +comprehensive_agent = loader.load_agent(create_adaptive_agent("comprehensive")) +``` + +## Best Practices + +1. **Use Schema Validation**: Enable IDE integration for better development experience +2. **Design Clear Schemas**: Define specific, well-documented properties with appropriate types +3. **Leverage Schema Reuse**: Create shared schema libraries for consistent data structures +4. **Test Schema Validation**: Validate that schemas work correctly with expected data +5. **Handle Validation Errors**: Configure appropriate retry and error handling strategies +6. **Document Schema Purpose**: Provide clear descriptions for schemas and their use cases + +## Error Handling and Troubleshooting + +### Common Issues + +1. **Schema Not Found**: Ensure schema names match exactly between definition and reference +2. **Validation Failures**: Check that the model output matches the schema requirements +3. **Import Errors**: Verify Python class paths are correct and modules are importable +4. **Schema File Issues**: Ensure external schema files exist and are properly formatted + +### Debugging Tips + +```python +# Enable detailed logging for structured output +import logging +logging.getLogger("strands.experimental.config_loader.agent").setLevel(logging.DEBUG) + +# Test schema validation separately +from jsonschema import validate +import json + +schema_def = { + "type": "object", + "properties": { + "name": {"type": "string"}, + "age": {"type": "integer"} + }, + "required": ["name"] +} + +test_data = {"name": "John", "age": 30} +validate(test_data, schema_def) # Should pass without error +``` + +## Next Steps + +- [Agent Configuration](agent-config.md) - Using structured output in agent configurations +- [Tool Configuration](tool-config.md) - Structured output for agent-as-tool configurations +- [Swarm Configuration](swarm-config.md) - Structured output for swarm agents +- [Graph Configuration](graph-config.md) - Structured output for graph node agents + required: ["name", "price", "category"] +``` + +### 2. External Schema Files + +Reference schemas stored in separate JSON or YAML files: + +```yaml +schemas: + - name: "CustomerData" + description: "Customer data from external file" + schema_file: "./schemas/customer.json" + + - name: "OrderInfo" + description: "Order information from YAML file" + schema_file: "./schemas/order.yaml" +``` + +**Example external schema file (`schemas/customer.json`):** + +```json +{ + "type": "object", + "properties": { + "customer_id": { + "type": "string", + "description": "Unique customer identifier" + }, + "name": { + "type": "string", + "description": "Customer full name" + }, + "contact_info": { + "type": "object", + "properties": { + "email": {"type": "string", "format": "email"}, + "phone": {"type": "string"} + }, + "required": ["email"] + } + }, + "required": ["customer_id", "name", "contact_info"] +} +``` + +### 3. Python Class References + +Reference existing Pydantic models from your codebase: + +```yaml +schemas: + - name: "BusinessMetrics" + description: "Business metrics from existing model" + python_class: "myapp.models.BusinessMetrics" +``` + +**Corresponding Python model:** + +```python +from pydantic import BaseModel, Field +from typing import List, Optional +from datetime import datetime + +class BusinessMetrics(BaseModel): + revenue: float = Field(ge=0, description="Revenue in USD") + growth_rate: float = Field(description="Growth rate percentage") + customer_count: int = Field(ge=0, description="Number of customers") + key_metrics: List[dict] = Field(description="Additional key metrics") + report_date: datetime = Field(description="Report generation date") +``` + +## Agent Configuration Options + +### Simple Reference + +Use a simple string to reference a schema: + +```yaml +agent: + name: "data_extractor" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: "Extract structured data from text." + structured_output: "ProductInfo" # Simple schema reference +``` + +### Direct Python Class Reference + +Reference a Python class directly without registering it in the schema registry: + +```yaml +agent: + name: "metrics_analyzer" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: "Analyze business metrics." + structured_output: "myapp.models.BusinessMetrics" # Direct class reference +``` + +### Advanced Configuration + +Configure validation and error handling options: + +```yaml +agent: + name: "advanced_extractor" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: "Extract data with advanced validation." + structured_output: + schema: "ProductInfo" + validation: + strict: true # Strict validation of output + allow_extra_fields: false # Reject extra fields not in schema + coerce_types: true # Attempt type coercion + error_handling: + retry_on_validation_error: true # Retry if validation fails + max_retries: 3 # Maximum retry attempts + fallback_to_text: false # Don't fall back to text output + timeout_seconds: 30 # Timeout for generation +``` + +## Global Configuration + +### Schema Registry + +Define schemas globally to be shared across multiple agents: + +```yaml +# Global schema registry +schemas: + - name: "ContactInfo" + schema: + type: "object" + properties: + name: {"type": "string"} + email: {"type": "string", "format": "email"} + phone: {"type": "string"} + required: ["name", "email"] + + - name: "CompanyInfo" + schema: + type: "object" + properties: + name: {"type": "string"} + industry: {"type": "string"} + size: {"type": "string", "enum": ["startup", "small", "medium", "large"]} + required: ["name"] + +# Multiple agents using shared schemas +agents: + - name: "contact_extractor" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: "Extract contact information." + structured_output: "ContactInfo" + + - name: "company_analyzer" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: "Analyze company information." + structured_output: "CompanyInfo" +``` + +### Default Configuration + +Set default validation and error handling options: + +```yaml +# Global defaults for all structured output +structured_output_defaults: + validation: + strict: false + allow_extra_fields: true + coerce_types: true + error_handling: + retry_on_validation_error: false + max_retries: 1 + fallback_to_text: true + timeout_seconds: 60 + +# Agents inherit defaults but can override +agents: + - name: "lenient_extractor" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + structured_output: "ContactInfo" + # Uses all defaults + + - name: "strict_extractor" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + structured_output: + schema: "ContactInfo" + validation: + strict: true # Overrides default + # Other settings inherited from defaults +``` + +## Complex Schema Examples + +### Nested Objects + +```yaml +schemas: + - name: "CustomerOrder" + schema: + type: "object" + properties: + order_id: + type: "string" + description: "Unique order identifier" + customer: + type: "object" + properties: + name: {"type": "string"} + email: {"type": "string", "format": "email"} + address: + type: "object" + properties: + street: {"type": "string"} + city: {"type": "string"} + zipcode: {"type": "string", "pattern": "^\\d{5}(-\\d{4})?$"} + required: ["street", "city", "zipcode"] + required: ["name", "email", "address"] + items: + type: "array" + items: + type: "object" + properties: + product_name: {"type": "string"} + quantity: {"type": "integer", "minimum": 1} + unit_price: {"type": "number", "minimum": 0} + required: ["product_name", "quantity", "unit_price"] + minItems: 1 + total_amount: + type: "number" + minimum: 0 + description: "Total order amount" + required: ["order_id", "customer", "items", "total_amount"] +``` + +### Enums and Constraints + +```yaml +schemas: + - name: "TaskManagement" + schema: + type: "object" + properties: + task_id: + type: "string" + pattern: "^TASK-\\d{4}$" + description: "Task ID in format TASK-XXXX" + title: + type: "string" + minLength: 5 + maxLength: 100 + description: "Task title" + priority: + type: "string" + enum: ["low", "medium", "high", "critical"] + description: "Task priority level" + status: + type: "string" + enum: ["todo", "in_progress", "review", "done"] + description: "Current task status" + assignee: + type: "object" + properties: + user_id: {"type": "string"} + name: {"type": "string"} + department: + type: "string" + enum: ["engineering", "design", "product", "marketing"] + required: ["user_id", "name"] + due_date: + type: "string" + format: "date" + description: "Task due date" + estimated_hours: + type: "number" + minimum: 0.5 + maximum: 40 + description: "Estimated hours to complete" + tags: + type: "array" + items: + type: "string" + uniqueItems: true + maxItems: 10 + description: "Task tags" + required: ["task_id", "title", "priority", "status"] +``` + +## Usage Patterns + +### Single Agent File + +```yaml +# single_agent.yaml +schemas: + - name: "EmailAnalysis" + schema: + type: "object" + properties: + sender: {"type": "string"} + subject: {"type": "string"} + sentiment: {"type": "string", "enum": ["positive", "negative", "neutral"]} + urgency: {"type": "string", "enum": ["low", "medium", "high"]} + action_required: {"type": "boolean"} + summary: {"type": "string", "maxLength": 200} + required: ["sender", "subject", "sentiment", "urgency", "action_required"] + +agent: + name: "email_analyzer" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: "Analyze email content and extract key information." + structured_output: "EmailAnalysis" +``` + +### Multi-Agent Configuration + +```yaml +# multi_agent_system.yaml +schemas: + - name: "CustomerFeedback" + schema: + type: "object" + properties: + customer_id: {"type": "string"} + sentiment: {"type": "string", "enum": ["very_positive", "positive", "neutral", "negative", "very_negative"]} + key_issues: {"type": "array", "items": {"type": "string"}} + satisfaction_score: {"type": "integer", "minimum": 1, "maximum": 10} + required: ["customer_id", "sentiment", "satisfaction_score"] + + - name: "ActionPlan" + schema: + type: "object" + properties: + priority: {"type": "string", "enum": ["low", "medium", "high", "critical"]} + actions: + type: "array" + items: + type: "object" + properties: + action: {"type": "string"} + owner: {"type": "string"} + deadline: {"type": "string", "format": "date"} + required: ["action", "owner"] + estimated_impact: {"type": "string", "enum": ["low", "medium", "high"]} + required: ["priority", "actions"] + +agents: + - name: "feedback_analyzer" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: "Analyze customer feedback and extract insights." + structured_output: "CustomerFeedback" + + - name: "action_planner" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: "Create action plans based on feedback analysis." + structured_output: "ActionPlan" +``` + +## Error Handling + +### Validation Errors + +When structured output validation fails, you can configure different behaviors: + +```yaml +agent: + name: "robust_extractor" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + structured_output: + schema: "StrictSchema" + validation: + strict: true + error_handling: + retry_on_validation_error: true + max_retries: 3 + fallback_to_text: true # Fall back to text if all retries fail + timeout_seconds: 45 +``` + +### Error Types + +The system handles several types of errors: + +- **Schema Validation Errors**: Invalid schema definitions +- **Model Creation Errors**: Failures in creating Pydantic models +- **Output Validation Errors**: Generated output doesn't match schema +- **Import Errors**: Cannot import specified Python classes +- **File Errors**: External schema files not found or malformed + +### Logging + +Enable detailed logging to debug structured output issues: + +```python +import logging + +# Enable debug logging for structured output +logging.getLogger('strands.experimental.config_loader.agent').setLevel(logging.DEBUG) + +# Load and use agent +loader = AgentConfigLoader() +agent = loader.load_agent(config) +``` + +## Best Practices + +### Schema Design + +1. **Keep schemas focused**: Each schema should represent a single, well-defined data structure +2. **Use descriptive names**: Schema and field names should be clear and self-documenting +3. **Add descriptions**: Include descriptions for all fields to help the AI understand the expected output +4. **Set appropriate constraints**: Use minimum/maximum values, string lengths, and patterns to ensure data quality +5. **Make required fields explicit**: Clearly specify which fields are required vs optional + +### Configuration Organization + +1. **Separate concerns**: Use external schema files for complex or reusable schemas +2. **Group related schemas**: Organize schemas by domain or use case +3. **Use consistent naming**: Follow consistent naming conventions across schemas +4. **Document your schemas**: Include comments and descriptions in your configuration files + +### Performance Optimization + +1. **Cache agents**: Use cache keys when loading agents to avoid repeated configuration parsing +2. **Reuse schemas**: Define schemas once and reference them across multiple agents +3. **Optimize schema complexity**: Simpler schemas generally perform better +4. **Set appropriate timeouts**: Configure timeouts based on your schema complexity and model performance + +### Error Handling Strategy + +1. **Start permissive**: Begin with lenient validation and tighten as needed +2. **Use fallbacks**: Configure fallback to text output for non-critical applications +3. **Monitor failures**: Log and monitor validation failures to improve schemas +4. **Test thoroughly**: Test your schemas with various input types and edge cases + +## Migration from Programmatic Usage + +### Before (Programmatic) + +```python +from pydantic import BaseModel +from strands import Agent + +class UserProfile(BaseModel): + name: str + email: str + age: int + +agent = Agent(model="us.anthropic.claude-3-7-sonnet-20250219-v1:0") +result = agent.structured_output(UserProfile, "Extract user info") +``` + +### After (Configuration-Driven) + +```yaml +# config.yaml +schemas: + - name: "UserProfile" + python_class: "myapp.models.UserProfile" + +agent: + name: "user_extractor" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + structured_output: "UserProfile" +``` + +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +loader = AgentConfigLoader() +agent = loader.load_agent_from_file("config.yaml") +result = agent.structured_output("Extract user info") +``` + +## Troubleshooting + +### Common Issues + +1. **Schema not found**: Ensure schema names match exactly between definition and reference +2. **Import errors**: Verify Python class paths are correct and modules are importable +3. **Validation failures**: Check that your schema constraints match expected output format +4. **File not found**: Verify external schema file paths are correct and accessible + +### Debug Steps + +1. **Enable debug logging**: Set log level to DEBUG for detailed information +2. **Test schemas independently**: Use the PydanticModelFactory to test schema creation +3. **Validate with sample data**: Test your schemas with known good data +4. **Check agent configuration**: Verify all required configuration fields are present + +### Getting Help + +- Check the logs for detailed error messages +- Validate your JSON Schema syntax using online validators +- Test Pydantic models independently before using in configuration +- Review the comprehensive test suite for usage examples + +## API Reference + +### AgentConfigLoader + +```python +class AgentConfigLoader: + def load_agent(self, config: Dict[str, Any], cache_key: Optional[str] = None) -> Agent + def get_schema_registry(self) -> SchemaRegistry + def list_schemas(self) -> Dict[str, str] +``` + +### SchemaRegistry + +```python +class SchemaRegistry: + def register_schema(self, name: str, schema: Union[Dict[str, Any], Type[BaseModel], str]) -> None + def register_from_config(self, schema_config: Dict[str, Any]) -> None + def get_schema(self, name: str) -> Type[BaseModel] + def resolve_schema_reference(self, reference: str) -> Type[BaseModel] + def list_schemas(self) -> Dict[str, str] +``` + +### PydanticModelFactory + +```python +class PydanticModelFactory: + @staticmethod + def create_model_from_schema(model_name: str, schema: Dict[str, Any]) -> Type[BaseModel] + + @staticmethod + def validate_schema(schema: Dict[str, Any]) -> bool + + @staticmethod + def get_schema_info(schema: Dict[str, Any]) -> Dict[str, Any] +``` + +## Examples Repository + +For complete working examples, see the samples repository: + +- `samples/01-tutorials/01-fundamentals/10-structured-output-config/` +- Business intelligence pipeline example +- Multi-agent structured output workflows +- Error handling and validation examples +- Performance optimization patterns diff --git a/docs/experimental/config-loader/swarm-config.md b/docs/experimental/config-loader/swarm-config.md new file mode 100644 index 00000000..0e1c98ef --- /dev/null +++ b/docs/experimental/config-loader/swarm-config.md @@ -0,0 +1,941 @@ +# SwarmConfigLoader + +The SwarmConfigLoader enables serialization and deserialization of Strands `Swarm` instances to/from dictionary configurations, supporting persistence and dynamic loading scenarios. This implementation leverages the existing `AgentConfigLoader` for agent serialization and adds swarm-specific configuration management. + +**Note**: This is an experimental feature that provides programmatic swarm configuration loading through dictionaries. For file-based configuration, use the main Swarm constructor's `config` parameter. + +## Overview + +The SwarmConfigLoader provides functionality to: +- Load swarms from dictionary configurations +- Serialize existing swarms to dictionary configurations +- Cache swarms for performance optimization +- Integrate seamlessly with AgentConfigLoader for agent management +- Support both programmatic and configuration-based swarm creation + +## Quick Start + +### Using SwarmConfigLoader + +```python +from strands.experimental.config_loader.swarm import SwarmConfigLoader + +# Define swarm configuration +config = { + "swarm": { + "max_handoffs": 20, + "agents": [ + { + "name": "research_agent", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a research agent.", + "tools": [] + }, + { + "name": "creative_agent", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a creative agent.", + "tools": [] + } + ] + } +} + +loader = SwarmConfigLoader() +swarm = loader.load_swarm(config) + +# Execute the swarm +result = swarm("Create a blog post explaining Agentic AI") +``` + +### File-Based Configuration (Use Main Constructors) + +For loading from YAML/JSON files, use the main constructors instead: + +```python +from strands.multiagent import Swarm + +# Load from YAML file path (not SwarmConfigLoader) +swarm = Swarm(config='swarm_config.yml') + +# Load from dictionary configuration (not SwarmConfigLoader) +config = { + "max_handoffs": 20, + "agents": [ + { + "name": "research_agent", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a research agent.", + "tools": [] + } + ] +} +swarm = Swarm(config=config) + +# Override config values with individual parameters +swarm = Swarm( + config='swarm_config.yml', + max_handoffs=15, # Override config value + execution_timeout=1200.0 # Override config value +) +``` + +### Traditional Constructor + +```python +from strands import Agent +from strands.multiagent import Swarm + +agents = [Agent(name="agent1", model="us.amazon.nova-lite-v1:0")] +swarm = Swarm(nodes=agents) +``` + +## Schema Validation + +The ConfigLoader includes comprehensive schema validation for swarms: + +- **IDE Integration**: VSCode, IntelliJ, Vim support with autocompletion +- **Error Prevention**: Catch configuration errors before runtime +- **Type Safety**: Enforced structure and types +- **Documentation**: Schema serves as living documentation + +### Global VSCode Settings +Add to your `settings.json`: +```json +{ + "yaml.schemas": { + "https://strandsagents.com/schemas/config/v1": "*.strands.yml" + } +} +``` + +## Configuration Schema + +### Basic Structure + +```python +config = { + "swarm": { + # Core swarm parameters (matching Swarm constructor) + "max_handoffs": 20, # Maximum handoffs to agents and users + "max_iterations": 20, # Maximum node executions within the swarm + "execution_timeout": 900.0, # Total execution timeout in seconds (15 minutes) + "node_timeout": 300.0, # Individual node timeout in seconds (5 minutes) + "repetitive_handoff_detection_window": 8, # Number of recent nodes to check for repetitive handoffs + "repetitive_handoff_min_unique_agents": 3, # Minimum unique agents required in recent sequence + + # Specialized agents for collaboration + "agents": [ + { + "name": "research_agent", + "description": "Research Agent specializing in gathering and analyzing information", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a Research Agent specializing in gathering and analyzing information.", + "tools": [] + }, + { + "name": "creative_agent", + "description": "Creative Agent specializing in generating innovative solutions", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a Creative Agent specializing in generating innovative solutions.", + "tools": [] + } + ] + } +} +``` + +### Complete Swarm Configuration + +```python +config = { + "swarm": { + # Swarm execution parameters + "max_handoffs": 25, + "max_iterations": 30, + "execution_timeout": 1200.0, # 20 minutes + "node_timeout": 180.0, # 3 minutes per agent + "repetitive_handoff_detection_window": 10, + "repetitive_handoff_min_unique_agents": 4, + + # Specialized agents for blog writing collaboration + "agents": [ + { + "name": "research_agent", + "description": "Research Agent specializing in gathering and analyzing information", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": """You are a Research Agent specializing in gathering and analyzing information. +Your role in the swarm is to provide factual information and research insights on the topic. +You should focus on providing accurate data and identifying key aspects of the problem. +When receiving input from other agents, evaluate if their information aligns with your research. + +When you need help from other specialists or have completed your research, use the available tools to coordinate with other agents.""", + "tools": [ + {"name": "web_search", "module": "research_tools.search"}, + {"name": "fact_checker", "module": "research_tools.verify"} + ], + "handoff_conditions": [ + { + "condition": "research_complete", + "target_agent": "creative_agent" + } + ] + }, + { + "name": "creative_agent", + "description": "Creative Agent specializing in generating innovative solutions", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": """You are a Creative Agent specializing in generating innovative solutions. +Your role in the swarm is to think outside the box and propose creative approaches. +You should build upon information from other agents while adding your unique creative perspective. +Focus on novel approaches that others might not have considered.""", + "tools": [ + {"name": "brainstorm_generator", "module": "creative_tools.brainstorm"}, + {"name": "analogy_finder", "module": "creative_tools.analogies"} + ], + "handoff_conditions": [ + { + "condition": "creative_ideas_generated", + "target_agent": "critical_agent" + } + ] + }, + { + "name": "critical_agent", + "description": "Critical Agent specializing in analyzing proposals and finding flaws", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": """You are a Critical Agent specializing in analyzing proposals and finding flaws. +Your role in the swarm is to evaluate solutions proposed by other agents and identify potential issues. +You should carefully examine proposed solutions, find weaknesses or oversights, and suggest improvements.""", + "tools": [ + {"name": "logic_checker", "module": "analysis_tools.logic"}, + {"name": "risk_assessor", "module": "analysis_tools.risk"} + ], + "handoff_conditions": [ + { + "condition": "analysis_complete", + "target_agent": "synthesis_agent" + } + ] + }, + { + "name": "synthesis_agent", + "description": "Synthesis Agent specializing in combining insights from all agents", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": """You are a Synthesis Agent specializing in combining insights from all agents. +Your role is to take the research, creative ideas, and critical analysis from other agents and synthesize them into a coherent final output. +You should balance all perspectives and create a comprehensive solution.""", + "tools": [ + {"name": "content_synthesizer", "module": "synthesis_tools.combine"}, + {"name": "quality_checker", "module": "synthesis_tools.quality"} + ] + } + ] + } +} +``` + +## Agent Configuration + +### Basic Agent in Swarm + +```python +{ + "name": "specialist_agent", + "description": "A specialized agent within the swarm", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a specialist in your domain.", + "tools": [ + {"name": "domain_tool", "module": "specialist_tools.domain"} + ] +} +``` + +### Agent with Handoff Conditions + +```python +{ + "name": "coordinator_agent", + "description": "Coordinates work and hands off to specialists", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You coordinate work and delegate to appropriate specialists.", + "tools": [ + {"name": "task_analyzer", "module": "coordination_tools.analyze"} + ], + "handoff_conditions": [ + { + "condition": "technical_task_identified", + "target_agent": "technical_specialist" + }, + { + "condition": "creative_task_identified", + "target_agent": "creative_specialist" + } + ] +} +``` + +### Agent with Full Configuration + +```python +{ + "name": "advanced_agent", + "description": "An agent with full configuration options", + "model": { + "type": "bedrock", + "model_id": "us.amazon.nova-pro-v1:0", + "temperature": 0.7, + "max_tokens": 4096 + }, + "system_prompt": "You are an advanced agent with sophisticated capabilities.", + "tools": [ + {"name": "advanced_analyzer", "module": "advanced_tools.analyzer"}, + { + "name": "sub_agent", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a sub-agent helping with specific tasks." + }, + "input_schema": { + "type": "object", + "properties": { + "task": {"type": "string", "description": "Task to perform"} + }, + "required": ["task"] + } + } + ], + "conversation_manager": { + "type": "sliding_window", + "window_size": 25 + }, + "state": { + "expertise_level": "advanced", + "specialization": "multi_domain" + }, + "handoff_conditions": [ + { + "condition": "task_complete", + "target_agent": "reviewer_agent" + } + ] +} +``` + +## Swarm Execution Parameters + +### Timeout and Iteration Control + +```python +config = { + "swarm": { + "max_handoffs": 30, # Maximum handoffs between agents + "max_iterations": 25, # Maximum total iterations + "execution_timeout": 1800.0, # 30 minutes total timeout + "node_timeout": 240.0, # 4 minutes per agent execution + # ... agents configuration + } +} +``` + +### Repetitive Handoff Detection + +```python +config = { + "swarm": { + "repetitive_handoff_detection_window": 8, # Look at last 8 handoffs + "repetitive_handoff_min_unique_agents": 3, # Need at least 3 unique agents + # ... rest of configuration + } +} +``` + +### Using Cache Keys + +```python +loader = SwarmConfigLoader() + +# Load with cache key +swarm1 = loader.load_swarm(config) +swarm2 = loader.load_swarm(config) # Returns cached instance + +``` + +### Serialization + +```python +# Load from config +swarm = loader.load_swarm(config) + +# Serialize back to config +serialized_config = loader.serialize_swarm(swarm) +``` + +## Error Handling + +The SwarmConfigLoader provides comprehensive error handling: + +```python +try: + swarm = loader.load_swarm(invalid_config) +except ValueError as e: + print(f"Configuration error: {e}") +except ImportError as e: + print(f"Missing dependency: {e}") +``` + +Common error scenarios: +- **Missing required fields**: Clear messages about required swarm components +- **Invalid agent configurations**: Specific guidance for agent setup +- **Tool loading errors**: Helpful messages for missing or invalid tools +- **Handoff condition errors**: Validation of handoff target agents + +## Advanced Examples + +### Research and Analysis Swarm + +```python +config = { + "swarm": { + "max_handoffs": 20, + "execution_timeout": 900.0, + "agents": [ + { + "name": "data_collector", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Collect and organize relevant data for analysis.", + "tools": [ + {"name": "web_scraper", "module": "data_tools.scraper"}, + {"name": "database_query", "module": "data_tools.db"} + ], + "handoff_conditions": [ + { + "condition": "data_collection_complete", + "target_agent": "data_analyst" + } + ] + }, + { + "name": "data_analyst", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Analyze collected data and identify patterns and insights.", + "tools": [ + {"name": "statistical_analyzer", "module": "analysis_tools.stats"}, + {"name": "pattern_detector", "module": "analysis_tools.patterns"} + ], + "handoff_conditions": [ + { + "condition": "analysis_complete", + "target_agent": "report_writer" + } + ] + }, + { + "name": "report_writer", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Create comprehensive reports based on data analysis.", + "tools": [ + {"name": "report_generator", "module": "reporting_tools.generator"}, + {"name": "chart_creator", "module": "reporting_tools.charts"} + ] + } + ] + } +} +``` + +### Customer Service Swarm + +```python +config = { + "swarm": { + "max_handoffs": 15, + "node_timeout": 120.0, + "agents": [ + { + "name": "intake_specialist", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Handle initial customer inquiries and route to appropriate specialists.", + "tools": [ + {"name": "customer_lookup", "module": "customer_tools.lookup"}, + {"name": "issue_classifier", "module": "customer_tools.classify"} + ], + "handoff_conditions": [ + { + "condition": "technical_issue_identified", + "target_agent": "technical_support" + }, + { + "condition": "billing_issue_identified", + "target_agent": "billing_specialist" + }, + { + "condition": "general_inquiry", + "target_agent": "general_support" + } + ] + }, + { + "name": "technical_support", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Provide technical support and troubleshooting assistance.", + "tools": [ + {"name": "diagnostic_tool", "module": "tech_tools.diagnostics"}, + {"name": "solution_database", "module": "tech_tools.solutions"} + ], + "handoff_conditions": [ + { + "condition": "escalation_needed", + "target_agent": "senior_technical" + } + ] + }, + { + "name": "billing_specialist", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Handle billing inquiries and account management.", + "tools": [ + {"name": "billing_system", "module": "billing_tools.system"}, + {"name": "payment_processor", "module": "billing_tools.payments"} + ] + }, + { + "name": "general_support", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Provide general customer support and information.", + "tools": [ + {"name": "knowledge_base", "module": "support_tools.kb"}, + {"name": "faq_search", "module": "support_tools.faq"} + ] + }, + { + "name": "senior_technical", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Handle complex technical issues requiring senior expertise.", + "tools": [ + {"name": "advanced_diagnostics", "module": "senior_tools.diagnostics"}, + {"name": "escalation_manager", "module": "senior_tools.escalation"} + ] + } + ] + } +} +``` + +### Content Creation Swarm + +```python +config = { + "swarm": { + "max_handoffs": 25, + "execution_timeout": 1200.0, + "repetitive_handoff_detection_window": 6, + "agents": [ + { + "name": "content_strategist", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Develop content strategy and outline key messaging.", + "tools": [ + {"name": "audience_analyzer", "module": "strategy_tools.audience"}, + {"name": "competitor_research", "module": "strategy_tools.competitors"} + ], + "handoff_conditions": [ + { + "condition": "strategy_complete", + "target_agent": "content_writer" + } + ] + }, + { + "name": "content_writer", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Create engaging content based on strategic direction.", + "tools": [ + {"name": "writing_assistant", "module": "writing_tools.assistant"}, + {"name": "style_checker", "module": "writing_tools.style"} + ], + "handoff_conditions": [ + { + "condition": "draft_complete", + "target_agent": "content_editor" + } + ] + }, + { + "name": "content_editor", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Edit and refine content for clarity and impact.", + "tools": [ + {"name": "grammar_checker", "module": "editing_tools.grammar"}, + {"name": "readability_analyzer", "module": "editing_tools.readability"} + ], + "handoff_conditions": [ + { + "condition": "needs_revision", + "target_agent": "content_writer" + }, + { + "condition": "ready_for_seo", + "target_agent": "seo_specialist" + } + ] + }, + { + "name": "seo_specialist", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Optimize content for search engines and discoverability.", + "tools": [ + {"name": "keyword_optimizer", "module": "seo_tools.keywords"}, + {"name": "meta_generator", "module": "seo_tools.meta"} + ] + } + ] + } +} +``` + +## Best Practices + +1. **Use Schema Validation**: Enable IDE integration for better development experience +2. **Design Clear Agent Roles**: Define specific, non-overlapping responsibilities for each agent +3. **Structure Handoff Conditions**: Create clear, testable conditions for agent transitions +4. **Manage Swarm Size**: Keep swarms focused with 3-7 agents for optimal coordination +5. **Test Handoff Flows**: Validate that handoff conditions work as expected +6. **Monitor Performance**: Use appropriate timeouts and iteration limits + +## Next Steps + +- [Agent Configuration](agent-config.md) - Detailed agent configuration for swarm members +- [Tool Configuration](tool-config.md) - Tool configuration for swarm agents +- [Graph Configuration](graph-config.md) - Using swarms within graph workflows +- [Structured Output](structured-output.md) - Structured output for swarm agents + repetitive_handoff_min_unique_agents: 3 # Minimum unique agents required in recent sequence + + # Agents configuration (list of specialized agent configurations) + agents: + - name: "research_agent" + description: "Research Agent specializing in gathering and analyzing information" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: | + You are a Research Agent specializing in gathering and analyzing information. + Your role in the swarm is to provide factual information and research insights on the topic. + You should focus on providing accurate data and identifying key aspects of the problem. + When receiving input from other agents, evaluate if their information aligns with your research. + tools: [] + + - name: "creative_agent" + description: "Creative Agent specializing in generating innovative solutions" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: | + You are a Creative Agent specializing in generating innovative solutions. + Your role in the swarm is to think outside the box and propose creative approaches. + You should build upon information from other agents while adding your unique creative perspective. + Focus on novel approaches that others might not have considered. + tools: [] +``` + +### Agent Configuration + +Each agent in the `agents` list follows the same configuration format as the `AgentConfigLoader`: + +```yaml +- name: "agent_name" # Required: Unique agent name + description: "Agent description" # Optional: Agent description + model: "model_id" # Required: Model identifier + system_prompt: "System prompt" # Optional: Agent system prompt + tools: [] # Optional: List of tools + messages: [] # Optional: Initial messages + agent_id: "custom_id" # Optional: Custom agent ID + # ... other AgentConfigLoader supported fields +``` + +### Advanced Options + +```yaml +swarm: + # Performance tuning + max_handoffs: 30 + max_iterations: 25 + execution_timeout: 1200.0 # 20 minutes + node_timeout: 400.0 # 6.67 minutes per agent + + # Repetitive handoff detection (prevents ping-pong behavior) + repetitive_handoff_detection_window: 10 + repetitive_handoff_min_unique_agents: 4 + + # Complex agents with tools + agents: + - name: "research_agent" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: "Research specialist with web search capabilities" + tools: + - name: "web_search" + - name: "file_reader" + conversation_manager: + type: "sliding_window" + window_size: 30 +``` + +## API Reference + +### SwarmConfigLoader Class + +```python +class SwarmConfigLoader: + def __init__(self, agent_config_loader: Optional[AgentConfigLoader] = None) + def load_swarm(self, config: Dict[str, Any], cache_key: Optional[str] = None) -> Swarm + def serialize_swarm(self, swarm: Swarm) -> Dict[str, Any] + def clear_cache(self) -> None + def get_available_swarms(self) -> List[str] +``` + +#### Methods + +**`load_swarm(config)`** +- Load a Swarm from YAML configuration (loaded as dictionary) +- `config`: Dictionary containing swarm configuration +- `cache_key`: Optional key for caching the loaded swarm +- Returns: Swarm instance configured according to the provided dictionary +- Raises: `ValueError` if configuration is invalid, `ImportError` if models/tools cannot be imported + +**`serialize_swarm(swarm)`** +- Serialize a Swarm instance to YAML-compatible dictionary configuration +- `swarm`: Swarm instance to serialize +- Returns: Dictionary containing the swarm's configuration that can be saved as YAML +- Note: Only includes non-default values to keep configuration clean + +**`clear_cache()`** +- Clear the internal swarm cache +- Useful for memory management in long-running applications + +**`get_available_swarms()`** +- Get list of cached swarm keys +- Returns: List of cached swarm keys + +### Swarm Constructor Enhancement + +The `Swarm` constructor now accepts an optional `config` parameter: + +```python +def __init__( + self, + nodes: Optional[list[Agent]] = None, + *, + max_handoffs: int = 20, + max_iterations: int = 20, + execution_timeout: float = 900.0, + node_timeout: float = 300.0, + repetitive_handoff_detection_window: int = 0, + repetitive_handoff_min_unique_agents: int = 0, + config: Optional[Union[str, Path, Dict[str, Any]]] = None, +) -> None +``` + +The `config` parameter can be: +- **String**: Path to a YAML (.yaml, .yml) or JSON (.json) configuration file +- **Path**: Path object to a YAML (.yaml, .yml) or JSON (.json) configuration file +- **Dict**: Configuration dictionary with swarm parameters + +## Examples + +### Loading from YAML File + +```python +from strands.multiagent import Swarm + +# Create swarm_config.yml +config_content = """ +swarm: + max_handoffs: 20 + max_iterations: 20 + execution_timeout: 900.0 + node_timeout: 300.0 + repetitive_handoff_detection_window: 8 + repetitive_handoff_min_unique_agents: 3 + + agents: + - name: "research_agent" + description: "Research specialist" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: | + You are a Research Agent specializing in gathering and analyzing information. + Your role in the swarm is to provide factual information and research insights. + tools: [] + + - name: "creative_agent" + description: "Creative specialist" + model: "us.anthropic.claude-3-7-sonnet-20250219-v1:0" + system_prompt: | + You are a Creative Agent specializing in generating innovative solutions. + Your role in the swarm is to think outside the box and propose creative approaches. + tools: [] +""" + +# Load and execute +swarm = Swarm(config='swarm_config.yml') +result = swarm("Create a blog post explaining Agentic AI then create a summary for a social media post.") + +# Access results +print(f"Status: {result.status}") +for node in result.node_history: + print(f"Agent: {node.node_id}") +print(f"Total iterations: {result.execution_count}") +print(f"Execution time: {result.execution_time}ms") +``` + +### Serializing Existing Swarms + +```python +from strands import Agent +from strands.multiagent import Swarm +from strands.experimental.config_loader.swarm import SwarmConfigLoader +import yaml + +# Create swarm programmatically +research_agent = Agent( + system_prompt="You are a research agent.", + name="research_agent", + model="us.anthropic.claude-3-7-sonnet-20250219-v1:0" +) + +creative_agent = Agent( + system_prompt="You are a creative agent.", + name="creative_agent", + model="us.anthropic.claude-3-7-sonnet-20250219-v1:0" +) + +swarm = Swarm( + [research_agent, creative_agent], + max_handoffs=20, + max_iterations=20, + execution_timeout=900.0, + node_timeout=300.0, + repetitive_handoff_detection_window=8, + repetitive_handoff_min_unique_agents=3 +) + +# Serialize swarm configuration +loader = SwarmConfigLoader() +swarm_config = loader.serialize_swarm(swarm) + +# Save to YAML file +with open('saved_swarm.yml', 'w') as f: + yaml.dump({'swarm': swarm_config}, f) + +# Load saved swarm +with open('saved_swarm.yml', 'r') as f: + config = yaml.safe_load(f) +restored_swarm = Swarm(config=config['swarm']) +``` + +### Integration with Persistence + +```python +import yaml +from strands.experimental.config_loader.swarm import SwarmConfigLoader + +class SwarmManager: + def __init__(self): + self.loader = SwarmConfigLoader() + + def save_swarm(self, swarm, filename): + """Save swarm to YAML file.""" + config = self.loader.serialize_swarm(swarm) + with open(filename, 'w') as f: + yaml.dump({'swarm': config}, f) + + def load_swarm(self, filename): + """Load swarm from YAML file.""" + with open(filename, 'r') as f: + config = yaml.safe_load(f) + return self.loader.load_swarm(config['swarm']) + + def clone_swarm(self, swarm): + """Create a copy of a swarm via serialization.""" + config = self.loader.serialize_swarm(swarm) + return self.loader.load_swarm(config) + +# Usage +manager = SwarmManager() +swarm = manager.load_swarm('my_swarm.yml') +result = swarm("Process this task") +manager.save_swarm(swarm, 'updated_swarm.yml') +``` + +## Best Practices + +1. **Use Descriptive Agent Names**: Agent names should reflect their specialty and role in the swarm +2. **Set Appropriate Timeouts**: Adjust timeouts based on task complexity and expected runtime +3. **Enable Repetitive Handoff Detection**: Set appropriate values for `repetitive_handoff_detection_window` and `repetitive_handoff_min_unique_agents` to prevent ping-pong behavior +4. **Include Agent Descriptions**: Add descriptions to help other agents understand capabilities +5. **Use Multi-line System Prompts**: Use YAML `|` syntax for readable, detailed system prompts +6. **Cache Frequently Used Swarms**: Use cache keys for swarms that are loaded multiple times +7. **Validate Configurations**: Test configurations with simple tasks before production use +8. **Version Control Configurations**: Store YAML configurations in version control for reproducibility +9. **Use Parameter Overrides**: Override config values with constructor parameters for dynamic adjustments +10. **Monitor Performance**: Use execution metrics to optimize timeout values and agent configurations + +## Troubleshooting + +### Common Issues + +**Configuration Validation Errors** +```python +# Error: Swarm configuration must include 'agents' field +# Solution: Ensure your config has an 'agents' list +config = { + "agents": [ # Required field + {"name": "agent1", "model": "model_id"} + ] +} +``` + +**Agent Loading Failures** +```python +# Error: Agent configuration must include 'model' field +# Solution: Ensure each agent has required fields +agents = [ + { + "name": "agent1", # Required + "model": "model_id", # Required + "system_prompt": "...", # Optional but recommended + "tools": [] # Optional + } +] +``` + +**File Loading Issues** +```python +# Error: Configuration file not found +# Solution: Check file path and ensure file exists +swarm = Swarm(config='path/to/swarm_config.yml') + +# Error: Unsupported config file format +# Solution: Use .yml, .yaml, or .json files +swarm = Swarm(config='config.yml') # ✓ Supported +swarm = Swarm(config='config.txt') # ✗ Not supported +``` + +**Parameter Override Issues** +```python +# Individual parameters override config values +swarm = Swarm( + config={'max_handoffs': 10}, + max_handoffs=20 # This overrides the config value +) +assert swarm.max_handoffs == 20 # Uses override value +``` + +### Performance Tips + +2. **Optimize Timeouts**: Set appropriate timeout values based on your use case +3. **Clear Cache**: Periodically clear cache in long-running applications +4. **Minimize Config Size**: Only include non-default values in configurations +5. **Batch Operations**: Load multiple swarms with the same SwarmConfigLoader instance + +### Integration Notes + +- **AgentConfigLoader Integration**: SwarmConfigLoader automatically uses AgentConfigLoader for agent management +- **Circular Import Avoidance**: Uses lazy loading to prevent circular import issues +- **Error Handling**: Provides clear error messages for debugging configuration issues +- **Backward Compatibility**: Existing Swarm usage patterns continue to work unchanged diff --git a/docs/experimental/config-loader/tool-config.md b/docs/experimental/config-loader/tool-config.md new file mode 100644 index 00000000..53a86370 --- /dev/null +++ b/docs/experimental/config-loader/tool-config.md @@ -0,0 +1,1531 @@ +# Tool Configuration Loading + +The Tool Configuration Loader provides flexible mechanisms for loading and managing tools in Strands Agents. It supports traditional `@tool` decorated functions, module-based tools, custom tool classes, and a powerful **Agent-as-Tool** feature that allows entire agents to be used as tools within other agents. + +**Note**: This is an experimental feature that provides programmatic tool configuration loading through dictionaries. For file-based configuration, use the main constructors' `config` parameter. + +## Overview + +The `ToolConfigLoader` enables: + +1. **String-based tool loading**: Load tools by identifier from modules or registries +2. **Module-based tool loading**: Support for tools that follow the TOOL_SPEC pattern +3. **Agent-as-Tool**: Configure complete agents as reusable tools with parameter substitution +4. **Swarm-as-Tool**: Configure swarms as tools for complex multi-agent operations +5. **Graph-as-Tool**: Configure graphs as tools for workflow-based operations +6. **Dynamic tool resolution**: Automatic discovery and loading from various sources +7. **Caching**: Efficient tool reuse across multiple agent instances + +## Schema Validation + +The ConfigLoader includes comprehensive schema validation for tools: + +- **IDE Integration**: VSCode, IntelliJ, Vim support with autocompletion +- **Error Prevention**: Catch configuration errors before runtime +- **Type Safety**: Enforced structure and types +- **Documentation**: Schema serves as living documentation + +### Global VSCode Settings +Add to your `settings.json`: +```json +{ + "yaml.schemas": { + "https://strandsagents.com/schemas/config/v1": "*.strands.yml" + } +} +``` + +## Agent-as-Tool Configuration + +The most powerful feature is the ability to define specialized agents as tools that can be used by other agents. This enables hierarchical agent architectures and specialized sub-agents. + +### Basic Agent-as-Tool Example + +```python +from strands.experimental.config_loader.tools import ToolConfigLoader + +# Define an agent-as-tool configuration +research_tool_config = { + "name": "research_assistant", + "description": "Specialized research agent that can investigate topics", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Research the topic '{topic}' and provide {detail_level} information.", + "tools": [] # This agent doesn't need additional tools + }, + "input_schema": { + "type": "object", + "properties": { + "topic": { + "type": "string", + "description": "The research topic" + }, + "detail_level": { + "type": "string", + "description": "Level of detail (brief, detailed, comprehensive)", + "default": "detailed" + } + }, + "required": ["topic"] + } +} + +# Load the agent-as-tool +loader = ToolConfigLoader() +research_tool = loader.load_tool(research_tool_config) + +# Use with an agent +from strands.experimental.config_loader.agent import AgentConfigLoader +agent_config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a coordinator that uses specialized tools.", + "tools": [research_tool_config] # Pass the config directly + } +} + +agent_loader = AgentConfigLoader() +agent = agent_loader.load_agent(agent_config) + +# The agent can now use the research tool +response = agent("Please research quantum computing and provide comprehensive information") +``` + +### Template Variable Substitution with Prompt Field + +Agent-as-Tool configurations support template variable substitution using `{variable_name}` syntax. You can use either the `system_prompt` field in the agent configuration or a separate `prompt` field: + +```python +code_reviewer_config = { + "name": "code_reviewer", + "description": "Reviews code and provides detailed feedback", + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a code review expert.", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "language": { + "type": "string", + "description": "Programming language (Python, JavaScript, etc.)" + }, + "code": { + "type": "string", + "description": "The code to review" + }, + "focus_area": { + "type": "string", + "description": "Primary focus area for review", + "default": "general quality" + } + }, + "required": ["language", "code"] + }, + # Use prompt field for template substitution + "prompt": "Review this {language} code focusing on {focus_area}: {code}" +} + +# Use in agent configuration +agent_config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a development team lead with access to specialized reviewers.", + "tools": [code_reviewer_config] + } +} +``` + +### Advanced Agent-as-Tool with Multiple Capabilities + +```python +documentation_agent_config = { + "name": "documentation_writer", + "description": "Specialized agent for writing technical documentation", + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a technical documentation specialist.", + "tools": [ + {"name": "code_analyzer", "module": "dev_tools.analyzer"}, + {"name": "style_checker", "module": "writing_tools.style"} + ], + "conversation_manager": { + "type": "sliding_window", + "window_size": 30 + } + }, + "input_schema": { + "type": "object", + "properties": { + "code_snippet": { + "type": "string", + "description": "Code to document" + }, + "documentation_type": { + "type": "string", + "enum": ["api", "tutorial", "reference", "guide"], + "description": "Type of documentation to create" + }, + "audience": { + "type": "string", + "enum": ["beginner", "intermediate", "advanced"], + "default": "intermediate" + } + }, + "required": ["code_snippet", "documentation_type"] + }, + "prompt": "Create {documentation_type} documentation for {audience} level audience: {code_snippet}" +} +``` + +## Swarm-as-Tool Configuration + +Configure entire swarms as tools for complex multi-agent operations: + +```python +research_swarm_tool_config = { + "name": "research_team", + "description": "Multi-agent research team for comprehensive analysis", + "swarm": { + "max_handoffs": 15, + "agents": [ + { + "name": "data_collector", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Collect relevant data and sources on the research topic." + }, + { + "name": "analyst", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Analyze collected data and identify key insights." + }, + { + "name": "synthesizer", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Synthesize analysis into comprehensive research report." + } + ] + }, + "input_schema": { + "type": "object", + "properties": { + "research_topic": { + "type": "string", + "description": "Topic to research" + }, + "depth": { + "type": "string", + "enum": ["surface", "detailed", "comprehensive"], + "default": "detailed" + } + }, + "required": ["research_topic"] + }, + "entry_agent": "data_collector" # Specify which agent receives the initial input +} + +# Use in agent configuration +coordinator_config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You coordinate research projects using specialized teams.", + "tools": [research_swarm_tool_config] + } +} +``` + +## Graph-as-Tool Configuration + +Configure graph workflows as tools for complex processing pipelines: + +```python +content_pipeline_tool_config = { + "name": "content_pipeline", + "description": "Multi-stage content creation and review pipeline", + "graph": { + "nodes": [ + { + "node_id": "writer", + "type": "agent", + "config": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Create engaging content based on the brief." + } + }, + { + "node_id": "editor", + "type": "agent", + "config": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Edit content for clarity and engagement." + } + }, + { + "node_id": "reviewer", + "type": "agent", + "config": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Final review for quality and accuracy." + } + } + ], + "edges": [ + { + "from_node": "writer", + "to_node": "editor", + "condition": { + "type": "expression", + "expression": "state.results.get('writer', {}).get('status') == 'complete'" + } + }, + { + "from_node": "editor", + "to_node": "reviewer", + "condition": { + "type": "expression", + "expression": "state.results.get('editor', {}).get('status') == 'complete'" + } + } + ], + "entry_points": ["writer"] + }, + "input_schema": { + "type": "object", + "properties": { + "content_brief": { + "type": "string", + "description": "Brief describing the content to create" + }, + "target_audience": { + "type": "string", + "description": "Target audience for the content" + }, + "content_type": { + "type": "string", + "enum": ["blog_post", "article", "social_media", "email"], + "description": "Type of content to create" + } + }, + "required": ["content_brief", "target_audience", "content_type"] + }, + "entry_point": "writer" # Specify which node receives the initial input +} + +# Use in agent configuration +content_manager_config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You manage content creation using specialized pipelines.", + "tools": [content_pipeline_tool_config] + } +} +``` + +## Simple Tool Configuration + +### String-based Tool Loading + +```python +# Simple tool references +tools_config = { + "tools": [ + "calculator", + "web_search", + "file_reader" + ] +} +``` + +### Module-based Tool Loading + +```python +# Tools with module paths +tools_config = { + "tools": [ + {"name": "custom_calculator", "module": "math_tools.calculator"}, + {"name": "advanced_search", "module": "search_tools.advanced"}, + {"name": "data_processor", "module": "data_tools.processor"} + ] +} +``` + +### Mixed Tool Configuration + +```python +tools_config = { + "tools": [ + # Simple string reference + "calculator", + + # Module-based tool + {"name": "web_search", "module": "search_tools.web"}, + + # Agent-as-tool + { + "name": "research_assistant", + "description": "Specialized research agent", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Research the topic: {topic}" + }, + "input_schema": { + "type": "object", + "properties": { + "topic": {"type": "string", "description": "Research topic"} + }, + "required": ["topic"] + } + }, + + # Swarm-as-tool + { + "name": "analysis_team", + "description": "Multi-agent analysis team", + "swarm": { + "max_handoffs": 10, + "agents": [ + { + "name": "data_analyst", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Analyze data patterns and trends." + }, + { + "name": "report_writer", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Create analysis reports." + } + ] + }, + "input_schema": { + "type": "object", + "properties": { + "data": {"type": "string", "description": "Data to analyze"} + }, + "required": ["data"] + } + } + ] +} +``` + +## Tool Loading and Caching + +### Using ToolConfigLoader Directly + +```python +from strands.experimental.config_loader.tools import ToolConfigLoader + +loader = ToolConfigLoader() + +# Load individual tools +calculator_tool = loader.load_tool("calculator") +search_tool = loader.load_tool({"name": "web_search", "module": "search_tools.web"}) + +# Load agent-as-tool +research_tool = loader.load_tool({ + "name": "research_assistant", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Research: {topic}" + }, + "input_schema": { + "type": "object", + "properties": { + "topic": {"type": "string"} + }, + "required": ["topic"] + } +}) + +# Load multiple tools +tools_list = loader.load_tools([ + "calculator", + {"name": "custom_tool", "module": "my_tools.custom"}, + research_tool +]) +``` + +### Caching + +```python +# Tools are automatically cached by configuration +tool1 = loader.load_tool(config) +tool2 = loader.load_tool(config) # Returns cached instance + +``` + +## Error Handling + +The ToolConfigLoader provides comprehensive error handling: + +```python +try: + tool = loader.load_tool(invalid_config) +except ValueError as e: + print(f"Configuration error: {e}") +except ImportError as e: + print(f"Missing tool module: {e}") +except Exception as e: + print(f"Tool loading error: {e}") +``` + +Common error scenarios: +- **Missing tool modules**: Clear messages about missing dependencies +- **Invalid agent configurations**: Specific guidance for nested agent setup +- **Schema validation errors**: Validation of input schemas +- **Tool registration errors**: Issues with tool discovery and loading + +## Advanced Examples + +### Multi-Level Agent Hierarchy + +```python +# Level 3: Specialized sub-agents +code_analyzer_config = { + "name": "code_analyzer", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Analyze code for: {analysis_type}" + }, + "input_schema": { + "type": "object", + "properties": { + "code": {"type": "string"}, + "analysis_type": {"type": "string", "enum": ["security", "performance", "style"]} + }, + "required": ["code", "analysis_type"] + } +} + +# Level 2: Code reviewer using specialized analyzers +code_reviewer_config = { + "name": "code_reviewer", + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Review code comprehensively using available analysis tools.", + "tools": [code_analyzer_config] + }, + "input_schema": { + "type": "object", + "properties": { + "code": {"type": "string"}, + "review_focus": {"type": "string", "default": "comprehensive"} + }, + "required": ["code"] + } +} + +# Level 1: Senior developer using code reviewer +senior_dev_config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a senior developer who coordinates code reviews.", + "tools": [code_reviewer_config] + } +} +``` + +### Dynamic Tool Configuration + +```python +def create_specialist_tool(domain, model_tier="lite"): + """Factory function for creating domain specialist tools""" + model_map = { + "lite": "us.amazon.nova-lite-v1:0", + "pro": "us.amazon.nova-pro-v1:0" + } + + return { + "name": f"{domain}_specialist", + "description": f"Specialist agent for {domain} domain", + "agent": { + "model": model_map[model_tier], + "system_prompt": f"You are a {domain} specialist. Help with: {{task}}", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "task": { + "type": "string", + "description": f"Task requiring {domain} expertise" + } + }, + "required": ["task"] + } + } + +# Create specialized tools +marketing_tool = create_specialist_tool("marketing", "pro") +finance_tool = create_specialist_tool("finance", "pro") +hr_tool = create_specialist_tool("human_resources", "lite") + +# Use in agent configuration +business_advisor_config = { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a business advisor with access to domain specialists.", + "tools": [marketing_tool, finance_tool, hr_tool] + } +} +``` + +### Conditional Tool Loading + +```python +def create_adaptive_agent_config(user_tier="basic"): + """Create agent config with tools based on user tier""" + + base_tools = [ + "calculator", + {"name": "web_search", "module": "search_tools.basic"} + ] + + if user_tier in ["premium", "enterprise"]: + base_tools.append({ + "name": "advanced_analyst", + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Provide advanced analysis for: {query}" + }, + "input_schema": { + "type": "object", + "properties": { + "query": {"type": "string"} + }, + "required": ["query"] + } + }) + + if user_tier == "enterprise": + base_tools.append({ + "name": "enterprise_research_team", + "swarm": { + "max_handoffs": 20, + "agents": [ + { + "name": "senior_researcher", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Lead comprehensive research projects." + }, + { + "name": "data_scientist", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Perform advanced data analysis." + }, + { + "name": "report_specialist", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Create executive-level reports." + } + ] + }, + "input_schema": { + "type": "object", + "properties": { + "research_brief": {"type": "string"} + }, + "required": ["research_brief"] + } + }) + + return { + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": f"You are a {user_tier} tier assistant with specialized capabilities.", + "tools": base_tools + } + } + +# Create different configurations based on user tier +basic_config = create_adaptive_agent_config("basic") +premium_config = create_adaptive_agent_config("premium") +enterprise_config = create_adaptive_agent_config("enterprise") +``` + +## Best Practices + +1. **Use Schema Validation**: Enable IDE integration for better development experience +2. **Design Clear Tool Interfaces**: Define specific, well-documented input schemas +3. **Leverage Tool Hierarchy**: Use agents-as-tools for complex, specialized operations +4. **Cache Expensive Tools**: Use cache keys for frequently loaded tool configurations +5. **Test Tool Interactions**: Validate that tools work correctly within agent contexts +6. **Document Tool Capabilities**: Provide clear descriptions and usage examples + +## Next Steps + +- [Agent Configuration](agent-config.md) - Using tools within agent configurations +- [Swarm Configuration](swarm-config.md) - Tools for swarm agents +- [Graph Configuration](graph-config.md) - Tools for graph node agents +- [Structured Output](structured-output.md) - Structured output for tool agents + } + }, + "required": ["language", "code"] + }, + "prompt": """Review the following {language} code for: +- Code quality and best practices +- Potential bugs or issues +- Performance considerations +- Security concerns + +Focus on {focus_area} aspects. + +Code to review: +{code}""" +} +``` + +**Note**: The `prompt` field is specific to Agent-as-Tool configurations and provides a template that gets sent to the agent with parameter substitution. This is different from the agent's `system_prompt` which sets the agent's overall behavior. + +### Complex Multi-Agent Tool Example + +```python +data_analysis_pipeline = { + "name": "data_analyzer", + "description": "Complete data analysis pipeline", + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a data analysis coordinator.", + "tools": [ + { + "name": "statistical_analyzer", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a statistical analysis expert.", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "data": { + "type": "string", + "description": "Data to analyze" + } + }, + "required": ["data"] + }, + "prompt": "Perform statistical analysis on: {data}" + }, + { + "name": "visualization_generator", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a data visualization expert.", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "data": { + "type": "string", + "description": "Data to visualize" + }, + "chart_type": { + "type": "string", + "description": "Type of chart to generate", + "default": "bar chart" + } + }, + "required": ["data"] + }, + "prompt": "Generate {chart_type} visualization for: {data}" + } + ] + }, + "input_schema": { + "type": "object", + "properties": { + "dataset_description": { + "type": "string", + "description": "Description of the dataset to analyze" + }, + "analysis_type": { + "type": "string", + "description": "Type of analysis (descriptive, predictive, diagnostic)", + "default": "descriptive" + }, + "output_format": { + "type": "string", + "description": "Desired output format (summary, detailed, presentation)", + "default": "summary" + } + }, + "required": ["dataset_description"] + }, + "prompt": """Analyze the dataset: {dataset_description} + +Analysis type: {analysis_type} +Output format: {output_format} + +Provide insights, patterns, and recommendations based on the data.""" +} +``` + +## Swarm-as-Tool Configuration + +Configure entire swarms as tools for complex multi-agent operations: + +```python +# Swarm-as-tool configuration +research_swarm_tool = { + "name": "research_team", + "description": "Multi-agent research team for comprehensive analysis", + "input_schema": { + "type": "object", + "properties": { + "research_topic": { + "type": "string", + "description": "Topic to research" + }, + "depth": { + "type": "string", + "description": "Research depth (surface, detailed, comprehensive)", + "default": "detailed" + }, + "focus_areas": { + "type": "array", + "items": {"type": "string"}, + "description": "Specific areas to focus on", + "default": [] + } + }, + "required": ["research_topic"] + }, + "prompt": "Research '{research_topic}' with {depth} analysis, focusing on: {focus_areas}", + "entry_agent": "coordinator", # Optional: specify which agent receives the initial prompt + "swarm": { + "max_handoffs": 15, + "agents": [ + { + "name": "coordinator", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You coordinate research tasks between specialists.", + "tools": [] + }, + { + "name": "data_researcher", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You specialize in finding and analyzing data sources.", + "tools": [{"name": "web_search"}] + }, + { + "name": "academic_researcher", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You specialize in academic and scientific research.", + "tools": [{"name": "academic_search"}] + } + ] + } +} + +# Load and use the swarm tool +loader = ToolConfigLoader() +research_swarm = loader.load_tool(research_swarm_tool) +``` + +## Graph-as-Tool Configuration + +Configure workflow graphs as tools for complex multi-step processes: + +```python +# Graph-as-tool configuration +analysis_workflow_tool = { + "name": "data_analysis_workflow", + "description": "Complete data analysis workflow with validation and reporting", + "input_schema": { + "type": "object", + "properties": { + "dataset_description": { + "type": "string", + "description": "Description of the dataset" + }, + "analysis_goals": { + "type": "array", + "items": {"type": "string"}, + "description": "Analysis objectives" + }, + "output_format": { + "type": "string", + "description": "Report format (summary, detailed, presentation)", + "default": "summary" + } + }, + "required": ["dataset_description"] + }, + "prompt": "Analyze dataset: {dataset_description}. Goals: {analysis_goals}. Format: {output_format}", + "entry_point": "data_validator", # Optional: specify entry node + "graph": { + "nodes": [ + { + "node_id": "data_validator", + "type": "agent", + "config": { + "name": "data_validator", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Validate data quality and structure.", + "tools": [{"name": "data_profiler"}] + } + }, + { + "node_id": "statistical_analyzer", + "type": "agent", + "config": { + "name": "statistical_analyzer", + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "Perform statistical analysis on validated data.", + "tools": [{"name": "statistics_calculator"}] + } + }, + { + "node_id": "report_generator", + "type": "agent", + "config": { + "name": "report_generator", + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "Generate analysis reports.", + "tools": [{"name": "report_formatter"}] + } + } + ], + "edges": [ + { + "from_node": "data_validator", + "to_node": "statistical_analyzer", + "condition": { + "type": "expression", + "expression": "state.results.get('data_validator', {}).get('status') == 'valid'" + } + }, + { + "from_node": "statistical_analyzer", + "to_node": "report_generator", + "condition": { + "type": "expression", + "expression": "state.results.get('statistical_analyzer', {}).get('status') == 'completed'" + } + } + ], + "entry_points": ["data_validator"] + } +} + +# Load and use the graph tool +loader = ToolConfigLoader() +analysis_workflow = loader.load_tool(analysis_workflow_tool) +``` +``` + +## Traditional Tool Loading + +### String Identifier Loading + +```python +from strands.experimental.config_loader.tools import ToolConfigLoader + +loader = ToolConfigLoader() + +# Load by function name (searches common locations) +calculator = loader.load_tool("calculator") + +# Load with module specification +web_search = loader.load_tool("web_search", "my_tools.search") + +# Load by fully qualified name +custom_tool = loader.load_tool("my_package.tools.custom_analyzer") + +# Load from strands_tools package +file_write = loader.load_tool("strands_tools.file_write") +``` + +### Module-Based Tool Loading + +The loader supports tools that follow the module-based pattern used by packages like `strands_tools`: + +```python +# These tools have a TOOL_SPEC dictionary and a function with the same name +# Example: strands_tools.calculator has both TOOL_SPEC and calculator() function + +loader = ToolConfigLoader() + +# Load module-based tools +calculator = loader.load_tool("calculator") # Finds strands_tools.calculator +file_reader = loader.load_tool("file_read") # Finds strands_tools.file_read + +# The loader automatically wraps these in ModuleFunctionTool instances +``` + +### Batch Tool Loading + +```python +# Load multiple tools at once +tool_specs = [ + "calculator", # String identifier + {"name": "web_search", "module": "my_tools.search"}, # Tool with module + { + # Agent-as-tool configuration + "name": "research_agent", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a research assistant.", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "Research query" + } + }, + "required": ["query"] + }, + "prompt": "Research: {query}" + } +] + +tools = loader.load_tools(tool_specs) +``` + +## Input Schema Configuration Format + +Agent-as-Tool configurations use JSONSchema format for defining input parameters: + +### JSONSchema Format (Recommended) + +```python +input_schema = { + "type": "object", + "properties": { + "input_text": { + "type": "string", + "description": "Text to process" + }, + "output_format": { + "type": "string", + "description": "Desired output format", + "default": "json" + }, + "max_length": { + "type": "integer", + "description": "Maximum output length", + "default": 1000 + } + }, + "required": ["input_text"] +} +``` + +### Automatic Query Parameter + +If no `prompt` field is provided and no `query` parameter exists in the input schema, the system automatically adds a default `query` parameter: + +```python +# This configuration... +agent_tool_config = { + "name": "simple_agent", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a helpful assistant.", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": {}, + "required": [] + } +} + +# ...automatically becomes equivalent to: +agent_tool_config = { + "name": "simple_agent", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a helpful assistant.", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "The query or input to send to the agent" + } + }, + "required": ["query"] + } +} +``` + +### Parameter Defaults and Substitution + +Default values from the input schema are used for template substitution: + +```python +config = { + "name": "formatter", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a text formatter.", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "description": "Text to format" + }, + "style": { + "type": "string", + "description": "Formatting style", + "default": "professional" + } + }, + "required": ["text"] + }, + "prompt": "Format this text in {style} style: {text}" +} + +# When called with {"text": "Hello world"}, the prompt becomes: +# "Format this text in professional style: Hello world" +``` + +## Tool Resolution Strategies + +The `ToolConfigLoader` uses multiple strategies to find tools: + +1. **Registry lookup**: Check already loaded tools in the registry +2. **Module path loading**: Load from specified module paths +3. **Fully qualified names**: Resolve `module.tool_name` patterns (e.g., `strands_tools.calculator`) +4. **Directory scanning**: Search in `./tools/` and current directory +5. **Module-based tools**: Support for TOOL_SPEC pattern (like `strands_tools`) +6. **Agent configuration**: Load agent-as-tool from configuration + +### Tool Discovery Example + +```python +from strands.experimental.config_loader.tools import ToolConfigLoader + +loader = ToolConfigLoader() + +# Get available tools from registry +available_tools = +# Scan specific module for tools +module_tools = loader.get_available_tools("./my_tools/analysis.py") + +``` + +### Module-Based Tool Support + +The loader automatically detects and wraps module-based tools that follow the pattern: +- A function with the tool name (e.g., `calculator`) +- A `TOOL_SPEC` dictionary defining the tool specification +- Function signature: `(tool: ToolUse, **kwargs) -> ToolResult` + +```python +# Example module-based tool (like in strands_tools) +# my_tools/calculator.py + +TOOL_SPEC = { + "name": "calculator", + "description": "Performs mathematical calculations", + "inputSchema": { + "type": "object", + "properties": { + "expression": { + "type": "string", + "description": "Mathematical expression to evaluate" + } + }, + "required": ["expression"] + } +} + +def calculator(tool, **kwargs): + """Calculate mathematical expressions.""" + expression = tool.get("input", {}).get("expression", "") + try: + result = eval(expression) # Note: Use safe evaluation in production + return { + "status": "success", + "content": [{"text": str(result)}] + } + except Exception as e: + return { + "status": "error", + "content": [{"text": f"Error: {str(e)}"}] + } + +# The loader automatically wraps this in ModuleFunctionTool +``` + +## Integration with Agent Configuration + +Agent-as-Tool configurations work seamlessly with the Agent Configuration Loader: + +```python +from strands.experimental.config_loader.agent import AgentConfigLoader + +# Agent configuration with mixed tool types +agent_config = { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a multi-modal assistant with specialized tools.", + "tools": [ + # Traditional tool + {"name": "calculator"}, + + # Module-based tool + {"name": "file_write", "module": "strands_tools"}, + + # Agent-as-tool + { + "name": "text_analyzer", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a text analysis expert.", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "text": { + "type": "string", + "description": "Text to analyze" + }, + "analysis_type": { + "type": "string", + "description": "Type of analysis (sentiment, readability, complexity)", + "default": "sentiment" + } + }, + "required": ["text"] + }, + "prompt": "Analyze the text '{text}' for {analysis_type} characteristics." + }, + + # Complex agent-as-tool with sub-tools + { + "name": "code_generator", + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a code generation expert.", + "tools": [{"name": "syntax_validator"}] + }, + "input_schema": { + "type": "object", + "properties": { + "language": { + "type": "string", + "description": "Programming language" + }, + "task_description": { + "type": "string", + "description": "Description of what the code should do" + }, + "constraints": { + "type": "string", + "description": "Additional constraints or requirements", + "default": "None" + } + }, + "required": ["language", "task_description"] + }, + "prompt": """Generate {language} code that {task_description}. + +Requirements: +- Follow best practices +- Include comments +- Handle edge cases + +Additional constraints: {constraints}""" + } + ] +} + +# Load the agent +loader = AgentConfigLoader() +agent = loader.load_agent(agent_config) +``` + +## Error Handling and Debugging + +```python +from strands.experimental.config_loader.tools import ToolConfigLoader + +loader = ToolConfigLoader() + +try: + # Tool not found + tool = loader.load_tool("nonexistent_tool") +except ValueError as e: + print(f"Tool loading failed: {e}") + +try: + # Invalid agent-as-tool configuration + agent_tool = loader.load_tool({ + "name": "invalid_agent", + "agent": {} # Missing required configuration + }) +except ValueError as e: + print(f"Agent tool configuration error: {e}") + +try: + # Invalid input schema + agent_tool = loader.load_tool({ + "name": "bad_schema", + "agent": {"model": "us.amazon.nova-lite-v1:0", "system_prompt": "Test"}, + "input_schema": {"type": "array"} # Must be "object" + }) +except ValueError as e: + print(f"Input schema error: {e}") +``` + +Common errors: +- Tool not found in any resolution strategy +- Missing required fields in agent-as-tool configurations +- Invalid input schema format (must be JSONSchema with type "object") +- Circular dependencies in agent tool hierarchies +- Module import failures + +## Performance Considerations + +### Caching + +The `ToolConfigLoader` automatically caches loaded tools and modules: + +```python +loader = ToolConfigLoader() + +# First load - reads from disk/imports module +tool1 = loader.load_tool("my_tool") + +# Second load - returns cached instance +tool2 = loader.load_tool("my_tool") # Fast! + +# Agent tools are cached based on configuration hash +agent_tool1 = loader.load_tool(agent_config) +agent_tool2 = loader.load_tool(agent_config) # Returns cached instance + +``` + +### Agent-as-Tool Performance + +- Agent-as-Tool instances are cached based on configuration hash +- Template substitution is performed at runtime for flexibility +- Consider using lighter models (e.g., `nova-lite`) for simple agent tools +- Complex agent tools with many sub-tools may have higher latency + +## Best Practices + +### 1. Design Focused Agent Tools + +```python +# Good: Focused, single-purpose agent tool +email_composer = { + "name": "email_composer", + "description": "Composes professional emails", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You are a professional email writing assistant.", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "description": "Email subject" + }, + "tone": { + "type": "string", + "description": "Email tone", + "default": "professional" + }, + "recipient_type": { + "type": "string", + "description": "Type of recipient", + "default": "colleague" + } + }, + "required": ["subject"] + }, + "prompt": "Compose a {tone} email about {subject} to {recipient_type}." +} +``` + +### 2. Use Appropriate Model Sizes + +```python +# Use lighter models for simple tasks +simple_formatter = { + "name": "text_formatter", + "agent": { + "model": "us.amazon.nova-lite-v1:0", # Faster, cheaper + "system_prompt": "You are a text formatting assistant.", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "text": {"type": "string", "description": "Text to format"}, + "format_type": {"type": "string", "description": "Format type"} + }, + "required": ["text", "format_type"] + }, + "prompt": "Format the text: {text} as {format_type}" +} + +# Use more capable models for complex reasoning +complex_analyzer = { + "name": "business_analyzer", + "agent": { + "model": "us.amazon.nova-pro-v1:0", # More capable + "system_prompt": "You are a business analysis expert.", + "tools": [{"name": "financial_calculator"}, {"name": "market_research"}] + }, + "input_schema": { + "type": "object", + "properties": { + "scenario": {"type": "string", "description": "Business scenario to analyze"} + }, + "required": ["scenario"] + }, + "prompt": "Analyze business scenario: {scenario}" +} +``` + +### 3. Template Design Patterns + +```python +# Pattern: Context + Task + Output specification +analysis_template = """Context: {context} + +Task: Analyze the {data_type} data for {analysis_goal}. + +Output Requirements: +- Format: {output_format} +- Detail Level: {detail_level} +- Include: {include_sections} + +Data: {data}""" + +analysis_tool = { + "name": "data_analyzer", + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You are a data analysis expert.", + "tools": [] + }, + "input_schema": { + "type": "object", + "properties": { + "context": {"type": "string", "description": "Analysis context"}, + "data_type": {"type": "string", "description": "Type of data"}, + "analysis_goal": {"type": "string", "description": "Analysis objective"}, + "output_format": {"type": "string", "default": "structured"}, + "detail_level": {"type": "string", "default": "detailed"}, + "include_sections": {"type": "string", "default": "summary, insights, recommendations"}, + "data": {"type": "string", "description": "The data to analyze"} + }, + "required": ["context", "data_type", "analysis_goal", "data"] + }, + "prompt": analysis_template +} +``` + +### 4. Hierarchical Tool Organization + +```python +# Main coordinator agent +coordinator_tools = [ + { + "name": "data_processor", + "agent": { + "model": "us.amazon.nova-lite-v1:0", + "system_prompt": "You coordinate data processing tasks.", + "tools": [ + {"name": "validator"}, + {"name": "transformer"}, + {"name": "enricher"} + ] + }, + "input_schema": { + "type": "object", + "properties": { + "data": {"type": "string", "description": "Data to process"} + }, + "required": ["data"] + }, + "prompt": "Process this data: {data}" + }, + { + "name": "report_generator", + "agent": { + "model": "us.amazon.nova-pro-v1:0", + "system_prompt": "You generate comprehensive reports.", + "tools": [{"name": "formatter"}, {"name": "chart_generator"}] + }, + "input_schema": { + "type": "object", + "properties": { + "processed_data": {"type": "string", "description": "Processed data for reporting"} + }, + "required": ["processed_data"] + }, + "prompt": "Generate report from: {processed_data}" + } +] + +# Each level handles appropriate complexity and specialization +``` + +### 5. Tool Configuration Management + +```python +from strands.experimental.config_loader.tools import ToolConfigLoader + +class ToolConfigManager: + """Manages tool configurations and loading.""" + + def __init__(self): + self.loader = ToolConfigLoader() + self.tool_configs = {} + + def register_tool_config(self, name: str, config: dict): + """Register a reusable tool configuration.""" + self.tool_configs[name] = config + + def get_tool(self, name: str): + """Get a tool by name.""" + if name in self.tool_configs: + return self.loader.load_tool(self.tool_configs[name]) + return self.loader.load_tool(name) + + def create_agent_tool(self, name: str, model: str, prompt: str, input_schema: dict): + """Helper to create simple agent tools.""" + config = { + "name": name, + "agent": { + "model": model, + "system_prompt": "You are a helpful assistant.", + "tools": [] + }, + "input_schema": input_schema, + "prompt": prompt + } + return self.loader.load_tool(config) + +# Usage +manager = ToolConfigManager() + +# Register common configurations +manager.register_tool_config("email_writer", email_composer) +manager.register_tool_config("code_reviewer", code_reviewer_config) + +# Use registered tools +email_tool = manager.get_tool("email_writer") +review_tool = manager.get_tool("code_reviewer") +``` + +This hierarchical and modular approach enables building sophisticated multi-agent systems where each level handles appropriate complexity and specialization, while maintaining clean separation of concerns and reusability. diff --git a/docs/user-guide/concepts/model-providers/cohere.md b/docs/user-guide/concepts/model-providers/cohere.md index d0988ca6..a7d0ca6e 100644 --- a/docs/user-guide/concepts/model-providers/cohere.md +++ b/docs/user-guide/concepts/model-providers/cohere.md @@ -1,6 +1,6 @@ # Cohere -[Cohere](https://cohere.com) provides cutting-edge language models. These are accessible accessible through OpenAI's SDK via the Compatibility API. This allows easy and portable integration with the Strands Agents SDK using the familiar OpenAI interface. +[Cohere](https://cohere.com) provides cutting-edge language models. These are accessible through OpenAI's SDK via the Compatibility API. This allows easy and portable integration with the Strands Agents SDK using the familiar OpenAI interface. ## Installation diff --git a/docs/user-guide/deploy/deploy_to_bedrock_agentcore.md b/docs/user-guide/deploy/deploy_to_bedrock_agentcore.md index 3073b3da..2ef9098a 100644 --- a/docs/user-guide/deploy/deploy_to_bedrock_agentcore.md +++ b/docs/user-guide/deploy/deploy_to_bedrock_agentcore.md @@ -15,8 +15,8 @@ Before you start, you need: --- -## 🚨 Don't forget observability -> +> 🚨 **Don't forget observability** +> > 📈 **[AgentCore runtime observability](#observability-enablement)** - Distributed tracing, metrics, and debugging > > **This section is at the bottom of this document - don't skip it** @@ -55,21 +55,21 @@ pip install bedrock-agentcore ### Step 2: Prepare Your Agent Code -#### Basic Setup (3 simple steps) +Basic Setup (3 simple steps) -##### Import the runtime +Import the runtime ```python from bedrock_agentcore.runtime import BedrockAgentCoreApp ``` -##### Initialize the app +Initialize the app ```python app = BedrockAgentCoreApp() ``` -##### Decorate your function +Decorate your function ```python @app.entrypoint @@ -81,9 +81,9 @@ if __name__ == "__main__": app.run() ``` -#### Complete Examples +Complete Examples -##### Basic Example +- Basic Example ```python from bedrock_agentcore.runtime import BedrockAgentCoreApp @@ -103,7 +103,7 @@ if __name__ == "__main__": app.run() ``` -##### Streaming Example +- Streaming Example ```python from strands import Agent @@ -142,7 +142,7 @@ curl -X POST http://localhost:8080/invocations \ > **Choose ONE of the following deployment methods:** -### Method A: Starter Toolkit (For quick prototyping) +#### Method A: Starter Toolkit (For quick prototyping) For quick prototyping with automated deployment: @@ -150,7 +150,7 @@ For quick prototyping with automated deployment: pip install bedrock-agentcore-starter-toolkit ``` -#### Project Structure +Project Structure ``` your_project_directory/ @@ -159,7 +159,7 @@ your_project_directory/ └── __init__.py # Makes the directory a Python package ``` -#### agent_example.py +Example: agent_example.py ```python from strands import Agent @@ -179,16 +179,16 @@ if __name__ == "__main__": app.run() ``` -#### requirements.txt +Example: requirements.txt ``` strands-agents bedrock-agentcore ``` -#### Deploy with Starter Toolkit +Deploy with Starter Toolkit -Ensure Docker is running before proceeding: +> Ensure Docker is running before proceeding: ```bash # Configure your agent @@ -204,7 +204,7 @@ agentcore launch agentcore invoke '{"prompt": "Hello"}' ``` -### Method B: Manual Deployment with boto3 +#### Method B: Manual Deployment with boto3 For more control over the deployment process: @@ -232,7 +232,7 @@ response = client.create_agent_runtime( ) ``` -3. Invoke Your Agent +Invoke Your Agent ```python import boto3 @@ -252,8 +252,8 @@ response = agent_core_client.invoke_agent_runtime( ) ``` -### 📊 Next Steps: Set Up Observability (Optional) - +>📊 Next Steps: Set Up Observability (Optional) +> > **⚠️ IMPORTANT**: Your agent is deployed, you could also set up [Observability](#observability-enablement) @@ -265,22 +265,22 @@ response = agent_core_client.invoke_agent_runtime( This approach demonstrates how to deploy a custom agent using FastAPI and Docker, following AgentCore Runtime requirements. -### Requirements +**Requirements** - **FastAPI Server**: Web server framework for handling requests - **/invocations Endpoint**: POST endpoint for agent interactions (REQUIRED) - **/ping Endpoint**: GET endpoint for health checks (REQUIRED) - **Docker Container**: ARM64 containerized deployment package -### Quick Start Setup +### Step 1: Quick Start Setup -#### Install uv +Install uv ```bash curl -LsSf https://astral.sh/uv/install.sh | sh ``` -#### Create Project +Create Project ```bash mkdir my-custom-agent && cd my-custom-agent @@ -288,7 +288,8 @@ uv init --python 3.11 uv add fastapi uvicorn[standard] pydantic httpx strands-agents ``` -### Project Structure +Project Structure example + ``` my-custom-agent/ ├── agent.py # FastAPI application @@ -297,9 +298,9 @@ my-custom-agent/ └── uv.lock # Created automatically by uv ``` -### Complete Strands Agent Example +### Step 2: Prepare your agent code -#### agent.py +Example: agent.py ```python from fastapi import FastAPI, HTTPException @@ -350,7 +351,7 @@ if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8080) ``` -### Test Locally +### Step 3: Test Locally ```bash # Run the application @@ -367,7 +368,9 @@ curl -X POST http://localhost:8080/invocations \ }' ``` -### Create Dockerfile +### Step 4: Prepare your docker image + +Create docker file ```dockerfile # Use uv's ARM64 Python base image @@ -391,15 +394,13 @@ EXPOSE 8080 CMD ["uv", "run", "uvicorn", "agent:app", "--host", "0.0.0.0", "--port", "8080"] ``` -### Build and Deploy ARM64 Image - -#### Setup Docker buildx +Setup Docker buildx ```bash docker buildx create --use ``` -#### Build and Test Locally +Build and Test Locally ```bash # Build the image @@ -414,7 +415,7 @@ docker run --platform linux/arm64 -p 8080:8080 \ my-agent:arm64 ``` -#### Deploy to ECR +Deploy to ECR ```bash # Create ECR repository @@ -430,9 +431,9 @@ docker buildx build --platform linux/arm64 -t .dkr.ecr.us-west-2.ama aws ecr describe-images --repository-name my-strands-agent --region us-west-2 ``` -### Deploy Agent Runtime +### Step 5: Deploy Agent Runtime -#### deploy_agent.py +Example: deploy_agent.py ```python import boto3 @@ -455,13 +456,15 @@ print(f"Agent Runtime ARN: {response['agentRuntimeArn']}") print(f"Status: {response['status']}") ``` +Execute python file + ```bash uv run deploy_agent.py ``` -### Invoke Your Agent +### Step 6: Invoke Your Agent -#### invoke_agent.py +Example: invoke_agent.py ```python import boto3 @@ -484,11 +487,13 @@ response_data = json.loads(response_body) print("Agent Response:", response_data) ``` +Execute python file + ```bash uv run invoke_agent.py ``` -### Expected Response Format +Expected Response Format ```json { @@ -509,11 +514,11 @@ uv run invoke_agent.py --- -# Shared Information (Both Options) +## Shared Information > **This section applies to both deployment approaches** - reference as needed regardless of which option you chose. -## AgentCore Runtime Requirements Summary +### AgentCore Runtime Requirements Summary - **Platform**: Must be linux/arm64 - **Endpoints**: /invocations POST and /ping GET are mandatory @@ -522,7 +527,7 @@ uv run invoke_agent.py - **Strands Integration**: Uses Strands Agent for AI processing - **Credentials**: Require AWS credentials for operation -## Best Practices +### Best Practices **Development** @@ -542,7 +547,7 @@ uv run invoke_agent.py - Secure sensitive information - Regular security updates -## Troubleshooting +### Troubleshooting **Deployment Failures** @@ -572,11 +577,13 @@ Amazon Bedrock AgentCore provides built-in metrics to monitor your Strands agent Before you can view metrics and traces, complete this one-time setup: **Via AgentCore Console** -- Look for the "Enable Observability" button when creating a memory resource + +Look for the **"Enable Observability"** button when creating a memory resource >If you don't see this button while configuring your agent (for example, if you don't create a memory resource in the console), you must enable observability manually by using the CloudWatch console to enable Transaction Search as described in the following procedure. **Via CloudWatch Console** + 1. Open the CloudWatch console 2. Navigate to Application Signals (APM) > Transaction search 3. Choose "Enable Transaction Search" @@ -586,36 +593,41 @@ Before you can view metrics and traces, complete this one-time setup: ### Step 2: Add ADOT to Your Strands Agent -#### 1. Add Dependencies - Add to your `requirements.txt`: ```text -aws-opentelemetry-distro>=0.10.0 +aws-opentelemetry-distro>=0.10.1 boto3 ``` Or install directly: ```bash -pip install aws-opentelemetry-distro>=0.10.0 boto3 +pip install aws-opentelemetry-distro>=0.10.1 boto3 ``` -#### 2. Run With Auto-Instrumentation +Run With Auto-Instrumentation -**For SDK Integration (Option A):** +- For SDK Integration (Option A): ```bash opentelemetry-instrument python my_agent.py ``` -**For Docker Deployment:** +- For Docker Deployment: ```dockerfile CMD ["opentelemetry-instrument", "python", "main.py"] ``` -**For Custom Agent (Option B):** +- For Custom Agent (Option B): ```dockerfile CMD ["opentelemetry-instrument", "uvicorn", "agent:app", "--host", "0.0.0.0", "--port", "8080"] ``` +### Step 3: Viewing Your Agent's Observability Data + +1. Open the CloudWatch console +2. Navigate to the GenAI Observability page +3. Find your agent service +4. View traces, metrics, and logs + ### Session ID support To propagate session ID, you need to invoke using session identifier in the OTEL baggage: @@ -643,7 +655,7 @@ def invoke_agent(agent_id, payload, session_id=None): return response ``` -#### Common Tracing Headers +Common Tracing Headers Examples: | Header | Description | Sample Value | |--------|-------------|-------------| @@ -654,19 +666,12 @@ def invoke_agent(agent_id, payload, session_id=None): For more supported headers details, please check [Bedrock AgentCore Runtime Observability Configuration](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/observability-configure.html) -### Viewing Your Agent's Observability Data - -1. Open the CloudWatch console -2. Navigate to the GenAI Observability page -3. Find your agent service -4. View traces, metrics, and logs - ### Best Practices -- **Use consistent session IDs** across related requests -- **Set appropriate sampling rates** (1% is default) -- **Monitor key metrics** like latency, error rates, and token usage -- **Set up CloudWatch alarms** for critical thresholds +- Use consistent session IDs across related requests +- Set appropriate sampling rates (1% is default) +- Monitor key metrics like latency, error rates, and token usage +- Set up CloudWatch alarms for critical thresholds --- diff --git a/docs/user-guide/observability-evaluation/traces.md b/docs/user-guide/observability-evaluation/traces.md index 45e6baaf..a990172b 100644 --- a/docs/user-guide/observability-evaluation/traces.md +++ b/docs/user-guide/observability-evaluation/traces.md @@ -83,7 +83,7 @@ Strands natively integrates with OpenTelemetry, an industry standard for distrib ## Enabling Tracing -!!! warning "To enable OTEL exporting, install Strands Agents with `otel` extra dependencies: `pip install strands-agents[otel]`" +!!! warning "To enable OTEL exporting, install Strands Agents with `otel` extra dependencies: `pip install 'strands-agents[otel]'`" ### Environment Variables diff --git a/mkdocs.yml b/mkdocs.yml index 311de0d4..fe7e8664 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -125,6 +125,15 @@ nav: - Amazon Bedrock AgentCore : user-guide/deploy/deploy_to_bedrock_agentcore.md - Amazon EKS: user-guide/deploy/deploy_to_amazon_eks.md - Amazon EC2: user-guide/deploy/deploy_to_amazon_ec2.md + - Experimental: + - Overview: experimental/README.md + - Configuration Loaders: + - Overview: experimental/config-loader/overview.md + - Agent Configuration: experimental/config-loader/agent-config.md + - Tool Configuration: experimental/config-loader/tool-config.md + - Swarm Configuration: experimental/config-loader/swarm-config.md + - Graph Configuration: experimental/config-loader/graph-config.md + - Structured Output Configuration: experimental/config-loader/structured-output.md - Examples: - Overview: examples/README.md - CLI Reference Agent Implementation: examples/python/cli-reference-agent.md