ruby_conversations 1.0.7 → 1.0.8

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -16
  3. data/app/models/concerns/ruby_conversations/conversation_chat.rb +49 -0
  4. data/app/models/concerns/ruby_conversations/conversation_messages.rb +18 -0
  5. data/app/models/{ruby_conversations/concerns → concerns/ruby_conversations}/llm_credentials.rb +1 -0
  6. data/app/models/concerns/ruby_conversations/message_api_attributes.rb +39 -0
  7. data/app/models/concerns/ruby_conversations/message_attributes.rb +44 -0
  8. data/app/models/concerns/ruby_conversations/message_processing.rb +48 -0
  9. data/app/models/{ruby_conversations/concerns → concerns/ruby_conversations}/message_validation.rb +2 -2
  10. data/app/models/concerns/ruby_conversations/storable.rb +13 -0
  11. data/app/models/ruby_conversations/conversation.rb +102 -0
  12. data/app/models/ruby_conversations/message.rb +108 -0
  13. data/app/models/ruby_conversations/message_builder.rb +45 -20
  14. data/app/models/ruby_conversations/message_input.rb +69 -0
  15. data/app/models/ruby_conversations/message_prompt.rb +110 -0
  16. data/app/models/ruby_conversations/prompt.rb +48 -39
  17. data/lib/ruby_conversations/aws_credential_provider.rb +11 -5
  18. data/lib/ruby_conversations/client.rb +90 -0
  19. data/lib/ruby_conversations/configuration.rb +3 -13
  20. data/lib/ruby_conversations/engine.rb +2 -0
  21. data/lib/ruby_conversations/errors.rb +9 -0
  22. data/lib/ruby_conversations/version.rb +1 -1
  23. data/lib/ruby_conversations.rb +15 -42
  24. metadata +43 -81
  25. data/Rakefile +0 -12
  26. data/app/models/concerns/ruby_conversations/messageable.rb +0 -13
  27. data/app/models/concerns/ruby_conversations/versionable.rb +0 -20
  28. data/app/models/ruby_conversations/ai_conversation.rb +0 -91
  29. data/app/models/ruby_conversations/ai_message.rb +0 -28
  30. data/app/models/ruby_conversations/ai_message_input.rb +0 -22
  31. data/app/models/ruby_conversations/ai_message_prompt.rb +0 -28
  32. data/app/models/ruby_conversations/prompt_version.rb +0 -16
  33. data/lib/generators/ruby_conversations/install/install_generator.rb +0 -60
  34. data/lib/generators/ruby_conversations/install/templates/README.md +0 -42
  35. data/lib/generators/ruby_conversations/install/templates/initializer.rb.erb +0 -18
  36. data/lib/generators/ruby_conversations/install/templates/migrations/create_ai_conversations.rb.erb +0 -13
  37. data/lib/generators/ruby_conversations/install/templates/migrations/create_ai_message_inputs.rb.erb +0 -13
  38. data/lib/generators/ruby_conversations/install/templates/migrations/create_ai_message_prompts.rb.erb +0 -18
  39. data/lib/generators/ruby_conversations/install/templates/migrations/create_ai_messages.rb.erb +0 -18
  40. data/lib/generators/ruby_conversations/install/templates/migrations/create_ai_tool_calls.rb.erb +0 -15
  41. data/lib/generators/ruby_conversations/install/templates/migrations/create_prompt_versions.rb.erb +0 -14
  42. data/lib/generators/ruby_conversations/install/templates/migrations/create_prompts.rb.erb +0 -16
  43. data/lib/ruby_conversations/jwt_client.rb +0 -23
  44. data/lib/ruby_conversations/storage/base.rb +0 -28
  45. data/lib/ruby_conversations/storage/local.rb +0 -30
  46. data/lib/ruby_conversations/storage/remote.rb +0 -93
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e51a404e8fe0e362f5429272e3c39fab96e281d8a7bf44e631e37e0ff6cdb689
4
- data.tar.gz: 499bcaf7b5959b0a132fcbf79d06c69752fbfaf497cb0bbd5c22ce0fa3e5679b
3
+ metadata.gz: 0e17ddcaa7e94a64865389aacc5a81be28420996569467fa5ce09df3bd89ae15
4
+ data.tar.gz: c58ed8d7b057648e44775625f968b735c636085b300aad2fd0f5a6d5a73466f1
5
5
  SHA512:
