m4Mindset docs

Mindset v3 / Deploy in your app / Agent Chat SDK 3: Client-side Integration APIs

View as Markdown

How to integrate the Mindset AI agent into your application

End-to-end walkthrough, from a blank page to an agent running against your data, with the client-side APIs ready to drive.

This guide walks through a Mindset AI agent integration from the start. By the end, you'll have an agent loading on your page, authenticating your user, and ready to use the client-side APIs (page tools, situational awareness, pass-through parameters, DOM events) that let your page talk to it. These APIs work whether you keep the built-in chat UI or render your own.

The integration has four pieces:

  1. Configure the agent in the Agent Management Studio (tools, knowledge, behavior).
  2. Set up your token endpoint, so your backend mints SDK tokens for your users.
  3. Add the SDK script and element to your page: one <script> tag, one <mindset-agent> element.
  4. Initialize and (optionally) build your UI. Call mindset.init(), then either let the agent render itself or hook into its events.

Each piece is independent. You can do (1) and (2) ahead of time, then iterate on (3) and (4) until the integration feels right.


Prerequisites

Before you start, you'll need:

  • A Mindset AI account and an app set up in the Agent Management Studio. This gives you an appUid and lets you build agents.
  • An agent configured with your tools and knowledge. Each agent has an agent-uid. You'll reference this from your page.
  • A backend that can call sdkusersapi to mint a token for the current user. Mindset AI doesn't talk to your auth system; you do, and you hand a token to the SDK.
  • A page where you can add a <script> tag. Vanilla HTML, React, Vue, Svelte, or any other setup that produces HTML works.

  1. Configure your agent

    Sign in to the Agent Management Studio, build the agent you want, and copy its agent-uid. You'll paste this into your HTML in step 3.

    See the Agent Management Studio walkthrough for a full tour of AMS, or Creating Agents for a focused agent-build guide.

  2. Set up your token endpoint

    The Mindset AI SDK never talks directly to your authentication system. Instead, it asks your app for a token using a callback you provide. Your callback hits an endpoint on your backend; that endpoint calls sdkusersapi with your API key to mint an SDK token for the current user.

    The flow:

    text
    Browser (your app)         Your backend             Mindset (sdkusersapi)
           │                         │                          │
           │ GET /api/mindset-token  │                          │
           ├────────────────────────▶│                          │
           │                         │ Auth + mint SDK token    │
           │                         ├─────────────────────────▶│
           │                         │                          │
           │                         │◀─────────────────────────┤
           │                         │  authToken               │
           │◀────────────────────────┤                          │
           │  { authToken }          │                          │
           │                         │                          │

    Your endpoint:

    • Authenticates the request using your existing session, JWT, or whatever you already have
    • Maps the user to a Mindset AI identity (you choose the strategy, typically your user ID becomes their Mindset AI user ID)
    • Calls sdkusersapi with your Mindset AI API key to mint a token
    • Returns the token to the browser

    See the SDK 3 Authentication guide for the full setup, including request body, headers, and example implementations. The SDK Users API reference has the parameter-level detail.

  3. Add the SDK script and element

    Add the SDK bundle and your <mindset-agent> element to the page.

    html
    <!DOCTYPE html>
    <html>
    <head>
      <script src="MINDSET-SERVER-URL/mindset-sdk3.umd.js"></script>
    </head>
    <body>
      <mindset-agent agent-uid="agt-your-agent-uid"></mindset-agent>
    </body>
    </html>

    Two things happen automatically:

    • The <script> registers <mindset-agent> as a custom element. After this, customElements.get('mindset-agent') returns the constructor.
    • The element is added to the DOM. The connectedCallback fires, the element dispatches mindset:agent-registered, and queues itself for runtime binding.

    The element doesn't load anything yet. It's waiting for mindset.init() to bind it to a runtime instance.

    Choose your mode

    The element has two modes, set with the headless attribute.

    In the default mode (no headless attribute), Mindset AI renders a chat UI inside the element. Your users get a working chat experience with no UI code on your side.

    In headless mode (headless attribute present), the element runs the agent and dispatches DOM events, but renders nothing. You build the UI.

    If you're not sure which to pick, start with the default mode. Switch to headless later if you need full UI control.

    html
    <!-- Built-in chat UI -->
    <mindset-agent agent-uid="agt-..."></mindset-agent>
    
    <!-- Headless: you build the UI -->
    <mindset-agent agent-uid="agt-..." headless></mindset-agent>

    The runtime, auth flow, state machine, and DOM events are identical in both modes. The only difference is whether the element renders its own chat UI.

  4. Initialize the SDK

    Call mindset.init() once. This wires up the runtime, calls your fetchAuthentication callback, and starts loading the agent.

    html
    <script>
      window.mindset.init({
        appUid: 'your-app-uid',
        fetchAuthentication: async () => {
          const r = await fetch('/api/mindset-token', { credentials: 'include' });
          const { authToken } = await r.json();
          return authToken;
        },
      });
    </script>

    You can call init before or after the <mindset-agent> element is added to the DOM. Both orders work. The SDK uses a MutationObserver to find elements added later, so React, Vue, and other frameworks that mount the element in a component lifecycle work without extra wiring.

    After init succeeds, each <mindset-agent> on the page fires:

    text
    mindset:agent-initializing
    mindset:agent-idle              ← ready to take input

    Listen for mindset:agent-idle if you want to know when an agent is ready.


