Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/user-guide/concepts/agents/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,56 @@ Some events come in pairs, such as Before/After events. The After event callback

## Advanced Usage

### Accessing Invocation State in Hooks

Hook events that involve tool execution include access to `invocation_state`, which provides configuration and context data passed through the agent invocation. This is particularly useful for:

1. **Custom Objects**: Access database client objects, connection pools, or other Python objects
2. **Request Context**: Access session IDs, user information, settings, or request-specific data
3. **Multi-Agent Shared State**: In multi-agent patterns, access state shared across all agents - see [Shared State Across Multi-Agent Patterns](../multi-agent/multi-agent-patterns.md#shared-state-across-multi-agent-patterns)
4. **Custom Parameters**: Pass any additional data that hooks might need

```python
from strands.hooks import BeforeToolCallEvent
import logging

def log_with_context(event: BeforeToolCallEvent) -> None:
"""Log tool invocations with context from invocation state."""
# Access invocation state from the event
user_id = event.invocation_state.get("user_id", "unknown")
session_id = event.invocation_state.get("session_id")

# Access non-JSON serializable objects like database connections
db_connection = event.invocation_state.get("database_connection")
logger_instance = event.invocation_state.get("custom_logger")

# Use custom logger if provided, otherwise use default
logger = logger_instance if logger_instance else logging.getLogger(__name__)

logger.info(
f"User {user_id} in session {session_id} "
f"invoking tool: {event.tool_use['name']} "
f"with DB connection: {db_connection is not None}"
)

# Register the hook
agent = Agent(tools=[my_tool])
agent.hooks.add_callback(BeforeToolCallEvent, log_with_context)

# Execute with context including non-serializable objects
import sqlite3
custom_logger = logging.getLogger("custom")
db_conn = sqlite3.connect(":memory:")

result = agent(
"Process the data",
user_id="user123",
session_id="sess456",
database_connection=db_conn, # Non-JSON serializable object
custom_logger=custom_logger # Non-JSON serializable object
)
```

### Fixed Tool Arguments

Enforce specific arguments for tools, ensuring they always use particular values regardless of what the agent specifies:
Expand Down
6 changes: 6 additions & 0 deletions docs/user-guide/concepts/multi-agent/graph.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,12 @@ From [another_node_id]:
- [Agent name]: [Result text]
```

## Shared State

Graphs support passing shared state to all agents through the `invocation_state` parameter. This enables sharing context and configuration across agents without exposing it to the LLM.

For detailed information about shared state, including examples and best practices, see [Shared State Across Multi-Agent Patterns](./multi-agent-patterns.md#shared-state-across-multi-agent-patterns).

## Graphs as a Tool

Agents can dynamically create and orchestrate graphs by using the `graph` tool available in the [Strands tools package](../tools/community-tools-package.md).
Expand Down
55 changes: 55 additions & 0 deletions docs/user-guide/concepts/multi-agent/multi-agent-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,61 @@ Some Examples:
- Automated Data Pipelines: A fixed set of tasks to extract, analyze, and report on data, where independent analysis steps can run in parallel.
- Standard Business Processes: Onboarding a new employee by creating accounts, assigning training, and sending a welcome email, all triggered by a single agent action.

## Shared State Across Multi-Agent Patterns

Both Graph and Swarm patterns support passing shared state to all agents through the `invocation_state` parameter. This enables sharing context and configuration across agents without exposing it to the LLM.

### How Shared State Works

The `invocation_state` is automatically propagated to:

- All agents in the pattern via their `**kwargs`
- Tools via `ToolContext` when using `@tool(context=True)` - see [Python Tools](../tools/python-tools.md#accessing-invocation-state-in-tools)
- Tool-related hooks (BeforeToolCallEvent, AfterToolCallEvent) - see [Hooks](../agents/hooks.md#accessing-invocation-state-in-hooks)

### Example Usage

```python
# Same invocation_state works for both patterns
shared_state = {
"user_id": "user123",
"session_id": "sess456",
"debug_mode": True,
"database_connection": db_connection_object
}

# Execute with Graph
result = graph(
"Analyze customer data",
invocation_state=shared_state
)

# Execute with Swarm (same shared_state)
result = swarm(
"Analyze customer data",
invocation_state=shared_state
)
```

### Accessing Shared State in Tools

```python
from strands import tool, ToolContext

@tool(context=True)
def query_data(query: str, tool_context: ToolContext) -> str:
user_id = tool_context.invocation_state.get("user_id")
debug_mode = tool_context.invocation_state.get("debug_mode", False)
# Use context for personalized queries...
```

### Important Distinctions

- **Shared State**: Configuration and objects passed via `invocation_state`, not visible in prompts
- **Pattern-Specific Data Flow**: Each pattern has its own mechanisms for passing data that the LLM should reason about including shared context for swarms and agent inputs for graphs

Use `invocation_state` for context and configuration that shouldn't appear in prompts, while using each pattern's specific data flow mechanisms for data the LLM should reason about.

## Conclusion

This guide has explored the three primary multi-agent patterns in Strands: Graph, Swarm, and Workflow. Each pattern serves distinct use cases based on how execution paths are determined and controlled. When choosing between patterns, consider your problem's complexity, the need for deterministic vs. emergent behavior, and whether you require cycles, parallel execution, or specific error handling approaches.
Expand Down
6 changes: 6 additions & 0 deletions docs/user-guide/concepts/multi-agent/swarm.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ Agent name: security_specialist. Agent description: Focuses on secure coding pra
You have access to swarm coordination tools if you need help from other agents.
```

## Shared State

Swarms support passing shared state to all agents through the `invocation_state` parameter. This enables sharing context and configuration across agents without exposing them to the LLM, keeping them separate from the shared context used for collaboration.

For detailed information about shared state, including examples and best practices, see [Shared State Across Multi-Agent Patterns](./multi-agent-patterns.md#shared-state-across-multi-agent-patterns).

## Asynchronous Execution

You can also execute a Swarm asynchronously by calling the [`invoke_async`](../../../api-reference/multiagent.md#strands.multiagent.swarm.Swarm.invoke_async) function:
Expand Down
44 changes: 44 additions & 0 deletions docs/user-guide/concepts/tools/python-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,50 @@ agent("What is the tool use id?")
agent("What is the invocation state?", custom_data="You're the best agent ;)")
```

#### Accessing Invocation State in Tools

The `invocation_state` attribute in `ToolContext` provides access to data passed through the agent invocation. This is particularly useful for:

1. **Request Context**: Access session IDs, user information, or request-specific data
2. **Multi-Agent Shared State**: In [Graph](../multi-agent/graph.md) and [Swarm](../multi-agent/swarm.md) patterns, access state shared across all agents
3. **Per-Invocation Overrides**: Override behavior or settings for specific requests

```python
from strands import tool, Agent, ToolContext
import requests

@tool(context=True)
def api_call(query: str, tool_context: ToolContext) -> dict:
"""Make an API call with user context.

Args:
query: The search query to send to the API
tool_context: Context containing user information
"""
user_id = tool_context.invocation_state.get("user_id")

response = requests.get(
"https://api.example.com/search",
headers={"X-User-ID": user_id},
params={"q": query}
)

return response.json()

agent = Agent(tools=[api_call])
result = agent("Get my profile data", user_id="user123")
```

##### Invocation State Compared To Other Approaches

It's important to understand how invocation state compares to other approaches that impact tool execution:

- **Tool Parameters**: Use for data that the LLM should reason about and provide based on the user's request. Examples include search queries, file paths, calculation inputs, or any data the agent needs to determine from context.

- **Invocation State**: Use for context and configuration that should not appear in prompts but affects tool behavior. Best suited for parameters that can change between agent invocations. Examples include user IDs for personalization, session IDs, or user flags.

- **[Class-based tools](#class-based-tools)**: Use for configuration that doesn't change between requests and requires initialization. Examples include API keys, database connection strings, service endpoints, or shared resources that need setup.

### Tool Streaming

Async tools can yield intermediate results to provide real-time progress updates. Each yielded value becomes a [streaming event](../streaming/overview.md), with the final value serving as the tool's return result:
Expand Down