Skip to content

Commit 5431a77

Browse files
committed
feat: migrate from openai to google adk multi-agent system
- Implemented hierarchical multi-agent architecture using Google ADK - Created CoordinatorAgent, MathAgent, TextAgent, and InfoAgent - Added specialized tools for each agent type - Updated streaming response handling for ADK integration - Added comprehensive documentation and migration guide
1 parent efd12d6 commit 5431a77

11 files changed

Lines changed: 1779 additions & 58 deletions

File tree

.vscode/.gitignore

Whitespace-only changes.

.vscode/settings.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"files.exclude": {
3+
"**/.git": true,
4+
"**/.svn": true,
5+
"**/.hg": true,
6+
"**/.DS_Store": true,
7+
"**/Thumbs.db": true,
8+
"**/.classpath": true,
9+
"**/.project": true,
10+
"**/.settings": true,
11+
"**/.factorypath": true
12+
},
13+
"hide-files.files": []
14+
}

CLAUDE.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Overview
6+
7+
This is a Slack AI Agent App built with Bolt for Python, implementing a multi-agent system using Google ADK (Agent Development Kit) with Gemini models. The app provides AI-powered assistance through Slack's Assistant interface with streaming responses.
8+
9+
## Development Commands
10+
11+
### Environment Setup
12+
13+
```sh
14+
# Create and activate virtual environment
15+
python3 -m venv .venv
16+
source .venv/bin/activate # Windows: .\.venv\Scripts\Activate
17+
18+
# Install dependencies
19+
pip install -r requirements.txt
20+
```
21+
22+
### Running the App
23+
24+
```sh
25+
# Using Slack CLI (recommended)
26+
slack run
27+
28+
# Or directly with Python
29+
python3 app.py
30+
```
31+
32+
### Code Quality
33+
34+
```sh
35+
# Lint code
36+
ruff check
37+
38+
# Format code
39+
ruff format
40+
```
41+
42+
### Testing
43+
44+
```sh
45+
# Run all tests
46+
pytest
47+
48+
# Run specific test file
49+
pytest tests/test_file.py
50+
51+
# Run with verbose output
52+
pytest -v
53+
```
54+
55+
## Architecture
56+
57+
### Multi-Agent System
58+
59+
The application uses Google ADK to implement a hierarchical multi-agent architecture:
60+
61+
- **CoordinatorAgent** (`ai/agents.py:55-78`): Root agent that analyzes user requests and delegates to specialized agents
62+
- **MathAgent** (`ai/agents.py:20-28`): Handles mathematical calculations and numerical operations
63+
- **TextAgent** (`ai/agents.py:31-40`): Processes text formatting, word counting, and list creation
64+
- **InfoAgent** (`ai/agents.py:43-52`): Provides current time, help information, and general queries
65+
66+
Each agent uses the `gemini-2.0-flash` model and has access to specific tools defined in `ai/tools.py`.
67+
68+
### Request Flow
69+
70+
1. **Entry Point** (`app.py`): Thin entry point that initializes the Bolt app and registers listeners
71+
2. **Listener Registration** (`listeners/__init__.py`): Routes incoming Slack events to appropriate handlers
72+
3. **Event Handlers**:
73+
- `listeners/assistant/message.py`: Handles messages in assistant threads
74+
- `listeners/events/app_mentioned.py`: Handles @mentions of the bot
75+
- `listeners/assistant/assistant_thread_started.py`: Sets up suggested prompts when threads start
76+
4. **LLM Integration** (`ai/llm_caller.py`): Provides `call_llm()` async generator that streams responses from the ADK agent system
77+
5. **Response Streaming**: Uses Slack's `chat_stream` API to stream chunks back to the user in real-time
78+
79+
### Key Design Patterns
80+
81+
- **Async Streaming**: All LLM responses are streamed using async generators to provide real-time feedback
82+
- **Event Loop Management**: Creates new event loops in synchronous Bolt handlers to call async ADK functions
83+
- **Session Management**: Uses thread timestamps as session IDs to maintain conversation context
84+
- **Tool-Based Architecture**: Agents use Python functions as tools, automatically exposed to the LLM by ADK
85+
86+
## Configuration
87+
88+
### Required Environment Variables
89+
90+
```sh
91+
SLACK_BOT_TOKEN=xoxb-... # From OAuth & Permissions
92+
SLACK_APP_TOKEN=xapp-... # App-level token with connections:write
93+
```
94+
95+
### Google ADK Authentication (one of):
96+
97+
```sh
98+
# Option 1: Service account (production)
99+
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-key.json
100+
101+
# Option 2: API key (development)
102+
GOOGLE_API_KEY=your-api-key
103+
104+
# Option 3: Use `gcloud auth application-default login`
105+
```
106+
107+
## Adding New Agents
108+
109+
To add a new specialized agent:
110+
111+
1. Create tools in `ai/tools.py` following the existing pattern (functions returning `Dict[str, Any]`)
112+
2. Define the agent in `ai/agents.py`:
113+
```python
114+
new_agent = Agent(
115+
name="AgentName",
116+
model="gemini-2.0-flash",
117+
description="When to use this agent",
118+
instruction="Detailed instructions for the agent",
119+
tools=[tool1, tool2],
120+
)
121+
```
122+
3. Add the agent to `coordinator_agent.sub_agents` list
123+
4. Update the coordinator's instruction to explain when to delegate to the new agent
124+
125+
## Slack-Specific Conventions
126+
127+
- **Markdown Compatibility**: Agents are instructed to convert markdown to Slack-compatible format
128+
- **Slack Syntax Preservation**: User mentions (`<@USER_ID>`) and channel mentions (`<#CHANNEL_ID>`) must be preserved as-is in responses
129+
- **Status Messages**: Use playful loading messages during "thinking" state (see `listeners/assistant/message.py:40-46`)
130+
- **Feedback Blocks**: Responses include feedback blocks for user interaction (`listeners/views/feedback_block.py`)
131+
132+
## Project Structure Notes
133+
134+
- `/listeners`: Organized by Slack Platform feature (events, assistant, actions, views)
135+
- `/ai`: Contains all LLM and agent-related code, separated from Slack-specific logic
136+
- Socket Mode is used for local development (no public URL required)
137+
- For OAuth/distribution, use `app_oauth.py` instead of `app.py`

