Inject dates, user info, and runtime context into your agents
LLMs don’t know the current date, who your user is, or what plan they’re on. You need to inject this information into the agent’s context. This page covers the most common patterns for working with dynamic data in production agents.
Without dynamic data, your agent is blind to reality:
// The agent has NO idea what day it is// If a user asks "schedule for tomorrow", the agent can't answer correctlyconst agent = new Agent({ instructions: 'You are a scheduling assistant.', model: openai('gpt-4o'),});
Instead of a static string, use a function that builds the instructions dynamically:
agent.ts
import { Agent, openai } from '@runflow-ai/sdk';import { format } from 'date-fns';import { ptBR } from 'date-fns/locale';function buildInstructions() { const now = new Date(); const today = format(now, "EEEE, d 'de' MMMM 'de' yyyy", { locale: ptBR }); const time = format(now, 'HH:mm'); return `You are a scheduling assistant.## Current Date and Time- Today is: ${today}- Current time: ${time} (Brasília timezone, UTC-3)- Use this as reference for all date calculations## Behavior- When the user says "tomorrow", calculate from today's date- When the user says "next week", calculate from this week- Always confirm dates explicitly: "Tuesday, March 15th at 2pm"- Never guess dates — always calculate from the current date above## Tools- Use schedule-appointment to book appointments- Use check-availability to verify open slots`;}export const schedulingAgent = new Agent({ name: 'Scheduling Assistant', instructions: buildInstructions(), model: openai('gpt-4o'), memory: { maxTurns: 20 }, tools: { scheduleAppointment: scheduleAppointmentTool, checkAvailability: checkAvailabilityTool, },});
If you build the instructions at module load time (outside main()), the date will be set when the agent starts and won’t update between requests. For most use cases this is fine since deploys are frequent. If you need per-request dates, see the next pattern.
When you need the date to be accurate on every single request, rebuild instructions inside main():
main.ts
import { Agent, openai } from '@runflow-ai/sdk';import { identify } from '@runflow-ai/sdk/observability';import { format } from 'date-fns';import { ptBR } from 'date-fns/locale';function buildInstructions() { const now = new Date(); return `You are a scheduling assistant.## Current Date and Time- Today: ${format(now, "EEEE, d 'de' MMMM 'de' yyyy", { locale: ptBR })}- Time: ${format(now, 'HH:mm')} (UTC-3)- Use this for all date calculations`;}export async function main(input: any) { identify(input.email || input.phone || 'anonymous'); // Create agent with fresh date on every request const agent = new Agent({ name: 'Scheduling Assistant', instructions: buildInstructions(), model: openai('gpt-4o'), memory: { maxTurns: 20 }, }); const result = await agent.process({ message: input.message, sessionId: input.sessionId, }); return { message: result.message };}
The agent.process() method accepts a messages array alongside message. Use it to inject structured context — user profile data, CRM records, previous interactions, or any information the agent needs to respond well.
Fixed behavior rules that don’t change per request
buildInstructions() function
Rules that depend on dynamic data (date, user plan)
messages array
Per-request context data (CRM records, order history, lead info)
Both combined
Fixed instructions + dynamic context data
A good rule of thumb: put behavior rules in instructions and data in messages. The instructions tell the agent how to behave; the messages tell it what it’s working with.
function buildCollectionsPrompt(debt: { customerName: string; amount: number; dueDate: string; daysOverdue: number;}) { return `You are a professional debt collection agent.## Customer & Debt Info- Customer: ${debt.customerName}- Amount due: R$ ${debt.amount.toFixed(2)}- Original due date: ${debt.dueDate}- Days overdue: ${debt.daysOverdue}## Strategy${debt.daysOverdue <= 7 ? '- Be gentle — this is a recent overdue. A friendly reminder is enough.' : debt.daysOverdue <= 30 ? '- Be firm but empathetic. Offer a payment plan if needed.' : '- This is significantly overdue. Offer flexible payment options. Escalate if refused.'}## Rules- Never be aggressive or threatening- You may share the amount with the customer directly- Never share the amount with third parties`;}
For prompts managed in the Runflow portal, use loadPrompt() with template variables:
agent.ts
import { Agent, openai, loadPrompt } from '@runflow-ai/sdk';import { format } from 'date-fns';const agent = new Agent({ name: 'Support Agent', instructions: loadPrompt('customer-support', { currentDate: format(new Date(), 'yyyy-MM-dd'), product: 'CRM Pro', language: 'Portuguese', }), model: openai('gpt-4o'),});
In the portal, your prompt template would look like:
You are a support agent for {{product}}.Today's date is {{currentDate}}.Respond in {{language}}.
Use loadPrompt() when you want non-developers (product managers, prompt engineers) to edit prompts through the portal without code changes. Use local functions when the prompt logic is complex or involves conditionals.
The single most important thing: always tell the LLM what today’s date is.
instructions: `...## Current DateToday is Wednesday, March 12, 2025. Current time: 14:30 (UTC-3).When the user says:- "tomorrow" → Thursday, March 13, 2025- "next Monday" → Monday, March 17, 2025- "in 2 weeks" → Wednesday, March 26, 2025Always confirm the calculated date with the user before scheduling.`
Don’t trust the LLM to calculate dates correctly. Validate in the tool:
tools/schedule-appointment.ts
import { createTool } from '@runflow-ai/sdk';import { track } from '@runflow-ai/sdk/observability';import { z } from 'zod';import { parseISO, isBefore, isWeekend, format, startOfDay } from 'date-fns';export const scheduleAppointmentTool = createTool({ id: 'schedule-appointment', description: 'Schedule an appointment on a specific date and time', inputSchema: z.object({ date: z.string().describe('Appointment date in ISO format (YYYY-MM-DD)'), time: z.string().describe('Appointment time (HH:mm)'), description: z.string().describe('What the appointment is about'), }), execute: async (params) => { const appointmentDate = parseISO(`${params.date}T${params.time}:00`); const now = new Date(); // Validate: not in the past if (isBefore(appointmentDate, now)) { return { success: false, error: `Cannot schedule in the past. The requested date ${params.date} ${params.time} has already passed. Current date is ${format(now, 'yyyy-MM-dd HH:mm')}.`, }; } // Validate: not on weekends if (isWeekend(appointmentDate)) { return { success: false, error: `${format(appointmentDate, 'EEEE, MMMM d')} is a weekend. Please choose a weekday.`, }; } // Validate: business hours (9-18) const hour = parseInt(params.time.split(':')[0]); if (hour < 9 || hour >= 18) { return { success: false, error: 'Appointments are only available between 9:00 and 18:00.', }; } // Schedule the appointment const appointment = await createAppointment({ date: appointmentDate, description: params.description, }); track('appointment_scheduled', { date: params.date, dayOfWeek: format(appointmentDate, 'EEEE'), }); return { success: true, id: appointment.id, date: format(appointmentDate, "EEEE, MMMM d 'at' HH:mm"), confirmation: `Appointment confirmed for ${format(appointmentDate, "EEEE, MMMM d 'at' HH:mm")}`, }; },});
Let the agent check available slots instead of guessing:
tools/check-availability.ts
import { createTool } from '@runflow-ai/sdk';import { z } from 'zod';import { parseISO, format, addDays, isWeekend } from 'date-fns';export const checkAvailabilityTool = createTool({ id: 'check-availability', description: 'Check available appointment slots for a date or date range', inputSchema: z.object({ date: z.string().describe('Start date in ISO format (YYYY-MM-DD)'), days: z.number().optional().describe('Number of days to check (default: 1, max: 7)'), }), execute: async (params) => { const startDate = parseISO(params.date); const daysToCheck = Math.min(params.days || 1, 7); const slots: { date: string; times: string[] }[] = []; for (let i = 0; i < daysToCheck; i++) { const day = addDays(startDate, i); if (isWeekend(day)) continue; // Fetch from your calendar/booking system const available = await getAvailableSlots(day); slots.push({ date: format(day, 'yyyy-MM-dd (EEEE)'), times: available.map((s: any) => s.time), }); } if (!slots.length) { return { available: false, message: 'No available slots in the requested period' }; } return { available: true, slots }; },});
A complete example that combines date injection, user context, and scheduling tools:
main.ts
import { Agent, openai } from '@runflow-ai/sdk';import { identify, track } from '@runflow-ai/sdk/observability';import { format } from 'date-fns';import { ptBR } from 'date-fns/locale';import { scheduleAppointmentTool } from './tools/schedule-appointment';import { checkAvailabilityTool } from './tools/check-availability';function buildInstructions(userName: string) { const now = new Date(); const today = format(now, "EEEE, d 'de' MMMM 'de' yyyy", { locale: ptBR }); const time = format(now, 'HH:mm'); return `You are a scheduling assistant for ACME Clinic.## Current Date and Time- Today: ${today}- Time: ${time} (Brasília, UTC-3)## Customer- Name: ${userName}## Behavior- Address the customer by name- Always check availability before scheduling- Confirm the full date and time with the customer before booking- Business hours: Monday to Friday, 9:00 to 18:00- Respond in Portuguese## Tools- Use check-availability FIRST to see open slots- Use schedule-appointment to book after customer confirms- Never schedule without checking availability first`;}export async function main(input: any) { if (!input?.message) { return { error: 'message is required' }; } const phone = input.phone || input.from; identify(phone || input.email || 'anonymous'); // Fetch user info const user = await fetchUser(phone); const agent = new Agent({ name: 'Scheduling Assistant', instructions: buildInstructions(user?.name || 'Cliente'), model: openai('gpt-4o'), memory: { maxTurns: 20 }, modelConfig: { temperature: 0 }, tools: { checkAvailability: checkAvailabilityTool, scheduleAppointment: scheduleAppointmentTool, }, observability: 'full', }); try { const result = await agent.process({ message: input.message, sessionId: input.sessionId || `scheduling_${phone}`, }); track('scheduling_interaction', { hasAppointment: result.metadata?.toolsUsed?.includes('schedule-appointment'), }); return { message: result.message }; } catch (error) { console.error('[scheduling] Error:', error); return { error: 'An error occurred. Please try again.' }; }}
Dynamic data with code logic (conditionals, formatting)
loadPrompt() with variables
Prompts managed in the portal by non-developers
Per-request agent creation
When data must be fresh on every request (dates, user context)
Date validation in tools
Always — never trust the LLM to calculate dates correctly
Never trust the LLM to calculate dates. Always validate dates in your tools — check for past dates, weekends, business hours, and conflicts. The LLM should propose, your tool should validate.