Agent Python executor: fix hyphenated service names and improve sandboxing #26

Closed
opened 2026-04-08 13:42:49 +00:00 by timur · 2 comments
Owner

Problem

The AI agent Python executor in server/agent.rs fails when service names contain hyphens (e.g. recipe-server). Python cannot import modules with hyphens in the name, causing ModuleNotFoundError.

Root cause

  1. Invalid Python identifiers from hyphens: derive_group_name returns names like recipe-server from socket paths. The staged client file becomes recipe-server_client.py, which Python cannot import because - is interpreted as the minus operator.

  2. to_class_name() only splits on _: It does not handle hyphens, so recipe-server becomes Recipe-server -- also invalid as a Python class name.

  3. LLM suggests pip install on failure: When the import fails, the retry LLM suggests pip install recipe_server_client, which is wrong -- the client is auto-generated, not a PyPI package.

Error observed

ModuleNotFoundError: No module named recipe_server_client

Script failed after 4 attempts (14836ms).

Fix required

  1. Normalize service names for Python: Replace hyphens with underscores in all Python-facing identifiers -- file names, import names, class names.

  2. Fix to_class_name(): Split on both _ and - so recipe-server becomes RecipeServer.

  3. Add explicit instruction to LLM system prompt: Tell the LLM to never use pip install -- all client libraries are pre-staged and available for import.

  4. Broader: The Python execution environment should use uv run for sandboxed, isolated script execution rather than maintaining a persistent venv. This prevents side effects between runs and aligns with the hero_proc sandboxing model.

## Problem The AI agent Python executor in `server/agent.rs` fails when service names contain hyphens (e.g. `recipe-server`). Python cannot import modules with hyphens in the name, causing `ModuleNotFoundError`. ### Root cause 1. **Invalid Python identifiers from hyphens**: `derive_group_name` returns names like `recipe-server` from socket paths. The staged client file becomes `recipe-server_client.py`, which Python cannot import because `-` is interpreted as the minus operator. 2. **`to_class_name()` only splits on `_`**: It does not handle hyphens, so `recipe-server` becomes `Recipe-server` -- also invalid as a Python class name. 3. **LLM suggests `pip install` on failure**: When the import fails, the retry LLM suggests `pip install recipe_server_client`, which is wrong -- the client is auto-generated, not a PyPI package. ### Error observed ``` ModuleNotFoundError: No module named recipe_server_client ``` Script failed after 4 attempts (14836ms). ## Fix required 1. **Normalize service names for Python**: Replace hyphens with underscores in all Python-facing identifiers -- file names, import names, class names. 2. **Fix `to_class_name()`**: Split on both `_` and `-` so `recipe-server` becomes `RecipeServer`. 3. **Add explicit instruction to LLM system prompt**: Tell the LLM to never use `pip install` -- all client libraries are pre-staged and available for import. 4. **Broader**: The Python execution environment should use `uv run` for sandboxed, isolated script execution rather than maintaining a persistent venv. This prevents side effects between runs and aligns with the `hero_proc` sandboxing model.
Author
Owner

Fixed in branch development_26 (commit 33e9848).

Changes

python_codegen.rs:

  • to_class_name() now splits on both _ and -, so recipe-server correctly becomes RecipeServer
  • Added to_python_module_name() — normalizes hyphens to underscores for valid Python identifiers
  • ensure_python_files(), get_cached_client(), get_cached_interface() all use normalized names for cache file paths
  • Interface stub usage comment uses normalized import name
  • Added tests for hyphenated service names

server/agent.rs:

  • Agent pipeline normalizes the service name before staging and LLM prompt generation
  • stage_client_library() now takes a py_module parameter for the Python-safe name
  • LLM system prompt explicitly forbids pip install — instructs to only use stdlib + pre-staged client

What was happening

Service names like recipe-server (from socket directory names) were used directly as Python module/file names. Python cannot import modules with hyphens (from recipe-server_client import ... fails because - is the minus operator). On failure, the LLM retry loop would suggest pip install recipe_server_client which is wrong — the client is auto-generated.

Remaining (tracked separately)

The broader sandboxing improvement (using uv run for isolated per-execution environments via hero_proc) is noted in the issue description but is a larger architectural change.

Fixed in branch `development_26` (commit 33e9848). ### Changes **`python_codegen.rs`:** - `to_class_name()` now splits on both `_` and `-`, so `recipe-server` correctly becomes `RecipeServer` - Added `to_python_module_name()` — normalizes hyphens to underscores for valid Python identifiers - `ensure_python_files()`, `get_cached_client()`, `get_cached_interface()` all use normalized names for cache file paths - Interface stub usage comment uses normalized import name - Added tests for hyphenated service names **`server/agent.rs`:** - Agent pipeline normalizes the service name before staging and LLM prompt generation - `stage_client_library()` now takes a `py_module` parameter for the Python-safe name - LLM system prompt explicitly forbids `pip install` — instructs to only use stdlib + pre-staged client ### What was happening Service names like `recipe-server` (from socket directory names) were used directly as Python module/file names. Python cannot import modules with hyphens (`from recipe-server_client import ...` fails because `-` is the minus operator). On failure, the LLM retry loop would suggest `pip install recipe_server_client` which is wrong — the client is auto-generated. ### Remaining (tracked separately) The broader sandboxing improvement (using `uv run` for isolated per-execution environments via `hero_proc`) is noted in the issue description but is a larger architectural change.
timur closed this issue 2026-04-08 13:47:04 +00:00
Author
Owner

Sandboxing improvement also done in commit 0907936.

What changed

Replaced the entire persistent venv approach with uv run --script --no-project --isolated.

Before: Created and maintained a persistent venv at ~/.hero/var/router/python/venv with a complex fallback chain (uv venv -> python3 -m venv). State could leak between runs, stale packages could accumulate.

After: Each script execution gets a clean, ephemeral environment via uv run --isolated. No venv to manage. Falls back to python3 directly if uv is not installed (since scripts only use stdlib + staged client files, no venv is needed).

Net result: -51 lines of venv management code removed.

All items from the issue are now addressed:

  • Normalize hyphens in Python identifiers
  • Fix to_class_name() for hyphens
  • LLM prompt forbids pip install
  • Sandboxed execution via uv run --isolated
Sandboxing improvement also done in commit 0907936. ### What changed Replaced the entire persistent venv approach with `uv run --script --no-project --isolated`. **Before**: Created and maintained a persistent venv at `~/.hero/var/router/python/venv` with a complex fallback chain (uv venv -> python3 -m venv). State could leak between runs, stale packages could accumulate. **After**: Each script execution gets a clean, ephemeral environment via `uv run --isolated`. No venv to manage. Falls back to `python3` directly if `uv` is not installed (since scripts only use stdlib + staged client files, no venv is needed). Net result: -51 lines of venv management code removed. All items from the issue are now addressed: - [x] Normalize hyphens in Python identifiers - [x] Fix `to_class_name()` for hyphens - [x] LLM prompt forbids pip install - [x] Sandboxed execution via `uv run --isolated`
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_router#26
No description provided.