@inkandswitch/patchwork-pkg-base 0.0.33 → 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",
@@ -0,0 +1,2 @@
1
+ import{a as We,b as H,c as V,d as oe,e as ne,f as se,g as ie,h as ae,i as ce,j as le,k as de,l as ue,m as fe,n as me,o as P,p as he,q as pe,r as ge,s as we}from"./chunk-ECU6ZS3G.js";import{a as N,b as be}from"./chunk-3H5MX256.js";import{b as Oe}from"./chunk-FW4363Y4.js";import{template as y}from"solid-js/web";import{delegateEvents as st}from"solid-js/web";import{memo as it}from"solid-js/web";import{setStyleProperty as at}from"solid-js/web";import{setAttribute as q}from"solid-js/web";import{effect as x}from"solid-js/web";import{insert as _}from"solid-js/web";import{createComponent as u}from"solid-js/web";import{getOwner as U}from"solid-js/web";import{use as C}from"solid-js/web";import"@inkandswitch/patchwork-elements";import{parseAutomergeUrl as At,stringifyAutomergeUrl as xt}from"@automerge/automerge-repo";import{interpretAsDocumentId as Ft,isValidAutomergeUrl as Mt,parseAutomergeUrl as Ht,stringifyAutomergeUrl as Vt}from"@automerge/automerge-repo";function ve(e,c,l){let a=e.closest("patchwork-view")??e,t=new MessageChannel,r=t.port2,s=new AbortController,{signal:n}=s;r.addEventListener("message",m=>{m.data?.type==="change"&&l(m.data.value)},{signal:n}),r.start();let i={selector:c,port:t.port1};return a.dispatchEvent(new CustomEvent("patchwork:subscribe",{detail:i,bubbles:!0,composed:!0})),()=>{n.aborted||(s.abort(),r.postMessage({type:"unsubscribe"}),r.close())}}import{template as j}from"solid-js/web";import{delegateEvents as He}from"solid-js/web";import{memo as Ve}from"solid-js/web";import{insert as _e}from"solid-js/web";import{createComponent as A}from"solid-js/web";import{For as ze,Show as B}from"solid-js";var Ne=j("<div class=threepane-widgets>"),Be=j("<div class=threepane-widgets__empty><button type=button class=threepane-widgets__add>\uFF0B Add document list"),je=j("<div class=threepane-widget>"),qe="chee/document-list";function ye(e){let c=()=>{let l=e.rootFolderUrl(),o=e.configHandle();!l||!o||o.change(a=>{a.sidebar.widgets.push([qe,l])})};return(()=>{var l=Ne();return _e(l,A(B,{get when(){return e.ready()},get children(){return A(B,{get when(){return e.widgets().length},get fallback(){return A(B,{get when(){return Ve(()=>!!e.rootFolderUrl())()&&e.configHandle()},get children(){var o=Be(),a=o.firstChild;return a.$$click=c,o}})},get children(){return A(ze,{get each(){return e.widgets()},children:o=>(()=>{var a=je();return _e(a,A(P,{slot:o})),a})()})}})}})),l})()}He(["click"]);import{template as De}from"solid-js/web";import{setAttribute as Ye}from"solid-js/web";import{effect as Ke}from"solid-js/web";import{insert as Se}from"solid-js/web";import{createComponent as z}from"solid-js/web";import{For as Je,Show as Qe}from"solid-js";var Xe=De("<div class=frame-tray>"),Ge=De("<div class=frame-tray__item>");function ke(e){return z(Qe,{get when(){return e.slots().length},get children(){var c=Xe();return Se(c,z(Je,{get each(){return e.slots()},children:l=>(()=>{var o=Ge();return Se(o,z(P,{slot:l})),Ke(()=>Ye(o,"data-tray-id",me(l))),o})()})),c}})}import{createEffect as L,createMemo as X,createSignal as b,onCleanup as k,onMount as G,Show as E}from"solid-js";import{render as bt}from"solid-js/web";import{createDocOfDatatype2 as et}from"@inkandswitch/patchwork-plugins";import{getRegistry as Ze}from"@inkandswitch/patchwork-plugins";function O(e){return Ze("patchwork:datatype").loadWhenReady(e)}var tt=new Set(["document-title","spacer"]),rt="chee/document-list";function $e(e){return e?[[rt,e]]:[]}async function Ce(e,c){let l=e.doc()?.rootFolderUrl,o=e.doc()?.tools?.threepane;if(o){(await c.find(o)).change(i=>{l&&!i.sidebar?.widgets?.length&&(i.sidebar.widgets=$e(l)),i.tray||(i.tray=N.slice()),i.doctitle?.tools?.length||(i.doctitle={...i.doctitle,tools:be.slice()})});return}let a=await O("threepane:config");if(!a){console.warn("frame: threepane:config datatype never registered");return}if(e.doc()?.tools?.threepane)return;let t=e.doc(),r=(t?.documentToolbarToolIds??[]).filter(n=>!tt.has(n)),s=await et(a,c);s.change(n=>{r.length&&(n.doctitle.tools=r),n.sidebar.widgets=$e(t?.rootFolderUrl),n.tray||(n.tray=N.slice())}),e.change(n=>{n.tools||(n.tools={}),n.tools.threepane||(n.tools.threepane=s.url)})}var Ie=Oe(We(),1);import{createDocOfDatatype2 as ot}from"@inkandswitch/patchwork-plugins";var w=(0,Ie.default)("patchwork:threepane:examples");async function Ue(e,c){let l=e.doc();if(!l?.rootFolderUrl){w("skipped \u2014 account has no rootFolderUrl");return}if(l.exampleDocsSeededAt){w("skipped \u2014 already ran for this account at",new Date(l.exampleDocsSeededAt).toISOString());return}w("claiming marker on account",e.url),e.change(i=>{i.exampleDocsSeededAt||(i.exampleDocsSeededAt=Date.now())});let o=await c.find(l.rootFolderUrl),a=o.doc()?.docs?.length??0;if(a){w(`skipped \u2014 root folder already has ${a} doc(s); only fresh accounts are seeded`);return}let t=await nt();if(w("bundle init scripts:",t),!t.length){w("skipped \u2014 no static module bundles to ask");return}let r=await O("folder");if(!r){w("folder datatype never registered; giving up");return}let s=await ot(r,c,i=>{i.title="Examples"});for(let i of t)try{await(await import(i)).default?.(c,s),w("ran init script",i)}catch(m){w("init script unavailable or failed",i,m)}let n=s.doc()?.docs?.length??0;if(!n){w("no bundle contributed any documents");return}o.change(i=>{i.docs.unshift({name:"Examples",type:"folder",url:s.url})}),w(`seeded ${n} document(s) into Examples folder`,s.url)}var Ee="https://patchwork-tools.netlify.app/init.js",Re="https://patchwork-base.netlify.app/init.js";async function nt(){let e=window.patchwork?.packages;if(!e?.urls)return[Re,Ee];await e.doneLoading;let c=Object.values(e.urls).filter(o=>typeof o=="string"&&!o.startsWith("automerge:")).map(o=>new URL("init.js",new URL(o,document.baseURI)).href),l=c.length?[]:[Re];return[...new Set([...c,...l,Ee])]}var ct=y("<div class=frame-shell><aside class=frame-warning-banner>research grade software. do not share links. sharing a doc is sharing your account.</aside><div class=frame><patchwork-view component=patchwork-selected-doc-provider><patchwork-view component=patchwork-account-provider><patchwork-view component=patchwork-tool-storage-provider>",!0,!1,!1),lt=y("<div style=display:contents>"),dt=y("<div class=main-area>"),ut=y("<div class=frame__popover-backdrop><div class=frame__popover role=dialog aria-modal=true><div class=frame__popover-toolbar><patchwork-view tool-id=doc-openwith></patchwork-view></div><div class=frame__popover-body><patchwork-view>",!0,!1,!1),ft=y('<button type=button class="frame__sidebar-toggle frame__left-toggle">'),mt=y("<div class=threepane-sidebar><div class=threepane-sidebar__footer><footer class=threepane-account-bar><button type=button class=threepane-account-bar__button>Settings"),ht=y("<div class=frame__tray-dock>"),pt=y('<button type=button class="threepane-account-bar__button threepane-account-bar__avatar"title=Account aria-label=Account><patchwork-view tool-id=contact-avatar>',!0,!1,!1),gt=y("<button type=button class=threepane-account-bar__button>Packages"),wt=y('<svg xmlns=http://www.w3.org/2000/svg width=18 height=18 viewBox="0 0 24 24"fill=none stroke=var(--studio-chrome-line) stroke-width=1.75 stroke-linecap=round stroke-linejoin=round><rect width=18 height=18 x=3 y=3 rx=2></rect><path d="M9 3v18">'),vt=180,_t=720,yt=120,St=3,Y=(e,c)=>{let[l,o]=b(!1);return L(()=>{let a=c();if(!a)return;o(!1);let t=r=>{r.detail?.componentId===e&&o(!0)};a.addEventListener("patchwork:mounted",t),k(()=>a.removeEventListener("patchwork:mounted",t))}),l};function K(e,c){e.dispatchEvent(new CustomEvent("patchwork:open-document",{detail:c,bubbles:!0,composed:!0}))}function Dt({handle:e,repo:c,...l}){ge();let o=e.url,[a,t]=b(),r=Y("patchwork-account-provider",a),[s,n]=b(),i=Y("patchwork-tool-storage-provider",s),[m,d]=b(),h=Y("patchwork-selected-doc-provider",m),p=X(()=>h()&&r()&&i());return(()=>{var S=ct(),g=S.firstChild,W=g.nextSibling,T=W.firstChild,R=T.firstChild,I=R.firstChild;return C(d,T),T._$owner=U(),C(t,R),R.docUrl=o,R._$owner=U(),C(n,I),I.docUrl=o,I._$owner=U(),_(I,u(E,{get when(){return p()},get children(){return u(kt,{handle:e,repo:c,get isolation(){return l.isolation}})}})),S})()}function kt(e){let c=H(()=>e.handle.url,{repo:e.repo});(async()=>{await Ce(e.handle,e.repo),await Ue(e.handle,e.repo)})().catch(f=>{console.error("frame: account bootstrap failed",f)});let[l,o]=b(0);L(()=>{let f=c();if(!f)return;let v=()=>o(D=>D+1);f.on("change",v),k(()=>f.off("change",v))});let a=X(()=>(l(),c()?.doc())),t=e.handle.url,r=()=>a()?.tools?.threepane,s=H(()=>r(),{repo:e.repo}),[n,i]=b(0);L(()=>{let f=s();if(!f)return;let v=()=>i(D=>D+1);f.on("change",v),k(()=>f.off("change",v))});let m=X(()=>(n(),s()?.doc())),d=()=>m()?.doctitle?.tools,h=()=>m()?.sidebar?.widgets??[],p=()=>m()?.tray??[],S=()=>a()?.rootFolderUrl,g=ae(),W=ce({setLeftSidebarWidth:g.setLeftSidebarWidth,setRightSidebarWidth:g.setRightSidebarWidth,setIsSidebarCollapsed:g.setIsSidebarCollapsed,setIsRightSidebarCollapsed:g.setIsRightSidebarCollapsed,isLeftCollapsed:g.isSidebarCollapsed,isRightCollapsed:g.isRightSidebarCollapsed,minWidth:vt,maxWidth:_t,autoCloseWidth:yt,dragThreshold:St}),{events:T,dismissEvent:R,clearAll:I}=de(),F,[J,Le]=b(null),[Te,Q]=b(null);G(()=>{let f=ve(F,{type:"patchwork:selected-view"},v=>Le(v));k(f)});let $=()=>J()?.url,M=()=>J()?.toolId??void 0,Z=()=>se(V.rightWidth,ne),ee=()=>ie(V.rightCollapsed),[Ae,te]=b(),xe=le(Ae,$),[re,Pe]=b(!1);return L(()=>{re()||(e.isolation||!$()||xe())&&Pe(!0)}),(()=>{var f=lt(),v=F;return typeof v=="function"?C(v,f):F=f,_(f,u(ue,{get events(){return T()},onDismiss:R,onClearAll:I}),null),_(f,u(Ct,{accountDocUrl:t,sidebarState:g,sidebarResize:W,sidebarWidgets:h,traySlots:p,configHandle:s,rootFolderUrl:S,widgetsReady:re,contactUrl:()=>a()?.contactUrl,moduleSettingsUrl:()=>a()?.moduleSettingsUrl,get isolation(){return e.isolation},onInterceptOpen:Q,get children(){return u(E,{get when(){return $()},get fallback(){return(()=>{var D=dt();return _(D,u(he,{viewKey:$,selectedDocUrl:$,toolId:M,ref:te})),D})()},get children(){return u(E,{get when(){return e.isolation},get fallback(){return u(pe,{setMainDocElement:te,selectedDocUrl:$,selectedToolId:M,doctitleSlots:d,get isLeftCollapsed(){return g.isSidebarCollapsed},initialRightWidth:Z,initialRightCollapsed:ee})},get children(){return u(we,{get contactUrl(){return a()?.contactUrl},selectedDocUrl:$,selectedToolId:M,doctitleSlots:d,get isLeftCollapsed(){return g.isSidebarCollapsed},initialRightWidth:Z,initialRightCollapsed:ee})}})}})}}),null),_(f,u(E,{get when(){return Te()},children:D=>u($t,{get view(){return D()},onClose:()=>Q(null)})}),null),f})()}function $t(e){let[c,l]=b(e.view.toolId??void 0);L(()=>l(e.view.toolId??void 0));let o;return G(()=>{let a=s=>{s.key==="Escape"&&e.onClose()};window.addEventListener("keydown",a),k(()=>window.removeEventListener("keydown",a));let t=o;if(!t)return;let r=s=>{let{url:n,toolId:i}=s.detail;n&&(s.stopPropagation(),l(i??void 0))};t.addEventListener("patchwork:open-document",r),k(()=>t.removeEventListener("patchwork:open-document",r))}),(()=>{var a=ut(),t=a.firstChild,r=t.firstChild,s=r.firstChild,n=r.nextSibling,i=n.firstChild;a.$$click=()=>e.onClose(),t.$$click=d=>d.stopPropagation();var m=o;return typeof m=="function"?C(m,t):o=t,s._$owner=U(),i._$owner=U(),x(d=>{var h=e.view.url,p=e.view.url,S=c();return h!==d.e&&(s.docUrl=d.e=h),p!==d.t&&(i.docUrl=d.t=p),S!==d.a&&(i.toolId=d.a=S),d},{e:void 0,t:void 0,a:void 0}),a})()}function Ct(e){let c=e.sidebarState.isSidebarCollapsed,l=()=>e.traySlots().length>0,o;G(()=>{if(!e.isolation||!o)return;let t=o,r=s=>{let{url:n,toolId:i}=s.detail;n&&(s.stopPropagation(),e.onInterceptOpen?.({url:n,toolId:i??null}))};t.addEventListener("patchwork:open-document",r),k(()=>t.removeEventListener("patchwork:open-document",r))});let a;return L(()=>{if(e.sidebarState.isSidebarCollapsed())return;let t=a;if(!t)return;let r=()=>{t.getBoundingClientRect().width<=window.innerWidth*.75||(e.sidebarState.setIsSidebarCollapsed(!0),window.dispatchEvent(new CustomEvent(oe)))};t.addEventListener("patchwork:open-document",r),k(()=>t.removeEventListener("patchwork:open-document",r))}),[(()=>{var t=ft();return t.$$click=()=>e.sidebarState.setIsSidebarCollapsed(r=>!r),_(t,u(Et,{})),x(r=>{var s=c()?"Show sidebar":"Hide sidebar",n=c()?"Show sidebar":"Hide sidebar",i=!c();return s!==r.e&&q(t,"title",r.e=s),n!==r.t&&q(t,"aria-label",r.t=n),i!==r.a&&q(t,"aria-pressed",r.a=i),r},{e:void 0,t:void 0,a:void 0}),t})(),u(fe,{side:"left",isCollapsed:c,get width(){return e.sidebarState.leftSidebarWidth},get onMouseDown(){return e.sidebarResize.handleMouseDown},get onToggleClick(){return e.sidebarResize.handleToggleClick},get children(){var t=mt(),r=t.firstChild,s=r.firstChild,n=s.firstChild,i=a;typeof i=="function"?C(i,t):a=t,_(t,u(ye,{get widgets(){return e.sidebarWidgets},get configHandle(){return e.configHandle},get rootFolderUrl(){return e.rootFolderUrl},get ready(){return e.widgetsReady}}),r);var m=o;return typeof m=="function"?C(m,r):o=r,_(s,u(E,{get when(){return e.contactUrl()},children:d=>(()=>{var h=pt(),p=h.firstChild;return h.$$click=S=>K(S.currentTarget,{url:e.accountDocUrl,toolId:"account-picker"}),p._$owner=U(),x(()=>p.docUrl=d()),h})()}),n),_(s,u(E,{get when(){return e.moduleSettingsUrl()},children:d=>(()=>{var h=gt();return h.$$click=p=>K(p.currentTarget,{url:d(),toolId:"packages"}),h})()}),n),n.$$click=d=>K(d.currentTarget,{url:e.accountDocUrl,toolId:"frame-configurator"}),x(()=>t.classList.toggle("threepane-sidebar--has-tray",!!l())),t}}),u(E,{get when(){return l()},get children(){var t=ht();return _(t,u(ke,{get slots(){return e.traySlots}})),x(r=>{var s=!!c(),n=`${e.sidebarState.leftSidebarWidth()}px`;return s!==r.e&&t.classList.toggle("frame__tray-dock--collapsed",r.e=s),n!==r.t&&at(t,"width",r.t=n),r},{e:void 0,t:void 0}),t}}),it(()=>e.children)]}function Et(){return wt()}function Xr(e){return(c,l)=>bt(()=>u(Dt,{handle:c,get repo(){return l.repo},isolation:e}),l)}st(["click"]);export{Dt as PatchworkFrame,Xr as renderPatchworkFrame};
2
+ //# sourceMappingURL=PatchworkFrame-Q4RU62XT.js.map