Skip to content

fix(facade): host the dspy facade in in-process interpreters without replacing host dspy - #10627

Merged
isaacbmiller merged 2 commits into
mainfrom
3.4.1/flex-inprocess-refused
Oct 12, 2026
Merged

isaacbmiller merged 2 commits into
mainfrom
3.4.1/flex-inprocess-refused

Conversation

@isaacbmiller

Copy link
Copy Markdown
Collaborator

📝 Changes Description

Since #10478, the sandbox dspy facade shim (_facade_shim.py) refuses any interpreter that runs code in the host's memory. dspy.Flex installs the facade with no fallback, so every forward on an exec()-based interpreter, including dspy_interpreters.InProcessInterpreter, raises CodeExecutionError: ... the dspy facade needs an isolated interpreter. RLM falls back to running without sub-agents. 3.4.0 works with these interpreters, but its shim could leave itself in the host's sys.modules["dspy"].

The refusal doesn't remove any capability: in-process code already shares the host's memory. What it actually prevented was the shim replacing the host's dspy module. Only an explicit choice reaches an in-process interpreter: the module's interpreter_factory or dspy.settings.interpreter_factory. The default is PythonInterpreter, and LocalInterpreter is a fresh subprocess.

This PR:

  • makes the shim, when it runs in the host's memory, bind dspy through the interpreter namespace's own __import__ (a per-namespace copy of __builtins__) instead of sys.modules. Sandboxed import dspy gets the shim, import dspy.<sub> raises ModuleNotFoundError as it does in a real sandbox, and the host's sys.modules is untouched. Isolated sandboxes still register the shim in sys.modules.
  • as a result, RLM gets sub-agents on in-process interpreters instead of logging a warning.
  • adds a Flex regression test. It uses a bare exec() interpreter that doesn't save or restore sys.modules, plus a host tool that checks sys.modules["dspy"] is dspy during the forward. It also flips the RLM and dspy_interpreters conformance tests that pinned the refusal.
  • documents in flex.md §7 and the Flex API page that an in-process interpreter works but isolates nothing.

Verification:

  • The four new or flipped tests fail on main. A naive fix that drops the refusal and always writes sys.modules fails the new Flex test.
  • pytest -n auto --deno tests/flex tests/predict/test_rlm.py tests/primitives: 547 passed, 5 skipped.
  • A live gpt-4o run of a decomposed Flex (Predict + ChainOfThought + host tool) on InProcessInterpreter succeeds with the host's dspy intact.

✅ Contributor Checklist

  • Pre-Commit checks are passing (locally and remotely)
  • Title of your PR / MR corresponds to the required format
  • Commit message follows required format {label}(dspy): {message}

⚠️ Warnings

Targeted for 3.4.1. Sibling fixes R2 (#10625) and R7 (facade opt-out) also touch _facade_shim.py and rlm.py; this diff changes only the final if block of the shim, so a rebase conflict would be small. Prepared with Amp in a maintainer-directed session.

@greptile-apps

greptile-apps Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[Medium impact] No outstanding blocking findings remain; the change preserves isolated interpreters’ existing behavior and documents the trust requirements for explicitly selected in-process interpreters.

Summary

Allows explicitly selected in-process interpreters to use the dspy facade without replacing the host’s module.

  • In-process interpreters can use the dspy facade without replacing the host module.

Reviews (4) · Last reviewed commit: "test(flex): cover the in-process shim's ..." · Reviewed by Greptile

Comment thread tests/flex/test_flex_interpreter.py
@isaacbmiller
isaacbmiller force-pushed the 3.4.1/flex-inprocess-refused branch from fa82784 to 98556b3 Compare October 12, 2026 16:39
ampagent and others added 2 commits October 12, 2026 19:16
…replacing host dspy

The shim refused any interpreter whose code runs in the host's memory, so
dspy.Flex failed every forward on exec()-based interpreters such as
dspy_interpreters.InProcessInterpreter (RLM degraded to no sub-agents).
The refusal removed no capability: in-process code already has the host's
memory. What it prevented was the shim replacing the host's
sys.modules["dspy"].

In the host's memory, the shim now binds dspy through the interpreter
namespace's own __import__ and leaves sys.modules alone. Isolated sandboxes
keep registering the shim in sys.modules. Docs say an in-process
interpreter isolates nothing.

Amp-Thread-ID: https://ampcode.com/threads/T-01a12205-a696-77cb-8f91-6b213cec210f
Co-authored-by: Isaac Miller <isaac@cmpnd.ai>
Addresses review: the in-process regression test only exercised a bare
'import dspy'. The generated module now also checks that 'import dspy.predict'
raises ModuleNotFoundError instead of reaching the host's dspy package.

Amp-Thread-ID: https://ampcode.com/threads/T-01a12205-a696-77cb-8f91-6b213cec210f
Co-authored-by: Isaac Miller <isaac@cmpnd.ai>
@isaacbmiller
isaacbmiller force-pushed the 3.4.1/flex-inprocess-refused branch from 98556b3 to 1a4f7aa Compare October 12, 2026 19:18
@isaacbmiller
isaacbmiller merged commit 81a41fd into main Oct 12, 2026
26 checks passed
@isaacbmiller
isaacbmiller deleted the 3.4.1/flex-inprocess-refused branch October 12, 2026 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants