Skip to content

feature: add OpenAI ChatKit UI integration#478

Open
bonk1t wants to merge 2 commits intomainfrom
feat/chatkit-integration
Open

feature: add OpenAI ChatKit UI integration#478
bonk1t wants to merge 2 commits intomainfrom
feat/chatkit-integration

Conversation

@bonk1t
Copy link
Collaborator

@bonk1t bonk1t commented Dec 10, 2025

  • Add ChatkitAdapter for converting OpenAI Agents SDK events to ChatKit ThreadStreamEvent format
  • Add /chatkit FastAPI endpoint via enable_chatkit=True in run_fastapi()
  • Add agency.chatkit_demo() method mirroring copilot_demo() pattern
  • Ship bundled React frontend (Vite + @openai/chatkit-react) for demo
  • Integrate conversation persistence
  • Add unit tests for ChatkitAdapter, integration tests for endpoint
  • Update FastAPI integration docs with ChatKit section and architecture diagram
Screenshot 2025-12-10 at 02 39 53 Screenshot 2025-12-10 at 02 43 56

Note

Medium Risk
Adds a new public FastAPI endpoint and SSE streaming translation layer, which could impact API surface and streaming correctness, but is gated behind enable_chatkit and covered by new tests.

Overview
Adds first-class OpenAI ChatKit support: run_fastapi(..., enable_chatkit=True) now exposes a POST /{agency_name}/chatkit endpoint that streams ChatKit-compatible SSE events.

Introduces a ChatkitAdapter to translate Agents SDK streaming events (assistant text deltas and tool calls/outputs) into ChatKit ThreadStreamEvent objects, plus a chatkit_demo() launcher on Agency that starts FastAPI + a bundled Vite/React ChatKit frontend.

Updates docs/navigation to document the new integration and demo, expands packaging config to ship the new frontend assets, and adds unit + integration tests covering adapter conversions and endpoint behavior.

Written by Cursor Bugbot for commit 255e09a. This will update automatically on new commits. Configure here.

- Add ChatkitAdapter for converting OpenAI Agents SDK events to ChatKit ThreadStreamEvent format
- Add /chatkit FastAPI endpoint via enable_chatkit=True in run_fastapi()
- Add agency.chatkit_demo() method mirroring copilot_demo() pattern
- Ship bundled React frontend (Vite + @openai/chatkit-react) for demo
- Implement in-memory thread storage for multi-turn conversation persistence
- Add 36 unit tests for ChatkitAdapter, 5 integration tests for endpoint
- Update FastAPI integration docs with ChatKit section and architecture diagram
@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

- Add ChatKit web component CDN script to index.html (required for web component to initialize)
- Simplify chatkit_handlers.py to stateless design (users handle persistence via hooks_override)
- Create dedicated chatkit-integration.mdx docs page
- Move ChatKit content from fastapi-integration.mdx to new page
Copy link
Collaborator

@ArtemShatokhin ArtemShatokhin left a comment

Choose a reason for hiding this comment

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

Along with the bug below, here's a list of bugs found during QA:

  1. Selecting chat from history leads this error:
Failed to load conversation.
We encountered an error. Reload to try again.
  1. Chats are not isolated. In new chats agents still retain memory from previous ones.

  2. Chat hangs after agent uses send_message or handoff tool.

  3. Tool calls are not shown

