Category: TypeScript

  • Angular 22: Implicaciones técnicas y coste real de migrar en 2026

    Angular 22: Implicaciones técnicas y coste real de migrar en 2026

    Angular 22 vs el resto: lo que nadie te dice sobre migrar en 2026

    Tiempo estimado de lectura: 4 min

    • Modernización estructural: Zoneless por defecto, Signals y Control Flow nativo cambian la forma de detectar cambios y escribir templates.
    • Contextos de ventaja: Angular 22 aporta coherencia en equipos grandes y proyectos de larga vida útil; no es la opción por defecto para prototipado rápido.
    • Coste real de migración: incluye trabajo manual de refactor y coste de formación; planifica recursos y tiempo (ej. 3–6 meses para monorepos medianos).
    • Testing y despliegue: migrar a Jest + Angular Testing Library es parte crítica del plan; usa despliegues canarios y métricas para validar.

    Buscar Angular 22 vs el resto: lo que nadie te dice sobre migrar en 2026 no es una charla de café. Es una decisión de arquitectura con consecuencias inmediatas en costes, ritmo de desarrollo y mantenimiento. Angular 22 ya no es el framework “pesado” que recuerdas. Pero esa modernización trae costes de migración reales y decisiones estratégicas que no aparecen en la documentación oficial.

    Resumen rápido (lectores con prisa)

    Angular 22 introduce Zoneless por defecto, Signals y Control Flow nativo en templates. Mejora TTI y reduce renders innecesarios. Es una buena opción para equipos grandes y proyectos de larga duración; la migración requiere refactor y formación. Incluye la migración del stack de testing a Jest + Angular Testing Library como parte del plan.

    Angular 22 vs el resto: lo que cambia y por qué importa

    Zoneless por defecto

    Se abandona Zone.js. La detección de cambios pasa de ser global e impulsiva a ser controlada y granular. Resultado: TTI más bajo y menos renders innecesarios.

    Signals como primitivo de reactividad

    Reactividad sin subscriptions masivas. Signals reduce la boilerplate de RxJS para estado local y mejora predictibilidad.

    Control Flow nativo en templates (@if, @for)

    El compilador procesa control de flujo a nivel de AST, lo que incrementa rendimiento y legibilidad.

    Traducido: Angular ya compite en métricas de rendimiento con frameworks “reactivos” como Solid o con Vue, pero manteniendo un conjunto de herramientas integradas (DI, routing, forms) que otros frameworks dejan al ecosistema.

    Comparativa honesta: cuándo Angular gana y cuándo no

    Angular no es la mejor opción por defecto. Es la mejor opción para ciertos contextos.

    • Si ganas con opinión y consistencia: equipos de >10 devs, código con vida útil >3 años, requisitos de accesibilidad y compliance, Angular aporta coherencia y reduce decisiones ad-hoc.
    • Si priorizas libertad y prototipado rápido: React o Vue siguen siendo más ágiles. Next.js / Nuxt dominan en SSR/Server Components y experiencia híbrida contenido-aplicación.

    Arquitectura

    Angular = opinado; React = flexible; Vue = progresivo.

    Reactividad

    Angular = Signals; React = Hooks/Virtual DOM; Vue = Composition API.

    SSR y SEO

    Next.js/Nuxt > Angular Universal (mejora pero no centro de innovación).

    Mantenimiento en equipos grandes

    Angular > React (por la opinión y patrones forzados).

    Lo que nadie te cuenta sobre el coste real de migrar

    Hay dos costes que muchos subestiman.

    1) Coste técnico (trabajo manual)

    Actualizar con el CLI es el viaje fácil. El trabajo duro es refactorizar: pasar de NgModules a Standalone Components, reescribir flujos con Signals, adaptar templates a Control Flow nativo. Eso no se hace con sed. Es trabajo de diseño con pruebas y revisiones de arquitectura.

    2) Coste de conocimiento (formación)

    Si tu equipo maneja Angular 8–12 y nunca siguió la evolución, la migración se convierte en un proceso de aprendizaje. No es solo código; es cambiar patrones mentales.

    Estimación práctica: para un monorepo mediano (~50–100 paquetes) con Angular legacy, planifica entre 3–6 meses de esfuerzo de ingeniería + formación (una squad dedicada en paralelo). Para apps pequeñas, 2–4 semanas si controlas las dependencias.

    Testing: la parte que obliga a modernizar

    Karma y Jasmine están oficialmente deprecados. Seguir con ellos en 2026 equivale a cargar deuda técnica que ralentiza CI. El estándar actual es Jest + Angular Testing Library: tests por comportamiento, más rápidos y menos frágiles ante refactors.

    Si vas a migrar, incluye la migración del stack de testing en el plan. No lo dejes para “después”; las pruebas son el talón de Aquiles de cualquier transición grande.

    Plan de migración (práctico y priorizado)

    1. Auditoría de superficie: identifica paquetes que usan NgModules, transformadores de compilador o dependencias tightly-coupled.
    2. Formación y pilot: entrena 2–3 leads en Standalone + Signals. Ejecuta un pilot migrando un módulo crítico.
    3. Reescritura incremental: migrar componentes a Standalone, adaptar servicios a nuevo DI y sustituir RxJS local por Signals donde aplique.
    4. Testing first: antes de cambiar templates, adapta tests a Jest + Testing Library.
    5. Despliegue canario: canary en producción para un subset de usuarios. Monitorea TTI, errores y coste de CI.
    6. Feedback loop: métricas + sesiones de code review para homogeneizar patrones.

    Formación recomendada (práctica)

    Si tu equipo necesita acelerar la adopción, dos recursos útiles y prácticos:

    Ambos cubren desde conceptos arquitectónicos hasta patrones aplicables en migraciones reales.

    Conclusión: criterio para decidir en 2026

    Angular 22 es una opción sólida cuando necesitas previsibilidad, escalabilidad y uniformidad. No es una moda; es una apuesta por la ingeniería predecible. Pero la migración exige plan, formación y disciplina. Si tu prioridad es velocidad de lanzamiento inmediata y equipo pequeño, otras opciones siguen siendo más prácticas. Si en cambio trabajas en dominios donde la UI es infraestructura con vida útil larga —migrar a Angular 22 tiene sentido y trae beneficios tangibles: menos renders innecesarios, menos deuda y mejores métricas de rendimiento.

    Migrar no es solo actualizar dependencias. Es reescribir la forma en que piensas la UI. Hazlo con criterio.

    FAQ

    Respuesta: Zoneless significa que Angular deja de depender de Zone.js para la detección de cambios. La detección se vuelve más controlada y granular, lo que reduce renders innecesarios y mejora TTI.

    Respuesta: Signals son un primitivo de reactividad que permiten manejar estado local sin la sobrecarga de subscriptions masivas. Conviene usarlos para reducir boilerplate y mejorar la predictibilidad del estado local.

    Respuesta: Estimación práctica indicada en el artículo: para un monorepo mediano (~50–100 paquetes) planifica entre 3–6 meses de esfuerzo de ingeniería + formación con una squad dedicada en paralelo.

    Respuesta: Karma y Jasmine están deprecados; mantenerlos añade deuda técnica y ralentiza CI. Migrar a Jest + Angular Testing Library hace los tests más rápidos y menos frágiles ante refactors, y debe formar parte del plan de migración.

    Respuesta: Pilotear un módulo crítico con leads formados en Standalone + Signals es la recomendación: forma 2–3 leads y ejecuta un pilot antes de reescrituras a gran escala.

    Respuesta: En SSR y SEO Next.js/Nuxt suelen ofrecer una experiencia más avanzada; Angular Universal ha mejorado pero no es el centro de innovación en este espacio.

  • Usa el sistema de tipos de TypeScript como documentación para IA

    Usa el sistema de tipos de TypeScript como documentación para IA

    El type system de TypeScript como documentación para tu agente de IA

    Tiempo estimado de lectura: 4 min

    • El type system actúa como contrato para agentes IA: reduce ambigüedad y alucinaciones.
    • Proveer tipos reales al modelo mejora la integración: interfaces y uniones limitan las soluciones válidas.
    • Prácticas recomendadas: evita any, usa uniones discriminadas, y documenta intenciones clave con JSDoc.
    • Aplica en sistemas críticos: APIs públicas, lógica financiera, workflows y automations en producción.

    El type system de TypeScript como documentación para tu agente de IA funciona mejor que mil parrafadas: le das al modelo un contrato, no una novela. Si quieres que Claude, GPT o cualquier agente genere código real y alineado con tu arquitectura, empieza por entregarle los tipos —no descripciones— y observa cómo las alucinaciones desaparecen.

    ¿Por qué? Porque un tipo es una restricción matemática. Un LLM con contexto tipado no puede inventar propiedades, estados o firmas que no existen.

    Resumen rápido (lectores con prisa)

    Qué: Usa el type system de TypeScript como contrato para agentes IA.

    Cuándo: En APIs públicas, lógica crítica y workflows en producción.

    Por qué importa: Reduce alucinaciones y errores de integración.

    Cómo: Pega las interfaces, enums y tipos en el prompt y obliga al agente a cumplir firmas y uniones discriminadas.

    Qué cambia en tu flujo de trabajo

    Los modelos de lenguaje predicen tokens; no “entienden” tus necesidades de negocio. Cuando les ofreces solo lenguaje natural, abrazan convenciones comunes y rellenan huecos con suposiciones populares. Resultado: código que “parece” correcto pero falla en integrarse con tu stack.

    Si en cambio inyectas las interfaces, enums y tipos de tu proyecto, reduces drásticamente el espacio de soluciones válidas. El agente no elige entre cien estructuras posibles: respeta la tuya.

    No es teoría. Es práctica:

    • Tipos explícitos delimitan estados válidos ('pending' | 'completed' | 'failed').
    • Relaciones entre interfaces exponen dependencias y claves foráneas.
    • Uniones discriminadas fuerzan el manejo correcto de errores y casos límite.

    Fuentes prácticas: documentación oficial de TypeScript, guías de APIs y plataformas de agentes como OpenAI o Anthropic.

    Ejemplo práctico: deja de explicar, pega el tipo

    Imagina que quieres delegar la lógica de cambio de estado de pedidos.

    Sin tipos: “Crea una función para actualizar el estado de un pedido”. El modelo inventa estados. Problema.

    Con tipos reales:

    type OrderStatus = 'pending' | 'confirmed' | 'dispatched' | 'delivered' | 'refunded';
    
    interface Order {
      id: string;
      status: OrderStatus;
      customerId: string;
      updatedAt: string; // ISO UTC
    }
    
    type UpdateOrderStatusResult = 
      | { success: true; order: Order }
      | { success: false; error: 'ORDER_NOT_FOUND' | 'INVALID_TRANSITION' };

    Pega esto en el prompt o en el contexto del agente (Cursor, GitHub Copilot, flujos custom via API) y pide: “Implementa updateOrderStatus que valide transiciones y devuelva UpdateOrderStatusResult”. Ahora el agente debe cumplir la firma. No habrá processing fantasmas ni retornos desordenados.

    Reglas prácticas para construir el contexto tipado

    1. Evita any como si fuera veneno

    any es una puerta abierta a alucinaciones.

    2. Prefiere uniones discriminadas sobre booleans dispersos

    Las banderas (isLoading, isError) permiten estados imposibles; una unión no.

    3. Añade JSDoc breve cuando la intención no sea obvia

    Ejemplo: /** Fecha en UTC. No convertir a local. */

    4. Expone las relaciones

    Usa referencias: invoice.orderId: Order['id']. El agente lo interpreta como clave foránea.

    5. Incluye los tipos de retorno claros (Result/Either)

    Obliga a manejar errores, no a ignorarlos.

    Herramientas que usan este enfoque

    Herramientas que usan este enfoque: n8n para orquestación, GitHub Copilot y Cursor en editores. También puedes integrar directamente archivos .d.ts en el contexto de la llamada a la API.

    ¿Cuándo aplicar Type-Driven Development con agentes?

    Úsalo cuando la consistencia importa: APIs públicas, lógica financiera, workflows críticos, transformaciones de datos y automations en producción. Evítalo solo en prototipos tempranos donde los modelos de datos cambian cada dos días.

    No confundas disciplina con burocracia: diseñar tipos claros al principio acelera todo lo demás. Es una inversión que reduce revisiones manuales y bugs silenciosos.

    Resultado esperado y próximos pasos

    Si empiezas hoy, el cambio es tangible: menos iteraciones, menos PRs arreglando supuestos imposibles y, sobre todo, código que entra en tu base sin romper contratos. El tipo es el contrato. El agente es el implementador.

    Haz esto ahora: copia el archivo de tipos relevante (o el fragmento clave) en el prompt de tu agente, pide una implementación concreta y compara el PR generado con lo que haría un desarrollador. Notarás dos cosas: consistencia y menos errores lógicos. Si trabajas con n8n, añade los tipos a los nodos o workflows para que los agentes que automatan tareas respeten tus contratos.

    No acaba aquí: diseña un checklist de tipos antes de delegar, prueba un par de endpoints y verás cómo el modelo deja de “inventar”. ¿Quieres un checklist listo para usar? Haz esto primero: pega tu index.d.ts en el prompt y pide al agente “Genera tests unitarios que verifiquen las transiciones permitidas”. Verás la diferencia al instante.

    Si quieres profundizar con proyectos y experimentos, revisa también los recursos y experimentos de Dominicode Labs. Es un buen complemento para validar patrones de Type-Driven Development aplicados a agentes y workflows antes de llevarlos a producción.

    FAQ

    ¿Por qué usar tipos en lugar de solo lenguaje natural?

    Porque los tipos actúan como restricciones matemáticas que reducen el espacio de soluciones válidas. Forzan al agente a no inventar propiedades o estados que no existen.

    ¿Qué tipos debo compartir primero?

    Empieza por los tipos que definen estados y contratos públicos: DTOs, modelos de entidad y tipos de retorno de API. Luego añade relaciones y uniones discriminadas.

    ¿Cómo evito que el agente ignore los tipos?

    Entrega los tipos en el contexto del prompt y pide explícitamente que la implementación cumpla las firmas. Usa ejemplos de tests o resultados (Result/Either) para que el agente devuelva formas esperadas.

    ¿Qué herramientas facilitan este flujo?

    Editores y orquestadores que soportan contexto tipado: Cursor, GitHub Copilot y plataformas de orquestación como n8n.

    ¿Es útil en prototipos rápidos?

    En prototipos muy tempranos donde los modelos de datos cambian constantemente, puede ser una carga. Para prototipos más avanzados o cuando la estructura es estable, sí acelera la integración.

    ¿Cómo manejar cambios de tipos en producción?

    Versiona tus tipos y mantén contratos retrocompatibles siempre que sea posible. Añade migraciones y tests que verifiquen transiciones permitidas entre versiones.

    ¿Debo incluir ejemplos de datos junto a los tipos?

    Sí. Ejemplos concretos ayudan al agente a mapear tipos a estructuras reales y generan pruebas útiles para validar implementaciones.

  • Construyendo Agentes Rápidos con TypeScript y Vercel AI SDK

    Construyendo Agentes Rápidos con TypeScript y Vercel AI SDK

    TypeScript + Vercel AI SDK: la combinación que uso para construir agentes rápido

    Tiempo estimado de lectura: 4 min

    • Tipado + validación: TypeScript en la superficie y Zod en runtime reducen errores silenciosos y permiten refactors seguros.
    • API unificada: Vercel AI SDK conecta proveedores y ofrece streaming y herramientas tipadas.
    • Extracción y control: generateObject y esquemas evitan ingeniería de prompt frágil y JSON truncado.
    • UX y operaciones: streamText mejora la percepción de latencia; métricas y circuit breakers mantienen robustez en producción.

    TypeScript + Vercel AI SDK: la combinación que uso para construir agentes rápido. Si vas a poner agentes en producción, necesitas que la capa que conecta al LLM con tus herramientas sea predecible, tipada y validada desde el primer día. Esa combinación reduce errores silenciosos, acelera refactors y convierte promesas estocásticas en contratos verificables.

    Resumen rápido (lectores con prisa)

    TypeScript para tipado estático, Zod para validación en runtime y Vercel AI SDK como API unificada. Juntos: herramientas tipadas, extracción estructurada (generateObject), y streaming (streamText) para agentes más seguros y previsibles.

    TypeScript + Vercel AI SDK: por qué funciona para agentes rápidos

    Tres problemas recurrentes al construir agentes:

    1. El LLM alucina parámetros para las herramientas (tool calls)

    Los modelos pueden generar parámetros inválidos o inventados para llamadas a herramientas, lo que puede llevar a ejecuciones peligrosas si no se validan antes.

    2. Las respuestas JSON vienen envueltas en markdown o truncadas

    Solemos ver JSON con backticks, texto adicional o respuestas incompletas que complican el parsing confiable.

    3. Cambios en la API del proveedor rompen integraciones silenciosamente

    Actualizar modelos o proveedores puede introducir cambios incompatibles si no hay contratos y pruebas robustas.

    La solución práctica es simple: tipos en la superficie (TypeScript), contratos ejecutables (Zod) y una API que integra ambas cosas (Vercel AI SDK). Beneficios concretos:

    • Autocompletado que evita buscar docs.
    • Tool calls que no se ejecutan si los datos no validan.
    • Extracción de objetos estructurados (generateObject) sin ingeniería de prompt frágil.
    • Streaming nativo (streamText) para UX reactiva.

    Tool calls tipados: la barrera que evita ejecuciones peligrosas

    Definir herramientas con esquemas evita que el agente ejecute acciones con parámetros inventados. Ejemplo:

    import { tool } from 'ai';
    import { z } from 'zod';
    
    const searchOrders = tool({
      description: 'Busca pedidos por ID de cliente',
      parameters: z.object({
        customerId: z.string().uuid(),
        status: z.enum(['pending','shipped','delivered']).optional(),
      }),
      execute: async ({ customerId, status }) => {
        return queryOrdersDatabase({ customerId, status });
      },
    });
    

    Si el LLM devuelve un customerId inválido, Zod lo rechazará antes de llamar a execute. Resultado: menos excepciones en la base de datos y trazabilidad clara del fallo (prompt → validación → rechazo).

    generateObject: extracción fiable de datos estructurados

    generateObject obliga al modelo a respetar un esquema y te devuelve un objeto tipado sin hacer JSON.parse() manual. Ejemplo práctico:

    import { generateObject } from 'ai';
    import { openai } from '@ai-sdk/openai';
    import { z } from 'zod';
    
    const schema = z.object({
      sentiment: z.enum(['positive','neutral','negative']),
      confidence: z.number().min(0).max(1),
      topics: z.array(z.string()).max(5)
    });
    
    const { object } = await generateObject({
      model: openai('gpt-4o'),
      schema,
      prompt: 'Analiza la reseña y devuelve sentiment, confidence y topics.'
    });
    
    // object ya está tipado según schema
    

    Esto reduce la ingeniería de prompts (“Devuelve SOLO JSON”) y aumenta la tasa de respuestas utilizables desde el primer intento.

    streamText: UX que comunica progreso y permite pasos intermedios

    Los agentes suelen ejecutar varias herramientas en cadena. streamText permite emitir texto progresivo y reflejar estados intermedios (p. ej. “consultando base de datos…”) en la UI sin arquitectura adicional:

    • Emite tokens progresivamente al frontend.
    • Reporta eventos de invocation/execute de herramientas.
    • Funciona tanto en Server (Next.js) como en cliente con hooks (useChat).

    Esto mejora la percepción de latencia y permite interacciones más naturales con agentes multi‑paso.

    Integración práctica y operaciones en producción

    Patrón recomendado

    1. Diseña esquemas Zod como fuente única de verdad.
    2. Expón el esquema (o ejemplo) en el prompt para guiar al LLM.
    3. Usa safeParse() para reintentos y autocorrección de prompts; usa parse() para endpoints que deben fallar rápido.
    4. Loguea prompt, raw response y error de Zod (flatten) para trazabilidad.

    Medidas operativas

    • Métricas: tasa de validación fallida, latencia media por herramienta, reintentos por prompt.
    • Retries limitados con backoff y contador de intentos (p. ej. 2 reintentos de autocorrección antes de degradar a humano).
    • Circuit breaker para evitar invocar herramientas costosas si la validación falla en cascada.

    Limitaciones y decisions trade‑offs

    • No eliminas la estocasticidad del LLM; la controlas. Algunos casos requerirán supervisión humana.
    • generateObject y Structured Outputs reducen errores de formato, pero no sustituyen la validación semántica (p. ej. números positivos). Zod sigue siendo necesaria.
    • Tipar desde el día 0 impone disciplina, pero acelera onboarding y refactors.

    Conclusión

    TypeScript + Vercel AI SDK: la combinación que uso para construir agentes rápido no es un truco de marketing. Es una estrategia concreta: tipos para detectar cambios, Zod para validar en runtime, y un SDK que une proveedores, streaming y herramientas tipadas. Si tu objetivo es desplegar agentes que actúen sobre sistemas reales—bases de datos, pedidos, o infraestructuras—esta pila reduce fallos silenciosos y convierte iteración rápida en ingeniería sostenible.

    Para equipos que exploran automatización y agentes como flujo de trabajo productivo, una guía práctica y recursos adicionales están disponibles en Dominicode Labs. Es una continuación lógica para quienes quieren aterrizar estas prácticas en sistemas reales.

    FAQ

    ¿Por qué combinar TypeScript con Zod y un SDK como Vercel AI SDK?

    TypeScript aporta seguridad estática y autocompletado; Zod proporciona validación en runtime; y Vercel AI SDK unifica la interacción con proveedores, streaming y herramientas tipadas. La combinación reduce errores silenciosos y facilita refactors.

    ¿Cómo evitan las herramientas tipadas ejecuciones peligrosas?

    Al definir parámetros con esquemas Zod, cualquier dato que no valide se rechaza antes de ejecutar la función execute, evitando operaciones con parámetros inventados o inválidos.

    ¿Qué ventaja ofrece generateObject frente a parsear JSON manualmente?

    generateObject obliga al modelo a respetar un esquema y devuelve un objeto ya tipado, evitando la ingeniería de prompt para forzar JSON y reduciendo errores por markdown, texto adicional o truncado.

    ¿Cuándo debo usar streamText?

    Cuando quieras mejorar la UX en interacciones multi‑paso: emitir tokens progresivamente, mostrar estados intermedios y reportar eventos de invocation/execute sin añadir complejidad arquitectónica.

    ¿Qué métricas operativas son críticas?

    Métricas como tasa de validación fallida, latencia media por herramienta y reintentos por prompt son esenciales para monitorear la salud y eficacia del agente.

    ¿Cuáles son las limitaciones principales de esta pila?

    No elimina la estocasticidad del LLM; solo la controla. También requiere validación semántica adicional (p. ej. asegurar números positivos). Tipar desde el día 0 impone disciplina, aunque acelera onboarding y refactors.

  • Cómo tipar las respuestas de una LLM utilizando Zod y TypeScript

    Cómo tipar las respuestas de una LLM utilizando Zod y TypeScript

    Cómo tipar las respuestas de una LLM con Zod + TypeScript

    Tiempo estimado de lectura: 4 min

    • Valida en runtime: TypeScript desaparece en runtime; usa Zod para convertir datos inciertos en contratos verificables.
    • Esquema primero: diseña el esquema Zod como fuente única, extrae tipos con z.infer<> y serializa el esquema en el prompt.
    • Elige parse vs safeParse: .parse() para fallos severos, .safeParse() para autocorrección y reintentos.
    • Producción robusta: logging contextual, reintentos limitados, métricas y SLOs para gestionar errores LLM.

    Saber cómo tipar las respuestas de una LLM con Zod + TypeScript aparece en las primeras líneas porque es lo que evita que un agente, workflow o microservicio se rompa en producción. El modelo devuelve JSON, a menudo; nunca con la forma exacta que esperabas. .parse() y z.infer<> no son trucos: son la defensa que convierte datos inciertos en contratos verificables.

    Resumen rápido (lectores con prisa)

    Qué: Usa Zod para validar y transformar respuestas de LLM en runtime.

    Cuándo: Siempre que vayas a persistir datos o ejecutar acciones críticas basadas en la salida de una LLM.

    Por qué importa: TypeScript no valida en runtime; sin validación, datos malformados pueden romper sistemas en producción.

    Cómo funciona: Diseña el esquema Zod como fuente única, extrae tipos con z.infer<>, limpia la salida si es necesario y valida con .parse() o .safeParse().

    Por qué JSON.parse() + as es una trampa (y qué rompe)

    El patrón clásico:

    const obj = JSON.parse(response) as MyType;

    Es práctico. Es una mentira. TypeScript desaparece en runtime; as no valida nada. Los fallos típicos de LLMs:

    • JSON envuelto en bloques Markdown (“`json … “`).
    • Strings donde esperabas números (“15” vs 15).
    • Campos faltantes, claves renombradas o truncamiento por token limit.
    • Estructuras válidas pero semánticamente inválidas (amount: -5).

    Si confías en casts, esos problemas llegan a tu base de datos o a la lógica que ejecuta acciones. Validación en runtime es obligatoria.

    El patrón sólido: esquema primero, prompt segundo

    1. Diseña el esquema Zod como la única fuente de verdad.
    2. Extrae el tipo estático con z.infer<>.
    3. Incluye una versión legible del esquema en el prompt.
    4. Valida la respuesta con .safeParse() / .parse() antes de usarla.

    Este patrón convierte la salida estocástica de la LLM en una entrada controlada para tu sistema.

    Ejemplo práctico mínimo

    import { z } from 'zod';
    
    const TaskSchema = z.object({
      title: z.string().min(5),
      priority: z.enum(['low','medium','high']),
      estimatedHours: z.number().positive().optional(),
    });
    
    type Task = z.infer;

    Al pedir al modelo que devuelva JSON, serializa el esquema (o su forma) en el prompt para guiar la salida.

    Limpieza defensiva y parse()

    Los LLMs suelen añadir markdown. Limpia antes de parsear:

    function cleanJson(raw: string) {
      return raw.replace(/```json\n?|\n?```/g, '').trim();
    }
    
    const parsed = JSON.parse(cleanJson(rawOutput));
    const valid = TaskSchema.parse(parsed); // lanza ZodError si falla

    Usa .parse() cuando quieras detener el flujo y tratar la anomalía como error severo (útil en endpoints HTTP que deben devolver 4xx/5xx claros).

    .safeParse() y auto‑corrección de prompts

    En agentes autónomos o workflows escalables (n8n, agentes con herramientas), es preferible no lanzar. .safeParse() devuelve { success, data?, error? } para manejar fallos:

    const result = TaskSchema.safeParse(parsed);
    if (!result.success) {
      // registrar, emitir métricas y reintentar con autocorrección
      const zodErrors = result.error.flatten();
      // reintentar: enviar a la LLM el error y pedir JSON corregido
    }

    Patrón de autocorrección: incluye los errores de Zod en un nuevo prompt — el LLM suele corregir la estructura en el siguiente intento.

    Structured Outputs no elimina Zod

    Structured Outputs de OpenAI ayuda a reducir errores de formato (Structured Outputs). Aun así:

    • No controla cortes por token o fallos de red.
    • No valida la semántica (p. ej., números positivos).
    • No sustituye la necesidad de validar localmente antes de persistir o ejecutar acciones.

    Zod sigue siendo la última línea de defensa.

    Operativa en producción: logging, reintentos y SLOs

    • Registra errores de validación con contexto (prompt, response, zod.flatten()).
    • Implementa reintentos limitados con backoff y un máximo de autocorrecciones.
    • Mide métricas: tasa de validación fallida por modelo y prompt, latencia de corrección.
    • Decide SLOs: p. ej., si tras 2 reintentos sigue fallando, encolar para revisión humana.

    Esto transforma un fallo LLM en un incidente manejable, no en una caída silenciosa.

    Consejos prácticos y anti‑patrones

    • No uses as para confiar en la salida del modelo. Siempre valida.
    • Mantén los esquemas Zod como fuente única; evita duplicar interfaces manualmente.
    • Evita validaciones laxas (p. ej., z.any()) en bordes críticos.
    • Serializa el esquema de forma legible en el prompt, no como dump técnico que el modelo no entenderá.
    • Usa discriminated unions para estados exclusivos; obligan a la LLM a responder con casos válidos.

    Conclusión técnica

    Tipar las respuestas de una LLM con Zod + TypeScript no es una cuestión de estilo: es ingeniería de fiabilidad. .parse() y z.infer<> convierten la salida no determinista de una IA en datos verificables. Si construyes agentes, pipelines en n8n o features que actúan sobre sistemas críticos, aplicar este patrón es la diferencia entre sistemas que escalan y sistemas que requieren vigilancia humana constante. Implementa el esquema primero, valida siempre y deja que la LLM vuelva a intentarlo cuando falle — pero que falle donde tú lo controles.

    Para equipos que implementan flujos autónomos y pipelines de IA, una práctica útil es centralizar patrones de validación y autocorrección; esto es exactamente el tipo de trabajo que se experimenta en Dominicode Labs, donde se documentan plantillas y prácticas para agentes y workflows.

    FAQ

    ¿Qué es Zod y por qué usarlo?

    Zod es una librería de validación y parsing para JavaScript/TypeScript que permite definir esquemas y validar datos en runtime. Se usa para asegurar que los datos provenientes de fuentes no confiables (como LLMs) cumplen un contrato antes de ser consumidos por la aplicación.

    ¿Por qué no usar JSON.parse() + as?

    Porque as es solo una aserción en TypeScript y no realiza validación en runtime. JSON.parse() + as asume que la estructura es correcta; si no lo es, introducirás datos inválidos en tu sistema.

    ¿Cuándo usar .parse() vs .safeParse()?

    Usa .parse() cuando quieras que una anomalía detenga el flujo y sea tratada como error severo (por ejemplo, en endpoints HTTP que deben devolver 4xx/5xx). Usa .safeParse() cuando prefieras manejar el fallo (registrar, reintentar con autocorrección) sin lanzar una excepción.

    ¿Cómo incluir el esquema en el prompt?

    Serializa una versión legible del esquema en el prompt (por ejemplo, un objeto JSON con tipos esperados o una tabla de campos requeridos/formatos). Evita dumps técnicos largos; prioriza ejemplos y restricciones clave que la LLM entienda fácilmente.

    ¿Los Structured Outputs de OpenAI reemplazan a Zod?

    No. Structured Outputs reduce errores de formato, pero no controla cortes por token, fallos de red ni valida semántica (p. ej., números positivos). Zod sigue siendo necesario para validación en runtime.

    ¿Qué debo registrar cuando falla la validación?

    Registra el prompt, la respuesta cruda, el resultado de result.error.flatten() o el stack de la excepción, e información contextual (modelo, versión del prompt, intento actual). Estos datos facilitan autocorrección y análisis de causa.

  • Cómo elegir entre Hono, NestJS y Express en 2026

    Cómo elegir entre Hono, NestJS y Express en 2026

    Hono vs Express vs NestJS: cuál usar en 2026

    Tiempo estimado de lectura: 4 min

    Ideas clave

    • Decide por ejecución y mantenimiento: Edge/Serverless → Hono; contenedores y equipos grandes → NestJS; Express solo para legacy.
    • Hono sigue estándares Web (Fetch API) → despliegue directo en Cloudflare Workers, Deno y Bun; bundles mínimos y cold starts bajos.
    • NestJS aporta estructura, DI y patterns enterprise que facilitan gobernanza en equipos grandes.
    • Patrón recomendado: combinar Hono en el perímetro y NestJS en el core para optimizar latencia y mantenibilidad.

    Tabla de contenidos

    Resumen rápido (lectores con prisa)

    Hono es un microframework basado en la Fetch API ideal para despliegues Edge/Serverless con cold starts mínimos. NestJS es un framework estructurado con DI pensado para equipos grandes y aplicaciones empresariales. Express queda como opción legacy; para nuevo desarrollo en Node considera Fastify. Usa Hono en el perímetro y NestJS en el core cuando necesitas ambas propiedades.

    Introducción

    Hono vs Express vs NestJS: cuál usar en 2026 es la pregunta que debes resolver antes del primer commit. No es trivia: elegir mal condiciona latencia, coste, pruebas y, sobre todo, la capacidad del equipo para mantener código sano durante años.

    Si vas a desplegar en Cloudflare Workers, Deno o Bun, Hono cambia las reglas. Si tu sistema vive en Kubernetes y lo mantienen varios equipos, NestJS también cambia las reglas. Express… debería quedarse en mantenimiento.

    Hono vs Express vs NestJS: criterio de elección en 2026

    Primera regla: responde a dos preguntas concretas antes de elegir.

    • ¿Dónde se ejecutará el código? (Edge / Serverless vs contenedor)
    • ¿Quién lo mantendrá? (1–3 devs vs equipos >5)

    Hono está diseñado sobre estándares Web (Fetch API). Eso le da dos ventajas técnicas inmediatas: ejecuta sin cambios en Cloudflare Workers y Deno, y los bundles son mínimos → cold starts casi nulos. Ideal para servicios perimetrales: autenticación perimetral, proxies, transformaciones ligeras y APIs públicas de alta concurrencia.

    NestJS es lo opuesto deliberado: peso inicial mayor, pero estructura y DI que escalan en equipos grandes. Si necesitas módulos, interceptores, pipes, testing con mocks y un modelo mental homogéneo entre 10–50 ingenieros, NestJS reduce la deuda humana.

    Express sigue vivo por legacy. Técnicamente tiene problemas: acoplamiento a primitivas de Node (IncomingMessage/ServerResponse), soporte TypeScript no nativo y mala compatibilidad con runtimes Edge sin polyfills. Para proyectos nuevos, Fastify es una alternativa Node que merece consideración por rendimiento y plugins modernos.

    Performance y cold starts: cuándo importa realmente

    Si tu SLA pide latencia global baja y tus endpoints reciben picos distribuidos geográficamente, los cold starts importan. Hono arranca en milisegundos; NestJS arranca en cientos. Esa diferencia se traduce en UX y factura cuando se escala en funciones serverless.

    Ejemplo práctico:

    • API pública de alta concurrencia (CDN + Edge): Hono en Workers.
    • Sistema de facturación con colas, auditoría y scheduling: NestJS en contenedores.

    No mezcles requisitos. Si necesitas ambos, separa responsabilidades: Hono en el perímetro, NestJS en el núcleo.

    Escalabilidad de equipo y mantenibilidad

    NestJS gana por goleada en proyectos donde:

    • Múltiples equipos aportan features.
    • Necesitas contratos claros (interfaces, DTOs, guards).
    • Quieres testing coherente con DI y mocks.

    Hono exige disciplina. Sin una capa organizativa —convenios de carpeta, inyección manual, testing— terminas con endpoints inconexos. Aún así, para equipos pequeños o equipos senior que aceptan convenciones internas, Hono es una opción mantenible.

    Seguridad, observabilidad y ecosistema

    NestJS integra patterns enterprise: interceptores para logging, guards para auth, módulos para integración de colas (BullMQ), microservicios gRPC, etc. Si necesitas trazabilidad distribuida y middlewares estandarizados, te lo pone más fácil.

    Hono no te impide instrumentar trazas, pero requiere que diseñes la integración desde cero. Para infra ligera y métricas puntuales está bien; para auditoría y cumplimiento, NestJS acelera la adopción.

    Reglas prácticas para decidir (lista accionable)

    1. Despliegue Edge (Cloudflare Workers, Deno, Bun) → Hono. Docs: https://hono.dev, Cloudflare Workers: https://developers.cloudflare.com/workers
    2. Núcleo empresarial en Kubernetes → NestJS. Docs: https://docs.nestjs.com
    3. Proyecto nuevo pequeño, necesitas rendimiento en Node → Fastify sobre Express. Fastify: https://www.fastify.io
    4. Mantener app legacy en Express → parche, migración gradual a Fastify/NestJS o mantener si coste de migración es mayor.
    5. Necesitas tipado extremo end-to-end con frontend TS → Hono RPC o compartir DTOs desde NestJS.
    6. Requisito de cold starts <20ms → Hono (Edge); NestJS requiere contenedores siempre calientes.

    Patrón recomendado: combinar, no elegir a ciegas

    La arquitectura más práctica en 2026 no es monolítica en framework. Usa NestJS para la lógica de negocio, colas, trabajos en background y microservicios críticos; usa Hono para la capa perimetral, autenticación global, webhooks y endpoints que deben estar cerca del usuario.

    Ventaja: reduces coste y latencia donde importa, y mantienes previsibilidad y pruebas allí donde importa más: en el core.

    Conclusión

    Hono vs Express vs NestJS: cuál usar en 2026 no es una competición de popularidad. Es una cuestión de contexto. Si necesitas extremar latencia y desplegar en Edge, Hono gana. Si necesitas gobernanza de código, DI y un stack mantenible por equipos grandes, NestJS gana. Express sigue siendo válido solo para mantener legacy; para nuevo desarrollo, elige Fastify si trabajas exclusivamente en Node.

    Decide según ejecución y mantenimiento, no por hype. La mejor arquitectura combina herramientas: perímetro ligero (Hono) + corazón estructurado (NestJS). Eso te dará velocidad hoy y coherencia mañana.

    FAQ

    Respuesta: ¿Cuándo debo usar Hono en lugar de NestJS?

    Usa Hono cuando despliegues en runtimes Edge/Serverless (Cloudflare Workers, Deno, Bun) y necesites cold starts mínimos y alta concurrencia en endpoints públicos. Usa NestJS cuando necesites estructura, DI y gobernanza para equipos grandes.

    Respuesta: ¿Express todavía tiene sentido para proyectos nuevos?

    No para la mayoría de proyectos nuevos. Express se mantiene por legacy. Para nuevo desarrollo en Node, considera Fastify por rendimiento y plugins modernos.

    Respuesta: ¿Cómo afecta el entorno de ejecución a la elección del framework?

    El entorno define compatibilidad y cold starts. Hono está diseñado para la Fetch API y funciona en Workers/Deno/Bun sin polyfills. NestJS está pensado para contenedores y necesita procesos calientes para minimizar latencia.

    Respuesta: ¿Qué alternativas a Express recomiendan para Node moderno?

    Fastify es la alternativa recomendada por rendimiento y ecosistema de plugins. Evalúa Fastify sobre Express para proyectos nuevos en Node.

    Respuesta: ¿Puedo mezclar Hono y NestJS en la misma plataforma?

    Sí. Patrón recomendado: Hono en el perímetro (autenticación global, webhooks, endpoints edge) y NestJS en el núcleo (lógica de negocio, colas, trabajos). Separar responsabilidades reduce coste y mejora latencia.

    Respuesta: ¿Qué considerar sobre cold starts en serverless?

    Si tu SLA requiere latencias muy bajas y tienes picos geográficos, los cold starts importan. Hono puede arrancar en milisegundos en Edge; NestJS suele requerir contenedores calientes y arranques en cientos de ms.

  • Cómo Zod resuelve la validación de datos en TypeScript

    Cómo Zod resuelve la validación de datos en TypeScript

    Zod: la librería que todo dev TypeScript debería conocer en 2026

    Tiempo estimado de lectura: 3 min

    Ideas clave

    • Zod valida, transforma e infiere tipos en runtime, cerrando la brecha de type erasure de TypeScript.
    • Define esquemas una sola vez: validación runtime y tipos TypeScript derivados automáticamente.
    • Para DX y rapidez de integración en apps empresariales, Zod suele ser la mejor opción; para bundle size en edge, considera Valibot.
    • Patrones prácticos: esquema + inferencia, safeParse y transformaciones/refinements.

    Introducción

    Zod: la librería que todo dev TypeScript debería conocer en 2026. Lo digo sin dramatismos: si trabajas con TypeScript y datos externos, Zod debería ser parte de tu kit. Resuelve el problema fundamental que TypeScript no puede cubrir en tiempo de ejecución: validar, transformar y garantizar contratos cuando el compilador ya no está.

    Resumen rápido (lectores con prisa)

    Zod es una librería de validación y transformación de datos para runtime que infiere tipos TypeScript a partir de esquemas. Úsalo donde recibes datos externos (APIs, formularios, ficheros) para asegurar contratos en producción. Priorízalo por su balance entre experiencia de desarrollador e integración con herramientas modernas.

    Por qué Zod importa (y qué problema técnico resuelve)

    TypeScript y la brecha en runtime

    TypeScript te protege durante el desarrollo, pero los tipos se pierden al compilar (type erasure). Eso deja una brecha entre “lo que esperamos” y “lo que llega” — APIs externas, formularios, cron jobs, ficheros CSV. Sin validación en runtime, esa brecha se traduce en bugs impredecibles en producción.

    Zod colapsa dos responsabilidades que históricamente iban por separado: definición de esquema (validación runtime) y tipos TypeScript (tipado estático). Defines un esquema una sola vez; Zod infiere el tipo para que no haya duplicidad ni desincronización entre validación y tipado.

    Zod: la librería que todo dev TypeScript debería conocer en 2026 — comparación técnica

    No es magia; es diseño de librería pensado para TypeScript. Frente a alternativas:

    Yup

    • Yup: nació para JavaScript. Su soporte TypeScript es parcheado; la inferencia es frágil y obliga a aserciones manuales en proyectos estrictos.

    Valibot

    • Valibot: arquitectura modular y tree-shaking superior. Excelente para entornos edge donde cada KB cuenta.

    Zod

    • Zod: equilibrio entre DX, integración y robustez. API legible, transformaciones y refinements potentes, y amplia adopción en herramientas (tRPC, React Hook Form).

    Decisión práctica:

    • Si priorizas DX y rapidez de integración en aplicaciones empresariales: Zod.
    • Si necesitas minimizar bundle en Workers/Edge: Valibot.
    • Si mantienes legado con Yup y no puedes refactorizar ahora: sigue con Yup, pero planifica migración.

    Tutorial práctico: patrones esenciales con Zod

    Tres patrones que uso en producción: esquema + inferencia, safeParse y transformaciones.

    1) Definir esquema e inferir tipo

    // TypeScript
    import { z } from "zod";
    
    export const ProductSchema = z.object({
      id: z.string().uuid(),
      name: z.string().min(1, "Nombre obligatorio"),
      price: z.number().positive("Precio > 0"),
      category: z.enum(["tech", "food"]),
      publishedAt: z.coerce.date().optional(),
    });
    
    export type Product = z.infer<typeof ProductSchema>;

    Nota: z.coerce.date() convierte strings ISO a Date durante la validación. No necesitas un DTO separado.

    2) safeParse: predecible en producción

    const result = ProductSchema.safeParse(raw);
    
    if (!result.success) {
      // result.error.format() -> errores por campo listos para UI/LOG
      console.error(result.error.format());
      throw new Error("Payload inválido");
    }
    
    const product: Product = result.data;

    Nota: parse lanza excepciones; safeParse devuelve un objeto discriminado que encaja mejor en flujos robustos.

    3) Transformaciones y refinements

    const PriceSchema = z.string()
      .regex(/^\d+(\.\d{1,2})?$/)
      .transform(v => parseFloat(v));
    type Price = z.infer<typeof PriceSchema>; // number
    const PasswordSchema = z.object({
      password: z.string().min(8),
      confirm: z.string(),
    }).refine(data => data.password === data.confirm, {
      message: "Las contraseñas no coinciden",
      path: ["confirm"]
    });

    Integración con Angular y formularios reactivos

    El error arquitectónico común: mezclar reglas de negocio con validators en el componente. Mejor patrón: extraer la lógica a Zod y mapear errores a los controles.

    Flujo sugerido

    1. spec/schema.ts con esquemas Zod como fuente de verdad.
    2. Validador personalizado en Angular que ejecuta schema.safeParse(form.getRawValue()).
    3. Mapear error.format() a control.setErrors({ zod: mensaje }).

    Así la lógica es portable (frontend/backend), testeable y mantiene tipado estricto. Para patrones completos con Signals y Standalone Components ve el curso de integración.

    Cuando preferir otra opción

    • Valibot si tu constraint es bundle size en entornos edge.
    • Yup si tienes una base de código legacy donde migrar no es viable a corto plazo.
    • Pero en la mayoría de proyectos empresariales, Zod ofrece mejor balance entre seguridad, DX e integración con herramientas modernas.

    Conclusión y siguiente paso práctico

    Zod no es una moda: es una decisión arquitectónica que reduce errores por desincronía entre tipos y datos reales. Centraliza contratos, facilita transformaciones y mejora la trazabilidad de errores.

    Si quieres llevar esto al siguiente nivel —transformaciones avanzadas, validaciones asincrónicas y patrones de dominio— el curso práctico es la forma más rápida de internalizar buenas prácticas: Zod: Validación y Transformación de datos con TypeScript

    Aprender Zod hoy evita bugs mañana. Y eso, en producción, paga más que cualquier micro-optimización.

    FAQ

    ¿Qué es Zod?

    Zod es una librería de validación y transformación de datos para JavaScript/TypeScript que permite definir esquemas en runtime y derivar tipos TypeScript automáticamente.

    ¿Cuándo debería validar con Zod?

    Valida en cualquier borde del sistema donde recibas datos no confiables: llamadas API, formularios del usuario, ficheros externos o integraciones de terceros.

    ¿Zod reemplaza los tipos de TypeScript?

    No reemplaza los tipos estáticos del compilador; los complementa. Zod permite derivar tipos TypeScript desde un esquema único y aplica validación en runtime donde el compilador no llega.

    ¿Qué diferencia hay entre parse y safeParse?

    parse lanza una excepción si la validación falla. safeParse devuelve un objeto discriminado con success booleano y datos o error, lo que facilita flujos robustos sin excepciones inesperadas.

    ¿Puedo usar Zod en el frontend y backend con el mismo esquema?

    Sí. Mantener esquemas Zod compartidos permite que la lógica de validación y las transformaciones sean portables y consistentes entre cliente y servidor.

    ¿Cuándo elegir Valibot o Yup en lugar de Zod?

    Elige Valibot si la restricción principal es el tamaño del bundle en entornos edge. Mantén Yup solo si tienes un legado amplio que no puedes refactorizar aún; planifica migración a librerías con mejor tipado si es posible.

  • Cómo usar SDKs de AI tipados en TypeScript para reducir errores

    Cómo usar SDKs de AI tipados en TypeScript para reducir errores

    Typed AI SDKs: por qué usar el SDK de Anthropic o OpenAI en TypeScript y no JavaScript puro

    Tiempo estimado de lectura: 3 min

    • TypeScript tipado reduce errores silenciosos: convierte fallos indetectables en errores visibles en desarrollo.
    • Zod aporta validación en runtime: evita confiar en casts y valida la forma real de respuestas del modelo.
    • Patrón “esquema primero, prompt segundo”: serializa el esquema en el prompt y valida antes de persistir.

    Typed AI SDKs: por qué usar el SDK de Anthropic o OpenAI en TypeScript y no JavaScript puro — si vas a poner LLMs en producción, esa decisión cambia el perfil de riesgo de tu sistema. TypeScript no arregla la aleatoriedad del modelo, pero convierte fallos indetectables en errores visibles mientras desarrollas. Eso es todo; y es suficiente.

    Resumen rápido (lectores con prisa)

    Un SDK tipado (OpenAI o Anthropic) + validación runtime (Zod) convierte errores silenciosos en errores detectables durante desarrollo. Diseña el esquema primero, serialízalo en el prompt, parsea y valida la respuesta antes de usarla.

    Introducción

    Cuando integras un LLM en un flujo de trabajo (agentes, pipelines n8n, microservicios de extracción) no luchas contra la IA: luchas contra su impredecibilidad. JavaScript puro acepta promesas rotas y propiedades ausentes hasta que explotjan en producción. Un SDK tipado (OpenAI o Anthropic) empuja la mayoría de esos errores al compilador.

    Fuentes prácticas:

    Errores en compile time, no en producción

    – Modelos como valores literales: los SDK tipados exponen uniones de strings para modelos. Intentar model: 'gpt-5' fallará en el editor, no en prod.

    – Parámetros obligatorios: el compilador te obliga a rellenar lo que la API realmente necesita.

    – Propiedades opcionales: TS fuerza comprobaciones (?., if) antes de operar con datos potencialmente nulos.

    Resultado: menos hotfixes nocturnos. Detectas que algo está mal cuando escribes, no cuando lo usan clientes.

    Autocompletado real: productividad que importa

    IntelliSense deja de ser un lujo y pasa a ser documentación viva. Parámetros como temperature, response_format o function_call aparecen en el editor con sus tipos exactos. En equipos, esto reduce discusiones sobre “¿qué forma tenía ese objeto?” y evita JSON mal formado en llamadas a herramientas.

    La trampa del casting y por qué Zod es obligatorio

    TypeScript desaparece en runtime. Hacer const x = JSON.parse(s) as MyType es mentirle al compilador. Si el modelo devuelve "age":"veinticinco" habrás metido basura en tu flujo.

    Zod ofrece validación en tiempo de ejecución y genera el tipo TypeScript desde el esquema. Patrones recomendados:

    Patrones recomendados

    • Definir el esquema Zod como fuente única de verdad.
    • Incluir el esquema (o un resumen) en el prompt para guiar al LLM.
    • Parsear y validar la respuesta con Zod antes de usarla.

    Ejemplo práctico (OpenAI/Anthropic + Zod):

    import { z } from 'zod';
    import OpenAI from 'openai'; // o Anthropic desde '@anthropic-ai/sdk'
    
    const UserProfileSchema = z.object({
      fullName: z.string(),
      age: z.number().int().positive(),
      email: z.string().email(),
      tags: z.array(z.string()).max(5),
    });
    
    type UserProfile = z.infer<typeof UserProfileSchema>;
    
    const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
    
    async function extractUserProfile(text: string): Promise<UserProfile> {
      const resp = await client.chat.completions.create({
        model: 'gpt-4o',
        messages: [
          { role: 'system', content: `Devuelve solo JSON válido que cumpla este esquema: ${JSON.stringify(UserProfileSchema.shape)}` },
          { role: 'user', content: text },
        ],
        // response_format o similar según SDK
      });
    
      const raw = resp.choices?.[0]?.message?.content;
      if (!raw) throw new Error('Respuesta vacía del modelo');
    
      // Validación runtime: si falla, aquí lo capturas y reintentas o lo registras
      const parsed = UserProfileSchema.parse(JSON.parse(raw));
      return parsed;
    }

    Si usas Anthropic, adapta la llamada al cliente: la idea es la misma: pedir JSON estructurado y validar con Zod.

    Patrones que escalan: esquema primero, prompt segundo

    1. Diseña el esquema Zod.
    2. Infiere tipos TypeScript con z.infer.
    3. Serializa el esquema (o una versión legible) en el prompt.
    4. Valida la respuesta antes de persistir o procesar.

    Este patrón convierte al LLM en una fuente estocástica que vive dentro de un perímetro controlado. No reduces la tasa de “alucinaciones”, pero transformas una alucinación en un error tratable y reproducible.

    Cuándo aplicar este enfoque

    – Sistemas críticos: facturación, reconciliaciones, autorizaciones.

    – Workflows orquestados en n8n donde agentes ejecutan cambios de estado.

    – Microservicios que procesan datos externos y alimentan otras partes del sistema.

    Evítalo solo en prototipos desechables donde la velocidad de exploración sea prioritaria frente a la robustez.

    Conclusión

    Usar Typed AI SDKs de Anthropic o OpenAI en TypeScript y validarlos con Zod no es postureo técnico: es una estrategia de mitigación de riesgo. Cambias errores silenciosos por fallos detectables en desarrollo, mejoras la DX y pones una barrera defensiva entre la naturaleza impredecible del LLM y la integridad de tus datos. Implementa el patrón “esquema primero, prompt segundo” y tu siguiente incidente nocturno será opcional, no inevitable.

    Para trabajos relacionados con automatización, agentes y workflows en entornos de producción puedes explorar más prácticas y experimentos en Dominicode Labs. Se integra como una continuación lógica de los patrones descritos y recursos para orquestación y pruebas.

    FAQ

    Respuesta: TypeScript detecta discrepancias de tipos en tiempo de compilación, obligando a llenar parámetros obligatorios y a tratar opcionales. Reduce errores silenciosos que aparecerían solo en producción.

    Respuesta: Comprobaciones manuales ayudan, pero son repetitivas y propensas a olvidos. Zod ofrece esquemas reutilizables y validación automatizada en runtime que complementa a TypeScript.

    Respuesta: No. Zod aporta validación en runtime; TypeScript aporta seguridad en compile time. Juntos cubren ambos límites: desarrollo y ejecución.

    Respuesta: Serializa el esquema o un resumen legible (ej.: propiedades y tipos esperados) y pídelo explícitamente en el prompt. Luego parsea y valida la respuesta con Zod antes de usarla.

    Respuesta: Sí. El enfoque es independiente del proveedor: adapta la llamada al cliente de Anthropic pero mantiene la misma estrategia de pedir JSON estructurado y validar con Zod.

    Respuesta: Evítalo en prototipos desechables donde la velocidad de exploración prima sobre la robustez. Para sistemas críticos, es la opción recomendada.

  • Impacto del compilador Go en TypeScript 7.0 y su migración

    Impacto del compilador Go en TypeScript 7.0 y su migración

    TypeScript con compilador en Go: qué cambia en tu día a día

    Tiempo estimado de lectura: 4 min

    • Rendimiento: TypeScript 7.0 mueve el motor de tipos fuera de Node.js a un binario en Go, prometiendo hasta 10x en chequeo de tipos en repos grandes.
    • Compatibilidad: Dejar de ser paquete Node.js rompe integraciones que importan la API JS del compilador (p. ej. transformers, ts-morph).
    • Migración práctica: Requiere auditoría de dependencias, estrategias de CI para binarios y puentes (IPC/FFI) para plugins críticos.
    • Balance: Beneficios reales en CI y editor, pero coste organizativo técnico en tooling y librerías.

    TypeScript con compilador en Go: qué cambia en tu día a día es la pregunta que tu equipo debería haberse hecho ayer. TypeScript 7.0 reescribe el motor de validación de tipos fuera de Node.js y lo ejecuta como binario en Go. La promesa es velocidad (hasta 10x en chequeo de tipos en repos grandes). La consecuencia práctica: breaking changes reales en tooling, plugins y pipelines. Este artículo ordena el impacto, da criterio y propone un plan de migración accionable.

    Resumen rápido (lectores con prisa)

    Qué es: TypeScript 7.0 reescribe el motor de tipos como binario en Go, fuera de Node.js.

    Cuándo usarlo: Cuando busques chequeos de tipos significativamente más rápidos y puedas auditar dependencias que tocan el AST.

    Por qué importa: Reduce tiempo en CI y mejora la latencia del IDE, pero rompe integraciones que dependen de la API JS del compilador.

    Cómo funciona (resumen): El compilador pasa de paquete Node.js a binario/WASM; consumidores que importan typescript pierden acceso directo a la API JS y se requieren puentes (IPC/FFI) para mantener compatibilidad.

    TypeScript con compilador en Go: impacto técnico y operativo

    Rendimiento

    Mover el compilador de JavaScript a Go no es un simple cambio de implementación; cambia el modelo de extensión y la superficie de integración.

    • Rendimiento: el chequeo de tipos (tsc) se beneficia de concurrencia nativa (goroutines) y memoria más eficiente. Pipelines que tardaban minutos pasan a segundos.

    Forma de consumo

    • Forma de consumo: deja de ser un paquete Node.js importable; pasa a ser un binario (o potencialmente WASM). Los consumidores que usaban import ts from 'typescript' pierden acceso directo a la API JS del compilador.

    Plugins y transformers

    • Plugins y transformers: APIs como ts.Program, ts.Transformer y librerías como ts-morph quedan en una zona de incompatibilidad. Reconstruir puentes implica IPC/FFI y coste de latencia.

    Estrictez y errores emergentes

    • Estrictez y errores emergentes: el nuevo compilador puede ser más estricto en resolución de módulos y rutas, sacando a la luz configuraciones frágiles en tsconfig.json.

    Fuentes útiles: TypeScript, esbuild, swc, Vite.

    Qué mejora en tu día a día (y sin fricción)

    • CI/CD: tsc --noEmit deja de ser el cuello de botella. Menos tiempo en runners reduce facturación en GitHub Actions, CircleCI, etc.
    • IDE: TSServer consume menos RAM y responde mejor en proyectos con tipos complejos (Zod, Prisma, tRPC — Zod, Prisma, tRPC).
    • Monorepos: escalabilidad de chequeos por paquete, menor bloqueo en cambios amplios.

    Estos beneficios son reales y medibles. Pero no son automáticos para todos los proyectos.

    Qué se rompe en la práctica

    • Frameworks que dependen del AST en tiempo de compilación: Angular, NestJS y ORMs que usan transformers y decoradores verán fallos si no migran sus pipelines.
    • Herramientas de generación de código y scripts que importan typescript quedarán sin la API JS directa.
    • Plugins de bundlers y herramientas de análisis estático (p. ej. ts-morph) requieren reescritura o compatibilidad por puente.

    La migración implica trabajo no trivial por parte de mantenedores de librerías. No es sólo actualizar package.json.

    Plan de acción para equipos (prioritario y práctico)

    1. Auditoría de superficie de riesgo

    • Busca en tu árbol de dependencias cualquier uso de import 'typescript' o require('typescript').
    • Lista paquetes que usan transformers o ts.Program. Estas son las integraciones en riesgo inmediato.

    2. Aísla la transpilación del type-checking

    • Usa Vite/esbuild para bundling y transpile rápido.
    • Corre tsc --noEmit como job paralelo en CI. Esto desacopla cambios de runtime del chequeo estricto.

    3. Congela versiones y crea una ventana de transición

    • Si dependes de plugins no migrados (decoradores de NestJS, Angular compilers), fija TypeScript a ~5.x hasta validar compatibilidad.
    • Comunica fechas internas de evaluación y migración para dependencias clave.

    4. Prepara CI y runners

    • Asegúrate de que los runners pueden descargar y ejecutar binarios (amd64/arm64).
    • Considera imágenes Docker con el binario del compilador preinstalado para reproducibilidad.

    5. Estrategia de puentes para plugins

    • Para librerías críticas, evalúa dos alternativas: 1) reescribir transformadores en Go o 2) implementar un proceso IPC que exponga el AST a JS (aceptable temporalmente, pero con latencia).
    • Prioriza reescrituras sólo si la librería es central; para consumo general, pide a mantenedores roadmap y plazos.

    6. Testing y despliegue gradual

    • Canary builds: ejecuta el compilador en Go en un subset de repos o paquetes.
    • Monitorea regresiones en CI (errores nuevos de tipo o resolución) y en IDEs de desarrolladores.

    Criterio técnico final

    Adoptar TypeScript 7.0 por rendimiento sin auditoría es una apuesta peligrosa. El enfoque correcto es pragmático: separar responsabilidades, auditar dependencias que manipulan AST, preparar CI para binarios y coordinar migraciones con mantenedores de librerías críticas.

    La ventaja económica y productiva es real: feedback loops más rápidos, menos microinterrupciones del IDE y menos coste de CI. El precio es técnico y organizativo: trabajo de migración en tooling. Quien lo planifique hoy evita picos de trabajo y bloqueos de entrega mañana.

    FAQ

    ¿Qué cambia con TypeScript 7.0?

    TypeScript 7.0 reescribe el motor de validación de tipos fuera de Node.js y lo ejecuta como binario en Go. Como consecuencia, deja de ser un paquete Node.js importable y puede ofrecer mejoras de velocidad (hasta 10x en chequeo de tipos en repos grandes) gracias a concurrencia nativa y manejo de memoria en Go.

    ¿Afecta esto a mi CI?

    Sí. tsc --noEmit puede dejar de ser el cuello de botella y reducir el tiempo de ejecución en runners, lo que baja costes en servicios como GitHub Actions o CircleCI. Sin embargo, es necesario garantizar que los runners puedan descargar y ejecutar binarios en las arquitecturas requeridas.

    ¿Qué pasa con plugins que usan transformers?

    APIs que manipulan el AST o dependen de la API JS del compilador (por ejemplo, ts-morph) quedan en riesgo de incompatibilidad. Las alternativas son reescribir transformadores en Go o implementar puentes IPC/FFI para exponer el AST a procesos JS, con coste de latencia.

    ¿Debo migrar inmediatamente?

    No necesariamente. Es recomendable auditar dependencias que usen typescript, congelar versiones críticas (p. ej. ~5.x) y crear una ventana de transición hasta validar compatibilidad de librerías y plugins antes de adoptar en producción.

    ¿Cómo mitigo riesgos en monorepos?

    Aísla la transpilación del type-checking usando herramientas como Vite o esbuild, ejecuta chequeos de tipos como jobs paralelos en CI y aplica canary builds para ejecutar el compilador en Go en subsets de paquetes antes del despliegue general.

  • Asegura el tipo de datos en function calling usando TypeScript

    Asegura el tipo de datos en function calling usando TypeScript

    Function calling tipado con TypeScript: deja de adivinar lo que devuelve el modelo

    Tiempo estimado de lectura: 4 min

    • Ideas clave:
    • Los LLMs fallan en formato y semántica: validar la salida evita errores en producción.
    • Define esquemas con Zod, deriva tipos con z.infer<>, y valida antes de ejecutar herramientas.
    • Usa .parse() para fallar rápido en endpoints y .safeParse() para autocorrección en agentes.
    • Mide y registra: trazabilidad completa (prompt, response, error de Zod, tool invocada).

    Introducción

    Cuando un agente llama a una herramienta, el modelo genera un JSON con argumentos. Asumir que ese JSON tendrá la forma correcta es la fuente de la mayoría de fallos en producción. Implementar Function calling tipado con TypeScript: deja de adivinar lo que devuelve el modelo no es opcional: es ingeniería defensiva. Con Zod validas en runtime, con z.infer<> obtienes tipos sincronizados y con un framework que integre ambos cierras el círculo.

    Fuentes útiles: Vercel AI SDK, Zod, OpenAI Structured Outputs.

    Resumen rápido (lectores con prisa)

    Qué es: Validación tipada de la salida de modelos mediante Zod y TypeScript.

    Cuándo usarlo: Siempre que un LLM invoque herramientas, modifique estado o llame APIs críticas.

    Por qué importa: Previene errores por campos faltantes, tipos incorrectos o JSON mal formado en producción.

    Cómo funciona: Define esquemas Zod, deriva tipos con z.infer<>, valida con .parse() o .safeParse() antes de ejecutar.

    Por qué tipar el function calling importa ahora

    Los LLMs fallan de formas predecibles: omiten campos, envían strings en vez de números, rodean JSON con Markdown o inventan claves. Si procesas ese output con JSON.parse() y as Tipo, renuncias a la seguridad de TypeScript en runtime. El resultado: escrituras corruptas en bases de datos, llamadas a APIs con parámetros inválidos y bugs que sólo aparecen semanas después.

    La alternativa técnica es clara:

    • declarar el esquema con Zod,
    • derivar el tipo TypeScript con z.infer<>,
    • validar antes de ejecutar la herramienta.

    Eso convierte la entrada del agente en un contrato matemático que protege tu lógica de negocio.

    Arquitectura práctica: esquema → validación → ejecución

    Patrón recomendado:

    1. Define el esquema Zod y añádele descripciones que el LLM pueda leer.
    2. Expón ese esquema en el prompt (o úsalo con Structured Outputs).
    3. Valida la respuesta del LLM con .safeParse() o .parse() antes de llamar a la función.
    4. Si falla, captura el ZodError, loguéalo y opcionalmente reintenta con autocorrección.

    Código mínimo (ejemplo de consulta de divisas)

    import { tool } from 'ai'; // p. ej. Vercel AI SDK
    import { z } from 'zod';
    
    const ExchangeSchema = z.object({
      base: z.string().length(3).toUpperCase().describe('Moneda base ISO 4217, ej. USD'),
      target: z.string().length(3).toUpperCase().describe('Moneda destino ISO 4217, ej. EUR'),
    });
    
    type ExchangeParams = z.infer;
    
    export const getExchangeRate = tool({
      description: 'Devuelve el tipo de cambio entre dos monedas',
      parameters: ExchangeSchema,
      execute: async ({ base, target }: ExchangeParams) => {
        const res = await fetch(`https://api.exchangerate-api.com/v4/latest/${base}`);
        if (!res.ok) throw new Error('API externa falló');
        const data = await res.json();
        return { rate: data.rates[target] };
      }
    });
    

    Si la validación falla, execute nunca se ejecuta: el SDK/Zod detiene la cadena y devuelve un error estructurado.

    .parse() vs .safeParse() y autocorrección

    Usa .parse() cuando quieras fallar rápido (endpoints HTTP que deben devolver 4xx/5xx). Usa .safeParse() en agentes y workflows que puedan auto‑corregirse sin intervención humana.

    Patrón de autocorrección:

    1. LLM genera JSON.
    2. .safeParse() devuelve success: false y error.
    3. Serializas error.flatten() y lo inyectas en un nuevo prompt: “Tu respuesta falló por X. Corrige el JSON.”
    4. Reintentás N veces con backoff; si sigue fallando, encolas para revisión humana.

    Ese ciclo convierte errores estructurales en una conversación de corrección con el modelo, robusta y trazable.

    Operaciones y observabilidad

    No basta con validar: mide y actúa.

    Métricas recomendadas:

    • tasa de validación fallida por prompt/modelo,
    • latencia media de autocorrección,
    • número de reintentos hasta éxito,
    • porcentaje de degradaciones a intervención humana.

    Registra siempre: prompt, raw response, resultado de Zod (.error.flatten()), y el tool invocado. Eso te da trazabilidad: prompt → response → validación → acción. Sin esos registros no hay postmortem útil.

    Decisiones arquitectónicas y trade‑offs

    – Structured Outputs (OpenAI) y generateObject reducen errores de formato pero no sustituyen la validación semántica: un amount: -5 puede pasar el schema si no validas signo y rango. Siempre valida con Zod (https://zod.dev/).

    – Tipar desde el día 0 exige disciplina: los esquemas son contratos que obligan a diseñar prompts claros y a mantener tests de integración. La deuda que previene compensa la inversión inicial.

    – En entornos orquestados (n8n, XState) preferir que el LLM decida la herramienta y que la ejecución quede en una máquina de estado puede ser más seguro para acciones críticas. Igual aplica: la entrada debe validarse antes de actuar.

    Conclusión: deja de adivinar, empieza a garantizar

    Function calling tipado con TypeScript: deja de adivinar lo que devuelve el modelo — es una fórmula sencilla y comprobada: define el esquema (Zod), extrae el tipo (z.infer<>), valida antes de ejecutar y automatiza la corrección cuando tenga sentido. Esa disciplina transforma un LLM impredecible en un componente confiable de tu arquitectura. Si tu agente escribe en bases de datos, llama APIs facturadas o toma decisiones que afectan a clientes, no hay excusas: valida antes de ejecutar y loguea todo. Así se construyen agentes que pueden correr solos, y no problemas que sólo aparecen en producción.

    Para continuar explorando prácticas operativas y experimentos en automatización e IA aplicada, consulta Dominicode Labs. Esta referencia complementa las técnicas descritas y ofrece recursos prácticos para implementar pipelines seguros y trazables en producción.

    FAQ

    ¿Por qué no basta con hacer JSON.parse() y castear a un tipo?

    Porque JSON.parse() solo asegura formato JSON válido, no la semántica ni la presencia y tipo de campos esperados. Castear con as Tipo ignora la verificación en runtime, lo que permite entradas inválidas que pueden provocar errores en bases de datos o llamadas a APIs en producción.

    ¿Cuándo debo usar .parse() en lugar de .safeParse()?

    Usa .parse() en contextos donde quieras fallar rápido y retornar un error (por ejemplo endpoints HTTP que deben devolver 4xx/5xx). Usa .safeParse() cuando el flujo puede intentar autocorrección o reintentos antes de degradar a intervención humana.

    ¿Qué hago si .safeParse() falla continuamente?

    Serializa el error con error.flatten(), inyecta esa información en un nuevo prompt pidiendo corrección, y reintenta N veces con backoff. Si sigue fallando, encola la unidad para revisión humana y registra el incidente para análisis posterior.

    ¿Debo exponer el esquema Zod en el prompt?

    Sí: exponer el esquema ayuda al modelo a generar la estructura correcta (especialmente con Structured Outputs). Aun así, la validación con Zod debe ejecutarse en runtime; el esquema en el prompt no sustituye la verificación.

    ¿Qué debo registrar para tener trazabilidad adecuada?

    Registra el prompt, la respuesta cruda del modelo, el resultado de Zod (error.flatten()), y la herramienta (tool) invocada. Esos datos permiten reconstruir el flujo prompt → response → validación → acción para postmortems.

    ¿Los Structured Outputs sustituyen la validación con Zod?

    No. Structured Outputs y utilidades como generateObject reducen errores de formato, pero no validan semántica ni rangos (por ejemplo, amount: -5 podría pasar). Sigue validando con Zod en runtime.

  • Cómo manejar errores en agentes de IA usando TypeScript

    Cómo manejar errores en agentes de IA usando TypeScript

    Error handling en agentes de IA: TypeScript te obliga a hacerlo bien

    Tiempo estimado de lectura: 3 min

    Ideas clave

    • Evita try/catch genéricos: ocultan la causa raíz y llevan a reintentos inútiles o a falsos positivos.
    • Usa Result<T, E>: convierte errores en valores tipados que el orquestador y el LLM pueden razonar.
    • Forzar exhaustividad con never: el compilador impide desplegar manejadores incompletos.
    • Persistir errores en memoria: guarda fallos estructurados en la memoria episódica para decisiones posteriores.
    • Instrumenta y prueba: telemetría, tests y SLAs para garantizar conducta operativa.

    Tabla de contenidos

    Introducción

    Error handling en agentes de IA: TypeScript te obliga a hacerlo bien. Dilo alto. Si tu agente llama herramientas, escribe datos o encadena flujos, el modo en que tratas los fallos decide si tendrás un sistema autocorrectivo o un monstruo que consume tokens y rompe tablas.

    Los try/catch genéricos son la forma más rápida de cegar a un agente. TypeScript, usado con disciplina, no te da magia: te da garantías. Garantías que convierten excepciones impredecibles en valores tipados que el agente puede razonar, registrar y recuperar.

    Resumen rápido (lectores con prisa)

    Qué: Trata errores como valores con Result<T,E> en lugar de throw.

    Cuándo: Siempre que tu agente llame herramientas, escriba en DB o coordine flujos.

    Por qué importa: Evita reintentos ciegos, reduce tokens gastados y hace al agente reparable.

    Cómo funciona: Devuelve {ok: true|false} con error tipado y usa checks exhaustivos con never para obligar a manejar nuevos casos.

    Por qué los try/catch genéricos matan tus agentes

    Un humano reintenta después de un HTTP 500. Un agente no. Cuando un LLM recibe solo “Error executing tool”, pierde la causa raíz. ¿Duplicado en la DB? ¿Timeout? ¿Bad payload? Sin esa información, el agente hará una de dos cosas útiles para nadie: reintentar la misma acción hasta agotar tu presupuesto o “alucinar” que la acción fue exitosa para seguir el flujo.

    En sistemas agénticos cada fallo es una señal. Ocultarla con un mensaje opaco equivale a apagar los sensores del coche mientras conduces rápido.

    Result<T, E>: convertir errores en datos con contrato

    La respuesta práctica es sencilla: deja de tirar (throw) y empieza a devolver. El patrón Result<T, E> transforma errores en valores discriminados que obligan al consumidor a lidiar con ellos.

    type Result<T, E> =
      | { ok: true; value: T }
      | { ok: false; error: E };

    Ejemplo de herramienta:

    async function createUser(email: string): Promise<Result<User, 'DUPLICATE_EMAIL' | 'DB_TIMEOUT' | 'INVALID_SCHEMA'>> {
      // nunca throw; siempre retorna ok: true | ok: false
    }

    ¿Qué cambia? Ahora el orquestador recibe información accionable. Si ok: false y error === ‘DUPLICATE_EMAIL’, inyectas esa razón en la memoria episódica y el LLM pregunta por otro email en vez de repetir la misma INSERT. Transformas ruido en contexto.

    Documentación útil sobre Result (concepto inspirado en Rust): Documentación útil sobre Result (concepto inspirado en Rust)

    never y exhaustive checks: el compilador como guardarraíl

    Pasa esto en equipos: alguien añade un nuevo error y olvida manejarlo. Resultado: el agente se comporta de forma impredecible en producción. Aquí entra el patrón de comprobación exhaustiva con never.

    Define tus errores como unión discriminada:

    type AgentError =
      | { type: 'DatabaseError'; code: number }
      | { type: 'AuthError'; reason: string }
      | { type: 'ValidationError'; issues: string[] };

    Y formatea para el LLM con un switch que fuerza exhaustividad:

    function formatErrorForLLM(error: AgentError): string {
      switch (error.type) {
        case 'DatabaseError': return `DB failure (${error.code}). No retry.`;
        case 'AuthError': return `Auth failed: ${error.reason}. Re-auth required.`;
        case 'ValidationError': return `Invalid: ${error.issues.join(', ')}. Fix and retry.`;
        default:
          const _exhaustive: never = error;
          return _exhaustive;
      }
    }

    Si alguien añade { type: 'RateLimit' } a AgentError y no actualiza este switch, TypeScript fallará en compilación. Lee sobre exhaustiveness checks: Lee sobre exhaustiveness checks

    Eso no es paranoia: es disciplina. Tu CI/CD no permitirá desplegar un agente que no explica cada fallo.

    Integración práctica con memoria y orquestación

    Errores tipados deben viajar junto con resultados hacia la memoria episódica. Diseño minimalista:

    • La tool retorna Result.
    • El orquestador persiste tanto éxitos como fallos en la memoria episódica (Redis) y semántica (vector DB si aplica).
    • El prompt incluye el fallo estructurado antes de la siguiente llamada al LLM.
    • El LLM decide la acción (retry con modificación, pedir datos al usuario, escalar).

    Además: valida entradas con Zod/JSON Schema antes de llamar a la tool. Un buen schema reduce la superficie de errores y hace que los fallos restantes sean reales y manejables.

    Operacional: telemetría, tests y SLAs

    No sirve con tipos si no lo verificas. Tienes que medir:

    • Retries por tipo de error (P50/P95).
    • Frecuencia de errores no mapeados (build-breakers).
    • Tokens gastados en reintentos.
    • Casos escalados a humano.

    Incluye tests que simulen fallos de DB, timeouts y errores de validación. Tu pipeline debe romper si un nuevo error llega a producción sin un handler en el switch exhaustivo.

    Cierre operativo

    El try/catch genérico es cómodo. También es la razón por la que tu agente se convierte en una caja negra con facturas altas y datos rotos. Convertir errores en valores tipados (Result<T,E>) y forzar comprobaciones exhaustivas con never no es estilo: es seguridad operativa.

    Aplica esto ya, instrumenta telemetría y haz que tu build falle si alguien olvida un caso de error. En el próximo artículo mostraremos cómo serializar esos errores en memoria episódica y usar feedback estructurado para que el agente aprenda a autocorregirse sin intervención humana.

    Dominicode Labs

    Para equipos que diseñan agentes y pipelines de orquestación, es útil contar con recursos y experimentos que muestren patrones de integración entre memoria episódica y errores tipados. Continúa explorando técnicas y prototipos en Dominicode Labs para ver implementaciones prácticas y ejemplos aplicados a agentes y workflows.

    FAQ

    ¿Por qué no debo usar try/catch genéricos en agentes?

    Porque ocultan la causa raíz y priven al agente de información accionable. Un mensaje opaco lleva a reintentos inútiles o a continuar el flujo como si la acción hubiera tenido éxito.

    ¿Qué es Result<T,E> y cómo cambia la arquitectura?

    Es un patrón que devuelve un valor tipado indicando éxito o fallo ({ok: true; value} | {ok: false; error}). Obliga al consumidor a tratar explícitamente los errores y permite que orquestadores y LLMs actúen sobre causas concretas.

    ¿Cómo obliga TypeScript a manejar nuevos errores?

    Mediante comprobaciones exhaustivas usando never en un switch sobre una unión discriminada. Si se añade un nuevo caso y no se maneja, el compilador falla.

    ¿Dónde guardo los errores para que el agente los use?

    Persiste fallos en la memoria episódica (ej. Redis) y en la memoria semántica si aplica (vector DB). El orquestador debe guardar tanto éxitos como fallos para proporcionar contexto al LLM.

    ¿Qué métricas debo instrumentar primero?

    Retries por tipo de error (P50/P95), frecuencia de errores no mapeados, tokens gastados en reintentos y casos escalados a humano.

    ¿Cómo debo testear los manejadores de error?

    Incluye tests que simulen fallos de DB, timeouts y errores de validación; el pipeline debe fallar si un nuevo error llega a producción sin handler.

    ¿Qué herramientas de validación recomiendan antes de llamar a una tool?

    Valida entradas con Zod o JSON Schema para reducir la superficie de errores y asegurar que los fallos restantes sean reales y manejables.