@aibranch/llm-meta-widget 0.14.0 → 0.15.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.
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ Option 3 if it does not.
|
|
|
61
61
|
|
|
62
62
|
```ruby
|
|
63
63
|
# Gemfile
|
|
64
|
-
gem "llm_meta_widget", "~> 0.
|
|
64
|
+
gem "llm_meta_widget", "~> 0.15.0"
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
```bash
|
|
@@ -152,17 +152,17 @@ The widget is a custom element in a single self-contained ES module, so the
|
|
|
152
152
|
whole integration is two lines of HTML:
|
|
153
153
|
|
|
154
154
|
```html
|
|
155
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@aibranch/llm-meta-widget@0.
|
|
155
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@aibranch/llm-meta-widget@0.15"></script>
|
|
156
156
|
<llm-meta-widget llm-url="https://your-meta-server.example"
|
|
157
157
|
model="gpt-oss-120b"
|
|
158
158
|
greeting="Hi — ask me anything about this page."></llm-meta-widget>
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
-
**`@0.
|
|
161
|
+
**`@0.15` is a version range, and it stops at 0.15.x on purpose.** You receive
|
|
162
162
|
bug fixes without editing your page, and a release that breaks your page cannot
|
|
163
163
|
arrive on its own.
|
|
164
164
|
|
|
165
|
-
Moving to 0.
|
|
165
|
+
Moving to 0.16 is therefore a change you make yourself. Read
|
|
166
166
|
[CHANGELOG.md](CHANGELOG.md) before you do, because this is where what your page
|
|
167
167
|
must provide can change. For example, 0.10.0 changed how the widget finds a page
|
|
168
168
|
card: by media type rather than by element id. A page that declared its card the
|
|
@@ -602,6 +602,18 @@ so no other consumer can rely on them. Each kind falls back on its own, so you
|
|
|
602
602
|
can move tools into the declared global and leave prompts and resources where
|
|
603
603
|
they are.
|
|
604
604
|
|
|
605
|
+
**Script order does not matter.** The widget looks up your global at the moment
|
|
606
|
+
it needs a handler, not when it reads the card. The script that defines
|
|
607
|
+
`window.mcp` may therefore run before or after the widget loads: a `defer`
|
|
608
|
+
attribute, an ES module, or a `<script>` near the end of the page are all fine.
|
|
609
|
+
If a handler is wanted while the global is still undefined, the widget says so
|
|
610
|
+
in the browser console once, and falls back to the older globals for that call.
|
|
611
|
+
|
|
612
|
+
Before 0.15.0 the lookup happened once at startup, so a page whose handler
|
|
613
|
+
script ran later got no handlers at all for the rest of its life, with only a
|
|
614
|
+
console warning to say why. If you are pinned below 0.15.0, define your global
|
|
615
|
+
before the widget's own script tag.
|
|
616
|
+
|
|
605
617
|
**The card is found by its media type.** A client matches
|
|
606
618
|
`script[type="application/mcp-static-primitives+json"]`, so the element needs no
|
|
607
619
|
`id`. This is how a client that was never told about your page can still read
|
|
@@ -708,24 +708,42 @@ function declaredPageGlobal(card, warn = console.warn) {
|
|
|
708
708
|
}
|
|
709
709
|
function pageHandlers({ card, scope = {}, legacy = {}, warn = console.warn } = {}) {
|
|
710
710
|
const name = declaredPageGlobal(card, warn);
|
|
711
|
-
const declared = name ? scope[name] : null;
|
|
712
|
-
if (name && !declared) {
|
|
713
|
-
warn(`[llm-meta-widget] the page card declares global "${name}", but window.${name} is not defined \u2014 is the script that defines it loaded, and did it run?`);
|
|
714
|
-
}
|
|
715
711
|
const isMap = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
712
|
+
const said = /* @__PURE__ */ new Set();
|
|
713
|
+
const sayOnce = (key, message) => {
|
|
714
|
+
if (said.has(key)) return;
|
|
715
|
+
said.add(key);
|
|
716
|
+
warn(message);
|
|
717
|
+
};
|
|
716
718
|
const pick = (kind, legacyName) => {
|
|
719
|
+
const declared = name ? scope[name] : null;
|
|
720
|
+
if (name && !declared) {
|
|
721
|
+
sayOnce(
|
|
722
|
+
"missing",
|
|
723
|
+
`[llm-meta-widget] the page card declares global "${name}", but window.${name} is not defined \u2014 is the script that defines it loaded, and did it run?`
|
|
724
|
+
);
|
|
725
|
+
}
|
|
717
726
|
const fromGlobal = declared ? declared[kind] : void 0;
|
|
718
727
|
if (isMap(fromGlobal)) return fromGlobal;
|
|
719
728
|
if (declared && fromGlobal !== void 0 && !isMap(fromGlobal)) {
|
|
720
|
-
|
|
729
|
+
sayOnce(
|
|
730
|
+
`shape:${kind}`,
|
|
731
|
+
`[llm-meta-widget] window.${name}.${kind} is ${Array.isArray(fromGlobal) ? "an array" : typeof fromGlobal}; it must be an object keyed by ${kind === "resources" ? "uri" : "name"}`
|
|
732
|
+
);
|
|
721
733
|
}
|
|
722
734
|
return legacyName && scope[legacyName] || {};
|
|
723
735
|
};
|
|
724
736
|
return {
|
|
725
737
|
global: name,
|
|
726
|
-
tools
|
|
727
|
-
|
|
728
|
-
|
|
738
|
+
get tools() {
|
|
739
|
+
return pick("tools", legacy.tools);
|
|
740
|
+
},
|
|
741
|
+
get prompts() {
|
|
742
|
+
return pick("prompts", legacy.prompts);
|
|
743
|
+
},
|
|
744
|
+
get resources() {
|
|
745
|
+
return pick("resources", legacy.resources);
|
|
746
|
+
}
|
|
729
747
|
};
|
|
730
748
|
}
|
|
731
749
|
function mergeStaticPrimitivesCards(cards, warn = console.warn) {
|
|
@@ -736,7 +754,7 @@ function mergeStaticPrimitivesCards(cards, warn = console.warn) {
|
|
|
736
754
|
if (!entry || typeof entry.type !== "string") continue;
|
|
737
755
|
const clash = merged[kind].find((r) => r.type === entry.type && r.global !== entry.global);
|
|
738
756
|
if (clash) {
|
|
739
|
-
warn(`[llm-meta-widget]
|
|
757
|
+
warn(`[llm-meta-widget] the ${entry.type} transport is declared more than once, with different globals ("${clash.global}" and "${entry.global}"); using "${clash.global}". One block may declare it twice, or two blocks may disagree`);
|
|
740
758
|
continue;
|
|
741
759
|
}
|
|
742
760
|
if (!merged[kind].some((r) => r.type === entry.type && r.global === entry.global)) {
|
|
@@ -4163,7 +4181,9 @@ function boot(cfg) {
|
|
|
4163
4181
|
);
|
|
4164
4182
|
} else {
|
|
4165
4183
|
var pageCardEl = document.getElementById(PAGE_CARD_ID);
|
|
4166
|
-
pageCard =
|
|
4184
|
+
pageCard = mergeStaticPrimitivesCards(
|
|
4185
|
+
[readStaticPrimitivesCard(pageCardEl ? pageCardEl.textContent : null)]
|
|
4186
|
+
);
|
|
4167
4187
|
}
|
|
4168
4188
|
var handlers = pageHandlers({
|
|
4169
4189
|
card: pageCard,
|
|
@@ -1165,19 +1165,36 @@ export function declaredPageGlobal(card, warn = console.warn) {
|
|
|
1165
1165
|
// keeps working instead of losing the primitives it has not moved yet.
|
|
1166
1166
|
export function pageHandlers({ card, scope = {}, legacy = {}, warn = console.warn } = {}) {
|
|
1167
1167
|
const name = declaredPageGlobal(card, warn)
|
|
1168
|
-
const
|
|
1169
|
-
|
|
1170
|
-
//
|
|
1171
|
-
//
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1168
|
+
const isMap = (v) => !!v && typeof v === "object" && !Array.isArray(v)
|
|
1169
|
+
|
|
1170
|
+
// Each said at most once. These now fire on dispatch rather than at mount, so
|
|
1171
|
+
// a page that never defines its global would otherwise repeat them every turn.
|
|
1172
|
+
const said = new Set()
|
|
1173
|
+
const sayOnce = (key, message) => {
|
|
1174
|
+
if (said.has(key)) return
|
|
1175
|
+
said.add(key)
|
|
1176
|
+
warn(message)
|
|
1177
1177
|
}
|
|
1178
1178
|
|
|
1179
|
-
const isMap = (v) => !!v && typeof v === "object" && !Array.isArray(v)
|
|
1180
1179
|
const pick = (kind, legacyName) => {
|
|
1180
|
+
// Resolved HERE, when a handler is wanted, not when the card was read. The
|
|
1181
|
+
// card is parsed from the DOM before the page's own scripts have
|
|
1182
|
+
// necessarily run, and a consumer may be injected before them, so a global
|
|
1183
|
+
// that is missing at discovery may well be defined by the time a tool is
|
|
1184
|
+
// called. Caching that first lookup turned a load-order detail into a page
|
|
1185
|
+
// that silently had no handlers for the rest of its life.
|
|
1186
|
+
const declared = name ? scope[name] : null
|
|
1187
|
+
|
|
1188
|
+
// A card that names a global the page never defines is almost always a load
|
|
1189
|
+
// order problem, or a script that threw before it got there. Falling back in
|
|
1190
|
+
// silence hides that: the page then behaves as if it had declared nothing,
|
|
1191
|
+
// and the first symptom is a prompt or tool that "has no handler".
|
|
1192
|
+
if (name && !declared) {
|
|
1193
|
+
sayOnce("missing",
|
|
1194
|
+
`[llm-meta-widget] the page card declares global "${name}", but window.${name} ` +
|
|
1195
|
+
"is not defined — is the script that defines it loaded, and did it run?")
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1181
1198
|
// `declared ? … : undefined`, not `declared && …`: the second yields null
|
|
1182
1199
|
// when nothing is declared, and `typeof null === "object"`, so the check
|
|
1183
1200
|
// below then warned about "window.null.tools" on every page with no card.
|
|
@@ -1186,16 +1203,20 @@ export function pageHandlers({ card, scope = {}, legacy = {}, warn = console.war
|
|
|
1186
1203
|
// An array is the mistake worth naming: it passes a typeof check, so it
|
|
1187
1204
|
// would be used as a map and answer every lookup with undefined.
|
|
1188
1205
|
if (declared && fromGlobal !== undefined && !isMap(fromGlobal)) {
|
|
1189
|
-
|
|
1190
|
-
|
|
1206
|
+
sayOnce(`shape:${kind}`,
|
|
1207
|
+
`[llm-meta-widget] window.${name}.${kind} is ${Array.isArray(fromGlobal) ? "an array" : typeof fromGlobal}; ` +
|
|
1208
|
+
`it must be an object keyed by ${kind === "resources" ? "uri" : "name"}`)
|
|
1191
1209
|
}
|
|
1192
1210
|
return (legacyName && scope[legacyName]) || {}
|
|
1193
1211
|
}
|
|
1212
|
+
|
|
1213
|
+
// Getters, so each dispatch re-resolves. The call sites read
|
|
1214
|
+
// `handlers.tools` at the moment they need it, which is what makes this work.
|
|
1194
1215
|
return {
|
|
1195
1216
|
global: name,
|
|
1196
|
-
tools
|
|
1197
|
-
prompts
|
|
1198
|
-
resources
|
|
1217
|
+
get tools() { return pick("tools", legacy.tools) },
|
|
1218
|
+
get prompts() { return pick("prompts", legacy.prompts) },
|
|
1219
|
+
get resources() { return pick("resources", legacy.resources) }
|
|
1199
1220
|
}
|
|
1200
1221
|
}
|
|
1201
1222
|
|
|
@@ -1224,8 +1245,9 @@ export function mergeStaticPrimitivesCards(cards, warn = console.warn) {
|
|
|
1224
1245
|
if (!entry || typeof entry.type !== "string") continue
|
|
1225
1246
|
const clash = merged[kind].find((r) => r.type === entry.type && r.global !== entry.global)
|
|
1226
1247
|
if (clash) {
|
|
1227
|
-
warn(`[llm-meta-widget]
|
|
1228
|
-
`("${clash.global}" and "${entry.global}"); using
|
|
1248
|
+
warn(`[llm-meta-widget] the ${entry.type} transport is declared more than once, ` +
|
|
1249
|
+
`with different globals ("${clash.global}" and "${entry.global}"); using ` +
|
|
1250
|
+
`"${clash.global}". One block may declare it twice, or two blocks may disagree`)
|
|
1229
1251
|
continue
|
|
1230
1252
|
}
|
|
1231
1253
|
if (!merged[kind].some((r) => r.type === entry.type && r.global === entry.global)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aibranch/llm-meta-widget",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"//version": "Must stay in step with lib/llm_meta_widget/version.rb. Two independently versioned copies of the same client is the drift docs/custom-element-distribution.md warns about: bump both, release both.",
|
|
5
5
|
"description": "Embeddable browser chat widget: a custom element that discovers tools at page, origin and hub scope and dispatches each tool call to the right one. Two lines of HTML on any host, Rails or not.",
|
|
6
6
|
"keywords": [
|