6
- metadata.gz: d520b36e1c90509515a80cff8a47c03232bdb80bcd3138423e6ca1337c6c245050919c5abab03cd94cfcfb1aa1ce224f6ee9405e810e722760418f9ab8c14efa
7
- data.tar.gz: 57924e0b318cb11b8c6f5f12e4614da011e5003912912f415e02dcea5ebb8090e0cfc0c4bef0d5575933667a6188edab1115126d87f3cdb88e486e3af0377db3
6
+ metadata.gz: df3e61d4e421e2dbf36d46000178d90ed880f2181f2734c41e64b00b92fc4008b7a5530b568d10e302daea259d3fec9c9e3106dda1e71beb7aa7ec7e95ece901
7
+ data.tar.gz: d908fdd54838e93af0e93fe3d00fd579f7663182c2166741f688cf5debc25d4cd98721d8db7222deaf38865d26480cd44019d84d84e397f225e0e9eba03ed778
data/README.md CHANGED
@@ -49,21 +49,11 @@ Configure the engine in `config/initializers/ai_conversation_engine.rb`:
49
49
 
50
50
  ```ruby
51
51
  AiConversationEngine.configure do |config|
52
- # Storage mode: :local or :remote
53
- config.storage_mode = :local
54
-
55
- # Remote API settings (only needed for remote mode)
56
- # config.api_url = ENV['AI_CONVERSATION_API_URL']
57
- # config.jwt_secret = ENV['AI_CONVERSATION_JWT_SECRET']
58
-
52
+ # API settings
53
+ config.api_url = ENV['AI_CONVERSATION_API_URL']
54
+ config.jwt_secret = ENV['AI_CONVERSATION_JWT_SECRET']
59
55
  # Default LLM settings
60
56
  config.default_llm_model = 'gpt-4'
61
-
62
- # Customize model behaviors
63
- config.conversation_class = 'AiConversation'
64
- config.message_class = 'AiMessage'
65
- config.prompt_class = 'Prompt'
66
-
67
57
  end
68
58
  ```
69
59
 
@@ -84,7 +74,7 @@ conversation.ask("explain_code", inputs: { code: "def hello; end" })
84
74
  ```ruby
85
75
  # Create a conversation linked to another object
86
76
  class Project < ApplicationRecord
87
- has_many :conversations, as: :conversationable,
77
+ has_many :conversations, as: :conversationable,
88
78
  class_name: 'AiConversationEngine::AiConversation'
89
79
  end
90
80
 
@@ -97,8 +87,7 @@ conversation.ask("analyze_project", inputs: { name: project.name })
97
87
 
98
88
  ```ruby
99
89
  # Configure for remote storage
100
- AiConversationEngine.configure do |config|
101
- config.storage_mode = :remote
90
+ ConversationEngine.configure do |config|
102
91
  config.api_url = "https://ai-conversation-api.example.com"
103
92
  config.jwt_secret = ENV['JWT_SECRET']
104
93
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyConversations
4
+ # Handles chat-related functionality for Conversation
5
+ module ConversationChat
6
+ extend ActiveSupport::Concern
7
+
8
+ def execute(system_message: nil)
9
+ message = messages.last
10
+ raise ArgumentError, 'Conversation must have at least one message to execute' unless message
11
+
12
+ chat = setup_llm_chat(system_message: system_message)
13
+ response = chat.ask(message.request)
14
+ update_last_message_response(message, response)
15
+ json_response = save_conversation
16
+ {
17
+ response: response,
18
+ conversation: json_response
19
+ }
20
+ end
21
+
22
+ def llm
23
+ case model_identifier
24
+ when 'claude-3-7-sonnet'
25
+ 'us.anthropic.claude-3-7-sonnet-20250219-v1:0'
26
+ else
27
+ model_identifier
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def setup_llm_chat(system_message: nil)
34
+ configure_llm_credentials
35
+ build_chat(system_message)
36
+ end
37
+
38
+ def update_last_message_response(message, response)
39
+ message.response = response.to_h.to_json
40
+ end
41
+
42
+ def build_chat(system_message)
43
+ chat = RubyLLM.chat(model: llm, provider: provider).with_temperature(0.0)
44
+ chat.with_tool(tool) if tool.present?
45
+ chat.add_message(role: :system, content: system_message) if system_message.present?
46
+ chat
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyConversations
4
+ # Handles message-related functionality for Conversation
5
+ module ConversationMessages
6
+ extend ActiveSupport::Concern
7
+
8
+ def ask_multiple(prompt_inputs, description: nil)
9
+ MessageBuilder.new(self).build_from_multiple_prompts(prompt_inputs, description: description)
10
+ self
11
+ end
12
+
13
+ def ask(name, description: nil, inputs: {})
14
+ MessageBuilder.new(self).build_from_single_prompt(name, description: description, inputs: inputs)
15
+ self
16
+ end
17
+ end
18
+ end
@@ -12,6 +12,7 @@ module RubyConversations
12
12
  def configure_llm_credentials
