girb 0.2.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 +56 -1
- data/README.md +271 -154
- data/README_ja.md +268 -151
- data/lib/girb/ai_client.rb +23 -5
- data/lib/girb/auto_continue.rb +1 -1
- data/lib/girb/conversation_history.rb +12 -7
- data/lib/girb/debug_integration.rb +158 -10
- data/lib/girb/debug_prompt_builder.rb +71 -11
- data/lib/girb/exception_capture.rb +4 -0
- data/lib/girb/irb_integration.rb +232 -0
- data/lib/girb/prompt_builder.rb +128 -51
- data/lib/girb/session_persistence.rb +170 -0
- data/lib/girb/tools/debug_session_history_tool.rb +61 -18
- data/lib/girb/tools/run_irb_debug_command.rb +58 -0
- data/lib/girb/tools/session_history_tool.rb +41 -8
- data/lib/girb/tools.rb +2 -1
- data/lib/girb/version.rb +1 -1
- data/lib/girb.rb +16 -7
- data/lib/irb/command/qq.rb +41 -0
- metadata +3 -1
data/README_ja.md
CHANGED
|
@@ -1,38 +1,75 @@
|
|
|
1
1
|
# girb (Generative IRB)
|
|
2
2
|
|
|
3
|
-
IRB
|
|
3
|
+
Ruby開発のためのAIアシスタント。IRB、Rails console、debug gemで動作します。
|
|
4
4
|
|
|
5
5
|
## 特徴
|
|
6
6
|
|
|
7
|
-
- **コンテキスト認識**:
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- **debug gem統合**: Rubyのdebug gemと連携し、AIアシスタント付きのステップ実行デバッグが可能
|
|
13
|
-
- **多言語対応**: ユーザーの言語を検出し、同じ言語で応答
|
|
14
|
-
- **カスタマイズ可能**: 独自のプロンプトを追加して、プロジェクト固有の指示を設定可能
|
|
15
|
-
- **プロバイダー非依存**: 任意のLLMプロバイダーを使用、または独自実装が可能
|
|
7
|
+
- **コンテキスト認識**: ローカル変数、インスタンス変数、実行時の状態を理解
|
|
8
|
+
- **ツール実行**: コード実行、オブジェクト検査、ファイル読み取りをAIが自律的に実行
|
|
9
|
+
- **自律的な調査**: 調査→実行→分析のサイクルをAIがループ
|
|
10
|
+
- **マルチ環境対応**: IRB、Rails console、debug gem (rdbg) で動作
|
|
11
|
+
- **プロバイダー非依存**: 任意のLLM(OpenAI、Anthropic、Gemini、Ollama等)を使用可能
|
|
16
12
|
|
|
17
|
-
##
|
|
13
|
+
## クイックスタート
|
|
18
14
|
|
|
19
|
-
|
|
15
|
+
```bash
|
|
16
|
+
# 1. インストール
|
|
17
|
+
gem install girb girb-ruby_llm
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
# 2. APIキーを設定
|
|
20
|
+
export GEMINI_API_KEY="your-api-key" # または OPENAI_API_KEY, ANTHROPIC_API_KEY
|
|
22
21
|
|
|
22
|
+
# 3. ~/.girbrc を作成
|
|
23
23
|
```ruby
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
require 'girb-ruby_llm'
|
|
25
|
+
Girb.configure do |c|
|
|
26
|
+
c.provider = Girb::Providers::RubyLlm.new(model: 'gemini-2.5-flash')
|
|
26
27
|
end
|
|
27
28
|
```
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
# 4. 実行
|
|
31
|
+
girb
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
質問を入力して **Ctrl+Space** を押すか、`qq <質問>` を使用します。
|
|
35
|
+
|
|
36
|
+
## 目次
|
|
37
|
+
|
|
38
|
+
1. [設定](#1-設定) - 全環境共通のセットアップ
|
|
39
|
+
2. [Rubyスクリプト (IRB)](#2-rubyスクリプト-irb) - 純粋なRubyでの使用
|
|
40
|
+
3. [Rails](#3-rails) - Rails consoleでの使用
|
|
41
|
+
4. [Debug Gem (rdbg)](#4-debug-gem-rdbg) - AIアシスタント付きステップ実行デバッグ
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 1. 設定
|
|
46
|
+
|
|
47
|
+
### インストール
|
|
30
48
|
|
|
31
49
|
```bash
|
|
32
|
-
|
|
50
|
+
gem install girb girb-ruby_llm
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
利用可能なプロバイダーgem:
|
|
54
|
+
- [girb-ruby_llm](https://github.com/rira100000000/girb-ruby_llm) - OpenAI、Anthropic、Gemini、Ollama等(推奨)
|
|
55
|
+
- [girb-gemini](https://github.com/rira100000000/girb-gemini) - Google Geminiのみ
|
|
56
|
+
|
|
57
|
+
### APIキー
|
|
58
|
+
|
|
59
|
+
使用するLLMプロバイダーのAPIキーを環境変数に設定:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
export GEMINI_API_KEY="your-api-key"
|
|
63
|
+
# または OPENAI_API_KEY, ANTHROPIC_API_KEY など
|
|
33
64
|
```
|
|
34
65
|
|
|
35
|
-
|
|
66
|
+
詳細な設定方法(Ollama、その他のプロバイダー、高度なオプション)は、プロバイダーgemのドキュメントを参照してください:
|
|
67
|
+
- [girb-ruby_llm](https://github.com/rira100000000/girb-ruby_llm)
|
|
68
|
+
- [girb-gemini](https://github.com/rira100000000/girb-gemini)
|
|
69
|
+
|
|
70
|
+
### .girbrcの作成
|
|
71
|
+
|
|
72
|
+
プロジェクトルート(またはホームディレクトリ)に `.girbrc` ファイルを作成:
|
|
36
73
|
|
|
37
74
|
```ruby
|
|
38
75
|
# .girbrc
|
|
@@ -43,70 +80,104 @@ Girb.configure do |c|
|
|
|
43
80
|
end
|
|
44
81
|
```
|
|
45
82
|
|
|
46
|
-
|
|
83
|
+
girbは以下の順序で `.girbrc` を探します:
|
|
84
|
+
1. カレントディレクトリ → 親ディレクトリ(ルートまで)
|
|
85
|
+
2. `~/.girbrc` にフォールバック
|
|
47
86
|
|
|
48
|
-
###
|
|
87
|
+
### モデルの例
|
|
49
88
|
|
|
50
|
-
|
|
89
|
+
```ruby
|
|
90
|
+
# Google Gemini
|
|
91
|
+
c.provider = Girb::Providers::RubyLlm.new(model: 'gemini-2.5-flash')
|
|
51
92
|
|
|
52
|
-
|
|
53
|
-
|
|
93
|
+
# OpenAI
|
|
94
|
+
c.provider = Girb::Providers::RubyLlm.new(model: 'gpt-5.2-2025-12-11')
|
|
95
|
+
|
|
96
|
+
# Anthropic
|
|
97
|
+
c.provider = Girb::Providers::RubyLlm.new(model: 'claude-opus-4-5')
|
|
54
98
|
```
|
|
55
99
|
|
|
56
|
-
|
|
100
|
+
### 設定オプション
|
|
57
101
|
|
|
58
102
|
```ruby
|
|
59
|
-
# .girbrc
|
|
60
|
-
require 'girb-ruby_llm'
|
|
61
|
-
|
|
62
103
|
Girb.configure do |c|
|
|
104
|
+
# 必須: LLMプロバイダー
|
|
63
105
|
c.provider = Girb::Providers::RubyLlm.new(model: 'gemini-2.5-flash')
|
|
106
|
+
|
|
107
|
+
# オプション: デバッグ出力
|
|
108
|
+
c.debug = true
|
|
109
|
+
|
|
110
|
+
# オプション: カスタムシステムプロンプト
|
|
111
|
+
c.custom_prompt = <<~PROMPT
|
|
112
|
+
破壊的操作の前に必ず確認してください。
|
|
113
|
+
PROMPT
|
|
64
114
|
end
|
|
65
115
|
```
|
|
66
116
|
|
|
67
|
-
|
|
117
|
+
### 環境変数(フォールバック)
|
|
68
118
|
|
|
69
|
-
|
|
119
|
+
`.girbrc` に設定がない場合に使用:
|
|
70
120
|
|
|
71
|
-
|
|
121
|
+
| 変数 | 説明 |
|
|
122
|
+
|------|------|
|
|
123
|
+
| `GIRB_PROVIDER` | プロバイダーgem(例: `girb-ruby_llm`) |
|
|
124
|
+
| `GIRB_MODEL` | モデル名(例: `gemini-2.5-flash`) |
|
|
125
|
+
| `GIRB_DEBUG` | `1` でデバッグ出力有効化 |
|
|
72
126
|
|
|
73
|
-
|
|
74
|
-
2. `~/.girbrc` にフォールバック
|
|
127
|
+
### セッション永続化(オプション)
|
|
75
128
|
|
|
76
|
-
|
|
129
|
+
AIとの会話履歴をセッション間で保持できます。明示的にセッションIDを指定した場合のみ有効になります。
|
|
77
130
|
|
|
78
|
-
|
|
79
|
-
- **共有設定**: 親ディレクトリに `.girbrc` を配置(例: `~/work/.girbrc` で仕事用プロジェクト全体に適用)
|
|
80
|
-
- **グローバルデフォルト**: ホームディレクトリに `.girbrc` を配置
|
|
131
|
+
#### 有効化
|
|
81
132
|
|
|
82
|
-
|
|
133
|
+
`.girbrc` でセッションIDを設定:
|
|
83
134
|
|
|
84
|
-
|
|
135
|
+
```ruby
|
|
136
|
+
Girb.configure do |c|
|
|
137
|
+
c.provider = Girb::Providers::RubyLlm.new(model: 'gemini-2.5-flash')
|
|
138
|
+
end
|
|
85
139
|
|
|
86
|
-
|
|
87
|
-
|
|
140
|
+
# セッション永続化を有効化(オプション)
|
|
141
|
+
Girb.debug_session = "my-project"
|
|
142
|
+
```
|
|
88
143
|
|
|
89
|
-
|
|
144
|
+
または、コード内で動的に設定:
|
|
90
145
|
|
|
91
|
-
|
|
146
|
+
```ruby
|
|
147
|
+
Girb.debug_session = "debug-user-auth"
|
|
148
|
+
debugger # このセッションの会話が保存される
|
|
149
|
+
```
|
|
92
150
|
|
|
93
|
-
|
|
151
|
+
#### セッション管理コマンド
|
|
152
|
+
|
|
153
|
+
IRBまたはデバッグモードで使用:
|
|
94
154
|
|
|
95
|
-
```bash
|
|
96
|
-
rails console
|
|
97
155
|
```
|
|
156
|
+
qq session status # 現在のセッション状態を表示
|
|
157
|
+
qq session list # 保存されたセッション一覧
|
|
158
|
+
qq session clear # 現在のセッションをクリア
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### 動作
|
|
162
|
+
|
|
163
|
+
- セッションは `.girb/sessions/<session_id>.json` に保存
|
|
164
|
+
- 7日以上アクセスのないセッションは自動削除
|
|
165
|
+
- 同じセッションIDで再開すると、過去の会話を引き継ぎ
|
|
166
|
+
- `get_session_history` ツールで過去の会話を参照可能
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 2. Rubyスクリプト (IRB)
|
|
98
171
|
|
|
99
|
-
|
|
172
|
+
### 使い方
|
|
100
173
|
|
|
101
|
-
|
|
174
|
+
`irb` の代わりに `girb` コマンドを使用:
|
|
102
175
|
|
|
103
176
|
```bash
|
|
104
177
|
girb
|
|
105
178
|
```
|
|
106
179
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
コード内に `binding.girb` を挿入:
|
|
180
|
+
または、コード内に `binding.girb` を挿入:
|
|
110
181
|
|
|
111
182
|
```ruby
|
|
112
183
|
def problematic_method
|
|
@@ -116,111 +187,192 @@ def problematic_method
|
|
|
116
187
|
end
|
|
117
188
|
```
|
|
118
189
|
|
|
119
|
-
###
|
|
190
|
+
### AIへの質問方法
|
|
120
191
|
|
|
121
|
-
|
|
192
|
+
**Ctrl+Space**: 質問を入力した後に押す
|
|
122
193
|
|
|
123
|
-
```
|
|
124
|
-
|
|
194
|
+
```
|
|
195
|
+
irb(main):001> なぜ失敗したの?[Ctrl+Space]
|
|
196
|
+
```
|
|
125
197
|
|
|
126
|
-
|
|
127
|
-
result = some_calculation
|
|
128
|
-
result
|
|
129
|
-
end
|
|
198
|
+
**qqコマンド**: qqメソッドを使用
|
|
130
199
|
|
|
131
|
-
problematic_method
|
|
132
200
|
```
|
|
201
|
+
irb(main):001> qq このメソッドの使い方を教えて
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### 利用可能なツール (IRB)
|
|
205
|
+
|
|
206
|
+
| ツール | 説明 |
|
|
207
|
+
|--------|------|
|
|
208
|
+
| `evaluate_code` | Rubyコードを実行 |
|
|
209
|
+
| `inspect_object` | オブジェクトの詳細を検査 |
|
|
210
|
+
| `get_source` | メソッド/クラスのソースコードを取得 |
|
|
211
|
+
| `list_methods` | オブジェクトのメソッド一覧を取得 |
|
|
212
|
+
| `find_file` | ファイルを検索 |
|
|
213
|
+
| `read_file` | ファイル内容を読み取り |
|
|
214
|
+
| `get_session_history` | IRBセッション履歴を取得 |
|
|
215
|
+
| `continue_analysis` | 自律調査のためのコンテキスト更新をリクエスト |
|
|
216
|
+
|
|
217
|
+
### 使用例
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
irb(main):001> x = [1, 2, 3]
|
|
221
|
+
irb(main):002> 合計を求めるメソッドは?[Ctrl+Space]
|
|
222
|
+
`x.sum` で合計6が得られます。他にも `x.reduce(:+)` や `x.inject(0, :+)` が使えます。
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 3. Rails
|
|
228
|
+
|
|
229
|
+
### インストール
|
|
230
|
+
|
|
231
|
+
Gemfileに追加:
|
|
133
232
|
|
|
134
|
-
|
|
233
|
+
```ruby
|
|
234
|
+
group :development do
|
|
235
|
+
gem 'girb'
|
|
236
|
+
gem 'girb-ruby_llm'
|
|
237
|
+
end
|
|
238
|
+
```
|
|
135
239
|
|
|
136
240
|
```bash
|
|
137
|
-
|
|
241
|
+
bundle install
|
|
138
242
|
```
|
|
139
243
|
|
|
140
|
-
|
|
141
|
-
- `ai <質問>` - AIに質問
|
|
142
|
-
- `Ctrl+Space` - 入力内容をAIに送信
|
|
143
|
-
- 日本語(非ASCII文字)の入力は自動的にAIにルーティング
|
|
244
|
+
### 設定
|
|
144
245
|
|
|
145
|
-
|
|
246
|
+
Railsプロジェクトルートに `.girbrc` を作成。詳細は[設定](#1-設定)を参照。
|
|
146
247
|
|
|
147
|
-
###
|
|
248
|
+
### 使い方
|
|
249
|
+
|
|
250
|
+
`rails console` を実行するだけ - Railtieで自動的にgirbが読み込まれます:
|
|
148
251
|
|
|
149
|
-
|
|
252
|
+
```bash
|
|
253
|
+
rails console
|
|
254
|
+
```
|
|
150
255
|
|
|
151
|
-
|
|
256
|
+
### 追加ツール (Rails)
|
|
257
|
+
|
|
258
|
+
| ツール | 説明 |
|
|
259
|
+
|--------|------|
|
|
260
|
+
| `query_model` | ActiveRecordクエリを実行 |
|
|
261
|
+
| `model_info` | モデルのスキーマ情報を取得 |
|
|
262
|
+
|
|
263
|
+
### 使用例
|
|
152
264
|
|
|
153
265
|
```
|
|
154
|
-
irb(main):001>
|
|
266
|
+
irb(main):001> user = User.find(1)
|
|
267
|
+
irb(main):002> user.update(name: "test")
|
|
268
|
+
=> false
|
|
269
|
+
irb(main):003> なぜ更新に失敗したの?[Ctrl+Space]
|
|
270
|
+
`user.errors.full_messages` を確認したところ:
|
|
271
|
+
- "Email can't be blank"
|
|
272
|
+
更新時にemail属性が空になっています。
|
|
155
273
|
```
|
|
156
274
|
|
|
157
|
-
|
|
275
|
+
---
|
|
158
276
|
|
|
277
|
+
## 4. Debug Gem (rdbg)
|
|
278
|
+
|
|
279
|
+
AIアシスタント付きのステップ実行デバッグ。
|
|
280
|
+
|
|
281
|
+
### 設定
|
|
282
|
+
|
|
283
|
+
上記と同じ `.girbrc` を使用。
|
|
284
|
+
|
|
285
|
+
### Rubyスクリプトの場合
|
|
286
|
+
|
|
287
|
+
`require "debug"` と `require "girb"` を追加し、`debugger`ステートメントを使用:
|
|
288
|
+
|
|
289
|
+
**注意:** `require "debug"` は必ず `require "girb"` より先に記述してください。
|
|
290
|
+
|
|
291
|
+
```ruby
|
|
292
|
+
require "debug"
|
|
293
|
+
require "girb"
|
|
294
|
+
|
|
295
|
+
def calculate(x)
|
|
296
|
+
result = x * 2
|
|
297
|
+
debugger # ここでAIアシスタント付きで停止
|
|
298
|
+
result + 1
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
calculate(5)
|
|
159
302
|
```
|
|
160
|
-
|
|
303
|
+
|
|
304
|
+
rubyで実行:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
ruby your_script.rb
|
|
161
308
|
```
|
|
162
309
|
|
|
163
|
-
|
|
310
|
+
### Railsの場合
|
|
164
311
|
|
|
165
|
-
|
|
312
|
+
debug gemより後にgirbを読み込むためinitializerを作成:
|
|
166
313
|
|
|
167
314
|
```ruby
|
|
168
|
-
|
|
315
|
+
# config/initializers/girb.rb
|
|
316
|
+
require "girb" if Rails.env.development? || Rails.env.test?
|
|
317
|
+
```
|
|
169
318
|
|
|
170
|
-
|
|
171
|
-
# デバッグ出力(デフォルト: false)
|
|
172
|
-
c.debug = true
|
|
319
|
+
コード内で`debugger`ステートメントを使用:
|
|
173
320
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
321
|
+
```ruby
|
|
322
|
+
def show
|
|
323
|
+
@user = User.find(params[:id])
|
|
324
|
+
debugger # ここでAIアシスタント付きで停止
|
|
178
325
|
end
|
|
179
326
|
```
|
|
180
327
|
|
|
181
|
-
###
|
|
328
|
+
### AIへの質問方法 (デバッグモード)
|
|
329
|
+
|
|
330
|
+
- **`qq <質問>`** - AIに質問
|
|
331
|
+
- **Ctrl+Space** - 現在の入力をAIに送信
|
|
332
|
+
- **日本語入力** - 非ASCII文字は自動的にAIにルーティング
|
|
182
333
|
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
girb --help # ヘルプを表示
|
|
334
|
+
```
|
|
335
|
+
(rdbg) qq ここでのresultの値は?
|
|
336
|
+
(rdbg) 次の行に進んで[Ctrl+Space]
|
|
187
337
|
```
|
|
188
338
|
|
|
189
|
-
###
|
|
339
|
+
### AIがデバッガコマンドを実行
|
|
190
340
|
|
|
191
|
-
|
|
341
|
+
AIがデバッガコマンドを自動で実行できます:
|
|
192
342
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
343
|
+
```
|
|
344
|
+
(rdbg) qq このループを実行して、xが1になるタイミングを教えて
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
AIは `step`、`next`、`continue`、`break` などを自動的に使用します。
|
|
348
|
+
|
|
349
|
+
### Ctrl+Cで中断
|
|
350
|
+
|
|
351
|
+
Ctrl+Cで長時間実行中のAI操作を中断できます。AIは進捗を要約します。
|
|
198
352
|
|
|
199
|
-
|
|
353
|
+
### 利用可能なツール (デバッグモード)
|
|
200
354
|
|
|
201
355
|
| ツール | 説明 |
|
|
202
356
|
|--------|------|
|
|
203
|
-
| `evaluate_code` |
|
|
357
|
+
| `evaluate_code` | 現在のコンテキストでRubyコードを実行 |
|
|
204
358
|
| `inspect_object` | オブジェクトの詳細を検査 |
|
|
205
|
-
| `get_source` |
|
|
206
|
-
| `
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `session_history` | IRBセッションの履歴を取得 |
|
|
210
|
-
| `continue_analysis` | 自律調査のためのコンテキスト更新をリクエスト |
|
|
359
|
+
| `get_source` | メソッド/クラスのソースコードを取得 |
|
|
360
|
+
| `read_file` | ソースファイルを読み取り |
|
|
361
|
+
| `run_debug_command` | デバッガコマンドを実行 |
|
|
362
|
+
| `get_session_history` | デバッグセッション履歴を取得 |
|
|
211
363
|
|
|
212
|
-
###
|
|
364
|
+
### 使用例: 変数の追跡
|
|
213
365
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
| `query_model` | ActiveRecordモデルへのクエリ実行 |
|
|
217
|
-
| `model_info` | モデルのスキーマ情報を取得 |
|
|
366
|
+
```
|
|
367
|
+
(rdbg) qq このループでxの全ての値を追跡して、完了したら報告して
|
|
218
368
|
|
|
219
|
-
|
|
369
|
+
[AIがブレークポイントを設定、continueを実行、値を収集]
|
|
220
370
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
371
|
+
追跡したxの値: [7, 66, 85, 11, 53, 42, 99, 23]
|
|
372
|
+
ループが完了しました。
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
---
|
|
224
376
|
|
|
225
377
|
## カスタムプロバイダー
|
|
226
378
|
|
|
@@ -232,61 +384,26 @@ class MyProvider < Girb::Providers::Base
|
|
|
232
384
|
@api_key = api_key
|
|
233
385
|
end
|
|
234
386
|
|
|
235
|
-
def chat(messages:, system_prompt:, tools:)
|
|
236
|
-
# messages: { role: :user/:assistant/:tool_call/:tool_result, content: "..." } の配列
|
|
237
|
-
# tools: { name: "...", description: "...", parameters: {...} } の配列
|
|
238
|
-
|
|
387
|
+
def chat(messages:, system_prompt:, tools:, binding: nil)
|
|
239
388
|
# LLM APIを呼び出す
|
|
240
389
|
response = call_my_llm(messages, system_prompt, tools)
|
|
241
390
|
|
|
242
|
-
# Responseオブジェクトを返す
|
|
243
391
|
Girb::Providers::Base::Response.new(
|
|
244
392
|
text: response.text,
|
|
245
393
|
function_calls: response.tool_calls&.map { |tc| { name: tc.name, args: tc.args } }
|
|
246
394
|
)
|
|
247
395
|
end
|
|
248
396
|
end
|
|
249
|
-
|
|
250
|
-
Girb.configure do |c|
|
|
251
|
-
c.provider = MyProvider.new(api_key: ENV['MY_API_KEY'])
|
|
252
|
-
end
|
|
253
397
|
```
|
|
254
398
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
### デバッグ支援
|
|
258
|
-
|
|
259
|
-
```
|
|
260
|
-
irb(main):001> user = User.find(1)
|
|
261
|
-
irb(main):002> user.update(name: "test")
|
|
262
|
-
=> false
|
|
263
|
-
irb(main):003> なぜ更新に失敗したの?[Ctrl+Space]
|
|
264
|
-
`user.errors.full_messages` を確認したところ、バリデーションエラーが発生しています:
|
|
265
|
-
- "Email can't be blank"
|
|
266
|
-
nameの更新時にemailが空になっている可能性があります。
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### コードの理解
|
|
270
|
-
|
|
271
|
-
```
|
|
272
|
-
irb(main):001> このプロジェクトでUserモデルはどこで定義されてる?[Ctrl+Space]
|
|
273
|
-
app/models/user.rb で定義されています。
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
### パターン認識
|
|
277
|
-
|
|
278
|
-
```
|
|
279
|
-
irb(main):001> a = 1
|
|
280
|
-
irb(main):002> b = 2
|
|
281
|
-
irb(main):003> c = 3以降も続けるとzはいくつ?[Ctrl+Space]
|
|
282
|
-
パターン a=1, b=2, c=3... を続けると、z=26 になります。
|
|
283
|
-
```
|
|
399
|
+
---
|
|
284
400
|
|
|
285
401
|
## 動作要件
|
|
286
402
|
|
|
287
403
|
- Ruby 3.2.0以上
|
|
288
|
-
- IRB 1.6.0
|
|
289
|
-
-
|
|
404
|
+
- IRB 1.6.0以上(IRB/Rails使用時)
|
|
405
|
+
- debug gem(rdbg使用時)
|
|
406
|
+
- LLMプロバイダーgem
|
|
290
407
|
|
|
291
408
|
## ライセンス
|
|
292
409
|
|
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"
|
|
@@ -35,6 +36,7 @@ module Girb
|
|
|
35
36
|
else
|
|
36
37
|
auto_continue_count = 0
|
|
37
38
|
original_int_handler = setup_interrupt_handler
|
|
39
|
+
@debug_command_queued = false
|
|
38
40
|
|
|
39
41
|
begin
|
|
40
42
|
loop do
|
|
@@ -47,6 +49,12 @@ module Girb
|
|
|
47
49
|
|
|
48
50
|
process_with_tools(tools)
|
|
49
51
|
|
|
52
|
+
# If a debug command was queued, exit immediately
|
|
53
|
+
# The command needs to be executed by IRB first, then DebugIntegration handles auto-continue
|
|
54
|
+
if @debug_command_queued
|
|
55
|
+
break
|
|
56
|
+
end
|
|
57
|
+
|
|
50
58
|
# Check for interrupt after API call (Ctrl+C during request)
|
|
51
59
|
if Girb::AutoContinue.interrupted?
|
|
52
60
|
Girb::AutoContinue.clear_interrupt!
|
|
@@ -73,10 +81,17 @@ module Girb
|
|
|
73
81
|
end
|
|
74
82
|
ensure
|
|
75
83
|
restore_interrupt_handler(original_int_handler)
|
|
76
|
-
|
|
84
|
+
# Only reset AutoContinue if no debug command was queued
|
|
85
|
+
# (it will be transferred to DebugIntegration in IrbDebugHook)
|
|
86
|
+
unless @debug_command_queued
|
|
87
|
+
Girb::AutoContinue.reset!
|
|
88
|
+
end
|
|
77
89
|
Girb::AutoContinue.clear_interrupt!
|
|
78
90
|
end
|
|
79
91
|
end
|
|
92
|
+
ensure
|
|
93
|
+
# 毎ターン会話履歴を保存(クラッシュやexitでの消失を防止)
|
|
94
|
+
SessionPersistence.save_session
|
|
80
95
|
end
|
|
81
96
|
|
|
82
97
|
private
|
|
@@ -190,16 +205,19 @@ module Girb
|
|
|
190
205
|
result: result
|
|
191
206
|
}
|
|
192
207
|
|
|
193
|
-
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])
|
|
194
209
|
|
|
195
210
|
if Girb.configuration.debug && result.is_a?(Hash) && result[:error]
|
|
196
211
|
puts "[girb] Tool error: #{result[:error]}"
|
|
197
212
|
end
|
|
198
213
|
|
|
199
|
-
#
|
|
200
|
-
#
|
|
201
|
-
if
|
|
214
|
+
# If run_debug_command was called, we need to exit the tool loop
|
|
215
|
+
# so the debugger/IRB can execute the pending commands
|
|
216
|
+
if tool_name == "run_debug_command"
|
|
202
217
|
debug_command_called = true
|
|
218
|
+
# In IRB mode, mark that we've queued a debug command
|
|
219
|
+
# This will prevent the auto-continue loop from continuing
|
|
220
|
+
@debug_command_queued = true unless @debug_mode
|
|
203
221
|
end
|
|
204
222
|
end
|
|
205
223
|
|
data/lib/girb/auto_continue.rb
CHANGED
|
@@ -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
|
|