/** A support agent that reads orders through your code. */
import OpenAI from 'openai';
const client = new OpenAI({ apiKey: process.env.ORCA_API_KEY!, baseURL: process.env.ORCA_BASE_URL! });
const agents = client.beta.agents;
const ORDERS: Record<string, object> = {
'order-42': { status: 'shipped', carrier: 'UPS', eta: '2026-10-14' },
'order-43': { status: 'processing' },
};
const TICKETS: { order_id: string; reason: string }[] = [];
const objectSchema = (...names: string[]) => ({
type: 'object',
properties: Object.fromEntries(names.map(name => [name, { type: 'string' }])),
required: names,
additionalProperties: false,
});
const INSTRUCTIONS = `You answer customer questions about their orders. Be brief and friendly.
Use lookup_order for any question about an order. Never guess an order's status.
If the customer has not given an order ID, ask for it in one sentence.
If they want a refund, call request_refund with the order ID and their reason,
then tell them a person will review it within one business day.
Do not promise a refund. Do not use emojis.`;
// The model chooses these arguments. Validate them like any untrusted request.
const handlers = {
lookup_order: (args: Record<string, unknown>) => {
const orderId = String(args.order_id ?? '');
return Object.hasOwn(ORDERS, orderId) ? ORDERS[orderId] : { error: 'No order with that ID.' };
},
request_refund: (args: Record<string, unknown>) => {
const orderId = String(args.order_id ?? '');
if (!Object.hasOwn(ORDERS, orderId)) return { error: 'No order with that ID.' };
TICKETS.push({ order_id: orderId, reason: String(args.reason ?? '').slice(0, 500) });
return { ticket: `T-${TICKETS.length}`, status: 'queued for review' };
},
};
/** Send one message, answer tool calls, and return the agent's reply. */
async function ask(sessionId: string, text: string) {
for await (const _ of agents.sessions.stream(sessionId, { input: text, toolHandlers: handlers })) {
// read to the end, or the helper stops answering calls
}
for (const item of (await agents.sessions.items.list(sessionId, { limit: 20 })).data as any[]) {
if (item.type === 'message' && item.role === 'assistant') {
return (item.content ?? []).map((p: any) => p.text).filter(Boolean).join(' ');
}
}
return '';
}
let agent: { id: string } | undefined;
let session: { id: string } | undefined;
try {
agent = await agents.create({
model: process.env.ORCA_MODEL!,
name: 'support',
instructions: INSTRUCTIONS,
tools: [
{
type: 'function',
name: 'lookup_order',
description: 'Read one order by ID. Use when the customer asks about an order.',
parameters: objectSchema('order_id'),
defer_loading: false,
},
{
type: 'function',
name: 'request_refund',
description: 'Record a refund request for a person to review. Does not issue a refund.',
parameters: objectSchema('order_id', 'reason'),
defer_loading: false,
},
],
});
session = await agents.sessions.create({ agent_id: agent.id, environment: { type: 'none' } });
console.log(await ask(session.id, 'Where is my order?'));
console.log(await ask(session.id, "It's order-42."));
console.log(await ask(session.id, 'It arrived broken. I want my money back.'));
console.log('tickets:', TICKETS);
} finally {
// Delete each resource on its own, so one failed delete does not skip the rest.
if (session) await agents.sessions.delete(session.id).catch(() => {});
if (agent) await agents.delete(agent.id).catch(() => {});
}