From 6926d88f0febe1b0db032d1f902ce8fd1618f0d4 Mon Sep 17 00:00:00 2001 From: Tyler Slaton Date: Wed, 27 May 2026 13:59:35 -0700 Subject: [PATCH 01/15] fix(shared): update PDX-199 docs error anchors --- packages/shared/src/utils/errors.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/shared/src/utils/errors.ts b/packages/shared/src/utils/errors.ts index 43e3c04752d..2673918590c 100644 --- a/packages/shared/src/utils/errors.ts +++ b/packages/shared/src/utils/errors.ts @@ -63,37 +63,37 @@ const getSeeMoreMarkdown = (link: string) => `See more: [${link}](${link})`; export const ERROR_CONFIG = { [CopilotKitErrorCode.NETWORK_ERROR]: { statusCode: 503, - troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#i-am-getting-a-network-errors--api-not-found`, + troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#network-errors-api-not-found`, visibility: ErrorVisibility.BANNER, severity: Severity.CRITICAL, }, [CopilotKitErrorCode.NOT_FOUND]: { statusCode: 404, - troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#i-am-getting-a-network-errors--api-not-found`, + troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#network-errors-api-not-found`, visibility: ErrorVisibility.BANNER, severity: Severity.CRITICAL, }, [CopilotKitErrorCode.AGENT_NOT_FOUND]: { statusCode: 500, - troubleshootingUrl: `${BASE_URL}/coagents/troubleshooting/common-issues#i-am-getting-agent-not-found-error`, + troubleshootingUrl: `${BASE_URL}/langgraph-python/coagent-troubleshooting/common-coagent-issues#i-am-getting-agent-not-found-error`, visibility: ErrorVisibility.BANNER, severity: Severity.CRITICAL, }, [CopilotKitErrorCode.API_NOT_FOUND]: { statusCode: 404, - troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#i-am-getting-a-network-errors--api-not-found`, + troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#network-errors-api-not-found`, visibility: ErrorVisibility.BANNER, severity: Severity.CRITICAL, }, [CopilotKitErrorCode.REMOTE_ENDPOINT_NOT_FOUND]: { statusCode: 404, - troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#i-am-getting-copilotkits-remote-endpoint-not-found-error`, + troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#remote-endpoint-not-found-error`, visibility: ErrorVisibility.BANNER, severity: Severity.CRITICAL, }, [CopilotKitErrorCode.AUTHENTICATION_ERROR]: { statusCode: 401, - troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues#authentication-errors`, + troubleshootingUrl: `${BASE_URL}/troubleshooting/common-issues`, visibility: ErrorVisibility.BANNER, severity: Severity.CRITICAL, }, From ec239b15f72fa1edaa0e91d30f86744df4395bcd Mon Sep 17 00:00:00 2001 From: Tyler Slaton Date: Thu, 28 May 2026 13:22:11 -0700 Subject: [PATCH 02/15] Add v1 reference selector and content --- .../src/app/reference/[...slug]/page.tsx | 85 ++--- .../shell-docs/src/app/reference/page.tsx | 161 ++++------ .../components/reference-version-selector.tsx | 119 +++++++ .../v1/classes/llm-adapters/meta.json | 11 + .../content/reference/v1/classes/meta.json | 8 + .../reference/v1/components/chat/index.mdx | 29 ++ .../reference/v1/components/chat/meta.json | 8 + .../content/reference/v1/components/meta.json | 8 + .../src/content/reference/v1/hooks/meta.json | 19 ++ .../content/reference/v1/hooks/useAgent.mdx | 304 ++++++++++++++++++ .../reference/v1/hooks/useCopilotAction.mdx | 199 ++++++++++++ .../reference/v1/hooks/useDefaultTool.mdx | 140 ++++++++ .../reference/v1/hooks/useFrontendTool.mdx | 187 +++++++++++ .../reference/v1/hooks/useHumanInTheLoop.mdx | 237 ++++++++++++++ .../v1/hooks/useLangGraphInterrupt.mdx | 77 +++++ .../reference/v1/hooks/useRenderToolCall.mdx | 131 ++++++++ .../src/content/reference/v1/index.mdx | 43 +++ .../src/content/reference/v1/meta.json | 14 + .../content/reference/v1/sdk/js/LangGraph.mdx | 12 + .../src/content/reference/v1/sdk/js/meta.json | 3 + .../src/content/reference/v1/sdk/meta.json | 3 + .../reference/v1/sdk/python/CrewAI.mdx | 102 ++++++ .../reference/v1/sdk/python/CrewAIAgent.mdx | 108 +++++++ .../reference/v1/sdk/python/LangGraph.mdx | 203 ++++++++++++ .../v1/sdk/python/LangGraphAgent.mdx | 102 ++++++ .../v1/sdk/python/RemoteEndpoints.mdx | 181 +++++++++++ .../content/reference/v1/sdk/python/meta.json | 9 + .../shell-docs/src/lib/reference-items.ts | 288 ++++++++++++++--- showcase/shell-docs/src/lib/seo-redirects.ts | 5 - 29 files changed, 2609 insertions(+), 187 deletions(-) create mode 100644 showcase/shell-docs/src/components/reference-version-selector.tsx create mode 100644 showcase/shell-docs/src/content/reference/v1/classes/llm-adapters/meta.json create mode 100644 showcase/shell-docs/src/content/reference/v1/classes/meta.json create mode 100644 showcase/shell-docs/src/content/reference/v1/components/chat/index.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/components/chat/meta.json create mode 100644 showcase/shell-docs/src/content/reference/v1/components/meta.json create mode 100644 showcase/shell-docs/src/content/reference/v1/hooks/meta.json create mode 100644 showcase/shell-docs/src/content/reference/v1/hooks/useAgent.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/hooks/useCopilotAction.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/hooks/useDefaultTool.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/hooks/useFrontendTool.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/hooks/useHumanInTheLoop.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/hooks/useLangGraphInterrupt.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/hooks/useRenderToolCall.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/index.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/meta.json create mode 100644 showcase/shell-docs/src/content/reference/v1/sdk/js/LangGraph.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/sdk/js/meta.json create mode 100644 showcase/shell-docs/src/content/reference/v1/sdk/meta.json create mode 100644 showcase/shell-docs/src/content/reference/v1/sdk/python/CrewAI.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/sdk/python/CrewAIAgent.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/sdk/python/LangGraph.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/sdk/python/LangGraphAgent.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/sdk/python/RemoteEndpoints.mdx create mode 100644 showcase/shell-docs/src/content/reference/v1/sdk/python/meta.json diff --git a/showcase/shell-docs/src/app/reference/[...slug]/page.tsx b/showcase/shell-docs/src/app/reference/[...slug]/page.tsx index 12379aded0c..1cd601a7a6c 100644 --- a/showcase/shell-docs/src/app/reference/[...slug]/page.tsx +++ b/showcase/shell-docs/src/app/reference/[...slug]/page.tsx @@ -1,8 +1,10 @@ import type { Metadata } from "next"; +import type React from "react"; import Link from "next/link"; import { notFound } from "next/navigation"; import { MDXRemote } from "next-mdx-remote/rsc"; import matter from "gray-matter"; +import { LinkIcon } from "lucide-react"; import { PropertyReference } from "@/components/property-reference"; import { Callout, @@ -19,14 +21,16 @@ import { DocsDescription, } from "fumadocs-ui/page"; import { ShellDocsLayout } from "@/components/shell-docs-layout"; -import type * as PageTree from "fumadocs-core/page-tree"; +import { ReferenceVersionSelector } from "@/components/reference-version-selector"; import { - REFERENCE_CONTENT_DIR, - loadAllReferenceItems, + REFERENCE_VERSIONS, + buildReferencePageTree, + referenceHref, referenceStaticParams, + referenceVersionHref, + resolveReferencePage, } from "@/lib/reference-items"; import { stripLeadingImports } from "@/lib/docs-render"; -import { safeReadFileSync } from "@/lib/safe-fs"; import { buildDocMetadata } from "@/lib/seo-metadata"; // Self-canonical for /reference/. Reference pages are not @@ -41,11 +45,8 @@ export async function generateMetadata({ params: Promise<{ slug: string[] }>; }): Promise { const { slug } = await params; - const slugPath = slug.join("/"); - const canonicalPath = `/reference/${slugPath}`; - // Read the reference MDX directly to extract frontmatter. Reuse - // safeReadFileSync so a crafted slug can't escape REFERENCE_CONTENT_DIR. - const raw = safeReadFileSync(REFERENCE_CONTENT_DIR, `${slugPath}.mdx`); + const resolved = resolveReferencePage(slug); + const raw = resolved?.raw ?? null; let title: string | undefined; let description: string | undefined; if (raw !== null) { @@ -64,7 +65,9 @@ export async function generateMetadata({ return buildDocMetadata({ title: title ?? slug[slug.length - 1], description, - canonicalPath, + canonicalPath: resolved + ? referenceHref(resolved.version, resolved.pageSlug) + : `/reference/${slug.join("/")}`, }); } @@ -77,6 +80,12 @@ const mdxComponents = { Accordions, Accordion, OpsPlatformCTA, + LinkIcon, + Frame: ({ children }: { children: React.ReactNode }) => ( +
+ {children} +
+ ), // Strip unknown imports — MDX import statements become no-ops in next-mdx-remote }; @@ -90,15 +99,12 @@ export default async function ReferenceSlugPage({ params: Promise<{ slug: string[] }>; }) { const { slug } = await params; - const slugPath = slug.join("/"); - // slugPath is user-supplied (URL segments). Route the filesystem read - // through safeReadFileSync so crafted paths like `..%2F..%2Fsecrets` - // can't escape REFERENCE_CONTENT_DIR. - const raw = safeReadFileSync(REFERENCE_CONTENT_DIR, `${slugPath}.mdx`); - if (raw === null) { + const resolved = resolveReferencePage(slug); + if (resolved === null) { notFound(); } + const { version, pageSlug, contentSlug, raw } = resolved; let content = ""; let data: Record = {}; try { @@ -107,7 +113,7 @@ export default async function ReferenceSlugPage({ data = parsed.data; } catch (err) { console.error( - `[reference] Failed to parse frontmatter in ${slugPath}.mdx:`, + `[reference] Failed to parse frontmatter in ${contentSlug}.mdx:`, err, ); notFound(); @@ -115,35 +121,28 @@ export default async function ReferenceSlugPage({ const cleanedContent = stripLeadingImports(content); - const allItems = loadAllReferenceItems(); const title = typeof data.title === "string" && data.title.length > 0 ? data.title : slug[slug.length - 1]; const description = typeof data.description === "string" ? data.description : undefined; - - // Build a Fumadocs PageTree from the reference items, grouped by - // category. Reference's IA is its own (Components / Hooks) — we don't - // share the docs nav tree here. - const pageTree: PageTree.Root = { - name: "Reference", - children: ["Components", "Hooks"].flatMap((cat) => [ - { type: "separator" as const, name: cat }, - ...allItems - .filter((i) => i.category === cat) - .map( - (item): PageTree.Item => ({ - type: "page", - name: item.title, - url: `/reference/${item.slug}`, - }), - ), - ]), - }; + const pageTree = buildReferencePageTree(version); + const versionOptions = REFERENCE_VERSIONS.map((referenceVersion) => ({ + version: referenceVersion, + href: referenceVersionHref(referenceVersion, pageSlug), + })); return ( - + + } + > {" / "} - {slug[0]} + {version} + {pageSlug && ( + <> + {" / "} + + {pageSlug.split("/")[0]} + + + )} {title} {description && ( diff --git a/showcase/shell-docs/src/app/reference/page.tsx b/showcase/shell-docs/src/app/reference/page.tsx index 8451be84991..63e0746ce4b 100644 --- a/showcase/shell-docs/src/app/reference/page.tsx +++ b/showcase/shell-docs/src/app/reference/page.tsx @@ -1,60 +1,50 @@ import Link from "next/link"; -import fs from "fs"; -import path from "path"; -import matter from "gray-matter"; import { DocsPage } from "fumadocs-ui/page"; import { ShellDocsLayout } from "@/components/shell-docs-layout"; -import type * as PageTree from "fumadocs-core/page-tree"; +import { ReferenceVersionSelector } from "@/components/reference-version-selector"; import { - REFERENCE_CONTENT_DIR, - loadReferenceItems, - loadAllReferenceItems, + REFERENCE_CATEGORIES, + REFERENCE_VERSIONS, + buildReferencePageTree, + loadReferenceVersionItems, + referenceVersionHref, + readReferenceIndexDescription, } from "@/lib/reference-items"; +import type { ReferenceCategory, ReferenceItem } from "@/lib/reference-items"; -export default function ReferencePage() { - const components = loadReferenceItems("components"); - const hooks = loadReferenceItems("hooks"); - const allItems = loadAllReferenceItems(); +function displayTitle(item: ReferenceItem): string { + if (item.category === "Components") return `<${item.title} />`; + if (item.category === "Hooks") return `${item.title}()`; + return item.title; +} - // Mirror the PageTree built by `/reference/[...slug]` so the sidebar - // chrome is identical between the index and the per-item pages. - const pageTree: PageTree.Root = { - name: "Reference", - children: ["Components", "Hooks"].flatMap((cat) => [ - { type: "separator" as const, name: cat }, - ...allItems - .filter((i) => i.category === cat) - .map( - (item): PageTree.Item => ({ - type: "page", - name: item.title, - url: `/reference/${item.slug}`, - }), - ), - ]), - }; +function categoryItems( + items: ReferenceItem[], + category: ReferenceCategory, +): ReferenceItem[] { + return items.filter((item) => item.category === category); +} - // Also load the index page frontmatter for the intro. Guarded so a - // malformed frontmatter block falls back to a default rather than - // crashing the whole index page. - let intro = "API Reference for the next-generation CopilotKit React API."; - const indexPath = path.join(REFERENCE_CONTENT_DIR, "index.mdx"); - if (fs.existsSync(indexPath)) { - try { - const { data } = matter(fs.readFileSync(indexPath, "utf-8")); - if (typeof data.description === "string" && data.description.length > 0) { - intro = data.description; - } - } catch (err) { - console.error( - `[reference] Failed to parse frontmatter in ${indexPath}:`, - err, - ); - } - } +export default function ReferencePage() { + const activeVersion = "v2"; + const allItems = loadReferenceVersionItems(activeVersion); + const pageTree = buildReferencePageTree(activeVersion); + const intro = readReferenceIndexDescription(activeVersion); + const versionOptions = REFERENCE_VERSIONS.map((version) => ({ + version, + href: referenceVersionHref(version), + })); return ( - + + } + >

{intro}

-
-

- UI Components -

-
- {components.map((item) => ( - -
- {"<"} - {item.title} - {" />"} -
- {item.description && ( -
- {item.description} -
- )} - - ))} -
-
+ {REFERENCE_CATEGORIES.map((category) => { + const items = categoryItems(allItems, category); + if (items.length === 0) return null; -
-

- Hooks -

-
- {hooks.map((item) => ( - -
- {item.title}() -
- {item.description && ( -
- {item.description} -
- )} - - ))} -
-
+ return ( +
+

+ {category === "Components" ? "UI Components" : category} +

+
+ {items.map((item) => ( + +
+ {displayTitle(item)} +
+ {item.description && ( +
+ {item.description} +
+ )} + + ))} +
+
+ ); + })}
diff --git a/showcase/shell-docs/src/components/reference-version-selector.tsx b/showcase/shell-docs/src/components/reference-version-selector.tsx new file mode 100644 index 00000000000..b703938dcf7 --- /dev/null +++ b/showcase/shell-docs/src/components/reference-version-selector.tsx @@ -0,0 +1,119 @@ +"use client"; + +import Link from "next/link"; +import { ChevronDown } from "lucide-react"; +import { useEffect, useRef, useState } from "react"; + +export type ReferenceVersion = "v2" | "v1"; + +export type ReferenceVersionOption = { + version: ReferenceVersion; + href: string; +}; + +const VERSION_LABELS: Record = { + v2: "v2", + v1: "v1", +}; + +export function ReferenceVersionSelector({ + activeVersion, + options, +}: { + activeVersion: ReferenceVersion; + options: ReferenceVersionOption[]; +}) { + const [open, setOpen] = useState(false); + const panelRef = useRef(null); + const buttonRef = useRef(null); + + useEffect(() => { + if (!open) return; + + const handleClick = (event: MouseEvent) => { + const target = event.target instanceof Node ? event.target : null; + if (!target) return; + if ( + panelRef.current?.contains(target) || + buttonRef.current?.contains(target) + ) { + return; + } + setOpen(false); + }; + const handleKey = (event: KeyboardEvent) => { + if (event.key === "Escape") setOpen(false); + }; + + document.addEventListener("mousedown", handleClick); + document.addEventListener("keydown", handleKey); + return () => { + document.removeEventListener("mousedown", handleClick); + document.removeEventListener("keydown", handleKey); + }; + }, [open]); + + return ( +
+
+ + + {open && ( +
+ {options.map(({ version, href }) => { + const active = version === activeVersion; + return ( + setOpen(false)} + className={[ + "flex w-full items-center gap-2 rounded px-2 py-1.5 text-[13px] transition-colors", + active + ? "bg-[var(--accent-light)] text-[var(--accent)]" + : "text-[var(--text-secondary)] hover:bg-[var(--bg-elevated)] hover:text-[var(--text)]", + ].join(" ")} + > + + + {VERSION_LABELS[version]} + + + ); + })} +
+ )} +
+
+ ); +} diff --git a/showcase/shell-docs/src/content/reference/v1/classes/llm-adapters/meta.json b/showcase/shell-docs/src/content/reference/v1/classes/llm-adapters/meta.json new file mode 100644 index 00000000000..98130eb5090 --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/classes/llm-adapters/meta.json @@ -0,0 +1,11 @@ +{ + "title": "LLM Adapters", + "pages": [ + "OpenAIAdapter", + "OpenAIAssistantAdapter", + "AnthropicAdapter", + "LangChainAdapter", + "GroqAdapter", + "GoogleGenerativeAIAdapter" + ] +} \ No newline at end of file diff --git a/showcase/shell-docs/src/content/reference/v1/classes/meta.json b/showcase/shell-docs/src/content/reference/v1/classes/meta.json new file mode 100644 index 00000000000..58380111948 --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/classes/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Copilot Runtime", + "pages": [ + "CopilotRuntime", + "llm-adapters", + "CopilotTask" + ] +} \ No newline at end of file diff --git a/showcase/shell-docs/src/content/reference/v1/components/chat/index.mdx b/showcase/shell-docs/src/content/reference/v1/components/chat/index.mdx new file mode 100644 index 00000000000..89199d4ab89 --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/components/chat/index.mdx @@ -0,0 +1,29 @@ +--- +title: All Chat Components +--- +import { LinkIcon } from "lucide-react" + + + v1 chat components are still supported, but we recommend using the [v2 chat components](/reference/v2/components/CopilotChat) for new projects. + + + + } + /> + } + /> + } + /> + diff --git a/showcase/shell-docs/src/content/reference/v1/components/chat/meta.json b/showcase/shell-docs/src/content/reference/v1/components/chat/meta.json new file mode 100644 index 00000000000..e59c4dc6d04 --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/components/chat/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Chat Components", + "pages": [ + "CopilotChat", + "CopilotPopup", + "CopilotSidebar" + ] +} \ No newline at end of file diff --git a/showcase/shell-docs/src/content/reference/v1/components/meta.json b/showcase/shell-docs/src/content/reference/v1/components/meta.json new file mode 100644 index 00000000000..377e750c462 --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/components/meta.json @@ -0,0 +1,8 @@ +{ + "title": "UI Components", + "pages": [ + "chat", + "CopilotTextarea", + "CopilotKit" + ] +} \ No newline at end of file diff --git a/showcase/shell-docs/src/content/reference/v1/hooks/meta.json b/showcase/shell-docs/src/content/reference/v1/hooks/meta.json new file mode 100644 index 00000000000..4dd34969b7c --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/hooks/meta.json @@ -0,0 +1,19 @@ +{ + "title": "hooks", + "pages": [ + "useAgent", + "useDefaultTool", + "useFrontendTool", + "useRenderToolCall", + "useHumanInTheLoop", + "useCopilotReadable", + "useCopilotAdditionalInstructions", + "useCopilotChat", + "useCopilotChatHeadless_c", + "useCopilotChatSuggestions", + "useCoAgent", + "useCoAgentStateRender", + "useLangGraphInterrupt", + "useCopilotAction" + ] +} diff --git a/showcase/shell-docs/src/content/reference/v1/hooks/useAgent.mdx b/showcase/shell-docs/src/content/reference/v1/hooks/useAgent.mdx new file mode 100644 index 00000000000..b54879c6fe6 --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/hooks/useAgent.mdx @@ -0,0 +1,304 @@ +--- +title: "useAgent" +description: "React hook for accessing AG-UI agent instances" +--- + + + `useAgent` is still supported, but we recommend migrating to [`useAgent`](/reference/v2/hooks/useAgent) from the v2 API (`@copilotkit/react-core/v2`). + + +## Overview + +`useAgent` is a React hook that returns an [AG-UI AbstractAgent](https://docs.ag-ui.com/sdk/js/client/abstract-agent) instance. The hook subscribes to agent state changes and triggers re-renders when the agent's state, messages, or execution status changes. + +**Throws error** if no agent is configured with the specified `agentId`. + +## Signature + +```tsx +function useAgent(options?: UseAgentOptions): { agent: AbstractAgent } +``` + +## Parameters + + + Configuration object for the hook. + + + ID of the agent to retrieve. Must match an agent configured in `CopilotKitProvider`. + + + + Controls which agent changes trigger component re-renders. Options: + - `UseAgentUpdate.OnMessagesChanged` - Re-render when messages change + - `UseAgentUpdate.OnStateChanged` - Re-render when state changes + - `UseAgentUpdate.OnRunStatusChanged` - Re-render when execution status changes + + Pass an empty array `[]` to prevent automatic re-renders. + + + +## Return Value + + + Object containing the agent instance. + + + The AG-UI agent instance. See [AbstractAgent documentation](https://docs.ag-ui.com/sdk/js/client/abstract-agent) for full interface details. + + ### Core Properties + + + Unique identifier for the agent instance. + + + + Human-readable description of the agent's purpose. + + + + Unique identifier for the current conversation thread. + + + + Array of conversation messages. Each message contains: + - `id: string` - Unique message identifier + - `role: "user" | "assistant" | "system"` - Message role + - `content: string` - Message content + + + + Shared state object synchronized between application and agent. Both can read and modify this state. + + + + Indicates whether the agent is currently executing. + + + + Enables debug logging for agent events and execution. + + + ### Methods + + + Manually triggers agent execution. + + **Parameters:** + - `options.forwardedProps?: any` - Data to pass to the agent execution context + + **Example:** + ```tsx + await agent.runAgent({ + forwardedProps: { + command: { resume: "user response" } + } + }); + ``` + + + + Updates the shared state. Changes are immediately available to both application and agent. + + **Example:** + ```tsx + agent.setState({ + ...agent.state, + theme: "dark" + }); + ``` + + + + Subscribes to agent events. Returns cleanup function. + + **Subscriber Events:** + - `onCustomEvent?: ({ event: { name: string, value: any } }) => void` - Custom events (e.g., LangGraph interrupts) + - `onRunStartedEvent?: () => void` - Agent execution starts + - `onRunFinalized?: () => void` - Agent execution completes + - `onStateChanged?: (state: any) => void` - State changes + - `onMessagesChanged?: (messages: Message[]) => void` - Messages added/modified + + **Example:** + ```tsx + const { unsubscribe } = agent.subscribe({ + onCustomEvent: ({ event }) => { + console.log(event.name, event.value); + } + }); + + // Cleanup + unsubscribe(); + ``` + + + + Adds a single message to the conversation and notifies subscribers. + + **Example:** + ```tsx + agent.addMessage({ + id: crypto.randomUUID(), + role: "user", + content: "Hello" + }); + ``` + + + + Adds multiple messages to the conversation and notifies subscribers once. + + + + Replaces the entire message history with a new array of messages. + + + + Connects to a streaming agent endpoint. Similar to `runAgent` but uses the `connect()` method for persistent connections. + + + + Detaches from the currently active agent run without aborting it. The run continues in the background but stops updating the local agent state. + + + + Aborts the currently running agent execution. Implementation varies by agent type. + + + + Creates a deep copy of the agent with cloned messages, state, and configuration. + + + + Adds middleware to the agent's execution pipeline. Middlewares can intercept and transform agent runs. + + + + + +## Usage + +### Basic Usage + +```tsx +import { useAgent } from "@copilotkit/react-core/v2"; + +function AgentStatus() { + const { agent } = useAgent(); + + return ( +
+
Agent: {agent.agentId}
+
Messages: {agent.messages.length}
+
Running: {agent.isRunning ? "Yes" : "No"}
+
+ ); +} +``` + +### Accessing State + +```tsx +function StateDisplay() { + const { agent } = useAgent(); + + return
{JSON.stringify(agent.state, null, 2)}
; +} +``` + +### Updating State + +```tsx +function StateController() { + const { agent } = useAgent(); + + return ( + + ); +} +``` + +### Event Subscription + +```tsx +import { useEffect } from "react"; +import { useAgent } from "@copilotkit/react-core/v2"; +import type { AgentSubscriber } from "@ag-ui/client"; + +function EventListener() { + const { agent } = useAgent(); + + useEffect(() => { + const { unsubscribe } = agent.subscribe({ + onRunStartedEvent: () => console.log("Started"), + onRunFinalized: () => console.log("Finished"), + }); + + return unsubscribe; + }, []); + + return null; +} +``` + +### Multiple Agents + +```tsx +function MultiAgentView() { + const { agent: primary } = useAgent({ agentId: "primary" }); + const { agent: support } = useAgent({ agentId: "support" }); + + return ( +
+
Primary: {primary.messages.length}
+
Support: {support.messages.length}
+
+ ); +} +``` + +### Optimizing Re-renders + +Control when your component re-renders using the `updates` parameter: + +```tsx +import { useAgent, UseAgentUpdate } from "@copilotkit/react-core/v2"; + +// Only re-render when messages change +function MessageCount() { + const { agent } = useAgent({ + updates: [UseAgentUpdate.OnMessagesChanged] + }); + + return
Messages: {agent.messages.length}
; +} + +// Manually manage subscriptions (no automatic re-renders) +function ManualSubscription() { + const { agent } = useAgent({ updates: [] }); + + useEffect(() => { + const { unsubscribe } = agent.subscribe({ + onMessagesChanged: () => { + // Handle changes manually + } + }); + return unsubscribe; + }, [agent]); + + return
Manual mode
; +} +``` + +## Behavior + +- **Automatic Re-renders**: Component re-renders when agent state, messages, or execution status changes (configurable via `updates` parameter) +- **Error Handling**: Throws error if no agent exists with specified `agentId` +- **State Synchronization**: State updates via `setState()` are immediately available to both app and agent +- **Event Subscriptions**: Subscribe/unsubscribe pattern for lifecycle and custom events + +## Related + +- [AG-UI AbstractAgent](https://docs.ag-ui.com/sdk/js/client/abstract-agent) - Full agent interface documentation diff --git a/showcase/shell-docs/src/content/reference/v1/hooks/useCopilotAction.mdx b/showcase/shell-docs/src/content/reference/v1/hooks/useCopilotAction.mdx new file mode 100644 index 00000000000..53cae32ece4 --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/hooks/useCopilotAction.mdx @@ -0,0 +1,199 @@ +--- +title: "useCopilotAction" +description: "The useCopilotAction hook allows your copilot to take action in the app." +--- + + + `useCopilotAction` is still supported, but we recommend migrating to [`useFrontendTool`](/reference/v2/hooks/useFrontendTool) from the v2 API. + + +
+ + +`useCopilotAction` is a React hook that you can use in your application to provide +custom actions that can be called by the AI. Essentially, it allows the Copilot to +execute these actions contextually during a chat, based on the user’s interactions +and needs. + +Here's how it works: + +Use `useCopilotAction` to set up actions that the Copilot can call. To provide +more context to the Copilot, you can provide it with a `description` (for example to explain +what the action does, under which conditions it can be called, etc.). + +Then you define the parameters of the action, which can be simple, e.g. primitives like strings or numbers, +or complex, e.g. objects or arrays. + +Finally, you provide a `handler` function that receives the parameters and returns a result. +CopilotKit takes care of automatically inferring the parameter types, so you get type safety +and autocompletion for free. + +To render a custom UI for the action, you can provide a `render()` function. This function +lets you render a custom component or return a string to display. + +## Usage + +### Simple Usage + +```tsx +useCopilotAction({ + name: "sayHello", + description: "Say hello to someone.", + parameters: [ + { + name: "name", + type: "string", + description: "name of the person to say greet", + }, + ], + handler: async ({ name }) => { + alert(`Hello, ${name}!`); + }, +}); +``` + +## Generative UI + +This hooks enables you to dynamically generate UI elements and render them in the copilot chat. For more information, check out the [Generative UI](/generative-ui/your-components/display-only) page. + +## Parameters + + + The function made available to the Copilot. See [Action](#action). + + + The name of the action. + + + + The handler of the action. + + + + A description of the action. This is used to instruct the Copilot on how to + use the action. + + + + Use this property to control when the action is available to the Copilot. When set to `"remote"`, the action is + available only for remote agents. + + + + Whether to report the result of a function call to the LLM which will then provide a follow-up response. Pass `false` to disable + + + + The parameters of the action. See [Parameter](#parameter). + + + The name of the parameter. + + + + The type of the argument. One of: + - `"string"` + - `"number"` + - `"boolean"` + - `"object"` + - `"object[]"` + - `"string[]"` + - `"number[]"` + - `"boolean[]"` + + + + A description of the argument. This is used to instruct the Copilot on what + this argument is used for. + + + + For string arguments, you can provide an array of possible values. + + + + Whether or not the argument is required. Defaults to true. + + + + If the argument is of a complex type, i.e. `object` or `object[]`, this field + lets you define the attributes of the object. For example: + ```js + { + name: "addresses", + description: "The addresses extracted from the text.", + type: "object[]", + attributes: [ + { + name: "street", + type: "string", + description: "The street of the address.", + }, + { + name: "city", + type: "string", + description: "The city of the address.", + }, + // ... + ], + } + ```` + + + + + Render lets you define a custom component or string to render instead of the + default. You can either pass in a string or a function that takes the following props: + +
+ + - `"inProgress"`: arguments are dynamically streamed to the function, allowing you to adjust your UI in real-time. + - `"executing"`: The action handler is executing. + - `"complete"`: The action handler has completed execution. + + + + The arguments passed to the action in real time. When the status is `"inProgress"`, they are + possibly incomplete. + + + + The result returned by the action. It is only available when the status is `"complete"`. + +
+
+ + + This is similar to `render`, but provides a `respond` function in the props that you must call with the user's response. The component will remain rendered until `respond` is called. The response will be passed as the result to the action handler. +
+ + - `"inProgress"`: arguments are dynamically streamed to the function, allowing you to adjust your UI in real-time. + - `"executing"`: The action handler is executing. + - `"complete"`: The action handler has completed execution. + + + + The arguments passed to the action in real time. When the status is `"inProgress"`, they are + possibly incomplete. + + + + A function that must be called with the user's response. The response will be passed as the result to the action handler. + Only available when status is `"executing"`. + + + + The result returned by the action. It is only available when the status is `"complete"`. + +
+
+ +
+ + + An optional array of dependencies. + diff --git a/showcase/shell-docs/src/content/reference/v1/hooks/useDefaultTool.mdx b/showcase/shell-docs/src/content/reference/v1/hooks/useDefaultTool.mdx new file mode 100644 index 00000000000..464d62c79e2 --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/hooks/useDefaultTool.mdx @@ -0,0 +1,140 @@ +--- +title: "useDefaultTool" +description: "The useDefaultTool hook enables rendering of a default UI which catches any tool that does not have a specific renderer." +--- + + + `useDefaultTool` is still supported, but we recommend migrating to [`useFrontendTool`](/reference/v2/hooks/useFrontendTool) from the v2 API. + + +`useDefaultTool` is a React hook that allows you to render custom UI for any tool +call that doesn't have a specific renderer + +## Usage + +```tsx +import { useDefaultTool } from "@copilotkit/react-core"; + +useDefaultTool({ + render: ({ name, args, status, result }) => { + return ( +
+
+

{name}

+ + {status === "inProgress" && "Running..."} + {status === "executing" && "Executing..."} + {status === "complete" && "Complete"} + +
+ + {Object.keys(args).length > 0 && ( +
+

Parameters:

+
+              {JSON.stringify(args, null, 2)}
+            
+
+ )} + + {status === "complete" && result && ( +
+

Result:

+
+              {JSON.stringify(result, null, 2)}
+            
+
+ )} +
+ ); + }, +}); +``` + +### Rendering Model Context Protocol (MCP) Tools + +```tsx +import { useDefaultTool } from "@copilotkit/react-core"; + +// Render any MCP tool call with a custom UI +useDefaultTool({ + render: ({ name, args, status, result }) => { + // Custom rendering for MCP tools + if (name.startsWith("mcp_")) { + return ; + } + + // Default rendering for other tools + return ; + }, +}); +``` + +## Parameters + + + The tool rendering configuration object. + + A React component that renders the tool call UI. The component receives props with: + +
+ + - `"inProgress"`: Tool is being prepared or arguments are being streamed. + - `"executing"`: Tool is actively running. + - `"complete"`: Tool execution has finished. + + + + The arguments passed to the tool. Type-safe if parameters schema is provided. + For catch-all renderers (`name: "*"`), this will be `any`. + + + + The result returned by the tool. Only available when status is `"complete"`. + + + + The actual name of the tool being executed. Particularly useful for + catch-all renderers to know which tool is being rendered. + + + + The description of the tool being executed. + +
+
+
+ + + An optional array of dependencies. + + +## Common Use Cases + +1. **Backend Tool Visualization**: Display progress and results of long-running backend operations +2. **Generic Tool Rendering**: Provide a fallback UI for any tool without specific rendering +3. **MCP Tool Integration**: Render Model Context Protocol tools from various sources +4. **Debugging**: Display all tool calls during development +5. **Analytics**: Track and display tool usage + +## Migration from useCopilotAction + +If you're migrating from `useCopilotAction` with only a `render` function: + +```tsx +// Before with useCopilotAction +useCopilotAction({ + render: ({ name, args, status, result }) => ( + + ), +}); + +// After with useDefaultTool +useDefaultTool({ + render: ({ name, args, status, result }) => ( + + ), +}); +``` + +The migration is straightforward - just change the hook name. The render props remain the same. diff --git a/showcase/shell-docs/src/content/reference/v1/hooks/useFrontendTool.mdx b/showcase/shell-docs/src/content/reference/v1/hooks/useFrontendTool.mdx new file mode 100644 index 00000000000..c2b098e9fa5 --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/hooks/useFrontendTool.mdx @@ -0,0 +1,187 @@ +--- +title: "useFrontendTool" +description: "The useFrontendTool hook allows the Copilot to execute tools in the frontend." +--- + + + `useFrontendTool` is still supported, but we recommend migrating to [`useFrontendTool`](/reference/v2/hooks/useFrontendTool) from the v2 API, which uses Zod schemas for parameters. + + +`useFrontendTool` allows you to define executable actions that the AI can call with a handler function. +This is the primary way to give your AI agent the ability to perform actions in your application—whether +that's updating state, making API calls, or triggering side effects. + +The hook requires three main pieces: +1. A name and description so the AI knows when to call it +2. A parameters definition describing what inputs the tool accepts +3. A handler function that executes when the AI calls the tool + +Optionally, you can provide a `render` function to display custom UI showing the tool's execution +status and results in the chat interface. + +## Usage + +### Simple Usage + +```tsx +import { useFrontendTool } from "@copilotkit/react-core"; + +useFrontendTool({ + name: "sayHello", + description: "Say hello to someone.", + parameters: [ + { + name: "name", + type: "string", + description: "name of the person to greet", + required: true, + }, + ], + handler: async ({ name }) => { + alert(`Hello, ${name}!`); + }, +}); +``` + +### With Custom UI Rendering + +```tsx +import { useFrontendTool } from "@copilotkit/react-core"; + +useFrontendTool({ + name: "showWeatherCard", + description: "Display weather information for a location", + parameters: [ + { + name: "location", + type: "string", + description: "The location to show weather for", + required: true, + }, + { + name: "temperature", + type: "number", + description: "Temperature in celsius", + required: true, + }, + ], + handler: async ({ location, temperature }) => { + // Fetch and return weather data + return { location, temperature, conditions: "Sunny" }; + }, + render: ({ args, status, result }) => { + if (status === "inProgress") { + return
Loading weather for {args.location}...
; + } + if (status === "complete" && result) { + return ( + + ); + } + return null; + }, +}); +``` + +## Generative UI + +This hook enables you to dynamically generate UI elements and render them in the copilot chat. For more information, check out the [Generative UI](/generative-ui/your-components/display-only) page. + +## Migration from useCopilotAction + +If you're migrating from `useCopilotAction`, here are the key differences: + +1. The render component props include `name` and `description` + +### Migration Example + +```tsx +// Before with useCopilotAction +useCopilotAction({ + name: "addTodo", + parameters: [ + { + name: "text", + type: "string", + description: "The todo text", + required: true, + }, + ], + handler: ({ text }) => { + addTodo(text); + }, +}); + +// After with useFrontendTool +useFrontendTool({ + name: "addTodo", + parameters: [ + { + name: "text", + type: "string", + description: "The todo text", + required: true, + }, + ], + handler: ({ text }) => { + addTodo(text); + }, +}); +``` + +## Parameters + + +The name of the tool. + + + +A description of the tool. This is used to instruct the Copilot on how to use the tool. + + + +Array of parameter definitions for the tool. Each parameter object should have: +- `name` (string): The parameter name +- `type` (string): The parameter type (e.g., "string", "number", "boolean", "string[]", "object") +- `description` (string): A description of what the parameter is for +- `required` (boolean): Whether the parameter is required +- `properties` (array, optional): For object types, define nested properties using the same schema + +Simple example: `[{ name: "query", type: "string", description: "The search query", required: true }]` + +Nested example: +```typescript +[ + { + name: "user", + type: "object", + description: "User information", + required: true, + properties: [ + { name: "name", type: "string", description: "User's name", required: true }, + { name: "age", type: "number", description: "User's age", required: false } + ] + } +] +``` + + + +The handler function that executes the tool logic. + + + +Whether to report the result of the tool call to the LLM which will then provide a follow-up response. Pass `false` to disable. + + + +A React component that renders custom UI for the tool. + + + +Whether the tool is available. Set to "disabled" to prevent the tool from being called. + diff --git a/showcase/shell-docs/src/content/reference/v1/hooks/useHumanInTheLoop.mdx b/showcase/shell-docs/src/content/reference/v1/hooks/useHumanInTheLoop.mdx new file mode 100644 index 00000000000..7a188296203 --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/hooks/useHumanInTheLoop.mdx @@ -0,0 +1,237 @@ +--- +title: "useHumanInTheLoop" +description: "The useHumanInTheLoop hook enables human approval and interaction workflows." +--- + + + `useHumanInTheLoop` is still supported, but we recommend migrating to [`useHumanInTheLoop`](/reference/v2/hooks/useHumanInTheLoop) from the v2 API. + + +`useHumanInTheLoop` pauses AI execution to request human input or approval. When the AI calls this +tool, it stops and waits for the user to respond through your custom UI before continuing. This is +essential for sensitive operations, confirmations, or collecting information that only the user can provide. + +Unlike `useFrontendTool`, there's no handler function—instead, your render function receives a `respond` +callback that sends the user's input back to the AI. The AI execution remains paused until `respond` is called, +making this a true blocking interaction. + +## Usage + +### Simple Confirmation Example + +```tsx +import { useHumanInTheLoop } from "@copilotkit/react-core"; + +useHumanInTheLoop({ + name: "confirmDeletion", + description: "Ask user to confirm before deleting items", + parameters: [ + { + name: "itemName", + type: "string", + description: "Name of the item to delete", + required: true, + }, + { + name: "itemCount", + type: "number", + description: "Number of items to delete", + required: true, + }, + ], + render: ({ args, status, respond, result }) => { + if (status === "executing" && respond) { + return ( +
+

