@degreesign/chat 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +175 -17
- package/dist/browser/chat.min.mjs +1 -1
- package/dist/browser/chat.min.mjs.LICENSE.txt +2 -0
- package/dist/engines/litert.d.ts +9 -2
- 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 +185 -7
- 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. |
|
|
@@ -317,10 +467,10 @@ without it goes quiet again.
|
|
|
317
467
|
|
|
318
468
|
## Models
|
|
319
469
|
|
|
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 |
|
|
470
|
+
| `ChatModelId` | Name | Reasoning | Images | Audio | Tools | CPU | WebGPU |
|
|
471
|
+
| ------------- | ---- | --------- | ------ | ----- | ----- | --- | ------ |
|
|
472
|
+
| `qwen3_vl_2b` | Qwen3-VL 2B | Yes | Yes | No | No | Yes | No |
|
|
473
|
+
| `gemma4_e2b` | Gemma 4 E2B | Yes | Desktop | Desktop | Yes | No | Yes |
|
|
324
474
|
|
|
325
475
|
A phone or tablet asking for Gemma gets the browser build,
|
|
326
476
|
`gemma-4-E2B-it-gpu.litertlm`, which is text only. It has no vision or audio
|
|
@@ -334,9 +484,9 @@ next attempt, including after a reload.
|
|
|
334
484
|
|
|
335
485
|
Qwen3-VL 2B downloads a vision projector of about 445 MB with the model, so its
|
|
336
486
|
total download is about 1.5 GB. It runs on the CPU engine, with a 4096 token
|
|
337
|
-
context on a phone and 8192 on a desktop. Its projector
|
|
338
|
-
|
|
339
|
-
images
|
|
487
|
+
context on a phone and 8192 on a desktop. Its projector runs on two CPU threads
|
|
488
|
+
because more threads stall the encoder, so its image turns are slower than the
|
|
489
|
+
Gemma 4 WebGPU path. Use the GPU model when images need to be fast.
|
|
340
490
|
|
|
341
491
|
Gemma 4 E2B downloads `gemma-4-E2B-it.litertlm`, about 2.6 GB, on a desktop. It
|
|
342
492
|
runs on the WebGPU engine with its vision and audio encoders in the same file,
|
|
@@ -528,9 +678,16 @@ const useReply = () => {
|
|
|
528
678
|
| `ChatStatusSnapshot` | Availability, engine status, backend, progress and request state. |
|
|
529
679
|
| `LlmLimits` | Token, prompt, image, audio and thread budgets, all overridable. |
|
|
530
680
|
| `WllamaAssets` | Wasm, compat wasm and compat worker URLs. |
|
|
681
|
+
| `ChatTool` | One tool: `name`, `description`, `parameters` and `execute`. |
|
|
682
|
+
| `ChatToolSchema` | The JSON-schema subset a tool parameter declares. |
|
|
683
|
+
| `ChatToolValue` | A JSON-safe argument or result value. |
|
|
684
|
+
| `ChatToolCall` | One model call: `id`, `name` and parsed `arguments`. |
|
|
685
|
+
| `ChatToolResult` | A finished call, with `result` or `error`. |
|
|
686
|
+
| `WebSearchConfig` | Provider, language, limit, snippet length and timeout. |
|
|
687
|
+
| `WebSearchResult` | One hit: `title`, `url` and `snippet`. |
|
|
531
688
|
|
|
532
689
|
The public enums are `ChatModelId`, `LlmRole`, `ChatStatus`, `LlmStatus`,
|
|
533
|
-
`LlmBackend` and `
|
|
690
|
+
`LlmBackend`, `LlmPhase`, `BuiltinTool` and `WebSearchProvider`.
|
|
534
691
|
|
|
535
692
|
## Architecture
|
|
536
693
|
|
|
@@ -578,10 +735,11 @@ includes no server component.
|
|
|
578
735
|
|
|
579
736
|
### Does it have runtime dependencies?
|
|
580
737
|
|
|
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
|
|
738
|
+
No runtime dependencies. `@wllama/wllama`, `@wllama/wllama-compat`,
|
|
739
|
+
`@litert-lm/core` and `@degreesign/utils` are build-time dependencies, bundled
|
|
740
|
+
into the dynamic engine chunks, the chat bundle and their wasm assets, so
|
|
741
|
+
consumers resolve no engine import and download no engine code beyond the chunk
|
|
742
|
+
they use.
|
|
585
743
|
|
|
586
744
|
### Where are the models stored?
|
|
587
745
|
|
|
@@ -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;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 l=[{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}}}],d=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},u=(e,t=d())=>{const n=e.litert;if(n)return t&&n.web?n.web:{file:n.file,vision:n.vision,audio:n.audio}},g=e=>e?l.find(t=>t.id==e):void 0,m=async()=>(await(async()=>{const e="undefined"==typeof navigator?void 0:navigator.gpu;if(!e)return!1;try{return!!await e.requestAdapter({powerPreference:"high-performance"})}catch{return!1}})()?l.find(e=>!!e.litert):l.find(e=>!!e.cpu))?.id,f=async e=>g(e||await m()),p=(e,t=d())=>!!e.cpu?.mmproj||!0===u(e,t)?.vision,h=(e,t=d())=>!!e.cpu?.mmproj?.audio||!0===u(e,t)?.audio,w=new URL("./../assets/wllama/wllama.wasm",import.meta.url).href,y=new URL("./../assets/wllama/compat/wllama.wasm",import.meta.url).href,b=new URL("./../assets/wllama/compat/wllama.js",import.meta.url).href,v=new URL("./../assets/litert/litertlm_wasm_internal.js",import.meta.url).href,x=(new URL("./../assets/litert/litertlm_wasm_internal.wasm",import.meta.url).href,288),k=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},_=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})(x,x),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,x,x),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}},M={maxReplyTokens:250,maxThinkingTokens:128,maxReasoningTokens:320,maxImages:2,maxAudio:1,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:6},T=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,E=(e={},t=!1)=>{const n=M;return{maxReplyTokens:T(e.maxReplyTokens,n.maxReplyTokens,1),maxThinkingTokens:T(e.maxThinkingTokens,n.maxThinkingTokens,1),maxReasoningTokens:T(e.maxReasoningTokens,t?1200:n.maxReasoningTokens,1),maxImages:T(e.maxImages,n.maxImages,0),maxAudio:T(e.maxAudio,n.maxAudio,0),maxContentLength:T(e.maxContentLength,n.maxContentLength,1),promptCharBudget:T(e.promptCharBudget,n.promptCharBudget,1),maxThreads:T(e.maxThreads,n.maxThreads,1)}},C=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),L=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,P=e=>Number(e.headers.get("content-length"))||0,$=(e,t)=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>e.type==t)),R=e=>$(e,"image"),j=e=>$(e,"audio"),S=["<|channel>thought\n","<|channel>thought","..."],A=["<channel|>","..."],B=(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,W=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,I=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...W(e),{type:"text",text:"\n"},...W(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n};class q extends Error{}const z=async(e,t,n)=>{let a;try{return await Promise.race([e,new Promise((e,o)=>{a=setTimeout(()=>o(new q(n)),t)})])}finally{a&&clearTimeout(a)}},O=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,A);if(t>=0){t&&e(s.slice(0,t)),s=s.slice(t+i.length),a=!1;continue}const c=r(s,A);e(s.slice(0,s.length-c.length)),n=c;break}{const{at:e,tag:i}=o(s,S);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,S);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 z(r(),s,"Model did not start"))[Symbol.asyncIterator]();for(;;){if(i()){O(e);break}let a;try{a=await z(e.next(),m?c:s,m?"Model stopped responding":"Model did not reply")}catch(n){if(n instanceof q&&(d||u)){l?.(),O(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 q&&!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},N=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 _(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=M)=>{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:B(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=I(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})},F=33554432,D=new Map;let H=!1;const Q=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}`},V=e=>{const t=/^part-(\d+)$/.exec(e);return t?Number(t[1]):-1},G=async()=>{if(!H)if("undefined"!=typeof navigator&&navigator.storage?.getDirectory)try{return await navigator.storage.getDirectory()}catch{return}else H=!0},J=async(e,t)=>{try{return await e.getDirectoryHandle(t)}catch{return}},K=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}},X=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{}},Y=async function*(e){for await(const t of e)yield t},Z=async e=>{try{for await(const[t,n]of Y(e))"file"==n.kind&&V(t)>=0&&await e.removeEntry(t).catch(()=>{})}catch{}},ee=async(e,t)=>{try{const n=await(await e.getFileHandle(t)).getFile(),a=await K(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}},te=async(e,t)=>{const n=await J(e,t);if(n){const e=await(async e=>await K(await e.getFileHandle("meta.json").catch(()=>{})))(n),t=await(async e=>{const t=[];try{for await(const[n,a]of Y(e)){const e=V(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 ee(e,t)},ne=(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:P(e)||t.total,etag:r||t.etag}},ae=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(F-d,o.byteLength-f);await c.write({type:"write",position:d,data:o.subarray(f,f+e)}),f+=e,d+=e,l+=e,d==F&&await m()}l>t&&r(a?l/a:0,s.download)}await m()}catch(e){throw await m(),e}return l},oe=e=>["NotAllowedError","NotSupportedError"].includes(e?.name||""),re=e=>{const t=async()=>{const t=await G();if(t)try{return await t.getDirectoryHandle(e,{create:!0})}catch{return}};return{stored:async e=>{const n=await t();return n?await te(n,Q(e)):void 0},download:async({url:n,signal:a,onProgress:o})=>{const r=`${e}|${n}`,i=D.get(r);if(i)return await i;const c=await t();if(!c)return;const l=(async(e,t,n,a)=>{const o=Q(t),r=await ee(e,o);if(r?.complete)return r;let i=await J(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 te(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+F,u)-1:d+F-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 X(i,{total:u,etag:g,complete:!0});continue}await Z(i),await X(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=ne(w,h);if(!n){await w.body.cancel().catch(()=>{}),await Z(i),await X(i,{total:0,etag:"",complete:!1});continue}await X(i,{total:n.total,etag:n.etag,complete:!1});const r=0==n.start?d:0,s=await ae({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 X(i,{total:s,etag:n.etag,complete:!0});const t=await te(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(()=>{D.delete(r)});return D.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,Q(e))},purge:async()=>{const t=await G();t&&await t.removeEntry(e,{recursive:!0}).catch(()=>{})}}},ie="litertlm-models",se=re("litert-store"),ce={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 le=!1;const de=(...e)=>{le&&console.log(...e)},ue=(...e)=>{le&&console.error(...e)},ge=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(ie)}catch{return}},me=new Map,fe=(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)}}))},pe=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 k(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},he=(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},we=async function*({engine:e,mod:t,params:n,messages:a,session:o}){const r=a[a.length-1],i=C(n.limits,n.reasoning);if("user"!=r?.role)throw new Error("No user turn");const s=a.slice(0,-1),c=(await pe([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&&!he(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(!he(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 pe(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=[])}},ye={backend:i.gpu,startLLM:async({model:e,limits:t,onProgress:a,signal:o,logging:r})=>{le=!0===r;const c=e.litert,l=u(e);if(!c||!l)throw new Error("Model has no LiteRT artifact");const d=await n.e(520).then(()=>n(507)),g=globalThis,m=g.Module;g.Module={print:de,printErr:ue};try{await d.getOrLoadGlobalLiteRtLm(v)}finally{g.Module=m}if(o?.aborted)throw new Error("Cancelled");const f=L(c.repo,l.file),p=await ge();let h;const w=p?await p.match(f):void 0;if(w?.body)h=w.body;else{const e=await se.stored(f);e?.complete&&(h=e.file.stream())}if(!h){const e=await se.download({url:f,signal:o,onProgress:a}).catch(e=>{if(o?.aborted)throw new Error("Cancelled");if(!oe(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=me.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=P(o),i=fe(o.body,r,a);await t.put(e,new Response(i,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{me.delete(e)});return me.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 fe(a.body,P(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=u(e);return{model:n,mainExecutorSettings:{maxNumTokens:4096,...o?.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:ce},...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})=>{le=!0===a.logging;const r=()=>{try{o.conversation?.cancel()}catch{}o.conversation=void 0,o.sent=[]};try{return await N({model:t,params:a,stopped:()=>!!a.signal?.aborted,onStall:r,start:async r=>{if(a.signal?.aborted)throw new Error("Cancelled");const i=u(t);if(R(r)&&!i?.vision)throw new Error("Model does not accept images");if(j(r)&&!i?.audio)throw new Error("Model does not accept audio");return we({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=u(e);if(!t||!n)return!1;const a=L(t.repo,n.file),[o,r]=await Promise.all([ge(),se.stored(a)]);if(r?.complete)return!0;try{return!(!o||!await o.match(a))}catch{return!1}},hasCache:async()=>{try{for(const e of l){const t=e.litert,n=u(e);if(!t||!n)continue;if(await se.stored(L(t.repo,n.file)))return!0}const e=await ge();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert,n=u(e);if(!t||!n)return;const a=L(t.repo,n.file),o=await ge();await se.remove(a),o&&await o.delete(a)}catch{}},purge:async()=>{try{await se.purge(),"undefined"!=typeof caches&&await caches.delete(ie)}catch{}}},be=re("wllama-store");let ve,xe,ke="",_e=!1;const Me=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,Te=e=>{const t={wasm:w,compatWasm:y,compatWorker:b};return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},Ee=e=>{const t=e=>(...t)=>{_e&&("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)}},Ce=async()=>{if(ve)return ve;const e=await n.e(924).then(()=>n(577)),t=xe||Te(),a=new e.Wllama({default:t.wasm},{logger:Ee(e.LoggerWithoutDebug)});return xe||(xe=t,ke=Me(t)),a.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),ve=a,a},Le=async()=>{const e=ve;ve=void 0;try{await(e?.exit())}catch{}},Pe=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),$e=e=>{const t=e.cpu;return t?[{name:t.file,url:L(t.repo,t.file)},...t.mmproj?[{name:t.mmproj.file,url:L(t.repo,t.mmproj.file)}]:[]]:[]},Re=async e=>{const t=$e(e);if(!t.length)return!1;for(const e of t){const t=await be.stored(e.url);if(!t?.complete)return!1}return!0},je=async(e,t)=>{const n=await e.cacheManager.list();return $e(t).every(e=>n.some(t=>Pe(t,e.name)))},Se=async({model:e,signal:t,onProgress:n})=>{const a=$e(e),o=[];for(let e=0;e<a.length;e++){if(t?.aborted)throw new Error("Cancelled");const r=await be.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},Ae=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 k(t.url)});t.push({role:"user",content:e})}return t},Be={backend:i.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{_e=!0===o;const c=d()?4096:8192,l=e.cpu;if(!l)throw new Error("Model has no CPU artifact");const u=Te(r),g=Me(u);ve&&g!=ke&&await Le(),xe=u,ke=g;const m=(f="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,p=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(f||4)-1)),p)));var f,p;const h=await Ce(),w=await Re(e),y=l.mmproj?.file,b=L(l.repo,l.file),v=y?L(l.repo,y):"";if(a?.aborted)throw await Le(),new Error("Cancelled");if(!w&&y){const e=await h.cacheManager.list(),t=e.some(e=>Pe(e,l.file)),n=e.some(e=>Pe(e,y));t&&!n&&await h.cacheManager.deleteMany(e=>Pe(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 Se({model:e,signal:a,onProgress:n}):void 0;t||w||await je(h,e).catch(()=>!1)||(t=await Se({model:e,signal:a,onProgress:n}).catch(e=>{if(a?.aborted)throw new Error("Cancelled");if(!oe(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 Le(),e}if(a?.aborted)throw await Le(),new Error("Cancelled");if(!h.getLoadedContextInfo().n_ctx)throw await Le(),new Error("Failed to create model context");return{model:e,backend:i.cpu,contextSize:c,chat:t=>(async(e,t,n)=>{if(_e=!0===n.logging,e.isModelLoaded())return await N({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if(R(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");if(j(a)&&!e.supportInputModality("audio"))throw new Error("Model does not accept audio");return await e.createChatCompletion({messages:await Ae(a),...C(n.limits,n.reasoning),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}})}})})(h,e,t),unload:async()=>{if(ve==h)await Le();else try{await h.exit()}catch{}}}},cached:async e=>{try{return!!e.cpu&&(!!await Re(e)||await je(await Ce(),e))}catch{return!1}},hasCache:async()=>{try{for(const e of l.flatMap(e=>$e(e)))if(await be.stored(e.url))return!0;const e=await Ce();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{const t=$e(e);try{for(const e of t)await be.remove(e.url)}catch{}try{const e=await Ce();await e.cacheManager.deleteMany(e=>t.some(t=>Pe(e,t.name)))}catch{}},purge:async()=>{try{await be.purge()}catch{}try{const e=await Ce();await e.cacheManager.clear()}catch{}}},We=((e={})=>{const t=e.engines?.cpu||Be,n=e.engines?.litert||ye;let a,o,c,d,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=d;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&&d&&_()})})(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(d&&u==e.id)return h(b.percent,b.phase),await M(h,f);d&&(_(),w=[],await d.catch(()=>!1));const E=++y,C=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const d=v(e);if(E!=y)return!1;if(!d)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 l)n.id!=e.id&&v(n)==t&&await t.remove(n)})(e,d),E!=y)return!1;const u=await d.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 l=await d.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 l.unload(),!1):(a=l,o=e,c=d,p=d.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(()=>{d==C&&(d=void 0,u=void 0,w=[])});return d=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}})(),Ie=(e,t,n)=>{const a=e.status(),i=g(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&&p(i),supportsAudio:!!i&&h(i),ready:e.ready(),loading:e.loading(),requesting:n.requesting,phase:n.phase,percent:n.percent,...n.error?{error:n.error}:{}}},qe=(e=>{let t,n=0;const o=t=>t.input.onStatus?.(Ie(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 f(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 void o(t);const m=p(c),w=h(c);if(!(l||d&&m||u&&w))return u&&!w?t.error="Model does not accept audio":d&&!m&&(t.error="Model does not accept images"),void o(t);const y=E(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&&!w?r.messages.map(({images:e,audio:t,...n})=>({...n,...e&&m?{images:e}:{},...t&&w?{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)}})(We),ze=(Oe=We,async(e={})=>{const t=await f(e.model),n=n=>e.onStatus?.(Ie(Oe,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=Oe.ready()&&Oe.model()?.id==t.id;return await Oe.load({model:t,limits:E(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||Oe.error()||"Model not ready"}),!1)});var Oe;export{c as ChatModelId,o as ChatStatus,i as LlmBackend,s as LlmPhase,a as LlmRole,r as LlmStatus,qe as createChat,ze 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,O=(new URL("./../assets/litert/litertlm_wasm_internal.wasm",import.meta.url).href,288),P=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},T=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})(O,O),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,O,O),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)),$=e=>D(e,"image"),L=e=>D(e,"audio"),R=["<|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 V=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)}},W=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,R);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,R);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 V(a(),s,"Model did not start"))[Symbol.asyncIterator]();for(;;){if(i()){W(e);break}let n;try{n=await V(e.next(),m?c:s,m?"Model stopped responding":"Model did not reply")}catch(r){if(r instanceof I&&(u||d)){l?.(),W(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),e instanceof I&&!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 T(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,J=new Map;let G=!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(!G)if("undefined"!=typeof navigator&&navigator.storage?.getDirectory)try{return await navigator.storage.getDirectory()}catch{return}else G=!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=J.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(()=>{J.delete(a)});return J.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=le("litert-store"),fe={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 me=!1;const pe=(...e)=>{me&&console.log(...e)},ge=(...e)=>{me&&console.error(...e)},he=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(ue)}catch{return}},ye=new Map,we=(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)}}))},be=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 P(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},ve=(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},xe=e=>({type:"function",function:{name:e.name,...void 0===e.description?{}:{description:e.description},...void 0===e.parameters?{}:{parameters:e.parameters}},execute:e.execute}),je=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 be([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&&!ve(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(!ve(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 be(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(xe),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=[])}},Me={backend:i.gpu,startLLM:async({model:e,limits:t,onProgress:n,signal:o,logging:a})=>{me=!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)),d=globalThis,f=d.Module;d.Module={print:pe,printErr:ge};try{await u.getOrLoadGlobalLiteRtLm(k)}finally{d.Module=f}if(o?.aborted)throw new Error("Cancelled");const m=_(c.repo,l.file),g=await he();let h;const y=g?await g.match(m):void 0;if(y?.body)h=y.body;else{const e=await de.stored(m);e?.complete&&(h=e.file.stream())}if(!h){const e=await de.download({url:m,signal:o,onProgress:n}).catch(e=>{if(o?.aborted)throw new Error("Cancelled");if(!ce(e))throw e;a&&console.log("Local model store failed",e)});e&&(h=e.file.stream())}if(!h&&g)try{await(async(e,t,r,n)=>{const o=ye.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=we(o.body,a,n);await t.put(e,new Response(i,{headers:{"content-type":"application/octet-stream",...a?{"content-length":`${a}`}:{}}}))})().finally(()=>{ye.delete(e)});return ye.set(e,a),await a})(m,g,o,n);const e=await g.match(m);e?.body&&(h=e.body)}catch(e){if(o?.aborted)throw new Error("Cancelled");a&&console.log("Local model cache failed",e)}if(h||(h=await(async(e,t,r)=>{const n=await fetch(e,{signal:t});if(!n.ok||!n.body)throw new Error("Model download failed");return we(n.body,A(n),r)})(m,o,n)),o?.aborted)throw new Error("Cancelled");n(1,s.load);const w=await u.Engine.create((({model:e,limits:t,source:r,mod:n})=>{const o=p(e);return{model:r,mainExecutorSettings:{maxNumTokens:4096,...o?.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:fe},...o?.vision?{visionBackend:n.Backend.GPU,maxVisionTokensPerImage:70,minVisionTokensPerImage:70}:{},...o?.audio?{audioBackend:n.Backend.CPU}:{}}})({model:e,limits:t,source:h,mod:u}));if(o?.aborted)throw await w.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:r,params:n,session:o})=>{me=!0===n.logging;const a=()=>{try{o.conversation?.cancel()}catch{}o.conversation=void 0,o.sent=[],o.tools=void 0};try{return await H({model:t,params:n,stopped:()=>!!n.signal?.aborted,onStall:a,start:async a=>{if(n.signal?.aborted)throw new Error("Cancelled");const i=p(t);if($(a)&&!i?.vision)throw new Error("Model does not accept images");if(L(a)&&!i?.audio)throw new Error("Model does not accept audio");if(n.tools?.length&&!i?.tools)throw new Error("Model does not accept tools");return je({engine:e,mod:r,params:n,messages:a,session:o})}})}catch(e){throw a(),e}})({engine:w,model:e,mod:u,params:t,session:b}),unload:async()=>{b.conversation=void 0,b.sent=[],b.tools=void 0,await w.delete()}}},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([he(),de.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 de.stored(_(t.repo,r.file)))return!0}const e=await he();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 he();await de.remove(n),o&&await o.delete(n)}catch{}},purge:async()=>{try{await de.purge(),"undefined"!=typeof caches&&await caches.delete(ue)}catch{}}},ke=le("wllama-store");let Oe,Pe,Te="",Se=!1;const Ce=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,Ne=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}},Ee=e=>{const t=e=>(...t)=>{Se&&("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)}},_e=async()=>{if(Oe)return Oe;const e=await r.e(924).then(()=>r(577)),t=Pe||Ne(),n=new e.Wllama({default:t.wasm},{logger:Ee(e.LoggerWithoutDebug)});return Pe||(Pe=t,Te=Ce(t)),n.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),Oe=n,n},Ae=async()=>{const e=Oe;Oe=void 0;try{await(e?.exit())}catch{}},De=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),$e=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)}]:[]]:[]},Le=async e=>{const t=$e(e);if(!t.length)return!1;for(const e of t){const t=await ke.stored(e.url);if(!t?.complete)return!1}return!0},Re=async(e,t)=>{const r=await e.cacheManager.list();return $e(t).every(e=>r.some(t=>De(t,e.name)))},Ue=async({model:e,signal:t,onProgress:r})=>{const n=$e(e),o=[];for(let e=0;e<n.length;e++){if(t?.aborted)throw new Error("Cancelled");const a=await ke.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},qe=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 P(t.url)});t.push({role:"user",content:e})}return t},ze={backend:i.cpu,startLLM:async({model:e,limits:t,onProgress:r,signal:n,logging:o,assets:a})=>{Se=!0===o;const c=m()?4096:8192,l=e.cpu;if(!l)throw new Error("Model has no CPU artifact");const u=Ne(a),d=Ce(u);Oe&&d!=Te&&await Ae(),Pe=u,Te=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 _e(),y=await Le(e),w=l.mmproj?.file,b=_(l.repo,l.file),v=w?_(l.repo,w):"";if(n?.aborted)throw await Ae(),new Error("Cancelled");if(!y&&w){const e=await h.cacheManager.list(),t=e.some(e=>De(e,l.file)),r=e.some(e=>De(e,w));t&&!r&&await h.cacheManager.deleteMany(e=>De(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 Ue({model:e,signal:n,onProgress:r}):void 0;t||y||await Re(h,e).catch(()=>!1)||(t=await Ue({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 Ae(),e}if(n?.aborted)throw await Ae(),new Error("Cancelled");if(!h.getLoadedContextInfo().n_ctx)throw await Ae(),new Error("Failed to create model context");return{model:e,backend:i.cpu,contextSize:c,chat:t=>(async(e,t,r)=>{if(Se=!0===r.logging,e.isModelLoaded())return await H({model:t,params:r,stopped:()=>!!r.signal?.aborted,start:async n=>{if($(n)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");if(L(n)&&!e.supportInputModality("audio"))throw new Error("Model does not accept audio");return await e.createChatCompletion({messages:await qe(n),...E(r.limits,r.reasoning),abortSignal:r.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:r.reasoning}}:{}})}})})(h,e,t),unload:async()=>{if(Oe==h)await Ae();else try{await h.exit()}catch{}}}},cached:async e=>{try{return!!e.cpu&&(!!await Le(e)||await Re(await _e(),e))}catch{return!1}},hasCache:async()=>{try{for(const e of f.flatMap(e=>$e(e)))if(await ke.stored(e.url))return!0;const e=await _e();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{const t=$e(e);try{for(const e of t)await ke.remove(e.url)}catch{}try{const e=await _e();await e.cacheManager.deleteMany(e=>t.some(t=>De(e,t.name)))}catch{}},purge:async()=>{try{await ke.purge()}catch{}try{const e=await _e();await e.cacheManager.clear()}catch{}}},Fe=((e={})=>{const t=e.engines?.cpu||ze,r=e.engines?.litert||Me;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)},O=()=>h==a.ready&&!!n&&!!o;return{load:async({model:e,limits:t,assets:r,logging:i,signal:p,onProgress:h})=>{if(p?.aborted)return!1;if(O()&&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 P=++w,T=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const l=v(e);if(P!=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),P!=w)return!1;const u=await l.cached(e);if(P!=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)=>{P==w&&x(e,t)}});return P!=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 P!=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==T&&(l=void 0,u=void 0,y=[])});return l=T,u=e.id,await k(h,p)},chat:async e=>{if(!O()||!n)return;for(;p;)await p.catch(()=>{});if(!O()||!n)return;const t=n.chat(e);p=t;try{return await t}finally{p==t&&(p=void 0)}},unload:async()=>{const e=n;M(),n=void 0,o=void 0,c=void 0,j(a.idle),await(e?.unload())},ready:O,loading:()=>!O()&&h==a.downloading,status:()=>h,backend:()=>g,error:()=>m,model:()=>o}})();var Ie=r(155);const Ve=/^[0-9+\-*/%^().]+$/,We=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},Be={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(!Ve.test(t))throw new Error("Unsupported character");const r=We(t);return{expression:t,result:Math.abs(r)>=1e5?(0,Ie.pNum)(r)??r:(0,Ie.rNum)(r,12)}})(t)}},He="degreesign-chat-prices-v1",Ye="EUR",Je=5*Ie.oneMin,Ge=30*Ie.oneSec;let Qe,Ze={},Ke=0,Xe=!1,et=!1;const tt=e=>{const t={};for(const[r,n]of Object.entries(e??{}))"number"==typeof n&&Number.isFinite(n)&&(t[r.trim().toUpperCase()]=n);return t},rt=(e,t)=>e&&e.sourceAt>t.sourceAt?e:t,nt=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=tt(e.rates?.current),n=tt(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&&(Ze.fiat=rt(Ze.fiat,a)),i&&(Ze.crypto=rt(Ze.crypto,i)),Ke=0,Xe=!1,(()=>{try{if("undefined"==typeof localStorage)return;localStorage.setItem(He,JSON.stringify(Ze))}catch{}})()}catch(e){throw Ke=Date.now(),Xe=!0,e}},ot=e=>!!Ze.crypto&&(e in Ze.crypto.prices||e in Ze.crypto.yesterday),at=e=>!!Ze.fiat&&(e in Ze.fiat.rates||e in Ze.fiat.yesterday),it=async e=>{const t=(e=>{const t={fiat:!1,crypto:!1};for(const r of e){if(r==Ye)continue;const e=ot(r)||at(r);!ot(r)&&e||(t.crypto=!0),ot(r)||(t.fiat=!0)}return t})(e),r=Date.now(),n=t.fiat&&r-(Ze.fiat?.fetchedAt??0)>=Ie.oneHr,o=t.crypto&&r-(Ze.crypto?.fetchedAt??0)>=Je;(n||o)&&("undefined"!=typeof navigator&&!1===navigator.onLine||Ke&&r-Ke<Ge||(Qe||(Qe=nt({fiat:n,crypto:o}).catch(()=>{}).finally(()=>{Qe=void 0})),await Qe))},st=e=>{if(e==Ye)return 1;const t=Ze.crypto?.yesterday[e],r=Ze.fiat?.yesterday[e];return t||(r?1/r:void 0)},ct=(e,t)=>{if("string"!=typeof e||!e.trim())throw new Error(`Missing ${t}`);return e.trim().toUpperCase()},lt=e=>Math.abs(e)>=1e5?(0,Ie.pNum)(e)??e:(0,Ie.rNum)(e,8),ut=async e=>{(()=>{if(!et){et=!0;try{if("undefined"==typeof localStorage)return;const e=localStorage.getItem(He);if(!e)return;const t=JSON.parse(e);Ze={...t.fiat?{fiat:t.fiat}:{},...t.crypto?{crypto:t.crypto}:{}}}catch{}}})();const t=ct(e.from,"from"),r=void 0===e.to||null===e.to?Ye:ct(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 it([t,r]);const o=e=>{const t=(e=>{if(e==Ye)return 1;const t=Ze.crypto?.prices[e],r=Ze.fiat?.rates[e];return t||(r?1/r:void 0)})(e);if(void 0!==t)return t;if(!Ze.fiat&&!Ze.crypto)throw new Error("Prices unavailable offline");if(ot(e)||at(e))throw new Error(`Unavailable quote for ${e}`);throw new Error(`Unknown symbol ${e}`)},a=o(t),i=o(r),s=st(t),c=st(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!=Ye&&(ot(r)?Ze.crypto&&t.push(Ze.crypto.sourceAt):at(r)&&Ze.fiat&&t.push(Ze.fiat.sourceAt));return t})([t,r]),p=m.length?Math.min(...m):Date.now();return{from:t,to:r,amount:n,rate:lt(l),...void 0===u?{}:{previousRate:lt(u),change:lt(d??0),changePercent:(0,Ie.rNum)(f??0,4)},result:lt(n*l),updatedAt:new Date(p).toISOString(),stale:Xe&&!(!Ze.fiat&&!Ze.crypto)}},dt={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=>ut(e)},ft={amp:"&",apos:"'",gt:">",lt:"<",nbsp:" ",quot:'"',hellip:"...",mdash:"-",ndash:"-",ldquo:'"',lsquo:"'",rdquo:'"',rsquo:"'"},mt=(e,t,r,n)=>"number"==typeof e&&Number.isFinite(e)?Math.min(r,Math.max(t,e)):n,pt=(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 ft[e.toLowerCase()]??e})(t);return r==t?e:r}).replace(/\s+/g," ").trim().slice(0,Math.max(0,t)).trim(),gt=/^[a-z]{2,3}(-[a-z]{2,4})?$/i,ht=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)}},yt=(e={})=>{const t=((e={})=>{const t=e.language?.trim()??"";return{provider:e.provider==u.duckduckgo?u.duckduckgo:u.wikipedia,language:gt.test(t)?t:"en",limit:Math.round(mt(e.limit,1,20,3)),snippetLength:Math.round(mt(e.snippetLength,1,4e3,400)),timeout:mt(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 ht(r,e.timeout),o=[],a=new Set,i=(t,r,n)=>{t&&n&&!a.has(t)&&(a.add(t),o.push({title:pt(r||n,200),url:t,snippet:pt(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 ht(n,e.timeout),a=[];for(const t of o.pages??[]){const n=t.key;n&&a.push({title:pt(t.title??n,200),url:`${r}/wiki/${encodeURIComponent(n)}`,snippet:pt(`${t.description??""} ${t.excerpt??""}`,e.snippetLength)})}return a})(t,r);return n}}},wt=[l.websearch,l.calculate,l.currency],bt=e=>{const t=e.tools??[],r=!1===e.builtins?[]:e.builtins??wt,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(yt(t)):n==l.calculate?r.push(Be):n==l.currency&&r.push(dt);return r})(r,e.websearch))n.has(t.name)||o.push(t);return o.push(...t),{tools:o,explicit:t.length>0}},vt=(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}:{}}},xt=(e=>{let t,r=0;const o=t=>t.input.onStatus?.(vt(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=bt(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 O,P="",T="";try{O=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||(P+=e,a.onThinking?.(P))},onText:e=>{t.token!=r||t.cancelled||(T+=e,a.onResponse?.(T))},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,O||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)}})(Fe),jt=(Mt=Fe,async(e={})=>{const t=await y(e.model),r=r=>e.onStatus?.(vt(Mt,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=Mt.ready()&&Mt.model()?.id==t.id;return await Mt.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||Mt.error()||"Model not ready"}),!1)});var Mt;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,xt as createChat,jt as preloadModel};
|
package/dist/engines/litert.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ToolWithImplementation } from '@litert-lm/core';
|
|
2
|
+
import type { ChatTool, EngineChunk, EngineMessage, LitertMessage, LitertSettings, LitertSettingsParams, LlmEngine, StartLlmParams, StreamLitertParams } from '../types';
|
|
2
3
|
declare const
|
|
3
4
|
/** Smallest Gemma 4 vision budget in tokens */
|
|
4
5
|
visionTokens = 70;
|
|
@@ -8,9 +9,15 @@ declare const cacheModel: (url: string, cache: Cache, signal: AbortSignal | unde
|
|
|
8
9
|
declare const toLitertMessages: (messages: EngineMessage[], keepMedia?: boolean) => Promise<LitertMessage[]>;
|
|
9
10
|
/** Whether the live conversation already holds the incoming history */
|
|
10
11
|
declare const continuesHistory: (sent: EngineMessage[], history: EngineMessage[]) => boolean;
|
|
12
|
+
/** Clamp the tool round budget of one reply */
|
|
13
|
+
declare const toolRounds: (value?: number) => number;
|
|
14
|
+
/** Map one host or built-in tool to the engine tool shape */
|
|
15
|
+
declare const engineTool: (tool: ChatTool) => ToolWithImplementation;
|
|
16
|
+
/** Whether two lists declare the same tools and the same functions */
|
|
17
|
+
declare const sameTools: (first?: ChatTool[], next?: ChatTool[]) => boolean;
|
|
11
18
|
/** Stream one LiteRT reply as engine chunks */
|
|
12
19
|
declare const streamLitert: ({ engine, mod, params, messages, session, }: StreamLitertParams) => AsyncGenerator<EngineChunk>;
|
|
13
20
|
/** Build one engine settings object with the small vision budget */
|
|
14
21
|
declare const litertSettings: ({ model, limits, source, mod, }: LitertSettingsParams) => LitertSettings;
|
|
15
22
|
declare const litertEngine: LlmEngine;
|
|
16
|
-
export { cacheModel, continuesHistory, litertEngine, litertSettings, streamLitert, toLitertMessages, visionTokens, };
|
|
23
|
+
export { cacheModel, continuesHistory, engineTool, litertEngine, litertSettings, sameTools, streamLitert, toLitertMessages, toolRounds, visionTokens, };
|
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, };
|