llm_meta_client 1.0.1 → 1.0.2
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/CHANGELOG.md +17 -0
- data/app/assets/stylesheets/llm_meta_client/generation_settings.css +15 -0
- data/lib/generators/llm_meta_client/scaffold/templates/app/javascript/controllers/chats_form_controller.js +15 -1
- data/lib/generators/llm_meta_client/scaffold/templates/app/javascript/controllers/generation_settings_controller.js +71 -0
- data/lib/generators/llm_meta_client/scaffold/templates/app/views/shared/_generation_settings_field.html.erb +3 -1
- data/lib/llm_meta_client/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5dde8e658e36a04b651c91bfcbd34d23b639449c4781529cd5c061e49e52cc53
|
|
4
|
+
data.tar.gz: 56d464e06df9afb9a92ef5dcafee8d806158fb1c333dc5a44800a1737095e68b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3a5442c238211a0432a26e54cd7923c1782d11178679a694cb2ac60ddb3bbd02365431bf0bbba61c9f505e65d1c3b8f60303a23dbb4752813fda580bfb997a4f
|
|
7
|
+
data.tar.gz: 955f0bb38816e24504041962e6b2a4cd9531ea89ad805c503624de927c9339383276c146dad1b346f64521f0cd3dfed985d2b5707676efdad27e998eb3441f60
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,23 @@ 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.2] - 2026-03-27
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Add client-side validation for Generation Settings JSON
|
|
13
|
+
|
|
14
|
+
## [1.0.1] - 2026-03-25
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Fix: normalize Ollama llm_type in server resource options
|
|
19
|
+
- Fix: update branch_from_uuid after LLM response
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Refactor: move llm_uuid and model from Chat to PromptExecution
|
|
24
|
+
|
|
8
25
|
## [1.0.0] - 2026-03-25
|
|
9
26
|
|
|
10
27
|
### Changed
|
|
@@ -62,6 +62,21 @@
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
.generation-settings-json-input--invalid {
|
|
66
|
+
border-color: #ef4444;
|
|
67
|
+
|
|
68
|
+
&:focus {
|
|
69
|
+
border-color: #ef4444;
|
|
70
|
+
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.generation-settings-error {
|
|
75
|
+
font-size: 12px;
|
|
76
|
+
color: #ef4444;
|
|
77
|
+
margin-top: 4px;
|
|
78
|
+
}
|
|
79
|
+
|
|
65
80
|
.generation-settings-hint {
|
|
66
81
|
font-size: 11px;
|
|
67
82
|
color: #9ca3af;
|
|
@@ -13,7 +13,15 @@ export default class extends Controller {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
// Handle form submission to show user message immediately
|
|
16
|
-
submit() {
|
|
16
|
+
submit(event) {
|
|
17
|
+
// Check generation settings validity before submitting
|
|
18
|
+
const gsController = this.#generationSettingsController()
|
|
19
|
+
if (gsController && !gsController.isValid) {
|
|
20
|
+
event.preventDefault()
|
|
21
|
+
gsController.validate()
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
// Don't prevent default - let Turbo handle the form submission
|
|
18
26
|
// Just add the user message to the DOM immediately
|
|
19
27
|
const messageContent = this.promptTarget.value.trim()
|
|
@@ -64,6 +72,12 @@ export default class extends Controller {
|
|
|
64
72
|
}
|
|
65
73
|
}
|
|
66
74
|
|
|
75
|
+
#generationSettingsController() {
|
|
76
|
+
const el = this.element.querySelector('[data-controller*="generation-settings"]')
|
|
77
|
+
if (!el) return null
|
|
78
|
+
return this.application.getControllerForElementAndIdentifier(el, "generation-settings")
|
|
79
|
+
}
|
|
80
|
+
|
|
67
81
|
#canSubmit() {
|
|
68
82
|
// Text field and prompt field can be validated using HTML5's required attribute,
|
|
69
83
|
// so we delegate to checkValidity() to utilize standard validation
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
|
2
2
|
|
|
3
|
+
const ALLOWED_KEYS = ["temperature", "top_k", "top_p", "max_tokens", "repeat_penalty"]
|
|
4
|
+
|
|
3
5
|
// Connects to data-controller="generation-settings"
|
|
4
6
|
export default class extends Controller {
|
|
5
7
|
static targets = [
|
|
@@ -7,6 +9,7 @@ export default class extends Controller {
|
|
|
7
9
|
"toggleIcon",
|
|
8
10
|
"panel",
|
|
9
11
|
"jsonInput",
|
|
12
|
+
"error",
|
|
10
13
|
]
|
|
11
14
|
|
|
12
15
|
connect() {
|
|
@@ -24,4 +27,72 @@ export default class extends Controller {
|
|
|
24
27
|
this.toggleIconTarget.classList.toggle("bi-chevron-up", this.expanded)
|
|
25
28
|
}
|
|
26
29
|
}
|
|
30
|
+
|
|
31
|
+
validate() {
|
|
32
|
+
const input = this.jsonInputTarget.value.trim()
|
|
33
|
+
|
|
34
|
+
if (!input) {
|
|
35
|
+
this.#clearError()
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let parsed
|
|
40
|
+
try {
|
|
41
|
+
parsed = JSON.parse(input)
|
|
42
|
+
} catch (e) {
|
|
43
|
+
this.#showError("Invalid JSON syntax")
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (typeof parsed !== "object" || Array.isArray(parsed) || parsed === null) {
|
|
48
|
+
this.#showError("Must be a JSON object (e.g. {\"temperature\": 0.7})")
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const unknownKeys = Object.keys(parsed).filter(k => !ALLOWED_KEYS.includes(k))
|
|
53
|
+
if (unknownKeys.length > 0) {
|
|
54
|
+
this.#showError(`Unknown keys: ${unknownKeys.join(", ")}`)
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const nonNumeric = Object.entries(parsed).filter(([, v]) => typeof v !== "number")
|
|
59
|
+
if (nonNumeric.length > 0) {
|
|
60
|
+
this.#showError(`Values must be numeric: ${nonNumeric.map(([k]) => k).join(", ")}`)
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.#clearError()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get isValid() {
|
|
68
|
+
if (!this.hasJsonInputTarget) return true
|
|
69
|
+
const input = this.jsonInputTarget.value.trim()
|
|
70
|
+
if (!input) return true
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const parsed = JSON.parse(input)
|
|
74
|
+
if (typeof parsed !== "object" || Array.isArray(parsed) || parsed === null) return false
|
|
75
|
+
if (Object.keys(parsed).some(k => !ALLOWED_KEYS.includes(k))) return false
|
|
76
|
+
if (Object.values(parsed).some(v => typeof v !== "number")) return false
|
|
77
|
+
return true
|
|
78
|
+
} catch {
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
#showError(message) {
|
|
84
|
+
if (this.hasErrorTarget) {
|
|
85
|
+
this.errorTarget.textContent = message
|
|
86
|
+
this.errorTarget.style.display = "block"
|
|
87
|
+
}
|
|
88
|
+
this.jsonInputTarget.classList.add("generation-settings-json-input--invalid")
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
#clearError() {
|
|
92
|
+
if (this.hasErrorTarget) {
|
|
93
|
+
this.errorTarget.textContent = ""
|
|
94
|
+
this.errorTarget.style.display = "none"
|
|
95
|
+
}
|
|
96
|
+
this.jsonInputTarget.classList.remove("generation-settings-json-input--invalid")
|
|
97
|
+
}
|
|
27
98
|
}
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
class="generation-settings-json-input"
|
|
21
21
|
rows="8"
|
|
22
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"
|
|
23
|
+
data-<%%= stimulus_controller %>-target="jsonInput"
|
|
24
|
+
data-action="input-><%%= stimulus_controller %>#validate"></textarea>
|
|
25
|
+
<div class="generation-settings-error" data-<%%= stimulus_controller %>-target="error" style="display: none;"></div>
|
|
24
26
|
<div class="generation-settings-hint">
|
|
25
27
|
Available keys: temperature, top_k, top_p, max_tokens, repeat_penalty
|
|
26
28
|
</div>
|