UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

160 lines • 20.2 kB
import{n as e}from"./rolldown-runtime-8BhlS34s.js";import{Cu as t,Eu as n,Is as r,Ji as i,Ls as a,Tu as o,Xi as s,ju as c,nl as l,tl as u}from"./control-ui-core-BncvAZjR.js";import{La as d,Ra as f,Ti as p,gn as m,ir as ee,mn as h,rr as g,wa as _,wi as te,wn as ne}from"./control-ui-core-9qYjK5B2.js";import{$ as v,X as y,Y as b,ct as x,nt as S}from"./lit-runtime-B8uOr6OX.js";import{Sn as re,wn as ie}from"./control-ui-boot-shared-DJkUdZmL.js";import{Xr as ae,Zr as oe,ii as C,sn as w}from"./ui-DuRgK6kL.js";import{Bi as se,G as ce,I as T,J as le,R as ue,Y as E,Z as D,l as O,q as k,u as A,zi as j}from"./control-ui-boot-shared-xfDhIVun.js";import{Cc as M,Gi as N,Hc as P,Hi as F,Uc as I,Ui as L,Wi as R,wc as z}from"./control-ui-boot-shared-D3oo_6Fq.js";import{n as B,t as V}from"./en-settings-KEcvGj5Z.js";import{n as H,o as U}from"./settings-targets-B_ZHOn2L.js";import{r as de}from"./login-runtime-ULR4eeNT.js";import{n as fe,t as pe}from"./system-info-C3-P4Ofh.js";import{a as me,n as he}from"./gateway-vitals-DuGt95EC.js";function ge(e){if(e.length===0)return null;let t=e.toSorted((e,t)=>e-t),n=e=>t[Math.ceil(t.length*e)-1];return{count:e.length,averageMs:e.reduce((e,t)=>e+t,0)/e.length,p50Ms:n(.5),p95Ms:n(.95),p99Ms:n(.99)}}function W(){return(W=e((()=>{})))()}function _e(e,t){let n=Math.min(Math.max(t,0),1),r=Math.round(n*100),i=n>=.92?`critical`:n>=.75?`warn`:`ok`;return v` <div class="config-host__meter" role="meter" aria-label=${c(`quickSettings.system.usage`,{label:e})} aria-valuemin="0" aria-valuemax="100" aria-valuenow=${r} > <div class="config-host__meter-fill config-host__meter-fill--${i}" style="--config-host-meter-fill: ${r}%" ></div> </div> `}function ve(e){let t=e.path?`${e.label} ${e.path}`:e.label;return v` <div class="config-host__stat" title=${e.title??y}> <div class="config-host__stat-label"> ${e.label}${e.path?v` <span class="config-host__stat-path">${e.path}</span>`:y} </div> <div class="config-host__stat-value"> ${e.value}${e.unit?v` <span class="config-host__stat-unit">${e.unit}</span>`:y} </div> ${e.usedFraction==null?y:_e(t,e.usedFraction)} ${e.detail?v`<div class="config-host__stat-detail">${e.detail}</div>`:y} </div> `}function G(e,t){if(!(e==null||t==null||e<=0))return(e-t)/e}function K(e){return`${Math.round(Math.min(Math.max(e,0),1)*100)}%`}function ye(e){let t=e.loadAverage?.[0],n=e.loadAverage?c(`quickSettings.system.loadAverage`,{values:e.loadAverage.map(e=>e.toFixed(1)).join(` · `)}):void 0,r=[e.cpuModel,n].filter(Boolean).join(` · `)||void 0,i=c(e.cpuCount===1?`quickSettings.system.core`:`quickSettings.system.cores`,{count:String(e.cpuCount)}),a=t==null?{label:c(`quickSettings.system.cpu`),value:i,detail:e.cpuModel}:{label:c(`quickSettings.system.cpu`),value:t.toFixed(1),unit:c(`quickSettings.system.load`),detail:i,usedFraction:e.cpuCount>0?t/e.cpuCount:void 0,title:r},o=G(e.memoryTotalBytes,e.memoryFreeBytes),s=[a,{label:c(`quickSettings.system.memory`),value:o==null?`—`:K(o),unit:o==null?void 0:c(`quickSettings.system.used`),detail:c(`quickSettings.system.freeOf`,{free:u(e.memoryFreeBytes),total:u(e.memoryTotalBytes)}),usedFraction:o}];for(let t of e.disks??[]){let e=G(t.totalBytes,t.availableBytes);e!=null&&s.push({label:c(`quickSettings.system.disk`),value:K(e),unit:c(`quickSettings.system.used`),detail:c(`quickSettings.system.freeOf`,{free:u(t.availableBytes),total:u(t.totalBytes)}),usedFraction:e,path:t.path})}return s}function be(e){return[{label:c(`quickSettings.system.cpu`),value:e},{label:c(`quickSettings.system.memory`),value:e},{label:c(`quickSettings.system.disk`),value:e}]}function xe(e){if(e.systemInfoUnavailable)return y;let t=e.systemInfo,n=e.systemInfoLoading?v`<span class="skeleton config-host__placeholder" aria-hidden="true"></span>`:`—`,r=t&&t.hostname!==t.machineName?t.hostname:void 0,i=t?.lanAddress?`${t.lanAddress}${t.port==null?``:`:${t.port}`}`:void 0,a=t?ye(t):be(n),o={title:c(`quickSettings.system.gatewayHost`),actions:t?D({kind:`ok`,label:c(`quickSettings.system.up`,{duration:re(t.uptimeMs)})}):void 0};return v` <div id=${H.host} aria-busy=${!!e.systemInfoLoading}> ${E(o,v` <div class="config-host"> <div class="config-host__identity"> <div class="config-host__name" title=${r??``}> ${t?.machineName??n} </div> <div class="config-host__meta"> ${t?`${t.osLabel} · ${t.arch}`:n} </div> <div class="config-host__meta"> ${t?c(`quickSettings.system.runtime`,{version:t.nodeVersion,pid:String(t.pid)}):n} </div> ${i?v`<code class="config-host__address">${i}</code>`:y} </div> <div class="config-host__stats">${a.map(ve)}</div> </div> `)} </div> `}function q(){return(q=e((()=>{b(),T(),n(),l(),ie(),U()})))()}function Se(e){return e?`${(e/1e3).toFixed(e%1e3==0?0:1)}s`:null}function Ce(e,t){let n=t===`password`?`connection.access.passwordHint`:t===`token`?`connection.access.tokenHint`:`connection.access.secretHint`;return k({title:c(`connection.access.secret`),description:c(n),control:v`<div class="settings-input-with-hint"> ${le({ariaLabel:c(`connection.access.secret`),value:e.secret,placeholder:c(`connection.access.secretPlaceholder`),visible:e.showGatewaySecret,showLabel:c(`connection.access.showSecret`),hideLabel:c(`connection.access.hideSecret`),toggleLabel:c(`connection.access.toggleSecretVisibility`),onInput:e.onSecretChange,onToggle:e.onToggleGatewaySecretVisibility})} ${de(e.secret)===`setup-code`?v`<p class="settings-row__desc" role="status"> ${c(`connection.access.setupCodeHint`)} </p>`:y} </div>`,stackedOnNarrow:!0})}function we(e){return`${e.toFixed(1)} ${c(`connection.ping.unit`)}`}function Te(e){let t=[{key:`average`,value:e.ping?.averageMs},{key:`p50`,value:e.ping?.p50Ms},{key:`p95`,value:e.ping?.p95Ms},{key:`p99`,value:e.ping?.p99Ms}];return v`<div class="settings-row connection-ping"> <dl class="connection-ping__stats" aria-label=${c(`connection.ping.title`)}> ${t.map(({key:e,value:t})=>v`<div title=${c(`connection.ping.${e}Hint`)}> <dt>${c(`connection.ping.${e}`)}</dt> <dd> ${t===void 0?`—`:v`${t.toFixed(1)} <span>${c(`connection.ping.unit`)}</span>`} </dd> </div>`)} </dl> <openclaw-sparkline class="gateway-vital connection-ping__trend" .label=${c(`connection.ping.latest`)} .samples=${e.pingSamples} .format=${we} .floorMax=${100} ></openclaw-sparkline> <p class="settings-row__desc"> ${e.ping?c(`connection.ping.samples`,{count:String(e.ping.count)}):e.pingFailed?y:c(`connection.ping.measuring`)} ${e.pingFailed?v`<span class="connection-ping__error" role="status"> ${c(`connection.ping.failed`)} </span>`:y} </p> </div>`}function J(e){let t=e.hello?.snapshot,n=e.phase===`connected`,i=[`connecting`,`starting`,`reconnecting`].includes(e.phase),a=i&&!e.dirty,o=e.phase===`reload-required`,s=t?.authMode,l=w(e.settings.gatewayUrl)===w(e.liveGatewayUrl)?s:void 0,u=l===`trusted-proxy`,d=n?`connected`:e.phase===`stopped`?`offline`:e.phase,f=c(a?e.phase===`reconnecting`?`connection.access.status.reconnecting`:`connection.access.status.connecting`:n||i?`connection.access.applyReconnect`:e.lastError?`connection.access.retry`:`common.connect`),p=Se(e.hello?.policy?.tickIntervalMs),m=v` ${n?Te(e):y} ${k({title:c(`connection.access.gatewayUrl`),description:c(`connection.access.gatewayUrlHint`),control:v` <input class="settings-input" aria-label=${c(`connection.access.gatewayUrl`)} inputmode="url" autocapitalize="none" autocorrect="off" autocomplete="off" spellcheck="false" .value=${e.settings.gatewayUrl} @input=${t=>{e.onConnectionChange({gatewayUrl:t.target.value})}} placeholder="wss://gateway.example:443" /> `})} ${u?k({title:c(`connection.access.secret`),description:c(`connection.access.trustedProxy`),control:D({kind:`ok`,label:c(`connection.access.trustedProxyStatus`)})}):Ce(e,l)} ${!n&&e.lastError?k({title:D({kind:`danger`,label:c(`connection.access.lastError`)}),description:e.lastError}):y} ${(!n||e.dirty)&&!o?v`<div class="settings-row connection-actions"> <div class="settings-row__text"> <span class="settings-row__desc" role="status"> ${e.dirty?c(`connection.access.unsavedHint`):y} </span> </div> <div class="settings-row__control connection-actions__buttons"> ${e.dirty?v`<button class="btn" @click=${e.onDiscardConnection}> ${c(`connection.access.discard`)} </button>`:y} <button class="btn primary" ?disabled=${a} @click=${e.onConnect}> ${a?v`<span class="btn__spinner" aria-hidden="true"></span>`:y} ${f} </button> </div> </div>`:y} <details class="connection-details"> <summary>${c(`connection.access.details`)}</summary> <div class="connection-details__body"> ${n&&(s||p)?v`<p class="settings-row__desc"> ${[s?c(Y[s]):null,p?c(`connection.access.tick`,{tick:p}):null].filter(Boolean).join(` · `)} </p>`:y} <p class="settings-row__desc">${c(`connection.access.reconnectHint`)}</p> <button class="btn" ?disabled=${!n||e.dirty} @click=${e.onReconnect}> ${c(`connection.access.reconnect`)} </button> </div> </details> `;return ce([E({title:c(`connection.access.title`),description:n?c(`connection.access.connectedTo`,{host:r(e.liveGatewayUrl)}):c(i||o?`connection.access.status.${d}`:`connection.access.descriptionOffline`),actions:D({kind:n?`ok`:`warn`,label:c(`connection.access.status.${d}`)})},m),E({title:c(`connection.activity.title`),description:c(`connection.activity.description`)},v`<div class="settings-row connection-activity"> ${me(e.statusHistory.at(-1)?.status??{},e.statusHistory)} ${e.statusFailed?v`<p class="settings-row__desc" role="status"> ${c(`connection.activity.failed`)} </p>`:n?e.statusHistory.length===0?v`<p class="settings-row__desc" role="status">${c(`common.loading`)}</p>`:y:v`<p class="settings-row__desc">${c(`connection.activity.offline`)}</p>`} </div>`),E({title:c(`connection.access.sessionTitle`),description:c(`connection.access.sessionDescription`,{host:r(e.liveGatewayUrl)})},v` ${k({title:c(`connection.access.sessionKey`),description:c(`connection.access.sessionKeyHint`),control:v` <input class="settings-input" aria-label=${c(`connection.access.sessionKey`)} .value=${e.settings.sessionKey} @input=${t=>e.onSessionKeyChange(t.target.value)} /> `})} ${e.sessionDirty?v`<div class="settings-row"> <div class="settings-row__text"></div> <div class="settings-row__control connection-actions__buttons"> <button class="btn" @click=${e.onDiscardSession}> ${c(`connection.access.discard`)} </button> <button class="btn primary" ?disabled=${!e.settings.sessionKey.trim()} @click=${e.onSaveSession} > ${c(`common.save`)} </button> </div> </div>`:e.sessionSaved?v`<div class="settings-row" role="status">${c(`connection.access.saved`)}</div>`:y} `),xe(e),e.canForgetDevice?E({title:c(`connection.browser.title`)},k({title:c(`connection.browser.savedSignIn`),control:v`<button class="btn" @click=${e.onForgetDevice}> ${c(`connection.browser.forgetDevice`)} </button>`})):y])}var Y;function X(){return(X=e((()=>{b(),he(),T(),n(),V(),a(),q(),B(),Y={none:`connection.access.auth.none`,token:`connection.access.auth.token`,password:`connection.access.auth.password`,"trusted-proxy":`connection.access.auth.trustedProxy`}})))()}var Z,Q;function $(){return($=e((()=>{oe(),b(),S(),_(),p(),h(),g(),j(),T(),O(),n(),i(),a(),R(),I(),o(),z(),W(),pe(),X(),Z=`https://docs.openclaw.ai/gateway/remote`,Q=class extends t{constructor(...e){super(...e),this.settings=m(),this.password=``,this.gatewaySecretVisible=!1,this.systemInfo=null,this.systemInfoUnavailable=!1,this.systemInfoLoading=!1,this.ping=null,this.pingFailed=!1,this.pingSamples=[],this.pingRequest=null,this.statusHistory=[],this.statusFailed=!1,this.systemInfoRequest=null,this.sessionKeyBaseline=``,this.sessionGatewayUrl=``,this.sessionSaved=!1,this.diagnosticsPolling=new M(this,F,()=>this.refreshDiagnostics(),!1),this.gateway=new P(this,{getGateway:()=>this.context?.gateway,invalidateRequests:()=>this.resetDiagnostics(),onSnapshot:e=>this.handleGatewaySnapshot(e),onPageActivation:()=>this.syncDiagnosticsPolling()})}disconnectedCallback(){this.resetDiagnostics(),this.gatewaySecretVisible=!1,super.disconnectedCallback()}handleGatewaySnapshot({snapshot:e,initial:t,sourceChanged:n,clientChanged:r}){let i=this.systemInfoUnavailable;t||n||r?(this.resetDiagnostics(),this.resetConnectionDraft(),(t||n||this.sessionGatewayUrl!==this.context.gateway.connection.gatewayUrl)&&this.resetSessionDraft(),this.systemInfo=null,this.systemInfoUnavailable=!1):e.phase!==`connected`&&(this.gatewaySecretVisible=!1,this.systemInfo=null),e.phase===`connected`&&e.hello&&(this.systemInfoUnavailable=!L(e),this.systemInfoUnavailable&&(this.gateway.invalidate(),this.systemInfoRequest?.abort(),this.systemInfoRequest=null,this.systemInfoLoading=!1,this.systemInfo=null,this.statusFailed=!0)),this.settings.sessionKey===this.sessionKeyBaseline&&(this.settings={...this.settings,sessionKey:e.sessionKey}),this.sessionKeyBaseline=e.sessionKey,this.syncDiagnosticsPolling(),i&&!this.systemInfoUnavailable&&this.loadSystemInfo()}stopDiagnosticsPolling(){this.diagnosticsPolling.stop(),this.pingRequest?.abort(),this.pingRequest=null,this.systemInfoRequest?.abort(),this.systemInfoRequest=null,this.systemInfoLoading=!1}resetDiagnostics(){this.stopDiagnosticsPolling(),this.pingSamples=[],this.ping=null,this.pingFailed=!1,this.statusHistory=[],this.statusFailed=!1}syncDiagnosticsPolling(){let e=this.context.gateway.snapshot;if(!this.isConnected||document.visibilityState===`hidden`||e.phase!==`connected`||!e.client){this.stopDiagnosticsPolling();return}this.diagnosticsPolling.start()&&this.refreshDiagnostics()}refreshDiagnostics(){this.measurePing(),this.loadSystemInfo()}async measurePing(){let e=this.gateway.gateway,t=this.gateway.capture();if(!e||e!==this.context.gateway||!t||this.pingRequest||document.visibilityState===`hidden`)return;let n=new AbortController;this.pingRequest=n;let r=()=>this.pingRequest===n&&this.isConnected&&document.visibilityState!==`hidden`&&this.context.gateway===e&&this.gateway.isCurrent(t),i=performance.now();try{if(await t.client.request(`last-heartbeat`,{},{timeoutMs:F,signal:n.signal}),!r())return;this.pingSamples=[...this.pingSamples.slice(-99),{at:Date.now(),value:performance.now()-i}],this.ping=ge(this.pingSamples.map(e=>e.value)),this.pingFailed=!1}catch{r()&&(this.pingFailed=!0)}finally{this.pingRequest===n&&(this.pingRequest=null)}}async loadSystemInfo(){let e=this.gateway.gateway,t=this.gateway.capture();if(!e||e!==this.context.gateway||!t||this.systemInfoUnavailable||this.systemInfoRequest||document.visibilityState===`hidden`)return;let n=new AbortController;this.systemInfoRequest=n,this.systemInfoLoading=!0;let r=()=>this.systemInfoRequest===n&&this.isConnected&&document.visibilityState!==`hidden`&&this.context.gateway===e&&this.gateway.isCurrent(t);try{let t=await N(e,n.signal);if(!r())return;this.systemInfo=t.value,this.diagnosticsPolling.stop(),this.diagnosticsPolling.start(),this.statusHistory.at(-1)?.at!==t.at&&(this.statusHistory=[...this.statusHistory.slice(-99),{at:t.at,status:{eventLoop:t.value.eventLoop,processMemory:t.value.processMemory}}]),this.statusFailed=!1}catch(e){if(!r())return;this.statusFailed=!0,(s(e)||fe(e))&&(this.systemInfo=null,this.systemInfoUnavailable=!0)}finally{this.systemInfoRequest===n&&(this.systemInfoRequest=null,this.systemInfoLoading=!1)}}resetConnectionDraft(){let{gatewayUrl:e,token:t,password:n}=this.context.gateway.connection;this.settings={...this.settings,gatewayUrl:e,token:t},this.password=n,this.gatewaySecretVisible=!1}resetSessionDraft(){this.sessionGatewayUrl=this.context.gateway.connection.gatewayUrl,this.sessionKeyBaseline=this.context.gateway.snapshot.sessionKey,this.settings={...this.settings,sessionKey:this.sessionKeyBaseline},this.sessionSaved=!1}saveSession(){this.context.gateway.setSessionKey(this.settings.sessionKey),this.resetSessionDraft(),this.sessionSaved=!0}async forgetDevice(){let e=this.context.gateway,t=e.connection.gatewayUrl;await se({title:c(`connection.browser.confirmTitle`),message:c(`connection.browser.confirmMessage`,{gateway:r(t)}),confirmLabel:c(`connection.browser.confirmLabel`),danger:!0})&&this.isConnected&&this.context.gateway===e&&e.connection.gatewayUrl===t&&(e.forgetDeviceToken?.(),this.requestUpdate())}updateConnection(e){if(e.gatewayUrl!==void 0){let t=ne(this.settings.gatewayUrl,e.gatewayUrl,{token:this.settings.token,password:this.password});this.password=t.password,this.settings={...this.settings,...e,token:t.token};return}this.settings={...this.settings,...e}}render(){let e=this.context.gateway.snapshot,t=this.context.gateway.connection,n=this.settings.gatewayUrl!==t.gatewayUrl||this.settings.token!==t.token||this.password!==t.password,r=J({phase:e.phase,hello:e.hello,settings:this.settings,liveGatewayUrl:t.gatewayUrl,secret:this.settings.token||this.password,lastError:e.lastError,systemInfo:this.systemInfo,systemInfoLoading:this.systemInfoLoading,systemInfoUnavailable:this.systemInfoUnavailable,ping:this.ping,pingFailed:this.pingFailed,pingSamples:this.pingSamples,statusHistory:this.statusHistory,statusFailed:this.statusFailed,dirty:n,sessionDirty:this.settings.sessionKey.trim()!==e.sessionKey,sessionSaved:this.sessionSaved,showGatewaySecret:this.gatewaySecretVisible,canForgetDevice:this.context.gateway.hasStoredDeviceToken?.()??!1,onForgetDevice:()=>void this.forgetDevice(),onConnectionChange:e=>this.updateConnection(e),onSecretChange:e=>{this.password=``,this.updateConnection({token:e})},onSessionKeyChange:e=>{this.sessionSaved=!1,this.settings={...this.settings,sessionKey:e}},onToggleGatewaySecretVisibility:()=>{this.gatewaySecretVisible=!this.gatewaySecretVisible},onConnect:()=>this.context.gateway.connect({gatewayUrl:this.settings.gatewayUrl,token:this.settings.token,password:this.password}),onDiscardConnection:()=>this.resetConnectionDraft(),onReconnect:()=>this.context.gateway.connect(),onSaveSession:()=>this.saveSession(),onDiscardSession:()=>this.resetSessionDraft()});return v` <section class="content-header" ${ee({toolbarHeader:!0})}> <div> <h1 class="page-title">${f(`connection`)}</h1> <div class="page-subtitle"> ${d(`connection`)} ${ue(Z)} </div> </div> </section> ${A(r)} `}},C([ae({context:te,subscribe:!0})],Q.prototype,`context`,void 0),C([x()],Q.prototype,`settings`,void 0),C([x()],Q.prototype,`password`,void 0),C([x()],Q.prototype,`gatewaySecretVisible`,void 0),C([x()],Q.prototype,`systemInfo`,void 0),C([x()],Q.prototype,`systemInfoUnavailable`,void 0),C([x()],Q.prototype,`systemInfoLoading`,void 0),C([x()],Q.prototype,`ping`,void 0),C([x()],Q.prototype,`pingFailed`,void 0),C([x()],Q.prototype,`statusHistory`,void 0),C([x()],Q.prototype,`statusFailed`,void 0),C([x()],Q.prototype,`sessionSaved`,void 0),customElements.get(`openclaw-connection-page`)||customElements.define(`openclaw-connection-page`,Q)})))()}$();