@inkandswitch/patchwork-pkg-base 0.0.34 → 0.0.35

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.
@@ -0,0 +1,9 @@
1
+ (function(){"use strict";const le="https://cdn.jsdelivr.net/npm/@huggingface/transformers@4",ee=new Set;function M(e){for(const o of ee)try{o.postMessage(e)}catch{}}function ie(e){return(e/1048576).toFixed(0)+" MB"}function ge(){const e=self;if(e.__llmWeightsFetchPatched)return;e.__llmWeightsFetchPatched=!0;const o=self.fetch.bind(self),t=50*1024*1024;self.fetch=async(s,r)=>{const d=await o(s,r);try{const a=+(d.headers.get("content-length")||0),i=((d.url||(typeof s=="string"?s:s?.url||"")).split("?")[0].split("/").pop()||"").toLowerCase();if(d.ok&&d.body&&a>t&&!i.endsWith(".onnx"))return ke(d,a)}catch{}return d}}function ke(e,o){let t=0,s=-1;const r=e.body.getReader(),d=new ReadableStream({async pull(a){const{done:l,value:i}=await r.read();if(l){a.close();return}t+=i.byteLength;const n=o?Math.round(100*t/o):0;n!==s&&(s=n,M({type:"status",message:`Downloading model weights… ${n}% (${ie(t)} / ${ie(o)})`})),a.enqueue(i)},cancel(a){return r.cancel(a)}});return new Response(d,{status:e.status,statusText:e.statusText,headers:e.headers})}function L(...e){try{console.log("[llm worker]",...e)}catch{}M({type:"log",args:e.map(o=>{if(o==null||typeof o!="object")return o;try{return JSON.parse(JSON.stringify(o))}catch{return String(o)}})})}const F=new Map;self.addEventListener("error",e=>M({type:"status",message:"Worker error: "+(e.message||"")})),self.addEventListener("unhandledrejection",e=>M({type:"status",message:"Worker error: "+(e.reason?.message||e.reason||"")}));const ce=[{id:"LiquidAI/LFM2.5-2.6B-ONNX",name:"LFM2.5 2.6B",dtype:"q4f16"},{id:"onnx-community/Qwen3-4B-ONNX",name:"Qwen3 4B (best)",dtype:"q4f16"},{id:"onnx-community/Qwen3-1.7B-ONNX",name:"Qwen3 1.7B",dtype:"q4f16"},{id:"onnx-community/Qwen3-0.6B-ONNX",name:"Qwen3 0.6B (fast)",dtype:"q4f16"},{id:"onnx-community/Llama-3.2-1B-Instruct-ONNX",name:"Llama 3.2 1B",dtype:"q4f16"},{id:"onnx-community/Phi-3.5-mini-instruct-onnx-web",name:"Phi 3.5 Mini",dtype:"q4f16"},{id:"onnx-community/SmolLM2-1.7B-Instruct-ONNX",name:"SmolLM2 1.7B",dtype:"q4f16"}],G="onnx-community/Qwen3-0.6B-ONNX",te=256;let R=null,k=null,T=G,U=null,J=!1,X=null,B=null;function Q(e){const o=String(e&&(e.message||e)||"unknown error");return/bad_alloc|out of memory|can'?t create a session/i.test(o)?"Out of memory while loading this model. Big models can exceed the browser's WASM memory ceiling (~4GB — independent of your system RAM). Try a smaller model, or open in a normal (non-incognito) window so WebGPU can run it on the GPU instead. (raw: "+o+")":/memory access out of bounds|RuntimeError: Aborted/i.test(o)?"The WASM backend crashed running this model — usually an fp16 weight format (q4f16/fp16) the CPU backend can't execute, not a size problem. Use an integer quantization (q4/q8) for WASM, or open in a normal (non-incognito) window so WebGPU is available. (raw: "+o+")":/unaligned/i.test(o)?"The WASM backend hit an unaligned-access fault. Try a normal window so WebGPU is available, or a smaller model. (raw: "+o+")":/tensor shape is too large|failed to call OrtRun|op_kernel\.cc/i.test(o)?"The model produced a tensor too large for this backend during the forward pass. That usually means either a very long prompt, or a model that emits extra big outputs every step — e.g. an attention-export model (…-attn) meant for analysis/overlays, not chat generation. Use the standard (non-attention) model for chat, shorten the prompt, or open in a normal window for WebGPU. (raw: "+o+")":o}function we(e){switch(e){case"q4f16":return"q4";case"q8f16":return"q8";case"fp16":return"fp32";default:return e}}function E(){return B?"Model load failed: "+Q(B):"Model not loaded"}function K(){const e=k,o=T;return k=null,e?(async()=>{try{typeof e.dispose=="function"?await e.dispose():e.model&&typeof e.model.dispose=="function"&&await e.model.dispose(),L("releaseGenerator: disposed previous session",{model:o})}catch(t){L("releaseGenerator: dispose failed",{model:o,message:t?.message||String(t)})}})():Promise.resolve()}const de=new Set,oe=new Map;async function be(e){try{const o=await caches.open("transformers-cache"),t=await o.keys();let s=0;for(const r of t)r.url.includes(e+"/")&&(await o.delete(r),s++);s&&L("purged cached entries for local model",{id:e,n:s})}catch(o){L("purgeCachedModel failed",{id:e,message:o?.message||String(o)})}}function pe(){const e=self;if(e.__llmFetchPatched)return;e.__llmFetchPatched=!0;const o=self.fetch.bind(self);self.fetch=(t,s)=>{try{const r=typeof t=="string"?t:t?.url||"";for(const[d,a]of oe){const l="/"+d+"/resolve/",i=r.indexOf(l);if(i===-1)continue;const n=r.slice(i+l.length),p=n.substring(n.indexOf("/")+1),c=a.files.get(p)||a.files.get(p.split("/").pop()||"");return c?Promise.resolve(new Response(c,{status:200,headers:{"content-length":String(c.size)}})):(L("local model: 404",{id:d,rel:p,have:[...a.files.keys()]}),Promise.resolve(new Response("local model file not found: "+p,{status:404})))}}catch{}return o(t,s)}}function _e(e,o,t){return Promise.race([e,new Promise((s,r)=>setTimeout(()=>r(new Error(t+" timed out")),o))])}async function $(e,o){e=e||G;const t=o&&U&&o!==U;if(k&&(T!==e||t)&&(L("loadModel: switching model — releasing previous",{from:T,to:e,dtypeChanged:t}),await K()),k)return;if(J&&X)return X;T=e,J=!0;let s=()=>{};X=new Promise(c=>s=c),B=null;const r=oe.get(e);pe();const d=r?{dtype:r.dtype}:ce.find(c=>c.id===e)||{dtype:"q4f16"},a={...d,dtype:o||d.dtype};U=a.dtype,L("loadModel: start",{modelId:e,dtype:a.dtype});try{M({type:"status",message:"Loading transformers.js…"}),R=await import(le),R.env.allowLocalModels=!1,ge(),R.env.fetch=(c,f)=>self.fetch(c,f),R.env.useBrowserCache=!r,navigator.storage?.persist&&await navigator.storage.persist()}catch(c){B=c,console.error("[llm worker] failed to load transformers.js from",le,c),M({type:"status",message:"Failed to load transformers.js: "+(c?.message||c)}),J=!1,X=null,s();return}const l=!de.has(e);function i(c){const f=new Map;return u=>{if(u.status==="progress"&&u.progress!=null&&u.file){f.set(u.file,{loaded:u.loaded||0,total:u.total||0});const y=u.file.split("/").pop()||u.file;let m=0,w=0;for(const _ of f.values())m+=_.loaded,w+=_.total;const x=w>0?Math.round(100*m/w):Math.round(u.progress);M({type:"status",message:`Downloading ${y}… ${Math.round(u.progress)}% (overall ${x}%)`})}else u.status==="ready"&&M({type:"status",message:l?`⚠️ Compiling shaders for ${c} (first time — might freeze for a bit)…`:`Compiling shaders for ${c}…`})}}const n=typeof navigator<"u"&&!!navigator.gpu,p=[];n&&p.push({device:"webgpu",label:"WebGPU"}),p.push({device:void 0,label:"WASM"}),n||M({type:"status",message:"WebGPU unavailable (navigator.gpu missing — incognito or unsupported context); using WASM"}),L("loadModel: backends to try",{hasWebGPU:n,order:p.map(c=>c.label)});for(const c of p){const f=c.device?a.dtype:we(a.dtype);try{L("loadModel: trying backend",{backend:c.label,dtype:f,requested:a.dtype}),k=await _e(R.pipeline("text-generation",e,{dtype:f,device:c.device,progress_callback:i(c.label)}),18e4,c.label+" pipeline"),de.add(e),U=f;try{const u=k.model,y={},m=u?.sessions||{};for(const[w,x]of Object.entries(m)){const _=x?.outputNames||[];y[w]=_}M({type:"model-info",model:e,sessions:y,config:u?.config?{output_attentions:u.config.output_attentions,num_hidden_layers:u.config.num_hidden_layers,num_attention_heads:u.config.num_attention_heads,model_type:u.config.model_type}:null})}catch(u){M({type:"model-info",model:e,error:u.message})}L("loadModel: ready",{modelId:e,backend:c.label,dtype:a.dtype}),M({type:"status",message:`Model ready (${c.label})`}),M({type:"ready",model:e,device:c.label}),B=null;break}catch(u){B=u,L("loadModel: backend failed",{backend:c.label,modelId:e,message:u?.message||String(u)}),console.error(`[llm worker] ${c.label} load failed for ${e}:`,u),M({type:"status",message:`${c.label} failed: ${u?.message||u}`+(c.device?" — trying WASM…":"")})}}k||(L("loadModel: all backends failed",{modelId:e,message:B?.message||String(B)}),console.error(`[llm worker] all backends failed to load ${e}:`,B),M({type:"status",message:E()}),M({type:"load-error",model:e,message:E()})),J=!1,X=null,s()}function se(e,o,t){let s=-1/0;for(let l=0;l<o;l++)e[l]>s&&(s=e[l]);let r=0;const d=[],a=[];for(let l=0;l<o;l++){const i=e[l];if(r+=Math.exp(i-s),d.length<t)d.push(l),a.push(i);else{let n=0;for(let p=1;p<t;p++)a[p]<a[n]&&(n=p);i>a[n]&&(a[n]=i,d[n]=l)}}return d.map((l,i)=>({id:l,p:Math.exp(a[i]-s)/r})).sort((l,i)=>i.p-l.p)}function ne(e){if(e&&typeof e=="object")return e;if(typeof e!="string")return{};try{return JSON.parse(e)}catch{return{}}}function xe(e){const o={};return e.topK>0&&(o.top_k=e.topK),e.minP>0&&(o.min_p=e.minP),e.repetitionPenalty&&e.repetitionPenalty!==1&&(o.repetition_penalty=e.repetitionPenalty),e.frequencyPenalty&&(o.frequency_penalty=e.frequencyPenalty),e.presencePenalty&&(o.presence_penalty=e.presencePenalty),e.seed!=null&&e.seed!==""&&(o.seed=e.seed),o}function Me(e){let o="";for(const t of e){const s=typeof t.content=="string"?t.content:"";o+=`<|im_start|>${t.role||"user"}
2
+ ${s}<|im_end|>
3
+ `}return o+`<|im_start|>assistant
4
+ `}async function Te(e,o,t){const s=k.tokenizer,r=typeof o=="string",d=t.temperature??.7,a=t.topk|0,l=t.maxNewTokens??2048,i=!r&&!s.chat_template;let n=i?Me(o):o,p=!r&&t.tools?.length?t.tools:void 0;if(p&&s.chat_template){const g=s.apply_chat_template(n,{tools:p,tokenize:!1,add_generation_prompt:!0});let v=!1;for(const N of p){const q=N?.function?.name||N?.name;if(q&&g.includes(q)){v=!0;break}}if(!v){const N=t.toolSystem;N&&(n=[...n],n[0]?.role==="system"?n[0]={...n[0],content:[N,n[0].content].filter(Boolean).join(`
5
+
6
+ `)}:n.unshift({role:"system",content:N})),p=void 0}}i&&(L("doGenerateLocal: NO CHAT TEMPLATE — falling back to ChatML",{model:T,warning:"output will be garbage unless this model is ChatML-native; check that tokenizer_config.json / chat_template.jinja loaded"}),M({type:"status",message:`⚠️ ${T} has no chat template — using ChatML. Output may be garbage.`}));const c=i?["<|im_end|>","<|im_start|>"]:[];let f=0;try{const g=typeof n=="string"?n:s.apply_chat_template(n,{tokenize:!1,add_generation_prompt:!0,...p?{tools:p}:{}});f=s.encode(g).length}catch(g){L("doGenerateLocal: prompt build/encode failed (continuing)",{model:T,hasChatTemplate:!!s.chat_template,usedFallback:i,message:g?.message||String(g)})}const u=performance.now();let y=0,m="",w=null,x=!1,_=0;const O=new R.TextStreamer(s,{skip_prompt:!0,skip_special_tokens:!0,callback_function:g=>{if(x)return;y||(y=performance.now(),w&&(clearInterval(w),w=null),L("doGenerateLocal: first token",{ttftMs:Math.round(y-u),promptTokens:f})),m+=g;let v=-1;for(const q of c){const I=m.indexOf(q);I!==-1&&(v===-1||I<v)&&(v=I)}v!==-1&&(m=m.slice(0,v),x=!0),e.fullText=m;const N=m.slice(_);_=m.length,N&&A(e,{type:"token",delta:N,text:m})}});let C=0;const j=a>0?[(g,v)=>{if(C<te)try{const N=v.dims.at(-1),q=v.data,I=se(q,N,a).map(({id:z,p:Z})=>({token:s.decode([z]),p:+Z.toFixed(4)}));let W=-1/0;for(let z=0;z<N;z++)q[z]>W&&(W=q[z]);let V=0;for(let z=0;z<N;z++)V+=Math.exp(q[z]-W);let H=0;for(let z=0;z<N;z++){const Z=Math.exp(q[z]-W)/V;Z>0&&(H-=Z*Math.log2(Z))}A(e,{type:"prediction",step:C,candidates:I,entropy:+H.toFixed(3)})}catch{}return C++,v}]:void 0;L("doGenerateLocal: generating",{model:T,dtype:U,promptTokens:f,maxNewTokens:l,temperature:d,inputKind:typeof n=="string"?"text":"messages"}),w=setInterval(()=>{if(y)return;const g=Math.round((performance.now()-u)/1e3);M({type:"status",message:`Generating… ${g}s (prefilling, no token yet)`}),L("doGenerateLocal: still prefilling",{elapsedS:g})},2e3);let h;try{h=await k(n,{...p?{tools:p}:{},max_new_tokens:l,do_sample:d>0,temperature:d,...t.topK>0?{top_k:t.topK}:{},repetition_penalty:t.repetitionPenalty??1.1,...t.noRepeatNgramSize>0?{no_repeat_ngram_size:t.noRepeatNgramSize}:{},streamer:O,logits_processor:j})}finally{w&&(clearInterval(w),w=null)}const S=m||h?.[0]?.generated_text?.at(-1)?.content||"";let b=0;try{b=s.encode(S).length}catch{}const P=performance.now();return A(e,{type:"stats",provider:"local",model:T,promptTokens:f,genTokens:b,ttftMs:y?Math.round(y-u):null,totalMs:Math.round(P-u),tokPerSec:y?+(b/((P-y)/1e3)).toFixed(1):null,decode:{greedy:!(d>0),temperature:d,top_k:t.topK>0?t.topK:null,repetition_penalty:t.repetitionPenalty??1.1,no_repeat_ngram_size:t.noRepeatNgramSize||0,maxNewTokens:l}}),{text:S,toolCalls:null,toolMode:p?"template":"text"}}const ue="You are a text-continuation engine inside a writing tool. Continue the user's text seamlessly from exactly where it ends, matching its voice, tense, and style. Output ONLY the continuation — no preamble, no commentary, no explanation, no quotation marks — and never restate or acknowledge the user's text. If it ends mid-word or mid-sentence, finish it.";async function Pe(e,o,t){const s=typeof o=="string",r=t.temperature??.7,d=t.topk|0,a={model:t.model||"anthropic/claude-sonnet-4",stream:!0,stream_options:{include_usage:!0},temperature:r};if(t.topP!=null&&(a.top_p=t.topP),Object.assign(a,xe(t)),a.messages=s?[{role:"system",content:ue},{role:"user",content:o}]:o,t.maxNewTokens)a.max_tokens=t.maxNewTokens;else if(t.contextLength){const h=Math.ceil(JSON.stringify(o).length/4),S=t.maxCompletionTokens||8192;a.max_tokens=Math.min(S,Math.max(1024,t.contextLength-h-256))}!!(t.tools&&t.tools.length)?(a.tools=t.tools,a.tool_choice="auto"):d>0&&(a.logprobs=!0,a.top_logprobs=Math.min(d,20));const i=await fetch("https://openrouter.ai/api/v1/chat/completions",{method:"POST",headers:{Authorization:"Bearer "+t.apiKey,"Content-Type":"application/json"},body:JSON.stringify(a),signal:e.abortController.signal});if(!i.ok)throw new Error("OpenRouter: "+await i.text());const n=performance.now();let p=0,c="",f=0,u=null;const y=i.body.getReader(),m=new TextDecoder;let w="";const x=new Map,_=h=>{if(!h.startsWith("data: "))return;const S=h.slice(6).trim();if(S==="[DONE]")return;let b;try{b=JSON.parse(S)}catch{return}b.usage&&(u=b.usage);const P=b.choices?.[0],g=P?.delta?.content;g&&(p||(p=performance.now()),c+=g,e.fullText=c,A(e,{type:"token",delta:g,text:c}));for(const v of P?.delta?.tool_calls||[]){const N=v.index??0;let q=x.get(N);q||(q={id:void 0,name:void 0,args:""},x.set(N,q)),v.id&&(q.id=v.id),v.function?.name&&(q.name=v.function.name),v.function?.arguments&&(q.args+=v.function.arguments)}if(d>0)for(const v of P?.logprobs?.content||[]){if(f>=te)break;const N=(v.top_logprobs||[]).map(q=>({token:q.token,p:+Math.exp(q.logprob).toFixed(4)}));N.length&&A(e,{type:"prediction",step:f,candidates:N}),f++}};for(;;){const{done:h,value:S}=await y.read();if(h)break;w+=m.decode(S,{stream:!0});const b=w.split(`
7
+ `);w=b.pop()||"";for(const P of b)_(P)}if(w.trim())for(const h of w.split(`
8
+ `))_(h);const O=performance.now(),C=u?.completion_tokens??null;A(e,{type:"stats",provider:"openrouter",model:t.model,promptTokens:u?.prompt_tokens??null,genTokens:C,ttftMs:p?Math.round(p-n):null,totalMs:Math.round(O-n),tokPerSec:p&&C?+(C/((O-p)/1e3)).toFixed(1):null,decode:{greedy:r===0,temperature:r}});const j=x.size?[...x.entries()].sort((h,S)=>h[0]-S[0]).map(([,h])=>({id:h.id,name:h.name,args:ne(h.args)})).filter(h=>h.name):[];return{text:c,toolCalls:j.length?j:null}}async function ve(e,o,t){const s=typeof o=="string",r=(t.url||"http://localhost:11434").replace(/\/$/,""),d={model:t.model||"llama3.2",stream:!0,options:{temperature:t.temperature??.7,...t.topP!=null?{top_p:t.topP}:{},...t.topK>0?{top_k:t.topK}:{},...t.minP>0?{min_p:t.minP}:{},...t.typicalP!=null&&t.typicalP<1?{typical_p:t.typicalP}:{},...t.repetitionPenalty&&t.repetitionPenalty!==1?{repeat_penalty:t.repetitionPenalty}:{},...t.frequencyPenalty?{frequency_penalty:t.frequencyPenalty}:{},...t.presencePenalty?{presence_penalty:t.presencePenalty}:{},...t.seed!=null&&t.seed!==""?{seed:t.seed}:{}}};if(s?d.prompt=o:d.messages=o,t.tools&&t.tools.length&&!s){d.tools=t.tools,d.stream=!1;const w=performance.now(),x=await fetch(r+"/api/chat",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d),signal:e.abortController.signal});if(!x.ok)throw new Error("Ollama: "+await x.text());const _=await x.json(),O=_.message?.content||"";O&&A(e,{type:"token",delta:O,text:O}),e.fullText=O;const C=(_.message?.tool_calls||[]).map((j,h)=>({id:j.id||"call_"+h,name:j.function?.name,args:ne(j.function?.arguments)}));return A(e,{type:"stats",provider:"ollama",model:t.model,promptTokens:_.prompt_eval_count??null,genTokens:_.eval_count??null,ttftMs:null,totalMs:Math.round(performance.now()-w),tokPerSec:null,decode:{greedy:(t.temperature??.7)===0,temperature:t.temperature??.7}}),{text:O,toolCalls:C}}const a=await fetch(r+(s?"/api/generate":"/api/chat"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(d),signal:e.abortController.signal});if(!a.ok)throw new Error("Ollama: "+await a.text());const l=performance.now();let i=0,n="",p=null;const c=a.body.getReader(),f=new TextDecoder;let u="";for(;;){const{done:w,value:x}=await c.read();if(w)break;u+=f.decode(x,{stream:!0});const _=u.split(`
9
+ `);u=_.pop()||"";for(const O of _)if(O.trim())try{const C=JSON.parse(O);C.done&&(p=C);const j=s?C.response:C.message?.content;j&&(i||(i=performance.now()),n+=j,e.fullText=n,A(e,{type:"token",delta:j,text:n}))}catch{}}const y=performance.now(),m=p?.eval_count??null;return A(e,{type:"stats",provider:"ollama",model:t.model,promptTokens:p?.prompt_eval_count??null,genTokens:m,ttftMs:i?Math.round(i-l):null,totalMs:Math.round(y-l),tokPerSec:p?.eval_count&&p?.eval_duration?+(p.eval_count/(p.eval_duration/1e9)).toFixed(1):null,decode:{temperature:t.temperature??.7}}),{text:n,toolCalls:null}}async function Se(e,o){const t=Math.max(1,o.topk|0||10),s=k.tokenizer;let r=[];return await k(e||" ",{max_new_tokens:1,do_sample:!1,logits_processor:[(d,a)=>{if(!r.length)try{const l=a.dims.at(-1);r=se(a.data,l,t).map(({id:i,p:n})=>({token:s.decode([i]),p:+n.toFixed(4)}))}catch{}return a}]}),r}async function Ce(e,o,t){const s=k.tokenizer,r=s.encode(o),d=[];for(let n=0;n<r.length&&!e.abortController.signal.aborted;n++){const p=n===0?"":s.decode(r.slice(0,n),{skip_special_tokens:!0});let c=null;await k(p||" ",{max_new_tokens:1,do_sample:!1,logits_processor:[(f,u)=>{if(c)return u;const y=u.dims.at(-1),m=u.data,w=r[n];let x=-1/0;for(let b=0;b<y;b++)m[b]>x&&(x=m[b]);let _=0;for(let b=0;b<y;b++)_+=Math.exp(m[b]-x);const O=Math.exp(m[w]-x)/_;let C=1;const j=m[w];for(let b=0;b<y;b++)m[b]>j+1e-8&&C++;let h=0;for(let b=0;b<y;b++){const P=Math.exp(m[b]-x)/_;P>0&&(h-=P*Math.log2(P))}const S=se(m,y,10).map(({id:b,p:P})=>({token:s.decode([b]),p:+P.toFixed(4)}));return c={token:s.decode([w]),p:+O.toFixed(6),rank:C,entropy:+h.toFixed(3),topk:S},u}]}),c&&d.push(c),A(e,{type:"score-progress",step:n,total:r.length})}const a=[];let l=0;for(let n=0;n<r.length&&n<d.length;n++){const p=s.decode(r.slice(0,n+1),{skip_special_tokens:!0}),c=l,f=p.length;f>c&&a.push({from:c,to:f,index:n}),l=p.length}const i=s.decode(r,{skip_special_tokens:!0});A(e,{type:"token-scores",scores:d,spans:a,decoded:i})}async function Le(e,o,t){const s=k.model,r=k.tokenizer,d=r(o,{return_tensor:!0}),a=Array.from(d.input_ids.data),l=a.length;if(l<2){A(e,{type:"importance-scores",decoded:o,spans:[]});return}const i=s.config?.vocab_size||151936,n=(l-1)*i;function p(h){const S=new Float64Array(i);let b=-1/0;for(let g=0;g<i;g++){const v=h[n+g];v>b&&(b=v)}let P=0;for(let g=0;g<i;g++)S[g]=Math.exp(h[n+g]-b),P+=S[g];for(let g=0;g<i;g++)S[g]/=P;return S}function c(h,S){let b=0;for(let P=0;P<i;P++){const g=(h[P]+S[P])/2;g>0&&(h[P]>0&&(b+=h[P]*Math.log(h[P]/g)),S[P]>0&&(b+=S[P]*Math.log(S[P]/g)))}return b/2}M({type:"status",message:"Saliency: baseline…"});const f=await s(d),u=p(f.logits.data),y=new Float64Array(l),m=new BigInt64Array(d.input_ids.data);for(let h=0;h<l&&!e.abortController.signal.aborted;h++){M({type:"status",message:`Saliency: ${h+1}/${l}…`}),A(e,{type:"score-progress",step:h,total:l});const S=new BigInt64Array(m);S[h]=0n;const b={input_ids:new R.Tensor("int64",S,d.input_ids.dims),attention_mask:d.attention_mask},P=await s(b),g=p(P.logits.data);y[h]=c(u,g)}let w=1/0,x=-1/0;for(let h=0;h<l;h++)y[h]<w&&(w=y[h]),y[h]>x&&(x=y[h]);const _=x-w||1,O=[];let C=0;for(let h=0;h<a.length;h++){const S=r.decode(a.slice(0,h+1),{skip_special_tokens:!0}),b=C,P=S.length;P>b&&O.push({from:b,to:P,importance:(y[h]-w)/_}),C=S.length}const j=r.decode(a,{skip_special_tokens:!0});A(e,{type:"importance-scores",decoded:j,spans:O}),M({type:"status",message:""})}async function Oe(e,o,t){const s=k.model,r=k.tokenizer,d=r(o,{return_tensor:!0}),a=Array.from(d.input_ids.data),l=a.length;if(l<2){A(e,{type:"attention-weights",supported:!0,dims:{layers:0,heads:0,seq:l},received:new Float32Array(0),fromLast:new Float32Array(0),spans:[],tokens:[],decoded:o});return}L("computeAttentionWeights: forward pass",{model:T,seqLen:l}),M({type:"status",message:"Attention: forward pass…"});const i=await s(d),n=i.attentions;if(!n||!n.dims||n.dims.length!==5){const g=Object.keys(i||{});L("computeAttentionWeights: no usable attentions output",{model:T,outputKeys:g,attnDims:n?.dims||null}),console.warn(`[llm worker] ${T} has no usable attentions output. forward outputs:`,g,n?`(attentions dims: [${n.dims}])`:"(no `attentions` key)"),A(e,{type:"attention-weights",supported:!1,model:T,outputKeys:g,attnDims:n?.dims||null}),M({type:"status",message:""});return}const[,p,c,f,u]=n.dims,y=n.data,m=u,w=c*f*u,x=f*u,_=u,O=new Float32Array(p*c*m),C=new Float32Array(p*c*m),j=f-1;for(let g=0;g<p;g++)for(let v=0;v<c;v++){const N=g*w+v*x,q=(g*c+v)*m,I=N+j*_;for(let W=0;W<m;W++)C[q+W]=y[I+W];for(let W=0;W<m;W++){let V=0,H=0;for(let z=W;z<f;z++)V+=y[N+z*_+W],H++;O[q+W]=H?V/H:0}}const h=[],S=[];let b=0;for(let g=0;g<l;g++){const v=r.decode(a.slice(0,g+1),{skip_special_tokens:!0}),N=b,q=v.length;S.push(r.decode([a[g]])),q>N&&h.push({from:N,to:q,index:g}),b=v.length}const P=r.decode(a,{skip_special_tokens:!0});A(e,{type:"attention-weights",supported:!0,dims:{layers:p,heads:c,seq:m},received:O,fromLast:C,spans:h,tokens:S,decoded:P}),M({type:"status",message:""})}async function Ae(e,o,t){const s=Math.min(Math.max(1,o.topk|0||10),20),r=await fetch("https://openrouter.ai/api/v1/chat/completions",{method:"POST",headers:{Authorization:"Bearer "+o.apiKey,"Content-Type":"application/json"},body:JSON.stringify({model:o.model,messages:o.continuation?[{role:"system",content:ue},{role:"user",content:e||" "}]:[{role:"user",content:e||" "}],max_tokens:1,temperature:0,logprobs:!0,top_logprobs:s}),signal:t});if(!r.ok)throw new Error("OpenRouter predict: "+await r.text());const a=(await r.json()).choices?.[0]?.logprobs?.content?.[0]?.top_logprobs;return a?a.map(l=>({token:l.token,p:+Math.exp(l.logprob).toFixed(4)})).sort((l,i)=>i.p-l.p):[]}function Ne(e,o){const{id:t,text:s,config:r={}}=o,d=o.provider,a=o.sessionKey||t,l=new AbortController;F.set(a,{id:t,port:e,done:!1,fullText:"",abortController:l});const i=()=>F.delete(a),n=u=>{i(),e.postMessage({type:"predictions",id:t,candidates:u})},p=u=>{i(),l.signal.aborted||e.postMessage({type:"error",id:t,message:u})};if(d==="openrouter"){Ae(s,r,l.signal).then(n).catch(u=>p(u?.message||String(u)));return}if(d==="ollama"){n([]);return}if(d==="webllm"){Fe(s,r).then(n).catch(u=>p(u?.message||String(u)));return}const c=r.model||G,f=()=>Se(s,r).then(n).catch(u=>p(u?.message||String(u)));!k||T!==c?(T!==c&&(k=null),$(c,r.dtype).then(()=>k?f():p(E()))):f()}let Y=null,D=null,me=null;async function fe(e,o){if(e=e||"Qwen2.5-1.5B-Instruct-q4f16_1-MLC",Y||(M({type:"status",message:"Loading WebLLM…"}),Y=await import("https://esm.run/@mlc-ai/web-llm")),D&&me===e)return;if(D){try{await D.unload?.()}catch{}D=null}me=e;const t=(Array.isArray(o)?o:[]).filter(r=>r&&r.model_id&&r.model_lib).map(r=>({...r,model:r.model||"https://huggingface.co/"+r.model_id})),s=t.length?{...Y.prebuiltAppConfig,model_list:[...Y.prebuiltAppConfig.model_list,...t]}:void 0;D=await Y.CreateMLCEngine(e,{appConfig:s,initProgressCallback:r=>M({type:"status",message:r.text||"Loading… "+(typeof r.progress=="number"?Math.round(r.progress*100)+"%":"")})}),M({type:"status",message:"Model ready (WebLLM)"}),M({type:"ready",model:e,device:"WebGPU"})}async function qe(e,o,t){await fe(t.model,t.custom);const s=typeof o=="string";if(t.tools&&t.tools.length&&!s){const m=performance.now(),w=await D.chat.completions.create({messages:o,tools:t.tools,tool_choice:"auto",stream:!1,temperature:t.temperature??.7,...t.topP!=null?{top_p:t.topP}:{},...t.maxNewTokens?{max_tokens:t.maxNewTokens}:{}}),x=w.choices?.[0]?.message||{},_=x.content||"";_&&A(e,{type:"token",delta:_,text:_}),e.fullText=_;const O=(x.tool_calls||[]).map(C=>({id:C.id,name:C.function?.name,args:ne(C.function?.arguments)}));return A(e,{type:"stats",provider:"webllm",model:t.model,promptTokens:w.usage?.prompt_tokens??null,genTokens:w.usage?.completion_tokens??null,ttftMs:null,totalMs:Math.round(performance.now()-m),tokPerSec:null,decode:{temperature:t.temperature??.7}}),{text:_,toolCalls:O}}const r=t.temperature??.7,d=t.topk|0,a={stream:!0,stream_options:{include_usage:!0},temperature:r,...t.topP!=null?{top_p:t.topP}:{},...t.frequencyPenalty?{frequency_penalty:t.frequencyPenalty}:{},...t.presencePenalty?{presence_penalty:t.presencePenalty}:{},...t.seed!=null&&t.seed!==""?{seed:t.seed}:{},...t.maxNewTokens?{max_tokens:t.maxNewTokens}:{},...d>0?{logprobs:!0,top_logprobs:d}:{}},l=performance.now();let i=0,n="",p=null,c=0;const f=s?await D.completions.create({prompt:o,...a}):await D.chat.completions.create({messages:o,...a});for await(const m of f){if(e.abortController.signal.aborted)break;m.usage&&(p=m.usage);const w=m.choices?.[0],x=s?w?.text:w?.delta?.content,_=w?.logprobs?.content;if(_&&d>0)for(const O of _){if(c>=te)break;const C=(O.top_logprobs||[]).map(j=>({token:j.token,p:+Math.exp(j.logprob).toFixed(4)}));C.length&&A(e,{type:"prediction",step:c,candidates:C}),c++}x&&(i||(i=performance.now()),n+=x,e.fullText=n,A(e,{type:"token",delta:x,text:n}))}const u=performance.now(),y=p?.completion_tokens??null;return A(e,{type:"stats",provider:"webllm",model:t.model,promptTokens:p?.prompt_tokens??null,genTokens:y,ttftMs:i?Math.round(i-l):null,totalMs:Math.round(u-l),tokPerSec:i&&y?+(y/((u-i)/1e3)).toFixed(1):null,decode:{temperature:r,top_p:t.topP}}),{text:n,toolCalls:null}}async function Fe(e,o){await fe(o.model,o.custom);const t=Math.max(1,o.topk|0||10),r=(await D.completions.create({prompt:e||" ",max_tokens:1,temperature:0,logprobs:!0,top_logprobs:t,stream:!1})).choices?.[0]?.logprobs?.content?.[0]?.top_logprobs;return r?r.map(d=>({token:d.token,p:+Math.exp(d.logprob).toFixed(4)})).sort((d,a)=>a.p-d.p):[]}function A(e,o){try{e.port.postMessage({...o,id:e.id})}catch{}}function ye(e,o,t,s,r){o.done=!0,o.finalText=t;try{o.port.postMessage({type:"result",id:o.id,text:t,toolCalls:s||null,toolMode:r})}catch{}M({type:"status",message:""}),e&&setTimeout(()=>F.delete(e),5e3)}function re(e,o,t){try{o.port.postMessage({type:"error",id:o.id,message:t})}catch{}M({type:"status",message:""}),e&&F.delete(e)}async function ae(e,o,t,s,r){try{L("runGeneration: start",{provider:t,model:r.model||T,inputKind:typeof s=="string"?"text":"messages",messages:Array.isArray(s)?s.length:void 0}),M({type:"status",message:"Thinking…"});let d;t==="openrouter"?d=await Pe(o,s,r):t==="ollama"?d=await ve(o,s,r):t==="webllm"?d=await qe(o,s,r):d=await Te(o,s,r),L("runGeneration: done",{provider:t,chars:d.text?.length||0}),ye(e,o,d.text,d.toolCalls,"toolMode"in d&&typeof d.toolMode=="string"?d.toolMode:void 0)}catch(d){if(o.abortController.signal.aborted){L("runGeneration: aborted",{provider:t,chars:o.fullText?.length||0});return}L("runGeneration: error",{provider:t,model:T,message:d?.message||String(d)}),o.fullText?ye(e,o,o.fullText):re(e,o,Q(d))}}async function je(e,o){const t=k.model,s=k.tokenizer,r=s(o||" ",{return_tensor:!0}),d=Array.from(r.input_ids.data,Number),a=d.length;M({type:"status",message:"Extracting features (forward pass)…"});const l=await t(r),i=l.last_hidden_state,n=l.logits;if(!i||!n){A(e,{type:"features",supported:!1,outputKeys:Object.keys(l||{}),message:`${T} has no last_hidden_state output — needs a hidden-state export (onnx_hidden.py).`}),M({type:"status",message:""});return}const p=i.dims.at(-1),c=n.dims.at(-1),f=Float32Array.from(i.data),u=Float32Array.from(n.data),y=[];let m=0;for(let _=0;_<a;_++){const O=s.decode(d.slice(0,_+1),{skip_special_tokens:!0});O.length>m&&y.push({from:m,to:O.length,index:_}),m=O.length}const w=s.decode(d,{skip_special_tokens:!0}),x=d.map(_=>s.decode([_]));A(e,{type:"features",supported:!0,seq:a,H:p,V:c,ids:d,tokens:x,spans:y,decoded:w,hidden:f,logits:u}),M({type:"status",message:""})}async function ze(e,o){const t=k.model,s=k.tokenizer,r=s(o||" ",{return_tensor:!0}),d=Array.from(r.input_ids.data,Number),a=d.length;M({type:"status",message:"Extracting cut features (forward pass)…"});const l=await t(r),i=l.cut_hidden;if(!i){A(e,{type:"cut-features",supported:!1,outputKeys:Object.keys(l||{}),message:`${T} has no cut_hidden output — needs a cut-point export (onnx_block.py).`}),M({type:"status",message:""});return}const n=i.dims.at(-1),p=Float32Array.from(i.data),c=[];let f=0;for(let m=0;m<a;m++){const w=s.decode(d.slice(0,m+1),{skip_special_tokens:!0});w.length>f&&c.push({from:f,to:w.length,index:m}),f=w.length}const u=s.decode(d,{skip_special_tokens:!0}),y=d.map(m=>s.decode([m]));A(e,{type:"cut-features",supported:!0,seq:a,d:n,ids:d,tokens:y,spans:c,decoded:u,hidden:p}),M({type:"status",message:""})}function he(e,o){const{type:t,id:s}=o,r=o.sessionKey||s,d=o.config?.dtype;if(k&&!J&&d&&U&&d!==U&&(k=null),t==="list-local-models"){e.postMessage({type:"local-models",models:ce});return}if(t==="predict"){Ne(e,o);return}if(t==="score-tokens"){const{provider:a,config:l={}}=o;if(a!=="local"){e.postMessage({type:"token-scores",id:s,scores:[]});return}const i={id:s,port:e,fullText:"",done:!1,finalText:"",abortController:new AbortController};F.set(r,i);const n=l.model||G,p=()=>Ce(i,o.text).then(()=>{i.done=!0,F.delete(r)}).catch(c=>{i.abortController.signal.aborted||e.postMessage({type:"error",id:s,message:c?.message||String(c)}),F.delete(r)});!k||T!==n?(T!==n&&K(),$(n,l.dtype).then(()=>{if(!k){e.postMessage({type:"error",id:s,message:E()});return}p()})):p();return}if(t==="compute-importance"){const{provider:a,config:l={}}=o;if(a!=="local"){e.postMessage({type:"importance-scores",id:s,scores:[]});return}const i={id:s,port:e,fullText:"",done:!1,finalText:"",abortController:new AbortController};F.set(r,i);const n=l.model||G,p=()=>Le(i,o.text).then(()=>{i.done=!0,F.delete(r)}).catch(c=>{i.abortController.signal.aborted||e.postMessage({type:"error",id:s,message:c?.message||String(c)}),F.delete(r)});!k||T!==n?(T!==n&&K(),$(n,l.dtype).then(()=>{if(!k){e.postMessage({type:"error",id:s,message:E()});return}p()})):p();return}if(t==="compute-attention-weights"){const{provider:a,config:l={}}=o;if(a!=="local"){e.postMessage({type:"attention-weights",id:s,supported:!1});return}const i={id:s,port:e,fullText:"",done:!1,finalText:"",abortController:new AbortController};F.set(r,i);const n=l.model||G,p=()=>(L("compute-attention-weights: run",{model:n}),Oe(i,o.text).then(()=>{i.done=!0,F.delete(r)}).catch(c=>{const f=i.abortController.signal.aborted;L("compute-attention-weights: error",{model:n,aborted:f,message:c?.message||String(c)}),f||e.postMessage({type:"error",id:s,message:Q(c)}),F.delete(r)}));!k||T!==n?(T!==n&&K(),$(n,l.dtype).then(()=>{if(!k){e.postMessage({type:"error",id:s,message:E()});return}p()}).catch(c=>{L("compute-attention-weights: loadModel threw",{model:n,message:c?.message||String(c)}),e.postMessage({type:"error",id:s,message:Q(c)})})):p();return}if(t==="extract-features"){const{provider:a,config:l={}}=o;if(a!=="local"){e.postMessage({type:"features",id:s,supported:!1,message:"features require a local model"});return}const i={id:s,port:e,fullText:"",done:!1,finalText:"",abortController:new AbortController};F.set(r,i);const n=l.model||G,p=()=>(L("extract-features: run",{model:n}),je(i,o.text).then(()=>{i.done=!0,F.delete(r)}).catch(c=>{const f=i.abortController.signal.aborted;L("extract-features: error",{model:n,aborted:f,message:c?.message||String(c)}),f||e.postMessage({type:"error",id:s,message:Q(c)}),F.delete(r)}));!k||T!==n?(T!==n&&K(),$(n,l.dtype).then(()=>{if(!k){e.postMessage({type:"error",id:s,message:E()});return}p()}).catch(c=>{L("extract-features: loadModel threw",{model:n,message:c?.message||String(c)}),e.postMessage({type:"error",id:s,message:Q(c)})})):p();return}if(t==="extract-cut-features"){const{provider:a,config:l={}}=o;if(a!=="local"){e.postMessage({type:"cut-features",id:s,supported:!1,message:"features require a local model"});return}const i={id:s,port:e,fullText:"",done:!1,finalText:"",abortController:new AbortController};F.set(r,i);const n=l.model||G,p=()=>ze(i,o.text).then(()=>{i.done=!0,F.delete(r)}).catch(c=>{i.abortController.signal.aborted||e.postMessage({type:"error",id:s,message:c?.message||String(c)}),F.delete(r)});!k||T!==n?(T!==n&&K(),$(n,l.dtype).then(()=>{if(!k){e.postMessage({type:"error",id:s,message:E()});return}p()})):p();return}if(t==="decode-tokens"){const a=()=>{try{const i=k.tokenizer,n=(o.ids||[]).map(p=>i.decode([p]));e.postMessage({type:"decoded-tokens",id:s,strings:n})}catch(i){e.postMessage({type:"error",id:s,message:i?.message||String(i)})}},l=o.config?.model||G;!k||T!==l?(T!==l&&K(),$(l,o.config?.dtype).then(()=>k?a():e.postMessage({type:"error",id:s,message:E()}))):a();return}if(t==="probe-attention"){const a=async()=>{const i=k.model,n=k.tokenizer,p=o.text||"Hello world",c=n(p,{return_tensor:!0}),f={type:"probe-attention-result",id:s},u={};for(const[y,m]of Object.entries(i?.sessions||{}))u[y]={inputNames:m?.inputNames||[],outputNames:m?.outputNames||[]};f.sessions=u;try{const y=await i(c);f.outputKeys=Object.keys(y||{}),f.hasAttentions="attentions"in(y||{}),f.attentionKeys=Object.keys(y||{}).filter(m=>/attention|attn/i.test(m))}catch(y){f.forwardError=y.message}try{const y=await i.generate({...c,max_new_tokens:1,output_attentions:!0,return_dict_in_generate:!0});f.generateKeys=Object.keys(y||{}),f.generateHasAttentions="attentions"in(y||{})}catch(y){f.generateError=y.message}e.postMessage(f)},l=o.config?.model||G;!k||T!==l?$(l,o.config?.dtype).then(()=>k?a():e.postMessage({type:"probe-attention-result",id:s,error:E()})):a();return}if(t==="register-local-model"){const a=new Map((o.files||[]).map(l=>[l.path,l.blob]));oe.set(o.id,{files:a,dtype:o.dtype||"q4f16"}),pe(),T===o.id&&K(),be(o.id).then(()=>e.postMessage({type:"local-model-registered",id:o.id,count:a.size}));return}if(t==="preload"){o.provider==="local"?(!k&&!J&&$(o.config?.model,o.config?.dtype),k&&e.postMessage({type:"ready"})):e.postMessage({type:"ready"});return}if(t==="resume"){const a=o.sessionKey,l=F.get(a);l&&!l.done?(l.port=e,e.postMessage({type:"resumed",id:l.id,sessionKey:a,text:l.fullText})):l&&l.done?(e.postMessage({type:"resume-result",id:l.id,sessionKey:a,text:l.finalText}),F.delete(a)):e.postMessage({type:"no-active-generation",sessionKey:a});return}if(t==="abort"){const a=F.get(o.sessionKey);a&&!a.done&&(a.abortController.abort(),F.delete(o.sessionKey));return}if(t==="generate"){const{provider:a,config:l={}}=o,i=o.text!=null?o.text:o.messages,n={id:s,port:e,fullText:"",done:!1,finalText:"",abortController:new AbortController};if(F.set(r,n),a==="local"){const p=l.model||G;!k||T!==p?(T!==p&&K(),$(p,l.dtype).then(()=>{if(!k)return re(r,n,`Model "${p}" failed to load (still not ready after load). Try a different local model, or check the device has enough memory.`);ae(r,n,a,i,l)}).catch(c=>re(r,n,`Couldn't load local model "${p}": ${c?.message||c}`))):ae(r,n,a,i,l)}else ae(r,n,a,i,l)}}self.onconnect=e=>{const o=e.ports[0];ee.add(o),o.onmessage=t=>he(o,t.data),k&&o.postMessage({type:"ready"}),o.start()},typeof self.SharedWorkerGlobalScope>"u"&&(ee.add(self),self.onmessage=e=>he(self,e.data))})();
@@ -1,7 +1,7 @@
1
1
  import { render as k, createComponent as y, insert as H, template as U } from "solid-js/web";
2
2
  import { createSignal as C, createEffect as m, onCleanup as S, Show as x } from "solid-js";
3
- import { C as T, s as _ } from "./ChatRoot-CgnJ5YGo.js";
4
- import { s as v, t as D } from "./index-d8BugVrl.js";
3
+ import { C as T, s as _ } from "./ChatRoot-C2Bt2HnE.js";
4
+ import { s as v, t as D } from "./index-Db7mD_tU.js";
5
5
  var L = /* @__PURE__ */ U("<div class=chat-context-empty>");
6
6
  const g = ["computer", "model"], A = ["computer"];
7
7
  function w(e) {
@@ -306,7 +306,7 @@ const J = [
306
306
  icon: "MessageSquare",
307
307
  supportedDatatypes: ["chitterchatter", "chat", "chitter"],
308
308
  async load() {
309
- return (await import("./tool-RMTBywaO.js")).ChatTool;
309
+ return (await import("./tool-BjR4Xz4J.js")).ChatTool;
310
310
  }
311
311
  },
312
312
  {
@@ -317,7 +317,7 @@ const J = [
317
317
  name: "Chat",
318
318
  icon: "MessageSquare",
319
319
  async load() {
320
- return (await import("./tool-RMTBywaO.js")).ChatComponent;
320
+ return (await import("./tool-BjR4Xz4J.js")).ChatComponent;
321
321
  }
322
322
  },
323
323
  {
@@ -330,7 +330,7 @@ const J = [
330
330
  icon: "MessageCircle",
331
331
  tags: ["context-tool"],
332
332
  async load() {
333
- const { ChatContextComponent: e } = await import("./context-tool-DB53-ESw.js");
333
+ const { ChatContextComponent: e } = await import("./context-tool-CC-JL_lb.js");
334
334
  return e;
335
335
  }
336
336
  },
@@ -1,5 +1,5 @@
1
1
  (function(){"use strict";try{if(typeof document<"u"){var e=document.createElement("style");e.appendChild(document.createTextNode('.chat-root{--bg-dark: var(--editor-fill, var(--studio-fill, oklch(.15 .03 270)));--bg-darkest: var(--editor-fill-offset-20, var(--studio-fill-offset-20, oklch(.12 .02 270)));--bg-mid: var(--editor-fill-offset-10, var(--studio-fill-offset-10, oklch(.19 .03 270)));--bg-input: var(--editor-fill, var(--studio-fill, oklch(.17 .03 270)));--bg-hover: var(--editor-fill-offset-20, var(--studio-fill-offset-20, oklch(.22 .04 270)));--border: var(--editor-fill-offset-20, var(--studio-fill-offset-20, oklch(.28 .05 270)));--accent: var(--studio-primary-fill, var(--studio-primary, oklch(.55 .18 270)));--accent-line: var(--studio-primary-line, var(--editor-fill, var(--studio-fill, oklch(1 0 0))));--accent-text: var(--studio-primary-text, var(--accent));--accent-hover: color-mix(in oklch, var(--accent), var(--studio-line, black) 18%);--accent-soft: color-mix(in oklch, var(--accent), transparent 85%);--accent-fg: var(--accent-line);--theme: var(--accent);--text-primary: var(--studio-line, oklch(1 0 0));--text-secondary: var(--studio-line-offset-30, oklch(1 0 0 / .6));--text-muted: var(--studio-line-offset-50, oklch(1 0 0 / .4));--link: var(--studio-link-text, var(--studio-link, oklch(.75 .15 250)))}.chat-root{display:flex;flex-direction:row;position:absolute;inset:0;font-family:var(--studio-family-sans, system-ui,-apple-system,sans-serif);background:var(--bg-dark);color:var(--text-primary);box-sizing:border-box;font-size:var(--studio-font-size, 15px);overflow:hidden;user-select:text;-webkit-user-select:text;height:100%}.chat-context-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;text-align:center;padding:24px;color:var(--text-secondary, #888);font-family:var(--studio-family-sans, system-ui,-apple-system,sans-serif);font-size:var(--studio-font-size, 15px)}.chat-root *,.chat-root *:before,.chat-root *:after{box-sizing:border-box}.chat-root a{color:var(--link);text-decoration:underline}.chat-root a:hover{text-decoration:none}.chat-theme-btn{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:16px;padding:2px 6px;border-radius:4px;position:relative}.chat-theme-btn:hover,.chat-notify-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.chat-notify-btn{background:none;border:none;color:var(--text-muted);cursor:pointer;padding:2px 4px;border-radius:4px;display:flex;align-items:center;position:relative}.chat-notify-menu{display:none;position:absolute;top:100%;right:0;margin-top:4px;background:var(--bg-darkest);border:1px solid var(--border);border-radius:8px;padding:8px;min-width:180px;z-index:200}.chat-notify-menu.show{display:block}.chat-notify-menu-row{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 4px;font-size:13px;color:var(--text-secondary);cursor:pointer;border-radius:4px}.chat-notify-menu-row:hover{background:var(--bg-hover)}.chat-notify-toggle{width:32px;height:18px;border-radius:9px;border:none;cursor:pointer;background:var(--bg-hover);position:relative;transition:background .15s;flex-shrink:0}.chat-notify-toggle.on{background:var(--accent)}.chat-notify-toggle:after{content:"";position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:#fff;transition:transform .15s}.chat-notify-toggle.on:after{transform:translate(14px)}.chat-presence-bar{padding:4px 16px;background:var(--bg-darkest);border-bottom:1px solid var(--border);display:flex;gap:8px;align-items:center;flex-shrink:0;min-height:24px;position:relative;z-index:50;overflow:visible}.chat-presence-user{display:flex;align-items:center;gap:4px;font-size:12px;color:var(--text-secondary);transition:opacity .2s}.chat-presence-user.away{opacity:.9}.chat-presence-avatar{width:18px;height:18px;border-radius:50%;overflow:hidden;flex-shrink:0;background:var(--bg-hover);display:flex;align-items:center;justify-content:center;font-size:10px;color:var(--text-muted)}.chat-presence-avatar img{width:100%;height:100%;object-fit:cover}.chat-messages{flex:1;overflow-y:auto;padding:8px 0;display:flex;flex-direction:column;min-height:0;height:100%;overflow:scroll}.chat-msg-group{padding:2px 16px;display:flex;gap:12px;position:relative}.chat-msg-group:hover{background:var(--bg-hover)}.chat-avatar-col{width:40px;flex-shrink:0;padding-top:2px}.chat-avatar{width:40px;height:40px;border-radius:50%;background:var(--accent);display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:700;color:var(--accent-fg);overflow:hidden;cursor:pointer;position:relative;user-select:none}.chat-avatar img{width:100%;height:100%;object-fit:cover}.chat-avatar-view{display:block;width:100%;height:100%}.chat-avatar-view img{width:100%;height:100%;object-fit:cover}.chat-avatar.gif-selfie,.chat-avatar.gif-selfie img{border-radius:4px}.chat-avatar.cat-ears:before{content:"";position:absolute;top:-6px;left:2px;border-left:8px solid transparent;border-right:8px solid transparent;border-bottom:12px solid var(--accent);z-index:2}.chat-avatar.cat-ears:after{content:"";position:absolute;top:-6px;right:2px;border-left:8px solid transparent;border-right:8px solid transparent;border-bottom:12px solid var(--accent);z-index:2}.chat-msg-body{flex:1;min-width:0}.chat-msg-header{display:flex;align-items:baseline;gap:8px}.chat-msg-name{font-weight:600;font-size:15px;color:var(--text-primary);cursor:pointer}.chat-msg-name:hover{text-decoration:underline}.chat-msg-time{font-size:11px;color:var(--text-muted)}.chat-msg-text{color:var(--text-primary);line-height:1.45;margin-top:2px;white-space:pre-wrap;word-wrap:break-word}.chat-msg-text.emoji-only{font-size:2em;line-height:1.2}.chat-quick-replies{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}.chat-quick-reply{font:inherit;font-size:.9em;cursor:pointer;padding:4px 10px;border-radius:var(--studio-radius-round, 999px);border:1px solid var(--accent-line, currentColor);background:transparent;color:var(--accent-text, var(--text-primary))}.chat-quick-reply:hover:not(:disabled){background:var(--accent);color:var(--accent-fg)}.chat-quick-reply:disabled{opacity:.5;cursor:default}.chat-msg-text.emoji-only .chat-emoticon-inline{height:2em}.chat-msg-text code:not(.shiki code):not(.chat-code-block code){background:var(--bg-hover);padding:1px 4px;border-radius:3px;font-family:ui-monospace,monospace;font-size:.9em}.chat-msg-text a{color:var(--link);text-decoration:underline}.chat-msg-text a:hover{text-decoration:none}.chat-msg-text.streaming:after{content:"";display:inline-block;width:6px;height:1em;background:var(--accent);margin-left:2px;vertical-align:text-bottom;border-radius:1px;animation:blink-cursor .8s step-end infinite}.chat-msg-text.streaming:empty:after{content:"";width:auto;height:auto;background:none;animation:none}.chat-msg-text.streaming:empty:before{content:"• • •";letter-spacing:2px;color:var(--text-muted);font-size:18px;animation:thinking-dots 1.4s ease-in-out infinite}@keyframes thinking-dots{0%,to{opacity:.3}50%{opacity:1}}@keyframes blink-cursor{0%,to{opacity:1}50%{opacity:0}}.chat-streaming-cancel{margin-top:4px;padding:2px 10px;border-radius:4px;border:1px solid var(--border);background:var(--bg-hover);color:var(--text-muted);cursor:pointer;font-size:11px}.chat-streaming-cancel:hover{color:var(--text-primary);background:var(--bg-mid)}.chat-spoiler{background:var(--text-primary);color:transparent;border-radius:3px;padding:0 3px;cursor:pointer;transition:all .2s}.chat-spoiler.revealed{background:var(--bg-hover);color:var(--text-primary)}.chat-inverted{background:var(--text-primary);color:var(--bg-dark);padding:0 3px;border-radius:3px}.chat-underline-em{text-decoration:underline;font-style:italic}.chat-msg-action{padding:4px 16px;font-style:italic;color:var(--text-secondary);font-size:14px;position:relative}.chat-msg-action:hover{background:var(--bg-hover)}.chat-msg-action .chat-msg-action-name{font-weight:600;color:var(--text-primary)}.chat-time-gap{margin-top:16px}.chat-input-wrap{position:relative;flex:1;min-width:0}.chat-input-wrap .cm-editor{background:transparent}.chat-input-wrap .cm-editor .cm-content,.chat-input-wrap .cm-editor .cm-scroller{max-height:120px}.chat-msg-continuation{padding:0 16px 0 68px;position:relative}.chat-msg-continuation.has-gif{padding-left:16px;display:flex;gap:12px;align-items:flex-start}.chat-msg-continuation:hover{background:var(--bg-hover)}.chat-msg-inline-time{font-size:10px;color:var(--text-muted);position:absolute;top:100%;right:0;white-space:nowrap;margin-top:2px;pointer-events:none}.chat-msg-gif-inline{width:40px;height:40px;border-radius:4px;object-fit:cover;border:none;display:block;margin-right:6px;flex-shrink:0}.chat-msg-reply-ref{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--text-muted);margin-bottom:2px;padding-left:36px;cursor:pointer;position:relative}.chat-msg-reply-ref:before{content:"";position:absolute;left:20px;top:50%;width:12px;height:12px;border-left:2px solid var(--border);border-top:2px solid var(--border);border-radius:6px 0 0;transform:translateY(-20%)}.chat-msg-reply-ref:hover{color:var(--text-primary)}.chat-msg-reply-ref-avatar{width:16px;height:16px;border-radius:50%;overflow:hidden;flex-shrink:0}.chat-msg-reply-ref-avatar img{width:100%;height:100%;object-fit:cover}.chat-msg-reply-ref-name{font-weight:600;color:var(--text-primary)}.chat-msg-reply-ref-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:300px}.chat-msg-image-wrap{position:relative;display:inline-block;margin-top:4px;max-width:100%}.chat-msg-image{display:block;border-radius:8px;cursor:pointer;width:100%;height:100%;object-fit:cover}.chat-msg-embed{margin-top:6px;border:1px solid var(--border);border-radius:8px;width:100%;height:300px;position:relative;background:var(--bg-surface);display:flex;flex-direction:column}.chat-msg-embed patchwork-view{width:100%;flex:1;min-height:0;display:block;overflow:hidden}.chat-msg-embed-title{padding:0 8px 0 0;font-weight:500;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex-shrink:1;min-width:0}.chat-embed-infobar{display:flex;align-items:center;gap:4px;padding:3px 6px;background:var(--bg-darkest);border-top:1px solid var(--border);font-size:11px;overflow:hidden;flex-wrap:wrap}.chat-embed-pill{display:inline-flex;align-items:center;gap:3px;background:var(--bg-hover);border:1px solid var(--border);border-radius:10px;padding:1px 8px;font-size:10px;color:var(--text-secondary);white-space:nowrap;cursor:default;max-width:200px;overflow:hidden;text-overflow:ellipsis;flex-shrink:0}.chat-embed-pill.clickable{cursor:pointer}.chat-embed-pill.clickable:hover{color:var(--text-primary);border-color:var(--accent-line);background:var(--bg-input)}.chat-embed-pill-label{opacity:.6;font-size:9px;text-transform:uppercase;letter-spacing:.3px}.chat-embed-tool-input{background:var(--bg-darkest);border:1px solid var(--accent-line);border-radius:10px;color:var(--text-primary);font-size:10px;padding:1px 8px;outline:none;width:120px}.chat-embed-tool-menu{position:absolute;top:100%;left:0;z-index:20;background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;padding:2px;box-shadow:0 2px 8px #0000004d;white-space:nowrap;min-width:140px;max-height:200px;overflow-y:auto}.chat-embed-tool-menu button{display:block;width:100%;text-align:left;background:none;border:none;color:var(--text-secondary);font-size:11px;padding:4px 8px;cursor:pointer;border-radius:4px}.chat-embed-tool-menu button:hover{background:var(--bg-hover);color:var(--text-primary)}.chat-embed-tool-menu button.active{color:var(--accent-text);font-weight:600}.chat-embed-tool-menu .tool-menu-input-row{display:flex;gap:4px;padding:4px;border-top:1px solid var(--border);margin-top:2px}.chat-embed-tool-menu .tool-menu-input-row input{flex:1;background:var(--bg-darkest);border:1px solid var(--border);border-radius:4px;color:var(--text-primary);font-size:10px;padding:2px 6px;outline:none;min-width:0}.chat-embed-tool-menu .tool-menu-input-row input:focus{border-color:var(--accent-line)}.chat-embed-url-menu{position:absolute;top:100%;left:0;z-index:20;background:var(--bg-surface);border:1px solid var(--border);border-radius:6px;padding:2px;box-shadow:0 2px 8px #0000004d;white-space:nowrap}.chat-embed-url-menu button{display:block;width:100%;text-align:left;background:none;border:none;color:var(--text-secondary);font-size:11px;padding:4px 10px;cursor:pointer;border-radius:4px}.chat-embed-url-menu button:hover{background:var(--bg-hover);color:var(--text-primary)}.chat-resize-handle{position:absolute;bottom:0;right:0;width:16px;height:16px;cursor:nwse-resize;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s;z-index:5}.chat-msg-image-wrap:hover .chat-resize-handle,.chat-msg-embed:hover .chat-resize-handle{opacity:.6}.chat-resize-handle:hover{opacity:1!important}.chat-resize-handle svg{width:10px;height:10px;color:var(--text-muted)}.chat-rich-blocks{display:flex;flex-direction:column;gap:4px;margin-top:6px}.chat-rich-block{border:1px solid var(--border);border-radius:6px;overflow:hidden;background:var(--bg-darkest);font-size:13px}.chat-rich-block-header{display:flex;align-items:center;gap:6px;padding:5px 10px;cursor:pointer;border:none;background:transparent;color:var(--text-secondary);width:100%;text-align:left;font-size:12px;font-family:monospace}.chat-rich-block-header:hover{background:var(--bg-hover);color:var(--text-primary)}.chat-rich-block-chevron{transition:transform .15s;flex-shrink:0}.chat-rich-block.open .chat-rich-block-chevron{transform:rotate(90deg)}.chat-rich-block-label{opacity:.8}.chat-rich-block-body{border-top:1px solid var(--border);max-height:400px;overflow:auto}.chat-rich-block-code{margin:0;font-size:12px;line-height:1.5}.chat-rich-block-code pre{margin:0;padding:10px;overflow-x:auto}.chat-rich-block-code code{font-family:monospace;white-space:pre}.chat-rich-block-result-label{font-size:11px;color:var(--text-muted);padding:6px 10px 2px;text-transform:uppercase;letter-spacing:.5px;border-top:1px solid var(--border)}.shiki{margin:0!important;padding:10px 12px!important;font-size:13px!important;line-height:1.5!important;overflow-x:auto;border-radius:6px}.shiki code{font-family:ui-monospace,SF Mono,Cascadia Code,Menlo,Consolas,monospace!important}.chat-code-block{background:var(--bg-darkest);border:none;border-radius:6px;padding:0;margin:6px 0;overflow-x:auto;font-size:13px;line-height:1.5}.chat-code-block code{font-family:ui-monospace,SF Mono,Cascadia Code,Menlo,Consolas,monospace;white-space:pre;display:block;padding:10px 12px}.chat-msg-text .shiki{border-radius:6px;border:none;margin:6px 0}.chat-msg-text .shiki code{white-space:pre;display:block}.chat-rich-block-code .shiki{margin:0;border-radius:0}.chat-think-block{background:var(--bg-darkest);border-radius:6px;margin:6px 0;font-size:13px;overflow:hidden}.chat-think-block summary{cursor:pointer;padding:5px 10px;color:var(--text-secondary);font-family:ui-monospace,monospace;font-size:12px;user-select:none;list-style:none}.chat-think-block summary:before{content:"▶ ";display:inline;font-size:10px}.chat-think-block[open] summary:before{content:"▼ "}.chat-think-block summary:hover{background:var(--bg-hover);color:var(--text-primary)}.chat-think-content{padding:8px 12px;white-space:pre-wrap;color:var(--text-secondary);font-family:ui-monospace,monospace;border-top:1px solid var(--bg-hover);max-height:300px;overflow-y:auto}.chat-voice-note{display:flex;align-items:center;gap:8px;margin-top:4px;padding:8px 12px;background:var(--bg-darkest);border-radius:8px;max-width:300px;flex-wrap:wrap}.chat-voice-transcription{width:100%;font-size:13px;color:var(--text-secondary);font-style:italic;padding-left:2px;margin-top:2px}.chat-voice-transcribing{opacity:.5;animation:chat-pulse 1.5s ease-in-out infinite}@keyframes chat-pulse{0%,to{opacity:.5}50%{opacity:.3}}.chat-voice-transcribe-btn{background:none;border:none;color:var(--text-muted);font-size:11px;cursor:pointer;padding:2px 4px;opacity:.6;font-style:italic}.chat-voice-transcribe-btn:hover{opacity:1;text-decoration:underline}.chat-voice-play-btn{width:32px;height:32px;border-radius:50%;background:var(--accent);color:var(--accent-fg);border:none;font-size:14px;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0}.chat-voice-play-btn:hover{background:var(--accent-hover)}.chat-voice-waveform{flex:1;height:24px;display:flex;align-items:center;gap:2px}.chat-voice-bar{width:3px;background:var(--accent);border-radius:2px;min-height:3px}.chat-voice-duration{font-size:12px;color:var(--text-muted);flex-shrink:0}.chat-reactions{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.chat-reaction{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:8px;border:1px solid var(--border);background:var(--bg-dark);font-size:15px;cursor:pointer;user-select:none;transition:all .1s}.chat-reaction:hover{border-color:var(--accent-line);background:var(--bg-hover)}.chat-reaction.mine{border-color:var(--accent-line);background:var(--accent-soft)}.chat-reaction-count{font-size:12px;color:var(--text-secondary);font-weight:500}.chat-reaction-add{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:8px;border:1px dashed var(--border);background:transparent;font-size:16px;cursor:pointer;color:var(--text-muted);transition:all .1s}.chat-reaction-add:hover{border-color:var(--accent-line);color:var(--text-primary);background:var(--bg-hover)}.chat-emoticon-tooltip{position:absolute;z-index:200;pointer-events:none;background:var(--bg-darkest);border:1px solid var(--border);border-radius:8px;padding:8px 12px;box-shadow:0 4px 16px #0000004d;display:none;flex-direction:column;align-items:center;gap:4px;max-width:200px}.chat-emoticon-tooltip.show{display:flex;pointer-events:auto}.chat-emoticon-tooltip-preview{font-size:48px;line-height:1}.chat-emoticon-tooltip-preview img{width:48px;height:48px;object-fit:contain}.chat-emoticon-tooltip-name{font-size:12px;color:var(--text-muted)}.chat-emoticon-tooltip-names{font-size:11px;color:var(--text-secondary);text-align:center}.chat-emoticon-tooltip-adopt{background:var(--accent);color:var(--accent-fg);border:none;cursor:pointer;font-size:11px;padding:2px 10px;border-radius:4px;font-weight:600}.chat-emoticon-tooltip-adopt:hover{opacity:.85}.chat-msg-actions{position:absolute;top:-14px;right:16px;display:none;background:var(--bg-darkest);border:1px solid var(--border);border-radius:4px;z-index:10}.chat-msg-group:hover .chat-msg-actions,.chat-msg-continuation:hover .chat-msg-actions,.chat-msg-action:hover .chat-msg-actions{display:flex}.chat-msg-action-btn{background:none;border:none;color:var(--text-secondary);padding:6px 8px;cursor:pointer;font-size:16px}.chat-msg-action-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.chat-emoji-picker-overlay{position:fixed;inset:0;z-index:100;display:none}.chat-emoji-picker-overlay.show{display:block}.chat-emoji-picker{position:absolute;background:var(--bg-darkest);border:1px solid var(--border);border-radius:8px;padding:8px;box-shadow:0 4px 20px #0000004d;z-index:101;max-width:280px;width:280px;display:flex;flex-direction:column;max-height:320px}.chat-emoji-picker-scroll{overflow-y:auto;overscroll-behavior:contain;min-height:0;flex:1}.chat-emoji-grid{display:flex;flex-wrap:wrap;gap:2px}.chat-emoji-grid button{background:none;border:none;font-size:22px;cursor:pointer;padding:4px;border-radius:4px;width:36px;height:36px;display:flex;align-items:center;justify-content:center}.chat-emoji-grid button:hover{background:var(--bg-hover)}.chat-emoji-active{background:var(--accent)!important;outline:2px solid var(--accent-line);outline-offset:-2px;opacity:.8}.chat-emoji-picker-search{width:100%;padding:6px 10px;background:var(--bg-input);border:1px solid var(--border);border-radius:4px;color:var(--text-primary);font-size:14px;margin-bottom:6px;outline:none;flex-shrink:0}.chat-emoji-picker-search:focus{border-color:var(--accent-line)}.chat-emoticon-section{border-bottom:1px solid var(--border);padding-bottom:6px;margin-bottom:6px}.chat-emoticon-section-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:4px;font-size:11px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px}.chat-emoticon-section-label{font-size:11px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin:6px 0 4px;padding:0 2px}.chat-emoticon-btn{position:relative;width:36px;height:36px;display:flex;align-items:center;justify-content:center;border:none;background:transparent;border-radius:4px;cursor:pointer;padding:2px}.chat-emoticon-btn:hover{background:var(--bg-hover)}.chat-emoticon-img{width:28px;height:28px;object-fit:contain}.chat-emoticon-add-btn{background:none;border:1px dashed var(--border);color:var(--text-muted);cursor:pointer;font-size:11px;padding:2px 8px;border-radius:4px}.chat-emoticon-add-btn:hover{border-color:var(--accent-line);color:var(--text-primary)}.chat-emoticon-grid{display:flex;flex-wrap:wrap;gap:2px}.chat-emoticon-grid button{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;width:36px;height:36px;display:flex;align-items:center;justify-content:center;position:relative}.chat-emoticon-grid button:hover{background:var(--bg-hover)}.chat-emoticon-grid button img{width:28px;height:28px;object-fit:contain}.chat-emoticon-adopt{position:absolute;top:-2px;right:-2px;width:14px;height:14px;border-radius:50%;background:var(--accent);color:var(--accent-fg);border:none;cursor:pointer;font-size:10px;display:none;align-items:center;justify-content:center;line-height:1}.chat-emoticon-grid button:hover .chat-emoticon-adopt{display:flex}.chat-emoticon-remove{position:absolute;top:-4px;right:-4px;width:16px;height:16px;border-radius:50%;background:var(--bg-hover);color:var(--text-muted);border:1px solid var(--border);cursor:pointer;font-size:10px;display:none;align-items:center;justify-content:center;line-height:1}.chat-emoticon-grid button:hover .chat-emoticon-remove{display:flex}.chat-emoticon-remove:hover{background:#ed4245!important;color:#fff!important;border-color:#ed4245!important}.chat-emoticon-remove.confirm{background:#ed4245;color:#fff;border-color:#ed4245;display:flex}.chat-emoticon-inline{height:1.5em;vertical-align:middle;display:inline}.chat-emoticon-dialog{padding:8px;display:flex;flex-direction:column;gap:8px}.chat-emoticon-dialog input[type=text]{width:100%;padding:6px 10px;background:var(--bg-input);border:1px solid var(--border);border-radius:4px;color:var(--text-primary);font-size:14px;outline:none}.chat-emoticon-dialog input[type=text]:focus{border-color:var(--accent-line)}.chat-emoticon-dialog-preview{width:80px;height:80px;border-radius:4px;background:var(--bg-hover);display:flex;align-items:center;justify-content:center;overflow:hidden;align-self:center;color:var(--text-muted);font-size:24px}.chat-emoticon-dialog-preview:hover{background:var(--bg-input);border:1px dashed var(--border)}.chat-emoticon-dialog-preview img{width:100%;height:100%;object-fit:contain}.chat-emoticon-dialog-counter{font-size:11px;color:var(--text-muted);text-align:center}.chat-emoticon-dialog-btns{display:flex;gap:6px;justify-content:flex-end}.chat-emoticon-dialog-btns button{padding:4px 12px;border-radius:4px;font-size:13px;cursor:pointer;border:none}.chat-emoticon-dialog .cancel-btn{background:var(--bg-hover);color:var(--text-primary)}.chat-emoticon-dialog .save-btn{background:var(--accent);color:var(--accent-fg);font-weight:600}.chat-emoticon-dialog .save-btn:disabled{opacity:.5;cursor:default}.chat-font-dialog{padding:8px;display:flex;flex-direction:column;gap:8px}.chat-font-dialog input[type=text]{width:100%;padding:6px 10px;background:var(--bg-input);border:1px solid var(--border);border-radius:4px;color:var(--text-primary);font-size:14px;outline:none}.chat-font-dialog input[type=text]:focus{border-color:var(--accent-line)}.chat-font-dialog-preview{padding:10px;border-radius:4px;background:var(--bg-hover);text-align:center;font-size:18px;color:var(--text-primary);min-height:48px;display:flex;align-items:center;justify-content:center}.chat-font-dialog-filebtn{background:none;border:1px dashed var(--border);color:var(--text-muted);cursor:pointer;font-size:13px;padding:6px 12px;border-radius:4px;text-align:center}.chat-font-dialog-filebtn:hover{border-color:var(--accent-line);color:var(--text-primary)}.chat-font-dialog-btns{display:flex;gap:6px;justify-content:flex-end}.chat-font-dialog-btns button{padding:4px 12px;border-radius:4px;font-size:13px;cursor:pointer;border:none}.chat-font-dialog .cancel-btn{background:var(--bg-hover);color:var(--text-primary)}.chat-font-dialog .save-btn{background:var(--accent);color:var(--accent-fg);font-weight:600}.chat-font-dialog .save-btn:disabled{opacity:.5;cursor:default}.chat-font-list{display:flex;flex-direction:column;gap:2px;max-height:120px;overflow-y:auto;overscroll-behavior:contain}.chat-font-list-item{display:flex;align-items:center;justify-content:space-between;padding:4px 8px;border-radius:4px;font-size:13px;color:var(--text-primary)}.chat-font-list-item:hover{background:var(--bg-hover)}.chat-font-list-item .font-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chat-font-list-remove{width:18px;height:18px;border-radius:50%;background:var(--bg-hover);color:var(--text-muted);border:1px solid var(--border);cursor:pointer;font-size:10px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.chat-font-list-remove:hover,.chat-font-list-remove.confirm{background:#ed4245;color:#fff;border-color:#ed4245}.chat-msg-menu-wrap{position:relative}.chat-msg-menu{display:none;position:absolute;top:100%;right:0;margin-top:2px;background:var(--bg-darkest);border:1px solid var(--border);border-radius:6px;padding:4px 0;min-width:120px;z-index:20;box-shadow:0 4px 12px #0000004d}.chat-msg-menu.show{display:block}.chat-msg-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:6px 12px;background:none;border:none;color:var(--text-primary);font-size:13px;cursor:pointer;text-align:left}.chat-msg-menu-item:hover{background:var(--bg-hover)}.chat-msg-menu-item.danger{color:#ed4245}.chat-msg-menu-item.danger:hover{background:#ed42451a}.chat-typing-bar{padding:0 16px;min-height:22px;font-size:12px;color:var(--text-muted);font-style:italic;flex-shrink:0}.chat-llm-status{padding:0 16px;min-height:22px;font-size:12px;color:var(--text-muted);font-style:italic;flex-shrink:0;font-family:monospace}.chat-stop-btn{display:inline-flex;align-items:center;gap:4px;padding:2px 10px;border:1px solid var(--border);border-radius:4px;background:var(--bg-mid);color:var(--text-secondary);font-size:12px;font-family:inherit;cursor:pointer;font-style:normal}.chat-stop-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.chat-input-wrapper{flex-shrink:0;padding:0 16px 16px;position:relative}.chat-autocomplete{display:none;position:absolute;bottom:100%;left:0;right:0;background:var(--bg-darkest);border:1px solid var(--border);border-radius:8px;max-height:200px;overflow-y:auto;overscroll-behavior:contain;box-shadow:0 -4px 16px #0000004d;z-index:50;margin-bottom:4px}.chat-autocomplete.show{display:block}.chat-autocomplete-item{display:flex;align-items:center;gap:8px;padding:6px 12px;cursor:pointer;font-size:14px;color:var(--text-primary)}.chat-autocomplete-item:hover,.chat-autocomplete-item.active{background:var(--bg-hover)}.chat-autocomplete-item-emoji{font-size:20px;width:28px;text-align:center;flex-shrink:0}.chat-autocomplete-item-emoji img{width:24px;height:24px;object-fit:contain}.chat-autocomplete-item-name{color:var(--text-secondary);font-size:12px}.chat-autocomplete-item-desc{color:var(--text-muted);font-size:11px;margin-left:auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:50%}.chat-autocomplete-item-cmd{font-weight:600;font-size:14px;color:var(--text-primary);min-width:0}.chat-autocomplete-pop{position:fixed;z-index:50;min-width:200px;max-width:340px;max-height:200px;overflow-y:auto;overscroll-behavior:contain;background:var(--editor-fill, Canvas);color:var(--editor-line, currentColor);border:1px solid var(--border);border-radius:8px;box-shadow:0 4px 16px #0000004d}.chat-autocomplete-item-icon{width:20px;height:20px;flex-shrink:0;color:var(--text-muted)}.chat-reply-bar{display:none;padding:8px 12px;background:var(--bg-mid);border-radius:8px 8px 0 0;border-left:3px solid var(--accent-line);align-items:center;gap:8px;font-size:13px;color:var(--text-secondary)}.chat-reply-bar.show{display:flex}.chat-reply-bar-text{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.chat-reply-bar-close{background:none;border:none;font-size:16px;cursor:pointer;color:var(--text-secondary)}.chat-reply-bar-close:hover{color:var(--text-primary)}.chat-paste-preview{display:none;padding:8px 12px;background:var(--bg-mid);align-items:center;gap:8px;flex-wrap:wrap}.chat-paste-preview.show{display:flex}.chat-paste-preview img{max-height:50px;border-radius:4px}.chat-paste-preview video{max-height:50px;border-radius:4px}.chat-paste-preview-close{background:none;border:none;font-size:16px;cursor:pointer;color:var(--text-secondary);margin-left:auto}.chat-paste-file{display:flex;align-items:center;gap:6px;background:var(--bg-hover);border-radius:6px;padding:4px 8px;font-size:12px;color:var(--text-secondary);max-width:200px}.chat-paste-file-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chat-paste-file-remove{background:none;border:none;cursor:pointer;color:var(--text-secondary);padding:0;display:flex;align-items:center}.chat-paste-file-remove:hover{color:var(--text-primary)}.chat-paste-embed{display:flex;align-items:center;gap:6px;background:var(--bg-hover);border-radius:6px;padding:4px 8px;font-size:12px;color:var(--text-secondary);max-width:200px}.chat-paste-embed-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chat-selection-chip{display:inline-flex;align-items:center;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:var(--bg-hover);color:var(--text-secondary);border-radius:6px;padding:2px 8px;margin:0 4px;font-size:12px}.chat-paste-embed-remove{background:none;border:none;cursor:pointer;color:var(--text-secondary);padding:0;display:flex;align-items:center}.chat-paste-embed-remove:hover{color:var(--text-primary)}.chat-sidebar-pinned-wrap{position:relative}.chat-sidebar-pinned-wrap[data-drop-position=above]:before{content:"";position:absolute;top:-2px;left:4px;right:4px;height:2px;background:var(--accent);border-radius:1px;z-index:10}.chat-sidebar-pinned-wrap[data-drop-position=below]:after{content:"";position:absolute;bottom:-2px;left:4px;right:4px;height:2px;background:var(--accent);border-radius:1px;z-index:10}.chat-sidebar-pinned-wrap.dragging{opacity:.4}.chat-drop-overlay{display:none;position:absolute;inset:0;z-index:100;background:color-mix(in oklch,var(--theme) 20%,black 60%);align-items:center;justify-content:center;font-size:18px;color:var(--text-primary);font-weight:600;border:3px dashed var(--accent-line);border-radius:12px;pointer-events:none}.chat-drop-overlay.show{display:flex}.chat-msg-video-wrap{max-width:350px;border-radius:8px;overflow:hidden;margin-top:4px;position:relative}.chat-msg-video{width:100%;display:block;border-radius:8px;cursor:pointer}.chat-lightbox{display:none;position:absolute;inset:0;z-index:200;background:#000000d9;align-items:center;justify-content:center;cursor:zoom-out}.chat-lightbox.show{display:flex}.chat-lightbox img,.chat-lightbox video{max-width:95%;max-height:95%;object-fit:contain;border-radius:4px;cursor:default}.chat-lightbox video{background:#000}.chat-msg-file{display:inline-flex;align-items:center;gap:6px;background:var(--bg-hover);border-radius:6px;padding:6px 10px;margin-top:4px;font-size:13px;color:var(--text-secondary);cursor:pointer;text-decoration:none}.chat-msg-file:hover{background:var(--bg-input);color:var(--text-primary)}.chat-msg-file-icon{flex-shrink:0}.chat-input-row{display:flex;gap:0;background:var(--bg-mid);border:1px solid var(--border);border-radius:8px;padding:3px;align-items:flex-end}.chat-input{width:100%;padding:8px 12px;border:none;font-size:15px;outline:none;background:transparent;color:var(--text-primary);font-family:inherit;resize:none;max-height:120px;min-height:24px;line-height:1.4;position:relative;z-index:1}.chat-input::placeholder{color:var(--text-muted)}.chat-input-btn{width:36px;height:36px;background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:20px;border-radius:4px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.chat-input-btn:hover{color:var(--text-primary)}.chat-input-btn.recording{color:#ed4245;animation:pulse 1s infinite}@keyframes pulse{0%,to{transform:scale(1)}50%{transform:scale(1.15)}}.chat-recording-bar{display:flex;align-items:center;gap:10px;background:var(--bg-input);border-radius:8px;padding:8px 12px;animation:fadeIn .15s ease}.chat-recording-overlay{position:absolute;inset:0;z-index:3}@keyframes fadeIn{0%{opacity:0;transform:scale(.98)}to{opacity:1;transform:scale(1)}}.chat-recording-dot{width:10px;height:10px;border-radius:50%;background:#ed4245;flex-shrink:0;animation:recPulse 1s ease-in-out infinite}@keyframes recPulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.8)}}.chat-recording-time{font-size:14px;color:var(--text-primary);font-variant-numeric:tabular-nums;min-width:40px}.chat-recording-viz{flex:1;height:24px;display:flex;align-items:center;gap:2px;overflow:hidden}.chat-recording-viz-bar{width:3px;border-radius:2px;background:var(--accent);min-height:3px;transition:height .1s ease}.chat-recording-cancel{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:13px;padding:4px 10px;border-radius:4px}.chat-recording-cancel:hover{color:var(--text-primary);background:var(--bg-hover)}.chat-recording-send{background:var(--accent);color:var(--accent-fg);border:none;cursor:pointer;padding:6px 14px;border-radius:6px;font-size:13px;font-weight:600}.chat-recording-send:hover{background:var(--accent-hover)}.chat-gif-toggle{width:36px;height:36px;border:none;cursor:pointer;border-radius:4px;display:flex;align-items:center;justify-content:center;flex-shrink:0;background:none;color:var(--text-muted);font-size:20px;position:relative;overflow:hidden}.chat-gif-toggle:hover{color:var(--text-primary)}.chat-gif-toggle.active{color:var(--accent-text)}.chat-gif-toggle video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:4px;display:none}.chat-gif-toggle.active video{display:block}.chat-gif-toggle.active .chat-gif-icon{display:none}.chat-gif-toggle.recording{pointer-events:none;position:relative;overflow:visible}.chat-gif-progress{position:absolute;top:-10px;left:-10px;width:calc(100% + 20px);height:calc(100% + 20px);z-index:20;pointer-events:none}.chat-gif-progress circle.chat-gif-progress-bg{fill:none;stroke:#00000026;stroke-width:2}.chat-gif-progress circle.chat-gif-progress-fg{fill:none;stroke:var(--accent-line);stroke-width:2;stroke-linecap:round;transform:rotate(-90deg);transform-origin:center;transition:stroke-dashoffset .1s linear}.chat-input-row.processing .chat-input,.chat-input-row.processing .chat-input-wrap,.chat-input-row.processing .chat-input-btn{opacity:.5;pointer-events:none}.chat-empty{flex:1;display:flex;align-items:center;justify-content:center;color:var(--text-muted);font-size:16px}@keyframes chat-skeleton-pulse{0%,to{opacity:.3}50%{opacity:.6}}.chat-msg-loading{opacity:.5}.chat-skeleton{background:var(--bg-hover);animation:chat-skeleton-pulse 1.5s ease-in-out infinite}.chat-skeleton-line{height:14px;background:var(--bg-hover);border-radius:4px;margin:4px 0;animation:chat-skeleton-pulse 1.5s ease-in-out infinite;width:60%}.chat-skeleton-line.short{width:30%}.chat-main{display:flex;flex-direction:column;flex:1;min-width:0;position:relative;height:100%}.chat-sidebar{display:none;flex-direction:column;width:40%;min-width:15%;border-left:1px solid var(--border);background:var(--bg-darkest);overflow:hidden;position:relative}.chat-sidebar.visible{display:flex}.chat-sidebar.drop-target{display:flex;min-width:60px;width:60px;align-items:center;justify-content:center;border:2px dashed var(--accent-line);background:color-mix(in oklch,var(--accent) 10%,var(--bg-darkest))}.chat-sidebar.drop-target:after{content:"Pin";font-size:11px;color:var(--accent-text);font-weight:600;pointer-events:none}.chat-sidebar.visible.drop-target{width:40%;min-width:15%}.chat-sidebar.visible.drop-target:after{display:none}.chat-sidebar.collapsed{width:0!important;min-width:0!important;border-left:none;overflow:hidden}.chat-root.sidebar-left{flex-direction:row-reverse}.chat-root.sidebar-left .chat-sidebar{border-left:none;border-right:1px solid var(--border)}.chat-root.sidebar-left .chat-sidebar-resize{left:auto;right:-3px}.chat-sidebar-resize{position:absolute;left:-3px;top:0;bottom:0;width:6px;cursor:col-resize;z-index:10}.chat-sidebar-resize:hover,.chat-sidebar-resize.dragging{background:var(--accent);opacity:.3}.chat-sidebar-header{display:flex;align-items:center;justify-content:space-between;padding:4px 6px;border-bottom:1px solid var(--border);flex-shrink:0}.chat-sidebar-header-title{font-size:11px;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px}.chat-sidebar-collapse-btn{background:none;border:none;cursor:pointer;padding:2px 4px;color:var(--text-muted);display:flex;align-items:center}.chat-sidebar-collapse-btn:hover{color:var(--text-primary)}.chat-sidebar-pinned{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:0;padding:4px}.chat-sidebar-pinned:empty{display:none}.chat-sidebar-pinned-wrap{position:relative;display:flex;flex-direction:column;flex:1;min-height:200px;border:1px solid var(--border);border-radius:6px;overflow:hidden;margin-bottom:4px;background:var(--bg-mid)}.chat-sidebar-pinned-toolbar{position:absolute;top:4px;right:4px;z-index:10;display:flex;gap:2px;opacity:0;transition:opacity .15s;pointer-events:auto}.chat-sidebar-pinned-wrap:hover .chat-sidebar-pinned-toolbar{opacity:1}.chat-sidebar-pinned-toolbar button{background:var(--bg-darkest);border:1px solid var(--border);border-radius:4px;color:var(--text-muted);cursor:pointer;padding:2px 4px;font-size:10px;display:flex;align-items:center;gap:2px;line-height:1}.chat-sidebar-pinned-toolbar button:hover{color:var(--text-primary);background:var(--bg-mid)}.chat-sidebar-pinned-toolbar button svg{width:12px;height:12px}.chat-sidebar-pinned iframe{width:100%;flex:1;border:none;border-radius:4px;min-height:200px;background:var(--bg-mid)}.chat-sidebar-pinned-info{background:var(--bg-darkest);border-bottom:1px solid var(--border);font-size:11px;color:var(--text-secondary)}.chat-sidebar-pinned-info-main{display:flex;align-items:center;gap:4px;padding:3px 8px;cursor:pointer}.chat-sidebar-pinned-info-main:hover{background:var(--bg-hover)}.chat-sidebar-pinned-info-title{flex:1;font-weight:600;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px}.chat-sidebar-pinned-info-chevron{font-size:10px;transition:transform .15s;flex-shrink:0}.chat-sidebar-pinned-info-chevron.open{transform:rotate(90deg)}.chat-sidebar-pinned-info-details{padding:2px 8px 4px}.chat-sidebar-pinned-info-row{display:flex;align-items:center;gap:4px;padding:1px 0}.chat-sidebar-pinned-info-label{color:var(--text-muted);font-size:10px;min-width:24px;flex-shrink:0}.chat-sidebar-pinned-info-value{font-family:monospace;font-size:10px;color:var(--text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chat-sidebar-pinned-info-url{cursor:pointer}.chat-sidebar-pinned-info-url:hover{color:var(--text-primary);text-decoration:underline}.chat-sidebar-pinned-info-editable{cursor:pointer;border-bottom:1px dashed var(--text-muted)}.chat-sidebar-pinned-info-editable:hover{color:var(--text-primary)}.chat-sidebar-pinned-info-input{font-family:monospace;font-size:10px;background:var(--bg-input);border:1px solid var(--border);border-radius:3px;color:var(--text-primary);padding:1px 4px;flex:1;min-width:0}.chat-sidebar-pinned-resize-handle{height:6px;cursor:row-resize;flex-shrink:0;background:transparent;position:relative}.chat-sidebar-pinned-resize-handle:after{content:"";position:absolute;left:20%;right:20%;top:2px;height:2px;border-radius:1px;background:var(--border);opacity:0;transition:opacity .15s}.chat-sidebar-pinned-resize-handle:hover:after,.chat-sidebar-pinned-resize-handle.active:after{opacity:1}.chat-sidebar-pinned-resize-handle.active:after{background:var(--accent)}.chat-sidebar-status{padding:4px 8px;font-size:11px;color:var(--text-muted);text-align:center}.chat-sidebar-toggle-btn{background:none;border:none;color:var(--text-muted);cursor:pointer;padding:2px 4px;border-radius:4px;display:flex;align-items:center}.chat-sidebar-toggle-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.chat-embed-pin{cursor:pointer}.chat-embed-pin.pinned{color:var(--accent-text)}.chat-msg-name-computer{color:var(--accent-text);font-style:italic}.chat-avatar.computer{background:var(--accent-soft);overflow:hidden}.chat-avatar.computer img{width:100%;height:100%;object-fit:cover;display:block}.computer-presence img{width:100%;height:100%;object-fit:cover;display:block;border-radius:50%}.chat-dialog-overlay{position:fixed;inset:0;z-index:100;background:#00000080;display:flex;align-items:center;justify-content:center;animation:fadeIn .15s ease}.chat-emoticon-dialog,.chat-font-dialog{background:var(--bg-dark);border:1px solid var(--border);border-radius:8px;min-width:300px;max-width:400px;box-shadow:0 8px 32px #0006}.chat-plugin-panel{background:var(--bg-dark);border:1px solid var(--border);border-radius:8px;min-width:300px;max-width:420px;max-height:70vh;display:flex;flex-direction:column;box-shadow:0 8px 32px #0006}.chat-plugin-panel-header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--border);font-size:14px;font-weight:600}.chat-plugin-panel-close{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:18px;line-height:1}.chat-plugin-panel-close:hover{color:var(--text-primary)}.chat-plugin-panel-body{padding:6px;overflow-y:auto;display:flex;flex-direction:column;gap:1px}.chat-plugin-section{font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:var(--text-muted);padding:10px 6px 4px}.chat-plugin-item{display:flex;align-items:center;gap:8px;padding:5px 6px;border-radius:4px;cursor:pointer;font-size:13px;color:var(--text-primary)}.chat-plugin-item:hover{background:var(--bg-hover)}.chat-plugin-item input{cursor:pointer}.chat-plugin-item-locked,.chat-plugin-item-locked input{cursor:default}.chat-plugin-item-locked{opacity:.55}.chat-plugin-item-locked:hover{background:none}.chat-plugin-id{margin-left:auto;font-family:ui-monospace,monospace;font-size:11px;color:var(--text-muted)}.chat-emoticon-dialog-header,.chat-font-dialog-header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--border);font-size:14px;font-weight:600}.chat-emoticon-dialog-close,.chat-font-dialog-close{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:18px;line-height:1}.chat-emoticon-dialog-close:hover,.chat-font-dialog-close:hover{color:var(--text-primary)}.chat-emoticon-dialog-body,.chat-font-dialog-body{padding:12px;display:flex;flex-direction:column;gap:8px}.chat-emoticon-dialog-footer,.chat-font-dialog-footer{display:flex;gap:6px;justify-content:flex-end;padding:8px 12px;border-top:1px solid var(--border)}.chat-emoticon-dialog-footer button,.chat-font-dialog-footer button{padding:6px 14px;border-radius:6px;font-size:13px;cursor:pointer;border:none}.chat-emoticon-dialog-save,.chat-font-dialog-save{background:var(--accent);color:var(--accent-fg);font-weight:600}.chat-emoticon-dialog-save:disabled,.chat-font-dialog-save:disabled{opacity:.5;cursor:default}.chat-emoticon-dialog-save:not(:disabled):hover,.chat-font-dialog-save:not(:disabled):hover{background:var(--accent-hover)}.chat-emoticon-dialog-nav{display:flex;align-items:center;justify-content:center;gap:8px;font-size:12px;color:var(--text-muted)}.chat-emoticon-dialog-nav button{background:none;border:1px solid var(--border);color:var(--text-secondary);cursor:pointer;padding:2px 8px;border-radius:4px;font-size:12px}.chat-emoticon-dialog-nav button:disabled{opacity:.4;cursor:default}.chat-emoticon-dialog-nav button:not(:disabled):hover{background:var(--bg-hover)}.chat-emoticon-dialog-name,.chat-font-dialog-name{width:100%;padding:6px 10px;background:var(--bg-input);border:1px solid var(--border);border-radius:4px;color:var(--text-primary);font-size:14px;outline:none}.chat-emoticon-dialog-name:focus,.chat-font-dialog-name:focus{border-color:var(--accent-line)}.chat-font-dialog-list{display:flex;flex-direction:column;gap:2px;max-height:120px;overflow-y:auto}.chat-font-dialog-item{display:flex;align-items:center;justify-content:space-between;padding:4px 8px;border-radius:4px;font-size:13px}.chat-font-dialog-item:hover{background:var(--bg-hover)}.chat-font-dialog-remove{width:20px;height:20px;border-radius:50%;background:var(--bg-hover);color:var(--text-muted);border:1px solid var(--border);cursor:pointer;font-size:12px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.chat-font-dialog-remove:hover{background:#ed4245;color:#fff;border-color:#ed4245}.chat-font-dialog-choose{background:none;border:1px dashed var(--border);color:var(--text-muted);cursor:pointer;font-size:13px;padding:8px 12px;border-radius:4px;text-align:center;width:100%}.chat-font-dialog-choose:hover{border-color:var(--accent-line);color:var(--text-primary)}.chat-font-dialog-preview{padding:10px;border-radius:4px;background:var(--bg-hover);text-align:center;font-size:16px;color:var(--text-primary)}.chat-gif-toggle .chat-gif-progress{position:absolute;inset:-4px;width:calc(100% + 8px);height:calc(100% + 8px);z-index:20;pointer-events:none}.chat-time-gap{text-align:center;color:var(--text-muted);font-size:11px;padding:8px 0 4px;position:relative}.chat-time-gap:before{content:"";position:absolute;left:20%;right:20%;top:50%;border-top:1px solid var(--border);z-index:0}.chat-time-gap span{position:relative;z-index:1;background:var(--bg-dark);padding:0 8px}.chat-model-dialog{background:var(--bg-mid);border:1px solid var(--border);border-radius:8px;width:420px;max-width:90vw;padding:0;overflow:hidden}.chat-model-dialog-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid var(--border);font-weight:600;font-size:14px}.chat-model-dialog-close{background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:20px;padding:0 4px}.chat-model-dialog-close:hover{color:var(--text-primary)}.chat-model-dialog-tabs{display:flex;border-bottom:1px solid var(--border)}.chat-model-dialog-tabs button{flex:1;background:none;border:none;color:var(--text-secondary);padding:8px 12px;cursor:pointer;font-size:13px;border-bottom:2px solid transparent}.chat-model-dialog-tabs button:hover{color:var(--text-primary)}.chat-model-dialog-tabs button.active{color:var(--accent-text);border-bottom-color:var(--accent-line)}.chat-model-dialog-body{padding:12px 16px;min-height:120px}.chat-model-dialog-label{display:block;font-size:12px;color:var(--text-secondary);margin-bottom:10px}.chat-model-dialog-input{display:block;width:100%;margin-top:4px;padding:6px 8px;background:var(--bg-input);border:1px solid var(--border);border-radius:4px;color:var(--text-primary);font-size:13px;outline:none}.chat-model-dialog-input:focus{border-color:var(--accent-line)}select.chat-model-dialog-input{flex:1}.chat-model-dialog-btn{background:var(--bg-hover);border:1px solid var(--border);border-radius:4px;color:var(--text-primary);padding:6px 12px;cursor:pointer;font-size:13px}.chat-model-dialog-btn:hover{background:var(--accent-soft)}.chat-model-dialog-btn.primary{background:var(--accent);color:var(--accent-fg);border-color:var(--accent-line)}.chat-model-dialog-btn.primary:hover{opacity:.9}.chat-model-dialog-footer{display:flex;gap:8px;justify-content:flex-end;padding:12px 16px;border-top:1px solid var(--border)}@media (max-width: 600px){.chat-root,.chat-root.sidebar-left{flex-direction:column-reverse!important}.chat-sidebar{width:100%!important;min-width:0!important;border-left:none!important;border-right:none!important;border-bottom:1px solid var(--border);max-height:50%}.chat-sidebar.visible{max-height:50%}.chat-sidebar.drop-target{width:100%!important;min-width:0!important;height:60px}.chat-sidebar.visible.drop-target{width:100%!important}.chat-sidebar-resize{display:none}.chat-msg-group{padding:2px 10px;gap:8px}.chat-msg-continuation{padding:0 10px 0 48px}.chat-msg-continuation.has-gif{padding-left:10px}.chat-msg-action{padding:4px 10px}.chat-avatar-col{width:30px}.chat-avatar{width:30px;height:30px;font-size:14px}.chat-msg-gif-inline{width:30px;height:30px}.chat-presence-bar{padding:4px 10px;gap:6px;flex-wrap:wrap}.chat-input-wrapper{padding:0 8px 8px}.chat-input{padding:6px 8px;font-size:14px}.chat-input-btn,.chat-gif-toggle{width:32px;height:32px;font-size:18px}.chat-reply-bar{padding:6px 8px;font-size:12px}.chat-msg-reply-ref{padding-left:24px;font-size:12px}.chat-msg-reply-ref:before{left:12px}.chat-msg-reply-ref-text{max-width:180px}.chat-voice-note{max-width:100%}.chat-msg-embed{height:200px}.chat-msg-video-wrap,.chat-msg-image-wrap{max-width:100%}.chat-code-block code{font-size:12px}.shiki{font-size:12px!important}.chat-emoji-picker{max-width:260px;width:260px}.chat-emoticon-dialog,.chat-font-dialog{min-width:0;max-width:calc(100vw - 24px);width:calc(100vw - 24px)}.chat-model-dialog{width:calc(100vw - 24px)}.chat-autocomplete-item{padding:6px 8px;font-size:13px}.chat-typing-bar,.chat-llm-status{padding:0 10px}.chat-recording-bar{padding:6px 8px}.chat-sidebar-pinned-wrap{min-height:120px}.chat-sidebar-toggle-btn svg,.chat-sidebar-collapse-btn svg{transform:rotate(90deg)}.chat-time-gap:before{left:10%;right:10%}}')),document.head.appendChild(e)}}catch(t){console.error("vite-plugin-css-injected-by-js",t)}})();
2
- import { p as r } from "./index-d8BugVrl.js";
2
+ import { p as r } from "./index-Db7mD_tU.js";
3
3
  export {
4
4
  r as plugins
5
5
  };
@@ -1,5 +1,5 @@
1
1
  import { render as p, createComponent as c } from "solid-js/web";
2
- import { s as e, C as u } from "./ChatRoot-CgnJ5YGo.js";
2
+ import { s as e, C as u } from "./ChatRoot-C2Bt2HnE.js";
3
3
  function C(t, o) {
4
4
  e(o.repo), getComputedStyle(o).position === "static" && (o.style.position = "relative");
5
5
  const s = p(() => c(u, {
@@ -23,7 +23,7 @@
23
23
  "dependencies": {
24
24
  "@automerge/automerge": "^3.2.1",
25
25
  "@automerge/automerge-repo": "^2.5.0",
26
- "@chee/patchwork-llm": "automerge:HaCFnBBADdADqJm4Bu5Sc4abQyE#26oUrk4Jj3kBUbJjGEr1SuQLskBBxxihaWGWL4g7jTPvwM9TM3",
26
+ "@chee/patchwork-llm": "^0.2.1",
27
27
  "@chee/patchwork-transcript": "automerge:2AdvAyQ85NfazBA4TtDyRYCqfvYb#RUCqgHPjqB8fwhZczav5rwJ9J7rBLj3rSfQ9ykaCkR3HrEN2n",
28
28
  "@inkandswitch/patchwork-elements": "^0.0.5",
29
29
  "@inkandswitch/patchwork-filesystem": "^0.1.2",