UNPKG

@directus/api

Version:

Directus is a real-time API and App dashboard for managing SQL database content

48 lines (47 loc) 2.09 kB
import { ForbiddenError, InvalidPayloadError } from '@directus/errors'; import { safeValidateUIMessages } from 'ai'; import { fromZodError } from 'zod-validation-error'; import { createUiStream } from '../lib/create-ui-stream.js'; import { ChatRequest } from '../models/chat-request.js'; import { chatRequestToolToAiSdkTool } from '../utils/chat-request-tool-to-ai-sdk-tool.js'; import { fixErrorToolCalls } from '../utils/fix-error-tool-calls.js'; export const aiChatPostHandler = async (req, res, _next) => { if (!req.accountability?.app) { throw new ForbiddenError(); } const parseResult = ChatRequest.safeParse(req.body); if (!parseResult.success) { throw new InvalidPayloadError({ reason: fromZodError(parseResult.error).message }); } const { provider, model, messages: rawMessages, tools: requestedTools, toolApprovals } = parseResult.data; if (rawMessages.length === 0) { throw new InvalidPayloadError({ reason: `"messages" must not be empty` }); } const tools = requestedTools.reduce((acc, t) => { const name = typeof t === 'string' ? t : t.name; const aiTool = chatRequestToolToAiSdkTool({ chatRequestTool: t, accountability: req.accountability, schema: req.schema, ...(toolApprovals && { toolApprovals }), }); acc[name] = aiTool; return acc; }, {}); const fixedMessages = fixErrorToolCalls(rawMessages); const validationResult = await safeValidateUIMessages({ messages: fixedMessages }); if (validationResult.success === false) { throw new InvalidPayloadError({ reason: validationResult.error.message }); } const stream = createUiStream(validationResult.data, { provider, model, tools: tools, apiKeys: res.locals['ai'].apiKeys, systemPrompt: res.locals['ai'].systemPrompt, onUsage: (usage) => { res.write(`data: ${JSON.stringify({ type: 'data-usage', data: usage })}\n\n`); }, }); stream.pipeUIMessageStreamToResponse(res); };