swarm_cli 2.1.2 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce573683afe4e8fbb1d144984c0b476db2dac070f490a62b0b1e3b7b32a3622e
4
- data.tar.gz: e4b3a5f950a7c007ed543f00d55603b17fad3db31748a4fdce6348de680764e7
3
+ metadata.gz: de6df6703665661e75ad0727c187c8fd20c1711b3dc24864bba27a4b9dd26ee1
4
+ data.tar.gz: 2c58cabd8e53712d73e51df8492cbef03a2b1c34b68021b162ed57e0c8e8402d
5
5
  SHA512:
6
- metadata.gz: 53f75f25ffe8d8a531db038274fc1d5853a56271215eacded92dba259737f3cc2f3d61e9dd9cd20b8c8273884a7156638e6646b58fccd44ece644637a362ba16
7
- data.tar.gz: 9298ef6cda98c97db7ff9fea9c5f2176a2285dbcc74a24ef729f43ac2cca04a803f3a9d38aed68f8900c45c95f2697c24038e96909362c25e0b932ebaab3d5eb
6
+ metadata.gz: a23fd6ace54fbbf1e61170f8c39752bb4e547d01f3870cd54b00ff1064a490cbd426b19e5a0b2e9b3bd6fac44f5e67244e54aa86820053d87ca9e2ce80a64ca2
7
+ data.tar.gz: 463832c8cea0a8abdf252aa6485e0c70343e3ea4df6de37ba7addaa4e52bd41974425721415ce878ef5fe6b267ac067cb4cacb6b8e91e2d39fff2344c29f24f5
@@ -95,11 +95,20 @@ module SwarmCLI
95
95
  handle_breakpoint_enter(entry)
96
96
  when "breakpoint_exit"
97
97
  handle_breakpoint_exit(entry)
98
+ when "llm_retry_attempt"
99
+ handle_llm_retry_attempt(entry)
100
+ when "llm_retry_exhausted"
101
+ handle_llm_retry_exhausted(entry)
102
+ when "response_parse_error"
103
+ handle_response_parse_error(entry)
98
104
  end
99
105
  end
100
106
 
101
107
  # Called when swarm execution completes successfully
102
108
  def on_success(result:)
109
+ # Defensive: ensure all spinners are stopped before showing result
110
+ @spinner_manager.stop_all
111
+
103
112
  if @mode == :non_interactive
104
113
  # Full result display with summary
105
114
  @output.puts
@@ -115,6 +124,9 @@ module SwarmCLI
115
124
 
116
125
  # Called when swarm execution fails
117
126
  def on_error(error:, duration: nil)
127
+ # Defensive: ensure all spinners are stopped before showing error
128
+ @spinner_manager.stop_all
129
+
118
130
  @output.puts
119
131
  @output.puts @divider.full
120
132
  print_error(error)
@@ -575,6 +587,97 @@ module SwarmCLI
575
587
  @output.puts
576
588
  end
577
589
 
