Skip to content

Commit 36b6c1c

Browse files
committed
feat: add Claude Agent SDK implementation
Add a third parallel Casey implementation using the Claude Agent SDK with AsyncApp. Tools are registered via @tool decorator and create_sdk_mcp_server(). Conversation context is managed server-side via session IDs instead of local message history storage. Updates root README, CLAUDE.md, CI matrix, and dependabot config.
1 parent 371f721 commit 36b6c1c

40 files changed

Lines changed: 1588 additions & 22 deletions

.claude/CLAUDE.md

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,20 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## What This Is
66

7-
A monorepo containing two parallel implementations of **Casey**, an AI-powered IT helpdesk agent for Slack built with Bolt for Python. Both implementations are functionally identical from the Slack user's perspective but use different AI agent frameworks:
7+
A monorepo containing three parallel implementations of **Casey**, an AI-powered IT helpdesk agent for Slack built with Bolt for Python. All implementations are functionally identical from the Slack user's perspective but use different AI agent frameworks:
88

99
- `pydantic-ai/` — Built with **Pydantic AI**
1010
- `openai-agents-sdk/` — Built with **OpenAI Agents SDK**
11+
- `claude-agent-sdk/` — Built with **Claude Agent SDK**
1112

1213
All tool data (knowledge base, tickets, password resets, system status, permissions) is hardcoded for demo purposes.
1314

1415
## Commands
1516

16-
All commands must be run from within the respective project directory (`pydantic-ai/` or `openai-agents-sdk/`).
17+
All commands must be run from within the respective project directory (`pydantic-ai/`, `openai-agents-sdk/`, or `claude-agent-sdk/`).
1718

1819
```sh
19-
# Run the app (requires .env with OPENAI_API_KEY; Slack tokens optional with CLI)
20+
# Run the app (requires .env with OPENAI_API_KEY or ANTHROPIC_API_KEY; Slack tokens optional with CLI)
2021
slack run # via Slack CLI
2122
python3 app.py # directly
2223

@@ -34,9 +35,10 @@ pytest
3435
.github/ # Shared CI workflows and dependabot config
3536
pydantic-ai/ # Pydantic AI implementation
3637
openai-agents-sdk/ # OpenAI Agents SDK implementation
38+
claude-agent-sdk/ # Claude Agent SDK implementation
3739
```
3840

39-
CI runs ruff lint/format checks against both directories via a matrix strategy in `.github/workflows/ruff.yml`. Dependabot monitors `requirements.txt` in both directories independently.
41+
CI runs ruff lint/format checks against all directories via a matrix strategy in `.github/workflows/ruff.yml`. Dependabot monitors `requirements.txt` in all directories independently.
4042

4143
## Architecture (shared across both implementations)
4244

