showcase/integrations/langgraph-python/qa/frontend-tools-async.md
/demos/frontend-tools-async on the dashboard host/api/copilotkit GET returns langgraph_status: "reachable"); OPENAI_API_KEY is set; LANGGRAPH_DEPLOYMENT_URL points at a deployment exposing the frontend_tools_async graph (registered under agent name frontend-tools-async)frontend_tools_async.py registers NO server-side tools; the frontend registers exactly ONE tool via useFrontendTool: query_notes (parameter: keyword: string)NOTES_DB of 7 hard-coded notes, returning up to 5 matches against title, excerpt, or tags (case-insensitive). The tool has a custom render that mounts NotesCard/demos/frontend-tools-async; verify the CopilotChat panel renders centered (max width 4xl, rounded-2xl corners) within 3squery_notesquery_notes — Async Handler Loading Statequery_notes flow (via pill or typing "Find my notes about planning"), verify within 10s a data-testid="notes-card" element renders in the transcriptcomplete), verify the card's header shows:
data-testid="notes-keyword" reading Matching "<keyword>" where <keyword> is the agent's chosen search term (e.g. planning, project planning)query_notes — Resolved State (Simulated DB Query)N match" or "N matches" (singular when N=1)data-testid="notes-list" <ul> renders (assuming N > 0)<li> entries, each with data-testid="note-<id>" (IDs from n1–n7)note-n1 (Q2 project planning kickoff) and note-n5 (Project planning retrospective notes)notes-card (confirms the agent awaited the async handler's resolved value, not just fired-and-forgot)n1's excerpt ("new onboarding flow") — proving the previous tool result is retained in contextdata-testid="notes-card" renders with heading Matching "xyzzy-nonsense-keyword" (or close variant)notes-list element)query_notesquery_notes invocations in quick succession (e.g. "Find auth notes" then immediately "Find reading notes"); verify both resolve independently and render two separate notes-card instances in the transcriptnotes-card loading state appears within 10 seconds of promptnotes-list renders with the correct subset of NOTES_DB matching the keyword