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 +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/girb/ai_client.rb +5 -1
- data/lib/girb/conversation_history.rb +12 -7
- data/lib/girb/debug_integration.rb +20 -0
- data/lib/girb/debug_prompt_builder.rb +54 -8
- data/lib/girb/session_persistence.rb +3 -3
- data/lib/girb/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c2d2144162ffe9fabd66b1a4eebab7854ad593e210d3dda57714dec1ba3e4ae6
|
|
4
|
+
data.tar.gz: 81ef617d448595e2d83367ae3799680b178b7e6d2967997806715990b441972e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
data/lib/girb/ai_client.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
**
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
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.
|
|
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