@degreesign/chat 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,14 @@
1
1
  # @degreesign/chat
2
2
 
3
- One-shot on-device AI chat for browsers, workers and Node, running a wllama CPU
4
- engine or a LiteRT-LM WebGPU engine. The host owns the messages and the UI; the
5
- package loads one model, streams one reply and reports status.
3
+ One-shot on-device AI chat for browsers, workers and Node, using wllama CPU
4
+ engine and LiteRT-LM WebGPU engine.
5
+ The package is an A-Z solution for local AI chat and more.
6
+ Includes voice transcription to many languages
7
+ and a super accurate image vision function.
8
+ The package manages download of AI models automatically,
9
+ with auto resume for low network connections.
10
+
11
+ `@degreesign/chat` is plug and play solution for any UI.
6
12
 
7
13
  [![npm version](https://img.shields.io/npm/v/@degreesign/chat.svg)](https://www.npmjs.com/package/@degreesign/chat)
8
14
  [![license](https://img.shields.io/badge/license-MIT-blue.svg)](#licensing)
@@ -25,6 +31,7 @@ package loads one model, streams one reply and reports status.
25
31
  - [Node.js](#nodejs)
26
32
  - [React](#react)
27
33
  - [Types](#types)
34
+ - [Testing](#testing)
28
35
  - [Architecture](#architecture)
29
36
  - [FAQ](#faq)
30
37
  - [Licensing](#licensing)
@@ -224,6 +231,13 @@ model. A lost device needs a page or model reload; later calls cannot reuse it.
224
231
  A phone or tablet resolves Gemma to the text-only browser build, so it never
225
232
  starts the vision or audio encoder.
226
233
 
234
+ While a reply streams, the GPU engine rests after every token readback, so the
235
+ card stays near 70% of wall time instead of pegging at 100% and starving the
236
+ desktop compositor. The rest applies after the prefill, so the first token is
237
+ not delayed. Unloading releases the WebGPU device and resets the LiteRT wasm,
238
+ because a deleted engine leaves both unusable; a later load rebuilds them from
239
+ the stored model file without downloading it again.
240
+
227
241
  ## Public API
228
242
 
229
243
  ```ts
@@ -231,14 +245,18 @@ createChat(input: ChatInput): CancelChat
231
245
  preloadModel(input?: ChatPreloadInput): Promise<boolean>
232
246
  describeImages(input: DescribeImagesInput): Promise<ImageDescription[]>
233
247
  describeTranslated(input: DescribeTranslatedInput): Promise<string[]>
248
+ describeModelId: ChatModelId
249
+ imageReplyTokens: number
234
250
  clearModelCache(): Promise<void>
235
251
  ```
236
252
 
237
253
  Call it once per response. A new call aborts the previous stream. When the
238
- requested model is already loaded, no download or load happens. Switching to a
239
- different model unloads the previous runtime and keeps its files on disk.
240
- `clearModelCache` releases the loaded model and deletes every cached model file
241
- from this device.
254
+ requested model is already loaded, no download or load happens. On a desktop a
255
+ loaded model stays resident, one per backend, so the CPU describer and the GPU
256
+ translator never reload each other; a new model of the same backend replaces the
257
+ old one. A phone keeps one model in total. Files stay on disk, and
258
+ `clearModelCache` releases every loaded model and deletes every cached model
259
+ file from this device.
242
260
 
243
261
  `ChatInput`:
244
262
 
@@ -258,19 +276,20 @@ Without `model` the package picks the GPU build when the browser provides a
258
276
  WebGPU adapter and the CPU build when it does not. The budget defaults are 250
259
277
  reply tokens, 128 CPU thinking tokens, 1200 GPU reasoning tokens (320 on the
260
278
  CPU), 2 images, 1 audio clip, 1000 characters per message, 10000 prompt
261
- characters and 6 CPU threads.
279
+ characters and 32 CPU threads.
262
280
 
263
281
  `CancelChat` is `() => void`. Its meaning depends on the current state:
264
282
 
265
283
  | State | Effect |
266
284
  | ----- | ------ |
267
285
  | Downloading or loading | Stops waiting for the load. Bytes stay on disk, and a download another caller waits for keeps going. |
268
- | Ready | Aborts the reply and unloads the model. |
286
+ | Ready | Aborts the reply and unloads the model that answered. |
269
287
  | An older call | Nothing, because a newer call owns the runtime. |
270
288
 
271
- The model stays loaded between calls until a cancel frees it. One model
272
- download serves every caller: a chat that joins a preload shares its progress
273
- and never starts a second download.
289
+ The model stays loaded between calls until a cancel frees it, and a newer
290
+ model of the same backend replaces it. One model download serves every caller:
291
+ a chat that joins a preload shares its progress and never starts a second
292
+ download.
274
293
 
275
294
  ### Preload
276
295
 
@@ -285,6 +304,10 @@ runtime, and either call joins a load already in flight. A preload owns no cance
285
304
  function, so a chat that joins its download and is cancelled leaves the download
286
305
  running.
287
306
 
307
+ Preloads on different backends run together, so a host may warm the GPU text
308
+ model and the CPU media model inside one `Promise.all`. Each call reports only
309
+ its own model, and a load on the same backend still replaces the one in flight.
310
+
288
311
  `ChatPreloadInput` is the subset of `ChatInput` that a preload needs:
289
312
 
290
313
  | Field | Description |
@@ -310,14 +333,17 @@ adapter exists and `targetLanguage` is not English, the English descriptions
310
333
  are then translated one by one with `gemma4_e2b_limited`. Without a GPU, when
311
334
  the translation model cannot load, or when the translator replies
312
335
  `CANNOT_TRANSLATE`, `description` stays equal to `descriptionEN`. Both the
313
- description and translation calls use a 600-token reply budget unless
314
- `limits.maxReplyTokens` overrides it. The describer sets an explicit 16 to
315
- 100 vision-token window; other models leave the engine image limits unset.
316
-
317
- The describer and translator each receive a system message that puts accuracy
318
- first: the describer reports only visible detail, and the translator translates
319
- its own previous reply, never the user's instruction, preserving meaning, names
320
- and numbers without adding or omitting anything.
336
+ description and translation calls use the `imageReplyTokens` budget of 128
337
+ tokens unless `limits.maxReplyTokens` overrides it. The describer requests
338
+ 192 vision tokens for its image resize; the CPU engine keeps its instruct
339
+ window at 16 to 128 tokens, and other models leave the engine image limits
340
+ unset.
341
+
342
+ The describer receives a system message that asks for every element of the
343
+ image and adds rules against lying, verdicts and vague referrals.
344
+ `DescribeImagesInput.additionalRules` appends host rules to that message. The
345
+ translator translates its own previous reply, never the user's instruction,
346
+ preserving meaning, names and numbers without adding or omitting anything.
321
347
 
322
348
  `DescribeImagesInput`:
323
349
 
@@ -463,7 +489,8 @@ vision or audio encoder, so `supportsImages` and `supportsAudio` report `false`
463
489
  there. Use `qwen3_vl_2b` for images on mobile.
464
490
 
465
491
  The first call downloads the model before its engine loads it. Later calls
466
- reuse the loaded runtime. Only one model stays in memory. An interrupted
492
+ reuse the loaded runtime. A desktop keeps one model per backend in memory, so
493
+ the CPU describer and the GPU text model stay resident together. An interrupted
467
494
  download keeps every part it committed and resumes from the last one on the
468
495
  next attempt, including after a reload.
469
496
 
@@ -489,6 +516,11 @@ GPU_ARTISAN build Google ships for browsers. The smaller file is what keeps a
489
516
  mobile tab alive at the end of the model load, and a desktop can ask for it
490
517
  too, trading vision and audio for 600 MB less download.
491
518
 
519
+ The WebGPU engine asks for a 32768 token context on a desktop and 16384 on a
520
+ phone, both multiples of 1024. Its int8 KV cache holds the full desktop window
521
+ in about 300 MB, so the larger window stays a small part of the 2 GB model
522
+ footprint.
523
+
492
524
  The WebGPU engine keeps one LiteRT conversation for consecutive turns. When the
493
525
  next prompt continues that history, only the new user turn is sent. A changed
494
526
  history opens a fresh conversation, and older images and audio become `[image]`
@@ -543,12 +575,28 @@ onProgress })` contract and return the runtime object with `model`, `backend`,
543
575
  `contextSize`, `chat()` and `unload()`. `createChat` starts the engine that
544
576
  matches the requested model.
545
577
 
546
- The CPU engine derives a raw thread count from the device, then caps it at
547
- `limits.maxThreads` and at 3 threads for a text model or 2 threads for a model
548
- with a vision projector. The vision cap keeps the wasm image path alive: a
549
- 100-token image completes in about 89 seconds with 2 threads, while 3 threads
550
- stalled past 10 minutes in the headless check. Every CPU model uses one count
551
- for the whole load.
578
+ The CPU engine reads `navigator.hardwareConcurrency`, keeps a fifth of the
579
+ logical cores free for the page (at least one) and gives the rest to the
580
+ engine: 8 threads run with 7, 16 with 13, 4 with 3. `limits.maxThreads` only
581
+ lowers the count, and phones follow the same rule; only the context window is
582
+ smaller there. On an 8-thread desktop a 128-token image reaches its first token
583
+ in 71.3 seconds with 7 threads, 82.3 seconds with 6 and 106.6 seconds with 4. A
584
+ JavaScript probe was measured and rejected: it follows JS worker scaling, not
585
+ the ggml pool, and its curve was too noisy to trust.
586
+
587
+ The vision path runs two ggml pools, one for the projector and one for the
588
+ model, so it needs twice the workers of a text model. wllama 3.8.1 pre-spawns
589
+ only `n_threads` workers, which leaves the second pool without workers and
590
+ stalls the encode at 3 or more threads. `scripts/patch-wllama.cjs` sizes the
591
+ pool at twice the thread count on every build until the fix is released
592
+ upstream; with it the image path runs at the heuristic count (7 threads on this
593
+ 8-thread desktop) instead of 2. Every CPU model uses one count for the whole
594
+ load.
595
+
596
+ The build bundles wllama from the installed package, so `yarn build` runs
597
+ `scripts/patch-wllama.cjs` first. The script is idempotent and fails loudly when
598
+ the installed wllama no longer matches the patch. `patches/wllama-pool.patch`
599
+ holds the same change as an upstream diff for wllama.
552
600
 
553
601
  The CPU engine needs cross-origin isolation for its threads. Serve the page with
554
602
  both headers:
@@ -570,8 +618,11 @@ self hosted. Chromium also accepts
570
618
  changed. A page inside an iframe is isolated only when every ancestor sets the
571
619
  same headers.
572
620
 
573
- Each engine keeps its own cache. Loading a model unloads the previous runtime
574
- and keeps the previous model's files, so a switch back skips the download.
621
+ Each engine keeps its own cache. A desktop keeps one loaded model per backend,
622
+ so a switch between the CPU and GPU models skips both the download and the
623
+ load; a model of the same backend replaces the previous one. A phone keeps one
624
+ model in total. The previous model's files always stay, so a switch back skips
625
+ the download.
575
626
  `clearModelCache()` deletes them all and frees the storage. Both engines store
576
627
  model files in the origin private file system as numbered parts, under
577
628
  `wllama-store` for the CPU engine and `litert-store` for the GPU engine. The GPU
@@ -683,6 +734,34 @@ const useReply = () => {
683
734
  The public enums are `ChatModelId`, `LlmRole`, `ChatStatus`, `LlmStatus`,
684
735
  `LlmBackend` and `LlmPhase`.
685
736
 
737
+ ## Testing
738
+
739
+ The suites live in `test/` and run against the local checkout.
740
+
741
+ `yarn test:instruct` starts a local llama.cpp server with the Qwen3-VL 2B
742
+ Instruct Q3_K_M build:
743
+
744
+ ```bash
745
+ yarn test:instruct
746
+ ```
747
+
748
+ It runs `llama serve` on `http://127.0.0.1:8080` with a 160k context, 4
749
+ threads and CPU inference. llama.cpp
750
+ downloads the weights on first run and caches them outside the repository.
751
+ llama.cpp runs about 10x faster than wllama, so prefer the live server
752
+ whenever a test needs real inference. Keep the server in its own terminal
753
+ while the live and image suites run.
754
+
755
+ The image suite bundles the browser harness, serves it from `test/drive.cjs`
756
+ and proxies `/llama/` to the server on port 8080, so start `test:instruct`
757
+ first:
758
+
759
+ ```bash
760
+ yarn test:images
761
+ ```
762
+
763
+ The fake-engine harness needs no server and never reaches the network.
764
+
686
765
  ## Architecture
687
766
 
688
767
  An interactive map of the package lives at
@@ -1,2 +1,2 @@
1
1
  /*! For license information please see chat.min.mjs.LICENSE.txt */
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.qwen3_vl_2b_instruct="qwen3-vl-2b-instruct",e.qwen3_vl_2b_instruct_q3="qwen3-vl-2b-instruct-q3",e.gemma4_e2b="gemma4-e2b",e.gemma4_e2b_limited="gemma4-e2b-limited"}(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 g=[{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.qwen3_vl_2b_instruct,reasoning:!1,cpu:{repo:"unsloth/Qwen3-VL-2B-Instruct-GGUF",file:"Qwen3-VL-2B-Instruct-Q4_K_M.gguf",mmproj:{repo:"Qwen/Qwen3-VL-2B-Instruct-GGUF",file:"mmproj-Qwen3VL-2B-Instruct-Q8_0.gguf"}}},{id:c.qwen3_vl_2b_instruct_q3,reasoning:!1,cpu:{repo:"unsloth/Qwen3-VL-2B-Instruct-GGUF",file:"Qwen3-VL-2B-Instruct-Q3_K_M.gguf",mmproj:{repo:"Qwen/Qwen3-VL-2B-Instruct-GGUF",file:"mmproj-Qwen3VL-2B-Instruct-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}},{id:c.gemma4_e2b_limited,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it-gpu.litertlm",vision:!1,audio:!1}}],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())=>e==c.gemma4_e2b&&t?c.gemma4_e2b_limited:e,f=e=>e?g.find(t=>t.id==e):void 0,h=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)}},y=async e=>f(p(e??await(async()=>(d||(d=(async()=>await h()?p(c.gemma4_e2b):c.qwen3_vl_2b)()),await d))())),w=e=>!!e.cpu?.mmproj||!0===e.litert?.vision,b=e=>!!e.cpu?.mmproj?.audio||!0===e.litert?.audio,v=new URL("./../assets/wllama/wllama.wasm",import.meta.url).href,x=new URL("./../assets/wllama/compat/wllama.wasm",import.meta.url).href,j=new URL("./../assets/wllama/compat/wllama.js",import.meta.url).href,M=new URL("./../assets/litert/litertlm_wasm_internal.js",import.meta.url).href,k=(new URL("./../assets/litert/litertlm_wasm_internal.wasm",import.meta.url).href,{width:384,height:384}),_=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},S=async(e,t)=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const r=await fetch(e),n=await createImageBitmap(await r.blob()),o=t??((e,t)=>{const r=e/Math.max(1,t);let n=32,o=32,a=1/0,i=1/0;for(let e=1;e<=128;e++){const t=Math.ceil(128/e),s=Math.floor(136/e);for(let c=t;c<=s;c++){const t=c*e,s=Math.abs(c/e-r);(s<a-1e-9||Math.abs(s-a)<=1e-9&&t<i)&&(n=32*c,o=32*e,a=s,i=t)}}return{width:n,height:o}})(n.width,n.height),a=n.width/Math.max(1,n.height),i=o.width/o.height,s=Math.min(n.width,a>i?n.height*i:n.width),c=Math.min(n.height,a>i?n.height:n.width/i),l=(n.width-s)/2,u=(n.height-c)/2,d=((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.width,o.height),g=d?d.getContext("2d"):null;if(!d||!g||n.width<1||n.height<1)return n.close(),e;if(g.drawImage(n,l,u,s,c,0,0,o.width,o.height),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(d)){const t=await d.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 d.toDataURL("image/jpeg",.85)}catch{return e}};var T=r(155);const P={maxReplyTokens:250,maxThinkingTokens:128,maxReasoningTokens:320,maxImages:2,maxAudio:1,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:6},O=(e,t,r)=>"number"==typeof e&&Number.isFinite(e)&&e>=r?Math.floor(e):t,D=(e={},t=!1)=>{const r=P;return{maxReplyTokens:O(e.maxReplyTokens,r.maxReplyTokens,1),maxThinkingTokens:O(e.maxThinkingTokens,r.maxThinkingTokens,1),maxReasoningTokens:O(e.maxReasoningTokens,t?1200:r.maxReasoningTokens,1),maxImages:O(e.maxImages,r.maxImages,0),maxAudio:O(e.maxAudio,r.maxAudio,0),maxContentLength:O(e.maxContentLength,r.maxContentLength,1),promptCharBudget:O(e.promptCharBudget,r.promptCharBudget,1),maxThreads:O(e.maxThreads,r.maxThreads,1)}},N=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),C=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,E=e=>Number(e.headers.get("content-length"))||0,A=(e,t)=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>e.type==t)),L=e=>A(e,"image"),$=e=>A(e,"audio"),R=["<|channel>thought\n","<|channel>thought","..."],q=["<channel|>","..."],U=(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,I=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,z=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const r=[];for(const n of[...I(e),{type:"text",text:"\n"},...I(t)]){const e=r[r.length-1];"text"==n.type&&"text"==e?.type?e.text+=n.text:r.push(n)}return r},F=m()?3e6:3e5,V=Math.max(F,84e4);class B extends Error{}const W=async(e,t,r)=>{let n;try{return await Promise.race([e,new Promise((e,o)=>{n=setTimeout(()=>o(new B(r)),t)})])}finally{n&&clearTimeout(n)}},Q=e=>{try{Promise.resolve(e.return?.()).catch(()=>{})}catch{}},Y=async({model:e,logging:t,onReason:r,onText:n,onSpeed:o,start:a,stopped:i,firstTimeoutMs:s=F,idleTimeoutMs:c=3e4,onStall:l})=>{let u="",d="",g="",m=!1,p=0,f=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,q);if(t>=0){t&&e(s.slice(0,t)),s=s.slice(t+i.length),n=!1;continue}const c=a(s,q);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 W(a(),s,"Model did not start"))[Symbol.asyncIterator]();for(;;){if(i()){Q(e);break}let n;try{n=await W(e.next(),m?c:s,m?"Model stopped responding":"Model did not reply")}catch(r){if(r instanceof B&&(u||d)){l?.(),Q(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&&(g=a.finish_reason),w&&(d+=w,r(w)),y?.content&&h.feed(y.content),w||y?.content){const e=performance.now();p||(f=e),p+=1,p>1&&e>f&&o?.((0,T.rNum)(1e3*p/(e-f)))}}h.flush()}catch(e){if(t&&console.log("Local chat failed",e),e instanceof B&&!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,g||"none",u.length,d.length)),y},G=async({model:e,params:t,start:r,stopped:o,onStall:a})=>{const i=await(async(e,t)=>{const r=[];for(const n of e){if("string"==typeof n.content){r.push(n);continue}const e=[];for(const r of n.content)e.push("image"==r.type?{type:"image",url:await S(r.url,t)}:r);r.push({role:"user",content:e})}return r})(((e,t=P)=>{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),g=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||g.length||m.length){if(d&&s+d.length>t.promptCharBudget)break;s+=d.length,c-=g.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:U(d,g,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=z(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"),g=[];return d&&g.push({role:"system",content:d}),g.push(...u),g})(t.messages,t.limits),e.litert?k:void 0);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 Y({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,onSpeed:t.onSpeed,start:()=>r(i),stopped:o,onStall:a,firstTimeoutMs:L(i)?V:F})},H=33554432,J=new Map;let Z=!1;const K=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}`},X=e=>{const t=/^part-(\d+)$/.exec(e);return t?Number(t[1]):-1},ee=async()=>{if(!Z)if("undefined"!=typeof navigator&&navigator.storage?.getDirectory)try{return await navigator.storage.getDirectory()}catch{return}else Z=!0},te=async(e,t)=>{try{return await e.getDirectoryHandle(t)}catch{return}},re=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}},ne=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{}},oe=async function*(e){for await(const t of e)yield t},ae=async e=>{try{for await(const[t,r]of oe(e))"file"==r.kind&&X(t)>=0&&await e.removeEntry(t).catch(()=>{})}catch{}},ie=async(e,t)=>{try{const r=await(await e.getFileHandle(t)).getFile(),n=await re(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}},se=async(e,t)=>{const r=await te(e,t);if(r){const e=await(async e=>await re(await e.getFileHandle("meta.json").catch(()=>{})))(r),t=await(async e=>{const t=[];try{for await(const[r,n]of oe(e)){const e=X(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 ie(e,t)},ce=(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:E(e)||t.total,etag:a||t.etag}},le=async({dir:e,start:t,skip:r,total:n,body:o,onProgress:a,onChunk:i})=>{let c,l=t,u=0,d=r;const g=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 g();const e=Math.min(H-u,o.byteLength-p);await c.write({type:"write",position:u,data:o.subarray(p,p+e)}),p+=e,u+=e,l+=e,u==H&&await m()}l>t&&a(n?l/n:0,s.download)}await m()}catch(e){throw await m(),e}return l},ue=e=>["NotAllowedError","NotSupportedError"].includes(e?.name||""),de=e=>{const t=async()=>{const t=await ee();if(t)try{return await t.getDirectoryHandle(e,{create:!0})}catch{return}};return{stored:async e=>{const r=await t();return r?await se(r,K(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=K(t),a=await ie(e,o);if(a?.complete)return a;let i=await te(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 se(e,o);if(a?.complete)return a;const u=a?.size??0,d=a?.total||0,g=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+H,d)-1:u+H-1,p=new AbortController,f=()=>p.abort(),h={size:u,total:d,etag:g};let y,w=setTimeout(f,3e4);r?.addEventListener("abort",f,{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 ne(i,{total:d,etag:g,complete:!0});continue}await ae(i),await ne(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=ce(y,h);if(!r){await y.body.cancel().catch(()=>{}),await ae(i),await ne(i,{total:0,etag:"",complete:!1});continue}await ne(i,{total:r.total,etag:r.etag,complete:!1});const a=0==r.start?u:0,s=await le({dir:i,start:r.start+a,skip:a,total:r.total,body:y.body,onProgress:n,onChunk:()=>{clearTimeout(w),w=setTimeout(f,3e4)}});if(!r.total){await ne(i,{total:s,etag:r.etag,complete:!0});const t=await se(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",f)}}})(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,K(e))},purge:async()=>{const t=await ee();t&&await t.removeEntry(e,{recursive:!0}).catch(()=>{})}}},ge="litertlm-models",me=de("litert-store"),pe={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 fe=!1;const he=(...e)=>{fe&&console.log(...e)},ye=(...e)=>{fe&&console.error(...e)},we=e=>{try{e.getGlobalLiteRtLm().liteRtLmWasm.preinitializedWebGPUDevice=void 0}catch{}},be=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(ge)}catch{return}},ve=new Map,xe=(e,t,r)=>{let n=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{n+=e.byteLength,r(t?n/t:0,s.download),o.enqueue(e)}}))},je=async(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 _(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},Me=(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},ke=async function*({engine:e,mod:t,params:r,messages:n,session:o}){const a=n[n.length-1],i=N(r.limits,r.reasoning);if("user"!=a?.role)throw new Error("No user turn");const s=n.slice(0,-1),c=(await je([a]))[0];if(!c)throw new Error("Empty prompt");const l=!!o.conversation&&o.reasoning==r.reasoning&&o.maxTokens==i.max_tokens&&((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&&!Me(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(!Me(o[i+e],a[e]))return!1;return!0})(o.sent,s);let u;if(l&&o.conversation)u=o.conversation;else{const n=await je(s,!1);o.conversation=void 0,o.sent=[],u=await e.createConversation({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}),o.conversation=u,o.reasoning=r.reasoning,o.maxTokens=i.max_tokens,o.sent=[...s]}o.sent.push(a);let d,g=!1,m="";const p=()=>{d&&d.cancel().catch(()=>{});try{u.cancel()}catch{}};r.signal?.addEventListener("abort",p,{once:!0});try{if(r.signal?.aborted)return;const e=u.sendMessageStreaming(c).getReader();for(d=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,m+=o);const a=r.channels?.thought;a&&(n.reasoning=a),(n.content||n.reasoning)&&(yield{choices:[{delta:n}]})}g=!0}finally{r.signal?.removeEventListener("abort",p),g&&m?o.sent.push({role:"assistant",content:m}):(o.conversation=void 0,o.sent=[])}},_e={backend:i.gpu,startLLM:async({model:e,limits:t,onProgress:n,signal:o,logging:a})=>{fe=!0===a;const c=e.litert;if(!c)throw new Error("Model has no LiteRT artifact");const l=await r.e(520).then(()=>r(507)),u=globalThis,d=u.Module;u.Module={print:he,printErr:ye};try{await l.getOrLoadGlobalLiteRtLm(M)}finally{u.Module=d}if(o?.aborted)throw new Error("Cancelled");const g=C(c.repo,c.file),m=await be();let p;const f=m?await m.match(g):void 0;if(f?.body)p=f.body;else{const e=await me.stored(g);e?.complete&&(p=e.file.stream())}if(!p){const e=await me.download({url:g,signal:o,onProgress:n}).catch(e=>{if(o?.aborted)throw new Error("Cancelled");if(!ue(e))throw e;a&&console.log("Local model store failed",e)});e&&(p=e.file.stream())}if(!p&&m)try{await(async(e,t,r,n)=>{const o=ve.get(e);if(o)return await o;const a=(async()=>{const o=await fetch(e,{signal:r});if(!o.ok||!o.body)throw new Error("Model download failed");const a=E(o),i=xe(o.body,a,n);await t.put(e,new Response(i,{headers:{"content-type":"application/octet-stream",...a?{"content-length":`${a}`}:{}}}))})().finally(()=>{ve.delete(e)});return ve.set(e,a),await a})(g,m,o,n);const e=await m.match(g);e?.body&&(p=e.body)}catch(e){if(o?.aborted)throw new Error("Cancelled");a&&console.log("Local model cache failed",e)}if(p||(p=await(async(e,t,r)=>{const n=await fetch(e,{signal:t});if(!n.ok||!n.body)throw new Error("Model download failed");return xe(n.body,E(n),r)})(g,o,n)),o?.aborted)throw new Error("Cancelled");n(1,s.load);const h=await l.Engine.create((({model:e,limits:t,source:r,mod:n})=>{const o=e.litert;return{model:r,mainExecutorSettings:{maxNumTokens:4096,...o?.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:pe},...o?.vision?{visionBackend:n.Backend.GPU,maxVisionTokensPerImage:70,minVisionTokensPerImage:70}:{},...o?.audio?{audioBackend:n.Backend.CPU}:{}}})({model:e,limits:t,source:p,mod:l}));if(o?.aborted)throw await h.delete(),we(l),new Error("Cancelled");const y={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})=>{fe=!0===n.logging;const a=()=>{try{o.conversation?.cancel()}catch{}o.conversation=void 0,o.sent=[]};try{return await G({model:t,params:n,stopped:()=>!!n.signal?.aborted,onStall:a,start:async a=>{if(n.signal?.aborted)throw new Error("Cancelled");if(L(a)&&!t.litert?.vision)throw new Error("Model does not accept images");if($(a)&&!t.litert?.audio)throw new Error("Model does not accept audio");return ke({engine:e,mod:r,params:n,messages:a,session:o})}})}catch(e){throw a(),e}})({engine:h,model:e,mod:l,params:t,session:y}),unload:async()=>{const e=y.conversation;y.conversation=void 0,y.sent=[];try{await(e?.delete())}catch{}await h.delete(),we(l)}}},cached:async e=>{const t=e.litert;if(!t)return!1;const r=C(t.repo,t.file),[n,o]=await Promise.all([be(),me.stored(r)]);if(o?.complete)return!0;try{return!(!n||!await n.match(r))}catch{return!1}},purge:async()=>{try{await me.purge(),"undefined"!=typeof caches&&await caches.delete(ge)}catch{}}},Se=de("wllama-store"),Te=[c.qwen3_vl_2b_instruct,c.qwen3_vl_2b_instruct_q3],Pe=e=>e.cpu?.mmproj&&Te.includes(e.id)?{image_min_tokens:16,image_max_tokens:100}:{};let Oe,De,Ne="",Ce=!1;const Ee=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,Ae=e=>{const t={wasm:v,compatWasm:x,compatWorker:j};return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},Le=e=>{const t=e=>(...t)=>{Ce&&("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=De||Ae(),n=new e.Wllama({default:t.wasm},{logger:Le(e.LoggerWithoutDebug)});return De||(De=t,Ne=Ee(t)),n.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),Oe=n,n},Re=async()=>{const e=Oe;Oe=void 0;try{await(e?.exit())}catch{}},qe=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),Ue=e=>{const t=e.cpu;return t?[{name:t.file,url:C(t.repo,t.file)},...t.mmproj?[{name:t.mmproj.file,url:C(t.mmproj.repo??t.repo,t.mmproj.file)}]:[]]:[]},Ie=async e=>{const t=Ue(e);if(!t.length)return!1;for(const e of t){const t=await Se.stored(e.url);if(!t?.complete)return!1}return!0},ze=async(e,t)=>{const r=await e.cacheManager.list();return Ue(t).every(e=>r.some(t=>qe(t,e.name)))},Fe=async({model:e,signal:t,onProgress:r})=>{const n=Ue(e),o=[];for(let e=0;e<n.length;e++){if(t?.aborted)throw new Error("Cancelled");const a=await Se.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},Ve=async e=>{const t=[];for(const r of e){if("string"==typeof r.content){"system"==r.role?t.push({role:"system",content:r.content}):"assistant"==r.role?t.push({role:"assistant",content:r.content}):t.push({role:"user",content:r.content});continue}const e=[];for(const t of r.content)"text"==t.type?e.push({type:"text",text:t.text}):e.push({type:t.type,data:await _(t.url)});t.push({role:"user",content:e})}return t},Be={backend:i.cpu,startLLM:async({model:e,limits:t,onProgress:r,signal:n,logging:o,assets:a})=>{Ce=!0===o;const c=m()?4096:8192,l=e.cpu;if(!l)throw new Error("Model has no CPU artifact");const u=Ae(a),d=Ee(u);Oe&&d!=Ne&&await Re(),De=u,Ne=d;const g=((e,t,r=!1)=>Math.max(1,Math.min(Math.max(2,Math.min(8,(e||4)-1)),t,r?2:3)))("undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,t.maxThreads,!!l.mmproj),p=await $e(),f=await Ie(e),h=l.mmproj?.file,y=C(l.repo,l.file),w=h?C(l.mmproj?.repo??l.repo,h):"";if(n?.aborted)throw await Re(),new Error("Cancelled");if(!f&&h){const e=await p.cacheManager.list(),t=e.some(e=>qe(e,l.file)),r=e.some(e=>qe(e,h));t&&!r&&await p.cacheManager.deleteMany(e=>qe(e,l.file))}const b={n_ctx:c,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,jinja:!0,...Pe(e)};try{let t=f?await Fe({model:e,signal:n,onProgress:r}):void 0;t||f||await ze(p,e).catch(()=>!1)||(t=await Fe({model:e,signal:n,onProgress:r}).catch(e=>{if(n?.aborted)throw new Error("Cancelled");if(!ue(e))throw e;o&&console.log("Local model store failed",e)})),t?(r(1,s.load),await p.loadModel(t,b)):await p.loadModelFromUrl(w?{url:y,mmprojUrl:w}:y,{...b,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 Re(),e}if(n?.aborted)throw await Re(),new Error("Cancelled");if(!p.getLoadedContextInfo().n_ctx)throw await Re(),new Error("Failed to create model context");return{model:e,backend:i.cpu,contextSize:c,chat:t=>(async(e,t,r)=>{if(Ce=!0===r.logging,e.isModelLoaded())return await G({model:t,params:r,stopped:()=>!!r.signal?.aborted,start:async n=>{if(L(n)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");if($(n)&&!e.supportInputModality("audio"))throw new Error("Model does not accept audio");return await e.createChatCompletion({messages:await Ve(n),...N(r.limits,r.reasoning),abortSignal:r.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:r.reasoning}}:{}})}})})(p,e,t),unload:async()=>{if(Oe==p)await Re();else try{await p.exit()}catch{}}}},cached:async e=>{try{return!!e.cpu&&(!!await Ie(e)||await ze(await $e(),e))}catch{return!1}},purge:async()=>{try{await Se.purge()}catch{}try{const e=await $e();await e.cacheManager.clear()}catch{}}},We=((e={})=>{const t=e.engines?.cpu||Be,r=e.engines?.litert||_e;let n,o,c,l,u,d,g,m=i.none,p=a.idle,f=[],h=0,y={percent:0,phase:s.download};const w=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},b=async()=>{const e=n;n=void 0,o=void 0,await(e?.unload())},v=(e,t)=>{y={percent:Math.max(0,Math.min(1,e)),phase:t||s.download};for(const e of[...f])e.report(y.percent,y.phase)},x=e=>{p=e},j=()=>{h++,u?.abort(),u=void 0,l=void 0,p==a.downloading&&x(a.idle)},M=(e,t)=>{const r=c;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=>{f=f.filter(t=>t!=e),queueMicrotask(()=>{!f.length&&c&&j()})})(a),a.settle(!1)};f.push(a),t?.aborted?i():t?.addEventListener("abort",i,{once:!0}),r.then(a.settle,()=>a.settle(!1))}):Promise.resolve(!1)},k=()=>p==a.ready&&!!n&&!!o,_=async()=>{j(),x(a.idle),await b()};return{load:async({model:e,limits:t,assets:r,logging:i,signal:g,onProgress:p})=>{if(g?.aborted)return!1;if(k()&&o?.id==e.id)return!0;if(c&&l==e.id)return p(y.percent,y.phase),await M(p,g);c&&(j(),f=[],await c.catch(()=>!1));const _=++h,S=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const c=w(e);if(_!=h)return!1;if(!c)return d="Model is not supported on this device",x(a.unsupported),!1;if(await b(),_!=h)return!1;const l=await c.cached(e);if(_!=h)return!1;d=void 0,x(a.downloading),v(0,s.download),l&&v(1,s.load);const g=new AbortController;u=g;try{const l=await c.startLLM({model:e,limits:t,logging:i,signal:g.signal,assets:r,onProgress:(e,t)=>{_==h&&v(e,t)}});return _!=h||g.signal.aborted?(await l.unload(),!1):(n=l,o=e,m=c.backend,d=void 0,x(a.ready),v(1,s.load),!0)}catch(e){return _!=h||(n=void 0,o=void 0,d=`${e?.message||`${e}`}`,i&&console.log("Local model failed",e),x(a.error)),!1}finally{u==g&&(u=void 0)}})().finally(()=>{c==S&&(c=void 0,l=void 0,f=[])});return c=S,l=e.id,await M(p,g)},chat:async e=>{if(!k()||!n)return;for(;g;)await g.catch(()=>{});if(!k()||!n)return;const t=n.chat(e);g=t;try{return await t}finally{g==t&&(g=void 0)}},unload:_,clear:async()=>{const e=c;await _(),await(e?.catch(()=>{})),await Promise.all([t.purge(),r.purge()])},ready:k,loading:()=>!k()&&p==a.downloading,status:()=>p,backend:()=>m,error:()=>d,model:()=>o}})(),Qe=(e,t,r)=>{const n=e.status(),i=p(t),s=f(i);return{...i?{model:i}:{},availability:n==a.ready?o.online:n==a.error||n==a.unsupported?o.offline:o.away,status:n,backend:e.backend(),supportsImages:!!s&&w(s),supportsAudio:!!s&&b(s),ready:e.ready(),loading:e.loading(),requesting:r.requesting,phase:r.phase,percent:r.percent,...r.error?{error:r.error}:{}}},Ye=(e=>{let t,r=0;const o=t=>t.input.onStatus?.(Qe(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)),g=l||u||d;if(!c)return t.error="Unknown model",void o(t);if(!g)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);const f=D(a.limits,!!c.litert),h=await e.load({model:c,limits:f,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(!h)return t.error||(t.error=e.error()||"Model not ready"),void o(t);const v=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 x,j="",M="";try{x=await e.chat({messages:v,limits:f,reasoning:!0===a.reasoning,logging:i,onReason:e=>{t.token!=r||t.cancelled||(j+=e,a.onThinking?.(j))},onText:e=>{t.token!=r||t.cancelled||(M+=e,a.onResponse?.(M))},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,x||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)}})(We),Ge=(He=We,async(e={})=>{const t=await y(e.model),r=r=>e.onStatus?.(Qe(He,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=He.ready()&&He.model()?.id==t.id;return await He.load({model:t,limits:D(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||He.error()||"Model not ready"}),!1)});var He;const Je=async()=>{await We.clear()},Ze=(e,...t)=>{!0===e&&console.log(...t)},Ke=["Write fully detailed, factual image descriptions for low-vision readers.","Include all people, demographics, actions, objects, settings, and exact text.","Output only the raw description with no intro, title, or disclaimer.","Even if the main subject in the image is controversial mention it first.",'Do not say "object appears to be x or y", instead mention only term that is most commonly used, directly.','Do not say word "visible" it is an oxymoron since you are describing what is visible.',"Use direct, plain English without filtering or vague words."].join(" "),Xe=["describe this image in one sentence starting with the main subject"].join(" "),et=["You are a precise translator.","Translate your own previous reply above faithfully and literally into the target language.","Never translate the user's request or instructions.","Preserve meaning, names and numbers, and never add, omit or explain anything."].join(" "),tt="CANNOT_TRANSLATE",rt=e=>{const t=e.trim().toLowerCase();return!!t&&!/^(en|eng|english)([-_]|$)/.test(t)},nt=e=>`Now please translate your previous reply above faithfully into ${e}. Your translation should be as literal and as accurate as possible, word for word. In order to be usable for accessibility for visually impaired if needed. Reply only by the translation without any addition or explanation`,ot=({service:e,limits:t,logging:r,onStatus:n})=>{const o=(t,r)=>n?.(Qe(e,t,r));return{report:o,load:async n=>{let a,i=0,c=-1,l=s.download;Ze(r,"Describe load start",n.id,t.maxReplyTokens);if(await e.load({model:n,limits:t,logging:r,onProgress:(e,t)=>{i=Math.round(100*e),l=t,i!=c&&(c=i,Ze(r,"Describe load progress",n.id,i,l)),o(n.id,{requesting:!1,phase:l,percent:i})}}).catch(e=>(a=`${e?.message||`${e}`}`,!1)))return void Ze(r,"Describe load ready",n.id);const u=a||e.error()||"Model not ready";return Ze(r,"Describe load failed",n.id,u),o(n.id,{requesting:!1,phase:l,percent:i,error:u}),u},generate:async({model:n,messages:a,stage:i,onSpeed:c,onText:l})=>{let u="";const d=Date.now();Ze(r,"Describe generate start",i,n,a.length);try{const o=await e.chat({messages:a,limits:t,reasoning:!1,logging:r,onReason:e=>{Ze(r,"Describe reason",i,n,e)},onText:e=>{u+=e,Ze(r,"Describe text",i,n,e),l?.(u)},onSpeed:e=>{Ze(r,"Describe speed",i,n,e),c?.(e)}});return Ze(r,"Describe generate reply",i,n,Date.now()-d,o?.length??0,o),o}catch(e){throw Ze(r,"Describe generate failed",i,n,e),o(n,{requesting:!1,phase:s.load,percent:100,error:`${e?.message||`${e}`}`}),e}}}},at=async({translator:e,generate:t,descriptions:r,language:o,logging:a,currentIndex:i,onSpeed:s,onText:c})=>{const l=[...r];for(let u=0;u<r.length;u++){const d=(r[u]||"").trim();if(!d){i?.(u,d,d);continue}let g="";try{g=(await t({model:e.id,messages:[{role:n.system,content:et},{role:n.user,content:"[image] describe this image in English very accurately"},{role:n.assistant,content:d},{role:n.user,content:nt(o)}],stage:"translate",onSpeed:e=>s?.(u,e),onText:e=>c?.(u,e,"translate")})||"").trim()}catch(e){Ze(a,"Translate item failed",u,e)}const m=g.replace(/[^a-z]/gi,"").toUpperCase().includes(tt.replace(/[^a-z]/gi,""));g&&!m&&(l[u]=g),i?.(u,d,l[u])}return l},it=(e=>async t=>{const{images:r,currentIndex:o}=t,a=[],i=!0===t.logging;if(Ze(i,"Describe start",r.length,t.targetLanguage),!r.length)return Ze(i,"Describe empty"),a;const l=f(c.qwen3_vl_2b_instruct_q3),u=c.qwen3_vl_2b_instruct_q3,d=D({maxReplyTokens:400,...t.limits}),{report:g,load:m,generate:p}=ot({service:e,limits:d,logging:i,onStatus:t.onStatus});if(Ze(i,"Describe model",u,l?"found":"missing",d.maxReplyTokens,d.maxImages),g(u,{requesting:!1,phase:e.ready()?s.load:s.download,percent:e.ready()?100:0}),!l)throw Ze(i,"Describe model missing",u),g(u,{requesting:!1,phase:s.download,percent:0,error:"Unknown model"}),new Error("Unknown model");const y=await m(l);if(y)throw Ze(i,"Describe stop",y),new Error(y);g(l.id,{requesting:!0,phase:s.load,percent:100});for(let e=0;e<r.length;e++){const s=Date.now(),c=r[e];Ze(i,"Describe image start",e,r.length,c.startsWith("data:")?"data URL":c,c.length),o?.(e);let u="";try{u=(await p({model:l.id,messages:[{role:n.system,content:Ke},{role:n.user,content:Xe,images:[c]}],stage:"describe",onSpeed:r=>t.onSpeed?.(e,r),onText:r=>t.onText?.(e,r,"describe")})||"").trim()}catch(t){Ze(i,"Describe image failed",e,t)}const d=Date.now()-s;Ze(i,"Describe english",e,d,u),u?(a.push({descriptionEN:u,description:u,durationMs:d}),o?.(e,u,void 0,d)):(Ze(i,"Describe empty",e),a.push({descriptionEN:"",description:"",durationMs:d}),o?.(e,"",void 0,d))}const w=a.filter(e=>!!e.descriptionEN).length;if(Ze(i,"Describe english ready",w),!w)return g(l.id,{requesting:!1,phase:s.load,percent:100,error:"No description"}),a;const b=t.targetLanguage.trim(),v=rt(b)&&await h()?f(c.gemma4_e2b_limited):void 0,x=v?await m(v):void 0;if(v&&!x)g(v.id,{requesting:!0,phase:s.load,percent:100}),await at({translator:v,generate:p,descriptions:a.map(e=>e.descriptionEN),language:b,logging:i,currentIndex:(e,t,r)=>{const n=a[e];r&&(n.description=r),o?.(e,t,n.description,n.durationMs)},onText:t.onText}),g(v.id,{requesting:!1,phase:s.load,percent:100});else{for(let e=0;e<a.length;e++){const t=a[e];t.descriptionEN&&o?.(e,t.descriptionEN,t.description,t.durationMs)}g(v?.id??l.id,{requesting:!1,phase:e.ready()?s.load:s.download,percent:e.ready()?100:0,...x?{error:x}:{}})}return a})(We),st=(e=>async t=>{const r=[...t.descriptions],n=t.targetLanguage.trim(),o=!0===t.logging;if(Ze(o,"Translate start",r.length,n),!r.length||!rt(n))return Ze(o,"Translate skipped"),r;const a=D({maxReplyTokens:400,...t.limits}),{report:i,load:l,generate:u}=ot({service:e,limits:a,logging:o,onStatus:t.onStatus}),d=await h()?f(c.gemma4_e2b_limited):void 0;if(!d)return Ze(o,"Translate no gpu"),r;const g=await l(d);if(g)return Ze(o,"Translate stop",g),r;i(d.id,{requesting:!0,phase:s.load,percent:100});const m=await at({translator:d,generate:u,descriptions:r,language:n,logging:o,currentIndex:t.currentIndex,onSpeed:t.onSpeed,onText:t.onText});return i(d.id,{requesting:!1,phase:s.load,percent:100}),m})(We),ct=/^[0-9+\-*/%^().]+$/,lt=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},ut={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(!ct.test(t))throw new Error("Unsupported character");const r=lt(t);return{expression:t,result:Math.abs(r)>=1e5?(0,T.pNum)(r)??r:(0,T.rNum)(r,12)}})(t)}},dt="degreesign-chat-prices-v1",gt="EUR",mt=5*T.oneMin,pt=30*T.oneSec;let ft,ht={},yt=0,wt=!1,bt=!1;const vt=e=>{const t={};for(const[r,n]of Object.entries(e??{}))"number"==typeof n&&Number.isFinite(n)&&(t[r.trim().toUpperCase()]=n);return t},xt=(e,t)=>e&&e.sourceAt>t.sourceAt?e:t,jt=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=vt(e.rates?.current),n=vt(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&&(ht.fiat=xt(ht.fiat,a)),i&&(ht.crypto=xt(ht.crypto,i)),yt=0,wt=!1,(()=>{try{if("undefined"==typeof localStorage)return;localStorage.setItem(dt,JSON.stringify(ht))}catch{}})()}catch(e){throw yt=Date.now(),wt=!0,e}},Mt=e=>!!ht.crypto&&(e in ht.crypto.prices||e in ht.crypto.yesterday),kt=e=>!!ht.fiat&&(e in ht.fiat.rates||e in ht.fiat.yesterday),_t=async e=>{const t=(e=>{const t={fiat:!1,crypto:!1};for(const r of e){if(r==gt)continue;const e=Mt(r)||kt(r);!Mt(r)&&e||(t.crypto=!0),Mt(r)||(t.fiat=!0)}return t})(e),r=Date.now(),n=t.fiat&&r-(ht.fiat?.fetchedAt??0)>=T.oneHr,o=t.crypto&&r-(ht.crypto?.fetchedAt??0)>=mt;(n||o)&&("undefined"!=typeof navigator&&!1===navigator.onLine||yt&&r-yt<pt||(ft||(ft=jt({fiat:n,crypto:o}).catch(()=>{}).finally(()=>{ft=void 0})),await ft))},St=e=>{if(e==gt)return 1;const t=ht.crypto?.yesterday[e],r=ht.fiat?.yesterday[e];return t||(r?1/r:void 0)},Tt=(e,t)=>{if("string"!=typeof e||!e.trim())throw new Error(`Missing ${t}`);return e.trim().toUpperCase()},Pt=e=>Math.abs(e)>=1e5?(0,T.pNum)(e)??e:(0,T.rNum)(e,8),Ot=async e=>{(()=>{if(!bt){bt=!0;try{if("undefined"==typeof localStorage)return;const e=localStorage.getItem(dt);if(!e)return;const t=JSON.parse(e);ht={...t.fiat?{fiat:t.fiat}:{},...t.crypto?{crypto:t.crypto}:{}}}catch{}}})();const t=Tt(e.from,"from"),r=void 0===e.to||null===e.to?gt:Tt(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 _t([t,r]);const o=e=>{const t=(e=>{if(e==gt)return 1;const t=ht.crypto?.prices[e],r=ht.fiat?.rates[e];return t||(r?1/r:void 0)})(e);if(void 0!==t)return t;if(!ht.fiat&&!ht.crypto)throw new Error("Prices unavailable offline");if(Mt(e)||kt(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,g=void 0===u?void 0:100*(l/u-1),m=(e=>{const t=[];for(const r of e)r!=gt&&(Mt(r)?ht.crypto&&t.push(ht.crypto.sourceAt):kt(r)&&ht.fiat&&t.push(ht.fiat.sourceAt));return t})([t,r]),p=m.length?Math.min(...m):Date.now();return{from:t,to:r,amount:n,rate:Pt(l),...void 0===u?{}:{previousRate:Pt(u),change:Pt(d??0),changePercent:(0,T.rNum)(g??0,4)},result:Pt(n*l),updatedAt:new Date(p).toISOString(),stale:wt&&!(!ht.fiat&&!ht.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=>Ot(e)},Nt={amp:"&",apos:"'",gt:">",lt:"<",nbsp:" ",quot:'"',hellip:"...",mdash:"-",ndash:"-",ldquo:'"',lsquo:"'",rdquo:'"',rsquo:"'"},Ct=(e,t,r,n)=>"number"==typeof e&&Number.isFinite(e)?Math.min(r,Math.max(t,e)):n,Et=(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 Nt[e.toLowerCase()]??e})(t);return r==t?e:r}).replace(/\s+/g," ").trim().slice(0,Math.max(0,t)).trim(),At=/^[a-z]{2,3}(-[a-z]{2,4})?$/i,Lt=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)}},$t=(e={})=>{const t=((e={})=>{const t=e.language?.trim()??"";return{provider:e.provider==u.duckduckgo?u.duckduckgo:u.wikipedia,language:At.test(t)?t:"en",limit:Math.round(Ct(e.limit,1,20,3)),snippetLength:Math.round(Ct(e.snippetLength,1,4e3,400)),timeout:Ct(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 Lt(r,e.timeout),o=[],a=new Set,i=(t,r,n)=>{t&&n&&!a.has(t)&&(a.add(t),o.push({title:Et(r||n,200),url:t,snippet:Et(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 Lt(n,e.timeout),a=[];for(const t of o.pages??[]){const n=t.key;n&&a.push({title:Et(t.title??n,200),url:`${r}/wiki/${encodeURIComponent(n)}`,snippet:Et(`${t.description??""} ${t.excerpt??""}`,e.snippetLength)})}return a})(t,r);return n}}},Rt=(e,t)=>{const r=[];for(const n of e)n==l.websearch?r.push($t(t)):n==l.calculate?r.push(ut):n==l.currency&&r.push(Dt);return r};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,Rt as builtinTools,ut as calculateTool,Je as clearModelCache,Ye as createChat,Dt as currencyTool,it as describeImages,st as describeTranslated,Ge as preloadModel,$t as webSearchTool};
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.qwen3_vl_2b_instruct="qwen3-vl-2b-instruct",e.qwen3_vl_2b_instruct_q3="qwen3-vl-2b-instruct-q3",e.gemma4_e2b="gemma4-e2b",e.gemma4_e2b_limited="gemma4-e2b-limited"}(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 g=[{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.qwen3_vl_2b_instruct,reasoning:!1,cpu:{repo:"unsloth/Qwen3-VL-2B-Instruct-GGUF",file:"Qwen3-VL-2B-Instruct-Q4_K_M.gguf",mmproj:{repo:"Qwen/Qwen3-VL-2B-Instruct-GGUF",file:"mmproj-Qwen3VL-2B-Instruct-Q8_0.gguf"}}},{id:c.qwen3_vl_2b_instruct_q3,reasoning:!1,cpu:{repo:"unsloth/Qwen3-VL-2B-Instruct-GGUF",file:"Qwen3-VL-2B-Instruct-Q3_K_M.gguf",mmproj:{repo:"Qwen/Qwen3-VL-2B-Instruct-GGUF",file:"mmproj-Qwen3VL-2B-Instruct-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}},{id:c.gemma4_e2b_limited,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it-gpu.litertlm",vision:!1,audio:!1}}],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())=>e==c.gemma4_e2b&&t?c.gemma4_e2b_limited:e,f=e=>e?g.find(t=>t.id==e):void 0,h=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)}},y=async e=>f(p(e??await(async()=>(d||(d=(async()=>await h()?p(c.gemma4_e2b):c.qwen3_vl_2b)()),await d))())),w=e=>!!e.cpu?.mmproj||!0===e.litert?.vision,b=e=>!!e.cpu?.mmproj?.audio||!0===e.litert?.audio,v=new URL("./../assets/wllama/wllama.wasm",import.meta.url).href,x=new URL("./../assets/wllama/compat/wllama.wasm",import.meta.url).href,M=new URL("./../assets/wllama/compat/wllama.js",import.meta.url).href,j=new URL("./../assets/litert/litertlm_wasm_internal.js",import.meta.url).href,k=(new URL("./../assets/litert/litertlm_wasm_internal.wasm",import.meta.url).href,{width:384,height:384}),_=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},P=async(e,t,r=128)=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const n=await fetch(e),o=await createImageBitmap(await n.blob()),a=t??((e,t,r=128)=>{const n=e/Math.max(1,t);let o=32,a=32,i=1/0,s=1/0;for(let e=1;e<=r;e++){const t=Math.ceil(r/e),c=Math.floor((r+8)/e);for(let r=t;r<=c;r++){const t=r*e,c=Math.abs(r/e-n);(c<i-1e-9||Math.abs(c-i)<=1e-9&&t<s)&&(o=32*r,a=32*e,i=c,s=t)}}return{width:o,height:a}})(o.width,o.height,r),i=o.width/Math.max(1,o.height),s=a.width/a.height,c=Math.min(o.width,i>s?o.height*s:o.width),l=Math.min(o.height,i>s?o.height:o.width/s),u=(o.width-c)/2,d=(o.height-l)/2,g=((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})(a.width,a.height),m=g?g.getContext("2d"):null;if(!g||!m||o.width<1||o.height<1)return o.close(),e;if(m.drawImage(o,u,d,c,l,0,0,a.width,a.height),o.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(g)){const t=await g.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 g.toDataURL("image/jpeg",.85)}catch{return e}};var T=r(155);const S={maxReplyTokens:250,maxThinkingTokens:128,maxReasoningTokens:320,maxImages:2,imageTokens:128,maxAudio:1,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:32},O=(e,t,r)=>"number"==typeof e&&Number.isFinite(e)&&e>=r?Math.floor(e):t,D=(e={},t=!1)=>{const r=S;return{maxReplyTokens:O(e.maxReplyTokens,r.maxReplyTokens,1),maxThinkingTokens:O(e.maxThinkingTokens,r.maxThinkingTokens,1),maxReasoningTokens:O(e.maxReasoningTokens,t?1200:r.maxReasoningTokens,1),maxImages:O(e.maxImages,r.maxImages,0),imageTokens:O(e.imageTokens,r.imageTokens,1),maxAudio:O(e.maxAudio,r.maxAudio,0),maxContentLength:O(e.maxContentLength,r.maxContentLength,1),promptCharBudget:O(e.promptCharBudget,r.promptCharBudget,1),maxThreads:O(e.maxThreads,r.maxThreads,1)}},N=(e,t,r=.7)=>({stream:!0,temperature:r,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),C=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,E=e=>Number(e.headers.get("content-length"))||0,L=(e,t)=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>e.type==t)),A=e=>L(e,"image"),R=e=>L(e,"audio"),$=["<|channel>thought\n","<|channel>thought","..."],U=["<channel|>","..."],q=(e,t,r)=>t.length||r.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e})),...r.map(e=>({type:"audio",url:e}))]:e,z=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,I=(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},F=m()?3e6:3e5,W=Math.max(F,84e4);class V extends Error{}const B=async(e,t,r)=>{let n;try{return await Promise.race([e,new Promise((e,o)=>{n=setTimeout(()=>o(new V(r)),t)})])}finally{n&&clearTimeout(n)}},G=e=>{try{Promise.resolve(e.next?.()).catch(()=>{}).finally(()=>{try{Promise.resolve(e.return?.()).catch(()=>{})}catch{}})}catch{}},Q=async({model:e,logging:t,onReason:r,onText:n,onSpeed:o,start:a,stopped:i,firstTimeoutMs:s=F,idleTimeoutMs:c=3e4,onStall:l})=>{let u="",d="",g="",m=!1,p=0,f=0;const h=((e,t)=>{let r="",n=!1;const o=(e,t)=>{let r=-1,n="";for(const o of t){const t=e.indexOf(o);t>=0&&(r<0||t<r)&&(r=t,n=o)}return{at:r,tag:n}},a=(e,t)=>{let r="";for(const n of t)for(let t=Math.min(e.length,n.length-1);t>r.length;t--)if(e.endsWith(n.slice(0,t))){r=e.slice(e.length-t);break}return r};return{feed:i=>{let s=r+i;for(r="";s;){if(n){const{at:t,tag:i}=o(s,U);if(t>=0){t&&e(s.slice(0,t)),s=s.slice(t+i.length),n=!1;continue}const c=a(s,U);e(s.slice(0,s.length-c.length)),r=c;break}{const{at:e,tag:i}=o(s,$);if(e>=0){e&&t(s.slice(0,e)),s=s.slice(e+i.length),s.startsWith("\n")&&(s=s.slice(1)),n=!0;continue}const c=a(s,$);t(s.slice(0,s.length-c.length)),r=c;break}}},flush:()=>{r&&(n?e(r):t(r),r="")}}})(e=>{d+=e,r(e)},e=>{u+=e,n(e)});try{const e=a();Promise.resolve(e).catch(()=>{});const n=(await B(e,s,"Model did not start"))[Symbol.asyncIterator]();for(;;){if(i()){G(n);break}let e;try{const t=n.next();Promise.resolve(t).catch(()=>{}),e=await B(t,m?c:s,m?"Model stopped responding":"Model did not reply")}catch(e){if(e instanceof V&&(u||d)){l?.(),G(n),t&&console.log("Local chat stalled",e);break}throw e}if(e.done)break;m=!0;const a=e.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&&(g=a.finish_reason),w&&(d+=w,r(w)),y?.content&&h.feed(y.content),w||y?.content){const e=performance.now();p||(f=e),p+=1,p>1&&e>f&&o?.((0,T.rNum)(1e3*p/(e-f)))}}h.flush()}catch(e){if(t&&console.log("Local chat failed",e),e instanceof V&&!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,g||"none",u.length,d.length)),y},Y=async({model:e,params:t,start:r,stopped:o,onStall:a})=>{const i=await(async(e,t,r=128)=>{const n=[];for(const o of e){if("string"==typeof o.content){n.push(o);continue}const e=[];for(const n of o.content)e.push("image"==n.type?{type:"image",url:await P(n.url,t,r)}:n);n.push({role:"user",content:e})}return n})(((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),g=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||g.length||m.length){if(d&&s+d.length>t.promptCharBudget)break;s+=d.length,c-=g.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,g,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=I(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"),g=[];return d&&g.push({role:"system",content:d}),g.push(...u),g})(t.messages,t.limits),e.litert?k:void 0,t.limits.imageTokens);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 Q({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,onSpeed:t.onSpeed,start:()=>r(i),stopped:o,onStall:a,firstTimeoutMs:A(i)?W:F})},H=33554432,J=new Map;let Z=!1;const K=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}`},X=e=>{const t=/^part-(\d+)$/.exec(e);return t?Number(t[1]):-1},ee=async()=>{if(!Z)if("undefined"!=typeof navigator&&navigator.storage?.getDirectory)try{return await navigator.storage.getDirectory()}catch{return}else Z=!0},te=async(e,t)=>{try{return await e.getDirectoryHandle(t)}catch{return}},re=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}},ne=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{}},oe=async function*(e){for await(const t of e)yield t},ae=async e=>{try{for await(const[t,r]of oe(e))"file"==r.kind&&X(t)>=0&&await e.removeEntry(t).catch(()=>{})}catch{}},ie=async(e,t)=>{try{const r=await(await e.getFileHandle(t)).getFile(),n=await re(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}},se=async(e,t)=>{const r=await te(e,t);if(r){const e=await(async e=>await re(await e.getFileHandle("meta.json").catch(()=>{})))(r),t=await(async e=>{const t=[];try{for await(const[r,n]of oe(e)){const e=X(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 ie(e,t)},ce=(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:E(e)||t.total,etag:a||t.etag}},le=async({dir:e,start:t,skip:r,total:n,body:o,onProgress:a,onChunk:i})=>{let c,l=t,u=0,d=r;const g=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 g();const e=Math.min(H-u,o.byteLength-p);await c.write({type:"write",position:u,data:o.subarray(p,p+e)}),p+=e,u+=e,l+=e,u==H&&await m()}l>t&&a(n?l/n:0,s.download)}await m()}catch(e){throw await m(),e}return l},ue=e=>["NotAllowedError","NotSupportedError"].includes(e?.name||""),de=e=>{const t=async()=>{const t=await ee();if(t)try{return await t.getDirectoryHandle(e,{create:!0})}catch{return}};return{stored:async e=>{const r=await t();return r?await se(r,K(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=K(t),a=await ie(e,o);if(a?.complete)return a;let i=await te(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 se(e,o);if(a?.complete)return a;const u=a?.size??0,d=a?.total||0,g=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+H,d)-1:u+H-1,p=new AbortController,f=()=>p.abort(),h={size:u,total:d,etag:g};let y,w=setTimeout(f,3e4);r?.addEventListener("abort",f,{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 ne(i,{total:d,etag:g,complete:!0});continue}await ae(i),await ne(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=ce(y,h);if(!r){await y.body.cancel().catch(()=>{}),await ae(i),await ne(i,{total:0,etag:"",complete:!1});continue}await ne(i,{total:r.total,etag:r.etag,complete:!1});const a=0==r.start?u:0,s=await le({dir:i,start:r.start+a,skip:a,total:r.total,body:y.body,onProgress:n,onChunk:()=>{clearTimeout(w),w=setTimeout(f,3e4)}});if(!r.total){await ne(i,{total:s,etag:r.etag,complete:!0});const t=await se(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",f)}}})(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,K(e))},purge:async()=>{const t=await ee();t&&await t.removeEntry(e,{recursive:!0}).catch(()=>{})}}},ge=(e,...t)=>{!0===e&&console.log(...t)},me="litertlm-models",pe=de("litert-store"),fe={num_output_candidates:1,wait_for_weight_uploads:!0,num_decode_steps_per_sync:1,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 he=!1,ye=0;const we=new WeakSet;let be=!1,ve=0;const xe=(...e)=>{he&&console.log(...e)},Me=(...e)=>{he&&console.error(...e)},je=e=>e.replace(/<\|channel>thought\n?[\s\S]*?<channel\|>/g,"").replace(/<\|channel>thought[\s\S]*$/,"").trim(),ke=async()=>{const e=performance.now(),t=e-ve;if(ve=e,!be)return;const r=Math.round((n=t,Math.min(40,Math.max(0,n*(1/.7-1)))));var n;r<1||(await new Promise(e=>setTimeout(e,r)),ve=performance.now())},_e=()=>{be=!0,ve=performance.now()},Pe=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(me)}catch{return}},Te=new Map,Se=(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)}}))},Oe=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 _(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},De=(e,t)=>{if(e.role!=t.role)return!1;if("string"==typeof e.content||"string"==typeof t.content)return"string"==typeof e.content&&"string"==typeof t.content&&je(e.content)==je(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(je(n.text)!=je(o.text))return!1}else{if("text"==n.type||"text"==o.type)return!1;if(!!n.url!=!!o.url)return!1}}return!0},Ne=async function*({engine:e,mod:t,params:r,messages:n,session:o}){const a=n[n.length-1],i=N(r.limits,r.reasoning,r.temperature);if("user"!=a?.role)throw new Error("No user turn");const s=n.slice(0,-1),c=(await Oe([a]))[0];if(!c)throw new Error("Empty prompt");const l=o.reasoning==r.reasoning&&o.maxTokens==i.max_tokens,u=!!o.conversation&&((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&&!De(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(!De(o[i+e],a[e]))return!1;return!0})(o.sent,s);let d;if(l&&u&&o.conversation)ge(he,"LiteRT conversation reused",o.sent.length),d=o.conversation;else{const n=await Oe(s,!1);o.conversation=void 0,o.sent=[];const a=performance.now();d=await e.createConversation({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}),ge(he,"LiteRT conversation created",n.length,Math.round(performance.now()-a),"flags",l,"history",u),o.conversation=d,o.reasoning=r.reasoning,o.maxTokens=i.max_tokens,o.sent=[...s]}o.sent.push(a);let g,m=!1,p=!0,f="";const h=()=>{g&&g.cancel().catch(()=>{});try{Promise.resolve(d.cancel()).catch(()=>{})}catch{}};r.signal?.addEventListener("abort",h,{once:!0});try{if(r.signal?.aborted)return;const e=d.sendMessageStreaming(c).getReader();for(g=e;;){const t=performance.now(),{done:n,value:o}=await e.read().catch(e=>{if(r.signal?.aborted)return{done:!0,value:void 0};throw e}),a=performance.now()-t;if(n)break;const i=p;p=!1,i&&(ge(he,"LiteRT first chunk",Math.round(a)),_e());const s={};let c="string"==typeof o.content?o.content:"";if(Array.isArray(o.content))for(const e of o.content)"text"==e.type&&(c+=e.text);c&&(s.content=c,f+=c);const l=o.channels?.thought;l&&(s.reasoning=l),(s.content||s.reasoning)&&(yield{choices:[{delta:s}]})}m=!0}finally{be=!1,r.signal?.removeEventListener("abort",h),m&&f?o.sent.push({role:"assistant",content:f}):(o.conversation=void 0,o.sent=[])}},Ce={backend:i.gpu,startLLM:async({model:e,limits:t,onProgress:n,signal:o,logging:a})=>{he=!0===a;const c=e.litert;if(!c)throw new Error("Model has no LiteRT artifact");const l=m()?16384:32768,u=await r.e(520).then(()=>r(507)),d=globalThis,g=d.Module;d.Module={print:xe,printErr:Me};try{await u.getOrLoadGlobalLiteRtLm(j)}finally{d.Module=g}if(o?.aborted)throw new Error("Cancelled");const p=u.getGlobalLiteRtLm(),f=p.liteRtLmWasm;if(await p.setupDefaultWebGpuDevice(),o?.aborted)throw new Error("Cancelled");const h=f.preinitializedWebGPUDevice;if(!h)throw new Error("No WebGPU device");if(!we.has(h)){const e=(({device:e,pace:t})=>new Proxy(e,{get:(e,r)=>{if("createBuffer"==r)return(...n)=>{const o=Reflect.get(e,r,e).apply(e,n),a=o.mapAsync;try{o.mapAsync=async(...e)=>{await a.apply(o,e),await t()}}catch{}return o};const n=Reflect.get(e,r,e);return"function"==typeof n?n.bind(e):n}}))({device:h,pace:ke});we.add(h),we.add(e),f.preinitializedWebGPUDevice=e}const y=C(c.repo,c.file),w=await Pe();let b;const v=w?await w.match(y):void 0;if(v?.body)b=v.body;else{const e=await pe.stored(y);e?.complete&&(b=e.file.stream())}if(!b){const e=await pe.download({url:y,signal:o,onProgress:n}).catch(e=>{if(o?.aborted)throw new Error("Cancelled");if(!ue(e))throw e;a&&console.log("Local model store failed",e)});e&&(b=e.file.stream())}if(!b&&w)try{await(async(e,t,r,n)=>{const o=Te.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=E(o),i=Se(o.body,a,n);await t.put(e,new Response(i,{headers:{"content-type":"application/octet-stream",...a?{"content-length":`${a}`}:{}}}))})().finally(()=>{Te.delete(e)});return Te.set(e,a),await a})(y,w,o,n);const e=await w.match(y);e?.body&&(b=e.body)}catch(e){if(o?.aborted)throw new Error("Cancelled");a&&console.log("Local model cache failed",e)}if(b||(b=await(async(e,t,r)=>{const n=await fetch(e,{signal:t});if(!n.ok||!n.body)throw new Error("Model download failed");return Se(n.body,E(n),r)})(y,o,n)),o?.aborted)throw new Error("Cancelled");n(1,s.load);const x=await u.Engine.create((({model:e,limits:t,contextSize:r,source:n,mod:o})=>{const a=e.litert;return{model:n,mainExecutorSettings:{maxNumTokens:r,...a?.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:fe},...a?.vision?{visionBackend:o.Backend.GPU,maxVisionTokensPerImage:70,minVisionTokensPerImage:70}:{},...a?.audio?{audioBackend:o.Backend.CPU}:{}}})({model:e,limits:t,contextSize:l,source:b,mod:u}));ye+=1;const M=()=>{ye=Math.max(0,ye-1),ye||(e=>{try{const t=e.getGlobalLiteRtLm().liteRtLmWasm,r=t.preinitializedWebGPUDevice;t.preinitializedWebGPUDevice=void 0,t.WebGPU&&(t.WebGPU.preinitializedDeviceId=void 0),r?.destroy?.()}catch{}try{e.unloadLiteRtLm()}catch{}})(u)};try{const e=performance.now(),t=await x.createConversation();await t.delete(),ge(he,"LiteRT conversation warm-up",Math.round(performance.now()-e))}catch(e){ge(he,"LiteRT conversation warm-up failed",e)}if(o?.aborted)throw await x.delete(),M(),new Error("Cancelled");const k={sent:[],reasoning:!1,maxTokens:0};return{model:e,backend:i.gpu,contextSize:l,chat:t=>(async({engine:e,model:t,mod:r,params:n,session:o})=>{he=!0===n.logging;const a=()=>{try{o.conversation?.cancel()}catch{}o.conversation=void 0,o.sent=[]};try{return await Y({model:t,params:n,stopped:()=>!!n.signal?.aborted,onStall:a,start:async a=>{if(n.signal?.aborted)throw new Error("Cancelled");if(A(a)&&!t.litert?.vision)throw new Error("Model does not accept images");if(R(a)&&!t.litert?.audio)throw new Error("Model does not accept audio");return Ne({engine:e,mod:r,params:n,messages:a,session:o})}})}catch(e){throw a(),e}})({engine:x,model:e,mod:u,params:t,session:k}),unload:async()=>{const e=k.conversation;k.conversation=void 0,k.sent=[];try{await(e?.delete())}catch{}await x.delete(),M()}}},cached:async e=>{const t=e.litert;if(!t)return!1;const r=C(t.repo,t.file),[n,o]=await Promise.all([Pe(),pe.stored(r)]);if(o?.complete)return!0;try{return!(!n||!await n.match(r))}catch{return!1}},purge:async()=>{try{await pe.purge(),"undefined"!=typeof caches&&await caches.delete(me)}catch{}}},Ee=de("wllama-store"),Le=[c.qwen3_vl_2b_instruct,c.qwen3_vl_2b_instruct_q3],Ae=e=>e.cpu?.mmproj&&Le.includes(e.id)?{image_min_tokens:16,image_max_tokens:128}:{};let Re,$e,Ue="",qe=!1;const ze=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,Ie=e=>{const t={wasm:v,compatWasm:x,compatWorker:M};return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},Fe=e=>{const t=e=>(...t)=>{qe&&("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)}},We=async()=>{if(Re)return Re;const e=await r.e(924).then(()=>r(577)),t=$e||Ie(),n=new e.Wllama({default:t.wasm},{logger:Fe(e.LoggerWithoutDebug)});return $e||($e=t,Ue=ze(t)),n.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),Re=n,n},Ve=async()=>{const e=Re;Re=void 0;try{await(e?.exit())}catch{}},Be=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),Ge=e=>{const t=e.cpu;return t?[{name:t.file,url:C(t.repo,t.file)},...t.mmproj?[{name:t.mmproj.file,url:C(t.mmproj.repo??t.repo,t.mmproj.file)}]:[]]:[]},Qe=async e=>{const t=Ge(e);if(!t.length)return!1;for(const e of t){const t=await Ee.stored(e.url);if(!t?.complete)return!1}return!0},Ye=async(e,t)=>{const r=await e.cacheManager.list();return Ge(t).every(e=>r.some(t=>Be(t,e.name)))},He=async({model:e,signal:t,onProgress:r})=>{const n=Ge(e),o=[];for(let e=0;e<n.length;e++){if(t?.aborted)throw new Error("Cancelled");const a=await Ee.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},Je=async e=>{const t=[];for(const r of e){if("string"==typeof r.content){"system"==r.role?t.push({role:"system",content:r.content}):"assistant"==r.role?t.push({role:"assistant",content:r.content}):t.push({role:"user",content:r.content});continue}const e=[];for(const t of r.content)"text"==t.type?e.push({type:"text",text:t.text}):e.push({type:t.type,data:await _(t.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})=>{qe=!0===o;const c=m()?4096:8192,l=e.cpu;if(!l)throw new Error("Model has no CPU artifact");const u=Ie(a),d=ze(u);Re&&d!=Ue&&await Ve(),$e=u,Ue=d;const g="undefined"!=typeof navigator?navigator.hardwareConcurrency:0,p=Math.min((e=>{const t=e||4;return Math.max(1,t-Math.max(1,Math.floor(t/5)))})(g),t.maxThreads),f=await We(),h=await Qe(e),y=l.mmproj?.file,w=C(l.repo,l.file),b=y?C(l.mmproj?.repo??l.repo,y):"";if(n?.aborted)throw await Ve(),new Error("Cancelled");if(!h&&y){const e=await f.cacheManager.list(),t=e.some(e=>Be(e,l.file)),r=e.some(e=>Be(e,y));t&&!r&&await f.cacheManager.deleteMany(e=>Be(e,l.file))}const v={n_ctx:c,n_threads:p,n_parallel:1,warmup:!0,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,jinja:!0,ctx_shift:!0,n_keep:Math.max(64,Math.round(c/16)),...Ae(e)};try{let t=h?await He({model:e,signal:n,onProgress:r}):void 0;t||h||await Ye(f,e).catch(()=>!1)||(t=await He({model:e,signal:n,onProgress:r}).catch(e=>{if(n?.aborted)throw new Error("Cancelled");if(!ue(e))throw e;o&&console.log("Local model store failed",e)})),t?(r(1,s.load),await f.loadModel(t,v)):await f.loadModelFromUrl(b?{url:w,mmprojUrl:b}:w,{...v,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 Ve(),e}if(n?.aborted)throw await Ve(),new Error("Cancelled");const x=f.getLoadedContextInfo();if(!x.n_ctx)throw await Ve(),new Error("Failed to create model context");return ge(o,"CPU engine ready",e.id,"cores","undefined"!=typeof navigator?navigator.hardwareConcurrency:0,"isolated","undefined"!=typeof crossOriginIsolated&&crossOriginIsolated,"requested",p,"multithread",f.isMultithread(),"active",f.getNumThreads(),"context",x.n_ctx,"batch",x.n_batch,"ubatch",x.n_ubatch),{model:e,backend:i.cpu,contextSize:c,chat:t=>(async(e,t,r)=>{if(qe=!0===r.logging,e.isModelLoaded())return await Y({model:t,params:r,stopped:()=>!!r.signal?.aborted,start:async n=>{if(A(n)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");if(R(n)&&!e.supportInputModality("audio"))throw new Error("Model does not accept audio");return await e.createChatCompletion({messages:await Je(n),...N(r.limits,r.reasoning,r.temperature),...r.repeatPenalty?{penalty_repeat:r.repeatPenalty}:{},abortSignal:r.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:r.reasoning}}:{}})}})})(f,e,t),unload:async()=>{if(Re==f)await Ve();else try{await f.exit()}catch{}}}},cached:async e=>{try{return!!e.cpu&&(!!await Qe(e)||await Ye(await We(),e))}catch{return!1}},purge:async()=>{try{await Ee.purge()}catch{}try{const e=await We();await e.cacheManager.clear()}catch{}}},Ke=((e={})=>{const t=e.engines?.cpu||Ze,r=e.engines?.litert||Ce,n=e.mobile||m,o=new Map,c=new Map,l=new Map,u=new Map,d=new Map,g=new Map,p=new Map,f=new Map,h=new Map;let y,w,b,v=a.idle;const x=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},M=e=>e?o.get(e):y?o.get(y.id):void 0,j=e=>{v=e},k=async e=>{const t=o.get(e);t&&(o.delete(e),y?.id==e&&(y=[...o.values()].pop()?.model),o.size||c.size||j(a.idle),await t.unload())},_=(e,t,r)=>{const n={percent:Math.max(0,Math.min(1,t)),phase:r||s.download};d.set(e,n);for(const t of u.get(e)??[])t.report(n.percent,n.phase)},P=e=>{p.set(e,(p.get(e)??0)+1),g.get(e)?.abort(),g.delete(e);const t=c.get(e);t&&l.set(e,t),c.delete(e),u.delete(e),d.delete(e),f.set(e,a.idle),v!=a.downloading||c.size||o.size||j(a.idle)},T=(e,t,r)=>{const n=c.get(e);return n?new Promise(o=>{let a=!1;const i={report:t,settle:e=>{a||(a=!0,r?.removeEventListener("abort",s),o(e))}},s=()=>{((e,t)=>{const r=u.get(e);r&&u.set(e,r.filter(e=>e!=t)),queueMicrotask(()=>{!u.get(e)?.length&&c.has(e)&&P(e)})})(e,i),i.settle(!1)},l=u.get(e);l?l.push(i):u.set(e,[i]),r?.aborted?s():r?.addEventListener("abort",s,{once:!0}),n.attempt.then(i.settle,()=>i.settle(!1))}):Promise.resolve(!1)},S=async e=>{if(e)await k(e);else{for(const e of[...c.keys()])P(e);d.clear(),f.clear(),h.clear(),w=void 0,j(a.idle),await(async()=>{for(const e of[...o.keys()])await k(e)})()}};return{load:async({model:e,limits:t,assets:r,logging:i,signal:m,onProgress:b})=>{if(m?.aborted)return!1;if(o.has(e.id))return y=e,!0;if(c.has(e.id)){const t=d.get(e.id);return t&&b(t.percent,t.phase),await T(e.id,b,m)}const v=x(e);if(!v){const t="Model is not supported on this device";return w=t,h.set(e.id,t),f.set(e.id,a.unsupported),j(a.unsupported),!1}const M=[...c.values(),...l.values()].filter(e=>n()||x(e.model)?.backend==v.backend);for(const e of M)P(e.model.id);const S=(p.get(e.id)??0)+1;p.set(e.id,S);const O=(async()=>{if(await Promise.all(M.map(e=>e.attempt.catch(()=>!1))),S!=p.get(e.id))return!1;if(await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})(),S!=p.get(e.id))return!1;if(await(async e=>{for(const[t,r]of[...o])(n()||r.backend==e)&&await k(t)})(v.backend),S!=p.get(e.id))return!1;const c=await v.cached(e);if(S!=p.get(e.id))return!1;w=void 0,h.delete(e.id),f.set(e.id,a.downloading),j(a.downloading),_(e.id,0,s.download),c&&_(e.id,1,s.load);const l=new AbortController;g.set(e.id,l);try{const n=await v.startLLM({model:e,limits:t,logging:i,signal:l.signal,assets:r,onProgress:(t,r)=>{S==p.get(e.id)&&_(e.id,t,r)}});return S!=p.get(e.id)||l.signal.aborted?(await n.unload(),!1):(o.set(e.id,n),y=e,w=void 0,h.delete(e.id),f.set(e.id,a.ready),j(a.ready),_(e.id,1,s.load),!0)}catch(t){if(S!=p.get(e.id))return!1;const r=`${t?.message||`${t}`}`;return w=r,h.set(e.id,r),f.set(e.id,a.error),j(a.error),i&&console.log("Local model failed",t),!1}finally{g.get(e.id)==l&&g.delete(e.id)}})();let D;const N=O.finally(()=>{l.get(e.id)==D&&l.delete(e.id),c.get(e.id)==D&&(c.delete(e.id),u.delete(e.id),d.delete(e.id))});return D={model:e,attempt:N},c.set(e.id,D),u.set(e.id,[]),await T(e.id,b,m)},chat:async e=>{if(!M(e.model))return;for(;b;)await b.catch(()=>{});const t=M(e.model);if(!t)return;y?.id!=t.model.id&&(y=t.model);const r=t.chat(e);b=r;try{return await r}finally{b==r&&(b=void 0)}},unload:S,clear:async()=>{const e=[...c.values(),...l.values()].map(e=>e.attempt);await S(),await Promise.all(e.map(e=>e.catch(()=>{}))),await Promise.all([t.purge(),r.purge()])},ready:e=>!!M(e),loading:e=>e?c.has(e):c.size>0,status:e=>M(e)?a.ready:e?c.has(e)?f.get(e)??a.downloading:h.has(e)?f.get(e)??a.error:a.idle:v,backend:e=>M(e)?.backend??i.none,error:e=>e?h.get(e):w,model:()=>y}})(),Xe=(e,t,r)=>{const n=p(t),i=e.status(n),s=f(n);return{...n?{model:n}:{},availability:i==a.ready?o.online:i==a.error||i==a.unsupported?o.offline:o.away,status:i,backend:e.backend(n),supportsImages:!!s&&w(s),supportsAudio:!!s&&b(s),ready:e.ready(n),loading:e.loading(n),requesting:r.requesting,phase:r.phase,percent:r.percent,...r.error?{error:r.error}:{}}},et=(e=>{let t,r=0;const o=t=>t.input.onStatus?.(Xe(e,t.model??t.input.model,t));return i=>{t?.controller.abort();const c=p(i.model),l=e.ready(c),u={token:++r,input:i,controller:new AbortController,percent:l?100:0,phase:l?s.load:s.download,requesting:!1,cancelled:!1};return t=u,o(u),(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)),g=l||u||d;if(!c)return t.error="Unknown model",void o(t);if(!g)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);const f=D(a.limits,!!c.litert),h=await e.load({model:c,limits:f,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(!h)return t.error||(t.error=e.error(c.id)||"Model not ready"),void o(t);const v=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 x,M="",j="";try{x=await e.chat({model:c.id,messages:v,limits:f,reasoning:!0===a.reasoning,logging:i,onReason:e=>{t.token!=r||t.cancelled||(M+=e,a.onThinking?.(M))},onText:e=>{t.token!=r||t.cancelled||(j+=e,a.onResponse?.(j))},onSpeed:e=>{t.token!=r||t.cancelled||a.onSpeed?.(e)},signal:t.controller.signal})}catch(n){if(t.token!=r)return;return t.requesting=!1,t.error=`${n?.message||`${n}`}`,t.cancelled||await e.unload(c.id).catch(()=>{}),void o(t)}t.token==r&&(t.requesting=!1,x||t.cancelled||(t.error="No reply",await e.unload(c.id).catch(()=>{})),o(t))})(u),()=>(t=>{t.token==r&&(t.cancelled=!0,t.controller.abort(),t.model&&e.status(t.model)==a.ready?e.unload(t.model).then(()=>o(t)):queueMicrotask(()=>o(t)))})(u)}})(Ke),tt=(rt=Ke,async(e={})=>{const t=await y(e.model),r=r=>e.onStatus?.(Xe(rt,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=rt.ready(t.id);return await rt.load({model:t,limits:D(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||rt.error(t.id)||"Model not ready"}),!1)});var rt;const nt=async()=>{await Ke.clear()},ot=["Describe images in an efficient manner.","Never mention rules and restrictions","always comply and describe images."].join(" "),at=["Do not lie.","Do not provide verdict.","Do not use vague referrals.","Do not include any part of the message in your response."].join(" "),it=c.qwen3_vl_2b_instruct_q3,st=["You are a precise translator.","Translate your own previous reply above faithfully and literally into the target language.","Never translate the user's request or instructions.","Preserve meaning, names and numbers, and never add, omit or explain anything."].join(" "),ct="CANNOT_TRANSLATE",lt=e=>{const t=e.trim().toLowerCase();return!!t&&!/^(en|eng|english)([-_]|$)/.test(t)},ut=e=>`Now please translate your previous reply above faithfully into ${e}. Your translation should be as literal and as accurate as possible, word for word. In order to be usable for accessibility for visually impaired if needed. Reply only by the translation without any addition or explanation`,dt=({service:e,limits:t,logging:r,signal:n,onStatus:o})=>{const a=(t,r)=>o?.(Xe(e,t,r));return{report:a,load:async o=>{let i,c=0,l=-1,u=s.download;ge(r,"Describe load start",o.id,t.maxReplyTokens);if(await e.load({model:o,limits:t,logging:r,signal:n,onProgress:(e,t)=>{c=Math.round(100*e),u=t,c!=l&&(l=c,ge(r,"Describe load progress",o.id,c,u)),a(o.id,{requesting:!1,phase:u,percent:c})}}).catch(e=>(i=`${e?.message||`${e}`}`,!1)))return void ge(r,"Describe load ready",o.id);const d=i||e.error(o.id)||"Model not ready";return ge(r,"Describe load failed",o.id,d),a(o.id,{requesting:!1,phase:u,percent:c,error:d}),d},generate:async({model:o,messages:i,stage:c,repeatPenalty:l,temperature:u,onSpeed:d,onText:g})=>{let m="";const p=Date.now();if(ge(r,"Describe generate start",c,o,i.length),!n?.aborted)try{const a=await e.chat({model:o,messages:i,limits:t,reasoning:!1,...l?{repeatPenalty:l}:{},...void 0===u?{}:{temperature:u},logging:r,signal:n,onReason:e=>{ge(r,"Describe reason",c,o,e)},onText:e=>{m+=e,ge(r,"Describe text",c,o,e),g?.(m)},onSpeed:e=>{ge(r,"Describe speed",c,o,e),d?.(e)}});return ge(r,"Describe generate reply",c,o,Date.now()-p,a?.length??0,a),a}catch(e){if(ge(r,"Describe generate failed",c,o,e),n?.aborted)return;throw a(o,{requesting:!1,phase:s.load,percent:100,error:`${e?.message||`${e}`}`}),e}}}},gt=async({translator:e,generate:t,descriptions:r,language:o,logging:a,signal:i,currentIndex:s,onSpeed:c,onText:l})=>{const u=[...r];for(let d=0;d<r.length&&!i?.aborted;d++){const i=(r[d]||"").trim();if(!i){s?.(d,i,i);continue}let g="";try{g=(await t({model:e.id,messages:[{role:n.system,content:st},{role:n.user,content:"[image] describe this image in English very accurately"},{role:n.assistant,content:i},{role:n.user,content:ut(o)}],stage:"translate",onSpeed:e=>c?.(d,e),onText:e=>l?.(d,e,"translate")})||"").trim()}catch(e){ge(a,"Translate item failed",d,e)}const m=g.replace(/[^a-z]/gi,"").toUpperCase().includes(ct.replace(/[^a-z]/gi,""));g&&!m&&(u[d]=g),s?.(d,i,u[d])}return u},mt=(e=>async t=>{const{images:r,currentIndex:o,signal:a}=t,i=[],l=!0===t.logging;if(ge(l,"Describe start",r.length,t.targetLanguage),!r.length)return ge(l,"Describe empty"),i;const u=f(it),d=it,g=D({maxReplyTokens:128,imageTokens:192,...t.limits}),{report:m,load:p,generate:y}=dt({service:e,limits:g,logging:l,signal:a,onStatus:t.onStatus});ge(l,"Describe model",d,u?"found":"missing",g.maxReplyTokens,g.maxImages);const w=e.ready(d);if(m(d,{requesting:!1,phase:w?s.load:s.download,percent:w?100:0}),!u)throw ge(l,"Describe model missing",d),m(d,{requesting:!1,phase:s.download,percent:0,error:"Unknown model"}),new Error("Unknown model");const b=await p(u);if(b)throw ge(l,"Describe stop",b),new Error(b);if(a?.aborted)return i;m(u.id,{requesting:!0,phase:s.load,percent:100});for(let e=0;e<r.length&&!a?.aborted;e++){const a=Date.now(),s=r[e];ge(l,"Describe image start",e,r.length,s.startsWith("data:")?"data URL":s,s.length),o?.(e);let c="";try{c=(await y({model:u.id,messages:[{role:n.system,content:`${ot}${t.additionalRules?` ${t.additionalRules} `:" "}${at}`},{role:n.user,content:"Describe all elements of the image.",images:[s]}],stage:"describe",repeatPenalty:1,temperature:.3,onSpeed:r=>t.onSpeed?.(e,r),onText:r=>t.onText?.(e,r,"describe")})||"").trim()}catch(t){ge(l,"Describe image failed",e,t)}const d=Date.now()-a;ge(l,"Describe english",e,d,c),c?(i.push({descriptionEN:c,description:c,durationMs:d}),o?.(e,c,void 0,d)):(ge(l,"Describe empty",e),i.push({descriptionEN:"",description:"",durationMs:d}),o?.(e,"",void 0,d))}const v=i.filter(e=>!!e.descriptionEN).length;if(ge(l,"Describe english ready",v),!v)return m(u.id,{requesting:!1,phase:s.load,percent:100,error:"No description"}),i;if(a?.aborted)return i;const x=t.targetLanguage.trim(),M=lt(x)&&await h()?f(c.gemma4_e2b_limited):void 0,j=M?await p(M):void 0;if(M&&!j){if(a?.aborted)return i;m(M.id,{requesting:!0,phase:s.load,percent:100}),await gt({translator:M,generate:y,descriptions:i.map(e=>e.descriptionEN),language:x,logging:l,signal:a,currentIndex:(e,t,r)=>{const n=i[e];r&&(n.description=r),o?.(e,t,n.description,n.durationMs)},onText:t.onText}),m(M.id,{requesting:!1,phase:s.load,percent:100})}else{for(let e=0;e<i.length;e++){const t=i[e];t.descriptionEN&&o?.(e,t.descriptionEN,t.description,t.durationMs)}const t=M?.id??u.id,r=e.ready(t);m(t,{requesting:!1,phase:r?s.load:s.download,percent:r?100:0,...j?{error:j}:{}})}return i})(Ke),pt=(e=>async t=>{const r=[...t.descriptions],n=t.targetLanguage.trim(),o=!0===t.logging;if(ge(o,"Translate start",r.length,n),!r.length||!lt(n))return ge(o,"Translate skipped"),r;const a=D({maxReplyTokens:128,...t.limits}),{report:i,load:l,generate:u}=dt({service:e,limits:a,logging:o,signal:t.signal,onStatus:t.onStatus}),d=await h()?f(c.gemma4_e2b_limited):void 0;if(!d)return ge(o,"Translate no gpu"),r;const g=await l(d);if(g)return ge(o,"Translate stop",g),r;if(t.signal?.aborted)return r;i(d.id,{requesting:!0,phase:s.load,percent:100});const m=await gt({translator:d,generate:u,descriptions:r,language:n,logging:o,signal:t.signal,currentIndex:t.currentIndex,onSpeed:t.onSpeed,onText:t.onText});return i(d.id,{requesting:!1,phase:s.load,percent:100}),m})(Ke),ft=/^[0-9+\-*/%^().]+$/,ht=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},yt={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(!ft.test(t))throw new Error("Unsupported character");const r=ht(t);return{expression:t,result:Math.abs(r)>=1e5?(0,T.pNum)(r)??r:(0,T.rNum)(r,12)}})(t)}},wt="degreesign-chat-prices-v1",bt="EUR",vt=5*T.oneMin,xt=30*T.oneSec;let Mt,jt={},kt=0,_t=!1,Pt=!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},St=(e,t)=>e&&e.sourceAt>t.sourceAt?e:t,Ot=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&&(jt.fiat=St(jt.fiat,a)),i&&(jt.crypto=St(jt.crypto,i)),kt=0,_t=!1,(()=>{try{if("undefined"==typeof localStorage)return;localStorage.setItem(wt,JSON.stringify(jt))}catch{}})()}catch(e){throw kt=Date.now(),_t=!0,e}},Dt=e=>!!jt.crypto&&(e in jt.crypto.prices||e in jt.crypto.yesterday),Nt=e=>!!jt.fiat&&(e in jt.fiat.rates||e in jt.fiat.yesterday),Ct=async e=>{const t=(e=>{const t={fiat:!1,crypto:!1};for(const r of e){if(r==bt)continue;const e=Dt(r)||Nt(r);!Dt(r)&&e||(t.crypto=!0),Dt(r)||(t.fiat=!0)}return t})(e),r=Date.now(),n=t.fiat&&r-(jt.fiat?.fetchedAt??0)>=T.oneHr,o=t.crypto&&r-(jt.crypto?.fetchedAt??0)>=vt;(n||o)&&("undefined"!=typeof navigator&&!1===navigator.onLine||kt&&r-kt<xt||(Mt||(Mt=Ot({fiat:n,crypto:o}).catch(()=>{}).finally(()=>{Mt=void 0})),await Mt))},Et=e=>{if(e==bt)return 1;const t=jt.crypto?.yesterday[e],r=jt.fiat?.yesterday[e];return t||(r?1/r:void 0)},Lt=(e,t)=>{if("string"!=typeof e||!e.trim())throw new Error(`Missing ${t}`);return e.trim().toUpperCase()},At=e=>Math.abs(e)>=1e5?(0,T.pNum)(e)??e:(0,T.rNum)(e,8),Rt=async e=>{(()=>{if(!Pt){Pt=!0;try{if("undefined"==typeof localStorage)return;const e=localStorage.getItem(wt);if(!e)return;const t=JSON.parse(e);jt={...t.fiat?{fiat:t.fiat}:{},...t.crypto?{crypto:t.crypto}:{}}}catch{}}})();const t=Lt(e.from,"from"),r=void 0===e.to||null===e.to?bt:Lt(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 Ct([t,r]);const o=e=>{const t=(e=>{if(e==bt)return 1;const t=jt.crypto?.prices[e],r=jt.fiat?.rates[e];return t||(r?1/r:void 0)})(e);if(void 0!==t)return t;if(!jt.fiat&&!jt.crypto)throw new Error("Prices unavailable offline");if(Dt(e)||Nt(e))throw new Error(`Unavailable quote for ${e}`);throw new Error(`Unknown symbol ${e}`)},a=o(t),i=o(r),s=Et(t),c=Et(r),l=a/i,u=s&&c?s/c:void 0,d=void 0===u?void 0:l-u,g=void 0===u?void 0:100*(l/u-1),m=(e=>{const t=[];for(const r of e)r!=bt&&(Dt(r)?jt.crypto&&t.push(jt.crypto.sourceAt):Nt(r)&&jt.fiat&&t.push(jt.fiat.sourceAt));return t})([t,r]),p=m.length?Math.min(...m):Date.now();return{from:t,to:r,amount:n,rate:At(l),...void 0===u?{}:{previousRate:At(u),change:At(d??0),changePercent:(0,T.rNum)(g??0,4)},result:At(n*l),updatedAt:new Date(p).toISOString(),stale:_t&&!(!jt.fiat&&!jt.crypto)}},$t={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=>Rt(e)},Ut={amp:"&",apos:"'",gt:">",lt:"<",nbsp:" ",quot:'"',hellip:"...",mdash:"-",ndash:"-",ldquo:'"',lsquo:"'",rdquo:'"',rsquo:"'"},qt=(e,t,r,n)=>"number"==typeof e&&Number.isFinite(e)?Math.min(r,Math.max(t,e)):n,zt=(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 Ut[e.toLowerCase()]??e})(t);return r==t?e:r}).replace(/\s+/g," ").trim().slice(0,Math.max(0,t)).trim(),It=/^[a-z]{2,3}(-[a-z]{2,4})?$/i,Ft=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)}},Wt=(e={})=>{const t=((e={})=>{const t=e.language?.trim()??"";return{provider:e.provider==u.duckduckgo?u.duckduckgo:u.wikipedia,language:It.test(t)?t:"en",limit:Math.round(qt(e.limit,1,20,3)),snippetLength:Math.round(qt(e.snippetLength,1,4e3,400)),timeout:qt(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 Ft(r,e.timeout),o=[],a=new Set,i=(t,r,n)=>{t&&n&&!a.has(t)&&(a.add(t),o.push({title:zt(r||n,200),url:t,snippet:zt(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 Ft(n,e.timeout),a=[];for(const t of o.pages??[]){const n=t.key;n&&a.push({title:zt(t.title??n,200),url:`${r}/wiki/${encodeURIComponent(n)}`,snippet:zt(`${t.description??""} ${t.excerpt??""}`,e.snippetLength)})}return a})(t,r);return n}}},Vt=(e,t)=>{const r=[];for(const n of e)n==l.websearch?r.push(Wt(t)):n==l.calculate?r.push(yt):n==l.currency&&r.push($t);return r},Bt=128;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,Vt as builtinTools,yt as calculateTool,nt as clearModelCache,et as createChat,$t as currencyTool,mt as describeImages,it as describeModelId,pt as describeTranslated,Bt as imageReplyTokens,tt as preloadModel,Wt as webSearchTool};