Skip to content

Commit 0c45233

Browse files
committed
wip
Signed-off-by: Tyler Slaton <[email protected]>
1 parent 5198170 commit 0c45233

File tree

6 files changed

+71
-469
lines changed

6 files changed

+71
-469
lines changed

.github/workflows/dojo-e2e.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ jobs:
5858
test_path: tests/serverStarterAllFeaturesTests
5959
services: ["dojo","server-starter-all"]
6060
wait_on: http://localhost:9999,tcp:localhost:8001
61-
- suite: vercel-ai-sdk
62-
test_path: tests/vercelAISdkTests
63-
services: ["dojo"]
64-
wait_on: http://localhost:9999
61+
# - suite: vercel-ai-sdk
62+
# test_path: tests/vercelAISdkTests
63+
# services: ["dojo"]
64+
# wait_on: http://localhost:9999
6565

6666
steps:
6767
- name: Checkout code

typescript-sdk/apps/dojo/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"@ag-ui/server-starter-all-features": "workspace:*",
2323
"@ag-ui/vercel-ai-sdk": "workspace:*",
2424
"@ai-sdk/openai": "^2.0.22",
25+
"ai": "^4.3.16",
2526
"@copilotkit/react-core": "1.10.1",
2627
"@copilotkit/react-ui": "1.10.1",
2728
"@copilotkit/runtime": "1.10.1",
@@ -66,7 +67,7 @@
6667
"tailwind-merge": "^3.0.2",
6768
"tailwindcss-animate": "^1.0.7",
6869
"uuid": "^11.1.0",
69-
"zod": "^4.1.5"
70+
"zod": "^3.25.67"
7071
},
7172
"peerDependencies": {
7273
"@ag-ui/client": "workspace:*",

typescript-sdk/apps/dojo/src/agents.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,15 @@ export const agentsIntegrations: AgentIntegrationConfig[] = [
103103
return MastraAgent.getLocalAgents({ mastra });
104104
},
105105
},
106-
{
107-
id: "vercel-ai-sdk",
108-
agents: async () => {
109-
return {
110-
agentic_chat: new VercelAISDKAgent({ model: openai("gpt-4o") }),
111-
};
112-
},
113-
},
106+
// Disabled until we can support Vercel AI SDK v5
107+
// {
108+
// id: "vercel-ai-sdk",
109+
// agents: async () => {
110+
// return {
111+
// agentic_chat: new VercelAISDKAgent({ model: openai("gpt-4o") }),
112+
// };
113+
// },
114+
// },
114115
{
115116
id: "langgraph",
116117
agents: async () => {

typescript-sdk/apps/dojo/src/files.json

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -337,32 +337,6 @@
337337
"type": "file"
338338
}
339339
],
340-
"vercel-ai-sdk::agentic_chat": [
341-
{
342-
"name": "page.tsx",
343-
"content": "\"use client\";\nimport React, { useState } from \"react\";\nimport \"@copilotkit/react-ui/styles.css\";\nimport \"./style.css\";\nimport { CopilotKit, useCoAgent, useCopilotAction, useCopilotChat } from \"@copilotkit/react-core\";\nimport { CopilotChat } from \"@copilotkit/react-ui\";\n\ninterface AgenticChatProps {\n params: Promise<{\n integrationId: string;\n }>;\n}\n\nconst AgenticChat: React.FC<AgenticChatProps> = ({ params }) => {\n const { integrationId } = React.use(params);\n\n return (\n <CopilotKit\n runtimeUrl={`/api/copilotkit/${integrationId}`}\n showDevConsole={false}\n // agent lock to the relevant agent\n agent=\"agentic_chat\"\n >\n <Chat />\n </CopilotKit>\n );\n};\n\nconst Chat = () => {\n const [background, setBackground] = useState<string>(\"--copilot-kit-background-color\");\n\n useCopilotAction({\n name: \"change_background\",\n description:\n \"Change the background color of the chat. Can be anything that the CSS background attribute accepts. Regular colors, linear of radial gradients etc.\",\n parameters: [\n {\n name: \"background\",\n type: \"string\",\n description: \"The background. Prefer gradients. Only use when asked.\",\n },\n ],\n handler: ({ background }) => {\n setBackground(background);\n return {\n status: \"success\",\n message: `Background changed to ${background}`,\n };\n },\n });\n\n return (\n <div className=\"flex justify-center items-center h-full w-full\" style={{ background }}>\n <div className=\"h-full w-full md:w-8/10 md:h-8/10 rounded-lg\">\n <CopilotChat\n className=\"h-full rounded-2xl\"\n labels={{ initial: \"Hi, I'm an agent. Want to chat?\" }}\n />\n </div>\n </div>\n );\n};\n\nexport default AgenticChat;\n",
344-
"language": "typescript",
345-
"type": "file"
346-
},
347-
{
348-
"name": "style.css",
349-
"content": ".copilotKitInput {\n border-bottom-left-radius: 0.75rem;\n border-bottom-right-radius: 0.75rem;\n border-top-left-radius: 0.75rem;\n border-top-right-radius: 0.75rem;\n border: 1px solid var(--copilot-kit-separator-color) !important;\n}\n \n.copilotKitChat {\n background-color: #fff !important;\n}\n ",
350-
"language": "css",
351-
"type": "file"
352-
},
353-
{
354-
"name": "README.mdx",
355-
"content": "# 🤖 Agentic Chat with Frontend Tools\n\n## What This Demo Shows\n\nThis demo showcases CopilotKit's **agentic chat** capabilities with **frontend\ntool integration**:\n\n1. **Natural Conversation**: Chat with your Copilot in a familiar chat interface\n2. **Frontend Tool Execution**: The Copilot can directly interacts with your UI\n by calling frontend functions\n3. **Seamless Integration**: Tools defined in the frontend and automatically\n discovered and made available to the agent\n\n## How to Interact\n\nTry asking your Copilot to:\n\n- \"Can you change the background color to something more vibrant?\"\n- \"Make the background a blue to purple gradient\"\n- \"Set the background to a sunset-themed gradient\"\n- \"Change it back to a simple light color\"\n\nYou can also chat about other topics - the agent will respond conversationally\nwhile having the ability to use your UI tools when appropriate.\n\n## ✨ Frontend Tool Integration in Action\n\n**What's happening technically:**\n\n- The React component defines a frontend function using `useCopilotAction`\n- CopilotKit automatically exposes this function to the agent\n- When you make a request, the agent determines whether to use the tool\n- The agent calls the function with the appropriate parameters\n- The UI immediately updates in response\n\n**What you'll see in this demo:**\n\n- The Copilot understands requests to change the background\n- It generates CSS values for colors and gradients\n- When it calls the tool, the background changes instantly\n- The agent provides a conversational response about the changes it made\n\nThis technique of exposing frontend functions to your Copilot can be extended to\nany UI manipulation you want to enable, from theme changes to data filtering,\nnavigation, or complex UI state management!\n",
356-
"language": "markdown",
357-
"type": "file"
358-
},
359-
{
360-
"name": "index.ts",
361-
"content": "import {\n AgentConfig,\n AbstractAgent,\n EventType,\n BaseEvent,\n Message,\n AssistantMessage,\n RunAgentInput,\n MessagesSnapshotEvent,\n RunFinishedEvent,\n RunStartedEvent,\n TextMessageChunkEvent,\n ToolCallArgsEvent,\n ToolCallEndEvent,\n ToolCallStartEvent,\n ToolCall,\n ToolMessage,\n} from \"@ag-ui/client\";\nimport { Observable } from \"rxjs\";\nimport {\n CoreMessage,\n LanguageModelV1,\n processDataStream,\n streamText,\n tool as createVercelAISDKTool,\n ToolChoice,\n ToolSet,\n} from \"ai\";\nimport { randomUUID } from \"crypto\";\nimport { z } from \"zod\";\n\ntype ProcessedEvent =\n | MessagesSnapshotEvent\n | RunFinishedEvent\n | RunStartedEvent\n | TextMessageChunkEvent\n | ToolCallArgsEvent\n | ToolCallEndEvent\n | ToolCallStartEvent;\n\ninterface VercelAISDKAgentConfig extends AgentConfig {\n model: LanguageModelV1;\n maxSteps?: number;\n toolChoice?: ToolChoice<Record<string, unknown>>;\n}\n\nexport class VercelAISDKAgent extends AbstractAgent {\n model: LanguageModelV1;\n maxSteps: number;\n toolChoice: ToolChoice<Record<string, unknown>>;\n constructor({ model, maxSteps, toolChoice, ...rest }: VercelAISDKAgentConfig) {\n super({ ...rest });\n this.model = model;\n this.maxSteps = maxSteps ?? 1;\n this.toolChoice = toolChoice ?? \"auto\";\n }\n\n protected run(input: RunAgentInput): Observable<BaseEvent> {\n const finalMessages: Message[] = input.messages;\n\n return new Observable<ProcessedEvent>((subscriber) => {\n subscriber.next({\n type: EventType.RUN_STARTED,\n threadId: input.threadId,\n runId: input.runId,\n } as RunStartedEvent);\n\n const response = streamText({\n model: this.model,\n messages: convertMessagesToVercelAISDKMessages(input.messages),\n tools: convertToolToVerlAISDKTools(input.tools),\n maxSteps: this.maxSteps,\n toolChoice: this.toolChoice,\n });\n\n let messageId = randomUUID();\n let assistantMessage: AssistantMessage = {\n id: messageId,\n role: \"assistant\",\n content: \"\",\n toolCalls: [],\n };\n finalMessages.push(assistantMessage);\n\n processDataStream({\n stream: response.toDataStreamResponse().body!,\n onTextPart: (text) => {\n assistantMessage.content += text;\n const event: TextMessageChunkEvent = {\n type: EventType.TEXT_MESSAGE_CHUNK,\n role: \"assistant\",\n messageId,\n delta: text,\n };\n subscriber.next(event);\n },\n onFinishMessagePart: () => {\n // Emit message snapshot\n const event: MessagesSnapshotEvent = {\n type: EventType.MESSAGES_SNAPSHOT,\n messages: finalMessages,\n };\n subscriber.next(event);\n\n // Emit run finished event\n subscriber.next({\n type: EventType.RUN_FINISHED,\n threadId: input.threadId,\n runId: input.runId,\n } as RunFinishedEvent);\n\n // Complete the observable\n subscriber.complete();\n },\n onToolCallPart(streamPart) {\n let toolCall: ToolCall = {\n id: streamPart.toolCallId,\n type: \"function\",\n function: {\n name: streamPart.toolName,\n arguments: JSON.stringify(streamPart.args),\n },\n };\n assistantMessage.toolCalls!.push(toolCall);\n\n const startEvent: ToolCallStartEvent = {\n type: EventType.TOOL_CALL_START,\n parentMessageId: messageId,\n toolCallId: streamPart.toolCallId,\n toolCallName: streamPart.toolName,\n };\n subscriber.next(startEvent);\n\n const argsEvent: ToolCallArgsEvent = {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId: streamPart.toolCallId,\n delta: JSON.stringify(streamPart.args),\n };\n subscriber.next(argsEvent);\n\n const endEvent: ToolCallEndEvent = {\n type: EventType.TOOL_CALL_END,\n toolCallId: streamPart.toolCallId,\n };\n subscriber.next(endEvent);\n },\n onToolResultPart(streamPart) {\n const toolMessage: ToolMessage = {\n role: \"tool\",\n id: randomUUID(),\n toolCallId: streamPart.toolCallId,\n content: JSON.stringify(streamPart.result),\n };\n finalMessages.push(toolMessage);\n },\n onErrorPart(streamPart) {\n subscriber.error(streamPart);\n },\n }).catch((error) => {\n console.error(\"catch error\", error);\n // Handle error\n subscriber.error(error);\n });\n\n return () => {};\n });\n }\n}\n\nexport function convertMessagesToVercelAISDKMessages(messages: Message[]): CoreMessage[] {\n const result: CoreMessage[] = [];\n\n for (const message of messages) {\n if (message.role === \"assistant\") {\n const parts: any[] = message.content ? [{ type: \"text\", text: message.content }] : [];\n for (const toolCall of message.toolCalls ?? []) {\n parts.push({\n type: \"tool-call\",\n toolCallId: toolCall.id,\n toolName: toolCall.function.name,\n args: JSON.parse(toolCall.function.arguments),\n });\n }\n result.push({\n role: \"assistant\",\n content: parts,\n });\n } else if (message.role === \"user\") {\n result.push({\n role: \"user\",\n content: message.content || \"\",\n });\n } else if (message.role === \"tool\") {\n let toolName = \"unknown\";\n for (const msg of messages) {\n if (msg.role === \"assistant\") {\n for (const toolCall of msg.toolCalls ?? []) {\n if (toolCall.id === message.toolCallId) {\n toolName = toolCall.function.name;\n break;\n }\n }\n }\n }\n result.push({\n role: \"tool\",\n content: [\n {\n type: \"tool-result\",\n toolCallId: message.toolCallId,\n toolName: toolName,\n result: message.content,\n },\n ],\n });\n }\n }\n\n return result;\n}\n\nexport function convertJsonSchemaToZodSchema(jsonSchema: any, required: boolean): z.ZodSchema {\n if (jsonSchema.type === \"object\") {\n const spec: { [key: string]: z.ZodSchema } = {};\n\n if (!jsonSchema.properties || !Object.keys(jsonSchema.properties).length) {\n return !required ? z.object(spec).optional() : z.object(spec);\n }\n\n for (const [key, value] of Object.entries(jsonSchema.properties)) {\n spec[key] = convertJsonSchemaToZodSchema(\n value,\n jsonSchema.required ? jsonSchema.required.includes(key) : false,\n );\n }\n let schema = z.object(spec).describe(jsonSchema.description);\n return required ? schema : schema.optional();\n } else if (jsonSchema.type === \"string\") {\n let schema = z.string().describe(jsonSchema.description);\n return required ? schema : schema.optional();\n } else if (jsonSchema.type === \"number\") {\n let schema = z.number().describe(jsonSchema.description);\n return required ? schema : schema.optional();\n } else if (jsonSchema.type === \"boolean\") {\n let schema = z.boolean().describe(jsonSchema.description);\n return required ? schema : schema.optional();\n } else if (jsonSchema.type === \"array\") {\n let itemSchema = convertJsonSchemaToZodSchema(jsonSchema.items, true);\n let schema = z.array(itemSchema).describe(jsonSchema.description);\n return required ? schema : schema.optional();\n }\n throw new Error(\"Invalid JSON schema\");\n}\n\nexport function convertToolToVerlAISDKTools(tools: RunAgentInput[\"tools\"]): ToolSet {\n return tools.reduce(\n (acc: ToolSet, tool: RunAgentInput[\"tools\"][number]) => ({\n ...acc,\n [tool.name]: createVercelAISDKTool({\n description: tool.description,\n parameters: convertJsonSchemaToZodSchema(tool.parameters, true),\n }),\n }),\n {},\n );\n}\n",
362-
"language": "ts",
363-
"type": "file"
364-
}
365-
],
366340
"langgraph::agentic_chat": [
367341
{
368342
"name": "page.tsx",

typescript-sdk/apps/dojo/src/menu.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,11 @@ export const menuIntegrations: MenuIntegrationConfig[] = [
110110
"tool_based_generative_ui",
111111
],
112112
},
113-
{
114-
id: "vercel-ai-sdk",
115-
name: "Vercel AI SDK",
116-
features: ["agentic_chat"],
117-
},
113+
// Disabled until we can support Vercel AI SDK v5
114+
// {
115+
// id: "vercel-ai-sdk",
116+
// name: "Vercel AI SDK",
117+
// features: ["agentic_chat"],
118+
// },
118119
];
119120

0 commit comments

Comments
 (0)