@@ -21,12 +21,13 @@ func TestParseLine_EmptyLine(t *testing.T) {
2121}
2222
2323func TestParseLine_InvalidJSON (t * testing.T ) {
24- _ , err := ParseLine ("not json at all" )
25- if err == nil {
26- t .Error ("ParseLine with invalid JSON should return error" )
24+ // Invalid JSON should be silently skipped, not return an error
25+ items , err := ParseLine ("not json at all" )
26+ if err != nil {
27+ t .Errorf ("ParseLine should skip invalid JSON, got error: %v" , err )
2728 }
28- if ! strings . Contains ( err . Error (), "failed to parse JSON" ) {
29- t .Errorf ("error should mention JSON parsing , got: %v " , err )
29+ if len ( items ) != 0 {
30+ t .Errorf ("expected 0 items for invalid JSON , got %d " , len ( items ) )
3031 }
3132}
3233
@@ -304,6 +305,47 @@ func TestFormatToolInput(t *testing.T) {
304305 }
305306}
306307
308+ func TestParseLine_UserMessageWithImage (t * testing.T ) {
309+ // User messages can contain image blocks (screenshots pasted into Claude Code)
310+ // These should be silently skipped, not cause errors
311+ line := `{"type":"user","timestamp":"2025-01-01T12:00:00Z","message":{"role":"user","content":[{"type":"image","source":{"type":"base64","media_type":"image/png","data":"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk"}}]}}`
312+ items , err := ParseLine (line )
313+ if err != nil {
314+ t .Fatalf ("ParseLine should not error on image content, got: %v" , err )
315+ }
316+ if len (items ) != 0 {
317+ t .Errorf ("expected 0 items (images skipped), got %d" , len (items ))
318+ }
319+ }
320+
321+ func TestParseLine_UserMessageWithImageAndToolResult (t * testing.T ) {
322+ // A user message can contain both image blocks and tool results
323+ line := `{"type":"user","timestamp":"2025-01-01T12:00:00Z","message":{"role":"user","content":[{"type":"image","source":{"type":"base64","media_type":"image/png","data":"iVBOR"}},{"type":"tool_result","tool_use_id":"toolu_img1","content":"tool output here"}]}}`
324+ items , err := ParseLine (line )
325+ if err != nil {
326+ t .Fatalf ("unexpected error: %v" , err )
327+ }
328+ if len (items ) != 1 {
329+ t .Fatalf ("expected 1 item (tool_result only), got %d" , len (items ))
330+ }
331+ if items [0 ].Content != "tool output here" {
332+ t .Errorf ("content = %q, want %q" , items [0 ].Content , "tool output here" )
333+ }
334+ }
335+
336+ func TestParseLine_TruncatedJSON (t * testing.T ) {
337+ // When a JSONL line exceeds the scanner buffer, it gets truncated
338+ // producing invalid JSON. This should be skipped gracefully, not crash.
339+ truncated := `{"type":"user","timestamp":"2025-01-01T12:00:00Z","message":{"role":"user","content":[{"type":"image","source":{"type":"base64","media_type":"image/png","data":"JVBER`
340+ items , err := ParseLine (truncated )
341+ if err != nil {
342+ t .Fatalf ("ParseLine should gracefully skip truncated JSON, got error: %v" , err )
343+ }
344+ if len (items ) != 0 {
345+ t .Errorf ("expected 0 items for truncated JSON, got %d" , len (items ))
346+ }
347+ }
348+
307349// buildAssistantLine builds a valid JSONL line for an assistant tool_use message
308350func buildAssistantLine (t * testing.T , toolName , toolID string , inputJSON json.RawMessage ) string {
309351 t .Helper ()
0 commit comments