@meistrari/chat-nuxt 1.5.0 → 1.5.1

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/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
3
  "configKey": "chatNuxt",
4
- "version": "1.5.0",
4
+ "version": "1.5.1",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -1,7 +1,7 @@
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, addImportsDir, addComponent, addComponentsDir } from 'nuxt/kit';
4
+ import { defineNuxtModule, createResolver, addPlugin, addImportsDir, addComponent, addComponentsDir } from 'nuxt/kit';
5
5
 
6
6
  const localRequire = createRequire(import.meta.url);
7
7
  const runtimeAliasPackages = [
@@ -277,6 +277,17 @@ const module$1 = defineNuxtModule({
277
277
  features
278
278
  };
279
279
  validateRuntimeConfig(rc, options.validateConfig ?? false, features);
280
+ nuxt.options.css = nuxt.options.css || [];
281
+ for (const css of [
282
+ "markstream-vue/index.css",
283
+ join(runtimeDir, "assets/css/markstream.css"),
284
+ join(runtimeDir, "assets/css/code-theme.css")
285
+ ]) {
286
+ if (!nuxt.options.css.includes(css)) {
287
+ nuxt.options.css.push(css);
288
+ }
289
+ }
290
+ addPlugin(join(runtimeDir, "plugins/markstream"));
280
291
  addImportsDir(join(runtimeDir, "composables"));
281
292
  addImportsDir(join(runtimeDir, "utils"));
282
293
  addComponent({
@@ -14,7 +14,7 @@ type __VLS_Props = {
14
14
  conversationFiles?: ConversationFile[];
15
15
  workspaceSettings?: DeepReadonly<WorkspaceSettings> | null;
16
16
  allowModelSelection?: boolean;
17
- agentInputSchema?: DeepReadonly<TelaAgentInputVariable[]> | null;
17
+ agentInputSchema?: readonly TelaAgentInputVariable[] | null;
18
18
  agentInputSchemaLoading?: boolean;
19
19
  showModelSelector?: boolean;
20
20
  showCancelButton?: boolean;
@@ -15,7 +15,7 @@ const props = defineProps({
15
15
  conversationFiles: { type: Array, required: false },
16
16
  workspaceSettings: { type: null, required: false },
17
17
  allowModelSelection: { type: Boolean, required: false },
18
- agentInputSchema: { type: null, required: false },
18
+ agentInputSchema: { type: [Array, null], required: false },
19
19
  agentInputSchemaLoading: { type: Boolean, required: false },
20
20
  showModelSelector: { type: Boolean, required: false },
21
21
  showCancelButton: { type: Boolean, required: false }
@@ -14,7 +14,7 @@ type __VLS_Props = {
14
14
  conversationFiles?: ConversationFile[];
15
15
  workspaceSettings?: DeepReadonly<WorkspaceSettings> | null;
16
16
  allowModelSelection?: boolean;
17
- agentInputSchema?: DeepReadonly<TelaAgentInputVariable[]> | null;
17
+ agentInputSchema?: readonly TelaAgentInputVariable[] | null;
18
18
  agentInputSchemaLoading?: boolean;
19
19
  showModelSelector?: boolean;
20
20
  showCancelButton?: boolean;
@@ -1,4 +1,21 @@
1
1
  import * as Sentry from "@sentry/nuxt";
2
+ function isNullableArray(value) {
3
+ return value === null || Array.isArray(value);
4
+ }
5
+ function assertWorkspaceSettingsResponse(value) {
6
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
7
+ throw new Error("Invalid workspace settings response");
8
+ }
9
+ const settings = value;
10
+ const hasValidWorkspaceId = typeof settings.workspaceId === "string" && settings.workspaceId.length > 0;
11
+ const hasValidSystemMessage = settings.systemMessage === null || typeof settings.systemMessage === "string";
12
+ const hasValidUpdatedAt = settings.updatedAt instanceof Date || typeof settings.updatedAt === "string" && settings.updatedAt.length > 0;
13
+ const hasValidCollections = isNullableArray(settings.contextFiles) && isNullableArray(settings.canvasTools) && isNullableArray(settings.knowledgeSources) && isNullableArray(settings.externalSkills);
14
+ if (!hasValidWorkspaceId || !hasValidSystemMessage || !hasValidUpdatedAt || !hasValidCollections) {
15
+ throw new Error("Invalid workspace settings response");
16
+ }
17
+ return value;
18
+ }
2
19
  export function useWorkspaceSettings() {
3
20
  const chatApi = useChatApi();
4
21
  const embedConfig = useEmbedConfig();
@@ -65,12 +82,14 @@ export function useWorkspaceSettings() {
65
82
  if (hasWorkspaceSettingsOverride.value) {
66
83
  return settings.value;
67
84
  } else if (embedConfig !== null) {
68
- data = await $fetch(
69
- chatApi.path("/workspace/settings"),
70
- chatApi.withChatHeaders()
85
+ data = assertWorkspaceSettingsResponse(
86
+ await $fetch(
87
+ chatApi.path("/workspace/settings"),
88
+ chatApi.withChatHeaders()
89
+ )
71
90
  );
72
91
  } else {
73
- data = await $fetch("/api/workspace/settings");
92
+ data = assertWorkspaceSettingsResponse(await $fetch("/api/workspace/settings"));
74
93
  }
75
94
  if (import.meta.dev && embedConfig !== null && currentSettings) {
76
95
  const hydratedSettings = {
@@ -109,7 +128,7 @@ export function useWorkspaceSettings() {
109
128
  try {
110
129
  const path = embedConfig !== null ? chatApi.path("/workspace/settings") : "/api/workspace/settings";
111
130
  const options = embedConfig !== null ? chatApi.withChatHeaders({ method: "PATCH", body: updates }) : { method: "PATCH", body: updates };
112
- const data = await $fetch(path, options);
131
+ const data = assertWorkspaceSettingsResponse(await $fetch(path, options));
113
132
  settings.value = data;
114
133
  return data;
115
134
  } catch (e) {
@@ -34,6 +34,7 @@ const effectiveWorkspaceSettings = computed(() => {
34
34
  return embedConfig?.workspaceSettings.value !== void 0 ? embedConfig.workspaceSettings.value : workspaceSettingsState.value;
35
35
  });
36
36
  const { closePanel: closeFilesPanel } = useConversationFilesPanel();
37
+ const { isOpen: isPreviewPanelOpen, panelWidth: previewPanelWidth, closePreview } = useFilePreviewPanel();
37
38
  const activeConversationId = ref(
38
39
  normalizeConversationId(props.conversationId) ?? normalizeConversationId(props.initialConversationId)
39
40
  );
@@ -119,6 +120,7 @@ function resetConversation(shouldEmit = true) {
119
120
  clearConversation();
120
121
  activeTab.value = "chat";
121
122
  closeFilesPanel();
123
+ closePreview();
122
124
  if (shouldEmit) {
123
125
  updateConversationId(null);
124
126
  } else {
@@ -130,6 +132,9 @@ async function openConversation(nextConversationId) {
130
132
  if (!normalizedConversationId) {
131
133
  return;
132
134
  }
135
+ if (activeConversationId.value !== normalizedConversationId) {
136
+ closePreview();
137
+ }
133
138
  updateConversationId(normalizedConversationId);
134
139
  await ensureConversationLoaded(normalizedConversationId);
135
140
  }
@@ -150,6 +155,7 @@ watch(() => props.conversationId, async (nextConversationId) => {
150
155
  return;
151
156
  }
152
157
  syncConversationId(normalizedConversationId);
158
+ closePreview();
153
159
  await ensureConversationLoaded(normalizedConversationId);
154
160
  });
155
161
  onMounted(async () => {
@@ -640,6 +646,14 @@ async function handleDelete() {
640
646
  </div>
641
647
  </TelaModal>
642
648
  </div>
649
+
650
+ <div
651
+ v-if="isPreviewPanelOpen"
652
+ h-full flex-shrink-0 pt-64px
653
+ :style="{ width: `${previewPanelWidth}px` }"
654
+ >
655
+ <FilePreviewPanel />
656
+ </div>
643
657
  </div>
644
658
  </template>
645
659
 
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { defineEventHandler, readBody } from "h3";
2
+ import { resolveChatContext } from "#chat-runtime/server/utils/chat-context";
3
+ import { persistWorkspaceSettingsUpdate } from "#chat-runtime/server/utils/workspace-settings-update";
4
+ export default defineEventHandler(async (event) => {
5
+ const context = resolveChatContext(event);
6
+ const body = await readBody(event);
7
+ return persistWorkspaceSettingsUpdate(context.workspaceId, context.user, body);
8
+ });
@@ -1,87 +1,8 @@
1
- import { createError, defineEventHandler, readBody } from "h3";
2
- import { eq, and, inArray } from "drizzle-orm";
3
- import { useDb, schema } from "#chat-runtime/server/db";
1
+ import { defineEventHandler, readBody } from "h3";
4
2
  import { requireUser } from "#chat-runtime/server/utils/auth";
5
- import { rowToExternalSkill } from "#chat-runtime/server/utils/external-skills";
6
- import { logger } from "#chat-runtime/server/utils/logger";
3
+ import { persistWorkspaceSettingsUpdate } from "#chat-runtime/server/utils/workspace-settings-update";
7
4
  export default defineEventHandler(async (event) => {
8
5
  const session = requireUser(event);
9
- const db = useDb();
10
6
  const body = await readBody(event);
11
- const hasSystemMessage = body.systemMessage !== void 0;
12
- const hasContextFiles = body.contextFiles !== void 0;
13
- const hasCanvasTools = body.canvasTools !== void 0;
14
- const hasKnowledgeSources = body.knowledgeSources !== void 0;
15
- const hasExternalSkills = body.externalSkills !== void 0;
16
- if (!hasSystemMessage && !hasContextFiles && !hasCanvasTools && !hasKnowledgeSources && !hasExternalSkills) {
17
- throw createError({
18
- statusCode: 400,
19
- statusMessage: "At least one field is required to update"
20
- });
21
- }
22
- const updateData = {
23
- updatedAt: /* @__PURE__ */ new Date()
24
- };
25
- if (hasSystemMessage) {
26
- updateData.systemMessage = body.systemMessage?.trim() || null;
27
- }
28
- if (hasContextFiles) {
29
- updateData.contextFiles = body.contextFiles && body.contextFiles.length > 0 ? body.contextFiles : null;
30
- }
31
- if (hasCanvasTools) {
32
- updateData.canvasTools = body.canvasTools && body.canvasTools.length > 0 ? body.canvasTools : null;
33
- }
34
- if (hasKnowledgeSources) {
35
- updateData.knowledgeSources = body.knowledgeSources && body.knowledgeSources.length > 0 ? body.knowledgeSources : null;
36
- }
37
- const [existing] = await db.select().from(schema.workspaceSettings).where(eq(schema.workspaceSettings.workspaceId, session.workspace.id));
38
- if (hasExternalSkills) {
39
- const existingSkillRows = await db.select().from(schema.externalSkills).where(eq(schema.externalSkills.workspaceId, session.workspace.id));
40
- const existingRefs = new Set(existingSkillRows.map((s) => s.ref));
41
- const newSkills = body.externalSkills ?? [];
42
- const newRefs = new Set(newSkills.map((s) => s.ref));
43
- const refsToDelete = existingSkillRows.filter((s) => !newRefs.has(s.ref)).map((s) => s.ref);
44
- if (refsToDelete.length > 0) {
45
- await db.delete(schema.externalSkills).where(
46
- and(
47
- eq(schema.externalSkills.workspaceId, session.workspace.id),
48
- inArray(schema.externalSkills.ref, refsToDelete)
49
- )
50
- );
51
- }
52
- const skillsToInsert = newSkills.filter((s) => !existingRefs.has(s.ref)).map((skill) => ({
53
- workspaceId: session.workspace.id,
54
- ref: skill.ref,
55
- name: skill.name,
56
- description: skill.description,
57
- runtime: skill.runtime,
58
- allowedTools: [...skill.allowedTools],
59
- isPublic: skill.isPublic,
60
- addedByUserId: skill.addedBy?.userId || session.user.id,
61
- addedByUsername: skill.addedBy?.username || session.user.name || "",
62
- addedAt: skill.addedAt ? new Date(skill.addedAt) : /* @__PURE__ */ new Date()
63
- }));
64
- if (skillsToInsert.length > 0) {
65
- await db.insert(schema.externalSkills).values(skillsToInsert);
66
- }
67
- }
68
- logger.info({ workspaceId: session.workspace.id, fields: Object.keys(updateData) }, "Workspace settings updating");
69
- let settings;
70
- if (existing) {
71
- const [updated] = await db.update(schema.workspaceSettings).set(updateData).where(eq(schema.workspaceSettings.workspaceId, session.workspace.id)).returning();
72
- settings = updated;
73
- } else {
74
- const [created] = await db.insert(schema.workspaceSettings).values({
75
- workspaceId: session.workspace.id,
76
- ...updateData
77
- }).returning();
78
- settings = created;
79
- }
80
- const skillRows = await db.select().from(schema.externalSkills).where(eq(schema.externalSkills.workspaceId, session.workspace.id));
81
- const externalSkills = skillRows.map(rowToExternalSkill);
82
- logger.info({ workspaceId: session.workspace.id, externalSkillsCount: externalSkills.length }, "Workspace settings updated");
83
- return {
84
- ...settings,
85
- externalSkills: externalSkills.length > 0 ? externalSkills : null
86
- };
7
+ return persistWorkspaceSettingsUpdate(session.workspace.id, session.user, body);
87
8
  });
@@ -0,0 +1,16 @@
1
+ import { type ContextFile, type ExternalSkill } from '#chat-runtime/server/db';
2
+ import type { CanvasTool } from '#chat-runtime/types/agent';
3
+ import type { KnowledgeSource } from '#chat-runtime/types/chat';
4
+ export type WorkspaceSettingsPatchBody = {
5
+ systemMessage?: string | null;
6
+ contextFiles?: ContextFile[] | null;
7
+ canvasTools?: CanvasTool[] | null;
8
+ knowledgeSources?: KnowledgeSource[] | null;
9
+ externalSkills?: ExternalSkill[] | null;
10
+ };
11
+ type WorkspaceSettingsUser = {
12
+ id: string;
13
+ name?: string | null;
14
+ };
15
+ export declare function persistWorkspaceSettingsUpdate(workspaceId: string, user: WorkspaceSettingsUser, body: WorkspaceSettingsPatchBody): Promise<any>;
16
+ export {};
@@ -0,0 +1,84 @@
1
+ import { createError } from "h3";
2
+ import { and, eq, inArray } from "drizzle-orm";
3
+ import { schema, useDb } from "#chat-runtime/server/db";
4
+ import { rowToExternalSkill } from "#chat-runtime/server/utils/external-skills";
5
+ import { logger } from "#chat-runtime/server/utils/logger";
6
+ export async function persistWorkspaceSettingsUpdate(workspaceId, user, body) {
7
+ const db = useDb();
8
+ const hasSystemMessage = body.systemMessage !== void 0;
9
+ const hasContextFiles = body.contextFiles !== void 0;
10
+ const hasCanvasTools = body.canvasTools !== void 0;
11
+ const hasKnowledgeSources = body.knowledgeSources !== void 0;
12
+ const hasExternalSkills = body.externalSkills !== void 0;
13
+ if (!hasSystemMessage && !hasContextFiles && !hasCanvasTools && !hasKnowledgeSources && !hasExternalSkills) {
14
+ throw createError({
15
+ statusCode: 400,
16
+ statusMessage: "At least one field is required to update"
17
+ });
18
+ }
19
+ const updateData = {
20
+ updatedAt: /* @__PURE__ */ new Date()
21
+ };
22
+ if (hasSystemMessage) {
23
+ updateData.systemMessage = body.systemMessage?.trim() || null;
24
+ }
25
+ if (hasContextFiles) {
26
+ updateData.contextFiles = body.contextFiles && body.contextFiles.length > 0 ? body.contextFiles : null;
27
+ }
28
+ if (hasCanvasTools) {
29
+ updateData.canvasTools = body.canvasTools && body.canvasTools.length > 0 ? body.canvasTools : null;
30
+ }
31
+ if (hasKnowledgeSources) {
32
+ updateData.knowledgeSources = body.knowledgeSources && body.knowledgeSources.length > 0 ? body.knowledgeSources : null;
33
+ }
34
+ const [existing] = await db.select().from(schema.workspaceSettings).where(eq(schema.workspaceSettings.workspaceId, workspaceId));
35
+ if (hasExternalSkills) {
36
+ const existingSkillRows = await db.select().from(schema.externalSkills).where(eq(schema.externalSkills.workspaceId, workspaceId));
37
+ const existingRefs = new Set(existingSkillRows.map((s) => s.ref));
38
+ const newSkills = body.externalSkills ?? [];
39
+ const newRefs = new Set(newSkills.map((s) => s.ref));
40
+ const refsToDelete = existingSkillRows.filter((s) => !newRefs.has(s.ref)).map((s) => s.ref);
41
+ if (refsToDelete.length > 0) {
42
+ await db.delete(schema.externalSkills).where(
43
+ and(
44
+ eq(schema.externalSkills.workspaceId, workspaceId),
45
+ inArray(schema.externalSkills.ref, refsToDelete)
46
+ )
47
+ );
48
+ }
49
+ const skillsToInsert = newSkills.filter((s) => !existingRefs.has(s.ref)).map((skill) => ({
50
+ workspaceId,
51
+ ref: skill.ref,
52
+ name: skill.name,
53
+ description: skill.description,
54
+ runtime: skill.runtime,
55
+ allowedTools: [...skill.allowedTools],
56
+ isPublic: skill.isPublic,
57
+ addedByUserId: skill.addedBy?.userId || user.id,
58
+ addedByUsername: skill.addedBy?.username || user.name || "",
59
+ addedAt: skill.addedAt ? new Date(skill.addedAt) : /* @__PURE__ */ new Date()
60
+ }));
61
+ if (skillsToInsert.length > 0) {
62
+ await db.insert(schema.externalSkills).values(skillsToInsert);
63
+ }
64
+ }
65
+ logger.info({ workspaceId, fields: Object.keys(updateData) }, "Workspace settings updating");
66
+ let settings;
67
+ if (existing) {
68
+ const [updated] = await db.update(schema.workspaceSettings).set(updateData).where(eq(schema.workspaceSettings.workspaceId, workspaceId)).returning();
69
+ settings = updated;
70
+ } else {
71
+ const [created] = await db.insert(schema.workspaceSettings).values({
72
+ workspaceId,
73
+ ...updateData
74
+ }).returning();
75
+ settings = created;
76
+ }
77
+ const skillRows = await db.select().from(schema.externalSkills).where(eq(schema.externalSkills.workspaceId, workspaceId));
78
+ const externalSkills = skillRows.map(rowToExternalSkill);
79
+ logger.info({ workspaceId, externalSkillsCount: externalSkills.length }, "Workspace settings updated");
80
+ return {
81
+ ...settings,
82
+ externalSkills: externalSkills.length > 0 ? externalSkills : null
83
+ };
84
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {