3.3.0b1
Breaking Changes📦 dspyView on GitHub →
⚠ 3 breaking✨ 6 features🐛 1 fixes🔧 13 symbols
Summary
DSPy 3.3.0b1 introduces the experimental ReActV2 module and moves towards a typed, provider-neutral LM boundary contract. This release also makes NumPy optional in the base install and updates GEPA integration to 0.1.1.
⚠️ Breaking Changes
- The base `dspy` install no longer includes `numpy`. Users requiring NumPy-backed features (embeddings, KNN/KNNFewShot, SIMBA, optimizers, retrieval) must now install with `pip install "dspy[numpy]"`.
- The structure of GEPA results returned by `optimized_program.detailed_results` has changed due to GEPA 0.1.1 updates. Specifically: `DspyGEPAResult.candidates` is now a list of compiled DSPy modules (was instruction dictionaries), `DspyGEPAResult.best_candidate` returns a compiled DSPy module, `val_subscores` is now `list[dict[Any, float]]`, `per_val_instance_best_candidates` is now `dict[Any, set[int]]`, `best_outputs_valset` is now `dict[Any, list[tuple[int, Prediction]]]`, and `highest_score_achieved_per_val_task` returns a dictionary keyed by validation instance id.
- If passing custom GEPA reflection templates directly, default placeholders have changed: `<curr_instructions>`/`<inputs_outputs_feedback>` are now `<curr_param>`/`<side_info>`. Passing `reflection_prompt_template` via `gepa_kwargs` now raises a `ValueError`; use `instruction_proposer` instead.
Migration Steps
- If your code depends on NumPy features (embeddings, KNN, SIMBA, etc.), install it explicitly using `pip install "dspy[numpy]"`.
- If you inspect detailed GEPA results, update code to handle the new shapes for `DspyGEPAResult.candidates`, `DspyGEPAResult.best_candidate`, `val_subscores`, `per_val_instance_best_candidates`, `best_outputs_valset`, and `highest_score_achieved_per_val_task`.
- If you pass custom GEPA reflection templates, use `instruction_proposer` instead of passing `reflection_prompt_template` via `gepa_kwargs`.
- If you catch specific provider exceptions for LM failures, update handlers to catch `dspy.LMError` or a DSPy subclass instead.
✨ New Features
- `dspy.ReActV2` module introduced, built around native tool calling and using `dspy.History`, `dspy.Tool`, and `dspy.ToolCalls` for trajectory management.
- Support for `parallel_tool_calls` and `Multi-turn native tool call` execution model within ReActV2.
- New typed, provider-neutral LM boundary contract defined by `forward(self, request: dspy.LMRequest) -> dspy.LMResponse` for custom LM authors.
- `BaseLM` now owns shared runtime state and supports sanitized state serialization via `dump_state()` and `load_state()`.
- Callers can now catch `dspy.LMError` or narrower DSPy subclasses for LM failures instead of provider-specific exceptions.
- `dspy.RLM` now supports custom sandbox-serializable values via `SandboxSerializable` for richer object passing into RLM sandboxes.
🐛 Bug Fixes
- LiteLLM imports are now lazy, decoupling the core LM API from specific provider bridges at import time.