llm_meta_client 0.6.1 → 1.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 931f6b078e6df954f5ab32218cb31c4c743112ed6ae037c3e027102cec3089d4
4
- data.tar.gz: 52febe0e221d964ad286ce8ad7ebb0ad595a8d80b87a4afa55af54e82e82873d
3
+ metadata.gz: cd284d6a68a9bbad852fbcb19054ce2aeda512f0ffe17c2ac7029eb30907a7e4
4
+ data.tar.gz: 5fe0cd2beef4c9bbc7fb75ee49099558a07626e0affa6b9ba9b065eca940dc67
5
5
  SHA512:
6
- metadata.gz: 6216c95f340ae0ef1b3e9ee54bd8a0906c2001d50ac45139df4f8da584c856962b462182e7fcc20e94c8785e6923f50f04882bf534da300bc8946fef5308cfa1
7
- data.tar.gz: 2223f1a7381b9bdb484a1ec8fade18c5b83789b007b6f078680887a81db4c6a5854572310a108864eba89656cff980359b9602e14a9cdae752d8d0ad98d7a48e
6
+ metadata.gz: 53f9fcccc2ffee1c08ba3df22bf95e08bc857d8da0cd748f520f26a7144b03dded4a3ceb4ca67b3108fda12d79f521ed88e5ce0b30cb8b232ac5185941d9832f
7
+ data.tar.gz: e5529bc832a453030d348cd8d01100bb664896d03cee385f83ee43b945c316b0c1d03d4227c65b23d6b360943e91e1c9727e7d52d1311b107eacf2bf7f58799f
data/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.0.0] - 2026-03-25
9
+
10
+ ### Changed
11
+
12
+ - Replace generation settings UI from individual sliders to JSON textarea input
13
+ - Improve prompt execution branching logic to use `execution_id` instead of message UUID
14
+ - Use `find_by!` for proper 404 handling in controllers
15
+ - Use URL-based chat lookup in `chats#update` instead of session-based lookup
16
+ - Keep existing chat when switching model or LLM (update instead of creating new chat)
17
+ - Upgrade `prompt_navigator` dependency to `~> 1.0`
18
+ - Upgrade `chat_manager` dependency to `~> 1.0`
19
+
20
+ ### Fixed
21
+
22
+ - Fix Turbo Stream history sidebar element ID mismatch (`history-content` → `history-sidebar`)
23
+ - Fix `next_ann` for proper history card rendering
24
+ - Wrap inline JavaScript in IIFE to prevent variable conflicts across Turbo Stream updates
25
+ - Fix scroll event listener duplication across Turbo navigations
26
+ - Validate generation settings JSON input before sending to LLM
27
+
8
28
  ## [0.6.1] - 2026-03-19
9
29
 
10
30
  ### Fixed
@@ -31,60 +31,39 @@
31
31
  padding: 12px 16px;
32
32
  }
33
33
 
