> ## Documentation Index
> Fetch the complete documentation index at: https://developers.firmly.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Ask Agent SDK

> Build your own UI on top of Firmly's embeddable AI shopping assistant

<Info>
  **Ask Agent** is Firmly's embeddable AI shopping assistant — it answers product and store
  questions, recommends products, and can hand shoppers into checkout, right on the merchant's own
  site. `@firmly/ask-agent-sdk` is the **headless, bring-your-own-UI** path to it: you render the
  chat experience yourself, on the same backend that powers Firmly's drop-in widget.
</Info>

## Headless SDK vs. drop-in embed

Every Ask Agent integration talks to the same backend. The only choice is who renders the UI.

<Tabs>
  <Tab title="Drop-in embed (script tag)">
    Add one script tag and Firmly renders the entire chat UI (launcher, panel, and voice) inside an
    iframe. Zero application code.

    ```html theme={null}
    <script
      src="https://chat.example.com/v1/embed.js"
      data-merchant="your-store.com"
      async
    ></script>
    ```

    **Use this when** you want Ask Agent live in minutes and are fine with Firmly's iframe UI and
    styling.
  </Tab>

  <Tab title="Headless SDK (bring your own UI)">
    Bring in `@firmly/ask-agent-sdk` and build the chat surface with your own components, using the
    [Vercel AI SDK UI](https://ai-sdk.dev) (`useChat` / `Chat`) as the state layer. The SDK supplies
    the transport, tool-call dispatching, session bootstrap, and capability negotiation that talk to
    the same Firmly backend the drop-in embed uses.

    **Use this when** you need the assistant to match your app's design system, live inline in a
    native (non-iframe) surface, or run inside a framework shell the drop-in embed can't reach.
  </Tab>
</Tabs>

## How it works

```mermaid theme={null}
flowchart LR
    subgraph Merchant["your-store.com"]
        Page["Merchant page"]
        UI["Your UI<br/>(built on @firmly/ask-agent-sdk)"]
        Hooks["Data hooks<br/>(your JS, shopper's session)"]
    end

    subgraph Firmly["Firmly backend"]
        Chat["/api/chat<br/>(streaming)"]
        Caps["/api/embed/capabilities"]
    end

    Page --> UI
    UI -- "first-party session cookie" --> Chat
    UI --> Caps
    Chat -- "client-executing tool call" --> Hooks
    Hooks -- "shopper data" --> UI
```

Your UI runs on the merchant's own origin, so requests ride the shopper's existing first-party
session cookie — no API keys in the browser. On load, the SDK's `createSession()` mints or refreshes
a short-lived browser-session token; `createAskAgentTransport()` then streams turns to `/api/chat`
and fetches the merchant's effective configuration from `/api/embed/capabilities`.

## Core concepts

**Capabilities → tools and components.** Every renderable piece of the agent's response (a product
card, a carousel, follow-up chips, the checkout handoff) is backed by a named tool. You call
`defineCapabilities({ components: [...] })` to declare which components your UI can render; the SDK
resolves that list to the concrete tool names (`supportedTools`) sent with every chat request. The
backend intersects your declared list with what the merchant has enabled in the dash — your
declaration can only narrow the tool set, never widen it beyond the merchant's configuration.

**Data hooks.** Some tools are "client-executing": the agent asks a question like "is this shopper
logged in?" or "what are their recent orders?", and your host page — not Firmly's backend — answers
it, because only the merchant's own JavaScript has access to the shopper's session on that page. The
SDK's tool dispatcher routes these calls to a `runDataHook` handler you provide, then feeds the
result back to resume the agent turn.

**First-party session.** The SDK never asks you for an API key. It bootstraps a browser-session
token over the shopper's existing first-party cookie, the same mechanism the drop-in embed uses, so
your UI and Firmly's backend share one session model.

**The IP boundary.** `/api/embed/capabilities` returns only client-safe data — the effective
tool/component set and presentation config. It never returns the system prompt, custom-instruction
text, or data-hook implementation details; those stay server-side. A handful of tools are
`hidden` — server-side metadata or pre-checks the model uses internally — and are never exposed to
your UI to render or gate.

## Next steps

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/ask-agent/quickstart">
    Wire up `@firmly/ask-agent-sdk` and render your first Ask Agent turn.
  </Card>

  <Card title="Reference" icon="book" href="/ask-agent/reference">
    Full reference for capabilities, transport, session, and the tool dispatcher.
  </Card>
</CardGroup>
