MCPcopy Index your code
hub / github.com/mudler/LocalAI / ParseJSONIterative

Function ParseJSONIterative

pkg/functions/parse.go:327–378  ·  view source on GitHub ↗

ParseJSONIterative parses JSON using the iterative parser Supports partial parsing for streaming scenarios Returns objects and arrays (matching llama.cpp behavior)

(s string, isPartial bool)

Source from the content-addressed store, hash-verified

325// Supports partial parsing for streaming scenarios
326// Returns objects and arrays (matching llama.cpp behavior)
327func ParseJSONIterative(s string, isPartial bool) ([]map[string]any, error) {
328 parser := NewChatMsgParser(s, isPartial)
329 var results []map[string]any
330
331 // Try to parse JSON values one by one
332 for parser.Pos() < len(parser.Input()) {
333 jsonValue, isPartialJSON, _, err := parser.TryConsumeJSON()
334 if err != nil {
335 // If it's a partial exception and we're in partial mode, return what we have
336 if _, ok := err.(*ChatMsgPartialException); ok && isPartial {
337 break
338 }
339 // For non-partial errors or when not in partial mode, try legacy parsing
340 return parseJSONLegacy(s)
341 }
342 if jsonValue != nil {
343 // Convert to map[string]any if it's an object, or handle arrays
344 if obj, ok := jsonValue.(map[string]any); ok {
345 // Skip stub objects that healed away to nothing. Partial inputs
346 // like `{`, `{"`, or `{"n` go through parseJSONWithStack and
347 // come back as `{"<marker>":1}`; after removeHealingMarkerFromJSON
348 // drops the marker key the map is empty. Returning it as a
349 // real result trips the streaming tool-call detector
350 // (chat_stream_workers.go) into thinking a tool call landed,
351 // gating off content emission for the rest of the stream
352 // (issue #9988).
353 if !(isPartialJSON && len(obj) == 0) {
354 results = append(results, obj)
355 }
356 } else if arr, ok := jsonValue.([]any); ok {
357 // Handle arrays: extract objects from array
358 for _, item := range arr {
359 if obj, ok := item.(map[string]any); ok {
360 results = append(results, obj)
361 }
362 }
363 }
364 }
365 if isPartialJSON {
366 break
367 }
368 // Skip whitespace between JSON values
369 parser.ConsumeSpaces()
370 }
371
372 if len(results) > 0 {
373 return results, nil
374 }
375
376 // Fallback to legacy parsing if iterative parser found nothing
377 return parseJSONLegacy(s)
378}
379
380// parseJSONLegacy is the original decoder-based JSON parsing (kept for compatibility)
381func parseJSONLegacy(s string) ([]map[string]any, error) {

Callers 4

processStreamWithToolsFunction · 0.92
parse_test.goFile · 0.85
ParseJSONFunction · 0.85

Calls 6

PosMethod · 0.95
InputMethod · 0.95
TryConsumeJSONMethod · 0.95
ConsumeSpacesMethod · 0.95
NewChatMsgParserFunction · 0.85
parseJSONLegacyFunction · 0.85

Tested by

no test coverage detected