"""Create a thread.item.done event to finalize an item."""
return {
"type": "thread.item.done",
"item_id": item_id,
Copy link
Collaborator

Choose a reason for hiding this comment

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

item: dict[str, Any] = {
"id": item_id,
"type": item_type,
"created_at": int(time.time()),
Copy link
Collaborator

Choose a reason for hiding this comment

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

@github-actions
Copy link
Contributor

This PR is stale because it has been open for 10 days with no activity.

@github-actions github-actions bot added the stale label Dec 24, 2025
@bonk1t
Copy link
Collaborator Author

bonk1t commented Dec 27, 2025

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +123 to +127
)

agency = agency_factory()
await attach_persistent_mcp_servers(agency)

Choose a reason for hiding this comment

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

P1 Badge ChatKit endpoint drops thread history

The new ChatKit FastAPI handler builds a thread_id for each request but then creates the agency via agency_factory() without supplying the usual load_threads_callback/save_threads_callback, so the thread state is never loaded or persisted. Follow‑up ChatKit calls such as threads.add_user_message therefore start with an empty conversation regardless of the thread_id, breaking multi‑turn continuity and persistence compared to the existing AG‑UI endpoints that pass the callbacks. This affects any ChatKit client sending multiple messages in the same thread.

Useful? React with 👍 / 👎.

Comment on lines +2 to +6
Agency Swarm ChatKit Demo

This example demonstrates the ChatKit UI capabilities of Agency Swarm v1.x.
Sets up a frontend and backend server for the OpenAI ChatKit UI chat demo.
"""

Choose a reason for hiding this comment

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

P1 Badge ChatKit demo script is syntactically invalid

The new examples/interactive/chatkit_demo.py lacks an opening triple‑quote before the intended module docstring, leaving bare words (Agency Swarm ChatKit Demo) at the top level. Importing or running the demo raises a SyntaxError before any code executes, so the documented ChatKit demo cannot be launched.

Useful? React with 👍 / 👎.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +103 to +126
thread_id = params.get("thread_id") or str(uuid.uuid4())
run_id = str(uuid.uuid4())
is_new_thread = req_type == "threads.create"

# Extract user message
user_message = ""
user_input = params.get("input", {})
if user_input:
content_list = user_input.get("content", [])
for part in content_list:
if isinstance(part, dict):
if part.get("type") == "input_text":
user_message += part.get("text", "")
elif "text" in part:
user_message += part.get("text", "")

if not user_message:
return Response(
content=json.dumps({"thread_id": thread_id, "status": "no_input"}),
media_type="application/json",
)

agency = agency_factory()
await attach_persistent_mcp_servers(agency)

Choose a reason for hiding this comment

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

P2 Badge Load prior messages for ChatKit thread requests

ChatKit requests send a thread_id, but the handler always builds a fresh agency without passing any load_threads_callback or previously saved messages, so the thread manager starts empty on every call. This makes multi-turn ChatKit sessions stateless: sending threads.add_user_message or reloading a thread will ignore earlier conversation state even if persistence callbacks are configured. Consider loading history (e.g., via ChatkitAdapter.chatkit_messages_to_chat_history or the agency’s persistence hooks) before streaming the response.

Useful? React with 👍 / 👎.

@github-actions github-actions bot removed the stale label Dec 28, 2025
@github-actions github-actions bot added the stale label Jan 8, 2026
@github-actions github-actions bot closed this Jan 16, 2026
@bonk1t bonk1t reopened this Jan 16, 2026
@github-actions github-actions bot removed the stale label Jan 17, 2026
@github-actions github-actions bot added the stale label Jan 27, 2026
@github-actions github-actions bot closed this Feb 3, 2026
@bonk1t bonk1t reopened this Feb 5, 2026
Repository owner deleted a comment from github-actions bot Feb 5, 2026
Repository owner deleted a comment from github-actions bot Feb 5, 2026
Repository owner deleted a comment from github-actions bot Feb 5, 2026
Repository owner deleted a comment from github-actions bot Feb 5, 2026
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 4 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

return {
"type": "thread.item.done",
"item_id": item_id,
}
Copy link

Choose a reason for hiding this comment

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

Done event uses wrong field name item_id

High Severity

The _create_item_done_event method returns {"type": "thread.item.done", "item_id": item_id} but the ChatKit API expects {"type": "thread.item.done", "item": {...}} with the full item object. The handler in chatkit_handlers.py line 144 correctly uses "item": user_item, but this adapter method uses the wrong field name. This was also flagged in the PR discussion by @ArtemShatokhin.

Fix in Cursor Fix in Web

return {
"type": "thread.item.added",
"item": item,
}
Copy link

Choose a reason for hiding this comment

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

Items missing required thread_id field

Medium Severity

The _create_item_added_event method creates items without including thread_id, though the ChatKit API types (ThreadItemBase, AssistantMessageItem) expect items to include this field. The thread_id parameter is available in openai_to_chatkit_events but isn't passed down to item creation methods. The handler correctly includes thread_id in user items (line 139), but assistant message and tool call items created by the adapter lack it.

Fix in Cursor Fix in Web

from pathlib import Path

# Add the src directory to the path so we can import agency_swarm
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
Copy link

Choose a reason for hiding this comment

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

Example file has incorrect module path calculation

Medium Severity

The path Path(__file__).parent.parent / "src" resolves to examples/src instead of the root src/ directory. Since this file is in examples/interactive/, it needs .parent.parent.parent / "src" (three levels up) to reach the repository root where src/ is located.

Fix in Cursor Fix in Web

agency_name = agency_name.replace(" ", "_")

# Set environment variables for the Vite frontend
os.environ["CHATKIT_BACKEND_URL"] = f"http://{host}:{port}"
Copy link

Choose a reason for hiding this comment

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

Backend URL uses bind address instead of routable address

High Severity

The CHATKIT_BACKEND_URL environment variable is set to f"http://{host}:{port}", which becomes http://0.0.0.0:8000 when using the default host. The Vite proxy uses this URL as its target, but 0.0.0.0 is a bind address (meaning "all interfaces"), not a routable destination address. The proxy target needs to be 127.0.0.1 or localhost to successfully connect to the backend, regardless of what address the backend binds to.

Fix in Cursor Fix in Web

@github-actions github-actions bot removed the stale label Feb 6, 2026
@github-actions
Copy link
Contributor

This PR is stale because it has been open for 10 days with no activity.

@github-actions github-actions bot added the stale label Feb 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments