Agent frameworks / Vercel AI SDK

Vercel AI SDK

Give an agent built on the Vercel AI SDK the two AIX operations as tools, through the MCP server or defined in code, with the timing rules the model needs.

The Vercel AI SDK is the TypeScript library most JavaScript chat agents are built on. It has nothing to do with where your app is hosted. An AIX integration gives the model two tools: submit_intent after any turn that states or changes what the shopper wants to buy, and report_handoff before the shopper is sent to a store. Both run on your server with your key; the browser never sees it.

Two ways to get there. Through the MCP server the tools appear by themselves; defined in code you control the schema and keep AIX out of the model's tool list until you need it.

Through the MCP server

Install the MCP client package next to ai, then connect with your key from the environment. The tools AIX exposes for a publisher key are submit_intent, report_handoff, delete_session and get_activity. The MCP submit_intent tool takes one argument, intent, with the same body as POST /intents (its turn input is reserved for Brambles-managed publishers; the model must send exactly one of the two).

bash
npm install ai @ai-sdk/mcp
ts
import { streamText } from "ai";
import { createMCPClient } from "@ai-sdk/mcp";
const mcpClient = await createMCPClient({
transport: {
type: "http",
url: "https://aix.brambles.ai/api/aix/mcp",
headers: { Authorization: `Bearer ${process.env.AIX_PUBLISHER_KEY}` },
},
});
const tools = await mcpClient.tools();
const result = await streamText({
model: yourModel,
system: AIX_RULES, // see below
tools,
messages,
onEnd: async () => {
await mcpClient.close();
},
});

For a one-shot call use generateText with the same tools and close the client in a finally block.

Defined in code

No extra package: two tool() definitions and one fetch helper with a three-second timeout. AIX must never slow down or break the shopper's experience, so every failure returns a skipped result instead of throwing. submit_intent takes the same { intent } argument as the MCP tool, so one prompt works whichever way the tools arrive.

ts
import { tool } from "ai";
import { z } from "zod";
const AIX = "https://aix.brambles.ai/api/aix";
async function aix(path: string, body: unknown) {
const key = process.env.AIX_PUBLISHER_KEY;
if (!key) return { status: "skipped", reason: "no_key" };
try {
const res = await fetch(`${AIX}/${path}`, {
method: "POST",
headers: { authorization: `Bearer ${key}`, "content-type": "application/json" },
body: JSON.stringify(body),
signal: AbortSignal.timeout(3000),
});
return res.ok ? await res.json() : { status: "skipped", reason: `http_${res.status}` };
} catch {
return { status: "skipped", reason: "timeout" }; // never block the shopper
}
}
const fact = z.object({
attribute: z.enum(["brand", "width", "size", "department", "use_case", "feature", "merchant", "deal"]),
value: z.string(),
strength: z.enum(["required", "preferred", "excluded"]),
});
export const aixTools = {
submit_intent: tool({
description:
"Report the shopper's current shopping task to AIX. Call after any turn that states or changes what they want to buy. Shopping requirements only, never personal data.",
inputSchema: z.object({
intent: z.object({
session_id: z.string().min(1).max(128),
country: z.string().length(2),
task: z.object({
category: z.string(),
summary: z.string().max(1600),
budget: z.object({ currency: z.string().length(3), max_cents: z.number().int() }).optional(),
facts: z.array(fact),
}),
}),
}),
execute: ({ intent }) => aix("intents", intent),
}),
report_handoff: tool({
description:
"Report that the shopper is being sent to a store or product page (the store's own URL). Returns landing_url, the store URL with AIX's id appended; use it as that page's URL, inside your affiliate link if you use one.",
inputSchema: z.object({
session_id: z.string(),
destination_url: z.string().url(),
consent: z.enum(["granted", "denied"]).optional(),
}),
execute: (input) => aix("handoffs", input),
}),
};

Then streamText({ model, system: AIX_RULES, tools: aixTools, messages }). The schemas mirror the intent and handoff bodies; session_id is your conversation id and AIX stores only a keyed hash of it.

The rules the model needs

Whichever way the tools arrive, the model has to know when to use them. Add this to your system prompt:

text
You can send shopping intent to the Agentic Intent Exchange (AIX).
- After any user turn that states or changes what they want to buy, call submit_intent with one
argument, intent: an object holding the conversation's session_id, the shopper's two-letter
country, and the task: a category, a one-line summary, the budget when they gave one, and facts
with attribute, value and strength (required, preferred or excluded). Send only shopping
requirements: never names, emails, phone numbers, addresses, account or order numbers, or the
conversation itself.
- Before you give the user a link to a store or product page, call report_handoff with the same
session_id and the store's page URL, then use the returned landing_url as that page's URL (inside
your own affiliate or ad link, if you use one).
- If either tool fails or is slow, carry on without it. Never ask the user for a key.

Set country on the server from your host's geolocation header rather than asking the shopper. Shoppers in the EEA, the UK or Switzerland are shared only with consent: show one line under your assistant, "Clicking a store link shares your shopping request with that store", and pass consent: "granted" on handoffs from those clicks. Health, sexual wellness, religion, politics and the other sensitive topics are suppressed by AIX on arrival; never reword a task to get it through.

Receiving side

A store's agent uses the same connection with AIX_RECEIVER_KEY. The tools then list deliveries (subscribe_intents), read one receipt (get_intent_context), acknowledge it (acknowledge_delivery) and redeem a handoff id from a landing or a checkout (redeem_handoff; with a sandbox key it returns a free test delivery for any well-formed id). Verification and acknowledgment belong on your server; see Receiving agents.

Test it

  1. Create a free sending agent in the AIX console and store the sandbox key as AIX_PUBLISHER_KEY.
  2. Run one conversation that names a product and ends with a store link. The intent answers accepted; the handoff answers test_delivered with a receiver_preview.
  3. GET /activity with the same key, or the AIX console, shows the test. Create the production key there and set it in production.
Was this helpful?