Tema
Tool de petición HTTP
La plantilla http_request conecta un agente (o una inferencia) con cualquier API HTTP sin escribir código: defines qué parámetros rellena el modelo y cómo se convierten en una petición, y lo que conteste la API es lo que el modelo lee. Es multi-instancia: una instancia por llamada («consultar un pedido», «buscar el código postal»…), cada una con su nombre y su descripción.
Se configura en Tools → Nueva instancia → HTTP request, en tres secciones además de la identidad.
Solo un administrador la engancha
Las cabeceras y la URL pueden llevar secretos del administrador que la configuró, y la llamada sale con ellos. Por eso un usuario que no es administrador no puede añadir una instancia http_request a sus agentes o inferencias (en el formulario sale deshabilitada, con el motivo); si un administrador ya se la había enganchado, se conserva aunque él edite el resto.
Identidad: lo que ve el modelo
El nombre es el de la función que invoca el modelo, y la descripción es lo único que sabe de la API junto con sus parámetros. Aquí es obligatoria: di qué hace la API, qué devuelve y cuándo llamarla (y cuándo no).
Entrada: los parámetros
Los parámetros son el esquema de entrada de la tool (un JSON Schema): el modelo ve cada uno con su tipo y su descripción, y los rellena al llamarla. En el modo guiado eliges nombre, tipo (texto, número, entero, sí/no, lista de textos o de números), si es obligatorio, una descripción y, para un texto, los valores permitidos. El modo JSON Schema permite objetos y listas de objetos.
Cada parámetro es además una variable: {{orderId}} se sustituye por lo que mande el modelo, y con un punto se entra en un objeto o una lista ({{customer.name}}, {{lines.0.sku}}).
Del JSON Schema se admite el subconjunto que entienden todos los proveedores: tipos simples (o [tipo, "null"]), enum de textos, items, properties, required, description, default, límites numéricos y de longitud, pattern y format. No se admiten anyOf/oneOf/allOf, $ref ni const: Anthropic descarta en silencio una tool con anyOf en la raíz y Google rechaza el turno entero con una unión de tipos. Si algo no cuadra, el error al guardar dice en qué propiedad.
Petición
| Campo | Cómo funciona |
|---|---|
| Método | GET, POST, PUT, PATCH o DELETE. GET y DELETE no llevan cuerpo. |
| URL | Variables solo en la ruta, y de parámetros obligatorios: https://api.example.com/orders/{{orderId}}. El host es fijo. Un valor con /, .. o . se rechaza, para que el modelo no pueda llegar a otro endpoint. |
| Query | Una fila por parámetro. Si el valor es solo una variable y el modelo no la rellena, el parámetro no se envía; si es una lista, se repite (tag=a&tag=b). |
| Cabeceras | Una fila por cabecera, con autocompletado. Content-Type se pone solo al elegir el cuerpo. |
| Cuerpo | JSON o formulario urlencoded. En JSON, una cadena que es solo una variable ("{{qty}}") recibe el valor con su tipo, y si falta, la clave no se envía. Un JSON vacío manda los argumentos tal cual. |
Valores secretos. Una fila de query o de cabecera marcada como secreta (un Authorization o un X-Api-Key se marcan solos) se guarda cifrada, no vuelve a mostrarse y no admite variables. Al editar se deja vacía para mantenerla, salvo que cambies el host de la URL: entonces hay que volver a escribirla, para que no se pueda redirigir una credencial guardada a otro sitio. Un secreto exige https.
Red interna. Por defecto la tool no llama a direcciones privadas, de loopback ni link-local (localhost, 10.x, 192.168.x, 169.254.169.254…). Actívalo solo para una API interna tuya. Las redirecciones se siguen hasta tres y solo dentro del mismo origen: una redirección a otro host no se sigue, para que no se lleve las cabeceras.
El usuario identificado
Si el agente identifica a su usuario, la tool puede mandar a tu API quién es. Para eso hay dos variables que no son parámetros:
{{$user.claims.<claim>}}: un claim del token del usuario,subincluido. Con un punto se entra en un objeto, como en los parámetros:{{$user.claims.sub}},{{$user.claims.email}},{{$user.claims.org.id}}.{{$user.token}}: el token entero, para que tu API lo verifique por su cuenta.
| Dónde | {{$user.claims.…}} | {{$user.token}} |
|---|---|---|
| Ruta de la URL | Sí | No |
| Query | Sí | No |
| Cabeceras | Sí | Sí |
| Cuerpo (JSON o formulario) | Sí | Sí |
| Mensajes de error | No | No |
El token no va nunca en la URL, porque las URL acaban en los logs. Los mensajes de error no admiten ninguno de los dos: los lee el modelo. En el editor, Datos del usuario identificado tiene las variables a mano para copiarlas.
Lo más habitual es reenviar el token tal cual al backend que lo firmó, que ya sabe verificarlo. Para eso está el interruptor Reenviar el token del usuario (forwardEndUserToken en la configuración), que manda Authorization: Bearer <token>. Equivale a una cabecera Authorization con {{$user.token}}, así que no puede haber además otra cabecera Authorization.
- El modelo no puede rellenar ni cambiar
$user: ningún parámetro se puede llamar así, y el valor lo poneurdespués de los argumentos. - El token cuenta como un valor secreto: la URL tiene que ser
https, salvo con Permitir red interna. - Solo va al host de la URL, que es fijo, y las redirecciones a otro host no se siguen.
- En Depuración y en el log, los valores del usuario en la ruta y en la query salen como
***. - Si el token no trae un claim que la petición usa, la petición no sale, esté donde esté (ruta, query, cabecera o cuerpo), y el modelo lee que a ese usuario le falta ese dato. Con un argumento que falta es distinto: su fila o su clave se quedan fuera, como siempre. La diferencia es a propósito: una cabecera
X-User-Idque no llega podría leerse en tu backend como «sin filtro». - Lo mismo con Reenviar el token del usuario cuando no hay token (una identidad de prueba hecha solo de claims): la petición no sale.
Una instancia que usa $user o reenvía el token solo funciona con un usuario identificado:
- Solo se engancha a agentes con el usuario en
optionalorequired. A un agente enoffo a una inferencia, no: guardar eso da un error con la lista de tools, tanto al engancharla como al pasar el agente aoffo al añadir$usera una instancia que ya está enganchada en uno de esos sitios. - En un turno sin usuario la petición no sale: el modelo lee que el usuario tiene que iniciar sesión.
- En un agente en
optional, el modelo ni la ve en los turnos anónimos.
Respuesta
Lo que devuelve la API le llega al modelo tal cual: nada lo resume, y todo cuenta como tokens del turno. Para darle solo lo que necesita:
- Ruta JSON (JMESPath):
postalCode,results[0].name,items[*].price, o{cp: postalCode, municipio: muni}para quedarte con varios campos. Se acepta el$.inicial de JSONPath. Un texto se devuelve tal cual; lo demás, como JSON. - Expresión regular (sintaxis RE2: sin lookarounds ni referencias,
(?i)para ignorar mayúsculas): cada coincidencia en una línea, o su primer grupo entre paréntesis si lo tiene. Se evalúa en tiempo lineal, así que una expresión mal escrita no puede bloquear el servidor. - TOON: convierte el JSON a TOON, que en listas de registros ocupa la mitad. Solo se usa si sale más corto que el JSON compacto, y se aplica después del filtro.
- Tratar como no fiable: envuelve la respuesta en
<untrusted_document>y le dice al modelo que su contenido son datos, no instrucciones. Para APIs que devuelven texto de terceros.
También se configuran el tiempo máximo (1–120 s, cubre la petición entera), el máximo de caracteres (lo que pase se recorta con una nota) y los mensajes de error, que es lo que lee el modelo cuando algo falla. Se aplica el primero que encaje: el código exacto (404), el rango (4xx, 5xx), timeout o network (no se pudo conectar), y por último default. empty es para una respuesta sin datos: vacía, o en la que el filtro no encuentra nada. Admiten variables.
Sin mensaje propio, un 4xx enseña el principio del cuerpo de la respuesta (suele decir qué corregir) y el resto una frase genérica: lo que lee el modelo lo puede leer el visitante del widget, así que un error interno no se le enseña.
Ejemplo: el código postal de una dirección
Con el geocodificador de CartoCiudad:
| Nombre | codigo_postal |
| Descripción | Devuelve el código postal de una dirección de España. Úsala cuando pregunten por el código postal de una calle. |
| Parámetro | direccion (texto, obligatorio): «Calle, número y municipio, p. ej. Campo Volantín 22, Bilbao» |
| URL | https://www.cartociudad.es/geocoder/api/geocoder/find |
| Query | q = {{direccion}} |
| Filtro | Ruta JSON postalCode |
Mensaje empty | No existe ninguna dirección así: pide al usuario que la revise. |
Para «Campo Volantín 22, Bilbao» la API devuelve una veintena de campos y el modelo recibe solo 48007. Para una dirección que no existe, la API contesta 204 sin cuerpo, y el modelo recibe el mensaje empty.
Probar la tool
Probar tool ejecuta la instancia guardada con los argumentos que escribas, sin pasar por un modelo. Enseña lo que recibiría el modelo, el código HTTP y un bloque Depuración con la URL (los secretos enmascarados) y, cuando hay filtro o TOON, el principio de la respuesta original: es lo que hace falta ver para escribir la ruta JSON. Si hay cambios sin guardar, primero se guardan.
Una instancia que usa al usuario identificado necesita una Identidad de prueba: un JWT, con Verificar la firma contra el emisor que elijas o sin verificar, o unos claims en JSON. Sin ella no envía la petición y contesta lo mismo que en un turno anónimo, que nadie ha iniciado sesión.
Un agente que ya usa la instancia tarda hasta un minuto en ver los cambios de su configuración.