@meistrari/chat-nuxt 1.5.1 → 1.7.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 (46) hide show
  1. package/README.md +82 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +129 -3
  4. package/dist/runtime/components/MeistrariChatEmbed.vue +3 -0
  5. package/dist/runtime/components/chat/message-bubble.vue +2 -1
  6. package/dist/runtime/composables/useChat.js +4 -2
  7. package/dist/runtime/composables/useChatApi.js +6 -1
  8. package/dist/runtime/composables/useConversations.js +5 -2
  9. package/dist/runtime/composables/useEmbedConfig.d.ts +2 -0
  10. package/dist/runtime/composables/useEmbedConfig.js +5 -0
  11. package/dist/runtime/composables/useGitHubSkills.js +2 -1
  12. package/dist/runtime/composables/useWorkspaceExternalSkills.js +2 -1
  13. package/dist/runtime/composables/useWorkspaceMembers.js +2 -1
  14. package/dist/runtime/composables/useWorkspaceSettings.js +2 -1
  15. package/dist/runtime/composables/useWorkspaces.js +2 -1
  16. package/dist/runtime/embed/components/ChatEmbed.vue +7 -3
  17. package/dist/runtime/embed/components/ChatEmbedInner.vue +2 -1
  18. package/dist/runtime/internal/agent-environment-resolver.stub.d.ts +2 -0
  19. package/dist/runtime/internal/agent-environment-resolver.stub.js +1 -0
  20. package/dist/runtime/server/api/conversations/[id]/duplicate.post.js +1 -0
  21. package/dist/runtime/server/api/conversations/[id]/messages/[messageId]/retry.post.js +6 -2
  22. package/dist/runtime/server/api/conversations/[id]/messages/index.post.js +6 -2
  23. package/dist/runtime/server/api/conversations/index.post.js +1 -0
  24. package/dist/runtime/server/db/schema/conversations.d.ts +17 -0
  25. package/dist/runtime/server/db/schema/conversations.js +1 -0
  26. package/dist/runtime/server/utils/agent-api.js +4 -3
  27. package/dist/runtime/server/utils/agent-environment.d.ts +8 -0
  28. package/dist/runtime/server/utils/agent-environment.js +34 -0
  29. package/dist/runtime/server/utils/auth-token.d.ts +2 -0
  30. package/dist/runtime/server/utils/auth-token.js +21 -0
  31. package/dist/runtime/server/utils/chat-context.d.ts +2 -0
  32. package/dist/runtime/server/utils/chat-context.js +15 -1
  33. package/dist/runtime/server/utils/conversation-agent-turn.d.ts +6 -1
  34. package/dist/runtime/server/utils/conversation-agent-turn.js +27 -8
  35. package/dist/runtime/server/utils/conversation-scope.js +2 -1
  36. package/dist/runtime/server/utils/tela-api.js +2 -1
  37. package/dist/runtime/server/utils/workspace.js +3 -1
  38. package/dist/runtime/types/chat-agent-environment-resolver.d.ts +4 -0
  39. package/dist/runtime/types/chat-auth.d.ts +35 -0
  40. package/dist/runtime/types/embed.d.ts +19 -0
  41. package/dist/runtime/utils/tela-chat.d.ts +3 -1
  42. package/dist/runtime/utils/tela-chat.js +11 -2
  43. package/drizzle/0015_illegal_blindfold.sql +1 -0
  44. package/drizzle/meta/0015_snapshot.json +738 -0
  45. package/drizzle/meta/_journal.json +7 -0
  46. package/package.json +6 -1
package/README.md CHANGED
@@ -103,6 +103,15 @@ These never appear in module options — set them via `.env`, Infisical, etc. Wh
103
103
 
104
104
  Set `chatNuxt.validateConfig` to `'warn'` to log a warning when keys for an enabled feature are missing, or `'error'` to fail fast at module setup. The check is off by default since some deployments inject runtime config after build.
105
105
 
106
+ ### Auth modes
107
+
108
+ `@meistrari/chat-nuxt` can run with either auth mode exposed by `@meistrari/auth-nuxt`:
109
+
110
+ - Application auth (`telaAuth.application.enabled: true`) delegates chat identity and workspace state to `useTelaApplicationAuth()`.
111
+ - First-party auth delegates chat identity to `useTelaSession()` and workspace state to `useTelaOrganization()`.
112
+
113
+ The module chooses the bridge during Nuxt setup. Host apps should keep registering `@meistrari/auth-nuxt` before `@meistrari/chat-nuxt`.
114
+
106
115
  ### Local mode (no database)
107
116
 
