forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcatalog-utils.ts
More file actions
138 lines (123 loc) · 4.46 KB
/
Copy pathcatalog-utils.ts
File metadata and controls
138 lines (123 loc) · 4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import { basicCatalog } from "./a2ui-react";
import type { ComponentApi, Catalog } from "@a2ui/web_core/v0_9";
import { zodToJsonSchema } from "zod-to-json-schema";
const BASIC_CATALOG_ID =
"https://a2ui.org/specification/v0_9/basic_catalog.json";
/**
* Context description used to identify the A2UI component schema in RunAgentInput.context.
* Must match the constant in @ag-ui/a2ui-middleware so the middleware can overwrite
* a frontend-provided schema with a server-side one.
*/
export const A2UI_SCHEMA_CONTEXT_DESCRIPTION =
"A2UI Component Schema — available components for generating UI surfaces. Use these component names and properties when creating A2UI operations.";
/**
* Check whether a catalog is a superset of the basic catalog
* (i.e., it contains all basic components by name).
*/
export function extendsBasicCatalog(catalog: Catalog<ComponentApi>): boolean {
for (const name of basicCatalog.components.keys()) {
if (!catalog.components.has(name)) {
return false;
}
}
return true;
}
/**
* Return the names of components in a catalog that are not in the basic catalog.
*/
export function getCustomComponentNames(
catalog: Catalog<ComponentApi>,
): string[] {
const custom: string[] = [];
for (const name of catalog.components.keys()) {
if (!basicCatalog.components.has(name)) {
custom.push(name);
}
}
return custom;
}
/**
* Build a context string describing the available A2UI catalog and custom components.
* Custom components (those not in the basic catalog) are described using their
* JSON Schema representation, matching the canonical A2UI catalog format.
*/
export function buildCatalogContextValue(
catalog?: Catalog<ComponentApi>,
): string {
const resolved = catalog ?? basicCatalog;
const lines: string[] = [];
lines.push("Available A2UI catalog:");
if (resolved.id === BASIC_CATALOG_ID) {
lines.push(`- ${resolved.id} (basic catalog)`);
return lines.join("\n");
}
const isSuperset = extendsBasicCatalog(resolved);
const customNames = getCustomComponentNames(resolved);
lines.push(`- ${resolved.id}`);
if (isSuperset) {
lines.push(
" Extends the basic catalog with all standard components plus:",
);
} else {
lines.push(" Custom catalog (does NOT include all basic components).");
lines.push(" Custom components:");
}
for (const name of customNames) {
const comp = resolved.components.get(name);
if (!comp) continue;
const jsonSchema = zodToJsonSchema(comp.schema);
lines.push(` - ${name}:`);
lines.push(
` ${JSON.stringify(jsonSchema, null, 2).split("\n").join("\n ")}`,
);
}
return lines.join("\n");
}
/**
* A2UI v0.9 inline catalog format — matches the structure defined by the
* A2UI specification (basic_catalog.json). Each component is keyed by
* name and uses `allOf` to compose ComponentCommon with component-specific
* properties so the schema mirrors the flat wire format the LLM must produce.
*/
export interface InlineCatalogSchema {
catalogId: string;
components: Record<string, Record<string, unknown>>;
}
/**
* Extract component schemas from a catalog in the A2UI v0.9 inline catalog
* format. This mirrors `generateInlineCatalog` from `@a2ui/web_core` so
* the schema the LLM sees matches the spec and the flat wire format:
*
* { "Column": { "allOf": [
* { "$ref": "common_types.json#/$defs/ComponentCommon" },
* { "properties": { "component": {"const":"Column"}, "gap": ..., "children": ... },
* "required": ["component"] }
* ]}}
*
* When sent via `useAgentContext` with `A2UI_SCHEMA_CONTEXT_DESCRIPTION`,
* the middleware can optionally overwrite it with a server-side schema.
*/
export function extractCatalogComponentSchemas(
catalog?: Catalog<ComponentApi>,
): InlineCatalogSchema {
const resolved = catalog ?? basicCatalog;
const components: Record<string, Record<string, unknown>> = {};
for (const [name, comp] of resolved.components) {
const zodSchema = zodToJsonSchema(comp.schema, {
target: "jsonSchema2019-09",
}) as { properties?: Record<string, unknown>; required?: string[] };
components[name] = {
allOf: [
{ $ref: "common_types.json#/$defs/ComponentCommon" },
{
properties: {
component: { const: name },
...(zodSchema.properties ?? {}),
},
required: ["component", ...(zodSchema.required ?? [])],
},
],
};
}
return { catalogId: resolved.id, components };
}