Are you sure you want to delete {args.itemCount} {args.itemName}(s)?

+
+ + +
+
+ ); + } + + if (status === "complete" && result) { + return ( +
+ {result.confirmed ? "Items deleted" : "Deletion cancelled"} +
+ ); + } + + return null; + }, +}); +``` + +### Complex Input Collection Example + +```tsx +import { useHumanInTheLoop } from "@copilotkit/react-core"; +import { useState } from "react"; + +useHumanInTheLoop({ + name: "collectUserPreferences", + description: "Collect detailed preferences from the user", + parameters: [ + { + name: "context", + type: "string", + description: "Context for why preferences are needed", + required: true, + }, + { + name: "requiredFields", + type: "string[]", + description: "Fields to collect", + required: true, + }, + ], + render: ({ args, status, respond }) => { + const [preferences, setPreferences] = useState({ + theme: "light", + notifications: true, + language: "en", + }); + + if (status === "executing" && respond) { + return ( +
+

{args.context}

+
{ + e.preventDefault(); + respond(preferences); + }}> + +
+
+ ); + } + + return null; + }, +}); +``` + +## Best Practices + +1. Always check for the `respond` function before rendering interactive elements +2. Handle all status states to provide good user feedback +3. Validate user input before calling `respond` +4. Provide clear instructions in your UI about what input is expected +5. Consider timeout scenarios for time-sensitive operations + +## Migration from useCopilotAction + +If you're migrating from `useCopilotAction` with `renderAndWaitForResponse`: + +```tsx +// Before with useCopilotAction +useCopilotAction({ + name: "confirmAction", + parameters: [ + { name: "message", type: "string", required: true }, + ], + renderAndWaitForResponse: ({ args, respond, status }) => { + return ( + respond(true)} + onCancel={() => respond(false)} + isActive={status === "executing"} + /> + ); + }, +}); + +// After with useHumanInTheLoop +useHumanInTheLoop({ + name: "confirmAction", + parameters: [ + { + name: "message", + type: "string", + description: "The message to display", + required: true, + }, + ], + render: ({ args, respond, status }) => { + if (status === "executing" && respond) { + return ( + respond(true)} + onCancel={() => respond(false)} + isActive={true} + /> + ); + } + return null; + }, +}); +``` + +The main differences are: +1. The property is called `render` instead of `renderAndWaitForResponse` +2. You need to check for the `respond` function's existence + +## Parameters + + +The name of the tool. + + + +A description of the tool. This is used to instruct the Copilot on when to request human input. + + + +Array of parameter definitions that will be passed to the render function. Each parameter object should have: +- `name` (string): The parameter name +- `type` (string): The parameter type (e.g., "string", "number", "boolean", "string[]", "object") +- `description` (string): A description of what the parameter is for +- `required` (boolean): Whether the parameter is required +- `properties` (array, optional): For object types, define nested properties using the same schema + +Simple example: `[{ name: "itemName", type: "string", description: "Name of the item", required: true }]` + +Nested example: +```typescript +[ + { + name: "approval", + type: "object", + description: "Approval request details", + required: true, + properties: [ + { name: "action", type: "string", description: "Action requiring approval", required: true }, + { name: "reason", type: "string", description: "Reason for the action", required: false } + ] + } +] +``` + + + +A React component that renders the interactive UI for human input. The component receives props including `args`, `status`, and `respond` function. + + + +Whether the tool is available. Set to "disabled" to prevent the tool from being called. + diff --git a/showcase/shell-docs/src/content/reference/v1/hooks/useLangGraphInterrupt.mdx b/showcase/shell-docs/src/content/reference/v1/hooks/useLangGraphInterrupt.mdx new file mode 100644 index 00000000000..9b2ce595c14 --- /dev/null +++ b/showcase/shell-docs/src/content/reference/v1/hooks/useLangGraphInterrupt.mdx @@ -0,0 +1,77 @@ +--- +title: "useLangGraphInterrupt" +description: "The useLangGraphInterrupt hook allows setting the generative UI to be displayed on LangGraph's Interrupt event." +--- + +
+