Self-Healing Structured Outputs and Saga-Backed Tool Calls for LLMs with @siglo/ai
Shipping an LLM feature in a prototype takes 20 lines of fetch(). Shipping that same LLM feature in a transactional backend service immediately hits four reliability walls:
- Malformed Structured Outputs: Even with JSON mode enabled, models occasionally violate domain constraints (e.g., returning a negative refund amount or missing a required enum field). If you just call
JSON.parse(), your request crashes. - Provider Outages & Rate Limits: When Anthropic returns a
529 Overloadedor OpenAI hits a429rate limit, your workflow needs to fail over cleanly to a secondary provider without losing prompt context or blowing past your request deadline. - Uncompensated Tool Side Effects: When an LLM agent calls two tools in sequence—say,
reserveInventoryfollowed byissueRefund—and then fails on the final step, standard AI SDKs leave the first tool’s database mutation dangling in production. - SSRF & Unrestricted Network Egress: Giving an LLM agent arbitrary tool-execution capabilities without step-level network egress policies is a security incident waiting to happen.
@siglo/ai on top of the Siglo workflow runtime to solve these exact failure modes: turning LLM calls and agentic tool loops into self-healing, Saga-compensated, and network-sandboxed workflow steps.
1. Self-Healing Structured Outputs (maxRepairAttempts + Standard Schema)
@siglo/ai accepts any validator that implements the Standard Schema (StandardSchemaV1) specification—including Zod, Valibot, and ArkType.
When you pass a schema to aiStep(), two things happen automatically:
- Preflight Native Schema Enforcement: Before sending the request,
@siglo/aiextracts the JSON Schema to enforce native structured outputs on providers that support it (OpenAI, Anthropic, Gemini, Ollama). - Bounded Self-Healing Repair Loop: When the model responds,
@siglo/aiparses the JSON and validates it against yourStandardSchemaV1validator. If validation fails andrepairs < maxRepairAttempts,@siglo/aidoes not throw immediately—it appends the assistant’s invalid output and the exact schema validation diagnostics back into the conversation history:
$ai:
maxRepairAttempts are exhausted, @siglo/ai throws a typed AiOutputValidationError containing the structured validation diagnostics.
2. Step-as-Tool: Bringing LIFO Saga Rollbacks to LLM Tool Calls (defineAiTool)
In most AI frameworks, a “tool” is just an arbitrary async callback. If an LLM calls a tool that mutates state (creates a Jira ticket, reserves stock, or issues a credit) and a subsequent step in the workflow fails, you have no built-in way to roll back the tool’s side effects.
In @siglo/ai, every AI tool is a full @siglo/core Step.
When you wrap a Step with defineAiTool():
- Batch Pre-Validation Before Side Effects: If the model emits multiple tool calls in a single turn,
@siglo/aivalidates the tool names, call IDs, andinputSchemapayloads for the entire batch before executing the first side effect (packages/ai/src/step.ts). - Parent Saga Registration: Each tool executes via
Step.start(tool.step, input, { stackId, ... }), binding its.compensate()handler directly to the parent workflow’s execution stack.
AiStep: if an aiStep is configured with tools, @siglo/ai explicitly forbids step-level .cache(), .onFail() retries, or .idempotent() replay on the outer aiStep (TypeError: AI steps with tools cannot use caching, retries, failure recovery or idempotent replay), preventing accidental duplicate tool executions while keeping individual tool steps and parent Sagas in full control.
3. Automatic Zero-Trust Network Egress Policies
When you instantiate anAiStep, it automatically computes a least-privilege network egress allowlist (this.allowNetwork(...)) consisting only of:
- The hostnames of the configured primary
modelandfallbackModels(e.g.,api.anthropic.com,api.openai.com). - Any hosts explicitly allowed by the attached
tools(tool.step.networkPolicyConfig?.allowedHosts).
Step.installNetworkInterceptors(), neither the AI step nor any tool invoked during the agent loop can make unauthorized outbound requests to internal metadata services (169.254.169.254), private VPC subnets, or unapproved third-party domains.
4. Built-In Token Cost & Latency Telemetry ($ai)
Every aiStep returns an AiStepResult<TOutput> that merges your parsed schema output alongside a non-enumerable $ai metrics summary (and emits OpenTelemetry GenAI semantic conventions plus live @siglo/monitor inspection cards):
Try @siglo/ai
- AI Adapter Documentation: AI & Agentic Inference
- Source Code:
packages/ai/src/
