girb 0.3.0 → 0.3.1

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: 3fb74de93bd206f42859682f712f57bf0603c2348e665775b6c19833af65fd1f
4
- data.tar.gz: af6f430afff9ca6123bddfc4a87820956cbff3fda65721d86f39f5ad688cdea5
3
+ metadata.gz: c2d2144162ffe9fabd66b1a4eebab7854ad593e210d3dda57714dec1ba3e4ae6
4
+ data.tar.gz: 81ef617d448595e2d83367ae3799680b178b7e6d2967997806715990b441972e
5
5
  SHA512:
6
- metadata.gz: 8998f2942d8cf0ed23012c65dbede91b88231a0e26e31ed2b808c8cc513dc69bf162fb709320768880f59536ab5a5e1031fac0f8ac5cfdb096281d0abcae3b49
7
- data.tar.gz: 1fda60427ec07042e05d2840f4ef99ba0740552e3735b10012d46c990ba62deeb653c21fc19c5653ae03e60150af9083fa3869deace3c7b3e0780632a0cbaa59
6
+ metadata.gz: e8e3cb78423ffe5b22af0c3bcbf94d8e12af8f2b537be73a3b53c1d68e0e30886ea06ff4ceaa49985049d5056a6858120a3e897163e7e5bd0e0ccdf3f0c1628f
7
+ data.tar.gz: 6cf65282ab7d1aa93097ce6e6cf7f9f9f55d113d8a34d35b44859caf48757f9dc241835de1e0f15de4933e5b17ef2d1061986cce6fed1ada15291ec3e7f70cfb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.1] - 2026-02-07
4
+
5
+ ### Added
6
+
7
+ - Generic `metadata` field for tool calls to support provider-specific data pass-through (e.g. Gemini 3 `thought_signature`)
8
+
9
+ ### Fixed
10
+
11
+ - Fix process crash when pressing Ctrl+C during AI API call in debug mode
12
+ - SIGINT now sets interrupt flag instead of propagating to main thread's `Queue.pop`
13
+ - Pending debug commands are properly discarded on interrupt
14
+ - Original SIGINT handler is always restored via `ensure` block
15
+ - Save session history on every AI turn instead of only at exit, preventing data loss on crash or unexpected exit
16
+
3
17
  ## [0.3.0] - 2026-02-07
4
18
 
5
19
  ### Added
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "auto_continue"
4
4
  require_relative "conversation_history"
5
+ require_relative "session_persistence"
5
6
  require_relative "providers/base"
6
7
  require_relative "debug_context_builder"
7
8
  require_relative "debug_prompt_builder"
@@ -88,6 +89,9 @@ module Girb
88
89
  Girb::AutoContinue.clear_interrupt!
89
90
  end
90
91
  end
92
+ ensure
93
+ # 毎ターン会話履歴を保存(クラッシュやexitでの消失を防止)
94
+ SessionPersistence.save_session
91
95
  end
92
96
 
93
97
  private
@@ -201,7 +205,7 @@ module Girb
201
205
  result: result
202
206
  }
203
207
 
204
- ConversationHistory.add_tool_call(tool_name, tool_args, result, id: tool_id)
208
+ ConversationHistory.add_tool_call(tool_name, tool_args, result, id: tool_id, metadata: function_call[:metadata])
205
209
 
206
210
  if Girb.configuration.debug && result.is_a?(Hash) && result[:error]
207
211
  puts "[girb] Tool error: #{result[:error]}"
@@ -22,8 +22,8 @@ module Girb
22
22
  instance.add_assistant_message(content)
23
23
  end
24
24
 
25
- def add_tool_call(tool_name, args, result, id: nil)
26
- instance.add_tool_call(tool_name, args, result, id: id)
25
+ def add_tool_call(tool_name, args, result, id: nil, metadata: nil)
26
+ instance.add_tool_call(tool_name, args, result, id: id, metadata: metadata)
27
27
  end
28
28
 
29
29
  def to_contents
@@ -72,13 +72,14 @@ module Girb
72
72
  end
73
73
  end
74
74
 
75
- def add_tool_call(tool_name, args, result, id: nil)
75
+ def add_tool_call(tool_name, args, result, id: nil, metadata: nil)
76
76
  @pending_tool_calls << {
77
77
  id: id || "call_#{SecureRandom.hex(12)}",
78
78
  name: tool_name,
79
79
  args: args,
80
- result: result
81
- }
80
+ result: result,
81
+ metadata: metadata
82
+ }.compact
82
83
  end
