@xopcai/xopcbot 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/service.js +121 -35
- package/dist/agent/service.js.map +1 -1
- package/dist/channels/telegram/command-handler.d.ts +3 -0
- package/dist/channels/telegram/command-handler.js +69 -0
- package/dist/channels/telegram/command-handler.js.map +1 -1
- package/dist/channels/telegram/plugin.js +26 -1
- package/dist/channels/telegram/plugin.js.map +1 -1
- package/dist/cli/commands/config.js +59 -0
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/gateway-daemon.d.ts +1 -0
- package/dist/cli/commands/gateway-daemon.js +141 -0
- package/dist/cli/commands/gateway-daemon.js.map +1 -0
- package/dist/cli/commands/gateway.js +387 -45
- package/dist/cli/commands/gateway.js.map +1 -1
- package/dist/cli/commands/onboard.js +198 -0
- package/dist/cli/commands/onboard.js.map +1 -1
- package/dist/cli/index.js +17 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/config/schema.d.ts +22 -0
- package/dist/config/schema.js +16 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/daemon/background-start.d.ts +33 -0
- package/dist/daemon/background-start.js +89 -0
- package/dist/daemon/background-start.js.map +1 -0
- package/dist/daemon/gateway-manager.d.ts +87 -0
- package/dist/daemon/gateway-manager.js +324 -0
- package/dist/daemon/gateway-manager.js.map +1 -0
- package/dist/daemon/index.d.ts +5 -0
- package/dist/daemon/index.js +6 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/gateway/__tests__/auth.test.d.ts +1 -0
- package/dist/gateway/__tests__/auth.test.js +128 -0
- package/dist/gateway/__tests__/auth.test.js.map +1 -0
- package/dist/gateway/__tests__/process-manager.test.d.ts +4 -0
- package/dist/gateway/__tests__/process-manager.test.js +140 -0
- package/dist/gateway/__tests__/process-manager.test.js.map +1 -0
- package/dist/gateway/auth.d.ts +33 -0
- package/dist/gateway/auth.js +94 -0
- package/dist/gateway/auth.js.map +1 -0
- package/dist/gateway/hono/app.js +54 -15
- package/dist/gateway/hono/app.js.map +1 -1
- package/dist/gateway/index.d.ts +3 -0
- package/dist/gateway/index.js +3 -0
- package/dist/gateway/index.js.map +1 -1
- package/dist/gateway/pid-file.d.ts +35 -0
- package/dist/gateway/pid-file.js +111 -0
- package/dist/gateway/pid-file.js.map +1 -0
- package/dist/gateway/port-checker.d.ts +24 -0
- package/dist/gateway/port-checker.js +132 -0
- package/dist/gateway/port-checker.js.map +1 -0
- package/dist/gateway/process-manager.d.ts +62 -0
- package/dist/gateway/process-manager.js +370 -0
- package/dist/gateway/process-manager.js.map +1 -0
- package/dist/gateway/process-manager.types.d.ts +64 -0
- package/dist/gateway/process-manager.types.js +5 -0
- package/dist/gateway/process-manager.types.js.map +1 -0
- package/dist/gateway/server.js +3 -1
- package/dist/gateway/server.js.map +1 -1
- package/dist/gateway/service.d.ts +20 -0
- package/dist/gateway/service.js +67 -0
- package/dist/gateway/service.js.map +1 -1
- package/dist/gateway/static/root/assets/{main-CfIxL-cL.js → main-DevbZW9K.js} +373 -251
- package/dist/gateway/static/root/assets/main-DevbZW9K.js.map +1 -0
- package/dist/gateway/static/root/assets/{main-DndcTCgX.css → main-DxZg1Nmz.css} +1 -1
- package/dist/gateway/static/root/index.html +2 -2
- package/dist/session/store.js +11 -2
- package/dist/session/store.js.map +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/main-CfIxL-cL.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))i(n);new MutationObserver(n=>{for(const
|
|
2
|
-
\f\r]`,
|
|
3
|
-
\f\r"'\`<>=]|("|')|))|$)`,"g"),Qe=/'/g,Xe=/"/g,rt=/^(?:script|style|textarea|title)$/i,Mt=e=>(t,...s)=>({_$litType$:e,strings:t,values:s}),o=Mt(1),G=Symbol.for("lit-noChange"),m=Symbol.for("lit-nothing"),Ze=new WeakMap,z=J.createTreeWalker(J,129);function at(e,t){if(!Be(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return Ge!==void 0?Ge.createHTML(t):t}const Tt=(e,t)=>{const s=e.length-1,i=[];let n,r=t===2?"<svg>":t===3?"<math>":"",l=re;for(let h=0;h<s;h++){const d=e[h];let g,S,f=-1,E=0;for(;E<d.length&&(l.lastIndex=E,S=l.exec(d),S!==null);)E=l.lastIndex,l===re?S[1]==="!--"?l=We:S[1]!==void 0?l=Ve:S[2]!==void 0?(rt.test(S[2])&&(n=RegExp("</"+S[2],"g")),l=N):S[3]!==void 0&&(l=N):l===N?S[0]===">"?(l=n??re,f=-1):S[1]===void 0?f=-2:(f=l.lastIndex-S[2].length,g=S[1],l=S[3]===void 0?N:S[3]==='"'?Xe:Qe):l===Xe||l===Qe?l=N:l===We||l===Ve?l=re:(l=N,n=void 0);const L=l===N&&e[h+1].startsWith("/>")?" ":"";r+=l===re?d+At:f>=0?(i.push(g),d.slice(0,f)+nt+d.slice(f)+B+L):d+B+(f===-2?h:L)}return[at(e,r+(e[s]||"<?>")+(t===2?"</svg>":t===3?"</math>":"")),i]};class ge{constructor({strings:t,_$litType$:s},i){let n;this.parts=[];let r=0,l=0;const h=t.length-1,d=this.parts,[g,S]=Tt(t,s);if(this.el=ge.createElement(g,i),z.currentNode=this.el.content,s===2||s===3){const f=this.el.content.firstChild;f.replaceWith(...f.childNodes)}for(;(n=z.nextNode())!==null&&d.length<h;){if(n.nodeType===1){if(n.hasAttributes())for(const f of n.getAttributeNames())if(f.endsWith(nt)){const E=S[l++],L=n.getAttribute(f).split(B),ve=/([.?@])?(.*)/.exec(E);d.push({type:1,index:r,name:ve[2],strings:L,ctor:ve[1]==="."?Pt:ve[1]==="?"?Ft:ve[1]==="@"?Lt:Ae}),n.removeAttribute(f)}else f.startsWith(B)&&(d.push({type:6,index:r}),n.removeAttribute(f));if(rt.test(n.tagName)){const f=n.textContent.split(B),E=f.length-1;if(E>0){n.textContent=be?be.emptyScript:"";for(let L=0;L<E;L++)n.append(f[L],pe()),z.nextNode(),d.push({type:2,index:++r});n.append(f[E],pe())}}}else if(n.nodeType===8)if(n.data===ot)d.push({type:2,index:r});else{let f=-1;for(;(f=n.data.indexOf(B,f+1))!==-1;)d.push({type:7,index:r}),f+=B.length-1}r++}}static createElement(t,s){const i=J.createElement("template");return i.innerHTML=t,i}}function se(e,t,s=e,i){if(t===G)return t;let n=i!==void 0?s._$Co?.[i]:s._$Cl;const r=ue(t)?void 0:t._$litDirective$;return n?.constructor!==r&&(n?._$AO?.(!1),r===void 0?n=void 0:(n=new r(e),n._$AT(e,s,i)),i!==void 0?(s._$Co??=[])[i]=n:s._$Cl=n),n!==void 0&&(t=se(e,n._$AS(e,t.values),n,i)),t}class Et{constructor(t,s){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=s}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:s},parts:i}=this._$AD,n=(t?.creationScope??J).importNode(s,!0);z.currentNode=n;let r=z.nextNode(),l=0,h=0,d=i[0];for(;d!==void 0;){if(l===d.index){let g;d.type===2?g=new _e(r,r.nextSibling,this,t):d.type===1?g=new d.ctor(r,d.name,d.strings,this,t):d.type===6&&(g=new It(r,this,t)),this._$AV.push(g),d=i[++h]}l!==d?.index&&(r=z.nextNode(),l++)}return z.currentNode=J,n}p(t){let s=0;for(const i of this._$AV)i!==void 0&&(i.strings!==void 0?(i._$AI(t,i,s),s+=i.strings.length-2):i._$AI(t[s])),s++}}class _e{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,s,i,n){this.type=2,this._$AH=m,this._$AN=void 0,this._$AA=t,this._$AB=s,this._$AM=i,this.options=n,this._$Cv=n?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode;const s=this._$AM;return s!==void 0&&t?.nodeType===11&&(t=s.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,s=this){t=se(this,t,s),ue(t)?t===m||t==null||t===""?(this._$AH!==m&&this._$AR(),this._$AH=m):t!==this._$AH&&t!==G&&this._(t):t._$litType$!==void 0?this.$(t):t.nodeType!==void 0?this.T(t):Ct(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==m&&ue(this._$AH)?this._$AA.nextSibling.data=t:this.T(J.createTextNode(t)),this._$AH=t}$(t){const{values:s,_$litType$:i}=t,n=typeof i=="number"?this._$AC(t):(i.el===void 0&&(i.el=ge.createElement(at(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===n)this._$AH.p(s);else{const r=new Et(n,this),l=r.u(this.options);r.p(s),this.T(l),this._$AH=r}}_$AC(t){let s=Ze.get(t.strings);return s===void 0&&Ze.set(t.strings,s=new ge(t)),s}k(t){Be(this._$AH)||(this._$AH=[],this._$AR());const s=this._$AH;let i,n=0;for(const r of t)n===s.length?s.push(i=new _e(this.O(pe()),this.O(pe()),this,this.options)):i=s[n],i._$AI(r),n++;n<s.length&&(this._$AR(i&&i._$AB.nextSibling,n),s.length=n)}_$AR(t=this._$AA.nextSibling,s){for(this._$AP?.(!1,!0,s);t!==this._$AB;){const i=Je(t).nextSibling;Je(t).remove(),t=i}}setConnected(t){this._$AM===void 0&&(this._$Cv=t,this._$AP?.(t))}}class Ae{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,s,i,n,r){this.type=1,this._$AH=m,this._$AN=void 0,this.element=t,this.name=s,this._$AM=n,this.options=r,i.length>2||i[0]!==""||i[1]!==""?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=m}_$AI(t,s=this,i,n){const r=this.strings;let l=!1;if(r===void 0)t=se(this,t,s,0),l=!ue(t)||t!==this._$AH&&t!==G,l&&(this._$AH=t);else{const h=t;let d,g;for(t=r[0],d=0;d<r.length-1;d++)g=se(this,h[i+d],s,d),g===G&&(g=this._$AH[d]),l||=!ue(g)||g!==this._$AH[d],g===m?t=m:t!==m&&(t+=(g??"")+r[d+1]),this._$AH[d]=g}l&&!n&&this.j(t)}j(t){t===m?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??"")}}class Pt extends Ae{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===m?void 0:t}}class Ft extends Ae{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==m)}}class Lt extends Ae{constructor(t,s,i,n,r){super(t,s,i,n,r),this.type=5}_$AI(t,s=this){if((t=se(this,t,s,0)??m)===G)return;const i=this._$AH,n=t===m&&i!==m||t.capture!==i.capture||t.once!==i.once||t.passive!==i.passive,r=t!==m&&(i===m||n);n&&this.element.removeEventListener(this.name,this,i),r&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}}class It{constructor(t,s,i){this.element=t,this.type=6,this._$AN=void 0,this._$AM=s,this.options=i}get _$AU(){return this._$AM._$AU}_$AI(t){se(this,t)}}const Dt=Re.litHtmlPolyfillSupport;Dt?.(ge,_e),(Re.litHtmlVersions??=[]).push("3.3.2");const Ot=(e,t,s)=>{const i=s?.renderBefore??t;let n=i._$litPart$;if(n===void 0){const r=s?.renderBefore??null;i._$litPart$=n=new _e(t.insertBefore(pe(),r),r,void 0,s??{})}return n._$AI(e),n};const Ke=globalThis;let y=class extends ee{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const s=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=Ot(s,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return G}};y._$litElement$=!0,y.finalized=!0,Ke.litElementHydrateSupport?.({LitElement:y});const Rt=Ke.litElementPolyfillSupport;Rt?.({LitElement:y});(Ke.litElementVersions??=[]).push("4.2.2");const k=e=>(t,s)=>{s!==void 0?s.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)};const Bt={attribute:!0,type:String,converter:we,reflect:!1,hasChanged:Oe},Kt=(e=Bt,t,s)=>{const{kind:i,metadata:n}=s;let r=globalThis.litPropertyMetadata.get(n);if(r===void 0&&globalThis.litPropertyMetadata.set(n,r=new Map),i==="setter"&&((e=Object.create(e)).wrapped=!0),r.set(s.name,e),i==="accessor"){const{name:l}=s;return{set(h){const d=t.get.call(this);t.set.call(this,h),this.requestUpdate(l,d,e,!0,h)},init(h){return h!==void 0&&this.C(l,void 0,e,h),h}}}if(i==="setter"){const{name:l}=s;return function(h){const d=this[l];t.call(this,h),this.requestUpdate(l,d,e,!0,h)}}throw Error("Unsupported decorator location: "+i)};function u(e){return(t,s)=>typeof s=="object"?Kt(e,t,s):((i,n,r)=>{const l=n.hasOwnProperty(r);return n.constructor.createProperty(r,i),l?Object.getOwnPropertyDescriptor(n,r):void 0})(e,t,s)}function c(e){return u({...e,state:!0,attribute:!1})}const jt=(e,t,s)=>(s.configurable=!0,s.enumerable=!0,Reflect.decorate&&typeof t!="object"&&Object.defineProperty(e,t,s),s);function ie(e,t){return(s,i,n)=>{const r=l=>l.renderRoot?.querySelector(e)??null;return jt(s,i,{get(){return r(this)}})}}const Ut=e=>e.strings===void 0;const lt={CHILD:2},ct=e=>(...t)=>({_$litDirective$:e,values:t});class ht{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,s,i){this._$Ct=t,this._$AM=s,this._$Ci=i}_$AS(t,s){return this.update(t,s)}update(t,s){return this.render(...s)}}const de=(e,t)=>{const s=e._$AN;if(s===void 0)return!1;for(const i of s)i._$AO?.(t,!1),de(i,t);return!0},$e=e=>{let t,s;do{if((t=e._$AM)===void 0)break;s=t._$AN,s.delete(e),e=t}while(s?.size===0)},dt=e=>{for(let t;t=e._$AM;e=t){let s=t._$AN;if(s===void 0)t._$AN=s=new Set;else if(s.has(e))break;s.add(e),zt(t)}};function Ht(e){this._$AN!==void 0?($e(this),this._$AM=e,dt(this)):this._$AM=e}function Nt(e,t=!1,s=0){const i=this._$AH,n=this._$AN;if(n!==void 0&&n.size!==0)if(t)if(Array.isArray(i))for(let r=s;r<i.length;r++)de(i[r],!1),$e(i[r]);else i!=null&&(de(i,!1),$e(i));else de(this,e)}const zt=e=>{e.type==lt.CHILD&&(e._$AP??=Nt,e._$AQ??=Ht)};class qt extends ht{constructor(){super(...arguments),this._$AN=void 0}_$AT(t,s,i){super._$AT(t,s,i),dt(this),this.isConnected=t._$AU}_$AO(t,s=!0){t!==this.isConnected&&(this.isConnected=t,t?this.reconnected?.():this.disconnected?.()),s&&(de(this,t),$e(this))}setValue(t){if(Ut(this._$Ct))this._$Ct._$AI(t,this);else{const s=[...this._$Ct._$AH];s[this._$Ci]=t,this._$Ct._$AI(s,this,0)}}disconnected(){}reconnected(){}}const Ye=()=>new Jt;class Jt{}const Ee=new WeakMap,et=ct(class extends qt{render(e){return m}update(e,[t]){const s=t!==this.G;return s&&this.G!==void 0&&this.rt(void 0),(s||this.lt!==this.ct)&&(this.G=t,this.ht=e.options?.host,this.rt(this.ct=e.element)),m}rt(e){if(this.isConnected||(e=void 0),typeof this.G=="function"){const t=this.ht??globalThis;let s=Ee.get(t);s===void 0&&(s=new WeakMap,Ee.set(t,s)),s.get(this.G)!==void 0&&this.G.call(this.ht,void 0),s.set(this.G,e),e!==void 0&&this.G.call(this.ht,e)}else this.G.value=e}get lt(){return typeof this.G=="function"?Ee.get(this.ht??globalThis)?.get(this.G):this.G?.value}disconnected(){this.lt===this.ct&&this.rt(void 0)}reconnected(){this.rt(this.ct)}});class Pe extends ht{constructor(t){if(super(t),this.it=m,t.type!==lt.CHILD)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(t){if(t===m||t==null)return this._t=void 0,this.it=t;if(t===G)return t;if(typeof t!="string")throw Error(this.constructor.directiveName+"() called with a non-string value");if(t===this.it)return this._t;this.it=t;const s=[t];return s.raw=s,this._t={_$litType$:this.constructor.resultType,strings:s,values:[]}}}Pe.directiveName="unsafeHTML",Pe.resultType=1;const ae=ct(Pe);const Ce={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"};const Gt=["svg",Ce,[["path",{d:"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48"}]]];const Wt=["svg",Ce,[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z"}],["path",{d:"m21.854 2.147-10.94 10.939"}]]];const Vt=["svg",Ce,[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2"}]]];const Qt=["svg",Ce,[["path",{d:"M18 6 6 18"}],["path",{d:"m6 6 12 12"}]]],Xt={title:"XOPCBOT Gateway",brand:"XOPCBOT"},Zt={chat:"Chat",sessions:"Sessions",cron:"Cron Jobs",logs:"Logs",settings:"Settings",management:"Management"},Yt={title:"XopcBot",newSession:"New Chat",welcomeTitle:"Welcome to xopcbot",welcomeDescription:"Send a message to get started",emptyState:"No messages yet",emptyStateDescription:"Start a conversation by typing a message below",you:"You",assistant:"Assistant",tool:"Tool",thinking:"thinking...",typeMessage:"Type a message...",attachFile:"Attach file",sendMessage:"Send message",abort:"Abort",retry:"Retry",reasoning:"Reasoning",thinkingLevelNone:"None",thinkingLevel1:"Level 1",thinkingLevel2:"Level 2",thinkingLevel3:"Level 3",thinkingLevel4:"Level 4",connecting:"Connecting...",disconnected:"Disconnected",connectionError:"Connection error",reconnecting:"Reconnecting...",online:"Online",offline:"Offline"},es={title:"Settings",save:"Save",cancel:"Cancel",close:"Close",loading:"Loading settings...",unsaved:"{{count}} unsaved",saveChanges:"Save Changes",saving:"Saving...",noSection:"No section selected",enableFeature:"Enable this feature",required:"{{field}} is required",invalidFormat:"Invalid format",unsavedChanges:"Unsaved changes",sections:{agent:"Agent",providers:"Providers",channels:"Channels",gateway:"Gateway"},descriptions:{agent:"Configure your agent settings",providers:"Configure your provider API keys",channels:"Configure messaging channels",gateway:"Configure gateway settings"},fields:{model:"Model",workspace:"Workspace",maxTokens:"Max Tokens",temperature:"Temperature",maxToolIterations:"Max Tool Iterations",openaiApiKey:"OpenAI API Key",anthropicApiKey:"Anthropic API Key",googleApiKey:"Google API Key",qwenApiKey:"Qwen API Key",kimiApiKey:"Kimi API Key",minimaxApiKey:"MiniMax API Key",deepseekApiKey:"DeepSeek API Key",grokApiKey:"Grok API Key",openrouterApiKey:"OpenRouter API Key",telegramEnabled:"Telegram",telegramToken:"Telegram Token",telegramApiRoot:"API Root (Optional)",telegramAllowFrom:"Allow From (Optional)",telegramDebug:"Debug Mode",whatsappEnabled:"WhatsApp",whatsappBridgeUrl:"Bridge URL",whatsappAllowFrom:"Allow From (Optional)",heartbeatEnabled:"Heartbeat",heartbeatIntervalMs:"Heartbeat Interval (ms)"},descriptionsFields:{model:"Default AI model to use",workspace:"Working directory for agent files",maxTokens:"Maximum tokens in response",temperature:"Randomness in responses (0-2)",maxToolIterations:"Maximum tool calls per message",openaiApiKey:"API key for OpenAI models",anthropicApiKey:"API key for Claude models",googleApiKey:"API key for Gemini models",qwenApiKey:"API key for Qwen models",kimiApiKey:"API key for Kimi models",minimaxApiKey:"API key for MiniMax models",deepseekApiKey:"API key for DeepSeek models",grokApiKey:"API key for Grok models",openrouterApiKey:"API key for OpenRouter models",telegramEnabled:"Enable Telegram bot",telegramToken:"Bot API token from @BotFather",telegramApiRoot:"Custom Telegram API root URL",telegramAllowFrom:"Allowed user IDs, comma separated",telegramDebug:"Enable debug logging for Telegram",whatsappEnabled:"Enable WhatsApp bridge",whatsappBridgeUrl:"WhatsApp bridge WebSocket URL",whatsappAllowFrom:"Allowed phone numbers, comma separated",heartbeatEnabled:"Enable heartbeat monitoring",heartbeatIntervalMs:"Heartbeat check interval in milliseconds"},placeholders:{workspace:"~/.xopcbot/workspace",openaiApiKey:"sk-...",anthropicApiKey:"sk-ant-...",googleApiKey:"AIzaSy...",qwenApiKey:"sk-...",kimiApiKey:"sk-kimi-...",minimaxApiKey:"sk-cp-...",deepseekApiKey:"sk-...",openrouterApiKey:"sk-or-...",telegramToken:"1234567890:ABCdefGHIjklMNOpqrsTUVwxyz",telegramApiRoot:"https://api.telegram.org",telegramAllowFrom:"123456789, 987654321",whatsappBridgeUrl:"ws://localhost:3001",whatsappAllowFrom:"+1234567890, +0987654321"},connection:{title:"Connection",gatewayUrl:"Gateway URL",gatewayUrlDesc:"WebSocket URL for the gateway server",authToken:"Auth Token",authTokenDesc:"Optional authentication token"},appearance:{title:"Appearance",theme:"Theme",themeDesc:"Choose your preferred color scheme",themeSystem:"System",themeLight:"Light",themeDark:"Dark"},chat:{title:"Chat",enableAttachments:"Enable Attachments",enableAttachmentsDesc:"Allow file attachments in chat",showModelSelector:"Show Model Selector",showModelSelectorDesc:"Display model selection dropdown",showThinkingSelector:"Show Thinking Selector",showThinkingSelectorDesc:"Display thinking level selection"}},ts={noSession:"No session available",noAgent:"No agent set",noModel:"No model set",requestTimeout:"Request timeout",sendFailed:"Failed to send message",invalidFileType:"Invalid file type",fileTooLarge:"File too large (max {{size}})",readFileFailed:"Failed to read file"},ss={dropHere:"Drop files here",dragDrop:"Drag and drop files here",image:"Image",document:"Document",pdf:"PDF",word:"Word",excel:"Excel",powerpoint:"PowerPoint",text:"Text",code:"Code",archive:"Archive",unknown:"Unknown"},is={settings:"Open settings"},ns={title:"Configuration",save:"Save Configuration",noResult:"No result",artifacts:"Artifacts",showArtifacts:"Show artifacts"},os={title:"Logs",refresh:"Refresh",clear:"Clear",totalLogs:"Total Logs",pause:"Pause",autoRefresh:"Auto Refresh",level:"Level",search:"Search",searchPlaceholder:"Search logs...",time:"Time",message:"Message",module:"Module",noLogs:"No logs found",noLogsDescription:"Try adjusting your filters or check back later.",details:"Log Details"},rs={title:"Sessions",newSession:"New Session",searchPlaceholder:"Search sessions...",totalSessions:"Total Sessions",activeSessions:"Active Sessions",pinnedSessions:"Pinned Sessions",archivedSessions:"Archived Sessions",noSessions:"No sessions",delete:"Delete",archive:"Archive",pin:"Pin",unpin:"Unpin",confirmDelete:"Are you sure you want to delete this session?"},as={title:"Cron Jobs",addJob:"Add Cron Job",editJob:"Edit Job",name:"Name (optional)",namePlaceholder:"My scheduled task",schedule:"Schedule (cron expression) *",scheduleHint:"e.g., */5 * * * * (every 5 minutes), 0 9 * * * (daily at 9am)",message:"Message *",messagePlaceholder:"What should the assistant do?",create:"Create Job",runNow:"Run Now",delete:"Delete",edit:"Edit",enable:"Enable",disable:"Disable",enabled:"Enabled",disabled:"Disabled",running:"Running",lastRun:"Last Run",nextRun:"Next Run",status:"Status",history:"History",actions:"Actions",noJobs:"No cron jobs",confirmDelete:"Are you sure you want to delete this cron job?",confirmRun:"Run this cron job now?",success:"Success",failed:"Failed",scheduleLabel:"Schedule",messageLabel:"Message",confirm:"Confirm",cancel:"Cancel",total:"Total",schedulePresets:{custom:"-- Custom (enter below) --",everyMinute:"Every minute",every5Minutes:"Every 5 minutes (default)",every10Minutes:"Every 10 minutes",every15Minutes:"Every 15 minutes",every30Minutes:"Every 30 minutes",everyHour:"Every hour",every2Hours:"Every 2 hours",every4Hours:"Every 4 hours",every6Hours:"Every 6 hours",every12Hours:"Every 12 hours",everyDayMidnight:"Every day at midnight",everyDay9AM:"Every day at 9:00 AM",everyDay9PM:"Every day at 9:00 PM"},scheduleHintPreset:"Select a preset or enter custom cron expression",mode:"Mode",modeDirect:"Send message directly to the channel without AI processing",modeAgent:"Use AI agent to process the message, then send the response",modeDirectOption:"Direct (send message directly)",modeAgentOption:"AI Agent (process with AI then send)",model:"Model",noConfiguredModels:"No configured models",save:"Save",failedToLoadJobs:"Failed to load jobs",scheduleRequired:"Schedule and message are required",chatIdRequired:"Chat ID is required",failedToJob:"Failed to {{mode}} job",failedToToggleJob:"Failed to toggle job",actionFailed:"Action failed",enterManuallyOrSelect:"Enter manually or select from recent chats",noRecentChats:"No recent chats found. Enter chat ID manually (e.g., 123456789 for Telegram)",timeLabels:{lessThanMinute:"Less than a minute",minutes:"{{count}} min",hours:"{{count}} hours",overdue:"Overdue"},lastActiveLabels:{justNow:"just now",minutesAgo:"{{count}}m ago",hoursAgo:"{{count}}h ago",daysAgo:"{{count}}d ago"}},ls={save:"Save",cancel:"Cancel",confirm:"Confirm",close:"Close",loading:"Loading...",error:"Error",success:"Success",noData:"No data"},cs={app:Xt,nav:Zt,chat:Yt,settings:es,errors:ts,fileUpload:ss,shortcuts:is,config:ns,logs:os,sessions:rs,cron:as,common:ls},hs={title:"XOPCBOT 网关",brand:"XOPCBOT"},ds={chat:"对话",sessions:"会话",cron:"定时任务",logs:"日志",settings:"设置",management:"管理"},ps={title:"XopcBot",newSession:"新建对话",welcomeTitle:"欢迎使用 xopcbot",welcomeDescription:"发送消息开始对话",emptyState:"暂无消息",emptyStateDescription:"在下方输入消息开始对话",you:"你",assistant:"助手",tool:"工具",thinking:"思考中...",typeMessage:"输入消息...",attachFile:"附加文件",sendMessage:"发送消息",abort:"中止",retry:"重试",reasoning:"推理",thinkingLevelNone:"无",thinkingLevel1:"级别 1",thinkingLevel2:"级别 2",thinkingLevel3:"级别 3",thinkingLevel4:"级别 4",connecting:"连接中...",disconnected:"已断开",connectionError:"连接错误",reconnecting:"重新连接中...",online:"在线",offline:"离线"},us={title:"设置",save:"保存",cancel:"取消",close:"关闭",loading:"加载设置中...",unsaved:"{{count}} 个未保存",saveChanges:"保存更改",saving:"保存中...",noSection:"未选择部分",enableFeature:"启用此功能",required:"{{field}} 为必填项",invalidFormat:"格式无效",unsavedChanges:"未保存的更改",sections:{agent:"代理",providers:"提供商",channels:"渠道",gateway:"网关"},descriptions:{agent:"配置代理设置",providers:"配置提供商 API 密钥",channels:"配置消息渠道",gateway:"配置网关设置"},fields:{model:"模型",workspace:"工作区",maxTokens:"最大 Token 数",temperature:"温度",maxToolIterations:"最大工具调用次数",openaiApiKey:"OpenAI API 密钥",anthropicApiKey:"Anthropic API 密钥",googleApiKey:"Google API 密钥",qwenApiKey:"Qwen API 密钥",kimiApiKey:"Kimi API 密钥",minimaxApiKey:"MiniMax API 密钥",deepseekApiKey:"DeepSeek API 密钥",grokApiKey:"Grok API 密钥",openrouterApiKey:"OpenRouter API 密钥",telegramEnabled:"Telegram",telegramToken:"Telegram 令牌",telegramApiRoot:"API 根地址(可选)",telegramAllowFrom:"允许来源(可选)",telegramDebug:"调试模式",whatsappEnabled:"WhatsApp",whatsappBridgeUrl:"桥接地址",whatsappAllowFrom:"允许来源(可选)",heartbeatEnabled:"心跳",heartbeatIntervalMs:"心跳间隔(毫秒)"},descriptionsFields:{model:"默认使用的 AI 模型",workspace:"代理文件的工作目录",maxTokens:"响应中的最大 token 数",temperature:"响应随机性(0-2)",maxToolIterations:"每条消息的最大工具调用次数",openaiApiKey:"OpenAI 模型的 API 密钥",anthropicApiKey:"Claude 模型的 API 密钥",googleApiKey:"Gemini 模型的 API 密钥",qwenApiKey:"Qwen 模型的 API 密钥",kimiApiKey:"Kimi 模型的 API 密钥",minimaxApiKey:"MiniMax 模型的 API 密钥",deepseekApiKey:"DeepSeek 模型的 API 密钥",grokApiKey:"Grok 模型的 API 密钥",openrouterApiKey:"OpenRouter 模型的 API 密钥",telegramEnabled:"启用 Telegram 机器人",telegramToken:"@BotFather 获取的机器人 API 令牌",telegramApiRoot:"自定义 Telegram API 根地址",telegramAllowFrom:"允许的用户 ID,逗号分隔",telegramDebug:"启用 Telegram 调试日志",whatsappEnabled:"启用 WhatsApp 桥接",whatsappBridgeUrl:"WhatsApp 桥接 WebSocket 地址",whatsappAllowFrom:"允许的电话号码,逗号分隔",heartbeatEnabled:"启用心跳监控",heartbeatIntervalMs:"心跳检查间隔(毫秒)"},placeholders:{workspace:"~/.xopcbot/workspace",openaiApiKey:"sk-...",anthropicApiKey:"sk-ant-...",googleApiKey:"AIzaSy...",qwenApiKey:"sk-...",kimiApiKey:"sk-kimi-...",minimaxApiKey:"sk-cp-...",deepseekApiKey:"sk-...",openrouterApiKey:"sk-or-...",telegramToken:"1234567890:ABCdefGHIjklMNOpqrsTUVwxyz",telegramApiRoot:"https://api.telegram.org",telegramAllowFrom:"123456789, 987654321",whatsappBridgeUrl:"ws://localhost:3001",whatsappAllowFrom:"+1234567890, +0987654321"},connection:{title:"连接",gatewayUrl:"网关地址",gatewayUrlDesc:"网关服务器的 WebSocket 地址",authToken:"认证令牌",authTokenDesc:"可选的认证令牌"},appearance:{title:"外观",theme:"主题",themeDesc:"选择你喜欢的配色方案",themeSystem:"跟随系统",themeLight:"浅色",themeDark:"深色"},chat:{title:"对话",enableAttachments:"启用附件",enableAttachmentsDesc:"允许在对话中附加文件",showModelSelector:"显示模型选择器",showModelSelectorDesc:"显示模型选择下拉框",showThinkingSelector:"显示思考选择器",showThinkingSelectorDesc:"显示思考级别选择"}},gs={noSession:"无可用会话",noAgent:"未设置代理",noModel:"未设置模型",requestTimeout:"请求超时",sendFailed:"发送消息失败",invalidFileType:"无效的文件类型",fileTooLarge:"文件过大(最大 {{size}})",readFileFailed:"读取文件失败"},ms={dropHere:"拖放文件到此处",dragDrop:"拖放文件到此处",image:"图片",document:"文档",pdf:"PDF",word:"Word",excel:"Excel",powerpoint:"PowerPoint",text:"文本",code:"代码",archive:"压缩包",unknown:"未知"},_s={settings:"打开设置"},vs={title:"配置",save:"保存配置",noResult:"无结果",artifacts:"产物",showArtifacts:"显示产物"},fs={title:"日志",refresh:"刷新",clear:"清空",totalLogs:"总日志数",pause:"暂停",autoRefresh:"自动刷新",level:"级别",search:"搜索",searchPlaceholder:"搜索日志...",time:"时间",message:"消息",module:"模块",noLogs:"暂无日志",noLogsDescription:"尝试调整筛选条件或稍后再查看。",details:"日志详情"},ys={title:"会话",newSession:"新建会话",searchPlaceholder:"搜索会话...",totalSessions:"总会话数",activeSessions:"活跃会话",pinnedSessions:"固定会话",archivedSessions:"归档会话",noSessions:"暂无会话",delete:"删除",archive:"归档",pin:"固定",unpin:"取消固定",confirmDelete:"确定要删除此会话吗?"},ws={title:"定时任务",addJob:"添加定时任务",editJob:"编辑任务",name:"名称(可选)",namePlaceholder:"我的定时任务",schedule:"计划表达式 *",scheduleHint:"例如:*/5 * * * *(每5分钟),0 9 * * *(每天9点)",message:"消息 *",messagePlaceholder:"助手应该做什么?",create:"创建任务",runNow:"立即执行",delete:"删除",edit:"编辑",enable:"启用",disable:"禁用",enabled:"已启用",disabled:"已禁用",running:"运行中",lastRun:"上次执行",nextRun:"下次执行",status:"状态",history:"历史记录",actions:"操作",noJobs:"暂无定时任务",confirmDelete:"确定要删除此定时任务吗?",confirmRun:"立即执行此定时任务?",success:"成功",failed:"失败",scheduleLabel:"计划",messageLabel:"消息",confirm:"确认",cancel:"取消",total:"总计",schedulePresets:{custom:"-- 自定义(在下方输入) --",everyMinute:"每分钟",every5Minutes:"每 5 分钟(默认)",every10Minutes:"每 10 分钟",every15Minutes:"每 15 分钟",every30Minutes:"每 30 分钟",everyHour:"每小时",every2Hours:"每 2 小时",every4Hours:"每 4 小时",every6Hours:"每 6 小时",every12Hours:"每 12 小时",everyDayMidnight:"每天午夜",everyDay9AM:"每天早上 9 点",everyDay9PM:"每天晚上 9 点"},scheduleHintPreset:"选择预设或输入自定义 cron 表达式",mode:"模式",modeDirect:"直接发送消息到渠道,不经过 AI 处理",modeAgent:"使用 AI 代理处理消息,然后发送回复",modeDirectOption:"直接发送(直接发送到渠道)",modeAgentOption:"AI 代理(经过 AI 处理后发送)",model:"模型",noConfiguredModels:"未配置模型",save:"保存",failedToLoadJobs:"加载任务失败",scheduleRequired:"计划表达式和消息为必填项",chatIdRequired:"Chat ID 为必填项",failedToJob:"{{mode}} 任务失败",failedToToggleJob:"切换任务状态失败",actionFailed:"操作失败",enterManuallyOrSelect:"手动输入或从最近聊天中选择",noRecentChats:"未找到最近聊天。请手动输入 chat ID(例如:Telegram 为 123456789)",timeLabels:{lessThanMinute:"不到 1 分钟",minutes:"{{count}} 分钟",hours:"{{count}} 小时",overdue:"已过期"},lastActiveLabels:{justNow:"刚刚",minutesAgo:"{{count}} 分钟前",hoursAgo:"{{count}} 小时前",daysAgo:"{{count}} 天前"}},bs={save:"保存",cancel:"取消",confirm:"确认",close:"关闭",loading:"加载中...",error:"错误",success:"成功",noData:"暂无数据"},$s={app:hs,nav:ds,chat:ps,settings:us,errors:gs,fileUpload:ms,shortcuts:_s,config:vs,logs:fs,sessions:ys,cron:ws,common:bs},pt={en:cs,zh:$s},K=new Map;K.set("en",pt.en);K.set("zh",pt.zh);let q="en";function a(e,t){const s=K.get(q);if(!s)return e;const i=e.split(".");let n=s;for(const r of i)if(n&&typeof n=="object"&&r in n)n=n[r];else{const l=K.get("en");if(l&&q!=="en"){let h=l;for(const d of i)if(h&&typeof h=="object"&&d in h)h=h[d];else return e;n=h}else return e}return typeof n!="string"?e:t?n.replace(/\{\{(\w+)\}\}/g,(r,l)=>{const h=t[l];return h!==void 0?String(h):`{{${l}}}`}):n}async function xs(e){if(K.has(e)){q=e;return}try{const t=await fetch(`/src/i18n/${e}.json`);if(!t.ok)throw new Error(`Failed to load ${e} translations`);const s=await t.json();K.set(e,s),q=e,window.dispatchEvent(new CustomEvent("languagechange",{detail:{language:e}}))}catch(t){console.error(`Failed to load ${e} translations:`,t),e!=="en"&&K.has("en")&&(q="en")}}function tt(e){K.has(e)?(q=e,window.dispatchEvent(new CustomEvent("languagechange",{detail:{language:e}}))):xs(e)}function Ss(e="en"){q=e}const ks={"Type a message...":"chat.typeMessage","Attach file":"chat.attachFile","Send message":"chat.sendMessage",Abort:"chat.abort","No session available":"errors.noSession","No agent set":"errors.noAgent",Configuration:"config.title",Cancel:"settings.cancel",Save:"settings.save","No result":"config.noResult",Artifacts:"config.artifacts","Show artifacts":"config.showArtifacts"};function te(e){const t=ks[e];return a(t||e)}var As=Object.defineProperty,Cs=Object.getOwnPropertyDescriptor,T=(e,t,s,i)=>{for(var n=i>1?void 0:i?Cs(t,s):t,r=e.length-1,l;r>=0;r--)(l=e[r])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&As(t,s,n),n};function le(e,t=""){if(!e||!Array.isArray(e))return"";const[s,i,n]=e,r=Object.entries(i||{}).map(([d,g])=>`${d}="${g}"`).join(" "),l=Array.isArray(n)?n.map(d=>{if(Array.isArray(d)){const[g,S]=d,f=Object.entries(S||{}).map(([E,L])=>`${E}="${L}"`).join(" ");return`<${g} ${f} />`}return""}).join(""):"";return`<svg ${t?`${r} class="${t}"`:r}>${l}</svg>`}let M=class extends y{constructor(){super(...arguments),this.value="",this.attachments=[],this.isStreaming=!1,this.showAttachmentButton=!0,this.showModelSelector=!0,this._isComposing=!1,this._isDragging=!1,this._processingFiles=!1,this._isSending=!1,this.textareaRef=Ye(),this.fileInputRef=Ye(),this.maxFileSize=20*1024*1024,this.acceptedTypes="image/*,application/pdf,.docx,.pptx,.xlsx,.xls,.txt,.md,.json,.xml,.html,.css,.js,.ts,.jsx,.tsx,.yml,.yaml,.zip",this._handleDocumentDragOver=e=>{e.dataTransfer?.types.includes("Files")&&(e.preventDefault(),this._isDragging=!0)},this._handleDocumentDragLeave=e=>{e.relatedTarget===null&&(this._isDragging=!1)},this._handleDocumentDrop=async e=>{e.preventDefault(),this._isDragging=!1;const t=e.dataTransfer?.files;t&&t.length>0&&await this._processFiles(Array.from(t))},this._handleInput=e=>{const t=e.target;this.value=t.value,this._adjustTextareaHeight()},this._handleKeydown=e=>{e.key==="Enter"&&!e.shiftKey&&!this._isComposing&&(e.preventDefault(),this._send())},this._handlePaste=async e=>{const t=e.clipboardData?.items;if(!t)return;const s=[];for(const i of Array.from(t))if(i.type.startsWith("image/")){const n=i.getAsFile();n&&s.push(n)}s.length>0&&(e.preventDefault(),await this._processFiles(s))},this._handleFileInputChange=async e=>{const t=e.target,s=t.files;s&&(await this._processFiles(Array.from(s)),t.value="")}}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),document.addEventListener("dragover",this._handleDocumentDragOver),document.addEventListener("drop",this._handleDocumentDrop),document.addEventListener("dragleave",this._handleDocumentDragLeave),document.addEventListener("click",this._handleOutsideClick)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("dragover",this._handleDocumentDragOver),document.removeEventListener("drop",this._handleDocumentDrop),document.removeEventListener("dragleave",this._handleDocumentDragLeave),document.removeEventListener("click",this._handleOutsideClick)}render(){return o`
|
|
1
|
+
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))i(n);new MutationObserver(n=>{for(const a of n)if(a.type==="childList")for(const l of a.addedNodes)l.tagName==="LINK"&&l.rel==="modulepreload"&&i(l)}).observe(document,{childList:!0,subtree:!0});function s(n){const a={};return n.integrity&&(a.integrity=n.integrity),n.referrerPolicy&&(a.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?a.credentials="include":n.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function i(n){if(n.ep)return;n.ep=!0;const a=s(n);fetch(n.href,a)}})();const $e=globalThis,Be=$e.ShadowRoot&&($e.ShadyCSS===void 0||$e.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,rt=Symbol(),qe=new WeakMap;let $t=class{constructor(t,s,i){if(this._$cssResult$=!0,i!==rt)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=s}get styleSheet(){let t=this.o;const s=this.t;if(Be&&t===void 0){const i=s!==void 0&&s.length===1;i&&(t=qe.get(s)),t===void 0&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),i&&qe.set(s,t))}return t}toString(){return this.cssText}};const kt=e=>new $t(typeof e=="string"?e:e+"",void 0,rt),xt=(e,t)=>{if(Be)e.adoptedStyleSheets=t.map(s=>s instanceof CSSStyleSheet?s:s.styleSheet);else for(const s of t){const i=document.createElement("style"),n=$e.litNonce;n!==void 0&&i.setAttribute("nonce",n),i.textContent=s.cssText,e.appendChild(i)}},Je=Be?e=>e:e=>e instanceof CSSStyleSheet?(t=>{let s="";for(const i of t.cssRules)s+=i.cssText;return kt(s)})(e):e;const{is:St,defineProperty:At,getOwnPropertyDescriptor:Ct,getOwnPropertyNames:Tt,getOwnPropertySymbols:Mt,getPrototypeOf:Et}=Object,Te=globalThis,Ge=Te.trustedTypes,Pt=Ge?Ge.emptyScript:"",Ft=Te.reactiveElementPolyfillSupport,ue=(e,t)=>e,ke={toAttribute(e,t){switch(t){case Boolean:e=e?Pt:null;break;case Object:case Array:e=e==null?e:JSON.stringify(e)}return e},fromAttribute(e,t){let s=e;switch(t){case Boolean:s=e!==null;break;case Number:s=e===null?null:Number(e);break;case Object:case Array:try{s=JSON.parse(e)}catch{s=null}}return s}},Ke=(e,t)=>!St(e,t),We={attribute:!0,type:String,converter:ke,reflect:!1,useDefault:!1,hasChanged:Ke};Symbol.metadata??=Symbol("metadata"),Te.litPropertyMetadata??=new WeakMap;let se=class extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=We){if(s.state&&(s.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((s=Object.create(s)).wrapped=!0),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),n=this.getPropertyDescriptor(t,i,s);n!==void 0&&At(this.prototype,t,n)}}static getPropertyDescriptor(t,s,i){const{get:n,set:a}=Ct(this.prototype,t)??{get(){return this[s]},set(l){this[s]=l}};return{get:n,set(l){const h=n?.call(this);a?.call(this,l),this.requestUpdate(t,h,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??We}static _$Ei(){if(this.hasOwnProperty(ue("elementProperties")))return;const t=Et(this);t.finalize(),t.l!==void 0&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(ue("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(ue("properties"))){const s=this.properties,i=[...Tt(s),...Mt(s)];for(const n of i)this.createProperty(n,s[n])}const t=this[Symbol.metadata];if(t!==null){const s=litPropertyMetadata.get(t);if(s!==void 0)for(const[i,n]of s)this.elementProperties.set(i,n)}this._$Eh=new Map;for(const[s,i]of this.elementProperties){const n=this._$Eu(s,i);n!==void 0&&this._$Eh.set(n,s)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const s=[];if(Array.isArray(t)){const i=new Set(t.flat(1/0).reverse());for(const n of i)s.unshift(Je(n))}else t!==void 0&&s.push(Je(t));return s}static _$Eu(t,s){const i=s.attribute;return i===!1?void 0:typeof i=="string"?i:typeof t=="string"?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),this.renderRoot!==void 0&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,s=this.constructor.elementProperties;for(const i of s.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return xt(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,s,i){this._$AK(t,i)}_$ET(t,s){const i=this.constructor.elementProperties.get(t),n=this.constructor._$Eu(t,i);if(n!==void 0&&i.reflect===!0){const a=(i.converter?.toAttribute!==void 0?i.converter:ke).toAttribute(s,i.type);this._$Em=t,a==null?this.removeAttribute(n):this.setAttribute(n,a),this._$Em=null}}_$AK(t,s){const i=this.constructor,n=i._$Eh.get(t);if(n!==void 0&&this._$Em!==n){const a=i.getPropertyOptions(n),l=typeof a.converter=="function"?{fromAttribute:a.converter}:a.converter?.fromAttribute!==void 0?a.converter:ke;this._$Em=n;const h=l.fromAttribute(s,a.type);this[n]=h??this._$Ej?.get(n)??h,this._$Em=null}}requestUpdate(t,s,i,n=!1,a){if(t!==void 0){const l=this.constructor;if(n===!1&&(a=this[t]),i??=l.getPropertyOptions(t),!((i.hasChanged??Ke)(a,s)||i.useDefault&&i.reflect&&a===this._$Ej?.get(t)&&!this.hasAttribute(l._$Eu(t,i))))return;this.C(t,s,i)}this.isUpdatePending===!1&&(this._$ES=this._$EP())}C(t,s,{useDefault:i,reflect:n,wrapped:a},l){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,l??s??this[t]),a!==!0||l!==void 0)||(this._$AL.has(t)||(this.hasUpdated||i||(s=void 0),this._$AL.set(t,s)),n===!0&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(s){Promise.reject(s)}const t=this.scheduleUpdate();return t!=null&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[n,a]of this._$Ep)this[n]=a;this._$Ep=void 0}const i=this.constructor.elementProperties;if(i.size>0)for(const[n,a]of i){const{wrapped:l}=a,h=this[n];l!==!0||this._$AL.has(n)||h===void 0||this.C(n,void 0,a,h)}}let t=!1;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),this._$EO?.forEach(i=>i.hostUpdate?.()),this.update(s)):this._$EM()}catch(i){throw t=!1,this._$EM(),i}t&&this._$AE(s)}willUpdate(t){}_$AE(t){this._$EO?.forEach(s=>s.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(s=>this._$ET(s,this[s])),this._$EM()}updated(t){}firstUpdated(t){}};se.elementStyles=[],se.shadowRootOptions={mode:"open"},se[ue("elementProperties")]=new Map,se[ue("finalized")]=new Map,Ft?.({ReactiveElement:se}),(Te.reactiveElementVersions??=[]).push("2.1.2");const je=globalThis,Ve=e=>e,xe=je.trustedTypes,Qe=xe?xe.createPolicy("lit-html",{createHTML:e=>e}):void 0,lt="$lit$",B=`lit$${Math.random().toFixed(9).slice(2)}$`,ct="?"+B,Lt=`<${ct}>`,G=document,_e=()=>G.createComment(""),me=e=>e===null||typeof e!="object"&&typeof e!="function",Ue=Array.isArray,Dt=e=>Ue(e)||typeof e?.[Symbol.iterator]=="function",Fe=`[
|
|
2
|
+
\f\r]`,ce=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,Xe=/-->/g,Ye=/>/g,N=RegExp(`>|${Fe}(?:([^\\s"'>=/]+)(${Fe}*=${Fe}*(?:[^
|
|
3
|
+
\f\r"'\`<>=]|("|')|))|$)`,"g"),Ze=/'/g,et=/"/g,ht=/^(?:script|style|textarea|title)$/i,It=e=>(t,...s)=>({_$litType$:e,strings:t,values:s}),o=It(1),W=Symbol.for("lit-noChange"),_=Symbol.for("lit-nothing"),tt=new WeakMap,q=G.createTreeWalker(G,129);function dt(e,t){if(!Ue(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return Qe!==void 0?Qe.createHTML(t):t}const Ot=(e,t)=>{const s=e.length-1,i=[];let n,a=t===2?"<svg>":t===3?"<math>":"",l=ce;for(let h=0;h<s;h++){const p=e[h];let g,S,f=-1,F=0;for(;F<p.length&&(l.lastIndex=F,S=l.exec(p),S!==null);)F=l.lastIndex,l===ce?S[1]==="!--"?l=Xe:S[1]!==void 0?l=Ye:S[2]!==void 0?(ht.test(S[2])&&(n=RegExp("</"+S[2],"g")),l=N):S[3]!==void 0&&(l=N):l===N?S[0]===">"?(l=n??ce,f=-1):S[1]===void 0?f=-2:(f=l.lastIndex-S[2].length,g=S[1],l=S[3]===void 0?N:S[3]==='"'?et:Ze):l===et||l===Ze?l=N:l===Xe||l===Ye?l=ce:(l=N,n=void 0);const I=l===N&&e[h+1].startsWith("/>")?" ":"";a+=l===ce?p+Lt:f>=0?(i.push(g),p.slice(0,f)+lt+p.slice(f)+B+I):p+B+(f===-2?h:I)}return[dt(e,a+(e[s]||"<?>")+(t===2?"</svg>":t===3?"</math>":"")),i]};class ve{constructor({strings:t,_$litType$:s},i){let n;this.parts=[];let a=0,l=0;const h=t.length-1,p=this.parts,[g,S]=Ot(t,s);if(this.el=ve.createElement(g,i),q.currentNode=this.el.content,s===2||s===3){const f=this.el.content.firstChild;f.replaceWith(...f.childNodes)}for(;(n=q.nextNode())!==null&&p.length<h;){if(n.nodeType===1){if(n.hasAttributes())for(const f of n.getAttributeNames())if(f.endsWith(lt)){const F=S[l++],I=n.getAttribute(f).split(B),we=/([.?@])?(.*)/.exec(F);p.push({type:1,index:a,name:we[2],strings:I,ctor:we[1]==="."?Bt:we[1]==="?"?Kt:we[1]==="@"?jt:Me}),n.removeAttribute(f)}else f.startsWith(B)&&(p.push({type:6,index:a}),n.removeAttribute(f));if(ht.test(n.tagName)){const f=n.textContent.split(B),F=f.length-1;if(F>0){n.textContent=xe?xe.emptyScript:"";for(let I=0;I<F;I++)n.append(f[I],_e()),q.nextNode(),p.push({type:2,index:++a});n.append(f[F],_e())}}}else if(n.nodeType===8)if(n.data===ct)p.push({type:2,index:a});else{let f=-1;for(;(f=n.data.indexOf(B,f+1))!==-1;)p.push({type:7,index:a}),f+=B.length-1}a++}}static createElement(t,s){const i=G.createElement("template");return i.innerHTML=t,i}}function ne(e,t,s=e,i){if(t===W)return t;let n=i!==void 0?s._$Co?.[i]:s._$Cl;const a=me(t)?void 0:t._$litDirective$;return n?.constructor!==a&&(n?._$AO?.(!1),a===void 0?n=void 0:(n=new a(e),n._$AT(e,s,i)),i!==void 0?(s._$Co??=[])[i]=n:s._$Cl=n),n!==void 0&&(t=ne(e,n._$AS(e,t.values),n,i)),t}class Rt{constructor(t,s){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=s}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:s},parts:i}=this._$AD,n=(t?.creationScope??G).importNode(s,!0);q.currentNode=n;let a=q.nextNode(),l=0,h=0,p=i[0];for(;p!==void 0;){if(l===p.index){let g;p.type===2?g=new ye(a,a.nextSibling,this,t):p.type===1?g=new p.ctor(a,p.name,p.strings,this,t):p.type===6&&(g=new Ut(a,this,t)),this._$AV.push(g),p=i[++h]}l!==p?.index&&(a=q.nextNode(),l++)}return q.currentNode=G,n}p(t){let s=0;for(const i of this._$AV)i!==void 0&&(i.strings!==void 0?(i._$AI(t,i,s),s+=i.strings.length-2):i._$AI(t[s])),s++}}class ye{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,s,i,n){this.type=2,this._$AH=_,this._$AN=void 0,this._$AA=t,this._$AB=s,this._$AM=i,this.options=n,this._$Cv=n?.isConnected??!0}get parentNode(){let t=this._$AA.parentNode;const s=this._$AM;return s!==void 0&&t?.nodeType===11&&(t=s.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,s=this){t=ne(this,t,s),me(t)?t===_||t==null||t===""?(this._$AH!==_&&this._$AR(),this._$AH=_):t!==this._$AH&&t!==W&&this._(t):t._$litType$!==void 0?this.$(t):t.nodeType!==void 0?this.T(t):Dt(t)?this.k(t):this._(t)}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t))}_(t){this._$AH!==_&&me(this._$AH)?this._$AA.nextSibling.data=t:this.T(G.createTextNode(t)),this._$AH=t}$(t){const{values:s,_$litType$:i}=t,n=typeof i=="number"?this._$AC(t):(i.el===void 0&&(i.el=ve.createElement(dt(i.h,i.h[0]),this.options)),i);if(this._$AH?._$AD===n)this._$AH.p(s);else{const a=new Rt(n,this),l=a.u(this.options);a.p(s),this.T(l),this._$AH=a}}_$AC(t){let s=tt.get(t.strings);return s===void 0&&tt.set(t.strings,s=new ve(t)),s}k(t){Ue(this._$AH)||(this._$AH=[],this._$AR());const s=this._$AH;let i,n=0;for(const a of t)n===s.length?s.push(i=new ye(this.O(_e()),this.O(_e()),this,this.options)):i=s[n],i._$AI(a),n++;n<s.length&&(this._$AR(i&&i._$AB.nextSibling,n),s.length=n)}_$AR(t=this._$AA.nextSibling,s){for(this._$AP?.(!1,!0,s);t!==this._$AB;){const i=Ve(t).nextSibling;Ve(t).remove(),t=i}}setConnected(t){this._$AM===void 0&&(this._$Cv=t,this._$AP?.(t))}}class Me{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,s,i,n,a){this.type=1,this._$AH=_,this._$AN=void 0,this.element=t,this.name=s,this._$AM=n,this.options=a,i.length>2||i[0]!==""||i[1]!==""?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=_}_$AI(t,s=this,i,n){const a=this.strings;let l=!1;if(a===void 0)t=ne(this,t,s,0),l=!me(t)||t!==this._$AH&&t!==W,l&&(this._$AH=t);else{const h=t;let p,g;for(t=a[0],p=0;p<a.length-1;p++)g=ne(this,h[i+p],s,p),g===W&&(g=this._$AH[p]),l||=!me(g)||g!==this._$AH[p],g===_?t=_:t!==_&&(t+=(g??"")+a[p+1]),this._$AH[p]=g}l&&!n&&this.j(t)}j(t){t===_?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??"")}}class Bt extends Me{constructor(){super(...arguments),this.type=3}j(t){this.element[this.name]=t===_?void 0:t}}class Kt extends Me{constructor(){super(...arguments),this.type=4}j(t){this.element.toggleAttribute(this.name,!!t&&t!==_)}}class jt extends Me{constructor(t,s,i,n,a){super(t,s,i,n,a),this.type=5}_$AI(t,s=this){if((t=ne(this,t,s,0)??_)===W)return;const i=this._$AH,n=t===_&&i!==_||t.capture!==i.capture||t.once!==i.once||t.passive!==i.passive,a=t!==_&&(i===_||n);n&&this.element.removeEventListener(this.name,this,i),a&&this.element.addEventListener(this.name,this,t),this._$AH=t}handleEvent(t){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t)}}class Ut{constructor(t,s,i){this.element=t,this.type=6,this._$AN=void 0,this._$AM=s,this.options=i}get _$AU(){return this._$AM._$AU}_$AI(t){ne(this,t)}}const Ht=je.litHtmlPolyfillSupport;Ht?.(ve,ye),(je.litHtmlVersions??=[]).push("3.3.2");const Nt=(e,t,s)=>{const i=s?.renderBefore??t;let n=i._$litPart$;if(n===void 0){const a=s?.renderBefore??null;i._$litPart$=n=new ye(t.insertBefore(_e(),a),a,void 0,s??{})}return n._$AI(e),n};const He=globalThis;let y=class extends se{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const s=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=Nt(s,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return W}};y._$litElement$=!0,y.finalized=!0,He.litElementHydrateSupport?.({LitElement:y});const zt=He.litElementPolyfillSupport;zt?.({LitElement:y});(He.litElementVersions??=[]).push("4.2.2");const k=e=>(t,s)=>{s!==void 0?s.addInitializer(()=>{customElements.define(e,t)}):customElements.define(e,t)};const qt={attribute:!0,type:String,converter:ke,reflect:!1,hasChanged:Ke},Jt=(e=qt,t,s)=>{const{kind:i,metadata:n}=s;let a=globalThis.litPropertyMetadata.get(n);if(a===void 0&&globalThis.litPropertyMetadata.set(n,a=new Map),i==="setter"&&((e=Object.create(e)).wrapped=!0),a.set(s.name,e),i==="accessor"){const{name:l}=s;return{set(h){const p=t.get.call(this);t.set.call(this,h),this.requestUpdate(l,p,e,!0,h)},init(h){return h!==void 0&&this.C(l,void 0,e,h),h}}}if(i==="setter"){const{name:l}=s;return function(h){const p=this[l];t.call(this,h),this.requestUpdate(l,p,e,!0,h)}}throw Error("Unsupported decorator location: "+i)};function u(e){return(t,s)=>typeof s=="object"?Jt(e,t,s):((i,n,a)=>{const l=n.hasOwnProperty(a);return n.constructor.createProperty(a,i),l?Object.getOwnPropertyDescriptor(n,a):void 0})(e,t,s)}function c(e){return u({...e,state:!0,attribute:!1})}const Gt=(e,t,s)=>(s.configurable=!0,s.enumerable=!0,Reflect.decorate&&typeof t!="object"&&Object.defineProperty(e,t,s),s);function oe(e,t){return(s,i,n)=>{const a=l=>l.renderRoot?.querySelector(e)??null;return Gt(s,i,{get(){return a(this)}})}}const Wt=e=>e.strings===void 0;const pt={CHILD:2},ut=e=>(...t)=>({_$litDirective$:e,values:t});class gt{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,s,i){this._$Ct=t,this._$AM=s,this._$Ci=i}_$AS(t,s){return this.update(t,s)}update(t,s){return this.render(...s)}}const ge=(e,t)=>{const s=e._$AN;if(s===void 0)return!1;for(const i of s)i._$AO?.(t,!1),ge(i,t);return!0},Se=e=>{let t,s;do{if((t=e._$AM)===void 0)break;s=t._$AN,s.delete(e),e=t}while(s?.size===0)},_t=e=>{for(let t;t=e._$AM;e=t){let s=t._$AN;if(s===void 0)t._$AN=s=new Set;else if(s.has(e))break;s.add(e),Xt(t)}};function Vt(e){this._$AN!==void 0?(Se(this),this._$AM=e,_t(this)):this._$AM=e}function Qt(e,t=!1,s=0){const i=this._$AH,n=this._$AN;if(n!==void 0&&n.size!==0)if(t)if(Array.isArray(i))for(let a=s;a<i.length;a++)ge(i[a],!1),Se(i[a]);else i!=null&&(ge(i,!1),Se(i));else ge(this,e)}const Xt=e=>{e.type==pt.CHILD&&(e._$AP??=Qt,e._$AQ??=Vt)};class Yt extends gt{constructor(){super(...arguments),this._$AN=void 0}_$AT(t,s,i){super._$AT(t,s,i),_t(this),this.isConnected=t._$AU}_$AO(t,s=!0){t!==this.isConnected&&(this.isConnected=t,t?this.reconnected?.():this.disconnected?.()),s&&(ge(this,t),Se(this))}setValue(t){if(Wt(this._$Ct))this._$Ct._$AI(t,this);else{const s=[...this._$Ct._$AH];s[this._$Ci]=t,this._$Ct._$AI(s,this,0)}}disconnected(){}reconnected(){}}const st=()=>new Zt;class Zt{}const Le=new WeakMap,it=ut(class extends Yt{render(e){return _}update(e,[t]){const s=t!==this.G;return s&&this.G!==void 0&&this.rt(void 0),(s||this.lt!==this.ct)&&(this.G=t,this.ht=e.options?.host,this.rt(this.ct=e.element)),_}rt(e){if(this.isConnected||(e=void 0),typeof this.G=="function"){const t=this.ht??globalThis;let s=Le.get(t);s===void 0&&(s=new WeakMap,Le.set(t,s)),s.get(this.G)!==void 0&&this.G.call(this.ht,void 0),s.set(this.G,e),e!==void 0&&this.G.call(this.ht,e)}else this.G.value=e}get lt(){return typeof this.G=="function"?Le.get(this.ht??globalThis)?.get(this.G):this.G?.value}disconnected(){this.lt===this.ct&&this.rt(void 0)}reconnected(){this.rt(this.ct)}});class De extends gt{constructor(t){if(super(t),this.it=_,t.type!==pt.CHILD)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(t){if(t===_||t==null)return this._t=void 0,this.it=t;if(t===W)return t;if(typeof t!="string")throw Error(this.constructor.directiveName+"() called with a non-string value");if(t===this.it)return this._t;this.it=t;const s=[t];return s.raw=s,this._t={_$litType$:this.constructor.resultType,strings:s,values:[]}}}De.directiveName="unsafeHTML",De.resultType=1;const he=ut(De);const Ee={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"};const es=["svg",Ee,[["path",{d:"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48"}]]];const ts=["svg",Ee,[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z"}],["path",{d:"m21.854 2.147-10.94 10.939"}]]];const ss=["svg",Ee,[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2"}]]];const is=["svg",Ee,[["path",{d:"M18 6 6 18"}],["path",{d:"m6 6 12 12"}]]],ns={title:"XOPCBOT Gateway",brand:"XOPCBOT"},os={chat:"Chat",sessions:"Sessions",cron:"Cron Jobs",logs:"Logs",settings:"Settings",management:"Management"},as={title:"XopcBot",newSession:"New Chat",welcomeTitle:"Welcome to xopcbot",welcomeDescription:"Send a message to get started",emptyState:"No messages yet",emptyStateDescription:"Start a conversation by typing a message below",you:"You",assistant:"Assistant",tool:"Tool",thinking:"thinking...",typeMessage:"Type a message...",attachFile:"Attach file",sendMessage:"Send message",abort:"Abort",retry:"Retry",reasoning:"Reasoning",thinkingLevelNone:"None",thinkingLevel1:"Level 1",thinkingLevel2:"Level 2",thinkingLevel3:"Level 3",thinkingLevel4:"Level 4",connecting:"Connecting...",disconnected:"Disconnected",connectionError:"Connection error",reconnecting:"Reconnecting...",online:"Online",offline:"Offline"},rs={title:"Settings",save:"Save",cancel:"Cancel",close:"Close",loading:"Loading settings...",unsaved:"{{count}} unsaved",saveChanges:"Save Changes",saving:"Saving...",noSection:"No section selected",enableFeature:"Enable this feature",required:"{{field}} is required",invalidFormat:"Invalid format",unsavedChanges:"Unsaved changes",sections:{agent:"Agent",providers:"Providers",channels:"Channels",gateway:"Gateway"},descriptions:{agent:"Configure your agent settings",providers:"Configure your provider API keys",channels:"Configure messaging channels",gateway:"Configure gateway settings"},fields:{model:"Model",workspace:"Workspace",maxTokens:"Max Tokens",temperature:"Temperature",maxToolIterations:"Max Tool Iterations",openaiApiKey:"OpenAI API Key",anthropicApiKey:"Anthropic API Key",googleApiKey:"Google API Key",qwenApiKey:"Qwen API Key",kimiApiKey:"Kimi API Key",minimaxApiKey:"MiniMax API Key",deepseekApiKey:"DeepSeek API Key",grokApiKey:"Grok API Key",openrouterApiKey:"OpenRouter API Key",telegramEnabled:"Telegram",telegramToken:"Telegram Token",telegramApiRoot:"API Root (Optional)",telegramAllowFrom:"Allow From (Optional)",telegramDebug:"Debug Mode",whatsappEnabled:"WhatsApp",whatsappBridgeUrl:"Bridge URL",whatsappAllowFrom:"Allow From (Optional)",heartbeatEnabled:"Heartbeat",heartbeatIntervalMs:"Heartbeat Interval (ms)",gatewayToken:"Gateway Token"},descriptionsFields:{model:"Default AI model to use",workspace:"Working directory for agent files",maxTokens:"Maximum tokens in response",temperature:"Randomness in responses (0-2)",maxToolIterations:"Maximum tool calls per message",openaiApiKey:"API key for OpenAI models",anthropicApiKey:"API key for Claude models",googleApiKey:"API key for Gemini models",qwenApiKey:"API key for Qwen models",kimiApiKey:"API key for Kimi models",minimaxApiKey:"API key for MiniMax models",deepseekApiKey:"API key for DeepSeek models",grokApiKey:"API key for Grok models",openrouterApiKey:"API key for OpenRouter models",telegramEnabled:"Enable Telegram bot",telegramToken:"Bot API token from @BotFather",telegramApiRoot:"Custom Telegram API root URL",telegramAllowFrom:"Allowed user IDs, comma separated",telegramDebug:"Enable debug logging for Telegram",whatsappEnabled:"Enable WhatsApp bridge",whatsappBridgeUrl:"WhatsApp bridge WebSocket URL",whatsappAllowFrom:"Allowed phone numbers, comma separated",heartbeatEnabled:"Enable heartbeat monitoring",heartbeatIntervalMs:"Heartbeat check interval in milliseconds",gatewayToken:"Authentication token for gateway API access"},placeholders:{workspace:"~/.xopcbot/workspace",openaiApiKey:"sk-...",anthropicApiKey:"sk-ant-...",googleApiKey:"AIzaSy...",qwenApiKey:"sk-...",kimiApiKey:"sk-kimi-...",minimaxApiKey:"sk-cp-...",deepseekApiKey:"sk-...",openrouterApiKey:"sk-or-...",telegramToken:"1234567890:ABCdefGHIjklMNOpqrsTUVwxyz",telegramApiRoot:"https://api.telegram.org",telegramAllowFrom:"123456789, 987654321",whatsappBridgeUrl:"ws://localhost:3001",whatsappAllowFrom:"+1234567890, +0987654321",gatewayToken:"Enter your gateway authentication token"},connection:{title:"Connection",gatewayUrl:"Gateway URL",gatewayUrlDesc:"WebSocket URL for the gateway server",authToken:"Auth Token",authTokenDesc:"Optional authentication token"},appearance:{title:"Appearance",theme:"Theme",themeDesc:"Choose your preferred color scheme",themeSystem:"System",themeLight:"Light",themeDark:"Dark"},chat:{title:"Chat",enableAttachments:"Enable Attachments",enableAttachmentsDesc:"Allow file attachments in chat",showModelSelector:"Show Model Selector",showModelSelectorDesc:"Display model selection dropdown",showThinkingSelector:"Show Thinking Selector",showThinkingSelectorDesc:"Display thinking level selection"}},ls={noSession:"No session available",noAgent:"No agent set",noModel:"No model set",requestTimeout:"Request timeout",sendFailed:"Failed to send message",invalidFileType:"Invalid file type",fileTooLarge:"File too large (max {{size}})",readFileFailed:"Failed to read file"},cs={dropHere:"Drop files here",dragDrop:"Drag and drop files here",image:"Image",document:"Document",pdf:"PDF",word:"Word",excel:"Excel",powerpoint:"PowerPoint",text:"Text",code:"Code",archive:"Archive",unknown:"Unknown"},hs={settings:"Open settings"},ds={title:"Configuration",save:"Save Configuration",noResult:"No result",artifacts:"Artifacts",showArtifacts:"Show artifacts"},ps={title:"Logs",refresh:"Refresh",clear:"Clear",totalLogs:"Total Logs",pause:"Pause",autoRefresh:"Auto Refresh",level:"Level",search:"Search",searchPlaceholder:"Search logs...",time:"Time",message:"Message",module:"Module",noLogs:"No logs found",noLogsDescription:"Try adjusting your filters or check back later.",details:"Log Details"},us={title:"Sessions",newSession:"New Session",searchPlaceholder:"Search sessions...",totalSessions:"Total Sessions",activeSessions:"Active Sessions",pinnedSessions:"Pinned Sessions",archivedSessions:"Archived Sessions",noSessions:"No sessions",delete:"Delete",archive:"Archive",pin:"Pin",unpin:"Unpin",confirmDelete:"Are you sure you want to delete this session?"},gs={title:"Cron Jobs",addJob:"Add Cron Job",editJob:"Edit Job",name:"Name (optional)",namePlaceholder:"My scheduled task",schedule:"Schedule (cron expression) *",scheduleHint:"e.g., */5 * * * * (every 5 minutes), 0 9 * * * (daily at 9am)",message:"Message *",messagePlaceholder:"What should the assistant do?",create:"Create Job",runNow:"Run Now",delete:"Delete",edit:"Edit",enable:"Enable",disable:"Disable",enabled:"Enabled",disabled:"Disabled",running:"Running",lastRun:"Last Run",nextRun:"Next Run",status:"Status",history:"History",actions:"Actions",noJobs:"No cron jobs",confirmDelete:"Are you sure you want to delete this cron job?",confirmRun:"Run this cron job now?",success:"Success",failed:"Failed",scheduleLabel:"Schedule",messageLabel:"Message",confirm:"Confirm",cancel:"Cancel",total:"Total",schedulePresets:{custom:"-- Custom (enter below) --",everyMinute:"Every minute",every5Minutes:"Every 5 minutes (default)",every10Minutes:"Every 10 minutes",every15Minutes:"Every 15 minutes",every30Minutes:"Every 30 minutes",everyHour:"Every hour",every2Hours:"Every 2 hours",every4Hours:"Every 4 hours",every6Hours:"Every 6 hours",every12Hours:"Every 12 hours",everyDayMidnight:"Every day at midnight",everyDay9AM:"Every day at 9:00 AM",everyDay9PM:"Every day at 9:00 PM"},scheduleHintPreset:"Select a preset or enter custom cron expression",mode:"Mode",modeDirect:"Send message directly to the channel without AI processing",modeAgent:"Use AI agent to process the message, then send the response",modeDirectOption:"Direct (send message directly)",modeAgentOption:"AI Agent (process with AI then send)",model:"Model",noConfiguredModels:"No configured models",save:"Save",failedToLoadJobs:"Failed to load jobs",scheduleRequired:"Schedule and message are required",chatIdRequired:"Chat ID is required",failedToJob:"Failed to {{mode}} job",failedToToggleJob:"Failed to toggle job",actionFailed:"Action failed",enterManuallyOrSelect:"Enter manually or select from recent chats",noRecentChats:"No recent chats found. Enter chat ID manually (e.g., 123456789 for Telegram)",timeLabels:{lessThanMinute:"Less than a minute",minutes:"{{count}} min",hours:"{{count}} hours",overdue:"Overdue"},lastActiveLabels:{justNow:"just now",minutesAgo:"{{count}}m ago",hoursAgo:"{{count}}h ago",daysAgo:"{{count}}d ago"}},_s={save:"Save",cancel:"Cancel",confirm:"Confirm",close:"Close",loading:"Loading...",error:"Error",success:"Success",noData:"No data"},ms={app:ns,nav:os,chat:as,settings:rs,errors:ls,fileUpload:cs,shortcuts:hs,config:ds,logs:ps,sessions:us,cron:gs,common:_s},vs={title:"XOPCBOT 网关",brand:"XOPCBOT"},fs={chat:"对话",sessions:"会话",cron:"定时任务",logs:"日志",settings:"设置",management:"管理"},ys={title:"XopcBot",newSession:"新建对话",welcomeTitle:"欢迎使用 xopcbot",welcomeDescription:"发送消息开始对话",emptyState:"暂无消息",emptyStateDescription:"在下方输入消息开始对话",you:"你",assistant:"助手",tool:"工具",thinking:"思考中...",typeMessage:"输入消息...",attachFile:"附加文件",sendMessage:"发送消息",abort:"中止",retry:"重试",reasoning:"推理",thinkingLevelNone:"无",thinkingLevel1:"级别 1",thinkingLevel2:"级别 2",thinkingLevel3:"级别 3",thinkingLevel4:"级别 4",connecting:"连接中...",disconnected:"已断开",connectionError:"连接错误",reconnecting:"重新连接中...",online:"在线",offline:"离线"},ws={title:"设置",save:"保存",cancel:"取消",close:"关闭",loading:"加载设置中...",unsaved:"{{count}} 个未保存",saveChanges:"保存更改",saving:"保存中...",noSection:"未选择部分",enableFeature:"启用此功能",required:"{{field}} 为必填项",invalidFormat:"格式无效",unsavedChanges:"未保存的更改",sections:{agent:"代理",providers:"提供商",channels:"渠道",gateway:"网关"},descriptions:{agent:"配置代理设置",providers:"配置提供商 API 密钥",channels:"配置消息渠道",gateway:"配置网关设置"},fields:{model:"模型",workspace:"工作区",maxTokens:"最大 Token 数",temperature:"温度",maxToolIterations:"最大工具调用次数",openaiApiKey:"OpenAI API 密钥",anthropicApiKey:"Anthropic API 密钥",googleApiKey:"Google API 密钥",qwenApiKey:"Qwen API 密钥",kimiApiKey:"Kimi API 密钥",minimaxApiKey:"MiniMax API 密钥",deepseekApiKey:"DeepSeek API 密钥",grokApiKey:"Grok API 密钥",openrouterApiKey:"OpenRouter API 密钥",telegramEnabled:"Telegram",telegramToken:"Telegram 令牌",telegramApiRoot:"API 根地址(可选)",telegramAllowFrom:"允许来源(可选)",telegramDebug:"调试模式",whatsappEnabled:"WhatsApp",whatsappBridgeUrl:"桥接地址",whatsappAllowFrom:"允许来源(可选)",heartbeatEnabled:"心跳",heartbeatIntervalMs:"心跳间隔(毫秒)",gatewayToken:"网关令牌"},descriptionsFields:{model:"默认使用的 AI 模型",workspace:"代理文件的工作目录",maxTokens:"响应中的最大 token 数",temperature:"响应随机性(0-2)",maxToolIterations:"每条消息的最大工具调用次数",openaiApiKey:"OpenAI 模型的 API 密钥",anthropicApiKey:"Claude 模型的 API 密钥",googleApiKey:"Gemini 模型的 API 密钥",qwenApiKey:"Qwen 模型的 API 密钥",kimiApiKey:"Kimi 模型的 API 密钥",minimaxApiKey:"MiniMax 模型的 API 密钥",deepseekApiKey:"DeepSeek 模型的 API 密钥",grokApiKey:"Grok 模型的 API 密钥",openrouterApiKey:"OpenRouter 模型的 API 密钥",telegramEnabled:"启用 Telegram 机器人",telegramToken:"@BotFather 获取的机器人 API 令牌",telegramApiRoot:"自定义 Telegram API 根地址",telegramAllowFrom:"允许的用户 ID,逗号分隔",telegramDebug:"启用 Telegram 调试日志",whatsappEnabled:"启用 WhatsApp 桥接",whatsappBridgeUrl:"WhatsApp 桥接 WebSocket 地址",whatsappAllowFrom:"允许的电话号码,逗号分隔",heartbeatEnabled:"启用心跳监控",heartbeatIntervalMs:"心跳检查间隔(毫秒)",gatewayToken:"网关 API 访问认证令牌"},placeholders:{workspace:"~/.xopcbot/workspace",openaiApiKey:"sk-...",anthropicApiKey:"sk-ant-...",googleApiKey:"AIzaSy...",qwenApiKey:"sk-...",kimiApiKey:"sk-kimi-...",minimaxApiKey:"sk-cp-...",deepseekApiKey:"sk-...",openrouterApiKey:"sk-or-...",telegramToken:"1234567890:ABCdefGHIjklMNOpqrsTUVwxyz",telegramApiRoot:"https://api.telegram.org",telegramAllowFrom:"123456789, 987654321",whatsappBridgeUrl:"ws://localhost:3001",whatsappAllowFrom:"+1234567890, +0987654321",gatewayToken:"输入网关认证令牌"},connection:{title:"连接",gatewayUrl:"网关地址",gatewayUrlDesc:"网关服务器的 WebSocket 地址",authToken:"认证令牌",authTokenDesc:"可选的认证令牌"},appearance:{title:"外观",theme:"主题",themeDesc:"选择你喜欢的配色方案",themeSystem:"跟随系统",themeLight:"浅色",themeDark:"深色"},chat:{title:"对话",enableAttachments:"启用附件",enableAttachmentsDesc:"允许在对话中附加文件",showModelSelector:"显示模型选择器",showModelSelectorDesc:"显示模型选择下拉框",showThinkingSelector:"显示思考选择器",showThinkingSelectorDesc:"显示思考级别选择"}},bs={noSession:"无可用会话",noAgent:"未设置代理",noModel:"未设置模型",requestTimeout:"请求超时",sendFailed:"发送消息失败",invalidFileType:"无效的文件类型",fileTooLarge:"文件过大(最大 {{size}})",readFileFailed:"读取文件失败"},$s={dropHere:"拖放文件到此处",dragDrop:"拖放文件到此处",image:"图片",document:"文档",pdf:"PDF",word:"Word",excel:"Excel",powerpoint:"PowerPoint",text:"文本",code:"代码",archive:"压缩包",unknown:"未知"},ks={settings:"打开设置"},xs={title:"配置",save:"保存配置",noResult:"无结果",artifacts:"产物",showArtifacts:"显示产物"},Ss={title:"日志",refresh:"刷新",clear:"清空",totalLogs:"总日志数",pause:"暂停",autoRefresh:"自动刷新",level:"级别",search:"搜索",searchPlaceholder:"搜索日志...",time:"时间",message:"消息",module:"模块",noLogs:"暂无日志",noLogsDescription:"尝试调整筛选条件或稍后再查看。",details:"日志详情"},As={title:"会话",newSession:"新建会话",searchPlaceholder:"搜索会话...",totalSessions:"总会话数",activeSessions:"活跃会话",pinnedSessions:"固定会话",archivedSessions:"归档会话",noSessions:"暂无会话",delete:"删除",archive:"归档",pin:"固定",unpin:"取消固定",confirmDelete:"确定要删除此会话吗?"},Cs={title:"定时任务",addJob:"添加定时任务",editJob:"编辑任务",name:"名称(可选)",namePlaceholder:"我的定时任务",schedule:"计划表达式 *",scheduleHint:"例如:*/5 * * * *(每5分钟),0 9 * * *(每天9点)",message:"消息 *",messagePlaceholder:"助手应该做什么?",create:"创建任务",runNow:"立即执行",delete:"删除",edit:"编辑",enable:"启用",disable:"禁用",enabled:"已启用",disabled:"已禁用",running:"运行中",lastRun:"上次执行",nextRun:"下次执行",status:"状态",history:"历史记录",actions:"操作",noJobs:"暂无定时任务",confirmDelete:"确定要删除此定时任务吗?",confirmRun:"立即执行此定时任务?",success:"成功",failed:"失败",scheduleLabel:"计划",messageLabel:"消息",confirm:"确认",cancel:"取消",total:"总计",schedulePresets:{custom:"-- 自定义(在下方输入) --",everyMinute:"每分钟",every5Minutes:"每 5 分钟(默认)",every10Minutes:"每 10 分钟",every15Minutes:"每 15 分钟",every30Minutes:"每 30 分钟",everyHour:"每小时",every2Hours:"每 2 小时",every4Hours:"每 4 小时",every6Hours:"每 6 小时",every12Hours:"每 12 小时",everyDayMidnight:"每天午夜",everyDay9AM:"每天早上 9 点",everyDay9PM:"每天晚上 9 点"},scheduleHintPreset:"选择预设或输入自定义 cron 表达式",mode:"模式",modeDirect:"直接发送消息到渠道,不经过 AI 处理",modeAgent:"使用 AI 代理处理消息,然后发送回复",modeDirectOption:"直接发送(直接发送到渠道)",modeAgentOption:"AI 代理(经过 AI 处理后发送)",model:"模型",noConfiguredModels:"未配置模型",save:"保存",failedToLoadJobs:"加载任务失败",scheduleRequired:"计划表达式和消息为必填项",chatIdRequired:"Chat ID 为必填项",failedToJob:"{{mode}} 任务失败",failedToToggleJob:"切换任务状态失败",actionFailed:"操作失败",enterManuallyOrSelect:"手动输入或从最近聊天中选择",noRecentChats:"未找到最近聊天。请手动输入 chat ID(例如:Telegram 为 123456789)",timeLabels:{lessThanMinute:"不到 1 分钟",minutes:"{{count}} 分钟",hours:"{{count}} 小时",overdue:"已过期"},lastActiveLabels:{justNow:"刚刚",minutesAgo:"{{count}} 分钟前",hoursAgo:"{{count}} 小时前",daysAgo:"{{count}} 天前"}},Ts={save:"保存",cancel:"取消",confirm:"确认",close:"关闭",loading:"加载中...",error:"错误",success:"成功",noData:"暂无数据"},Ms={app:vs,nav:fs,chat:ys,settings:ws,errors:bs,fileUpload:$s,shortcuts:ks,config:xs,logs:Ss,sessions:As,cron:Cs,common:Ts},mt={en:ms,zh:Ms},K=new Map;K.set("en",mt.en);K.set("zh",mt.zh);let J="en";function r(e,t){const s=K.get(J);if(!s)return e;const i=e.split(".");let n=s;for(const a of i)if(n&&typeof n=="object"&&a in n)n=n[a];else{const l=K.get("en");if(l&&J!=="en"){let h=l;for(const p of i)if(h&&typeof h=="object"&&p in h)h=h[p];else return e;n=h}else return e}return typeof n!="string"?e:t?n.replace(/\{\{(\w+)\}\}/g,(a,l)=>{const h=t[l];return h!==void 0?String(h):`{{${l}}}`}):n}async function Es(e){if(K.has(e)){J=e;return}try{const t=await fetch(`/src/i18n/${e}.json`);if(!t.ok)throw new Error(`Failed to load ${e} translations`);const s=await t.json();K.set(e,s),J=e,window.dispatchEvent(new CustomEvent("languagechange",{detail:{language:e}}))}catch(t){console.error(`Failed to load ${e} translations:`,t),e!=="en"&&K.has("en")&&(J="en")}}function nt(e){K.has(e)?(J=e,window.dispatchEvent(new CustomEvent("languagechange",{detail:{language:e}}))):Es(e)}function Ps(e="en"){J=e}const Fs={"Type a message...":"chat.typeMessage","Attach file":"chat.attachFile","Send message":"chat.sendMessage",Abort:"chat.abort","No session available":"errors.noSession","No agent set":"errors.noAgent",Configuration:"config.title",Cancel:"settings.cancel",Save:"settings.save","No result":"config.noResult",Artifacts:"config.artifacts","Show artifacts":"config.showArtifacts"};function ie(e){const t=Fs[e];return r(t||e)}var Ls=Object.defineProperty,Ds=Object.getOwnPropertyDescriptor,M=(e,t,s,i)=>{for(var n=i>1?void 0:i?Ds(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Ls(t,s,n),n};function de(e,t=""){if(!e||!Array.isArray(e))return"";const[s,i,n]=e,a=Object.entries(i||{}).map(([p,g])=>`${p}="${g}"`).join(" "),l=Array.isArray(n)?n.map(p=>{if(Array.isArray(p)){const[g,S]=p,f=Object.entries(S||{}).map(([F,I])=>`${F}="${I}"`).join(" ");return`<${g} ${f} />`}return""}).join(""):"";return`<svg ${t?`${a} class="${t}"`:a}>${l}</svg>`}let T=class extends y{constructor(){super(...arguments),this.value="",this.attachments=[],this.isStreaming=!1,this.showAttachmentButton=!0,this.showModelSelector=!0,this._isComposing=!1,this._isDragging=!1,this._processingFiles=!1,this._isSending=!1,this.textareaRef=st(),this.fileInputRef=st(),this.maxFileSize=20*1024*1024,this.acceptedTypes="image/*,application/pdf,.docx,.pptx,.xlsx,.xls,.txt,.md,.json,.xml,.html,.css,.js,.ts,.jsx,.tsx,.yml,.yaml,.zip",this._handleDocumentDragOver=e=>{e.dataTransfer?.types.includes("Files")&&(e.preventDefault(),this._isDragging=!0)},this._handleDocumentDragLeave=e=>{e.relatedTarget===null&&(this._isDragging=!1)},this._handleDocumentDrop=async e=>{e.preventDefault(),this._isDragging=!1;const t=e.dataTransfer?.files;t&&t.length>0&&await this._processFiles(Array.from(t))},this._handleInput=e=>{const t=e.target;this.value=t.value,this._adjustTextareaHeight()},this._handleKeydown=e=>{e.key==="Enter"&&!e.shiftKey&&!this._isComposing&&(e.preventDefault(),this._send())},this._handlePaste=async e=>{const t=e.clipboardData?.items;if(!t)return;const s=[];for(const i of Array.from(t))if(i.type.startsWith("image/")){const n=i.getAsFile();n&&s.push(n)}s.length>0&&(e.preventDefault(),await this._processFiles(s))},this._handleFileInputChange=async e=>{const t=e.target,s=t.files;s&&(await this._processFiles(Array.from(s)),t.value="")}}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),document.addEventListener("dragover",this._handleDocumentDragOver),document.addEventListener("drop",this._handleDocumentDrop),document.addEventListener("dragleave",this._handleDocumentDragLeave),document.addEventListener("click",this._handleOutsideClick)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("dragover",this._handleDocumentDragOver),document.removeEventListener("drop",this._handleDocumentDrop),document.removeEventListener("dragleave",this._handleDocumentDragLeave),document.removeEventListener("click",this._handleOutsideClick)}render(){return o`
|
|
4
4
|
<div class="editor-container">
|
|
5
5
|
${this.attachments.length>0?this._renderAttachments():""}
|
|
6
6
|
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
${this.showAttachmentButton?this._renderAttachmentButton():""}
|
|
9
9
|
|
|
10
10
|
<textarea
|
|
11
|
-
${
|
|
11
|
+
${it(this.textareaRef)}
|
|
12
12
|
class="text-input"
|
|
13
|
-
placeholder=${
|
|
13
|
+
placeholder=${ie("Type a message...")}
|
|
14
14
|
.value=${this.value}
|
|
15
15
|
@input=${this._handleInput}
|
|
16
16
|
@keydown=${this._handleKeydown}
|
|
@@ -35,23 +35,23 @@
|
|
|
35
35
|
${e.mimeType.startsWith("image/")?o`
|
|
36
36
|
<img src="${e.content}" alt="${e.name}" />
|
|
37
37
|
`:o`
|
|
38
|
-
${
|
|
38
|
+
${he(de(FileText,"w-4 h-4"))}
|
|
39
39
|
`}
|
|
40
40
|
</div>
|
|
41
41
|
<span class="attachment-name">${e.name}</span>
|
|
42
42
|
<button type="button" class="attachment-remove" @click=${()=>this._removeAttachment(t)}>
|
|
43
|
-
${
|
|
43
|
+
${he(de(is,"w-3 h-3"))}
|
|
44
44
|
</button>
|
|
45
45
|
</div>
|
|
46
46
|
`)}
|
|
47
47
|
</div>
|
|
48
48
|
`}_renderAttachmentButton(){return o`
|
|
49
|
-
<button type="button" class="attach-btn" @click=${()=>this._triggerFileSelect("all")} title=${
|
|
50
|
-
${
|
|
49
|
+
<button type="button" class="attach-btn" @click=${()=>this._triggerFileSelect("all")} title=${ie("Attach file")}>
|
|
50
|
+
${he(de(es,"w-4 h-4"))}
|
|
51
51
|
</button>
|
|
52
52
|
|
|
53
53
|
<input
|
|
54
|
-
${
|
|
54
|
+
${it(this.fileInputRef)}
|
|
55
55
|
type="file"
|
|
56
56
|
multiple
|
|
57
57
|
accept=${this.acceptedTypes}
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
@change=${this._handleFileInputChange}
|
|
60
60
|
/>
|
|
61
61
|
`}_renderSendButton(){const e=this.value.trim()||this.attachments.length>0;return this.isStreaming?o`
|
|
62
|
-
<button type="button" class="stop-btn" @click=${()=>this.onAbort?.()} title=${
|
|
63
|
-
${
|
|
62
|
+
<button type="button" class="stop-btn" @click=${()=>this.onAbort?.()} title=${ie("Abort")}>
|
|
63
|
+
${he(de(ss,"w-4 h-4"))}
|
|
64
64
|
</button>
|
|
65
65
|
`:o`
|
|
66
66
|
<button
|
|
@@ -68,15 +68,15 @@
|
|
|
68
68
|
class="send-btn ${e?"active":""}"
|
|
69
69
|
?disabled=${!e}
|
|
70
70
|
@click=${this._send}
|
|
71
|
-
title=${
|
|
71
|
+
title=${ie("Send message")}
|
|
72
72
|
>
|
|
73
|
-
${
|
|
73
|
+
${he(de(ts,"w-4 h-4"))}
|
|
74
74
|
</button>
|
|
75
75
|
`}_renderDropOverlay(){return o`
|
|
76
76
|
<div class="drop-overlay">
|
|
77
77
|
<span>Drop files here to attach</span>
|
|
78
78
|
</div>
|
|
79
|
-
`}_triggerFileSelect(e){let t=this.fileInputRef.value;if(t||(t=this.querySelector('input[type="file"]')),!t){console.warn("File input not found");return}e==="image"?t.accept="image/*":e==="document"?t.accept=".pdf,.docx,.pptx,.xlsx,.xls,.txt,.md,.json,.xml,.html,.css,.js,.ts,.jsx,.tsx,.yml,.yaml,.zip":t.accept=this.acceptedTypes,t.click()}_adjustTextareaHeight(){const e=this.textareaRef.value;e&&(e.style.height="auto",e.style.height=Math.min(e.scrollHeight,200)+"px")}_send(){if(this._isSending||this.isStreaming||!this.value.trim()&&this.attachments.length===0)return;this._isSending=!0;const e=[...this.attachments];this.onSend?.(this.value,e),this.value="",this.attachments=[],requestAnimationFrame(()=>{this._adjustTextareaHeight(),setTimeout(()=>{this._isSending=!1},500)})}async _processFiles(e){this._processingFiles=!0;try{for(const t of e){if(t.size>this.maxFileSize){console.warn(`File ${t.name} exceeds max size of ${this.maxFileSize} bytes`);continue}const s=await this._loadAttachment(t);this.attachments=[...this.attachments,s]}}finally{this._processingFiles=!1}}async _loadAttachment(e){const t=await this._readFileAsBase64(e),s=e.type.startsWith("image/");return{id:crypto.randomUUID(),name:e.name,type:s?"image":"document",mimeType:e.type,size:e.size,content:t}}_readFileAsBase64(e){return new Promise((t,s)=>{const i=new FileReader;i.onload=()=>t(i.result),i.onerror=()=>s(i.error),i.readAsDataURL(e)})}_removeAttachment(e){this.attachments=this.attachments.filter((t,s)=>s!==e)}_formatFileSize(e){const t=["B","KB","MB","GB"];let s=0,i=e;for(;i>=1024&&s<t.length-1;)i/=1024,s++;return`${i.toFixed(1)} ${t[s]}`}};
|
|
79
|
+
`}_triggerFileSelect(e){let t=this.fileInputRef.value;if(t||(t=this.querySelector('input[type="file"]')),!t){console.warn("File input not found");return}e==="image"?t.accept="image/*":e==="document"?t.accept=".pdf,.docx,.pptx,.xlsx,.xls,.txt,.md,.json,.xml,.html,.css,.js,.ts,.jsx,.tsx,.yml,.yaml,.zip":t.accept=this.acceptedTypes,t.click()}_adjustTextareaHeight(){const e=this.textareaRef.value;e&&(e.style.height="auto",e.style.height=Math.min(e.scrollHeight,200)+"px")}_send(){if(this._isSending||this.isStreaming||!this.value.trim()&&this.attachments.length===0)return;this._isSending=!0;const e=[...this.attachments];this.onSend?.(this.value,e),this.value="",this.attachments=[],requestAnimationFrame(()=>{this._adjustTextareaHeight(),setTimeout(()=>{this._isSending=!1},500)})}async _processFiles(e){this._processingFiles=!0;try{for(const t of e){if(t.size>this.maxFileSize){console.warn(`File ${t.name} exceeds max size of ${this.maxFileSize} bytes`);continue}const s=await this._loadAttachment(t);this.attachments=[...this.attachments,s]}}finally{this._processingFiles=!1}}async _loadAttachment(e){const t=await this._readFileAsBase64(e),s=e.type.startsWith("image/");return{id:crypto.randomUUID(),name:e.name,type:s?"image":"document",mimeType:e.type,size:e.size,content:t}}_readFileAsBase64(e){return new Promise((t,s)=>{const i=new FileReader;i.onload=()=>t(i.result),i.onerror=()=>s(i.error),i.readAsDataURL(e)})}_removeAttachment(e){this.attachments=this.attachments.filter((t,s)=>s!==e)}_formatFileSize(e){const t=["B","KB","MB","GB"];let s=0,i=e;for(;i>=1024&&s<t.length-1;)i/=1024,s++;return`${i.toFixed(1)} ${t[s]}`}};M([oe("textarea")],T.prototype,"textarea",2);M([u({type:String})],T.prototype,"value",2);M([u({type:Array})],T.prototype,"attachments",2);M([u({type:Boolean})],T.prototype,"isStreaming",2);M([u({type:Boolean})],T.prototype,"showAttachmentButton",2);M([u({type:Boolean})],T.prototype,"showModelSelector",2);M([u({attribute:!1})],T.prototype,"currentModel",2);M([u({attribute:!1})],T.prototype,"onSend",2);M([u({attribute:!1})],T.prototype,"onAbort",2);M([u({attribute:!1})],T.prototype,"onModelSelect",2);M([c()],T.prototype,"_isComposing",2);M([c()],T.prototype,"_isDragging",2);M([c()],T.prototype,"_processingFiles",2);M([c()],T.prototype,"_isSending",2);T=M([k("message-editor")],T);function d(e){return Ie[e]||Ie.helpCircle}const Ie={messageSquare:o`
|
|
80
80
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
81
81
|
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
82
82
|
</svg>
|
|
@@ -393,7 +393,7 @@
|
|
|
393
393
|
<circle cx="12" cy="12" r="10"></circle>
|
|
394
394
|
<line x1="4.93" y1="4.93" x2="19.07" y2="19.07"></line>
|
|
395
395
|
</svg>
|
|
396
|
-
`};function
|
|
396
|
+
`};function Is(e){return e.includes("pdf")?o`
|
|
397
397
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2">
|
|
398
398
|
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
|
399
399
|
<polyline points="14,2 14,8 20,8"/>
|
|
@@ -413,7 +413,7 @@
|
|
|
413
413
|
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
|
414
414
|
<polyline points="14,2 14,8 20,8"/>
|
|
415
415
|
</svg>
|
|
416
|
-
`:
|
|
416
|
+
`:Ie.file}var Os=Object.defineProperty,Rs=Object.getOwnPropertyDescriptor,vt=(e,t,s,i)=>{for(var n=i>1?void 0:i?Rs(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Os(t,s,n),n};let Oe=class extends y{constructor(){super(...arguments),this.attachments=[]}createRenderRoot(){return this}render(){if(!this.attachments?.length)return null;const e=this.attachments.filter(s=>s.type==="image"||s.mimeType?.startsWith("image/")),t=this.attachments.filter(s=>s.type!=="image"&&!s.mimeType?.startsWith("image/"));return o`
|
|
417
417
|
<div class="flex flex-col gap-2 mt-2">
|
|
418
418
|
${e.length>0?this._renderImageGallery(e):""}
|
|
419
419
|
${t.length>0?this._renderDocumentList(t):""}
|
|
@@ -423,7 +423,7 @@
|
|
|
423
423
|
${e.map(i=>o`
|
|
424
424
|
<img
|
|
425
425
|
src="${i.data||i.content}"
|
|
426
|
-
alt="${i.name||
|
|
426
|
+
alt="${i.name||r("fileUpload.image")}"
|
|
427
427
|
@click=${()=>this._handleImageClick(i)}
|
|
428
428
|
/>
|
|
429
429
|
`)}
|
|
@@ -432,19 +432,19 @@
|
|
|
432
432
|
<div class="flex flex-col gap-2">
|
|
433
433
|
${e.map(t=>this._renderDocumentPreview(t))}
|
|
434
434
|
</div>
|
|
435
|
-
`}_renderDocumentPreview(e){const t=e.name||
|
|
435
|
+
`}_renderDocumentPreview(e){const t=e.name||r("fileUpload.document"),s=e.size?this._formatFileSize(e.size):"";return o`
|
|
436
436
|
<div class="document-preview" @click=${()=>this._handleDocumentClick(e)}>
|
|
437
|
-
<div class="icon">${
|
|
437
|
+
<div class="icon">${Is(e.mimeType||"")}</div>
|
|
438
438
|
<div class="info">
|
|
439
439
|
<div class="name">${t}</div>
|
|
440
|
-
<div class="meta">${s||e.mimeType||
|
|
440
|
+
<div class="meta">${s||e.mimeType||r("fileUpload.unknown")}</div>
|
|
441
441
|
</div>
|
|
442
442
|
</div>
|
|
443
|
-
`}_formatFileSize(e){const t=["B","KB","MB","GB"];let s=0,i=e;for(;i>=1024&&s<t.length-1;)i/=1024,s++;return`${i.toFixed(1)} ${t[s]}`}_handleImageClick(e){this.dispatchEvent(new CustomEvent("image-click",{detail:e,bubbles:!0,composed:!0}))}_handleDocumentClick(e){this.dispatchEvent(new CustomEvent("document-click",{detail:e,bubbles:!0,composed:!0}))}};
|
|
443
|
+
`}_formatFileSize(e){const t=["B","KB","MB","GB"];let s=0,i=e;for(;i>=1024&&s<t.length-1;)i/=1024,s++;return`${i.toFixed(1)} ${t[s]}`}_handleImageClick(e){this.dispatchEvent(new CustomEvent("image-click",{detail:e,bubbles:!0,composed:!0}))}_handleDocumentClick(e){this.dispatchEvent(new CustomEvent("document-click",{detail:e,bubbles:!0,composed:!0}))}};vt([u({attribute:!1})],Oe.prototype,"attachments",2);Oe=vt([k("attachment-renderer")],Oe);var Bs=Object.defineProperty,Ks=Object.getOwnPropertyDescriptor,ft=(e,t,s,i)=>{for(var n=i>1?void 0:i?Ks(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Bs(t,s,n),n};let Re=class extends y{createRenderRoot(){return this}render(){if(!this.usage)return null;const e=[];return this.usage.totalTokens!==void 0?e.push(`${this.usage.totalTokens} tokens`):this.usage.inputTokens!==void 0&&this.usage.outputTokens!==void 0&&e.push(`${this.usage.inputTokens+this.usage.outputTokens} tokens`),this.usage.cost!==void 0&&this.usage.cost>0&&e.push(`$${this.usage.cost.toFixed(4)}`),e.length===0?null:o`
|
|
444
444
|
<span class="usage-badge">
|
|
445
445
|
${e.join(" · ")}
|
|
446
446
|
</span>
|
|
447
|
-
`}};
|
|
447
|
+
`}};ft([u({attribute:!1})],Re.prototype,"usage",2);Re=ft([k("usage-badge")],Re);var js=Object.defineProperty,Us=Object.getOwnPropertyDescriptor,Ne=(e,t,s,i)=>{for(var n=i>1?void 0:i?Us(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&js(t,s,n),n};let Ae=class extends y{constructor(){super(...arguments),this.isStreaming=!1}createRenderRoot(){return this}render(){const e=this.message.role==="user"||this.message.role==="user-with-attachments",t=this.message.role==="assistant";this.message.role==="tool"||this.message.role;const s=r(e?"chat.you":t?"chat.assistant":"chat.tool"),i=s.charAt(0);return o`
|
|
448
448
|
<div class="message-item ${e?"flex-row-reverse":""}">
|
|
449
449
|
<div class="avatar ${e?"user":t?"assistant":"tool"}">
|
|
450
450
|
${i}
|
|
@@ -455,7 +455,7 @@
|
|
|
455
455
|
<span class="font-medium">${s}</span>
|
|
456
456
|
<span>·</span>
|
|
457
457
|
<span>${this._formatTime(this.message.timestamp)}</span>
|
|
458
|
-
${this.isStreaming?o`<span class="text-primary animate-pulse">${
|
|
458
|
+
${this.isStreaming?o`<span class="text-primary animate-pulse">${r("chat.thinking")}</span>`:""}
|
|
459
459
|
</div>
|
|
460
460
|
|
|
461
461
|
<div class="message-bubble ${e?"bg-primary-light":"bg-secondary"}">
|
|
@@ -488,7 +488,7 @@
|
|
|
488
488
|
<div class="tool-call-result">${JSON.stringify(e.content)}</div>
|
|
489
489
|
`:""}
|
|
490
490
|
</div>
|
|
491
|
-
`}_formatTime(e){return e?new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}):""}};
|
|
491
|
+
`}_formatTime(e){return e?new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}):""}};Ne([u({attribute:!1})],Ae.prototype,"message",2);Ne([u({type:Boolean})],Ae.prototype,"isStreaming",2);Ae=Ne([k("message-bubble")],Ae);var Hs=Object.defineProperty,Ns=Object.getOwnPropertyDescriptor,Pe=(e,t,s,i)=>{for(var n=i>1?void 0:i?Ns(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Hs(t,s,n),n};let fe=class extends y{constructor(){super(...arguments),this.messages=[],this.isStreaming=!1,this.useVirtualScroll=!1}createRenderRoot(){return this}render(){return!this.messages||this.messages.length===0?this._renderEmptyState():o`
|
|
492
492
|
<div class="flex flex-col gap-4 pb-4">
|
|
493
493
|
${this.messages.map((e,t)=>o`
|
|
494
494
|
<message-bubble
|
|
@@ -500,10 +500,10 @@
|
|
|
500
500
|
`}_renderEmptyState(){return o`
|
|
501
501
|
<div class="empty-state">
|
|
502
502
|
<div class="icon">💬</div>
|
|
503
|
-
<div class="title">${
|
|
504
|
-
<div class="description">${
|
|
503
|
+
<div class="title">${r("chat.emptyState")}</div>
|
|
504
|
+
<div class="description">${r("chat.emptyStateDescription")}</div>
|
|
505
505
|
</div>
|
|
506
|
-
`}scrollToBottom(){const e=this.closest(".overflow-y-auto");e&&(e.scrollTop=e.scrollHeight)}isNearBottom(e=100){const t=this.closest(".overflow-y-auto");if(!t)return!0;const{scrollTop:s,scrollHeight:i,clientHeight:n}=t;return i-s-n<e}};
|
|
506
|
+
`}scrollToBottom(){const e=this.closest(".overflow-y-auto");e&&(e.scrollTop=e.scrollHeight)}isNearBottom(e=100){const t=this.closest(".overflow-y-auto");if(!t)return!0;const{scrollTop:s,scrollHeight:i,clientHeight:n}=t;return i-s-n<e}};Pe([u({attribute:!1})],fe.prototype,"messages",2);Pe([u({type:Boolean})],fe.prototype,"isStreaming",2);Pe([u({type:Boolean})],fe.prototype,"useVirtualScroll",2);fe=Pe([k("message-list")],fe);var zs=Object.defineProperty,qs=Object.getOwnPropertyDescriptor,ae=(e,t,s,i)=>{for(var n=i>1?void 0:i?qs(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&zs(t,s,n),n};let V=class extends y{constructor(){super(...arguments),this.tools=new Map,this.pendingToolCalls=new Set,this.isStreaming=!1,this._currentMessage=null,this._isComplete=!1}createRenderRoot(){return this}setMessage(e,t){this._currentMessage=e,this._isComplete=t}render(){return this._currentMessage?o`
|
|
507
507
|
<div class="flex gap-3 message-item">
|
|
508
508
|
<div class="avatar assistant">
|
|
509
509
|
AI
|
|
@@ -536,12 +536,12 @@
|
|
|
536
536
|
</div>
|
|
537
537
|
<pre class="input">${i}</pre>
|
|
538
538
|
</div>
|
|
539
|
-
`}_escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}};
|
|
539
|
+
`}_escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}};ae([u({attribute:!1})],V.prototype,"tools",2);ae([u({attribute:!1})],V.prototype,"pendingToolCalls",2);ae([u({type:Boolean})],V.prototype,"isStreaming",2);ae([c()],V.prototype,"_currentMessage",2);ae([c()],V.prototype,"_isComplete",2);V=ae([k("streaming-message-container")],V);var Js=Object.defineProperty,Gs=Object.getOwnPropertyDescriptor,x=(e,t,s,i)=>{for(var n=i>1?void 0:i?Gs(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Js(t,s,n),n};function Ws(){return window.location.origin}function te(e){return`${Ws()}${e}`}function pe(e){const t={"Content-Type":"application/json"};return e&&(t.Authorization=`Bearer ${e}`),t}let w=class extends y{constructor(){super(...arguments),this.enableAttachments=!0,this.enableModelSelector=!0,this._connectionState="disconnected",this._error=null,this._messages=[],this._isStreaming=!1,this._streamingContent="",this._streamingMessage=null,this._reconnectCount=0,this._isAtBottom=!0,this._currentSessionKey=null,this._sessions=[],this._hasMoreMessages=!0,this._isLoadingMore=!1,this._shouldReconnect=!0,this._isSending=!1,this._lastLoadedSessionKey=null,this._handleScroll=()=>{if(!this._chatMessages)return;const{scrollTop:e,scrollHeight:t,clientHeight:s}=this._chatMessages,i=t-e-s<50;i!==this._isAtBottom&&(this._isAtBottom=i),e<100&&!this._isAtBottom&&this._hasMoreMessages&&!this._isLoadingMore&&this._loadMoreMessages()},this._handleSend=(e,t)=>{const s=t?.map(i=>({type:i.type||"file",mimeType:i.mimeType,data:i.content,name:i.name,size:i.size}));this.sendMessage(e,s)}}get _maxReconnectAttempts(){return this.config?.maxReconnectAttempts??10}get _autoReconnect(){return this.config?.autoReconnect??!0}createRenderRoot(){return this}async connectedCallback(){super.connectedCallback(),this.classList.add("chat-container"),await Ps("en")}firstUpdated(){this._chatMessages&&this._chatMessages.addEventListener("scroll",this._handleScroll),this._handleRouteChange()}updated(e){super.updated(e),e.has("config")&&this.config&&this._connectionState==="disconnected"&&this.connect(),e.has("route")&&this.route&&this._handleRouteChange()}async _handleRouteChange(){const e=this.route;if(!e)return;let t=null;switch(e.type){case"recent":this._lastLoadedSessionKey=null,await this._loadSessions();return;case"session":t=e.sessionKey;break;case"new":await this._createNewSession();return}t&&t!==this._lastLoadedSessionKey&&(await this._loadSession(t,0),this._lastLoadedSessionKey=t)}async _loadSession(e,t=0){if(this.config)try{const s=te(`/api/sessions/${encodeURIComponent(e)}?offset=${t}&limit=50`),i=pe(this.config.token),n=await fetch(s,{headers:i});if(!n.ok)throw new Error(`HTTP ${n.status}`);const l=(await n.json()).session;this._currentSessionKey=e;const h=l.messages||[],p=h.filter(g=>g.role==="user"||g.role==="assistant").map(g=>({role:g.role,content:typeof g.content=="string"?[{type:"text",text:g.content}]:g.content||[],attachments:g.attachments,timestamp:g.timestamp?new Date(g.timestamp).getTime():Date.now()}));t>0?this._messages=[...p,...this._messages]:this._messages=p,this._hasMoreMessages=h.length>=50,t===0&&this._scrollToBottom(!1),this.requestUpdate()}catch(s){console.error("[GatewayChat] Failed to load session:",s)}}async _loadMoreMessages(){if(!this._currentSessionKey||this._isLoadingMore||!this._hasMoreMessages)return;this._isLoadingMore=!0;const e=this._messages.length;try{await this._loadSession(this._currentSessionKey,e)}finally{this._isLoadingMore=!1}}disconnectedCallback(){super.disconnectedCallback(),this._shouldReconnect=!1,this.disconnect(),this._chatMessages&&this._chatMessages.removeEventListener("scroll",this._handleScroll)}_scrollToBottom(e=!0){this.updateComplete.then(()=>{this._chatMessages&&this._chatMessages.scrollTo({top:this._chatMessages.scrollHeight,behavior:e?"smooth":"auto"})})}connect(){if(!(!this.config||this._connectionState==="connecting")){this._connectionState="connecting",this._error=null,this.requestUpdate();try{const e=te("/api/events"),t=new URL(e);this.config.token&&t.searchParams.set("token",this.config.token),this._eventSource=new EventSource(t.toString()),this._eventSource.onopen=()=>{this._connectionState="connected",this._error=null,this._reconnectCount=0,this.requestUpdate(),this._lastLoadedSessionKey||this._loadSessions()},this._eventSource.addEventListener("connected",()=>{this._connectionState="connected",this._error=null,this.requestUpdate()}),this._eventSource.addEventListener("config.reload",s=>{try{const i=JSON.parse(s.data);this.dispatchEvent(new CustomEvent("config-reload",{detail:i}))}catch{}}),this._eventSource.addEventListener("channels.status",s=>{try{const i=JSON.parse(s.data);this.dispatchEvent(new CustomEvent("channels-status",{detail:i}))}catch{}}),this._eventSource.addEventListener("message.sent",s=>{try{const i=JSON.parse(s.data);this.dispatchEvent(new CustomEvent("message-sent",{detail:i}))}catch{}}),this._eventSource.onerror=()=>{this._eventSource?.readyState===EventSource.CLOSED?(this._connectionState="disconnected",this._handlePermanentDisconnect()):this._connectionState="reconnecting",this.requestUpdate()}}catch(e){console.error("[GatewayChat] Failed to create EventSource:",e),this._connectionState="error",this._error=r("errors.connectionError"),this.requestUpdate()}}}_handlePermanentDisconnect(){this._isStreaming&&(this._isStreaming=!1,this._isSending=!1,this._streamingContent="",this._streamingMessage=null),this._shouldReconnect&&this._autoReconnect&&(this._reconnectCount++,this._reconnectCount>this._maxReconnectAttempts&&(this._error=r("errors.connectionError"),this._connectionState="error"))}disconnect(){this._shouldReconnect=!1,this._eventSource?.close(),this._eventSource=void 0,this._agentAbort?.abort(),this._agentAbort=void 0,this._connectionState="disconnected"}reconnect(){this._shouldReconnect=!0,this._reconnectCount=0,this.disconnect(),setTimeout(()=>this.connect(),100)}async _loadSessions(){if(this.config)try{const e=te("/api/sessions?limit=20"),t=pe(this.config.token),s=await fetch(e,{headers:t});if(!s.ok)throw new Error(`HTTP ${s.status}`);const a=((await s.json()).items||[]).filter(h=>h.key.startsWith("gateway:")).sort((h,p)=>new Date(p.updatedAt).getTime()-new Date(h.updatedAt).getTime());this._sessions=a;const l=a.filter(h=>h.messageCount>0);if(l.length>0){const h=l[0].key;await this._loadSession(h,0),this._lastLoadedSessionKey=h,this._updateUrlWithSession(h)}else if(a.length>0){const h=a[0];this._currentSessionKey=h.key,this._messages=[],this._lastLoadedSessionKey=h.key,this._updateUrlWithSession(h.key)}else await this._createNewSession()}catch(e){console.error("[GatewayChat] Failed to load sessions:",e)}}_updateUrlWithSession(e){const t=`#/chat/${encodeURIComponent(e)}`;location.hash!==t&&history.replaceState(null,"",t)}async _createNewSession(){if(!this.config)return;const e=this._sessions.find(t=>t.messageCount===0);if(e){this._currentSessionKey=e.key,this._messages=[],this._lastLoadedSessionKey=e.key,this._updateUrlWithSession(e.key);return}try{const t=te("/api/sessions"),s={...pe(this.config.token),"Content-Type":"application/json"},i=await fetch(t,{method:"POST",headers:s,body:JSON.stringify({channel:"gateway"})});if(!i.ok)throw new Error(`HTTP ${i.status}`);const a=(await i.json()).session;this._currentSessionKey=a.key,this._messages=[],this._sessions=[{key:a.key,name:a.name,updatedAt:a.updatedAt},...this._sessions],this._currentSessionKey=a.key,this._lastLoadedSessionKey=a.key,this._updateUrlWithSession(a.key),this._scrollToBottom(),this.requestUpdate()}catch(t){console.error("[GatewayChat] Failed to create new session:",t)}}async sendMessage(e,t){if(!(this._isSending||this._isStreaming)&&!(!e.trim()&&!t?.length)&&this.config){this._isSending=!0,this._messages=[...this._messages,{role:"user",content:e?[{type:"text",text:e}]:[],attachments:t,timestamp:Date.now()}],this._scrollToBottom(),this.requestUpdate();try{this._agentAbort=new AbortController;const s=te("/api/agent"),i={...pe(this.config.token),Accept:"text/event-stream"},n=this._currentSessionKey?this._currentSessionKey.replace("gateway:",""):"default",a=await fetch(s,{method:"POST",headers:i,body:JSON.stringify({message:e,channel:"gateway",chatId:n,attachments:t}),signal:this._agentAbort.signal});if(!a.ok){const h=await a.json().catch(()=>({}));throw new Error(h.error?.message||`HTTP ${a.status}`)}if((a.headers.get("Content-Type")||"").includes("text/event-stream")&&a.body)await this._consumeSSEStream(a.body);else{const h=await a.json();h.ok&&h.payload?.content&&(this._updateStreamingMessage(h.payload.content),this._finalizeMessage())}}catch(s){if(s.name==="AbortError")return;this._error=s instanceof Error?s.message:r("errors.sendFailed"),this._isStreaming=!1,this._isSending=!1,this._streamingMessage=null,this.requestUpdate()}finally{this._agentAbort=void 0,this._isSending=!1}}}async _consumeSSEStream(e){const t=e.pipeThrough(new TextDecoderStream).getReader();let s="",i="",n="";try{for(;;){const{done:a,value:l}=await t.read();if(a)break;for(s+=l;s.includes(`
|
|
540
540
|
`);){const h=s.indexOf(`
|
|
541
|
-
`),
|
|
542
|
-
`:"")+
|
|
543
|
-
`);for(const l of
|
|
544
|
-
`:"")+l.slice(5).trim():l===""&&n&&(this._handleSSEEvent(i||"message",n),i="",n="")}n&&this._handleSSEEvent(i||"message",n)}}finally{t.releaseLock()}}_handleSSEEvent(e,t){try{const s=JSON.parse(t);switch(e){case"status":this._isStreaming=!0,this.requestUpdate();break;case"token":s.content&&this._updateStreamingMessage(s.content);break;case"error":this._error=s.content||s.error?.message||
|
|
541
|
+
`),p=s.slice(0,h);s=s.slice(h+1),p.startsWith("event:")?i=p.slice(6).trim():p.startsWith("data:")?n+=(n?`
|
|
542
|
+
`:"")+p.slice(5).trim():p===""&&n&&(this._handleSSEEvent(i||"message",n),i="",n="")}}if(s.trim()||n){if(s.trim()){const a=s.split(`
|
|
543
|
+
`);for(const l of a)l.startsWith("event:")?i=l.slice(6).trim():l.startsWith("data:")?n+=(n?`
|
|
544
|
+
`:"")+l.slice(5).trim():l===""&&n&&(this._handleSSEEvent(i||"message",n),i="",n="")}n&&this._handleSSEEvent(i||"message",n)}}finally{t.releaseLock()}}_handleSSEEvent(e,t){try{const s=JSON.parse(t);switch(e){case"status":this._isStreaming=!0,this.requestUpdate();break;case"token":s.content&&this._updateStreamingMessage(s.content);break;case"error":this._error=s.content||s.error?.message||r("errors.sendFailed"),this._isStreaming=!1,this._isSending=!1,this._streamingMessage=null,this.requestUpdate();break;case"result":this._finalizeMessage();break;default:s.content&&this._updateStreamingMessage(s.content);break}}catch{}}_updateStreamingMessage(e){if(this._streamingMessage){const t=this._streamingMessage.content.find(s=>s.type==="text");t?t.text=(t.text||"")+e:this._streamingMessage.content.push({type:"text",text:e})}else this._streamingMessage={role:"assistant",content:[{type:"text",text:e}],timestamp:Date.now()};this._isStreaming=!0,this._streamingContent=e,this.requestUpdate(),this._isAtBottom&&this._scrollToBottom()}_finalizeMessage(){this._streamingMessage&&(this._messages=[...this._messages,this._streamingMessage],this._streamingMessage=null),this._isStreaming=!1,this._streamingContent="",this._isSending=!1,this._isAtBottom&&this._scrollToBottom(),this.requestUpdate()}async request(e,t,s){if(!this.config)throw new Error("Not configured");const i=te(t),n=await fetch(i,{method:e,headers:pe(this.config.token),body:s?JSON.stringify(s):void 0});if(!n.ok){const a=await n.json().catch(()=>({error:{message:`HTTP ${n.status}`}}));throw new Error(a.error?.message||`HTTP ${n.status}`)}return n.json()}abort(){this._agentAbort?.abort(),this._agentAbort=void 0,this._isStreaming=!1,this._isSending=!1,this._streamingContent="",this._streamingMessage=null,this.requestUpdate()}get connectionState(){return this._connectionState}get messages(){return this._messages}clearMessages(){this._messages=[],this.requestUpdate()}render(){return o`
|
|
545
545
|
${this._renderStatus()}
|
|
546
546
|
${this._renderHeader()}
|
|
547
547
|
|
|
@@ -571,31 +571,31 @@
|
|
|
571
571
|
`}_renderHeader(){return o`
|
|
572
572
|
<div class="chat-header">
|
|
573
573
|
<div class="chat-header-title">
|
|
574
|
-
<span class="font-semibold">${
|
|
574
|
+
<span class="font-semibold">${r("chat.title")||"XopcBot"}</span>
|
|
575
575
|
${this._currentSessionKey?o`
|
|
576
576
|
<span class="text-xs text-muted ml-2">${this._sessions.find(e=>e.key===this._currentSessionKey)?.name||this._currentSessionKey}</span>
|
|
577
577
|
`:""}
|
|
578
578
|
</div>
|
|
579
579
|
<button class="new-session-btn" @click=${()=>this._createNewSession()}>
|
|
580
580
|
${this._renderIcon("plus")}
|
|
581
|
-
<span>${
|
|
581
|
+
<span>${r("chat.newSession")||"New Chat"}</span>
|
|
582
582
|
</button>
|
|
583
583
|
</div>
|
|
584
584
|
`}_renderStatus(){return this._connectionState==="error"&&this._error?o`
|
|
585
585
|
<div class="status-bar error">
|
|
586
586
|
${this._renderIcon("alertCircle")}
|
|
587
587
|
<span>${this._error}</span>
|
|
588
|
-
<button class="underline ml-auto" @click=${()=>this.reconnect()}>${
|
|
588
|
+
<button class="underline ml-auto" @click=${()=>this.reconnect()}>${r("chat.retry")}</button>
|
|
589
589
|
</div>
|
|
590
590
|
`:this._connectionState==="reconnecting"?o`
|
|
591
591
|
<div class="status-bar warning">
|
|
592
592
|
<div class="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
|
|
593
|
-
<span>${
|
|
593
|
+
<span>${r("chat.reconnecting")}</span>
|
|
594
594
|
</div>
|
|
595
595
|
`:this._connectionState==="connecting"?o`
|
|
596
596
|
<div class="status-bar warning">
|
|
597
597
|
<div class="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
|
|
598
|
-
<span>${
|
|
598
|
+
<span>${r("chat.connecting")}</span>
|
|
599
599
|
</div>
|
|
600
600
|
`:null}_renderIcon(e){return{alertCircle:o`
|
|
601
601
|
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
@@ -624,8 +624,8 @@
|
|
|
624
624
|
`}_renderMessages(){return!this._messages.length&&!this._isStreaming?o`
|
|
625
625
|
<div class="empty-state" style="padding-top: 30vh;">
|
|
626
626
|
<div class="icon">🤖</div>
|
|
627
|
-
<div class="title">${
|
|
628
|
-
<div class="description">${
|
|
627
|
+
<div class="title">${r("chat.welcomeTitle")}</div>
|
|
628
|
+
<div class="description">${r("chat.welcomeDescription")}</div>
|
|
629
629
|
</div>
|
|
630
630
|
`:o`
|
|
631
631
|
<div class="flex flex-col gap-4">
|
|
@@ -635,12 +635,12 @@
|
|
|
635
635
|
`}_renderMessage(e){const t=e.role==="user";return!e.content?.some(i=>i.text)&&!e.attachments?.length?null:o`
|
|
636
636
|
<div class="message-item ${t?"flex-row-reverse":""}">
|
|
637
637
|
<div class="avatar ${t?"user":"assistant"}">
|
|
638
|
-
${t?
|
|
638
|
+
${t?r("chat.you").charAt(0):"X"}
|
|
639
639
|
</div>
|
|
640
640
|
|
|
641
641
|
<div class="flex flex-col gap-1 max-w-[calc(100%-3rem)]">
|
|
642
642
|
<div class="flex items-center gap-2 text-xs text-muted ${t?"flex-row-reverse":""}">
|
|
643
|
-
<span class="font-medium">${
|
|
643
|
+
<span class="font-medium">${r(t?"chat.you":"chat.assistant")}</span>
|
|
644
644
|
<span>·</span>
|
|
645
645
|
<span>${this._formatTime(e.timestamp)}</span>
|
|
646
646
|
</div>
|
|
@@ -656,9 +656,9 @@
|
|
|
656
656
|
<div class="avatar assistant">X</div>
|
|
657
657
|
<div class="flex flex-col gap-1 max-w-[calc(100%-3rem)]">
|
|
658
658
|
<div class="flex items-center gap-2 text-xs text-muted">
|
|
659
|
-
<span class="font-medium">${
|
|
659
|
+
<span class="font-medium">${r("chat.assistant")}</span>
|
|
660
660
|
<span>·</span>
|
|
661
|
-
<span class="text-primary animate-pulse">${
|
|
661
|
+
<span class="text-primary animate-pulse">${r("chat.thinking")}</span>
|
|
662
662
|
</div>
|
|
663
663
|
<div class="message-bubble assistant">
|
|
664
664
|
<div class="markdown-content">
|
|
@@ -706,18 +706,18 @@
|
|
|
706
706
|
.onSend=${(e,t)=>this._handleSend(e,t)}
|
|
707
707
|
.onAbort=${()=>this.abort()}
|
|
708
708
|
></message-editor>
|
|
709
|
-
`}_formatTime(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}_formatFileSize(e){const t=["B","KB","MB","GB"];let s=0,i=e;for(;i>=1024&&s<t.length-1;)i/=1024,s++;return`${i.toFixed(1)} ${t[s]}`}};x([u({attribute:!1})],w.prototype,"config",2);x([u({attribute:!1})],w.prototype,"route",2);x([u({type:Boolean})],w.prototype,"enableAttachments",2);x([u({type:Boolean})],w.prototype,"enableModelSelector",2);x([
|
|
709
|
+
`}_formatTime(e){return new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}_formatFileSize(e){const t=["B","KB","MB","GB"];let s=0,i=e;for(;i>=1024&&s<t.length-1;)i/=1024,s++;return`${i.toFixed(1)} ${t[s]}`}};x([u({attribute:!1})],w.prototype,"config",2);x([u({attribute:!1})],w.prototype,"route",2);x([u({type:Boolean})],w.prototype,"enableAttachments",2);x([u({type:Boolean})],w.prototype,"enableModelSelector",2);x([oe("message-editor")],w.prototype,"_messageEditor",2);x([oe(".chat-messages")],w.prototype,"_chatMessages",2);x([c()],w.prototype,"_connectionState",2);x([c()],w.prototype,"_error",2);x([c()],w.prototype,"_messages",2);x([c()],w.prototype,"_isStreaming",2);x([c()],w.prototype,"_streamingContent",2);x([c()],w.prototype,"_streamingMessage",2);x([c()],w.prototype,"_reconnectCount",2);x([c()],w.prototype,"_isAtBottom",2);x([c()],w.prototype,"_currentSessionKey",2);x([c()],w.prototype,"_sessions",2);x([c()],w.prototype,"_hasMoreMessages",2);x([c()],w.prototype,"_isLoadingMore",2);w=x([k("xopcbot-gateway-chat")],w);var Vs=Object.defineProperty,Qs=Object.getOwnPropertyDescriptor,ze=(e,t,s,i)=>{for(var n=i>1?void 0:i?Qs(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Vs(t,s,n),n};let Ce=class extends y{constructor(){super(...arguments),this.selected=!1}createRenderRoot(){return this}_emit(e){this.dispatchEvent(new CustomEvent("session-action",{detail:{action:e,key:this.session.key},bubbles:!0,composed:!0}))}_formatDate(e){const t=new Date(e),i=Math.floor((new Date().getTime()-t.getTime())/(1e3*60*60*24));return i===0?t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}):i===1?"Yesterday":i<7?t.toLocaleDateString([],{weekday:"short"}):t.toLocaleDateString([],{month:"short",day:"numeric"})}_getChannelIcon(e){return{telegram:"send",whatsapp:"phone",gateway:"globe",cli:"terminal"}[e]||"messageSquare"}_getStatusBadge(){switch(this.session.status){case"archived":return"bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400";case"pinned":return"bg-blue-100 text-blue-600 dark:bg-blue-900/30 dark:text-blue-400";default:return"bg-green-100 text-green-600 dark:bg-green-900/30 dark:text-green-400"}}render(){const e=this.session.name||this.session.key,t=this.session.status==="archived",s=this.session.status==="pinned";return o`
|
|
710
710
|
<div
|
|
711
711
|
class="session-card ${this.selected?"session-card--selected":""} ${t?"session-card--archived":""}"
|
|
712
712
|
@click=${()=>this._emit("click")}
|
|
713
713
|
>
|
|
714
714
|
<div class="session-card__header">
|
|
715
715
|
<div class="session-card__channel">
|
|
716
|
-
<span class="channel-icon">${
|
|
716
|
+
<span class="channel-icon">${d(this._getChannelIcon(this.session.sourceChannel))}</span>
|
|
717
717
|
<span class="channel-name">${this.session.sourceChannel}</span>
|
|
718
718
|
</div>
|
|
719
719
|
<div class="session-card__meta">
|
|
720
|
-
${s?o`<span class="pin-badge" title="Pinned">${
|
|
720
|
+
${s?o`<span class="pin-badge" title="Pinned">${d("pin")}</span>`:""}
|
|
721
721
|
<span class="date">${this._formatDate(this.session.updatedAt)}</span>
|
|
722
722
|
</div>
|
|
723
723
|
</div>
|
|
@@ -728,11 +728,11 @@
|
|
|
728
728
|
|
|
729
729
|
<div class="session-card__stats">
|
|
730
730
|
<span class="stat">
|
|
731
|
-
${
|
|
731
|
+
${d("messageSquare")}
|
|
732
732
|
${this.session.messageCount}
|
|
733
733
|
</span>
|
|
734
734
|
<span class="stat">
|
|
735
|
-
${
|
|
735
|
+
${d("zap")}
|
|
736
736
|
${this._formatTokens(this.session.estimatedTokens)}
|
|
737
737
|
</span>
|
|
738
738
|
</div>
|
|
@@ -754,13 +754,13 @@
|
|
|
754
754
|
class="btn-icon btn-icon--success"
|
|
755
755
|
title="Unarchive"
|
|
756
756
|
@click=${()=>this._emit("unarchive")}
|
|
757
|
-
>${
|
|
757
|
+
>${d("archiveRestore")}</button>
|
|
758
758
|
`:o`
|
|
759
759
|
<button
|
|
760
760
|
class="btn-icon"
|
|
761
761
|
title="Archive"
|
|
762
762
|
@click=${()=>this._emit("archive")}
|
|
763
|
-
>${
|
|
763
|
+
>${d("archive")}</button>
|
|
764
764
|
`}
|
|
765
765
|
|
|
766
766
|
${s?o`
|
|
@@ -768,29 +768,29 @@
|
|
|
768
768
|
class="btn-icon btn-icon--primary"
|
|
769
769
|
title="Unpin"
|
|
770
770
|
@click=${()=>this._emit("unpin")}
|
|
771
|
-
>${
|
|
771
|
+
>${d("pinOff")}</button>
|
|
772
772
|
`:o`
|
|
773
773
|
<button
|
|
774
774
|
class="btn-icon"
|
|
775
775
|
title="Pin"
|
|
776
776
|
@click=${()=>this._emit("pin")}
|
|
777
|
-
>${
|
|
777
|
+
>${d("pin")}</button>
|
|
778
778
|
`}
|
|
779
779
|
|
|
780
780
|
<button
|
|
781
781
|
class="btn-icon"
|
|
782
782
|
title="Export"
|
|
783
783
|
@click=${()=>this._emit("export")}
|
|
784
|
-
>${
|
|
784
|
+
>${d("download")}</button>
|
|
785
785
|
|
|
786
786
|
<button
|
|
787
787
|
class="btn-icon btn-icon--danger"
|
|
788
788
|
title="Delete"
|
|
789
789
|
@click=${()=>this._emit("delete")}
|
|
790
|
-
>${
|
|
790
|
+
>${d("trash")}</button>
|
|
791
791
|
</div>
|
|
792
792
|
</div>
|
|
793
|
-
`}_formatTokens(e){return e>=1e3?(e/1e3).toFixed(1)+"k":e.toString()}};
|
|
793
|
+
`}_formatTokens(e){return e>=1e3?(e/1e3).toFixed(1)+"k":e.toString()}};ze([u({attribute:!1})],Ce.prototype,"session",2);ze([u({type:Boolean})],Ce.prototype,"selected",2);Ce=ze([k("session-card")],Ce);var Xs=Object.defineProperty,Ys=Object.getOwnPropertyDescriptor,re=(e,t,s,i)=>{for(var n=i>1?void 0:i?Ys(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Xs(t,s,n),n};let Q=class extends y{constructor(){super(...arguments),this.sessions=[],this.loading=!1,this.hasMore=!1,this.selectedKey=null,this._viewMode="grid"}createRenderRoot(){return this}_emit(e,t){this.dispatchEvent(new CustomEvent("list-action",{detail:{action:e,key:t},bubbles:!0,composed:!0}))}_handleCardAction(e){const{action:t,key:s}=e.detail;t==="click"?this._emit("select",s):this._emit(t,s)}_loadMore(){this.dispatchEvent(new CustomEvent("load-more",{bubbles:!0,composed:!0}))}render(){return this.loading&&this.sessions.length===0?this._renderLoading():this.sessions.length===0?this._renderEmpty():o`
|
|
794
794
|
<div class="session-list">
|
|
795
795
|
${this._renderToolbar()}
|
|
796
796
|
|
|
@@ -807,7 +807,7 @@
|
|
|
807
807
|
${this.hasMore?o`
|
|
808
808
|
<div class="session-list__load-more">
|
|
809
809
|
<button class="btn btn--secondary" @click=${this._loadMore}>
|
|
810
|
-
${
|
|
810
|
+
${d("chevronDown")}
|
|
811
811
|
Load More
|
|
812
812
|
</button>
|
|
813
813
|
</div>
|
|
@@ -830,12 +830,12 @@
|
|
|
830
830
|
class="btn-icon ${this._viewMode==="grid"?"btn-icon--active":""}"
|
|
831
831
|
title="Grid view"
|
|
832
832
|
@click=${()=>this._viewMode="grid"}
|
|
833
|
-
>${
|
|
833
|
+
>${d("grid")}</button>
|
|
834
834
|
<button
|
|
835
835
|
class="btn-icon ${this._viewMode==="list"?"btn-icon--active":""}"
|
|
836
836
|
title="List view"
|
|
837
837
|
@click=${()=>this._viewMode="list"}
|
|
838
|
-
>${
|
|
838
|
+
>${d("list")}</button>
|
|
839
839
|
</div>
|
|
840
840
|
</div>
|
|
841
841
|
`}_renderLoading(){return o`
|
|
@@ -853,14 +853,14 @@
|
|
|
853
853
|
`}_renderEmpty(){return o`
|
|
854
854
|
<div class="session-list session-list--empty">
|
|
855
855
|
<div class="empty-state">
|
|
856
|
-
<div class="empty-state__icon">${
|
|
856
|
+
<div class="empty-state__icon">${d("folderOpen")}</div>
|
|
857
857
|
<div class="empty-state__title">No sessions found</div>
|
|
858
858
|
<div class="empty-state__description">
|
|
859
859
|
Start a conversation to create your first session.
|
|
860
860
|
</div>
|
|
861
861
|
</div>
|
|
862
862
|
</div>
|
|
863
|
-
`}};
|
|
863
|
+
`}};re([u({attribute:!1})],Q.prototype,"sessions",2);re([u({type:Boolean})],Q.prototype,"loading",2);re([u({type:Boolean})],Q.prototype,"hasMore",2);re([u({type:String})],Q.prototype,"selectedKey",2);re([c()],Q.prototype,"_viewMode",2);Q=re([k("session-list")],Q);var Zs=Object.defineProperty,ei=Object.getOwnPropertyDescriptor,Y=(e,t,s,i)=>{for(var n=i>1?void 0:i?ei(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Zs(t,s,n),n};let j=class extends y{constructor(){super(...arguments),this.session=null,this.open=!1,this.loading=!1,this._searchQuery="",this._searchResults=[],this._currentResultIndex=-1}createRenderRoot(){return this}_emit(e){this.dispatchEvent(new CustomEvent("detail-action",{detail:{action:e},bubbles:!0,composed:!0}))}_handleClose(){this._emit("close")}_handleBackdropClick(e){e.target===e.currentTarget&&this._handleClose()}_handleSearch(e){const t=e.target;this._searchQuery=t.value,this._performSearch()}_performSearch(){if(!this.session||!this._searchQuery.trim()){this._searchResults=[],this._currentResultIndex=-1;return}const e=this._searchQuery.toLowerCase(),t=[];this.session.messages.forEach((s,i)=>{s.content.toLowerCase().includes(e)&&t.push(i)}),this._searchResults=t,this._currentResultIndex=t.length>0?0:-1}_navigateSearch(e){if(this._searchResults.length===0)return;e==="next"?this._currentResultIndex=(this._currentResultIndex+1)%this._searchResults.length:this._currentResultIndex=(this._currentResultIndex-1+this._searchResults.length)%this._searchResults.length;const t=this._searchResults[this._currentResultIndex],s=this.querySelector(`[data-message-index="${t}"]`);s&&s.scrollIntoView({behavior:"smooth",block:"center"})}_highlightText(e){if(!this._searchQuery.trim())return e;const t=this._searchQuery;return e.split(new RegExp(`(${t})`,"gi")).map((i,n)=>i.toLowerCase()===t.toLowerCase()?o`<mark class="search-highlight">${i}</mark>`:i)}_formatDate(e){return new Date(e).toLocaleString()}render(){return this.open?o`
|
|
864
864
|
<div class="drawer-backdrop" @click=${this._handleBackdropClick}>
|
|
865
865
|
<div class="drawer drawer--${this.open?"open":"closed"}">
|
|
866
866
|
${this._renderHeader()}
|
|
@@ -874,7 +874,7 @@
|
|
|
874
874
|
<div class="drawer-header__info">
|
|
875
875
|
<div class="drawer-header__title">
|
|
876
876
|
${this.session.name||this.session.key}
|
|
877
|
-
${t?o`<span class="pin-badge">${
|
|
877
|
+
${t?o`<span class="pin-badge">${d("pin")}</span>`:""}
|
|
878
878
|
${e?o`<span class="archive-badge">Archived</span>`:""}
|
|
879
879
|
</div>
|
|
880
880
|
<div class="drawer-header__meta">
|
|
@@ -886,13 +886,13 @@
|
|
|
886
886
|
</div>
|
|
887
887
|
</div>
|
|
888
888
|
<button class="btn-icon" @click=${this._handleClose} title="Close">
|
|
889
|
-
${
|
|
889
|
+
${d("x")}
|
|
890
890
|
</button>
|
|
891
891
|
</div>
|
|
892
892
|
`}_renderSearch(){return this.session?o`
|
|
893
893
|
<div class="drawer-search">
|
|
894
894
|
<div class="search-input-wrapper">
|
|
895
|
-
${
|
|
895
|
+
${d("search")}
|
|
896
896
|
<input
|
|
897
897
|
type="text"
|
|
898
898
|
placeholder="Search in session..."
|
|
@@ -901,7 +901,7 @@
|
|
|
901
901
|
/>
|
|
902
902
|
${this._searchQuery?o`
|
|
903
903
|
<button class="btn-icon btn-icon--sm" @click=${()=>{this._searchQuery="",this._performSearch()}}>
|
|
904
|
-
${
|
|
904
|
+
${d("x")}
|
|
905
905
|
</button>
|
|
906
906
|
`:""}
|
|
907
907
|
</div>
|
|
@@ -910,10 +910,10 @@
|
|
|
910
910
|
<div class="search-nav">
|
|
911
911
|
<span class="search-count">${this._currentResultIndex+1} / ${this._searchResults.length}</span>
|
|
912
912
|
<button class="btn-icon btn-icon--sm" @click=${()=>this._navigateSearch("prev")} title="Previous">
|
|
913
|
-
${
|
|
913
|
+
${d("chevronUp")}
|
|
914
914
|
</button>
|
|
915
915
|
<button class="btn-icon btn-icon--sm" @click=${()=>this._navigateSearch("next")} title="Next">
|
|
916
|
-
${
|
|
916
|
+
${d("chevronDown")}
|
|
917
917
|
</button>
|
|
918
918
|
</div>
|
|
919
919
|
`:""}
|
|
@@ -946,37 +946,37 @@
|
|
|
946
946
|
<div class="drawer-actions">
|
|
947
947
|
${e?o`
|
|
948
948
|
<button class="btn btn--secondary" @click=${()=>this._emit("unarchive")}>
|
|
949
|
-
${
|
|
949
|
+
${d("archiveRestore")} Unarchive
|
|
950
950
|
</button>
|
|
951
951
|
`:o`
|
|
952
952
|
<button class="btn btn--secondary" @click=${()=>this._emit("archive")}>
|
|
953
|
-
${
|
|
953
|
+
${d("archive")} Archive
|
|
954
954
|
</button>
|
|
955
955
|
`}
|
|
956
956
|
|
|
957
957
|
${t?o`
|
|
958
958
|
<button class="btn btn--secondary" @click=${()=>this._emit("unpin")}>
|
|
959
|
-
${
|
|
959
|
+
${d("pinOff")} Unpin
|
|
960
960
|
</button>
|
|
961
961
|
`:o`
|
|
962
962
|
<button class="btn btn--secondary" @click=${()=>this._emit("pin")}>
|
|
963
|
-
${
|
|
963
|
+
${d("pin")} Pin
|
|
964
964
|
</button>
|
|
965
965
|
`}
|
|
966
966
|
|
|
967
967
|
<button class="btn btn--secondary" @click=${()=>this._emit("export")}>
|
|
968
|
-
${
|
|
968
|
+
${d("download")} Export
|
|
969
969
|
</button>
|
|
970
970
|
|
|
971
971
|
<button class="btn btn--danger" @click=${()=>this._emit("delete")}>
|
|
972
|
-
${
|
|
972
|
+
${d("trash")} Delete
|
|
973
973
|
</button>
|
|
974
974
|
</div>
|
|
975
|
-
`}};
|
|
975
|
+
`}};Y([u({attribute:!1})],j.prototype,"session",2);Y([u({type:Boolean})],j.prototype,"open",2);Y([u({type:Boolean})],j.prototype,"loading",2);Y([c()],j.prototype,"_searchQuery",2);Y([c()],j.prototype,"_searchResults",2);Y([c()],j.prototype,"_currentResultIndex",2);j=Y([k("session-detail-drawer")],j);var ti=Object.defineProperty,si=Object.getOwnPropertyDescriptor,Z=(e,t,s,i)=>{for(var n=i>1?void 0:i?si(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&ti(t,s,n),n};let U=class extends y{constructor(){super(...arguments),this.open=!1,this.title="Confirm",this.message="Are you sure?",this.confirmText="Confirm",this.cancelText="Cancel",this.type="warning"}createRenderRoot(){return this}_emit(e){this.dispatchEvent(new CustomEvent("confirm",{detail:{confirmed:e},bubbles:!0,composed:!0})),this.open=!1}_handleBackdropClick(e){e.target===e.currentTarget&&this._emit(!1)}_getIcon(){switch(this.type){case"danger":return"trash";case"warning":return"alertTriangle";case"info":return"info";default:return"helpCircle"}}_getIconColor(){switch(this.type){case"danger":return"text-red-500";case"warning":return"text-amber-500";case"info":return"text-blue-500";default:return"text-gray-500"}}render(){return this.open?o`
|
|
976
976
|
<div class="modal-backdrop" @click=${this._handleBackdropClick}>
|
|
977
977
|
<div class="modal modal--${this.type}">
|
|
978
978
|
<div class="modal__icon ${this._getIconColor()}">
|
|
979
|
-
${
|
|
979
|
+
${d(this._getIcon())}
|
|
980
980
|
</div>
|
|
981
981
|
|
|
982
982
|
<div class="modal__content">
|
|
@@ -994,7 +994,7 @@
|
|
|
994
994
|
</div>
|
|
995
995
|
</div>
|
|
996
996
|
</div>
|
|
997
|
-
`:""}};
|
|
997
|
+
`:""}};Z([u({type:Boolean})],U.prototype,"open",2);Z([u({type:String})],U.prototype,"title",2);Z([u({type:String})],U.prototype,"message",2);Z([u({type:String})],U.prototype,"confirmText",2);Z([u({type:String})],U.prototype,"cancelText",2);Z([u({type:String})],U.prototype,"type",2);U=Z([k("confirm-dialog")],U);class ii{constructor(t,s){this.baseUrl=t.replace(/\/$/,""),this.token=s}async request(t,s,i){const n={"Content-Type":"application/json"};this.token&&(n.Authorization=`Bearer ${this.token}`);const a=await fetch(`${this.baseUrl}${s}`,{method:t,headers:n,body:i?JSON.stringify(i):void 0});if(!a.ok){const l=await a.json().catch(()=>({error:"Request failed"}));throw new Error(l.error||`HTTP ${a.status}`)}return a.json()}async listSessions(t){const s=new URLSearchParams;t?.status&&s.set("status",t.status),t?.search&&s.set("search",t.search),t?.limit&&s.set("limit",String(t.limit)),t?.offset&&s.set("offset",String(t.offset));const i=s.toString(),n=`/api/sessions${i?`?${i}`:""}`;return await this.request("GET",n)}async getSession(t){try{return(await this.request("GET",`/api/sessions/${t}`)).session||null}catch(s){if(s instanceof Error&&s.message.includes("404"))return null;throw s}}async deleteSession(t){return await this.request("DELETE",`/api/sessions/${t}`)}async archiveSession(t){return await this.request("POST",`/api/sessions/${t}/archive`)}async unarchiveSession(t){return await this.request("POST",`/api/sessions/${t}/unarchive`)}async pinSession(t){return await this.request("POST",`/api/sessions/${t}/pin`)}async unpinSession(t){return await this.request("POST",`/api/sessions/${t}/unpin`)}async renameSession(t,s){return await this.request("POST",`/api/sessions/${t}/rename`,{name:s})}async exportSession(t,s="json"){return(await this.request("GET",`/api/sessions/${t}/export?format=${s}`)).content}async getStats(){return await this.request("GET","/api/sessions/stats")}}var ni=Object.defineProperty,oi=Object.getOwnPropertyDescriptor,A=(e,t,s,i)=>{for(var n=i>1?void 0:i?oi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&ni(t,s,n),n};let b=class extends y{constructor(){super(...arguments),this._sessions=[],this._loading=!1,this._hasMore=!1,this._stats=null,this._searchQuery="",this._statusFilter="all",this._offset=0,this._error=null,this._detailOpen=!1,this._detailSession=null,this._detailLoading=!1,this._confirmOpen=!1,this._confirmTitle="",this._confirmMessage="",this._confirmKey=null,this._confirmAction=null,this._limit=20,this._initialized=!1,this._debouncedSearch=this._debounce(()=>{this._loadSessions(!0)},300)}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._tryInitialize()}willUpdate(e){super.willUpdate(e),e.has("config")&&this._tryInitialize()}_tryInitialize(){if(this._initialized)return;const e=window.location.origin;this._api=new ii(e,this.config?.token),this._initialized=!0,this._loadSessions(),this._loadStats()}disconnectedCallback(){super.disconnectedCallback()}async _loadSessions(e=!1){if(!this._loading){this._loading=!0,this._error=null,e&&(this._offset=0,this._sessions=[]);try{const t={limit:this._limit,offset:this._offset,sortBy:"updatedAt",sortOrder:"desc",...this._statusFilter!=="all"&&{status:this._statusFilter},...this._searchQuery&&{search:this._searchQuery}},s=await this._api.listSessions(t);e?this._sessions=s.items:this._sessions=[...this._sessions,...s.items],this._hasMore=s.hasMore,this._offset=s.offset+s.items.length}catch(t){this._error=t instanceof Error?t.message:"Failed to load sessions",console.error("[SessionManager] Load error:",t)}finally{this._loading=!1}}}async _loadStats(){try{this._stats=await this._api.getStats()}catch(e){console.error("[SessionManager] Stats error:",e)}}async _openDetail(e){this._detailOpen=!0,this._detailLoading=!0;try{const t=await this._api.getSession(e);this._detailSession=t}catch(t){console.error("[SessionManager] Load detail error:",t),this._detailOpen=!1}finally{this._detailLoading=!1}}_closeDetail(){this._detailOpen=!1,this._detailSession=null}_handleDetailAction(e){const{action:t}=e.detail,s=this._detailSession?.key;if(s)switch(t){case"close":this._closeDetail();break;case"delete":this._showConfirm(s);break;case"archive":this._archiveSession(s);break;case"unarchive":this._unarchiveSession(s);break;case"pin":this._pinSession(s);break;case"unpin":this._unpinSession(s);break;case"export":this._exportSession(s);break}}_showConfirm(e){this._confirmKey=e,this._confirmAction="delete",this._confirmTitle="Delete Session",this._confirmMessage=`Are you sure you want to delete session "${e}"?
|
|
998
998
|
|
|
999
999
|
This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.detail.confirmed||!this._confirmKey){this._confirmOpen=!1,this._confirmKey=null;return}this._deleteSession(this._confirmKey),this._confirmOpen=!1,this._confirmKey=null}async _deleteSession(e){try{await this._api.deleteSession(e),this._sessions=this._sessions.filter(t=>t.key!==e),this._detailSession?.key===e&&this._closeDetail(),await this._loadStats()}catch(t){alert("Failed to delete session: "+(t instanceof Error?t.message:String(t)))}}async _archiveSession(e){try{await this._api.archiveSession(e),this._updateSessionStatus(e,"archived"),this._detailSession?.key===e&&(this._detailSession={...this._detailSession,status:"archived"}),await this._loadStats()}catch(t){console.error("[SessionManager] Archive error:",t)}}async _unarchiveSession(e){try{await this._api.unarchiveSession(e),this._updateSessionStatus(e,"active"),this._detailSession?.key===e&&(this._detailSession={...this._detailSession,status:"active"}),await this._loadStats()}catch(t){console.error("[SessionManager] Unarchive error:",t)}}async _pinSession(e){try{await this._api.pinSession(e),this._updateSessionStatus(e,"pinned"),this._detailSession?.key===e&&(this._detailSession={...this._detailSession,status:"pinned"}),await this._loadStats()}catch(t){console.error("[SessionManager] Pin error:",t)}}async _unpinSession(e){try{await this._api.unpinSession(e),this._updateSessionStatus(e,"active"),this._detailSession?.key===e&&(this._detailSession={...this._detailSession,status:"active"}),await this._loadStats()}catch(t){console.error("[SessionManager] Unpin error:",t)}}async _exportSession(e){try{const t=await this._api.exportSession(e,"json"),s=new Blob([t],{type:"application/json"}),i=URL.createObjectURL(s),n=document.createElement("a");n.href=i,n.download=`session-${e.replace(/[^a-z0-9]/gi,"_")}.json`,document.body.appendChild(n),n.click(),document.body.removeChild(n),URL.revokeObjectURL(i)}catch(t){alert("Failed to export session: "+(t instanceof Error?t.message:String(t)))}}_updateSessionStatus(e,t){this._sessions=this._sessions.map(s=>s.key===e?{...s,status:t}:s)}_handleListAction(e){const{action:t,key:s}=e.detail;switch(t){case"select":this._openDetail(s);break;case"delete":this._showConfirm(s);break;case"archive":this._archiveSession(s);break;case"unarchive":this._unarchiveSession(s);break;case"pin":this._pinSession(s);break;case"unpin":this._unpinSession(s);break;case"export":this._exportSession(s);break}}_handleSearch(e){const t=e.target;this._searchQuery=t.value,this._debouncedSearch()}_debounce(e,t){let s;return()=>{clearTimeout(s),s=setTimeout(e,t)}}_handleStatusFilter(e){this._statusFilter=e,this._loadSessions(!0)}_handleLoadMore(){this._loadSessions()}render(){return o`
|
|
1000
1000
|
<div class="session-manager">
|
|
@@ -1030,12 +1030,12 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1030
1030
|
></confirm-dialog>
|
|
1031
1031
|
`}_renderHeader(){return o`
|
|
1032
1032
|
<div class="session-manager__header">
|
|
1033
|
-
<h1 class="page-title">${
|
|
1033
|
+
<h1 class="page-title">${d("folderOpen")} ${r("sessions.title")}</h1>
|
|
1034
1034
|
<div class="search-box">
|
|
1035
|
-
${
|
|
1035
|
+
${d("search")}
|
|
1036
1036
|
<input
|
|
1037
1037
|
type="text"
|
|
1038
|
-
placeholder="${
|
|
1038
|
+
placeholder="${r("sessions.searchPlaceholder")}"
|
|
1039
1039
|
.value=${this._searchQuery}
|
|
1040
1040
|
@input=${this._handleSearch}
|
|
1041
1041
|
/>
|
|
@@ -1048,7 +1048,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1048
1048
|
class="filter-btn ${this._statusFilter===t.key?"filter-btn--active":""}"
|
|
1049
1049
|
@click=${()=>this._handleStatusFilter(t.key)}
|
|
1050
1050
|
>
|
|
1051
|
-
${
|
|
1051
|
+
${d(t.icon)}
|
|
1052
1052
|
${t.label}
|
|
1053
1053
|
</button>
|
|
1054
1054
|
`)}
|
|
@@ -1057,34 +1057,34 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1057
1057
|
<div class="session-manager__stats">
|
|
1058
1058
|
<div class="stat-card">
|
|
1059
1059
|
<div class="stat-value">${this._stats.totalSessions}</div>
|
|
1060
|
-
<div class="stat-label">${
|
|
1060
|
+
<div class="stat-label">${r("sessions.totalSessions")}</div>
|
|
1061
1061
|
</div>
|
|
1062
1062
|
<div class="stat-card">
|
|
1063
1063
|
<div class="stat-value">${this._stats.activeSessions}</div>
|
|
1064
|
-
<div class="stat-label">${
|
|
1064
|
+
<div class="stat-label">${r("sessions.activeSessions")}</div>
|
|
1065
1065
|
</div>
|
|
1066
1066
|
<div class="stat-card">
|
|
1067
1067
|
<div class="stat-value">${this._stats.pinnedSessions}</div>
|
|
1068
|
-
<div class="stat-label">${
|
|
1068
|
+
<div class="stat-label">${r("sessions.pinnedSessions")}</div>
|
|
1069
1069
|
</div>
|
|
1070
1070
|
<div class="stat-card">
|
|
1071
1071
|
<div class="stat-value">${this._stats.archivedSessions}</div>
|
|
1072
|
-
<div class="stat-label">${
|
|
1072
|
+
<div class="stat-label">${r("sessions.archivedSessions")}</div>
|
|
1073
1073
|
</div>
|
|
1074
1074
|
</div>
|
|
1075
|
-
`:""}};A([u({attribute:!1})],b.prototype,"config",2);A([c()],b.prototype,"_sessions",2);A([c()],b.prototype,"_loading",2);A([c()],b.prototype,"_hasMore",2);A([c()],b.prototype,"_stats",2);A([c()],b.prototype,"_searchQuery",2);A([c()],b.prototype,"_statusFilter",2);A([c()],b.prototype,"_offset",2);A([c()],b.prototype,"_error",2);A([c()],b.prototype,"_detailOpen",2);A([c()],b.prototype,"_detailSession",2);A([c()],b.prototype,"_detailLoading",2);A([c()],b.prototype,"_confirmOpen",2);A([c()],b.prototype,"_confirmTitle",2);A([c()],b.prototype,"_confirmMessage",2);A([c()],b.prototype,"_confirmKey",2);A([c()],b.prototype,"_confirmAction",2);b=A([k("session-manager")],b);class
|
|
1075
|
+
`:""}};A([u({attribute:!1})],b.prototype,"config",2);A([c()],b.prototype,"_sessions",2);A([c()],b.prototype,"_loading",2);A([c()],b.prototype,"_hasMore",2);A([c()],b.prototype,"_stats",2);A([c()],b.prototype,"_searchQuery",2);A([c()],b.prototype,"_statusFilter",2);A([c()],b.prototype,"_offset",2);A([c()],b.prototype,"_error",2);A([c()],b.prototype,"_detailOpen",2);A([c()],b.prototype,"_detailSession",2);A([c()],b.prototype,"_detailLoading",2);A([c()],b.prototype,"_confirmOpen",2);A([c()],b.prototype,"_confirmTitle",2);A([c()],b.prototype,"_confirmMessage",2);A([c()],b.prototype,"_confirmKey",2);A([c()],b.prototype,"_confirmAction",2);b=A([k("session-manager")],b);class ai{constructor(t,s){this.baseUrl=t.replace(/\/$/,""),this.token=s}async request(t,s,i){const n={"Content-Type":"application/json"};this.token&&(n.Authorization=`Bearer ${this.token}`);const a=await fetch(`${this.baseUrl}${s}`,{method:t,headers:n,body:i?JSON.stringify(i):void 0});if(!a.ok){const l=await a.json().catch(()=>({error:"Request failed"}));throw new Error(l.error||`HTTP ${a.status}`)}return a.json()}async listJobs(){return(await this.request("GET","/api/cron")).jobs||[]}async getJob(t){try{return(await this.request("GET",`/api/cron/${t}`)).job||null}catch(s){if(s instanceof Error&&s.message.includes("404"))return null;throw s}}async addJob(t,s,i){return await this.request("POST","/api/cron",{schedule:t,message:s,...i})}async updateJob(t,s){return(await this.request("PATCH",`/api/cron/${t}`,s)).updated}async removeJob(t){return(await this.request("DELETE",`/api/cron/${t}`)).removed}async toggleJob(t,s){return(await this.request("POST",`/api/cron/${t}/toggle`,{enabled:s})).toggled}async runJob(t){await this.request("POST",`/api/cron/${t}/run`)}async getHistory(t,s=10){return(await this.request("GET",`/api/cron/${t}/history?limit=${s}`)).history||[]}async getMetrics(){return await this.request("GET","/api/cron/metrics")}async getChannels(){return(await this.request("GET","/api/channels/status")).payload?.channels||[]}async getModels(){return(await this.request("GET","/api/models")).payload?.models||[]}async getConfig(){return{model:((await this.request("GET","/api/config")).config||{}).agents?.defaults?.model||""}}async getSessionChatIds(t){const s=t?`?channel=${encodeURIComponent(t)}`:"";return(await this.request("GET",`/api/sessions/chat-ids${s}`)).payload?.chatIds||[]}disconnect(){}}var ri=Object.defineProperty,li=Object.getOwnPropertyDescriptor,v=(e,t,s,i)=>{for(var n=i>1?void 0:i?li(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&ri(t,s,n),n};let m=class extends y{constructor(){super(...arguments),this._jobs=[],this._metrics=null,this._channels=[],this._availableModels=[],this._defaultModel="",this._sessionChatIds=[],this._loading=!1,this._error=null,this._formOpen=!1,this._formMode="add",this._formJobId=null,this._formName="",this._formSchedule="*/5 * * * *",this._formChannel="telegram",this._formChatId="",this._formMessage="",this._formSessionTarget="main",this._formModel="",this._formSubmitting=!1,this._detailOpen=!1,this._detailJob=null,this._detailHistory=[],this._detailLoading=!1,this._confirmOpen=!1,this._confirmTitle="",this._confirmMessage="",this._confirmJobId=null,this._confirmAction=null,this._initialized=!1}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._tryInitialize()}willUpdate(e){super.willUpdate(e),e.has("config")&&this._tryInitialize()}_tryInitialize(){if(this._initialized)return;const e=window.location.origin;this._api=new ai(e,this.config?.token),this._initialized=!0,this._loadJobs(),this._loadMetrics(),this._loadChannels(),this._loadModels(),this._loadSessionChatIds()}disconnectedCallback(){super.disconnectedCallback(),this._api?.disconnect()}async _loadJobs(){if(!this._loading){this._loading=!0,this._error=null;try{this._jobs=await this._api.listJobs()}catch(e){this._error=e instanceof Error&&e.message||r("cron.failedToLoadJobs"),console.error("[CronManager] Load error:",e)}finally{this._loading=!1}}}async _loadMetrics(){try{this._metrics=await this._api.getMetrics()}catch(e){console.error("[CronManager] Metrics error:",e)}}async _loadChannels(){try{this._channels=await this._api.getChannels()}catch(e){console.error("[CronManager] Channels error:",e)}}async _loadModels(){try{this._availableModels=await this._api.getModels();const e=await this._api.getConfig();this._defaultModel=e.model||"",this._formModel=this._defaultModel,console.log("[CronManager] Loaded models:",this._availableModels.length,"default:",this._defaultModel)}catch(e){console.error("[CronManager] Models error:",e)}}async _loadSessionChatIds(){try{const e=await this._api.getSessionChatIds(this._formChannel);this._sessionChatIds=e,console.log("[CronManager] Loaded session chatIds for channel",this._formChannel,":",e.length,e)}catch(e){console.error("[CronManager] Session chatIds error:",e),this._sessionChatIds=[]}}_openForm(e){if(this._formOpen=!0,this._formMode=e?"edit":"add",this._formJobId=e?.id||null,e||this._loadSessionChatIds(),e)if(this._formName=e.name||"",this._formSchedule=e.schedule,this._formMessage=e.message,this._formSessionTarget=e.sessionTarget||"main",this._formModel=e.model||"",e.delivery)this._formChannel=e.delivery.channel||"telegram",this._formChatId=e.delivery.to||"";else{const t=e.message.split(":"),s=["telegram","whatsapp","cli","gateway"];t.length>=3&&s.includes(t[0])?(this._formChannel=t[0],this._formChatId=t[1],this._formMessage=t.slice(2).join(":")):(this._formChannel="telegram",this._formChatId="")}else this._formName="",this._formSchedule="*/5 * * * *",this._formChannel="telegram",this._formChatId="",this._formMessage="",this._formSessionTarget="main",this._formModel=this._defaultModel||(this._availableModels.length>0?this._availableModels[0].id:"")}_closeForm(){this._formOpen=!1,this._formMode="add",this._formJobId=null,this._formName="",this._formSchedule="*/5 * * * *",this._formChannel="telegram",this._formChatId="",this._formMessage="",this._formSessionTarget="main",this._formModel=""}async _submitForm(){if(!this._formSchedule||!this._formMessage){this._error=r("cron.scheduleRequired");return}if(!this._formChatId){this._error=r("cron.chatIdRequired");return}this._formSubmitting=!0,this._error=null;try{const e=this._formMessage,t={mode:"direct",channel:this._formChannel,to:this._formChatId},s=this._formSessionTarget==="isolated"?{kind:"agentTurn",message:e,model:this._formModel}:{kind:"systemEvent",text:e},i={name:this._formName||void 0,schedule:this._formSchedule,message:e,sessionTarget:this._formSessionTarget,model:this._formSessionTarget==="isolated"?this._formModel:void 0,delivery:t};this._formMode==="edit"&&this._formJobId?await this._api.updateJob(this._formJobId,i):await this._api.addJob(this._formSchedule,e,i),this._closeForm(),await this._loadJobs(),await this._loadMetrics()}catch(e){this._error=e instanceof Error?e.message||r("cron.failedToJob",{mode:this._formMode}):r("cron.failedToJob",{mode:this._formMode})}finally{this._formSubmitting=!1}}async _openDetail(e){this._detailOpen=!0,this._detailJob=e,this._detailLoading=!0;try{const t=await this._api.getJob(e.id);t&&(this._detailJob=t,this._detailHistory=await this._api.getHistory(e.id,20))}catch(t){console.error("[CronManager] Load detail error:",t)}finally{this._detailLoading=!1}}_closeDetail(){this._detailOpen=!1,this._detailJob=null,this._detailHistory=[]}async _toggleJob(e,t){try{await this._api.toggleJob(e.id,t),await this._loadJobs(),await this._loadMetrics()}catch(s){this._error=s instanceof Error&&s.message||r("cron.failedToToggleJob")}}_showRunConfirm(e){this._confirmOpen=!0,this._confirmTitle=r("cron.runNow"),this._confirmMessage=r("cron.confirmRun"),this._confirmJobId=e.id,this._confirmAction="run"}_showDeleteConfirm(e){this._confirmOpen=!0,this._confirmTitle=r("cron.delete"),this._confirmMessage=r("cron.confirmDelete"),this._confirmJobId=e.id,this._confirmAction="delete"}_closeConfirm(){this._confirmOpen=!1,this._confirmTitle="",this._confirmMessage="",this._confirmJobId=null,this._confirmAction=null}_handleConfirm(e){e.detail.confirmed?this._executeConfirmAction():this._closeConfirm()}async _executeConfirmAction(){if(!this._confirmJobId||!this._confirmAction)return;const e=this._confirmJobId,t=this._confirmAction;this._closeConfirm();try{t==="run"?(await this._api.runJob(e),await this._loadJobs(),await this._loadMetrics()):t==="delete"&&(await this._api.removeJob(e),await this._loadJobs(),await this._loadMetrics())}catch(s){this._error=s instanceof Error&&s.message||r("cron.actionFailed")}}render(){return o`
|
|
1076
1076
|
<div class="cron-manager">
|
|
1077
1077
|
${this._error?o`<div class="error-banner">${this._error}</div>`:""}
|
|
1078
1078
|
|
|
1079
1079
|
<!-- Header -->
|
|
1080
1080
|
<div class="cron-manager__header">
|
|
1081
|
-
<h1 class="page-title">${
|
|
1081
|
+
<h1 class="page-title">${d("clock")} ${r("cron.title")}</h1>
|
|
1082
1082
|
<div class="cron-manager__actions">
|
|
1083
1083
|
<button class="btn btn-secondary" @click=${this._loadJobs} ?disabled=${this._loading}>
|
|
1084
|
-
${
|
|
1084
|
+
${d("refresh")} ${r("logs.refresh")}
|
|
1085
1085
|
</button>
|
|
1086
1086
|
<button class="btn btn-primary" @click=${()=>this._openForm()}>
|
|
1087
|
-
${
|
|
1087
|
+
${d("plus")} ${r("cron.addJob")}
|
|
1088
1088
|
</button>
|
|
1089
1089
|
</div>
|
|
1090
1090
|
</div>
|
|
@@ -1094,24 +1094,24 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1094
1094
|
<div class="cron-manager__stats">
|
|
1095
1095
|
<div class="stat-card" style="text-align: center;">
|
|
1096
1096
|
<div class="stat-value">${this._metrics.totalJobs}</div>
|
|
1097
|
-
<div class="stat-label">${
|
|
1097
|
+
<div class="stat-label">${r("sessions.totalSessions")}</div>
|
|
1098
1098
|
</div>
|
|
1099
1099
|
<div class="stat-card" style="text-align: center;">
|
|
1100
1100
|
<div class="stat-value">${this._metrics.enabledJobs}</div>
|
|
1101
|
-
<div class="stat-label">${
|
|
1101
|
+
<div class="stat-label">${r("cron.enabled")}</div>
|
|
1102
1102
|
</div>
|
|
1103
1103
|
<div class="stat-card" style="text-align: center;">
|
|
1104
1104
|
<div class="stat-value">${this._metrics.runningJobs}</div>
|
|
1105
|
-
<div class="stat-label">${
|
|
1105
|
+
<div class="stat-label">${r("cron.running")}</div>
|
|
1106
1106
|
</div>
|
|
1107
1107
|
<div class="stat-card" style="text-align: center;">
|
|
1108
1108
|
<div class="stat-value" style="font-size: 0.875rem;">
|
|
1109
1109
|
${this._metrics.nextScheduledJob?this._formatNextRun(this._metrics.nextScheduledJob.runAt):"N/A"}
|
|
1110
1110
|
</div>
|
|
1111
|
-
<div class="stat-label">${
|
|
1111
|
+
<div class="stat-label">${r("cron.nextRun")}</div>
|
|
1112
1112
|
</div>
|
|
1113
1113
|
</div>
|
|
1114
|
-
`:
|
|
1114
|
+
`:_}
|
|
1115
1115
|
|
|
1116
1116
|
<!-- Job List -->
|
|
1117
1117
|
<div class="session-list">
|
|
@@ -1122,7 +1122,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1122
1122
|
`:this._jobs.length===0?o`
|
|
1123
1123
|
<div class="session-list session-list--empty">
|
|
1124
1124
|
<div class="empty-state">
|
|
1125
|
-
<div class="empty-state__icon">${
|
|
1125
|
+
<div class="empty-state__icon">${d("clock")}</div>
|
|
1126
1126
|
<div class="empty-state__title">No cron jobs yet</div>
|
|
1127
1127
|
<button class="btn btn-primary" @click=${this._openForm}>Create your first job</button>
|
|
1128
1128
|
</div>
|
|
@@ -1135,11 +1135,11 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1135
1135
|
<table class="data-table">
|
|
1136
1136
|
<thead>
|
|
1137
1137
|
<tr>
|
|
1138
|
-
<th>${
|
|
1139
|
-
<th>${
|
|
1140
|
-
<th>${
|
|
1141
|
-
<th>${
|
|
1142
|
-
<th>${
|
|
1138
|
+
<th>${r("cron.name")}</th>
|
|
1139
|
+
<th>${r("cron.scheduleLabel")}</th>
|
|
1140
|
+
<th>${r("cron.nextRun")}</th>
|
|
1141
|
+
<th>${r("cron.status")}</th>
|
|
1142
|
+
<th>${r("cron.actions")}</th>
|
|
1143
1143
|
</tr>
|
|
1144
1144
|
</thead>
|
|
1145
1145
|
<tbody>
|
|
@@ -1165,13 +1165,13 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1165
1165
|
<td style="vertical-align: middle; text-align: center;">
|
|
1166
1166
|
<div class="action-buttons">
|
|
1167
1167
|
<button class="btn btn-icon btn-secondary" title="Edit" @click=${()=>this._openForm(e)}>
|
|
1168
|
-
${
|
|
1168
|
+
${d("edit")}
|
|
1169
1169
|
</button>
|
|
1170
|
-
<button class="btn btn-icon btn-secondary" title="${
|
|
1171
|
-
${
|
|
1170
|
+
<button class="btn btn-icon btn-secondary" title="${r("cron.runNow")}" @click=${()=>this._showRunConfirm(e)}>
|
|
1171
|
+
${d("play")}
|
|
1172
1172
|
</button>
|
|
1173
|
-
<button class="btn btn-icon btn-danger" title="${
|
|
1174
|
-
${
|
|
1173
|
+
<button class="btn btn-icon btn-danger" title="${r("cron.delete")}" @click=${()=>this._showDeleteConfirm(e)}>
|
|
1174
|
+
${d("trash")}
|
|
1175
1175
|
</button>
|
|
1176
1176
|
</div>
|
|
1177
1177
|
</td>
|
|
@@ -1189,22 +1189,22 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1189
1189
|
<div class="modal-backdrop" @click=${this._closeForm}>
|
|
1190
1190
|
<div class="modal modal--form" @click=${e=>e.stopPropagation()}>
|
|
1191
1191
|
<div class="modal__header">
|
|
1192
|
-
<h2 class="modal__title">${this._formMode==="edit"?
|
|
1193
|
-
<button class="btn-icon" @click=${this._closeForm}>${
|
|
1192
|
+
<h2 class="modal__title">${this._formMode==="edit"?r("cron.editJob"):r("cron.addJob")}</h2>
|
|
1193
|
+
<button class="btn-icon" @click=${this._closeForm}>${d("x")}</button>
|
|
1194
1194
|
</div>
|
|
1195
1195
|
<div class="modal__content">
|
|
1196
1196
|
<div class="form-field">
|
|
1197
|
-
<label class="form-field__label">${
|
|
1197
|
+
<label class="form-field__label">${r("cron.name")}</label>
|
|
1198
1198
|
<input
|
|
1199
1199
|
type="text"
|
|
1200
1200
|
class="form-field__input"
|
|
1201
1201
|
.value=${this._formName??""}
|
|
1202
1202
|
@input=${e=>this._formName=e.target.value}
|
|
1203
|
-
placeholder="${
|
|
1203
|
+
placeholder="${r("cron.namePlaceholder")??"My scheduled task"}"
|
|
1204
1204
|
/>
|
|
1205
1205
|
</div>
|
|
1206
1206
|
<div class="form-field">
|
|
1207
|
-
<label class="form-field__label">${
|
|
1207
|
+
<label class="form-field__label">${r("cron.schedule")}</label>
|
|
1208
1208
|
<div style="display: flex; gap: 0.5rem; align-items: center;">
|
|
1209
1209
|
<input
|
|
1210
1210
|
type="text"
|
|
@@ -1220,43 +1220,43 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1220
1220
|
.value=${this._formSchedule??"*/5 * * * *"}
|
|
1221
1221
|
@change=${e=>{const t=e.target.value;t&&(this._formSchedule=t)}}
|
|
1222
1222
|
>
|
|
1223
|
-
<option value="">${
|
|
1224
|
-
<option value="*/1 * * * *">${
|
|
1225
|
-
<option value="*/5 * * * *">${
|
|
1226
|
-
<option value="*/10 * * * *">${
|
|
1227
|
-
<option value="*/15 * * * *">${
|
|
1228
|
-
<option value="*/30 * * * *">${
|
|
1229
|
-
<option value="0 * * * *">${
|
|
1230
|
-
<option value="0 */2 * * *">${
|
|
1231
|
-
<option value="0 */4 * * *">${
|
|
1232
|
-
<option value="0 */6 * * *">${
|
|
1233
|
-
<option value="0 */12 * * *">${
|
|
1234
|
-
<option value="0 0 * * *">${
|
|
1235
|
-
<option value="0 9 * * *">${
|
|
1236
|
-
<option value="0 21 * * *">${
|
|
1223
|
+
<option value="">${r("cron.schedulePresets.custom")}</option>
|
|
1224
|
+
<option value="*/1 * * * *">${r("cron.schedulePresets.everyMinute")}</option>
|
|
1225
|
+
<option value="*/5 * * * *">${r("cron.schedulePresets.every5Minutes")}</option>
|
|
1226
|
+
<option value="*/10 * * * *">${r("cron.schedulePresets.every10Minutes")}</option>
|
|
1227
|
+
<option value="*/15 * * * *">${r("cron.schedulePresets.every15Minutes")}</option>
|
|
1228
|
+
<option value="*/30 * * * *">${r("cron.schedulePresets.every30Minutes")}</option>
|
|
1229
|
+
<option value="0 * * * *">${r("cron.schedulePresets.everyHour")}</option>
|
|
1230
|
+
<option value="0 */2 * * *">${r("cron.schedulePresets.every2Hours")}</option>
|
|
1231
|
+
<option value="0 */4 * * *">${r("cron.schedulePresets.every4Hours")}</option>
|
|
1232
|
+
<option value="0 */6 * * *">${r("cron.schedulePresets.every6Hours")}</option>
|
|
1233
|
+
<option value="0 */12 * * *">${r("cron.schedulePresets.every12Hours")}</option>
|
|
1234
|
+
<option value="0 0 * * *">${r("cron.schedulePresets.everyDayMidnight")}</option>
|
|
1235
|
+
<option value="0 9 * * *">${r("cron.schedulePresets.everyDay9AM")}</option>
|
|
1236
|
+
<option value="0 21 * * *">${r("cron.schedulePresets.everyDay9PM")}</option>
|
|
1237
1237
|
</select>
|
|
1238
1238
|
</div>
|
|
1239
1239
|
<p class="form-field__hint">
|
|
1240
|
-
${
|
|
1240
|
+
${r("cron.scheduleHintPreset")}
|
|
1241
1241
|
</p>
|
|
1242
1242
|
</div>
|
|
1243
1243
|
<div class="form-field">
|
|
1244
|
-
<label class="form-field__label">${
|
|
1244
|
+
<label class="form-field__label">${r("cron.mode")}</label>
|
|
1245
1245
|
<select
|
|
1246
1246
|
class="form-field__select"
|
|
1247
1247
|
.value=${this._formSessionTarget??"main"}
|
|
1248
1248
|
@change=${e=>this._formSessionTarget=e.target.value}
|
|
1249
1249
|
>
|
|
1250
|
-
<option value="main">${
|
|
1251
|
-
<option value="isolated">${
|
|
1250
|
+
<option value="main">${r("cron.modeDirectOption")||"Direct (send message directly)"}</option>
|
|
1251
|
+
<option value="isolated">${r("cron.modeAgentOption")||"AI Agent (process with AI then send)"}</option>
|
|
1252
1252
|
</select>
|
|
1253
1253
|
<p class="form-field__hint">
|
|
1254
|
-
${this._formSessionTarget==="main"?
|
|
1254
|
+
${this._formSessionTarget==="main"?r("cron.modeDirect"):r("cron.modeAgent")}
|
|
1255
1255
|
</p>
|
|
1256
1256
|
</div>
|
|
1257
1257
|
${this._formSessionTarget==="isolated"?o`
|
|
1258
1258
|
<div class="form-field">
|
|
1259
|
-
<label class="form-field__label">${
|
|
1259
|
+
<label class="form-field__label">${r("cron.model")}</label>
|
|
1260
1260
|
<select
|
|
1261
1261
|
class="form-field__select"
|
|
1262
1262
|
.value=${this._formModel??""}
|
|
@@ -1265,11 +1265,11 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1265
1265
|
${this._availableModels.length>0?this._availableModels.map(e=>o`
|
|
1266
1266
|
<option value=${e.id}>${e.name} (${e.provider})</option>
|
|
1267
1267
|
`):o`
|
|
1268
|
-
<option value="">${
|
|
1268
|
+
<option value="">${r("cron.noConfiguredModels")}</option>
|
|
1269
1269
|
`}
|
|
1270
1270
|
</select>
|
|
1271
1271
|
</div>
|
|
1272
|
-
`:
|
|
1272
|
+
`:_}
|
|
1273
1273
|
<div class="form-field">
|
|
1274
1274
|
<label class="form-field__label">Channel</label>
|
|
1275
1275
|
<select
|
|
@@ -1294,7 +1294,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1294
1294
|
title="Refresh chat list"
|
|
1295
1295
|
style="padding: 0.25rem 0.5rem; font-size: 0.75rem;"
|
|
1296
1296
|
>
|
|
1297
|
-
${
|
|
1297
|
+
${d("refresh")} Refresh
|
|
1298
1298
|
</button>
|
|
1299
1299
|
</div>
|
|
1300
1300
|
<div style="display: flex; gap: 0.5rem; align-items: center;">
|
|
@@ -1323,33 +1323,33 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1323
1323
|
</select>
|
|
1324
1324
|
</div>
|
|
1325
1325
|
<p class="form-field__hint">
|
|
1326
|
-
${this._sessionChatIds.length>0?
|
|
1326
|
+
${this._sessionChatIds.length>0?r("cron.enterManuallyOrSelect"):r("cron.noRecentChats")}
|
|
1327
1327
|
</p>
|
|
1328
1328
|
</div>
|
|
1329
1329
|
<div class="form-field">
|
|
1330
|
-
<label class="form-field__label">${
|
|
1330
|
+
<label class="form-field__label">${r("cron.message")}</label>
|
|
1331
1331
|
<textarea
|
|
1332
1332
|
class="form-field__textarea"
|
|
1333
1333
|
.value=${this._formMessage??""}
|
|
1334
1334
|
@input=${e=>this._formMessage=e.target.value}
|
|
1335
|
-
placeholder="${
|
|
1335
|
+
placeholder="${r("cron.messagePlaceholder")??"What should the assistant do?"}"
|
|
1336
1336
|
rows="4"
|
|
1337
1337
|
></textarea>
|
|
1338
1338
|
</div>
|
|
1339
1339
|
</div>
|
|
1340
1340
|
<div class="modal__actions">
|
|
1341
|
-
<button class="btn btn-secondary" @click=${this._closeForm}>${
|
|
1341
|
+
<button class="btn btn-secondary" @click=${this._closeForm}>${r("common.cancel")}</button>
|
|
1342
1342
|
<button
|
|
1343
1343
|
class="btn btn-primary"
|
|
1344
1344
|
@click=${this._submitForm}
|
|
1345
1345
|
?disabled=${this._formSubmitting||!this._formSchedule||!this._formChatId||!this._formMessage}
|
|
1346
1346
|
>
|
|
1347
|
-
${this._formSubmitting?
|
|
1347
|
+
${this._formSubmitting?r("common.loading"):this._formMode==="edit"?r("cron.save"):r("cron.create")}
|
|
1348
1348
|
</button>
|
|
1349
1349
|
</div>
|
|
1350
1350
|
</div>
|
|
1351
1351
|
</div>
|
|
1352
|
-
`:
|
|
1352
|
+
`:_}
|
|
1353
1353
|
|
|
1354
1354
|
<!-- Detail Drawer -->
|
|
1355
1355
|
${this._detailOpen?o`
|
|
@@ -1359,7 +1359,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1359
1359
|
<div class="drawer-header__info">
|
|
1360
1360
|
<div class="drawer-header__title">${this._detailJob?.name||this._detailJob?.id}</div>
|
|
1361
1361
|
</div>
|
|
1362
|
-
<button class="btn-icon" @click=${this._closeDetail}>${
|
|
1362
|
+
<button class="btn-icon" @click=${this._closeDetail}>${d("x")}</button>
|
|
1363
1363
|
</div>
|
|
1364
1364
|
<div class="drawer-content ${this._detailLoading?"drawer-content--loading":""}">
|
|
1365
1365
|
${this._detailLoading?o`
|
|
@@ -1367,19 +1367,19 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1367
1367
|
`:o`
|
|
1368
1368
|
<div class="session-detail">
|
|
1369
1369
|
<div class="session-detail__row">
|
|
1370
|
-
<span class="session-detail__label">${
|
|
1370
|
+
<span class="session-detail__label">${r("cron.scheduleLabel")}</span>
|
|
1371
1371
|
<code>${this._detailJob?.schedule}</code>
|
|
1372
1372
|
</div>
|
|
1373
1373
|
<div class="session-detail__row">
|
|
1374
|
-
<span class="session-detail__label">${
|
|
1374
|
+
<span class="session-detail__label">${r("cron.messageLabel")}</span>
|
|
1375
1375
|
<span>${this._detailJob?.message}</span>
|
|
1376
1376
|
</div>
|
|
1377
1377
|
<div class="session-detail__row">
|
|
1378
|
-
<span class="session-detail__label">${
|
|
1379
|
-
<span>${this._detailJob?.enabled?
|
|
1378
|
+
<span class="session-detail__label">${r("cron.status")}</span>
|
|
1379
|
+
<span>${this._detailJob?.enabled?r("cron.enabled"):r("cron.disabled")}</span>
|
|
1380
1380
|
</div>
|
|
1381
1381
|
<div class="session-detail__row">
|
|
1382
|
-
<span class="session-detail__label">${
|
|
1382
|
+
<span class="session-detail__label">${r("cron.nextRun")}</span>
|
|
1383
1383
|
<span>${this._detailJob?.next_run?this._formatNextRun(this._detailJob.next_run):"N/A"}</span>
|
|
1384
1384
|
</div>
|
|
1385
1385
|
</div>
|
|
@@ -1387,19 +1387,19 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1387
1387
|
</div>
|
|
1388
1388
|
</div>
|
|
1389
1389
|
</div>
|
|
1390
|
-
`:
|
|
1390
|
+
`:_}
|
|
1391
1391
|
|
|
1392
1392
|
<!-- Confirm Dialog -->
|
|
1393
1393
|
<confirm-dialog
|
|
1394
1394
|
.open=${this._confirmOpen}
|
|
1395
1395
|
.title=${this._confirmTitle}
|
|
1396
1396
|
.message=${this._confirmMessage}
|
|
1397
|
-
.confirmText=${this._confirmAction==="delete"?
|
|
1398
|
-
.cancelText=${
|
|
1397
|
+
.confirmText=${this._confirmAction==="delete"?r("cron.delete"):r("cron.runNow")}
|
|
1398
|
+
.cancelText=${r("common.cancel")}
|
|
1399
1399
|
.type=${this._confirmAction==="delete"?"danger":"warning"}
|
|
1400
1400
|
@confirm=${this._handleConfirm}
|
|
1401
1401
|
></confirm-dialog>
|
|
1402
|
-
`}_formatNextRun(e){const t=typeof e=="string"?new Date(e):e,s=new Date,i=t.getTime()-s.getTime();if(i<0)return
|
|
1402
|
+
`}_formatNextRun(e){const t=typeof e=="string"?new Date(e):e,s=new Date,i=t.getTime()-s.getTime();if(i<0)return r("cron.timeLabels.overdue");if(i<6e4)return r("cron.timeLabels.lessThanMinute");if(i<36e5){const n=Math.floor(i/6e4);return r("cron.timeLabels.minutes",{count:n})}if(i<864e5){const n=Math.floor(i/36e5);return r("cron.timeLabels.hours",{count:n})}return t.toLocaleString()}_formatLastActive(e){const t=new Date(e),i=new Date().getTime()-t.getTime();if(i<0||i<6e4)return r("cron.lastActiveLabels.justNow");if(i<36e5){const n=Math.floor(i/6e4);return r("cron.lastActiveLabels.minutesAgo",{count:n})}if(i<864e5){const n=Math.floor(i/36e5);return r("cron.lastActiveLabels.hoursAgo",{count:n})}if(i<6048e5){const n=Math.floor(i/864e5);return r("cron.lastActiveLabels.daysAgo",{count:n})}return t.toLocaleDateString()}_formatTime(e){return new Date(e).toLocaleString()}};v([u({attribute:!1})],m.prototype,"config",2);v([c()],m.prototype,"_jobs",2);v([c()],m.prototype,"_metrics",2);v([c()],m.prototype,"_channels",2);v([c()],m.prototype,"_availableModels",2);v([c()],m.prototype,"_defaultModel",2);v([c()],m.prototype,"_sessionChatIds",2);v([c()],m.prototype,"_loading",2);v([c()],m.prototype,"_error",2);v([c()],m.prototype,"_formOpen",2);v([c()],m.prototype,"_formMode",2);v([c()],m.prototype,"_formJobId",2);v([c()],m.prototype,"_formName",2);v([c()],m.prototype,"_formSchedule",2);v([c()],m.prototype,"_formChannel",2);v([c()],m.prototype,"_formChatId",2);v([c()],m.prototype,"_formMessage",2);v([c()],m.prototype,"_formSessionTarget",2);v([c()],m.prototype,"_formModel",2);v([c()],m.prototype,"_formSubmitting",2);v([c()],m.prototype,"_detailOpen",2);v([c()],m.prototype,"_detailJob",2);v([c()],m.prototype,"_detailHistory",2);v([c()],m.prototype,"_detailLoading",2);v([c()],m.prototype,"_confirmOpen",2);v([c()],m.prototype,"_confirmTitle",2);v([c()],m.prototype,"_confirmMessage",2);v([c()],m.prototype,"_confirmJobId",2);v([c()],m.prototype,"_confirmAction",2);m=v([k("cron-manager")],m);const ci=["trace","debug","info","warn","error","fatal"],be={trace:"#9ca3af",debug:"#6b7280",info:"#3b82f6",warn:"#f59e0b",error:"#ef4444",fatal:"#dc2626"};class hi{constructor(t,s){this.baseUrl=t.replace(/\/$/,""),this.token=s}async request(t,s,i){const n={"Content-Type":"application/json"};this.token&&(n.Authorization=`Bearer ${this.token}`);const a=await fetch(`${this.baseUrl}${s}`,{method:t,headers:n,body:i?JSON.stringify(i):void 0});if(!a.ok){const l=await a.json().catch(()=>({error:"Request failed"}));throw new Error(l.error||`HTTP ${a.status}`)}return a.json()}async queryLogs(t){const s=new URLSearchParams;t?.level?.length&&s.set("level",t.level.join(",")),t?.from&&s.set("from",t.from),t?.to&&s.set("to",t.to),t?.q&&s.set("q",t.q),t?.module&&s.set("module",t.module),t?.limit&&s.set("limit",String(t.limit)),t?.offset&&s.set("offset",String(t.offset));const i=s.toString(),n=`/api/logs${i?`?${i}`:""}`;return await this.request("GET",n)}async getLogFiles(){return(await this.request("GET","/api/logs/files")).files||[]}async getLogStats(){return await this.request("GET","/api/logs/stats")}async getLogLevels(){return(await this.request("GET","/api/logs/levels")).levels||[]}async getLogModules(){return(await this.request("GET","/api/logs/modules")).modules||[]}async getLogDir(){return(await this.request("GET","/api/logs/dir")).dir}}var di=Object.defineProperty,pi=Object.getOwnPropertyDescriptor,C=(e,t,s,i)=>{for(var n=i>1?void 0:i?pi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&di(t,s,n),n};let $=class extends y{constructor(){super(...arguments),this._logs=[],this._loading=!1,this._hasMore=!1,this._files=[],this._modules=[],this._showFilesPanel=!1,this._selectedLevels=new Set,this._searchQuery="",this._selectedModule="",this._dateFrom="",this._dateTo="",this._offset=0,this._error=null,this._selectedLog=null,this._autoRefresh=!1,this._limit=50,this._initialized=!1,this._debouncedSearch=this._debounce(()=>{this._loadLogs(!0)},300)}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._tryInitialize()}willUpdate(e){super.willUpdate(e),e.has("config")&&this._tryInitialize()}disconnectedCallback(){super.disconnectedCallback(),this._stopAutoRefresh()}firstUpdated(){this._tryInitialize()}_tryInitialize(){if(this._initialized)return;const e=window.location.origin;this._api=new hi(e,this.config?.token),this._initialized=!0,this._loadLogs(),this._loadFiles(),this._loadModules()}async _loadLogs(e=!1){if(!this._loading){this._loading=!0,this._error=null,e&&(this._offset=0,this._logs=[]);try{const t={level:this._selectedLevels.size>0?Array.from(this._selectedLevels):void 0,from:this._dateFrom||void 0,to:this._dateTo||void 0,q:this._searchQuery||void 0,module:this._selectedModule||void 0,limit:this._limit,offset:this._offset},s=await this._api.queryLogs(t);e?this._logs=s.logs:this._logs=[...this._logs,...s.logs],console.log("[LogManager] Total logs in state:",this._logs.length),this._hasMore=s.logs.length===this._limit,this._offset=this._offset+s.logs.length}catch(t){this._error=t instanceof Error?t.message:"Failed to load logs",console.error("[LogManager] Load error:",t)}finally{this._loading=!1}}}async _loadFiles(){try{this._files=await this._api.getLogFiles()}catch(e){console.error("[LogManager] Files error:",e)}}async _loadModules(){try{this._modules=await this._api.getLogModules()}catch(e){console.error("[LogManager] Modules error:",e)}}_toggleLevel(e){this._selectedLevels.has(e)?this._selectedLevels.delete(e):this._selectedLevels.add(e),this._selectedLevels=new Set(this._selectedLevels),this._loadLogs(!0)}_handleSearch(e){const t=e.target;this._searchQuery=t.value,this._debouncedSearch()}_debounce(e,t){let s;return()=>{clearTimeout(s),s=setTimeout(e,t)}}_handleModuleChange(e){const t=e.target;this._selectedModule=t.value,this._loadLogs(!0)}_handleDateFromChange(e){const t=e.target;this._dateFrom=t.value,this._loadLogs(!0)}_handleDateToChange(e){const t=e.target;this._dateTo=t.value,this._loadLogs(!0)}_clearFilters(){this._selectedLevels.clear(),this._selectedLevels=new Set,this._searchQuery="",this._selectedModule="",this._dateFrom="",this._dateTo="",this._loadLogs(!0)}_selectLog(e){this._selectedLog=e}_closeDetail(){this._selectedLog=null}_toggleAutoRefresh(){this._autoRefresh=!this._autoRefresh,this._autoRefresh?this._startAutoRefresh():this._stopAutoRefresh()}_startAutoRefresh(){this._refreshInterval=window.setInterval(()=>{this._loadLogs(!0)},5e3)}_stopAutoRefresh(){this._refreshInterval&&(clearInterval(this._refreshInterval),this._refreshInterval=void 0)}_handleLoadMore(){this._loadLogs()}_formatTimestamp(e){try{return new Date(e).toLocaleString([],{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"})}catch{return e}}_formatFileSize(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}render(){return o`
|
|
1403
1403
|
<div class="log-manager">
|
|
1404
1404
|
${this._renderHeader()}
|
|
1405
1405
|
<div class="log-manager__main">
|
|
@@ -1414,9 +1414,9 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1414
1414
|
`}_renderHeader(){return o`
|
|
1415
1415
|
<div class="log-manager__header">
|
|
1416
1416
|
<div class="log-manager__title">
|
|
1417
|
-
<span class="title-icon">${
|
|
1417
|
+
<span class="title-icon">${d("fileText")}</span>
|
|
1418
1418
|
<div class="title-text">
|
|
1419
|
-
<h1>${
|
|
1419
|
+
<h1>${r("logs.title")}</h1>
|
|
1420
1420
|
<span class="title-subtitle">System logs and diagnostics</span>
|
|
1421
1421
|
</div>
|
|
1422
1422
|
</div>
|
|
@@ -1426,52 +1426,54 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1426
1426
|
@click=${this._toggleFilesPanel}
|
|
1427
1427
|
title="Toggle log files"
|
|
1428
1428
|
>
|
|
1429
|
-
${
|
|
1429
|
+
${d("folder")}
|
|
1430
1430
|
${this._files.length>0?o`<span class="badge">${this._files.length}</span>`:""}
|
|
1431
1431
|
</button>
|
|
1432
1432
|
<button
|
|
1433
1433
|
class="btn-icon ${this._autoRefresh?"btn-icon--active":""}"
|
|
1434
1434
|
@click=${this._toggleAutoRefresh}
|
|
1435
|
-
title=${this._autoRefresh?
|
|
1435
|
+
title=${this._autoRefresh?r("logs.pause"):r("logs.autoRefresh")}
|
|
1436
1436
|
>
|
|
1437
|
-
${
|
|
1437
|
+
${d(this._autoRefresh?"pause":"play")}
|
|
1438
1438
|
</button>
|
|
1439
1439
|
<button
|
|
1440
1440
|
class="btn-icon"
|
|
1441
1441
|
@click=${()=>this._loadLogs(!0)}
|
|
1442
|
-
title=${
|
|
1442
|
+
title=${r("logs.refresh")}
|
|
1443
1443
|
>
|
|
1444
|
-
${
|
|
1444
|
+
${d("refreshCw")}
|
|
1445
1445
|
</button>
|
|
1446
1446
|
</div>
|
|
1447
1447
|
</div>
|
|
1448
1448
|
`}_renderFilters(){return o`
|
|
1449
1449
|
<div class="log-manager__filters">
|
|
1450
|
-
<div class="
|
|
1451
|
-
<
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1450
|
+
<div class="log-manager__filters-row">
|
|
1451
|
+
<div class="filter-group">
|
|
1452
|
+
<label class="filter-label">${r("logs.level")}</label>
|
|
1453
|
+
<div class="level-filters">
|
|
1454
|
+
${ci.map(e=>o`
|
|
1455
|
+
<button
|
|
1456
|
+
class="level-badge ${this._selectedLevels.has(e)?"level-badge--active":""}"
|
|
1457
|
+
style="--level-color: ${be[e]}"
|
|
1458
|
+
@click=${()=>this._toggleLevel(e)}
|
|
1459
|
+
>
|
|
1460
|
+
${e}
|
|
1461
|
+
</button>
|
|
1462
|
+
`)}
|
|
1463
|
+
</div>
|
|
1462
1464
|
</div>
|
|
1463
|
-
</div>
|
|
1464
1465
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1466
|
+
<div class="filter-group">
|
|
1467
|
+
<label class="filter-label">${r("logs.search")}</label>
|
|
1468
|
+
<div class="search-box">
|
|
1469
|
+
${d("search")}
|
|
1470
|
+
<input
|
|
1471
|
+
type="text"
|
|
1472
|
+
placeholder="${r("logs.searchPlaceholder")}"
|
|
1473
|
+
.value=${this._searchQuery}
|
|
1474
|
+
@input=${this._handleSearch}
|
|
1475
|
+
/>
|
|
1476
|
+
</div>
|
|
1475
1477
|
</div>
|
|
1476
1478
|
</div>
|
|
1477
1479
|
|
|
@@ -1503,7 +1505,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1503
1505
|
</div>
|
|
1504
1506
|
|
|
1505
1507
|
<button class="btn btn-ghost" @click=${this._clearFilters}>
|
|
1506
|
-
${
|
|
1508
|
+
${d("x")}
|
|
1507
1509
|
Clear
|
|
1508
1510
|
</button>
|
|
1509
1511
|
</div>
|
|
@@ -1511,10 +1513,10 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1511
1513
|
`}_renderLogTable(){return this._loading&&this._logs.length===0?this._renderLoading():this._logs.length===0?o`
|
|
1512
1514
|
<div class="log-manager__empty">
|
|
1513
1515
|
<div class="empty-state">
|
|
1514
|
-
<div class="empty-state__icon">${
|
|
1515
|
-
<div class="empty-state__title">${
|
|
1516
|
+
<div class="empty-state__icon">${d("fileText")}</div>
|
|
1517
|
+
<div class="empty-state__title">${r("logs.noLogs")}</div>
|
|
1516
1518
|
<div class="empty-state__description">
|
|
1517
|
-
${
|
|
1519
|
+
${r("logs.noLogsDescription")}
|
|
1518
1520
|
</div>
|
|
1519
1521
|
</div>
|
|
1520
1522
|
</div>
|
|
@@ -1523,10 +1525,10 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1523
1525
|
<table class="log-table">
|
|
1524
1526
|
<thead>
|
|
1525
1527
|
<tr>
|
|
1526
|
-
<th>${
|
|
1527
|
-
<th>${
|
|
1528
|
-
<th>${
|
|
1529
|
-
<th>${
|
|
1528
|
+
<th>${r("logs.time")}</th>
|
|
1529
|
+
<th>${r("logs.level")}</th>
|
|
1530
|
+
<th>${r("logs.module")}</th>
|
|
1531
|
+
<th>${r("logs.message")}</th>
|
|
1530
1532
|
</tr>
|
|
1531
1533
|
</thead>
|
|
1532
1534
|
<tbody>
|
|
@@ -1542,7 +1544,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1542
1544
|
<td class="log-cell log-cell--level">
|
|
1543
1545
|
<span
|
|
1544
1546
|
class="level-badge level-badge--small"
|
|
1545
|
-
style="--level-color: ${
|
|
1547
|
+
style="--level-color: ${be[e.level]||be.info}"
|
|
1546
1548
|
>
|
|
1547
1549
|
${e.level||"info"}
|
|
1548
1550
|
</span>
|
|
@@ -1557,7 +1559,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1557
1559
|
${this._hasMore?o`
|
|
1558
1560
|
<div class="log-table__load-more">
|
|
1559
1561
|
<button class="btn btn-secondary" @click=${this._handleLoadMore} ?disabled=${this._loading}>
|
|
1560
|
-
${this._loading?o`<span class="spinner"></span>`:
|
|
1562
|
+
${this._loading?o`<span class="spinner"></span>`:d("chevronDown")}
|
|
1561
1563
|
Load More
|
|
1562
1564
|
</button>
|
|
1563
1565
|
</div>
|
|
@@ -1570,11 +1572,11 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1570
1572
|
<div class="files-panel ${this._showFilesPanel?"files-panel--open":""}">
|
|
1571
1573
|
<div class="files-panel__header">
|
|
1572
1574
|
<span class="files-panel__title">
|
|
1573
|
-
${
|
|
1575
|
+
${d("folder")}
|
|
1574
1576
|
Log Files
|
|
1575
1577
|
</span>
|
|
1576
1578
|
<button class="btn btn-icon" @click=${this._toggleFilesPanel}>
|
|
1577
|
-
${
|
|
1579
|
+
${d("x")}
|
|
1578
1580
|
</button>
|
|
1579
1581
|
</div>
|
|
1580
1582
|
<div class="files-panel__content">
|
|
@@ -1584,7 +1586,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1584
1586
|
<div class="file-list">
|
|
1585
1587
|
${this._files.map(e=>o`
|
|
1586
1588
|
<div class="file-item">
|
|
1587
|
-
<span class="file-name">${
|
|
1589
|
+
<span class="file-name">${d("file")}${e.name}</span>
|
|
1588
1590
|
<span class="file-meta">
|
|
1589
1591
|
<span class="file-size">${this._formatFileSize(e.size)}</span>
|
|
1590
1592
|
<span class="file-time">${this._formatTimestamp(e.modified)}</span>
|
|
@@ -1599,30 +1601,30 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1599
1601
|
<div class="drawer-overlay" @click=${this._closeDetail}></div>
|
|
1600
1602
|
<div class="drawer drawer--right">
|
|
1601
1603
|
<div class="drawer-header">
|
|
1602
|
-
<h3 class="drawer-header__title">${
|
|
1603
|
-
<button class="btn btn-icon" @click=${this._closeDetail}>${
|
|
1604
|
+
<h3 class="drawer-header__title">${r("logs.details")}</h3>
|
|
1605
|
+
<button class="btn btn-icon" @click=${this._closeDetail}>${d("x")}</button>
|
|
1604
1606
|
</div>
|
|
1605
1607
|
<div class="drawer__content">
|
|
1606
1608
|
<div class="log-detail">
|
|
1607
1609
|
<div class="log-detail__field">
|
|
1608
|
-
<label>${
|
|
1610
|
+
<label>${r("logs.time")}</label>
|
|
1609
1611
|
<code>${e.timestamp}</code>
|
|
1610
1612
|
</div>
|
|
1611
1613
|
<div class="log-detail__field">
|
|
1612
|
-
<label>${
|
|
1614
|
+
<label>${r("logs.level")}</label>
|
|
1613
1615
|
<span
|
|
1614
1616
|
class="level-badge"
|
|
1615
|
-
style="--level-color: ${
|
|
1617
|
+
style="--level-color: ${be[e.level]}"
|
|
1616
1618
|
>
|
|
1617
1619
|
${e.level}
|
|
1618
1620
|
</span>
|
|
1619
1621
|
</div>
|
|
1620
1622
|
<div class="log-detail__field">
|
|
1621
|
-
<label>${
|
|
1623
|
+
<label>${r("logs.module")}</label>
|
|
1622
1624
|
<code>${e.module}</code>
|
|
1623
1625
|
</div>
|
|
1624
1626
|
<div class="log-detail__field">
|
|
1625
|
-
<label>${
|
|
1627
|
+
<label>${r("logs.message")}</label>
|
|
1626
1628
|
<pre class="log-detail__message">${e.message}</pre>
|
|
1627
1629
|
</div>
|
|
1628
1630
|
${e.meta?o`
|
|
@@ -1647,11 +1649,11 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1647
1649
|
`)}
|
|
1648
1650
|
</div>
|
|
1649
1651
|
</div>
|
|
1650
|
-
`}};C([u({attribute:!1})],$.prototype,"config",2);C([c()],$.prototype,"_logs",2);C([c()],$.prototype,"_loading",2);C([c()],$.prototype,"_hasMore",2);C([c()],$.prototype,"_files",2);C([c()],$.prototype,"_modules",2);C([c()],$.prototype,"_showFilesPanel",2);C([c()],$.prototype,"_selectedLevels",2);C([c()],$.prototype,"_searchQuery",2);C([c()],$.prototype,"_selectedModule",2);C([c()],$.prototype,"_dateFrom",2);C([c()],$.prototype,"_dateTo",2);C([c()],$.prototype,"_offset",2);C([c()],$.prototype,"_error",2);C([c()],$.prototype,"_selectedLog",2);C([c()],$.prototype,"_autoRefresh",2);C([c()],$.prototype,"_refreshInterval",2);$=C([k("log-manager")],$);var oi=Object.defineProperty,ri=Object.getOwnPropertyDescriptor,D=(e,t,s,i)=>{for(var n=i>1?void 0:i?ri(t,s):t,r=e.length-1,l;r>=0;r--)(l=e[r])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&oi(t,s,n),n};let P=class extends y{constructor(){super(...arguments),this._activeSection="agent",this._loading=!1,this._saving=!1,this._dirtyFields=new Set,this._errors=new Map,this._saveSuccess=!1,this._models=[],this._values={model:"anthropic/claude-sonnet-4-5",maxTokens:8192,temperature:.7,maxToolIterations:20,telegramEnabled:!1,telegramToken:"",telegramApiRoot:"",telegramDebug:!1,telegramAllowFrom:"",whatsappEnabled:!1,whatsappBridgeUrl:"ws://localhost:3001",whatsappAllowFrom:"",heartbeatEnabled:!0,heartbeatIntervalMs:6e4,openaiApiKey:"",anthropicApiKey:"",googleApiKey:"",qwenApiKey:"",kimiApiKey:"",minimaxApiKey:"",deepseekApiKey:"",grokApiKey:"",openrouterApiKey:"",workspace:"",theme:"system"},this._initialized=!1}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._tryInitialize()}willUpdate(e){super.willUpdate(e),e.has("config")&&this._tryInitialize()}_tryInitialize(){this.config?.url&&this._loadSettings()}get _sections(){const e=this._models.map(t=>({value:t.id,label:`${t.provider}/${t.name}`}));return[{id:"agent",title:a("settings.sections.agent"),icon:"bot",fields:[{key:"model",label:a("settings.fields.model"),type:"select",description:a("settings.descriptionsFields.model"),options:e},{key:"workspace",label:a("settings.fields.workspace"),type:"text",description:a("settings.descriptionsFields.workspace"),placeholder:a("settings.placeholders.workspace")},{key:"maxTokens",label:a("settings.fields.maxTokens"),type:"number",description:a("settings.descriptionsFields.maxTokens"),validation:{min:256,max:128e3}},{key:"temperature",label:a("settings.fields.temperature"),type:"number",description:a("settings.descriptionsFields.temperature"),validation:{min:0,max:2}},{key:"maxToolIterations",label:a("settings.fields.maxToolIterations"),type:"number",description:a("settings.descriptionsFields.maxToolIterations"),validation:{min:1,max:100}}]},{id:"providers",title:a("settings.sections.providers"),icon:"cloud",fields:[{key:"openaiApiKey",label:a("settings.fields.openaiApiKey"),type:"password",description:a("settings.descriptionsFields.openaiApiKey"),placeholder:a("settings.placeholders.openaiApiKey")},{key:"anthropicApiKey",label:a("settings.fields.anthropicApiKey"),type:"password",description:a("settings.descriptionsFields.anthropicApiKey"),placeholder:a("settings.placeholders.anthropicApiKey")},{key:"googleApiKey",label:a("settings.fields.googleApiKey"),type:"password",description:a("settings.descriptionsFields.googleApiKey"),placeholder:a("settings.placeholders.googleApiKey")},{key:"qwenApiKey",label:a("settings.fields.qwenApiKey"),type:"password",description:a("settings.descriptionsFields.qwenApiKey"),placeholder:a("settings.placeholders.qwenApiKey")},{key:"kimiApiKey",label:a("settings.fields.kimiApiKey"),type:"password",description:a("settings.descriptionsFields.kimiApiKey"),placeholder:a("settings.placeholders.kimiApiKey")},{key:"minimaxApiKey",label:a("settings.fields.minimaxApiKey"),type:"password",description:a("settings.descriptionsFields.minimaxApiKey"),placeholder:a("settings.placeholders.minimaxApiKey")},{key:"deepseekApiKey",label:a("settings.fields.deepseekApiKey"),type:"password",description:a("settings.descriptionsFields.deepseekApiKey"),placeholder:a("settings.placeholders.deepseekApiKey")},{key:"openrouterApiKey",label:a("settings.fields.openrouterApiKey"),type:"password",description:a("settings.descriptionsFields.openrouterApiKey"),placeholder:a("settings.placeholders.openrouterApiKey")}]},{id:"channels",title:a("settings.sections.channels"),icon:"plug",fields:[{key:"telegramEnabled",label:a("settings.fields.telegramEnabled"),type:"boolean",description:a("settings.descriptionsFields.telegramEnabled")},...this._values.telegramEnabled?[{key:"telegramToken",label:a("settings.fields.telegramToken"),type:"password",description:a("settings.descriptionsFields.telegramToken"),placeholder:a("settings.placeholders.telegramToken")},{key:"telegramApiRoot",label:a("settings.fields.telegramApiRoot"),type:"text",description:a("settings.descriptionsFields.telegramApiRoot"),placeholder:a("settings.placeholders.telegramApiRoot")},{key:"telegramAllowFrom",label:a("settings.fields.telegramAllowFrom"),type:"text",description:a("settings.descriptionsFields.telegramAllowFrom"),placeholder:a("settings.placeholders.telegramAllowFrom")},{key:"telegramDebug",label:a("settings.fields.telegramDebug"),type:"boolean",description:a("settings.descriptionsFields.telegramDebug")}]:[],{key:"whatsappEnabled",label:a("settings.fields.whatsappEnabled"),type:"boolean",description:a("settings.descriptionsFields.whatsappEnabled")},...this._values.whatsappEnabled?[{key:"whatsappBridgeUrl",label:a("settings.fields.whatsappBridgeUrl"),type:"text",description:a("settings.descriptionsFields.whatsappBridgeUrl"),placeholder:a("settings.placeholders.whatsappBridgeUrl")},{key:"whatsappAllowFrom",label:a("settings.fields.whatsappAllowFrom"),type:"text",description:a("settings.descriptionsFields.whatsappAllowFrom"),placeholder:a("settings.placeholders.whatsappAllowFrom")}]:[]]},{id:"gateway",title:a("settings.sections.gateway"),icon:"globe",fields:[{key:"heartbeatEnabled",label:a("settings.fields.heartbeatEnabled"),type:"boolean",description:a("settings.descriptionsFields.heartbeatEnabled")},{key:"heartbeatIntervalMs",label:a("settings.fields.heartbeatIntervalMs"),type:"number",description:a("settings.descriptionsFields.heartbeatIntervalMs"),validation:{min:1e3,max:6e5}}]}]}async _loadSettings(){if(!this.config?.url)return;this._loading=!0;const{url:e,token:t}=this.config;try{await this._loadModels();const s=await fetch(`${e}/api/config`,{headers:t?{Authorization:`Bearer ${t}`}:{}});if(s.ok){const n=(await s.json()).payload?.config;if(n){let r=n.agents?.defaults?.model;r&&typeof r=="object"&&(r=r.primary||""),this._values={...this._values,model:r||"anthropic/claude-sonnet-4-5",workspace:n.agents?.defaults?.workspace||"",maxTokens:n.agents?.defaults?.maxTokens||8192,temperature:n.agents?.defaults?.temperature??.7,maxToolIterations:n.agents?.defaults?.maxToolIterations||20,openaiApiKey:n.providers?.openai?.apiKey||"",anthropicApiKey:n.providers?.anthropic?.apiKey||"",googleApiKey:n.providers?.google?.apiKey||"",qwenApiKey:n.providers?.qwen?.apiKey||"",kimiApiKey:n.providers?.kimi?.apiKey||"",minimaxApiKey:n.providers?.minimax?.apiKey||"",deepseekApiKey:n.providers?.deepseek?.apiKey||"",openrouterApiKey:n.providers?.openrouter?.apiKey||"",telegramEnabled:n.channels?.telegram?.enabled||!1,telegramToken:n.channels?.telegram?.token||"",telegramApiRoot:n.channels?.telegram?.apiRoot||"",telegramDebug:n.channels?.telegram?.debug||!1,telegramAllowFrom:(n.channels?.telegram?.allowFrom||[]).join(", "),whatsappEnabled:n.channels?.whatsapp?.enabled||!1,whatsappBridgeUrl:n.channels?.whatsapp?.bridgeUrl||"ws://localhost:3001",whatsappAllowFrom:(n.channels?.whatsapp?.allowFrom||[]).join(", "),heartbeatEnabled:n.gateway?.heartbeat?.enabled??!0,heartbeatIntervalMs:n.gateway?.heartbeat?.intervalMs||6e4}}}}catch(s){console.error("Failed to load settings:",s)}finally{this._loading=!1}}async _loadModels(){if(this.config?.url)try{const{url:e,token:t}=this.config,s=await fetch(`${e}/api/models`,{headers:t?{Authorization:`Bearer ${t}`}:{}});if(s.ok){const i=await s.json();i.payload?.models&&(this._models=i.payload.models)}}catch(e){console.error("Failed to load models:",e)}}async _saveSettings(){if(!this.config?.url||this._errors.size>0)return;this._saving=!0,this._saveSuccess=!1;const{url:e,token:t}=this.config,s={};(this._dirtyFields.has("model")||this._dirtyFields.has("maxTokens")||this._dirtyFields.has("temperature")||this._dirtyFields.has("maxToolIterations")||this._dirtyFields.has("workspace"))&&(s.agents={defaults:{}},this._dirtyFields.has("model")&&(s.agents.defaults.model=this._values.model),this._dirtyFields.has("workspace")&&(s.agents.defaults.workspace=this._values.workspace),this._dirtyFields.has("maxTokens")&&(s.agents.defaults.maxTokens=Number(this._values.maxTokens)),this._dirtyFields.has("temperature")&&(s.agents.defaults.temperature=Number(this._values.temperature)),this._dirtyFields.has("maxToolIterations")&&(s.agents.defaults.maxToolIterations=Number(this._values.maxToolIterations))),["openaiApiKey","anthropicApiKey","googleApiKey","qwenApiKey","kimiApiKey","minimaxApiKey","deepseekApiKey","openrouterApiKey"].filter(r=>this._dirtyFields.has(r)).length>0&&(s.providers={},this._dirtyFields.has("openaiApiKey")&&(s.providers.openai={apiKey:this._values.openaiApiKey}),this._dirtyFields.has("anthropicApiKey")&&(s.providers.anthropic={apiKey:this._values.anthropicApiKey}),this._dirtyFields.has("googleApiKey")&&(s.providers.google={apiKey:this._values.googleApiKey}),this._dirtyFields.has("qwenApiKey")&&(s.providers.qwen={apiKey:this._values.qwenApiKey}),this._dirtyFields.has("kimiApiKey")&&(s.providers.kimi={apiKey:this._values.kimiApiKey}),this._dirtyFields.has("minimaxApiKey")&&(s.providers.minimax={apiKey:this._values.minimaxApiKey}),this._dirtyFields.has("deepseekApiKey")&&(s.providers.deepseek={apiKey:this._values.deepseekApiKey}),this._dirtyFields.has("openrouterApiKey")&&(s.providers.openrouter={apiKey:this._values.openrouterApiKey})),(this._dirtyFields.has("telegramEnabled")||this._dirtyFields.has("whatsappEnabled")||this._dirtyFields.has("telegramToken")||this._dirtyFields.has("telegramApiRoot")||this._dirtyFields.has("telegramDebug")||this._dirtyFields.has("telegramAllowFrom")||this._dirtyFields.has("whatsappBridgeUrl")||this._dirtyFields.has("whatsappAllowFrom"))&&(s.channels={},(this._dirtyFields.has("telegramEnabled")||this._dirtyFields.has("telegramToken")||this._dirtyFields.has("telegramApiRoot")||this._dirtyFields.has("telegramDebug")||this._dirtyFields.has("telegramAllowFrom"))&&(s.channels={...s.channels,telegram:{}},this._dirtyFields.has("telegramEnabled")&&(s.channels.telegram.enabled=!!this._values.telegramEnabled),this._dirtyFields.has("telegramToken")&&(s.channels.telegram.token=this._values.telegramToken),this._dirtyFields.has("telegramApiRoot")&&(s.channels.telegram.apiRoot=this._values.telegramApiRoot||void 0),this._dirtyFields.has("telegramDebug")&&(s.channels.telegram.debug=!!this._values.telegramDebug),this._dirtyFields.has("telegramAllowFrom")&&(s.channels.telegram.allowFrom=this._values.telegramAllowFrom?this._values.telegramAllowFrom.split(",").map(r=>r.trim()).filter(r=>r):[])),(this._dirtyFields.has("whatsappEnabled")||this._dirtyFields.has("whatsappBridgeUrl")||this._dirtyFields.has("whatsappAllowFrom"))&&(s.channels={...s.channels,whatsapp:{}},this._dirtyFields.has("whatsappEnabled")&&(s.channels.whatsapp.enabled=!!this._values.whatsappEnabled),this._dirtyFields.has("whatsappBridgeUrl")&&(s.channels.whatsapp.bridgeUrl=this._values.whatsappBridgeUrl),this._dirtyFields.has("whatsappAllowFrom")&&(s.channels.whatsapp.allowFrom=this._values.whatsappAllowFrom?this._values.whatsappAllowFrom.split(",").map(r=>r.trim()).filter(r=>r):[]))),(this._dirtyFields.has("heartbeatEnabled")||this._dirtyFields.has("heartbeatIntervalMs"))&&(s.gateway={heartbeat:{}},this._dirtyFields.has("heartbeatEnabled")&&(s.gateway.heartbeat.enabled=!!this._values.heartbeatEnabled),this._dirtyFields.has("heartbeatIntervalMs")&&(s.gateway.heartbeat.intervalMs=Number(this._values.heartbeatIntervalMs)));try{const r=await fetch(`${e}/api/config`,{method:"PATCH",headers:{"Content-Type":"application/json",...t?{Authorization:`Bearer ${t}`}:{}},body:JSON.stringify(s)});if(!r.ok){const l=await r.json();throw new Error(l.error||"Failed to save settings")}this._dirtyFields.clear(),this._saveSuccess=!0,setTimeout(()=>{this._saveSuccess=!1},3e3)}catch(r){console.error("Failed to save settings:",r),alert(r instanceof Error?r.message:"Failed to save settings")}finally{this._saving=!1}}_handleInput(e,t){this._values={...this._values,[e]:t},this._dirtyFields.add(e),this.requestUpdate()}render(){return o`
|
|
1652
|
+
`}};C([u({attribute:!1})],$.prototype,"config",2);C([c()],$.prototype,"_logs",2);C([c()],$.prototype,"_loading",2);C([c()],$.prototype,"_hasMore",2);C([c()],$.prototype,"_files",2);C([c()],$.prototype,"_modules",2);C([c()],$.prototype,"_showFilesPanel",2);C([c()],$.prototype,"_selectedLevels",2);C([c()],$.prototype,"_searchQuery",2);C([c()],$.prototype,"_selectedModule",2);C([c()],$.prototype,"_dateFrom",2);C([c()],$.prototype,"_dateTo",2);C([c()],$.prototype,"_offset",2);C([c()],$.prototype,"_error",2);C([c()],$.prototype,"_selectedLog",2);C([c()],$.prototype,"_autoRefresh",2);C([c()],$.prototype,"_refreshInterval",2);$=C([k("log-manager")],$);var ui=Object.defineProperty,gi=Object.getOwnPropertyDescriptor,P=(e,t,s,i)=>{for(var n=i>1?void 0:i?gi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&ui(t,s,n),n};let E=class extends y{constructor(){super(...arguments),this._activeSection="agent",this._loading=!1,this._saving=!1,this._refreshingToken=!1,this._serverToken=null,this._showToken=!1,this._dirtyFields=new Set,this._errors=new Map,this._saveSuccess=!1,this._models=[],this._values={model:"anthropic/claude-sonnet-4-5",maxTokens:8192,temperature:.7,maxToolIterations:20,telegramEnabled:!1,telegramToken:"",telegramApiRoot:"",telegramDebug:!1,telegramAllowFrom:"",whatsappEnabled:!1,whatsappBridgeUrl:"ws://localhost:3001",whatsappAllowFrom:"",gatewayToken:"",heartbeatEnabled:!0,heartbeatIntervalMs:6e4,openaiApiKey:"",anthropicApiKey:"",googleApiKey:"",qwenApiKey:"",kimiApiKey:"",minimaxApiKey:"",deepseekApiKey:"",grokApiKey:"",openrouterApiKey:"",workspace:"",theme:"system"},this._initialized=!1}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._tryInitialize()}willUpdate(e){super.willUpdate(e),e.has("config")&&this._tryInitialize()}_tryInitialize(){this._initialized||(this._initialized=!0,this._loadSettings())}get _sections(){const e=this._models.map(t=>({value:t.id,label:`${t.provider}/${t.name}`}));return[{id:"agent",title:r("settings.sections.agent"),icon:"bot",fields:[{key:"model",label:r("settings.fields.model"),type:"select",description:r("settings.descriptionsFields.model"),options:e},{key:"workspace",label:r("settings.fields.workspace"),type:"text",description:r("settings.descriptionsFields.workspace"),placeholder:r("settings.placeholders.workspace")},{key:"maxTokens",label:r("settings.fields.maxTokens"),type:"number",description:r("settings.descriptionsFields.maxTokens"),validation:{min:256,max:128e3}},{key:"temperature",label:r("settings.fields.temperature"),type:"number",description:r("settings.descriptionsFields.temperature"),validation:{min:0,max:2}},{key:"maxToolIterations",label:r("settings.fields.maxToolIterations"),type:"number",description:r("settings.descriptionsFields.maxToolIterations"),validation:{min:1,max:100}}]},{id:"providers",title:r("settings.sections.providers"),icon:"cloud",fields:[{key:"openaiApiKey",label:r("settings.fields.openaiApiKey"),type:"password",description:r("settings.descriptionsFields.openaiApiKey"),placeholder:r("settings.placeholders.openaiApiKey")},{key:"anthropicApiKey",label:r("settings.fields.anthropicApiKey"),type:"password",description:r("settings.descriptionsFields.anthropicApiKey"),placeholder:r("settings.placeholders.anthropicApiKey")},{key:"googleApiKey",label:r("settings.fields.googleApiKey"),type:"password",description:r("settings.descriptionsFields.googleApiKey"),placeholder:r("settings.placeholders.googleApiKey")},{key:"qwenApiKey",label:r("settings.fields.qwenApiKey"),type:"password",description:r("settings.descriptionsFields.qwenApiKey"),placeholder:r("settings.placeholders.qwenApiKey")},{key:"kimiApiKey",label:r("settings.fields.kimiApiKey"),type:"password",description:r("settings.descriptionsFields.kimiApiKey"),placeholder:r("settings.placeholders.kimiApiKey")},{key:"minimaxApiKey",label:r("settings.fields.minimaxApiKey"),type:"password",description:r("settings.descriptionsFields.minimaxApiKey"),placeholder:r("settings.placeholders.minimaxApiKey")},{key:"deepseekApiKey",label:r("settings.fields.deepseekApiKey"),type:"password",description:r("settings.descriptionsFields.deepseekApiKey"),placeholder:r("settings.placeholders.deepseekApiKey")},{key:"openrouterApiKey",label:r("settings.fields.openrouterApiKey"),type:"password",description:r("settings.descriptionsFields.openrouterApiKey"),placeholder:r("settings.placeholders.openrouterApiKey")}]},{id:"channels",title:r("settings.sections.channels"),icon:"plug",fields:[{key:"telegramEnabled",label:r("settings.fields.telegramEnabled"),type:"boolean",description:r("settings.descriptionsFields.telegramEnabled")},...this._values.telegramEnabled?[{key:"telegramToken",label:r("settings.fields.telegramToken"),type:"password",description:r("settings.descriptionsFields.telegramToken"),placeholder:r("settings.placeholders.telegramToken")},{key:"telegramApiRoot",label:r("settings.fields.telegramApiRoot"),type:"text",description:r("settings.descriptionsFields.telegramApiRoot"),placeholder:r("settings.placeholders.telegramApiRoot")},{key:"telegramAllowFrom",label:r("settings.fields.telegramAllowFrom"),type:"text",description:r("settings.descriptionsFields.telegramAllowFrom"),placeholder:r("settings.placeholders.telegramAllowFrom")},{key:"telegramDebug",label:r("settings.fields.telegramDebug"),type:"boolean",description:r("settings.descriptionsFields.telegramDebug")}]:[],{key:"whatsappEnabled",label:r("settings.fields.whatsappEnabled"),type:"boolean",description:r("settings.descriptionsFields.whatsappEnabled")},...this._values.whatsappEnabled?[{key:"whatsappBridgeUrl",label:r("settings.fields.whatsappBridgeUrl"),type:"text",description:r("settings.descriptionsFields.whatsappBridgeUrl"),placeholder:r("settings.placeholders.whatsappBridgeUrl")},{key:"whatsappAllowFrom",label:r("settings.fields.whatsappAllowFrom"),type:"text",description:r("settings.descriptionsFields.whatsappAllowFrom"),placeholder:r("settings.placeholders.whatsappAllowFrom")}]:[]]},{id:"gateway",title:r("settings.sections.gateway"),icon:"globe",fields:[{key:"gatewayToken",label:r("settings.fields.gatewayToken"),type:"password",description:r("settings.descriptionsFields.gatewayToken"),placeholder:r("settings.placeholders.gatewayToken")},{key:"heartbeatEnabled",label:r("settings.fields.heartbeatEnabled"),type:"boolean",description:r("settings.descriptionsFields.heartbeatEnabled")},{key:"heartbeatIntervalMs",label:r("settings.fields.heartbeatIntervalMs"),type:"number",description:r("settings.descriptionsFields.heartbeatIntervalMs"),validation:{min:1e3,max:6e5}}]}]}async _loadSettings(){this._loading=!0;const e=window.location.origin,t=this.config?.token;try{await this._loadModels();const s=this._loadUiSettings();this._values.gatewayToken=s.token||"",await this._loadServerToken();const i=await fetch(`${e}/api/config`,{headers:t?{Authorization:`Bearer ${t}`}:{}});if(i.ok){const a=(await i.json()).payload?.config;if(a){let l=a.agents?.defaults?.model;l&&typeof l=="object"&&(l=l.primary||""),this._values={...this._values,model:l||"anthropic/claude-sonnet-4-5",workspace:a.agents?.defaults?.workspace||"",maxTokens:a.agents?.defaults?.maxTokens||8192,temperature:a.agents?.defaults?.temperature??.7,maxToolIterations:a.agents?.defaults?.maxToolIterations||20,openaiApiKey:a.providers?.openai?.apiKey||"",anthropicApiKey:a.providers?.anthropic?.apiKey||"",googleApiKey:a.providers?.google?.apiKey||"",qwenApiKey:a.providers?.qwen?.apiKey||"",kimiApiKey:a.providers?.kimi?.apiKey||"",minimaxApiKey:a.providers?.minimax?.apiKey||"",deepseekApiKey:a.providers?.deepseek?.apiKey||"",openrouterApiKey:a.providers?.openrouter?.apiKey||"",telegramEnabled:a.channels?.telegram?.enabled||!1,telegramToken:a.channels?.telegram?.token||"",telegramApiRoot:a.channels?.telegram?.apiRoot||"",telegramDebug:a.channels?.telegram?.debug||!1,telegramAllowFrom:(a.channels?.telegram?.allowFrom||[]).join(", "),whatsappEnabled:a.channels?.whatsapp?.enabled||!1,whatsappBridgeUrl:a.channels?.whatsapp?.bridgeUrl||"ws://localhost:3001",whatsappAllowFrom:(a.channels?.whatsapp?.allowFrom||[]).join(", "),heartbeatEnabled:a.gateway?.heartbeat?.enabled??!0,heartbeatIntervalMs:a.gateway?.heartbeat?.intervalMs||6e4}}}}catch(s){console.error("Failed to load settings:",s)}finally{this._loading=!1}}_loadUiSettings(){try{return{token:localStorage.getItem("xopcbot.token")||""}}catch{return{token:""}}}_saveUiSettings(e){try{localStorage.setItem("xopcbot.token",e)}catch(t){console.error("Failed to save UI settings:",t)}}async _loadServerToken(){try{const e=window.location.origin,t=this.config?.token,s=await fetch(`${e}/api/auth/token`,{headers:t?{Authorization:`Bearer ${t}`}:{}});if(s.ok){const i=await s.json();i.ok&&i.payload?.token&&(this._serverToken=i.payload.token)}}catch(e){console.error("Failed to load server token:",e)}}async _refreshServerToken(){this._refreshingToken=!0;try{const e=window.location.origin,t=this.config?.token,s=await fetch(`${e}/api/auth/token/refresh`,{method:"POST",headers:t?{Authorization:`Bearer ${t}`}:{}});if(s.ok){const i=await s.json();i.ok&&i.payload?.token&&(this._serverToken=i.payload.token,this._values.gatewayToken=i.payload.token,this._saveUiSettings(i.payload.token),this.requestUpdate(),alert("Token refreshed successfully! Please copy the new token and update any other clients."))}else{const i=await s.json();throw new Error(i.error||"Failed to refresh token")}}catch(e){console.error("Failed to refresh token:",e),alert(e instanceof Error?e.message:"Failed to refresh token")}finally{this._refreshingToken=!1,this.requestUpdate()}}async _loadModels(){try{const e=window.location.origin,t=this.config?.token,s=await fetch(`${e}/api/models`,{headers:t?{Authorization:`Bearer ${t}`}:{}});if(s.ok){const i=await s.json();i.payload?.models&&(this._models=i.payload.models)}}catch(e){console.error("Failed to load models:",e)}}async _saveSettings(){if(this._errors.size>0)return;this._saving=!0,this._saveSuccess=!1;const e=window.location.origin,t=this.config?.token,s={};(this._dirtyFields.has("model")||this._dirtyFields.has("maxTokens")||this._dirtyFields.has("temperature")||this._dirtyFields.has("maxToolIterations")||this._dirtyFields.has("workspace"))&&(s.agents={defaults:{}},this._dirtyFields.has("model")&&(s.agents.defaults.model=this._values.model),this._dirtyFields.has("workspace")&&(s.agents.defaults.workspace=this._values.workspace),this._dirtyFields.has("maxTokens")&&(s.agents.defaults.maxTokens=Number(this._values.maxTokens)),this._dirtyFields.has("temperature")&&(s.agents.defaults.temperature=Number(this._values.temperature)),this._dirtyFields.has("maxToolIterations")&&(s.agents.defaults.maxToolIterations=Number(this._values.maxToolIterations))),["openaiApiKey","anthropicApiKey","googleApiKey","qwenApiKey","kimiApiKey","minimaxApiKey","deepseekApiKey","openrouterApiKey"].filter(a=>this._dirtyFields.has(a)).length>0&&(s.providers={},this._dirtyFields.has("openaiApiKey")&&(s.providers.openai={apiKey:this._values.openaiApiKey}),this._dirtyFields.has("anthropicApiKey")&&(s.providers.anthropic={apiKey:this._values.anthropicApiKey}),this._dirtyFields.has("googleApiKey")&&(s.providers.google={apiKey:this._values.googleApiKey}),this._dirtyFields.has("qwenApiKey")&&(s.providers.qwen={apiKey:this._values.qwenApiKey}),this._dirtyFields.has("kimiApiKey")&&(s.providers.kimi={apiKey:this._values.kimiApiKey}),this._dirtyFields.has("minimaxApiKey")&&(s.providers.minimax={apiKey:this._values.minimaxApiKey}),this._dirtyFields.has("deepseekApiKey")&&(s.providers.deepseek={apiKey:this._values.deepseekApiKey}),this._dirtyFields.has("openrouterApiKey")&&(s.providers.openrouter={apiKey:this._values.openrouterApiKey})),(this._dirtyFields.has("telegramEnabled")||this._dirtyFields.has("whatsappEnabled")||this._dirtyFields.has("telegramToken")||this._dirtyFields.has("telegramApiRoot")||this._dirtyFields.has("telegramDebug")||this._dirtyFields.has("telegramAllowFrom")||this._dirtyFields.has("whatsappBridgeUrl")||this._dirtyFields.has("whatsappAllowFrom"))&&(s.channels={},(this._dirtyFields.has("telegramEnabled")||this._dirtyFields.has("telegramToken")||this._dirtyFields.has("telegramApiRoot")||this._dirtyFields.has("telegramDebug")||this._dirtyFields.has("telegramAllowFrom"))&&(s.channels={...s.channels,telegram:{}},this._dirtyFields.has("telegramEnabled")&&(s.channels.telegram.enabled=!!this._values.telegramEnabled),this._dirtyFields.has("telegramToken")&&(s.channels.telegram.token=this._values.telegramToken),this._dirtyFields.has("telegramApiRoot")&&(s.channels.telegram.apiRoot=this._values.telegramApiRoot||void 0),this._dirtyFields.has("telegramDebug")&&(s.channels.telegram.debug=!!this._values.telegramDebug),this._dirtyFields.has("telegramAllowFrom")&&(s.channels.telegram.allowFrom=this._values.telegramAllowFrom?this._values.telegramAllowFrom.split(",").map(a=>a.trim()).filter(a=>a):[])),(this._dirtyFields.has("whatsappEnabled")||this._dirtyFields.has("whatsappBridgeUrl")||this._dirtyFields.has("whatsappAllowFrom"))&&(s.channels={...s.channels,whatsapp:{}},this._dirtyFields.has("whatsappEnabled")&&(s.channels.whatsapp.enabled=!!this._values.whatsappEnabled),this._dirtyFields.has("whatsappBridgeUrl")&&(s.channels.whatsapp.bridgeUrl=this._values.whatsappBridgeUrl),this._dirtyFields.has("whatsappAllowFrom")&&(s.channels.whatsapp.allowFrom=this._values.whatsappAllowFrom?this._values.whatsappAllowFrom.split(",").map(a=>a.trim()).filter(a=>a):[]))),(this._dirtyFields.has("heartbeatEnabled")||this._dirtyFields.has("heartbeatIntervalMs"))&&(s.gateway={heartbeat:{}},this._dirtyFields.has("heartbeatEnabled")&&(s.gateway.heartbeat.enabled=!!this._values.heartbeatEnabled),this._dirtyFields.has("heartbeatIntervalMs")&&(s.gateway.heartbeat.intervalMs=Number(this._values.heartbeatIntervalMs)));try{const a=await fetch(`${e}/api/config`,{method:"PATCH",headers:{"Content-Type":"application/json",...t?{Authorization:`Bearer ${t}`}:{}},body:JSON.stringify(s)});if(!a.ok){const l=await a.json();throw new Error(l.error||"Failed to save settings")}this._dirtyFields.clear(),this._dirtyFields.has("gatewayToken")&&this._saveUiSettings(this._values.gatewayToken||""),this._saveSuccess=!0,setTimeout(()=>{this._saveSuccess=!1},3e3)}catch(a){console.error("Failed to save settings:",a),alert(a instanceof Error?a.message:"Failed to save settings")}finally{this._saving=!1}}_handleInput(e,t){this._values={...this._values,[e]:t},this._dirtyFields.add(e),this.requestUpdate()}render(){return o`
|
|
1651
1653
|
<div class="settings-page">
|
|
1652
1654
|
<div class="settings-sidebar">
|
|
1653
1655
|
<div class="sidebar-header">
|
|
1654
|
-
<h3>${
|
|
1656
|
+
<h3>${r("settings.title")}</h3>
|
|
1655
1657
|
</div>
|
|
1656
1658
|
<nav class="sidebar-nav">
|
|
1657
1659
|
${this._sections.map(e=>o`
|
|
@@ -1659,7 +1661,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1659
1661
|
class="nav-item ${this._activeSection===e.id?"active":""}"
|
|
1660
1662
|
@click=${()=>this._activeSection=e.id}
|
|
1661
1663
|
>
|
|
1662
|
-
${
|
|
1664
|
+
${d(e.icon)}
|
|
1663
1665
|
<span>${e.title}</span>
|
|
1664
1666
|
</button>
|
|
1665
1667
|
`)}
|
|
@@ -1670,7 +1672,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1670
1672
|
${this._loading?o`
|
|
1671
1673
|
<div class="loading-state">
|
|
1672
1674
|
<div class="spinner"></div>
|
|
1673
|
-
<p>${
|
|
1675
|
+
<p>${r("settings.loading")}</p>
|
|
1674
1676
|
</div>
|
|
1675
1677
|
`:this._renderSection()}
|
|
1676
1678
|
</div>
|
|
@@ -1678,7 +1680,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1678
1680
|
<!-- Save button floating -->
|
|
1679
1681
|
${this._dirtyFields.size>0?o`
|
|
1680
1682
|
<div class="floating-save">
|
|
1681
|
-
<span class="dirty-count">${
|
|
1683
|
+
<span class="dirty-count">${r("settings.unsaved",{count:this._dirtyFields.size})}</span>
|
|
1682
1684
|
<button
|
|
1683
1685
|
class="btn btn-primary"
|
|
1684
1686
|
?disabled=${this._saving||this._errors.size>0}
|
|
@@ -1686,26 +1688,74 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1686
1688
|
>
|
|
1687
1689
|
${this._saving?o`
|
|
1688
1690
|
<span class="spinner-sm"></span>
|
|
1689
|
-
${
|
|
1691
|
+
${r("settings.saving")}
|
|
1690
1692
|
`:o`
|
|
1691
|
-
<span>${
|
|
1692
|
-
${
|
|
1693
|
+
<span>${d("save")}</span>
|
|
1694
|
+
${r("settings.saveChanges")}
|
|
1693
1695
|
`}
|
|
1694
1696
|
</button>
|
|
1695
1697
|
</div>
|
|
1696
1698
|
`:""}
|
|
1697
1699
|
</div>
|
|
1698
|
-
`}_renderSection(){const e=this._sections.find(s=>s.id===this._activeSection);if(!e)return o`<div>${
|
|
1700
|
+
`}_renderSection(){const e=this._sections.find(s=>s.id===this._activeSection);if(!e)return o`<div>${r("settings.noSection")}</div>`;const t=`settings.descriptions.${e.id}`;return o`
|
|
1699
1701
|
<div class="section-content">
|
|
1700
1702
|
<div class="section-header">
|
|
1701
1703
|
<h2>${e.title}</h2>
|
|
1702
|
-
<p class="section-desc">${
|
|
1704
|
+
<p class="section-desc">${r(t)}</p>
|
|
1703
1705
|
</div>
|
|
1704
1706
|
|
|
1707
|
+
${e.id==="gateway"?this._renderGatewaySection():""}
|
|
1708
|
+
|
|
1705
1709
|
<div class="fields-grid">
|
|
1706
1710
|
${e.fields.map(s=>this._renderField(s))}
|
|
1707
1711
|
</div>
|
|
1708
1712
|
</div>
|
|
1713
|
+
`}_renderGatewaySection(){const e=this._serverToken?`${this._serverToken.slice(0,8)}...${this._serverToken.slice(-8)}`:"Not available";return o`
|
|
1714
|
+
<div class="gateway-token-section" style="margin-bottom: 24px; padding: 16px; background: var(--muted); border-radius: 8px;">
|
|
1715
|
+
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px;">
|
|
1716
|
+
<h4 style="margin: 0; font-size: 14px; font-weight: 600;">Server Authentication Token</h4>
|
|
1717
|
+
<button
|
|
1718
|
+
class="btn btn-sm btn-secondary"
|
|
1719
|
+
?disabled=${this._refreshingToken}
|
|
1720
|
+
@click=${this._refreshServerToken}
|
|
1721
|
+
style="display: flex; align-items: center; gap: 6px;"
|
|
1722
|
+
>
|
|
1723
|
+
${this._refreshingToken?o`
|
|
1724
|
+
<span class="spinner-sm"></span>
|
|
1725
|
+
Refreshing...
|
|
1726
|
+
`:o`
|
|
1727
|
+
${d("refreshCw")}
|
|
1728
|
+
Refresh Token
|
|
1729
|
+
`}
|
|
1730
|
+
</button>
|
|
1731
|
+
</div>
|
|
1732
|
+
|
|
1733
|
+
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 8px;">
|
|
1734
|
+
<code style="flex: 1; padding: 8px 12px; background: var(--background); border-radius: 4px; font-family: monospace; font-size: 13px; word-break: break-all;">
|
|
1735
|
+
${this._showToken?this._serverToken||"Not available":e}
|
|
1736
|
+
</code>
|
|
1737
|
+
<button
|
|
1738
|
+
class="btn btn-icon"
|
|
1739
|
+
@click=${()=>this._showToken=!this._showToken}
|
|
1740
|
+
title=${this._showToken?"Hide token":"Show token"}
|
|
1741
|
+
>
|
|
1742
|
+
${this._showToken?d("eyeOff"):d("eye")}
|
|
1743
|
+
</button>
|
|
1744
|
+
<button
|
|
1745
|
+
class="btn btn-icon"
|
|
1746
|
+
?disabled=${!this._serverToken}
|
|
1747
|
+
@click=${()=>{this._serverToken&&(navigator.clipboard.writeText(this._serverToken),alert("Token copied to clipboard!"))}}
|
|
1748
|
+
title="Copy token"
|
|
1749
|
+
>
|
|
1750
|
+
${d("copy")}
|
|
1751
|
+
</button>
|
|
1752
|
+
</div>
|
|
1753
|
+
|
|
1754
|
+
<p style="margin: 0; font-size: 12px; color: var(--muted-foreground);">
|
|
1755
|
+
This is the current server token. Click "Refresh Token" to generate a new one.
|
|
1756
|
+
After refreshing, copy the new token and update your client configuration.
|
|
1757
|
+
</p>
|
|
1758
|
+
</div>
|
|
1709
1759
|
`}_renderField(e){const t=this._values[e.key],s=this._errors.get(e.key);return o`
|
|
1710
1760
|
<div class="field-group ${s?"has-error":""}">
|
|
1711
1761
|
<div class="field-header">
|
|
@@ -1756,19 +1806,87 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1756
1806
|
@change=${s=>this._handleInput(e.key,s.target.checked)}
|
|
1757
1807
|
/>
|
|
1758
1808
|
<span class="toggle-switch"></span>
|
|
1759
|
-
<span class="toggle-text">${e.description||
|
|
1809
|
+
<span class="toggle-text">${e.description||r("settings.enableFeature")}</span>
|
|
1760
1810
|
</label>
|
|
1761
|
-
`}};
|
|
1811
|
+
`}};P([u({attribute:!1})],E.prototype,"config",2);P([c()],E.prototype,"_activeSection",2);P([c()],E.prototype,"_loading",2);P([c()],E.prototype,"_saving",2);P([c()],E.prototype,"_refreshingToken",2);P([c()],E.prototype,"_serverToken",2);P([c()],E.prototype,"_showToken",2);P([c()],E.prototype,"_dirtyFields",2);P([c()],E.prototype,"_errors",2);P([c()],E.prototype,"_saveSuccess",2);P([c()],E.prototype,"_models",2);P([c()],E.prototype,"_values",2);E=P([k("settings-page")],E);var _i=Object.defineProperty,mi=Object.getOwnPropertyDescriptor,le=(e,t,s,i)=>{for(var n=i>1?void 0:i?mi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&_i(t,s,n),n};let X=class extends y{constructor(){super(...arguments),this._token="",this._showToken=!1,this._loading=!1,this._error=""}createRenderRoot(){return this}_handleSave(){if(!this._token.trim()){this._error="Please enter a token";return}this.config?.onSave(this._token.trim())}_handleKeydown(e){e.key==="Enter"&&this._handleSave()}render(){return o`
|
|
1812
|
+
<div class="token-dialog-overlay" @click=${this._handleOverlayClick}>
|
|
1813
|
+
<div class="token-dialog" @click=${e=>e.stopPropagation()}>
|
|
1814
|
+
<div class="token-dialog-header">
|
|
1815
|
+
<h3>🔐 Authentication Required</h3>
|
|
1816
|
+
<p>Please enter your gateway authentication token to continue.</p>
|
|
1817
|
+
</div>
|
|
1818
|
+
|
|
1819
|
+
<div class="token-dialog-body">
|
|
1820
|
+
<div class="field-group">
|
|
1821
|
+
<label class="field-label">Gateway URL</label>
|
|
1822
|
+
<input
|
|
1823
|
+
type="text"
|
|
1824
|
+
class="text-input"
|
|
1825
|
+
.value=${this.config?.serverUrl||""}
|
|
1826
|
+
disabled
|
|
1827
|
+
/>
|
|
1828
|
+
</div>
|
|
1829
|
+
|
|
1830
|
+
<div class="field-group">
|
|
1831
|
+
<label class="field-label">Token</label>
|
|
1832
|
+
<div class="token-input-wrapper">
|
|
1833
|
+
<input
|
|
1834
|
+
type=${this._showToken?"text":"password"}
|
|
1835
|
+
class="text-input"
|
|
1836
|
+
.value=${this._token}
|
|
1837
|
+
placeholder="Enter your gateway token (e.g., ea4c67bf...)"
|
|
1838
|
+
@input=${e=>{this._token=e.target.value,this._error=""}}
|
|
1839
|
+
@keydown=${this._handleKeydown}
|
|
1840
|
+
/>
|
|
1841
|
+
<button
|
|
1842
|
+
class="btn btn-icon toggle-visibility"
|
|
1843
|
+
@click=${()=>this._showToken=!this._showToken}
|
|
1844
|
+
title=${this._showToken?"Hide token":"Show token"}
|
|
1845
|
+
>
|
|
1846
|
+
${this._showToken?d("eyeOff"):d("eye")}
|
|
1847
|
+
</button>
|
|
1848
|
+
</div>
|
|
1849
|
+
${this._error?o`<span class="field-error">${this._error}</span>`:""}
|
|
1850
|
+
</div>
|
|
1851
|
+
|
|
1852
|
+
<div class="token-hint">
|
|
1853
|
+
<p>💡 <strong>How to get your token:</strong></p>
|
|
1854
|
+
<ol>
|
|
1855
|
+
<li>Run <code>xopcbot gateway token</code> in your terminal</li>
|
|
1856
|
+
<li>Or run <code>xopcbot gateway token --generate</code> to create a new one</li>
|
|
1857
|
+
<li>Copy the token and paste it here</li>
|
|
1858
|
+
</ol>
|
|
1859
|
+
</div>
|
|
1860
|
+
</div>
|
|
1861
|
+
|
|
1862
|
+
<div class="token-dialog-footer">
|
|
1863
|
+
<button
|
|
1864
|
+
class="btn btn-primary"
|
|
1865
|
+
?disabled=${this._loading}
|
|
1866
|
+
@click=${this._handleSave}
|
|
1867
|
+
>
|
|
1868
|
+
${this._loading?o`
|
|
1869
|
+
<span class="spinner-sm"></span>
|
|
1870
|
+
Connecting...
|
|
1871
|
+
`:o`
|
|
1872
|
+
${d("check")}
|
|
1873
|
+
Connect
|
|
1874
|
+
`}
|
|
1875
|
+
</button>
|
|
1876
|
+
</div>
|
|
1877
|
+
</div>
|
|
1878
|
+
</div>
|
|
1879
|
+
`}_handleOverlayClick(e){this.config?.onCancel&&this.config.onCancel()}};le([u({attribute:!1})],X.prototype,"config",2);le([c()],X.prototype,"_token",2);le([c()],X.prototype,"_showToken",2);le([c()],X.prototype,"_loading",2);le([c()],X.prototype,"_error",2);X=le([k("token-dialog")],X);function vi(){return[{label:r("nav.chat"),tabs:["chat"]},{label:r("nav.management"),tabs:["sessions","cron","logs"]},{label:r("nav.settings"),tabs:["settings"]}]}function fi(e){return r(`nav.${e}`)}const yi={chat:"messageSquare",sessions:"folderOpen",cron:"clock",logs:"fileText",settings:"settings"};function wi(e){const t=e.replace(/^#\/?chat\/?/,"");if(!t||t==="/")return{type:"recent"};const s=t.replace(/^\/?/,"");return s==="new"?{type:"new"}:s&&s.length>0?{type:"session",sessionKey:decodeURIComponent(s)}:{type:"recent"}}function ot(e){switch(e.type){case"recent":return"#/chat";case"new":return"#/chat/new";case"session":return`#/chat/${encodeURIComponent(e.sessionKey)}`}}function bi(e,t,s){const i=yi[e],n=fi(e);return o`
|
|
1762
1880
|
<button
|
|
1763
1881
|
class="nav-item ${t?"nav-item--active":""}"
|
|
1764
1882
|
@click=${s}
|
|
1765
1883
|
role="tab"
|
|
1766
1884
|
aria-selected=${t}
|
|
1767
1885
|
>
|
|
1768
|
-
<span class="nav-item__icon">${
|
|
1886
|
+
<span class="nav-item__icon">${d(i)}</span>
|
|
1769
1887
|
<span class="nav-item__text">${n}</span>
|
|
1770
1888
|
</button>
|
|
1771
|
-
`}var
|
|
1889
|
+
`}const yt="xopcbot.token",wt="xopcbot.theme",bt="xopcbot.language";function z(){try{return localStorage.getItem(yt)||""}catch{return""}}function at(e){try{localStorage.setItem(yt,e)}catch(t){console.error("Failed to save token:",t)}}function $i(){try{const e=localStorage.getItem(wt);return e==="light"||e==="dark"||e==="system"?e:"system"}catch{return"system"}}function ki(e){try{localStorage.setItem(wt,e)}catch(t){console.error("Failed to save theme:",t)}}function xi(){try{const e=localStorage.getItem(bt);return e==="en"||e==="zh"?e:"en"}catch{return"en"}}function Si(e){try{localStorage.setItem(bt,e)}catch(t){console.error("Failed to save language:",t)}}var Ai=Object.defineProperty,Ci=Object.getOwnPropertyDescriptor,O=(e,t,s,i)=>{for(var n=i>1?void 0:i?Ci(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Ai(t,s,n),n};let L=class extends y{constructor(){super(),this._gatewayConfig={url:window.location.origin,token:z()||void 0},this._activeTab="chat",this._navCollapsed=!1,this._navMobileOpen=!1,this._theme="system",this._language="en",this._chatRoute={type:"recent"},this._showTokenDialog=!1}get gatewayConfig(){return this._gatewayConfig}set gatewayConfig(e){this._gatewayConfig=e||{url:window.location.origin}}_initializeToken(){const t=new URLSearchParams(window.location.search).get("token");if(t){at(t);const i=window.location.pathname+window.location.hash;window.history.replaceState({},"",i)}const s=z();this._gatewayConfig={url:window.location.origin,token:s||void 0},this._showTokenDialog=!s}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._initializeToken(),this._loadTheme(),this._loadLanguage(),this._loadRouteFromHash(),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{this._theme==="system"&&this._applyTheme()}),window.addEventListener("languagechange",()=>{this.requestUpdate()}),window.addEventListener("hashchange",()=>{this._loadRouteFromHash()})}_loadRouteFromHash(){const e=location.hash.slice(1);if(e.startsWith("chat")){const i=wi(e);i&&(this._activeTab!=="chat"&&(this._activeTab="chat"),JSON.stringify(this._chatRoute)!==JSON.stringify(i)&&(this._chatRoute=i));return}const t=e;["sessions","cron","logs","settings"].includes(t)&&this._activeTab!==t&&(this._activeTab=t)}_switchTab(e){this._activeTab=e;let t;e==="chat"?t=ot(this._chatRoute):t=`#${e}`,location.hash!==t&&history.pushState(null,"",t),this._navMobileOpen=!1}_updateChatRoute(e){this._chatRoute=e;const t=ot(e);history.pushState(null,"",t)}_loadTheme(){this._theme=$i(),this._applyTheme()}_loadLanguage(){this._language=xi(),nt(this._language)}_applyTheme(){const e=document.documentElement;e.classList.remove("light","dark");let t=!1;this._theme==="dark"?t=!0:this._theme==="system"&&(t=window.matchMedia("(prefers-color-scheme: dark)").matches),t?e.classList.add("dark"):e.classList.add("light"),window.dispatchEvent(new CustomEvent("themechange",{detail:{theme:t?"dark":"light"}}))}_setTheme(e){this._theme=e,ki(e),this._applyTheme()}_setLanguage(e){this._language=e,nt(e),Si(e),this.requestUpdate()}_renderThemeToggle(){return o`
|
|
1772
1890
|
<div class="pill-toggle">
|
|
1773
1891
|
<button
|
|
1774
1892
|
class="pill-btn ${this._theme==="light"?"active":""}"
|
|
@@ -1825,7 +1943,11 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1825
1943
|
中
|
|
1826
1944
|
</button>
|
|
1827
1945
|
</div>
|
|
1828
|
-
`}_toggleNav(){window.innerWidth<768?this._navMobileOpen=!this._navMobileOpen:this._navCollapsed=!this._navCollapsed}_closeNavMobile(){this._navMobileOpen=!1}render(){return o`
|
|
1946
|
+
`}_toggleNav(){window.innerWidth<768?this._navMobileOpen=!this._navMobileOpen:this._navCollapsed=!this._navCollapsed}_closeNavMobile(){this._navMobileOpen=!1}_handleTokenSave(e){at(e),this._gatewayConfig={url:window.location.origin,token:e},this._showTokenDialog=!1,this.requestUpdate()}render(){return this._showTokenDialog?o`
|
|
1947
|
+
<token-dialog
|
|
1948
|
+
.config=${{serverUrl:window.location.origin,onSave:e=>this._handleTokenSave(e)}}
|
|
1949
|
+
></token-dialog>
|
|
1950
|
+
`:o`
|
|
1829
1951
|
<div class="shell ${this._activeTab==="chat"?"shell--chat":""} ${this._navCollapsed?"shell--nav-collapsed":""}">
|
|
1830
1952
|
<!-- Topbar -->
|
|
1831
1953
|
<header class="topbar">
|
|
@@ -1836,7 +1958,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1836
1958
|
title="${this._navCollapsed?"Expand sidebar":"Collapse sidebar"}"
|
|
1837
1959
|
aria-label="${this._navCollapsed?"Expand sidebar":"Collapse sidebar"}"
|
|
1838
1960
|
>
|
|
1839
|
-
<span class="nav-collapse-toggle__icon">${
|
|
1961
|
+
<span class="nav-collapse-toggle__icon">${d("menu")}</span>
|
|
1840
1962
|
</button>
|
|
1841
1963
|
|
|
1842
1964
|
<div class="brand">
|
|
@@ -1868,18 +1990,18 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1868
1990
|
<!-- Mobile Overlay Backdrop -->
|
|
1869
1991
|
${this._navMobileOpen?o`
|
|
1870
1992
|
<div class="nav-overlay" @click=${this._closeNavMobile}></div>
|
|
1871
|
-
`:
|
|
1993
|
+
`:_}
|
|
1872
1994
|
|
|
1873
1995
|
<div class="shell-main">
|
|
1874
1996
|
<!-- Sidebar Navigation -->
|
|
1875
1997
|
<aside class="nav ${this._navCollapsed?"nav--collapsed":""} ${this._navMobileOpen?"nav--mobile-open":""}">
|
|
1876
|
-
${
|
|
1998
|
+
${vi().map(e=>(e.tabs.some(t=>t===this._activeTab),o`
|
|
1877
1999
|
<div class="nav-group">
|
|
1878
2000
|
<div class="nav-label nav-label--static">
|
|
1879
2001
|
<span class="nav-label__text">${e.label}</span>
|
|
1880
2002
|
</div>
|
|
1881
2003
|
<div class="nav-group__items">
|
|
1882
|
-
${e.tabs.map(t=>
|
|
2004
|
+
${e.tabs.map(t=>bi(t,this._activeTab===t,()=>{this._switchTab(t)}))}
|
|
1883
2005
|
</div>
|
|
1884
2006
|
</div>
|
|
1885
2007
|
`))}
|
|
@@ -1887,40 +2009,40 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1887
2009
|
|
|
1888
2010
|
<!-- Main Content -->
|
|
1889
2011
|
<main class="content ${this._activeTab==="chat"?"content--chat":""}">
|
|
1890
|
-
${this._activeTab==="chat"?this._renderChat():
|
|
1891
|
-
${this._activeTab==="sessions"?this._renderSessions():
|
|
1892
|
-
${this._activeTab==="cron"?this._renderCron():
|
|
1893
|
-
${this._activeTab==="logs"?this._renderLogs():
|
|
1894
|
-
${this._activeTab==="settings"?this._renderSettings():
|
|
2012
|
+
${this._activeTab==="chat"?this._renderChat():_}
|
|
2013
|
+
${this._activeTab==="sessions"?this._renderSessions():_}
|
|
2014
|
+
${this._activeTab==="cron"?this._renderCron():_}
|
|
2015
|
+
${this._activeTab==="logs"?this._renderLogs():_}
|
|
2016
|
+
${this._activeTab==="settings"?this._renderSettings():_}
|
|
1895
2017
|
</main>
|
|
1896
2018
|
</div>
|
|
1897
2019
|
</div>
|
|
1898
|
-
`}_renderChat(){return o`
|
|
2020
|
+
`}_renderChat(){const e=z();return o`
|
|
1899
2021
|
<xopcbot-gateway-chat
|
|
1900
|
-
.config=${
|
|
2022
|
+
.config=${{url:window.location.origin,token:e||void 0}}
|
|
1901
2023
|
.route=${this._chatRoute}
|
|
1902
2024
|
.enableAttachments=${!0}
|
|
1903
2025
|
.enableModelSelector=${!0}
|
|
1904
2026
|
.enableThinkingSelector=${!0}
|
|
1905
|
-
@route-change=${
|
|
2027
|
+
@route-change=${t=>this._updateChatRoute(t.detail)}
|
|
1906
2028
|
></xopcbot-gateway-chat>
|
|
1907
|
-
`}_renderSessions(){const e=
|
|
2029
|
+
`}_renderSessions(){const e=z()||this._gatewayConfig?.token;return o`
|
|
1908
2030
|
<session-manager
|
|
1909
|
-
.config=${{
|
|
2031
|
+
.config=${{token:e}}
|
|
1910
2032
|
></session-manager>
|
|
1911
|
-
`}_renderCron(){const e=
|
|
2033
|
+
`}_renderCron(){const e=z()||this._gatewayConfig?.token;return o`
|
|
1912
2034
|
<cron-manager
|
|
1913
|
-
.config=${{
|
|
2035
|
+
.config=${{token:e}}
|
|
1914
2036
|
></cron-manager>
|
|
1915
|
-
`}_renderLogs(){const e=
|
|
2037
|
+
`}_renderLogs(){const e=z()||this._gatewayConfig?.token;return o`
|
|
1916
2038
|
<log-manager
|
|
1917
|
-
.config=${{
|
|
2039
|
+
.config=${{token:e}}
|
|
1918
2040
|
></log-manager>
|
|
1919
|
-
`}_renderSettings(){const e=
|
|
2041
|
+
`}_renderSettings(){const e=z()||this._gatewayConfig?.token;return o`
|
|
1920
2042
|
<settings-page
|
|
1921
|
-
.config=${{
|
|
2043
|
+
.config=${{token:e}}
|
|
1922
2044
|
></settings-page>
|
|
1923
|
-
`}showChat(){this._activeTab="chat"}get chatElement(){return this._chatElement}};
|
|
2045
|
+
`}showChat(){this._activeTab="chat"}get chatElement(){return this._chatElement}};O([c()],L.prototype,"_gatewayConfig",2);O([c()],L.prototype,"_activeTab",2);O([c()],L.prototype,"_navCollapsed",2);O([c()],L.prototype,"_navMobileOpen",2);O([c()],L.prototype,"_theme",2);O([c()],L.prototype,"_language",2);O([c()],L.prototype,"_chatRoute",2);O([c()],L.prototype,"_showTokenDialog",2);O([oe("xopcbot-gateway-chat")],L.prototype,"_chatElement",2);L=O([k("xopcbot-app")],L);var Ti=Object.defineProperty,Mi=Object.getOwnPropertyDescriptor,R=(e,t,s,i)=>{for(var n=i>1?void 0:i?Mi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Ti(t,s,n),n};let D=class extends y{constructor(){super(...arguments),this.sections=[],this.values={},this.loading=!1,this._activeSection="",this._dirtyFields=new Set,this._showPasswords=new Set,this._errors=new Map}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this._updateActiveSection()}willUpdate(e){e.has("sections")&&this._updateActiveSection()}_updateActiveSection(){this.sections.length>0&&!this._activeSection&&(this._activeSection=this.sections[0].id)}_getIcon(e){return{user:o`<User class="w-5 h-5" />`,bot:o`<Bot class="w-5 h-5" />`,plug:o`<Plug class="w-5 h-5" />`,globe:o`<Globe class="w-5 h-5" />`,search:o`<Search class="w-5 h-5" />`,clock:o`<Clock class="w-5 h-5" />`,puzzle:o`<Puzzle class="w-5 h-5" />`,settings:o`<Settings class="w-5 h-5" />`}[e]||o`<Settings class="w-5 h-5" />`}render(){return o`
|
|
1924
2046
|
<div class="settings-overlay" @click=${e=>e.target===e.currentTarget&&this.onClose?.()}>
|
|
1925
2047
|
<div class="settings-dialog">
|
|
1926
2048
|
${this.renderHeader()}
|
|
@@ -1954,19 +2076,19 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1954
2076
|
</button>
|
|
1955
2077
|
`)}
|
|
1956
2078
|
</nav>
|
|
1957
|
-
`}renderMain(){const e=this.sections.find(s=>s.id===this._activeSection);if(!e)return o`<div class="settings-main">${
|
|
2079
|
+
`}renderMain(){const e=this.sections.find(s=>s.id===this._activeSection);if(!e)return o`<div class="settings-main">${r("settings.noSection")}</div>`;const t=`settings.descriptions.${e.id}`;return o`
|
|
1958
2080
|
<div class="settings-main">
|
|
1959
2081
|
<div class="section-header">
|
|
1960
2082
|
<h2>${e.title}</h2>
|
|
1961
|
-
<p class="section-description">${
|
|
2083
|
+
<p class="section-description">${r(t)}</p>
|
|
1962
2084
|
</div>
|
|
1963
2085
|
|
|
1964
2086
|
<div class="fields-grid">
|
|
1965
2087
|
${e.fields.map(s=>this.renderField(s,e.id))}
|
|
1966
2088
|
</div>
|
|
1967
2089
|
</div>
|
|
1968
|
-
`}renderField(e,t){const s=`${t}.${e.key}`,i=this._getValue(e.key),n=this._dirtyFields.has(s),
|
|
1969
|
-
<div class="field-group ${
|
|
2090
|
+
`}renderField(e,t){const s=`${t}.${e.key}`,i=this._getValue(e.key),n=this._dirtyFields.has(s),a=this._errors.get(s),l=this._showPasswords.has(s);return o`
|
|
2091
|
+
<div class="field-group ${a?"has-error":""}">
|
|
1970
2092
|
<div class="field-header">
|
|
1971
2093
|
<label class="field-label">${e.label}</label>
|
|
1972
2094
|
${e.validation?.required?o`<span class="required-mark">*</span>`:""}
|
|
@@ -1982,15 +2104,15 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
1982
2104
|
|
|
1983
2105
|
${["text","password","number"].includes(e.type)?this.renderInputField(e,i,s,l):""}
|
|
1984
2106
|
|
|
1985
|
-
${
|
|
2107
|
+
${a?o`
|
|
1986
2108
|
<div class="field-error">
|
|
1987
2109
|
<AlertCircle class="w-4 h-4" />
|
|
1988
|
-
<span>${
|
|
2110
|
+
<span>${a}</span>
|
|
1989
2111
|
</div>
|
|
1990
2112
|
`:""}
|
|
1991
2113
|
|
|
1992
|
-
${n&&!
|
|
1993
|
-
<div class="field-dirty">${
|
|
2114
|
+
${n&&!a?o`
|
|
2115
|
+
<div class="field-dirty">${r("settings.unsavedChanges")}</div>
|
|
1994
2116
|
`:""}
|
|
1995
2117
|
</div>
|
|
1996
2118
|
`}renderInputField(e,t,s,i){const n=e.type==="password"?i?"text":"password":e.type;return o`
|
|
@@ -2003,7 +2125,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
2003
2125
|
minlength=${e.validation?.min}
|
|
2004
2126
|
maxlength=${e.validation?.max}
|
|
2005
2127
|
pattern=${e.validation?.pattern||""}
|
|
2006
|
-
@input=${
|
|
2128
|
+
@input=${a=>this._handleInput(e,s,a.target.value)}
|
|
2007
2129
|
/>
|
|
2008
2130
|
${e.type==="password"?o`
|
|
2009
2131
|
<button
|
|
@@ -2042,12 +2164,12 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
2042
2164
|
@change=${i=>this._handleInput(e,s,i.target.checked)}
|
|
2043
2165
|
/>
|
|
2044
2166
|
<span class="toggle-switch"></span>
|
|
2045
|
-
<span class="toggle-text">${e.description||
|
|
2167
|
+
<span class="toggle-text">${e.description||r("settings.enableFeature")}</span>
|
|
2046
2168
|
</label>
|
|
2047
2169
|
`}renderFooter(){const e=this._dirtyFields.size>0;return o`
|
|
2048
2170
|
<div class="settings-footer">
|
|
2049
2171
|
<button class="btn btn-ghost" @click=${()=>this.onClose?.()}>
|
|
2050
|
-
${
|
|
2172
|
+
${r("settings.cancel")}
|
|
2051
2173
|
</button>
|
|
2052
2174
|
<button
|
|
2053
2175
|
class="btn btn-primary"
|
|
@@ -2056,14 +2178,14 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
2056
2178
|
>
|
|
2057
2179
|
${this.loading?o`
|
|
2058
2180
|
<Loader2 class="w-4 h-4 animate-spin" />
|
|
2059
|
-
${
|
|
2181
|
+
${r("settings.saving")}
|
|
2060
2182
|
`:o`
|
|
2061
2183
|
<Save class="w-4 h-4" />
|
|
2062
|
-
${
|
|
2184
|
+
${r("settings.saveChanges")}
|
|
2063
2185
|
`}
|
|
2064
2186
|
</button>
|
|
2065
2187
|
</div>
|
|
2066
|
-
`}_getValue(e){return this.values[e]}_handleInput(e,t,s){e.validation?.required&&!s?this._errors.set(t,
|
|
2188
|
+
`}_getValue(e){return this.values[e]}_handleInput(e,t,s){e.validation?.required&&!s?this._errors.set(t,r("settings.required",{field:e.label})):e.validation?.pattern&&s?new RegExp(e.validation.pattern).test(s)?this._errors.delete(t):this._errors.set(t,r("settings.invalidFormat")):this._errors.delete(t),this._dirtyFields.add(t),this.requestUpdate()}_togglePassword(e){this._showPasswords.has(e)?this._showPasswords.delete(e):this._showPasswords.add(e),this.requestUpdate()}_save(){this._errors.size>0||this.onSave&&this.onSave(this.values)}};R([u({attribute:!1})],D.prototype,"sections",2);R([u({attribute:!1})],D.prototype,"values",2);R([u({type:Boolean})],D.prototype,"loading",2);R([u({attribute:!1})],D.prototype,"onSave",2);R([u({attribute:!1})],D.prototype,"onClose",2);R([c()],D.prototype,"_activeSection",2);R([c()],D.prototype,"_dirtyFields",2);R([c()],D.prototype,"_showPasswords",2);R([c()],D.prototype,"_errors",2);D=R([k("xopcbot-settings")],D);var Ei=Object.defineProperty,Pi=Object.getOwnPropertyDescriptor,ee=(e,t,s,i)=>{for(var n=i>1?void 0:i?Pi(t,s):t,a=e.length-1,l;a>=0;a--)(l=e[a])&&(n=(i?l(t,s,n):l(n))||n);return i&&n&&Ei(t,s,n),n};let H=class extends y{constructor(){super(...arguments),this.enableAttachments=!0,this.enableModelSelector=!0,this.enableThinkingSelector=!0,this._autoScroll=!0,this._lastScrollTop=0,this._handleScroll=()=>{if(!this._scrollContainer)return;const e=this._scrollContainer.scrollTop,t=this._scrollContainer.scrollHeight,s=this._scrollContainer.clientHeight,i=t-e-s;if(s<this._lastClientHeight){this._lastClientHeight=s;return}e!==0&&e<this._lastScrollTop&&i>50?this._autoScroll=!1:i<10&&(this._autoScroll=!0),this._lastScrollTop=e,this._lastClientHeight=s}}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.style.display="flex",this.style.flexDirection="column",this.style.height="100%",this.style.minHeight="0",this.setupSessionSubscription()}disconnectedCallback(){super.disconnectedCallback(),this._resizeObserver?.disconnect(),this._scrollContainer?.removeEventListener("scroll",this._handleScroll),this._unsubscribeSession?.()}setupSessionSubscription(){this._unsubscribeSession&&this._unsubscribeSession(),this.agent&&(this._unsubscribeSession=this.agent.subscribe(async e=>{switch(e.type){case"message_start":case"message_end":case"turn_start":case"turn_end":case"agent_start":this.requestUpdate();break;case"agent_end":this._streamingContainer&&(this._streamingContainer.isStreaming=!1,this._streamingContainer.setMessage(null,!0)),this.requestUpdate();break;case"message_update":this._streamingContainer&&(this._streamingContainer.isStreaming=this.agent?.state.isStreaming||!1,this._streamingContainer.setMessage(e.message,!this._streamingContainer.isStreaming)),this.requestUpdate();break}}))}setInput(e,t){this._messageEditor&&(this._messageEditor.value=e,this._messageEditor.attachments=t||[])}setAutoScroll(e){this._autoScroll=e}async sendMessage(e,t){if(!(!e.trim()&&t?.length===0||this.agent?.state.isStreaming)){if(!this.agent)throw new Error("No agent set");if(!this.agent.state.model)throw new Error("No model set");this._messageEditor.value="",this._messageEditor.attachments=[],this._autoScroll=!0,t&&t.length>0?await this.agent.prompt({role:"user-with-attachments",content:e,attachments:t,timestamp:Date.now()}):await this.agent.prompt(e)}}renderMessages(){if(!this.agent)return o`<div class="p-4 text-center text-muted-foreground">${ie("No session available")}</div>`;const e=this.agent.state;return o`
|
|
2067
2189
|
<div class="flex flex-col gap-3">
|
|
2068
2190
|
<message-list
|
|
2069
2191
|
.messages=${this.agent.state.messages}
|
|
@@ -2080,7 +2202,7 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
2080
2202
|
.isStreaming=${e.isStreaming}
|
|
2081
2203
|
></streaming-message-container>
|
|
2082
2204
|
</div>
|
|
2083
|
-
`}render(){if(!this.agent)return o`<div class="p-4 text-center text-muted-foreground">${
|
|
2205
|
+
`}render(){if(!this.agent)return o`<div class="p-4 text-center text-muted-foreground">${ie("No agent set")}</div>`;const e=this.agent.state;return o`
|
|
2084
2206
|
<div class="flex flex-col h-full bg-background text-foreground">
|
|
2085
2207
|
<div class="flex-1 overflow-y-auto">
|
|
2086
2208
|
<div class="max-w-3xl mx-auto p-4 pb-0">${this.renderMessages()}</div>
|
|
@@ -2101,5 +2223,5 @@ This action cannot be undone.`,this._confirmOpen=!0}_handleConfirm(e){if(!e.deta
|
|
|
2101
2223
|
</div>
|
|
2102
2224
|
</div>
|
|
2103
2225
|
</div>
|
|
2104
|
-
`}};
|
|
2105
|
-
//# sourceMappingURL=main-
|
|
2226
|
+
`}};ee([u({attribute:!1})],H.prototype,"agent",2);ee([u({type:Boolean})],H.prototype,"enableAttachments",2);ee([u({type:Boolean})],H.prototype,"enableModelSelector",2);ee([u({type:Boolean})],H.prototype,"enableThinkingSelector",2);ee([oe("message-editor")],H.prototype,"_messageEditor",2);ee([oe("streaming-message-container")],H.prototype,"_streamingContainer",2);H=ee([k("xopcbot-chat")],H);
|
|
2227
|
+
//# sourceMappingURL=main-DevbZW9K.js.map
|