@degreesign/chat 0.3.3 → 0.3.5

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
@@ -220,10 +220,10 @@ follow the flag.
220
220
  | `qwen3_vl_2b` | Qwen3-VL 2B | Yes | Yes | Yes | No |
221
221
  | `gemma4_e2b` | Gemma 4 E2B | Yes | Yes | No | Yes |
222
222
 
223
- The first call downloads the model through its engine and caches it. Later
224
- calls reuse the loaded runtime. Only one model stays in memory. An interrupted
225
- download keeps the bytes it stored and resumes on the next attempt, including
226
- after a reload.
223
+ The first call downloads the model before its engine loads it. Later calls
224
+ reuse the loaded runtime. Only one model stays in memory. An interrupted
225
+ download keeps every part it committed and resumes from the last one on the
226
+ next attempt, including after a reload.
227
227
 
228
228
  Qwen3-VL 2B downloads a vision projector of about 445 MB with the model, so its
229
229
  total download is about 1.5 GB. It runs on the CPU engine.
@@ -300,22 +300,26 @@ changed. A page inside an iframe is isolated only when every ancestor sets the
300
300
  same headers.
301
301
 
302
302
  Each engine keeps its own cache. Loading a model unloads the previous runtime
303
- and removes the previous model's cache. The CPU engine uses the wllama cache
304
- manager. The GPU engine stores the single `.litertlm` file in the origin private
305
- file system under `litert-store`, and reads a Cache Storage entry under
306
- `litertlm-models` when an older version stored one. A quota failure purges the
307
- cache of the engine being loaded.
308
-
309
- The GPU engine stores the file before it compiles the model, and one download
310
- serves every caller. A failed compile, a cancelled call or a repeated
311
- `createChat` reads the stored file instead of downloading it again. A download
312
- cut short keeps its bytes and continues from that offset with a range request,
313
- checking the file size and entity tag so a changed model starts over. Hosts
314
- without a writable file system still stream from the network and fall back to
315
- Cache Storage, without resuming.
316
-
317
- A CPU vision model downloads its projector with the model and caches both. A
318
- GPU vision model keeps its encoder in the single `.litertlm` file.
303
+ and removes the previous model's cache. Both engines store model files in the
304
+ origin private file system as numbered parts, under `wllama-store` for the CPU
305
+ engine and `litert-store` for the GPU engine. The GPU engine also reads a Cache
306
+ Storage entry under `litertlm-models` when an older version stored the file. A
307
+ quota failure keeps the parts already stored, so freeing disk lets the next
308
+ attempt resume.
309
+
310
+ Both engines store the files before they load them, and one download serves
311
+ every caller. A failed load, a cancelled call or a repeated `createChat` reads
312
+ the stored parts instead of downloading them again. A download fetches bounded
313
+ ranges of 32 MB, commits each part as it arrives and retries a stalled or cut
314
+ connection from the last committed byte, so a reload loses at most one part.
315
+ Each attempt checks the file size and entity tag, and a changed model starts
316
+ over. A host that ignores the range replays the stored prefix and keeps the
317
+ parts already stored. Hosts without a writable file system still stream from
318
+ the network; the CPU engine falls back to the wllama cache manager and the GPU
319
+ engine to Cache Storage, without resuming.
320
+
321
+ A CPU vision model downloads its projector with the model and stores both files
322
+ as parts. A GPU vision model keeps its encoder in the single `.litertlm` file.
319
323
 
320
324
  Both engines are bundled into `dist/browser` and `dist/node` as dynamic chunks.
321
325
  The package ships the wllama binaries under `dist/assets/wllama` and the LiteRT
@@ -445,9 +449,10 @@ download no engine code beyond the chunk they use.
445
449
 
446
450
  ### Where are the models stored?
447
451
 
448
- The CPU engine owns its cache through the wllama cache manager. The GPU engine
449
- stores its model in Cache Storage under `litertlm-models`. The package stores no
450
- model data itself.
452
+ Both engines store model files in the origin private file system as resumable
453
+ parts, under `wllama-store` for the CPU engine and `litert-store` for the GPU
454
+ engine. The GPU engine also reads a Cache Storage entry under `litertlm-models`
455
+ when an older version stored the file. The package stores no model data itself.
451
456
 
452
457
  ### Which model should I pick?
453
458
 
