Modulo de Entrada HTTP¶
El modulo de Entrada HTTP proporciona un servidor webhook que permite a sistemas externos invocar agentes Symbiont a traves de peticiones HTTP. Este modulo habilita la integracion con servicios externos, webhooks y APIs exponiendo agentes a traves de endpoints HTTP.
Descripcion General¶
En esta rama, cada peticion HTTP de razonamiento se ejecuta de forma independiente
aunque su agente registrado ya este activo. El codigo fuente registrado y el nivel
de seguridad seleccionan un ejecutor de herramientas congelado antes de la
inferencia. Los limites de CPU, memoria y tiempo de ejecucion acotan esa
invocacion. Los workers gobernados tambien comparten la CPU, la memoria y el pool
de workers configurados del supervisor con los lanzamientos del planificador y de
la CLI que usan el mismo directorio de estado privado; consulta
presupuestos compartidos. Las respuestas correctas incluyen
audit con run_id, path y public_key. Los fallos del almacenamiento
obligatorio detienen cualquier efecto posterior, y las peticiones descartadas
conservan la propiedad de la limpieza. Consulta
auditoria de ejecuciones y la guia de la rama.
El modulo de Entrada HTTP consiste en:
- Servidor HTTP: Un servidor web basado en Axum que escucha peticiones HTTP entrantes
- Autenticacion: Soporte para autenticacion basada en Bearer token y JWT
- Enrutamiento de Peticiones: Reglas de enrutamiento flexibles para dirigir peticiones a agentes especificos
- Control de Respuestas: Formato de respuesta configurable y codigos de estado
- Caracteristicas de Seguridad: Soporte CORS, limites de tamano de peticion y registro de auditoria
- Gestion de Concurrencia: Limitacion de tasa de peticiones integrada y control de concurrencia
- Invocacion LLM con ToolClad: Cada peticion invoca al agente registrado de forma independiente a traves del proveedor LLM configurado y del bucle gobernado de llamada a herramientas ORGA, incluso cuando hay otra invocacion activa
El modulo se compila condicionalmente con el flag de caracteristica http-input y se integra sin problemas con el runtime de agentes Symbiont.
Configuracion¶
El modulo de Entrada HTTP se configura usando la estructura HttpInputConfig:
Configuracion Basica¶
use symbiont_runtime::http_input::HttpInputConfig;
use symbiont_runtime::types::AgentId;
let config = HttpInputConfig {
bind_address: "127.0.0.1".to_string(),
port: 8081,
path: "/webhook".to_string(),
agent: AgentId::from_str("webhook_handler")?,
// ... other fields
..Default::default()
};
Campos de Configuracion¶
| Campo | Tipo | Por Defecto | Descripcion |
|---|---|---|---|
bind_address |
String |
"127.0.0.1" |
Direccion IP para vincular el servidor HTTP |
port |
u16 |
8081 |
Numero de puerto en el que escuchar |
path |
String |
"/webhook" |
Endpoint de ruta HTTP |
agent |
AgentId |
Nuevo ID | Agente por defecto a invocar para peticiones |
auth_header |
Option<String> |
None |
Bearer token para autenticacion |
jwt_public_key_path |
Option<String> |
None |
Ruta al archivo de clave publica JWT |
max_body_bytes |
usize |
65536 |
Tamano maximo del cuerpo de peticion (64 KB) |
concurrency |
usize |
10 |
Maximo numero de peticiones concurrentes |
routing_rules |
Option<Vec<AgentRoutingRule>> |
None |
Reglas de enrutamiento de peticiones |
response_control |
Option<ResponseControlConfig> |
None |
Configuracion de formato de respuesta |
forward_headers |
Vec<String> |
[] |
Cabeceras a reenviar a los agentes |
cors_origins |
Vec<String> |
[] |
Origenes CORS permitidos (vacio = CORS deshabilitado) |
audit_enabled |
bool |
true |
Habilitar registro de auditoria de peticiones |
Reglas de Enrutamiento de Agentes¶
Enrutar peticiones a diferentes agentes basandose en caracteristicas de la peticion:
use symbiont_runtime::http_input::{AgentRoutingRule, RouteMatch};
let routing_rules = vec![
AgentRoutingRule {
condition: RouteMatch::PathPrefix("/api/github".to_string()),
agent: AgentId::from_str("github_handler")?,
},
AgentRoutingRule {
condition: RouteMatch::HeaderEquals("X-Source".to_string(), "slack".to_string()),
agent: AgentId::from_str("slack_handler")?,
},
AgentRoutingRule {
condition: RouteMatch::JsonFieldEquals("source".to_string(), "twilio".to_string()),
agent: AgentId::from_str("sms_handler")?,
},
];
Control de Respuestas¶
Personalizar respuestas HTTP con ResponseControlConfig:
use symbiont_runtime::http_input::ResponseControlConfig;
let response_control = ResponseControlConfig {
default_status: 200,
agent_output_to_json: true,
error_status: 500,
echo_input_on_error: false,
};
Caracteristicas de Seguridad¶
Autenticacion¶
El modulo de Entrada HTTP soporta multiples metodos de autenticacion:
Autenticacion con Bearer Token¶
Configurar un bearer token estatico:
let config = HttpInputConfig {
auth_header: Some("Bearer your-secret-token".to_string()),
..Default::default()
};
Integracion con Almacen de Secretos¶
Usar referencias de secretos para seguridad mejorada:
let config = HttpInputConfig {
auth_header: Some("vault://webhook/auth_token".to_string()),
..Default::default()
};
Autenticacion JWT (EdDSA)¶
Configurar autenticacion basada en JWT con claves publicas Ed25519:
let config = HttpInputConfig {
jwt_public_key_path: Some("/path/to/jwt/ed25519-public.pem".to_string()),
jwt_issuer: Some("https://identity.example.com".to_string()),
jwt_audience: Some("symbiont-http-input".to_string()),
..Default::default()
};
Los JWT deben contener exp, sub, iss y aud. El emisor debe coincidir con jwt_issuer y la audiencia debe incluir jwt_audience. Ambos valores de configuración son obligatorios cuando se utiliza autenticación JWT. El sujeto no puede estar vacío ni superar 512 bytes. Se permiten cinco segundos de desfase para la expiración. La renovación con el mismo sujeto, emisor y clave conserva la identidad del llamante.
Migración: configure el emisor y la audiencia esperados y emita tokens para este servicio. Los tokens para otros servicios se rechazan aunque usen la misma clave. La firma del webhook sigue siendo una comprobación adicional.
Endpoint de Salud¶
El modulo de Entrada HTTP no expone su propio endpoint /health. Las verificaciones de salud estan disponibles a traves de la API HTTP principal en /api/v1/health cuando se ejecuta symbi up, que inicia el runtime completo incluyendo el servidor de API:
# Health check via the main API server (default port 8080)
curl http://127.0.0.1:8080/api/v1/health
# => {"status": "ok"}
Si necesita sondas de salud para el servidor de Entrada HTTP especificamente, dirija su balanceador de carga al endpoint de salud de la API principal.
Controles de Seguridad¶
- Solo Loopback por Defecto:
bind_addresspor defecto es127.0.0.1— el servidor solo acepta conexiones locales a menos que se configure explicitamente de otra manera - CORS Deshabilitado por Defecto:
cors_originspor defecto es una lista vacia, lo que significa que CORS esta deshabilitado; agregue origenes especificos para habilitar el acceso entre origenes. Un literal"*"encors_originses rechazado al arranque — el servidor de Entrada HTTP se negara a iniciar con un origen comodin. (Anadido en la auditoria posterior a v1.13.0; consultaSECURITY_AUDIT.mdM1.) - Limites de Tamano de Peticion: El tamano maximo configurable del cuerpo previene el agotamiento de recursos
- Limites de Concurrencia: Semaforo integrado controla el procesamiento de peticiones concurrentes
- Registro de Auditoria: Registro estructurado de todas las peticiones entrantes cuando esta habilitado
- Resolucion de Secretos: Integracion con Vault y almacenes de secretos basados en archivos
Ejemplo de Uso¶
Iniciar el Servidor de Entrada HTTP¶
use symbiont_runtime::http_input::{HttpInputConfig, start_http_input};
use symbiont_runtime::secrets::SecretsConfig;
use std::sync::Arc;
// Configurar el servidor de entrada HTTP
let config = HttpInputConfig {
bind_address: "127.0.0.1".to_string(),
port: 8081,
path: "/webhook".to_string(),
agent: AgentId::from_str("webhook_handler")?,
auth_header: Some("Bearer secret-token".to_string()),
audit_enabled: true,
cors_origins: vec!["https://example.com".to_string()],
..Default::default()
};
// Opcional: Configurar secretos
let secrets_config = SecretsConfig::default();
// Iniciar el servidor
start_http_input(config, Some(runtime), Some(secrets_config)).await?;
Ejemplo de Definicion de Agente¶
Crear un agente manejador de webhook en webhook_handler.symbi:
agent webhook_handler(body: JSON) -> Maybe<Alert> {
capabilities = ["http_input", "event_processing", "alerting"]
memory = "ephemeral"
privacy = "strict"
policy webhook_guard {
allow: use("llm") if body.source == "slack" || body.user.ends_with("@company.com")
allow: publish("topic://alerts") if body.type == "security_alert"
audit: all_operations
}
with context = {} {
if body.type == "security_alert" {
alert = {
"summary": body.message,
"source": body.source,
"level": body.severity,
"user": body.user
}
publish("topic://alerts", alert)
return alert
}
return None
}
}
Ejemplo de Peticion HTTP¶
Enviar una peticion webhook para activar el agente:
curl -X POST http://localhost:8081/webhook \
-H "Content-Type: application/json" \
-H "Authorization: Bearer secret-token" \
-H "Idempotency-Key: 72d6a833-b825-4b22-b50c-206337d77f7c" \
-d '{
"type": "security_alert",
"message": "Suspicious login detected",
"source": "slack",
"severity": "high",
"user": "admin@company.com"
}'
Elige y conserva un UUID nuevo para cada tarea prevista. Cada envio HTTP requiere
exactamente una cabecera Idempotency-Key; reintenta con el mismo ID, la misma URI
y la misma carga util JSON. Reutilizar el ID de este ejemplo para un trabajo
distinto se rechazara. Los emisores de webhooks deben conservar un UUID estable por
entrega, o usar un adaptador que asigne su identidad de entrega a un UUID estable
antes del envio. El servidor no infiere la identidad a partir de la salida del
modelo ni genera un sustituto cuando falta la cabecera.
Estados de reintento¶
Los IDs ocupan un unico dominio HTTP por proyecto canonico. La reclamacion duradera
vincula al llamante verificado, la URI de la peticion, la entrada JSON y el codigo
fuente y los ajustes de destino en los que se confia. Los IDs de agente registrados
pueden cambiar al reiniciar sin que eso cree una peticion distinta. Un servidor SDK
autonomo debe conservar su AgentId configurado entre reinicios. Cambiar el codigo
fuente, el destino, el llamante o la carga util bajo un ID existente rechaza el
trabajo; no se devuelve a otro llamante ningun contenido de la cache ni referencia
de auditoria.
| Estado HTTP | status del cuerpo |
Significado |
|---|---|---|
| 200 por defecto | completed |
El resultado original se persistio; replayed identifica una respuesta guardada. |
| 422 | failed |
Se persistio un fallo terminal con la evidencia completa registrada; los reintentos lo devuelven. |
| 409 | in_progress |
Otro propietario tiene el ID; esta peticion no inicia ningun trabajo. |
| 409 | unresolved |
La ejecucion original necesita reconciliacion; incluye su referencia de auditoria cuando esta disponible. |
| 409 | reconciled |
Devuelve una valoracion de operador firmada por separado; el ID original no puede volver a ejecutarse. |
| 409 | conflict |
El ID esta vinculado a otro llamante o a otra peticion. |
| 400 | invalid_invocation_id |
Cabecera UUID ausente, repetida o invalida. |
| 503 | unavailable |
El almacenamiento de invocaciones requerido no pudo autorizar la ejecucion. |
Las respuestas de estado de invocacion incluyen las cabeceras Idempotency-Key,
Idempotency-Replayed y Cache-Control: no-store. El formato de exito configurado
sigue aplicandose a los resultados completados; no puede convertir desenlaces sin
resolver o en conflicto en respuestas correctas. Los origenes CORS configurados
permiten y exponen las cabeceras de invocacion.
Un propietario retenido mantiene la reclamacion durante la preparacion, la ejecucion, la limpieza y el guardado del resultado. La desconexion del cliente cancela el trabajo de ese propietario, pero no libera el ID para volver a ejecutarlo. La perdida del proceso antes de persistir el resultado deja una reclamacion sin resolver. Los resultados guardados se verifican contra su auditoria firmada original antes de devolverse; la recuperacion no vuelve a ejecutar el proveedor ni el ejecutor.
Las credenciales compartidas estaticas representan a un solo llamante. Un llamante JWT queda vinculado a la clave configurada, al emisor firmado y al sujeto; los campos de expiracion y renovacion no lo cambian. Rotar las credenciales o el material de clave hace que un ID existente entre en conflicto en lugar de crear silenciosamente una segunda tarea. Las reclamaciones abarcan todo el proyecto a traves de los listeners HTTP, asi que usa UUID aleatorios nuevos y conserva el almacen junto con su evidencia de auditoria. Consulta identidades de invocacion persistentes para conocer los limites del almacenamiento.
Respuesta Esperada¶
Cada peticion de razonamiento devuelve su propio resultado, incluso cuando hay otra
invocacion del mismo agente activa. La antigua respuesta de entrega con
execution_started / message_id ya no se usa en esta ruta. Las respuestas
correctas incluyen la referencia publica de auditoria de la ejecucion,
invocation_id, replayed, total_usage y la instantanea compartida de
budget. Valores ilustrativos:
{
"status": "completed",
"agent_id": "11111111-1111-4111-8111-111111111111",
"response": "Task complete.",
"tool_runs": [],
"termination_reason": "Completed",
"iterations": 1,
"audit": {
"run_id": "22222222-2222-4222-8222-222222222222",
"path": "/srv/control/.symbiont/governed/11111111-1111-4111-8111-111111111111.22222222-2222-4222-8222-222222222222.jsonl",
"public_key": "<hex-encoded-public-key>"
},
"model": "<configured-model>",
"provider": "<configured-provider>",
"latency_ms": 4821,
"timestamp": "2024-01-15T10:30:00Z"
}
tool_runs resume las observaciones de herramientas correlacionadas, incluidas las
denegaciones y los fallos de validacion. Su presencia no demuestra que un efecto se
haya ejecutado, y status: completed puede acompanar a una respuesta de rechazo por
politica. Usa los argumentos normalizados exactos, la decision y los registros de
efecto del diario protegido para verificarlo. Los fallos de auditoria o de limpieza
obligatorias devuelven un error, aunque ya se hubiera producido un efecto previo. El
valor de audit.path es una ruta en el host del runtime, no una URL de descarga.
Invocacion LLM con Herramientas ToolClad¶
Cada peticion HTTP de razonamiento inicia una invocacion gobernada independiente, incluso cuando el agente registrado ya tiene otra invocacion activa.
Como funciona¶
- Con un runtime adjunto, se resuelve el agente desde el registro de confianza. Se congelan su codigo fuente, su sandbox y sus ajustes de recursos seleccionados; se rechazan los agentes inexistentes, las selecciones ambiguas y los niveles de seguridad que no coinciden, antes de la inferencia. Un servidor SDK autonomo usa el agente y el ejecutor genericos que tenga configurados de forma explicita.
- El prompt de sistema se construye unicamente a partir del codigo fuente del
agente seleccionado. El
system_promptopcional proporcionado por el llamante sigue teniendo limite de longitud y quedando registrado; no aporta autoridad de politica, de principal ni de sandbox. El mensaje de usuario se construye a partir de la carga util de la peticion. - Se descubren las herramientas ToolClad del proyecto congelado y se abre un diario privado firmado obligatorio. El bucle ORGA permite hasta 15 iteraciones. Los plazos registrados y los seleccionados por el agente endurecen los limites del bucle y de las herramientas; el limite por herramienta es de 120 segundos por defecto.
- Las llamadas propuestas se preparan y normalizan antes de Cedar. Las aprobaciones exactas obligatorias, la auditoria requerida y la autorizacion de un solo uso preceden a los efectos. Los IDs de llamada duplicados o vacios se rechazan; los resultados deben correlacionarse con las llamadas realmente preparadas.
- Se espera la limpieza del worker y el registro terminal en el diario. Las
respuestas correctas incluyen la respuesta final, los desenlaces de las
herramientas, los metadatos de proveedor y modelo, y la referencia
audit. La cancelacion conserva la propiedad de la limpieza; los errores de almacenamiento obligatorio o de limpieza no pueden producir en silencio un resultado correcto.
Consulta llamadas preparadas y auditoria de ejecuciones. Los limites de recursos por invocacion no establecen una admision agregada de peticiones.
Deteccion automatica de proveedor¶
El cliente LLM se inicializa a partir de variables de entorno al iniciar el servidor. Gana el primer proveedor cuya clave API este establecida, en este orden:
| Variable de entorno | Proveedor | Sobrescritura de modelo | Sobrescritura de URL base |
|---|---|---|---|
OPENROUTER_API_KEY |
OpenRouter | OPENROUTER_MODEL (por defecto: anthropic/claude-sonnet-4) |
OPENROUTER_BASE_URL |
OPENAI_API_KEY |
OpenAI | CHAT_MODEL (por defecto: gpt-4o) |
OPENAI_BASE_URL |
ANTHROPIC_API_KEY |
Anthropic | ANTHROPIC_MODEL (por defecto: claude-sonnet-4-20250514) |
ANTHROPIC_BASE_URL |
Sin un proveedor de inferencia configurado, las peticiones de razonamiento devuelven un error. Los endpoints locales configurados por el operador siguen estando soportados.
Campos de entrada¶
El cuerpo JSON del webhook se interpreta de la siguiente manera cuando se toma la ruta LLM:
promptomessage— se usa como el mensaje de usuario. Si no esta presente ninguno, toda la carga util se imprime de forma legible y se pasa como la descripcion de la tarea.system_prompt— prompt de sistema opcional proporcionado por el llamante que se agrega al prompt de sistema derivado del DSL. Limitado a 4096 bytes y registrado. Tratelo como una superficie de inyeccion de prompts: siempre aplique autenticacion cuando exponga este endpoint a llamantes no confiables.
Formato normalizado de llamada a herramientas¶
El cliente LLM normaliza la llamada a funciones de OpenAI/OpenRouter a la misma forma de bloque de contenido usada por la API de Mensajes de Anthropic. Independientemente del proveedor, cada bloque de contenido de respuesta es {"type": "text", "text": "..."} o {"type": "tool_use", "id": "...", "name": "...", "input": {...}}, y stop_reason es "end_turn" o "tool_use".
Patrones de Integracion¶
Endpoints de Webhook¶
Configurar diferentes agentes para diferentes fuentes de webhook:
let routing_rules = vec![
AgentRoutingRule {
condition: RouteMatch::HeaderEquals("X-GitHub-Event".to_string(), "push".to_string()),
agent: AgentId::from_str("github_push_handler")?,
},
AgentRoutingRule {
condition: RouteMatch::JsonFieldEquals("source".to_string(), "stripe".to_string()),
agent: AgentId::from_str("payment_processor")?,
},
];
Integracion con API Gateway¶
Usar como servicio backend detras de un API gateway:
let config = HttpInputConfig {
bind_address: "0.0.0.0".to_string(),
port: 8081,
path: "/api/webhook".to_string(),
cors_origins: vec!["https://example.com".to_string()],
forward_headers: vec![
"X-Forwarded-For".to_string(),
"X-Request-ID".to_string(),
],
..Default::default()
};
Integracion de Verificacion de Salud¶
El modulo de Entrada HTTP no incluye un endpoint de salud dedicado. Use el endpoint de salud de la API principal (/api/v1/health) para la integracion con balanceadores de carga y monitoreo. Consulte la seccion Endpoint de Salud para mas detalles.
Manejo de Errores¶
El modulo de Entrada HTTP proporciona manejo de errores integral:
- Errores de Autenticacion: Devuelve
401 Unauthorizedpara tokens invalidos - Limitacion de Tasa: Devuelve
429 Too Many Requestscuando se exceden los limites de concurrencia - Errores de Carga Util: Devuelve
400 Bad Requestpara JSON mal formado - Desenlaces de Invocacion: Devuelve los estados de reintento explicitos descritos arriba; el trabajo sin resolver nunca se reporta como completado.
- Errores del Servidor: Los fallos de runtime sin clasificar devuelven un estado configurable con un mensaje publico generico.
Monitoreo y Observabilidad¶
Registro de Auditoria¶
Cuando audit_enabled es true, el modulo registra informacion estructurada sobre todas las peticiones:
INFO HTTP Input: Received request with 5 headers
INFO Agent webhook_handler is running, dispatching via communication bus
INFO Runtime execution dispatched for agent webhook_handler: message_id=… latency=3ms
Cuando se usa la ruta de invocacion LLM, lineas adicionales trazan el bucle ORGA:
INFO Agent webhook_handler is not running, using LLM invocation path
INFO Invoking LLM for agent webhook_handler: provider=Anthropic model=… tools=4 …
INFO ORGA ACT: executing tool 'nmap_scan' (id=…) for agent webhook_handler
INFO Tool 'nmap_scan' executed successfully
INFO ORGA loop iteration 1 for agent webhook_handler: executed 1 tool(s), continuing
INFO LLM invocation completed for agent webhook_handler: latency=4821ms tool_runs=1 response_len=…
Integracion de Metricas¶
El modulo se integra con el sistema de metricas del runtime Symbiont para proporcionar:
- Conteo y tasa de peticiones
- Distribuciones de tiempo de respuesta
- Tasas de error por tipo
- Conteos de conexiones activas
- Utilizacion de concurrencia
Mejores Practicas¶
- Seguridad: Siempre usar autenticacion en entornos de produccion
- Limitacion de Tasa: Configurar limites de concurrencia apropiados basados en su infraestructura
- Monitoreo: Habilitar registro de auditoria e integrar con su stack de monitoreo
- Manejo de Errores: Configurar respuestas de error apropiadas para su caso de uso
- Diseno de Agentes: Disenar agentes para manejar formatos de entrada especificos de webhook
- Limites de Recursos: Establecer limites razonables de tamano de cuerpo para prevenir agotamiento de recursos
Ver Tambien¶
- Guia de Inicio
- Guia DSL
- Referencia de API
- Bucle de Razonamiento (ORGA)
- Contratos de Herramientas ToolClad
- Documentacion del Runtime de Agentes
Una invocacion retenida con una resolucion del operador devuelve HTTP 409 y
status: "reconciled", su referencia de auditoria original y un recibo de
resolution firmado por separado. No devuelve un resultado correcto fabricado ni
vuelve a ejecutarse. Consulta la
reconciliacion por el operador.