forked from enderofwings/NexusOS
feat(chat): add run_snippet, an execution track beside the render track
render_preview validates markup and hands it to the browser, which renders it in an opaque-origin sandboxed iframe. Nothing executes server-side. That model fits HTML/SVG/JSX and cannot fit C, Rust or Erlang, which need a real toolchain - so those get a second tool instead of a widened first one. The split is the feature: the model picks a track by picking a tool, rather than picking a `lang` value from an enum where half the entries run server-side and half do not. synapse/code_run.py compiles and runs one file in a throwaway directory and returns a ```nexus-run fence carrying the source and its captured output together, so a model cannot paste output without the code that produced it. Backticks in the source are re-encoded as ` - still valid JSON, and it cannot close the fence early. It is not a sandbox, and the module docstring says so up front. What it gives is containment by layers: consent (an action tool, gated by action_tool_policy, per-call Approve/Deny on "ask"), static screening, a scrubbed environment in a temp dir, wall-clock and POSIX rlimits, and a network namespace on Linux where unprivileged userns are available. Screening is a tripwire against a model reaching for `requests` out of habit, not a boundary against an adversary; layers 1 and 3-5 are the load-bearing ones. Backend RUN_LANGS and frontend run-langs.js are separate registries because the two sides need different things - one executes, one labels - and neither should depend on the other at runtime. tests/test_tools.py asserts the key sets and the fence tag stay equal, so drift fails the gate instead of rendering a run result under the wrong language. tests/snippet_probes/ is a data catalog rather than inlined cases, so adding a language is a data change and the meta-tests can assert every RUN_LANGS key has both a smoke probe and a screening probe. Probes skip cleanly on hosts without the toolchain. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
425184a30b
commit
affba1805c
@@ -109,6 +109,28 @@ A bundled Ollama binary lives at `ollama/bin/ollama`. `OllamaManager` in `synaps
|
||||
### Frontend (`interface/web/`)
|
||||
React 19 + Vite. No routing library — `App.jsx` manages page state in a single `currentPage` useState. All API calls hit `http://localhost:8000` (configured in `src/config.js`). Built to `dist/` (gitignored) via `npm run build` and served by the backend at `:8000` — the mount is in `synapse/main.py` (`_DIST` at `/`, guarded by `is_dir()`), so `dist/` must be built for the UI to appear. Pages: Chatbot, Playbook editor, Conversation History, Models, Memory, Settings, Logs.
|
||||
|
||||
### Code Tracks (`synapse/tools.py` + `synapse/code_run.py`)
|
||||
|
||||
Two separate tools, split by *where the code runs*:
|
||||
|
||||
- **`render_preview`** — validates markup and returns a fence the chat renders in
|
||||
an opaque-origin `sandbox="allow-scripts"` iframe. Nothing executes
|
||||
server-side. Languages: `PREVIEW_LANGS` in `synapse/tools.py`, mirrored by
|
||||
`interface/web/src/preview/languages.js`.
|
||||
- **`run_snippet`** — compiles and runs a single file on the host via
|
||||
`synapse/code_run.py`, and returns a ```nexus-run fence carrying the source and
|
||||
its captured output. Languages: `RUN_LANGS` in `synapse/code_run.py`, mirrored
|
||||
by `interface/web/src/preview/run-langs.js`.
|
||||
|
||||
Each pair of registries is asserted equal by `tests/test_tools.py` — nothing
|
||||
couples them at runtime, so drift fails the check gate instead of silently
|
||||
degrading in the chat.
|
||||
|
||||
`run_snippet` is an **action tool**: `action_tool_policy` gates it (`off` by
|
||||
default, `ask` = per-call Approve/Deny in chat). Read the `code_run.py` module
|
||||
docstring before touching it — it runs code as the current user and is explicit
|
||||
about which of its five layers are load-bearing and which are only a tripwire.
|
||||
|
||||
### Persistent Storage
|
||||
Most data lands in `synapse/memory/memory.db` (SQLite, WAL mode). Tables: memory facts, conversations, messages, app settings. `synapse/memory/store.py` (`PersistentMemoryStore`) owns the schema and all queries. Playbooks are the exception — they live as YAML files in `data/playbooks/` (see Playbook System). `nexus_config.py` defines all paths; it also ensures all required directories exist on import.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user