mirror of
https://github.com/supabase/supabase.git
synced 2026-06-01 02:14:43 +08:00
177 lines
5.4 KiB
TypeScript
177 lines
5.4 KiB
TypeScript
import type { ToolUIPart } from 'ai'
|
|
import { describe, expect, test } from 'vitest'
|
|
|
|
// End of third-party imports
|
|
|
|
import { prepareMessagesForAPI } from '../message-utils'
|
|
import {
|
|
createAssistantMessageWithExecuteSqlTool,
|
|
createAssistantMessageWithMultipleTools,
|
|
createLongConversation,
|
|
} from '../test-fixtures'
|
|
import { NO_DATA_PERMISSIONS, sanitizeMessagePart } from './tool-sanitizer'
|
|
|
|
describe('messages are sanitized based on opt-in level', () => {
|
|
test('messages are sanitized at disabled level', () => {
|
|
const messages = [
|
|
createAssistantMessageWithExecuteSqlTool('SELECT email FROM users', [
|
|
{ email: 'test@example.com' },
|
|
]),
|
|
]
|
|
|
|
// Prepare messages as frontend would
|
|
const preparedMessages = prepareMessagesForAPI(messages)
|
|
|
|
// Sanitize messages as API endpoint would
|
|
const processedMessages = preparedMessages.map((msg) => {
|
|
if (msg.role === 'assistant' && msg.parts) {
|
|
const processedParts = msg.parts.map((part) => {
|
|
return sanitizeMessagePart(part, 'disabled')
|
|
})
|
|
|
|
return { ...msg, parts: processedParts }
|
|
}
|
|
return msg
|
|
})
|
|
|
|
const output = (processedMessages[0].parts[1] as ToolUIPart).output
|
|
expect(output).toMatch(NO_DATA_PERMISSIONS)
|
|
})
|
|
|
|
test('messages are sanitized at schema level', () => {
|
|
const messages = [
|
|
createAssistantMessageWithExecuteSqlTool('SELECT email FROM users', [
|
|
{ email: 'test@example.com' },
|
|
]),
|
|
]
|
|
|
|
// Prepare messages as frontend would
|
|
const preparedMessages = prepareMessagesForAPI(messages)
|
|
|
|
// Sanitize messages as API endpoint would
|
|
const processedMessages = preparedMessages.map((msg) => {
|
|
if (msg.role === 'assistant' && msg.parts) {
|
|
const processedParts = msg.parts.map((part) => {
|
|
return sanitizeMessagePart(part, 'schema')
|
|
})
|
|
|
|
return { ...msg, parts: processedParts }
|
|
}
|
|
return msg
|
|
})
|
|
|
|
const output = (processedMessages[0].parts[1] as ToolUIPart).output
|
|
expect(output).toMatch(NO_DATA_PERMISSIONS)
|
|
})
|
|
|
|
test('messages are sanitized at schema and log level', () => {
|
|
const messages = [
|
|
createAssistantMessageWithExecuteSqlTool('SELECT email FROM users', [
|
|
{ email: 'test@example.com' },
|
|
]),
|
|
]
|
|
|
|
// Prepare messages as frontend would
|
|
const preparedMessages = prepareMessagesForAPI(messages)
|
|
|
|
// Sanitize messages as API endpoint would
|
|
const processedMessages = preparedMessages.map((msg) => {
|
|
if (msg.role === 'assistant' && msg.parts) {
|
|
const processedParts = msg.parts.map((part) => {
|
|
return sanitizeMessagePart(part, 'schema_and_log')
|
|
})
|
|
|
|
return { ...msg, parts: processedParts }
|
|
}
|
|
return msg
|
|
})
|
|
|
|
const output = (processedMessages[0].parts[1] as ToolUIPart).output
|
|
expect(output).toMatch(NO_DATA_PERMISSIONS)
|
|
})
|
|
|
|
test('messages are not sanitized at data level', () => {
|
|
const messages = [
|
|
createAssistantMessageWithExecuteSqlTool('SELECT email FROM users', [
|
|
{ email: 'test@example.com' },
|
|
]),
|
|
]
|
|
|
|
// Prepare messages as frontend would
|
|
const preparedMessages = prepareMessagesForAPI(messages)
|
|
|
|
// Sanitize messages as API endpoint would
|
|
const processedMessages = preparedMessages.map((msg) => {
|
|
if (msg.role === 'assistant' && msg.parts) {
|
|
const processedParts = msg.parts.map((part) => {
|
|
return sanitizeMessagePart(part, 'schema_and_log_and_data')
|
|
})
|
|
|
|
return { ...msg, parts: processedParts }
|
|
}
|
|
return msg
|
|
})
|
|
|
|
const output = (processedMessages[0].parts[1] as ToolUIPart).output
|
|
expect(output).toEqual([{ email: 'test@example.com' }])
|
|
})
|
|
|
|
test('multiple tool parts in message are sanitized', () => {
|
|
const messages = [createAssistantMessageWithMultipleTools()]
|
|
|
|
// Prepare messages as frontend would
|
|
const preparedMessages = prepareMessagesForAPI(messages)
|
|
|
|
// Sanitize messages as API endpoint would
|
|
const processedMessages = preparedMessages.map((msg) => {
|
|
if (msg.role === 'assistant' && msg.parts) {
|
|
const processedParts = msg.parts.map((part) => {
|
|
return sanitizeMessagePart(part, 'schema')
|
|
})
|
|
|
|
return { ...msg, parts: processedParts }
|
|
}
|
|
return msg
|
|
})
|
|
|
|
const parts = processedMessages[0].parts
|
|
parts.forEach((part) => {
|
|
if (part.type.startsWith('tool')) {
|
|
const tool = part as ToolUIPart
|
|
expect(tool.output).toMatch(NO_DATA_PERMISSIONS)
|
|
}
|
|
})
|
|
})
|
|
|
|
test('long message chain is sanitized', () => {
|
|
const messages = createLongConversation()
|
|
|
|
// Prepare messages as frontend would
|
|
const preparedMessages = prepareMessagesForAPI(messages)
|
|
|
|
// Sanitize messages as API endpoint would
|
|
const processedMessages = preparedMessages.map((msg) => {
|
|
if (msg.role === 'assistant' && msg.parts) {
|
|
const processedParts = msg.parts.map((part) => {
|
|
return sanitizeMessagePart(part, 'schema')
|
|
})
|
|
|
|
return { ...msg, parts: processedParts }
|
|
}
|
|
return msg
|
|
})
|
|
|
|
processedMessages.forEach((msg) => {
|
|
if (msg.role === 'assistant' && msg.parts) {
|
|
const parts = msg.parts
|
|
parts.forEach((part) => {
|
|
if (part.type.startsWith('tool')) {
|
|
const tool = part as ToolUIPart
|
|
expect(tool.output).toMatch(NO_DATA_PERMISSIONS)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
})
|
|
})
|