murmur-rag 1.1.0 → 1.3.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 +28 -19
- package/dist/cdn/{anthropic-dc7h9prc.js → anthropic-tw416spz.js} +2 -2
- package/dist/cdn/chunk-xyp6nm65.js +1 -0
- package/dist/cdn/{embed-fd96s8qk.js → embed-3am76qfd.js} +9 -9
- package/dist/cdn/embed-50pfy67v.js +83 -0
- package/dist/cdn/{embed-z32y952f.js → embed-cx1r66ch.js} +6 -6
- package/dist/cdn/{embed-ssqsb38w.js → embed-g0p6yc29.js} +2 -2
- package/dist/cdn/{embed-krrjjyf5.js → embed-q81wdr1z.js} +4 -4
- package/dist/cdn/embed-rjpq8psf.js +10 -0
- package/dist/cdn/{embed-acjpjh6t.js → embed-yz75savs.js} +3 -3
- package/dist/cdn/{google-yywkqdph.js → google-556tp13p.js} +8 -8
- package/dist/cdn/index-8r44b2wt.js +1 -0
- package/dist/cdn/index-a5j4aat5.js +1 -0
- package/dist/cdn/index-ft8r539a.js +1 -0
- package/dist/cdn/index-pjxy71n5.js +1 -0
- package/dist/cdn/{index-gyd02jvt.js → index-qpy1k923.js} +2 -2
- package/dist/cdn/mistral-25w1nsx5.js +3 -0
- package/dist/cdn/{murmur-j1ky5vmr.js → murmur-1a55et82.js} +3 -3
- package/dist/cdn/murmur.js +7 -7
- package/dist/cdn/openai-bjrbem49.js +18 -0
- package/dist/cdn/{openai-compatible-zhaj1r43.js → openai-compatible-sg25g0vj.js} +6 -6
- package/dist/cdn/retriever-06ybegpd.js +1 -0
- package/dist/cdn/{transformers.web-3kmbvcbt.js → transformers.web-49m0ht4a.js} +9 -9
- package/dist/lib/chunks/{index-92w507gk.js → index-4ftk20yq.js} +164 -50
- package/dist/lib/embed.js +10 -4
- package/dist/lib/llm/index.js +23 -0
- package/dist/lib/local/index.js +38 -2
- package/dist/lib/widget/index.js +2 -2
- package/dist/types/llm/index.d.ts +8 -0
- package/dist/types/local/index.d.ts +12 -0
- package/dist/types/widget/element.d.ts +4 -0
- package/dist/types/widget/i18n.d.ts +1 -0
- package/dist/types/widget/session.d.ts +56 -8
- package/dist/types/widget/styles.d.ts +1 -1
- package/package.json +1 -1
- package/dist/cdn/chunk-hpx6rpea.js +0 -1
- package/dist/cdn/embed-6gef7ym5.js +0 -10
- package/dist/cdn/embed-jdraznwg.js +0 -83
- package/dist/cdn/index-bq0x71h1.js +0 -1
- package/dist/cdn/index-jt6n0d28.js +0 -1
- package/dist/cdn/index-nesgnf2n.js +0 -1
- package/dist/cdn/index-wgzgvzaf.js +0 -1
- package/dist/cdn/mistral-0mg4kk7s.js +0 -3
- package/dist/cdn/openai-g1685z9v.js +0 -18
- package/dist/cdn/retriever-dqxzjaqk.js +0 -1
|
@@ -31,8 +31,24 @@ export interface WidgetOptions {
|
|
|
31
31
|
/** Open the panel on load. */
|
|
32
32
|
open?: boolean;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
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.
|
|
38
|
+
*/
|
|
39
|
+
mode?: WidgetMode;
|
|
40
|
+
/**
|
|
41
|
+
* When the in-browser model downloads (about 1.1 GB, once; then it loads from the browser's
|
|
42
|
+
* cache): `question` (default) on the first question, `open` when the panel opens, `idle` as
|
|
43
|
+
* soon as the page is idle, `consent` after the visitor agrees on a prompt. A model already in
|
|
44
|
+
* the cache is prepared in the background whatever this says, without network.
|
|
45
|
+
*/
|
|
46
|
+
preload?: Preload;
|
|
47
|
+
/**
|
|
48
|
+
* The model that runs in the visitor's browser on WebGPU, the default way to answer when there
|
|
49
|
+
* is no proxy: LFM3 1.7B, about 1.1 GB downloaded once after the visitor agrees. Visitors can
|
|
50
|
+
* still connect their own key in the AI settings. Pass your own spec to run another model, or
|
|
51
|
+
* `false` to offer only the visitor's key.
|
|
36
52
|
*/
|
|
37
53
|
local?: boolean | LocalModelSpec;
|
|
38
54
|
}
|
|
@@ -41,7 +57,14 @@ export interface ChatTurn extends Turn {
|
|
|
41
57
|
cited?: number[];
|
|
42
58
|
error?: string;
|
|
43
59
|
}
|
|
44
|
-
type
|
|
60
|
+
export type WidgetMode = "auto" | "proxy" | "local" | "key";
|
|
61
|
+
export type Preload = "question" | "open" | "idle" | "consent";
|
|
62
|
+
/** Where the in-browser model is: not started, downloading or compiling, ready, or failed. */
|
|
63
|
+
export interface LocalState {
|
|
64
|
+
status: "idle" | "loading" | "ready" | "error";
|
|
65
|
+
progress?: LoadProgress;
|
|
66
|
+
}
|
|
67
|
+
type Mode = "custom" | "local" | "owner" | "proxy" | "visitor";
|
|
45
68
|
/** Everything the widget does except drawing: index, model settings, history. */
|
|
46
69
|
export declare class ChatSession {
|
|
47
70
|
readonly options: WidgetOptions;
|
|
@@ -50,16 +73,41 @@ export declare class ChatSession {
|
|
|
50
73
|
private storePromise;
|
|
51
74
|
private readonly historyKey;
|
|
52
75
|
private readonly key;
|
|
53
|
-
|
|
54
|
-
|
|
76
|
+
private local;
|
|
77
|
+
private readonly localListeners;
|
|
55
78
|
constructor(options: WidgetOptions);
|
|
79
|
+
private get configured();
|
|
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.
|
|
83
|
+
*/
|
|
56
84
|
get mode(): Mode;
|
|
85
|
+
/** Whether the in-browser model is offered at all. */
|
|
86
|
+
get localAllowed(): boolean;
|
|
87
|
+
/** Whether visitors may connect their own key (the AI settings). */
|
|
88
|
+
get keyAllowed(): boolean;
|
|
89
|
+
/** Where the in-browser model is, and a way to follow it. */
|
|
90
|
+
get localState(): LocalState;
|
|
91
|
+
onLocalState(listener: (state: LocalState) => void): () => void;
|
|
92
|
+
private setLocal;
|
|
93
|
+
/**
|
|
94
|
+
* Starts loading the in-browser model now, in the background: downloads it if needed, then
|
|
95
|
+
* compiles it. Does nothing outside the local mode or without WebGPU. Safe to call often.
|
|
96
|
+
*/
|
|
97
|
+
warmUp(): Promise<void>;
|
|
98
|
+
/** A model already in the browser's cache is prepared right away: no network, no prompt. */
|
|
99
|
+
warmUpIfCached(): Promise<void>;
|
|
100
|
+
get preload(): Preload;
|
|
101
|
+
/**
|
|
102
|
+
* Before a question: a visitor who saved a key before the in-browser model became the default,
|
|
103
|
+
* and never chose between the two, keeps their key.
|
|
104
|
+
*/
|
|
105
|
+
settleChoice(): Promise<void>;
|
|
57
106
|
/** The in-browser model this session would run. */
|
|
58
107
|
localSpec(): Promise<LocalModelSpec>;
|
|
59
|
-
|
|
60
|
-
/** The visitor picks the in-browser model (or goes back to a key). */
|
|
108
|
+
/** The visitor picks the in-browser model, or their own key. */
|
|
61
109
|
useLocal(on: boolean): void;
|
|
62
|
-
/** Whether the visitor must still agree to download the in-browser model. */
|
|
110
|
+
/** Whether the visitor must still agree to download the in-browser model (`preload: "consent"`). */
|
|
63
111
|
get needsDownloadConsent(): boolean;
|
|
64
112
|
agreeToDownload(): void;
|
|
65
113
|
persist(): void;
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* custom properties on the element: --murmur-accent, --murmur-accent-ink, --murmur-font,
|
|
4
4
|
* --murmur-radius, --murmur-z.
|
|
5
5
|
*/
|
|
6
|
-
export declare const STYLES = "\n:host {\n --accent: var(--murmur-accent, #211c17);\n --accent-ink: var(--murmur-accent-ink, #f6efe0);\n --lamp: var(--murmur-lamp, #e0a032);\n --surface: #fbf8f1;\n --raised: #f2ece0;\n --ink: #211c17;\n --muted: #675c4f;\n --line: #e2d8c5;\n --focus: #b4541d;\n --danger: #a1301f;\n --radius: var(--murmur-radius, 16px);\n --shadow: 0 18px 48px -12px rgb(33 28 23 / 0.28), 0 4px 12px -4px rgb(33 28 23 / 0.16);\n --ease: cubic-bezier(0.16, 1, 0.3, 1);\n all: initial;\n position: fixed;\n z-index: var(--murmur-z, 2147483000);\n inset: auto 20px 20px auto;\n font-family: var(--murmur-font, inherit);\n font-size: 15px;\n line-height: 1.5;\n color: var(--ink);\n color-scheme: light;\n -webkit-font-smoothing: antialiased;\n}\n:host([position=\"bottom-left\"]) { inset: auto auto 20px 20px; }\n:host([inline]) { position: relative; inset: auto; z-index: auto; display: block; height: 100%; }\n:host([theme=\"dark\"]) { --surface: #1c1814; --raised: #26211b; --ink: #f2ead9; --muted: #b8ab95; --line: #3b342b; --focus: #f0a35c; --danger: #f08a73; color-scheme: dark; }\n@media (prefers-color-scheme: dark) {\n :host(:not([theme=\"light\"])) { --surface: #1c1814; --raised: #26211b; --ink: #f2ead9; --muted: #b8ab95; --line: #3b342b; --focus: #f0a35c; --danger: #f08a73; color-scheme: dark; }\n :host(:not([theme=\"light\"])) { --murmur-accent-default: #f2ead9; }\n}\n@media print { :host { display: none !important; } }\n* { box-sizing: border-box; }\n[hidden] { display: none !important; }\n::selection { background: color-mix(in oklab, var(--lamp) 45%, transparent); color: inherit; }\nbutton, input, select, textarea { font: inherit; color: inherit; }\nbutton { cursor: pointer; }\n:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }\na { color: inherit; text-underline-offset: 0.2em; text-decoration-thickness: 1px; }\n\n/* Launcher */\n.launcher {\n display: inline-flex; align-items: center; gap: 10px;\n height: 52px; padding: 0 20px 0 16px; border: 0; border-radius: 26px;\n background: var(--accent); color: var(--accent-ink);\n box-shadow: var(--shadow); font-weight: 600; letter-spacing: 0.01em;\n transition: transform 220ms var(--ease), box-shadow 220ms var(--ease);\n}\n.launcher:hover { transform: translateY(-2px); }\n.launcher:active { transform: translateY(0); }\n.launcher[aria-expanded=\"true\"] { display: none; }\n.lamp {\n width: 8px; height: 8px; border-radius: 50%; flex: none;\n background: var(--lamp); box-shadow: 0 0 0 3px color-mix(in oklab, var(--lamp) 28%, transparent);\n}\n.lamp.off { background: transparent; box-shadow: inset 0 0 0 1.5px var(--muted); }\n.lamp.busy { animation: blink 1.1s steps(2, jump-none) infinite; }\n@keyframes blink { 50% { opacity: 0.25; } }\n\n/* Panel */\n.panel {\n position: absolute; right: 0; bottom: 0;\n display: flex; flex-direction: column;\n width: min(400px, calc(100vw - 40px)); height: min(640px, calc(100dvh - 40px));\n background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow);\n overflow: hidden; transform-origin: bottom right;\n animation: rise 320ms var(--ease);\n}\n:host([position=\"bottom-left\"]) .panel { right: auto; left: 0; transform-origin: bottom left; }\n:host([inline]) .panel { position: static; width: 100%; height: 100%; box-shadow: none; animation: none; border-radius: inherit; }\n@keyframes rise { from { opacity: 0; transform: translateY(12px) scale(0.98); } }\n@media (max-width: 480px) {\n :host(:not([inline])) { inset: auto 12px 12px auto; }\n :host(:not([inline])[position=\"bottom-left\"]) { inset: auto auto 12px 12px; }\n :host(:not([inline])) .panel { position: fixed; inset: 0; width: 100%; height: 100dvh; border-radius: 0; }\n}\n\nheader {\n display: flex; align-items: center; gap: 10px;\n padding: 14px 10px 14px 18px; background: var(--accent); color: var(--accent-ink);\n}\nheader h2 { flex: 1; margin: 0; font-size: 16px; font-weight: 650; letter-spacing: 0.005em; line-height: 1.25; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.icon-btn {\n display: inline-grid; place-items: center; width: 36px; height: 36px; flex: none;\n border: 0; border-radius: 10px; background: transparent; color: inherit;\n transition: background 160ms;\n}\n.icon-btn:hover { background: color-mix(in oklab, currentColor 14%, transparent); }\nheader .icon-btn:focus-visible { outline-color: var(--accent-ink); }\n\n/* Conversation */\n.log {\n flex: 1; overflow-y: auto; overscroll-behavior: contain;\n padding: 18px 18px 8px; display: flex; flex-direction: column; gap: 16px;\n scrollbar-width: thin; scrollbar-color: var(--line) transparent;\n}\n.msg { max-width: 100%; overflow-wrap: anywhere; }\n.msg p { margin: 0 0 0.6em; }\n.msg p:last-child { margin-bottom: 0; }\n.msg ul, .msg ol { margin: 0 0 0.6em; padding-left: 1.3em; }\n.msg li + li { margin-top: 0.2em; }\n.msg code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.88em; background: var(--raised); padding: 0.1em 0.35em; border-radius: 5px; }\n.msg pre { margin: 0 0 0.6em; padding: 10px 12px; background: var(--raised); border-radius: 10px; overflow-x: auto; }\n.msg pre code { background: none; padding: 0; }\n.msg .table { margin: 0 0 0.6em; overflow-x: auto; border-radius: 10px; box-shadow: inset 0 0 0 1px var(--line); }\n.msg table { width: 100%; border-collapse: collapse; font-size: 14px; }\n.msg th, .msg td { padding: 6px 10px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--line); }\n.msg tr:last-child td { border-bottom: 0; }\n.msg th { font-weight: 650; background: var(--raised); }\n.msg blockquote { margin: 0 0 0.6em; padding: 2px 0 2px 12px; color: var(--muted); box-shadow: inset 1px 0 0 var(--line); }\n.msg hr { margin: 0.8em 0; border: 0; border-top: 1px solid var(--line); }\n.user {\n align-self: flex-end; max-width: 85%;\n padding: 9px 14px; border-radius: 16px 16px 4px 16px;\n background: var(--accent); color: var(--accent-ink); white-space: pre-wrap;\n}\n.bot { align-self: stretch; }\n.greeting { color: var(--muted); }\n\n.cite {\n display: inline-grid; place-items: center; min-width: 1.45em; height: 1.45em; padding: 0 0.3em;\n margin: 0 0.1em; vertical-align: 0.12em;\n border-radius: 1em; box-shadow: inset 0 0 0 1.25px currentColor;\n font-size: 0.72em; font-weight: 700; line-height: 1; text-decoration: none;\n font-variant-numeric: tabular-nums; color: var(--muted);\n transition: background 160ms, color 160ms;\n}\n.cite:hover, .cite:focus-visible { background: var(--lamp); color: #211c17; box-shadow: none; }\n\n.sources { margin: 12px 0 0; padding: 0; list-style: none; display: grid; gap: 2px; }\n.sources-label { margin: 18px 0 2px; font-size: 12px; font-weight: 650; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }\n.sources a {\n display: grid; grid-template-columns: auto 1fr; align-items: baseline; gap: 10px;\n padding: 7px 10px; margin: 0 -10px; border-radius: 10px; text-decoration: none;\n}\n.sources a:hover { background: var(--raised); }\n.sources .cite { margin: 0; }\n.sources .where { min-width: 0; font-size: 14px; line-height: 1.35; }\n.sources .where span { color: var(--muted); }\n\n.status { display: flex; align-items: center; gap: 10px; color: var(--muted); font-size: 14px; }\n.error { color: var(--danger); }\n.error p { margin: 0 0 8px; }\n.text-btn {\n display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 9px;\n border: 0; background: var(--raised); color: var(--ink); font-size: 14px; font-weight: 600;\n}\n.text-btn:hover { background: var(--line); }\n\n/* Composer */\nform.composer {\n display: flex; align-items: flex-end; gap: 8px; margin: 8px 12px 0; padding: 6px 6px 6px 14px;\n border-radius: 14px; background: var(--raised);\n box-shadow: inset 0 0 0 1px var(--line); transition: box-shadow 160ms;\n}\nform.composer:focus-within { box-shadow: inset 0 0 0 1.5px var(--focus); }\ntextarea {\n flex: 1; min-height: 38px; max-height: 140px; padding: 8px 0; resize: none;\n border: 0; background: transparent; outline: none; line-height: 1.4;\n}\ntextarea:focus-visible { outline: none; }\ntextarea::placeholder, input::placeholder { color: var(--muted); opacity: 1; }\n.send {\n display: inline-grid; place-items: center; width: 38px; height: 38px; flex: none;\n border: 0; border-radius: 10px; background: var(--accent); color: var(--accent-ink);\n transition: opacity 160ms;\n}\n.send:disabled { opacity: 0.35; cursor: default; }\nfooter { padding: 8px 18px 12px; font-size: 12px; color: var(--muted); text-align: center; }\nfooter a { text-decoration: none; }\nfooter a:hover { text-decoration: underline; }\n\n/* Settings */\n.setup { flex: 1; overflow-y: auto; padding: 18px; display: grid; gap: 16px; align-content: start; }\n.setup p.intro { margin: 0; color: var(--muted); font-size: 14px; }\n.field { display: grid; gap: 6px; }\n.field > span { font-size: 13px; font-weight: 650; }\n.field small { color: var(--muted); font-size: 12.5px; }\n.field input:not([type=\"checkbox\"]), .field select {\n width: 100%; height: 40px; padding: 0 12px; border-radius: 10px;\n border: 0; background: var(--raised); box-shadow: inset 0 0 0 1px var(--line);\n}\n.field input:focus-visible, .field select:focus-visible { outline: none; box-shadow: inset 0 0 0 1.5px var(--focus); }\n.check { display: flex; align-items: center; gap: 10px; font-size: 14px; }\n.check input { width: 18px; height: 18px; accent-color: var(--accent); margin: 0; }\n.presets { display: flex; gap: 8px; flex-wrap: wrap; }\n.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }\n.primary {\n display: inline-flex; align-items: center; justify-content: center; gap: 8px;\n height: 42px; padding: 0 18px; border: 0; border-radius: 11px;\n background: var(--accent); color: var(--accent-ink); font-weight: 650;\n}\n.primary:disabled { opacity: 0.4; cursor: default; }\n.result { font-size: 14px; }\n.result.ok { color: inherit; }\n.result.ok::before { content: \"\"; display: inline-block; width: 8px; height: 8px; margin-right: 8px; border-radius: 50%; background: var(--lamp); }\n.result.fail { color: var(--danger); }\n.local-choice { display: grid; gap: 6px; padding: 14px; border-radius: 12px; background: var(--raised); }\n.local-choice small { color: var(--muted); font-size: 12.5px; }\n.local-choice .link-btn { margin-top: 2px; }\np.or { margin: 0; color: var(--muted); font-size: 13px; text-align: center; }\n.consent { display: grid; gap: 10px; padding: 14px; border-radius: 12px; background: var(--raised); }\n.consent p { margin: 0; }\n.status .grow { display: grid; gap: 6px; flex: 1; }\nprogress { width: 100%; height: 6px; appearance: none; border: 0; border-radius: 3px; background: var(--line); overflow: hidden; }\nprogress::-webkit-progress-bar { background: var(--line); }\nprogress::-webkit-progress-value { background: var(--lamp); }\nprogress::-moz-progress-bar { background: var(--lamp); }\n.link-btn { padding: 0; border: 0; background: none; color: var(--muted); font-size: 13px; text-decoration: underline; text-underline-offset: 0.2em; justify-self: start; }\n\n.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }\n\n@media (prefers-reduced-motion: reduce) {\n *, .panel { animation: none !important; transition: none !important; }\n}\n";
|
|
6
|
+
export declare const STYLES = "\n:host {\n --accent: var(--murmur-accent, #211c17);\n --accent-ink: var(--murmur-accent-ink, #f6efe0);\n --lamp: var(--murmur-lamp, #e0a032);\n --surface: #fbf8f1;\n --raised: #f2ece0;\n --ink: #211c17;\n --muted: #675c4f;\n --line: #e2d8c5;\n --focus: #b4541d;\n --danger: #a1301f;\n --radius: var(--murmur-radius, 16px);\n --shadow: 0 18px 48px -12px rgb(33 28 23 / 0.28), 0 4px 12px -4px rgb(33 28 23 / 0.16);\n --ease: cubic-bezier(0.16, 1, 0.3, 1);\n all: initial;\n position: fixed;\n z-index: var(--murmur-z, 2147483000);\n inset: auto 20px 20px auto;\n font-family: var(--murmur-font, inherit);\n font-size: 15px;\n line-height: 1.5;\n color: var(--ink);\n color-scheme: light;\n -webkit-font-smoothing: antialiased;\n}\n:host([position=\"bottom-left\"]) { inset: auto auto 20px 20px; }\n:host([inline]) { position: relative; inset: auto; z-index: auto; display: block; height: 100%; }\n:host([theme=\"dark\"]) { --surface: #1c1814; --raised: #26211b; --ink: #f2ead9; --muted: #b8ab95; --line: #3b342b; --focus: #f0a35c; --danger: #f08a73; color-scheme: dark; }\n@media (prefers-color-scheme: dark) {\n :host(:not([theme=\"light\"])) { --surface: #1c1814; --raised: #26211b; --ink: #f2ead9; --muted: #b8ab95; --line: #3b342b; --focus: #f0a35c; --danger: #f08a73; color-scheme: dark; }\n :host(:not([theme=\"light\"])) { --murmur-accent-default: #f2ead9; }\n}\n@media print { :host { display: none !important; } }\n* { box-sizing: border-box; }\n[hidden] { display: none !important; }\n::selection { background: color-mix(in oklab, var(--lamp) 45%, transparent); color: inherit; }\nbutton, input, select, textarea { font: inherit; color: inherit; }\nbutton { cursor: pointer; }\n:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }\na { color: inherit; text-underline-offset: 0.2em; text-decoration-thickness: 1px; }\n\n/* Launcher */\n.launcher {\n display: inline-flex; align-items: center; gap: 10px;\n height: 52px; padding: 0 20px 0 16px; border: 0; border-radius: 26px;\n background: var(--accent); color: var(--accent-ink);\n box-shadow: var(--shadow); font-weight: 600; letter-spacing: 0.01em;\n transition: transform 220ms var(--ease), box-shadow 220ms var(--ease);\n}\n.launcher:hover { transform: translateY(-2px); }\n.launcher:active { transform: translateY(0); }\n.launcher[aria-expanded=\"true\"] { display: none; }\n.lamp {\n width: 8px; height: 8px; border-radius: 50%; flex: none;\n background: var(--lamp); box-shadow: 0 0 0 3px color-mix(in oklab, var(--lamp) 28%, transparent);\n}\n.lamp.off { background: transparent; box-shadow: inset 0 0 0 1.5px var(--muted); }\n.lamp.busy { animation: blink 1.1s steps(2, jump-none) infinite; }\n@keyframes blink { 50% { opacity: 0.25; } }\n\n/* Panel */\n.panel {\n position: absolute; right: 0; bottom: 0;\n display: flex; flex-direction: column;\n width: min(400px, calc(100vw - 40px)); height: min(640px, calc(100dvh - 40px));\n background: var(--surface); border-radius: var(--radius); box-shadow: var(--shadow);\n overflow: hidden; transform-origin: bottom right;\n animation: rise 320ms var(--ease);\n}\n:host([position=\"bottom-left\"]) .panel { right: auto; left: 0; transform-origin: bottom left; }\n:host([inline]) .panel { position: static; width: 100%; height: 100%; box-shadow: none; animation: none; border-radius: inherit; }\n@keyframes rise { from { opacity: 0; transform: translateY(12px) scale(0.98); } }\n@media (max-width: 480px) {\n :host(:not([inline])) { inset: auto 12px 12px auto; }\n :host(:not([inline])[position=\"bottom-left\"]) { inset: auto auto 12px 12px; }\n :host(:not([inline])) .panel { position: fixed; inset: 0; width: 100%; height: 100dvh; border-radius: 0; }\n}\n\nheader {\n display: flex; align-items: center; gap: 10px;\n padding: 14px 10px 14px 18px; background: var(--accent); color: var(--accent-ink);\n}\nheader h2 { flex: 1; margin: 0; font-size: 16px; font-weight: 650; letter-spacing: 0.005em; line-height: 1.25; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.icon-btn {\n display: inline-grid; place-items: center; width: 36px; height: 36px; flex: none;\n border: 0; border-radius: 10px; background: transparent; color: inherit;\n transition: background 160ms;\n}\n.icon-btn:hover { background: color-mix(in oklab, currentColor 14%, transparent); }\nheader .icon-btn:focus-visible { outline-color: var(--accent-ink); }\n\n/* Conversation */\n.log {\n flex: 1; overflow-y: auto; overscroll-behavior: contain;\n padding: 18px 18px 8px; display: flex; flex-direction: column; gap: 16px;\n scrollbar-width: thin; scrollbar-color: var(--line) transparent;\n}\n.msg { max-width: 100%; overflow-wrap: anywhere; }\n.msg p { margin: 0 0 0.6em; }\n.msg p:last-child { margin-bottom: 0; }\n.msg ul, .msg ol { margin: 0 0 0.6em; padding-left: 1.3em; }\n.msg li + li { margin-top: 0.2em; }\n.msg code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.88em; background: var(--raised); padding: 0.1em 0.35em; border-radius: 5px; }\n.msg pre { margin: 0 0 0.6em; padding: 10px 12px; background: var(--raised); border-radius: 10px; overflow-x: auto; }\n.msg pre code { background: none; padding: 0; }\n.msg .table { margin: 0 0 0.6em; overflow-x: auto; border-radius: 10px; box-shadow: inset 0 0 0 1px var(--line); }\n.msg table { width: 100%; border-collapse: collapse; font-size: 14px; }\n.msg th, .msg td { padding: 6px 10px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--line); }\n.msg tr:last-child td { border-bottom: 0; }\n.msg th { font-weight: 650; background: var(--raised); }\n.msg blockquote { margin: 0 0 0.6em; padding: 2px 0 2px 12px; color: var(--muted); box-shadow: inset 1px 0 0 var(--line); }\n.msg hr { margin: 0.8em 0; border: 0; border-top: 1px solid var(--line); }\n.user {\n align-self: flex-end; max-width: 85%;\n padding: 9px 14px; border-radius: 16px 16px 4px 16px;\n background: var(--accent); color: var(--accent-ink); white-space: pre-wrap;\n}\n.bot { align-self: stretch; }\n.greeting { color: var(--muted); }\n\n.cite {\n display: inline-grid; place-items: center; min-width: 1.45em; height: 1.45em; padding: 0 0.3em;\n margin: 0 0.1em; vertical-align: 0.12em;\n border-radius: 1em; box-shadow: inset 0 0 0 1.25px currentColor;\n font-size: 0.72em; font-weight: 700; line-height: 1; text-decoration: none;\n font-variant-numeric: tabular-nums; color: var(--muted);\n transition: background 160ms, color 160ms;\n}\n.cite:hover, .cite:focus-visible { background: var(--lamp); color: #211c17; box-shadow: none; }\n\n.sources { margin: 12px 0 0; padding: 0; list-style: none; display: grid; gap: 2px; }\n.sources-label { margin: 18px 0 2px; font-size: 12px; font-weight: 650; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }\n.sources a {\n display: grid; grid-template-columns: auto 1fr; align-items: baseline; gap: 10px;\n padding: 7px 10px; margin: 0 -10px; border-radius: 10px; text-decoration: none;\n}\n.sources a:hover { background: var(--raised); }\n.sources .cite { margin: 0; }\n.sources .where { min-width: 0; font-size: 14px; line-height: 1.35; }\n.sources .where span { color: var(--muted); }\n\n.status { display: flex; align-items: center; gap: 10px; color: var(--muted); font-size: 14px; }\n.error { color: var(--danger); }\n.error p { margin: 0 0 8px; }\n.text-btn {\n display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 9px;\n border: 0; background: var(--raised); color: var(--ink); font-size: 14px; font-weight: 600;\n}\n.text-btn:hover { background: var(--line); }\n\n/* Composer */\nform.composer {\n display: flex; align-items: flex-end; gap: 8px; margin: 8px 12px 0; padding: 6px 6px 6px 14px;\n border-radius: 14px; background: var(--raised);\n box-shadow: inset 0 0 0 1px var(--line); transition: box-shadow 160ms;\n}\nform.composer:focus-within { box-shadow: inset 0 0 0 1.5px var(--focus); }\ntextarea {\n flex: 1; min-height: 38px; max-height: 140px; padding: 8px 0; resize: none;\n border: 0; background: transparent; outline: none; line-height: 1.4;\n}\ntextarea:focus-visible { outline: none; }\ntextarea::placeholder, input::placeholder { color: var(--muted); opacity: 1; }\n.send {\n display: inline-grid; place-items: center; width: 38px; height: 38px; flex: none;\n border: 0; border-radius: 10px; background: var(--accent); color: var(--accent-ink);\n transition: opacity 160ms;\n}\n.send:disabled { opacity: 0.35; cursor: default; }\nfooter { padding: 8px 18px 12px; font-size: 12px; color: var(--muted); text-align: center; }\nfooter a { text-decoration: none; }\nfooter a:hover { text-decoration: underline; }\n\n/* Settings */\n.setup { flex: 1; overflow-y: auto; padding: 18px; display: grid; gap: 16px; align-content: start; }\n.setup p.intro { margin: 0; color: var(--muted); font-size: 14px; }\n.field { display: grid; gap: 6px; }\n.field > span { font-size: 13px; font-weight: 650; }\n.field small { color: var(--muted); font-size: 12.5px; }\n.field input:not([type=\"checkbox\"]), .field select {\n width: 100%; height: 40px; padding: 0 12px; border-radius: 10px;\n border: 0; background: var(--raised); box-shadow: inset 0 0 0 1px var(--line);\n}\n.field input:focus-visible, .field select:focus-visible { outline: none; box-shadow: inset 0 0 0 1.5px var(--focus); }\n.check { display: flex; align-items: center; gap: 10px; font-size: 14px; }\n.check input { width: 18px; height: 18px; accent-color: var(--accent); margin: 0; }\n.presets { display: flex; gap: 8px; flex-wrap: wrap; }\n.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }\n.primary {\n display: inline-flex; align-items: center; justify-content: center; gap: 8px;\n height: 42px; padding: 0 18px; border: 0; border-radius: 11px;\n background: var(--accent); color: var(--accent-ink); font-weight: 650;\n}\n.primary:disabled { opacity: 0.4; cursor: default; }\n.result { font-size: 14px; }\n.result.ok { color: inherit; }\n.result.ok::before { content: \"\"; display: inline-block; width: 8px; height: 8px; margin-right: 8px; border-radius: 50%; background: var(--lamp); }\n.result.fail { color: var(--danger); }\n.local-choice { display: grid; gap: 6px; padding: 14px; border-radius: 12px; background: var(--raised); }\n.local-choice small { color: var(--muted); font-size: 12.5px; }\n.local-choice .link-btn { margin-top: 2px; }\np.or { margin: 0; color: var(--muted); font-size: 13px; text-align: center; }\n.consent { display: grid; gap: 10px; padding: 14px; border-radius: 12px; background: var(--raised); }\n.consent p { margin: 0; }\n.loadbar { display: grid; gap: 6px; margin: 4px 12px 0; padding: 8px 12px; border-radius: 10px; background: var(--raised); color: var(--muted); font-size: 13px; }\nprogress { width: 100%; height: 6px; appearance: none; border: 0; border-radius: 3px; background: var(--line); overflow: hidden; }\nprogress::-webkit-progress-bar { background: var(--line); }\nprogress::-webkit-progress-value { background: var(--lamp); }\nprogress::-moz-progress-bar { background: var(--lamp); }\n.link-btn { padding: 0; border: 0; background: none; color: var(--muted); font-size: 13px; text-decoration: underline; text-underline-offset: 0.2em; justify-self: start; }\n\n.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }\n\n@media (prefers-reduced-motion: reduce) {\n *, .panel { animation: none !important; transition: none !important; }\n}\n";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "murmur-rag",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.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{kt,mt,wn,Tt,vn}from"./embed-krrjjyf5.js";export{kt as MAX_CHUNK,Tt as buildIndex,vn as isMurmurIndex,wn as markdownSections,mt as slugify};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import{F}from"./embed-z32y952f.js";var re=["@ai-sdk/anthropic","@ai-sdk/google","@ai-sdk/mistral","@ai-sdk/openai","@ai-sdk/openai-compatible"];function K(e){if(!e)return;if(e.defaultModel&&e.models[e.defaultModel])return e.defaultModel;return Object.keys(e.models)[0]}function ne(e,t=""){if(!e)return[];let r=Object.values(e.models),n=t.trim().toLowerCase();if(!n)return r;return r.filter((i)=>i.name.toLowerCase().includes(n)||i.id.toLowerCase().includes(n))}var se="llm-connect-catalog",ce=3600000;var Ke=["content-type","etag","last-modified"];function Fe(){try{return globalThis.caches}catch{return}}function Ge(e){let t=globalThis.location;if(!t)return!0;try{return new URL(e,t.href).origin===t.origin}catch{return!1}}function He(e){if(typeof e==="string")return e;if(e instanceof URL)return e.href;return e.url}function ae(e){if(!e?.aborted)return!1;return e.reason?.name!=="TimeoutError"}async function ie(e,t,r,n){let i=new Headers({["x-llm-connect-stored-at"]:String(Date.now())});for(let l of Ke){let d=n.get(l);if(d)i.set(l,d)}try{await e.put(t,new Response(r,{headers:i}))}catch{}return new Response(r,{status:200,headers:i})}function le(e={}){let{cacheName:t="llm-connect-catalog",ttlMs:r=3600000}=e,n=(d,f)=>(e.fetch??globalThis.fetch)(d,f),i,l=()=>(i??=(async()=>{let d=e.caches??Fe();if(!d)return null;try{return await d.open(t)}catch{return null}})(),i);return async(d,f)=>{let m=(f?.method??(d instanceof Request?d.method:"GET")).toUpperCase()==="GET"?await l():null;if(!m)return n(d,f);let p=He(d),c=await m.match(p).catch(()=>{return}),h=Number(c?.headers.get("x-llm-connect-stored-at"));if(c&&Date.now()-h<r)return c;let b=new Headers(f?.headers),w=c?.headers.get("etag");if(w&&Ge(p))b.set("If-None-Match",w);let E;try{E=await n(p,{...f,headers:b})}catch(a){if(c&&!ae(f?.signal))return c;throw a}if(c&&E.status===304)return ie(m,p,await c.text(),c.headers);if(!E.ok)return c??E;let o;try{o=await E.text()}catch(a){if(c&&!ae(f?.signal))return c;throw a}return ie(m,p,o,E.headers)}}var Re=["openai","anthropic","google","mistral"],B=new Map;function M(e,t=globalThis.fetch){let r=B.get(e);if(!r)r=t(e).then((n)=>{if(!n.ok)throw Error(`Model list unavailable (${n.status})`);return n.json()}).catch((n)=>{throw B.delete(e),n}),B.set(e,r);return r}async function qe(e){let{buildSlimCatalog:t}=await (F("t87kf8t0"),import("./browser-t87kf8t0.js"));return t(e)}function ft(e={}){let{fallbackUrl:t,npm:r=re,required:n,build:i=qe,cacheName:l=se,cacheTtlMs:d=ce}=e,f=(c,h)=>(e.fetch??globalThis.fetch)(c,h),u=l===!1?f:le({cacheName:l,ttlMs:d,fetch:f,...e.cacheStorage?{caches:e.cacheStorage}:{}}),m=null;async function p(){try{let c=await i({npm:r,...n?{required:n}:{},fetch:u});if(Object.keys(c).length===0)throw Error("Empty catalog");return c}catch(c){if(!t)throw c;return M(t,e.fetch)}}return()=>{if(!m)m=p().catch((c)=>{throw m=null,c});return m}}function G(e,t){if(!e)return{recommended:[],others:[]};let r=t.map((i)=>e[i]).filter((i)=>!!i),n=Object.values(e).filter((i)=>!t.includes(i.id)).sort((i,l)=>i.name.localeCompare(l.name));return{recommended:r,others:n}}var H={providerId:"openai",providerName:"OpenAI",providerNpm:"@ai-sdk/openai",providerApi:"https://api.openai.com/v1"};function q(e,t){let r=e?.[t];if(!r)return null;return{providerId:r.id,providerName:r.name,providerNpm:r.npm,providerApi:r.api??""}}var R={authentication_error:"auth",permission_error:"auth",rate_limit_error:"rate-limit",overloaded_error:"overloaded",api_error:"server",not_found_error:"not-found",invalid_request_error:"invalid-request",request_too_large:"invalid-request",context_length_exceeded:"context-length",insufficient_quota:"rate-limit"},je=/prompt is too long|context[ _-]?length|context window|maximum context|too many (input )?tokens|input is too long|exceeds the model'?s? (maximum|context)/i,We=/api key not valid|invalid api key|incorrect api key|invalid x-api-key/i,$e=/failed to fetch|fetch failed|networkerror|network error|load failed|cannot connect|network connection/i,Je=new Set(["auth-or-network","rate-limit","overloaded","server"]);function T(e,t){let r=e;if(t&&t.length>=4)r=r.split(t).join("***");return r.length>500?`${r.slice(0,500)}…`:r}function S(e){return typeof e==="object"&&e!==null}function ue(e,t){if(!S(e))return!1;return e[Symbol.for(`vercel.ai.error.${t}`)]===!0}var y=(e)=>typeof e==="string"&&e.length>0?e:void 0;function Ve(e){let t=Array.isArray(e)?e[0]:e;if(!S(t))return{};let r=S(t.error)?t.error:t,n=y(r.message)??y(r.msg)??y(t.message)??y(t.msg)??(typeof t.error==="string"?t.error:void 0);return{type:y(r.type)??y(r.status),code:y(r.code),message:n}}var Ye=["choices","content","candidates","output","data","models"];function j(e){let t=typeof e==="string"?Number(e):e;return typeof t==="number"&&Number.isInteger(t)&&t>=400&&t<=599?t:void 0}function L(e){let t=Array.isArray(e)&&e.length===1?e[0]:e;if(!S(t)||Array.isArray(t))return null;if(Ye.some((l)=>t[l]!==void 0))return null;let r=S(t.error)?t.error:void 0,n=y(t.msg)!==void 0||y(t.message)!==void 0;if(!(r!==void 0||y(t.error)!==void 0||t.type==="error"||t.success===!1||j(t.code)!==void 0&&n))return null;return j(t.code)??j(r?.code)??502}function ze(e){if(typeof e!=="string"||!e)return;try{return JSON.parse(e)}catch{return}}function Xe(e,t){let r=t.code&&R[t.code]||t.type&&R[t.type]||void 0;if(r==="context-length"||je.test(t.message)){if(e===400||e===413||e===422||r==="context-length")return"context-length"}if(e===401||e===403)return"auth";if(e===429)return r==="overloaded"?"overloaded":"rate-limit";if(e===529||e===503||r==="overloaded")return"overloaded";if(e===404)return"not-found";if(e>=500)return"server";if(e===400||e===413||e===422)return r==="auth"||We.test(t.message)?"auth":"invalid-request";return r??"unknown"}function O(e,t,r,n){return{code:e,message:T(t,r),...n===void 0?{}:{status:n},retryable:Je.has(e)}}function Ze(e){let t=e;for(let r=0;r<5&&t instanceof Error;r++){if($e.test(t.message))return!0;t=t.cause}return!1}function De(e,t){if(ue(e,"AI_RetryError")&&S(e)&&e.lastError!==void 0)return De(e.lastError,t);if(S(e)){let r=ue(e,"AI_APICallError"),n=r?ze(e.responseBody):void 0,i=Ve(e.data??n),l=y(e.type)??i.type,d=y(e.code)??i.code,f=typeof e.statusCode==="number"?e.statusCode:void 0,u=i.message??y(e.message)??"";if(f!==void 0)return O(Xe(f,{type:l,code:d,message:u}),u,t,r?f:void 0);let m=l&&R[l]||d&&R[d]||void 0;if(m)return O(m,u,t)}if(Ze(e))return O("auth-or-network",e instanceof Error?e.message:"",t);return O("unknown",e instanceof Error?e.message:String(e),t)}var de=Symbol.for("llm-connect.registry"),fe=globalThis;fe[de]??=new Map;var W=fe[de],et={"@ai-sdk/openai":"openai","@ai-sdk/anthropic":"anthropic","@ai-sdk/google":"google","@ai-sdk/mistral":"mistral","@ai-sdk/openai-compatible":"openai-compatible"};function v(e){return et[e]??e}function oe(e,t){W.set(v(e),t)}var C="https://api.openai.com/v1";function tt(e){return e.trim().replace(/\/+$/,"")===C}function Ie(e){return(t)=>{let r=e({apiKey:t.apiKey,...t.baseURL&&{baseURL:t.baseURL},...t.headers&&{headers:t.headers},...t.fetch&&{fetch:t.fetch}});if(t.baseURL&&!tt(t.baseURL)&&typeof r.chat==="function")return r.chat(t.model);return r(t.model)}}function me(e){return W.has(v(e))}var rt={openai:"openai",anthropic:"anthropic",google:"google",mistral:"mistral","openai-compatible":"openai-compatible"};function pe(e){let t=v(e),r=W.get(t);if(r)return r;let n=rt[t],i=n?` import { register } from "llm-connect/providers/${n}";
|
|
2
|
-
register();
|
|
3
|
-
|
|
4
|
-
or let loadModel() import it on demand.`:` import { registerProvider } from "llm-connect";
|
|
5
|
-
registerProvider("${t}", (config) => /* your LanguageModel */);`;throw Error(`Provider "${t}" is not registered.
|
|
6
|
-
|
|
7
|
-
Register it before calling AI functions:
|
|
8
|
-
|
|
9
|
-
${i}
|
|
10
|
-
`)}var qt={anthropic:"https://api.anthropic.com/v1",openai:C,google:"https://generativelanguage.googleapis.com/v1beta",mistral:"https://api.mistral.ai/v1"},ot="api.anthropic.com";function he(e){return e.trim().replace(/\/+$/,"")}function ge(e){if(e.customEndpoint)return"openai-compatible";let t=v(e.providerNpm||"openai");if(t==="openai"&&e.providerApi&&he(e.providerApi)!==C)return"openai-compatible";return t}function Be(e){if(!e)return!1;try{return new URL(e).hostname===ot}catch{return!1}}function ht(e){let t=he(e);try{let{pathname:r}=new URL(t);return/\/v\d+$/.test(r)?t:`${t}/v1`}catch{return t}}var gt="anthropic-dangerous-direct-browser-access",nt={anthropic:["x-api-key","anthropic-version","anthropic-beta",gt],openai:["authorization"],google:["x-goog-api-key"],mistral:["authorization"],"openai-compatible":["authorization"]},at="server-side-fallback-2026-06-01";function it(e){return typeof Request<"u"&&e instanceof Request?e.url:String(e)}function st(e,t){let r=t["anthropic-beta"];if(r===void 0||typeof e!=="string"||!e.includes('"fallbacks"'))return;let n;try{n=JSON.parse(e)}catch{return}if(n?.fallbacks!=="default")return;let i=r.split(",").filter((l)=>l.trim()!==at);if(i.length>0)t["anthropic-beta"]=i.join(",");else delete t["anthropic-beta"]}async function ct(e){if(!e.ok||!(e.headers.get("content-type")??"").includes("json"))return e;let t,r;try{t=await e.clone().text(),r=L(JSON.parse(t))}catch{return e}if(r===null)return e;return new Response(t,{status:r,headers:e.headers})}function Ee(e,t={}){let r=nt[e],n=t.strictHeaders&&r?new Set(["content-type","accept",...r]):void 0;return(i,l)=>{let d=it(i),f=l?.headers??(typeof Request<"u"&&i instanceof Request?i.headers:void 0),u={};if(new Headers(f).forEach((p,c)=>{if(c==="user-agent")return;if(n&&!n.has(c))return;if(c===gt&&!Be(d))return;u[c]=p}),e==="anthropic")st(l?.body,u);return(t.fetch??globalThis.fetch)(i instanceof URL||typeof i==="string"?d:i,{...l,headers:u}).then(ct)}}function J(e){if(e.customEndpoint)return"openai";return v(e.providerNpm||"openai")}function ye(e,t={}){let r=pe(J(e)),n=Ee(ge(e),t);if(e.customEndpoint)return r({apiKey:e.apiKey||"",model:e.customModel||e.model||"",baseURL:e.customEndpoint,...e.headers&&{headers:e.headers},fetch:n});return r({apiKey:e.apiKey,model:e.model||"",...e.providerApi&&{baseURL:e.providerApi},...e.headers&&{headers:e.headers},fetch:n})}async function lt(e){switch(e){case"openai":(await (F("g1685z9v"),import("./openai-g1685z9v.js"))).register();return;case"anthropic":(await (F("dc7h9prc"),import("./anthropic-dc7h9prc.js"))).register();return;case"google":(await (F("yywkqdph"),import("./google-yywkqdph.js"))).register();return;case"mistral":(await (F("0mg4kk7s"),import("./mistral-0mg4kk7s.js"))).register();return;case"openai-compatible":(await (F("zhaj1r43"),import("./openai-compatible-zhaj1r43.js"))).register();return}}async function Qe(e,t={}){let r=J(e);if(!me(r))await lt(r);return ye(e,t)}function Le(e){if(e?.customEndpoint?.trim())return!!e.customModel?.trim();return!!e?.apiKey?.trim()}function k(e){return e.custom?e.customApiKey:e.apiKey}function N(e){return e.custom?!!e.customEndpoint.trim()&&!!e.customModel.trim():!!e.apiKey.trim()&&!!e.model}function V(e){return e.custom?!!e.customEndpoint.trim():!!e.apiKey.trim()}function be(e){let t=e.toLowerCase();return t==="localhost"||t.endsWith(".localhost")||t==="[::1]"||/^127(?:\.\d{1,3}){3}$/.test(t)}function _(e){let t;try{t=new URL(e.trim())}catch{return"invalid-endpoint"}if(t.username||t.password)return"invalid-endpoint";if(t.protocol==="https:")return null;if(t.protocol!=="http:")return"invalid-endpoint";return be(t.hostname)?null:"insecure-endpoint"}function Ue(e){if(_(e))return null;return e.trim().replace(/\/+$/,"")}var gn={ollama:{id:"ollama",name:"Ollama",endpoint:"http://localhost:11434/v1",model:"llama3.2"},lmstudio:{id:"lmstudio",name:"LM Studio",endpoint:"http://localhost:1234/v1",model:"local-model"},jan:{id:"jan",name:"Jan",endpoint:"http://localhost:1337/v1"}};function Y(e){try{return globalThis[e]??null}catch{return null}}function z(e,t){try{return Y(e)?.getItem(t)??null}catch{return null}}function X(e,t,r){try{Y(e)?.setItem(t,r)}catch{}}function I(e,t){try{Y(e)?.removeItem(t)}catch{}}var ut=["model","providerId","providerName","providerNpm","providerApi","customEndpoint","customModel","language"];function Ae(e){let t=z("localStorage",e);if(t===null)return null;let r={};try{let i=JSON.parse(t);if(i&&typeof i==="object"&&!Array.isArray(i))r=i}catch{}let n={...r,apiKey:"",model:""};for(let i of ut){let l=r[i];if(typeof l==="string"&&l)n[i]=l;else if(i!=="model")delete n[i]}return n.rememberKey=r.rememberKey===!0,n}var Q="kv",Z="crypto-key",P="api-key";function ee(){try{return!!globalThis.indexedDB&&!!globalThis.crypto?.subtle}catch{return!1}}function Se(e){let t="";for(let r of e)t+=String.fromCharCode(r);return btoa(t)}function ve(e){let t=atob(e),r=new Uint8Array(new ArrayBuffer(t.length));for(let n=0;n<t.length;n++)r[n]=t.charCodeAt(n);return r}function _t({prefsKey:e,dbName:t,sessionKey:r=`${e}-key`}){let n=null;function i(){return new Promise((o,a)=>{let s=indexedDB.open(t,1);s.onupgradeneeded=()=>s.result.createObjectStore(Q),s.onsuccess=()=>o(s.result),s.onerror=()=>a(s.error)})}async function l(o,a){let s=await i();try{return await new Promise((g,A)=>{let x=s.transaction(Q,o),Pe=a(x.objectStore(Q));x.oncomplete=()=>g(Pe.result),x.onerror=()=>A(x.error),x.onabort=()=>A(x.error)})}finally{s.close()}}let d=(o)=>l("readonly",(a)=>a.get(o)),f=(o,a)=>l("readwrite",(s)=>s.put(a,o)),u=(o)=>l("readwrite",(a)=>a.delete(o));async function m(o){let a=await d(Z);if(a||!o)return a;let s=await crypto.subtle.generateKey({name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);return await f(Z,s),s}async function p(o){let a=await m(!0);if(!a)throw Error("No encryption key");let s=crypto.getRandomValues(new Uint8Array(new ArrayBuffer(12))),g=await crypto.subtle.encrypt({name:"AES-GCM",iv:s},a,new TextEncoder().encode(o));return{iv:s,ciphertext:g}}async function c(o){let a=o&&await m(!1);if(!o||!a)return"";let s=await crypto.subtle.decrypt({name:"AES-GCM",iv:o.iv},a,o.ciphertext);return new TextDecoder().decode(s)}function h(){let o=z("sessionStorage",r);if(!o)return;try{let{iv:a,ciphertext:s}=JSON.parse(o);return{iv:ve(a),ciphertext:ve(s).buffer}}catch{return}}async function b(o){if(!ee())return"";try{return await c(o?await d(P):h())}catch{return""}}async function w(o,a){if(I("sessionStorage",r),!ee())return;try{if(!o||!a)await u(P);if(!o)return;let s=await p(o);if(a)await f(P,s);else X("sessionStorage",r,JSON.stringify({iv:Se(s.iv),ciphertext:Se(new Uint8Array(s.ciphertext))}))}catch{}}async function E(){let o=Ae(e);if(!o)return null;if(n===null)n=await b(o.rememberKey===!0);return{...o,apiKey:n}}return{loadDraft:E,async load(){let o=await E();return Le(o)?o:null},async save(o,{rememberKey:a}){let{apiKey:s,...g}=o;X("localStorage",e,JSON.stringify({...g,rememberKey:a})),n=s,await w(s,a)},async clear(){if(n=null,I("localStorage",e),I("sessionStorage",r),!ee())return;try{await u(P),await u(Z)}catch{}}}}var xe=5000,dt=1e4;function _e(e){return e.trim().replace(/\/+$/,"")}function Te(e,t,r){let n=t.trim();if(!n)return{};if(e==="@ai-sdk/anthropic")return{"x-api-key":n,"anthropic-version":"2023-06-01",...Be(r)&&{"anthropic-dangerous-direct-browser-access":"true"}};if(e==="@ai-sdk/google")return{"x-goog-api-key":n};return{Authorization:`Bearer ${n}`}}function D(e,t){return e instanceof Error&&e.name===t}function mt(e){let t=e;if(Array.isArray(t?.data))return t.data.map((r)=>r?.id).filter((r)=>typeof r==="string");if(Array.isArray(t?.models))return t.models.map((r)=>r?.name).filter((r)=>typeof r==="string").map((r)=>r.replace(/^models\//,""));return[]}function te(e,t){return{ok:!1,reason:e===401||e===403?"auth":"http",status:e,...t?{message:t}:{}}}function pt(e){if(typeof AbortSignal.any==="function")return AbortSignal.any(e);let t=new AbortController;for(let r of e){if(r.aborted){t.abort(r.reason);break}r.addEventListener("abort",()=>t.abort(r.reason),{once:!0})}return t.signal}function Me(e,t){let r=t?AbortSignal.timeout(t):void 0;if(e&&r)return pt([e,r]);return e??r}async function Oe(e,t,r,n){let i=r.fetch??globalThis.fetch;try{let l=await i(e,{headers:t,signal:Me(r.signal,r.timeoutMs)});if(!l.ok)return te(l.status);let d=await l.json().catch(()=>null),f=L(d);if(f!==null){let{message:m}=De({statusCode:f,data:d},n.trim());return te(f,m||void 0)}let u=mt(d);return{ok:!0,modelCount:u.length,models:u}}catch(l){if(r.signal?.aborted)throw l;if(D(l,"TimeoutError")||D(l,"AbortError"))return{ok:!1,reason:"timeout"};return{ok:!1,reason:"cors",...l instanceof Error?{message:T(l.message,n.trim())}:{}}}}function Et(e,t="",r={}){let n=`${_e(e)}/models`;return Oe(n,Te(void 0,t,n),{timeoutMs:xe,...r},t)}function bt(e){let t=[];for(let r=e;r instanceof Error&&t.length<4;r=r.cause)t.push(r.message);return t.some((r)=>/failed to fetch|fetch failed|networkerror|load failed|cannot connect to api/i.test(r))}async function we(e,t){try{let[{generateText:r},n]=await Promise.all([(F("wgzgvzaf"),import("./index-wgzgvzaf.js")),Qe(e,t.fetch?{fetch:t.fetch}:{})]);return await r({model:n,prompt:"Reply with OK.",maxOutputTokens:16,maxRetries:0,abortSignal:Me(t.signal,t.timeoutMs)}),{ok:!0}}catch(r){if(t.signal?.aborted)throw r;if(D(r,"TimeoutError")||D(r,"AbortError"))return{ok:!1,reason:"timeout"};let n=T(r instanceof Error?r.message:String(r),e.apiKey?.trim()),i=r?.statusCode;if(typeof i==="number")return te(i,n);if(bt(r))return{ok:!1,reason:"cors",message:n};return{ok:!1,reason:"config",message:n}}}var At=new Set([404,405,501]);function St(e){if(e.ok)return!1;if(e.reason==="cors")return!0;return e.reason==="http"&&e.status!==void 0&&At.has(e.status)}async function vt(e,t){if(e.customEndpoint)return Et(e.customEndpoint,e.apiKey,{signal:t.signal,fetch:t.fetch,timeoutMs:t.timeoutMs??xe});let r=_e(e.providerApi??""),n=r&&e.providerNpm==="@ai-sdk/anthropic"?ht(r):r;if(!n)return null;let i=`${n}/models`;return Oe(i,Te(e.providerNpm,e.apiKey,i),{signal:t.signal,fetch:t.fetch,timeoutMs:t.timeoutMs??dt},e.apiKey)}async function Ce(e,t={}){if(e.customEndpoint){let n=_(e.customEndpoint);if(n==="insecure-endpoint")return{ok:!1,reason:"insecure",message:"Plain http is only allowed to this machine: use https"};if(n)return{ok:!1,reason:"config",message:"Invalid endpoint URL"}}if(t.mode==="generate")return we(e,t);let r=await vt(e,t);if(t.mode==="auto"&&(!r||St(r)))return we(e,t);return r??{ok:!1,reason:"config",message:"No API URL for this provider"}}var wt=[{code:"en",name:"English",label:"English"},{code:"fr",name:"French",label:"Français"},{code:"es",name:"Spanish",label:"Español"},{code:"de",name:"German",label:"Deutsch"},{code:"it",name:"Italian",label:"Italiano"},{code:"pt",name:"Portuguese",label:"Português"},{code:"nl",name:"Dutch",label:"Nederlands"},{code:"ru",name:"Russian",label:"Русский"},{code:"zh",name:"Chinese",label:"中文"},{code:"ja",name:"Japanese",label:"日本語"},{code:"ko",name:"Korean",label:"한국어"},{code:"ar",name:"Arabic",label:"العربية"},{code:"hi",name:"Hindi",label:"हिन्दी"},{code:"tr",name:"Turkish",label:"Türkçe"},{code:"pl",name:"Polish",label:"Polski"},{code:"sv",name:"Swedish",label:"Svenska"}];function ke(e){let t=e?.trim().toLowerCase();if(!t)return;let r=t.split(/[-_]/)[0];return wt.find((n)=>n.code===r||n.name.toLowerCase()===t||n.label.toLowerCase()===t)}function U(e){return ke(e)?.code??"en"}function Ne(){try{let e=globalThis.navigator?.languages??[globalThis.navigator?.language];for(let t of e){let r=ke(t);if(r)return r.code}}catch{}return"en"}function yt(e){let t=e.recommended??Re,r=e.catalog??e.catalogUrl;if(!r)throw Error("createLlmSettingsStore: `catalog` is required");let n=r,i={providerId:e.defaults?.providerId??t[0]??"openai",model:e.defaults?.model??"",rememberKey:e.defaults?.rememberKey??!1},l=()=>e.defaults?.language?U(e.defaults.language):Ne();function d(o){let a=!!o?.customEndpoint,s=o?.apiKey??"";return{custom:a,providerId:o?.providerId||i.providerId,model:o?.model||i.model,apiKey:a?"":s,customApiKey:a?s:"",customEndpoint:o?.customEndpoint??"",customModel:o?.customModel??"",rememberKey:o?.rememberKey??i.rememberKey,language:o?.language?U(o.language):l()}}function f(o){let a=o.catalog?.[o.draft.providerId]??null,s=ne(a,o.search),g=a?.defaultModel;return{...o,provider:a,providers:G(o.catalog,t),isRecommendedProvider:t.includes(o.draft.providerId),models:s,recommendedModel:g?s.find((A)=>A.id===g)??null:null,apiKey:k(o.draft),canSave:N(o.draft),canTest:V(o.draft)}}let u=f({catalog:null,catalogStatus:"idle",catalogError:null,saved:null,draft:d(null),search:"",testing:!1,testResult:null}),m=new Set,p=!1;function c(o){let a={...u,...o};if(!a.draft.model&&a.catalog){let s=K(a.catalog[a.draft.providerId]);if(s)a.draft={...a.draft,model:s}}u=f(a);for(let s of m)s(u)}function h(o){p=!0,c({draft:{...u.draft,...o},testResult:null})}function b(){if(u.catalogStatus==="loading"||u.catalogStatus==="ready")return;c({catalogStatus:"loading",catalogError:null}),(typeof n==="string"?M(n,e.fetch):n()).then((a)=>c({catalog:a,catalogStatus:"ready",catalogError:null}),(a)=>c({catalogStatus:"error",catalogError:a instanceof Error?a.message:"Model list unavailable"}))}function w(){let{draft:o,catalog:a,saved:s}=u,g=q(a,o.providerId);if(g)return g;if(s?.providerId===o.providerId)return{providerId:o.providerId,providerName:s.providerName??o.providerId,providerNpm:s.providerNpm??"",providerApi:s.providerApi??""};return H}function E(){let{draft:o}=u;return{apiKey:k(o),model:o.model,...w(),language:o.language,...o.custom?{customEndpoint:Ue(o.customEndpoint)??o.customEndpoint.trim(),customModel:o.customModel.trim()}:{}}}return{getState:()=>u,subscribe(o){return m.add(o),o(u),()=>{m.delete(o)}},async load(){let o=await(e.storage.loadDraft??e.storage.load)();if(p)c({saved:o});else c({saved:o,draft:d(o),search:"",testResult:null});return o},reset(o){p=!1,c({saved:o,draft:d(o),search:"",testResult:null})},open(){p=!1,c({draft:d(u.saved),search:"",testing:!1,testResult:null}),b()},retryCatalog:b,selectProvider(o){let a=K(u.catalog?.[o])??"";p=!0,c({draft:{...u.draft,providerId:o,model:a},search:"",testResult:null})},selectModel:(o)=>h({model:o}),setApiKey(o){h(u.draft.custom?{customApiKey:o}:{apiKey:o})},setSearch:(o)=>c({search:o}),toggleCustom(o){h({custom:o??!u.draft.custom})},applyPreset(o){h({customEndpoint:o.endpoint,...!u.draft.customModel.trim()&&o.model?{customModel:o.model}:{}})},setEndpoint:(o)=>h({customEndpoint:o}),setCustomModel:(o)=>h({customModel:o}),setRememberKey:(o)=>h({rememberKey:o}),setLanguage:(o)=>h({language:U(o)}),settings:E,async test(o={}){c({testing:!0,testResult:null});try{let a=await Ce(E(),{mode:e.testMode??"models",signal:o.signal,fetch:e.fetch});return c({testing:!1,testResult:a}),a}catch(a){throw c({testing:!1}),a}},async save(o){let{draft:a}=u;if(!N(a))return{ok:!1,reason:"incomplete"};let s=a.custom?_(a.customEndpoint):null;if(s)return{ok:!1,reason:s};let g={...E(),...o};await e.storage.save(g,{rememberKey:a.rememberKey});let A={...g,rememberKey:a.rememberKey};return c({saved:A}),{ok:!0,settings:A}},async clear(){await e.storage.clear(),c({saved:null,draft:{...u.draft,custom:!1,apiKey:"",customApiKey:"",customEndpoint:"",customModel:"",language:l()},testResult:null})}}}export{Re,ft,De,oe,Ie,qt,Be,ht,gt,Qe,Le,Ue,gn,_t,yt};
|