Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
35 changes: 19 additions & 16 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**
- `openai-agents-sdk/` — Built with **OpenAI Agents SDK**
- `claude-agent-sdk/` — Built with **Claude Agent SDK**
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧮 quibble: For @claude - Can you add alphabetical orderings to CLAUDE.md please?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zimeg good catch! Commit 51998f1 updates the ordering :)


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 (`pydantic-ai/`, `openai-agents-sdk/`, or `claude-agent-sdk/`).

```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 @@ -34,9 +35,10 @@ pytest
.github/ # Shared CI workflows and dependabot config
pydantic-ai/ # Pydantic AI implementation
openai-agents-sdk/ # OpenAI Agents SDK implementation
claude-agent-sdk/ # Claude Agent SDK 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)

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 | Pydantic AI | OpenAI Agents SDK | Claude Agent SDK |
|--------|-------------|-------------------|-----------------|
| Agent file | `agent/casey.py` | `agent/support_agent.py` | `agent/casey.py` |
| App type | `App` (sync) | `App` (sync) | `AsyncApp` (fully async) |
| Agent definition | `Agent(deps_type=CaseyDeps)` | `Agent[CaseyDeps](model="gpt-4o-mini")` | `ClaudeSDKClient` with `ClaudeAgentOptions` |
| Model config | Passed at runtime via `run_sync(model=DEFAULT_MODEL)` | Set directly on agent constructor | Managed by SDK (Claude models) |
| Tool definition | Plain async functions | `@function_tool` decorated functions | `@tool` decorated functions via MCP server |
| Tool context param | `RunContext[CaseyDeps]` | `RunContextWrapper[CaseyDeps]` | `args` dict (no context param) |
| Execution | `casey_agent.run_sync(text, model=..., deps=..., message_history=...)` | `Runner.run_sync(casey_agent, input=..., context=...)` | `await run_casey_agent(text, session_id=...)` |
| Result output | `result.output` | `result.final_output` | `response_text` from collected `TextBlock.text` |
| Conversation history | `list[ModelMessage]` stored locally | `list` stored locally | Session-based via `resume` (server-side) |
| API key env var | `OPENAI_API_KEY` | `OPENAI_API_KEY` | `ANTHROPIC_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
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ 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) |
| | [Pydantic AI](./pydantic-ai/) | [OpenAI Agents SDK](./openai-agents-sdk/) | [Claude Agent SDK](./claude-agent-sdk/) |
|---|---|---|---|
| **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) |
| **Get started** | [View README](./pydantic-ai/README.md) | [View README](./openai-agents-sdk/README.md) | [View README](./claude-agent-sdk/README.md) |

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