@@ -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,s,i,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 s,i,c=0;for(s in o)n.o(o,s)&&(n.m[s]=o[s]);for(r&&r(n);c<a.length;c++)i=a[c],n.o(t,i)&&t[i]&&t[i][0](),t[i]=0};n.f.j=(o,r)=>{let s=n.o(t,o)?t[o]:void 0;if(0!==s)if(s)r.push(s[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=>s=t[o]=[e])]),r.push(s[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"}(s||(s={})),function(e){e.download="download",e.load="load"}(i||(i={})),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}}],d=e=>e?l.find(t=>t.id==e):void 0,g=e=>!!e.cpu?.mmproj||!!e.litert?.vision,m=new URL("./../assets/wllama/wllama.wasm",import.meta.url).href,u=new URL("./../assets/wllama/compat/wllama.wasm",import.meta.url).href,p=new URL("./../assets/wllama/compat/wllama.js",import.meta.url).href,f=new URL("./../assets/litert/litertlm_wasm_internal.js",import.meta.url).href,h=(new URL("./../assets/litert/litertlm_wasm_internal.wasm",import.meta.url).href,288),w=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},y=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),s=((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})(h,h),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,h,h),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.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 s.toDataURL("image/jpeg",.85)}catch{return e}},b={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},x=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,k=(e={})=>{const t=b;return{maxReplyTokens:x(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:x(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:x(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:x(e.maxImages,t.maxImages,0),maxContentLength:x(e.maxContentLength,t.maxContentLength,1),promptCharBudget:x(e.promptCharBudget,t.promptCharBudget,1),maxThreads:x(e.maxThreads,t.maxThreads,1)}},v=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),_=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,M=e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)),T=["<|channel>thought\n","<|channel>thought","..."],L=["<channel|>","..."],C=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,R=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,E=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...R(e),{type:"text",text:"\n"},...R(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},j=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((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:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,L);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,L);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,T);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,T);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},q=async({model:e,params:t,start:n,stopped:o})=>{const r=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 y(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=b)=>{const n=t.maxContentLength,o=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=a.user||!e.images?.length)),r=[],s=[];let i=0,c=t.maxImages;for(let e=o.length-1;e>=0;e--){const l=o[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==a.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==a.system?r.unshift(d):l.role==a.assistant?s.unshift({role:"assistant",content:d}):s.unshift({role:"user",content:C(d,g)})}}for(;s.length&&"user"!=s[0].role;)s.shift();const l=[];for(const e of s){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=E(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=r.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),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}:{}})))})(e,r),await j({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(r),stopped:o})},P="litertlm-models",W={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},$=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(P)}catch{return}},B=new Map,U=e=>Number(e.headers.get("content-length"))||0,I=(e,t,n)=>{let a=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{a+=e.byteLength,n(t?a/t:0,i.download),o.enqueue(e)}}))},O=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push({role:n.role,content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await w(t.url)});t.push({role:"user",content:e})}return t},A=async({engine:e,model:t,mod:n,params:a})=>await q({model:t,params:a,stopped:()=>!!a.signal?.aborted,start:async o=>{if(a.signal?.aborted)throw new Error("Cancelled");if(M(o)&&!t.litert?.vision)throw new Error("Model does not accept images");return async function*({engine:e,mod:t,params:n,messages:a}){const o=a[a.length-1],r=v(n.limits,n.reasoning);if("user"!=o?.role)throw new Error("No user turn");const s=await O(a.slice(0,-1)),i=(await O([o]))[0];if(!i)throw new Error("Empty prompt");const c=await e.createConversation({sessionConfig:{maxOutputTokens:r.max_tokens,samplerParams:{type:t.SamplerType.TOP_K,temperature:r.temperature,k:40,p:.95}},preface:{...s.length?{messages:s}:{},extra_context:{enable_thinking:n.reasoning}}});let l;const d=()=>{l&&l.cancel().catch(()=>{});try{c.cancel()}catch{}};n.signal?.addEventListener("abort",d,{once:!0});try{if(n.signal?.aborted)return;const e=c.sendMessageStreaming(i).getReader();for(l=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);const r=n.channels?.thought;r&&(a.reasoning=r),(a.content||a.reasoning)&&(yield{choices:[{delta:a}]})}}finally{n.signal?.removeEventListener("abort",d);try{await c.delete()}catch{}}}({engine:e,mod:n,params:a,messages:o})}}),S={backend:s.gpu,startLLM:async({model:e,limits:t,onProgress:a,signal:o,logging:r})=>{const c=e.litert;if(!c)throw new Error("Model has no LiteRT artifact");const l=await n.e(520).then(()=>n(507));if(await l.getOrLoadGlobalLiteRtLm(f),o?.aborted)throw new Error("Cancelled");const d=_(c.repo,c.file),g=await $();let m;if(g){if(!await g.match(d))try{await(async(e,t,n,a)=>{const o=B.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=U(o),s=I(o.body,r,a);await t.put(e,new Response(s,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{B.delete(e)});return B.set(e,r),await r})(d,g,o,a)}catch(e){if(o?.aborted)throw new Error("Cancelled");r&&console.log("Local model cache failed",e)}const e=await g.match(d);e?.body&&(m=e.body)}if(m||(m=await(async(e,t,n)=>{const a=await fetch(e,{signal:t});if(!a.ok||!a.body)throw new Error("Model download failed");return I(a.body,U(a),n)})(d,o,a)),o?.aborted)throw new Error("Cancelled");a(1,i.load);const u=await l.Engine.create({model:m,mainExecutorSettings:{maxNumTokens:4096,...c.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:W},...c.vision?{visionBackend:l.Backend.GPU}:{}});if(o?.aborted)throw await u.delete(),new Error("Cancelled");return{model:e,backend:s.gpu,contextSize:4096,chat:t=>A({engine:u,model:e,mod:l,params:t}),unload:async()=>{await u.delete()}}},cached:async e=>{try{const t=e.litert,n=await $();return!(!t||!n)&&!!await n.match(_(t.repo,t.file))}catch{return!1}},hasCache:async()=>{try{const e=await $();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert,n=await $();if(!t||!n)return;await n.delete(_(t.repo,t.file))}catch{}},purge:async()=>{try{"undefined"!=typeof caches&&await caches.delete(P)}catch{}}};let F,N,Q="",z=!1;const G=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,D=e=>{const t={wasm:m,compatWasm:u,compatWorker:p};return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},V=e=>{const t=e=>(...t)=>{z&&("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)}},K=async()=>{if(F)return F;const e=await n.e(924).then(()=>n(577)),t=N||D(),a=new e.Wllama({default:t.wasm},{logger:V(e.LoggerWithoutDebug)});return N||(N=t,Q=G(t)),a.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),F=a,a},H=async()=>{const e=F;F=void 0;try{await(e?.exit())}catch{}},J=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),X=e=>e.cpu?[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]]:[],Y=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)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await w(t.url)});t.push({role:"user",content:e})}return t},Z={backend:s.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{z=!0===o;const c=e.cpu;if(!c)throw new Error("Model has no CPU artifact");const l=D(r),d=G(l);F&&d!=Q&&await H(),N=l,Q=d;const g=(m="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,u=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(m||4)-1)),u)));var m,u;const p=await K(),f=_(c.repo,c.file),h=c.mmproj?.file,w=h?_(c.repo,h):"";if(a?.aborted)throw await H(),new Error("Cancelled");if(h){const e=await p.cacheManager.list(),t=e.some(e=>J(e,c.file)),n=e.some(e=>J(e,h));t&&!n&&await p.cacheManager.deleteMany(e=>J(e,c.file))}try{await p.loadModelFromUrl(w?{url:f,mmprojUrl:w}:f,{n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?i.load:i.download)}})}catch(e){throw await H(),e}if(a?.aborted)throw await H(),new Error("Cancelled");if(!p.getLoadedContextInfo().n_ctx)throw await H(),new Error("Failed to create model context");return{model:e,backend:s.cpu,contextSize:8192,chat:t=>(async(e,t,n)=>{if(z=!0===n.logging,e.isModelLoaded())return await q({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if(M(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await Y(a),...v(n.limits,n.reasoning),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}})}})})(p,e,t),unload:async()=>{if(F==p)await H();else try{await p.exit()}catch{}}}},cached:async e=>{try{if(!e.cpu)return!1;const t=await K(),n=await t.cacheManager.list();return X(e).every(e=>n.some(t=>J(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await K();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{if(!e.cpu)return;const t=await K();await t.cacheManager.deleteMany(t=>X(e).some(e=>J(t,e)))}catch{}},purge:async()=>{try{const e=await K();await e.cacheManager.clear()}catch{}}},ee=((e={})=>{const t=e.engines?.cpu||Z,n=e.engines?.litert||S;let a,o,c,d,g,m,u,p=s.none,f=r.idle,h=[],w=0,y={percent:0,phase:i.download};const b=a=>{if(e.backend!=s.none)return e.backend==s.cpu?a.cpu?t:void 0:e.backend==s.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)=>{y={percent:Math.max(0,Math.min(1,e)),phase:t||i.download};for(const e of[...h])e.report(y.percent,y.phase)},k=e=>{f=e},v=()=>{w++,m?.abort(),m=void 0,g=void 0,f==r.downloading&&k(r.idle)},_=(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",s),a(e))}},s=()=>{(e=>{h=h.filter(t=>t!=e),queueMicrotask(()=>{!h.length&&d&&v()})})(r),r.settle(!1)};h.push(r),t?.aborted?s():t?.addEventListener("abort",s,{once:!0}),n.then(r.settle,()=>r.settle(!1))}):Promise.resolve(!1)},M=()=>f==r.ready&&!!a&&!!o;return{load:async({model:e,limits:t,assets:n,logging:s,signal:u,onProgress:f})=>{if(u?.aborted)return!1;if(M()&&o?.id==e.id)return!0;if(d&&g==e.id)return f(y.percent,y.phase),await _(f,u);d&&(v(),h=[],await d.catch(()=>!1));const T=++w,L=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const d=b(e);if(T!=w)return!1;if(!d)return 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&&b(n)==t&&await t.remove(n)})(e,d),T!=w)return!1;const g=await d.cached(e);if(T!=w)return!1;if(!g&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await d.purge(),T!=w)return!1;k(r.downloading),x(0,i.download),g&&x(1,i.load);const u=new AbortController;m=u;try{const l=await d.startLLM({model:e,limits:t,logging:s,signal:u.signal,assets:n,onProgress:(e,t)=>{T==w&&x(e,t)}});return T!=w||u.signal.aborted?(await l.unload(),!1):(a=l,o=e,c=d,p=d.backend,k(r.ready),x(1,i.load),!0)}catch(e){return T!=w||(a=void 0,o=void 0,c=void 0,s&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await d.purge(),k(r.error)),!1}finally{m==u&&(m=void 0)}})().finally(()=>{d==L&&(d=void 0,g=void 0,h=[])});return d=L,g=e.id,await _(f,u)},chat:async e=>{if(!M()||!a)return;for(;u;)await u.catch(()=>{});if(!M()||!a)return;const t=a.chat(e);u=t;try{return await t}finally{u==t&&(u=void 0)}},unload:async()=>{const e=a;v(),a=void 0,o=void 0,c=void 0,k(r.idle),await(e?.unload())},ready:M,loading:()=>!M()&&f==r.downloading,status:()=>f,backend:()=>p,model:()=>o}})(),te=(e,t,n)=>{const a=e.status(),s=d(t);return{availability:a==r.ready?o.online:a==r.error||a==r.unsupported?o.offline:o.away,status:a,backend:e.backend(),supportsImages:!!s&&g(s),ready:e.ready(),loading:e.loading(),requesting:n.requesting,phase:n.phase,percent:n.percent,...n.error?{error:n.error}:{}}},ne=(e=>{let t,n=0;const o=t=>t.input.onStatus?.(te(e,t.input.model,t));return s=>{t?.controller.abort();const c={token:++n,input:s,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?i.load:i.download,requesting:!1,cancelled:!1};return t=c,o(c),(async t=>{const{input:r}=t,s=!0===r.logging,c=d(r.model),l=r.messages.some(e=>e.role!=a.system&&"string"==typeof e.content&&!!e.content.trim()),m=r.messages.some(e=>e.role==a.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),u=l||m;if(!c)return t.error="Unknown model",void o(t);if(!u)return void o(t);if(m&&!l&&!g(c))return t.error="Model does not accept images",void o(t);const p=k(r.limits),f=await e.load({model:c,limits:p,logging:s,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(!f)return t.error||(t.error="Model not ready"),void o(t);const h=g(c),w=m&&!h?r.messages.map(({images:e,...t})=>t):r.messages;if(m&&!h&&!l)return t.error="Model does not accept images",void o(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=i.load,o(t);let y,b="",x="";try{y=await e.chat({messages:w,limits:p,reasoning:!0===r.reasoning,logging:s,onReason:e=>{t.token!=n||t.cancelled||(b+=e,r.onThinking?.(b))},onText:e=>{t.token!=n||t.cancelled||(x+=e,r.onResponse?.(x))},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,y||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)}})(ee),ae=(oe=ee,async e=>{const t=d(e.model),n=t=>e.onStatus?.(te(oe,e.model,t));if(!t)return n({requesting:!1,phase:i.download,percent:0,error:"Unknown model"}),!1;let a,o=0,r=i.download;const s=oe.ready()&&oe.model()?.id==t.id;return await oe.load({model:t,limits:k(e.limits),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))?(s&&n({requesting:!1,phase:i.load,percent:100}),!0):(n({requesting:!1,phase:r,percent:o,error:a||"Model not ready"}),!1)});var oe;export{c as ChatModelId,o as ChatStatus,s as LlmBackend,i as LlmPhase,a as LlmRole,r as LlmStatus,ne as createChat,ae as preloadModel};
2
+ var e={};const t={};function a(n){const o=t[n];if(void 0!==o)return o.exports;const r=t[n]={exports:{}};return e[n](r,r.exports,a),r.exports}var n,o,r,i,s,c;a.m=e,a.d=(e,t)=>{for(var n in t)a.o(t,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},a.f={},a.e=e=>{const t=[];return a.f.j(e,t),Promise.all(t)},a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a.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__:r}=e;var i,s,c=0;for(i in o)a.o(o,i)&&(a.m[i]=o[i]);for(r&&r(a);c<n.length;c++)s=n[c],a.o(t,s)&&t[s]&&t[s][0](),t[s]=0};a.f.j=(o,r)=>{let i=a.o(t,o)?t[o]:void 0;if(0!==i)if(i)r.push(i[1]);else{let a=e[o]().then(n,e=>{throw 0!==t[o]&&(t[o]=void 0),e});a=Promise.race([a,new Promise(e=>i=t[o]=[e])]),r.push(i[1]=a)}}})(),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"}(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}}],d=e=>e?l.find(t=>t.id==e):void 0,g=e=>!!e.cpu?.mmproj||!!e.litert?.vision,u=new URL("./../assets/wllama/wllama.wasm",import.meta.url).href,m=new URL("./../assets/wllama/compat/wllama.wasm",import.meta.url).href,f=new URL("./../assets/wllama/compat/wllama.js",import.meta.url).href,w=new URL("./../assets/litert/litertlm_wasm_internal.js",import.meta.url).href,p=(new URL("./../assets/litert/litertlm_wasm_internal.wasm",import.meta.url).href,288),h=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),a=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!a.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},y=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),a=await createImageBitmap(await t.blob()),n=Math.min(a.width,a.height),o=Math.floor((a.width-n)/2),r=Math.floor((a.height-n)/2),i=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const a=document.createElement("canvas");return a.width=e,a.height=t,a})(p,p),s=i?i.getContext("2d"):null;if(!i||!s||n<1)return a.close(),e;if(s.drawImage(a,o,r,n,n,0,0,p,p),a.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 a=new FileReader;a.onerror=()=>t(""),a.onload=()=>t(`${a.result}`),a.readAsDataURL(e)}))(t)||e}return i.toDataURL("image/jpeg",.85)}catch{return e}},b={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},v=(e,t,a)=>"number"==typeof e&&Number.isFinite(e)&&e>=a?Math.floor(e):t,k=(e={})=>{const t=b;return{maxReplyTokens:v(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:v(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:v(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:v(e.maxImages,t.maxImages,0),maxContentLength:v(e.maxContentLength,t.maxContentLength,1),promptCharBudget:v(e.promptCharBudget,t.promptCharBudget,1),maxThreads:v(e.maxThreads,t.maxThreads,1)}},x=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),_=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,M=e=>Number(e.headers.get("content-length"))||0,E=e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)),C=["<|channel>thought\n","<|channel>thought","..."],T=["<channel|>","..."],L=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,R=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,P=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const a=[];for(const n of[...R(e),{type:"text",text:"\n"},...R(t)]){const e=a[a.length-1];"text"==n.type&&"text"==e?.type?e.text+=n.text:a.push(n)}return a},$=async({model:e,logging:t,onReason:a,onText:n,start:o,stopped:r})=>{let i="",s="",c="";const l=((e,t)=>{let a="",n=!1;const o=(e,t)=>{let a=-1,n="";for(const o of t){const t=e.indexOf(o);t>=0&&(a<0||t<a)&&(a=t,n=o)}return{at:a,tag:n}},r=(e,t)=>{let a="";for(const n of t)for(let t=Math.min(e.length,n.length-1);t>a.length;t--)if(e.endsWith(n.slice(0,t))){a=e.slice(e.length-t);break}return a};return{feed:i=>{let s=a+i;for(a="";s;){if(n){const{at:t,tag:i}=o(s,T);if(t>=0){t&&e(s.slice(0,t)),s=s.slice(t+i.length),n=!1;continue}const c=r(s,T);e(s.slice(0,s.length-c.length)),a=c;break}{const{at:e,tag:i}=o(s,C);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=r(s,C);t(s.slice(0,s.length-c.length)),a=c;break}}},flush:()=>{a&&(n?e(a):t(a),a="")}}})(e=>{s+=e,a(e)},e=>{i+=e,n(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],n=e?.delta,o="string"==typeof n?.reasoning_content?n.reasoning_content:"string"==typeof n?.reasoning?n.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(s+=o,a(o)),n?.content&&l.feed(n.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:i||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",i.length,s.length)),d},j=async({model:e,params:t,start:a,stopped:o})=>{const r=await(async e=>{const t=[];for(const a of e){if("string"==typeof a.content){t.push(a);continue}const e=[];for(const t of a.content)e.push("image"==t.type?{type:"image",url:await y(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=b)=>{const a=t.maxContentLength,o=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=n.user||!e.images?.length)),r=[],i=[];let s=0,c=t.maxImages;for(let e=o.length-1;e>=0;e--){const l=o[e],d=("string"==typeof l.content?l.content:"").slice(0,a),g=l.role==n.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&s+d.length>t.promptCharBudget)break;s+=d.length,c-=g.length,l.role==n.system?r.unshift(d):l.role==n.assistant?i.unshift({role:"assistant",content:d}):i.unshift({role:"user",content:L(d,g)})}}for(;i.length&&"user"!=i[0].role;)i.shift();const l=[];for(const e of i){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=P(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=r.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),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}:{}})))})(e,r),await $({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>a(r),stopped:o})},W=33554432,z=new Map;let B=!1;const S=e=>{const t=(e.split("/").pop()||"model").replace(/[^\w.-]+/g,"_");let a=0;for(let t=0;t<e.length;t++)a=31*a+e.charCodeAt(t)>>>0;return`${a.toString(16)}-${t}`},q=e=>{const t=/^part-(\d+)$/.exec(e);return t?Number(t[1]):-1},A=async()=>{if(!B)if("undefined"!=typeof navigator&&navigator.storage?.getDirectory)try{return await navigator.storage.getDirectory()}catch{return}else B=!0},O=async(e,t)=>{try{return await e.getDirectoryHandle(t)}catch{return}},N=async e=>{if(e)try{const t=await e.getFile(),a=JSON.parse(await t.text());return{total:Number(a.total)||0,etag:`${a.etag||""}`,complete:!0===a.complete}}catch{return}},U=async(e,t)=>{try{const a=await e.getFileHandle("meta.json",{create:!0}),n=await a.createWritable();await n.write(JSON.stringify(t)),await n.close()}catch{}},F=async function*(e){for await(const t of e)yield t},I=async e=>{try{for await(const[t,a]of F(e))"file"==a.kind&&q(t)>=0&&await e.removeEntry(t).catch(()=>{})}catch{}},D=async(e,t)=>{try{const a=await(await e.getFileHandle(t)).getFile(),n=await N(await e.getFileHandle(`${t}.json`).catch(()=>{}));if(!n)return;return{file:a,size:a.size,total:n.total,etag:n.etag,complete:n.total?a.size>=n.total:!0===n.complete}}catch{return}},H=async(e,t)=>{const a=await O(e,t);if(a){const e=await(async e=>await N(await e.getFileHandle("meta.json").catch(()=>{})))(a),t=await(async e=>{const t=[];try{for await(const[a,n]of F(e)){const e=q(a);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 a=(e=>{const t=[];let a=0;for(const n of[...e].sort((e,t)=>e.start-t.start))if(n.size){if(n.start!=a)break;t.push(n),a+=n.size}return t})(t.map(e=>e.part)),n=new Set(a.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:a.reduce((e,t)=>e+t.size,0)}})(a),n=e?.total||0,o=t?.size??0,r=t?.file??new Blob;return{file:n&&o>n?r.slice(0,n):r,size:o,total:n,etag:e?.etag||"",complete:n?o>=n:!0===e?.complete}}return await D(e,t)},Q=(e,t)=>{const a=e.headers.get("content-range"),n=/bytes (\d+)-/.exec(a||""),o=/\/(\d+)\s*$/.exec(a||""),r=e.headers.get("etag")||"";if(206==e.status){const e=n?Number(n[1]):t.size,a=o?Number(o[1]):t.total;if(e!=t.size)return;if(t.total&&a&&t.total!=a)return;if(t.etag&&r&&t.etag!=r)return;return{start:e,total:a||t.total,etag:r||t.etag}}if(!t.etag||!r||t.etag==r)return{start:0,total:M(e)||t.total,etag:r||t.etag}},G=async({dir:e,start:t,skip:a,total:n,body:o,onProgress:r,onChunk:i})=>{let c,l=t,d=0,g=a;const u=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:a,value:o}=await e.read();if(a)break;i();let f=0;for(g&&(f=Math.min(g,o.byteLength),g-=f);f<o.byteLength;){c||await u();const e=Math.min(W-d,o.byteLength-f);await c.write({type:"write",position:d,data:o.subarray(f,f+e)}),f+=e,d+=e,l+=e,d==W&&await m()}l>t&&r(n?l/n:0,s.download)}await m()}catch(e){throw await m(),e}return l},V=e=>["NotAllowedError","NotSupportedError"].includes(e?.name||""),J=e=>{const t=async()=>{const t=await A();if(t)try{return await t.getDirectoryHandle(e,{create:!0})}catch{return}};return{stored:async e=>{const a=await t();return a?await H(a,S(e)):void 0},download:async({url:a,signal:n,onProgress:o})=>{const r=`${e}|${a}`,i=z.get(r);if(i)return await i;const c=await t();if(!c)return;const l=(async(e,t,a,n)=>{const o=S(t),r=await D(e,o);if(r?.complete)return r;let i=await O(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(a?.aborted)throw new Error("Cancelled");const r=await H(e,o);if(r?.complete)return r;const d=r?.size??0,g=r?.total||0,u=r?.etag||"";if(d>c)c=d,l=0;else if(++l>4)throw new Error("Model download failed");d&&g&&n(d/g,s.download);const m=g?Math.min(d+W,g)-1:d+W-1,f=new AbortController,w=()=>f.abort(),p={size:d,total:g,etag:u};let h,y=setTimeout(w,3e4);a?.addEventListener("abort",w,{once:!0});try{if(h=await fetch(t,{signal:f.signal,headers:{Range:`bytes=${d}-${m}`}}),416==h.status){if(await(h.body?.cancel().catch(()=>{})),g&&d>=g){await U(i,{total:g,etag:u,complete:!0});continue}await I(i),await U(i,{total:0,etag:"",complete:!1});continue}if(!h.ok||!h.body)throw await(h.body?.cancel().catch(()=>{})),new Error("Model download failed");const a=Q(h,p);if(!a){await h.body.cancel().catch(()=>{}),await I(i),await U(i,{total:0,etag:"",complete:!1});continue}await U(i,{total:a.total,etag:a.etag,complete:!1});const r=0==a.start?d:0,s=await G({dir:i,start:a.start+r,skip:r,total:a.total,body:h.body,onProgress:n,onChunk:()=>{clearTimeout(y),y=setTimeout(w,3e4)}});if(!a.total){await U(i,{total:s,etag:a.etag,complete:!0});const t=await H(e,o);if(t)return t}}catch(e){if(a?.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),a?.removeEventListener("abort",w)}}})(c,a,n,o).finally(()=>{z.delete(r)});return z.set(r,l),await l},remove:async e=>{const a=await t();a&&await(async(e,t)=>{await e.removeEntry(t,{recursive:!0}).catch(()=>{}),await e.removeEntry(`${t}.json`).catch(()=>{})})(a,S(e))},purge:async()=>{const t=await A();t&&await t.removeEntry(e,{recursive:!0}).catch(()=>{})}}},K="litertlm-models",X=J("litert-store"),Y={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},Z=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(K)}catch{return}},ee=new Map,te=(e,t,a)=>{let n=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{n+=e.byteLength,a(t?n/t:0,s.download),o.enqueue(e)}}))},ae=async e=>{const t=[];for(const a of e){if("string"==typeof a.content){t.push({role:a.role,content:a.content});continue}const e=[];for(const t of a.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await h(t.url)});t.push({role:"user",content:e})}return t},ne=async({engine:e,model:t,mod:a,params:n})=>await j({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async o=>{if(n.signal?.aborted)throw new Error("Cancelled");if(E(o)&&!t.litert?.vision)throw new Error("Model does not accept images");return async function*({engine:e,mod:t,params:a,messages:n}){const o=n[n.length-1],r=x(a.limits,a.reasoning);if("user"!=o?.role)throw new Error("No user turn");const i=await ae(n.slice(0,-1)),s=(await ae([o]))[0];if(!s)throw new Error("Empty prompt");const c=await e.createConversation({sessionConfig:{maxOutputTokens:r.max_tokens,samplerParams:{type:t.SamplerType.TOP_K,temperature:r.temperature,k:40,p:.95}},preface:{...i.length?{messages:i}:{},extra_context:{enable_thinking:a.reasoning}}});let l;const d=()=>{l&&l.cancel().catch(()=>{});try{c.cancel()}catch{}};a.signal?.addEventListener("abort",d,{once:!0});try{if(a.signal?.aborted)return;const e=c.sendMessageStreaming(s).getReader();for(l=e;;){const{done:t,value:a}=await e.read();if(t)break;const n={};let o="string"==typeof a.content?a.content:"";if(Array.isArray(a.content))for(const e of a.content)"text"==e.type&&(o+=e.text);o&&(n.content=o);const r=a.channels?.thought;r&&(n.reasoning=r),(n.content||n.reasoning)&&(yield{choices:[{delta:n}]})}}finally{a.signal?.removeEventListener("abort",d);try{await c.delete()}catch{}}}({engine:e,mod:a,params:n,messages:o})}}),oe={backend:i.gpu,startLLM:async({model:e,limits:t,onProgress:n,signal:o,logging:r})=>{const c=e.litert;if(!c)throw new Error("Model has no LiteRT artifact");const l=await a.e(520).then(()=>a(507));if(await l.getOrLoadGlobalLiteRtLm(w),o?.aborted)throw new Error("Cancelled");const d=_(c.repo,c.file),g=await Z();let u;const m=g?await g.match(d):void 0;if(m?.body)u=m.body;else{const e=await X.stored(d);e?.complete&&(u=e.file.stream())}if(!u){const e=await X.download({url:d,signal:o,onProgress:n}).catch(e=>{if(o?.aborted)throw new Error("Cancelled");if(!V(e))throw e;r&&console.log("Local model store failed",e)});e&&(u=e.file.stream())}if(!u&&g)try{await(async(e,t,a,n)=>{const o=ee.get(e);if(o)return await o;const r=(async()=>{const o=await fetch(e,{signal:a});if(!o.ok||!o.body)throw new Error("Model download failed");const r=M(o),i=te(o.body,r,n);await t.put(e,new Response(i,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{ee.delete(e)});return ee.set(e,r),await r})(d,g,o,n);const e=await g.match(d);e?.body&&(u=e.body)}catch(e){if(o?.aborted)throw new Error("Cancelled");r&&console.log("Local model cache failed",e)}if(u||(u=await(async(e,t,a)=>{const n=await fetch(e,{signal:t});if(!n.ok||!n.body)throw new Error("Model download failed");return te(n.body,M(n),a)})(d,o,n)),o?.aborted)throw new Error("Cancelled");n(1,s.load);const f=await l.Engine.create({model:u,mainExecutorSettings:{maxNumTokens:4096,...c.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:Y},...c.vision?{visionBackend:l.Backend.GPU}:{}});if(o?.aborted)throw await f.delete(),new Error("Cancelled");return{model:e,backend:i.gpu,contextSize:4096,chat:t=>ne({engine:f,model:e,mod:l,params:t}),unload:async()=>{await f.delete()}}},cached:async e=>{const t=e.litert;if(!t)return!1;const a=_(t.repo,t.file),[n,o]=await Promise.all([Z(),X.stored(a)]);if(o?.complete)return!0;try{return!(!n||!await n.match(a))}catch{return!1}},hasCache:async()=>{try{for(const e of l){const t=e.litert;if(!t)continue;if(await X.stored(_(t.repo,t.file)))return!0}const e=await Z();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert;if(!t)return;const a=_(t.repo,t.file),n=await Z();await X.remove(a),n&&await n.delete(a)}catch{}},purge:async()=>{try{await X.purge(),"undefined"!=typeof caches&&await caches.delete(K)}catch{}}},re=J("wllama-store");let ie,se,ce="",le=!1;const de=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,ge=e=>{const t={wasm:u,compatWasm:m,compatWorker:f};return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},ue=e=>{const t=e=>(...t)=>{le&&("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)}},me=async()=>{if(ie)return ie;const e=await a.e(924).then(()=>a(577)),t=se||ge(),n=new e.Wllama({default:t.wasm},{logger:ue(e.LoggerWithoutDebug)});return se||(se=t,ce=de(t)),n.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),ie=n,n},fe=async()=>{const e=ie;ie=void 0;try{await(e?.exit())}catch{}},we=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),pe=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)}]:[]]:[]},he=async e=>{const t=pe(e);if(!t.length)return!1;for(const e of t){const t=await re.stored(e.url);if(!t?.complete)return!1}return!0},ye=async(e,t)=>{const a=await e.cacheManager.list();return pe(t).every(e=>a.some(t=>we(t,e.name)))},be=async({model:e,signal:t,onProgress:a})=>{const n=pe(e),o=[];for(let e=0;e<n.length;e++){if(t?.aborted)throw new Error("Cancelled");const r=await re.download({url:n[e].url,signal:t,onProgress:(t,o)=>a((e+t)/n.length,o)});if(!r)return;o.push(r.file)}return o.length?o:void 0},ve=async e=>{const t=[];for(const a of e){if("string"==typeof a.content){"system"==a.role?t.push({role:"system",content:a.content}):"assistant"==a.role?t.push({role:"assistant",content:a.content}):t.push({role:"user",content:a.content});continue}const e=[];for(const t of a.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await h(t.url)});t.push({role:"user",content:e})}return t},ke={backend:i.cpu,startLLM:async({model:e,limits:t,onProgress:a,signal:n,logging:o,assets:r})=>{le=!0===o;const c=e.cpu;if(!c)throw new Error("Model has no CPU artifact");const l=ge(r),d=de(l);ie&&d!=ce&&await fe(),se=l,ce=d;const g=(u="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,m=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(u||4)-1)),m)));var u,m;const f=await me(),w=await he(e),p=c.mmproj?.file,h=_(c.repo,c.file),y=p?_(c.repo,p):"";if(n?.aborted)throw await fe(),new Error("Cancelled");if(!w&&p){const e=await f.cacheManager.list(),t=e.some(e=>we(e,c.file)),a=e.some(e=>we(e,p));t&&!a&&await f.cacheManager.deleteMany(e=>we(e,c.file))}const b={n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,jinja:!0};try{let t=w?await be({model:e,signal:n,onProgress:a}):void 0;t||w||await ye(f,e).catch(()=>!1)||(t=await be({model:e,signal:n,onProgress:a}).catch(e=>{if(n?.aborted)throw new Error("Cancelled");if(!V(e))throw e;o&&console.log("Local model store failed",e)})),t?(a(1,s.load),await f.loadModel(t,b)):await f.loadModelFromUrl(y?{url:h,mmprojUrl:y}:h,{...b,useCache:!0,signal:n,progressCallback:({loaded:e,total:t})=>{const n=t?e/t:0;a(n,n>=1?s.load:s.download)}})}catch(e){throw await fe(),e}if(n?.aborted)throw await fe(),new Error("Cancelled");if(!f.getLoadedContextInfo().n_ctx)throw await fe(),new Error("Failed to create model context");return{model:e,backend:i.cpu,contextSize:8192,chat:t=>(async(e,t,a)=>{if(le=!0===a.logging,e.isModelLoaded())return await j({model:t,params:a,stopped:()=>!!a.signal?.aborted,start:async n=>{if(E(n)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await ve(n),...x(a.limits,a.reasoning),abortSignal:a.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:a.reasoning}}:{}})}})})(f,e,t),unload:async()=>{if(ie==f)await fe();else try{await f.exit()}catch{}}}},cached:async e=>{try{return!!e.cpu&&(!!await he(e)||await ye(await me(),e))}catch{return!1}},hasCache:async()=>{try{for(const e of l.flatMap(e=>pe(e)))if(await re.stored(e.url))return!0;const e=await me();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{const t=pe(e);try{for(const e of t)await re.remove(e.url)}catch{}try{const e=await me();await e.cacheManager.deleteMany(e=>t.some(t=>we(e,t.name)))}catch{}},purge:async()=>{try{await re.purge()}catch{}try{const e=await me();await e.cacheManager.clear()}catch{}}},xe=((e={})=>{const t=e.engines?.cpu||ke,a=e.engines?.litert||oe;let n,o,c,d,g,u,m,f=i.none,w=r.idle,p=[],h=0,y={percent:0,phase:s.download};const b=n=>{if(e.backend!=i.none)return e.backend==i.cpu?n.cpu?t:void 0:e.backend==i.gpu?n.litert?a:void 0:n.litert&&"undefined"!=typeof navigator&&navigator.gpu&&"undefined"!=typeof WebAssembly?a:!n.cpu||"undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?void 0:t},v=(e,t)=>{y={percent:Math.max(0,Math.min(1,e)),phase:t||s.download};for(const e of[...p])e.report(y.percent,y.phase)},k=e=>{w=e},x=()=>{h++,u?.abort(),u=void 0,g=void 0,w==r.downloading&&k(r.idle)},_=(e,t)=>{const a=d;return a?new Promise(n=>{let o=!1;const r={report:e,settle:e=>{o||(o=!0,t?.removeEventListener("abort",i),n(e))}},i=()=>{(e=>{p=p.filter(t=>t!=e),queueMicrotask(()=>{!p.length&&d&&x()})})(r),r.settle(!1)};p.push(r),t?.aborted?i():t?.addEventListener("abort",i,{once:!0}),a.then(r.settle,()=>r.settle(!1))}):Promise.resolve(!1)},M=()=>w==r.ready&&!!n&&!!o;return{load:async({model:e,limits:t,assets:a,logging:i,signal:m,onProgress:w})=>{if(m?.aborted)return!1;if(M()&&o?.id==e.id)return!0;if(d&&g==e.id)return w(y.percent,y.phase),await _(w,m);d&&(x(),p=[],await d.catch(()=>!1));const E=++h,C=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const d=b(e);if(E!=h)return!1;if(!d)return k(r.unsupported),!1;if(await(async(e,t)=>{if(o&&o.id!=e.id){const e=o,t=c,a=n;n=void 0,o=void 0,c=void 0,await(a?.unload()),await(t?.remove(e))}if(await t.hasCache())for(const a of l)a.id!=e.id&&b(a)==t&&await t.remove(a)})(e,d),E!=h)return!1;const g=await d.cached(e);if(E!=h)return!1;k(r.downloading),v(0,s.download),g&&v(1,s.load);const m=new AbortController;u=m;try{const l=await d.startLLM({model:e,limits:t,logging:i,signal:m.signal,assets:a,onProgress:(e,t)=>{E==h&&v(e,t)}});return E!=h||m.signal.aborted?(await l.unload(),!1):(n=l,o=e,c=d,f=d.backend,k(r.ready),v(1,s.load),!0)}catch(e){return E!=h||(n=void 0,o=void 0,c=void 0,i&&console.log("Local model failed",e),k(r.error)),!1}finally{u==m&&(u=void 0)}})().finally(()=>{d==C&&(d=void 0,g=void 0,p=[])});return d=C,g=e.id,await _(w,m)},chat:async e=>{if(!M()||!n)return;for(;m;)await m.catch(()=>{});if(!M()||!n)return;const t=n.chat(e);m=t;try{return await t}finally{m==t&&(m=void 0)}},unload:async()=>{const e=n;x(),n=void 0,o=void 0,c=void 0,k(r.idle),await(e?.unload())},ready:M,loading:()=>!M()&&w==r.downloading,status:()=>w,backend:()=>f,model:()=>o}})(),_e=(e,t,a)=>{const n=e.status(),i=d(t);return{availability:n==r.ready?o.online:n==r.error||n==r.unsupported?o.offline:o.away,status:n,backend:e.backend(),supportsImages:!!i&&g(i),ready:e.ready(),loading:e.loading(),requesting:a.requesting,phase:a.phase,percent:a.percent,...a.error?{error:a.error}:{}}},Me=(e=>{let t,a=0;const o=t=>t.input.onStatus?.(_e(e,t.input.model,t));return i=>{t?.controller.abort();const c={token:++a,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=d(r.model),l=r.messages.some(e=>e.role!=n.system&&"string"==typeof e.content&&!!e.content.trim()),u=r.messages.some(e=>e.role==n.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),m=l||u;if(!c)return t.error="Unknown model",void o(t);if(!m)return void o(t);if(u&&!l&&!g(c))return t.error="Model does not accept images",void o(t);const f=k(r.limits),w=await e.load({model:c,limits:f,logging:i,signal:t.controller.signal,onProgress:(e,n)=>{t.token==a&&(t.percent=Math.round(100*e),t.phase=n,o(t))}}).catch(e=>(t.token==a&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=a)return;if(t.cancelled)return;if(!w)return t.error||(t.error="Model not ready"),void o(t);const p=g(c),h=u&&!p?r.messages.map(({images:e,...t})=>t):r.messages;if(u&&!p&&!l)return t.error="Model does not accept images",void o(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=s.load,o(t);let y,b="",v="";try{y=await e.chat({messages:h,limits:f,reasoning:!0===r.reasoning,logging:i,onReason:e=>{t.token!=a||t.cancelled||(b+=e,r.onThinking?.(b))},onText:e=>{t.token!=a||t.cancelled||(v+=e,r.onResponse?.(v))},signal:t.controller.signal})}catch(e){if(t.token!=a)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void o(t)}t.token==a&&(t.requesting=!1,y||t.cancelled||(t.error="No reply"),o(t))})(c),()=>(t=>{t.token==a&&(t.cancelled=!0,t.controller.abort(),e.status()!=r.ready?queueMicrotask(()=>o(t)):e.unload().then(()=>o(t)))})(c)}})(xe),Ee=(Ce=xe,async e=>{const t=d(e.model),a=t=>e.onStatus?.(_e(Ce,e.model,t));if(!t)return a({requesting:!1,phase:s.download,percent:0,error:"Unknown model"}),!1;let n,o=0,r=s.download;const i=Ce.ready()&&Ce.model()?.id==t.id;return await Ce.load({model:t,limits:k(e.limits),logging:!0===e.logging,onProgress:(e,t)=>{o=Math.round(100*e),r=t,a({requesting:!1,phase:r,percent:o})}}).catch(e=>(n=`${e?.message||`${e}`}`,!1))?(i&&a({requesting:!1,phase:s.load,percent:100}),!0):(a({requesting:!1,phase:r,percent:o,error:n||"Model not ready"}),!1)});var Ce;export{c as ChatModelId,o as ChatStatus,i as LlmBackend,s as LlmPhase,n as LlmRole,r as LlmStatus,Me as createChat,Ee as preloadModel};
@@ -12,6 +12,8 @@ declare const replyOptions: (limits: LlmLimits, reasoning: boolean) => {
12
12
  declare const
13
13
  /** Resolve one model file on the model host */
14
14
  modelUrl: (repo: string, file: string) => string,
15
+ /** Declared size of one download, zero when the host hides it */
16
+ contentLength: (response: Response) => number,
15
17
  /** Whether any turn carries an image */
16
18
  hasImages: (messages: EngineMessage[]) => boolean;
17
19
  declare const
@@ -30,4 +32,4 @@ streamReply: ({ model, logging, onReason, onText, start, stopped, }: StreamReply
30
32
  declare const
31
33
  /** Build the prompt and stream one reply through an engine */
32
34
  runEngineChat: ({ model, params, start, stopped, }: EngineRunParams) => Promise<string | undefined>;
33
- export { buildMessages, createThinkSplitter, logChatCall, runEngineChat, streamReply, replyOptions, defaultLlmLimits, resolveLlmLimits, hasImages, modelUrl, };
35
+ export { buildMessages, createThinkSplitter, logChatCall, runEngineChat, streamReply, replyOptions, defaultLlmLimits, resolveLlmLimits, hasImages, modelUrl, contentLength, };
@@ -0,0 +1,11 @@
1
+ import type { ModelStore, ResumePlan, StoredFilePart, StoredPart } from '../types';
2
+ declare const
3
+ /** Contiguous parts from offset zero, stopping at the first gap */
4
+ chainParts: (parts: StoredFilePart[]) => StoredFilePart[],
5
+ /** Where one response continues the parts, undefined restarts them */
6
+ resumePlan: (response: Response, part: StoredPart) => ResumePlan | undefined,
7
+ /** Whether a failed store write means this host cannot use a file store */
8
+ isStoreError: (error: unknown) => boolean;
9
+ /** Create the resumable file store of one engine */
10
+ declare const createModelStore: (dirName: string) => ModelStore;
11
+ export { chainParts, createModelStore, isStoreError, resumePlan, };
@@ -1,9 +1,20 @@
1
- import type { EngineMessage, LlmEngine, LlmRuntime, StartLlmParams, WllamaMessage } from '../types';
1
+ import type { ChatModel, EngineMessage, LlmEngine, LlmRuntime, StartLlmParams, WllamaMessage } from '../types';
2
2
  /** CPU threads after the hardware maximum and the caller cap */
3
3
  declare const cpuThreads: (cores: number, maxThreads: number) => number;
4
4
  declare const
5
+ /** Every CPU file of one model, its name and remote URL */
6
+ cpuFiles: (model: ChatModel) => Array<{
7
+ name: string;
8
+ url: string;
9
+ }>,
10
+ /** Every CPU file as a Blob, from the store or a resumable download */
11
+ storedBlobs: ({ model, signal, onProgress, }: {
12
+ model: ChatModel;
13
+ signal?: AbortSignal;
14
+ onProgress: StartLlmParams[`onProgress`];
15
+ }) => Promise<Blob[] | undefined>,
5
16
  /** Map built messages to wllama turns */
6
17
  toWllamaMessages: (messages: EngineMessage[]) => Promise<WllamaMessage[]>,
7
18
  /** Start the CPU runtime, the unified engine entry */
8
19
  startLLM: ({ model, limits, onProgress, signal, logging, assets: overrides, }: StartLlmParams) => Promise<LlmRuntime>, wllamaEngine: LlmEngine;
9
- export { cpuThreads, startLLM, toWllamaMessages, wllamaEngine, };
20
+ export { cpuFiles, cpuThreads, startLLM, storedBlobs, toWllamaMessages, wllamaEngine, };
@@ -1,2 +1,2 @@
1
1
  /*! For license information please see chat.node.min.js.LICENSE.txt */
2
- (()=>{"use strict";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}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.require(e,t),Promise.all(t)},n.u=e=>({520:"engine-litert",924:"engine-wllama"}[e]+".node.min.js"),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={792:1};n.f.require=(t,a)=>{if(!e[t]){const a=require("./"+n.u(t));e[t]||(t=>{const a=t.modules,o=t.ids,r=t.runtime;for(var s in a)n.o(a,s)&&(n.m[s]=a[s]);r&&r(n);for(var i=0;i<o.length;i++)e[o[i]]=1})(a)}}})();let a={};var o,r,s,i,c,l;n.r(a),n.d(a,{ChatModelId:()=>l,ChatStatus:()=>r,LlmBackend:()=>i,LlmPhase:()=>c,LlmRole:()=>o,LlmStatus:()=>s,createChat:()=>ne,preloadModel:()=>ae}),function(e){e.system="system",e.user="user",e.assistant="assistant"}(o||(o={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(r||(r={})),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"}(s||(s={})),function(e){e.cpu="cpu",e.gpu="gpu",e.none="none"}(i||(i={})),function(e){e.download="download",e.load="load"}(c||(c={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b",e.gemma4_e2b="gemma4-e2b"}(l||(l={}));const d=[{id:l.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:l.gemma4_e2b,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it.litertlm",vision:!0}}],g=e=>e?d.find(t=>t.id==e):void 0,u=e=>!!e.cpu?.mmproj||!!e.litert?.vision,m=require("node:path"),p=()=>{return e=(0,m.join)(__dirname,"../assets/wllama"),{wasm:(0,m.join)(e,"wllama.wasm"),compatWasm:(0,m.join)(e,"compat/wllama.wasm"),compatWorker:(0,m.join)(e,"compat/wllama.js")};var e},f=()=>{return e=(0,m.join)(__dirname,"../assets/litert"),{script:(0,m.join)(e,"litertlm_wasm_internal.js"),wasm:(0,m.join)(e,"litertlm_wasm_internal.wasm")};var e},h=288,w=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},y=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),s=((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})(h,h),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,h,h),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.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 s.toDataURL("image/jpeg",.85)}catch{return e}},b={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},x=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,v=(e={})=>{const t=b;return{maxReplyTokens:x(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:x(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:x(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:x(e.maxImages,t.maxImages,0),maxContentLength:x(e.maxContentLength,t.maxContentLength,1),promptCharBudget:x(e.promptCharBudget,t.promptCharBudget,1),maxThreads:x(e.maxThreads,t.maxThreads,1)}},k=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),_=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,M=e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)),C=["<|channel>thought\n","<|channel>thought","..."],T=["<channel|>","..."],L=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,E=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,j=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...E(e),{type:"text",text:"\n"},...E(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},q=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((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:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,T);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,T);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,C);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,C);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},R=async({model:e,params:t,start:n,stopped:a})=>{const r=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 y(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=b)=>{const n=t.maxContentLength,a=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=o.user||!e.images?.length)),r=[],s=[];let i=0,c=t.maxImages;for(let e=a.length-1;e>=0;e--){const l=a[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==o.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==o.system?r.unshift(d):l.role==o.assistant?s.unshift({role:"assistant",content:d}):s.unshift({role:"user",content:L(d,g)})}}for(;s.length&&"user"!=s[0].role;)s.shift();const l=[];for(const e of s){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=j(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=r.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),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}:{}})))})(e,r),await q({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(r),stopped:a})},W="litertlm-models",$={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},P=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(W)}catch{return}},B=new Map,I=e=>Number(e.headers.get("content-length"))||0,O=(e,t,n)=>{let a=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{a+=e.byteLength,n(t?a/t:0,c.download),o.enqueue(e)}}))},A=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push({role:n.role,content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await w(t.url)});t.push({role:"user",content:e})}return t},S=async({engine:e,model:t,mod:n,params:a})=>await R({model:t,params:a,stopped:()=>!!a.signal?.aborted,start:async o=>{if(a.signal?.aborted)throw new Error("Cancelled");if(M(o)&&!t.litert?.vision)throw new Error("Model does not accept images");return async function*({engine:e,mod:t,params:n,messages:a}){const o=a[a.length-1],r=k(n.limits,n.reasoning);if("user"!=o?.role)throw new Error("No user turn");const s=await A(a.slice(0,-1)),i=(await A([o]))[0];if(!i)throw new Error("Empty prompt");const c=await e.createConversation({sessionConfig:{maxOutputTokens:r.max_tokens,samplerParams:{type:t.SamplerType.TOP_K,temperature:r.temperature,k:40,p:.95}},preface:{...s.length?{messages:s}:{},extra_context:{enable_thinking:n.reasoning}}});let l;const d=()=>{l&&l.cancel().catch(()=>{});try{c.cancel()}catch{}};n.signal?.addEventListener("abort",d,{once:!0});try{if(n.signal?.aborted)return;const e=c.sendMessageStreaming(i).getReader();for(l=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);const r=n.channels?.thought;r&&(a.reasoning=r),(a.content||a.reasoning)&&(yield{choices:[{delta:a}]})}}finally{n.signal?.removeEventListener("abort",d);try{await c.delete()}catch{}}}({engine:e,mod:n,params:a,messages:o})}}),U={backend:i.gpu,startLLM:async({model:e,limits:t,onProgress:a,signal:o,logging:r})=>{const s=e.litert;if(!s)throw new Error("Model has no LiteRT artifact");const l=await n.e(520).then(()=>n(507));if(await l.getOrLoadGlobalLiteRtLm(f().script),o?.aborted)throw new Error("Cancelled");const d=_(s.repo,s.file),g=await P();let u;if(g){if(!await g.match(d))try{await(async(e,t,n,a)=>{const o=B.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=I(o),s=O(o.body,r,a);await t.put(e,new Response(s,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{B.delete(e)});return B.set(e,r),await r})(d,g,o,a)}catch(e){if(o?.aborted)throw new Error("Cancelled");r&&console.log("Local model cache failed",e)}const e=await g.match(d);e?.body&&(u=e.body)}if(u||(u=await(async(e,t,n)=>{const a=await fetch(e,{signal:t});if(!a.ok||!a.body)throw new Error("Model download failed");return O(a.body,I(a),n)})(d,o,a)),o?.aborted)throw new Error("Cancelled");a(1,c.load);const m=await l.Engine.create({model:u,mainExecutorSettings:{maxNumTokens:4096,...s.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:$},...s.vision?{visionBackend:l.Backend.GPU}:{}});if(o?.aborted)throw await m.delete(),new Error("Cancelled");return{model:e,backend:i.gpu,contextSize:4096,chat:t=>S({engine:m,model:e,mod:l,params:t}),unload:async()=>{await m.delete()}}},cached:async e=>{try{const t=e.litert,n=await P();return!(!t||!n)&&!!await n.match(_(t.repo,t.file))}catch{return!1}},hasCache:async()=>{try{const e=await P();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert,n=await P();if(!t||!n)return;await n.delete(_(t.repo,t.file))}catch{}},purge:async()=>{try{"undefined"!=typeof caches&&await caches.delete(W)}catch{}}};let F,N,Q="",z=!1;const G=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,D=e=>{const t=p();return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},V=e=>{const t=e=>(...t)=>{z&&("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)}},K=async()=>{if(F)return F;const e=await n.e(924).then(()=>n(577)),t=N||D(),a=new e.Wllama({default:t.wasm},{logger:V(e.LoggerWithoutDebug)});return N||(N=t,Q=G(t)),a.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),F=a,a},H=async()=>{const e=F;F=void 0;try{await(e?.exit())}catch{}},J=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),X=e=>e.cpu?[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]]:[],Y=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)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await w(t.url)});t.push({role:"user",content:e})}return t},Z={backend:i.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{z=!0===o;const s=e.cpu;if(!s)throw new Error("Model has no CPU artifact");const l=D(r),d=G(l);F&&d!=Q&&await H(),N=l,Q=d;const g=(u="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,m=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(u||4)-1)),m)));var u,m;const p=await K(),f=_(s.repo,s.file),h=s.mmproj?.file,w=h?_(s.repo,h):"";if(a?.aborted)throw await H(),new Error("Cancelled");if(h){const e=await p.cacheManager.list(),t=e.some(e=>J(e,s.file)),n=e.some(e=>J(e,h));t&&!n&&await p.cacheManager.deleteMany(e=>J(e,s.file))}try{await p.loadModelFromUrl(w?{url:f,mmprojUrl:w}:f,{n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?c.load:c.download)}})}catch(e){throw await H(),e}if(a?.aborted)throw await H(),new Error("Cancelled");if(!p.getLoadedContextInfo().n_ctx)throw await H(),new Error("Failed to create model context");return{model:e,backend:i.cpu,contextSize:8192,chat:t=>(async(e,t,n)=>{if(z=!0===n.logging,e.isModelLoaded())return await R({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if(M(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await Y(a),...k(n.limits,n.reasoning),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}})}})})(p,e,t),unload:async()=>{if(F==p)await H();else try{await p.exit()}catch{}}}},cached:async e=>{try{if(!e.cpu)return!1;const t=await K(),n=await t.cacheManager.list();return X(e).every(e=>n.some(t=>J(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await K();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{if(!e.cpu)return;const t=await K();await t.cacheManager.deleteMany(t=>X(e).some(e=>J(t,e)))}catch{}},purge:async()=>{try{const e=await K();await e.cacheManager.clear()}catch{}}},ee=((e={})=>{const t=e.engines?.cpu||Z,n=e.engines?.litert||U;let a,o,r,l,g,u,m,p=i.none,f=s.idle,h=[],w=0,y={percent:0,phase:c.download};const b=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)=>{y={percent:Math.max(0,Math.min(1,e)),phase:t||c.download};for(const e of[...h])e.report(y.percent,y.phase)},v=e=>{f=e},k=()=>{w++,u?.abort(),u=void 0,g=void 0,f==s.downloading&&v(s.idle)},_=(e,t)=>{const n=l;return n?new Promise(a=>{let o=!1;const r={report:e,settle:e=>{o||(o=!0,t?.removeEventListener("abort",s),a(e))}},s=()=>{(e=>{h=h.filter(t=>t!=e),queueMicrotask(()=>{!h.length&&l&&k()})})(r),r.settle(!1)};h.push(r),t?.aborted?s():t?.addEventListener("abort",s,{once:!0}),n.then(r.settle,()=>r.settle(!1))}):Promise.resolve(!1)},M=()=>f==s.ready&&!!a&&!!o;return{load:async({model:e,limits:t,assets:n,logging:i,signal:m,onProgress:f})=>{if(m?.aborted)return!1;if(M()&&o?.id==e.id)return!0;if(l&&g==e.id)return f(y.percent,y.phase),await _(f,m);l&&(k(),h=[],await l.catch(()=>!1));const C=++w,T=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const l=b(e);if(C!=w)return!1;if(!l)return v(s.unsupported),!1;if(await(async(e,t)=>{if(o&&o.id!=e.id){const e=o,t=r,n=a;a=void 0,o=void 0,r=void 0,await(n?.unload()),await(t?.remove(e))}if(await t.hasCache())for(const n of d)n.id!=e.id&&b(n)==t&&await t.remove(n)})(e,l),C!=w)return!1;const g=await l.cached(e);if(C!=w)return!1;if(!g&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await l.purge(),C!=w)return!1;v(s.downloading),x(0,c.download),g&&x(1,c.load);const m=new AbortController;u=m;try{const d=await l.startLLM({model:e,limits:t,logging:i,signal:m.signal,assets:n,onProgress:(e,t)=>{C==w&&x(e,t)}});return C!=w||m.signal.aborted?(await d.unload(),!1):(a=d,o=e,r=l,p=l.backend,v(s.ready),x(1,c.load),!0)}catch(e){return C!=w||(a=void 0,o=void 0,r=void 0,i&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await l.purge(),v(s.error)),!1}finally{u==m&&(u=void 0)}})().finally(()=>{l==T&&(l=void 0,g=void 0,h=[])});return l=T,g=e.id,await _(f,m)},chat:async e=>{if(!M()||!a)return;for(;m;)await m.catch(()=>{});if(!M()||!a)return;const t=a.chat(e);m=t;try{return await t}finally{m==t&&(m=void 0)}},unload:async()=>{const e=a;k(),a=void 0,o=void 0,r=void 0,v(s.idle),await(e?.unload())},ready:M,loading:()=>!M()&&f==s.downloading,status:()=>f,backend:()=>p,model:()=>o}})(),te=(e,t,n)=>{const a=e.status(),o=g(t);return{availability:a==s.ready?r.online:a==s.error||a==s.unsupported?r.offline:r.away,status:a,backend:e.backend(),supportsImages:!!o&&u(o),ready:e.ready(),loading:e.loading(),requesting:n.requesting,phase:n.phase,percent:n.percent,...n.error?{error:n.error}:{}}},ne=(e=>{let t,n=0;const a=t=>t.input.onStatus?.(te(e,t.input.model,t));return r=>{t?.controller.abort();const i={token:++n,input:r,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?c.load:c.download,requesting:!1,cancelled:!1};return t=i,a(i),(async t=>{const{input:r}=t,s=!0===r.logging,i=g(r.model),l=r.messages.some(e=>e.role!=o.system&&"string"==typeof e.content&&!!e.content.trim()),d=r.messages.some(e=>e.role==o.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),m=l||d;if(!i)return t.error="Unknown model",void a(t);if(!m)return void a(t);if(d&&!l&&!u(i))return t.error="Model does not accept images",void a(t);const p=v(r.limits),f=await e.load({model:i,limits:p,logging:s,signal:t.controller.signal,onProgress:(e,o)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=o,a(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(t.cancelled)return;if(!f)return t.error||(t.error="Model not ready"),void a(t);const h=u(i),w=d&&!h?r.messages.map(({images:e,...t})=>t):r.messages;if(d&&!h&&!l)return t.error="Model does not accept images",void a(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=c.load,a(t);let y,b="",x="";try{y=await e.chat({messages:w,limits:p,reasoning:!0===r.reasoning,logging:s,onReason:e=>{t.token!=n||t.cancelled||(b+=e,r.onThinking?.(b))},onText:e=>{t.token!=n||t.cancelled||(x+=e,r.onResponse?.(x))},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void a(t)}t.token==n&&(t.requesting=!1,y||t.cancelled||(t.error="No reply"),a(t))})(i),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=s.ready?queueMicrotask(()=>a(t)):e.unload().then(()=>a(t)))})(i)}})(ee),ae=(oe=ee,async e=>{const t=g(e.model),n=t=>e.onStatus?.(te(oe,e.model,t));if(!t)return n({requesting:!1,phase:c.download,percent:0,error:"Unknown model"}),!1;let a,o=0,r=c.download;const s=oe.ready()&&oe.model()?.id==t.id;return await oe.load({model:t,limits:v(e.limits),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))?(s&&n({requesting:!1,phase:c.load,percent:100}),!0):(n({requesting:!1,phase:r,percent:o,error:a||"Model not ready"}),!1)});var oe;module.exports=a})();
2
+ (()=>{"use strict";var e={};const t={};function a(n){const o=t[n];if(void 0!==o)return o.exports;const r=t[n]={exports:{}};return e[n](r,r.exports,a),r.exports}a.m=e,a.d=(e,t)=>{for(var n in t)a.o(t,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},a.f={},a.e=e=>{const t=[];return a.f.require(e,t),Promise.all(t)},a.u=e=>({520:"engine-litert",924:"engine-wllama"}[e]+".node.min.js"),a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={792:1};a.f.require=(t,n)=>{if(!e[t]){const n=require("./"+a.u(t));e[t]||(t=>{const n=t.modules,o=t.ids,r=t.runtime;for(var i in n)a.o(n,i)&&(a.m[i]=n[i]);r&&r(a);for(var s=0;s<o.length;s++)e[o[s]]=1})(n)}}})();let n={};var o,r,i,s,c,l;a.r(n),a.d(n,{ChatModelId:()=>l,ChatStatus:()=>r,LlmBackend:()=>s,LlmPhase:()=>c,LlmRole:()=>o,LlmStatus:()=>i,createChat:()=>Me,preloadModel:()=>Ee}),function(e){e.system="system",e.user="user",e.assistant="assistant"}(o||(o={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(r||(r={})),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"}(i||(i={})),function(e){e.cpu="cpu",e.gpu="gpu",e.none="none"}(s||(s={})),function(e){e.download="download",e.load="load"}(c||(c={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b",e.gemma4_e2b="gemma4-e2b"}(l||(l={}));const d=[{id:l.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:l.gemma4_e2b,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it.litertlm",vision:!0}}],g=e=>e?d.find(t=>t.id==e):void 0,u=e=>!!e.cpu?.mmproj||!!e.litert?.vision,m=require("node:path"),f=()=>{return e=(0,m.join)(__dirname,"../assets/wllama"),{wasm:(0,m.join)(e,"wllama.wasm"),compatWasm:(0,m.join)(e,"compat/wllama.wasm"),compatWorker:(0,m.join)(e,"compat/wllama.js")};var e},w=()=>{return e=(0,m.join)(__dirname,"../assets/litert"),{script:(0,m.join)(e,"litertlm_wasm_internal.js"),wasm:(0,m.join)(e,"litertlm_wasm_internal.wasm")};var e},p=288,h=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),a=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!a.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},y=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),a=await createImageBitmap(await t.blob()),n=Math.min(a.width,a.height),o=Math.floor((a.width-n)/2),r=Math.floor((a.height-n)/2),i=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const a=document.createElement("canvas");return a.width=e,a.height=t,a})(p,p),s=i?i.getContext("2d"):null;if(!i||!s||n<1)return a.close(),e;if(s.drawImage(a,o,r,n,n,0,0,p,p),a.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 a=new FileReader;a.onerror=()=>t(""),a.onload=()=>t(`${a.result}`),a.readAsDataURL(e)}))(t)||e}return i.toDataURL("image/jpeg",.85)}catch{return e}},b={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},v=(e,t,a)=>"number"==typeof e&&Number.isFinite(e)&&e>=a?Math.floor(e):t,x=(e={})=>{const t=b;return{maxReplyTokens:v(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:v(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:v(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:v(e.maxImages,t.maxImages,0),maxContentLength:v(e.maxContentLength,t.maxContentLength,1),promptCharBudget:v(e.promptCharBudget,t.promptCharBudget,1),maxThreads:v(e.maxThreads,t.maxThreads,1)}},k=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),_=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,M=e=>Number(e.headers.get("content-length"))||0,E=e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)),C=["<|channel>thought\n","<|channel>thought","..."],T=["<channel|>","..."],L=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,j=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,$=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const a=[];for(const n of[...j(e),{type:"text",text:"\n"},...j(t)]){const e=a[a.length-1];"text"==n.type&&"text"==e?.type?e.text+=n.text:a.push(n)}return a},P=async({model:e,logging:t,onReason:a,onText:n,start:o,stopped:r})=>{let i="",s="",c="";const l=((e,t)=>{let a="",n=!1;const o=(e,t)=>{let a=-1,n="";for(const o of t){const t=e.indexOf(o);t>=0&&(a<0||t<a)&&(a=t,n=o)}return{at:a,tag:n}},r=(e,t)=>{let a="";for(const n of t)for(let t=Math.min(e.length,n.length-1);t>a.length;t--)if(e.endsWith(n.slice(0,t))){a=e.slice(e.length-t);break}return a};return{feed:i=>{let s=a+i;for(a="";s;){if(n){const{at:t,tag:i}=o(s,T);if(t>=0){t&&e(s.slice(0,t)),s=s.slice(t+i.length),n=!1;continue}const c=r(s,T);e(s.slice(0,s.length-c.length)),a=c;break}{const{at:e,tag:i}=o(s,C);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=r(s,C);t(s.slice(0,s.length-c.length)),a=c;break}}},flush:()=>{a&&(n?e(a):t(a),a="")}}})(e=>{s+=e,a(e)},e=>{i+=e,n(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],n=e?.delta,o="string"==typeof n?.reasoning_content?n.reasoning_content:"string"==typeof n?.reasoning?n.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(s+=o,a(o)),n?.content&&l.feed(n.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:i||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",i.length,s.length)),d},R=async({model:e,params:t,start:a,stopped:n})=>{const r=await(async e=>{const t=[];for(const a of e){if("string"==typeof a.content){t.push(a);continue}const e=[];for(const t of a.content)e.push("image"==t.type?{type:"image",url:await y(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=b)=>{const a=t.maxContentLength,n=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=o.user||!e.images?.length)),r=[],i=[];let s=0,c=t.maxImages;for(let e=n.length-1;e>=0;e--){const l=n[e],d=("string"==typeof l.content?l.content:"").slice(0,a),g=l.role==o.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&s+d.length>t.promptCharBudget)break;s+=d.length,c-=g.length,l.role==o.system?r.unshift(d):l.role==o.assistant?i.unshift({role:"assistant",content:d}):i.unshift({role:"user",content:L(d,g)})}}for(;i.length&&"user"!=i[0].role;)i.shift();const l=[];for(const e of i){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=$(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=r.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),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}:{}})))})(e,r),await P({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>a(r),stopped:n})},q=33554432,W=new Map;let S=!1;const B=e=>{const t=(e.split("/").pop()||"model").replace(/[^\w.-]+/g,"_");let a=0;for(let t=0;t<e.length;t++)a=31*a+e.charCodeAt(t)>>>0;return`${a.toString(16)}-${t}`},z=e=>{const t=/^part-(\d+)$/.exec(e);return t?Number(t[1]):-1},A=async()=>{if(!S)if("undefined"!=typeof navigator&&navigator.storage?.getDirectory)try{return await navigator.storage.getDirectory()}catch{return}else S=!0},O=async(e,t)=>{try{return await e.getDirectoryHandle(t)}catch{return}},I=async e=>{if(e)try{const t=await e.getFile(),a=JSON.parse(await t.text());return{total:Number(a.total)||0,etag:`${a.etag||""}`,complete:!0===a.complete}}catch{return}},N=async(e,t)=>{try{const a=await e.getFileHandle("meta.json",{create:!0}),n=await a.createWritable();await n.write(JSON.stringify(t)),await n.close()}catch{}},F=async function*(e){for await(const t of e)yield t},U=async e=>{try{for await(const[t,a]of F(e))"file"==a.kind&&z(t)>=0&&await e.removeEntry(t).catch(()=>{})}catch{}},D=async(e,t)=>{try{const a=await(await e.getFileHandle(t)).getFile(),n=await I(await e.getFileHandle(`${t}.json`).catch(()=>{}));if(!n)return;return{file:a,size:a.size,total:n.total,etag:n.etag,complete:n.total?a.size>=n.total:!0===n.complete}}catch{return}},H=async(e,t)=>{const a=await O(e,t);if(a){const e=await(async e=>await I(await e.getFileHandle("meta.json").catch(()=>{})))(a),t=await(async e=>{const t=[];try{for await(const[a,n]of F(e)){const e=z(a);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 a=(e=>{const t=[];let a=0;for(const n of[...e].sort((e,t)=>e.start-t.start))if(n.size){if(n.start!=a)break;t.push(n),a+=n.size}return t})(t.map(e=>e.part)),n=new Set(a.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:a.reduce((e,t)=>e+t.size,0)}})(a),n=e?.total||0,o=t?.size??0,r=t?.file??new Blob;return{file:n&&o>n?r.slice(0,n):r,size:o,total:n,etag:e?.etag||"",complete:n?o>=n:!0===e?.complete}}return await D(e,t)},Q=(e,t)=>{const a=e.headers.get("content-range"),n=/bytes (\d+)-/.exec(a||""),o=/\/(\d+)\s*$/.exec(a||""),r=e.headers.get("etag")||"";if(206==e.status){const e=n?Number(n[1]):t.size,a=o?Number(o[1]):t.total;if(e!=t.size)return;if(t.total&&a&&t.total!=a)return;if(t.etag&&r&&t.etag!=r)return;return{start:e,total:a||t.total,etag:r||t.etag}}if(!t.etag||!r||t.etag==r)return{start:0,total:M(e)||t.total,etag:r||t.etag}},G=async({dir:e,start:t,skip:a,total:n,body:o,onProgress:r,onChunk:i})=>{let s,l=t,d=0,g=a;const u=async()=>{const t=await e.getFileHandle((e=>`part-${e}`)(l),{create:!0});s=await t.createWritable(),d=0},m=async()=>{const e=s;s=void 0,e&&await e.close().catch(()=>{})};try{const e=o.getReader();for(;;){const{done:a,value:o}=await e.read();if(a)break;i();let f=0;for(g&&(f=Math.min(g,o.byteLength),g-=f);f<o.byteLength;){s||await u();const e=Math.min(q-d,o.byteLength-f);await s.write({type:"write",position:d,data:o.subarray(f,f+e)}),f+=e,d+=e,l+=e,d==q&&await m()}l>t&&r(n?l/n:0,c.download)}await m()}catch(e){throw await m(),e}return l},V=e=>["NotAllowedError","NotSupportedError"].includes(e?.name||""),J=e=>{const t=async()=>{const t=await A();if(t)try{return await t.getDirectoryHandle(e,{create:!0})}catch{return}};return{stored:async e=>{const a=await t();return a?await H(a,B(e)):void 0},download:async({url:a,signal:n,onProgress:o})=>{const r=`${e}|${a}`,i=W.get(r);if(i)return await i;const s=await t();if(!s)return;const l=(async(e,t,a,n)=>{const o=B(t),r=await D(e,o);if(r?.complete)return r;let i=await O(e,o);i||(await e.removeEntry(o).catch(()=>{}),await e.removeEntry(`${o}.json`).catch(()=>{}),i=await e.getDirectoryHandle(o,{create:!0}));let s=0,l=0;for(;;){if(a?.aborted)throw new Error("Cancelled");const r=await H(e,o);if(r?.complete)return r;const d=r?.size??0,g=r?.total||0,u=r?.etag||"";if(d>s)s=d,l=0;else if(++l>4)throw new Error("Model download failed");d&&g&&n(d/g,c.download);const m=g?Math.min(d+q,g)-1:d+q-1,f=new AbortController,w=()=>f.abort(),p={size:d,total:g,etag:u};let h,y=setTimeout(w,3e4);a?.addEventListener("abort",w,{once:!0});try{if(h=await fetch(t,{signal:f.signal,headers:{Range:`bytes=${d}-${m}`}}),416==h.status){if(await(h.body?.cancel().catch(()=>{})),g&&d>=g){await N(i,{total:g,etag:u,complete:!0});continue}await U(i),await N(i,{total:0,etag:"",complete:!1});continue}if(!h.ok||!h.body)throw await(h.body?.cancel().catch(()=>{})),new Error("Model download failed");const a=Q(h,p);if(!a){await h.body.cancel().catch(()=>{}),await U(i),await N(i,{total:0,etag:"",complete:!1});continue}await N(i,{total:a.total,etag:a.etag,complete:!1});const r=0==a.start?d:0,s=await G({dir:i,start:a.start+r,skip:r,total:a.total,body:h.body,onProgress:n,onChunk:()=>{clearTimeout(y),y=setTimeout(w,3e4)}});if(!a.total){await N(i,{total:s,etag:a.etag,complete:!0});const t=await H(e,o);if(t)return t}}catch(e){if(a?.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),a?.removeEventListener("abort",w)}}})(s,a,n,o).finally(()=>{W.delete(r)});return W.set(r,l),await l},remove:async e=>{const a=await t();a&&await(async(e,t)=>{await e.removeEntry(t,{recursive:!0}).catch(()=>{}),await e.removeEntry(`${t}.json`).catch(()=>{})})(a,B(e))},purge:async()=>{const t=await A();t&&await t.removeEntry(e,{recursive:!0}).catch(()=>{})}}},K="litertlm-models",X=J("litert-store"),Y={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},Z=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(K)}catch{return}},ee=new Map,te=(e,t,a)=>{let n=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{n+=e.byteLength,a(t?n/t:0,c.download),o.enqueue(e)}}))},ae=async e=>{const t=[];for(const a of e){if("string"==typeof a.content){t.push({role:a.role,content:a.content});continue}const e=[];for(const t of a.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await h(t.url)});t.push({role:"user",content:e})}return t},ne=async({engine:e,model:t,mod:a,params:n})=>await R({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async o=>{if(n.signal?.aborted)throw new Error("Cancelled");if(E(o)&&!t.litert?.vision)throw new Error("Model does not accept images");return async function*({engine:e,mod:t,params:a,messages:n}){const o=n[n.length-1],r=k(a.limits,a.reasoning);if("user"!=o?.role)throw new Error("No user turn");const i=await ae(n.slice(0,-1)),s=(await ae([o]))[0];if(!s)throw new Error("Empty prompt");const c=await e.createConversation({sessionConfig:{maxOutputTokens:r.max_tokens,samplerParams:{type:t.SamplerType.TOP_K,temperature:r.temperature,k:40,p:.95}},preface:{...i.length?{messages:i}:{},extra_context:{enable_thinking:a.reasoning}}});let l;const d=()=>{l&&l.cancel().catch(()=>{});try{c.cancel()}catch{}};a.signal?.addEventListener("abort",d,{once:!0});try{if(a.signal?.aborted)return;const e=c.sendMessageStreaming(s).getReader();for(l=e;;){const{done:t,value:a}=await e.read();if(t)break;const n={};let o="string"==typeof a.content?a.content:"";if(Array.isArray(a.content))for(const e of a.content)"text"==e.type&&(o+=e.text);o&&(n.content=o);const r=a.channels?.thought;r&&(n.reasoning=r),(n.content||n.reasoning)&&(yield{choices:[{delta:n}]})}}finally{a.signal?.removeEventListener("abort",d);try{await c.delete()}catch{}}}({engine:e,mod:a,params:n,messages:o})}}),oe={backend:s.gpu,startLLM:async({model:e,limits:t,onProgress:n,signal:o,logging:r})=>{const i=e.litert;if(!i)throw new Error("Model has no LiteRT artifact");const l=await a.e(520).then(()=>a(507));if(await l.getOrLoadGlobalLiteRtLm(w().script),o?.aborted)throw new Error("Cancelled");const d=_(i.repo,i.file),g=await Z();let u;const m=g?await g.match(d):void 0;if(m?.body)u=m.body;else{const e=await X.stored(d);e?.complete&&(u=e.file.stream())}if(!u){const e=await X.download({url:d,signal:o,onProgress:n}).catch(e=>{if(o?.aborted)throw new Error("Cancelled");if(!V(e))throw e;r&&console.log("Local model store failed",e)});e&&(u=e.file.stream())}if(!u&&g)try{await(async(e,t,a,n)=>{const o=ee.get(e);if(o)return await o;const r=(async()=>{const o=await fetch(e,{signal:a});if(!o.ok||!o.body)throw new Error("Model download failed");const r=M(o),i=te(o.body,r,n);await t.put(e,new Response(i,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{ee.delete(e)});return ee.set(e,r),await r})(d,g,o,n);const e=await g.match(d);e?.body&&(u=e.body)}catch(e){if(o?.aborted)throw new Error("Cancelled");r&&console.log("Local model cache failed",e)}if(u||(u=await(async(e,t,a)=>{const n=await fetch(e,{signal:t});if(!n.ok||!n.body)throw new Error("Model download failed");return te(n.body,M(n),a)})(d,o,n)),o?.aborted)throw new Error("Cancelled");n(1,c.load);const f=await l.Engine.create({model:u,mainExecutorSettings:{maxNumTokens:4096,...i.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:Y},...i.vision?{visionBackend:l.Backend.GPU}:{}});if(o?.aborted)throw await f.delete(),new Error("Cancelled");return{model:e,backend:s.gpu,contextSize:4096,chat:t=>ne({engine:f,model:e,mod:l,params:t}),unload:async()=>{await f.delete()}}},cached:async e=>{const t=e.litert;if(!t)return!1;const a=_(t.repo,t.file),[n,o]=await Promise.all([Z(),X.stored(a)]);if(o?.complete)return!0;try{return!(!n||!await n.match(a))}catch{return!1}},hasCache:async()=>{try{for(const e of d){const t=e.litert;if(!t)continue;if(await X.stored(_(t.repo,t.file)))return!0}const e=await Z();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert;if(!t)return;const a=_(t.repo,t.file),n=await Z();await X.remove(a),n&&await n.delete(a)}catch{}},purge:async()=>{try{await X.purge(),"undefined"!=typeof caches&&await caches.delete(K)}catch{}}},re=J("wllama-store");let ie,se,ce="",le=!1;const de=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,ge=e=>{const t=f();return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},ue=e=>{const t=e=>(...t)=>{le&&("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)}},me=async()=>{if(ie)return ie;const e=await a.e(924).then(()=>a(577)),t=se||ge(),n=new e.Wllama({default:t.wasm},{logger:ue(e.LoggerWithoutDebug)});return se||(se=t,ce=de(t)),n.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),ie=n,n},fe=async()=>{const e=ie;ie=void 0;try{await(e?.exit())}catch{}},we=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),pe=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)}]:[]]:[]},he=async e=>{const t=pe(e);if(!t.length)return!1;for(const e of t){const t=await re.stored(e.url);if(!t?.complete)return!1}return!0},ye=async(e,t)=>{const a=await e.cacheManager.list();return pe(t).every(e=>a.some(t=>we(t,e.name)))},be=async({model:e,signal:t,onProgress:a})=>{const n=pe(e),o=[];for(let e=0;e<n.length;e++){if(t?.aborted)throw new Error("Cancelled");const r=await re.download({url:n[e].url,signal:t,onProgress:(t,o)=>a((e+t)/n.length,o)});if(!r)return;o.push(r.file)}return o.length?o:void 0},ve=async e=>{const t=[];for(const a of e){if("string"==typeof a.content){"system"==a.role?t.push({role:"system",content:a.content}):"assistant"==a.role?t.push({role:"assistant",content:a.content}):t.push({role:"user",content:a.content});continue}const e=[];for(const t of a.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await h(t.url)});t.push({role:"user",content:e})}return t},xe={backend:s.cpu,startLLM:async({model:e,limits:t,onProgress:a,signal:n,logging:o,assets:r})=>{le=!0===o;const i=e.cpu;if(!i)throw new Error("Model has no CPU artifact");const l=ge(r),d=de(l);ie&&d!=ce&&await fe(),se=l,ce=d;const g=(u="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,m=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(u||4)-1)),m)));var u,m;const f=await me(),w=await he(e),p=i.mmproj?.file,h=_(i.repo,i.file),y=p?_(i.repo,p):"";if(n?.aborted)throw await fe(),new Error("Cancelled");if(!w&&p){const e=await f.cacheManager.list(),t=e.some(e=>we(e,i.file)),a=e.some(e=>we(e,p));t&&!a&&await f.cacheManager.deleteMany(e=>we(e,i.file))}const b={n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,jinja:!0};try{let t=w?await be({model:e,signal:n,onProgress:a}):void 0;t||w||await ye(f,e).catch(()=>!1)||(t=await be({model:e,signal:n,onProgress:a}).catch(e=>{if(n?.aborted)throw new Error("Cancelled");if(!V(e))throw e;o&&console.log("Local model store failed",e)})),t?(a(1,c.load),await f.loadModel(t,b)):await f.loadModelFromUrl(y?{url:h,mmprojUrl:y}:h,{...b,useCache:!0,signal:n,progressCallback:({loaded:e,total:t})=>{const n=t?e/t:0;a(n,n>=1?c.load:c.download)}})}catch(e){throw await fe(),e}if(n?.aborted)throw await fe(),new Error("Cancelled");if(!f.getLoadedContextInfo().n_ctx)throw await fe(),new Error("Failed to create model context");return{model:e,backend:s.cpu,contextSize:8192,chat:t=>(async(e,t,a)=>{if(le=!0===a.logging,e.isModelLoaded())return await R({model:t,params:a,stopped:()=>!!a.signal?.aborted,start:async n=>{if(E(n)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await ve(n),...k(a.limits,a.reasoning),abortSignal:a.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:a.reasoning}}:{}})}})})(f,e,t),unload:async()=>{if(ie==f)await fe();else try{await f.exit()}catch{}}}},cached:async e=>{try{return!!e.cpu&&(!!await he(e)||await ye(await me(),e))}catch{return!1}},hasCache:async()=>{try{for(const e of d.flatMap(e=>pe(e)))if(await re.stored(e.url))return!0;const e=await me();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{const t=pe(e);try{for(const e of t)await re.remove(e.url)}catch{}try{const e=await me();await e.cacheManager.deleteMany(e=>t.some(t=>we(e,t.name)))}catch{}},purge:async()=>{try{await re.purge()}catch{}try{const e=await me();await e.cacheManager.clear()}catch{}}},ke=((e={})=>{const t=e.engines?.cpu||xe,a=e.engines?.litert||oe;let n,o,r,l,g,u,m,f=s.none,w=i.idle,p=[],h=0,y={percent:0,phase:c.download};const b=n=>{if(e.backend!=s.none)return e.backend==s.cpu?n.cpu?t:void 0:e.backend==s.gpu?n.litert?a:void 0:n.litert&&"undefined"!=typeof navigator&&navigator.gpu&&"undefined"!=typeof WebAssembly?a:!n.cpu||"undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?void 0:t},v=(e,t)=>{y={percent:Math.max(0,Math.min(1,e)),phase:t||c.download};for(const e of[...p])e.report(y.percent,y.phase)},x=e=>{w=e},k=()=>{h++,u?.abort(),u=void 0,g=void 0,w==i.downloading&&x(i.idle)},_=(e,t)=>{const a=l;return a?new Promise(n=>{let o=!1;const r={report:e,settle:e=>{o||(o=!0,t?.removeEventListener("abort",i),n(e))}},i=()=>{(e=>{p=p.filter(t=>t!=e),queueMicrotask(()=>{!p.length&&l&&k()})})(r),r.settle(!1)};p.push(r),t?.aborted?i():t?.addEventListener("abort",i,{once:!0}),a.then(r.settle,()=>r.settle(!1))}):Promise.resolve(!1)},M=()=>w==i.ready&&!!n&&!!o;return{load:async({model:e,limits:t,assets:a,logging:s,signal:m,onProgress:w})=>{if(m?.aborted)return!1;if(M()&&o?.id==e.id)return!0;if(l&&g==e.id)return w(y.percent,y.phase),await _(w,m);l&&(k(),p=[],await l.catch(()=>!1));const E=++h,C=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const l=b(e);if(E!=h)return!1;if(!l)return x(i.unsupported),!1;if(await(async(e,t)=>{if(o&&o.id!=e.id){const e=o,t=r,a=n;n=void 0,o=void 0,r=void 0,await(a?.unload()),await(t?.remove(e))}if(await t.hasCache())for(const a of d)a.id!=e.id&&b(a)==t&&await t.remove(a)})(e,l),E!=h)return!1;const g=await l.cached(e);if(E!=h)return!1;x(i.downloading),v(0,c.download),g&&v(1,c.load);const m=new AbortController;u=m;try{const d=await l.startLLM({model:e,limits:t,logging:s,signal:m.signal,assets:a,onProgress:(e,t)=>{E==h&&v(e,t)}});return E!=h||m.signal.aborted?(await d.unload(),!1):(n=d,o=e,r=l,f=l.backend,x(i.ready),v(1,c.load),!0)}catch(e){return E!=h||(n=void 0,o=void 0,r=void 0,s&&console.log("Local model failed",e),x(i.error)),!1}finally{u==m&&(u=void 0)}})().finally(()=>{l==C&&(l=void 0,g=void 0,p=[])});return l=C,g=e.id,await _(w,m)},chat:async e=>{if(!M()||!n)return;for(;m;)await m.catch(()=>{});if(!M()||!n)return;const t=n.chat(e);m=t;try{return await t}finally{m==t&&(m=void 0)}},unload:async()=>{const e=n;k(),n=void 0,o=void 0,r=void 0,x(i.idle),await(e?.unload())},ready:M,loading:()=>!M()&&w==i.downloading,status:()=>w,backend:()=>f,model:()=>o}})(),_e=(e,t,a)=>{const n=e.status(),o=g(t);return{availability:n==i.ready?r.online:n==i.error||n==i.unsupported?r.offline:r.away,status:n,backend:e.backend(),supportsImages:!!o&&u(o),ready:e.ready(),loading:e.loading(),requesting:a.requesting,phase:a.phase,percent:a.percent,...a.error?{error:a.error}:{}}},Me=(e=>{let t,a=0;const n=t=>t.input.onStatus?.(_e(e,t.input.model,t));return r=>{t?.controller.abort();const s={token:++a,input:r,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?c.load:c.download,requesting:!1,cancelled:!1};return t=s,n(s),(async t=>{const{input:r}=t,i=!0===r.logging,s=g(r.model),l=r.messages.some(e=>e.role!=o.system&&"string"==typeof e.content&&!!e.content.trim()),d=r.messages.some(e=>e.role==o.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),m=l||d;if(!s)return t.error="Unknown model",void n(t);if(!m)return void n(t);if(d&&!l&&!u(s))return t.error="Model does not accept images",void n(t);const f=x(r.limits),w=await e.load({model:s,limits:f,logging:i,signal:t.controller.signal,onProgress:(e,o)=>{t.token==a&&(t.percent=Math.round(100*e),t.phase=o,n(t))}}).catch(e=>(t.token==a&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=a)return;if(t.cancelled)return;if(!w)return t.error||(t.error="Model not ready"),void n(t);const p=u(s),h=d&&!p?r.messages.map(({images:e,...t})=>t):r.messages;if(d&&!p&&!l)return t.error="Model does not accept images",void n(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=c.load,n(t);let y,b="",v="";try{y=await e.chat({messages:h,limits:f,reasoning:!0===r.reasoning,logging:i,onReason:e=>{t.token!=a||t.cancelled||(b+=e,r.onThinking?.(b))},onText:e=>{t.token!=a||t.cancelled||(v+=e,r.onResponse?.(v))},signal:t.controller.signal})}catch(e){if(t.token!=a)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void n(t)}t.token==a&&(t.requesting=!1,y||t.cancelled||(t.error="No reply"),n(t))})(s),()=>(t=>{t.token==a&&(t.cancelled=!0,t.controller.abort(),e.status()!=i.ready?queueMicrotask(()=>n(t)):e.unload().then(()=>n(t)))})(s)}})(ke),Ee=(Ce=ke,async e=>{const t=g(e.model),a=t=>e.onStatus?.(_e(Ce,e.model,t));if(!t)return a({requesting:!1,phase:c.download,percent:0,error:"Unknown model"}),!1;let n,o=0,r=c.download;const i=Ce.ready()&&Ce.model()?.id==t.id;return await Ce.load({model:t,limits:x(e.limits),logging:!0===e.logging,onProgress:(e,t)=>{o=Math.round(100*e),r=t,a({requesting:!1,phase:r,percent:o})}}).catch(e=>(n=`${e?.message||`${e}`}`,!1))?(i&&a({requesting:!1,phase:c.load,percent:100}),!0):(a({requesting:!1,phase:r,percent:o,error:n||"Model not ready"}),!1)});var Ce;module.exports=n})();
@@ -1,2 +1,2 @@
1
1
  /*! For license information please see chat.node.min.mjs.LICENSE.txt */
2
- import{dirname as e,join as t}from"node:path";import{fileURLToPath as n}from"node:url";var a={};const o={};function r(e){const t=o[e];if(void 0!==t)return t.exports;const n=o[e]={exports:{}};return a[e](n,n.exports,r),n.exports}var s,i,c,l,d,g;r.m=a,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.node.min.mjs"),924:()=>import("./engine-wllama.node.min.mjs")},t={792:0},n=e=>{let{__webpack_esm_ids__:n,__webpack_esm_modules__:a,__webpack_esm_runtime__:o}=e;var s,i,c=0;for(s in a)r.o(a,s)&&(r.m[s]=a[s]);for(o&&o(r);c<n.length;c++)i=n[c],r.o(t,i)&&t[i]&&t[i][0](),t[i]=0};r.f.j=(a,o)=>{let s=r.o(t,a)?t[a]:void 0;if(0!==s)if(s)o.push(s[1]);else{let r=e[a]().then(n,e=>{throw 0!==t[a]&&(t[a]=void 0),e});r=Promise.race([r,new Promise(e=>s=t[a]=[e])]),o.push(s[1]=r)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(s||(s={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(i||(i={})),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"}(c||(c={})),function(e){e.cpu="cpu",e.gpu="gpu",e.none="none"}(l||(l={})),function(e){e.download="download",e.load="load"}(d||(d={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b",e.gemma4_e2b="gemma4-e2b"}(g||(g={}));const m=[{id:g.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:g.gemma4_e2b,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it.litertlm",vision:!0}}],u=e=>e?m.find(t=>t.id==e):void 0,p=e=>!!e.cpu?.mmproj||!!e.litert?.vision,f=()=>{return a=t(e(n("file:///media/x/store/code/DegreeSign/ds_chat/src/assets/nodeEsm.js")),"../assets/wllama"),{wasm:t(a,"wllama.wasm"),compatWasm:t(a,"compat/wllama.wasm"),compatWorker:t(a,"compat/wllama.js")};var a},h=()=>{return a=t(e(n("file:///media/x/store/code/DegreeSign/ds_chat/src/assets/nodeEsm.js")),"../assets/litert"),{script:t(a,"litertlm_wasm_internal.js"),wasm:t(a,"litertlm_wasm_internal.wasm")};var a},w=288,y=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},b=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),s=((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})(w,w),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,w,w),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.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 s.toDataURL("image/jpeg",.85)}catch{return e}},x={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},k=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,v=(e={})=>{const t=x;return{maxReplyTokens:k(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:k(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:k(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:k(e.maxImages,t.maxImages,0),maxContentLength:k(e.maxContentLength,t.maxContentLength,1),promptCharBudget:k(e.promptCharBudget,t.promptCharBudget,1),maxThreads:k(e.maxThreads,t.maxThreads,1)}},_=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),M=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,T=e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)),C=["<|channel>thought\n","<|channel>thought","..."],L=["<channel|>","..."],E=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,j=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,R=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...j(e),{type:"text",text:"\n"},...j(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},q=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((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:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,L);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,L);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,C);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,C);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},P=async({model:e,params:t,start:n,stopped:a})=>{const o=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 b(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=x)=>{const n=t.maxContentLength,a=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=s.user||!e.images?.length)),o=[],r=[];let i=0,c=t.maxImages;for(let e=a.length-1;e>=0;e--){const l=a[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==s.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==s.system?o.unshift(d):l.role==s.assistant?r.unshift({role:"assistant",content:d}):r.unshift({role:"user",content:E(d,g)})}}for(;r.length&&"user"!=r[0].role;)r.shift();const l=[];for(const e of r){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=R(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=o.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),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}:{}})))})(e,o),await q({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(o),stopped:a})},W="litertlm-models",$={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},B=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(W)}catch{return}},I=new Map,O=e=>Number(e.headers.get("content-length"))||0,A=(e,t,n)=>{let a=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{a+=e.byteLength,n(t?a/t:0,d.download),o.enqueue(e)}}))},S=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push({role:n.role,content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await y(t.url)});t.push({role:"user",content:e})}return t},U=async({engine:e,model:t,mod:n,params:a})=>await P({model:t,params:a,stopped:()=>!!a.signal?.aborted,start:async o=>{if(a.signal?.aborted)throw new Error("Cancelled");if(T(o)&&!t.litert?.vision)throw new Error("Model does not accept images");return async function*({engine:e,mod:t,params:n,messages:a}){const o=a[a.length-1],r=_(n.limits,n.reasoning);if("user"!=o?.role)throw new Error("No user turn");const s=await S(a.slice(0,-1)),i=(await S([o]))[0];if(!i)throw new Error("Empty prompt");const c=await e.createConversation({sessionConfig:{maxOutputTokens:r.max_tokens,samplerParams:{type:t.SamplerType.TOP_K,temperature:r.temperature,k:40,p:.95}},preface:{...s.length?{messages:s}:{},extra_context:{enable_thinking:n.reasoning}}});let l;const d=()=>{l&&l.cancel().catch(()=>{});try{c.cancel()}catch{}};n.signal?.addEventListener("abort",d,{once:!0});try{if(n.signal?.aborted)return;const e=c.sendMessageStreaming(i).getReader();for(l=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);const r=n.channels?.thought;r&&(a.reasoning=r),(a.content||a.reasoning)&&(yield{choices:[{delta:a}]})}}finally{n.signal?.removeEventListener("abort",d);try{await c.delete()}catch{}}}({engine:e,mod:n,params:a,messages:o})}}),F={backend:l.gpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o})=>{const s=e.litert;if(!s)throw new Error("Model has no LiteRT artifact");const i=await r.e(520).then(()=>r(507));if(await i.getOrLoadGlobalLiteRtLm(h().script),a?.aborted)throw new Error("Cancelled");const c=M(s.repo,s.file),g=await B();let m;if(g){if(!await g.match(c))try{await(async(e,t,n,a)=>{const o=I.get(e);if(o)return await o;const r=(async()=>{const o=await fetch(e,{signal:n});if(!o.ok||!o.body)throw new Error("Model download failed");const r=O(o),s=A(o.body,r,a);await t.put(e,new Response(s,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{I.delete(e)});return I.set(e,r),await r})(c,g,a,n)}catch(e){if(a?.aborted)throw new Error("Cancelled");o&&console.log("Local model cache failed",e)}const e=await g.match(c);e?.body&&(m=e.body)}if(m||(m=await(async(e,t,n)=>{const a=await fetch(e,{signal:t});if(!a.ok||!a.body)throw new Error("Model download failed");return A(a.body,O(a),n)})(c,a,n)),a?.aborted)throw new Error("Cancelled");n(1,d.load);const u=await i.Engine.create({model:m,mainExecutorSettings:{maxNumTokens:4096,...s.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:$},...s.vision?{visionBackend:i.Backend.GPU}:{}});if(a?.aborted)throw await u.delete(),new Error("Cancelled");return{model:e,backend:l.gpu,contextSize:4096,chat:t=>U({engine:u,model:e,mod:i,params:t}),unload:async()=>{await u.delete()}}},cached:async e=>{try{const t=e.litert,n=await B();return!(!t||!n)&&!!await n.match(M(t.repo,t.file))}catch{return!1}},hasCache:async()=>{try{const e=await B();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert,n=await B();if(!t||!n)return;await n.delete(M(t.repo,t.file))}catch{}},purge:async()=>{try{"undefined"!=typeof caches&&await caches.delete(W)}catch{}}};let N,Q,D="",z=!1;const G=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,V=e=>{const t=f();return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},K=e=>{const t=e=>(...t)=>{z&&("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)}},H=async()=>{if(N)return N;const e=await r.e(924).then(()=>r(577)),t=Q||V(),n=new e.Wllama({default:t.wasm},{logger:K(e.LoggerWithoutDebug)});return Q||(Q=t,D=G(t)),n.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),N=n,n},J=async()=>{const e=N;N=void 0;try{await(e?.exit())}catch{}},X=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),Y=e=>e.cpu?[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]]:[],Z=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)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await y(t.url)});t.push({role:"user",content:e})}return t},ee={backend:l.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{z=!0===o;const s=e.cpu;if(!s)throw new Error("Model has no CPU artifact");const i=V(r),c=G(i);N&&c!=D&&await J(),Q=i,D=c;const g=(m="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,u=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(m||4)-1)),u)));var m,u;const p=await H(),f=M(s.repo,s.file),h=s.mmproj?.file,w=h?M(s.repo,h):"";if(a?.aborted)throw await J(),new Error("Cancelled");if(h){const e=await p.cacheManager.list(),t=e.some(e=>X(e,s.file)),n=e.some(e=>X(e,h));t&&!n&&await p.cacheManager.deleteMany(e=>X(e,s.file))}try{await p.loadModelFromUrl(w?{url:f,mmprojUrl:w}:f,{n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?d.load:d.download)}})}catch(e){throw await J(),e}if(a?.aborted)throw await J(),new Error("Cancelled");if(!p.getLoadedContextInfo().n_ctx)throw await J(),new Error("Failed to create model context");return{model:e,backend:l.cpu,contextSize:8192,chat:t=>(async(e,t,n)=>{if(z=!0===n.logging,e.isModelLoaded())return await P({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if(T(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await Z(a),..._(n.limits,n.reasoning),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}})}})})(p,e,t),unload:async()=>{if(N==p)await J();else try{await p.exit()}catch{}}}},cached:async e=>{try{if(!e.cpu)return!1;const t=await H(),n=await t.cacheManager.list();return Y(e).every(e=>n.some(t=>X(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await H();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{if(!e.cpu)return;const t=await H();await t.cacheManager.deleteMany(t=>Y(e).some(e=>X(t,e)))}catch{}},purge:async()=>{try{const e=await H();await e.cacheManager.clear()}catch{}}},te=((e={})=>{const t=e.engines?.cpu||ee,n=e.engines?.litert||F;let a,o,r,s,i,g,u,p=l.none,f=c.idle,h=[],w=0,y={percent:0,phase:d.download};const b=a=>{if(e.backend!=l.none)return e.backend==l.cpu?a.cpu?t:void 0:e.backend==l.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)=>{y={percent:Math.max(0,Math.min(1,e)),phase:t||d.download};for(const e of[...h])e.report(y.percent,y.phase)},k=e=>{f=e},v=()=>{w++,g?.abort(),g=void 0,i=void 0,f==c.downloading&&k(c.idle)},_=(e,t)=>{const n=s;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=>{h=h.filter(t=>t!=e),queueMicrotask(()=>{!h.length&&s&&v()})})(r),r.settle(!1)};h.push(r),t?.aborted?i():t?.addEventListener("abort",i,{once:!0}),n.then(r.settle,()=>r.settle(!1))}):Promise.resolve(!1)},M=()=>f==c.ready&&!!a&&!!o;return{load:async({model:e,limits:t,assets:n,logging:l,signal:u,onProgress:f})=>{if(u?.aborted)return!1;if(M()&&o?.id==e.id)return!0;if(s&&i==e.id)return f(y.percent,y.phase),await _(f,u);s&&(v(),h=[],await s.catch(()=>!1));const T=++w,C=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const s=b(e);if(T!=w)return!1;if(!s)return k(c.unsupported),!1;if(await(async(e,t)=>{if(o&&o.id!=e.id){const e=o,t=r,n=a;a=void 0,o=void 0,r=void 0,await(n?.unload()),await(t?.remove(e))}if(await t.hasCache())for(const n of m)n.id!=e.id&&b(n)==t&&await t.remove(n)})(e,s),T!=w)return!1;const i=await s.cached(e);if(T!=w)return!1;if(!i&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await s.purge(),T!=w)return!1;k(c.downloading),x(0,d.download),i&&x(1,d.load);const u=new AbortController;g=u;try{const i=await s.startLLM({model:e,limits:t,logging:l,signal:u.signal,assets:n,onProgress:(e,t)=>{T==w&&x(e,t)}});return T!=w||u.signal.aborted?(await i.unload(),!1):(a=i,o=e,r=s,p=s.backend,k(c.ready),x(1,d.load),!0)}catch(e){return T!=w||(a=void 0,o=void 0,r=void 0,l&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await s.purge(),k(c.error)),!1}finally{g==u&&(g=void 0)}})().finally(()=>{s==C&&(s=void 0,i=void 0,h=[])});return s=C,i=e.id,await _(f,u)},chat:async e=>{if(!M()||!a)return;for(;u;)await u.catch(()=>{});if(!M()||!a)return;const t=a.chat(e);u=t;try{return await t}finally{u==t&&(u=void 0)}},unload:async()=>{const e=a;v(),a=void 0,o=void 0,r=void 0,k(c.idle),await(e?.unload())},ready:M,loading:()=>!M()&&f==c.downloading,status:()=>f,backend:()=>p,model:()=>o}})(),ne=(e,t,n)=>{const a=e.status(),o=u(t);return{availability:a==c.ready?i.online:a==c.error||a==c.unsupported?i.offline:i.away,status:a,backend:e.backend(),supportsImages:!!o&&p(o),ready:e.ready(),loading:e.loading(),requesting:n.requesting,phase:n.phase,percent:n.percent,...n.error?{error:n.error}:{}}},ae=(e=>{let t,n=0;const a=t=>t.input.onStatus?.(ne(e,t.input.model,t));return o=>{t?.controller.abort();const r={token:++n,input:o,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?d.load:d.download,requesting:!1,cancelled:!1};return t=r,a(r),(async t=>{const{input:o}=t,r=!0===o.logging,i=u(o.model),c=o.messages.some(e=>e.role!=s.system&&"string"==typeof e.content&&!!e.content.trim()),l=o.messages.some(e=>e.role==s.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),g=c||l;if(!i)return t.error="Unknown model",void a(t);if(!g)return void a(t);if(l&&!c&&!p(i))return t.error="Model does not accept images",void a(t);const m=v(o.limits),f=await e.load({model:i,limits:m,logging:r,signal:t.controller.signal,onProgress:(e,o)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=o,a(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(t.cancelled)return;if(!f)return t.error||(t.error="Model not ready"),void a(t);const h=p(i),w=l&&!h?o.messages.map(({images:e,...t})=>t):o.messages;if(l&&!h&&!c)return t.error="Model does not accept images",void a(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=d.load,a(t);let y,b="",x="";try{y=await e.chat({messages:w,limits:m,reasoning:!0===o.reasoning,logging:r,onReason:e=>{t.token!=n||t.cancelled||(b+=e,o.onThinking?.(b))},onText:e=>{t.token!=n||t.cancelled||(x+=e,o.onResponse?.(x))},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void a(t)}t.token==n&&(t.requesting=!1,y||t.cancelled||(t.error="No reply"),a(t))})(r),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=c.ready?queueMicrotask(()=>a(t)):e.unload().then(()=>a(t)))})(r)}})(te),oe=(re=te,async e=>{const t=u(e.model),n=t=>e.onStatus?.(ne(re,e.model,t));if(!t)return n({requesting:!1,phase:d.download,percent:0,error:"Unknown model"}),!1;let a,o=0,r=d.download;const s=re.ready()&&re.model()?.id==t.id;return await re.load({model:t,limits:v(e.limits),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))?(s&&n({requesting:!1,phase:d.load,percent:100}),!0):(n({requesting:!1,phase:r,percent:o,error:a||"Model not ready"}),!1)});var re;export{g as ChatModelId,i as ChatStatus,l as LlmBackend,d as LlmPhase,s as LlmRole,c as LlmStatus,ae as createChat,oe as preloadModel};
2
+ import{dirname as e,join as t}from"node:path";import{fileURLToPath as a}from"node:url";var n={};const o={};function r(e){const t=o[e];if(void 0!==t)return t.exports;const a=o[e]={exports:{}};return n[e](a,a.exports,r),a.exports}var s,i,c,l,d,g;r.m=n,r.d=(e,t)=>{for(var a in t)r.o(t,a)&&!r.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},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.node.min.mjs"),924:()=>import("./engine-wllama.node.min.mjs")},t={792:0},a=e=>{let{__webpack_esm_ids__:a,__webpack_esm_modules__:n,__webpack_esm_runtime__:o}=e;var s,i,c=0;for(s in n)r.o(n,s)&&(r.m[s]=n[s]);for(o&&o(r);c<a.length;c++)i=a[c],r.o(t,i)&&t[i]&&t[i][0](),t[i]=0};r.f.j=(n,o)=>{let s=r.o(t,n)?t[n]:void 0;if(0!==s)if(s)o.push(s[1]);else{let r=e[n]().then(a,e=>{throw 0!==t[n]&&(t[n]=void 0),e});r=Promise.race([r,new Promise(e=>s=t[n]=[e])]),o.push(s[1]=r)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(s||(s={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(i||(i={})),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"}(c||(c={})),function(e){e.cpu="cpu",e.gpu="gpu",e.none="none"}(l||(l={})),function(e){e.download="download",e.load="load"}(d||(d={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b",e.gemma4_e2b="gemma4-e2b"}(g||(g={}));const u=[{id:g.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:g.gemma4_e2b,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it.litertlm",vision:!0}}],m=e=>e?u.find(t=>t.id==e):void 0,f=e=>!!e.cpu?.mmproj||!!e.litert?.vision,p=()=>{return n=t(e(a("file:///media/x/store/code/DegreeSign/ds_chat/src/assets/nodeEsm.js")),"../assets/wllama"),{wasm:t(n,"wllama.wasm"),compatWasm:t(n,"compat/wllama.wasm"),compatWorker:t(n,"compat/wllama.js")};var n},w=()=>{return n=t(e(a("file:///media/x/store/code/DegreeSign/ds_chat/src/assets/nodeEsm.js")),"../assets/litert"),{script:t(n,"litertlm_wasm_internal.js"),wasm:t(n,"litertlm_wasm_internal.wasm")};var n},h=288,y=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),a=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!a.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},b=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),a=await createImageBitmap(await t.blob()),n=Math.min(a.width,a.height),o=Math.floor((a.width-n)/2),r=Math.floor((a.height-n)/2),s=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const a=document.createElement("canvas");return a.width=e,a.height=t,a})(h,h),i=s?s.getContext("2d"):null;if(!s||!i||n<1)return a.close(),e;if(i.drawImage(a,o,r,n,n,0,0,h,h),a.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const a=new FileReader;a.onerror=()=>t(""),a.onload=()=>t(`${a.result}`),a.readAsDataURL(e)}))(t)||e}return s.toDataURL("image/jpeg",.85)}catch{return e}},v={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},x=(e,t,a)=>"number"==typeof e&&Number.isFinite(e)&&e>=a?Math.floor(e):t,k=(e={})=>{const t=v;return{maxReplyTokens:x(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:x(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:x(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:x(e.maxImages,t.maxImages,0),maxContentLength:x(e.maxContentLength,t.maxContentLength,1),promptCharBudget:x(e.promptCharBudget,t.promptCharBudget,1),maxThreads:x(e.maxThreads,t.maxThreads,1)}},_=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),M=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,E=e=>Number(e.headers.get("content-length"))||0,T=e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)),C=["<|channel>thought\n","<|channel>thought","..."],L=["<channel|>","..."],j=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,P=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,$=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const a=[];for(const n of[...P(e),{type:"text",text:"\n"},...P(t)]){const e=a[a.length-1];"text"==n.type&&"text"==e?.type?e.text+=n.text:a.push(n)}return a},R=async({model:e,logging:t,onReason:a,onText:n,start:o,stopped:r})=>{let s="",i="",c="";const l=((e,t)=>{let a="",n=!1;const o=(e,t)=>{let a=-1,n="";for(const o of t){const t=e.indexOf(o);t>=0&&(a<0||t<a)&&(a=t,n=o)}return{at:a,tag:n}},r=(e,t)=>{let a="";for(const n of t)for(let t=Math.min(e.length,n.length-1);t>a.length;t--)if(e.endsWith(n.slice(0,t))){a=e.slice(e.length-t);break}return a};return{feed:s=>{let i=a+s;for(a="";i;){if(n){const{at:t,tag:s}=o(i,L);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),n=!1;continue}const c=r(i,L);e(i.slice(0,i.length-c.length)),a=c;break}{const{at:e,tag:s}=o(i,C);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),n=!0;continue}const c=r(i,C);t(i.slice(0,i.length-c.length)),a=c;break}}},flush:()=>{a&&(n?e(a):t(a),a="")}}})(e=>{i+=e,a(e)},e=>{s+=e,n(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],n=e?.delta,o="string"==typeof n?.reasoning_content?n.reasoning_content:"string"==typeof n?.reasoning?n.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,a(o)),n?.content&&l.feed(n.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},W=async({model:e,params:t,start:a,stopped:n})=>{const o=await(async e=>{const t=[];for(const a of e){if("string"==typeof a.content){t.push(a);continue}const e=[];for(const t of a.content)e.push("image"==t.type?{type:"image",url:await b(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=v)=>{const a=t.maxContentLength,n=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=s.user||!e.images?.length)),o=[],r=[];let i=0,c=t.maxImages;for(let e=n.length-1;e>=0;e--){const l=n[e],d=("string"==typeof l.content?l.content:"").slice(0,a),g=l.role==s.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==s.system?o.unshift(d):l.role==s.assistant?r.unshift({role:"assistant",content:d}):r.unshift({role:"user",content:j(d,g)})}}for(;r.length&&"user"!=r[0].role;)r.shift();const l=[];for(const e of r){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=$(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=o.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),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}:{}})))})(e,o),await R({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>a(o),stopped:n})},S=33554432,z=new Map;let B=!1;const q=e=>{const t=(e.split("/").pop()||"model").replace(/[^\w.-]+/g,"_");let a=0;for(let t=0;t<e.length;t++)a=31*a+e.charCodeAt(t)>>>0;return`${a.toString(16)}-${t}`},A=e=>{const t=/^part-(\d+)$/.exec(e);return t?Number(t[1]):-1},O=async()=>{if(!B)if("undefined"!=typeof navigator&&navigator.storage?.getDirectory)try{return await navigator.storage.getDirectory()}catch{return}else B=!0},N=async(e,t)=>{try{return await e.getDirectoryHandle(t)}catch{return}},F=async e=>{if(e)try{const t=await e.getFile(),a=JSON.parse(await t.text());return{total:Number(a.total)||0,etag:`${a.etag||""}`,complete:!0===a.complete}}catch{return}},I=async(e,t)=>{try{const a=await e.getFileHandle("meta.json",{create:!0}),n=await a.createWritable();await n.write(JSON.stringify(t)),await n.close()}catch{}},U=async function*(e){for await(const t of e)yield t},D=async e=>{try{for await(const[t,a]of U(e))"file"==a.kind&&A(t)>=0&&await e.removeEntry(t).catch(()=>{})}catch{}},H=async(e,t)=>{try{const a=await(await e.getFileHandle(t)).getFile(),n=await F(await e.getFileHandle(`${t}.json`).catch(()=>{}));if(!n)return;return{file:a,size:a.size,total:n.total,etag:n.etag,complete:n.total?a.size>=n.total:!0===n.complete}}catch{return}},Q=async(e,t)=>{const a=await N(e,t);if(a){const e=await(async e=>await F(await e.getFileHandle("meta.json").catch(()=>{})))(a),t=await(async e=>{const t=[];try{for await(const[a,n]of U(e)){const e=A(a);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 a=(e=>{const t=[];let a=0;for(const n of[...e].sort((e,t)=>e.start-t.start))if(n.size){if(n.start!=a)break;t.push(n),a+=n.size}return t})(t.map(e=>e.part)),n=new Set(a.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:a.reduce((e,t)=>e+t.size,0)}})(a),n=e?.total||0,o=t?.size??0,r=t?.file??new Blob;return{file:n&&o>n?r.slice(0,n):r,size:o,total:n,etag:e?.etag||"",complete:n?o>=n:!0===e?.complete}}return await H(e,t)},G=(e,t)=>{const a=e.headers.get("content-range"),n=/bytes (\d+)-/.exec(a||""),o=/\/(\d+)\s*$/.exec(a||""),r=e.headers.get("etag")||"";if(206==e.status){const e=n?Number(n[1]):t.size,a=o?Number(o[1]):t.total;if(e!=t.size)return;if(t.total&&a&&t.total!=a)return;if(t.etag&&r&&t.etag!=r)return;return{start:e,total:a||t.total,etag:r||t.etag}}if(!t.etag||!r||t.etag==r)return{start:0,total:E(e)||t.total,etag:r||t.etag}},V=async({dir:e,start:t,skip:a,total:n,body:o,onProgress:r,onChunk:s})=>{let i,c=t,l=0,g=a;const u=async()=>{const t=await e.getFileHandle((e=>`part-${e}`)(c),{create:!0});i=await t.createWritable(),l=0},m=async()=>{const e=i;i=void 0,e&&await e.close().catch(()=>{})};try{const e=o.getReader();for(;;){const{done:a,value:o}=await e.read();if(a)break;s();let f=0;for(g&&(f=Math.min(g,o.byteLength),g-=f);f<o.byteLength;){i||await u();const e=Math.min(S-l,o.byteLength-f);await i.write({type:"write",position:l,data:o.subarray(f,f+e)}),f+=e,l+=e,c+=e,l==S&&await m()}c>t&&r(n?c/n:0,d.download)}await m()}catch(e){throw await m(),e}return c},J=e=>["NotAllowedError","NotSupportedError"].includes(e?.name||""),K=e=>{const t=async()=>{const t=await O();if(t)try{return await t.getDirectoryHandle(e,{create:!0})}catch{return}};return{stored:async e=>{const a=await t();return a?await Q(a,q(e)):void 0},download:async({url:a,signal:n,onProgress:o})=>{const r=`${e}|${a}`,s=z.get(r);if(s)return await s;const i=await t();if(!i)return;const c=(async(e,t,a,n)=>{const o=q(t),r=await H(e,o);if(r?.complete)return r;let s=await N(e,o);s||(await e.removeEntry(o).catch(()=>{}),await e.removeEntry(`${o}.json`).catch(()=>{}),s=await e.getDirectoryHandle(o,{create:!0}));let i=0,c=0;for(;;){if(a?.aborted)throw new Error("Cancelled");const r=await Q(e,o);if(r?.complete)return r;const l=r?.size??0,g=r?.total||0,u=r?.etag||"";if(l>i)i=l,c=0;else if(++c>4)throw new Error("Model download failed");l&&g&&n(l/g,d.download);const m=g?Math.min(l+S,g)-1:l+S-1,f=new AbortController,p=()=>f.abort(),w={size:l,total:g,etag:u};let h,y=setTimeout(p,3e4);a?.addEventListener("abort",p,{once:!0});try{if(h=await fetch(t,{signal:f.signal,headers:{Range:`bytes=${l}-${m}`}}),416==h.status){if(await(h.body?.cancel().catch(()=>{})),g&&l>=g){await I(s,{total:g,etag:u,complete:!0});continue}await D(s),await I(s,{total:0,etag:"",complete:!1});continue}if(!h.ok||!h.body)throw await(h.body?.cancel().catch(()=>{})),new Error("Model download failed");const a=G(h,w);if(!a){await h.body.cancel().catch(()=>{}),await D(s),await I(s,{total:0,etag:"",complete:!1});continue}await I(s,{total:a.total,etag:a.etag,complete:!1});const r=0==a.start?l:0,i=await V({dir:s,start:a.start+r,skip:r,total:a.total,body:h.body,onProgress:n,onChunk:()=>{clearTimeout(y),y=setTimeout(p,3e4)}});if(!a.total){await I(s,{total:i,etag:a.etag,complete:!0});const t=await Q(e,o);if(t)return t}}catch(e){if(a?.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*c))}finally{clearTimeout(y),a?.removeEventListener("abort",p)}}})(i,a,n,o).finally(()=>{z.delete(r)});return z.set(r,c),await c},remove:async e=>{const a=await t();a&&await(async(e,t)=>{await e.removeEntry(t,{recursive:!0}).catch(()=>{}),await e.removeEntry(`${t}.json`).catch(()=>{})})(a,q(e))},purge:async()=>{const t=await O();t&&await t.removeEntry(e,{recursive:!0}).catch(()=>{})}}},X="litertlm-models",Y=K("litert-store"),Z={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},ee=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(X)}catch{return}},te=new Map,ae=(e,t,a)=>{let n=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{n+=e.byteLength,a(t?n/t:0,d.download),o.enqueue(e)}}))},ne=async e=>{const t=[];for(const a of e){if("string"==typeof a.content){t.push({role:a.role,content:a.content});continue}const e=[];for(const t of a.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await y(t.url)});t.push({role:"user",content:e})}return t},oe=async({engine:e,model:t,mod:a,params:n})=>await W({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async o=>{if(n.signal?.aborted)throw new Error("Cancelled");if(T(o)&&!t.litert?.vision)throw new Error("Model does not accept images");return async function*({engine:e,mod:t,params:a,messages:n}){const o=n[n.length-1],r=_(a.limits,a.reasoning);if("user"!=o?.role)throw new Error("No user turn");const s=await ne(n.slice(0,-1)),i=(await ne([o]))[0];if(!i)throw new Error("Empty prompt");const c=await e.createConversation({sessionConfig:{maxOutputTokens:r.max_tokens,samplerParams:{type:t.SamplerType.TOP_K,temperature:r.temperature,k:40,p:.95}},preface:{...s.length?{messages:s}:{},extra_context:{enable_thinking:a.reasoning}}});let l;const d=()=>{l&&l.cancel().catch(()=>{});try{c.cancel()}catch{}};a.signal?.addEventListener("abort",d,{once:!0});try{if(a.signal?.aborted)return;const e=c.sendMessageStreaming(i).getReader();for(l=e;;){const{done:t,value:a}=await e.read();if(t)break;const n={};let o="string"==typeof a.content?a.content:"";if(Array.isArray(a.content))for(const e of a.content)"text"==e.type&&(o+=e.text);o&&(n.content=o);const r=a.channels?.thought;r&&(n.reasoning=r),(n.content||n.reasoning)&&(yield{choices:[{delta:n}]})}}finally{a.signal?.removeEventListener("abort",d);try{await c.delete()}catch{}}}({engine:e,mod:a,params:n,messages:o})}}),re={backend:l.gpu,startLLM:async({model:e,limits:t,onProgress:a,signal:n,logging:o})=>{const s=e.litert;if(!s)throw new Error("Model has no LiteRT artifact");const i=await r.e(520).then(()=>r(507));if(await i.getOrLoadGlobalLiteRtLm(w().script),n?.aborted)throw new Error("Cancelled");const c=M(s.repo,s.file),g=await ee();let u;const m=g?await g.match(c):void 0;if(m?.body)u=m.body;else{const e=await Y.stored(c);e?.complete&&(u=e.file.stream())}if(!u){const e=await Y.download({url:c,signal:n,onProgress:a}).catch(e=>{if(n?.aborted)throw new Error("Cancelled");if(!J(e))throw e;o&&console.log("Local model store failed",e)});e&&(u=e.file.stream())}if(!u&&g)try{await(async(e,t,a,n)=>{const o=te.get(e);if(o)return await o;const r=(async()=>{const o=await fetch(e,{signal:a});if(!o.ok||!o.body)throw new Error("Model download failed");const r=E(o),s=ae(o.body,r,n);await t.put(e,new Response(s,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{te.delete(e)});return te.set(e,r),await r})(c,g,n,a);const e=await g.match(c);e?.body&&(u=e.body)}catch(e){if(n?.aborted)throw new Error("Cancelled");o&&console.log("Local model cache failed",e)}if(u||(u=await(async(e,t,a)=>{const n=await fetch(e,{signal:t});if(!n.ok||!n.body)throw new Error("Model download failed");return ae(n.body,E(n),a)})(c,n,a)),n?.aborted)throw new Error("Cancelled");a(1,d.load);const f=await i.Engine.create({model:u,mainExecutorSettings:{maxNumTokens:4096,...s.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:Z},...s.vision?{visionBackend:i.Backend.GPU}:{}});if(n?.aborted)throw await f.delete(),new Error("Cancelled");return{model:e,backend:l.gpu,contextSize:4096,chat:t=>oe({engine:f,model:e,mod:i,params:t}),unload:async()=>{await f.delete()}}},cached:async e=>{const t=e.litert;if(!t)return!1;const a=M(t.repo,t.file),[n,o]=await Promise.all([ee(),Y.stored(a)]);if(o?.complete)return!0;try{return!(!n||!await n.match(a))}catch{return!1}},hasCache:async()=>{try{for(const e of u){const t=e.litert;if(!t)continue;if(await Y.stored(M(t.repo,t.file)))return!0}const e=await ee();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert;if(!t)return;const a=M(t.repo,t.file),n=await ee();await Y.remove(a),n&&await n.delete(a)}catch{}},purge:async()=>{try{await Y.purge(),"undefined"!=typeof caches&&await caches.delete(X)}catch{}}},se=K("wllama-store");let ie,ce,le="",de=!1;const ge=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,ue=e=>{const t=p();return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},me=e=>{const t=e=>(...t)=>{de&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},fe=async()=>{if(ie)return ie;const e=await r.e(924).then(()=>r(577)),t=ce||ue(),a=new e.Wllama({default:t.wasm},{logger:me(e.LoggerWithoutDebug)});return ce||(ce=t,le=ge(t)),a.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),ie=a,a},pe=async()=>{const e=ie;ie=void 0;try{await(e?.exit())}catch{}},we=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),he=e=>{const t=e.cpu;return t?[{name:t.file,url:M(t.repo,t.file)},...t.mmproj?[{name:t.mmproj.file,url:M(t.repo,t.mmproj.file)}]:[]]:[]},ye=async e=>{const t=he(e);if(!t.length)return!1;for(const e of t){const t=await se.stored(e.url);if(!t?.complete)return!1}return!0},be=async(e,t)=>{const a=await e.cacheManager.list();return he(t).every(e=>a.some(t=>we(t,e.name)))},ve=async({model:e,signal:t,onProgress:a})=>{const n=he(e),o=[];for(let e=0;e<n.length;e++){if(t?.aborted)throw new Error("Cancelled");const r=await se.download({url:n[e].url,signal:t,onProgress:(t,o)=>a((e+t)/n.length,o)});if(!r)return;o.push(r.file)}return o.length?o:void 0},xe=async e=>{const t=[];for(const a of e){if("string"==typeof a.content){"system"==a.role?t.push({role:"system",content:a.content}):"assistant"==a.role?t.push({role:"assistant",content:a.content}):t.push({role:"user",content:a.content});continue}const e=[];for(const t of a.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await y(t.url)});t.push({role:"user",content:e})}return t},ke={backend:l.cpu,startLLM:async({model:e,limits:t,onProgress:a,signal:n,logging:o,assets:r})=>{de=!0===o;const s=e.cpu;if(!s)throw new Error("Model has no CPU artifact");const i=ue(r),c=ge(i);ie&&c!=le&&await pe(),ce=i,le=c;const g=(u="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,m=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(u||4)-1)),m)));var u,m;const f=await fe(),p=await ye(e),w=s.mmproj?.file,h=M(s.repo,s.file),y=w?M(s.repo,w):"";if(n?.aborted)throw await pe(),new Error("Cancelled");if(!p&&w){const e=await f.cacheManager.list(),t=e.some(e=>we(e,s.file)),a=e.some(e=>we(e,w));t&&!a&&await f.cacheManager.deleteMany(e=>we(e,s.file))}const b={n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,jinja:!0};try{let t=p?await ve({model:e,signal:n,onProgress:a}):void 0;t||p||await be(f,e).catch(()=>!1)||(t=await ve({model:e,signal:n,onProgress:a}).catch(e=>{if(n?.aborted)throw new Error("Cancelled");if(!J(e))throw e;o&&console.log("Local model store failed",e)})),t?(a(1,d.load),await f.loadModel(t,b)):await f.loadModelFromUrl(y?{url:h,mmprojUrl:y}:h,{...b,useCache:!0,signal:n,progressCallback:({loaded:e,total:t})=>{const n=t?e/t:0;a(n,n>=1?d.load:d.download)}})}catch(e){throw await pe(),e}if(n?.aborted)throw await pe(),new Error("Cancelled");if(!f.getLoadedContextInfo().n_ctx)throw await pe(),new Error("Failed to create model context");return{model:e,backend:l.cpu,contextSize:8192,chat:t=>(async(e,t,a)=>{if(de=!0===a.logging,e.isModelLoaded())return await W({model:t,params:a,stopped:()=>!!a.signal?.aborted,start:async n=>{if(T(n)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await xe(n),..._(a.limits,a.reasoning),abortSignal:a.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:a.reasoning}}:{}})}})})(f,e,t),unload:async()=>{if(ie==f)await pe();else try{await f.exit()}catch{}}}},cached:async e=>{try{return!!e.cpu&&(!!await ye(e)||await be(await fe(),e))}catch{return!1}},hasCache:async()=>{try{for(const e of u.flatMap(e=>he(e)))if(await se.stored(e.url))return!0;const e=await fe();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{const t=he(e);try{for(const e of t)await se.remove(e.url)}catch{}try{const e=await fe();await e.cacheManager.deleteMany(e=>t.some(t=>we(e,t.name)))}catch{}},purge:async()=>{try{await se.purge()}catch{}try{const e=await fe();await e.cacheManager.clear()}catch{}}},_e=((e={})=>{const t=e.engines?.cpu||ke,a=e.engines?.litert||re;let n,o,r,s,i,g,m,f=l.none,p=c.idle,w=[],h=0,y={percent:0,phase:d.download};const b=n=>{if(e.backend!=l.none)return e.backend==l.cpu?n.cpu?t:void 0:e.backend==l.gpu?n.litert?a:void 0:n.litert&&"undefined"!=typeof navigator&&navigator.gpu&&"undefined"!=typeof WebAssembly?a:!n.cpu||"undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?void 0:t},v=(e,t)=>{y={percent:Math.max(0,Math.min(1,e)),phase:t||d.download};for(const e of[...w])e.report(y.percent,y.phase)},x=e=>{p=e},k=()=>{h++,g?.abort(),g=void 0,i=void 0,p==c.downloading&&x(c.idle)},_=(e,t)=>{const a=s;return a?new Promise(n=>{let o=!1;const r={report:e,settle:e=>{o||(o=!0,t?.removeEventListener("abort",i),n(e))}},i=()=>{(e=>{w=w.filter(t=>t!=e),queueMicrotask(()=>{!w.length&&s&&k()})})(r),r.settle(!1)};w.push(r),t?.aborted?i():t?.addEventListener("abort",i,{once:!0}),a.then(r.settle,()=>r.settle(!1))}):Promise.resolve(!1)},M=()=>p==c.ready&&!!n&&!!o;return{load:async({model:e,limits:t,assets:a,logging:l,signal:m,onProgress:p})=>{if(m?.aborted)return!1;if(M()&&o?.id==e.id)return!0;if(s&&i==e.id)return p(y.percent,y.phase),await _(p,m);s&&(k(),w=[],await s.catch(()=>!1));const E=++h,T=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const s=b(e);if(E!=h)return!1;if(!s)return x(c.unsupported),!1;if(await(async(e,t)=>{if(o&&o.id!=e.id){const e=o,t=r,a=n;n=void 0,o=void 0,r=void 0,await(a?.unload()),await(t?.remove(e))}if(await t.hasCache())for(const a of u)a.id!=e.id&&b(a)==t&&await t.remove(a)})(e,s),E!=h)return!1;const i=await s.cached(e);if(E!=h)return!1;x(c.downloading),v(0,d.download),i&&v(1,d.load);const m=new AbortController;g=m;try{const i=await s.startLLM({model:e,limits:t,logging:l,signal:m.signal,assets:a,onProgress:(e,t)=>{E==h&&v(e,t)}});return E!=h||m.signal.aborted?(await i.unload(),!1):(n=i,o=e,r=s,f=s.backend,x(c.ready),v(1,d.load),!0)}catch(e){return E!=h||(n=void 0,o=void 0,r=void 0,l&&console.log("Local model failed",e),x(c.error)),!1}finally{g==m&&(g=void 0)}})().finally(()=>{s==T&&(s=void 0,i=void 0,w=[])});return s=T,i=e.id,await _(p,m)},chat:async e=>{if(!M()||!n)return;for(;m;)await m.catch(()=>{});if(!M()||!n)return;const t=n.chat(e);m=t;try{return await t}finally{m==t&&(m=void 0)}},unload:async()=>{const e=n;k(),n=void 0,o=void 0,r=void 0,x(c.idle),await(e?.unload())},ready:M,loading:()=>!M()&&p==c.downloading,status:()=>p,backend:()=>f,model:()=>o}})(),Me=(e,t,a)=>{const n=e.status(),o=m(t);return{availability:n==c.ready?i.online:n==c.error||n==c.unsupported?i.offline:i.away,status:n,backend:e.backend(),supportsImages:!!o&&f(o),ready:e.ready(),loading:e.loading(),requesting:a.requesting,phase:a.phase,percent:a.percent,...a.error?{error:a.error}:{}}},Ee=(e=>{let t,a=0;const n=t=>t.input.onStatus?.(Me(e,t.input.model,t));return o=>{t?.controller.abort();const r={token:++a,input:o,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?d.load:d.download,requesting:!1,cancelled:!1};return t=r,n(r),(async t=>{const{input:o}=t,r=!0===o.logging,i=m(o.model),c=o.messages.some(e=>e.role!=s.system&&"string"==typeof e.content&&!!e.content.trim()),l=o.messages.some(e=>e.role==s.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),g=c||l;if(!i)return t.error="Unknown model",void n(t);if(!g)return void n(t);if(l&&!c&&!f(i))return t.error="Model does not accept images",void n(t);const u=k(o.limits),p=await e.load({model:i,limits:u,logging:r,signal:t.controller.signal,onProgress:(e,o)=>{t.token==a&&(t.percent=Math.round(100*e),t.phase=o,n(t))}}).catch(e=>(t.token==a&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=a)return;if(t.cancelled)return;if(!p)return t.error||(t.error="Model not ready"),void n(t);const w=f(i),h=l&&!w?o.messages.map(({images:e,...t})=>t):o.messages;if(l&&!w&&!c)return t.error="Model does not accept images",void n(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=d.load,n(t);let y,b="",v="";try{y=await e.chat({messages:h,limits:u,reasoning:!0===o.reasoning,logging:r,onReason:e=>{t.token!=a||t.cancelled||(b+=e,o.onThinking?.(b))},onText:e=>{t.token!=a||t.cancelled||(v+=e,o.onResponse?.(v))},signal:t.controller.signal})}catch(e){if(t.token!=a)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void n(t)}t.token==a&&(t.requesting=!1,y||t.cancelled||(t.error="No reply"),n(t))})(r),()=>(t=>{t.token==a&&(t.cancelled=!0,t.controller.abort(),e.status()!=c.ready?queueMicrotask(()=>n(t)):e.unload().then(()=>n(t)))})(r)}})(_e),Te=(Ce=_e,async e=>{const t=m(e.model),a=t=>e.onStatus?.(Me(Ce,e.model,t));if(!t)return a({requesting:!1,phase:d.download,percent:0,error:"Unknown model"}),!1;let n,o=0,r=d.download;const s=Ce.ready()&&Ce.model()?.id==t.id;return await Ce.load({model:t,limits:k(e.limits),logging:!0===e.logging,onProgress:(e,t)=>{o=Math.round(100*e),r=t,a({requesting:!1,phase:r,percent:o})}}).catch(e=>(n=`${e?.message||`${e}`}`,!1))?(s&&a({requesting:!1,phase:d.load,percent:100}),!0):(a({requesting:!1,phase:r,percent:o,error:n||"Model not ready"}),!1)});var Ce;export{g as ChatModelId,i as ChatStatus,l as LlmBackend,d as LlmPhase,s as LlmRole,c as LlmStatus,Ee as createChat,Te as preloadModel};
package/dist/types.d.ts CHANGED
@@ -150,6 +150,61 @@ interface RuntimeLoadWaiter {
150
150
  /** Resolve this caller, early when it leaves the load */
151
151
  settle: (loaded: boolean) => void;
152
152
  }
153
+ /** Bytes of one model file already stored on disk */
154
+ interface StoredPart {
155
+ /** Bytes already stored */
156
+ size: number;
157
+ /** Full file size, zero while unknown */
158
+ total: number;
159
+ /** Entity tag of the stored bytes, empty when the host hides it */
160
+ etag: string;
161
+ }
162
+ /** One part file of a model, at its byte offset */
163
+ interface StoredFilePart {
164
+ /** Byte offset of the part in the model file */
165
+ start: number;
166
+ /** Bytes stored in the part */
167
+ size: number;
168
+ }
169
+ /** One stored model file, complete or still downloading */
170
+ interface StoredModel extends StoredPart {
171
+ /** The stored bytes, a snapshot of the parts on disk */
172
+ file: Blob;
173
+ /** Whether every byte of the total is stored */
174
+ complete: boolean;
175
+ }
176
+ /** Download metadata kept beside one stored model file */
177
+ interface StoredModelMeta {
178
+ total: number;
179
+ etag: string;
180
+ complete: boolean;
181
+ }
182
+ /** Where one response continues a stored part */
183
+ interface ResumePlan {
184
+ /** Byte the response body starts at */
185
+ start: number;
186
+ /** Full file size, zero while unknown */
187
+ total: number;
188
+ etag: string;
189
+ }
190
+ /** One model file download into the store */
191
+ interface StoreDownloadParams {
192
+ url: string;
193
+ /** Stop the download, the bytes stored so far are kept */
194
+ signal?: AbortSignal;
195
+ onProgress: StartLlmParams[`onProgress`];
196
+ }
197
+ /** Resumable model file store owned by one engine */
198
+ interface ModelStore {
199
+ /** Stored bytes and metadata of one model file, undefined when absent */
200
+ stored: (url: string) => Promise<StoredModel | undefined>;
201
+ /** Download one model file, resuming the parts already stored */
202
+ download: (params: StoreDownloadParams) => Promise<StoredModel | undefined>;
203
+ /** Delete one stored model file and its metadata */
204
+ remove: (url: string) => Promise<void>;
205
+ /** Delete the whole store directory and every model file in it */
206
+ purge: () => Promise<void>;
207
+ }
153
208
  /** One generation request */
154
209
  interface RuntimeChatParams {
155
210
  messages: ChatMessage[];
@@ -325,4 +380,4 @@ interface EngineRunParams {
325
380
  /** Whether the caller stopped the generation */
326
381
  stopped: () => boolean;
327
382
  }
328
- export type { ChatMessage, ChatModel, LlmLimits, ChatStatusSnapshot, ChatInput, ChatPreloadInput, ChatState, CancelChat, WllamaAssets, LitertAssets, GpuNavigator, ActiveCall, RuntimeDeps, RuntimeLoadParams, RuntimeLoadWaiter, RuntimeChatParams, Runtime, EngineChatParams, StartLlmParams, LlmRuntime, LlmEngine, EngineMessage, EngineContentPart, WllamaContentPart, WllamaMessage, LitertContentPart, LitertMessage, LitertEngine, LitertModule, LitertChatParams, StreamLitertParams, EngineDelta, EngineChunk, StreamReplyParams, EngineRunParams, };
383
+ export type { ChatMessage, ChatModel, LlmLimits, ChatStatusSnapshot, ChatInput, ChatPreloadInput, ChatState, CancelChat, WllamaAssets, LitertAssets, GpuNavigator, ActiveCall, RuntimeDeps, RuntimeLoadParams, RuntimeLoadWaiter, RuntimeChatParams, StoredPart, StoredFilePart, StoredModel, StoredModelMeta, ResumePlan, StoreDownloadParams, ModelStore, Runtime, EngineChatParams, StartLlmParams, LlmRuntime, LlmEngine, EngineMessage, EngineContentPart, WllamaContentPart, WllamaMessage, LitertContentPart, LitertMessage, LitertEngine, LitertModule, LitertChatParams, StreamLitertParams, EngineDelta, EngineChunk, StreamReplyParams, EngineRunParams, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@degreesign/chat",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Headless on-device AI chat for browsers and Node with wllama CPU and LiteRT WebGPU engines",
5
5
  "main": "dist/node/chat.node.min.js",
6
6
  "module": "dist/browser/chat.min.mjs",