# @meistrari/chat-nuxt

Nuxt module that adds a complete AI chat interface to your app. Server-side chat behavior is delegated to the dedicated Chat API; the Nuxt module owns the UI, auth bridge, and local proxy routes.

Consumer documentation lives in `docs/guides/` (indexed [below](#guides)); this README covers the package boundary and working on the package itself.

## Public Surface

`@meistrari/chat-nuxt` is an external package. Its supported consumer surface is intentionally small:

- Nuxt module registration through `@meistrari/chat-nuxt`.
- Module options under `chatNuxt`.
- Auto-registered `<MeistrariChatEmbed>`.
- Public component import from `@meistrari/chat-nuxt/components/MeistrariChatEmbed`.
- Public types from the package root and `@meistrari/chat-nuxt/types/*`.

Runtime internals under `src/runtime/**`, generated Nuxt aliases, and workspace-only schema package imports are implementation details unless they are explicitly exported above.

`typedoc.ts` at the package root is the documentation barrel for that surface — it is what the published API reference is generated from. Adding an export there makes it public; keep internals out of it.

## Guides

| Guide | Covers |
|-------|--------|
| [Installation and setup](docs/guides/installation.md) | Install, Vue dedupe override, module registration, module options, auth modes |
| [Embedding in your layout](docs/guides/embedding.md) | Layout, key props, conversation scoping, events, slots |
| [Chat runtime modes](docs/guides/tela-agent-mode.md) | Default chat mode vs Tela agent mode, agent inputs |
| [Citations](docs/guides/citations.md) | `cite://` chips, metadata popover, document panel |
| [Feature flags](docs/guides/feature-flags.md) | Usage tab, debug entry, cancel button, PostHog wiring |
| [Message feedback](docs/guides/message-feedback.md) | 👍/👎 controls and host-owned persistence |
| [Composer extension](docs/guides/composer-extension.md) | Host actions, shared attachment strip, outbound content and retry lifecycle, "/" commands |
| [Interactive message widgets](docs/guides/message-widgets.md) | Message context and programmatic send for `customComponents` widgets |
| [Workspace settings](docs/guides/workspace-settings.md) | Settings overrides, agent runtime ownership, `<ChatConfigurationModal>` |
| [Upgrading to 4.0](docs/guides/upgrading-to-4.md) | Required Chat API version for v2 sends, upgrade order, vue-i18n removal |

## Conversation forks

Completed assistant responses offer **Continuar em nova conversa** in the three-dot
menu below the response, beside the feedback controls. User messages cannot be forked.
The embed selects the new conversation and emits its existing `update:conversationId` event.
The new conversation stays idle until the user sends a message.
Fork titles use `<original title> - Cópia <number>` and remain intact when the first response completes.
New forks show a separator after the copied response with a link to the immediate source conversation.
Existing forks do not gain this separator.

This feature requires the matching Chat API fork endpoint described in
[Conversation forks](../chat-api/README.md#conversation-forks). History, tool data and file references
are copied; the new agent session receives the history as text, without cloning the original sandbox.

## API Reference

The JSDoc on each type is the source of truth, and the hosted reference is generated from it — Pantry builds it from [`typedoc.ts`](typedoc.ts), the barrel listing every public symbol, using its own pinned TypeDoc. Generated output is never committed here. The `postinstall` hook runs `nuxi prepare` so the Nuxt types `tsconfig.json` depends on exist before that build runs.

To render the reference locally:

```bash
bunx --bun typedoc --entryPoints typedoc.ts --out /tmp/chat-nuxt-api --skipErrorChecking
```

The table below is a quick index for reading in-repo. **When you change a prop, update its JSDoc and this row together.**

The embed automatically sets the browser tab title to the active conversation title and synchronizes its ID to `?conversationId=` using router replacement, preserving other query parameters and the URL fragment. Starting a new conversation removes the conversation parameter. Opening or reloading that URL restores the conversation; existing `?conversation=` links are also accepted and converted to `?conversationId=`. Explicit `conversationId` and `initialConversationId` props take precedence over the URL on mount. Without a conversation title, the host application controls the tab title.

### `<MeistrariChatEmbed>` props

Declared in `src/runtime/embed/types.ts`; prop, feature-flag, and event payload types are importable from the package root or `@meistrari/chat-nuxt/types/embed`.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `hideSidebar` | `boolean` | `false` | Hide the conversation list and render only the active chat surface |
| `sidebar` | `ChatSidebarConfig` | `undefined` | Sidebar layout: `{ position?, width?, bottomHeight?, collapsible?, defaultCollapsed? }`. `position` (`'left'`\|`'right'`, default `'left'`) picks the edge; `width` is the sidebar width in pixels (default `240`); `bottomHeight` is the `sidebar-bottom` pane height as a percentage 0–100 of the conversation area (default `50`); `collapsible` (default `false`) renders a native collapse handle and animates the sidebar open/closed; `defaultCollapsed` (default `false`) starts it collapsed |
| `hideSettings` | `boolean` | `false` | Hide workspace settings actions while keeping the chat header and content unchanged |
| `conversationId` | `string \| null` | `null` | Controlled conversation (supports `v-model:conversation-id`) |
| `initialConversationId` | `string \| null` | `null` | Conversation to open once on mount when `conversationId` is uncontrolled |
| `conversationScope` | `string \| null` | `null` | Isolate conversation history by technical scope within the current workspace and runtime. Scoped embeds only see same-scope conversations; values are trimmed, blank becomes `null`, and the server accepts 1-200 chars from `A-Z`, `a-z`, `0-9`, `.`, `_`, `:`, `/`, `-` |
| `defaultConversationCreatorFilter` | `'all' \| 'mine'` | `'all'` | Initial sidebar creator filter: every conversation in scope, or only the current user's |
| `availableModels` | `AvailableChatModels` | Full catalog | Non-empty ordered list of models this embed may display and execute. A missing or invalid restored selection falls back to the first entry; an empty list fails fast |
| `defaultModel` | `ChatModel` | Package default | Initial model for untouched drafts. Explicit selections and existing conversations take precedence; `availableModels` still limits the selection |
| `defaultReasoningEffort` | `ChatReasoningEffort` | Automatic (`null`) | Initial reasoning effort for untouched drafts. Explicit user choices (including automatic) take precedence |
| `conversationCreatorFilter` | `'all' \| 'mine'` | — | Controlled sidebar creator filter; use with `v-model:conversation-creator-filter` when the host changes it at runtime |
| `hideConversationCreatorFilter` | `boolean` | `false` | Hide the creator selector without changing the active filter |
| `telaAgentId` | `string` | — | Use Tela agent mode for this embed |
| `telaAgentBranch` | `string` | Published version | Repository branch to use for new agent sessions |
| `telaAgentInputs` | `TelaAgentExecutionInput[] \| null` | `undefined` | Inputs sent with each Tela agent run; hides the variables panel when non-null |
| `workspaceSettings` | `WorkspaceSettings \| null` | `null` | Override settings from host app; not accepted in Tela agent mode |
| `user` | `ChatActor \| null` | `null` | Override current user display info; not accepted in Tela agent mode |
| `features` | `Partial<ChatFeatureConfig>` | `{}` | Toggle `showUsageTab`, `showDebugOption`, `showCancelButton`, `showTtft`, and `chatOutboundQueue`; all released features default to `true` |
| `loadingMessages` | `readonly string[] \| null` | Default chat messages | Override pending-response messages |
| `loadingMessagesMode` | `'ordered' \| 'random' \| null` | `'ordered'` | Rotate custom messages in order or at random; only applies when `loadingMessages` has a non-empty message |
| `labels` | `Partial<ChatLabels>` | Portuguese defaults | Override conversation-search text; see [UI labels](docs/guides/embedding.md#ui-labels) for supported keys and surfaces |
| `customComponents` | `Record<string, Component>` | `undefined` | Custom markdown renderers keyed by markdown node or tag name. Components receive `node` plus the parser lifecycle props `loading` and `autoClosed` |
| `customHtmlTags` | `readonly string[]` | `undefined` | Extra HTML tags allowed by the markdown renderer |
| `citations` | `ChatCitationsConfig \| null` | `undefined` | Enables `cite://` citations in assistant and user messages (see [Citations](docs/guides/citations.md)) |
| `feedbackConfig` | `MessageFeedbackConfig \| null` | `undefined` | Enables 👍/👎 feedback on assistant messages; providing the prop (even `{}`) shows the controls |
| `messageFeedback` | `Record<string, MessageFeedbackRating> \| null` | `undefined` | Host-persisted votes keyed by message id; when provided, it is the single source of truth for the selected thumbs |

Events and slots are listed in [Embedding in your layout](docs/guides/embedding.md); `<ChatConfigurationModal>` props and events are in [Workspace settings](docs/guides/workspace-settings.md).

## What's Included

The module auto-registers everything — no manual imports needed:

- **Components**: full chat UI, message bubbles, tool widgets (code, search, files), markdown rendering, file previews
- **Composables**: `useChat`, `useConversations`, `useWorkspaceSettings`, `useFileUpload`, `useFeatureFlags`, and more
- **Server routes**: thin proxy routes that forward chat requests to the Chat API service

## Development

Run from this package:

```bash
pnpm build          # nuxt-module-build + embedded schema/declaration post-processing
pnpm dev:prepare    # stub build for local development
pnpm typecheck      # builds the module, prepares chat-app, typechecks the host app
pnpm test:types     # build + tsc against the consumer type tests
pnpm smoke:pack     # pack the module and install it into a scratch consumer
pnpm smoke:browser  # packed-consumer smoke test with a real browser
pnpm lint           # eslint
pnpm lint:attrs     # guards against stray `!` attribute typos in runtime templates
```

Unit tests run from the workspace root (`pnpm test`), which prepares this package before invoking vitest.

Package versions are assigned by release automation from conventional commits; do not edit the version manually.

## Package Dependencies

Installing `@meistrari/chat-nuxt` installs the runtime packages used by the layer. The host Nuxt app still owns the Nuxt and Vue versions.

| Package | Version | Purpose |
|---------|---------|---------|
| `@meistrari/auth-nuxt` | `3.31.0` | Authentication (required) |
| `@meistrari/logger` | `^2.1.3` | Structured logging for the server proxy routes |
| `@meistrari/tela-build` | `^1.70.2` | UI component library (Nuxt layer), with no global i18n requirement |
| `@sentry/nuxt` | `^10.0.0` | Client-side error capture used by chat composables |
| `@iconify/vue` + `@iconify-json/ph` | `^5.0.0` / `^1.2.2` | Icon rendering support (Phosphor set) |
| `@vueuse/core` | `^12.8.0` | Runtime composables used by chat UI |
| `@vueuse/components` | `^12.8.0` | VueUse component peer expected by the shared runtime |
| `mermaid` | `^11.13.0` | Native markstream Mermaid diagram rendering |
| `h3` | `^1.15.0` | Server route utilities provided by Nuxt/Nitro |
| `markstream-vue` | `2.0.7` | Markdown streaming renderer |
| `motion` | `^11.13.0` | Animation component runtime |
| `nitropack` | `^2.10.0` | Runtime config and task utilities provided by Nuxt/Nitro |
| `pdfjs-dist` | `^5.4.530` | PDF file previews |
| `posthog-js` | `^1.364.2` | Optional PostHog feature-flag helper |
| `stream-diffs` | `0.0.2` | Native markstream rich code and diff rendering |
| `virtua` | `^0.42.0` | Virtualized list runtime expected by shared UI |
| `xlsx` | `^0.18.5` | Spreadsheet file previews |
| `zod` | `^4.1.13` | Schema validation for API payloads |

The chat package does not declare or expect the host application to configure an i18n plugin. Hosts can override the supported conversation-search text through `labels`, using plain strings or their own translator. This is not a full-chat localization API; other UI text retains its existing defaults.

Peer dependencies:

| Package | Version | Purpose |
|---------|---------|---------|
| `nuxt` | `^3.17.0 \|\| ^4.0.0` | Host framework |
| `vue` | `^3.5.0` | Host Vue runtime |
