omp packages

@hheei/pi-python-eval0.5.0

Persistent session-scoped Python eval for Pi, with nested tool calls through the Pi host.

GitHub Actions Published 3 hours ago MIT ~609 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

@hheei/pi-python-eval

Persistent, session-scoped Python for Pi. One python_eval tool runs trusted local Python in a kernel that keeps its namespace across cells, and lets a cell call other installed tools through the Pi host.

Install @hheei/pi-settings separately for the Settings UI. @hheei/pi-ext-core is a production dependency, not a separately loaded Pi extension.

Tool

python_eval({ code, reset?, timeout_ms? })

  • code is non-empty trusted source, at most 1 MiB. This is not a sandbox.
  • reset: true discards the kernel and its scope before the cell runs.
  • timeout_ms is a hard wall-clock deadline for the whole cell, defaulting to 180000 ms (180 seconds). Set it explicitly to override the default. Nested tool calls count toward it.
  • exposure: "model-only", defaultActive: false: enable it with --tools or defaultTools.

Each cell reports its namespace, so names that survived are visible instead of assumed. print and console go to the transcript, display() keeps a JSON-safe value, and the last expression is the cell result. A restart is reported explicitly, because a kernel that died lost its names.

Nested tools

A cell reaches exactly read, grep, find, bash, edit, write, and apply_patch, and only while that tool is active in the session. Every call goes through the Pi host's context.executeTool(), so the host's own validation, hooks, and permission checks apply and the host's reported outcome decides whether the call failed. The package holds no tool definitions and no fallback dispatch, so a missing tool or a blocked call surfaces as a tool failure.

Nested calls return the tool's text, or its structuredContent when it declares one (for example bash). Each call is recorded as a trace row with its arguments, text, duration, and error.

Tool calls are synchronous Python: result = tools.apply_patch({"patch": patch}). Do not use await; top-level await is unsupported. A compile-time SyntaxError prevents the entire cell from running, so earlier assignments in that cell do not create names. Fix and re-run the whole cell, including those assignments. Runtime errors can leave earlier assignments intact; check the reported namespace before retrying.

Kernel lifecycle

One kernel per extension instance, at most one cell at a time: a concurrent cell fails immediately rather than queueing. Cancellation interrupts the cell (SIGINT) and escalates to SIGKILL after about 5 seconds; session shutdown kills the kernel. Names never survive into another session.

The kernel runs src/kernel/child.py (packed beside the built host) over NDJSON on a private pipe, so the child's stdout reaches the transcript instead of the protocol. Environment variables that look like credentials (*_API_KEY, *_TOKEN, *_SECRET, *_PASSWORD) are not inherited. Python 3.9+ is required.

Settings

Group eval in the global ext_settings.json, provider pi-python-eval.eval:

Field Default Meaning
pythonBin (auto) Interpreter for the kernel. Empty uses python3 or python on PATH.

Changes apply on reload or in a new session.

Details

Results carry format: "pi-ext-tools-python-eval" and bounded rows (200 rows, 4,000 characters per row, 12,000 characters of model-visible transcript).

Rendering

createPythonEvalPresentation in this package owns the cell's rendering facts: container status, summary ((reset), (timeout 2s), call stats, duration), the highlighted Python input section, transcript sections (muted namespace report, display:/result: prefixes, one header row per nested call), collapsed nested rows, and copy text. registerPythonEvalTool publishes it through ext-core's optional renderer point, so an installed UI package draws the frame and this package's native renderer shows the plain transcript when none is installed. No UI package is a dependency.