Skip to content

OpenAI Agent

Build an agent using OpenAI’s function calling API that pushes ggui UIs to collect structured data from users.

Terminal window
npm install @ggui-ai/mcp-client openai

Set environment variables:

Terminal window
export OPENAI_API_KEY="sk-..."
export GGUI_API_KEY="ggui_sk_..."
export GGUI_APP_ID="app_..."
openai-agent.ts
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 function
const 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);
Terminal window
npx tsx openai-agent.ts
  • Uses OpenAI’s tools format (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 a tool_call_id
  • The ggui SDK usage is identical — push(), waitForCompletion(), close()