[Bug] Tool args with defaults are emitted as `required` in native function-calling schema
bug
### What happened?
`dspy.Tool.format_as_litellm_function_call` marks every tool argument as
`required`, despite also advertising default values on argument properties.
### Steps to reproduce
```python
import json
from typing import Any, Literal
import dspy
from dspy.dsp.utils.utils import dotdict
from dspy.utils import DummyLM
def look_up(query: str, state_optional: Literal["fresh", "cached"] = "fresh") -> str:
"""Look something up."""
return f"{query}:{state_optional}"
class _FCDummyLM(DummyLM):
@property
def supports_function_calling(self) -> bool:
return True
def forward(self, prompt: Any = None, messages: Any = None, **kwargs: Any) -> Any:
message = dotdict(
content=self._format_answer_fields({"next_thought": "ready"}),
tool_calls=[
dotdict(
id="call_0",
type="function",
function=dotdict(name="submit", arguments=json.dumps({"answer": "x"})),
)
],
)
return dotdict(
choices=[dotdict(message=message, finish_reason="stop")],
usage=dotdict(prompt_tokens=0, completion_tokens=0, total_tokens=0),
model="dummy",
)
lm = _FCDummyLM([])
with dspy.context(lm=lm, adapter=dspy.ChatAdapter(use_native_function_calling=True)):
pred = dspy.ReActV2("question -> answer", tools=[dspy.Tool(look_up)], max_iters=1)(question="hi")
print(f"termination_reason={pred.termination_reason!r} answer={pred.answer!r} lm_calls={len(lm.history)}\n")
sent_tools = lm.history[-1]["kwargs"]["tools"]
params = next(t for t in sent_tools if t["function"]["name"] == "look_up")["function"]["parameters"]
print(json.dumps(params, indent=2))
```
Output — `state_optional` is wrongly listed in `required` despite its `default`:
```
termination_reason='submit' answer='x' lm_calls=1
{
"type": "object",
"properties": {
"query": {
"type": "string"
},
"state_optional": {
"enum": [
"fresh",
"cached"
],
"type": "string",
"default": "fresh"
}
},
"required": [
"query",
"state_optional"
]
}
```
### DSPy version
3.3.0b1
1 条评论