Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mindset.ai/llms.txt

Use this file to discover all available pages before exploring further.

The <mindset-agent> element exposes methods you call directly on the DOM node. They fall into three groups:
  • State setters and readers: sync, safe to call once the SDK script has loaded and mindset.init() has completed.
  • Turn-driving: sync, throws if the agent is busy.
  • Thread CRUD: async, throws if the element isn’t initialized.
Get the element with document.querySelector('mindset-agent') (or React refs, or any other DOM lookup) and call methods on it directly:
const agent = document.querySelector('mindset-agent');
agent.setPageTools([{ name: 'lookup', /* ... */ }]);
agent.sendMessage('hello');

State setters and readers

These methods are synchronous. Call them once the SDK is ready, see § When the element is ready to call below. Last write wins per slot.

agent.setPageTools(tools)

Register page tools for this agent. Page tools are functions on the host page that the agent can call during a turn. The agent sees the tool’s name, description, and argument schema; you handle the call and return a result. See the page tools guide for the full feature walkthrough, scenarios, and security notes. Signature:
agent.setPageTools(tools: PageToolDefinition[]): void
Behavior:
  • Replaces the entire page-tools list for this agent. Pass an empty array to clear.
  • Last write wins: calling it twice keeps only the second list.
agent.setPageTools([
  {
    name: 'lookup_order',
    description: 'Look up an order by ID',
    parameters: { /* JSON Schema */ },
    handler: async ({ orderId }) => fetchOrder(orderId),
  },
]);

agent.setSituationalAwareness(sa)

Pass structured context about the current page or user state to the agent. The agent reads this on every turn so it can personalize responses without the user having to repeat themselves. See the situational awareness guide for the full feature walkthrough, scenarios, and best practices. Signature:
agent.setSituationalAwareness(sa: Record<string, string>): void
Behavior:
  • Replaces the situational awareness object for this agent.
  • Default character limit: 10,000. Lift to 20,000 with extendedSituationalAwareness: true in mindset.init().
agent.setSituationalAwareness({
  currentPage: '/products/widget-pro',
  userPlan: 'enterprise',
  cartItems: '3',
});

agent.setPassthroughParams(params)

Pass parameters that the agent forwards to its tool calls. Useful for injecting tenant IDs, authorization tokens, or routing hints that tools need but the agent shouldn’t see in its prompt. See the pass-through parameters guide for the full feature walkthrough including targeted vs wildcard keys and the platform-managed parameters story. Signature:
agent.setPassthroughParams(params: Record<string, string>): void
Behavior:
  • Replaces the passthrough params object.
  • Available as a tool-call argument; not surfaced to the LLM.
agent.setPassthroughParams({
  tenantId: 'acme-corp',
  region: 'us-east-1',
});

agent.isAgentBusy()

Check whether the agent is processing a turn. Returns false if the element isn’t bound yet. Signature:
agent.isAgentBusy(): boolean
if (!agent.isAgentBusy()) {
  agent.sendMessage('hello');
}
You can also track busy state via mindset:agent-busy and mindset:agent-idle events.

Turn-driving

agent.sendMessage(text, options?)

Send a user message and start a turn. Sync, returns void. The turn runs asynchronously, listen for mindset:complete (or the streaming events) to see the response. Signature:
agent.sendMessage(
  text: string,
  options?: { silent?: boolean }
): void
Behavior:
  • Throws if the agent is currently busy. Wait for mindset:agent-idle first, or check agent.isAgentBusy().
