@degreesign/chat 0.3.4 → 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 +26 -23
- package/dist/browser/chat.min.mjs +1 -1
- package/dist/engines/store.d.ts +7 -12
- package/dist/engines/wllama.d.ts +13 -2
- package/dist/node/chat.node.min.js +1 -1
- package/dist/node/chat.node.min.mjs +1 -1
- package/dist/types.d.ts +12 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -220,8 +220,8 @@ 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
|
|
224
|
-
|
|
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
225
|
download keeps every part it committed and resumes from the last one on the
|
|
226
226
|
next attempt, including after a reload.
|
|
227
227
|
|
|
@@ -300,24 +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.
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
under `litertlm-models` when an older version stored
|
|
307
|
-
the parts already stored, so freeing disk lets the next
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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.
|
|
321
323
|
|
|
322
324
|
Both engines are bundled into `dist/browser` and `dist/node` as dynamic chunks.
|
|
323
325
|
The package ships the wllama binaries under `dist/assets/wllama` and the LiteRT
|
|
@@ -447,9 +449,10 @@ download no engine code beyond the chunk they use.
|
|
|
447
449
|
|
|
448
450
|
### Where are the models stored?
|
|
449
451
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
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.
|
|
453
456
|
|
|
454
457
|
### Which model should I pick?
|
|
455
458
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see chat.min.mjs.LICENSE.txt */
|
|
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,p=new URL("./../assets/litert/litertlm_wasm_internal.js",import.meta.url).href,w=(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})(w,w),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,w,w),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)),T=["<|channel>thought\n","<|channel>thought","..."],C=["<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,$=(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},j=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,C);if(t>=0){t&&e(s.slice(0,t)),s=s.slice(t+i.length),n=!1;continue}const c=r(s,C);e(s.slice(0,s.length-c.length)),a=c;break}{const{at:e,tag:i}=o(s,T);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,T);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},P=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=$(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:()=>a(r),stopped:o})},W="litert-store",z=33554432,B=new Map;let S=!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(!S)if("undefined"!=typeof navigator&&navigator.storage?.getDirectory)try{return await navigator.storage.getDirectory()}catch{return}else S=!0},N=async()=>{const e=await O();if(e)try{return await e.getDirectoryHandle(W,{create:!0})}catch{return}},U=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{}},D=async function*(e){for await(const t of e)yield t},H=async e=>{try{for await(const[t,a]of D(e))"file"==a.kind&&A(t)>=0&&await e.removeEntry(t).catch(()=>{})}catch{}},Q=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}},G=async(e,t)=>{const a=await U(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 D(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 Q(e,t)},V=(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}},J=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(z-d,o.byteLength-f);await c.write({type:"write",position:d,data:o.subarray(f,f+e)}),f+=e,d+=e,l+=e,d==z&&await m()}l>t&&r(n?l/n:0,s.download)}await m()}catch(e){throw await m(),e}return l},K=async e=>{const t=await N();return t?await G(t,q(e)):void 0},X=async({url:e,signal:t,onProgress:a})=>{const n=B.get(e);if(n)return await n;const o=await N();if(!o)return;const r=(async(e,t,a,n)=>{const o=q(t),r=await Q(e,o);if(r?.complete)return r;let i=await U(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 G(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+z,g)-1:d+z-1,f=new AbortController,p=()=>f.abort(),w={size:d,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=${d}-${m}`}}),416==h.status){if(await(h.body?.cancel().catch(()=>{})),g&&d>=g){await I(i,{total:g,etag:u,complete:!0});continue}await H(i),await I(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=V(h,w);if(!a){await h.body.cancel().catch(()=>{}),await H(i),await I(i,{total:0,etag:"",complete:!1});continue}await I(i,{total:a.total,etag:a.etag,complete:!1});const r=0==a.start?d:0,s=await J({dir:i,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(i,{total:s,etag:a.etag,complete:!0});const t=await G(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",p)}}})(o,e,t,a).finally(()=>{B.delete(e)});return B.set(e,r),await r},Y="litertlm-models",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(Y)}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,s.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 h(t.url)});t.push({role:"user",content:e})}return t},oe=async({engine:e,model:t,mod:a,params:n})=>await P({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 ne(n.slice(0,-1)),s=(await ne([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})}}),re={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(p),o?.aborted)throw new Error("Cancelled");const d=_(c.repo,c.file),g=await ee();let u;const m=g?await g.match(d):void 0;if(m?.body)u=m.body;else{const e=await K(d);e?.complete&&(u=e.file.stream())}if(!u){const e=await X({url:d,signal:o,onProgress:n}).catch(e=>{if(o?.aborted)throw new Error("Cancelled");if(!(e=>["NotAllowedError","NotSupportedError"].includes(e?.name||""))(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=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=M(o),i=ae(o.body,r,n);await t.put(e,new Response(i,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{te.delete(e)});return te.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 ae(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:Z},...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=>oe({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([ee(),K(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 K(_(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=_(t.repo,t.file),n=await ee();await(async e=>{const t=await N();t&&await(async(e,t)=>{await e.removeEntry(t,{recursive:!0}).catch(()=>{}),await e.removeEntry(`${t}.json`).catch(()=>{})})(t,q(e))})(a),n&&await n.delete(a)}catch{}},purge:async()=>{try{await(async()=>{const e=await O();e&&await e.removeEntry(W,{recursive:!0}).catch(()=>{})})(),"undefined"!=typeof caches&&await caches.delete(Y)}catch{}}};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{}},pe=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),we=e=>e.cpu?[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]]:[],he=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},ye={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(),p=_(c.repo,c.file),w=c.mmproj?.file,h=w?_(c.repo,w):"";if(n?.aborted)throw await fe(),new Error("Cancelled");if(w){const e=await f.cacheManager.list(),t=e.some(e=>pe(e,c.file)),a=e.some(e=>pe(e,w));t&&!a&&await f.cacheManager.deleteMany(e=>pe(e,c.file))}try{await f.loadModelFromUrl(h?{url:p,mmprojUrl:h}:p,{n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!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 P({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 he(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{if(!e.cpu)return!1;const t=await me(),a=await t.cacheManager.list();return we(e).every(e=>a.some(t=>pe(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await me();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{if(!e.cpu)return;const t=await me();await t.cacheManager.deleteMany(t=>we(e).some(e=>pe(t,e)))}catch{}},purge:async()=>{try{const e=await me();await e.cacheManager.clear()}catch{}}},be=((e={})=>{const t=e.engines?.cpu||ye,a=e.engines?.litert||re;let n,o,c,d,g,u,m,f=i.none,p=r.idle,w=[],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[...w])e.report(y.percent,y.phase)},k=e=>{p=e},x=()=>{h++,u?.abort(),u=void 0,g=void 0,p==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=>{w=w.filter(t=>t!=e),queueMicrotask(()=>{!w.length&&d&&x()})})(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==r.ready&&!!n&&!!o;return{load:async({model:e,limits:t,assets:a,logging:i,signal:m,onProgress:p})=>{if(m?.aborted)return!1;if(M()&&o?.id==e.id)return!0;if(d&&g==e.id)return p(y.percent,y.phase),await _(p,m);d&&(x(),w=[],await d.catch(()=>!1));const E=++h,T=(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==T&&(d=void 0,g=void 0,w=[])});return d=T,g=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;x(),n=void 0,o=void 0,c=void 0,k(r.idle),await(e?.unload())},ready:M,loading:()=>!M()&&p==r.downloading,status:()=>p,backend:()=>f,model:()=>o}})(),ve=(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}:{}}},ke=(e=>{let t,a=0;const o=t=>t.input.onStatus?.(ve(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),p=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(!p)return t.error||(t.error="Model not ready"),void o(t);const w=g(c),h=u&&!w?r.messages.map(({images:e,...t})=>t):r.messages;if(u&&!w&&!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)}})(be),xe=(_e=be,async e=>{const t=d(e.model),a=t=>e.onStatus?.(ve(_e,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=_e.ready()&&_e.model()?.id==t.id;return await _e.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 _e;export{c as ChatModelId,o as ChatStatus,i as LlmBackend,s as LlmPhase,n as LlmRole,r as LlmStatus,ke as createChat,xe 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};
|
package/dist/engines/store.d.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import type { ResumePlan, StoredFilePart,
|
|
1
|
+
import type { ModelStore, ResumePlan, StoredFilePart, StoredPart } from '../types';
|
|
2
2
|
declare const
|
|
3
3
|
/** Contiguous parts from offset zero, stopping at the first gap */
|
|
4
4
|
chainParts: (parts: StoredFilePart[]) => StoredFilePart[],
|
|
5
5
|
/** Where one response continues the parts, undefined restarts them */
|
|
6
|
-
resumePlan: (response: Response, part: StoredPart) => ResumePlan | undefined
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/** Delete one stored model file and its metadata */
|
|
13
|
-
removeModel: (url: string) => Promise<void>,
|
|
14
|
-
/** Delete the whole store directory and every model file in it */
|
|
15
|
-
purgeModels: () => Promise<void>;
|
|
16
|
-
export { chainParts, downloadModel, purgeModels, removeModel, resumePlan, storedModel, };
|
|
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, };
|
package/dist/engines/wllama.d.ts
CHANGED
|
@@ -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 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:()=>xe,preloadModel:()=>ke}),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},p=()=>{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(","),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})(h,h),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,h,h),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},R=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},P=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 R({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>a(r),stopped:n})},q="litert-store",W=33554432,S=new Map;let B=!1;const z=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},I=async()=>{const e=await O();if(e)try{return await e.getDirectoryHandle(q,{create:!0})}catch{return}},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}},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{}},D=async function*(e){for await(const t of e)yield t},H=async e=>{try{for await(const[t,a]of D(e))"file"==a.kind&&A(t)>=0&&await e.removeEntry(t).catch(()=>{})}catch{}},Q=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}},G=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 D(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 Q(e,t)},V=(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}},J=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(W-d,o.byteLength-f);await s.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,c.download)}await m()}catch(e){throw await m(),e}return l},K=async e=>{const t=await I();return t?await G(t,z(e)):void 0},X=async({url:e,signal:t,onProgress:a})=>{const n=S.get(e);if(n)return await n;const o=await I();if(!o)return;const r=(async(e,t,a,n)=>{const o=z(t),r=await Q(e,o);if(r?.complete)return r;let i=await N(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 G(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+W,g)-1:d+W-1,f=new AbortController,p=()=>f.abort(),h={size:d,total:g,etag:u};let w,y=setTimeout(p,3e4);a?.addEventListener("abort",p,{once:!0});try{if(w=await fetch(t,{signal:f.signal,headers:{Range:`bytes=${d}-${m}`}}),416==w.status){if(await(w.body?.cancel().catch(()=>{})),g&&d>=g){await U(i,{total:g,etag:u,complete:!0});continue}await H(i),await U(i,{total:0,etag:"",complete:!1});continue}if(!w.ok||!w.body)throw await(w.body?.cancel().catch(()=>{})),new Error("Model download failed");const a=V(w,h);if(!a){await w.body.cancel().catch(()=>{}),await H(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 J({dir:i,start:a.start+r,skip:r,total:a.total,body:w.body,onProgress:n,onChunk:()=>{clearTimeout(y),y=setTimeout(p,3e4)}});if(!a.total){await U(i,{total:s,etag:a.etag,complete:!0});const t=await G(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",p)}}})(o,e,t,a).finally(()=>{S.delete(e)});return S.set(e,r),await r},Y="litertlm-models",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(Y)}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,c.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 w(t.url)});t.push({role:"user",content:e})}return t},oe=async({engine:e,model:t,mod:a,params:n})=>await P({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 ne(n.slice(0,-1)),s=(await ne([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})}}),re={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(p().script),o?.aborted)throw new Error("Cancelled");const d=_(i.repo,i.file),g=await ee();let u;const m=g?await g.match(d):void 0;if(m?.body)u=m.body;else{const e=await K(d);e?.complete&&(u=e.file.stream())}if(!u){const e=await X({url:d,signal:o,onProgress:n}).catch(e=>{if(o?.aborted)throw new Error("Cancelled");if(!(e=>["NotAllowedError","NotSupportedError"].includes(e?.name||""))(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=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=M(o),i=ae(o.body,r,n);await t.put(e,new Response(i,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{te.delete(e)});return te.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 ae(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:Z},...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=>oe({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([ee(),K(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 K(_(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=_(t.repo,t.file),n=await ee();await(async e=>{const t=await I();t&&await(async(e,t)=>{await e.removeEntry(t,{recursive:!0}).catch(()=>{}),await e.removeEntry(`${t}.json`).catch(()=>{})})(t,z(e))})(a),n&&await n.delete(a)}catch{}},purge:async()=>{try{await(async()=>{const e=await O();e&&await e.removeEntry(q,{recursive:!0}).catch(()=>{})})(),"undefined"!=typeof caches&&await caches.delete(Y)}catch{}}};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{}},pe=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),he=e=>e.cpu?[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]]:[],we=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 w(t.url)});t.push({role:"user",content:e})}return t},ye={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(),p=_(i.repo,i.file),h=i.mmproj?.file,w=h?_(i.repo,h):"";if(n?.aborted)throw await fe(),new Error("Cancelled");if(h){const e=await f.cacheManager.list(),t=e.some(e=>pe(e,i.file)),a=e.some(e=>pe(e,h));t&&!a&&await f.cacheManager.deleteMany(e=>pe(e,i.file))}try{await f.loadModelFromUrl(w?{url:p,mmprojUrl:w}:p,{n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!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 P({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 we(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{if(!e.cpu)return!1;const t=await me(),a=await t.cacheManager.list();return he(e).every(e=>a.some(t=>pe(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await me();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{if(!e.cpu)return;const t=await me();await t.cacheManager.deleteMany(t=>he(e).some(e=>pe(t,e)))}catch{}},purge:async()=>{try{const e=await me();await e.cacheManager.clear()}catch{}}},be=((e={})=>{const t=e.engines?.cpu||ye,a=e.engines?.litert||re;let n,o,r,l,g,u,m,f=s.none,p=i.idle,h=[],w=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[...h])e.report(y.percent,y.phase)},x=e=>{p=e},k=()=>{w++,u?.abort(),u=void 0,g=void 0,p==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=>{h=h.filter(t=>t!=e),queueMicrotask(()=>{!h.length&&l&&k()})})(r),r.settle(!1)};h.push(r),t?.aborted?i():t?.addEventListener("abort",i,{once:!0}),a.then(r.settle,()=>r.settle(!1))}):Promise.resolve(!1)},M=()=>p==i.ready&&!!n&&!!o;return{load:async({model:e,limits:t,assets:a,logging:s,signal:m,onProgress:p})=>{if(m?.aborted)return!1;if(M()&&o?.id==e.id)return!0;if(l&&g==e.id)return p(y.percent,y.phase),await _(p,m);l&&(k(),h=[],await l.catch(()=>!1));const E=++w,C=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const l=b(e);if(E!=w)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!=w)return!1;const g=await l.cached(e);if(E!=w)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==w&&v(e,t)}});return E!=w||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!=w||(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,h=[])});return l=C,g=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(i.idle),await(e?.unload())},ready:M,loading:()=>!M()&&p==i.downloading,status:()=>p,backend:()=>f,model:()=>o}})(),ve=(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}:{}}},xe=(e=>{let t,a=0;const n=t=>t.input.onStatus?.(ve(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),p=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(!p)return t.error||(t.error="Model not ready"),void n(t);const h=u(s),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 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:w,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)}})(be),ke=(_e=be,async e=>{const t=g(e.model),a=t=>e.onStatus?.(ve(_e,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=_e.ready()&&_e.model()?.id==t.id;return await _e.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 _e;module.exports=n})();
|
|
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 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 i,s,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 i,s,c=0;for(i in n)r.o(n,i)&&(r.m[i]=n[i]);for(o&&o(r);c<a.length;c++)s=a[c],r.o(t,s)&&t[s]&&t[s][0](),t[s]=0};r.f.j=(n,o)=>{let i=r.o(t,n)?t[n]:void 0;if(0!==i)if(i)o.push(i[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=>i=t[n]=[e])]),o.push(i[1]=r)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(i||(i={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(s||(s={})),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},h=()=>{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},w=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),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})(w,w),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,w,w),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}},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,$=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[...$(e),{type:"text",text:"\n"},...$(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 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,L);if(t>=0){t&&e(s.slice(0,t)),s=s.slice(t+i.length),n=!1;continue}const c=r(s,L);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},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!=i.user||!e.images?.length)),o=[],r=[];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==i.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==i.system?o.unshift(d):l.role==i.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=P(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="litert-store",z=33554432,B=new Map;let q=!1;const A=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}`},O=e=>{const t=/^part-(\d+)$/.exec(e);return t?Number(t[1]):-1},N=async()=>{if(!q)if("undefined"!=typeof navigator&&navigator.storage?.getDirectory)try{return await navigator.storage.getDirectory()}catch{return}else q=!0},F=async()=>{const e=await N();if(e)try{return await e.getDirectoryHandle(S,{create:!0})}catch{return}},I=async(e,t)=>{try{return await e.getDirectoryHandle(t)}catch{return}},U=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}},D=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{}},H=async function*(e){for await(const t of e)yield t},Q=async e=>{try{for await(const[t,a]of H(e))"file"==a.kind&&O(t)>=0&&await e.removeEntry(t).catch(()=>{})}catch{}},G=async(e,t)=>{try{const a=await(await e.getFileHandle(t)).getFile(),n=await U(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}},V=async(e,t)=>{const a=await I(e,t);if(a){const e=await(async e=>await U(await e.getFileHandle("meta.json").catch(()=>{})))(a),t=await(async e=>{const t=[];try{for await(const[a,n]of H(e)){const e=O(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 G(e,t)},J=(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}},K=async({dir:e,start:t,skip:a,total:n,body:o,onProgress:r,onChunk:i})=>{let s,c=t,l=0,g=a;const u=async()=>{const t=await e.getFileHandle((e=>`part-${e}`)(c),{create:!0});s=await t.createWritable(),l=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(z-l,o.byteLength-f);await s.write({type:"write",position:l,data:o.subarray(f,f+e)}),f+=e,l+=e,c+=e,l==z&&await m()}c>t&&r(n?c/n:0,d.download)}await m()}catch(e){throw await m(),e}return c},X=async e=>{const t=await F();return t?await V(t,A(e)):void 0},Y=async({url:e,signal:t,onProgress:a})=>{const n=B.get(e);if(n)return await n;const o=await F();if(!o)return;const r=(async(e,t,a,n)=>{const o=A(t),r=await G(e,o);if(r?.complete)return r;let i=await I(e,o);i||(await e.removeEntry(o).catch(()=>{}),await e.removeEntry(`${o}.json`).catch(()=>{}),i=await e.getDirectoryHandle(o,{create:!0}));let s=0,c=0;for(;;){if(a?.aborted)throw new Error("Cancelled");const r=await V(e,o);if(r?.complete)return r;const l=r?.size??0,g=r?.total||0,u=r?.etag||"";if(l>s)s=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+z,g)-1:l+z-1,f=new AbortController,p=()=>f.abort(),h={size:l,total:g,etag:u};let w,y=setTimeout(p,3e4);a?.addEventListener("abort",p,{once:!0});try{if(w=await fetch(t,{signal:f.signal,headers:{Range:`bytes=${l}-${m}`}}),416==w.status){if(await(w.body?.cancel().catch(()=>{})),g&&l>=g){await D(i,{total:g,etag:u,complete:!0});continue}await Q(i),await D(i,{total:0,etag:"",complete:!1});continue}if(!w.ok||!w.body)throw await(w.body?.cancel().catch(()=>{})),new Error("Model download failed");const a=J(w,h);if(!a){await w.body.cancel().catch(()=>{}),await Q(i),await D(i,{total:0,etag:"",complete:!1});continue}await D(i,{total:a.total,etag:a.etag,complete:!1});const r=0==a.start?l:0,s=await K({dir:i,start:a.start+r,skip:r,total:a.total,body:w.body,onProgress:n,onChunk:()=>{clearTimeout(y),y=setTimeout(p,3e4)}});if(!a.total){await D(i,{total:s,etag:a.etag,complete:!0});const t=await V(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)}}})(o,e,t,a).finally(()=>{B.delete(e)});return B.set(e,r),await r},Z="litertlm-models",ee={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},te=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(Z)}catch{return}},ae=new Map,ne=(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)}}))},oe=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},re=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 i=await oe(n.slice(0,-1)),s=(await oe([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})}}),ie={backend:l.gpu,startLLM:async({model:e,limits:t,onProgress:a,signal:n,logging:o})=>{const i=e.litert;if(!i)throw new Error("Model has no LiteRT artifact");const s=await r.e(520).then(()=>r(507));if(await s.getOrLoadGlobalLiteRtLm(h().script),n?.aborted)throw new Error("Cancelled");const c=M(i.repo,i.file),g=await te();let u;const m=g?await g.match(c):void 0;if(m?.body)u=m.body;else{const e=await X(c);e?.complete&&(u=e.file.stream())}if(!u){const e=await Y({url:c,signal:n,onProgress:a}).catch(e=>{if(n?.aborted)throw new Error("Cancelled");if(!(e=>["NotAllowedError","NotSupportedError"].includes(e?.name||""))(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=ae.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),i=ne(o.body,r,n);await t.put(e,new Response(i,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{ae.delete(e)});return ae.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 ne(n.body,E(n),a)})(c,n,a)),n?.aborted)throw new Error("Cancelled");a(1,d.load);const f=await s.Engine.create({model:u,mainExecutorSettings:{maxNumTokens:4096,...i.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:ee},...i.vision?{visionBackend:s.Backend.GPU}:{}});if(n?.aborted)throw await f.delete(),new Error("Cancelled");return{model:e,backend:l.gpu,contextSize:4096,chat:t=>re({engine:f,model:e,mod:s,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([te(),X(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 X(M(t.repo,t.file)))return!0}const e=await te();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 te();await(async e=>{const t=await F();t&&await(async(e,t)=>{await e.removeEntry(t,{recursive:!0}).catch(()=>{}),await e.removeEntry(`${t}.json`).catch(()=>{})})(t,A(e))})(a),n&&await n.delete(a)}catch{}},purge:async()=>{try{await(async()=>{const e=await N();e&&await e.removeEntry(S,{recursive:!0}).catch(()=>{})})(),"undefined"!=typeof caches&&await caches.delete(Z)}catch{}}};let se,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(se)return se;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}),se=a,a},pe=async()=>{const e=se;se=void 0;try{await(e?.exit())}catch{}},he=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),we=e=>e.cpu?[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]]:[],ye=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},be={backend:l.cpu,startLLM:async({model:e,limits:t,onProgress:a,signal:n,logging:o,assets:r})=>{de=!0===o;const i=e.cpu;if(!i)throw new Error("Model has no CPU artifact");const s=ue(r),c=ge(s);se&&c!=le&&await pe(),ce=s,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=M(i.repo,i.file),h=i.mmproj?.file,w=h?M(i.repo,h):"";if(n?.aborted)throw await pe(),new Error("Cancelled");if(h){const e=await f.cacheManager.list(),t=e.some(e=>he(e,i.file)),a=e.some(e=>he(e,h));t&&!a&&await f.cacheManager.deleteMany(e=>he(e,i.file))}try{await f.loadModelFromUrl(w?{url:p,mmprojUrl:w}:p,{n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!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 ye(n),..._(a.limits,a.reasoning),abortSignal:a.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:a.reasoning}}:{}})}})})(f,e,t),unload:async()=>{if(se==f)await pe();else try{await f.exit()}catch{}}}},cached:async e=>{try{if(!e.cpu)return!1;const t=await fe(),a=await t.cacheManager.list();return we(e).every(e=>a.some(t=>he(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await fe();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{if(!e.cpu)return;const t=await fe();await t.cacheManager.deleteMany(t=>we(e).some(e=>he(t,e)))}catch{}},purge:async()=>{try{const e=await fe();await e.cacheManager.clear()}catch{}}},ve=((e={})=>{const t=e.engines?.cpu||be,a=e.engines?.litert||ie;let n,o,r,i,s,g,m,f=l.none,p=c.idle,h=[],w=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[...h])e.report(y.percent,y.phase)},x=e=>{p=e},k=()=>{w++,g?.abort(),g=void 0,s=void 0,p==c.downloading&&x(c.idle)},_=(e,t)=>{const a=i;return a?new Promise(n=>{let o=!1;const r={report:e,settle:e=>{o||(o=!0,t?.removeEventListener("abort",s),n(e))}},s=()=>{(e=>{h=h.filter(t=>t!=e),queueMicrotask(()=>{!h.length&&i&&k()})})(r),r.settle(!1)};h.push(r),t?.aborted?s():t?.addEventListener("abort",s,{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(i&&s==e.id)return p(y.percent,y.phase),await _(p,m);i&&(k(),h=[],await i.catch(()=>!1));const E=++w,T=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const i=b(e);if(E!=w)return!1;if(!i)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,i),E!=w)return!1;const s=await i.cached(e);if(E!=w)return!1;x(c.downloading),v(0,d.download),s&&v(1,d.load);const m=new AbortController;g=m;try{const s=await i.startLLM({model:e,limits:t,logging:l,signal:m.signal,assets:a,onProgress:(e,t)=>{E==w&&v(e,t)}});return E!=w||m.signal.aborted?(await s.unload(),!1):(n=s,o=e,r=i,f=i.backend,x(c.ready),v(1,d.load),!0)}catch(e){return E!=w||(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(()=>{i==T&&(i=void 0,s=void 0,h=[])});return i=T,s=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}})(),xe=(e,t,a)=>{const n=e.status(),o=m(t);return{availability:n==c.ready?s.online:n==c.error||n==c.unsupported?s.offline:s.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}:{}}},ke=(e=>{let t,a=0;const n=t=>t.input.onStatus?.(xe(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,s=m(o.model),c=o.messages.some(e=>e.role!=i.system&&"string"==typeof e.content&&!!e.content.trim()),l=o.messages.some(e=>e.role==i.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),g=c||l;if(!s)return t.error="Unknown model",void n(t);if(!g)return void n(t);if(l&&!c&&!f(s))return t.error="Model does not accept images",void n(t);const u=k(o.limits),p=await e.load({model:s,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 h=f(s),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 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:w,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)}})(ve),_e=(Me=ve,async e=>{const t=m(e.model),a=t=>e.onStatus?.(xe(Me,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 i=Me.ready()&&Me.model()?.id==t.id;return await Me.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:d.load,percent:100}),!0):(a({requesting:!1,phase:r,percent:o,error:n||"Model not ready"}),!1)});var Me;export{g as ChatModelId,s as ChatStatus,l as LlmBackend,d as LlmPhase,i as LlmRole,c as LlmStatus,ke as createChat,_e 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
|
@@ -194,6 +194,17 @@ interface StoreDownloadParams {
|
|
|
194
194
|
signal?: AbortSignal;
|
|
195
195
|
onProgress: StartLlmParams[`onProgress`];
|
|
196
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
|
+
}
|
|
197
208
|
/** One generation request */
|
|
198
209
|
interface RuntimeChatParams {
|
|
199
210
|
messages: ChatMessage[];
|
|
@@ -369,4 +380,4 @@ interface EngineRunParams {
|
|
|
369
380
|
/** Whether the caller stopped the generation */
|
|
370
381
|
stopped: () => boolean;
|
|
371
382
|
}
|
|
372
|
-
export type { ChatMessage, ChatModel, LlmLimits, ChatStatusSnapshot, ChatInput, ChatPreloadInput, ChatState, CancelChat, WllamaAssets, LitertAssets, GpuNavigator, ActiveCall, RuntimeDeps, RuntimeLoadParams, RuntimeLoadWaiter, RuntimeChatParams, StoredPart, StoredFilePart, StoredModel, StoredModelMeta, ResumePlan, StoreDownloadParams, 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