-
Notifications
You must be signed in to change notification settings - Fork 0
refactor: restructure repo as monorepo with Pydantic AI and OpenAI Agents SDK #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
7d4937e
refactor: move all files into pydantic-ai subdirectory
mwbrooks 169de43
feat: add OpenAI Agents SDK sample app
mwbrooks d7fd85a
build: update ruff workflow for monorepo with matrix strategy
mwbrooks 5a989cf
feat(openai): update to 'Casey - OpenAI SDK'
mwbrooks ac0f00a
docs: add monorepo CLAUDE.md and update per-project docs
mwbrooks cec90c6
docs: add monorepo README
mwbrooks 0f92639
feat(openai): sync eyes reaction and feedback blocks with pydantic-ai
mwbrooks 6080d54
docs: remove agent style row from README table
mwbrooks f8126ce
Update .github/workflows/ruff.yml
mwbrooks 0bff937
chore: add .gitignore
mwbrooks File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,10 +4,17 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co | |
|
|
||
| ## What This Is | ||
|
|
||
| Casey is an AI-powered IT helpdesk agent for Slack, built with Bolt for Python and Pydantic AI. It uses simulated tools (knowledge base, ticket creation, password reset, system status, permissions lookup) to demonstrate an agentic IT support workflow. All tool data is hardcoded for demo purposes. | ||
| 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: | ||
|
|
||
| - `pydantic-ai/` — Built with **Pydantic AI** | ||
| - `openai-agents-sdk/` — Built with **OpenAI Agents SDK** | ||
|
|
||
| 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/`). | ||
|
|
||
| ```sh | ||
| # Run the app (requires .env with OPENAI_API_KEY; Slack tokens optional with CLI) | ||
| slack run # via Slack CLI | ||
|
|
@@ -21,28 +28,46 @@ ruff format --check . | |
| pytest | ||
| ``` | ||
|
|
||
| ## Architecture | ||
| ## Monorepo Structure | ||
|
|
||
| ``` | ||
| .github/ # Shared CI workflows and dependabot config | ||
| pydantic-ai/ # Pydantic AI implementation | ||
| openai-agents-sdk/ # OpenAI Agents 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. | ||
|
|
||
| ## Architecture (shared across both implementations) | ||
|
|
||
| Three-layer design: **app.py** → **listeners/** → **agent/** | ||
|
|
||
| **Entry point (`app.py`)** initializes Bolt with Socket Mode and calls `register_listeners(app)`. | ||
|
|
||
| **Listeners** are organized by Slack platform feature: | ||
| - `listeners/events/` — `app_home_opened`, `app_mentioned`, `message_im` | ||
| - `listeners/actions/` — `category_buttons` (regex `^category_`), `feedback_good`, `feedback_bad` | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ⭐ praise: Feedback good! |
||
| - `listeners/actions/` — `category_buttons` (regex `^category_`), feedback handlers | ||
| - `listeners/views/` — `issue_submission` modal handler | ||
|
|
||
| Each sub-package has a `register(app)` function called from `listeners/__init__.py`. | ||
|
|
||
| **Agent (`agent/casey.py`)** is a Pydantic AI `Agent` with `deps_type=CaseyDeps`. The model is **not** set on the agent (to avoid import-time OpenAI client creation); instead `DEFAULT_MODEL` (`openai:gpt-4o-mini`) is passed at each `run_sync()` call site. Tools are passed via the `tools=[]` constructor parameter (not decorators) so each tool lives in its own file under `agent/tools/`. | ||
| **CaseyDeps** (`agent/deps.py`) is a dataclass carrying `client`, `user_id`, `channel_id`, `thread_ts`. Constructed in each listener handler and passed to the agent at runtime. | ||
|
|
||
| **CaseyDeps** (`agent/deps.py`) is a dataclass carrying `client`, `user_id`, `channel_id`, `thread_ts`. It's constructed in each listener handler and passed as `deps=` to `run_sync()`. | ||
| **Conversation history** (`conversation/store.py`) is a thread-safe in-memory dict keyed by `(channel_id, thread_ts)` with TTL-based cleanup. This enables multi-turn context. | ||
|
|
||
| **Conversation history** (`conversation/store.py`) is an in-memory dict keyed by `(channel_id, thread_ts)` storing `list[ModelMessage]` from Pydantic AI. This is what enables multi-turn context. The singleton `conversation_store` is imported from `conversation/`. | ||
| **Handler flow** (DM, mention, modal submit): add `:eyes:` reaction → get history from store → run agent → post response in thread with feedback blocks → store updated messages. | ||
|
|
||
| ## Key Patterns | ||
| ## Key Differences Between Implementations | ||
|
|
||
| - All three message handlers (DM, mention, modal submit) follow the same flow: add :eyes: reaction → get history from store → `casey_agent.run_sync(text, model=DEFAULT_MODEL, deps=deps, message_history=history)` → post `result.output` in thread with feedback blocks → store `result.all_messages()`. | ||
| - Emoji/reaction logic is in the handlers, not the agent. Resolution detection checks `result.output` against a hardcoded phrase list. | ||
| - View builders (`app_home_builder.py`, `modal_builder.py`, `feedback_block.py`) return raw dicts or Block Kit objects, not views themselves. The handlers call `client.views_publish()` or `client.views_open()`. | ||
| - The `message_im` handler filters out bot messages (`event.bot_id`) and subtypes to avoid self-reply loops. | ||
| | 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` | | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,16 @@ | ||
| version: 2 | ||
| updates: | ||
| - package-ecosystem: "pip" | ||
| directory: "/" | ||
| directories: | ||
| - "/" | ||
| - "/openai-agents-sdk" | ||
| - "/pydantic-ai" | ||
| schedule: | ||
| interval: "monthly" | ||
| interval: "weekly" | ||
| labels: | ||
| - "pip" | ||
| - "dependencies" | ||
| - package-ecosystem: "github-actions" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "monthly" | ||
| interval: "weekly" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,43 +1,2 @@ | ||
| # 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 | ||
| .claude/*.local.json |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👾