@degreesign/chat 0.5.2 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +178 -14
- package/dist/browser/chat.min.mjs +1 -1
- package/dist/browser/chat.min.mjs.LICENSE.txt +2 -0
- package/dist/engines/litert.d.ts +22 -3
- package/dist/enums.d.ts +12 -1
- package/dist/index.d.ts +2 -2
- package/dist/models.d.ts +4 -2
- package/dist/node/chat.node.min.js +1 -1
- package/dist/node/chat.node.min.js.LICENSE.txt +2 -0
- package/dist/node/chat.node.min.mjs +1 -1
- package/dist/node/chat.node.min.mjs.LICENSE.txt +2 -0
- package/dist/tools/calculator.d.ts +9 -0
- package/dist/tools/currency.d.ts +9 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/search.d.ts +9 -0
- package/dist/tools/text.d.ts +7 -0
- package/dist/types.d.ts +211 -9
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -17,6 +17,7 @@ package loads one model, streams one reply and reports status.
|
|
|
17
17
|
- [Quick start](#quick-start)
|
|
18
18
|
- [Enable WebGPU](#enable-webgpu)
|
|
19
19
|
- [Public API](#public-api)
|
|
20
|
+
- [Tools](#tools)
|
|
20
21
|
- [Status](#status)
|
|
21
22
|
- [Models](#models)
|
|
22
23
|
- [Prompt assembly](#prompt-assembly)
|
|
@@ -39,6 +40,8 @@ package loads one model, streams one reply and reports status.
|
|
|
39
40
|
capped by the prompt budgets.
|
|
40
41
|
- Audio: a user turn can carry an audio URL, sent only to a model with audio
|
|
41
42
|
support and capped by the prompt budgets.
|
|
43
|
+
- Tools: the model may call Web search, arithmetic and currency built-ins, plus
|
|
44
|
+
any tool the host supplies, in the same reply.
|
|
42
45
|
- Reusable: the loaded model stays in memory for the next call.
|
|
43
46
|
- Typed: written in TypeScript with declarations for every export.
|
|
44
47
|
- Portable: importing and calling works in browsers, workers, React and Node.
|
|
@@ -58,11 +61,11 @@ yarn add @degreesign/chat
|
|
|
58
61
|
pnpm add @degreesign/chat
|
|
59
62
|
```
|
|
60
63
|
|
|
61
|
-
`@wllama/wllama`, `@wllama/wllama-compat
|
|
62
|
-
dependencies. The engines are bundled into
|
|
63
|
-
chunks and their wasm assets ship beside them,
|
|
64
|
-
extra and resolves no engine import. Only the
|
|
65
|
-
runtime.
|
|
64
|
+
`@wllama/wllama`, `@wllama/wllama-compat`, `@litert-lm/core` and
|
|
65
|
+
`@degreesign/utils` are build-time dependencies. The engines are bundled into
|
|
66
|
+
the published build as dynamic chunks and their wasm assets ship beside them,
|
|
67
|
+
so a consumer installs nothing extra and resolves no engine import. Only the
|
|
68
|
+
model weights are downloaded at runtime.
|
|
66
69
|
|
|
67
70
|
The build emits:
|
|
68
71
|
|
|
@@ -238,6 +241,12 @@ requested model is already loaded, no download or load happens.
|
|
|
238
241
|
| `onResponse` | Receives the accumulated reply text as it streams. Required. |
|
|
239
242
|
| `onSpeed?` | Receives the current generation speed in tokens per second. |
|
|
240
243
|
| `onStatus?` | Receives a `ChatStatusSnapshot` on every state change. |
|
|
244
|
+
| `builtins?` | Built-in tools to attach, all three by default; `false` attaches none. |
|
|
245
|
+
| `websearch?` | `WebSearchConfig` for the built-in search, provider, language and limits. |
|
|
246
|
+
| `tools?` | Extra `ChatTool` entries, appended after the built-ins. |
|
|
247
|
+
| `onToolCall?` | Receives a `ChatToolCall` before a tool runs. |
|
|
248
|
+
| `onToolResult?` | Receives a `ChatToolResult` when a tool returns or throws. |
|
|
249
|
+
| `maxToolRounds?` | Ceiling on tool rounds in one reply, default 4, clamped 1 to 25. |
|
|
241
250
|
|
|
242
251
|
Without `model` the package picks the GPU build when the browser provides a
|
|
243
252
|
WebGPU adapter and the CPU build when it does not. The budget defaults are 250
|
|
@@ -283,6 +292,146 @@ The final snapshot reports `ready: true`, `phase: LlmPhase.load` and
|
|
|
283
292
|
`percent: 100` on success, or an `error` with `availability: ChatStatus.offline`
|
|
284
293
|
on failure. A preload owns no cancel function; a new load replaces it.
|
|
285
294
|
|
|
295
|
+
## Tools
|
|
296
|
+
|
|
297
|
+
Gemma 4 E2B on the WebGPU engine can call tools. A reply may contain a tool
|
|
298
|
+
call, the package runs it, feeds the result back and lets the model answer, all
|
|
299
|
+
inside the one `createChat` call. Qwen3-VL 2B and the CPU engine never receive
|
|
300
|
+
tools: `ChatStatusSnapshot.supportsTools` reports `false` there, the built-ins
|
|
301
|
+
are dropped and a host tool ends the call with `Model does not accept tools`.
|
|
302
|
+
|
|
303
|
+
Three built-ins ship and all three attach by default:
|
|
304
|
+
|
|
305
|
+
| `BuiltinTool` | What it does |
|
|
306
|
+
| ------------- | ------------ |
|
|
307
|
+
| `websearch` | Searches Wikipedia by default, or DuckDuckGo, and returns a few hits. |
|
|
308
|
+
| `calculate` | Evaluates an arithmetic expression with a safe parser. |
|
|
309
|
+
| `currency` | Quotes and converts fiat, crypto and metals with the 24-hour change. |
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
import { BuiltinTool, WebSearchProvider, createChat } from "@degreesign/chat";
|
|
313
|
+
|
|
314
|
+
const cancel = createChat({
|
|
315
|
+
messages,
|
|
316
|
+
// all three by default; narrow or disable them here
|
|
317
|
+
builtins: [BuiltinTool.calculate, BuiltinTool.currency],
|
|
318
|
+
websearch: { provider: WebSearchProvider.wikipedia, language: "en", limit: 3 },
|
|
319
|
+
onToolCall: (call) => renderToolStart(call),
|
|
320
|
+
onToolResult: (result) => renderToolEnd(result),
|
|
321
|
+
onResponse: (text) => renderReply(text),
|
|
322
|
+
});
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
`builtins: false` disables every built-in. A tool is only offered to the model
|
|
326
|
+
when the model accepts tools, so the default set costs nothing on the CPU
|
|
327
|
+
engine.
|
|
328
|
+
|
|
329
|
+
### Custom tools
|
|
330
|
+
|
|
331
|
+
`ChatInput.tools` is the extension point, with no registration and no global
|
|
332
|
+
state. Each mention is appended after the built-ins and offered in the same
|
|
333
|
+
conversation.
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
import { createChat } from "@degreesign/chat";
|
|
337
|
+
|
|
338
|
+
const cancel = createChat({
|
|
339
|
+
messages,
|
|
340
|
+
tools: [
|
|
341
|
+
{
|
|
342
|
+
name: "lookup_order",
|
|
343
|
+
description: "Read one order from the shop.",
|
|
344
|
+
parameters: {
|
|
345
|
+
type: "object",
|
|
346
|
+
properties: {
|
|
347
|
+
id: { type: "string", description: "Order id" },
|
|
348
|
+
},
|
|
349
|
+
required: ["id"],
|
|
350
|
+
},
|
|
351
|
+
execute: async ({ id }) => await shop.order(String(id)),
|
|
352
|
+
},
|
|
353
|
+
],
|
|
354
|
+
onToolCall: (call) => renderToolStart(call),
|
|
355
|
+
onToolResult: (result) => renderToolEnd(result),
|
|
356
|
+
onResponse: (text) => renderReply(text),
|
|
357
|
+
});
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
- `name` is required and unique. A host tool named `websearch`, `calculate` or
|
|
361
|
+
`currency` replaces that built-in.
|
|
362
|
+
- `description` and `parameters` reach the model as written.
|
|
363
|
+
- `execute` receives the parsed arguments and may return a value or a promise.
|
|
364
|
+
A thrown error becomes a tool error the model reads, and `onToolResult`
|
|
365
|
+
receives `error`.
|
|
366
|
+
- Tools and callbacks are captured when the conversation is created. Rebuilding
|
|
367
|
+
the array with the same functions and declarations reuses the conversation;
|
|
368
|
+
changing a declaration or a function opens a new one and pays one history
|
|
369
|
+
prefill.
|
|
370
|
+
- The package cannot abort a running `execute`. A cancel stops generation and
|
|
371
|
+
discards its result.
|
|
372
|
+
- The package neither clamps nor times out a host result. Keep it small: three
|
|
373
|
+
declarations already cost roughly 200 to 250 of the 4096 context tokens.
|
|
374
|
+
|
|
375
|
+
### Search
|
|
376
|
+
|
|
377
|
+
`websearch` sends one query and returns a short list of `title`, `url` and
|
|
378
|
+
`snippet`.
|
|
379
|
+
|
|
380
|
+
| `WebSearchConfig` | Default | Meaning |
|
|
381
|
+
| ----------------- | ------- | ------- |
|
|
382
|
+
| `provider` | Wikipedia | `WebSearchProvider.wikipedia` or `.duckduckgo`. |
|
|
383
|
+
| `language` | `en` | Wikipedia edition, two or three letters plus an optional region. |
|
|
384
|
+
| `limit` | 3 | Hits asked of the provider, clamped 1 to 20. |
|
|
385
|
+
| `snippetLength` | 400 | Characters kept per snippet. |
|
|
386
|
+
| `timeout` | 8000 | Request budget in milliseconds. |
|
|
387
|
+
|
|
388
|
+
Wikipedia is the default because its REST search has CORS `*`, no key and a
|
|
389
|
+
predictable result shape. DuckDuckGo returns an instant answer and related
|
|
390
|
+
topics, and many queries have neither, so it can return an empty list. Both
|
|
391
|
+
endpoints are public and keyless.
|
|
392
|
+
|
|
393
|
+
### Calculator
|
|
394
|
+
|
|
395
|
+
`calculate` accepts `+`, `-`, `*`, `/`, `%`, `^` and parentheses, and returns
|
|
396
|
+
`{ expression, result }`.
|
|
397
|
+
|
|
398
|
+
- `×`, `÷` and `−` are normalized, and thousands commas and spaces are removed.
|
|
399
|
+
- No implicit multiplication: write `2*(3+4)`.
|
|
400
|
+
- No functions: use `^0.5` for a square root.
|
|
401
|
+
- `%` is a postfix division by 100, so `200*15%` is 30 and `200+10%` is 200.1.
|
|
402
|
+
- Unbalanced parentheses, division by zero, an unknown character, an expression
|
|
403
|
+
over 200 characters and a non-finite result are errors.
|
|
404
|
+
- The parser is hand written. The package never uses `eval` or `new Function`.
|
|
405
|
+
|
|
406
|
+
### Currency
|
|
407
|
+
|
|
408
|
+
`currency` reads one public price file published by [CoinExams](https://coinexams.com)
|
|
409
|
+
and answers from it.
|
|
410
|
+
|
|
411
|
+
- Every rate is quoted against `EUR`, which is always 1.
|
|
412
|
+
- Fiat and metals come from the fiat section. Crypto comes from the coin
|
|
413
|
+
section, which wins when a symbol appears in both.
|
|
414
|
+
- Metals are `XAU`, `XAG`, `XPT` and `XPD`, quoted per gram. A zero or missing
|
|
415
|
+
quote is unavailable.
|
|
416
|
+
- Arguments are `from` (required), `to` (default `EUR`) and `amount` (default 1).
|
|
417
|
+
- A result carries `from`, `to`, `amount`, `rate`, `result`, `updatedAt` and
|
|
418
|
+
`stale`, plus `previousRate`, `change` and `changePercent` when the feed has a
|
|
419
|
+
24-hour value for both symbols.
|
|
420
|
+
|
|
421
|
+
The feed is cached on the device under `degreesign-chat-prices-v1` in
|
|
422
|
+
`localStorage`. Fiat and metals refresh at most hourly, crypto at most every
|
|
423
|
+
five minutes, and concurrent calls share one fetch. A failed refresh keeps the
|
|
424
|
+
previous snapshot, serves it with `stale: true` and waits 30 seconds before the
|
|
425
|
+
next attempt. `navigator.onLine === false` skips the fetch and serves the cache.
|
|
426
|
+
With no cache and no network the tool reports `Prices unavailable offline`.
|
|
427
|
+
|
|
428
|
+
### Privacy
|
|
429
|
+
|
|
430
|
+
Search sends the model's query to the chosen provider, and currency fetches the
|
|
431
|
+
public price file. Nothing else leaves the device, and no key is sent. To keep a
|
|
432
|
+
call fully local, pass `builtins: [BuiltinTool.calculate]`, which computes on
|
|
433
|
+
device.
|
|
434
|
+
|
|
286
435
|
## Status
|
|
287
436
|
|
|
288
437
|
`ChatStatusSnapshot` is the only lifecycle signal:
|
|
@@ -294,6 +443,7 @@ on failure. A preload owns no cancel function; a new load replaces it.
|
|
|
294
443
|
| `backend` | `LlmBackend.cpu`, `.gpu` or `.none`. |
|
|
295
444
|
| `supportsImages` | Whether the requested model accepts images. |
|
|
296
445
|
| `supportsAudio` | Whether the requested model accepts audio. |
|
|
446
|
+
| `supportsTools` | Whether the requested model accepts tool declarations. |
|
|
297
447
|
| `ready` | Whether a model is loaded and accepts a reply. |
|
|
298
448
|
| `loading` | Whether a download or load is in flight. |
|
|
299
449
|
| `requesting` | Whether a reply is streaming right now. |
|
|
@@ -308,6 +458,12 @@ A stream that never produces its first chunk ends with an error after 180
|
|
|
308
458
|
seconds instead of waiting forever. Once a chunk has arrived, 30 seconds of
|
|
309
459
|
silence ends the stream and keeps the text already delivered.
|
|
310
460
|
|
|
461
|
+
A lost WebGPU device is rebuilt once: the package drops the dead engine and its
|
|
462
|
+
device, reloads the LiteRT wasm, retries the turn on the next smaller context
|
|
463
|
+
window (4096, 2048, 1024) and reports the reply normally. When no rebuild is
|
|
464
|
+
possible the runtime ends as `error` with `backend: none`, so the host can fall
|
|
465
|
+
back to the CPU model.
|
|
466
|
+
|
|
311
467
|
## Logging
|
|
312
468
|
|
|
313
469
|
Console output stays off by default. Pass `logging: true` in a call to receive
|
|
@@ -317,10 +473,10 @@ without it goes quiet again.
|
|
|
317
473
|
|
|
318
474
|
## Models
|
|
319
475
|
|
|
320
|
-
| `ChatModelId` | Name | Reasoning | Images | Audio | CPU | WebGPU |
|
|
321
|
-
| ------------- | ---- | --------- | ------ | ----- | --- | ------ |
|
|
322
|
-
| `qwen3_vl_2b` | Qwen3-VL 2B | Yes | Yes | No | Yes | No |
|
|
323
|
-
| `gemma4_e2b` | Gemma 4 E2B | Yes | Desktop | Desktop | No | Yes |
|
|
476
|
+
| `ChatModelId` | Name | Reasoning | Images | Audio | Tools | CPU | WebGPU |
|
|
477
|
+
| ------------- | ---- | --------- | ------ | ----- | ----- | --- | ------ |
|
|
478
|
+
| `qwen3_vl_2b` | Qwen3-VL 2B | Yes | Yes | No | No | Yes | No |
|
|
479
|
+
| `gemma4_e2b` | Gemma 4 E2B | Yes | Desktop | Desktop | Yes | No | Yes |
|
|
324
480
|
|
|
325
481
|
A phone or tablet asking for Gemma gets the browser build,
|
|
326
482
|
`gemma-4-E2B-it-gpu.litertlm`, which is text only. It has no vision or audio
|
|
@@ -528,9 +684,16 @@ const useReply = () => {
|
|
|
528
684
|
| `ChatStatusSnapshot` | Availability, engine status, backend, progress and request state. |
|
|
529
685
|
| `LlmLimits` | Token, prompt, image, audio and thread budgets, all overridable. |
|
|
530
686
|
| `WllamaAssets` | Wasm, compat wasm and compat worker URLs. |
|
|
687
|
+
| `ChatTool` | One tool: `name`, `description`, `parameters` and `execute`. |
|
|
688
|
+
| `ChatToolSchema` | The JSON-schema subset a tool parameter declares. |
|
|
689
|
+
| `ChatToolValue` | A JSON-safe argument or result value. |
|
|
690
|
+
| `ChatToolCall` | One model call: `id`, `name` and parsed `arguments`. |
|
|
691
|
+
| `ChatToolResult` | A finished call, with `result` or `error`. |
|
|
692
|
+
| `WebSearchConfig` | Provider, language, limit, snippet length and timeout. |
|
|
693
|
+
| `WebSearchResult` | One hit: `title`, `url` and `snippet`. |
|
|
531
694
|
|
|
532
695
|
The public enums are `ChatModelId`, `LlmRole`, `ChatStatus`, `LlmStatus`,
|
|
533
|
-
`LlmBackend` and `
|
|
696
|
+
`LlmBackend`, `LlmPhase`, `BuiltinTool` and `WebSearchProvider`.
|
|
534
697
|
|
|
535
698
|
## Architecture
|
|
536
699
|
|
|
@@ -578,10 +741,11 @@ includes no server component.
|
|
|
578
741
|
|
|
579
742
|
### Does it have runtime dependencies?
|
|
580
743
|
|
|
581
|
-
No runtime dependencies. `@wllama/wllama`, `@wllama/wllama-compat
|
|
582
|
-
`@litert-lm/core` are build-time dependencies, bundled
|
|
583
|
-
chunks and their wasm assets, so
|
|
584
|
-
download no engine code beyond the chunk
|
|
744
|
+
No runtime dependencies. `@wllama/wllama`, `@wllama/wllama-compat`,
|
|
745
|
+
`@litert-lm/core` and `@degreesign/utils` are build-time dependencies, bundled
|
|
746
|
+
into the dynamic engine chunks, the chat bundle and their wasm assets, so
|
|
747
|
+
consumers resolve no engine import and download no engine code beyond the chunk
|
|
748
|
+
they use.
|
|
585
749
|
|
|
586
750
|
### Where are the models stored?
|
|
587
751
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see chat.min.mjs.LICENSE.txt */
|
|
2
|
-
var e={};const t={};function n(a){const o=t[a];if(void 0!==o)return o.exports;const r=t[a]={exports:{}};return e[a](r,r.exports,n),r.exports}var a,o,r,i,s,c;let l;n.m=e,n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.f={},n.e=e=>{const t=[];return n.f.j(e,t),Promise.all(t)},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={520:()=>import("./engine-litert.min.mjs"),924:()=>import("./engine-wllama.min.mjs")},t={792:0},a=e=>{let{__webpack_esm_ids__:a,__webpack_esm_modules__:o,__webpack_esm_runtime__:r}=e;var i,s,c=0;for(i in o)n.o(o,i)&&(n.m[i]=o[i]);for(r&&r(n);c<a.length;c++)s=a[c],n.o(t,s)&&t[s]&&t[s][0](),t[s]=0};n.f.j=(o,r)=>{let i=n.o(t,o)?t[o]:void 0;if(0!==i)if(i)r.push(i[1]);else{let n=e[o]().then(a,e=>{throw 0!==t[o]&&(t[o]=void 0),e});n=Promise.race([n,new Promise(e=>i=t[o]=[e])]),r.push(i[1]=n)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(a||(a={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(o||(o={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(r||(r={})),function(e){e.cpu="cpu",e.gpu="gpu",e.none="none"}(i||(i={})),function(e){e.download="download",e.load="load"}(s||(s={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b",e.gemma4_e2b="gemma4-e2b"}(c||(c={}));const d=[{id:c.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}},{id:c.gemma4_e2b,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it.litertlm",vision:!0,audio:!0,web:{file:"gemma-4-E2B-it-gpu.litertlm",vision:!1,audio:!1}}}],u=e=>{const t=e??("undefined"==typeof navigator?void 0:navigator);if(!t)return!1;if("boolean"==typeof t.userAgentData?.mobile)return t.userAgentData.mobile;const n=t.userAgent||"";return/Android|iPhone|iPad|iPod|Mobile/i.test(n)||/Macintosh/.test(n)&&t.maxTouchPoints>1},g=(e,t=u())=>{const n=e.litert;if(n)return t&&n.web?n.web:{file:n.file,vision:n.vision,audio:n.audio}},m=e=>e?d.find(t=>t.id==e):void 0,f=async()=>(l||(l=(async()=>(await(async()=>{const e="undefined"==typeof navigator?void 0:navigator.gpu;if(!e)return!1;let t;try{return!!await Promise.race([e.requestAdapter({powerPreference:"high-performance"}),new Promise(e=>{t=setTimeout(()=>e(void 0),1500)})])}catch{return!1}finally{t&&clearTimeout(t)}})()?d.find(e=>!!e.litert):d.find(e=>!!e.cpu))?.id)()),await l),p=async e=>m(e||await f()),h=(e,t=u())=>!!e.cpu?.mmproj||!0===g(e,t)?.vision,w=(e,t=u())=>!!e.cpu?.mmproj?.audio||!0===g(e,t)?.audio,y=new URL("./../assets/wllama/wllama.wasm",import.meta.url).href,b=new URL("./../assets/wllama/compat/wllama.wasm",import.meta.url).href,v=new URL("./../assets/wllama/compat/wllama.js",import.meta.url).href,x=new URL("./../assets/litert/litertlm_wasm_internal.js",import.meta.url).href,k=(new URL("./../assets/litert/litertlm_wasm_internal.wasm",import.meta.url).href,288),_=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),n=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!n.includes(";base64"))return await(await fetch(e)).arrayBuffer();const a=atob(e.slice(t+1)),o=new Uint8Array(a.length);for(let e=0;e<a.length;e++)o[e]=a.charCodeAt(e);return o.buffer},M=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),n=await createImageBitmap(await t.blob()),a=Math.min(n.width,n.height),o=Math.floor((n.width-a)/2),r=Math.floor((n.height-a)/2),i=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const n=document.createElement("canvas");return n.width=e,n.height=t,n})(k,k),s=i?i.getContext("2d"):null;if(!i||!s||a<1)return n.close(),e;if(s.drawImage(n,o,r,a,a,0,0,k,k),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(i)){const t=await i.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const n=new FileReader;n.onerror=()=>t(""),n.onload=()=>t(`${n.result}`),n.readAsDataURL(e)}))(t)||e}return i.toDataURL("image/jpeg",.85)}catch{return e}},T={maxReplyTokens:250,maxThinkingTokens:128,maxReasoningTokens:320,maxImages:2,maxAudio:1,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:6},E=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,C=(e={},t=!1)=>{const n=T;return{maxReplyTokens:E(e.maxReplyTokens,n.maxReplyTokens,1),maxThinkingTokens:E(e.maxThinkingTokens,n.maxThinkingTokens,1),maxReasoningTokens:E(e.maxReasoningTokens,t?1200:n.maxReasoningTokens,1),maxImages:E(e.maxImages,n.maxImages,0),maxAudio:E(e.maxAudio,n.maxAudio,0),maxContentLength:E(e.maxContentLength,n.maxContentLength,1),promptCharBudget:E(e.promptCharBudget,n.promptCharBudget,1),maxThreads:E(e.maxThreads,n.maxThreads,1)}},L=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),P=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,$=e=>Number(e.headers.get("content-length"))||0,R=(e,t)=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>e.type==t)),j=e=>R(e,"image"),S=e=>R(e,"audio"),A=["<|channel>thought\n","<|channel>thought","..."],B=["<channel|>","..."],W=(e,t,n)=>t.length||n.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e})),...n.map(e=>({type:"audio",url:e}))]:e,I=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,q=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...I(e),{type:"text",text:"\n"},...I(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n};class z extends Error{}const O=async(e,t,n)=>{let a;try{return await Promise.race([e,new Promise((e,o)=>{a=setTimeout(()=>o(new z(n)),t)})])}finally{a&&clearTimeout(a)}},N=e=>{try{Promise.resolve(e.return?.()).catch(()=>{})}catch{}},U=async({model:e,logging:t,onReason:n,onText:a,onSpeed:o,start:r,stopped:i,firstTimeoutMs:s=18e4,idleTimeoutMs:c=3e4,onStall:l})=>{let d="",u="",g="",m=!1,f=0,p=0;const h=((e,t)=>{let n="",a=!1;const o=(e,t)=>{let n=-1,a="";for(const o of t){const t=e.indexOf(o);t>=0&&(n<0||t<n)&&(n=t,a=o)}return{at:n,tag:a}},r=(e,t)=>{let n="";for(const a of t)for(let t=Math.min(e.length,a.length-1);t>n.length;t--)if(e.endsWith(a.slice(0,t))){n=e.slice(e.length-t);break}return n};return{feed:i=>{let s=n+i;for(n="";s;){if(a){const{at:t,tag:i}=o(s,B);if(t>=0){t&&e(s.slice(0,t)),s=s.slice(t+i.length),a=!1;continue}const c=r(s,B);e(s.slice(0,s.length-c.length)),n=c;break}{const{at:e,tag:i}=o(s,A);if(e>=0){e&&t(s.slice(0,e)),s=s.slice(e+i.length),s.startsWith("\n")&&(s=s.slice(1)),a=!0;continue}const c=r(s,A);t(s.slice(0,s.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{u+=e,n(e)},e=>{d+=e,a(e)});try{const e=(await O(r(),s,"Model did not start"))[Symbol.asyncIterator]();for(;;){if(i()){N(e);break}let a;try{a=await O(e.next(),m?c:s,m?"Model stopped responding":"Model did not reply")}catch(n){if(n instanceof z&&(d||u)){l?.(),N(e),t&&console.log("Local chat stalled",n);break}throw n}if(a.done)break;m=!0;const r=a.value?.choices?.[0],w=r?.delta,y="string"==typeof w?.reasoning_content?w.reasoning_content:"string"==typeof w?.reasoning?w.reasoning:"";if(r?.finish_reason&&(g=r.finish_reason),y&&(u+=y,n(y)),w?.content&&h.feed(w.content),y||w?.content){const e=performance.now();f||(p=e),f+=1,f>1&&e>p&&o?.(1e3*f/(e-p))}}h.flush()}catch(e){if(t&&console.log("Local chat failed",e),e instanceof z&&!i())throw e}const w=i()?void 0:d||void 0;return t&&(console.log("Local chat reply",e.id,w?"****":""),console.log("Local chat finish",e.id,g||"none",d.length,u.length)),w},F=async({model:e,params:t,start:n,stopped:o,onStall:r})=>{const i=await(async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push(n);continue}const e=[];for(const t of n.content)e.push("image"==t.type?{type:"image",url:await M(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=T)=>{const n=t.maxContentLength,o=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=a.user||!e.images?.length&&!e.audio?.length)),r=[],i=[];let s=0,c=t.maxImages,l=t.maxAudio;for(let e=o.length-1;e>=0;e--){const d=o[e],u=("string"==typeof d.content?d.content:"").slice(0,n),g=d.role==a.user?(d.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[],m=d.role==a.user?(d.audio||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,l)):[];if(u||g.length||m.length){if(u&&s+u.length>t.promptCharBudget)break;s+=u.length,c-=g.length,l-=m.length,d.role==a.system?r.unshift(u):d.role==a.assistant?i.unshift({role:"assistant",content:u}):i.unshift({role:"user",content:W(u,g,m)})}}for(;i.length&&"user"!=i[0].role;)i.shift();const d=[];for(const e of i){const t=d[d.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=q(t.content,e.content):"assistant"==e.role?d.push({role:"assistant",content:e.content}):d.push({role:"user",content:e.content})}const u=r.join("\n\n"),g=[];return u&&g.push({role:"system",content:u}),g.push(...d),g})(t.messages,t.limits));return t.logging&&((e,t)=>{console.log("Local chat call",e.id,t.map(({role:e,content:t})=>({role:e,content:"****",...Array.isArray(t)?{images:t.filter(e=>"image"==e.type).length,audio:t.filter(e=>"audio"==e.type).length}:{}})))})(e,i),await U({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,onSpeed:t.onSpeed,start:()=>n(i),stopped:o,onStall:r})},D=33554432,H=new Map;let Q=!1;const V=e=>{const t=(e.split("/").pop()||"model").replace(/[^\w.-]+/g,"_");let n=0;for(let t=0;t<e.length;t++)n=31*n+e.charCodeAt(t)>>>0;return`${n.toString(16)}-${t}`},G=e=>{const t=/^part-(\d+)$/.exec(e);return t?Number(t[1]):-1},J=async()=>{if(!Q)if("undefined"!=typeof navigator&&navigator.storage?.getDirectory)try{return await navigator.storage.getDirectory()}catch{return}else Q=!0},K=async(e,t)=>{try{return await e.getDirectoryHandle(t)}catch{return}},X=async e=>{if(e)try{const t=await e.getFile(),n=JSON.parse(await t.text());return{total:Number(n.total)||0,etag:`${n.etag||""}`,complete:!0===n.complete}}catch{return}},Y=async(e,t)=>{try{const n=await e.getFileHandle("meta.json",{create:!0}),a=await n.createWritable();await a.write(JSON.stringify(t)),await a.close()}catch{}},Z=async function*(e){for await(const t of e)yield t},ee=async e=>{try{for await(const[t,n]of Z(e))"file"==n.kind&&G(t)>=0&&await e.removeEntry(t).catch(()=>{})}catch{}},te=async(e,t)=>{try{const n=await(await e.getFileHandle(t)).getFile(),a=await X(await e.getFileHandle(`${t}.json`).catch(()=>{}));if(!a)return;return{file:n,size:n.size,total:a.total,etag:a.etag,complete:a.total?n.size>=a.total:!0===a.complete}}catch{return}},ne=async(e,t)=>{const n=await K(e,t);if(n){const e=await(async e=>await X(await e.getFileHandle("meta.json").catch(()=>{})))(n),t=await(async e=>{const t=[];try{for await(const[n,a]of Z(e)){const e=G(n);if("file"!=a.kind||e<0)continue;const o=await a.getFile();t.push({part:{start:e,size:o.size},file:o})}}catch{return}const n=(e=>{const t=[];let n=0;for(const a of[...e].sort((e,t)=>e.start-t.start))if(a.size){if(a.start!=n)break;t.push(a),n+=a.size}return t})(t.map(e=>e.part)),a=new Set(n.map(e=>e.start)),o=t.filter(e=>a.has(e.part.start)).sort((e,t)=>e.part.start-t.part.start).map(e=>e.file);if(o.length)return{file:1==o.length?o[0]:new Blob(o),size:n.reduce((e,t)=>e+t.size,0)}})(n),a=e?.total||0,o=t?.size??0,r=t?.file??new Blob;return{file:a&&o>a?r.slice(0,a):r,size:o,total:a,etag:e?.etag||"",complete:a?o>=a:!0===e?.complete}}return await te(e,t)},ae=(e,t)=>{const n=e.headers.get("content-range"),a=/bytes (\d+)-/.exec(n||""),o=/\/(\d+)\s*$/.exec(n||""),r=e.headers.get("etag")||"";if(206==e.status){const e=a?Number(a[1]):t.size,n=o?Number(o[1]):t.total;if(e!=t.size)return;if(t.total&&n&&t.total!=n)return;if(t.etag&&r&&t.etag!=r)return;return{start:e,total:n||t.total,etag:r||t.etag}}if(!t.etag||!r||t.etag==r)return{start:0,total:$(e)||t.total,etag:r||t.etag}},oe=async({dir:e,start:t,skip:n,total:a,body:o,onProgress:r,onChunk:i})=>{let c,l=t,d=0,u=n;const g=async()=>{const t=await e.getFileHandle((e=>`part-${e}`)(l),{create:!0});c=await t.createWritable(),d=0},m=async()=>{const e=c;c=void 0,e&&await e.close().catch(()=>{})};try{const e=o.getReader();for(;;){const{done:n,value:o}=await e.read();if(n)break;i();let f=0;for(u&&(f=Math.min(u,o.byteLength),u-=f);f<o.byteLength;){c||await g();const e=Math.min(D-d,o.byteLength-f);await c.write({type:"write",position:d,data:o.subarray(f,f+e)}),f+=e,d+=e,l+=e,d==D&&await m()}l>t&&r(a?l/a:0,s.download)}await m()}catch(e){throw await m(),e}return l},re=e=>["NotAllowedError","NotSupportedError"].includes(e?.name||""),ie=e=>{const t=async()=>{const t=await J();if(t)try{return await t.getDirectoryHandle(e,{create:!0})}catch{return}};return{stored:async e=>{const n=await t();return n?await ne(n,V(e)):void 0},download:async({url:n,signal:a,onProgress:o})=>{const r=`${e}|${n}`,i=H.get(r);if(i)return await i;const c=await t();if(!c)return;const l=(async(e,t,n,a)=>{const o=V(t),r=await te(e,o);if(r?.complete)return r;let i=await K(e,o);i||(await e.removeEntry(o).catch(()=>{}),await e.removeEntry(`${o}.json`).catch(()=>{}),i=await e.getDirectoryHandle(o,{create:!0}));let c=0,l=0;for(;;){if(n?.aborted)throw new Error("Cancelled");const r=await ne(e,o);if(r?.complete)return r;const d=r?.size??0,u=r?.total||0,g=r?.etag||"";if(d>c)c=d,l=0;else if(++l>4)throw new Error("Model download failed");d&&u&&a(d/u,s.download);const m=u?Math.min(d+D,u)-1:d+D-1,f=new AbortController,p=()=>f.abort(),h={size:d,total:u,etag:g};let w,y=setTimeout(p,3e4);n?.addEventListener("abort",p,{once:!0});try{if(w=await fetch(t,{signal:f.signal,headers:{Range:`bytes=${d}-${m}`}}),416==w.status){if(await(w.body?.cancel().catch(()=>{})),u&&d>=u){await Y(i,{total:u,etag:g,complete:!0});continue}await ee(i),await Y(i,{total:0,etag:"",complete:!1});continue}if(!w.ok||!w.body)throw await(w.body?.cancel().catch(()=>{})),new Error("Model download failed");const n=ae(w,h);if(!n){await w.body.cancel().catch(()=>{}),await ee(i),await Y(i,{total:0,etag:"",complete:!1});continue}await Y(i,{total:n.total,etag:n.etag,complete:!1});const r=0==n.start?d:0,s=await oe({dir:i,start:n.start+r,skip:r,total:n.total,body:w.body,onProgress:a,onChunk:()=>{clearTimeout(y),y=setTimeout(p,3e4)}});if(!n.total){await Y(i,{total:s,etag:n.etag,complete:!0});const t=await ne(e,o);if(t)return t}}catch(e){if(n?.aborted)throw new Error("Cancelled");if(e instanceof DOMException&&["QuotaExceededError","NotAllowedError","NotSupportedError","InvalidStateError","TypeMismatchError","SecurityError"].includes(e.name))throw e;await new Promise(e=>setTimeout(e,250+500*l))}finally{clearTimeout(y),n?.removeEventListener("abort",p)}}})(c,n,a,o).finally(()=>{H.delete(r)});return H.set(r,l),await l},remove:async e=>{const n=await t();n&&await(async(e,t)=>{await e.removeEntry(t,{recursive:!0}).catch(()=>{}),await e.removeEntry(`${t}.json`).catch(()=>{})})(n,V(e))},purge:async()=>{const t=await J();t&&await t.removeEntry(e,{recursive:!0}).catch(()=>{})}}},se="litertlm-models",ce=ie("litert-store"),le={num_output_candidates:1,wait_for_weight_uploads:!0,num_decode_steps_per_sync:3,sequence_batch_size:0,supported_lora_ranks:[],max_top_k:40,enable_decode_logits:!1,enable_external_embeddings:!1,use_submodel:!1,use_autosized_ringbuffers:!0};let de=!1;const ue=(...e)=>{de&&console.log(...e)},ge=(...e)=>{de&&console.error(...e)},me=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(se)}catch{return}},fe=new Map,pe=(e,t,n)=>{let a=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{a+=e.byteLength,n(t?a/t:0,s.download),o.enqueue(e)}}))},he=async(e,t=!0)=>{const n=[];for(const a of e){if("string"==typeof a.content){n.push({role:a.role,content:a.content});continue}const e=[];for(const n of a.content)"text"!=n.type?t?e.push({type:n.type,data:await _(n.url)}):e.push({type:"text",text:`[${n.type}]`}):e.push({type:"text",text:n.text});n.push({role:a.role,content:e})}return n},we=(e,t)=>{if(e.role!=t.role)return!1;if("string"==typeof e.content||"string"==typeof t.content)return e.content==t.content;if(e.content.length!=t.content.length)return!1;for(let n=0;n<e.content.length;n++){const a=e.content[n],o=t.content[n];if(a.type!=o.type)return!1;if("text"==a.type&&"text"==o.type){if(a.text!=o.text)return!1}else if(("image"==a.type&&"image"==o.type||"audio"==a.type&&"audio"==o.type)&&a.url!=o.url)return!1}return!0},ye=async function*({engine:e,mod:t,params:n,messages:a,session:o}){const r=a[a.length-1],i=L(n.limits,n.reasoning);if("user"!=r?.role)throw new Error("No user turn");const s=a.slice(0,-1),c=(await he([r]))[0];if(!c)throw new Error("Empty prompt");const l=!!o.conversation&&o.reasoning==n.reasoning&&o.maxTokens==i.max_tokens&&((e,t)=>{const n="system"==e[0]?.role?e[0]:void 0,a="system"==t[0]?.role?t[0]:void 0;if(!n!=!a)return!1;if(n&&a&&!we(n,a))return!1;const o=n?e.slice(1):e,r=a?t.slice(1):t;if(!r.length||r.length>o.length)return!1;const i=o.length-r.length;for(let e=0;e<r.length;e++)if(!we(o[i+e],r[e]))return!1;return!0})(o.sent,s);let d;if(l&&o.conversation)d=o.conversation;else{const a=await he(s,!1);o.conversation=void 0,o.sent=[],d=await e.createConversation({sessionConfig:{maxOutputTokens:i.max_tokens,samplerParams:{type:t.SamplerType.TOP_K,temperature:i.temperature,k:40,p:.95}},preface:{...a.length?{messages:a}:{},extra_context:{enable_thinking:n.reasoning}},prefillPrefaceOnInit:a.length>0}),o.conversation=d,o.reasoning=n.reasoning,o.maxTokens=i.max_tokens,o.sent=[...s]}o.sent.push(r);let u,g=!1,m="";const f=()=>{u&&u.cancel().catch(()=>{});try{d.cancel()}catch{}};n.signal?.addEventListener("abort",f,{once:!0});try{if(n.signal?.aborted)return;const e=d.sendMessageStreaming(c).getReader();for(u=e;;){const{done:t,value:n}=await e.read();if(t)break;const a={};let o="string"==typeof n.content?n.content:"";if(Array.isArray(n.content))for(const e of n.content)"text"==e.type&&(o+=e.text);o&&(a.content=o,m+=o);const r=n.channels?.thought;r&&(a.reasoning=r),(a.content||a.reasoning)&&(yield{choices:[{delta:a}]})}g=!0}finally{n.signal?.removeEventListener("abort",f),g&&m?o.sent.push({role:"assistant",content:m}):(o.conversation=void 0,o.sent=[])}},be={backend:i.gpu,startLLM:async({model:e,limits:t,onProgress:a,signal:o,logging:r})=>{de=!0===r;const c=e.litert,l=g(e);if(!c||!l)throw new Error("Model has no LiteRT artifact");const d=await n.e(520).then(()=>n(507)),u=globalThis,m=u.Module;u.Module={print:ue,printErr:ge};try{await d.getOrLoadGlobalLiteRtLm(x)}finally{u.Module=m}if(o?.aborted)throw new Error("Cancelled");const f=P(c.repo,l.file),p=await me();let h;const w=p?await p.match(f):void 0;if(w?.body)h=w.body;else{const e=await ce.stored(f);e?.complete&&(h=e.file.stream())}if(!h){const e=await ce.download({url:f,signal:o,onProgress:a}).catch(e=>{if(o?.aborted)throw new Error("Cancelled");if(!re(e))throw e;r&&console.log("Local model store failed",e)});e&&(h=e.file.stream())}if(!h&&p)try{await(async(e,t,n,a)=>{const o=fe.get(e);if(o)return await o;const r=(async()=>{const o=await fetch(e,{signal:n});if(!o.ok||!o.body)throw new Error("Model download failed");const r=$(o),i=pe(o.body,r,a);await t.put(e,new Response(i,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{fe.delete(e)});return fe.set(e,r),await r})(f,p,o,a);const e=await p.match(f);e?.body&&(h=e.body)}catch(e){if(o?.aborted)throw new Error("Cancelled");r&&console.log("Local model cache failed",e)}if(h||(h=await(async(e,t,n)=>{const a=await fetch(e,{signal:t});if(!a.ok||!a.body)throw new Error("Model download failed");return pe(a.body,$(a),n)})(f,o,a)),o?.aborted)throw new Error("Cancelled");a(1,s.load);const y=await d.Engine.create((({model:e,limits:t,source:n,mod:a})=>{const o=g(e);return{model:n,mainExecutorSettings:{maxNumTokens:4096,...o?.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:le},...o?.vision?{visionBackend:a.Backend.GPU,maxVisionTokensPerImage:70,minVisionTokensPerImage:70}:{},...o?.audio?{audioBackend:a.Backend.CPU}:{}}})({model:e,limits:t,source:h,mod:d}));if(o?.aborted)throw await y.delete(),new Error("Cancelled");const b={sent:[],reasoning:!1,maxTokens:0};return{model:e,backend:i.gpu,contextSize:4096,chat:t=>(async({engine:e,model:t,mod:n,params:a,session:o})=>{de=!0===a.logging;const r=()=>{try{o.conversation?.cancel()}catch{}o.conversation=void 0,o.sent=[]};try{return await F({model:t,params:a,stopped:()=>!!a.signal?.aborted,onStall:r,start:async r=>{if(a.signal?.aborted)throw new Error("Cancelled");const i=g(t);if(j(r)&&!i?.vision)throw new Error("Model does not accept images");if(S(r)&&!i?.audio)throw new Error("Model does not accept audio");return ye({engine:e,mod:n,params:a,messages:r,session:o})}})}catch(e){throw r(),e}})({engine:y,model:e,mod:d,params:t,session:b}),unload:async()=>{b.conversation=void 0,b.sent=[],await y.delete()}}},cached:async e=>{const t=e.litert,n=g(e);if(!t||!n)return!1;const a=P(t.repo,n.file),[o,r]=await Promise.all([me(),ce.stored(a)]);if(r?.complete)return!0;try{return!(!o||!await o.match(a))}catch{return!1}},hasCache:async()=>{try{for(const e of d){const t=e.litert,n=g(e);if(!t||!n)continue;if(await ce.stored(P(t.repo,n.file)))return!0}const e=await me();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert,n=g(e);if(!t||!n)return;const a=P(t.repo,n.file),o=await me();await ce.remove(a),o&&await o.delete(a)}catch{}},purge:async()=>{try{await ce.purge(),"undefined"!=typeof caches&&await caches.delete(se)}catch{}}},ve=ie("wllama-store");let xe,ke,_e="",Me=!1;const Te=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,Ee=e=>{const t={wasm:y,compatWasm:b,compatWorker:v};return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},Ce=e=>{const t=e=>(...t)=>{Me&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},Le=async()=>{if(xe)return xe;const e=await n.e(924).then(()=>n(577)),t=ke||Ee(),a=new e.Wllama({default:t.wasm},{logger:Ce(e.LoggerWithoutDebug)});return ke||(ke=t,_e=Te(t)),a.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),xe=a,a},Pe=async()=>{const e=xe;xe=void 0;try{await(e?.exit())}catch{}},$e=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),Re=e=>{const t=e.cpu;return t?[{name:t.file,url:P(t.repo,t.file)},...t.mmproj?[{name:t.mmproj.file,url:P(t.repo,t.mmproj.file)}]:[]]:[]},je=async e=>{const t=Re(e);if(!t.length)return!1;for(const e of t){const t=await ve.stored(e.url);if(!t?.complete)return!1}return!0},Se=async(e,t)=>{const n=await e.cacheManager.list();return Re(t).every(e=>n.some(t=>$e(t,e.name)))},Ae=async({model:e,signal:t,onProgress:n})=>{const a=Re(e),o=[];for(let e=0;e<a.length;e++){if(t?.aborted)throw new Error("Cancelled");const r=await ve.download({url:a[e].url,signal:t,onProgress:(t,o)=>n((e+t)/a.length,o)});if(!r)return;o.push(r.file)}return o.length?o:void 0},Be=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){"system"==n.role?t.push({role:"system",content:n.content}):"assistant"==n.role?t.push({role:"assistant",content:n.content}):t.push({role:"user",content:n.content});continue}const e=[];for(const t of n.content)"text"==t.type?e.push({type:"text",text:t.text}):e.push({type:t.type,data:await _(t.url)});t.push({role:"user",content:e})}return t},We={backend:i.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{Me=!0===o;const c=u()?4096:8192,l=e.cpu;if(!l)throw new Error("Model has no CPU artifact");const d=Ee(r),g=Te(d);xe&&g!=_e&&await Pe(),ke=d,_e=g;const m=(f="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,p=l.mmproj?Math.min(t.maxThreads,2):t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(f||4)-1)),p)));var f,p;const h=await Le(),w=await je(e),y=l.mmproj?.file,b=P(l.repo,l.file),v=y?P(l.repo,y):"";if(a?.aborted)throw await Pe(),new Error("Cancelled");if(!w&&y){const e=await h.cacheManager.list(),t=e.some(e=>$e(e,l.file)),n=e.some(e=>$e(e,y));t&&!n&&await h.cacheManager.deleteMany(e=>$e(e,l.file))}const x={n_ctx:c,n_threads:m,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,jinja:!0};try{let t=w?await Ae({model:e,signal:a,onProgress:n}):void 0;t||w||await Se(h,e).catch(()=>!1)||(t=await Ae({model:e,signal:a,onProgress:n}).catch(e=>{if(a?.aborted)throw new Error("Cancelled");if(!re(e))throw e;o&&console.log("Local model store failed",e)})),t?(n(1,s.load),await h.loadModel(t,x)):await h.loadModelFromUrl(v?{url:b,mmprojUrl:v}:b,{...x,useCache:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?s.load:s.download)}})}catch(e){throw await Pe(),e}if(a?.aborted)throw await Pe(),new Error("Cancelled");if(!h.getLoadedContextInfo().n_ctx)throw await Pe(),new Error("Failed to create model context");return{model:e,backend:i.cpu,contextSize:c,chat:t=>(async(e,t,n)=>{if(Me=!0===n.logging,e.isModelLoaded())return await F({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if(j(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");if(S(a)&&!e.supportInputModality("audio"))throw new Error("Model does not accept audio");return await e.createChatCompletion({messages:await Be(a),...L(n.limits,n.reasoning),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}})}})})(h,e,t),unload:async()=>{if(xe==h)await Pe();else try{await h.exit()}catch{}}}},cached:async e=>{try{return!!e.cpu&&(!!await je(e)||await Se(await Le(),e))}catch{return!1}},hasCache:async()=>{try{for(const e of d.flatMap(e=>Re(e)))if(await ve.stored(e.url))return!0;const e=await Le();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{const t=Re(e);try{for(const e of t)await ve.remove(e.url)}catch{}try{const e=await Le();await e.cacheManager.deleteMany(e=>t.some(t=>$e(e,t.name)))}catch{}},purge:async()=>{try{await ve.purge()}catch{}try{const e=await Le();await e.cacheManager.clear()}catch{}}},Ie=((e={})=>{const t=e.engines?.cpu||We,n=e.engines?.litert||be;let a,o,c,l,u,g,m,f,p=i.none,h=r.idle,w=[],y=0,b={percent:0,phase:s.download};const v=a=>{if(e.backend!=i.none)return e.backend==i.cpu?a.cpu?t:void 0:e.backend==i.gpu?a.litert?n:void 0:a.litert&&"undefined"!=typeof navigator&&navigator.gpu&&"undefined"!=typeof WebAssembly?n:!a.cpu||"undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?void 0:t},x=(e,t)=>{b={percent:Math.max(0,Math.min(1,e)),phase:t||s.download};for(const e of[...w])e.report(b.percent,b.phase)},k=e=>{h=e},_=()=>{y++,g?.abort(),g=void 0,u=void 0,h==r.downloading&&k(r.idle)},M=(e,t)=>{const n=l;return n?new Promise(a=>{let o=!1;const r={report:e,settle:e=>{o||(o=!0,t?.removeEventListener("abort",i),a(e))}},i=()=>{(e=>{w=w.filter(t=>t!=e),queueMicrotask(()=>{!w.length&&l&&_()})})(r),r.settle(!1)};w.push(r),t?.aborted?i():t?.addEventListener("abort",i,{once:!0}),n.then(r.settle,()=>r.settle(!1))}):Promise.resolve(!1)},T=()=>h==r.ready&&!!a&&!!o;return{load:async({model:e,limits:t,assets:n,logging:i,signal:f,onProgress:h})=>{if(f?.aborted)return!1;if(T()&&o?.id==e.id)return!0;if(l&&u==e.id)return h(b.percent,b.phase),await M(h,f);l&&(_(),w=[],await l.catch(()=>!1));const E=++y,C=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const l=v(e);if(E!=y)return!1;if(!l)return m="Model is not supported on this device",k(r.unsupported),!1;if(await(async(e,t)=>{if(o&&o.id!=e.id){const e=o,t=c,n=a;a=void 0,o=void 0,c=void 0,await(n?.unload()),await(t?.remove(e))}if(await t.hasCache())for(const n of d)n.id!=e.id&&v(n)==t&&await t.remove(n)})(e,l),E!=y)return!1;const u=await l.cached(e);if(E!=y)return!1;m=void 0,k(r.downloading),x(0,s.download),u&&x(1,s.load);const f=new AbortController;g=f;try{const d=await l.startLLM({model:e,limits:t,logging:i,signal:f.signal,assets:n,onProgress:(e,t)=>{E==y&&x(e,t)}});return E!=y||f.signal.aborted?(await d.unload(),!1):(a=d,o=e,c=l,p=l.backend,m=void 0,k(r.ready),x(1,s.load),!0)}catch(e){return E!=y||(a=void 0,o=void 0,c=void 0,m=`${e?.message||`${e}`}`,i&&console.log("Local model failed",e),k(r.error)),!1}finally{g==f&&(g=void 0)}})().finally(()=>{l==C&&(l=void 0,u=void 0,w=[])});return l=C,u=e.id,await M(h,f)},chat:async e=>{if(!T()||!a)return;for(;f;)await f.catch(()=>{});if(!T()||!a)return;const t=a.chat(e);f=t;try{return await t}finally{f==t&&(f=void 0)}},unload:async()=>{const e=a;_(),a=void 0,o=void 0,c=void 0,k(r.idle),await(e?.unload())},ready:T,loading:()=>!T()&&h==r.downloading,status:()=>h,backend:()=>p,error:()=>m,model:()=>o}})(),qe=(e,t,n)=>{const a=e.status(),i=m(t);return{availability:a==r.ready?o.online:a==r.error||a==r.unsupported?o.offline:o.away,status:a,backend:e.backend(),supportsImages:!!i&&h(i),supportsAudio:!!i&&w(i),ready:e.ready(),loading:e.loading(),requesting:n.requesting,phase:n.phase,percent:n.percent,...n.error?{error:n.error}:{}}},ze=(e=>{let t,n=0;const o=t=>t.input.onStatus?.(qe(e,t.model??t.input.model,t));return i=>{t?.controller.abort();const c={token:++n,input:i,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?s.load:s.download,requesting:!1,cancelled:!1};return t=c,o(c),(async t=>{const{input:r}=t,i=!0===r.logging,c=await p(r.model);if(t.model=c?.id,t.token!=n)return;const l=r.messages.some(e=>e.role!=a.system&&"string"==typeof e.content&&!!e.content.trim()),d=r.messages.some(e=>e.role==a.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),u=r.messages.some(e=>e.role==a.user&&!!e.audio?.some(e=>"string"==typeof e&&!!e)),g=l||d||u;if(!c)return t.error="Unknown model",void o(t);if(!g)return t.error="No prompt",void o(t);const m=h(c),f=w(c);if(!(l||d&&m||u&&f))return u&&!f?t.error="Model does not accept audio":d&&!m&&(t.error="Model does not accept images"),void o(t);const y=C(r.limits,!!c.litert),b=await e.load({model:c,limits:y,logging:i,signal:t.controller.signal,onProgress:(e,a)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=a,o(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(t.cancelled)return;if(!b)return t.error||(t.error=e.error()||"Model not ready"),void o(t);const v=d&&!m||u&&!f?r.messages.map(({images:e,audio:t,...n})=>({...n,...e&&m?{images:e}:{},...t&&f?{audio:t}:{}})):r.messages;t.requesting=!0,t.error=void 0,t.percent=100,t.phase=s.load,o(t);let x,k="",_="";try{x=await e.chat({messages:v,limits:y,reasoning:!0===r.reasoning,logging:i,onReason:e=>{t.token!=n||t.cancelled||(k+=e,r.onThinking?.(k))},onText:e=>{t.token!=n||t.cancelled||(_+=e,r.onResponse?.(_))},onSpeed:e=>{t.token!=n||t.cancelled||r.onSpeed?.(e)},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void o(t)}t.token==n&&(t.requesting=!1,x||t.cancelled||(t.error="No reply"),o(t))})(c),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=r.ready?queueMicrotask(()=>o(t)):e.unload().then(()=>o(t)))})(c)}})(Ie),Oe=(Ne=Ie,async(e={})=>{const t=await p(e.model),n=n=>e.onStatus?.(qe(Ne,t?.id,n));if(!t)return n({requesting:!1,phase:s.download,percent:0,error:"Unknown model"}),!1;let a,o=0,r=s.download;const i=Ne.ready()&&Ne.model()?.id==t.id;return await Ne.load({model:t,limits:C(e.limits,!!t.litert),logging:!0===e.logging,onProgress:(e,t)=>{o=Math.round(100*e),r=t,n({requesting:!1,phase:r,percent:o})}}).catch(e=>(a=`${e?.message||`${e}`}`,!1))?(i&&n({requesting:!1,phase:s.load,percent:100}),!0):(n({requesting:!1,phase:r,percent:o,error:a||Ne.error()||"Model not ready"}),!1)});var Ne;export{c as ChatModelId,o as ChatStatus,i as LlmBackend,s as LlmPhase,a as LlmRole,r as LlmStatus,ze as createChat,Oe as preloadModel};
|
|
2
|
+
var e={155(e){e.exports=(()=>{var e={125:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.addZ=t.tN=t.monNm=t.tmUTC=t.tmAP=t.moYrDt=t.shortDt=t.fullLong=t.fullDate=t.fullDt=t.invDt=t.dayRes=t.timeStandard=t.dateStandard=t.seoDt=t.thisYear=t.oneMon=t.oneMin=t.oneHr=t.oneDay=t.oneSec=void 0;const r=()=>Date.now(),n=["January","February","March","April","May","June","July","August","September","October","November","December"],o=["JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"],a=["st","nd","rd","th"],i=e=>0==+e?"00":+e<10&&+e>=1?`0${e}`:`${e}`,s=e=>{const t=new Date(e);return`${t.getUTCFullYear()}-${i(t.getUTCMonth()+1)}-${i(t.getUTCDate())}`},c=e=>i(e.getUTCHours())+`:${i(e.getUTCMinutes())}`+`:${i(e.getUTCSeconds())}`;t.tN=r,t.monNm=n,t.dayRes=90,t.oneSec=1e3,t.oneMin=6e4,t.oneHr=36e5,t.oneDay=864e5,t.oneMon=27e8,t.addZ=i,t.tmUTC=e=>{const t=new Date(e);return i(t.getUTCHours())+`:${i(t.getUTCMinutes())} UTC`},t.tmAP=e=>{const t=new Date(e),r=t.getHours();return i(r>12?r-12:r)+`:${i(t.getMinutes())}`+(r>=12?"pm":"am")},t.shortDt=e=>{const t=new Date(e);return`${t.getDate()} ${o[t.getMonth()]}`},t.moYrDt=e=>{const t=new Date(e);return`${o[t.getMonth()]} ${t.getFullYear()}`},t.fullDt=e=>{const t=new Date(e);return`${t.getDate()} ${o[t.getMonth()]} ${t.getFullYear()}`},t.fullDate=e=>{const t=new Date(e);return`${t.getDate()} ${n[t.getMonth()]} ${t.getFullYear()}`},t.fullLong=e=>`${(e=>{const t=new Date(e),r=t.getDate();return r+a[r<5?r-1:r>4&&r<21?3:r>20&&r<25?r-21:r>24&&r<31?3:0]+` of ${n[t.getMonth()]}`})(e)} ${new Date(e).getFullYear()}`,t.thisYear=e=>(e?new Date(e):new Date)?.getUTCFullYear(),t.dateStandard=s,t.timeStandard=c,t.seoDt=e=>{!e&&(e=r());const t=new Date(e);return`${s(t)}T${c(t)}Z`},t.invDt=e=>{const t=new Date(e);return`${t.getUTCFullYear()}`.split("20")[1]+i(t.getUTCMonth()+1)+i(t.getUTCDate())+`${e}`.slice(10)}},240:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.idRandLong=t.idRandShort=t.idShuffle=void 0;const r=["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","@",".","_","0","1","2","3","4","5","6","7","8","9"],n=({data:e,password:t})=>{try{const n=(e,t)=>r.includes(e.toLowerCase())?r[(r.indexOf(e.toLowerCase())+Math.pow(t,3))%r.length]:e;return[...e].map(e=>n(e,Number(t))).join("")}catch{return""}},o=async({data:e,password:t})=>{if(!e||!t)return"";try{crypto.subtle;const r=new TextEncoder,n=r.encode(e),o=r.encode(t),a=await crypto.subtle.digest("SHA-256",o),i=new Uint8Array(a),s=i.slice(0,32),c=i.slice(0,12),l=await crypto.subtle.importKey("raw",s,{name:"AES-GCM"},!1,["encrypt"]),u=await crypto.subtle.encrypt({name:"AES-GCM",iv:c},l,n);return btoa(String.fromCharCode(...new Uint8Array(u))).replace(/\+/g,"a").replace(/\//g,"b").replace(/=/g,"c").toLowerCase()}catch{return""}};t.idShuffle=async({data:e,password:t})=>4==t?.length?n({data:e,password:t}):await o({data:e,password:t}),t.idRandShort=(e=10)=>{try{return crypto.randomUUID()?.replaceAll("-","")?.slice(0,e)}catch(e){return console.log("idRandShort failed",e),""}},t.idRandLong=(e=10)=>{try{const t="abcdefghijklmnopqrstuvwxyz",r=new Uint8Array(e);return crypto.getRandomValues(r),Array.from(r).map(e=>t[e%26]).join("")}catch(e){return console.log("idRandLong failed",e),""}}},246:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.cacheCheck=t.delayCode=void 0;const n=r(125);t.delayCode=async(e=0)=>await new Promise(t=>setTimeout(t,e)),t.cacheCheck=({analysisCacheLimit:e,lastUpdated:t,forceRefresh:r})=>{const o=Date.now();if(t&&(!r&&t>o-e||r&&t>o-n.oneDay))return!0}},792:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.isEven=t.pNum=t.sharpeRatio=t.priceVariations=t.nTxtAr=t.zNum=t.addCom=t.adjNum=t.rNum=void 0;const r=[1,.1,.01,.001,1e-4,1e-5,1e-6,1e-7,1e-8,1e-9,1e-10,1e-11,1e-12,1e-13,1e-14,1e-15,1e-16,1e-17,1e-18,1e-19],n=(e,t=6)=>{const n=+e,o=n?Math.abs(n):0,a=o>1&&t?t-`${Math.round(o)}`.length:0;return n?(n<0?-1:1)*(Number.isInteger(o)||o<1e-16?o:o>1e5?Math.round(o):o>1?Number(o.toFixed(a<0?0:a)):((e,t)=>{let n=0;for(const o of r){if(o<e)return Number(e.toFixed(t+n-1));n++}return e})(o,t)):e},o=(e,t)=>{const r=(n(e,t)+"").split(".");return r[0]=r[0].replace(/\B(?=(\d{3})+(?!\d))/g,","),r.join(".")},a=(e,t=3)=>{const r=Number(e);if(!e||!r)return e+"";const a=Math.abs(r);return(r<0?"-":"")+(a>1e9?o(a/1e9,t)+"b":a>1e6?o(a/1e6,t)+"m":a<1e-6&&a>1e-16?(1+n(a,t)+"").replace(/1./g,"0."):o(a,t))};t.nTxtAr=["zero","one","two","three","four","five","six","seven","eight","nine","ten"],t.rNum=n,t.addCom=o,t.adjNum=a,t.zNum=e=>{const t=Number(e);let r=t?Math.abs(t):0,n=1e10;for(;n>1;)r>n&&(r=Math.round(r/(n/10))*(n/10)),n/=10;return t?(t<0?"-":"")+a(r,2):e},t.pNum=e=>+e||0==+e?Math.round(1e6*+e)/1e6:null,t.priceVariations=e=>{try{let t=0;const r=[...e].sort((e,t)=>e[0]-t[0]),n=e.reduce((e,[,t])=>e+t,0),o=r.find(([,e])=>(t+=e,t>=n/2))[0];return e.filter(([e])=>Math.abs(e-o)/o<.05).map(([e])=>e)}catch{return[]}},t.sharpeRatio=({assetPrices:e,minExpectedReturn:t=.05})=>{if(!e?.length||e?.length<2)return 0;const r=e.slice(1).map((t,r)=>(t-e[r])/e[r]),n=r.reduce((e,t)=>e+t,0)/r.length,o=Math.sqrt(r.reduce((e,t)=>e+Math.pow(t-n,2),0)/r.length);return(n-t)/o},t.isEven=e=>e%2==0},794:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.restoreObj=t.restoreObjStr=t.storeObj=t.storeObjStr=t.objNestValueCount=t.objLen=t.objSortSimple=t.objSort=void 0;const n=r(125),o=e=>{try{return Object.keys(e||{})?.length||0}catch(e){return console.log(e),0}},a=e=>{try{return e?.replace(/"/g,"'")}catch(e){return console.log((0,n.tN)(),"storeObjStr failed",e),""}},i=e=>{try{return e?.toString()?.replace(/'/g,'"')}catch(e){console.log((0,n.tN)(),"restoreObjStr failed",e)}};t.objLen=o,t.objNestValueCount=e=>{let t=0;if(o(e))for(const r in e)t+=o(e[r])?1:0;return t},t.objSort=(e={},t,r=-1)=>Object.fromEntries(Object.entries(e).sort(([,e],[,n])=>null===e[t]||void 0===e[t]?1:null===n[t]||void 0===n[t]?-1:e[t]>n[t]?1*r:-1*r)),t.objSortSimple=(e={},t=-1)=>Object.fromEntries(Object.entries(e).sort(([,e],[,r])=>null==e?1:null==r?-1:e>r?1*t:-1*t)),t.storeObjStr=a,t.storeObj=e=>{try{return a(JSON.stringify(e))}catch(e){return console.log((0,n.tN)(),"storeObj failed",e),""}},t.restoreObjStr=i,t.restoreObj=e=>{try{if(!e)return;const t=i(e);return t?JSON.parse(t):void 0}catch(e){console.log((0,n.tN)(),"restoreObj failed",e)}}},830:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.phaseDifference=t.compareArrays=t.squeezeArray=t.forecastNextTotal=t.forecastNext=t.getMax=t.getMean=t.getSum=t.maxVl=t.minVl=t.sumArr=void 0;const r=e=>{try{return e?.length?e.reduce((e,t)=>e+t):0}catch(e){return console.log("sumArr failed",e),0}},n=e=>{try{return e?.length?e.reduce((e,t)=>e+t,0):0}catch(e){return console.log("getSum failed",e),0}},o=e=>{try{return e?.length?n(e)/e.length:0}catch(e){return console.log("getMean failed",e),0}},a=e=>{try{return e?.length?Math.max(...e):0}catch(e){return console.log("getMax failed",e),0}},i=e=>{try{if(!e?.length)return 0;const t=[...e].sort((e,t)=>e-t),r=Math.floor(t.length/2);return t.length%2?t[r]:(t[r-1]+t[r])/2}catch(e){return console.log("median failed",e),0}},s=({currentPeriod:e,steps:t=1})=>{try{const r=(Array.isArray(e)?e:[]).filter(Number.isFinite);if(!r.length||t<=0)return[];if(r.length<2){const e=Math.max(0,o(r));return Array.from({length:t},()=>e)}const n=r.length,{slope:s,intercept:c}=(e=>{try{const t=e.length,r=[];for(let n=0;n<t-1;n++)for(let o=n+1;o<t;o++)r.push((e[o]-e[n])/(o-n));const n=i(r);return{slope:n,intercept:i(e.map((e,t)=>e-n*t))}}catch(e){return console.log("theilSen failed",e),{slope:0,intercept:0}}})(r),l=c+s*(n-1),u=a(r),d=u>0?3*u:1/0;return Array.from({length:t},(e,t)=>{const r=t+1,o=l+s*n*Math.log1p(r/n);return Math.max(0,Math.min(o,d))})}catch(e){return console.log("forecastNext failed",e),[]}};t.sumArr=r,t.maxVl=(e,t)=>{let r=0;for(let n=0;n<e.length;n++){const o=e[n];o[t]>r&&(r=o[t])}return r},t.minVl=(e,t)=>{let r=0;for(let n=0;n<e.length;n++){const o=e[n];o[t]<r&&(r=o[t])}return r},t.getSum=n,t.getMean=o,t.getMax=a,t.forecastNext=s,t.forecastNextTotal=e=>{try{const t=s({currentPeriod:e,steps:e?.length});return n(t)}catch(e){return console.log("forecastNextTotal failed",e),0}},t.squeezeArray=({arr:e,targetLength:t})=>{try{if(!e||0===e.length||t<=0)throw new Error("Invalid input");const n=Math.ceil(e.length/t);return Array.from({length:t},(t,o)=>{const a=o*n,i=Math.min(a+n,e.length),s=e.slice(a,i);return r(s)}).slice(0,t)}catch(e){return console.log("squeezeArray failed",e),[]}},t.compareArrays=({arrays:e})=>{try{const t=[...e],n=Math.min(...t.map(e=>e.length));for(let e=0;e<t.length;e++)t.splice(n);const o=t.map(e=>r(e)),a=[],i=Math.min(...o),s=o.indexOf(i),c=i/Math.max(...o);for(let e=0;e<t.length;e++){const r=t[e];if(a[e]=[],e==s)a[e]=r;else for(let t=0;t<r.length;t++)a[e].push(c*r[t])}return a}catch(t){return console.log("compareArrays failed",t),e}},t.phaseDifference=({array1:e,array2:t})=>{try{let r=e.length,n=e.reduce((e,t)=>e+t)/r,o=t.reduce((e,t)=>e+t)/r,a=e.map(e=>e-n),i=t.map(e=>e-o),s=Math.floor(r/2),c=-1/0,l=0;for(let e=-s;e<=s;e++){let t=0,n=0,o=0,s=0;for(let c=0;c<r;c++){let l=c+e;l>=0&&l<r&&(t+=a[c]*i[l],n+=a[c]*a[c],o+=i[l]*i[l],s++)}if(n>0&&o>0&&s>=.8*r){let r=t/Math.sqrt(n*o);r>c&&(c=r,l=e)}}return l}catch(e){return console.log("phaseDifference failed",e),0}}}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var a=t[n]={exports:{}};return e[n](a,a.exports,r),a.exports}var n={};return(()=>{var e=n;Object.defineProperty(e,"__esModule",{value:!0}),e.idShuffle=e.isEven=e.pNum=e.nTxtAr=e.zNum=e.addCom=e.adjNum=e.rNum=e.sharpeRatio=e.priceVariations=e.timeStandard=e.dateStandard=e.addZ=e.tN=e.monNm=e.tmUTC=e.tmAP=e.moYrDt=e.shortDt=e.fullLong=e.fullDate=e.fullDt=e.invDt=e.dayRes=e.thisYear=e.seoDt=e.oneMon=e.oneMin=e.oneHr=e.oneDay=e.oneSec=e.restoreObj=e.restoreObjStr=e.storeObj=e.storeObjStr=e.objSortSimple=e.objSort=e.objNestValueCount=e.objLen=e.phaseDifference=e.compareArrays=e.squeezeArray=e.forecastNextTotal=e.forecastNext=e.getMax=e.getMean=e.getSum=e.maxVl=e.minVl=e.sumArr=void 0,e.cacheCheck=e.delayCode=e.idRandLong=e.idRandShort=void 0;const t=r(246);Object.defineProperty(e,"cacheCheck",{enumerable:!0,get:function(){return t.cacheCheck}}),Object.defineProperty(e,"delayCode",{enumerable:!0,get:function(){return t.delayCode}});const o=r(830);Object.defineProperty(e,"sumArr",{enumerable:!0,get:function(){return o.sumArr}}),Object.defineProperty(e,"minVl",{enumerable:!0,get:function(){return o.minVl}}),Object.defineProperty(e,"maxVl",{enumerable:!0,get:function(){return o.maxVl}}),Object.defineProperty(e,"getMax",{enumerable:!0,get:function(){return o.getMax}}),Object.defineProperty(e,"getMean",{enumerable:!0,get:function(){return o.getMean}}),Object.defineProperty(e,"getSum",{enumerable:!0,get:function(){return o.getSum}}),Object.defineProperty(e,"forecastNext",{enumerable:!0,get:function(){return o.forecastNext}}),Object.defineProperty(e,"forecastNextTotal",{enumerable:!0,get:function(){return o.forecastNextTotal}}),Object.defineProperty(e,"squeezeArray",{enumerable:!0,get:function(){return o.squeezeArray}}),Object.defineProperty(e,"compareArrays",{enumerable:!0,get:function(){return o.compareArrays}}),Object.defineProperty(e,"phaseDifference",{enumerable:!0,get:function(){return o.phaseDifference}});const a=r(240);Object.defineProperty(e,"idRandLong",{enumerable:!0,get:function(){return a.idRandLong}}),Object.defineProperty(e,"idRandShort",{enumerable:!0,get:function(){return a.idRandShort}}),Object.defineProperty(e,"idShuffle",{enumerable:!0,get:function(){return a.idShuffle}});const i=r(792);Object.defineProperty(e,"addCom",{enumerable:!0,get:function(){return i.addCom}}),Object.defineProperty(e,"adjNum",{enumerable:!0,get:function(){return i.adjNum}}),Object.defineProperty(e,"priceVariations",{enumerable:!0,get:function(){return i.priceVariations}}),Object.defineProperty(e,"nTxtAr",{enumerable:!0,get:function(){return i.nTxtAr}}),Object.defineProperty(e,"rNum",{enumerable:!0,get:function(){return i.rNum}}),Object.defineProperty(e,"zNum",{enumerable:!0,get:function(){return i.zNum}}),Object.defineProperty(e,"sharpeRatio",{enumerable:!0,get:function(){return i.sharpeRatio}}),Object.defineProperty(e,"pNum",{enumerable:!0,get:function(){return i.pNum}}),Object.defineProperty(e,"isEven",{enumerable:!0,get:function(){return i.isEven}});const s=r(125);Object.defineProperty(e,"oneSec",{enumerable:!0,get:function(){return s.oneSec}}),Object.defineProperty(e,"oneDay",{enumerable:!0,get:function(){return s.oneDay}}),Object.defineProperty(e,"oneHr",{enumerable:!0,get:function(){return s.oneHr}}),Object.defineProperty(e,"oneMin",{enumerable:!0,get:function(){return s.oneMin}}),Object.defineProperty(e,"oneMon",{enumerable:!0,get:function(){return s.oneMon}}),Object.defineProperty(e,"seoDt",{enumerable:!0,get:function(){return s.seoDt}}),Object.defineProperty(e,"dayRes",{enumerable:!0,get:function(){return s.dayRes}}),Object.defineProperty(e,"invDt",{enumerable:!0,get:function(){return s.invDt}}),Object.defineProperty(e,"fullDt",{enumerable:!0,get:function(){return s.fullDt}}),Object.defineProperty(e,"fullDate",{enumerable:!0,get:function(){return s.fullDate}}),Object.defineProperty(e,"fullLong",{enumerable:!0,get:function(){return s.fullLong}}),Object.defineProperty(e,"shortDt",{enumerable:!0,get:function(){return s.shortDt}}),Object.defineProperty(e,"moYrDt",{enumerable:!0,get:function(){return s.moYrDt}}),Object.defineProperty(e,"tmAP",{enumerable:!0,get:function(){return s.tmAP}}),Object.defineProperty(e,"tmUTC",{enumerable:!0,get:function(){return s.tmUTC}}),Object.defineProperty(e,"monNm",{enumerable:!0,get:function(){return s.monNm}}),Object.defineProperty(e,"tN",{enumerable:!0,get:function(){return s.tN}}),Object.defineProperty(e,"addZ",{enumerable:!0,get:function(){return s.addZ}}),Object.defineProperty(e,"timeStandard",{enumerable:!0,get:function(){return s.timeStandard}}),Object.defineProperty(e,"dateStandard",{enumerable:!0,get:function(){return s.dateStandard}}),Object.defineProperty(e,"thisYear",{enumerable:!0,get:function(){return s.thisYear}});const c=r(794);Object.defineProperty(e,"objSort",{enumerable:!0,get:function(){return c.objSort}}),Object.defineProperty(e,"objLen",{enumerable:!0,get:function(){return c.objLen}}),Object.defineProperty(e,"objNestValueCount",{enumerable:!0,get:function(){return c.objNestValueCount}}),Object.defineProperty(e,"restoreObj",{enumerable:!0,get:function(){return c.restoreObj}}),Object.defineProperty(e,"restoreObjStr",{enumerable:!0,get:function(){return c.restoreObjStr}}),Object.defineProperty(e,"storeObj",{enumerable:!0,get:function(){return c.storeObj}}),Object.defineProperty(e,"storeObjStr",{enumerable:!0,get:function(){return c.storeObjStr}}),Object.defineProperty(e,"objSortSimple",{enumerable:!0,get:function(){return c.objSortSimple}})})(),n})()}};const t={};function r(n){const o=t[n];if(void 0!==o)return o.exports;const a=t[n]={exports:{}};return e[n].call(a.exports,a,a.exports,r),a.exports}var n,o,a,i,s,c,l,u;let d;r.m=e,r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.f={},r.e=e=>{const t=[];return r.f.j(e,t),Promise.all(t)},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={520:()=>import("./engine-litert.min.mjs"),924:()=>import("./engine-wllama.min.mjs")},t={792:0},n=e=>{let{__webpack_esm_ids__:n,__webpack_esm_modules__:o,__webpack_esm_runtime__:a}=e;var i,s,c=0;for(i in o)r.o(o,i)&&(r.m[i]=o[i]);for(a&&a(r);c<n.length;c++)s=n[c],r.o(t,s)&&t[s]&&t[s][0](),t[s]=0};r.f.j=(o,a)=>{let i=r.o(t,o)?t[o]:void 0;if(0!==i)if(i)a.push(i[1]);else{let r=e[o]().then(n,e=>{throw 0!==t[o]&&(t[o]=void 0),e});r=Promise.race([r,new Promise(e=>i=t[o]=[e])]),a.push(i[1]=r)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(n||(n={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(o||(o={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(a||(a={})),function(e){e.cpu="cpu",e.gpu="gpu",e.none="none"}(i||(i={})),function(e){e.download="download",e.load="load"}(s||(s={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b",e.gemma4_e2b="gemma4-e2b"}(c||(c={})),function(e){e.websearch="websearch",e.calculate="calculate",e.currency="currency"}(l||(l={})),function(e){e.wikipedia="wikipedia",e.duckduckgo="duckduckgo"}(u||(u={}));const f=[{id:c.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}},{id:c.gemma4_e2b,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it.litertlm",vision:!0,audio:!0,tools:!0,web:{file:"gemma-4-E2B-it-gpu.litertlm",vision:!1,audio:!1,tools:!0}}}],m=e=>{const t=e??("undefined"==typeof navigator?void 0:navigator);if(!t)return!1;if("boolean"==typeof t.userAgentData?.mobile)return t.userAgentData.mobile;const r=t.userAgent||"";return/Android|iPhone|iPad|iPod|Mobile/i.test(r)||/Macintosh/.test(r)&&t.maxTouchPoints>1},p=(e,t=m())=>{const r=e.litert;if(r)return t&&r.web?r.web:{file:r.file,vision:r.vision,audio:r.audio,tools:r.tools}},g=e=>e?f.find(t=>t.id==e):void 0,h=async()=>(d||(d=(async()=>(await(async()=>{const e="undefined"==typeof navigator?void 0:navigator.gpu;if(!e)return!1;let t;try{return!!await Promise.race([e.requestAdapter({powerPreference:"high-performance"}),new Promise(e=>{t=setTimeout(()=>e(void 0),1500)})])}catch{return!1}finally{t&&clearTimeout(t)}})()?f.find(e=>!!e.litert):f.find(e=>!!e.cpu))?.id)()),await d),y=async e=>g(e||await h()),w=(e,t=m())=>!!e.cpu?.mmproj||!0===p(e,t)?.vision,b=(e,t=m())=>!!e.cpu?.mmproj?.audio||!0===p(e,t)?.audio,v=(e,t=m())=>!0===p(e,t)?.tools,x=new URL("./../assets/wllama/wllama.wasm",import.meta.url).href,j=new URL("./../assets/wllama/compat/wllama.wasm",import.meta.url).href,M=new URL("./../assets/wllama/compat/wllama.js",import.meta.url).href,k=new URL("./../assets/litert/litertlm_wasm_internal.js",import.meta.url).href,P=(new URL("./../assets/litert/litertlm_wasm_internal.wasm",import.meta.url).href,288),T=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),r=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!r.includes(";base64"))return await(await fetch(e)).arrayBuffer();const n=atob(e.slice(t+1)),o=new Uint8Array(n.length);for(let e=0;e<n.length;e++)o[e]=n.charCodeAt(e);return o.buffer},O=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),r=await createImageBitmap(await t.blob()),n=Math.min(r.width,r.height),o=Math.floor((r.width-n)/2),a=Math.floor((r.height-n)/2),i=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const r=document.createElement("canvas");return r.width=e,r.height=t,r})(P,P),s=i?i.getContext("2d"):null;if(!i||!s||n<1)return r.close(),e;if(s.drawImage(r,o,a,n,n,0,0,P,P),r.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(i)){const t=await i.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const r=new FileReader;r.onerror=()=>t(""),r.onload=()=>t(`${r.result}`),r.readAsDataURL(e)}))(t)||e}return i.toDataURL("image/jpeg",.85)}catch{return e}},S={maxReplyTokens:250,maxThinkingTokens:128,maxReasoningTokens:320,maxImages:2,maxAudio:1,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:6},C=(e,t,r)=>"number"==typeof e&&Number.isFinite(e)&&e>=r?Math.floor(e):t,N=(e={},t=!1)=>{const r=S;return{maxReplyTokens:C(e.maxReplyTokens,r.maxReplyTokens,1),maxThinkingTokens:C(e.maxThinkingTokens,r.maxThinkingTokens,1),maxReasoningTokens:C(e.maxReasoningTokens,t?1200:r.maxReasoningTokens,1),maxImages:C(e.maxImages,r.maxImages,0),maxAudio:C(e.maxAudio,r.maxAudio,0),maxContentLength:C(e.maxContentLength,r.maxContentLength,1),promptCharBudget:C(e.promptCharBudget,r.promptCharBudget,1),maxThreads:C(e.maxThreads,r.maxThreads,1)}},E=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),_=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,A=e=>Number(e.headers.get("content-length"))||0,D=(e,t)=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>e.type==t)),L=e=>D(e,"image"),R=e=>D(e,"audio"),$=["<|channel>thought\n","<|channel>thought","..."],U=["<channel|>","..."],q=(e,t,r)=>t.length||r.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e})),...r.map(e=>({type:"audio",url:e}))]:e,z=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,F=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const r=[];for(const n of[...z(e),{type:"text",text:"\n"},...z(t)]){const e=r[r.length-1];"text"==n.type&&"text"==e?.type?e.text+=n.text:r.push(n)}return r};class I extends Error{}const W=async(e,t,r)=>{let n;try{return await Promise.race([e,new Promise((e,o)=>{n=setTimeout(()=>o(new I(r)),t)})])}finally{n&&clearTimeout(n)}},V=e=>{try{Promise.resolve(e.return?.()).catch(()=>{})}catch{}},B=async({model:e,logging:t,onReason:r,onText:n,onSpeed:o,start:a,stopped:i,firstTimeoutMs:s=18e4,idleTimeoutMs:c=3e4,onStall:l})=>{let u="",d="",f="",m=!1,p=0,g=0;const h=((e,t)=>{let r="",n=!1;const o=(e,t)=>{let r=-1,n="";for(const o of t){const t=e.indexOf(o);t>=0&&(r<0||t<r)&&(r=t,n=o)}return{at:r,tag:n}},a=(e,t)=>{let r="";for(const n of t)for(let t=Math.min(e.length,n.length-1);t>r.length;t--)if(e.endsWith(n.slice(0,t))){r=e.slice(e.length-t);break}return r};return{feed:i=>{let s=r+i;for(r="";s;){if(n){const{at:t,tag:i}=o(s,U);if(t>=0){t&&e(s.slice(0,t)),s=s.slice(t+i.length),n=!1;continue}const c=a(s,U);e(s.slice(0,s.length-c.length)),r=c;break}{const{at:e,tag:i}=o(s,$);if(e>=0){e&&t(s.slice(0,e)),s=s.slice(e+i.length),s.startsWith("\n")&&(s=s.slice(1)),n=!0;continue}const c=a(s,$);t(s.slice(0,s.length-c.length)),r=c;break}}},flush:()=>{r&&(n?e(r):t(r),r="")}}})(e=>{d+=e,r(e)},e=>{u+=e,n(e)});try{const e=(await W(a(),s,"Model did not start"))[Symbol.asyncIterator]();for(;;){if(i()){V(e);break}let n;try{n=await W(e.next(),m?c:s,m?"Model stopped responding":"Model did not reply")}catch(r){if(r instanceof I&&(u||d)){l?.(),V(e),t&&console.log("Local chat stalled",r);break}throw r}if(n.done)break;m=!0;const a=n.value?.choices?.[0],y=a?.delta,w="string"==typeof y?.reasoning_content?y.reasoning_content:"string"==typeof y?.reasoning?y.reasoning:"";if(a?.finish_reason&&(f=a.finish_reason),w&&(d+=w,r(w)),y?.content&&h.feed(y.content),w||y?.content){const e=performance.now();p||(g=e),p+=1,p>1&&e>g&&o?.(1e3*p/(e-g))}}h.flush()}catch(e){if(t&&console.log("Local chat failed",e),!i())throw e}const y=i()?void 0:u||void 0;return t&&(console.log("Local chat reply",e.id,y?"****":""),console.log("Local chat finish",e.id,f||"none",u.length,d.length)),y},H=async({model:e,params:t,start:r,stopped:o,onStall:a})=>{const i=await(async e=>{const t=[];for(const r of e){if("string"==typeof r.content){t.push(r);continue}const e=[];for(const t of r.content)e.push("image"==t.type?{type:"image",url:await O(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=S)=>{const r=t.maxContentLength,o=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=n.user||!e.images?.length&&!e.audio?.length)),a=[],i=[];let s=0,c=t.maxImages,l=t.maxAudio;for(let e=o.length-1;e>=0;e--){const u=o[e],d=("string"==typeof u.content?u.content:"").slice(0,r),f=u.role==n.user?(u.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[],m=u.role==n.user?(u.audio||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,l)):[];if(d||f.length||m.length){if(d&&s+d.length>t.promptCharBudget)break;s+=d.length,c-=f.length,l-=m.length,u.role==n.system?a.unshift(d):u.role==n.assistant?i.unshift({role:"assistant",content:d}):i.unshift({role:"user",content:q(d,f,m)})}}for(;i.length&&"user"!=i[0].role;)i.shift();const u=[];for(const e of i){const t=u[u.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=F(t.content,e.content):"assistant"==e.role?u.push({role:"assistant",content:e.content}):u.push({role:"user",content:e.content})}const d=a.join("\n\n"),f=[];return d&&f.push({role:"system",content:d}),f.push(...u),f})(t.messages,t.limits));return t.logging&&((e,t)=>{console.log("Local chat call",e.id,t.map(({role:e,content:t})=>({role:e,content:"****",...Array.isArray(t)?{images:t.filter(e=>"image"==e.type).length,audio:t.filter(e=>"audio"==e.type).length}:{}})))})(e,i),await B({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,onSpeed:t.onSpeed,start:()=>r(i),stopped:o,onStall:a})},Y=33554432,G=new Map;let J=!1;const Q=e=>{const t=(e.split("/").pop()||"model").replace(/[^\w.-]+/g,"_");let r=0;for(let t=0;t<e.length;t++)r=31*r+e.charCodeAt(t)>>>0;return`${r.toString(16)}-${t}`},Z=e=>{const t=/^part-(\d+)$/.exec(e);return t?Number(t[1]):-1},K=async()=>{if(!J)if("undefined"!=typeof navigator&&navigator.storage?.getDirectory)try{return await navigator.storage.getDirectory()}catch{return}else J=!0},X=async(e,t)=>{try{return await e.getDirectoryHandle(t)}catch{return}},ee=async e=>{if(e)try{const t=await e.getFile(),r=JSON.parse(await t.text());return{total:Number(r.total)||0,etag:`${r.etag||""}`,complete:!0===r.complete}}catch{return}},te=async(e,t)=>{try{const r=await e.getFileHandle("meta.json",{create:!0}),n=await r.createWritable();await n.write(JSON.stringify(t)),await n.close()}catch{}},re=async function*(e){for await(const t of e)yield t},ne=async e=>{try{for await(const[t,r]of re(e))"file"==r.kind&&Z(t)>=0&&await e.removeEntry(t).catch(()=>{})}catch{}},oe=async(e,t)=>{try{const r=await(await e.getFileHandle(t)).getFile(),n=await ee(await e.getFileHandle(`${t}.json`).catch(()=>{}));if(!n)return;return{file:r,size:r.size,total:n.total,etag:n.etag,complete:n.total?r.size>=n.total:!0===n.complete}}catch{return}},ae=async(e,t)=>{const r=await X(e,t);if(r){const e=await(async e=>await ee(await e.getFileHandle("meta.json").catch(()=>{})))(r),t=await(async e=>{const t=[];try{for await(const[r,n]of re(e)){const e=Z(r);if("file"!=n.kind||e<0)continue;const o=await n.getFile();t.push({part:{start:e,size:o.size},file:o})}}catch{return}const r=(e=>{const t=[];let r=0;for(const n of[...e].sort((e,t)=>e.start-t.start))if(n.size){if(n.start!=r)break;t.push(n),r+=n.size}return t})(t.map(e=>e.part)),n=new Set(r.map(e=>e.start)),o=t.filter(e=>n.has(e.part.start)).sort((e,t)=>e.part.start-t.part.start).map(e=>e.file);if(o.length)return{file:1==o.length?o[0]:new Blob(o),size:r.reduce((e,t)=>e+t.size,0)}})(r),n=e?.total||0,o=t?.size??0,a=t?.file??new Blob;return{file:n&&o>n?a.slice(0,n):a,size:o,total:n,etag:e?.etag||"",complete:n?o>=n:!0===e?.complete}}return await oe(e,t)},ie=(e,t)=>{const r=e.headers.get("content-range"),n=/bytes (\d+)-/.exec(r||""),o=/\/(\d+)\s*$/.exec(r||""),a=e.headers.get("etag")||"";if(206==e.status){const e=n?Number(n[1]):t.size,r=o?Number(o[1]):t.total;if(e!=t.size)return;if(t.total&&r&&t.total!=r)return;if(t.etag&&a&&t.etag!=a)return;return{start:e,total:r||t.total,etag:a||t.etag}}if(!t.etag||!a||t.etag==a)return{start:0,total:A(e)||t.total,etag:a||t.etag}},se=async({dir:e,start:t,skip:r,total:n,body:o,onProgress:a,onChunk:i})=>{let c,l=t,u=0,d=r;const f=async()=>{const t=await e.getFileHandle((e=>`part-${e}`)(l),{create:!0});c=await t.createWritable(),u=0},m=async()=>{const e=c;c=void 0,e&&await e.close().catch(()=>{})};try{const e=o.getReader();for(;;){const{done:r,value:o}=await e.read();if(r)break;i();let p=0;for(d&&(p=Math.min(d,o.byteLength),d-=p);p<o.byteLength;){c||await f();const e=Math.min(Y-u,o.byteLength-p);await c.write({type:"write",position:u,data:o.subarray(p,p+e)}),p+=e,u+=e,l+=e,u==Y&&await m()}l>t&&a(n?l/n:0,s.download)}await m()}catch(e){throw await m(),e}return l},ce=e=>["NotAllowedError","NotSupportedError"].includes(e?.name||""),le=e=>{const t=async()=>{const t=await K();if(t)try{return await t.getDirectoryHandle(e,{create:!0})}catch{return}};return{stored:async e=>{const r=await t();return r?await ae(r,Q(e)):void 0},download:async({url:r,signal:n,onProgress:o})=>{const a=`${e}|${r}`,i=G.get(a);if(i)return await i;const c=await t();if(!c)return;const l=(async(e,t,r,n)=>{const o=Q(t),a=await oe(e,o);if(a?.complete)return a;let i=await X(e,o);i||(await e.removeEntry(o).catch(()=>{}),await e.removeEntry(`${o}.json`).catch(()=>{}),i=await e.getDirectoryHandle(o,{create:!0}));let c=0,l=0;for(;;){if(r?.aborted)throw new Error("Cancelled");const a=await ae(e,o);if(a?.complete)return a;const u=a?.size??0,d=a?.total||0,f=a?.etag||"";if(u>c)c=u,l=0;else if(++l>4)throw new Error("Model download failed");u&&d&&n(u/d,s.download);const m=d?Math.min(u+Y,d)-1:u+Y-1,p=new AbortController,g=()=>p.abort(),h={size:u,total:d,etag:f};let y,w=setTimeout(g,3e4);r?.addEventListener("abort",g,{once:!0});try{if(y=await fetch(t,{signal:p.signal,headers:{Range:`bytes=${u}-${m}`}}),416==y.status){if(await(y.body?.cancel().catch(()=>{})),d&&u>=d){await te(i,{total:d,etag:f,complete:!0});continue}await ne(i),await te(i,{total:0,etag:"",complete:!1});continue}if(!y.ok||!y.body)throw await(y.body?.cancel().catch(()=>{})),new Error("Model download failed");const r=ie(y,h);if(!r){await y.body.cancel().catch(()=>{}),await ne(i),await te(i,{total:0,etag:"",complete:!1});continue}await te(i,{total:r.total,etag:r.etag,complete:!1});const a=0==r.start?u:0,s=await se({dir:i,start:r.start+a,skip:a,total:r.total,body:y.body,onProgress:n,onChunk:()=>{clearTimeout(w),w=setTimeout(g,3e4)}});if(!r.total){await te(i,{total:s,etag:r.etag,complete:!0});const t=await ae(e,o);if(t)return t}}catch(e){if(r?.aborted)throw new Error("Cancelled");if(e instanceof DOMException&&["QuotaExceededError","NotAllowedError","NotSupportedError","InvalidStateError","TypeMismatchError","SecurityError"].includes(e.name))throw e;await new Promise(e=>setTimeout(e,250+500*l))}finally{clearTimeout(w),r?.removeEventListener("abort",g)}}})(c,r,n,o).finally(()=>{G.delete(a)});return G.set(a,l),await l},remove:async e=>{const r=await t();r&&await(async(e,t)=>{await e.removeEntry(t,{recursive:!0}).catch(()=>{}),await e.removeEntry(`${t}.json`).catch(()=>{})})(r,Q(e))},purge:async()=>{const t=await K();t&&await t.removeEntry(e,{recursive:!0}).catch(()=>{})}}},ue="litertlm-models",de=[4096,2048,1024],fe=le("litert-store"),me={num_output_candidates:1,wait_for_weight_uploads:!0,num_decode_steps_per_sync:3,sequence_batch_size:0,supported_lora_ranks:[],max_top_k:40,enable_decode_logits:!1,enable_external_embeddings:!1,use_submodel:!1,use_autosized_ringbuffers:!0};let pe=!1;const ge=(...e)=>{pe&&console.log(...e)},he=(...e)=>{pe&&console.error(...e)},ye=e=>{const t=e.mod.getGlobalLiteRtLm().liteRtLmWasm.preinitializedWebGPUDevice;e.device=t,e.lost=!1,t&&t.lost.then(()=>{e.device==t&&(e.lost=!0)})},we=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(ue)}catch{return}},be=async e=>{const t=globalThis,r=t.Module;t.Module={print:ge,printErr:he};try{await e.getOrLoadGlobalLiteRtLm(k)}finally{t.Module=r}},ve=new Map,xe=(e,t,r)=>{let n=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{n+=e.byteLength,r(t?n/t:0,s.download),o.enqueue(e)}}))},je=async({url:e,signal:t,onProgress:r})=>{const n=await we();let o;const a=n?await n.match(e):void 0;if(a?.body)o=a.body;else{const t=await fe.stored(e);t?.complete&&(o=t.file.stream())}if(!o){const n=await fe.download({url:e,signal:t,onProgress:r}).catch(e=>{if(t?.aborted)throw new Error("Cancelled");if(!ce(e))throw e;pe&&console.log("Local model store failed",e)});n&&(o=n.file.stream())}if(!o&&n)try{await(async(e,t,r,n)=>{const o=ve.get(e);if(o)return await o;const a=(async()=>{const o=await fetch(e,{signal:r});if(!o.ok||!o.body)throw new Error("Model download failed");const a=A(o),i=xe(o.body,a,n);await t.put(e,new Response(i,{headers:{"content-type":"application/octet-stream",...a?{"content-length":`${a}`}:{}}}))})().finally(()=>{ve.delete(e)});return ve.set(e,a),await a})(e,n,t,r);const a=await n.match(e);a?.body&&(o=a.body)}catch(e){if(t?.aborted)throw new Error("Cancelled");pe&&console.log("Local model cache failed",e)}return o||(o=await(async(e,t,r)=>{const n=await fetch(e,{signal:t});if(!n.ok||!n.body)throw new Error("Model download failed");return xe(n.body,A(n),r)})(e,t,r)),o},Me=async(e,t=!0)=>{const r=[];for(const n of e){if("string"==typeof n.content){r.push({role:n.role,content:n.content});continue}const e=[];for(const r of n.content)"text"!=r.type?t?e.push({type:r.type,data:await T(r.url)}):e.push({type:"text",text:`[${r.type}]`}):e.push({type:"text",text:r.text});r.push({role:n.role,content:e})}return r},ke=(e,t)=>{if(e.role!=t.role)return!1;if("string"==typeof e.content||"string"==typeof t.content)return e.content==t.content;if(e.content.length!=t.content.length)return!1;for(let r=0;r<e.content.length;r++){const n=e.content[r],o=t.content[r];if(n.type!=o.type)return!1;if("text"==n.type&&"text"==o.type){if(n.text!=o.text)return!1}else if(("image"==n.type&&"image"==o.type||"audio"==n.type&&"audio"==o.type)&&n.url!=o.url)return!1}return!0},Pe=e=>({type:"function",function:{name:e.name,...void 0===e.description?{}:{description:e.description},...void 0===e.parameters?{}:{parameters:e.parameters}},execute:e.execute}),Te=async function*({engine:e,mod:t,params:r,messages:n,session:o}){const a=n[n.length-1],i=E(r.limits,r.reasoning),s=r.tools??[];if("user"!=a?.role)throw new Error("No user turn");const c=n.slice(0,-1),l=(await Me([a]))[0];if(!l)throw new Error("Empty prompt");const u=!!o.conversation&&o.reasoning==r.reasoning&&o.maxTokens==i.max_tokens&&((e=[],t=[])=>{if(e.length!=t.length)return!1;for(let r=0;r<e.length;r++){const n=e[r],o=t[r];if(n.name!=o.name)return!1;if(n.description!=o.description)return!1;if(n.execute!==o.execute)return!1;if(JSON.stringify(n.parameters)!=JSON.stringify(o.parameters))return!1}return!0})(o.tools,s)&&((e,t)=>{const r="system"==e[0]?.role?e[0]:void 0,n="system"==t[0]?.role?t[0]:void 0;if(!r!=!n)return!1;if(r&&n&&!ke(r,n))return!1;const o=r?e.slice(1):e,a=n?t.slice(1):t;if(!a.length||a.length>o.length)return!1;const i=o.length-a.length;for(let e=0;e<a.length;e++)if(!ke(o[i+e],a[e]))return!1;return!0})(o.sent,c);let d;if(u&&o.conversation)d=o.conversation;else{const n=await Me(c,!1);o.conversation=void 0,o.sent=[];const a={sessionConfig:{maxOutputTokens:i.max_tokens,samplerParams:{type:t.SamplerType.TOP_K,temperature:i.temperature,k:40,p:.95}},preface:{...n.length?{messages:n}:{},extra_context:{enable_thinking:r.reasoning}},prefillPrefaceOnInit:n.length>0};d=s.length?new t.AutoToolChat({engine:e,config:a,tools:s.map(Pe),recurringToolCallLimit:(f=r.maxToolRounds,"number"==typeof f&&Number.isFinite(f)?Math.min(25,Math.max(1,Math.floor(f))):4),onToolProgress:e=>((e,t)=>{const r={id:t.id,name:t.name,arguments:t.arguments};"started"!=t.status?"completed"==t.status?e.onToolResult?.({...r,result:t.result}):e.onToolResult?.({...r,error:t.error||"Tool failed"}):e.onToolCall?.(r)})(r,e)}):await e.createConversation(a),o.conversation=d,o.reasoning=r.reasoning,o.maxTokens=i.max_tokens,o.tools=[...s],o.sent=[...c]}var f;o.sent.push(a);let m,p=!1,g="";const h=()=>{m&&m.cancel().catch(()=>{});try{d.cancel()}catch{}};r.signal?.addEventListener("abort",h,{once:!0});try{if(r.signal?.aborted)return;const e=d.sendMessageStreaming(l).getReader();for(m=e;;){const{done:t,value:r}=await e.read();if(t)break;const n={};let o="string"==typeof r.content?r.content:"";if(Array.isArray(r.content))for(const e of r.content)"text"==e.type&&(o+=e.text);o&&(n.content=o,g+=o);const a=r.channels?.thought;a&&(n.reasoning=a),(n.content||n.reasoning)&&(yield{choices:[{delta:n}]})}p=!0}finally{r.signal?.removeEventListener("abort",h),p&&g?o.sent.push({role:"assistant",content:g}):(o.conversation=void 0,o.sent=[])}},Oe=({model:e,limits:t,source:r,mod:n,contextTokens:o=4096})=>{const a=p(e);return{model:r,mainExecutorSettings:{maxNumTokens:o,...a?.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:me},...a?.vision?{visionBackend:n.Backend.GPU,maxVisionTokensPerImage:70,minVisionTokensPerImage:70}:{},...a?.audio?{audioBackend:n.Backend.CPU}:{}}},Se=async(e,t,r)=>{if(e.contextStep>=de.length-1)throw new Error("The graphics device was lost");try{await e.engine.delete()}catch{}e.mod.unloadLiteRtLm(),await be(e.mod),await e.mod.getGlobalLiteRtLm().setupDefaultWebGpuDevice(),e.contextStep+=1,e.engine=await e.mod.Engine.create(Oe({model:t,limits:r,source:await e.reopen(),mod:e.mod,contextTokens:de[e.contextStep]})),ye(e)},Ce={backend:i.gpu,startLLM:async({model:e,limits:t,onProgress:n,signal:o,logging:a})=>{pe=!0===a;const c=e.litert,l=p(e);if(!c||!l)throw new Error("Model has no LiteRT artifact");const u=await r.e(520).then(()=>r(507));if(await be(u),o?.aborted)throw new Error("Cancelled");const d=_(c.repo,l.file),f=await je({url:d,signal:o,onProgress:n});if(o?.aborted)throw new Error("Cancelled");n(1,s.load);const m=u.getGlobalLiteRtLm();m.liteRtLmWasm.preinitializedWebGPUDevice||await m.setupDefaultWebGpuDevice();const g={engine:await u.Engine.create(Oe({model:e,limits:t,source:f,mod:u})),mod:u,lost:!1,contextStep:0,reopen:()=>je({url:d,onProgress:()=>{}})};if(ye(g),o?.aborted)throw await g.engine.delete(),new Error("Cancelled");const h={sent:[],reasoning:!1,maxTokens:0};return{model:e,backend:i.gpu,contextSize:de[g.contextStep],chat:t=>(async({gpu:e,model:t,params:r,session:n})=>{pe=!0===r.logging;const o=()=>!!r.signal?.aborted,a=()=>{try{n.conversation?.cancel()}catch{}n.conversation=void 0,n.sent=[],n.tools=void 0},i=async()=>{try{return await H({model:t,params:r,stopped:o,onStall:a,start:async a=>{if(o())throw new Error("Cancelled");const i=p(t);if(L(a)&&!i?.vision)throw new Error("Model does not accept images");if(R(a)&&!i?.audio)throw new Error("Model does not accept audio");if(r.tools?.length&&!i?.tools)throw new Error("Model does not accept tools");return Te({engine:e.engine,mod:e.mod,params:r,messages:a,session:n})}})}catch(e){throw a(),e}};let s;try{s=await i()}catch(t){if(!e.lost&&!(e=>/device.*lost|lost.*device|vkQueueSubmit|device.*destroyed|aborted/i.test(`${e?.message||e}`))(t))throw t;e.lost=!0}return!e.lost||o()?s:(r.onRestart?.(),a(),await Se(e,t,r.limits),await i())})({gpu:g,model:e,params:t,session:h}),fatal:()=>g.lost,unload:async()=>{h.conversation=void 0,h.sent=[],h.tools=void 0;try{await g.engine.delete()}catch{}}}},cached:async e=>{const t=e.litert,r=p(e);if(!t||!r)return!1;const n=_(t.repo,r.file),[o,a]=await Promise.all([we(),fe.stored(n)]);if(a?.complete)return!0;try{return!(!o||!await o.match(n))}catch{return!1}},hasCache:async()=>{try{for(const e of f){const t=e.litert,r=p(e);if(!t||!r)continue;if(await fe.stored(_(t.repo,r.file)))return!0}const e=await we();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert,r=p(e);if(!t||!r)return;const n=_(t.repo,r.file),o=await we();await fe.remove(n),o&&await o.delete(n)}catch{}},purge:async()=>{try{await fe.purge(),"undefined"!=typeof caches&&await caches.delete(ue)}catch{}}},Ne=le("wllama-store");let Ee,_e,Ae="",De=!1;const Le=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,Re=e=>{const t={wasm:x,compatWasm:j,compatWorker:M};return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},$e=e=>{const t=e=>(...t)=>{De&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},Ue=async()=>{if(Ee)return Ee;const e=await r.e(924).then(()=>r(577)),t=_e||Re(),n=new e.Wllama({default:t.wasm},{logger:$e(e.LoggerWithoutDebug)});return _e||(_e=t,Ae=Le(t)),n.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),Ee=n,n},qe=async()=>{const e=Ee;Ee=void 0;try{await(e?.exit())}catch{}},ze=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),Fe=e=>{const t=e.cpu;return t?[{name:t.file,url:_(t.repo,t.file)},...t.mmproj?[{name:t.mmproj.file,url:_(t.repo,t.mmproj.file)}]:[]]:[]},Ie=async e=>{const t=Fe(e);if(!t.length)return!1;for(const e of t){const t=await Ne.stored(e.url);if(!t?.complete)return!1}return!0},We=async(e,t)=>{const r=await e.cacheManager.list();return Fe(t).every(e=>r.some(t=>ze(t,e.name)))},Ve=async({model:e,signal:t,onProgress:r})=>{const n=Fe(e),o=[];for(let e=0;e<n.length;e++){if(t?.aborted)throw new Error("Cancelled");const a=await Ne.download({url:n[e].url,signal:t,onProgress:(t,o)=>r((e+t)/n.length,o)});if(!a)return;o.push(a.file)}return o.length?o:void 0},Be=async e=>{const t=[];for(const r of e){if("string"==typeof r.content){"system"==r.role?t.push({role:"system",content:r.content}):"assistant"==r.role?t.push({role:"assistant",content:r.content}):t.push({role:"user",content:r.content});continue}const e=[];for(const t of r.content)"text"==t.type?e.push({type:"text",text:t.text}):e.push({type:t.type,data:await T(t.url)});t.push({role:"user",content:e})}return t},He={backend:i.cpu,startLLM:async({model:e,limits:t,onProgress:r,signal:n,logging:o,assets:a})=>{De=!0===o;const c=m()?4096:8192,l=e.cpu;if(!l)throw new Error("Model has no CPU artifact");const u=Re(a),d=Le(u);Ee&&d!=Ae&&await qe(),_e=u,Ae=d;const f=(p="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,g=l.mmproj?Math.min(t.maxThreads,2):t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(p||4)-1)),g)));var p,g;const h=await Ue(),y=await Ie(e),w=l.mmproj?.file,b=_(l.repo,l.file),v=w?_(l.repo,w):"";if(n?.aborted)throw await qe(),new Error("Cancelled");if(!y&&w){const e=await h.cacheManager.list(),t=e.some(e=>ze(e,l.file)),r=e.some(e=>ze(e,w));t&&!r&&await h.cacheManager.deleteMany(e=>ze(e,l.file))}const x={n_ctx:c,n_threads:f,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,jinja:!0};try{let t=y?await Ve({model:e,signal:n,onProgress:r}):void 0;t||y||await We(h,e).catch(()=>!1)||(t=await Ve({model:e,signal:n,onProgress:r}).catch(e=>{if(n?.aborted)throw new Error("Cancelled");if(!ce(e))throw e;o&&console.log("Local model store failed",e)})),t?(r(1,s.load),await h.loadModel(t,x)):await h.loadModelFromUrl(v?{url:b,mmprojUrl:v}:b,{...x,useCache:!0,signal:n,progressCallback:({loaded:e,total:t})=>{const n=t?e/t:0;r(n,n>=1?s.load:s.download)}})}catch(e){throw await qe(),e}if(n?.aborted)throw await qe(),new Error("Cancelled");if(!h.getLoadedContextInfo().n_ctx)throw await qe(),new Error("Failed to create model context");return{model:e,backend:i.cpu,contextSize:c,chat:t=>(async(e,t,r)=>{if(De=!0===r.logging,e.isModelLoaded())return await H({model:t,params:r,stopped:()=>!!r.signal?.aborted,start:async n=>{if(L(n)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");if(R(n)&&!e.supportInputModality("audio"))throw new Error("Model does not accept audio");return await e.createChatCompletion({messages:await Be(n),...E(r.limits,r.reasoning),abortSignal:r.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:r.reasoning}}:{}})}})})(h,e,t),unload:async()=>{if(Ee==h)await qe();else try{await h.exit()}catch{}}}},cached:async e=>{try{return!!e.cpu&&(!!await Ie(e)||await We(await Ue(),e))}catch{return!1}},hasCache:async()=>{try{for(const e of f.flatMap(e=>Fe(e)))if(await Ne.stored(e.url))return!0;const e=await Ue();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{const t=Fe(e);try{for(const e of t)await Ne.remove(e.url)}catch{}try{const e=await Ue();await e.cacheManager.deleteMany(e=>t.some(t=>ze(e,t.name)))}catch{}},purge:async()=>{try{await Ne.purge()}catch{}try{const e=await Ue();await e.cacheManager.clear()}catch{}}},Ye=((e={})=>{const t=e.engines?.cpu||He,r=e.engines?.litert||Ce;let n,o,c,l,u,d,m,p,g=i.none,h=a.idle,y=[],w=0,b={percent:0,phase:s.download};const v=n=>{if(e.backend!=i.none)return e.backend==i.cpu?n.cpu?t:void 0:e.backend==i.gpu?n.litert?r:void 0:n.litert&&"undefined"!=typeof navigator&&navigator.gpu&&"undefined"!=typeof WebAssembly?r:!n.cpu||"undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?void 0:t},x=(e,t)=>{b={percent:Math.max(0,Math.min(1,e)),phase:t||s.download};for(const e of[...y])e.report(b.percent,b.phase)},j=e=>{h=e},M=()=>{w++,d?.abort(),d=void 0,u=void 0,h==a.downloading&&j(a.idle)},k=(e,t)=>{const r=l;return r?new Promise(n=>{let o=!1;const a={report:e,settle:e=>{o||(o=!0,t?.removeEventListener("abort",i),n(e))}},i=()=>{(e=>{y=y.filter(t=>t!=e),queueMicrotask(()=>{!y.length&&l&&M()})})(a),a.settle(!1)};y.push(a),t?.aborted?i():t?.addEventListener("abort",i,{once:!0}),r.then(a.settle,()=>a.settle(!1))}):Promise.resolve(!1)},P=()=>h==a.ready&&!!n&&!!o,T=async()=>{const e=n;M(),n=void 0,o=void 0,c=void 0,j(a.idle),await(e?.unload())};return{load:async({model:e,limits:t,assets:r,logging:i,signal:p,onProgress:h})=>{if(p?.aborted)return!1;if(P()&&o?.id==e.id)return!0;if(l&&u==e.id)return h(b.percent,b.phase),await k(h,p);l&&(M(),y=[],await l.catch(()=>!1));const T=++w,O=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const l=v(e);if(T!=w)return!1;if(!l)return m="Model is not supported on this device",j(a.unsupported),!1;if(await(async(e,t)=>{if(o&&o.id!=e.id){const e=o,t=c,r=n;n=void 0,o=void 0,c=void 0,await(r?.unload()),await(t?.remove(e))}if(await t.hasCache())for(const r of f)r.id!=e.id&&v(r)==t&&await t.remove(r)})(e,l),T!=w)return!1;const u=await l.cached(e);if(T!=w)return!1;m=void 0,j(a.downloading),x(0,s.download),u&&x(1,s.load);const p=new AbortController;d=p;try{const u=await l.startLLM({model:e,limits:t,logging:i,signal:p.signal,assets:r,onProgress:(e,t)=>{T==w&&x(e,t)}});return T!=w||p.signal.aborted?(await u.unload(),!1):(n=u,o=e,c=l,g=l.backend,m=void 0,j(a.ready),x(1,s.load),!0)}catch(e){return T!=w||(n=void 0,o=void 0,c=void 0,m=`${e?.message||`${e}`}`,i&&console.log("Local model failed",e),j(a.error)),!1}finally{d==p&&(d=void 0)}})().finally(()=>{l==O&&(l=void 0,u=void 0,y=[])});return l=O,u=e.id,await k(h,p)},chat:async e=>{if(!P()||!n)return;for(;p;)await p.catch(()=>{});if(!P()||!n)return;const t=n,r=t.chat(e);p=r;try{return await r}catch(e){throw t.fatal?.()&&n==t&&(await T(),g=i.none,m=`${e?.message||`${e}`}`,j(a.error)),e}finally{p==r&&(p=void 0)}},unload:T,ready:P,loading:()=>!P()&&h==a.downloading,status:()=>h,backend:()=>g,error:()=>m,model:()=>o}})();var Ge=r(155);const Je=/^[0-9+\-*/%^().]+$/,Qe=e=>{let t=0;const r=e=>!!e&&e>="0"&&e<="9",n=e=>{throw new Error(e)},o=()=>{let o;for("("==e[t]?(t++,o=s(),")"!=e[t]&&n("Unbalanced parentheses"),t++):o=(()=>{const o=t;for(;r(e[t]);)t++;const a=e.slice(o,t);let i="";if("."==e[t]){t++;const n=t;for(;r(e[t]);)t++;i=e.slice(n,t)}return a||i?Number(`${a||"0"}.${i||"0"}`):n("Expected a number")})();"%"==e[t];)t++,o/=100;return o},a=()=>"+"==e[t]?(t++,a()):"-"==e[t]?(t++,-a()):(()=>{const r=o();return"^"!=e[t]?r:(t++,r**a())})(),i=()=>{let r=a();for(;"*"==e[t]||"/"==e[t];){const o=e[t];t++;const i=a();"*"==o?r*=i:(i||n("Division by zero"),r/=i)}return r},s=()=>{let r=i();for(;"+"==e[t]||"-"==e[t];){const n=e[t];t++;const o=i();r="+"==n?r+o:r-o}return r},c=s();return t<e.length&&n("Unexpected character"),Number.isFinite(c)||n("Result is not a finite number"),c},Ze={name:"calculate",description:"Evaluate an arithmetic expression. Supports + - * / % ^ and parentheses; % divides by 100.",parameters:{type:"object",properties:{expression:{type:"string",description:"Arithmetic expression, for example 2*(3+4)"}},required:["expression"]},execute:e=>{const t=e.expression;if("string"!=typeof t)throw new Error("Missing expression");return(e=>{if(e.trim().length>200)throw new Error("Expression is too long");const t=(e=>e.replace(/×/g,"*").replace(/÷/g,"/").replace(/−/g,"-").replace(/,/g,"").replace(/\s+/g,""))(e);if(!t)throw new Error("Expression is empty");if(!Je.test(t))throw new Error("Unsupported character");const r=Qe(t);return{expression:t,result:Math.abs(r)>=1e5?(0,Ge.pNum)(r)??r:(0,Ge.rNum)(r,12)}})(t)}},Ke="degreesign-chat-prices-v1",Xe="EUR",et=5*Ge.oneMin,tt=30*Ge.oneSec;let rt,nt={},ot=0,at=!1,it=!1;const st=e=>{const t={};for(const[r,n]of Object.entries(e??{}))"number"==typeof n&&Number.isFinite(n)&&(t[r.trim().toUpperCase()]=n);return t},ct=(e,t)=>e&&e.sourceAt>t.sourceAt?e:t,lt=async({fiat:e,crypto:t})=>{try{const r=await fetch("https://srv.coinexams.com/data.json");if(!r.ok)throw new Error(`Price feed failed with ${r.status}`);const n=await r.json(),o=Date.now(),a=e?((e,t)=>{const r=st(e.rates?.current),n=st(e.rates?.yesterday);if(Object.keys(r).length)return{fetchedAt:t,sourceAt:Number(e.rates?.date)||t,rates:r,yesterday:n}})(n,o):void 0,i=t?((e,t)=>{const r=e.coins??{},n={},o={};for(const[e,t]of Object.entries(r)){const r=e.trim().toUpperCase(),a=t?.pr,i=t?.yst;"number"==typeof a&&Number.isFinite(a)&&(n[r]=a),"number"==typeof i&&Number.isFinite(i)&&(o[r]=i)}if(Object.keys(n).length)return{fetchedAt:t,sourceAt:Number(e.date)||t,prices:n,yesterday:o}})(n,o):void 0;if(e&&!a)throw new Error("Price feed is unavailable");if(t&&!i)throw new Error("Price feed is unavailable");a&&(nt.fiat=ct(nt.fiat,a)),i&&(nt.crypto=ct(nt.crypto,i)),ot=0,at=!1,(()=>{try{if("undefined"==typeof localStorage)return;localStorage.setItem(Ke,JSON.stringify(nt))}catch{}})()}catch(e){throw ot=Date.now(),at=!0,e}},ut=e=>!!nt.crypto&&(e in nt.crypto.prices||e in nt.crypto.yesterday),dt=e=>!!nt.fiat&&(e in nt.fiat.rates||e in nt.fiat.yesterday),ft=async e=>{const t=(e=>{const t={fiat:!1,crypto:!1};for(const r of e){if(r==Xe)continue;const e=ut(r)||dt(r);!ut(r)&&e||(t.crypto=!0),ut(r)||(t.fiat=!0)}return t})(e),r=Date.now(),n=t.fiat&&r-(nt.fiat?.fetchedAt??0)>=Ge.oneHr,o=t.crypto&&r-(nt.crypto?.fetchedAt??0)>=et;(n||o)&&("undefined"!=typeof navigator&&!1===navigator.onLine||ot&&r-ot<tt||(rt||(rt=lt({fiat:n,crypto:o}).catch(()=>{}).finally(()=>{rt=void 0})),await rt))},mt=e=>{if(e==Xe)return 1;const t=nt.crypto?.yesterday[e],r=nt.fiat?.yesterday[e];return t||(r?1/r:void 0)},pt=(e,t)=>{if("string"!=typeof e||!e.trim())throw new Error(`Missing ${t}`);return e.trim().toUpperCase()},gt=e=>Math.abs(e)>=1e5?(0,Ge.pNum)(e)??e:(0,Ge.rNum)(e,8),ht=async e=>{(()=>{if(!it){it=!0;try{if("undefined"==typeof localStorage)return;const e=localStorage.getItem(Ke);if(!e)return;const t=JSON.parse(e);nt={...t.fiat?{fiat:t.fiat}:{},...t.crypto?{crypto:t.crypto}:{}}}catch{}}})();const t=pt(e.from,"from"),r=void 0===e.to||null===e.to?Xe:pt(e.to,"to"),n=(e=>{if(null==e)return 1;if("number"!=typeof e||!Number.isFinite(e))throw new Error("Invalid amount");return e})(e.amount);await ft([t,r]);const o=e=>{const t=(e=>{if(e==Xe)return 1;const t=nt.crypto?.prices[e],r=nt.fiat?.rates[e];return t||(r?1/r:void 0)})(e);if(void 0!==t)return t;if(!nt.fiat&&!nt.crypto)throw new Error("Prices unavailable offline");if(ut(e)||dt(e))throw new Error(`Unavailable quote for ${e}`);throw new Error(`Unknown symbol ${e}`)},a=o(t),i=o(r),s=mt(t),c=mt(r),l=a/i,u=s&&c?s/c:void 0,d=void 0===u?void 0:l-u,f=void 0===u?void 0:100*(l/u-1),m=(e=>{const t=[];for(const r of e)r!=Xe&&(ut(r)?nt.crypto&&t.push(nt.crypto.sourceAt):dt(r)&&nt.fiat&&t.push(nt.fiat.sourceAt));return t})([t,r]),p=m.length?Math.min(...m):Date.now();return{from:t,to:r,amount:n,rate:gt(l),...void 0===u?{}:{previousRate:gt(u),change:gt(d??0),changePercent:(0,Ge.rNum)(f??0,4)},result:gt(n*l),updatedAt:new Date(p).toISOString(),stale:at&&!(!nt.fiat&&!nt.crypto)}},yt={name:"currency",description:"Get the EUR price of a fiat currency, crypto coin or metal, or convert an amount. Returns the 24-hour change.",parameters:{type:"object",properties:{from:{type:"string",description:"Currency, coin or metal to convert from"},to:{type:"string",description:"Currency, coin or metal to convert to, EUR by default"},amount:{type:"number",description:"Amount to convert, 1 by default"}},required:["from"]},execute:e=>ht(e)},wt={amp:"&",apos:"'",gt:">",lt:"<",nbsp:" ",quot:'"',hellip:"...",mdash:"-",ndash:"-",ldquo:'"',lsquo:"'",rdquo:'"',rsquo:"'"},bt=(e,t,r,n)=>"number"==typeof e&&Number.isFinite(e)?Math.min(r,Math.max(t,e)):n,vt=(e,t)=>e.replace(/<[^>]*>/g," ").replace(/&(#x?[0-9a-f]+|[a-z]+);/gi,(e,t)=>{const r=(e=>{if(e.startsWith("#")){const t="x"==e[1]||"X"==e[1],r=parseInt(t?e.slice(2):e.slice(1),t?16:10);return r>0&&r<=1114111?String.fromCodePoint(r):e}return wt[e.toLowerCase()]??e})(t);return r==t?e:r}).replace(/\s+/g," ").trim().slice(0,Math.max(0,t)).trim(),xt=/^[a-z]{2,3}(-[a-z]{2,4})?$/i,jt=async(e,t)=>{const r=new AbortController,n=setTimeout(()=>r.abort(),t);try{const t=await fetch(e,{signal:r.signal});if(!t.ok)throw new Error(`Search failed with ${t.status}`);return await t.json()}catch(e){if(r.signal.aborted)throw new Error(`Search timed out after ${t} ms`);throw e}finally{clearTimeout(n)}},Mt=(e={})=>{const t=((e={})=>{const t=e.language?.trim()??"";return{provider:e.provider==u.duckduckgo?u.duckduckgo:u.wikipedia,language:xt.test(t)?t:"en",limit:Math.round(bt(e.limit,1,20,3)),snippetLength:Math.round(bt(e.snippetLength,1,4e3,400)),timeout:bt(e.timeout,1e3,3e4,8e3)}})(e);return{name:"websearch",description:t.provider==u.duckduckgo?"Search DuckDuckGo for an instant answer and related topics.":"Search Wikipedia and return a few matching articles.",parameters:{type:"object",properties:{query:{type:"string",description:"What to search for"}},required:["query"]},execute:async e=>{const r="string"==typeof e.query?e.query.trim():"";if(!r)throw new Error("Missing query");const n=t.provider==u.duckduckgo?await(async(e,t)=>{const r=`https://api.duckduckgo.com/?format=json&no_html=1&skip_disambig=1&q=${encodeURIComponent(t)}`,n=await jt(r,e.timeout),o=[],a=new Set,i=(t,r,n)=>{t&&n&&!a.has(t)&&(a.add(t),o.push({title:vt(r||n,200),url:t,snippet:vt(n,e.snippetLength)}))},s=e=>{for(const t of e)t.Topics?s(t.Topics):i(t.FirstURL,t.Text,t.Text)};i(n.AbstractURL,n.Heading||n.AbstractText,n.AbstractText);for(const e of n.Results??[])i(e.FirstURL,e.Text,e.Text);return s(n.RelatedTopics??[]),o.slice(0,e.limit)})(t,r):await(async(e,t)=>{const r=`https://${e.language}.wikipedia.org`,n=`${r}/w/rest.php/v1/search/page?q=${encodeURIComponent(t)}&limit=${e.limit}`,o=await jt(n,e.timeout),a=[];for(const t of o.pages??[]){const n=t.key;n&&a.push({title:vt(t.title??n,200),url:`${r}/wiki/${encodeURIComponent(n)}`,snippet:vt(`${t.description??""} ${t.excerpt??""}`,e.snippetLength)})}return a})(t,r);return n}}},kt=[l.websearch,l.calculate,l.currency],Pt=e=>{const t=e.tools??[],r=!1===e.builtins?[]:e.builtins??kt,n=new Set,o=[];for(const e of t){if(n.has(e.name))throw new Error(`Duplicate tool name ${e.name}`);n.add(e.name)}for(const t of((e,t)=>{const r=[];for(const n of e)n==l.websearch?r.push(Mt(t)):n==l.calculate?r.push(Ze):n==l.currency&&r.push(yt);return r})(r,e.websearch))n.has(t.name)||o.push(t);return o.push(...t),{tools:o,explicit:t.length>0}},Tt=(e,t,r)=>{const n=e.status(),i=g(t);return{availability:n==a.ready?o.online:n==a.error||n==a.unsupported?o.offline:o.away,status:n,backend:e.backend(),supportsImages:!!i&&w(i),supportsAudio:!!i&&b(i),supportsTools:!!i&&v(i),ready:e.ready(),loading:e.loading(),requesting:r.requesting,phase:r.phase,percent:r.percent,...r.error?{error:r.error}:{}}},Ot=(e=>{let t,r=0;const o=t=>t.input.onStatus?.(Tt(e,t.model??t.input.model,t));return i=>{t?.controller.abort();const c={token:++r,input:i,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?s.load:s.download,requesting:!1,cancelled:!1};return t=c,o(c),(async t=>{const{input:a}=t,i=!0===a.logging,c=await y(a.model);if(t.model=c?.id,t.token!=r)return;const l=a.messages.some(e=>e.role!=n.system&&"string"==typeof e.content&&!!e.content.trim()),u=a.messages.some(e=>e.role==n.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),d=a.messages.some(e=>e.role==n.user&&!!e.audio?.some(e=>"string"==typeof e&&!!e)),f=l||u||d;if(!c)return t.error="Unknown model",void o(t);if(!f)return t.error="No prompt",void o(t);const m=w(c),p=b(c);if(!(l||u&&m||d&&p))return d&&!p?t.error="Model does not accept audio":u&&!m&&(t.error="Model does not accept images"),void o(t);let g;try{g=Pt(a)}catch(e){return t.error=`${e?.message||`${e}`}`,void o(t)}const h=v(c);if(!h&&g.explicit)return t.error="Model does not accept tools",void o(t);const x=h?g.tools:[],j=N(a.limits,!!c.litert),M=await e.load({model:c,limits:j,logging:i,signal:t.controller.signal,onProgress:(e,n)=>{t.token==r&&(t.percent=Math.round(100*e),t.phase=n,o(t))}}).catch(e=>(t.token==r&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=r)return;if(t.cancelled)return;if(!M)return t.error||(t.error=e.error()||"Model not ready"),void o(t);const k=u&&!m||d&&!p?a.messages.map(({images:e,audio:t,...r})=>({...r,...e&&m?{images:e}:{},...t&&p?{audio:t}:{}})):a.messages;t.requesting=!0,t.error=void 0,t.percent=100,t.phase=s.load,o(t);let P,T="",O="";try{P=await e.chat({messages:k,limits:j,reasoning:!0===a.reasoning,logging:i,...x.length?{tools:x}:{},...void 0===a.maxToolRounds?{}:{maxToolRounds:a.maxToolRounds},onToolCall:e=>{t.token!=r||t.cancelled||a.onToolCall?.(e)},onToolResult:e=>{t.token!=r||t.cancelled||a.onToolResult?.(e)},onReason:e=>{t.token!=r||t.cancelled||(T+=e,a.onThinking?.(T))},onText:e=>{t.token!=r||t.cancelled||(O+=e,a.onResponse?.(O))},onRestart:()=>{T="",O="",a.onThinking?.(T),a.onResponse?.(O)},onSpeed:e=>{t.token!=r||t.cancelled||a.onSpeed?.(e)},signal:t.controller.signal})}catch(e){if(t.token!=r)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void o(t)}t.token==r&&(t.requesting=!1,P||t.cancelled||(t.error="No reply"),o(t))})(c),()=>(t=>{t.token==r&&(t.cancelled=!0,t.controller.abort(),e.status()!=a.ready?queueMicrotask(()=>o(t)):e.unload().then(()=>o(t)))})(c)}})(Ye),St=(Ct=Ye,async(e={})=>{const t=await y(e.model),r=r=>e.onStatus?.(Tt(Ct,t?.id,r));if(!t)return r({requesting:!1,phase:s.download,percent:0,error:"Unknown model"}),!1;let n,o=0,a=s.download;const i=Ct.ready()&&Ct.model()?.id==t.id;return await Ct.load({model:t,limits:N(e.limits,!!t.litert),logging:!0===e.logging,onProgress:(e,t)=>{o=Math.round(100*e),a=t,r({requesting:!1,phase:a,percent:o})}}).catch(e=>(n=`${e?.message||`${e}`}`,!1))?(i&&r({requesting:!1,phase:s.load,percent:100}),!0):(r({requesting:!1,phase:a,percent:o,error:n||Ct.error()||"Model not ready"}),!1)});var Ct;export{l as BuiltinTool,c as ChatModelId,o as ChatStatus,i as LlmBackend,s as LlmPhase,n as LlmRole,a as LlmStatus,u as WebSearchProvider,Ot as createChat,St as preloadModel};
|
package/dist/engines/litert.d.ts
CHANGED
|
@@ -1,16 +1,35 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ToolWithImplementation } from '@litert-lm/core';
|
|
2
|
+
import type { ChatModel, ChatTool, EngineChunk, EngineMessage, LitertChatParams, LitertGpu, LitertMessage, LitertSettings, LitertSettingsParams, LlmEngine, LlmLimits, StartLlmParams, StreamLitertParams } from '../types';
|
|
2
3
|
declare const
|
|
3
4
|
/** Smallest Gemma 4 vision budget in tokens */
|
|
4
5
|
visionTokens = 70;
|
|
6
|
+
/** Watch the live device, marking the engine dead when it is lost */
|
|
7
|
+
declare const watchDevice: (gpu: LitertGpu) => void;
|
|
5
8
|
/** Fetch one model file into the cache, once per URL */
|
|
6
9
|
declare const cacheModel: (url: string, cache: Cache, signal: AbortSignal | undefined, onProgress: StartLlmParams[`onProgress`]) => Promise<void>;
|
|
10
|
+
/** Open the model file, from a store, the cache or the network */
|
|
11
|
+
declare const openSource: ({ url, signal, onProgress, }: {
|
|
12
|
+
url: string;
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
onProgress: StartLlmParams[`onProgress`];
|
|
15
|
+
}) => Promise<ReadableStream<Uint8Array>>;
|
|
7
16
|
/** Map built messages to LiteRT turns */
|
|
8
17
|
declare const toLitertMessages: (messages: EngineMessage[], keepMedia?: boolean) => Promise<LitertMessage[]>;
|
|
9
18
|
/** Whether the live conversation already holds the incoming history */
|
|
10
19
|
declare const continuesHistory: (sent: EngineMessage[], history: EngineMessage[]) => boolean;
|
|
20
|
+
/** Clamp the tool round budget of one reply */
|
|
21
|
+
declare const toolRounds: (value?: number) => number;
|
|
22
|
+
/** Map one host or built-in tool to the engine tool shape */
|
|
23
|
+
declare const engineTool: (tool: ChatTool) => ToolWithImplementation;
|
|
24
|
+
/** Whether two lists declare the same tools and the same functions */
|
|
25
|
+
declare const sameTools: (first?: ChatTool[], next?: ChatTool[]) => boolean;
|
|
11
26
|
/** Stream one LiteRT reply as engine chunks */
|
|
12
27
|
declare const streamLitert: ({ engine, mod, params, messages, session, }: StreamLitertParams) => AsyncGenerator<EngineChunk>;
|
|
28
|
+
/** Stream one reply on a started GPU runtime */
|
|
29
|
+
declare const chatOn: ({ gpu, model, params, session, }: LitertChatParams) => Promise<string | undefined>;
|
|
13
30
|
/** Build one engine settings object with the small vision budget */
|
|
14
|
-
declare const litertSettings: ({ model, limits, source, mod, }: LitertSettingsParams) => LitertSettings;
|
|
31
|
+
declare const litertSettings: ({ model, limits, source, mod, contextTokens, }: LitertSettingsParams) => LitertSettings;
|
|
32
|
+
/** Rebuild the engine on a fresh device after a loss */
|
|
33
|
+
declare const rebuildGpu: (gpu: LitertGpu, model: ChatModel, limits: LlmLimits) => Promise<void>;
|
|
15
34
|
declare const litertEngine: LlmEngine;
|
|
16
|
-
export { cacheModel, continuesHistory, litertEngine, litertSettings, streamLitert, toLitertMessages, visionTokens, };
|
|
35
|
+
export { cacheModel, chatOn, continuesHistory, engineTool, litertEngine, litertSettings, openSource, rebuildGpu, sameTools, streamLitert, toLitertMessages, toolRounds, visionTokens, watchDevice, };
|
package/dist/enums.d.ts
CHANGED
|
@@ -34,4 +34,15 @@ declare enum ChatModelId {
|
|
|
34
34
|
qwen3_vl_2b = "qwen3-vl-2b",
|
|
35
35
|
gemma4_e2b = "gemma4-e2b"
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
/** Built-in tools the package ships */
|
|
38
|
+
declare enum BuiltinTool {
|
|
39
|
+
websearch = "websearch",
|
|
40
|
+
calculate = "calculate",
|
|
41
|
+
currency = "currency"
|
|
42
|
+
}
|
|
43
|
+
/** Search provider behind the websearch tool */
|
|
44
|
+
declare enum WebSearchProvider {
|
|
45
|
+
wikipedia = "wikipedia",
|
|
46
|
+
duckduckgo = "duckduckgo"
|
|
47
|
+
}
|
|
48
|
+
export { LlmRole, ChatStatus, LlmStatus, LlmBackend, LlmPhase, ChatModelId, BuiltinTool, WebSearchProvider, };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { createChat, preloadModel } from './chat';
|
|
2
|
-
export { LlmRole, ChatStatus, LlmStatus, LlmBackend, LlmPhase, ChatModelId, } from './enums';
|
|
3
|
-
export type { ChatMessage, LlmLimits, ChatStatusSnapshot, ChatInput, ChatPreloadInput, CancelChat, WllamaAssets, } from './types';
|
|
2
|
+
export { LlmRole, ChatStatus, LlmStatus, LlmBackend, LlmPhase, ChatModelId, BuiltinTool, WebSearchProvider, } from './enums';
|
|
3
|
+
export type { ChatMessage, LlmLimits, ChatStatusSnapshot, ChatInput, ChatPreloadInput, CancelChat, WllamaAssets, ChatTool, ChatToolCall, ChatToolResult, ChatToolSchema, ChatToolValue, WebSearchConfig, WebSearchResult, } from './types';
|
package/dist/models.d.ts
CHANGED
|
@@ -22,5 +22,7 @@ resolveLlmModel: (id?: ChatModelId) => Promise<ChatModel | undefined>,
|
|
|
22
22
|
/** Whether a model accepts images */
|
|
23
23
|
supportsImages: (model: ChatModel, mobile?: boolean) => boolean,
|
|
24
24
|
/** Whether a model accepts audio */
|
|
25
|
-
supportsAudio: (model: ChatModel, mobile?: boolean) => boolean
|
|
26
|
-
|
|
25
|
+
supportsAudio: (model: ChatModel, mobile?: boolean) => boolean,
|
|
26
|
+
/** Whether a model accepts tool declarations */
|
|
27
|
+
supportsTools: (model: ChatModel, mobile?: boolean) => boolean;
|
|
28
|
+
export { llmModels, cpuContextWindow, mobileCpuContextWindow, litertContextWindow, mobileDevice, litertArtifact, findLlmModel, gpuAdapter, defaultLlmModel, resolveLlmModel, supportsImages, supportsAudio, supportsTools, };
|