From 39b99b3c14643ddecd2c9814d30f5a3804a55865 Mon Sep 17 00:00:00 2001 From: Amp Date: Tue, 11 Aug 2026 14:42:18 +0000 Subject: [PATCH 1/3] Deprecate CodeAct and ProgramOfThought Amp-Thread-ID: https://ampcode.com/threads/T-019fed60-80a9-766c-80b3-73ee5487fe65 Co-authored-by: Isaac Miller --- docs/docs/api/modules/CodeAct.md | 4 ++++ docs/docs/api/modules/ProgramOfThought.md | 4 ++++ dspy/predict/code_act.py | 22 +++++++++++++++++---- dspy/predict/program_of_thought.py | 9 +++++++++ tests/predict/test_code_act.py | 24 ++++++++++++++++------- tests/predict/test_program_of_thought.py | 11 +++++++++-- 6 files changed, 61 insertions(+), 13 deletions(-) diff --git a/docs/docs/api/modules/CodeAct.md b/docs/docs/api/modules/CodeAct.md index d42707d8c6..bea89e4ba6 100644 --- a/docs/docs/api/modules/CodeAct.md +++ b/docs/docs/api/modules/CodeAct.md @@ -1,5 +1,9 @@ # dspy.CodeAct +!!! warning "Deprecated" + + `CodeAct` is deprecated and will be removed in DSPy 3.5. [`RLM`](RLM.md) is the preferred replacement. + ::: dspy.CodeAct handler: python diff --git a/docs/docs/api/modules/ProgramOfThought.md b/docs/docs/api/modules/ProgramOfThought.md index 91efe7194e..a6ff9c3013 100644 --- a/docs/docs/api/modules/ProgramOfThought.md +++ b/docs/docs/api/modules/ProgramOfThought.md @@ -1,5 +1,9 @@ # dspy.ProgramOfThought +!!! warning "Deprecated" + + `ProgramOfThought` is deprecated and will be removed in DSPy 3.5. [`RLM`](RLM.md) is the preferred replacement. + ::: dspy.ProgramOfThought handler: python diff --git a/dspy/predict/code_act.py b/dspy/predict/code_act.py index f53023993e..ad4912f202 100644 --- a/dspy/predict/code_act.py +++ b/dspy/predict/code_act.py @@ -1,5 +1,6 @@ import inspect import logging +import warnings from typing import Callable import dspy @@ -12,8 +13,12 @@ logger = logging.getLogger(__name__) + class CodeAct(ReAct, ProgramOfThought): """ + .. deprecated:: 3.5 + CodeAct is deprecated. RLM is the preferred replacement. + CodeAct is a module that utilizes the Code Interpreter and predefined tools to solve the problem. """ @@ -45,15 +50,18 @@ def factorial(n): act(n=5) # 120 ``` """ + warnings.warn( + "CodeAct is deprecated and will be removed in 3.5. RLM is the preferred replacement.", + DeprecationWarning, + stacklevel=2, + ) _validate_interpreter_factory(interpreter_factory) self.signature = ensure_signature(signature) self.max_iters = max_iters self.history = [] tools = [t if isinstance(t, Tool) else Tool(t) for t in tools] - if any( - not inspect.isfunction(tool.func) for tool in tools - ): + if any(not inspect.isfunction(tool.func) for tool in tools): raise ValueError("CodeAct only accepts functions and not callable objects.") tools = {tool.name: tool for tool in tools} @@ -62,7 +70,13 @@ def factorial(n): codeact_signature = ( dspy.Signature({**self.signature.input_fields}, "\n".join(instructions)) .append("trajectory", dspy.InputField(), type_=str) - .append("generated_code", dspy.OutputField(desc="Python code that when executed, produces output relevant to answering the question"), type_=str) + .append( + "generated_code", + dspy.OutputField( + desc="Python code that when executed, produces output relevant to answering the question" + ), + type_=str, + ) .append("finished", dspy.OutputField(desc="a boolean flag to determine if the process is done"), type_=bool) ) diff --git a/dspy/predict/program_of_thought.py b/dspy/predict/program_of_thought.py index 175e027bee..df32c5ad2e 100644 --- a/dspy/predict/program_of_thought.py +++ b/dspy/predict/program_of_thought.py @@ -1,6 +1,7 @@ import json import logging import re +import warnings from collections.abc import Callable, Iterator from contextlib import contextmanager @@ -23,6 +24,9 @@ class ProgramOfThought(Module): """ + .. deprecated:: 3.5 + ProgramOfThought is deprecated. RLM is the preferred replacement. + A DSPy module that runs Python programs to solve a problem. This module requires deno to be installed. Please install deno following https://docs.deno.com/runtime/getting_started/installation/ @@ -51,6 +55,11 @@ def __init__( callable may be invoked concurrently, and DSPy shuts down each interpreter it returns. """ super().__init__() + warnings.warn( + "ProgramOfThought is deprecated and will be removed in 3.5. RLM is the preferred replacement.", + DeprecationWarning, + stacklevel=2, + ) _validate_interpreter_factory(interpreter_factory) self.signature = signature = ensure_signature(signature) self.max_iters = max_iters diff --git a/tests/predict/test_code_act.py b/tests/predict/test_code_act.py index 471b16a07a..49fb61d356 100644 --- a/tests/predict/test_code_act.py +++ b/tests/predict/test_code_act.py @@ -31,10 +31,20 @@ class RaisingPredictor: def __call__(self, **kwargs): raise ValueError("unexpected extractor failure") + def add(a: float, b: float) -> float: "add two numbers" return a + b + +def test_codeact_warns_that_rlm_is_preferred(): + with pytest.warns( + DeprecationWarning, + match=r"CodeAct is deprecated and will be removed in 3\.5\. RLM is the preferred replacement\.", + ): + CodeAct(BasicQA, tools=[add]) + + def test_codeact_code_generation(pooled_interpreter): lm = DummyLM( [ @@ -61,10 +71,12 @@ class ExtremumFinder(Signature): maximum = dspy.OutputField(desc="The maximum of the given numbers") minimum = dspy.OutputField(desc="The minimum of the given numbers") + def extract_maximum_minimum(input_list: str) -> dict[str, float]: numbers = list(map(float, input_list.split(","))) return {"maximum": max(numbers), "minimum": min(numbers)} + def test_codeact_support_multiple_fields(pooled_interpreter): lm = DummyLM( [ @@ -82,7 +94,7 @@ def test_codeact_support_multiple_fields(pooled_interpreter): assert res.maximum == "6" assert res.minimum == "2" assert res.trajectory == { - "code_output_0": '"{\'maximum\': 6.0, \'minimum\': 2.0}\\n"', + "code_output_0": "\"{'maximum': 6.0, 'minimum': 2.0}\\n\"", "generated_code_0": "result = extract_maximum_minimum('2, 3, 5, 6')\nprint(result)", } @@ -137,7 +149,7 @@ def test_codeact_code_execution_failure(pooled_interpreter): assert res.answer == "2" assert res.trajectory == { "generated_code_0": "unknown+1", - "observation_0": 'Failed to execute the generated code: NameError: ["name \'unknown\' is not defined"]', + "observation_0": "Failed to execute the generated code: NameError: [\"name 'unknown' is not defined\"]", "generated_code_1": "result = add(1,1)\nprint(result)", "code_output_1": '"2\\n"', } @@ -157,8 +169,7 @@ def execute(code, variables): program.codeact = StaticPredictor(generated_code="print(add(1, 1))", finished=True) program.extractor = StaticPredictor(answer="2") devset = [ - dspy.Example(question=f"What is 1+1? ({index})", answer="2").with_inputs("question") - for index in range(4) + dspy.Example(question=f"What is 1+1? ({index})", answer="2").with_inputs("question") for index in range(4) ] result = dspy.Evaluate( @@ -197,9 +208,7 @@ def test_codeact_factory_creates_fresh_interpreter_per_sequential_call(): def test_codeact_allows_interpreter_as_signature_input(): factory = MockInterpreterFactory(responses=["", "CPython\n"]) program = CodeAct("interpreter -> answer", tools=[add], interpreter_factory=factory) - program.codeact = Mock( - return_value=dspy.Prediction(generated_code="print(interpreter)", finished=True) - ) + program.codeact = Mock(return_value=dspy.Prediction(generated_code="print(interpreter)", finished=True)) program.extractor = StaticPredictor(answer="CPython") result = program(interpreter="CPython") @@ -272,6 +281,7 @@ class CustomTool: def __call__(self, a: float, b: float) -> float: return a + b + def test_codeact_tool_validation(): with pytest.raises(ValueError, match=r"CodeAct only accepts functions and not callable objects."): CodeAct(BasicQA, tools=[CustomTool()]) diff --git a/tests/predict/test_program_of_thought.py b/tests/predict/test_program_of_thought.py index 3b4084a11a..a08a808d56 100644 --- a/tests/predict/test_program_of_thought.py +++ b/tests/predict/test_program_of_thought.py @@ -39,6 +39,14 @@ def __call__(self): return interpreter +def test_pot_warns_that_rlm_is_preferred(): + with pytest.warns( + DeprecationWarning, + match=r"ProgramOfThought is deprecated and will be removed in 3\.5\. RLM is the preferred replacement\.", + ): + ProgramOfThought(BasicQA) + + @pytest.mark.deno def test_pot_code_generation(pooled_interpreter): lm = DummyLM( @@ -123,8 +131,7 @@ def test_pot_evaluate_creates_one_interpreter_per_example(): pot.code_generate = StaticPredictor(generated_code="SUBMIT({'answer': 2})") pot.generate_output = StaticPredictor(answer="2") devset = [ - dspy.Example(question=f"What is 1+1? ({index})", answer="2").with_inputs("question") - for index in range(4) + dspy.Example(question=f"What is 1+1? ({index})", answer="2").with_inputs("question") for index in range(4) ] result = dspy.Evaluate( From b2438148a9fd86216e2d78aa5ebb55271129668a Mon Sep 17 00:00:00 2001 From: Amp Date: Tue, 11 Aug 2026 16:28:58 +0000 Subject: [PATCH 2/3] Clarify deprecation timeline Amp-Thread-ID: https://ampcode.com/threads/T-019fed60-80a9-766c-80b3-73ee5487fe65 Co-authored-by: Isaac Miller --- dspy/predict/code_act.py | 2 +- dspy/predict/program_of_thought.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dspy/predict/code_act.py b/dspy/predict/code_act.py index ad4912f202..118561cde9 100644 --- a/dspy/predict/code_act.py +++ b/dspy/predict/code_act.py @@ -16,7 +16,7 @@ class CodeAct(ReAct, ProgramOfThought): """ - .. deprecated:: 3.5 + .. deprecated:: 3.4 CodeAct is deprecated. RLM is the preferred replacement. CodeAct is a module that utilizes the Code Interpreter and predefined tools to solve the problem. diff --git a/dspy/predict/program_of_thought.py b/dspy/predict/program_of_thought.py index df32c5ad2e..ef21e89a7c 100644 --- a/dspy/predict/program_of_thought.py +++ b/dspy/predict/program_of_thought.py @@ -24,7 +24,7 @@ class ProgramOfThought(Module): """ - .. deprecated:: 3.5 + .. deprecated:: 3.4 ProgramOfThought is deprecated. RLM is the preferred replacement. A DSPy module that runs Python programs to solve a problem. From 050343ed0f12eaaa6f3e81e700b3922da121b8f2 Mon Sep 17 00:00:00 2001 From: Amp Date: Tue, 11 Aug 2026 16:48:17 +0000 Subject: [PATCH 3/3] Remove deprecated modules from Flex docs Amp-Thread-ID: https://ampcode.com/threads/T-019fed60-80a9-766c-80b3-73ee5487fe65 Co-authored-by: Isaac Miller --- docs/docs/diving-deeper/flex.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/diving-deeper/flex.md b/docs/docs/diving-deeper/flex.md index e9fddbc3a2..c47830733c 100644 --- a/docs/docs/diving-deeper/flex.md +++ b/docs/docs/diving-deeper/flex.md @@ -90,7 +90,7 @@ The optimizer-authored code does not run against the real `dspy` package. Inside **Available** - `dspy.Module` — the base class the generated source subclasses. `__init__` assigns predictors; `forward` runs in the sandbox. -- `dspy.Predict`, `dspy.ChainOfThought`, `dspy.ReAct`, `dspy.ReActV2`, `dspy.RLM`, `dspy.CodeAct`, `dspy.ProgramOfThought` — constructed in the sandbox but *built on the host*, where the real LM calls happen. Constructor kwargs cross as JSON. +- `dspy.Predict`, `dspy.ChainOfThought`, `dspy.ReAct`, `dspy.ReActV2`, `dspy.RLM` — constructed in the sandbox but *built on the host*, where the real LM calls happen. Constructor kwargs cross as JSON. - `dspy.Signature("inputs -> outputs", "instructions")` — the string form only, used to give an inner predictor its instructions. It is a marker the host turns back into a real `Signature`, not the class: it has no methods, no `with_instructions()`, and no `dspy.InputField` / `dspy.OutputField` class form. - `dspy.Prediction(**fields)` — the return value of `forward`. Holds fields; it is not the host `Prediction` type. - `dspy.Tool(func)` — a pass-through wrapper. Only tools you passed to `dspy.Flex(tools=...)` can be handed to a bridged sub-predictor; they are already in scope by name, so wrapping is optional.