83
84
 
84
85
  def clear!
@@ -106,14 +107,18 @@ module Girb
106
107
 
107
108
  # Add tool calls and results if present
108
109
  msg.tool_calls&.each do |tc|
109
- result << { role: :tool_call, id: tc[:id], name: tc[:name], args: tc[:args] }
110
+ tool_call = { role: :tool_call, id: tc[:id], name: tc[:name], args: tc[:args] }
111
+ tool_call[:metadata] = tc[:metadata] if tc[:metadata]
112
+ result << tool_call
110
113
  result << { role: :tool_result, id: tc[:id], name: tc[:name], result: tc[:result] }
111
114
  end
112
115
  end
113
116
 
114
117
  # Add pending tool calls
115
118
  @pending_tool_calls.each do |tc|
116
- result << { role: :tool_call, id: tc[:id], name: tc[:name], args: tc[:args] }
119
+ tool_call = { role: :tool_call, id: tc[:id], name: tc[:name], args: tc[:args] }
120
+ tool_call[:metadata] = tc[:metadata] if tc[:metadata]
121
+ result << tool_call
117
122
  result << { role: :tool_result, id: tc[:id], name: tc[:name], result: tc[:result] }
118
123
  end
119
124
 
@@ -313,17 +313,37 @@ module Girb
313
313
  # 初回のAI質問時にセッションを開始
314
314
  Girb::DebugIntegration.start_session!
315
315
 
316
+ # Ctrl+Cでプロセスがクラッシュするのを防ぐ
317
+ # trapハンドラを設置し、SIGINTをフラグ設定のみに抑える
318
+ original_handler = trap("INT") do
319
+ Girb::DebugIntegration.interrupt!
320
+ end
321
+
316
322
  context = Girb::DebugContextBuilder.new(current_binding).build
317
323
  client = Girb::AiClient.new
318
324
  # Disable Ruby's Timeout during API call to avoid deadlock with debug gem's threading
319
325
  with_timeout_disabled do
320
326
  client.ask(question, context, binding: current_binding, debug_mode: true)
321
327
  end
328
+
329
+ # API呼び出し後にinterruptチェック
330
+ if Girb::DebugIntegration.interrupted?
331
+ Girb::DebugIntegration.clear_interrupt!
332
+ Girb::DebugIntegration.auto_continue = false
333
+ Girb::DebugIntegration.take_pending_debug_commands
334
+ puts "\n[girb] Interrupted by user (Ctrl+C)"
335
+ end
322
336
  rescue Girb::ConfigurationError => e
323
337
  puts "[girb] #{e.message}"
324
338
  rescue StandardError => e
325
339
  puts "[girb] Error: #{e.message}"
326
340
  puts e.backtrace.first(3).join("\n") if Girb.configuration.debug
341
+ ensure
342
+ if original_handler
343
+ trap("INT", original_handler)
344
+ else
345
+ trap("INT", "DEFAULT")
346
+ end
327
347
  end
328
348
 
329
349
  # Temporarily disable Ruby's Timeout module to avoid deadlock with debug gem
@@ -46,15 +46,56 @@ module Girb
46
46
  When tracking variables through many iterations (loops, recursion), avoid repeated `next`/`step`
47
47
  commands. Each step requires an API call, which is slow. Use conditional breakpoints instead:
48
48
 
49
- **Efficient approach for loops with many iterations:**
50
- 1. `evaluate_code("$tracked = []")` - initialize tracking array
51
- 2. Use a conditional breakpoint that records AND stops on condition:
52
- `break file.rb:10 if: ($tracked << x; x == 1)`
53
- This appends x to $tracked on EVERY hit, but only stops when x == 1.
54
- 3. `continue` - run through all iterations at full speed
55
- 4. When stopped (or at end): `evaluate_code("$tracked")` to see all collected values
49
+ **CRITICAL: Breakpoint Line Placement Rules**
50
+ Before setting a breakpoint, use `read_file` to verify the target line.
51
+ - NEVER place a breakpoint on a block header line (a line containing `do |...|`, `.each`, `.map`, `.times`, etc.).
52
+ Block header lines execute only ONCE when the method is called, so the breakpoint will only hit once.
53
+ - ALWAYS place breakpoints on a line INSIDE the block body. Block body lines execute on every iteration.
54
+ - Example:
55
+ ```
56
+ 10: data.each_with_index do |val, i| # BAD: this line hits only once
57
+ 11: x = (x * val + i * 3) % 100 # GOOD: this line hits every iteration
58
+ 12: end
59
+ ```
60
+ Use `break file.rb:11` (body line), NOT `break file.rb:10` (header line).
56
61
 
