-
Notifications
You must be signed in to change notification settings - Fork 139
Feat(agent): add agent core for agent metadata #899
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
CasperGN
wants to merge
26
commits into
dapr:main
Choose a base branch
from
CasperGN:feat(agent)--add-agent-core-for-agent-metadata
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
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 49cba9f
feat: include dapr-agents mapper & init of LangGraph mapper
CasperGN 0e53685
chore: rename folder
CasperGN cacefae
feat: support extracting metadata from langgraph
CasperGN 7ade3b1
feat: extract agent from gc references to automatically infer the age…
CasperGN 13bcc9d
feat(strands): add strands metadata shim
CasperGN 2fa0277
test: add comprehensive test suite for langgraph and strands
CasperGN 44ce2a0
feat: add strands example & streamline metadata extractor
CasperGN e465671
fix: naming for langgraph & remove irrelevant comments
CasperGN 924f1e5
chore(format): ruff
CasperGN 256de6c
fix: comment out depending on agent_core as there's no pkg yet
CasperGN 4ac3b31
chore(format): ruff
CasperGN 08cb9ad
fix: correctly ref dapr_agents & formatting
CasperGN c9ee335
chore: remove session_id from memory metadata as per https://github.c…
CasperGN 46e04fa
Merge branch 'main' into feat(agent)--add-agent-core-for-agent-metadata
CasperGN 9183102
chore: bump versions and include uncommented agent_core pkg
CasperGN f65ff53
feat: add field for framework
CasperGN 3d87824
fix: add framework field
CasperGN 4cf308e
fix: extract orchestrator from execution profile if available else se…
CasperGN 2345002
chore: update schemas with new field
CasperGN d1ed48b
fix: ensure install of agent_core
CasperGN aea1dc2
fix: remove StrEnum to support 3.10
CasperGN 764ccdd
feat: copy session constructs from dapr agents needed to persist stat…
CasperGN 08167dc
chore(format): ruff
CasperGN 3ecd29a
fix: correct importing & generate schema
CasperGN 88442e3
fix: use enum for framework
CasperGN File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
examples/langgraph-checkpointer/components/agent-registry.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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') | ||
| 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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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: [] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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.