parseJSONWithStack parses JSON with stack tracking, matching llama.cpp's common_json_parse Returns the parsed JSON value, whether it was healed, and any error
(input string, healingMarker string)
| 35 | // parseJSONWithStack parses JSON with stack tracking, matching llama.cpp's common_json_parse |
| 36 | // Returns the parsed JSON value, whether it was healed, and any error |
| 37 | func parseJSONWithStack(input string, healingMarker string) (any, bool, string, error) { |
| 38 | if healingMarker == "" { |
| 39 | // No healing marker, just try to parse normally |
| 40 | var result any |
| 41 | if err := json.Unmarshal([]byte(input), &result); err != nil { |
| 42 | return nil, false, "", err |
| 43 | } |
| 44 | return result, false, "", nil |
| 45 | } |
| 46 | |
| 47 | // Try to parse complete JSON first |
| 48 | var result any |
| 49 | if err := json.Unmarshal([]byte(input), &result); err == nil { |
| 50 | return result, false, "", nil |
| 51 | } |
| 52 | |
| 53 | // Parsing failed, need to track stack and heal |
| 54 | errLoc := &JSONErrorLocator{ |
| 55 | position: 0, |
| 56 | foundError: false, |
| 57 | stack: make([]JSONStackElement, 0), |
| 58 | } |
| 59 | |
| 60 | // Parse with stack tracking to find where error occurs |
| 61 | errorPos, err := parseJSONWithStackTracking(input, errLoc) |
| 62 | if err == nil && !errLoc.foundError { |
| 63 | // No error found, should have parsed successfully |
| 64 | var result any |
| 65 | if err := json.Unmarshal([]byte(input), &result); err != nil { |
| 66 | return nil, false, "", err |
| 67 | } |
| 68 | return result, false, "", nil |
| 69 | } |
| 70 | |
| 71 | if !errLoc.foundError || len(errLoc.stack) == 0 { |
| 72 | // Can't heal without stack information |
| 73 | return nil, false, "", errors.New("incomplete JSON") |
| 74 | } |
| 75 | |
| 76 | // Build closing braces/brackets from stack |
| 77 | closing := "" |
| 78 | for i := len(errLoc.stack) - 1; i >= 0; i-- { |
| 79 | el := errLoc.stack[i] |
| 80 | if el.Type == JSONStackElementObject { |
| 81 | closing += "}" |
| 82 | } else if el.Type == JSONStackElementArray { |
| 83 | closing += "]" |
| 84 | } |
| 85 | // Keys don't add closing characters |
| 86 | } |
| 87 | |
| 88 | // Get the partial input up to error position |
| 89 | partialInput := input |
| 90 | if errorPos > 0 && errorPos < len(input) { |
| 91 | partialInput = input[:errorPos] |
| 92 | } |
| 93 | |
| 94 | // Find last non-space character |
no test coverage detected