ruvector/studio/components/ui/AIAssistantPanel/Message.utils.ts
rUv 814f595995 feat(studio): Add complete RuVector Studio application
Major additions:
- Complete Next.js studio application with 1600+ components
- Docker support (Dockerfile.combined, docker-compose.yml)
- GCP deployment documentation and benchmarks
- SQL benchmark scripts for performance testing
- Sentry integration for monitoring
- Comprehensive test suite and mocks

Studio features:
- Dashboard and admin interfaces
- Data visualization components
- Authentication and user management
- API integration with RuVector backend
- Static data and public assets

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:04:48 +00:00

113 lines
3.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { type SafeParseReturnType, z } from 'zod'
// [Joshen] From https://github.com/remarkjs/react-markdown/blob/fda7fa560bec901a6103e195f9b1979dab543b17/lib/index.js#L425
export function defaultUrlTransform(value: string) {
const safeProtocol = /^(https?|ircs?|mailto|xmpp)$/i
const colon = value.indexOf(':')
const questionMark = value.indexOf('?')
const numberSign = value.indexOf('#')
const slash = value.indexOf('/')
if (
// If there is no protocol, its relative.
colon === -1 ||
// If the first colon is after a `?`, `#`, or `/`, its not a protocol.
(slash !== -1 && colon > slash) ||
(questionMark !== -1 && colon > questionMark) ||
(numberSign !== -1 && colon > numberSign) ||
// It is a protocol, it should be allowed.
safeProtocol.test(value.slice(0, colon))
) {
return value
}
return ''
}
const chartArgsSchema = z
.object({
view: z.enum(['table', 'chart']).optional(),
xKey: z.string().optional(),
xAxis: z.string().optional(),
yKey: z.string().optional(),
yAxis: z.string().optional(),
})
.passthrough()
const chartArgsFieldSchema = z.preprocess((value) => {
if (!value || typeof value !== 'object') return undefined
if (Array.isArray(value)) return value[0]
return value
}, chartArgsSchema.optional())
const executeSqlChartResultSchema = z
.object({
sql: z.string().optional(),
label: z.string().optional(),
isWriteQuery: z.boolean().optional(),
chartConfig: chartArgsFieldSchema,
config: chartArgsFieldSchema,
})
.passthrough()
.transform(({ sql, label, isWriteQuery, chartConfig, config }) => {
const chartArgs = chartConfig ?? config
return {
sql: sql ?? '',
label,
isWriteQuery,
view: chartArgs?.view,
xAxis: chartArgs?.xKey ?? chartArgs?.xAxis,
yAxis: chartArgs?.yKey ?? chartArgs?.yAxis,
}
})
export function parseExecuteSqlChartResult(
input: unknown
): SafeParseReturnType<unknown, z.infer<typeof executeSqlChartResultSchema>> {
return executeSqlChartResultSchema.safeParse(input)
}
export const deployEdgeFunctionInputSchema = z
.object({
code: z.string().min(1),
name: z.string().trim().optional(),
slug: z.string().trim().optional(),
functionName: z.string().trim().optional(),
label: z.string().optional(),
})
.passthrough()
.transform((data) => {
const rawName = data.functionName ?? data.name ?? data.slug
const trimmedName = rawName?.trim()
const functionName = trimmedName && trimmedName.length > 0 ? trimmedName : 'my-function'
const rawLabel = data.label ?? rawName
const trimmedLabel = rawLabel?.trim()
const label = trimmedLabel && trimmedLabel.length > 0 ? trimmedLabel : 'Edge Function'
return {
code: data.code,
functionName,
label,
}
})
export const deployEdgeFunctionOutputSchema = z
.object({ success: z.boolean().optional() })
.passthrough()
export const rateMessageResponseSchema = z.object({
category: z.enum([
'sql_generation',
'schema_design',
'rls_policies',
'edge_functions',
'database_optimization',
'debugging',
'general_help',
'other',
]),
})
export type RateMessageResponse = z.infer<typeof rateMessageResponseSchema>