### Install and Run News Guide from Project Directory Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Commands to navigate to the News Guide project directory, install dependencies, and start the example. ```bash cd examples/news-guide && npm install && npm run start ``` -------------------------------- ### Install and Run Customer Support from Project Directory Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Commands to navigate to the Customer Support project directory, install dependencies, and start the example. ```bash cd examples/customer-support && npm install && npm run start ``` -------------------------------- ### Run News Guide Example Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Command to run the News Guide example from the repository root. ```bash npm run news-guide ``` -------------------------------- ### Install and Run Cat Lounge from Project Directory Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Commands to navigate to the Cat Lounge project directory, install dependencies, and start the example. ```bash cd examples/cat-lounge && npm install && npm run start ``` -------------------------------- ### Run ChatKit Examples Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Setup environment variables and run example applications using npm commands. Includes backend development setup. ```bash # Prerequisites export OPENAI_API_KEY="sk-proj-..." export VITE_CHATKIT_API_DOMAIN_KEY="domain_pk_local_dev" # From repo root npm run cat-lounge # http://localhost:5170 npm run customer-support # http://localhost:5171 npm run news-guide # http://localhost:5172 npm run metro-map # http://localhost:5173 # Or from project directory cd examples/cat-lounge npm install && npm run start # Backend only (for development) cd backend uv sync uv run uvicorn app.main:app --reload --port 8000 ``` -------------------------------- ### Install and Run Metro Map from Project Directory Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Commands to navigate to the Metro Map project directory, install dependencies, and start the example. ```bash cd examples/metro-map && npm install && npm run start ``` -------------------------------- ### Frontend Project Setup Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/agents.md Steps to set up the frontend project, including installing dependencies and running the development server. ```bash cd frontend npm install npm run dev ``` -------------------------------- ### Install and Run ChatKit Frontend Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/examples/cat-lounge/frontend/README.md Installs project dependencies and starts the development server. Ensure Node.js 20+ is installed. The dev server runs on http://127.0.0.1:5170. ```bash npm install npm run dev ``` -------------------------------- ### Backend Project Setup Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/agents.md Steps to set up the backend project, including installing dependencies, setting the API key, and running the development server. ```bash cd backend uv sync export OPENAI_API_KEY="sk-proj-..." uv run uvicorn app.main:app --reload --port 8000 ``` -------------------------------- ### Run the React Frontend Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/examples/customer-support/README.md Commands to install dependencies and start the development server for the React frontend. ```bash cd examples/customer-support/frontend npm install npm run dev ``` -------------------------------- ### News Guide - Show Article List Widget Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Python function to display a list of articles to the user in the News Guide example. ```python def show_article_list_widget(self, articles: list[dict]): return self.ui.show_article_list_widget(articles) ``` -------------------------------- ### Run Customer Support Example Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Command to run the Customer Support example from the repository root. ```bash npm run customer-support ``` -------------------------------- ### Start the FastAPI Backend Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/examples/customer-support/README.md Commands to initialize the Python environment and launch the backend server for the support demo. ```bash cd examples/customer-support/backend uv sync export OPENAI_API_KEY="sk-proj-..." uv run uvicorn app.main:app --reload --port 8001 ``` -------------------------------- ### Run Cat Lounge Example Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Command to run the Cat Lounge example from the repository root. ```bash npm run cat-lounge ``` -------------------------------- ### Run Metro Map Example Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Command to run the Metro Map example from the repository root. ```bash npm run metro-map ``` -------------------------------- ### News Guide - Retrieval Tools Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Python functions for the News Guide agent to list tags, get articles by ID, search articles, and retrieve the current page. ```python def list_available_tags_and_keywords(self): return self.news.list_available_tags_and_keywords() def get_article_by_id(self, article_id: str): return self.news.get_article_by_id(article_id) def search_articles_by_tags_keywords_exact_text(self, tags: list[str] | None = None, keywords: list[str] | None = None, exact_text: str | None = None): return self.news.search_articles_by_tags_keywords_exact_text(tags=tags, keywords=keywords, exact_text=exact_text) def get_current_page(self) -> str: return self.news.get_current_page() ``` -------------------------------- ### Entity Search and @-Mention Setup Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Configures entity search and click handling for stations within the ChatKit composer. Requires `useMemo`, `useCallback`, and `Entity` type. ```typescript // frontend/src/components/ChatKitPanel.tsx - Entity search setup const stationEntities = useMemo(() => { if (!currentMap) return []; return currentMap.stations.map((station) => ({ id: station.id, title: station.name, interactive: true, group: "Stations", data: { type: "station", station_id: station.id, name: station.name }, })); }, [currentMap]); const searchStations = useCallback(async (query: string) => { const normalized = query.trim().toLowerCase(); if (!normalized) return stationEntities; return stationEntities.filter((entity) => entity.title.toLowerCase().includes(normalized) || entity.id.toLowerCase().includes(normalized) ); }, [stationEntities]); const handleEntityClick = useCallback((entity: Entity) => { const stationId = (entity.data?.station_id || entity.id || "").trim(); if (stationId) focusStation(stationId, currentMap); }, [currentMap, focusStation]); const chatkit = useChatKit({ entities: { onTagSearch: searchStations, showComposerMenu: true, onClick: handleEntityClick, }, }); ``` -------------------------------- ### Configuring Composer Tools for News Guide Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Configures the ChatKit client with a `composer.tools` option to specify available tools in the composer menu. This allows users to select specific agents or actions. ```typescript import { Tool } from "@chatkit/ui"; const tools: Tool[] = [ { id: "event_finder", name: "Find Event" }, { id: "puzzle", name: "Solve Puzzle" }, // ... other tools ]; // In ChatKitPanel.tsx ; ``` -------------------------------- ### Server-handled Widget Action: News Guide Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Processes the `view_event_details` action server-side to update the timeline widget with expanded descriptions without a model round trip. ```python def view_event_details(self, event_id: str): """Handle the view_event_details action.""" event = self.events.get(event_id) return event.to_widget() ``` -------------------------------- ### Cat Lounge - Get Cat Status Tool Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Python function to retrieve the latest cat statistics for the agent in the Cat Lounge example. ```python def get_cat_status(self): return self.cat.get_status() ``` -------------------------------- ### Thread Titles: News Guide Title Agent Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Runs on the first user message to generate a short newsroom-friendly title when none exists. ```python def title_agent(self, user_message: str) -> str: """Generate a news-friendly title for the conversation.""" # ... implementation details ... return "News Headline" ``` -------------------------------- ### Build Interactive Widgets with Templates in Python Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Construct interactive widgets using `.widget` template files and render them with `stream_widget`. This example demonstrates building a widget to display cat name suggestions with optional selection. ```python # backend/app/widgets/name_suggestions_widget.py from chatkit.widgets import WidgetRoot, WidgetTemplate from pydantic import BaseModel class CatNameSuggestion(BaseModel): name: str reason: str | None = None name_suggestions_widget_template = WidgetTemplate.from_file("cat_name_suggestions.widget") def build_name_suggestions_widget( names: list[CatNameSuggestion], selected: str | None = None, ) -> WidgetRoot: return name_suggestions_widget_template.build( data={ "items": [suggestion.model_dump() for suggestion in names], "selected": selected.strip().title() if selected else None, } ) # Usage in tool @function_tool(description_override="Render cat name options.\n- `suggestions`: List of name suggestions.") async def suggest_cat_names( ctx: RunContextWrapper[CatAgentContext], suggestions: list[CatNameSuggestion], ): widget = build_name_suggestions_widget(suggestions) await ctx.context.stream_widget(widget, copy_text=", ".join(s.name for s in suggestions)) ``` -------------------------------- ### Handle Client Tool Calls in ChatKit (Frontend) Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Implement the `onClientTool` handler in the frontend to respond to requests from server tools. This example shows how to return `selectedStationIds` when the `get_selected_stations` tool is called. ```tsx // frontend/src/components/ChatKitPanel.tsx - Client tool handler const handleClientTool = useCallback( ({ name }: { name: string; params: Record }) => { if (name === "get_selected_stations") { return { stationIds: selectedStationIds }; } }, [selectedStationIds] ); const chatkit = useChatKit({ // ... onClientTool: handleClientTool, }); ``` -------------------------------- ### Request UI State with ClientToolCall in Python Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Enable server tools to request data from the client UI using `ClientToolCall`. This example shows how a server tool can fetch currently selected stations from a client map. ```python # backend/app/agents/metro_map_agent.py from chatkit.agents import ClientToolCall from chatkit.types import ProgressUpdateEvent @function_tool(description_override="Fetch currently selected stations from the client UI. No parameters.") async def get_selected_stations(ctx: RunContextWrapper[MetroAgentContext]) -> SelectedStationsResult: # Show progress while waiting for client response await ctx.context.stream(ProgressUpdateEvent(text="Fetching selected stations from the map...")) # Request data from client ctx.context.client_tool_call = ClientToolCall( name="get_selected_stations", arguments={}, ) return SelectedStationsResult(station_ids=[]) ``` -------------------------------- ### Routing Tool Choices to Specialized Agents Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md The backend routes tool choices made by the user to specialized agents. If no specific agent matches, it falls back to a default agent, such as the News Guide agent. ```python from fastapi import FastAPI app = FastAPI() @app.post("/chat") async def chat(request: ChatRequest): if request.tool_choice == "event_finder": return await event_finder_agent.handle_message(request.message) elif request.tool_choice == "puzzle": return await puzzle_agent.handle_message(request.message) else: return await news_agent.handle_message(request.message) ``` -------------------------------- ### Metro Map - Show Line Selector Widget Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Python function to present a multiple-choice question for line selection using a UI widget in the Metro Map example. ```python def show_line_selector(self, lines: list[str]): return self.ui.show_line_selector(lines) ``` -------------------------------- ### Stream Progress Updates During Tool Execution Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Keep users informed during long-running operations by streaming progress updates using `ProgressUpdateEvent`. This example shows a news agent providing feedback while searching for articles. ```python # backend/app/agents/news_agent.py from chatkit.types import ProgressUpdateEvent @function_tool(description_override="Search articles by keywords.\n- `keywords`: List of keywords.") async def search_articles_by_keywords( ctx: RunContextWrapper[NewsAgentContext], keywords: List[str], ) -> ArticleSearchResult: cleaned = [k.strip().lower() for k in keywords if k and k.strip()] formatted = ", ".join(cleaned) # Stream progress update to UI await ctx.context.stream(ProgressUpdateEvent(text=f"Searching for keywords: {formatted}")) records = ctx.context.articles.search_metadata_by_keywords(cleaned) return ArticleSearchResult(articles=[ArticleMetadata.model_validate(r) for r in records]) ``` -------------------------------- ### Metro Map - Map Data Tools Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Python functions for the Metro Map agent to get map data, list lines and stations, and retrieve route information. ```python def get_map(self): return self.metro.get_map() def list_lines(self) -> list[str]: return self.metro.list_lines() def list_stations(self) -> list[str]: return self.metro.list_stations() def get_line_route(self, line_name: str) -> list[str]: return self.metro.get_line_route(line_name) def get_station(self, station_name: str) -> dict: return self.metro.get_station(station_name) ``` -------------------------------- ### Lock Interaction During Response Streaming Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Controls UI interaction during response streaming by calling `lockInteraction` on response start and `unlockInteraction` on response end. ```typescript // frontend/src/components/ChatKitPanel.tsx - Lock interaction during responses const lockInteraction = useMapStore((state) => state.lockInteraction); const unlockInteraction = useMapStore((state) => state.unlockInteraction); const chatkit = useChatKit({ onResponseStart: () => lockInteraction(), onResponseEnd: () => unlockInteraction(), }); ``` -------------------------------- ### Metro Map - Get Selected Stations Client Tool Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md TypeScript function to retrieve currently selected nodes from the canvas in the Metro Map frontend, allowing the agent to use client-side state. ```typescript const getSelectedStations = () => { return cy.get('.selected').map((el) => el.id()); }; // Agent code // const selectedStations = cy.get_selected_stations(); ``` -------------------------------- ### Domain Allowlisting for Local Development Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/agents.md Export a placeholder domain key for local development. This key is used by the SDK to identify the domain. ```bash export VITE_CHATKIT_API_DOMAIN_KEY=domain_pk_local_dev ``` -------------------------------- ### ChatKitServer Implementation Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Custom implementation of ChatKitServer for a cat assistant. Overrides respond() and action() methods to handle user messages and widget actions, integrating with stores and agents. ```python from typing import Any, AsyncIterator from agents import Runner from chatkit.agents import ResponseStreamConverter, stream_agent_response from chatkit.server import ChatKitServer from chatkit.types import ( Action, ThreadMetadata, ThreadStreamEvent, UserMessageItem, WidgetItem, StreamOptions ) class CatAssistantServer(ChatKitServer[dict[str, Any]]): def __init__(self) -> None: self.store = MemoryStore() super().__init__(self.store) self.cat_store = CatStore() self.thread_item_converter = BasicThreadItemConverter() async def respond( self, thread: ThreadMetadata, item: UserMessageItem | None, context: dict[str, Any], ) -> AsyncIterator[ThreadStreamEvent]: # Build agent context with access to stores agent_context = CatAgentContext( thread=thread, store=self.store, cats=self.cat_store, request_context=context, ) # Load thread history (most recent last) items_page = await self.store.load_thread_items( thread.id, after=None, limit=20, order="desc", context=context ) items = list(reversed(items_page.data)) input_items = await self.thread_item_converter.to_agent_input(items) # Run the agent with streaming result = Runner.run_streamed(cat_agent, input_items, context=agent_context) async for event in stream_agent_response( agent_context, result, converter=ResponseStreamConverter(partial_images=3) ): yield event async def action( self, thread: ThreadMetadata, action: Action[str, Any], sender: WidgetItem | None, context: dict[str, Any], ) -> AsyncIterator[ThreadStreamEvent]: if action.type == "cats.select_name": async for event in self._handle_select_name_action( thread, action.payload, sender, context ): yield event def get_stream_options(self, thread: ThreadMetadata, context: dict[str, Any]) -> StreamOptions: return StreamOptions(allow_cancel=False) ``` -------------------------------- ### Image Generation Tool Configuration Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Configures an `ImageGenerationTool` with partial images. The `cat_agent` uses this tool to generate images based on user requests. ```python from chatkit.tools import ImageGenerationTool cat_agent = BaseAgent( # ... other agent config tools=[ ImageGenerationTool( partial_images=3, # Configures the tool with 3 partial images # ... other tool options ) ] ) ``` -------------------------------- ### Server-handled Widget Actions: Customer Support Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Action handlers persist bookings, meals, upsells, and rebooks; lock widgets; log hidden context; and refresh the profile. ```python def support_set_meal_preference(self, meal_preference: str): """Handle the support.set_meal_preference action.""" self.profile.meal_preference = meal_preference return self.profile.to_widget() def flight_select(self, flight_id: str): """Handle the flight.select action.""" self.profile.flight_id = flight_id return self.profile.to_widget() ``` -------------------------------- ### Configure Tool Choice Menu Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Define an array of tool choices for the chat composer. Each choice includes a name, label, and icon. ```typescript // frontend/src/lib/config.ts - Tool choice configuration export const TOOL_CHOICES = [ { name: "event_finder", label: "Find Events", icon: "calendar" }, { name: "puzzle", label: "Coffee Break", icon: "puzzle" }, ]; ``` ```typescript // frontend/src/components/ChatKitPanel.tsx const chatkit = useChatKit({ composer: { placeholder: getPlaceholder(Boolean(activeThread)), tools: TOOL_CHOICES, }, }); ``` -------------------------------- ### Implement Two-Phase File Upload Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Backend endpoint to handle file uploads for attachments. It supports both multipart/form-data and raw body uploads. ```python # backend/app/main.py - Attachment upload endpoint @app.api_route("/support/attachments/{attachment_id}/upload", methods=["POST", "PUT"]) async def upload_attachment( attachment_id: str, request: Request, server: CustomerSupportServer = Depends(get_server), ): content_type = request.headers.get("content-type", "").lower() if content_type.startswith("multipart/form-data"): form = await request.form() file = form.get("file") data = await file.read() else: data = await request.body() attachment = await server.attachment_uploader.write_file(attachment_id, data, {"request": request}) return attachment.model_dump() ``` -------------------------------- ### Image Attachments: Customer Support Backend Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Backend handles image uploads/downloads, enforces limits, and converts uploads to data URLs for the model. Requires `attachment_store.py`, `main.py`, and `thread_item_converter.py`. ```python def create_attachment(self, filename: str, content_type: str): """Issue upload/download URLs for attachments.""" return self.attachment_store.issue_urls(filename, content_type) ``` -------------------------------- ### Handle Widget Actions in ChatKit (Client/Server) Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Implement client-side and server-side handlers for custom widget actions using `sendCustomAction`. Client-only actions can send user messages directly, while server-handled actions invoke backend logic and refresh the UI state. ```tsx // frontend/src/components/ChatKitPanel.tsx - Widget action handling const handleWidgetAction = useCallback( async ( action: { type: string; payload?: Record }, widgetItem: { id: string; widget: Widgets.Card | Widgets.ListView } ) => { const chatkit = chatkitRef.current; if (!chatkit) return; // Client-only action: send a follow-up message if (action.type === "cats.more_names") { await chatkit.sendUserMessage({ text: "More name suggestions, please" }); return; } // Server-handled action: invoke backend then refresh state if (action.type === "cats.select_name") { await chatkit.sendCustomAction(action, widgetItem.id); const data = await refresh(); if (data) handleStatusUpdate(data, `Now called ${data.name}`); } }, [refresh, handleStatusUpdate] ); ``` -------------------------------- ### Plan Route Functionality with Annotations Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Defines a function to plan a route and generate annotations for stations within a message. Requires `chatkit.types` and `datetime`. ```python from chatkit.types import Annotation, EntitySource, AssistantMessageContent @function_tool(description_override="Show planned route.\n- `route`: Stations in journey.\n- `message`: Description.") async def plan_route( ctx: RunContextWrapper[MetroAgentContext], route: list[Station], message: str, ): annotations = [] for station in route: index = message.index(station.name) + len(station.name) if station.name in message else None annotations.append( Annotation( source=EntitySource( id=station.id, icon="map-pin", title=station.name, description=station.description, interactive=True, label="Station", data={"type": "station", "station_id": station.id}, ), index=index, ) ) await ctx.context.stream( ThreadItemDoneEvent( item=AssistantMessageItem( thread_id=ctx.context.thread.id, id=ctx.context.generate_id("message"), created_at=datetime.now(), content=[AssistantMessageContent(text=message, annotations=annotations)], ) ) ) ``` -------------------------------- ### Configure React Client with useChatKit Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Configures the chat interface using the useChatKit hook, including theme settings and client effect handlers. ```tsx // frontend/src/components/ChatKitPanel.tsx import { ChatKit, useChatKit } from "@openai/chatkit-react"; export function ChatKitPanel({ onChatKitReady }: { onChatKitReady: (chatkit: ChatKit) => void }) { const theme = useAppStore((state) => state.scheme); const setThreadId = useAppStore((state) => state.setThreadId); const applyUpdate = useAppStore((state) => state.applyCatUpdate); const handleClientEffect = useCallback(({ name, data }: { name: string; data: Record }) => { if (name === "update_cat_status") { const catState = data.state as CatStatePayload | undefined; if (catState) applyUpdate(catState); } if (name === "cat_say") { const message = String(data.message ?? ""); if (message) setSpeech({ message }); } }, [applyUpdate]); const chatkit = useChatKit({ api: { url: CHATKIT_API_URL, domainKey: CHATKIT_API_DOMAIN_KEY }, theme: { density: "spacious", colorScheme: theme, color: { grayscale: { hue: 220, tint: 6, shade: theme === "dark" ? -1 : -4 }, accent: { primary: theme === "dark" ? "#f1f5f9" : "#0f172a", level: 1 }, }, radius: "round", }, startScreen: { greeting: GREETING, prompts: STARTER_PROMPTS }, composer: { placeholder: getPlaceholder(cat.name) }, widgets: { onAction: handleWidgetAction }, onThreadChange: ({ threadId }) => setThreadId(threadId), onEffect: handleClientEffect, onReady: () => onChatKitReady?.(chatkit), }); return (
); } ``` -------------------------------- ### Define Agent with Function Tools in Python Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Uses the Agent class and @function_tool decorator to define agent behavior and tools. Requires the agents and chatkit modules. ```python # backend/app/cat_agent.py from agents import Agent, RunContextWrapper, StopAtTools, function_tool, ImageGenerationTool from chatkit.agents import AgentContext from chatkit.types import ClientEffectEvent, HiddenContextItem, ThreadItemDoneEvent INSTRUCTIONS = """ You are Cozy Cat Companion, a playful caretaker helping the user look after a virtual cat. Always keep the per-thread cat stats (energy, happiness, cleanliness) in sync with tools. When you need the latest numbers, call `get_cat_status` before making a plan. """ class CatAgentContext(AgentContext): model_config = ConfigDict(arbitrary_types_allowed=True) cats: Annotated[CatStore, Field(exclude=True)] @function_tool(description_override="Read the cat's current stats. No parameters.") async def get_cat_status(ctx: RunContextWrapper[CatAgentContext]) -> dict[str, Any]: state = await ctx.context.cats.load(ctx.context.thread.id) return state.to_payload(ctx.context.thread.id) @function_tool(description_override="Feed the cat to replenish energy. - `meal`: Meal description.") async def feed_cat(ctx: RunContextWrapper[CatAgentContext], meal: str | None = None): state = await ctx.context.cats.mutate(ctx.context.thread.id, lambda s: s.feed()) flash = f"Fed {state.name} {meal}" if meal else f"{state.name} enjoyed a snack" # Add hidden context for future agent turns await ctx.context.store.add_thread_item( ctx.context.thread.id, HiddenContextItem( id=ctx.context.generate_id("message"), thread_id=ctx.context.thread.id, created_at=datetime.now(), content=f"{flash}", ), context=ctx.context.request_context, ) # Stream client effect to sync UI state await ctx.context.stream( ClientEffectEvent( name="update_cat_status", data={"state": state.to_payload(ctx.context.thread.id), "flash": flash}, ) ) cat_agent = Agent[CatAgentContext]( model="gpt-4.1-mini", name="Cozy Cat Companion", instructions=INSTRUCTIONS, tools=[ get_cat_status, feed_cat, play_with_cat, clean_cat, set_cat_name, show_cat_profile, speak_as_cat, suggest_cat_names, ImageGenerationTool(tool_config=ImageGeneration(type="image_generation", partial_images=3)), ], tool_use_behavior=StopAtTools(stop_at_tool_names=[suggest_cat_names.name, show_cat_profile.name]), ) ``` -------------------------------- ### Speech-to-Text Transcription Implementation Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Implements server-side audio transcription using OpenAI's Whisper model. Handles various audio formats and returns transcribed text. Requires `OpenAI`, `io`, `AudioInput`, `TranscriptionResult`, and `HTTPException`. ```python # backend/app/server.py - Transcription implementation import io from openai import OpenAI from chatkit.types import AudioInput, TranscriptionResult from fastapi import HTTPException client = OpenAI() class CustomerSupportServer(ChatKitServer[dict[str, Any]]): async def transcribe( self, audio_input: AudioInput, context: dict[str, Any] ) -> TranscriptionResult: ext = {"audio/webm": "webm", "audio/mp4": "m4a", "audio/ogg": "ogg"}.get(audio_input.media_type) if not ext: raise HTTPException(status_code=400, detail="Unexpected audio format") audio_file = io.BytesIO(audio_input.data) audio_file.name = f"audio.{ext}" transcription = client.audio.transcriptions.create(model="gpt-4o-transcribe", file=audio_file) return TranscriptionResult(text=transcription.text) ``` -------------------------------- ### Streaming Image Generation Progress Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md The `respond` method in the cat lounge server passes `ResponseStreamConverter(partial_images=3)` when invoking `stream_agent_response`. This helper correctly computes image generation progress when streaming each partial image. ```python from chatkit.response_stream import ResponseStreamConverter # Inside the cat lounge server's respond method response_stream = stream_agent_response( agent=cat_agent, message=message, response_converter=ResponseStreamConverter(partial_images=3) ) ``` -------------------------------- ### Image Attachments: Customer Support Frontend Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md React panel registers `attachments.create`, uploads via signed URL, and drops the attachment into the composer when users share photos. ```typescript const handleAttachment = async (file: File) => { const attachment = await chatkit.attachments.create({ filename: file.name, content_type: file.type, }); await fetch(attachment.upload_url, { method: 'PUT', body: file, headers: { 'Content-Type': file.type, }, }); await chatkit.updateMessage({ message_id: props.message.id, attachment: attachment.id, }); }; ``` -------------------------------- ### Server-handled Widget Action: Metro Map Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Handles the `line.select` action server-side to stream an updated widget, add context, stream an assistant message, and trigger a client effect. ```python def line_select(self, line_name: str): """Handle the line.select action.""" self.map.select_line(line_name) return [ self.map.to_widget(), ChatKit.HiddenContext(LINE_SELECTED, line_name), ChatKit.AssistantMessage( f"Which station on the {line_name} line would you like to add?" ), ChatKit.ClientEffect(LOCATION_SELECT_MODE), ] ``` -------------------------------- ### Entity Tagging for News Articles and Authors Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Implements entity search and previews for articles and authors in the composer, enabling @-mentions and hover previews. Tagged entities are converted into model-readable markers for agent processing. ```typescript export class ChatKitPanel extends React.Component { render() { return ( { const response = await fetch(`/articles/tags?query=${query}`); return response.json(); }, preview: async (id: string) => { const response = await fetch(`/articles/tags/${id}`); return response.json(); }, }, }, }} /> ); } } ``` -------------------------------- ### Enable Speech-to-Text Dictation in Composer Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Enables voice input functionality in the ChatKit composer by setting the `dictation.enabled` option. ```typescript // frontend/src/components/ChatKitPanel.tsx - Enable dictation const chatkit = useChatKit({ composer: { placeholder: "Ask the concierge a question", dictation: { enabled: true }, }, }); ``` -------------------------------- ### Thread Titles: Customer Support Lightweight Title Agent Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Names the conversation on the first user message without delaying the first reply. ```python def title_agent(self, user_message: str) -> str: """Generate a title for the conversation.""" # ... implementation details ... return "Conversation Title" ``` -------------------------------- ### Customer Support - Airline State Manager Tools Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Python functions for the Customer Support agent to manage airline-related actions using the AirlineStateManager. ```python def change_seat(self, flight_id: str, seat: str): return self.state.change_seat(flight_id, seat) def cancel_trip(self, flight_id: str): return self.state.cancel_trip(flight_id) def add_bags(self, flight_id: str, num_bags: int): return self.state.add_bags(flight_id, num_bags) def set_meal(self, flight_id: str, meal: str): return self.state.set_meal(flight_id, meal) def surface_flight_options(self, flight_id: str): return self.state.surface_flight_options(flight_id) def request_assistance(self, flight_id: str, reason: str): return self.state.request_assistance(flight_id, reason) ``` -------------------------------- ### ChatKit FastAPI Endpoint Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Sets up the main FastAPI application and defines the /chatkit endpoint for handling ChatKit requests. Includes an additional REST endpoint for retrieving cat state. ```python from chatkit.server import StreamingResult from fastapi import Depends, FastAPI, Request from fastapi.responses import Response, StreamingResponse from starlette.responses import JSONResponse from .server import CatAssistantServer, create_chatkit_server app = FastAPI(title="ChatKit API") _chatkit_server = create_chatkit_server() def get_chatkit_server() -> CatAssistantServer: return _chatkit_server @app.post("/chatkit") async def chatkit_endpoint( request: Request, server: CatAssistantServer = Depends(get_chatkit_server) ) -> Response: payload = await request.body() result = await server.process(payload, {"request": request}) if isinstance(result, StreamingResult): return StreamingResponse(result, media_type="text/event-stream") if hasattr(result, "json"): return Response(content=result.json, media_type="application/json") return JSONResponse(result) # Additional REST endpoint for state retrieval @app.get("/cats/{thread_id}") async def read_cat_state( thread_id: str, server: CatAssistantServer = Depends(get_chatkit_server), ): state = await server.cat_store.load(thread_id) return {"cat": state.to_payload(thread_id)} ``` -------------------------------- ### Enable File Attachments in ChatKit Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Configure ChatKit to enable file attachments in the composer, specifying maximum size and accepted file types. ```typescript // frontend/src/components/ChatKitPanel.tsx - Enable attachments const chatkit = useChatKit({ api: { url: SUPPORT_CHATKIT_API_URL, domainKey: SUPPORT_CHATKIT_API_DOMAIN_KEY, uploadStrategy: { type: "two_phase" }, }, composer: { attachments: { enabled: true, maxSize: MAX_UPLOAD_BYTES, accept: IMAGE_ATTACHMENT_ACCEPT, }, }, }); ``` -------------------------------- ### Converting Station Tags to Blocks with Line Metadata Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Converts tagged stations into `` blocks that include full line metadata. This allows the agent to answer queries without requiring an additional lookup. ```python def convert_thread_item_to_model(thread_item: ThreadItem): if thread_item.type == ThreadItemType.STATION_TAG: return f"" # ... other types ``` -------------------------------- ### Setting Tool Choice for Specific Agents Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Allows users to force specific agents (e.g., `event_finder`, `puzzle`) by setting the `tool_choice` option on the request. This directs the backend to route the query to the chosen agent. ```typescript import { ChatbotUI } from "@chatkit/ui"; const chatbot = new ChatbotUI({ // ... other options }); async function sendMessage() { await chatbot.sendMessage("Find events tomorrow", { tool_choice: "event_finder", }); } ``` -------------------------------- ### Dictation: Customer Support Server Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Server-side handling of transcribed audio from the chat composer. ```python def transcribe(self, audio: bytes, content_type: str) -> str: """Transcribe audio input from the user.""" # ... implementation details ... return "Transcription result" ``` -------------------------------- ### Resolving Article Reference Tags with a Tool Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Resolves article reference tags into full articles using the `get_article_by_id` tool. This allows the agent to cite specific details from the article. ```python class NewsAgent(BaseAgent): def __init__(self, **kwargs): super().__init__(**kwargs) self.add_tool( Tool( name="get_article_by_id", func=self.get_article_by_id, description="Fetches an article by its ID.", ) ) def get_article_by_id(self, id: str) -> dict: # ... implementation to fetch article details ``` -------------------------------- ### Server-handled Widget Action: Cat Lounge Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Handles the `cats.select_name` action server-side to update data and stream back suggestions. Invoked using `chatkit.sendAction()` from the `handleWidgetAction` callback. ```python def cats_select_name(self, name: str): """Handle the cats.select_name action.""" self.cats.select_name(name) return self.cats.to_widget() ``` -------------------------------- ### Dictation: Customer Support Chat Composer Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Enables client-side dictation via `composer.dictation` and handles transcription server-side using `ChatKitServer.transcribe()`. ```typescript const composer = chatkit.elements.get('composer'); composer.dictation = true; ``` -------------------------------- ### Converting Article Reference Tags to Model-Readable Markers Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Converts article reference tags into model-readable markers (``) for agent processing. This ensures the agent can fetch the correct records. ```python def convert_thread_item_to_model(thread_item: ThreadItem): if thread_item.type == ThreadItemType.ARTICLE_REFERENCE: return f"" elif thread_item.type == ThreadItemType.AUTHOR_REFERENCE: return f"" # ... other types ``` -------------------------------- ### Entity Tagging for Metro Map Stations Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Enables @-mentions for stations in the composer, allowing users to tag them. Clicking a tag focuses the station on the canvas and converts tagged stations into blocks with line metadata. ```typescript export class ChatKitPanel extends React.Component { render() { return ( { const response = await fetch(`/stations/tags?query=${query}`); return response.json(); }, preview: async (id: string) => { const response = await fetch(`/stations/tags/${id}`); return response.json(); }, }, }, }} onEvent={(event) => { if (event.type === "tag_clicked") { // Focus station on canvas this.focusStation(event.payload.id); } }} /> ); } } ``` -------------------------------- ### Custom Header Action for Dark Mode Toggle Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Implements a right-side icon toggle in the chat header for dark/light mode switching. This action flips the app's color scheme client-side. ```typescript import { ChatKit } from "@chatkit/ui"; export class ChatKitPanel extends React.Component { render() { return ( this.toggleDarkMode(), }, ]} /> ); } toggleDarkMode() { // ... logic to toggle dark mode } } ``` -------------------------------- ### Thread Titles: Metro Map Dedicated Title Agent Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Sets a brief metro-planning title on the first turn and persists it to thread metadata. ```python def title_agent(self, user_message: str) -> str: """Generate a title for the metro map conversation.""" # ... implementation details ... return "Metro Route Plan" ``` -------------------------------- ### Custom Fetch with Article ID Header Source: https://context7.com/openai/openai-chatkit-advanced-samples/llms.txt Configures a custom fetch function to include the current `article-id` header in requests to the ChatKit API. Defaults to 'featured' if no article ID is available. ```typescript // frontend/src/components/ChatKitPanel.tsx - Custom fetch with headers const articleId = useAppStore((state) => state.articleId); const customFetch = useMemo(() => { return async (input: RequestInfo | URL, init?: RequestInit) => { const headers = new Headers(init?.headers ?? {}); const currentArticleId = articleId ?? "featured"; if (currentArticleId) { headers.set("article-id", currentArticleId); } return fetch(input, { ...init, headers }); }; }, [articleId]); const chatkit = useChatKit({ api: { url: CHATKIT_API_URL, domainKey: CHATKIT_API_DOMAIN_KEY, fetch: customFetch } }); ``` -------------------------------- ### Thread Titles: Cat Lounge Tool Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Locks in the cat's name and updates the thread title to '{name}’s Lounge' before saving. ```python def set_cat_name(self, name: str): """Set the cat's name and update the thread title.""" self.cat.name = name self.thread.title = f"{name}'s Lounge" self.thread.save() ``` -------------------------------- ### Annotations: Metro Map Entity Click Handler Source: https://github.com/openai/openai-chatkit-advanced-samples/blob/main/README.md Client's entity click handler pans the React Flow canvas to the clicked station, rendering stations as inline annotations and in the sources list. ```typescript const handleEntityClick = (entity: Entity) => { // Pan canvas to the clicked station flowInstance.current?.zoomTo(entity.x, entity.y); }; ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.