Class: Legion::Extensions::Llm::Chat
- Inherits:
-
Object
- Object
- Legion::Extensions::Llm::Chat
- Includes:
- Enumerable, Logging::Helper
- Defined in:
- lib/legion/extensions/llm/chat.rb
Overview
Represents a conversation with an AI model
Instance Attribute Summary collapse
-
#headers ⇒ Object
readonly
Returns the value of attribute headers.
-
#messages ⇒ Object
readonly
Returns the value of attribute messages.
-
#model ⇒ Object
readonly
Returns the value of attribute model.
-
#params ⇒ Object
readonly
Returns the value of attribute params.
-
#schema ⇒ Object
readonly
Returns the value of attribute schema.
-
#tool_prefs ⇒ Object
readonly
Returns the value of attribute tool_prefs.
-
#tools ⇒ Object
readonly
Returns the value of attribute tools.
Instance Method Summary collapse
- #add_message(message_or_attributes) ⇒ Object
- #ask(message = nil, with: nil) ⇒ Object (also: #say)
-
#complete ⇒ Object
rubocop:disable Metrics/PerceivedComplexity.
- #each ⇒ Object
-
#initialize(model: nil, provider: nil, assume_model_exists: false, context: nil) ⇒ Chat
constructor
A new instance of Chat.
- #instance_variables ⇒ Object
- #on_end_message(&block) ⇒ Object
- #on_new_message(&block) ⇒ Object
- #on_tool_call(&block) ⇒ Object
- #on_tool_result(&block) ⇒ Object
- #reset_messages! ⇒ Object
- #with_context(context) ⇒ Object
- #with_headers(**headers) ⇒ Object
- #with_instructions(instructions, append: false, replace: nil) ⇒ Object
- #with_model(model_id, provider: nil, assume_exists: false) ⇒ Object
- #with_params(**params) ⇒ Object
- #with_schema(schema) ⇒ Object
- #with_temperature(temperature) ⇒ Object
- #with_thinking(effort: nil, budget: nil) ⇒ Object
- #with_tool(tool, choice: nil, calls: nil) ⇒ Object
- #with_tools(*tools, replace: false, choice: nil, calls: nil) ⇒ Object
Constructor Details
#initialize(model: nil, provider: nil, assume_model_exists: false, context: nil) ⇒ Chat
Returns a new instance of Chat.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/legion/extensions/llm/chat.rb', line 13 def initialize(model: nil, provider: nil, assume_model_exists: false, context: nil) if assume_model_exists && !provider raise ArgumentError, 'Provider must be specified if assume_model_exists is true' end @context = context @config = context&.config || Legion::Extensions::Llm.config model_id = model || @config.default_model with_model(model_id, provider: provider, assume_exists: assume_model_exists) @temperature = nil @messages = [] @tools = {} @tool_prefs = { choice: nil, calls: nil } @params = {} @headers = {} @schema = nil @thinking = nil @on = { new_message: nil, end_message: nil, tool_call: nil, tool_result: nil } end |
Instance Attribute Details
#headers ⇒ Object (readonly)
Returns the value of attribute headers.
11 12 13 |
# File 'lib/legion/extensions/llm/chat.rb', line 11 def headers @headers end |
#messages ⇒ Object (readonly)
Returns the value of attribute messages.
11 12 13 |
# File 'lib/legion/extensions/llm/chat.rb', line 11 def @messages end |
#model ⇒ Object (readonly)
Returns the value of attribute model.
11 12 13 |
# File 'lib/legion/extensions/llm/chat.rb', line 11 def model @model end |
#params ⇒ Object (readonly)
Returns the value of attribute params.
11 12 13 |
# File 'lib/legion/extensions/llm/chat.rb', line 11 def params @params end |
#schema ⇒ Object (readonly)
Returns the value of attribute schema.
11 12 13 |
# File 'lib/legion/extensions/llm/chat.rb', line 11 def schema @schema end |
#tool_prefs ⇒ Object (readonly)
Returns the value of attribute tool_prefs.
11 12 13 |
# File 'lib/legion/extensions/llm/chat.rb', line 11 def tool_prefs @tool_prefs end |
#tools ⇒ Object (readonly)
Returns the value of attribute tools.
11 12 13 |
# File 'lib/legion/extensions/llm/chat.rb', line 11 def tools @tools end |
Instance Method Details
#add_message(message_or_attributes) ⇒ Object
176 177 178 179 180 |
# File 'lib/legion/extensions/llm/chat.rb', line 176 def () = .is_a?(Message) ? : Message.new() << end |
#ask(message = nil, with: nil) ⇒ Object Also known as: say
38 39 40 41 |
# File 'lib/legion/extensions/llm/chat.rb', line 38 def ask( = nil, with: nil, &) role: :user, content: build_content(, with) complete(&) end |
#complete ⇒ Object
rubocop:disable Metrics/PerceivedComplexity
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/legion/extensions/llm/chat.rb', line 142 def complete(&) # rubocop:disable Metrics/PerceivedComplexity response = @provider.complete( , tools: @tools, tool_prefs: @tool_prefs, temperature: @temperature, model: @model, params: @params, headers: @headers, schema: @schema, thinking: @thinking, &wrap_streaming_block(&) ) @on[:new_message]&.call unless block_given? if @schema && response.content.is_a?(String) && !response.tool_call? begin response.content = Legion::JSON.parse(response.content, symbolize_names: false) rescue Legion::JSON::ParseError => e handle_exception(e, level: :warn, handled: true, operation: 'llm.chat.complete') end end response @on[:end_message]&.call(response) if response.tool_call? handle_tool_calls(response, &) else response end end |
#each ⇒ Object
138 139 140 |
# File 'lib/legion/extensions/llm/chat.rb', line 138 def each(&) .each(&) end |
#instance_variables ⇒ Object
186 187 188 |
# File 'lib/legion/extensions/llm/chat.rb', line 186 def instance_variables super - %i[@connection @config] end |
#on_end_message(&block) ⇒ Object
123 124 125 126 |
# File 'lib/legion/extensions/llm/chat.rb', line 123 def (&block) @on[:end_message] = block self end |
#on_new_message(&block) ⇒ Object
118 119 120 121 |
# File 'lib/legion/extensions/llm/chat.rb', line 118 def (&block) @on[:new_message] = block self end |
#on_tool_call(&block) ⇒ Object
128 129 130 131 |
# File 'lib/legion/extensions/llm/chat.rb', line 128 def on_tool_call(&block) @on[:tool_call] = block self end |
#on_tool_result(&block) ⇒ Object
133 134 135 136 |
# File 'lib/legion/extensions/llm/chat.rb', line 133 def on_tool_result(&block) @on[:tool_result] = block self end |
#reset_messages! ⇒ Object
182 183 184 |
# File 'lib/legion/extensions/llm/chat.rb', line 182 def @messages.clear end |
#with_context(context) ⇒ Object
91 92 93 94 95 96 |
# File 'lib/legion/extensions/llm/chat.rb', line 91 def with_context(context) @context = context @config = context.config with_model(@model.id, provider: @provider.slug, assume_exists: true) self end |
#with_headers(**headers) ⇒ Object
103 104 105 106 |
# File 'lib/legion/extensions/llm/chat.rb', line 103 def with_headers(**headers) @headers = headers self end |
#with_instructions(instructions, append: false, replace: nil) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/legion/extensions/llm/chat.rb', line 45 def with_instructions(instructions, append: false, replace: nil) append ||= (replace == false) unless replace.nil? if append append_system_instruction(instructions) else replace_system_instruction(instructions) end self end |
#with_model(model_id, provider: nil, assume_exists: false) ⇒ Object
73 74 75 76 77 |
# File 'lib/legion/extensions/llm/chat.rb', line 73 def with_model(model_id, provider: nil, assume_exists: false) @model, @provider = Models.resolve(model_id, provider:, assume_exists:, config: @config) @connection = @provider.connection self end |
#with_params(**params) ⇒ Object
98 99 100 101 |
# File 'lib/legion/extensions/llm/chat.rb', line 98 def with_params(**params) @params = params self end |
#with_schema(schema) ⇒ Object
108 109 110 111 112 113 114 115 116 |
# File 'lib/legion/extensions/llm/chat.rb', line 108 def with_schema(schema) schema_instance = schema.is_a?(Class) ? schema.new : schema @schema = normalize_schema_payload( schema_instance.respond_to?(:to_json_schema) ? schema_instance.to_json_schema : schema_instance ) self end |
#with_temperature(temperature) ⇒ Object
79 80 81 82 |
# File 'lib/legion/extensions/llm/chat.rb', line 79 def with_temperature(temperature) @temperature = temperature self end |
#with_thinking(effort: nil, budget: nil) ⇒ Object
84 85 86 87 88 89 |
# File 'lib/legion/extensions/llm/chat.rb', line 84 def with_thinking(effort: nil, budget: nil) raise ArgumentError, 'with_thinking requires :effort or :budget' if effort.nil? && budget.nil? @thinking = Thinking::Config.new(effort: effort, budget: budget) self end |
#with_tool(tool, choice: nil, calls: nil) ⇒ Object
57 58 59 60 61 62 63 64 |
# File 'lib/legion/extensions/llm/chat.rb', line 57 def with_tool(tool, choice: nil, calls: nil) unless tool.nil? tool_instance = tool.is_a?(Class) ? tool.new : tool @tools[tool_instance.name.to_sym] = tool_instance end (choice:, calls:) self end |
#with_tools(*tools, replace: false, choice: nil, calls: nil) ⇒ Object
66 67 68 69 70 71 |
# File 'lib/legion/extensions/llm/chat.rb', line 66 def with_tools(*tools, replace: false, choice: nil, calls: nil) @tools.clear if replace tools.compact.each { |tool| with_tool tool } (choice:, calls:) self end |