@degreesign/chat 0.3.2 → 0.3.4
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 +18 -11
- package/dist/browser/chat.min.mjs +1 -1
- package/dist/engines/engine.d.ts +3 -1
- package/dist/engines/store.d.ts +16 -0
- package/dist/node/chat.node.min.js +1 -1
- package/dist/node/chat.node.min.mjs +1 -1
- package/dist/types.d.ts +45 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -151,7 +151,7 @@ requested model is already loaded, no download or load happens.
|
|
|
151
151
|
|
|
152
152
|
| State | Effect |
|
|
153
153
|
| ----- | ------ |
|
|
154
|
-
| Downloading or loading | Stops waiting for the load.
|
|
154
|
+
| Downloading or loading | Stops waiting for the load. Bytes stay on disk, and a download another caller waits for keeps going. |
|
|
155
155
|
| Ready | Aborts the reply and unloads the model. |
|
|
156
156
|
| An older call | Nothing, because a newer call owns the runtime. |
|
|
157
157
|
|
|
@@ -221,7 +221,9 @@ follow the flag.
|
|
|
221
221
|
| `gemma4_e2b` | Gemma 4 E2B | Yes | Yes | No | Yes |
|
|
222
222
|
|
|
223
223
|
The first call downloads the model through its engine and caches it. Later
|
|
224
|
-
calls reuse the loaded runtime. Only one model stays in memory.
|
|
224
|
+
calls reuse the loaded runtime. Only one model stays in memory. An interrupted
|
|
225
|
+
download keeps every part it committed and resumes from the last one on the
|
|
226
|
+
next attempt, including after a reload.
|
|
225
227
|
|
|
226
228
|
Qwen3-VL 2B downloads a vision projector of about 445 MB with the model, so its
|
|
227
229
|
total download is about 1.5 GB. It runs on the CPU engine.
|
|
@@ -299,15 +301,20 @@ same headers.
|
|
|
299
301
|
|
|
300
302
|
Each engine keeps its own cache. Loading a model unloads the previous runtime
|
|
301
303
|
and removes the previous model's cache. The CPU engine uses the wllama cache
|
|
302
|
-
manager
|
|
303
|
-
under `
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
304
|
+
manager. The GPU engine stores the `.litertlm` file in the origin private file
|
|
305
|
+
system under `litert-store` as numbered parts, and reads a Cache Storage entry
|
|
306
|
+
under `litertlm-models` when an older version stored one. A quota failure keeps
|
|
307
|
+
the parts already stored, so freeing disk lets the next attempt resume.
|
|
308
|
+
|
|
309
|
+
The GPU engine stores the file before it compiles the model, and one download
|
|
310
|
+
serves every caller. A failed compile, a cancelled call or a repeated
|
|
311
|
+
`createChat` reads the stored parts instead of downloading them again. A
|
|
312
|
+
download fetches bounded ranges of 32 MB, commits each part as it arrives and
|
|
313
|
+
retries a stalled or cut connection from the last committed byte, so a reload
|
|
314
|
+
loses at most one part. Each attempt checks the file size and entity tag, and a
|
|
315
|
+
changed model starts over. A host that ignores the range replays the stored
|
|
316
|
+
prefix and keeps the parts already stored. Hosts without a writable file system
|
|
317
|
+
still stream from the network and fall back to Cache Storage, without resuming.
|
|
311
318
|
|
|
312
319
|
A CPU vision model downloads its projector with the model and caches both. A
|
|
313
320
|
GPU vision model keeps its encoder in the single `.litertlm` file.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see chat.min.mjs.LICENSE.txt */
|
|
2
|
-
var e={};const t={};function n(a){const o=t[a];if(void 0!==o)return o.exports;const r=t[a]={exports:{}};return e[a](r,r.exports,n),r.exports}var a,o,r,s,i,c;n.m=e,n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.f={},n.e=e=>{const t=[];return n.f.j(e,t),Promise.all(t)},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={520:()=>import("./engine-litert.min.mjs"),924:()=>import("./engine-wllama.min.mjs")},t={792:0},a=e=>{let{__webpack_esm_ids__:a,__webpack_esm_modules__:o,__webpack_esm_runtime__:r}=e;var s,i,c=0;for(s in o)n.o(o,s)&&(n.m[s]=o[s]);for(r&&r(n);c<a.length;c++)i=a[c],n.o(t,i)&&t[i]&&t[i][0](),t[i]=0};n.f.j=(o,r)=>{let s=n.o(t,o)?t[o]:void 0;if(0!==s)if(s)r.push(s[1]);else{let n=e[o]().then(a,e=>{throw 0!==t[o]&&(t[o]=void 0),e});n=Promise.race([n,new Promise(e=>s=t[o]=[e])]),r.push(s[1]=n)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(a||(a={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(o||(o={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(r||(r={})),function(e){e.cpu="cpu",e.gpu="gpu",e.none="none"}(s||(s={})),function(e){e.download="download",e.load="load"}(i||(i={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b",e.gemma4_e2b="gemma4-e2b"}(c||(c={}));const l=[{id:c.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}},{id:c.gemma4_e2b,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it.litertlm",vision:!0}}],d=e=>e?l.find(t=>t.id==e):void 0,g=e=>!!e.cpu?.mmproj||!!e.litert?.vision,m=new URL("./../assets/wllama/wllama.wasm",import.meta.url).href,u=new URL("./../assets/wllama/compat/wllama.wasm",import.meta.url).href,p=new URL("./../assets/wllama/compat/wllama.js",import.meta.url).href,f=new URL("./../assets/litert/litertlm_wasm_internal.js",import.meta.url).href,h=(new URL("./../assets/litert/litertlm_wasm_internal.wasm",import.meta.url).href,288),w=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),n=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!n.includes(";base64"))return await(await fetch(e)).arrayBuffer();const a=atob(e.slice(t+1)),o=new Uint8Array(a.length);for(let e=0;e<a.length;e++)o[e]=a.charCodeAt(e);return o.buffer},y=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),n=await createImageBitmap(await t.blob()),a=Math.min(n.width,n.height),o=Math.floor((n.width-a)/2),r=Math.floor((n.height-a)/2),s=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const n=document.createElement("canvas");return n.width=e,n.height=t,n})(h,h),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,h,h),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const n=new FileReader;n.onerror=()=>t(""),n.onload=()=>t(`${n.result}`),n.readAsDataURL(e)}))(t)||e}return s.toDataURL("image/jpeg",.85)}catch{return e}},b={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},x=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,k=(e={})=>{const t=b;return{maxReplyTokens:x(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:x(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:x(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:x(e.maxImages,t.maxImages,0),maxContentLength:x(e.maxContentLength,t.maxContentLength,1),promptCharBudget:x(e.promptCharBudget,t.promptCharBudget,1),maxThreads:x(e.maxThreads,t.maxThreads,1)}},v=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),_=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,M=e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)),T=["<|channel>thought\n","<|channel>thought","..."],L=["<channel|>","..."],C=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,R=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,E=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...R(e),{type:"text",text:"\n"},...R(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},j=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((e,t)=>{let n="",a=!1;const o=(e,t)=>{let n=-1,a="";for(const o of t){const t=e.indexOf(o);t>=0&&(n<0||t<n)&&(n=t,a=o)}return{at:n,tag:a}},r=(e,t)=>{let n="";for(const a of t)for(let t=Math.min(e.length,a.length-1);t>n.length;t--)if(e.endsWith(a.slice(0,t))){n=e.slice(e.length-t);break}return n};return{feed:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,L);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,L);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,T);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,T);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},q=async({model:e,params:t,start:n,stopped:o})=>{const r=await(async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push(n);continue}const e=[];for(const t of n.content)e.push("image"==t.type?{type:"image",url:await y(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=b)=>{const n=t.maxContentLength,o=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=a.user||!e.images?.length)),r=[],s=[];let i=0,c=t.maxImages;for(let e=o.length-1;e>=0;e--){const l=o[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==a.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==a.system?r.unshift(d):l.role==a.assistant?s.unshift({role:"assistant",content:d}):s.unshift({role:"user",content:C(d,g)})}}for(;s.length&&"user"!=s[0].role;)s.shift();const l=[];for(const e of s){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=E(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=r.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),g})(t.messages,t.limits));return t.logging&&((e,t)=>{console.log("Local chat call",e.id,t.map(({role:e,content:t})=>({role:e,content:"****",...Array.isArray(t)?{images:t.filter(e=>"image"==e.type).length}:{}})))})(e,r),await j({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(r),stopped:o})},P="litertlm-models",W={num_output_candidates:1,wait_for_weight_uploads:!0,num_decode_steps_per_sync:3,sequence_batch_size:0,supported_lora_ranks:[],max_top_k:40,enable_decode_logits:!1,enable_external_embeddings:!1,use_submodel:!1,use_autosized_ringbuffers:!0},$=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(P)}catch{return}},B=new Map,U=e=>Number(e.headers.get("content-length"))||0,I=(e,t,n)=>{let a=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{a+=e.byteLength,n(t?a/t:0,i.download),o.enqueue(e)}}))},O=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push({role:n.role,content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await w(t.url)});t.push({role:"user",content:e})}return t},A=async({engine:e,model:t,mod:n,params:a})=>await q({model:t,params:a,stopped:()=>!!a.signal?.aborted,start:async o=>{if(a.signal?.aborted)throw new Error("Cancelled");if(M(o)&&!t.litert?.vision)throw new Error("Model does not accept images");return async function*({engine:e,mod:t,params:n,messages:a}){const o=a[a.length-1],r=v(n.limits,n.reasoning);if("user"!=o?.role)throw new Error("No user turn");const s=await O(a.slice(0,-1)),i=(await O([o]))[0];if(!i)throw new Error("Empty prompt");const c=await e.createConversation({sessionConfig:{maxOutputTokens:r.max_tokens,samplerParams:{type:t.SamplerType.TOP_K,temperature:r.temperature,k:40,p:.95}},preface:{...s.length?{messages:s}:{},extra_context:{enable_thinking:n.reasoning}}});let l;const d=()=>{l&&l.cancel().catch(()=>{});try{c.cancel()}catch{}};n.signal?.addEventListener("abort",d,{once:!0});try{if(n.signal?.aborted)return;const e=c.sendMessageStreaming(i).getReader();for(l=e;;){const{done:t,value:n}=await e.read();if(t)break;const a={};let o="string"==typeof n.content?n.content:"";if(Array.isArray(n.content))for(const e of n.content)"text"==e.type&&(o+=e.text);o&&(a.content=o);const r=n.channels?.thought;r&&(a.reasoning=r),(a.content||a.reasoning)&&(yield{choices:[{delta:a}]})}}finally{n.signal?.removeEventListener("abort",d);try{await c.delete()}catch{}}}({engine:e,mod:n,params:a,messages:o})}}),S={backend:s.gpu,startLLM:async({model:e,limits:t,onProgress:a,signal:o,logging:r})=>{const c=e.litert;if(!c)throw new Error("Model has no LiteRT artifact");const l=await n.e(520).then(()=>n(507));if(await l.getOrLoadGlobalLiteRtLm(f),o?.aborted)throw new Error("Cancelled");const d=_(c.repo,c.file),g=await $();let m;if(g){if(!await g.match(d))try{await(async(e,t,n,a)=>{const o=B.get(e);if(o)return await o;const r=(async()=>{const o=await fetch(e,{signal:n});if(!o.ok||!o.body)throw new Error("Model download failed");const r=U(o),s=I(o.body,r,a);await t.put(e,new Response(s,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{B.delete(e)});return B.set(e,r),await r})(d,g,o,a)}catch(e){if(o?.aborted)throw new Error("Cancelled");r&&console.log("Local model cache failed",e)}const e=await g.match(d);e?.body&&(m=e.body)}if(m||(m=await(async(e,t,n)=>{const a=await fetch(e,{signal:t});if(!a.ok||!a.body)throw new Error("Model download failed");return I(a.body,U(a),n)})(d,o,a)),o?.aborted)throw new Error("Cancelled");a(1,i.load);const u=await l.Engine.create({model:m,mainExecutorSettings:{maxNumTokens:4096,...c.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:W},...c.vision?{visionBackend:l.Backend.GPU}:{}});if(o?.aborted)throw await u.delete(),new Error("Cancelled");return{model:e,backend:s.gpu,contextSize:4096,chat:t=>A({engine:u,model:e,mod:l,params:t}),unload:async()=>{await u.delete()}}},cached:async e=>{try{const t=e.litert,n=await $();return!(!t||!n)&&!!await n.match(_(t.repo,t.file))}catch{return!1}},hasCache:async()=>{try{const e=await $();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert,n=await $();if(!t||!n)return;await n.delete(_(t.repo,t.file))}catch{}},purge:async()=>{try{"undefined"!=typeof caches&&await caches.delete(P)}catch{}}};let F,N,Q="",z=!1;const G=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,D=e=>{const t={wasm:m,compatWasm:u,compatWorker:p};return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},V=e=>{const t=e=>(...t)=>{z&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},K=async()=>{if(F)return F;const e=await n.e(924).then(()=>n(577)),t=N||D(),a=new e.Wllama({default:t.wasm},{logger:V(e.LoggerWithoutDebug)});return N||(N=t,Q=G(t)),a.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),F=a,a},H=async()=>{const e=F;F=void 0;try{await(e?.exit())}catch{}},J=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),X=e=>e.cpu?[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]]:[],Y=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){"system"==n.role?t.push({role:"system",content:n.content}):"assistant"==n.role?t.push({role:"assistant",content:n.content}):t.push({role:"user",content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await w(t.url)});t.push({role:"user",content:e})}return t},Z={backend:s.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{z=!0===o;const c=e.cpu;if(!c)throw new Error("Model has no CPU artifact");const l=D(r),d=G(l);F&&d!=Q&&await H(),N=l,Q=d;const g=(m="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,u=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(m||4)-1)),u)));var m,u;const p=await K(),f=_(c.repo,c.file),h=c.mmproj?.file,w=h?_(c.repo,h):"";if(a?.aborted)throw await H(),new Error("Cancelled");if(h){const e=await p.cacheManager.list(),t=e.some(e=>J(e,c.file)),n=e.some(e=>J(e,h));t&&!n&&await p.cacheManager.deleteMany(e=>J(e,c.file))}try{await p.loadModelFromUrl(w?{url:f,mmprojUrl:w}:f,{n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?i.load:i.download)}})}catch(e){throw await H(),e}if(a?.aborted)throw await H(),new Error("Cancelled");if(!p.getLoadedContextInfo().n_ctx)throw await H(),new Error("Failed to create model context");return{model:e,backend:s.cpu,contextSize:8192,chat:t=>(async(e,t,n)=>{if(z=!0===n.logging,e.isModelLoaded())return await q({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if(M(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await Y(a),...v(n.limits,n.reasoning),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}})}})})(p,e,t),unload:async()=>{if(F==p)await H();else try{await p.exit()}catch{}}}},cached:async e=>{try{if(!e.cpu)return!1;const t=await K(),n=await t.cacheManager.list();return X(e).every(e=>n.some(t=>J(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await K();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{if(!e.cpu)return;const t=await K();await t.cacheManager.deleteMany(t=>X(e).some(e=>J(t,e)))}catch{}},purge:async()=>{try{const e=await K();await e.cacheManager.clear()}catch{}}},ee=((e={})=>{const t=e.engines?.cpu||Z,n=e.engines?.litert||S;let a,o,c,d,g,m,u,p=s.none,f=r.idle,h=[],w=0,y={percent:0,phase:i.download};const b=a=>{if(e.backend!=s.none)return e.backend==s.cpu?a.cpu?t:void 0:e.backend==s.gpu?a.litert?n:void 0:a.litert&&"undefined"!=typeof navigator&&navigator.gpu&&"undefined"!=typeof WebAssembly?n:!a.cpu||"undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?void 0:t},x=(e,t)=>{y={percent:Math.max(0,Math.min(1,e)),phase:t||i.download};for(const e of[...h])e.report(y.percent,y.phase)},k=e=>{f=e},v=()=>{w++,m?.abort(),m=void 0,g=void 0,f==r.downloading&&k(r.idle)},_=(e,t)=>{const n=d;return n?new Promise(a=>{let o=!1;const r={report:e,settle:e=>{o||(o=!0,t?.removeEventListener("abort",s),a(e))}},s=()=>{(e=>{h=h.filter(t=>t!=e),queueMicrotask(()=>{!h.length&&d&&v()})})(r),r.settle(!1)};h.push(r),t?.aborted?s():t?.addEventListener("abort",s,{once:!0}),n.then(r.settle,()=>r.settle(!1))}):Promise.resolve(!1)},M=()=>f==r.ready&&!!a&&!!o;return{load:async({model:e,limits:t,assets:n,logging:s,signal:u,onProgress:f})=>{if(u?.aborted)return!1;if(M()&&o?.id==e.id)return!0;if(d&&g==e.id)return f(y.percent,y.phase),await _(f,u);d&&(v(),h=[],await d.catch(()=>!1));const T=++w,L=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const d=b(e);if(T!=w)return!1;if(!d)return k(r.unsupported),!1;if(await(async(e,t)=>{if(o&&o.id!=e.id){const e=o,t=c,n=a;a=void 0,o=void 0,c=void 0,await(n?.unload()),await(t?.remove(e))}if(await t.hasCache())for(const n of l)n.id!=e.id&&b(n)==t&&await t.remove(n)})(e,d),T!=w)return!1;const g=await d.cached(e);if(T!=w)return!1;if(!g&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await d.purge(),T!=w)return!1;k(r.downloading),x(0,i.download),g&&x(1,i.load);const u=new AbortController;m=u;try{const l=await d.startLLM({model:e,limits:t,logging:s,signal:u.signal,assets:n,onProgress:(e,t)=>{T==w&&x(e,t)}});return T!=w||u.signal.aborted?(await l.unload(),!1):(a=l,o=e,c=d,p=d.backend,k(r.ready),x(1,i.load),!0)}catch(e){return T!=w||(a=void 0,o=void 0,c=void 0,s&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await d.purge(),k(r.error)),!1}finally{m==u&&(m=void 0)}})().finally(()=>{d==L&&(d=void 0,g=void 0,h=[])});return d=L,g=e.id,await _(f,u)},chat:async e=>{if(!M()||!a)return;for(;u;)await u.catch(()=>{});if(!M()||!a)return;const t=a.chat(e);u=t;try{return await t}finally{u==t&&(u=void 0)}},unload:async()=>{const e=a;v(),a=void 0,o=void 0,c=void 0,k(r.idle),await(e?.unload())},ready:M,loading:()=>!M()&&f==r.downloading,status:()=>f,backend:()=>p,model:()=>o}})(),te=(e,t,n)=>{const a=e.status(),s=d(t);return{availability:a==r.ready?o.online:a==r.error||a==r.unsupported?o.offline:o.away,status:a,backend:e.backend(),supportsImages:!!s&&g(s),ready:e.ready(),loading:e.loading(),requesting:n.requesting,phase:n.phase,percent:n.percent,...n.error?{error:n.error}:{}}},ne=(e=>{let t,n=0;const o=t=>t.input.onStatus?.(te(e,t.input.model,t));return s=>{t?.controller.abort();const c={token:++n,input:s,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?i.load:i.download,requesting:!1,cancelled:!1};return t=c,o(c),(async t=>{const{input:r}=t,s=!0===r.logging,c=d(r.model),l=r.messages.some(e=>e.role!=a.system&&"string"==typeof e.content&&!!e.content.trim()),m=r.messages.some(e=>e.role==a.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),u=l||m;if(!c)return t.error="Unknown model",void o(t);if(!u)return void o(t);if(m&&!l&&!g(c))return t.error="Model does not accept images",void o(t);const p=k(r.limits),f=await e.load({model:c,limits:p,logging:s,signal:t.controller.signal,onProgress:(e,a)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=a,o(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(t.cancelled)return;if(!f)return t.error||(t.error="Model not ready"),void o(t);const h=g(c),w=m&&!h?r.messages.map(({images:e,...t})=>t):r.messages;if(m&&!h&&!l)return t.error="Model does not accept images",void o(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=i.load,o(t);let y,b="",x="";try{y=await e.chat({messages:w,limits:p,reasoning:!0===r.reasoning,logging:s,onReason:e=>{t.token!=n||t.cancelled||(b+=e,r.onThinking?.(b))},onText:e=>{t.token!=n||t.cancelled||(x+=e,r.onResponse?.(x))},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void o(t)}t.token==n&&(t.requesting=!1,y||t.cancelled||(t.error="No reply"),o(t))})(c),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=r.ready?queueMicrotask(()=>o(t)):e.unload().then(()=>o(t)))})(c)}})(ee),ae=(oe=ee,async e=>{const t=d(e.model),n=t=>e.onStatus?.(te(oe,e.model,t));if(!t)return n({requesting:!1,phase:i.download,percent:0,error:"Unknown model"}),!1;let a,o=0,r=i.download;const s=oe.ready()&&oe.model()?.id==t.id;return await oe.load({model:t,limits:k(e.limits),logging:!0===e.logging,onProgress:(e,t)=>{o=Math.round(100*e),r=t,n({requesting:!1,phase:r,percent:o})}}).catch(e=>(a=`${e?.message||`${e}`}`,!1))?(s&&n({requesting:!1,phase:i.load,percent:100}),!0):(n({requesting:!1,phase:r,percent:o,error:a||"Model not ready"}),!1)});var oe;export{c as ChatModelId,o as ChatStatus,s as LlmBackend,i as LlmPhase,a as LlmRole,r as LlmStatus,ne as createChat,ae as preloadModel};
|
|
2
|
+
var e={};const t={};function a(n){const o=t[n];if(void 0!==o)return o.exports;const r=t[n]={exports:{}};return e[n](r,r.exports,a),r.exports}var n,o,r,i,s,c;a.m=e,a.d=(e,t)=>{for(var n in t)a.o(t,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},a.f={},a.e=e=>{const t=[];return a.f.j(e,t),Promise.all(t)},a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={520:()=>import("./engine-litert.min.mjs"),924:()=>import("./engine-wllama.min.mjs")},t={792:0},n=e=>{let{__webpack_esm_ids__:n,__webpack_esm_modules__:o,__webpack_esm_runtime__:r}=e;var i,s,c=0;for(i in o)a.o(o,i)&&(a.m[i]=o[i]);for(r&&r(a);c<n.length;c++)s=n[c],a.o(t,s)&&t[s]&&t[s][0](),t[s]=0};a.f.j=(o,r)=>{let i=a.o(t,o)?t[o]:void 0;if(0!==i)if(i)r.push(i[1]);else{let a=e[o]().then(n,e=>{throw 0!==t[o]&&(t[o]=void 0),e});a=Promise.race([a,new Promise(e=>i=t[o]=[e])]),r.push(i[1]=a)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(n||(n={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(o||(o={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(r||(r={})),function(e){e.cpu="cpu",e.gpu="gpu",e.none="none"}(i||(i={})),function(e){e.download="download",e.load="load"}(s||(s={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b",e.gemma4_e2b="gemma4-e2b"}(c||(c={}));const l=[{id:c.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}},{id:c.gemma4_e2b,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it.litertlm",vision:!0}}],d=e=>e?l.find(t=>t.id==e):void 0,g=e=>!!e.cpu?.mmproj||!!e.litert?.vision,u=new URL("./../assets/wllama/wllama.wasm",import.meta.url).href,m=new URL("./../assets/wllama/compat/wllama.wasm",import.meta.url).href,f=new URL("./../assets/wllama/compat/wllama.js",import.meta.url).href,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};
|
package/dist/engines/engine.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ declare const replyOptions: (limits: LlmLimits, reasoning: boolean) => {
|
|
|
12
12
|
declare const
|
|
13
13
|
/** Resolve one model file on the model host */
|
|
14
14
|
modelUrl: (repo: string, file: string) => string,
|
|
15
|
+
/** Declared size of one download, zero when the host hides it */
|
|
16
|
+
contentLength: (response: Response) => number,
|
|
15
17
|
/** Whether any turn carries an image */
|
|
16
18
|
hasImages: (messages: EngineMessage[]) => boolean;
|
|
17
19
|
declare const
|
|
@@ -30,4 +32,4 @@ streamReply: ({ model, logging, onReason, onText, start, stopped, }: StreamReply
|
|
|
30
32
|
declare const
|
|
31
33
|
/** Build the prompt and stream one reply through an engine */
|
|
32
34
|
runEngineChat: ({ model, params, start, stopped, }: EngineRunParams) => Promise<string | undefined>;
|
|
33
|
-
export { buildMessages, createThinkSplitter, logChatCall, runEngineChat, streamReply, replyOptions, defaultLlmLimits, resolveLlmLimits, hasImages, modelUrl, };
|
|
35
|
+
export { buildMessages, createThinkSplitter, logChatCall, runEngineChat, streamReply, replyOptions, defaultLlmLimits, resolveLlmLimits, hasImages, modelUrl, contentLength, };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ResumePlan, StoredFilePart, StoredModel, StoredPart, StoreDownloadParams } from '../types';
|
|
2
|
+
declare const
|
|
3
|
+
/** Contiguous parts from offset zero, stopping at the first gap */
|
|
4
|
+
chainParts: (parts: StoredFilePart[]) => StoredFilePart[],
|
|
5
|
+
/** Where one response continues the parts, undefined restarts them */
|
|
6
|
+
resumePlan: (response: Response, part: StoredPart) => ResumePlan | undefined;
|
|
7
|
+
declare const
|
|
8
|
+
/** Stored bytes and metadata of one model file, undefined when absent */
|
|
9
|
+
storedModel: (url: string) => Promise<StoredModel | undefined>,
|
|
10
|
+
/** Download one model file, resuming the parts already stored */
|
|
11
|
+
downloadModel: ({ url, signal, onProgress, }: StoreDownloadParams) => Promise<StoredModel | undefined>,
|
|
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, };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see chat.node.min.js.LICENSE.txt */
|
|
2
|
-
(()=>{"use strict";var e={};const t={};function n(a){const o=t[a];if(void 0!==o)return o.exports;const r=t[a]={exports:{}};return e[a](r,r.exports,n),r.exports}n.m=e,n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.f={},n.e=e=>{const t=[];return n.f.require(e,t),Promise.all(t)},n.u=e=>({520:"engine-litert",924:"engine-wllama"}[e]+".node.min.js"),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={792:1};n.f.require=(t,a)=>{if(!e[t]){const a=require("./"+n.u(t));e[t]||(t=>{const a=t.modules,o=t.ids,r=t.runtime;for(var s in a)n.o(a,s)&&(n.m[s]=a[s]);r&&r(n);for(var i=0;i<o.length;i++)e[o[i]]=1})(a)}}})();let a={};var o,r,s,i,c,l;n.r(a),n.d(a,{ChatModelId:()=>l,ChatStatus:()=>r,LlmBackend:()=>i,LlmPhase:()=>c,LlmRole:()=>o,LlmStatus:()=>s,createChat:()=>ne,preloadModel:()=>ae}),function(e){e.system="system",e.user="user",e.assistant="assistant"}(o||(o={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(r||(r={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(s||(s={})),function(e){e.cpu="cpu",e.gpu="gpu",e.none="none"}(i||(i={})),function(e){e.download="download",e.load="load"}(c||(c={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b",e.gemma4_e2b="gemma4-e2b"}(l||(l={}));const d=[{id:l.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}},{id:l.gemma4_e2b,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it.litertlm",vision:!0}}],g=e=>e?d.find(t=>t.id==e):void 0,u=e=>!!e.cpu?.mmproj||!!e.litert?.vision,m=require("node:path"),p=()=>{return e=(0,m.join)(__dirname,"../assets/wllama"),{wasm:(0,m.join)(e,"wllama.wasm"),compatWasm:(0,m.join)(e,"compat/wllama.wasm"),compatWorker:(0,m.join)(e,"compat/wllama.js")};var e},f=()=>{return e=(0,m.join)(__dirname,"../assets/litert"),{script:(0,m.join)(e,"litertlm_wasm_internal.js"),wasm:(0,m.join)(e,"litertlm_wasm_internal.wasm")};var e},h=288,w=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),n=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!n.includes(";base64"))return await(await fetch(e)).arrayBuffer();const a=atob(e.slice(t+1)),o=new Uint8Array(a.length);for(let e=0;e<a.length;e++)o[e]=a.charCodeAt(e);return o.buffer},y=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),n=await createImageBitmap(await t.blob()),a=Math.min(n.width,n.height),o=Math.floor((n.width-a)/2),r=Math.floor((n.height-a)/2),s=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const n=document.createElement("canvas");return n.width=e,n.height=t,n})(h,h),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,h,h),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const n=new FileReader;n.onerror=()=>t(""),n.onload=()=>t(`${n.result}`),n.readAsDataURL(e)}))(t)||e}return s.toDataURL("image/jpeg",.85)}catch{return e}},b={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},x=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,v=(e={})=>{const t=b;return{maxReplyTokens:x(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:x(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:x(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:x(e.maxImages,t.maxImages,0),maxContentLength:x(e.maxContentLength,t.maxContentLength,1),promptCharBudget:x(e.promptCharBudget,t.promptCharBudget,1),maxThreads:x(e.maxThreads,t.maxThreads,1)}},k=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),_=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,M=e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)),C=["<|channel>thought\n","<|channel>thought","..."],T=["<channel|>","..."],L=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,E=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,j=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...E(e),{type:"text",text:"\n"},...E(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},q=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((e,t)=>{let n="",a=!1;const o=(e,t)=>{let n=-1,a="";for(const o of t){const t=e.indexOf(o);t>=0&&(n<0||t<n)&&(n=t,a=o)}return{at:n,tag:a}},r=(e,t)=>{let n="";for(const a of t)for(let t=Math.min(e.length,a.length-1);t>n.length;t--)if(e.endsWith(a.slice(0,t))){n=e.slice(e.length-t);break}return n};return{feed:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,T);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,T);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,C);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,C);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},R=async({model:e,params:t,start:n,stopped:a})=>{const r=await(async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push(n);continue}const e=[];for(const t of n.content)e.push("image"==t.type?{type:"image",url:await y(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=b)=>{const n=t.maxContentLength,a=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=o.user||!e.images?.length)),r=[],s=[];let i=0,c=t.maxImages;for(let e=a.length-1;e>=0;e--){const l=a[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==o.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==o.system?r.unshift(d):l.role==o.assistant?s.unshift({role:"assistant",content:d}):s.unshift({role:"user",content:L(d,g)})}}for(;s.length&&"user"!=s[0].role;)s.shift();const l=[];for(const e of s){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=j(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=r.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),g})(t.messages,t.limits));return t.logging&&((e,t)=>{console.log("Local chat call",e.id,t.map(({role:e,content:t})=>({role:e,content:"****",...Array.isArray(t)?{images:t.filter(e=>"image"==e.type).length}:{}})))})(e,r),await q({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(r),stopped:a})},W="litertlm-models",$={num_output_candidates:1,wait_for_weight_uploads:!0,num_decode_steps_per_sync:3,sequence_batch_size:0,supported_lora_ranks:[],max_top_k:40,enable_decode_logits:!1,enable_external_embeddings:!1,use_submodel:!1,use_autosized_ringbuffers:!0},P=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(W)}catch{return}},B=new Map,I=e=>Number(e.headers.get("content-length"))||0,O=(e,t,n)=>{let a=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{a+=e.byteLength,n(t?a/t:0,c.download),o.enqueue(e)}}))},A=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push({role:n.role,content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await w(t.url)});t.push({role:"user",content:e})}return t},S=async({engine:e,model:t,mod:n,params:a})=>await R({model:t,params:a,stopped:()=>!!a.signal?.aborted,start:async o=>{if(a.signal?.aborted)throw new Error("Cancelled");if(M(o)&&!t.litert?.vision)throw new Error("Model does not accept images");return async function*({engine:e,mod:t,params:n,messages:a}){const o=a[a.length-1],r=k(n.limits,n.reasoning);if("user"!=o?.role)throw new Error("No user turn");const s=await A(a.slice(0,-1)),i=(await A([o]))[0];if(!i)throw new Error("Empty prompt");const c=await e.createConversation({sessionConfig:{maxOutputTokens:r.max_tokens,samplerParams:{type:t.SamplerType.TOP_K,temperature:r.temperature,k:40,p:.95}},preface:{...s.length?{messages:s}:{},extra_context:{enable_thinking:n.reasoning}}});let l;const d=()=>{l&&l.cancel().catch(()=>{});try{c.cancel()}catch{}};n.signal?.addEventListener("abort",d,{once:!0});try{if(n.signal?.aborted)return;const e=c.sendMessageStreaming(i).getReader();for(l=e;;){const{done:t,value:n}=await e.read();if(t)break;const a={};let o="string"==typeof n.content?n.content:"";if(Array.isArray(n.content))for(const e of n.content)"text"==e.type&&(o+=e.text);o&&(a.content=o);const r=n.channels?.thought;r&&(a.reasoning=r),(a.content||a.reasoning)&&(yield{choices:[{delta:a}]})}}finally{n.signal?.removeEventListener("abort",d);try{await c.delete()}catch{}}}({engine:e,mod:n,params:a,messages:o})}}),U={backend:i.gpu,startLLM:async({model:e,limits:t,onProgress:a,signal:o,logging:r})=>{const s=e.litert;if(!s)throw new Error("Model has no LiteRT artifact");const l=await n.e(520).then(()=>n(507));if(await l.getOrLoadGlobalLiteRtLm(f().script),o?.aborted)throw new Error("Cancelled");const d=_(s.repo,s.file),g=await P();let u;if(g){if(!await g.match(d))try{await(async(e,t,n,a)=>{const o=B.get(e);if(o)return await o;const r=(async()=>{const o=await fetch(e,{signal:n});if(!o.ok||!o.body)throw new Error("Model download failed");const r=I(o),s=O(o.body,r,a);await t.put(e,new Response(s,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{B.delete(e)});return B.set(e,r),await r})(d,g,o,a)}catch(e){if(o?.aborted)throw new Error("Cancelled");r&&console.log("Local model cache failed",e)}const e=await g.match(d);e?.body&&(u=e.body)}if(u||(u=await(async(e,t,n)=>{const a=await fetch(e,{signal:t});if(!a.ok||!a.body)throw new Error("Model download failed");return O(a.body,I(a),n)})(d,o,a)),o?.aborted)throw new Error("Cancelled");a(1,c.load);const m=await l.Engine.create({model:u,mainExecutorSettings:{maxNumTokens:4096,...s.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:$},...s.vision?{visionBackend:l.Backend.GPU}:{}});if(o?.aborted)throw await m.delete(),new Error("Cancelled");return{model:e,backend:i.gpu,contextSize:4096,chat:t=>S({engine:m,model:e,mod:l,params:t}),unload:async()=>{await m.delete()}}},cached:async e=>{try{const t=e.litert,n=await P();return!(!t||!n)&&!!await n.match(_(t.repo,t.file))}catch{return!1}},hasCache:async()=>{try{const e=await P();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert,n=await P();if(!t||!n)return;await n.delete(_(t.repo,t.file))}catch{}},purge:async()=>{try{"undefined"!=typeof caches&&await caches.delete(W)}catch{}}};let F,N,Q="",z=!1;const G=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,D=e=>{const t=p();return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},V=e=>{const t=e=>(...t)=>{z&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},K=async()=>{if(F)return F;const e=await n.e(924).then(()=>n(577)),t=N||D(),a=new e.Wllama({default:t.wasm},{logger:V(e.LoggerWithoutDebug)});return N||(N=t,Q=G(t)),a.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),F=a,a},H=async()=>{const e=F;F=void 0;try{await(e?.exit())}catch{}},J=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),X=e=>e.cpu?[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]]:[],Y=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){"system"==n.role?t.push({role:"system",content:n.content}):"assistant"==n.role?t.push({role:"assistant",content:n.content}):t.push({role:"user",content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await w(t.url)});t.push({role:"user",content:e})}return t},Z={backend:i.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{z=!0===o;const s=e.cpu;if(!s)throw new Error("Model has no CPU artifact");const l=D(r),d=G(l);F&&d!=Q&&await H(),N=l,Q=d;const g=(u="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,m=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(u||4)-1)),m)));var u,m;const p=await K(),f=_(s.repo,s.file),h=s.mmproj?.file,w=h?_(s.repo,h):"";if(a?.aborted)throw await H(),new Error("Cancelled");if(h){const e=await p.cacheManager.list(),t=e.some(e=>J(e,s.file)),n=e.some(e=>J(e,h));t&&!n&&await p.cacheManager.deleteMany(e=>J(e,s.file))}try{await p.loadModelFromUrl(w?{url:f,mmprojUrl:w}:f,{n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?c.load:c.download)}})}catch(e){throw await H(),e}if(a?.aborted)throw await H(),new Error("Cancelled");if(!p.getLoadedContextInfo().n_ctx)throw await H(),new Error("Failed to create model context");return{model:e,backend:i.cpu,contextSize:8192,chat:t=>(async(e,t,n)=>{if(z=!0===n.logging,e.isModelLoaded())return await R({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if(M(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await Y(a),...k(n.limits,n.reasoning),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}})}})})(p,e,t),unload:async()=>{if(F==p)await H();else try{await p.exit()}catch{}}}},cached:async e=>{try{if(!e.cpu)return!1;const t=await K(),n=await t.cacheManager.list();return X(e).every(e=>n.some(t=>J(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await K();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{if(!e.cpu)return;const t=await K();await t.cacheManager.deleteMany(t=>X(e).some(e=>J(t,e)))}catch{}},purge:async()=>{try{const e=await K();await e.cacheManager.clear()}catch{}}},ee=((e={})=>{const t=e.engines?.cpu||Z,n=e.engines?.litert||U;let a,o,r,l,g,u,m,p=i.none,f=s.idle,h=[],w=0,y={percent:0,phase:c.download};const b=a=>{if(e.backend!=i.none)return e.backend==i.cpu?a.cpu?t:void 0:e.backend==i.gpu?a.litert?n:void 0:a.litert&&"undefined"!=typeof navigator&&navigator.gpu&&"undefined"!=typeof WebAssembly?n:!a.cpu||"undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?void 0:t},x=(e,t)=>{y={percent:Math.max(0,Math.min(1,e)),phase:t||c.download};for(const e of[...h])e.report(y.percent,y.phase)},v=e=>{f=e},k=()=>{w++,u?.abort(),u=void 0,g=void 0,f==s.downloading&&v(s.idle)},_=(e,t)=>{const n=l;return n?new Promise(a=>{let o=!1;const r={report:e,settle:e=>{o||(o=!0,t?.removeEventListener("abort",s),a(e))}},s=()=>{(e=>{h=h.filter(t=>t!=e),queueMicrotask(()=>{!h.length&&l&&k()})})(r),r.settle(!1)};h.push(r),t?.aborted?s():t?.addEventListener("abort",s,{once:!0}),n.then(r.settle,()=>r.settle(!1))}):Promise.resolve(!1)},M=()=>f==s.ready&&!!a&&!!o;return{load:async({model:e,limits:t,assets:n,logging:i,signal:m,onProgress:f})=>{if(m?.aborted)return!1;if(M()&&o?.id==e.id)return!0;if(l&&g==e.id)return f(y.percent,y.phase),await _(f,m);l&&(k(),h=[],await l.catch(()=>!1));const C=++w,T=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const l=b(e);if(C!=w)return!1;if(!l)return v(s.unsupported),!1;if(await(async(e,t)=>{if(o&&o.id!=e.id){const e=o,t=r,n=a;a=void 0,o=void 0,r=void 0,await(n?.unload()),await(t?.remove(e))}if(await t.hasCache())for(const n of d)n.id!=e.id&&b(n)==t&&await t.remove(n)})(e,l),C!=w)return!1;const g=await l.cached(e);if(C!=w)return!1;if(!g&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await l.purge(),C!=w)return!1;v(s.downloading),x(0,c.download),g&&x(1,c.load);const m=new AbortController;u=m;try{const d=await l.startLLM({model:e,limits:t,logging:i,signal:m.signal,assets:n,onProgress:(e,t)=>{C==w&&x(e,t)}});return C!=w||m.signal.aborted?(await d.unload(),!1):(a=d,o=e,r=l,p=l.backend,v(s.ready),x(1,c.load),!0)}catch(e){return C!=w||(a=void 0,o=void 0,r=void 0,i&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await l.purge(),v(s.error)),!1}finally{u==m&&(u=void 0)}})().finally(()=>{l==T&&(l=void 0,g=void 0,h=[])});return l=T,g=e.id,await _(f,m)},chat:async e=>{if(!M()||!a)return;for(;m;)await m.catch(()=>{});if(!M()||!a)return;const t=a.chat(e);m=t;try{return await t}finally{m==t&&(m=void 0)}},unload:async()=>{const e=a;k(),a=void 0,o=void 0,r=void 0,v(s.idle),await(e?.unload())},ready:M,loading:()=>!M()&&f==s.downloading,status:()=>f,backend:()=>p,model:()=>o}})(),te=(e,t,n)=>{const a=e.status(),o=g(t);return{availability:a==s.ready?r.online:a==s.error||a==s.unsupported?r.offline:r.away,status:a,backend:e.backend(),supportsImages:!!o&&u(o),ready:e.ready(),loading:e.loading(),requesting:n.requesting,phase:n.phase,percent:n.percent,...n.error?{error:n.error}:{}}},ne=(e=>{let t,n=0;const a=t=>t.input.onStatus?.(te(e,t.input.model,t));return r=>{t?.controller.abort();const i={token:++n,input:r,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?c.load:c.download,requesting:!1,cancelled:!1};return t=i,a(i),(async t=>{const{input:r}=t,s=!0===r.logging,i=g(r.model),l=r.messages.some(e=>e.role!=o.system&&"string"==typeof e.content&&!!e.content.trim()),d=r.messages.some(e=>e.role==o.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),m=l||d;if(!i)return t.error="Unknown model",void a(t);if(!m)return void a(t);if(d&&!l&&!u(i))return t.error="Model does not accept images",void a(t);const p=v(r.limits),f=await e.load({model:i,limits:p,logging:s,signal:t.controller.signal,onProgress:(e,o)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=o,a(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(t.cancelled)return;if(!f)return t.error||(t.error="Model not ready"),void a(t);const h=u(i),w=d&&!h?r.messages.map(({images:e,...t})=>t):r.messages;if(d&&!h&&!l)return t.error="Model does not accept images",void a(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=c.load,a(t);let y,b="",x="";try{y=await e.chat({messages:w,limits:p,reasoning:!0===r.reasoning,logging:s,onReason:e=>{t.token!=n||t.cancelled||(b+=e,r.onThinking?.(b))},onText:e=>{t.token!=n||t.cancelled||(x+=e,r.onResponse?.(x))},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void a(t)}t.token==n&&(t.requesting=!1,y||t.cancelled||(t.error="No reply"),a(t))})(i),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=s.ready?queueMicrotask(()=>a(t)):e.unload().then(()=>a(t)))})(i)}})(ee),ae=(oe=ee,async e=>{const t=g(e.model),n=t=>e.onStatus?.(te(oe,e.model,t));if(!t)return n({requesting:!1,phase:c.download,percent:0,error:"Unknown model"}),!1;let a,o=0,r=c.download;const s=oe.ready()&&oe.model()?.id==t.id;return await oe.load({model:t,limits:v(e.limits),logging:!0===e.logging,onProgress:(e,t)=>{o=Math.round(100*e),r=t,n({requesting:!1,phase:r,percent:o})}}).catch(e=>(a=`${e?.message||`${e}`}`,!1))?(s&&n({requesting:!1,phase:c.load,percent:100}),!0):(n({requesting:!1,phase:r,percent:o,error:a||"Model not ready"}),!1)});var oe;module.exports=a})();
|
|
2
|
+
(()=>{"use strict";var e={};const t={};function a(n){const o=t[n];if(void 0!==o)return o.exports;const r=t[n]={exports:{}};return e[n](r,r.exports,a),r.exports}a.m=e,a.d=(e,t)=>{for(var n in t)a.o(t,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},a.f={},a.e=e=>{const t=[];return a.f.require(e,t),Promise.all(t)},a.u=e=>({520:"engine-litert",924:"engine-wllama"}[e]+".node.min.js"),a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={792:1};a.f.require=(t,n)=>{if(!e[t]){const n=require("./"+a.u(t));e[t]||(t=>{const n=t.modules,o=t.ids,r=t.runtime;for(var i in n)a.o(n,i)&&(a.m[i]=n[i]);r&&r(a);for(var s=0;s<o.length;s++)e[o[s]]=1})(n)}}})();let n={};var o,r,i,s,c,l;a.r(n),a.d(n,{ChatModelId:()=>l,ChatStatus:()=>r,LlmBackend:()=>s,LlmPhase:()=>c,LlmRole:()=>o,LlmStatus:()=>i,createChat:()=>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})();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see chat.node.min.mjs.LICENSE.txt */
|
|
2
|
-
import{dirname as e,join as t}from"node:path";import{fileURLToPath as n}from"node:url";var a={};const o={};function r(e){const t=o[e];if(void 0!==t)return t.exports;const n=o[e]={exports:{}};return a[e](n,n.exports,r),n.exports}var s,i,c,l,d,g;r.m=a,r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.f={},r.e=e=>{const t=[];return r.f.j(e,t),Promise.all(t)},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{const e={520:()=>import("./engine-litert.node.min.mjs"),924:()=>import("./engine-wllama.node.min.mjs")},t={792:0},n=e=>{let{__webpack_esm_ids__:n,__webpack_esm_modules__:a,__webpack_esm_runtime__:o}=e;var s,i,c=0;for(s in a)r.o(a,s)&&(r.m[s]=a[s]);for(o&&o(r);c<n.length;c++)i=n[c],r.o(t,i)&&t[i]&&t[i][0](),t[i]=0};r.f.j=(a,o)=>{let s=r.o(t,a)?t[a]:void 0;if(0!==s)if(s)o.push(s[1]);else{let r=e[a]().then(n,e=>{throw 0!==t[a]&&(t[a]=void 0),e});r=Promise.race([r,new Promise(e=>s=t[a]=[e])]),o.push(s[1]=r)}}})(),function(e){e.system="system",e.user="user",e.assistant="assistant"}(s||(s={})),function(e){e[e.online=0]="online",e[e.away=1]="away",e[e.offline=2]="offline"}(i||(i={})),function(e){e[e.idle=0]="idle",e[e.downloading=1]="downloading",e[e.ready=2]="ready",e[e.error=3]="error",e[e.unsupported=4]="unsupported"}(c||(c={})),function(e){e.cpu="cpu",e.gpu="gpu",e.none="none"}(l||(l={})),function(e){e.download="download",e.load="load"}(d||(d={})),function(e){e.qwen3_vl_2b="qwen3-vl-2b",e.gemma4_e2b="gemma4-e2b"}(g||(g={}));const m=[{id:g.qwen3_vl_2b,reasoning:!0,cpu:{repo:"Qwen/Qwen3-VL-2B-Thinking-GGUF",file:"Qwen3VL-2B-Thinking-Q4_K_M.gguf",mmproj:{file:"mmproj-Qwen3VL-2B-Thinking-Q8_0.gguf"}}},{id:g.gemma4_e2b,reasoning:!0,litert:{repo:"litert-community/gemma-4-E2B-it-litert-lm",file:"gemma-4-E2B-it.litertlm",vision:!0}}],u=e=>e?m.find(t=>t.id==e):void 0,p=e=>!!e.cpu?.mmproj||!!e.litert?.vision,f=()=>{return a=t(e(n("file:///media/x/store/code/DegreeSign/ds_chat/src/assets/nodeEsm.js")),"../assets/wllama"),{wasm:t(a,"wllama.wasm"),compatWasm:t(a,"compat/wllama.wasm"),compatWorker:t(a,"compat/wllama.js")};var a},h=()=>{return a=t(e(n("file:///media/x/store/code/DegreeSign/ds_chat/src/assets/nodeEsm.js")),"../assets/litert"),{script:t(a,"litertlm_wasm_internal.js"),wasm:t(a,"litertlm_wasm_internal.wasm")};var a},w=288,y=async e=>{if(!e.startsWith("data:"))return await(await fetch(e)).arrayBuffer();const t=e.indexOf(","),n=t>=0?e.slice(0,t):"";if(t<0)throw new Error("Invalid image data");if(!n.includes(";base64"))return await(await fetch(e)).arrayBuffer();const a=atob(e.slice(t+1)),o=new Uint8Array(a.length);for(let e=0;e<a.length;e++)o[e]=a.charCodeAt(e);return o.buffer},b=async e=>{if(!e||"function"!=typeof fetch||"function"!=typeof createImageBitmap)return e;try{const t=await fetch(e),n=await createImageBitmap(await t.blob()),a=Math.min(n.width,n.height),o=Math.floor((n.width-a)/2),r=Math.floor((n.height-a)/2),s=((e,t)=>{if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(e,t);if("undefined"==typeof document)return;const n=document.createElement("canvas");return n.width=e,n.height=t,n})(w,w),i=s?s.getContext("2d"):null;if(!s||!i||a<1)return n.close(),e;if(i.drawImage(n,o,r,a,a,0,0,w,w),n.close(),(e=>"undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)(s)){const t=await s.convertToBlob({type:"image/jpeg",quality:.85});return await(e=>new Promise(t=>{if("undefined"==typeof FileReader)return void t("");const n=new FileReader;n.onerror=()=>t(""),n.onload=()=>t(`${n.result}`),n.readAsDataURL(e)}))(t)||e}return s.toDataURL("image/jpeg",.85)}catch{return e}},x={maxReplyTokens:200,maxThinkingTokens:64,maxReasoningTokens:150,maxImages:2,maxContentLength:1e3,promptCharBudget:1e4,maxThreads:2},k=(e,t,n)=>"number"==typeof e&&Number.isFinite(e)&&e>=n?Math.floor(e):t,v=(e={})=>{const t=x;return{maxReplyTokens:k(e.maxReplyTokens,t.maxReplyTokens,1),maxThinkingTokens:k(e.maxThinkingTokens,t.maxThinkingTokens,1),maxReasoningTokens:k(e.maxReasoningTokens,t.maxReasoningTokens,1),maxImages:k(e.maxImages,t.maxImages,0),maxContentLength:k(e.maxContentLength,t.maxContentLength,1),promptCharBudget:k(e.promptCharBudget,t.promptCharBudget,1),maxThreads:k(e.maxThreads,t.maxThreads,1)}},_=(e,t)=>({stream:!0,temperature:.7,max_tokens:t?e.maxReasoningTokens:e.maxReplyTokens}),M=(e,t)=>`https://huggingface.co/${e}/resolve/main/${t}`,T=e=>e.some(e=>Array.isArray(e.content)&&e.content.some(e=>"image"==e.type)),C=["<|channel>thought\n","<|channel>thought","..."],L=["<channel|>","..."],E=(e,t)=>t.length?[...e?[{type:"text",text:e}]:[],...t.map(e=>({type:"image",url:e}))]:e,j=e=>"string"==typeof e?e?[{type:"text",text:e}]:[]:e,R=(e,t)=>{if("string"==typeof e&&"string"==typeof t)return`${e}\n${t}`;const n=[];for(const a of[...j(e),{type:"text",text:"\n"},...j(t)]){const e=n[n.length-1];"text"==a.type&&"text"==e?.type?e.text+=a.text:n.push(a)}return n},q=async({model:e,logging:t,onReason:n,onText:a,start:o,stopped:r})=>{let s="",i="",c="";const l=((e,t)=>{let n="",a=!1;const o=(e,t)=>{let n=-1,a="";for(const o of t){const t=e.indexOf(o);t>=0&&(n<0||t<n)&&(n=t,a=o)}return{at:n,tag:a}},r=(e,t)=>{let n="";for(const a of t)for(let t=Math.min(e.length,a.length-1);t>n.length;t--)if(e.endsWith(a.slice(0,t))){n=e.slice(e.length-t);break}return n};return{feed:s=>{let i=n+s;for(n="";i;){if(a){const{at:t,tag:s}=o(i,L);if(t>=0){t&&e(i.slice(0,t)),i=i.slice(t+s.length),a=!1;continue}const c=r(i,L);e(i.slice(0,i.length-c.length)),n=c;break}{const{at:e,tag:s}=o(i,C);if(e>=0){e&&t(i.slice(0,e)),i=i.slice(e+s.length),i.startsWith("\n")&&(i=i.slice(1)),a=!0;continue}const c=r(i,C);t(i.slice(0,i.length-c.length)),n=c;break}}},flush:()=>{n&&(a?e(n):t(n),n="")}}})(e=>{i+=e,n(e)},e=>{s+=e,a(e)});try{const e=await o();for await(const t of e){if(r())break;const e=t?.choices?.[0],a=e?.delta,o="string"==typeof a?.reasoning_content?a.reasoning_content:"string"==typeof a?.reasoning?a.reasoning:"";e?.finish_reason&&(c=e.finish_reason),o&&(i+=o,n(o)),a?.content&&l.feed(a.content)}l.flush()}catch(e){t&&console.log("Local chat failed",e)}const d=r()?void 0:s||void 0;return t&&(console.log("Local chat reply",e.id,d?"****":""),console.log("Local chat finish",e.id,c||"none",s.length,i.length)),d},P=async({model:e,params:t,start:n,stopped:a})=>{const o=await(async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push(n);continue}const e=[];for(const t of n.content)e.push("image"==t.type?{type:"image",url:await b(t.url)}:t);t.push({role:"user",content:e})}return t})(((e,t=x)=>{const n=t.maxContentLength,a=e.filter(e=>"string"==typeof e.content&&!!e.content.trim()||!(e.role!=s.user||!e.images?.length)),o=[],r=[];let i=0,c=t.maxImages;for(let e=a.length-1;e>=0;e--){const l=a[e],d=("string"==typeof l.content?l.content:"").slice(0,n),g=l.role==s.user?(l.images||[]).filter(e=>"string"==typeof e&&!!e).slice(0,Math.max(0,c)):[];if(d||g.length){if(d&&i+d.length>t.promptCharBudget)break;i+=d.length,c-=g.length,l.role==s.system?o.unshift(d):l.role==s.assistant?r.unshift({role:"assistant",content:d}):r.unshift({role:"user",content:E(d,g)})}}for(;r.length&&"user"!=r[0].role;)r.shift();const l=[];for(const e of r){const t=l[l.length-1];"assistant"==t?.role&&"assistant"==e.role?t.content=`${t.content}\n${e.content}`:"user"==t?.role&&"user"==e.role?t.content=R(t.content,e.content):"assistant"==e.role?l.push({role:"assistant",content:e.content}):l.push({role:"user",content:e.content})}const d=o.join("\n\n"),g=[];return d&&g.push({role:"system",content:d}),g.push(...l),g})(t.messages,t.limits));return t.logging&&((e,t)=>{console.log("Local chat call",e.id,t.map(({role:e,content:t})=>({role:e,content:"****",...Array.isArray(t)?{images:t.filter(e=>"image"==e.type).length}:{}})))})(e,o),await q({model:e,logging:t.logging,onReason:t.onReason,onText:t.onText,start:()=>n(o),stopped:a})},W="litertlm-models",$={num_output_candidates:1,wait_for_weight_uploads:!0,num_decode_steps_per_sync:3,sequence_batch_size:0,supported_lora_ranks:[],max_top_k:40,enable_decode_logits:!1,enable_external_embeddings:!1,use_submodel:!1,use_autosized_ringbuffers:!0},B=async()=>{try{if("undefined"==typeof caches)return;return await caches.open(W)}catch{return}},I=new Map,O=e=>Number(e.headers.get("content-length"))||0,A=(e,t,n)=>{let a=0;return e.pipeThrough(new TransformStream({transform:(e,o)=>{a+=e.byteLength,n(t?a/t:0,d.download),o.enqueue(e)}}))},S=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){t.push({role:n.role,content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await y(t.url)});t.push({role:"user",content:e})}return t},U=async({engine:e,model:t,mod:n,params:a})=>await P({model:t,params:a,stopped:()=>!!a.signal?.aborted,start:async o=>{if(a.signal?.aborted)throw new Error("Cancelled");if(T(o)&&!t.litert?.vision)throw new Error("Model does not accept images");return async function*({engine:e,mod:t,params:n,messages:a}){const o=a[a.length-1],r=_(n.limits,n.reasoning);if("user"!=o?.role)throw new Error("No user turn");const s=await S(a.slice(0,-1)),i=(await S([o]))[0];if(!i)throw new Error("Empty prompt");const c=await e.createConversation({sessionConfig:{maxOutputTokens:r.max_tokens,samplerParams:{type:t.SamplerType.TOP_K,temperature:r.temperature,k:40,p:.95}},preface:{...s.length?{messages:s}:{},extra_context:{enable_thinking:n.reasoning}}});let l;const d=()=>{l&&l.cancel().catch(()=>{});try{c.cancel()}catch{}};n.signal?.addEventListener("abort",d,{once:!0});try{if(n.signal?.aborted)return;const e=c.sendMessageStreaming(i).getReader();for(l=e;;){const{done:t,value:n}=await e.read();if(t)break;const a={};let o="string"==typeof n.content?n.content:"";if(Array.isArray(n.content))for(const e of n.content)"text"==e.type&&(o+=e.text);o&&(a.content=o);const r=n.channels?.thought;r&&(a.reasoning=r),(a.content||a.reasoning)&&(yield{choices:[{delta:a}]})}}finally{n.signal?.removeEventListener("abort",d);try{await c.delete()}catch{}}}({engine:e,mod:n,params:a,messages:o})}}),F={backend:l.gpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o})=>{const s=e.litert;if(!s)throw new Error("Model has no LiteRT artifact");const i=await r.e(520).then(()=>r(507));if(await i.getOrLoadGlobalLiteRtLm(h().script),a?.aborted)throw new Error("Cancelled");const c=M(s.repo,s.file),g=await B();let m;if(g){if(!await g.match(c))try{await(async(e,t,n,a)=>{const o=I.get(e);if(o)return await o;const r=(async()=>{const o=await fetch(e,{signal:n});if(!o.ok||!o.body)throw new Error("Model download failed");const r=O(o),s=A(o.body,r,a);await t.put(e,new Response(s,{headers:{"content-type":"application/octet-stream",...r?{"content-length":`${r}`}:{}}}))})().finally(()=>{I.delete(e)});return I.set(e,r),await r})(c,g,a,n)}catch(e){if(a?.aborted)throw new Error("Cancelled");o&&console.log("Local model cache failed",e)}const e=await g.match(c);e?.body&&(m=e.body)}if(m||(m=await(async(e,t,n)=>{const a=await fetch(e,{signal:t});if(!a.ok||!a.body)throw new Error("Model download failed");return A(a.body,O(a),n)})(c,a,n)),a?.aborted)throw new Error("Cancelled");n(1,d.load);const u=await i.Engine.create({model:m,mainExecutorSettings:{maxNumTokens:4096,...s.vision?{maxNumImages:Math.max(1,t.maxImages)}:{},backendConfig:$},...s.vision?{visionBackend:i.Backend.GPU}:{}});if(a?.aborted)throw await u.delete(),new Error("Cancelled");return{model:e,backend:l.gpu,contextSize:4096,chat:t=>U({engine:u,model:e,mod:i,params:t}),unload:async()=>{await u.delete()}}},cached:async e=>{try{const t=e.litert,n=await B();return!(!t||!n)&&!!await n.match(M(t.repo,t.file))}catch{return!1}},hasCache:async()=>{try{const e=await B();return!!e&&(await e.keys()).length>0}catch{return!1}},remove:async e=>{try{const t=e.litert,n=await B();if(!t||!n)return;await n.delete(M(t.repo,t.file))}catch{}},purge:async()=>{try{"undefined"!=typeof caches&&await caches.delete(W)}catch{}}};let N,Q,D="",z=!1;const G=e=>`${e.wasm}|${e.compatWasm}|${e.compatWorker}`,V=e=>{const t=f();return{wasm:e?.wasm||t.wasm,compatWasm:e?.compatWasm||t.compatWasm,compatWorker:e?.compatWorker||t.compatWorker}},K=e=>{const t=e=>(...t)=>{z&&("string"==typeof t[0]&&t[0].includes("ggml_webgpu: Failed to get an adapter")||e(...t))};return{...e,log:t(e.log),warn:t(e.warn),error:t(e.error)}},H=async()=>{if(N)return N;const e=await r.e(924).then(()=>r(577)),t=Q||V(),n=new e.Wllama({default:t.wasm},{logger:K(e.LoggerWithoutDebug)});return Q||(Q=t,D=G(t)),n.setCompat({wasm:t.compatWasm,worker:t.compatWorker}),N=n,n},J=async()=>{const e=N;N=void 0;try{await(e?.exit())}catch{}},X=(e,t)=>e.name.includes(t)||!!e.metadata?.originalURL?.includes(t),Y=e=>e.cpu?[e.cpu.file,...e.cpu.mmproj?[e.cpu.mmproj.file]:[]]:[],Z=async e=>{const t=[];for(const n of e){if("string"==typeof n.content){"system"==n.role?t.push({role:"system",content:n.content}):"assistant"==n.role?t.push({role:"assistant",content:n.content}):t.push({role:"user",content:n.content});continue}const e=[];for(const t of n.content)e.push("text"==t.type?{type:"text",text:t.text}:{type:"image",data:await y(t.url)});t.push({role:"user",content:e})}return t},ee={backend:l.cpu,startLLM:async({model:e,limits:t,onProgress:n,signal:a,logging:o,assets:r})=>{z=!0===o;const s=e.cpu;if(!s)throw new Error("Model has no CPU artifact");const i=V(r),c=G(i);N&&c!=D&&await J(),Q=i,D=c;const g=(m="undefined"!=typeof navigator&&navigator.hardwareConcurrency||4,u=t.maxThreads,Math.max(1,Math.min(Math.max(2,Math.min(8,(m||4)-1)),u)));var m,u;const p=await H(),f=M(s.repo,s.file),h=s.mmproj?.file,w=h?M(s.repo,h):"";if(a?.aborted)throw await J(),new Error("Cancelled");if(h){const e=await p.cacheManager.list(),t=e.some(e=>X(e,s.file)),n=e.some(e=>X(e,h));t&&!n&&await p.cacheManager.deleteMany(e=>X(e,s.file))}try{await p.loadModelFromUrl(w?{url:f,mmprojUrl:w}:f,{n_ctx:8192,n_threads:g,reasoning_budget_tokens:t.maxThinkingTokens,n_gpu_layers:0,useCache:!0,jinja:!0,signal:a,progressCallback:({loaded:e,total:t})=>{const a=t?e/t:0;n(a,a>=1?d.load:d.download)}})}catch(e){throw await J(),e}if(a?.aborted)throw await J(),new Error("Cancelled");if(!p.getLoadedContextInfo().n_ctx)throw await J(),new Error("Failed to create model context");return{model:e,backend:l.cpu,contextSize:8192,chat:t=>(async(e,t,n)=>{if(z=!0===n.logging,e.isModelLoaded())return await P({model:t,params:n,stopped:()=>!!n.signal?.aborted,start:async a=>{if(T(a)&&!e.supportInputModality("image"))throw new Error("Model does not accept images");return await e.createChatCompletion({messages:await Z(a),..._(n.limits,n.reasoning),abortSignal:n.signal,...t.reasoning?{chat_template_kwargs:{enable_thinking:n.reasoning}}:{}})}})})(p,e,t),unload:async()=>{if(N==p)await J();else try{await p.exit()}catch{}}}},cached:async e=>{try{if(!e.cpu)return!1;const t=await H(),n=await t.cacheManager.list();return Y(e).every(e=>n.some(t=>X(t,e)))}catch{return!1}},hasCache:async()=>{try{const e=await H();return(await e.cacheManager.list()).length>0}catch{return!1}},remove:async e=>{try{if(!e.cpu)return;const t=await H();await t.cacheManager.deleteMany(t=>Y(e).some(e=>X(t,e)))}catch{}},purge:async()=>{try{const e=await H();await e.cacheManager.clear()}catch{}}},te=((e={})=>{const t=e.engines?.cpu||ee,n=e.engines?.litert||F;let a,o,r,s,i,g,u,p=l.none,f=c.idle,h=[],w=0,y={percent:0,phase:d.download};const b=a=>{if(e.backend!=l.none)return e.backend==l.cpu?a.cpu?t:void 0:e.backend==l.gpu?a.litert?n:void 0:a.litert&&"undefined"!=typeof navigator&&navigator.gpu&&"undefined"!=typeof WebAssembly?n:!a.cpu||"undefined"==typeof window&&"undefined"==typeof self&&"undefined"==typeof Worker||"undefined"==typeof WebAssembly?void 0:t},x=(e,t)=>{y={percent:Math.max(0,Math.min(1,e)),phase:t||d.download};for(const e of[...h])e.report(y.percent,y.phase)},k=e=>{f=e},v=()=>{w++,g?.abort(),g=void 0,i=void 0,f==c.downloading&&k(c.idle)},_=(e,t)=>{const n=s;return n?new Promise(a=>{let o=!1;const r={report:e,settle:e=>{o||(o=!0,t?.removeEventListener("abort",i),a(e))}},i=()=>{(e=>{h=h.filter(t=>t!=e),queueMicrotask(()=>{!h.length&&s&&v()})})(r),r.settle(!1)};h.push(r),t?.aborted?i():t?.addEventListener("abort",i,{once:!0}),n.then(r.settle,()=>r.settle(!1))}):Promise.resolve(!1)},M=()=>f==c.ready&&!!a&&!!o;return{load:async({model:e,limits:t,assets:n,logging:l,signal:u,onProgress:f})=>{if(u?.aborted)return!1;if(M()&&o?.id==e.id)return!0;if(s&&i==e.id)return f(y.percent,y.phase),await _(f,u);s&&(v(),h=[],await s.catch(()=>!1));const T=++w,C=(async()=>{await(async()=>{try{if("undefined"==typeof navigator)return;await(navigator.storage?.persist?.())}catch{}})();const s=b(e);if(T!=w)return!1;if(!s)return k(c.unsupported),!1;if(await(async(e,t)=>{if(o&&o.id!=e.id){const e=o,t=r,n=a;a=void 0,o=void 0,r=void 0,await(n?.unload()),await(t?.remove(e))}if(await t.hasCache())for(const n of m)n.id!=e.id&&b(n)==t&&await t.remove(n)})(e,s),T!=w)return!1;const i=await s.cached(e);if(T!=w)return!1;if(!i&&await(async()=>{try{if("undefined"==typeof navigator)return!1;if(!navigator.storage?.estimate)return!1;const{quota:e=0,usage:t=0}=await navigator.storage.estimate();return!!e&&t>=e}catch{return!1}})()&&await s.purge(),T!=w)return!1;k(c.downloading),x(0,d.download),i&&x(1,d.load);const u=new AbortController;g=u;try{const i=await s.startLLM({model:e,limits:t,logging:l,signal:u.signal,assets:n,onProgress:(e,t)=>{T==w&&x(e,t)}});return T!=w||u.signal.aborted?(await i.unload(),!1):(a=i,o=e,r=s,p=s.backend,k(c.ready),x(1,d.load),!0)}catch(e){return T!=w||(a=void 0,o=void 0,r=void 0,l&&console.log("Local model failed",e),(e=>["quota","no space","disk full","ns_error_dom_quota_reached"].some(t=>`${e?.name||""} ${e?.message||`${e}`}`.toLowerCase().includes(t)))(e)&&await s.purge(),k(c.error)),!1}finally{g==u&&(g=void 0)}})().finally(()=>{s==C&&(s=void 0,i=void 0,h=[])});return s=C,i=e.id,await _(f,u)},chat:async e=>{if(!M()||!a)return;for(;u;)await u.catch(()=>{});if(!M()||!a)return;const t=a.chat(e);u=t;try{return await t}finally{u==t&&(u=void 0)}},unload:async()=>{const e=a;v(),a=void 0,o=void 0,r=void 0,k(c.idle),await(e?.unload())},ready:M,loading:()=>!M()&&f==c.downloading,status:()=>f,backend:()=>p,model:()=>o}})(),ne=(e,t,n)=>{const a=e.status(),o=u(t);return{availability:a==c.ready?i.online:a==c.error||a==c.unsupported?i.offline:i.away,status:a,backend:e.backend(),supportsImages:!!o&&p(o),ready:e.ready(),loading:e.loading(),requesting:n.requesting,phase:n.phase,percent:n.percent,...n.error?{error:n.error}:{}}},ae=(e=>{let t,n=0;const a=t=>t.input.onStatus?.(ne(e,t.input.model,t));return o=>{t?.controller.abort();const r={token:++n,input:o,controller:new AbortController,percent:e.ready()?100:0,phase:e.ready()?d.load:d.download,requesting:!1,cancelled:!1};return t=r,a(r),(async t=>{const{input:o}=t,r=!0===o.logging,i=u(o.model),c=o.messages.some(e=>e.role!=s.system&&"string"==typeof e.content&&!!e.content.trim()),l=o.messages.some(e=>e.role==s.user&&!!e.images?.some(e=>"string"==typeof e&&!!e)),g=c||l;if(!i)return t.error="Unknown model",void a(t);if(!g)return void a(t);if(l&&!c&&!p(i))return t.error="Model does not accept images",void a(t);const m=v(o.limits),f=await e.load({model:i,limits:m,logging:r,signal:t.controller.signal,onProgress:(e,o)=>{t.token==n&&(t.percent=Math.round(100*e),t.phase=o,a(t))}}).catch(e=>(t.token==n&&(t.error=`${e?.message||`${e}`}`),!1));if(t.token!=n)return;if(t.cancelled)return;if(!f)return t.error||(t.error="Model not ready"),void a(t);const h=p(i),w=l&&!h?o.messages.map(({images:e,...t})=>t):o.messages;if(l&&!h&&!c)return t.error="Model does not accept images",void a(t);t.requesting=!0,t.error=void 0,t.percent=100,t.phase=d.load,a(t);let y,b="",x="";try{y=await e.chat({messages:w,limits:m,reasoning:!0===o.reasoning,logging:r,onReason:e=>{t.token!=n||t.cancelled||(b+=e,o.onThinking?.(b))},onText:e=>{t.token!=n||t.cancelled||(x+=e,o.onResponse?.(x))},signal:t.controller.signal})}catch(e){if(t.token!=n)return;return t.requesting=!1,t.error=`${e?.message||`${e}`}`,void a(t)}t.token==n&&(t.requesting=!1,y||t.cancelled||(t.error="No reply"),a(t))})(r),()=>(t=>{t.token==n&&(t.cancelled=!0,t.controller.abort(),e.status()!=c.ready?queueMicrotask(()=>a(t)):e.unload().then(()=>a(t)))})(r)}})(te),oe=(re=te,async e=>{const t=u(e.model),n=t=>e.onStatus?.(ne(re,e.model,t));if(!t)return n({requesting:!1,phase:d.download,percent:0,error:"Unknown model"}),!1;let a,o=0,r=d.download;const s=re.ready()&&re.model()?.id==t.id;return await re.load({model:t,limits:v(e.limits),logging:!0===e.logging,onProgress:(e,t)=>{o=Math.round(100*e),r=t,n({requesting:!1,phase:r,percent:o})}}).catch(e=>(a=`${e?.message||`${e}`}`,!1))?(s&&n({requesting:!1,phase:d.load,percent:100}),!0):(n({requesting:!1,phase:r,percent:o,error:a||"Model not ready"}),!1)});var re;export{g as ChatModelId,i as ChatStatus,l as LlmBackend,d as LlmPhase,s as LlmRole,c as LlmStatus,ae as createChat,oe as preloadModel};
|
|
2
|
+
import{dirname as e,join as t}from"node:path";import{fileURLToPath as a}from"node:url";var n={};const o={};function r(e){const t=o[e];if(void 0!==t)return t.exports;const a=o[e]={exports:{}};return n[e](a,a.exports,r),a.exports}var 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};
|
package/dist/types.d.ts
CHANGED
|
@@ -150,6 +150,50 @@ interface RuntimeLoadWaiter {
|
|
|
150
150
|
/** Resolve this caller, early when it leaves the load */
|
|
151
151
|
settle: (loaded: boolean) => void;
|
|
152
152
|
}
|
|
153
|
+
/** Bytes of one model file already stored on disk */
|
|
154
|
+
interface StoredPart {
|
|
155
|
+
/** Bytes already stored */
|
|
156
|
+
size: number;
|
|
157
|
+
/** Full file size, zero while unknown */
|
|
158
|
+
total: number;
|
|
159
|
+
/** Entity tag of the stored bytes, empty when the host hides it */
|
|
160
|
+
etag: string;
|
|
161
|
+
}
|
|
162
|
+
/** One part file of a model, at its byte offset */
|
|
163
|
+
interface StoredFilePart {
|
|
164
|
+
/** Byte offset of the part in the model file */
|
|
165
|
+
start: number;
|
|
166
|
+
/** Bytes stored in the part */
|
|
167
|
+
size: number;
|
|
168
|
+
}
|
|
169
|
+
/** One stored model file, complete or still downloading */
|
|
170
|
+
interface StoredModel extends StoredPart {
|
|
171
|
+
/** The stored bytes, a snapshot of the parts on disk */
|
|
172
|
+
file: Blob;
|
|
173
|
+
/** Whether every byte of the total is stored */
|
|
174
|
+
complete: boolean;
|
|
175
|
+
}
|
|
176
|
+
/** Download metadata kept beside one stored model file */
|
|
177
|
+
interface StoredModelMeta {
|
|
178
|
+
total: number;
|
|
179
|
+
etag: string;
|
|
180
|
+
complete: boolean;
|
|
181
|
+
}
|
|
182
|
+
/** Where one response continues a stored part */
|
|
183
|
+
interface ResumePlan {
|
|
184
|
+
/** Byte the response body starts at */
|
|
185
|
+
start: number;
|
|
186
|
+
/** Full file size, zero while unknown */
|
|
187
|
+
total: number;
|
|
188
|
+
etag: string;
|
|
189
|
+
}
|
|
190
|
+
/** One model file download into the store */
|
|
191
|
+
interface StoreDownloadParams {
|
|
192
|
+
url: string;
|
|
193
|
+
/** Stop the download, the bytes stored so far are kept */
|
|
194
|
+
signal?: AbortSignal;
|
|
195
|
+
onProgress: StartLlmParams[`onProgress`];
|
|
196
|
+
}
|
|
153
197
|
/** One generation request */
|
|
154
198
|
interface RuntimeChatParams {
|
|
155
199
|
messages: ChatMessage[];
|
|
@@ -325,4 +369,4 @@ interface EngineRunParams {
|
|
|
325
369
|
/** Whether the caller stopped the generation */
|
|
326
370
|
stopped: () => boolean;
|
|
327
371
|
}
|
|
328
|
-
export type { ChatMessage, ChatModel, LlmLimits, ChatStatusSnapshot, ChatInput, ChatPreloadInput, ChatState, CancelChat, WllamaAssets, LitertAssets, GpuNavigator, ActiveCall, RuntimeDeps, RuntimeLoadParams, RuntimeLoadWaiter, RuntimeChatParams, Runtime, EngineChatParams, StartLlmParams, LlmRuntime, LlmEngine, EngineMessage, EngineContentPart, WllamaContentPart, WllamaMessage, LitertContentPart, LitertMessage, LitertEngine, LitertModule, LitertChatParams, StreamLitertParams, EngineDelta, EngineChunk, StreamReplyParams, EngineRunParams, };
|
|
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, };
|
package/package.json
CHANGED