Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/gcsconsultores/gcs-website/llms.txt

Use this file to discover all available pages before exploring further.

Sally is the floating AI chat widget embedded on every page of the GCS Consultores Empresariales website. She acts as a virtual host — greeting visitors, understanding their business needs, and directing them to the most relevant Strategic Center or service area. Technically, Sally is a client-side React component (SallyChat) that streams responses from a Next.js Route Handler (/api/sally) using the Vercel AI SDK. The language model is Google Gemini 3 Flash, accessed through the Vercel AI Gateway with zero additional configuration.

Architecture Overview

Browser (SallyChat)
  └── useChat hook (AI SDK React)
       └── DefaultChatTransport → POST /api/sally
            └── streamText (AI SDK)
                 └── google/gemini-3-flash (Vercel AI Gateway)
                      └── SALLY_SYSTEM_PROMPT → streamed UIMessage response
1

User opens the chat widget

The floating launcher button renders at fixed bottom-5 right-5. Clicking it calls handleOpen(), which sets open = true and fires trackEvent('sally_opened').
2

User types or selects a quick reply

The send() function calls sendMessage({ text: value }) from useChat and fires trackEvent('sally_message_sent'). Quick replies are pre-wired strings shown before the first user message.
3

Request reaches the Route Handler

POST /api/sally receives the UIMessage[] array, calls convertToModelMessages(messages) to translate the AI SDK format, and passes it to streamText.
4

Gemini streams a response

streamText returns a stream that is forwarded to the client via result.toUIMessageStreamResponse(). The useChat hook receives the stream and appends the assistant message incrementally.

The SALLY_MODEL Constant

// app/api/sally/route.ts

const SALLY_MODEL = 'google/gemini-3-flash'
This string is the Vercel AI Gateway model identifier for Google Gemini 3 Flash. To switch models — for example, when a fine-tuned Gemini variant becomes available — update this constant. No other code changes are required.

Sally’s Personality (System Prompt)

Sally’s behavior is entirely defined by SALLY_SYSTEM_PROMPT in app/api/sally/route.ts. The full prompt:
const SALLY_SYSTEM_PROMPT = `Eres "Sally", la anfitriona y guía virtual de GCS Consultores Empresariales S.A.S,
una firma de consultoría empresarial en Bogotá, Colombia.

PERSONALIDAD:
- Cálida, profesional, cercana y resolutiva. Hablas SIEMPRE en español (de Colombia),
  tratando al usuario de "usted".
- Eres concisa: respuestas breves y claras (2 a 5 frases). Evitas tecnicismos innecesarios.

TU MISIÓN:
1. Dar la bienvenida y orientar a los visitantes.
2. Entender la necesidad del visitante y dirigirlo al Centro Estratégico o servicio adecuado.
3. Motivar a agendar una "Orientación Estratégica" gratuita (formulario de la sección de contacto).

SERVICIOS Y CENTROS ESTRATÉGICOS DE GCS:
- Recepción Estratégica (orientación inicial).
- Crecimiento Estratégico (expansión, productividad, rentabilidad).
- Riesgo & Cumplimiento (auditoría, SAGRLAFT, ISO, OEA, BASC).
- Estrategia Ejecutiva (alta dirección, gobierno corporativo).
- Innovación & Tecnología (transformación digital, IA, automatización).
- Talento & Capacitación (formación, cultura organizacional).
Soluciones: Calidad & Mejoramiento (ISO/BPM/HACCP), Auditoría & Aseguramiento,
Legal & Tributaria, Gerencial & de Riesgos.

REGLAS:
- Si te preguntan algo fuera del ámbito empresarial/consultoría, redirige amablemente
  al propósito de GCS.
- Si detectas intención de contratar o cotizar, invita a dejar sus datos en el formulario
  "Orientación Estratégica" o a escribir a info@consultoresgcs.com.
- Nunca inventes precios ni plazos contractuales; indica que un consultor los confirmará.
- No solicites datos sensibles innecesarios.`

