Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/docs/api/modules/CodeAct.md
Original file line number Diff line number Diff line change
@@ -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.

<!-- START_API_REF -->
::: dspy.CodeAct
handler: python
Expand Down
4 changes: 4 additions & 0 deletions docs/docs/api/modules/ProgramOfThought.md
Original file line number Diff line number Diff line change
@@ -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.

<!-- START_API_REF -->
::: dspy.ProgramOfThought
handler: python
Expand Down
22 changes: 18 additions & 4 deletions dspy/predict/code_act.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import inspect
import logging
import warnings
from typing import Callable

import dspy
Expand All @@ -12,8 +13,12 @@

logger = logging.getLogger(__name__)


class CodeAct(ReAct, ProgramOfThought):
"""
.. deprecated:: 3.5
CodeAct is deprecated. RLM is the preferred replacement.
Comment thread
isaacbmiller marked this conversation as resolved.
Outdated
Comment on lines +19 to +20

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Deprecation directive records the wrong release

This release is version 3.3.0, but the directive says 3.4. Generated API documentation will therefore tell users that CodeAct was deprecated in a later release than the one that actually introduced the deprecation. Update this directive and the matching directive in program_of_thought.py to .. deprecated:: 3.3.0; the separate 3.5 removal target can remain unchanged.

Artifacts

Deprecation directive check script

  • This authored script extracts the two target directive versions from a selected Git revision and uses Sphinx when installed or a semantic fallback when unavailable, with the takeaway that it directly verifies each documented deprecated-since value.

Directive versions before clarification

  • The executed check at commit 39b99b3 reports both target directives as deprecated since 3.5, with the takeaway that the original PR state did not document 3.3.0.

Current directive versions

  • The executed check at commit b243814 reports both target directives as deprecated since 3.4, with the takeaway that current PR code still documents the wrong introduction version.

Release metadata at introduction

  • The executed Git capture at commit 39b99b3 shows `version="3.3.0"` and `__version__="3.3.0"`, with the takeaway that the deprecation was introduced in release 3.3.0.

Release metadata at current PR

  • The executed Git capture at commit b243814 shows `version="3.3.0"` and `__version__="3.3.0"`, with the takeaway that the current PR remains a 3.3.0 release.

Tracked files unchanged check

  • The executed diff check exited successfully for both target files and release metadata, with the takeaway that validation did not modify tracked files.

View artifacts

T-Rex Ran code and verified through T-Rex


CodeAct is a module that utilizes the Code Interpreter and predefined tools to solve the problem.
"""

Expand Down Expand Up @@ -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}

Expand All @@ -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)
)

Expand Down
9 changes: 9 additions & 0 deletions dspy/predict/program_of_thought.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import logging
import re
import warnings
from collections.abc import Callable, Iterator
from contextlib import contextmanager

Expand All @@ -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/

Expand Down Expand Up @@ -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
Expand Down
24 changes: 17 additions & 7 deletions tests/predict/test_code_act.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
[
Expand All @@ -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(
[
Expand All @@ -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)",
}

Expand Down Expand Up @@ -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"',
}
Expand All @@ -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(
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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()])
11 changes: 9 additions & 2 deletions tests/predict/test_program_of_thought.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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(
Expand Down