SPB Git forge

spb/wp13_uqo

Public
3commits 1branches 1releases
1.2 MBsize
maindefault branch
1 h agolast push
TeX 93.9% Python 6%
12.1 KB · 167 lines latex
Raw Blame History
1% ============================================================================2\section{Execution Substrate, Document Generation, and an Illustrative Walk-Through}3\label{sec:capabilities}4% ============================================================================56Having described how the agent is orchestrated, we now detail the two subsystems that turn its7plans into artifacts---the sandboxed Python substrate that executes model-authored code and the8pipeline that renders the resulting report into several document formats---and then walk through9one request end to end. The walk-through is a \emph{demonstration} in the design-science sense10\citep{peffers2007design}: it shows that the mechanisms compose, and it reports no measurements.1112\subsection{The Python execution sandbox}13\label{subsec:sandbox}1415When the model invokes the custom-analysis tool, the server does not evaluate the code in process.16It spawns a separate Python interpreter---the project's virtual environment if present, otherwise17the system interpreter---as a child process and communicates with it over standard streams. The18process boundary protects the server from faults in the executed code and bounds their effect19(Figure~\ref{fig:sandbox}); it is isolation by process, not by container, and20Section~\ref{subsec:threats} returns to what that does and does not guarantee.2122\input{figures/sandbox}2324\paragraph{Inter-process protocol.} The server serialises a single JSON object---the25model-authored code, an optional context dictionary, and the market-data credential---and writes26it to the child's standard input, then closes the stream. The child reads the entire input,27executes, and writes exactly one JSON object to standard output: a success flag, captured textual28output, a list of base64-encoded figures, a list of generated files, and any error. The child is29launched with output buffering disabled and a hard 90-second wall-clock timeout. The parent30collects standard output and standard error separately; a non-zero exit code, or error output with31no standard output, is treated as failure, and the error text is returned to the model as the tool32result so that it can revise its code on the next turn. This single-request, single-response33discipline keeps the boundary simple and makes failures explicit.3435\paragraph{Namespace construction.} Inside the child, execution is performed by building an36execution namespace---a dictionary---and calling the interpreter's \texttt{exec} against it. The37runtime attempts to import, and injects when available, 29 packages: the core scientific stack38(NumPy, pandas, SciPy, Matplotlib, seaborn, Plotly), statistics and econometrics (statsmodels,39\texttt{arch}, pmdarima, Prophet, hmmlearn), machine learning (scikit-learn, XGBoost, LightGBM),40optimisation and portfolio construction (CVXPY, PyPortfolioOpt, Riskfolio-Lib), market and41technical-analysis utilities (yfinance, \texttt{ta}, mplfinance, vectorbt), data engines (DuckDB,42Polars), and symbolic and graph libraries (SymPy, NetworkX, Numba), together with the43spreadsheet and word-processing writers. Each import is wrapped so that a missing package degrades44to an absent name rather than a failed execution; the platform's own documentation advertises45``17 libraries'', which undercounts what the executor attempts to load. The runtime also injects46two artifact helpers (\texttt{save\_excel}, \texttt{save\_word}) and a market-data client47constructed from the supplied credential; any context variables passed by the model are merged48in last, so that the model can parameterise a reusable script without string interpolation.49Matplotlib is configured for a non-interactive backend before any plotting occurs. If the executed50code defines a callable named \texttt{main}, the runtime invokes it after execution and captures51its return value.5253\paragraph{Output and figure capture.} Standard output and standard error produced by the code are54redirected into in-memory buffers for the duration of execution, so that \texttt{print} statements55become the textual result rather than corrupting the JSON protocol. Figures are captured after56execution by a deterministic sweep: the runtime enumerates all live Matplotlib figure numbers and,57for each, renders the figure to an in-memory PNG at 150 dots per inch with a tight bounding box58and base64-encodes the bytes. This is why the single-call convention asks the model to emit each59chart as a separate figure: the sweep turns each one into an individually addressable image. The60encoded figures travel back through the JSON response, are written to a served directory, and are61streamed to the client as figure events. Files written by the artifact helpers are returned as62download links in the same way.6364\subsection{Pre-built numerical routines}65\label{subsec:numerical}6667Alongside the open-ended sandbox, the server contains Python implementations of several routine68computations---a Monte Carlo path simulator under geometric Brownian motion, a Black--Scholes69pricer returning prices and Greeks, a GARCH(1,1) estimator, historical, parametric, and simulated70Value-at-Risk with expected shortfall and companion ratios, a mean--variance portfolio optimiser,71a risk-metrics module, a plotting module, and a volatility-surface renderer---each exposed through72the same child-process contract as the sandbox. Their closed forms are recorded in73Appendix~\ref{app:numerical}. At the audited commit, however, only the option pricer is declared74in the tool catalogue; the handlers for the Monte Carlo, GARCH, VaR, portfolio-optimisation,75risk-metrics, and plotting routines exist in the route module but have no corresponding tool76definition, so the model cannot invoke them, even though the system prompt still describes the77Monte Carlo and volatility-surface tools. The practical consequence is that, at this commit, such78analyses are performed through the custom-Python path of Listing~\ref{lst:onecall}, with the79model writing the code, rather than through a fixed implementation. The first version of this80paper presented the four routines as model-callable tools; we correct that here and note that81restoring the definitions is a small change.8283\subsection{The document-generation pipeline}84\label{subsec:docs}8586VQuant treats the deliverable as a first-class artifact. From a single Markdown report---the text87the agent streams to the user, with embedded figure references---the platform produces several88output formats, each through a distinct mechanism (Figure~\ref{fig:docpipeline}).8990\input{figures/docpipeline}9192\paragraph{PDF via headless rendering.} Rendering Markdown that contains mathematics is delicate93because a Markdown parser will mangle mathematical syntax. The pipeline solves this with a94protect--parse--restore step: before parsing, every display and inline mathematics span is95extracted and replaced by a unique placeholder; the now mathematics-free Markdown is parsed to96HTML (with \texttt{marked}); the placeholders are then restored as spans destined for a client-side97renderer (KaTeX). The assembled HTML is loaded into a headless Chromium instance (Puppeteer), which98executes the renderer; the server waits until rendered output appears in the document before99printing the page to PDF with headers, footers, and pagination. Rendering in a real browser engine100is what lets complex notation and styled tables reproduce faithfully; it also makes PDF generation101depend on a content-delivery network for the renderer's assets, a deployment constraint noted in102Section~\ref{subsec:threats}.103104\paragraph{Slides via model restructuring and two-pass \LaTeX.} Presentation output is a two-phase105mechanism. First, the platform issues a second model call---pinned to \texttt{claude-opus-4-8}106irrespective of the model that produced the report---whose sole task is to restructure the report107into slide content, one idea per slide, with special characters escaped and key quantities108emphasised, returning only body \LaTeX. The server wraps that body in a fixed Beamer preamble and109compiles it with two sequential passes of \texttt{pdflatex}, the second being required for110cross-references and the table of contents to resolve; a non-zero exit code is tolerated when a111PDF was nonetheless produced, since \LaTeX{} returns one on warnings. When the analysis produced112figures, the server synthesises one slide per figure without further model involvement.113114\paragraph{Word via document conversion.} For an editable office format, the same Markdown is115written to a temporary file and converted with Pandoc, which preserves tables, lists, and heading116structure.117118\paragraph{Spreadsheets with live formulas.} Within the sandbox, the spreadsheet helper writes119multi-sheet workbooks that contain live formulas---column sums, averages, extrema, and counts,120together with optional per-column formulas supplied by the model---and conditional formats, rather121than pre-computed constants, so that the recipient can audit and modify the calculations. This122mirrors, at the spreadsheet level, the platform's commitment to auditable output: the deliverable123carries its own derivation.124125\paragraph{Sharing and persistence.} Any report can be published to a stable URL under an126eight-character identifier; the server stores the report content and its figure references and127serves them through a public viewer, so an analysis can be revisited or cited without re-running128the computation. Figure files themselves live on the server's disk and are lost on redeployment, a129limitation the code acknowledges. Sessions, token ledgers, and cost estimates are persisted per130user.131132\subsection{An illustrative walk-through}133\label{subsec:walkthrough}134135To show how the mechanisms compose, we trace the request ``analyse NVDA's fundamentals,136technicals, and run a Monte Carlo simulation'' through the system as implemented. No numbers are137reported, because none were measured; the trace describes control flow.138139The route handler appends the query to an empty message list and calls140\textsc{ProcessResponse}. \textsc{PrepareContext} finds nothing to truncate or summarise. The141streaming call opens with the date-stamped system prompt, the 245 tool schemas, and the single142user message; the model's reasoning summary begins to arrive on the thinking channel and is143rendered in the collapsible panel. Under the routing policy the request is ``comprehensive'', so144the model requests on the order of ten tools in one turn---profile, income statement, balance145sheet, cash flow, key metrics, quote, historical prices, RSI, MACD, peers, news---plus one call to146the custom-Python tool whose code fetches the price history inside the sandbox, simulates147geometric-Brownian paths, and emits a fan chart and a terminal-value histogram as separate148figures. The server emits a \texttt{tools} event listing the requests, then executes them in three149batches of at most five with 500-millisecond pauses, emitting \texttt{tool\_start},150\texttt{tool\_complete}, and per-batch \texttt{status} events. The Python call spawns the child151process, which returns captured output and two base64 figures; the server writes the images to the152served directory, emits \texttt{python\_code} and \texttt{custom\_python\_figures} events, and153returns the textual output---capped at 15{,}000 characters---as the tool result. All other results154are capped at 3{,}000 characters. The assistant message with the tool-use blocks and the user155message with the tool-result blocks are appended, and the routine recurses.156157On the second call the model has every result in context and, in the typical case, requests no158further tools: it streams the report section by section, following the template in159Appendix~\ref{app:prompt}, with Markdown tables for the financial statements and image references160for the two figures. The accumulated text, figures, token totals, and cost are persisted with the161session and a \texttt{done} event closes the stream. From the rendered report the user may request162a PDF (headless rendering), a DOCX (Pandoc), a Beamer deck (a second model call, pinned to Opus1634.8, then two \texttt{pdflatex} passes, with one synthesised slide per figure), or a share link.164Had the model instead decomposed the analysis---fetching prices in one turn and simulating in165another---the trace would contain one additional recursion, which is the round trip the166single-call convention is designed to remove.167