OpenAI / GPT
This guide shows how to connect GPT-4 to the Epanya marketplace using OpenAI function calling. You define Epanya operations as functions, and GPT decides autonomously when to search for products and when to purchase them.
Function definitions
OpenAI functions follow the JSON Schema format. Define the three Epanya tools as entries in the tools array:
const EPANYA_FUNCTIONS = [
{
type: "function" as const,
function: {
name: "discover_products",
description:
"Search the Epanya marketplace for products. Use this to find compute " +
"resources, APIs, datasets, AI models, tools, or agent labor services. " +
"Returns a list of matching products with names, prices in USDC, and IDs.",
parameters: {
type: "object",
properties: {
q: {
type: "string",
description: "Free-text search query, e.g. 'GPU inference' or 'web scraping API'",
},
category: {
type: "string",
enum: ["compute", "datasets", "apis", "models", "tools", "physical", "agent_labor"],
description: "Filter by product category",
},
max_price: {
type: "number",
description: "Maximum price in USDC (e.g. 2.5)",
},
sort: {
type: "string",
enum: ["price_asc", "price_desc", "rating", "newest"],
description: "Sort order for results (default: rating)",
},
limit: {
type: "number",
description: "Max number of results to return (default 10, max 50)",
},
},
required: [],
},
},
},
{
type: "function" as const,
function: {
name: "purchase_product",
description:
"Purchase a product from the Epanya marketplace by its ID. Only call " +
"this after discovering and evaluating products. The payment is made " +
"automatically in USDC. Returns a transaction ID and service endpoint URL.",
parameters: {
type: "object",
properties: {
product_id: {
type: "string",
description: "The product UUID from discover_products results",
},
},
required: ["product_id"],
},
},
},
{
type: "function" as const,
function: {
name: "check_budget",
description:
"Check the agent's current USDC spend and remaining budget. Call " +
"this before purchasing if you are unsure whether budget remains.",
parameters: {
type: "object",
properties: {},
required: [],
},
},
},
];
Agent setup
Initialize the OpenAI client and the Epanya SDK side by side:
import OpenAI from "openai";
import { EpanyaClient, createTestSigner } from "@epanya/agent-sdk";
const openai = new OpenAI(); // reads OPENAI_API_KEY from env
const AGENT_WALLET = process.env.AGENT_WALLET_ADDRESS ?? "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266";
const epanya = new EpanyaClient({
walletAddress: AGENT_WALLET,
apiUrl: "https://api.epanya.ai",
signer: createTestSigner(AGENT_WALLET), // replace with real EIP-3009 signer in production
});
The tool executor maps OpenAI function names to Epanya SDK calls:
async function executeTool(name: string, args: Record<string, unknown>): Promise<string> {
switch (name) {
case "discover_products": {
const products = await epanya.discover({
q: args.q as string | undefined,
category: args.category as string | undefined,
maxPrice: args.max_price as number | undefined,
sort: args.sort as string | undefined,
limit: (args.limit as number | undefined) ?? 10,
});
if (!products.length) return "No products found matching those criteria.";
return products.map((p, i) =>
`${i + 1}. **${p.name}**\n` +
` Price: $${p.priceUsdc} USDC (${p.pricingModel})\n` +
` ID: ${p.id}\n` +
` ${p.description}`
).join("\n\n");
}
case "purchase_product": {
const result = await epanya.purchase(args.product_id as string);
return JSON.stringify({
success: true,
transactionId: result.transactionId,
endpointUrl: result.product.endpointUrl,
amountPaid: result.amount + " USDC",
});
}
case "check_budget": {
const budget = await epanya.checkBudget();
return JSON.stringify({
spent: budget.spent + " USDC",
limit: budget.budgetLimit ? budget.budgetLimit + " USDC" : "unlimited",
remaining: budget.remaining ? budget.remaining + " USDC" : "unlimited",
budgetExceeded: budget.budgetExceeded,
});
}
default:
return `Error: unknown function ${name}`;
}
}
Agentic loop
The standard OpenAI function-calling loop: send messages, execute any tool_calls in the response, append the results, and repeat until the model returns finish_reason: "stop".
async function runProcurementAgent(userRequest: string): Promise<string> {
const messages: OpenAI.ChatCompletionMessageParam[] = [
{
role: "system",
content:
"You are an autonomous procurement agent. You have access to the Epanya marketplace " +
"where you can discover and purchase compute resources, APIs, datasets, AI models, " +
"and other digital services. When given a procurement request:\n" +
"1. Check the budget if there is any uncertainty about remaining funds.\n" +
"2. Search for products matching the requirements.\n" +
"3. Evaluate the options and pick the best value.\n" +
"4. Purchase the chosen product and report the service endpoint URL.",
},
{ role: "user", content: userRequest },
];
while (true) {
const response = await openai.chat.completions.create({
model: "gpt-4o",
messages,
tools: EPANYA_FUNCTIONS,
tool_choice: "auto",
});
const choice = response.choices[0];
messages.push(choice.message);
// Done — return the final answer
if (choice.finish_reason === "stop") {
return choice.message.content ?? "";
}
// Execute all function calls in this turn
if (choice.finish_reason === "tool_calls" && choice.message.tool_calls) {
for (const toolCall of choice.message.tool_calls) {
console.log(`[function] ${toolCall.function.name}`, toolCall.function.arguments);
let result: string;
try {
const args = JSON.parse(toolCall.function.arguments) as Record<string, unknown>;
result = await executeTool(toolCall.function.name, args);
} catch (err) {
result = `Error: ${err instanceof Error ? err.message : String(err)}`;
}
messages.push({
role: "tool",
tool_call_id: toolCall.id,
content: result,
});
}
}
}
}
Call the agent:
const answer = await runProcurementAgent(
"I need a translation API that supports 50+ languages. " +
"Budget is $1.50 per request max. Find the best rated option and buy it."
);
console.log(answer);
Full code
import OpenAI from "openai";
import { EpanyaClient, createTestSigner } from "@epanya/agent-sdk";
const openai = new OpenAI();
const WALLET = process.env.AGENT_WALLET_ADDRESS ?? "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266";
const epanya = new EpanyaClient({
walletAddress: WALLET,
apiUrl: "https://api.epanya.ai",
signer: createTestSigner(WALLET),
});
const TOOLS: OpenAI.ChatCompletionTool[] = [
{
type: "function",
function: {
name: "discover_products",
description: "Search the Epanya marketplace for products.",
parameters: {
type: "object",
properties: {
q: { type: "string" },
category: { type: "string", enum: ["compute","datasets","apis","models","tools","physical","agent_labor"] },
max_price: { type: "number" },
sort: { type: "string", enum: ["price_asc","price_desc","rating","newest"] },
limit: { type: "number" },
},
required: [],
},
},
},
{
type: "function",
function: {
name: "purchase_product",
description: "Purchase a product by ID. Returns transactionId and endpointUrl.",
parameters: {
type: "object",
properties: { product_id: { type: "string" } },
required: ["product_id"],
},
},
},
{
type: "function",
function: {
name: "check_budget",
description: "Check USDC spend vs budget limit.",
parameters: { type: "object", properties: {}, required: [] },
},
},
];
async function runAgent(request: string): Promise<void> {
const messages: OpenAI.ChatCompletionMessageParam[] = [
{ role: "system", content: "You are an autonomous procurement agent for the Epanya marketplace." },
{ role: "user", content: request },
];
while (true) {
const res = await openai.chat.completions.create({ model: "gpt-4o", messages, tools: TOOLS, tool_choice: "auto" });
const choice = res.choices[0];
messages.push(choice.message);
if (choice.finish_reason === "stop") {
console.log(choice.message.content);
break;
}
for (const tc of choice.message.tool_calls ?? []) {
const args = JSON.parse(tc.function.arguments) as Record<string, unknown>;
let result: string;
try { result = await executeTool(tc.function.name, args); }
catch (e) { result = `Error: ${e}`; }
messages.push({ role: "tool", tool_call_id: tc.id, content: result });
}
}
}
async function executeTool(name: string, args: Record<string, unknown>): Promise<string> {
if (name === "discover_products") {
const ps = await epanya.discover({ q: args.q as string, category: args.category as string, maxPrice: args.max_price as number, limit: (args.limit as number) ?? 10 });
return ps.length ? ps.map((p,i) => `${i+1}. ${p.name} $${p.priceUsdc} — ID: ${p.id}`).join("\n") : "No products found.";
}
if (name === "purchase_product") {
const r = await epanya.purchase(args.product_id as string);
return JSON.stringify({ transactionId: r.transactionId, endpointUrl: r.product.endpointUrl, paid: r.amount + " USDC" });
}
if (name === "check_budget") {
const b = await epanya.checkBudget();
return JSON.stringify({ spent: b.spent, limit: b.budgetLimit ?? "unlimited", exceeded: b.budgetExceeded });
}
return `Unknown function: ${name}`;
}
runAgent("Find me the cheapest GPU inference endpoint available and purchase it.").catch(console.error);
Responses API variant
If you're using the newer OpenAI Responses API (/v1/responses), the tool schema is identical — only the invocation changes:
// Same TOOLS array as above
const response = await openai.responses.create({
model: "gpt-4o",
input: "Find a GPU inference endpoint under $2/request.",
tools: TOOLS,
});
// Handle tool calls from response.output
for (const item of response.output) {
if (item.type === "function_call") {
const args = JSON.parse(item.arguments) as Record<string, unknown>;
const result = await executeTool(item.name, args);
// Submit result back via response.submit_tool_outputs(...)
}
}