bug fixes with proxy

main
Steve Nyemba 3 hours ago
parent 65710e6d24
commit 972d6f9bb3

@ -6,7 +6,7 @@
"threaded": true,
"host": "0.0.0.0"
},
"context": "",
"context": "studio",
"logo": "_assets/images/logo.png",
"source": {
"id": "disk",

@ -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($('<i class="fa-solid fa-play"></i>'))
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 = $('<img>').attr('src',this._args.icon)
var _icon = $('<img>').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 = $('<div class="border-left"><div class="active" title="New Connection"><i class="fa-solid fa-plug-circle-plus" style="color:#4682B4;"></i></div></div>')
_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 = $('<div class="border-left"><div class="active expand"><i class="fa-solid fa-angle-up" title="Expand spreadsheet"></div></div></div>')

@ -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
"""
_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
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
_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:
return self.read(_query)
_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"""

@ -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
```

@ -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)
})

@ -1,11 +1,11 @@
<link href="_assets/themes/default/layout.css" rel="stylesheet" type="text/css">
<link href="_assets/themes/default/header.css" rel="stylesheet" type="text/css">
<link href="_assets/themes/default/menu.css" rel="stylesheet" type="text/css">
<link href="_assets/themes/default/borders.css" rel="stylesheet" type="text/css">
<link href="_assets/themes/default/footer.css" rel="stylesheet" type="text/css">
<link href="_assets/themes/default/pane.css" rel="stylesheet" type="text/css">
<link href="_assets/themes/default/responsive.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/themes/default/layout.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/themes/default/header.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/themes/default/menu.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/themes/default/borders.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/themes/default/footer.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/themes/default/pane.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/themes/default/responsive.css" rel="stylesheet" type="text/css">
<style>
.features {display:grid; grid-template-columns: repeat(2,1fr); gap:4px; padding:4px ;

@ -1,53 +1,53 @@
<link href="_assets/css/studio.css" type="text/css" rel="stylesheet">
<link href="{{system.context}}/_assets/css/studio.css" type="text/css" rel="stylesheet">
<link href="_assets/css/mermaid.min.css" type="text/css" rel="stylesheet">
<script src="_assets/js/gridjs.umd.js"></script>
<link href="{{system.context}}/_assets/css/mermaid.min.css" type="text/css" rel="stylesheet">
<script src="{{system.context}}/_assets/js/gridjs.umd.js"></script>
<!-- data table for grid implementation ... -->
<link href="_assets/css/dataTables.min.css" type="text/css" rel="stylesheet">
<script src="_assets/js/dataTables.min.js"></script>
<link href="{{system.context}}/_assets/css/dataTables.min.css" type="text/css" rel="stylesheet">
<script src="{{system.context}}/_assets/js/dataTables.min.js"></script>
<!-- jspredhsheet (community edition) -->
<link href="_assets/lib/spreadsheet/jspreadsheet-ce/css/material.css" rel="stylesheet" type="text/css">
<link href="_assets/lib/spreadsheet/jspreadsheet-ce/css/jspreadsheet.css" rel="stylesheet" type="text/css">
<link href="_assets/lib/spreadsheet/jspreadsheet-ce/css/jsuites.css" rel="stylesheet" type="text/css">
<script src="_assets/lib/spreadsheet/jspreadsheet-ce/jspreadsheet.js"></script>
<script src="_assets/lib/spreadsheet/jspreadsheet-ce/jsuites.js"></script>
<link href="{{system.context}}/_assets/lib/spreadsheet/jspreadsheet-ce/css/material.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/lib/spreadsheet/jspreadsheet-ce/css/jspreadsheet.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/lib/spreadsheet/jspreadsheet-ce/css/jsuites.css" rel="stylesheet" type="text/css">
<script src="{{system.context}}/_assets/lib/spreadsheet/jspreadsheet-ce/jspreadsheet.js"></script>
<script src="{{system.context}}/_assets/lib/spreadsheet/jspreadsheet-ce/jsuites.js"></script>
<!-- syncfusion spreadsheet-->
<link href="_assets/lib/spreadsheet/syncfusion/css/material-0.css" rel="stylesheet" type="text/css">
<link href="_assets/lib/spreadsheet/syncfusion/css/material-1.css" rel="stylesheet" type="text/css">
<link href="_assets/lib/spreadsheet/syncfusion/css/material-2.css" rel="stylesheet" type="text/css">
<link href="_assets/lib/spreadsheet/syncfusion/css/material-3.css" rel="stylesheet" type="text/css">
<link href="_assets/lib/spreadsheet/syncfusion/css/material-4.css" rel="stylesheet" type="text/css">
<link href="_assets/lib/spreadsheet/syncfusion/css/material-5.css" rel="stylesheet" type="text/css">
<link href="_assets/lib/spreadsheet/syncfusion/css/material-6.css" rel="stylesheet" type="text/css">
<link href="_assets/lib/spreadsheet/syncfusion/css/material-7.css" rel="stylesheet" type="text/css">
<link href="_assets/lib/spreadsheet/syncfusion/css/material-8.css" rel="stylesheet" type="text/css">
<link href="_assets/lib/spreadsheet/syncfusion/css/material-9.css" rel="stylesheet" type="text/css">
<script src="_assets/lib/spreadsheet/syncfusion/ej2.min.js"></script>
<script src="_assets/lib/spreadsheet/syncfusion/shim.min.js"></script>
<script src="_assets/lib/spreadsheet/syncfusion/syncfusion-helper.js"></script>
<link href="{{system.context}}/_assets/lib/spreadsheet/syncfusion/css/material-0.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/lib/spreadsheet/syncfusion/css/material-1.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/lib/spreadsheet/syncfusion/css/material-2.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/lib/spreadsheet/syncfusion/css/material-3.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/lib/spreadsheet/syncfusion/css/material-4.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/lib/spreadsheet/syncfusion/css/material-5.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/lib/spreadsheet/syncfusion/css/material-6.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/lib/spreadsheet/syncfusion/css/material-7.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/lib/spreadsheet/syncfusion/css/material-8.css" rel="stylesheet" type="text/css">
<link href="{{system.context}}/_assets/lib/spreadsheet/syncfusion/css/material-9.css" rel="stylesheet" type="text/css">
<script src="{{system.context}}/_assets/lib/spreadsheet/syncfusion/ej2.min.js"></script>
<script src="{{system.context}}/_assets/lib/spreadsheet/syncfusion/shim.min.js"></script>
<script src="{{system.context}}/_assets/lib/spreadsheet/syncfusion/syncfusion-helper.js"></script>
<link href="_assets/css/prism.css" type="text/css" rel="stylesheet">
<script src="_assets/js/prism.js"></script>
<link href="{{system.context}}/_assets/css/prism.css" type="text/css" rel="stylesheet">
<script src="{{system.context}}/_assets/js/prism.js"></script>
<script src="_assets/js/forms.js"></script>
<script src="{{system.context}}/_assets/js/forms.js"></script>
<!-- <script src="https://bossanova.uk/jspreadsheet/v5/jspreadsheet.js"></script>
<script src="https://jsuites.net/v5/jsuites.js"></script>
<link rel="stylesheet" href="https://jsuites.net/v5/jsuites.css" type="text/css" />
<link rel="stylesheet" href="https://bossanova.uk/jspreadsheet/v5/jspreadsheet.css" type="text/css" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
-->
<script src="_assets/js/studio.js"></script>
<script src="_assets/js/ai.js"></script>
<script src="{{system.context}}/_assets/js/studio.js"></script>
<script src="{{system.context}}/_assets/js/ai.js"></script>
<script>
var Initialize =function(){
var http = HttpClient.instance()
uri = 'api/transport/version'
uri = `${qcms.context}/api/transport/version`
http.get(uri,(x)=>{
var _html = ('<div>Powered By <span style="text-transform:lowercase; color:#4682B4;">data-transport</span> '+x.responseText+'</div>')
$

@ -147,19 +147,13 @@
// _init()
//_aiInit()
var _layout = {on:{load:{'search-settings':['www/html/search.html']}}}
// $('.pane .tabs label')[0].click()
// var tabs = new QCMSTabs(_layout,'{{system.context}}','.pane .tabs')
// tabs.init()
// _layout.on.load = {'form':['www/html/_assets/wizard/technologies.html']}
bootup.init('{{system.context}}',_layout)
var _layout = {on:{load:{'search-settings':['search.html']}}}
bootup.init(_layout)
})
</script>
<div class="menu-1">
<div id="search-settings"></div>
<p>
<div class="border" style="padding:16px;">
@ -171,7 +165,7 @@
<div class=" border" style="margin-top:4px;padding:4px; background-color: #f3f3f3;">
<div class="active" style="margin-top:4px" onclick="dialog.show({uri:'www/html/setup-ai.html',title:'Setup AI',context:'{{system.context}}'})">
<i class="fa-solid fa-microchip"></i> <span>Setup AI</span>
<i class="fa-solid fa-microchip" style="color:#FF6500"></i> <span>Setup AI</span>
<span class="ai-status " style="margin-left:8px">Enabled</span>

@ -10,7 +10,6 @@
})
</script>
<div class="settings">
<div class="setting-frame lookup">
<div class="search-box border" >

@ -35,15 +35,15 @@
<br>
<p>
<div class="border" style="align-items:center; width:34%; margin-left:33%; padding:8px; display:grid; grid-template-columns: auto 64px; gap:8px; background-color: #f3f3f3;">
<div>
<div style="display:grid; grid-template-columns: 32px 32px auto;">
<i class="fa-solid fa-microchip" style="color:#FF6500"></i>
<span class="bold">AI</span>
<span class="ai-status bold">Enabled</span>
</div>
<div class="border-left" style="display:grid;">
<div align="center" class="active ai-button " >
<span class="fa-solid fa-check" style="color:green"></span>
<div align="center" align="center" class="active ai-button " >
<span class="fa-solid fa-toggle-on" style="color:#4682b4"></span>
</div>
</div>
</div>

@ -78,7 +78,7 @@
// $('.db-form').slideUp()
wizard.jumpTo('.db-provider')
window.wizard = wizard
$('.provider-s.earch').focus()
$('.provider-search').focus()
})
</script>
@ -138,7 +138,7 @@
display:grid;
grid-template-columns: 125px auto 125px;
padding:4px;
margin-top:8px;
margin-top:22px;
font-size:14px; font-weight:lighter;
}
.db-form .form-item .input-error {

Loading…
Cancel
Save