Download Latest Version 3.3.1 source code.zip (17.1 MB)
Email in envelope

Get an email when there's a new version of DSPy

Home / 3.3.1
Name Modified Size InfoDownloads / Week
Parent folder
3.3.1 source code.tar.gz 2026-08-21 16.9 MB
3.3.1 source code.zip 2026-08-21 17.1 MB
README.md 2026-08-21 16.4 kB
Totals: 3 Items   34.0 MB 2

DSPy 3.3.1

DSPy 3.3.1 contains many interpreter fixes and improvements. It makes PythonInterpreter easier to install, substantially strengthens sandbox isolation and request handling, and adds end-to-end visibility into interpreter execution. The release also improves optimizer throughput, adapter correctness, and MCP compatibility.

Highlights

PythonInterpreter: Managed Runtime, Hardening, and Lifecycle Visibility

Installation, isolation, and execution integrity

PythonInterpreter now has an optional managed runtime installation:

:::bash
pip install "dspy[deno]"

DSPy prefers that managed binary when present, while continuing to support system Deno 2.x and an explicit custom deno_command. The default path pins Pyodide, validates Deno >=2.0.0,<3.0.0, and ignores ambient Node and Deno project configuration so nearby application files cannot change sandbox startup.

The interpreter also closes several execution-integrity and isolation gaps:

  • unsolicited sandbox diagnostics can no longer desynchronize JSON-RPC replies;
  • request IDs are unpredictable, and recursive execution through one of an interpreter's own host tools is rejected;
  • bundled runtime files are protected and Deno-cache access is revoked after startup;
  • mounted files with distinct host paths cannot silently collide at the same sandbox basename; and
  • guest code cannot change host-tool identity by mutating JavaScript globals or prototypes.

Observability and agent integration

DSPy's callback API now exposes the complete interpreter lifecycle:

  • interpreter execution start and end;
  • sandbox-to-host tool-call start and end;
  • interpreter process startup and shutdown.

Events retain callback ancestry across modules, interpreters, tools, and LM calls. End callbacks receive terminating BaseException values such as cancellation and interruption instead of incorrectly reporting those operations as successful. Optimizer compile() runs receive the same start/end coverage.

PythonInterpreter.execution_instructions now gives RLM an accurate description of the Pyodide environment, including state persistence and unavailable native process capabilities. This helps generated code use the sandbox correctly.

Typing, serialization, and compatibility details

  • Tool defaults and NoneType annotations serialize correctly across the sandbox boundary.
  • CodeInterpreterError is now a DSPyError while retaining its existing RuntimeError compatibility.
  • LM-facing execution errors use one consistent formatter across interpreter and agent modules.
  • Existing system Deno and custom-command integrations remain supported; the managed runtime is opt-in.

PRs: #10119, #10120, #10134, #10135, #10136, #10186, #10190, #10194, #10205, #10206, #10208, and #10255

Faster Multi-Proposal GEPA Optimization

DSPy now uses GEPA 0.1.4 and supports its multi-proposal sampling, selection, acceptance, tracking, and checkpoint-state contracts through gepa_kwargs. DSPy's adapter saves and restores its random-number-generator state, making resumed proposal sampling consistent with uninterrupted optimization.

When a sampling strategy produces multiple candidates, DSPy can evaluate those candidates concurrently. Candidate-level and example-level concurrency share the existing num_threads budget rather than multiplying it. For example, four candidates evaluated with num_threads=8 receive two example workers each; total DSPy-controlled concurrency remains eight.

:::python
import dspy
from gepa.strategies.proposal_sampling import IndependentSampling
from gepa.strategies.proposal_selection import BestImprovement

optimizer = dspy.GEPA(
    metric=metric,
    max_metric_calls=2_000,
    reflection_lm=dspy.LM("openai/gpt-5", temperature=1.0, max_tokens=32_000),
    num_threads=8,
    gepa_kwargs={
        "sampling_strategy": IndependentSampling(4),
        "selection_strategy": BestImprovement(),
        "acceptance_criterion": "strict_improvement",
    },
)

