Class: RubyCoded::Chat::State
- Inherits:
-
Object
- Object
- RubyCoded::Chat::State
- Includes:
- LoginFlow, MessageAssistant, MessageTokenTracking, Messages, ModelSelection, PlanTracking, Scrollable, TokenCost, ToolConfirmation
- Defined in:
- lib/ruby_coded/chat/state.rb,
lib/ruby_coded/chat/state/messages.rb,
lib/ruby_coded/chat/state/login_flow.rb,
lib/ruby_coded/chat/state/scrollable.rb,
lib/ruby_coded/chat/state/token_cost.rb,
lib/ruby_coded/chat/state/plan_tracking.rb,
lib/ruby_coded/chat/state/model_selection.rb,
lib/ruby_coded/chat/state/login_flow_steps.rb,
lib/ruby_coded/chat/state/message_assistant.rb,
lib/ruby_coded/chat/state/tool_confirmation.rb,
lib/ruby_coded/chat/state/message_token_tracking.rb
Overview
This class is used to manage the state of the chat
Defined Under Namespace
Modules: LoginFlow, LoginFlowSteps, MessageAssistant, MessageTokenTracking, Messages, ModelSelection, PlanTracking, Scrollable, TokenCost, ToolConfirmation
Constant Summary collapse
- MIN_RENDER_INTERVAL =
0.05
Constants included from TokenCost
TokenCost::CACHE_CREATION_INPUT_MULTIPLIER, TokenCost::UNPRICED_DEFAULTS
Constants included from MessageTokenTracking
MessageTokenTracking::TOKEN_KEYS
Constants included from Messages
Instance Attribute Summary collapse
-
#codex_mode ⇒ Object
Returns the value of attribute codex_mode.
-
#cursor_position ⇒ Object
readonly
Returns the value of attribute cursor_position.
-
#input_buffer ⇒ Object
readonly
Returns the value of attribute input_buffer.
-
#input_scroll_offset ⇒ Object
readonly
Returns the value of attribute input_scroll_offset.
-
#messages ⇒ Object
readonly
Returns the value of attribute messages.
-
#mode ⇒ Object
readonly
Returns the value of attribute mode.
-
#model ⇒ Object
Returns the value of attribute model.
-
#model_list ⇒ Object
readonly
Returns the value of attribute model_list.
-
#model_select_filter ⇒ Object
readonly
Returns the value of attribute model_select_filter.
-
#model_select_index ⇒ Object
readonly
Returns the value of attribute model_select_index.
-
#mutex ⇒ Object
readonly
Returns the value of attribute mutex.
-
#scroll_offset ⇒ Object
readonly
Returns the value of attribute scroll_offset.
-
#should_quit ⇒ Object
Returns the value of attribute should_quit.
-
#streaming ⇒ Object
Returns the value of attribute streaming.
-
#tui_suspend_reason ⇒ Object
readonly
Returns the value of attribute tui_suspend_reason.
Attributes included from LoginFlow
#login_auth_method, #login_error, #login_items, #login_key_buffer, #login_key_cursor, #login_oauth_result, #login_provider, #login_select_index, #login_step
Attributes included from PlanTracking
#clarification_custom_input, #clarification_index, #clarification_input_mode, #clarification_options, #clarification_question
Attributes included from ToolConfirmation
Attributes included from Messages
Instance Method Summary collapse
- #agentic_mode=(value) ⇒ Object
- #agentic_mode? ⇒ Boolean
- #append_to_input(text) ⇒ Object
- #clear_input! ⇒ Object
- #clear_tui_suspend! ⇒ Object
- #consume_input! ⇒ Object
- #delete_last_char ⇒ Object
- #dirty? ⇒ Boolean
-
#initialize(model:) ⇒ State
constructor
A new instance of State.
- #mark_clean! ⇒ Object
- #mark_dirty! ⇒ Object
- #move_cursor_left ⇒ Object
- #move_cursor_right ⇒ Object
- #move_cursor_to_end ⇒ Object
- #move_cursor_to_start ⇒ Object
- #request_tui_suspend!(reason, **metadata) ⇒ Object
- #should_quit? ⇒ Boolean
- #streaming? ⇒ Boolean
- #tui_suspend_metadata ⇒ Object
- #tui_suspend_requested? ⇒ Boolean
-
#update_input_scroll_offset ⇒ Object
Updates the horizontal scroll offset of the input area so the cursor is always visible.
-
#update_input_visible_width(width) ⇒ Object
Called by the renderer so the state knows how many characters fit on screen (inner width minus the prompt prefix).
Methods included from LoginFlow
#append_to_login_key, #delete_last_login_key_char, #enter_login_flow!, #exit_login_flow!, #init_login_flow, #login_active?, #login_advance_to_api_key!, #login_advance_to_auth_method!, #login_advance_to_oauth!, #login_clear_oauth_result!, #login_provider_module, #login_select_down, #login_select_up, #login_selected_item, #login_set_error!, #login_set_oauth_result!
Methods included from TokenCost
#init_token_cost, #session_cost_breakdown, #total_session_cost
Methods included from PlanTracking
#activate_plan_mode!, #append_to_clarification_input, #clarification_down, #clarification_up, #clear_plan!, #current_plan, #deactivate_plan_mode!, #delete_last_clarification_char, #enter_plan_clarification!, #exit_plan_clarification!, #has_unsaved_plan?, #init_plan_tracking, #mark_plan_saved!, #plan_clarification?, #plan_mode_active?, #plan_saved?, #selected_clarification_option, #toggle_clarification_input_mode!, #update_current_plan!
Methods included from ToolConfirmation
#auto_approve_tools?, #awaiting_tool_confirmation?, #clear_tool_confirmation!, #disable_auto_approve!, #enable_auto_approve!, #init_tool_confirmation, #pending_tool_args, #pending_tool_name, #request_tool_confirmation!, #resolve_tool_confirmation!, #tool_confirmation_response, #tool_confirmation_response=
Methods included from Scrollable
#scroll_down, #scroll_to_bottom, #scroll_to_top, #scroll_up, #update_scroll_metrics
Methods included from MessageTokenTracking
#token_usage_by_model, #total_input_tokens, #total_output_tokens, #total_thinking_tokens, #update_last_message_tokens
Methods included from MessageAssistant
#ensure_last_is_assistant!, #fail_last_assistant, #last_assistant_empty?, #reset_last_assistant_content, #streaming_append
Methods included from Messages
#add_message, #append_to_last_message, #build_message, #clear_messages!, #init_messages, #messages_snapshot
Methods included from ModelSelection
#append_to_model_filter, #delete_last_filter_char, #enter_model_select!, #exit_model_select!, #filtered_model_list, #model_select?, #model_select_down, #model_select_show_all?, #model_select_up, #selected_model
Constructor Details
#initialize(model:) ⇒ State
Returns a new instance of State.
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 |
# File 'lib/ruby_coded/chat/state.rb', line 34 def initialize(model:) @model = model # String.new: literals like "" are frozen under frozen_string_literal @input_buffer = String.new @cursor_position = 0 @input_scroll_offset = 0 @messages = [] @streaming = false @should_quit = false @agentic_mode = false @codex_mode = false @mutex = Mutex.new @dirty = true @last_render_at = 0.0 @scroll_offset = 0 @total_lines = 0 @visible_height = 0 @mode = :chat @model_list = [] @model_select_index = 0 @model_select_filter = String.new @model_select_show_all = false init_tool_confirmation init_plan_tracking init_token_cost init_login_flow init_plugin_state end |
Instance Attribute Details
#codex_mode ⇒ Object
Returns the value of attribute codex_mode.
30 31 32 |
# File 'lib/ruby_coded/chat/state.rb', line 30 def codex_mode @codex_mode end |
#cursor_position ⇒ Object (readonly)
Returns the value of attribute cursor_position.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def cursor_position @cursor_position end |
#input_buffer ⇒ Object (readonly)
Returns the value of attribute input_buffer.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def input_buffer @input_buffer end |
#input_scroll_offset ⇒ Object (readonly)
Returns the value of attribute input_scroll_offset.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def input_scroll_offset @input_scroll_offset end |
#messages ⇒ Object (readonly)
Returns the value of attribute messages.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def @messages end |
#mode ⇒ Object (readonly)
Returns the value of attribute mode.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def mode @mode end |
#model ⇒ Object
Returns the value of attribute model.
30 31 32 |
# File 'lib/ruby_coded/chat/state.rb', line 30 def model @model end |
#model_list ⇒ Object (readonly)
Returns the value of attribute model_list.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def model_list @model_list end |
#model_select_filter ⇒ Object (readonly)
Returns the value of attribute model_select_filter.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def model_select_filter @model_select_filter end |
#model_select_index ⇒ Object (readonly)
Returns the value of attribute model_select_index.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def model_select_index @model_select_index end |
#mutex ⇒ Object (readonly)
Returns the value of attribute mutex.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def mutex @mutex end |
#scroll_offset ⇒ Object (readonly)
Returns the value of attribute scroll_offset.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def scroll_offset @scroll_offset end |
#should_quit ⇒ Object
Returns the value of attribute should_quit.
30 31 32 |
# File 'lib/ruby_coded/chat/state.rb', line 30 def should_quit @should_quit end |
#streaming ⇒ Object
Returns the value of attribute streaming.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def streaming @streaming end |
#tui_suspend_reason ⇒ Object (readonly)
Returns the value of attribute tui_suspend_reason.
27 28 29 |
# File 'lib/ruby_coded/chat/state.rb', line 27 def tui_suspend_reason @tui_suspend_reason end |
Instance Method Details
#agentic_mode=(value) ⇒ Object
77 78 79 80 |
# File 'lib/ruby_coded/chat/state.rb', line 77 def agentic_mode=(value) @agentic_mode = value mark_dirty! end |
#agentic_mode? ⇒ Boolean
73 74 75 |
# File 'lib/ruby_coded/chat/state.rb', line 73 def agentic_mode? @agentic_mode end |
#append_to_input(text) ⇒ Object
128 129 130 131 132 133 134 |
# File 'lib/ruby_coded/chat/state.rb', line 128 def append_to_input(text) @input_buffer.insert(@cursor_position, text) @cursor_position += text.length update_input_scroll_offset mark_dirty! reset_command_completion_index if respond_to?(:reset_command_completion_index, true) end |
#clear_input! ⇒ Object
178 179 180 181 182 183 |
# File 'lib/ruby_coded/chat/state.rb', line 178 def clear_input! @input_buffer.clear @cursor_position = 0 @input_scroll_offset = 0 mark_dirty! end |
#clear_tui_suspend! ⇒ Object
207 208 209 210 |
# File 'lib/ruby_coded/chat/state.rb', line 207 def clear_tui_suspend! @tui_suspend_reason = nil @tui_suspend_metadata = nil end |
#consume_input! ⇒ Object
185 186 187 188 189 190 191 |
# File 'lib/ruby_coded/chat/state.rb', line 185 def consume_input! input = @input_buffer.dup @input_buffer.clear @cursor_position = 0 @input_scroll_offset = 0 input end |
#delete_last_char ⇒ Object
136 137 138 139 140 141 142 143 144 |
# File 'lib/ruby_coded/chat/state.rb', line 136 def delete_last_char return if @cursor_position <= 0 @input_buffer.slice!(@cursor_position - 1) @cursor_position -= 1 update_input_scroll_offset mark_dirty! reset_command_completion_index if respond_to?(:reset_command_completion_index, true) end |
#dirty? ⇒ Boolean
86 87 88 89 90 91 92 93 94 |
# File 'lib/ruby_coded/chat/state.rb', line 86 def dirty? @mutex.synchronize do return false unless @dirty return true unless @streaming now = Process.clock_gettime(Process::CLOCK_MONOTONIC) (now - @last_render_at) >= MIN_RENDER_INTERVAL end end |
#mark_clean! ⇒ Object
96 97 98 99 100 101 |
# File 'lib/ruby_coded/chat/state.rb', line 96 def mark_clean! @mutex.synchronize do @dirty = false @last_render_at = Process.clock_gettime(Process::CLOCK_MONOTONIC) end end |
#mark_dirty! ⇒ Object
103 104 105 |
# File 'lib/ruby_coded/chat/state.rb', line 103 def mark_dirty! @mutex.synchronize { @dirty = true } end |
#move_cursor_left ⇒ Object
146 147 148 149 150 151 152 |
# File 'lib/ruby_coded/chat/state.rb', line 146 def move_cursor_left return if @cursor_position <= 0 @cursor_position -= 1 update_input_scroll_offset mark_dirty! end |
#move_cursor_right ⇒ Object
154 155 156 157 158 159 160 |
# File 'lib/ruby_coded/chat/state.rb', line 154 def move_cursor_right return if @cursor_position >= @input_buffer.length @cursor_position += 1 update_input_scroll_offset mark_dirty! end |
#move_cursor_to_end ⇒ Object
170 171 172 173 174 175 176 |
# File 'lib/ruby_coded/chat/state.rb', line 170 def move_cursor_to_end return if @cursor_position == @input_buffer.length @cursor_position = @input_buffer.length update_input_scroll_offset mark_dirty! end |
#move_cursor_to_start ⇒ Object
162 163 164 165 166 167 168 |
# File 'lib/ruby_coded/chat/state.rb', line 162 def move_cursor_to_start return if @cursor_position == 0 @cursor_position = 0 update_input_scroll_offset mark_dirty! end |
#request_tui_suspend!(reason, **metadata) ⇒ Object
193 194 195 196 197 |
# File 'lib/ruby_coded/chat/state.rb', line 193 def request_tui_suspend!(reason, **) @tui_suspend_reason = reason @tui_suspend_metadata = mark_dirty! end |
#should_quit? ⇒ Boolean
82 83 84 |
# File 'lib/ruby_coded/chat/state.rb', line 82 def should_quit? @should_quit end |
#streaming? ⇒ Boolean
69 70 71 |
# File 'lib/ruby_coded/chat/state.rb', line 69 def streaming? @streaming end |
#tui_suspend_metadata ⇒ Object
203 204 205 |
# File 'lib/ruby_coded/chat/state.rb', line 203 def @tui_suspend_metadata || {} end |
#tui_suspend_requested? ⇒ Boolean
199 200 201 |
# File 'lib/ruby_coded/chat/state.rb', line 199 def tui_suspend_requested? !@tui_suspend_reason.nil? end |
#update_input_scroll_offset ⇒ Object
Updates the horizontal scroll offset of the input area so the cursor is always visible. Call this after every cursor / buffer change. visible_width is set by the renderer each frame via update_input_visible_width.
111 112 113 114 115 116 117 118 119 120 |
# File 'lib/ruby_coded/chat/state.rb', line 111 def update_input_scroll_offset visible = @input_visible_width || 0 return if visible <= 0 if @cursor_position < @input_scroll_offset @input_scroll_offset = @cursor_position elsif @cursor_position >= @input_scroll_offset + visible @input_scroll_offset = @cursor_position - visible + 1 end end |
#update_input_visible_width(width) ⇒ Object
Called by the renderer so the state knows how many characters fit on screen (inner width minus the prompt prefix).
124 125 126 |
# File 'lib/ruby_coded/chat/state.rb', line 124 def update_input_visible_width(width) @input_visible_width = width end |