Step 5: Render the UI

If you went with default mode, you're done. Mindset AI renders a chat panel inside the element. Users can chat, switch threads, and view the history.

You can still hook into events if you want to react to what the agent does:

js
const agent = document.querySelector('mindset-agent');

agent.addEventListener('mindset:thread-changed', (e) => {
  // Sync the active thread to your URL. threadUid can be null between threads
  // (e.g. immediately after newThread() before the user's first message persists).
  if (e.detail.threadUid) {
    history.pushState({}, '', `?thread=${e.detail.threadUid}`);
  }
});

agent.addEventListener('mindset:complete', (e) => {
  // Track turn completions in your analytics
  analytics.track('agent_turn_complete', {
    agentUid: agent.getAttribute('agent-uid'),
    responseLength: e.detail.response.length,
  });
});

You can drive the agent programmatically too, for example to open a thread when the user clicks something on your page:

js
async function openSupportThread(threadUid) {
  const agent = document.querySelector('mindset-agent');
  await agent.switchThread(threadUid);
}

See the Examples page (Built-in chat UI tab) for a complete working setup.

In headless mode, the element runs the agent and dispatches DOM events. You write the UI.

The minimum you need:

  • An input control (textarea, contenteditable div, your own component)
  • An output area for the agent's reply
  • Event listeners for mindset:text-delta (streaming output) and mindset:complete (turn end)
  • A call to agent.sendMessage(text) when the user submits
html
<mindset-agent agent-uid="agt-..." headless id="agent"></mindset-agent>

<div id="output"></div>
<textarea id="input"></textarea>
<button id="send">Send</button>

<script>
  const agent = document.getElementById('agent');
  const output = document.getElementById('output');
  const input = document.getElementById('input');

  let currentReply = '';

  agent.addEventListener('mindset:agent-busy', () => {
    currentReply = '';
    output.textContent = '';
  });

  agent.addEventListener('mindset:text-delta', (e) => {
    currentReply += e.detail.content;
    output.textContent = currentReply;
  });

  // sendWhenIdle queues the send if the agent is busy (e.g. running its
  // icebreaker turn after init). See "Choosing when to send" below.
  function sendWhenIdle(text) {
    if (!agent.isAgentBusy()) {
      agent.sendMessage(text);
    } else {
      agent.addEventListener('mindset:agent-idle', () => sendWhenIdle(text), { once: true });
    }
  }

  document.getElementById('send').addEventListener('click', () => {
    sendWhenIdle(input.value);
    input.value = '';
  });
