lex-llm 0.1.2 → 0.1.3
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/.gitignore +1 -0
- data/CHANGELOG.md +7 -1
- data/Gemfile +1 -19
- data/README.md +22 -25
- data/lex-llm.gemspec +2 -2
- data/lib/legion/extensions/llm/agent.rb +366 -0
- data/lib/legion/extensions/llm/aliases.rb +42 -0
- data/lib/legion/extensions/llm/attachment.rb +229 -0
- data/lib/legion/extensions/llm/chat.rb +355 -0
- data/lib/legion/extensions/llm/chunk.rb +10 -0
- data/lib/legion/extensions/llm/configuration.rb +82 -0
- data/lib/legion/extensions/llm/connection.rb +134 -0
- data/lib/legion/extensions/llm/content.rb +81 -0
- data/lib/legion/extensions/llm/context.rb +33 -0
- data/lib/legion/extensions/llm/embedding.rb +33 -0
- data/lib/legion/extensions/llm/error.rb +116 -0
- data/lib/legion/extensions/llm/image.rb +109 -0
- data/lib/legion/extensions/llm/message.rb +111 -0
- data/lib/legion/extensions/llm/mime_type.rb +75 -0
- data/lib/legion/extensions/llm/model/info.rb +117 -0
- data/lib/legion/extensions/llm/model/modalities.rb +26 -0
- data/lib/legion/extensions/llm/model/pricing.rb +52 -0
- data/lib/legion/extensions/llm/model/pricing_category.rb +50 -0
- data/lib/legion/extensions/llm/model/pricing_tier.rb +37 -0
- data/lib/legion/extensions/llm/model.rb +11 -0
- data/lib/legion/extensions/llm/models.rb +514 -0
- data/lib/{lex_llm → legion/extensions/llm}/models_schema.json +1 -1
- data/lib/legion/extensions/llm/moderation.rb +60 -0
- data/lib/legion/extensions/llm/provider/open_ai_compatible.rb +240 -0
- data/lib/legion/extensions/llm/provider.rb +282 -0
- data/lib/legion/extensions/llm/routing/lane_key.rb +57 -0
- data/lib/legion/extensions/llm/routing/model_offering.rb +173 -0
- data/lib/legion/extensions/llm/routing.rb +11 -0
- data/lib/legion/extensions/llm/stream_accumulator.rb +209 -0
- data/lib/legion/extensions/llm/streaming.rb +181 -0
- data/lib/legion/extensions/llm/thinking.rb +53 -0
- data/lib/legion/extensions/llm/tokens.rb +51 -0
- data/lib/legion/extensions/llm/tool.rb +258 -0
- data/lib/legion/extensions/llm/tool_call.rb +29 -0
- data/lib/legion/extensions/llm/transcription.rb +39 -0
- data/lib/legion/extensions/llm/utils.rb +95 -0
- data/lib/legion/extensions/llm/version.rb +9 -0
- data/lib/legion/extensions/llm.rb +85 -6
- metadata +40 -122
- data/lib/generators/lex_llm/agent/agent_generator.rb +0 -36
- data/lib/generators/lex_llm/agent/templates/agent.rb.tt +0 -6
- data/lib/generators/lex_llm/agent/templates/instructions.txt.erb.tt +0 -0
- data/lib/generators/lex_llm/chat_ui/chat_ui_generator.rb +0 -256
- data/lib/generators/lex_llm/chat_ui/templates/controllers/chats_controller.rb.tt +0 -38
- data/lib/generators/lex_llm/chat_ui/templates/controllers/messages_controller.rb.tt +0 -21
- data/lib/generators/lex_llm/chat_ui/templates/controllers/models_controller.rb.tt +0 -14
- data/lib/generators/lex_llm/chat_ui/templates/helpers/messages_helper.rb.tt +0 -25
- data/lib/generators/lex_llm/chat_ui/templates/jobs/chat_response_job.rb.tt +0 -12
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/chats/_chat.html.erb.tt +0 -16
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/chats/_form.html.erb.tt +0 -31
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/chats/index.html.erb.tt +0 -31
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/chats/new.html.erb.tt +0 -9
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/chats/show.html.erb.tt +0 -27
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_assistant.html.erb.tt +0 -14
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_content.html.erb.tt +0 -1
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_error.html.erb.tt +0 -13
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_form.html.erb.tt +0 -23
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_system.html.erb.tt +0 -10
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_tool.html.erb.tt +0 -2
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_tool_calls.html.erb.tt +0 -4
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/_user.html.erb.tt +0 -14
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/tool_calls/_default.html.erb.tt +0 -13
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/messages/tool_results/_default.html.erb.tt +0 -21
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/models/_model.html.erb.tt +0 -17
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/models/index.html.erb.tt +0 -40
- data/lib/generators/lex_llm/chat_ui/templates/tailwind/views/models/show.html.erb.tt +0 -27
- data/lib/generators/lex_llm/chat_ui/templates/views/chats/_chat.html.erb.tt +0 -16
- data/lib/generators/lex_llm/chat_ui/templates/views/chats/_form.html.erb.tt +0 -29
- data/lib/generators/lex_llm/chat_ui/templates/views/chats/index.html.erb.tt +0 -28
- data/lib/generators/lex_llm/chat_ui/templates/views/chats/new.html.erb.tt +0 -11
- data/lib/generators/lex_llm/chat_ui/templates/views/chats/show.html.erb.tt +0 -25
- data/lib/generators/lex_llm/chat_ui/templates/views/messages/_assistant.html.erb.tt +0 -9
- data/lib/generators/lex_llm/chat_ui/templates/views/messages/_content.html.erb.tt +0 -1
- data/lib/generators/lex_llm/chat_ui/templates/views/messages/_error.html.erb.tt +0 -8
- data/lib/generators/lex_llm/chat_ui/templates/views/messages/_form.html.erb.tt +0 -21
- data/lib/generators/lex_llm/chat_ui/templates/views/messages/_system.html.erb.tt +0 -6
- data/lib/generators/lex_llm/chat_ui/templates/views/messages/_tool.html.erb.tt +0 -2
- data/lib/generators/lex_llm/chat_ui/templates/views/messages/_tool_calls.html.erb.tt +0 -4
- data/lib/generators/lex_llm/chat_ui/templates/views/messages/_user.html.erb.tt +0 -9
- data/lib/generators/lex_llm/chat_ui/templates/views/messages/create.turbo_stream.erb.tt +0 -7
- data/lib/generators/lex_llm/chat_ui/templates/views/messages/tool_calls/_default.html.erb.tt +0 -8
- data/lib/generators/lex_llm/chat_ui/templates/views/messages/tool_results/_default.html.erb.tt +0 -16
- data/lib/generators/lex_llm/chat_ui/templates/views/models/_model.html.erb.tt +0 -15
- data/lib/generators/lex_llm/chat_ui/templates/views/models/index.html.erb.tt +0 -38
- data/lib/generators/lex_llm/chat_ui/templates/views/models/show.html.erb.tt +0 -17
- data/lib/generators/lex_llm/generator_helpers.rb +0 -214
- data/lib/generators/lex_llm/install/install_generator.rb +0 -109
- data/lib/generators/lex_llm/install/templates/add_references_to_chats_tool_calls_and_messages_migration.rb.tt +0 -9
- data/lib/generators/lex_llm/install/templates/chat_model.rb.tt +0 -3
- data/lib/generators/lex_llm/install/templates/create_chats_migration.rb.tt +0 -7
- data/lib/generators/lex_llm/install/templates/create_messages_migration.rb.tt +0 -19
- data/lib/generators/lex_llm/install/templates/create_models_migration.rb.tt +0 -39
- data/lib/generators/lex_llm/install/templates/create_tool_calls_migration.rb.tt +0 -21
- data/lib/generators/lex_llm/install/templates/initializer.rb.tt +0 -20
- data/lib/generators/lex_llm/install/templates/message_model.rb.tt +0 -4
- data/lib/generators/lex_llm/install/templates/model_model.rb.tt +0 -3
- data/lib/generators/lex_llm/install/templates/tool_call_model.rb.tt +0 -3
- data/lib/generators/lex_llm/schema/schema_generator.rb +0 -26
- data/lib/generators/lex_llm/schema/templates/schema.rb.tt +0 -2
- data/lib/generators/lex_llm/tool/templates/tool.rb.tt +0 -9
- data/lib/generators/lex_llm/tool/templates/tool_call.html.erb.tt +0 -13
- data/lib/generators/lex_llm/tool/templates/tool_result.html.erb.tt +0 -13
- data/lib/generators/lex_llm/tool/tool_generator.rb +0 -96
- data/lib/generators/lex_llm/upgrade_to_v1_10/templates/add_v1_10_message_columns.rb.tt +0 -19
- data/lib/generators/lex_llm/upgrade_to_v1_10/upgrade_to_v1_10_generator.rb +0 -50
- data/lib/generators/lex_llm/upgrade_to_v1_14/templates/add_v1_14_tool_call_columns.rb.tt +0 -7
- data/lib/generators/lex_llm/upgrade_to_v1_14/upgrade_to_v1_14_generator.rb +0 -49
- data/lib/generators/lex_llm/upgrade_to_v1_7/templates/migration.rb.tt +0 -145
- data/lib/generators/lex_llm/upgrade_to_v1_7/upgrade_to_v1_7_generator.rb +0 -122
- data/lib/generators/lex_llm/upgrade_to_v1_9/templates/add_v1_9_message_columns.rb.tt +0 -15
- data/lib/generators/lex_llm/upgrade_to_v1_9/upgrade_to_v1_9_generator.rb +0 -49
- data/lib/lex_llm/active_record/acts_as.rb +0 -180
- data/lib/lex_llm/active_record/acts_as_legacy.rb +0 -503
- data/lib/lex_llm/active_record/chat_methods.rb +0 -468
- data/lib/lex_llm/active_record/message_methods.rb +0 -131
- data/lib/lex_llm/active_record/model_methods.rb +0 -76
- data/lib/lex_llm/active_record/payload_helpers.rb +0 -26
- data/lib/lex_llm/active_record/tool_call_methods.rb +0 -15
- data/lib/lex_llm/agent.rb +0 -365
- data/lib/lex_llm/aliases.rb +0 -38
- data/lib/lex_llm/attachment.rb +0 -223
- data/lib/lex_llm/chat.rb +0 -351
- data/lib/lex_llm/chunk.rb +0 -6
- data/lib/lex_llm/configuration.rb +0 -81
- data/lib/lex_llm/connection.rb +0 -130
- data/lib/lex_llm/content.rb +0 -77
- data/lib/lex_llm/context.rb +0 -29
- data/lib/lex_llm/embedding.rb +0 -29
- data/lib/lex_llm/error.rb +0 -112
- data/lib/lex_llm/image.rb +0 -105
- data/lib/lex_llm/message.rb +0 -107
- data/lib/lex_llm/mime_type.rb +0 -71
- data/lib/lex_llm/model/info.rb +0 -113
- data/lib/lex_llm/model/modalities.rb +0 -22
- data/lib/lex_llm/model/pricing.rb +0 -48
- data/lib/lex_llm/model/pricing_category.rb +0 -46
- data/lib/lex_llm/model/pricing_tier.rb +0 -33
- data/lib/lex_llm/model.rb +0 -7
- data/lib/lex_llm/models.rb +0 -506
- data/lib/lex_llm/moderation.rb +0 -56
- data/lib/lex_llm/provider/open_ai_compatible.rb +0 -219
- data/lib/lex_llm/provider.rb +0 -278
- data/lib/lex_llm/railtie.rb +0 -35
- data/lib/lex_llm/routing/lane_key.rb +0 -51
- data/lib/lex_llm/routing/model_offering.rb +0 -169
- data/lib/lex_llm/routing.rb +0 -7
- data/lib/lex_llm/stream_accumulator.rb +0 -203
- data/lib/lex_llm/streaming.rb +0 -175
- data/lib/lex_llm/thinking.rb +0 -49
- data/lib/lex_llm/tokens.rb +0 -47
- data/lib/lex_llm/tool.rb +0 -254
- data/lib/lex_llm/tool_call.rb +0 -25
- data/lib/lex_llm/transcription.rb +0 -35
- data/lib/lex_llm/utils.rb +0 -91
- data/lib/lex_llm/version.rb +0 -5
- data/lib/lex_llm.rb +0 -96
- data/lib/tasks/lex_llm.rake +0 -23
- /data/lib/{lex_llm → legion/extensions/llm}/aliases.json +0 -0
- /data/lib/{lex_llm → legion/extensions/llm}/models.json +0 -0
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module LexLLM
|
|
4
|
-
module Generators
|
|
5
|
-
# Shared helpers for LexLLM generators
|
|
6
|
-
module GeneratorHelpers
|
|
7
|
-
def parse_model_mappings
|
|
8
|
-
@model_names = {
|
|
9
|
-
chat: 'Chat',
|
|
10
|
-
message: 'Message',
|
|
11
|
-
tool_call: 'ToolCall',
|
|
12
|
-
model: 'Model'
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
model_mappings.each do |mapping|
|
|
16
|
-
if mapping.include?(':')
|
|
17
|
-
key, value = mapping.split(':', 2)
|
|
18
|
-
@model_names[key.to_sym] = value.classify
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
@model_names
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
%i[chat message tool_call model].each do |type|
|
|
26
|
-
define_method("#{type}_model_name") do
|
|
27
|
-
@model_names ||= parse_model_mappings
|
|
28
|
-
@model_names[type]
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
define_method("#{type}_table_name") do
|
|
32
|
-
table_name_for(send("#{type}_model_name"))
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
define_method("#{type}_variable_name") do
|
|
36
|
-
variable_name_for(send("#{type}_model_name"))
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
define_method("#{type}_controller_class_name") do
|
|
40
|
-
controller_class_name_for(send("#{type}_model_name"))
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
define_method("#{type}_job_class_name") do
|
|
44
|
-
"#{variable_name_for(send("#{type}_model_name")).camelize}ResponseJob"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
define_method("#{type}_partial") do
|
|
48
|
-
partial_path_for(send("#{type}_model_name"))
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def acts_as_chat_declaration
|
|
53
|
-
params = []
|
|
54
|
-
|
|
55
|
-
add_association_params(params, :messages, message_table_name, message_model_name,
|
|
56
|
-
owner_table: chat_table_name, owner_model_name: chat_model_name, plural: true)
|
|
57
|
-
add_association_params(params, :model, model_table_name, model_model_name,
|
|
58
|
-
owner_table: chat_table_name, owner_model_name: chat_model_name)
|
|
59
|
-
|
|
60
|
-
"acts_as_chat#{" #{params.join(', ')}" if params.any?}"
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def acts_as_message_declaration
|
|
64
|
-
params = []
|
|
65
|
-
|
|
66
|
-
add_association_params(params, :chat, chat_table_name, chat_model_name,
|
|
67
|
-
owner_table: message_table_name, owner_model_name: message_model_name)
|
|
68
|
-
add_association_params(params, :tool_calls, tool_call_table_name, tool_call_model_name,
|
|
69
|
-
owner_table: message_table_name, owner_model_name: message_model_name, plural: true)
|
|
70
|
-
add_association_params(params, :model, model_table_name, model_model_name,
|
|
71
|
-
owner_table: message_table_name, owner_model_name: message_model_name)
|
|
72
|
-
|
|
73
|
-
"acts_as_message#{" #{params.join(', ')}" if params.any?}"
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def acts_as_model_declaration
|
|
77
|
-
params = []
|
|
78
|
-
|
|
79
|
-
add_association_params(params, :chats, chat_table_name, chat_model_name,
|
|
80
|
-
owner_table: model_table_name, owner_model_name: model_model_name, plural: true)
|
|
81
|
-
|
|
82
|
-
"acts_as_model#{" #{params.join(', ')}" if params.any?}"
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def acts_as_tool_call_declaration
|
|
86
|
-
params = []
|
|
87
|
-
|
|
88
|
-
add_association_params(params, :message, message_table_name, message_model_name,
|
|
89
|
-
owner_table: tool_call_table_name, owner_model_name: tool_call_model_name)
|
|
90
|
-
|
|
91
|
-
"acts_as_tool_call#{" #{params.join(', ')}" if params.any?}"
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def create_namespace_modules
|
|
95
|
-
namespaces = []
|
|
96
|
-
|
|
97
|
-
[chat_model_name, message_model_name, tool_call_model_name, model_model_name].each do |model_name|
|
|
98
|
-
if model_name.include?('::')
|
|
99
|
-
namespace = model_name.split('::').first
|
|
100
|
-
namespaces << namespace unless namespaces.include?(namespace)
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
namespaces.each do |namespace|
|
|
105
|
-
module_path = "app/models/#{namespace.underscore}.rb"
|
|
106
|
-
next if File.exist?(Rails.root.join(module_path))
|
|
107
|
-
|
|
108
|
-
create_file module_path do
|
|
109
|
-
<<~RUBY
|
|
110
|
-
module #{namespace}
|
|
111
|
-
def self.table_name_prefix
|
|
112
|
-
"#{namespace.underscore}_"
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
RUBY
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def migration_version
|
|
121
|
-
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def create_migration_class_name(table_name)
|
|
125
|
-
"create_#{table_name}".camelize
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def postgresql?
|
|
129
|
-
::ActiveRecord::Base.connection.adapter_name.downcase.include?('postgresql')
|
|
130
|
-
rescue StandardError
|
|
131
|
-
false
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def mysql?
|
|
135
|
-
::ActiveRecord::Base.connection.adapter_name.downcase.include?('mysql')
|
|
136
|
-
rescue StandardError
|
|
137
|
-
false
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def table_exists?(table_name)
|
|
141
|
-
::ActiveRecord::Base.connection.table_exists?(table_name)
|
|
142
|
-
rescue StandardError
|
|
143
|
-
false
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
private
|
|
147
|
-
|
|
148
|
-
# rubocop:disable Metrics/ParameterLists
|
|
149
|
-
def add_association_params(params, default_assoc, table_name, model_name,
|
|
150
|
-
owner_table:, owner_model_name:, plural: false)
|
|
151
|
-
assoc = plural ? table_name.to_sym : table_name.singularize.to_sym
|
|
152
|
-
collection_association = collection_association?(default_assoc, plural)
|
|
153
|
-
foreign_key = inferred_foreign_key(table_name, owner_table, collection_association)
|
|
154
|
-
default_foreign_key = default_inferred_foreign_key(assoc, owner_model_name, collection_association)
|
|
155
|
-
|
|
156
|
-
params << "#{default_assoc}: :#{assoc}" if assoc != default_assoc
|
|
157
|
-
params << "#{default_assoc.to_s.singularize}_class: '#{model_name}'" if model_name != assoc.to_s.classify
|
|
158
|
-
params << "#{default_assoc}_foreign_key: :#{foreign_key}" if foreign_key != default_foreign_key
|
|
159
|
-
end
|
|
160
|
-
# rubocop:enable Metrics/ParameterLists
|
|
161
|
-
|
|
162
|
-
def collection_association?(default_assoc, plural)
|
|
163
|
-
plural || default_assoc.to_s.pluralize == default_assoc.to_s
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def inferred_foreign_key(table_name, owner_table, collection_association)
|
|
167
|
-
return "#{table_name.singularize}_id" unless collection_association
|
|
168
|
-
|
|
169
|
-
"#{owner_table.singularize}_id"
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
# Rails default inference:
|
|
173
|
-
# belongs_to :assoc -> assoc_id
|
|
174
|
-
# has_many/has_one -> owner demodulized model name + _id
|
|
175
|
-
def default_inferred_foreign_key(association_name, owner_model_name, collection_association)
|
|
176
|
-
return "#{association_name}_id" unless collection_association
|
|
177
|
-
|
|
178
|
-
"#{owner_model_name.demodulize.underscore}_id"
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
# Convert namespaced model names to proper table names
|
|
182
|
-
# e.g., "Assistant::Chat" -> "assistant_chats" (not "assistant/chats")
|
|
183
|
-
def table_name_for(model_name)
|
|
184
|
-
model_name.underscore.pluralize.tr('/', '_')
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
# Convert model name to instance variable name
|
|
188
|
-
# e.g., "LLM::Chat" -> "llm_chat" (not "llm/chat")
|
|
189
|
-
def variable_name_for(model_name)
|
|
190
|
-
model_name.underscore.tr('/', '_')
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
# Convert model name to controller class name
|
|
194
|
-
# For namespaced models, use Rails convention: "Llm::Chat" -> "Llm::ChatsController"
|
|
195
|
-
# For regular models: "Chat" -> "ChatsController"
|
|
196
|
-
def controller_class_name_for(model_name)
|
|
197
|
-
if model_name.include?('::')
|
|
198
|
-
parts = model_name.split('::')
|
|
199
|
-
namespace = parts[0..-2].join('::')
|
|
200
|
-
resource = parts.last.pluralize
|
|
201
|
-
"#{namespace}::#{resource}Controller"
|
|
202
|
-
else
|
|
203
|
-
"#{model_name.pluralize}Controller"
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
# Convert model name to partial path
|
|
208
|
-
# e.g., "LLM::Message" -> "llm/message" (not "llm_message")
|
|
209
|
-
def partial_path_for(model_name)
|
|
210
|
-
"#{model_name.underscore.pluralize}/#{model_name.demodulize.underscore}"
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
end
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rails/generators'
|
|
4
|
-
require 'rails/generators/active_record'
|
|
5
|
-
require_relative '../generator_helpers'
|
|
6
|
-
|
|
7
|
-
module LexLLM
|
|
8
|
-
module Generators
|
|
9
|
-
# Generator for LexLLM Rails models and migrations
|
|
10
|
-
class InstallGenerator < Rails::Generators::Base
|
|
11
|
-
include Rails::Generators::Migration
|
|
12
|
-
include LexLLM::Generators::GeneratorHelpers
|
|
13
|
-
|
|
14
|
-
namespace 'lex_llm:install'
|
|
15
|
-
|
|
16
|
-
source_root File.expand_path('templates', __dir__)
|
|
17
|
-
|
|
18
|
-
argument :model_mappings, type: :array, default: [], banner: 'chat:ChatName message:MessageName ...'
|
|
19
|
-
|
|
20
|
-
class_option :skip_active_storage, type: :boolean, default: false,
|
|
21
|
-
desc: 'Skip ActiveStorage installation and attachment setup'
|
|
22
|
-
|
|
23
|
-
desc 'Creates models and migrations for LexLLM Rails integration\n' \
|
|
24
|
-
'Usage: bin/rails g lex_llm:install [chat:ChatName] [message:MessageName] ...'
|
|
25
|
-
|
|
26
|
-
def self.next_migration_number(dirname)
|
|
27
|
-
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def create_migration_files
|
|
31
|
-
migration_template 'create_chats_migration.rb.tt',
|
|
32
|
-
"db/migrate/create_#{chat_table_name}.rb"
|
|
33
|
-
migration_template 'create_messages_migration.rb.tt',
|
|
34
|
-
"db/migrate/create_#{message_table_name}.rb"
|
|
35
|
-
migration_template 'create_tool_calls_migration.rb.tt',
|
|
36
|
-
"db/migrate/create_#{tool_call_table_name}.rb"
|
|
37
|
-
migration_template 'create_models_migration.rb.tt',
|
|
38
|
-
"db/migrate/create_#{model_table_name}.rb"
|
|
39
|
-
migration_template 'add_references_to_chats_tool_calls_and_messages_migration.rb.tt',
|
|
40
|
-
'db/migrate/add_references_to_' \
|
|
41
|
-
"#{chat_table_name}_#{tool_call_table_name}_and_#{message_table_name}.rb"
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def create_model_files
|
|
45
|
-
create_namespace_modules
|
|
46
|
-
|
|
47
|
-
template 'chat_model.rb.tt', "app/models/#{chat_model_name.underscore}.rb"
|
|
48
|
-
template 'message_model.rb.tt', "app/models/#{message_model_name.underscore}.rb"
|
|
49
|
-
template 'tool_call_model.rb.tt', "app/models/#{tool_call_model_name.underscore}.rb"
|
|
50
|
-
|
|
51
|
-
template 'model_model.rb.tt', "app/models/#{model_model_name.underscore}.rb"
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def create_initializer
|
|
55
|
-
template 'initializer.rb.tt', 'config/initializers/lex_llm.rb'
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def create_convention_directories
|
|
59
|
-
%w[agents tools schemas prompts].each do |name|
|
|
60
|
-
empty_directory "app/#{name}"
|
|
61
|
-
create_file "app/#{name}/.gitkeep" unless File.exist?(Rails.root.join("app/#{name}/.gitkeep"))
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def install_active_storage
|
|
66
|
-
return if options[:skip_active_storage]
|
|
67
|
-
|
|
68
|
-
say ' Installing ActiveStorage for file attachments...', :cyan
|
|
69
|
-
rails_command 'active_storage:install'
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def show_install_info
|
|
73
|
-
say "\n ✅ LexLLM installed!", :green
|
|
74
|
-
|
|
75
|
-
say ' ✅ ActiveStorage configured for file attachments support', :green unless options[:skip_active_storage]
|
|
76
|
-
|
|
77
|
-
say "\n Next steps:", :yellow
|
|
78
|
-
say ' 1. Run: bin/rails db:migrate'
|
|
79
|
-
say ' 2. Run: bin/rails lex_llm:load_models'
|
|
80
|
-
say ' 3. Install a lex-llm-* provider gem and configure its settings'
|
|
81
|
-
|
|
82
|
-
say " 4. Start chatting: #{chat_model_name}.create!(model: 'your-provider-model').ask('Hello!')"
|
|
83
|
-
say " 5. Optional UI: #{chat_ui_generator_command}"
|
|
84
|
-
|
|
85
|
-
if options[:skip_active_storage]
|
|
86
|
-
say "\n 📎 Note: ActiveStorage was skipped", :yellow
|
|
87
|
-
say ' File attachments won\'t work without ActiveStorage.'
|
|
88
|
-
say ' To enable later:'
|
|
89
|
-
say ' 1. Run: bin/rails active_storage:install && bin/rails db:migrate'
|
|
90
|
-
say " 2. Add to your #{message_model_name} model: has_many_attached :attachments"
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
say "\n 📚 Documentation: https://github.com/LegionIO/lex-llm", :cyan
|
|
94
|
-
|
|
95
|
-
say "\n ❤️ Love LexLLM?", :magenta
|
|
96
|
-
say ' • ⭐ Star on GitHub: https://github.com/LegionIO/lex-llm'
|
|
97
|
-
say "\n"
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
private
|
|
101
|
-
|
|
102
|
-
def chat_ui_generator_command
|
|
103
|
-
mappings = model_mappings.join(' ')
|
|
104
|
-
mappings = " #{mappings}" unless mappings.empty?
|
|
105
|
-
"bin/rails generate lex_llm:chat_ui#{mappings}"
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
end
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
class AddReferencesTo<%= "#{chat_model_name.gsub('::', '').pluralize}#{tool_call_model_name.gsub('::', '').pluralize}And#{message_model_name.gsub('::', '').pluralize}" %> < ActiveRecord::Migration<%= migration_version %>
|
|
2
|
-
def change
|
|
3
|
-
add_reference :<%= chat_table_name %>, :<%= model_table_name.singularize %>, foreign_key: true
|
|
4
|
-
add_reference :<%= tool_call_table_name %>, :<%= message_table_name.singularize %>, null: false, foreign_key: true
|
|
5
|
-
add_reference :<%= message_table_name %>, :<%= chat_table_name.singularize %>, null: false, foreign_key: true
|
|
6
|
-
add_reference :<%= message_table_name %>, :<%= model_table_name.singularize %>, foreign_key: true
|
|
7
|
-
add_reference :<%= message_table_name %>, :<%= tool_call_table_name.singularize %>, foreign_key: true
|
|
8
|
-
end
|
|
9
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
class <%= create_migration_class_name(message_table_name) %> < ActiveRecord::Migration<%= migration_version %>
|
|
2
|
-
def change
|
|
3
|
-
create_table :<%= message_table_name %> do |t|
|
|
4
|
-
t.string :role, null: false
|
|
5
|
-
t.text :content
|
|
6
|
-
t.json :content_raw
|
|
7
|
-
t.text :thinking_text
|
|
8
|
-
t.text :thinking_signature
|
|
9
|
-
t.integer :thinking_tokens
|
|
10
|
-
t.integer :input_tokens
|
|
11
|
-
t.integer :output_tokens
|
|
12
|
-
t.integer :cached_tokens
|
|
13
|
-
t.integer :cache_creation_tokens
|
|
14
|
-
t.timestamps
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
add_index :<%= message_table_name %>, :role
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
class <%= create_migration_class_name(model_table_name) %> < ActiveRecord::Migration<%= migration_version %>
|
|
2
|
-
def change
|
|
3
|
-
create_table :<%= model_table_name %> do |t|
|
|
4
|
-
t.string :model_id, null: false
|
|
5
|
-
t.string :name, null: false
|
|
6
|
-
t.string :provider, null: false
|
|
7
|
-
t.string :family
|
|
8
|
-
t.datetime :model_created_at
|
|
9
|
-
t.integer :context_window
|
|
10
|
-
t.integer :max_output_tokens
|
|
11
|
-
t.date :knowledge_cutoff
|
|
12
|
-
<% if postgresql? %>
|
|
13
|
-
t.jsonb :modalities, default: {}
|
|
14
|
-
t.jsonb :capabilities, default: []
|
|
15
|
-
t.jsonb :pricing, default: {}
|
|
16
|
-
t.jsonb :metadata, default: {}
|
|
17
|
-
<% elsif mysql? %>
|
|
18
|
-
t.json :modalities
|
|
19
|
-
t.json :capabilities
|
|
20
|
-
t.json :pricing
|
|
21
|
-
t.json :metadata
|
|
22
|
-
<% else %>
|
|
23
|
-
t.json :modalities, default: {}
|
|
24
|
-
t.json :capabilities, default: []
|
|
25
|
-
t.json :pricing, default: {}
|
|
26
|
-
t.json :metadata, default: {}
|
|
27
|
-
<% end %>
|
|
28
|
-
t.timestamps
|
|
29
|
-
|
|
30
|
-
t.index [ :provider, :model_id ], unique: true
|
|
31
|
-
t.index :provider
|
|
32
|
-
t.index :family
|
|
33
|
-
<% if postgresql? -%>
|
|
34
|
-
t.index :capabilities, using: :gin
|
|
35
|
-
t.index :modalities, using: :gin
|
|
36
|
-
<% end -%>
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<%#- # Migration for creating tool_calls table with database-specific JSON handling -%>
|
|
2
|
-
class <%= create_migration_class_name(tool_call_table_name) %> < ActiveRecord::Migration<%= migration_version %>
|
|
3
|
-
def change
|
|
4
|
-
create_table :<%= tool_call_table_name %> do |t|
|
|
5
|
-
t.string :tool_call_id, null: false
|
|
6
|
-
t.string :name, null: false
|
|
7
|
-
t.text :thought_signature
|
|
8
|
-
<% if postgresql? %>
|
|
9
|
-
t.jsonb :arguments, default: {}
|
|
10
|
-
<% elsif mysql? %>
|
|
11
|
-
t.json :arguments
|
|
12
|
-
<% else %>
|
|
13
|
-
t.json :arguments, default: {}
|
|
14
|
-
<% end %>
|
|
15
|
-
t.timestamps
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
add_index :<%= tool_call_table_name %>, :tool_call_id, unique: true
|
|
19
|
-
add_index :<%= tool_call_table_name %>, :name
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
require "lex_llm"
|
|
2
|
-
require "lex_llm/active_record/acts_as"
|
|
3
|
-
|
|
4
|
-
LexLLM.configure do |config|
|
|
5
|
-
# Provider gems register their own settings.
|
|
6
|
-
# Example after installing a provider extension:
|
|
7
|
-
# config.default_model = "your-provider-model"
|
|
8
|
-
|
|
9
|
-
# Use the new association-based acts_as API (recommended)
|
|
10
|
-
config.use_new_acts_as = true
|
|
11
|
-
<% if model_model_name != 'Model' -%>
|
|
12
|
-
|
|
13
|
-
# Custom model registry class name
|
|
14
|
-
config.model_registry_class = "<%= model_model_name %>"
|
|
15
|
-
<% end -%>
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
ActiveSupport.on_load :active_record do
|
|
19
|
-
::ActiveRecord::Base.include LexLLM::ActiveRecord::ActsAs
|
|
20
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rails/generators'
|
|
4
|
-
|
|
5
|
-
module LexLLM
|
|
6
|
-
module Generators
|
|
7
|
-
# Generator for LexLLM schema classes.
|
|
8
|
-
class SchemaGenerator < Rails::Generators::NamedBase
|
|
9
|
-
source_root File.expand_path('templates', __dir__)
|
|
10
|
-
|
|
11
|
-
namespace 'lex_llm:schema'
|
|
12
|
-
|
|
13
|
-
desc 'Creates a LexLLM schema class'
|
|
14
|
-
|
|
15
|
-
def create_schema_file
|
|
16
|
-
template 'schema.rb.tt', File.join('app/schemas', class_path, "#{file_name}.rb")
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
def schema_class_name
|
|
22
|
-
class_name.end_with?('Schema') ? class_name : "#{class_name}Schema"
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<%% tool_call_error = tool_call.tool_error_message %>
|
|
2
|
-
<%% if tool_call_error.present? %>
|
|
3
|
-
<%%= render "messages/error", message: tool_calls, title: "Tool Call Error", error_message: tool_call_error %>
|
|
4
|
-
<%% else %>
|
|
5
|
-
<div id="message_<%%= tool_calls.id %>" class="message"
|
|
6
|
-
style="margin-bottom: 20px; padding: 10px; border-left: 3px solid #6b7280; background: #f9fafb;">
|
|
7
|
-
<div style="font-weight: bold; margin-bottom: 5px;"><%= tool_display_name %> Call</div>
|
|
8
|
-
<pre style="white-space: pre-wrap; margin: 0;"><%%= tool_call.name %>(<%%= tool_call.arguments.map { |k, v| "#{k}: #{v.inspect}" }.join(", ") %>)</pre>
|
|
9
|
-
<div style="font-size: 0.85em; color: #666; margin-top: 5px;">
|
|
10
|
-
<%%= tool_calls.created_at&.strftime("%I:%M %p") %>
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
<%% end %>
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<%% error_message = tool.tool_error_message %>
|
|
2
|
-
<%% if error_message.present? %>
|
|
3
|
-
<%%= render "messages/error", message: tool, title: "Tool Result Error", error_message: error_message %>
|
|
4
|
-
<%% else %>
|
|
5
|
-
<div id="message_<%%= tool.id %>" class="message"
|
|
6
|
-
style="margin-bottom: 20px; padding: 10px; border-left: 3px solid #6b7280; background: #f9fafb;">
|
|
7
|
-
<div style="font-weight: bold; margin-bottom: 5px;"><%= tool_display_name %> Result</div>
|
|
8
|
-
<pre style="white-space: pre-wrap; margin: 0;"><%%= tool.content.presence || "(no output)" %></pre>
|
|
9
|
-
<div style="font-size: 0.85em; color: #666; margin-top: 5px;">
|
|
10
|
-
<%%= tool.created_at&.strftime("%I:%M %p") %>
|
|
11
|
-
</div>
|
|
12
|
-
</div>
|
|
13
|
-
<%% end %>
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'rails/generators'
|
|
4
|
-
|
|
5
|
-
module LexLLM
|
|
6
|
-
module Generators
|
|
7
|
-
# Generator for LexLLM tool classes and related message partials.
|
|
8
|
-
class ToolGenerator < Rails::Generators::NamedBase
|
|
9
|
-
source_root File.expand_path('templates', __dir__)
|
|
10
|
-
|
|
11
|
-
namespace 'lex_llm:tool'
|
|
12
|
-
|
|
13
|
-
check_class_collision suffix: 'Tool'
|
|
14
|
-
|
|
15
|
-
desc 'Creates a LexLLM tool class and matching tool call/result view partials'
|
|
16
|
-
|
|
17
|
-
def create_tool_file
|
|
18
|
-
template 'tool.rb.tt', File.join('app/tools', class_path, "#{file_name}_tool.rb")
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def create_tool_view_partials
|
|
22
|
-
empty_directory 'app/views/messages/tool_calls'
|
|
23
|
-
empty_directory 'app/views/messages/tool_results'
|
|
24
|
-
|
|
25
|
-
create_tool_call_partial
|
|
26
|
-
create_tool_result_partial
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
def create_tool_call_partial
|
|
32
|
-
destination_path = File.join('app/views/messages/tool_calls', "_#{tool_partial_name}.html.erb")
|
|
33
|
-
default_partial_path = File.join(destination_root, 'app/views/messages/tool_calls/_default.html.erb')
|
|
34
|
-
|
|
35
|
-
if File.exist?(default_partial_path)
|
|
36
|
-
default_markup = tool_named_call_markup(File.read(default_partial_path))
|
|
37
|
-
indented_markup = indent_non_empty_lines(default_markup, 2)
|
|
38
|
-
create_file destination_path, <<~ERB
|
|
39
|
-
<% tool_call_error = tool_call.tool_error_message %>
|
|
40
|
-
<% if tool_call_error.present? %>
|
|
41
|
-
<%= render "messages/error", message: tool_calls, title: "Tool Call Error", error_message: tool_call_error %>
|
|
42
|
-
<% else %>
|
|
43
|
-
#{indented_markup}<% end %>
|
|
44
|
-
ERB
|
|
45
|
-
else
|
|
46
|
-
template 'tool_call.html.erb.tt', destination_path
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
strip_trailing_whitespace(destination_path)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def create_tool_result_partial
|
|
53
|
-
destination_path = File.join('app/views/messages/tool_results', "_#{tool_partial_name}.html.erb")
|
|
54
|
-
default_partial_path = File.join(destination_root, 'app/views/messages/tool_results/_default.html.erb')
|
|
55
|
-
|
|
56
|
-
if File.exist?(default_partial_path)
|
|
57
|
-
create_file destination_path, tool_named_result_markup(File.read(default_partial_path))
|
|
58
|
-
else
|
|
59
|
-
template 'tool_result.html.erb.tt', destination_path
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
strip_trailing_whitespace(destination_path)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def tool_named_call_markup(markup)
|
|
66
|
-
markup.sub('Tool Call', "#{tool_display_name} Call")
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def tool_named_result_markup(markup)
|
|
70
|
-
markup.sub(/\bTool\b(?!\s*Result)/, "#{tool_display_name} Result")
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def tool_display_name
|
|
74
|
-
class_name.demodulize
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def tool_partial_name
|
|
78
|
-
file_name.delete_suffix('_tool')
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def indent_non_empty_lines(markup, spaces)
|
|
82
|
-
indentation = ' ' * spaces
|
|
83
|
-
markup.lines.map { |line| line.strip.empty? ? line : "#{indentation}#{line}" }.join
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def strip_trailing_whitespace(path)
|
|
87
|
-
content = File.read(path)
|
|
88
|
-
stripped_content = content.lines.map(&:rstrip).join("\n")
|
|
89
|
-
stripped_content = "#{stripped_content}\n" unless stripped_content.end_with?("\n")
|
|
90
|
-
return if content == stripped_content
|
|
91
|
-
|
|
92
|
-
File.write(path, stripped_content)
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
class AddLexLlmV110Columns < ActiveRecord::Migration<%= migration_version %>
|
|
2
|
-
def change
|
|
3
|
-
unless column_exists?(:<%= message_table_name %>, :thinking_text)
|
|
4
|
-
add_column :<%= message_table_name %>, :thinking_text, :text
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
unless column_exists?(:<%= message_table_name %>, :thinking_signature)
|
|
8
|
-
add_column :<%= message_table_name %>, :thinking_signature, :text
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
unless column_exists?(:<%= message_table_name %>, :thinking_tokens)
|
|
12
|
-
add_column :<%= message_table_name %>, :thinking_tokens, :integer
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
unless column_exists?(:<%= tool_call_table_name %>, :thought_signature)
|
|
16
|
-
add_column :<%= tool_call_table_name %>, :thought_signature, :string
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|