Class: Girb::AiClient

Inherits:
Object
  • Object
show all
Defined in:
lib/girb/ai_client.rb

Constant Summary collapse

MAX_TOOL_ITERATIONS =
10
MAX_SELF_CORRECTION =

Max provider-agnostic retries after a malformed tool call before giving up.

2

Instance Method Summary collapse

Constructor Details

#initializeAiClient

Returns a new instance of AiClient.



17
18
19
# File 'lib/girb/ai_client.rb', line 17

def initialize
  @provider = Girb.configuration.provider!
end

Instance Method Details

#ask(question, context, binding: nil, line_no: nil, irb_context: nil, debug_mode: false) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/girb/ai_client.rb', line 21

def ask(question, context, binding: nil, line_no: nil, irb_context: nil, debug_mode: false)
  @current_binding = binding
  @current_line_no = line_no
  @irb_context = irb_context
  @debug_mode = debug_mode
  @reasoning_log = []
  @self_correction_count = 0
  # Lock the response language to the original question once, so English
  # auto-continue / interrupt / limit messages can't re-anchor it.
  @response_language = Girb::LanguageDetector.detect(question)

  prompt_builder = create_prompt_builder(question, context)
  @system_prompt = prompt_builder.system_prompt
  user_message = prompt_builder.user_message

  ConversationHistory.add_user_message(user_message)

  tools = build_tools

  # In debug mode, auto-continue is handled by DebugIntegration, not here
  if @debug_mode
    process_with_tools(tools)
  else
    auto_continue_count = 0
    original_int_handler = setup_interrupt_handler
    @debug_command_queued = false

    begin
      loop do
        # Check for interrupt at start of loop
        if Girb::AutoContinue.interrupted?
          Girb::AutoContinue.clear_interrupt!
          handle_irb_interrupted
          break
        end

        process_with_tools(tools)

        # If a debug command was queued, exit immediately
        # The command needs to be executed by IRB first, then DebugIntegration handles auto-continue
        if @debug_command_queued
          break
        end

        # Check for interrupt after API call (Ctrl+C during request)
        if Girb::AutoContinue.interrupted?
          Girb::AutoContinue.clear_interrupt!
          handle_irb_interrupted
          break
        end

        break unless Girb::AutoContinue.active?

        auto_continue_count += 1
        if auto_continue_count >= Girb::AutoContinue::MAX_ITERATIONS
          handle_irb_limit_reached
          break
        end

        Girb::AutoContinue.reset!

        # Rebuild context with current binding state
        new_context = create_context_builder(@current_binding, @irb_context).build
        continuation = "(auto-continue: Your previous action has been completed. " \
                       "Here is the updated context. Continue your investigation.)"
        continuation_builder = create_prompt_builder(continuation, new_context)
        ConversationHistory.add_user_message(continuation_builder.user_message)
      end
    ensure
      restore_interrupt_handler(original_int_handler)
      # Only reset AutoContinue if no debug command was queued
      # (it will be transferred to DebugIntegration in IrbDebugHook)
      unless @debug_command_queued
        Girb::AutoContinue.reset!
      end
      Girb::AutoContinue.clear_interrupt!
    end
  end
ensure
  # 毎ターン会話履歴を保存(クラッシュやexitでの消失を防止)
  SessionPersistence.save_session
end