Análisis profundo · 10 min de lectura
Thorondor evolucionado
Fëanor's Code
8 de agosto de 2026

Durante las últimas semanas hemos convertido Thorondor en algo bastante más útil para un agente.
Antes, Thorondor recibía una pregunta, buscaba páginas, las procesaba y devolvía pasajes relevantes con sus fuentes. Eso sigue siendo el núcleo del sistema, pero ahora el agente puede trabajar con la web de una forma mucho más precisa.
Thorondor puede consultar una URL concreta, seguir sus redirecciones, identificar exactamente qué documento ha recibido y devolver enlaces, tablas, metadatos estructurados y fragmentos verificables de la fuente original.
También puede detectar si una página es nueva, sigue igual, ha cambiado o ha desaparecido. Pero la parte importante es que no se limita a comparar páginas enteras. El agente puede señalar un objetivo concreto: un botón, un precio, un estado o un texto dentro de una sección.
Por ejemplo:
“Vigila esta página de producto y avísame cuando pase de ‘Agotado’ a ‘Disponible’.”
Los anuncios, contadores y otros cambios irrelevantes pueden modificar la página completa, pero no activarán ese aviso si el objetivo específico no ha cambiado. Thorondor distingue entre “la página es diferente” y “ha ocurrido exactamente la transición que me interesa”.
Para páginas más complejas añadimos perfiles estructurados para enlaces, tablas y JSON-LD, además de extracción limitada mediante esquemas JSON. Cada dato extraído conserva la identidad del documento del que procede y una referencia verificable a su contenido. Si el modelo devuelve un dato que no puede demostrarse en el texto original, Thorondor lo descarta.
Esto es especialmente importante porque una página web no es una fuente confiable por defecto. Puede contener instrucciones maliciosas, datos incompletos o contenido diseñado para confundir a un agente. Todo lo que procede de la web se trata como información externa y no confiable. La extracción estructurada valida los resultados antes de presentarlos como evidencia.
También incorporamos mapas de sitios, lectura de robots.txt, rastreo limitado por dominio y ruta, límites de tiempo, límites de memoria y cancelación cooperativa. Para operaciones más largas existe ahora un modo de trabajos duraderos con paginación, reanudación tras reinicio, cancelación e idempotencia.
La arquitectura mantiene una decisión importante: la búsqueda normal sigue siendo viva y no persistente. La caché de páginas solo se activa explícitamente para URLs conocidas. Del mismo modo, Thorondor no programa tareas ni envía notificaciones por sí mismo. Su función es proporcionar observaciones precisas; Tengwar o el agente que lo utiliza decide cuándo consultar, qué transición espera y qué acción ejecutar después.
El resultado es un Thorondor más útil para agentes autónomos: menos respuestas basadas en páginas enteras, más evidencia direccionable, más control sobre los cambios relevantes y menos posibilidades de que una fuente web ruidosa o maliciosa se convierta accidentalmente en una decisión.
Thorondor ya no solo busca páginas. Ahora permite descubrir, inspeccionar, comparar y vigilar información concreta de la web con evidencia verificable.
Durante las últimas fases hemos convertido Thorondor en una capa de inteligencia web diseñada específicamente para agentes.
Un agente puede buscar información actualizada, consultar una URL concreta, descubrir las páginas de un sitio, rastrear una sección limitada de una web o pedir datos estructurados como enlaces, tablas y metadatos.
La diferencia fundamental es que Thorondor no devuelve únicamente texto generado. Devuelve información acompañada de su procedencia: URL final, documento, fragmento exacto, posición dentro del documento y estado de confianza.
Una visión general
flowchart LR
A[Agente] --> M[MCP de Thorondor]
M --> S[web_search]
M --> F[web_fetch]
M --> MP[web_map]
M --> C[web_crawl]
S --> SX[SearXNG]
SX --> W[Web pública]
S --> CR[Crawl4AI]
CR --> E[Contenido limpio y citado]
F --> CR
MP --> R[Robots y sitemaps]
MP --> L[Enlaces y políticas de alcance]
C --> R
C --> CR
E --> V[Identidad documental y evidencia]
F --> V
C --> VLas cuatro herramientas son:
1. web_search: buscar información actual
Esta es la herramienta que usaría un agente cuando todavía no sabe exactamente qué URL contiene la respuesta.
Request:
{
"query": "Python official documentation",
"search_profile": "quick",
"decompose": false,
"max_urls": 2,
"max_passages": 2,
"token_budget": 500,
"include_raw_markdown": false
}Response:
{
"query": "Python official documentation",
"passages": [
{
"citation_id": 1,
"document_id": "fb3e28edef8719c102...",
"evidence_id": "4027d2eff4788ad28...",
"start_index": 0,
"end_index": 4620,
"section_heading": null,
"text": "Python is a programming language that lets you work more quickly...",
"score": 0.89,
"provenance": "external_web",
"trust": "untrusted",
"verbatim": true
}
],
"citations": [
{
"id": 1,
"url": "https://www.python.org/",
"title": "Welcome to Python.org",
"document_id": "fb3e28edef8719c102...",
"evidence_spans": [
{
"start_index": 0,
"end_index": 4620,
"evidence_id": "4027d2eff4788ad28...",
"verbatim": true
}
]
}
],
"stats": {
"discovery_status": "degraded",
"urls_discovered": 10,
"urls_selected": 2,
"urls_crawled_ok": 1,
"reranked": false,
"tokens_returned": 500
},
"schema_version": "thorondor.search.v1"
}Lo importante no es solo que aparezca https://www.python.org/, Thorondor también indica:
Qué documento produjo el dato.
Qué fragmento exacto se utilizó.
Dónde empieza y termina ese fragmento.
Si el pasaje es realmente una porción literal del documento.
Si la búsqueda funcionó completamente o se ejecutó degradada.
Esto permite que el agente responda con una fuente concreta y pueda verificar el pasaje original.
2. web_fetch: consultar una URL conocida
Cuando el agente ya conoce la página, no necesita realizar una búsqueda. Puede pedir directamente:
Request:
{
"urls": ["https://example.com"],
"structured_formats": ["links"]
}Response:
{
"schema_version": "thorondor.fetch.v1",
"stats": {
"requested": 1,
"succeeded": 1,
"failed": 0,
"cache_bypassed": 1
},
"results": [
{
"requested_url": "https://example.com",
"final_url": "https://example.com/",
"outcome": "content",
"status_code": 200,
"content_type": "text/html",
"title": "Example Domain",
"markdown": "This domain is for use in documentation examples...",
"cache": {
"state": "bypass",
"reason": "structured_source_required"
},
"links": {
"internal": [],
"external": [
{
"href": "https://iana.org/domains/example",
"text": "Learn more",
"base_domain": "iana.org"
}
]
},
"structured": [
{
"format": "links",
"status": "ok",
"links": [
{
"url": "https://iana.org/domains/example",
"text": "Learn more",
"trust": "untrusted",
"source": {
"document_id": "1bf80e41d06818d706...",
"start_index": 477,
"end_index": 534,
"final_url": "https://example.com/"
}
}
]
}
]
}
]
}Aquí aparecen dos niveles de información:
El resultado normal de la página: Markdown, título, URL final, estado HTTP y enlaces.
El perfil estructurado: una lista de enlaces con la posición exacta donde cada enlace fue encontrado.
Esto es útil cuando el agente no quiere interpretar toda la página, sino responder preguntas como:
¿Qué enlaces aparecen en esta página?
¿Qué páginas de documentación enlaza este artículo?
¿Cuál es el enlace de descarga?
¿Qué precio, botón o estado aparece dentro de una página concreta?
3. web_map: descubrir la estructura de un sitio
Esta herramienta no está pensada principalmente para devolver contenido. Sirve para descubrir qué URLs existen y por qué fueron incluidas o descartadas.
Request:
{
"url": "https://example.com",
"sitemap": "skip",
"include_search": false,
"max_depth": 1,
"max_pages": 3,
"max_discovered_urls": 10
}Response:
{
"schema_version": "thorondor.map.v1",
"requested_url": "https://example.com",
"effective_url": "https://example.com/",
"requested_origin": "https://example.com",
"effective_origin": "https://example.com",
"outcome": "completed",
"urls": [
{
"url": "https://example.com/",
"depth": 0,
"sources": ["seed"],
"states": [
"discovered",
"admitted",
"queued",
"fetched"
],
"reason": null,
"trust": "untrusted"
},
{
"url": "https://iana.org/domains/example",
"depth": 1,
"sources": ["link"],
"states": [
"discovered",
"filtered"
],
"reason": "outside_origin",
"trust": "untrusted"
}
],
"stats": {
"discovered": 2,
"admitted": 1,
"fetched": 1,
"filtered": 1,
"pages_succeeded": 1,
"pages_failed": 0
},
"warnings": []
}En la respuesta se puede ver como la URL de iana.org aparece en el mapa, pero se descarta porque está fuera del origen de example.com. Esto evita que un agente rastree accidentalmente toda la web al seguir enlaces externos. Por defecto, Thorondor mantiene el rastreo dentro del origen y de la jerarquía de rutas permitida.
flowchart TD
S[URL inicial] --> R[Resolver redirecciones]
R --> O[Determinar origen efectivo]
O --> SM[Consultar sitemaps]
O --> B[Búsqueda BFS limitada]
SM --> P[Aplicar robots y políticas]
B --> P
P --> D{¿URL admitida?}
D -->|Sí| Q[Encolar]
D -->|No| X[Registrar motivo]
Q --> U[Estado fetched]4. web_crawl: descubrir y descargar páginas
Esta herramienta combina el mapa + descarga de las páginas admitidas.
Request:
{
"url": "https://example.com",
"sitemap": "skip",
"include_search": false,
"max_depth": 1,
"max_pages": 1,
"max_discovered_urls": 10,
"capabilities": ["markdown", "links"],
"structured_formats": ["links"]
}Response:
{
"schema_version": "thorondor.crawl.v1",
"requested_url": "https://example.com",
"effective_url": "https://example.com/",
"outcome": "completed",
"results": [
{
"requested_url": "https://example.com",
"final_url": "https://example.com/",
"outcome": "content",
"status_code": 200,
"content_type": "text/html",
"capabilities": ["links", "markdown"],
"markdown": "# Example Domain\nThis domain is for use in documentation examples...",
"cache": {
"state": "bypass",
"reason": "disabled"
},
"structured": [
{
"format": "links",
"status": "ok",
"links": [
{
"url": "https://iana.org/domains/example",
"text": "Learn more",
"trust": "untrusted"
}
]
}
]
}
],
"stats": {
"discovered": 2,
"admitted": 1,
"pages_succeeded": 1,
"pages_failed": 0,
"filtered": 1
},
"urls": [
{
"url": "https://example.com/",
"states": ["discovered", "admitted", "queued", "fetched"],
"sources": ["seed"]
}
],
"warnings": []
}La diferencia con web_map es que web_crawl devuelve también el contenido tipado de cada página descargada.
El agente puede utilizarlo para:
Leer una documentación completa, pero limitada a una ruta.
Obtener todas las páginas de una sección.
Procesar una documentación técnica.
Extraer tablas o enlaces de varias páginas.
Continuar el procesamiento mediante un trabajo duradero cuando el rastreo es mayor.
Cambio de páginas y vigilancia de objetivos concretos
Thorondor separa dos conceptos:
flowchart LR
A[¿La página cambió?] --> B[Comparación de documento]
B --> C[new / same / changed / removed]
D[¿Cambió el objetivo que me importa?] --> E[Resolver un elemento único]
E --> F[Comparar texto o atributo]
F --> G[expected → desired]
G --> H[condition_met]Una página puede cambiar porque ha aparecido un anuncio, un contador o una recomendación nueva. Eso puede generar:
{
"change": {
"state": "changed"
}
}Pero ese cambio no satisface necesariamente una vigilancia específica.
Un agente puede expresar algo como:
{
"urls": ["https://example.com/product"],
"watch": {
"target": {
"role": "button",
"name": "Availability"
},
"expected": {
"text": "Out of stock"
},
"desired": {
"text": "Available"
},
"match": "exact"
}
}La condición solo se cumple cuando Thorondor observa una transición desde el estado esperado al estado deseado.
En la instancia desplegada actualmente, la caché está desactivada por defecto. Una llamada real de vigilancia a example.com devolvió:
{
"cache": {
"state": "bypass",
"reason": "disabled"
},
"watch": {
"condition_met": false,
"current": null,
"previous": null,
"resolution": "unsupported",
"state": null
}
}Esto es deliberado: activar la vigilancia requiere aceptar persistencia local, configurar la caché y realizar observaciones sucesivas. Thorondor no programa tareas ni envía notificaciones; Tengwar o el agente que lo use decide cuándo repetir la llamada y qué hacer después.
Una respuesta MCP tiene dos niveles
Por debajo, MCP transporta el resultado dentro de un sobre parecido a este:
{
"is_error": false,
"content": [
{
"type": "text",
"text": "{\"schema_version\":\"thorondor.fetch.v1\", ...}"
}
]
}Esto permite que clientes MCP sencillos puedan consumir el resultado como texto JSON, mientras que clientes más avanzados pueden interpretar el contrato versionado y sus campos tipados.
Seguridad y límites
flowchart TD
U[URL o contenido externo] --> S[Validación de URL]
S --> R[Robots y alcance]
R --> C[Crawl4AI]
C --> P[DNS pinning y egress dedicado]
P --> T[Web pública]
T --> C
C --> V[Contenido marcado como untrusted]
V --> A[Agente]Thorondor impone:
Límites de URLs, páginas, profundidad y bytes.
Deadlines y cancelación.
Protección contra destinos internos y SSRF.
Redes separadas para el control interno y la salida web.
Robots.txt y políticas de alcance.
Identidad documental estable.
Evidencia exacta con offsets.
Validación local de las respuestas estructuradas.
Rechazo total de resultados de esquema que no puedan probarse en la fuente.
El contenido web nunca se convierte automáticamente en instrucciones confiables para el agente.
Qué cambia para el agente
La mejora principal no es que Thorondor “sepa más cosas”. Es que ahora puede responder preguntas más precisas:
Antes:
“Busca información sobre este producto.”
Ahora:
“Consulta esta página, comprueba si el producto está disponible, verifica el texto del botón y avísame únicamente cuando cambie de ‘Agotado’ a ‘Disponible’.”
Antes:
“Rastrea este sitio.”
Ahora:
“Descubre las URLs bajo esta sección, respeta robots.txt, no salgas del dominio, limita el rastreo a diez páginas y devuélveme los resultados con su estado y procedencia.”
Antes:
“Extrae los datos de la página.”
Ahora:
“Devuelve los enlaces y las tablas, indicando de qué documento y posición exacta procede cada valor.”
Ese es el objetivo de esta evolución: que Thorondor sea una herramienta fiable para que los agentes observen la web, comprueben hechos y reaccionen ante cambios concretos, manteniendo siempre visible el origen de la información.