-
Notifications
You must be signed in to change notification settings - Fork 406
fix(analyzer): handle Claude CLI JSON array output format #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(analyzer): handle Claude CLI JSON array output format #114
Conversation
Claude Code CLI outputs a JSON array instead of a single object:
[{type: "system", ...}, {type: "assistant", ...}, {type: "result", ...}]
This caused parse_json_response to fail with "jq: invalid JSON text"
because it assumed the top-level JSON was an object.
Changes:
- Detect if JSON is an array before parsing
- Extract the "result" type message from the array
- Preserve session_id from init message for continuity
- Normalize to object format for existing parsing logic
- Clean up temporary file after processing
Fixes frankbria#112
Co-Authored-By: Claude <[email protected]>
WalkthroughThis PR introduces support for Claude CLI JSON array output format in v0.10.1. It modifies the JSON parsing logic to detect array inputs, extract result objects, merge session IDs from init messages, and adds comprehensive test coverage for the new format handling. Changes
Sequence DiagramsequenceDiagram
participant Input as JSON Input<br/>(File)
participant Validator as JSON Validator
participant Detector as Format Detector
participant Extractor as Array Handler
participant Merger as Session ID Merger
participant Parser as JSON Parser
participant Output as Output<br/>(File)
Input->>Validator: Pass input file
Validator->>Validator: Validate JSON syntax
alt Invalid JSON
Validator->>Output: Error exit
else Valid JSON
Validator->>Detector: JSON is valid
Detector->>Detector: Check if array or object
alt Is JSON Array (Claude CLI format)
Detector->>Extractor: Array detected
Extractor->>Extractor: Extract "result" type object
Extractor->>Merger: Pass extracted result
Merger->>Merger: Query array for "system init"<br/>session_id
alt Session ID found in init message
Merger->>Merger: Create temp file with<br/>merged session_id
Merger->>Parser: Use normalized temp file
else No Session ID in init
Merger->>Parser: Use extracted result
end
else Is JSON Object (Standard format)
Detector->>Parser: Use original file
end
Parser->>Parser: Parse fields (status,<br/>metadata, result, etc.)
Parser->>Output: Write parsed result
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Add JSON array support to
|
|
|
||
| # Extract the "result" type message from the array (usually the last entry) | ||
| # This contains: result, session_id, is_error, duration_ms, etc. | ||
| local result_obj=$(jq '[.[] | select(.type == "result")] | .[-1] // {}' "$output_file" 2>/dev/null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If jq on line 85 fails, result_obj becomes empty and you then write invalid JSON. Consider guarding that result_obj is non-empty (default to {}) before echoing.
local result_obj=$(jq '[.[] | select(.type == "result")] | .[-1] // {}' "$output_file" 2>/dev/null)
+ [[ -z "$result_obj" ]] && result_obj="{}"🚀 Want me to fix this? Reply ex: "fix it for me".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/response_analyzer.sh (1)
65-99: Prioritize result object's session_id field to prevent session ID loss during array normalization.The normalization logic at lines 84–91 unconditionally injects the init message's
session_idassessionId, but never maps a result object's ownsession_idfield (which per code comments contains "result, session_id, is_error, duration_ms, etc.") into the normalizedsessionIdfield. Sinceparse_json_responselater extracts only.sessionId // .metadata.session_id // ""and does not check for.session_id, arrays that lack an init message withsession_idwill lose the result's session ID, breaking session continuity.🔧 Suggested fix
# Build normalized object merging result with session_id - if [[ -n "$init_session_id" && "$init_session_id" != "null" ]]; then - echo "$result_obj" | jq --arg sid "$init_session_id" '. + {sessionId: $sid}' > "$normalized_file" - else - echo "$result_obj" > "$normalized_file" - fi + local effective_session_id + effective_session_id=$(echo "$result_obj" | jq -r '.sessionId // .session_id // empty' 2>/dev/null) + if [[ -z "$effective_session_id" ]]; then + effective_session_id="$init_session_id" + fi + + if [[ -n "$effective_session_id" && "$effective_session_id" != "null" ]]; then + echo "$result_obj" | jq --arg sid "$effective_session_id" '. + {sessionId: $sid} | del(.session_id)' > "$normalized_file" + else + echo "$result_obj" | jq 'del(.session_id)' > "$normalized_file" + fi
🧹 Nitpick comments (1)
tests/unit/test_json_parsing.bats (1)
741-898: Add a regression case for arrays where only the result element carries the session id.Current array tests cover init-derived session IDs, but not the variant where the result element includes
session_id/sessionIdand no init message. A small test would lock in the normalization behavior and prevent future regressions.
|
Code review fixes applied during merge:
All 319 tests pass. Thanks for the contribution! 🎉 |
Summary
Fixes #112
The
parse_json_responsefunction inlib/response_analyzer.shwas failing when processing Claude Code CLI output because it assumed a single JSON object, but Claude CLI outputs a JSON array:[ {"type": "system", "subtype": "init", "session_id": "..."}, {"type": "assistant", "message": {...}}, {"type": "result", "subtype": "success", "result": "...", "is_error": false} ]This caused Ralph to crash after Loop #1 with
jq: invalid JSON text passed to --argjson.Changes
jq -e 'type == "array"'Files Changed
lib/response_analyzer.sh- JSON array format detection and normalization (+30 lines)tests/unit/test_json_parsing.bats- 8 new tests for array format handling (+158 lines)CLAUDE.md- Documentation updates (version, test count, recent improvements)Test Plan
detect_output_format identifies JSON array as jsonparse_json_response handles Claude CLI JSON array formatparse_json_response extracts session_id from Claude CLI array init messageparse_json_response handles empty array gracefullyparse_json_response handles array without result type messageparse_json_response extracts is_error from Claude CLI array resultanalyze_response handles Claude CLI JSON array and extracts signalsanalyze_response persists session_id from Claude CLI array format🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Tests
✏️ Tip: You can customize this high-level summary in your review settings.