@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.
- package/README.md +82 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +129 -3
- package/dist/runtime/components/MeistrariChatEmbed.vue +3 -0
- package/dist/runtime/components/chat/message-bubble.vue +2 -1
- package/dist/runtime/composables/useChat.js +4 -2
- package/dist/runtime/composables/useChatApi.js +6 -1
- package/dist/runtime/composables/useConversations.js +5 -2
- package/dist/runtime/composables/useEmbedConfig.d.ts +2 -0
- package/dist/runtime/composables/useEmbedConfig.js +5 -0
- package/dist/runtime/composables/useGitHubSkills.js +2 -1
- package/dist/runtime/composables/useWorkspaceExternalSkills.js +2 -1
- package/dist/runtime/composables/useWorkspaceMembers.js +2 -1
- package/dist/runtime/composables/useWorkspaceSettings.js +2 -1
- package/dist/runtime/composables/useWorkspaces.js +2 -1
- package/dist/runtime/embed/components/ChatEmbed.vue +7 -3
- package/dist/runtime/embed/components/ChatEmbedInner.vue +2 -1
- package/dist/runtime/internal/agent-environment-resolver.stub.d.ts +2 -0
- package/dist/runtime/internal/agent-environment-resolver.stub.js +1 -0
- package/dist/runtime/server/api/conversations/[id]/duplicate.post.js +1 -0
- package/dist/runtime/server/api/conversations/[id]/messages/[messageId]/retry.post.js +6 -2
- package/dist/runtime/server/api/conversations/[id]/messages/index.post.js +6 -2
- package/dist/runtime/server/api/conversations/index.post.js +1 -0
- package/dist/runtime/server/db/schema/conversations.d.ts +17 -0
- package/dist/runtime/server/db/schema/conversations.js +1 -0
- package/dist/runtime/server/utils/agent-api.js +4 -3
- package/dist/runtime/server/utils/agent-environment.d.ts +8 -0
- package/dist/runtime/server/utils/agent-environment.js +34 -0
- package/dist/runtime/server/utils/auth-token.d.ts +2 -0
- package/dist/runtime/server/utils/auth-token.js +21 -0
- package/dist/runtime/server/utils/chat-context.d.ts +2 -0
- package/dist/runtime/server/utils/chat-context.js +15 -1
- package/dist/runtime/server/utils/conversation-agent-turn.d.ts +6 -1
- package/dist/runtime/server/utils/conversation-agent-turn.js +27 -8
- package/dist/runtime/server/utils/conversation-scope.js +2 -1
- package/dist/runtime/server/utils/tela-api.js +2 -1
- package/dist/runtime/server/utils/workspace.js +3 -1
- package/dist/runtime/types/chat-agent-environment-resolver.d.ts +4 -0
- package/dist/runtime/types/chat-auth.d.ts +35 -0
- package/dist/runtime/types/embed.d.ts +19 -0
- package/dist/runtime/utils/tela-chat.d.ts +3 -1
- package/dist/runtime/utils/tela-chat.js +11 -2
- package/drizzle/0015_illegal_blindfold.sql +1 -0
- package/drizzle/meta/0015_snapshot.json +738 -0
- package/drizzle/meta/_journal.json +7 -0
- 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
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
|
|
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 } =
|
|
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 } =
|
|
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 } =
|
|
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 } =
|
|
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 } =
|
|
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 } =
|
|
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 } =
|
|
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 } =
|
|
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 } =
|
|
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 } =
|
|
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 } =
|
|
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 @@
|
|
|
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
|
-
{
|
|
94
|
-
|
|
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
|
-
{
|
|
119
|
-
|
|
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) {
|