@meistrari/chat-nuxt 1.2.3 → 1.4.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 +70 -38
- package/dist/module.d.mts +24 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +38 -29
- package/dist/runtime/components/MeistrariChatEmbed.d.vue.ts +9 -2
- package/dist/runtime/components/MeistrariChatEmbed.vue +11 -4
- package/dist/runtime/components/MeistrariChatEmbed.vue.d.ts +9 -2
- package/dist/runtime/components/app-markdown-render.d.vue.ts +3 -1
- package/dist/runtime/components/app-markdown-render.vue +15 -4
- package/dist/runtime/components/app-markdown-render.vue.d.ts +3 -1
- package/dist/runtime/components/chat/message-bubble.vue +10 -2
- package/dist/runtime/components/chat/thinking-indicator.vue +28 -17
- package/dist/runtime/composables/useChat.js +8 -1
- package/dist/runtime/composables/useChatAction.d.ts +10 -0
- package/dist/runtime/composables/useChatAction.js +12 -0
- package/dist/runtime/composables/useEmbedConfig.d.ts +10 -1
- package/dist/runtime/composables/useEmbedConfig.js +24 -3
- package/dist/runtime/embed/components/ChatConfigurationModal.vue +8 -6
- package/dist/runtime/embed/components/ChatEmbed.d.vue.ts +9 -2
- package/dist/runtime/embed/components/ChatEmbed.vue +22 -13
- package/dist/runtime/embed/components/ChatEmbed.vue.d.ts +9 -2
- package/dist/runtime/embed/components/ChatEmbedInner.vue +5 -1
- package/dist/runtime/server/api/conversations/[id]/messages/[messageId]/retry.post.js +7 -4
- package/dist/runtime/server/api/conversations/[id]/messages/index.get.js +1 -1
- package/dist/runtime/server/api/conversations/[id]/messages/index.post.js +15 -9
- package/dist/runtime/server/api/conversations/[id]/usage.get.js +1 -1
- package/dist/runtime/server/api/conversations/generate-title.post.js +18 -5
- package/dist/runtime/server/api/workspace/usage.get.js +1 -1
- package/dist/runtime/server/db/index.d.ts +20 -3
- package/dist/runtime/server/db/index.js +149 -10
- package/dist/runtime/server/db/schema/_schema.d.ts +2 -0
- package/dist/runtime/server/db/schema/_schema.js +3 -0
- package/dist/runtime/server/db/schema/conversation-usage.d.ts +1 -1
- package/dist/runtime/server/db/schema/conversation-usage.js +3 -2
- package/dist/runtime/server/db/schema/conversations.d.ts +1 -1
- package/dist/runtime/server/db/schema/conversations.js +3 -2
- package/dist/runtime/server/db/schema/external-skills.d.ts +1 -1
- package/dist/runtime/server/db/schema/external-skills.js +3 -2
- package/dist/runtime/server/db/schema/index.d.ts +1 -0
- package/dist/runtime/server/db/schema/index.js +1 -0
- package/dist/runtime/server/db/schema/messages.d.ts +1 -1
- package/dist/runtime/server/db/schema/messages.js +3 -2
- package/dist/runtime/server/db/schema/workspace-settings.d.ts +1 -1
- package/dist/runtime/server/db/schema/workspace-settings.js +3 -2
- package/dist/runtime/server/plugins/init-db.d.ts +2 -0
- package/dist/runtime/server/plugins/init-db.js +11 -0
- package/dist/runtime/server/utils/agent-api.d.ts +1 -1
- package/dist/runtime/server/utils/agent-api.js +2 -5
- package/dist/runtime/server/utils/billing.d.ts +26 -4
- package/dist/runtime/server/utils/billing.js +52 -13
- package/dist/runtime/server/utils/chat-workspace-settings.d.ts +2 -1
- package/dist/runtime/server/utils/chat-workspace-settings.js +11 -2
- package/dist/runtime/utils/chat-loading-messages.d.ts +12 -0
- package/dist/runtime/utils/chat-loading-messages.js +40 -0
- package/dist/runtime/utils/custom-markdown-components.d.ts +9 -0
- package/dist/runtime/utils/custom-markdown-components.js +54 -0
- package/dist/runtime/utils/features.d.ts +6 -0
- package/dist/runtime/utils/features.js +15 -0
- package/dist/types.d.mts +1 -1
- package/drizzle/0000_material_hiroim.sql +28 -0
- package/drizzle/0001_famous_scalphunter.sql +1 -0
- package/drizzle/0002_gorgeous_big_bertha.sql +1 -0
- package/drizzle/0003_massive_forge.sql +2 -0
- package/drizzle/0004_absent_black_tom.sql +2 -0
- package/drizzle/0005_first_kid_colt.sql +1 -0
- package/drizzle/0006_sloppy_mauler.sql +13 -0
- package/drizzle/0007_grey_rhino.sql +1 -0
- package/drizzle/0008_chilly_blue_blade.sql +27 -0
- package/drizzle/0009_cultured_maddog.sql +16 -0
- package/drizzle/0010_small_barracuda.sql +1 -0
- package/drizzle/0011_fat_lady_mastermind.sql +6 -0
- package/drizzle/0012_puzzling_rick_jones.sql +1 -0
- package/drizzle/0013_blue_gwen_stacy.sql +11 -0
- package/drizzle/meta/0000_snapshot.json +239 -0
- package/drizzle/meta/0001_snapshot.json +245 -0
- package/drizzle/meta/0002_snapshot.json +251 -0
- package/drizzle/meta/0003_snapshot.json +263 -0
- package/drizzle/meta/0004_snapshot.json +275 -0
- package/drizzle/meta/0005_snapshot.json +281 -0
- package/drizzle/meta/0006_snapshot.json +320 -0
- package/drizzle/meta/0007_snapshot.json +326 -0
- package/drizzle/meta/0008_snapshot.json +539 -0
- package/drizzle/meta/0009_snapshot.json +646 -0
- package/drizzle/meta/0010_snapshot.json +653 -0
- package/drizzle/meta/0011_snapshot.json +689 -0
- package/drizzle/meta/0012_snapshot.json +695 -0
- package/drizzle/meta/0013_snapshot.json +699 -0
- package/drizzle/meta/_journal.json +104 -0
- package/package.json +5 -3
- package/dist/runtime/server/tasks/send-daily-usage-report.d.ts +0 -2
- package/dist/runtime/server/tasks/send-daily-usage-report.js +0 -74
- package/dist/runtime/server/utils/auth-api.d.ts +0 -1
- package/dist/runtime/server/utils/auth-api.js +0 -27
|
@@ -19,7 +19,7 @@ export type ModelUsageEntry = {
|
|
|
19
19
|
};
|
|
20
20
|
export declare const conversationUsage: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
21
21
|
name: "conversation_usage";
|
|
22
|
-
schema:
|
|
22
|
+
schema: "chat";
|
|
23
23
|
columns: {
|
|
24
24
|
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
25
25
|
name: "id";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { uuid, text, timestamp, index, jsonb, integer, numeric, unique } from "drizzle-orm/pg-core";
|
|
2
|
+
import { chatSchema } from "./_schema.js";
|
|
2
3
|
import { conversations } from "./conversations.js";
|
|
3
|
-
export const conversationUsage =
|
|
4
|
+
export const conversationUsage = chatSchema.table("conversation_usage", {
|
|
4
5
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
5
6
|
workspaceId: text("workspace_id").notNull(),
|
|
6
7
|
conversationId: uuid("conversation_id").notNull().references(() => conversations.id, { onDelete: "cascade" }),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ResolvedWorkspaceSettings } from './workspace-settings.js';
|
|
2
2
|
export declare const conversations: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
3
3
|
name: "conversations";
|
|
4
|
-
schema:
|
|
4
|
+
schema: "chat";
|
|
5
5
|
columns: {
|
|
6
6
|
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
7
7
|
name: "id";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { uuid, text, timestamp, index, jsonb } from "drizzle-orm/pg-core";
|
|
2
|
+
import { chatSchema } from "./_schema.js";
|
|
3
|
+
export const conversations = chatSchema.table("conversations", {
|
|
3
4
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
4
5
|
workspaceId: text("workspace_id").notNull(),
|
|
5
6
|
userId: text("user_id").notNull(),
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { text, timestamp, jsonb, boolean, serial, unique } from "drizzle-orm/pg-core";
|
|
2
2
|
import { relations } from "drizzle-orm";
|
|
3
|
+
import { chatSchema } from "./_schema.js";
|
|
3
4
|
import { workspaceSettings } from "./workspace-settings.js";
|
|
4
|
-
export const externalSkills =
|
|
5
|
+
export const externalSkills = chatSchema.table("external_skills", {
|
|
5
6
|
id: serial("id").primaryKey(),
|
|
6
7
|
workspaceId: text("workspace_id").notNull(),
|
|
7
8
|
ref: text("ref").notNull(),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { CHAT_SCHEMA_NAME, chatSchema } from './_schema.js';
|
|
1
2
|
export { conversationUsage, type ConversationUsageMetadata, type ModelUsageEntry } from './conversation-usage.js';
|
|
2
3
|
export { conversations } from './conversations.js';
|
|
3
4
|
export { type ExternalSkillInsert, type ExternalSkillRow, externalSkills, externalSkillsRelations } from './external-skills.js';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { uuid, text, timestamp, index, jsonb } from "drizzle-orm/pg-core";
|
|
2
|
+
import { chatSchema } from "./_schema.js";
|
|
2
3
|
import { conversations } from "./conversations.js";
|
|
3
|
-
export const messages =
|
|
4
|
+
export const messages = chatSchema.table("messages", {
|
|
4
5
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
5
6
|
conversationId: uuid("conversation_id").notNull().references(() => conversations.id, { onDelete: "cascade" }),
|
|
6
7
|
role: text("role", { enum: ["user", "assistant"] }).notNull(),
|
|
@@ -29,7 +29,7 @@ export type ResolvedWorkspaceSettings = {
|
|
|
29
29
|
};
|
|
30
30
|
export declare const workspaceSettings: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
31
31
|
name: "workspace_settings";
|
|
32
|
-
schema:
|
|
32
|
+
schema: "chat";
|
|
33
33
|
columns: {
|
|
34
34
|
workspaceId: import("drizzle-orm/pg-core").PgColumn<{
|
|
35
35
|
name: "workspace_id";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { text, timestamp, jsonb } from "drizzle-orm/pg-core";
|
|
2
2
|
import { relations } from "drizzle-orm";
|
|
3
|
+
import { chatSchema } from "./_schema.js";
|
|
3
4
|
import { externalSkills } from "./external-skills.js";
|
|
4
|
-
export const workspaceSettings =
|
|
5
|
+
export const workspaceSettings = chatSchema.table("workspace_settings", {
|
|
5
6
|
workspaceId: text("workspace_id").primaryKey(),
|
|
6
7
|
systemMessage: text("system_message"),
|
|
7
8
|
contextFiles: jsonb("context_files").$type(),
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { defineNitroPlugin } from "nitropack/runtime";
|
|
2
|
+
import { initDb } from "../db/index.js";
|
|
3
|
+
import { logger } from "../utils/logger.js";
|
|
4
|
+
export default defineNitroPlugin(async () => {
|
|
5
|
+
try {
|
|
6
|
+
await initDb();
|
|
7
|
+
} catch (error) {
|
|
8
|
+
logger.error({ error }, "Failed to initialize chat-nuxt database during Nitro boot");
|
|
9
|
+
throw error;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
@@ -36,4 +36,4 @@ export declare function cancelSession(token: string, sessionId: string): Promise
|
|
|
36
36
|
error: string;
|
|
37
37
|
}>;
|
|
38
38
|
export declare function extractContentFromReasoning(reasoning: ReasoningItem[]): string;
|
|
39
|
-
export declare function extractContentFromSession(session: AgentApiSession
|
|
39
|
+
export declare function extractContentFromSession(session: AgentApiSession): string;
|
|
@@ -150,11 +150,8 @@ export function extractContentFromReasoning(reasoning) {
|
|
|
150
150
|
}
|
|
151
151
|
return "";
|
|
152
152
|
}
|
|
153
|
-
export function extractContentFromSession(session
|
|
154
|
-
if (
|
|
155
|
-
return extractContentFromReasoning(turnReasoning);
|
|
156
|
-
}
|
|
157
|
-
if (session.result?.content) {
|
|
153
|
+
export function extractContentFromSession(session) {
|
|
154
|
+
if (typeof session.result?.content === "string") {
|
|
158
155
|
return session.result.content;
|
|
159
156
|
}
|
|
160
157
|
if (session.result?.structuredContent) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { H3Event } from 'h3';
|
|
1
2
|
export type BillingConfig = {
|
|
2
3
|
mode: 'plan';
|
|
3
4
|
cvp: number;
|
|
@@ -9,13 +10,17 @@ export type WorkspaceInfo = {
|
|
|
9
10
|
name: string;
|
|
10
11
|
};
|
|
11
12
|
/**
|
|
12
|
-
* Fetch workspace info
|
|
13
|
+
* Fetch workspace info via the authenticated user's session.
|
|
14
|
+
*
|
|
15
|
+
* Calls auth-api's `whoAmI` with the user's `tela-access-token`, which returns
|
|
16
|
+
* the active organization (including the `settings` JSONB blob and `name`).
|
|
17
|
+
* No internal API key is required.
|
|
13
18
|
*/
|
|
14
|
-
export declare function getWorkspaceInfo(
|
|
19
|
+
export declare function getWorkspaceInfo(event: H3Event): Promise<WorkspaceInfo>;
|
|
15
20
|
/**
|
|
16
|
-
* Fetch workspace billing settings
|
|
21
|
+
* Fetch workspace billing settings via the authenticated user's session.
|
|
17
22
|
*/
|
|
18
|
-
export declare function getWorkspaceBilling(
|
|
23
|
+
export declare function getWorkspaceBilling(event: H3Event): Promise<BillingConfig>;
|
|
19
24
|
export type UsageData = {
|
|
20
25
|
promptCost: number;
|
|
21
26
|
completionCost: number;
|
|
@@ -35,3 +40,20 @@ export type TransformedCosts = {
|
|
|
35
40
|
* For 'credits' mode: calculates credits based on costs and token amounts
|
|
36
41
|
*/
|
|
37
42
|
export declare function transformCostForBilling(usage: UsageData, billing: BillingConfig): TransformedCosts;
|
|
43
|
+
export type DailyUsageRow = {
|
|
44
|
+
workspaceId: string;
|
|
45
|
+
totalTokens: number;
|
|
46
|
+
totalCost: number;
|
|
47
|
+
promptTokens: number;
|
|
48
|
+
completionTokens: number;
|
|
49
|
+
promptCost: number;
|
|
50
|
+
completionCost: number;
|
|
51
|
+
conversationCount: number;
|
|
52
|
+
userCount: number;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Aggregate per-workspace conversation usage between the given timestamps.
|
|
56
|
+
* Returns plain numeric rows so consumers can avoid pulling drizzle types
|
|
57
|
+
* across package boundaries.
|
|
58
|
+
*/
|
|
59
|
+
export declare function loadDailyUsageStats(start: Date, end: Date): Promise<DailyUsageRow[]>;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getCookie } from "h3";
|
|
2
|
+
import { and, gte, lte, sql } from "drizzle-orm";
|
|
3
|
+
import { useRuntimeConfig } from "nitropack/runtime";
|
|
4
|
+
import { AuthClient } from "@meistrari/auth-nuxt/core";
|
|
5
|
+
import { useDb, schema } from "#chat-runtime/server/db";
|
|
2
6
|
import { logger } from "#chat-runtime/server/utils/logger";
|
|
3
7
|
const DEFAULT_CVP = 1.5;
|
|
4
8
|
function calculateCreditsUsed(inputCost, outputCost, inputAmount, outputAmount) {
|
|
@@ -13,27 +17,42 @@ function calculateCreditsUsed(inputCost, outputCost, inputAmount, outputAmount)
|
|
|
13
17
|
);
|
|
14
18
|
return credits;
|
|
15
19
|
}
|
|
16
|
-
|
|
20
|
+
function defaultWorkspaceInfo(name) {
|
|
21
|
+
return {
|
|
22
|
+
billing: { mode: "plan", cvp: DEFAULT_CVP },
|
|
23
|
+
name: name ?? "workspace"
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export async function getWorkspaceInfo(event) {
|
|
27
|
+
const fallbackName = event.context.auth?.workspace?.id;
|
|
28
|
+
const accessToken = event.context.auth?.token ?? getCookie(event, "tela-access-token");
|
|
29
|
+
if (!accessToken) {
|
|
30
|
+
return defaultWorkspaceInfo(fallbackName);
|
|
31
|
+
}
|
|
17
32
|
try {
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
33
|
+
const config = useRuntimeConfig();
|
|
34
|
+
const authConfig = config.public.telaAuth;
|
|
35
|
+
const apiUrl = authConfig?.apiUrl;
|
|
36
|
+
if (!apiUrl) {
|
|
37
|
+
logger.warn("telaAuth.apiUrl not configured; falling back to default workspace info");
|
|
38
|
+
return defaultWorkspaceInfo(fallbackName);
|
|
39
|
+
}
|
|
40
|
+
const authClient = new AuthClient(apiUrl);
|
|
41
|
+
const { organization } = await authClient.application.whoAmI(accessToken, {});
|
|
42
|
+
const settings = organization?.settings;
|
|
21
43
|
const billingSettings = settings?.billing;
|
|
22
44
|
const billing = billingSettings?.mode === "credits" ? { mode: "credits" } : { mode: "plan", cvp: billingSettings?.cvp ?? DEFAULT_CVP };
|
|
23
45
|
return {
|
|
24
46
|
billing,
|
|
25
|
-
name:
|
|
47
|
+
name: organization?.name ?? fallbackName ?? "workspace"
|
|
26
48
|
};
|
|
27
49
|
} catch (error) {
|
|
28
|
-
logger.error(error, "Failed to fetch workspace info");
|
|
29
|
-
return
|
|
30
|
-
billing: { mode: "plan", cvp: DEFAULT_CVP },
|
|
31
|
-
name: workspaceId
|
|
32
|
-
};
|
|
50
|
+
logger.error(error, "Failed to fetch workspace info via whoAmI");
|
|
51
|
+
return defaultWorkspaceInfo(fallbackName);
|
|
33
52
|
}
|
|
34
53
|
}
|
|
35
|
-
export async function getWorkspaceBilling(
|
|
36
|
-
const info = await getWorkspaceInfo(
|
|
54
|
+
export async function getWorkspaceBilling(event) {
|
|
55
|
+
const info = await getWorkspaceInfo(event);
|
|
37
56
|
return info.billing;
|
|
38
57
|
}
|
|
39
58
|
export function transformCostForBilling(usage, billing) {
|
|
@@ -66,3 +85,23 @@ export function transformCostForBilling(usage, billing) {
|
|
|
66
85
|
totalCost: totalCredits
|
|
67
86
|
};
|
|
68
87
|
}
|
|
88
|
+
export async function loadDailyUsageStats(start, end) {
|
|
89
|
+
const db = useDb();
|
|
90
|
+
const rows = await db.select({
|
|
91
|
+
workspaceId: schema.conversationUsage.workspaceId,
|
|
92
|
+
totalTokens: sql`SUM(${schema.conversationUsage.totalTokens})::int`,
|
|
93
|
+
totalCost: sql`SUM(${schema.conversationUsage.totalCost}::numeric)::float`,
|
|
94
|
+
promptTokens: sql`SUM(${schema.conversationUsage.promptTokens})::int`,
|
|
95
|
+
completionTokens: sql`SUM(${schema.conversationUsage.completionTokens})::int`,
|
|
96
|
+
promptCost: sql`SUM(${schema.conversationUsage.promptCost}::numeric)::float`,
|
|
97
|
+
completionCost: sql`SUM(${schema.conversationUsage.completionCost}::numeric)::float`,
|
|
98
|
+
conversationCount: sql`COUNT(DISTINCT ${schema.conversationUsage.conversationId})::int`,
|
|
99
|
+
userCount: sql`COUNT(DISTINCT ${schema.conversationUsage.userId})::int`
|
|
100
|
+
}).from(schema.conversationUsage).where(
|
|
101
|
+
and(
|
|
102
|
+
gte(schema.conversationUsage.createdAt, start),
|
|
103
|
+
lte(schema.conversationUsage.createdAt, end)
|
|
104
|
+
)
|
|
105
|
+
).groupBy(schema.conversationUsage.workspaceId).orderBy(sql`SUM(${schema.conversationUsage.totalCost}::numeric) DESC`);
|
|
106
|
+
return rows;
|
|
107
|
+
}
|
|
@@ -8,8 +8,9 @@ export declare function normalizeResolvedWorkspaceSettings(settings: ResolvedWor
|
|
|
8
8
|
export declare function serializeResolvedWorkspaceSettings(settings: ResolvedWorkspaceSettings): ResolvedWorkspaceSettings;
|
|
9
9
|
export declare function getConversationAppliedSettings(conversation: {
|
|
10
10
|
appliedSettingsSnapshot?: ResolvedWorkspaceSettingsInput | null;
|
|
11
|
-
}, trustedSettings?: ResolvedWorkspaceSettingsInput | null): ResolvedWorkspaceSettings;
|
|
11
|
+
}, trustedSettings?: ResolvedWorkspaceSettingsInput | null, explicitSettings?: ResolvedWorkspaceSettingsInput | null): ResolvedWorkspaceSettings;
|
|
12
12
|
export declare function hasMaterialWorkspaceSettingsMismatch(currentSettings: ResolvedWorkspaceSettingsInput | null | undefined, trustedSettings: ResolvedWorkspaceSettingsInput | null | undefined): boolean;
|
|
13
|
+
export declare function parseWorkspaceSettingsSnapshot(settings: unknown): ResolvedWorkspaceSettings;
|
|
13
14
|
export declare function resolveDefaultWorkspaceSettings(db: DbInstance, workspaceId: string): Promise<ResolvedWorkspaceSettings>;
|
|
14
15
|
export declare function resolveWorkspaceSettings(event: H3Event, context: ChatContext, db: DbInstance): Promise<ResolvedWorkspaceSettings>;
|
|
15
16
|
export declare function getWorkspaceSettingsUpdatedAt(settings: ResolvedWorkspaceSettings): Date;
|
|
@@ -15,7 +15,7 @@ const contextFileSchema = z.object({
|
|
|
15
15
|
const resolvedWorkspaceSettingsSchema = z.object({
|
|
16
16
|
systemMessage: z.string().nullable().optional(),
|
|
17
17
|
contextFiles: z.array(contextFileSchema).nullable().optional(),
|
|
18
|
-
canvasTools: z.array(z.object({
|
|
18
|
+
canvasTools: z.array(z.object({ canvasId: z.string() }).passthrough()).nullable().optional(),
|
|
19
19
|
knowledgeSources: z.array(z.object({ id: z.string() }).passthrough()).nullable().optional(),
|
|
20
20
|
externalSkills: z.array(z.object({ ref: z.string(), name: z.string() }).passthrough()).nullable().optional(),
|
|
21
21
|
updatedAt: z.union([z.string(), z.date()]).optional()
|
|
@@ -40,10 +40,13 @@ export function serializeResolvedWorkspaceSettings(settings) {
|
|
|
40
40
|
updatedAt: settings.updatedAt instanceof Date ? settings.updatedAt.toISOString() : settings.updatedAt
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
-
export function getConversationAppliedSettings(conversation, trustedSettings) {
|
|
43
|
+
export function getConversationAppliedSettings(conversation, trustedSettings, explicitSettings) {
|
|
44
44
|
if (conversation.appliedSettingsSnapshot) {
|
|
45
45
|
return normalizeResolvedWorkspaceSettings(conversation.appliedSettingsSnapshot);
|
|
46
46
|
}
|
|
47
|
+
if (explicitSettings !== void 0) {
|
|
48
|
+
return normalizeResolvedWorkspaceSettings(explicitSettings);
|
|
49
|
+
}
|
|
47
50
|
return normalizeResolvedWorkspaceSettings(trustedSettings);
|
|
48
51
|
}
|
|
49
52
|
export function hasMaterialWorkspaceSettingsMismatch(currentSettings, trustedSettings) {
|
|
@@ -69,6 +72,12 @@ function parseResolverResult(settings) {
|
|
|
69
72
|
}
|
|
70
73
|
return normalizeResolvedWorkspaceSettings(parsedSettings.data);
|
|
71
74
|
}
|
|
75
|
+
export function parseWorkspaceSettingsSnapshot(settings) {
|
|
76
|
+
if (settings === null) {
|
|
77
|
+
return normalizeResolvedWorkspaceSettings(null);
|
|
78
|
+
}
|
|
79
|
+
return parseResolverResult(settings);
|
|
80
|
+
}
|
|
72
81
|
export async function resolveDefaultWorkspaceSettings(db, workspaceId) {
|
|
73
82
|
const [settings, skillRows] = await Promise.all([
|
|
74
83
|
db.select().from(schema.workspaceSettings).where(eq(schema.workspaceSettings.workspaceId, workspaceId)),
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const DEFAULT_CHAT_LOADING_MESSAGES: readonly ["Analisando sua pergunta", "Processando informações", "Consultando base de conhecimento", "Organizando ideias", "Elaborando resposta", "Refinando detalhes", "Verificando contexto", "Conectando conceitos", "Preparando resultado", "Quase lá", "Finalizando análise", "Estruturando resposta"];
|
|
2
|
+
export type ChatLoadingMessageMode = 'ordered' | 'random';
|
|
3
|
+
export type ChatLoadingMessagesInput = {
|
|
4
|
+
loadingMessages?: readonly string[] | null;
|
|
5
|
+
loadingMessagesMode?: ChatLoadingMessageMode | null;
|
|
6
|
+
};
|
|
7
|
+
export type ResolvedChatLoadingMessages = {
|
|
8
|
+
mode: ChatLoadingMessageMode;
|
|
9
|
+
messages: readonly string[];
|
|
10
|
+
};
|
|
11
|
+
export declare function resolveChatLoadingMessages(input?: ChatLoadingMessagesInput | null): ResolvedChatLoadingMessages;
|
|
12
|
+
export declare function getNextChatLoadingMessageIndex(mode: ChatLoadingMessageMode, messageCount: number, currentIndex: number, random?: () => number): number;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const DEFAULT_CHAT_LOADING_MESSAGES = [
|
|
2
|
+
"Analisando sua pergunta",
|
|
3
|
+
"Processando informa\xE7\xF5es",
|
|
4
|
+
"Consultando base de conhecimento",
|
|
5
|
+
"Organizando ideias",
|
|
6
|
+
"Elaborando resposta",
|
|
7
|
+
"Refinando detalhes",
|
|
8
|
+
"Verificando contexto",
|
|
9
|
+
"Conectando conceitos",
|
|
10
|
+
"Preparando resultado",
|
|
11
|
+
"Quase l\xE1",
|
|
12
|
+
"Finalizando an\xE1lise",
|
|
13
|
+
"Estruturando resposta"
|
|
14
|
+
];
|
|
15
|
+
function normalizeMessages(messages) {
|
|
16
|
+
if (!messages?.length)
|
|
17
|
+
return [];
|
|
18
|
+
return messages.map((message) => message.trim()).filter((message) => message.length > 0);
|
|
19
|
+
}
|
|
20
|
+
export function resolveChatLoadingMessages(input) {
|
|
21
|
+
const loadingMessages = normalizeMessages(input?.loadingMessages);
|
|
22
|
+
if (loadingMessages.length > 0) {
|
|
23
|
+
return {
|
|
24
|
+
mode: input?.loadingMessagesMode === "random" ? "random" : "ordered",
|
|
25
|
+
messages: loadingMessages
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
mode: "ordered",
|
|
30
|
+
messages: DEFAULT_CHAT_LOADING_MESSAGES
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function getNextChatLoadingMessageIndex(mode, messageCount, currentIndex, random = Math.random) {
|
|
34
|
+
if (messageCount <= 1)
|
|
35
|
+
return 0;
|
|
36
|
+
if (mode === "ordered")
|
|
37
|
+
return (currentIndex + 1) % messageCount;
|
|
38
|
+
const nextIndex = Math.floor(random() * (messageCount - 1));
|
|
39
|
+
return nextIndex >= currentIndex ? nextIndex + 1 : nextIndex;
|
|
40
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Component } from 'vue';
|
|
2
|
+
import type { BaseNode } from 'markstream-vue';
|
|
3
|
+
export type CustomMarkdownNode = BaseNode & {
|
|
4
|
+
attrs?: [string, unknown][];
|
|
5
|
+
content?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function customMarkdownNodeProps(node: CustomMarkdownNode): Record<string, unknown>;
|
|
8
|
+
export declare function wrapCustomMarkdownComponent(component: Component, tagName?: string): Component;
|
|
9
|
+
export declare function wrapCustomMarkdownComponents(components: Record<string, Component>): Record<string, Component>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { defineComponent, h } from "vue";
|
|
2
|
+
function camelizeAttributeName(name) {
|
|
3
|
+
return name.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
4
|
+
}
|
|
5
|
+
export function customMarkdownNodeProps(node) {
|
|
6
|
+
const attrProps = {};
|
|
7
|
+
for (const attr of node.attrs ?? []) {
|
|
8
|
+
const [name, value] = attr;
|
|
9
|
+
if (!name)
|
|
10
|
+
continue;
|
|
11
|
+
const propName = camelizeAttributeName(name);
|
|
12
|
+
if (propName === "node")
|
|
13
|
+
continue;
|
|
14
|
+
attrProps[propName] = value;
|
|
15
|
+
}
|
|
16
|
+
return { node, ...attrProps };
|
|
17
|
+
}
|
|
18
|
+
function customMarkdownComponentAdapterName(tagName, component) {
|
|
19
|
+
if (typeof component === "function" && component.name)
|
|
20
|
+
return component.name;
|
|
21
|
+
if (typeof component === "object" && component) {
|
|
22
|
+
const namedComponent = component;
|
|
23
|
+
return namedComponent.displayName ?? namedComponent.name ?? tagName;
|
|
24
|
+
}
|
|
25
|
+
return tagName;
|
|
26
|
+
}
|
|
27
|
+
export function wrapCustomMarkdownComponent(component, tagName = "unknown") {
|
|
28
|
+
return defineComponent({
|
|
29
|
+
name: `CustomMarkdownComponentAdapter(${customMarkdownComponentAdapterName(tagName, component)})`,
|
|
30
|
+
props: {
|
|
31
|
+
node: {
|
|
32
|
+
type: Object,
|
|
33
|
+
required: true
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
setup(props, { attrs }) {
|
|
37
|
+
return () => h(
|
|
38
|
+
component,
|
|
39
|
+
{
|
|
40
|
+
...attrs,
|
|
41
|
+
...customMarkdownNodeProps(props.node)
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
default: () => props.node.content ?? ""
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export function wrapCustomMarkdownComponents(components) {
|
|
51
|
+
return Object.fromEntries(
|
|
52
|
+
Object.entries(components).map(([name, component]) => [name, wrapCustomMarkdownComponent(component, name)])
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useRuntimeConfig } from "#imports";
|
|
2
|
+
const DEFAULTS = {
|
|
3
|
+
usage: true,
|
|
4
|
+
generateTitle: false,
|
|
5
|
+
credentials: false
|
|
6
|
+
};
|
|
7
|
+
export function useChatNuxtFeatures() {
|
|
8
|
+
const config = useRuntimeConfig();
|
|
9
|
+
const features = config.public.chatNuxtFeatures;
|
|
10
|
+
return {
|
|
11
|
+
usage: features?.usage ?? DEFAULTS.usage,
|
|
12
|
+
generateTitle: features?.generateTitle ?? DEFAULTS.generateTitle,
|
|
13
|
+
credentials: features?.credentials ?? DEFAULTS.credentials
|
|
14
|
+
};
|
|
15
|
+
}
|
package/dist/types.d.mts
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
CREATE TABLE "conversations" (
|
|
2
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
3
|
+
"workspace_id" text NOT NULL,
|
|
4
|
+
"user_id" text NOT NULL,
|
|
5
|
+
"title" text DEFAULT 'Nova conversa' NOT NULL,
|
|
6
|
+
"thread_session_id" text,
|
|
7
|
+
"canvas_tools" jsonb,
|
|
8
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
9
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
10
|
+
);
|
|
11
|
+
--> statement-breakpoint
|
|
12
|
+
CREATE TABLE "messages" (
|
|
13
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
14
|
+
"conversation_id" uuid NOT NULL,
|
|
15
|
+
"role" text NOT NULL,
|
|
16
|
+
"content" text NOT NULL,
|
|
17
|
+
"status" text DEFAULT 'completed',
|
|
18
|
+
"reasoning_data" jsonb,
|
|
19
|
+
"files" jsonb,
|
|
20
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
21
|
+
);
|
|
22
|
+
--> statement-breakpoint
|
|
23
|
+
ALTER TABLE "messages" ADD CONSTRAINT "messages_conversation_id_conversations_id_fk" FOREIGN KEY ("conversation_id") REFERENCES "public"."conversations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
24
|
+
CREATE INDEX "idx_conversations_workspace" ON "conversations" USING btree ("workspace_id");--> statement-breakpoint
|
|
25
|
+
CREATE INDEX "idx_conversations_user" ON "conversations" USING btree ("user_id");--> statement-breakpoint
|
|
26
|
+
CREATE INDEX "idx_conversations_updated" ON "conversations" USING btree ("updated_at");--> statement-breakpoint
|
|
27
|
+
CREATE INDEX "idx_messages_conversation" ON "messages" USING btree ("conversation_id");--> statement-breakpoint
|
|
28
|
+
CREATE INDEX "idx_messages_created" ON "messages" USING btree ("created_at");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "messages" ADD COLUMN "external_uuid" text;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "messages" ADD COLUMN "ttft" text;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "messages" ADD COLUMN "updated_at" timestamp with time zone;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS "workspace_settings" (
|
|
2
|
+
"workspace_id" text PRIMARY KEY NOT NULL,
|
|
3
|
+
"system_message" text,
|
|
4
|
+
"context_files" jsonb,
|
|
5
|
+
"canvas_tools" jsonb,
|
|
6
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
7
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
8
|
+
);
|
|
9
|
+
--> statement-breakpoint
|
|
10
|
+
ALTER TABLE "conversations" ADD COLUMN IF NOT EXISTS "applied_settings_at" timestamp with time zone;--> statement-breakpoint
|
|
11
|
+
ALTER TABLE "conversations" DROP COLUMN IF EXISTS "canvas_tools";--> statement-breakpoint
|
|
12
|
+
ALTER TABLE "conversations" DROP COLUMN IF EXISTS "system_message";--> statement-breakpoint
|
|
13
|
+
ALTER TABLE "conversations" DROP COLUMN IF EXISTS "context_files";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "workspace_settings" ADD COLUMN IF NOT EXISTS "knowledge_sources" jsonb;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
CREATE TABLE "conversation_usage" (
|
|
2
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
3
|
+
"workspace_id" text NOT NULL,
|
|
4
|
+
"conversation_id" uuid NOT NULL,
|
|
5
|
+
"prompt_tokens" integer NOT NULL,
|
|
6
|
+
"completion_tokens" integer NOT NULL,
|
|
7
|
+
"total_tokens" integer NOT NULL,
|
|
8
|
+
"prompt_cost" numeric(12, 8) NOT NULL,
|
|
9
|
+
"completion_cost" numeric(12, 8) NOT NULL,
|
|
10
|
+
"total_cost" numeric(12, 8) NOT NULL,
|
|
11
|
+
"duration_ms" integer,
|
|
12
|
+
"turns" integer,
|
|
13
|
+
"user_id" text NOT NULL,
|
|
14
|
+
"user_email" text,
|
|
15
|
+
"model" text,
|
|
16
|
+
"session_id" text,
|
|
17
|
+
"metadata" jsonb,
|
|
18
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
19
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
20
|
+
CONSTRAINT "conversation_usage_conversation_id_unique" UNIQUE("conversation_id")
|
|
21
|
+
);
|
|
22
|
+
--> statement-breakpoint
|
|
23
|
+
ALTER TABLE "conversation_usage" ADD CONSTRAINT "conversation_usage_conversation_id_conversations_id_fk" FOREIGN KEY ("conversation_id") REFERENCES "public"."conversations"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
24
|
+
CREATE INDEX "idx_usage_workspace" ON "conversation_usage" USING btree ("workspace_id");--> statement-breakpoint
|
|
25
|
+
CREATE INDEX "idx_usage_workspace_created" ON "conversation_usage" USING btree ("workspace_id","created_at");--> statement-breakpoint
|
|
26
|
+
CREATE INDEX "idx_usage_conversation" ON "conversation_usage" USING btree ("conversation_id");--> statement-breakpoint
|
|
27
|
+
CREATE INDEX "idx_usage_user" ON "conversation_usage" USING btree ("user_id");
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
CREATE TABLE "external_skills" (
|
|
2
|
+
"id" serial PRIMARY KEY NOT NULL,
|
|
3
|
+
"workspace_id" text NOT NULL,
|
|
4
|
+
"ref" text NOT NULL,
|
|
5
|
+
"name" text NOT NULL,
|
|
6
|
+
"description" text DEFAULT '' NOT NULL,
|
|
7
|
+
"runtime" text DEFAULT 'unknown' NOT NULL,
|
|
8
|
+
"allowed_tools" jsonb DEFAULT '[]'::jsonb NOT NULL,
|
|
9
|
+
"is_public" boolean DEFAULT true NOT NULL,
|
|
10
|
+
"added_by_user_id" text NOT NULL,
|
|
11
|
+
"added_by_username" text NOT NULL,
|
|
12
|
+
"added_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
13
|
+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
14
|
+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
15
|
+
CONSTRAINT "external_skills_workspace_ref_unique" UNIQUE("workspace_id","ref")
|
|
16
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "conversations" ADD COLUMN "model" text DEFAULT 'claude-sonnet-4-5';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
ALTER TABLE "conversation_usage" ADD COLUMN "cache_read_input_tokens" integer;--> statement-breakpoint
|
|
2
|
+
ALTER TABLE "conversation_usage" ADD COLUMN "cache_creation_input_tokens" integer;--> statement-breakpoint
|
|
3
|
+
ALTER TABLE "conversation_usage" ADD COLUMN "model_usage" jsonb;--> statement-breakpoint
|
|
4
|
+
ALTER TABLE "conversation_usage" ADD COLUMN "duration_api_ms" integer;--> statement-breakpoint
|
|
5
|
+
ALTER TABLE "conversation_usage" ADD COLUMN "web_search_requests" integer;--> statement-breakpoint
|
|
6
|
+
ALTER TABLE "conversation_usage" ADD COLUMN "web_fetch_requests" integer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE "conversations" ADD COLUMN "applied_settings_snapshot" jsonb;
|