mirror of
https://github.com/supabase/supabase.git
synced 2026-10-12 04:45:08 +03:00
* chore: bump `supabase` CLI * chore: stricter message types in `generate-v4.ts` * feat: tutorial eval https://www.braintrust.dev/docs/evaluation * feat: project ID for eval * refactor: `generateAssistantResponse` out of `handlePost` * refactor: generateAssistantResponse to lib/ai * feat: factuality eval with assistant response * chore: upgrade braintrust to v1.0.1 * chore: silence tsconfig warning * feat: assertion scorer * fix: aggregate tools across all steps * refactor: strict tool names, remove need for `as const` * refactor: generic tool name type in assertions * feat: transfer mocks from `feature/braintrust` * feat: LLM criteria assertion * feat: braintrust evals workflow * fix: BRAINTRUST_PROJECT_ID * feat: `sql_similar` assertion * fix: `OPENAI_API_KEY` in workflow env * feat: split AssertionScorer into separate scorers * feat: remove tutorial eval * feat: 20 minute CI timeout * feat: category in test case metadata * feat: score with gpt-5 * refactor: dataset to own file, colocate scorers * feat: "gpt-5.2-2025-12-11" for llm as a judge * feat: SQL syntax scorer with `libpg-query` * feat: `evals:setup` and `evals:run` scripts * feat: `evals:setup` in CI * feat: human readable scorer names * chore: rename to "SQL Validity" * feat: add 2 "sql_generation" test cases * feat: update requiredTools in test cases * chore: ignore Cursor MCP config * feat: "Conciseness" score * feat: "Completeness" scorer * fix: generate-v4 test mocks * feat: serialize "steps" for scorer inputs * updated node mem options for typecheck * updated runner * remove ram update as actions handle this * feat: read `BRAINTRUST_PROJECT_ID` from secrets * feat: score helpfulness, remove old scorers * feat: separate `evals:run` and `evals:upload` scripts * feat: passthrough entire classifier result * feat: use live `search_docs` impl, store docs result in metadata * feat: reduce classifier options * feat: filter workflow by `run-evals` PR label or `master` branch * chore: cleanup stubbed mock tools * fix: checkout actual branch with `ref:` * fix: capture search_docs results from all content parts * feat: simplify sql syntax score calculation * feat: use AI SDK's UI message validator * docs: justification for relative `extends` * fix: cleanup leftover validatedMessages * doc: note mock token isn't secret for snyk * fix: mock ui message to pass validation * feat: revert ignoring Cursor MCP config Using `.git/info/exclude` instead until we have an opinion on this * feat: add "tsconfig" as shared-data devDependency, revert relative path in tsconfig * refactor: tool call parsing into function * Update apps/studio/evals/assistant.eval.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * refactor: organize mock schemas and tool factories --------- Co-authored-by: Ali Waseem <waseema393@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
131 lines
3.6 KiB
TypeScript
131 lines
3.6 KiB
TypeScript
import * as ai from 'ai'
|
|
import {
|
|
convertToModelMessages,
|
|
isToolUIPart,
|
|
type LanguageModel,
|
|
type ModelMessage,
|
|
stepCountIs,
|
|
type ToolSet,
|
|
type UIMessage,
|
|
} from 'ai'
|
|
import { wrapAISDK } from 'braintrust'
|
|
import { source } from 'common-tags'
|
|
|
|
import type { AiOptInLevel } from 'hooks/misc/useOrgOptedIntoAi'
|
|
import {
|
|
CHAT_PROMPT,
|
|
EDGE_FUNCTION_PROMPT,
|
|
GENERAL_PROMPT,
|
|
PG_BEST_PRACTICES,
|
|
RLS_PROMPT,
|
|
REALTIME_PROMPT,
|
|
SECURITY_PROMPT,
|
|
LIMITATIONS_PROMPT,
|
|
} from 'lib/ai/prompts'
|
|
import { sanitizeMessagePart } from 'lib/ai/tools/tool-sanitizer'
|
|
|
|
const { streamText } = wrapAISDK(ai)
|
|
|
|
export async function generateAssistantResponse({
|
|
messages: rawMessages,
|
|
model,
|
|
tools,
|
|
aiOptInLevel = 'schema',
|
|
getSchemas,
|
|
projectRef,
|
|
chatName,
|
|
promptProviderOptions,
|
|
providerOptions,
|
|
abortSignal,
|
|
}: {
|
|
messages: UIMessage[]
|
|
model: LanguageModel
|
|
tools: ToolSet
|
|
aiOptInLevel?: AiOptInLevel
|
|
getSchemas?: () => Promise<string>
|
|
projectRef?: string
|
|
chatName?: string
|
|
promptProviderOptions?: Record<string, any>
|
|
providerOptions?: Record<string, any>
|
|
abortSignal?: AbortSignal
|
|
}) {
|
|
// Only returns last 7 messages
|
|
// Filters out tools with invalid states
|
|
// Filters out tool outputs based on opt-in level using renderingToolOutputParser
|
|
const messages = (rawMessages || []).slice(-7).map((msg) => {
|
|
if (msg && msg.role === 'assistant' && 'results' in msg) {
|
|
const cleanedMsg = { ...msg }
|
|
delete cleanedMsg.results
|
|
return cleanedMsg
|
|
}
|
|
if (msg && msg.role === 'assistant' && msg.parts) {
|
|
const cleanedParts = msg.parts
|
|
.filter((part) => {
|
|
if (isToolUIPart(part)) {
|
|
const invalidStates = ['input-streaming', 'input-available', 'output-error']
|
|
return !invalidStates.includes(part.state)
|
|
}
|
|
return true
|
|
})
|
|
.map((part) => {
|
|
return sanitizeMessagePart(part, aiOptInLevel)
|
|
})
|
|
return { ...msg, parts: cleanedParts }
|
|
}
|
|
return msg
|
|
})
|
|
|
|
const schemasString =
|
|
aiOptInLevel !== 'disabled' && getSchemas
|
|
? await getSchemas()
|
|
: "You don't have access to any schemas."
|
|
|
|
// Important: do not use dynamic content in the system prompt or Bedrock will not cache it
|
|
const system = source`
|
|
${GENERAL_PROMPT}
|
|
${CHAT_PROMPT}
|
|
${PG_BEST_PRACTICES}
|
|
${RLS_PROMPT}
|
|
${EDGE_FUNCTION_PROMPT}
|
|
${REALTIME_PROMPT}
|
|
${SECURITY_PROMPT}
|
|
${LIMITATIONS_PROMPT}
|
|
`
|
|
|
|
// Note: these must be of type `CoreMessage` to prevent AI SDK from stripping `providerOptions`
|
|
// https://github.com/vercel/ai/blob/81ef2511311e8af34d75e37fc8204a82e775e8c3/packages/ai/core/prompt/standardize-prompt.ts#L83-L88
|
|
const assistantContent =
|
|
projectRef || chatName || schemasString !== "You don't have access to any schemas."
|
|
? `The user's current project is ${projectRef || 'unknown'}. Their available schemas are: ${schemasString}. The current chat name is: ${chatName || 'unnamed'}`
|
|
: undefined
|
|
|
|
const coreMessages: ModelMessage[] = [
|
|
{
|
|
role: 'system',
|
|
content: system,
|
|
...(promptProviderOptions && {
|
|
providerOptions: promptProviderOptions,
|
|
}),
|
|
},
|
|
...(assistantContent
|
|
? [
|
|
{
|
|
role: 'assistant' as const,
|
|
// Add any dynamic context here
|
|
content: assistantContent,
|
|
},
|
|
]
|
|
: []),
|
|
...convertToModelMessages(messages),
|
|
]
|
|
|
|
return streamText({
|
|
model,
|
|
stopWhen: stepCountIs(5),
|
|
messages: coreMessages,
|
|
...(providerOptions && { providerOptions }),
|
|
tools,
|
|
...(abortSignal && { abortSignal }),
|
|
})
|
|
}
|