diff --git a/apps/dbagent/package.json b/apps/dbagent/package.json index f2773d38..ba0abc10 100644 --- a/apps/dbagent/package.json +++ b/apps/dbagent/package.json @@ -55,6 +55,7 @@ "@opentelemetry/semantic-conventions": "^1.32.0", "@tailwindcss/postcss": "^4.1.6", "@tanstack/react-query": "^5.75.7", + "@types/ndjson": "^2.0.4", "@vercel/functions": "^2.0.3", "ai": "^4.3.15", "bytes": "^3.1.2", @@ -72,9 +73,11 @@ "geist": "^1.4.2", "import-in-the-middle": "^1.13.1", "kysely": "^0.28.2", + "langfuse": "^3.37.2", "langfuse-vercel": "^3.37.2", "litellm-api": "^0.0.3", "lucide-react": "^0.509.0", + "ndjson": "^2.0.0", "next": "^15.3.2", "next-auth": "5.0.0-beta.25", "next-themes": "^0.4.6", @@ -118,6 +121,7 @@ "@types/react-dom": "^19.1.3", "@types/react-syntax-highlighter": "^15.5.13", "autoprefixer": "^10.4.21", + "cmd-ts": "^0.13.0", "dockerode": "^4.0.6", "dotenv": "^16.5.0", "filenamify": "^6.0.0", diff --git a/apps/dbagent/playground/default/index.ts b/apps/dbagent/playground/default/index.ts index f2375f06..ea126a46 100644 --- a/apps/dbagent/playground/default/index.ts +++ b/apps/dbagent/playground/default/index.ts @@ -1,29 +1,38 @@ import { Agent } from '@mastra/core/agent'; -import { AnswerRelevancyMetric, PromptAlignmentMetric } from '@mastra/evals/llm'; +import { AnswerRelevancyMetric } from '@mastra/evals/llm'; import { CompletenessMetric } from '@mastra/evals/nlp'; import { CloudProvider } from '~/lib/db/schema'; import { openai } from '@ai-sdk/openai'; +import { RuntimeContext } from '@mastra/core/runtime-context'; +import { z } from 'zod'; import { getChatSystemPrompt, getMonitoringSystemPrompt } from '~/lib/ai/agent'; -import { getBuiltinProviderRegistry } from '~/lib/ai/providers'; +import { getProviderRegistry } from '~/lib/ai/providers'; import { buildPlaygroundTools } from '../tools'; -/* eslint-disable no-process-env */ -const defaultModel = getBuiltinProviderRegistry() - .languageModel(process.env.MASTRA_MODEL ?? 'chat') - .instance(); -const cloudProvider = (process.env.MASTRA_CLOUD_PROVIDER ?? 'aws') as CloudProvider; -const defaultTools = buildPlaygroundTools({ - projectConnection: process.env.MASTRA_PROJECT_CONNECTION ?? undefined, - dbUrl: process.env.MASTRA_DB_URL ?? undefined, - userId: process.env.MASTRA_USER_ID ?? undefined +export const runtimeContextSchema = z.object({ + cloudProvider: z.enum(['other', 'aws', 'gcp']).default('other'), + model_id: z.string().default('chat'), + projectConnection: z.string().optional(), + dbUrl: z.string().optional(), + userId: z.string().optional() }); -/* eslint-enable no-process-env */ - -const chatPrompt = getChatSystemPrompt({ cloudProvider }); -const monitoringPrompt = getMonitoringSystemPrompt({ cloudProvider }); export function createAgents() { + /* eslint-disable no-process-env */ + const runtimeContext = new RuntimeContext( + Object.entries({ + cloudProvider: (process.env.MASTRA_CLOUD_PROVIDER ?? 'aws') as CloudProvider, + model_id: process.env.MASTRA_MODEL ?? 'chat', + projectConnection: process.env.MASTRA_PROJECT_CONNECTION ?? undefined, + dbUrl: process.env.MASTRA_DB_URL ?? undefined, + userId: process.env.MASTRA_USER_ID ?? undefined + }) + ); + // verify runtimeContextSchema + console.log(runtimeContextSchema.parse(runtimeContext)); + /* eslint-enable no-process-env */ + const evals = { completeness: new CompletenessMetric(), relevancy: new AnswerRelevancyMetric(openai('gpt-4o-mini'), { @@ -32,33 +41,44 @@ export function createAgents() { }) }; + const defaultOptions = { + defaultGenerateOptions: { runtimeContext }, + defaultStreamOptions: { runtimeContext }, + model: getModel, + tools: getTools, + evals: { + ...evals + } + }; + // TODO: create agent per supported model (assuming we have the keys)? return { monitoringAgent: new Agent({ name: 'monitoring-agent', - instructions: monitoringPrompt, - model: defaultModel, - tools: defaultTools, - evals: { - ...evals, - 'prompt-alignment': new PromptAlignmentMetric(openai('gpt-4o-mini'), { - instructions: [monitoringPrompt], - scale: 1 // Scale for the final score - }) + ...defaultOptions, + instructions: ({ runtimeContext }) => { + return getMonitoringSystemPrompt({ cloudProvider: runtimeContext.get('cloudProvider') }); } }), chatAgent: new Agent({ name: 'chat-agent', - instructions: chatPrompt, - model: defaultModel, - tools: defaultTools, - evals: { - ...evals, - 'prompt-alignment': new PromptAlignmentMetric(openai('gpt-4o-mini'), { - instructions: [chatPrompt], - scale: 1 // Scale for the final score - }) + ...defaultOptions, + instructions: ({ runtimeContext }) => { + return getChatSystemPrompt({ cloudProvider: runtimeContext.get('cloudProvider') }); } }) }; } + +const getModel = async ({ runtimeContext }: { runtimeContext: RuntimeContext }) => { + const { model_id } = runtimeContextSchema.parse(runtimeContext); + console.log('model_id', model_id); + const registry = await getProviderRegistry(); + return registry.languageModel(model_id || 'chat', true).instance(); +}; + +const getTools = async ({ runtimeContext }: { runtimeContext: RuntimeContext }) => { + const entries = runtimeContextSchema.parse(runtimeContext); + console.log('entries', entries); + return await buildPlaygroundTools(entries); +}; diff --git a/apps/dbagent/playground/index.ts b/apps/dbagent/playground/index.ts index 01f5059b..bd9ae795 100644 --- a/apps/dbagent/playground/index.ts +++ b/apps/dbagent/playground/index.ts @@ -1,5 +1,80 @@ +import { Agent } from '@mastra/core/agent'; +import { AnswerRelevancyMetric } from '@mastra/evals/llm'; +import { CompletenessMetric } from '@mastra/evals/nlp'; +import { CloudProvider } from '~/lib/db/schema'; + +import { openai } from '@ai-sdk/openai'; import { Mastra } from '@mastra/core'; -import { createAgents } from './default'; +import { RuntimeContext } from '@mastra/core/runtime-context'; +import { z } from 'zod'; +import { getChatSystemPrompt, getMonitoringSystemPrompt } from '~/lib/ai/agent'; +import { getProviderRegistry } from '~/lib/ai/providers'; +import { buildPlaygroundTools } from './tools'; + +/* eslint-disable no-process-env */ +const cloudProvider = process.env.MASTRA_CLOUD_PROVIDER ?? ('aws' as CloudProvider); + +export const runtimeContextSchema = z.object({ + cloudProvider: z.enum(['other', 'aws', 'gcp']).default(cloudProvider as any as CloudProvider), + model_id: z.string().default(process.env.MASTRA_MODEL ?? 'chat'), + projectConnection: process.env.MASTRA_PROJECT_CONNECTION + ? z.string().default(process.env.MASTRA_PROJECT_CONNECTION) + : z.string().optional(), + dbUrl: process.env.MASTRA_DB_URL ? z.string().default(process.env.MASTRA_DB_URL) : z.string().optional(), + userId: process.env.MASTRA_USER_ID ? z.string().default(process.env.MASTRA_USER_ID) : z.string().optional() +}); +/* eslint-enable no-process-env */ + +// verify runtimeContextSchema + +export function createAgents() { + const evals = { + completeness: new CompletenessMetric(), + relevancy: new AnswerRelevancyMetric(openai('gpt-4o-mini'), { + uncertaintyWeight: 0.3, // Weight for 'unsure' verdicts + scale: 1 // Scale for the final score + }) + }; + + const defaultOptions = { + model: getModel, + tools: getTools, + evals: { + ...evals + } + }; + + // TODO: create agent per supported model (assuming we have the keys)? + return { + monitoringAgent: new Agent({ + name: 'monitoring-agent', + ...defaultOptions, + instructions: ({ runtimeContext }) => { + return getMonitoringSystemPrompt({ cloudProvider: runtimeContext.get('cloudProvider') }); + } + }), + chatAgent: new Agent({ + name: 'chat-agent', + ...defaultOptions, + instructions: ({ runtimeContext }) => { + return getChatSystemPrompt({ cloudProvider: runtimeContext.get('cloudProvider') }); + } + }) + }; +} + +const getModel = async ({ runtimeContext }: { runtimeContext: RuntimeContext }) => { + const { model_id } = runtimeContextSchema.parse(runtimeContext); + console.log('model_id', model_id); + const registry = await getProviderRegistry(); + return registry.languageModel(model_id || 'chat', true).instance(); +}; + +const getTools = async ({ runtimeContext }: { runtimeContext: RuntimeContext }) => { + const entries = runtimeContextSchema.parse(runtimeContext); + console.log('entries', entries); + return await buildPlaygroundTools(entries); +}; export const mastra = new Mastra({ agents: createAgents() diff --git a/apps/dbagent/playground/tools/index.ts b/apps/dbagent/playground/tools/index.ts index 843d9e42..cef7382a 100644 --- a/apps/dbagent/playground/tools/index.ts +++ b/apps/dbagent/playground/tools/index.ts @@ -2,17 +2,18 @@ import { Tool } from 'ai'; import { builtinPlaybookToolset, commonToolset, - DBSQLTools, getDBClusterTools, - mergeToolsets, - playbookTools, - Toolset + getDBSQLTools, + getPlaybookToolset, + getProjectClusterService, + projectPlaybookService, + targetDBService } from '~/lib/ai/tools'; import { getConnectionByName, getDefaultConnection } from '~/lib/db/connections'; import { DBUserAccess } from '~/lib/db/db'; import { getProjectByName } from '~/lib/db/projects'; import { CloudProvider, Connection } from '~/lib/db/schema'; -import { getTargetDbPool, Pool } from '~/lib/targetdb/db'; +import { getTargetDbPool } from '~/lib/targetdb/db'; type PlaygroundToolsConfig = { projectConnection?: string; @@ -21,8 +22,8 @@ type PlaygroundToolsConfig = { cloudProvider?: CloudProvider; }; -export function buildPlaygroundTools(config: PlaygroundToolsConfig): Record { - const toolsets: Toolset[] = [commonToolset]; +export async function buildPlaygroundTools(config: PlaygroundToolsConfig): Promise> { + const toolsets: Record[] = [commonToolset]; const connString: string | null = config.dbUrl ?? null; // Set up user ID provider if configured @@ -37,79 +38,56 @@ export function buildPlaygroundTools(config: PlaygroundToolsConfig): Record { - const conn = await connGetter(); - return { projectId: conn.projectId }; - }); + const playbookToolset = getPlaybookToolset(projectPlaybookService(db, conn.projectId)); toolsets.push(playbookToolset); hasPlaybookToolset = true; if (!connString) { - const targetDBPoolGetter = createTargetDBPoolGetter(connGetter); - toolsets.push(new DBSQLTools(targetDBPoolGetter)); + const targetDBPool = getTargetDbPool(conn.connectionString); + toolsets.push(getDBSQLTools({ db: targetDBService(targetDBPool) })); hasDBTools = true; } } } if (connString && !hasDBTools) { - toolsets.push(new DBSQLTools(getTargetDbPool(connString))); + toolsets.push(getDBSQLTools({ db: targetDBService(getTargetDbPool(connString)) })); } if (!hasPlaybookToolset) { toolsets.push(builtinPlaybookToolset); } - return mergeToolsets(...toolsets); + return toolsets.reduce((acc, toolset) => { + return { + ...acc, + ...toolset + }; + }, {}); } -function createConnectionGetter( - userId: string, - projectName: string, - connectionName?: string -): () => Promise { - let cachedConnection: Connection | null = null; - return async () => { - if (cachedConnection) { - return cachedConnection; - } - - const db = new DBUserAccess(userId); - - // First find the project by name where user has access - const project = await getProjectByName(db, projectName); - if (!project) { - throw new Error(`Project "${projectName}" not found or access denied`); - } - - const connection = connectionName - ? await getConnectionByName(db, project.id, connectionName) - : await getDefaultConnection(db, project.id); - if (!connection) { - throw new Error( - connectionName - ? `Connection "${connectionName}" not found in project "${projectName}"` - : `No default connection found in project "${projectName}"` - ); - } +export async function getConnection(userId: string, projectName: string, connectionName?: string): Promise { + const db = new DBUserAccess(userId); + const project = await getProjectByName(db, projectName); + if (!project) { + throw new Error(`Project "${projectName}" not found or access denied`); + } - cachedConnection = connection; - return connection; - }; -} + const connection = connectionName + ? await getConnectionByName(db, project.id, connectionName) + : await getDefaultConnection(db, project.id); + if (!connection) { + throw new Error( + connectionName + ? `Connection "${connectionName}" not found in project "${projectName}"` + : `No default connection found in project "${projectName}"` + ); + } -function createTargetDBPoolGetter(connGetter: () => Promise) { - let cachedPool: Pool | null = null; - return async () => { - if (cachedPool) { - return cachedPool; - } - const connection = await connGetter(); - cachedPool = getTargetDbPool(connection.connectionString); - return cachedPool; - }; + return connection; } diff --git a/apps/dbagent/scripts/eval/simple.ts b/apps/dbagent/scripts/eval/simple.ts new file mode 100644 index 00000000..c4f00cbd --- /dev/null +++ b/apps/dbagent/scripts/eval/simple.ts @@ -0,0 +1,14 @@ +'use server'; + +import Langfuse from 'langfuse'; +import { evalAllTurn, LLMTurn } from '~/evals/lib/llmcheck'; +import { conciseAnswerMetric, finalAnswerMetric, Measure } from '~/evals/lib/llmcheck/metrics'; + +const metrics = [conciseAnswerMetric(), finalAnswerMetric()]; + +export async function evalFunction(langfuse: Langfuse, turn: LLMTurn): Promise> { + console.log(turn); + + const evals = await evalAllTurn(turn, metrics); + return evals; +} diff --git a/apps/dbagent/scripts/lftool/env.ts b/apps/dbagent/scripts/lftool/env.ts new file mode 100644 index 00000000..3b7f8e3b --- /dev/null +++ b/apps/dbagent/scripts/lftool/env.ts @@ -0,0 +1,8 @@ +import { config } from '@dotenvx/dotenvx'; + +// Load environment variables first +config({ + path: ['.env', '.env.local'], + strict: false, + ignore: ['MISSING_ENV_FILE'] +}); diff --git a/apps/dbagent/scripts/lftool/lftool.ts b/apps/dbagent/scripts/lftool/lftool.ts new file mode 100644 index 00000000..ed61b2fd --- /dev/null +++ b/apps/dbagent/scripts/lftool/lftool.ts @@ -0,0 +1,431 @@ +// Import env configuration first +import { evalFunction } from '../eval/simple'; +import './env'; + +import { WriteStream } from 'fs'; +import { ApiTraceWithDetails, ApiUtilsMetaResponse, Langfuse } from 'langfuse'; +import { z } from 'zod'; + +import { command, number, option, optional, positional, restPositionals, run, string, subcommands } from 'cmd-ts'; +import { promises as fs } from 'fs'; +import { FileHandle } from 'fs/promises'; +import { turnFromResponse } from '~/evals/lib/chat-runner'; +import { setEvalModel } from '~/evals/lib/llmcheck'; +import { AgentModelDeps, chatModel, getAgentMockDeps, getModelInstance } from '~/lib/ai/agent'; +import { Tool } from '~/lib/ai/model'; + +const envSchema = z.object({ + LANGFUSE_HOST: z.string().optional(), + LANGFUSE_PUBLIC_KEY: z.string().optional(), + LANGFUSE_SECRET_KEY: z.string().optional(), + LANGFUSE_DEBUG: z.string(z.enum(['true', 'false'])).default('false') +}); + +/* eslint-disable-next-line no-process-env */ +const env = envSchema.parse(process.env); + +function getLangfuse(): Langfuse { + return new Langfuse({ + baseUrl: env.LANGFUSE_HOST, + publicKey: env.LANGFUSE_PUBLIC_KEY, + secretKey: env.LANGFUSE_SECRET_KEY + }); +} + +const cmdSessionsList = command({ + name: 'list', + args: { + limit: option({ type: optional(number), long: 'limit', short: 'l' }) + }, + handler: async ({ limit }) => { + const langfuse = getLangfuse(); + const sessions = await langfuse.fetchSessions({ + limit: limit + }); + console.log(sessions.data); + } +}); + +const cmdSessionDownload = command({ + name: 'dlsession', + args: { + sessionIds: restPositionals({ type: string }), + output: option({ type: optional(string), long: 'output', short: 'o' }) + }, + handler: async ({ sessionIds, output }) => { + const langfuse = getLangfuse(); + + const sessionPages = async function* (sessionId: string, data: ApiTraceWithDetails[], meta: ApiUtilsMetaResponse) { + while (true) { + yield data; + if (meta.page == meta.totalPages) { + break; + } + + ({ data, meta } = await langfuse.fetchTraces({ + sessionId: sessionId, + limit: 20, + page: meta.page + 1 + })); + } + }; + + const sessionItems = async function* (sessionId: string, data: ApiTraceWithDetails[], meta: ApiUtilsMetaResponse) { + for await (const page of sessionPages(sessionId, data, meta)) { + for (const item of page) { + yield item; + } + } + }; + + const sessions = async function* () { + let ids = sessionIds; + if (ids.length == 0) { + const sessions = await langfuse.fetchSessions({ + limit: 20 + }); + ids = sessions.data.map((session) => session.id); + } + + for (const sessionId of ids) { + const { data, meta } = await langfuse.fetchTraces({ + sessionId: sessionId, + limit: 20 + }); + + yield { + sessionId: sessionId, + items: sessionItems(sessionId, data, meta) + }; + } + }; + + const header = { + type: 'langfuse-session', + version: 1 + }; + + let file: FileHandle | undefined; + if (output) { + file = await fs.open(output, 'w'); + } + + const outputStream: WriteStream = (file ? file.createWriteStream() : process.stdout) as WriteStream; + try { + outputStream.write(JSON.stringify(header)); + outputStream.write('\n'); + + for await (const { sessionId, items } of sessions()) { + outputStream.write(`{"sessionId": "${sessionId}", items:[`); + let count = 0; + for await (const item of items) { + if (count > 0) outputStream.write(', '); + outputStream.write(JSON.stringify(item)); + count++; + } + outputStream.write(']}\n'); + } + } finally { + outputStream.end(); + await file?.close(); + } + } +}); + +const cmdSessions = subcommands({ + name: 'session', + cmds: { + list: cmdSessionsList, + download: cmdSessionDownload + } +}); + +const cmdDatasetsList = command({ + name: 'list', + args: {}, + handler: async () => { + const langfuse = getLangfuse(); + const url = `${langfuse.baseUrl}/api/public/v2/datasets`; + + const fetchDatasets = async ({ limit = 50, page = 1 }: { limit?: number; page?: number }) => { + const params = new URLSearchParams({ limit: limit.toString(), page: page.toString() }); + const response = await langfuse.fetch( + `${url}?${params.toString()}`, + langfuse._getFetchOptions({ + method: 'GET' + }) + ); + if (response.status !== 200) { + throw new Error(`Failed to fetch datasets: ${response.status}`); + } + return await response.json(); + }; + + const datasetPages = async function* () { + let { data, meta } = await fetchDatasets({}); + + while (true) { + yield data; + if (meta.page == meta.totalPages) { + break; + } + + ({ data, meta } = await fetchDatasets({ + limit: 50, + page: meta.page + 1 + })); + } + }; + + for await (const page of datasetPages()) { + for (const item of page) { + console.log(item); + } + } + } +}); + +const cmdDatasetDownload = command({ + name: 'download', + args: { + datasetName: positional({ type: string }), + output: option({ type: optional(string), long: 'output', short: 'o' }) + }, + handler: async ({ datasetName: datasetId, output }) => { + const langfuse = getLangfuse(); + const response = await langfuse.getDataset(datasetId); + const { items, ...rest } = response; + const header = { + type: 'langfuse-dataset', + version: 1, + ...rest + }; + + let file: FileHandle | undefined; + if (output) { + file = await fs.open(output, 'w'); + } + const outputStream: WriteStream = (file ? file.createWriteStream() : process.stdout) as WriteStream; + try { + outputStream.write(JSON.stringify(header)); + outputStream.write('\n'); + for (const item of items) { + outputStream.write(JSON.stringify(item)); + outputStream.write('\n'); + } + } finally { + outputStream.end(); + await file?.close(); + } + } +}); + +const cmdDatasetEval = command({ + name: 'eval', + args: { + datasetName: positional({ type: string, displayName: 'dataset-name' }) + }, + handler: async ({ datasetName }) => { + const langfuse = getLangfuse(); + const response = await langfuse.getDataset(datasetName); + const { items } = response; + + setEvalModel(await getModelInstance(process.env.EVAL_MODEL ?? 'chat')); + + const runName = `${datasetName}-${new Date().toISOString()}`; + const model = process.env.CHAT_MODEL; + + for (const item of items) { + type ToolCall = { input: any; output: any }; + type ToolCallTable = Record; + type ToolCallItem = ToolCall & { toolName: string }; + + const trace = langfuse.trace({ + name: runName + }); + + const toolCalls: ToolCallTable = (item.metadata as any).toolCalls.reduce( + (acc: ToolCallTable, toolCall: ToolCallItem) => { + acc[toolCall.toolName] = [...(acc[toolCall.toolName] || []), toolCall]; + return acc; + }, + {} as ToolCallTable + ); + console.log(toolCalls); + + const inputEqual = (a: any, b: any) => { + return Object.keys(a).length === Object.keys(b).length && Object.keys(a).every((key) => a[key] === b[key]); + }; + + const messages = (item.input as any).messages; + const response = await chatModel.generateText({ + model, + maxSteps: 20, + deps: getAgentMockDeps({}), + messages, + tools: (tools: Record>) => { + for (const [name, toolCallVariants] of Object.entries(toolCalls)) { + const tool = tools[name]; + if (!tool) { + console.log(`Tool ${name} not found`); + continue; + } + tool.execute = async (input: any) => { + console.log(`tool call: ${name}(${JSON.stringify(input)})`); + + const toolCall = toolCallVariants.find((toolCall) => inputEqual(toolCall.input, input)); + if (!toolCall) { + console.log(`Error: tool call ${name} for input ${JSON.stringify(input)} not found`); + return null; + } + + const output = toolCall.output; + console.log(` => ${name}: ${JSON.stringify(output)}`); + return output; + }; + } + return tools; + } + }); + + // find prompt in messages + let prompt = ''; + for (const message of messages) { + if (message.role === 'user') { + prompt = message.content; + break; + } + } + + const turn = { + ...turnFromResponse(prompt, response), + expectedOutput: item.expectedOutput as any + }; + const evals = await evalFunction(langfuse, turn); + console.log(evals); + + const runMetadata = { + output: turn.output, + evals + }; + + await item.link(trace, runName, { + metadata: runMetadata + }); + + // try to set scores + try { + for (const [metricName, measure] of Object.entries(evals)) { + const value = measure.type === 'bool' ? (measure.success ? 'PASS' : 'FAIL') : measure.score; + console.log(`${metricName}: ${value}`); + + langfuse.score({ + name: metricName, + value, + traceId: trace.id + }); + } + } catch (e) { + console.error(e); + } + } + + await langfuse.flushAsync(); + } +}); + +async function* traceSpans(langfuse: Langfuse, traceId: string) { + const pages = async function* () { + let { data, meta } = await langfuse.fetchObservations({ traceId, type: 'SPAN' }); + while (true) { + yield data; + if (meta.page == meta.totalPages) { + break; + } + + ({ data, meta } = await langfuse.fetchObservations({ traceId, type: 'SPAN', page: meta.page + 1 })); + } + }; + + for await (const page of pages()) { + for (const item of page) { + yield item; + } + } +} + +async function* traceToolCalls(langfuse: Langfuse, traceId: string) { + const spans = traceSpans(langfuse, traceId); + for await (const span of spans) { + if (!span.name || !span.name || !span.name.startsWith('ai.toolCall')) { + continue; + } + + const toolName = span.name.split(' ')[1]; + const { input, output } = span; + yield { toolName, input, output }; + } +} + +const cmdDatasetPromote = command({ + name: 'enhance', + args: { + datasetName: positional({ type: string, displayName: 'dataset-name' }), + staging: option({ type: optional(string), long: 'staging', short: 's' }) + }, + handler: async ({ datasetName, staging }) => { + const langfuse = getLangfuse(); + const response = await langfuse.getDataset(staging || 'staging'); + const { items } = response; + + // make sure the target dataset exists + await langfuse.createDataset({ name: datasetName }); + for (const item of items) { + const { sourceTraceId } = item; + if (!sourceTraceId) { + console.log(`Skipping item ${item.id} because it has no sourceTraceId`); + continue; + } + + const toolCalls = []; + for await (const toolCall of traceToolCalls(langfuse, sourceTraceId)) { + toolCalls.push(toolCall); + } + + const metadata = { + ...(item.metadata ?? {}), + toolCalls + }; + + await langfuse.createDatasetItem({ + id: item.id + '-enhanced', + datasetName, + expectedOutput: item.expectedOutput, + input: item.input, + metadata, + sourceTraceId: item.id + }); + } + } +}); + +const cmdDatasets = subcommands({ + name: 'datasets', + cmds: { + list: cmdDatasetsList, + download: cmdDatasetDownload, + promote: cmdDatasetPromote, + eval: cmdDatasetEval + } +}); + +const tool = subcommands({ + name: 'tool', + cmds: { + session: cmdSessions, + dataset: cmdDatasets, + ds: cmdDatasets + } +}); + +run(tool, process.argv.slice(2)).catch(console.error); diff --git a/apps/dbagent/scripts/lftool/loader.mjs b/apps/dbagent/scripts/lftool/loader.mjs new file mode 100644 index 00000000..21a45019 --- /dev/null +++ b/apps/dbagent/scripts/lftool/loader.mjs @@ -0,0 +1,15 @@ +import { dirname, resolve as resolvePath } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +export async function resolve(specifier, context, nextResolve) { + if (specifier === 'server-only') { + return { + shortCircuit: true, + url: `file://${resolvePath(__dirname, './mocks/empty.ts')}` + }; + } + + return nextResolve(specifier); +} diff --git a/apps/dbagent/scripts/lftool/mocks/empty.ts b/apps/dbagent/scripts/lftool/mocks/empty.ts new file mode 100644 index 00000000..2c076590 --- /dev/null +++ b/apps/dbagent/scripts/lftool/mocks/empty.ts @@ -0,0 +1,2 @@ +// Empty mock for server-only module +export {}; diff --git a/apps/dbagent/src/app/(main)/projects/[project]/chats/actions.ts b/apps/dbagent/src/app/(main)/projects/[project]/chats/actions.ts index 26157aec..f6cb0452 100644 --- a/apps/dbagent/src/app/(main)/projects/[project]/chats/actions.ts +++ b/apps/dbagent/src/app/(main)/projects/[project]/chats/actions.ts @@ -1,33 +1,17 @@ 'use server'; -import { generateText, Message } from 'ai'; -import { getModelInstance } from '~/lib/ai/agent'; +import { Message } from 'ai'; +import { titleModel } from '~/lib/ai/agent'; import { deleteMessagesByChatIdAfterTimestamp, getMessageById } from '~/lib/db/chats'; import { getUserSessionDBAccess } from '~/lib/db/db'; export async function generateTitleFromUserMessage({ message }: { message: Message }) { - const { text: title } = await generateText({ - model: await getModelInstance('title'), - experimental_telemetry: { - isEnabled: true, - metadata: { - tags: ['internal', 'chat', 'title'] - } - }, - system: `\n - - you will generate a short title based on the first message a user begins a conversation with - - ensure it is not more than 80 characters long - - the title should be a summary of the user's message - - do not use quotes or colons`, - prompt: JSON.stringify(message) - }); - + const { text: title } = await titleModel.generateText({ prompt: JSON.stringify(message) }); return title; } export async function deleteTrailingMessages({ id }: { id: string }) { const dbAccess = await getUserSessionDBAccess(); - const [message] = await getMessageById(dbAccess, { id }); if (!message) { throw new Error('Message not found'); diff --git a/apps/dbagent/src/app/api/chat/route.ts b/apps/dbagent/src/app/api/chat/route.ts index ba83e6e0..73e344f4 100644 --- a/apps/dbagent/src/app/api/chat/route.ts +++ b/apps/dbagent/src/app/api/chat/route.ts @@ -1,11 +1,9 @@ -import { UIMessage, appendResponseMessages, createDataStreamResponse, smoothStream, streamText } from 'ai'; +import { appendResponseMessages, createDataStreamResponse, UIMessage } from 'ai'; import { notFound } from 'next/navigation'; import { NextRequest } from 'next/server'; import { generateTitleFromUserMessage } from '~/app/(main)/projects/[project]/chats/actions'; -import { generateUUID } from '~/components/chat/utils'; -import { getChatSystemPrompt } from '~/lib/ai/agent'; +import { agentModelDeps, chatModel } from '~/lib/ai/agent'; import { getLanguageModel } from '~/lib/ai/providers'; -import { getTools } from '~/lib/ai/tools'; import { deleteChatById, getChatById, getChatsByProject, saveChat } from '~/lib/db/chats'; import { getConnection } from '~/lib/db/connections'; import { getUserSessionDBAccess } from '~/lib/db/db'; @@ -59,34 +57,33 @@ export async function POST(request: Request) { if (!chat) notFound(); const targetDb = getTargetDbPool(connection.connectionString); - const context = getChatSystemPrompt({ cloudProvider: project.cloudProvider, useArtifacts }); + // const context = getChatSystemPrompt({ cloudProvider: project.cloudProvider, useArtifacts }); const model = await getLanguageModel(modelId); return createDataStreamResponse({ execute: async (dataStream) => { - const tools = await getTools({ project, connection, targetDb, useArtifacts, userId, dataStream }); - - const result = streamText({ + const result = await chatModel.streamText({ model: model.instance(), - system: context, + deps: agentModelDeps({ + targetDb, + dbAccess, + connection, + cloudProvider: project.cloudProvider, + userId, + withMCP: true, + withArtifacts: useArtifacts, + dataStream + }), messages, maxSteps: 20, - toolCallStreaming: true, - experimental_transform: smoothStream({ chunking: 'word' }), - experimental_generateMessageId: generateUUID, - experimental_telemetry: { - isEnabled: true, - metadata: { - projectId: connection.projectId, - connectionId: connectionId, - sessionId: id, - model: model.info().id, - userId, - cloudProvider: project.cloudProvider, - tags: ['chat'] - } + metadata: { + projectId: connection.projectId, + connectionId: connectionId, + sessionId: id, + model: model.info().id, + userId, + cloudProvider: project.cloudProvider }, - tools, onFinish: async ({ response }) => { try { const assistantId = getTrailingMessageId({ diff --git a/apps/dbagent/src/components/chat/artifacts/server-document-handler.ts b/apps/dbagent/src/components/chat/artifacts/server-document-handler.ts new file mode 100644 index 00000000..18d21452 --- /dev/null +++ b/apps/dbagent/src/components/chat/artifacts/server-document-handler.ts @@ -0,0 +1,89 @@ +import { DataStreamWriter } from 'ai'; +import { saveDocument } from '~/lib/db/chats'; +import { DBAccess } from '~/lib/db/db'; +import { ArtifactDocument } from '~/lib/db/schema'; +import { ArtifactKind } from './artifact'; + +export interface SaveDocumentProps { + id: string; + title: string; + kind: ArtifactKind; + content: string; + userId: string; +} + +export interface CreateDocumentCallbackProps { + id: string; + title: string; + dataStream: DataStreamWriter; + userId: string; + projectId: string; + dbAccess: DBAccess; +} + +export interface UpdateDocumentCallbackProps { + document: ArtifactDocument; + description: string; + dataStream: DataStreamWriter; + userId: string; + projectId: string; + dbAccess: DBAccess; +} + +export interface DocumentHandler { + kind: T; + onCreateDocument: (args: CreateDocumentCallbackProps) => Promise; + onUpdateDocument: (args: UpdateDocumentCallbackProps) => Promise; +} + +export function createDocumentHandler(config: { + kind: T; + onCreateDocument: (params: CreateDocumentCallbackProps) => Promise; + onUpdateDocument: (params: UpdateDocumentCallbackProps) => Promise; +}): DocumentHandler { + return { + kind: config.kind, + onCreateDocument: async (args: CreateDocumentCallbackProps) => { + const draftContent = await config.onCreateDocument({ + id: args.id, + title: args.title, + dataStream: args.dataStream, + userId: args.userId, + projectId: args.projectId, + dbAccess: args.dbAccess + }); + + await saveDocument(args.dbAccess, { + id: args.id, + title: args.title, + content: draftContent, + kind: config.kind, + projectId: args.projectId, + userId: args.userId + }); + + return; + }, + onUpdateDocument: async (args: UpdateDocumentCallbackProps) => { + const draftContent = await config.onUpdateDocument({ + document: args.document, + description: args.description, + dataStream: args.dataStream, + userId: args.userId, + projectId: args.projectId, + dbAccess: args.dbAccess + }); + + await saveDocument(args.dbAccess, { + id: args.document.id, + title: args.document.title, + content: draftContent, + kind: config.kind, + projectId: args.projectId, + userId: args.userId + }); + + return; + } + }; +} diff --git a/apps/dbagent/src/components/chat/artifacts/server.ts b/apps/dbagent/src/components/chat/artifacts/server.ts index b020b289..f155068a 100644 --- a/apps/dbagent/src/components/chat/artifacts/server.ts +++ b/apps/dbagent/src/components/chat/artifacts/server.ts @@ -1,95 +1,7 @@ -import { DataStreamWriter } from 'ai'; -import { saveDocument } from '~/lib/db/chats'; -import { DBAccess } from '~/lib/db/db'; -import { ArtifactDocument } from '~/lib/db/schema'; -import { ArtifactKind } from './artifact'; +import { DocumentHandler } from './server-document-handler'; import { sheetDocumentHandler } from './sheet/server'; import { textDocumentHandler } from './text/server'; -export interface SaveDocumentProps { - id: string; - title: string; - kind: ArtifactKind; - content: string; - userId: string; -} - -export interface CreateDocumentCallbackProps { - id: string; - title: string; - dataStream: DataStreamWriter; - userId: string; - projectId: string; - dbAccess: DBAccess; -} - -export interface UpdateDocumentCallbackProps { - document: ArtifactDocument; - description: string; - dataStream: DataStreamWriter; - userId: string; - projectId: string; - dbAccess: DBAccess; -} - -export interface DocumentHandler { - kind: T; - onCreateDocument: (args: CreateDocumentCallbackProps) => Promise; - onUpdateDocument: (args: UpdateDocumentCallbackProps) => Promise; -} - -export function createDocumentHandler(config: { - kind: T; - onCreateDocument: (params: CreateDocumentCallbackProps) => Promise; - onUpdateDocument: (params: UpdateDocumentCallbackProps) => Promise; -}): DocumentHandler { - return { - kind: config.kind, - onCreateDocument: async (args: CreateDocumentCallbackProps) => { - const draftContent = await config.onCreateDocument({ - id: args.id, - title: args.title, - dataStream: args.dataStream, - userId: args.userId, - projectId: args.projectId, - dbAccess: args.dbAccess - }); - - await saveDocument(args.dbAccess, { - id: args.id, - title: args.title, - content: draftContent, - kind: config.kind, - projectId: args.projectId, - userId: args.userId - }); - - return; - }, - onUpdateDocument: async (args: UpdateDocumentCallbackProps) => { - const draftContent = await config.onUpdateDocument({ - document: args.document, - description: args.description, - dataStream: args.dataStream, - userId: args.userId, - projectId: args.projectId, - dbAccess: args.dbAccess - }); - - await saveDocument(args.dbAccess, { - id: args.document.id, - title: args.document.title, - content: draftContent, - kind: config.kind, - projectId: args.projectId, - userId: args.userId - }); - - return; - } - }; -} - /* * Use this array to define the document handlers for each artifact kind. */ diff --git a/apps/dbagent/src/components/chat/artifacts/sheet/server.ts b/apps/dbagent/src/components/chat/artifacts/sheet/server.ts index 7ddee6e4..caad60ec 100644 --- a/apps/dbagent/src/components/chat/artifacts/sheet/server.ts +++ b/apps/dbagent/src/components/chat/artifacts/sheet/server.ts @@ -1,23 +1,24 @@ -import { streamObject } from 'ai'; import { z } from 'zod'; -import { getModelInstance } from '~/lib/ai/agent'; +import { commonModel } from '~/lib/ai/agent'; import { sheetPrompt, updateDocumentPrompt } from '~/lib/ai/prompts'; -import { createDocumentHandler } from '../server'; +import { createDocumentHandler } from '../server-document-handler'; + +// Note: To mock createDocumentHandler in tests, you can use a jest mock or a similar mocking library. +// For example, you can define a mock implementation like this: +// jest.mock('~/components/chat/artifacts/server', () => ({ +// createDocumentHandler: jest.fn().mockReturnValue(jest.fn()) +// })); export const sheetDocumentHandler = createDocumentHandler<'sheet'>({ kind: 'sheet', onCreateDocument: async ({ title, dataStream }) => { let draftContent = ''; - const { fullStream } = streamObject({ - model: await getModelInstance('chat'), - experimental_telemetry: { - isEnabled: true, - metadata: { - tags: ['artifact', 'sheet', 'create'] - } - }, + const { fullStream } = await commonModel.streamObject({ system: sheetPrompt, + metadata: { + tags: ['artifact', 'sheet', 'create'] + }, prompt: title, schema: z.object({ csv: z.string().describe('CSV data') @@ -52,19 +53,15 @@ export const sheetDocumentHandler = createDocumentHandler<'sheet'>({ onUpdateDocument: async ({ document, description, dataStream }) => { let draftContent = ''; - const { fullStream } = streamObject({ - model: await getModelInstance('chat'), - experimental_telemetry: { - isEnabled: true, - metadata: { - tags: ['artifact', 'sheet', 'update'] - } - }, + const { fullStream } = await commonModel.streamObject({ system: updateDocumentPrompt(document.content, 'sheet'), prompt: description, schema: z.object({ csv: z.string() - }) + }), + metadata: { + tags: ['artifact', 'sheet', 'update'] + } }); for await (const delta of fullStream) { diff --git a/apps/dbagent/src/components/chat/artifacts/text/server.ts b/apps/dbagent/src/components/chat/artifacts/text/server.ts index c59c52aa..7a8967b3 100644 --- a/apps/dbagent/src/components/chat/artifacts/text/server.ts +++ b/apps/dbagent/src/components/chat/artifacts/text/server.ts @@ -1,26 +1,36 @@ -import { smoothStream, streamText } from 'ai'; -import { getModelInstance } from '~/lib/ai/agent'; +import { AugmentedLanguageModel } from '~/lib/ai/model'; import { updateDocumentPrompt } from '~/lib/ai/prompts'; -import { createDocumentHandler } from '../server'; +import { getProviderRegistry } from '~/lib/ai/providers'; +import { createDocumentHandler } from '../server-document-handler'; + +const titleModel = new AugmentedLanguageModel({ + providerRegistry: getProviderRegistry, + baseModel: 'title', + systemPrompt: 'Write about the given topic. Markdown is supported. Use headings wherever appropriate.', + metadata: { + tags: ['artifact', 'text', 'create'] + } +}); + +type DocumentUpdateDeps = { + content: string | null; +}; + +const documentUpdateModel = new AugmentedLanguageModel({ + providerRegistry: getProviderRegistry, + baseModel: 'chat', + systemPrompt: ({ content }) => updateDocumentPrompt(content, 'text'), + metadata: { + tags: ['artifact', 'text', 'update'] + } +}); export const textDocumentHandler = createDocumentHandler<'text'>({ kind: 'text', onCreateDocument: async ({ title, dataStream }) => { let draftContent = ''; - const { fullStream } = streamText({ - model: await getModelInstance('chat'), - system: 'Write about the given topic. Markdown is supported. Use headings wherever appropriate.', - experimental_transform: smoothStream({ chunking: 'word' }), - experimental_telemetry: { - isEnabled: true, - metadata: { - tags: ['artifact', 'text', 'create'] - } - }, - prompt: title - }); - + const { fullStream } = await titleModel.streamText({ prompt: title }); for await (const delta of fullStream) { const { type } = delta; @@ -41,16 +51,8 @@ export const textDocumentHandler = createDocumentHandler<'text'>({ onUpdateDocument: async ({ document, description, dataStream }) => { let draftContent = ''; - const { fullStream } = streamText({ - model: await getModelInstance('chat'), - system: updateDocumentPrompt(document.content, 'text'), - experimental_transform: smoothStream({ chunking: 'word' }), - experimental_telemetry: { - isEnabled: true, - metadata: { - tags: ['artifact', 'text', 'update'] - } - }, + const { fullStream } = await documentUpdateModel.streamText({ + deps: { content: document.content }, prompt: description, experimental_providerMetadata: { openai: { diff --git a/apps/dbagent/src/components/monitoring/actions.ts b/apps/dbagent/src/components/monitoring/actions.ts index 237ed1ec..34e1fd08 100644 --- a/apps/dbagent/src/components/monitoring/actions.ts +++ b/apps/dbagent/src/components/monitoring/actions.ts @@ -1,8 +1,7 @@ 'use server'; -import { openai } from '@ai-sdk/openai'; -import { generateText } from 'ai'; import { auth } from '~/auth'; +import { commonModel } from '~/lib/ai/agent'; import { getUserDBAccess, getUserSessionDBAccess } from '~/lib/db/db'; import { getScheduleRuns } from '~/lib/db/schedule-runs'; import { @@ -21,17 +20,12 @@ export async function generateCronExpression(description: string): Promise { try { await requireUserSession(); + const userId = await requireUserSession(); const dbAccess = await getUserSessionDBAccess(); const connection = await getConnection(dbAccess, connectionId); if (!connection) { throw new Error('Connection not found'); } - const targetDb = getTargetDbPool(connection.connectionString); - const dbTools = getDBSQLTools(targetDb); + const chatTools = await chatModel.getTools( + agentModelDeps({ + targetDb: getTargetDbPool(connection.connectionString), + dbAccess, + connection, + userId, + cloudProvider: 'aws', + withArtifacts: false, + withMCP: false + }) + ); - const clusterTools = getDBClusterTools(dbAccess, connection, 'aws'); // Default to AWS for now - const playbookToolset = getPlaybookToolset(dbAccess, connection.projectId); - const mergedTools = mergeToolsets(commonToolset, playbookToolset, dbTools, clusterTools); - - return Object.entries(mergedTools).map(([name, tool]) => ({ + return Object.entries(chatTools).map(([name, tool]) => ({ name, description: tool.description || 'No description available', isBuiltIn: true diff --git a/apps/dbagent/src/evals/chat/judge.eval.ts b/apps/dbagent/src/evals/chat/judge.eval.ts index a66206d2..b00334bd 100644 --- a/apps/dbagent/src/evals/chat/judge.eval.ts +++ b/apps/dbagent/src/evals/chat/judge.eval.ts @@ -1,110 +1,93 @@ -import { generateObject } from 'ai'; import fs from 'fs'; import path from 'path'; import { afterAll, beforeAll, describe } from 'vitest'; -import { z } from 'zod'; -import { evalChat } from '~/evals/lib/chat-runner'; -import { getModelInstance } from '~/lib/ai/agent'; +import { AgentModelDeps, chatModel, getAgentMockDeps, getModelInstance } from '~/lib/ai/agent'; +import { Tool } from '~/lib/ai/model'; import { env } from '~/lib/env/eval'; -import { PostgresConfig, runSql, startPostgresContainer } from '../lib/eval-docker-db'; -import { mockGetConnectionInfo, mockGetProjectsById } from '../lib/mocking'; -import { evalResultEnum } from '../lib/schemas'; +import { TableStat } from '~/lib/targetdb/db'; +import { turnFromResponse } from '../lib/chat-runner'; +import { evalTurn, LLMTurn, setEvalModel } from '../lib/llmcheck'; +import { conciseAnswerMetric, finalAnswerMetric, Metric } from '../lib/llmcheck/metrics'; import { ensureTraceFolderExistsExpect } from '../lib/test-id'; -import { stepToHuman } from '../lib/trace'; import { EvalCase, runEvals } from '../lib/vitest-helpers'; -let dbConfig: PostgresConfig; beforeAll(async () => { - mockGetProjectsById(); - mockGetConnectionInfo(); - try { - dbConfig = await startPostgresContainer({ port: 9888 }); - await runSql( - `create table dogs ( - id serial primary key, - name text - );`, - dbConfig - ); - } catch (error) { - console.error('Error starting postgres container', error); - throw error; - } + const model = await getModelInstance(env.JUDGE_MODEL); + setEvalModel(model); }); afterAll(async () => { - await dbConfig.close(); + setEvalModel(undefined); }); -type LLMJudgeConfig = { - prompt: (args: { input: string; steps: string[]; finalAnswer: string }) => string; - name: string; -}; - -const finalAnswerJudge = (expectedAnswer = ''): LLMJudgeConfig => ({ - name: 'final_answer', - prompt: ({ input, finalAnswer }) => ` - The following question was answered by an expert in PostgreSQL and database administration: - ${input} - ${finalAnswer} - ${expectedAnswer ? `${expectedAnswer}` : ''} - Please determine whether expert passed or failed at answering the question correctly and accurately. Please provied a critique of how the answer could be improved or does not match the response of an expert in PostgreSQl and database administration. - ` -}); +type LLMJudgeEval = EvalCase & { turn: LLMTurn; judge: Metric }; -const conciseAnswerJudge: LLMJudgeConfig = { - name: 'concise', - prompt: ({ input, finalAnswer }) => ` - The following question was answered by an expert in PostgreSQL and database administration: - ${input} - ${finalAnswer} +const conciseAnswer = conciseAnswerMetric(); - Please determine whether expert passed or failed at answering the question concisely with no extra information offered unless it's explicitly asked for in the question or it's almost certain from the question the user would want it. Please provied a critique of how the answer could be improved or does not match the resp` +// Mock the agent backend services. The getAgentMockDeps creates +// mocks that will raise an error when the tools are called. +// Set some default tool response for the eval via toolMocks. `toolMocks` gets +// the mocked tools as used by the agent and modifies the responsess for a +// selected set of tools. +const deps = getAgentMockDeps({}); +const toolMocks = (tools: Record>) => { + tools.getTablesInfo!.execute = async () => { + const data: TableStat[] = [ + { + name: 'dogs', + schema: 'public', + rows: 100, + size: '100', + seqScans: 100, + idxScans: 100, + nTupIns: 100, + nTupUpd: 100, + nTupDel: 100 + } + ]; + return data; + }; + return tools; }; -type LLMJudgeEval = EvalCase & { prompt: string; judge: LLMJudgeConfig }; +describe.concurrent('judge', async () => { + const evalCases: LLMJudgeEval[] = ( + await Promise.all( + [ + { + id: 'tables_in_db', + prompt: 'What tables do I have in my db?', + judges: [finalAnswerMetric('dogs'), conciseAnswer] + }, + { + id: 'tables_in_db_how_many', + prompt: 'How many tables do I have in my db?', + judges: [finalAnswerMetric('1'), conciseAnswer] + } + ].map(async (evalCase) => { + const result = await chatModel.generateText({ + prompt: evalCase.prompt, + deps, + maxSteps: 20, + tools: toolMocks + }); -describe.concurrent('judge', () => { - const evalCases: LLMJudgeEval[] = [ - { - id: 'tables_in_db', - prompt: 'What tables do I have in my db?', - judges: [finalAnswerJudge('dogs'), conciseAnswerJudge] - }, - { - id: 'tables_in_db_how_many', - prompt: 'How many tables do I have in my db?', - judges: [finalAnswerJudge('1'), conciseAnswerJudge] - } - ].flatMap((evalCase) => - evalCase.judges.map((judge) => ({ - id: `${judge.name}_${evalCase.id}`, - prompt: evalCase.prompt, - judge: judge - })) - ); + return evalCase.judges.map((judge) => ({ + id: `${judge.name()}_${evalCase.id}`, + turn: turnFromResponse(evalCase.prompt, result), + judge + })) as LLMJudgeEval[]; + }) + ) + ).flat(); - runEvals(evalCases, async ({ prompt, judge }, { expect }) => { + runEvals(evalCases, async ({ turn, judge }, { expect }) => { const traceFolder = ensureTraceFolderExistsExpect(expect); - const result = await evalChat({ - messages: [{ role: 'user', content: prompt }], - dbConnection: dbConfig.connectionString, - expect - }); - const humanSteps = result.steps.map(stepToHuman); - const finalAnswer = result.text; - const { object: judgeResponse } = await generateObject({ - model: await getModelInstance(env.JUDGE_MODEL), - schema: z.object({ - result: evalResultEnum, - critique: z.string() - }), - prompt: judge.prompt({ input: prompt, steps: humanSteps, finalAnswer }) - }); - const judgeResponseFile = path.join(traceFolder, 'judgeResponse.txt'); - fs.writeFileSync(judgeResponseFile, judgeResponse.critique); + const measure = await evalTurn(turn, judge); - expect(judgeResponse.result).toEqual('passed'); + const evalFile = path.join(traceFolder, 'eval.txt'); + fs.writeFileSync(evalFile, measure.reason ?? ''); + expect(measure.success).toBe(true); }); }); diff --git a/apps/dbagent/src/evals/chat/tests.eval.ts b/apps/dbagent/src/evals/chat/tests.eval.ts index becf04cd..ef07289a 100644 --- a/apps/dbagent/src/evals/chat/tests.eval.ts +++ b/apps/dbagent/src/evals/chat/tests.eval.ts @@ -1,37 +1,38 @@ -import { afterAll, beforeAll, describe } from 'vitest'; -import { evalChat } from '~/evals/lib/chat-runner'; -import { PostgresConfig, runSql, startPostgresContainer } from '../lib/eval-docker-db'; -import { mockGetConnectionInfo, mockGetProjectsById } from '../lib/mocking'; +import { describe } from 'vitest'; +import { evalChat, turnFromResponse } from '~/evals/lib/chat-runner'; +import { TableStat } from '~/lib/targetdb/db'; +import { evalTurn } from '../lib/llmcheck'; +import { regexResponseMetric } from '../lib/llmcheck/metrics'; import { EvalCase, runEvals } from '../lib/vitest-helpers'; -let dbConfig: PostgresConfig; -beforeAll(async () => { - mockGetProjectsById(); - mockGetConnectionInfo(); - try { - dbConfig = await startPostgresContainer({ port: 9889 }); - await runSql( - `create table dogs ( - id serial primary key, - name text - );`, - dbConfig - ); - } catch (error) { - console.error('Error starting postgres container', error); - throw error; - } -}); - -afterAll(async () => { - await dbConfig.close(); -}); - type Test = EvalCase & { prompt: string; finalAnswerRegex: RegExp; }; +const toolCalls = { + findTableSchema: async (_table: string) => { + return 'public'; + }, + + getTablesInfo: async () => { + const data: TableStat[] = [ + { + name: 'dogs', + schema: 'public', + rows: 100, + size: '24 kB', + seqScans: 100, + idxScans: 100, + nTupIns: 100, + nTupUpd: 100, + nTupDel: 100 + } + ]; + return data; + } +}; + describe.concurrent('test', () => { const evalCases: Test[] = [ { @@ -51,14 +52,11 @@ describe.concurrent('test', () => { } ]; runEvals(evalCases, async ({ prompt, finalAnswerRegex }, { expect }) => { - const result = await evalChat({ - messages: [{ role: 'user', content: prompt }], - dbConnection: dbConfig.connectionString, - expect - }); - - const finalAnswer = result.text; + const result = await evalChat({ prompt, expect, toolCalls }); + const turn = turnFromResponse(prompt, result); + const metric = regexResponseMetric(finalAnswerRegex); + const measure = await evalTurn(turn, metric); - expect(finalAnswer).toMatch(finalAnswerRegex); + expect(measure.success).toBe(true); }); }); diff --git a/apps/dbagent/src/evals/chat/toolChoice.eval.ts b/apps/dbagent/src/evals/chat/toolChoice.eval.ts index f645c3c3..c8933092 100644 --- a/apps/dbagent/src/evals/chat/toolChoice.eval.ts +++ b/apps/dbagent/src/evals/chat/toolChoice.eval.ts @@ -1,6 +1,8 @@ import { afterAll, beforeAll, describe } from 'vitest'; -import { evalChat } from '~/evals/lib/chat-runner'; +import { evalChat, turnFromResponse } from '~/evals/lib/chat-runner'; import { PostgresConfig, runSql, startPostgresContainer } from '../lib/eval-docker-db'; +import { evalTurn } from '../lib/llmcheck'; +import { toolChoiceMetric } from '../lib/llmcheck/metrics'; import { mockGetConnectionInfo, mockGetProjectsById } from '../lib/mocking'; import { EvalCase, runEvals } from '../lib/vitest-helpers'; @@ -171,12 +173,21 @@ describe.concurrent('tool_choice', () => { expect }); - const allToolCalls = result.steps.flatMap((step) => step.toolCalls); - const toolCallNames = allToolCalls.map((toolCall) => toolCall.toolName); - expect(toolCallNames).toEqual(expect.arrayContaining(toolCalls)); - const unexpectedToolCalls = toolCallNames.filter((toolCall) => !toolCalls.includes(toolCall)); - if (!allowOtherTools) { - expect(unexpectedToolCalls).toEqual([]); - } + const turn = { + ...turnFromResponse(prompt, result), + expectedTools: toolCalls.map((toolCall) => ({ + name: toolCall + })) + }; + + const measure = await evalTurn( + turn, + toolChoiceMetric({ + allowMissing: false, + allowOthers: allowOtherTools + }) + ); + + expect(measure.success).toBe(true); }); }); diff --git a/apps/dbagent/src/evals/lib/chat-runner.ts b/apps/dbagent/src/evals/lib/chat-runner.ts index 3fab4297..4806dd24 100644 --- a/apps/dbagent/src/evals/lib/chat-runner.ts +++ b/apps/dbagent/src/evals/lib/chat-runner.ts @@ -1,21 +1,67 @@ -import { CoreMessage, generateText, Message as SDKMessage } from 'ai'; +import { CoreMessage, Message as SDKMessage } from 'ai'; +import { Pool } from 'pg'; import { ExpectStatic } from 'vitest'; import { generateUUID } from '~/components/chat/utils'; -import { getChatSystemPrompt, getModelInstance } from '~/lib/ai/agent'; -import { getTools } from '~/lib/ai/tools'; +import { AgentModelDeps, agentModelDeps, chatModel, getAgentMockDeps } from '~/lib/ai/agent'; +import { Tool } from '~/lib/ai/model'; +import { getUserDBAccess } from '~/lib/db/db'; import { Connection, Project } from '~/lib/db/schema'; -import { env } from '~/lib/env/eval'; import { getTargetDbPool } from '~/lib/targetdb/db'; -import { traceVercelAiResponse } from './trace'; +import { LLMTurn } from './llmcheck'; +import { GenerateTextResponse, traceVercelAiResponse } from './trace'; + +export const turnFromResponse = (prompt: string, response: GenerateTextResponse): LLMTurn => { + const allToolCalls = response.steps.flatMap((step) => { + console.log(`step ${step.usage.totalTokens}`); + + return step.toolResults.flatMap((toolResult: any) => { + console.log(` toolResult: ${JSON.stringify(toolResult, null, 2)}`); + + if ('type' in toolResult && toolResult.type === 'tool-result') { + // generateText format + return [ + { + name: toolResult.toolName, + inputs: toolResult.args, + output: toolResult.result + } + ]; + } + return Object.values(toolResult).map((toolCall: any) => { + const transformed = { + name: toolCall.toolName, + inputs: toolCall.args, + output: toolCall.result + }; + console.log(` transformed: ${JSON.stringify(transformed)}`); + return transformed; + }); + }); + }); + + return { + input: prompt, + output: response.text, + toolCalls: allToolCalls + }; +}; export const evalChat = async ({ + model, messages, + prompt, + deps, dbConnection, - expect + expect, + toolCalls }: { - messages: CoreMessage[] | Omit[]; - dbConnection: string; + model?: string; + prompt?: string; + messages?: CoreMessage[] | Omit[]; + deps?: AgentModelDeps; + dbConnection?: string; expect: ExpectStatic; + toolCalls?: Record PromiseLike>; }) => { const project: Project = { id: 'projectId', @@ -23,27 +69,59 @@ export const evalChat = async ({ cloudProvider: 'aws' }; - const connection: Connection = { - id: generateUUID(), - name: 'evaldb', - connectionString: dbConnection, - projectId: project.id, - isDefault: true - }; + let targetDb: Pool | undefined; + if (!deps) { + if (dbConnection) { + const connection: Connection = { + id: generateUUID(), + name: 'evaldb', + connectionString: dbConnection, + projectId: project.id, + isDefault: true + }; + + targetDb = getTargetDbPool(connection.connectionString); + const userId = 'evalUser'; + const dbAccess = await getUserDBAccess(userId); + deps = agentModelDeps({ + withMCP: true, + targetDb, + dbAccess, + connection, + cloudProvider: project.cloudProvider, + userId, + withArtifacts: false + }); + } else { + deps = getAgentMockDeps({}); + } + } - const targetDb = getTargetDbPool(connection.connectionString); try { - const tools = await getTools({ project, connection, targetDb, userId: 'evalUser' }); - const response = await generateText({ - model: await getModelInstance(env.CHAT_MODEL), - system: getChatSystemPrompt({ cloudProvider: project.cloudProvider }), + const response = await chatModel.generateText({ + model: model, maxSteps: 20, - tools, - messages + deps, + messages, + prompt, + tools: (tools: Record>) => { + if (toolCalls) { + for (const [name, execute] of Object.entries(toolCalls)) { + const tool = tools[name]; + if (!tool) { + throw new Error(`Tool ${name} not found`); + } + tool.execute = execute; + } + } + return tools; + } }); traceVercelAiResponse(response, expect); return response; } finally { - await targetDb.end(); + if (targetDb) { + await targetDb.end(); + } } }; diff --git a/apps/dbagent/src/evals/lib/llmcheck/dataset.ts b/apps/dbagent/src/evals/lib/llmcheck/dataset.ts new file mode 100644 index 00000000..7e9e5963 --- /dev/null +++ b/apps/dbagent/src/evals/lib/llmcheck/dataset.ts @@ -0,0 +1,32 @@ +import { Chat, LLMTurn } from './types'; + +export type DatasetItem = LLMTurn | Chat; +export type Dataset = AsyncIterable; + +import { promises as fs } from 'fs'; + +import ndjson from 'ndjson'; + +export async function writeToJSONFile(dataset: Dataset, path: string) { + const file = await fs.open(path, 'w'); + try { + const writer = file.createWriteStream().pipe(ndjson.stringify()); + for await (const item of dataset) { + writer.write(item); + } + } finally { + await file.close(); + } +} + +export async function* readFromJSONFile(path: string): AsyncGenerator { + const file = await fs.open(path, 'r'); + try { + const reader = file.createReadStream().pipe(ndjson.parse()); + for await (const item of reader) { + yield item; + } + } finally { + await file.close(); + } +} diff --git a/apps/dbagent/src/evals/lib/llmcheck/index.ts b/apps/dbagent/src/evals/lib/llmcheck/index.ts new file mode 100644 index 00000000..0a3b4a3f --- /dev/null +++ b/apps/dbagent/src/evals/lib/llmcheck/index.ts @@ -0,0 +1,65 @@ +import { LanguageModel } from 'ai'; +import { Measure, Metric } from './metrics/types'; +import { Chat, LLMTurn, LLMTurnField } from './types'; + +export * from './types'; + +let evalModel: LanguageModel | undefined = undefined; + +export function setEvalModel(model: LanguageModel | undefined) { + evalModel = model; +} + +export function getEvalModel(): LanguageModel { + if (!evalModel) { + throw new Error('Eval model not set'); + } + return evalModel; +} + +export async function evalAllTurn( + turn: LLMTurn, + metrics: Record | Metric[] +): Promise> { + const usedMetrics: [string, Metric][] = Array.isArray(metrics) + ? metrics.filter(isMeasureTurnMetric).map((metric) => [metric.name(), metric]) + : Object.entries(metrics).filter(([_, metric]) => isMeasureTurnMetric(metric)); + if (usedMetrics.length === 0) { + throw new Error('No metrics provided'); + } + + for (const [name, metric] of usedMetrics) { + if (!turnHasFields(turn, metric.requiredParams())) { + throw new Error(`Metric ${name} requires fields ${metric.requiredParams().join(', ')}`); + } + } + + const result: Record = {}; + for (const [name, metric] of usedMetrics) { + result[name] = await metric.measureTurn!(turn); + } + + return result; +} + +export async function evalTurn(turn: LLMTurn, metric: Metric): Promise { + if (!isMeasureTurnMetric(metric)) { + throw new Error(`Metric ${metric.name()} is not a measure turn metric`); + } + if (!turnHasFields(turn, metric.requiredParams())) { + throw new Error(`Metric ${metric.name()} requires fields ${metric.requiredParams().join(', ')}`); + } + return metric.measureTurn!(turn); +} + +function isMeasureTurnMetric(metric: Metric) { + return 'measureTurn' in metric && metric.measureTurn; +} + +export function turnHasFields(turn: LLMTurn, fields: LLMTurnField[]) { + return fields.every((field) => field in turn); +} + +export function chatHasFields(chat: Chat, fields: LLMTurnField[]) { + return chat.turns.every((turn) => turnHasFields(turn, fields)); +} diff --git a/apps/dbagent/src/evals/lib/llmcheck/metrics/concise.ts b/apps/dbagent/src/evals/lib/llmcheck/metrics/concise.ts new file mode 100644 index 00000000..2450aff5 --- /dev/null +++ b/apps/dbagent/src/evals/lib/llmcheck/metrics/concise.ts @@ -0,0 +1,28 @@ +import { BoolMeasure, Metric } from './types'; +import { EvalPassResult, JudgeEvalModel, evalPassResultSchema, simpleJudgeMetric } from './util'; + +export function conciseAnswerMetric(model?: JudgeEvalModel): Metric { + return simpleJudgeMetric({ + model, + config: { + name: 'concise', + schema: evalPassResultSchema, + prompt: ({ input, output }) => ` + The following question was answered by an expert in PostgreSQL and database administration: + ${input} + ${output} + + Please determine whether expert passed or failed at answering the question + concisely with no extra information offered unless it's explicitly asked for + in the question or it's almost certain from the question the user would + want it. Please provide a critique of how the answer could be improved or + does not match the response of an expert in PostgreSQL and database + administration.`, + result: (result) => ({ + type: 'bool', + success: result.result === 'passed', + reason: result.critique + }) + } + }); +} diff --git a/apps/dbagent/src/evals/lib/llmcheck/metrics/final-answer.ts b/apps/dbagent/src/evals/lib/llmcheck/metrics/final-answer.ts new file mode 100644 index 00000000..108b6142 --- /dev/null +++ b/apps/dbagent/src/evals/lib/llmcheck/metrics/final-answer.ts @@ -0,0 +1,28 @@ +import { BoolMeasure, Metric } from './types'; +import { EvalPassResult, evalPassResultSchema, JudgeEvalModel, simpleJudgeMetric } from './util'; + +export function finalAnswerMetric(expectedResult?: string, model?: JudgeEvalModel): Metric { + return simpleJudgeMetric({ + model, + config: { + name: 'finalAnswer', + schema: evalPassResultSchema, + prompt: ({ input, output, expectedOutput }) => { + const expected = expectedOutput ?? expectedResult; + + return ` + The following question was answered by an expert in PostgreSQL and database administration: + ${input} + ${output} + ${expected ? `${expected}` : ''} + Please determine whether expert passed or failed at answering the question correctly and accurately. Please provied a critique of how the answer could be improved or does not match the response of an expert in PostgreSQl and database administration. + `; + }, + result: (result) => ({ + type: 'bool', + success: result.result === 'passed', + reason: result.critique + }) + } + }); +} diff --git a/apps/dbagent/src/evals/lib/llmcheck/metrics/index.ts b/apps/dbagent/src/evals/lib/llmcheck/metrics/index.ts new file mode 100644 index 00000000..bef16271 --- /dev/null +++ b/apps/dbagent/src/evals/lib/llmcheck/metrics/index.ts @@ -0,0 +1,5 @@ +export * from './concise'; +export * from './final-answer'; +export * from './regex-response'; +export * from './toolchoice'; +export * from './types'; diff --git a/apps/dbagent/src/evals/lib/llmcheck/metrics/regex-response.ts b/apps/dbagent/src/evals/lib/llmcheck/metrics/regex-response.ts new file mode 100644 index 00000000..b069cb71 --- /dev/null +++ b/apps/dbagent/src/evals/lib/llmcheck/metrics/regex-response.ts @@ -0,0 +1,32 @@ +import { Measure, Metric, reportBool } from '../metrics'; +import { Chat, LLMTurn } from '../types'; + +export function regexResponseMetric(regex: RegExp): Metric { + return { + name: () => 'regexResponse', + requiredParams: () => ['output'], + measureTurn: async (turn: LLMTurn) => measureTurn(regex, turn), + measureChat: async (chat: Chat) => measureChat(regex, chat) + }; +} + +function measureTurn(regex: RegExp, turn: LLMTurn): Measure { + return measure(regex, turn.output); +} + +function measureChat(regex: RegExp, chat: Chat): Measure { + if (!chat.turns || chat.turns.length === 0) { + return reportBool(false, 'No turns in the chat'); + } + const lastTurn = chat.turns[chat.turns.length - 1]!; + return measure(regex, lastTurn.output); +} + +function measure(regex: RegExp, text: string): Measure { + const match = text.match(regex); + if (match) { + return reportBool(true, `The text matches the regex ${regex.source}`); + } else { + return reportBool(false, `The text does not match the regex ${regex.source}`); + } +} diff --git a/apps/dbagent/src/evals/lib/llmcheck/metrics/toolchoice.ts b/apps/dbagent/src/evals/lib/llmcheck/metrics/toolchoice.ts new file mode 100644 index 00000000..0f25079a --- /dev/null +++ b/apps/dbagent/src/evals/lib/llmcheck/metrics/toolchoice.ts @@ -0,0 +1,51 @@ +import { LLMTurn, ToolCall } from '../types'; +import { Measure, Metric, reportScoreBool } from './types'; + +export type ToolChoiceProps = { + expectedToolCalls?: ToolCall[]; + allowOthers: boolean; + allowMissing: boolean; +}; + +export function toolChoiceMetric(props: ToolChoiceProps): Metric { + return { + name: () => 'toolChoice', + requiredParams: () => (props.expectedToolCalls ? ['toolCalls'] : ['toolCalls', 'expectedTools']), + measureTurn: async (turn: LLMTurn) => measureTurn(turn, props) + }; +} + +// toolChoice uses the expectedTools from the LLMTurn configuration +export const toolChoice = toolChoiceMetric({ allowOthers: false, allowMissing: false }); + +function measureTurn(turn: LLMTurn, { expectedToolCalls, allowOthers, allowMissing }: ToolChoiceProps): Measure { + const expectedToolsSet = new Set([ + ...(turn.expectedTools?.map((tool) => tool.name) ?? []), + ...(expectedToolCalls?.map((tool) => tool.name) ?? []) + ]); + const actualToolsSet = new Set(turn.toolCalls?.map((tool) => tool.name) ?? []); + + const missing = [...expectedToolsSet].filter((tool) => !actualToolsSet.has(tool)).sort(); + const others = [...actualToolsSet].filter((tool) => !expectedToolsSet.has(tool)).sort(); + + const errorReport: string[] = []; + let success = true; + if (missing.length > 0) { + errorReport.push(`Missing tools: ${missing.join(', ')}`); + if (!allowMissing) { + success = false; + } + } + if (others.length > 0) { + errorReport.push(`Unexpected tools: ${others.join(', ')}`); + if (!allowOthers) { + success = false; + } + } + + const total = expectedToolsSet.size; + const expectedCount = total - errorReport.length; + const score = total > 0 ? expectedCount / total : 0; + + return reportScoreBool(score, success, errorReport.join('\n')); +} diff --git a/apps/dbagent/src/evals/lib/llmcheck/metrics/types.ts b/apps/dbagent/src/evals/lib/llmcheck/metrics/types.ts new file mode 100644 index 00000000..481c2028 --- /dev/null +++ b/apps/dbagent/src/evals/lib/llmcheck/metrics/types.ts @@ -0,0 +1,49 @@ +import { Chat, LLMTurn, LLMTurnField } from '../types'; + +export type Metric = { + name: () => string; + requiredParams: () => LLMTurnField[]; + measureTurn?: (turn: LLMTurn) => PromiseLike; + measureChat?: (chat: Chat) => PromiseLike; +}; + +export type Measure = ScoreMeasure | BoolMeasure; + +export type BoolMeasure = { + type: 'bool'; + success: boolean; + reason?: string; +}; + +export function reportBool(success: boolean, reason?: string): Measure { + return { + type: 'bool', + success, + reason + }; +} + +export type ScoreMeasure = { + type: 'score'; + success: boolean; + score: number; + reason?: string; +}; + +export function reportScore(score: number, min_success: number, reason?: string): Measure { + return { + type: 'score', + success: score >= min_success, + score, + reason + }; +} + +export function reportScoreBool(score: number, success: boolean, reason?: string): Measure { + return { + type: 'score', + success, + score, + reason + }; +} diff --git a/apps/dbagent/src/evals/lib/llmcheck/metrics/util.ts b/apps/dbagent/src/evals/lib/llmcheck/metrics/util.ts new file mode 100644 index 00000000..3e3e7396 --- /dev/null +++ b/apps/dbagent/src/evals/lib/llmcheck/metrics/util.ts @@ -0,0 +1,98 @@ +import { generateObject, LanguageModel } from 'ai'; + +import { z } from 'zod'; +import { getEvalModel } from '..'; +import { Chat, LLMTurn } from '../types'; +import { Measure, Metric } from './types'; + +export const evalPassResultSchema = z.object({ + result: z.enum(['passed', 'failed']), + critique: z.string() +}); + +export type EvalPassResult = z.infer; + +export const evalScoreResultSchema = z.object({ + score: z.number(), + critique: z.string() +}); + +export type EvalScoreResult = z.infer; + +export type LLMJudgeConfig = { + name: string; + schema: z.ZodTypeAny; + prompt: (args: { input: string; steps: string[]; output: string; expectedOutput?: string }) => string; + result?: (result: T) => R; +}; + +export type JudgeEvalModel = LanguageModel | (() => Promise); + +export function simpleJudgeMetric({ + model, + config +}: { + model?: JudgeEvalModel; + config: LLMJudgeConfig; +}): Metric { + return { + name: () => config.name, + requiredParams: () => ['input', 'output'], + measureTurn: (turn) => measureTurn({ model, config, turn }), + measureChat: (chat) => measureChat({ model, config, chat }) + }; +} + +async function measureTurn({ + model, + config, + turn +}: { + model?: JudgeEvalModel; + config: LLMJudgeConfig; + turn: LLMTurn; +}): Promise { + return await measure({ model, config, input: turn.input, output: turn.output }); +} + +async function measureChat({ + model, + config, + chat +}: { + model?: JudgeEvalModel; + config: LLMJudgeConfig; + chat: Chat; +}): Promise { + if (chat.turns.length === 0) { + throw new Error('Chat has no turns'); + } + const initialTurn = chat.turns[0]!; + const finalTurn = chat.turns[chat.turns.length - 1]!; + return await measure({ model, config, input: initialTurn.input, output: finalTurn.output }); +} + +async function measure({ + model, + config, + input, + output, + expectedOutput +}: { + model?: JudgeEvalModel; + config: LLMJudgeConfig; + input: string; + output: string; + expectedOutput?: string; +}): Promise { + const prompt = config.prompt({ input, steps: [], output, expectedOutput }); + + const evalModel = model ? (typeof model === 'function' ? await model() : model) : getEvalModel(); + const { object: judgeResponse } = await generateObject({ + model: evalModel, + schema: config.schema, + prompt + }); + + return config.result ? config.result(judgeResponse) : (judgeResponse as R); +} diff --git a/apps/dbagent/src/evals/lib/llmcheck/types.ts b/apps/dbagent/src/evals/lib/llmcheck/types.ts new file mode 100644 index 00000000..f81e851d --- /dev/null +++ b/apps/dbagent/src/evals/lib/llmcheck/types.ts @@ -0,0 +1,31 @@ +export type Chat = { + id?: string; + turns: LLMTurn[]; + name?: string; +}; + +export type LLMTurnField = keyof LLMTurn; + +export type LLMTurn = { + id?: string; + name?: string; + input: string; + output: string; + expectedOutput?: string; + reasoning?: string; + tokenCost?: number; + durationMs?: number; + context?: LLMTurn[]; + toolCalls?: ToolCall[]; + expectedTools?: ToolCall[]; +}; + +export type ToolCallFields = keyof ToolCall; + +export type ToolCall = { + id?: string; + name: string; + description?: string; + inputs?: any[]; + output?: any; +}; diff --git a/apps/dbagent/src/evals/lib/schemas.ts b/apps/dbagent/src/evals/lib/schemas.ts index 08e59d4a..c6d200fc 100644 --- a/apps/dbagent/src/evals/lib/schemas.ts +++ b/apps/dbagent/src/evals/lib/schemas.ts @@ -2,8 +2,13 @@ import { z } from 'zod'; import { evalEnvSchema } from '../../lib/env/eval'; export const evalResultSchema = z - .object({ id: z.string(), result: z.enum(['passed', 'failed']), env: evalEnvSchema }) + .object({ + id: z.string(), + result: z.enum(['passed', 'failed']), + env: evalEnvSchema + }) .strict(); + export type EvalResult = z.infer; export const evalResultEnum = z.enum(['passed', 'failed']); diff --git a/apps/dbagent/src/evals/lib/trace.ts b/apps/dbagent/src/evals/lib/trace.ts index e32fd3bd..777928ce 100644 --- a/apps/dbagent/src/evals/lib/trace.ts +++ b/apps/dbagent/src/evals/lib/trace.ts @@ -4,7 +4,7 @@ import path from 'path'; import { ExpectStatic } from 'vitest'; import { ensureTraceFolderExistsExpect } from './test-id'; -type GenerateTextResponse = Awaited>; +export type GenerateTextResponse = Awaited>; const toolResultToHuman = (toolResult: any) => { return ` @@ -31,12 +31,32 @@ const parseRequestBody = (response: GenerateTextResponse) => { const getSystemPromptFromResponse = (response: GenerateTextResponse) => { const body = parseRequestBody(response); - return body.system[0].text; + const system = + body.system && body.system.length > 0 + ? getResponseMessageText(body.system[0]) + : body.messages[0].role === 'system' + ? getResponseMessageText(body.messages[0].content) + : ''; + return system; }; const getUserPromptFromResponse = (response: GenerateTextResponse) => { const body = parseRequestBody(response); - return body.messages[0].content[0].text; + for (const message of body.messages) { + if (message.role === 'user') { + return getResponseMessageText(message.content); + } + } + return ''; +}; + +const getResponseMessageText = (content: any) => { + if (typeof content === 'string') { + return content; + } else if (Array.isArray(content)) { + return content[0].text; + } + return ''; }; export const traceVercelAiResponse = (response: GenerateTextResponse, expect: ExpectStatic) => { diff --git a/apps/dbagent/src/lib/ai/agent.ts b/apps/dbagent/src/lib/ai/agent.ts index 387e5821..231bf4a6 100644 --- a/apps/dbagent/src/lib/ai/agent.ts +++ b/apps/dbagent/src/lib/ai/agent.ts @@ -1,22 +1,204 @@ -import { LanguageModel } from 'ai'; -import { CloudProvider } from '../db/schema'; -import { artifactsPrompt, chatSystemPrompt, commonSystemPrompt, monitoringSystemPrompt } from './prompts'; -import { getLanguageModel, getLanguageModelWithFallback, ModelWithFallback } from './providers'; +import { DataStreamWriter, LanguageModel } from 'ai'; +import { Pool } from 'pg'; +import { ArtifactsService, projectArtifactService } from '~/lib/tools/artifacts'; +import { DBAccess } from '../db/db'; +import { CloudProvider, Connection } from '../db/schema'; +import { AugmentedLanguageModel, ToolSet } from './model'; +import { + artifactsPrompt, + awsCloudProviderPrompt, + chatSystemPrompt, + commonSystemPrompt, + gcpCloudProviderPrompt, + monitoringSystemPrompt +} from './prompts'; +import { getLanguageModel, getLanguageModelWithFallback, getProviderRegistry, ModelWithFallback } from './providers'; +import { commonToolset } from './tools'; +import { getArtifactTools } from './tools/artifacts'; +import { ClusterService, getDBClusterTools, getProjectClusterService } from './tools/cluster'; +import { DBService, getDBSQLTools, targetDBService } from './tools/db'; +import { getPlaybookToolset, PlaybookService, projectPlaybookService } from './tools/playbook'; +import { mcpToolset } from './tools/user-mcp'; + +export type AgentModelDeps = { + withMCP?: boolean; + targetDb: DBService; + playbookService: PlaybookService; + clusterService: ClusterService; + artifactsService?: ArtifactsService; +}; + +export function agentModelDeps({ + withMCP, + targetDb, + dbAccess, + connection, + userId, + cloudProvider, + withArtifacts, + dataStream +}: { + withMCP: boolean; + targetDb: Pool; + dbAccess: DBAccess; + connection: Connection; + cloudProvider: CloudProvider; + userId: string; + withArtifacts?: boolean; + dataStream?: DataStreamWriter; +}): AgentModelDeps { + return { + withMCP, + targetDb: targetDBService(targetDb), + playbookService: projectPlaybookService(dbAccess, connection.projectId), + clusterService: getProjectClusterService(dbAccess, connection, cloudProvider), + artifactsService: + withArtifacts && dataStream + ? projectArtifactService({ + userId: userId, + projectId: connection.projectId, + dataStream: dataStream, + dbAccess: dbAccess + }) + : undefined + }; +} + +export function getAgentMockDeps({ + withMCP = false, + useArtifacts = false, + targetDbService, + playbookService, + clusterService, + artifactsService +}: { + withMCP?: boolean; + useArtifacts?: boolean; + targetDbService?: DBService; + playbookService?: PlaybookService; + clusterService?: ClusterService | CloudProvider; + artifactsService?: ArtifactsService; +}): AgentModelDeps { + const mockHandler = { + get(_target: any, prop: any, _receiver: any) { + console.trace(`Stack trace for property access: ${prop}`); + throw new Error(`Not implemented: ${prop}`); + } + }; + + const useClusterService = clusterService + ? typeof clusterService === 'string' + ? getMockClusterService(clusterService) + : clusterService + : getMockClusterService('aws'); + + return { + withMCP: withMCP ?? false, + targetDb: targetDbService || new Proxy({} as DBService, mockHandler), + playbookService: playbookService || new Proxy({} as PlaybookService, mockHandler), + clusterService: useClusterService, + artifactsService: + artifactsService || (useArtifacts ? new Proxy({} as ArtifactsService, mockHandler) : undefined) + }; +} + +export function getMockClusterService(cloudProvider: CloudProvider): ClusterService { + const mockData = { + type: cloudProvider + }; + + return new Proxy(mockData as unknown as ClusterService, { + get(target, prop): any { + if (!(prop in target)) { + console.trace(`Stack trace for property access: ${String(prop)}`); + throw new Error(`Property ${String(prop)} is not implemented in mockData.`); + } + return target[prop as keyof typeof target]; + } + }); +} + +export const toolsets = [ + { + active: (deps?: { withMCP: boolean }) => { + const enabled = !deps || deps.withMCP !== false; + return enabled; + }, + tools: mcpToolset.listMCPTools + }, + { tools: commonToolset }, + + // Target DB support + { tools: async ({ targetDb }: { targetDb: DBService }) => getDBSQLTools({ db: targetDb }) }, + + // Playbook support + { tools: async ({ playbookService }: { playbookService: PlaybookService }) => getPlaybookToolset(playbookService) }, + + // Cloud provider support + { + systemPrompt: ({ clusterService }: { clusterService: ClusterService }) => + clusterService.type === 'aws' + ? awsCloudProviderPrompt + : clusterService.type === 'gcp' + ? gcpCloudProviderPrompt + : '', + tools: async ({ clusterService }: { clusterService: ClusterService }) => getDBClusterTools(clusterService) + }, + + // Artifacts support + { + active: (deps?: { artifactsService: ArtifactsService }) => !!deps?.artifactsService, + systemPrompt: artifactsPrompt, + tools: async ({ artifactsService }: { artifactsService: ArtifactsService }) => { + return getArtifactTools({ tools: artifactsService }); + } + } +]; + +export const commonModel = new AugmentedLanguageModel({ + providerRegistry: getProviderRegistry, + baseModel: 'chat' +}); + +export const chatModel = new AugmentedLanguageModel({ + providerRegistry: getProviderRegistry, + baseModel: 'chat', + metadata: { + tags: ['chat'] + }, + systemPrompt: [commonSystemPrompt, chatSystemPrompt], + toolsets: toolsets as ToolSet[] +}); + +export const monitoringModel = new AugmentedLanguageModel({ + providerRegistry: getProviderRegistry, + baseModel: 'chat', + metadata: { + tags: ['monitoring'] + }, + systemPrompt: [commonSystemPrompt, monitoringSystemPrompt], + toolsets: toolsets as ToolSet[] +}); + +export const titleModel = new AugmentedLanguageModel({ + providerRegistry: getProviderRegistry, + baseModel: 'title', + systemPrompt: `\n + - you will generate a short title based on the first message a user begins a conversation with + - ensure it is not more than 80 characters long + - the title should be a summary of the user's message + - do not use quotes or colons`, + metadata: { + tags: ['internal', 'chat', 'title'] + } +}); function getCloudProviderPrompt(cloudProvider: string): string { switch (cloudProvider) { case 'aws': - return `All Postgres instances in this project are hosted on AWS, either RDS or Aurora. - When recommending actions, only recommend actions that can be performed on RDS or Aurora. - If you need to know more about the instance, you can use the getClusterInfo tool. - If you want to recommend changes to the instance, provide instructions specific to RDS or Aurora. - `; + return awsCloudProviderPrompt; case 'gcp': - return `All Postgres instances in this project are GCP Cloud SQL instances. - When recommending actions, only recommend actions that can be performed on GCP Cloud SQL. - If you need to know more about the instance, you can use the getInstanceInfo tool. - If you want to recommend changes to the instance, provide instructions specific to GCP Cloud SQL. - `; + return gcpCloudProviderPrompt; default: return ''; } diff --git a/apps/dbagent/src/lib/ai/model.ts b/apps/dbagent/src/lib/ai/model.ts new file mode 100644 index 00000000..5e17c449 --- /dev/null +++ b/apps/dbagent/src/lib/ai/model.ts @@ -0,0 +1,552 @@ +import { AttributeValue } from '@opentelemetry/api'; +import { + CoreMessage, + DeepPartial, + generateObject, + GenerateObjectResult, + generateText, + GenerateTextResult, + LanguageModel, + Message, + ProviderMetadata, + Schema, + Tool as SDKTool, + tool as sdkTool, + ToolSet as SDKToolSet, + smoothStream, + streamObject, + StreamObjectResult, + streamText, + StreamTextOnChunkCallback, + StreamTextOnErrorCallback, + StreamTextOnFinishCallback, + StreamTextOnStepFinishCallback +} from 'ai'; + +function generateUUID(): string { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === 'x' ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} + +type PromptOptions = { + system?: string; + prompt?: string; + messages?: Array | Array>; +}; + +interface Telemetry { + metadata?: Record; +} + +type ModelOptions = { + maxTokens?: number; + temperature?: number; + topP?: number; + topK?: number; + presencePenalty?: number; + frequencyPenalty?: number; + stopSequences?: string[]; + seed?: number; + maxRetries?: number; + abortSignal?: AbortSignal; +}; + +type ToolOptions = { + // Add additional tools or modify existing tools + tools?: Record> | ((tools: Record>, deps?: DEPS) => Record>); +}; + +type StreamTextOptions = PromptOptions & + ToolOptions & + Telemetry & { + model?: LanguageModel | string; + modelSettings?: ModelOptions; + deps?: DEPS; + maxSteps?: number; + onChunk?: StreamTextOnChunkCallback; + onError?: StreamTextOnErrorCallback; + onFinish?: StreamTextOnFinishCallback; + onStepFinish?: StreamTextOnStepFinishCallback; + experimental_providerMetadata?: ProviderMetadata; + }; + +type StreamResult = Awaited>; + +type GenerateTextOptions = PromptOptions & + ToolOptions & + Telemetry & { + model?: LanguageModel | string; + modelSettings?: ModelOptions; + deps?: DEPS; + maxSteps?: number; + }; + +type GenerateObjectOptions = PromptOptions & + Telemetry & { + model?: LanguageModel | string; + modelSettings?: ModelOptions; + deps?: DEPS; + maxSteps?: number; + schema: z.Schema; + schemaName?: string; + schemaDescription?: string; + mode?: 'auto' | 'json' | 'tool'; + }; + +type StreamObjectOptions = PromptOptions & + Telemetry & { + model?: LanguageModel | string; + modelSettings?: ModelOptions; + deps?: DEPS; + maxSteps?: number; + schema: z.Schema | Schema; + schemaName?: string; + schemaDescription?: string; + mode?: 'auto' | 'json' | 'tool'; + }; + +interface Model { + streamText(options: StreamTextOptions): Promise; + generateText(options: GenerateTextOptions): Promise>; +} + +export class AugmentedLanguageModel implements Model { + #providerRegistry?: ProviderRegistry | (() => Promise); + #baseModel?: LanguageModel | (() => Promise) | string; + #systemPrompt: Prompt[] = []; + #tools: Record> = {}; + #toolSets: ToolSet[] = []; + #metadata?: Record; + + constructor({ + baseModel, + providerRegistry, + metadata, + systemPrompt, + toolsets + }: { + baseModel?: LanguageModel | string; + providerRegistry?: ProviderRegistry | (() => Promise); + metadata?: Record; + systemPrompt?: Prompt | Prompt[]; + toolsets?: ToolSet | ToolSet[]; + }) { + if (!baseModel && !providerRegistry) { + throw new Error('baseModel and providerRegistry are required.'); + } + this.#baseModel = baseModel; + this.#providerRegistry = providerRegistry; + this.#metadata = metadata; + if (systemPrompt) { + if (Array.isArray(systemPrompt)) { + this.#systemPrompt.push(...systemPrompt); + } else { + this.#systemPrompt.push(systemPrompt); + } + } + if (toolsets) { + if (Array.isArray(toolsets)) { + this.#toolSets.push(...toolsets); + } else { + this.#toolSets.push(toolsets); + } + } + } + + addSystemPrompt(prompt: Prompt) { + this.#systemPrompt.push(prompt); + } + + addSystemPrompts(...prompts: Prompt[]) { + this.#systemPrompt.push(...prompts); + } + + addTool(name: string, tool: Tool) { + this.#tools[name] = tool; + } + + addTools(tools: Record>) { + Object.entries(tools).forEach(([name, tool]) => { + this.addTool(name, tool); + }); + } + + addToolSet(toolSet: ToolSet) { + this.#toolSets.push(toolSet); + } + + addToolSets(...toolSets: ToolSet[]) { + this.#toolSets.push(...toolSets); + } + + private async getModel(optModel?: LanguageModel | string): Promise { + const model = optModel || this.#baseModel; + if (typeof model === 'string') { + const providerRegistry = + typeof this.#providerRegistry === 'function' ? await this.#providerRegistry() : this.#providerRegistry; + const m = providerRegistry!.languageModel(model, true); + return m.instance(); + } + if (typeof model === 'function') { + const m = await model(); + return m; + } + return model as LanguageModel; + } + + async getTools(deps?: DEPS): Promise { + const { tools } = await this.getToolsWithPrompt({}, deps); + return tools; + } + + private async getToolsWithPrompt( + options: ToolOptions, + deps?: DEPS + ): Promise<{ tools: SDKToolSet; systemPrompts: Prompt[] }> { + const systemPrompts: Prompt[] = []; + const toolsetTools: Record> = ( + await Promise.all( + this.#toolSets.map(async (toolSet) => { + if (toolSet.active && !toolSet.active(deps)) { + return {}; + } + + const tools = typeof toolSet.tools !== 'function' ? toolSet.tools : deps ? await toolSet.tools(deps) : {}; + if (toolSet.systemPrompt && Object.keys(tools).length > 0) { + systemPrompts.push(toolSet.systemPrompt); + } + return tools; + }) + ) + ).reduce((acc: Record>, tools: Record>) => { + return { ...acc, ...tools }; + }, {}); + + let allTools = { ...toolsetTools, ...this.#tools }; + if (options.tools) { + if (typeof options.tools === 'function') { + allTools = options.tools(allTools, deps); + } else { + allTools = { ...allTools, ...options.tools }; + } + } + + return { + systemPrompts, + tools: toSDKTools(allTools, deps) + }; + } + + private getSystemPrompt(deps?: DEPS, system?: string, toolSystemPrompts?: Prompt[]) { + const systemPrompts = [generatePrompt(this.#systemPrompt, deps)]; + if (system) { + systemPrompts.push(system); + } + if (toolSystemPrompts) { + const toolPrompts = generatePrompt(toolSystemPrompts, deps); + systemPrompts.push(toolPrompts); + } + return joinPrompts(systemPrompts); + } + + private getTelemetryConfig(metadata?: Record) { + return { + isEnabled: true, + metadata: { + ...this.#metadata, + ...metadata + } + }; + } + + async streamText(options: StreamTextOptions): Promise { + const { + model, + modelSettings, + deps, + system, + prompt, + messages, + metadata, + maxSteps, + onChunk, + onError, + onFinish, + onStepFinish, + tools: toolsOptions + } = options; + + const { tools, systemPrompts: toolSystemPrompts } = await this.getToolsWithPrompt({ tools: toolsOptions }, deps); + const systemPrompt = this.getSystemPrompt(deps, system, toolSystemPrompts); + const llm = await this.getModel(model); + const telemetry = this.getTelemetryConfig(metadata); + + return streamText({ + model: llm, + ...modelSettings, + system: systemPrompt, + prompt, + messages, + maxSteps, + onChunk, + onError, + onFinish, + onStepFinish, + tools, + toolCallStreaming: true, + experimental_telemetry: telemetry, + experimental_transform: smoothStream({ chunking: 'word' }), + experimental_generateMessageId: generateUUID + }); + } + + async generateText(options: GenerateTextOptions): Promise> { + const { model, modelSettings, deps, system, prompt, messages, metadata, maxSteps, tools: toolsOptions } = options; + const { tools, systemPrompts: toolSystemPrompts } = await this.getToolsWithPrompt({ tools: toolsOptions }, deps); + const systemPrompt = this.getSystemPrompt(deps, system, toolSystemPrompts); + const llm = await this.getModel(model); + const telemetry = this.getTelemetryConfig(metadata); + + return generateText({ + model: llm, + ...modelSettings, + system: systemPrompt, + prompt, + messages, + maxSteps, + tools, + experimental_telemetry: telemetry + }); + } + + async generateObject(options: GenerateObjectOptions): Promise> { + const { + model, + modelSettings, + deps, + system, + prompt, + messages, + metadata, + schema, + schemaName, + schemaDescription, + mode + } = options; + const systemPrompt = this.getSystemPrompt(deps, system, []); + const llm = await this.getModel(model); + const telemetry = this.getTelemetryConfig(metadata); + + return generateObject({ + model: llm, + ...modelSettings, + system: systemPrompt, + messages, + prompt, + schema: schema, + schemaName, + schemaDescription, + mode, + experimental_telemetry: telemetry + }); + } + + async streamObject( + options: StreamObjectOptions & { + output?: 'object' | undefined; + } + ): Promise, OBJECT, never>>; + async streamObject( + options: StreamObjectOptions & { + output: 'array'; + } + ): Promise, Array, AsyncIterable & ReadableStream>>; + + async streamObject( + options: StreamObjectOptions & { output?: 'object' } + ): Promise, OBJECT, never>>; + async streamObject( + options: StreamObjectOptions> & { output: 'array' } + ): Promise, Array, AsyncIterable & ReadableStream>>; + async streamObject( + options: StreamObjectOptions & { output?: 'object' | 'array' } + ): Promise> { + const { + model, + output = 'object', + modelSettings, + deps, + system, + prompt, + messages, + metadata, + schema, + schemaName, + schemaDescription, + mode + } = options; + const systemPrompt = this.getSystemPrompt(deps, system, []); + const llm = await this.getModel(model); + const telemetry = this.getTelemetryConfig(metadata); + + return streamObject({ + model: llm, + output: output as any, + ...modelSettings, + system: systemPrompt, + messages, + prompt, + schema, + schemaName, + schemaDescription, + mode, + experimental_telemetry: telemetry + }) as unknown as StreamObjectResult; + } +} + +type Prompt = StaticPrompt | PromptFunction; + +export function generatePrompt(prompts: Prompt[], deps?: DEPS): string { + return joinPrompts(prompts.map((p) => callPrompt(p, deps)).filter((p) => p !== '')); +} + +function callPrompt(prompt: Prompt, deps?: DEPS): string { + if (typeof prompt === 'string') { + return prompt; + } + if (!deps) { + return ''; + } + return prompt(deps); +} + +function joinPrompts(prompts: string[]): string { + return prompts.join('\n\n'); +} + +type StaticPrompt = string; + +type PromptFunction = (deps: DepsT) => string; + +import { ToolExecutionOptions } from 'ai'; +import { z } from 'zod'; +import { ProviderRegistry } from './providers'; + +type ToolParameters = z.ZodTypeAny; + +export type Tool = + | SDKTool + | { + type: 'function-deps'; + description?: string; + parameters: PARAMETERS; + active?: (deps?: DEPS) => boolean; + execute: (deps: DEPS, args: z.infer, options: ToolExecutionOptions) => PromiseLike; + }; + +export type ToolSet = { + active?: (deps?: DEPS) => boolean; + systemPrompt?: Prompt; + tools: Record> | ((deps: DEPS) => Promise>>); +}; + +function toSDKTool( + tool: Tool, + deps: DEPS +): SDKTool | null { + if (tool.type === 'function-deps') { + if (tool.active && !tool.active(deps)) { + return null; + } + + return sdkTool({ + description: tool.description, + parameters: tool.parameters, + execute: (args, options) => tool.execute(deps, args, options) + }); + } + return tool; +} + +export function tool({ + description, + parameters, + execute +}: { + description?: string; + parameters: PARAMETERS; + active?: (deps: DEPS) => boolean; + execute: (deps: DEPS, args: z.infer) => PromiseLike; +}): Tool; +export function tool(tool: { + description?: string; + parameters: PARAMETERS; + execute: (args: z.infer) => PromiseLike; +}): Tool; +export function tool(tool: { + description?: string; + parameters: PARAMETERS; + active?: (deps?: DEPS) => boolean; + execute: any; +}): Tool { + if (typeof tool.execute === 'function' && tool.execute.length === 2) { + return { + type: 'function-deps', + description: tool.description, + parameters: tool.parameters, + active: tool.active, + execute: tool.execute + }; + } + return sdkTool(tool); +} + +export function toSDKTools(tools: Record>, deps?: DEPS): Record { + return Object.fromEntries(toolsWithErrorCatch(generateSDKTools(tools, deps))); +} + +function* generateSDKTools(tools: Record>, deps?: DEPS): Generator<[string, SDKTool]> { + if (deps) { + for (const [key, tool] of Object.entries(tools)) { + const sdkToolInstance = toSDKTool(tool, deps); + if (sdkToolInstance !== null) { + yield [key, sdkToolInstance]; + } + } + } else { + for (const [key, tool] of Object.entries(tools)) { + if (tool.type !== 'function-deps') { + yield [key, tool]; + } + } + } +} + +export function* toolsWithErrorCatch(tools: Iterable<[string, SDKTool]>): Generator<[string, SDKTool]> { + for (const [key, tool] of tools) { + if (!tool.execute) { + yield [key, tool]; + continue; + } + const errorMessage = tool.description ? `Error: ${tool.description.split('.')[0]}` : 'Error, operation failed'; + tool.execute = executeWithErrorHandling(tool.execute, errorMessage); + yield [key, tool]; + } +} + +export function executeWithErrorHandling( + fn: (...args: T) => PromiseLike, + errorMessage?: string +): (...args: T) => Promise { + return (...args: T): Promise => { + return Promise.resolve(fn(...args)) + .then((result) => result) + .catch((error) => { + return errorMessage ? `${errorMessage}: ${error}` : `Error: ${error}`; + }); + }; +} diff --git a/apps/dbagent/src/lib/ai/prompts.ts b/apps/dbagent/src/lib/ai/prompts.ts index fdddc1a7..8037f56b 100644 --- a/apps/dbagent/src/lib/ai/prompts.ts +++ b/apps/dbagent/src/lib/ai/prompts.ts @@ -26,6 +26,20 @@ Then use the contents of the playbook as an action plan. Execute the plan step b At the end of your execution, print a summary of the results. `; +export const awsCloudProviderPrompt = ` +All Postgres instances in this project are hosted on AWS, either RDS or Aurora. +When recommending actions, only recommend actions that can be performed on RDS or Aurora. +If you need to know more about the instance, you can use the getClusterInfo tool. +If you want to recommend changes to the instance, provide instructions specific to RDS or Aurora. +`; + +export const gcpCloudProviderPrompt = ` +All Postgres instances in this project are GCP Cloud SQL instances. +When recommending actions, only recommend actions that can be performed on GCP Cloud SQL. +If you need to know more about the instance, you can use the getInstanceInfo tool. +If you want to recommend changes to the instance, provide instructions specific to GCP Cloud SQL. +`; + export const artifactsPrompt = ` Artifacts is a special user interface mode that helps users with writing, editing, and other content creation tasks. When artifact is open, it is on the right side of the screen, while the conversation is on the left side. When creating or updating documents, changes are reflected in real-time on the artifacts and visible to the user. diff --git a/apps/dbagent/src/lib/ai/tools/artifacts.ts b/apps/dbagent/src/lib/ai/tools/artifacts.ts index 3c7285c0..2147ae55 100644 --- a/apps/dbagent/src/lib/ai/tools/artifacts.ts +++ b/apps/dbagent/src/lib/ai/tools/artifacts.ts @@ -1,33 +1,21 @@ -import { DataStreamWriter, streamObject, tool, Tool } from 'ai'; +import { tool, Tool } from 'ai'; import { z } from 'zod'; -import { artifactKinds, documentHandlersByArtifactKind } from '~/components/chat/artifacts/server'; -import { generateUUID } from '~/components/chat/utils'; -import { getDocumentById, saveSuggestions } from '~/lib/db/chats'; -import { DBAccess } from '~/lib/db/db'; -import { ArtifactSuggestion } from '~/lib/db/schema'; -import { getModelInstance } from '../agent'; +import { artifactKinds } from '~/components/chat/artifacts/server'; +import { ArtifactsService } from '~/lib/tools/artifacts'; interface ArtifactToolProps { - userId: string; - projectId: string; - dataStream: DataStreamWriter; - dbAccess: DBAccess; + tools: ArtifactsService; } -export function getArtifactTools({ userId, projectId, dataStream, dbAccess }: ArtifactToolProps): Record { +export function getArtifactTools({ tools }: ArtifactToolProps): Record { return { - createDocument: createDocument({ userId, projectId, dataStream, dbAccess }), - updateDocument: updateDocument({ userId, projectId, dataStream, dbAccess }), - requestSuggestions: requestSuggestions({ - userId, - projectId, - dataStream, - dbAccess - }) + createDocument: createDocument({ tools }), + updateDocument: updateDocument({ tools }), + requestSuggestions: requestSuggestions({ tools }) }; } -export const createDocument = ({ userId, projectId, dataStream, dbAccess }: ArtifactToolProps) => +export const createDocument = ({ tools }: ArtifactToolProps) => tool({ description: 'Create a document for a writing or content creation activities. This tool will call other functions that will generate the contents of the document based on the title and kind.', @@ -36,57 +24,15 @@ export const createDocument = ({ userId, projectId, dataStream, dbAccess }: Arti kind: z.enum(artifactKinds) }), execute: async ({ title, kind }) => { - const id = generateUUID(); - - dataStream.writeData({ - type: 'kind', - content: kind - }); - - dataStream.writeData({ - type: 'id', - content: id - }); - - dataStream.writeData({ - type: 'title', - content: title - }); - - dataStream.writeData({ - type: 'clear', - content: '' - }); - - const documentHandler = documentHandlersByArtifactKind.find( - (documentHandlerByArtifactKind) => documentHandlerByArtifactKind.kind === kind - ); - - if (!documentHandler) { - throw new Error(`No document handler found for kind: ${kind}`); - } - - await documentHandler.onCreateDocument({ - id, - title, - dataStream, - userId, - projectId, - dbAccess - }); - - dataStream.writeData({ type: 'finish', content: '' }); - + const result = await tools.createDocument({ title, kind }); return { - id, - title, - kind, + ...result, content: 'A document was created and is now visible to the user.' }; } }); -export const updateDocument = ({ userId, projectId, dataStream, dbAccess }: ArtifactToolProps) => +export const updateDocument = ({ tools }: ArtifactToolProps) => tool({ description: 'Update a document with the given description.', parameters: z.object({ @@ -94,116 +40,30 @@ export const updateDocument = ({ userId, projectId, dataStream, dbAccess }: Arti description: z.string().describe('The description of changes that need to be made') }), execute: async ({ id, description }) => { - const document = await getDocumentById(dbAccess, { id }); - - if (!document) { - return { - error: 'Document not found' - }; + const result = await tools.updateDocument({ id, description }); + if ('error' in result) { + return result; } - - dataStream.writeData({ - type: 'clear', - content: document.title - }); - - const documentHandler = documentHandlersByArtifactKind.find( - (documentHandlerByArtifactKind) => documentHandlerByArtifactKind.kind === document.kind - ); - - if (!documentHandler) { - throw new Error(`No document handler found for kind: ${document.kind}`); - } - - await documentHandler.onUpdateDocument({ - document, - description, - dataStream, - userId, - projectId, - dbAccess - }); - - dataStream.writeData({ type: 'finish', content: '' }); - return { - id, - title: document.title, - kind: document.kind, + ...result, content: 'The document has been updated successfully.' }; } }); -export const requestSuggestions = ({ userId, projectId, dataStream, dbAccess }: ArtifactToolProps) => +export const requestSuggestions = ({ tools }: ArtifactToolProps) => tool({ description: 'Request suggestions for a document', parameters: z.object({ documentId: z.string().describe('The ID of the document to request edits') }), execute: async ({ documentId }) => { - const document = await getDocumentById(dbAccess, { id: documentId }); - - if (!document || !document.content) { - return { - error: 'Document not found' - }; + const result = await tools.requestSuggestions({ documentId }); + if ('error' in result) { + return result; } - - const suggestions: Array> = []; - - const { elementStream } = streamObject({ - model: await getModelInstance('chat'), - experimental_telemetry: { - isEnabled: true, - metadata: { - tags: ['artifact', 'suggestion'] - } - }, - system: - 'You are a help writing assistant. Given a piece of writing, please offer suggestions to improve the piece of writing and describe the change. It is very important for the edits to contain full sentences instead of just words. Max 5 suggestions.', - prompt: document.content, - output: 'array', - schema: z.object({ - originalSentence: z.string().describe('The original sentence'), - suggestedSentence: z.string().describe('The suggested sentence'), - description: z.string().describe('The description of the suggestion') - }) - }); - - for await (const element of elementStream) { - const suggestion = { - originalText: element.originalSentence, - suggestedText: element.suggestedSentence, - description: element.description, - id: generateUUID(), - documentId: documentId, - isResolved: false, - projectId - }; - - dataStream.writeData({ - type: 'suggestion', - content: suggestion - }); - - suggestions.push(suggestion); - } - - await saveSuggestions(dbAccess, { - suggestions: suggestions.map((suggestion) => ({ - ...suggestion, - userId, - projectId, - createdAt: new Date(), - documentCreatedAt: document.createdAt - })) - }); - return { - id: documentId, - title: document.title, - kind: document.kind, + ...result, message: 'Suggestions have been added to the document' }; } diff --git a/apps/dbagent/src/lib/ai/tools/cluster.ts b/apps/dbagent/src/lib/ai/tools/cluster.ts index abe52652..62d4e3fd 100644 --- a/apps/dbagent/src/lib/ai/tools/cluster.ts +++ b/apps/dbagent/src/lib/ai/tools/cluster.ts @@ -3,91 +3,87 @@ import { z } from 'zod'; import { getClusterByConnection } from '~/lib/db/aws-clusters'; import { DBAccess } from '~/lib/db/db'; import { getInstanceByConnection } from '~/lib/db/gcp-instances'; -import { CloudProvider, Connection } from '~/lib/db/schema'; +import { AWSCluster, CloudProvider, Connection, GCPInstance } from '~/lib/db/schema'; import { getPostgresExtensions, getTablesInfo } from '~/lib/tools/dbinfo'; import { getInstanceLogsGCP, getInstanceLogsRDS } from '~/lib/tools/logs'; import { getClusterMetricGCP, getClusterMetricRDS } from '~/lib/tools/metrics'; -import { mergeToolsets, Toolset, ToolsetGroup } from './types'; -export function getDBClusterTools( - dbAccess: DBAccess, - connection: Connection | (() => Promise), - cloudProvider: CloudProvider -): Record { - const connectionGetter = typeof connection === 'function' ? connection : () => Promise.resolve(connection); - const toolset: Toolset[] = [new CommonDBClusterTools(dbAccess, connectionGetter)]; - if (cloudProvider === 'aws') { - toolset.push(new AWSDBClusterTools(dbAccess, connectionGetter)); - } else if (cloudProvider === 'gcp') { - toolset.push(new GCPDBClusterTools(dbAccess, connectionGetter)); - } - return mergeToolsets(...toolset); +export interface ClusterService { + type: 'aws' | 'gcp' | 'other'; + getTablesInfo(): Promise; + getPostgresExtensions(): Promise; } -export class CommonDBClusterTools implements ToolsetGroup { - #dbAccess: DBAccess; - #getter: () => Promise; +export interface AWSProjectClusterService extends ClusterService { + type: 'aws'; + getInstanceLogs({ periodInSeconds, grep }: { periodInSeconds: number; grep?: string }): Promise; + getInstanceMetric({ + metricName, + periodInSeconds, + stat + }: { + metricName: string; + periodInSeconds: number; + stat: 'Average' | 'Maximum' | 'Minimum' | 'Sum'; + }): Promise; + getClusterInfo(): Promise; +} - constructor(dbAccess: DBAccess, getter: () => Promise) { - this.#dbAccess = dbAccess; - this.#getter = getter; +export interface GCPProjectClusterService extends ClusterService { + type: 'gcp'; + getInstanceLogs({ periodInSeconds, grep }: { periodInSeconds: number; grep?: string }): Promise; + getInstanceMetric({ metricName, periodInSeconds }: { metricName: string; periodInSeconds: number }): Promise; + getInstanceInfo(): Promise; +} + +export function getDBClusterTools(tools: ClusterService): Record { + switch (tools.type) { + case 'aws': + return awsDBClusterTools(tools as AWSProjectClusterService); + case 'gcp': + return gpcDBClusterTools(tools as GCPProjectClusterService); + default: + return commonDBClusterTools(tools); } +} - toolset(): Record { +export function getProjectClusterService( + dbAccess: DBAccess, + connection: Connection | (() => Promise), + cloudProvider: CloudProvider +): ClusterService { + if (cloudProvider === 'aws') { + return awsProjectClusterTools(dbAccess, connection); + } else if (cloudProvider === 'gcp') { + return gcpProjectClusterTools(dbAccess, connection); + } else { + const getter = typeof connection === 'function' ? connection : () => Promise.resolve(connection); return { - getTablesInfo: this.getTablesInfo(), - getPostgresExtensions: this.getPostgresExtensions() + type: 'other', + getTablesInfo: async () => await getTablesInfo(dbAccess, await getter()), + getPostgresExtensions: async () => await getPostgresExtensions(dbAccess, await getter()) }; } +} - private getTablesInfo(): Tool { - const getter = this.#getter; - const db = this.#dbAccess; - return tool({ +export function commonDBClusterTools(clusterTools: ClusterService): Record { + return { + getTablesInfo: tool({ description: `Get the information about tables (sizes, row counts, usage).`, parameters: z.object({}), - execute: async () => { - const connection = await getter(); - return await getTablesInfo(db, connection); - } - }); - } - - private getPostgresExtensions(): Tool { - const getter = this.#getter; - const db = this.#dbAccess; - return tool({ + execute: async () => clusterTools.getTablesInfo() + }), + getPostgresExtensions: tool({ description: `Get the available and installed PostgreSQL extensions for the database.`, parameters: z.object({}), - execute: async () => { - const connection = await getter(); - return await getPostgresExtensions(db, connection); - } - }); - } + execute: async () => clusterTools.getPostgresExtensions() + }) + }; } -export class AWSDBClusterTools implements ToolsetGroup { - #dbAccess: DBAccess; - #getter: () => Promise; - - constructor(dbAccess: DBAccess, getter: () => Promise) { - this.#dbAccess = dbAccess; - this.#getter = getter; - } - - toolset(): Record { - return { - getInstanceLogs: this.getInstanceLogsRDS(), - getInstanceMetric: this.getInstanceMetricRDS(), - getClusterInfo: this.getClusterInfo() - }; - } - - private getInstanceLogsRDS(): Tool { - const getter = this.#getter; - const db = this.#dbAccess; - return tool({ +export function createAWSDBClusterTools(awsClusterTools: AWSProjectClusterService): Record { + return { + getInstanceLogs: tool({ description: `Get the recent logs from the RDS instance. You can specify the period in seconds and optionally grep for a substring. If you don't want to grep for a substring, you can pass an empty string.`, parameters: z.object({ @@ -96,16 +92,10 @@ export class AWSDBClusterTools implements ToolsetGroup { }), execute: async ({ periodInSeconds, grep }) => { console.log('getInstanceLogs', periodInSeconds, grep); - const connection = await getter(); - return await getInstanceLogsRDS(db, { connection, periodInSeconds, grep }); + return await awsClusterTools.getInstanceLogs({ periodInSeconds, grep }); } - }); - } - - private getInstanceMetricRDS(): Tool { - const getter = this.#getter; - const db = this.#dbAccess; - return tool({ + }), + getInstanceMetric: tool({ description: `Get the metrics for the RDS instance. If this is a cluster, the metric is read from the current writer instance. You can specify the period in seconds. The stat parameter is one of the following: Average, Maximum, Minimum, Sum.`, parameters: z.object({ @@ -115,47 +105,88 @@ export class AWSDBClusterTools implements ToolsetGroup { }), execute: async ({ metricName, periodInSeconds, stat }) => { console.log('getClusterMetric', metricName, periodInSeconds); - const connection = await getter(); - return await getClusterMetricRDS(db, { connection, metricName, periodInSeconds, stat }); + return await awsClusterTools.getInstanceMetric({ metricName, periodInSeconds, stat }); } - }); - } - - private getClusterInfo(): Tool { - const getter = this.#getter; - const db = this.#dbAccess; - return tool({ + }), + getClusterInfo: tool({ description: `Get the information about the RDS cluster or instance.`, parameters: z.object({}), execute: async () => { - const connection = await getter(); - return await getClusterByConnection(db, connection.id); + return await awsClusterTools.getClusterInfo(); } - }); - } + }) + }; } -export class GCPDBClusterTools implements ToolsetGroup { - #dbAccess: DBAccess; - #getter: () => Promise; +export function awsDBClusterTools(awsClusterTools: AWSProjectClusterService): Record { + const commonTools = commonDBClusterTools(awsClusterTools); + return { + ...commonTools, + getInstanceLogs: tool({ + description: `Get the recent logs from the RDS instance. You can specify the period in seconds and optionally grep for a substring. + If you don't want to grep for a substring, you can pass an empty string.`, + parameters: z.object({ + periodInSeconds: z.number(), + grep: z.string() + }), + execute: async ({ periodInSeconds, grep }) => { + console.log('getInstanceLogs', periodInSeconds, grep); + return await awsClusterTools.getInstanceLogs({ periodInSeconds, grep }); + } + }), + getInstanceMetric: tool({ + description: `Get the metrics for the RDS instance. If this is a cluster, the metric is read from the current writer instance. + You can specify the period in seconds. The stat parameter is one of the following: Average, Maximum, Minimum, Sum.`, + parameters: z.object({ + metricName: z.string(), + periodInSeconds: z.number(), + stat: z.enum(['Average', 'Maximum', 'Minimum', 'Sum']) + }), + execute: async ({ metricName, periodInSeconds, stat }) => { + console.log('getClusterMetric', metricName, periodInSeconds); + return await awsClusterTools.getInstanceMetric({ metricName, periodInSeconds, stat }); + } + }), + getClusterInfo: tool({ + description: `Get the information about the RDS cluster or instance.`, + parameters: z.object({}), + execute: async () => { + return await awsClusterTools.getClusterInfo(); + } + }) + }; +} - constructor(dbAccess: DBAccess, getter: () => Promise) { - this.#dbAccess = dbAccess; - this.#getter = getter; - } +export function awsProjectClusterTools( + dbAccess: DBAccess, + connection: Connection | (() => Promise) +): AWSProjectClusterService { + const getter = typeof connection === 'function' ? connection : () => Promise.resolve(connection); - toolset(): Record { - return { - getInstanceLogs: this.getInstanceLogsGCP(), - getInstanceMetric: this.getInstanceMetricGCP(), - getInstanceInfo: this.getInstanceInfo() - }; - } + return { + type: 'aws', + getTablesInfo: async () => await getTablesInfo(dbAccess, await getter()), + getPostgresExtensions: async () => await getPostgresExtensions(dbAccess, await getter()), + getInstanceLogs: async ({ periodInSeconds, grep }) => { + const connection = await getter(); + return await getInstanceLogsRDS(dbAccess, { connection, periodInSeconds, grep }); + }, + getInstanceMetric: async ({ metricName, periodInSeconds, stat }) => { + const connection = await getter(); + return getClusterMetricRDS(dbAccess, { connection, metricName, periodInSeconds, stat }); + }, + getClusterInfo: async () => { + const connection = await getter(); + return await getClusterByConnection(dbAccess, connection.id); + } + }; +} - private getInstanceLogsGCP(): Tool { - const getter = this.#getter; - const db = this.#dbAccess; - return tool({ +export function gpcDBClusterTools(gcpProjectClusterTools: GCPProjectClusterService): Record { + const commonTools = commonDBClusterTools(gcpProjectClusterTools); + return { + ...commonTools, + getInstanceLogs: tool({ description: `Get the recent logs from a GCP CloudSQL instance. You can specify the period in seconds and optionally grep for a substring.`, parameters: z.object({ periodInSeconds: z.number(), @@ -163,52 +194,63 @@ export class GCPDBClusterTools implements ToolsetGroup { }), execute: async ({ periodInSeconds, grep }) => { console.log('getInstanceLogs', periodInSeconds, grep); - const connection = await getter(); - return await getInstanceLogsGCP(db, { connection, periodInSeconds, grep }); + return await gcpProjectClusterTools.getInstanceLogs({ periodInSeconds, grep }); } - }); - } - - private getInstanceMetricGCP(): Tool { - const getter = this.#getter; - const db = this.#dbAccess; - - return tool({ + }), + getInstanceMetric: tool({ description: `Get the metrics for the GCP Cloud SQL instance. You can specify the period in seconds. - The metric name MUST be a valid Cloud SQL metric name. Common CloudSQL metrics are: - - cloudsql.googleapis.com/database/cpu/utilization - - cloudsql.googleapis.com/database/memory/utilization - - cloudsql.googleapis.com/database/disk/utilization - - cloudsql.googleapis.com/database/disk/write_ops_count - - cloudsql.googleapis.com/database/disk/read_ops_count - - cloudsql.googleapis.com/database/memory/total_usage - - cloudsql.googleapis.com/database/postgresql/num_backends - - cloudsql.googleapis.com/database/postgresql/new_connection_count - - cloudsql.googleapis.com/database/postgresql/deadlock_count - - cloudsql.googleapis.com/database/postgresql/write_ahead_log/written_bytes_count - `, + The metric name MUST be a valid Cloud SQL metric name. Common CloudSQL metrics are: + - cloudsql.googleapis.com/database/cpu/utilization + - cloudsql.googleapis.com/database/memory/utilization + - cloudsql.googleapis.com/database/disk/utilization + - cloudsql.googleapis.com/database/disk/write_ops_count + - cloudsql.googleapis.com/database/disk/read_ops_count + - cloudsql.googleapis.com/database/memory/total_usage + - cloudsql.googleapis.com/database/postgresql/num_backends + - cloudsql.googleapis.com/database/postgresql/new_connection_count + - cloudsql.googleapis.com/database/postgresql/deadlock_count + - cloudsql.googleapis.com/database/postgresql/write_ahead_log/written_bytes_count + `, parameters: z.object({ metricName: z.string(), periodInSeconds: z.number() }), execute: async ({ metricName, periodInSeconds }) => { console.log('getClusterMetricGCP', metricName, periodInSeconds); - const connection = await getter(); - return await getClusterMetricGCP(db, { connection, metricName, periodInSeconds }); + return await gcpProjectClusterTools.getInstanceMetric({ metricName, periodInSeconds }); } - }); - } - - private getInstanceInfo(): Tool { - const getter = this.#getter; - const db = this.#dbAccess; - return tool({ + }), + getInstanceInfo: tool({ description: `Get the information about the GCP Cloud SQL instance.`, parameters: z.object({}), execute: async () => { - const connection = await getter(); - return await getInstanceByConnection(db, connection.id); + return await gcpProjectClusterTools.getInstanceInfo(); } - }); - } + }) + }; +} + +export function gcpProjectClusterTools( + dbAccess: DBAccess, + connection: Connection | (() => Promise) +): GCPProjectClusterService { + const getter = typeof connection === 'function' ? connection : () => Promise.resolve(connection); + + return { + type: 'gcp', + getTablesInfo: async () => await getTablesInfo(dbAccess, await getter()), + getPostgresExtensions: async () => await getPostgresExtensions(dbAccess, await getter()), + getInstanceLogs: async ({ periodInSeconds, grep }) => { + const connection = await getter(); + return await getInstanceLogsGCP(dbAccess, { connection, periodInSeconds, grep }); + }, + getInstanceMetric: async ({ metricName, periodInSeconds }) => { + const connection = await getter(); + return await getClusterMetricGCP(dbAccess, { connection, metricName, periodInSeconds }); + }, + getInstanceInfo: async () => { + const connection = await getter(); + return await getInstanceByConnection(dbAccess, connection.id); + } + }; } diff --git a/apps/dbagent/src/lib/ai/tools/db.ts b/apps/dbagent/src/lib/ai/tools/db.ts index a28b7d85..cf0e3af4 100644 --- a/apps/dbagent/src/lib/ai/tools/db.ts +++ b/apps/dbagent/src/lib/ai/tools/db.ts @@ -1,6 +1,6 @@ import { Tool, tool } from 'ai'; import { z } from 'zod'; -import { getPerformanceAndVacuumSettings, toolFindTableSchema } from '~/lib/tools/dbinfo'; +import { toolFindTableSchema } from '~/lib/tools/dbinfo'; import { toolDescribeTable, toolExplainQuery, toolGetSlowQueries } from '~/lib/tools/slow-queries'; import { toolCurrentActiveQueries, @@ -9,204 +9,161 @@ import { toolGetQueriesWaitingOnLocks, toolGetVacuumStats } from '~/lib/tools/stats'; -import { ToolsetGroup } from './types'; -import { Pool, withPoolConnection } from '~/lib/targetdb/db'; - -export function getDBSQLTools(targetDb: Pool): DBSQLTools { - return new DBSQLTools(targetDb); +import { getPerformanceSettings, getVacuumSettings, Pool, withPoolConnection } from '~/lib/targetdb/db'; + +type DBToolsProps = { + db: DBService; +}; + +export interface DBService { + slowQueries(thresholdMs: number): Promise; + explainQuery(schema: string, query: string): Promise; + describeTable(schema: string, table: string): Promise; + findTableSchema(table: string): Promise; + currentActiveQueries(): Promise; + queriesWaitingOnLocks(): Promise; + vacuumStats(): Promise; + connectionsStats(): Promise; + connectionsGroups(): Promise; + getPerformanceAndVacuumSettings(): Promise; } -// The DBSQLTools toolset provides tools for querying the postgres database -// directly via SQL to collect system performance information. -export class DBSQLTools implements ToolsetGroup { - #pool: Pool | (() => Promise); - - constructor(pool: Pool | (() => Promise)) { - this.#pool = pool; - } +export function getDBSQLTools(props: DBToolsProps): Record { + return { + getSlowQueries: getSlowQueries(props), + explainQuery: explainQuery(props), + describeTable: describeTable(props), + findTableSchema: findTableSchema(props), + getCurrentActiveQueries: getCurrentActiveQueries(props), + getQueriesWaitingOnLocks: getQueriesWaitingOnLocks(props), + getVacuumStats: getVacuumStats(props), + getConnectionsStats: getConnectionsStats(props), + getConnectionsGroups: getConnectionsGroups(props), + getPerformanceAndVacuumSettings: getPerformanceAndVacuumSettings(props) + }; +} - toolset(): Record { - return { - getSlowQueries: this.getSlowQueries(), - explainQuery: this.explainQuery(), - describeTable: this.describeTable(), - findTableSchema: this.findTableSchema(), - getCurrentActiveQueries: this.getCurrentActiveQueries(), - getQueriesWaitingOnLocks: this.getQueriesWaitingOnLocks(), - getVacuumStats: this.getVacuumStats(), - getConnectionsStats: this.getConnectionsStats(), - getConnectionsGroups: this.getConnectionsGroups(), - getPerformanceAndVacuumSettings: this.getPerformanceAndVacuumSettings() - }; - } +export function targetDBService(pool: Pool | (() => Promise)): DBService { + return { + slowQueries: async (thresholdMs: number) => + await withPoolConnection(pool, async (client) => await toolGetSlowQueries(client, thresholdMs)), + explainQuery: async (schema: string, query: string) => + await withPoolConnection(pool, async (client) => await toolExplainQuery(client, schema, query)), + describeTable: async (schema: string, table: string) => + await withPoolConnection(pool, async (client) => await toolDescribeTable(client, schema, table)), + findTableSchema: async (table: string) => + await withPoolConnection(pool, async (client) => await toolFindTableSchema(client, table)), + currentActiveQueries: async () => await withPoolConnection(pool, toolCurrentActiveQueries), + queriesWaitingOnLocks: async () => await withPoolConnection(pool, toolGetQueriesWaitingOnLocks), + vacuumStats: async () => await withPoolConnection(pool, toolGetVacuumStats), + connectionsStats: async () => await withPoolConnection(pool, toolGetConnectionsStats), + connectionsGroups: async () => await withPoolConnection(pool, toolGetConnectionsGroups), + getPerformanceAndVacuumSettings: async () => + await withPoolConnection(pool, async (client) => { + const performanceSettings = await getPerformanceSettings(client); + const vacuumSettings = await getVacuumSettings(client); + return ` + Performance settings: ${JSON.stringify(performanceSettings)} + Vacuum settings: ${JSON.stringify(vacuumSettings)} + `; + }) + }; +} - getSlowQueries(): Tool { - const pool = this.#pool; - return tool({ - description: `Get a list of slow queries formatted as a JSON array. Contains how many times the query was called, +function getSlowQueries({ db }: DBToolsProps): Tool { + return tool({ + description: `Get a list of slow queries formatted as a JSON array. Contains how many times the query was called, the max execution time in seconds, the mean execution time in seconds, the total execution time (all calls together) in seconds, and the query itself.`, - parameters: z.object({}), - execute: async () => { - try { - return await withPoolConnection(pool, async (client) => await toolGetSlowQueries(client, 2000)); - } catch (error) { - return `Error getting slow queries: ${error}`; - } - } - }); - } + parameters: z.object({}), + execute: async () => await db.slowQueries(2000) + }); +} - explainQuery(): Tool { - const pool = this.#pool; - return tool({ - description: `Run explain on a a query. Returns the explain plan as received from PostgreSQL. +function explainQuery({ db }: DBToolsProps): Tool { + return tool({ + description: `Run explain on a a query. Returns the explain plan as received from PostgreSQL. The query needs to be complete, it cannot contain $1, $2, etc. If you need to, replace the parameters with your own made up values. It's very important that $1, $2, etc. are not passed to this tool. Use the tool describeTable to get the types of the columns. If you know the schema, pass it in as well.`, - parameters: z.object({ - schema: z.string(), - query: z.string() - }), - execute: async ({ schema = 'public', query }) => { - try { - const explain = await withPoolConnection( - pool, - async (client) => await toolExplainQuery(client, schema, query) - ); - if (!explain) return 'Could not run EXPLAIN on the query'; - - return explain; - } catch (error) { - return `Error running EXPLAIN on the query: ${error}`; - } - } - }); - } + parameters: z.object({ + schema: z.string(), + query: z.string() + }), + execute: async ({ schema = 'public', query }) => { + const explain = await db.explainQuery(schema, query); + if (!explain) return 'Could not run EXPLAIN on the query'; + return explain; + } + }); +} - describeTable(): Tool { - const pool = this.#pool; - return tool({ - description: `Describe a table. If you know the schema, pass it as a parameter. If you don't, use public.`, - parameters: z.object({ - schema: z.string(), - table: z.string() - }), - execute: async ({ schema = 'public', table }) => { - try { - return await withPoolConnection(pool, async (client) => await toolDescribeTable(client, schema, table)); - } catch (error) { - return `Error describing table: ${error}`; - } - } - }); - } +function describeTable({ db }: DBToolsProps): Tool { + return tool({ + description: `Describe a table. If you know the schema, pass it as a parameter. If you don't, use public.`, + parameters: z.object({ + schema: z.string(), + table: z.string() + }), + execute: async ({ schema = 'public', table }) => await db.describeTable(schema, table) + }); +} - findTableSchema(): Tool { - const pool = this.#pool; - return tool({ - description: `Find the schema of a table. Use this tool to find the schema of a table.`, - parameters: z.object({ - table: z.string() - }), - execute: async ({ table }) => { - try { - return await withPoolConnection(pool, async (client) => await toolFindTableSchema(client, table)); - } catch (error) { - return `Error finding table schema: ${error}`; - } - } - }); - } +function findTableSchema({ db }: DBToolsProps): Tool { + return tool({ + description: `Find the schema of a table. Use this tool to find the schema of a table.`, + parameters: z.object({ + table: z.string() + }), + execute: async ({ table }) => await db.findTableSchema(table) + }); +} - getCurrentActiveQueries(): Tool { - const pool = this.#pool; - return tool({ - description: `Get the currently active queries.`, - parameters: z.object({}), - execute: async () => { - try { - return await withPoolConnection(pool, toolCurrentActiveQueries); - } catch (error) { - return `Error getting current active queries: ${error}`; - } - } - }); - } +function getCurrentActiveQueries({ db }: DBToolsProps): Tool { + return tool({ + description: `Get the currently active queries.`, + parameters: z.object({}), + execute: async () => await db.currentActiveQueries() + }); +} - getQueriesWaitingOnLocks(): Tool { - const pool = this.#pool; - return tool({ - description: `Get the queries that are currently blocked waiting on locks.`, - parameters: z.object({}), - execute: async () => { - try { - return await withPoolConnection(pool, toolGetQueriesWaitingOnLocks); - } catch (error) { - return `Error getting queries waiting on locks: ${error}`; - } - } - }); - } +function getQueriesWaitingOnLocks({ db }: DBToolsProps): Tool { + return tool({ + description: `Get the queries that are currently blocked waiting on locks.`, + parameters: z.object({}), + execute: async () => await db.queriesWaitingOnLocks() + }); +} - getVacuumStats(): Tool { - const pool = this.#pool; - return tool({ - description: `Get the vacuum stats for the top tables in the database. They are sorted by the number of dead tuples descending.`, - parameters: z.object({}), - execute: async () => { - try { - return await withPoolConnection(pool, toolGetVacuumStats); - } catch (error) { - return `Error getting vacuum stats: ${error}`; - } - } - }); - } +function getVacuumStats({ db }: DBToolsProps): Tool { + return tool({ + description: `Get the vacuum stats for the top tables in the database. They are sorted by the number of dead tuples descending.`, + parameters: z.object({}), + execute: async () => await db.vacuumStats() + }); +} - getConnectionsStats(): Tool { - const pool = this.#pool; - return tool({ - description: `Get the connections stats for the database.`, - parameters: z.object({}), - execute: async () => { - try { - return await withPoolConnection(pool, toolGetConnectionsStats); - } catch (error) { - return `Error getting connections stats: ${error}`; - } - } - }); - } +function getConnectionsStats({ db }: DBToolsProps): Tool { + return tool({ + description: `Get the connections stats for the database.`, + parameters: z.object({}), + execute: async () => await db.connectionsStats() + }); +} - getConnectionsGroups(): Tool { - const pool = this.#pool; - return tool({ - description: `Get the connections groups for the database. This is a view in the pg_stat_activity table, grouped by (state, user, application_name, client_addr, wait_event_type, wait_event).`, - parameters: z.object({}), - execute: async () => { - try { - return await withPoolConnection(pool, toolGetConnectionsGroups); - } catch (error) { - return `Error getting connections groups: ${error}`; - } - } - }); - } +function getConnectionsGroups({ db }: DBToolsProps): Tool { + return tool({ + description: `Get the connections groups for the database. This is a view in the pg_stat_activity table, grouped by (state, user, application_name, client_addr, wait_event_type, wait_event).`, + parameters: z.object({}), + execute: async () => await db.connectionsGroups() + }); +} - getPerformanceAndVacuumSettings(): Tool { - const pool = this.#pool; - return tool({ - description: `Get the performance and vacuum settings for the database.`, - parameters: z.object({}), - execute: async () => { - try { - return await withPoolConnection(pool, getPerformanceAndVacuumSettings); - } catch (error) { - return `Error getting performance and vacuum settings: ${error}`; - } - } - }); - } +function getPerformanceAndVacuumSettings({ db }: DBToolsProps): Tool { + return tool({ + description: `Get the performance and vacuum settings for the database.`, + parameters: z.object({}), + execute: async () => await db.getPerformanceAndVacuumSettings() + }); } diff --git a/apps/dbagent/src/lib/ai/tools/index.ts b/apps/dbagent/src/lib/ai/tools/index.ts index 77d0cd5c..f1dbe19f 100644 --- a/apps/dbagent/src/lib/ai/tools/index.ts +++ b/apps/dbagent/src/lib/ai/tools/index.ts @@ -1,45 +1,4 @@ -import { DataStreamWriter, Tool } from 'ai'; -import { Pool } from 'pg'; -import { getUserSessionDBAccess } from '~/lib/db/db'; -import { Connection, Project } from '~/lib/db/schema'; -import { getArtifactTools } from './artifacts'; -import { getDBClusterTools } from './cluster'; -import { commonToolset } from './common'; -import { getDBSQLTools } from './db'; -import { getPlaybookToolset } from './playbook'; -import { mergeToolsets } from './types'; -import { mcpToolset } from './user-mcp'; - export * from './cluster'; export * from './common'; export * from './db'; export * from './playbook'; -export * from './types'; - -export async function getTools({ - project, - connection, - targetDb, - userId, - useArtifacts = false, - dataStream -}: { - project: Project; - connection: Connection; - targetDb: Pool; - userId: string; - useArtifacts?: boolean; - dataStream?: DataStreamWriter; -}): Promise> { - const dbAccess = await getUserSessionDBAccess(); - - const dbTools = getDBSQLTools(targetDb); - const clusterTools = getDBClusterTools(dbAccess, connection, project.cloudProvider); - const playbookToolset = getPlaybookToolset(dbAccess, project.id); - const mcpTools = await mcpToolset.listMCPTools(); - - const artifactsToolset = - useArtifacts && dataStream ? getArtifactTools({ dbAccess, userId, projectId: project.id, dataStream }) : {}; - - return mergeToolsets(mcpTools, commonToolset, playbookToolset, dbTools, clusterTools, artifactsToolset); -} diff --git a/apps/dbagent/src/lib/ai/tools/playbook.ts b/apps/dbagent/src/lib/ai/tools/playbook.ts index 4afb1dd3..3de265db 100644 --- a/apps/dbagent/src/lib/ai/tools/playbook.ts +++ b/apps/dbagent/src/lib/ai/tools/playbook.ts @@ -3,10 +3,42 @@ import { z } from 'zod'; import { DBAccess } from '~/lib/db/db'; import { getCustomPlaybookAndPlaybookTool, listCustomPlaybooksAndPlaybookTool } from '~/lib/tools/custom-playbooks'; import { getPlaybook, listPlaybooks } from '~/lib/tools/playbooks'; -import { ToolsetGroup } from './types'; -export function getPlaybookToolset(dbAccess: DBAccess, projectId: string): Record { - return new playbookTools(dbAccess, () => Promise.resolve({ projectId })).toolset(); +export interface PlaybookService { + fetch(name: string): Promise; + list(): Promise; +} + +export function getPlaybookToolset(tools?: PlaybookService): Record { + if (!tools) { + return builtinPlaybookToolset; + } + return { + fetch: playbookFetchTool(async (name: string) => tools.fetch(name)), + list: playbookListTool(async () => tools.list()) + }; +} + +export const builtinPlaybookToolset = { + getPlaybookTool: playbookFetchTool(async (name: string) => getPlaybook(name)), + listPlaybooksTool: playbookListTool(async () => listPlaybooks()) +}; + +export function projectPlaybookService( + dbAccess: DBAccess, + connProjectId: string | (() => Promise<{ projectId: string }>) +): PlaybookService { + const getter = typeof connProjectId === 'string' ? async () => ({ projectId: connProjectId }) : connProjectId; + return { + fetch: async (name: string): Promise => { + const { projectId } = await getter(); + return await getCustomPlaybookAndPlaybookTool(dbAccess, name, projectId); + }, + list: async (): Promise => { + const { projectId } = await getter(); + return await listCustomPlaybooksAndPlaybookTool(dbAccess, projectId); + } + }; } function playbookFetchTool(execute: (name: string) => Promise): Tool { @@ -26,43 +58,3 @@ function playbookListTool(execute: () => Promise): Tool { execute: async () => execute() }); } - -export const builtinPlaybookToolset = { - getPlaybookTool: playbookFetchTool(async (name: string) => getPlaybook(name)), - listPlaybooksTool: playbookListTool(async () => listPlaybooks()) -}; - -export class playbookTools implements ToolsetGroup { - #dbAccess: DBAccess; - #connProjectId: () => Promise<{ projectId: string }>; - - constructor(dbAccess: DBAccess, getter: () => Promise<{ projectId: string }>) { - this.#dbAccess = dbAccess; - this.#connProjectId = getter; - } - - toolset(): Record { - return { - getPlaybookTool: this.getPlaybookTool(), - listPlaybooksTool: this.listPlaybooksTool() - }; - } - - private getPlaybookTool(): Tool { - const db = this.#dbAccess; - const getter = this.#connProjectId; - return playbookFetchTool(async (name: string) => { - const { projectId } = await getter(); - return await getCustomPlaybookAndPlaybookTool(db, name, projectId); - }); - } - - private listPlaybooksTool(): Tool { - const db = this.#dbAccess; - const getter = this.#connProjectId; - return playbookListTool(async () => { - const { projectId } = await getter(); - return await listCustomPlaybooksAndPlaybookTool(db, projectId); - }); - } -} diff --git a/apps/dbagent/src/lib/ai/tools/types.ts b/apps/dbagent/src/lib/ai/tools/types.ts deleted file mode 100644 index 74654474..00000000 --- a/apps/dbagent/src/lib/ai/tools/types.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Tool } from 'ai'; - -export interface ToolsetGroup { - toolset(): Record; -} - -export type ToolsetBuilderFunction = () => Record; - -export type Toolset = ToolsetGroup | ToolsetBuilderFunction | Record; - -export function mergeToolsets(...toolsets: Toolset[]): Record { - const sets: Record[] = toolsets.map((toolset) => { - if (typeof toolset === 'function') { - return toolset(); - } else if ('toolset' in toolset) { - return (toolset as ToolsetGroup).toolset(); - } - return toolset; - }); - return sets.reduce((acc, tool) => ({ ...acc, ...tool }), {}); -} diff --git a/apps/dbagent/src/lib/env/server.ts b/apps/dbagent/src/lib/env/server.ts index 3daf17b7..2e485a39 100644 --- a/apps/dbagent/src/lib/env/server.ts +++ b/apps/dbagent/src/lib/env/server.ts @@ -38,5 +38,6 @@ const schema = z.object({ }); const serverEnv = schema.parse(process.env); +console.log('serverEnv', serverEnv); export const env = { ...clientEnv, ...serverEnv }; diff --git a/apps/dbagent/src/lib/monitoring/runner.ts b/apps/dbagent/src/lib/monitoring/runner.ts index 3eb6ac5e..e3c19655 100644 --- a/apps/dbagent/src/lib/monitoring/runner.ts +++ b/apps/dbagent/src/lib/monitoring/runner.ts @@ -1,10 +1,9 @@ import { Message } from '@ai-sdk/ui-utils'; import { generateId, generateObject, generateText, LanguageModelV1 } from 'ai'; import { z } from 'zod'; -import { getMonitoringModel, getMonitoringSystemPrompt } from '../ai/agent'; -import { getTools } from '../ai/tools'; +import { agentModelDeps, getMonitoringModel, getMonitoringSystemPrompt, monitoringModel } from '../ai/agent'; import { getConnectionFromSchedule } from '../db/connections'; -import { DBAccess } from '../db/db'; +import { DBAccess, getUserDBAccess } from '../db/db'; import { getProjectById } from '../db/projects'; import { insertScheduleRunLimitHistory } from '../db/schedule-runs'; import { Connection, Project, Schedule } from '../db/schema'; @@ -38,16 +37,23 @@ async function runModelPlaybook({ createdAt: new Date() }); - const monitoringSystemPrompt = getMonitoringSystemPrompt({ cloudProvider: project.cloudProvider }); const targetDb = getTargetDbPool(connection.connectionString); + const dbAccess = await getUserDBAccess(schedule.userId); + const deps = agentModelDeps({ + withMCP: true, + targetDb, + dbAccess, + connection, + cloudProvider: project.cloudProvider, + userId: schedule.userId + }); + try { - const tools = await getTools({ project, connection, targetDb, userId: schedule.userId }); - const result = await generateText({ + const result = await monitoringModel.generateText({ model: modelInstance, - system: monitoringSystemPrompt, maxSteps: 20, - tools, - messages + messages, + deps }); messages.push({ diff --git a/apps/dbagent/src/lib/tools/artifacts.ts b/apps/dbagent/src/lib/tools/artifacts.ts new file mode 100644 index 00000000..3ea31e6e --- /dev/null +++ b/apps/dbagent/src/lib/tools/artifacts.ts @@ -0,0 +1,199 @@ +import { DataStreamWriter } from 'ai'; +import { z } from 'zod'; +import { ArtifactKind } from '~/components/chat/artifacts/artifact'; +import { artifactKinds, documentHandlersByArtifactKind } from '~/components/chat/artifacts/server'; +import { generateUUID } from '~/components/chat/utils'; +import { getDocumentById, saveSuggestions } from '~/lib/db/chats'; +import { ArtifactSuggestion } from '~/lib/db/schema'; +import { commonModel } from '../ai/agent'; +import { DBAccess } from '../db/db'; + +export type ArtifactProjectProps = { + userId: string; + projectId: string; + dataStream: DataStreamWriter; + dbAccess: DBAccess; +}; + +export interface ArtifactsService { + createDocument({ title, kind }: { title: string; kind: (typeof artifactKinds)[number] }): Promise; + updateDocument({ id, description }: { id: string; description: string }): Promise; + requestSuggestions({ documentId }: { documentId: string }): Promise; +} + +export type DocumentOpResult = + | { + id: string; + title: string; + kind: ArtifactKind; + } + | { + error: string; + }; + +export function projectArtifactService(project: ArtifactProjectProps): ArtifactsService { + return { + createDocument: async ({ title, kind }) => await execCreateDocument(project, { title, kind }), + updateDocument: async ({ id, description }) => await execUpdateDocument(project, { id, description }), + requestSuggestions: async ({ documentId }) => await execRequestSuggestions(project, { documentId }) + }; +} + +export const execCreateDocument = async ( + { dataStream, userId, projectId, dbAccess }: ArtifactProjectProps, + { title, kind }: { title: string; kind: ArtifactKind } +): Promise => { + const id = generateUUID(); + + dataStream.writeData({ + type: 'kind', + content: kind + }); + + dataStream.writeData({ + type: 'id', + content: id + }); + + dataStream.writeData({ + type: 'title', + content: title + }); + + dataStream.writeData({ + type: 'clear', + content: '' + }); + + const documentHandler = documentHandlersByArtifactKind.find( + (documentHandlerByArtifactKind) => documentHandlerByArtifactKind.kind === kind + ); + + if (!documentHandler) { + throw new Error(`No document handler found for kind: ${kind}`); + } + + await documentHandler.onCreateDocument({ + id, + title, + dataStream, + userId, + projectId, + dbAccess + }); + + dataStream.writeData({ type: 'finish', content: '' }); + + return { + id, + title, + kind + }; +}; + +export const execUpdateDocument = async ( + { dataStream, userId, projectId, dbAccess }: ArtifactProjectProps, + { id, description }: { id: string; description: string } +): Promise => { + const document = await getDocumentById(dbAccess, { id }); + + if (!document) { + return { + error: 'Document not found' + }; + } + + dataStream.writeData({ + type: 'clear', + content: document.title + }); + + const documentHandler = documentHandlersByArtifactKind.find( + (documentHandlerByArtifactKind) => documentHandlerByArtifactKind.kind === document.kind + ); + + if (!documentHandler) { + throw new Error(`No document handler found for kind: ${document.kind}`); + } + + await documentHandler.onUpdateDocument({ + document, + description, + dataStream, + userId, + projectId, + dbAccess + }); + + dataStream.writeData({ type: 'finish', content: '' }); + + return { + id, + title: document.title, + kind: document.kind + }; +}; + +export const execRequestSuggestions = async ( + { dataStream, userId, projectId, dbAccess }: ArtifactProjectProps, + { documentId }: { documentId: string } +): Promise => { + const document = await getDocumentById(dbAccess, { id: documentId }); + if (!document || !document.content) { + return { + error: 'Document not found' + }; + } + + const suggestions: Array> = []; + + const { elementStream } = await commonModel.streamObject({ + system: + 'You are a help writing assistant. Given a piece of writing, please offer suggestions to improve the piece of writing and describe the change. It is very important for the edits to contain full sentences instead of just words. Max 5 suggestions.', + prompt: document.content, + output: 'array', + schema: z.object({ + originalSentence: z.string().describe('The original sentence'), + suggestedSentence: z.string().describe('The suggested sentence'), + description: z.string().describe('The description of the suggestion') + }), + metadata: { + tags: ['artifact', 'suggestion'] + } + }); + + for await (const element of elementStream) { + const suggestion = { + originalText: element.originalSentence, + suggestedText: element.suggestedSentence, + description: element.description, + id: generateUUID(), + documentId: documentId, + isResolved: false, + projectId + }; + + dataStream.writeData({ + type: 'suggestion', + content: suggestion + }); + + suggestions.push(suggestion); + } + + await saveSuggestions(dbAccess, { + suggestions: suggestions.map((suggestion) => ({ + ...suggestion, + userId, + projectId, + createdAt: new Date(), + documentCreatedAt: document.createdAt + })) + }); + + return { + id: documentId, + title: document.title, + kind: document.kind + }; +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 089b40bc..21d597b8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -113,10 +113,10 @@ importers: version: link:../../packages/theme '@mastra/core': specifier: ^0.9.3 - version: 0.9.3(react@19.1.0)(zod@3.24.4) + version: 0.9.3(openapi-types@12.1.3)(react@19.1.0)(zod@3.24.4) '@mastra/evals': specifier: ^0.1.22 - version: 0.1.22(ai@4.3.15(react@19.1.0)(zod@3.24.4))(react@19.1.0) + version: 0.1.22(ai@4.3.15(react@19.1.0)(zod@3.24.4))(openapi-types@12.1.3)(react@19.1.0) '@modelcontextprotocol/sdk': specifier: ^1.11.1 version: 1.11.1 @@ -171,6 +171,9 @@ importers: '@tanstack/react-query': specifier: ^5.75.7 version: 5.76.0(react@19.1.0) + '@types/ndjson': + specifier: ^2.0.4 + version: 2.0.4 '@vercel/functions': specifier: ^2.0.3 version: 2.0.3(@aws-sdk/credential-provider-web-identity@3.806.0) @@ -215,13 +218,16 @@ importers: version: 12.10.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) geist: specifier: ^1.4.2 - version: 1.4.2(next@15.3.2(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4)) + version: 1.4.2(next@15.3.2(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4)) import-in-the-middle: specifier: ^1.13.1 version: 1.13.1 kysely: specifier: ^0.28.2 version: 0.28.2 + langfuse: + specifier: ^3.37.2 + version: 3.37.2 langfuse-vercel: specifier: ^3.37.2 version: 3.37.2(ai@4.3.15(react@19.1.0)(zod@3.24.4)) @@ -231,12 +237,15 @@ importers: lucide-react: specifier: ^0.509.0 version: 0.509.0(react@19.1.0) + ndjson: + specifier: ^2.0.0 + version: 2.0.0 next: specifier: ^15.3.2 - version: 15.3.2(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4) + version: 15.3.2(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4) next-auth: specifier: 5.0.0-beta.25 - version: 5.0.0-beta.25(next@15.3.2(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4))(react@19.1.0) + version: 5.0.0-beta.25(next@15.3.2(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4))(react@19.1.0) next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -355,6 +364,9 @@ importers: autoprefixer: specifier: ^10.4.21 version: 10.4.21(postcss@8.5.3) + cmd-ts: + specifier: ^0.13.0 + version: 0.13.0 dockerode: specifier: ^4.0.6 version: 4.0.6 @@ -366,7 +378,7 @@ importers: version: 6.0.0 mastra: specifier: ^0.6.2 - version: 0.6.2(@opentelemetry/api@1.9.0)(react@19.1.0)(typescript@5.8.3) + version: 0.6.2(@opentelemetry/api@1.9.0)(openapi-types@12.1.3)(react@19.1.0)(typescript@5.8.3) papaparse: specifier: ^5.5.2 version: 5.5.2 @@ -764,118 +776,106 @@ packages: resolution: {integrity: sha512-qLKslgZbU+iocKo2+OwS2typ0EieN10bpa1MmHTte87DhcNrbEFPNEGRuYwDgfQCs9gMgMkjcNlFlFL6w0yF6Q==} engines: {node: '>=18.0.0'} - '@aws-sdk/client-cognito-identity@3.787.0': - resolution: {integrity: sha512-7v6nywZ5wcQxX7qdZ5M1ld15QdkzLU6fAKiEqbvJKu4dM8cFW6As+DbS990Mg46pp1xM/yvme+51xZDTfTfJZA==} + '@aws-sdk/client-cognito-identity@3.804.0': + resolution: {integrity: sha512-l4R2usRE9WHGK9MqU94+veX70m5moUj5hB+IAqI8tAZ4nAgeXpot3QKGgwdEVjKe1pKZwDP5tkHl01Umm2Ir7w==} engines: {node: '>=18.0.0'} '@aws-sdk/client-rds@3.806.0': resolution: {integrity: sha512-tHc0ca5f2iy+vTD2BqF4sYIV1J9tkyrsSBKl+k2psq9AgIvUOatSoL2rymuAKIgF7YqbA6qrpHI5vIjyEfRtaQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/client-sagemaker@3.787.0': - resolution: {integrity: sha512-uHmF6MiMus+OjFfVnkYs46CkExjUp6kZGB/gFjwiq5IU+DGnkIlmfbOlRuIlLflqPuADPcbiTiNi4IjluHGqVA==} + '@aws-sdk/client-sagemaker@3.805.0': + resolution: {integrity: sha512-c0HWGMjKhQ1sA/m032VWt1xS0FGOjJKPMgt6YsqwEzkFLQODb0V0bvdgukuwoLe1cI47M0pQSthKL5oTWXNdXg==} engines: {node: '>=18.0.0'} - '@aws-sdk/client-sso@3.787.0': - resolution: {integrity: sha512-L8R+Mh258G0DC73ktpSVrG4TT9i2vmDLecARTDR/4q5sRivdDQSL5bUp3LKcK80Bx+FRw3UETIlX6mYMLL9PJQ==} + '@aws-sdk/client-sso@3.804.0': + resolution: {integrity: sha512-6D5iQbL0MqlJ7B5aaHdP21k9+3H/od0jHjHSXegvFd4h2KQbD+QVTdEOSLeakgBGgHYRfiQXsrdMMzUz8vcpsw==} engines: {node: '>=18.0.0'} '@aws-sdk/client-sso@3.806.0': resolution: {integrity: sha512-X0p/9/u9e6b22rlQqKucdtjdqmjSNB4c/8zDEoD5MvgYAAbMF9HNE0ST2xaA/WsJ7uE0jFfhPY2/00pslL1DqQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/core@3.775.0': - resolution: {integrity: sha512-8vpW4WihVfz0DX+7WnnLGm3GuQER++b0IwQG35JlQMlgqnc44M//KbJPsIHA0aJUJVwJAEShgfr5dUbY8WUzaA==} + '@aws-sdk/core@3.804.0': + resolution: {integrity: sha512-KrYDEc6HaJE+Mx5lrwq6uhJxj1RYYfggQ+X+zQeKRyrZHl2GOxFl7PdnpdwtnaQIjX0gNkDzquhZSdyT0ar5rA==} engines: {node: '>=18.0.0'} '@aws-sdk/core@3.806.0': resolution: {integrity: sha512-HJRINPncdjPK0iL3f6cBpqCMaxVwq2oDbRCzOx04tsLZ0tNgRACBfT3d/zNVRvMt6fnOVKXoN1LAtQaw50pjEA==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-cognito-identity@3.787.0': - resolution: {integrity: sha512-nF5XjgvZHFuyttOeTjMgfEsg6slZPQ6uI34yzq12Kq4icFgcD4bQsijnQClMN7A0u5qR8Ad8kume4b7+I2++Ig==} + '@aws-sdk/credential-provider-cognito-identity@3.804.0': + resolution: {integrity: sha512-bAk/1McqERHl7LbmbqD5ZGlyyO10N80+YiM/2NI2HXd8MKm/7roZBGEQH8VH2pDDZsWnI4c24rue4xFEmH+gjw==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-env@3.775.0': - resolution: {integrity: sha512-6ESVxwCbGm7WZ17kY1fjmxQud43vzJFoLd4bmlR+idQSWdqlzGDYdcfzpjDKTcivdtNrVYmFvcH1JBUwCRAZhw==} + '@aws-sdk/credential-provider-env@3.804.0': + resolution: {integrity: sha512-5mjrWPa4iaBK9/HDEIVN8lGxsnjk60eBjwGaJV0I2uqxnTo1EuQmpLV3XdY/OzQeqJdpuH/DbC6XUIdy9bXNQA==} engines: {node: '>=18.0.0'} '@aws-sdk/credential-provider-env@3.806.0': resolution: {integrity: sha512-nbPwmZn0kt6Q1XI2FaJWP6AhF9tro4cO5HlmZQx8NU+B0H1y9WMo659Q5zLLY46BXgoQVIJEsPSZpcZk27O4aw==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-http@3.775.0': - resolution: {integrity: sha512-PjDQeDH/J1S0yWV32wCj2k5liRo0ssXMseCBEkCsD3SqsU8o5cU82b0hMX4sAib/RkglCSZqGO0xMiN0/7ndww==} + '@aws-sdk/credential-provider-http@3.804.0': + resolution: {integrity: sha512-TD84TXS/iDWcf+ggCq3n6yx36p1WXB2qgyHkbP/yVbdmix/vKU1twuB5qJvaY0PJWI0TOwBa9680XfsYrzaJAA==} engines: {node: '>=18.0.0'} '@aws-sdk/credential-provider-http@3.806.0': resolution: {integrity: sha512-e/gB2iJQQ4ZpecOVpEFhEvjGwuTqNCzhVaVsFYVc49FPfR1seuN7qBGYe1MO7mouGDQFInzJgcNup0DnYUrLiw==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-ini@3.787.0': - resolution: {integrity: sha512-hc2taRoDlXn2uuNuHWDJljVWYrp3r9JF1a/8XmOAZhVUNY+ImeeStylHXhXXKEA4JOjW+5PdJj0f1UDkVCHJiQ==} + '@aws-sdk/credential-provider-ini@3.804.0': + resolution: {integrity: sha512-LfReL9TnOOunJWeZbDXPePFEnvJE+jcA7iY/ItsThUALgTy+ydLUdOiwzMZFo1f0JZN/Rfrsb9FOd/xTOoZiFw==} engines: {node: '>=18.0.0'} '@aws-sdk/credential-provider-ini@3.806.0': resolution: {integrity: sha512-FogfbuYSEZgFxbNy0QcsBZHHe5mSv5HV3+JyB5n0kCyjOISCVCZD7gwxKdXjt8O1hXq5k5SOdQvydGULlB6rew==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-node@3.787.0': - resolution: {integrity: sha512-JioVi44B1vDMaK2CdzqimwvJD3uzvzbQhaEWXsGMBcMcNHajXAXf08EF50JG3ZhLrhhUsT1ObXpbTaPINOhh+g==} + '@aws-sdk/credential-provider-node@3.804.0': + resolution: {integrity: sha512-L2EK5fy2+7El7j7TcRcuwr2lzU5tQfXsfscg+dtFkLPjOqShknnqV/lXylb3QlWx8B3K/c/KK5rcWQl6cYUiDQ==} engines: {node: '>=18.0.0'} '@aws-sdk/credential-provider-node@3.806.0': resolution: {integrity: sha512-fZX8xP2Kf0k70kDTog/87fh/M+CV0E2yujSw1cUBJhDSwDX3RlUahiJk7TpB/KGw6hEFESMd6+7kq3UzYuw3rg==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-process@3.775.0': - resolution: {integrity: sha512-A6k68H9rQp+2+7P7SGO90Csw6nrUEm0Qfjpn9Etc4EboZhhCLs9b66umUsTsSBHus4FDIe5JQxfCUyt1wgNogg==} + '@aws-sdk/credential-provider-process@3.804.0': + resolution: {integrity: sha512-s6ng/rZj7WP8GGgxBXsoPZYlSu7MZAm9O8OLgSSWcw8/vaYW7hBVSEVVNMEUkJiJeEo7Lh+Y/3d6SY27S1of/g==} engines: {node: '>=18.0.0'} '@aws-sdk/credential-provider-process@3.806.0': resolution: {integrity: sha512-8Y8GYEw/1e5IZRDQL02H6nsTDcRWid/afRMeWg+93oLQmbHcTtdm48tjis+7Xwqy+XazhMDmkbUht11QPTDJcQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-sso@3.787.0': - resolution: {integrity: sha512-fHc08bsvwm4+dEMEQKnQ7c1irEQmmxbgS+Fq41y09pPvPh31nAhoMcjBSTWAaPHvvsRbTYvmP4Mf12ZGr8/nfg==} + '@aws-sdk/credential-provider-sso@3.804.0': + resolution: {integrity: sha512-9Tt5zmhiK2nBfJv52Is5gNtW6bhK0W20GRhckg4T+BlnxOkPy//2ui23DzYacrwETH6TE3kdoyL3xgEL++HSLg==} engines: {node: '>=18.0.0'} '@aws-sdk/credential-provider-sso@3.806.0': resolution: {integrity: sha512-hT9OBwCxWMPBydNhXm2gdNNzx5AJNheS9RglwDDvXWzQ9qDuRztjuMBilMSUMb0HF9K4IqQjYzGqczMuktz4qQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-provider-web-identity@3.787.0': - resolution: {integrity: sha512-SobmCwNbk6TfEsF283mZPQEI5vV2j6eY5tOCj8Er4Lzraxu9fBPADV+Bib2A8F6jlB1lMPJzOuDCbEasSt/RIw==} + '@aws-sdk/credential-provider-web-identity@3.804.0': + resolution: {integrity: sha512-eBICjQUnqaoiHl9/AHKVPt/YkrifDddAUNGWUj+9cb3bRml6PEBSHE0k/tbbCTMq1xz7CCP+gmnnAA92ChnseA==} engines: {node: '>=18.0.0'} '@aws-sdk/credential-provider-web-identity@3.806.0': resolution: {integrity: sha512-XxaSY9Zd3D4ClUGENYMvi52ac5FuJPPAsvRtEfyrSdEpf6QufbMpnexWBZMYRF31h/VutgqtJwosGgNytpxMEg==} engines: {node: '>=18.0.0'} - '@aws-sdk/credential-providers@3.787.0': - resolution: {integrity: sha512-kR3RtI7drOc9pho13vWbUC2Bvrx9A0G4iizBDGmTs08NOdg4w3c1I4kdLG9tyPiIMeVnH+wYrsli5CM7xIfqiA==} - engines: {node: '>=18.0.0'} - - '@aws-sdk/middleware-host-header@3.775.0': - resolution: {integrity: sha512-tkSegM0Z6WMXpLB8oPys/d+umYIocvO298mGvcMCncpRl77L9XkvSLJIFzaHes+o7djAgIduYw8wKIMStFss2w==} + '@aws-sdk/credential-providers@3.804.0': + resolution: {integrity: sha512-qDPsrmp4Z35T5Rprg4+mnZF+xz1cqMJYuwB3KuBaOyJ7ja5UlMthhnCEs2mwqSZZ3oLELSLEuWLio5hgmGbjLg==} engines: {node: '>=18.0.0'} '@aws-sdk/middleware-host-header@3.804.0': resolution: {integrity: sha512-bum1hLVBrn2lJCi423Z2fMUYtsbkGI2s4N+2RI2WSjvbaVyMSv/WcejIrjkqiiMR+2Y7m5exgoKeg4/TODLDPQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-logger@3.775.0': - resolution: {integrity: sha512-FaxO1xom4MAoUJsldmR92nT1G6uZxTdNYOFYtdHfd6N2wcNaTuxgjIvqzg5y7QIH9kn58XX/dzf1iTjgqUStZw==} - engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-logger@3.804.0': resolution: {integrity: sha512-w/qLwL3iq0KOPQNat0Kb7sKndl9BtceigINwBU7SpkYWX9L/Lem6f8NPEKrC9Tl4wDBht3Yztub4oRTy/horJA==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-recursion-detection@3.775.0': - resolution: {integrity: sha512-GLCzC8D0A0YDG5u3F5U03Vb9j5tcOEFhr8oc6PDk0k0vm5VwtZOE6LvK7hcCSoAB4HXyOUM0sQuXrbaAh9OwXA==} - engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-recursion-detection@3.804.0': resolution: {integrity: sha512-zqHOrvLRdsUdN/ehYfZ9Tf8svhbiLLz5VaWUz22YndFv6m9qaAcijkpAOlKexsv3nLBMJdSdJ6GUTAeIy3BZzw==} engines: {node: '>=18.0.0'} @@ -884,16 +884,16 @@ packages: resolution: {integrity: sha512-aMDWvYuO3bjoUm/wFLpG7TXRuocdddguZOtHyb+jLNIwhztChXkJHKSfAjtS6hNLTKL3JoRZM9dkiyFaYA2OdQ==} engines: {node: '>=18.0.0'} - '@aws-sdk/middleware-user-agent@3.787.0': - resolution: {integrity: sha512-Lnfj8SmPLYtrDFthNIaNj66zZsBCam+E4XiUDr55DIHTGstH6qZ/q6vg0GfbukxwSmUcGMwSR4Qbn8rb8yd77g==} + '@aws-sdk/middleware-user-agent@3.804.0': + resolution: {integrity: sha512-HoBaun4t3vAFhMj/I7L/HNBKBrAYu7Sb5bTFINx8kFCxPbqsvF+jOrEE8WiljHNy7FbPjz0mPVRUwO7RZSYNiQ==} engines: {node: '>=18.0.0'} '@aws-sdk/middleware-user-agent@3.806.0': resolution: {integrity: sha512-XoIromVffgXnc+/mjlR2EVzQVIei3bPVtafIZNsHuEmUvIWJXiWsa2eJpt3BUqa0HF9YPknK7ommNEhqRb8ucg==} engines: {node: '>=18.0.0'} - '@aws-sdk/nested-clients@3.787.0': - resolution: {integrity: sha512-xk03q1xpKNHgbuo+trEf1dFrI239kuMmjKKsqLEsHlAZbuFq4yRGMlHBrVMnKYOPBhVFDS/VineM991XI52fKg==} + '@aws-sdk/nested-clients@3.804.0': + resolution: {integrity: sha512-IOUcw6stjqYBMhLoAXlLVipYpAqLlA17jcyI0OzpS0pTD1RvBqEBckYibF4HJeReI+IiEHu/m0If0SKVR5WyXQ==} engines: {node: '>=18.0.0'} '@aws-sdk/nested-clients@3.806.0': @@ -905,8 +905,8 @@ packages: engines: {node: '>=14.0.0'} deprecated: This package has moved to @smithy/protocol-http - '@aws-sdk/region-config-resolver@3.775.0': - resolution: {integrity: sha512-40iH3LJjrQS3LKUJAl7Wj0bln7RFPEvUYKFxtP8a+oKFDO0F65F52xZxIJbPn6sHkxWDAnZlGgdjZXM3p2g5wQ==} + '@aws-sdk/region-config-resolver@3.804.0': + resolution: {integrity: sha512-Qlr8jVUL5U8Ej+84ElUTGeOok6hQXcJdx5IOSRoqKs6bCKVa8TtwgX1zZIajzjMhMgMlR3/V+M8oDVDKPB43Ug==} engines: {node: '>=18.0.0'} '@aws-sdk/region-config-resolver@3.806.0': @@ -918,24 +918,20 @@ packages: engines: {node: '>=14.0.0'} deprecated: This package has moved to @smithy/signature-v4 - '@aws-sdk/token-providers@3.787.0': - resolution: {integrity: sha512-d7/NIqxq308Zg0RPMNrmn0QvzniL4Hx8Qdwzr6YZWLYAbUSvZYS2ppLR3BFWSkV6SsTJUx8BuDaj3P8vttkrog==} + '@aws-sdk/token-providers@3.804.0': + resolution: {integrity: sha512-ndcLGD1nHEVJdWRl0lK8SfC0dN4j3X4gcGXEJxK16KZD23veMB2adHP69ySYXNFNo5gI6W9Ct9QXnB+tJCCS1Q==} engines: {node: '>=18.0.0'} '@aws-sdk/token-providers@3.806.0': resolution: {integrity: sha512-I6SxcsvV7yinJZmPgGullFHS0tsTKa7K3jEc5dmyCz8X+kZPfsWNffZmtmnCvWXPqMXWBvK6hVaxwomx79yeHA==} engines: {node: '>=18.0.0'} - '@aws-sdk/types@3.775.0': - resolution: {integrity: sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==} - engines: {node: '>=18.0.0'} - '@aws-sdk/types@3.804.0': resolution: {integrity: sha512-A9qnsy9zQ8G89vrPPlNG9d1d8QcKRGqJKqwyGgS0dclJpwy6d1EWgQLIolKPl6vcFpLoe6avLOLxr+h8ur5wpg==} engines: {node: '>=18.0.0'} - '@aws-sdk/util-endpoints@3.787.0': - resolution: {integrity: sha512-fd3zkiOkwnbdbN0Xp9TsP5SWrmv0SpT70YEdbb8wAj2DWQwiCmFszaSs+YCvhoCdmlR3Wl9Spu0pGpSAGKeYvQ==} + '@aws-sdk/util-endpoints@3.804.0': + resolution: {integrity: sha512-mT2R1De1fBT3vgm00ELVFoaArblW3PqGUCVteGGSUdJA525To7h6xPThrNrw3Dn8blAcR8VYGYte/JX7vKgFxw==} engines: {node: '>=18.0.0'} '@aws-sdk/util-endpoints@3.806.0': @@ -950,14 +946,11 @@ packages: resolution: {integrity: sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==} engines: {node: '>=18.0.0'} - '@aws-sdk/util-user-agent-browser@3.775.0': - resolution: {integrity: sha512-txw2wkiJmZKVdDbscK7VBK+u+TJnRtlUjRTLei+elZg2ADhpQxfVAQl436FUeIv6AhB/oRHW6/K/EAGXUSWi0A==} - '@aws-sdk/util-user-agent-browser@3.804.0': resolution: {integrity: sha512-KfW6T6nQHHM/vZBBdGn6fMyG/MgX5lq82TDdX4HRQRRuHKLgBWGpKXqqvBwqIaCdXwWHgDrg2VQups6GqOWW2A==} - '@aws-sdk/util-user-agent-node@3.787.0': - resolution: {integrity: sha512-mG7Lz8ydfG4SF9e8WSXiPQ/Lsn3n8A5B5jtPROidafi06I3ckV2WxyMLdwG14m919NoS6IOfWHyRGSqWIwbVKA==} + '@aws-sdk/util-user-agent-node@3.804.0': + resolution: {integrity: sha512-TacXL50ZHOeTUvN9LbHjS3muvvJNpzZp9cAtGRKpKXzlu8zCxPHrVU7dGOF6ONuNG30GpN2xzz81/XcCtg+8/A==} engines: {node: '>=18.0.0'} peerDependencies: aws-crt: '>=1.0.0' @@ -977,54 +970,54 @@ packages: '@aws-sdk/util-utf8-browser@3.259.0': resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} - '@babel/code-frame@7.26.2': - resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.26.8': - resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==} + '@babel/compat-data@7.27.2': + resolution: {integrity: sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==} engines: {node: '>=6.9.0'} - '@babel/core@7.26.10': - resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==} + '@babel/core@7.27.1': + resolution: {integrity: sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==} engines: {node: '>=6.9.0'} - '@babel/generator@7.27.0': - resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==} + '@babel/generator@7.27.1': + resolution: {integrity: sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.0': - resolution: {integrity: sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==} + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.25.9': - resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.26.0': - resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + '@babel/helper-module-transforms@7.27.1': + resolution: {integrity: sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-string-parser@7.25.9': - resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.25.9': - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.25.9': - resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.27.0': - resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==} + '@babel/helpers@7.27.1': + resolution: {integrity: sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==} engines: {node: '>=6.9.0'} - '@babel/parser@7.27.0': - resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==} + '@babel/parser@7.27.2': + resolution: {integrity: sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==} engines: {node: '>=6.0.0'} hasBin: true @@ -1032,16 +1025,16 @@ packages: resolution: {integrity: sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==} engines: {node: '>=6.9.0'} - '@babel/template@7.27.0': - resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==} + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.27.0': - resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==} + '@babel/traverse@7.27.1': + resolution: {integrity: sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg==} engines: {node: '>=6.9.0'} - '@babel/types@7.27.0': - resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} + '@babel/types@7.27.1': + resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} engines: {node: '>=6.9.0'} '@balena/dockerignore@1.0.2': @@ -1097,150 +1090,300 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.25.4': + resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.2': resolution: {integrity: sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.25.4': + resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.2': resolution: {integrity: sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.25.4': + resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.2': resolution: {integrity: sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.25.4': + resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.2': resolution: {integrity: sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.25.4': + resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.2': resolution: {integrity: sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.25.4': + resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.2': resolution: {integrity: sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.25.4': + resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.2': resolution: {integrity: sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.25.4': + resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.2': resolution: {integrity: sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.25.4': + resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.2': resolution: {integrity: sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.25.4': + resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.2': resolution: {integrity: sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.25.4': + resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.2': resolution: {integrity: sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.25.4': + resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.2': resolution: {integrity: sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.25.4': + resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.2': resolution: {integrity: sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.25.4': + resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.2': resolution: {integrity: sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.25.4': + resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.2': resolution: {integrity: sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.25.4': + resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.2': resolution: {integrity: sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.25.4': + resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.2': resolution: {integrity: sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.25.4': + resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.2': resolution: {integrity: sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.25.4': + resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.2': resolution: {integrity: sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.25.4': + resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.2': resolution: {integrity: sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.25.4': + resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/sunos-x64@0.25.2': resolution: {integrity: sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.25.4': + resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.2': resolution: {integrity: sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.25.4': + resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.2': resolution: {integrity: sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.25.4': + resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.2': resolution: {integrity: sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.25.4': + resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.4.1': resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2626,8 +2769,8 @@ packages: '@panva/hkdf@1.2.1': resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} - '@petamoriken/float16@3.9.1': - resolution: {integrity: sha512-j+ejhYwY6PeB+v1kn7lZFACUIG97u90WxMuGosILFsl9d4Ovi0sjk0GlPfoEcx+FzvXZDAfioD+NGnnPamXgMA==} + '@petamoriken/float16@3.9.2': + resolution: {integrity: sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog==} '@playwright/test@1.50.1': resolution: {integrity: sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==} @@ -3433,101 +3576,201 @@ packages: cpu: [arm] os: [android] + '@rollup/rollup-android-arm-eabi@4.40.2': + resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==} + cpu: [arm] + os: [android] + '@rollup/rollup-android-arm64@4.39.0': resolution: {integrity: sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==} cpu: [arm64] os: [android] + '@rollup/rollup-android-arm64@4.40.2': + resolution: {integrity: sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==} + cpu: [arm64] + os: [android] + '@rollup/rollup-darwin-arm64@4.39.0': resolution: {integrity: sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==} cpu: [arm64] os: [darwin] + '@rollup/rollup-darwin-arm64@4.40.2': + resolution: {integrity: sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==} + cpu: [arm64] + os: [darwin] + '@rollup/rollup-darwin-x64@4.39.0': resolution: {integrity: sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==} cpu: [x64] os: [darwin] + '@rollup/rollup-darwin-x64@4.40.2': + resolution: {integrity: sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==} + cpu: [x64] + os: [darwin] + '@rollup/rollup-freebsd-arm64@4.39.0': resolution: {integrity: sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==} cpu: [arm64] os: [freebsd] + '@rollup/rollup-freebsd-arm64@4.40.2': + resolution: {integrity: sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==} + cpu: [arm64] + os: [freebsd] + '@rollup/rollup-freebsd-x64@4.39.0': resolution: {integrity: sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==} cpu: [x64] os: [freebsd] + '@rollup/rollup-freebsd-x64@4.40.2': + resolution: {integrity: sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==} + cpu: [x64] + os: [freebsd] + '@rollup/rollup-linux-arm-gnueabihf@4.39.0': resolution: {integrity: sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==} cpu: [arm] os: [linux] + '@rollup/rollup-linux-arm-gnueabihf@4.40.2': + resolution: {integrity: sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==} + cpu: [arm] + os: [linux] + '@rollup/rollup-linux-arm-musleabihf@4.39.0': resolution: {integrity: sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==} cpu: [arm] os: [linux] + '@rollup/rollup-linux-arm-musleabihf@4.40.2': + resolution: {integrity: sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==} + cpu: [arm] + os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.39.0': resolution: {integrity: sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-gnu@4.40.2': + resolution: {integrity: sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==} + cpu: [arm64] + os: [linux] + '@rollup/rollup-linux-arm64-musl@4.39.0': resolution: {integrity: sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==} cpu: [arm64] os: [linux] + '@rollup/rollup-linux-arm64-musl@4.40.2': + resolution: {integrity: sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==} + cpu: [arm64] + os: [linux] + '@rollup/rollup-linux-loongarch64-gnu@4.39.0': resolution: {integrity: sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==} cpu: [loong64] os: [linux] + '@rollup/rollup-linux-loongarch64-gnu@4.40.2': + resolution: {integrity: sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==} + cpu: [loong64] + os: [linux] + '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': resolution: {integrity: sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==} cpu: [ppc64] os: [linux] + '@rollup/rollup-linux-powerpc64le-gnu@4.40.2': + resolution: {integrity: sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==} + cpu: [ppc64] + os: [linux] + '@rollup/rollup-linux-riscv64-gnu@4.39.0': resolution: {integrity: sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==} cpu: [riscv64] os: [linux] + '@rollup/rollup-linux-riscv64-gnu@4.40.2': + resolution: {integrity: sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==} + cpu: [riscv64] + os: [linux] + '@rollup/rollup-linux-riscv64-musl@4.39.0': resolution: {integrity: sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==} cpu: [riscv64] os: [linux] + '@rollup/rollup-linux-riscv64-musl@4.40.2': + resolution: {integrity: sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==} + cpu: [riscv64] + os: [linux] + '@rollup/rollup-linux-s390x-gnu@4.39.0': resolution: {integrity: sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==} cpu: [s390x] os: [linux] + '@rollup/rollup-linux-s390x-gnu@4.40.2': + resolution: {integrity: sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==} + cpu: [s390x] + os: [linux] + '@rollup/rollup-linux-x64-gnu@4.39.0': resolution: {integrity: sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-gnu@4.40.2': + resolution: {integrity: sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==} + cpu: [x64] + os: [linux] + '@rollup/rollup-linux-x64-musl@4.39.0': resolution: {integrity: sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==} cpu: [x64] os: [linux] + '@rollup/rollup-linux-x64-musl@4.40.2': + resolution: {integrity: sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==} + cpu: [x64] + os: [linux] + '@rollup/rollup-win32-arm64-msvc@4.39.0': resolution: {integrity: sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==} cpu: [arm64] os: [win32] + '@rollup/rollup-win32-arm64-msvc@4.40.2': + resolution: {integrity: sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==} + cpu: [arm64] + os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.39.0': resolution: {integrity: sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==} cpu: [ia32] os: [win32] + '@rollup/rollup-win32-ia32-msvc@4.40.2': + resolution: {integrity: sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==} + cpu: [ia32] + os: [win32] + '@rollup/rollup-win32-x64-msvc@4.39.0': resolution: {integrity: sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==} cpu: [x64] os: [win32] + '@rollup/rollup-win32-x64-msvc@4.40.2': + resolution: {integrity: sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==} + cpu: [x64] + os: [win32] + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -3571,18 +3814,10 @@ packages: resolution: {integrity: sha512-Sl/78VDtgqKxN2+1qduaVE140XF+Xg+TafkncspwM4jFP/LHr76ZHmIY/y3V1M0mMLNk+Je6IGbzxy23RSToMw==} engines: {node: '>=18.0.0'} - '@smithy/config-resolver@4.1.0': - resolution: {integrity: sha512-8smPlwhga22pwl23fM5ew4T9vfLUCeFXlcqNOCD5M5h8VmNPNUE9j6bQSuRXpDSV11L/E/SwEBQuW8hr6+nS1A==} - engines: {node: '>=18.0.0'} - '@smithy/config-resolver@4.1.2': resolution: {integrity: sha512-7r6mZGwb5LmLJ+zPtkLoznf2EtwEuSWdtid10pjGl/7HefCE4mueOkrfki8JCUm99W6UfP47/r3tbxx9CfBN5A==} engines: {node: '>=18.0.0'} - '@smithy/core@3.3.0': - resolution: {integrity: sha512-r6gvs5OfRq/w+9unPm7B3po4rmWaGh0CIL/OwHntGGux7+RhOOZLGuurbeMgWV6W55ZuyMTypJLeH0vn/ZRaWQ==} - engines: {node: '>=18.0.0'} - '@smithy/core@3.3.1': resolution: {integrity: sha512-W7AppgQD3fP1aBmo8wWo0id5zeR2/aYRy067vZsDVaa6v/mdhkg6DxXwEVuSPjZl+ZnvWAQbUMCd5ckw38+tHQ==} engines: {node: '>=18.0.0'} @@ -3630,18 +3865,10 @@ packages: resolution: {integrity: sha512-hAfEXm1zU+ELvucxqQ7I8SszwQ4znWMbNv6PLMndN83JJN41EPuS93AIyh2N+gJ6x8QFhzSO6b7q2e6oClDI8A==} engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@4.1.1': - resolution: {integrity: sha512-z5RmcHxjvScL+LwEDU2mTNCOhgUs4lu5PGdF1K36IPRmUHhNFxNxgenSB7smyDiYD4vdKQ7CAZtG5cUErqib9w==} - engines: {node: '>=18.0.0'} - '@smithy/middleware-endpoint@4.1.4': resolution: {integrity: sha512-qWyYvszzvDjT2AxRvEpNhnMTo8QX9MCAtuSA//kYbXewb+2mEGQCk1UL4dNIrKLcF5KT11dOJtxFYT0kzajq5g==} engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.1.2': - resolution: {integrity: sha512-qN/Mmxm8JWtFAjozJ8VSTM83KOX4cIks8UjDqqNkKIegzPrE5ZKPNCQ/DqUSIF90pue5a/NycNXnBod2NwvZZQ==} - engines: {node: '>=18.0.0'} - '@smithy/middleware-retry@4.1.5': resolution: {integrity: sha512-eQguCTA2TRGyg4P7gDuhRjL2HtN5OKJXysq3Ufj0EppZe4XBmSyKIvVX9ws9KkD3lkJskw1tfE96wMFsiUShaw==} engines: {node: '>=18.0.0'} @@ -3654,10 +3881,6 @@ packages: resolution: {integrity: sha512-eSPVcuJJGVYrFYu2hEq8g8WWdJav3sdrI4o2c6z/rjnYDd3xH9j9E7deZQCzFn4QvGPouLngH3dQ+QVTxv5bOQ==} engines: {node: '>=18.0.0'} - '@smithy/node-config-provider@4.0.2': - resolution: {integrity: sha512-WgCkILRZfJwJ4Da92a6t3ozN/zcvYyJGUTmfGbgS/FkCcoCjl7G4FJaCDN1ySdvLvemnQeo25FdkyMSTSwulsw==} - engines: {node: '>=18.0.0'} - '@smithy/node-config-provider@4.1.1': resolution: {integrity: sha512-1slS5jf5icHETwl5hxEVBj+mh6B+LbVW4yRINsGtUKH+nxM5Pw2H59+qf+JqYFCHp9jssG4vX81f5WKnjMN3Vw==} engines: {node: '>=18.0.0'} @@ -3702,10 +3925,6 @@ packages: resolution: {integrity: sha512-4t5WX60sL3zGJF/CtZsUQTs3UrZEDO2P7pEaElrekbLqkWPYkgqNW1oeiNYC6xXifBnT9dVBOnNQRvOE9riU9w==} engines: {node: '>=18.0.0'} - '@smithy/smithy-client@4.2.1': - resolution: {integrity: sha512-fbniZef60QdsBc4ZY0iyI8xbFHIiC/QRtPi66iE4ufjiE/aaz7AfUXzcWMkpO8r+QhLeNRIfmPchIG+3/QDZ6g==} - engines: {node: '>=18.0.0'} - '@smithy/smithy-client@4.2.4': resolution: {integrity: sha512-oolSEpr/ABUtVmFMdNgi6sSXsK4csV9n4XM9yXgvDJGRa32tQDUdv9s+ztFZKccay1AiTWLSGsyDj2xy1gsv7Q==} engines: {node: '>=18.0.0'} @@ -3754,22 +3973,10 @@ packages: resolution: {integrity: sha512-0vPKiC+rXWMq397tsa/RFcO/kJ1UsibgNCXScMsRwzm9WMT4QjGf43zVPWZ5hPLu3z/1XddiZFIlKcu2j/yUuQ==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-browser@4.0.9': - resolution: {integrity: sha512-B8j0XsElvyhv6+5hlFf6vFV/uCSyLKcInpeXOGnOImX2mGXshE01RvPoGipTlRpIk53e6UfYj7WdDdgbVfXDZw==} - engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.0.12': resolution: {integrity: sha512-zCx9noceM3Pw2jvcJ3w3RbvKnPe3lCo6txH9ksZj6CeRZPkvRZPLXmKVSOvDr9QQP3VRq/WnBLd+LTZAL7+0IQ==} engines: {node: '>=18.0.0'} - '@smithy/util-defaults-mode-node@4.0.9': - resolution: {integrity: sha512-wTDU8P/zdIf9DOpV5qm64HVgGRXvqjqB/fJZTEQbrz3s79JHM/E7XkMm/876Oq+ZLHJQgnXM9QHDo29dlM62eA==} - engines: {node: '>=18.0.0'} - - '@smithy/util-endpoints@3.0.2': - resolution: {integrity: sha512-6QSutU5ZyrpNbnd51zRTL7goojlcnuOB55+F9VBD+j8JpRY50IGamsjlycrmpn8PQkmJucFW8A0LSfXj7jjtLQ==} - engines: {node: '>=18.0.0'} - '@smithy/util-endpoints@3.0.4': resolution: {integrity: sha512-VfFATC1bmZLV2858B/O1NpMcL32wYo8DPPhHxYxDCodDl3f3mSZ5oJheW1IF91A0EeAADz2WsakM/hGGPGNKLg==} engines: {node: '>=18.0.0'} @@ -4117,6 +4324,9 @@ packages: '@types/mysql@2.15.26': resolution: {integrity: sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==} + '@types/ndjson@2.0.4': + resolution: {integrity: sha512-ajAl7AjhFstF6waORYNSS49GL5iBKisqJlgvXuprXFKCX9fto4ordlNU3+XMgkMddgeR0WoQQBmKUk0v0dJ4pw==} + '@types/node@18.19.80': resolution: {integrity: sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ==} @@ -4161,6 +4371,9 @@ packages: '@types/tedious@4.0.14': resolution: {integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==} + '@types/through@0.0.33': + resolution: {integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==} + '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} @@ -4428,8 +4641,8 @@ packages: resolution: {integrity: sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==} engines: {node: '>=4'} - axios@1.8.4: - resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==} + axios@1.9.0: + resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} @@ -4483,6 +4696,11 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + browserslist@4.24.5: + resolution: {integrity: sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} @@ -4545,6 +4763,9 @@ packages: caniuse-lite@1.0.30001703: resolution: {integrity: sha512-kRlAGTRWgPsOj7oARC9m1okJEXdL/8fekFVcxA8Hl7GH4r/sN4OJn/i6Flde373T50KS7Y37oFbMwlE8+F42kQ==} + caniuse-lite@1.0.30001717: + resolution: {integrity: sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw==} + canvas-confetti@1.9.3: resolution: {integrity: sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==} @@ -4646,14 +4867,17 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + cmd-ts@0.13.0: + resolution: {integrity: sha512-nsnxf6wNIM/JAS7T/x/1JmbEsjH0a8tezXqqpaL0O6+eV0/aDEnRxwjxpu0VzDdRcaC1ixGSbRlUuf/IU59I4g==} + cmdk@1.1.1: resolution: {integrity: sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==} peerDependencies: react: ^18 || ^19 || ^19.0.0-rc react-dom: ^18 || ^19 || ^19.0.0-rc - cohere-ai@7.16.0: - resolution: {integrity: sha512-hrG3EtVNSJLxJTaEeGRli+5rX34GiQC/UZ2WuUpaWiRwYbfzz7zKflfU/tg8SFFjkvYHDyS43UvVESepNd8C4w==} + cohere-ai@7.17.1: + resolution: {integrity: sha512-GI/uWVYYGIN3gdjJRlbjEaLJNJVXsUJyOlPqwBWgAmK18kP4CJoErxKwU0aLe3tHHOBcC2RqXe6PmGO0dz7dpQ==} color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -4960,6 +5184,9 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + diff-match-patch@1.0.5: resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==} @@ -5109,6 +5336,9 @@ packages: resolution: {integrity: sha512-/RInbCy1d4P6Zdfa+TMVsf/ufZVotat5hCw3QXmWtjU+3pFEOvOQ7ibo3aIxyCJw2leIeAMjmPj+1SLJiCpdrQ==} engines: {node: '>=12.0.0'} + electron-to-chromium@1.5.150: + resolution: {integrity: sha512-rOOkP2ZUMx1yL4fCxXQKDHQ8ZXwisb2OycOQVKHgvB3ZI4CvehOd4y2tfnnLDieJ3Zs1RL1Dlp3cMkyIn7nnXA==} + electron-to-chromium@1.5.87: resolution: {integrity: sha512-mPFwmEWmRivw2F8x3w3l2m6htAUN97Gy0kwpO++2m9iT1Gt8RCFVUfv9U/sIbHJ6rY4P6/ooqFL/eL7ock+pPg==} @@ -5166,9 +5396,6 @@ packages: resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} - es-module-lexer@1.6.0: - resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==} - es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} @@ -5204,6 +5431,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.25.4: + resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -5419,6 +5651,10 @@ packages: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -5793,8 +6029,8 @@ packages: highlightjs-vue@1.0.0: resolution: {integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==} - hono-openapi@0.4.6: - resolution: {integrity: sha512-wSDySp2cS5Zcf1OeLG7nCP3eMsCpcDomN137T9B6/Z5Qq3D0nWgMf0I3Gl41SE1rE37OBQ0Smqx3LOP9Hk//7A==} + hono-openapi@0.4.8: + resolution: {integrity: sha512-LYr5xdtD49M7hEAduV1PftOMzuT8ZNvkyWfh1DThkLsIr4RkvDb12UxgIiFbwrJB6FLtFXLoOZL9x4IeDk2+VA==} peerDependencies: '@hono/arktype-validator': ^2.0.0 '@hono/effect-validator': ^1.2.0 @@ -5803,7 +6039,7 @@ packages: '@hono/zod-validator': ^0.4.1 '@sinclair/typebox': ^0.34.9 '@valibot/to-json-schema': ^1.0.0-beta.3 - arktype: ^2.0.0-rc.25 + arktype: ^2.0.0 effect: ^3.11.3 hono: ^4.6.13 openapi-types: ^12.1.3 @@ -5831,8 +6067,6 @@ packages: optional: true hono: optional: true - openapi-types: - optional: true valibot: optional: true zod: @@ -5840,8 +6074,8 @@ packages: zod-openapi: optional: true - hono@4.7.6: - resolution: {integrity: sha512-564rVzELU+9BRqqx5k8sT2NFwGD3I3Vifdb6P7CmM6FiarOSY+fDC+6B+k9wcCb86ReoayteZP2ki0cRLN1jbw==} + hono@4.7.8: + resolution: {integrity: sha512-PCibtFdxa7/Ldud9yddl1G81GjYaeMYYTq4ywSaNsYbB1Lug4mwtOMJf2WXykL0pntYwmpRJeOI3NmoDgD+Jxw==} engines: {node: '>=16.9.0'} html-entities@2.6.0: @@ -5982,6 +6216,10 @@ packages: resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + is-data-view@1.0.2: resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} engines: {node: '>= 0.4'} @@ -6259,6 +6497,7 @@ packages: libsql@0.4.7: resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lightningcss-darwin-arm64@1.29.2: @@ -6688,6 +6927,11 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + ndjson@2.0.0: + resolution: {integrity: sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==} + engines: {node: '>=10'} + hasBin: true + negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} @@ -6858,6 +7102,9 @@ packages: resolution: {integrity: sha512-NeaCX6WW2L8cRCSqy3bInlo5ojjQqu2fD3D+9W5qb5irwxhEyWKXeH2vZ8W9r6VxaMPUan+4/7NDwZMtouZxEw==} os: [win32, darwin, linux] + openapi-types@12.1.3: + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -7501,6 +7748,11 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -7554,6 +7806,11 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rollup@4.40.2: + resolution: {integrity: sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + rope-sequence@1.3.4: resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} @@ -7743,6 +8000,9 @@ packages: split-ca@1.0.1: resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} + split2@3.2.2: + resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -7952,6 +8212,9 @@ packages: resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} engines: {node: '>=18'} + through2@4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -8157,6 +8420,12 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -8590,7 +8859,7 @@ snapshots: '@aws-crypto/crc32@3.0.0': dependencies: '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.775.0 + '@aws-sdk/types': 3.804.0 tslib: 1.14.1 '@aws-crypto/sha256-browser@5.2.0': @@ -8615,7 +8884,7 @@ snapshots: '@aws-crypto/util@3.0.0': dependencies: - '@aws-sdk/types': 3.775.0 + '@aws-sdk/types': 3.804.0 '@aws-sdk/util-utf8-browser': 3.259.0 tslib: 1.14.1 @@ -8671,43 +8940,43 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-cognito-identity@3.787.0': + '@aws-sdk/client-cognito-identity@3.804.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.775.0 - '@aws-sdk/credential-provider-node': 3.787.0 - '@aws-sdk/middleware-host-header': 3.775.0 - '@aws-sdk/middleware-logger': 3.775.0 - '@aws-sdk/middleware-recursion-detection': 3.775.0 - '@aws-sdk/middleware-user-agent': 3.787.0 - '@aws-sdk/region-config-resolver': 3.775.0 - '@aws-sdk/types': 3.775.0 - '@aws-sdk/util-endpoints': 3.787.0 - '@aws-sdk/util-user-agent-browser': 3.775.0 - '@aws-sdk/util-user-agent-node': 3.787.0 - '@smithy/config-resolver': 4.1.0 - '@smithy/core': 3.3.0 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/credential-provider-node': 3.804.0 + '@aws-sdk/middleware-host-header': 3.804.0 + '@aws-sdk/middleware-logger': 3.804.0 + '@aws-sdk/middleware-recursion-detection': 3.804.0 + '@aws-sdk/middleware-user-agent': 3.804.0 + '@aws-sdk/region-config-resolver': 3.804.0 + '@aws-sdk/types': 3.804.0 + '@aws-sdk/util-endpoints': 3.804.0 + '@aws-sdk/util-user-agent-browser': 3.804.0 + '@aws-sdk/util-user-agent-node': 3.804.0 + '@smithy/config-resolver': 4.1.2 + '@smithy/core': 3.3.1 '@smithy/fetch-http-handler': 5.0.2 '@smithy/hash-node': 4.0.2 '@smithy/invalid-dependency': 4.0.2 '@smithy/middleware-content-length': 4.0.2 - '@smithy/middleware-endpoint': 4.1.1 - '@smithy/middleware-retry': 4.1.2 + '@smithy/middleware-endpoint': 4.1.4 + '@smithy/middleware-retry': 4.1.5 '@smithy/middleware-serde': 4.0.3 '@smithy/middleware-stack': 4.0.2 - '@smithy/node-config-provider': 4.0.2 + '@smithy/node-config-provider': 4.1.1 '@smithy/node-http-handler': 4.0.4 '@smithy/protocol-http': 5.1.0 - '@smithy/smithy-client': 4.2.1 + '@smithy/smithy-client': 4.2.4 '@smithy/types': 4.2.0 '@smithy/url-parser': 4.0.2 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.9 - '@smithy/util-defaults-mode-node': 4.0.9 - '@smithy/util-endpoints': 3.0.2 + '@smithy/util-defaults-mode-browser': 4.0.12 + '@smithy/util-defaults-mode-node': 4.0.12 + '@smithy/util-endpoints': 3.0.4 '@smithy/util-middleware': 4.0.2 '@smithy/util-retry': 4.0.3 '@smithy/util-utf8': 4.0.0 @@ -8761,43 +9030,43 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sagemaker@3.787.0': + '@aws-sdk/client-sagemaker@3.805.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.775.0 - '@aws-sdk/credential-provider-node': 3.787.0 - '@aws-sdk/middleware-host-header': 3.775.0 - '@aws-sdk/middleware-logger': 3.775.0 - '@aws-sdk/middleware-recursion-detection': 3.775.0 - '@aws-sdk/middleware-user-agent': 3.787.0 - '@aws-sdk/region-config-resolver': 3.775.0 - '@aws-sdk/types': 3.775.0 - '@aws-sdk/util-endpoints': 3.787.0 - '@aws-sdk/util-user-agent-browser': 3.775.0 - '@aws-sdk/util-user-agent-node': 3.787.0 - '@smithy/config-resolver': 4.1.0 - '@smithy/core': 3.3.0 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/credential-provider-node': 3.804.0 + '@aws-sdk/middleware-host-header': 3.804.0 + '@aws-sdk/middleware-logger': 3.804.0 + '@aws-sdk/middleware-recursion-detection': 3.804.0 + '@aws-sdk/middleware-user-agent': 3.804.0 + '@aws-sdk/region-config-resolver': 3.804.0 + '@aws-sdk/types': 3.804.0 + '@aws-sdk/util-endpoints': 3.804.0 + '@aws-sdk/util-user-agent-browser': 3.804.0 + '@aws-sdk/util-user-agent-node': 3.804.0 + '@smithy/config-resolver': 4.1.2 + '@smithy/core': 3.3.1 '@smithy/fetch-http-handler': 5.0.2 '@smithy/hash-node': 4.0.2 '@smithy/invalid-dependency': 4.0.2 '@smithy/middleware-content-length': 4.0.2 - '@smithy/middleware-endpoint': 4.1.1 - '@smithy/middleware-retry': 4.1.2 + '@smithy/middleware-endpoint': 4.1.4 + '@smithy/middleware-retry': 4.1.5 '@smithy/middleware-serde': 4.0.3 '@smithy/middleware-stack': 4.0.2 - '@smithy/node-config-provider': 4.0.2 + '@smithy/node-config-provider': 4.1.1 '@smithy/node-http-handler': 4.0.4 '@smithy/protocol-http': 5.1.0 - '@smithy/smithy-client': 4.2.1 + '@smithy/smithy-client': 4.2.4 '@smithy/types': 4.2.0 '@smithy/url-parser': 4.0.2 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.9 - '@smithy/util-defaults-mode-node': 4.0.9 - '@smithy/util-endpoints': 3.0.2 + '@smithy/util-defaults-mode-browser': 4.0.12 + '@smithy/util-defaults-mode-node': 4.0.12 + '@smithy/util-endpoints': 3.0.4 '@smithy/util-middleware': 4.0.2 '@smithy/util-retry': 4.0.3 '@smithy/util-utf8': 4.0.0 @@ -8808,42 +9077,42 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso@3.787.0': + '@aws-sdk/client-sso@3.804.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.775.0 - '@aws-sdk/middleware-host-header': 3.775.0 - '@aws-sdk/middleware-logger': 3.775.0 - '@aws-sdk/middleware-recursion-detection': 3.775.0 - '@aws-sdk/middleware-user-agent': 3.787.0 - '@aws-sdk/region-config-resolver': 3.775.0 - '@aws-sdk/types': 3.775.0 - '@aws-sdk/util-endpoints': 3.787.0 - '@aws-sdk/util-user-agent-browser': 3.775.0 - '@aws-sdk/util-user-agent-node': 3.787.0 - '@smithy/config-resolver': 4.1.0 - '@smithy/core': 3.3.0 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/middleware-host-header': 3.804.0 + '@aws-sdk/middleware-logger': 3.804.0 + '@aws-sdk/middleware-recursion-detection': 3.804.0 + '@aws-sdk/middleware-user-agent': 3.804.0 + '@aws-sdk/region-config-resolver': 3.804.0 + '@aws-sdk/types': 3.804.0 + '@aws-sdk/util-endpoints': 3.804.0 + '@aws-sdk/util-user-agent-browser': 3.804.0 + '@aws-sdk/util-user-agent-node': 3.804.0 + '@smithy/config-resolver': 4.1.2 + '@smithy/core': 3.3.1 '@smithy/fetch-http-handler': 5.0.2 '@smithy/hash-node': 4.0.2 '@smithy/invalid-dependency': 4.0.2 '@smithy/middleware-content-length': 4.0.2 - '@smithy/middleware-endpoint': 4.1.1 - '@smithy/middleware-retry': 4.1.2 + '@smithy/middleware-endpoint': 4.1.4 + '@smithy/middleware-retry': 4.1.5 '@smithy/middleware-serde': 4.0.3 '@smithy/middleware-stack': 4.0.2 - '@smithy/node-config-provider': 4.0.2 + '@smithy/node-config-provider': 4.1.1 '@smithy/node-http-handler': 4.0.4 '@smithy/protocol-http': 5.1.0 - '@smithy/smithy-client': 4.2.1 + '@smithy/smithy-client': 4.2.4 '@smithy/types': 4.2.0 '@smithy/url-parser': 4.0.2 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.9 - '@smithy/util-defaults-mode-node': 4.0.9 - '@smithy/util-endpoints': 3.0.2 + '@smithy/util-defaults-mode-browser': 4.0.12 + '@smithy/util-defaults-mode-node': 4.0.12 + '@smithy/util-endpoints': 3.0.4 '@smithy/util-middleware': 4.0.2 '@smithy/util-retry': 4.0.3 '@smithy/util-utf8': 4.0.0 @@ -8894,15 +9163,15 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/core@3.775.0': + '@aws-sdk/core@3.804.0': dependencies: - '@aws-sdk/types': 3.775.0 - '@smithy/core': 3.3.0 - '@smithy/node-config-provider': 4.0.2 + '@aws-sdk/types': 3.804.0 + '@smithy/core': 3.3.1 + '@smithy/node-config-provider': 4.1.1 '@smithy/property-provider': 4.0.2 '@smithy/protocol-http': 5.1.0 '@smithy/signature-v4': 5.1.0 - '@smithy/smithy-client': 4.2.1 + '@smithy/smithy-client': 4.2.4 '@smithy/types': 4.2.0 '@smithy/util-middleware': 4.0.2 fast-xml-parser: 4.4.1 @@ -8922,20 +9191,20 @@ snapshots: fast-xml-parser: 4.4.1 tslib: 2.8.1 - '@aws-sdk/credential-provider-cognito-identity@3.787.0': + '@aws-sdk/credential-provider-cognito-identity@3.804.0': dependencies: - '@aws-sdk/client-cognito-identity': 3.787.0 - '@aws-sdk/types': 3.775.0 + '@aws-sdk/client-cognito-identity': 3.804.0 + '@aws-sdk/types': 3.804.0 '@smithy/property-provider': 4.0.2 '@smithy/types': 4.2.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-env@3.775.0': + '@aws-sdk/credential-provider-env@3.804.0': dependencies: - '@aws-sdk/core': 3.775.0 - '@aws-sdk/types': 3.775.0 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/types': 3.804.0 '@smithy/property-provider': 4.0.2 '@smithy/types': 4.2.0 tslib: 2.8.1 @@ -8948,15 +9217,15 @@ snapshots: '@smithy/types': 4.2.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-http@3.775.0': + '@aws-sdk/credential-provider-http@3.804.0': dependencies: - '@aws-sdk/core': 3.775.0 - '@aws-sdk/types': 3.775.0 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/types': 3.804.0 '@smithy/fetch-http-handler': 5.0.2 '@smithy/node-http-handler': 4.0.4 '@smithy/property-provider': 4.0.2 '@smithy/protocol-http': 5.1.0 - '@smithy/smithy-client': 4.2.1 + '@smithy/smithy-client': 4.2.4 '@smithy/types': 4.2.0 '@smithy/util-stream': 4.2.0 tslib: 2.8.1 @@ -8974,17 +9243,17 @@ snapshots: '@smithy/util-stream': 4.2.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-ini@3.787.0': + '@aws-sdk/credential-provider-ini@3.804.0': dependencies: - '@aws-sdk/core': 3.775.0 - '@aws-sdk/credential-provider-env': 3.775.0 - '@aws-sdk/credential-provider-http': 3.775.0 - '@aws-sdk/credential-provider-process': 3.775.0 - '@aws-sdk/credential-provider-sso': 3.787.0 - '@aws-sdk/credential-provider-web-identity': 3.787.0 - '@aws-sdk/nested-clients': 3.787.0 - '@aws-sdk/types': 3.775.0 - '@smithy/credential-provider-imds': 4.0.2 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/credential-provider-env': 3.804.0 + '@aws-sdk/credential-provider-http': 3.804.0 + '@aws-sdk/credential-provider-process': 3.804.0 + '@aws-sdk/credential-provider-sso': 3.804.0 + '@aws-sdk/credential-provider-web-identity': 3.804.0 + '@aws-sdk/nested-clients': 3.804.0 + '@aws-sdk/types': 3.804.0 + '@smithy/credential-provider-imds': 4.0.4 '@smithy/property-provider': 4.0.2 '@smithy/shared-ini-file-loader': 4.0.2 '@smithy/types': 4.2.0 @@ -9010,16 +9279,16 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.787.0': + '@aws-sdk/credential-provider-node@3.804.0': dependencies: - '@aws-sdk/credential-provider-env': 3.775.0 - '@aws-sdk/credential-provider-http': 3.775.0 - '@aws-sdk/credential-provider-ini': 3.787.0 - '@aws-sdk/credential-provider-process': 3.775.0 - '@aws-sdk/credential-provider-sso': 3.787.0 - '@aws-sdk/credential-provider-web-identity': 3.787.0 - '@aws-sdk/types': 3.775.0 - '@smithy/credential-provider-imds': 4.0.2 + '@aws-sdk/credential-provider-env': 3.804.0 + '@aws-sdk/credential-provider-http': 3.804.0 + '@aws-sdk/credential-provider-ini': 3.804.0 + '@aws-sdk/credential-provider-process': 3.804.0 + '@aws-sdk/credential-provider-sso': 3.804.0 + '@aws-sdk/credential-provider-web-identity': 3.804.0 + '@aws-sdk/types': 3.804.0 + '@smithy/credential-provider-imds': 4.0.4 '@smithy/property-provider': 4.0.2 '@smithy/shared-ini-file-loader': 4.0.2 '@smithy/types': 4.2.0 @@ -9044,10 +9313,10 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-process@3.775.0': + '@aws-sdk/credential-provider-process@3.804.0': dependencies: - '@aws-sdk/core': 3.775.0 - '@aws-sdk/types': 3.775.0 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/types': 3.804.0 '@smithy/property-provider': 4.0.2 '@smithy/shared-ini-file-loader': 4.0.2 '@smithy/types': 4.2.0 @@ -9062,12 +9331,12 @@ snapshots: '@smithy/types': 4.2.0 tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.787.0': + '@aws-sdk/credential-provider-sso@3.804.0': dependencies: - '@aws-sdk/client-sso': 3.787.0 - '@aws-sdk/core': 3.775.0 - '@aws-sdk/token-providers': 3.787.0 - '@aws-sdk/types': 3.775.0 + '@aws-sdk/client-sso': 3.804.0 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/token-providers': 3.804.0 + '@aws-sdk/types': 3.804.0 '@smithy/property-provider': 4.0.2 '@smithy/shared-ini-file-loader': 4.0.2 '@smithy/types': 4.2.0 @@ -9088,11 +9357,11 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-web-identity@3.787.0': + '@aws-sdk/credential-provider-web-identity@3.804.0': dependencies: - '@aws-sdk/core': 3.775.0 - '@aws-sdk/nested-clients': 3.787.0 - '@aws-sdk/types': 3.775.0 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/nested-clients': 3.804.0 + '@aws-sdk/types': 3.804.0 '@smithy/property-provider': 4.0.2 '@smithy/types': 4.2.0 tslib: 2.8.1 @@ -9110,37 +9379,30 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-providers@3.787.0': - dependencies: - '@aws-sdk/client-cognito-identity': 3.787.0 - '@aws-sdk/core': 3.775.0 - '@aws-sdk/credential-provider-cognito-identity': 3.787.0 - '@aws-sdk/credential-provider-env': 3.775.0 - '@aws-sdk/credential-provider-http': 3.775.0 - '@aws-sdk/credential-provider-ini': 3.787.0 - '@aws-sdk/credential-provider-node': 3.787.0 - '@aws-sdk/credential-provider-process': 3.775.0 - '@aws-sdk/credential-provider-sso': 3.787.0 - '@aws-sdk/credential-provider-web-identity': 3.787.0 - '@aws-sdk/nested-clients': 3.787.0 - '@aws-sdk/types': 3.775.0 - '@smithy/config-resolver': 4.1.0 - '@smithy/core': 3.3.0 - '@smithy/credential-provider-imds': 4.0.2 - '@smithy/node-config-provider': 4.0.2 + '@aws-sdk/credential-providers@3.804.0': + dependencies: + '@aws-sdk/client-cognito-identity': 3.804.0 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/credential-provider-cognito-identity': 3.804.0 + '@aws-sdk/credential-provider-env': 3.804.0 + '@aws-sdk/credential-provider-http': 3.804.0 + '@aws-sdk/credential-provider-ini': 3.804.0 + '@aws-sdk/credential-provider-node': 3.804.0 + '@aws-sdk/credential-provider-process': 3.804.0 + '@aws-sdk/credential-provider-sso': 3.804.0 + '@aws-sdk/credential-provider-web-identity': 3.804.0 + '@aws-sdk/nested-clients': 3.804.0 + '@aws-sdk/types': 3.804.0 + '@smithy/config-resolver': 4.1.2 + '@smithy/core': 3.3.1 + '@smithy/credential-provider-imds': 4.0.4 + '@smithy/node-config-provider': 4.1.1 '@smithy/property-provider': 4.0.2 '@smithy/types': 4.2.0 tslib: 2.8.1 transitivePeerDependencies: - aws-crt - '@aws-sdk/middleware-host-header@3.775.0': - dependencies: - '@aws-sdk/types': 3.775.0 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 - tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.804.0': dependencies: '@aws-sdk/types': 3.804.0 @@ -9148,25 +9410,12 @@ snapshots: '@smithy/types': 4.2.0 tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.775.0': - dependencies: - '@aws-sdk/types': 3.775.0 - '@smithy/types': 4.2.0 - tslib: 2.8.1 - '@aws-sdk/middleware-logger@3.804.0': dependencies: '@aws-sdk/types': 3.804.0 '@smithy/types': 4.2.0 tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.775.0': - dependencies: - '@aws-sdk/types': 3.775.0 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 - tslib: 2.8.1 - '@aws-sdk/middleware-recursion-detection@3.804.0': dependencies: '@aws-sdk/types': 3.804.0 @@ -9184,12 +9433,12 @@ snapshots: '@smithy/types': 4.2.0 tslib: 2.8.1 - '@aws-sdk/middleware-user-agent@3.787.0': + '@aws-sdk/middleware-user-agent@3.804.0': dependencies: - '@aws-sdk/core': 3.775.0 - '@aws-sdk/types': 3.775.0 - '@aws-sdk/util-endpoints': 3.787.0 - '@smithy/core': 3.3.0 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/types': 3.804.0 + '@aws-sdk/util-endpoints': 3.804.0 + '@smithy/core': 3.3.1 '@smithy/protocol-http': 5.1.0 '@smithy/types': 4.2.0 tslib: 2.8.1 @@ -9204,42 +9453,42 @@ snapshots: '@smithy/types': 4.2.0 tslib: 2.8.1 - '@aws-sdk/nested-clients@3.787.0': + '@aws-sdk/nested-clients@3.804.0': dependencies: '@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-js': 5.2.0 - '@aws-sdk/core': 3.775.0 - '@aws-sdk/middleware-host-header': 3.775.0 - '@aws-sdk/middleware-logger': 3.775.0 - '@aws-sdk/middleware-recursion-detection': 3.775.0 - '@aws-sdk/middleware-user-agent': 3.787.0 - '@aws-sdk/region-config-resolver': 3.775.0 - '@aws-sdk/types': 3.775.0 - '@aws-sdk/util-endpoints': 3.787.0 - '@aws-sdk/util-user-agent-browser': 3.775.0 - '@aws-sdk/util-user-agent-node': 3.787.0 - '@smithy/config-resolver': 4.1.0 - '@smithy/core': 3.3.0 + '@aws-sdk/core': 3.804.0 + '@aws-sdk/middleware-host-header': 3.804.0 + '@aws-sdk/middleware-logger': 3.804.0 + '@aws-sdk/middleware-recursion-detection': 3.804.0 + '@aws-sdk/middleware-user-agent': 3.804.0 + '@aws-sdk/region-config-resolver': 3.804.0 + '@aws-sdk/types': 3.804.0 + '@aws-sdk/util-endpoints': 3.804.0 + '@aws-sdk/util-user-agent-browser': 3.804.0 + '@aws-sdk/util-user-agent-node': 3.804.0 + '@smithy/config-resolver': 4.1.2 + '@smithy/core': 3.3.1 '@smithy/fetch-http-handler': 5.0.2 '@smithy/hash-node': 4.0.2 '@smithy/invalid-dependency': 4.0.2 '@smithy/middleware-content-length': 4.0.2 - '@smithy/middleware-endpoint': 4.1.1 - '@smithy/middleware-retry': 4.1.2 + '@smithy/middleware-endpoint': 4.1.4 + '@smithy/middleware-retry': 4.1.5 '@smithy/middleware-serde': 4.0.3 '@smithy/middleware-stack': 4.0.2 - '@smithy/node-config-provider': 4.0.2 + '@smithy/node-config-provider': 4.1.1 '@smithy/node-http-handler': 4.0.4 '@smithy/protocol-http': 5.1.0 - '@smithy/smithy-client': 4.2.1 + '@smithy/smithy-client': 4.2.4 '@smithy/types': 4.2.0 '@smithy/url-parser': 4.0.2 '@smithy/util-base64': 4.0.0 '@smithy/util-body-length-browser': 4.0.0 '@smithy/util-body-length-node': 4.0.0 - '@smithy/util-defaults-mode-browser': 4.0.9 - '@smithy/util-defaults-mode-node': 4.0.9 - '@smithy/util-endpoints': 3.0.2 + '@smithy/util-defaults-mode-browser': 4.0.12 + '@smithy/util-defaults-mode-node': 4.0.12 + '@smithy/util-endpoints': 3.0.4 '@smithy/util-middleware': 4.0.2 '@smithy/util-retry': 4.0.3 '@smithy/util-utf8': 4.0.0 @@ -9295,10 +9544,10 @@ snapshots: '@smithy/protocol-http': 1.2.0 tslib: 2.8.1 - '@aws-sdk/region-config-resolver@3.775.0': + '@aws-sdk/region-config-resolver@3.804.0': dependencies: - '@aws-sdk/types': 3.775.0 - '@smithy/node-config-provider': 4.0.2 + '@aws-sdk/types': 3.804.0 + '@smithy/node-config-provider': 4.1.1 '@smithy/types': 4.2.0 '@smithy/util-config-provider': 4.0.0 '@smithy/util-middleware': 4.0.2 @@ -9318,10 +9567,10 @@ snapshots: '@smithy/signature-v4': 1.1.0 tslib: 2.8.1 - '@aws-sdk/token-providers@3.787.0': + '@aws-sdk/token-providers@3.804.0': dependencies: - '@aws-sdk/nested-clients': 3.787.0 - '@aws-sdk/types': 3.775.0 + '@aws-sdk/nested-clients': 3.804.0 + '@aws-sdk/types': 3.804.0 '@smithy/property-provider': 4.0.2 '@smithy/shared-ini-file-loader': 4.0.2 '@smithy/types': 4.2.0 @@ -9340,21 +9589,16 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/types@3.775.0': - dependencies: - '@smithy/types': 4.2.0 - tslib: 2.8.1 - '@aws-sdk/types@3.804.0': dependencies: '@smithy/types': 4.2.0 tslib: 2.8.1 - '@aws-sdk/util-endpoints@3.787.0': + '@aws-sdk/util-endpoints@3.804.0': dependencies: - '@aws-sdk/types': 3.775.0 + '@aws-sdk/types': 3.804.0 '@smithy/types': 4.2.0 - '@smithy/util-endpoints': 3.0.2 + '@smithy/util-endpoints': 3.0.4 tslib: 2.8.1 '@aws-sdk/util-endpoints@3.806.0': @@ -9375,13 +9619,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.775.0': - dependencies: - '@aws-sdk/types': 3.775.0 - '@smithy/types': 4.2.0 - bowser: 2.11.0 - tslib: 2.8.1 - '@aws-sdk/util-user-agent-browser@3.804.0': dependencies: '@aws-sdk/types': 3.804.0 @@ -9389,11 +9626,11 @@ snapshots: bowser: 2.11.0 tslib: 2.8.1 - '@aws-sdk/util-user-agent-node@3.787.0': + '@aws-sdk/util-user-agent-node@3.804.0': dependencies: - '@aws-sdk/middleware-user-agent': 3.787.0 - '@aws-sdk/types': 3.775.0 - '@smithy/node-config-provider': 4.0.2 + '@aws-sdk/middleware-user-agent': 3.804.0 + '@aws-sdk/types': 3.804.0 + '@smithy/node-config-provider': 4.1.1 '@smithy/types': 4.2.0 tslib: 2.8.1 @@ -9409,26 +9646,26 @@ snapshots: dependencies: tslib: 2.8.1 - '@babel/code-frame@7.26.2': + '@babel/code-frame@7.27.1': dependencies: - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.27.1 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.26.8': {} + '@babel/compat-data@7.27.2': {} - '@babel/core@7.26.10': + '@babel/core@7.27.1': dependencies: '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.27.0 - '@babel/helper-compilation-targets': 7.27.0 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10) - '@babel/helpers': 7.27.0 - '@babel/parser': 7.27.0 - '@babel/template': 7.27.0 - '@babel/traverse': 7.27.0 - '@babel/types': 7.27.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.1 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.1(@babel/core@7.27.1) + '@babel/helpers': 7.27.1 + '@babel/parser': 7.27.2 + '@babel/template': 7.27.2 + '@babel/traverse': 7.27.1 + '@babel/types': 7.27.1 convert-source-map: 2.0.0 debug: 4.4.0 gensync: 1.0.0-beta.2 @@ -9437,79 +9674,79 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.27.0': + '@babel/generator@7.27.1': dependencies: - '@babel/parser': 7.27.0 - '@babel/types': 7.27.0 + '@babel/parser': 7.27.2 + '@babel/types': 7.27.1 '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.27.0': + '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/compat-data': 7.26.8 - '@babel/helper-validator-option': 7.25.9 - browserslist: 4.24.4 + '@babel/compat-data': 7.27.2 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.24.5 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-module-imports@7.25.9': + '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/traverse': 7.27.0 - '@babel/types': 7.27.0 + '@babel/traverse': 7.27.1 + '@babel/types': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)': + '@babel/helper-module-transforms@7.27.1(@babel/core@7.27.1)': dependencies: - '@babel/core': 7.26.10 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.27.0 + '@babel/core': 7.27.1 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/helper-string-parser@7.25.9': {} + '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.25.9': {} + '@babel/helper-validator-identifier@7.27.1': {} - '@babel/helper-validator-option@7.25.9': {} + '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.27.0': + '@babel/helpers@7.27.1': dependencies: - '@babel/template': 7.27.0 - '@babel/types': 7.27.0 + '@babel/template': 7.27.2 + '@babel/types': 7.27.1 - '@babel/parser@7.27.0': + '@babel/parser@7.27.2': dependencies: - '@babel/types': 7.27.0 + '@babel/types': 7.27.1 '@babel/runtime@7.26.10': dependencies: regenerator-runtime: 0.14.1 - '@babel/template@7.27.0': + '@babel/template@7.27.2': dependencies: - '@babel/code-frame': 7.26.2 - '@babel/parser': 7.27.0 - '@babel/types': 7.27.0 + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.27.2 + '@babel/types': 7.27.1 - '@babel/traverse@7.27.0': + '@babel/traverse@7.27.1': dependencies: - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.27.0 - '@babel/parser': 7.27.0 - '@babel/template': 7.27.0 - '@babel/types': 7.27.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.1 + '@babel/parser': 7.27.2 + '@babel/template': 7.27.2 + '@babel/types': 7.27.1 debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: - supports-color - '@babel/types@7.27.0': + '@babel/types@7.27.1': dependencies: - '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 '@balena/dockerignore@1.0.2': {} @@ -9570,78 +9807,153 @@ snapshots: '@esbuild/aix-ppc64@0.25.2': optional: true + '@esbuild/aix-ppc64@0.25.4': + optional: true + '@esbuild/android-arm64@0.25.2': optional: true + '@esbuild/android-arm64@0.25.4': + optional: true + '@esbuild/android-arm@0.25.2': optional: true + '@esbuild/android-arm@0.25.4': + optional: true + '@esbuild/android-x64@0.25.2': optional: true + '@esbuild/android-x64@0.25.4': + optional: true + '@esbuild/darwin-arm64@0.25.2': optional: true + '@esbuild/darwin-arm64@0.25.4': + optional: true + '@esbuild/darwin-x64@0.25.2': optional: true + '@esbuild/darwin-x64@0.25.4': + optional: true + '@esbuild/freebsd-arm64@0.25.2': optional: true + '@esbuild/freebsd-arm64@0.25.4': + optional: true + '@esbuild/freebsd-x64@0.25.2': optional: true + '@esbuild/freebsd-x64@0.25.4': + optional: true + '@esbuild/linux-arm64@0.25.2': optional: true + '@esbuild/linux-arm64@0.25.4': + optional: true + '@esbuild/linux-arm@0.25.2': optional: true + '@esbuild/linux-arm@0.25.4': + optional: true + '@esbuild/linux-ia32@0.25.2': optional: true + '@esbuild/linux-ia32@0.25.4': + optional: true + '@esbuild/linux-loong64@0.25.2': optional: true + '@esbuild/linux-loong64@0.25.4': + optional: true + '@esbuild/linux-mips64el@0.25.2': optional: true + '@esbuild/linux-mips64el@0.25.4': + optional: true + '@esbuild/linux-ppc64@0.25.2': optional: true + '@esbuild/linux-ppc64@0.25.4': + optional: true + '@esbuild/linux-riscv64@0.25.2': optional: true + '@esbuild/linux-riscv64@0.25.4': + optional: true + '@esbuild/linux-s390x@0.25.2': optional: true + '@esbuild/linux-s390x@0.25.4': + optional: true + '@esbuild/linux-x64@0.25.2': optional: true + '@esbuild/linux-x64@0.25.4': + optional: true + '@esbuild/netbsd-arm64@0.25.2': optional: true + '@esbuild/netbsd-arm64@0.25.4': + optional: true + '@esbuild/netbsd-x64@0.25.2': optional: true + '@esbuild/netbsd-x64@0.25.4': + optional: true + '@esbuild/openbsd-arm64@0.25.2': optional: true + '@esbuild/openbsd-arm64@0.25.4': + optional: true + '@esbuild/openbsd-x64@0.25.2': optional: true + '@esbuild/openbsd-x64@0.25.4': + optional: true + '@esbuild/sunos-x64@0.25.2': optional: true + '@esbuild/sunos-x64@0.25.4': + optional: true + '@esbuild/win32-arm64@0.25.2': optional: true + '@esbuild/win32-arm64@0.25.4': + optional: true + '@esbuild/win32-ia32@0.25.2': optional: true + '@esbuild/win32-ia32@0.25.4': + optional: true + '@esbuild/win32-x64@0.25.2': optional: true + '@esbuild/win32-x64@0.25.4': + optional: true + '@eslint-community/eslint-utils@4.4.1(eslint@9.21.0(jiti@2.4.2))': dependencies: eslint: 9.21.0(jiti@2.4.2) @@ -10039,7 +10351,7 @@ snapshots: dependencies: '@lukeed/csprng': 1.1.0 - '@mastra/core@0.9.3(react@19.1.0)(zod@3.24.4)': + '@mastra/core@0.9.3(openapi-types@12.1.3)(react@19.1.0)(zod@3.24.4)': dependencies: '@libsql/client': 0.14.0 '@opentelemetry/api': 1.9.0 @@ -10056,12 +10368,12 @@ snapshots: '@opentelemetry/sdk-trace-node': 1.30.1(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.32.0 ai: 4.3.15(react@19.1.0)(zod@3.24.4) - cohere-ai: 7.16.0 + cohere-ai: 7.17.1 date-fns: 3.6.0 dotenv: 16.5.0 fastembed: 1.14.4 - hono: 4.7.6 - hono-openapi: 0.4.6(hono@4.7.6)(zod@3.24.4) + hono: 4.7.8 + hono-openapi: 0.4.8(hono@4.7.8)(openapi-types@12.1.3)(zod@3.24.4) json-schema: 0.4.0 json-schema-to-zod: 2.6.1 pino: 9.6.0 @@ -10091,30 +10403,30 @@ snapshots: - valibot - zod-openapi - '@mastra/deployer@0.3.3(react@19.1.0)(typescript@5.8.3)': + '@mastra/deployer@0.3.3(openapi-types@12.1.3)(react@19.1.0)(typescript@5.8.3)': dependencies: - '@babel/core': 7.26.10 - '@babel/helper-module-imports': 7.25.9 - '@mastra/core': 0.9.3(react@19.1.0)(zod@3.24.4) - '@mastra/server': 2.0.3(@mastra/core@0.9.3(react@19.1.0)(zod@3.24.4)) + '@babel/core': 7.27.1 + '@babel/helper-module-imports': 7.27.1 + '@mastra/core': 0.9.3(openapi-types@12.1.3)(react@19.1.0)(zod@3.24.4) + '@mastra/server': 2.0.3(@mastra/core@0.9.3(openapi-types@12.1.3)(react@19.1.0)(zod@3.24.4)) '@neon-rs/load': 0.1.82 - '@rollup/plugin-alias': 5.1.1(rollup@4.39.0) - '@rollup/plugin-commonjs': 28.0.3(rollup@4.39.0) - '@rollup/plugin-json': 6.1.0(rollup@4.39.0) - '@rollup/plugin-node-resolve': 16.0.1(rollup@4.39.0) - '@rollup/plugin-virtual': 3.0.2(rollup@4.39.0) + '@rollup/plugin-alias': 5.1.1(rollup@4.40.2) + '@rollup/plugin-commonjs': 28.0.3(rollup@4.40.2) + '@rollup/plugin-json': 6.1.0(rollup@4.40.2) + '@rollup/plugin-node-resolve': 16.0.1(rollup@4.40.2) + '@rollup/plugin-virtual': 3.0.2(rollup@4.40.2) '@sindresorhus/slugify': 2.2.1 builtins: 5.1.0 - detect-libc: 2.0.3 + detect-libc: 2.0.4 dotenv: 16.5.0 - esbuild: 0.25.2 + esbuild: 0.25.4 find-workspaces: 0.3.1 fs-extra: 11.3.0 - hono: 4.7.6 + hono: 4.7.8 resolve-from: 5.0.0 - rollup: 4.39.0 - rollup-plugin-esbuild: 6.2.1(esbuild@0.25.2)(rollup@4.39.0) - rollup-plugin-node-externals: 8.0.0(rollup@4.39.0) + rollup: 4.40.2 + rollup-plugin-esbuild: 6.2.1(esbuild@0.25.4)(rollup@4.40.2) + rollup-plugin-node-externals: 8.0.0(rollup@4.40.2) typescript-paths: 1.5.1(typescript@5.8.3) zod: 3.24.4 transitivePeerDependencies: @@ -10138,9 +10450,9 @@ snapshots: - valibot - zod-openapi - '@mastra/evals@0.1.22(ai@4.3.15(react@19.1.0)(zod@3.24.4))(react@19.1.0)': + '@mastra/evals@0.1.22(ai@4.3.15(react@19.1.0)(zod@3.24.4))(openapi-types@12.1.3)(react@19.1.0)': dependencies: - '@mastra/core': 0.9.3(react@19.1.0)(zod@3.24.4) + '@mastra/core': 0.9.3(openapi-types@12.1.3)(react@19.1.0)(zod@3.24.4) ai: 4.3.15(react@19.1.0)(zod@3.24.4) compromise: 14.14.4 difflib: 0.2.4 @@ -10169,9 +10481,9 @@ snapshots: - valibot - zod-openapi - '@mastra/server@2.0.3(@mastra/core@0.9.3(react@19.1.0)(zod@3.24.4))': + '@mastra/server@2.0.3(@mastra/core@0.9.3(openapi-types@12.1.3)(react@19.1.0)(zod@3.24.4))': dependencies: - '@mastra/core': 0.9.3(react@19.1.0)(zod@3.24.4) + '@mastra/core': 0.9.3(openapi-types@12.1.3)(react@19.1.0)(zod@3.24.4) '@modelcontextprotocol/sdk@1.11.0': dependencies: @@ -11603,7 +11915,7 @@ snapshots: '@panva/hkdf@1.2.1': {} - '@petamoriken/float16@3.9.1': + '@petamoriken/float16@3.9.2': optional: true '@playwright/test@1.50.1': @@ -12420,13 +12732,13 @@ snapshots: - '@types/react' - immer - '@rollup/plugin-alias@5.1.1(rollup@4.39.0)': + '@rollup/plugin-alias@5.1.1(rollup@4.40.2)': optionalDependencies: - rollup: 4.39.0 + rollup: 4.40.2 - '@rollup/plugin-commonjs@28.0.3(rollup@4.39.0)': + '@rollup/plugin-commonjs@28.0.3(rollup@4.40.2)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/pluginutils': 5.1.4(rollup@4.40.2) commondir: 1.0.1 estree-walker: 2.0.2 fdir: 6.4.4(picomatch@4.0.2) @@ -12434,96 +12746,156 @@ snapshots: magic-string: 0.30.17 picomatch: 4.0.2 optionalDependencies: - rollup: 4.39.0 + rollup: 4.40.2 - '@rollup/plugin-json@6.1.0(rollup@4.39.0)': + '@rollup/plugin-json@6.1.0(rollup@4.40.2)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/pluginutils': 5.1.4(rollup@4.40.2) optionalDependencies: - rollup: 4.39.0 + rollup: 4.40.2 - '@rollup/plugin-node-resolve@16.0.1(rollup@4.39.0)': + '@rollup/plugin-node-resolve@16.0.1(rollup@4.40.2)': dependencies: - '@rollup/pluginutils': 5.1.4(rollup@4.39.0) + '@rollup/pluginutils': 5.1.4(rollup@4.40.2) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 - resolve: 1.22.8 + resolve: 1.22.10 optionalDependencies: - rollup: 4.39.0 + rollup: 4.40.2 - '@rollup/plugin-virtual@3.0.2(rollup@4.39.0)': + '@rollup/plugin-virtual@3.0.2(rollup@4.40.2)': optionalDependencies: - rollup: 4.39.0 + rollup: 4.40.2 - '@rollup/pluginutils@5.1.4(rollup@4.39.0)': + '@rollup/pluginutils@5.1.4(rollup@4.40.2)': dependencies: '@types/estree': 1.0.7 estree-walker: 2.0.2 picomatch: 4.0.2 optionalDependencies: - rollup: 4.39.0 + rollup: 4.40.2 '@rollup/rollup-android-arm-eabi@4.39.0': optional: true + '@rollup/rollup-android-arm-eabi@4.40.2': + optional: true + '@rollup/rollup-android-arm64@4.39.0': optional: true + '@rollup/rollup-android-arm64@4.40.2': + optional: true + '@rollup/rollup-darwin-arm64@4.39.0': optional: true + '@rollup/rollup-darwin-arm64@4.40.2': + optional: true + '@rollup/rollup-darwin-x64@4.39.0': optional: true + '@rollup/rollup-darwin-x64@4.40.2': + optional: true + '@rollup/rollup-freebsd-arm64@4.39.0': optional: true + '@rollup/rollup-freebsd-arm64@4.40.2': + optional: true + '@rollup/rollup-freebsd-x64@4.39.0': optional: true + '@rollup/rollup-freebsd-x64@4.40.2': + optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.39.0': optional: true + '@rollup/rollup-linux-arm-gnueabihf@4.40.2': + optional: true + '@rollup/rollup-linux-arm-musleabihf@4.39.0': optional: true + '@rollup/rollup-linux-arm-musleabihf@4.40.2': + optional: true + '@rollup/rollup-linux-arm64-gnu@4.39.0': optional: true + '@rollup/rollup-linux-arm64-gnu@4.40.2': + optional: true + '@rollup/rollup-linux-arm64-musl@4.39.0': optional: true + '@rollup/rollup-linux-arm64-musl@4.40.2': + optional: true + '@rollup/rollup-linux-loongarch64-gnu@4.39.0': optional: true + '@rollup/rollup-linux-loongarch64-gnu@4.40.2': + optional: true + '@rollup/rollup-linux-powerpc64le-gnu@4.39.0': optional: true + '@rollup/rollup-linux-powerpc64le-gnu@4.40.2': + optional: true + '@rollup/rollup-linux-riscv64-gnu@4.39.0': optional: true + '@rollup/rollup-linux-riscv64-gnu@4.40.2': + optional: true + '@rollup/rollup-linux-riscv64-musl@4.39.0': optional: true + '@rollup/rollup-linux-riscv64-musl@4.40.2': + optional: true + '@rollup/rollup-linux-s390x-gnu@4.39.0': optional: true + '@rollup/rollup-linux-s390x-gnu@4.40.2': + optional: true + '@rollup/rollup-linux-x64-gnu@4.39.0': optional: true + '@rollup/rollup-linux-x64-gnu@4.40.2': + optional: true + '@rollup/rollup-linux-x64-musl@4.39.0': optional: true + '@rollup/rollup-linux-x64-musl@4.40.2': + optional: true + '@rollup/rollup-win32-arm64-msvc@4.39.0': optional: true + '@rollup/rollup-win32-arm64-msvc@4.40.2': + optional: true + '@rollup/rollup-win32-ia32-msvc@4.39.0': optional: true + '@rollup/rollup-win32-ia32-msvc@4.40.2': + optional: true + '@rollup/rollup-win32-x64-msvc@4.39.0': optional: true + '@rollup/rollup-win32-x64-msvc@4.40.2': + optional: true + '@rtsao/scc@1.1.0': {} '@sec-ant/readable-stream@0.4.1': {} @@ -12579,14 +12951,6 @@ snapshots: '@smithy/types': 4.2.0 tslib: 2.8.1 - '@smithy/config-resolver@4.1.0': - dependencies: - '@smithy/node-config-provider': 4.0.2 - '@smithy/types': 4.2.0 - '@smithy/util-config-provider': 4.0.0 - '@smithy/util-middleware': 4.0.2 - tslib: 2.8.1 - '@smithy/config-resolver@4.1.2': dependencies: '@smithy/node-config-provider': 4.1.1 @@ -12595,17 +12959,6 @@ snapshots: '@smithy/util-middleware': 4.0.2 tslib: 2.8.1 - '@smithy/core@3.3.0': - dependencies: - '@smithy/middleware-serde': 4.0.3 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 - '@smithy/util-body-length-browser': 4.0.0 - '@smithy/util-middleware': 4.0.2 - '@smithy/util-stream': 4.2.0 - '@smithy/util-utf8': 4.0.0 - tslib: 2.8.1 - '@smithy/core@3.3.1': dependencies: '@smithy/middleware-serde': 4.0.3 @@ -12691,17 +13044,6 @@ snapshots: '@smithy/types': 4.2.0 tslib: 2.8.1 - '@smithy/middleware-endpoint@4.1.1': - dependencies: - '@smithy/core': 3.3.0 - '@smithy/middleware-serde': 4.0.3 - '@smithy/node-config-provider': 4.0.2 - '@smithy/shared-ini-file-loader': 4.0.2 - '@smithy/types': 4.2.0 - '@smithy/url-parser': 4.0.2 - '@smithy/util-middleware': 4.0.2 - tslib: 2.8.1 - '@smithy/middleware-endpoint@4.1.4': dependencies: '@smithy/core': 3.3.1 @@ -12713,18 +13055,6 @@ snapshots: '@smithy/util-middleware': 4.0.2 tslib: 2.8.1 - '@smithy/middleware-retry@4.1.2': - dependencies: - '@smithy/node-config-provider': 4.0.2 - '@smithy/protocol-http': 5.1.0 - '@smithy/service-error-classification': 4.0.3 - '@smithy/smithy-client': 4.2.1 - '@smithy/types': 4.2.0 - '@smithy/util-middleware': 4.0.2 - '@smithy/util-retry': 4.0.3 - tslib: 2.8.1 - uuid: 9.0.1 - '@smithy/middleware-retry@4.1.5': dependencies: '@smithy/node-config-provider': 4.1.1 @@ -12747,13 +13077,6 @@ snapshots: '@smithy/types': 4.2.0 tslib: 2.8.1 - '@smithy/node-config-provider@4.0.2': - dependencies: - '@smithy/property-provider': 4.0.2 - '@smithy/shared-ini-file-loader': 4.0.2 - '@smithy/types': 4.2.0 - tslib: 2.8.1 - '@smithy/node-config-provider@4.1.1': dependencies: '@smithy/property-provider': 4.0.2 @@ -12826,16 +13149,6 @@ snapshots: '@smithy/util-utf8': 4.0.0 tslib: 2.8.1 - '@smithy/smithy-client@4.2.1': - dependencies: - '@smithy/core': 3.3.0 - '@smithy/middleware-endpoint': 4.1.1 - '@smithy/middleware-stack': 4.0.2 - '@smithy/protocol-http': 5.1.0 - '@smithy/types': 4.2.0 - '@smithy/util-stream': 4.2.0 - tslib: 2.8.1 - '@smithy/smithy-client@4.2.4': dependencies: '@smithy/core': 3.3.1 @@ -12901,14 +13214,6 @@ snapshots: bowser: 2.11.0 tslib: 2.8.1 - '@smithy/util-defaults-mode-browser@4.0.9': - dependencies: - '@smithy/property-provider': 4.0.2 - '@smithy/smithy-client': 4.2.1 - '@smithy/types': 4.2.0 - bowser: 2.11.0 - tslib: 2.8.1 - '@smithy/util-defaults-mode-node@4.0.12': dependencies: '@smithy/config-resolver': 4.1.2 @@ -12919,22 +13224,6 @@ snapshots: '@smithy/types': 4.2.0 tslib: 2.8.1 - '@smithy/util-defaults-mode-node@4.0.9': - dependencies: - '@smithy/config-resolver': 4.1.0 - '@smithy/credential-provider-imds': 4.0.2 - '@smithy/node-config-provider': 4.0.2 - '@smithy/property-provider': 4.0.2 - '@smithy/smithy-client': 4.2.1 - '@smithy/types': 4.2.0 - tslib: 2.8.1 - - '@smithy/util-endpoints@3.0.2': - dependencies: - '@smithy/node-config-provider': 4.0.2 - '@smithy/types': 4.2.0 - tslib: 2.8.1 - '@smithy/util-endpoints@3.0.4': dependencies: '@smithy/node-config-provider': 4.1.1 @@ -13306,6 +13595,11 @@ snapshots: dependencies: '@types/node': 22.15.17 + '@types/ndjson@2.0.4': + dependencies: + '@types/node': 22.15.17 + '@types/through': 0.0.33 + '@types/node@18.19.80': dependencies: undici-types: 5.26.5 @@ -13365,6 +13659,10 @@ snapshots: dependencies: '@types/node': 22.15.17 + '@types/through@0.0.33': + dependencies: + '@types/node': 22.15.17 + '@types/tough-cookie@4.0.5': {} '@types/unist@2.0.11': {} @@ -13681,7 +13979,7 @@ snapshots: axe-core@4.10.2: {} - axios@1.8.4: + axios@1.9.0: dependencies: follow-redirects: 1.15.9 form-data: 4.0.2 @@ -13749,6 +14047,13 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.2(browserslist@4.24.4) + browserslist@4.24.5: + dependencies: + caniuse-lite: 1.0.30001717 + electron-to-chromium: 1.5.150 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.24.5) + buffer-equal-constant-time@1.0.1: {} buffer-from@1.1.2: {} @@ -13811,6 +14116,8 @@ snapshots: caniuse-lite@1.0.30001703: {} + caniuse-lite@1.0.30001717: {} + canvas-confetti@1.9.3: {} ccount@2.0.1: {} @@ -13908,6 +14215,15 @@ snapshots: clsx@2.1.1: {} + cmd-ts@0.13.0: + dependencies: + chalk: 4.1.2 + debug: 4.4.0 + didyoumean: 1.2.2 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - supports-color + cmdk@1.1.1(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.3)(react@19.1.0) @@ -13920,10 +14236,10 @@ snapshots: - '@types/react' - '@types/react-dom' - cohere-ai@7.16.0: + cohere-ai@7.17.1: dependencies: - '@aws-sdk/client-sagemaker': 3.787.0 - '@aws-sdk/credential-providers': 3.787.0 + '@aws-sdk/client-sagemaker': 3.805.0 + '@aws-sdk/credential-providers': 3.804.0 '@aws-sdk/protocol-http': 3.374.0 '@aws-sdk/signature-v4': 3.374.0 convict: 6.2.4 @@ -14196,6 +14512,8 @@ snapshots: dependencies: dequal: 2.0.3 + didyoumean@1.2.2: {} + diff-match-patch@1.0.5: {} difflib@0.2.4: @@ -14289,6 +14607,8 @@ snapshots: efrt@2.7.0: {} + electron-to-chromium@1.5.150: {} + electron-to-chromium@1.5.87: {} emoji-regex-xs@1.0.0: {} @@ -14396,8 +14716,6 @@ snapshots: iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 - es-module-lexer@1.6.0: {} - es-module-lexer@1.7.0: {} es-object-atoms@1.0.0: @@ -14462,6 +14780,34 @@ snapshots: '@esbuild/win32-ia32': 0.25.2 '@esbuild/win32-x64': 0.25.2 + esbuild@0.25.4: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.4 + '@esbuild/android-arm': 0.25.4 + '@esbuild/android-arm64': 0.25.4 + '@esbuild/android-x64': 0.25.4 + '@esbuild/darwin-arm64': 0.25.4 + '@esbuild/darwin-x64': 0.25.4 + '@esbuild/freebsd-arm64': 0.25.4 + '@esbuild/freebsd-x64': 0.25.4 + '@esbuild/linux-arm': 0.25.4 + '@esbuild/linux-arm64': 0.25.4 + '@esbuild/linux-ia32': 0.25.4 + '@esbuild/linux-loong64': 0.25.4 + '@esbuild/linux-mips64el': 0.25.4 + '@esbuild/linux-ppc64': 0.25.4 + '@esbuild/linux-riscv64': 0.25.4 + '@esbuild/linux-s390x': 0.25.4 + '@esbuild/linux-x64': 0.25.4 + '@esbuild/netbsd-arm64': 0.25.4 + '@esbuild/netbsd-x64': 0.25.4 + '@esbuild/openbsd-arm64': 0.25.4 + '@esbuild/openbsd-x64': 0.25.4 + '@esbuild/sunos-x64': 0.25.4 + '@esbuild/win32-arm64': 0.25.4 + '@esbuild/win32-ia32': 0.25.4 + '@esbuild/win32-x64': 0.25.4 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -14804,6 +15150,14 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -14882,7 +15236,7 @@ snapshots: find-workspaces@0.3.1: dependencies: - fast-glob: 3.3.2 + fast-glob: 3.3.3 pkg-types: 1.3.1 yaml: 2.7.1 @@ -15008,13 +15362,13 @@ snapshots: transitivePeerDependencies: - supports-color - geist@1.4.2(next@15.3.2(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4)): + geist@1.4.2(next@15.3.2(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4)): dependencies: - next: 15.3.2(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4) + next: 15.3.2(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4) gel@2.0.0: dependencies: - '@petamoriken/float16': 3.9.1 + '@petamoriken/float16': 3.9.2 debug: 4.4.0 env-paths: 3.0.0 semver: 7.7.1 @@ -15281,14 +15635,15 @@ snapshots: highlightjs-vue@1.0.0: {} - hono-openapi@0.4.6(hono@4.7.6)(zod@3.24.4): + hono-openapi@0.4.8(hono@4.7.8)(openapi-types@12.1.3)(zod@3.24.4): dependencies: json-schema-walker: 2.0.0 + openapi-types: 12.1.3 optionalDependencies: - hono: 4.7.6 + hono: 4.7.8 zod: 3.24.4 - hono@4.7.6: {} + hono@4.7.8: {} html-entities@2.6.0: {} @@ -15429,6 +15784,10 @@ snapshots: dependencies: hasown: 2.0.2 + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + is-data-view@1.0.2: dependencies: call-bound: 1.0.3 @@ -15836,12 +16195,12 @@ snapshots: markdown-table@3.0.4: {} - mastra@0.6.2(@opentelemetry/api@1.9.0)(react@19.1.0)(typescript@5.8.3): + mastra@0.6.2(@opentelemetry/api@1.9.0)(openapi-types@12.1.3)(react@19.1.0)(typescript@5.8.3): dependencies: '@clack/prompts': 0.8.2 '@lukeed/uuid': 2.0.1 - '@mastra/core': 0.9.3(react@19.1.0)(zod@3.24.4) - '@mastra/deployer': 0.3.3(react@19.1.0)(typescript@5.8.3) + '@mastra/core': 0.9.3(openapi-types@12.1.3)(react@19.1.0)(zod@3.24.4) + '@mastra/deployer': 0.3.3(openapi-types@12.1.3)(react@19.1.0)(typescript@5.8.3) '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) '@webcontainer/env': 1.1.1 commander: 12.1.0 @@ -16329,12 +16688,20 @@ snapshots: natural-compare@1.4.0: {} + ndjson@2.0.0: + dependencies: + json-stringify-safe: 5.0.1 + minimist: 1.2.8 + readable-stream: 3.6.2 + split2: 3.2.2 + through2: 4.0.2 + negotiator@1.0.0: {} - next-auth@5.0.0-beta.25(next@15.3.2(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4))(react@19.1.0): + next-auth@5.0.0-beta.25(next@15.3.2(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4))(react@19.1.0): dependencies: '@auth/core': 0.37.2 - next: 15.3.2(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4) + next: 15.3.2(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4) react: 19.1.0 next-themes@0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0): @@ -16342,17 +16709,17 @@ snapshots: react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - next@15.3.2(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4): + next@15.3.2(@babel/core@7.27.1)(@opentelemetry/api@1.9.0)(@playwright/test@1.50.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4): dependencies: '@next/env': 15.3.2 '@swc/counter': 0.1.3 '@swc/helpers': 0.5.15 busboy: 1.6.0 - caniuse-lite: 1.0.30001703 + caniuse-lite: 1.0.30001717 postcss: 8.4.31 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) - styled-jsx: 5.1.6(@babel/core@7.26.10)(react@19.1.0) + styled-jsx: 5.1.6(@babel/core@7.27.1)(react@19.1.0) optionalDependencies: '@next/swc-darwin-arm64': 15.3.2 '@next/swc-darwin-x64': 15.3.2 @@ -16491,6 +16858,8 @@ snapshots: onnxruntime-common: 1.21.0 tar: 7.4.3 + openapi-types@12.1.3: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -16727,7 +17096,7 @@ snapshots: posthog-node@4.16.0: dependencies: - axios: 1.8.4 + axios: 1.9.0 transitivePeerDependencies: - debug @@ -17196,6 +17565,12 @@ snapshots: resolve-pkg-maps@1.0.0: {} + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + resolve@1.22.8: dependencies: is-core-module: 2.15.1 @@ -17245,20 +17620,20 @@ snapshots: semver-compare: 1.0.0 sprintf-js: 1.1.3 - rollup-plugin-esbuild@6.2.1(esbuild@0.25.2)(rollup@4.39.0): + rollup-plugin-esbuild@6.2.1(esbuild@0.25.4)(rollup@4.40.2): dependencies: debug: 4.4.0 - es-module-lexer: 1.6.0 - esbuild: 0.25.2 + es-module-lexer: 1.7.0 + esbuild: 0.25.4 get-tsconfig: 4.10.0 - rollup: 4.39.0 + rollup: 4.40.2 unplugin-utils: 0.2.4 transitivePeerDependencies: - supports-color - rollup-plugin-node-externals@8.0.0(rollup@4.39.0): + rollup-plugin-node-externals@8.0.0(rollup@4.40.2): dependencies: - rollup: 4.39.0 + rollup: 4.40.2 rollup@4.39.0: dependencies: @@ -17286,6 +17661,32 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.39.0 fsevents: 2.3.3 + rollup@4.40.2: + dependencies: + '@types/estree': 1.0.7 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.40.2 + '@rollup/rollup-android-arm64': 4.40.2 + '@rollup/rollup-darwin-arm64': 4.40.2 + '@rollup/rollup-darwin-x64': 4.40.2 + '@rollup/rollup-freebsd-arm64': 4.40.2 + '@rollup/rollup-freebsd-x64': 4.40.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.40.2 + '@rollup/rollup-linux-arm-musleabihf': 4.40.2 + '@rollup/rollup-linux-arm64-gnu': 4.40.2 + '@rollup/rollup-linux-arm64-musl': 4.40.2 + '@rollup/rollup-linux-loongarch64-gnu': 4.40.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.40.2 + '@rollup/rollup-linux-riscv64-gnu': 4.40.2 + '@rollup/rollup-linux-riscv64-musl': 4.40.2 + '@rollup/rollup-linux-s390x-gnu': 4.40.2 + '@rollup/rollup-linux-x64-gnu': 4.40.2 + '@rollup/rollup-linux-x64-musl': 4.40.2 + '@rollup/rollup-win32-arm64-msvc': 4.40.2 + '@rollup/rollup-win32-ia32-msvc': 4.40.2 + '@rollup/rollup-win32-x64-msvc': 4.40.2 + fsevents: 2.3.3 + rope-sequence@1.3.4: {} router@2.2.0: @@ -17410,7 +17811,7 @@ snapshots: sharp@0.34.1: dependencies: color: 4.2.3 - detect-libc: 2.0.3 + detect-libc: 2.0.4 semver: 7.7.1 optionalDependencies: '@img/sharp-darwin-arm64': 0.34.1 @@ -17534,6 +17935,10 @@ snapshots: split-ca@1.0.1: {} + split2@3.2.2: + dependencies: + readable-stream: 3.6.2 + split2@4.2.0: {} sprintf-js@1.1.3: {} @@ -17671,12 +18076,12 @@ snapshots: dependencies: inline-style-parser: 0.2.4 - styled-jsx@5.1.6(@babel/core@7.26.10)(react@19.1.0): + styled-jsx@5.1.6(@babel/core@7.27.1)(react@19.1.0): dependencies: client-only: 0.0.1 react: 19.1.0 optionalDependencies: - '@babel/core': 7.26.10 + '@babel/core': 7.27.1 stylis@4.3.5: {} @@ -17782,6 +18187,10 @@ snapshots: throttleit@2.1.0: {} + through2@4.0.2: + dependencies: + readable-stream: 3.6.2 + tiny-invariant@1.3.3: {} tinybench@2.9.0: {} @@ -17990,6 +18399,12 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + update-browserslist-db@1.1.3(browserslist@4.24.5): + dependencies: + browserslist: 4.24.5 + escalade: 3.2.0 + picocolors: 1.1.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1