Repository: stanfordnlp/dspy
Pull request #8538 (2025-07-16 12:27:45)

update cheatsheet
Add the newly added APIs to the cheatsheet.


Patch:
diff --git a/docs/docs/cheatsheet.md b/docs/docs/cheatsheet.md
index 76778cb6..f445f6d6 100644
--- a/docs/docs/cheatsheet.md
+++ b/docs/docs/cheatsheet.md
@@ -40,7 +40,7 @@ print(f"Question: {question}")
 print(f"Final Predicted Answer (after ProgramOfThought process): {result.answer}")
 ```
 
-### dspy.ReACT
+### dspy.ReAct
 
 ```python
 react_module = dspy.ReAct(BasicQA)
@@ -70,6 +70,38 @@ for idx, passage in enumerate(topK_passages):
     print(f'{idx+1}]', passage, '\n')
 ```
 
+### dspy.CodeAct
+
+```python
+from dspy import CodeAct
+
+def factorial(n):
+    """Calculate factorial of n"""
+    if n == 1:
+        return 1
+    return n * factorial(n-1)
+
+act = CodeAct("n->factorial", tools=[factorial])
+result = act(n=5)
+result # Returns 120
+```
+
+### dspy.Parallel
+
+```python
+import dspy
+
+parallel = dspy.Parallel(num_threads=2)
+predict = dspy.Predict("question -> answer")
+result = parallel(
+    [
+        (predict, dspy.Example(question="1+1").with_inputs("question")),
+        (predict, dspy.Example(question="2+2").with_inputs("question"))
+    ]
+)
+result
+```
+
 ## DSPy Metrics
 
 ### Function as Metric
@@ -355,6 +387,78 @@ optimized_program = simba.compile(student=your_dspy_program, trainset=trainset)
 ```
 
 
+## DSPy Tools and Utilities
+
+### dspy.Tool
+
+```python
+import dspy
+
+def search_web(query: str) -> str:
+    """Search the web for information"""
+    return f"Search results for: {query}"
+
+tool = dspy.Tool(search_web)
+result = tool(query="Python programming")
+```
+
+### dspy.streamify
+
+```python
+import dspy
+import asyncio
+
+predict = dspy.Predict("question->answer")
+
+stream_predict = dspy.streamify(
+    predict,
+    stream_listeners=[dspy.streaming.StreamListener(signature_field_name="answer")],
+)
+
+async def read_output_stream():
+    output_stream = stream_predict(question="Why did a chicken cross the kitchen?")
+
+    async for chunk in output_stream:
+        print(chunk)
+
+asyncio.run(read_output_stream())
+```
+
+
+### dspy.asyncify
+
+```python
+import dspy
+
+dspy_program = dspy.ChainOfThought("question -> answer")
+dspy_program = dspy.asyncify(dspy_program)
+
+asyncio.run(dspy_program(question="What is DSPy"))
+```
+
+
+### Track Usage
+
+```python
+import dspy
+dspy.settings.configure(track_usage=True)
+
+result = dspy.ChainOfThought(BasicQA)(question="What is 2+2?")
+print(f"Token usage: {result.get_lm_usage()}")
+```
+
+### dspy.configure_cache
+
+```python
+import dspy
+
+# Configure cache settings
+dspy.configure_cache(
+    enable_disk_cache=False,
+    enable_memory_cache=False,
+)
+```
+
 ## DSPy `Refine` and `BestofN`
 
 >`dspy.Suggest` and `dspy.Assert` are replaced by `dspy.Refine` and `dspy.BestofN` in DSPy 2.6.
