Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e417740
feat: add dapr-ext-agent_core
CasperGN Jan 28, 2026
49cba9f
feat: include dapr-agents mapper & init of LangGraph mapper
CasperGN Jan 28, 2026
0e53685
chore: rename folder
CasperGN Feb 2, 2026
cacefae
feat: support extracting metadata from langgraph
CasperGN Feb 2, 2026
7ade3b1
feat: extract agent from gc references to automatically infer the age…
CasperGN Feb 2, 2026
13bcc9d
feat(strands): add strands metadata shim
CasperGN Feb 2, 2026
2fa0277
test: add comprehensive test suite for langgraph and strands
CasperGN Feb 2, 2026
44ce2a0
feat: add strands example & streamline metadata extractor
CasperGN Feb 3, 2026
e465671
fix: naming for langgraph & remove irrelevant comments
CasperGN Feb 3, 2026
924f1e5
chore(format): ruff
CasperGN Feb 3, 2026
256de6c
fix: comment out depending on agent_core as there's no pkg yet
CasperGN Feb 3, 2026
4ac3b31
chore(format): ruff
CasperGN Feb 3, 2026
08cb9ad
fix: correctly ref dapr_agents & formatting
CasperGN Feb 3, 2026
c9ee335
chore: remove session_id from memory metadata as per https://github.c…
CasperGN Feb 6, 2026
46e04fa
Merge branch 'main' into feat(agent)--add-agent-core-for-agent-metadata
CasperGN Feb 10, 2026
9183102
chore: bump versions and include uncommented agent_core pkg
CasperGN Feb 10, 2026
f65ff53
feat: add field for framework
CasperGN Feb 10, 2026
3d87824
fix: add framework field
CasperGN Feb 10, 2026
4cf308e
fix: extract orchestrator from execution profile if available else se…
CasperGN Feb 10, 2026
2345002
chore: update schemas with new field
CasperGN Feb 10, 2026
d1ed48b
fix: ensure install of agent_core
CasperGN Feb 10, 2026
aea1dc2
fix: remove StrEnum to support 3.10
CasperGN Feb 10, 2026
764ccdd
feat: copy session constructs from dapr agents needed to persist stat…
CasperGN Feb 10, 2026
08167dc
chore(format): ruff
CasperGN Feb 10, 2026
3ecd29a
fix: correct importing & generate schema
CasperGN Feb 10, 2026
88442e3
fix: use enum for framework
CasperGN Feb 10, 2026
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
2 changes: 1 addition & 1 deletion examples/langgraph-checkpointer/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def assistant(state: MessagesState):
)
builder.add_edge('tools', 'assistant')

memory = DaprCheckpointer(store_name='statestore', key_prefix='dapr')
memory = DaprCheckpointer(state_store_name='statestore', key_prefix='dapr')
react_graph_memory = builder.compile(checkpointer=memory)

config = {'configurable': {'thread_id': '1'}}
Expand Down
14 changes: 14 additions & 0 deletions examples/langgraph-checkpointer/components/agent-registry.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: agent-registry
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
- name: keyPrefix
value: none
12 changes: 12 additions & 0 deletions examples/langgraph-checkpointer/dapr-llm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# https://docs.dapr.io/developing-applications/local-development/multi-app-dapr-run/multi-app-template/#template-properties
version: 1
common:
resourcesPath: ./components
logLevel: info
appLogDestination: console
daprdLogDestination: console

apps:
- appID: langgraph
appDirPath: ./
command: ["python3", "agent.py"]
168 changes: 168 additions & 0 deletions examples/strands-agent/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Dapr For Agents - Strands Agent with Persistent Session Storage

Supporting Dapr-backed session persistence for Strands Agent SDK with distributed state storage.

## Overview

This example demonstrates how to use a **real Strands Agent** from the Strands Agent SDK together with `DaprSessionManager` for distributed session persistence. The example shows:

- Creating a Strands Agent with the official Strands SDK
- Using DaprSessionManager for distributed session storage across restarts
- Tool integration (weather checking example)
- Conversation history persistence and restoration
- Seamless LLM integration through Strands model providers

