DSPy 3.3.0
DSPy 3.3.0 is a feature release with a new experimental way to optimize programs as code, a native-tool-aware ReAct implementation, and the next stage of DSPy's move toward a typed, provider-neutral language-model system.
Most existing DSPy programs should keep working without changes. Review the API changes if you construct Image, Audio, or File values from paths or URLs; use NumPy-backed features from the base install; inspect detailed GEPA results; construct code interpreters directly; use RLM(max_iterations=...); consume raw Responses API tool-call outputs; or catch provider-specific LM exceptions.
We would especially appreciate feedback on Flex, ReActV2, and the typed LM path. These APIs expand what DSPy can optimize and how it can connect to model providers, and real-world usage will help shape their next iterations.
Highlights
Flex Optimizes Program Structure, Not Just Prompts — @michaelisaac-dev
Most DSPy modules fix the shape of a program up front: Predict makes one prediction, ReAct runs a tool loop, and RLM runs a code interpreter in a loop. Optimizers can improve the instructions around that structure, but the structure itself stays fixed. The new experimental dspy.Flex moves the implementation into the search space so GEPA can discover the decomposition instead.
Give Flex the same signature you would give Predict and it starts with the simplest working baseline: one dspy.Predict, or one dspy.RLM when tools are supplied. During compilation, GEPA can rewrite the complete module implementation—changing the predictors, control flow, DSPy primitives, and balance between Python and LM calls—against your metric.
program = dspy.Flex("question -> answer")
optimized = dspy.GEPA(metric=metric, reflection_lm=reflection_lm).compile(
program,
trainset=trainset,
valset=valset,
)
print(optimized.module_src)Optimizer-authored source always runs in a CodeInterpreter sandbox, using dspy.PythonInterpreter by default. Predictor construction and LM calls bridge back to the host, broken candidates score as failures instead of crashing the search, and max_predictor_calls guards against runaway generated programs. Metrics can also accept a program_trace to score how a result was produced—for example, penalizing programs that make too many LM calls.
The optimized module_src is part of the program's serialized state, so saving and loading preserves the implementation GEPA discovered. Flex is experimental, and ordinary GEPA behavior is unchanged when a program does not contain a Flex module.
PR: #10047
ReActV2 and Native Tool-Calling History - @isaacbmiller
dspy.ReActV2 is a new version of ReAct built around native tool calling. It is currently marked as experimental.
The signature now uses dspy.History, dspy.Tool, and dspy.ToolCalls(which can now optionally store dspy.ToolCallResults), rather than the custom next_tool_args and custom trajectory syntax. Using dspy.History also means that messages are now broken up into user/assistant/tool groups rather than one long user message with the trajectory.
This changes the execution model in a few concrete ways:
parallel_tool_callssupport: DSPy preserves each call/result pair by ID. You can do this in native mode or in non-native modeMulti-turn native tool callsupport: Prior tool calls and results can be replayed as assistant and tool messages instead of being flattened into prompt text.- Each turn lives in
dspy.Historyas structured messages rather than one ever-growingtrajectorystring, so providers with prompt caching can reuse stable prefixes more effectively. We have seen up to 50% decreases in cost for some tasks when testing this internally.
ReActV2 converts callables to dspy.Tool, adds an internal submit tool for final outputs, handles unknown tools and tool exceptions, accepts serialized history input, and can force final submission when the model does not call submit.
PRs: #9823, #9824, #9825, #9835
Typed, Provider-Neutral LM Boundary - @MaximeRivest
DSPy is moving from an untyped LM boundary based on prompt, messages, and provider-shaped kwargs toward a typed, provider-neutral contract:
def forward(self, request: dspy.LMRequest) -> dspy.LMResponse:
...The resulting API is a cleaner LM extension point:
- LiteLLM can become an optional compatibility fallback in the planned 3.5+ path, instead of a required part of the core LM contract.
- Custom LM authors can implement one typed
LMRequest -> LMResponsepath instead of guessing which OpenAI/LiteLLM-shaped inputs will arrive. - Custom LMs can translate between DSPy's typed objects and their own provider, local runtime, gateway, or inference stack.
- Adapters can start to depend on DSPy's representation of messages, multimodal content, tool calls, reasoning, citations, usage, cache controls, metadata, and stream events.
Most users do not need to change anything in 3.3. Existing lm(...), modules, and programs keep their current behavior by default.
Try out the typed return path with dspy.context(experimental=True), and the public migration plan explains the staged transition for custom LM and adapter authors.
BaseLM Runtime, Save/Load, Errors, and LiteLLM Decoupling - @MaximeRivest
BaseLM now owns shared runtime state and supports sanitized state serialization through dump_state() and load_state(). Serialized LM state excludes API keys, preserves legacy saved states, and requires explicit opt-in before importing trusted custom LM classes.
Saved programs with custom LMs are easier to reason about, LM copies isolate DSPy-owned mutable state, and callers can catch dspy.LMError or a narrower DSPy subclass instead of depending on provider-specific exception classes. LiteLLM imports are lazy, which keeps the core LM API less coupled to a specific provider bridge at import time.
PRs: #9752, #9820, #9821, #9826
LM and Responses API Updates Since 3.3.0b1 - @MaximeRivest, @isaacbmiller
Since the beta, DSPy has added an explicit BaseLM.forward() contract, exported the typed LM API, supported typed direct calls through BaseLM.__call__, made optional-provider imports thread-safe, and fixed LM state round trips for GPT-5 models.
The OpenAI Responses path now emits Responses-native tool and tool_choice request shapes. Legacy Responses outputs use the same Chat-style tool-call representation as the Chat Completions path, while typed LMToolCallPart objects preserve raw provider fields.
PRs: #9837, #9840, #9841, #9843, #9877, #9999, #10003, #10014, #10026, #10028
API Changes
Breaking Changes
Resource Construction and Validation No Longer Perform Implicit I/O
Constructing or validating dspy.Image, dspy.Audio, and dspy.File values no longer interprets locator-shaped strings as instructions to read a local file or fetch a remote URL. This prevents LM-output parsing, Pydantic validation, and deserialization from silently granting filesystem or network access merely because a value resembles a path or URL.
Resource loading now requires an explicit factory:
| Before 3.3 | DSPy 3.3 | Behavior |
|---|---|---|
Image(path) or Image(url=path)
| Image.from_path(path)
| Read and embed a local image |
Image(url, download=True)
| Image.from_url(url)
| Download and embed a remote image |
Image.from_url(url) or Image.from_url(url, download=False)
| Image(url) or Image(url=url)
| Keep a non-downloading provider-fetched URL reference |
Audio(path)
| Audio.from_path(path)
| Read and embed local audio |
Audio(url)
| Audio.from_url(url)
| Download and embed remote audio |
File(path)
| File.from_path(path)
| Read and embed a local file |
encode_image(path)
| Image.from_path(path)
| Explicitly read a local image |
encode_audio(path_or_url)
| Audio.from_path(path) or Audio.from_url(url)
| Explicitly load audio |
encode_file_to_dict(path)
| File.from_path(path)
| Explicitly read a local file |
There are several related compatibility changes:
Image.from_url()now downloads the resource and returns an embedded data URI. UseImage(url)when the model provider should fetch the reference instead.Image.from_url(..., download=...)and thedownload_images/verifyoptions onencode_image()were removed. Choose reference construction or an explicit factory instead.- Pydantic payloads containing
downloadorverifyare rejected without fetching. The deprecated direct developer callImage(url, download=True)remains available with a warning through 3.3. - The deprecated compatibility call requires a positional source:
Image(url, download=True). Validation-style calls such asImage(url=url, download=True)are rejected. Image.from_file(),Image.from_PIL(), andAudio.from_file()remain as deprecated aliases through 3.3 and are scheduled for removal in 3.4. UseImage.from_path(),Image(pil_image), andAudio.from_path()respectively.- Safe in-memory inputs—including data URIs, bytes, PIL images, audio arrays, structured dictionaries, and existing resource instances—remain supported.
The explicit Image.from_url(url, verify=...) and Audio.from_url(url, verify=...) factories still accept TLS certificate verification controls. The removed verify option applies to encode_image().
Image.from_url() and Audio.from_url() make synchronous caller-initiated requests, follow redirects, and do not provide an SSRF allowlist. Applications remain responsible for validating or allowlisting destinations derived from untrusted input.
PR: #10111 by @isaacbmiller
numpy Is Now Optional
numpy is no longer installed with base dspy. Features that need NumPy now require the numpy extra:
pip install "dspy[numpy]"Affected areas include embeddings, KNN/KNNFewShot, SIMBA, and other NumPy-backed optimizer or retrieval paths. (#9659 by @isaacbmiller)
GEPA Result Shapes Changed With gepa[dspy]==0.1.1
The upstream GEPA 0.1.1 API changed several result structures, and DspyGEPAResult now mirrors those shapes. Users who inspect optimized_program.detailed_results may need to update code:
DspyGEPAResult.candidatesis now a list of compiled DSPy modules, not instruction dictionaries.DspyGEPAResult.best_candidatenow returns a compiled DSPy module.val_subscoresis nowlist[dict[Any, float]], keyed by validation instance id.per_val_instance_best_candidatesis nowdict[Any, set[int]].best_outputs_valsetis nowdict[Any, list[tuple[int, Prediction]]]when tracked.highest_score_achieved_per_val_tasknow returns a dictionary keyed by validation instance id.
If you pass custom GEPA reflection templates directly, note that GEPA 0.1.1 renamed default placeholders from <curr_instructions> / <inputs_outputs_feedback> to <curr_param> / <side_info>. In dspy.GEPA, passing reflection_prompt_template through gepa_kwargs now raises a clear ValueError; use instruction_proposer for custom proposal behavior instead. (#9673 by @BenMcH)
RLM.max_iterations Is Now RLM.max_iters
The RLM constructor now uses the same max_iters name as other iterative DSPy modules:
# Before
rlm = dspy.RLM("context, query -> answer", max_iterations=10)
# DSPy 3.3
rlm = dspy.RLM("context, query -> answer", max_iters=10)PR: #9920 by @isaacbmiller
RLM Rejects Colliding Names and Unexpected Inputs
RLM now validates its execution namespace up front. Construction fails for duplicate tool names, Python-keyword tool names, signature inputs that collide with built-in sandbox functions or tools, and output fields named trajectory or final_reasoning. Invocation also rejects unexpected input fields rather than ignoring them. Rename colliding fields or tools before constructing the module.
PR: #10020 by @isaacbmiller
RLM Sub-LM and Tool Execution Are Stricter
llm_query and llm_query_batched now require the sub-LM to return either a dspy.LMResponse containing text or a non-empty legacy output list whose first item is text. Arbitrary response objects are no longer converted with str(). Batched queries convert dspy.LMError failures to [ERROR] entries, but programming and response-contract errors now propagate.
RLM also invokes user tools through dspy.Tool, so tool argument validation and coercion, default handling, and tool callbacks now apply.
PRs: #10023, #10025 by @isaacbmiller
Code-Executing Modules Use an Interpreter Factory
ProgramOfThought, CodeAct, and RLM now accept interpreter_factory=, a zero-argument callable that creates a fresh CodeInterpreter for each invocation. This isolates concurrent calls and makes interpreter ownership explicit.
program = dspy.ProgramOfThought(
"question -> answer",
interpreter_factory=MyInterpreter,
)To use an existing interpreter, pass it as the first positional argument when invoking the module. DSPy does not shut down a caller-owned interpreter, and reuse is supported only for sequential calls to the same module instance.
These modules no longer expose a constructor-owned interpreter attribute or preserve its sandbox state across calls. Without a caller-owned interpreter, each invocation creates and shuts down a fresh interpreter. Interpreter process and protocol failures are terminal for that interpreter session rather than automatically restarting it, and submitted-code failures now raise CodeExecutionError, a subclass of CodeInterpreterError.
PRs: #10018, #10022 by @isaacbmiller
ToolCalls Uses DSPy's Native Serialized Shape
dspy.ToolCalls.format() and Pydantic serialization now represent each call as {"name": ..., "args": ...} rather than the prior OpenAI-style {"type": "function", "function": {"name": ..., "arguments": ...}} shape. Code that persists ToolCalls, calls .format() directly, or forwards the result to an OpenAI-compatible endpoint must update its conversion logic. Provider adapters still produce the wire shape required by their APIs.
PR: #9823 by @isaacbmiller
Direct BaseLM Defaults and Copy Semantics Changed
The direct BaseLM constructor now defaults temperature and max_tokens to None instead of 0.0 and 1000. This primarily affects custom LM subclasses that inherit or delegate to BaseLM.__init__; ordinary dspy.LM already used the provider-default None values.
BaseLM.copy() now shallow-copies subclass-owned attributes while separately copying DSPy-owned mutable runtime containers. Custom LM subclasses that relied on arbitrary mutable attributes being deep-copied should override copy() or copy that state explicitly.
PR: #9821 by @MaximeRivest
Responses Tool Calls Use the Chat-Compatible Legacy Shape
Legacy output from dspy.LM(..., model_type="responses") now represents tool calls in the same shape as the Chat Completions path:
{
"type": "function",
"id": call_id,
"function": {
"name": tool_name,
"arguments": arguments,
},
}The text key is now always present. Raw Responses item IDs, status, and provider fields remain available through LMToolCallPart.provider_data on the typed path.
PR: #10028 by @isaacbmiller
LM Error Types Are DSPy-Normalized
LM failures are now mapped into DSPy exception classes. This should make LM error handling more consistent, but code that catches provider-specific or LiteLLM-specific errors directly may need to catch dspy.LMError or a narrower DSPy subclass. (#9826 by @MaximeRivest)
ChatAdapter and JSONAdapter no longer retry with an alternate output format after an LMError; provider and transport failures propagate directly. TwoStepAdapter now raises dspy.AdapterParseError rather than ValueError for local extraction or parsing failures, while extraction-LM failures propagate as dspy.LMError.
New and Updated APIs
- Added exported
LMRequest,LMResponse, typed message/content classes, tool specifications, reasoning and cache configuration, usage records, history entries, and streaming types. (#9786, #9841, #9877 by @MaximeRivest) - Added
forward_contract = "typed_lm"and an explicitBaseLM.forward(request) -> LMResponsecontract for new custom LM implementations. (#9843, #9877 by @MaximeRivest) - Added
Signature.append_instructions()for deriving a signature with additional instructions without mutating the original. (#9923 by @mathurk1) - Added experimental
dspy.Flexand trace-aware GEPA metrics through the optional sixthprogram_traceparameter. (#10047 by @michaelisaac-dev) - Added experimental
dspy.ReActV2, structured native tool-call history, and tool-result replay. (#9823, #9824, #9825, #9836 by @isaacbmiller) - Added explicit
from_path()andfrom_url()resource-loading factories forImageandAudio, plusFile.from_path(), while keeping construction and validation free of implicit host I/O. (#10111 by @isaacbmiller) - Made
BaseLMown and serialize shared runtime state.copy()now makes a shallow object copy, resets history, and separately copies the callbacks list and kwargs dictionary. (#9820, #9821 by @MaximeRivest) - Excluded defaulted arguments from required tool parameters and stabilized open-ended tool argument schemas. (#9971 by @katherineahn, #10012 by @isaacbmiller)
- Protected RLM-owned namespaces, normalized sub-LM responses, and routed tool execution through
dspy.Tool. (#10020, #10023, #10025 by @isaacbmiller) - Made interpreter process and protocol failures terminal for the affected session and isolated interpreters per invocation. (#10018, #10022 by @isaacbmiller)
- Improved interpreter transport for Pydantic objects, scalar values, dataclasses, named tuples, and non-finite floats. (#9753 by @Archelunch, #9991 by @Vinay152003, #10015 and #10049 by @migurski)
- Made module
load_state()transactional, isolated BootstrapFinetune data by predictor, validated random-search restrictions up front, and preserved callback lineage in parallel workers. (#9741 by @ashishSoni1234, #10005 and #10043 by @isaacbmiller, #10033 by @chuenchen309)
Compatibility Notices
- OpenAI 1.66.2 is now the supported minimum. (#9999 by @isaacbmiller)
- LiteLLM 1.65.8 is required for the reasoning-capability API. (#10003 by @isaacbmiller)
- The LangChain extra now requires LangChain Core 0.3.0 or newer. (#10004 by @isaacbmiller)
- The base install no longer depends directly on
asyncer,xxhash, ortypeguard; DSPy now uses AnyIO and standard-library equivalents. (#9733, #9734, #9735 by @isaacbmiller) dspy.utils.hasher.Hashernow uses SHA-256 instead of xxhash64. Hash strings, hash-derived fine-tuning filenames, and deterministic bootstrap trace selection may change; LM response-cache keys are unaffected. (#9734 by @isaacbmiller)Module.set_lm(),get_lm(), and state loading now include module-valued parameter leaves such asFlex, rather than onlyPredict. Custom classes that combineModuleandParametershould expose compatible LM state and acceptallow_unsafe_lm_state=when overridingload_state(). (#10047 by @michaelisaac-dev)
Full PR List
Language Models and Adapters — 23 PRs
- #9718 — Handle missing usage from truncated Responses API responses — @isaacbmiller
- #9752 — Make LiteLLM imports lazy — @MaximeRivest
- #9786 — Add core language-model types — @MaximeRivest
- #9791 — Add exact adapter-format message tests — @MaximeRivest
- #9792 — Expand exact adapter-format message coverage — @MaximeRivest
- #9802 — Introduce a normalized LM boundary for adapters — @MaximeRivest
- #9820 — Support
BaseLMstate serialization — @MaximeRivest - #9821 — Make
BaseLMown shared LM runtime state — @MaximeRivest - #9826 — Normalize DSPy LM errors — @MaximeRivest
- #9828 — Add the normalized LM API migration plan — @MaximeRivest
- #9830 — Fix cached-provider Pydantic serializers — @isaacbmiller
- #9834 — Silence missing-input warnings for optional fields — @MaximeRivest
- #9837 — Fix GPT-5 LM state round trips — @isaacbmiller
- #9840 — Make lazy optional imports thread-safe — @MaximeRivest
- #9841 — Export typed LM API symbols — @MaximeRivest
- #9843 — Add an explicit
BaseLM.forward()contract — @MaximeRivest - #9877 — Make
BaseLM.__call__support typedLMRequestandLMResponsewhile preserving the legacy default — @MaximeRivest - #9999 — Declare OpenAI 1.66.2 as the supported floor — @isaacbmiller
- #10003 — Require the LiteLLM reasoning-capability API — @isaacbmiller
- #10014 — Omit absent Responses tool fields — @isaacbmiller
- #10026 — Send Responses-native tool and
tool_choiceshapes — @isaacbmiller - #10028 — Normalize Responses output parsing and unify the legacy tool-call shape — @isaacbmiller
- #10111 — Prevent implicit resource loading during validation — @isaacbmiller
Agents, Tools, and Interpreters — 25 PRs
- #9411 — Add
SandboxSerializablefor custom RLM types — @kmad - #9748 — Resolve symlinks for Deno
--allow-readpaths — @npow - #9753 — Transport Pydantic models as JSON through the interpreter — @Archelunch
- #9754 — Await asynchronous tool functions in
PythonInterpreter— @Archelunch - #9823 — Preserve tool-call IDs and add tool results — @isaacbmiller
- #9824 — Replay native tool-call history through adapters — @isaacbmiller
- #9825 — Add ReActV2 — @isaacbmiller
- #9835 — Render tool calls in
inspect_history()— @isaacbmiller - #9836 — Mark ReActV2 experimental — @isaacbmiller
- #9873 — Add a Diving Deeper page for
dspy.RLM— @dbreunig - #9920 — Rename RLM
max_iterationstomax_iters— @isaacbmiller - #9971 — Exclude defaulted arguments from required function-calling parameters — @katherineahn
- #9989 — Revise Deno installation instructions in the RLM documentation — @migurski
- #9991 — Serialize
inf,-inf, andnanas valid Python literals — @Vinay152003 - #10002 — Declare the MCP hello tool's actual return type — @isaacbmiller
- #10007 — Propagate DSPy context to batched RLM subqueries — @isaacbmiller
- #10012 — Stabilize open tool-argument schemas — @isaacbmiller
- #10015 — Preserve scalar tool results in the Python-interpreter sandbox — @migurski
- #10018 — Make interpreter failures terminal — @isaacbmiller
- #10020 — Protect RLM-owned namespaces — @isaacbmiller
- #10022 — Isolate interpreters per invocation — @isaacbmiller
- #10023 — Normalize RLM sub-LM responses — @isaacbmiller
- #10025 — Execute RLM tools through
dspy.Tool— @isaacbmiller - #10049 — Serialize dataclass and named-tuple tool results in RLM — @migurski
- #10054 — Prevent
ReAct.truncate_trajectory()from emptying a single-tool-call trajectory — @chuenchen309
Core APIs and Optimizers — 10 PRs
- #9659 — Make NumPy an optional dependency — @isaacbmiller
- #9673 — Update
DspyGEPAResultfor GEPA 0.1.1 — @BenMcH - #9705 — Raise
ValueErrorwhen no valid program is found — @Ricardo-M-L - #9741 — Make
load_state()transactional — @ashishSoni1234 - #9767 — Remove deprecated prefix arguments from internal Avatar signatures — @nullhack
- #9923 — Add
Signature.append_instructions()— @mathurk1 - #10005 — Isolate BootstrapFinetune data by predictor — @isaacbmiller
- #10033 — Validate BootstrapFewShotWithRandomSearch restrictions up front — @chuenchen309
- #10043 — Preserve callback call lineage in parallel workers — @isaacbmiller
- #10047 — Add experimental
dspy.Flexand its GEPA extension — @michaelisaac-dev
Documentation and Community — 16 PRs plus one direct commit
- #9771 — Correct a mismatched closing code fence in the README — @abhicris
b16d109— Fix the FAQ Learn-guide link — @cosmopolitan033- #9855 — Revamp the home page and restructure learning and reference documentation — @dbreunig
- #9856 — Update homepage release status — @isaacbmiller
- #9875 — Add a link to the example dataset — @dbreunig
- #9886 — Fix the RAGatouille typo and replace deprecated
dspy.OpenAIreferences — @FBISiri - #9889 — Fix the entity-extraction tutorial dataset — @10gyal
- #9893 — Fix a typo in the customer-service agent tutorial — @Maxim-Mazurok
- #9902 — Add API category index pages to prevent directory URL 404s — @migurski
- #9908 — Correct typos in comments and error messages — @arnav-144p
- #9953 — Move class-level docstrings to
ChainOfThoughtandBestOfN— @katherineahn - #9970 — Add the Microsoft AI logo, use case, and links to the community page — @dbreunig
- #10080 — Fix article usage in the MIPROv2 documentation — @SpiliosDimakopoulos
- #10081 — Fix article usage in the modules documentation — @SpiliosDimakopoulos
- #10082 — Fix article usage in the BestOfN and Refine documentation — @SpiliosDimakopoulos
- #10083 — Fix article usage in the FAQ — @SpiliosDimakopoulos
- #10084 — Fix a non-standard word in a section heading — @SpiliosDimakopoulos
CI, Testing, and Release Infrastructure — 17 PRs
- #9602 — Update
actions/setup-pythonfrom 3.1.4 to 6.2.0 — @dependabot - #9742 — Add zizmor and actionlint to CI — @isaacbmiller
- #9743 — Fix zizmor and actionlint findings across workflows — @isaacbmiller
- #9745 — Add
security-eventspermission for SARIF uploads — @isaacbmiller - #9746 — Remove
git-auto-commit-actionfrom the release workflow — @isaacbmiller - #9787 — Update
zizmor-actionfrom 0.5.3 to 0.5.5 — @dependabot - #9795 — Isolate the DSPy cache in tests — @isaacbmiller
- #9844 — Mark KNN tests as extra-dependent — @isaacbmiller
- #9845 — Update versions for 3.3.0b1 — @github-actions
- #9854 — Update
zizmor-actionfrom 0.5.5 to 0.5.6 — @dependabot - #9909 — Update
actions/checkoutfrom 6.0.2 to 6.0.3 — @dependabot - #9910 — Update
astral-sh/setup-uvfrom 8.1.0 to 8.2.0 — @dependabot - #10000 — Audit dependency-range boundaries — @isaacbmiller
- #10041 — Pin Ollama to 0.31.2 and add a warm-up health check — @isaacbmiller
- #10078 — Parallelize pytest with xdist and simplify CI jobs — @isaacbmiller
- #10079 — Remove the AMX backend CI variant — @isaacbmiller
- #10089 — Pool Deno/Pyodide interpreters across tests — @isaacbmiller
Dependencies — 18 PRs
- #9624 — Update
mkdocstrings-pythonfrom 1.16.7 to 2.0.3 — @dependabot - #9729 — Update
typeguardfrom 4.4.3 to 4.5.1 — @dependabot - #9730 — Update
anyiofrom 4.9.0 to 4.13.0 — @dependabot - #9731 — Update
tenacityfrom 9.1.2 to 9.1.4 — @dependabot - #9732 — Update
cachetoolsfrom 6.1.0 to 7.0.6 — @dependabot - #9733 — Remove
asyncerand use AnyIO directly — @isaacbmiller - #9734 — Replace
xxhashwithhashlib.sha256— @isaacbmiller - #9735 — Replace
typeguardwith standard-library type checking — @isaacbmiller - #9757 — Update
cachetoolsfrom 7.0.6 to 7.1.1 — @dependabot - #9759 — Update
mistunefrom 3.2.0 to 3.2.1 — @dependabot - #9760 — Update
weaviate-clientfrom 4.5.7 to 4.21.0 — @dependabot - #9761 — Update documentation
urllib3from 1.26.6 to 2.7.0 — @dependabot - #9762 — Update documentation
mistunefrom 3.2.0 to 3.2.1 — @dependabot - #9789 — Update
anthropicfrom 0.89.0 to 0.102.0 — @dependabot - #9790 — Update
regexfrom 2025.11.3 to 2026.5.9 — @dependabot - #10004 — Declare LangChain Core 0.3.0 as the supported floor — @isaacbmiller
- #10059 — Update documentation
mistunefrom 3.2.1 to 3.3.3 — @dependabot - #10077 — Update
mkdocstringsfrom 1.0.4 to 1.0.6 — @dependabot
Contributors
Thank you to everyone who contributed to DSPy 3.3.0:
- @isaacbmiller
- @MaximeRivest
- @kmad
- @BenMcH
- @Ricardo-M-L
- @ashishSoni1234
- @npow
- @Archelunch
- @nullhack
- @abhicris
- @cosmopolitan033
- @dbreunig
- @FBISiri
- @10gyal
- @Maxim-Mazurok
- @migurski
- @arnav-144p
- @mathurk1
- @katherineahn
- @Vinay152003
- @chuenchen309
- @SpiliosDimakopoulos
- @michaelisaac-dev
Automation contributions were made by @dependabot and @github-actions.
First-Time Contributors
- @kmad made their first contribution in #9411.
- @ashishSoni1234 made their first contribution in #9741.
- @npow made their first contribution in #9748.
- @Archelunch made their first contributions in #9753 and #9754.
- @nullhack made their first contribution in #9767.
- @cosmopolitan033 made their first contribution in
b16d109. - @dbreunig made their first contribution in #9855.
- @FBISiri made their first contribution in #9886.
- @10gyal made their first contribution in #9889.
- @Maxim-Mazurok made their first contribution in #9893.
- @migurski made their first contribution in #9902.
- @arnav-144p made their first contribution in #9908.
- @mathurk1 made their first contribution in #9923.
- @katherineahn made their first contribution in #9953.
- @Vinay152003 made their first contribution in #9991.
- @chuenchen309 made their first contribution in #10033.
- @SpiliosDimakopoulos made their first contribution in #10080.
Full Changelog: 3.2.1...3.3.0