llm_meta_widget 0.7.1 → 0.7.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b2ed58b9f42be3c20c0b3cd3c7ca4bfa7742daf95d94af95efb499de84e3c55a
|
|
4
|
+
data.tar.gz: 6916c9639a124219b8637dfb985b96fff8eb6bc8390bbb57143b521003d60b19
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ecef782468671eac0d28b2846cee99e21bf57c1bcdcd04027d7feb066d8c0b706d80f4357b61d37e2ea5307ebe9f8ace40ac6ace63e59a8c88a84b4123a6d327
|
|
7
|
+
data.tar.gz: fcd6bdcc159d1368e910a46109fb3a38688f528809b8e0fd4b4fbcb57c2d87e2795cbf497f967d49b9ade039b60d90fd7a558bf4e973d6c66a42648aa5c8b768
|
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Embeddable browser chat widget for the [llm_meta](https://github.com/pubannotation) ecosystem.
|
|
4
4
|
|
|
5
|
-
Client-orchestrated: the widget fetches host-side action schemas + host-published `.well-known/mcp.json` manifests at boot, dispatches tool_calls locally (page-embedded actions) or directly to MCP endpoints (host-wide well-known), and consumes the meta-server's SSE `single_llm_calls` API. Ships
|
|
5
|
+
Client-orchestrated: the widget fetches host-side action schemas + host-published `.well-known/mcp.json` manifests at boot, dispatches tool_calls locally (page-embedded actions) or directly to MCP endpoints (host-wide well-known), and consumes the meta-server's SSE `single_llm_calls` API. Ships as a custom element in one self-contained ES module — on npm for any host, and in a Rails gem whose helper serves the identical file.
|
|
6
6
|
|
|
7
7
|
**No** Devise, DB migrations, ChatManager, or PromptNavigator. Adds only `rails >= 8.0` as a runtime dep — so hosts that haven't bumped to 8.1 can adopt it without a Rails upgrade.
|
|
8
8
|
|
|
@@ -32,7 +32,7 @@ step, no Node at runtime.
|
|
|
32
32
|
|
|
33
33
|
```ruby
|
|
34
34
|
# Gemfile
|
|
35
|
-
gem "llm_meta_widget", "~> 0.
|
|
35
|
+
gem "llm_meta_widget", "~> 0.7"
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
```
|
|
@@ -62,8 +62,8 @@ the role label turns into a spinning gear reading "Working…", and the reply
|
|
|
62
62
|
streams in.
|
|
63
63
|
|
|
64
64
|
If the panel opens but nothing comes back, it is almost always CORS. The hub
|
|
65
|
-
must list your app's origin in its `
|
|
66
|
-
`/api/*` resource, because the widget calls the hub **from the visitor's
|
|
65
|
+
must list your app's origin in its `CORS_ORIGINS` environment variable for
|
|
66
|
+
the `/api/*` resource, because the widget calls the hub **from the visitor's
|
|
67
67
|
browser**, not from your server. Open the browser console: a blocked request
|
|
68
68
|
says so explicitly.
|
|
69
69
|
|
|
@@ -248,7 +248,7 @@ By default the widget renders two pickers below the input textarea:
|
|
|
248
248
|
- **Model dropdown** — populated from the hub's `GET /api/llms` (anon path returns Ollama-only, since the widget's LLM calls use `api_key_uuid: "ollama-local"`).
|
|
249
249
|
- **Tool picker** — populated from the hub's `GET /api/mcp_servers` (anon path returns `public_to_anonymous: true` servers). Two-level UX: server bulk-toggle + individual tool checkboxes on expand.
|
|
250
250
|
|
|
251
|
-
Both pickers require **CORS**: the meta-server must
|
|
251
|
+
Both pickers require **CORS**: the meta-server must allow the host's origin on its `/api/*` resource. That allowlist is an environment variable, not code — `CORS_ORIGINS`, a comma-separated list — so adding a host is a deployment change and a restart, with no commit and nothing about one deployment's hosts published in the repo. Without CORS the fetch is silently blocked and the pickers stay empty.
|
|
252
252
|
|
|
253
253
|
To adjust picker behavior at the helper call site:
|
|
254
254
|
|
|
@@ -257,8 +257,8 @@ To adjust picker behavior at the helper call site:
|
|
|
257
257
|
llm_url: "https://your-meta-server.example",
|
|
258
258
|
tool_hub_url: "https://your-meta-server.example",
|
|
259
259
|
model: "qwen3-6-35b-fast", # initial selection
|
|
260
|
-
enable_model_picker: true, # false →
|
|
261
|
-
enable_tool_picker: true, # false →
|
|
260
|
+
enable_model_picker: true, # false → omit picker, use fixed `model:`
|
|
261
|
+
enable_tool_picker: true, # false → omit picker, no Class-1 tools
|
|
262
262
|
models: nil, # nil = all anon models; ["qwen3-6-35b-fast", …] = allowlist
|
|
263
263
|
hub_tools: nil # nil = all anon-public MCPs; ["togomcp", …] = allowlist by server name
|
|
264
264
|
) %>
|
|
@@ -289,8 +289,8 @@ To lock the widget to the fixed `model:` prop and disable Class-1 tools entirely
|
|
|
289
289
|
| `well_known_urls:` | `nil` | `nil` = auto-discover same-origin; explicit array = fetch those; `[]` = disable |
|
|
290
290
|
| `greeting:` | `nil` | First thing a visitor sees when the panel opens, above the offered prompt templates. `nil` = a generic line |
|
|
291
291
|
| `max_rounds:` | `3` | Cap on tool-call rounds per LLM turn. Page actions cost a round each since 0.4.0 — raise it for multi-step flows |
|
|
292
|
-
| `enable_model_picker:` | `true` | Show model dropdown (Level-1) |
|
|
293
|
-
| `enable_tool_picker:` | `true` | Show tool picker (Level-1) |
|
|
292
|
+
| `enable_model_picker:` | `true` | Show model dropdown (Level-1). `false` removes it from the DOM |
|
|
293
|
+
| `enable_tool_picker:` | `true` | Show tool picker (Level-1). `false` removes it from the DOM |
|
|
294
294
|
| `models:` | `nil` | Model-name allowlist; `nil` = all anon-available |
|
|
295
295
|
| `hub_tools:` | `nil` | MCP-server-name allowlist; `nil` = all anon-public |
|
|
296
296
|
|
|
@@ -404,6 +404,10 @@ it most, since they must already know your form to press it.
|
|
|
404
404
|
three tool classes plus prompts and resources. Its
|
|
405
405
|
`app/views/annotation/text_annotation.html.erb` and `app/controllers/mcp_controller.rb`
|
|
406
406
|
are the fullest example available.
|
|
407
|
+
- **Shipping the element** — `docs/custom-element-distribution.md` is the design note
|
|
408
|
+
behind the custom-element move: the npm package and its CDN URL, why `main`,
|
|
409
|
+
`exports` and `sideEffects` are set the way they are, and why the gem and the npm
|
|
410
|
+
package must never drift in version.
|
|
407
411
|
- **Issues and questions** — <https://github.com/jdkim/llm_meta_widget/issues>
|
|
408
412
|
|
|
409
413
|
## License
|
|
@@ -50,8 +50,6 @@ const MARKUP = `
|
|
|
50
50
|
</div>
|
|
51
51
|
<div class="lmw-messages"></div>
|
|
52
52
|
<div class="lmw-input-container">
|
|
53
|
-
host MCP server actually offers one, so a tools-only server leaves
|
|
54
|
-
the widget exactly as it was. %>
|
|
55
53
|
<div class="lmw-prompts" style="display:none"></div>
|
|
56
54
|
<form class="lmw-form">
|
|
57
55
|
<div class="lmw-input-wrapper">
|
|
@@ -62,25 +60,19 @@ const MARKUP = `
|
|
|
62
60
|
</svg>
|
|
63
61
|
</button>
|
|
64
62
|
</div>
|
|
65
|
-
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
<div class="lmw-tools-empty">Loading…</div>
|
|
79
|
-
</div>
|
|
80
|
-
</details>
|
|
81
|
-
<% end %>
|
|
82
|
-
</div>
|
|
83
|
-
<% end %>
|
|
63
|
+
<div class="lmw-input-controls">
|
|
64
|
+
<select class="lmw-model-picker" title="Select model" aria-label="Select model" style="display:none">
|
|
65
|
+
</select>
|
|
66
|
+
<details class="lmw-tools-picker">
|
|
67
|
+
<summary>
|
|
68
|
+
🔧 Tools
|
|
69
|
+
<span class="lmw-tools-count lmw-tools-count-zero">0</span>
|
|
70
|
+
</summary>
|
|
71
|
+
<div class="lmw-tools-list">
|
|
72
|
+
<div class="lmw-tools-empty">Loading…</div>
|
|
73
|
+
</div>
|
|
74
|
+
</details>
|
|
75
|
+
</div>
|
|
84
76
|
</form>
|
|
85
77
|
</div>
|
|
86
78
|
</div>
|
|
@@ -126,6 +118,11 @@ if (typeof customElements !== "undefined" && !customElements.get("llm-meta-widge
|
|
|
126
118
|
// Everything below is the panel's original logic, moved verbatim from the ERB
|
|
127
119
|
// template. The only change is the sixteen bindings above it, which the
|
|
128
120
|
// template used to inject.
|
|
121
|
+
// Removes a node if it is there. Used to honour the picker flags: see boot().
|
|
122
|
+
function dropNode(node) {
|
|
123
|
+
if (node && node.parentNode) node.parentNode.removeChild(node);
|
|
124
|
+
}
|
|
125
|
+
|
|
129
126
|
function boot(cfg) {
|
|
130
127
|
var LLM_BASE = cfg.LLM_BASE;
|
|
131
128
|
var TOOL_HUB_BASE = cfg.TOOL_HUB_BASE;
|
|
@@ -151,6 +148,14 @@ function boot(cfg) {
|
|
|
151
148
|
var inputEl = root.querySelector(".lmw-input");
|
|
152
149
|
var clearBtn = root.querySelector(".lmw-clear");
|
|
153
150
|
var hideBtn = root.querySelector(".lmw-hide");
|
|
151
|
+
// The ERB partial omitted these nodes entirely when their flag was false.
|
|
152
|
+
// One static template cannot express that, so prune instead — otherwise a
|
|
153
|
+
// disabled Tools picker still renders, and the lookups below never return
|
|
154
|
+
// the null the rest of boot() is written against.
|
|
155
|
+
if (!ENABLE_MODEL_PICKER) dropNode(root.querySelector(".lmw-model-picker"));
|
|
156
|
+
if (!ENABLE_TOOL_PICKER) dropNode(root.querySelector(".lmw-tools-picker"));
|
|
157
|
+
if (!ENABLE_MODEL_PICKER && !ENABLE_TOOL_PICKER) dropNode(root.querySelector(".lmw-input-controls"));
|
|
158
|
+
|
|
154
159
|
var modelPicker = root.querySelector(".lmw-model-picker"); // null when disabled
|
|
155
160
|
var toolsPicker = root.querySelector(".lmw-tools-picker"); // null when disabled
|
|
156
161
|
var toolsListEl = root.querySelector(".lmw-tools-list"); // null when disabled
|
|
@@ -3564,8 +3564,6 @@ var MARKUP = `
|
|
|
3564
3564
|
</div>
|
|
3565
3565
|
<div class="lmw-messages"></div>
|
|
3566
3566
|
<div class="lmw-input-container">
|
|
3567
|
-
host MCP server actually offers one, so a tools-only server leaves
|
|
3568
|
-
the widget exactly as it was. %>
|
|
3569
3567
|
<div class="lmw-prompts" style="display:none"></div>
|
|
3570
3568
|
<form class="lmw-form">
|
|
3571
3569
|
<div class="lmw-input-wrapper">
|
|
@@ -3576,25 +3574,19 @@ var MARKUP = `
|
|
|
3576
3574
|
</svg>
|
|
3577
3575
|
</button>
|
|
3578
3576
|
</div>
|
|
3579
|
-
|
|
3580
|
-
<
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
<div class="lmw-tools-empty">Loading\u2026</div>
|
|
3593
|
-
</div>
|
|
3594
|
-
</details>
|
|
3595
|
-
<% end %>
|
|
3596
|
-
</div>
|
|
3597
|
-
<% end %>
|
|
3577
|
+
<div class="lmw-input-controls">
|
|
3578
|
+
<select class="lmw-model-picker" title="Select model" aria-label="Select model" style="display:none">
|
|
3579
|
+
</select>
|
|
3580
|
+
<details class="lmw-tools-picker">
|
|
3581
|
+
<summary>
|
|
3582
|
+
\u{1F527} Tools
|
|
3583
|
+
<span class="lmw-tools-count lmw-tools-count-zero">0</span>
|
|
3584
|
+
</summary>
|
|
3585
|
+
<div class="lmw-tools-list">
|
|
3586
|
+
<div class="lmw-tools-empty">Loading\u2026</div>
|
|
3587
|
+
</div>
|
|
3588
|
+
</details>
|
|
3589
|
+
</div>
|
|
3598
3590
|
</form>
|
|
3599
3591
|
</div>
|
|
3600
3592
|
</div>
|
|
@@ -3628,6 +3620,9 @@ var LlmMetaWidgetElement = class extends HTMLElement {
|
|
|
3628
3620
|
if (typeof customElements !== "undefined" && !customElements.get("llm-meta-widget")) {
|
|
3629
3621
|
customElements.define("llm-meta-widget", LlmMetaWidgetElement);
|
|
3630
3622
|
}
|
|
3623
|
+
function dropNode(node) {
|
|
3624
|
+
if (node && node.parentNode) node.parentNode.removeChild(node);
|
|
3625
|
+
}
|
|
3631
3626
|
function boot(cfg) {
|
|
3632
3627
|
var LLM_BASE = cfg.LLM_BASE;
|
|
3633
3628
|
var TOOL_HUB_BASE = cfg.TOOL_HUB_BASE;
|
|
@@ -3652,6 +3647,9 @@ function boot(cfg) {
|
|
|
3652
3647
|
var inputEl = root.querySelector(".lmw-input");
|
|
3653
3648
|
var clearBtn = root.querySelector(".lmw-clear");
|
|
3654
3649
|
var hideBtn = root.querySelector(".lmw-hide");
|
|
3650
|
+
if (!ENABLE_MODEL_PICKER) dropNode(root.querySelector(".lmw-model-picker"));
|
|
3651
|
+
if (!ENABLE_TOOL_PICKER) dropNode(root.querySelector(".lmw-tools-picker"));
|
|
3652
|
+
if (!ENABLE_MODEL_PICKER && !ENABLE_TOOL_PICKER) dropNode(root.querySelector(".lmw-input-controls"));
|
|
3655
3653
|
var modelPicker = root.querySelector(".lmw-model-picker");
|
|
3656
3654
|
var toolsPicker = root.querySelector(".lmw-tools-picker");
|
|
3657
3655
|
var toolsListEl = root.querySelector(".lmw-tools-list");
|