Skip to content

Commit d0152e4

Browse files
committed
initial commit
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
0 parents  commit d0152e4

27 files changed

+2509
-0
lines changed

.gitignore

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.*
7+
.yarn/*
8+
!.yarn/patches
9+
!.yarn/plugins
10+
!.yarn/releases
11+
!.yarn/versions
12+
13+
# testing
14+
/coverage
15+
16+
# next.js
17+
/.next/
18+
/out/
19+
20+
# production
21+
/build
22+
23+
# misc
24+
.DS_Store
25+
*.pem
26+
27+
# debug
28+
npm-debug.log*
29+
yarn-debug.log*
30+
yarn-error.log*
31+
.pnpm-debug.log*
32+
33+
# env files (can opt-in for committing if needed)
34+
.env*
35+
36+
# vercel
37+
.vercel
38+
39+
# typescript
40+
*.tsbuildinfo
41+
next-env.d.ts
42+
43+
.mastra/
44+
45+
# lock files
46+
package-lock.json
47+
yarn.lock
48+
pnpm-lock.yaml
49+
bun.lockb
50+
51+
# python
52+
agent/venv/
53+
__pycache__/
54+
.venv/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License
2+
3+
Copyright (c) Atai Barkai
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# CopilotKit <> strands Starter
2+
3+
This is a starter template for building AI agents using [strands](https://strands.com) and [CopilotKit](https://copilotkit.ai). It provides a modern Next.js application with an integrated investment analyst agent that can research stocks, analyze market data, and provide investment insights.
4+
5+
## Prerequisites
6+
7+
- Node.js 20+
8+
- Python 3.12+
9+
- OpenAI API Key (for the strands agent)
10+
- Any of the following package managers:
11+
- pnpm (recommended)
12+
- npm
13+
- yarn
14+
- bun
15+
16+
> **Note:** This repository ignores lock files (package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb) to avoid conflicts between different package managers. Each developer should generate their own lock file using their preferred package manager. After that, make sure to delete it from the .gitignore.
17+
18+
## Getting Started
19+
20+
1. Install dependencies using your preferred package manager:
21+
```bash
22+
# Using pnpm (recommended)
23+
pnpm install
24+
25+
# Using npm
26+
npm install
27+
28+
# Using yarn
29+
yarn install
30+
31+
# Using bun
32+
bun install
33+
```
34+
35+
> **Note:** Installing the package dependencies will also install the agent's python dependencies via the `install:agent` script.
36+
37+
2. Set up your OpenAI API key:
38+
```bash
39+
export OPENAI_API_KEY="your-openai-api-key-here"
40+
```
41+
42+
or create a `.env` file.
43+
44+
```bash
45+
echo "OPENAI_API_KEY=your-openai-api-key-here" > agent/.env
46+
```
47+
48+
3. Start the development server:
49+
```bash
50+
# Using pnpm
51+
pnpm dev
52+
53+
# Using npm
54+
npm run dev
55+
56+
# Using yarn
57+
yarn dev
58+
59+
# Using bun
60+
bun run dev
61+
```
62+
63+
This will start both the UI and agent servers concurrently.
64+
65+
## Available Scripts
66+
The following scripts can also be run using your preferred package manager:
67+
- `dev` - Starts both UI and agent servers in development mode
68+
- `dev:debug` - Starts development servers with debug logging enabled
69+
- `dev:ui` - Starts only the Next.js UI server
70+
- `dev:agent` - Starts only the strands agent server
71+
- `build` - Builds the Next.js application for production
72+
- `start` - Starts the production server
73+
- `lint` - Runs ESLint for code linting
74+
- `install:agent` - Installs Python dependencies for the agent
75+
76+
## 📚 Documentation
77+
78+
The main UI component is in `src/app/page.tsx`. You can:
79+
- Modify the theme colors and styling
80+
- Add new frontend actions
81+
- Customize the CopilotKit sidebar appearance
82+
83+
Otherwise, check out the documentation relevant to your task:
84+
85+
- [Strands Documentation](https://strandsagents.com/latest/documentation/docs/) - Learn more about Strands and its features
86+
- [CopilotKit Documentation](https://docs.copilotkit.ai) - Explore CopilotKit's capabilities
87+
- [Next.js Documentation](https://nextjs.org/docs) - Learn about Next.js features and API
88+
89+
## Contributing
90+
91+
Feel free to submit issues and enhancement requests! This starter is designed to be easily extensible.
92+
93+
## License
94+
95+
This project is licensed under the MIT License - see the LICENSE file for details.
96+
97+
## Troubleshooting
98+
99+
### Agent Connection Issues
100+
If you see "I'm having trouble connecting to my tools", make sure:
101+
1. The strands agent is running on port 8000
102+
2. Your OpenAI API key is set correctly
103+
3. Both servers started successfully
104+
105+
### Python Dependencies
106+
If you encounter Python import errors:
107+
```bash
108+
cd agent
109+
uv sync
110+
```

agent/main.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
"""Strands AG-UI Integration Example - Proverbs Agent.
2+
3+
This example demonstrates a Strands agent integrated with AG-UI, featuring:
4+
- Shared state management between agent and UI
5+
- Backend tool execution (get_weather, update_proverbs)
6+
- Frontend tools (set_theme_color)
7+
- Generative UI rendering
8+
"""
9+
10+
import json
11+
import os
12+
from typing import List
13+
14+
from ag_ui_strands import (
15+
StrandsAgent,
16+
StrandsAgentConfig,
17+
ToolBehavior,
18+
create_strands_app,
19+
)
20+
from dotenv import load_dotenv
21+
from pydantic import BaseModel, Field
22+
from strands import Agent, tool
23+
from strands.models.openai import OpenAIModel
24+
25+
load_dotenv()
26+
27+
28+
class ProverbsList(BaseModel):
29+
"""A list of proverbs."""
30+
31+
proverbs: List[str] = Field(description="The complete list of proverbs")
32+
33+
34+
@tool
35+
def get_weather(location: str):
36+
"""Get the weather for a location.
37+
38+
Args:
39+
location: The location to get weather for
40+
41+
Returns:
42+
Weather information as JSON string
43+
"""
44+
return json.dumps({"location": "70 degrees"})
45+
46+
47+
@tool
48+
def set_theme_color(theme_color: str):
49+
"""Change the theme color of the UI.
50+
51+
This is a frontend tool - it returns None as the actual
52+
execution happens on the frontend via useFrontendTool.
53+
54+
Args:
55+
theme_color: The color to set as theme
56+
"""
57+
return None
58+
59+
60+
@tool
61+
def update_proverbs(proverbs_list: ProverbsList):
62+
"""Update the complete list of proverbs.
63+
64+
IMPORTANT: Always provide the entire list, not just new proverbs.
65+
66+
Args:
67+
proverbs_list: The complete updated proverbs list
68+
69+
Returns:
70+
Success message
71+
"""
72+
return "Proverbs updated successfully"
73+
74+
75+
def build_proverbs_prompt(input_data, user_message: str) -> str:
76+
"""Inject the current proverbs state into the prompt."""
77+
state_dict = getattr(input_data, "state", None)
78+
if isinstance(state_dict, dict) and "proverbs" in state_dict:
79+
proverbs_json = json.dumps(state_dict["proverbs"], indent=2)
80+
return (
81+
f"Current proverbs list:\n{proverbs_json}\n\nUser request: {user_message}"
82+
)
83+
return user_message
84+
85+
86+
async def proverbs_state_from_args(context):
87+
"""Extract proverbs state from tool arguments.
88+
89+
This function is called when update_proverbs tool is executed
90+
to emit a state snapshot to the UI.
91+
92+
Args:
93+
context: ToolResultContext containing tool execution details
94+
95+
Returns:
96+
dict: State snapshot with proverbs array, or None on error
97+
"""
98+
try:
99+
tool_input = context.tool_input
100+
if isinstance(tool_input, str):
101+
tool_input = json.loads(tool_input)
102+
103+
proverbs_data = tool_input.get("proverbs_list", tool_input)
104+
105+
# Extract proverbs array
106+
if isinstance(proverbs_data, dict):
107+
proverbs_array = proverbs_data.get("proverbs", [])
108+
else:
109+
proverbs_array = []
110+
111+
return {"proverbs": proverbs_array}
112+
except Exception:
113+
return None
114+
115+
116+
# Configure agent behavior
117+
shared_state_config = StrandsAgentConfig(
118+
state_context_builder=build_proverbs_prompt,
119+
tool_behaviors={
120+
"update_proverbs": ToolBehavior(
121+
skip_messages_snapshot=True,
122+
state_from_args=proverbs_state_from_args,
123+
)
124+
},
125+
)
126+
127+
# Initialize OpenAI model
128+
api_key = os.getenv("OPENAI_API_KEY", "")
129+
model = OpenAIModel(
130+
client_args={"api_key": api_key},
131+
model_id="gpt-4o",
132+
)
133+
134+
system_prompt = (
135+
"You are a helpful and wise assistant that helps manage a collection of proverbs."
136+
)
137+
138+
# Create Strands agent with tools
139+
# Note: Frontend tools (set_theme_color, hitl_test) return None - actual execution happens in the UI
140+
strands_agent = Agent(
141+
model=model,
142+
system_prompt=system_prompt,
143+
tools=[update_proverbs, get_weather, set_theme_color],
144+
)
145+
146+
# Wrap with AG-UI integration
147+
agui_agent = StrandsAgent(
148+
agent=strands_agent,
149+
name="proverbs_agent",
150+
description="A proverbs assistant that collaborates with you to manage proverbs",
151+
config=shared_state_config,
152+
)
153+
154+
# Create the FastAPI app
155+
app = create_strands_app(agui_agent, "/")
156+
157+
if __name__ == "__main__":
158+
import uvicorn
159+
160+
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

agent/pyproject.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[project]
2+
name = "aws-strands-server"
3+
version = "0.1.0"
4+
description = "Strands integration server for AG-UI using OpenAI models"
5+
authors = [{ name = "AG-UI Contributors" }]
6+
readme = "README.md"
7+
requires-python = ">=3.12,<3.14"
8+
dependencies = [
9+
"ag-ui-protocol>=0.1.5",
10+
"fastapi>=0.115.12",
11+
"uvicorn>=0.34.3",
12+
"strands-agents[OpenAI]>=1.15.0",
13+
"strands-agents-tools>=0.2.14",
14+
"ag_ui_strands==0.1.0b12",
15+
]

0 commit comments

Comments
 (0)