murmur-rag 1.3.1 → 2.1.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.
Files changed (37) hide show
  1. package/README.md +7 -9
  2. package/dist/cdn/{anthropic-tw416spz.js → anthropic-1y1mb77z.js} +2 -2
  3. package/dist/cdn/chunk-nhd6pd73.js +1 -0
  4. package/dist/cdn/embed-3swpcbya.js +83 -0
  5. package/dist/cdn/{embed-yz75savs.js → embed-7xhp36fz.js} +3 -3
  6. package/dist/cdn/{embed-3am76qfd.js → embed-hhcax25m.js} +6 -6
  7. package/dist/cdn/{embed-cx1r66ch.js → embed-q03dhgpb.js} +5 -5
  8. package/dist/cdn/embed-s9zy3aav.js +10 -0
  9. package/dist/cdn/{embed-g0p6yc29.js → embed-wd4wcxtq.js} +2 -2
  10. package/dist/cdn/{embed-q81wdr1z.js → embed-zckjbrcx.js} +4 -4
  11. package/dist/cdn/{google-556tp13p.js → google-b4zxgp7g.js} +5 -5
  12. package/dist/cdn/index-ev3304hr.js +1 -0
  13. package/dist/cdn/{index-8r44b2wt.js → index-f5ctpc4w.js} +1 -1
  14. package/dist/cdn/index-k0v6as0z.js +1 -0
  15. package/dist/cdn/index-q38abctd.js +1 -0
  16. package/dist/cdn/{index-qpy1k923.js → index-tjxzgn54.js} +2 -2
  17. package/dist/cdn/{mistral-25w1nsx5.js → mistral-e1jxb6vy.js} +2 -2
  18. package/dist/cdn/{murmur-1a55et82.js → murmur-yjgc7apa.js} +3 -3
  19. package/dist/cdn/murmur.js +6 -6
  20. package/dist/cdn/{openai-compatible-sg25g0vj.js → openai-compatible-8byk6wkm.js} +2 -2
  21. package/dist/cdn/{openai-bjrbem49.js → openai-q9byakt1.js} +11 -11
  22. package/dist/cdn/retriever-3yz0vzz9.js +1 -0
  23. package/dist/cdn/{transformers.web-49m0ht4a.js → transformers.web-nr67a9j3.js} +14 -14
  24. package/dist/lib/chunks/{index-4ftk20yq.js → index-ekxks9vp.js} +17 -17
  25. package/dist/lib/embed.js +4 -4
  26. package/dist/lib/llm/index.js +0 -23
  27. package/dist/lib/widget/index.js +2 -2
  28. package/dist/types/llm/index.d.ts +0 -8
  29. package/dist/types/widget/session.d.ts +7 -7
  30. package/package.json +1 -1
  31. package/dist/cdn/chunk-xyp6nm65.js +0 -1
  32. package/dist/cdn/embed-50pfy67v.js +0 -83
  33. package/dist/cdn/embed-rjpq8psf.js +0 -10
  34. package/dist/cdn/index-a5j4aat5.js +0 -1
  35. package/dist/cdn/index-ft8r539a.js +0 -1
  36. package/dist/cdn/index-pjxy71n5.js +0 -1
  37. package/dist/cdn/retriever-06ybegpd.js +0 -1
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  cleanAnswer2,
3
+ citedSources2,
3
4
  passageHref2
4
5
  } from "./index-b77xqap3.js";
5
6
  var __chunkGraphs;
