Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
41 changes: 22 additions & 19 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## What This Is

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:
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:

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

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

## Commands

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

```sh
# Run the app (requires .env with OPENAI_API_KEY; Slack tokens optional with CLI)
# Run the app (requires .env with OPENAI_API_KEY or ANTHROPIC_API_KEY; Slack tokens optional with CLI)
slack run # via Slack CLI
python3 app.py # directly

Expand All @@ -32,13 +33,14 @@ pytest

```
.github/ # Shared CI workflows and dependabot config
pydantic-ai/ # Pydantic AI implementation
claude-agent-sdk/ # Claude Agent SDK implementation
openai-agents-sdk/ # OpenAI Agents SDK implementation
pydantic-ai/ # Pydantic AI implementation
```

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.
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.

## Architecture (shared across both implementations)
## Architecture (shared across all implementations)

Three-layer design: **app.py** → **listeners/** → **agent/**

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

## Key Differences Between Implementations

| Aspect | Pydantic AI | OpenAI Agents SDK |
|--------|-------------|-------------------|
| Agent file | `agent/casey.py` | `agent/support_agent.py` |
| Agent definition | `Agent(deps_type=CaseyDeps)` | `Agent[CaseyDeps](model="gpt-4o-mini")` |
| Model config | Passed at runtime via `run_sync(model=DEFAULT_MODEL)` | Set directly on agent constructor |
| Tool definition | Plain async functions | `@function_tool` decorated functions |
| Tool context param | `RunContext[CaseyDeps]` | `RunContextWrapper[CaseyDeps]` |
| Execution | `casey_agent.run_sync(text, model=..., deps=..., message_history=...)` | `Runner.run_sync(casey_agent, input=..., context=...)` |
| Result output | `result.output` | `result.final_output` |
| Result messages | `result.all_messages()` | `result.to_input_list()` |
| History type | `list[ModelMessage]` (framework-native) | `list` (generic, manually constructed) |
| Feedback blocks | Native `FeedbackButtonsElement` | Native `FeedbackButtonsElement` |
| Aspect | Claude Agent SDK | OpenAI Agents SDK | Pydantic AI |
|--------|-----------------|-------------------|-------------|
| Agent file | `agent/casey.py` | `agent/support_agent.py` | `agent/casey.py` |
| App type | `AsyncApp` (fully async) | `App` (sync) | `App` (sync) |
| Agent definition | `ClaudeSDKClient` with `ClaudeAgentOptions` | `Agent[CaseyDeps](model="gpt-4o-mini")` | `Agent(deps_type=CaseyDeps)` |
| Model config | Managed by SDK (Claude models) | Set directly on agent constructor | Passed at runtime via `run_sync(model=DEFAULT_MODEL)` |
| Tool definition | `@tool` decorated functions via MCP server | `@function_tool` decorated functions | Plain async functions |
| Tool context param | `args` dict (no context param) | `RunContextWrapper[CaseyDeps]` | `RunContext[CaseyDeps]` |
| Execution | `await run_casey_agent(text, session_id=...)` | `Runner.run_sync(casey_agent, input=..., context=...)` | `casey_agent.run_sync(text, model=..., deps=..., message_history=...)` |
| Result output | `response_text` from collected `TextBlock.text` | `result.final_output` | `result.output` |
| Conversation history | Session-based via `resume` (server-side) | `list` stored locally | `list[ModelMessage]` stored locally |
| API key env var | `ANTHROPIC_API_KEY` | `OPENAI_API_KEY` | `OPENAI_API_KEY` |
| Feedback blocks | Native `FeedbackButtonsElement` | Native `FeedbackButtonsElement` | Native `FeedbackButtonsElement` |
1 change: 1 addition & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ updates:
- "/"
- "/openai-agents-sdk"
- "/pydantic-ai"
- "/claude-agent-sdk"
schedule:
interval: "weekly"
labels:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ruff.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
directory:
- openai-agents-sdk
- pydantic-ai
- claude-agent-sdk
defaults:
run:
working-directory: ${{ matrix.directory }}
Expand Down
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ Built with [Bolt for Python](https://docs.slack.dev/tools/bolt-python/).

## Choose Your Framework

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

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

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.
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.

## What Casey Can Do

Expand Down
19 changes: 19 additions & 0 deletions claude-agent-sdk/.claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

See the root `../.claude/CLAUDE.md` for monorepo-wide architecture, commands, and a comparison of all implementations.

## Claude Agent SDK Specifics

**App (`app.py`)** uses `AsyncApp` from Bolt for Python. All listeners and Slack API calls are fully async (`await`).

**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)`.

**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()`.

**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)`.

**Feedback blocks** use the native `FeedbackButtonsElement` from `slack_sdk.models.blocks`. A single `feedback` action ID is registered.

**Dependencies** (`agent/deps.py`) use `AsyncWebClient` from `slack_sdk.web.async_client` instead of the sync `WebClient`.
9 changes: 9 additions & 0 deletions claude-agent-sdk/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Optional, uncomment and set when running without the Slack CLI (python3 app.py).
# SLACK_APP_TOKEN=YOUR_SLACK_APP_TOKEN
# SLACK_BOT_TOKEN=YOUR_SLACK_BOT_TOKEN

# Optional, uncomment and set when using a custom Slack instance.
# SLACK_API_URL=YOUR_SLACK_API_URL

# Required, set your Anthropic API key.
ANTHROPIC_API_KEY=YOUR_ANTHROPIC_API_KEY
43 changes: 43 additions & 0 deletions claude-agent-sdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# general things to ignore
build/
dist/
docs/_sources/
docs/.doctrees
.eggs/
*.egg-info/
*.egg
*.py[cod]
__pycache__/
*.so
*~

# virtualenv
env*/
venv/
.venv*
.env*
!.env.sample

# codecov / coverage
.coverage
cov_*
coverage.xml

# due to using tox and pytest
.tox
.cache
.pytest_cache/
.python-version
pip
.mypy_cache/

# misc
tmp.txt
.DS_Store
logs/
*.db
.pytype/
.idea/

# claude
.claude/*.local.json
2 changes: 2 additions & 0 deletions claude-agent-sdk/.slack/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
apps.dev.json
cache/
6 changes: 6 additions & 0 deletions claude-agent-sdk/.slack/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"manifest": {
"source": "local"
},
"project_id": "c189134c-231e-4c96-b800-ea39c055aa77"
}
5 changes: 5 additions & 0 deletions claude-agent-sdk/.slack/hooks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"hooks": {
"get-hooks": "python3 -m slack_cli_hooks.hooks.get_hooks"
}
}
Loading