npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@synerise/ai-assistant-core

v1.15.0

Published

Core component and API helpers for embedding the Synerise AI Assistant in Preact applications.

Readme

@synerise/ai-assistant-core

Core component and API helpers for embedding the Synerise AI Assistant in Preact applications.


Requirements

This package is designed for the Synerise platform. To use it you need:

  • An active Synerise tenant and a tracker key
  • Network access to https://api.synerise.com (or your custom Synerise API endpoint)
  • Preact 10 in your application

If you don't have a Synerise account, visit synerise.com.


Which package do I need?

| Your stack | Package | | --- | --- | | Vanilla JS / no bundler / <script> tag | @synerise/ai-assistant-sdk | | React 18 | @synerise/ai-assistant-react | | Preact | @synerise/ai-assistant-core (this package) | | Build a custom chat UI from primitives | @synerise/ai-assistant-ui |

How packages relate

@synerise/ai-assistant-core  ──>  @synerise/ai-assistant-ui

core provides the high-level AIAssistant component with chat lifecycle, API integration, error handling, streaming, etc. ui provides only visual primitives.


Installation

npm install @synerise/ai-assistant-core preact
# or
pnpm add @synerise/ai-assistant-core preact
# or
yarn add @synerise/ai-assistant-core preact

Peer dependencies

  • preact ^10.26.9

What this package provides

  • AIAssistant — Preact component with built-in chat lifecycle handling, exposing an imperative ref (AIAssistantRef) for thread loading
  • assistantApi — direct API helpers (initChat, sendChatMessage, getChatMessages, getConversations)
  • Constants — message types, chat states, error types, operation types
  • Errors — typed ApiError and NetworkError classes
  • Re-exports from @synerise/ai-assistant-ui — BaseChat, Icon, action/message constants, theme types

Quick start

import { AIAssistant } from "@synerise/ai-assistant-core";

export function SupportChat() {
  return (
    <AIAssistant
      apiUrl="https://api.synerise.com/agents/v1/ai-assistant"
      context={{ profileId: "user-123" }}
      additionalContextValues={{ segment: "premium" }}
      displayMode="bordered"
      onPromptSuccess={(response) => {
        console.log("threadId:", response.meta.threadId);
      }}
      onCustomAction={({ actionName, params }) => {
        console.log("custom action:", actionName, params);
      }}
    />
  );
}

Important props

| Prop | Type | Description | | --- | --- | --- | | apiUrl | string | Base assistant API URL | | context | Context \| null | Per-request context object. Optional — pass null or omit when unused. | | additionalContextValues | AdditionalContextValues \| null | Per-request metadata. Optional — pass null or omit when unused. | | displayMode | "drawer" \| "bordered" | UI layout | | onPromptSuccess | (response) => void | Required. Called after init/message response | | onCustomAction | ({ actionName, params }) => void | Called when the assistant emits a custom action | | onConversationTitle | ({ threadId, title }) => void | Called when the backend emits the conversation's auto-generated title (conversation_title SSE event, stream mode only) | | onStreamError | ({ message, type, stage }) => void | Called when the backend refuses a streamed exchange (error SSE event, stream mode only) — see Refused responses | | threadId | string | If provided, loads an existing conversation | | stream | boolean | Enables SSE mode (text/event-stream) | | fastMode | boolean | Appends fastMode=true query param | | assistantId | string | Optional assistant configuration ID (UUID). Sent as assistantId query param; falls back to backend default when omitted. | | authParams | { code, clientUUID } | Auth payload (alternative to XSRF cookie auth) | | disableXSRFToken | boolean | Skip XSRF token header in fetch calls |


Imperative API — AIAssistantRef

AIAssistant is a forwardRef component. Attaching a ref gives you a small imperative surface for interacting with the running chat from outside the component tree — useful for "history" pickers, "resume conversation" affordances, deep-link handlers, etc.

import { useRef } from "preact/compat";
import { AIAssistant, type AIAssistantRef } from "@synerise/ai-assistant-core";

function SupportChat() {
  const chatRef = useRef<AIAssistantRef>(null);

  return (
    <>
      <button
        onClick={async () => {
          const conversations = await chatRef.current?.getConversations();
          // …render a list, then on click:
          // await chatRef.current?.loadThread(conv.threadId);
        }}
      >
        History
      </button>

      <AIAssistant
        ref={chatRef}
        apiUrl="https://api.synerise.com/gen-ai/v3/ai-assistant"
        displayMode="bordered"
        onPromptSuccess={(response) => console.log(response.meta.threadId)}
      />
    </>
  );
}

| Method | Returns | Description | | ---------------------- | ------------------------------------ | -------------------------------------------------------------------------------------------------------- | | loadThread(threadId) | Promise<void> | Replace the active conversation with the messages of an existing thread. 404 → THREAD_NOT_FOUND state. | | getConversations() | Promise<AIAssistantConversation[]> | List the current user's historical threads. |

Pass threadId as a prop to mount the component with an existing thread already loaded instead of calling loadThread after mount.


