Tool Invoker Doesn't Pass Default Param Value From Dict
===========================================================
Describe the Bug
When declaring tool parameters, we can define the default value for a param. This value is serialized in tools.data.parameters section of the dumped pipeline. However, this value is not passed to function call during the first tool invocation.
Error Message
Failed to invoke Tool <tool_name>
Expected Behavior
If default is defined in the pipeline yaml, the value is passed to function params as default if LLM doesn't provide any value for the param.
Additional Context
The pipeline is loaded from yaml file/string.
To Reproduce
Steps to Reproduce the Behavior
from haystack.core.pipeline import Pipeline
from haystack.tools.tool import Tool
pipeline_str = """
components:
agent:
init_parameters:
chat_generator:
init_parameters:
api_key:
env_vars:
- AZURE_OPENAI_API_KEY
strict: false
type: env_var
api_version: '2023-05-15'
azure_ad_token:
env_vars:
- AZURE_OPENAI_AD_TOKEN
strict: false
type: env_var
azure_ad_token_provider: null
azure_deployment: gpt-4o-mini
azure_endpoint: https://caat-openai-test-central.openai.azure.com/
default_headers: {}
generation_kwargs: {}
max_retries: 5
organization: null
streaming_callback: null
timeout: 30.0
tools: null
tools_strict: false
type: haystack.components.generators.chat.azure.AzureOpenAIChatGenerator
exit_conditions:
- text
max_agent_steps: 100
raise_on_tool_invocation_failure: false
state_schema: {}
streaming_callback: null
system_prompt: "\n you are a helpful assistant that can perform calculations\
\ and fetch weather information.\n\n "
tools:
- data:
description: Get the current weather for a city.
function: __main__.weather_api
inputs_from_state: null
name: weather
outputs_to_state: null
outputs_to_string: null
parameters:
properties:
api_url:
default: https://api.weather.com
description: The url to call the weather API
type: string
city:
description: The city to get the weather for
type: string
required:
- expression
type: object
type: haystack.tools.tool.Tool
type: haystack.components.agents.agent.Agent
prompt:
init_parameters:
required_variables: null
template:
- content:
- text: "\n Answer the question:\n {{query}}\n"
meta: {}
name: null
role: user
variables: null
type: haystack.components.builders.chat_prompt_builder.ChatPromptBuilder
connection_type_validation: true
connections:
- receiver: agent.messages
sender: prompt.prompt
max_runs_per_component: 100
metadata: {}
"""
def weather_api(city: str, api_url str) -> dict:
# Simulate a weather API call
print(f"Fetching weather for {city} using {api_url}...")
weather_data = {
"New York": {"temperature": 20, "condition": "Sunny"},
"Los Angeles": {"temperature": 25, "condition": "Sunny"},
"Chicago": {"temperature": 15, "condition": "Cloudy"},
"Rome": {"temperature": 20, "condition": "Sunny"},
}
return {"result": weather_data.get(city, {"error": "City not found"})}
# Tool Definition
weather_tool = Tool(
name="weather",
description="Get the current weather for a city.",
parameters={
"type": "object",
"properties": {
"city": {"type": "string", "description": "The city to get the weather for"},
"api_url": {"type": "string", "description": "The url to call the weather API", "default": "https://api.weather.com"},
},
"required": ["expression"]
},
function=weather_api,
)
pipelne = Pipeline.loads(pipeline_str)
response = pipelne.run(
data={
"prompt": {"query": "what's the weather in Rome?"}
}
)
print("Result:", response)
Output Logs
Agent step: 0 ToolInvoker.run() Invoking Tool: weather Parameters: 'city'
Failed to invoke Tool weather
with parameters 'city'. Error: weather_api() missing 1 required positional argument: 'api_url'
Agent step: 1 ToolInvoker.run() Invoking Tool: weather Parameters: 'api_url'
FAQ Check
- [ ] Have you had a look at our new FAQ page?
System:
- OS:
- GPU/CPU:
- Haystack version (commit or version number):
- DocumentStore:
- Reader:
- Retriever:
Root Cause Analysis
The root cause of this issue is that the ToolInvoker
is not passing the default value of the api_url
parameter to the weather_api
function during the first tool invocation.
Solution
To fix this issue, we need to modify the ToolInvoker
to pass the default value of the api_url
parameter to the weather_api
function during the first tool invocation.
Modified Code
class ToolInvoker:
def run(self, tool, parameters):
# ...
if 'api_url' not in parameters:
parameters['api_url'] = tool.parameters['properties']['api_url']['default']
# ...
Explanation
In the modified code, we added a check to see if the api_url
parameter is present in the parameters
dictionary. If it's not present, we set its value to the default value defined in the tool.parameters
.
Testing
To test this solution, we can run the pipeline again with the modified ToolInvoker
class```python
pipelne = Pipeline.loads(pipeline_str)
response = pipelne.run(
data=
"prompt"
}
)
print("Result:", response)
## **Expected Output**
-------------------------
The expected output should be the same as before, but with the correct value of the `api_url` parameter.
```python
Agent step: 0
ToolInvoker.run()
Invoking Tool: weather
Parameters: {'city': 'Rome', 'api_url': 'https://api.weather.com'}
Result: {'result': {'temperature': 20, 'condition': 'Sunny'}}
Conclusion
Q: What is the issue with the Tool Invoker?
A: The issue with the Tool Invoker is that it doesn't pass the default value of the api_url
parameter to the weather_api
function during the first tool invocation.
Q: What is the expected behavior of the Tool Invoker?
A: The expected behavior of the Tool Invoker is to pass the default value of the api_url
parameter to the weather_api
function during the first tool invocation if the parameter is not provided.
Q: How can I reproduce the issue?
A: To reproduce the issue, you can run the pipeline with the provided code and observe the output logs.
Q: What is the root cause of the issue?
A: The root cause of the issue is that the ToolInvoker
is not passing the default value of the api_url
parameter to the weather_api
function during the first tool invocation.
Q: How can I fix the issue?
A: To fix the issue, you can modify the ToolInvoker
class to pass the default value of the api_url
parameter to the weather_api
function during the first tool invocation.
Q: What is the modified code for the Tool Invoker?
A: The modified code for the Tool Invoker is as follows:
class ToolInvoker:
def run(self, tool, parameters):
# ...
if 'api_url' not in parameters:
parameters['api_url'] = tool.parameters['properties']['api_url']['default']
# ...
Q: How can I test the modified code?
A: To test the modified code, you can run the pipeline again with the modified ToolInvoker
class and observe the output logs.
Q: What is the expected output of the modified code?
A: The expected output of the modified code is the same as before, but with the correct value of the api_url
parameter.
Q: Can you provide an example of the expected output?
A: Yes, the expected output is as follows:
Agent step: 0
ToolInvoker.run()
Invoking Tool: weather
Parameters: {'city': 'Rome', 'api_url': 'https://api.weather.com'}
Result: {'result': {'temperature': 20, 'condition': 'Sunny'}}
Q: Is there anything else I need to know?
A: Yes, it's essential to note that the modified code is a temporary fix and may not be the most efficient solution. It's recommended to investigate the root cause of the issue and implement a more robust solution.
Q: Where can I find more information about the issue?
A: You can find more information about the issue in the Haystack documentation.
Q: Can I get help with implementing the modified code?
A: Yes, you can reach out to the Haystack support team for assistance with implementing the modified code.