-
-
Save shricodev/c2918c741dce9dbd2288b7c39b45cfa5 to your computer and use it in GitHub Desktop.
OpenAI GPT-5.1 Calendar AI Agent Test - Blog Demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import React, { useState } from "react"; | |
| type ChatInputProps = { | |
| disabled?: boolean; | |
| onSend: (message: string) => void; | |
| }; | |
| export const ChatInput: React.FC<ChatInputProps> = ({ | |
| disabled, | |
| onSend, | |
| }) => { | |
| const [value, setValue] = useState(""); | |
| const handleSubmit = (event: React.FormEvent) => { | |
| event.preventDefault(); | |
| const trimmed = value.trim(); | |
| if (!trimmed || disabled) return; | |
| onSend(trimmed); | |
| setValue(""); | |
| }; | |
| return ( | |
| <form | |
| onSubmit={handleSubmit} | |
| className="flex w-full items-center gap-3 rounded-2xl border border-zinc-200 bg-white p-2 shadow-sm dark:border-zinc-800 dark:bg-zinc-900" | |
| > | |
| <textarea | |
| className="max-h-32 min-h-[40px] flex-1 resize-none border-0 bg-transparent px-2 py-2 text-sm text-zinc-900 outline-none dark:text-zinc-50" | |
| placeholder="Ask me to schedule, list, or cancel meetings..." | |
| value={value} | |
| onChange={(event) => setValue(event.target.value)} | |
| disabled={disabled} | |
| /> | |
| <button | |
| type="submit" | |
| disabled={disabled || value.trim().length === 0} | |
| className="inline-flex h-9 items-center justify-center rounded-full bg-sky-600 px-4 text-xs font-medium text-white transition hover:bg-sky-700 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-sky-500 dark:hover:bg-sky-400" | |
| > | |
| Send | |
| </button> | |
| </form> | |
| ); | |
| }; | |
| export default ChatInput; | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import React from "react"; | |
| import { ChatMessage } from "../lib/types"; | |
| import { mapToolResponseToMeetings } from "../lib/meetingUtils"; | |
| import { MeetingCard } from "./MeetingCard"; | |
| type ChatMessageBubbleProps = { | |
| message: ChatMessage; | |
| }; | |
| export const ChatMessageBubble: React.FC<ChatMessageBubbleProps> = ({ | |
| message, | |
| }) => { | |
| const isUser = message.role === "user"; | |
| const meetings = mapToolResponseToMeetings(message.toolResponses); | |
| const hasToolError = | |
| message.toolResponses && | |
| message.toolResponses.some( | |
| (tool) => tool.result?.successful === false || tool.result?.error, | |
| ); | |
| return ( | |
| <div | |
| className={`flex w-full gap-2 ${ | |
| isUser ? "justify-end" : "justify-start" | |
| }`} | |
| > | |
| {!isUser && ( | |
| <div className="mt-1 flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-zinc-900 text-xs font-semibold text-zinc-50 dark:bg-zinc-100 dark:text-zinc-900"> | |
| A | |
| </div> | |
| )} | |
| <div className={`flex max-w-lg flex-col ${isUser ? "items-end" : ""}`}> | |
| <div | |
| className={`rounded-2xl px-3 py-2 text-sm leading-relaxed shadow-sm ${ | |
| isUser | |
| ? "bg-sky-600 text-white dark:bg-sky-500" | |
| : "bg-zinc-100 text-zinc-900 dark:bg-zinc-800 dark:text-zinc-50" | |
| }`} | |
| > | |
| {message.content} | |
| </div> | |
| {hasToolError && !isUser && ( | |
| <div className="mt-1 rounded-xl bg-red-50 px-3 py-1 text-xs text-red-700 dark:bg-red-950/60 dark:text-red-200"> | |
| I ran into an issue while talking to Google Calendar. Please try | |
| again or adjust your request. | |
| </div> | |
| )} | |
| {meetings.length > 0 && ( | |
| <div className="mt-2 flex w-full flex-col gap-2"> | |
| {meetings.map((meeting) => ( | |
| <MeetingCard | |
| key={meeting.id ?? meeting.title} | |
| meeting={meeting} | |
| /> | |
| ))} | |
| </div> | |
| )} | |
| </div> | |
| {isUser && ( | |
| <div className="mt-1 flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-sky-100 text-xs font-semibold text-sky-700 dark:bg-sky-900 dark:text-sky-200"> | |
| U | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| }; | |
| export default ChatMessageBubble; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import React from "react"; | |
| import { ChatMessage } from "../lib/types"; | |
| import ChatMessageBubble from "./ChatMessageBubble"; | |
| type ChatMessagesListProps = { | |
| messages: ChatMessage[]; | |
| isLoading?: boolean; | |
| }; | |
| export const ChatMessagesList: React.FC<ChatMessagesListProps> = ({ | |
| messages, | |
| isLoading, | |
| }) => { | |
| return ( | |
| <div className="flex-1 space-y-4 overflow-y-auto px-2 py-4"> | |
| {messages.map((message) => ( | |
| <ChatMessageBubble key={message.id} message={message} /> | |
| ))} | |
| {isLoading && ( | |
| <div className="flex justify-start"> | |
| <div className="flex max-w-xs items-center gap-2 rounded-2xl bg-zinc-100 px-3 py-2 text-xs text-zinc-700 shadow-sm dark:bg-zinc-800 dark:text-zinc-200"> | |
| <span>Assistant is thinking</span> | |
| <span className="flex items-center gap-0.5"> | |
| <span className="h-1.5 w-1.5 animate-bounce rounded-full bg-zinc-500 [animation-delay:-0.2s]" /> | |
| <span className="h-1.5 w-1.5 animate-bounce rounded-full bg-zinc-500 [animation-delay:-0.1s]" /> | |
| <span className="h-1.5 w-1.5 animate-bounce rounded-full bg-zinc-500" /> | |
| </span> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| }; | |
| export default ChatMessagesList; | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import type { Metadata } from "next"; | |
| import { Geist, Geist_Mono } from "next/font/google"; | |
| import "./globals.css"; | |
| const geistSans = Geist({ | |
| variable: "--font-geist-sans", | |
| subsets: ["latin"], | |
| }); | |
| const geistMono = Geist_Mono({ | |
| variable: "--font-geist-mono", | |
| subsets: ["latin"], | |
| }); | |
| export const metadata: Metadata = { | |
| title: "Create Next App", | |
| description: "Generated by create next app", | |
| }; | |
| export default function RootLayout({ | |
| children, | |
| }: Readonly<{ | |
| children: React.ReactNode; | |
| }>) { | |
| return ( | |
| <html lang="en"> | |
| <body | |
| className={`${geistSans.variable} ${geistMono.variable} antialiased`} | |
| > | |
| {children} | |
| </body> | |
| </html> | |
| ); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import React from "react"; | |
| import { Meeting } from "../lib/types"; | |
| import { formatMeetingTime } from "../lib/meetingUtils"; | |
| type MeetingCardProps = { | |
| meeting: Meeting; | |
| }; | |
| export const MeetingCard: React.FC<MeetingCardProps> = ({ meeting }) => { | |
| const statusLabel = | |
| meeting.status === "cancelled" | |
| ? "Cancelled" | |
| : meeting.status === "tentative" | |
| ? "Tentative" | |
| : "Confirmed"; | |
| const statusClassName = | |
| meeting.status === "cancelled" | |
| ? "bg-red-100 text-red-700 border-red-200" | |
| : meeting.status === "tentative" | |
| ? "bg-amber-100 text-amber-700 border-amber-200" | |
| : "bg-emerald-100 text-emerald-700 border-emerald-200"; | |
| return ( | |
| <div className="mt-3 w-full max-w-md rounded-xl border border-zinc-200 bg-white p-4 shadow-sm dark:border-zinc-800 dark:bg-zinc-900"> | |
| <div className="mb-2 flex items-center justify-between gap-2"> | |
| <h3 className="text-sm font-semibold text-zinc-900 dark:text-zinc-50"> | |
| {meeting.title} | |
| </h3> | |
| <span | |
| className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${statusClassName}`} | |
| > | |
| {statusLabel} | |
| </span> | |
| </div> | |
| <p className="mb-2 text-xs text-zinc-600 dark:text-zinc-400"> | |
| {formatMeetingTime(meeting.start, meeting.end)} | |
| </p> | |
| {meeting.organizerEmail && ( | |
| <p className="mb-1 text-xs text-zinc-600 dark:text-zinc-400"> | |
| <span className="font-medium text-zinc-700 dark:text-zinc-200"> | |
| Organizer: | |
| </span>{" "} | |
| {meeting.organizerEmail} | |
| </p> | |
| )} | |
| {meeting.attendees && meeting.attendees.length > 0 && ( | |
| <div className="mt-2"> | |
| <p className="mb-1 text-xs font-medium text-zinc-700 dark:text-zinc-200"> | |
| Attendees | |
| </p> | |
| <ul className="space-y-0.5"> | |
| {meeting.attendees.map((attendee, index) => ( | |
| <li | |
| key={attendee.email ?? index} | |
| className="flex items-center justify-between text-[11px] text-zinc-600 dark:text-zinc-400" | |
| > | |
| <span>{attendee.email ?? "Unknown attendee"}</span> | |
| {attendee.responseStatus && ( | |
| <span className="rounded-full bg-zinc-100 px-2 py-0.5 text-[10px] capitalize text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300"> | |
| {attendee.responseStatus} | |
| </span> | |
| )} | |
| </li> | |
| ))} | |
| </ul> | |
| </div> | |
| )} | |
| {meeting.htmlLink && ( | |
| <a | |
| href={meeting.htmlLink} | |
| target="_blank" | |
| rel="noreferrer" | |
| className="mt-3 inline-flex items-center text-xs font-medium text-sky-600 hover:text-sky-700 dark:text-sky-400 dark:hover:text-sky-300" | |
| > | |
| Open in Google Calendar | |
| </a> | |
| )} | |
| </div> | |
| ); | |
| }; | |
| export default MeetingCard; | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Meeting, ToolResponse } from "./types"; | |
| type ResponseData = NonNullable< | |
| NonNullable<NonNullable<ToolResponse["result"]>["data"]>["response_data"] | |
| >; | |
| export function mapToolResponseToMeetings( | |
| toolResponses?: ToolResponse[], | |
| ): Meeting[] { | |
| if (!toolResponses || toolResponses.length === 0) return []; | |
| const meetings: Meeting[] = []; | |
| for (const tr of toolResponses) { | |
| const responseData = tr.result?.data?.response_data as | |
| | ResponseData | |
| | { items?: ResponseData[] } | |
| | undefined; | |
| if (!responseData) continue; | |
| // Allow a list response via an `items` array. | |
| const items = | |
| "items" in responseData && Array.isArray(responseData.items) | |
| ? responseData.items | |
| : [responseData as ResponseData]; | |
| for (const item of items) { | |
| if (!item) continue; | |
| meetings.push({ | |
| id: item.id, | |
| title: item.summary ?? "Untitled meeting", | |
| htmlLink: item.htmlLink, | |
| start: item.start, | |
| end: item.end, | |
| attendees: item.attendees, | |
| organizerEmail: item.organizer?.email, | |
| status: | |
| (item.status as Meeting["status"]) ?? | |
| (tr.toolType === "deleteEvent" ? "cancelled" : "confirmed"), | |
| }); | |
| } | |
| } | |
| return meetings; | |
| } | |
| export function formatMeetingTime( | |
| start?: { dateTime?: string; timeZone?: string }, | |
| end?: { dateTime?: string; timeZone?: string }, | |
| ): string { | |
| if (!start?.dateTime || !end?.dateTime) { | |
| return "Time not available"; | |
| } | |
| try { | |
| const startDate = new Date(start.dateTime); | |
| const endDate = new Date(end.dateTime); | |
| const timeZone = start.timeZone || end.timeZone || "UTC"; | |
| const dateFormatter = new Intl.DateTimeFormat(undefined, { | |
| weekday: "short", | |
| month: "short", | |
| day: "numeric", | |
| year: "numeric", | |
| timeZone, | |
| }); | |
| const timeFormatter = new Intl.DateTimeFormat(undefined, { | |
| hour: "numeric", | |
| minute: "2-digit", | |
| timeZone, | |
| }); | |
| const dateStr = dateFormatter.format(startDate); | |
| const startTimeStr = timeFormatter.format(startDate); | |
| const endTimeStr = timeFormatter.format(endDate); | |
| return `${dateStr}, ${startTimeStr} – ${endTimeStr} (${timeZone})`; | |
| } catch { | |
| return "Time not available"; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| "use client"; | |
| import React, { useCallback, useState } from "react"; | |
| import ChatMessagesList from "../components/ChatMessagesList"; | |
| import ChatInput from "../components/ChatInput"; | |
| import { | |
| AgentResponsePayload, | |
| ChatMessage, | |
| AgentRequestPayload, | |
| } from "../lib/types"; | |
| function createInitialMessages(): ChatMessage[] { | |
| return [ | |
| { | |
| id: "assistant-welcome", | |
| role: "assistant", | |
| content: | |
| "Hi! I’m your calendar assistant. Ask me to create a meeting, show your agenda, or cancel an event in Google Calendar.", | |
| createdAt: new Date().toISOString(), | |
| }, | |
| ]; | |
| } | |
| export default function Home() { | |
| const [messages, setMessages] = useState<ChatMessage[]>(() => | |
| createInitialMessages(), | |
| ); | |
| const [isLoading, setIsLoading] = useState(false); | |
| const handleSend = useCallback( | |
| async (text: string) => { | |
| const userMessage: ChatMessage = { | |
| id: `user-${Date.now()}`, | |
| role: "user", | |
| content: text, | |
| createdAt: new Date().toISOString(), | |
| }; | |
| const nextMessages = [...messages, userMessage]; | |
| setMessages(nextMessages); | |
| setIsLoading(true); | |
| try { | |
| const payload: AgentRequestPayload = { | |
| messages: nextMessages, | |
| }; | |
| const res = await fetch("/api/agent", { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| body: JSON.stringify(payload), | |
| }); | |
| if (!res.ok) { | |
| throw new Error(`Agent request failed with status ${res.status}`); | |
| } | |
| const data = (await res.json()) as AgentResponsePayload; | |
| if (data.messages && data.messages.length > 0) { | |
| setMessages((current) => [...current, ...data.messages]); | |
| } | |
| } catch { | |
| const fallbackAssistant: ChatMessage = { | |
| id: `assistant-error-${Date.now()}`, | |
| role: "assistant", | |
| content: | |
| "Something went wrong while talking to the agent. Please try again.", | |
| createdAt: new Date().toISOString(), | |
| }; | |
| setMessages((current) => [...current, fallbackAssistant]); | |
| } finally { | |
| setIsLoading(false); | |
| } | |
| }, | |
| [messages], | |
| ); | |
| return ( | |
| <div className="flex min-h-screen justify-center bg-zinc-50 px-4 py-6 font-sans text-zinc-900 dark:bg-black dark:text-zinc-50"> | |
| <main className="flex h-[min(720px,calc(100vh-3rem))] w-full max-w-3xl flex-col rounded-3xl border border-zinc-200 bg-white shadow-lg shadow-zinc-200/40 dark:border-zinc-800 dark:bg-zinc-950 dark:shadow-none"> | |
| <header className="flex items-center justify-between border-b border-zinc-200 px-5 py-4 dark:border-zinc-800"> | |
| <div> | |
| <h1 className="text-sm font-semibold text-zinc-900 dark:text-zinc-50"> | |
| Calendar Assistant | |
| </h1> | |
| <p className="mt-1 text-xs text-zinc-500 dark:text-zinc-400"> | |
| Chat with an AI agent that can manage your Google Calendar using | |
| Composio Tool Router. | |
| </p> | |
| </div> | |
| </header> | |
| <ChatMessagesList messages={messages} isLoading={isLoading} /> | |
| <div className="border-t border-zinc-200 bg-zinc-50 px-4 py-3 dark:border-zinc-800 dark:bg-zinc-900/60"> | |
| <ChatInput disabled={isLoading} onSend={handleSend} /> | |
| <p className="mt-1 px-1 text-[10px] text-zinc-500 dark:text-zinc-400"> | |
| This is a demo. The agent talks to a mocked Composio Tool Router | |
| endpoint so you can plug in a real model later. | |
| </p> | |
| </div> | |
| </main> | |
| </div> | |
| ); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export const runtime = "nodejs"; | |
| import { NextResponse } from "next/server"; | |
| import { Composio } from "@composio/core"; | |
| import { OpenAIAgentsProvider } from "@composio/openai-agents"; | |
| import { Agent, hostedMcpTool, run } from "@openai/agents"; | |
| import { | |
| AgentRequestPayload, | |
| AgentResponsePayload, | |
| ChatMessage, | |
| ToolResponse, | |
| } from "../../../lib/types"; | |
| const COMPOSIO_API_KEY = process.env.COMPOSIO_API_KEY; | |
| const OPENAI_API_KEY = process.env.OPENAI_API_KEY; | |
| export async function POST(req: Request) { | |
| try { | |
| if (!COMPOSIO_API_KEY || !OPENAI_API_KEY) { | |
| return NextResponse.json( | |
| { error: "Missing API Keys" }, | |
| { status: 500 }, | |
| ); | |
| } | |
| const body = (await req.json()) as AgentRequestPayload; | |
| const { messages } = body; | |
| // Simple session ID or user ID | |
| const userId = "user-session-" + new Date().toISOString().split("T")[0]; | |
| const composio = new Composio({ | |
| apiKey: COMPOSIO_API_KEY, | |
| provider: new OpenAIAgentsProvider(), | |
| }); | |
| // Create Tool Router Session | |
| // We limit to google_calendar as per instructions to "create/delete calendar meetings" | |
| const session = await composio.experimental.toolRouter.createSession( | |
| userId, | |
| { | |
| toolkits: ["googlecalendar"], | |
| }, | |
| ); | |
| const agent = new Agent({ | |
| name: "Calendar Assistant", | |
| model: "gpt-4o", | |
| instructions: `You are a helpful assistant that manages Google Calendar. | |
| You can create, list, and delete meetings. | |
| RULES: | |
| 1. When asked to create a meeting, identify: attendees, date/time, duration, title. | |
| 2. Before calling the tool, confirm the details with the user. | |
| 3. When asked to delete, identify the meeting (time, attendee, etc). Confirm if ambiguous. | |
| 4. When asked to list events, summarise the agenda clearly. | |
| 5. If the tool fails, describe the error clearly. | |
| `, | |
| tools: [ | |
| hostedMcpTool({ | |
| serverLabel: "tool_router", | |
| serverUrl: session.url, | |
| }), | |
| ], | |
| }); | |
| // Construct the "task" from the conversation history | |
| const transcript = messages | |
| .map((m) => `${m.role.toUpperCase()}: ${m.content}`) | |
| .join("\n\n"); | |
| const result = await run(agent, transcript); | |
| const { finalOutput, newItems } = result as { | |
| finalOutput: string; | |
| newItems?: unknown[]; | |
| }; | |
| let toolResponseData: ToolResponse | undefined; | |
| if (Array.isArray(newItems)) { | |
| // We look for the last tool message to show the most relevant card | |
| type ToolCallItem = { | |
| type?: string; | |
| rawItem?: { output?: string }; | |
| }; | |
| const toolItem = [...newItems] | |
| .reverse() | |
| .find( | |
| (item): item is ToolCallItem => | |
| typeof item === "object" && | |
| item !== null && | |
| (item as ToolCallItem).type === "tool_call_item" && | |
| !!(item as ToolCallItem).rawItem?.output, | |
| ); | |
| if (toolItem?.rawItem?.output) { | |
| try { | |
| const parsedContent = JSON.parse(toolItem.rawItem.output); | |
| toolResponseData = { | |
| toolType: "google_calendar", | |
| result: parsedContent, | |
| }; | |
| } catch (e) { | |
| console.error("Error parsing tool response:", e); | |
| } | |
| } | |
| } | |
| const assistantMessage: ChatMessage = { | |
| id: `assistant-${Date.now()}`, | |
| role: "assistant", | |
| content: finalOutput, | |
| createdAt: new Date().toISOString(), | |
| toolResponses: toolResponseData ? [toolResponseData] : undefined, | |
| }; | |
| const response: AgentResponsePayload = { | |
| messages: [assistantMessage], | |
| toolResponses: assistantMessage.toolResponses, | |
| }; | |
| return NextResponse.json(response); | |
| } catch (error: unknown) { | |
| console.error("Error in chat route:", error); | |
| const errorMessage = | |
| error instanceof Error ? error.message : "Internal Server Error"; | |
| const assistantMessage: ChatMessage = { | |
| id: `assistant-error-${Date.now()}`, | |
| role: "assistant", | |
| content: | |
| "I ran into an error while using Composio Tool Router and Google Calendar. Please try again.", | |
| createdAt: new Date().toISOString(), | |
| toolResponses: [ | |
| { | |
| toolType: "tool_router", | |
| result: { | |
| successful: false, | |
| error: errorMessage, | |
| }, | |
| }, | |
| ], | |
| }; | |
| const response: AgentResponsePayload = { | |
| messages: [assistantMessage], | |
| toolResponses: assistantMessage.toolResponses, | |
| }; | |
| return NextResponse.json(response, { status: 500 }); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export type Role = "user" | "assistant"; | |
| export type ToolResponse = { | |
| toolType?: string; | |
| result?: { | |
| successful?: boolean; | |
| data?: { | |
| // Shape follows Composio Tool Router + Google Calendar event | |
| response_data?: { | |
| summary?: string; | |
| htmlLink?: string; | |
| start?: { dateTime?: string; timeZone?: string }; | |
| end?: { dateTime?: string; timeZone?: string }; | |
| attendees?: { | |
| email?: string; | |
| organizer?: boolean; | |
| responseStatus?: string; | |
| self?: boolean; | |
| }[]; | |
| organizer?: { email?: string; self?: boolean }; | |
| status?: string; | |
| id?: string; | |
| }; | |
| }; | |
| error?: unknown; | |
| }; | |
| }; | |
| export type Meeting = { | |
| id?: string; | |
| title: string; | |
| htmlLink?: string; | |
| start?: { dateTime?: string; timeZone?: string }; | |
| end?: { dateTime?: string; timeZone?: string }; | |
| attendees?: { | |
| email?: string; | |
| organizer?: boolean; | |
| responseStatus?: string; | |
| self?: boolean; | |
| }[]; | |
| organizerEmail?: string; | |
| status?: "confirmed" | "cancelled" | "tentative" | "unknown"; | |
| }; | |
| export type ChatMessage = { | |
| id: string; | |
| role: Role; | |
| content: string; | |
| createdAt: string; | |
| // Optional tool responses that this message is describing | |
| toolResponses?: ToolResponse[]; | |
| }; | |
| export type AgentRequestPayload = { | |
| messages: ChatMessage[]; | |
| }; | |
| export type AgentResponsePayload = { | |
| messages: ChatMessage[]; | |
| toolResponses?: ToolResponse[]; | |
| }; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment