@degreesign/chat 0.5.1 → 0.6.0

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