Conversation flow

   ┌──────────┐  initChat()    ┌─────────────┐
   │  init    ├───────────────>│  threadId   │
   └──────────┘                └──────┬──────┘
                                      │
   ┌──────────┐  sendChatMessage()    │
   │  user    ├───────────────────────┤
   │  message │                       │
   └──────────┘                       │
                                      v
                            ┌─────────────────┐
                            │  assistant      │
                            │  response       │
                            │  (POST or SSE)  │
                            └─────────┬───────┘
                                      v
                          onPromptSuccess(response)

AIAssistant orchestrates the entire flow internally. Use assistantApi directly only if you need custom UX (e.g. headless integration).


Direct API usage

import { assistantApi } from "@synerise/ai-assistant-core";

const initResponse = await assistantApi.initChat({
  apiUrl: "https://api.synerise.com/agents/v1/ai-assistant",
  context: { profileId: "user-123" },
  additionalContextValues: { segment: "premium" },
  message: null,
});

const threadId = initResponse?.meta.threadId;

if (threadId) {
  const response = await assistantApi.sendChatMessage({
    apiUrl: "https://api.synerise.com/agents/v1/ai-assistant",
    threadId,
    message: "Show me products for trail running",
    context: { profileId: "user-123" },
    additionalContextValues: { segment: "premium" },
  });

  console.log(response.data.messages);
}

Listing historical conversations

import { assistantApi, type AIAssistantConversation } from "@synerise/ai-assistant-core";

const conversations: AIAssistantConversation[] = await assistantApi.getConversations({
  apiUrl: "https://api.synerise.com/gen-ai/v3/ai-assistant",
});

// Each entry: { threadId, agentType, realm, businessProfileId, createdAt, summary?, … }

To then load a specific thread's messages, use either assistantApi.getChatMessages({ apiUrl, threadId }) (headless) or ref.loadThread(threadId) on a mounted <AIAssistant> (component).


Error handling

import { ApiError, NetworkError, AI_ASSISTANT_ERROR_TYPE } from "@synerise/ai-assistant-core";

try {
  await assistantApi.initChat({ /* ... */ });
} catch (error) {
  if (error instanceof ApiError) {
    console.error("API error:", error.body.errorCode, error.body.message);
    console.error("trace id:", error.body.traceId);
  } else if (error instanceof NetworkError) {
    console.error("Network error — check connectivity");
  }
}

AI_ASSISTANT_ERROR_TYPE enumerates the error types surfaced by the chat component callbacks.

Refused responses (guardrails)

In stream mode the backend can refuse an exchange with an error SSE event emitted instead of the response (no message event follows, only [DONE]):

event: error
data: {"message":"Nie mogę pomóc w tej sprawie. Czy mogę pomóc w czymś innym?","type":"validation_failed","stage":"input"}
  • With message — the copy is user-facing and already prepared by the backend, so it is appended as the assistant's reply (the way guardrails behaved when they arrived as ordinary messages). No error state, chat stays usable, onError does not fire, and the turn is reported through onPromptSuccess like any other response. A prompt refused at stage: "input" was never echoed by the backend, so the human bubble is re-added client-side — that turn is not part of the server-side history.
    • The exception is an init refused this way: the refusal replaces the response, so no threadId was ever received and nothing can be sent afterwards. The copy is still shown, but the chat ends in the error state below it (errorType: "STREAM_ERROR") so the user can retry — and because that turn ends as an error rather than a response, onPromptSuccess does not fire for it (onError does).
  • Without message — raised as a StreamError, which unwinds into the regular error path: errorType: "STREAM_ERROR", error state with "try again", onError fires. Customise the copy via texts.errorMessage.STREAM_ERROR. The prompt is kept in the transcript, so the error is shown under the question it belongs to.

onStreamError receives the raw payload in both cases; a callback that throws is contained, so the refusal still reaches the user.


Exports

  • AIAssistant, AIAssistantRef (imperative handle exposing loadThread, getConversations)
  • assistantApi (initChat, sendChatMessage, getChatMessages, getConversations)
  • BaseChat, Icon (re-exported from @synerise/ai-assistant-ui)
  • AI_ASSISTANT_MESSAGE_ELEMENT_TYPE, AI_ASSISTANT_MESSAGE_TYPE, AI_ASSISTANT_ERROR_TYPE (includes THREAD_NOT_FOUND, STREAM_ERROR), AI_ASSISTANT_OPERATION (includes LOAD_THREAD), CHAT_STATE, CHAT_ACTION_TYPE, CHAT_MESSAGE_TYPE
  • ApiError, NetworkError, StreamError
  • TypeScript types from AIAssistant.types (including AIAssistantConversation)
  • Storefront page context (PDP) primitives — StorefrontPageContext, detectPageContextFromMeta(), observePageContext({ onChange }). Pass detected values to <AIAssistant> under additionalContextValues.page_context (snake_case outer key required by the backend; inner object stays camelCase). See the SDK or React package README for end-to-end usage.

Troubleshooting

  • document is not defined — this package is browser-only (uses cookies, fetch, DOM). Render only on the client in SSR frameworks.
  • 401 / 403 from API — verify your tracker key, that apiUrl matches your tenant, and that disableXSRFToken matches your tenant's auth flow.
  • CORS errors — your tenant must allow your origin. Contact Synerise support.
  • Using from React — install @synerise/ai-assistant-react instead, which provides a typed React wrapper.

Support

For technical and licensing inquiries: [email protected].

License

Proprietary. See LICENSE.