@@ -59,15 +61,16 @@ Each sub-package has a `register(app)` function called from `listeners/__init__.
5961

6062
## Key Differences Between Implementations
6163

62-
| Aspect | Pydantic AI | OpenAI Agents SDK |
63-
|--------|-------------|-------------------|
64-
| Agent file | `agent/casey.py` | `agent/support_agent.py` |
65-
| Agent definition | `Agent(deps_type=CaseyDeps)` | `Agent[CaseyDeps](model="gpt-4o-mini")` |
66-
| Model config | Passed at runtime via `run_sync(model=DEFAULT_MODEL)` | Set directly on agent constructor |
67-
| Tool definition | Plain async functions | `@function_tool` decorated functions |
68-
| Tool context param | `RunContext[CaseyDeps]` | `RunContextWrapper[CaseyDeps]` |
69-
| Execution | `casey_agent.run_sync(text, model=..., deps=..., message_history=...)` | `Runner.run_sync(casey_agent, input=..., context=...)` |
70-
| Result output | `result.output` | `result.final_output` |
71-
| Result messages | `result.all_messages()` | `result.to_input_list()` |
72-
| History type | `list[ModelMessage]` (framework-native) | `list` (generic, manually constructed) |
73-
| Feedback blocks | Native `FeedbackButtonsElement` | Native `FeedbackButtonsElement` |
64+
| Aspect | Pydantic AI | OpenAI Agents SDK | Claude Agent SDK |
65+
|--------|-------------|-------------------|-----------------|
66+
| Agent file | `agent/casey.py` | `agent/support_agent.py` | `agent/casey.py` |
67+
| App type | `App` (sync) | `App` (sync) | `AsyncApp` (fully async) |
68+
| Agent definition | `Agent(deps_type=CaseyDeps)` | `Agent[CaseyDeps](model="gpt-4o-mini")` | `ClaudeSDKClient` with `ClaudeAgentOptions` |
69+
| Model config | Passed at runtime via `run_sync(model=DEFAULT_MODEL)` | Set directly on agent constructor | Managed by SDK (Claude models) |
70+
| Tool definition | Plain async functions | `@function_tool` decorated functions | `@tool` decorated functions via MCP server |
71+
| Tool context param | `RunContext[CaseyDeps]` | `RunContextWrapper[CaseyDeps]` | `args` dict (no context param) |
72+
| Execution | `casey_agent.run_sync(text, model=..., deps=..., message_history=...)` | `Runner.run_sync(casey_agent, input=..., context=...)` | `await run_casey_agent(text, session_id=...)` |
73+
| Result output | `result.output` | `result.final_output` | `response_text` from collected `TextBlock.text` |
74+
| Conversation history | `list[ModelMessage]` stored locally | `list` stored locally | Session-based via `resume` (server-side) |
75+
| API key env var | `OPENAI_API_KEY` | `OPENAI_API_KEY` | `ANTHROPIC_API_KEY` |
76+
| Feedback blocks | Native `FeedbackButtonsElement` | Native `FeedbackButtonsElement` | Native `FeedbackButtonsElement` |

.github/dependabot.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ updates:
55
- "/"
66
- "/openai-agents-sdk"
77
- "/pydantic-ai"
8+
- "/claude-agent-sdk"
89
schedule:
910
interval: "weekly"
1011
labels:

.github/workflows/ruff.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ jobs:
1414
directory:
1515
- openai-agents-sdk
1616
- pydantic-ai
17+
- claude-agent-sdk
1718
defaults:
1819
run:
1920
working-directory: ${{ matrix.directory }}

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ Built with [Bolt for Python](https://docs.slack.dev/tools/bolt-python/).
66

77
## Choose Your Framework
88

9-
This repo contains the same app built with two different AI agent frameworks. Pick the one that fits your stack:
9+
This repo contains the same app built with three different AI agent frameworks. Pick the one that fits your stack:
1010

11-
| | [Pydantic AI](./pydantic-ai/) | [OpenAI Agents SDK](./openai-agents-sdk/) |
12-
|---|---|---|
13-
| **Framework** | [pydantic-ai](https://ai.pydantic.dev/) | [openai-agents](https://openai.github.io/openai-agents-python/) |
14-
| **Get started** | [View README](./pydantic-ai/README.md) | [View README](./openai-agents-sdk/README.md) |
11+
| | [Pydantic AI](./pydantic-ai/) | [OpenAI Agents SDK](./openai-agents-sdk/) | [Claude Agent SDK](./claude-agent-sdk/) |
12+
|---|---|---|---|
13+
| **Framework** | [pydantic-ai](https://ai.pydantic.dev/) | [openai-agents](https://openai.github.io/openai-agents-python/) | [claude-agent-sdk](https://docs.anthropic.com/en/docs/agents/claude-agent-sdk) |
14+
| **Get started** | [View README](./pydantic-ai/README.md) | [View README](./openai-agents-sdk/README.md) | [View README](./claude-agent-sdk/README.md) |
1515

16-
Both implementations share the same Slack listener layer, the same five simulated IT tools, and the same user experience. The only difference is how the agent is defined and executed under the hood.
16+
All implementations share the same Slack listener layer, the same five simulated IT tools, and the same user experience. The only difference is how the agent is defined and executed under the hood.
1717

1818
## What Casey Can Do
1919

claude-agent-sdk/.claude/CLAUDE.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
See the root `../.claude/CLAUDE.md` for monorepo-wide architecture, commands, and a comparison of all implementations.
6+
7+
## Claude Agent SDK Specifics
8+
9+
**App (`app.py`)** uses `AsyncApp` from Bolt for Python. All listeners and Slack API calls are fully async (`await`).
10+
11+
**Agent (`agent/casey.py`)** uses `ClaudeSDKClient` from the Claude Agent SDK. Tools are registered via `create_sdk_mcp_server()` and passed as `mcp_servers` in `ClaudeAgentOptions`. The `run_casey_agent()` function is async and returns `(response_text, session_id)`.
12+
13+
**Tools (`agent/tools/`)** are defined with the `@tool` decorator from `claude_agent_sdk`. Each tool returns `{"content": [{"type": "text", "text": ...}]}`. Tools are registered into a single MCP server via `create_sdk_mcp_server()`.
14+
15+
**Conversation history** is managed server-side by the Claude Agent SDK via sessions. The local `SessionStore` (`conversation/store.py`) only maps `(channel_id, thread_ts)` to session IDs. Sessions are resumed via `ClaudeAgentOptions(resume=session_id)`.
16+
17+
**Feedback blocks** use the native `FeedbackButtonsElement` from `slack_sdk.models.blocks`. A single `feedback` action ID is registered.
18+
19+
**Dependencies** (`agent/deps.py`) use `AsyncWebClient` from `slack_sdk.web.async_client` instead of the sync `WebClient`.

claude-agent-sdk/.env.sample

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Optional, uncomment and set when running without the Slack CLI (python3 app.py).
2+
# SLACK_APP_TOKEN=YOUR_SLACK_APP_TOKEN
3+
# SLACK_BOT_TOKEN=YOUR_SLACK_BOT_TOKEN
4+
5+
# Optional, uncomment and set when using a custom Slack instance.
6+
# SLACK_API_URL=YOUR_SLACK_API_URL
7+
8+
# Required, set your Anthropic API key.
9+
ANTHROPIC_API_KEY=YOUR_ANTHROPIC_API_KEY

claude-agent-sdk/.gitignore

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# general things to ignore
2+
build/
3+
dist/
4+
docs/_sources/
5+
docs/.doctrees
6+
.eggs/
7+
*.egg-info/
8+
*.egg
9+
*.py[cod]
10+
__pycache__/
11+
*.so
12+
*~
13+
14+
# virtualenv
15+
env*/
16+
venv/
17+
.venv*
18+
.env*
19+
!.env.sample
20+
21+
# codecov / coverage
22+
.coverage
23+
cov_*
24+
coverage.xml
25+
26+
# due to using tox and pytest
27+
.tox
28+
.cache
29+
.pytest_cache/
30+
.python-version
31+
pip
32+
.mypy_cache/
33+
34+
# misc
35+
tmp.txt
36+
.DS_Store
37+
logs/
38+
*.db
39+
.pytype/
40+
.idea/
41+
42+
# claude
43+
.claude/*.local.json

claude-agent-sdk/.slack/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
apps.dev.json
2+
cache/
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"manifest": {
3+
"source": "local"
4+
},
5+
"project_id": "c189134c-231e-4c96-b800-ea39c055aa77"
6+
}

claude-agent-sdk/.slack/hooks.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"hooks": {
3+
"get-hooks": "python3 -m slack_cli_hooks.hooks.get_hooks"
4+
}
5+
}

0 commit comments

Comments
 (0)