108
117
  When `databaseUrl` is empty, chat-nuxt runs an embedded [pglite](https://pglite.dev) instance — Postgres compiled to WASM, in-process, file-backed at `<rootDir>/.data/chat-nuxt.db`. Migrations are applied automatically on first boot. Tables live under a dedicated `chat` Postgres schema so the database can be safely shared with the host app's own Drizzle setup.
@@ -152,11 +161,18 @@ The chat workspace is resolved from the authenticated `activeOrganization` provi
152
161
  <MeistrariChatEmbed tela-agent-id="agent_123" />
153
162
  ```
154
163
 
164
+ `conversationScope` works in both runtimes. In default chat mode, it isolates conversations inside the authenticated workspace without requiring a Tela agent:
165
+
166
+ ```vue
167
+ <MeistrariChatEmbed :conversation-scope="`user:${userId}`" />
168
+ ```
169
+
155
170
  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.
156
171
 
157
172
  ```vue
158
173
  <MeistrariChatEmbed
159
174
  tela-agent-id="agent_123"
175
+ :conversation-scope="`customer:${customerId}`"
160
176
  :tela-agent-inputs="[
161
177
  { type: 'text', name: 'customer_id', content: customerId },
162
178
  ]"
@@ -194,6 +210,7 @@ Key props for embedding:
194
210
  - **`:hide-sidebar="true"`** — removes the conversation list, keeps just the chat
195
211
  - **`v-model:conversation-id`** — sync the active conversation with your app's state
196
212
  - **`:initial-conversation-id`** — open a specific conversation on mount
213
+ - **`conversation-scope`** — isolate conversation history inside the same workspace or Tela agent
197
214
 
198
215
  ## `<MeistrariChatEmbed>` Props
199
216
 
@@ -202,6 +219,7 @@ Key props for embedding:
202
219
  | `hideSidebar` | `boolean` | `false` | Hide conversation list sidebar |
203
220
  | `conversationId` | `string \| null` | `null` | Controlled conversation (supports v-model) |
204
221
  | `initialConversationId` | `string \| null` | `null` | Open this conversation on mount |
222
+ | `conversationScope` | `string \| null` | `null` | Isolate conversation history by technical scope within the current workspace and runtime |
205
223
  | `telaAgentId` | `string` | — | Use Tela agent mode for this embed |
206
224
  | `telaAgentInputs` | `TelaAgentExecutionInput[] \| null` | `undefined` | Inputs sent with each Tela agent run; hides the variables panel when non-null |
207
225
  | `workspaceSettings` | `WorkspaceSettings \| null` | `null` | Override settings from host app |
@@ -212,6 +230,22 @@ Key props for embedding:
212
230
 
213
231
  `loadingMessagesMode` only applies when `loadingMessages` has at least one non-empty message.
214
232
 
233
+ 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`.
234
+
235
+ 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 `-`.
236
+
237
+ ```vue
238
+ <!-- Default chat mode: workspace + scope -->
239
+ <MeistrariChatEmbed :conversation-scope="`user:${userId}`" />
240
+ <MeistrariChatEmbed :conversation-scope="`customer:${customerId}`" />
241
+
242
+ <!-- Tela agent mode: workspace + telaAgentId + scope -->
243
+ <MeistrariChatEmbed
244
+ tela-agent-id="agent_123"
245
+ :conversation-scope="`template:${templateId}`"
246
+ />
247
+ ```
248
+
215
249
  **Events:**
216
250
 
217
251
  | Event | Payload | Description |
@@ -256,8 +290,17 @@ runtimeConfig: {
256
290
  ```vue
257
291
  <script setup lang="ts">
258
292
  const { posthogPublicKey, posthogHost, posthogDefaults } = useRuntimeConfig().public
293
+
294
+ // Application auth hosts:
259
295
  const { user, activeOrganization } = useTelaApplicationAuth()
260
296
 
