escobar 0.1.98__py3-none-any.whl → 0.1.99__py3-none-any.whl

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.
Files changed (28) hide show
  1. escobar/_version.py +1 -1
  2. escobar/labextension/package.json +2 -2
  3. escobar/labextension/schemas/escobar/package.json.orig +1 -1
  4. escobar/labextension/schemas/escobar/plugin.json +5 -0
  5. escobar/labextension/static/{653.a61eb8cd9cf80cfd7b4e.js → 653.8fa15689dd3bd50b26c4.js} +1 -1
  6. escobar/labextension/static/{remoteEntry.1d8a02992fa4c724ab72.js → remoteEntry.8d091bb81aa84a37e688.js} +1 -1
  7. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/package.json +2 -2
  8. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/schemas/escobar/package.json.orig +1 -1
  9. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/schemas/escobar/plugin.json +5 -0
  10. escobar-0.1.98.data/data/share/jupyter/labextensions/escobar/static/653.a61eb8cd9cf80cfd7b4e.js → escobar-0.1.99.data/data/share/jupyter/labextensions/escobar/static/653.8fa15689dd3bd50b26c4.js +1 -1
  11. escobar-0.1.98.data/data/share/jupyter/labextensions/escobar/static/remoteEntry.1d8a02992fa4c724ab72.js → escobar-0.1.99.data/data/share/jupyter/labextensions/escobar/static/remoteEntry.8d091bb81aa84a37e688.js +1 -1
  12. {escobar-0.1.98.dist-info → escobar-0.1.99.dist-info}/METADATA +1 -1
  13. {escobar-0.1.98.dist-info → escobar-0.1.99.dist-info}/RECORD +28 -28
  14. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/install.json +0 -0
  15. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/static/304.bf7e91be734e5b36cdc9.js +0 -0
  16. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/static/346.8a1e61ca6789b6fddfa7.js +0 -0
  17. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/static/379.40dd59dc19d4a6b42d25.js +0 -0
  18. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/static/57.17e53b4b9a954f39c4d8.js +0 -0
  19. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/static/648.a7d314faeacc762d891d.js +0 -0
  20. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/static/666.3bc65aac3a3be183ee19.js +0 -0
  21. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/static/874.c539726f31a1baa0267e.js +0 -0
  22. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/static/986.cbcf9d7c1cd8d06be435.js +0 -0
  23. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/static/oauth-callback.html +0 -0
  24. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/static/style.js +0 -0
  25. {escobar-0.1.98.data → escobar-0.1.99.data}/data/share/jupyter/labextensions/escobar/static/third-party-licenses.json +0 -0
  26. {escobar-0.1.98.dist-info → escobar-0.1.99.dist-info}/WHEEL +0 -0
  27. {escobar-0.1.98.dist-info → escobar-0.1.99.dist-info}/entry_points.txt +0 -0
  28. {escobar-0.1.98.dist-info → escobar-0.1.99.dist-info}/licenses/LICENSE +0 -0