13
13
  RubyLLM.configure do |config|
14
14
  credentials = ENV['AWS_ACCESS_KEY_ID'].present? ? env_credentials : provider_credentials
15
+ config.bedrock_region = ENV.fetch('AWS_REGION', 'us-west-2')
15
16
  config.bedrock_api_key = credentials[:api_key]
16
17
  config.bedrock_secret_key = credentials[:secret_key]
17
18
  config.bedrock_session_token = credentials[:session_token]
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyConversations
4
+ # Handles API-related attribute functionality for Message
5
+ module MessageApiAttributes
6
+ extend ActiveSupport::Concern
7
+
8
+ def message_attributes_for_api
9
+ {
10
+ request: request,
11
+ response: response,
12
+ model_identifier: model_identifier,
13
+ change_description: change_description,
14
+ llm: llm
15
+ }.compact
16
+ end
17
+
18
+ def message_base_attributes
19
+ {
20
+ 'request' => request,
21
+ 'response' => response,
22
+ 'model_identifier' => model_identifier,
23
+ 'change_description' => change_description
24
+ }
25
+ end
26
+
27
+ def remote_attributes
28
+ base_attributes.compact
29
+ end
30
+
31
+ private
32
+
33
+ def base_attributes
34
+ MessageAttributes::ATTRIBUTE_NAMES.each_with_object({}) do |attr_name, attrs|
35
+ attrs[attr_name] = public_send(attr_name)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyConversations
4
+ # Handles attribute-related functionality for Message
5
+ module MessageAttributes
6
+ extend ActiveSupport::Concern
7
+
8
+ ATTRIBUTE_NAMES = %w[
9
+ id ai_conversation_id request response model_identifier
10
+ tool change_description llm created_at updated_at
11
+ ].freeze
12
+
13
+ included do
14
+ # Define core message attributes
15
+ attr_accessor :request, :response, :model_identifier, :change_description
16
+
17
+ # Define relationship attributes
18
+ attr_accessor :ai_conversation, :message_prompts, :prompts
19
+
20
+ # Common validations
21
+ validates :llm, presence: true
22
+ validates :request, presence: true
23
+
24
+ # Override initialize to ensure arrays are initialized
25
+ def initialize(attributes = {})
26
+ @message_prompts = []
27
+ @prompts = []
28
+ super
29
+ end
30
+ end
31
+
32
+ def remote_attributes
33
+ base_attributes.compact
34
+ end
35
+
36
+ private
37
+
38
+ def base_attributes
39
+ ATTRIBUTE_NAMES.each_with_object({}) do |attr_name, attrs|
40
+ attrs[attr_name] = public_send(attr_name)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyConversations
4
+ # Handles message processing and initialization logic
5
+ module MessageProcessing
6
+ extend ActiveSupport::Concern
7
+
8
+ private
9
+
10
+ def process_message_prompts(msg_data)
11
+ prompts_data = extract_prompts_data(msg_data)
12
+ prompts_data.map { |prompt_data| build_message_prompt(prompt_data) }
13
+ end
14
+
15
+ def extract_prompts_data(msg_data)
16
+ prompts_data = msg_data.delete(:prompts) ||
17
+ msg_data.delete(:message_prompts) ||
18
+ msg_data.delete('message_prompts') ||
19
+ msg_data.delete(:ai_message_prompts_attributes) ||
20
+ msg_data.delete('ai_message_prompts_attributes')
21
+ prompts_data || []
22
+ end
23
+
24
+ def build_message_prompt(prompt_data)
25
+ inputs_data = extract_inputs_data(prompt_data)
26
+ processed_inputs = inputs_data.map { |input_data| build_message_input(input_data) }
27
+
28
+ prompt_instance = RubyConversations::MessagePrompt.new(
29
+ prompt_data.except('id', 'message_id', 'created_at', 'updated_at')
30
+ )
31
+ prompt_instance.message_inputs = processed_inputs
32
+ prompt_instance
33
+ end
34
+
35
+ def extract_inputs_data(prompt_data)
36
+ inputs_data = prompt_data.delete(:inputs) ||
37
+ prompt_data.delete(:message_inputs) ||
38
+ prompt_data.delete('message_inputs')
39
+ inputs_data || []
40
+ end
41
+
42
+ def build_message_input(input_data)
43
+ RubyConversations::MessageInput.new(
44
+ input_data.except('id', 'message_prompt_id', 'created_at', 'updated_at')
45
+ )
46
+ end
47
+ end
48
+ end
@@ -10,11 +10,11 @@ module RubyConversations
10
10
  private