297
+ // First-party auth hosts can use this instead:
298
+ // const session = useTelaSession()
299
+ // const organization = useTelaOrganization()
300
+ // const user = session.user
301
+ // const activeOrganization = organization.activeOrganization
302
+ // await organization.getActiveOrganization()
303
+
261
304
  onMounted(async () => {
262
305
  if (!posthogPublicKey || !posthogHost) return
263
306
  await initPosthog(posthogPublicKey, posthogHost, posthogDefaults)
@@ -335,6 +378,45 @@ export default async function resolveWorkspaceSettings(
335
378
  }
336
379
  ```
337
380
 
381
+ ## Optional: Agent API Environment Resolver
382
+
383
+ When default chat mode starts a new Agent API session, `chat-nuxt` can attach `environmentVariables` to the Agent API create payload. Built-in workspace credentials still come from the `credentials` feature. Host apps can add server-only variables by creating `server/chat/resolve-agent-environment.ts`:
384
+
385
+ ```typescript
386
+ import type { H3Event } from 'h3'
387
+
388
+ export default async function resolveAgentEnvironment(
389
+ event: H3Event,
390
+ context: {
391
+ user: { id: string; email: string }
392
+ workspaceId: string
393
+ telaAgentId: string | null
394
+ conversationId: string
395
+ skills: readonly string[]
396
+ },
397
+ ) {
398
+ if (!context.skills.includes('github:meistrari/backoffice/skills/backoffice-admin')) {
399
+ return null
400
+ }
401
+
402
+ return {
403
+ BACKOFFICE_ADMIN_TOOL_URL: 'https://backoffice.example.com/api/admin-chat/tool',
404
+ BACKOFFICE_ADMIN_INVOCATION_GRANT: await mintInvocationGrant({
405
+ userId: context.user.id,
406
+ workspaceId: context.workspaceId,
407
+ conversationId: context.conversationId,
408
+ skills: context.skills,
409
+ }),
410
+ }
411
+ }
412
+ ```
413
+
414
+ The resolver runs on the server only. It is called for new default Agent API sessions, before `POST /v2/chat`. Continued sessions do not receive new environment variables.
415
+
416
+ If the resolver returns the same environment variable name as a workspace credential, the resolver value wins.
417
+
418
+ `chat-nuxt` only transports these variables to Agent API. 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.
419
+
338
420
  ## `<ChatConfigurationModal>`
339
421
 
340
422
  A reusable settings modal (system prompt, context files, Tela workstations, Tela skills, external skills, credentials) that any host app can open from any button. 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.
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
3
  "configKey": "chatNuxt",
4
- "version": "1.5.1",
4
+ "version": "1.7.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -1,7 +1,33 @@
1
1
  import { existsSync, readFileSync, mkdirSync, symlinkSync } from 'node:fs';
2
2
  import { createRequire } from 'node:module';
3
3
  import { join, dirname } from 'node:path';
4
- import { defineNuxtModule, createResolver, addPlugin, addImportsDir, addComponent, addComponentsDir } from 'nuxt/kit';
4
+ import { defineNuxtModule, createResolver, addTemplate, addTypeTemplate, addPlugin, addImportsDir, addComponent, addComponentsDir } from 'nuxt/kit';
5
+
6
+ const agentEnvironmentResolverCandidates = [
7
+ "server/chat/resolve-agent-environment.ts",
8
+ "server/chat/resolve-agent-environment.mts",
9
+ "server/chat/resolve-agent-environment.mjs",
10
+ "server/chat/resolve-agent-environment.js"
11
+ ];
12
+ const stubExtensions$1 = [".ts", ".mjs", ".js"];
13
+ function resolveAgentEnvironmentResolverEntry(srcDir, fallbackResolverBase) {
14
+ for (const relativePath of agentEnvironmentResolverCandidates) {
15
+ const candidate = join(srcDir, relativePath);
16
+ if (existsSync(candidate)) {
17
+ return candidate;
18
+ }
19
+ }
20
+ for (const ext of stubExtensions$1) {
21
+ const candidate = fallbackResolverBase + ext;
22
+ if (existsSync(candidate)) {
23
+ return candidate;
24
+ }
25
+ }
26
+ const attempted = stubExtensions$1.map((ext) => fallbackResolverBase + ext).join(", ");
27
+ throw new Error(
28
+ `[@meistrari/chat-nuxt] Unable to resolve agent-environment stub. Tried: ${attempted}. This indicates a packaging bug - please report it.`
29
+ );
30
+ }
5
31
 
6
32
  const localRequire = createRequire(import.meta.url);
7
33
  const runtimeAliasPackages = [
@@ -153,6 +179,75 @@ const DEFAULT_FEATURES = {
153
179
  generateTitle: false,
154
180
  credentials: false
155
181
  };
182
+ const VUE_COMPONENT_EXTENSIONS = [".vue"];
183
+ function resolveChatAuthMode(runtimeConfig) {
184
+ const publicConfig = runtimeConfig.public;
185
+ const telaAuth = publicConfig?.telaAuth;
186
+ return telaAuth?.application?.enabled ? "application" : "first-party";
187
+ }
188
+ function buildChatAuthTemplate(mode) {
189
+ if (mode === "application") {
190
+ return `
191
+ import { useTelaApplicationAuth } from '#imports'
192
+
193
+ export function useChatAuth() {
194
+ const auth = useTelaApplicationAuth()
195
+
196
+ return {
197
+ user: auth.user,
198
+ activeOrganization: auth.activeOrganization,
199
+ getToken: auth.getToken,
200
+ getAvailableOrganizations: auth.getAvailableOrganizations,
201
+ switchOrganization: auth.switchOrganization,
202
+ }
203
+ }
204
+ `.trimStart();
205
+ }
206
+ return `
207
+ import { useState, useTelaOrganization, useTelaSession, watch } from '#imports'
208
+
209
+ export function useChatAuth() {
210
+ const session = useTelaSession()
211
+ const organization = useTelaOrganization()
212
+ const isHydratingActiveOrganization = useState('chat-nuxt:auth:is-hydrating-active-organization', () => false)
213
+ const hasHydratedActiveOrganization = useState('chat-nuxt:auth:has-hydrated-active-organization', () => false)
214
+
215
+ if (import.meta.client) {
216
+ watch(
217
+ () => session.user.value,
218
+ async (user) => {
219
+ if (!user) {
220
+ hasHydratedActiveOrganization.value = false
221
+ return
222
+ }
223
+
224
+ if (organization.activeOrganization.value || hasHydratedActiveOrganization.value || isHydratingActiveOrganization.value) {
225
+ return
226
+ }
227
+
228
+ isHydratingActiveOrganization.value = true
229
+ try {
230
+ await organization.getActiveOrganization()
231
+ hasHydratedActiveOrganization.value = true
232
+ }
233
+ finally {
234
+ isHydratingActiveOrganization.value = false
235
+ }
236
+ },
237
+ { immediate: true },
238
+ )
239
+ }
240
+
241
+ return {
242
+ user: session.user,
243
+ activeOrganization: organization.activeOrganization,
244
+ getToken: session.getToken,
245
+ getAvailableOrganizations: organization.listOrganizations,
246
+ switchOrganization: organization.setActiveOrganization,
247
+ }
248
+ }
249
+ `.trimStart();
250
+ }
156
251
  const ALWAYS_REQUIRED_KEYS = [
157
252
  "telaApiUrl",
158
253
  "agentApiUrl",
@@ -225,7 +320,7 @@ const module$1 = defineNuxtModule({
225
320
  const hasAuthModule = (nuxt.options.modules ?? []).some(isAuthModuleEntry);
226
321
  if (!hasAuthModule) {
227
322
  throw new Error(
228
- '[@meistrari/chat-nuxt] Missing required module "@meistrari/auth-nuxt". Install and enable it so useTelaApplicationAuth() and event.context.auth are available.'
323
+ '[@meistrari/chat-nuxt] Missing required module "@meistrari/auth-nuxt". Install and enable it so chat auth composables and event.context.auth are available.'
229
324
  );
230
325
  }
231
326
  ensureIconifyPackages(nuxt.options.rootDir);
@@ -237,14 +332,41 @@ const module$1 = defineNuxtModule({
237
332
  nuxt.options.srcDir,
238
333
  join(runtimeDir, "internal/workspace-settings-resolver.stub")
239
334
  );
335
+ const agentEnvironmentResolverEntry = resolveAgentEnvironmentResolverEntry(
336
+ nuxt.options.srcDir,
337
+ join(runtimeDir, "internal/agent-environment-resolver.stub")
338
+ );
240
339
  const telaBuildPath = resolveTelaBuildLayer();
241
340
  const runtimeAliases = resolveRuntimeAliases(telaBuildPath);
341
+ const chatAuthMode = resolveChatAuthMode(nuxt.options.runtimeConfig);
342
+ const chatAuthTemplate = addTemplate({
343
+ filename: "chat-nuxt/auth.mjs",
344
+ getContents: () => buildChatAuthTemplate(chatAuthMode)
345
+ });
346
+ const chatAuthTypeTemplate = addTypeTemplate({
347
+ filename: "chat-nuxt/chat-auth.d.ts",
348
+ src: join(runtimeDir, "types/chat-auth.d.ts")
349
+ });
350
+ addTypeTemplate({
351
+ filename: "chat-nuxt/chat-agent-environment-resolver.d.ts",
352
+ src: join(runtimeDir, "types/chat-agent-environment-resolver.d.ts")
353
+ }, {
354
+ nitro: true,
355
+ nuxt: true
356
+ });
357
+ nuxt.hook("prepare:types", ({ tsConfig }) => {
358
+ tsConfig.compilerOptions ||= {};
359
+ tsConfig.compilerOptions.paths ||= {};
360
+ tsConfig.compilerOptions.paths["#chat-auth"] = [chatAuthTypeTemplate.dst];
361
+ });
242
362
  if (!Array.isArray(nuxt.options.extends)) {
243
363
  nuxt.options.extends = nuxt.options.extends ? [nuxt.options.extends] : [];
244
364
  }
245
365
  nuxt.options.extends.unshift(telaBuildPath);
246
366
  nuxt.options.alias = {
247
367
  ...nuxt.options.alias,
368
+ "#chat-auth": chatAuthTemplate.dst,
369
+ "#chat-agent-environment-resolver": agentEnvironmentResolverEntry,
248
370
  "#chat-workspace-settings-resolver": workspaceSettingsResolverEntry,
249
371
  "#chat-runtime": runtimeDir,
250
372
  "@iconify-json/ph": resolvePackageRoot("@iconify-json/ph")
@@ -296,10 +418,12 @@ const module$1 = defineNuxtModule({
296
418
  priority: 1e3
297
419
  });
298
420
  addComponentsDir({
299
- path: join(runtimeDir, "components")
421
+ path: join(runtimeDir, "components"),
422
+ extensions: VUE_COMPONENT_EXTENSIONS
300
423
  });
301
424
  addComponentsDir({
302
425
  path: join(runtimeDir, "embed/components"),
426
+ extensions: VUE_COMPONENT_EXTENSIONS,
303
427
  pathPrefix: false
304
428
  });
305
429
  nuxt.hook("vite:extendConfig", (config, { isServer }) => {
@@ -349,6 +473,8 @@ export default globalThis.ELK;
349
473
  nitroConfig.scanDirs.push(serverDir);
350
474
  nitroConfig.alias = {
351
475
  ...nitroConfig.alias,
476
+ "#chat-auth": chatAuthTemplate.dst,
477
+ "#chat-agent-environment-resolver": agentEnvironmentResolverEntry,
352
478
  "#chat-runtime": runtimeDir,
353
479
  "#chat-workspace-settings-resolver": workspaceSettingsResolverEntry
354
480
  };
@@ -2,6 +2,7 @@
2
2
  defineProps({
3
3
  conversationId: { type: [String, null], required: false },
4
4
  initialConversationId: { type: [String, null], required: false },
5
+ conversationScope: { type: [String, null], required: false },
5
6
  hideSidebar: { type: Boolean, required: false },
6
7
  loadingMessages: { type: [Array, null], required: false },
7
8
  loadingMessagesMode: { type: [String, null], required: false },
@@ -23,6 +24,7 @@ defineEmits(["update:conversationId", "action"]);
23
24
  :tela-agent-inputs="telaAgentInputs"
24
25
  :conversation-id="conversationId"
25
26
  :initial-conversation-id="initialConversationId"
27
+ :conversation-scope="conversationScope"
26
28
  :hide-sidebar="hideSidebar"
27
29
  :features="features"
28
30
  :loading-messages="loadingMessages"
@@ -38,6 +40,7 @@ defineEmits(["update:conversationId", "action"]);
38
40
  :user="user"
39
41
  :conversation-id="conversationId"
40
42
  :initial-conversation-id="initialConversationId"
43
+ :conversation-scope="conversationScope"
41
44
  :hide-sidebar="hideSidebar"
42
45
  :features="features"
43
46
  :loading-messages="loadingMessages"
@@ -1,11 +1,12 @@
1
1
  <script setup>
2
+ import { useChatAuth } from "#chat-auth";
2
3
  import { parseContentWithFiles } from "../../utils/file";
3
4
  import ChatVaultLink from "./vault-link.vue";
4
5
  const props = defineProps({
5
6
  message: { type: Object, required: true }
6
7
  });
7
8
  const emit = defineEmits(["retry"]);
8
- const { user } = useTelaApplicationAuth();
9
+ const { user } = useChatAuth();
9
10
  const { getMemberByEmail } = useWorkspaceMembers();
10
11
  const embedConfig = useEmbedConfig();
11
12
  const mergedCustomComponents = computed(() => ({
@@ -1,4 +1,5 @@
1
1
  import * as Sentry from "@sentry/nuxt";
2
+ import { useChatAuth } from "#chat-auth";
2
3
  import { exportConversationToMarkdown } from "../utils/export-conversation.js";
3
4
  import { resolveChatStateScope } from "../utils/tela-chat.js";
4
5
  import { useConversationFileActions } from "./useConversationFiles.js";
@@ -150,12 +151,13 @@ function parseReasoningFromPolling(reasoning) {
150
151
  export function useChat() {
151
152
  const chatApi = useChatApi();
152
153
  const embedConfig = useEmbedConfig();
153
- const { user: authUser, activeOrganization } = useTelaApplicationAuth();
154
+ const { user: authUser, activeOrganization } = useChatAuth();
154
155
  const { addFilesToConversation } = useConversationFileActions();
155
156
  const isTelaAgentMode = computed(() => !!embedConfig?.telaAgentId.value);
156
157
  const chatScope = computed(() => resolveChatStateScope(
157
158
  embedConfig?.workspaceId.value || activeOrganization.value?.id,
158
- embedConfig?.telaAgentId.value
159
+ embedConfig?.telaAgentId.value,
160
+ embedConfig?.conversationScope?.value
159
161
  ));
160
162
  const currentConversationBuckets = useState("chat-current-conversation", () => ({}));
161
163
  const messageBuckets = useState("chat-messages", () => ({}));
@@ -1,6 +1,7 @@
1
+ import { useChatAuth } from "#chat-auth";
1
2
  export function useChatApi() {
2
3
  const embedConfig = useEmbedConfig();
3
- const { activeOrganization } = useTelaApplicationAuth();
4
+ const { activeOrganization } = useChatAuth();
4
5
  function buildHeaders(headers) {
5
6
  const mergedHeaders = {
6
7
  ...headers ?? {}
@@ -13,6 +14,10 @@ export function useChatApi() {
13
14
  if (telaAgentId) {
14
15
  mergedHeaders["x-chat-tela-agent-id"] = telaAgentId;
15
16
  }
17
+ const conversationScope = embedConfig?.conversationScope?.value?.trim();
18
+ if (conversationScope) {
19
+ mergedHeaders["x-chat-conversation-scope"] = conversationScope;
20
+ }
16
21
  return Object.keys(mergedHeaders).length > 0 ? mergedHeaders : void 0;
17
22
  }
18
23
  function withChatHeaders(options) {
@@ -1,4 +1,5 @@
1
1
  import * as Sentry from "@sentry/nuxt";
2
+ import { useChatAuth } from "#chat-auth";
2
3
  import { resolveChatStateScope } from "../utils/tela-chat.js";
3
4
  function sortConversationsByUpdatedAt(conversations) {
4
5
  return [...conversations].sort(
@@ -26,7 +27,7 @@ export function mergeFetchedConversations(fetchedConversations, localConversatio
26
27
  export function useConversations() {
27
28
  const chatApi = useChatApi();
28
29
  const embedConfig = useEmbedConfig();
29
- const { activeOrganization } = useTelaApplicationAuth();
30
+ const { activeOrganization } = useChatAuth();
30
31
  const conversationBuckets = useState("conversations", () => ({}));
31
32
  const loadingBuckets = useState("conversations-loading", () => ({}));
32
33
  const errorBuckets = useState("conversations-error", () => ({}));
@@ -37,7 +38,8 @@ export function useConversations() {
37
38
  const isTelaAgentMode = computed(() => !!embedConfig?.telaAgentId.value);
38
39
  const workspaceScope = computed(() => resolveChatStateScope(
39
40
  embedConfig?.workspaceId.value || activeOrganization.value?.id,
40
- embedConfig?.telaAgentId.value
41
+ embedConfig?.telaAgentId.value,
42
+ embedConfig?.conversationScope?.value
41
43
  ));
42
44
  const conversations = computed({
43
45
  get: () => conversationBuckets.value[workspaceScope.value] ?? [],
@@ -229,6 +231,7 @@ export function useConversations() {
229
231
  appliedSettingsSnapshot: cloneAppliedSettingsSnapshot(updated.appliedSettingsSnapshot),
230
232
  telaAgentId: updated.telaAgentId,
231
233
  createdBy: updated.createdBy,
234
+ conversationScope: updated.conversationScope,
232
235
  createdAt: updated.createdAt,
233
236
  updatedAt: updated.updatedAt
234
237
  };
@@ -6,6 +6,7 @@ type ConfiguredTelaAgentInputs = DeepReadonly<TelaAgentExecutionInput[]> | null
6
6
  export type EmbedConfig = {
7
7
  workspaceId: Ref<string>;
8
8
  telaAgentId: Ref<string | null>;
9
+ conversationScope: Ref<string | null>;
9
10
  telaAgentInputs: Ref<ConfiguredTelaAgentInputs>;
10
11
  workspaceSettings: Ref<DeepReadonly<WorkspaceSettings> | WorkspaceSettings | null | undefined>;
11
12
  hideSidebar: Ref<boolean>;
@@ -17,6 +18,7 @@ export type EmbedConfig = {
17
18
  type EmbedConfigInput = {
18
19
  workspaceId: MaybeRefOrGetter<string>;
19
20
  telaAgentId?: MaybeRefOrGetter<string | null | undefined>;
21
+ conversationScope?: MaybeRefOrGetter<string | null | undefined>;
20
22
  telaAgentInputs?: MaybeRefOrGetter<ConfiguredTelaAgentInputs>;
21
23
  workspaceSettings?: MaybeRefOrGetter<DeepReadonly<WorkspaceSettings> | WorkspaceSettings | null | undefined>;
22
24
  hideSidebar?: MaybeRefOrGetter<boolean | undefined>;
@@ -1,3 +1,4 @@
1
+ import { normalizeConversationScope } from "../utils/tela-chat.js";
1
2
  const EMBED_CONFIG_KEY = "embed-config";
2
3
  function useGlobalCustomComponentsState() {
3
4
  const nuxtApp = useNuxtApp();
@@ -9,6 +10,7 @@ function useGlobalEmbedConfigState() {
9
10
  provided: useState("chat-embed-config-provided", () => false),
10
11
  workspaceId: useState("chat-embed-config-workspace-id", () => ""),
11
12
  telaAgentId: useState("chat-embed-config-tela-agent-id", () => null),
13
+ conversationScope: useState("chat-embed-config-conversation-scope", () => null),
12
14
  telaAgentInputs: useState("chat-embed-config-tela-agent-inputs", () => void 0),
13
15
  workspaceSettings: useState("chat-embed-config-workspace-settings", () => void 0),
14
16
  hideSidebar: useState("chat-embed-config-hide-sidebar", () => void 0),
@@ -22,6 +24,7 @@ export function provideEmbedConfig(input, options = {}) {
22
24
  const config = {
23
25
  workspaceId: computed(() => toValue(input.workspaceId)),
24
26
  telaAgentId: computed(() => toValue(input.telaAgentId) ?? null),
27
+ conversationScope: computed(() => normalizeConversationScope(toValue(input.conversationScope))),
25
28
  telaAgentInputs: computed(() => toValue(input.telaAgentInputs)),
26
29
  workspaceSettings: computed(() => toValue(input.workspaceSettings)),
27
30
  hideSidebar: computed(() => toValue(input.hideSidebar) ?? true),
@@ -36,6 +39,7 @@ export function provideEmbedConfig(input, options = {}) {
36
39
  globalConfig.provided.value = true;
37
40
  globalConfig.workspaceId.value = config.workspaceId.value;
38
41
  globalConfig.telaAgentId.value = config.telaAgentId.value;
42
+ globalConfig.conversationScope.value = config.conversationScope.value;
39
43
  globalConfig.telaAgentInputs.value = config.telaAgentInputs.value;
40
44
  globalConfig.workspaceSettings.value = config.workspaceSettings.value;
41
45
  globalConfig.hideSidebar.value = config.hideSidebar.value;
@@ -57,6 +61,7 @@ export function useEmbedConfig() {
57
61
  return {
58
62
  workspaceId: computed(() => globalConfig.workspaceId.value),
59
63
  telaAgentId: computed(() => globalConfig.telaAgentId.value),
64
+ conversationScope: computed(() => globalConfig.conversationScope.value),
60
65
  telaAgentInputs: computed(() => globalConfig.telaAgentInputs.value),
61
66
  workspaceSettings: computed(() => globalConfig.workspaceSettings.value),
62
67
  hideSidebar: computed(() => globalConfig.hideSidebar.value ?? true),
@@ -1,7 +1,8 @@
1
1
  import * as Sentry from "@sentry/nuxt";
2
+ import { useChatAuth } from "#chat-auth";
2
3
  export function useGitHubSkills() {
3
4
  const config = useRuntimeConfig();
4
- const { activeOrganization } = useTelaApplicationAuth();
5
+ const { activeOrganization } = useChatAuth();
5
6
  const { settings, updateSettings } = useWorkspaceSettings();
6
7
  const connection = useState("github-skills-connection", () => ({
7
8
  connected: false,
@@ -1,5 +1,6 @@
1
+ import { useChatAuth } from "#chat-auth";
1
2
  export function useWorkspaceExternalSkills(currentExternalSkills, searchQuery) {
2
- const { user } = useTelaApplicationAuth();
3
+ const { user } = useChatAuth();
3
4
  const { connection: skillsConnection, fetchConnection: fetchGitHubConnection, connect: connectGitHub } = useGitHubSkills();
4
5
  const pendingSkills = ref([]);
5
6
  const removedRefs = ref([]);
@@ -1,5 +1,6 @@
1
+ import { useChatAuth } from "#chat-auth";
1
2
  export function useWorkspaceMembers() {
2
- const { activeOrganization } = useTelaApplicationAuth();
3
+ const { activeOrganization } = useChatAuth();
3
4
  const members = computed(() => activeOrganization.value?.members ?? []);
4
5
  const membersMap = computed(() => {
5
6
  const map = /* @__PURE__ */ new Map();
@@ -1,4 +1,5 @@
1
1
  import * as Sentry from "@sentry/nuxt";
2
+ import { useChatAuth } from "#chat-auth";
2
3
  function isNullableArray(value) {
3
4
  return value === null || Array.isArray(value);
4
5
  }
@@ -19,7 +20,7 @@ function assertWorkspaceSettingsResponse(value) {
19
20
  export function useWorkspaceSettings() {
20
21
  const chatApi = useChatApi();
21
22
  const embedConfig = useEmbedConfig();
22
- const { activeOrganization } = useTelaApplicationAuth();
23
+ const { activeOrganization } = useChatAuth();
23
24
  const workspaceScope = computed(() => embedConfig?.workspaceId.value.trim() || activeOrganization.value?.id?.trim() || "default");
24
25
  const settingsBuckets = useState("workspace-settings", () => ({}));
25
26
  const loadingBuckets = useState("workspace-settings-loading", () => ({}));
@@ -1,5 +1,6 @@
1
+ import { useChatAuth } from "#chat-auth";
1
2
  export function useWorkspaces() {
2
- const { getAvailableOrganizations } = useTelaApplicationAuth();
3
+ const { getAvailableOrganizations } = useChatAuth();
3
4
  const { data: workspaces, status, refresh: refreshWorkspaces } = useAsyncData(
4
5
  "workspaces",
5
6
  () => getAvailableOrganizations(),
@@ -1,11 +1,13 @@
1
1
  <script setup>
2
+ import { useChatAuth } from "#chat-auth";
2
3
  import { provideEmbedConfig, useEmbedConfig } from "../../composables/useEmbedConfig";
3
4
  import { provideChatAction } from "../../composables/useChatAction";
4
- import { normalizeTelaAgentId } from "../../utils/tela-chat";
5
+ import { normalizeConversationScope, normalizeTelaAgentId, resolveConversationScopeKeySegment } from "../../utils/tela-chat";
5
6
  import ChatEmbedInner from "./ChatEmbedInner.vue";
6
7
  const props = defineProps({
7
8
  conversationId: { type: [String, null], required: false },
8
9
  initialConversationId: { type: [String, null], required: false },
10
+ conversationScope: { type: [String, null], required: false },
9
11
  hideSidebar: { type: Boolean, required: false },
10
12
  loadingMessages: { type: [Array, null], required: false },
11
13
  loadingMessagesMode: { type: [String, null], required: false },
@@ -19,13 +21,15 @@ const props = defineProps({
19
21
  });
20
22
  const emit = defineEmits(["update:conversationId", "action"]);
21
23
  const parentEmbedConfig = useEmbedConfig();
22
- const { activeOrganization } = useTelaApplicationAuth();
24
+ const { activeOrganization } = useChatAuth();
23
25
  const workspaceId = computed(() => activeOrganization.value?.id?.trim() ?? "");
24
26
  const normalizedTelaAgentId = computed(() => normalizeTelaAgentId(props.telaAgentId));
27
+ const normalizedConversationScope = computed(() => normalizeConversationScope(props.conversationScope));
25
28
  const ignoredPropsWarningKey = ref(null);
26
29
  provideEmbedConfig({
27
30
  workspaceId,
28
31
  telaAgentId: normalizedTelaAgentId,
32
+ conversationScope: normalizedConversationScope,
29
33
  telaAgentInputs: computed(() => props.telaAgentInputs),
30
34
  workspaceSettings: computed(() => props.workspaceSettings),
31
35
  hideSidebar: computed(() => props.hideSidebar),
@@ -61,7 +65,7 @@ provideChatAction((payload) => {
61
65
  <template>
62
66
  <ChatEmbedInner
63
67
  v-if="workspaceId"
64
- :key="`${workspaceId}:${normalizedTelaAgentId ?? 'default-chat'}`"
68
+ :key="`${workspaceId}:${normalizedTelaAgentId ?? 'default-chat'}:scope:${resolveConversationScopeKeySegment(normalizedConversationScope)}`"
65
69
  :conversation-id="conversationId"
66
70
  :initial-conversation-id="initialConversationId"
67
71
  :hide-sidebar="hideSidebar"
@@ -1,4 +1,5 @@
1
1
  <script setup>
2
+ import { useChatAuth } from "#chat-auth";
2
3
  import { exportConversationToMarkdown } from "../../utils/export-conversation";
3
4
  import { conversationListSkeletonRows } from "../../utils/conversation-list-skeleton";
4
5
  import {
@@ -16,7 +17,7 @@ const props = defineProps({
16
17
  const emit = defineEmits(["update:conversationId"]);
17
18
  const chatApi = useChatApi();
18
19
  const embedConfig = useEmbedConfig();
19
- const { user: authUser } = useTelaApplicationAuth();
20
+ const { user: authUser } = useChatAuth();
20
21
  const { getMember } = useWorkspaceMembers();
21
22
  const statusToast = useStatusToast();
22
23
  const { conversations, loading: conversationsLoading, fetchConversations, createConversation, deleteConversation, renameConversation, duplicateConversation, updateConversationInList } = useConversations();
@@ -0,0 +1,2 @@
1
+ declare const _default: null;
2
+ export default _default;
@@ -0,0 +1 @@
1
+ export default null;
@@ -30,6 +30,7 @@ export default defineEventHandler(async (event) => {
30
30
  title: `${original.title} (copy)`,
31
31
  createdBy: context.user.email,
32
32
  telaAgentId: original.telaAgentId,
33
+ conversationScope: original.conversationScope,
33
34
  threadSessionId: null,
34
35
  model: original.telaAgentId ? null : original.model,
35
36
  appliedSettingsAt: trustedSettings ? getWorkspaceSettingsUpdatedAt(trustedSettings) : null,
@@ -90,8 +90,12 @@ export default defineEventHandler(async (event) => {
90
90
  const environmentVariables = await resolveDefaultAgentEnvironmentVariables(
91
91
  event,
92
92
  context,
93
- { conversationId, messageId },
94
- "Failed to resolve workspace credentials on retry, proceeding without env vars"
93
+ {
94
+ conversationId,
95
+ skills: defaultAgentTurn.createPayload.skills ?? [],
96
+ logContext: { conversationId, messageId },
97
+ credentialsFailureMessage: "Failed to resolve workspace credentials on retry, proceeding without env vars"
98
+ }
95
99
  );
96
100
  const result = await createChatAgentSession(token, withEnvironmentVariables(defaultAgentTurn.createPayload, environmentVariables));
97
101
  if (result.success) {
@@ -115,8 +115,12 @@ export default defineEventHandler(async (event) => {
115
115
  const environmentVariables = await resolveDefaultAgentEnvironmentVariables(
116
116
  event,
117
117
  context,
118
- { conversationId },
119
- "Failed to resolve workspace credentials, proceeding without env vars"
118
+ {
119
+ conversationId,
120
+ skills: defaultAgentTurn.createPayload.skills ?? [],
121
+ logContext: { conversationId },
122
+ credentialsFailureMessage: "Failed to resolve workspace credentials, proceeding without env vars"
123
+ }
120
124
  );
121
125
  createChatAgentSession(token, withEnvironmentVariables(defaultAgentTurn.createPayload, environmentVariables)).then(async (result) => {
122
126
  if (result.success) {