showcase/integrations/langgraph-python/qa/headless-complete.md
/demos/headless-complete on the dashboard host/api/health); OPENAI_API_KEY is set on Railway; LANGGRAPH_DEPLOYMENT_URL points at a LangGraph deployment exposing the headless_complete graph (backend tools: get_weather, get_stock_price)agent="headless-complete" at /api/copilotkit-mcp-apps (shared with the mcp-apps cell) so the Excalidraw MCP server at MCP_SERVER_URL || https://mcp.excalidraw.com is availabledata-testid in the source is headless-complete-messages on the scrollable messages container in message-list.tsx. Other checks rely on verbatim text, role selectors, and Tailwind utility classes/demos/headless-complete; verify the page renders within 3s with a centered card (max-width 3xl, full-height) on a bg-gray-50 background<h1> text "Headless Chat (Complete)" and subtext "Built from scratch on useAgent — no CopilotChat."[data-testid="headless-complete-messages"]) is present and shows the empty-state hint "Try weather, a stock, a highlighted note, or an Excalidraw sketch."<textarea> with placeholder "Type a message..." and a <button type="submit">Send</button> (disabled while textarea is empty).copilotKitChat, .copilotKitMessages, or .copilotKitMessage element in the DOM — the cell is truly headless and does NOT render <CopilotChatMessageView> or <CopilotChatAssistantMessage>bg-[#DBDBE5] disabled to bg-[#010507] active)Enter; verify the message submits and the textarea clears; press Shift+Enter in a follow-up message and verify a newline is inserted without submittingbg-[#FAFAFC] muted), its placeholder switches to "Agent is working...", and the right-hand button swaps from "Send" to a red bg-[#FA5F67] "Stop" buttoncopilotkit.stopAgent({ agent }) fires and the button reverts to "Send" once isRunning returns falseflex justify-end), rounded with rounded-2xl rounded-br-sm, bg-[#010507] text-white at max-w-[75%], text "Hello"bg-[#F0F0F4] rounded bubble) appears while isRunning is true and BEFORE any assistant content has streamedflex justify-start), rounded-2xl rounded-bl-sm, bg-[#F0F0F4] text-[#010507] at max-w-[85%], with the assistant's plain-text response inside a whitespace-pre-wrap break-words divbg-[#F0F0F4] box — AssistantBubble's isEmpty check suppresses themuseRenderTool + backend get_weather)text-sm font-semibold capitalize), temperature "68°", conditions "Sunny", wrapper bg-[#EDEDF5] border-[#DBDBE5] rounded-xl max-w-xsuseRenderTool + backend get_stock_price)font-mono font-semibold), price "$189.42", change "▲ 1.27%" in green text-[#189370]useComponent / highlight_note)bg-[#FFF388]/30 border-[#FFF388]COLOR_CLASSES are applieduseDefaultRenderTool + useRenderActivityMessage)MCPAppsActivityRenderer), proving the hand-rolled useRenderActivityMessage path in use-rendered-messages.tsxget_weather / get_stock_price / highlight_note) gets a visible default card via useDefaultRenderTool — not silently droppedrole: "reasoning" messages, verify each renders via the imported CopilotChatReasoningMessage leaf inside an assistant bubble (the only chat primitive imported in use-rendered-messages.tsx)useConfigureSuggestions with available: "always" ("Weather in Tokyo", "AAPL stock price", "Highlight a note", "Sketch a diagram") — exercised by manually sending the matching prompts aboveisRunning is true, verify additional keystrokes cannot trigger a second run (handleSubmit's if (!text || isRunning) return; guard)break-words without horizontal scrollac.abort() + agent.detachActiveRun()) does not produce an uncaught rejection in DevTools → Console (connect/run rejections are swallowed by design)console.error("headless-complete: runAgent failed", err) is emitted but no uncaught exception leaks, and the Send/Stop UI recovers to the idle state<CopilotChatMessageView> / <CopilotChatAssistantMessage>: assistant text + tool-call renders (per-tool + catch-all) + reasoning + activity messages all appear through the hand-rolled useRenderedMessages composition