34
- .generation-setting-item {
35
- margin-bottom: 14px;
36
-
37
- &:last-child {
38
- margin-bottom: 0;
39
- }
34
+ .generation-settings-label {
35
+ display: block;
36
+ font-size: 13px;
37
+ font-weight: 600;
38
+ color: #374151;
39
+ margin-bottom: 6px;
40
+ }
40
41
 
41
- label {
42
- display: flex;
43
- align-items: center;
44
- gap: 8px;
45
- font-size: 13px;
46
- font-weight: 600;
47
- color: #374151;
48
- margin-bottom: 4px;
49
- }
42
+ .generation-settings-json-input {
43
+ width: 100%;
44
+ padding: 8px 10px;
45
+ border: 1px solid #d1d5db;
46
+ border-radius: 6px;
47
+ font-size: 13px;
48
+ font-family: "SFMono-Regular", "Consolas", "Liberation Mono", "Menlo", monospace;
49
+ background-color: white;
50
+ resize: vertical;
51
+ transition: border-color 0.2s;
52
+ box-sizing: border-box;
50
53
 
51
- input[type="range"] {
52
- width: 100%;
53
- accent-color: #3b82f6;
54
- cursor: pointer;
54
+ &:focus {
55
+ outline: none;
56
+ border-color: #3b82f6;
57
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
55
58
  }
56
59
 
57
- .max-tokens-input {
58
- width: 100%;
59
- padding: 6px 10px;
60
- border: 1px solid #d1d5db;
61
- border-radius: 6px;
62
- font-size: 13px;
63
- background-color: white;
64
- transition: border-color 0.2s;
65
-
66
- &:focus {
67
- outline: none;
68
- border-color: #3b82f6;
69
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
70
- }
71
-
72
- &::placeholder {
73
- color: #9ca3af;
74
- }
60
+ &::placeholder {
61
+ color: #9ca3af;
75
62
  }
76
63
  }
77
64
 
78
- .setting-value {
79
- font-weight: 700;
80
- color: #3b82f6;
81
- font-size: 13px;
82
- }
83
-
84
- .setting-range-labels {
85
- display: flex;
86
- justify-content: space-between;
65
+ .generation-settings-hint {
87
66
  font-size: 11px;
88
67
  color: #9ca3af;
89
- margin-top: 2px;
68
+ margin-top: 4px;
90
69
  }
@@ -10,7 +10,8 @@ class ChatsController < ApplicationController
10
10
  # Initialize chat context
11
11
  initialize_chat current_user&.chats
12
12
 
13
- @chat = current_user&.chats.includes(:messages).find_by(uuid: params[:id])
13
+ @chat = current_user&.chats.includes(:messages).find_by!(uuid: params[:id])
14
+ session[:chat_id] = @chat.id
14
15
  @messages = @chat.ordered_messages
15
16
 
16
17
  # Initialize history
@@ -71,6 +72,18 @@ class ChatsController < ApplicationController
71
72
  initialize_history @chat&.ordered_by_descending_prompt_executions
72
73
 
73
74
  if params[:message].present?
75
+ # Validate generation settings before proceeding
76
+ begin
77
+ generation_settings = generation_settings_param
78
+ rescue InvalidGenerationSettingsError => e
79
+ @error_message = e.message
80
+ respond_to do |format|
81
+ format.turbo_stream
82
+ format.html { redirect_to new_chat_path, alert: e.message }
83
+ end
84
+ return
85
+ end
86
+
74
87
  # Add user message (will be rendered via turbo stream)
75
88
  @prompt_execution, @user_message = @chat.add_user_message(params[:message],
76
89
  params[:model],
@@ -82,7 +95,7 @@ class ChatsController < ApplicationController
82
95
 
83
96
  # Send to LLM and get assistant response
84
97
  begin
85
- @assistant_message = @chat.add_assistant_response(@prompt_execution, jwt_token, tool_ids: tool_ids_param, generation_settings: generation_settings_param)
98
+ @assistant_message = @chat.add_assistant_response(@prompt_execution, jwt_token, tool_ids: tool_ids_param, generation_settings: generation_settings)
86
99
  # Generate chat title from the user's prompt (only if title is not yet set)
87
100
  @chat.generate_title(params[:message], jwt_token)
88
101
  rescue StandardError => e
@@ -149,18 +162,26 @@ class ChatsController < ApplicationController
149
162
  def update
150
163
  jwt_token = current_user.id_token if user_signed_in?
151
164
 
152
- # Find or create chat
153
- @chat = Chat.find_or_switch_for_session(
154
- session,
155
- current_user,
156
- llm_uuid: params[:api_key_uuid],
157
- model: params[:model]
158
- )
165
+ # Use the chat identified by the URL, not the session
166
+ @chat = current_user.chats.find(params[:id])
167
+ session[:chat_id] = @chat.id
159
168
  @messages = @chat&.ordered_messages || []
160
169
  # initialize history for the chat
161
170
  initialize_history @chat&.ordered_by_descending_prompt_executions
162
171
 
163
172
  if params[:message].present?
173
+ # Validate generation settings before proceeding
174
+ begin
175
+ generation_settings = generation_settings_param
176
+ rescue InvalidGenerationSettingsError => e
177
+ @error_message = e.message
178
+ respond_to do |format|
179
+ format.turbo_stream
180
+ format.html { redirect_to chat_path(@chat), alert: e.message }
181
+ end
182
+ return
183
+ end
184
+
164
185
  # Add user message (will be rendered via turbo stream)
165
186
  @prompt_execution, @user_message = @chat.add_user_message(params[:message],
166
187
  params[:model],
@@ -172,7 +193,7 @@ class ChatsController < ApplicationController
172
193
 
173
194
  # Send to LLM and get assistant response
174
195
  begin
175
- @assistant_message = @chat.add_assistant_response(@prompt_execution, jwt_token, tool_ids: tool_ids_param, generation_settings: generation_settings_param)
196
+ @assistant_message = @chat.add_assistant_response(@prompt_execution, jwt_token, tool_ids: tool_ids_param, generation_settings: generation_settings)
176
197
  rescue StandardError => e
177
198
  Rails.logger.error "Error in chat response: #{e.class} - #{e.message}\n#{e.backtrace&.join("\n")}"
178
199
  @error_message = "An error occurred while getting the response. Please try again."
@@ -192,13 +213,27 @@ class ChatsController < ApplicationController
192
213
  params[:tool_ids].presence || []
193
214
  end
194
215
 
216
+ ALLOWED_GENERATION_KEYS = %w[temperature top_k top_p max_tokens repeat_penalty].freeze
217
+
218
+ class InvalidGenerationSettingsError < StandardError; end
219
+
195
220
  def generation_settings_param
196
- settings = {}
197
- settings[:temperature] = params[:temperature].to_f if params[:temperature].present?
198
- settings[:top_k] = params[:top_k].to_i if params[:top_k].present?
199
- settings[:top_p] = params[:top_p].to_f if params[:top_p].present?
200
- settings[:max_tokens] = params[:max_tokens].to_i if params[:max_tokens].present?
201
- settings[:repeat_penalty] = params[:repeat_penalty].to_f if params[:repeat_penalty].present?
202
- settings
221
+ return {} if params[:generation_settings_json].blank?
222
+
223
+ parsed = JSON.parse(params[:generation_settings_json])
224
+ raise InvalidGenerationSettingsError, "Generation settings must be a JSON object" unless parsed.is_a?(Hash)
225
+
226
+ settings = parsed.slice(*ALLOWED_GENERATION_KEYS)
227
+ invalid_keys = parsed.keys - ALLOWED_GENERATION_KEYS
228
+ raise InvalidGenerationSettingsError, "Unknown keys: #{invalid_keys.join(', ')}" if invalid_keys.any?
229
+
230
+ non_numeric = settings.reject { |_k, v| v.is_a?(Numeric) }
231
+ if non_numeric.any?
232
+ raise InvalidGenerationSettingsError, "Values must be numeric: #{non_numeric.keys.join(', ')}"
233
+ end
234
+
235
+ settings.symbolize_keys
236
+ rescue JSON::ParserError => e
237
+ raise InvalidGenerationSettingsError, "Invalid JSON: #{e.message}"
203
238
  end
204
239
  end
@@ -4,8 +4,8 @@ class PromptsController < ApplicationController
4
4
  skip_before_action :authenticate_user!, raise: false
5
5
 
6
6
  def show
7
- @prompt_execution = PromptNavigator::PromptExecution.includes(:messages).find_by(execution_id: params[:id])
8
- @message = @prompt_execution.messages.first
7
+ @prompt_execution = PromptNavigator::PromptExecution.find_by!(execution_id: params[:id])
8
+ @message = Message.where(prompt_navigator_prompt_execution: @prompt_execution).order(:created_at).first
9
9
  @chat = @message.chat
10
10
  @messages = @chat.ordered_messages
11
11
 
@@ -25,6 +25,9 @@ class PromptsController < ApplicationController
25
25
  # Set active UUID for history sidebar highlighting
26
26
  set_active_message_uuid(@prompt_execution.execution_id)
27
27
 
28
+ # Set branch_from_uuid so the form knows which message to branch from
29
+ @branch_from_uuid = @prompt_execution.execution_id
30
+
28
31
  render "chats/edit"
29
32
  rescue StandardError => e
30
33
  Rails.logger.error "Error in PromptsController#show_by_uuid: #{e.class} - #{e.message}\n#{e.backtrace&.join("\n")}"
@@ -6,15 +6,7 @@ export default class extends Controller {
6
6
  "toggleButton",
7
7
  "toggleIcon",
8
8
  "panel",
9
- "temperatureRange",
10
- "temperatureValue",
11
- "topKRange",
12
- "topKValue",
13
- "topPRange",
14
- "topPValue",
15
- "maxTokensInput",
16
- "repeatPenaltyRange",
17
- "repeatPenaltyValue",
9
+ "jsonInput",
18
10
  ]
19
11
 
20
12
  connect() {
@@ -32,20 +24,4 @@ export default class extends Controller {
32
24
  this.toggleIconTarget.classList.toggle("bi-chevron-up", this.expanded)
33
25
  }
34
26
  }
35
-
36
- updateTemperature() {
37
- this.temperatureValueTarget.textContent = this.temperatureRangeTarget.value
38
- }
39
-
40
- updateTopK() {
41
- this.topKValueTarget.textContent = this.topKRangeTarget.value
42
- }
43
-
44
- updateTopP() {
45
- this.topPValueTarget.textContent = this.topPRangeTarget.value
46
- }
47
-
48
- updateRepeatPenalty() {
49
- this.repeatPenaltyValueTarget.textContent = this.repeatPenaltyRangeTarget.value
50
- }
51
27
  }
@@ -15,13 +15,11 @@ class Chat < ApplicationRecord
15
15
  chat = find_by_session_chat_id(session, current_user)
16
16
  return chat if llm_uuid.nil? || model.nil?
17
17
 
18
- # Create new chat if it doesn't exist or LLM/model has changed
19
- if llm_uuid.present? && model.present? && (chat.nil? || (chat.present? && chat.needs_reset?(llm_uuid, model)))
20
- chat = create!(
21
- user: current_user,
22
- llm_uuid: llm_uuid,
23
- model: model
24
- )
18
+ if chat.present?
19
+ # Update LLM/model on existing chat if changed
20
+ chat.update!(llm_uuid: llm_uuid, model: model) if chat.needs_reset?(llm_uuid, model)
21
+ else
22
+ chat = create!(user: current_user, llm_uuid: llm_uuid, model: model)
25
23
  session[:chat_id] = chat.id
26
24
  end
27
25
 
@@ -49,13 +47,17 @@ class Chat < ApplicationRecord
49
47
  end
50
48
 
51
49
  # Add a user message to the chat
52
- def add_user_message(message, model, branch_from_uuid = nil)
53
- parent_message = branch_from_uuid.present? ? messages.find_by(uuid: branch_from_uuid) : nil
50
+ def add_user_message(message, model, branch_from_execution_id = nil)
51
+ previous_id = if branch_from_execution_id.present?
52
+ PromptNavigator::PromptExecution.find_by(execution_id: branch_from_execution_id)&.id
53
+ else
54
+ messages.where(role: "user").order(:created_at).last&.prompt_navigator_prompt_execution_id
55
+ end
54
56
  prompt_execution = PromptNavigator::PromptExecution.create!(
55
57
  prompt: message,
56
58
  model: model,
57
59
  configuration: "",
58
- previous_id: parent_message&.prompt_navigator_prompt_execution_id
60
+ previous_id: previous_id
59
61
  )
60
62
 
61
63
  new_message = messages.create!(
@@ -33,12 +33,12 @@
33
33
  <%% # Update history sidebar - replace entire content to ensure update %>
34
34
  <%% if @prompt_execution %>
35
35
  <%%= turbo_stream.replace "history-sidebar" do %>
36
- <div id="history-content">
36
+ <div id="history-sidebar">
37
37
  <h2>History</h2>
38
38
  <div class="history-stack" id="history-stack" data-controller="history">
39
39
  <%%= render 'prompt_navigator/history_card', locals: {
40
40
  ann: @prompt_execution,
41
- next_ann: nil,
41
+ next_ann: (@chat&.ordered_by_descending_prompt_executions || [])[1],
42
42
  is_active: @prompt_execution.execution_id == @active_message_uuid,
43
43
  card_path: ->(uuid) { prompt_path(uuid) }
44
44
  } %>
@@ -60,25 +60,27 @@
60
60
  <turbo-stream action="after" target="messages-list">
61
61
  <template>
62
62
  <script>
63
- // Clear and refocus message input
64
- const messageInput = document.getElementById('message-input');
65
- if (messageInput) {
66
- messageInput.value = '';
67
- messageInput.focus();
68
- }
63
+ (function() {
64
+ // Clear and refocus message input
65
+ const messageInput = document.getElementById('message-input');
66
+ if (messageInput) {
67
+ messageInput.value = '';
68
+ messageInput.focus();
69
+ }
69
70
 
70
- // Update submit button state
71
- const form = document.querySelector('[data-controller="chats-form"]');
72
- if (form && messageInput) {
73
- const event = new Event('input', { bubbles: true });
74
- messageInput.dispatchEvent(event);
75
- }
71
+ // Update submit button state
72
+ const form = document.querySelector('[data-controller="chats-form"]');
73
+ if (form && messageInput) {
74
+ const event = new Event('input', { bubbles: true });
75
+ messageInput.dispatchEvent(event);
76
+ }
76
77
 
77
- // Scroll to bottom
78
- const chatMessages = document.getElementById('chat-messages');
79
- if (chatMessages) {
80
- chatMessages.scrollTop = chatMessages.scrollHeight;
81
- }
78
+ // Scroll to bottom
79
+ const chatMessages = document.getElementById('chat-messages');
80
+ if (chatMessages) {
81
+ chatMessages.scrollTop = chatMessages.scrollHeight;
82
+ }
83
+ })();
82
84
  </script>
83
85
  </template>
84
86
  </turbo-stream>
@@ -30,7 +30,7 @@
30
30
  id: "message-input",
31
31
  data: { "chats-form-target": "prompt", action: "input->chats-form#updateSubmitButton" } %>
32
32
  </div>
33
- <%%= f.hidden_field :branch_from_uuid, value: params.dig(:chat, :branch_from_uuid) %>
33
+ <%%= f.hidden_field :branch_from_uuid, value: @branch_from_uuid || params.dig(:chat, :branch_from_uuid) %>
34
34
  <div class="button-wrapper">
35
35
  <%%= f.button type: "submit",
36
36
  class: "send-button",
@@ -47,16 +47,18 @@
47
47
 
48
48
 
49
49
  <script>
50
- // Function to handle scrolling for both initial load and Turbo navigation
51
- function scrollChatMessages() {
50
+ // Remove previous listener to prevent duplicates across Turbo navigations
51
+ if (window._scrollChatMessages) {
52
+ document.removeEventListener('turbo:load', window._scrollChatMessages);
53
+ }
54
+
55
+ window._scrollChatMessages = function() {
52
56
  const chatMessages = document.getElementById('chat-messages');
53
57
  if (chatMessages) {
54
58
  <%% if @target_message_id.present? %>
55
- // Scroll to target message
56
59
  const targetMessage = document.getElementById('message-<%%= @target_message_id %>');
57
60
  if (targetMessage) {
58
61
  targetMessage.scrollIntoView({ behavior: 'smooth', block: 'center' });
59
- // Highlight the target message
60
62
  targetMessage.style.backgroundColor = '#fef3c7';
61
63
  targetMessage.style.border = '2px solid #fbbf24';
62
64
  setTimeout(() => {
@@ -69,10 +71,8 @@
69
71
  chatMessages.scrollTop = chatMessages.scrollHeight;
70
72
  <%% end %>
71
73
  }
72
- }
74
+ };
73
75
 
74
- // Scroll chat messages to bottom or to target message
75
- // Support both regular page loads and Turbo navigation
76
- document.addEventListener('DOMContentLoaded', scrollChatMessages);
77
- document.addEventListener('turbo:load', scrollChatMessages);
76
+ document.addEventListener('DOMContentLoaded', window._scrollChatMessages);
77
+ document.addEventListener('turbo:load', window._scrollChatMessages);
78
78
  </script>
@@ -30,7 +30,7 @@
30
30
  id: "message-input",
31
31
  data: { "chats-form-target": "prompt", action: "input->chats-form#updateSubmitButton" } %>
32
32
  </div>
33
- <%%= f.hidden_field :branch_from_uuid, value: params.dig(:chat, :branch_from_uuid) %>
33
+ <%%= f.hidden_field :branch_from_uuid, value: @branch_from_uuid || params.dig(:chat, :branch_from_uuid) %>
34
34
  <div class="button-wrapper">
35
35
  <%%= f.button type: "submit",
36
36
  class: "send-button",
@@ -26,13 +26,12 @@
26
26
  <%% # Update history sidebar - replace entire content to ensure update %>
27
27
  <%% if @prompt_execution %>
28
28
  <%%= turbo_stream.replace "history-sidebar" do %>
29
-
30
- <div id="history-content">
29
+ <div id="history-sidebar">
31
30
  <h2>History</h2>
32
31
  <div class="history-stack" id="history-stack" data-controller="history">
33
32
  <%%= render 'prompt_navigator/history_card', locals: {
34
33
  ann: @prompt_execution,
35
- next_ann: nil,
34
+ next_ann: (@chat&.ordered_by_descending_prompt_executions || [])[1],
36
35
  is_active: @prompt_execution.execution_id == @active_message_uuid,
37
36
  card_path: ->(uuid) { prompt_path(uuid) }
38
37
  } %>
@@ -54,25 +53,27 @@
54
53
  <turbo-stream action="after" target="messages-list">
55
54
  <template>
56
55
  <script>
57
- // Clear and refocus message input
58
- const messageInput = document.getElementById('message-input');
59
- if (messageInput) {
60
- messageInput.value = '';
61
- messageInput.focus();
62
- }
56
+ (function() {
57
+ // Clear and refocus message input
58
+ const messageInput = document.getElementById('message-input');
59
+ if (messageInput) {
60
+ messageInput.value = '';
61
+ messageInput.focus();
62
+ }
63
63
 
64
- // Update submit button state
65
- const form = document.querySelector('[data-controller="chats-form"]');
66
- if (form && messageInput) {
67
- const event = new Event('input', { bubbles: true });
68
- messageInput.dispatchEvent(event);
69
- }
64
+ // Update submit button state
65
+ const form = document.querySelector('[data-controller="chats-form"]');
66
+ if (form && messageInput) {
67
+ const event = new Event('input', { bubbles: true });
68
+ messageInput.dispatchEvent(event);
69
+ }
70
70
 
71
- // Scroll to bottom
72
- const chatMessages = document.getElementById('chat-messages');
73
- if (chatMessages) {
74
- chatMessages.scrollTop = chatMessages.scrollHeight;
75
- }
71
+ // Scroll to bottom
72
+ const chatMessages = document.getElementById('chat-messages');
73
+ if (chatMessages) {
74
+ chatMessages.scrollTop = chatMessages.scrollHeight;
75
+ }
76
+ })();
76
77
  </script>
77
78
  </template>
78
79
  </turbo-stream>
@@ -13,75 +13,16 @@
13
13
  </button>
14
14
  </div>
15
15
  <div class="generation-settings-panel" data-<%%= stimulus_controller %>-target="panel" style="display: none;">
16
- <div class="generation-setting-item">
17
- <label for="temperature">
18
- Temperature
19
- <span class="setting-value" data-<%%= stimulus_controller %>-target="temperatureValue">0.7</span>
20
- </label>
21
- <input type="range" name="temperature" id="temperature"
22
- min="0" max="2" step="0.1" value="0.7"
23
- data-<%%= stimulus_controller %>-target="temperatureRange"
24
- data-action="input-><%%= stimulus_controller %>#updateTemperature">
25
- <div class="setting-range-labels">
26
- <span>0 (deterministic)</span>
27
- <span>2 (creative)</span>
28
- </div>
29
- </div>
30
-
31
- <div class="generation-setting-item">
32
- <label for="top_k">
33
- Top-K
34
- <span class="setting-value" data-<%%= stimulus_controller %>-target="topKValue">40</span>
35
- </label>
36
- <input type="range" name="top_k" id="top_k"
37
- min="1" max="100" step="1" value="40"
38
- data-<%%= stimulus_controller %>-target="topKRange"
39
- data-action="input-><%%= stimulus_controller %>#updateTopK">
40
- <div class="setting-range-labels">
41
- <span>1 (focused)</span>
42
- <span>100 (diverse)</span>
43
- </div>
44
- </div>
45
-
46
- <div class="generation-setting-item">
47
- <label for="top_p">
48
- Top-P
49
- <span class="setting-value" data-<%%= stimulus_controller %>-target="topPValue">0.9</span>
50
- </label>
51
- <input type="range" name="top_p" id="top_p"
52
- min="0" max="1" step="0.05" value="0.9"
53
- data-<%%= stimulus_controller %>-target="topPRange"
54
- data-action="input-><%%= stimulus_controller %>#updateTopP">
55
- <div class="setting-range-labels">
56
- <span>0 (narrow)</span>
57
- <span>1 (broad)</span>
58
- </div>
59
- </div>
60
-
61
- <div class="generation-setting-item">
62
- <label for="max_tokens">
63
- Max Tokens
64
- </label>
65
- <input type="number" name="max_tokens" id="max_tokens"
66
- min="1" max="128000" step="1" value=""
67
- placeholder="Default (model-dependent)"
68
- class="max-tokens-input"
69
- data-<%%= stimulus_controller %>-target="maxTokensInput">
70
- </div>
71
-
72
- <div class="generation-setting-item">
73
- <label for="repeat_penalty">
74
- Repeat Penalty
75
- <span class="setting-value" data-<%%= stimulus_controller %>-target="repeatPenaltyValue">1.1</span>
76
- </label>
77
- <input type="range" name="repeat_penalty" id="repeat_penalty"
78
- min="1" max="2" step="0.05" value="1.1"
79
- data-<%%= stimulus_controller %>-target="repeatPenaltyRange"
80
- data-action="input-><%%= stimulus_controller %>#updateRepeatPenalty">
81
- <div class="setting-range-labels">
82
- <span>1.0 (no penalty)</span>
83
- <span>2.0 (strong)</span>
84
- </div>
16
+ <label for="generation_settings_json" class="generation-settings-label">
17
+ JSON format
18
+ </label>
19
+ <textarea name="generation_settings_json" id="generation_settings_json"
20
+ class="generation-settings-json-input"
21
+ rows="8"
22
+ placeholder='{"temperature": 0.7, "top_k": 40, "top_p": 0.9, "max_tokens": 4096, "repeat_penalty": 1.1}'
23
+ data-<%%= stimulus_controller %>-target="jsonInput"></textarea>
24
+ <div class="generation-settings-hint">
25
+ Available keys: temperature, top_k, top_p, max_tokens, repeat_penalty
85
26
  </div>
86
27
  </div>
87
28
  </div>
@@ -1,3 +1,3 @@
1
1
  module LlmMetaClient
2
- VERSION = "0.6.1"
2
+ VERSION = "1.0.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: llm_meta_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - dhq_boiler
@@ -49,28 +49,28 @@ dependencies:
49
49
  requirements:
50
50
  - - "~>"
51
51
  - !ruby/object:Gem::Version
52
- version: '0.2'
52
+ version: '1.0'
53
53
  type: :runtime
54
54
  prerelease: false
55
55
  version_requirements: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: '0.2'
59
+ version: '1.0'
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: chat_manager
62
62
  requirement: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: '0.2'
66
+ version: '1.0'
67
67
  type: :runtime
68
68
  prerelease: false
69
69
  version_requirements: !ruby/object:Gem::Requirement
70
70
  requirements:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
- version: '0.2'
73
+ version: '1.0'
74
74
  description: llm_meta_client provides a Rails Engine with scaffold and authentication
75
75
  generators for building LLM-powered chat applications. Supports OpenAI, Anthropic,
76
76
  Google, and Ollama providers.