3.3.0
Breaking Changes📦 dspyView on GitHub →
⚠ 7 breaking✨ 7 features🐛 5 fixes⚡ 5 deprecations🔧 22 symbols
Summary
DSPy 3.3.0 introduces Flex for experimental program structure optimization and ReActV2 for native tool-calling. It also advances towards a typed, provider-neutral LM system and decouples LiteLLM.
⚠️ Breaking Changes
- Resource construction and validation for dspy.Image, dspy.Audio, and dspy.File no longer implicitly read local files or fetch remote URLs from path/URL strings. To load resources, use explicit factory methods like `Image.from_path(path)`, `Image.from_url(url)`, `Audio.from_path(path)`, `Audio.from_url(url)`, and `File.from_path(path)`. Existing `Image(url)` or `Image(url=url)` will now preserve a non-downloading provider-fetched URL reference.
- NumPy-backed features from the base install are no longer available. Users should explicitly import NumPy.
- Inspection of detailed GEPA results is no longer directly supported. Users should refer to the new Flex optimization capabilities.
- Direct construction of code interpreters is deprecated. Use `dspy.CodeInterpreter` within a Flex module or other appropriate contexts.
- Catching provider-specific LM exceptions is deprecated. Use the new `dspy.LMError` or its narrower DSPy subclasses.
- The custom next_tool_args and custom trajectory syntax in ReAct are replaced by dspy.History, dspy.Tool, and dspy.ToolCalls.
- The untyped LM boundary based on `prompt`, `messages`, and provider-shaped `kwargs` is being replaced by a typed, provider-neutral contract: `def forward(self, request: dspy.LMRequest) -> dspy.LMResponse:`.
Migration Steps
- Update `Image` construction from `Image(path)` or `Image(url=path)` to `Image.from_path(path)`.
- Update `Image` construction from `Image(url, download=True)` to `Image.from_url(url)`.
- Update `Image` construction from `Image.from_url(url)` or `Image.from_url(url, download=False)` to `Image(url)` or `Image(url=url)` to preserve non-downloading URL references.
- Update `Audio` construction from `Audio(path)` to `Audio.from_path(path)`.
- Update `Audio` construction from `Audio(url)` to `Audio.from_url(url)`.
- Update `File` construction from `File(path)` to `File.from_path(path)`.
- Explicitly import NumPy if you were relying on NumPy-backed features from the base install.
- Refactor code that directly constructs code interpreters to use `dspy.CodeInterpreter` within appropriate contexts, potentially within a Flex module.
- Update exception handling to catch `dspy.LMError` or its subclasses instead of provider-specific LM exceptions.
- Replace custom `next_tool_args` and trajectory syntax in ReAct with `dspy.History`, `dspy.Tool`, and `dspy.ToolCalls`.
- For custom LM authors, adapt to the new typed LM boundary: `def forward(self, request: dspy.LMRequest) -> dspy.LMResponse:`.
- If using `RLM(max_iterations=...)`, review its behavior in the context of Flex or other interpreter sandboxes.
- Review code that consumes raw Responses API tool-call outputs for compatibility with new shapes and typed objects.
- If you previously relied on implicit I/O for `Image`, `Audio`, or `File` construction from paths or URLs, update to use the explicit factory methods.
✨ New Features
- Introduced `dspy.Flex`, an experimental feature that optimizes program structure, not just prompts, by moving the implementation into the search space for GEPA to discover.
- Introduced `dspy.ReActV2`, a new experimental version of ReAct built around native tool calling, supporting `parallel_tool_calls` and multi-turn native tool calls.
- DSPy is moving towards a typed, provider-neutral LM boundary with a `LMRequest -> LMResponse` contract.
- BaseLM now owns shared runtime state and supports sanitized state serialization through `dump_state()` and `load_state()`.
- LiteLLM imports are now lazy, decoupling the core LM API from specific provider bridges at import time.
- The OpenAI Responses path now emits Responses-native tool and `tool_choice` request shapes.
- Typed `LMToolCallPart` objects preserve raw provider fields for tool calls.
🐛 Bug Fixes
- Resource loading now requires an explicit factory to prevent silent filesystem or network access.
- LM copies isolate DSPy-owned mutable state.
- Callers can catch `dspy.LMError` or a narrower DSPy subclass instead of depending on provider-specific exception classes.
- Fixed LM state round trips for GPT-5 models.
- Legacy Responses outputs use the same Chat-style tool-call representation as the Chat Completions path.
Affected Symbols
⚡ Deprecations
- NumPy-backed features from the base install are deprecated. Users should explicitly import NumPy.
- Direct construction of code interpreters is deprecated. Use `dspy.CodeInterpreter` within a Flex module or other appropriate contexts.
- Catching provider-specific LM exceptions is deprecated. Use the new `dspy.LMError` or its narrower DSPy subclasses.
- The custom next_tool_args and custom trajectory syntax in ReAct are deprecated in favor of dspy.History, dspy.Tool, and dspy.ToolCalls.
- The untyped LM boundary based on `prompt`, `messages`, and provider-shaped `kwargs` is being deprecated in favor of a typed, provider-neutral contract.