Class: Kreator::InteractiveCLI
- Inherits:
-
Object
- Object
- Kreator::InteractiveCLI
- Defined in:
- lib/kreator/interactive_cli.rb
Defined Under Namespace
Classes: ChatModel, Command, Config, MatchedCommand, TranscriptEntry
Constant Summary collapse
- PROMPT_MARKER =
"You"- DEFAULT_MODELS =
{ "openai" => %w[gpt-5.5 gpt-5.4 gpt-5.4-mini gpt-5.3-codex gpt-5.3-codex-spark gpt-5.2], "anthropic" => %w[ claude-sonnet-4-20250514 claude-opus-4-1-20250805 claude-opus-4-20250514 claude-3-7-sonnet-20250219 claude-3-5-haiku-20241022 ], "openrouter" => %w[ openrouter/auto moonshotai/kimi-k2.6 qwen/qwen3.6-plus openai/gpt-5.5 openai/gpt-5.4 openai/gpt-5.3-codex z-ai/glm-5 moonshotai/kimi-k2.5 anthropic/claude-sonnet-4 google/gemini-2.5-pro ] }.freeze
- DEFAULT_CONTEXT_WINDOWS =
{ "openai" => [ [/gpt-5(?:\.|-|\z)/, 400_000], [/4\.1|4o/, 128_000] ], "anthropic" => [ [/.*/, 200_000] ], "openrouter" => [ [/kimi-k2\.[56]/, 262_144], [/qwen3\.6-plus/, 1_000_000], [/glm-5/, 80_000], [/gpt-5(?:\.|-|\z)/, 400_000], [/4\.1|4o/, 128_000], [/claude/, 200_000] ] }.freeze
- COMMAND_AUTOCOMPLETE =
[ ["/exit", "exit the CLI"], ["/help", "show commands"], ["/clear", "clear context and start a new session"], ["/new", "clear context and start a new session"], ["/resume", "resume recent session"], ["/login", "authenticate OpenAI ChatGPT/Codex"], ["/logout", "remove Kreator OpenAI OAuth credentials"], ["/model", "show or change model"], ["/session", "show or resume session"], ["/label", "label current session"], ["/search", "search sessions"], ["/export", "export current session"], ["/cleanup", "delete empty sessions"], ["/branches", "list session branches"], ["/fork", "fork session history"], ["/prompts", "list prompt templates"], ["/prompt", "run a prompt template"], ["/skills", "list skills"], ["/plugins", "list plugins"], ["/plugin validate", "validate a plugin"], ["/compact", "compact session context"] ].freeze
- COMMANDS =
[ Command.new(pattern: %r{\A(?::q|/(?:exit|quit))\z}, handler: :exit_command), Command.new(pattern: %r{\A/help\z}, handler: :help_command), Command.new(pattern: %r{\A/(?:clear|new)\z}, handler: :clear_session_command), Command.new(pattern: %r{\A/resume\z}, handler: :resume_recent_command), Command.new(pattern: %r{\A/login\z}, handler: :login_command), Command.new(pattern: %r{\A/logout\z}, handler: :logout_command), Command.new(pattern: %r{\A/model\s+(.+)\z}, handler: :select_model_command), Command.new(pattern: %r{\A/model\z}, handler: :current_model_command), Command.new(pattern: %r{\A/session\s+(.+)\z}, handler: :resume_session_command), Command.new(pattern: %r{\A/session\z}, handler: :current_session_command), Command.new(pattern: %r{\A/label\s+(.+)\z}, handler: :label_session_command), Command.new(pattern: %r{\A/search\s+(.+)\z}, handler: :search_sessions_command), Command.new(pattern: %r{\A/export(?:\s+(\S+))?\z}, handler: :export_session_command), Command.new(pattern: %r{\A/cleanup\z}, handler: :cleanup_empty_sessions_command), Command.new(pattern: %r{\A/branches\z}, handler: :branches_command), Command.new(pattern: %r{\A/fork\s+(\d+)\z}, handler: :fork_session_command), Command.new(pattern: %r{\A/prompts\z}, handler: :prompts_command), Command.new(pattern: %r{\A/skills\z}, handler: :skills_command), Command.new(pattern: %r{\A/(?:plugins|plugin list)\z}, handler: :plugins_command), Command.new(pattern: %r{\A/plugin\s+validate\s+(.+)\z}, handler: :validate_plugin_command), Command.new(pattern: %r{\A/prompt\s+(\S+)(?:\s+(.+))?\z}m, handler: :prompt_template_command), Command.new(pattern: %r{\A/compact\z}, handler: :compact_command) ].freeze
Instance Method Summary collapse
- #available_autocomplete_items ⇒ Object
- #available_models ⇒ Object
- #available_plugins ⇒ Object
- #available_prompts ⇒ Object
- #available_sessions ⇒ Object
- #available_skills ⇒ Object
- #consume_context_cleared ⇒ Object
- #consume_model_changed ⇒ Object
- #context_meter ⇒ Object
- #fork_session(entry_index) ⇒ Object
-
#initialize(config = nil) ⇒ InteractiveCLI
constructor
A new instance of InteractiveCLI.
- #resume_session(path) ⇒ Object
- #run ⇒ Object
- #select_model(model_name) ⇒ Object
- #submit(prompt, signal: nil, on_entry: nil) ⇒ Object
- #transcript ⇒ Object
- #welcome_panel ⇒ Object
Constructor Details
#initialize(config = nil) ⇒ InteractiveCLI
Returns a new instance of InteractiveCLI.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/kreator/interactive_cli.rb', line 112 def initialize(config = nil, **) config ||= Config.new(**) @provider_builder = config.provider_builder @provider_name = config.provider_name @model = config.model @tools = config.tools @context = config.context @session_manager = config.session_manager @session = config.session @stdin = config.stdin @stdout = config.stdout @stderr = config.stderr @resources = config.resources || Resources.new @compact_threshold = config.compact_threshold @auth_manager = config.auth_manager || Providers::OpenAIAuth @last_usage = nil @context_window = inferred_context_window end |
Instance Method Details
#available_autocomplete_items ⇒ Object
180 181 182 183 184 185 186 187 188 189 |
# File 'lib/kreator/interactive_cli.rb', line 180 def available_autocomplete_items command_items = COMMAND_AUTOCOMPLETE.map do |value, description| { value: value, label: value, description: description, kind: "command" } end skill_items = resources.skills.map do |skill| { value: "$#{skill.name}", label: "skill: #{skill.name}", description: "load skill context", kind: "skill" } end command_items + skill_items end |
#available_models ⇒ Object
160 161 162 |
# File 'lib/kreator/interactive_cli.rb', line 160 def available_models (DEFAULT_MODELS.fetch(provider_name, []) | [model]).compact end |
#available_plugins ⇒ Object
176 177 178 |
# File 'lib/kreator/interactive_cli.rb', line 176 def available_plugins resources.plugins end |
#available_prompts ⇒ Object
168 169 170 |
# File 'lib/kreator/interactive_cli.rb', line 168 def available_prompts resources.prompt_templates end |
#available_sessions ⇒ Object
164 165 166 |
# File 'lib/kreator/interactive_cli.rb', line 164 def available_sessions session_manager.list(cwd: Dir.pwd) end |
#available_skills ⇒ Object
172 173 174 |
# File 'lib/kreator/interactive_cli.rb', line 172 def available_skills resources.skills end |
#consume_context_cleared ⇒ Object
233 234 235 236 237 |
# File 'lib/kreator/interactive_cli.rb', line 233 def consume_context_cleared cleared = @context_cleared @context_cleared = false cleared end |
#consume_model_changed ⇒ Object
239 240 241 242 243 |
# File 'lib/kreator/interactive_cli.rb', line 239 def consume_model_changed changed = @model_changed @model_changed = false changed end |
#context_meter ⇒ Object
222 223 224 225 226 227 228 229 230 231 |
# File 'lib/kreator/interactive_cli.rb', line 222 def context_meter window = @context_window used = @last_usage&.fetch("total_tokens", nil) { window: window, used: used, available: window && used ? [window - used, 0].max : nil } end |
#fork_session(entry_index) ⇒ Object
245 246 247 248 249 250 |
# File 'lib/kreator/interactive_cli.rb', line 245 def fork_session(entry_index) return system_line("Session persistence disabled") unless session @session = session_manager.fork(path: session.path, entry_index: entry_index) system_line("Forked session #{@session.id} from entry #{entry_index}") end |
#resume_session(path) ⇒ Object
217 218 219 220 |
# File 'lib/kreator/interactive_cli.rb', line 217 def resume_session(path) @session = @session_manager.open(path: path) system_line("Resumed session #{@session.id}") end |
#run ⇒ Object
131 132 133 134 135 136 137 138 139 140 |
# File 'lib/kreator/interactive_cli.rb', line 131 def run return run_line_mode unless tty? load_charm! Bubbletea.run(ChatModel.new(runtime: self)) 0 rescue LoadError => e @stderr.puts "kreator: interactive mode requires Charm Ruby gems: #{e.}" 1 end |
#select_model(model_name) ⇒ Object
208 209 210 211 212 213 214 215 |
# File 'lib/kreator/interactive_cli.rb', line 208 def select_model(model_name) @model = model_name @session&.append_model_change(provider: @provider_name, model: @model) @last_usage = nil @context_window = inferred_context_window @model_changed = true system_line("Model set to #{@model}") end |
#submit(prompt, signal: nil, on_entry: nil) ⇒ Object
142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/kreator/interactive_cli.rb', line 142 def submit(prompt, signal: nil, on_entry: nil) prompt = prompt.to_s.strip return [] if prompt.empty? command = matched_command(prompt) return dispatch_command(command, signal: signal, on_entry: on_entry) if command run_agent(prompt, signal: signal) rescue ToolCancellationError [system_line("Interrupted.")] rescue StandardError => e [system_line("#{e.class}: #{e.}")] end |
#transcript ⇒ Object
156 157 158 |
# File 'lib/kreator/interactive_cli.rb', line 156 def transcript .map { || () } end |
#welcome_panel ⇒ Object
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/kreator/interactive_cli.rb', line 191 def welcome_panel rows = [ ">_ Kreator (v#{Kreator::VERSION})", "", "model: #{model} /model to change", "directory: #{display_directory}" ] content_width = [44, rows.map(&:length).max].max horizontal = "─" * (content_width + 2) [ "╭#{horizontal}╮", *rows.map { |row| "│ #{row.ljust(content_width)} │" }, "╰#{horizontal}╯" ].join("\n") end |