@@ -403,8 +404,6 @@ class ChatSession {
403
404
  return "custom";
404
405
  if (m === "proxy" || m === "auto" && this.options.llm?.endpoint)
405
406
  return "proxy";
406
- if ((m === "auto" || m === "key") && this.options.llm?.apiKey)
407
- return "owner";
408
407
  if (m === "local")
409
408
  return "local";
410
409
  if (m === "key" || !this.localAllowed)
@@ -417,13 +416,13 @@ class ChatSession {
417
416
  return false;
418
417
  if (m === "local")
419
418
  return true;
420
- return !this.options.llm?.endpoint && !this.options.llm?.apiKey && this.options.local !== false;
419
+ return !this.options.llm?.endpoint && this.options.local !== false;
421
420
  }
422
421
  get keyAllowed() {
423
422
  const m = this.configured;
424
423
  if (this.options.model || m === "proxy" || m === "local")
425
424
  return false;
426
- return !this.options.llm?.endpoint && !this.options.llm?.apiKey;
425
+ return !this.options.llm?.endpoint;
427
426
  }
428
427
  get localState() {
429
428
  return this.local;
@@ -464,7 +463,7 @@ class ChatSession {
464
463
  async settleChoice() {
465
464
  if (!this.localAllowed || !this.keyAllowed || readLocal(`${this.key}-local`) !== null)
466
465
  return;
467
- const [{ isConfigured }, store] = await Promise.all([(__preload("xreqcp1t"), import("../llm/index.js")), this.store()]);
466
+ const [{ isConfigured }, store] = await Promise.all([(__preload("vb9smwta"), import("../llm/index.js")), this.store()]);
468
467
  const saved = await store.load();
469
468
  if (saved && isConfigured(saved))
470
469
  writeLocal(`${this.key}-local`, "0");
@@ -495,7 +494,7 @@ class ChatSession {
495
494
  this.persist();
496
495
  }
497
496
  store() {
498
- this.storePromise ??= (__preload("xreqcp1t"), import("../llm/index.js")).then((llm) => {
497
+ this.storePromise ??= (__preload("vb9smwta"), import("../llm/index.js")).then((llm) => {
499
498
  const opts = {};
500
499
  if (this.options.catalogUrl)
501
500
  opts.catalogUrl = this.options.catalogUrl;
@@ -509,12 +508,10 @@ class ChatSession {
509
508
  const mode = this.mode;
510
509
  if (mode === "custom" || mode === "local")
511
510
  return null;
512
- const llm = await (__preload("xreqcp1t"), import("../llm/index.js"));
511
+ const llm = await (__preload("vb9smwta"), import("../llm/index.js"));
513
512
  const config = this.options.llm ?? {};
514
513
  if (mode === "proxy")
515
514
  return llm.proxySettings(config);
516
- if (mode === "owner")
517
- return llm.ownerKeySettings(config, this.options.catalogUrl);
518
515
  return llm.resolveSettings({ ...config, endpoint: "" }, await this.store());
519
516
  }
520
517
  async needsSetup() {
@@ -557,7 +554,7 @@ class ChatSession {
557
554
  const settings = await this.settings();
558
555
  if (!settings)
559
556
  throw new SetupNeeded2;
560
- const { loadModel } = await (__preload("xreqcp1t"), import("../llm/index.js"));
557
+ const { loadModel } = await (__preload("vb9smwta"), import("../llm/index.js"));
561
558
  return loadModel(settings);
562
559
  });
563
560
  const opts = {
@@ -621,7 +618,7 @@ class ChatSession {
621
618
  return `local-${error.code ?? "load"}|${error.message}`;
622
619
  }
623
620
  try {
624
- const { describeError } = await (__preload("xreqcp1t"), import("../llm/index.js"));
621
+ const { describeError } = await (__preload("vb9smwta"), import("../llm/index.js"));
625
622
  const settings = this.mode === "custom" || this.mode === "local" ? null : await this.settings();
626
623
  const info = describeError(error, settings?.apiKey);
627
624
  return `${info.code}|${info.message}`;
@@ -1154,14 +1151,17 @@ class MurmurChat2 extends Base {
1154
1151
  return;
1155
1152
  }
1156
1153
  const passages = turn.passages ?? [];
1154
+ const content = cleanAnswer2(turn.content);
1155
+ const order = citedSources2(content, passages.length);
1156
+ const label = (n) => order.indexOf(n) + 1;
1157
1157
  const body = el(doc, "div");
1158
- renderMarkdown2(body, cleanAnswer2(turn.content), (n) => {
1158
+ renderMarkdown2(body, content, (n) => {
1159
1159
  const p = passages[n - 1];
1160
- if (!p)
1160
+ if (!p || !label(n))
1161
1161
  return null;
1162
1162
  const a = el(doc, "a", { class: "cite", href: passageHref2(p) });
1163
- a.textContent = String(n);
1164
- a.setAttribute("aria-label", `${this.t.sources} ${n}: ${p.title}`);
1163
+ a.textContent = String(label(n));
1164
+ a.setAttribute("aria-label", `${this.t.sources} ${label(n)}: ${p.title}`);
1165
1165
  return a;
1166
1166
  });
1167
1167
  const parts = [body];
@@ -1170,7 +1170,7 @@ class MurmurChat2 extends Base {
1170
1170
  status.append(el(doc, "span", { class: "lamp off", "aria-hidden": "true" }), doc.createTextNode(this.t.notFound));
1171
1171
  parts.push(status);
1172
1172
  }
1173
- const cited = turn.cited ?? [];
1173
+ const cited = order;
1174
1174
  if (finished && cited.length) {
1175
1175
  parts.push(text(doc, "p", this.t.sources, "sources-label"));
1176
1176
  const list = el(doc, "ol", { class: "sources" });
@@ -1180,7 +1180,7 @@ class MurmurChat2 extends Base {
1180
1180
  continue;
1181
1181
  const li = el(doc, "li");
1182
1182
  const a = el(doc, "a", { href: passageHref2(p) });
1183
- const ring = text(doc, "span", String(n), "cite");
1183
+ const ring = text(doc, "span", String(label(n)), "cite");
1184
1184
  ring.setAttribute("aria-hidden", "true");
1185
1185
  const where = el(doc, "span", { class: "where" });
1186
1186
  where.append(doc.createTextNode(p.title || p.url));
package/dist/lib/embed.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  __chunks,
3
3
  mountMurmur2
4
- } from "./chunks/index-4ftk20yq.js";
5
- __chunks(import.meta.url,["n035jphv","4ftk20yq","t36hd4vt","wxshtnm0","dj4321kh","xreqcp1t","qfx1tgz2","kaeec41p","b77xqap3","8h9c8ekq","p86sy3y4","1zk822m5"],[["./embed.js",1],["./chunks/index-4ftk20yq.js",8],["./chunks/murmur-t36hd4vt.js",9,10],["./chunks/retriever-wxshtnm0.js",10],["./indexer/index.js",11],["./llm/index.js"],["./local/index.js"],["./chunks/chunk-kaeec41p.js",11],["./chunks/index-b77xqap3.js"],["./chunks/index-8h9c8ekq.js",10,8],["./chunks/index-p86sy3y4.js",8],["./chunks/index-1zk822m5.js"]],0);
4
+ } from "./chunks/index-ekxks9vp.js";
5
+ __chunks(import.meta.url,["mas10d36","ekxks9vp","t36hd4vt","wxshtnm0","dj4321kh","vb9smwta","qfx1tgz2","kaeec41p","b77xqap3","8h9c8ekq","p86sy3y4","1zk822m5"],[["./embed.js",1],["./chunks/index-ekxks9vp.js",8],["./chunks/murmur-t36hd4vt.js",9,10],["./chunks/retriever-wxshtnm0.js",10],["./indexer/index.js",11],["./llm/index.js"],["./local/index.js"],["./chunks/chunk-kaeec41p.js",11],["./chunks/index-b77xqap3.js"],["./chunks/index-8h9c8ekq.js",10,8],["./chunks/index-p86sy3y4.js",8],["./chunks/index-1zk822m5.js"]],0);
6
6
 
7
7
  // src/embed.ts
8
8
  function optionsFromDataset(data, base) {
@@ -16,8 +16,8 @@ function optionsFromDataset(data, base) {
16
16
  llm.model = data.model;
17
17
  if (data.endpoint)
18
18
  llm.endpoint = data.endpoint;
19
- if (data.apiKey)
20
- llm.apiKey = data.apiKey;
19
+ if (data.apiKey && typeof console !== "undefined")
20
+ console.error('murmur: data-api-key is ignored: a key in the page can be read by anyone. Keep it in a Worker (data-endpoint), run the model in the browser (data-mode="local"), or let visitors use their own key.');
21
21
  if (Object.keys(llm).length)
22
22
  o.llm = llm;
23
23
  if (data.instructions)
@@ -2,11 +2,8 @@
2
2
  import {
3
3
  createLlmSettingsStore,
4
4
  DEFAULT_RECOMMENDED,
5
- defaultModelOf,
6
5
  isConfigured,
7
6
  liveCatalog,
8
- loadCatalog,
9
- providerMeta,
10
7
  secureStorage,
11
8
  validateEndpoint
12
9
  } from "llm-connect";
@@ -26,25 +23,6 @@ function proxySettings(config) {
26
23
  settings.headers = config.headers;
27
24
  return settings;
28
25
  }
29
- var warned = false;
30
- async function ownerKeySettings(config, catalogUrl = DEFAULT_CATALOG_URL) {
31
- if (!config.apiKey)
32
- return null;
33
- if (!warned && typeof console !== "undefined") {
34
- warned = true;
35
- console.warn("murmur: the API key in this page can be read by anyone. Use a key with a spending limit, or a proxy (data-endpoint).");
36
- }
37
- const providerId = config.provider || "openai";
38
- const catalog = await loadCatalog(catalogUrl);
39
- const meta = providerMeta(catalog, providerId);
40
- if (!meta)
41
- throw new Error(`murmur: unknown provider "${providerId}"`);
42
- const model = config.model || defaultModelOf(catalog[providerId]) || "";
43
- const settings = { apiKey: config.apiKey, model, ...meta };
44
- if (config.headers)
45
- settings.headers = config.headers;
46
- return settings;
47
- }
48
26
  function visitorStore(config, options = {}) {
49
27
  const key = options.storageKey ?? "murmur";
50
28
  const defaults = {};
@@ -71,7 +49,6 @@ export {
71
49
  describeError,
72
50
  isConfigured2 as isConfigured,
73
51
  loadModel,
74
- ownerKeySettings,
75
52
  proxySettings,
76
53
  resolveSettings,
77
54
  visitorStore
@@ -8,8 +8,8 @@ import {
8
8
  MurmurChat2,
9
9
  defineMurmurChat2,
10
10
  mountMurmur2
11
- } from "../chunks/index-4ftk20yq.js";
12
- __chunks(import.meta.url,["kaf6n93p","4ftk20yq","t36hd4vt","wxshtnm0","dj4321kh","xreqcp1t","qfx1tgz2","kaeec41p","b77xqap3","8h9c8ekq","p86sy3y4","1zk822m5"],[["./index.js",1],["../chunks/index-4ftk20yq.js",8],["../chunks/murmur-t36hd4vt.js",9,10],["../chunks/retriever-wxshtnm0.js",10],["../indexer/index.js",11],["../llm/index.js"],["../local/index.js"],["../chunks/chunk-kaeec41p.js",11],["../chunks/index-b77xqap3.js"],["../chunks/index-8h9c8ekq.js",10,8],["../chunks/index-p86sy3y4.js",8],["../chunks/index-1zk822m5.js"]],0);
11
+ } from "../chunks/index-ekxks9vp.js";
12
+ __chunks(import.meta.url,["mm7xk878","ekxks9vp","t36hd4vt","wxshtnm0","dj4321kh","vb9smwta","qfx1tgz2","kaeec41p","b77xqap3","8h9c8ekq","p86sy3y4","1zk822m5"],[["./index.js",1],["../chunks/index-ekxks9vp.js",8],["../chunks/murmur-t36hd4vt.js",9,10],["../chunks/retriever-wxshtnm0.js",10],["../indexer/index.js",11],["../llm/index.js"],["../local/index.js"],["../chunks/chunk-kaeec41p.js",11],["../chunks/index-b77xqap3.js"],["../chunks/index-8h9c8ekq.js",10,8],["../chunks/index-p86sy3y4.js",8],["../chunks/index-1zk822m5.js"]],0);
13
13
  export {
14
14
  MESSAGES2 as MESSAGES,
15
15
  MurmurChat2 as MurmurChat,
@@ -13,19 +13,11 @@ export interface LlmConfig {
13
13
  endpoint?: string;
14
14
  /** Extra headers sent to the proxy. */
15
15
  headers?: Record<string, string>;
16
- /**
17
- * The owner's own key, used for every visitor with `provider` and `model`. It is in the page,
18
- * so anyone can read it: only a key with a spending limit (OpenRouter, a restricted project
19
- * key), or prefer a proxy that keeps it secret.
20
- */
21
- apiKey?: string;
22
16
  }
23
17
  /** Where the catalog falls back to when models.dev or OpenRouter cannot be reached. */
24
18
  export declare const DEFAULT_CATALOG_URL = "https://maxgfr.github.io/murmur/cdn/models.json";
25
19
  /** Settings calling the owner's proxy, or null when there is no (valid) proxy. */
26
20
  export declare function proxySettings(config: LlmConfig): LlmSettings | null;
27
- /** Settings that call the provider with the owner's key, or null when there is none. */
28
- export declare function ownerKeySettings(config: LlmConfig, catalogUrl?: string): Promise<LlmSettings | null>;
29
21
  export interface VisitorStoreOptions {
30
22
  /** Fallback catalog URL. Default {@link DEFAULT_CATALOG_URL}. */
31
23
  catalogUrl?: string;
@@ -31,10 +31,10 @@ export interface WidgetOptions {
31
31
  /** Open the panel on load. */
32
32
  open?: boolean;
33
33
  /**
34
- * How the widget answers. `auto` (default): the owner's proxy or key if set, else the model in
35
- * the visitor's browser with their own key as an option. `proxy`: only `llm.endpoint`. `local`:
36
- * only the in-browser model, no key settings. `key`: only a key, the owner's `llm.apiKey` or
37
- * else each visitor's own.
34
+ * How the widget answers, never with a key in the page. `auto` (default): the owner's proxy if
35
+ * set, else the model in the visitor's browser with their own key as an option. `proxy`: only
36
+ * `llm.endpoint`. `local`: only the in-browser model, no key settings. `key`: only each
37
+ * visitor's own key.
38
38
  */
39
39
  mode?: WidgetMode;
40
40
  /**
@@ -64,7 +64,7 @@ export interface LocalState {
64
64
  status: "idle" | "loading" | "ready" | "error";
65
65
  progress?: LoadProgress;
66
66
  }
67
- type Mode = "custom" | "local" | "owner" | "proxy" | "visitor";
67
+ type Mode = "custom" | "local" | "proxy" | "visitor";
68
68
  /** Everything the widget does except drawing: index, model settings, history. */
69
69
  export declare class ChatSession {
70
70
  readonly options: WidgetOptions;
@@ -78,8 +78,8 @@ export declare class ChatSession {
78
78
  constructor(options: WidgetOptions);
79
79
  private get configured();
80
80
  /**
81
- * How this session answers: your own model; then the owner's proxy, then the owner's key;
82
- * then the visitor's own key if they chose one; else the model in the browser.
81
+ * How this session answers: your own model; then the owner's proxy; then the visitor's own
82
+ * key if they chose one; else the model in the browser.
83
83
  */
84
84
  get mode(): Mode;
85
85
  /** Whether the in-browser model is offered at all. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "murmur-rag",
3
- "version": "1.3.1",
3
+ "version": "2.1.0",
4
4
  "description": "Embeddable AI chat for static sites: one script tag, a mini RAG over your own pages, any LLM through llm-connect (your proxy or the visitor's own key). No backend.",
5
5
  "author": "maxgfr",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- import{St,gt,kn,Ct,Tn}from"./embed-q81wdr1z.js";export{St as MAX_CHUNK,Ct as buildIndex,Tn as isMurmurIndex,kn as markdownSections,gt as slugify};