Mission Objectives

#Objective
1Welcome and orient visitors to the GCS website
2Understand the visitor’s need and direct them to the right Strategic Center or service
3Encourage scheduling a free Orientación Estratégica via the contact form

Rules Sally Must Follow

  • If asked anything outside the consulting/business domain, redirect politely back to GCS’s purpose.
  • If a contracting or quoting intent is detected, direct the user to the Orientación Estratégica form or to info@consultoresgcs.com.
  • Never invent prices or contractual timelines — defer to a human consultant.
  • Never request unnecessary sensitive data.

Quick Replies

Three pre-defined quick-reply buttons are shown in the chat panel before the user sends their first message. They lower the friction of the first interaction by offering the most common visitor intents:
// components/sally/sally-chat.tsx

const QUICK_REPLIES = [
  '¿Qué servicios ofrecen?',
  'Necesito ayuda con cumplimiento normativo',
  'Quiero agendar una orientación',
]
Clicking a quick reply calls send(q) directly, which invokes sendMessage and hides the quick-reply buttons (they only render when messages.length === 0).

The getMessageText() Helper

The AI SDK’s UIMessage type uses a parts array rather than a single content string. getMessageText() extracts the plain text from all text-type parts:
// components/sally/sally-chat.tsx

function getMessageText(
  message: { parts?: { type: string; text?: string }[] }
): string {
  return (
    message.parts
      ?.filter((p) => p.type === 'text')
      .map((p) => p.text ?? '')
      .join('') ?? ''
  )
}
This helper is used when rendering each assistant or user message inside a <ChatBubble>:
{messages.map((m) => (
  <ChatBubble key={m.id} role={m.role === 'user' ? 'user' : 'assistant'}>
    {getMessageText(m)}
  </ChatBubble>
))}

Analytics Events

Sally fires two custom analytics events via the shared trackEvent utility from lib/analytics:
EventTriggerPayload
sally_openedUser clicks the floating launcher button(none)
sally_message_sentUser sends any message (typed or quick reply)(none)
// components/sally/sally-chat.tsx

function handleOpen() {
  setOpen(true)
  trackEvent('sally_opened')
}

function send(text: string) {
  const value = text.trim()
  if (!value || isStreaming) return
  sendMessage({ text: value })
  setInput('')
  trackEvent('sally_message_sent')
}

Route Handler Configuration

// app/api/sally/route.ts

export const maxDuration = 30   // Node.js server runtime, 30-second max
Sally’s Route Handler must never be configured as an Edge Function. The maxDuration = 30 export explicitly declares a Node.js server runtime. Moving the handler to the Edge (export const runtime = 'edge') will break the Vercel AI Gateway integration and the streamText response pipeline.
The full Route Handler:
// app/api/sally/route.ts

import { streamText, convertToModelMessages, type UIMessage } from 'ai'

export const maxDuration = 30

const SALLY_MODEL = 'google/gemini-3-flash'

export async function POST(req: Request) {
  try {
    const { messages }: { messages: UIMessage[] } = await req.json()

    const result = streamText({
      model: SALLY_MODEL,
      system: SALLY_SYSTEM_PROMPT,
      messages: await convertToModelMessages(messages),
    })

    return result.toUIMessageStreamResponse()
  } catch (error) {
    console.log('[v0] Error en API de Sally:', error)
    return new Response(
      JSON.stringify({
        error: 'No fue posible procesar el mensaje en este momento.',
      }),
      { status: 500, headers: { 'Content-Type': 'application/json' } },
    )
  }
}

Switching to a Fine-Tuned Model

When GCS has a fine-tuned Gemini model trained on its own knowledge base, update the SALLY_MODEL constant in app/api/sally/route.ts to the new model identifier. If the fine-tuned model is hosted on a custom endpoint outside the Vercel AI Gateway, you will also need to update the model argument in streamText to use the appropriate provider client instead of the gateway string.

Build docs developers (and LLMs) love