@meistrari/chat-nuxt 3.9.2 → 3.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +50 -440
  2. package/dist/module.d.mts +1 -1
  3. package/dist/module.json +1 -1
  4. package/dist/runtime/assets/css/markstream.css +1 -1
  5. package/dist/runtime/conversations/components/chat-conversation-creator-filter.vue +11 -67
  6. package/dist/runtime/conversations/components/chat-conversation-item.d.vue.ts +2 -1
  7. package/dist/runtime/conversations/components/chat-conversation-item.vue +29 -33
  8. package/dist/runtime/conversations/components/chat-conversation-item.vue.d.ts +2 -1
  9. package/dist/runtime/conversations/components/chat-conversation-list.d.vue.ts +0 -1
  10. package/dist/runtime/conversations/components/chat-conversation-list.vue +117 -158
  11. package/dist/runtime/conversations/components/chat-conversation-list.vue.d.ts +0 -1
  12. package/dist/runtime/conversations/components/chat-conversation-new-group-button.vue +34 -73
  13. package/dist/runtime/conversations/components/chat-conversation-search.vue +1 -21
  14. package/dist/runtime/conversations/components/chat-widget-history-list.d.vue.ts +12 -0
  15. package/dist/runtime/conversations/components/chat-widget-history-list.vue +27 -0
  16. package/dist/runtime/conversations/components/chat-widget-history-list.vue.d.ts +12 -0
  17. package/dist/runtime/conversations/composables/conversation-groups.d.ts +1 -0
  18. package/dist/runtime/conversations/composables/conversation-groups.js +2 -0
  19. package/dist/runtime/conversations/composables/conversation-item.js +4 -4
  20. package/dist/runtime/conversations/composables/conversation-list.js +14 -5
  21. package/dist/runtime/embed/components/chat-configuration-modal.d.vue.ts +3 -3
  22. package/dist/runtime/embed/components/chat-configuration-modal.vue.d.ts +3 -3
  23. package/dist/runtime/embed/components/chat-embed-inner.d.vue.ts +6 -3
  24. package/dist/runtime/embed/components/chat-embed-inner.vue +365 -152
  25. package/dist/runtime/embed/components/chat-embed-inner.vue.d.ts +6 -3
  26. package/dist/runtime/embed/components/chat-embed.d.vue.ts +31 -4
  27. package/dist/runtime/embed/components/chat-embed.vue +10 -4
  28. package/dist/runtime/embed/components/chat-embed.vue.d.ts +31 -4
  29. package/dist/runtime/embed/components/chat-topbar.vue +83 -85
  30. package/dist/runtime/embed/components/meistrari-chat-embed.d.vue.ts +5 -3
  31. package/dist/runtime/embed/components/meistrari-chat-embed.vue +118 -57
  32. package/dist/runtime/embed/components/meistrari-chat-embed.vue.d.ts +5 -3
  33. package/dist/runtime/embed/components/mobile/chat-mobile-drawer.d.vue.ts +0 -1
  34. package/dist/runtime/embed/components/mobile/chat-mobile-drawer.vue +2 -45
  35. package/dist/runtime/embed/components/mobile/chat-mobile-drawer.vue.d.ts +0 -1
  36. package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.d.vue.ts +9 -5
  37. package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.vue +14 -25
  38. package/dist/runtime/embed/components/mobile/chat-mobile-home-suggestions.vue.d.ts +9 -5
  39. package/dist/runtime/embed/components/mobile/chat-mobile-shell.d.vue.ts +4 -4
  40. package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue +2 -3
  41. package/dist/runtime/embed/components/mobile/chat-mobile-shell.vue.d.ts +4 -4
  42. package/dist/runtime/embed/feature-config.d.ts +7 -0
  43. package/dist/runtime/embed/types.d.ts +47 -8
  44. package/dist/runtime/files/icons.d.ts +1 -1
  45. package/dist/runtime/files/icons.js +1 -1
  46. package/dist/runtime/messages/components/chat-mention-dropdown.d.vue.ts +6 -1
  47. package/dist/runtime/messages/components/chat-mention-dropdown.vue +46 -22
  48. package/dist/runtime/messages/components/chat-mention-dropdown.vue.d.ts +6 -1
  49. package/dist/runtime/messages/components/chat-message-bubble.vue +53 -71
  50. package/dist/runtime/messages/components/chat-message-feedback.vue +25 -229
  51. package/dist/runtime/messages/components/chat-message-input.vue +176 -134
  52. package/dist/runtime/messages/components/chat-message-list.d.vue.ts +6 -0
  53. package/dist/runtime/messages/components/chat-message-list.vue +27 -23
  54. package/dist/runtime/messages/components/chat-message-list.vue.d.ts +6 -0
  55. package/dist/runtime/messages/components/chat-model-selector.vue +10 -22
  56. package/dist/runtime/messages/components/reasoning/chat-reasoning-message.vue +2 -3
  57. package/dist/runtime/messages/components/reasoning/chat-reasoning-thought.vue +60 -69
  58. package/dist/runtime/messages/components/reasoning/chat-thinking-indicator.vue +3 -9
  59. package/dist/runtime/messages/components/widgets/chat-bash-widget.vue +3 -12
  60. package/dist/runtime/messages/components/widgets/chat-doc-sdk-widget.vue +3 -12
  61. package/dist/runtime/messages/components/widgets/chat-generic-tool-widget.vue +3 -12
  62. package/dist/runtime/messages/components/widgets/chat-grep-widget.vue +7 -17
  63. package/dist/runtime/messages/components/widgets/chat-read-widget.vue +7 -17
  64. package/dist/runtime/messages/components/widgets/chat-tela-skill-widget.vue +4 -13
  65. package/dist/runtime/messages/components/widgets/chat-thinking-widget.vue +11 -22
  66. package/dist/runtime/messages/components/widgets/chat-web-search-widget.vue +13 -40
  67. package/dist/runtime/messages/components/widgets/chat-workstation-query-widget.vue +52 -65
  68. package/dist/runtime/messages/components/widgets/chat-write-widget.vue +8 -18
  69. package/dist/runtime/messages/composables/mention-autocomplete.js +4 -0
  70. package/dist/runtime/messages/message-state.js +1 -0
  71. package/dist/runtime/public/files/generic.svg +2 -5
  72. package/dist/runtime/public/files/image.svg +2 -1
  73. package/dist/runtime/types/embed.d.ts +1 -1
  74. package/dist/runtime/types/schemas/chat/conversations.d.ts +2 -0
  75. package/dist/runtime/types/schemas/chat/conversations.js +3 -0
  76. package/dist/runtime/types/schemas/chat/messages.d.ts +4 -0
  77. package/dist/runtime/types/schemas/chat/messages.js +7 -0
  78. package/dist/types.d.mts +1 -1
  79. package/package.json +5 -4
  80. package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.d.vue.ts +0 -23
  81. package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.vue +0 -75
  82. package/dist/runtime/conversations/components/chat-conversation-new-group-popover-content.vue.d.ts +0 -23
  83. package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.d.vue.ts +0 -37
  84. package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.vue +0 -125
  85. package/dist/runtime/messages/components/reasoning/chat-reasoning-step-item.vue.d.ts +0 -37
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  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.
4
4
 
