Tools permiten a un agente ejecutar acciones externas o acceder a
recursos asociados. Esta sección documenta el flujo básico: listar →
conectar → ejecutar.
Requiere permisos tools:read para listar y
tools:execute para ejecutar. También requiere el header
X-Workspace-Id.
import { createClient } from '@getsupervisor/agents-studio-sdk';
const client = createClient({
baseUrl: process.env.API_BASE_URL!,
workspaceId: process.env.WORKSPACE_ID!,
apiKey: process.env.API_KEY!,
});
const page1 = await client.tools.list({
page: 1,
limit: 20,
// agentType: 'chat',
});
console.log(page1.data.map((t) => t.id));
curl -sS "$API_BASE_URL/v1/tools?page=1&limit=20" \
-H "X-API-Key: $API_KEY" \
-H "X-Workspace-Id: $WORKSPACE_ID"
Ejecuta una acción específica de una tool.
import { createClient } from '@getsupervisor/agents-studio-sdk';
const client = createClient({
baseUrl: process.env.API_BASE_URL!,
workspaceId: process.env.WORKSPACE_ID!,
apiKey: process.env.API_KEY!,
});
const result = await client.tools.execute(
'geocoding',
{
agentId: '00000000-0000-4000-8000-000000000301',
action: 'geocode',
args: { address: 'Av. Reforma, CDMX' },
},
{
// Opcional: para evitar duplicados en reintentos
idempotencyKey: 'idemp_example_001',
},
);
console.log(result.status, result.toolExecutionId);
curl -sS -X POST "$API_BASE_URL/v1/tools/geocoding/execute" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: idemp_example_001" \
-H "X-API-Key: $API_KEY" \
-H "X-Workspace-Id: $WORKSPACE_ID" \
-d '{"agentId":"00000000-0000-4000-8000-000000000301","action":"geocode","args":{"address":"Av. Reforma, CDMX"}}'
Las conexiones representan un vínculo persistente entre un agente y una tool.
Listar conexiones
import { createClient } from '@getsupervisor/agents-studio-sdk';
const client = createClient({
baseUrl: process.env.API_BASE_URL!,
workspaceId: process.env.WORKSPACE_ID!,
apiKey: process.env.API_KEY!,
});
const connections = await client.tools.connections.list({
page: 1,
limit: 20,
// filter: 'and(eq(status,"connected"))',
});
console.log(connections.data.length);
curl -sS "$API_BASE_URL/v1/tools/connections?page=1&limit=20" \
-H "X-API-Key: $API_KEY" \
-H "X-Workspace-Id: $WORKSPACE_ID"
Crear conexión (por body)
import { createClient } from '@getsupervisor/agents-studio-sdk';
const client = createClient({
baseUrl: process.env.API_BASE_URL!,
workspaceId: process.env.WORKSPACE_ID!,
apiKey: process.env.API_KEY!,
});
const connection = await client.tools.connections.create(
{
toolId: 'geocoding',
agentId: '00000000-0000-4000-8000-000000000301',
connectionKey: 'default',
descriptionUsage:
'Usa esta conexión cuando el usuario pida geocodificar una dirección.',
usageExample:
'Usuario: "¿Dónde queda Av. Reforma, CDMX?"\nTool: action=geocode args={"address":"Av. Reforma, CDMX"}',
// auth: { type: 'api_key', data: { key: '...' } },
},
{ idempotencyKey: 'idemp_connect_001' },
);
console.log(connection.status, connection.toolAgentConnectionId);
console.log(connection.descriptionUsage);
console.log(connection.usageExample);
curl -sS -X POST "$API_BASE_URL/v1/tools/connections" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: idemp_connect_001" \
-H "X-API-Key: $API_KEY" \
-H "X-Workspace-Id: $WORKSPACE_ID" \
-d '{"toolId":"geocoding","agentId":"00000000-0000-4000-8000-000000000301","connectionKey":"default","descriptionUsage":"Usa esta conexión cuando el usuario pida geocodificar una dirección.","usageExample":"Usuario: \"¿Dónde queda Av. Reforma, CDMX?\"\nTool: action=geocode args={\"address\":\"Av. Reforma, CDMX\"}"}'
Ejecutar por conexión
import { createClient } from '@getsupervisor/agents-studio-sdk';
const client = createClient({
baseUrl: process.env.API_BASE_URL!,
workspaceId: process.env.WORKSPACE_ID!,
apiKey: process.env.API_KEY!,
});
const result = await client.tools.connections.execute(
'00000000-0000-4000-8000-000000000901',
{
action: 'geocode',
args: { address: 'Av. Reforma, CDMX' },
},
{ idempotencyKey: 'idemp_exec_001' },
);
console.log(result.status, result.toolExecutionId);
curl -sS -X POST "$API_BASE_URL/v1/tools/connections/00000000-0000-4000-8000-000000000901/execute" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: idemp_exec_001" \
-H "X-API-Key: $API_KEY" \
-H "X-Workspace-Id: $WORKSPACE_ID" \
-d '{"action":"geocode","args":{"address":"Av. Reforma, CDMX"}}'
custom.http es una tool base que te permite “construir” acciones HTTP sin crear una tool nueva en el catálogo.
La idea es:
- Creas una conexión (agent ↔ custom.http) y ahí dejas configurado:
metadata.baseUrl
metadata.actions (acciones disponibles y cómo se resuelven)
metadata.defaultHeaders (headers fijos)
auth (secretos que se guardan como ToolSecret)
- En runtime ejecutas por
toolAgentConnectionId con:
action (ej. campaigns.list)
args._query / args._headers / args._body para overrides.
Cómo mapear un curl a custom.http
Ejemplo de curl original:
curl 'https://{baseUrl}/v1/campaigns?page=1&limit=100&filter=empty%28%29' \
-H 'x-api-key: ****' \
-H 'x-workspace-id: 70dc0f15-c0ab-430d-93cc-c161282880be'
Mapeo recomendado:
- URL
metadata.baseUrl = https://{baseUrl}
metadata.actions["campaigns.list"].path = /v1/campaigns
metadata.actions["campaigns.list"].method = GET
- Query params
- Se pasan en ejecución como
args._query.
- Headers
x-workspace-id puede ir en metadata.defaultHeaders.
x-api-key debe ir en auth.data.apiKey (se guarda como secret) para no exponerlo en metadata.
1) Crear conexión custom.http
Requisitos:
- Necesitas el
toolId de custom.http (si no lo tienes, búscalo con GET /v1/tools filtrando por identifier=="custom.http").
- Necesitas el
agentId del agente.
curl -sS -X POST "$API_BASE_URL/v1/tools/connections" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-H "X-Workspace-Id: $WORKSPACE_ID" \
-d '{
"toolId": "a3d9b0d6-2b9b-4d32-8efc-94e5f0a4d4e2",
"agentId": "722110ed-c98a-4a2c-a262-38ecfb005356",
"connectionKey": "campaigns",
"descriptionUsage": "Usa esta conexión cuando el usuario pregunte qué campañas existen o pida listar campañas.",
"usageExample": "Usuario: ¿qué campañas existen?\nTool: action=campaigns.list args={_query:{page:'1',limit:'100',filter:'empty()'}}",
"metadata": {
"baseUrl": "https://{baseUrl}",
"defaultHeaders": {
"x-workspace-id": "70dc0f15-c0ab-430d-93cc-c161282880be"
},
"actions": {
"campaigns.list": {
"path": "/v1/campaigns",
"method": "GET"
}
}
},
"auth": {
"type": "custom",
"data": {
"apiKey": "****",
"auth": {
"kind": "api_key",
"apiKeyKey": "apiKey",
"headerName": "x-api-key",
"tokenPrefix": ""
}
}
}
}'
Notas:
auth.type=custom (o api_key) hace que el backend cree un ToolSecret asociado a la conexión y guarde ahí auth.data.
- El bloque
auth.data.auth es importante: define cómo convertir el secret en headers.
descriptionUsage y usageExample son opcionales: sirven como guía para que el motor (voz/LLM) sepa cuándo conviene ejecutar esta conexión.
2) Ejecutar la acción (equivalente al curl)
En la respuesta de create connection obtendrás toolAgentConnectionId. Usa ese id para ejecutar.
curl -sS -X POST "$API_BASE_URL/v1/tools/connections/$TOOL_AGENT_CONNECTION_ID/execute" \
-H "Content-Type: application/json" \
-H "X-API-Key: $API_KEY" \
-H "X-Workspace-Id: $WORKSPACE_ID" \
-d '{
"action": "campaigns.list",
"args": {
"_query": {
"page": "1",
"limit": "100",
"filter": "empty()"
}
}
}'
Overriding rápido
- Cambiar query:
args._query.
- Forzar headers extra puntuales:
args._headers.
- Enviar body:
- Si
args._body existe, ese objeto se manda como body.
- Si
args._body no existe, todo lo que venga en args (menos _query/_headers/_body) se toma como body.
Troubleshooting
Error: “Missing bearer token in secret data (expected “accessToken”) for tool auth type “custom""
- Causa: para
provider=custom + auth_type=custom, el catálogo de auth por defecto usa bearer (Authorization: Bearer <accessToken>).
- Fix: en
auth.data incluye auth: { kind: "api_key", apiKeyKey: "apiKey", headerName: "x-api-key" } y guarda el valor en auth.data.apiKey.
No quiero duplicar secrets
- El secret se guarda por conexión (
toolAgentConnectionId).
- Si vuelves a crear la misma conexión (mismo tool + workspace + agent + connectionKey) sin
Idempotency-Key, fallará por “connection exists”.
- Para “cambiar” configuración hoy, crea una nueva conexión con otro
connectionKey.