</script>

Choosing when to send

sendMessage throws if the agent is busy. The most common place this trips people up is the first send. If your agent is configured with an icebreaker (a turn that fires automatically as the agent settles after init), the lifecycle is agent-idle (init done) → agent-busy (icebreaker streaming) → agent-idle (icebreaker done). A user who clicks Send during that first window will hit a busy throw.

The sendWhenIdle helper above handles this. It sends straight away if the agent is idle, otherwise it waits for the next mindset:agent-idle and recurses. Safe to call at any point, with or without an icebreaker configured. See the methods reference for the full pattern.

This is the minimum. From here you'll typically add:

  • Thread management (list, switch, create, delete) via thread CRUD methods
  • Tool widgets that render mindset:tool-end payloads for tools that produce visual artifacts
  • Quick replies and follow-ups, rendering mindset:quick-replies and mindset:follow-up-questions as buttons
  • Citations and references, displaying sources from mindset:references

See the Examples page for three complete headless integrations: vanilla HTML (thread management and widget rendering), React (component pattern with refs, useEffect, and cleanup), and Angular (standalone components, signals, and zone-safe event handling).


Configuring per-agent state

Two common pieces of per-agent setup happen on the element itself, not in mindset.init(). Both have dedicated guides, page tools and situational awareness, covering scenarios, best practices, and security in depth. The summaries below get you started.

Page tools

Page tools are functions on your page that the agent can call during a turn. You declare the name, description, and arguments; the agent decides when to call.

js
const agent = document.querySelector('mindset-agent');

agent.setPageTools([
  {
    name: 'lookup_order',
    description: 'Look up the current user\'s order by ID',
    parameters: {
      type: 'object',
      properties: { orderId: { type: 'string' } },
      required: ['orderId'],
    },
    handler: async ({ orderId }) => {
      const r = await fetch(`/api/orders/${orderId}`);
      return await r.json();
    },
  },
]);

Call setPageTools whenever your tool list changes. The element applies the new value on the agent's next turn.

Call element methods only after the element has fired mindset:agent-idle. See § When the element is ready to call.

Situational awareness

Situational awareness is structured context the agent reads on every turn. Use it for the things the agent should know about the current user or the current page that the user shouldn't have to repeat.

js
agent.setSituationalAwareness({
  currentPage: location.pathname,
  userPlan: currentUser.plan,
  cartItems: cart.length.toString(),
});

Update it whenever the page state changes. The agent sees the latest values on the next turn.


What's next


Common questions

Do I need a build step?

No. The SDK is a UMD bundle you load with a <script> tag. It works in any HTML page, with or without a JavaScript framework.

Do I need an npm package?

Not for the integration itself. We may publish a TypeScript type declaration package later for IDE autocomplete; the runtime stays as a hosted bundle.

Can I have multiple agents on one page?

Yes. Each <mindset-agent> element has its own runtime, state, and threads. Use different agent-uid values for each. See the <mindset-agent> reference for the current single-active-agent constraint.

What about TypeScript?

TypeScript declarations for the element and DOM events are on the roadmap. For now, type the events with CustomEvent<{ ... }> based on the events reference payload tables.

What about React?

Custom elements work in React out of the box. <mindset-agent> is a valid JSX tag. Use refs to access the element instance and useEffect for event subscription. See the Examples page (Headless: React tab).

What about Angular?

Angular needs CUSTOM_ELEMENTS_SCHEMA on the component so the template accepts <mindset-agent>. Subscribe to events with addEventListener rather than template binding, because the colon in mindset:* event names clashes with Angular's target:event syntax. See the Examples page (Headless: Angular tab).

Can I host the bundle myself?

The recommended path is the hosted URL. You always run the latest tested build, and we handle availability. Self-hosting is not currently supported.