11
11
 
12
12
  def validate_messages
13
- ai_messages.each do |message|
13
+ messages.each do |message|
14
14
  validate_message_level(message)
15
15
  message.ai_message_prompts.each do |prompt|
16
16
  validate_prompt_level(prompt)
17
- prompt.ai_message_inputs.each do |input|
17
+ prompt.message_inputs.each do |input|
18
18
  validate_input_level(input)
19
19
  end
20
20
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyConversations
4
+ # Module for handling storage functionality in Ruby Conversations
5
+ # Provides methods for storing and retrieving conversation data
6
+ module Storable
7
+ extend ActiveSupport::Concern
8
+
9
+ def save_conversation
10
+ RubyConversations.client.store_conversation(self)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model'
4
+ require_relative '../concerns/ruby_conversations/conversation_chat'
5
+ require_relative '../concerns/ruby_conversations/conversation_messages'
6
+ require_relative '../concerns/ruby_conversations/llm_credentials'
7
+ require_relative '../concerns/ruby_conversations/message_validation'
8
+ require_relative '../concerns/ruby_conversations/message_processing'
9
+ require_relative '../concerns/ruby_conversations/storable'
10
+ module RubyConversations
11
+ # Represents a conversation thread, managing messages and interactions with the LLM.
12
+ class Conversation
13
+ include ActiveModel::Model
14
+ include ConversationChat
15
+ include ConversationMessages
16
+ include LlmCredentials
17
+ include MessageValidation
18
+ include MessageProcessing
19
+ include Storable
20
+
21
+ # Define attributes needed for API interaction & local state
22
+ attr_accessor :id, :conversationable_type, :conversationable_id, :conversationable,
23
+ :messages, :tool, :created_at, :updated_at
24
+
25
+ # Validations
26
+ validates :messages, presence: { message: 'At least one message is required' }, on: :update
27
+ validate :validate_messages
28
+
29
+ # Initialization
30
+ def initialize(attributes = nil)
31
+ attributes ||= {}
32
+ # Ensure messages is always an array before super assigns other attributes
33
+ @messages = []
34
+ # Extract nested attributes before super tries to assign them
35
+ messages_attrs = attributes.delete(:messages) || attributes.delete('messages') ||
36
+ attributes.delete(:messages_attributes) || attributes.delete('messages_attributes') || []
37
+
38
+ super # Initialize with remaining attributes using ActiveModel::Model
39
+ initialize_messages(messages_attrs)
40
+ end
41
+
42
+ def model_identifier
43
+ @model_identifier ||= RubyConversations.configuration.default_llm_model
44
+ end
45
+
46
+ def provider
47
+ @provider ||= RubyConversations.configuration.default_llm_provider
48
+ end
49
+
50
+ def initialize_messages(message_attributes)
51
+ (message_attributes || []).each do |msg_data|
52
+ processed_prompts = process_message_prompts(msg_data)
53
+
54
+ message_instance = RubyConversations::Message.new(msg_data.except('id', 'conversation_id', 'created_at',
55
+ 'updated_at'))
56
+ message_instance.message_prompts = processed_prompts
57
+ @messages << message_instance # Add to the messages array
58
+ end
59
+ end
60
+
61
+ def conversation_attributes_for_storage
62
+ { ai_conversation: base_attributes.merge(relationship_attributes).merge(messages_attributes).compact }
63
+ end
64
+
65
+ private
66
+
67
+ def base_attributes
68
+ {
69
+ id: id
70
+ }
71
+ end
72
+
73
+ def configuration_attributes
74
+ {
75
+ tool: tool
76
+ }
77
+ end
78
+
79
+ def relationship_attributes
80
+ {
81
+ conversationable_type: conversationable_type,
82
+ conversationable_id: conversationable_id
83
+ }
84
+ end
85
+
86
+ def messages_attributes
87
+ {
88
+ messages_attributes: messages.map(&:attributes_for_api)
89
+ }
90
+ end
91
+
92
+ def validate_messages
93
+ messages.each do |message|
94
+ next if message.valid?
95
+
96
+ message.errors.full_messages.each do |msg|
97
+ errors.add(:messages, "invalid: #{msg}")
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model'
4
+ require_relative 'message_prompt'
5
+ require_relative '../concerns/ruby_conversations/message_attributes'
6
+ require_relative '../concerns/ruby_conversations/message_api_attributes'
7
+
8
+ module RubyConversations
9
+ # Represents a message in a conversation, either from the user or AI
10
+ class Message
11
+ include ActiveModel::Model
12
+ include MessageAttributes
13
+ include MessageApiAttributes
14
+
15
+ # Define attributes
16
+ attr_accessor :id, :conversation_id, :llm,
17
+ :temperature, :tool, :metadata, :created_at, :updated_at,
18
+ :message_prompts
19
+
20
+ # Constants
21
+ ROLES = {
22
+ user: 'user',
23
+ assistant: 'assistant'
24
+ }.freeze
25
+
26
+ def initialize(attributes = {})
27
+ @message_prompts = []
28
+ prompts_attributes = extract_nested_attributes!(attributes, :message_prompts)
29
+ # Also check for Rails-style nested attributes
30
+ prompts_attributes ||= extract_nested_attributes!(attributes, :ai_message_prompts_attributes)
31
+
32
+ super
33
+ initialize_message_prompts(prompts_attributes)
34
+ end
35
+
36
+ def initialize_message_prompts(attributes_array)
37
+ (attributes_array || []).each do |attrs|
38
+ next if attrs.blank?
39
+
40
+ @message_prompts << RubyConversations::MessagePrompt.new(attrs)
41
+ end
42
+ end
43
+
44
+ def message_prompts_attributes=(attributes_array)
45
+ @message_prompts = []
46
+ initialize_message_prompts(attributes_array)
47
+ end
48
+
49
+ # Alias for Rails nested attributes convention
50
+ alias ai_message_prompts_attributes= message_prompts_attributes=
51
+
52
+ # Attributes method for serialization/logging
53
+ def attributes
54
+ base_attributes.merge(
55
+ 'llm' => llm,
56
+ 'temperature' => temperature,
57
+ 'tool' => tool,
58
+ 'ai_message_prompts_attributes' => message_prompts.map(&:attributes)
59
+ )
60
+ end
61
+
62
+ # Method for API serialization
63
+ def attributes_for_api
64
+ {
65
+ id: id,
66
+ conversation_id: conversation_id,
67
+ metadata: metadata,
68
+ llm: llm,
69
+ tool: tool,
70
+ ai_message_prompts_attributes: message_prompts.map(&:attributes_for_api)
71
+ }.merge(message_attributes_for_api).compact
72
+ end
73
+
74
+ # Helper methods for role checking
75
+ def user?
76
+ request.present? && response.blank?
77
+ end
78
+
79
+ def assistant?
80
+ response.present?
81
+ end
82
+
83
+ def prompt_inputs
84
+ message_prompts.flat_map(&:message_inputs)
85
+ end
86
+
87
+ private
88
+
89
+ def base_attributes
90
+ {
91
+ 'id' => id,
92
+ 'conversation_id' => conversation_id,
93
+ 'metadata' => metadata,
94
+ 'created_at' => created_at,
95
+ 'updated_at' => updated_at
96
+ }.merge(message_base_attributes)
97
+ end
98
+
99
+ def extract_nested_attributes!(attributes, key)
100
+ nested = attributes.delete(key)
101
+ nested ||= attributes.delete(key.to_s)
102
+ nested
103
+ end
104
+ end
105
+
106
+ # Alias for compatibility with Zeitwerk
107
+ AIMessage = Message
108
+ end
@@ -1,25 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RubyConversations
4
- # Builds AiMessage objects with their prompts and inputs based on Prompt templates.
4
+ # Builds Message objects with their prompts and inputs based on Prompt templates.
5
5
  class MessageBuilder