**Note:** This uses the actual [Strands Agent SDK](https://strandsagents.com/), not just session types.

## Pre-requisites

- [Dapr CLI and initialized environment](https://docs.dapr.io/getting-started)
- [Install Python 3.10+](https://www.python.org/downloads/)
- OpenAI API key (or configure a different model provider)

## Install Dependencies

```sh
pip3 install -r requirements.txt
```

Set your API key:
```sh
export OPENAI_API_KEY=your-key-here
```

## Run the Example

Run the following command in a terminal/command prompt:

```sh
dapr run --app-id strands-agent --resources-path ./components -- python3 agent.py
```

### What to Expect

The example will:

1. Create a Strands Agent with:
- GPT-4o model via OpenAIModel provider
- A `get_weather` tool function
- System prompt and agent metadata
- DaprSessionManager for session persistence
2. Process user queries:
- "What's the weather in San Francisco?" → Agent uses get_weather tool
- "How about New York?" → Agent continues conversation with context
3. Persist all conversation state to Dapr state store
4. On subsequent runs, automatically restore full conversation history

Run the example again to see the conversation resume from where it left off!

### Example Output

**First run:**
```
📂 Using session: assistant-session-1
✅ Created Strands Agent: weather-assistant
Model: OpenAIModel(model='gpt-4o')
Tools: ['get_weather']
Session Manager: DaprSessionManager

🆕 Starting fresh conversation

👤 USER: What's the weather in San Francisco?
🤖 ASSISTANT: The weather in San Francisco is sunny and 72°F

👤 USER: How about New York?
🤖 ASSISTANT: Let me check that for you. The weather in New York is sunny and 72°F

✅ Conversation complete!
🔄 Run again to resume the conversation with full history from Dapr state store.
```

**Second run (conversation resumes):**
```
📂 Using session: assistant-session-1
✅ Created Strands Agent: weather-assistant
Model: OpenAIModel(model='gpt-4o')
Tools: ['get_weather']
Session Manager: DaprSessionManager

💬 Resuming conversation with 4 previous messages
────────────────────────────────────────────────────────────
👤 USER: What's the weather in San Francisco?
🤖 ASSISTANT: The weather in San Francisco is sunny and 72°F
👤 USER: How about New York?
🤖 ASSISTANT: Let me check that for you. The weather in New York is sunny and 72°F
────────────────────────────────────────────────────────────

👤 USER: What's the weather in San Francisco?
🤖 ASSISTANT: I just checked that - it's still sunny and 72°F in San Francisco!
```

## Key Features

### Real Strands Agent
- Uses the official Strands Agent SDK from strandsagents.com
- Full agent capabilities: tools, system prompts, state management
- Multiple LLM provider support (Anthropic, OpenAI, Bedrock, etc.)

### Distributed Session Persistence
- DaprSessionManager stores all conversation state in Dapr state stores
- Supports any Dapr state store: Redis, PostgreSQL, MongoDB, Cosmos DB, etc.
- Automatic conversation restoration across application restarts
- Full message history maintained

### Tool Integration
- Define Python functions as tools
- Agent automatically calls tools when needed
- Tool results integrated into conversation flow

### LLM Provider Flexibility
- Easy to swap model providers (AnthropicModel, OpenAIModel, etc.)
- Configure model parameters (temperature, max tokens, etc.)
- Strands handles all LLM interactions

### State Persistence
- Automatic state synchronization with Dapr
- Support for TTL and consistency levels
- Compatible with any Dapr state store (Redis, PostgreSQL, Cosmos DB, etc.)

## Customization

You can customize the session manager with:

```python
session_manager = DaprSessionManager(
session_id='my-session',
state_store_name='statestore',
dapr_client=dapr_client,
ttl=3600, # Optional: TTL in seconds
consistency='strong', # Optional: 'eventual' or 'strong'
)
```

## Configuration

### State Store

The example uses a Redis state store component. You can modify [components/statestore.yaml](./components/statestore.yaml) to use a different state store backend supported by Dapr.

### Conversation Provider

The example uses the `echo` conversation component by default (which echoes back your input). To use a real LLM:

1. Set up a conversation component (e.g., OpenAI, Anthropic) in `components/conversation.yaml`
2. Update the `conversation_provider` variable in `agent.py` to match your component name
3. Set required API keys as environment variables

Example for OpenAI:
```bash
export OPENAI_API_KEY="your-api-key"
```

See [examples/conversation](../conversation/) for more conversation component examples.

## Learn More

- [Dapr State Management](https://docs.dapr.io/developing-applications/building-blocks/state-management/)
- [Strands Framework](https://github.com/microsoft/strands)
- [Dapr Python SDK](https://github.com/dapr/python-sdk)
105 changes: 105 additions & 0 deletions examples/strands-agent/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""
Example demonstrating a Strands Agent with DaprSessionManager for persistent session storage.

This example shows how to:
- Create a Strands Agent with the Strands Agent SDK
- Use DaprSessionManager for distributed session persistence
- Leverage LLM providers through Strands
- Maintain conversation history across restarts
"""

import os

from dapr.ext.strands import DaprSessionManager
from strands import Agent, tool
from strands.models import OpenAIModel

from dapr.clients import DaprClient


@tool
def get_weather(location: str) -> str:
"""Get the current weather for a location.

Args:
location: The city and state, e.g. "San Francisco, CA"

Returns:
A description of the current weather
"""
return f'The weather in {location} is sunny and 72°F'


def run_agent_conversation():
"""Run a Strands Agent with Dapr session persistence."""

openai_api_key = os.getenv('OPENAI_API_KEY')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can we better users trying out different LLM Providers here? Maybe warn instead of returning? What all would be needed to update if they did swap providers here?

Can you pls rm the return and just warn for this. Also, no emojis in print outs please.

if not openai_api_key:
print('❌ Error: OPENAI_API_KEY environment variable not set')
print('💡 Set it with: export OPENAI_API_KEY=your-key-here')
return

session_id = 'assistant-session-1'
agent_id = 'weather-assistant'

with DaprClient() as dapr_client:
session_manager = DaprSessionManager(
session_id=session_id, state_store_name='statestore', dapr_client=dapr_client
)
Comment on lines +42 to +48
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we removed the concept of a session in the dapr agents state revamp then should the session id from a dapr for agents POV be hidden too and this would just be the workflow id under the hood?


agent = Agent(
model=OpenAIModel(model_id='gpt-4o'),
system_prompt=(
'You are a helpful weather assistant. '
'You can check the weather for any location. '
'Be concise and friendly in your responses.'
),
tools=[get_weather],
agent_id=agent_id,
name='Weather Assistant',
description='An AI assistant that helps users check the weather',
state={
'role': 'Weather Assistant',
'goal': 'Help users get weather information',
'instructions': ['Be concise', 'Be friendly', 'Always use the get_weather tool'],
'max_iterations': 5,
},
session_manager=session_manager,
)

queries = [
"What's the weather in San Francisco?",
'How about New York?',
]

for query in queries:
print(f'👤 USER: {query}')

try:
import asyncio

response = asyncio.run(agent.invoke_async(query))

if hasattr(response, 'content'):
content = response.content
elif hasattr(response, 'text'):
content = response.text
else:
content = str(response)

print(f'🤖 ASSISTANT: {content}')

except Exception as e:
print(f'❌ Error: {e}')
print('💡 Tip: Make sure you have OPENAI_API_KEY set in your environment.')
print(' Or switch to a different model provider (Anthropic, Bedrock, etc.)')
break

print()

print('✅ Conversation complete!')
print('🔄 Run again to resume the conversation with full history from Dapr state store.')


if __name__ == '__main__':
run_agent_conversation()
14 changes: 14 additions & 0 deletions examples/strands-agent/components/agent-registry.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: agent-registry
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
- name: keyPrefix
value: none
8 changes: 8 additions & 0 deletions examples/strands-agent/components/conversation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: echo
spec:
type: conversation.echo
version: v1
metadata: []
14 changes: 14 additions & 0 deletions examples/strands-agent/components/statestore.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
- name: actorStateStore
value: "true"
12 changes: 12 additions & 0 deletions examples/strands-agent/dapr-llm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# https://docs.dapr.io/developing-applications/local-development/multi-app-dapr-run/multi-app-template/#template-properties
version: 1
common:
resourcesPath: ./components
logLevel: info
appLogDestination: console
daprdLogDestination: console

apps:
- appID: strands-agent
appDirPath: ./
command: ["python3", "agent.py"]
3 changes: 3 additions & 0 deletions examples/strands-agent/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dapr>=1.15.0
dapr-ext-strands>=0.1.0
strands-agents>=1.24.0
Loading
Loading