ai/agents.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""
2+
Multi-agent system using Google ADK.
3+
4+
This module defines a multi-agent system with specialized agents for different tasks.
5+
"""
6+
7+
from google.adk.agents import Agent
8+
from google.adk.models.lite_llm import LiteLlm
9+
10+
from .tools import (
11+
get_current_time,
12+
calculate,
13+
format_text,
14+
count_words,
15+
create_list,
16+
get_help_info,
17+
)
18+
19+
# Configure OpenAI model via LiteLLM
20+
# Requires OPENAI_API_KEY environment variable
21+
openai_model = LiteLlm(model="openai/gpt-4o")
22+
23+
24+
# Specialized agent for mathematical operations
25+
math_agent = Agent(
26+
name="MathAgent",
27+
model=openai_model,
28+
description="Specializes in mathematical calculations and numerical operations. Use this agent for any math-related queries.",
29+
instruction="""You are a mathematical expert. You can perform calculations, solve equations,
30+
and help with numerical problems. Use the calculate tool to evaluate mathematical expressions.
31+
Always explain your calculations clearly.""",
32+
tools=[calculate],
33+
)
34+
35+
# Specialized agent for text processing
36+
text_agent = Agent(
37+
name="TextAgent",
38+
model=openai_model,
39+
description="Specializes in text processing, formatting, and analysis. Use this agent for text manipulation tasks.",
40+
instruction="""You are a text processing expert. You can format text, count words,
41+
create lists, and analyze text content. Use the available tools to help users with text-related tasks.
42+
When you include markdown text, convert them to Slack compatible ones.
43+
When a prompt has Slack's special syntax like <@USER_ID> or <#CHANNEL_ID>, you must keep them as-is in your response.""",
44+
tools=[format_text, count_words, create_list],
45+
)
46+
47+
# Specialized agent for information and utilities
48+
info_agent = Agent(
49+
name="InfoAgent",
50+
model=openai_model,
51+
description="Provides general information, current time, and help about available capabilities.",
52+
instruction="""You are an information assistant. You can provide the current time,
53+
help users understand what tools are available, and answer general questions.
54+
When you include markdown text, convert them to Slack compatible ones.
55+
When a prompt has Slack's special syntax like <@USER_ID> or <#CHANNEL_ID>, you must keep them as-is in your response.""",
56+
tools=[get_current_time, get_help_info],
57+
)
58+
59+
# Coordinator agent that routes requests to specialized agents
60+
coordinator_agent = Agent(
61+
name="CoordinatorAgent",
62+
model=openai_model,
63+
description="Main coordinator that routes user requests to specialized agents.",
64+
instruction="""You are a helpful assistant coordinator in a Slack workspace.
65+
Users in the workspace will ask you to help them with various tasks.
66+
67+
You have access to specialized agents:
68+
- MathAgent: For mathematical calculations and numerical operations
69+
- TextAgent: For text processing, formatting, and analysis
70+
- InfoAgent: For general information, current time, and help
71+
72+
Analyze the user's request and delegate to the appropriate specialized agent:
73+
- For math problems, calculations, or numerical queries -> use MathAgent
74+
- For text formatting, word counting, or list creation -> use TextAgent
75+
- For time queries, help requests, or general information -> use InfoAgent
76+
- For general conversation or questions that don't fit the above -> answer directly
77+
78+
When you include markdown text, convert them to Slack compatible ones.
79+
When a prompt has Slack's special syntax like <@USER_ID> or <#CHANNEL_ID>, you must keep them as-is in your response.
80+
81+
Always be professional, helpful, and friendly in your responses.""",
82+
sub_agents=[math_agent, text_agent, info_agent],
83+
)
84+
85+
86+
def get_root_agent() -> Agent:
87+
"""
88+
Get the root coordinator agent for the multi-agent system.
89+
90+
Returns:
91+
Agent: The coordinator agent that routes requests to specialized agents.
92+
"""
93+
return coordinator_agent

0 commit comments

Comments
 (0)