@@ -1 +1 @@
1
- "use strict";(self.webpackChunkescobar=self.webpackChunkescobar||[]).push([[653],{4364:(e,t,n)=>{n.r(t),n.d(t,{default:()=>Ie});var o=n(6118),r=n(2653),i=n(5551),s=n(8968),a=n(2226),c=n(5256);class l{constructor(){this.prompt="These functions faciliate access to Jupyter Lab environment",this.tools=[]}get_prompt(){return this.prompt}get_tools(){return function(e,t="FastAPI",n="0.1.0"){const o={openapi:"3.1.0",info:{title:t,version:n},paths:{"/__prompt__":{get:{summary:"Prompt",operationId:"prompt___prompt___get",responses:{200:{description:"Successful Response",content:{"application/json":{schema:{}}}}}}}},components:{schemas:{HTTPValidationError:{properties:{detail:{items:{$ref:"#/components/schemas/ValidationError"},type:"array",title:"Detail"}},type:"object",title:"HTTPValidationError"},ValidationError:{properties:{loc:{items:{anyOf:[{type:"string"},{type:"integer"}]},type:"array",title:"Location"},msg:{type:"string",title:"Message"},type:{type:"string",title:"Error Type"}},type:"object",required:["loc","msg","type"],title:"ValidationError"}}}};return e.forEach((e=>{const t=`/${e.name}`,n=`${e.name}_${e.name}_post`,r=`Body_${e.name}_${e.name}_post`,i={properties:{},type:"object",required:[],title:r};Object.entries(e.arguments).forEach((([e,t])=>{var n;i.properties[e]={type:(n=t.type,{str:"string",int:"integer",float:"number",bool:"boolean",object:"object",array:"array"}[n]||n),title:d(e),description:t.name},void 0!==t.default&&(i.properties[e].default=t.default),!1!==t.required&&i.required.push(e)})),o.components.schemas[r]=i,o.paths[t]={post:{summary:d(e.name.split("_").join(" ")),description:e.description,operationId:n,parameters:[{name:"authorization",in:"header",required:!1,schema:{type:"string",title:"Authorization"}},{name:"oauthtoken",in:"header",required:!1,schema:{type:"string",title:"Oauthtoken"}}],requestBody:{required:!0,content:{"application/x-www-form-urlencoded":{schema:{$ref:`#/components/schemas/${r}`}}}},responses:{200:{description:"Successful Response",content:{"application/json":{schema:{}}}},422:{description:"Validation Error",content:{"application/json":{schema:{$ref:"#/components/schemas/HTTPValidationError"}}}}},"x-CPM":"1.0"}}})),o}(this.tools)}intraspect(){return console.log("-------- Intraspection called ------"),{prompt:this.get_prompt(),tools:this.get_tools()}}}function d(e){return e.split("_").map((e=>e.charAt(0).toUpperCase()+e.slice(1))).join("")}var u=n(5355),p=n(5263),g=n(8914),m=n(4461);async function h(e,t,n=!0,o=""){var r,i;const s=e.serviceManager.contents,a=t.replace(/\\/g,"/").replace(/\/+/g,"/"),c=a.split("/").filter((e=>""!==e&&"."!==e)),l=c.pop();if(c.length>0){let e="";for(const t of c){e=e?`${e}/${t}`:t;try{if("directory"!==(await s.get(e)).type)throw new Error(`${e} exists but is not a directory`)}catch(t){if(404!==(null===(r=null==t?void 0:t.response)||void 0===r?void 0:r.status)&&!/not found/i.test(t.message))throw new Error(`Failed checking/creating directory ${e}: ${t.message}`);await s.save(e,{type:"directory",format:"json",content:null})}}}if(n&&l)try{await s.get(a)}catch(e){if(404!==(null===(i=null==e?void 0:e.response)||void 0===i?void 0:i.status)&&!/not found/i.test(e.message))throw new Error(`Failed checking file ${a}: ${e.message}`);await s.save(a,{type:"file",format:"text",content:o})}}function y(e){return e.replace(/\x1b\[[0-9;?]*[a-zA-Z]/g,"")}async function f(e,t){const{terminals:n}=e.serviceManager;await n.ready;const o=await n.running(),r=Array.from(o);console.log("All available terminals:",r.map((e=>({name:e.name})))),console.log("Looking for terminal with name:",t);for(const e of r)if(e.name===t)return console.log("Found exact terminal match:",e.name),n.connectTo({model:e});if(/^\d+$/.test(t))for(const e of r)if(e.name.includes(t))return console.log("Found numeric terminal match:",e.name,"for input:",t),n.connectTo({model:e});return 1===r.length?(console.log("No match found but only one terminal exists, using:",r[0].name),n.connectTo({model:r[0]})):(console.log("No terminal found with name:",t),null)}const v={};var b=n(8178),w=n(5963),x=n(2084),S=n(9329),C=n(6609),E=n(2256),I=n(9311),k=n(2941),N=n(7425);function A(e){return null==e||""===e?"":e.replace(/\\"/g,'"').replace(/\\'/g,"'").replace(/\\\\/g,"\\").replace(/\\n/g,"\n").replace(/\\t/g,"\t").replace(/\\r/g,"\r").replace(/\\b/g,"\b").replace(/\\f/g,"\f").replace(/\\v/g,"\v").replace(/\\0/g,"\0").replace(/\\x([0-9A-Fa-f]{2})/g,((e,t)=>String.fromCharCode(parseInt(t,16)))).replace(/\\u([0-9A-Fa-f]{4})/g,((e,t)=>String.fromCharCode(parseInt(t,16)))).replace(/\\u\{([0-9A-Fa-f]+)\}/g,((e,t)=>String.fromCodePoint(parseInt(t,16)))).replace(/\\([0-3][0-7]{2}|[0-7]{1,2})/g,((e,t)=>String.fromCharCode(parseInt(t,8))))}function O(e){var t;const n=(null===(t=e.split(".").pop())||void 0===t?void 0:t.toLowerCase())||"",o=[];o.push((0,x.syntaxHighlighting)(b.jupyterHighlightStyle));let r=null;switch(n){case"py":r=(0,S.Hg)();break;case"js":r=(0,C.Q2)();break;case"ts":r=(0,C.Q2)({typescript:!0});break;case"jsx":r=(0,C.Q2)({jsx:!0});break;case"tsx":r=(0,C.Q2)({jsx:!0,typescript:!0});break;case"json":r=(0,E.Pq)();break;case"md":r=(0,I.wD)();break;case"html":case"htm":r=(0,k.qy)();break;case"css":r=(0,N.AH)()}return r?(o.push(r),console.log(`Added language support for ${n}`)):console.log(`No specific language support for ${n}, using default highlighting`),o}var T,M,P,J={},U={},_=n(1041),L={},$={};const F={};F.listFiles={def:{name:"listFiles",description:"List files and directories at a specified relative path. Ignore rootPath if it exists",arguments:{path:{type:"string",name:"Relative path to list files from. Relative!",default:"/"}}},func:async e=>{if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});const t=e.path||"/",n=T.serviceManager.contents;try{const e=await n.get(t,{content:!0});if("directory"!==e.type)return JSON.stringify({error:`Path '${t}' is not a directory`});const o=e.content.map((e=>({name:e.name,path:e.path,type:e.type,last_modified:e.last_modified})));return JSON.stringify({success:!0,files:o})}catch(e){return JSON.stringify({error:`Error listing files: ${e.message}`})}}},F.writeToFile={def:{name:"writeToFile",description:"Opens a non-notebook file for editing (code, text, etc) and write into it. Do not use for files that start with '.' (period)",arguments:{filePath:{type:"string",name:"Relative path to the file to write to. Relative! "},content:{type:"string",name:"New content for the file. Entire file is being replaced by this!"}}},func:async(e,t=!1,n=void 0)=>{if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});const{contents:o}=T.serviceManager,{filePath:r,content:i}=e;if(null==n)return JSON.stringify({status:"fail",message:"no call_id received"});let s;await h(T,r);try{s=await T.commands.execute("docmanager:open",{path:r,factory:"Editor"})}catch(e){return JSON.stringify({status:"fail",message:"could not open file",detail:`${e.message}`})}await o.save(r,{type:"file",format:"text",content:i}),null==L[n]&&(L[n]=!0);try{await Promise.race([s.context.ready,new Promise(((e,t)=>setTimeout((()=>t(new Error("Timeout waiting for context.ready"))),1500)))])}catch(e){return JSON.stringify({status:"fail",message:"could not open file"})}if(await s.context.revert(),s.content&&s.content.editor){const e=s.content.editor,t=e.model.sharedModel.source.length,n=e.getPositionAt(t);n&&(e.setCursorPosition(n),e.revealPosition(n))}return JSON.stringify({status:"ok"})}},F.openFile={def:{name:"openFile",description:"Opens a non-notebook file for editing (code, text, etc) and returns its contents. \n Never open notebooks with this method! Do not use for files that start with '.' (period)",arguments:{filePath:{type:"string",name:"Relative path to the file to open. Relative! "}}},func:async e=>{if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});const t=e.filePath;if(t.endsWith(".ipynb"))return JSON.stringify({status:"fail",message:"Cannot open notebook files with this method"});const{contents:n}=T.serviceManager;let o,r;await h(T,t);try{try{if(o=await n.get(t),o.content&&"string"==typeof o.content&&o.content.length>65536)return JSON.stringify({status:"fail",message:"File is too large (> 64KB)"})}catch(e){await n.save(t,{type:"file",format:"text",content:""}),o=await n.get(t)}}catch(e){return JSON.stringify({status:"fail",message:"could not open file",detail:`${e.message} `})}try{r=await T.commands.execute("docmanager:open",{path:t,factory:"Editor"})}catch(e){return JSON.stringify({status:"fail",message:"could not open file",detail:`${e.message} `})}try{await Promise.race([r.context.ready,new Promise(((e,t)=>setTimeout((()=>t(new Error("Timeout waiting for context.ready"))),500)))])}catch(e){return JSON.stringify({status:"fail",message:"could not open file"})}return JSON.stringify({status:"ok",content:o.content})}},F.startTerminal={def:{name:"startTerminal",description:"Opens a command line terminal",arguments:{}},func:async e=>{const t=T.serviceManager.terminals,n=await t.startNew();return await T.commands.execute("terminal:open",{name:n.name}),v[n.name]="",n.messageReceived.connect(((e,t)=>{if("stdout"===t.type&&Array.isArray(t.content))for(var o=0;o<t.content.length;o++){const e=y(t.content[o]);v[n.name]+=e}})),JSON.stringify({staus:"ok",terminal_name:n.name})}},F.runCommandInTerminal={def:{name:"runCommandInTerminal",description:"Runs a command in a terminal. This will block until the command ends, only use for very short-lived tasks!",arguments:{name:{type:"string",name:"Name for the terminal to run the command in"},command:{type:"string",name:"Command to run in the terminal. Make sure to properly escape control sequnces like '!' "},timeout:{type:"integer",name:"Timeout in milliseconds, default 10000"}}},func:async e=>{let t=e.name||"";const n=e.command||"",o=e.timeout||6e4;if(console.log(`Attempting to run command in terminal: ${t}`),t.startsWith("{")&&t.endsWith("}"))try{const e=JSON.parse(t);e.name&&(t=e.name,console.log(`Parsed terminal name from JSON: ${t}`))}catch(e){console.log(`Failed to parse terminal name as JSON: ${e.message}`)}const{terminals:r}=T.serviceManager;if(!t){const e=await r.running(),n=Array.from(e);n.length>0?(t=n[0].name,console.log(`No terminal name provided, using first available: ${t}`)):(console.log("No terminals available, creating a new one"),t=(await r.startNew()).name,await T.commands.execute("terminal:open",{name:t}),await new Promise((e=>setTimeout(e,1e3))))}const i=await f(T,t);if(null===i)return JSON.stringify({status:"failure",message:`Terminal with name ${t} not found`});await T.commands.execute("terminal:open",{name:t});const s=(0,u.lk)(),a=new Promise((e=>{i.messageReceived.connect(((t,n)=>{if("stdout"===n.type)if(Array.isArray(n.content))for(var o=0;o<n.content.length;o++){const t=y(n.content[o]);l+=t,t.includes(`__${s}__`)&&(d=!0,e())}else console.log("> >",n);else console.log("> >",n)}))})),c=new Promise((e=>setTimeout(e,o)));var l="",d=!1;i.send({type:"stdin",content:[`${n} ; echo "cwd: $(pwd)"; echo __${s}__ \n`]}),await Promise.race([a,c]);const p=function(e,t){const n=e.indexOf(t);if(-1===n)return"";const o=e.indexOf(t,n+t.length);if(-1===o){const o=e.substring(n+t.length).trim();return o.length<16?e.substring(0,n).slice(-16e3).trim():o.slice(-16e3)}return e.substring(n+t.length,o).trim().slice(-16e3)}(l,`__${s}__`);return JSON.stringify({status:"success",stop:d?"natural":"timeout",result:p.trim()})}},F.runCommandInTerminalAsync={def:{name:"runCommandInTerminalAsync",description:"Runs a command in a terminal without waiting for completion. \n Returns immediately with 'ok' status. \n Use this for long-running commands where you don't need to wait for the result.\n Always check the terminal output before sending new commands to this terminal!",arguments:{name:{type:"string",name:"Name for the terminal to run the command in"},command:{type:"string",name:"Command to send to the terminal. Mak sur to proprly escape contol sequences like '!' "}}},func:async e=>{let t=e.name||"";const n=e.command||"";if(console.log(`Attempting to run command asynchronously in terminal: ${t}`),t.startsWith("{")&&t.endsWith("}"))try{const e=JSON.parse(t);e.name&&(t=e.name,console.log(`Parsed terminal name from JSON: ${t}`))}catch(e){console.log(`Failed to parse terminal name as JSON: ${e.message}`)}const{terminals:o}=T.serviceManager;if(!t){const e=await o.running(),n=Array.from(e);n.length>0?(t=n[0].name,console.log(`No terminal name provided, using first available: ${t}`)):(console.log("No terminals available, creating a new one"),t=(await o.startNew()).name,await T.commands.execute("terminal:open",{name:t}),await new Promise((e=>setTimeout(e,1e3))))}const r=await f(T,t);return null===r?JSON.stringify({status:"failure",message:`Terminal with name ${t} not found`}):(await T.commands.execute("terminal:open",{name:t}),r.send({type:"stdin",content:[`${n}\n`]}),JSON.stringify({status:"success",message:"Command sent to terminal"}))}},F.sendCommandToAsyncTerminal={def:{name:"sendCommandToAsyncTerminal",description:"Sends a command to an existing async terminal without waiting for completion. Use this to send additional commands to terminals started with runCommandInTerminalAsync.",arguments:{name:{type:"string",name:"Name of the terminal to send the command to"},command:{type:"string",name:"Command to send to the terminal"}}},func:async e=>{let t=e.name||"";const n=e.command||"";if(console.log(`Sending command to async terminal: ${t}`),t.startsWith("{")&&t.endsWith("}"))try{const e=JSON.parse(t);e.name&&(t=e.name,console.log(`Parsed terminal name from JSON: ${t}`))}catch(e){console.log(`Failed to parse terminal name as JSON: ${e.message}`)}const o=await f(T,t);return null===o?JSON.stringify({status:"failure",message:`Terminal with name ${t} not found`}):(await T.commands.execute("terminal:open",{name:t}),o.send({type:"stdin",content:[`${n}\n`]}),JSON.stringify({status:"success",message:"Command sent to terminal"}))}},F.getAsyncTerminalOutput={def:{name:"getAsyncTerminalOutput",description:"Retrieves the current output from an async terminal. Use this to check progress or results from terminals started with runCommandInTerminalAsync.",arguments:{name:{type:"string",name:"Name of the terminal to get output from"},clear:{type:"boolean",name:"Whether to clear the output buffer after retrieving (default: false)"}}},func:async e=>{let t=e.name||"";const n=e.clear||!1;if(t.startsWith("{")&&t.endsWith("}"))try{const e=JSON.parse(t);e.name&&(t=e.name,console.log(`Parsed terminal name from JSON: ${t}`))}catch(e){console.log(`Failed to parse terminal name as JSON: ${e.message}`)}if(null===await f(T,t))return JSON.stringify({status:"failure",message:`Terminal with name ${t} not found`});const o=v[t]||"";return n&&(v[t]=""),JSON.stringify({status:"success",output:o})}},F.insertExecuteCell={def:{name:"insertExecuteCell",description:"Index at which to place the new cell",arguments:{index:{type:"integer",name:"New cel lindex"},cellType:{type:"string",name:"Type of the cell being edited (code/markdown)"},content:{type:"string",name:"New content for the cell"}}},func:async(e,t=!1,n=void 0)=>{var{index:o,cellType:r,content:i}=e;const s=M.currentWidget;T.shell.activateById(s.id);const a=s.content;var c=(o="string"==typeof o?parseInt(o,10):o)<=0?0:o;if(null==L[n]?(L[n]=o,function(e,t,n){var o=n;n<=0?(e.activeCellIndex=0,p.NotebookActions.insertAbove(e),o=0,e.activeCellIndex=o,p.NotebookActions.changeCellType(e,t)):(e.activeCellIndex=n-1,p.NotebookActions.insertBelow(e),o=n,e.activeCellIndex=o,p.NotebookActions.changeCellType(e,t))}(a,r,o)):a.activeCellIndex=c,"edit"!=a.mode&&(a.activate(),a.mode="edit"),!t){const t=a.activeCell;if(null==u.gb[n]&&t.node.scrollIntoView({behavior:"smooth",block:"end"}),t.model.sharedModel.setSource(e.content),a.mode="command",t instanceof g.MarkdownCell)return t.rendered=!0,await s.context.save(),"ok";{await p.NotebookActions.run(a,s.sessionContext);const e=await F.getCellOutput.func({index:o,scroll:!1});return t instanceof g.CodeCell&&t.outputArea.node.scrollIntoView({behavior:"smooth",block:"end"}),await s.context.save(),e}}{const t=a.activeCell;t.node.scrollIntoView({behavior:"smooth",block:"end"}),t.model.sharedModel.setSource(e.content),t instanceof g.MarkdownCell&&(t.rendered=!0)}return"ok"}},F.editExecuteCell={def:{name:"editExecuteCell",description:"Edit the content of a cell by index and execute (render) it. Do not use if no edits required",arguments:{index:{type:"integer",name:"Index of the cell to edit"},cellType:{type:"string",name:"Type of the cell being edited"},content:{type:"string",name:"New content for the cell"}}},func:async(e,t=!1,n=void 0)=>{if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});var{index:o,cellType:r,content:i}=e;o="string"==typeof o?parseInt(o,10):o;try{const n=M.currentWidget;T.shell.activateById(n.id);const i=n.content;i.activeCellIndex=o;const s=i.activeCell;return s.node.scrollIntoView({behavior:"smooth",block:"end"}),s instanceof g.CodeCell&&p.NotebookActions.clearOutputs(i),p.NotebookActions.changeCellType(i,r),"edit"!=i.mode&&(i.activate(),i.mode="edit"),s.model.sharedModel.setSource(e.content),s instanceof g.MarkdownCell?(s.rendered=!0,"ok"):t?"ok":(await n.context.save(),await p.NotebookActions.run(i,n.sessionContext),await F.getCellOutput.func({index:o,scroll:!0}))}catch(e){return JSON.stringify({error:`Error editing cell: ${e.message}`})}}},F.executeCell={def:{name:"executeCell",description:"Execute a cell by index. Use when no code change were made to the cell",arguments:{index:{type:"integer",name:"Index of the cell to execute"},maxWaitTime:{type:"integer",name:"Maximum time to wait for execution or breakpoint (ms)",optional:!0}}},func:async e=>{var{index:t,maxWaitTime:n}=e;t="string"==typeof t?parseInt(t,10):t,n="string"==typeof n?parseInt(n,10):n;const o=M.currentWidget;if(!o)return JSON.stringify({error:"No active notebook"});T.shell.activateById(o.id);const r=o.content;r.activeCellIndex=t;const i=r.activeCell;if(i.node.scrollIntoView({behavior:"smooth",block:"center"}),i instanceof g.MarkdownCell)return i.rendered=!0,"ok";{p.NotebookActions.run(r,o.sessionContext);const e=await F.waitForDebugger.func({index:t,maxWaitTime:n}),s=JSON.parse(e);if(s.completed){const e=await F.getCellOutput.func({index:t,scroll:!1});return i instanceof g.CodeCell&&i.outputArea.node.scrollIntoView({behavior:"smooth",block:"start"}),e}return s.breakpointHit?JSON.stringify({success:!0,message:"Execution paused at breakpoint",debuggerPaused:!0,elapsedTime:s.elapsedTime}):JSON.stringify({success:!0,message:"Execution started, but neither completed nor hit a breakpoint within timeout period",debuggerPaused:!1,timedOut:!0,elapsedTime:s.elapsedTime})}}},F.getCellOutput={def:{name:"getCellOutput",description:"Get the output of a cell by index",arguments:{index:{type:"integer",name:"Index of the cell to get output from"}}},func:async e=>{var{index:t,scroll:n}=e;t="string"==typeof t?parseInt(t,10):t,n=!1!==n;const o=M.currentWidget;T.shell.activateById(o.id);const r=o.content;r.activeCellIndex=t;const i=r.activeCell;if(n&&i.node.scrollIntoView({behavior:"smooth",block:"center"}),i instanceof g.CodeCell){const e=i.outputArea,t=[];for(let n=0;n<e.model.length;n++){const o=e.model.get(n);console.log(`Output is array: ${Array.isArray(o)}`),console.log(JSON.stringify(o).substring(0,200)),t.push(o)}return t}return"markdown cells do not have outputs"}},F.listCells={def:{name:"listCells",description:"Lists all cells in the currently opened notebook with their content, type, and outputs. Open a notebook first!",arguments:{}},func:async e=>{const t=M.currentWidget;if(null==t)return[];t.content;const n=M.currentWidget.content,o=[];for(let e=0;e<n.widgets.length;e++){const t=n.widgets[e],r=t.model,i={index:e,type:r.type,content:r.sharedModel.getSource()};if(t instanceof g.CodeCell){const e=t.outputArea,n=[];for(let t=0;t<e.model.length;t++){const o=e.model.get(t);n.push(o)}i.outputs=n}o.push(i)}return{cells:o,path:t.context.path}}},F.deleteCell={def:{name:"deleteCell",description:"Delete a cell by index",arguments:{index:{type:"integer",name:"Index of the cell to delete"}}},func:async e=>{if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});const{index:t}=e,n=H(T);if(!n||!n.content)return JSON.stringify({error:"No active notebook found"});if(!B(n,t))return JSON.stringify({error:`Invalid cell index: ${t}`});try{return n.content.activeCellIndex=t,p.NotebookActions.deleteCells(n.content),JSON.stringify({success:!0,message:`Cell at index ${t} deleted`})}catch(e){return JSON.stringify({error:`Error deleting cell: ${e.message}`})}}},F.saveAllOutputImages={def:{name:"saveAllOutputImages",description:"Save all output images from a cell to a specified folder",arguments:{cellIndex:{type:"integer",name:"Index of the cell containing the images"},folderPath:{type:"string",name:"Folder path where images should be saved"},filePrefix:{type:"string",name:"Prefix for the image filenames",default:"image"}}},func:async e=>{if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});const{cellIndex:t,folderPath:n,filePrefix:o="image"}=e,r=H(T);if(!r||!r.content)return JSON.stringify({error:"No active notebook found"});if(!B(r,t))return JSON.stringify({error:`Invalid cell index: ${t}`});try{if(!(r.content.widgets[t]instanceof g.CodeCell))return JSON.stringify({error:`Cell ${t} is not a code cell and has no output`});const e=await F.getCellOutput.func({index:t});console.log("[saveAllOutputImages] Raw getCellOutput result:",e);let i=[];if("string"==typeof e){console.log("[saveAllOutputImages] Parsing string output result");try{i=JSON.parse(e),console.log("[saveAllOutputImages] Successfully parsed output JSON")}catch(t){console.error("[saveAllOutputImages] Error parsing outputs:",t),console.log("[saveAllOutputImages] Raw string output:",e)}}else if(Array.isArray(e))console.log("[saveAllOutputImages] Output result is already an array"),i=e;else if(e&&"object"==typeof e){console.log("[saveAllOutputImages] Output result is an object, checking for array properties");for(const t in e)if(Array.isArray(e[t])){console.log(`[saveAllOutputImages] Found array in property '${t}'`),i=e[t];break}0===i.length&&e.data&&(console.log("[saveAllOutputImages] Treating object as a single output"),i=[e])}else console.log("[saveAllOutputImages] Unrecognized output format, using as is"),i=e;if(console.log("[saveAllOutputImages] Processed outputs:",i),!i||!Array.isArray(i)||0===i.length)return JSON.stringify({error:`No outputs found for cell ${t}`});console.log(`[saveAllOutputImages] Ensuring directory exists: ${n}`);try{const e=`${n}/dummy.txt`;await h(T,e),console.log(`[saveAllOutputImages] Directory ensured: ${n}`)}catch(e){throw console.error(`[saveAllOutputImages] Error ensuring directory: ${e.message}`),e}const s=T.serviceManager.contents,a=["image/png","image/jpeg","image/jpg","image/gif","image/svg+xml"],c=[];let l=0;for(let e=0;e<i.length;e++){const r=i[e];if(console.log(`[saveAllOutputImages] Processing output ${e}:`,r),r&&r.data){console.log(`[saveAllOutputImages] Output ${e} data:`,r.data),console.log(`[saveAllOutputImages] Available MIME types in output ${e}:`,Object.keys(r.data||{}).filter((e=>e.startsWith("image/"))));for(const i of a)if(r.data[i]){const a=r.data[i];console.log(`[saveAllOutputImages] Found image data in output ${e} with MIME type: ${i}`),console.log("[saveAllOutputImages] Image data preview:","string"==typeof a?`${a.substring(0,50)}... (${a.length} chars)`:"Non-string data");const d=Date.now(),u=`${n}/${o}_cell${t}_${l}_${d}.${i.split("/")[1].replace("jpeg","jpg")}`;let p="base64";"image/svg+xml"!==i||"string"!=typeof a||a.startsWith("data:")?console.log(`[saveAllOutputImages] Using base64 format for ${i} data`):(p="text",console.log("[saveAllOutputImages] Using text format for SVG data")),console.log(`[saveAllOutputImages] Saving image to: ${u}`),console.log(`[saveAllOutputImages] File format: ${p}`);try{await s.save(u,{type:"file",format:p,content:a}),console.log(`[saveAllOutputImages] Successfully saved image to ${u}`)}catch(e){throw console.error(`[saveAllOutputImages] Error saving image to ${u}:`,e),e}c.push({filePath:u,mimeType:i,outputIndex:e}),l++}}else console.log(`[saveAllOutputImages] Output ${e} has no data, skipping`)}return 0===c.length?JSON.stringify({error:`No image data found in any outputs of cell ${t}`}):JSON.stringify({success:!0,message:`Saved ${c.length} images to ${n}`,savedImages:c})}catch(e){return JSON.stringify({error:`Error saving images: ${e.message}`})}}},F.saveOutputImage={def:{name:"saveOutputImage",description:"Save an output image from a cell to a specified file",arguments:{cellIndex:{type:"integer",name:"Index of the cell containing the image"},outputIndex:{type:"integer",name:"Index of the output to save (if cell has multiple outputs)",default:0},filePath:{type:"string",name:"Path where the image should be saved"}}},func:async e=>{if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});const{cellIndex:t,outputIndex:n=0,filePath:o}=e,r=H(T);if(!r||!r.content)return JSON.stringify({error:"No active notebook found"});if(!B(r,t))return JSON.stringify({error:`Invalid cell index: ${t}`});try{if(!(r.content.widgets[t]instanceof g.CodeCell))return JSON.stringify({error:`Cell ${t} is not a code cell and has no output`});const e=await F.getCellOutput.func({index:t});console.log("[saveOutputImage] Raw getCellOutput result:",e);let i=[];if("string"==typeof e){console.log("[saveOutputImage] Parsing string output result");try{i=JSON.parse(e),console.log("[saveOutputImage] Successfully parsed output JSON")}catch(t){console.error("[saveOutputImage] Error parsing outputs:",t),console.log("[saveOutputImage] Raw string output:",e)}}else if(Array.isArray(e))console.log("[saveOutputImage] Output result is already an array"),i=e;else if(e&&"object"==typeof e){console.log("[saveOutputImage] Output result is an object, checking for array properties");for(const t in e)if(Array.isArray(e[t])){console.log(`[saveOutputImage] Found array in property '${t}'`),i=e[t];break}0===i.length&&e.data&&(console.log("[saveOutputImage] Treating object as a single output"),i=[e])}else console.log("[saveOutputImage] Unrecognized output format, using as is"),i=e;if(console.log("[saveOutputImage] Processed outputs:",i),!i||!Array.isArray(i)||i.length<=n)return JSON.stringify({error:`No output found at index ${n} for cell ${t}`});const s=i[n];if(!s||!s.data)return JSON.stringify({error:`Output at index ${n} does not contain data`});const a=["image/png","image/jpeg","image/jpg","image/gif","image/svg+xml"];console.log("[saveOutputImage] Output data:",s.data),console.log("[saveOutputImage] Available MIME types in output:",Object.keys(s.data||{}).filter((e=>e.startsWith("image/"))));let c=null,l=null;for(const e of a)if(s.data[e]){c=s.data[e],l=e,console.log(`[saveOutputImage] Found image data with MIME type: ${e}`),console.log("[saveOutputImage] Image data preview:","string"==typeof c?`${c.substring(0,50)}... (${c.length} chars)`:"Non-string data");break}if(!c||!l)return JSON.stringify({error:`No image data found in output ${n}`});const d=o.lastIndexOf("/"),u=-1!==d?o.substring(0,d):".";console.log(`[saveOutputImage] Ensuring directory exists: ${u}`);try{const e=`${u}/dummy.txt`;await h(T,e),console.log(`[saveOutputImage] Directory ensured: ${u}`)}catch(e){throw console.error(`[saveOutputImage] Error ensuring directory: ${e.message}`),e}const p=T.serviceManager.contents;let m="base64",y=c;"image/svg+xml"!==l||"string"!=typeof c||c.startsWith("data:")?console.log(`[saveOutputImage] Using base64 format for ${l} data`):(m="text",console.log("[saveOutputImage] Using text format for SVG data")),console.log(`[saveOutputImage] Saving image to: ${o}`),console.log(`[saveOutputImage] File format: ${m}`);try{await p.save(o,{type:"file",format:m,content:y}),console.log(`[saveOutputImage] Successfully saved image to ${o}`)}catch(e){throw console.error(`[saveOutputImage] Error saving image to ${o}:`,e),e}return JSON.stringify({success:!0,message:`Image saved to ${o}`,mimeType:l})}catch(e){return JSON.stringify({error:`Error saving image: ${e.message}`})}}},F.setValue={def:{name:"setValue",description:"Sets a session variable, aka settings vairable, setting, variable, etc",arguments:{key:{type:"string",name:"Name of the property to set"},value:{type:"string",name:"The value to store"}}},func:async e=>{let t=e.key||"",n=e.value||"";return $[t]=n,"ok"}},F.getValue={def:{name:"getValue",description:"Gets a session variable, aka settings vairable, setting, variable, etc",arguments:{key:{type:"string",name:"Name of the property to retrieve"}}},func:async e=>{let t=e.key||"",n=$[t]=$[t];return JSON.stringify({key:t,velue:n})}},F.diffToFile={def:{name:"diffToFile",description:"Makes tagreted change in file. Search must match the entire piece exactly. Use it in as a diff",arguments:{filePath:{type:"string",name:"Relative path to the file to display in merge view. Relative! "},search:{type:"string",name:"text to be removed. Pass '+' string to append to file, '-' to add at the beginning"},replace:{type:"string",name:"text to insert instead of the removed text"}}},func:async(e,t=!1,n=void 0)=>{if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});const{contents:o}=T.serviceManager,{filePath:r,search:i,replace:s}=e;if(null==i||null==s)return"";try{let e;try{e=await o.get(r)}catch(e){return JSON.stringify({status:"fail",message:`Cannot open file: ${r} does not exist`})}const l=e.content;var a=l;if("+"==i?a+=A(s):a="-"==i?s+A(s):a.replace(A(i),A(s)),null!=J[n])!function(e,t){try{if(!e.b||!e.b.state)return console.error("Could not access state for doc B"),!1;const n=e.b.state;return e.b.dispatch({changes:{from:0,to:n.doc.length,insert:t}}),console.log("Successfully updated doc B"),!0}catch(e){return console.error("Error updating doc B:",e),!1}}(J[n],a);else if(null==J[n]){const e=document.createElement("div");e.style.height="100%",e.style.overflow="auto";const t=[b.jupyterTheme,...O(r)],o=document.createElement("style");o.textContent="\n /* Basic syntax highlighting styles using JupyterLab variables */\n .cm - keyword { color: var(--jp - mirror - editor - keyword - color); font - weight: bold; }\n .cm - comment { color: var(--jp - mirror - editor - comment - color); }\n .cm - string { color: var(--jp - mirror - editor - string - color); }\n .cm - number { color: var(--jp - mirror - editor - number - color); }\n .cm - operator { color: var(--jp - mirror - editor - operator - color); }\n .cm - property { color: var(--jp - mirror - editor - property - color); }\n .cm - variable { color: var(--jp - mirror - editor - variable - color); }\n .cm - function, .cm - def { color: var(--jp - mirror - editor - def - color); }\n .cm - atom { color: var(--jp - mirror - editor - atom - color); }\n .cm - meta { color: var(--jp - mirror - editor - meta - color); }\n .cm - tag { color: var(--jp - mirror - editor - tag - color); }\n .cm - attribute { color: var(--jp - mirror - editor - attribute - color); }\n .cm - qualifier { color: var(--jp - mirror - editor - qualifier - color); }\n .cm - bracket { color: var(--jp - mirror - editor - bracket - color); }\n .cm - builtin { color: var(--jp - mirror - editor - builtin - color); }\n .cm - special { color: var(--jp - mirror - editor - string - 2 - color); }\n ",document.head.appendChild(o);const i=new w.MergeView({a:{doc:l,extensions:t},b:{doc:a,extensions:t},highlightChanges:!0});J[n]=i,e.appendChild(i.dom),setTimeout((function(){(e=>{try{const t=e.dom.querySelectorAll(".cm-editor");console.log(`Found ${t.length} editors in merge view`),t.forEach(((e,t)=>{var n;const o=e.view;if(o){i=o,s=`Editor ${t}`,console.log(`Debug ${s}:`,{hasFocus:i.hasFocus,docLength:i.state.doc.length});const a=(null===(n=r.split(".").pop())||void 0===n?void 0:n.toLowerCase())||"";e.classList.add(`language-${a}`),setTimeout((()=>{try{o.dispatch({})}catch(e){console.error(`Error refreshing editor ${t}:`,e)}}),100)}else console.log(`Could not access view for editor ${t}`);var i,s}))}catch(e){console.error("Error applying syntax highlighting:",e)}})(i)}),500);const s=new c.Widget;U[n]=s,s.id=n,s.title.label=`Merge View: ${r} `,s.title.closable=!0,s.node.appendChild(e),T.shell.add(s,"main"),T.shell.activateById(s.id)}if(!t){if(console.log(T.commands.listCommands()),J[n]){const e=U[n];e&&setTimeout((()=>{e.close(),setTimeout((()=>{T.commands.execute("docmanager:open",{path:r}),setTimeout((()=>{T.commands.execute("docmanager:reload")}),100)}),100)}),1e3)}return await o.save(r,{type:"file",format:"text",content:a}),JSON.stringify({status:"ok",new_content:a})}}catch(e){return JSON.stringify({status:"fail",message:`Failed to open merge view: ${e.message} `})}}},F.startDebugger={def:{name:"startDebugger",description:"Turn on the debugger for the current notebook",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});const t=H(T);if(!t||!t.sessionContext)return JSON.stringify({error:"No active notebook found"});try{if(!await P.isAvailable(t.sessionContext.session))return JSON.stringify({error:"Debugging is not available for the current kernel"});P.session&&(P.session.connection=t.sessionContext.session),await P.start(),await P.restoreState(!0),await P.displayDefinedVariables();const e=new _.Debugger.Handler({type:"notebook",shell:T.shell,service:P});return await e.updateContext(t,t.sessionContext),T.commands.hasCommand("debugger:show-panel")&&T.commands.execute("debugger:show-panel"),document.body.dataset.jpDebuggerActive="true",P.hasStoppedThreads()&&(document.body.dataset.jpDebuggerStoppedThreads="true"),JSON.stringify({success:!0,message:"Debugger started successfully and UI activated"})}catch(e){return JSON.stringify({error:`Error starting debugger: ${e.message}`})}}},F.stopDebugger={def:{name:"stopDebugger",description:"Turn off the debugger for the current notebook",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});try{if(!P.isStarted)return JSON.stringify({success:!0,message:"Debugger is not running"});await P.stop(),delete document.body.dataset.jpDebuggerActive,delete document.body.dataset.jpDebuggerStoppedThreads;const e=T.shell;return e&&"function"==typeof e.collapseRight&&e.collapseRight(),JSON.stringify({success:!0,message:"Debugger stopped successfully"})}catch(e){return JSON.stringify({error:`Error stopping debugger: ${e.message}`})}}},F.isDebuggerAvailable={def:{name:"isDebuggerAvailable",description:"Check if debugging is available for the current notebook",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});const t=H(T);if(!t||!t.sessionContext)return JSON.stringify({error:"No active notebook found"});try{const e=await P.isAvailable(t.sessionContext.session);return JSON.stringify({success:!0,available:e})}catch(e){return JSON.stringify({error:`Error checking debugger availability: ${e.message}`})}}},F.getDebuggerState={def:{name:"getDebuggerState",description:"Get the current state of the debugger",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});try{return JSON.stringify({success:!0,isStarted:P.isStarted,hasStoppedThreads:P.hasStoppedThreads()})}catch(e){return JSON.stringify({error:`Error getting debugger state: ${e.message}`})}}},F.setBreakpoint={def:{name:"setBreakpoint",description:"Set a breakpoint in the current notebook cell",arguments:{index:{type:"integer",name:"Index of the cell to set breakpoint in"},lineNumber:{type:"integer",name:"Line number to set breakpoint at (1-based)"}}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});const t=H(T);if(!t||!t.content)return JSON.stringify({error:"No active notebook found"});try{const n="string"==typeof e.index?parseInt(e.index,10):e.index,o="string"==typeof e.lineNumber?parseInt(e.lineNumber,10):e.lineNumber;if(n<0||n>=t.content.widgets.length)return JSON.stringify({error:"Invalid cell index"});if(!o||o<1)return JSON.stringify({error:"Invalid line number"});const r=t.content.widgets[n].model.sharedModel.getSource(),i=[{line:o,verified:!1}];return await P.updateBreakpoints(r,i),JSON.stringify({success:!0,message:"Breakpoints set successfully"})}catch(e){return JSON.stringify({error:`Error setting breakpoints: ${e.message}`})}}},F.clearBreakpoints={def:{name:"clearBreakpoints",description:"Clear all breakpoints in the notebook",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});try{return await P.clearBreakpoints(),JSON.stringify({success:!0,message:"All breakpoints cleared"})}catch(e){return JSON.stringify({error:`Error clearing breakpoints: ${e.message}`})}}},F.stepOver={def:{name:"stepOver",description:"Step over to the next line of code",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{return await P.next(),JSON.stringify({success:!0,message:"Stepped over to next line"})}catch(e){return JSON.stringify({error:`Error stepping over: ${e.message}`})}}},F.stepInto={def:{name:"stepInto",description:"Step into a function or method",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{return await P.stepIn(),JSON.stringify({success:!0,message:"Stepped into function"})}catch(e){return JSON.stringify({error:`Error stepping into: ${e.message}`})}}},F.stepOut={def:{name:"stepOut",description:"Step out of the current function or method",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{return await P.stepOut(),JSON.stringify({success:!0,message:"Stepped out of function"})}catch(e){return JSON.stringify({error:`Error stepping out: ${e.message}`})}}},F.continueExecution={def:{name:"continueExecution",description:"Continue execution until the next breakpoint or end of program",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{return await P.continue(),JSON.stringify({success:!0,message:"Execution continued"})}catch(e){return JSON.stringify({error:`Error continuing execution: ${e.message}`})}}},F.pauseExecution={def:{name:"pauseExecution",description:"Pause the execution of the current program",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});try{return await P.pause(),JSON.stringify({success:!0,message:"Execution paused"})}catch(e){return JSON.stringify({error:`Error pausing execution: ${e.message}`})}}},F.evaluateExpression={def:{name:"evaluateExpression",description:"Evaluate an expression in the current debug context",arguments:{expression:{type:"string",name:"Expression to evaluate"}}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{const t=e.expression;if(!t)return JSON.stringify({error:"No expression provided"});const n=await P.evaluate(t);return JSON.stringify({success:!0,result:n})}catch(e){return JSON.stringify({error:`Error evaluating expression: ${e.message}`})}}},F.inspectVariables={def:{name:"inspectVariables",description:"Get all variables in the current scope",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});try{await P.displayDefinedVariables();const e=P.model.variables.scopes;return JSON.stringify({success:!0,scopes:e})}catch(e){return JSON.stringify({error:`Error inspecting variables: ${e.message}`})}}},F.inspectVariable={def:{name:"inspectVariable",description:"Inspect a specific variable by reference ID",arguments:{variableReference:{type:"integer",name:"Reference ID of the variable to inspect"}}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});try{const t=e.variableReference;if(!t)return JSON.stringify({error:"No variable reference provided"});P.inspectVariable(t),await new Promise((e=>setTimeout(e,100)));const n=P.model.variables;return JSON.stringify({success:!0,variables:n})}catch(e){return JSON.stringify({error:`Error inspecting variable: ${e.message}`})}}},F.getCallStack={def:{name:"getCallStack",description:"Get the current call stack when execution is paused",arguments:{}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{const e=P.model.callstack.frames;return JSON.stringify({success:!0,callstack:e})}catch(e){return JSON.stringify({error:`Error getting call stack: ${e.message}`})}}},F.setPauseOnExceptions={def:{name:"setPauseOnExceptions",description:"Configure the debugger to pause on exceptions",arguments:{filter:{type:"string",name:"Exception type to pause on (e.g., 'uncaught' or 'raised')"}}},func:async e=>{if(!T||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});try{const t=e.filter||"";return t?(await P.pauseOnExceptionsFilter(t),JSON.stringify({success:!0,message:"Exception breakpoints configured"})):JSON.stringify({error:"No filter provided"})}catch(e){return JSON.stringify({error:`Error setting exception breakpoints: ${e.message}`})}}},F.waitForDebugger={def:{name:"waitForDebugger",description:"Wait for either a breakpoint to be hit or cell execution to complete",arguments:{index:{type:"integer",name:"Index of the cell being executed"},maxWaitTime:{type:"integer",name:"Maximum time to wait in milliseconds",optional:!0},pollInterval:{type:"integer",name:"Interval between checks in milliseconds",optional:!0}}},func:async e=>{const{index:t,maxWaitTime:n=1e4,pollInterval:o=100}=e,r=M.currentWidget;if(!r)return JSON.stringify({error:"No active notebook"});const i=r.content;if(t<0||t>=i.widgets.length)return JSON.stringify({error:"Invalid cell index"});const s=i.widgets[t],a=Date.now();for(;Date.now()-a<n;){if((null==P?void 0:P.isStarted)&&P.hasStoppedThreads()){const e=Date.now()-a;return JSON.stringify({completed:!1,breakpointHit:!0,timedOut:!1,elapsedTime:e})}if("idle"===s.model.executionState){const e=Date.now()-a;return JSON.stringify({completed:!0,breakpointHit:!1,timedOut:!1,elapsedTime:e})}await new Promise((e=>setTimeout(e,o)))}const c=Date.now()-a;return JSON.stringify({completed:!1,breakpointHit:!1,timedOut:!0,elapsedTime:c})}};var D=!1;function H(e){const{shell:t}=e,n=t.currentWidget;return n&&n instanceof p.NotebookPanel?n:null}function B(e,t){if(!e||!e.content)return!1;const n=e.content.widgets.length;return t>=0&&t<n}async function R(e,t,n){console.log("=============== register_functions ==============="),T=e,M=t,P=n;for(const e of Object.keys(F))console.log("register function:",e),(0,u.uo)(e,!0,F[e].func,F[e],!0)}F.listAvailableKernels={def:{name:"listAvailableKernels",description:"Lists kernels (such as python) available on the system",arguments:{}},func:async e=>{var t;await T.serviceManager.kernelspecs.refreshSpecs(),await T.serviceManager.kernelspecs.refreshSpecs();const n=null===(t=T.serviceManager.kernelspecs.specs)||void 0===t?void 0:t.kernelspecs,o=Object.values(n).map((e=>({name:e.name,display_name:e.display_name,language:e.language})));return JSON.stringify(o)}},F.createAndOpenNotebook={def:{name:"createAndOpenNotebook",description:"Creates and opens a new notebook",arguments:{name:{type:"string",name:"Name for the new notebook"},kernelName:{type:"string",name:"Name of kernel to use"}}},func:async e=>{var t,n,o,r;let i=e.name;const s=e.kernelName,a=T.serviceManager.contents,c=null===(t=T.serviceManager.kernelspecs.specs)||void 0===t?void 0:t.kernelspecs;i.endsWith(".ipynb")||(i+=".ipynb");const l=i.startsWith("./")?i.slice(2):i,d=null==c?void 0:c[s],u=null!==(n=null==d?void 0:d.display_name)&&void 0!==n?n:s,p=null!==(o=null==d?void 0:d.language)&&void 0!==o?o:"python";try{await a.get(l)}catch(e){if(404!==(null===(r=e.response)||void 0===r?void 0:r.status))return console.error(e),"There was an error retrieving notebook info.";await a.save(l,{type:"notebook",format:"json",content:{cells:[],metadata:{kernelspec:{name:s,display_name:u,language:p}},nbformat:4,nbformat_minor:5}})}return await T.commands.execute("docmanager:open",{path:l,factory:"Notebook",options:{kernel:{name:s}}}),"done"}},F.openNotebook={def:{name:"openNotebook",description:"Opens an existing notebook",arguments:{name:{type:"string",name:"Name for the notebook to open"}}},func:async e=>{const t=e.name,n=T.serviceManager.contents;try{await n.get(t)}catch(e){return`Notebook ${t} does not exit`}return await T.commands.execute("docmanager:open",{path:t,factory:"Notebook"}),"done"}},F.restartKernel={def:{name:"restartKernel",description:"Restart the kernel of the active notebook",arguments:{}},func:async e=>{var t;if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});const n=H(T);if(!n||!n.sessionContext)return JSON.stringify({error:"No active notebook found"});try{if(!(null===(t=n.sessionContext.session)||void 0===t?void 0:t.kernel))throw new Error("No kernel available to restart");return await n.sessionContext.session.kernel.restart(),JSON.stringify({success:!0,message:"Kernel restarted successfully"})}catch(e){return JSON.stringify({error:`Error restarting kernel: ${e.message}`})}}},F.stopExecution={def:{name:"stopExecution",description:"Stop the execution of the active notebook by interrupting the kernel",arguments:{}},func:async e=>{var t,n;if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});const o=H(T);if(!o||!o.sessionContext)return JSON.stringify({error:"No active notebook found"});try{return await(null===(n=null===(t=o.sessionContext.session)||void 0===t?void 0:t.kernel)||void 0===n?void 0:n.interrupt()),JSON.stringify({success:!0,message:"Execution interrupted"})}catch(e){return JSON.stringify({error:`Error interrupting kernel: ${e.message}`})}}},F.getCurrentNotebook={def:{name:"getCurrentNotebook",description:"Gets information about the currently open notebook",arguments:{}},func:async e=>{if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});const t=H(T);if(!t||!t.content)return JSON.stringify({error:"No active notebook found"});try{const e=t.context,n=t.model,o=e.path,r=o.split("/").pop()||"",i=e.model.dirty;let s={};if(n&&n.metadata)try{const e=n;s={kernelName:e.metadata.kernelName||"",kernelLanguage:e.metadata.kernelLanguage||""}}catch(e){console.error("Error extracting notebook metadata:",e)}return JSON.stringify({success:!0,notebook:{path:o,name:r,dirty:i,metadata:s,cell_count:n.cells.length}})}catch(e){return JSON.stringify({error:`Error getting notebook information: ${e.message}`})}}},F.getKernelState={def:{name:"getKernelState",description:"Get the state of the kernel and information about any currently executing cell",arguments:{}},func:async e=>{if(!T)return JSON.stringify({error:"JupyterLab app not initialized"});const t=H(T);if(!t||!t.sessionContext)return JSON.stringify({error:"No active notebook found"});try{const e=t.sessionContext.session,n=null==e?void 0:e.kernel;if(!n)return JSON.stringify({success:!0,kernel_state:"no_kernel",executing:!1});const o=n.status,r=[],i=t.content.widgets;for(let e=0;e<i.length;e++){const t=i[e];t instanceof g.CodeCell&&null!==t.model.executionCount&&t.hasClass("jp-mod-executing")&&r.push({index:e,execution_count:t.model.executionCount})}return JSON.stringify({success:!0,kernel_state:o,executing:"busy"===o,executing_cells:r})}catch(e){return JSON.stringify({error:`Error getting kernel state: ${e.message}`})}}};var K=n(9838);class j{constructor(e,t){this.authProviders=[{id:"google",name:"Google",icon:'<svg viewBox="0 0 24 24" width="18" height="18"><path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/><path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/></svg>',description:"Sign in with your Google account"}],this.onSuccess=e,this.onCancel=t,this.overlay=document.createElement("div"),this.overlay.className="escobar-login-overlay",this.overlay.style.cssText="\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n opacity: 0;\n transition: opacity 0.3s ease;\n ",this.overlay.addEventListener("click",(e=>{e.target===this.overlay&&(this.hide(),this.onCancel())})),this.container=this.createContainer(),this.overlay.appendChild(this.container)}createContainer(){const e=document.createElement("div");e.className="escobar-login-container",e.style.cssText="\n background: var(--jp-layout-color0);\n border: 1px solid var(--jp-border-color1);\n border-radius: 8px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n max-width: 400px;\n width: 90%;\n max-height: 80vh;\n overflow-y: auto;\n transform: scale(0.9);\n transition: transform 0.3s ease;\n ";const t=document.createElement("div");t.style.cssText="\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px 24px 16px;\n border-bottom: 1px solid var(--jp-border-color1);\n ";const n=document.createElement("h2");n.textContent="Authentication Required",n.style.cssText="\n margin: 0;\n color: var(--jp-content-font-color1);\n font-size: 18px;\n font-weight: 600;\n ",t.appendChild(n);const o=document.createElement("button");o.innerHTML="&times;",o.style.cssText="\n background: none;\n border: none;\n font-size: 24px;\n color: var(--jp-content-font-color2);\n cursor: pointer;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n transition: background-color 0.2s ease;\n ",o.addEventListener("click",(()=>{this.hide(),this.onCancel()})),o.addEventListener("mouseenter",(()=>{o.style.backgroundColor="var(--jp-layout-color2)"})),o.addEventListener("mouseleave",(()=>{o.style.backgroundColor="transparent"})),t.appendChild(o),e.appendChild(t);const r=document.createElement("div");r.style.cssText="\n padding: 24px;\n ";const i=document.createElement("p");i.textContent="Please authenticate to access AI services:",i.style.cssText="\n margin: 0 0 20px 0;\n color: var(--jp-content-font-color2);\n font-size: 14px;\n line-height: 1.5;\n ",r.appendChild(i);const s=document.createElement("div");return s.style.cssText="\n display: flex;\n flex-direction: column;\n gap: 12px;\n ",this.authProviders.forEach((e=>{const t=document.createElement("button");t.dataset.provider=e.id,t.style.cssText="\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n background: var(--jp-layout-color1);\n border: 1px solid var(--jp-border-color1);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n text-align: left;\n width: 100%;\n ",t.addEventListener("mouseenter",(()=>{t.style.backgroundColor="var(--jp-layout-color2)",t.style.borderColor="var(--jp-brand-color1)"})),t.addEventListener("mouseleave",(()=>{t.style.backgroundColor="var(--jp-layout-color1)",t.style.borderColor="var(--jp-border-color1)"}));const n=document.createElement("span");n.innerHTML=e.icon,n.style.cssText="\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n ",t.appendChild(n);const o=document.createElement("div");o.style.cssText="\n flex: 1;\n ";const r=document.createElement("div");r.textContent=e.name,r.style.cssText="\n font-weight: 500;\n color: var(--jp-content-font-color1);\n font-size: 14px;\n margin-bottom: 2px;\n ",o.appendChild(r);const i=document.createElement("div");i.textContent=e.description,i.style.cssText="\n font-size: 12px;\n color: var(--jp-content-font-color2);\n line-height: 1.3;\n ",o.appendChild(i),t.appendChild(o),t.addEventListener("click",(()=>{this.handleProviderClick(e.id)})),s.appendChild(t)})),r.appendChild(s),e.appendChild(r),e}async handleProviderClick(e){if("google"===e){this.setLoadingState(e,!0);try{let t=(0,K.Hn)();if(!t){const n=window.escobarCurrentSettings,o=null==n?void 0:n.googleClientId;if(!o)return this.setLoadingState(e,!1),void this.showError("Google Client ID not configured. Please set it in the settings first.");t=(0,K.e$)({clientId:o,scope:"openid email profile https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/documents.readonly"})}const n=await t.loginWithAuthCode();this.setLoadingState(e,!1),n.success&&n.idToken?(console.log("🔐 LOGIN-UI: Authentication successful"),window.escobarGoogleIdToken=n.idToken,window.escobarGoogleUserInfo=n.userInfo,this.hide(),this.onSuccess(n.idToken)):(console.error("🔐 LOGIN-UI: Authentication failed:",n.error),this.showError(n.error||"Authentication failed. Please try again."))}catch(t){console.error("🔐 LOGIN-UI: Authentication error:",t),this.setLoadingState(e,!1),this.showError(`Authentication error: ${t.message||"Unknown error occurred"}`)}}else this.showError(`${this.getProviderById(e).name} authentication is not yet implemented.`)}setLoadingState(e,t){const n=this.container.querySelector(`button[data-provider="${e}"]`);if(n)if(t){n.disabled=!0,n.style.opacity="0.6",n.style.cursor="not-allowed";const t=n.querySelector("div > div:first-child");t&&(t.textContent=`Connecting to ${this.getProviderById(e).name}...`)}else{n.disabled=!1,n.style.opacity="1",n.style.cursor="pointer";const t=n.querySelector("div > div:first-child");t&&(t.textContent=this.getProviderById(e).name)}}showError(e){const t=this.container.querySelector(".escobar-login-error");t&&t.remove();const n=document.createElement("div");n.className="escobar-login-error",n.textContent=e,n.style.cssText="\n background: var(--jp-error-color3);\n color: var(--jp-error-color1);\n border: 1px solid var(--jp-error-color1);\n border-radius: 4px;\n padding: 12px;\n margin: 16px 24px;\n font-size: 13px;\n line-height: 1.4;\n ";const o=this.container.querySelector("div:last-child");o&&this.container.insertBefore(n,o),setTimeout((()=>{n.parentNode&&n.parentNode.removeChild(n)}),5e3)}getProviderById(e){return this.authProviders.find((t=>t.id===e))||this.authProviders[0]}show(){document.body.appendChild(this.overlay),requestAnimationFrame((()=>{this.overlay.style.opacity="1",this.container.style.transform="scale(1)"}))}hide(){this.overlay.style.opacity="0",this.container.style.transform="scale(0.9)",setTimeout((()=>{this.overlay.parentNode&&this.overlay.parentNode.removeChild(this.overlay)}),300)}}function G(){return new Promise(((e,t)=>{new j((t=>{e(t)}),(()=>{t(new Error("Authentication cancelled"))})).show()}))}const z="0.1.98";function W(){const e=window.location.pathname.match(/\/user\/([^\/]+)\//);if(e&&e[1])return!0;try{const e=document.getElementById("jupyter-config-data");if(e&&e.textContent){const t=JSON.parse(e.textContent);if(t.hubUser||t.hubUsername||t.user)return!0}}catch(e){console.error("Error parsing JupyterHub config:",e)}try{const e=document.baseURI.match(/\/user\/([^\/]+)\//);if(e&&e[1])return!0}catch(e){console.error("Error checking baseURI:",e)}try{const e=document.cookie.split(";");for(const t of e){const[e,n]=t.trim().split("=");if("jupyterhub-user"===e)return!0}}catch(e){console.error("Error checking cookies:",e)}const t=window.location.pathname.match(/\/user\/([^\/]*)\//);return!(!t||!t[1])}class q{constructor(e,t,n){this.settingsRegistry=e,this.currentSettings=t,this.onSave=n,this.overlay=document.createElement("div"),this.overlay.className="escobar-settings-overlay",this.overlay.addEventListener("click",(e=>{e.target===this.overlay&&this.hide()})),this.container=this.createContainer(),this.overlay.appendChild(this.container)}createHeader(e){const t=document.createElement("div");t.className="escobar-settings-header";const n=document.createElement("h2");n.textContent=e,t.appendChild(n);const o=document.createElement("button");return o.className="escobar-settings-close-button",o.innerHTML="&times;",o.addEventListener("click",(()=>this.hide())),t.appendChild(o),t}createFormGroup(e,t,n){const o=document.createElement("div");o.className="escobar-settings-group";const r=document.createElement("label");r.textContent=t,r.htmlFor=e,o.appendChild(r);const i=document.createElement("div");return i.className="escobar-settings-description",i.textContent=n,o.appendChild(i),o}createModelDropdown(e,t,n,o){const r=this.createFormGroup(e,t,n),i=document.createElement("select");if(i.id=e,i.className="escobar-settings-input",i._savedValue=o,o){const e=document.createElement("option");e.value=o,e.textContent=`${o} (Loading models...)`,e.selected=!0,i.appendChild(e)}else{const e=document.createElement("option");e.value="undefined",e.textContent="Loading models...",e.selected=!0,i.appendChild(e)}const s=e=>{const t=i._savedValue;if(i.innerHTML="",e.length>0)if(e.forEach((e=>{const t=document.createElement("option");t.value=e.model,t.textContent=e.model,i.appendChild(t)})),t){if(i.value=t,i.value!==t){const e=document.createElement("option");e.value=t,e.textContent=`${t} (Custom)`,i.insertBefore(e,i.firstChild),i.value=t}}else i.value=e[0].model;else{const e=document.createElement("option");e.value="undefined",e.textContent="No models available",e.selected=!0,i.appendChild(e)}},a=window.escobarAvailableModels||[];a.length>0&&s(a);const c=e=>{s(e.detail.models)};return window.addEventListener("escobar-models-updated",c),i._modelUpdateCleanup=()=>{window.removeEventListener("escobar-models-updated",c)},r.appendChild(i),r}createButtonsContainer(){const e=document.createElement("div");e.className="escobar-settings-buttons";const t=document.createElement("button");t.className="escobar-settings-button escobar-settings-cancel-button",t.textContent="Cancel",t.type="button",t.addEventListener("click",(()=>this.hide())),e.appendChild(t);const n=document.createElement("button");return n.className="escobar-settings-button escobar-settings-save-button",n.textContent="Save",n.type="submit",e.appendChild(n),e}show(){console.log("🔧 SETTINGS: Opening settings page, loading latest settings..."),this.loadCompleteSettings().then((e=>{console.log("🔧 SETTINGS: Complete settings loaded successfully"),this.currentSettings=e,document.body.appendChild(this.overlay),this.updateFormFields(),setTimeout((()=>{this.overlay.classList.add("escobar-settings-overlay-visible"),this.container.classList.add("escobar-settings-container-visible")}),10)})).catch((e=>{console.error("🔧 SETTINGS: Failed to load complete settings:",e),console.log("🔧 SETTINGS: Using fallback settings"),document.body.appendChild(this.overlay),this.updateFormFields(),setTimeout((()=>{this.overlay.classList.add("escobar-settings-overlay-visible"),this.container.classList.add("escobar-settings-container-visible")}),10)}))}async loadCompleteSettings(){console.log("🔧 SETTINGS: Loading local settings from registry");let e={};try{const t=(await this.settingsRegistry.load("escobar:plugin")).composite;e={serverUrl:t.serverUrl||this.currentSettings.serverUrl,username:t.username||this.currentSettings.username,usernameFromJupyterHub:t.usernameFromJupyterHub||this.currentSettings.usernameFromJupyterHub,bonnieUrl:t.bonnieUrl||this.currentSettings.bonnieUrl},console.log("🔧 SETTINGS: Local settings loaded from registry")}catch(t){console.error("🔧 SETTINGS: Failed to load from registry:",t),e={serverUrl:this.currentSettings.serverUrl,username:this.currentSettings.username,usernameFromJupyterHub:this.currentSettings.usernameFromJupyterHub}}let t={};try{console.log("🔧 SETTINGS: Loading remote settings from server");const e=window.escobarMessageHandler;if(e){console.log("📤 PROTOCOL: Sending retrieveSettings request");const n=await e.retrieveSettingsFromServer();console.log("📥 PROTOCOL: Received retrieveSettings response"),t={maxMessages:n.maxMessages||this.currentSettings.maxMessages,voittaApiKey:n.voittaApiKey||"",openaiApiKey:n.openaiApiKey||"",anthropicApiKey:n.anthropicApiKey||"",geminiApiKey:n.geminiApiKey||"",proxyPort:n.proxyPort||3e3,primaryModel:n.primaryModel,secondaryProvider:n.secondaryProvider,imageParseProvider:n.imageParseProvider},console.log("🔧 SETTINGS: Remote settings loaded successfully")}else console.warn("🔧 SETTINGS: MessageHandler not available, using defaults for remote settings"),t={maxMessages:this.currentSettings.maxMessages,voittaApiKey:this.currentSettings.voittaApiKey||"",openaiApiKey:this.currentSettings.openaiApiKey||"",anthropicApiKey:this.currentSettings.anthropicApiKey||"",geminiApiKey:this.currentSettings.geminiApiKey||"",proxyPort:this.currentSettings.proxyPort||3e3,primaryModel:this.currentSettings.primaryModel,secondaryProvider:this.currentSettings.secondaryProvider,imageParseProvider:this.currentSettings.imageParseProvider}}catch(e){console.error("🔧 SETTINGS: Failed to load remote settings from server:",e),t={maxMessages:this.currentSettings.maxMessages,voittaApiKey:this.currentSettings.voittaApiKey||"",openaiApiKey:this.currentSettings.openaiApiKey||"",anthropicApiKey:this.currentSettings.anthropicApiKey||"",geminiApiKey:this.currentSettings.geminiApiKey||"",proxyPort:this.currentSettings.proxyPort||3e3,primaryModel:this.currentSettings.primaryModel,secondaryProvider:this.currentSettings.secondaryProvider,imageParseProvider:this.currentSettings.imageParseProvider}}const n={serverUrl:e.serverUrl,username:e.username,usernameFromJupyterHub:e.usernameFromJupyterHub,bonnieUrl:e.bonnieUrl,maxMessages:t.maxMessages,voittaApiKey:t.voittaApiKey,openaiApiKey:t.openaiApiKey,anthropicApiKey:t.anthropicApiKey,geminiApiKey:t.geminiApiKey,proxyPort:t.proxyPort,primaryModel:t.primaryModel,secondaryProvider:t.secondaryProvider,imageParseProvider:t.imageParseProvider};return console.log("🔧 SETTINGS: Settings merged successfully"),n}hide(){this.overlay.classList.remove("escobar-settings-overlay-visible"),this.container.classList.remove("escobar-settings-container-visible"),setTimeout((()=>{this.overlay.parentNode&&this.overlay.parentNode.removeChild(this.overlay)}),300)}validateAndSaveCommonSettings(e){if(!e.voittaApiKey&&!e.openaiApiKey&&!e.anthropicApiKey)return alert("At least one API Key is required"),!1;const t=document.getElementById("escobar-gemini-api-key"),n=t?t.value.trim():this.currentSettings.geminiApiKey||"",o=document.getElementById("escobar-primary-model"),r=document.getElementById("escobar-secondary-provider"),i=document.getElementById("escobar-image-parse-provider"),s=o?o.value:"undefined",a=r?r.value:"undefined",c=i?i.value:"undefined",l={maxMessages:this.currentSettings.maxMessages,serverUrl:this.currentSettings.serverUrl,username:this.currentSettings.username,usernameFromJupyterHub:this.currentSettings.usernameFromJupyterHub,voittaApiKey:e.voittaApiKey,openaiApiKey:e.openaiApiKey,anthropicApiKey:e.anthropicApiKey,geminiApiKey:n,proxyPort:e.proxyPort||3e3,primaryModel:s,secondaryProvider:a,imageParseProvider:c};return this.currentSettings=l,window.escobarCurrentSettings=l,this.saveSettingsToServerOnly(l),!0}async saveSettingsToServerOnly(e){console.log("🔧 SETTINGS: Saving remote settings to server only");try{const t=window.escobarMessageHandler;if(!t)throw new Error("Message handler not available - cannot save settings to server");console.log("📤 PROTOCOL: Sending saveSettings request to server"),await t.saveSettingsToServer({maxMessages:e.maxMessages,voittaApiKey:e.voittaApiKey,openaiApiKey:e.openaiApiKey,anthropicApiKey:e.anthropicApiKey,geminiApiKey:e.geminiApiKey,proxyPort:e.proxyPort,primaryModel:e.primaryModel,secondaryProvider:e.secondaryProvider,imageParseProvider:e.imageParseProvider}),console.log("✅ SETTINGS: Remote settings saved to server successfully"),this.hide()}catch(e){console.error("❌ SETTINGS: Failed to save settings to server:",e);const t=e instanceof Error?e.message:"Unknown error occurred";alert(`Failed to save settings to server:\n\n${t}\n\nPlease check your connection and try again.`)}}}class V extends q{createContainer(){const e=document.createElement("div");e.className="escobar-settings-container";const t=this.createHeader("Settings");e.appendChild(t);const n=document.createElement("div");n.className="escobar-mode-indicator",n.innerHTML=`Running in JupyterHub Mode <span style="font-size: 0.8em; opacity: 0.8;">v${z}</span>`,n.style.backgroundColor="#f0f7ff",n.style.color="#0366d6",n.style.padding="8px 16px",n.style.margin="0 16px 16px 16px",n.style.borderRadius="4px",n.style.fontWeight="bold",n.style.textAlign="center",n.style.border="1px solid #c8e1ff",e.appendChild(n);const o=document.createElement("form");o.className="escobar-settings-form",o.addEventListener("submit",(e=>{e.preventDefault(),this.saveSettings()}));const r=this.createFormGroup("escobar-voitta-api-key","Voitta API Key","The API key for authentication with Voitta services. (Optional)"),i=document.createElement("input");i.id="escobar-voitta-api-key",i.className="escobar-settings-input",i.type="text",i.value=this.currentSettings.voittaApiKey||"",r.appendChild(i);const s=document.createElement("a");s.href="#",s.className="escobar-get-api-key-link",s.textContent="Get Voitta API Key",s.style.display=this.currentSettings.voittaApiKey?"none":"block",s.addEventListener("click",(e=>{e.preventDefault(),G().then((e=>{i.value=e,s.style.display="none",alert("Successfully obtained Voitta API key!")})).catch((e=>{"Authentication cancelled"!==e.message&&(console.error("Authentication error:",e),alert("Failed to authenticate. Please try again."))}))})),r.appendChild(s),i.addEventListener("input",(()=>{s.style.display=i.value?"none":"block"})),o.appendChild(r);const a=this.createFormGroup("escobar-openai-api-key","OpenAI API Key","Your OpenAI API key for OpenAI-powered features. (Optional)"),c=document.createElement("input");c.id="escobar-openai-api-key",c.className="escobar-settings-input",c.type="text",c.value=this.currentSettings.openaiApiKey||"",a.appendChild(c),o.appendChild(a);const l=this.createFormGroup("escobar-anthropic-api-key","Anthropic API Key","Your Anthropic API key for Claude-powered features. (Optional)"),d=document.createElement("input");d.id="escobar-anthropic-api-key",d.className="escobar-settings-input",d.type="text",d.value=this.currentSettings.anthropicApiKey||"",l.appendChild(d),o.appendChild(l);const u=this.createFormGroup("escobar-gemini-api-key","Gemini API Key","Your Google Gemini API key for Gemini-powered features. (Optional)"),p=document.createElement("input");p.id="escobar-gemini-api-key",p.className="escobar-settings-input",p.type="text",p.value=this.currentSettings.geminiApiKey||"",u.appendChild(p),o.appendChild(u);const g=document.createElement("div");g.id="primary-model-container",g.className="escobar-settings-group",o.appendChild(g);const m=document.createElement("div");m.id="secondary-provider-container",m.className="escobar-settings-group",o.appendChild(m);const h=document.createElement("div");h.id="image-parse-provider-container",h.className="escobar-settings-group",o.appendChild(h);const y=this.createFormGroup("escobar-proxy-port","Proxy Port","The port number for the proxy server."),f=document.createElement("input");f.id="escobar-proxy-port",f.className="escobar-settings-input",f.type="number",f.min="1",f.max="65535",f.value=(this.currentSettings.proxyPort||3e3).toString(),y.appendChild(f),o.appendChild(y);const v=this.createButtonsContainer();return o.appendChild(v),e.appendChild(o),e}updateFormFields(){const e=document.getElementById("escobar-max-messages"),t=document.getElementById("escobar-server-url"),n=document.getElementById("escobar-voitta-api-key"),o=document.getElementById("escobar-openai-api-key"),r=document.getElementById("escobar-anthropic-api-key"),i=document.getElementById("escobar-gemini-api-key"),s=document.getElementById("escobar-username"),a=document.getElementById("escobar-proxy-port");e&&(e.value=this.currentSettings.maxMessages.toString()),t&&(t.value=this.currentSettings.serverUrl),n&&(n.value=this.currentSettings.voittaApiKey||""),o&&(o.value=this.currentSettings.openaiApiKey||""),r&&(r.value=this.currentSettings.anthropicApiKey||""),i&&(i.value=this.currentSettings.geminiApiKey||""),s&&(s.value=this.currentSettings.username),a&&(a.value=(this.currentSettings.proxyPort||3e3).toString());const c=document.getElementById("primary-model-container"),l=document.getElementById("secondary-provider-container"),d=document.getElementById("image-parse-provider-container");if(c){c.innerHTML="";const e=this.createModelDropdown("escobar-primary-model","Primary Model","The main AI model used for chat responses.",this.currentSettings.primaryModel);c.appendChild(e)}if(l){l.innerHTML="";const e=this.createModelDropdown("escobar-secondary-provider","Secondary Provider","Secondary AI model for specialized tasks.",this.currentSettings.secondaryProvider);l.appendChild(e)}if(d){d.innerHTML="";const e=this.createModelDropdown("escobar-image-parse-provider","Image Parse Provider","AI model used for image analysis and parsing.",this.currentSettings.imageParseProvider);d.appendChild(e)}}saveSettings(){const e=document.getElementById("escobar-voitta-api-key"),t=document.getElementById("escobar-openai-api-key"),n=document.getElementById("escobar-anthropic-api-key"),o=document.getElementById("escobar-proxy-port");this.validateAndSaveCommonSettings({voittaApiKey:e.value.trim(),openaiApiKey:t.value.trim(),anthropicApiKey:n.value.trim(),proxyPort:o?parseInt(o.value,10):3e3})}}class Y extends q{createContainer(){const e=document.createElement("div");e.className="escobar-settings-container",e.style.maxWidth="400px";const t=this.createHeader("Connection Settings");e.appendChild(t);const n=document.createElement("div");n.className="escobar-mode-indicator",n.innerHTML=`Connection Parameters <span style="font-size: 0.8em; opacity: 0.8;">v${z}</span>`,n.style.backgroundColor="#e8f5e8",n.style.color="#2d5a2d",n.style.padding="8px 16px",n.style.margin="0 16px 16px 16px",n.style.borderRadius="4px",n.style.fontWeight="bold",n.style.textAlign="center",n.style.border="1px solid #a8d8a8",e.appendChild(n);const o=document.createElement("form");o.className="escobar-settings-form",o.addEventListener("submit",(e=>{e.preventDefault(),this.saveSettings()}));const r=this.createFormGroup("escobar-connection-server-url","Server URL","The WebSocket server URL. Changing this will trigger a reconnection."),i=document.createElement("input");i.id="escobar-connection-server-url",i.className="escobar-settings-input",i.type="text",i.value=this.currentSettings.serverUrl,r.appendChild(i),o.appendChild(r);const s=W(),a=this.createFormGroup("escobar-connection-username","Username",s?"Username extracted from JupyterHub (read-only).":"Your display name for chat messages."),c=document.createElement("input");if(c.id="escobar-connection-username",c.className="escobar-settings-input",c.type="text",c.value=this.currentSettings.username,s){c.disabled=!0,c.style.opacity="0.7",c.style.cursor="not-allowed";const e=document.createElement("div");e.className="escobar-settings-note",e.style.fontSize="0.85em",e.style.fontStyle="italic",e.style.marginTop="5px",e.style.color="#666",e.textContent="Username is extracted from JupyterHub URL and cannot be changed.",a.appendChild(e)}a.appendChild(c),o.appendChild(a);const l=this.createFormGroup("escobar-connection-bonnie-url","Bonnie URL","The WebSocket URL for the Bonnie backend server. If specified, this overrides the WEBSOCKET_PROXY_TARGET environment variable. (Optional)"),d=document.createElement("input");d.id="escobar-connection-bonnie-url",d.className="escobar-settings-input",d.type="text",d.placeholder="ws://bonnie:8777/ws",d.value=this.currentSettings.bonnieUrl||"",l.appendChild(d);const u=document.createElement("div");u.className="escobar-settings-note",u.style.fontSize="0.85em",u.style.fontStyle="italic",u.style.marginTop="5px",u.style.color="#666",u.innerHTML="Examples: <code>ws://localhost:8777/ws</code>, <code>wss://api.example.com/ws</code>",l.appendChild(u),o.appendChild(l);const p=document.createElement("div");p.style.cssText="\n background: #fff3cd;\n color: #856404;\n border: 1px solid #ffeaa7;\n border-radius: 4px;\n padding: 12px;\n margin: 16px;\n font-size: 14px;\n ",p.innerHTML="\n <strong>⚠️ Connection Settings</strong><br>\n Saving these settings will trigger a WebSocket reconnection. \n Any ongoing chat operations will be interrupted.\n ",o.appendChild(p);const g=this.createButtonsContainer();return o.appendChild(g),e.appendChild(o),e}updateFormFields(){const e=document.getElementById("escobar-connection-server-url"),t=document.getElementById("escobar-connection-username"),n=document.getElementById("escobar-connection-bonnie-url");e&&(e.value=this.currentSettings.serverUrl),t&&(t.value=this.currentSettings.username),n&&(n.value=this.currentSettings.bonnieUrl||"")}saveSettings(){const e=document.getElementById("escobar-connection-server-url"),t=document.getElementById("escobar-connection-username"),n=document.getElementById("escobar-connection-bonnie-url"),o=e.value.trim(),r=t.value.trim(),i=n.value.trim();if(!o)return void alert("Server URL is required");if(!r)return void alert("Username is required");if(i&&i.length>0)try{const e=new URL(i);if(!["ws:","wss:"].includes(e.protocol))return void alert("Bonnie URL must use ws:// or wss:// protocol")}catch(e){return void alert("Invalid Bonnie URL format. Please enter a valid WebSocket URL.")}const s={...this.currentSettings,serverUrl:o,username:r,bonnieUrl:i||void 0};console.log("🔗 CONNECTION: Saving connection settings"),this.saveConnectionSettings(s)}async saveConnectionSettings(e){try{const t=await this.settingsRegistry.load("escobar:plugin");console.log("🔗 CONNECTION: Saving to registry (will trigger reconnection)"),await t.set("serverUrl",e.serverUrl),await t.set("username",e.username),await t.set("usernameFromJupyterHub",e.usernameFromJupyterHub),await t.set("bonnieUrl",e.bonnieUrl||""),console.log("🔗 CONNECTION: Registry save successful"),this.currentSettings=e,window.escobarCurrentSettings=e,this.onSave(e),console.log("🔗 CONNECTION: Connection settings save completed"),this.hide()}catch(e){console.error("🔗 CONNECTION: Failed to save connection settings:",e),alert(`Failed to save connection settings:\n\n${e instanceof Error?e.message:"Unknown error"}\n\nPlease try again.`)}}}class X extends q{createContainer(){const e=document.createElement("div");e.className="escobar-settings-container";const t=this.createHeader("Settings");e.appendChild(t);const n=document.createElement("div");n.className="escobar-mode-indicator",n.innerHTML=`Running in Plugin Mode <span style="font-size: 0.8em; opacity: 0.8;">v${z}</span>`,n.style.backgroundColor="#f6f8fa",n.style.color="#24292e",n.style.padding="8px 16px",n.style.margin="0 16px 16px 16px",n.style.borderRadius="4px",n.style.fontWeight="bold",n.style.textAlign="center",n.style.border="1px solid #e1e4e8",e.appendChild(n);const o=document.createElement("form");o.className="escobar-settings-form",o.addEventListener("submit",(e=>{e.preventDefault(),this.saveSettings()}));const r=this.createFormGroup("escobar-voitta-api-key","Voitta API Key","The API key for authentication with Voitta services. (Optional)"),i=document.createElement("input");i.id="escobar-voitta-api-key",i.className="escobar-settings-input",i.type="text",i.value=this.currentSettings.voittaApiKey||"",r.appendChild(i);const s=document.createElement("a");s.href="#",s.className="escobar-get-api-key-link",s.textContent="Get Voitta API Key",s.style.display=this.currentSettings.voittaApiKey?"none":"block",s.addEventListener("click",(e=>{e.preventDefault(),G().then((e=>{i.value=e,s.style.display="none",alert("Successfully obtained Voitta API key!")})).catch((e=>{"Authentication cancelled"!==e.message&&(console.error("Authentication error:",e),alert("Failed to authenticate. Please try again."))}))})),r.appendChild(s),i.addEventListener("input",(()=>{s.style.display=i.value?"none":"block"})),o.appendChild(r);const a=this.createFormGroup("escobar-openai-api-key","OpenAI API Key","Your OpenAI API key for OpenAI-powered features. (Optional)"),c=document.createElement("input");c.id="escobar-openai-api-key",c.className="escobar-settings-input",c.type="text",c.value=this.currentSettings.openaiApiKey||"",a.appendChild(c),o.appendChild(a);const l=this.createFormGroup("escobar-anthropic-api-key","Anthropic API Key","Your Anthropic API key for Claude-powered features. (Optional)"),d=document.createElement("input");d.id="escobar-anthropic-api-key",d.className="escobar-settings-input",d.type="text",d.value=this.currentSettings.anthropicApiKey||"",l.appendChild(d),o.appendChild(l);const u=this.createFormGroup("escobar-gemini-api-key","Gemini API Key","Your Google Gemini API key for Gemini-powered features. (Optional)"),p=document.createElement("input");p.id="escobar-gemini-api-key",p.className="escobar-settings-input",p.type="text",p.value=this.currentSettings.geminiApiKey||"",u.appendChild(p),o.appendChild(u);const g=document.createElement("div");g.id="primary-model-container",g.className="escobar-settings-group",o.appendChild(g);const m=document.createElement("div");m.id="secondary-provider-container",m.className="escobar-settings-group",o.appendChild(m);const h=document.createElement("div");h.id="image-parse-provider-container",h.className="escobar-settings-group",o.appendChild(h);const y=this.createFormGroup("escobar-proxy-port","Proxy Port","The port number for the proxy server."),f=document.createElement("input");f.id="escobar-proxy-port",f.className="escobar-settings-input",f.type="number",f.min="1",f.max="65535",f.value=(this.currentSettings.proxyPort||3e3).toString(),y.appendChild(f),o.appendChild(y);const v=this.createButtonsContainer();return o.appendChild(v),e.appendChild(o),e}updateFormFields(){const e=document.getElementById("escobar-max-messages"),t=document.getElementById("escobar-server-url"),n=document.getElementById("escobar-voitta-api-key"),o=document.getElementById("escobar-openai-api-key"),r=document.getElementById("escobar-anthropic-api-key"),i=document.getElementById("escobar-gemini-api-key"),s=document.getElementById("escobar-username"),a=document.getElementById("escobar-proxy-port");document.getElementById("escobar-primary-model"),document.getElementById("escobar-secondary-provider"),document.getElementById("escobar-image-parse-provider"),e&&(e.value=this.currentSettings.maxMessages.toString()),t&&(t.value=this.currentSettings.serverUrl),n&&(n.value=this.currentSettings.voittaApiKey||""),o&&(o.value=this.currentSettings.openaiApiKey||""),r&&(r.value=this.currentSettings.anthropicApiKey||""),i&&(i.value=this.currentSettings.geminiApiKey||""),s&&(s.value=this.currentSettings.username),a&&(a.value=(this.currentSettings.proxyPort||3e3).toString());const c=document.getElementById("primary-model-container"),l=document.getElementById("secondary-provider-container"),d=document.getElementById("image-parse-provider-container");if(c){c.innerHTML="";const e=this.createModelDropdown("escobar-primary-model","Primary Model","The main AI model used for chat responses.",this.currentSettings.primaryModel);c.appendChild(e)}if(l){l.innerHTML="";const e=this.createModelDropdown("escobar-secondary-provider","Secondary Provider",`Current value: ${this.currentSettings.secondaryProvider||"Not set"}`,this.currentSettings.secondaryProvider);l.appendChild(e)}if(d){d.innerHTML="";const e=this.createModelDropdown("escobar-image-parse-provider","Image Parse Provider","AI model used for image analysis and parsing.",this.currentSettings.imageParseProvider);d.appendChild(e)}}saveSettings(){const e=document.getElementById("escobar-voitta-api-key"),t=document.getElementById("escobar-openai-api-key"),n=document.getElementById("escobar-anthropic-api-key"),o=document.getElementById("escobar-proxy-port");this.validateAndSaveCommonSettings({voittaApiKey:e.value.trim(),openaiApiKey:t.value.trim(),anthropicApiKey:n.value.trim(),proxyPort:o?parseInt(o.value,10):3e3})}}var Q=n(2235);function Z(e,t,n,o){const r=document.createElement("button");r.className=`escobar-icon-button ${e}`,r.title=o,r.style.cssText=t;const i=document.createElement("span");return i.className="escobar-icon-container",i.innerHTML=n,r.appendChild(i),r}var ee=n(9650),te=n.n(ee),ne=n(5271),oe=n.n(ne),re=n(1731),ie=n.n(re),se=n(6954),ae=n.n(se);const ce=new(te())({html:!0,breaks:!0,linkify:!0,typographer:!0,highlight:function(e,t){if(t&&oe().getLanguage(t))try{return oe().highlight(e,{language:t,ignoreIllegals:!0}).value}catch(e){}return""}});ce.enable("emphasis"),ce.enable("link"),ce.enable("heading"),ce.enable("code"),ce.enable("fence"),ce.enable("blockquote"),ce.enable("list"),ce.enable("table"),ce.enable("image"),ce.enable("strikethrough"),ce.use(ie()),ce.use(ae()),ce.use((function(e){const t=e.renderer.rules.fence.bind(e.renderer.rules);e.renderer.rules.fence=(e,n,o,r,i)=>{const s=e[n];if("question"===s.info.trim()){const e=s.content.trim().split("\n"),t=e[0],n=e.slice(1).filter((e=>e.trim()));let o='<div class="escobar-question-block">';return o+=`<div class="escobar-question">${t}</div>`,o+='<div class="escobar-question-options">',n.forEach(((e,t)=>{const n=e.replace(/'/g,"\\'");o+=`<button class="escobar-question-option" data-option="${t}" \n onclick="(function() {\n // Find the chat input textarea\n const chatInput = document.querySelector('.escobar-chat-input');\n if (chatInput) {\n // Set the textarea value to the button text\n chatInput.value = '${n}';\n \n // Find and click the send button\n const sendButton = document.querySelector('.jp-Button.escobar-send-button');\n if (sendButton) {\n sendButton.click();\n } else {\n // Fallback to any button that might be the send button\n const buttons = document.querySelectorAll('button');\n for (const btn of buttons) {\n if (btn.textContent && ['Send', 'Talk', 'Plan', 'Act'].includes(btn.textContent.trim())) {\n btn.click();\n break;\n }\n }\n }\n }\n })();">${e}</button>`})),o+="</div></div>",o}return t(e,n,o,r,i)}}));const le=ce.renderer.rules.table_open||function(e,t,n,o,r){return r.renderToken(e,t,n)};ce.renderer.rules.table_open=function(e,t,n,o,r){return'<div class="table-wrapper">'+le(e,t,n,o,r)};const de=ce.renderer.rules.table_close||function(e,t,n,o,r){return r.renderToken(e,t,n)};ce.renderer.rules.table_close=function(e,t,n,o,r){return de(e,t,n,o,r)+"</div>"};const ue=ce.renderer.rules.image||function(e,t,n,o,r){return r.renderToken(e,t,n)};ce.renderer.rules.image=function(e,t,n,o,r){const i=e[t],s=i.attrIndex("src");return s>=0&&i.attrs[s][1],i.attrIndex("loading")<0&&i.attrPush(["loading","lazy"]),i.attrIndex("onerror")<0&&i.attrPush(["onerror","this.onerror=null;this.style.border='1px solid #ddd';this.style.padding='10px';this.style.width='auto';this.style.height='auto';this.alt='Image failed to load: ' + this.alt;this.src='data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"%3E%3Cpath fill=\"%23ccc\" d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"/%3E%3C/svg%3E';"]),ue(e,t,n,o,r)};class pe{constructor(e,t,n=""){this.id=e,this.role=t,this.isNew=!0,this.content=n,this.rawContent=n,this.messageElement=document.createElement("div"),this.messageElement.className=`escobar-message escobar-message-${t}`,this.messageElement.dataset.messageId=e,this.contentElement=document.createElement("div"),this.contentElement.className="escobar-message-content markdown-content","assistant"!==t&&"action"!==t||!n?this.contentElement.textContent=n:this.contentElement.innerHTML=ce.render(n),this.messageElement.appendChild(this.contentElement)}setContent(e){this.content=e,this.rawContent=e,"assistant"===this.role||"action"===this.role?this.contentElement.innerHTML=ce.render(e):this.contentElement.textContent=e;const t=this.messageElement.closest(".escobar-chat-container");t&&setTimeout((()=>{t.scrollTop=t.scrollHeight}),0)}getRawContent(){return this.rawContent}getContent(){return this.content}getElement(){return this.messageElement}}class ge{constructor(e,t,n,o,r,i,s,a=100){this.messages=[],this.messageMap=new Map,this.currentChatID="temp-session",this.voittaApiKey=e,this.openaiApiKey=t,this.anthropicApiKey=n,this.geminiApiKey=o,this.selectedProvider=r,this.username=i,this.chatContainer=s,this.maxMessages=a}updateSettings(e,t,n,o,r,i,s){this.voittaApiKey=e,this.openaiApiKey=t,this.anthropicApiKey=n,this.geminiApiKey=o,this.selectedProvider=r,this.username=i,this.maxMessages=s}setCurrentChatID(e){this.currentChatID=e}getCurrentChatID(){return this.currentChatID}generateMessageId(e=""){return`${e}-msg-${Date.now()}-${ge.messageCounter++}`}findMessageById(e){return this.messageMap.get(e)}addMessage(e,t,n){const o=n||this.generateMessageId(),r=new pe(o,e,t);return this.messages.push(r),this.messageMap.set(o,r),this.chatContainer.appendChild(r.getElement()),this.chatContainer.scrollTop=this.chatContainer.scrollHeight,this.limitMessages(),r}limitMessages(){if(this.messages.length>this.maxMessages){const e=this.messages.length-this.maxMessages,t=this.messages.splice(0,e);for(const e of t)this.chatContainer.removeChild(e.getElement()),this.messageMap.delete(e.id)}}async clearMessages(){const e=[...this.messages];this.messages=[];for(const t of e)try{this.chatContainer.contains(t.getElement())&&this.chatContainer.removeChild(t.getElement()),this.messageMap.delete(t.id)}catch(e){console.error("Error removing message:",e)}this.messageMap.clear()}async loadMessages(){const e=this.generateMessageId(),t={method:"loadMessages",username:this.username,chatID:this.currentChatID,call_id:e,message_type:"request"};try{const e=await(0,u.callPython)(t);if(!e.value||!Array.isArray(e.value))return void console.warn("Invalid response format for loadMessages:",e);for(let t=0;t<e.value.length;t++){const n=e.value[t];switch(n.role){case"user":("string"==typeof n.content||n.content instanceof String)&&this.addMessage("user",n.content);break;case"assistant":if("string"==typeof n.content||n.content instanceof String)this.addMessage("assistant",String(n.content));else if(n.content&&Array.isArray(n.content))for(let e=0;e<n.content.length;e++){const t=n.content[e];"tool_use"===t.type&&t.name?this.addMessage("action",`🔧 ${t.name}`):"text"===t.type&&t.text&&this.addMessage("assistant",t.text)}}}}catch(e){throw console.error("Error loading messages:",e),e}}async createNewChat(e){var t;await this.clearMessages();let n="openai";if(e)switch(e.toLowerCase()){case"openai":n="openai";break;case"anthropic":n="anthropic";break;case"gemini":n="gemini";break;default:console.warn(`Unknown provider: ${e}, defaulting to openai`),n="openai"}const o=this.generateMessageId(),r={method:"createNewChat",username:this.username,call_id:o,message_type:"request",provider:n,api_key:"--key--",openai_api_key:"--key--",anthropic_api_key:"--key--",gemini_api_key:"--key--"};console.log("Sending createNewChat request:",r);const i=await(0,u.callPython)(r);if(console.log("Received createNewChat response:",i),"error_type"in i||"string"==typeof i.value&&!i.value.includes("chatID")){const e=i,t=e.value||"Unknown error occurred while creating chat";throw console.error("Error creating new chat:",e),new Error(`Failed to create new chat: ${t}`)}const s=null===(t=i.value)||void 0===t?void 0:t.chatID;if(!s)throw console.error("Invalid server response for createNewChat:",i),new Error(`Server did not return a valid chatID. Response: ${JSON.stringify(i)}`);return console.log("Successfully created new chat with ID:",s),this.currentChatID=s,s}async sendMessage(e,t,n){if("temp-session"===this.currentChatID){const e=this.generateMessageId();this.addMessage("assistant","💡 **Starting a new chat session** - Your conversation will be saved automatically.",e);const t=await this.createNewChat();this.onChatCreated&&this.onChatCreated(t)}const o=this.generateMessageId(),r=this.generateMessageId(),i=await async function(){const e=T.shell.widgets("main"),t=(T.shell.currentWidget,[]);return Array.from(e).forEach((e=>{var n,o,r,i,s,a;let c={id:e.id,title:e.title.label||"Untitled",type:"unknown",isVisible:!1};e instanceof p.NotebookPanel?(c.type="notebook",c.path=(null===(n=e.context)||void 0===n?void 0:n.path)||""):e instanceof m.FileEditor||(null===(r=null===(o=e.context)||void 0===o?void 0:o.path)||void 0===r?void 0:r.includes("."))?(c.type="file",c.path=(null===(i=e.context)||void 0===i?void 0:i.path)||""):(e.id.startsWith("terminal")||(null===(a=null===(s=e.title)||void 0===s?void 0:s.label)||void 0===a?void 0:a.toLowerCase().includes("terminal")))&&(c.type="terminal",c.name=e.title.label.replace("Terminal ","")||""),c.isVisible=e.isVisible,t.push(c)})),t}(),s=await F.listCells.func();this.addMessage("user",e,o);const a=this.addMessage("assistant","Waiting for response...",r),c=(0,u.mt)();var l=!1;if(c&&c.readyState===WebSocket.OPEN)try{const n=window.escobarCurrentSettings,o=(null==n?void 0:n.primaryModel)||"undefined",c=(null==n?void 0:n.secondaryProvider)||"undefined",l=(null==n?void 0:n.imageParseProvider)||"undefined",d={method:"userMessage",username:this.username,chatID:this.currentChatID,call_id:r,message_type:"request",user_message:e,opened_tabs:i,current_notebook:s,mode:t,api_key:this.voittaApiKey,openai_api_key:this.openaiApiKey,anthropic_api_key:this.anthropicApiKey,gemini_api_key:this.geminiApiKey,selected_provider:o,secondary_provider:c,image_parse_provider:l},p=await(0,u.callPython)(d,36e5,!0,!0);this.handlePythonResponse(p,a)}catch(e){null!=e.stop?(l=!0,u.Tg[r]=!0,a.setContent("Interrupted by the user")):a.setContent("Error sending message to server")}else setTimeout((()=>{a.setContent(`Echo: ${e} (WebSocket not connected)`)}),500);if(l){const e={method:"userStop",username:this.username,chatID:this.currentChatID,call_id:r,message_type:"request"};await(0,u.callPython)(e,0,!1)}return a}handlePythonResponse(e,t){try{let o;var n=e.value;o="string"==typeof n?n:n&&"object"==typeof n?JSON.stringify(n):"Received empty response from server",t&&t.setContent(o)}catch(e){console.error("Error handling Python response:",e),t&&t.setContent("Error: Failed to process server response")}}async saveSettingsToServer(e){const t=this.generateMessageId(),n={method:"saveSettings",username:this.username,call_id:t,message_type:"request",openai_api_key:e.openaiApiKey,gemini_api_key:e.geminiApiKey,anthropic_api_key:e.anthropicApiKey,voitta_api_key:e.voittaApiKey,max_messages:e.maxMessages,proxy_port:e.proxyPort,primary_model:e.primaryModel,secondary_provider:e.secondaryProvider,image_parse_provider:e.imageParseProvider},o=await(0,u.callPython)(n);if("error_type"in o)throw new Error(`Failed to save settings: ${o.value}`);console.log("Settings saved to server successfully")}async retrieveSettingsFromServer(){const e=this.generateMessageId(),t={method:"retrieveSettings",username:this.username,call_id:e,message_type:"request"},n=await(0,u.callPython)(t);if("error_type"in n)throw new Error(`Failed to retrieve settings: ${n.value}`);const o=n;return{openaiApiKey:o.openai_api_key||"",geminiApiKey:o.gemini_api_key||"",anthropicApiKey:o.anthropic_api_key||"",voittaApiKey:o.voitta_api_key||"",maxMessages:o.max_messages||100,proxyPort:o.proxy_port||3e3,primaryModel:o.primary_model,secondaryProvider:o.secondary_provider,imageParseProvider:o.image_parse_provider}}getMessages(){return[...this.messages]}}ge.messageCounter=0;var me=n(5606);const he={serverUrl:me.env.SERVER_URL||"/ws",username:"User",usernameFromJupyterHub:!1,bonnieUrl:"ws://bonnie:8777/ws",googleClientId:""},ye={voittaApiKey:"The Future Of Computing",openaiApiKey:"",anthropicApiKey:"",geminiApiKey:"",maxMessages:100,proxyPort:3e3,primaryModel:void 0,secondaryProvider:void 0,imageParseProvider:void 0};class fe{constructor(e){this.messageHandler=null,this.settingsRegistry=e,this.localSettings={...he},this.remoteSettings={...ye}}setMessageHandler(e){this.messageHandler=e}setOnSettingsChanged(e){this.onSettingsChanged=e}async loadLocalSettings(){if(console.log("🔧 SETTINGS: Loading local settings from registry"),!this.settingsRegistry)return console.warn("🔧 SETTINGS: Registry not available, using defaults"),{...he};try{const e=(await this.settingsRegistry.load("escobar:plugin")).composite;return this.localSettings={serverUrl:e.serverUrl||he.serverUrl,username:e.username||he.username,usernameFromJupyterHub:e.usernameFromJupyterHub||he.usernameFromJupyterHub,bonnieUrl:e.bonnieUrl||he.bonnieUrl,googleClientId:e.googleClientId||he.googleClientId},me.env.SERVER_URL&&(this.localSettings.serverUrl=me.env.SERVER_URL,console.log("🔧 SETTINGS: Using serverUrl from environment")),console.log("🔧 SETTINGS: Local settings loaded successfully"),{...this.localSettings}}catch(e){return console.error("🔧 SETTINGS: Failed to load local settings:",e),this.localSettings={...he},{...this.localSettings}}}async saveLocalSettings(e){if(console.log("🔧 SETTINGS: Saving local settings to registry"),!this.settingsRegistry)throw new Error("Settings registry not available");try{const t=await this.settingsRegistry.load("escobar:plugin");console.log("📋 SCHEMA: Saving to registry:",{serverUrl:e.serverUrl,username:e.username,usernameFromJupyterHub:e.usernameFromJupyterHub,bonnieUrl:e.bonnieUrl,googleClientId:e.googleClientId}),await t.set("serverUrl",e.serverUrl),await t.set("username",e.username),await t.set("usernameFromJupyterHub",e.usernameFromJupyterHub),void 0!==e.bonnieUrl&&await t.set("bonnieUrl",e.bonnieUrl),void 0!==e.googleClientId&&await t.set("googleClientId",e.googleClientId),this.localSettings={...e},console.log("🔧 SETTINGS: Local settings saved successfully"),this.notifySettingsChanged()}catch(e){throw console.error("📋 SCHEMA: Registry save failed:",e),e}}async loadRemoteSettings(){if(console.log("🔧 SETTINGS: Loading remote settings from server"),!this.messageHandler)return console.warn("🔧 SETTINGS: Message handler not available, using defaults"),{...ye};try{console.log("📤 PROTOCOL: Sending retrieveSettings request");const e=await this.messageHandler.retrieveSettingsFromServer();return console.log("📥 PROTOCOL: Received retrieveSettings response"),this.remoteSettings={voittaApiKey:e.voittaApiKey||ye.voittaApiKey,openaiApiKey:e.openaiApiKey||ye.openaiApiKey,anthropicApiKey:e.anthropicApiKey||ye.anthropicApiKey,geminiApiKey:e.geminiApiKey||ye.geminiApiKey,maxMessages:e.maxMessages||ye.maxMessages,proxyPort:e.proxyPort||ye.proxyPort,primaryModel:e.primaryModel,secondaryProvider:e.secondaryProvider,imageParseProvider:e.imageParseProvider},console.log("🔧 SETTINGS: Remote settings loaded successfully"),{...this.remoteSettings}}catch(e){return console.warn("🔧 SETTINGS: Failed to load remote settings, using defaults:",e),this.remoteSettings={...ye},{...this.remoteSettings}}}async saveRemoteSettings(e){if(console.log("🔧 SETTINGS: Saving remote settings to server"),!this.messageHandler)throw new Error("Message handler not available for saving remote settings");try{console.log("📤 PROTOCOL: Sending saveSettings request"),await this.messageHandler.saveSettingsToServer(e),console.log("📥 PROTOCOL: Received saveSettings response"),this.remoteSettings={...e},console.log("🔧 SETTINGS: Remote settings saved successfully"),this.notifySettingsChanged()}catch(e){throw console.error("🔧 SETTINGS: Failed to save remote settings:",e),e}}getCompleteSettings(){return{...this.localSettings,...this.remoteSettings}}getLocalSettings(){return{...this.localSettings}}getRemoteSettings(){return{...this.remoteSettings}}async initializeSettings(){if(console.log("Initializing settings..."),await this.loadLocalSettings(),this.messageHandler)try{await this.loadRemoteSettings()}catch(e){console.warn("Could not load remote settings during initialization:",e)}const e=this.getCompleteSettings();return console.log("Settings initialization complete"),e}async updateLocalSetting(e,t){const n={...this.localSettings,[e]:t};await this.saveLocalSettings(n)}async updateRemoteSetting(e,t){const n={...this.remoteSettings,[e]:t};await this.saveRemoteSettings(n)}notifySettingsChanged(){this.onSettingsChanged&&this.onSettingsChanged(this.getCompleteSettings())}setupLocalSettingsListener(){this.settingsRegistry&&this.settingsRegistry.load("escobar:plugin").then((e=>{e.changed.connect((()=>{this.loadLocalSettings().then((()=>{this.notifySettingsChanged()}))}))})).catch((e=>{console.error("Failed to setup local settings listener:",e)}))}}const ve=36e5;function be(e){let t=null;if(e&&(t=e.getLocalSettings()),(null==t?void 0:t.usernameFromJupyterHub)||window.location.href.includes("/user/")){const e=function(){const e=/\/user\/([^\/]+)\//,t=window.location.pathname.match(e);if(t&&t[1])return{username:decodeURIComponent(t[1]),fromJupyterHub:!0};const n=window.location.href.match(e);if(n&&n[1])return{username:decodeURIComponent(n[1]),fromJupyterHub:!0};try{const e=document.getElementById("jupyter-config-data");if(e&&e.textContent){const t=JSON.parse(e.textContent);if(t.hubUser)return{username:t.hubUser,fromJupyterHub:!0};if(t.hubUsername)return{username:t.hubUsername,fromJupyterHub:!0};if(t.user)return{username:t.user,fromJupyterHub:!0}}}catch(e){console.error("Error parsing JupyterHub config:",e)}try{const e=document.baseURI.match(/\/user\/([^\/]+)\//);if(e&&e[1])return{username:decodeURIComponent(e[1]),fromJupyterHub:!0}}catch(e){console.error("Error checking baseURI:",e)}try{const e=document.cookie.split(";");for(const t of e){const[e,n]=t.trim().split("=");if("jupyterhub-user"===e)return{username:decodeURIComponent(n),fromJupyterHub:!0}}}catch(e){console.error("Error checking cookies:",e)}const o=/user\/([^\/]+)/,r=window.location.pathname.match(o);if(r&&r[1])return{username:decodeURIComponent(r[1]),fromJupyterHub:!0};const i=window.location.href.match(o);if(i&&i[1])return{username:decodeURIComponent(i[1]),fromJupyterHub:!0};const s=window.location.href.match(/user\/([^\/]+@[^\/]+)/);return s&&s[1]?{username:decodeURIComponent(s[1]),fromJupyterHub:!0}:(console.log("No JupyterHub username found, using default"),{username:"VoittaDefaultUser",fromJupyterHub:!1})}();if(e.fromJupyterHub)return e.username}return(null==t?void 0:t.username)&&"User"!==t.username||(null==t?void 0:t.username)?t.username:`VoittaDefaultUser@${window.location.hostname||"localhost"}`}class we extends c.Widget{constructor(e,t,o,r){const i="escobar-chat-"+we.idCounter++;super(),this.chatSelectionContainer=null,this.currentChatID="temp-session",this.availableChats=[],this.availableModels=[],this.call_id_log={},this.app=e,this.notebookTracker=o,this.settingsRegistry=t,this.debuggerService=r,this.id=i,this.addClass("escobar-chat"),this.title.label="Voitta",this.title.caption="Escobar Voitta",this.title.iconClass="jp-MessageIcon",this.title.closable=!0,this.settingsManager=new fe(t),this.node.style.display="flex",this.node.style.flexDirection="column",this.node.style.height="100%",this.node.style.padding="5px",this.node.style.position="relative",this.buttonContainer=function(e,t,o,r,i,s,a=[],c,l="temp-session"){const d=document.createElement("div");d.className="escobar-button-container",d.style.position="relative";const u="\n font-weight: bold;\n margin: 0 5px;\n padding: 5px;\n background: transparent;\n border: none;\n color: var(--jp-content-font-color1);\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.2s ease;\n ",p=Z("escobar-new-chat-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <line x1="12" y1="5" x2="12" y2="19"></line>\n <line x1="5" y1="12" x2="19" y2="12"></line>\n </svg>',"New Chat"),g=document.createElement("div");g.className="escobar-warning-container",g.style.cssText="\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n background: var(--jp-warn-color0);\n color: var(--jp-warn-color1);\n border: 1px solid var(--jp-warn-color1);\n border-radius: 4px;\n padding: 8px;\n font-size: 12px;\n z-index: 1000;\n display: none;\n margin-top: 4px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n ";let m=!1;d.updateChatState=e=>{m="temp-session"!==e&&""!==e},p.addEventListener("click",(async()=>{g.style.display="none",await r(),console.log("New chat created"),m=!0})),document.addEventListener("click",(e=>{g.contains(e.target)||(g.style.display="none")})),d.appendChild(p),d.appendChild(g);const h=Z("escobar-reconnect-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"></path>\n </svg>',"Reconnect");h.addEventListener("click",(async()=>{console.log("Reconnect button clicked");try{await i(),console.log("Reconnected and initialized successfully");const e=h.querySelector(".escobar-icon-container");if(e){e.style.opacity;for(let t=0;t<3;t++)e.style.opacity="0.2",await new Promise((e=>setTimeout(e,150))),e.style.opacity="1",await new Promise((e=>setTimeout(e,150)))}}catch(e){console.error("Error reconnecting to server:",e)}})),d.appendChild(h);const y=Z("escobar-ui-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>\n <line x1="8" y1="21" x2="16" y2="21"></line>\n <line x1="12" y1="17" x2="12" y2="21"></line>\n </svg>',"Open UI");y.addEventListener("click",(()=>{console.log("UI button clicked - opening iframe");const t=$["ui-url"];if(void 0===t)return;const n=Array.from(e.shell.widgets("main")).find((e=>"escobar-iframe"===e.id));if(n){console.log("Updating existing iframe URL to:",t),n.url=t;try{n.sandbox=["allow-scripts","allow-same-origin","allow-forms","allow-modals"]}catch(e){console.warn("Could not update iframe sandbox settings:",e)}e.shell.activateById(n.id)}else{const n=new Q.IFrame({sandbox:["allow-scripts","allow-same-origin","allow-forms","allow-modals"]});n.node.setAttribute("frameborder","0"),n.node.setAttribute("allowfullscreen","true"),n.node.setAttribute("webkitallowfullscreen","true"),n.node.setAttribute("mozallowfullscreen","true"),n.url=t,n.id="escobar-iframe",n.title.label="UI",n.title.closable=!0,n.node.style.height="100%",e.shell.add(n,"main"),e.shell.activateById(n.id)}})),d.appendChild(y);const f=document.createElement("select");f.className="escobar-chat-dropdown",f.style.cssText="\n font-weight: bold;\n margin: 0 5px;\n padding: 5px 8px;\n background: var(--jp-layout-color0);\n color: var(--jp-content-font-color1);\n border: 1px solid var(--jp-border-color1);\n border-radius: 4px;\n font-size: 12px;\n cursor: pointer;\n min-width: 150px;\n max-width: 200px;\n ";const v=(e,t)=>{void 0!==e&&(a.length=0,a.push(...e)),void 0!==t&&(l=t),f.innerHTML="";const n=a.filter((e=>e.chatId&&"temp-session"!==e.chatId));n.forEach((e=>{const t=document.createElement("option");t.value=e.chatId;const n=e.title||"Untitled Chat";let o="Unknown";if(e.lastModified&&"Unknown"!==e.lastModified)try{const t=new Date(e.lastModified);isNaN(t.getTime())||(o=t.toLocaleString("en-US",{month:"numeric",day:"numeric",year:"numeric",hour:"2-digit",minute:"2-digit",hour12:!0}))}catch(t){console.warn("Error parsing date:",e.lastModified,t)}t.textContent=`${n} - ${o}`,f.appendChild(t)})),f.style.display="inline-block","temp-session"!==l&&n.length>0&&n.some((e=>e.chatId===l))&&(f.value=l)};f.addEventListener("change",(async()=>{const e=f.value;e&&c&&(console.log("Chat dropdown selection:",e),await c(e))})),v(),d.updateChatDropdown=v,d.appendChild(f);const b=Z("escobar-google-auth-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <circle cx="12" cy="7" r="4"/>\n <path d="M12 11v10"/>\n <path d="M14 19h4"/>\n <path d="M14 16h3"/>\n <path d="M14 22h2"/>\n </svg>',"Google Authentication");b.addEventListener("click",(async()=>{var e,t,r;console.log("🔐 UI: Google Auth button clicked");try{const i=o().googleClientId;if(!i){const e=document.createElement("div");return e.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: var(--jp-error-color0);\n color: var(--jp-error-color1);\n padding: 12px 16px;\n border-radius: 4px;\n border: 1px solid var(--jp-error-color1);\n z-index: 10000;\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n ",e.textContent="Google Client ID not configured. Please set it in the settings first.",document.body.appendChild(e),void setTimeout((()=>{e.parentNode&&e.parentNode.removeChild(e)}),5e3)}let s=(0,K.Hn)();s||(s=(0,K.e$)({clientId:i,scope:"openid email profile https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/documents.readonly"}));const a=b.innerHTML;b.innerHTML='\n <span class="escobar-icon-container">\n <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <path d="M21 12a9 9 0 11-6.219-8.56"/>\n </svg>\n </span>\n ',b.disabled=!0;const c=await s.loginWithAuthCode();if(b.innerHTML=a,b.disabled=!1,c.success&&c.authorizationCode){console.log("🔐 UI: Google OAuth successful, received authorization code"),console.log("🔐 UI: Auth code:",c.authorizationCode.substring(0,20)+"...");const{updateCredentials:o}=await Promise.resolve().then(n.bind(n,9838)),a=await o(c.authorizationCode,c.redirectUri||s.getRedirectUri(),i,void 0,c.state);if(a.success){console.log("🔐 UI: Credentials updated successfully"),console.log("🔐 UI: User:",null===(e=a.userInfo)||void 0===e?void 0:e.email),window.escobarGoogleUserInfo=a.userInfo,console.log("🔐 UI: User info stored globally"),b.title=`Authenticated as ${(null===(t=a.userInfo)||void 0===t?void 0:t.email)||"Google User"}`;const n=document.createElement("div");n.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: var(--jp-success-color0);\n color: var(--jp-success-color1);\n padding: 12px 16px;\n border-radius: 4px;\n border: 1px solid var(--jp-success-color1);\n z-index: 10000;\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n ",n.textContent=`Successfully authenticated as ${(null===(r=a.userInfo)||void 0===r?void 0:r.email)||"Google User"}`,document.body.appendChild(n),setTimeout((()=>{n.parentNode&&n.parentNode.removeChild(n)}),3e3)}else{console.error("🔐 UI: Failed to update credentials:",a.error);const e=document.createElement("div");e.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: var(--jp-error-color0);\n color: var(--jp-error-color1);\n padding: 12px 16px;\n border-radius: 4px;\n border: 1px solid var(--jp-error-color1);\n z-index: 10000;\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n ",e.textContent=`Credential update failed: ${a.error||"Unknown error"}`,document.body.appendChild(e),setTimeout((()=>{e.parentNode&&e.parentNode.removeChild(e)}),5e3)}}else{console.error("🔐 UI: Google authentication failed:",c.error);const e=document.createElement("div");e.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: var(--jp-error-color0);\n color: var(--jp-error-color1);\n padding: 12px 16px;\n border-radius: 4px;\n border: 1px solid var(--jp-error-color1);\n z-index: 10000;\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n ",e.textContent=`Authentication failed: ${c.error||"Unknown error"}`,document.body.appendChild(e),setTimeout((()=>{e.parentNode&&e.parentNode.removeChild(e)}),5e3)}}catch(e){console.error("🔐 UI: Error during Google authentication:",e);const t='\n <span class="escobar-icon-container">\n <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <circle cx="12" cy="7" r="4"/>\n <path d="M12 11v10"/>\n <path d="M14 19h4"/>\n <path d="M14 16h3"/>\n <path d="M14 22h2"/>\n </svg>\n </span>\n ';b.innerHTML=t,b.disabled=!1;const n=document.createElement("div");n.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: var(--jp-error-color0);\n color: var(--jp-error-color1);\n padding: 12px 16px;\n border-radius: 4px;\n border: 1px solid var(--jp-error-color1);\n z-index: 10000;\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n ",n.textContent=`Authentication error: ${e.message||"Unknown error occurred"}`,document.body.appendChild(n),setTimeout((()=>{n.parentNode&&n.parentNode.removeChild(n)}),5e3)}})),d.appendChild(b);const w=Z("escobar-settings-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <circle cx="12" cy="12" r="3"></circle>\n <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>\n </svg>',"Settings");w.addEventListener("click",(()=>{if(t){const e=function(e,t,n){return W()?new V(e,t,n):new X(e,t,n)}(t,o(),(e=>{s(e),console.log("Settings updated:",e)}));e.show()}else console.error("Settings registry not available")})),d.appendChild(w);const x=Z("escobar-connection-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <polygon points="13,2 3,14 12,14 11,22 21,10 12,10 13,2"></polygon>\n </svg>',"Connection Settings");return x.addEventListener("click",(()=>{t?function(e,t,n){new Y(e,t,n).show()}(t,o(),s):console.error("Settings registry not available")})),d.appendChild(x),d}(this.app,this.settingsRegistry,(()=>this.settingsManager.getCompleteSettings()),this.createNewChat.bind(this),this.init.bind(this),this.onSettingsChanged.bind(this),this.availableChats,this.onChatSelect.bind(this),this.currentChatID,this.availableModels),this.node.appendChild(this.buttonContainer),this.updateChatStateInUI(this.currentChatID),this.chatContainer=document.createElement("div"),this.chatContainer.className="escobar-chat-container",this.chatContainer.style.height="80%",this.chatContainer.style.flex="none",this.node.appendChild(this.chatContainer),this.divider=document.createElement("div"),this.divider.className="escobar-divider",this.node.appendChild(this.divider),this.setupDividerDrag(),this.inputContainer=document.createElement("div"),this.inputContainer.className="escobar-input-container",this.node.appendChild(this.inputContainer),this.chatInput=document.createElement("textarea"),this.chatInput.className="escobar-chat-input",this.chatInput.placeholder="Type your message here...",this.chatInput.rows=2,this.chatInput.addEventListener("keydown",(e=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),this.sendMessage(this.sendButton.textContent))})),this.inputContainer.appendChild(this.chatInput),this.stopIcon=document.createElement("div"),this.stopIcon.className="escobar-stop-icon",this.stopIcon.innerHTML='\n <svg viewBox="0 0 100 100" width="100" height="100">\n \x3c!-- Octagonal stop sign shape with white border --\x3e\n <polygon points="29,5 71,5 95,29 95,71 71,95 29,95 5,71 5,29" fill="#c0392b" />\n <polygon points="29,5 71,5 95,29 95,71 71,95 29,95 5,71 5,29" fill="none" stroke="white" stroke-width="1.5" />\n \x3c!-- STOP text - highway style, positioned slightly higher --\x3e\n <text x="50" y="53" font-family="Arial, Helvetica, sans-serif" font-size="30" font-weight="bold" text-anchor="middle" dominant-baseline="middle" fill="white" letter-spacing="1">STOP</text>\n </svg>\n ',this.stopIcon.style.display="none",this.stopIcon.addEventListener("click",(()=>{window.dispatchEvent(new CustomEvent(u.I3.STOP))})),this.inputContainer.appendChild(this.stopIcon),this.boundDisableInput=this.disableInput.bind(this),this.boundEnableInput=this.enableInput.bind(this),window.addEventListener(u.I3.START,this.boundDisableInput),window.addEventListener(u.I3.END,this.boundEnableInput);const s=function(e=[]){const t=document.createElement("div");t.className="escobar-split-button";const n=document.createElement("button");n.className="escobar-main-button",n.textContent=e[0]||"Select";const o=document.createElement("button");o.className="escobar-dropdown-toggle";const r=document.createElementNS("http://www.w3.org/2000/svg","svg");r.setAttribute("xmlns","http://www.w3.org/2000/svg"),r.setAttribute("width","16"),r.setAttribute("height","16"),r.setAttribute("viewBox","0 0 24 24"),r.setAttribute("fill","none"),r.setAttribute("stroke","currentColor"),r.setAttribute("stroke-width","2"),r.setAttribute("stroke-linecap","round"),r.setAttribute("stroke-linejoin","round"),r.classList.add("escobar-icon-svg");const i=document.createElementNS("http://www.w3.org/2000/svg","path");i.setAttribute("d","M6 9l6 6 6-6"),r.appendChild(i),o.appendChild(r);const s=document.createElement("ul");return s.className="escobar-dropdown-menu",e.forEach((e=>{const t=document.createElement("li"),o=document.createElement("button");o.textContent=e,o.onclick=t=>{t.stopPropagation(),n.textContent=e,s.style.display="none"},t.appendChild(o),s.appendChild(t)})),document.addEventListener("click",(e=>{"block"!==s.style.display||s.contains(e.target)||e.target===o||(s.style.display="none")})),o.onclick=e=>{if(e.stopPropagation(),"block"===s.style.display)s.style.display="none";else{s.parentNode&&s.parentNode.removeChild(s),document.body.appendChild(s);const e=o.getBoundingClientRect();s.style.position="fixed",s.style.bottom=window.innerHeight-e.top+5+"px",s.style.right=window.innerWidth-e.right+"px",s.style.display="block"}},t.appendChild(n),t.appendChild(o),t.appendChild(s),t.mainButton=n,t}(["Talk","Plan","Act"]);this.sendButton=s.mainButton,this.inputContainer.appendChild(s),this.sendButton.addEventListener("click",(()=>{this.sendMessage(this.sendButton.textContent)}));const a=be(this.settingsManager),c=this.settingsManager.getCompleteSettings();this.messageHandler=new ge(c.voittaApiKey,c.openaiApiKey,c.anthropicApiKey,c.geminiApiKey,"",a,this.chatContainer,c.maxMessages),this.messageHandler.onChatCreated=e=>{this.currentChatID=e,this.updateChatStateInUI(e)},this.settingsManager.setMessageHandler(this.messageHandler),this.settingsManager.setOnSettingsChanged(this.onSettingsChanged.bind(this)),this.settingsManager.setupLocalSettingsListener(),window.escobarMessageHandler=this.messageHandler,window.escobarUsername=a,window.escobarAvailableModels=this.availableModels,window.escobarCurrentSettings=c,this.cleanupLocalStorage(),setTimeout((async()=>{await this.initializeSettings(),await this.init()}),100)}handlePythonResponse(e,t){this.messageHandler.handlePythonResponse(e,t)}async say(e){const t=this.messageHandler.findMessageById(e.msg_call_id);t.isNew?(t.setContent(e.text),t.isNew=!1):t.setContent(t.getContent()+e.text)}async tool_say(e){if("string"==typeof e.name&&null!=typeof e.name){if(u.gb[e.id],e.name.includes("editExecuteCell_editExecuteCell")||e.name.includes("insertExecuteCell_insertExecuteCell")||e.name.includes("writeToFile_writeToFile")||e.name.includes("diffToFile_diffToFile"))try{null==this.call_id_log[e.id]&&(this.call_id_log[e.id]=""),this.call_id_log[e.id]+=e.text;var t={};try{t=JSON.parse(this.call_id_log[e.id])}catch(n){t=JSON.parse(this.call_id_log[e.id]+'"}')}if(e.name.includes("diffToFile_diffToFile")){const n=t.search,o=t.replace,r=t.filePath;if(null!=n&&null!=o){const t=e.name.split("_").reverse()[1];await F[t].func({filePath:r,search:n,replace:o},!0,e.id)}}else if(e.name.includes("writeToFile_writeToFile")){const n=t.content,o=t.filePath;if(n){const t=e.name.split("_").reverse()[1];await F[t].func({filePath:o,content:n},!0,e.id)}}else{const n=t.content,o=t.cellType,r=parseInt(t.index,10);if(n){const t=e.name.split("_").reverse()[1];await F[t].func({index:r,cellType:o,content:n},!0,e.id)}}}catch(e){}}else console.log(e)}cleanupLocalStorage(){try{localStorage.getItem("escobar-settings")&&(localStorage.removeItem("escobar-settings"),console.log("🧹 CLEANUP: Removed legacy localStorage settings"))}catch(e){console.warn("🧹 CLEANUP: Failed to clean localStorage:",e)}}async initializeSettings(){await this.settingsManager.initializeSettings();const e=this.settingsManager.getCompleteSettings();window.escobarCurrentSettings=e}onSettingsChanged(e){console.log("🔧 SETTINGS: Settings change detected");const t=be(this.settingsManager);this.messageHandler.updateSettings(e.voittaApiKey,e.openaiApiKey,e.anthropicApiKey,e.geminiApiKey,"",t,e.maxMessages),window.escobarCurrentSettings=e,window.escobarUsername=t,console.log("🔧 SETTINGS: Updated username to:",t)}async reinitializeConnection(){console.log("Reinitializing WebSocket connection...");const e=(0,u.mt)();e&&e.close(),setTimeout((()=>{this.init()}),100)}async init(){await this.messageHandler.clearMessages(),this.voittaToolRouter=new l;const e=await async function(e,t,n){D||(await R(e,t,n),D=!0);const o=[];for(const e of Object.values(F))o.push(e.def);return o}(this.app,this.notebookTracker,this.debuggerService),t=be(this.settingsManager),n=this.settingsManager.getCompleteSettings();this.messageHandler.updateSettings(n.voittaApiKey,n.openaiApiKey,n.anthropicApiKey,n.geminiApiKey,"",t,n.maxMessages),window.escobarUsername=t,console.log("🔧 INIT: Updated username to:",t),(0,u.uo)("handleResponse",!1,this.handlePythonResponse.bind(this)),(0,u.uo)("say",!1,this.say.bind(this)),(0,u.uo)("tool_say",!1,this.tool_say.bind(this)),this.voittaToolRouter.tools=e;try{const e=this.settingsManager.getCompleteSettings();console.log("🌐 WS: Attempting connection to",e.serverUrl),await(0,u.YL)(e.serverUrl),console.log("🌐 WS: Connection established successfully")}catch(e){return void console.error("🌐 WS: Connection failed:",e)}try{const e={method:"listChats",username:t,chatID:"",call_id:this.messageHandler.generateMessageId(),message_type:"request",intraspection:this.voittaToolRouter.intraspect()},n=await(0,u.callPython)(e,ve,!0,!1);n&&n.value&&n.value.chats&&(this.availableChats=n.value.chats.filter((e=>e.chatId&&"temp-session"!==e.chatId))),n&&n.value&&n.value.models?(this.availableModels=n.value.models,console.log("📋 MODELS: Received",this.availableModels.length,"models from server"),window.escobarAvailableModels=this.availableModels,window.dispatchEvent(new CustomEvent("escobar-models-updated",{detail:{models:this.availableModels}})),this.updateModelDropdown()):(console.log("📋 MODELS: No models received from server"),this.availableModels=[],window.escobarAvailableModels=this.availableModels,window.dispatchEvent(new CustomEvent("escobar-models-updated",{detail:{models:this.availableModels}})));let o="temp-session";if(this.availableChats.length>0){const e=this.availableChats.length-1,t=this.availableChats[e];o=t.chatId,o||(console.error("No chatID found in chat object! Chat object structure may be incorrect."),console.log("Expected chatId property, but got:",t),o="temp-session"),this.currentChatID=o,this.messageHandler.setCurrentChatID(o);try{await this.messageHandler.loadMessages(),this.updateChatStateInUI(o),this.messageHandler.getMessages().length}catch(e){console.error("Error loading messages for chat:",o,e),this.updateChatStateInUI(o)}}else this.currentChatID=o,this.messageHandler.setCurrentChatID(o),this.updateChatStateInUI(o);this.updateChatDropdown()}catch(e){console.error("Error in chat management flow:",e),await this.messageHandler.loadMessages()}}disableInput(){this.chatInput&&(this.chatInput.disabled=!0,this.chatInput.style.opacity="0.6",this.chatInput.placeholder="Processing...",this.stopIcon&&(this.stopIcon.style.display="flex"))}enableInput(){this.chatInput&&(this.chatInput.disabled=!1,this.chatInput.style.opacity="1",this.chatInput.placeholder="Type your message here...",this.stopIcon&&(this.stopIcon.style.display="none"))}updateChatStateInUI(e){this.buttonContainer&&this.buttonContainer.updateChatState&&this.buttonContainer.updateChatState(e)}updateChatDropdown(){this.buttonContainer&&this.buttonContainer.updateChatDropdown&&this.buttonContainer.updateChatDropdown(this.availableChats,this.currentChatID)}updateModelDropdown(){this.buttonContainer&&this.buttonContainer.updateModelDropdown&&this.buttonContainer.updateModelDropdown(this.availableModels)}async createNewChat(e){const t=await this.messageHandler.createNewChat(e);this.currentChatID=t,this.messageHandler.setCurrentChatID(t),await this.refreshChatList(),this.updateChatDropdown(),this.updateChatStateInUI(t)}async onChatSelect(e){this.currentChatID=e,this.messageHandler.setCurrentChatID(e),console.log(`Selected chat: ${e}`),this.updateChatStateInUI(e),await this.messageHandler.clearMessages(),await this.messageHandler.loadMessages()}async refreshChatList(){const e=be(this.settingsManager);try{const t={method:"listChats",username:e,chatID:"",call_id:this.messageHandler.generateMessageId(),message_type:"request",intraspection:this.voittaToolRouter.intraspect()},n=await(0,u.callPython)(t,ve,!0,!1);if(n&&n.value&&n.value.chats)return this.availableChats=n.value.chats,this.availableChats}catch(e){console.error("Error refreshing chat list:",e)}return[]}getSelectedProvider(){return this.buttonContainer&&this.buttonContainer.getSelectedProvider?this.buttonContainer.getSelectedProvider():"OpenAI"}async sendMessage(e){const t=this.chatInput.value.trim();if(!t)return;this.chatInput.value="";const n=this.getSelectedProvider();await this.messageHandler.sendMessage(t,e,n)}onActivateRequest(e){super.onActivateRequest(e),this.chatInput.focus()}setupDividerDrag(){let e=!1,t=0,n=0;const o=()=>{const e=this.chatContainer.scrollTop,t=this.chatContainer.clientHeight,n=this.chatContainer.scrollHeight;return Math.abs(e+t-n)<100},r=r=>{if(!e)return;const i=r.pageY-t-18,s=this.node.offsetHeight,a=Math.max(100,.3*s),c=.85*s,l=Math.min(c,Math.max(a,n+i));this.chatContainer.style.height=`${l}px`,this.chatContainer.style.flex="none",o()&&(this.chatContainer.scrollTop=this.chatContainer.scrollHeight)},i=()=>{e&&(e=!1,window.removeEventListener("mousemove",r),window.removeEventListener("mouseup",i),document.body.style.userSelect="")};this.divider.addEventListener("mousedown",(o=>{o.preventDefault(),o.stopPropagation(),e=!0,t=o.pageY,n=this.chatContainer.offsetHeight,window.addEventListener("mousemove",r),window.addEventListener("mouseup",i),document.body.style.userSelect="none"}))}dispose(){window.removeEventListener(u.I3.START,this.boundDisableInput),window.removeEventListener(u.I3.END,this.boundEnableInput);const e=(0,u.mt)();e&&e.close(),super.dispose()}}we.idCounter=0,new Q.LabIcon({name:"escobar:voitta-icon",svgstr:'\n<svg viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">\n \x3c!-- Background circle with gradient --\x3e\n <defs>\n <linearGradient id="bg-grad" x1="0%" y1="0%" x2="100%" y2="100%">\n <stop offset="0%" stop-color="#2563EB" />\n <stop offset="100%" stop-color="#1E40AF" />\n </linearGradient>\n </defs>\n <circle cx="200" cy="200" r="200" fill="url(#bg-grad)" />\n \n \x3c!-- Inner circle --\x3e\n <circle cx="200" cy="200" r="180" fill="#1E3A8A" />\n \n \x3c!-- Connected hexagons representing different systems --\x3e\n <g transform="translate(200, 200)">\n \x3c!-- Center hexagon --\x3e\n <polygon points="0,-40 34.6,-20 34.6,20 0,40 -34.6,20 -34.6,-20" \n fill="#3B82F6" stroke="#BFDBFE" stroke-width="2" />\n \n \x3c!-- Outer hexagons --\x3e\n <polygon points="0,-100 34.6,-80 34.6,-40 0,-20 -34.6,-40 -34.6,-80" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n <polygon points="69.2,-40 103.8,-20 103.8,20 69.2,40 34.6,20 34.6,-20" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n <polygon points="69.2,40 103.8,60 103.8,100 69.2,120 34.6,100 34.6,60" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n <polygon points="0,40 34.6,60 34.6,100 0,120 -34.6,100 -34.6,60" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n <polygon points="-69.2,40 -34.6,60 -34.6,100 -69.2,120 -103.8,100 -103.8,60" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n <polygon points="-69.2,-40 -34.6,-20 -34.6,20 -69.2,40 -103.8,20 -103.8,-20" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n \x3c!-- Connection lines --\x3e\n <line x1="0" y1="-40" x2="0" y2="-20" stroke="#93C5FD" stroke-width="3" />\n <line x1="34.6" y1="20" x2="34.6" y2="60" stroke="#93C5FD" stroke-width="3" />\n <line x1="34.6" y1="-20" x2="69.2" y2="-40" stroke="#93C5FD" stroke-width="3" />\n <line x1="0" y1="40" x2="0" y2="60" stroke="#93C5FD" stroke-width="3" />\n <line x1="-34.6" y1="20" x2="-34.6" y2="60" stroke="#93C5FD" stroke-width="3" />\n <line x1="-34.6" y1="-20" x2="-69.2" y2="-40" stroke="#93C5FD" stroke-width="3" />\n \n \x3c!-- Data flow indicators --\x3e\n <circle cx="0" cy="-30" r="3" fill="#DBEAFE" />\n <circle cx="34.6" cy="40" r="3" fill="#DBEAFE" />\n <circle cx="51.9" cy="-30" r="3" fill="#DBEAFE" />\n <circle cx="0" cy="50" r="3" fill="#DBEAFE" />\n <circle cx="-34.6" cy="40" r="3" fill="#DBEAFE" />\n <circle cx="-51.9" cy="-30" r="3" fill="#DBEAFE" />\n </g>\n \n \x3c!-- Subtle outer ring --\x3e\n <circle cx="200" cy="200" r="170" fill="none" stroke="#60A5FA" stroke-width="1" stroke-dasharray="3,6" />\n \n \x3c!-- Central AI core indicator --\x3e\n <circle cx="200" cy="200" r="15" fill="#DBEAFE" />\n <circle cx="200" cy="200" r="8" fill="#3B82F6" />\n</svg>\n'}).bindprops({stylesheet:"sideBar"});const xe=new Q.LabIcon({name:"escobar:voitta-launcher-icon",svgstr:'\n<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">\n <circle cx="8" cy="8" r="8" fill="#2563EB" />\n <circle cx="8" cy="8" r="7" fill="#1E3A8A" />\n <polygon points="8,4 10.4,6 10.4,10 8,12 5.6,10 5.6,6" fill="#3B82F6" stroke="#BFDBFE" stroke-width="0.2" />\n <circle cx="8" cy="8" r="1" fill="#DBEAFE" />\n</svg>\n'}).bindprops({stylesheet:"menuItem"});function Se(){const e=document.getElementById("jp-MainLogo");e&&(e.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="5 5 50 50">\n <defs>\n \x3c!-- Gradients --\x3e\n <linearGradient id="logo-gradient-1" x1="0%" y1="0%" x2="100%" y2="100%">\n <stop offset="0%" stop-color="#4A00E0" />\n <stop offset="100%" stop-color="#0084FF" />\n </linearGradient>\n <linearGradient id="logo-gradient-2" x1="0%" y1="0%" x2="100%" y2="100%">\n <stop offset="0%" stop-color="#0084FF" />\n <stop offset="100%" stop-color="#00E0A3" />\n </linearGradient>\n \n \x3c!-- Filters --\x3e\n <filter id="logo-shadow" x="-20%" y="-20%" width="140%" height="140%">\n <feDropShadow dx="1" dy="1" stdDeviation="1.5" flood-opacity="0.3" />\n </filter>\n \n \x3c!-- Patterns --\x3e\n <pattern id="circuit-pattern" width="40" height="40" patternUnits="userSpaceOnUse">\n <path d="M 10 0 L 10 40 M 20 0 L 20 40 M 30 0 L 30 40 M 0 10 L 40 10 M 0 20 L 40 20 M 0 30 L 40 30" \n stroke="#4A00E0" stroke-width="0.5" stroke-opacity="0.2" fill="none" />\n </pattern>\n </defs>\n \n \x3c!-- Logo Mark --\x3e\n <g transform="translate(30, 30)">\n \x3c!-- Background Circuit Pattern --\x3e\n <circle cx="0" cy="0" r="25" fill="url(#circuit-pattern)" opacity="0.1" />\n \n \x3c!-- Outer Circle --\x3e\n <circle cx="0" cy="0" r="20" fill="url(#logo-gradient-1)" filter="url(#logo-shadow)" />\n \n \x3c!-- Inner Network Pattern --\x3e\n <g>\n \x3c!-- Central Node --\x3e\n <circle cx="0" cy="0" r="6" fill="#FFFFFF" opacity="0.9" />\n \n \x3c!-- Connection Lines --\x3e\n <path d="M 0 0 L -8 -8 M 0 0 L 8 -8 M 0 0 L -8 8 M 0 0 L 8 8" \n stroke="white" stroke-width="2" stroke-linecap="round" />\n \n \x3c!-- Outer Nodes --\x3e\n <circle cx="-8" cy="-8" r="3" fill="white" />\n <circle cx="8" cy="-8" r="3" fill="white" />\n <circle cx="-8" cy="8" r="3" fill="white" />\n <circle cx="8" cy="8" r="3" fill="white" />\n \n \x3c!-- Animated Data Flow --\x3e\n <circle cx="0" cy="0" r="1" fill="#00E0A3">\n <animate attributeName="cx" values="0;-8" dur="1.5s" repeatCount="indefinite" />\n <animate attributeName="cy" values="0;-8" dur="1.5s" repeatCount="indefinite" />\n <animate attributeName="opacity" values="0;1;0" dur="1.5s" repeatCount="indefinite" />\n </circle>\n \n <circle cx="0" cy="0" r="1" fill="#00E0A3">\n <animate attributeName="cx" values="0;8" dur="1.5s" begin="0.5s" repeatCount="indefinite" />\n <animate attributeName="cy" values="0;-8" dur="1.5s" begin="0.5s" repeatCount="indefinite" />\n <animate attributeName="opacity" values="0;1;0" dur="1.5s" begin="0.5s" repeatCount="indefinite" />\n </circle>\n \n <circle cx="0" cy="0" r="1" fill="#00E0A3">\n <animate attributeName="cx" values="0;-8" dur="1.5s" begin="1s" repeatCount="indefinite" />\n <animate attributeName="cy" values="0;8" dur="1.5s" begin="1s" repeatCount="indefinite" />\n <animate attributeName="opacity" values="0;1;0" dur="1.5s" begin="1s" repeatCount="indefinite" />\n </circle>\n \n <circle cx="0" cy="0" r="1" fill="#00E0A3">\n <animate attributeName="cx" values="0;8" dur="1.5s" begin="1.5s" repeatCount="indefinite" />\n <animate attributeName="cy" values="0;8" dur="1.5s" begin="1.5s" repeatCount="indefinite" />\n <animate attributeName="opacity" values="0;1;0" dur="1.5s" begin="1.5s" repeatCount="indefinite" />\n </circle>\n </g>\n \n \x3c!-- Pulsing animation --\x3e\n <circle cx="0" cy="0" r="20" fill="none" stroke="url(#logo-gradient-2)" stroke-width="1.5">\n <animate attributeName="r" values="20;23;20" dur="3s" repeatCount="indefinite" />\n <animate attributeName="opacity" values="1;0.5;1" dur="3s" repeatCount="indefinite" />\n </circle>\n \n \x3c!-- Rotating Outer Ring --\x3e\n <g opacity="0.7">\n <circle cx="0" cy="-22" r="2" fill="#FFFFFF">\n <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="10s" repeatCount="indefinite" />\n </circle>\n <circle cx="22" cy="0" r="2" fill="#FFFFFF">\n <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="90" to="450" dur="10s" repeatCount="indefinite" />\n </circle>\n <circle cx="0" cy="22" r="2" fill="#FFFFFF">\n <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="180" to="540" dur="10s" repeatCount="indefinite" />\n </circle>\n <circle cx="-22" cy="0" r="2" fill="#FFFFFF">\n <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="270" to="630" dur="10s" repeatCount="indefinite" />\n </circle>\n </g>\n </g>\n</svg>')}var Ce;!function(e){e.create="escobar:create-chat"}(Ce||(Ce={}));const Ee={id:"escobar:plugin",description:"AI CHAT EXTENSION",autoStart:!0,optional:[r.ISettingRegistry,i.ICommandPalette,s.ILauncher,a.IMainMenu,o.ILayoutRestorer,p.INotebookTracker,_.IDebugger],activate:(e,t,n,o,r,s,a,c)=>{console.log("JupyterLab extension escobar is activated!");const l=new i.WidgetTracker({namespace:"escobar"}),d=Ce.create;e.commands.addCommand(d,{label:"Voitta",icon:xe,execute:()=>{const n=new we(e,t||void 0,a||void 0,c||void 0);return e.shell.add(n,"left",{rank:900}),e.shell.activateById(n.id),console.log("Created chat widget with ID:",n.id),l.add(n),n}}),n&&n.addItem({command:d,category:"Escobar"}),o&&o.add({command:d,category:"Other",rank:1}),r.helpMenu.addGroup([{command:d}],30),s&&s.restore(l,{command:d,name:e=>"escobar-chat",args:e=>({id:e.id})}),e.restored.then((()=>{setTimeout(Se,100)})),t&&t.load(Ee.id).then((e=>{console.log("escobar settings loaded:",e.composite)})).catch((e=>{console.error("Failed to load settings for escobar.",e)}))}},Ie=Ee},5355:(e,t,n)=>{n.d(t,{I3:()=>p,Tg:()=>r,YL:()=>y,callPython:()=>v,gb:()=>o,lk:()=>i,mt:()=>g,uo:()=>b});var o={};const r={};function i(){const e=Date.now().toString(16);return"M-xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(e){const t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)}))+"-"+e}const s=new Map,a=36e5,c={};let l=null,d=!1;var u=null;const p={START:"escobar-python-call-start",END:"escobar-python-call-end",STOP:"escobar-stop-event"};function g(){return l}let m=!1,h=!1;function y(e="ws://127.0.0.1:8777/ws"){return console.log("Entering initPythonBridge"),l&&d&&l.readyState===WebSocket.OPEN?Promise.resolve():(m||(window.addEventListener(p.STOP,f),m=!0),u=new Promise(((t,n)=>{let i=function(e){if(console.log(`##>>## Original URL: ${e}`),e.startsWith("ws://")||e.startsWith("wss://"))return console.log(`##>>## Absolute URL, using as-is: ${e}`),e;const t=window.location.pathname.match(/^\/user\/([^\/]+)\//);if(t){const n=t[0],o=n.slice(0,-1)+e,r=`${"https:"===window.location.protocol?"wss:":"ws:"}//${window.location.host}${o}`;return console.log(`##>>## JupyterHub detected, resolved URL: ${r}`),console.log(`##>>## User path: ${n}`),console.log(`##>>## Resolved path: ${o}`),r}{const t=`${"https:"===window.location.protocol?"wss:":"ws:"}//${window.location.host}${e}`;return console.log(`##>>## Standalone JupyterLab, resolved URL: ${t}`),t}}(e);const a=window.escobarCurrentSettings;if((null==a?void 0:a.bonnieUrl)&&e.startsWith("/")){console.log(`>>> Adding bonnieUrl as proxy target: ${a.bonnieUrl}`);const e=i.includes("?")?"&":"?";i+=`${e}bonnie_url=${encodeURIComponent(a.bonnieUrl)}`,console.log(`>>> Final URL with bonnieUrl parameter: ${i}`)}else console.log(">>> No bonnieUrl parameter needed");console.log(">>> Connecting to "+i),l=new WebSocket(i),l.addEventListener("open",(e=>{d=!0,t(),u=null})),l.addEventListener("error",(e=>{console.error("Error connecting to Python server:",e),n(e),u=null})),l.addEventListener("close",(e=>{d=!1})),l.addEventListener("message",(async e=>{const t=e.data;try{var n=t;"string"==typeof t&&(n=JSON.parse(t));let e=n.message_type;if("response"===e){const e=n.call_id,t=n.finish_reason;if(console.log(`Finish Reason: ${t}`),e&&s.has(e)){const o=s.get(e);if(t&&"tool_calls"===t)console.log(`Intermediate response with finish_reason: ${t} - keeping request pending`);else{clearTimeout(o.timeout),s.delete(e);const r=n.data||n.response||n;o.resolve({...r,finish_reason:t})}}else c.handleResponse?x({...n.data||n.response||n,function:"handleResponse",params:{value:n.value||"-- value not found in response --"}}):console.warn("Received response with no matching request or handler")}else if("request"===e){let e=n.function,t=n.__msg_call_id__,i=n.call_id;if(null!=r[t])return void(c[e].returns&&w(i,"__stopped__"));if(n.params,!c[e])return void console.error(`Function "${e}" not found in registry`);c[e].isAsync?await async function(e){const t=e.call_id||"",n=e.function||"";var r=e.params||{};const i=r.partial||!1;r.param,i&&r.text;const s=c[n];if(!s)throw new Error(`Function "${n}" not found in registry`);try{var a;a="diffToFile"==n||"writeToFile"==n||"insertExecuteCell"==n||"editExecuteCell"==n?await s.fn.call(s.obj,r,!1,t):await s.fn.call(s.obj,r),s.returns&&w(t,a)}catch(e){throw console.error(`Error calling function "${n}":`,e),e}o[t]=!0}(n):x(n)}}catch(e){console.error("Error parsing JSON message:",e)}}))})),u)}function f(){h=!0;for(const[e,t]of s.entries()){clearTimeout(t.timeout);const n=new Error("Operation stopped by user");n.stop=!0,t.reject(n),s.delete(e)}setTimeout((()=>{h=!1}),100)}async function v(e,t=a,n=!0,o=!1){o&&window.dispatchEvent(new CustomEvent(p.START)),!l||!d||(l.readyState,WebSocket.OPEN);const r=i();let c="",u="";window.escobarUsername?c=window.escobarUsername:(console.warn("Username not available from global variable, using default"),c="VoittaDefaultUser"),u="chatID"in e?e.chatID:"temp-session";const g={...e,user_id:c,session_id:u,call_id:r,msg_call_id:e.call_id||r,message_type:"request"},m=JSON.stringify(g);return new Promise(((e,o)=>{if(l&&d&&l.readyState===WebSocket.OPEN){const i=setTimeout((()=>{s.delete(r),window.dispatchEvent(new CustomEvent(p.END)),o(new Error(`Request timed out after ${t}ms`))}),t);n?s.set(r,{resolve:t=>{(!t.finish_reason||"tool_calls"!==t.finish_reason)&&window.dispatchEvent(new CustomEvent(p.END)),e(t)},reject:e=>{window.dispatchEvent(new CustomEvent(p.END)),o(e)},timeout:i}):(s.delete(r),window.dispatchEvent(new CustomEvent(p.END))),l.send(m)}else window.dispatchEvent(new CustomEvent(p.END)),o(new Error("Cannot send message. WebSocket is not connected after attempting to reconnect."))}))}function b(e,t,n,o=null,r=!1){c[e]&&console.warn(`Function "${e}" already exists in the registry. Overwriting`),c[e]={fn:n,obj:o,isAsync:t,returns:r}}function w(e,t){const n={call_id:e,message_type:"response"};"string"==typeof t?n.value=t:n.binary_value=t,null!==l?"string"==typeof n?l.send(n):l.send(JSON.stringify(n)):console.error("WebSocket is null. Cannot send message.")}function x(e){const t=e.call_id||"",n=e.function||"";var o=e.params||{};const r=o.partial||!1;o.msg_call_id,o.param,r&&o.text;const i=c[n];if(!i)throw new Error(`Function "${n}" not found in registry`);try{let e=i.fn.call(i.obj,o);i.returns&&w(t,e)}catch(e){throw console.error(`Error calling function "${n}":`,e),e}}},9838:(e,t,n)=>{n.d(t,{Hn:()=>s,e$:()=>i,updateCredentials:()=>a});class o{constructor(e){this.currentToken=null,this.userInfo=null,this.tokenExpirationTime=null,this.clientId=e.clientId,this.scope=e.scope||"openid email profile https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/documents.readonly",this.redirectUri=e.redirectUri||`${window.location.origin}/escobar/oauth-callback.html`,this.isValidClientId(this.clientId)||console.warn("Invalid Google Client ID format. Please check your configuration.")}isValidClientId(e){return e&&e.includes(".apps.googleusercontent.com")}async loginWithAuthCode(){return new Promise((e=>{try{if(!this.isValidClientId(this.clientId))return void e({success:!1,error:"Invalid Google Client ID. Please configure a valid Client ID in settings."});console.log("🔐 AUTH: Starting OAuth authorization code flow with Client ID:",this.clientId.substring(0,20)+"...");const t=this.generateRandomState(),n=this.buildOAuthUrl(t);console.log("🔐 AUTH: Opening OAuth popup to:",n);const o=window.open(n,"google-oauth","width=500,height=600,scrollbars=yes,resizable=yes");if(!o)return void e({success:!1,error:"Failed to open popup window. Please allow popups for this site."});const r=n=>{if(n.origin===window.location.origin)if("GOOGLE_OAUTH_CODE_SUCCESS"===n.data.type){if(console.log("🔐 AUTH: Authorization code received successfully"),n.data.state!==t)return console.error("🔐 AUTH: State parameter mismatch"),e({success:!1,error:"Security validation failed (state mismatch)"}),void i();const o=n.data.authorizationCode;console.log("🔐 AUTH: Authorization code:",o.substring(0,20)+"..."),e({success:!0,authorizationCode:o,redirectUri:this.redirectUri,state:t}),i()}else"GOOGLE_OAUTH_CODE_ERROR"===n.data.type&&(console.error("🔐 AUTH: OAuth error:",n.data.error),e({success:!1,error:n.data.error||"OAuth authentication failed"}),i());else console.warn("🔐 AUTH: Ignoring message from unknown origin:",n.origin)},i=()=>{window.removeEventListener("message",r),o&&!o.closed&&o.close()};window.addEventListener("message",r);const s=setInterval((()=>{o.closed&&(clearInterval(s),e({success:!1,error:"Authentication cancelled by user"}),i())}),1e3);setTimeout((()=>{clearInterval(s),e({success:!1,error:"Authentication timeout"}),i()}),3e5)}catch(t){console.error("🔐 AUTH: Unexpected error during OAuth flow:",t),e({success:!1,error:`OAuth error: ${t.message}`})}}))}generateRandomState(){const e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e,(e=>e.toString(16).padStart(2,"0"))).join("")}buildOAuthUrl(e){return`https://accounts.google.com/o/oauth2/v2/auth?${new URLSearchParams({response_type:"code",client_id:this.clientId,redirect_uri:this.redirectUri,scope:this.scope,state:e,access_type:"offline",prompt:"consent"}).toString()}`}triggerPopupAuthentication(e){try{console.log("🔐 AUTH: Creating temporary Google Sign-In button...");const t=document.createElement("div");t.id="google-signin-temp-container",t.style.cssText="\n position: fixed;\n top: -1000px;\n left: -1000px;\n width: 1px;\n height: 1px;\n overflow: hidden;\n opacity: 0;\n pointer-events: none;\n z-index: -1;\n ",document.body.appendChild(t),window.google.accounts.id.renderButton(t,{theme:"outline",size:"large",type:"standard",shape:"rectangular",text:"signin_with",logo_alignment:"left"}),setTimeout((()=>{const n=t.querySelector('div[role="button"]');n?(console.log("🔐 AUTH: Triggering Google Sign-In button click..."),n.click()):(console.error("🔐 AUTH: Could not find rendered Google Sign-In button"),this.cleanupTempContainer(t),e({success:!1,error:"Failed to initialize Google Sign-In button"}))}),500),setTimeout((()=>{this.cleanupTempContainer(t)}),1e4)}catch(t){console.error("🔐 AUTH: Error triggering popup authentication:",t),e({success:!1,error:`Popup authentication error: ${t.message}`})}}cleanupTempContainer(e){try{document.body.contains(e)&&document.body.removeChild(e)}catch(e){console.warn("🔐 AUTH: Error cleaning up temp container:",e)}}loadGoogleIdentityServices(){return new Promise(((e,t)=>{if(void 0!==window.google&&window.google.accounts&&window.google.accounts.id)return void e();const n=document.querySelector('script[src="https://accounts.google.com/gsi/client"]');if(n)return void n.addEventListener("load",(()=>{setTimeout((()=>{void 0!==window.google&&window.google.accounts&&window.google.accounts.id?e():t(new Error("Google Identity Services failed to initialize after script load"))}),200)}));const o=document.createElement("script");o.src="https://accounts.google.com/gsi/client",o.async=!0,o.defer=!0,o.onload=()=>{setTimeout((()=>{void 0!==window.google&&window.google.accounts&&window.google.accounts.id?e():t(new Error("Google Identity Services failed to initialize"))}),200)},o.onerror=()=>{t(new Error("Failed to load Google Identity Services script"))},document.head.appendChild(o)}))}decodeJWT(e){try{const t=e.split(".");if(3!==t.length)throw new Error("Invalid JWT format");const n=t[1].replace(/-/g,"+").replace(/_/g,"/"),o=decodeURIComponent(atob(n).split("").map((e=>"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2))).join("")),r=JSON.parse(o);if(!r.email||!r.name||!r.sub)throw new Error("Missing required fields in JWT token");return r}catch(e){throw console.error("🔐 AUTH: Error decoding JWT:",e),new Error("Failed to decode authentication token")}}validateDecodedToken(e){try{if(!e.email||!e.name||!e.sub)return console.error("🔐 AUTH: Missing required fields in token"),!1;const t=Math.floor(Date.now()/1e3);return e.exp&&e.exp<t?(console.error("🔐 AUTH: Token is expired"),!1):e.aud===this.clientId||(console.error("🔐 AUTH: Token audience does not match client ID"),!1)}catch(e){return console.error("🔐 AUTH: Error validating token:",e),!1}}isAuthenticated(){return!(!this.currentToken||!this.tokenExpirationTime)&&!(Date.now()>=this.tokenExpirationTime&&(console.log("🔐 AUTH: Token expired, clearing authentication"),this.logout(),1))}getIdToken(){return this.isAuthenticated()?this.currentToken:null}getUserInfo(){return this.isAuthenticated()?this.userInfo:null}getTimeUntilExpiration(){return this.tokenExpirationTime?Math.max(0,this.tokenExpirationTime-Date.now()):null}getRedirectUri(){return this.redirectUri}logout(){if(console.log("🔐 AUTH: Logging out user"),this.currentToken=null,this.userInfo=null,this.tokenExpirationTime=null,window.escobarGoogleIdToken&&delete window.escobarGoogleIdToken,window.escobarGoogleUserInfo&&delete window.escobarGoogleUserInfo,void 0!==window.google)try{window.google.accounts.id.disableAutoSelect()}catch(e){console.warn("🔐 AUTH: Error disabling Google auto-select:",e)}}validateToken(){if(!this.currentToken)return!1;try{const e=this.decodeJWT(this.currentToken);return this.validateDecodedToken(e)}catch(e){return console.error("🔐 AUTH: Error validating token:",e),this.logout(),!1}}}let r=null;function i(e){return console.log("🔐 AUTH: Initializing Google Auth Manager"),r=new o(e),r}function s(){return r}async function a(e,t,o,r,i){try{console.log("🔐 UPDATE: Sending Google OAuth credentials to Bonnie via WebSocket..."),console.log("🔐 UPDATE: Auth code:",e.substring(0,20)+"..."),console.log("🔐 UPDATE: Redirect URI:",t),console.log("🔐 UPDATE: Client ID:",o.substring(0,20)+"...");const{callPython:s}=await Promise.resolve().then(n.bind(n,5355)),a=window.escobarCurrentSettings,c={method:"updateCredentials",username:(null==a?void 0:a.username)||"default-user",call_id:`google-auth-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,message_type:"request",oauth_provider:"google",authorization_code:e,redirect_uri:t,client_id:o,client_secret:r,state:i,scope:"openid email profile https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/documents.readonly"};console.log("🔐 UPDATE: Sending Google OAuth message to Bonnie:",{method:c.method,username:c.username,call_id:c.call_id,has_auth_code:!!e,has_client_id:!!o});const l=await s(c);if(console.log("🔐 UPDATE: Received response from Bonnie:",l),l.error_type)return console.error("🔐 UPDATE: Bonnie returned error:",l.value),{success:!1,error:l.value||"Unknown error from Bonnie"};let d=null;try{d={email:"user@example.com",name:"Google User",picture:null}}catch(e){console.warn("🔐 UPDATE: Could not extract user info locally:",e)}return console.log("🔐 UPDATE: Google OAuth credentials sent to Bonnie successfully"),{success:!0,userInfo:d}}catch(e){return console.error("🔐 UPDATE: Error sending credentials to Bonnie:",e),{success:!1,error:`Failed to send credentials to Bonnie: ${e.message||"Unknown error"}`}}}}}]);
1
+ "use strict";(self.webpackChunkescobar=self.webpackChunkescobar||[]).push([[653],{4364:(e,t,n)=>{n.r(t),n.d(t,{default:()=>Ee});var o=n(6118),r=n(2653),i=n(5551),s=n(8968),a=n(2226),c=n(5256);class l{constructor(){this.prompt="These functions faciliate access to Jupyter Lab environment",this.tools=[]}get_prompt(){return this.prompt}get_tools(){return function(e,t="FastAPI",n="0.1.0"){const o={openapi:"3.1.0",info:{title:t,version:n},paths:{"/__prompt__":{get:{summary:"Prompt",operationId:"prompt___prompt___get",responses:{200:{description:"Successful Response",content:{"application/json":{schema:{}}}}}}}},components:{schemas:{HTTPValidationError:{properties:{detail:{items:{$ref:"#/components/schemas/ValidationError"},type:"array",title:"Detail"}},type:"object",title:"HTTPValidationError"},ValidationError:{properties:{loc:{items:{anyOf:[{type:"string"},{type:"integer"}]},type:"array",title:"Location"},msg:{type:"string",title:"Message"},type:{type:"string",title:"Error Type"}},type:"object",required:["loc","msg","type"],title:"ValidationError"}}}};return e.forEach((e=>{const t=`/${e.name}`,n=`${e.name}_${e.name}_post`,r=`Body_${e.name}_${e.name}_post`,i={properties:{},type:"object",required:[],title:r};Object.entries(e.arguments).forEach((([e,t])=>{var n;i.properties[e]={type:(n=t.type,{str:"string",int:"integer",float:"number",bool:"boolean",object:"object",array:"array"}[n]||n),title:d(e),description:t.name},void 0!==t.default&&(i.properties[e].default=t.default),!1!==t.required&&i.required.push(e)})),o.components.schemas[r]=i,o.paths[t]={post:{summary:d(e.name.split("_").join(" ")),description:e.description,operationId:n,parameters:[{name:"authorization",in:"header",required:!1,schema:{type:"string",title:"Authorization"}},{name:"oauthtoken",in:"header",required:!1,schema:{type:"string",title:"Oauthtoken"}}],requestBody:{required:!0,content:{"application/x-www-form-urlencoded":{schema:{$ref:`#/components/schemas/${r}`}}}},responses:{200:{description:"Successful Response",content:{"application/json":{schema:{}}}},422:{description:"Validation Error",content:{"application/json":{schema:{$ref:"#/components/schemas/HTTPValidationError"}}}}},"x-CPM":"1.0"}}})),o}(this.tools)}intraspect(){return console.log("-------- Intraspection called ------"),{prompt:this.get_prompt(),tools:this.get_tools()}}}function d(e){return e.split("_").map((e=>e.charAt(0).toUpperCase()+e.slice(1))).join("")}var u=n(5355),p=n(5263),g=n(8914),m=n(4461);async function h(e,t,n=!0,o=""){var r,i;const s=e.serviceManager.contents,a=t.replace(/\\/g,"/").replace(/\/+/g,"/"),c=a.split("/").filter((e=>""!==e&&"."!==e)),l=c.pop();if(c.length>0){let e="";for(const t of c){e=e?`${e}/${t}`:t;try{if("directory"!==(await s.get(e)).type)throw new Error(`${e} exists but is not a directory`)}catch(t){if(404!==(null===(r=null==t?void 0:t.response)||void 0===r?void 0:r.status)&&!/not found/i.test(t.message))throw new Error(`Failed checking/creating directory ${e}: ${t.message}`);await s.save(e,{type:"directory",format:"json",content:null})}}}if(n&&l)try{await s.get(a)}catch(e){if(404!==(null===(i=null==e?void 0:e.response)||void 0===i?void 0:i.status)&&!/not found/i.test(e.message))throw new Error(`Failed checking file ${a}: ${e.message}`);await s.save(a,{type:"file",format:"text",content:o})}}function y(e){return e.replace(/\x1b\[[0-9;?]*[a-zA-Z]/g,"")}async function f(e,t){const{terminals:n}=e.serviceManager;await n.ready;const o=await n.running(),r=Array.from(o);console.log("All available terminals:",r.map((e=>({name:e.name})))),console.log("Looking for terminal with name:",t);for(const e of r)if(e.name===t)return console.log("Found exact terminal match:",e.name),n.connectTo({model:e});if(/^\d+$/.test(t))for(const e of r)if(e.name.includes(t))return console.log("Found numeric terminal match:",e.name,"for input:",t),n.connectTo({model:e});return 1===r.length?(console.log("No match found but only one terminal exists, using:",r[0].name),n.connectTo({model:r[0]})):(console.log("No terminal found with name:",t),null)}const v={};var b=n(8178),w=n(5963),x=n(2084),S=n(9329),C=n(6609),I=n(2256),E=n(9311),k=n(2941),N=n(7425);function A(e){return null==e||""===e?"":e.replace(/\\"/g,'"').replace(/\\'/g,"'").replace(/\\\\/g,"\\").replace(/\\n/g,"\n").replace(/\\t/g,"\t").replace(/\\r/g,"\r").replace(/\\b/g,"\b").replace(/\\f/g,"\f").replace(/\\v/g,"\v").replace(/\\0/g,"\0").replace(/\\x([0-9A-Fa-f]{2})/g,((e,t)=>String.fromCharCode(parseInt(t,16)))).replace(/\\u([0-9A-Fa-f]{4})/g,((e,t)=>String.fromCharCode(parseInt(t,16)))).replace(/\\u\{([0-9A-Fa-f]+)\}/g,((e,t)=>String.fromCodePoint(parseInt(t,16)))).replace(/\\([0-3][0-7]{2}|[0-7]{1,2})/g,((e,t)=>String.fromCharCode(parseInt(t,8))))}function T(e){var t;const n=(null===(t=e.split(".").pop())||void 0===t?void 0:t.toLowerCase())||"",o=[];o.push((0,x.syntaxHighlighting)(b.jupyterHighlightStyle));let r=null;switch(n){case"py":r=(0,S.Hg)();break;case"js":r=(0,C.Q2)();break;case"ts":r=(0,C.Q2)({typescript:!0});break;case"jsx":r=(0,C.Q2)({jsx:!0});break;case"tsx":r=(0,C.Q2)({jsx:!0,typescript:!0});break;case"json":r=(0,I.Pq)();break;case"md":r=(0,E.wD)();break;case"html":case"htm":r=(0,k.qy)();break;case"css":r=(0,N.AH)()}return r?(o.push(r),console.log(`Added language support for ${n}`)):console.log(`No specific language support for ${n}, using default highlighting`),o}var O,M,P,J={},_={},U=n(1041),L={},F={};const $={};$.listFiles={def:{name:"listFiles",description:"List files and directories at a specified relative path. Ignore rootPath if it exists",arguments:{path:{type:"string",name:"Relative path to list files from. Relative!",default:"/"}}},func:async e=>{if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});const t=e.path||"/",n=O.serviceManager.contents;try{const e=await n.get(t,{content:!0});if("directory"!==e.type)return JSON.stringify({error:`Path '${t}' is not a directory`});const o=e.content.map((e=>({name:e.name,path:e.path,type:e.type,last_modified:e.last_modified})));return JSON.stringify({success:!0,files:o})}catch(e){return JSON.stringify({error:`Error listing files: ${e.message}`})}}},$.writeToFile={def:{name:"writeToFile",description:"Opens a non-notebook file for editing (code, text, etc) and write into it. Do not use for files that start with '.' (period)",arguments:{filePath:{type:"string",name:"Relative path to the file to write to. Relative! "},content:{type:"string",name:"New content for the file. Entire file is being replaced by this!"}}},func:async(e,t=!1,n=void 0)=>{if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});const{contents:o}=O.serviceManager,{filePath:r,content:i}=e;if(null==n)return JSON.stringify({status:"fail",message:"no call_id received"});let s;await h(O,r);try{s=await O.commands.execute("docmanager:open",{path:r,factory:"Editor"})}catch(e){return JSON.stringify({status:"fail",message:"could not open file",detail:`${e.message}`})}await o.save(r,{type:"file",format:"text",content:i}),null==L[n]&&(L[n]=!0);try{await Promise.race([s.context.ready,new Promise(((e,t)=>setTimeout((()=>t(new Error("Timeout waiting for context.ready"))),1500)))])}catch(e){return JSON.stringify({status:"fail",message:"could not open file"})}if(await s.context.revert(),s.content&&s.content.editor){const e=s.content.editor,t=e.model.sharedModel.source.length,n=e.getPositionAt(t);n&&(e.setCursorPosition(n),e.revealPosition(n))}return JSON.stringify({status:"ok"})}},$.openFile={def:{name:"openFile",description:"Opens a non-notebook file for editing (code, text, etc) and returns its contents. \n Never open notebooks with this method! Do not use for files that start with '.' (period)",arguments:{filePath:{type:"string",name:"Relative path to the file to open. Relative! "}}},func:async e=>{if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});const t=e.filePath;if(t.endsWith(".ipynb"))return JSON.stringify({status:"fail",message:"Cannot open notebook files with this method"});const{contents:n}=O.serviceManager;let o,r;await h(O,t);try{try{if(o=await n.get(t),o.content&&"string"==typeof o.content&&o.content.length>65536)return JSON.stringify({status:"fail",message:"File is too large (> 64KB)"})}catch(e){await n.save(t,{type:"file",format:"text",content:""}),o=await n.get(t)}}catch(e){return JSON.stringify({status:"fail",message:"could not open file",detail:`${e.message} `})}try{r=await O.commands.execute("docmanager:open",{path:t,factory:"Editor"})}catch(e){return JSON.stringify({status:"fail",message:"could not open file",detail:`${e.message} `})}try{await Promise.race([r.context.ready,new Promise(((e,t)=>setTimeout((()=>t(new Error("Timeout waiting for context.ready"))),500)))])}catch(e){return JSON.stringify({status:"fail",message:"could not open file"})}return JSON.stringify({status:"ok",content:o.content})}},$.startTerminal={def:{name:"startTerminal",description:"Opens a command line terminal",arguments:{}},func:async e=>{const t=O.serviceManager.terminals,n=await t.startNew();return await O.commands.execute("terminal:open",{name:n.name}),v[n.name]="",n.messageReceived.connect(((e,t)=>{if("stdout"===t.type&&Array.isArray(t.content))for(var o=0;o<t.content.length;o++){const e=y(t.content[o]);v[n.name]+=e}})),JSON.stringify({staus:"ok",terminal_name:n.name})}},$.runCommandInTerminal={def:{name:"runCommandInTerminal",description:"Runs a command in a terminal. This will block until the command ends, only use for very short-lived tasks!",arguments:{name:{type:"string",name:"Name for the terminal to run the command in"},command:{type:"string",name:"Command to run in the terminal. Make sure to properly escape control sequnces like '!' "},timeout:{type:"integer",name:"Timeout in milliseconds, default 10000"}}},func:async e=>{let t=e.name||"";const n=e.command||"",o=e.timeout||6e4;if(console.log(`Attempting to run command in terminal: ${t}`),t.startsWith("{")&&t.endsWith("}"))try{const e=JSON.parse(t);e.name&&(t=e.name,console.log(`Parsed terminal name from JSON: ${t}`))}catch(e){console.log(`Failed to parse terminal name as JSON: ${e.message}`)}const{terminals:r}=O.serviceManager;if(!t){const e=await r.running(),n=Array.from(e);n.length>0?(t=n[0].name,console.log(`No terminal name provided, using first available: ${t}`)):(console.log("No terminals available, creating a new one"),t=(await r.startNew()).name,await O.commands.execute("terminal:open",{name:t}),await new Promise((e=>setTimeout(e,1e3))))}const i=await f(O,t);if(null===i)return JSON.stringify({status:"failure",message:`Terminal with name ${t} not found`});await O.commands.execute("terminal:open",{name:t});const s=(0,u.lk)(),a=new Promise((e=>{i.messageReceived.connect(((t,n)=>{if("stdout"===n.type)if(Array.isArray(n.content))for(var o=0;o<n.content.length;o++){const t=y(n.content[o]);l+=t,t.includes(`__${s}__`)&&(d=!0,e())}else console.log("> >",n);else console.log("> >",n)}))})),c=new Promise((e=>setTimeout(e,o)));var l="",d=!1;i.send({type:"stdin",content:[`${n} ; echo "cwd: $(pwd)"; echo __${s}__ \n`]}),await Promise.race([a,c]);const p=function(e,t){const n=e.indexOf(t);if(-1===n)return"";const o=e.indexOf(t,n+t.length);if(-1===o){const o=e.substring(n+t.length).trim();return o.length<16?e.substring(0,n).slice(-16e3).trim():o.slice(-16e3)}return e.substring(n+t.length,o).trim().slice(-16e3)}(l,`__${s}__`);return JSON.stringify({status:"success",stop:d?"natural":"timeout",result:p.trim()})}},$.runCommandInTerminalAsync={def:{name:"runCommandInTerminalAsync",description:"Runs a command in a terminal without waiting for completion. \n Returns immediately with 'ok' status. \n Use this for long-running commands where you don't need to wait for the result.\n Always check the terminal output before sending new commands to this terminal!",arguments:{name:{type:"string",name:"Name for the terminal to run the command in"},command:{type:"string",name:"Command to send to the terminal. Mak sur to proprly escape contol sequences like '!' "}}},func:async e=>{let t=e.name||"";const n=e.command||"";if(console.log(`Attempting to run command asynchronously in terminal: ${t}`),t.startsWith("{")&&t.endsWith("}"))try{const e=JSON.parse(t);e.name&&(t=e.name,console.log(`Parsed terminal name from JSON: ${t}`))}catch(e){console.log(`Failed to parse terminal name as JSON: ${e.message}`)}const{terminals:o}=O.serviceManager;if(!t){const e=await o.running(),n=Array.from(e);n.length>0?(t=n[0].name,console.log(`No terminal name provided, using first available: ${t}`)):(console.log("No terminals available, creating a new one"),t=(await o.startNew()).name,await O.commands.execute("terminal:open",{name:t}),await new Promise((e=>setTimeout(e,1e3))))}const r=await f(O,t);return null===r?JSON.stringify({status:"failure",message:`Terminal with name ${t} not found`}):(await O.commands.execute("terminal:open",{name:t}),r.send({type:"stdin",content:[`${n}\n`]}),JSON.stringify({status:"success",message:"Command sent to terminal"}))}},$.sendCommandToAsyncTerminal={def:{name:"sendCommandToAsyncTerminal",description:"Sends a command to an existing async terminal without waiting for completion. Use this to send additional commands to terminals started with runCommandInTerminalAsync.",arguments:{name:{type:"string",name:"Name of the terminal to send the command to"},command:{type:"string",name:"Command to send to the terminal"}}},func:async e=>{let t=e.name||"";const n=e.command||"";if(console.log(`Sending command to async terminal: ${t}`),t.startsWith("{")&&t.endsWith("}"))try{const e=JSON.parse(t);e.name&&(t=e.name,console.log(`Parsed terminal name from JSON: ${t}`))}catch(e){console.log(`Failed to parse terminal name as JSON: ${e.message}`)}const o=await f(O,t);return null===o?JSON.stringify({status:"failure",message:`Terminal with name ${t} not found`}):(await O.commands.execute("terminal:open",{name:t}),o.send({type:"stdin",content:[`${n}\n`]}),JSON.stringify({status:"success",message:"Command sent to terminal"}))}},$.getAsyncTerminalOutput={def:{name:"getAsyncTerminalOutput",description:"Retrieves the current output from an async terminal. Use this to check progress or results from terminals started with runCommandInTerminalAsync.",arguments:{name:{type:"string",name:"Name of the terminal to get output from"},clear:{type:"boolean",name:"Whether to clear the output buffer after retrieving (default: false)"}}},func:async e=>{let t=e.name||"";const n=e.clear||!1;if(t.startsWith("{")&&t.endsWith("}"))try{const e=JSON.parse(t);e.name&&(t=e.name,console.log(`Parsed terminal name from JSON: ${t}`))}catch(e){console.log(`Failed to parse terminal name as JSON: ${e.message}`)}if(null===await f(O,t))return JSON.stringify({status:"failure",message:`Terminal with name ${t} not found`});const o=v[t]||"";return n&&(v[t]=""),JSON.stringify({status:"success",output:o})}},$.insertExecuteCell={def:{name:"insertExecuteCell",description:"Index at which to place the new cell",arguments:{index:{type:"integer",name:"New cel lindex"},cellType:{type:"string",name:"Type of the cell being edited (code/markdown)"},content:{type:"string",name:"New content for the cell"}}},func:async(e,t=!1,n=void 0)=>{var{index:o,cellType:r,content:i}=e;const s=M.currentWidget;O.shell.activateById(s.id);const a=s.content;var c=(o="string"==typeof o?parseInt(o,10):o)<=0?0:o;if(null==L[n]?(L[n]=o,function(e,t,n){var o=n;n<=0?(e.activeCellIndex=0,p.NotebookActions.insertAbove(e),o=0,e.activeCellIndex=o,p.NotebookActions.changeCellType(e,t)):(e.activeCellIndex=n-1,p.NotebookActions.insertBelow(e),o=n,e.activeCellIndex=o,p.NotebookActions.changeCellType(e,t))}(a,r,o)):a.activeCellIndex=c,"edit"!=a.mode&&(a.activate(),a.mode="edit"),!t){const t=a.activeCell;if(null==u.gb[n]&&t.node.scrollIntoView({behavior:"smooth",block:"end"}),t.model.sharedModel.setSource(e.content),a.mode="command",t instanceof g.MarkdownCell)return t.rendered=!0,await s.context.save(),"ok";{await p.NotebookActions.run(a,s.sessionContext);const e=await $.getCellOutput.func({index:o,scroll:!1});return t instanceof g.CodeCell&&t.outputArea.node.scrollIntoView({behavior:"smooth",block:"end"}),await s.context.save(),e}}{const t=a.activeCell;t.node.scrollIntoView({behavior:"smooth",block:"end"}),t.model.sharedModel.setSource(e.content),t instanceof g.MarkdownCell&&(t.rendered=!0)}return"ok"}},$.editExecuteCell={def:{name:"editExecuteCell",description:"Edit the content of a cell by index and execute (render) it. Do not use if no edits required",arguments:{index:{type:"integer",name:"Index of the cell to edit"},cellType:{type:"string",name:"Type of the cell being edited"},content:{type:"string",name:"New content for the cell"}}},func:async(e,t=!1,n=void 0)=>{if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});var{index:o,cellType:r,content:i}=e;o="string"==typeof o?parseInt(o,10):o;try{const n=M.currentWidget;O.shell.activateById(n.id);const i=n.content;i.activeCellIndex=o;const s=i.activeCell;return s.node.scrollIntoView({behavior:"smooth",block:"end"}),s instanceof g.CodeCell&&p.NotebookActions.clearOutputs(i),p.NotebookActions.changeCellType(i,r),"edit"!=i.mode&&(i.activate(),i.mode="edit"),s.model.sharedModel.setSource(e.content),s instanceof g.MarkdownCell?(s.rendered=!0,"ok"):t?"ok":(await n.context.save(),await p.NotebookActions.run(i,n.sessionContext),await $.getCellOutput.func({index:o,scroll:!0}))}catch(e){return JSON.stringify({error:`Error editing cell: ${e.message}`})}}},$.executeCell={def:{name:"executeCell",description:"Execute a cell by index. Use when no code change were made to the cell",arguments:{index:{type:"integer",name:"Index of the cell to execute"},maxWaitTime:{type:"integer",name:"Maximum time to wait for execution or breakpoint (ms)",optional:!0}}},func:async e=>{var{index:t,maxWaitTime:n}=e;t="string"==typeof t?parseInt(t,10):t,n="string"==typeof n?parseInt(n,10):n;const o=M.currentWidget;if(!o)return JSON.stringify({error:"No active notebook"});O.shell.activateById(o.id);const r=o.content;r.activeCellIndex=t;const i=r.activeCell;if(i.node.scrollIntoView({behavior:"smooth",block:"center"}),i instanceof g.MarkdownCell)return i.rendered=!0,"ok";{p.NotebookActions.run(r,o.sessionContext);const e=await $.waitForDebugger.func({index:t,maxWaitTime:n}),s=JSON.parse(e);if(s.completed){const e=await $.getCellOutput.func({index:t,scroll:!1});return i instanceof g.CodeCell&&i.outputArea.node.scrollIntoView({behavior:"smooth",block:"start"}),e}return s.breakpointHit?JSON.stringify({success:!0,message:"Execution paused at breakpoint",debuggerPaused:!0,elapsedTime:s.elapsedTime}):JSON.stringify({success:!0,message:"Execution started, but neither completed nor hit a breakpoint within timeout period",debuggerPaused:!1,timedOut:!0,elapsedTime:s.elapsedTime})}}},$.getCellOutput={def:{name:"getCellOutput",description:"Get the output of a cell by index",arguments:{index:{type:"integer",name:"Index of the cell to get output from"}}},func:async e=>{var{index:t,scroll:n}=e;t="string"==typeof t?parseInt(t,10):t,n=!1!==n;const o=M.currentWidget;O.shell.activateById(o.id);const r=o.content;r.activeCellIndex=t;const i=r.activeCell;if(n&&i.node.scrollIntoView({behavior:"smooth",block:"center"}),i instanceof g.CodeCell){const e=i.outputArea,t=[];for(let n=0;n<e.model.length;n++){const o=e.model.get(n);console.log(`Output is array: ${Array.isArray(o)}`),console.log(JSON.stringify(o).substring(0,200)),t.push(o)}return t}return"markdown cells do not have outputs"}},$.listCells={def:{name:"listCells",description:"Lists all cells in the currently opened notebook with their content, type, and outputs. Open a notebook first!",arguments:{}},func:async e=>{const t=M.currentWidget;if(null==t)return[];t.content;const n=M.currentWidget.content,o=[];for(let e=0;e<n.widgets.length;e++){const t=n.widgets[e],r=t.model,i={index:e,type:r.type,content:r.sharedModel.getSource()};if(t instanceof g.CodeCell){const e=t.outputArea,n=[];for(let t=0;t<e.model.length;t++){const o=e.model.get(t);n.push(o)}i.outputs=n}o.push(i)}return{cells:o,path:t.context.path}}},$.deleteCell={def:{name:"deleteCell",description:"Delete a cell by index",arguments:{index:{type:"integer",name:"Index of the cell to delete"}}},func:async e=>{if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});const{index:t}=e,n=H(O);if(!n||!n.content)return JSON.stringify({error:"No active notebook found"});if(!B(n,t))return JSON.stringify({error:`Invalid cell index: ${t}`});try{return n.content.activeCellIndex=t,p.NotebookActions.deleteCells(n.content),JSON.stringify({success:!0,message:`Cell at index ${t} deleted`})}catch(e){return JSON.stringify({error:`Error deleting cell: ${e.message}`})}}},$.saveAllOutputImages={def:{name:"saveAllOutputImages",description:"Save all output images from a cell to a specified folder",arguments:{cellIndex:{type:"integer",name:"Index of the cell containing the images"},folderPath:{type:"string",name:"Folder path where images should be saved"},filePrefix:{type:"string",name:"Prefix for the image filenames",default:"image"}}},func:async e=>{if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});const{cellIndex:t,folderPath:n,filePrefix:o="image"}=e,r=H(O);if(!r||!r.content)return JSON.stringify({error:"No active notebook found"});if(!B(r,t))return JSON.stringify({error:`Invalid cell index: ${t}`});try{if(!(r.content.widgets[t]instanceof g.CodeCell))return JSON.stringify({error:`Cell ${t} is not a code cell and has no output`});const e=await $.getCellOutput.func({index:t});console.log("[saveAllOutputImages] Raw getCellOutput result:",e);let i=[];if("string"==typeof e){console.log("[saveAllOutputImages] Parsing string output result");try{i=JSON.parse(e),console.log("[saveAllOutputImages] Successfully parsed output JSON")}catch(t){console.error("[saveAllOutputImages] Error parsing outputs:",t),console.log("[saveAllOutputImages] Raw string output:",e)}}else if(Array.isArray(e))console.log("[saveAllOutputImages] Output result is already an array"),i=e;else if(e&&"object"==typeof e){console.log("[saveAllOutputImages] Output result is an object, checking for array properties");for(const t in e)if(Array.isArray(e[t])){console.log(`[saveAllOutputImages] Found array in property '${t}'`),i=e[t];break}0===i.length&&e.data&&(console.log("[saveAllOutputImages] Treating object as a single output"),i=[e])}else console.log("[saveAllOutputImages] Unrecognized output format, using as is"),i=e;if(console.log("[saveAllOutputImages] Processed outputs:",i),!i||!Array.isArray(i)||0===i.length)return JSON.stringify({error:`No outputs found for cell ${t}`});console.log(`[saveAllOutputImages] Ensuring directory exists: ${n}`);try{const e=`${n}/dummy.txt`;await h(O,e),console.log(`[saveAllOutputImages] Directory ensured: ${n}`)}catch(e){throw console.error(`[saveAllOutputImages] Error ensuring directory: ${e.message}`),e}const s=O.serviceManager.contents,a=["image/png","image/jpeg","image/jpg","image/gif","image/svg+xml"],c=[];let l=0;for(let e=0;e<i.length;e++){const r=i[e];if(console.log(`[saveAllOutputImages] Processing output ${e}:`,r),r&&r.data){console.log(`[saveAllOutputImages] Output ${e} data:`,r.data),console.log(`[saveAllOutputImages] Available MIME types in output ${e}:`,Object.keys(r.data||{}).filter((e=>e.startsWith("image/"))));for(const i of a)if(r.data[i]){const a=r.data[i];console.log(`[saveAllOutputImages] Found image data in output ${e} with MIME type: ${i}`),console.log("[saveAllOutputImages] Image data preview:","string"==typeof a?`${a.substring(0,50)}... (${a.length} chars)`:"Non-string data");const d=Date.now(),u=`${n}/${o}_cell${t}_${l}_${d}.${i.split("/")[1].replace("jpeg","jpg")}`;let p="base64";"image/svg+xml"!==i||"string"!=typeof a||a.startsWith("data:")?console.log(`[saveAllOutputImages] Using base64 format for ${i} data`):(p="text",console.log("[saveAllOutputImages] Using text format for SVG data")),console.log(`[saveAllOutputImages] Saving image to: ${u}`),console.log(`[saveAllOutputImages] File format: ${p}`);try{await s.save(u,{type:"file",format:p,content:a}),console.log(`[saveAllOutputImages] Successfully saved image to ${u}`)}catch(e){throw console.error(`[saveAllOutputImages] Error saving image to ${u}:`,e),e}c.push({filePath:u,mimeType:i,outputIndex:e}),l++}}else console.log(`[saveAllOutputImages] Output ${e} has no data, skipping`)}return 0===c.length?JSON.stringify({error:`No image data found in any outputs of cell ${t}`}):JSON.stringify({success:!0,message:`Saved ${c.length} images to ${n}`,savedImages:c})}catch(e){return JSON.stringify({error:`Error saving images: ${e.message}`})}}},$.saveOutputImage={def:{name:"saveOutputImage",description:"Save an output image from a cell to a specified file",arguments:{cellIndex:{type:"integer",name:"Index of the cell containing the image"},outputIndex:{type:"integer",name:"Index of the output to save (if cell has multiple outputs)",default:0},filePath:{type:"string",name:"Path where the image should be saved"}}},func:async e=>{if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});const{cellIndex:t,outputIndex:n=0,filePath:o}=e,r=H(O);if(!r||!r.content)return JSON.stringify({error:"No active notebook found"});if(!B(r,t))return JSON.stringify({error:`Invalid cell index: ${t}`});try{if(!(r.content.widgets[t]instanceof g.CodeCell))return JSON.stringify({error:`Cell ${t} is not a code cell and has no output`});const e=await $.getCellOutput.func({index:t});console.log("[saveOutputImage] Raw getCellOutput result:",e);let i=[];if("string"==typeof e){console.log("[saveOutputImage] Parsing string output result");try{i=JSON.parse(e),console.log("[saveOutputImage] Successfully parsed output JSON")}catch(t){console.error("[saveOutputImage] Error parsing outputs:",t),console.log("[saveOutputImage] Raw string output:",e)}}else if(Array.isArray(e))console.log("[saveOutputImage] Output result is already an array"),i=e;else if(e&&"object"==typeof e){console.log("[saveOutputImage] Output result is an object, checking for array properties");for(const t in e)if(Array.isArray(e[t])){console.log(`[saveOutputImage] Found array in property '${t}'`),i=e[t];break}0===i.length&&e.data&&(console.log("[saveOutputImage] Treating object as a single output"),i=[e])}else console.log("[saveOutputImage] Unrecognized output format, using as is"),i=e;if(console.log("[saveOutputImage] Processed outputs:",i),!i||!Array.isArray(i)||i.length<=n)return JSON.stringify({error:`No output found at index ${n} for cell ${t}`});const s=i[n];if(!s||!s.data)return JSON.stringify({error:`Output at index ${n} does not contain data`});const a=["image/png","image/jpeg","image/jpg","image/gif","image/svg+xml"];console.log("[saveOutputImage] Output data:",s.data),console.log("[saveOutputImage] Available MIME types in output:",Object.keys(s.data||{}).filter((e=>e.startsWith("image/"))));let c=null,l=null;for(const e of a)if(s.data[e]){c=s.data[e],l=e,console.log(`[saveOutputImage] Found image data with MIME type: ${e}`),console.log("[saveOutputImage] Image data preview:","string"==typeof c?`${c.substring(0,50)}... (${c.length} chars)`:"Non-string data");break}if(!c||!l)return JSON.stringify({error:`No image data found in output ${n}`});const d=o.lastIndexOf("/"),u=-1!==d?o.substring(0,d):".";console.log(`[saveOutputImage] Ensuring directory exists: ${u}`);try{const e=`${u}/dummy.txt`;await h(O,e),console.log(`[saveOutputImage] Directory ensured: ${u}`)}catch(e){throw console.error(`[saveOutputImage] Error ensuring directory: ${e.message}`),e}const p=O.serviceManager.contents;let m="base64",y=c;"image/svg+xml"!==l||"string"!=typeof c||c.startsWith("data:")?console.log(`[saveOutputImage] Using base64 format for ${l} data`):(m="text",console.log("[saveOutputImage] Using text format for SVG data")),console.log(`[saveOutputImage] Saving image to: ${o}`),console.log(`[saveOutputImage] File format: ${m}`);try{await p.save(o,{type:"file",format:m,content:y}),console.log(`[saveOutputImage] Successfully saved image to ${o}`)}catch(e){throw console.error(`[saveOutputImage] Error saving image to ${o}:`,e),e}return JSON.stringify({success:!0,message:`Image saved to ${o}`,mimeType:l})}catch(e){return JSON.stringify({error:`Error saving image: ${e.message}`})}}},$.setValue={def:{name:"setValue",description:"Sets a session variable, aka settings vairable, setting, variable, etc",arguments:{key:{type:"string",name:"Name of the property to set"},value:{type:"string",name:"The value to store"}}},func:async e=>{let t=e.key||"",n=e.value||"";return F[t]=n,"ok"}},$.getValue={def:{name:"getValue",description:"Gets a session variable, aka settings vairable, setting, variable, etc",arguments:{key:{type:"string",name:"Name of the property to retrieve"}}},func:async e=>{let t=e.key||"",n=F[t]=F[t];return JSON.stringify({key:t,velue:n})}},$.diffToFile={def:{name:"diffToFile",description:"Makes tagreted change in file. Search must match the entire piece exactly. Use it in as a diff",arguments:{filePath:{type:"string",name:"Relative path to the file to display in merge view. Relative! "},search:{type:"string",name:"text to be removed. Pass '+' string to append to file, '-' to add at the beginning"},replace:{type:"string",name:"text to insert instead of the removed text"}}},func:async(e,t=!1,n=void 0)=>{if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});const{contents:o}=O.serviceManager,{filePath:r,search:i,replace:s}=e;if(null==i||null==s)return"";try{let e;try{e=await o.get(r)}catch(e){return JSON.stringify({status:"fail",message:`Cannot open file: ${r} does not exist`})}const l=e.content;var a=l;if("+"==i?a+=A(s):a="-"==i?s+A(s):a.replace(A(i),A(s)),null!=J[n])!function(e,t){try{if(!e.b||!e.b.state)return console.error("Could not access state for doc B"),!1;const n=e.b.state;return e.b.dispatch({changes:{from:0,to:n.doc.length,insert:t}}),console.log("Successfully updated doc B"),!0}catch(e){return console.error("Error updating doc B:",e),!1}}(J[n],a);else if(null==J[n]){const e=document.createElement("div");e.style.height="100%",e.style.overflow="auto";const t=[b.jupyterTheme,...T(r)],o=document.createElement("style");o.textContent="\n /* Basic syntax highlighting styles using JupyterLab variables */\n .cm - keyword { color: var(--jp - mirror - editor - keyword - color); font - weight: bold; }\n .cm - comment { color: var(--jp - mirror - editor - comment - color); }\n .cm - string { color: var(--jp - mirror - editor - string - color); }\n .cm - number { color: var(--jp - mirror - editor - number - color); }\n .cm - operator { color: var(--jp - mirror - editor - operator - color); }\n .cm - property { color: var(--jp - mirror - editor - property - color); }\n .cm - variable { color: var(--jp - mirror - editor - variable - color); }\n .cm - function, .cm - def { color: var(--jp - mirror - editor - def - color); }\n .cm - atom { color: var(--jp - mirror - editor - atom - color); }\n .cm - meta { color: var(--jp - mirror - editor - meta - color); }\n .cm - tag { color: var(--jp - mirror - editor - tag - color); }\n .cm - attribute { color: var(--jp - mirror - editor - attribute - color); }\n .cm - qualifier { color: var(--jp - mirror - editor - qualifier - color); }\n .cm - bracket { color: var(--jp - mirror - editor - bracket - color); }\n .cm - builtin { color: var(--jp - mirror - editor - builtin - color); }\n .cm - special { color: var(--jp - mirror - editor - string - 2 - color); }\n ",document.head.appendChild(o);const i=new w.MergeView({a:{doc:l,extensions:t},b:{doc:a,extensions:t},highlightChanges:!0});J[n]=i,e.appendChild(i.dom),setTimeout((function(){(e=>{try{const t=e.dom.querySelectorAll(".cm-editor");console.log(`Found ${t.length} editors in merge view`),t.forEach(((e,t)=>{var n;const o=e.view;if(o){i=o,s=`Editor ${t}`,console.log(`Debug ${s}:`,{hasFocus:i.hasFocus,docLength:i.state.doc.length});const a=(null===(n=r.split(".").pop())||void 0===n?void 0:n.toLowerCase())||"";e.classList.add(`language-${a}`),setTimeout((()=>{try{o.dispatch({})}catch(e){console.error(`Error refreshing editor ${t}:`,e)}}),100)}else console.log(`Could not access view for editor ${t}`);var i,s}))}catch(e){console.error("Error applying syntax highlighting:",e)}})(i)}),500);const s=new c.Widget;_[n]=s,s.id=n,s.title.label=`Merge View: ${r} `,s.title.closable=!0,s.node.appendChild(e),O.shell.add(s,"main"),O.shell.activateById(s.id)}if(!t){if(console.log(O.commands.listCommands()),J[n]){const e=_[n];e&&setTimeout((()=>{e.close(),setTimeout((()=>{O.commands.execute("docmanager:open",{path:r}),setTimeout((()=>{O.commands.execute("docmanager:reload")}),100)}),100)}),1e3)}return await o.save(r,{type:"file",format:"text",content:a}),JSON.stringify({status:"ok",new_content:a})}}catch(e){return JSON.stringify({status:"fail",message:`Failed to open merge view: ${e.message} `})}}},$.startDebugger={def:{name:"startDebugger",description:"Turn on the debugger for the current notebook",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});const t=H(O);if(!t||!t.sessionContext)return JSON.stringify({error:"No active notebook found"});try{if(!await P.isAvailable(t.sessionContext.session))return JSON.stringify({error:"Debugging is not available for the current kernel"});P.session&&(P.session.connection=t.sessionContext.session),await P.start(),await P.restoreState(!0),await P.displayDefinedVariables();const e=new U.Debugger.Handler({type:"notebook",shell:O.shell,service:P});return await e.updateContext(t,t.sessionContext),O.commands.hasCommand("debugger:show-panel")&&O.commands.execute("debugger:show-panel"),document.body.dataset.jpDebuggerActive="true",P.hasStoppedThreads()&&(document.body.dataset.jpDebuggerStoppedThreads="true"),JSON.stringify({success:!0,message:"Debugger started successfully and UI activated"})}catch(e){return JSON.stringify({error:`Error starting debugger: ${e.message}`})}}},$.stopDebugger={def:{name:"stopDebugger",description:"Turn off the debugger for the current notebook",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});try{if(!P.isStarted)return JSON.stringify({success:!0,message:"Debugger is not running"});await P.stop(),delete document.body.dataset.jpDebuggerActive,delete document.body.dataset.jpDebuggerStoppedThreads;const e=O.shell;return e&&"function"==typeof e.collapseRight&&e.collapseRight(),JSON.stringify({success:!0,message:"Debugger stopped successfully"})}catch(e){return JSON.stringify({error:`Error stopping debugger: ${e.message}`})}}},$.isDebuggerAvailable={def:{name:"isDebuggerAvailable",description:"Check if debugging is available for the current notebook",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});const t=H(O);if(!t||!t.sessionContext)return JSON.stringify({error:"No active notebook found"});try{const e=await P.isAvailable(t.sessionContext.session);return JSON.stringify({success:!0,available:e})}catch(e){return JSON.stringify({error:`Error checking debugger availability: ${e.message}`})}}},$.getDebuggerState={def:{name:"getDebuggerState",description:"Get the current state of the debugger",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});try{return JSON.stringify({success:!0,isStarted:P.isStarted,hasStoppedThreads:P.hasStoppedThreads()})}catch(e){return JSON.stringify({error:`Error getting debugger state: ${e.message}`})}}},$.setBreakpoint={def:{name:"setBreakpoint",description:"Set a breakpoint in the current notebook cell",arguments:{index:{type:"integer",name:"Index of the cell to set breakpoint in"},lineNumber:{type:"integer",name:"Line number to set breakpoint at (1-based)"}}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});const t=H(O);if(!t||!t.content)return JSON.stringify({error:"No active notebook found"});try{const n="string"==typeof e.index?parseInt(e.index,10):e.index,o="string"==typeof e.lineNumber?parseInt(e.lineNumber,10):e.lineNumber;if(n<0||n>=t.content.widgets.length)return JSON.stringify({error:"Invalid cell index"});if(!o||o<1)return JSON.stringify({error:"Invalid line number"});const r=t.content.widgets[n].model.sharedModel.getSource(),i=[{line:o,verified:!1}];return await P.updateBreakpoints(r,i),JSON.stringify({success:!0,message:"Breakpoints set successfully"})}catch(e){return JSON.stringify({error:`Error setting breakpoints: ${e.message}`})}}},$.clearBreakpoints={def:{name:"clearBreakpoints",description:"Clear all breakpoints in the notebook",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});try{return await P.clearBreakpoints(),JSON.stringify({success:!0,message:"All breakpoints cleared"})}catch(e){return JSON.stringify({error:`Error clearing breakpoints: ${e.message}`})}}},$.stepOver={def:{name:"stepOver",description:"Step over to the next line of code",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{return await P.next(),JSON.stringify({success:!0,message:"Stepped over to next line"})}catch(e){return JSON.stringify({error:`Error stepping over: ${e.message}`})}}},$.stepInto={def:{name:"stepInto",description:"Step into a function or method",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{return await P.stepIn(),JSON.stringify({success:!0,message:"Stepped into function"})}catch(e){return JSON.stringify({error:`Error stepping into: ${e.message}`})}}},$.stepOut={def:{name:"stepOut",description:"Step out of the current function or method",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{return await P.stepOut(),JSON.stringify({success:!0,message:"Stepped out of function"})}catch(e){return JSON.stringify({error:`Error stepping out: ${e.message}`})}}},$.continueExecution={def:{name:"continueExecution",description:"Continue execution until the next breakpoint or end of program",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{return await P.continue(),JSON.stringify({success:!0,message:"Execution continued"})}catch(e){return JSON.stringify({error:`Error continuing execution: ${e.message}`})}}},$.pauseExecution={def:{name:"pauseExecution",description:"Pause the execution of the current program",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});try{return await P.pause(),JSON.stringify({success:!0,message:"Execution paused"})}catch(e){return JSON.stringify({error:`Error pausing execution: ${e.message}`})}}},$.evaluateExpression={def:{name:"evaluateExpression",description:"Evaluate an expression in the current debug context",arguments:{expression:{type:"string",name:"Expression to evaluate"}}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{const t=e.expression;if(!t)return JSON.stringify({error:"No expression provided"});const n=await P.evaluate(t);return JSON.stringify({success:!0,result:n})}catch(e){return JSON.stringify({error:`Error evaluating expression: ${e.message}`})}}},$.inspectVariables={def:{name:"inspectVariables",description:"Get all variables in the current scope",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});try{await P.displayDefinedVariables();const e=P.model.variables.scopes;return JSON.stringify({success:!0,scopes:e})}catch(e){return JSON.stringify({error:`Error inspecting variables: ${e.message}`})}}},$.inspectVariable={def:{name:"inspectVariable",description:"Inspect a specific variable by reference ID",arguments:{variableReference:{type:"integer",name:"Reference ID of the variable to inspect"}}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});try{const t=e.variableReference;if(!t)return JSON.stringify({error:"No variable reference provided"});P.inspectVariable(t),await new Promise((e=>setTimeout(e,100)));const n=P.model.variables;return JSON.stringify({success:!0,variables:n})}catch(e){return JSON.stringify({error:`Error inspecting variable: ${e.message}`})}}},$.getCallStack={def:{name:"getCallStack",description:"Get the current call stack when execution is paused",arguments:{}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});if(!P.hasStoppedThreads())return JSON.stringify({error:"Debugger is not paused at a breakpoint"});try{const e=P.model.callstack.frames;return JSON.stringify({success:!0,callstack:e})}catch(e){return JSON.stringify({error:`Error getting call stack: ${e.message}`})}}},$.setPauseOnExceptions={def:{name:"setPauseOnExceptions",description:"Configure the debugger to pause on exceptions",arguments:{filter:{type:"string",name:"Exception type to pause on (e.g., 'uncaught' or 'raised')"}}},func:async e=>{if(!O||!P)return JSON.stringify({error:"JupyterLab app or debugger service not initialized"});if(!P.isStarted)return JSON.stringify({error:"Debugger is not running"});try{const t=e.filter||"";return t?(await P.pauseOnExceptionsFilter(t),JSON.stringify({success:!0,message:"Exception breakpoints configured"})):JSON.stringify({error:"No filter provided"})}catch(e){return JSON.stringify({error:`Error setting exception breakpoints: ${e.message}`})}}},$.waitForDebugger={def:{name:"waitForDebugger",description:"Wait for either a breakpoint to be hit or cell execution to complete",arguments:{index:{type:"integer",name:"Index of the cell being executed"},maxWaitTime:{type:"integer",name:"Maximum time to wait in milliseconds",optional:!0},pollInterval:{type:"integer",name:"Interval between checks in milliseconds",optional:!0}}},func:async e=>{const{index:t,maxWaitTime:n=1e4,pollInterval:o=100}=e,r=M.currentWidget;if(!r)return JSON.stringify({error:"No active notebook"});const i=r.content;if(t<0||t>=i.widgets.length)return JSON.stringify({error:"Invalid cell index"});const s=i.widgets[t],a=Date.now();for(;Date.now()-a<n;){if((null==P?void 0:P.isStarted)&&P.hasStoppedThreads()){const e=Date.now()-a;return JSON.stringify({completed:!1,breakpointHit:!0,timedOut:!1,elapsedTime:e})}if("idle"===s.model.executionState){const e=Date.now()-a;return JSON.stringify({completed:!0,breakpointHit:!1,timedOut:!1,elapsedTime:e})}await new Promise((e=>setTimeout(e,o)))}const c=Date.now()-a;return JSON.stringify({completed:!1,breakpointHit:!1,timedOut:!0,elapsedTime:c})}};var D=!1;function H(e){const{shell:t}=e,n=t.currentWidget;return n&&n instanceof p.NotebookPanel?n:null}function B(e,t){if(!e||!e.content)return!1;const n=e.content.widgets.length;return t>=0&&t<n}async function R(e,t,n){console.log("=============== register_functions ==============="),O=e,M=t,P=n;for(const e of Object.keys($))console.log("register function:",e),(0,u.uo)(e,!0,$[e].func,$[e],!0)}$.listAvailableKernels={def:{name:"listAvailableKernels",description:"Lists kernels (such as python) available on the system",arguments:{}},func:async e=>{var t;await O.serviceManager.kernelspecs.refreshSpecs(),await O.serviceManager.kernelspecs.refreshSpecs();const n=null===(t=O.serviceManager.kernelspecs.specs)||void 0===t?void 0:t.kernelspecs,o=Object.values(n).map((e=>({name:e.name,display_name:e.display_name,language:e.language})));return JSON.stringify(o)}},$.createAndOpenNotebook={def:{name:"createAndOpenNotebook",description:"Creates and opens a new notebook",arguments:{name:{type:"string",name:"Name for the new notebook"},kernelName:{type:"string",name:"Name of kernel to use"}}},func:async e=>{var t,n,o,r;let i=e.name;const s=e.kernelName,a=O.serviceManager.contents,c=null===(t=O.serviceManager.kernelspecs.specs)||void 0===t?void 0:t.kernelspecs;i.endsWith(".ipynb")||(i+=".ipynb");const l=i.startsWith("./")?i.slice(2):i,d=null==c?void 0:c[s],u=null!==(n=null==d?void 0:d.display_name)&&void 0!==n?n:s,p=null!==(o=null==d?void 0:d.language)&&void 0!==o?o:"python";try{await a.get(l)}catch(e){if(404!==(null===(r=e.response)||void 0===r?void 0:r.status))return console.error(e),"There was an error retrieving notebook info.";await a.save(l,{type:"notebook",format:"json",content:{cells:[],metadata:{kernelspec:{name:s,display_name:u,language:p}},nbformat:4,nbformat_minor:5}})}return await O.commands.execute("docmanager:open",{path:l,factory:"Notebook",options:{kernel:{name:s}}}),"done"}},$.openNotebook={def:{name:"openNotebook",description:"Opens an existing notebook",arguments:{name:{type:"string",name:"Name for the notebook to open"}}},func:async e=>{const t=e.name,n=O.serviceManager.contents;try{await n.get(t)}catch(e){return`Notebook ${t} does not exit`}return await O.commands.execute("docmanager:open",{path:t,factory:"Notebook"}),"done"}},$.restartKernel={def:{name:"restartKernel",description:"Restart the kernel of the active notebook",arguments:{}},func:async e=>{var t;if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});const n=H(O);if(!n||!n.sessionContext)return JSON.stringify({error:"No active notebook found"});try{if(!(null===(t=n.sessionContext.session)||void 0===t?void 0:t.kernel))throw new Error("No kernel available to restart");return await n.sessionContext.session.kernel.restart(),JSON.stringify({success:!0,message:"Kernel restarted successfully"})}catch(e){return JSON.stringify({error:`Error restarting kernel: ${e.message}`})}}},$.stopExecution={def:{name:"stopExecution",description:"Stop the execution of the active notebook by interrupting the kernel",arguments:{}},func:async e=>{var t,n;if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});const o=H(O);if(!o||!o.sessionContext)return JSON.stringify({error:"No active notebook found"});try{return await(null===(n=null===(t=o.sessionContext.session)||void 0===t?void 0:t.kernel)||void 0===n?void 0:n.interrupt()),JSON.stringify({success:!0,message:"Execution interrupted"})}catch(e){return JSON.stringify({error:`Error interrupting kernel: ${e.message}`})}}},$.getCurrentNotebook={def:{name:"getCurrentNotebook",description:"Gets information about the currently open notebook",arguments:{}},func:async e=>{if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});const t=H(O);if(!t||!t.content)return JSON.stringify({error:"No active notebook found"});try{const e=t.context,n=t.model,o=e.path,r=o.split("/").pop()||"",i=e.model.dirty;let s={};if(n&&n.metadata)try{const e=n;s={kernelName:e.metadata.kernelName||"",kernelLanguage:e.metadata.kernelLanguage||""}}catch(e){console.error("Error extracting notebook metadata:",e)}return JSON.stringify({success:!0,notebook:{path:o,name:r,dirty:i,metadata:s,cell_count:n.cells.length}})}catch(e){return JSON.stringify({error:`Error getting notebook information: ${e.message}`})}}},$.getKernelState={def:{name:"getKernelState",description:"Get the state of the kernel and information about any currently executing cell",arguments:{}},func:async e=>{if(!O)return JSON.stringify({error:"JupyterLab app not initialized"});const t=H(O);if(!t||!t.sessionContext)return JSON.stringify({error:"No active notebook found"});try{const e=t.sessionContext.session,n=null==e?void 0:e.kernel;if(!n)return JSON.stringify({success:!0,kernel_state:"no_kernel",executing:!1});const o=n.status,r=[],i=t.content.widgets;for(let e=0;e<i.length;e++){const t=i[e];t instanceof g.CodeCell&&null!==t.model.executionCount&&t.hasClass("jp-mod-executing")&&r.push({index:e,execution_count:t.model.executionCount})}return JSON.stringify({success:!0,kernel_state:o,executing:"busy"===o,executing_cells:r})}catch(e){return JSON.stringify({error:`Error getting kernel state: ${e.message}`})}}};var K=n(9838);class j{constructor(e,t){this.authProviders=[{id:"google",name:"Google",icon:'<svg viewBox="0 0 24 24" width="18" height="18"><path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/><path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/></svg>',description:"Sign in with your Google account"}],this.onSuccess=e,this.onCancel=t,this.overlay=document.createElement("div"),this.overlay.className="escobar-login-overlay",this.overlay.style.cssText="\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n opacity: 0;\n transition: opacity 0.3s ease;\n ",this.overlay.addEventListener("click",(e=>{e.target===this.overlay&&(this.hide(),this.onCancel())})),this.container=this.createContainer(),this.overlay.appendChild(this.container)}createContainer(){const e=document.createElement("div");e.className="escobar-login-container",e.style.cssText="\n background: var(--jp-layout-color0);\n border: 1px solid var(--jp-border-color1);\n border-radius: 8px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n max-width: 400px;\n width: 90%;\n max-height: 80vh;\n overflow-y: auto;\n transform: scale(0.9);\n transition: transform 0.3s ease;\n ";const t=document.createElement("div");t.style.cssText="\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px 24px 16px;\n border-bottom: 1px solid var(--jp-border-color1);\n ";const n=document.createElement("h2");n.textContent="Authentication Required",n.style.cssText="\n margin: 0;\n color: var(--jp-content-font-color1);\n font-size: 18px;\n font-weight: 600;\n ",t.appendChild(n);const o=document.createElement("button");o.innerHTML="&times;",o.style.cssText="\n background: none;\n border: none;\n font-size: 24px;\n color: var(--jp-content-font-color2);\n cursor: pointer;\n padding: 0;\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n transition: background-color 0.2s ease;\n ",o.addEventListener("click",(()=>{this.hide(),this.onCancel()})),o.addEventListener("mouseenter",(()=>{o.style.backgroundColor="var(--jp-layout-color2)"})),o.addEventListener("mouseleave",(()=>{o.style.backgroundColor="transparent"})),t.appendChild(o),e.appendChild(t);const r=document.createElement("div");r.style.cssText="\n padding: 24px;\n ";const i=document.createElement("p");i.textContent="Please authenticate to access AI services:",i.style.cssText="\n margin: 0 0 20px 0;\n color: var(--jp-content-font-color2);\n font-size: 14px;\n line-height: 1.5;\n ",r.appendChild(i);const s=document.createElement("div");return s.style.cssText="\n display: flex;\n flex-direction: column;\n gap: 12px;\n ",this.authProviders.forEach((e=>{const t=document.createElement("button");t.dataset.provider=e.id,t.style.cssText="\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n background: var(--jp-layout-color1);\n border: 1px solid var(--jp-border-color1);\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n text-align: left;\n width: 100%;\n ",t.addEventListener("mouseenter",(()=>{t.style.backgroundColor="var(--jp-layout-color2)",t.style.borderColor="var(--jp-brand-color1)"})),t.addEventListener("mouseleave",(()=>{t.style.backgroundColor="var(--jp-layout-color1)",t.style.borderColor="var(--jp-border-color1)"}));const n=document.createElement("span");n.innerHTML=e.icon,n.style.cssText="\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n ",t.appendChild(n);const o=document.createElement("div");o.style.cssText="\n flex: 1;\n ";const r=document.createElement("div");r.textContent=e.name,r.style.cssText="\n font-weight: 500;\n color: var(--jp-content-font-color1);\n font-size: 14px;\n margin-bottom: 2px;\n ",o.appendChild(r);const i=document.createElement("div");i.textContent=e.description,i.style.cssText="\n font-size: 12px;\n color: var(--jp-content-font-color2);\n line-height: 1.3;\n ",o.appendChild(i),t.appendChild(o),t.addEventListener("click",(()=>{this.handleProviderClick(e.id)})),s.appendChild(t)})),r.appendChild(s),e.appendChild(r),e}async handleProviderClick(e){if("google"===e){this.setLoadingState(e,!0);try{let t=(0,K.Hn)();if(!t){const n=window.escobarCurrentSettings,o=null==n?void 0:n.googleClientId;if(!o)return this.setLoadingState(e,!1),void this.showError("Google Client ID not configured. Please set it in the settings first.");t=(0,K.e$)({clientId:o,scope:"openid email profile https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/documents.readonly"})}const n=await t.loginWithAuthCode();this.setLoadingState(e,!1),n.success&&n.idToken?(console.log("🔐 LOGIN-UI: Authentication successful"),window.escobarGoogleIdToken=n.idToken,window.escobarGoogleUserInfo=n.userInfo,this.hide(),this.onSuccess(n.idToken)):(console.error("🔐 LOGIN-UI: Authentication failed:",n.error),this.showError(n.error||"Authentication failed. Please try again."))}catch(t){console.error("🔐 LOGIN-UI: Authentication error:",t),this.setLoadingState(e,!1),this.showError(`Authentication error: ${t.message||"Unknown error occurred"}`)}}else this.showError(`${this.getProviderById(e).name} authentication is not yet implemented.`)}setLoadingState(e,t){const n=this.container.querySelector(`button[data-provider="${e}"]`);if(n)if(t){n.disabled=!0,n.style.opacity="0.6",n.style.cursor="not-allowed";const t=n.querySelector("div > div:first-child");t&&(t.textContent=`Connecting to ${this.getProviderById(e).name}...`)}else{n.disabled=!1,n.style.opacity="1",n.style.cursor="pointer";const t=n.querySelector("div > div:first-child");t&&(t.textContent=this.getProviderById(e).name)}}showError(e){const t=this.container.querySelector(".escobar-login-error");t&&t.remove();const n=document.createElement("div");n.className="escobar-login-error",n.textContent=e,n.style.cssText="\n background: var(--jp-error-color3);\n color: var(--jp-error-color1);\n border: 1px solid var(--jp-error-color1);\n border-radius: 4px;\n padding: 12px;\n margin: 16px 24px;\n font-size: 13px;\n line-height: 1.4;\n ";const o=this.container.querySelector("div:last-child");o&&this.container.insertBefore(n,o),setTimeout((()=>{n.parentNode&&n.parentNode.removeChild(n)}),5e3)}getProviderById(e){return this.authProviders.find((t=>t.id===e))||this.authProviders[0]}show(){document.body.appendChild(this.overlay),requestAnimationFrame((()=>{this.overlay.style.opacity="1",this.container.style.transform="scale(1)"}))}hide(){this.overlay.style.opacity="0",this.container.style.transform="scale(0.9)",setTimeout((()=>{this.overlay.parentNode&&this.overlay.parentNode.removeChild(this.overlay)}),300)}}function G(){return new Promise(((e,t)=>{new j((t=>{e(t)}),(()=>{t(new Error("Authentication cancelled"))})).show()}))}const z="0.1.99";function W(){const e=window.location.pathname.match(/\/user\/([^\/]+)\//);if(e&&e[1])return!0;try{const e=document.getElementById("jupyter-config-data");if(e&&e.textContent){const t=JSON.parse(e.textContent);if(t.hubUser||t.hubUsername||t.user)return!0}}catch(e){console.error("Error parsing JupyterHub config:",e)}try{const e=document.baseURI.match(/\/user\/([^\/]+)\//);if(e&&e[1])return!0}catch(e){console.error("Error checking baseURI:",e)}try{const e=document.cookie.split(";");for(const t of e){const[e,n]=t.trim().split("=");if("jupyterhub-user"===e)return!0}}catch(e){console.error("Error checking cookies:",e)}const t=window.location.pathname.match(/\/user\/([^\/]*)\//);return!(!t||!t[1])}class q{constructor(e,t,n){this.settingsRegistry=e,this.currentSettings=t,this.onSave=n,this.overlay=document.createElement("div"),this.overlay.className="escobar-settings-overlay",this.overlay.addEventListener("click",(e=>{e.target===this.overlay&&this.hide()})),this.container=this.createContainer(),this.overlay.appendChild(this.container)}createHeader(e){const t=document.createElement("div");t.className="escobar-settings-header";const n=document.createElement("h2");n.textContent=e,t.appendChild(n);const o=document.createElement("button");return o.className="escobar-settings-close-button",o.innerHTML="&times;",o.addEventListener("click",(()=>this.hide())),t.appendChild(o),t}createFormGroup(e,t,n){const o=document.createElement("div");o.className="escobar-settings-group";const r=document.createElement("label");r.textContent=t,r.htmlFor=e,o.appendChild(r);const i=document.createElement("div");return i.className="escobar-settings-description",i.textContent=n,o.appendChild(i),o}createModelDropdown(e,t,n,o){const r=this.createFormGroup(e,t,n),i=document.createElement("select");if(i.id=e,i.className="escobar-settings-input",i._savedValue=o,o){const e=document.createElement("option");e.value=o,e.textContent=`${o} (Loading models...)`,e.selected=!0,i.appendChild(e)}else{const e=document.createElement("option");e.value="undefined",e.textContent="Loading models...",e.selected=!0,i.appendChild(e)}const s=e=>{const t=i._savedValue;if(i.innerHTML="",e.length>0)if(e.forEach((e=>{const t=document.createElement("option");t.value=e.model,t.textContent=e.model,i.appendChild(t)})),t){if(i.value=t,i.value!==t){const e=document.createElement("option");e.value=t,e.textContent=`${t} (Custom)`,i.insertBefore(e,i.firstChild),i.value=t}}else i.value=e[0].model;else{const e=document.createElement("option");e.value="undefined",e.textContent="No models available",e.selected=!0,i.appendChild(e)}},a=window.escobarAvailableModels||[];a.length>0&&s(a);const c=e=>{s(e.detail.models)};return window.addEventListener("escobar-models-updated",c),i._modelUpdateCleanup=()=>{window.removeEventListener("escobar-models-updated",c)},r.appendChild(i),r}createButtonsContainer(){const e=document.createElement("div");e.className="escobar-settings-buttons";const t=document.createElement("button");t.className="escobar-settings-button escobar-settings-cancel-button",t.textContent="Cancel",t.type="button",t.addEventListener("click",(()=>this.hide())),e.appendChild(t);const n=document.createElement("button");return n.className="escobar-settings-button escobar-settings-save-button",n.textContent="Save",n.type="submit",e.appendChild(n),e}show(){console.log("🔧 SETTINGS: Opening settings page, loading latest settings..."),this.loadCompleteSettings().then((e=>{console.log("🔧 SETTINGS: Complete settings loaded successfully"),this.currentSettings=e,document.body.appendChild(this.overlay),this.updateFormFields(),setTimeout((()=>{this.overlay.classList.add("escobar-settings-overlay-visible"),this.container.classList.add("escobar-settings-container-visible")}),10)})).catch((e=>{console.error("🔧 SETTINGS: Failed to load complete settings:",e),console.log("🔧 SETTINGS: Using fallback settings"),document.body.appendChild(this.overlay),this.updateFormFields(),setTimeout((()=>{this.overlay.classList.add("escobar-settings-overlay-visible"),this.container.classList.add("escobar-settings-container-visible")}),10)}))}async loadCompleteSettings(){console.log("🔧 SETTINGS: Loading local settings from registry");let e={};try{const t=(await this.settingsRegistry.load("escobar:plugin")).composite;e={serverUrl:t.serverUrl||this.currentSettings.serverUrl,username:t.username||this.currentSettings.username,usernameFromJupyterHub:t.usernameFromJupyterHub||this.currentSettings.usernameFromJupyterHub,bonnieUrl:t.bonnieUrl||this.currentSettings.bonnieUrl},console.log("🔧 SETTINGS: Local settings loaded from registry")}catch(t){console.error("🔧 SETTINGS: Failed to load from registry:",t),e={serverUrl:this.currentSettings.serverUrl,username:this.currentSettings.username,usernameFromJupyterHub:this.currentSettings.usernameFromJupyterHub}}let t={};try{console.log("🔧 SETTINGS: Loading remote settings from server");const e=window.escobarMessageHandler;if(e){console.log("📤 PROTOCOL: Sending retrieveSettings request");const n=await e.retrieveSettingsFromServer();console.log("📥 PROTOCOL: Received retrieveSettings response"),t={maxMessages:n.maxMessages||this.currentSettings.maxMessages,voittaApiKey:n.voittaApiKey||"",openaiApiKey:n.openaiApiKey||"",anthropicApiKey:n.anthropicApiKey||"",geminiApiKey:n.geminiApiKey||"",proxyPort:n.proxyPort||3e3,primaryModel:n.primaryModel,secondaryProvider:n.secondaryProvider,imageParseProvider:n.imageParseProvider},console.log("🔧 SETTINGS: Remote settings loaded successfully")}else console.warn("🔧 SETTINGS: MessageHandler not available, using defaults for remote settings"),t={maxMessages:this.currentSettings.maxMessages,voittaApiKey:this.currentSettings.voittaApiKey||"",openaiApiKey:this.currentSettings.openaiApiKey||"",anthropicApiKey:this.currentSettings.anthropicApiKey||"",geminiApiKey:this.currentSettings.geminiApiKey||"",proxyPort:this.currentSettings.proxyPort||3e3,primaryModel:this.currentSettings.primaryModel,secondaryProvider:this.currentSettings.secondaryProvider,imageParseProvider:this.currentSettings.imageParseProvider}}catch(e){console.error("🔧 SETTINGS: Failed to load remote settings from server:",e),t={maxMessages:this.currentSettings.maxMessages,voittaApiKey:this.currentSettings.voittaApiKey||"",openaiApiKey:this.currentSettings.openaiApiKey||"",anthropicApiKey:this.currentSettings.anthropicApiKey||"",geminiApiKey:this.currentSettings.geminiApiKey||"",proxyPort:this.currentSettings.proxyPort||3e3,primaryModel:this.currentSettings.primaryModel,secondaryProvider:this.currentSettings.secondaryProvider,imageParseProvider:this.currentSettings.imageParseProvider}}const n={serverUrl:e.serverUrl,username:e.username,usernameFromJupyterHub:e.usernameFromJupyterHub,bonnieUrl:e.bonnieUrl,maxMessages:t.maxMessages,voittaApiKey:t.voittaApiKey,openaiApiKey:t.openaiApiKey,anthropicApiKey:t.anthropicApiKey,geminiApiKey:t.geminiApiKey,proxyPort:t.proxyPort,primaryModel:t.primaryModel,secondaryProvider:t.secondaryProvider,imageParseProvider:t.imageParseProvider};return console.log("🔧 SETTINGS: Settings merged successfully"),n}hide(){this.overlay.classList.remove("escobar-settings-overlay-visible"),this.container.classList.remove("escobar-settings-container-visible"),setTimeout((()=>{this.overlay.parentNode&&this.overlay.parentNode.removeChild(this.overlay)}),300)}validateAndSaveCommonSettings(e){if(!e.voittaApiKey&&!e.openaiApiKey&&!e.anthropicApiKey)return alert("At least one API Key is required"),!1;const t=document.getElementById("escobar-gemini-api-key"),n=t?t.value.trim():this.currentSettings.geminiApiKey||"",o=document.getElementById("escobar-primary-model"),r=document.getElementById("escobar-secondary-provider"),i=document.getElementById("escobar-image-parse-provider"),s=o?o.value:"undefined",a=r?r.value:"undefined",c=i?i.value:"undefined",l={maxMessages:this.currentSettings.maxMessages,serverUrl:this.currentSettings.serverUrl,username:this.currentSettings.username,usernameFromJupyterHub:this.currentSettings.usernameFromJupyterHub,voittaApiKey:e.voittaApiKey,openaiApiKey:e.openaiApiKey,anthropicApiKey:e.anthropicApiKey,geminiApiKey:n,proxyPort:e.proxyPort||3e3,primaryModel:s,secondaryProvider:a,imageParseProvider:c};return this.currentSettings=l,window.escobarCurrentSettings=l,this.saveSettingsToServerOnly(l),!0}async saveSettingsToServerOnly(e){console.log("🔧 SETTINGS: Saving remote settings to server only");try{const t=window.escobarMessageHandler;if(!t)throw new Error("Message handler not available - cannot save settings to server");console.log("📤 PROTOCOL: Sending saveSettings request to server"),await t.saveSettingsToServer({maxMessages:e.maxMessages,voittaApiKey:e.voittaApiKey,openaiApiKey:e.openaiApiKey,anthropicApiKey:e.anthropicApiKey,geminiApiKey:e.geminiApiKey,proxyPort:e.proxyPort,primaryModel:e.primaryModel,secondaryProvider:e.secondaryProvider,imageParseProvider:e.imageParseProvider}),console.log("✅ SETTINGS: Remote settings saved to server successfully"),this.hide()}catch(e){console.error("❌ SETTINGS: Failed to save settings to server:",e);const t=e instanceof Error?e.message:"Unknown error occurred";alert(`Failed to save settings to server:\n\n${t}\n\nPlease check your connection and try again.`)}}}class V extends q{createContainer(){const e=document.createElement("div");e.className="escobar-settings-container";const t=this.createHeader("Settings");e.appendChild(t);const n=document.createElement("div");n.className="escobar-mode-indicator",n.innerHTML=`Running in JupyterHub Mode <span style="font-size: 0.8em; opacity: 0.8;">v${z}</span>`,n.style.backgroundColor="#f0f7ff",n.style.color="#0366d6",n.style.padding="8px 16px",n.style.margin="0 16px 16px 16px",n.style.borderRadius="4px",n.style.fontWeight="bold",n.style.textAlign="center",n.style.border="1px solid #c8e1ff",e.appendChild(n);const o=document.createElement("form");o.className="escobar-settings-form",o.addEventListener("submit",(e=>{e.preventDefault(),this.saveSettings()}));const r=this.createFormGroup("escobar-voitta-api-key","Voitta API Key","The API key for authentication with Voitta services. (Optional)"),i=document.createElement("input");i.id="escobar-voitta-api-key",i.className="escobar-settings-input",i.type="text",i.value=this.currentSettings.voittaApiKey||"",r.appendChild(i);const s=document.createElement("a");s.href="#",s.className="escobar-get-api-key-link",s.textContent="Get Voitta API Key",s.style.display=this.currentSettings.voittaApiKey?"none":"block",s.addEventListener("click",(e=>{e.preventDefault(),G().then((e=>{i.value=e,s.style.display="none",alert("Successfully obtained Voitta API key!")})).catch((e=>{"Authentication cancelled"!==e.message&&(console.error("Authentication error:",e),alert("Failed to authenticate. Please try again."))}))})),r.appendChild(s),i.addEventListener("input",(()=>{s.style.display=i.value?"none":"block"})),o.appendChild(r);const a=this.createFormGroup("escobar-openai-api-key","OpenAI API Key","Your OpenAI API key for OpenAI-powered features. (Optional)"),c=document.createElement("input");c.id="escobar-openai-api-key",c.className="escobar-settings-input",c.type="text",c.value=this.currentSettings.openaiApiKey||"",a.appendChild(c),o.appendChild(a);const l=this.createFormGroup("escobar-anthropic-api-key","Anthropic API Key","Your Anthropic API key for Claude-powered features. (Optional)"),d=document.createElement("input");d.id="escobar-anthropic-api-key",d.className="escobar-settings-input",d.type="text",d.value=this.currentSettings.anthropicApiKey||"",l.appendChild(d),o.appendChild(l);const u=this.createFormGroup("escobar-gemini-api-key","Gemini API Key","Your Google Gemini API key for Gemini-powered features. (Optional)"),p=document.createElement("input");p.id="escobar-gemini-api-key",p.className="escobar-settings-input",p.type="text",p.value=this.currentSettings.geminiApiKey||"",u.appendChild(p),o.appendChild(u);const g=document.createElement("div");g.id="primary-model-container",g.className="escobar-settings-group",o.appendChild(g);const m=document.createElement("div");m.id="secondary-provider-container",m.className="escobar-settings-group",o.appendChild(m);const h=document.createElement("div");h.id="image-parse-provider-container",h.className="escobar-settings-group",o.appendChild(h);const y=this.createFormGroup("escobar-proxy-port","Proxy Port","The port number for the proxy server."),f=document.createElement("input");f.id="escobar-proxy-port",f.className="escobar-settings-input",f.type="number",f.min="1",f.max="65535",f.value=(this.currentSettings.proxyPort||3e3).toString(),y.appendChild(f),o.appendChild(y);const v=this.createButtonsContainer();return o.appendChild(v),e.appendChild(o),e}updateFormFields(){const e=document.getElementById("escobar-max-messages"),t=document.getElementById("escobar-server-url"),n=document.getElementById("escobar-voitta-api-key"),o=document.getElementById("escobar-openai-api-key"),r=document.getElementById("escobar-anthropic-api-key"),i=document.getElementById("escobar-gemini-api-key"),s=document.getElementById("escobar-username"),a=document.getElementById("escobar-proxy-port");e&&(e.value=this.currentSettings.maxMessages.toString()),t&&(t.value=this.currentSettings.serverUrl),n&&(n.value=this.currentSettings.voittaApiKey||""),o&&(o.value=this.currentSettings.openaiApiKey||""),r&&(r.value=this.currentSettings.anthropicApiKey||""),i&&(i.value=this.currentSettings.geminiApiKey||""),s&&(s.value=this.currentSettings.username),a&&(a.value=(this.currentSettings.proxyPort||3e3).toString());const c=document.getElementById("primary-model-container"),l=document.getElementById("secondary-provider-container"),d=document.getElementById("image-parse-provider-container");if(c){c.innerHTML="";const e=this.createModelDropdown("escobar-primary-model","Primary Model","The main AI model used for chat responses.",this.currentSettings.primaryModel);c.appendChild(e)}if(l){l.innerHTML="";const e=this.createModelDropdown("escobar-secondary-provider","Secondary Provider","Secondary AI model for specialized tasks.",this.currentSettings.secondaryProvider);l.appendChild(e)}if(d){d.innerHTML="";const e=this.createModelDropdown("escobar-image-parse-provider","Image Parse Provider","AI model used for image analysis and parsing.",this.currentSettings.imageParseProvider);d.appendChild(e)}}saveSettings(){const e=document.getElementById("escobar-voitta-api-key"),t=document.getElementById("escobar-openai-api-key"),n=document.getElementById("escobar-anthropic-api-key"),o=document.getElementById("escobar-proxy-port");this.validateAndSaveCommonSettings({voittaApiKey:e.value.trim(),openaiApiKey:t.value.trim(),anthropicApiKey:n.value.trim(),proxyPort:o?parseInt(o.value,10):3e3})}}class Y extends q{createContainer(){const e=document.createElement("div");e.className="escobar-settings-container",e.style.maxWidth="400px";const t=this.createHeader("Connection Settings");e.appendChild(t);const n=document.createElement("div");n.className="escobar-mode-indicator",n.innerHTML=`Connection Parameters <span style="font-size: 0.8em; opacity: 0.8;">v${z}</span>`,n.style.backgroundColor="#e8f5e8",n.style.color="#2d5a2d",n.style.padding="8px 16px",n.style.margin="0 16px 16px 16px",n.style.borderRadius="4px",n.style.fontWeight="bold",n.style.textAlign="center",n.style.border="1px solid #a8d8a8",e.appendChild(n);const o=document.createElement("form");o.className="escobar-settings-form",o.addEventListener("submit",(e=>{e.preventDefault(),this.saveSettings()}));const r=this.createFormGroup("escobar-connection-server-url","Server URL","The WebSocket server URL. Changing this will trigger a reconnection."),i=document.createElement("input");i.id="escobar-connection-server-url",i.className="escobar-settings-input",i.type="text",i.value=this.currentSettings.serverUrl,r.appendChild(i),o.appendChild(r);const s=W(),a=this.createFormGroup("escobar-connection-username","Username",s?"Username extracted from JupyterHub (read-only).":"Your display name for chat messages."),c=document.createElement("input");if(c.id="escobar-connection-username",c.className="escobar-settings-input",c.type="text",c.value=this.currentSettings.username,s){c.disabled=!0,c.style.opacity="0.7",c.style.cursor="not-allowed";const e=document.createElement("div");e.className="escobar-settings-note",e.style.fontSize="0.85em",e.style.fontStyle="italic",e.style.marginTop="5px",e.style.color="#666",e.textContent="Username is extracted from JupyterHub URL and cannot be changed.",a.appendChild(e)}a.appendChild(c),o.appendChild(a);const l=this.createFormGroup("escobar-connection-bonnie-url","Bonnie URL","The WebSocket URL for the Bonnie backend server. If specified, this overrides the WEBSOCKET_PROXY_TARGET environment variable. (Optional)"),d=document.createElement("input");d.id="escobar-connection-bonnie-url",d.className="escobar-settings-input",d.type="text",d.placeholder="ws://bonnie:8777/ws",d.value=this.currentSettings.bonnieUrl||"",l.appendChild(d);const u=document.createElement("div");u.className="escobar-settings-note",u.style.fontSize="0.85em",u.style.fontStyle="italic",u.style.marginTop="5px",u.style.color="#666",u.innerHTML="Examples: <code>ws://localhost:8777/ws</code>, <code>wss://api.example.com/ws</code>",l.appendChild(u),o.appendChild(l);const p=document.createElement("div");p.style.cssText="\n background: #fff3cd;\n color: #856404;\n border: 1px solid #ffeaa7;\n border-radius: 4px;\n padding: 12px;\n margin: 16px;\n font-size: 14px;\n ",p.innerHTML="\n <strong>⚠️ Connection Settings</strong><br>\n Saving these settings will trigger a WebSocket reconnection. \n Any ongoing chat operations will be interrupted.\n ",o.appendChild(p);const g=this.createButtonsContainer();return o.appendChild(g),e.appendChild(o),e}updateFormFields(){const e=document.getElementById("escobar-connection-server-url"),t=document.getElementById("escobar-connection-username"),n=document.getElementById("escobar-connection-bonnie-url");e&&(e.value=this.currentSettings.serverUrl),t&&(t.value=this.currentSettings.username),n&&(n.value=this.currentSettings.bonnieUrl||"")}saveSettings(){const e=document.getElementById("escobar-connection-server-url"),t=document.getElementById("escobar-connection-username"),n=document.getElementById("escobar-connection-bonnie-url"),o=e.value.trim(),r=t.value.trim(),i=n.value.trim();if(!o)return void alert("Server URL is required");if(!r)return void alert("Username is required");if(i&&i.length>0)try{const e=new URL(i);if(!["ws:","wss:"].includes(e.protocol))return void alert("Bonnie URL must use ws:// or wss:// protocol")}catch(e){return void alert("Invalid Bonnie URL format. Please enter a valid WebSocket URL.")}const s={...this.currentSettings,serverUrl:o,username:r,bonnieUrl:i||void 0};console.log("🔗 CONNECTION: Saving connection settings"),this.saveConnectionSettings(s)}async saveConnectionSettings(e){try{const t=await this.settingsRegistry.load("escobar:plugin");console.log("🔗 CONNECTION: Saving to registry (will trigger reconnection)"),await t.set("serverUrl",e.serverUrl),await t.set("username",e.username),await t.set("usernameFromJupyterHub",e.usernameFromJupyterHub),await t.set("bonnieUrl",e.bonnieUrl||""),console.log("🔗 CONNECTION: Registry save successful"),this.currentSettings=e,window.escobarCurrentSettings=e,this.onSave(e),console.log("🔗 CONNECTION: Connection settings save completed"),this.hide()}catch(e){console.error("🔗 CONNECTION: Failed to save connection settings:",e),alert(`Failed to save connection settings:\n\n${e instanceof Error?e.message:"Unknown error"}\n\nPlease try again.`)}}}class X extends q{createContainer(){const e=document.createElement("div");e.className="escobar-settings-container";const t=this.createHeader("Settings");e.appendChild(t);const n=document.createElement("div");n.className="escobar-mode-indicator",n.innerHTML=`Running in Plugin Mode <span style="font-size: 0.8em; opacity: 0.8;">v${z}</span>`,n.style.backgroundColor="#f6f8fa",n.style.color="#24292e",n.style.padding="8px 16px",n.style.margin="0 16px 16px 16px",n.style.borderRadius="4px",n.style.fontWeight="bold",n.style.textAlign="center",n.style.border="1px solid #e1e4e8",e.appendChild(n);const o=document.createElement("form");o.className="escobar-settings-form",o.addEventListener("submit",(e=>{e.preventDefault(),this.saveSettings()}));const r=this.createFormGroup("escobar-voitta-api-key","Voitta API Key","The API key for authentication with Voitta services. (Optional)"),i=document.createElement("input");i.id="escobar-voitta-api-key",i.className="escobar-settings-input",i.type="text",i.value=this.currentSettings.voittaApiKey||"",r.appendChild(i);const s=document.createElement("a");s.href="#",s.className="escobar-get-api-key-link",s.textContent="Get Voitta API Key",s.style.display=this.currentSettings.voittaApiKey?"none":"block",s.addEventListener("click",(e=>{e.preventDefault(),G().then((e=>{i.value=e,s.style.display="none",alert("Successfully obtained Voitta API key!")})).catch((e=>{"Authentication cancelled"!==e.message&&(console.error("Authentication error:",e),alert("Failed to authenticate. Please try again."))}))})),r.appendChild(s),i.addEventListener("input",(()=>{s.style.display=i.value?"none":"block"})),o.appendChild(r);const a=this.createFormGroup("escobar-openai-api-key","OpenAI API Key","Your OpenAI API key for OpenAI-powered features. (Optional)"),c=document.createElement("input");c.id="escobar-openai-api-key",c.className="escobar-settings-input",c.type="text",c.value=this.currentSettings.openaiApiKey||"",a.appendChild(c),o.appendChild(a);const l=this.createFormGroup("escobar-anthropic-api-key","Anthropic API Key","Your Anthropic API key for Claude-powered features. (Optional)"),d=document.createElement("input");d.id="escobar-anthropic-api-key",d.className="escobar-settings-input",d.type="text",d.value=this.currentSettings.anthropicApiKey||"",l.appendChild(d),o.appendChild(l);const u=this.createFormGroup("escobar-gemini-api-key","Gemini API Key","Your Google Gemini API key for Gemini-powered features. (Optional)"),p=document.createElement("input");p.id="escobar-gemini-api-key",p.className="escobar-settings-input",p.type="text",p.value=this.currentSettings.geminiApiKey||"",u.appendChild(p),o.appendChild(u);const g=document.createElement("div");g.id="primary-model-container",g.className="escobar-settings-group",o.appendChild(g);const m=document.createElement("div");m.id="secondary-provider-container",m.className="escobar-settings-group",o.appendChild(m);const h=document.createElement("div");h.id="image-parse-provider-container",h.className="escobar-settings-group",o.appendChild(h);const y=this.createFormGroup("escobar-proxy-port","Proxy Port","The port number for the proxy server."),f=document.createElement("input");f.id="escobar-proxy-port",f.className="escobar-settings-input",f.type="number",f.min="1",f.max="65535",f.value=(this.currentSettings.proxyPort||3e3).toString(),y.appendChild(f),o.appendChild(y);const v=this.createButtonsContainer();return o.appendChild(v),e.appendChild(o),e}updateFormFields(){const e=document.getElementById("escobar-max-messages"),t=document.getElementById("escobar-server-url"),n=document.getElementById("escobar-voitta-api-key"),o=document.getElementById("escobar-openai-api-key"),r=document.getElementById("escobar-anthropic-api-key"),i=document.getElementById("escobar-gemini-api-key"),s=document.getElementById("escobar-username"),a=document.getElementById("escobar-proxy-port");document.getElementById("escobar-primary-model"),document.getElementById("escobar-secondary-provider"),document.getElementById("escobar-image-parse-provider"),e&&(e.value=this.currentSettings.maxMessages.toString()),t&&(t.value=this.currentSettings.serverUrl),n&&(n.value=this.currentSettings.voittaApiKey||""),o&&(o.value=this.currentSettings.openaiApiKey||""),r&&(r.value=this.currentSettings.anthropicApiKey||""),i&&(i.value=this.currentSettings.geminiApiKey||""),s&&(s.value=this.currentSettings.username),a&&(a.value=(this.currentSettings.proxyPort||3e3).toString());const c=document.getElementById("primary-model-container"),l=document.getElementById("secondary-provider-container"),d=document.getElementById("image-parse-provider-container");if(c){c.innerHTML="";const e=this.createModelDropdown("escobar-primary-model","Primary Model","The main AI model used for chat responses.",this.currentSettings.primaryModel);c.appendChild(e)}if(l){l.innerHTML="";const e=this.createModelDropdown("escobar-secondary-provider","Secondary Provider",`Current value: ${this.currentSettings.secondaryProvider||"Not set"}`,this.currentSettings.secondaryProvider);l.appendChild(e)}if(d){d.innerHTML="";const e=this.createModelDropdown("escobar-image-parse-provider","Image Parse Provider","AI model used for image analysis and parsing.",this.currentSettings.imageParseProvider);d.appendChild(e)}}saveSettings(){const e=document.getElementById("escobar-voitta-api-key"),t=document.getElementById("escobar-openai-api-key"),n=document.getElementById("escobar-anthropic-api-key"),o=document.getElementById("escobar-proxy-port");this.validateAndSaveCommonSettings({voittaApiKey:e.value.trim(),openaiApiKey:t.value.trim(),anthropicApiKey:n.value.trim(),proxyPort:o?parseInt(o.value,10):3e3})}}var Q=n(2235);function Z(e,t,n,o){const r=document.createElement("button");r.className=`escobar-icon-button ${e}`,r.title=o,r.style.cssText=t;const i=document.createElement("span");return i.className="escobar-icon-container",i.innerHTML=n,r.appendChild(i),r}var ee=n(9650),te=n.n(ee),ne=n(5271),oe=n.n(ne),re=n(1731),ie=n.n(re),se=n(6954),ae=n.n(se);const ce=new(te())({html:!0,breaks:!0,linkify:!0,typographer:!0,highlight:function(e,t){if(t&&oe().getLanguage(t))try{return oe().highlight(e,{language:t,ignoreIllegals:!0}).value}catch(e){}return""}});ce.enable("emphasis"),ce.enable("link"),ce.enable("heading"),ce.enable("code"),ce.enable("fence"),ce.enable("blockquote"),ce.enable("list"),ce.enable("table"),ce.enable("image"),ce.enable("strikethrough"),ce.use(ie()),ce.use(ae()),ce.use((function(e){const t=e.renderer.rules.fence.bind(e.renderer.rules);e.renderer.rules.fence=(e,n,o,r,i)=>{const s=e[n];if("question"===s.info.trim()){const e=s.content.trim().split("\n"),t=e[0],n=e.slice(1).filter((e=>e.trim()));let o='<div class="escobar-question-block">';return o+=`<div class="escobar-question">${t}</div>`,o+='<div class="escobar-question-options">',n.forEach(((e,t)=>{const n=e.replace(/'/g,"\\'");o+=`<button class="escobar-question-option" data-option="${t}" \n onclick="(function() {\n // Find the chat input textarea\n const chatInput = document.querySelector('.escobar-chat-input');\n if (chatInput) {\n // Set the textarea value to the button text\n chatInput.value = '${n}';\n \n // Find and click the send button\n const sendButton = document.querySelector('.jp-Button.escobar-send-button');\n if (sendButton) {\n sendButton.click();\n } else {\n // Fallback to any button that might be the send button\n const buttons = document.querySelectorAll('button');\n for (const btn of buttons) {\n if (btn.textContent && ['Send', 'Talk', 'Plan', 'Act'].includes(btn.textContent.trim())) {\n btn.click();\n break;\n }\n }\n }\n }\n })();">${e}</button>`})),o+="</div></div>",o}return t(e,n,o,r,i)}}));const le=ce.renderer.rules.table_open||function(e,t,n,o,r){return r.renderToken(e,t,n)};ce.renderer.rules.table_open=function(e,t,n,o,r){return'<div class="table-wrapper">'+le(e,t,n,o,r)};const de=ce.renderer.rules.table_close||function(e,t,n,o,r){return r.renderToken(e,t,n)};ce.renderer.rules.table_close=function(e,t,n,o,r){return de(e,t,n,o,r)+"</div>"};const ue=ce.renderer.rules.image||function(e,t,n,o,r){return r.renderToken(e,t,n)};ce.renderer.rules.image=function(e,t,n,o,r){const i=e[t],s=i.attrIndex("src");return s>=0&&i.attrs[s][1],i.attrIndex("loading")<0&&i.attrPush(["loading","lazy"]),i.attrIndex("onerror")<0&&i.attrPush(["onerror","this.onerror=null;this.style.border='1px solid #ddd';this.style.padding='10px';this.style.width='auto';this.style.height='auto';this.alt='Image failed to load: ' + this.alt;this.src='data:image/svg+xml,%3Csvg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"%3E%3Cpath fill=\"%23ccc\" d=\"M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z\"/%3E%3C/svg%3E';"]),ue(e,t,n,o,r)};class pe{constructor(e,t,n=""){this.id=e,this.role=t,this.isNew=!0,this.content=n,this.rawContent=n,this.messageElement=document.createElement("div"),this.messageElement.className=`escobar-message escobar-message-${t}`,this.messageElement.dataset.messageId=e,this.contentElement=document.createElement("div"),this.contentElement.className="escobar-message-content markdown-content","assistant"!==t&&"action"!==t||!n?this.contentElement.textContent=n:this.contentElement.innerHTML=ce.render(n),this.messageElement.appendChild(this.contentElement)}setContent(e){this.content=e,this.rawContent=e,"assistant"===this.role||"action"===this.role?this.contentElement.innerHTML=ce.render(e):this.contentElement.textContent=e;const t=this.messageElement.closest(".escobar-chat-container");t&&setTimeout((()=>{t.scrollTop=t.scrollHeight}),0)}getRawContent(){return this.rawContent}getContent(){return this.content}getElement(){return this.messageElement}}class ge{constructor(e,t,n,o,r,i,s,a=100){this.messages=[],this.messageMap=new Map,this.currentChatID="temp-session",this.voittaApiKey=e,this.openaiApiKey=t,this.anthropicApiKey=n,this.geminiApiKey=o,this.selectedProvider=r,this.username=i,this.chatContainer=s,this.maxMessages=a}updateSettings(e,t,n,o,r,i,s){this.voittaApiKey=e,this.openaiApiKey=t,this.anthropicApiKey=n,this.geminiApiKey=o,this.selectedProvider=r,this.username=i,this.maxMessages=s}setCurrentChatID(e){this.currentChatID=e}getCurrentChatID(){return this.currentChatID}generateMessageId(e=""){return`${e}-msg-${Date.now()}-${ge.messageCounter++}`}findMessageById(e){return this.messageMap.get(e)}addMessage(e,t,n){const o=n||this.generateMessageId(),r=new pe(o,e,t);return this.messages.push(r),this.messageMap.set(o,r),this.chatContainer.appendChild(r.getElement()),this.chatContainer.scrollTop=this.chatContainer.scrollHeight,this.limitMessages(),r}limitMessages(){if(this.messages.length>this.maxMessages){const e=this.messages.length-this.maxMessages,t=this.messages.splice(0,e);for(const e of t)this.chatContainer.removeChild(e.getElement()),this.messageMap.delete(e.id)}}async clearMessages(){const e=[...this.messages];this.messages=[];for(const t of e)try{this.chatContainer.contains(t.getElement())&&this.chatContainer.removeChild(t.getElement()),this.messageMap.delete(t.id)}catch(e){console.error("Error removing message:",e)}this.messageMap.clear()}async loadMessages(){const e=this.generateMessageId(),t={method:"loadMessages",username:this.username,chatID:this.currentChatID,call_id:e,message_type:"request"};try{const e=await(0,u.callPython)(t);if(!e.value||!Array.isArray(e.value))return void console.warn("Invalid response format for loadMessages:",e);for(let t=0;t<e.value.length;t++){const n=e.value[t];switch(n.role){case"user":("string"==typeof n.content||n.content instanceof String)&&this.addMessage("user",n.content);break;case"assistant":if("string"==typeof n.content||n.content instanceof String)this.addMessage("assistant",String(n.content));else if(n.content&&Array.isArray(n.content))for(let e=0;e<n.content.length;e++){const t=n.content[e];"tool_use"===t.type&&t.name?this.addMessage("action",`🔧 ${t.name}`):"text"===t.type&&t.text&&this.addMessage("assistant",t.text)}}}}catch(e){throw console.error("Error loading messages:",e),e}}async createNewChat(e){var t;await this.clearMessages();let n="openai";if(e)switch(e.toLowerCase()){case"openai":n="openai";break;case"anthropic":n="anthropic";break;case"gemini":n="gemini";break;default:console.warn(`Unknown provider: ${e}, defaulting to openai`),n="openai"}const o=this.generateMessageId(),r={method:"createNewChat",username:this.username,call_id:o,message_type:"request",provider:n,api_key:"--key--",openai_api_key:"--key--",anthropic_api_key:"--key--",gemini_api_key:"--key--"};console.log("Sending createNewChat request:",r);const i=await(0,u.callPython)(r);if(console.log("Received createNewChat response:",i),"error_type"in i||"string"==typeof i.value&&!i.value.includes("chatID")){const e=i,t=e.value||"Unknown error occurred while creating chat";throw console.error("Error creating new chat:",e),new Error(`Failed to create new chat: ${t}`)}const s=null===(t=i.value)||void 0===t?void 0:t.chatID;if(!s)throw console.error("Invalid server response for createNewChat:",i),new Error(`Server did not return a valid chatID. Response: ${JSON.stringify(i)}`);return console.log("Successfully created new chat with ID:",s),this.currentChatID=s,s}async sendMessage(e,t,n){if("temp-session"===this.currentChatID){const e=this.generateMessageId();this.addMessage("assistant","💡 **Starting a new chat session** - Your conversation will be saved automatically.",e);const t=await this.createNewChat();this.onChatCreated&&this.onChatCreated(t)}const o=this.generateMessageId(),r=this.generateMessageId(),i=await async function(){const e=O.shell.widgets("main"),t=(O.shell.currentWidget,[]);return Array.from(e).forEach((e=>{var n,o,r,i,s,a;let c={id:e.id,title:e.title.label||"Untitled",type:"unknown",isVisible:!1};e instanceof p.NotebookPanel?(c.type="notebook",c.path=(null===(n=e.context)||void 0===n?void 0:n.path)||""):e instanceof m.FileEditor||(null===(r=null===(o=e.context)||void 0===o?void 0:o.path)||void 0===r?void 0:r.includes("."))?(c.type="file",c.path=(null===(i=e.context)||void 0===i?void 0:i.path)||""):(e.id.startsWith("terminal")||(null===(a=null===(s=e.title)||void 0===s?void 0:s.label)||void 0===a?void 0:a.toLowerCase().includes("terminal")))&&(c.type="terminal",c.name=e.title.label.replace("Terminal ","")||""),c.isVisible=e.isVisible,t.push(c)})),t}(),s=await $.listCells.func();this.addMessage("user",e,o);const a=this.addMessage("assistant","Waiting for response...",r),c=(0,u.mt)();var l=!1;if(c&&c.readyState===WebSocket.OPEN)try{const n=window.escobarCurrentSettings,o=(null==n?void 0:n.primaryModel)||"undefined",c=(null==n?void 0:n.secondaryProvider)||"undefined",l=(null==n?void 0:n.imageParseProvider)||"undefined",d={method:"userMessage",username:this.username,chatID:this.currentChatID,call_id:r,message_type:"request",user_message:e,opened_tabs:i,current_notebook:s,mode:t,api_key:this.voittaApiKey,openai_api_key:this.openaiApiKey,anthropic_api_key:this.anthropicApiKey,gemini_api_key:this.geminiApiKey,selected_provider:o,secondary_provider:c,image_parse_provider:l},p=await(0,u.callPython)(d,36e5,!0,!0);this.handlePythonResponse(p,a)}catch(e){null!=e.stop?(l=!0,u.Tg[r]=!0,a.setContent("Interrupted by the user")):a.setContent("Error sending message to server")}else setTimeout((()=>{a.setContent(`Echo: ${e} (WebSocket not connected)`)}),500);if(l){const e={method:"userStop",username:this.username,chatID:this.currentChatID,call_id:r,message_type:"request"};await(0,u.callPython)(e,0,!1)}return a}handlePythonResponse(e,t){try{let o;var n=e.value;o="string"==typeof n?n:n&&"object"==typeof n?JSON.stringify(n):"Received empty response from server",t&&t.setContent(o)}catch(e){console.error("Error handling Python response:",e),t&&t.setContent("Error: Failed to process server response")}}async saveSettingsToServer(e){const t=this.generateMessageId(),n={method:"saveSettings",username:this.username,call_id:t,message_type:"request",openai_api_key:e.openaiApiKey,gemini_api_key:e.geminiApiKey,anthropic_api_key:e.anthropicApiKey,voitta_api_key:e.voittaApiKey,max_messages:e.maxMessages,proxy_port:e.proxyPort,primary_model:e.primaryModel,secondary_provider:e.secondaryProvider,image_parse_provider:e.imageParseProvider},o=await(0,u.callPython)(n);if("error_type"in o)throw new Error(`Failed to save settings: ${o.value}`);console.log("Settings saved to server successfully")}async retrieveSettingsFromServer(){const e=this.generateMessageId(),t={method:"retrieveSettings",username:this.username,call_id:e,message_type:"request"},n=await(0,u.callPython)(t);if("error_type"in n)throw new Error(`Failed to retrieve settings: ${n.value}`);const o=n;return{openaiApiKey:o.openai_api_key||"",geminiApiKey:o.gemini_api_key||"",anthropicApiKey:o.anthropic_api_key||"",voittaApiKey:o.voitta_api_key||"",maxMessages:o.max_messages||100,proxyPort:o.proxy_port||3e3,primaryModel:o.primary_model,secondaryProvider:o.secondary_provider,imageParseProvider:o.image_parse_provider}}getMessages(){return[...this.messages]}}ge.messageCounter=0;var me=n(5606);const he={serverUrl:me.env.SERVER_URL||"/ws",username:"User",usernameFromJupyterHub:!1,bonnieUrl:"ws://bonnie:8777/ws",googleClientId:""},ye={voittaApiKey:"The Future Of Computing",openaiApiKey:"",anthropicApiKey:"",geminiApiKey:"",maxMessages:100,proxyPort:3e3,primaryModel:void 0,secondaryProvider:void 0,imageParseProvider:void 0};class fe{constructor(e){this.messageHandler=null,this.settingsRegistry=e,this.localSettings={...he},this.remoteSettings={...ye}}setMessageHandler(e){this.messageHandler=e}setOnSettingsChanged(e){this.onSettingsChanged=e}async loadLocalSettings(){if(console.log("🔧 SETTINGS: Loading local settings from registry"),!this.settingsRegistry)return console.warn("🔧 SETTINGS: Registry not available, using defaults"),{...he};try{const e=(await this.settingsRegistry.load("escobar:plugin")).composite;return this.localSettings={serverUrl:e.serverUrl||he.serverUrl,username:e.username||he.username,usernameFromJupyterHub:e.usernameFromJupyterHub||he.usernameFromJupyterHub,bonnieUrl:e.bonnieUrl||he.bonnieUrl,googleClientId:e.googleClientId||he.googleClientId,_currentChatId:e._currentChatId||""},me.env.SERVER_URL&&(this.localSettings.serverUrl=me.env.SERVER_URL,console.log("🔧 SETTINGS: Using serverUrl from environment")),console.log("🔧 SETTINGS: Local settings loaded successfully"),{...this.localSettings}}catch(e){return console.error("🔧 SETTINGS: Failed to load local settings:",e),this.localSettings={...he},{...this.localSettings}}}async saveLocalSettings(e){if(console.log("🔧 SETTINGS: Saving local settings to registry"),!this.settingsRegistry)throw new Error("Settings registry not available");try{const t=await this.settingsRegistry.load("escobar:plugin");console.log("📋 SCHEMA: Saving to registry:",{serverUrl:e.serverUrl,username:e.username,usernameFromJupyterHub:e.usernameFromJupyterHub,bonnieUrl:e.bonnieUrl,googleClientId:e.googleClientId,_currentChatId:e._currentChatId}),await t.set("serverUrl",e.serverUrl),await t.set("username",e.username),await t.set("usernameFromJupyterHub",e.usernameFromJupyterHub),void 0!==e.bonnieUrl&&await t.set("bonnieUrl",e.bonnieUrl),void 0!==e.googleClientId&&await t.set("googleClientId",e.googleClientId),void 0!==e._currentChatId&&await t.set("_currentChatId",e._currentChatId),this.localSettings={...e},console.log("🔧 SETTINGS: Local settings saved successfully"),this.notifySettingsChanged()}catch(e){throw console.error("📋 SCHEMA: Registry save failed:",e),e}}async loadRemoteSettings(){if(console.log("🔧 SETTINGS: Loading remote settings from server"),!this.messageHandler)return console.warn("🔧 SETTINGS: Message handler not available, using defaults"),{...ye};try{console.log("📤 PROTOCOL: Sending retrieveSettings request");const e=await this.messageHandler.retrieveSettingsFromServer();return console.log("📥 PROTOCOL: Received retrieveSettings response"),this.remoteSettings={voittaApiKey:e.voittaApiKey||ye.voittaApiKey,openaiApiKey:e.openaiApiKey||ye.openaiApiKey,anthropicApiKey:e.anthropicApiKey||ye.anthropicApiKey,geminiApiKey:e.geminiApiKey||ye.geminiApiKey,maxMessages:e.maxMessages||ye.maxMessages,proxyPort:e.proxyPort||ye.proxyPort,primaryModel:e.primaryModel,secondaryProvider:e.secondaryProvider,imageParseProvider:e.imageParseProvider},console.log("🔧 SETTINGS: Remote settings loaded successfully"),{...this.remoteSettings}}catch(e){return console.warn("🔧 SETTINGS: Failed to load remote settings, using defaults:",e),this.remoteSettings={...ye},{...this.remoteSettings}}}async saveRemoteSettings(e){if(console.log("🔧 SETTINGS: Saving remote settings to server"),!this.messageHandler)throw new Error("Message handler not available for saving remote settings");try{console.log("📤 PROTOCOL: Sending saveSettings request"),await this.messageHandler.saveSettingsToServer(e),console.log("📥 PROTOCOL: Received saveSettings response"),this.remoteSettings={...e},console.log("🔧 SETTINGS: Remote settings saved successfully"),this.notifySettingsChanged()}catch(e){throw console.error("🔧 SETTINGS: Failed to save remote settings:",e),e}}getCompleteSettings(){return{...this.localSettings,...this.remoteSettings}}getLocalSettings(){return{...this.localSettings}}getRemoteSettings(){return{...this.remoteSettings}}async initializeSettings(){if(console.log("Initializing settings..."),await this.loadLocalSettings(),this.messageHandler)try{await this.loadRemoteSettings()}catch(e){console.warn("Could not load remote settings during initialization:",e)}const e=this.getCompleteSettings();return console.log("Settings initialization complete"),e}async updateLocalSetting(e,t){const n={...this.localSettings,[e]:t};await this.saveLocalSettings(n)}async updateRemoteSetting(e,t){const n={...this.remoteSettings,[e]:t};await this.saveRemoteSettings(n)}notifySettingsChanged(){this.onSettingsChanged&&this.onSettingsChanged(this.getCompleteSettings())}setupLocalSettingsListener(){this.settingsRegistry&&this.settingsRegistry.load("escobar:plugin").then((e=>{e.changed.connect((()=>{this.loadLocalSettings().then((()=>{this.notifySettingsChanged()}))}))})).catch((e=>{console.error("Failed to setup local settings listener:",e)}))}}const ve=36e5;function be(e){let t=null;if(e&&(t=e.getLocalSettings()),(null==t?void 0:t.usernameFromJupyterHub)||window.location.href.includes("/user/")){const e=function(){const e=/\/user\/([^\/]+)\//,t=window.location.pathname.match(e);if(t&&t[1])return{username:decodeURIComponent(t[1]),fromJupyterHub:!0};const n=window.location.href.match(e);if(n&&n[1])return{username:decodeURIComponent(n[1]),fromJupyterHub:!0};try{const e=document.getElementById("jupyter-config-data");if(e&&e.textContent){const t=JSON.parse(e.textContent);if(t.hubUser)return{username:t.hubUser,fromJupyterHub:!0};if(t.hubUsername)return{username:t.hubUsername,fromJupyterHub:!0};if(t.user)return{username:t.user,fromJupyterHub:!0}}}catch(e){console.error("Error parsing JupyterHub config:",e)}try{const e=document.baseURI.match(/\/user\/([^\/]+)\//);if(e&&e[1])return{username:decodeURIComponent(e[1]),fromJupyterHub:!0}}catch(e){console.error("Error checking baseURI:",e)}try{const e=document.cookie.split(";");for(const t of e){const[e,n]=t.trim().split("=");if("jupyterhub-user"===e)return{username:decodeURIComponent(n),fromJupyterHub:!0}}}catch(e){console.error("Error checking cookies:",e)}const o=/user\/([^\/]+)/,r=window.location.pathname.match(o);if(r&&r[1])return{username:decodeURIComponent(r[1]),fromJupyterHub:!0};const i=window.location.href.match(o);if(i&&i[1])return{username:decodeURIComponent(i[1]),fromJupyterHub:!0};const s=window.location.href.match(/user\/([^\/]+@[^\/]+)/);return s&&s[1]?{username:decodeURIComponent(s[1]),fromJupyterHub:!0}:(console.log("No JupyterHub username found, using default"),{username:"VoittaDefaultUser",fromJupyterHub:!1})}();if(e.fromJupyterHub)return e.username}return(null==t?void 0:t.username)&&"User"!==t.username||(null==t?void 0:t.username)?t.username:`VoittaDefaultUser@${window.location.hostname||"localhost"}`}class we extends c.Widget{constructor(e,t,o,r){const i="escobar-chat-"+we.idCounter++;super(),this.chatSelectionContainer=null,this.currentChatID="temp-session",this.availableChats=[],this.availableModels=[],this.call_id_log={},this.app=e,this.notebookTracker=o,this.settingsRegistry=t,this.debuggerService=r,this.id=i,this.addClass("escobar-chat"),this.title.label="Voitta",this.title.caption="Escobar Voitta",this.title.iconClass="jp-MessageIcon",this.title.closable=!0,this.settingsManager=new fe(t),this.node.style.display="flex",this.node.style.flexDirection="column",this.node.style.height="100%",this.node.style.padding="5px",this.node.style.position="relative",this.buttonContainer=function(e,t,o,r,i,s,a=[],c,l="temp-session"){const d=document.createElement("div");d.className="escobar-button-container",d.style.position="relative";const u="\n font-weight: bold;\n margin: 0 5px;\n padding: 5px;\n background: transparent;\n border: none;\n color: var(--jp-content-font-color1);\n cursor: pointer;\n border-radius: 4px;\n transition: all 0.2s ease;\n ",p=Z("escobar-new-chat-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <line x1="12" y1="5" x2="12" y2="19"></line>\n <line x1="5" y1="12" x2="19" y2="12"></line>\n </svg>',"New Chat"),g=document.createElement("div");g.className="escobar-warning-container",g.style.cssText="\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n background: var(--jp-warn-color0);\n color: var(--jp-warn-color1);\n border: 1px solid var(--jp-warn-color1);\n border-radius: 4px;\n padding: 8px;\n font-size: 12px;\n z-index: 1000;\n display: none;\n margin-top: 4px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\n ";let m=!1;d.updateChatState=e=>{m="temp-session"!==e&&""!==e},p.addEventListener("click",(async()=>{g.style.display="none",await r(),console.log("New chat created"),m=!0})),document.addEventListener("click",(e=>{g.contains(e.target)||(g.style.display="none")})),d.appendChild(p),d.appendChild(g);const h=Z("escobar-reconnect-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"></path>\n </svg>',"Reconnect");h.addEventListener("click",(async()=>{console.log("Reconnect button clicked");try{await i(),console.log("Reconnected and initialized successfully");const e=h.querySelector(".escobar-icon-container");if(e){e.style.opacity;for(let t=0;t<3;t++)e.style.opacity="0.2",await new Promise((e=>setTimeout(e,150))),e.style.opacity="1",await new Promise((e=>setTimeout(e,150)))}}catch(e){console.error("Error reconnecting to server:",e)}})),d.appendChild(h);const y=Z("escobar-ui-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>\n <line x1="8" y1="21" x2="16" y2="21"></line>\n <line x1="12" y1="17" x2="12" y2="21"></line>\n </svg>',"Open UI");y.addEventListener("click",(()=>{console.log("UI button clicked - opening iframe");const t=F["ui-url"];if(void 0===t)return;const n=Array.from(e.shell.widgets("main")).find((e=>"escobar-iframe"===e.id));if(n){console.log("Updating existing iframe URL to:",t),n.url=t;try{n.sandbox=["allow-scripts","allow-same-origin","allow-forms","allow-modals"]}catch(e){console.warn("Could not update iframe sandbox settings:",e)}e.shell.activateById(n.id)}else{const n=new Q.IFrame({sandbox:["allow-scripts","allow-same-origin","allow-forms","allow-modals"]});n.node.setAttribute("frameborder","0"),n.node.setAttribute("allowfullscreen","true"),n.node.setAttribute("webkitallowfullscreen","true"),n.node.setAttribute("mozallowfullscreen","true"),n.url=t,n.id="escobar-iframe",n.title.label="UI",n.title.closable=!0,n.node.style.height="100%",e.shell.add(n,"main"),e.shell.activateById(n.id)}})),d.appendChild(y);const f=document.createElement("select");f.className="escobar-chat-dropdown",f.style.cssText="\n font-weight: bold;\n margin: 0 5px;\n padding: 5px 8px;\n background: var(--jp-layout-color0);\n color: var(--jp-content-font-color1);\n border: 1px solid var(--jp-border-color1);\n border-radius: 4px;\n font-size: 12px;\n cursor: pointer;\n min-width: 150px;\n max-width: 200px;\n ";const v=(e,t)=>{void 0!==e&&(a.length=0,a.push(...e)),void 0!==t&&(l=t),f.innerHTML="";const n=a.filter((e=>e.chatId&&"temp-session"!==e.chatId));n.forEach((e=>{const t=document.createElement("option");t.value=e.chatId;const n=e.title||"Untitled Chat";let o="Unknown";if(e.lastModified&&"Unknown"!==e.lastModified)try{const t=new Date(e.lastModified);isNaN(t.getTime())||(o=t.toLocaleString("en-US",{month:"numeric",day:"numeric",year:"numeric",hour:"2-digit",minute:"2-digit",hour12:!0}))}catch(t){console.warn("Error parsing date:",e.lastModified,t)}t.textContent=`${n} - ${o}`,f.appendChild(t)})),f.style.display="inline-block","temp-session"!==l&&n.length>0&&n.some((e=>e.chatId===l))&&(f.value=l)};f.addEventListener("change",(async()=>{const e=f.value;e&&c&&(console.log("Chat dropdown selection:",e),await c(e))})),v(),d.updateChatDropdown=v,d.appendChild(f);const b=Z("escobar-google-auth-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <circle cx="12" cy="7" r="4"/>\n <path d="M12 11v10"/>\n <path d="M14 19h4"/>\n <path d="M14 16h3"/>\n <path d="M14 22h2"/>\n </svg>',"Google Authentication");b.addEventListener("click",(async()=>{var e,t,r;console.log("🔐 UI: Google Auth button clicked");try{const i=o().googleClientId;if(!i){const e=document.createElement("div");return e.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: var(--jp-error-color0);\n color: var(--jp-error-color1);\n padding: 12px 16px;\n border-radius: 4px;\n border: 1px solid var(--jp-error-color1);\n z-index: 10000;\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n ",e.textContent="Google Client ID not configured. Please set it in the settings first.",document.body.appendChild(e),void setTimeout((()=>{e.parentNode&&e.parentNode.removeChild(e)}),5e3)}let s=(0,K.Hn)();s||(s=(0,K.e$)({clientId:i,scope:"openid email profile https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/documents.readonly"}));const a=b.innerHTML;b.innerHTML='\n <span class="escobar-icon-container">\n <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <path d="M21 12a9 9 0 11-6.219-8.56"/>\n </svg>\n </span>\n ',b.disabled=!0;const c=await s.loginWithAuthCode();if(b.innerHTML=a,b.disabled=!1,c.success&&c.authorizationCode){console.log("🔐 UI: Google OAuth successful, received authorization code"),console.log("🔐 UI: Auth code:",c.authorizationCode.substring(0,20)+"...");const{updateCredentials:o}=await Promise.resolve().then(n.bind(n,9838)),a=await o(c.authorizationCode,c.redirectUri||s.getRedirectUri(),i,void 0,c.state);if(a.success){console.log("🔐 UI: Credentials updated successfully"),console.log("🔐 UI: User:",null===(e=a.userInfo)||void 0===e?void 0:e.email),window.escobarGoogleUserInfo=a.userInfo,console.log("🔐 UI: User info stored globally"),b.title=`Authenticated as ${(null===(t=a.userInfo)||void 0===t?void 0:t.email)||"Google User"}`;const n=document.createElement("div");n.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: var(--jp-success-color0);\n color: var(--jp-success-color1);\n padding: 12px 16px;\n border-radius: 4px;\n border: 1px solid var(--jp-success-color1);\n z-index: 10000;\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n ",n.textContent=`Successfully authenticated as ${(null===(r=a.userInfo)||void 0===r?void 0:r.email)||"Google User"}`,document.body.appendChild(n),setTimeout((()=>{n.parentNode&&n.parentNode.removeChild(n)}),3e3)}else{console.error("🔐 UI: Failed to update credentials:",a.error);const e=document.createElement("div");e.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: var(--jp-error-color0);\n color: var(--jp-error-color1);\n padding: 12px 16px;\n border-radius: 4px;\n border: 1px solid var(--jp-error-color1);\n z-index: 10000;\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n ",e.textContent=`Credential update failed: ${a.error||"Unknown error"}`,document.body.appendChild(e),setTimeout((()=>{e.parentNode&&e.parentNode.removeChild(e)}),5e3)}}else{console.error("🔐 UI: Google authentication failed:",c.error);const e=document.createElement("div");e.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: var(--jp-error-color0);\n color: var(--jp-error-color1);\n padding: 12px 16px;\n border-radius: 4px;\n border: 1px solid var(--jp-error-color1);\n z-index: 10000;\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n ",e.textContent=`Authentication failed: ${c.error||"Unknown error"}`,document.body.appendChild(e),setTimeout((()=>{e.parentNode&&e.parentNode.removeChild(e)}),5e3)}}catch(e){console.error("🔐 UI: Error during Google authentication:",e);const t='\n <span class="escobar-icon-container">\n <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <circle cx="12" cy="7" r="4"/>\n <path d="M12 11v10"/>\n <path d="M14 19h4"/>\n <path d="M14 16h3"/>\n <path d="M14 22h2"/>\n </svg>\n </span>\n ';b.innerHTML=t,b.disabled=!1;const n=document.createElement("div");n.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: var(--jp-error-color0);\n color: var(--jp-error-color1);\n padding: 12px 16px;\n border-radius: 4px;\n border: 1px solid var(--jp-error-color1);\n z-index: 10000;\n font-size: 14px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n ",n.textContent=`Authentication error: ${e.message||"Unknown error occurred"}`,document.body.appendChild(n),setTimeout((()=>{n.parentNode&&n.parentNode.removeChild(n)}),5e3)}})),d.appendChild(b);const w=Z("escobar-settings-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <circle cx="12" cy="12" r="3"></circle>\n <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>\n </svg>',"Settings");w.addEventListener("click",(()=>{if(t){const e=function(e,t,n){return W()?new V(e,t,n):new X(e,t,n)}(t,o(),(e=>{s(e),console.log("Settings updated:",e)}));e.show()}else console.error("Settings registry not available")})),d.appendChild(w);const x=Z("escobar-connection-button",u,'<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="escobar-icon-svg">\n <polygon points="13,2 3,14 12,14 11,22 21,10 12,10 13,2"></polygon>\n </svg>',"Connection Settings");return x.addEventListener("click",(()=>{t?function(e,t,n){new Y(e,t,n).show()}(t,o(),s):console.error("Settings registry not available")})),d.appendChild(x),d}(this.app,this.settingsRegistry,(()=>this.settingsManager.getCompleteSettings()),this.createNewChat.bind(this),this.init.bind(this),this.onSettingsChanged.bind(this),this.availableChats,this.onChatSelect.bind(this),this.currentChatID,this.availableModels),this.node.appendChild(this.buttonContainer),this.updateChatStateInUI(this.currentChatID),this.chatContainer=document.createElement("div"),this.chatContainer.className="escobar-chat-container",this.chatContainer.style.height="80%",this.chatContainer.style.flex="none",this.node.appendChild(this.chatContainer),this.divider=document.createElement("div"),this.divider.className="escobar-divider",this.node.appendChild(this.divider),this.setupDividerDrag(),this.inputContainer=document.createElement("div"),this.inputContainer.className="escobar-input-container",this.node.appendChild(this.inputContainer),this.chatInput=document.createElement("textarea"),this.chatInput.className="escobar-chat-input",this.chatInput.placeholder="Type your message here...",this.chatInput.rows=2,this.chatInput.addEventListener("keydown",(e=>{"Enter"!==e.key||e.shiftKey||(e.preventDefault(),this.sendMessage(this.sendButton.textContent))})),this.inputContainer.appendChild(this.chatInput),this.stopIcon=document.createElement("div"),this.stopIcon.className="escobar-stop-icon",this.stopIcon.innerHTML='\n <svg viewBox="0 0 100 100" width="100" height="100">\n \x3c!-- Octagonal stop sign shape with white border --\x3e\n <polygon points="29,5 71,5 95,29 95,71 71,95 29,95 5,71 5,29" fill="#c0392b" />\n <polygon points="29,5 71,5 95,29 95,71 71,95 29,95 5,71 5,29" fill="none" stroke="white" stroke-width="1.5" />\n \x3c!-- STOP text - highway style, positioned slightly higher --\x3e\n <text x="50" y="53" font-family="Arial, Helvetica, sans-serif" font-size="30" font-weight="bold" text-anchor="middle" dominant-baseline="middle" fill="white" letter-spacing="1">STOP</text>\n </svg>\n ',this.stopIcon.style.display="none",this.stopIcon.addEventListener("click",(()=>{window.dispatchEvent(new CustomEvent(u.I3.STOP))})),this.inputContainer.appendChild(this.stopIcon),this.boundDisableInput=this.disableInput.bind(this),this.boundEnableInput=this.enableInput.bind(this),window.addEventListener(u.I3.START,this.boundDisableInput),window.addEventListener(u.I3.END,this.boundEnableInput);const s=function(e=[]){const t=document.createElement("div");t.className="escobar-split-button";const n=document.createElement("button");n.className="escobar-main-button",n.textContent=e[0]||"Select";const o=document.createElement("button");o.className="escobar-dropdown-toggle";const r=document.createElementNS("http://www.w3.org/2000/svg","svg");r.setAttribute("xmlns","http://www.w3.org/2000/svg"),r.setAttribute("width","16"),r.setAttribute("height","16"),r.setAttribute("viewBox","0 0 24 24"),r.setAttribute("fill","none"),r.setAttribute("stroke","currentColor"),r.setAttribute("stroke-width","2"),r.setAttribute("stroke-linecap","round"),r.setAttribute("stroke-linejoin","round"),r.classList.add("escobar-icon-svg");const i=document.createElementNS("http://www.w3.org/2000/svg","path");i.setAttribute("d","M6 9l6 6 6-6"),r.appendChild(i),o.appendChild(r);const s=document.createElement("ul");return s.className="escobar-dropdown-menu",e.forEach((e=>{const t=document.createElement("li"),o=document.createElement("button");o.textContent=e,o.onclick=t=>{t.stopPropagation(),n.textContent=e,s.style.display="none"},t.appendChild(o),s.appendChild(t)})),document.addEventListener("click",(e=>{"block"!==s.style.display||s.contains(e.target)||e.target===o||(s.style.display="none")})),o.onclick=e=>{if(e.stopPropagation(),"block"===s.style.display)s.style.display="none";else{s.parentNode&&s.parentNode.removeChild(s),document.body.appendChild(s);const e=o.getBoundingClientRect();s.style.position="fixed",s.style.bottom=window.innerHeight-e.top+5+"px",s.style.right=window.innerWidth-e.right+"px",s.style.display="block"}},t.appendChild(n),t.appendChild(o),t.appendChild(s),t.mainButton=n,t}(["Talk","Plan","Act"]);this.sendButton=s.mainButton,this.inputContainer.appendChild(s),this.sendButton.addEventListener("click",(()=>{this.sendMessage(this.sendButton.textContent)}));const a=be(this.settingsManager),c=this.settingsManager.getCompleteSettings();this.messageHandler=new ge(c.voittaApiKey,c.openaiApiKey,c.anthropicApiKey,c.geminiApiKey,"",a,this.chatContainer,c.maxMessages),this.messageHandler.onChatCreated=e=>{this.currentChatID=e,this.updateChatStateInUI(e)},this.settingsManager.setMessageHandler(this.messageHandler),this.settingsManager.setOnSettingsChanged(this.onSettingsChanged.bind(this)),this.settingsManager.setupLocalSettingsListener(),window.escobarMessageHandler=this.messageHandler,window.escobarUsername=a,window.escobarAvailableModels=this.availableModels,window.escobarCurrentSettings=c,this.cleanupLocalStorage(),setTimeout((async()=>{await this.initializeSettings(),await this.init()}),100)}handlePythonResponse(e,t){this.messageHandler.handlePythonResponse(e,t)}async say(e){const t=this.messageHandler.findMessageById(e.msg_call_id);t.isNew?(t.setContent(e.text),t.isNew=!1):t.setContent(t.getContent()+e.text)}async tool_say(e){if("string"==typeof e.name&&null!=typeof e.name){if(u.gb[e.id],e.name.includes("editExecuteCell_editExecuteCell")||e.name.includes("insertExecuteCell_insertExecuteCell")||e.name.includes("writeToFile_writeToFile")||e.name.includes("diffToFile_diffToFile"))try{null==this.call_id_log[e.id]&&(this.call_id_log[e.id]=""),this.call_id_log[e.id]+=e.text;var t={};try{t=JSON.parse(this.call_id_log[e.id])}catch(n){t=JSON.parse(this.call_id_log[e.id]+'"}')}if(e.name.includes("diffToFile_diffToFile")){const n=t.search,o=t.replace,r=t.filePath;if(null!=n&&null!=o){const t=e.name.split("_").reverse()[1];await $[t].func({filePath:r,search:n,replace:o},!0,e.id)}}else if(e.name.includes("writeToFile_writeToFile")){const n=t.content,o=t.filePath;if(n){const t=e.name.split("_").reverse()[1];await $[t].func({filePath:o,content:n},!0,e.id)}}else{const n=t.content,o=t.cellType,r=parseInt(t.index,10);if(n){const t=e.name.split("_").reverse()[1];await $[t].func({index:r,cellType:o,content:n},!0,e.id)}}}catch(e){}}else console.log(e)}cleanupLocalStorage(){try{localStorage.getItem("escobar-settings")&&(localStorage.removeItem("escobar-settings"),console.log("🧹 CLEANUP: Removed legacy localStorage settings"))}catch(e){console.warn("🧹 CLEANUP: Failed to clean localStorage:",e)}}async initializeSettings(){await this.settingsManager.initializeSettings();const e=this.settingsManager.getCompleteSettings();window.escobarCurrentSettings=e}onSettingsChanged(e){console.log("🔧 SETTINGS: Settings change detected");const t=be(this.settingsManager);this.messageHandler.updateSettings(e.voittaApiKey,e.openaiApiKey,e.anthropicApiKey,e.geminiApiKey,"",t,e.maxMessages),window.escobarCurrentSettings=e,window.escobarUsername=t,console.log("🔧 SETTINGS: Updated username to:",t)}async reinitializeConnection(){console.log("Reinitializing WebSocket connection...");const e=(0,u.mt)();e&&e.close(),setTimeout((()=>{this.init()}),100)}async init(){await this.messageHandler.clearMessages(),this.voittaToolRouter=new l;const e=await async function(e,t,n){D||(await R(e,t,n),D=!0);const o=[];for(const e of Object.values($))o.push(e.def);return o}(this.app,this.notebookTracker,this.debuggerService),t=be(this.settingsManager),n=this.settingsManager.getCompleteSettings();this.messageHandler.updateSettings(n.voittaApiKey,n.openaiApiKey,n.anthropicApiKey,n.geminiApiKey,"",t,n.maxMessages),window.escobarUsername=t,console.log("🔧 INIT: Updated username to:",t),(0,u.uo)("handleResponse",!1,this.handlePythonResponse.bind(this)),(0,u.uo)("say",!1,this.say.bind(this)),(0,u.uo)("tool_say",!1,this.tool_say.bind(this)),this.voittaToolRouter.tools=e;try{const e=this.settingsManager.getCompleteSettings();console.log("🌐 WS: Attempting connection to",e.serverUrl),await(0,u.YL)(e.serverUrl),console.log("🌐 WS: Connection established successfully")}catch(e){return void console.error("🌐 WS: Connection failed:",e)}try{const e={method:"listChats",username:t,chatID:"",call_id:this.messageHandler.generateMessageId(),message_type:"request",intraspection:this.voittaToolRouter.intraspect()},n=await(0,u.callPython)(e,ve,!0,!1);n&&n.value&&n.value.chats&&(this.availableChats=n.value.chats.filter((e=>e.chatId&&"temp-session"!==e.chatId))),n&&n.value&&n.value.models?(this.availableModels=n.value.models,console.log("📋 MODELS: Received",this.availableModels.length,"models from server"),window.escobarAvailableModels=this.availableModels,window.dispatchEvent(new CustomEvent("escobar-models-updated",{detail:{models:this.availableModels}})),this.updateModelDropdown()):(console.log("📋 MODELS: No models received from server"),this.availableModels=[],window.escobarAvailableModels=this.availableModels,window.dispatchEvent(new CustomEvent("escobar-models-updated",{detail:{models:this.availableModels}})));let o="temp-session";if(this.availableChats.length>0){const e=this.settingsManager.getLocalSettings()._currentChatId;if(e&&""!==e)if(this.availableChats.some((t=>t.chatId===e)))o=e,console.log("🔄 CHAT: Using saved current chat ID:",o);else{console.log("🔄 CHAT: Saved chat ID not found in available chats, falling back to last chat");const e=this.availableChats.length-1;o=this.availableChats[e].chatId}else{const e=this.availableChats.length-1;o=this.availableChats[e].chatId}o||(console.error("No chatID found in chat object! Chat object structure may be incorrect."),console.log("Expected chatId property, but got:",this.availableChats[this.availableChats.length-1]),o="temp-session"),this.currentChatID=o,this.messageHandler.setCurrentChatID(o);try{await this.messageHandler.loadMessages(),this.updateChatStateInUI(o),this.messageHandler.getMessages().length}catch(e){console.error("Error loading messages for chat:",o,e),this.updateChatStateInUI(o)}}else this.currentChatID=o,this.messageHandler.setCurrentChatID(o),this.updateChatStateInUI(o);this.updateChatDropdown()}catch(e){console.error("Error in chat management flow:",e),await this.messageHandler.loadMessages()}}disableInput(){this.chatInput&&(this.chatInput.disabled=!0,this.chatInput.style.opacity="0.6",this.chatInput.placeholder="Processing...",this.stopIcon&&(this.stopIcon.style.display="flex"))}enableInput(){this.chatInput&&(this.chatInput.disabled=!1,this.chatInput.style.opacity="1",this.chatInput.placeholder="Type your message here...",this.stopIcon&&(this.stopIcon.style.display="none"))}updateChatStateInUI(e){this.buttonContainer&&this.buttonContainer.updateChatState&&this.buttonContainer.updateChatState(e)}updateChatDropdown(){this.buttonContainer&&this.buttonContainer.updateChatDropdown&&this.buttonContainer.updateChatDropdown(this.availableChats,this.currentChatID)}updateModelDropdown(){this.buttonContainer&&this.buttonContainer.updateModelDropdown&&this.buttonContainer.updateModelDropdown(this.availableModels)}async createNewChat(e){const t=await this.messageHandler.createNewChat(e);this.currentChatID=t,this.messageHandler.setCurrentChatID(t);try{await this.settingsManager.updateLocalSetting("_currentChatId",t),console.log("🔄 CHAT: Saved new chat ID to settings:",t)}catch(e){console.error("🔄 CHAT: Failed to save new chat ID:",e)}await this.refreshChatList(),this.updateChatDropdown(),this.updateChatStateInUI(t)}async onChatSelect(e){this.currentChatID=e,this.messageHandler.setCurrentChatID(e),console.log(`Selected chat: ${e}`);try{await this.settingsManager.updateLocalSetting("_currentChatId",e),console.log("🔄 CHAT: Saved current chat ID to settings:",e)}catch(e){console.error("🔄 CHAT: Failed to save current chat ID:",e)}this.updateChatStateInUI(e),await this.messageHandler.clearMessages(),await this.messageHandler.loadMessages()}async refreshChatList(){const e=be(this.settingsManager);try{const t={method:"listChats",username:e,chatID:"",call_id:this.messageHandler.generateMessageId(),message_type:"request",intraspection:this.voittaToolRouter.intraspect()},n=await(0,u.callPython)(t,ve,!0,!1);if(n&&n.value&&n.value.chats)return this.availableChats=n.value.chats,this.availableChats}catch(e){console.error("Error refreshing chat list:",e)}return[]}getSelectedProvider(){return this.buttonContainer&&this.buttonContainer.getSelectedProvider?this.buttonContainer.getSelectedProvider():"OpenAI"}async sendMessage(e){const t=this.chatInput.value.trim();if(!t)return;this.chatInput.value="";const n=this.getSelectedProvider();await this.messageHandler.sendMessage(t,e,n)}onActivateRequest(e){super.onActivateRequest(e),this.chatInput.focus()}setupDividerDrag(){let e=!1,t=0,n=0;const o=()=>{const e=this.chatContainer.scrollTop,t=this.chatContainer.clientHeight,n=this.chatContainer.scrollHeight;return Math.abs(e+t-n)<100},r=r=>{if(!e)return;const i=r.pageY-t-18,s=this.node.offsetHeight,a=Math.max(100,.3*s),c=.85*s,l=Math.min(c,Math.max(a,n+i));this.chatContainer.style.height=`${l}px`,this.chatContainer.style.flex="none",o()&&(this.chatContainer.scrollTop=this.chatContainer.scrollHeight)},i=()=>{e&&(e=!1,window.removeEventListener("mousemove",r),window.removeEventListener("mouseup",i),document.body.style.userSelect="")};this.divider.addEventListener("mousedown",(o=>{o.preventDefault(),o.stopPropagation(),e=!0,t=o.pageY,n=this.chatContainer.offsetHeight,window.addEventListener("mousemove",r),window.addEventListener("mouseup",i),document.body.style.userSelect="none"}))}dispose(){window.removeEventListener(u.I3.START,this.boundDisableInput),window.removeEventListener(u.I3.END,this.boundEnableInput);const e=(0,u.mt)();e&&e.close(),super.dispose()}}we.idCounter=0,new Q.LabIcon({name:"escobar:voitta-icon",svgstr:'\n<svg viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg">\n \x3c!-- Background circle with gradient --\x3e\n <defs>\n <linearGradient id="bg-grad" x1="0%" y1="0%" x2="100%" y2="100%">\n <stop offset="0%" stop-color="#2563EB" />\n <stop offset="100%" stop-color="#1E40AF" />\n </linearGradient>\n </defs>\n <circle cx="200" cy="200" r="200" fill="url(#bg-grad)" />\n \n \x3c!-- Inner circle --\x3e\n <circle cx="200" cy="200" r="180" fill="#1E3A8A" />\n \n \x3c!-- Connected hexagons representing different systems --\x3e\n <g transform="translate(200, 200)">\n \x3c!-- Center hexagon --\x3e\n <polygon points="0,-40 34.6,-20 34.6,20 0,40 -34.6,20 -34.6,-20" \n fill="#3B82F6" stroke="#BFDBFE" stroke-width="2" />\n \n \x3c!-- Outer hexagons --\x3e\n <polygon points="0,-100 34.6,-80 34.6,-40 0,-20 -34.6,-40 -34.6,-80" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n <polygon points="69.2,-40 103.8,-20 103.8,20 69.2,40 34.6,20 34.6,-20" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n <polygon points="69.2,40 103.8,60 103.8,100 69.2,120 34.6,100 34.6,60" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n <polygon points="0,40 34.6,60 34.6,100 0,120 -34.6,100 -34.6,60" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n <polygon points="-69.2,40 -34.6,60 -34.6,100 -69.2,120 -103.8,100 -103.8,60" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n <polygon points="-69.2,-40 -34.6,-20 -34.6,20 -69.2,40 -103.8,20 -103.8,-20" \n fill="#2563EB" stroke="#BFDBFE" stroke-width="1.5" />\n \n \x3c!-- Connection lines --\x3e\n <line x1="0" y1="-40" x2="0" y2="-20" stroke="#93C5FD" stroke-width="3" />\n <line x1="34.6" y1="20" x2="34.6" y2="60" stroke="#93C5FD" stroke-width="3" />\n <line x1="34.6" y1="-20" x2="69.2" y2="-40" stroke="#93C5FD" stroke-width="3" />\n <line x1="0" y1="40" x2="0" y2="60" stroke="#93C5FD" stroke-width="3" />\n <line x1="-34.6" y1="20" x2="-34.6" y2="60" stroke="#93C5FD" stroke-width="3" />\n <line x1="-34.6" y1="-20" x2="-69.2" y2="-40" stroke="#93C5FD" stroke-width="3" />\n \n \x3c!-- Data flow indicators --\x3e\n <circle cx="0" cy="-30" r="3" fill="#DBEAFE" />\n <circle cx="34.6" cy="40" r="3" fill="#DBEAFE" />\n <circle cx="51.9" cy="-30" r="3" fill="#DBEAFE" />\n <circle cx="0" cy="50" r="3" fill="#DBEAFE" />\n <circle cx="-34.6" cy="40" r="3" fill="#DBEAFE" />\n <circle cx="-51.9" cy="-30" r="3" fill="#DBEAFE" />\n </g>\n \n \x3c!-- Subtle outer ring --\x3e\n <circle cx="200" cy="200" r="170" fill="none" stroke="#60A5FA" stroke-width="1" stroke-dasharray="3,6" />\n \n \x3c!-- Central AI core indicator --\x3e\n <circle cx="200" cy="200" r="15" fill="#DBEAFE" />\n <circle cx="200" cy="200" r="8" fill="#3B82F6" />\n</svg>\n'}).bindprops({stylesheet:"sideBar"});const xe=new Q.LabIcon({name:"escobar:voitta-launcher-icon",svgstr:'\n<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">\n <circle cx="8" cy="8" r="8" fill="#2563EB" />\n <circle cx="8" cy="8" r="7" fill="#1E3A8A" />\n <polygon points="8,4 10.4,6 10.4,10 8,12 5.6,10 5.6,6" fill="#3B82F6" stroke="#BFDBFE" stroke-width="0.2" />\n <circle cx="8" cy="8" r="1" fill="#DBEAFE" />\n</svg>\n'}).bindprops({stylesheet:"menuItem"});function Se(){const e=document.getElementById("jp-MainLogo");e&&(e.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="5 5 50 50">\n <defs>\n \x3c!-- Gradients --\x3e\n <linearGradient id="logo-gradient-1" x1="0%" y1="0%" x2="100%" y2="100%">\n <stop offset="0%" stop-color="#4A00E0" />\n <stop offset="100%" stop-color="#0084FF" />\n </linearGradient>\n <linearGradient id="logo-gradient-2" x1="0%" y1="0%" x2="100%" y2="100%">\n <stop offset="0%" stop-color="#0084FF" />\n <stop offset="100%" stop-color="#00E0A3" />\n </linearGradient>\n \n \x3c!-- Filters --\x3e\n <filter id="logo-shadow" x="-20%" y="-20%" width="140%" height="140%">\n <feDropShadow dx="1" dy="1" stdDeviation="1.5" flood-opacity="0.3" />\n </filter>\n \n \x3c!-- Patterns --\x3e\n <pattern id="circuit-pattern" width="40" height="40" patternUnits="userSpaceOnUse">\n <path d="M 10 0 L 10 40 M 20 0 L 20 40 M 30 0 L 30 40 M 0 10 L 40 10 M 0 20 L 40 20 M 0 30 L 40 30" \n stroke="#4A00E0" stroke-width="0.5" stroke-opacity="0.2" fill="none" />\n </pattern>\n </defs>\n \n \x3c!-- Logo Mark --\x3e\n <g transform="translate(30, 30)">\n \x3c!-- Background Circuit Pattern --\x3e\n <circle cx="0" cy="0" r="25" fill="url(#circuit-pattern)" opacity="0.1" />\n \n \x3c!-- Outer Circle --\x3e\n <circle cx="0" cy="0" r="20" fill="url(#logo-gradient-1)" filter="url(#logo-shadow)" />\n \n \x3c!-- Inner Network Pattern --\x3e\n <g>\n \x3c!-- Central Node --\x3e\n <circle cx="0" cy="0" r="6" fill="#FFFFFF" opacity="0.9" />\n \n \x3c!-- Connection Lines --\x3e\n <path d="M 0 0 L -8 -8 M 0 0 L 8 -8 M 0 0 L -8 8 M 0 0 L 8 8" \n stroke="white" stroke-width="2" stroke-linecap="round" />\n \n \x3c!-- Outer Nodes --\x3e\n <circle cx="-8" cy="-8" r="3" fill="white" />\n <circle cx="8" cy="-8" r="3" fill="white" />\n <circle cx="-8" cy="8" r="3" fill="white" />\n <circle cx="8" cy="8" r="3" fill="white" />\n \n \x3c!-- Animated Data Flow --\x3e\n <circle cx="0" cy="0" r="1" fill="#00E0A3">\n <animate attributeName="cx" values="0;-8" dur="1.5s" repeatCount="indefinite" />\n <animate attributeName="cy" values="0;-8" dur="1.5s" repeatCount="indefinite" />\n <animate attributeName="opacity" values="0;1;0" dur="1.5s" repeatCount="indefinite" />\n </circle>\n \n <circle cx="0" cy="0" r="1" fill="#00E0A3">\n <animate attributeName="cx" values="0;8" dur="1.5s" begin="0.5s" repeatCount="indefinite" />\n <animate attributeName="cy" values="0;-8" dur="1.5s" begin="0.5s" repeatCount="indefinite" />\n <animate attributeName="opacity" values="0;1;0" dur="1.5s" begin="0.5s" repeatCount="indefinite" />\n </circle>\n \n <circle cx="0" cy="0" r="1" fill="#00E0A3">\n <animate attributeName="cx" values="0;-8" dur="1.5s" begin="1s" repeatCount="indefinite" />\n <animate attributeName="cy" values="0;8" dur="1.5s" begin="1s" repeatCount="indefinite" />\n <animate attributeName="opacity" values="0;1;0" dur="1.5s" begin="1s" repeatCount="indefinite" />\n </circle>\n \n <circle cx="0" cy="0" r="1" fill="#00E0A3">\n <animate attributeName="cx" values="0;8" dur="1.5s" begin="1.5s" repeatCount="indefinite" />\n <animate attributeName="cy" values="0;8" dur="1.5s" begin="1.5s" repeatCount="indefinite" />\n <animate attributeName="opacity" values="0;1;0" dur="1.5s" begin="1.5s" repeatCount="indefinite" />\n </circle>\n </g>\n \n \x3c!-- Pulsing animation --\x3e\n <circle cx="0" cy="0" r="20" fill="none" stroke="url(#logo-gradient-2)" stroke-width="1.5">\n <animate attributeName="r" values="20;23;20" dur="3s" repeatCount="indefinite" />\n <animate attributeName="opacity" values="1;0.5;1" dur="3s" repeatCount="indefinite" />\n </circle>\n \n \x3c!-- Rotating Outer Ring --\x3e\n <g opacity="0.7">\n <circle cx="0" cy="-22" r="2" fill="#FFFFFF">\n <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="360" dur="10s" repeatCount="indefinite" />\n </circle>\n <circle cx="22" cy="0" r="2" fill="#FFFFFF">\n <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="90" to="450" dur="10s" repeatCount="indefinite" />\n </circle>\n <circle cx="0" cy="22" r="2" fill="#FFFFFF">\n <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="180" to="540" dur="10s" repeatCount="indefinite" />\n </circle>\n <circle cx="-22" cy="0" r="2" fill="#FFFFFF">\n <animateTransform attributeName="transform" attributeType="XML" type="rotate" from="270" to="630" dur="10s" repeatCount="indefinite" />\n </circle>\n </g>\n </g>\n</svg>')}var Ce;!function(e){e.create="escobar:create-chat"}(Ce||(Ce={}));const Ie={id:"escobar:plugin",description:"AI CHAT EXTENSION",autoStart:!0,optional:[r.ISettingRegistry,i.ICommandPalette,s.ILauncher,a.IMainMenu,o.ILayoutRestorer,p.INotebookTracker,U.IDebugger],activate:(e,t,n,o,r,s,a,c)=>{console.log("JupyterLab extension escobar is activated!");const l=new i.WidgetTracker({namespace:"escobar"}),d=Ce.create;e.commands.addCommand(d,{label:"Voitta",icon:xe,execute:()=>{const n=new we(e,t||void 0,a||void 0,c||void 0);return e.shell.add(n,"left",{rank:900}),e.shell.activateById(n.id),console.log("Created chat widget with ID:",n.id),l.add(n),n}}),n&&n.addItem({command:d,category:"Escobar"}),o&&o.add({command:d,category:"Other",rank:1}),r.helpMenu.addGroup([{command:d}],30),s&&s.restore(l,{command:d,name:e=>"escobar-chat",args:e=>({id:e.id})}),e.restored.then((()=>{setTimeout(Se,100)})),t&&t.load(Ie.id).then((e=>{console.log("escobar settings loaded:",e.composite)})).catch((e=>{console.error("Failed to load settings for escobar.",e)}))}},Ee=Ie},5355:(e,t,n)=>{n.d(t,{I3:()=>p,Tg:()=>r,YL:()=>y,callPython:()=>v,gb:()=>o,lk:()=>i,mt:()=>g,uo:()=>b});var o={};const r={};function i(){const e=Date.now().toString(16);return"M-xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(e){const t=16*Math.random()|0;return("x"===e?t:3&t|8).toString(16)}))+"-"+e}const s=new Map,a=36e5,c={};let l=null,d=!1;var u=null;const p={START:"escobar-python-call-start",END:"escobar-python-call-end",STOP:"escobar-stop-event"};function g(){return l}let m=!1,h=!1;function y(e="ws://127.0.0.1:8777/ws"){return console.log("Entering initPythonBridge"),l&&d&&l.readyState===WebSocket.OPEN?Promise.resolve():(m||(window.addEventListener(p.STOP,f),m=!0),u=new Promise(((t,n)=>{let i=function(e){if(console.log(`##>>## Original URL: ${e}`),e.startsWith("ws://")||e.startsWith("wss://"))return console.log(`##>>## Absolute URL, using as-is: ${e}`),e;const t=window.location.pathname.match(/^\/user\/([^\/]+)\//);if(t){const n=t[0],o=n.slice(0,-1)+e,r=`${"https:"===window.location.protocol?"wss:":"ws:"}//${window.location.host}${o}`;return console.log(`##>>## JupyterHub detected, resolved URL: ${r}`),console.log(`##>>## User path: ${n}`),console.log(`##>>## Resolved path: ${o}`),r}{const t=`${"https:"===window.location.protocol?"wss:":"ws:"}//${window.location.host}${e}`;return console.log(`##>>## Standalone JupyterLab, resolved URL: ${t}`),t}}(e);const a=window.escobarCurrentSettings;if((null==a?void 0:a.bonnieUrl)&&e.startsWith("/")){console.log(`>>> Adding bonnieUrl as proxy target: ${a.bonnieUrl}`);const e=i.includes("?")?"&":"?";i+=`${e}bonnie_url=${encodeURIComponent(a.bonnieUrl)}`,console.log(`>>> Final URL with bonnieUrl parameter: ${i}`)}else console.log(">>> No bonnieUrl parameter needed");console.log(">>> Connecting to "+i),l=new WebSocket(i),l.addEventListener("open",(e=>{d=!0,t(),u=null})),l.addEventListener("error",(e=>{console.error("Error connecting to Python server:",e),n(e),u=null})),l.addEventListener("close",(e=>{d=!1})),l.addEventListener("message",(async e=>{const t=e.data;try{var n=t;"string"==typeof t&&(n=JSON.parse(t));let e=n.message_type;if("response"===e){const e=n.call_id,t=n.finish_reason;if(console.log(`Finish Reason: ${t}`),e&&s.has(e)){const o=s.get(e);if(t&&"tool_calls"===t)console.log(`Intermediate response with finish_reason: ${t} - keeping request pending`);else{clearTimeout(o.timeout),s.delete(e);const r=n.data||n.response||n;o.resolve({...r,finish_reason:t})}}else c.handleResponse?x({...n.data||n.response||n,function:"handleResponse",params:{value:n.value||"-- value not found in response --"}}):console.warn("Received response with no matching request or handler")}else if("request"===e){let e=n.function,t=n.__msg_call_id__,i=n.call_id;if(null!=r[t])return void(c[e].returns&&w(i,"__stopped__"));if(n.params,!c[e])return void console.error(`Function "${e}" not found in registry`);c[e].isAsync?await async function(e){const t=e.call_id||"",n=e.function||"";var r=e.params||{};const i=r.partial||!1;r.param,i&&r.text;const s=c[n];if(!s)throw new Error(`Function "${n}" not found in registry`);try{var a;a="diffToFile"==n||"writeToFile"==n||"insertExecuteCell"==n||"editExecuteCell"==n?await s.fn.call(s.obj,r,!1,t):await s.fn.call(s.obj,r),s.returns&&w(t,a)}catch(e){throw console.error(`Error calling function "${n}":`,e),e}o[t]=!0}(n):x(n)}}catch(e){console.error("Error parsing JSON message:",e)}}))})),u)}function f(){h=!0;for(const[e,t]of s.entries()){clearTimeout(t.timeout);const n=new Error("Operation stopped by user");n.stop=!0,t.reject(n),s.delete(e)}setTimeout((()=>{h=!1}),100)}async function v(e,t=a,n=!0,o=!1){o&&window.dispatchEvent(new CustomEvent(p.START)),!l||!d||(l.readyState,WebSocket.OPEN);const r=i();let c="",u="";window.escobarUsername?c=window.escobarUsername:(console.warn("Username not available from global variable, using default"),c="VoittaDefaultUser"),u="chatID"in e?e.chatID:"temp-session";const g={...e,user_id:c,session_id:u,call_id:r,msg_call_id:e.call_id||r,message_type:"request"},m=JSON.stringify(g);return new Promise(((e,o)=>{if(l&&d&&l.readyState===WebSocket.OPEN){const i=setTimeout((()=>{s.delete(r),window.dispatchEvent(new CustomEvent(p.END)),o(new Error(`Request timed out after ${t}ms`))}),t);n?s.set(r,{resolve:t=>{(!t.finish_reason||"tool_calls"!==t.finish_reason)&&window.dispatchEvent(new CustomEvent(p.END)),e(t)},reject:e=>{window.dispatchEvent(new CustomEvent(p.END)),o(e)},timeout:i}):(s.delete(r),window.dispatchEvent(new CustomEvent(p.END))),l.send(m)}else window.dispatchEvent(new CustomEvent(p.END)),o(new Error("Cannot send message. WebSocket is not connected after attempting to reconnect."))}))}function b(e,t,n,o=null,r=!1){c[e]&&console.warn(`Function "${e}" already exists in the registry. Overwriting`),c[e]={fn:n,obj:o,isAsync:t,returns:r}}function w(e,t){const n={call_id:e,message_type:"response"};"string"==typeof t?n.value=t:n.binary_value=t,null!==l?"string"==typeof n?l.send(n):l.send(JSON.stringify(n)):console.error("WebSocket is null. Cannot send message.")}function x(e){const t=e.call_id||"",n=e.function||"";var o=e.params||{};const r=o.partial||!1;o.msg_call_id,o.param,r&&o.text;const i=c[n];if(!i)throw new Error(`Function "${n}" not found in registry`);try{let e=i.fn.call(i.obj,o);i.returns&&w(t,e)}catch(e){throw console.error(`Error calling function "${n}":`,e),e}}},9838:(e,t,n)=>{n.d(t,{Hn:()=>s,e$:()=>i,updateCredentials:()=>a});class o{constructor(e){this.currentToken=null,this.userInfo=null,this.tokenExpirationTime=null,this.clientId=e.clientId,this.scope=e.scope||"openid email profile https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/documents.readonly",this.redirectUri=e.redirectUri||`${window.location.origin}/escobar/oauth-callback.html`,this.isValidClientId(this.clientId)||console.warn("Invalid Google Client ID format. Please check your configuration.")}isValidClientId(e){return e&&e.includes(".apps.googleusercontent.com")}async loginWithAuthCode(){return new Promise((e=>{try{if(!this.isValidClientId(this.clientId))return void e({success:!1,error:"Invalid Google Client ID. Please configure a valid Client ID in settings."});console.log("🔐 AUTH: Starting OAuth authorization code flow with Client ID:",this.clientId.substring(0,20)+"...");const t=this.generateRandomState(),n=this.buildOAuthUrl(t);console.log("🔐 AUTH: Opening OAuth popup to:",n);const o=window.open(n,"google-oauth","width=500,height=600,scrollbars=yes,resizable=yes");if(!o)return void e({success:!1,error:"Failed to open popup window. Please allow popups for this site."});const r=n=>{if(n.origin===window.location.origin)if("GOOGLE_OAUTH_CODE_SUCCESS"===n.data.type){if(console.log("🔐 AUTH: Authorization code received successfully"),n.data.state!==t)return console.error("🔐 AUTH: State parameter mismatch"),e({success:!1,error:"Security validation failed (state mismatch)"}),void i();const o=n.data.authorizationCode;console.log("🔐 AUTH: Authorization code:",o.substring(0,20)+"..."),e({success:!0,authorizationCode:o,redirectUri:this.redirectUri,state:t}),i()}else"GOOGLE_OAUTH_CODE_ERROR"===n.data.type&&(console.error("🔐 AUTH: OAuth error:",n.data.error),e({success:!1,error:n.data.error||"OAuth authentication failed"}),i());else console.warn("🔐 AUTH: Ignoring message from unknown origin:",n.origin)},i=()=>{window.removeEventListener("message",r),o&&!o.closed&&o.close()};window.addEventListener("message",r);const s=setInterval((()=>{o.closed&&(clearInterval(s),e({success:!1,error:"Authentication cancelled by user"}),i())}),1e3);setTimeout((()=>{clearInterval(s),e({success:!1,error:"Authentication timeout"}),i()}),3e5)}catch(t){console.error("🔐 AUTH: Unexpected error during OAuth flow:",t),e({success:!1,error:`OAuth error: ${t.message}`})}}))}generateRandomState(){const e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e,(e=>e.toString(16).padStart(2,"0"))).join("")}buildOAuthUrl(e){return`https://accounts.google.com/o/oauth2/v2/auth?${new URLSearchParams({response_type:"code",client_id:this.clientId,redirect_uri:this.redirectUri,scope:this.scope,state:e,access_type:"offline",prompt:"consent"}).toString()}`}triggerPopupAuthentication(e){try{console.log("🔐 AUTH: Creating temporary Google Sign-In button...");const t=document.createElement("div");t.id="google-signin-temp-container",t.style.cssText="\n position: fixed;\n top: -1000px;\n left: -1000px;\n width: 1px;\n height: 1px;\n overflow: hidden;\n opacity: 0;\n pointer-events: none;\n z-index: -1;\n ",document.body.appendChild(t),window.google.accounts.id.renderButton(t,{theme:"outline",size:"large",type:"standard",shape:"rectangular",text:"signin_with",logo_alignment:"left"}),setTimeout((()=>{const n=t.querySelector('div[role="button"]');n?(console.log("🔐 AUTH: Triggering Google Sign-In button click..."),n.click()):(console.error("🔐 AUTH: Could not find rendered Google Sign-In button"),this.cleanupTempContainer(t),e({success:!1,error:"Failed to initialize Google Sign-In button"}))}),500),setTimeout((()=>{this.cleanupTempContainer(t)}),1e4)}catch(t){console.error("🔐 AUTH: Error triggering popup authentication:",t),e({success:!1,error:`Popup authentication error: ${t.message}`})}}cleanupTempContainer(e){try{document.body.contains(e)&&document.body.removeChild(e)}catch(e){console.warn("🔐 AUTH: Error cleaning up temp container:",e)}}loadGoogleIdentityServices(){return new Promise(((e,t)=>{if(void 0!==window.google&&window.google.accounts&&window.google.accounts.id)return void e();const n=document.querySelector('script[src="https://accounts.google.com/gsi/client"]');if(n)return void n.addEventListener("load",(()=>{setTimeout((()=>{void 0!==window.google&&window.google.accounts&&window.google.accounts.id?e():t(new Error("Google Identity Services failed to initialize after script load"))}),200)}));const o=document.createElement("script");o.src="https://accounts.google.com/gsi/client",o.async=!0,o.defer=!0,o.onload=()=>{setTimeout((()=>{void 0!==window.google&&window.google.accounts&&window.google.accounts.id?e():t(new Error("Google Identity Services failed to initialize"))}),200)},o.onerror=()=>{t(new Error("Failed to load Google Identity Services script"))},document.head.appendChild(o)}))}decodeJWT(e){try{const t=e.split(".");if(3!==t.length)throw new Error("Invalid JWT format");const n=t[1].replace(/-/g,"+").replace(/_/g,"/"),o=decodeURIComponent(atob(n).split("").map((e=>"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2))).join("")),r=JSON.parse(o);if(!r.email||!r.name||!r.sub)throw new Error("Missing required fields in JWT token");return r}catch(e){throw console.error("🔐 AUTH: Error decoding JWT:",e),new Error("Failed to decode authentication token")}}validateDecodedToken(e){try{if(!e.email||!e.name||!e.sub)return console.error("🔐 AUTH: Missing required fields in token"),!1;const t=Math.floor(Date.now()/1e3);return e.exp&&e.exp<t?(console.error("🔐 AUTH: Token is expired"),!1):e.aud===this.clientId||(console.error("🔐 AUTH: Token audience does not match client ID"),!1)}catch(e){return console.error("🔐 AUTH: Error validating token:",e),!1}}isAuthenticated(){return!(!this.currentToken||!this.tokenExpirationTime)&&!(Date.now()>=this.tokenExpirationTime&&(console.log("🔐 AUTH: Token expired, clearing authentication"),this.logout(),1))}getIdToken(){return this.isAuthenticated()?this.currentToken:null}getUserInfo(){return this.isAuthenticated()?this.userInfo:null}getTimeUntilExpiration(){return this.tokenExpirationTime?Math.max(0,this.tokenExpirationTime-Date.now()):null}getRedirectUri(){return this.redirectUri}logout(){if(console.log("🔐 AUTH: Logging out user"),this.currentToken=null,this.userInfo=null,this.tokenExpirationTime=null,window.escobarGoogleIdToken&&delete window.escobarGoogleIdToken,window.escobarGoogleUserInfo&&delete window.escobarGoogleUserInfo,void 0!==window.google)try{window.google.accounts.id.disableAutoSelect()}catch(e){console.warn("🔐 AUTH: Error disabling Google auto-select:",e)}}validateToken(){if(!this.currentToken)return!1;try{const e=this.decodeJWT(this.currentToken);return this.validateDecodedToken(e)}catch(e){return console.error("🔐 AUTH: Error validating token:",e),this.logout(),!1}}}let r=null;function i(e){return console.log("🔐 AUTH: Initializing Google Auth Manager"),r=new o(e),r}function s(){return r}async function a(e,t,o,r,i){try{console.log("🔐 UPDATE: Sending Google OAuth credentials to Bonnie via WebSocket..."),console.log("🔐 UPDATE: Auth code:",e.substring(0,20)+"..."),console.log("🔐 UPDATE: Redirect URI:",t),console.log("🔐 UPDATE: Client ID:",o.substring(0,20)+"...");const{callPython:s}=await Promise.resolve().then(n.bind(n,5355)),a=window.escobarCurrentSettings,c={method:"updateCredentials",username:(null==a?void 0:a.username)||"default-user",call_id:`google-auth-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,message_type:"request",oauth_provider:"google",authorization_code:e,redirect_uri:t,client_id:o,client_secret:r,state:i,scope:"openid email profile https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/documents.readonly"};console.log("🔐 UPDATE: Sending Google OAuth message to Bonnie:",{method:c.method,username:c.username,call_id:c.call_id,has_auth_code:!!e,has_client_id:!!o});const l=await s(c);if(console.log("🔐 UPDATE: Received response from Bonnie:",l),l.error_type)return console.error("🔐 UPDATE: Bonnie returned error:",l.value),{success:!1,error:l.value||"Unknown error from Bonnie"};let d=null;try{d={email:"user@example.com",name:"Google User",picture:null}}catch(e){console.warn("🔐 UPDATE: Could not extract user info locally:",e)}return console.log("🔐 UPDATE: Google OAuth credentials sent to Bonnie successfully"),{success:!0,userInfo:d}}catch(e){return console.error("🔐 UPDATE: Error sending credentials to Bonnie:",e),{success:!1,error:`Failed to send credentials to Bonnie: ${e.message||"Unknown error"}`}}}}}]);