diff --git a/docs/docs/community/community-resources.md b/docs/docs/community/community-resources.md
index 93173737..7adf149a 100644
--- a/docs/docs/community/community-resources.md
+++ b/docs/docs/community/community-resources.md
@@ -60,7 +60,7 @@ Weaviate has a directory of 10 amazing notebooks and 6 podcasts!
 Huge shoutout to them for the massive support ❤️. See the [Weaviate DSPy directory](https://weaviate.io/developers/weaviate/more-resources/dspy).
 
 
-TODO: This list in particular is highly incomplete. There are dozens of other good ones. To allow space, divide into opintionated blogs / podcasts / interviews vs. tutorials & talks.
+This list represents a curated selection of DSPy resources. We continuously add new content as it becomes available in the community.
 
 Credit: Some of these resources were originally compiled in the [Awesome DSPy](https://github.com/ganarajpr/awesome-dspy/tree/master) repo.
 
diff --git a/docs/docs/community/use-cases.md b/docs/docs/community/use-cases.md
index 02e7204a..5f9c3c31 100644
--- a/docs/docs/community/use-cases.md
+++ b/docs/docs/community/use-cases.md
@@ -2,7 +2,7 @@
 
 We often get questions like “How are people using DSPy in practice?”, both in production and for research. This list was created to collect a few pointers and to encourage others in the community to add their own work below.
 
-This list is ever-expanding and highly incomplete (WIP)! We'll be adding a bunch more. If you would like to add your product or research to this list, please submit a PR.
+This list is continuously growing. We regularly add new use cases and welcome community contributions. If you would like to add your product or research to this list, please submit a PR.
 
 ## A Few Company Use Cases
 
@@ -35,7 +35,7 @@ This list is ever-expanding and highly incomplete (WIP)! We'll be adding a bunch
 | **[Pretrain](https://pretrain.com)** | Uses DSPy to automatically optimize AI performance towards user-defined tasks based on uploaded examples. |
 | **[Spindle AI](https://spindle.ai)** | Turns natural-language constrained optimization problems into solvable mathematical programs whose candidate solutions are scenarios. |
 
-WIP. This list mainly the small fraction of companies that have public posts or have OKed being publicly included for specific products so far, out of hundreds of other industry use cases.
+This list represents companies that have publicly shared their use cases or have provided permission to be included. It reflects a selection of the many industry applications of DSPy currently in production.
 
 
 ## A Few Papers Using DSPy
@@ -57,7 +57,7 @@ WIP. This list mainly the small fraction of companies that have public posts or
 | **[Co-STORM](https://arxiv.org/pdf/2408.15232)** | Collaborative STORM: Generate Wikipedia-like articles through collaborative discourse among users and multiple LM agents |
 | **[MedVAL](https://arxiv.org/abs/2507.03152)** | Expert-level validation of AI-generated medical text with scalable language models |
 
-WIP, this list is highly outdated and incomplete.
+This list is regularly updated with new research publications using DSPy.
 
 ## A Few Repositories (or other OSS examples) using DSPy
 
@@ -86,7 +86,7 @@ WIP, this list is highly outdated and incomplete.
 | **Self Discover**| [Github](https://colab.research.google.com/drive/1GkAQKmw1XQgg5UNzzy8OncRe79V6pADB?usp=sharing) |
 | **MedVAL**| [Github](https://github.com/StanfordMIMI/MedVAL) |
 
-TODO: This list in particular is highly incomplete. There are a couple dozen other good ones.
+This list showcases some of the open-source projects and repositories using DSPy, with many more examples available in the community.
 
 ## A Few Providers, Integrations, and related Blog Releases
 
diff --git a/docs/docs/tutorials/build_ai_program/index.md b/docs/docs/tutorials/build_ai_program/index.md
index 53dd0d28..b594cb43 100644
--- a/docs/docs/tutorials/build_ai_program/index.md
+++ b/docs/docs/tutorials/build_ai_program/index.md
@@ -4,6 +4,9 @@ This section contains hands-on tutorials that guide you through building product
 
 ## Core Applications
 
+### [Managing Conversation History](../conversation_history/index.md)
+Learn how to manage conversation history in DSPy applications.
+
 ### [Building AI Agents with DSPy](../customer_service_agent/index.ipynb)
 Learn to create intelligent agents that can handle complex customer service scenarios. This tutorial shows how to build agents that can understand context, maintain conversation state, and provide helpful responses.
 
diff --git a/docs/docs/tutorials/core_development/index.md b/docs/docs/tutorials/core_development/index.md
index cd945250..6736ccd8 100644
--- a/docs/docs/tutorials/core_development/index.md
+++ b/docs/docs/tutorials/core_development/index.md
@@ -4,9 +4,6 @@ This section covers essential DSPy features and best practices for professional
 
 ## Integration and Tooling
 
-### [Managing Conversation History](../conversation_history/index.md)
-Learn how to manage conversation history in DSPy applications.
-
 ### [Use MCP in DSPy](../mcp/index.md)
 Learn to integrate Model Context Protocol (MCP) with DSPy applications. This tutorial shows how to leverage MCP for enhanced context management and more sophisticated AI interactions.
 
diff --git a/docs/docs/tutorials/index.md b/docs/docs/tutorials/index.md
index f578734c..301c8495 100644
--- a/docs/docs/tutorials/index.md
+++ b/docs/docs/tutorials/index.md
@@ -13,6 +13,7 @@ Welcome to DSPy tutorials! We've organized our tutorials into three main categor
 
 
 - Build AI Programs with DSPy
+    - [Managing Conversation History](conversation_history/index.md)
     - [Building AI Agents with DSPy](customer_service_agent/index.ipynb)
     - [Building AI Applications by Customizing DSPy Modules](custom_module/index.ipynb)
     - [Retrieval-Augmented Generation (RAG)](rag/index.ipynb)
@@ -33,7 +34,6 @@ Welcome to DSPy tutorials! We've organized our tutorials into three main categor
     - [Finetuning Agents](games/index.ipynb)
 
 - Tools, Development, and Deployment
-    - [Managing Conversation History](conversation_history/index.md)
     - [Use MCP in DSPy](mcp/index.md)
     - [Output Refinement](output_refinement/best-of-n-and-refine.md)
     - [Saving and Loading](saving/index.md)
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index 113dc387..976f3b5d 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -28,6 +28,7 @@ nav:
         - Tutorials Overview: tutorials/index.md
         - Build AI Programs with DSPy:
             - Overview: tutorials/build_ai_program/index.md
+            - Managing Conversation History: tutorials/conversation_history/index.md
             - Building AI Agents with DSPy: tutorials/customer_service_agent/index.ipynb
             - Building AI Applications by Customizing DSPy Modules: tutorials/custom_module/index.ipynb
             - Retrieval-Augmented Generation (RAG): tutorials/rag/index.ipynb
@@ -51,7 +52,6 @@ nav:
             - RL for Multi-Hop Research: tutorials/rl_multihop/index.ipynb
         - Tools, Development, and Deployment:
             - Overview: tutorials/core_development/index.md
-            - Managing Conversation History: tutorials/conversation_history/index.md
             - Use MCP in DSPy: tutorials/mcp/index.md
             - Output Refinement: tutorials/output_refinement/best-of-n-and-refine.md
             - Saving and Loading: tutorials/saving/index.md
diff --git a/dspy/adapters/types/tool.py b/dspy/adapters/types/tool.py
index b3e6b451..843eceed 100644
--- a/dspy/adapters/types/tool.py
+++ b/dspy/adapters/types/tool.py
@@ -103,7 +103,7 @@ class Tool(Type):
                 v_json_schema = _resolve_json_schema_reference(v.model_json_schema())
                 args[k] = v_json_schema
             else:
-                args[k] = TypeAdapter(v).json_schema()
+                args[k] = _resolve_json_schema_reference(TypeAdapter(v).json_schema())
             if default_values[k] is not inspect.Parameter.empty:
                 args[k]["default"] = default_values[k]
             if arg_desc and k in arg_desc:


Test patch:
diff --git a/tests/adapters/test_tool.py b/tests/adapters/test_tool.py
index 20f59604..18571453 100644
--- a/tests/adapters/test_tool.py
+++ b/tests/adapters/test_tool.py
@@ -50,7 +50,12 @@ class UserProfile(BaseModel):
     tags: list[str] = []
 
 
-def complex_dummy_function(profile: UserProfile, priority: int, notes: str | None = None) -> dict[str, Any]:
+class Note(BaseModel):
+    content: str
+    author: str
+
+
+def complex_dummy_function(profile: UserProfile, priority: int, notes: list[Note] | None = None) -> dict[str, Any]:
     """Process user profile with complex nested structure.
 
     Args:
@@ -89,7 +94,9 @@ async def async_dummy_with_pydantic(model: DummyModel) -> str:
 
 
 async def async_complex_dummy_function(
-    profile: UserProfile, priority: int, notes: str | None = None
+    profile: UserProfile,
+    priority: int,
+    notes: list[Note] | None = None,
 ) -> dict[str, Any]:
     """Process user profile with complex nested structure asynchronously.
 
@@ -167,6 +174,7 @@ def test_tool_from_function_with_pydantic_nesting():
     tool = Tool(complex_dummy_function)
 
     assert tool.name == "complex_dummy_function"
+
     assert "profile" in tool.args
     assert "priority" in tool.args
     assert "notes" in tool.args
@@ -177,6 +185,13 @@ def test_tool_from_function_with_pydantic_nesting():
     assert tool.args["profile"]["properties"]["contact"]["type"] == "object"
     assert tool.args["profile"]["properties"]["contact"]["properties"]["email"]["type"] == "string"
 
+    # Reference should be resolved for nested pydantic models
+    assert "$defs" not in str(tool.args["notes"])
+    assert tool.args["notes"]["anyOf"][0]["type"] == "array"
+    assert tool.args["notes"]["anyOf"][0]["items"]["type"] == "object"
+    assert tool.args["notes"]["anyOf"][0]["items"]["properties"]["content"]["type"] == "string"
+    assert tool.args["notes"]["anyOf"][0]["items"]["properties"]["author"]["type"] == "string"
+
 
 def test_tool_callable():
     tool = Tool(dummy_function)
@@ -319,11 +334,11 @@ async def test_async_tool_with_complex_pydantic():
         ),
     )
 
-    result = await tool.acall(profile=profile, priority=1, notes="Test note")
+    result = await tool.acall(profile=profile, priority=1, notes=[Note(content="Test note", author="Test author")])
     assert result["user_id"] == 1
     assert result["name"] == "Test User"
     assert result["priority"] == 1
-    assert result["notes"] == "Test note"
+    assert result["notes"] == [Note(content="Test note", author="Test author")]
     assert result["primary_address"]["street"] == "123 Main St"
 
 
@@ -382,42 +397,39 @@ TOOL_CALL_TEST_CASES = [
     ([], [{"type": "tool_calls", "tool_calls": []}]),
     (
         [{"name": "search", "args": {"query": "hello"}}],
-        [{
-            "type": "tool_calls",
-            "tool_calls": [{
-                "type": "function",
-                "function": {"name": "search", "arguments": {"query": "hello"}}
-            }]
-        }],
+        [
+            {
+                "type": "tool_calls",
+                "tool_calls": [{"type": "function", "function": {"name": "search", "arguments": {"query": "hello"}}}],
+            }
+        ],
     ),
     (
         [
             {"name": "search", "args": {"query": "hello"}},
-            {"name": "translate", "args": {"text": "world", "lang": "fr"}}
+            {"name": "translate", "args": {"text": "world", "lang": "fr"}},
+        ],
+        [
+            {
+                "type": "tool_calls",
+                "tool_calls": [
+                    {"type": "function", "function": {"name": "search", "arguments": {"query": "hello"}}},
+                    {
+                        "type": "function",
+                        "function": {"name": "translate", "arguments": {"text": "world", "lang": "fr"}},
+                    },
+                ],
+            }
         ],
-        [{
-            "type": "tool_calls",
-            "tool_calls": [
-                {
-                    "type": "function",
-                    "function": {"name": "search", "arguments": {"query": "hello"}}
-                },
-                {
-                    "type": "function",
-                    "function": {"name": "translate", "arguments": {"text": "world", "lang": "fr"}}
-                }
-            ]
-        }],
     ),
     (
         [{"name": "get_time", "args": {}}],
-        [{
-            "type": "tool_calls",
-            "tool_calls": [{
-                "type": "function",
-                "function": {"name": "get_time", "arguments": {}}
-            }]
-        }],
+        [
+            {
+                "type": "tool_calls",
+                "tool_calls": [{"type": "function", "function": {"name": "get_time", "arguments": {}}}],
+            }
+        ],
     ),
 ]
 
@@ -431,11 +443,12 @@ def test_tool_calls_format_basic(tool_calls_data, expected):
 
     assert result == expected
 
+
 def test_tool_calls_format_from_dict_list():
     """Test format works with ToolCalls created from from_dict_list."""
     tool_calls_dicts = [
         {"name": "search", "args": {"query": "hello"}},
-        {"name": "translate", "args": {"text": "world", "lang": "fr"}}
+        {"name": "translate", "args": {"text": "world", "lang": "fr"}},
     ]
 
     tool_calls = ToolCalls.from_dict_list(tool_calls_dicts)