Merka2a Tools for the Vercel AI SDK
Define Merka2a search, negotiate, and order as Vercel AI SDK tools so generateText / streamText can run autonomous procurement with any model provider.
The Vercel AI SDK gives you a unified tool() + generateText interface across model providers, with built-in multi-step tool calling. Merka2a slots in as a small set of typed tools backed by the @merk.a2a/sdk client — so your Next.js or Node app can search, negotiate, and order in a single generateText call.
What We're Building
Three AI SDK tools (searchProducts, negotiate, placeOrder) and an agent call that loops through them with stopWhen.
Prerequisites
- Node.js 18+ or Bun
- A Merka2a API key (register here)
- A model provider key (OpenAI shown here)
Installation
npm install ai @ai-sdk/openai @merk.a2a/sdk zod
Step 1: The Client
import { Merka2aClient } from '@merk.a2a/sdk'
const merka2a = new Merka2aClient({
baseUrl: 'https://merka2a.com',
apiKey: process.env.MERKA2A_API_KEY,
})
Step 2: Define the Tools
Each tool() gets a Zod schema for type-safe arguments and an execute that calls the SDK.
import { tool } from 'ai'
import { z } from 'zod'
const tools = {
searchProducts: tool({
description: 'Search the Merka2a marketplace for products.',
parameters: z.object({
query: z.string().optional(),
category: z.string().optional(),
maxBudget: z.number().optional().describe('Max price in minor units'),
currency: z.string().default('GBP'),
limit: z.number().default(10),
}),
execute: async ({ query, category, maxBudget, currency, limit }) => {
const result = await merka2a.searchIntent(
{
category,
query,
budget: maxBudget
? { max: { amount: maxBudget, currency } }
: undefined,
},
{ limit },
)
return result.results ?? []
},
}),
negotiate: tool({
description: 'Negotiate a price on an offer. Returns the session and status.',
parameters: z.object({
offerId: z.string(),
targetPrice: z.number().describe('Target in minor units'),
currency: z.string().default('GBP'),
volume: z.number().default(1),
}),
execute: async ({ offerId, targetPrice, currency, volume }) => {
return merka2a.negotiate({
offerIds: [offerId],
targetPrice: { amount: targetPrice, currency },
volume,
})
},
}),
placeOrder: tool({
description: 'Place an order for an offer with shipping details.',
parameters: z.object({
offerId: z.string(),
quantity: z.number().default(1),
negotiationSessionId: z.string().optional(),
shippingCountry: z.string(),
shippingCity: z.string().optional(),
shippingPostalCode: z.string().optional(),
shippingMethod: z.enum(['standard', 'express', 'next-day']).default('standard'),
}),
execute: async (input) => {
return merka2a.createOrder({
offerId: input.offerId,
quantity: input.quantity,
negotiationSessionId: input.negotiationSessionId,
shippingAddress: {
country: input.shippingCountry,
city: input.shippingCity,
postalCode: input.shippingPostalCode,
},
shippingMethod: input.shippingMethod,
})
},
}),
}
Step 3: Run the Agent
stopWhen lets the model take multiple tool-calling steps before producing a final answer.
import { generateText, stepCountIs } from 'ai'
import { openai } from '@ai-sdk/openai'
const { text, steps } = await generateText({
model: openai('gpt-4-turbo'),
tools,
stopWhen: stepCountIs(10),
system:
'You are a procurement agent. Search, evaluate by price and specs, negotiate when worthwhile, then place the order. Prices are in minor units.',
prompt:
'Find a wireless mouse under £50, negotiate ~10% off, ship to London UK (EC1A 1BB).',
})
console.log(text)
Step 4: Stream to the Browser
In a Next.js Route Handler, swap generateText for streamText and return the stream — the same tools apply:
// app/api/procure/route.ts
import { streamText, stepCountIs } from 'ai'
import { openai } from '@ai-sdk/openai'
export async function POST(req: Request) {
const { prompt } = await req.json()
const result = streamText({
model: openai('gpt-4-turbo'),
tools,
stopWhen: stepCountIs(10),
prompt,
})
return result.toUIMessageStreamResponse()
}
Provider-Agnostic
Because the tools are plain tool() definitions, swapping providers is a one-line change — @ai-sdk/anthropic, @ai-sdk/google, etc. The Merka2a execute functions stay identical.
Next Steps
- OpenAI Integration Guide — raw function calling
- LlamaIndex Integration Guide — function tools in LlamaIndex
- API Reference — full endpoint documentation
Ready to add a marketplace to your AI SDK app? Get your API key →