Skip to main content

Validate, repair, retry LLM structured output (JSON/YAML/TOML/python-literal)

Project description

arcanada-output-guard

PyPI Python License: MIT

Validate, repair, and retry LLM structured output (JSON / YAML / TOML / Python literal) — battle-tested 15-strategy repair chain with two-pass orchestrator. Python sibling of @arcanada/output-guard with shared golden fixtures and byte-equal parity gate.

Install

pip install arcanada-output-guard
# or
uv add arcanada-output-guard
# or
poetry add arcanada-output-guard

Requires Python ≥ 3.11. Runtime deps: pyyaml, tomli-w, pydantic, jsonschema, json-repair.

Quick start

from output_guard import repair

# Functional API — format-only repair, no schema
result = repair('{"name": "Alice", "age": 30,}', "json")

print(result.data)                  # {'name': 'Alice', 'age': 30}
print(result.repaired)              # True
print(result.pass_)                 # 'A'
print(result.strategies_applied)    # ['fix-commas']

Stateful API with pydantic schema

from pydantic import BaseModel
from output_guard import OutputGuard

class User(BaseModel):
    name: str
    age: int

guard = OutputGuard(format="json", schema=User)
result = guard.repair('```json\n{"name": "Bob", "age": 25}\n```')

print(result.data)               # User(name='Bob', age=25)
print(result.pass_)              # 'A' or 'B'

Output format support

  • JSON — strict + relaxed parsing with common error recovery (trailing commas, unquoted keys, single→double quote, true/false casing, fenced blocks).
  • YAML — structural repair for indentation + missing keys.
  • TOML — fixing malformed tables and value assignments.
  • Python literaldict / list literals via safe ast.literal_eval.
  • Auto-detect — pass format="auto" to infer from content.

RepairResult semantics

@dataclass(frozen=True, slots=True)
class RepairResult:
    repaired: bool                       # False when raw was already valid
    raw: str                             # original input as supplied
    pass_: Literal["A", "B"]             # "A" = combined-apply; "B" = isolating fallback
    data: Any = None                     # parsed + (optionally) schema-validated payload
    strategies_applied: list[str] = []   # ordered list of repair strategies invoked

MAX_RETRIES exhaustion signals via ParseError raise, not via a pass_ value.

Async wrapper for LLM calls

import asyncio
from pydantic import BaseModel
from output_guard import guarded_generate, GuardedGenerateOptions

class Answer(BaseModel):
    result: int

async def my_llm(prompt: str, history=None) -> str:
    # call your LLM client here (OpenAI / Anthropic / OpenRouter / MC / etc.)
    return '{"result": 42}'

async def main():
    out = await guarded_generate(GuardedGenerateOptions(
        generate=my_llm,
        prompt='Return JSON {"result": <integer>}',
        schema=Answer,
        fmt="json",
        max_retries=3,
    ))
    print(out.data)                  # Answer(result=42)
    print(out.pass_)                 # 'A' | 'B'
    print(out.strategies_applied)

asyncio.run(main())

Error handling

from output_guard import (
    ParseError,
    SchemaValidationError,
    RepairError,
    GuardedGenerationError,
)

try:
    result = guard.repair(bad_input)
except SchemaValidationError:
    ...  # input parsed but doesn't satisfy schema
except ParseError:
    ...  # MAX_RETRIES exhausted — all strategies failed
except RepairError:
    ...  # a repair strategy itself raised
except GuardedGenerationError:
    ...  # guarded_generate gave up after max_retries LLM round-trips

Schema adapters

from output_guard import pydantic_adapter, jsonschema_adapter
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

# pydantic v2
adapter = pydantic_adapter(User)

# JSON Schema (dict)
adapter = jsonschema_adapter({
    "type": "object",
    "properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
    "required": ["name", "age"],
})

Batch API

from output_guard import repair_batch

results = repair_batch(
    ['{"a": 1,}', '{"b": 2,}', '{"c": 3,}'],
    fmt="json",
)
# returns list[RepairResult]; per-item failure surfaces as RepairResult with repaired=False

Documentation

License

MIT — see LICENSE.


Жизнь одного человека имеет значение / One human life matters

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

arcanada_output_guard-0.1.2.tar.gz (49.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

arcanada_output_guard-0.1.2-py3-none-any.whl (26.1 kB view details)

Uploaded Python 3

File details

Details for the file arcanada_output_guard-0.1.2.tar.gz.

File metadata

  • Download URL: arcanada_output_guard-0.1.2.tar.gz
  • Upload date:
  • Size: 49.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for arcanada_output_guard-0.1.2.tar.gz
Algorithm Hash digest
SHA256 e26eb34bb844674cb130ddeceaa58209e5a9ba150797f4100427cf178eb072da
MD5 3b6a5ba14f727a7f7815f177d9abe63b
BLAKE2b-256 1d821d436a5b3de98ec9a9a4cb615375f0e69df846059cec8c2203dfa252d2cb

See more details on using hashes here.

Provenance

The following attestation bundles were made for arcanada_output_guard-0.1.2.tar.gz:

Publisher: publish-pypi.yml on Arcanada-one/output-guard

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file arcanada_output_guard-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for arcanada_output_guard-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 9e1567ebc16673c6ca63b8a8d19fc8cce5c65a6adc6197ad5440415d3a1fbfc3
MD5 c19d426d5cb5da06c8dba559a51c0e47
BLAKE2b-256 c042f9555e44341692064de50d06ca6a7c22d6a6e290f40c729285d8c8a51e3a

See more details on using hashes here.

Provenance

The following attestation bundles were made for arcanada_output_guard-0.1.2-py3-none-any.whl:

Publisher: publish-pypi.yml on Arcanada-one/output-guard

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page