6
6
  def initialize(conversation)
7
7
  @conversation = conversation
8
8
  end
9
9
 
10
10
  def build_from_single_prompt(name, description: nil, inputs: {})
11
- prompt = Prompt.find_by!(name: name)
11
+ prompt = Prompt.find_by_name!(name)
12
12
  validate_inputs!(prompt, inputs)
13
13
 
14
14
  interpolated_message = prompt.interpolate(inputs)
15
- message = build_ai_message(interpolated_message, description)
15
+ message = build_message(interpolated_message, description)
16
16
  build_prompt_association(message, prompt, inputs)
17
17
 
18
18
  message # Return the built message
19
19
  end
20
20
 
21
21
  def build_from_multiple_prompts(prompt_inputs, description: nil)
22
- message = build_ai_message('', description)
22
+ message = build_message('', description)
23
23
 
24
24
  prompt_inputs.each do |prompt_name, inputs|
25
25
  process_single_prompt_input(message, prompt_name, inputs)
@@ -36,10 +36,7 @@ module RubyConversations
36
36
  interpolated_message = prompt.interpolate(inputs)
37
37
  message.request += "#{interpolated_message}\n\n"
38
38
 
39
- message_prompt = message.ai_message_prompts.build(
40
- prompt_version_id: prompt.latest_version_id,
41
- draft: prompt.message
42
- )
39
+ message_prompt = build_message_prompt(message, prompt)
43
40
  build_inputs_for_prompt(message_prompt, inputs)
