@lantos1618/better-ui 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -2
- package/dist/agui/index.d.mts +116 -0
- package/dist/agui/index.d.ts +116 -0
- package/dist/agui/index.js +328 -0
- package/dist/agui/index.mjs +156 -0
- package/dist/auth/index.mjs +1 -1
- package/dist/chunk-CIESM3BP.mjs +33 -0
- package/dist/chunk-XDWHMRBN.mjs +159 -0
- package/dist/components/index.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/mcp/index.d.mts +13 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/index.js +78 -0
- package/dist/mcp/index.mjs +87 -141
- package/dist/persistence/index.mjs +1 -1
- package/dist/react/index.mjs +1 -1
- package/package.json +12 -3
- package/dist/chunk-Y6FXYEAI.mjs +0 -10
package/README.md
CHANGED
|
@@ -52,6 +52,7 @@ npm install @lantos1618/better-ui zod
|
|
|
52
52
|
|---------|------|
|
|
53
53
|
| **View integration** | Tools render their own results — no other framework does this |
|
|
54
54
|
| **MCP server** | Expose any tool registry to Claude Desktop, Cursor, VS Code |
|
|
55
|
+
| **AG-UI protocol** | Compatible with CopilotKit, LangChain, Google ADK frontends |
|
|
55
56
|
| **Multi-provider** | OpenAI, Anthropic, Google Gemini, OpenRouter |
|
|
56
57
|
| **Streaming views** | Progressive partial data rendering |
|
|
57
58
|
| **Drop-in chat** | `<Chat />` component with automatic tool view rendering |
|
|
@@ -404,6 +405,26 @@ zodToJsonSchema(z.object({
|
|
|
404
405
|
|
|
405
406
|
---
|
|
406
407
|
|
|
408
|
+
## AG-UI Protocol
|
|
409
|
+
|
|
410
|
+
Expose your tools via the [AG-UI (Agent-User Interaction Protocol)](https://docs.ag-ui.com) — compatible with CopilotKit, LangChain, Google ADK, and any AG-UI frontend.
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
import { createAGUIServer } from '@lantos1618/better-ui/agui';
|
|
414
|
+
|
|
415
|
+
const server = createAGUIServer({
|
|
416
|
+
name: 'my-tools',
|
|
417
|
+
tools: { weather, search },
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// Next.js route handler — returns SSE event stream
|
|
421
|
+
export const POST = server.handler();
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
The handler emits standard AG-UI events (`RUN_STARTED`, `TOOL_CALL_START`, `TOOL_CALL_ARGS`, `TOOL_CALL_RESULT`, `TOOL_CALL_END`, `RUN_FINISHED`) over Server-Sent Events.
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
407
428
|
## Providers
|
|
408
429
|
|
|
409
430
|
```typescript
|
|
@@ -532,8 +553,10 @@ src/
|
|
|
532
553
|
types.ts PersistenceAdapter interface
|
|
533
554
|
memory.ts In-memory adapter
|
|
534
555
|
mcp/
|
|
535
|
-
server.ts MCP server (stdio + HTTP)
|
|
556
|
+
server.ts MCP server (stdio + HTTP + SSE)
|
|
536
557
|
schema.ts Zod → JSON Schema converter
|
|
558
|
+
agui/
|
|
559
|
+
server.ts AG-UI protocol server (SSE)
|
|
537
560
|
examples/
|
|
538
561
|
nextjs-demo/ Full Next.js demo app
|
|
539
562
|
vite-demo/ Vite + Express demo app
|
|
@@ -545,7 +568,7 @@ examples/
|
|
|
545
568
|
```bash
|
|
546
569
|
npm install
|
|
547
570
|
npm run build # Build library
|
|
548
|
-
npm test # Run tests (
|
|
571
|
+
npm test # Run tests (226 tests)
|
|
549
572
|
npm run type-check # TypeScript check
|
|
550
573
|
```
|
|
551
574
|
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { T as Tool, c as ToolContext } from '../tool-Ca2x-VNK.mjs';
|
|
2
|
+
import 'zod';
|
|
3
|
+
import 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* AG-UI (Agent-User Interaction Protocol) Server for Better UI
|
|
7
|
+
*
|
|
8
|
+
* Implements the AG-UI protocol, allowing Better UI tools to be used with
|
|
9
|
+
* CopilotKit, LangChain, and any AG-UI compatible frontend.
|
|
10
|
+
*
|
|
11
|
+
* Protocol: Server-Sent Events (SSE) over HTTP
|
|
12
|
+
*
|
|
13
|
+
* @see https://docs.ag-ui.com
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { createAGUIServer } from '@lantos1618/better-ui/agui';
|
|
18
|
+
*
|
|
19
|
+
* const server = createAGUIServer({
|
|
20
|
+
* name: 'my-tools',
|
|
21
|
+
* tools: { weather: weatherTool, search: searchTool },
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* // Next.js route handler
|
|
25
|
+
* export const POST = server.handler();
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
type AGUIEventType = 'RUN_STARTED' | 'RUN_FINISHED' | 'RUN_ERROR' | 'STEP_STARTED' | 'STEP_FINISHED' | 'TEXT_MESSAGE_START' | 'TEXT_MESSAGE_CONTENT' | 'TEXT_MESSAGE_END' | 'TOOL_CALL_START' | 'TOOL_CALL_ARGS' | 'TOOL_CALL_END' | 'TOOL_CALL_RESULT' | 'STATE_SNAPSHOT' | 'STATE_DELTA' | 'CUSTOM' | 'RAW';
|
|
30
|
+
interface AGUIEvent {
|
|
31
|
+
type: AGUIEventType;
|
|
32
|
+
timestamp?: number;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
interface RunAgentInput {
|
|
36
|
+
threadId: string;
|
|
37
|
+
runId: string;
|
|
38
|
+
/** Tool calls to execute */
|
|
39
|
+
tools?: Array<{
|
|
40
|
+
name: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
}>;
|
|
43
|
+
/** Messages context */
|
|
44
|
+
messages?: Array<{
|
|
45
|
+
role: string;
|
|
46
|
+
content: string;
|
|
47
|
+
}>;
|
|
48
|
+
/** Tool call to execute (for direct tool invocation) */
|
|
49
|
+
toolCall?: {
|
|
50
|
+
id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
args: Record<string, unknown>;
|
|
53
|
+
};
|
|
54
|
+
/** State context from the frontend */
|
|
55
|
+
state?: Record<string, unknown>;
|
|
56
|
+
}
|
|
57
|
+
interface AGUIServerConfig {
|
|
58
|
+
/** Server name */
|
|
59
|
+
name: string;
|
|
60
|
+
/** Tool registry — keys are tool names */
|
|
61
|
+
tools: Record<string, Tool>;
|
|
62
|
+
/** Optional context passed to every tool execution */
|
|
63
|
+
context?: Partial<ToolContext>;
|
|
64
|
+
/** Called on errors */
|
|
65
|
+
onError?: (error: Error) => void;
|
|
66
|
+
}
|
|
67
|
+
declare class AGUIServer {
|
|
68
|
+
private config;
|
|
69
|
+
constructor(config: AGUIServerConfig);
|
|
70
|
+
/** Get available tools in AG-UI format */
|
|
71
|
+
listTools(): Array<{
|
|
72
|
+
name: string;
|
|
73
|
+
description: string;
|
|
74
|
+
parameters: Record<string, unknown>;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Create an HTTP handler that implements the AG-UI protocol.
|
|
78
|
+
* Returns an SSE stream of AG-UI events.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* // Next.js: app/api/agui/route.ts
|
|
83
|
+
* export const POST = server.handler();
|
|
84
|
+
*
|
|
85
|
+
* // Express:
|
|
86
|
+
* app.post('/api/agui', (req, res) => server.handler()(req));
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
handler(): (req: Request) => Promise<Response>;
|
|
90
|
+
/**
|
|
91
|
+
* Execute a tool call and emit AG-UI events.
|
|
92
|
+
*/
|
|
93
|
+
private executeToolCall;
|
|
94
|
+
/**
|
|
95
|
+
* Minimal Zod-to-JSON-Schema for AG-UI tool parameters.
|
|
96
|
+
* Delegates to the MCP schema converter if available, otherwise provides a basic fallback.
|
|
97
|
+
*/
|
|
98
|
+
private zodToJsonSchema;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Create an AG-UI server from a Better UI tool registry.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* const server = createAGUIServer({
|
|
106
|
+
* name: 'my-app',
|
|
107
|
+
* tools: { weather: weatherTool, search: searchTool },
|
|
108
|
+
* });
|
|
109
|
+
*
|
|
110
|
+
* // Use as Next.js route handler
|
|
111
|
+
* export const POST = server.handler();
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
declare function createAGUIServer(config: AGUIServerConfig): AGUIServer;
|
|
115
|
+
|
|
116
|
+
export { type AGUIEvent, type AGUIEventType, AGUIServer, type AGUIServerConfig, type RunAgentInput, createAGUIServer };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { T as Tool, c as ToolContext } from '../tool-Ca2x-VNK.js';
|
|
2
|
+
import 'zod';
|
|
3
|
+
import 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* AG-UI (Agent-User Interaction Protocol) Server for Better UI
|
|
7
|
+
*
|
|
8
|
+
* Implements the AG-UI protocol, allowing Better UI tools to be used with
|
|
9
|
+
* CopilotKit, LangChain, and any AG-UI compatible frontend.
|
|
10
|
+
*
|
|
11
|
+
* Protocol: Server-Sent Events (SSE) over HTTP
|
|
12
|
+
*
|
|
13
|
+
* @see https://docs.ag-ui.com
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import { createAGUIServer } from '@lantos1618/better-ui/agui';
|
|
18
|
+
*
|
|
19
|
+
* const server = createAGUIServer({
|
|
20
|
+
* name: 'my-tools',
|
|
21
|
+
* tools: { weather: weatherTool, search: searchTool },
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* // Next.js route handler
|
|
25
|
+
* export const POST = server.handler();
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
type AGUIEventType = 'RUN_STARTED' | 'RUN_FINISHED' | 'RUN_ERROR' | 'STEP_STARTED' | 'STEP_FINISHED' | 'TEXT_MESSAGE_START' | 'TEXT_MESSAGE_CONTENT' | 'TEXT_MESSAGE_END' | 'TOOL_CALL_START' | 'TOOL_CALL_ARGS' | 'TOOL_CALL_END' | 'TOOL_CALL_RESULT' | 'STATE_SNAPSHOT' | 'STATE_DELTA' | 'CUSTOM' | 'RAW';
|
|
30
|
+
interface AGUIEvent {
|
|
31
|
+
type: AGUIEventType;
|
|
32
|
+
timestamp?: number;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
interface RunAgentInput {
|
|
36
|
+
threadId: string;
|
|
37
|
+
runId: string;
|
|
38
|
+
/** Tool calls to execute */
|
|
39
|
+
tools?: Array<{
|
|
40
|
+
name: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
}>;
|
|
43
|
+
/** Messages context */
|
|
44
|
+
messages?: Array<{
|
|
45
|
+
role: string;
|
|
46
|
+
content: string;
|
|
47
|
+
}>;
|
|
48
|
+
/** Tool call to execute (for direct tool invocation) */
|
|
49
|
+
toolCall?: {
|
|
50
|
+
id: string;
|
|
51
|
+
name: string;
|
|
52
|
+
args: Record<string, unknown>;
|
|
53
|
+
};
|
|
54
|
+
/** State context from the frontend */
|
|
55
|
+
state?: Record<string, unknown>;
|
|
56
|
+
}
|
|
57
|
+
interface AGUIServerConfig {
|
|
58
|
+
/** Server name */
|
|
59
|
+
name: string;
|
|
60
|
+
/** Tool registry — keys are tool names */
|
|
61
|
+
tools: Record<string, Tool>;
|
|
62
|
+
/** Optional context passed to every tool execution */
|
|
63
|
+
context?: Partial<ToolContext>;
|
|
64
|
+
/** Called on errors */
|
|
65
|
+
onError?: (error: Error) => void;
|
|
66
|
+
}
|
|
67
|
+
declare class AGUIServer {
|
|
68
|
+
private config;
|
|
69
|
+
constructor(config: AGUIServerConfig);
|
|
70
|
+
/** Get available tools in AG-UI format */
|
|
71
|
+
listTools(): Array<{
|
|
72
|
+
name: string;
|
|
73
|
+
description: string;
|
|
74
|
+
parameters: Record<string, unknown>;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Create an HTTP handler that implements the AG-UI protocol.
|
|
78
|
+
* Returns an SSE stream of AG-UI events.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* // Next.js: app/api/agui/route.ts
|
|
83
|
+
* export const POST = server.handler();
|
|
84
|
+
*
|
|
85
|
+
* // Express:
|
|
86
|
+
* app.post('/api/agui', (req, res) => server.handler()(req));
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
handler(): (req: Request) => Promise<Response>;
|
|
90
|
+
/**
|
|
91
|
+
* Execute a tool call and emit AG-UI events.
|
|
92
|
+
*/
|
|
93
|
+
private executeToolCall;
|
|
94
|
+
/**
|
|
95
|
+
* Minimal Zod-to-JSON-Schema for AG-UI tool parameters.
|
|
96
|
+
* Delegates to the MCP schema converter if available, otherwise provides a basic fallback.
|
|
97
|
+
*/
|
|
98
|
+
private zodToJsonSchema;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Create an AG-UI server from a Better UI tool registry.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* const server = createAGUIServer({
|
|
106
|
+
* name: 'my-app',
|
|
107
|
+
* tools: { weather: weatherTool, search: searchTool },
|
|
108
|
+
* });
|
|
109
|
+
*
|
|
110
|
+
* // Use as Next.js route handler
|
|
111
|
+
* export const POST = server.handler();
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
declare function createAGUIServer(config: AGUIServerConfig): AGUIServer;
|
|
115
|
+
|
|
116
|
+
export { type AGUIEvent, type AGUIEventType, AGUIServer, type AGUIServerConfig, type RunAgentInput, createAGUIServer };
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __esm = (fn, res) => function __init() {
|
|
7
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
8
|
+
};
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
|
+
|
|
23
|
+
// src/mcp/schema.ts
|
|
24
|
+
var schema_exports = {};
|
|
25
|
+
__export(schema_exports, {
|
|
26
|
+
zodToJsonSchema: () => zodToJsonSchema
|
|
27
|
+
});
|
|
28
|
+
function zodToJsonSchema(schema) {
|
|
29
|
+
return convert(schema);
|
|
30
|
+
}
|
|
31
|
+
function convert(schema) {
|
|
32
|
+
const def = schema._def;
|
|
33
|
+
const typeName = def?.typeName;
|
|
34
|
+
switch (typeName) {
|
|
35
|
+
case "ZodString":
|
|
36
|
+
return convertString(def);
|
|
37
|
+
case "ZodNumber":
|
|
38
|
+
return convertNumber(def);
|
|
39
|
+
case "ZodBoolean":
|
|
40
|
+
return { type: "boolean" };
|
|
41
|
+
case "ZodNull":
|
|
42
|
+
return { type: "null" };
|
|
43
|
+
case "ZodLiteral":
|
|
44
|
+
return { enum: [def.value] };
|
|
45
|
+
case "ZodEnum":
|
|
46
|
+
return { type: "string", enum: def.values };
|
|
47
|
+
case "ZodNativeEnum":
|
|
48
|
+
return { enum: Object.values(def.values) };
|
|
49
|
+
case "ZodObject":
|
|
50
|
+
return convertObject(def);
|
|
51
|
+
case "ZodArray":
|
|
52
|
+
return convertArray(def);
|
|
53
|
+
case "ZodOptional":
|
|
54
|
+
return convert(def.innerType);
|
|
55
|
+
case "ZodNullable": {
|
|
56
|
+
const inner = convert(def.innerType);
|
|
57
|
+
return { anyOf: [inner, { type: "null" }] };
|
|
58
|
+
}
|
|
59
|
+
case "ZodDefault":
|
|
60
|
+
return { ...convert(def.innerType), default: def.defaultValue() };
|
|
61
|
+
case "ZodUnion":
|
|
62
|
+
return { anyOf: def.options.map((o) => convert(o)) };
|
|
63
|
+
case "ZodDiscriminatedUnion":
|
|
64
|
+
return { oneOf: [...def.options.values()].map((o) => convert(o)) };
|
|
65
|
+
case "ZodRecord":
|
|
66
|
+
return {
|
|
67
|
+
type: "object",
|
|
68
|
+
additionalProperties: convert(def.valueType)
|
|
69
|
+
};
|
|
70
|
+
case "ZodTuple": {
|
|
71
|
+
const items = def.items.map((item) => convert(item));
|
|
72
|
+
return { type: "array", items: items.length === 1 ? items[0] : void 0, prefixItems: items };
|
|
73
|
+
}
|
|
74
|
+
case "ZodEffects":
|
|
75
|
+
return convert(def.schema);
|
|
76
|
+
case "ZodPipeline":
|
|
77
|
+
return convert(def.in);
|
|
78
|
+
case "ZodLazy":
|
|
79
|
+
return convert(def.getter());
|
|
80
|
+
case "ZodAny":
|
|
81
|
+
return {};
|
|
82
|
+
case "ZodUnknown":
|
|
83
|
+
return {};
|
|
84
|
+
default:
|
|
85
|
+
return {};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function convertString(def) {
|
|
89
|
+
const schema = { type: "string" };
|
|
90
|
+
if (def.checks) {
|
|
91
|
+
for (const check of def.checks) {
|
|
92
|
+
switch (check.kind) {
|
|
93
|
+
case "min":
|
|
94
|
+
schema.minLength = check.value;
|
|
95
|
+
break;
|
|
96
|
+
case "max":
|
|
97
|
+
schema.maxLength = check.value;
|
|
98
|
+
break;
|
|
99
|
+
case "email":
|
|
100
|
+
schema.format = "email";
|
|
101
|
+
break;
|
|
102
|
+
case "url":
|
|
103
|
+
schema.format = "uri";
|
|
104
|
+
break;
|
|
105
|
+
case "uuid":
|
|
106
|
+
schema.format = "uuid";
|
|
107
|
+
break;
|
|
108
|
+
case "regex":
|
|
109
|
+
schema.pattern = check.regex.source;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (def.description) schema.description = def.description;
|
|
115
|
+
return schema;
|
|
116
|
+
}
|
|
117
|
+
function convertNumber(def) {
|
|
118
|
+
const schema = { type: "number" };
|
|
119
|
+
if (def.checks) {
|
|
120
|
+
for (const check of def.checks) {
|
|
121
|
+
switch (check.kind) {
|
|
122
|
+
case "min":
|
|
123
|
+
schema.minimum = check.value;
|
|
124
|
+
if (check.inclusive === false) schema.exclusiveMinimum = check.value;
|
|
125
|
+
break;
|
|
126
|
+
case "max":
|
|
127
|
+
schema.maximum = check.value;
|
|
128
|
+
if (check.inclusive === false) schema.exclusiveMaximum = check.value;
|
|
129
|
+
break;
|
|
130
|
+
case "int":
|
|
131
|
+
schema.type = "integer";
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (def.description) schema.description = def.description;
|
|
137
|
+
return schema;
|
|
138
|
+
}
|
|
139
|
+
function convertObject(def) {
|
|
140
|
+
const shape = def.shape();
|
|
141
|
+
const properties = {};
|
|
142
|
+
const required = [];
|
|
143
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
144
|
+
properties[key] = convert(value);
|
|
145
|
+
const fieldDef = value._def;
|
|
146
|
+
const isOptional = fieldDef?.typeName === "ZodOptional" || fieldDef?.typeName === "ZodDefault";
|
|
147
|
+
if (!isOptional) {
|
|
148
|
+
required.push(key);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const schema = { type: "object", properties };
|
|
152
|
+
if (required.length > 0) schema.required = required;
|
|
153
|
+
if (def.description) schema.description = def.description;
|
|
154
|
+
return schema;
|
|
155
|
+
}
|
|
156
|
+
function convertArray(def) {
|
|
157
|
+
const schema = {
|
|
158
|
+
type: "array",
|
|
159
|
+
items: convert(def.type)
|
|
160
|
+
};
|
|
161
|
+
if (def.minLength) schema.minItems = def.minLength.value;
|
|
162
|
+
if (def.maxLength) schema.maxItems = def.maxLength.value;
|
|
163
|
+
if (def.description) schema.description = def.description;
|
|
164
|
+
return schema;
|
|
165
|
+
}
|
|
166
|
+
var init_schema = __esm({
|
|
167
|
+
"src/mcp/schema.ts"() {
|
|
168
|
+
"use strict";
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// src/agui/index.ts
|
|
173
|
+
var agui_exports = {};
|
|
174
|
+
__export(agui_exports, {
|
|
175
|
+
AGUIServer: () => AGUIServer,
|
|
176
|
+
createAGUIServer: () => createAGUIServer
|
|
177
|
+
});
|
|
178
|
+
module.exports = __toCommonJS(agui_exports);
|
|
179
|
+
|
|
180
|
+
// src/agui/server.ts
|
|
181
|
+
var AGUIServer = class {
|
|
182
|
+
constructor(config) {
|
|
183
|
+
this.config = config;
|
|
184
|
+
}
|
|
185
|
+
/** Get available tools in AG-UI format */
|
|
186
|
+
listTools() {
|
|
187
|
+
return Object.values(this.config.tools).map((tool) => ({
|
|
188
|
+
name: tool.name,
|
|
189
|
+
description: tool.description || tool.name,
|
|
190
|
+
parameters: this.zodToJsonSchema(tool.inputSchema)
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Create an HTTP handler that implements the AG-UI protocol.
|
|
195
|
+
* Returns an SSE stream of AG-UI events.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```typescript
|
|
199
|
+
* // Next.js: app/api/agui/route.ts
|
|
200
|
+
* export const POST = server.handler();
|
|
201
|
+
*
|
|
202
|
+
* // Express:
|
|
203
|
+
* app.post('/api/agui', (req, res) => server.handler()(req));
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
handler() {
|
|
207
|
+
return async (req) => {
|
|
208
|
+
let input;
|
|
209
|
+
try {
|
|
210
|
+
input = await req.json();
|
|
211
|
+
} catch {
|
|
212
|
+
return new Response("Invalid JSON", { status: 400 });
|
|
213
|
+
}
|
|
214
|
+
const { threadId, runId, toolCall } = input;
|
|
215
|
+
if (!threadId || !runId) {
|
|
216
|
+
return new Response("Missing threadId or runId", { status: 400 });
|
|
217
|
+
}
|
|
218
|
+
const encoder = new TextEncoder();
|
|
219
|
+
const self = this;
|
|
220
|
+
const stream = new ReadableStream({
|
|
221
|
+
async start(controller) {
|
|
222
|
+
const emit = (event) => {
|
|
223
|
+
const data = JSON.stringify({ ...event, timestamp: event.timestamp ?? Date.now() });
|
|
224
|
+
controller.enqueue(encoder.encode(`data: ${data}
|
|
225
|
+
|
|
226
|
+
`));
|
|
227
|
+
};
|
|
228
|
+
try {
|
|
229
|
+
emit({ type: "RUN_STARTED", threadId, runId });
|
|
230
|
+
if (toolCall) {
|
|
231
|
+
await self.executeToolCall(toolCall, emit);
|
|
232
|
+
} else {
|
|
233
|
+
const tools = self.listTools();
|
|
234
|
+
const messageId = `msg_${runId}`;
|
|
235
|
+
emit({ type: "TEXT_MESSAGE_START", messageId, role: "assistant" });
|
|
236
|
+
emit({
|
|
237
|
+
type: "TEXT_MESSAGE_CONTENT",
|
|
238
|
+
messageId,
|
|
239
|
+
delta: `Available tools: ${tools.map((t) => t.name).join(", ")}`
|
|
240
|
+
});
|
|
241
|
+
emit({ type: "TEXT_MESSAGE_END", messageId });
|
|
242
|
+
}
|
|
243
|
+
emit({ type: "RUN_FINISHED", threadId, runId });
|
|
244
|
+
} catch (err) {
|
|
245
|
+
emit({
|
|
246
|
+
type: "RUN_ERROR",
|
|
247
|
+
threadId,
|
|
248
|
+
runId,
|
|
249
|
+
message: err instanceof Error ? err.message : "Unknown error"
|
|
250
|
+
});
|
|
251
|
+
self.config.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
252
|
+
}
|
|
253
|
+
controller.close();
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
return new Response(stream, {
|
|
257
|
+
headers: {
|
|
258
|
+
"Content-Type": "text/event-stream",
|
|
259
|
+
"Cache-Control": "no-cache",
|
|
260
|
+
"Connection": "keep-alive"
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Execute a tool call and emit AG-UI events.
|
|
267
|
+
*/
|
|
268
|
+
async executeToolCall(toolCall, emit) {
|
|
269
|
+
const { id, name, args } = toolCall;
|
|
270
|
+
if (!Object.prototype.hasOwnProperty.call(this.config.tools, name)) {
|
|
271
|
+
emit({
|
|
272
|
+
type: "TOOL_CALL_START",
|
|
273
|
+
toolCallId: id,
|
|
274
|
+
toolCallName: name
|
|
275
|
+
});
|
|
276
|
+
emit({
|
|
277
|
+
type: "TOOL_CALL_END",
|
|
278
|
+
toolCallId: id
|
|
279
|
+
});
|
|
280
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
281
|
+
}
|
|
282
|
+
const tool = this.config.tools[name];
|
|
283
|
+
emit({
|
|
284
|
+
type: "TOOL_CALL_START",
|
|
285
|
+
toolCallId: id,
|
|
286
|
+
toolCallName: name
|
|
287
|
+
});
|
|
288
|
+
emit({
|
|
289
|
+
type: "TOOL_CALL_ARGS",
|
|
290
|
+
toolCallId: id,
|
|
291
|
+
delta: JSON.stringify(args)
|
|
292
|
+
});
|
|
293
|
+
const result = await tool.run(args, {
|
|
294
|
+
isServer: true,
|
|
295
|
+
...this.config.context
|
|
296
|
+
});
|
|
297
|
+
const resultText = typeof result === "string" ? result : JSON.stringify(result);
|
|
298
|
+
emit({
|
|
299
|
+
type: "TOOL_CALL_RESULT",
|
|
300
|
+
toolCallId: id,
|
|
301
|
+
result: resultText
|
|
302
|
+
});
|
|
303
|
+
emit({
|
|
304
|
+
type: "TOOL_CALL_END",
|
|
305
|
+
toolCallId: id
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Minimal Zod-to-JSON-Schema for AG-UI tool parameters.
|
|
310
|
+
* Delegates to the MCP schema converter if available, otherwise provides a basic fallback.
|
|
311
|
+
*/
|
|
312
|
+
zodToJsonSchema(schema) {
|
|
313
|
+
try {
|
|
314
|
+
const { zodToJsonSchema: zodToJsonSchema2 } = (init_schema(), __toCommonJS(schema_exports));
|
|
315
|
+
return zodToJsonSchema2(schema);
|
|
316
|
+
} catch {
|
|
317
|
+
return { type: "object", properties: {} };
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
function createAGUIServer(config) {
|
|
322
|
+
return new AGUIServer(config);
|
|
323
|
+
}
|
|
324
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
325
|
+
0 && (module.exports = {
|
|
326
|
+
AGUIServer,
|
|
327
|
+
createAGUIServer
|
|
328
|
+
});
|