| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- 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)
- }
- })
- }
- })
- })
- })
|