Add AI assistant tools for site search, project details, experience matching, and calendar availability
This commit is contained in:
@@ -1,14 +1,12 @@
|
||||
import { auth } from '@clerk/nextjs/server'
|
||||
import { createOpenAI } from '@ai-sdk/openai'
|
||||
import { streamText, tool, convertToModelMessages, stepCountIs, type UIMessage } from 'ai'
|
||||
import { success, z } from 'zod'
|
||||
import { streamText, convertToModelMessages, stepCountIs, type UIMessage } from 'ai'
|
||||
import { eq, and } from 'drizzle-orm'
|
||||
import { env } from '~/env'
|
||||
import { db } from '~/server/db'
|
||||
import { chatSession, chatMessage } from '~/server/dbschema/schema'
|
||||
import { servTrpc } from '~/app/_trpc/ServerClient'
|
||||
import { scheduleMeeting } from '~/app/actions/scheduleMeeting'
|
||||
import currentTime from '~/app/actions/currentTime';
|
||||
import { createChatTools } from '~/server/ai/tools'
|
||||
|
||||
const openai = createOpenAI({ apiKey: env.OPENAI_API_KEY })
|
||||
|
||||
@@ -31,7 +29,15 @@ export async function POST(req: Request) {
|
||||
|
||||
if (!session) return new Response('Session not found', { status: 404 })
|
||||
|
||||
const systemPrompt = await servTrpc.chat.getSystemPrompt() || 'You are an AI recruiter assistant.'
|
||||
const configuredSystemPrompt = await servTrpc.chat.getSystemPrompt() || 'You are an AI recruiter assistant.'
|
||||
const systemPrompt = `${configuredSystemPrompt}
|
||||
|
||||
Runtime context:
|
||||
- Current server time: ${new Date().toISOString()}.
|
||||
- Default meeting timezone: Europe/Berlin.
|
||||
- For availability questions like "next open spot", call getAvailability once. It defaults to checking from now. Use nextAvailableSlot for the next opening, or the first item in availableSlots if needed. Do not call getAvailability again just to get more slots.
|
||||
- After scheduleMeeting succeeds, include the returned inviteLink or htmlLink in your response.
|
||||
- Do not calculate or invent calendar availability yourself.`
|
||||
const model = await servTrpc.chat.getModel()
|
||||
|
||||
// Save the latest user message
|
||||
@@ -50,42 +56,14 @@ export async function POST(req: Request) {
|
||||
model: openai(model),
|
||||
system: systemPrompt,
|
||||
messages: await convertToModelMessages(messages),
|
||||
tools: {
|
||||
scheduleMeeting: tool({
|
||||
description: 'Schedule a meeting with Gregor Lohaus and add it to his Google Calendar',
|
||||
inputSchema: z.object({
|
||||
title: z.string().describe('Meeting title, make something up if not provided'),
|
||||
description: z.string().describe('Meeting description / agenda, make something up if not provided'),
|
||||
dateTime: z
|
||||
.string()
|
||||
.describe(
|
||||
'ISO 8601 datetime for the meeting start, e.g. 2025-04-01T10:00:00',
|
||||
),
|
||||
durationMinutes: z
|
||||
.number()
|
||||
.int()
|
||||
.min(15)
|
||||
.max(120)
|
||||
.describe('Duration of the meeting in minutes, if none provided ask if 20 minutes is ok'),
|
||||
attendeeEmail: z
|
||||
.string()
|
||||
.email()
|
||||
.optional()
|
||||
.describe('Optional Email of the visitor to invite (if provided)'),
|
||||
attendeeName: z.string().optional().describe('Name of the visitor'),
|
||||
}),
|
||||
execute: async (input) => scheduleMeeting({ ...input }),
|
||||
}),
|
||||
getCurrentUnixTime: tool({
|
||||
description: 'Get the current unix time to reference for meeting dates',
|
||||
inputSchema: z.object({
|
||||
none: z.string().optional().describe("no inputs are needed")
|
||||
}),
|
||||
execute: async () => currentTime()
|
||||
})
|
||||
},
|
||||
stopWhen: stepCountIs(5),
|
||||
tools: createChatTools(),
|
||||
stopWhen: stepCountIs(2),
|
||||
onFinish: async ({ text, finishReason }) => {
|
||||
console.log('[ai:chat:onFinish]', {
|
||||
finishReason,
|
||||
hasText: Boolean(text),
|
||||
textLength: text.length,
|
||||
})
|
||||
if (text && finishReason === 'stop') {
|
||||
await db.insert(chatMessage).values({
|
||||
sessionId,
|
||||
|
||||
Reference in New Issue
Block a user