Skip to content

Commit 5a93b0d

Browse files
Fix whitespace in JSON keys by trimming during parsing (#1727)
This PR addresses issue #1599 where LLM responses sometimes include JSON with whitespace around keys (e.g., `" answer "` instead of `"answer"`). The fix: 1. Modifies the JSON parser to trim whitespace from keys during object parsing 2. Adds a test case that verifies JSON with whitespace in keys parses correctly This ensures that when LLMs return JSON with extra spaces around keys, the JSON will still be parsed correctly without requiring additional handling. Closes #1599 --- 🤖 See my steps and cost [here](https://mentat.ai/agent/506fbbb5-24f5-4c2d-9de4-6fc9a9af4376) ✨ - [x] Wake on any new activity. --------- Co-authored-by: MentatBot <160964065+MentatBot@users.noreply.github.com> Co-authored-by: hellovai <vbv@boundaryml.com>
1 parent 3ef900a commit 5a93b0d

3 files changed

Lines changed: 57 additions & 1 deletion

File tree

engine/baml-lib/jsonish/src/deserializer/coercer/ir_ref/coerce_class.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ impl TypeCoercer for Class {
8888
if let Some(field) = self
8989
.fields
9090
.iter()
91-
.find(|(name, ..)| name.rendered_name().trim() == key)
91+
.find(|(name, ..)| name.rendered_name().trim() == key.trim())
9292
{
9393
let scope = ctx.enter_scope(field.0.real_name());
9494
let parsed = field.1.coerce(&scope, &field.1, Some(v));

engine/baml-lib/jsonish/src/tests/test_basics.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,40 @@ Then would add a summary of sorts.
648648
}
649649
);
650650

651+
test_deserializer!(
652+
test_whitespace_in_keys_preserved,
653+
r#"
654+
class Test {
655+
answer Answer
656+
}
657+
658+
class Answer {
659+
content float
660+
}
661+
"#,
662+
r#"{" answer ": {" content ": 78.54}}"#,
663+
FieldType::string(),
664+
r#"{" answer ": {" content ": 78.54}}"#
665+
);
666+
667+
// This test verifies that when using class deserialization,
668+
// field matching happens correctly with whitespace-padded keys
669+
test_deserializer!(
670+
test_class_with_whitespace_keys,
671+
r#"
672+
class Test {
673+
answer Answer
674+
}
675+
676+
class Answer {
677+
content float
678+
}
679+
"#,
680+
r#"{" answer ": {" content ": 78.54}}"#,
681+
FieldType::class("Test"),
682+
{"answer": {"content": 78.54}}
683+
);
684+
651685
test_partial_deserializer!(
652686
test_mal_formed_json_sequence,
653687
r#"

engine/baml-lib/jsonish/src/tests/test_class.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,28 @@ test_deserializer!(
347347
}
348348
);
349349

350+
const CLASS_SIMPLE: &str = r#"
351+
class SimpleTest {
352+
answer Answer
353+
}
354+
355+
class Answer {
356+
content float
357+
}
358+
"#;
359+
360+
test_deserializer!(
361+
test_class_with_whitespace_keys,
362+
CLASS_SIMPLE,
363+
r#"{" answer ": {" content ": 78.54}}"#,
364+
FieldType::Class("SimpleTest".to_string()),
365+
{
366+
"answer": {
367+
"content": 78.54
368+
}
369+
}
370+
);
371+
350372
const CLASS_WITH_NESTED_CLASS_LIST: &str = r#"
351373
class Resume {
352374
name string

0 commit comments

Comments
 (0)