From b2bee03ca207568f184fca6f910425d51b571b92 Mon Sep 17 00:00:00 2001 From: oliver Date: Wed, 4 Nov 2026 15:46:58 -0300 Subject: [PATCH] Show build date next to "Settings" heading Inject a yyyy-mm-dd_hh:mm timestamp at build time via Vite's `define` (app/vite.config.ts: __BUILD_DATE__, computed fresh on every `vite build`/`vite dev` invocation) and render it next to the Settings panel's title, so it's easy to tell which build is deployed. - app/vite.config.ts: buildDateString() + define.__BUILD_DATE__ - app/src/vite-env.d.ts: ambient declaration for the injected constant - app/src/components/SettingsPanel.tsx: render it next to "Settings" - app/src/styles.css: .build-date styling Rebuilt and redeployed to the repo root. --- app/src/components/SettingsPanel.tsx | 4 +++- app/src/styles.css | 7 +++++++ app/src/vite-env.d.ts | 4 ++++ app/vite.config.ts | 10 ++++++++++ assets/{index-SBr79e_P.js => index-BFnujVjw.js} | 2 +- assets/{index-CWSassUi.css => index-BQJys9C3.css} | 2 +- index.html | 4 ++-- sw.js | 2 +- 8 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 app/src/vite-env.d.ts rename assets/{index-SBr79e_P.js => index-BFnujVjw.js} (96%) rename assets/{index-CWSassUi.css => index-BQJys9C3.css} (92%) diff --git a/app/src/components/SettingsPanel.tsx b/app/src/components/SettingsPanel.tsx index 258e523..3975c80 100644 --- a/app/src/components/SettingsPanel.tsx +++ b/app/src/components/SettingsPanel.tsx @@ -24,7 +24,9 @@ export function SettingsPanel() {
setShowSettings(false)}>
e.stopPropagation()}>
-

Settings

+

+ Settings {__BUILD_DATE__} +