44
41
  end
45
42
 
@@ -56,36 +53,64 @@ module RubyConversations
56
53
  end
57
54
 
58
55
  def build_prompt_association(message, prompt, inputs)
59
- message_prompt = message.ai_message_prompts.build(
60
- prompt_version_id: prompt.latest_version_id,
61
- draft: prompt.message
62
- )
56
+ message_prompt = build_message_prompt(message, prompt)
63
57
  build_inputs_for_prompt(message_prompt, inputs)
64
58
  end
65
59
 
60
+ def build_message_prompt(message, prompt)
61
+ prompt_attrs = base_prompt_attrs(prompt)
62
+ prompt_attrs[:message] = message
63
+ prompt_attrs[:name] = prompt.name
64
+ prompt_attrs[:role] = prompt.role
65
+ prompt = RubyConversations::MessagePrompt.new(prompt_attrs)
66
+ message.message_prompts << prompt
67
+ prompt
68
+ end
69
+
66
70
  def build_inputs_for_prompt(message_prompt, inputs)
67
71
  inputs.each do |input_name, value|
68
- message_prompt.ai_message_inputs.build(
69
- placeholder_name: input_name.to_s,
70
- value: value.to_s
71
- )
72
+ input_attrs = base_input_attrs(input_name, value)
73
+ input_attrs[:message_prompt] = message_prompt
74
+ input = RubyConversations::MessageInput.new(input_attrs)
75
+ message_prompt.message_inputs << input
72
76
  end
73
77
  end
74
78
 
75
- # Calculates missing inputs compared to prompt placeholders
76
79
  def calculate_missing_inputs(prompt, inputs)
77
80
  required_placeholders = prompt.valid_placeholders.split(',').map(&:strip)
78
81
  provided_keys = inputs.keys.map(&:to_s)
79
82
  required_placeholders - provided_keys
80
83
  end
81
84
 
82
- def build_ai_message(request, description)
83
- @conversation.ai_messages.build(
85
+ def build_message(request, description)
86
+ message_attrs = base_message_attrs(request, description)
87
+ message = RubyConversations::Message.new(message_attrs)
88
+ @conversation.messages << message
89
+ message
90
+ end
91
+
92
+ def base_prompt_attrs(prompt)
93
+ {
94
+ prompt_version_id: prompt.latest_version_id,
95
+ draft: prompt.message
96
+ }
97
+ end
98
+
99
+ def base_message_attrs(request, description)
100
+ {
84
101
  request: request,
85
102
  change_description: description,
103
+ model_identifier: @conversation.model_identifier,
86
104
  llm: @conversation.llm,
87
105
  tool: @conversation.tool
88
- )
106
+ }
107
+ end
108
+
109
+ def base_input_attrs(input_name, value)
110
+ {
111
+ placeholder_name: input_name.to_s,
112
+ value: value.to_s
113
+ }
89
114
  end
90
115
  end
91
116
  end