mirror of
https://github.com/CopilotKit/CopilotKit.git
synced 2026-09-14 16:26:20 +08:00
364 lines
12 KiB
TypeScript
364 lines
12 KiB
TypeScript
import registryData from "@/data/registry.json";
|
|
|
|
export interface Feature {
|
|
id: string;
|
|
name: string;
|
|
category: string;
|
|
description: string;
|
|
}
|
|
|
|
export interface FeatureCategory {
|
|
id: string;
|
|
name: string;
|
|
}
|
|
|
|
export interface Demo {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
tags: string[];
|
|
route: string;
|
|
animated_preview_url?: string | null;
|
|
}
|
|
|
|
export interface Integration {
|
|
name: string;
|
|
slug: string;
|
|
category: string;
|
|
language: string;
|
|
logo?: string;
|
|
description: string;
|
|
partner_docs: string | null;
|
|
repo: string;
|
|
copilotkit_version: string;
|
|
backend_url: string;
|
|
deployed: boolean;
|
|
/**
|
|
* How shell-docs renders this framework's docs pages.
|
|
* - `generated` (default): data-driven `FrameworkOverview` + agnostic
|
|
* root MDX merged with per-framework overrides. Kept for the three
|
|
* "ready" frameworks (langgraph-{python,typescript}, google-adk).
|
|
* - `authored`: render the per-framework MDX tree under
|
|
* `content/docs/integrations/<docsFolder>/` with its own sidebar
|
|
* (built from that folder's meta.json). Root MDX may still be used
|
|
* as a fallback for intentionally shared pages.
|
|
* - `hidden`: exclude from the docs site entirely — no `/<slug>`
|
|
* route, no switcher entry. Single toggle for "framework has no
|
|
* v1 docs to port" (or otherwise should not appear in docs yet).
|
|
*
|
|
* Source of truth: `showcase/integrations/<slug>/manifest.yaml`'s
|
|
* `docs_mode` field.
|
|
*/
|
|
docs_mode?: "generated" | "authored" | "hidden";
|
|
generative_ui?: string[];
|
|
interaction_modalities?: string[];
|
|
/**
|
|
* Implementation pattern for `a2ui-fixed-schema`. Set only when the
|
|
* feature is wired in this integration. Drives `<WhenFrameworkHas>`
|
|
* gating in the docs.
|
|
*
|
|
* - `schema-loading`: backend loads the schema from a JSON file at
|
|
* startup (e.g. `a2ui.load_schema(path)`).
|
|
* - `schema-inline`: schema is declared inline as a typed literal in
|
|
* source (e.g. spring-ai `List.of(Map.of(...))`, .NET C# array).
|
|
* - `llm-driven`: backend generates the schema dynamically via a
|
|
* secondary LLM call (e.g. mastra `generateA2uiTool`, strands
|
|
* `generate_a2ui` tool).
|
|
*/
|
|
a2ui_pattern?: "schema-loading" | "schema-inline" | "llm-driven" | null;
|
|
/**
|
|
* Whether the A2UI docs should additionally show how to attach the
|
|
* fixed-schema tool to a hand-built graph rather than the cell's agent
|
|
* factory. Set only where the rendered snippet's language matches the
|
|
* integration's own — `langgraph-typescript` is deliberately left unset
|
|
* because the snippet is Python.
|
|
*
|
|
* - `langgraph-state-graph`: render the Python `StateGraph` + `ToolNode`
|
|
* form next to the `create_agent` snippet.
|
|
*/
|
|
a2ui_agent_form?: "langgraph-state-graph" | null;
|
|
/**
|
|
* Implementation pattern for `gen-ui-interrupt` / `interrupt-headless`.
|
|
* Set only when at least one is wired.
|
|
*
|
|
* - `native`: framework has a real interrupt primitive (LangGraph
|
|
* `interrupt()` + `useInterrupt`).
|
|
* - `promise-based`: demo uses `useFrontendTool` with a Promise-based
|
|
* handler (ms-agent-python, ms-agent-dotnet).
|
|
*/
|
|
interrupt_pattern?: "native" | "promise-based" | null;
|
|
/**
|
|
* Framework-specific pattern for aligning CopilotKit Intelligence threads
|
|
* with an external framework's own persistence/session
|
|
* identifiers.
|
|
*
|
|
* - `langgraph`: explicit CopilotKit thread IDs are forwarded as AG-UI
|
|
* `threadId` and can be aligned with LangGraph checkpoint/thread IDs
|
|
* when the backend accepts them.
|
|
* - `adk-session`: CopilotKit thread IDs may be mapped to ADK session
|
|
* IDs; ADK durability still depends on the configured ADK session
|
|
* service.
|
|
*/
|
|
thread_persistence_pattern?: "langgraph" | "adk-session" | null;
|
|
agent_config_pattern?: "shared-state" | "runtime-properties" | null;
|
|
auth_pattern?:
|
|
| "langgraph"
|
|
| "ag2-context-variables"
|
|
| "microsoft-agent-framework"
|
|
| "runtime-onrequest"
|
|
| null;
|
|
voice_backend_pattern?: "adk-fastapi-agent-path" | null;
|
|
sort_order?: number;
|
|
managed_platform?: { name: string; url: string };
|
|
animated_preview_url?: string | null;
|
|
starter?: {
|
|
path: string;
|
|
name: string;
|
|
description?: string;
|
|
github_url?: string;
|
|
demo_url?: string;
|
|
clone_command?: string;
|
|
};
|
|
features: string[];
|
|
demos: Demo[];
|
|
}
|
|
|
|
export interface Registry {
|
|
feature_registry: {
|
|
version: string;
|
|
categories: FeatureCategory[];
|
|
features: Feature[];
|
|
};
|
|
integrations: Integration[];
|
|
}
|
|
|
|
const registry = registryData as Registry;
|
|
|
|
/**
|
|
* The soft-default framework whose authored docs are served at the ROOT
|
|
* URL surface (`/quickstart`, `/server-tools`, …) instead of under a
|
|
* `/<framework>/` prefix. `/built-in-agent/:path*` permanently
|
|
* redirects to `/:path*` (next.config.ts).
|
|
*
|
|
* Client components must not import this (registry.json would leak into
|
|
* the client bundle) — they use DEFAULT_FRAMEWORK in
|
|
* `components/framework-provider.tsx`, which mirrors this value.
|
|
*/
|
|
export const ROOT_FRAMEWORK = "built-in-agent";
|
|
|
|
const DOCS_ONLY_INTEGRATIONS: Integration[] = [
|
|
{
|
|
name: "Deep Agents",
|
|
slug: "deepagents",
|
|
category: "popular",
|
|
language: "python",
|
|
description:
|
|
"LangChain Deep Agents connected to CopilotKit chat, state, tools, and generative UI.",
|
|
partner_docs: null,
|
|
repo: "",
|
|
copilotkit_version: "",
|
|
backend_url: "",
|
|
deployed: true,
|
|
docs_mode: "authored",
|
|
sort_order: 13,
|
|
features: [],
|
|
demos: [],
|
|
},
|
|
];
|
|
|
|
function allIntegrations(): Integration[] {
|
|
const registeredSlugs = new Set(registry.integrations.map((i) => i.slug));
|
|
return [
|
|
...registry.integrations,
|
|
...DOCS_ONLY_INTEGRATIONS.filter((i) => !registeredSlugs.has(i.slug)),
|
|
];
|
|
}
|
|
|
|
export function getRegistry(): Registry {
|
|
return registry;
|
|
}
|
|
|
|
export function getIntegrations(): Integration[] {
|
|
return allIntegrations();
|
|
}
|
|
|
|
export function getIntegration(slug: string): Integration | undefined {
|
|
return allIntegrations().find((i) => i.slug === slug);
|
|
}
|
|
|
|
/**
|
|
* Frameworks that have no `showcase/integrations/<slug>/` package (and
|
|
* therefore no `manifest.yaml`) but DO have a `frameworkOverviews`
|
|
* entry and/or per-framework docs MDX. These are the "docs-only"
|
|
* frameworks (`a2a`, `agent-spec`, `deepagents`). They never come
|
|
* through the registry, so `docs_mode` resolution falls through to
|
|
* this map. Keep entries here in sync with
|
|
* `showcase/shell-docs/src/data/frameworks/index.ts` if a new docs-
|
|
* only framework is added.
|
|
*/
|
|
const DOCS_ONLY_FRAMEWORK_MODES: Record<string, "generated" | "authored"> = {
|
|
a2a: "generated",
|
|
"agent-spec": "generated",
|
|
deepagents: "authored",
|
|
};
|
|
|
|
/**
|
|
* Resolve the docs rendering mode for a framework slug. The integration
|
|
* record's `docs_mode` wins; docs-only frameworks fall back to the map
|
|
* above; everything else defaults to `generated` for backwards
|
|
* compatibility with manifests that haven't been updated yet.
|
|
*/
|
|
export function getDocsMode(slug: string): "generated" | "authored" | "hidden" {
|
|
const integration = getIntegration(slug);
|
|
if (integration?.docs_mode) return integration.docs_mode;
|
|
if (DOCS_ONLY_FRAMEWORK_MODES[slug]) return DOCS_ONLY_FRAMEWORK_MODES[slug];
|
|
return "generated";
|
|
}
|
|
|
|
/**
|
|
* Maps a registry slug to the `integrations/<folder>/` directory name
|
|
* that holds its framework-unique docs content. Most slugs match their
|
|
* folder 1:1. These overrides exist because:
|
|
*
|
|
* - Three LangChain/LangGraph URL variants (`-python`, `-typescript`,
|
|
* `-fastapi`) read from one shared `langgraph/` tree, with
|
|
* in-page `<Tabs>` and `<TailoredContent>` handling the per-variant
|
|
* code examples. The URL slug determines which tab opens by default
|
|
* (see TAB_DEFAULTS_BY_SLUG below).
|
|
* - `microsoft-agent-framework/` serves `ms-agent-dotnet`,
|
|
* `ms-agent-python`, and `ms-agent-harness-dotnet`, same in-page-tabs
|
|
* pattern.
|
|
* - `google-adk` / `strands` are legacy renames — the slug changed in
|
|
* the registry but the docs folder still uses the earlier name.
|
|
*
|
|
* Unlisted slugs default to the slug itself, so registry entries
|
|
* whose folder already matches their slug need no entry here.
|
|
*/
|
|
const DOCS_FOLDER_OVERRIDES: Record<string, string> = {
|
|
"langgraph-python": "langgraph",
|
|
"langgraph-typescript": "langgraph",
|
|
"langgraph-fastapi": "langgraph",
|
|
"google-adk": "adk",
|
|
"crewai-crews": "crewai-flows",
|
|
strands: "aws-strands",
|
|
"strands-typescript": "aws-strands",
|
|
"ms-agent-dotnet": "microsoft-agent-framework",
|
|
"ms-agent-python": "microsoft-agent-framework",
|
|
"ms-agent-harness-dotnet": "microsoft-agent-framework",
|
|
};
|
|
|
|
export function getDocsFolder(slug: string): string {
|
|
return DOCS_FOLDER_OVERRIDES[slug] ?? slug;
|
|
}
|
|
|
|
/**
|
|
* Per-slug default-tab selections for the in-page `<Tabs>` component,
|
|
* keyed by the MDX `groupId` prop. When a page renders under one of
|
|
* these slugs, any tab whose `groupId` matches opens with the mapped
|
|
* value pre-selected — so `/langgraph-typescript/configurable` opens
|
|
* the TypeScript tab, `/ms-agent-dotnet/auth` opens .NET, etc.
|
|
*
|
|
* The MDX still authors `items={['Python', 'TypeScript']}` once; only
|
|
* the initially-selected label differs per URL variant. Unmapped
|
|
* slugs, or tabs with a `groupId` not listed here, fall back to the
|
|
* component's existing behavior (first label wins).
|
|
*/
|
|
const TAB_DEFAULTS_BY_SLUG: Record<string, Record<string, string>> = {
|
|
"langgraph-python": {
|
|
language_langgraph_agent: "Python",
|
|
deployment_method: "LangSmith",
|
|
},
|
|
"langgraph-typescript": {
|
|
language_langgraph_agent: "TypeScript",
|
|
},
|
|
"langgraph-fastapi": {
|
|
language_langgraph_agent: "Python",
|
|
deployment_method: "FastAPI",
|
|
},
|
|
// strands and strands-typescript share the aws-strands/ docs folder, whose
|
|
// pages carry Python/TypeScript language tabs (groupId
|
|
// "language_strands_agent"). Default each framework to its own language so
|
|
// the TS framework opens on the TS snippets (mirrors the langgraph split).
|
|
strands: {
|
|
language_strands_agent: "Python",
|
|
},
|
|
"strands-typescript": {
|
|
language_strands_agent: "TypeScript",
|
|
},
|
|
"ms-agent-dotnet": {
|
|
"language_microsoft-agent-framework_agent": ".NET",
|
|
},
|
|
"ms-agent-python": {
|
|
"language_microsoft-agent-framework_agent": "Python",
|
|
},
|
|
"ms-agent-harness-dotnet": {
|
|
"language_microsoft-agent-framework_agent": ".NET",
|
|
},
|
|
};
|
|
|
|
export function getTabDefault(
|
|
slug: string | null | undefined,
|
|
groupId: string | undefined,
|
|
): string | undefined {
|
|
if (!slug || !groupId) return undefined;
|
|
return TAB_DEFAULTS_BY_SLUG[slug]?.[groupId];
|
|
}
|
|
|
|
export function getFeatures(): Feature[] {
|
|
return registry.feature_registry.features;
|
|
}
|
|
|
|
export function getFeature(id: string): Feature | undefined {
|
|
return registry.feature_registry.features.find((f) => f.id === id);
|
|
}
|
|
|
|
export function getFeatureCategories(): FeatureCategory[] {
|
|
return registry.feature_registry.categories;
|
|
}
|
|
|
|
export function getIntegrationsByCategory(): Record<string, Integration[]> {
|
|
const grouped: Record<string, Integration[]> = {};
|
|
for (const integration of getIntegrations()) {
|
|
if (!grouped[integration.category]) {
|
|
grouped[integration.category] = [];
|
|
}
|
|
grouped[integration.category].push(integration);
|
|
}
|
|
return grouped;
|
|
}
|
|
|
|
export function getDemo(
|
|
integrationSlug: string,
|
|
demoId: string,
|
|
): { integration: Integration; demo: Demo } | undefined {
|
|
const integration = getIntegration(integrationSlug);
|
|
if (!integration) return undefined;
|
|
const demo = integration.demos.find((d) => d.id === demoId);
|
|
if (!demo) return undefined;
|
|
return { integration, demo };
|
|
}
|
|
|
|
const CATEGORY_LABELS: Record<string, string> = {
|
|
popular: "Most Popular",
|
|
"agent-framework": "Agent Frameworks",
|
|
"enterprise-platform": "Intelligence",
|
|
"provider-sdk": "Provider SDKs",
|
|
protocol: "Protocols & Standards",
|
|
emerging: "Emerging",
|
|
starter: "Getting Started",
|
|
};
|
|
|
|
export function getCategoryLabel(slug: string): string {
|
|
return CATEGORY_LABELS[slug] || slug;
|
|
}
|
|
|
|
const LANGUAGE_LABELS: Record<string, string> = {
|
|
python: "Python",
|
|
typescript: "TypeScript",
|
|
dotnet: ".NET",
|
|
};
|
|
|
|
export function getLanguageLabel(lang: string): string {
|
|
return LANGUAGE_LABELS[lang] || lang;
|
|
}
|