<!-- Source: https://docs.squirro.com/en/latest/technical/neo/dev-guide/chat-widget.html -->
# The Chat Widget

> **Warning**
>
> Project Neo is currently in [Technical Preview](../../../a-z/squirro-glossary.md#term-Technical-Preview). Features described in this section may change before general availability.

Your bundle can embed the same conversational GenAI experience the core Squirro application ships: a full chat panel that streams answers with citations, footnotes, thinking steps, and interrupt handling, backed by the GenAI service of the project. This page covers embedding the widget, the data source and its authentication prerequisite, and how to theme, localize, and gate it.

The widget is exported from `@squirro/neo-core/chat`. The bundle scaffold also installs a `squirro-chat` skill under `.claude/skills/` with the full API reference and patterns, which is a useful companion when building with Claude Code.

## What It Is

Two components work together:

- **ChatProvider**

  Owns one instance-scoped bundle of chat state: the conversation, streaming, agents, and interrupts. Everything a chat surface needs is read from it.
- **ChatPanel**

  The embeddable widget itself, made up of the conversation thread and the composer. It reads its state from the surrounding provider, so you can drop it in without passing props.

> **Note**
>
> One `ChatProvider` corresponds to one conversation. Two `ChatPanel` components under the same provider share a single conversation. To run two independent chats on a page, mount two providers.

The panel deliberately does not include a conversation-list sidebar or any URL syncing. Those belong to the surface that mounts the provider.

## The Data Source and Authentication

The chat widget talks to `/service/genai` through a data source built with `createChatDataSource()`. Authentication works the same way as for the rest of the Squirro API, described on the [Squirro API](squirro-api.md#neo-extensions-api) page:

- **During local development**

  The dev proxy injects a valid access token into every request.
- **In production**

  The Squirro backend authenticates the request via session cookies on the same origin.

Called with no arguments, `createChatDataSource()` reuses the authentication and project-scoping bindings registered by the host, which are the same ones `useSquirroApi()` uses. No manual token handling is required, and the same code path works in both environments.

## Embedding the Widget

`ChatProvider` needs a `dataSource`, project-scoped `queryKeys`, and a `getProjectId` accessor. A standalone bundle panel owns neither a conversation-list sidebar nor a host rejoin service, so the `cacheUtils` and `observers` props default to built-in no-ops and you do not pass them at all.

```jsx
import {
  ChatPanel,
  ChatProvider,
  createChatDataSource,
  createGenaiQueryKeys,
} from '@squirro/neo-core/chat';
import { useSquirroApi } from '@squirro/neo-core/api';
import { useCallback, useMemo } from 'react';

export default function ChatDashboard() {
  const api = useSquirroApi();
  const getProjectId = useCallback(() => api.projectId, [api]);
  const dataSource = useMemo(() => createChatDataSource(), []);
  const queryKeys = useMemo(() => createGenaiQueryKeys(getProjectId), [getProjectId]);

  return (
    <ChatProvider
      dataSource={dataSource}
      queryKeys={queryKeys}
      getProjectId={getProjectId}
    >
      <div className="h-full min-h-0">
        <ChatPanel welcomeContent={<p className="text-muted-foreground">Ask a question to start.</p>} />
      </div>
    </ChatProvider>
  );
}
```

Four points are worth calling out:

- **Memoize the data source and query keys**

  `ChatProvider` rebuilds its store bundle when the identity of those props changes, so keep the references stable.
- **Size the container**

  Give the panel a sized container with `min-h-0` so its internal scroll area lays out correctly inside a flex dashboard card.
- **Query client**

  Dashboards render inside the React Query provider of the host, so the GenAI hooks resolve their client automatically. You do not need to supply one.
- **No sidebar wiring**

  `cacheUtils` and `observers` are optional and default to no-ops. Supply them only if you build your own conversation-list sidebar or rejoin service.

## Theming, Strings, and Capabilities

The widget uses the same theme tokens and typography as the rest of the application, so it picks up the active theme with no extra work. For more information, see the [Styling and Components](styling-and-components.md#neo-extensions-styling) page.

Four optional `ChatProvider` props tailor the rest:

| Prop | Type | Purpose |
| --- | --- | --- |
| `strings` | `Partial<ChatStrings>` | Overrides user-facing text. Only the keys you pass change. The rest fall back to the English `defaultChatStrings`. Wire this to your bundle translations, described on the [Translations](translations.md#neo-extensions-translations) page. |
| `locale` | `string` | BCP-47 tag, for example `de`, used for dates interpolated into those strings. Without it, a date follows the browser locale rather than the language of your interface. Omit the prop to keep the browser locale. |
| `capabilities` | `ChatCapabilities` | Feature gates. `inlineActions` turns on the selection actions offered on answer text, such as Explain and Translate. Flags you omit stay off. Turning `inlineActions` on requires the `onExecuteSelectionStream` callback. |
| `callbacks` | `ChatCallbacks` | Host hooks: `onNavigateToItem`, `onNotify`, `onOpenSidePanel`, `onSubmitFeedback`, and `onExecuteSelectionStream`. |

For example, to localize a label and route document clicks into your own detail view:

```jsx
<ChatProvider
  dataSource={dataSource}
  queryKeys={queryKeys}
  getProjectId={getProjectId}
  strings={{ codeBlockCopy: 'Copy code' }}
  callbacks={{
    onNotify: (kind, message) => toast[kind](message),
    onNavigateToItem: (itemId) => openItemDetail(itemId),
  }}
>
  <ChatPanel />
</ChatProvider>
```

> **Note**
>
> Closing a side panel is a separate top-level prop, `onCloseSidePanel`, and is not part of `callbacks`.

## Next Steps

| Topic | Guide |
| --- | --- |
| Wiring the panel into a dashboard entry | [The Bundle Manifest](manifest.md#neo-extensions-manifest) |
| Calling the Squirro API and how authentication is wired | [Squirro API](squirro-api.md#neo-extensions-api) |
| UI components, icons, and theme tokens | [Styling and Components](styling-and-components.md#neo-extensions-styling) |
| Overriding text per language | [Translations](translations.md#neo-extensions-translations) |
| Live preview and prop table for the panel | [neo-catalog.squirro.com](https://neo-catalog.squirro.com) |
| Full chat API reference | The `squirro-chat` skill under `.claude/skills/` in your bundle |
