-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplugin.json
More file actions
133 lines (133 loc) · 27.2 KB
/
Copy pathplugin.json
File metadata and controls
133 lines (133 loc) · 27.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
{
"id": "execute_python",
"uuid": "b1756fa0-b8af-4236-bbdf-92303f5a6e9d",
"emoji": "🐍",
"title": "satware® AI Python",
"system": false,
"createdAt": "2026-08-24T00:00:00.000Z",
"version": "1.1.3",
"githubURL": "https://github.com/satwareAG/satag-python-plugin",
"disabled": false,
"syncedAt": null,
"implementationType": "javascript",
"outputType": "render_html",
"openaiSpec": {
"name": "execute_python",
"description": "Execute Python code in a secure browser-based Pyodide runtime (Python 3.14, WebAssembly). The result renders as an HTML view for the user showing stdout, stderr, and matplotlib figures. Use print() to emit results. For matplotlib visuals call show_plot(dpi=120, figsize=(10, 6)) after plotting. No local file system; packages load from CDN/PyPI at runtime. First execution in a session needs ~10 s warmup.",
"parameters": {
"type": "object",
"required": [
"code",
"packages"
],
"properties": {
"code": {
"type": "string",
"description": "A valid Python 3.14 code snippet for the Pyodide WASM runtime. No access to the local file system. Prefer concise snippets with direct print statements; use real newlines for multi-line code. Use show_plot() after plt commands to display matplotlib figures."
},
"packages": {
"type": "array",
"items": {
"type": "string"
},
"description": "Python packages to load before execution from the Pyodide distribution. Common: 'numpy', 'pandas', 'matplotlib', 'scipy', 'scikit-learn', 'sympy'. Aliases 'np', 'pd', 'plt', 'sklearn', 'stats' are mapped automatically. Pass [] when no packages are needed."
}
}
}
},
"code": "",
"httpAction": null,
"oauthConfig": null,
"permissions": [],
"userSettings": null,
"isServerPlugin": false,
"pluginFunctions": [
{
"id": "LEGACY_DEFAULT_FUNCTION",
"name": "execute_python",
"implementationType": "javascript",
"outputType": "render_html",
"openaiSpec": {
"name": "execute_python",
"description": "Execute Python code in a secure browser-based Pyodide runtime (Python 3.14, WebAssembly). The result renders as an HTML view for the user showing stdout, stderr, and matplotlib figures. Use print() to emit results. For matplotlib visuals call show_plot(dpi=120, figsize=(10, 6)) after plotting. No local file system; packages load from CDN/PyPI at runtime. First execution in a session needs ~10 s warmup.",
"parameters": {
"type": "object",
"required": [
"code",
"packages"
],
"properties": {
"code": {
"type": "string",
"description": "A valid Python 3.14 code snippet for the Pyodide WASM runtime. No access to the local file system. Prefer concise snippets with direct print statements; use real newlines for multi-line code. Use show_plot() after plt commands to display matplotlib figures."
},
"packages": {
"type": "array",
"items": {
"type": "string"
},
"description": "Python packages to load before execution from the Pyodide distribution. Common: 'numpy', 'pandas', 'matplotlib', 'scipy', 'scikit-learn', 'sympy'. Aliases 'np', 'pd', 'plt', 'sklearn', 'stats' are mapped automatically. Pass [] when no packages are needed."
}
}
}
},
"code": "/**\n * satware(R) AI python - primary function (loaded by TypingMind from GitHub).\n *\n * execute_python: validates { code, packages }, maps package aliases, and\n * returns a standalone HTML document that runs the Python code in Pyodide\n * (WebAssembly, pinned v314.0.5) at display time - the mermaid-fleet\n * render_html architecture. Stdout/stderr, package feedback, matplotlib\n * figures (wasm backend) and tracebacks render directly in the document.\n *\n * Fleet conformance: input coercion + try/catch, invalid input returns\n * { isError: true, error } instead of throwing. Escaping policy: Python\n * output is inserted via textContent only (escaped by construction);\n * no innerHTML with model-generated content - see docs/source-analysis.md.\n */\n\nconst PYODIDE_VERSION = 'v314.0.5';\nconst PYODIDE_CDN = `https://cdn.jsdelivr.net/pyodide/${PYODIDE_VERSION}/full/`;\n\n// v314 no longer bundles the matplotlib Wasm backend with the matplotlib\n// package (0.27.x lock had it as a dependency). It is a pure-Python PyPI\n// wheel, installed at runtime via micropip. Verified against Pyodide\n// v314.0.5: requires-python >=3.12, imports clean with matplotlib 3.10.8.\nconst MATPLOTLIB_PYODIDE_VERSION = '0.2.3';\n\nconst PACKAGE_ALIASES = {\n np: 'numpy',\n pd: 'pandas',\n plt: 'matplotlib',\n sklearn: 'scikit-learn',\n stats: 'scipy',\n};\n\nfunction execute_python(params) {\n try {\n const code = params && params.code != null ? String(params.code) : '';\n if (!code.trim()) {\n return { isError: true, error: 'Parameter \"code\" is required and must contain Python code.' };\n }\n\n let packages = params && params.packages != null ? params.packages : [];\n if (!Array.isArray(packages)) {\n return { isError: true, error: 'Parameter \"packages\" must be an array of package names (empty array allowed).' };\n }\n if (packages.some((p) => typeof p !== 'string' || !p.trim())) {\n return { isError: true, error: 'Parameter \"packages\" must contain only non-empty package name strings.' };\n }\n packages = [...new Set(packages.map((p) => PACKAGE_ALIASES[p.trim()] || p.trim()))];\n\n // Embed the payload as JSON; escape \"</\" so \"</script>\" cannot break out.\n const payloadJson = JSON.stringify({ code, packages }).replace(/<\\//g, '<\\\\/');\n\n const htmlString = `<!DOCTYPE html>\n<html lang=\"de\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>satware® AI Python</title>\n<style>\n*{box-sizing:border-box}\nbody{margin:0;padding:12px;font-family:system-ui,-apple-system,sans-serif;font-size:14px;color:#1a1a1a}\n.py-status{margin:8px 0;font-style:italic;color:#555}\n.py-status::before{content:\"\";display:inline-block;width:11px;height:11px;border:2px solid #ccc;border-top-color:#07d;border-radius:50%;margin-right:8px;vertical-align:-1px;animation:py-spin 1s linear infinite}\n.py-status.done::before{display:none}\n.py-status.done{font-style:normal;color:#2a7a2a}\n@keyframes py-spin{to{transform:rotate(360deg)}}\n.py-stdout{font-family:ui-monospace,Menlo,Consolas,monospace;padding:10px;background:#f5f5f5;border-radius:4px;overflow-x:auto;margin:10px 0;white-space:pre-wrap;line-height:1.4}\n.py-stdout:empty{display:none}\n.py-stderr{font-family:ui-monospace,Menlo,Consolas,monospace;padding:10px;background:#fff8e8;border-left:3px solid #e6a817;border-radius:4px;white-space:pre-wrap;margin:10px 0}\n.py-stderr:empty{display:none}\n.py-error{background:#fff0f0;border-left:3px solid #d33;border-radius:4px;padding:10px 12px;font-family:ui-monospace,Menlo,Consolas,monospace;white-space:pre-wrap;margin:10px 0}\n.py-plot{margin:10px 0;text-align:center}\n.py-plot img,canvas{max-width:100%;height:auto}\n</style>\n</head>\n<body>\n<div class=\"py-status\" id=\"py-status\">Initialisiere Pyodide (Python 3.14) - beim ersten Aufruf ca. 10 Sekunden...</div>\n<pre class=\"py-stdout\" id=\"py-stdout\"></pre>\n<pre class=\"py-stderr\" id=\"py-stderr\"></pre>\n<div id=\"py-plot-root\"></div>\n<script id=\"py-payload\" type=\"application/json\">${payloadJson}</script>\n<script>\n(function () {\n 'use strict';\n var payload = JSON.parse(document.getElementById('py-payload').textContent);\n var statusEl = document.getElementById('py-status');\n var stdoutEl = document.getElementById('py-stdout');\n var stderrEl = document.getElementById('py-stderr');\n var started = Date.now();\n\n function setStatus(text) { statusEl.textContent = text; }\n function done() {\n statusEl.classList.add('done');\n statusEl.textContent = 'Fertig in ' + ((Date.now() - started) / 1000).toFixed(1) + ' s.';\n }\n\n var SUGGESTIONS = [\n [/ModuleNotFoundError/, 'Fehlendes Modul im Parameter \"packages\" ergänzen (z.B. \"scikit-learn\", nicht \"sklearn\").'],\n [/SyntaxError/, 'Python-Syntax prüfen: Doppelpunkte, Klammern, Einrückung.'],\n [/NameError/, 'Variablen vor Verwendung definieren bzw. Schreibweise prüfen.'],\n [/MemoryError|allocation|out of memory/i, 'Datenmenge reduzieren oder effizientere Operationen nutzen.']\n ];\n\n function showError(message) {\n var suggestion = '';\n for (var i = 0; i < SUGGESTIONS.length; i++) {\n if (SUGGESTIONS[i][0].test(message)) { suggestion = SUGGESTIONS[i][1]; break; }\n }\n var el = document.createElement('div');\n el.className = 'py-error';\n // textContent only - escaping by construction, never innerHTML.\n el.textContent = 'Fehler: ' + message + (suggestion ? '\\\\n\\\\nTipp: ' + suggestion : '');\n document.body.appendChild(el);\n }\n\n var script = document.createElement('script');\n script.src = '${PYODIDE_CDN}pyodide.js';\n script.onload = function () { main(); };\n script.onerror = function () {\n showError('Pyodide konnte nicht geladen werden (CDN unerreichbar).', '');\n };\n document.head.appendChild(script);\n\n async function main() {\n try {\n // convertNullToNone: matplotlib_pyodide 0.2.3 (archived upstream) checks\n // DOM lookups with \"is not None\" - on v314 a missing element returns\n // JsNull, which passes that check and crashes at scrollIntoView.\n // The flag restores 0.27.x null->None semantics.\n var pyodide = await loadPyodide({ indexURL: '${PYODIDE_CDN}', convertNullToNone: true });\n\n // Capture stdout/stderr; batched lines go through textContent (escaped).\n pyodide.setStdout({ batched: function (s) { stdoutEl.textContent += s + '\\\\n'; } });\n pyodide.setStderr({ batched: function (s) { stderrEl.textContent += s + '\\\\n'; } });\n\n // v314: the Emscripten module handle is gone from the Python pyodide\n // module but still reachable on the JS object. Bridge the heap size\n // (reserved wasm memory, in MB) so memory_status() keeps working.\n window.__py_heap_mb = function () {\n try {\n return pyodide._module.HEAP8.buffer.byteLength / (1024 * 1024);\n } catch (e) {\n return null;\n }\n };\n\n var loaded = [];\n if (payload.packages.length > 0) {\n setStatus('Lade Pakete: ' + payload.packages.join(', ') + ' ...');\n for (var i = 0; i < payload.packages.length; i++) {\n var name = payload.packages[i];\n try {\n await pyodide.loadPackage(name);\n loaded.push(name);\n stdoutEl.textContent += '\\u2713 Paket geladen: ' + name + '\\n';\n } catch (e) {\n stderrEl.textContent += '\\u26a0 Paket fehlgeschlagen: ' + name + ' (' + (e && e.message ? e.message : e) + ')\\n';\n }\n }\n }\n }\n }\n\n // v314 fix (#2 F1): the matplotlib Wasm backend lives in a separate\n // pure-Python wheel now. Install it via micropip whenever matplotlib\n // was requested; on failure fall back to the Pyodide default backend\n // (webagg) so plotting code still runs.\n var mplPyodideOk = false;\n if (loaded.indexOf('matplotlib') !== -1) {\n setStatus('Lade matplotlib-pyodide (Wasm-Backend)...');\n try {\n await pyodide.loadPackage('micropip');\n var micropip = pyodide.pyimport('micropip');\n await micropip.install('matplotlib-pyodide==${MATPLOTLIB_PYODIDE_VERSION}');\n mplPyodideOk = true;\n stdoutEl.textContent += '\\\\u2713 Paket geladen: matplotlib-pyodide ${MATPLOTLIB_PYODIDE_VERSION}\\\\n';\n } catch (e) {\n stderrEl.textContent += '\\\\u26a0 matplotlib-pyodide nicht verfügbar - Plots nutzen den Pyodide-Standard-Backend (' + (e && e.message ? e.message : e) + ')\\\\n';\n }\n }\n\n // Auto-import standard aliases for successfully loaded core packages.\n var imports = '';\n if (loaded.indexOf('numpy') !== -1) imports += 'import numpy as np\\\\n';\n if (loaded.indexOf('pandas') !== -1) {\n imports += 'import pandas as pd\\\\n' +\n 'pd.set_option(\"display.max_rows\", 20)\\\\n' +\n 'pd.set_option(\"display.max_columns\", 10)\\\\n' +\n 'pd.set_option(\"display.precision\", 3)\\\\n' +\n 'pd.set_option(\"display.width\", 1000)\\\\n';\n }\n if (loaded.indexOf('matplotlib') !== -1) {\n imports += 'import matplotlib\\\\n' +\n // matplotlib 3.10.8's own render path (backend_agg draw_text) emits\n // x/y-as-float deprecation warnings - pure noise the model would\n // try to \"fix\". Filter the category for matplotlib-generated code.\n 'import warnings\\\\n' +\n 'from matplotlib import MatplotlibDeprecationWarning\\\\n' +\n 'warnings.filterwarnings(\"ignore\", category=MatplotlibDeprecationWarning)\\\\n';\n if (mplPyodideOk) {\n imports += 'matplotlib.use(\"module://matplotlib_pyodide.wasm_backend\")\\\\n';\n }\n imports += 'import matplotlib.pyplot as plt\\\\n' +\n 'plt.rcParams[\"figure.figsize\"] = (8, 5)\\\\n' +\n 'plt.rcParams[\"figure.dpi\"] = 100\\\\n' +\n 'plt.rcParams[\"savefig.bbox\"] = \"tight\"\\\\n' +\n 'def show_plot(dpi=100, figsize=None):\\\\n' +\n ' if figsize is not None: plt.gcf().set_size_inches(*figsize)\\\\n' +\n ' plt.gcf().set_dpi(dpi)\\\\n' +\n ' plt.show()\\\\n';\n }\n if (imports) pyodide.runPython(imports);\n\n // v314 fix (#2 F2): sys.modules['pyodide']._module was removed.\n // Primary: JS bridge (reserved wasm heap, same semantics as before);\n // fallback: ctypes sbrk(0) allocator break; never raises.\n pyodide.runPython(\n 'def memory_status():\\\\n' +\n ' heap = None\\\\n' +\n ' try:\\\\n' +\n ' from js import __py_heap_mb as _heapfn\\\\n' +\n ' heap = _heapfn()\\\\n' +\n ' except Exception:\\\\n' +\n ' pass\\\\n' +\n ' if heap is None:\\\\n' +\n ' try:\\\\n' +\n ' import ctypes as _ct\\\\n' +\n ' _libc = _ct.CDLL(None)\\\\n' +\n ' _libc.sbrk.restype = _ct.c_void_p\\\\n' +\n ' heap = _libc.sbrk(0) / (1024 * 1024)\\\\n' +\n ' except Exception:\\\\n' +\n ' pass\\\\n' +\n ' if heap is not None:\\\\n' +\n ' print(f\"Heap: {heap:.0f} MB\")\\\\n' +\n ' else:\\\\n' +\n ' print(\"Heap-Info nicht verfügbar\")\\\\n'\n );\n\n setStatus('Führe Python-Code aus...');\n pyodide.runPython(payload.code);\n done();\n } catch (err) {\n done();\n // Pyodide PythonError messages already contain the full traceback.\n showError(String(err && err.message ? err.message : err));\n }\n }\n})();\n</script>\n</body>\n</html>`;\n\n return htmlString;\n } catch (err) {\n return { isError: true, error: String(err && err.message ? err.message : err) };\n }\n}\n",
"httpAction": null
},
{
"name": "python_compute",
"title": "satware® AI Python (Compute)",
"description": "Run Python 3.14 code in a browser Pyodide runtime and get the printed output BACK AS TEXT for further reasoning. Use this whenever YOU (the assistant) need computed values to continue: sums, statistics, data inspection, verification of your own calculations. Results are the captured stdout (stderr appended, truncated at ~4 KB). For visuals the USER should see (charts, styled tables) use execute_python instead. Packages: numpy, pandas, matplotlib, scipy, scikit-learn, sympy (aliases np/pd/plt/sklearn/stats). First call per session needs ~10 s warmup.",
"type": "javascript",
"implementationType": "javascript",
"outputType": "respond_to_ai",
"authenticationType": "AUTH_TYPE_NONE",
"isServerPlugin": false,
"turnedOnByDefault": true,
"openaiSpec": {
"name": "python_compute",
"description": "Run Python 3.14 code in a browser Pyodide runtime and get the printed output BACK AS TEXT for further reasoning. Use this whenever YOU (the assistant) need computed values to continue: sums, statistics, data inspection, verification of your own calculations. Results are the captured stdout (stderr appended, truncated at ~4 KB). For visuals the USER should see (charts, styled tables) use execute_python instead. Packages: numpy, pandas, matplotlib, scipy, scikit-learn, sympy (aliases np/pd/plt/sklearn/stats). First call per session needs ~10 s warmup.",
"parameters": {
"type": "object",
"required": [
"code",
"packages"
],
"properties": {
"code": {
"type": "string",
"description": "Python 3.14 code to execute. Use print() to return values."
},
"packages": {
"type": "array",
"items": {
"type": "string"
},
"description": "Pyodide package names, e.g. [\"numpy\"]. Aliases np/pd/plt/sklearn/stats map automatically."
}
}
}
},
"httpAction": null,
"dynamicContextEndpoints": [],
"userSettings": [],
"code": "/**\n * satware(R) AI python - python_compute (respond_to_ai, #4).\n *\n * Model-side compute function: runs Python in Pyodide IN-CALL (raw-plugin\n * production precedent) and returns captured stdout/stderr as plain text\n * so the model can continue reasoning on real values (fixes Gate B:\n * render_html returns only a fixed notice to the model).\n *\n * This file is the canonical source for plugin.json pluginFunctions[1].code\n * (private, never mirrored). After editing: run\n * node tools/embed-python-compute.js\n * then node tests/run-tests.js. The embedded copy is the runtime artifact.\n *\n * Fleet conformance: async function, whole body in try/catch, invalid input\n * returns { isError: true, error } instead of throwing. Logging and DOM\n * insertion APIs forbidden by the fleet are not used; output is plain text.\n * Same Pyodide pin and package-alias contract as execute_python.\n */\n\nconst PC_PYODIDE_VERSION = 'v314.0.5';\nconst PC_PYODIDE_CDN = `https://cdn.jsdelivr.net/pyodide/${PC_PYODIDE_VERSION}/full/`;\nconst PC_MAX_RESULT_CHARS = 4096;\n\nconst PC_PACKAGE_ALIASES = {\n np: 'numpy',\n pd: 'pandas',\n plt: 'matplotlib',\n sklearn: 'scikit-learn',\n stats: 'scipy',\n};\n\nasync function python_compute(params) {\n try {\n const code = params && params.code != null ? String(params.code) : '';\n if (!code.trim()) {\n return { isError: true, error: 'Parameter \"code\" is required and must contain Python code.' };\n }\n\n let packages = params && params.packages != null ? params.packages : [];\n if (!Array.isArray(packages)) {\n return { isError: true, error: 'Parameter \"packages\" must be an array of package names (empty array allowed).' };\n }\n if (packages.some((p) => typeof p !== 'string' || !p.trim())) {\n return { isError: true, error: 'Parameter \"packages\" must contain only non-empty package name strings.' };\n }\n packages = [...new Set(packages.map((p) => PC_PACKAGE_ALIASES[p.trim()] || p.trim()))];\n\n // Feature-detect a global loadPyodide first (dedupes when the host page\n // already provides it; lets headless tests inject the npm runtime).\n // Otherwise inject the pinned CDN script once per window.\n if (typeof loadPyodide === 'undefined') {\n await new Promise(function (resolve, reject) {\n const s = document.createElement('script');\n s.src = PC_PYODIDE_CDN + 'pyodide.js';\n s.onload = function () { resolve(); };\n s.onerror = function () {\n reject(new Error('Pyodide konnte nicht geladen werden (CDN unerreichbar).'));\n };\n document.head.appendChild(s);\n });\n }\n\n if (!window.__pc_pyodide) {\n // convertNullToNone: restores 0.27.x null->None semantics (see\n // implementation.js / docs/source-analysis.md section 7).\n window.__pc_pyodide = await loadPyodide({\n indexURL: PC_PYODIDE_CDN,\n convertNullToNone: true,\n });\n }\n const pyodide = window.__pc_pyodide;\n\n let stdoutText = '';\n let stderrText = '';\n pyodide.setStdout({ batched: function (s) { stdoutText += s + '\\n'; } });\n pyodide.setStderr({ batched: function (s) { stderrText += s + '\\n'; } });\n\n const loaded = [];\n for (let i = 0; i < packages.length; i++) {\n try {\n await pyodide.loadPackage(packages[i]);\n loaded.push(packages[i]);\n } catch (e) {\n stderrText += '\\u26a0 Paket fehlgeschlagen: ' + packages[i] +\n ' (' + (e && e.message ? e.message : e) + ')\\n';\n }\n }\n\n // Auto-import parity with execute_python (same aliases/options).\n let imports = '';\n if (loaded.indexOf('numpy') !== -1) imports += 'import numpy as np\\n';\n if (loaded.indexOf('pandas') !== -1) {\n imports += 'import pandas as pd\\n' +\n 'pd.set_option(\"display.max_rows\", 20)\\n' +\n 'pd.set_option(\"display.max_columns\", 10)\\n' +\n 'pd.set_option(\"display.precision\", 3)\\n' +\n 'pd.set_option(\"display.width\", 1000)\\n';\n }\n if (loaded.indexOf('matplotlib') !== -1) {\n // No display here: matplotlib stays importable for computation, but\n // show_plot() steers the model to execute_python for visuals.\n // The deprecation filter matches execute_python (internal mpl noise).\n imports += 'import matplotlib\\n' +\n 'import warnings\\n' +\n 'from matplotlib import MatplotlibDeprecationWarning\\n' +\n 'warnings.filterwarnings(\"ignore\", category=MatplotlibDeprecationWarning)\\n' +\n 'import matplotlib.pyplot as plt\\n' +\n 'def show_plot(*args, **kwargs):\\n' +\n ' print(\"[Plots werden in python_compute nicht angezeigt - fuer Visualisierungen execute_python verwenden.]\")\\n';\n }\n if (imports) pyodide.runPython(imports);\n\n // v314-safe memory_status (same contract as execute_python).\n window.__py_heap_mb = function () {\n try {\n return pyodide._module.HEAP8.buffer.byteLength / (1024 * 1024);\n } catch (e) {\n return null;\n }\n };\n pyodide.runPython(\n 'def memory_status():\\n' +\n ' heap = None\\n' +\n ' try:\\n' +\n ' from js import __py_heap_mb as _heapfn\\n' +\n ' heap = _heapfn()\\n' +\n ' except Exception:\\n' +\n ' pass\\n' +\n ' if heap is None:\\n' +\n ' try:\\n' +\n ' import ctypes as _ct\\n' +\n ' _libc = _ct.CDLL(None)\\n' +\n ' _libc.sbrk.restype = _ct.c_void_p\\n' +\n ' heap = _libc.sbrk(0) / (1024 * 1024)\\n' +\n ' except Exception:\\n' +\n ' pass\\n' +\n ' if heap is not None:\\n' +\n ' print(f\"Heap: {heap:.0f} MB\")\\n' +\n ' else:\\n' +\n ' print(\"Heap-Info nicht verfuegbar\")\\n'\n );\n\n pyodide.runPython(code);\n\n let result = stdoutText.replace(/\\n$/, '');\n const errPart = stderrText.replace(/\\n$/, '');\n if (errPart) {\n result = result ? result + '\\n--- stderr ---\\n' + errPart : '--- stderr ---\\n' + errPart;\n }\n if (result.length > PC_MAX_RESULT_CHARS) {\n result = result.slice(0, PC_MAX_RESULT_CHARS) +\n '\\n[... ' + (result.length - PC_MAX_RESULT_CHARS) + ' Zeichen gekürzt]';\n }\n return result || '(keine Ausgabe - print() verwenden, um Ergebnisse zurückzugeben)';\n } catch (err) {\n return { isError: true, error: String(err && err.message ? err.message : err) };\n }\n}\n"
}
],
"overviewMarkdown": "# satware® AI Python\n\n## Überblick\n\n**satware® AI Python** führt Python-Code sicher direkt im Browser aus (Pyodide/WebAssembly, Python 3.14) - ohne Server, ohne Installation. Ausgaben (stdout/stderr), Matplotlib-Diagramme über show_plot() und Fehler mit Hinweisen erscheinen als HTML-Ansicht im Chat.\n\n**Werkzeuge:**\n- **execute_python**: Python-Code mit optionaler Paketliste ausführen (numpy, pandas, matplotlib, scipy, scikit-learn, sympy; Aliase np/pd/plt/sklearn/stats) - Ausgabe als HTML-Ansicht für den Benutzer\n- **python_compute**: Python-Code ausführen und die gedruckte Ausgabe als Text zurückliefern - für Berechnungen, deren Ergebnis das Modell weiterverarbeiten soll (Model-Seite, ca. 4 KB Begrenzung)\n\n## Overview\n\n**satware® AI Python** executes Python securely in the browser via Pyodide (Python 3.14, WebAssembly) - no server, no setup. Stdout/stderr, matplotlib figures via show_plot(), and errors with suggestions render as an HTML view in the chat.\n\n**Tools:**\n- **execute_python**: Run Python code with an optional package list (numpy, pandas, matplotlib, scipy, scikit-learn, sympy; aliases np/pd/plt/sklearn/stats) - renders as an HTML view for the user\n- **python_compute**: Run Python code and get the printed output back as text - for computations whose result the model needs to continue (model-side, ~4 KB limit)\n",
"turnedOnByDefault": true,
"authenticationType": "AUTH_TYPE_NONE",
"dynamicContextEndpoints": [
{
"id": "d1f4a2b6-8c93-4e17-9a52-6b0d3f81c7e4",
"url": "",
"name": "python-execution-requirements",
"method": "GET",
"source": "static",
"staticContent": "Two Python tools exist; pick by WHO consumes the result:\n\n- python_compute: the ASSISTANT needs the computed values to continue (sums, stats, data inspection, verifying calculations). Returns captured stdout/stderr as plain text (truncated ~4 KB).\n- execute_python: the USER should SEE the output (charts via show_plot(), formatted tables, visual results). Renders an HTML view; the assistant only sees a rendered-notice.\n\n# Python Execution Requirements (both tools)\n\n**IMPORTANT: These are STRICT REQUIREMENTS.**\n\n- Pass valid Python 3.14 code in \"code\" (string). The runtime (Pyodide/WebAssembly) has NO local file system (packages load automatically from CDN/PyPI).\n- ALWAYS pass \"packages\" as an array (use [] when none are needed), e.g. [\"numpy\", \"pandas\"]. Aliases np/pd/plt/sklearn/stats are mapped automatically to numpy/pandas/matplotlib/scikit-learn/scipy.\n- Use print() to emit results. pandas DataFrames print well via print(df).\n- In execute_python, for matplotlib visuals call show_plot(dpi=120, figsize=(10, 6)) AFTER the plotting commands; do not call plt.savefig(). In python_compute, show_plot() prints a notice (no display) - use execute_python for charts.\n- matplotlib-internal MatplotlibDeprecationWarning messages (e.g. \"x parameter as float\") are harmless runtime noise from this Pyodide build's render path and are already filtered out automatically. NEVER rework or simplify plotting code to chase them.\n- memory_status() prints the current WASM heap size.\n- The first execution in a session warms up Pyodide (~10 s); subsequent runs are fast.\n- Prefer concise, direct snippets over multiple descriptive prints.",
"cacheDurationHours": 1,
"cacheRefreshPolicy": "REFRESH_NEVER"
}
],
"sharedOAuthConnectionID": null
}