diff --git a/qcms-manifest.json b/qcms-manifest.json
index 4223b35..21d6ed7 100644
--- a/qcms-manifest.json
+++ b/qcms-manifest.json
@@ -6,7 +6,7 @@
"threaded": true,
"host": "0.0.0.0"
},
- "context": "",
+ "context": "studio",
"logo": "_assets/images/logo.png",
"source": {
"id": "disk",
diff --git a/www/html/_assets/js/studio.js b/www/html/_assets/js/studio.js
index 5318632..463f993 100644
--- a/www/html/_assets/js/studio.js
+++ b/www/html/_assets/js/studio.js
@@ -15,11 +15,11 @@ studio.defaults = {
'mariadb':'SHOW TABLES','files':'{"query":"index > -1"}'
}
studio.init = function (_context){
- studio._context = _context
+ qcms.context = _context
}
studio.dbe = {}
// studio.dbe.get = function (){
-// var uri = [studio._context,'api/dbe/get']
+// var uri = [qcms.context,'api/dbe/get']
// uri = uri.join('/')
// var http = HttpClient.instance()
// http.get(uri,function(x){
@@ -30,7 +30,7 @@ studio.dbe = {}
// }
studio.dbe.providers = function (_render){
- var uri = [studio._context,'api/transport/providers']
+ var uri = [qcms.context,'api/transport/providers']
uri = uri.join('/')
var http = HttpClient.instance()
http.get(uri,function(x){
@@ -44,7 +44,7 @@ studio.dbe.providers = function (_render){
// studio.dbe.apply = function (label,_query){
-// var uri = [studio._context,'api/transport/apply']
+// var uri = [qcms.context,'api/transport/apply']
// uri = uri.join('/')
// var http = HttpClient.instance()
@@ -205,7 +205,7 @@ studio.grid = function (){
// }
// ]
- spreadsheet.saveUrl = studio._context+'api/io/write'
+ spreadsheet.saveUrl = qcms.context+'api/io/write'
spreadsheet.appendTo(_id)
$(_id)[0].spreadsheet = spreadsheet
@@ -230,8 +230,8 @@ studio.frame = function (_args){
// Render the template
this.read = function(_args,_query,_compute){
var _label = _args.label
- var uri = [studio._context,'api/transport/apply']
- uri = uri.join('/')
+ //var uri = [qcms.context,'api/transport/apply']
+ var uri = `${qcms.context}api/transport/apply` //'api/transport/apply']
if (_args.AI && sessionStorage.AI !="0"){
uri = uri.replace(/transport/g,'agent')
}
@@ -250,7 +250,6 @@ studio.frame = function (_args){
$(_id).empty()
$(_id).append($(''))
if(x.status == 200 && x.readyState == 4){
- console.log(x.responseText)
_r = JSON.parse(x.responseText)
// sessionStorage._data = x.responseText
@@ -306,7 +305,7 @@ studio.frame = function (_args){
_message = $(doc.querySelector('title')).text().replace(/\/\/ Werkzeug Debugger/g,'').trim()
sessionStorage.error_mesage = _message
- dialog.show({uri:'www/html/error.html',title:'Error Found',context:studio._context})
+ dialog.show({uri:'www/html/error.html',title:'Error Found',context:qcms.context})
}
})
@@ -318,11 +317,7 @@ studio.frame = function (_args){
form.append('file',file)
http.setData(form)
var _index = $(_id)[0].spreadsheet.sheets.length
- // _name = file.name
- // $(_id)[0].spreadsheet.insertSheet([{name:_name,_index:1}],0)
- // console.log([_index, $(_id)[0].spreadsheet.sheets.length])
- // $(_id)[0].spreadsheet.sheets[_index].name = `sheet {_index}`
http.post(_uri,function(x){
if(x.status == 200 && x.readyState == 4){
var _data = JSON.parse(x.responseText)
@@ -419,7 +414,7 @@ studio.frame = function (_args){
}
this.export = function (_label,spreadsheet){
// spreadsheet.save({filename:_label+'-export.xlsx'})
- uri = studio._context+'api/io/write'
+ uri = qcms.context+'api/io/write'
filename = _label+'.xlsx'
spreadsheet.saveAsJson().then(response => {
@@ -469,8 +464,7 @@ studio.frame = function (_args){
var _args = this._args
var _importSheet = this.open
var _exportSheet = this.export
-
- var _icon = $('').attr('src',this._args.icon)
+ var _icon = $('').attr('src',`${qcms.context}${this._args.icon}`)
_text = _args.provider
if (_args.AI){
//
@@ -521,7 +515,7 @@ studio.frame = function (_args){
sessionStorage._label = _args.label
sessionStorage._query = _query
- var _kwargs = {uri:'www/html/python.html',title:'Generated Python Code',context:studio._context}
+ var _kwargs = {uri:'www/html/python.html',title:'Generated Python Code',context:qcms.context}
dialog.show(_kwargs)
})
@@ -543,7 +537,7 @@ studio.frame = function (_args){
})
_wizButton = $('
')
_wizButton.on('click',function(){
- dialog.show({uri:'www/html/wizard.html',title:'Create New Connection',context:studio._context})
+ dialog.show({uri:'www/html/wizard.html',title:'Create New Connection',context:qcms.context})
})
_expandButton = $('
')
diff --git a/www/html/_plugins/agent.py b/www/html/_plugins/agent.py
index 692a342..c531615 100644
--- a/www/html/_plugins/agent.py
+++ b/www/html/_plugins/agent.py
@@ -52,9 +52,11 @@ class QueryOutput(BaseModel):
return v
class Tool:
- def __init__(self,_dbr) :
+ _cache = {}
+ def __init__(self,_dbr,label) :
self._dbr = _dbr
self._provider = _dbr._agent._engine.name
+ self._label = label
def catalog(self):
@@ -63,19 +65,34 @@ class Tool:
"""
global _map
_query = _map.get(self._provider)
+ #
- return self.read(_query)
+ if self._label not in Tool._cache :
+ Tool._cache[self._label] = {'catalog':self.read(_query),'schema':None}
+ #
+ # We hope to gain something by caching this kind of request
+ _catalog = Tool._cache[self._label].get('catalog',None)
+ return _catalog
def schema(self,table:str) ->dict:
"""
This function returns the schema for a given database, if table is not provided the entire catalog will be returned with the list of tables
"""
- _query = f""" {_map[self._provider]} WHERE name = '{table}' """
- if self._provider in ['sqlite','sqlite3'] :
- _info = self.read(f"select * from {table} limit 20").dtypes
- return pd.DataFrame({"column_name":_info.dtypes.index.tolist()[1:],"data_type": [x.name for x in _info.dtypes.tolist()[1:]]}).to_dict(orient='records')
- pass
- else:
- return self.read(_query)
+ _schema = None
+ if self._label not in Tool._cache :
+ Tool._cache[self._label] = {'catalog':None,'schema':None}
+ elif Tool._cache[self._label].get('schema') :
+ _schema = Tool._cache[self._label].get('schema')
+ else :
+ _query = f""" {_map[self._provider]} WHERE name = '{table}' """
+
+ if self._provider in ['sqlite','sqlite3'] :
+ _info = self.read(f"select * from {table} limit 20").dtypes
+ _schema = pd.DataFrame({"column_name":_info.dtypes.index.tolist()[1:],"data_type": [x.name for x in _info.dtypes.tolist()[1:]]}).to_dict(orient='records')
+
+ else:
+ _schema = self.read(_query)
+ Tool._cache[self._label]['schema'] = _schema
+ return _schema
def read(self,query:str)->dict:
"""
This function will execute a query against a given label/database. The query must adhere to the schema of the tables involved.
@@ -117,7 +134,7 @@ class TransportAgent:
return ChatOllama(**kwargs)
def get(self,label,query):
dbr = transport.get.reader(label=label)
- tools = Tool(dbr)
+ tools = Tool(dbr,label)
# self.chatbot.bind_tools ([tools.catalog,tools.read])
_message = f"""
diff --git a/www/html/_plugins/readme.md b/www/html/_plugins/readme.md
deleted file mode 100644
index e6a3f4c..0000000
--- a/www/html/_plugins/readme.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# Transport Agent Notebook
-
-This notebook provides a way to interact with the **data-transport MCP server** using LangChain and Marimo.
-
-## Overview
-
-The `notebook.py` file implements a `TransportAgent` class that bridges the gap between Large Language Models (LLMs) and the capabilities of the data-transport system via the **Model Context Protocol (MCP)**. It also demonstrates how to perform direct data access using the `transport` library.
-
-## How it Works
-
-The `notebook.py` file demonstrates how to integrate MCP with LangChain through the following steps:
-
-1. **Dynamic Tool Discovery**: Instead of hard-coding tool definitions, the `TransportAgent` fetches the OpenAPI specification from the MCP server (at `http://localhost:8090/openapi.json`).
-2. **Schema Mapping**: It automatically parses the OpenAPI `components` and `paths` to generate LangChain `StructuredTool` instances. This ensures that the agent always has the latest tools available as defined by the MCP server.
-3. **Agent Construction**: These tools are then passed into a LangChain agent. The agent uses these tools to fulfill user requests, such as listing databases or performing data analysis.
-4. **Interactive Interface**: The Marimo framework is used to provide a clean, interactive UI where users can type questions and see the agent's thought process and results.
-
-## Code Breakdown
-
-### `TransportAgent` Class
-The heart of the notebook. It manages:
-- **LLM Configuration**: Supports `ollama`, `openai`, and `azure_openai` backends.
-- **Tool Initialization (`_init_mcp_tools`)**:
- - Fetches the `openapi.json` from the local MCP server.
- - Maps API types (string, integer, etc.) to Python types.
- - Dynamically creates `StructuredTool` objects with proper descriptions and argument schemas.
-- **Agent Initialization (`_init_agent`)**: Combines the chosen LLM with the discovered tools into a functional agent.
-- **Query Handling (`get`)**: Takes a natural language prompt and returns the final response from the agent's execution chain.
-
-## How to leverage MCP with LangChain (Summary)
-
-To integrate MCP with LangChain in this project:
-1. **Expose via OpenAPI**: The MCP server must provide an `openapi.json` endpoint.
-2. **Automate Tool Creation**: Use a helper function (like `_init_mcp_tools` in this notebook) to iterate over the OpenAPI paths and generate `StructuredTool` objects.
-3. **Bind to Agent**: Pass the list of generated tools to a LangChain agent (e.g., `create_agent`).
-4. **Dynamic Updates**: Because the tools are loaded at runtime from the OpenAPI spec, any update to the MCP server's capabilities is automatically reflected in the agent.
-
-## Usage
-To run this notebook, ensure the MCP server is running on `localhost:8090` and then execute the marimo notebook:
-```bash
-marimo edit www/html/_plugins/notebook.py
-```
diff --git a/www/html/about.html b/www/html/about.html
index e9b0837..efd6d49 100644
--- a/www/html/about.html
+++ b/www/html/about.html
@@ -54,8 +54,8 @@
// })
$(document).ready(()=>{
var layout = {on:{load:{}}}
- layout.on.load.intro = ['www/html/features.html']
- bootup.init('{{system.context}}',layout)
+ layout.on.load.intro = ['features.html']
+ bootup.init(layout)
})
@@ -124,4 +124,4 @@ $(document).ready(()=>{
-
\ No newline at end of file
+
diff --git a/www/html/features.html b/www/html/features.html
index b834046..3c57c38 100644
--- a/www/html/features.html
+++ b/www/html/features.html
@@ -1,11 +1,11 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+