ruby_conversations 1.0.8 → 1.0.10
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.
- checksums.yaml +4 -4
- data/README.md +1 -26
- data/app/models/concerns/ruby_conversations/conversation_chat.rb +23 -11
- data/app/models/ruby_conversations/conversation.rb +1 -2
- data/lib/ruby_conversations/client.rb +46 -11
- data/lib/ruby_conversations/version.rb +1 -1
- metadata +16 -3
- data/app/models/concerns/ruby_conversations/storable.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d32de256fcc9a8676794a2da52b5e7f1d6340dee5db4614232b8ffb42dde3bae
|
4
|
+
data.tar.gz: d557589614b047b2e33cf5c8ec1e81fdaf8cafc6b605e37084aaad6bbb6cd58f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6412f0ff57642fce95b680e7024c69fa1ec1e20a7718ed93f0370d73d2d5a4d435179b0effd569c7be9720298f4b4d6bda1f6d15873e87b313ff366e6c302da4
|
7
|
+
data.tar.gz: 83f0c09530212693fc8e5ada3506a9469c1c07a770d34fc3931cd6a9401f1eca54c48a3f86ccdb66fc4c1765555dd38ae3c62ec9bfc405af8a9aac5a31fd8d81
|
data/README.md
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
# RubyConversations
|
2
2
|
|
3
|
-
A Rails engine for managing AI conversations
|
3
|
+
A Rails engine for managing AI conversations and storing them in prompt studio. Built on top of RubyLLM for AI interactions.
|
4
4
|
|
5
5
|
## Features
|
6
6
|
|
7
|
-
- **Flexible Storage**: Choose between local database storage or remote API storage
|
8
7
|
- **Built-in Prompt Management**: Version-controlled prompts with placeholder validation
|
9
8
|
- **Conversation History**: Track and manage conversation threads
|
10
9
|
- **Input/Output Storage**: Structured storage for message inputs and responses
|
@@ -32,17 +31,6 @@ Or install it yourself as:
|
|
32
31
|
gem install ruby_conversations
|
33
32
|
```
|
34
33
|
|
35
|
-
After installation, run the setup generator:
|
36
|
-
|
37
|
-
```bash
|
38
|
-
rails generate ai_conversation_engine:install
|
39
|
-
```
|
40
|
-
|
41
|
-
This will:
|
42
|
-
- Create necessary database migrations
|
43
|
-
- Generate an initializer file
|
44
|
-
- Set up default configurations
|
45
|
-
|
46
34
|
## Configuration
|
47
35
|
|
48
36
|
Configure the engine in `config/initializers/ai_conversation_engine.rb`:
|
@@ -83,19 +71,6 @@ conversation = project.conversations.create!
|
|
83
71
|
conversation.ask("analyze_project", inputs: { name: project.name })
|
84
72
|
```
|
85
73
|
|
86
|
-
### Remote Storage Mode
|
87
|
-
|
88
|
-
```ruby
|
89
|
-
# Configure for remote storage
|
90
|
-
ConversationEngine.configure do |config|
|
91
|
-
config.api_url = "https://ai-conversation-api.example.com"
|
92
|
-
config.jwt_secret = ENV['JWT_SECRET']
|
93
|
-
end
|
94
|
-
|
95
|
-
# Usage remains the same
|
96
|
-
conversation = AiConversation.create!
|
97
|
-
conversation.ask("explain_code", inputs: { code: "def hello; end" })
|
98
|
-
```
|
99
74
|
|
100
75
|
### Real-time Updates
|
101
76
|
|
@@ -6,17 +6,9 @@ module RubyConversations
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
def execute(system_message: nil)
|
9
|
-
|
10
|
-
|
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
|
-
}
|
9
|
+
validate_conversation_state
|
10
|
+
response = generate_chat_response(system_message)
|
11
|
+
store_and_update_conversation(response)
|
20
12
|
end
|
21
13
|
|
22
14
|
def llm
|
@@ -30,6 +22,26 @@ module RubyConversations
|
|
30
22
|
|
31
23
|
private
|
32
24
|
|
25
|
+
def validate_conversation_state
|
26
|
+
message = messages.last
|
27
|
+
raise ArgumentError, 'Conversation must have at least one message to execute' unless message
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_chat_response(system_message)
|
31
|
+
chat = setup_llm_chat(system_message: system_message)
|
32
|
+
chat.ask(messages.last.request)
|
33
|
+
end
|
34
|
+
|
35
|
+
def store_and_update_conversation(response)
|
36
|
+
update_last_message_response(messages.last, response)
|
37
|
+
RubyConversations.client.store_conversation_or_message(self, messages.last)
|
38
|
+
|
39
|
+
{
|
40
|
+
response: response,
|
41
|
+
conversation: self
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
33
45
|
def setup_llm_chat(system_message: nil)
|
34
46
|
configure_llm_credentials
|
35
47
|
build_chat(system_message)
|
@@ -6,7 +6,7 @@ require_relative '../concerns/ruby_conversations/conversation_messages'
|
|
6
6
|
require_relative '../concerns/ruby_conversations/llm_credentials'
|
7
7
|
require_relative '../concerns/ruby_conversations/message_validation'
|
8
8
|
require_relative '../concerns/ruby_conversations/message_processing'
|
9
|
-
|
9
|
+
|
10
10
|
module RubyConversations
|
11
11
|
# Represents a conversation thread, managing messages and interactions with the LLM.
|
12
12
|
class Conversation
|
@@ -16,7 +16,6 @@ module RubyConversations
|
|
16
16
|
include LlmCredentials
|
17
17
|
include MessageValidation
|
18
18
|
include MessageProcessing
|
19
|
-
include Storable
|
20
19
|
|
21
20
|
# Define attributes needed for API interaction & local state
|
22
21
|
attr_accessor :id, :conversationable_type, :conversationable_id, :conversationable,
|
@@ -2,26 +2,67 @@
|
|
2
2
|
|
3
3
|
require 'faraday'
|
4
4
|
require 'jwt'
|
5
|
+
require 'logger'
|
5
6
|
|
6
7
|
module RubyConversations
|
7
8
|
# HTTP client for interacting with the conversations API
|
8
9
|
class Client
|
10
|
+
attr_reader :client
|
11
|
+
|
9
12
|
PROMPT_ATTRIBUTES = %w[
|
10
13
|
id name message role temperature valid_placeholders created_at updated_at latest_version_id
|
11
14
|
].freeze
|
12
15
|
|
16
|
+
# Initialize a new API client
|
17
|
+
# @param url [String] The base URL for the API
|
18
|
+
# @param jwt_secret [String, #call] The JWT secret or a callable that returns a JWT token
|
13
19
|
def initialize(url:, jwt_secret:)
|
14
20
|
@url = url
|
15
21
|
@jwt_secret = jwt_secret
|
16
22
|
@jwt_token = nil
|
17
23
|
@jwt_expiration = nil
|
24
|
+
@logger = Logger.new($stdout)
|
25
|
+
@client = build_client
|
18
26
|
end
|
19
27
|
|
28
|
+
# Store a conversation or add a message to an existing conversation
|
29
|
+
# @param conversation [Conversation] The conversation to store
|
30
|
+
# @param message [Message] The message to store
|
31
|
+
# @return [Hash] The API response data
|
32
|
+
def store_conversation_or_message(conversation, message)
|
33
|
+
if conversation.id.present?
|
34
|
+
store_message(conversation, message)
|
35
|
+
else
|
36
|
+
store_conversation(conversation)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Store a new conversation
|
41
|
+
# @param conversation [Conversation] The conversation to store
|
42
|
+
# @return [Hash] The API response data
|
43
|
+
# @raise [Error] If the API response is missing a conversation ID
|
20
44
|
def store_conversation(conversation)
|
21
45
|
response = client.post('api/ai_conversations', conversation.conversation_attributes_for_storage)
|
46
|
+
data = handle_response(response)
|
47
|
+
raise RubyConversations::Error, 'API response missing conversation ID' unless data['id'].present?
|
48
|
+
|
49
|
+
conversation.id = data['id']
|
50
|
+
data
|
51
|
+
end
|
52
|
+
|
53
|
+
# Store a message in an existing conversation
|
54
|
+
# @param conversation [Conversation] The conversation to add the message to
|
55
|
+
# @param message [Message] The message to store
|
56
|
+
# @return [Hash] The API response data
|
57
|
+
def store_message(conversation, message)
|
58
|
+
response = client.post("api/ai_conversations/#{conversation.id}/ai_messages",
|
59
|
+
{ ai_message: message.attributes_for_api })
|
22
60
|
handle_response(response)
|
23
61
|
end
|
24
62
|
|
63
|
+
# Fetch a prompt by name
|
64
|
+
# @param name [String] The name of the prompt to fetch
|
65
|
+
# @return [Hash] The prompt attributes
|
25
66
|
def fetch_prompt(name)
|
26
67
|
response = client.get("api/prompts/#{name}")
|
27
68
|
data = handle_response(response)
|
@@ -36,10 +77,6 @@ module RubyConversations
|
|
36
77
|
end
|
37
78
|
end
|
38
79
|
|
39
|
-
def client
|
40
|
-
@client ||= build_client
|
41
|
-
end
|
42
|
-
|
43
80
|
def build_client
|
44
81
|
Faraday.new(url: @url) do |faraday|
|
45
82
|
faraday.request :json
|
@@ -55,7 +92,7 @@ module RubyConversations
|
|
55
92
|
end
|
56
93
|
|
57
94
|
def token_expired?
|
58
|
-
@jwt_token
|
95
|
+
[@jwt_token, @jwt_expiration].any?(&:nil?) || Time.now.to_i >= @jwt_expiration
|
59
96
|
end
|
60
97
|
|
61
98
|
def refresh_jwt
|
@@ -79,12 +116,10 @@ module RubyConversations
|
|
79
116
|
end
|
80
117
|
|
81
118
|
def handle_response(response)
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
raise Error, "API request failed: #{response.body}"
|
87
|
-
end
|
119
|
+
return response.body if response.success?
|
120
|
+
|
121
|
+
@logger.error("API request failed: #{response.body.inspect}")
|
122
|
+
raise RubyConversations::Error, "API request failed: #{response.body}"
|
88
123
|
end
|
89
124
|
end
|
90
125
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_conversations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Shippy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -192,6 +192,20 @@ dependencies:
|
|
192
192
|
- - ">="
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: rubocop-factory_bot
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
195
209
|
- !ruby/object:Gem::Dependency
|
196
210
|
name: rubocop-rails
|
197
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -249,7 +263,6 @@ files:
|
|
249
263
|
- app/models/concerns/ruby_conversations/message_attributes.rb
|
250
264
|
- app/models/concerns/ruby_conversations/message_processing.rb
|
251
265
|
- app/models/concerns/ruby_conversations/message_validation.rb
|
252
|
-
- app/models/concerns/ruby_conversations/storable.rb
|
253
266
|
- app/models/ruby_conversations/conversation.rb
|
254
267
|
- app/models/ruby_conversations/message.rb
|
255
268
|
- app/models/ruby_conversations/message_builder.rb
|
@@ -1,13 +0,0 @@
|
|
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
|