57
- This completes in 2-3 API turns instead of many turns with repeated stepping.
62
+ **Efficient approach for loops with many iterations:**
63
+ 1. `read_file` to check the source and identify the correct body line (not a block header)
64
+ 2. `evaluate_code("$tracked = []")` - initialize tracking array
65
+ 3. Use a conditional breakpoint on a block BODY line that records AND stops on condition:
66
+ `break file.rb:11 if: ($tracked << x; x == 1)`
67
+ This appends x to $tracked on EVERY iteration, but only stops when x == 1.
68
+ 4. CRITICAL: In the SAME tool call batch, call `run_debug_command("c")` with `auto_continue: true`.
69
+ You MUST continue immediately after setting the breakpoint — do NOT stop and wait for user input.
70
+ When the breakpoint hits, you will be re-invoked with the new context.
71
+ 5. When re-invoked after the breakpoint hits: `evaluate_code("$tracked")` to retrieve results,
72
+ then report the findings to the user.
73
+
74
+ Steps 3 and 4 MUST happen in the same turn. Example tool calls in one response:
75
+ - `run_debug_command("break file.rb:11 if: ($tracked << x; x == 1)")`
76
+ - `run_debug_command("c", auto_continue: true)`
77
+
78
+ This completes in 3-4 API turns instead of many turns with repeated stepping.
79
+
80
+ **Alternative: evaluate_code for pure tracking scenarios**
81
+ When the goal is purely to collect variable values and stop on a condition (without needing
82
+ to interact at the breakpoint), `evaluate_code` can run the loop directly. This is simpler
83
+ and avoids breakpoint line selection issues entirely:
84
+ ```ruby
85
+ evaluate_code <<~RUBY
86
+ $tracked = [x]
87
+ catch(:girb_stop) do
88
+ data.each_with_index do |val, i|
89
+ x = (x * val + i * 3) % 100
90
+ $tracked << x
91
+ throw(:girb_stop) if x == 1
92
+ end
93
+ end
94
+ { tracked_values: $tracked, stopped: (x == 1) }
95
+ RUBY
96
+ ```
97
+ Use this when the user wants to collect values and find when a condition is met,
98
+ and you can reconstruct the loop logic from the source code.
58
99
 
59
100
  **When to use repeated stepping (next/step):**
60
101
  - Understanding complex logic flow (few lines)
@@ -68,6 +109,11 @@ module Girb
68
109
  - "Find when X becomes Y" requests
69
110
  - Collecting history of values
70
111
 
112
+ **When to use evaluate_code loop:**
113
+ - Pure value tracking without needing to stop and interact
114
+ - When you can reconstruct the loop logic from source code
115
+ - When breakpoint placement is complex (nested blocks, etc.)
116
+
71
117
  ## CRITICAL: Executing Debugger Commands
72
118
  When the user asks you to perform a debugging action (e.g., "go to the next line", "step into",
73
119
  "continue", "advance to line N", "set a breakpoint"), you MUST use the `run_debug_command` tool.
@@ -66,12 +66,11 @@ module Girb
66
66
 
67
67
  data = {
68
68
  session_id: @current_session_id,
69
- saved_at: Time.now.iso8601,
69
+ saved_at: Time.now.to_s,
70
70
  messages: serialize_messages
71
71
  }
72
72
 
73
73
  File.write(file_path, JSON.pretty_generate(data))
74
- puts "[girb] Session saved: #{@current_session_id}"
75
74
  rescue => e
76
75
  puts "[girb] Failed to save session: #{e.message}"
77
76
  end
@@ -157,7 +156,8 @@ module Girb
157
156
  tc[:name],
158
157
  tc[:args],
159
158
  tc[:result],
160
- id: tc[:id]
159
+ id: tc[:id],
160
+ metadata: tc[:metadata]
161
161
  )
162
162
  end
163
163
  end
data/lib/girb/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Girb
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: girb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - rira100000000