diff --git a/app/src/styles.css b/app/src/styles.css index c2a44fc..cea23a1 100644 --- a/app/src/styles.css +++ b/app/src/styles.css @@ -1087,6 +1087,13 @@ select:focus { margin: 0; font-size: 18px; } + +.panel-head .build-date { + font-size: 11.5px; + font-weight: 400; + color: var(--text-faint); + margin-left: 6px; +} .panel-head .icon-btn { margin-left: auto; } diff --git a/app/src/vite-env.d.ts b/app/src/vite-env.d.ts new file mode 100644 index 0000000..f121204 --- /dev/null +++ b/app/src/vite-env.d.ts @@ -0,0 +1,4 @@ +/// + +/** Injected by `vite.config.ts` via `define` — set to the build/dev-server start time. */ +declare const __BUILD_DATE__: string; diff --git a/app/vite.config.ts b/app/vite.config.ts index 83e42c9..9b0bc3a 100644 --- a/app/vite.config.ts +++ b/app/vite.config.ts @@ -4,6 +4,13 @@ import { defineConfig, loadEnv, type Plugin } from "vite"; import react from "@vitejs/plugin-react"; import { VitePWA } from "vite-plugin-pwa"; +/** `yyyy-mm-dd_hh:mm` timestamp of this build/dev-server start, shown in the UI. */ +function buildDateString(): string { + const d = new Date(); + const pad = (n: number) => String(n).padStart(2, "0"); + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}_${pad(d.getHours())}:${pad(d.getMinutes())}`; +} + /** Emits the repo's LICENSE file into the build output. */ function licensePlugin(): Plugin { return { @@ -27,6 +34,9 @@ export default defineConfig(({ mode }) => { const target = env.HERMES_DEV_TARGET; return { + define: { + __BUILD_DATE__: JSON.stringify(buildDateString()), + }, server: { port: 5173, proxy: target diff --git a/assets/index-SBr79e_P.js b/assets/index-BFnujVjw.js similarity index 96% rename from assets/index-SBr79e_P.js rename to assets/index-BFnujVjw.js index 6106beb..b82e91c 100644 --- a/assets/index-SBr79e_P.js +++ b/assets/index-BFnujVjw.js @@ -57,4 +57,4 @@ Error generating stack: `+i.message+` `)){if(!z||z.startsWith(":"))continue;const m=z.indexOf(":"),f=m===-1?z:z.slice(0,m);let v=m===-1?"":z.slice(m+1);v.startsWith(" ")&&(v=v.slice(1)),f==="event"?d=v:f==="data"&&y.push(v)}if(!y.length)return;const g=y.join(` `);if(g==="[DONE]"){n("done",{});return}let x=g;try{x=JSON.parse(g)}catch{}n(d,x)};try{for(;;){const{done:h,value:d}=await o.read();if(h)break;a+=s.decode(d,{stream:!0});let y;for(;(y=a.indexOf(` -`))!==-1;){const g=a.slice(0,y);a=a.slice(y+2),c(g)}}a.trim()&&c(a)}finally{(p=o.releaseLock)==null||p.call(o)}}}const io=2,Rt={connections:[],activeConnectionId:null,speakReplies:!1,ttsVoice:"",showToolCalls:!1,showReasoning:!1,showSystem:!0,transcribeUrl:"",transcribeKey:"",transcribeModel:"whisper-1",mediaBaseUrl:"",mediaPathPrefix:"",prefsVersion:io},Xc="hermes.config.v2";function dh(){try{const e=localStorage.getItem(Xc);if(!e)return{...Rt};const t=JSON.parse(e),n={...Rt,...t,connections:Array.isArray(t.connections)?t.connections:[]};return(t.prefsVersion??1)t.id===e.activeConnectionId)??e.connections[0]??null:null}function ph(e){const t=Qn(e);return!!t&&(t.sameOrigin===!0||t.baseUrl.trim().length>0)}function hh(){return`conn-${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`}let Rn=null;function mh(e){return new Gc({baseUrl:e.baseUrl,apiKey:e.apiKey,profile:e.profile,sameOrigin:e.sameOrigin,customHeaders:e.customHeaders})}function Ve(e){return e instanceof Wn||e instanceof Error?e.message:String(e)}function rt(e,t,n){return e.map(r=>r.id===t?n(r):r)}const j=uh()((e,t)=>({config:{...Rt},client:null,ready:!1,connectionError:null,capabilities:null,models:[],sessions:[],sessionsLoading:!1,searchQuery:"",activeSessionId:null,session:null,messages:[],sessionLoading:!1,streaming:!1,runId:null,streamError:null,steerLeftover:null,sidebarOpen:!1,showSettings:!1,toast:null,async bootstrap(){const n=dh();e({config:n,ready:!0}),Qn(n)&&await t().connect()},async saveConnection(n){const r=t().config,i=r.connections.some(s=>s.id===n.id)?r.connections.map(s=>s.id===n.id?n:s):[...r.connections,n],o={...r,connections:i,activeConnectionId:n.id};Mr(o),e({config:o}),await t().connect()},async removeConnection(n){var s;const r=t().config,l=r.connections.filter(a=>a.id!==n),i=r.activeConnectionId===n?((s=l[0])==null?void 0:s.id)??null:r.activeConnectionId,o={...r,connections:l,activeConnectionId:i};Mr(o),e({config:o,sessions:[],session:null,messages:[],activeSessionId:null}),Qn(o)&&await t().connect()},async setActiveConnection(n){const r={...t().config,activeConnectionId:n};Mr(r),e({config:r,sessions:[],session:null,messages:[],activeSessionId:null}),await t().connect()},updatePrefs(n){const r={...t().config,...n};Mr(r),e({config:r})},async connect(){const n=Qn(t().config);if(!n||!n.sameOrigin&&!n.baseUrl.trim())return;const r=mh(n);e({client:r,connectionError:null,capabilities:null});try{const l=await r.capabilities();e({capabilities:l}),r.models().then(i=>e({models:i})).catch(()=>{}),await t().loadSessions()}catch(l){e({connectionError:Ve(l),capabilities:null})}},async loadSessions(){const{client:n,searchQuery:r}=t();if(n){e({sessionsLoading:!0});try{const l=await n.listSessions({limit:200}),i=r.trim().toLowerCase(),o=i?l.filter(s=>s.title.toLowerCase().includes(i)):l;e({sessions:o,sessionsLoading:!1})}catch(l){e({sessionsLoading:!1,toast:Ve(l)})}}},setSearch(n){e({searchQuery:n}),t().loadSessions()},async openSession(n){const{client:r}=t();if(r){e({activeSessionId:n,sessionLoading:!0,session:null,messages:[],sidebarOpen:!1,streamError:null});try{const[l,i]=await Promise.all([r.getSession(n).catch(()=>null),r.getMessages(n,{limit:500,order:"oldest"})]);e({session:l??{id:n,title:"Untitled"},messages:i,sessionLoading:!1})}catch(l){e({sessionLoading:!1,toast:Ve(l)})}}},async newSession(){const{client:n}=t();if(n)try{const r=await n.createSession();e({session:r,messages:[],activeSessionId:r.id,sidebarOpen:!1,streamError:null}),await t().loadSessions()}catch(r){e({toast:Ve(r)})}},async renameSession(n,r){var i;const{client:l}=t();if(l)try{await l.updateSession(n,{title:r}),e({sessions:t().sessions.map(o=>o.id===n?{...o,title:r}:o),session:((i=t().session)==null?void 0:i.id)===n?{...t().session,title:r}:t().session})}catch(o){e({toast:Ve(o)})}},async deleteSession(n){const{client:r}=t();if(r)try{await r.deleteSession(n);const l=t().activeSessionId===n;e({sessions:t().sessions.filter(i=>i.id!==n),...l?{activeSessionId:null,session:null,messages:[]}:{}})}catch(l){e({toast:Ve(l)})}},async forkSession(n){const{client:r}=t();if(r)try{const l=await r.forkSession(n);await t().loadSessions(),await t().openSession(l.id)}catch(l){e({toast:Ve(l)})}},async send(n,r){const{client:l,activeSessionId:i,messages:o}=t();if(!l||!i)return;const s=n.trim();if(!s&&!(r!=null&&r.length)||t().streaming)return;const a={id:`local-user-${Date.now()}`,role:"user",content:s,attachments:r,timestamp:Date.now()},c=`local-assistant-${Date.now()}`,p={id:c,role:"assistant",content:"",timestamp:Date.now(),streaming:!0,toolCalls:[]};e({messages:[...o,a,p],streaming:!0,streamError:null,runId:null});let h=s;if(r!=null&&r.length){const d=[];s&&d.push({type:"text",text:s});for(const y of r)d.push({type:"image_url",image_url:{url:y.dataUrl}});h=d}try{Rn=new AbortController,await l.chatStream(i,{input:h},(d,y)=>vh(e,t,d,y,c),Rn.signal)}catch(d){if((d==null?void 0:d.name)!=="AbortError"){const y=d instanceof Wn&&d.status===409?"This session is owned by another surface (CLI, dashboard, or messaging) and can't be continued from the API server. Start a new chat to talk to the agent here.":Ve(d);e({streamError:y})}}finally{e({streaming:!1,runId:null}),e({messages:rt(t().messages,c,d=>({...d,streaming:!1}))}),t().loadSessions()}},async cancel(){const{client:n,runId:r}=t();if(Rn==null||Rn.abort(),n&&r)try{await n.stopRun(r)}catch(l){e({toast:Ve(l)})}e({streaming:!1})},async steer(n){const{client:r,runId:l}=t();if(!(!r||!l||!n.trim()))try{await r.steerRun(l,n.trim())}catch(i){e({toast:Ve(i)})}},clearSteerLeftover(){e({steerLeftover:null})},setSidebarOpen(n){e({sidebarOpen:n})},setShowSettings(n){e({showSettings:n})},setToast(n){e({toast:n})}}));function ci(e){for(const t of["text","delta","content","output_text"]){const n=e[t];if(typeof n=="string")return n}return""}function xu(e){return String(e.id??e.tool_call_id??e.tool_use_id??e.tool??e.name??Math.random())}function vh(e,t,n,r,l){const i=r??{};switch(typeof i.run_id=="string"&&i.run_id!==t().runId&&e({runId:i.run_id}),n){case"assistant.delta":case"message.delta":{const o=ci(i);if(!o)break;e({messages:rt(t().messages,l,s=>({...s,content:s.content+o}))});break}case"assistant.commentary":case"message.interim":{if(i.already_streamed)break;const o=ci(i);if(!o)break;e({messages:rt(t().messages,l,s=>({...s,content:o}))});break}case"assistant.completed":case"message.complete":{const o=ci(i);e({messages:rt(t().messages,l,s=>({...s,content:o||s.content,streaming:!1}))});break}case"tool.started":{const o={id:xu(i),name:String(i.tool??i.name??"tool"),preview:typeof i.preview=="string"?i.preview:void 0,status:"running"};e({messages:rt(t().messages,l,s=>{const a=s.toolCalls??[],c=a.some(p=>p.id===o.id);return{...s,toolCalls:c?a.map(p=>p.id===o.id?{...p,...o}:p):[...a,o]}})});break}case"tool.completed":case"tool.failed":{const o=n==="tool.failed"||i.error===!0||typeof i.error=="string",s={id:xu(i),name:String(i.tool??i.name??"tool"),preview:typeof i.preview=="string"?i.preview:void 0,status:o?"error":"done",duration:typeof i.duration=="number"?i.duration:void 0};e({messages:rt(t().messages,l,a=>{const c=a.toolCalls??[],p=c.some(h=>h.id===s.id);return{...a,toolCalls:p?c.map(h=>h.id===s.id?{...h,...s}:h):[...c,s]}})});break}case"run.completed":{const o=typeof i.output=="string"?i.output:"";e({messages:rt(t().messages,l,s=>({...s,content:o||s.content,streaming:!1}))}),typeof i.pending_steer=="string"&&i.pending_steer&&e({steerLeftover:i.pending_steer});break}case"run.failed":case"run.cancelled":{const o=typeof i.output=="string"?i.output:"",s=typeof i.error=="string"?i.error:void 0;e({messages:rt(t().messages,l,a=>({...a,content:o||a.content,streaming:!1,error:n==="run.failed"})),...s?{streamError:s}:{}});break}case"error":{e({streamError:String(i.error??i.message??"The turn failed."),streaming:!1});break}}}function Zc(){const e=j(l=>l.config.ttsVoice),t=R.useRef(null),n=R.useCallback(()=>{typeof speechSynthesis<"u"&&speechSynthesis.cancel(),t.current=null},[]);return{speak:R.useCallback(l=>{const i=l.trim();if(!i||typeof speechSynthesis>"u")return;speechSynthesis.cancel();const o=new SpeechSynthesisUtterance(i);if(e){const s=speechSynthesis.getVoices().find(a=>a.name===e);s&&(o.voice=s)}t.current=o,speechSynthesis.speak(o)},[e]),stop:n}}const J=e=>({width:20,height:20,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.8,strokeLinecap:"round",strokeLinejoin:"round",...e}),xn=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M12 5v14M5 12h14"})}),gh=e=>u.jsxs("svg",{...J(e),children:[u.jsx("circle",{cx:"11",cy:"11",r:"7"}),u.jsx("path",{d:"m20 20-3.5-3.5"})]}),yh=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M4 12 20 4l-6 16-3-7-7-1Z"})}),wh=e=>u.jsxs("svg",{...J(e),children:[u.jsx("rect",{x:"9",y:"3",width:"6",height:"11",rx:"3"}),u.jsx("path",{d:"M5 11a7 7 0 0 0 14 0M12 18v3"})]}),Su=e=>u.jsxs("svg",{...J(e),children:[u.jsx("rect",{x:"3",y:"4",width:"18",height:"16",rx:"2"}),u.jsx("circle",{cx:"8.5",cy:"9.5",r:"1.5"}),u.jsx("path",{d:"m21 16-5-5L5 20"})]}),xh=e=>u.jsx("svg",{...J(e),children:u.jsx("rect",{x:"6",y:"6",width:"12",height:"12",rx:"2",fill:"currentColor",stroke:"none"})}),Sh=e=>u.jsxs("svg",{...J(e),children:[u.jsx("circle",{cx:"12",cy:"12",r:"3"}),u.jsx("path",{d:"M19.4 15a1.7 1.7 0 0 0 .3 1.9l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-2.9 1.2 2 2 0 1 1-4 0 1.7 1.7 0 0 0-2.9-1.2l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1A1.7 1.7 0 0 0 4.6 15a2 2 0 1 1 0-4 1.7 1.7 0 0 0 1.2-2.9l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1A1.7 1.7 0 0 0 11.5 4a2 2 0 1 1 4 0 1.7 1.7 0 0 0 2.9 1.2l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1A1.7 1.7 0 0 0 19.4 11a2 2 0 1 1 0 4Z"})]}),kh=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M4 6h16M4 12h16M4 18h16"})}),ts=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M6 6l12 12M18 6 6 18"})}),ns=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M4 7h16M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13"})}),jh=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"m6 9 6 6 6-6"})}),Ch=e=>u.jsxs("svg",{...J(e),children:[u.jsx("path",{d:"M4 9v6h4l5 4V5L8 9H4Z"}),u.jsx("path",{d:"M16.5 8.5a5 5 0 0 1 0 7"})]}),Eh=e=>u.jsxs("svg",{...J(e),children:[u.jsx("circle",{cx:"12",cy:"8",r:"4"}),u.jsx("path",{d:"M4 20a8 8 0 0 1 16 0"})]}),rs=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"m5 13 4 4L19 7"})}),Nh=e=>u.jsxs("svg",{...J(e),children:[u.jsx("path",{d:"M21 12a9 9 0 1 1-3-6.7L21 8"}),u.jsx("path",{d:"M21 3v5h-5"})]}),ls=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"})}),_h=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M9 4a3 3 0 0 0-3 3 3 3 0 0 0-1 5.8V15a3 3 0 0 0 4 2.8V20h2V4H9ZM15 4a3 3 0 0 1 3 3 3 3 0 0 1 1 5.8V15a3 3 0 0 1-4 2.8V20h-2V4h2Z"})}),Jc=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M12 3v12M7 11l5 5 5-5M5 21h14"})}),Ph=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M3 5h18l-7 8v6l-4-2v-4L3 5Z"})}),Ol=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M14.7 6.3a4 4 0 0 0-5.4 5.4L4 17v3h3l5.3-5.3a4 4 0 0 0 5.4-5.4l-2.3 2.3-2-2 2.3-2.3Z"})});function Th(){return{id:hh(),name:"My Hermes",baseUrl:"",apiKey:"",profile:"",customHeaders:[]}}function gl({initial:e,onSave:t,onCancel:n,saveLabel:r="Save & connect"}){const[l,i]=R.useState(e??Th()),[o,s]=R.useState(!1),[a,c]=R.useState(null),p=d=>i(y=>({...y,...d})),h=async()=>{s(!0),c(null);try{const d=new Gc({baseUrl:l.baseUrl,apiKey:l.apiKey,profile:l.profile,sameOrigin:l.sameOrigin,customHeaders:l.customHeaders}),y=await d.health(),g=await d.capabilities(),x=g.features?Object.keys(g.features).length:0;c({ok:!0,msg:`Connected to ${y.platform??"hermes-agent"} ${y.version??""} — API key accepted (${x} features).`})}catch(d){c({ok:!1,msg:d instanceof Error?d.message:String(d)})}finally{s(!1)}};return u.jsxs("div",{children:[a&&u.jsx("div",{className:`alert ${a.ok?"ok":"error"}`,children:a.msg}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Name"}),u.jsx("input",{value:l.name,onChange:d=>p({name:d.target.value}),placeholder:"My Hermes"})]}),u.jsxs("div",{className:"field",children:[u.jsxs("label",{className:"toggle",style:{marginBottom:8},children:[u.jsx("input",{type:"checkbox",checked:!!l.sameOrigin,onChange:d=>p({sameOrigin:d.target.checked})}),"Same origin (behind the bundled proxy)"]}),l.sameOrigin?u.jsxs("div",{className:"hint",style:{marginTop:0},children:["Requests go to this app's own origin, which the proxy forwards to your API server — no CORS needed. Run the proxy with ",u.jsx("code",{children:"HERMES_TARGET"})," (no key required)."]}):u.jsxs(u.Fragment,{children:[u.jsx("input",{value:l.baseUrl,onChange:d=>p({baseUrl:d.target.value}),placeholder:"https://api.example.com",autoCapitalize:"none",autoCorrect:"off",spellCheck:!1,inputMode:"url"}),u.jsxs("div",{className:"hint",children:["The API server origin (default port ",u.jsx("code",{children:"8642"}),"), e.g."," ",u.jsx("code",{children:"https://api.beaver.derez.ai"}),". Needs ",u.jsx("code",{children:"API_SERVER_CORS_ORIGINS"})," to allow this app's origin."]})]})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"API key (API_SERVER_KEY)"}),u.jsx("input",{type:"password",value:l.apiKey,onChange:d=>p({apiKey:d.target.value}),placeholder:"Bearer token",autoCapitalize:"none"}),u.jsxs("div",{className:"hint",children:["Stored only on this device. Sent as ",u.jsx("code",{children:"Authorization: Bearer …"}),"."]})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Profile (optional)"}),u.jsx("input",{value:l.profile??"",onChange:d=>p({profile:d.target.value}),placeholder:"default",autoCapitalize:"none"}),u.jsxs("div",{className:"hint",children:["Multi-profile gateways route to ",u.jsx("code",{children:"/p//…"}),". Each profile needs its own key — add one connection per profile to see them all."]})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Custom headers (optional)"}),(l.customHeaders??[]).map((d,y)=>u.jsxs("div",{className:"header-row",children:[u.jsx("input",{value:d.name,placeholder:"Header name",onChange:g=>{const x=[...l.customHeaders??[]];x[y]={...x[y],name:g.target.value},p({customHeaders:x})}}),u.jsx("input",{value:d.value,placeholder:"Value",onChange:g=>{const x=[...l.customHeaders??[]];x[y]={...x[y],value:g.target.value},p({customHeaders:x})}}),u.jsx("button",{className:"icon-btn",title:"Remove",onClick:()=>p({customHeaders:(l.customHeaders??[]).filter((g,x)=>x!==y)}),children:u.jsx(ts,{width:16,height:16})})]},y)),u.jsxs("button",{className:"btn",style:{marginTop:8},onClick:()=>p({customHeaders:[...l.customHeaders??[],{name:"",value:""}]}),children:[u.jsx(xn,{width:15,height:15,style:{verticalAlign:"-2px",marginRight:6}}),"Add header"]})]}),u.jsxs("div",{className:"actions",children:[n&&u.jsx("button",{className:"btn",onClick:n,children:"Cancel"}),u.jsx("button",{className:"btn",onClick:h,disabled:o||!l.sameOrigin&&!l.baseUrl.trim(),children:o?"Testing…":"Test"}),u.jsx("button",{className:"btn primary",onClick:()=>t({...l,name:l.name.trim()||"Hermes"}),disabled:!l.sameOrigin&&!l.baseUrl.trim(),children:r})]})]})}function qc({height:e=26,withText:t=!0}){const n=R.useId().replace(/:/g,""),r=t?e*132/34:e;return u.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:r,height:e,viewBox:t?"0 0 132 34":"0 0 34 34",role:"img","aria-label":"derez.ai",children:[u.jsx("defs",{children:u.jsxs("linearGradient",{id:`box-bg-${n}`,x1:"0",y1:"0",x2:"0",y2:"1",children:[u.jsx("stop",{offset:"0%",stopColor:"#003545"}),u.jsx("stop",{offset:"100%",stopColor:"#00202e"})]})}),u.jsx("rect",{x:"0",y:"0",width:"34",height:"34",rx:"10",fill:`url(#box-bg-${n})`,stroke:"#005570",strokeWidth:"1.2"}),u.jsx("rect",{x:"6",y:"11",width:"22",height:"15",rx:"2.5",fill:"none",stroke:"#00f5ff",strokeWidth:"1.8"}),u.jsx("path",{d:"M17 11V7",stroke:"#00f5ff",strokeWidth:"1.8",strokeLinecap:"round"}),u.jsx("circle",{cx:"17",cy:"5.5",r:"1.5",fill:"#00f5ff"}),u.jsx("circle",{cx:"10",cy:"15.5",r:"1",fill:"#00f5ff"}),u.jsx("circle",{cx:"14",cy:"15.5",r:"1",fill:"#00f5ff"}),u.jsx("path",{d:"M10 20h14",stroke:"#00f5ff",strokeWidth:"1.5",strokeLinecap:"round"}),t&&u.jsx("text",{x:"46",y:"23",fill:"#00f5ff",fontFamily:"'Courier New', Courier, monospace",fontSize:"17",fontWeight:"700",letterSpacing:"-0.5",children:"derez.ai"})]})}function is({height:e=26}){return u.jsx("a",{className:"brand-link",href:"https://derez.ai/",target:"_blank",rel:"noopener noreferrer",title:"derez.ai — AI Agent Hosting",children:u.jsx(qc,{height:e})})}function Rh(){const e=j(o=>o.config),t=j(o=>o.saveConnection),n=j(o=>o.removeConnection),r=j(o=>o.setActiveConnection),[l,i]=R.useState(null);return u.jsx("div",{className:"screen",children:u.jsxs("div",{className:"card",children:[u.jsx("div",{style:{marginBottom:18},children:u.jsx(is,{height:30})}),u.jsx("h1",{children:"Connect to your Hermes"}),u.jsxs("p",{className:"lead",children:["Point this app at your Hermes ",u.jsx("strong",{children:"API Server"})," (the OpenAI-compatible endpoint), not the dashboard. It authenticates with your ",u.jsx("code",{children:"API_SERVER_KEY"}),"."]}),u.jsx(gl,{onSave:t}),e.connections.length>0&&u.jsxs("div",{className:"section",style:{marginTop:24,marginBottom:0},children:[u.jsx("h3",{children:"Saved connections"}),e.connections.map(o=>u.jsxs("div",{children:[u.jsxs("div",{className:"kv",children:[u.jsxs("span",{className:"link-btn",style:{cursor:"pointer"},onClick:()=>r(o.id),children:[o.name,o.profile?` · ${o.profile}`:""]}),u.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8},children:[o.sameOrigin?"same origin":o.baseUrl,u.jsx("button",{className:`icon-btn ${l===o.id?"active":""}`,title:"Edit",onClick:()=>i(l===o.id?null:o.id),children:u.jsx(ls,{width:15,height:15})}),u.jsx("button",{className:"icon-btn",title:"Remove",onClick:()=>n(o.id),children:u.jsx(ns,{width:15,height:15})})]})]}),l===o.id&&u.jsx("div",{style:{margin:"10px 0 18px"},children:u.jsx(gl,{initial:o,onSave:async s=>{await t(s),i(null)},onCancel:()=>i(null),saveLabel:"Save changes"})})]},o.id))]})]})})}function Lh(e){if(!e)return"";const t=e>1e12?e:e*1e3,n=Date.now()-t,r=Math.round(n/1e3);if(r<60)return"just now";const l=Math.round(r/60);if(l<60)return`${l}m ago`;const i=Math.round(l/60);if(i<24)return`${i}h ago`;const o=Math.round(i/24);return o<7?`${o}d ago`:new Date(t).toLocaleDateString()}function zh(e){return e==null||e===0?"":e<.01?`$${e.toFixed(4)}`:`$${e.toFixed(2)}`}function Ih(e){return e?e.length>14?`${e.slice(0,13)}…`:e:""}function Mh({s:e}){const t=j(c=>c.activeSessionId),n=j(c=>c.openSession),r=j(c=>c.deleteSession),l=j(c=>c.renameSession),i=j(c=>c.forkSession),o=t===e.id,s=()=>{const c=window.prompt("Rename session",e.title);c&&c.trim()&&l(e.id,c.trim())},a=()=>{window.confirm(`Delete "${e.title}"? This cannot be undone.`)&&r(e.id)};return u.jsxs("div",{className:`session-item ${o?"active":""}`,onClick:()=>n(e.id),title:e.preview||void 0,children:[u.jsxs("div",{className:"body",children:[u.jsx("div",{className:"title",children:e.title}),u.jsxs("div",{className:"meta",children:[u.jsx("span",{children:Lh(e.updatedAt)}),typeof e.messageCount=="number"&&e.messageCount>0&&u.jsxs("span",{children:[e.messageCount," msg"]}),e.source&&u.jsx("span",{children:Ih(e.source)}),e.costUsd?u.jsx("span",{children:zh(e.costUsd)}):null]})]}),u.jsxs("div",{className:"actions",onClick:c=>c.stopPropagation(),children:[u.jsx("button",{className:"icon-btn",title:"Rename",onClick:s,children:u.jsx(ls,{width:15,height:15})}),u.jsx("button",{className:"icon-btn",title:"Fork",onClick:()=>i(e.id),children:u.jsx(xn,{width:15,height:15})}),u.jsx("button",{className:"icon-btn",title:"Delete",onClick:a,children:u.jsx(ns,{width:15,height:15})})]})]})}function Oh(){const e=j(a=>a.config.connections),t=j(a=>a.config.activeConnectionId),n=j(a=>a.setActiveConnection),r=j(a=>a.setShowSettings),[l,i]=R.useState(!1),o=R.useRef(null);R.useEffect(()=>{const a=c=>{o.current&&!o.current.contains(c.target)&&i(!1)};return document.addEventListener("mousedown",a),()=>document.removeEventListener("mousedown",a)},[]);const s=e.find(a=>a.id===t)??e[0];return u.jsxs("div",{className:"profile-switch",ref:o,children:[u.jsxs("button",{className:"profile-btn",onClick:()=>i(a=>!a),children:[u.jsx("span",{className:"dot"}),u.jsx("span",{className:"name",children:(s==null?void 0:s.name)??"No connection"}),(s==null?void 0:s.profile)&&u.jsx("span",{className:"sub",children:s.profile}),u.jsx(jh,{width:15,height:15,style:{marginLeft:6,color:"var(--text-faint)"}})]}),l&&u.jsxs("div",{className:"menu",children:[e.map(a=>u.jsxs("button",{className:"menu-item",onClick:()=>{i(!1),a.id!==t&&n(a.id)},children:[u.jsx("span",{children:a.name}),a.profile&&u.jsx("span",{style:{fontSize:11,color:"var(--text-faint)"},children:a.profile}),a.id===t&&u.jsx(rs,{width:15,height:15,className:"check"})]},a.id)),u.jsxs("button",{className:"menu-item",onClick:()=>{i(!1),r(!0)},children:[u.jsx(xn,{width:15,height:15}),u.jsx("span",{children:"Add connection…"})]})]})]})}function Dh(){const e=j(c=>c.sessions),t=j(c=>c.sessionsLoading),n=j(c=>c.searchQuery),r=j(c=>c.setSearch),l=j(c=>c.newSession),i=j(c=>c.loadSessions),o=j(c=>c.setShowSettings),s=j(c=>c.sidebarOpen),a=j(c=>c.setSidebarOpen);return u.jsxs(u.Fragment,{children:[u.jsx("div",{className:`scrim ${s?"show":""}`,onClick:()=>a(!1)}),u.jsxs("aside",{className:`sidebar ${s?"open":""}`,children:[u.jsxs("div",{className:"sidebar-head",children:[u.jsxs("div",{className:"brand",children:[u.jsx(is,{height:26}),u.jsxs("div",{className:"brand-actions",children:[u.jsx("button",{className:"icon-btn",title:"Refresh",onClick:()=>i(),children:u.jsx(Nh,{width:17,height:17})}),u.jsx("button",{className:"icon-btn",title:"Settings",onClick:()=>o(!0),children:u.jsx(Sh,{width:17,height:17})})]})]}),u.jsx(Oh,{}),u.jsxs("button",{className:"new-chat",onClick:()=>l(),children:[u.jsx(xn,{width:17,height:17}),"New chat"]}),u.jsxs("div",{className:"search-wrap",children:[u.jsx(gh,{width:16,height:16}),u.jsx("input",{value:n,onChange:c=>r(c.target.value),placeholder:"Filter sessions…"})]})]}),u.jsx("div",{className:"sidebar-tools",children:u.jsxs("span",{children:[e.length," sessions"]})}),u.jsxs("div",{className:"session-list",children:[t&&e.length===0&&u.jsx("div",{className:"empty",children:"Loading sessions…"}),!t&&e.length===0&&u.jsxs("div",{className:"empty",children:["No sessions yet.",u.jsx("br",{}),"Start a new chat to begin."]}),e.map(c=>u.jsx(Mh,{s:c},c.id))]})]})]})}function $h(e,t){const n=(t||"image").trim().replace(/[^\w.-]+/g,"_").replace(/^_+|_+$/g,"").slice(0,48)||"image";let r="";const l=/^data:image\/([a-zA-Z0-9.+-]+)/.exec(e);if(l)r=l[1].toLowerCase();else try{const i=new URL(e,location.href).pathname,o=/\.([a-zA-Z0-9]{2,5})$/.exec(i);o&&(r=o[1].toLowerCase())}catch{}return r==="jpeg"&&(r="jpg"),r||(r="png"),`${n}.${r}`}function bc(e,t){const n=document.createElement("a");n.href=e,n.download=$h(e,t),n.rel="noopener",document.body.appendChild(n),n.click(),n.remove()}function Uh(e,t,n){const r=t.trim();if(!r)return null;let l=e.trim();const i=n.trim();return i&&l.startsWith(i)&&(l=l.slice(i.length)),l.startsWith("/")||(l=`/${l}`),r.replace(/\/+$/,"")+l}function Fh(e){const t=e.trim().replace(/[/\\]+$/,""),n=t.split(/[/\\]/);return n[n.length-1]||t}const ku=/(`[^`]+`)|(!\[[^\]]*\]\([^)]*\))|(\[[^\]]*\]\([^)]*\))|(\*\*[^*]+\*\*)|(\*[^*\n]+\*)|(https?:\/\/[^\s<)]+)|(data:image\/[^\s)]+)|(MEDIA:\S+)/g;function ju(e){const t=e.indexOf("](");return t===-1?{label:e,url:""}:{label:e.slice(0,t),url:e.slice(t+2)}}function Ah(e){return e.startsWith("data:")?e.replace(/\s+/g,""):e}function Vh({path:e}){const t=j(s=>s.config.mediaBaseUrl),n=j(s=>s.config.mediaPathPrefix),[r,l]=R.useState(!1),i=Uh(e,t,n),o=Fh(e);return i&&!r?u.jsxs("span",{className:"md-figure",children:[u.jsx("img",{src:i,alt:o,onError:()=>l(!0)}),u.jsxs("button",{type:"button",className:"md-download",onClick:()=>bc(i,o),children:[u.jsx(Jc,{width:15,height:15}),"Download"]})]}):u.jsxs("span",{className:"media-ref",title:e,children:[u.jsx(Ol,{width:15,height:15}),u.jsx("span",{className:"nm",children:o}),u.jsx("span",{className:"path",children:e})]})}function Cu({url:e,alt:t}){const n=Ah(e);return u.jsxs("span",{className:"md-figure",children:[u.jsx("img",{src:n,alt:t}),u.jsxs("button",{type:"button",className:"md-download",onClick:()=>bc(n,t),children:[u.jsx(Jc,{width:15,height:15}),"Download"]})]})}function Eu(e,t){const n=[];let r=0,l=0,i;for(ku.lastIndex=0;(i=ku.exec(e))!==null;){i.index>r&&n.push(e.slice(r,i.index));const o=i[0],s=`${t}-${l++}`;if(i[1])n.push(u.jsx("code",{children:o.slice(1,-1)},s));else if(i[2]){const{label:a,url:c}=ju(o.slice(2,-1));n.push(u.jsx(Cu,{url:c,alt:a},s))}else if(i[3]){const{label:a,url:c}=ju(o.slice(1,-1));n.push(u.jsx("a",{href:c,target:"_blank",rel:"noreferrer noopener",children:a},s))}else i[4]?n.push(u.jsx("strong",{children:o.slice(2,-2)},s)):i[5]?n.push(u.jsx("em",{children:o.slice(1,-1)},s)):i[6]?n.push(u.jsx("a",{href:o,target:"_blank",rel:"noreferrer noopener",children:o},s)):i[7]?n.push(u.jsx(Cu,{url:o,alt:"image"},s)):i[8]&&n.push(u.jsx(Vh,{path:o.slice(6)},s));r=i.index+o.length}return rr&&t.push(u.jsx("span",{children:Eu(e.slice(r,l.index),`t${i}`)},`t${i}`)),t.push(u.jsx("pre",{children:u.jsx("code",{children:l[2].replace(/\n$/,"")})},`c${i}`)),r=l.index+l[0].length,i++;return r{const r=/^image\//.test(t.mime)||t.dataUrl.startsWith("data:image");return u.jsxs("div",{className:"attachment",children:[r?u.jsx("img",{src:t.dataUrl,alt:t.name}):u.jsx(Ol,{width:16,height:16}),u.jsx("span",{className:"nm",children:t.name})]},n)})}):null}function Bh({call:e}){const[t,n]=R.useState(!1),r=e.status==="error"?"error":e.status==="done"?"done":"running…";return u.jsxs("div",{className:"tool-card",children:[u.jsxs("div",{className:"head",onClick:()=>n(l=>!l),style:{cursor:e.preview?"pointer":"default"},children:[u.jsx(Ol,{width:15,height:15,style:{color:"var(--text-dim)"}}),u.jsx("span",{className:"name",children:e.name}),u.jsx("span",{className:`status ${e.status==="error"?"err":e.status==="done"?"ok":""}`,children:r})]}),e.preview&&t&&u.jsx("div",{className:"preview",children:e.preview})]})}function Wh({message:e}){const[t,n]=R.useState(!1);return u.jsxs("div",{className:"tool-card",children:[u.jsxs("div",{className:"head",onClick:()=>n(r=>!r),style:{cursor:"pointer"},children:[u.jsx(Ol,{width:15,height:15,style:{color:"var(--text-dim)"}}),u.jsx("span",{className:"name",children:e.toolName??"tool result"}),u.jsx("span",{className:"status ok",children:"result"})]}),t&&u.jsx("div",{className:"preview",children:ef(e.content)})]})}function Qh({message:e}){return u.jsx("div",{style:{fontSize:12.5,color:"var(--text-faint)",padding:"2px 0 2px 41px",whiteSpace:"pre-wrap"},children:e.content})}function Kh({message:e}){const{speak:t}=Zc(),[n,r]=R.useState(!1),l=j(g=>g.config.showToolCalls),i=j(g=>g.config.showReasoning),o=j(g=>g.config.showSystem);if(e.role==="tool")return l?u.jsx(Wh,{message:e}):null;if(e.role==="system")return o?u.jsx(Qh,{message:e}):null;const s=e.role==="user",a=e.content,c=e.toolCalls??[],p=e.attachments??[],h=!!e.streaming;if(!(!!a||i&&!!e.reasoning||l&&c.length>0||p.length>0||h))return null;const y=async()=>{try{await navigator.clipboard.writeText(a),r(!0),setTimeout(()=>r(!1),1400)}catch{}};return u.jsxs("div",{className:`msg ${s?"user":"assistant"}`,children:[u.jsx("div",{className:`avatar ${s?"user":"brand"}`,children:s?u.jsx(Eh,{width:16,height:16}):u.jsx(qc,{height:30,withText:!1})}),u.jsxs("div",{className:"content",children:[u.jsx("div",{className:"who",children:s?"You":"Hermes"}),e.reasoning&&i&&u.jsxs("details",{className:"reasoning",children:[u.jsxs("summary",{children:[u.jsx(_h,{width:14,height:14}),"Reasoning"]}),u.jsx("div",{className:"body",children:e.reasoning})]}),l&&c.map(g=>u.jsx(Bh,{call:g},g.id)),a?u.jsx("div",{className:"bubble",children:s?a:ef(a)}):h?u.jsxs("div",{className:"typing",children:[u.jsx("span",{}),u.jsx("span",{}),u.jsx("span",{})]}):null,u.jsx(Hh,{items:p}),!s&&a&&!h&&u.jsxs("div",{className:"msg-actions",children:[u.jsx("button",{className:"icon-btn",title:"Copy",onClick:y,children:n?u.jsx(rs,{width:15,height:15}):u.jsx("span",{style:{fontSize:13},children:"⧉"})}),u.jsx("button",{className:"icon-btn",title:"Speak",onClick:()=>t(a),children:u.jsx(Ch,{width:15,height:15})})]})]})]})}function Nu(){const e=window;return e.SpeechRecognition??e.webkitSpeechRecognition??null}function Yh(){const[e,t]=R.useState(!1),[n,r]=R.useState(""),[l,i]=R.useState(null),o=R.useRef(null),s=R.useRef(""),a=typeof window<"u"&&!!Nu(),c=R.useCallback(()=>{var h;(h=o.current)==null||h.stop(),t(!1)},[]),p=R.useCallback(h=>{const d=Nu();if(!d){i("Speech recognition isn't supported in this browser.");return}i(null),r(""),s.current="";const y=new d;y.lang=navigator.language||"en-US",y.continuous=!0,y.interimResults=!0,y.onresult=g=>{let x="";for(let z=g.resultIndex;z{i(g.error==="not-allowed"?"Microphone permission denied.":"Speech recognition error."),t(!1)},y.onend=()=>{t(!1),r("");const g=s.current.trim();g&&h(g)},o.current=y,y.start(),t(!0)},[]);return{supported:a,listening:e,interim:n,error:l,start:p,stop:c}}function Gh(){const[e,t]=R.useState(!1),[n,r]=R.useState(null),l=R.useRef(null),i=R.useRef([]),o=R.useRef(null),s=R.useCallback(async()=>{var c;if(r(null),!((c=navigator.mediaDevices)!=null&&c.getUserMedia))return r("Microphone capture is not supported in this browser."),!1;try{const p=await navigator.mediaDevices.getUserMedia({audio:!0}),h=new MediaRecorder(p);return i.current=[],h.ondataavailable=d=>{d.data.size>0&&i.current.push(d.data)},h.onstop=()=>{var y;p.getTracks().forEach(g=>g.stop());const d=new Blob(i.current,{type:h.mimeType||"audio/webm"});(y=o.current)==null||y.call(o,d.size>0?d:null),o.current=null},l.current=h,h.start(),t(!0),!0}catch(p){return r(p instanceof Error?p.message:"Could not access the microphone."),!1}},[]),a=R.useCallback(()=>new Promise(c=>{const p=l.current;if(!p||p.state==="inactive"){t(!1),c(null);return}o.current=c,p.stop(),t(!1)}),[]);return{recording:e,error:n,start:s,stop:a}}async function Xh(e,t){const n=new FormData,r=e.type.includes("ogg")?"ogg":e.type.includes("mp4")?"mp4":"webm";n.append("file",e,`recording.${r}`),t.model&&n.append("model",t.model);const l={};t.key&&(l.Authorization=`Bearer ${t.key}`);let i;try{i=await fetch(t.url,{method:"POST",headers:l,body:n})}catch{throw new Error(`Could not reach the transcription endpoint (${t.url}).`)}const o=await i.text();let s;try{s=o?JSON.parse(o):void 0}catch{s=o}if(!i.ok){const a=s&&typeof s=="object"?s.error:void 0,c=typeof a=="string"?a:a==null?void 0:a.message;throw new Error(c||`Transcription failed (HTTP ${i.status}).`)}if(s&&typeof s=="object"){const a=s;if(typeof a.text=="string")return a.text;if(typeof a.transcript=="string")return a.transcript}return typeof s=="string"?s:""}function Zh(e){return new Promise((t,n)=>{const r=new FileReader;r.onload=()=>t({name:e.name,mime:e.type||"application/octet-stream",dataUrl:String(r.result),size:e.size}),r.onerror=()=>n(r.error),r.readAsDataURL(e)})}const Jh=()=>{var e;return typeof window<"u"&&((e=window.matchMedia)==null?void 0:e.call(window,"(pointer: coarse)").matches)};function qh(){const e=j(k=>k.streaming),t=j(k=>k.send),n=j(k=>k.steer),r=j(k=>k.cancel),l=j(k=>k.steerLeftover),i=j(k=>k.clearSteerLeftover),o=j(k=>k.setToast),s=j(k=>k.config.transcribeUrl),a=j(k=>k.config.transcribeKey),c=j(k=>k.config.transcribeModel),[p,h]=R.useState(""),[d,y]=R.useState([]),[g,x]=R.useState(!1),z=R.useRef(null),m=R.useRef(null),f=Yh(),v=Gh(),w=!!s.trim(),C=w||f.supported,_=f.listening||v.recording;R.useEffect(()=>{l&&(h(k=>k||l),i())},[l,i]),R.useEffect(()=>{f.error&&o(f.error)},[f.error,o]),R.useEffect(()=>{v.error&&o(v.error)},[v.error,o]),R.useEffect(()=>{const k=z.current;k&&(k.style.height="auto",k.style.height=`${Math.min(k.scrollHeight,200)}px`)},[p]);const P=async k=>{for(const U of k)try{const Fe=await Zh(U);y(E=>[...E,Fe])}catch{o(`Could not attach ${U.name}`)}},T=()=>{const k=p.trim();if(!(!k&&!d.length)){if(e){n(k),h("");return}t(k,d),h(""),y([])}},H=k=>{const U=k.trim();U&&h(Fe=>Fe?`${Fe} ${U}`:U)},M=async()=>{if(f.listening){f.stop();return}if(v.recording){const k=await v.stop();if(!k)return;x(!0);try{const U=await Xh(k,{url:s.trim(),key:a.trim()||void 0,model:c.trim()||void 0});H(U)}catch(U){o(U instanceof Error?U.message:"Transcription failed.")}finally{x(!1)}}},we=async()=>{if(_){await M();return}if(w){await v.start()||o("Could not access the microphone.");return}if(f.supported){if(!window.isSecureContext){o("Dictation needs a secure context (HTTPS or localhost).");return}f.start(H);return}o("Dictation isn't available in this browser. Use Chrome, Edge, or Safari — or set a transcription endpoint in Settings.")},jt=k=>{k.key==="Enter"&&!k.shiftKey&&!Jh()&&(k.preventDefault(),T())},Ct=p.trim().length>0||d.length>0,Sn=g?"Transcribing…":f.listening?f.interim||"Listening…":v.recording?"Recording… tap the mic to stop":"";return u.jsx("div",{className:"composer-wrap",children:u.jsxs("div",{className:"composer",onDragOver:k=>k.preventDefault(),onDrop:k=>{var U;k.preventDefault(),(U=k.dataTransfer.files)!=null&&U.length&&P(Array.from(k.dataTransfer.files))},children:[d.length>0&&u.jsx("div",{className:"attach-chips",children:d.map(k=>u.jsxs("div",{className:"chip",children:[/^image\//.test(k.mime)?u.jsx("img",{src:k.dataUrl,alt:k.name}):u.jsx(Su,{width:15,height:15}),u.jsx("span",{className:"nm",children:k.name}),u.jsx("button",{title:"Remove",onClick:()=>y(U=>U.filter(Fe=>Fe!==k)),children:u.jsx(ts,{width:14,height:14})})]},k.name+k.size))}),Sn&&u.jsxs("div",{className:"recording-pill",style:{padding:"2px 4px"},children:[!g&&u.jsx("span",{className:"pulse"}),u.jsx("span",{style:{color:"var(--text-dim)"},children:Sn})]}),u.jsx("textarea",{ref:z,rows:1,value:p,onChange:k=>h(k.target.value),onKeyDown:jt,onPaste:k=>{const U=Array.from(k.clipboardData.files);U.length&&(k.preventDefault(),P(U))},placeholder:e?"Steer the running turn…":"Message Hermes…"}),u.jsxs("div",{className:"composer-row",children:[u.jsx("input",{ref:m,type:"file",accept:"image/*",multiple:!0,hidden:!0,onChange:k=>{var U;(U=k.target.files)!=null&&U.length&&P(Array.from(k.target.files)),k.target.value=""}}),u.jsx("button",{className:"icon-btn",title:"Attach image",onClick:()=>{var k;return(k=m.current)==null?void 0:k.click()},children:u.jsx(Su,{width:19,height:19})}),u.jsx("button",{className:`icon-btn ${_?"active":""}`,title:_?"Stop dictation":C?"Dictate (speak your prompt)":"Dictation unavailable — see Settings",onClick:we,disabled:g,children:u.jsx(wh,{width:19,height:19})}),u.jsx("div",{className:"spacer"}),e?u.jsx("button",{className:"send-btn stop",title:"Stop",onClick:()=>r(),children:u.jsx(xh,{width:18,height:18})}):u.jsx("button",{className:"send-btn",title:"Send",disabled:!Ct,onClick:T,children:u.jsx(yh,{width:18,height:18})})]})]})})}function bh(){const e=j(a=>a.config.showToolCalls),t=j(a=>a.config.showReasoning),n=j(a=>a.config.showSystem),r=j(a=>a.updatePrefs),[l,i]=R.useState(!1),o=R.useRef(null);R.useEffect(()=>{const a=c=>{o.current&&!o.current.contains(c.target)&&i(!1)};return document.addEventListener("mousedown",a),()=>document.removeEventListener("mousedown",a)},[]);const s=[["Tool calls & results",e,a=>r({showToolCalls:a})],["Reasoning",t,a=>r({showReasoning:a})],["System messages",n,a=>r({showSystem:a})]];return u.jsxs("div",{className:"profile-switch",ref:o,style:{width:"auto"},children:[u.jsx("button",{className:`icon-btn ${l?"active":""}`,title:"Filter messages",onClick:()=>i(a=>!a),children:u.jsx(Ph,{width:19,height:19})}),l&&u.jsx("div",{className:"menu",style:{left:"auto",right:0,width:230},children:s.map(([a,c,p])=>u.jsxs("label",{className:"menu-item toggle",children:[u.jsx("input",{type:"checkbox",checked:c,onChange:h=>p(h.target.checked)}),a]},a))})]})}function em(){const e=j(p=>p.session),t=j(p=>p.messages),n=j(p=>p.sessionLoading),r=j(p=>p.streamError),l=j(p=>p.setSidebarOpen),i=j(p=>p.newSession),o=R.useRef(null),s=R.useRef(!0),a=()=>{const p=o.current;p&&(s.current=p.scrollHeight-p.scrollTop-p.clientHeight<120)};R.useEffect(()=>{const p=o.current;p&&s.current&&(p.scrollTop=p.scrollHeight)},[t]);const c=u.jsxs("div",{className:"chat-head",children:[u.jsx("button",{className:"icon-btn menu-btn",onClick:()=>l(!0),children:u.jsx(kh,{width:20,height:20})}),u.jsxs("div",{className:"titles",children:[u.jsx("div",{className:"t",children:(e==null?void 0:e.title)??"Hermes"}),u.jsxs("div",{className:"s",children:[(e==null?void 0:e.model)&&u.jsx("span",{className:"pill",children:e.model}),(e==null?void 0:e.source)&&u.jsx("span",{children:e.source})]})]}),u.jsx(bh,{}),u.jsx("button",{className:"icon-btn",title:"New chat",onClick:()=>i(),children:u.jsx(xn,{width:19,height:19})})]});return!e&&!n?u.jsxs("div",{className:"main",children:[c,u.jsx("div",{className:"center-fill",children:u.jsxs("div",{children:[u.jsx("div",{style:{fontSize:40,marginBottom:12},children:"💬"}),u.jsx("div",{style:{color:"var(--text)",fontWeight:600,marginBottom:6},children:"No conversation open"}),u.jsx("div",{children:"Pick a session from the sidebar, or start a new chat."}),u.jsx("button",{className:"btn primary",style:{marginTop:18},onClick:()=>i(),children:"New chat"})]})})]}):u.jsxs("div",{className:"main",children:[c,u.jsx("div",{className:"messages",ref:o,onScroll:a,children:u.jsxs("div",{className:"messages-inner",children:[n&&u.jsx("div",{className:"center-fill",children:u.jsx("div",{className:"spinner"})}),t.map(p=>u.jsx(Kh,{message:p},p.id)),r&&u.jsx("div",{className:"alert error",children:r})]})}),u.jsx(qh,{})]})}function fi(){const e=j(g=>g.config),t=j(g=>g.capabilities),n=j(g=>g.models),r=j(g=>g.saveConnection),l=j(g=>g.removeConnection),i=j(g=>g.setActiveConnection),o=j(g=>g.updatePrefs),s=j(g=>g.setShowSettings),[a,c]=R.useState(!1),[p,h]=R.useState(null),d=Qn(e),y=t!=null&&t.features?Object.entries(t.features):[];return u.jsx("div",{className:"panel",onClick:()=>s(!1),children:u.jsxs("div",{className:"panel-inner",onClick:g=>g.stopPropagation(),children:[u.jsxs("div",{className:"panel-head",children:[u.jsx("h2",{children:"Settings"}),u.jsx("button",{className:"icon-btn",onClick:()=>s(!1),children:u.jsx(ts,{width:20,height:20})})]}),u.jsxs("div",{className:"section",children:[u.jsx("h3",{children:"Connections"}),e.connections.map(g=>u.jsxs("div",{children:[u.jsxs("div",{className:"kv",children:[u.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8},children:[u.jsxs("button",{className:"link-btn",style:{cursor:"pointer"},onClick:()=>i(g.id),children:[g.name,g.profile?` · ${g.profile}`:""]}),g.id===e.activeConnectionId&&u.jsx(rs,{width:14,height:14,style:{color:"var(--accent)"}})]}),u.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8},children:[g.sameOrigin?"same origin":g.baseUrl,u.jsx("button",{className:`icon-btn ${p===g.id?"active":""}`,title:"Edit",onClick:()=>{c(!1),h(p===g.id?null:g.id)},children:u.jsx(ls,{width:15,height:15})}),u.jsx("button",{className:"icon-btn",title:"Remove",onClick:()=>l(g.id),children:u.jsx(ns,{width:15,height:15})})]})]}),p===g.id&&u.jsx("div",{style:{margin:"10px 0 18px"},children:u.jsx(gl,{initial:g,onSave:async x=>{await r(x),h(null)},onCancel:()=>h(null),saveLabel:"Save changes"})})]},g.id)),a?u.jsx("div",{style:{marginTop:12},children:u.jsx(gl,{onSave:async g=>{await r(g),c(!1)},onCancel:()=>c(!1),saveLabel:"Add"})}):u.jsxs("button",{className:"btn",style:{marginTop:12},onClick:()=>{h(null),c(!0)},children:[u.jsx(xn,{width:15,height:15,style:{verticalAlign:"-2px",marginRight:6}}),"Add connection"]})]}),u.jsxs("div",{className:"section",children:[u.jsx("h3",{children:"Voice"}),u.jsxs("label",{className:"toggle",style:{marginBottom:12},children:[u.jsx("input",{type:"checkbox",checked:e.speakReplies,onChange:g=>o({speakReplies:g.target.checked})}),"Speak replies automatically"]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Voice (browser)"}),u.jsx("input",{value:e.ttsVoice,onChange:g=>o({ttsVoice:g.target.value}),placeholder:"System default"})]})]}),u.jsxs("div",{className:"section",children:[u.jsx("h3",{children:"Dictation"}),u.jsx("div",{className:"hint",style:{marginTop:0,marginBottom:10},children:"If a transcription endpoint is set below, it's used for dictation (usually far more accurate). Otherwise Chrome, Edge, and Safari fall back to on-device dictation via the Web Speech API — Firefox has no speech API, so it needs an endpoint set here."}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Transcription endpoint"}),u.jsx("input",{value:e.transcribeUrl,onChange:g=>o({transcribeUrl:g.target.value}),placeholder:"https://api.openai.com/v1/audio/transcriptions",autoCapitalize:"none",autoCorrect:"off",spellCheck:!1,inputMode:"url"}),u.jsxs("div",{className:"hint",children:["Any OpenAI-compatible ",u.jsx("code",{children:"/v1/audio/transcriptions"})," — OpenAI, Groq, or a local whisper.cpp server. Leave empty to disable."]})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"API key"}),u.jsx("input",{type:"password",value:e.transcribeKey,onChange:g=>o({transcribeKey:g.target.value}),placeholder:"sk-…",autoCapitalize:"none"})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Model"}),u.jsx("input",{value:e.transcribeModel,onChange:g=>o({transcribeModel:g.target.value}),placeholder:"whisper-1",autoCapitalize:"none"})]})]}),u.jsxs("div",{className:"section",children:[u.jsx("h3",{children:"Media"}),u.jsxs("div",{className:"hint",style:{marginTop:0,marginBottom:10},children:["Your agent emits ",u.jsx("code",{children:"MEDIA:/path/to/file.png"})," for generated files. The Hermes API server can't serve those, so point this at a URL where the agent's workspace is reachable to render them as images."]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Media base URL"}),u.jsx("input",{value:e.mediaBaseUrl,onChange:g=>o({mediaBaseUrl:g.target.value}),placeholder:"https://files.example.com",autoCapitalize:"none",autoCorrect:"off",spellCheck:!1,inputMode:"url"})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Strip path prefix"}),u.jsx("input",{value:e.mediaPathPrefix,onChange:g=>o({mediaPathPrefix:g.target.value}),placeholder:"/root/workspace",autoCapitalize:"none",autoCorrect:"off",spellCheck:!1}),u.jsxs("div",{className:"hint",children:["Removed from the start of the path before appending. E.g. base"," ",u.jsx("code",{children:"https://files.example.com"})," + prefix ",u.jsx("code",{children:"/root/workspace"})," turns"," ",u.jsx("code",{children:"MEDIA:/root/workspace/a.png"})," into"," ",u.jsx("code",{children:"https://files.example.com/a.png"}),"."]})]})]}),u.jsxs("div",{className:"section",children:[u.jsx("h3",{children:"Server"}),u.jsxs("div",{className:"kv",children:[u.jsx("span",{children:"Connection"}),u.jsx("span",{children:(d==null?void 0:d.name)??"—"})]}),u.jsxs("div",{className:"kv",children:[u.jsx("span",{children:"Platform"}),u.jsx("span",{children:(t==null?void 0:t.platform)??"—"})]}),u.jsxs("div",{className:"kv",children:[u.jsx("span",{children:"Model"}),u.jsx("span",{children:(t==null?void 0:t.model)??"—"})]}),u.jsxs("div",{className:"kv",children:[u.jsx("span",{children:"Models available"}),u.jsx("span",{children:n.length||"—"})]}),y.length>0&&u.jsxs("div",{style:{marginTop:10},children:[u.jsx("div",{className:"hint",style:{marginBottom:6},children:"Features"}),u.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:6},children:y.filter(([,g])=>g===!0).map(([g])=>u.jsx("span",{style:{fontSize:11,padding:"2px 8px",borderRadius:20,background:"var(--bg-elev2)",border:"1px solid var(--border)",color:"var(--text-dim)"},children:g},g))})]})]})]})})}function di(){const e=j(n=>n.toast),t=j(n=>n.setToast);return R.useEffect(()=>{if(!e)return;const n=setTimeout(()=>t(null),5e3);return()=>clearTimeout(n)},[e,t]),e?u.jsx("div",{className:"toast",onClick:()=>t(null),children:e}):null}function tm(){const e=j(i=>i.messages),t=j(i=>i.streaming),n=j(i=>i.config.speakReplies),{speak:r}=Zc(),l=R.useRef(null);return R.useEffect(()=>{if(!n||t)return;const i=e[e.length-1];!i||i.role!=="assistant"||!i.id||i.id===l.current||i.content.trim()&&(l.current=i.id,r(i.content))},[e,t,n,r]),null}function nm(){const e=j(o=>o.ready),t=j(o=>o.config),n=j(o=>o.connectionError),r=j(o=>o.showSettings),l=j(o=>o.bootstrap),i=j(o=>o.connect);return R.useEffect(()=>{l()},[l]),e?ph(t)?n?u.jsxs("div",{className:"screen",children:[u.jsxs("div",{className:"card",children:[u.jsx("div",{style:{marginBottom:18},children:u.jsx(is,{height:30})}),u.jsx("h1",{children:"Can’t reach Hermes"}),u.jsx("p",{className:"lead",children:n}),u.jsxs("div",{className:"actions",children:[u.jsx("button",{className:"btn",onClick:()=>j.getState().setShowSettings(!0),children:"Settings"}),u.jsx("button",{className:"btn primary",onClick:()=>i(),children:"Retry"})]})]}),r&&u.jsx(fi,{}),u.jsx(di,{})]}):u.jsxs(u.Fragment,{children:[u.jsxs("div",{className:"app",children:[u.jsx(Dh,{}),u.jsx(em,{})]}),u.jsx(tm,{}),r&&u.jsx(fi,{}),u.jsx(di,{})]}):u.jsxs(u.Fragment,{children:[u.jsx(Rh,{}),r&&u.jsx(fi,{}),u.jsx(di,{})]}):u.jsx("div",{className:"screen",children:u.jsx("div",{className:"spinner"})})}Mp({immediate:!0});const _u=document.getElementById("root");_u&&Vc(_u).render(u.jsx(R.StrictMode,{children:u.jsx(nm,{})})); +`))!==-1;){const g=a.slice(0,y);a=a.slice(y+2),c(g)}}a.trim()&&c(a)}finally{(p=o.releaseLock)==null||p.call(o)}}}const io=2,Rt={connections:[],activeConnectionId:null,speakReplies:!1,ttsVoice:"",showToolCalls:!1,showReasoning:!1,showSystem:!0,transcribeUrl:"",transcribeKey:"",transcribeModel:"whisper-1",mediaBaseUrl:"",mediaPathPrefix:"",prefsVersion:io},Xc="hermes.config.v2";function dh(){try{const e=localStorage.getItem(Xc);if(!e)return{...Rt};const t=JSON.parse(e),n={...Rt,...t,connections:Array.isArray(t.connections)?t.connections:[]};return(t.prefsVersion??1)t.id===e.activeConnectionId)??e.connections[0]??null:null}function ph(e){const t=Qn(e);return!!t&&(t.sameOrigin===!0||t.baseUrl.trim().length>0)}function hh(){return`conn-${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`}let Rn=null;function mh(e){return new Gc({baseUrl:e.baseUrl,apiKey:e.apiKey,profile:e.profile,sameOrigin:e.sameOrigin,customHeaders:e.customHeaders})}function Ve(e){return e instanceof Wn||e instanceof Error?e.message:String(e)}function rt(e,t,n){return e.map(r=>r.id===t?n(r):r)}const j=uh()((e,t)=>({config:{...Rt},client:null,ready:!1,connectionError:null,capabilities:null,models:[],sessions:[],sessionsLoading:!1,searchQuery:"",activeSessionId:null,session:null,messages:[],sessionLoading:!1,streaming:!1,runId:null,streamError:null,steerLeftover:null,sidebarOpen:!1,showSettings:!1,toast:null,async bootstrap(){const n=dh();e({config:n,ready:!0}),Qn(n)&&await t().connect()},async saveConnection(n){const r=t().config,i=r.connections.some(s=>s.id===n.id)?r.connections.map(s=>s.id===n.id?n:s):[...r.connections,n],o={...r,connections:i,activeConnectionId:n.id};Mr(o),e({config:o}),await t().connect()},async removeConnection(n){var s;const r=t().config,l=r.connections.filter(a=>a.id!==n),i=r.activeConnectionId===n?((s=l[0])==null?void 0:s.id)??null:r.activeConnectionId,o={...r,connections:l,activeConnectionId:i};Mr(o),e({config:o,sessions:[],session:null,messages:[],activeSessionId:null}),Qn(o)&&await t().connect()},async setActiveConnection(n){const r={...t().config,activeConnectionId:n};Mr(r),e({config:r,sessions:[],session:null,messages:[],activeSessionId:null}),await t().connect()},updatePrefs(n){const r={...t().config,...n};Mr(r),e({config:r})},async connect(){const n=Qn(t().config);if(!n||!n.sameOrigin&&!n.baseUrl.trim())return;const r=mh(n);e({client:r,connectionError:null,capabilities:null});try{const l=await r.capabilities();e({capabilities:l}),r.models().then(i=>e({models:i})).catch(()=>{}),await t().loadSessions()}catch(l){e({connectionError:Ve(l),capabilities:null})}},async loadSessions(){const{client:n,searchQuery:r}=t();if(n){e({sessionsLoading:!0});try{const l=await n.listSessions({limit:200}),i=r.trim().toLowerCase(),o=i?l.filter(s=>s.title.toLowerCase().includes(i)):l;e({sessions:o,sessionsLoading:!1})}catch(l){e({sessionsLoading:!1,toast:Ve(l)})}}},setSearch(n){e({searchQuery:n}),t().loadSessions()},async openSession(n){const{client:r}=t();if(r){e({activeSessionId:n,sessionLoading:!0,session:null,messages:[],sidebarOpen:!1,streamError:null});try{const[l,i]=await Promise.all([r.getSession(n).catch(()=>null),r.getMessages(n,{limit:500,order:"oldest"})]);e({session:l??{id:n,title:"Untitled"},messages:i,sessionLoading:!1})}catch(l){e({sessionLoading:!1,toast:Ve(l)})}}},async newSession(){const{client:n}=t();if(n)try{const r=await n.createSession();e({session:r,messages:[],activeSessionId:r.id,sidebarOpen:!1,streamError:null}),await t().loadSessions()}catch(r){e({toast:Ve(r)})}},async renameSession(n,r){var i;const{client:l}=t();if(l)try{await l.updateSession(n,{title:r}),e({sessions:t().sessions.map(o=>o.id===n?{...o,title:r}:o),session:((i=t().session)==null?void 0:i.id)===n?{...t().session,title:r}:t().session})}catch(o){e({toast:Ve(o)})}},async deleteSession(n){const{client:r}=t();if(r)try{await r.deleteSession(n);const l=t().activeSessionId===n;e({sessions:t().sessions.filter(i=>i.id!==n),...l?{activeSessionId:null,session:null,messages:[]}:{}})}catch(l){e({toast:Ve(l)})}},async forkSession(n){const{client:r}=t();if(r)try{const l=await r.forkSession(n);await t().loadSessions(),await t().openSession(l.id)}catch(l){e({toast:Ve(l)})}},async send(n,r){const{client:l,activeSessionId:i,messages:o}=t();if(!l||!i)return;const s=n.trim();if(!s&&!(r!=null&&r.length)||t().streaming)return;const a={id:`local-user-${Date.now()}`,role:"user",content:s,attachments:r,timestamp:Date.now()},c=`local-assistant-${Date.now()}`,p={id:c,role:"assistant",content:"",timestamp:Date.now(),streaming:!0,toolCalls:[]};e({messages:[...o,a,p],streaming:!0,streamError:null,runId:null});let h=s;if(r!=null&&r.length){const d=[];s&&d.push({type:"text",text:s});for(const y of r)d.push({type:"image_url",image_url:{url:y.dataUrl}});h=d}try{Rn=new AbortController,await l.chatStream(i,{input:h},(d,y)=>vh(e,t,d,y,c),Rn.signal)}catch(d){if((d==null?void 0:d.name)!=="AbortError"){const y=d instanceof Wn&&d.status===409?"This session is owned by another surface (CLI, dashboard, or messaging) and can't be continued from the API server. Start a new chat to talk to the agent here.":Ve(d);e({streamError:y})}}finally{e({streaming:!1,runId:null}),e({messages:rt(t().messages,c,d=>({...d,streaming:!1}))}),t().loadSessions()}},async cancel(){const{client:n,runId:r}=t();if(Rn==null||Rn.abort(),n&&r)try{await n.stopRun(r)}catch(l){e({toast:Ve(l)})}e({streaming:!1})},async steer(n){const{client:r,runId:l}=t();if(!(!r||!l||!n.trim()))try{await r.steerRun(l,n.trim())}catch(i){e({toast:Ve(i)})}},clearSteerLeftover(){e({steerLeftover:null})},setSidebarOpen(n){e({sidebarOpen:n})},setShowSettings(n){e({showSettings:n})},setToast(n){e({toast:n})}}));function ci(e){for(const t of["text","delta","content","output_text"]){const n=e[t];if(typeof n=="string")return n}return""}function xu(e){return String(e.id??e.tool_call_id??e.tool_use_id??e.tool??e.name??Math.random())}function vh(e,t,n,r,l){const i=r??{};switch(typeof i.run_id=="string"&&i.run_id!==t().runId&&e({runId:i.run_id}),n){case"assistant.delta":case"message.delta":{const o=ci(i);if(!o)break;e({messages:rt(t().messages,l,s=>({...s,content:s.content+o}))});break}case"assistant.commentary":case"message.interim":{if(i.already_streamed)break;const o=ci(i);if(!o)break;e({messages:rt(t().messages,l,s=>({...s,content:o}))});break}case"assistant.completed":case"message.complete":{const o=ci(i);e({messages:rt(t().messages,l,s=>({...s,content:o||s.content,streaming:!1}))});break}case"tool.started":{const o={id:xu(i),name:String(i.tool??i.name??"tool"),preview:typeof i.preview=="string"?i.preview:void 0,status:"running"};e({messages:rt(t().messages,l,s=>{const a=s.toolCalls??[],c=a.some(p=>p.id===o.id);return{...s,toolCalls:c?a.map(p=>p.id===o.id?{...p,...o}:p):[...a,o]}})});break}case"tool.completed":case"tool.failed":{const o=n==="tool.failed"||i.error===!0||typeof i.error=="string",s={id:xu(i),name:String(i.tool??i.name??"tool"),preview:typeof i.preview=="string"?i.preview:void 0,status:o?"error":"done",duration:typeof i.duration=="number"?i.duration:void 0};e({messages:rt(t().messages,l,a=>{const c=a.toolCalls??[],p=c.some(h=>h.id===s.id);return{...a,toolCalls:p?c.map(h=>h.id===s.id?{...h,...s}:h):[...c,s]}})});break}case"run.completed":{const o=typeof i.output=="string"?i.output:"";e({messages:rt(t().messages,l,s=>({...s,content:o||s.content,streaming:!1}))}),typeof i.pending_steer=="string"&&i.pending_steer&&e({steerLeftover:i.pending_steer});break}case"run.failed":case"run.cancelled":{const o=typeof i.output=="string"?i.output:"",s=typeof i.error=="string"?i.error:void 0;e({messages:rt(t().messages,l,a=>({...a,content:o||a.content,streaming:!1,error:n==="run.failed"})),...s?{streamError:s}:{}});break}case"error":{e({streamError:String(i.error??i.message??"The turn failed."),streaming:!1});break}}}function Zc(){const e=j(l=>l.config.ttsVoice),t=R.useRef(null),n=R.useCallback(()=>{typeof speechSynthesis<"u"&&speechSynthesis.cancel(),t.current=null},[]);return{speak:R.useCallback(l=>{const i=l.trim();if(!i||typeof speechSynthesis>"u")return;speechSynthesis.cancel();const o=new SpeechSynthesisUtterance(i);if(e){const s=speechSynthesis.getVoices().find(a=>a.name===e);s&&(o.voice=s)}t.current=o,speechSynthesis.speak(o)},[e]),stop:n}}const J=e=>({width:20,height:20,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.8,strokeLinecap:"round",strokeLinejoin:"round",...e}),xn=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M12 5v14M5 12h14"})}),gh=e=>u.jsxs("svg",{...J(e),children:[u.jsx("circle",{cx:"11",cy:"11",r:"7"}),u.jsx("path",{d:"m20 20-3.5-3.5"})]}),yh=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M4 12 20 4l-6 16-3-7-7-1Z"})}),wh=e=>u.jsxs("svg",{...J(e),children:[u.jsx("rect",{x:"9",y:"3",width:"6",height:"11",rx:"3"}),u.jsx("path",{d:"M5 11a7 7 0 0 0 14 0M12 18v3"})]}),Su=e=>u.jsxs("svg",{...J(e),children:[u.jsx("rect",{x:"3",y:"4",width:"18",height:"16",rx:"2"}),u.jsx("circle",{cx:"8.5",cy:"9.5",r:"1.5"}),u.jsx("path",{d:"m21 16-5-5L5 20"})]}),xh=e=>u.jsx("svg",{...J(e),children:u.jsx("rect",{x:"6",y:"6",width:"12",height:"12",rx:"2",fill:"currentColor",stroke:"none"})}),Sh=e=>u.jsxs("svg",{...J(e),children:[u.jsx("circle",{cx:"12",cy:"12",r:"3"}),u.jsx("path",{d:"M19.4 15a1.7 1.7 0 0 0 .3 1.9l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-2.9 1.2 2 2 0 1 1-4 0 1.7 1.7 0 0 0-2.9-1.2l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1A1.7 1.7 0 0 0 4.6 15a2 2 0 1 1 0-4 1.7 1.7 0 0 0 1.2-2.9l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1A1.7 1.7 0 0 0 11.5 4a2 2 0 1 1 4 0 1.7 1.7 0 0 0 2.9 1.2l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1A1.7 1.7 0 0 0 19.4 11a2 2 0 1 1 0 4Z"})]}),kh=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M4 6h16M4 12h16M4 18h16"})}),ts=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M6 6l12 12M18 6 6 18"})}),ns=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M4 7h16M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13"})}),jh=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"m6 9 6 6 6-6"})}),Ch=e=>u.jsxs("svg",{...J(e),children:[u.jsx("path",{d:"M4 9v6h4l5 4V5L8 9H4Z"}),u.jsx("path",{d:"M16.5 8.5a5 5 0 0 1 0 7"})]}),Eh=e=>u.jsxs("svg",{...J(e),children:[u.jsx("circle",{cx:"12",cy:"8",r:"4"}),u.jsx("path",{d:"M4 20a8 8 0 0 1 16 0"})]}),rs=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"m5 13 4 4L19 7"})}),Nh=e=>u.jsxs("svg",{...J(e),children:[u.jsx("path",{d:"M21 12a9 9 0 1 1-3-6.7L21 8"}),u.jsx("path",{d:"M21 3v5h-5"})]}),ls=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"})}),_h=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M9 4a3 3 0 0 0-3 3 3 3 0 0 0-1 5.8V15a3 3 0 0 0 4 2.8V20h2V4H9ZM15 4a3 3 0 0 1 3 3 3 3 0 0 1 1 5.8V15a3 3 0 0 1-4 2.8V20h-2V4h2Z"})}),Jc=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M12 3v12M7 11l5 5 5-5M5 21h14"})}),Ph=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M3 5h18l-7 8v6l-4-2v-4L3 5Z"})}),Ol=e=>u.jsx("svg",{...J(e),children:u.jsx("path",{d:"M14.7 6.3a4 4 0 0 0-5.4 5.4L4 17v3h3l5.3-5.3a4 4 0 0 0 5.4-5.4l-2.3 2.3-2-2 2.3-2.3Z"})});function Th(){return{id:hh(),name:"My Hermes",baseUrl:"",apiKey:"",profile:"",customHeaders:[]}}function gl({initial:e,onSave:t,onCancel:n,saveLabel:r="Save & connect"}){const[l,i]=R.useState(e??Th()),[o,s]=R.useState(!1),[a,c]=R.useState(null),p=d=>i(y=>({...y,...d})),h=async()=>{s(!0),c(null);try{const d=new Gc({baseUrl:l.baseUrl,apiKey:l.apiKey,profile:l.profile,sameOrigin:l.sameOrigin,customHeaders:l.customHeaders}),y=await d.health(),g=await d.capabilities(),x=g.features?Object.keys(g.features).length:0;c({ok:!0,msg:`Connected to ${y.platform??"hermes-agent"} ${y.version??""} — API key accepted (${x} features).`})}catch(d){c({ok:!1,msg:d instanceof Error?d.message:String(d)})}finally{s(!1)}};return u.jsxs("div",{children:[a&&u.jsx("div",{className:`alert ${a.ok?"ok":"error"}`,children:a.msg}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Name"}),u.jsx("input",{value:l.name,onChange:d=>p({name:d.target.value}),placeholder:"My Hermes"})]}),u.jsxs("div",{className:"field",children:[u.jsxs("label",{className:"toggle",style:{marginBottom:8},children:[u.jsx("input",{type:"checkbox",checked:!!l.sameOrigin,onChange:d=>p({sameOrigin:d.target.checked})}),"Same origin (behind the bundled proxy)"]}),l.sameOrigin?u.jsxs("div",{className:"hint",style:{marginTop:0},children:["Requests go to this app's own origin, which the proxy forwards to your API server — no CORS needed. Run the proxy with ",u.jsx("code",{children:"HERMES_TARGET"})," (no key required)."]}):u.jsxs(u.Fragment,{children:[u.jsx("input",{value:l.baseUrl,onChange:d=>p({baseUrl:d.target.value}),placeholder:"https://api.example.com",autoCapitalize:"none",autoCorrect:"off",spellCheck:!1,inputMode:"url"}),u.jsxs("div",{className:"hint",children:["The API server origin (default port ",u.jsx("code",{children:"8642"}),"), e.g."," ",u.jsx("code",{children:"https://api.beaver.derez.ai"}),". Needs ",u.jsx("code",{children:"API_SERVER_CORS_ORIGINS"})," to allow this app's origin."]})]})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"API key (API_SERVER_KEY)"}),u.jsx("input",{type:"password",value:l.apiKey,onChange:d=>p({apiKey:d.target.value}),placeholder:"Bearer token",autoCapitalize:"none"}),u.jsxs("div",{className:"hint",children:["Stored only on this device. Sent as ",u.jsx("code",{children:"Authorization: Bearer …"}),"."]})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Profile (optional)"}),u.jsx("input",{value:l.profile??"",onChange:d=>p({profile:d.target.value}),placeholder:"default",autoCapitalize:"none"}),u.jsxs("div",{className:"hint",children:["Multi-profile gateways route to ",u.jsx("code",{children:"/p//…"}),". Each profile needs its own key — add one connection per profile to see them all."]})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Custom headers (optional)"}),(l.customHeaders??[]).map((d,y)=>u.jsxs("div",{className:"header-row",children:[u.jsx("input",{value:d.name,placeholder:"Header name",onChange:g=>{const x=[...l.customHeaders??[]];x[y]={...x[y],name:g.target.value},p({customHeaders:x})}}),u.jsx("input",{value:d.value,placeholder:"Value",onChange:g=>{const x=[...l.customHeaders??[]];x[y]={...x[y],value:g.target.value},p({customHeaders:x})}}),u.jsx("button",{className:"icon-btn",title:"Remove",onClick:()=>p({customHeaders:(l.customHeaders??[]).filter((g,x)=>x!==y)}),children:u.jsx(ts,{width:16,height:16})})]},y)),u.jsxs("button",{className:"btn",style:{marginTop:8},onClick:()=>p({customHeaders:[...l.customHeaders??[],{name:"",value:""}]}),children:[u.jsx(xn,{width:15,height:15,style:{verticalAlign:"-2px",marginRight:6}}),"Add header"]})]}),u.jsxs("div",{className:"actions",children:[n&&u.jsx("button",{className:"btn",onClick:n,children:"Cancel"}),u.jsx("button",{className:"btn",onClick:h,disabled:o||!l.sameOrigin&&!l.baseUrl.trim(),children:o?"Testing…":"Test"}),u.jsx("button",{className:"btn primary",onClick:()=>t({...l,name:l.name.trim()||"Hermes"}),disabled:!l.sameOrigin&&!l.baseUrl.trim(),children:r})]})]})}function qc({height:e=26,withText:t=!0}){const n=R.useId().replace(/:/g,""),r=t?e*132/34:e;return u.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",width:r,height:e,viewBox:t?"0 0 132 34":"0 0 34 34",role:"img","aria-label":"derez.ai",children:[u.jsx("defs",{children:u.jsxs("linearGradient",{id:`box-bg-${n}`,x1:"0",y1:"0",x2:"0",y2:"1",children:[u.jsx("stop",{offset:"0%",stopColor:"#003545"}),u.jsx("stop",{offset:"100%",stopColor:"#00202e"})]})}),u.jsx("rect",{x:"0",y:"0",width:"34",height:"34",rx:"10",fill:`url(#box-bg-${n})`,stroke:"#005570",strokeWidth:"1.2"}),u.jsx("rect",{x:"6",y:"11",width:"22",height:"15",rx:"2.5",fill:"none",stroke:"#00f5ff",strokeWidth:"1.8"}),u.jsx("path",{d:"M17 11V7",stroke:"#00f5ff",strokeWidth:"1.8",strokeLinecap:"round"}),u.jsx("circle",{cx:"17",cy:"5.5",r:"1.5",fill:"#00f5ff"}),u.jsx("circle",{cx:"10",cy:"15.5",r:"1",fill:"#00f5ff"}),u.jsx("circle",{cx:"14",cy:"15.5",r:"1",fill:"#00f5ff"}),u.jsx("path",{d:"M10 20h14",stroke:"#00f5ff",strokeWidth:"1.5",strokeLinecap:"round"}),t&&u.jsx("text",{x:"46",y:"23",fill:"#00f5ff",fontFamily:"'Courier New', Courier, monospace",fontSize:"17",fontWeight:"700",letterSpacing:"-0.5",children:"derez.ai"})]})}function is({height:e=26}){return u.jsx("a",{className:"brand-link",href:"https://derez.ai/",target:"_blank",rel:"noopener noreferrer",title:"derez.ai — AI Agent Hosting",children:u.jsx(qc,{height:e})})}function Rh(){const e=j(o=>o.config),t=j(o=>o.saveConnection),n=j(o=>o.removeConnection),r=j(o=>o.setActiveConnection),[l,i]=R.useState(null);return u.jsx("div",{className:"screen",children:u.jsxs("div",{className:"card",children:[u.jsx("div",{style:{marginBottom:18},children:u.jsx(is,{height:30})}),u.jsx("h1",{children:"Connect to your Hermes"}),u.jsxs("p",{className:"lead",children:["Point this app at your Hermes ",u.jsx("strong",{children:"API Server"})," (the OpenAI-compatible endpoint), not the dashboard. It authenticates with your ",u.jsx("code",{children:"API_SERVER_KEY"}),"."]}),u.jsx(gl,{onSave:t}),e.connections.length>0&&u.jsxs("div",{className:"section",style:{marginTop:24,marginBottom:0},children:[u.jsx("h3",{children:"Saved connections"}),e.connections.map(o=>u.jsxs("div",{children:[u.jsxs("div",{className:"kv",children:[u.jsxs("span",{className:"link-btn",style:{cursor:"pointer"},onClick:()=>r(o.id),children:[o.name,o.profile?` · ${o.profile}`:""]}),u.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8},children:[o.sameOrigin?"same origin":o.baseUrl,u.jsx("button",{className:`icon-btn ${l===o.id?"active":""}`,title:"Edit",onClick:()=>i(l===o.id?null:o.id),children:u.jsx(ls,{width:15,height:15})}),u.jsx("button",{className:"icon-btn",title:"Remove",onClick:()=>n(o.id),children:u.jsx(ns,{width:15,height:15})})]})]}),l===o.id&&u.jsx("div",{style:{margin:"10px 0 18px"},children:u.jsx(gl,{initial:o,onSave:async s=>{await t(s),i(null)},onCancel:()=>i(null),saveLabel:"Save changes"})})]},o.id))]})]})})}function Lh(e){if(!e)return"";const t=e>1e12?e:e*1e3,n=Date.now()-t,r=Math.round(n/1e3);if(r<60)return"just now";const l=Math.round(r/60);if(l<60)return`${l}m ago`;const i=Math.round(l/60);if(i<24)return`${i}h ago`;const o=Math.round(i/24);return o<7?`${o}d ago`:new Date(t).toLocaleDateString()}function zh(e){return e==null||e===0?"":e<.01?`$${e.toFixed(4)}`:`$${e.toFixed(2)}`}function Ih(e){return e?e.length>14?`${e.slice(0,13)}…`:e:""}function Mh({s:e}){const t=j(c=>c.activeSessionId),n=j(c=>c.openSession),r=j(c=>c.deleteSession),l=j(c=>c.renameSession),i=j(c=>c.forkSession),o=t===e.id,s=()=>{const c=window.prompt("Rename session",e.title);c&&c.trim()&&l(e.id,c.trim())},a=()=>{window.confirm(`Delete "${e.title}"? This cannot be undone.`)&&r(e.id)};return u.jsxs("div",{className:`session-item ${o?"active":""}`,onClick:()=>n(e.id),title:e.preview||void 0,children:[u.jsxs("div",{className:"body",children:[u.jsx("div",{className:"title",children:e.title}),u.jsxs("div",{className:"meta",children:[u.jsx("span",{children:Lh(e.updatedAt)}),typeof e.messageCount=="number"&&e.messageCount>0&&u.jsxs("span",{children:[e.messageCount," msg"]}),e.source&&u.jsx("span",{children:Ih(e.source)}),e.costUsd?u.jsx("span",{children:zh(e.costUsd)}):null]})]}),u.jsxs("div",{className:"actions",onClick:c=>c.stopPropagation(),children:[u.jsx("button",{className:"icon-btn",title:"Rename",onClick:s,children:u.jsx(ls,{width:15,height:15})}),u.jsx("button",{className:"icon-btn",title:"Fork",onClick:()=>i(e.id),children:u.jsx(xn,{width:15,height:15})}),u.jsx("button",{className:"icon-btn",title:"Delete",onClick:a,children:u.jsx(ns,{width:15,height:15})})]})]})}function Oh(){const e=j(a=>a.config.connections),t=j(a=>a.config.activeConnectionId),n=j(a=>a.setActiveConnection),r=j(a=>a.setShowSettings),[l,i]=R.useState(!1),o=R.useRef(null);R.useEffect(()=>{const a=c=>{o.current&&!o.current.contains(c.target)&&i(!1)};return document.addEventListener("mousedown",a),()=>document.removeEventListener("mousedown",a)},[]);const s=e.find(a=>a.id===t)??e[0];return u.jsxs("div",{className:"profile-switch",ref:o,children:[u.jsxs("button",{className:"profile-btn",onClick:()=>i(a=>!a),children:[u.jsx("span",{className:"dot"}),u.jsx("span",{className:"name",children:(s==null?void 0:s.name)??"No connection"}),(s==null?void 0:s.profile)&&u.jsx("span",{className:"sub",children:s.profile}),u.jsx(jh,{width:15,height:15,style:{marginLeft:6,color:"var(--text-faint)"}})]}),l&&u.jsxs("div",{className:"menu",children:[e.map(a=>u.jsxs("button",{className:"menu-item",onClick:()=>{i(!1),a.id!==t&&n(a.id)},children:[u.jsx("span",{children:a.name}),a.profile&&u.jsx("span",{style:{fontSize:11,color:"var(--text-faint)"},children:a.profile}),a.id===t&&u.jsx(rs,{width:15,height:15,className:"check"})]},a.id)),u.jsxs("button",{className:"menu-item",onClick:()=>{i(!1),r(!0)},children:[u.jsx(xn,{width:15,height:15}),u.jsx("span",{children:"Add connection…"})]})]})]})}function Dh(){const e=j(c=>c.sessions),t=j(c=>c.sessionsLoading),n=j(c=>c.searchQuery),r=j(c=>c.setSearch),l=j(c=>c.newSession),i=j(c=>c.loadSessions),o=j(c=>c.setShowSettings),s=j(c=>c.sidebarOpen),a=j(c=>c.setSidebarOpen);return u.jsxs(u.Fragment,{children:[u.jsx("div",{className:`scrim ${s?"show":""}`,onClick:()=>a(!1)}),u.jsxs("aside",{className:`sidebar ${s?"open":""}`,children:[u.jsxs("div",{className:"sidebar-head",children:[u.jsxs("div",{className:"brand",children:[u.jsx(is,{height:26}),u.jsxs("div",{className:"brand-actions",children:[u.jsx("button",{className:"icon-btn",title:"Refresh",onClick:()=>i(),children:u.jsx(Nh,{width:17,height:17})}),u.jsx("button",{className:"icon-btn",title:"Settings",onClick:()=>o(!0),children:u.jsx(Sh,{width:17,height:17})})]})]}),u.jsx(Oh,{}),u.jsxs("button",{className:"new-chat",onClick:()=>l(),children:[u.jsx(xn,{width:17,height:17}),"New chat"]}),u.jsxs("div",{className:"search-wrap",children:[u.jsx(gh,{width:16,height:16}),u.jsx("input",{value:n,onChange:c=>r(c.target.value),placeholder:"Filter sessions…"})]})]}),u.jsx("div",{className:"sidebar-tools",children:u.jsxs("span",{children:[e.length," sessions"]})}),u.jsxs("div",{className:"session-list",children:[t&&e.length===0&&u.jsx("div",{className:"empty",children:"Loading sessions…"}),!t&&e.length===0&&u.jsxs("div",{className:"empty",children:["No sessions yet.",u.jsx("br",{}),"Start a new chat to begin."]}),e.map(c=>u.jsx(Mh,{s:c},c.id))]})]})]})}function $h(e,t){const n=(t||"image").trim().replace(/[^\w.-]+/g,"_").replace(/^_+|_+$/g,"").slice(0,48)||"image";let r="";const l=/^data:image\/([a-zA-Z0-9.+-]+)/.exec(e);if(l)r=l[1].toLowerCase();else try{const i=new URL(e,location.href).pathname,o=/\.([a-zA-Z0-9]{2,5})$/.exec(i);o&&(r=o[1].toLowerCase())}catch{}return r==="jpeg"&&(r="jpg"),r||(r="png"),`${n}.${r}`}function bc(e,t){const n=document.createElement("a");n.href=e,n.download=$h(e,t),n.rel="noopener",document.body.appendChild(n),n.click(),n.remove()}function Uh(e,t,n){const r=t.trim();if(!r)return null;let l=e.trim();const i=n.trim();return i&&l.startsWith(i)&&(l=l.slice(i.length)),l.startsWith("/")||(l=`/${l}`),r.replace(/\/+$/,"")+l}function Fh(e){const t=e.trim().replace(/[/\\]+$/,""),n=t.split(/[/\\]/);return n[n.length-1]||t}const ku=/(`[^`]+`)|(!\[[^\]]*\]\([^)]*\))|(\[[^\]]*\]\([^)]*\))|(\*\*[^*]+\*\*)|(\*[^*\n]+\*)|(https?:\/\/[^\s<)]+)|(data:image\/[^\s)]+)|(MEDIA:\S+)/g;function ju(e){const t=e.indexOf("](");return t===-1?{label:e,url:""}:{label:e.slice(0,t),url:e.slice(t+2)}}function Ah(e){return e.startsWith("data:")?e.replace(/\s+/g,""):e}function Vh({path:e}){const t=j(s=>s.config.mediaBaseUrl),n=j(s=>s.config.mediaPathPrefix),[r,l]=R.useState(!1),i=Uh(e,t,n),o=Fh(e);return i&&!r?u.jsxs("span",{className:"md-figure",children:[u.jsx("img",{src:i,alt:o,onError:()=>l(!0)}),u.jsxs("button",{type:"button",className:"md-download",onClick:()=>bc(i,o),children:[u.jsx(Jc,{width:15,height:15}),"Download"]})]}):u.jsxs("span",{className:"media-ref",title:e,children:[u.jsx(Ol,{width:15,height:15}),u.jsx("span",{className:"nm",children:o}),u.jsx("span",{className:"path",children:e})]})}function Cu({url:e,alt:t}){const n=Ah(e);return u.jsxs("span",{className:"md-figure",children:[u.jsx("img",{src:n,alt:t}),u.jsxs("button",{type:"button",className:"md-download",onClick:()=>bc(n,t),children:[u.jsx(Jc,{width:15,height:15}),"Download"]})]})}function Eu(e,t){const n=[];let r=0,l=0,i;for(ku.lastIndex=0;(i=ku.exec(e))!==null;){i.index>r&&n.push(e.slice(r,i.index));const o=i[0],s=`${t}-${l++}`;if(i[1])n.push(u.jsx("code",{children:o.slice(1,-1)},s));else if(i[2]){const{label:a,url:c}=ju(o.slice(2,-1));n.push(u.jsx(Cu,{url:c,alt:a},s))}else if(i[3]){const{label:a,url:c}=ju(o.slice(1,-1));n.push(u.jsx("a",{href:c,target:"_blank",rel:"noreferrer noopener",children:a},s))}else i[4]?n.push(u.jsx("strong",{children:o.slice(2,-2)},s)):i[5]?n.push(u.jsx("em",{children:o.slice(1,-1)},s)):i[6]?n.push(u.jsx("a",{href:o,target:"_blank",rel:"noreferrer noopener",children:o},s)):i[7]?n.push(u.jsx(Cu,{url:o,alt:"image"},s)):i[8]&&n.push(u.jsx(Vh,{path:o.slice(6)},s));r=i.index+o.length}return rr&&t.push(u.jsx("span",{children:Eu(e.slice(r,l.index),`t${i}`)},`t${i}`)),t.push(u.jsx("pre",{children:u.jsx("code",{children:l[2].replace(/\n$/,"")})},`c${i}`)),r=l.index+l[0].length,i++;return r{const r=/^image\//.test(t.mime)||t.dataUrl.startsWith("data:image");return u.jsxs("div",{className:"attachment",children:[r?u.jsx("img",{src:t.dataUrl,alt:t.name}):u.jsx(Ol,{width:16,height:16}),u.jsx("span",{className:"nm",children:t.name})]},n)})}):null}function Bh({call:e}){const[t,n]=R.useState(!1),r=e.status==="error"?"error":e.status==="done"?"done":"running…";return u.jsxs("div",{className:"tool-card",children:[u.jsxs("div",{className:"head",onClick:()=>n(l=>!l),style:{cursor:e.preview?"pointer":"default"},children:[u.jsx(Ol,{width:15,height:15,style:{color:"var(--text-dim)"}}),u.jsx("span",{className:"name",children:e.name}),u.jsx("span",{className:`status ${e.status==="error"?"err":e.status==="done"?"ok":""}`,children:r})]}),e.preview&&t&&u.jsx("div",{className:"preview",children:e.preview})]})}function Wh({message:e}){const[t,n]=R.useState(!1);return u.jsxs("div",{className:"tool-card",children:[u.jsxs("div",{className:"head",onClick:()=>n(r=>!r),style:{cursor:"pointer"},children:[u.jsx(Ol,{width:15,height:15,style:{color:"var(--text-dim)"}}),u.jsx("span",{className:"name",children:e.toolName??"tool result"}),u.jsx("span",{className:"status ok",children:"result"})]}),t&&u.jsx("div",{className:"preview",children:ef(e.content)})]})}function Qh({message:e}){return u.jsx("div",{style:{fontSize:12.5,color:"var(--text-faint)",padding:"2px 0 2px 41px",whiteSpace:"pre-wrap"},children:e.content})}function Kh({message:e}){const{speak:t}=Zc(),[n,r]=R.useState(!1),l=j(g=>g.config.showToolCalls),i=j(g=>g.config.showReasoning),o=j(g=>g.config.showSystem);if(e.role==="tool")return l?u.jsx(Wh,{message:e}):null;if(e.role==="system")return o?u.jsx(Qh,{message:e}):null;const s=e.role==="user",a=e.content,c=e.toolCalls??[],p=e.attachments??[],h=!!e.streaming;if(!(!!a||i&&!!e.reasoning||l&&c.length>0||p.length>0||h))return null;const y=async()=>{try{await navigator.clipboard.writeText(a),r(!0),setTimeout(()=>r(!1),1400)}catch{}};return u.jsxs("div",{className:`msg ${s?"user":"assistant"}`,children:[u.jsx("div",{className:`avatar ${s?"user":"brand"}`,children:s?u.jsx(Eh,{width:16,height:16}):u.jsx(qc,{height:30,withText:!1})}),u.jsxs("div",{className:"content",children:[u.jsx("div",{className:"who",children:s?"You":"Hermes"}),e.reasoning&&i&&u.jsxs("details",{className:"reasoning",children:[u.jsxs("summary",{children:[u.jsx(_h,{width:14,height:14}),"Reasoning"]}),u.jsx("div",{className:"body",children:e.reasoning})]}),l&&c.map(g=>u.jsx(Bh,{call:g},g.id)),a?u.jsx("div",{className:"bubble",children:s?a:ef(a)}):h?u.jsxs("div",{className:"typing",children:[u.jsx("span",{}),u.jsx("span",{}),u.jsx("span",{})]}):null,u.jsx(Hh,{items:p}),!s&&a&&!h&&u.jsxs("div",{className:"msg-actions",children:[u.jsx("button",{className:"icon-btn",title:"Copy",onClick:y,children:n?u.jsx(rs,{width:15,height:15}):u.jsx("span",{style:{fontSize:13},children:"⧉"})}),u.jsx("button",{className:"icon-btn",title:"Speak",onClick:()=>t(a),children:u.jsx(Ch,{width:15,height:15})})]})]})]})}function Nu(){const e=window;return e.SpeechRecognition??e.webkitSpeechRecognition??null}function Yh(){const[e,t]=R.useState(!1),[n,r]=R.useState(""),[l,i]=R.useState(null),o=R.useRef(null),s=R.useRef(""),a=typeof window<"u"&&!!Nu(),c=R.useCallback(()=>{var h;(h=o.current)==null||h.stop(),t(!1)},[]),p=R.useCallback(h=>{const d=Nu();if(!d){i("Speech recognition isn't supported in this browser.");return}i(null),r(""),s.current="";const y=new d;y.lang=navigator.language||"en-US",y.continuous=!0,y.interimResults=!0,y.onresult=g=>{let x="";for(let z=g.resultIndex;z{i(g.error==="not-allowed"?"Microphone permission denied.":"Speech recognition error."),t(!1)},y.onend=()=>{t(!1),r("");const g=s.current.trim();g&&h(g)},o.current=y,y.start(),t(!0)},[]);return{supported:a,listening:e,interim:n,error:l,start:p,stop:c}}function Gh(){const[e,t]=R.useState(!1),[n,r]=R.useState(null),l=R.useRef(null),i=R.useRef([]),o=R.useRef(null),s=R.useCallback(async()=>{var c;if(r(null),!((c=navigator.mediaDevices)!=null&&c.getUserMedia))return r("Microphone capture is not supported in this browser."),!1;try{const p=await navigator.mediaDevices.getUserMedia({audio:!0}),h=new MediaRecorder(p);return i.current=[],h.ondataavailable=d=>{d.data.size>0&&i.current.push(d.data)},h.onstop=()=>{var y;p.getTracks().forEach(g=>g.stop());const d=new Blob(i.current,{type:h.mimeType||"audio/webm"});(y=o.current)==null||y.call(o,d.size>0?d:null),o.current=null},l.current=h,h.start(),t(!0),!0}catch(p){return r(p instanceof Error?p.message:"Could not access the microphone."),!1}},[]),a=R.useCallback(()=>new Promise(c=>{const p=l.current;if(!p||p.state==="inactive"){t(!1),c(null);return}o.current=c,p.stop(),t(!1)}),[]);return{recording:e,error:n,start:s,stop:a}}async function Xh(e,t){const n=new FormData,r=e.type.includes("ogg")?"ogg":e.type.includes("mp4")?"mp4":"webm";n.append("file",e,`recording.${r}`),t.model&&n.append("model",t.model);const l={};t.key&&(l.Authorization=`Bearer ${t.key}`);let i;try{i=await fetch(t.url,{method:"POST",headers:l,body:n})}catch{throw new Error(`Could not reach the transcription endpoint (${t.url}).`)}const o=await i.text();let s;try{s=o?JSON.parse(o):void 0}catch{s=o}if(!i.ok){const a=s&&typeof s=="object"?s.error:void 0,c=typeof a=="string"?a:a==null?void 0:a.message;throw new Error(c||`Transcription failed (HTTP ${i.status}).`)}if(s&&typeof s=="object"){const a=s;if(typeof a.text=="string")return a.text;if(typeof a.transcript=="string")return a.transcript}return typeof s=="string"?s:""}function Zh(e){return new Promise((t,n)=>{const r=new FileReader;r.onload=()=>t({name:e.name,mime:e.type||"application/octet-stream",dataUrl:String(r.result),size:e.size}),r.onerror=()=>n(r.error),r.readAsDataURL(e)})}const Jh=()=>{var e;return typeof window<"u"&&((e=window.matchMedia)==null?void 0:e.call(window,"(pointer: coarse)").matches)};function qh(){const e=j(k=>k.streaming),t=j(k=>k.send),n=j(k=>k.steer),r=j(k=>k.cancel),l=j(k=>k.steerLeftover),i=j(k=>k.clearSteerLeftover),o=j(k=>k.setToast),s=j(k=>k.config.transcribeUrl),a=j(k=>k.config.transcribeKey),c=j(k=>k.config.transcribeModel),[p,h]=R.useState(""),[d,y]=R.useState([]),[g,x]=R.useState(!1),z=R.useRef(null),m=R.useRef(null),f=Yh(),v=Gh(),w=!!s.trim(),C=w||f.supported,_=f.listening||v.recording;R.useEffect(()=>{l&&(h(k=>k||l),i())},[l,i]),R.useEffect(()=>{f.error&&o(f.error)},[f.error,o]),R.useEffect(()=>{v.error&&o(v.error)},[v.error,o]),R.useEffect(()=>{const k=z.current;k&&(k.style.height="auto",k.style.height=`${Math.min(k.scrollHeight,200)}px`)},[p]);const P=async k=>{for(const U of k)try{const Fe=await Zh(U);y(E=>[...E,Fe])}catch{o(`Could not attach ${U.name}`)}},T=()=>{const k=p.trim();if(!(!k&&!d.length)){if(e){n(k),h("");return}t(k,d),h(""),y([])}},H=k=>{const U=k.trim();U&&h(Fe=>Fe?`${Fe} ${U}`:U)},M=async()=>{if(f.listening){f.stop();return}if(v.recording){const k=await v.stop();if(!k)return;x(!0);try{const U=await Xh(k,{url:s.trim(),key:a.trim()||void 0,model:c.trim()||void 0});H(U)}catch(U){o(U instanceof Error?U.message:"Transcription failed.")}finally{x(!1)}}},we=async()=>{if(_){await M();return}if(w){await v.start()||o("Could not access the microphone.");return}if(f.supported){if(!window.isSecureContext){o("Dictation needs a secure context (HTTPS or localhost).");return}f.start(H);return}o("Dictation isn't available in this browser. Use Chrome, Edge, or Safari — or set a transcription endpoint in Settings.")},jt=k=>{k.key==="Enter"&&!k.shiftKey&&!Jh()&&(k.preventDefault(),T())},Ct=p.trim().length>0||d.length>0,Sn=g?"Transcribing…":f.listening?f.interim||"Listening…":v.recording?"Recording… tap the mic to stop":"";return u.jsx("div",{className:"composer-wrap",children:u.jsxs("div",{className:"composer",onDragOver:k=>k.preventDefault(),onDrop:k=>{var U;k.preventDefault(),(U=k.dataTransfer.files)!=null&&U.length&&P(Array.from(k.dataTransfer.files))},children:[d.length>0&&u.jsx("div",{className:"attach-chips",children:d.map(k=>u.jsxs("div",{className:"chip",children:[/^image\//.test(k.mime)?u.jsx("img",{src:k.dataUrl,alt:k.name}):u.jsx(Su,{width:15,height:15}),u.jsx("span",{className:"nm",children:k.name}),u.jsx("button",{title:"Remove",onClick:()=>y(U=>U.filter(Fe=>Fe!==k)),children:u.jsx(ts,{width:14,height:14})})]},k.name+k.size))}),Sn&&u.jsxs("div",{className:"recording-pill",style:{padding:"2px 4px"},children:[!g&&u.jsx("span",{className:"pulse"}),u.jsx("span",{style:{color:"var(--text-dim)"},children:Sn})]}),u.jsx("textarea",{ref:z,rows:1,value:p,onChange:k=>h(k.target.value),onKeyDown:jt,onPaste:k=>{const U=Array.from(k.clipboardData.files);U.length&&(k.preventDefault(),P(U))},placeholder:e?"Steer the running turn…":"Message Hermes…"}),u.jsxs("div",{className:"composer-row",children:[u.jsx("input",{ref:m,type:"file",accept:"image/*",multiple:!0,hidden:!0,onChange:k=>{var U;(U=k.target.files)!=null&&U.length&&P(Array.from(k.target.files)),k.target.value=""}}),u.jsx("button",{className:"icon-btn",title:"Attach image",onClick:()=>{var k;return(k=m.current)==null?void 0:k.click()},children:u.jsx(Su,{width:19,height:19})}),u.jsx("button",{className:`icon-btn ${_?"active":""}`,title:_?"Stop dictation":C?"Dictate (speak your prompt)":"Dictation unavailable — see Settings",onClick:we,disabled:g,children:u.jsx(wh,{width:19,height:19})}),u.jsx("div",{className:"spacer"}),e?u.jsx("button",{className:"send-btn stop",title:"Stop",onClick:()=>r(),children:u.jsx(xh,{width:18,height:18})}):u.jsx("button",{className:"send-btn",title:"Send",disabled:!Ct,onClick:T,children:u.jsx(yh,{width:18,height:18})})]})]})})}function bh(){const e=j(a=>a.config.showToolCalls),t=j(a=>a.config.showReasoning),n=j(a=>a.config.showSystem),r=j(a=>a.updatePrefs),[l,i]=R.useState(!1),o=R.useRef(null);R.useEffect(()=>{const a=c=>{o.current&&!o.current.contains(c.target)&&i(!1)};return document.addEventListener("mousedown",a),()=>document.removeEventListener("mousedown",a)},[]);const s=[["Tool calls & results",e,a=>r({showToolCalls:a})],["Reasoning",t,a=>r({showReasoning:a})],["System messages",n,a=>r({showSystem:a})]];return u.jsxs("div",{className:"profile-switch",ref:o,style:{width:"auto"},children:[u.jsx("button",{className:`icon-btn ${l?"active":""}`,title:"Filter messages",onClick:()=>i(a=>!a),children:u.jsx(Ph,{width:19,height:19})}),l&&u.jsx("div",{className:"menu",style:{left:"auto",right:0,width:230},children:s.map(([a,c,p])=>u.jsxs("label",{className:"menu-item toggle",children:[u.jsx("input",{type:"checkbox",checked:c,onChange:h=>p(h.target.checked)}),a]},a))})]})}function em(){const e=j(p=>p.session),t=j(p=>p.messages),n=j(p=>p.sessionLoading),r=j(p=>p.streamError),l=j(p=>p.setSidebarOpen),i=j(p=>p.newSession),o=R.useRef(null),s=R.useRef(!0),a=()=>{const p=o.current;p&&(s.current=p.scrollHeight-p.scrollTop-p.clientHeight<120)};R.useEffect(()=>{const p=o.current;p&&s.current&&(p.scrollTop=p.scrollHeight)},[t]);const c=u.jsxs("div",{className:"chat-head",children:[u.jsx("button",{className:"icon-btn menu-btn",onClick:()=>l(!0),children:u.jsx(kh,{width:20,height:20})}),u.jsxs("div",{className:"titles",children:[u.jsx("div",{className:"t",children:(e==null?void 0:e.title)??"Hermes"}),u.jsxs("div",{className:"s",children:[(e==null?void 0:e.model)&&u.jsx("span",{className:"pill",children:e.model}),(e==null?void 0:e.source)&&u.jsx("span",{children:e.source})]})]}),u.jsx(bh,{}),u.jsx("button",{className:"icon-btn",title:"New chat",onClick:()=>i(),children:u.jsx(xn,{width:19,height:19})})]});return!e&&!n?u.jsxs("div",{className:"main",children:[c,u.jsx("div",{className:"center-fill",children:u.jsxs("div",{children:[u.jsx("div",{style:{fontSize:40,marginBottom:12},children:"💬"}),u.jsx("div",{style:{color:"var(--text)",fontWeight:600,marginBottom:6},children:"No conversation open"}),u.jsx("div",{children:"Pick a session from the sidebar, or start a new chat."}),u.jsx("button",{className:"btn primary",style:{marginTop:18},onClick:()=>i(),children:"New chat"})]})})]}):u.jsxs("div",{className:"main",children:[c,u.jsx("div",{className:"messages",ref:o,onScroll:a,children:u.jsxs("div",{className:"messages-inner",children:[n&&u.jsx("div",{className:"center-fill",children:u.jsx("div",{className:"spinner"})}),t.map(p=>u.jsx(Kh,{message:p},p.id)),r&&u.jsx("div",{className:"alert error",children:r})]})}),u.jsx(qh,{})]})}function fi(){const e=j(g=>g.config),t=j(g=>g.capabilities),n=j(g=>g.models),r=j(g=>g.saveConnection),l=j(g=>g.removeConnection),i=j(g=>g.setActiveConnection),o=j(g=>g.updatePrefs),s=j(g=>g.setShowSettings),[a,c]=R.useState(!1),[p,h]=R.useState(null),d=Qn(e),y=t!=null&&t.features?Object.entries(t.features):[];return u.jsx("div",{className:"panel",onClick:()=>s(!1),children:u.jsxs("div",{className:"panel-inner",onClick:g=>g.stopPropagation(),children:[u.jsxs("div",{className:"panel-head",children:[u.jsxs("h2",{children:["Settings ",u.jsx("span",{className:"build-date",children:"2026-11-04_15:46"})]}),u.jsx("button",{className:"icon-btn",onClick:()=>s(!1),children:u.jsx(ts,{width:20,height:20})})]}),u.jsxs("div",{className:"section",children:[u.jsx("h3",{children:"Connections"}),e.connections.map(g=>u.jsxs("div",{children:[u.jsxs("div",{className:"kv",children:[u.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8},children:[u.jsxs("button",{className:"link-btn",style:{cursor:"pointer"},onClick:()=>i(g.id),children:[g.name,g.profile?` · ${g.profile}`:""]}),g.id===e.activeConnectionId&&u.jsx(rs,{width:14,height:14,style:{color:"var(--accent)"}})]}),u.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8},children:[g.sameOrigin?"same origin":g.baseUrl,u.jsx("button",{className:`icon-btn ${p===g.id?"active":""}`,title:"Edit",onClick:()=>{c(!1),h(p===g.id?null:g.id)},children:u.jsx(ls,{width:15,height:15})}),u.jsx("button",{className:"icon-btn",title:"Remove",onClick:()=>l(g.id),children:u.jsx(ns,{width:15,height:15})})]})]}),p===g.id&&u.jsx("div",{style:{margin:"10px 0 18px"},children:u.jsx(gl,{initial:g,onSave:async x=>{await r(x),h(null)},onCancel:()=>h(null),saveLabel:"Save changes"})})]},g.id)),a?u.jsx("div",{style:{marginTop:12},children:u.jsx(gl,{onSave:async g=>{await r(g),c(!1)},onCancel:()=>c(!1),saveLabel:"Add"})}):u.jsxs("button",{className:"btn",style:{marginTop:12},onClick:()=>{h(null),c(!0)},children:[u.jsx(xn,{width:15,height:15,style:{verticalAlign:"-2px",marginRight:6}}),"Add connection"]})]}),u.jsxs("div",{className:"section",children:[u.jsx("h3",{children:"Voice"}),u.jsxs("label",{className:"toggle",style:{marginBottom:12},children:[u.jsx("input",{type:"checkbox",checked:e.speakReplies,onChange:g=>o({speakReplies:g.target.checked})}),"Speak replies automatically"]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Voice (browser)"}),u.jsx("input",{value:e.ttsVoice,onChange:g=>o({ttsVoice:g.target.value}),placeholder:"System default"})]})]}),u.jsxs("div",{className:"section",children:[u.jsx("h3",{children:"Dictation"}),u.jsx("div",{className:"hint",style:{marginTop:0,marginBottom:10},children:"If a transcription endpoint is set below, it's used for dictation (usually far more accurate). Otherwise Chrome, Edge, and Safari fall back to on-device dictation via the Web Speech API — Firefox has no speech API, so it needs an endpoint set here."}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Transcription endpoint"}),u.jsx("input",{value:e.transcribeUrl,onChange:g=>o({transcribeUrl:g.target.value}),placeholder:"https://api.openai.com/v1/audio/transcriptions",autoCapitalize:"none",autoCorrect:"off",spellCheck:!1,inputMode:"url"}),u.jsxs("div",{className:"hint",children:["Any OpenAI-compatible ",u.jsx("code",{children:"/v1/audio/transcriptions"})," — OpenAI, Groq, or a local whisper.cpp server. Leave empty to disable."]})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"API key"}),u.jsx("input",{type:"password",value:e.transcribeKey,onChange:g=>o({transcribeKey:g.target.value}),placeholder:"sk-…",autoCapitalize:"none"})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Model"}),u.jsx("input",{value:e.transcribeModel,onChange:g=>o({transcribeModel:g.target.value}),placeholder:"whisper-1",autoCapitalize:"none"})]})]}),u.jsxs("div",{className:"section",children:[u.jsx("h3",{children:"Media"}),u.jsxs("div",{className:"hint",style:{marginTop:0,marginBottom:10},children:["Your agent emits ",u.jsx("code",{children:"MEDIA:/path/to/file.png"})," for generated files. The Hermes API server can't serve those, so point this at a URL where the agent's workspace is reachable to render them as images."]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Media base URL"}),u.jsx("input",{value:e.mediaBaseUrl,onChange:g=>o({mediaBaseUrl:g.target.value}),placeholder:"https://files.example.com",autoCapitalize:"none",autoCorrect:"off",spellCheck:!1,inputMode:"url"})]}),u.jsxs("div",{className:"field",children:[u.jsx("label",{children:"Strip path prefix"}),u.jsx("input",{value:e.mediaPathPrefix,onChange:g=>o({mediaPathPrefix:g.target.value}),placeholder:"/root/workspace",autoCapitalize:"none",autoCorrect:"off",spellCheck:!1}),u.jsxs("div",{className:"hint",children:["Removed from the start of the path before appending. E.g. base"," ",u.jsx("code",{children:"https://files.example.com"})," + prefix ",u.jsx("code",{children:"/root/workspace"})," turns"," ",u.jsx("code",{children:"MEDIA:/root/workspace/a.png"})," into"," ",u.jsx("code",{children:"https://files.example.com/a.png"}),"."]})]})]}),u.jsxs("div",{className:"section",children:[u.jsx("h3",{children:"Server"}),u.jsxs("div",{className:"kv",children:[u.jsx("span",{children:"Connection"}),u.jsx("span",{children:(d==null?void 0:d.name)??"—"})]}),u.jsxs("div",{className:"kv",children:[u.jsx("span",{children:"Platform"}),u.jsx("span",{children:(t==null?void 0:t.platform)??"—"})]}),u.jsxs("div",{className:"kv",children:[u.jsx("span",{children:"Model"}),u.jsx("span",{children:(t==null?void 0:t.model)??"—"})]}),u.jsxs("div",{className:"kv",children:[u.jsx("span",{children:"Models available"}),u.jsx("span",{children:n.length||"—"})]}),y.length>0&&u.jsxs("div",{style:{marginTop:10},children:[u.jsx("div",{className:"hint",style:{marginBottom:6},children:"Features"}),u.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:6},children:y.filter(([,g])=>g===!0).map(([g])=>u.jsx("span",{style:{fontSize:11,padding:"2px 8px",borderRadius:20,background:"var(--bg-elev2)",border:"1px solid var(--border)",color:"var(--text-dim)"},children:g},g))})]})]})]})})}function di(){const e=j(n=>n.toast),t=j(n=>n.setToast);return R.useEffect(()=>{if(!e)return;const n=setTimeout(()=>t(null),5e3);return()=>clearTimeout(n)},[e,t]),e?u.jsx("div",{className:"toast",onClick:()=>t(null),children:e}):null}function tm(){const e=j(i=>i.messages),t=j(i=>i.streaming),n=j(i=>i.config.speakReplies),{speak:r}=Zc(),l=R.useRef(null);return R.useEffect(()=>{if(!n||t)return;const i=e[e.length-1];!i||i.role!=="assistant"||!i.id||i.id===l.current||i.content.trim()&&(l.current=i.id,r(i.content))},[e,t,n,r]),null}function nm(){const e=j(o=>o.ready),t=j(o=>o.config),n=j(o=>o.connectionError),r=j(o=>o.showSettings),l=j(o=>o.bootstrap),i=j(o=>o.connect);return R.useEffect(()=>{l()},[l]),e?ph(t)?n?u.jsxs("div",{className:"screen",children:[u.jsxs("div",{className:"card",children:[u.jsx("div",{style:{marginBottom:18},children:u.jsx(is,{height:30})}),u.jsx("h1",{children:"Can’t reach Hermes"}),u.jsx("p",{className:"lead",children:n}),u.jsxs("div",{className:"actions",children:[u.jsx("button",{className:"btn",onClick:()=>j.getState().setShowSettings(!0),children:"Settings"}),u.jsx("button",{className:"btn primary",onClick:()=>i(),children:"Retry"})]})]}),r&&u.jsx(fi,{}),u.jsx(di,{})]}):u.jsxs(u.Fragment,{children:[u.jsxs("div",{className:"app",children:[u.jsx(Dh,{}),u.jsx(em,{})]}),u.jsx(tm,{}),r&&u.jsx(fi,{}),u.jsx(di,{})]}):u.jsxs(u.Fragment,{children:[u.jsx(Rh,{}),r&&u.jsx(fi,{}),u.jsx(di,{})]}):u.jsx("div",{className:"screen",children:u.jsx("div",{className:"spinner"})})}Mp({immediate:!0});const _u=document.getElementById("root");_u&&Vc(_u).render(u.jsx(R.StrictMode,{children:u.jsx(nm,{})})); diff --git a/assets/index-CWSassUi.css b/assets/index-BQJys9C3.css similarity index 92% rename from assets/index-CWSassUi.css rename to assets/index-BQJys9C3.css index a31c75a..500e439 100644 --- a/assets/index-CWSassUi.css +++ b/assets/index-BQJys9C3.css @@ -1 +1 @@ -:root{--bg: #000810;--bg-elev: #010f20;--bg-elev2: #001a30;--bg-hover: #001a30;--border: #0a3060;--border-soft: #072348;--text: #c8f0ff;--text-dim: #6aa8bf;--text-faint: #2e6a80;--accent: #00f5ff;--accent-soft: rgba(0, 245, 255, .12);--accent-strong: #00c8d4;--accent-contrast: #001018;--danger: #ff3b3b;--danger-soft: rgba(255, 59, 59, .14);--ok: #00ff88;--warn: #ffaa00;--radius: 10px;--radius-sm: 8px;--sidebar-w: 304px;--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji", sans-serif;--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;color-scheme:dark}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{font-family:var(--font);background:var(--bg);color:var(--text);-webkit-font-smoothing:antialiased;overscroll-behavior-y:none}button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}input,textarea,select{font-family:inherit;font-size:15px;color:var(--text);background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:10px 12px;outline:none;width:100%}input:focus,textarea:focus,select:focus{border-color:var(--accent)}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:#0a3060;border-radius:8px;border:2px solid transparent;background-clip:padding-box}::-webkit-scrollbar-thumb:hover{background:#0f4a6e;background-clip:padding-box}.app{display:flex;height:100dvh;overflow:hidden}.sidebar{width:var(--sidebar-w);flex-shrink:0;background:var(--bg-elev);border-right:1px solid var(--border);display:flex;flex-direction:column;min-height:0}.main{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--bg)}.scrim{display:none}@media (max-width: 820px){.sidebar{position:fixed;inset:0 auto 0 0;z-index:40;transform:translate(-100%);transition:transform .22s ease;box-shadow:0 0 40px #00000080;padding-top:env(safe-area-inset-top)}.sidebar.open{transform:translate(0)}.scrim.show{display:block;position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;z-index:30}}.sidebar-head{padding:14px 14px 10px;display:flex;flex-direction:column;gap:10px;border-bottom:1px solid var(--border-soft)}.brand{display:flex;align-items:center;gap:9px;font-weight:650;letter-spacing:.2px}.brand-mark{width:26px;height:26px;border-radius:7px;background:linear-gradient(180deg,#003545,#00202e);border:1px solid #005570;display:grid;place-items:center;color:var(--accent);font-weight:800;font-size:14px}.brand-link{display:inline-flex;align-items:center;text-decoration:none;border-radius:8px;padding:2px 4px;margin-left:-4px}.brand-link:hover{background:var(--bg-hover)}.brand-actions{margin-left:auto;display:flex;gap:4px}.icon-btn{width:34px;height:34px;border-radius:9px;display:grid;place-items:center;color:var(--text-dim);transition:background .15s,color .15s}.icon-btn:hover{background:var(--bg-hover);color:var(--text)}.icon-btn.active{color:var(--accent);background:var(--accent-soft)}.profile-switch{position:relative}.profile-btn{width:100%;display:flex;align-items:center;gap:9px;padding:9px 11px;border-radius:var(--radius-sm);background:var(--bg-elev2);border:1px solid var(--border);text-align:left}.profile-btn:hover{border-color:#2f3b4d}.profile-btn .dot{width:8px;height:8px;border-radius:50%;background:var(--ok);flex-shrink:0}.profile-btn .name{font-weight:600;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.profile-btn .sub{font-size:11px;color:var(--text-faint);margin-left:auto;flex-shrink:0}.menu{position:absolute;top:calc(100% + 6px);left:0;right:0;background:var(--bg-elev2);border:1px solid var(--border);border-radius:var(--radius-sm);padding:5px;z-index:20;box-shadow:0 12px 30px #00000073;max-height:320px;overflow:auto}.menu-item{width:100%;display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:7px;font-size:14px;text-align:left}.menu-item:hover{background:var(--bg-hover)}.menu-item .check{margin-left:auto;color:var(--accent)}.new-chat{display:flex;align-items:center;justify-content:center;gap:8px;padding:10px;border-radius:var(--radius-sm);background:var(--accent);color:var(--accent-contrast);font-weight:700;font-size:14px}.new-chat:hover{background:var(--accent-strong)}.search-wrap{position:relative}.search-wrap svg{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:var(--text-faint);pointer-events:none}.search-wrap input{padding-left:34px;background:var(--bg)}.sidebar-tools{display:flex;align-items:center;gap:8px;padding:8px 14px;font-size:12px;color:var(--text-dim);border-bottom:1px solid var(--border-soft)}.toggle{display:inline-flex;align-items:center;gap:6px;cursor:pointer;-webkit-user-select:none;user-select:none}.toggle input{width:auto;accent-color:var(--accent)}.session-list{flex:1;overflow-y:auto;padding:8px;min-height:0}.group-label{font-size:11px;text-transform:uppercase;letter-spacing:.6px;color:var(--text-faint);padding:12px 8px 6px;font-weight:600}.session-item{display:flex;align-items:center;gap:10px;padding:9px 10px;border-radius:var(--radius-sm);cursor:pointer;position:relative}.session-item:hover{background:var(--bg-hover)}.session-item.active{background:var(--accent-soft)}.session-item .body{min-width:0;flex:1}.session-item .title{font-size:14px;font-weight:550;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-item .meta{font-size:11.5px;color:var(--text-faint);display:flex;gap:8px;margin-top:2px;overflow:hidden;white-space:nowrap}.session-item .meta .badge{color:var(--accent)}.session-item .actions{display:none;gap:2px}.session-item:hover .actions{display:flex}.session-item .actions .icon-btn{width:28px;height:28px}.pin-dot{color:var(--warn);flex-shrink:0}.empty{padding:30px 16px;text-align:center;color:var(--text-faint);font-size:13.5px;line-height:1.6}.chat-head{display:flex;align-items:center;gap:10px;padding:10px 14px;padding-top:calc(10px + env(safe-area-inset-top));border-bottom:1px solid var(--border);background:var(--bg-elev);min-height:56px}.chat-head .titles{min-width:0;flex:1}.chat-head .t{font-weight:600;font-size:15px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chat-head .s{font-size:11.5px;color:var(--text-faint);display:flex;gap:8px;margin-top:1px}.chat-head .s .pill{background:var(--bg-elev2);border:1px solid var(--border);border-radius:20px;padding:1px 8px}.menu-btn{display:none}@media (max-width: 820px){.menu-btn{display:grid}}.messages{flex:1;overflow-y:auto;padding:20px 16px 8px;display:flex;flex-direction:column;gap:18px;min-height:0}.messages-inner{width:100%;max-width:820px;margin:0 auto;display:flex;flex-direction:column;gap:18px}.msg{display:flex;gap:11px;align-items:flex-start}.msg .avatar{width:30px;height:30px;border-radius:8px;flex-shrink:0;display:grid;place-items:center;background:var(--bg-elev2);border:1px solid var(--border);color:var(--text-dim)}.msg.user .avatar{background:var(--accent-soft);color:var(--accent);border-color:transparent}.msg .avatar.brand{background:none;border:none;padding:0;border-radius:9px}.msg .content{min-width:0;flex:1;padding-top:3px}.msg .who{font-size:12px;color:var(--text-faint);margin-bottom:5px;display:flex;align-items:center;gap:8px}.msg .bubble{font-size:15px;line-height:1.62;white-space:pre-wrap;word-wrap:break-word;overflow-wrap:anywhere}.msg.user .bubble{background:var(--bg-elev2);border:1px solid var(--border);border-radius:12px;padding:10px 13px}.msg .bubble code{font-family:var(--mono);font-size:13px;background:var(--bg-elev2);padding:1px 5px;border-radius:5px}.msg .bubble pre{background:var(--bg-elev2);border:1px solid var(--border);border-radius:10px;padding:12px;overflow-x:auto;font-family:var(--mono);font-size:13px}.msg .bubble pre code{background:none;padding:0}.msg .bubble a{color:var(--accent)}.msg .bubble img{max-width:100%;border-radius:10px;margin-top:6px}.md-figure{display:block;margin-top:8px}.md-figure img{display:block;max-width:100%;border-radius:10px;margin-top:0}.md-download{display:inline-flex;align-items:center;gap:6px;margin-top:8px;padding:6px 12px;border-radius:8px;border:1px solid var(--border);background:var(--bg-elev2);color:var(--text-dim);font-size:12.5px;font-weight:600}.md-download:hover{background:var(--bg-hover);color:var(--text);border-color:var(--accent)}.media-ref{display:inline-flex;align-items:center;gap:8px;max-width:100%;margin-top:6px;padding:7px 11px;border:1px solid var(--border);border-radius:9px;background:var(--bg-elev);color:var(--text-dim);font-size:12.5px}.media-ref .nm{color:var(--text);font-weight:600}.media-ref .path{font-family:var(--mono);font-size:11.5px;color:var(--text-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:320px}.msg-actions{display:flex;gap:4px;margin-top:6px;opacity:0;transition:opacity .15s}.msg:hover .msg-actions{opacity:1}.msg-actions .icon-btn{width:28px;height:28px}.typing{display:inline-flex;gap:4px;padding:4px 0}.typing span{width:6px;height:6px;border-radius:50%;background:var(--text-faint);animation:blink 1.3s infinite both}.typing span:nth-child(2){animation-delay:.2s}.typing span:nth-child(3){animation-delay:.4s}@keyframes blink{0%,80%,to{opacity:.25}40%{opacity:1}}.reasoning{border:1px solid var(--border);border-radius:10px;background:var(--bg-elev);margin-bottom:8px;overflow:hidden}.reasoning summary{cursor:pointer;padding:8px 12px;font-size:12.5px;color:var(--text-dim);display:flex;align-items:center;gap:7px;list-style:none}.reasoning summary::-webkit-details-marker{display:none}.reasoning .body{padding:0 12px 12px;font-size:13.5px;color:var(--text-dim);white-space:pre-wrap;line-height:1.55}.tool-card{border:1px solid var(--border);border-radius:10px;background:var(--bg-elev);margin:6px 0;overflow:hidden}.tool-card .head{display:flex;align-items:center;gap:8px;padding:8px 12px;font-size:13px}.tool-card .head .name{font-weight:600;font-family:var(--mono);font-size:12.5px}.tool-card .head .status{margin-left:auto;font-size:11px;color:var(--text-faint)}.tool-card .head .status.err{color:var(--danger)}.tool-card .head .status.ok{color:var(--ok)}.tool-card .preview{padding:0 12px 10px;font-family:var(--mono);font-size:12px;color:var(--text-dim);white-space:pre-wrap;word-break:break-word;max-height:220px;overflow:auto}.attachments{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}.attachment{display:flex;align-items:center;gap:8px;border:1px solid var(--border);border-radius:9px;padding:6px 9px;font-size:12.5px;background:var(--bg-elev);max-width:240px}.attachment img{width:34px;height:34px;object-fit:cover;border-radius:6px}.attachment .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.composer-wrap{padding:10px 16px calc(12px + env(safe-area-inset-bottom));border-top:1px solid var(--border);background:var(--bg-elev)}.composer{max-width:820px;margin:0 auto;border:1px solid var(--border);border-radius:16px;background:var(--bg);padding:8px 8px 8px 12px;display:flex;flex-direction:column;gap:6px;transition:border-color .15s}.composer:focus-within{border-color:#33415a}.composer textarea{border:none;background:none;padding:6px 0;resize:none;max-height:200px;line-height:1.5}.composer textarea:focus{border:none}.composer-row{display:flex;align-items:center;gap:6px}.composer-row .spacer{flex:1}.send-btn{width:38px;height:38px;border-radius:11px;background:var(--accent);color:var(--accent-contrast);display:grid;place-items:center}.send-btn:disabled{background:var(--bg-elev2);color:var(--text-faint);cursor:default}.send-btn.stop{background:var(--danger)}.recording-pill{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--danger);padding:0 6px}.recording-pill .pulse{width:9px;height:9px;border-radius:50%;background:var(--danger);animation:pulse 1s infinite}@keyframes pulse{0%,to{opacity:1}50%{opacity:.3}}.attach-chips{display:flex;flex-wrap:wrap;gap:6px;padding:2px 0}.chip{display:flex;align-items:center;gap:6px;background:var(--bg-elev2);border:1px solid var(--border);border-radius:8px;padding:4px 6px 4px 8px;font-size:12px;max-width:220px}.chip img{width:26px;height:26px;object-fit:cover;border-radius:5px}.chip .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chip button{color:var(--text-faint);display:grid;place-items:center}.chip button:hover{color:var(--danger)}.prompt{max-width:820px;margin:0 auto 10px;border:1px solid var(--warn);background:#fbbf2414;border-radius:12px;padding:12px 14px}.prompt.clarify{border-color:var(--accent);background:var(--accent-soft)}.prompt .pt{font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--warn);font-weight:700;margin-bottom:6px}.prompt.clarify .pt{color:var(--accent)}.prompt .q{font-size:14.5px;line-height:1.5;margin-bottom:10px}.prompt .cmd{font-family:var(--mono);font-size:12.5px;background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:8px 10px;margin-bottom:10px;white-space:pre-wrap;word-break:break-word}.prompt .btns{display:flex;flex-wrap:wrap;gap:8px}.btn{padding:8px 14px;border-radius:9px;font-size:13.5px;font-weight:600;border:1px solid var(--border);background:var(--bg-elev2)}.btn:hover{background:var(--bg-hover)}.btn.primary{background:var(--accent);border-color:transparent;color:var(--accent-contrast);font-weight:700}.btn.primary:hover{background:var(--accent-strong)}.btn.danger{color:var(--danger);border-color:#f8717166}.btn.danger:hover{background:var(--danger-soft)}.btn:disabled{opacity:.5;cursor:default}.screen{min-height:100dvh;display:flex;align-items:center;justify-content:center;padding:24px;padding-top:calc(24px + env(safe-area-inset-top));background:radial-gradient(1200px 600px at 50% -10%,#00202e 0%,var(--bg) 55%)}.card{width:100%;max-width:460px;background:var(--bg-elev);border:1px solid var(--border);border-radius:18px;padding:26px;box-shadow:0 24px 60px #00000073}.card h1{margin:0 0 4px;font-size:22px}.card .lead{color:var(--text-dim);font-size:13.5px;line-height:1.6;margin:0 0 20px}.field{margin-bottom:14px}.field label{display:block;font-size:12.5px;font-weight:600;color:var(--text-dim);margin-bottom:6px}.field .hint{font-size:11.5px;color:var(--text-faint);margin-top:5px;line-height:1.5}.row{display:flex;gap:8px;align-items:center}.header-row{display:flex;align-items:center;gap:8px;margin-bottom:6px}.header-row input{flex:1}.alert{border-radius:10px;padding:10px 12px;font-size:13px;margin-bottom:14px;line-height:1.5}.alert.error{background:var(--danger-soft);color:#fca5a5;border:1px solid rgba(248,113,113,.35)}.alert.ok{background:#34d3991f;color:#6ee7b7;border:1px solid rgba(52,211,153,.3)}.alert.info{background:var(--accent-soft);color:#9dc4fb;border:1px solid rgba(79,156,249,.3)}.card .actions{display:flex;gap:10px;margin-top:20px}.card .actions .btn{flex:1;text-align:center;padding:11px}.link-btn{color:var(--accent);font-size:13px;text-decoration:none}.link-btn:hover{text-decoration:underline}.panel{position:fixed;top:0;right:0;bottom:0;left:0;z-index:60;background:#0000008c;display:flex;justify-content:flex-end}.panel-inner{width:100%;max-width:440px;background:var(--bg-elev);border-left:1px solid var(--border);height:100%;overflow-y:auto;padding:20px;padding-top:calc(20px + env(safe-area-inset-top));animation:slidein .2s ease}@keyframes slidein{0%{transform:translate(20px);opacity:.6}}.panel-head{display:flex;align-items:center;margin-bottom:18px}.panel-head h2{margin:0;font-size:18px}.panel-head .icon-btn{margin-left:auto}.section{margin-bottom:22px}.section h3{font-size:12px;text-transform:uppercase;letter-spacing:.6px;color:var(--text-faint);margin:0 0 10px}.kv{display:flex;justify-content:space-between;font-size:13px;padding:7px 0;border-bottom:1px solid var(--border-soft);color:var(--text-dim)}.kv span:last-child{color:var(--text);font-family:var(--mono);font-size:12.5px}.toast{position:fixed;left:50%;bottom:calc(24px + env(safe-area-inset-bottom));transform:translate(-50%);background:var(--bg-elev2);border:1px solid var(--border);color:var(--text);padding:11px 16px;border-radius:11px;font-size:13.5px;z-index:80;max-width:min(90vw,460px);box-shadow:0 12px 30px #00000080;animation:toastin .2s ease}@keyframes toastin{0%{transform:translate(-50%,10px);opacity:0}}.center-fill{flex:1;display:grid;place-items:center;color:var(--text-faint);font-size:14px;text-align:center;padding:40px;line-height:1.7}.spinner{width:22px;height:22px;border:2.5px solid var(--border);border-top-color:var(--accent);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}} +:root{--bg: #000810;--bg-elev: #010f20;--bg-elev2: #001a30;--bg-hover: #001a30;--border: #0a3060;--border-soft: #072348;--text: #c8f0ff;--text-dim: #6aa8bf;--text-faint: #2e6a80;--accent: #00f5ff;--accent-soft: rgba(0, 245, 255, .12);--accent-strong: #00c8d4;--accent-contrast: #001018;--danger: #ff3b3b;--danger-soft: rgba(255, 59, 59, .14);--ok: #00ff88;--warn: #ffaa00;--radius: 10px;--radius-sm: 8px;--sidebar-w: 304px;--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji", sans-serif;--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;color-scheme:dark}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{font-family:var(--font);background:var(--bg);color:var(--text);-webkit-font-smoothing:antialiased;overscroll-behavior-y:none}button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}input,textarea,select{font-family:inherit;font-size:15px;color:var(--text);background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:10px 12px;outline:none;width:100%}input:focus,textarea:focus,select:focus{border-color:var(--accent)}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:#0a3060;border-radius:8px;border:2px solid transparent;background-clip:padding-box}::-webkit-scrollbar-thumb:hover{background:#0f4a6e;background-clip:padding-box}.app{display:flex;height:100dvh;overflow:hidden}.sidebar{width:var(--sidebar-w);flex-shrink:0;background:var(--bg-elev);border-right:1px solid var(--border);display:flex;flex-direction:column;min-height:0}.main{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--bg)}.scrim{display:none}@media (max-width: 820px){.sidebar{position:fixed;inset:0 auto 0 0;z-index:40;transform:translate(-100%);transition:transform .22s ease;box-shadow:0 0 40px #00000080;padding-top:env(safe-area-inset-top)}.sidebar.open{transform:translate(0)}.scrim.show{display:block;position:fixed;top:0;right:0;bottom:0;left:0;background:#00000080;z-index:30}}.sidebar-head{padding:14px 14px 10px;display:flex;flex-direction:column;gap:10px;border-bottom:1px solid var(--border-soft)}.brand{display:flex;align-items:center;gap:9px;font-weight:650;letter-spacing:.2px}.brand-mark{width:26px;height:26px;border-radius:7px;background:linear-gradient(180deg,#003545,#00202e);border:1px solid #005570;display:grid;place-items:center;color:var(--accent);font-weight:800;font-size:14px}.brand-link{display:inline-flex;align-items:center;text-decoration:none;border-radius:8px;padding:2px 4px;margin-left:-4px}.brand-link:hover{background:var(--bg-hover)}.brand-actions{margin-left:auto;display:flex;gap:4px}.icon-btn{width:34px;height:34px;border-radius:9px;display:grid;place-items:center;color:var(--text-dim);transition:background .15s,color .15s}.icon-btn:hover{background:var(--bg-hover);color:var(--text)}.icon-btn.active{color:var(--accent);background:var(--accent-soft)}.profile-switch{position:relative}.profile-btn{width:100%;display:flex;align-items:center;gap:9px;padding:9px 11px;border-radius:var(--radius-sm);background:var(--bg-elev2);border:1px solid var(--border);text-align:left}.profile-btn:hover{border-color:#2f3b4d}.profile-btn .dot{width:8px;height:8px;border-radius:50%;background:var(--ok);flex-shrink:0}.profile-btn .name{font-weight:600;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.profile-btn .sub{font-size:11px;color:var(--text-faint);margin-left:auto;flex-shrink:0}.menu{position:absolute;top:calc(100% + 6px);left:0;right:0;background:var(--bg-elev2);border:1px solid var(--border);border-radius:var(--radius-sm);padding:5px;z-index:20;box-shadow:0 12px 30px #00000073;max-height:320px;overflow:auto}.menu-item{width:100%;display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:7px;font-size:14px;text-align:left}.menu-item:hover{background:var(--bg-hover)}.menu-item .check{margin-left:auto;color:var(--accent)}.new-chat{display:flex;align-items:center;justify-content:center;gap:8px;padding:10px;border-radius:var(--radius-sm);background:var(--accent);color:var(--accent-contrast);font-weight:700;font-size:14px}.new-chat:hover{background:var(--accent-strong)}.search-wrap{position:relative}.search-wrap svg{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:var(--text-faint);pointer-events:none}.search-wrap input{padding-left:34px;background:var(--bg)}.sidebar-tools{display:flex;align-items:center;gap:8px;padding:8px 14px;font-size:12px;color:var(--text-dim);border-bottom:1px solid var(--border-soft)}.toggle{display:inline-flex;align-items:center;gap:6px;cursor:pointer;-webkit-user-select:none;user-select:none}.toggle input{width:auto;accent-color:var(--accent)}.session-list{flex:1;overflow-y:auto;padding:8px;min-height:0}.group-label{font-size:11px;text-transform:uppercase;letter-spacing:.6px;color:var(--text-faint);padding:12px 8px 6px;font-weight:600}.session-item{display:flex;align-items:center;gap:10px;padding:9px 10px;border-radius:var(--radius-sm);cursor:pointer;position:relative}.session-item:hover{background:var(--bg-hover)}.session-item.active{background:var(--accent-soft)}.session-item .body{min-width:0;flex:1}.session-item .title{font-size:14px;font-weight:550;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-item .meta{font-size:11.5px;color:var(--text-faint);display:flex;gap:8px;margin-top:2px;overflow:hidden;white-space:nowrap}.session-item .meta .badge{color:var(--accent)}.session-item .actions{display:none;gap:2px}.session-item:hover .actions{display:flex}.session-item .actions .icon-btn{width:28px;height:28px}.pin-dot{color:var(--warn);flex-shrink:0}.empty{padding:30px 16px;text-align:center;color:var(--text-faint);font-size:13.5px;line-height:1.6}.chat-head{display:flex;align-items:center;gap:10px;padding:10px 14px;padding-top:calc(10px + env(safe-area-inset-top));border-bottom:1px solid var(--border);background:var(--bg-elev);min-height:56px}.chat-head .titles{min-width:0;flex:1}.chat-head .t{font-weight:600;font-size:15px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chat-head .s{font-size:11.5px;color:var(--text-faint);display:flex;gap:8px;margin-top:1px}.chat-head .s .pill{background:var(--bg-elev2);border:1px solid var(--border);border-radius:20px;padding:1px 8px}.menu-btn{display:none}@media (max-width: 820px){.menu-btn{display:grid}}.messages{flex:1;overflow-y:auto;padding:20px 16px 8px;display:flex;flex-direction:column;gap:18px;min-height:0}.messages-inner{width:100%;max-width:820px;margin:0 auto;display:flex;flex-direction:column;gap:18px}.msg{display:flex;gap:11px;align-items:flex-start}.msg .avatar{width:30px;height:30px;border-radius:8px;flex-shrink:0;display:grid;place-items:center;background:var(--bg-elev2);border:1px solid var(--border);color:var(--text-dim)}.msg.user .avatar{background:var(--accent-soft);color:var(--accent);border-color:transparent}.msg .avatar.brand{background:none;border:none;padding:0;border-radius:9px}.msg .content{min-width:0;flex:1;padding-top:3px}.msg .who{font-size:12px;color:var(--text-faint);margin-bottom:5px;display:flex;align-items:center;gap:8px}.msg .bubble{font-size:15px;line-height:1.62;white-space:pre-wrap;word-wrap:break-word;overflow-wrap:anywhere}.msg.user .bubble{background:var(--bg-elev2);border:1px solid var(--border);border-radius:12px;padding:10px 13px}.msg .bubble code{font-family:var(--mono);font-size:13px;background:var(--bg-elev2);padding:1px 5px;border-radius:5px}.msg .bubble pre{background:var(--bg-elev2);border:1px solid var(--border);border-radius:10px;padding:12px;overflow-x:auto;font-family:var(--mono);font-size:13px}.msg .bubble pre code{background:none;padding:0}.msg .bubble a{color:var(--accent)}.msg .bubble img{max-width:100%;border-radius:10px;margin-top:6px}.md-figure{display:block;margin-top:8px}.md-figure img{display:block;max-width:100%;border-radius:10px;margin-top:0}.md-download{display:inline-flex;align-items:center;gap:6px;margin-top:8px;padding:6px 12px;border-radius:8px;border:1px solid var(--border);background:var(--bg-elev2);color:var(--text-dim);font-size:12.5px;font-weight:600}.md-download:hover{background:var(--bg-hover);color:var(--text);border-color:var(--accent)}.media-ref{display:inline-flex;align-items:center;gap:8px;max-width:100%;margin-top:6px;padding:7px 11px;border:1px solid var(--border);border-radius:9px;background:var(--bg-elev);color:var(--text-dim);font-size:12.5px}.media-ref .nm{color:var(--text);font-weight:600}.media-ref .path{font-family:var(--mono);font-size:11.5px;color:var(--text-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:320px}.msg-actions{display:flex;gap:4px;margin-top:6px;opacity:0;transition:opacity .15s}.msg:hover .msg-actions{opacity:1}.msg-actions .icon-btn{width:28px;height:28px}.typing{display:inline-flex;gap:4px;padding:4px 0}.typing span{width:6px;height:6px;border-radius:50%;background:var(--text-faint);animation:blink 1.3s infinite both}.typing span:nth-child(2){animation-delay:.2s}.typing span:nth-child(3){animation-delay:.4s}@keyframes blink{0%,80%,to{opacity:.25}40%{opacity:1}}.reasoning{border:1px solid var(--border);border-radius:10px;background:var(--bg-elev);margin-bottom:8px;overflow:hidden}.reasoning summary{cursor:pointer;padding:8px 12px;font-size:12.5px;color:var(--text-dim);display:flex;align-items:center;gap:7px;list-style:none}.reasoning summary::-webkit-details-marker{display:none}.reasoning .body{padding:0 12px 12px;font-size:13.5px;color:var(--text-dim);white-space:pre-wrap;line-height:1.55}.tool-card{border:1px solid var(--border);border-radius:10px;background:var(--bg-elev);margin:6px 0;overflow:hidden}.tool-card .head{display:flex;align-items:center;gap:8px;padding:8px 12px;font-size:13px}.tool-card .head .name{font-weight:600;font-family:var(--mono);font-size:12.5px}.tool-card .head .status{margin-left:auto;font-size:11px;color:var(--text-faint)}.tool-card .head .status.err{color:var(--danger)}.tool-card .head .status.ok{color:var(--ok)}.tool-card .preview{padding:0 12px 10px;font-family:var(--mono);font-size:12px;color:var(--text-dim);white-space:pre-wrap;word-break:break-word;max-height:220px;overflow:auto}.attachments{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}.attachment{display:flex;align-items:center;gap:8px;border:1px solid var(--border);border-radius:9px;padding:6px 9px;font-size:12.5px;background:var(--bg-elev);max-width:240px}.attachment img{width:34px;height:34px;object-fit:cover;border-radius:6px}.attachment .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.composer-wrap{padding:10px 16px calc(12px + env(safe-area-inset-bottom));border-top:1px solid var(--border);background:var(--bg-elev)}.composer{max-width:820px;margin:0 auto;border:1px solid var(--border);border-radius:16px;background:var(--bg);padding:8px 8px 8px 12px;display:flex;flex-direction:column;gap:6px;transition:border-color .15s}.composer:focus-within{border-color:#33415a}.composer textarea{border:none;background:none;padding:6px 0;resize:none;max-height:200px;line-height:1.5}.composer textarea:focus{border:none}.composer-row{display:flex;align-items:center;gap:6px}.composer-row .spacer{flex:1}.send-btn{width:38px;height:38px;border-radius:11px;background:var(--accent);color:var(--accent-contrast);display:grid;place-items:center}.send-btn:disabled{background:var(--bg-elev2);color:var(--text-faint);cursor:default}.send-btn.stop{background:var(--danger)}.recording-pill{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--danger);padding:0 6px}.recording-pill .pulse{width:9px;height:9px;border-radius:50%;background:var(--danger);animation:pulse 1s infinite}@keyframes pulse{0%,to{opacity:1}50%{opacity:.3}}.attach-chips{display:flex;flex-wrap:wrap;gap:6px;padding:2px 0}.chip{display:flex;align-items:center;gap:6px;background:var(--bg-elev2);border:1px solid var(--border);border-radius:8px;padding:4px 6px 4px 8px;font-size:12px;max-width:220px}.chip img{width:26px;height:26px;object-fit:cover;border-radius:5px}.chip .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chip button{color:var(--text-faint);display:grid;place-items:center}.chip button:hover{color:var(--danger)}.prompt{max-width:820px;margin:0 auto 10px;border:1px solid var(--warn);background:#fbbf2414;border-radius:12px;padding:12px 14px}.prompt.clarify{border-color:var(--accent);background:var(--accent-soft)}.prompt .pt{font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--warn);font-weight:700;margin-bottom:6px}.prompt.clarify .pt{color:var(--accent)}.prompt .q{font-size:14.5px;line-height:1.5;margin-bottom:10px}.prompt .cmd{font-family:var(--mono);font-size:12.5px;background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:8px 10px;margin-bottom:10px;white-space:pre-wrap;word-break:break-word}.prompt .btns{display:flex;flex-wrap:wrap;gap:8px}.btn{padding:8px 14px;border-radius:9px;font-size:13.5px;font-weight:600;border:1px solid var(--border);background:var(--bg-elev2)}.btn:hover{background:var(--bg-hover)}.btn.primary{background:var(--accent);border-color:transparent;color:var(--accent-contrast);font-weight:700}.btn.primary:hover{background:var(--accent-strong)}.btn.danger{color:var(--danger);border-color:#f8717166}.btn.danger:hover{background:var(--danger-soft)}.btn:disabled{opacity:.5;cursor:default}.screen{min-height:100dvh;display:flex;align-items:center;justify-content:center;padding:24px;padding-top:calc(24px + env(safe-area-inset-top));background:radial-gradient(1200px 600px at 50% -10%,#00202e 0%,var(--bg) 55%)}.card{width:100%;max-width:460px;background:var(--bg-elev);border:1px solid var(--border);border-radius:18px;padding:26px;box-shadow:0 24px 60px #00000073}.card h1{margin:0 0 4px;font-size:22px}.card .lead{color:var(--text-dim);font-size:13.5px;line-height:1.6;margin:0 0 20px}.field{margin-bottom:14px}.field label{display:block;font-size:12.5px;font-weight:600;color:var(--text-dim);margin-bottom:6px}.field .hint{font-size:11.5px;color:var(--text-faint);margin-top:5px;line-height:1.5}.row{display:flex;gap:8px;align-items:center}.header-row{display:flex;align-items:center;gap:8px;margin-bottom:6px}.header-row input{flex:1}.alert{border-radius:10px;padding:10px 12px;font-size:13px;margin-bottom:14px;line-height:1.5}.alert.error{background:var(--danger-soft);color:#fca5a5;border:1px solid rgba(248,113,113,.35)}.alert.ok{background:#34d3991f;color:#6ee7b7;border:1px solid rgba(52,211,153,.3)}.alert.info{background:var(--accent-soft);color:#9dc4fb;border:1px solid rgba(79,156,249,.3)}.card .actions{display:flex;gap:10px;margin-top:20px}.card .actions .btn{flex:1;text-align:center;padding:11px}.link-btn{color:var(--accent);font-size:13px;text-decoration:none}.link-btn:hover{text-decoration:underline}.panel{position:fixed;top:0;right:0;bottom:0;left:0;z-index:60;background:#0000008c;display:flex;justify-content:flex-end}.panel-inner{width:100%;max-width:440px;background:var(--bg-elev);border-left:1px solid var(--border);height:100%;overflow-y:auto;padding:20px;padding-top:calc(20px + env(safe-area-inset-top));animation:slidein .2s ease}@keyframes slidein{0%{transform:translate(20px);opacity:.6}}.panel-head{display:flex;align-items:center;margin-bottom:18px}.panel-head h2{margin:0;font-size:18px}.panel-head .build-date{font-size:11.5px;font-weight:400;color:var(--text-faint);margin-left:6px}.panel-head .icon-btn{margin-left:auto}.section{margin-bottom:22px}.section h3{font-size:12px;text-transform:uppercase;letter-spacing:.6px;color:var(--text-faint);margin:0 0 10px}.kv{display:flex;justify-content:space-between;font-size:13px;padding:7px 0;border-bottom:1px solid var(--border-soft);color:var(--text-dim)}.kv span:last-child{color:var(--text);font-family:var(--mono);font-size:12.5px}.toast{position:fixed;left:50%;bottom:calc(24px + env(safe-area-inset-bottom));transform:translate(-50%);background:var(--bg-elev2);border:1px solid var(--border);color:var(--text);padding:11px 16px;border-radius:11px;font-size:13.5px;z-index:80;max-width:min(90vw,460px);box-shadow:0 12px 30px #00000080;animation:toastin .2s ease}@keyframes toastin{0%{transform:translate(-50%,10px);opacity:0}}.center-fill{flex:1;display:grid;place-items:center;color:var(--text-faint);font-size:14px;text-align:center;padding:40px;line-height:1.7}.spinner{width:22px;height:22px;border:2.5px solid var(--border);border-top-color:var(--accent);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}} diff --git a/index.html b/index.html index 7f49efd..64d586f 100644 --- a/index.html +++ b/index.html @@ -13,8 +13,8 @@ Hermes - - + +
diff --git a/sw.js b/sw.js index 9b17d07..211e278 100644 --- a/sw.js +++ b/sw.js @@ -1 +1 @@ -if(!self.define){let e,i={};const n=(n,s)=>(n=new URL(n+".js",s).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(s,o)=>{const r=e||("document"in self?document.currentScript.src:"")||location.href;if(i[r])return;let c={};const l=e=>n(e,r),t={module:{uri:r},exports:c,require:l};i[r]=Promise.all(s.map(e=>t[e]||l(e))).then(e=>(o(...e),c))}}define(["./workbox-abeb32eb"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"index.html",revision:"84ac5ebbe2382c8ec70814e7f406d21e"},{url:"assets/workbox-window.prod.es5-BqEJf4Xk.js",revision:null},{url:"assets/index-SBr79e_P.js",revision:null},{url:"assets/index-CWSassUi.css",revision:null},{url:"favicon.svg",revision:"a3baf2b041a9ed1fcc08d8a3634b535b"},{url:"icons/apple-touch-icon.png",revision:"ed81749f391ac07000b948263124e943"},{url:"icons/icon-192.png",revision:"8b2374bbaec1e3d1db8a07af64a6ef77"},{url:"icons/icon-512.png",revision:"c44a8f2da9095157b9b9aff7ec8e1aeb"},{url:"icons/maskable-512.png",revision:"beb4196443dc6daafcaab4497038613d"},{url:"manifest.webmanifest",revision:"d1afe01b7c52b0c511fd7e5f11079c23"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html"),{denylist:[/^\/api\//]})),e.registerRoute(({url:e})=>e.pathname.startsWith("/api/"),new e.NetworkOnly,"GET")}); +if(!self.define){let e,i={};const n=(n,s)=>(n=new URL(n+".js",s).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(s,o)=>{const r=e||("document"in self?document.currentScript.src:"")||location.href;if(i[r])return;let c={};const l=e=>n(e,r),t={module:{uri:r},exports:c,require:l};i[r]=Promise.all(s.map(e=>t[e]||l(e))).then(e=>(o(...e),c))}}define(["./workbox-abeb32eb"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"index.html",revision:"8e29677639fefa5c95cb54316bb425d0"},{url:"assets/workbox-window.prod.es5-BqEJf4Xk.js",revision:null},{url:"assets/index-BQJys9C3.css",revision:null},{url:"assets/index-BFnujVjw.js",revision:null},{url:"favicon.svg",revision:"a3baf2b041a9ed1fcc08d8a3634b535b"},{url:"icons/apple-touch-icon.png",revision:"ed81749f391ac07000b948263124e943"},{url:"icons/icon-192.png",revision:"8b2374bbaec1e3d1db8a07af64a6ef77"},{url:"icons/icon-512.png",revision:"c44a8f2da9095157b9b9aff7ec8e1aeb"},{url:"icons/maskable-512.png",revision:"beb4196443dc6daafcaab4497038613d"},{url:"manifest.webmanifest",revision:"d1afe01b7c52b0c511fd7e5f11079c23"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html"),{denylist:[/^\/api\//]})),e.registerRoute(({url:e})=>e.pathname.startsWith("/api/"),new e.NetworkOnly,"GET")});