Ekairos · Librería
Flujo base de Ekairos Agent
Referencia mínima de cómo integrar la librería tal cual se encuentra hoy: API route, configuración del agente y UI de prueba. Cada sección enlaza directamente con el archivo real dentro del monorepo.
packages/web/src/lib/agents/simple-agent.ts
1. Configuración del Agente (createAgent)
El núcleo del flujo es la función fluida `createAgent()` expuesta por `ekairos/agent`. Define el contexto persistente, el prompt del sistema y las herramientas (tipadas con Zod) sin tocar genéricos.
import { createAgent } from "ekairos/agent"
import { z } from "zod"
import { tool } from "ai"
const simpleAgentBuilder = createAgent()
.context(async (stored) => {
const previous = stored.content
return {
userId: previous?.userId ?? "test-user",
topic: previous?.topic ?? "general",
}
})
.systemPrompt(async ({ content }) => {
const { topic } = content
return `You are a helpful assistant for testing purposes.
Current topic: ${topic}.`
})
.tools(async ({ content }, stream) => {
void stream
const { topic } = content
return {
setTopic: tool({
description: `Set the conversation topic (current: ${topic})`,
inputSchema: z.object({
topic: z.string().describe("The topic to set for the conversation"),
}),
execute: async ({ topic }) => ({ success: true, message: `Topic set to ${topic}` }),
}),
}
})
.model("gpt-4o-mini")
export const simpleAgentConfig = simpleAgentBuilder.config()
export const simpleAgent = simpleAgentBuilder.build()packages/web/src/app/api/test-agent/route.ts
2. API Route
La API HTTP recibe los mensajes del componente Agent y los convierte en eventos compatibles con Ekairos. Esta es la pieza que siempre se monta primero.
import { UIMessage, createUIMessageStreamResponse } from "ai"
import { simpleAgent } from "@/lib/agents/simple-agent"
function createUserItemFromUIMessages(messages: UIMessage[]) {
if (!Array.isArray(messages) || messages.length === 0) {
throw new Error("Missing messages to create event")
}
const lastMessage = messages[messages.length - 1]
return {
id: lastMessage.id,
type: "user.message",
channel: "web",
content: {
parts: lastMessage.parts,
},
createdAt: new Date().toISOString(),
}
}
export async function POST(req: Request) {
const { messages, contextKey }: { messages: UIMessage[]; contextKey?: string } = await req.json()
const event = createUserItemFromUIMessages(messages)
try {
const result = await simpleAgent.progressStream(event, contextKey ? { key: contextKey } : null)
return createUIMessageStreamResponse({ stream: result.stream })
} catch (error) {
console.error("[api/test-agent] progressStream failed", JSON.stringify(error, null, 2))
return new Response(
JSON.stringify({
error: "Agent failed to respond",
}),
{
status: 500,
headers: { "Content-Type": "application/json" },
},
)
}
}packages/web/src/app/test-agent/page.tsx
3. UI del Agente (opcional)
La librería es independiente de la UI. Aquí mostramos cómo el `Agent` de Ekairos consume la API, pero cualquier cliente que emita eventos compatibles funcionará.
"use client"
import { useCallback, Suspense } from "react"
import { useSearchParams } from "next/navigation"
import Agent from "@/components/ekairos/agent/Agent"
function TestAgentContent() {
const searchParams = useSearchParams()
const handleContextUpdate = useCallback((contextId: string) => {
const params = new URLSearchParams(window.location.search)
if (contextId && contextId.length > 0) {
params.set("contextId", contextId)
} else {
params.delete("contextId")
}
const paramsString = params.toString()
let nextUrl = window.location.pathname
if (paramsString.length > 0) {
nextUrl = `${nextUrl}?${paramsString}`
}
window.history.replaceState({}, "", nextUrl)
console.log("[Test Agent] Context updated:", contextId)
}, [])
const initialContextId = searchParams.get("contextId") || undefined
return (
<div className="min-h-screen h-screen w-full">
<Agent
apiUrl="/api/test-agent"
onContextUpdate={handleContextUpdate}
toolComponents={{}}
initialContextId={initialContextId}
/>
</div>
)
}
export default function TestAgentPage() {
return (
<Suspense
fallback={
<div className="min-h-screen h-screen flex items-center justify-center bg-background">
<div className="text-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
<p className="text-muted-foreground">Loading Ekairos Agent...</p>
</div>
</div>
}
>
<TestAgentContent />
</Suspense>
)
}Flujo completo
Resumen operacional
Estos pasos explican el pipeline sin modificar nada: ideal para validar antes de iterar nombres o comportamientos.
- 1. Configuración con `createAgent()`. Definimos el contexto, prompt y herramientas mediante la API fluida sin genéricos. El builder produce el `AgentConfig` y la instancia final (`build()`).
- 2. La API traduce a eventos. La función `createUserItemFromUIMessages` del route prepara un evento `user.message` compatible con `simpleAgent.progressStream`.
- 3. El agente responde en streaming. `simpleAgent.progressStream` (definido en `packages/web/src/lib/agents/simple-agent.ts`) regresa un stream que `createUIMessageStreamResponse` transforma en SSE para el componente `Agent`.
Por qué usar la librería
Conceptos clave de `ekairos/agent`
Contexto tipado
El callback `context()` del builder define y persiste estados arbitrarios (InstantDB, KV, etc.). Su return type alimenta automáticamente al resto de la cadena.
Herramientas basadas en Zod
Cada `tool` usa `inputSchema` para validar la carga útil. Esto genera JSON Schema automáticamente para AI SDK y evita prompts frágiles.
Streams con control de progreso
`progressStream(event, opts?)` retorna `{ stream, metadata }`. El stream es compatible con `ai` (`createUIMessageStreamResponse`) y conserva `contextKey` para reanudar conversaciones.