Documentación
Adjuntar recursos
Darle al turno bibliotecas, archivos, habilidades, conectores y agentes — y saber cuáles podés.
Un turno sin adjuntos usa el conocimiento del modelo y las reglas de la organización. Con adjuntos, además, recibe contexto tuyo: documentos que buscar, instrucciones que seguir, herramientas que usar.
{
"content": "Resumí la política de devoluciones y redactá una respuesta al cliente.",
"permission_mode": "auto",
"attachments": {
"workspace_ids": [31],
"file_ids": [],
"skill_ids": [147],
"mcp_server_ids": []
}
}| Campo | Qué adjunta | Scope adicional |
|---|---|---|
workspace_ids | Bibliotecas enteras. El modelo busca dentro cuando lo necesita. | libraries:read |
file_ids | Archivos concretos, sin traer su biblioteca entera. | libraries:read |
skill_ids | Instrucciones reutilizables que guían la respuesta. Si citan otros recursos, esos también se suman, dentro del alcance de la credencial (ver). | skills:read |
mcp_server_ids | Conectores cuyas herramientas el turno podrá ejecutar. | connectors:use |
agent_ids | Agentes en los que el turno puede delegar tareas (ver). | agents:use |
Atención
chat:write autoriza conversar, no leer lo que se adjunte. Sin el scope compañero, el turno se rechaza con 403 api_token_scope_not_allowed y data.required_scopes nombra los que faltan. La validación ocurre antes de reservar la idempotencia, así que no te quema la key.
Qué podés adjuntar
No adivines los ids. GET /chat/catalog devuelve exactamente lo que esta credencial puede usar, ya recortado por los permisos del usuario y por el alcance de la credencial.
curl -sS 'https://api.niucore.com/api/v1/chat/catalog' \
-H "Authorization: Bearer $NIUCORE_ACCESS_TOKEN" | jq{
"models": [
{ "id": 17, "name": "GPT-4o", "code": "gpt-4o", "type": "COMPLETION" }
],
"permission_modes": ["manual", "auto"],
"libraries": [{ "id": 31, "name": "Procedimientos de soporte" }],
"skills": [{ "id": 147, "name": "Redactar respuesta a cliente" }],
"connectors": [{ "id": 8, "name": "gmail", "display_name": "Gmail" }]
}Nota
Los bloques son condicionales por scope: sin libraries:read la clave libraries no viene — no viene vacía, no viene. Una lista vacía se leería como «no hay ninguna», y eso sería falso. Programá con catalog.libraries ?? [].
Elegir el modelo
model_id viaja por turno. Sin él se usa el del chat, y sin ese el de la empresa. Los ids válidos son los de catalog.models, que solo trae modelos de tipo COMPLETION: un modelo de embedding nunca aparece ahí, porque mandarlo produciría un turno que falla del otro lado.
Límites
- Hasta 20 ids por tipo y 50 en total. Pasarse devuelve
422 api_v1_too_many_attachments, con el campo culpable endata. - Un id fuera del alcance de la credencial también rechaza el turno, y tampoco consume la idempotencia.
- Adjuntar mucho no siempre es mejor: cada biblioteca agrega contexto que el modelo tiene que atravesar, y eso se paga en tokens.
Conectores
Adjuntar un mcp_server_id habilita las herramientas de ese conector para el turno — pero solo funcionan las que el usuario ya conectó desde la aplicación. Si el modelo intenta usar una sin autorizar, el turno se detiene con message.action_required de tipo auth_required, y desde la API la única salida es cancelarlo.
Sugerencia
Con conectores conviene permission_mode: "manual": una herramienta de Gmail o Calendar tiene efectos fuera de NiuCore, y aprobarla explícitamente es lo que evita sorpresas. Ver Interacciones.
Agentes
Con agents:use el turno puede delegar: el modelo reparte tareas entre agentes y las coordina. Hay tres formas de usarlo:
- Sin selección: el turno lleva el catálogo automático de la credencial (el bloque
agentsdeGET /chat/catalog) y el modelo decide si delega. También puede crear agentes temporales para esa solicitud. - Con `attachments.agent_ids` (o citas
{{agent:N}}encontent, que se suman igual): el turno ofrece esos agentes. - Con `principal_agent_id`: además, ese agente conduce el turno con sus instrucciones y su persona. Tiene que estar entre los seleccionados.
{
"content": "Conciliá agosto y prepará el resumen para el cliente.",
"permission_mode": "manual",
"attachments": { "agent_ids": [4, 9], "workspace_ids": [31] },
"principal_agent_id": 4
}El agente no amplía la credencial
Cada tarea trabaja con lo que la credencial alcanza, no con lo que cite la definición del agente: sin libraries:read un agente no busca en ninguna biblioteca, sin connectors:use no usa conectores, y una biblioteca fuera de la allowlist no llega ni por nombre. Personas y contextos compartidos no se exponen en la API.
- Sin
agents:useno hay delegación: unagent_idso una cita{{agent:N}}dan403 api_token_scope_not_allowed. - Las habilidades no suman agentes: un agente citado dentro de una habilidad no se adjunta (ver).
- Máximo 15 agentes por turno. Los topes de concurrencia y de tareas son los de la empresa, igual que en la aplicación; la API no los relaja.
- Cada tarea consume niucredits.
usage.agent_tokensdesglosa ese consumo, que ya está incluido enusage.total_tokens. - El progreso llega en
message.stepy las aprobaciones de los agentes enmessage.action_requiredconagent(Eventos). El terminal traeagent_runs; el detalle de cada tarea, en `…/agent-runs`. No hay cancelación por tarea:actions/cancelcorta el turno entero. - La delegación ocurre dentro del mismo turno y de su tiempo máximo: el stream permite observarla, no la extiende.
Tu propio metadata
metadata es un objeto libre que se guarda con el turno y se devuelve tal cual en la respuesta y en el listado de mensajes. No llega al modelo: es para correlacionar de tu lado. Máximo 2048 bytes serializados.
{
"content": "…",
"metadata": {
"ticket": "8842",
"channel": "whatsapp",
"customer_id": "c-91021"
}
}Es la forma recomendada de atar un turno de NiuCore a un registro tuyo: GET /chats/{id}/messages lo devuelve en cada mensaje, así que podés reconstruir la trazabilidad sin mantener una tabla de correspondencias.