Skip to main content
This walks through building a minimal Ask Agent chat surface with @firmly/ask-agent-sdk on top of the Vercel AI SDK UI (@ai-sdk/svelte’s Chat). Every SDK call below uses the real exported function names and parameters — nothing here is illustrative pseudocode. A few host-supplied glue functions (e.g. currentShopper, runMerchantHook) are your own code, not SDK exports — each is marked inline where it appears.
1

Install

@firmly/ask-agent-sdk isn’t on npm yet — it’s available on request. Contact Firmly for access to the package.
The SDK ships as an ES module with a single optional peer dependency:
package.json
ai (v6) is only required once you actually construct a transport or chat — a host that only needs defineCapabilities/createToolDispatcher can import the SDK without it. For this Svelte walkthrough, also install the AI SDK’s Svelte binding:
2

Fetch the merchant's config

fetchAskAgentConfig calls the backend’s /api/embed/capabilities endpoint and returns only client-safe data — the merchant’s effective tool/component set and presentation config, never the system prompt or hook implementations.
3

Declare capabilities

Tell the SDK which UI components your host can render. It resolves that list down to the concrete tool names — supportedTools — that ride on every chat request. Your declaration can only narrow the merchant’s enabled tool set, never widen it.
4

Bootstrap the session

A standalone host running on the merchant’s own origin needs a first-party browser-session token before it can call /api/chat. createSession mints or refreshes it over the shopper’s existing session cookie — no API keys in the browser.
5

Create the transport

createAskAgentTransport returns an AI SDK v6 ChatTransport that posts to /api/chat and injects pageContext/shopperContext/supportedTools into the request body on every turn.
getPageContext and getShopperContext are functions you supply, each returning a plain object (or a Promise of one) fetched fresh per turn — e.g. the current PDP/category the shopper is on, or { user, orders } from your own session state.
6

Build the tool dispatcher

Some tools are client-executing: the agent asks a question only your host page can answer (because only the merchant’s own JavaScript has the shopper’s session), and your dispatcher handlers answer it.
  • runDataHook({ name, input }) — runs the merchant’s data-hook JS for the requested hook name and returns its JSON-serializable result; the SDK feeds it back to the model via addToolResult.
  • onCheckout(input) — fires when the agent calls proceed_to_checkout; swap your UI into checkout. The server tool already resolved, so this handler does not call addToolResult.
  • onBuyNow(input) — resolves a buy_now call (variant lookup + cart/checkout handoff) and returns output the SDK feeds back so the model can confirm the action.
7

Wire the chat

Drop the transport and dispatcher into @ai-sdk/svelte’s Chat:

Complete example

Putting the six pieces together in one component:
shouldResumeAfterHook is the hooks-only baseline for sendAutomaticallyWhen — it resumes the turn once every data-hook tool call in the latest message has a result. Hosts that also intercept custom UI components or buy_now outside the dispatcher (as Firmly’s own dogfood widget does) may need a richer resume predicate that additionally accounts for those tool calls.
The SDK is framework-agnostic (built on AI SDK v6): the same defineCapabilities, createSession, createAskAgentTransport, and createToolDispatcher calls work unchanged with React’s useChat or any other AI SDK UI binding — only the chat hook itself differs.
You need the assistant to match your app’s design system, render inline in a native (non-iframe) surface, or run inside a framework shell the drop-in embed can’t reach.

Next steps

Reference

Full reference for capabilities, transport, session, and the tool dispatcher.

Overview

How the headless SDK fits alongside the drop-in embed.