simple-agents-healing
Response healing system for SimpleAgents - BAML-inspired JSON parsing and type coercion.
Overview
This crate implements a sophisticated JSON healing system that handles malformed LLM outputs. Instead of failing on broken JSON, it tracks all transformations via a flag system and provides confidence scores, making LLM integrations robust in production.
Features
🔧 Three-Phase Parsing
-
Strip & Fix: Quick string transformations
- Remove markdown code fences (`````json ... ```)
- Fix trailing commas (
{...,}→{...}) - Normalize quotes (
'...'→"...") - Remove BOM and control characters
- Fix unquoted keys (optional with
regex-supportfeature)
-
Standard Parse: Fast path using
serde_json- If JSON is valid after Strip & Fix, use standard parser
- Optimal performance for slightly malformed inputs
-
Lenient Parse: State machine for deeply broken JSON
- Character-by-character parsing
- Auto-close unclosed structures
- Handle incomplete streaming responses
- Truncate to last valid object/array
📊 Confidence Scoring
Every parse result includes a confidence score (0.0-1.0):
- 1.0: Perfect JSON, no healing needed
- 0.95-0.99: Minor fixes (markdown, trailing commas)
- 0.85-0.94: Quote normalization or simple fixes
- 0.70-0.84: Type coercion or truncation
- <0.70: Significant healing required
🏷️ Transparency via Flags
All transformations are tracked with CoercionFlag:
StrippedMarkdown- Removed code fencesFixedTrailingComma- Removed trailing commasFixedQuotes- Normalized single quotes to doubleFixedUnquotedKeys- Added quotes to object keysFixedControlCharacters- Removed control charactersRemovedBom- Removed byte order markTruncatedJson- Truncated incomplete JSON
Usage
Basic Example
use *;
let parser = new;
// Parse markdown-wrapped JSON
let malformed = r#"```json
{"name": "Alice", "age": 30,}
```"#;
let result = parser.parse?;
// Access parsed value
assert_eq!;
assert_eq!;
// Check confidence and flags
assert!;
assert!;
assert!;
Custom Configuration
use *;
let config = ParserConfig ;
let parser = with_config;
let result = parser.parse?;
Confidence Thresholds
use *;
let strict_config = ParserConfig ;
let parser = with_config;
match parser.parse
Examples
Run the included examples:
# Basic healing demonstration
Testing
# Run all tests
# Run with coverage
# Run clippy
Architecture
Parser Components
Input String
↓
┌─────────────────────┐
│ Strip & Fix Phase │ ← Remove markdown, fix commas, quotes
└─────────────────────┘
↓
┌─────────────────────┐
│ Standard Parse │ ← Try serde_json (fast path)
└─────────────────────┘
↓ (if fails)
┌─────────────────────┐
│ Lenient Parse │ ← State machine for broken JSON
└─────────────────────┘
↓
CoercionResult<Value>
Flag System
Every transformation is tracked:
Confidence Calculation
confidence = 1.0
*
*
*
*
*
Future Features
Week 6 (Planned)
-
Coercion Engine: Type coercion with schema validation
- String → Number coercion
- Fuzzy field matching (case-insensitive, snake_case ↔ camelCase)
- Union resolution with best-match selection
- Default value injection
-
Streaming Parser: Incremental parsing
- Partial value extraction from incomplete buffers
- Progressive emission during streaming
- Annotation support (
stream.not_null,stream.done)
Performance
- Fast path: Standard
serde_jsonfor valid JSON after Strip & Fix - Zero allocations: In-place string transformations where possible
- Minimal overhead: Flags are small enums, confidence is a single f32
Safety
- No unsafe code: 100% safe Rust
- No panics: All errors are
Resulttypes - Send + Sync: Parser can be shared across threads
Credits
Inspired by BAML's Jsonish parser and coercion system.
License
MIT OR Apache-2.0