The default single-proposal strategy retains its previous execution shape. max_reflection_cost is not yet supported by DSPy's GEPA adapter and now raises clearly when set instead of silently providing an ineffective budget.

Metrics can also report named objective_scores and select an objective-aware frontier through gepa_kwargs. Objective, hybrid, and cartesian frontiers let GEPA use dimensions such as quality, privacy, or cost when selecting parents and merges, while the scalar metric continues to gate acceptance and select the final program. Tracked results expose aggregate objective scores, best candidates per objective, and each objective's independently achieved maximum.

GEPA 0.1.4 has a known upstream limitation: it requests traces while evaluating accepted candidates on the full validation set. For programs whose traced and ordinary evaluation paths differ after a runtime failure, this can cause missing or misaligned validation results. The upstream correction is targeted for GEPA 0.1.5.

PRs: #10209, #10210, #10259

More Reliable Structured Adapter Outputs

When an LM omits an output field with a declared default, default factory, or None-allowing annotation, ChatAdapter, JSONAdapter, XMLAdapter, and adapters built on them now apply the declared fallback. Missing required outputs continue to raise AdapterParseError.

This also prevents adapter fallback merely because a provider omitted a native optional output.

XMLAdapter now formats and parses nested Pydantic models, typed dictionaries, lists, mappings, nullable fields, and unions as nested XML. It continues to accept the previous JSON-inside-an-outer-XML-field representation for backward compatibility.

PRs: #10148, #10239

MCP SDK v2 Compatibility and Structured Results

DSPy's MCP bridge supports both MCP SDK v1 and v2 field names, v1 ClientSession, and the v2 high-level Client. The default tool-result semantics are unchanged: historical text and non-text content remains authoritative rather than being replaced by v2 structured content.

Applications can now opt into machine-readable MCP results:

:::python
tool = dspy.Tool.from_mcp_tool(client, mcp_tool, result_mode="structured")

Structured mode returns structuredContent exactly when the server supplies it, including arrays, scalar values, empty values, and explicit JSON null. It falls back to the existing content conversion when structured content is absent. DSPy does not infer, parse, or unwrap the returned value.

PRs: #10188, #10235

API and Compatibility Changes

CodeAct and ProgramOfThought Deprecation

dspy.CodeAct and dspy.ProgramOfThought now emit DeprecationWarning when constructed. They are scheduled for removal in DSPy 3.5; use dspy.RLM for new code.

PR: #10198

Resource Download Timeouts

Image.from_url() and Audio.from_url() now default to a 30-second request timeout instead of potentially waiting forever:

:::python
image = dspy.Image.from_url(url, timeout=60)
audio = dspy.Audio.from_url(url, timeout=60)

Pass timeout=None to retain the previous unbounded behavior.

PR: #10149

Typed Interpreter and ReAct Errors

CodeInterpreterError is now also a DSPyError while retaining RuntimeError compatibility. ReAct preserves ContextWindowExceededError after trajectory truncation is exhausted, and LM-facing execution errors now use one consistent formatter.

PRs: #10134, #10132, #10135, #10139

Additional Fixes

  • ParallelExecutor correctly treats a completed task returning None as complete. #10142
  • COPRO.compile(..., eval_kwargs=None) now matches its documented optional contract. #10087
  • Dataset.reset_seeds() now honors valid zero-valued sizes and seeds. #9906

Full PR List

