Configurar el agente que conversa
Publicar el borrador, conectar herramientas y atender solicitudes.
GET /ai-agents lista los agentes que responden por el workspace cuando nadie del equipo escribe primero. Cada uno trae un system_prompt, un modelo y las herramientas que puede llamar. También trae los skills que sabe aplicar y la base de conocimiento que puede citar.
Leer pide ai_agents:read; escribir, ai_agents:write.
Borrador y versión en vivo
Cada agente tiene dos caras. El system_prompt, el modelo y las herramientas ya wireadas son lo que corre ahora mismo. Todo lo que empieza con draft_ es un cambio a medio hacer que nadie más ve todavía.
curl https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001 \
-H "Authorization: Bearer $VITRINA_KEY"{
"data": {
"id": "a3a3a3a3-0000-4000-8000-000000000001",
"name": "Asistente de ventas",
"status": "active",
"is_default": true,
"model": "deepseek/deepseek-v4.1-flash",
"system_prompt": "Eres un asistente de ventas. Responde de forma breve y cercana.",
"published_version_id": "a3a3a3a3-1000-4000-8000-000000000007",
"draft_system_prompt": null,
"draft_updated_at": null,
"created_at": "2026-08-04T19:07:05.226Z",
"updated_at": "2026-09-17T14:49:02.893Z"
}
}model casi nunca se manda. La plataforma elige y administra el modelo de cada agente, y la UI nunca lo pide. Mandar model es un escape hatch y no un catálogo abierto.
Editar el borrador
curl -X PUT https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/draft \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"system_prompt": "Eres un asistente de ventas. Ahora también ofreces financiamiento.",
"knowledge_tags": ["horarios", "garantia", "financiamiento"]
}'Nada de esto llega al runtime todavía. PUT /ai-agents/{id}/system-prompt es un atajo sobre lo mismo: edita solo el prompt, staged igual. GET /ai-agents/{id}/draft lee el borrador pendiente y DELETE lo descarta sin tocar lo que está en vivo.
Publicar
curl -X POST https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/publish \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{}'Publicar copia el borrador a lo que corre, guarda una versión (GET /ai-agents/{id}/versions) y dispara ai_agent.publish.
Hay un freno. Si el agente tiene una suite golden de Agent Evals habilitada y su último veredicto está blocked o stale, la llamada responde 409 en vez de publicar. Antes de automatizar un publish, consulta el freno:
curl https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/publish-gate \
-H "Authorization: Bearer $VITRINA_KEY"{
"data": {
"gate": "clear",
"suite": {
"id": "b6b6b6b6-0000-4000-8000-000000000001",
"name": "Golden",
"kind": "golden"
},
"last_run": {
"pass_rate": 91.2,
"hard_fails": 0
}
}
}Con force: true el publish se salta el freno, y queda en el registro de auditoría con quién lo hizo.
POST /ai-agents/{id}/versions/{version}/restore carga una versión pasada al borrador, para revisarla antes de publicar. POST /ai-agents/{id}/versions/{version}/rollback hace las dos cosas de una vez: carga y publica, y deja esa versión en vivo de inmediato.
Skills
Un skill es un playbook reutilizable que se adjunta a uno o más agentes: «cómo ofrecer horarios», «cómo pedir el número de referencia antes de confirmar». Vive en una biblioteca del workspace y no dentro de un agente en particular.
curl -X PUT https://api.vitrinadev.com/api/v1/skills/a4a4a4a4-0000-4000-8000-000000000001 \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Cuando el cliente quiera agendar, ofrece SOLO horarios de la sucursal más cercana y confirma antes de reservar."
}'Editar un skill es solo contenido y aplica al instante. No hay borrador ni publish para un skill: el cambio llega a cada agente que lo tiene adjunto en su próximo turno.
POST /ai-agents/{id}/skills adjunta uno que ya existe y DELETE /ai-agents/{id}/skills/{skillId} lo desadjunta sin borrarlo. DELETE /skills/{id} sí lo borra, con un borrado suave. Sale de la biblioteca y de todo agente al instante.
Herramientas
GET /ai-agents/tools-catalog lista lo que este workspace puede wirear hoy, filtrado por rubro e integraciones conectadas. PUT /ai-agents/{id}/tools reemplaza el set completo con tool_names, y aplica en vivo, no al borrador: el próximo turno del agente ya ve el cambio.
Herramientas personalizadas
Cuando la API que el agente necesita llamar es la del propio workspace, no hace falta escribir código. El Tool Store enseña el llamado como una plantilla.
curl -X POST https://api.vitrinadev.com/api/v1/custom-tools \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "consultar_clima",
"description": "Consulta el clima actual de una ciudad",
"parameters": [
{ "name": "ciudad", "type": "string", "description": "Nombre de la ciudad", "required": true }
],
"request_template": {
"method": "GET",
"url": "https://api.example.com/weather?city=${param.ciudad}"
}
}'Los valores de los parámetros se interpolan en la URL, los headers o el body como ${param.NOMBRE}. Una credencial se referencia como ${secret.NOMBRE} y nunca se escribe en la plantilla. POST /custom-tools/{id}/test hace la llamada real, porque no hay modo sandbox, y guarda cada invocación redactada para auditoría.
Cuando la API de destino pide autenticación, la credencial vive aparte, en /tool-credentials:
curl -X POST https://api.vitrinadev.com/api/v1/tool-credentials \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "weather_api_key", "kind": "api_key", "value": "wapi_live_abc123wx91" }'{
"data": {
"id": "a7a7a7a7-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "weather_api_key",
"kind": "api_key",
"value_preview": "••••wx91",
"metadata": {},
"created_by": "11111111-0000-4000-8000-000000000001",
"created_at": "2026-09-12T10:00:00.000Z",
"updated_at": "2026-09-12T10:00:00.000Z",
"last_used_at": "2026-09-21T18:04:11.000Z",
"rotation_grace_until": null
}
}El valor en texto plano nunca vuelve a mostrarse. Cada lectura trae solo value_preview, unos caracteres enmascarados, igual que una API key. Rotar es un PATCH con un value nuevo. El valor viejo sigue funcionando 24 horas más, así una llamada en curso no se rompe a mitad de la rotación.
Base de conocimiento
Un agente cita lo que tiene adjunto y no toda la biblioteca del workspace:
curl https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/knowledge \
-H "Authorization: Bearer $VITRINA_KEY"POST /ai-agents/{id}/knowledge sube un archivo nuevo directo al agente, en multipart, o adjunta uno que ya existe en la biblioteca con { "kb_file_id": "…" }. DELETE /ai-agents/{id}/knowledge/{fileId} desadjunta, y el archivo sigue existiendo y sirviendo a cualquier otro agente. Cómo se sube, genera y reemplaza un archivo está en Base de conocimiento.
Canal de voz
curl https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/voice-channel \
-H "Authorization: Bearer $VITRINA_KEY"Trae el estado de la línea, el saludo, la voz elegida de un catálogo curado y el número de derivación a un humano. Del saludo solo se edita el segmento de marca. El aviso de que es IA y de que la llamada se graba lo compone el servidor, y no se puede quitar. voice_id es una clave de ese catálogo y no un id propio del workspace.
PUT guarda el cambio y lo empuja a la capa de voz. Si el empuje falla queda pendiente, y POST /ai-agents/{id}/voice-channel/propagate reintenta.
Solicitudes: cuando un cliente pide un cambio
Una Solicitud (agent_change_request) es un requerimiento que alguien planteó con sus propias palabras: «no uses guiones», «si algo no está disponible, dile que lo vamos a conseguir». Es distinta de un hallazgo que la plataforma detectó sola.
curl -X POST https://api.vitrinadev.com/api/v1/ai-agents/a3a3a3a3-0000-4000-8000-000000000001/change-requests \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{ "verbatim": "No uses guiones largos, suena robótico.", "reporter_kind": "client_via_member" }'También se puede archivar como audio (multipart/form-data, campo file). Se transcribe, y la transcripción es el verbatim, así que nada queda guardado que no se pudiera convertir a texto.
El ciclo de vida:
| Estado | Qué significa |
|---|---|
received | Se registró lo que dijo el cliente |
grounded | Se confirmó en qué conversación pasó |
reproduced | Un escenario reprodujo el problema contra la versión reclamada |
proposed | Se propuso un arreglo |
applied | El arreglo se aplicó |
verified | Se confirmó que el arreglo funciona |
ya_cumple | El agente ya lo hacía bien y la queja era sobre una versión vieja |
harness | El arreglo es de la plataforma y no del prompt de este agente |
POST .../change-requests/{crId}/ground busca en qué conversaciones pasó, sin tocar nada. POST .../ground/confirm es la respuesta humana a esa búsqueda. POST .../scenario autoría un escenario de prueba desde la solicitud y lo corre contra la versión reclamada. POST .../propose investiga y guarda una propuesta de arreglo, una vez que el escenario reprodujo el problema en rojo.
Los eventos
| Evento | Cuándo |
|---|---|
ai_agent.publish | Un borrador se publicó como configuración en vivo |
skill.created / .updated / .deleted | Cambió la biblioteca de skills |
custom_tool.created / .updated / .deleted | Cambió el Tool Store |
ai_agent.publish lleva ai_agent_id, name y updated_at, lo justo para saber qué agente cambió y cuándo. El contenido de la publicación se lee con GET /ai-agents/{id}/versions.