mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
fix(workflow): validate outermost custom output object
This commit is contained in:
parent
8cc711463b
commit
813e73a0bb
1 changed files with 66 additions and 1 deletions
|
|
@ -226,6 +226,16 @@ pub(crate) fn apply_validated_output(
|
|||
|
||||
/// Find all balanced `{...}` JSON object substrings in the text.
|
||||
fn find_json_objects(text: &str) -> Vec<&str> {
|
||||
find_json_objects_with_nested(text, true)
|
||||
}
|
||||
|
||||
/// Find balanced `{...}` JSON object substrings in the text, skipping objects
|
||||
/// nested within a previous match.
|
||||
fn find_outermost_json_objects(text: &str) -> Vec<&str> {
|
||||
find_json_objects_with_nested(text, false)
|
||||
}
|
||||
|
||||
fn find_json_objects_with_nested(text: &str, include_nested: bool) -> Vec<&str> {
|
||||
let mut results = Vec::new();
|
||||
let bytes = text.as_bytes();
|
||||
let mut i = 0;
|
||||
|
|
@ -251,6 +261,9 @@ fn find_json_objects(text: &str) -> Vec<&str> {
|
|||
depth -= 1;
|
||||
if depth == 0 {
|
||||
results.push(&text[start..=j]);
|
||||
if !include_nested {
|
||||
i = j;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -334,7 +347,7 @@ fn validate_custom_response_text(
|
|||
validator: &Validator,
|
||||
text: &str,
|
||||
) -> Result<ValidatedStructuredOutput, StructuredOutputError> {
|
||||
let candidates = find_json_objects(text);
|
||||
let candidates = find_outermost_json_objects(text);
|
||||
let Some(candidate) = candidates.last() else {
|
||||
return Err(StructuredOutputError::new(
|
||||
StructuredOutputErrorKind::NoJsonObject,
|
||||
|
|
@ -558,6 +571,58 @@ mod tests {
|
|||
assert_eq!(validated.value, serde_json::json!({"passed": true}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validates_custom_schema_against_outermost_object() {
|
||||
let schema = schema(serde_json::json!({
|
||||
"type": "object",
|
||||
"required": ["issue"],
|
||||
"properties": {
|
||||
"issue": {
|
||||
"type": "object",
|
||||
"required": ["number"],
|
||||
"properties": {
|
||||
"number": { "type": "integer" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
let validated = validate_response_text(&schema, r#"{"issue":{"number":19}}"#).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
validated.value,
|
||||
serde_json::json!({"issue": {"number": 19}})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validates_last_outermost_object_when_response_has_trailing_prose() {
|
||||
let schema = schema(serde_json::json!({
|
||||
"type": "object",
|
||||
"required": ["issue"],
|
||||
"properties": {
|
||||
"issue": {
|
||||
"type": "object",
|
||||
"required": ["number"],
|
||||
"properties": {
|
||||
"number": { "type": "integer" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
let validated = validate_response_text(
|
||||
&schema,
|
||||
r#"ignore {"issue":{"number":1}} final {"issue":{"number":19}} trailing"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
validated.value,
|
||||
serde_json::json!({"issue": {"number": 19}})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_schema_validation_errors_are_reported() {
|
||||
let schema = schema(serde_json::json!({
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue