OpenAI Agent
Build an agent using OpenAI’s function calling API that pushes ggui UIs to collect structured data from users.
npm install @ggui-ai/mcp-client openaiSet environment variables:
export OPENAI_API_KEY="sk-..."export GGUI_API_KEY="ggui_sk_..."export GGUI_APP_ID="app_..."import OpenAI from "openai";import { GguiClient } from "@ggui-ai/mcp-client";
const openai = new OpenAI();const ggui = new GguiClient({ apiKey: process.env.GGUI_API_KEY!, appId: process.env.GGUI_APP_ID!,});
// Define ggui as an OpenAI functionconst tools: OpenAI.ChatCompletionTool[] = [ { type: "function", function: { name: "show_ui", description: "Show an interactive UI to the user to collect structured data, display information, or present choices.", parameters: { type: "object", properties: { prompt: { type: "string", description: "Natural language description of the UI to generate", }, context: { type: "object", description: "Data to pass into the UI (visible to the generated component)", }, }, required: ["prompt"], }, }, },];
async function showUi(args: { prompt: string; context?: Record<string, unknown>;}): Promise<string> { const { sessionId, url } = await ggui.push({ story: { intent: args.prompt, prompt: args.prompt, context: args.context, }, });
console.log(`\n--- UI Ready: ${url} ---\n`);
const events = await ggui.waitForCompletion(sessionId, { pollInterval: 2000, maxWait: 300_000, });
await ggui.close(sessionId);
const submitEvent = events.find((e) => e.type === "data:submit"); return JSON.stringify( submitEvent ? { status: "submitted", data: submitEvent.payload } : { status: "no_submission" } );}
async function chat(userMessage: string) { console.log(`\nUser: ${userMessage}`);
const messages: OpenAI.ChatCompletionMessageParam[] = [ { role: "system", content: "You are a helpful assistant. Use the show_ui function when you need to collect structured data from the user.", }, { role: "user", content: userMessage }, ];
let response = await openai.chat.completions.create({ model: "gpt-5.2", messages, tools, });
let message = response.choices[0].message;
// Handle function calls in a loop while (message.tool_calls && message.tool_calls.length > 0) { messages.push(message);
for (const toolCall of message.tool_calls) { const args = JSON.parse(toolCall.function.arguments); const result = await showUi(args);
messages.push({ role: "tool", tool_call_id: toolCall.id, content: result, }); }
response = await openai.chat.completions.create({ model: "gpt-5.2", messages, tools, }); message = response.choices[0].message; }
console.log(`\nAssistant: ${message.content}`);}
chat("Help me plan a team dinner for 8 people").catch(console.error);npx tsx openai-agent.tsKey Differences from Claude Example
Section titled “Key Differences from Claude Example”- Uses OpenAI’s
toolsformat (function definitions) instead of Anthropic’s tool format - Function call arguments come as a JSON string that needs
JSON.parse() - Tool results are sent as
role: 'tool'messages with atool_call_id - The ggui SDK usage is identical —
push(),waitForCompletion(),close()