Options:
OptionTypeDescription
silentbooleanWhen true, the user-side message bubble is hidden from the chat UI. The agent processes the message identically (same DOM events, same situational awareness, same response), but the user side of the turn is invisible. Default: false.
// Normal turn
agent.sendMessage('What's my order status?');

// Silent: programmatic priming, host-page context injection, widget action follow-ups
agent.sendMessage('the user just opened the cart panel', { silent: true });
Silent mode is useful for:
  • Programmatic priming. Inject an instruction so the agent responds as if a precondition occurred, without polluting the chat with the instruction.
  • Background context injection. Let the host page steer the agent without user-visible noise.
  • Widget action follow-ups. When a non-text user action should drive the agent without showing a synthetic “user said X” bubble.
The agent’s response is still shown in chat. Silent suppresses only the user side of the turn. If you need the entire interaction invisible, that’s a separate concern (open a support ticket).

Waiting for the agent to be ready

sendMessage throws if the agent is currently busy. Calling it on first load is the most common place this trips people up: if the agent is configured with an icebreaker (a turn that fires automatically when the agent starts), the lifecycle looks like this:
mindset:agent-initializing
mindset:agent-idle             ← init done (but icebreaker is about to fire)
mindset:agent-busy             ← icebreaker turn starts
mindset:text-delta...
mindset:complete
mindset:agent-idle             ← icebreaker done, NOW you can send
If you wait for the first mindset:agent-idle and immediately call sendMessage, your call lands while the icebreaker is in flight and throws. The recommended pattern handles both cases (icebreaker or no icebreaker) without you needing to know which:
function sendWhenIdle(agent, text) {
  if (!agent.isAgentBusy()) {
    agent.sendMessage(text);
  } else {
    agent.addEventListener('mindset:agent-idle', () => sendWhenIdle(agent, text), { once: true });
  }
}

sendWhenIdle(agent, 'hello');
What this does:
  • If the agent is idle right now, send straight away.
  • If the agent is busy (could be the icebreaker still running, could be a previous turn finishing), wait for the next mindset:agent-idle and recurse. The recursion re-checks busy state, so it’s safe across any sequence of idle/busy flips.
Use the same pattern whenever you don’t know whether the agent is currently free, for instance, when triggering a message from a host-page event handler. For sends that strictly follow your own previous turn (you sent, you got mindset:complete, now you send again), the agent is guaranteed to be idle and a plain agent.sendMessage(text) is fine.
Programmatic resume after mindset:interrupt is on the roadmap. There’s no agent.resume() method on the element today. When the agent pauses on a UI-interrupt tool, render UI based on the event detail and drive the next turn with agent.sendMessage().
Vote and widget-action methods are on the roadmap. Submitting feedback on a message or driving a tool widget’s actions programmatically is not yet exposed on the element. Use the built-in chat UI for these flows for now, or open a request describing your use case.

Thread CRUD

These methods are async because they hit the network. They throw if the element isn’t bound to a runtime yet. The host needs to wait for the agent to initialize before calling them. Use the mindset:agent-idle event as your signal.
Thread uids are exposed only after the user engages. A freshly-created thread doesn’t have a customer-visible uid until a user-message turn completes and the thread persists server-side. This means agent.newThread() doesn’t return a uid, and agent.threadUid returns null until the user sends a message. See Thread-uid persistence semantics below.

agent.newThread()

Start a new thread. The agent’s local state resets and a fresh thread is created. Customers don’t get a uid back from this call. The new thread isn’t persisted server-side until the user sends a message. Listen for mindset:thread-changed to know when the persisted uid is available. Signature:
agent.newThread(): Promise<void>
await agent.newThread();
// agent.threadUid is null at this point.
// Listen for mindset:thread-changed to know when the persisted uid arrives.

agent.switchThread(threadUid)

Switch to an existing persisted thread. The uid must come from agent.listThreads() or a prior mindset:thread-changed event. These are the only sources of uids that are guaranteed to be switchable. Signature:
agent.switchThread(threadUid: string): Promise<void>
Behavior:
  • Throws <mindset-agent>.switchThread: thread "<uid>" not found. Only persisted threads (returned by agent.listThreads() or surfaced via mindset:thread-changed events) are switchable. if the uid is not in the persisted thread list.
  • Resolves cleanly if the switch succeeds. mindset:thread-changed fires once with { threadUid: <target>, previous: <prior> }.
await agent.switchThread('thread-abc123');

agent.deleteThread(threadUid)

Delete a thread. If you delete the active thread, a new one is created automatically and mindset:thread-changed fires. Signature:
agent.deleteThread(threadUid: string): Promise<boolean>
Returns true on success, false if the thread couldn’t be deleted.

agent.renameThread(threadUid, title)

Rename a thread. Useful when you let users name their threads manually. Signature:
agent.renameThread(threadUid: string, title: string): Promise<boolean>
Returns true on success.

agent.listThreads(options?)

List the user’s threads, oldest-first by default. Pass a pageToken from a previous response to continue paging. Signature:
agent.listThreads(options?: {
  pageSize?: number;
  pageToken?: string;
}): Promise<ListThreadsResponse>
Returns Promise<ListThreadsResponse>:
FieldTypeDescription
threadsThreadSummary[]The page of threads, ordered by updatedAt descending.
nextPageTokenstring | nullPass to the next call to continue paging. null when there are no more pages.
hasMorebooleantrue if more pages exist. Use this as your loop condition.
Each ThreadSummary:
FieldTypeDescription
uidstringThe thread’s UID.
titlestringThread title. Generated by the agent on the first turn (see mindset:thread-title); can be overwritten with agent.renameThread().
createdAtstringISO 8601 timestamp.
updatedAtstringISO 8601 timestamp.
messageCountnumberNumber of messages in the thread.
const { threads, nextPageToken, hasMore } = await agent.listThreads({ pageSize: 20 });
threads.forEach(t => renderThreadInList(t));

// Iterate to load all pages
let pageToken;
do {
  const page = await agent.listThreads({ pageSize: 50, pageToken });
  page.threads.forEach(t => allThreads.push(t));
  pageToken = page.nextPageToken;
} while (pageToken && page.hasMore);

Properties

agent.threadUid

A sync getter that reads the active thread’s UID, but only when the thread is persisted server-side. Returns null while the thread is local-only (just created via newThread(), no completed user-message turn yet) or while the element isn’t bound to a runtime yet. Type: string | null
const current = agent.threadUid;
if (current) {
  syncToUrl(current);
}
This is the same value mindset:thread-changed reports in event.detail.threadUid. Use the property when you need the current value on demand; use the event when you want to react to changes. See Thread-uid persistence semantics for the full transition matrix.

Thread-uid persistence semantics

agent.threadUid and mindset:thread-changed only surface a uid once the thread is persisted server-side. This deliberately matches the chat-UI thread list, which only displays threads the user has engaged with, so the headless API never exposes a uid that wouldn’t also appear in the UI list, can’t be loaded later, or can’t be passed back to agent.switchThread().
Customer actionagent.threadUidmindset:thread-changed
SDK boots, agent has no icebreakernull (current thread is local-only)Not fired
SDK boots, agent fires icebreakernull (icebreaker turn alone doesn’t persist the thread, only a user message does)Not fired
agent.newThread() returnsnullNot fired
agent.sendMessage('hi'), turn completes and the thread persists shortly afterThe new uidFires with { threadUid: <new uid>, previous: null }
agent.newThread() again, then sendMessage again, persistsThe newest uidFires twice: { null, previous: <old uid> } when newThread resets, then { <new uid>, null } when persists
Page boots with <mindset-agent thread-uid="<existing>"><existing uid> immediatelyFires with { <existing uid>, null } once the thread loads
Why this shape: three reasons converge.
  1. Matches the chat-UI thread list semantics. The chat UI only shows threads the user has engaged with. The headless API uses the same gate so the customer never gets a uid that isn’t visible, listable, or switchable.
  2. switchThread(uid) only works for persisted threads. Uids the customer received via mindset:thread-changed or listThreads() are always switchable. Stale or invented uids throw immediately.
  3. No silent failures. switchThread throws on a uid that isn’t in the persisted thread list, surfacing the problem at the call site rather than disappearing.
Practical implication for UIs: a “New thread” button should call agent.newThread() and clear your message list, but not try to read the new uid until either:
  • The next mindset:thread-changed event fires (after the user sends a message), or
  • You call agent.listThreads() again later to pick up the persisted entry.

When the element is ready to call

Element methods must be called after both of the following:
  1. The SDK script has loaded, i.e. the <mindset-agent> custom element is defined.
  2. mindset.init() has completed, i.e. the runtime is bound to the element.
The first mindset:agent-idle event is the signal that both have happened. Listen for it once before driving the agent:
<script src="MINDSET-SERVER-URL/mindset-sdk3.umd.js"></script>
<mindset-agent agent-uid="your-agent-uid"></mindset-agent>
<script>
  await window.mindset.init({ appUid, fetchAuthentication });

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

  agent.addEventListener('mindset:agent-idle', () => {
    agent.setPageTools([/* ... */]);
    agent.setSituationalAwareness({ currentPage: location.pathname });
    agent.sendMessage('Hello');
  }, { once: true });
</script>
mindset:agent-idle also fires after every turn ends, so you can keep listening for it to drive subsequent turns reactively. For one-shot setup like the above, use { once: true }. If you load the SDK script asynchronously (document.createElement('script'), framework dynamic imports, Webpack code-splitting), wait for the script to load before reading the element off the DOM and calling methods on it. For sendMessage specifically, see § Waiting for the agent to be ready. sendMessage throws if the agent is currently busy (e.g. the icebreaker turn is in flight), and the sendWhenIdle helper handles that case automatically.

Errors

MethodThrows whenWhat to do
agent.sendMessageAgent is currently busyWait for mindset:agent-idle, or check agent.isAgentBusy() first
agent.newThread, switchThread, deleteThread, renameThread, listThreadsElement isn’t bound to a runtime yetWait for mindset:agent-idle to fire once before calling thread CRUD
agent.switchThread(uid)uid isn’t in the persisted thread listOnly pass uids you got from agent.listThreads() or a prior mindset:thread-changed event
State setters never throw on init order or busy state.

Method-to-event reference

When a method drives the agent or changes its state, the corresponding events fire as follows:
MethodEvents
agent.sendMessage(text)mindset:agent-busymindset:text-delta (repeated) → mindset:completemindset:agent-idle. The first sendMessage after newThread() also triggers mindset:thread-changed shortly after mindset:complete, once the new thread persists.
agent.newThread()None directly. The new thread isn’t persisted yet, so mindset:thread-changed doesn’t fire until the user sends a message.
agent.switchThread(uid)mindset:thread-changed
agent.deleteThread(uid)mindset:thread-changed (if the active thread was deleted)
agent.setPageTools(...), setSituationalAwareness(...), setPassthroughParams(...)None. These are silent state updates.
See the DOM events reference for full event payload shapes and the order they fire in.