590
+ def handle_llm_retry_attempt(entry)
591
+ agent = entry[:agent]
592
+ attempt = entry[:attempt]
593
+ max_retries = entry[:max_retries]
594
+ error_class = entry[:error_class]
595
+ error_message = entry[:error_message]
596
+ retry_delay = entry[:retry_delay]
597
+
598
+ # Stop agent thinking spinner (if active)
599
+ unless @quiet
600
+ spinner_key = "agent_#{agent}".to_sym
601
+ @spinner_manager.stop(spinner_key) if @spinner_manager.active?(spinner_key)
602
+ end
603
+
604
+ lines = [
605
+ @pastel.yellow("LLM API request failed (attempt #{attempt}/#{max_retries})"),
606
+ @pastel.dim("Error: #{error_class}: #{error_message}"),
607
+ @pastel.dim("Retrying in #{retry_delay}s..."),
608
+ ]
609
+
610
+ @output.puts @panel.render(
611
+ type: :warning,
612
+ title: "RETRY #{@agent_badge.render(agent)}",
613
+ lines: lines,
614
+ indent: @depth_tracker.get(agent),
615
+ )
616
+
617
+ # Restart spinner for next attempt
618
+ unless @quiet
619
+ spinner_key = "agent_#{agent}".to_sym
620
+ @spinner_manager.start(spinner_key, "#{agent} is retrying...")
621
+ end
622
+ end
623
+
624
+ def handle_llm_retry_exhausted(entry)
625
+ agent = entry[:agent]
626
+ attempts = entry[:attempts]
627
+ error_class = entry[:error_class]
628
+ error_message = entry[:error_message]
629
+
630
+ # Stop agent thinking spinner (if active)
631
+ unless @quiet
632
+ spinner_key = "agent_#{agent}".to_sym
633
+ @spinner_manager.stop(spinner_key) if @spinner_manager.active?(spinner_key)
634
+ end
635
+
636
+ lines = [
637
+ @pastel.red("LLM API request failed after #{attempts} attempts"),
638
+ @pastel.dim("Error: #{error_class}: #{error_message}"),
639
+ @pastel.dim("No more retries available"),
640
+ ]
641
+
642
+ @output.puts @panel.render(
643
+ type: :error,
644
+ title: "RETRY EXHAUSTED #{@agent_badge.render(agent)}",
645
+ lines: lines,
646
+ indent: @depth_tracker.get(agent),
647
+ )
648
+ end
649
+
650
+ def handle_response_parse_error(entry)
651
+ agent = entry[:agent]
652
+ error_class = entry[:error_class]
653
+ error_message = entry[:error_message]
654
+
655
+ # Stop agent thinking spinner (if active)
656
+ unless @quiet
657
+ spinner_key = "agent_#{agent}".to_sym
658
+ @spinner_manager.stop(spinner_key) if @spinner_manager.active?(spinner_key)
659
+ end
660
+
661
+ lines = [
662
+ @pastel.red("Failed to parse LLM API response"),
663
+ @pastel.dim("Error: #{error_class}: #{error_message}"),
664
+ ]
665
+
666
+ # Add response body preview if available (truncated)
667
+ if entry[:response_body]
668
+ body_preview = entry[:response_body].to_s[0..200]
669
+ body_preview += "..." if entry[:response_body].to_s.length > 200
670
+ lines << @pastel.dim("Response: #{body_preview}")
671
+ end
672
+
673
+ @output.puts @panel.render(
674
+ type: :error,
675
+ title: "PARSE ERROR #{@agent_badge.render(agent)}",
676
+ lines: lines,
677
+ indent: @depth_tracker.get(agent),
678
+ )
679
+ end
680
+
578
681
  def display_todo_list(agent, timestamp)
579
682
  todos = SwarmSDK::Tools::Stores::TodoManager.get_todos(agent.to_sym)
580
683
  indent = @depth_tracker.indent(agent)
@@ -81,6 +81,9 @@ module SwarmCLI
81
81
  display_session_summary
82
82
  exit(130)
83
83
  ensure
84
+ # Defensive: ensure all spinners are stopped on exit
85
+ @formatter&.spinner_manager&.stop_all
86
+
84
87
  # Save history on exit
85
88
  save_persistent_history
86
89
  end
@@ -432,11 +435,12 @@ module SwarmCLI
432
435
  end
433
436
  end
434
437
 
438
+ # CRITICAL: Stop all spinners after execution completes
439
+ # This ensures spinner doesn't interfere with error/success display or REPL prompt
440
+ @formatter.spinner_manager.stop_all
441
+
435
442
  # Handle cancellation (result is nil when cancelled)
436
443
  if result.nil?
437
- # Stop all active spinners
438
- @formatter.spinner_manager.stop_all
439
-
440
444
  puts ""
441
445
  puts @colors[:warning].call("✗ Request cancelled by user")
442
446
  puts ""
@@ -459,6 +463,8 @@ module SwarmCLI
459
463
  # Add response to history
460
464
  @conversation_history << { role: "agent", content: result.content }
461
465
  rescue StandardError => e
466
+ # Defensive: ensure spinners are stopped on exception
467
+ @formatter.spinner_manager.stop_all
462
468
  @formatter.on_error(error: e)
463
469
  end
464
470
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SwarmCLI
4
- VERSION = "2.1.2"
4
+ VERSION = "2.1.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swarm_cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paulo Arruda
@@ -43,14 +43,14 @@ dependencies:
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '2.1'
46
+ version: '2.2'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '2.1'
53
+ version: '2.2'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: tty-box
56
56
  requirement: !ruby/object:Gem::Requirement