5
+ Consumer documentation lives in `docs/guides/` (indexed [below](#guides)); this README covers the package boundary and working on the package itself.
6
+
5
7
  ## Public Surface
6
8
 
7
9
  `@meistrari/chat-nuxt` is an external package. Its supported consumer surface is intentionally small:
@@ -14,468 +16,59 @@ Nuxt module that adds a complete AI chat interface to your app. Server-side chat
14
16
 
15
17
  Runtime internals under `src/runtime/**`, generated Nuxt aliases, and workspace-only schema package imports are implementation details unless they are explicitly exported above.
16
18
 
17
- ## Installation
18
-
19
- ```bash
20
- pnpm add @meistrari/chat-nuxt
21
- ```
22
-
23
- ### Required: Vue dedupe via pnpm overrides
24
-
25
- `@meistrari/tela-build` pins `vue@3.5.13` as a direct dependency, which collides with the Vue that Nuxt installs. Without an override, pnpm installs two Vue copies and you'll hit runtime errors such as `root.ce._hasShadowRoot is not a function` when custom elements register against one Vue and mount against the other.
26
-
27
- Until tela-build is published with Vue as a peer dependency, pin a single Vue version in your consumer `package.json`:
28
-
29
- ```json
30
- {
31
- "pnpm": {
32
- "overrides": {
33
- "vue": "3.5.33"
34
- }
35
- }
36
- }
37
- ```
38
-
39
- Keep this entry until `@meistrari/tela-build` moves Vue to `peerDependencies` — at that point the override becomes unnecessary and should be removed.
40
-
41
- ## Setup
42
-
43
- ### 1. Register the modules
44
-
45
- ```typescript
46
- // nuxt.config.ts
47
- export default defineNuxtConfig({
48
- modules: [
49
- '@meistrari/auth-nuxt', // must come before chat-nuxt
50
- '@meistrari/chat-nuxt',
51
- ],
52
-
53
- ssr: false,
54
-
55
- chatNuxt: {
56
- chatApiUrl: process.env.CHAT_API_URL,
57
- validateConfig: 'warn',
58
- },
59
-
60
- telaAuth: {
61
- apiUrl: process.env.AUTH_API_URL ?? '',
62
- application: {
63
- enabled: true,
64
- applicationId: process.env.APPLICATION_ID ?? '',
65
- redirectUri: process.env.AUTH_REDIRECT_URI ?? 'http://localhost:3000/auth/callback',
66
- dashboardUrl: process.env.AUTH_DASHBOARD_URL ?? '',
67
- },
68
- },
69
- })
70
- ```
71
-
72
- ### 2. Module options
73
-
74
- `chatApiUrl` accepts the value inline, or you can leave the option empty and set `CHAT_API_URL`. Resolution order: **module option → existing `runtimeConfig` → env var → empty**.
75
-
76
- | Option | Required | Env fallback | Description |
77
- |--------|----------|--------------|-------------|
78
- | `chatApiUrl` | ✅ Always | `CHAT_API_URL` | Dedicated Chat API base URL used by Nuxt server proxy routes. |
79
- | `validateConfig` | 🔧 Optional | — | `false` (default), `'warn'`, or `'error'`. Warns or fails fast when `chatApiUrl` is missing. |
80
-
81
- Set `chatNuxt.validateConfig` to `'warn'` to log a warning when `chatApiUrl` is missing, or `'error'` to fail fast at module setup. The check is off by default since some deployments inject runtime config after build.
82
-
83
- UI features are configured per component instance, not at the module level: the embed takes a `:features` prop (`ChatFeatureConfig`) and `<ChatConfigurationModal>` takes `show-credentials-tab`.
84
-
85
- ### 3. Auth modes
86
-
87
- `@meistrari/chat-nuxt` can run with either auth mode exposed by `@meistrari/auth-nuxt`:
88
-
89
- - Application auth (`telaAuth.application.enabled: true`) delegates chat identity and workspace state to `useTelaApplicationAuth()`.
90
- - First-party auth delegates chat identity to `useTelaSession()` and workspace state to `useTelaOrganization()`.
91
-
92
- The module chooses the bridge during Nuxt setup. Host apps should keep registering `@meistrari/auth-nuxt` before `@meistrari/chat-nuxt`.
93
-
94
- ### 4. Setup `app.vue`
95
-
96
- ```vue
97
- <!-- app.vue -->
98
- <template>
99
- <NuxtPage />
100
- <AppStatusToast />
101
- </template>
102
- ```
103
-
104
- `AppStatusToast`, Markstream styles, code block styles, and math delimiter defaults are auto-registered by the module.
105
-
106
- ### 5. Use it
107
-
108
- ```vue
109
- <!-- pages/index.vue -->
110
- <template>
111
- <div h-screen>
112
- <MeistrariChatEmbed />
113
- </div>
114
- </template>
115
- ```
116
-
117
- The chat workspace is resolved from the authenticated `activeOrganization` provided by `@meistrari/auth-nuxt`.
19
+ `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.
118
20
 
119
- ### Chat runtime modes
21
+ ## Guides
120
22
 
121
- `<MeistrariChatEmbed />` has two mutually exclusive runtimes:
122
-
123
- - **Default chat mode** uses the Chat API and the workspace's configured Tela agent. Runtime configuration, entitlements, and workspace-specific agent selection are owned by `@meistrari/chat-api`. Workspaces whose legacy customization has not been migrated to a Tela agent are not ready to chat: sends fail with `workspace_agent_not_ready` and the embed surfaces guidance pointing to the settings modal, where the **Agente** tab offers a one-click agent creation.
124
- - **Tela agent mode** uses a configured Tela agent directly. Pass `telaAgentId`; the embed sends user messages to `POST /agent/:id/run`, polls `GET /agent/sessions/:sessionId`, and ends sessions with `DELETE /agent/sessions/:sessionId`.
125
-
126
- ```vue
127
- <MeistrariChatEmbed tela-agent-id="agent_123" />
128
- ```
129
-
130
- `conversationScope` works in both runtimes. In default chat mode, it isolates conversations inside the authenticated workspace while the Chat API resolves the correct Tela agent:
131
-
132
- ```vue
133
- <MeistrariChatEmbed :conversation-scope="`user:${userId}`" />
134
- ```
135
-
136
- Host apps can also provide Tela agent inputs directly. When `telaAgentInputs` is non-null, the chat sends those inputs with each agent run and does not render the agent variables panel.
137
-
138
- ```vue
139
- <MeistrariChatEmbed
140
- tela-agent-id="agent_123"
141
- :conversation-scope="`customer:${customerId}`"
142
- :tela-agent-inputs="[
143
- { type: 'text', name: 'customer_id', content: customerId },
144
- ]"
145
- />
146
- ```
147
-
148
- In Tela agent mode, `workspaceSettings` and `user` are not accepted by the public prop contract - the Tela agent owns runtime configuration and identity for execution. `features` is still accepted for shared UI controls.
23
+ | Guide | Covers |
24
+ |-------|--------|
25
+ | [Installation and setup](docs/guides/installation.md) | Install, Vue dedupe override, module registration, module options, auth modes |
26
+ | [Embedding in your layout](docs/guides/embedding.md) | Layout, key props, conversation scoping, events, slots |
27
+ | [Chat runtime modes](docs/guides/tela-agent-mode.md) | Default chat mode vs Tela agent mode, agent inputs |
28
+ | [Citations](docs/guides/citations.md) | `cite://` chips, metadata popover, document panel |
29
+ | [Feature flags](docs/guides/feature-flags.md) | Usage tab, debug entry, cancel button, PostHog wiring |
30
+ | [Message feedback](docs/guides/message-feedback.md) | 👍/👎 controls and host-owned persistence |
31
+ | [Workspace settings](docs/guides/workspace-settings.md) | Settings overrides, agent runtime ownership, `<ChatConfigurationModal>` |
149
32
 
150
- ## Embedding in Your Layout
33
+ ## API Reference
151
34
 
152
- The main use case: drop the chat inside your existing app UI.
35
+ 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.
153
36
 
154
- ```vue
155
- <template>
156
- <div class="my-app-layout">
157
- <MyHeader />
37
+ To render the reference locally:
158
38
 
159
- <main>
160
- <!-- Chat embedded in a card -->
161
- <div style="height: 600px" class="rounded-2xl overflow-hidden border">
162
- <MeistrariChatEmbed
163
- v-model:conversation-id="activeConversation"
164
- :hide-sidebar="true"
165
- :loading-messages="['Buscando contratos', 'Lendo documentos', 'Preparando resposta']"
166
- loading-messages-mode="ordered"
167
- />
168
- </div>
169
- </main>
170
- </div>
171
- </template>
39
+ ```bash
40
+ bunx --bun typedoc --entryPoints typedoc.ts --out /tmp/chat-nuxt-api --skipErrorChecking
172
41
  ```
173
42
 
174
- Key props for embedding:
175
-
176
- - **`:hide-sidebar="true"`** — removes the conversation list, keeps just the chat
177
- - **`v-model:conversation-id`** — sync the active conversation with your app's state
178
- - **`:initial-conversation-id`** — open a specific conversation on mount
179
- - **`conversation-scope`** — isolate conversation history inside the same workspace or Tela agent
43
+ The table below is a quick index for reading in-repo. **When you change a prop, update its JSDoc and this row together.**
180
44
 
181
- ## `<MeistrariChatEmbed>` Props
45
+ ### `<MeistrariChatEmbed>` props
182
46
 
183
- All prop, feature-flag, and event payload types are importable from the package root (or the `types/embed` subpath):
184
-
185
- ```ts
186
- import type {
187
- ChatActionPayload,
188
- ChatFeatureConfig,
189
- MeistrariChatEmbedProps,
190
- MessageFeedbackConfig,
191
- MessageFeedbackPayload,
192
- MessageFeedbackRating,
193
- } from '@meistrari/chat-nuxt'
194
- ```
47
+ 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`.
195
48
 
196
49
  | Prop | Type | Default | Description |
197
50
  |------|------|---------|-------------|
198
- | `hideSidebar` | `boolean` | `false` | Hide conversation list sidebar |
51
+ | `hideSidebar` | `boolean` | `false` | Hide the conversation list and render only the active chat surface |
199
52
  | `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 |
200
53
  | `hideSettings` | `boolean` | `false` | Hide workspace settings actions while keeping the chat header and content unchanged |
201
- | `conversationId` | `string \| null` | `null` | Controlled conversation (supports v-model) |
202
- | `initialConversationId` | `string \| null` | `null` | Open this conversation on mount |
203
- | `conversationScope` | `string \| null` | `null` | Isolate conversation history by technical scope within the current workspace and runtime |
204
- | `defaultConversationCreatorFilter` | `'all' \| 'mine'` | `'all'` | Initial sidebar creator filter |
54
+ | `conversationId` | `string \| null` | `null` | Controlled conversation (supports `v-model:conversation-id`) |
55
+ | `initialConversationId` | `string \| null` | `null` | Conversation to open once on mount when `conversationId` is uncontrolled |
56
+ | `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`, `.`, `_`, `:`, `/`, `-` |
57
+ | `defaultConversationCreatorFilter` | `'all' \| 'mine'` | `'all'` | Initial sidebar creator filter: every conversation in scope, or only the current user's |
205
58
  | `telaAgentId` | `string` | — | Use Tela agent mode for this embed |
206
59
  | `telaAgentInputs` | `TelaAgentExecutionInput[] \| null` | `undefined` | Inputs sent with each Tela agent run; hides the variables panel when non-null |
207
- | `workspaceSettings` | `WorkspaceSettings \| null` | `null` | Override settings from host app |
208
- | `user` | `ChatActor \| null` | `null` | Override current user display info |
209
- | `features` | `Partial<ChatFeatureConfig>` | `{}` | Toggle optional features |
60
+ | `workspaceSettings` | `WorkspaceSettings \| null` | `null` | Override settings from host app; not accepted in Tela agent mode |
61
+ | `user` | `ChatActor \| null` | `null` | Override current user display info; not accepted in Tela agent mode |
62
+ | `features` | `Partial<ChatFeatureConfig>` | `{}` | Toggle optional features: `showUsageTab`, `showDebugOption`, `showCancelButton` (all `false`) |
210
63
  | `loadingMessages` | `readonly string[] \| null` | Default chat messages | Override pending-response messages |
211
- | `loadingMessagesMode` | `'ordered' \| 'random' \| null` | `'ordered'` | Show custom messages sequentially or randomly |
64
+ | `loadingMessagesMode` | `'ordered' \| 'random' \| null` | `'ordered'` | Rotate custom messages in order or at random; only applies when `loadingMessages` has a non-empty message |
212
65
  | `customComponents` | `Record<string, Component>` | `undefined` | Custom markdown renderers keyed by markdown node or tag name |
213
66
  | `customHtmlTags` | `readonly string[]` | `undefined` | Extra HTML tags allowed by the markdown renderer |
214
- | `citations` | `ChatCitationsConfig \| null` | `undefined` | Enables `cite://` citations in assistant messages (see Citations below) |
67
+ | `citations` | `ChatCitationsConfig \| null` | `undefined` | Enables `cite://` citations in assistant messages (see [Citations](docs/guides/citations.md)) |
215
68
  | `feedbackConfig` | `MessageFeedbackConfig \| null` | `undefined` | Enables 👍/👎 feedback on assistant messages; providing the prop (even `{}`) shows the controls |
216
69
  | `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 |
217
70
 
218
- `loadingMessagesMode` only applies when `loadingMessages` has at least one non-empty message.
219
-
220
- Use `conversationScope` when you need multiple chat surfaces to share the same authenticated workspace but keep separate histories. This is useful for per-user inboxes, record detail pages, customer workspaces, template previews, workflow steps, or any app route where the same chat should only show conversations for that route's domain object. The scope is applied together with the workspace and, when present, the `telaAgentId`.
221
-
222
- Scoped embeds only see conversations created with the same scope. Unscoped embeds only see unscoped conversations, so adding a scope will not mix with existing workspace-level history. Scope values are technical identifiers: they are trimmed, blank strings become `null`, and server requests accept 1-200 characters from `A-Z`, `a-z`, `0-9`, `.`, `_`, `:`, `/`, and `-`.
223
-
224
- ```vue
225
- <!-- Default chat mode: workspace + scope -->
226
- <MeistrariChatEmbed :conversation-scope="`user:${userId}`" />
227
- <MeistrariChatEmbed :conversation-scope="`customer:${customerId}`" />
228
-
229
- <!-- Tela agent mode: workspace + telaAgentId + scope -->
230
- <MeistrariChatEmbed
231
- tela-agent-id="agent_123"
232
- :conversation-scope="`template:${templateId}`"
233
- />
234
- ```
235
-
236
- **Citations (`cite://`):**
237
-
238
- Hosts whose agents cite retrievable documents can teach them (via prompt) the notation
239
-
240
- ```
241
- [visible text](cite://<namespace>/<id>[#q=<term>&n=<nth>&p=<page>])
242
- ```
243
-
244
- and pass `citations` to enable it. The lib detects the notation in assistant messages (markdown links and bare tokens), renders each citation as a chip with a metadata popover, and — when `getDocument` is provided — opens a built-in side panel that shows the document with the cited term highlighted (`#q`, nth occurrence via `#n`). What a namespace means, and every data access, belongs to the host: callbacks run against the host's own backend, carrying the viewing user's authorization. A citation that fails to resolve renders as "unverified" — an agent cannot fabricate a trusted-looking reference, and a viewer without access to a document learns nothing from a citation to it.
245
-
246
- ```vue
247
- <MeistrariChatEmbed
248
- tela-agent-id="agent_123"
249
- :citations="{
250
- resolve: ref => $fetch(`/api/citations/${ref.namespace}/${encodeURIComponent(ref.id)}`).catch(() => null),
251
- getDocument: ref => $fetch(`/api/citations/${ref.namespace}/${encodeURIComponent(ref.id)}/document`).catch(() => null),
252
- locate: (ref, term) => $fetch(`/api/citations/${ref.namespace}/${encodeURIComponent(ref.id)}/occurrences`, { query: { term } }).catch(() => null),
253
- }"
254
- />
255
- ```
256
-
257
- `ref.id` arrives percent-decoded (natural identifiers may carry pipes, spaces, accents or slashes) — re-encode it when building URLs, as above.
258
-
259
- `ChatCitationsConfig` (exported from `@meistrari/chat-nuxt/types/citations`): `resolve` maps a citation to display metadata (`null` = unverified); `getDocument` enables the document panel; `locate` returns precise term offsets for highlighting (omit it for a client-side, accent-sensitive fallback); `component` replaces the built-in chip; `onOpen` takes over the click entirely. Without the `citations` prop nothing changes: `cite://` hrefs keep rendering as plain links.
260
-
261
- **Events:**
262
-
263
- | Event | Payload | Description |
264
- |-------|---------|-------------|
265
- | `update:conversationId` | `string \| null` | Active conversation changed |
266
- | `action` | `ChatActionPayload` | Custom action triggered from chat content (`{ name, data, messageId? }`) |
267
- | `messageFeedback` | `MessageFeedbackPayload` | User voted on an assistant message (see [Message Feedback](#optional-message-feedback)) |
268
-
269
- **Slots:**
270
-
271
- | Slot | Description |
272
- |------|-------------|
273
- | `sidebar-bottom` | Splits the desktop sidebar into two panes and renders your content in the bottom one, below the conversation list. Each pane scrolls independently. Size it with `sidebar.bottomHeight` (percentage, default `50`). Not rendered on mobile or when `hideSidebar` is set. |
274
-
275
- ```vue
276
- <MeistrariChatEmbed :sidebar="{ position: 'right', width: 300, bottomHeight: 30 }">
277
- <template #sidebar-bottom>
278
- <MyPinnedDocuments />
279
- </template>
280
- </MeistrariChatEmbed>
281
- ```
282
-
283
- ## Optional: Feature Flags
284
-
285
- `<MeistrariChatEmbed>` accepts a `:features` prop with three optional toggles. All default to `false`. The host owns the policy - hardcode them, gate by user role, or wire them through a feature-flag provider of your choice.
286
-
287
- | Flag | Effect |
288
- |------|--------|
289
- | `showUsageTab` | Usage tab in the chat topbar (per-conversation token/cost stats) |
290
- | `showDebugOption` | Debug entry in the topbar overflow menu |
291
- | `showCancelButton` | "Stop generation" button while a response streams |
292
-
293
- Static example:
294
-
295
- ```vue
296
- <MeistrariChatEmbed :features="{ showUsageTab: true, showCancelButton: true }" />
297
- ```
298
-
299
- ### With PostHog
300
-
301
- `chat-nuxt` ships a small PostHog helper for hosts that want to gate flags dynamically. The flag names live in your app — `chat-nuxt` has no opinion about them.
302
-
303
- 1. Add to `nuxt.config.ts`:
304
-
305
- ```typescript
306
- runtimeConfig: {
307
- public: {
308
- posthogPublicKey: process.env.POSTHOG_PUBLIC_KEY ?? '',
309
- posthogHost: process.env.POSTHOG_HOST ?? '',
310
- posthogDefaults: process.env.POSTHOG_DEFAULTS ?? '2026-01-30',
311
- },
312
- },
313
- ```
314
-
315
- 2. Initialize in `app.vue`:
316
-
317
- ```vue
318
- <script setup lang="ts">
319
- const { posthogPublicKey, posthogHost, posthogDefaults } = useRuntimeConfig().public
320
-
321
- // Application auth hosts:
322
- const { user, activeOrganization } = useTelaApplicationAuth()
323
-
324
- // First-party auth hosts can use this instead:
325
- // const session = useTelaSession()
326
- // const organization = useTelaOrganization()
327
- // const user = session.user
328
- // const activeOrganization = organization.activeOrganization
329
- // await organization.getActiveOrganization()
330
-
331
- onMounted(async () => {
332
- if (!posthogPublicKey || !posthogHost) return
333
- await initPosthog(posthogPublicKey, posthogHost, posthogDefaults)
334
- if (user.value) identifyPosthogUser(user.value)
335
- if (activeOrganization.value) setPosthogWorkspace(activeOrganization.value)
336
- })
337
- </script>
338
- ```
339
-
340
- 3. Thread the flags into the embed:
341
-
342
- ```vue
343
- <script setup lang="ts">
344
- const { isFeatureEnabled } = useFeatureFlags()
345
-
346
- const features = computed(() => ({
347
- showUsageTab: isFeatureEnabled('enable-usage-tab'),
348
- showDebugOption: isFeatureEnabled('enable-debug-mode'),
349
- showCancelButton: isFeatureEnabled('enable-cancel-generation'),
350
- }))
351
- </script>
352
-
353
- <template>
354
- <MeistrariChatEmbed :features="features" />
355
- </template>
356
- ```
357
-
358
- ## Optional: Message Feedback
359
-
360
- Assistant messages can carry 👍/👎 controls. The package renders the controls and collects the vote; **persistence is owned by the host** — nothing is stored by `chat-nuxt`.
361
-
362
- Passing `feedbackConfig` (even `{}`) enables the controls:
363
-
364
- ```vue
365
- <script setup lang="ts">
366
- import type { MessageFeedbackPayload, MessageFeedbackRating } from '@meistrari/chat-nuxt'
367
-
368
- const votes = ref<Record<string, MessageFeedbackRating>>({})
369
-
370
- async function onFeedback(payload: MessageFeedbackPayload) {
371
- // payload: { conversationId, messageId, rating, reasons, comment }
372
- await saveVoteToMyBackend(payload)
373
- votes.value = { ...votes.value, [payload.messageId]: payload.rating }
374
- }
375
- </script>
376
-
377
- <template>
378
- <MeistrariChatEmbed
379
- :feedback-config="{
380
- negativeReasons: ['Resposta incorreta', 'Fora do tema', 'Incompleta'],
381
- requireReason: true,
382
- }"
383
- :message-feedback="votes"
384
- @message-feedback="onFeedback"
385
- />
386
- </template>
387
- ```
388
-
389
- `MessageFeedbackConfig` fields:
390
-
391
- | Field | Effect |
392
- |-------|--------|
393
- | `positiveReasons` | Reason chips offered on a positive vote. Empty or omitted: 👍 submits directly |
394
- | `negativeReasons` | Reason chips offered on a negative vote |
395
- | `requireReason` | Blocks a bare negative vote: requires at least one reason chip when `negativeReasons` are configured, otherwise a non-empty comment |
396
-
397
- `messageFeedback` controls which thumb renders selected:
398
-
399
- - **Provided** (controlled): only host-persisted votes render. Update the map as `message-feedback` events are saved — optimistically or after persistence.
400
- - **Omitted**: votes are kept in component-local state only.
401
-
402
- ## Optional: Custom Workspace Settings
403
-
404
- Agent-level configuration (system prompt, context files, tools, skills) lives in the workspace's Tela agent and is edited in the Tela app. The module's built-in settings UI manages knowledge sources (Tela workstations) and workspace credentials, persisted by the Chat API service.
405
-
406
- To override the settings the embed reads, pass them directly from your host app:
407
-
408
- ```vue
409
- <MeistrariChatEmbed
410
- :workspace-settings="{
411
- workspaceId: 'ws_123',
412
- systemMessage: 'You are a helpful assistant for Acme Corp.',
413
- contextFiles: null,
414
- canvasTools: null,
415
- knowledgeSources: null,
416
- externalSkills: null,
417
- updatedAt: new Date(),
418
- }"
419
- />
420
- ```
421
-
422
- The `server/chat/resolve-workspace-settings.ts` host resolver from earlier versions is no longer invoked: the module proxies chat requests to the Chat API, which owns workspace settings resolution.
423
-
424
- ## Agent Runtime Configuration
425
-
426
- `chat-nuxt` proxies chat requests to `@meistrari/chat-api`; it does not start agent sessions directly or resolve runtime environment variables. Agent runtime configuration, entitlements, and Tela agent selection are owned by `chat-api` and the Tela agent configuration. Host apps do not need Nuxt-side agent environment resolver files for this module.
427
-
428
- A skill that calls a host backend must implement its own callback contract with the host backend. In short, callback authorization belongs to the skill and host backend, not `chat-nuxt`. The host backend remains responsible for validating invocation grants, allowed tools, schemas, replay protection, confirmation for writes, and audit logging.
429
-
430
- ## `<ChatConfigurationModal>`
431
-
432
- A reusable workspace settings modal that any host app can open from any button. It has three tabs:
433
-
434
- - **`agent`** (Agente) — the workspace's Tela agent status. Shows the generic-chat state, the dedicated agent (id, copy, open in Tela), or — for workspaces whose legacy customization has not been migrated — a setup-required warning with a create-agent action. Agent configuration itself (system prompt, context files, tools, skills) is edited in the Tela app, not here.
435
- - **`knowledge-sources`** (Tela workstations) — the workstations injected as knowledge sources into new chat sessions.
436
- - **`credentials`** (Credenciais) — workspace credentials, shown when `showCredentialsTab` is set.
437
-
438
- By default, the modal uses `useWorkspaceSettings()` to fetch and persist settings. If the host passes the `settings` prop, the host owns workspace settings state and persistence.
439
-
440
- ```vue
441
- <script setup lang="ts">
442
- import type { ChatConfigurationTab } from '@meistrari/chat-nuxt/types/workspace-settings'
443
-
444
- const open = ref(false)
445
- const initialTab = ref<ChatConfigurationTab>('agent')
446
-
447
- function openSettings(tab: ChatConfigurationTab = 'agent') {
448
- initialTab.value = tab
449
- open.value = true
450
- }
451
- </script>
452
-
453
- <template>
454
- <button @click="openSettings()">
455
- Configurações
456
- </button>
457
-
458
- <ChatConfigurationModal
459
- v-model:open="open"
460
- :initial-tab="initialTab"
461
- />
462
- </template>
463
- ```
464
-
465
- | Prop | Type | Default | Description |
466
- |------|------|---------|-------------|
467
- | `open` | `boolean` | — | Modal visibility (supports `v-model:open`) |
468
- | `settings` | `WorkspaceSettings \| null` | `undefined` | Optional host-controlled settings. Omit this prop to let the modal fetch and persist via `useWorkspaceSettings()`; pass `null` or a settings object to make the host own state and persistence |
469
- | `initialTab` | `ChatConfigurationTab` | `'agent'` | Tab to open on: `'agent' \| 'knowledge-sources' \| 'credentials'` |
470
- | `saving` | `boolean` | `false` | Host-controlled spinner/disable while persistence is in flight |
471
- | `showCredentialsTab` | `boolean` | `false` | Show the workspace credentials tab |
472
-
473
- | Event | Payload | Description |
474
- |-------|---------|-------------|
475
- | `update:open` | `boolean` | Modal open state changed |
476
- | `save` | `ChatConfigurationSavePayload` | Emitted only when the host passes `settings`; carries the knowledge-source updates plus `onSaved`; host persists (e.g. via `useWorkspaceSettings().updateSettings()`), calls `onSaved` after persistence succeeds, and closes the modal |
477
-
478
- Only the knowledge-sources tab produces a `save` payload. The `agent` tab acts immediately through the module's `/api/workspace/agent` endpoints, and the `credentials` tab manages its own data via `/api/workspace/credentials` — neither is part of the `save` payload.
71
+ 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).
479
72
 
480
73
  ## What's Included
481
74
 
@@ -485,6 +78,23 @@ The module auto-registers everything — no manual imports needed:
485
78
  - **Composables**: `useChat`, `useConversations`, `useWorkspaceSettings`, `useFileUpload`, `useFeatureFlags`, and more
486
79
  - **Server routes**: thin proxy routes that forward chat requests to the Chat API service
487
80
 
81
+ ## Development
82
+
83
+ Run from this package:
84
+
85
+ ```bash
86
+ pnpm build # nuxt-module-build + embedded schema/declaration post-processing
87
+ pnpm dev:prepare # stub build for local development
88
+ pnpm typecheck # builds the module, prepares chat-app, typechecks the host app
89
+ pnpm test:types # build + tsc against the consumer type tests
90
+ pnpm smoke:pack # pack the module and install it into a scratch consumer
91
+ pnpm smoke:browser # packed-consumer smoke test with a real browser
92
+ pnpm lint # eslint
93
+ pnpm lint:attrs # guards against stray `!` attribute typos in runtime templates
94
+ ```
95
+
96
+ Unit tests run from the workspace root (`pnpm test`), which prepares this package before invoking vitest.
97
+
488
98
  ## Package Dependencies
489
99
 
490
100
  Installing `@meistrari/chat-nuxt` installs the runtime packages used by the layer. The host Nuxt app still owns the Nuxt and Vue versions.
@@ -515,5 +125,5 @@ Peer dependencies:
515
125
 
516
126
  | Package | Version | Purpose |
517
127
  |---------|---------|---------|
518
- | `nuxt` | `^3.17.0` | Host framework |
128
+ | `nuxt` | `^3.17.0 \|\| ^4.0.0` | Host framework |
519
129
  | `vue` | `^3.5.0` | Host Vue runtime |
package/dist/module.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { ChatMessageStatus } from '../dist/runtime/messages/composables/chat-message-terminal.js';
2
- export { ChatActionPayload, ChatActor, ChatEmbedSharedProps, ChatFeatureConfig, ChatMessageTerminalPayload, ChatSidebarConfig, DefaultChatEmbedProps, MeistrariChatEmbedProps, MessageFeedbackConfig, MessageFeedbackPayload, MessageFeedbackRating, MessageOverviewResponse, TelaAgentChatEmbedProps, TelaAgentExecutionInput } from '../dist/runtime/types/embed.js';
2
+ export { ChatActionPayload, ChatActor, ChatEmbedSharedProps, ChatEmbedVariant, ChatEmbedVariantProps, ChatFeatureConfig, ChatMessageTerminalPayload, ChatSidebarConfig, ChatSuggestion, DefaultChatEmbedProps, MeistrariChatEmbedProps, MessageFeedbackConfig, MessageFeedbackPayload, MessageFeedbackRating, MessageOverviewResponse, TelaAgentChatEmbedProps, TelaAgentExecutionInput } from '../dist/runtime/types/embed.js';
3
3
 
4
4
  type ChatNuxtConfigValidationMode = false | 'warn' | 'error';
5
5
 
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
3
  "configKey": "chatNuxt",
4
- "version": "3.9.2",
4
+ "version": "3.10.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -1 +1 @@
1
- .markstream-vue{color:var(--black-900);font-family:Inter,"Inter Fallback: Arial",sans-serif;font-size:16px;font-weight:400;letter-spacing:-.15px;line-height:24px}.markstream-vue code,.markstream-vue kbd,.markstream-vue pre,.markstream-vue samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-size:13px;font-variation-settings:normal;line-height:1.5}.markstream-vue ol,.markstream-vue ul{margin:8px 0;padding-left:1.5em}.markstream-vue ul{list-style:disc;list-style-position:outside}.markstream-vue ol{list-style:decimal;list-style-position:outside}.markstream-vue li{margin:4px 0}.markstream-vue .paragraph-node{margin:0}.markstream-vue .heading-1,.markstream-vue h1{font-family:Inter,"Inter Fallback: Arial",sans-serif;font-size:32px;font-weight:580;letter-spacing:-1px;line-height:36px;margin:24px 0 16px}.markstream-vue .heading-2,.markstream-vue h2{font-family:Inter,"Inter Fallback: Arial",sans-serif;font-size:24px;font-weight:580;letter-spacing:-.8px;line-height:28px;margin:20px 0 12px}.markstream-vue .heading-3,.markstream-vue h3{font-family:Inter,"Inter Fallback: Arial",sans-serif;font-size:20px;font-weight:580;letter-spacing:-.5px;line-height:24px;margin:16px 0 8px}.markstream-vue .heading-4,.markstream-vue h4{font-family:Inter,"Inter Fallback: Arial",sans-serif;font-size:16px;font-weight:580;letter-spacing:-.2px;line-height:20px;margin:12px 0 6px}.markstream-vue .heading-5,.markstream-vue h5{font-family:Inter,"Inter Fallback: Arial",sans-serif;font-size:14px;font-weight:580;letter-spacing:-.15px;line-height:16px;margin:8px 0 4px}.markstream-vue .heading-6,.markstream-vue h6{font-family:Inter,"Inter Fallback: Arial",sans-serif;font-size:12px;font-weight:580;letter-spacing:-.1px;line-height:14px;margin:8px 0 4px}.markstream-vue [class*=tooltip],[class*=tooltip-element]{background-color:var(--black-900,#1a1a1a)!important;border-radius:4px;color:#fff!important;font-size:12px;padding:4px 8px}.mention-tag{align-items:center;border-radius:9999px;display:inline-flex;font-size:.875em;font-weight:500;gap:4px;padding:2px 8px;vertical-align:middle;white-space:nowrap}.mention-tag-file{background-color:rgba(127,189,247,.12);color:#7fbdf7}.mention-tag-skill{background-color:rgba(155,111,222,.12);color:#9b6fde}.mention-tag-canvas{background-color:rgba(234,161,65,.12);color:#d4882e}.mention-tag>span[class*=i-ph]{flex-shrink:0}
1
+ .markstream-vue{color:#171717;font-family:Inter,"Inter Fallback: Arial",sans-serif;font-size:16px;font-weight:400;letter-spacing:-.15px;line-height:24px;--list-item-marker:#a3a3a3}.markstream-vue code,.markstream-vue kbd,.markstream-vue pre,.markstream-vue samp{font-family:Geist Mono Variable,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-size:13px;font-variation-settings:normal;line-height:1.5}.markstream-vue ol,.markstream-vue ul{margin:8px 0;padding-left:1.5em}.markstream-vue .hr-node{border-color:#e5e5e5;border-top-width:.5px;margin-bottom:24px;margin-top:24px}.markstream-vue .strong-node{font-weight:580}.markstream-vue .list-node.list-node{margin-bottom:8px;margin-left:4px;margin-top:8px;padding-left:1em}.markstream-vue ul{list-style:disc;list-style-position:outside}.markstream-vue ol{list-style:decimal;list-style-position:outside}.markstream-vue li{margin:4px 0}.markstream-vue .paragraph-node{margin:0}.markstream-vue .my-8{margin-bottom:8px;margin-top:8px}.markstream-vue .heading-node.heading-1,.markstream-vue h1{font-size:24px;font-weight:540;letter-spacing:-.8px;line-height:28px;margin:24px 0 16px}.markstream-vue .heading-node.heading-2,.markstream-vue h2{font-size:20px;font-weight:540;letter-spacing:-.5px;line-height:24px;margin:20px 0 12px}.markstream-vue .heading-node.heading-3,.markstream-vue h3{font-size:20px;font-weight:540;letter-spacing:-.5px;line-height:24px;margin:16px 0 8px}.markstream-vue .heading-node.heading-4,.markstream-vue h4{font-size:16px;font-weight:540;letter-spacing:-.2px;line-height:20px;margin:12px 0 6px}.markstream-vue .heading-node.heading-5,.markstream-vue h5{font-size:14px;font-weight:540;letter-spacing:-.15px;line-height:16px;margin:8px 0 4px}.markstream-vue .heading-node.heading-6,.markstream-vue h6{font-size:12px;font-weight:540;letter-spacing:-.1px;line-height:14px;margin:8px 0 4px}.markstream-vue [class*=tooltip],[class*=tooltip-element]{background-color:var(--neutral-900,#1a1a1a)!important;border-radius:4px;color:#fff!important;font-size:12px;padding:4px 8px}.mention-tag{align-items:center;border-radius:9999px;display:inline-flex;font-size:.875em;font-weight:500;gap:4px;padding:2px 8px;vertical-align:middle;white-space:nowrap}.mention-tag-file{background-color:rgba(127,189,247,.12);color:#7fbdf7}.mention-tag-skill{background-color:rgba(155,111,222,.12);color:#9b6fde}.mention-tag-canvas{background-color:rgba(234,161,65,.12);color:#d4882e}.mention-tag>span[class*=i-ph]{flex-shrink:0}