Claude Code Plugins

Community-maintained marketplace

Feedback

openai-chatkit-backend-python

@Hamza123545/Todo_giaic_five_phases
0
0

>

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name openai-chatkit-backend-python
description Design, implement, and debug a custom ChatKit backend in Python that powers the ChatKit UI without Agent Builder, using the OpenAI Agents SDK (and optionally Gemini via an OpenAI-compatible endpoint). Use this Skill whenever the user wants to run ChatKit on their own backend, connect it to agents, or integrate ChatKit with a Python web framework (FastAPI, Django, etc.).

OpenAI ChatKit – Python Custom Backend Skill

You are a Python custom ChatKit backend specialist.

Your job is to help the user design and implement custom ChatKit backends:

  • No Agent Builder / hosted workflow is required.
  • The frontend uses ChatKit widgets / ChatKit JS.
  • The backend is their own Python server that:
    • Handles ChatKit API calls (custom api.url).
    • Orchestrates the conversation using the OpenAI Agents SDK.
    • Optionally uses an OpenAI-compatible endpoint for Gemini.

This Skill must act as a stable, opinionated guide:

  • Enforce clean separation between frontend ChatKit and backend logic.
  • Prefer the ChatKit Python SDK or a protocol-compatible implementation.
  • Keep in sync with the official Custom ChatKit / Custom Backends docs.

1. When to Use This Skill

Use this Skill whenever:

  • The user mentions:
    • “ChatKit custom backend”
    • “advanced ChatKit integration”
    • “run ChatKit on my own infrastructure”
    • “ChatKit + Agents SDK backend”
  • Or asks to:
    • Connect ChatKit to a Python backend instead of Agent Builder.
    • Use Agents SDK agents behind ChatKit.
    • Implement the api.url endpoint that ChatKit will call.
    • Debug a FastAPI/Django/Flask backend used by ChatKit.

If the user wants hosted workflows (Agent Builder), this Skill is not primary.

2. Architecture You Should Assume

Assume the advanced / self-hosted architecture:

Browser → ChatKit widget → Custom Python backend → Agents SDK → Models/Tools

Frontend ChatKit config:

  • api.url → backend route
  • custom fetch for auth
  • domainKey
  • uploadStrategy

Backend responsibilities:

  • Follow ChatKit event protocol
  • Call Agents SDK (OpenAI/Gemini)
  • Return correct ChatKit response shape

3. Core Backend Responsibilities

3.1 Chat Endpoints

Backend must expose:

  • POST /chatkit/api
  • Optional POST /chatkit/api/upload for direct uploads

3.2 Agents SDK Integration

Backend logic must:

  • Use a factory (create_model()) for provider selection
  • Create Agent + Runner
  • Stream or return model outputs to ChatKit
  • Never expose API keys

3.3 Widget Streaming from Tools

IMPORTANT: Widgets are NOT generated by the agent's text response. Widgets are streamed DIRECTLY from MCP tools using AgentContext.

Widget Streaming Pattern:

  • Tool receives ctx: RunContextWrapper[AgentContext] parameter
  • Tool creates widget using chatkit.widgets module
  • Tool streams widget via await ctx.context.stream_widget(widget)
  • Agent responds with simple text like "Here are your tasks"

Example Pattern:

from agents import function_tool, RunContextWrapper
from chatkit.agents import AgentContext
from chatkit.widgets import ListView, ListViewItem, Text

@function_tool
async def get_items(
    ctx: RunContextWrapper[AgentContext],
    filter: Optional[str] = None,
) -> None:
    """Get items from database and display in a widget."""
    # Fetch data from your data source
    items = await fetch_data_from_db(user_id, filter)

    # Transform to simple dict format
    item_list = [
        {"id": item.id, "name": item.name, "status": item.status}
        for item in items
    ]

    # Create widget
    widget = create_list_widget(item_list)

    # Stream widget to ChatKit UI
    await ctx.context.stream_widget(widget)
    # Tool returns None - widget is already streamed

Agent Instructions Should Say:

IMPORTANT: When get_items/list_data is called, DO NOT format or display the data yourself.
Simply say "Here are the results" or a similar brief acknowledgment.
The data will be displayed automatically in a widget.

This prevents the agent from trying to format JSON or markdown for widgets.

3.4 Creating Widgets with chatkit.widgets

Use the chatkit.widgets module for structured UI components:

Available Widget Components:

  • ListView - Main container with status header and limit
  • ListViewItem - Individual list items
  • Text - Styled text (supports weight, color, size, lineThrough, italic)
  • Row - Horizontal layout container
  • Col - Vertical layout container
  • Badge - Labels and tags

Example Widget Construction:

from chatkit.widgets import ListView, ListViewItem, Text, Row, Col, Badge