GEPA and Optimizers

  • Upgrade DSPy's GEPA engine to 0.1.4 by @isaacbmiller (#10209).
  • Parallelize GEPA candidate evaluation within the existing thread budget by @isaacbmiller (#10210).
  • Add objective-aware GEPA frontier tracking and result metadata by @isaacbmiller (#10259).
  • Make COPRO.compile's eval_kwargs optional by @katherineahn (#10087).

Callbacks and Parallel Execution

  • Expose interpreter lifecycle callback events by @isaacbmiller (#10119).
  • Expose optimizer compile callback events by @isaacbmiller (#10120).
  • Report terminating BaseException values to callback end handlers by @isaacbmiller (#10194).
  • Track completed None results in ParallelExecutor by @isaacbmiller (#10142).

Adapters, Tools, and MCP

  • Apply defaults and nullable fallbacks for omitted optional output fields by @michaelisaac-dev (#10148).
  • Add default timeouts to explicit image and audio URL downloads by @immu4989 (#10149).
  • Support MCP SDK v2 without changing tool-result semantics by @isaacbmiller (#10188).
  • Add opt-in structured MCP tool results by @isaacbmiller (#10235).
  • Format and parse nested structured data with XMLAdapter by @isaacbmiller (#10239).

Agents, Errors, and Code Execution

  • Preserve typed ReAct context-window errors by @isaacbmiller (#10132).
  • Root CodeInterpreterError under DSPyError while retaining RuntimeError compatibility by @isaacbmiller (#10134).
  • Share LM-facing exception formatting across modules by @isaacbmiller (#10135).
  • Add interpreter execution instructions to RLM prompts by @isaacbmiller (#10136).
  • Repair ReAct's formatter after parallel merges by @isaacbmiller (#10139).
  • Add managed Deno support and isolate interpreter dependencies by @isaacbmiller (#10186).
  • Prevent unhandled sandbox rejections from desynchronizing interpreter requests by @michaelisaac-dev (#10190).
  • Deprecate CodeAct and ProgramOfThought in favor of RLM by @isaacbmiller (#10198).
  • Reject colliding interpreter file mounts by @isaacbmiller (#10205).
  • Isolate the interpreter's Deno cache and runtime files by @isaacbmiller (#10206).
  • Harden interpreter request handling and tool wrappers by @isaacbmiller (#10208).
  • Scope Python standard-library guidance to PythonInterpreter-backed RLMs by @isaacbmiller (#10255).

Datasets

  • Honor zero-valued sizes and seeds in Dataset.reset_seeds by @alvinttang (#9906).

Documentation

  • Fix four dead external documentation links by @yzxcj797 (#10213).
  • Add the Nubank DSPy case study by @isaacbmiller (#10228).
  • Document the ReActV2 transition, structured history, and tool interfaces by @isaacbmiller (#10229).
  • Update the MCP tutorial to use the SDK v2 high-level Client by @isaacbmiller (#10249).
  • Repair the BetterTogether optimizer-overview link by @saime428 (#10253).

Testing, CI, Dependencies, and Release Engineering

  • Update main's version metadata after the 3.3.0 release (#10127).
  • Repair dead settings ownership assertions by @isaacbmiller (#10131).
  • Cap FastAPI for LiteLLM proxy compatibility in the development environment by @daleselaji-dev (#10151).
  • Reuse one LiteLLM test server per pytest worker by @isaacbmiller (#10154).
  • Use a memory-only cache by default in tests by @isaacbmiller (#10156).
  • Remove wall-clock retry waits from tests by @isaacbmiller (#10157).
  • Run extra test suites in parallel by @isaacbmiller (#10164).
  • Prefetch the Ollama image during test setup by @isaacbmiller (#10169).
  • Regenerate the project lockfile by @isaacbmiller (#10199).
  • Update the documentation build's urllib3 dependency (#9931).
  • Update GitHub Actions checkout (#9945).
  • Update GitHub Actions Python setup (#9965).
  • Update GitHub Actions caching (#9966).
  • Update the zizmor security-analysis action (#9967).
  • Update the documentation build's mkdocstrings-python dependency (#9968).
  • Update the actionlint workflow action (#9988).
  • Update the documentation build's Mistune dependency (#10109).
  • Update the documentation build's MkDocs Material dependency (#10110).

Contributors

Thank you to @alvinttang, @daleselaji-dev, @immu4989, @isaacbmiller, @katherineahn, @michaelisaac-dev, @saime428, and @yzxcj797 for contributing to this release.

Full Changelog: https://github.com/stanfordnlp/dspy/compare/3.3.0...3.3.1

Source: README.md, updated 2026-08-21