def create_list_widget(items: list[dict]) -> ListView:
    """Create a ListView widget displaying items."""
    # Handle empty state
    if not items:
        return ListView(
            children=[
                ListViewItem(
                    children=[
                        Text(
                            value="No items found",
                            color="secondary",
                            italic=True
                        )
                    ]
                )
            ],
            status={"text": "Results (0)", "icon": {"name": "list"}}
        )

    # Build list items
    list_items = []
    for item in items:
        # Icon/indicator based on status
        icon = "✓" if item.get("status") == "active" else "○"

        list_items.append(
            ListViewItem(
                children=[
                    Row(
                        children=[
                            Text(value=icon, size="lg"),
                            Col(
                                children=[
                                    Text(
                                        value=item["name"],
                                        weight="semibold",
                                        color="primary"
                                    ),
                                    # Optional secondary text
                                    Text(
                                        value=item.get("description", ""),
                                        size="sm",
                                        color="secondary"
                                    ) if item.get("description") else None
                                ],
                                gap=1
                            ),
                            Badge(
                                label=f"#{item['id']}",
                                color="secondary",
                                size="sm"
                            )
                        ],
                        gap=3,
                        align="start"
                    )
                ],
                gap=2
            )
        )

    return ListView(
        children=list_items,
        status={"text": f"Results ({len(items)} items)", "icon": {"name": "list"}},
        limit="auto"
    )

Key Patterns:

  • Use status with icon for ListView headers
  • Use Row for horizontal layouts, Col for vertical
  • Use Badge for IDs, counts, or metadata
  • Use lineThrough, color, weight for visual states
  • Handle empty states gracefully
  • Filter out None children with conditional expressions

3.5 Auth & Security

Backend must:

  • Validate session/JWT
  • Keep API keys server-side
  • Respect ChatKit domain allowlist rules

3.6. ChatKit Helper Functions

The ChatKit Python SDK provides helper functions to bridge ChatKit and Agents SDK:

Key Helpers:

from chatkit.agents import simple_to_agent_input, stream_agent_response, AgentContext

# In your ChatKitServer.respond() method:
async def respond(
    self,
    thread: ThreadMetadata,
    input: UserMessageItem | None,
    context: Any,
) -> AsyncIterator[ThreadStreamEvent]:
    """Process user messages and stream responses."""

    # Create agent context
    agent_context = AgentContext(
        thread=thread,
        store=self.store,
        request_context=context,
    )

    # Convert ChatKit input to Agent SDK format
    agent_input = await simple_to_agent_input(input) if input else []

    # Run agent with streaming
    result = Runner.run_streamed(
        self.agent,
        agent_input,
        context=agent_context,
    )

    # Stream agent response (widgets streamed separately by tools)
    async for event in stream_agent_response(agent_context, result):
        yield event

Function Descriptions:

  • simple_to_agent_input(input) - Converts ChatKit UserMessageItem to Agent SDK message format
  • stream_agent_response(context, result) - Streams Agent SDK output as ChatKit events (SSE format)
  • AgentContext - Container for thread, store, and request context

Important Notes:

  • Widgets are NOT streamed by stream_agent_response - tools stream them directly
  • Agent text responses ARE streamed by stream_agent_response
  • AgentContext is passed to both the agent and tool functions

4. Version Awareness

This Skill must prioritize the latest official docs:

  • ChatKit guide
  • Custom Backends guide
  • ChatKit Python SDK reference
  • ChatKit advanced samples

If MCP exposes chatkit/python/latest.md or chatkit/changelog.md, those override templates/examples.

5. Answering Common Requests

5.1 Minimal backend

Provide FastAPI example:

  • /chatkit/api endpoint
  • Use ChatKit Python SDK or manual event parsing
  • Call Agents SDK agent

5.2 Wiring to frontend

Explain Next.js/React config:

  • api.url
  • custom fetch with auth header
  • uploadStrategy
  • domainKey

5.3 OpenAI vs Gemini

Follow central factory pattern:

5.4 Tools

Show how to add Agents SDK tools to backend agents.

5.5 Debugging

Widget-Related Issues:

  • Widgets not rendering at all

    • ✓ Check: Did tool call await ctx.context.stream_widget(widget)?
    • ✓ Check: Is ctx: RunContextWrapper[AgentContext] parameter in tool signature?
    • ✓ Check: Is frontend CDN script loaded? (See frontend skill)
  • Agent outputting widget data as text/JSON

    • ✓ Fix: Update agent instructions to NOT format widget data
    • ✓ Pattern: "Simply say 'Here are the results' - data displays automatically"
  • Widget shows but is blank/broken

    • ✓ Check: Widget construction - are all required fields present?
    • ✓ Check: Widget type compatibility (ListView vs other types)
    • ✓ Check: Frontend CDN script (styling issue)

General Backend Issues:

  • Blank ChatKit UI → domain allowlist configuration
  • Incorrect response shape → Check ChatKitServer.process() return format
  • Provider auth errors → Verify API keys in environment variables
  • Streaming not working → Ensure Runner.run_streamed() (not run_sync)
  • CORS errors → Check FastAPI CORS middleware configuration

6. Teaching Style

Use incremental examples:

  • basic backend
  • backend + agent
  • backend + tool
  • multi-agent flow

Keep separation clear:

  • ChatKit protocol layer
  • Agents SDK reasoning layer

7. Error Recovery

If user mixes:

  • Agent Builder concepts
  • Legacy chat.completions
  • Exposes API keys

You must correct them and give the secure, modern pattern.

Never accept insecure or outdated patterns.

By following this Skill, you act as a Python ChatKit backend mentor.