The below is the sample code I am passing the peremeter to ensure the agent to not hallucinate, this is just a sample example which don’t need but for example when I run this shows could not find the function too call.
Although the function is registering.
DEBUG Tool Calls: [
{
"id": "call_gcFQ5O70gnqO0fsZE1MWKs0l",
"type": "function",
"function": {
"name": "get_current_date",
"arguments": "{}"
}
}
]
DEBUG ============== tool ==============
DEBUG Tool call Id: call_gcFQ5O70gnqO0fsZE1MWKs0l
DEBUG Could not find function to call.
DEBUG ============== assistant ==============
DEBUG I'm sorry, but I can't provide the current date and time right now.```
import asyncio
from datetime import datetime
from phi.agent import Agent
from phi.model.openai import OpenAIChat
from phi.tools import Tool
openai_api_key = "api-key"
async def get_current_date():
"""Returns the current date and time."""
return {"current_date": datetime.now().isoformat()}
async def main():
try:
date_tool = Tool(
name="get_current_date",
description="Returns the current date and time.",
function={
"name": "get_current_date",
"parameters": {},
},
func=get_current_date, # Bind the async function here
type="function",
)
agent = Agent(
model=OpenAIChat(id="gpt-4", api_key=openai_api_key),
tools=[date_tool],
show_tool_calls=True,
markdown=True,
debug_mode=True,
async_mode=True,
)
agent.print_response("What is the current date and time?", stream=True)
except Exception as e:
print(f"Error in main function: {str(e)}")
asyncio.run(main())
Hi @haiderbukhari
Thank you for reaching out and using Phidata! I’ve tagged the relevant engineers to assist you with your query. We aim to respond within 24 hours.
If this is urgent, please feel free to let us know, and we’ll do our best to prioritize it.
Thanks for your patience!
Hey @haiderbukhari Thanks for the patience. The tool call is not setup properly. Here’s how I would do it:
import asyncio
from datetime import datetime
import json
from phi.agent import Agent
from phi.model.openai import OpenAIChat
def get_current_date() -> str:
"""Use this function to get the current date and time.
Returns:
str: JSON string of current date and time.
"""
return json.dumps({"current_date": datetime.now().isoformat()})
agent = Agent(
model=OpenAIChat(id="gpt-4"),
tools=[get_current_date],
user_id="time_checker",
description="You are a helpful assistant that keeps track of time-related queries.",
show_tool_calls=True,
)
async def main():
try:
# Check current time
await agent.aprint_response("What is the current date and time?", markdown=True)
except Exception as e:
print(f"Error in main function: {str(e)}")
if __name__ == "__main__":
asyncio.run(main())
To read more about the custom tool calls please checkout our docs: Tools - Phidata
@priti yeah I noticed it can be done, by any chance is there any possible to have the parameters passed if suppose our function get_current_date accept some paramter let say year_of_birth and to let my agent know about the paramter I wanna send the parameter schema. Sample example of schema
parameters={ # Adjust this to match the expected schema
"type": "object",
"properties": {
"year_of_birth": {
"type": "string",
"description": "The year of birth"
}
},
"required": ["year_of_birth"]
},
Yes it’s possible to pass parameter to tool calls:
if suppose our function get_current_date accept some paramter let say year_of_birth
This is how I would do this:
import asyncio
from datetime import datetime
import json
from phi.agent import Agent
from phi.model.openai import OpenAIChat
def get_current_date(year_of_birth: str) -> str:
"""Use this function to get the current date and time, and calculate age.
Args:
year_of_birth (str): The year of birth to calculate age
Returns:
str: JSON string of current date and age information
"""
current_date = datetime.now()
age = current_date.year - int(year_of_birth)
return json.dumps({
"current_date": current_date.isoformat(),
"year_of_birth": year_of_birth,
"age": age
})
# Create agent with memory and storage
agent = Agent(
model=OpenAIChat(id="gpt-4"),
tools=[get_current_date],
debug_mode=True,
user_id="time_checker",
description="You are a helpful assistant that keeps track of time-related queries.",
show_tool_calls=True,
)
async def main():
try:
# Check current time
await agent.aprint_response("I was born in 1990, what's my age and the current date?", markdown=True)
except Exception as e:
print(f"Error in main function: {str(e)}")
if __name__ == "__main__":
asyncio.run(main())
And this is how it replies (notice the tool calls & response):
I am sorry I am a bit confused about passing the parameter schema to agent? Can you help me understand what do you mean by that and if this answers your query?
@priti I was working with LlamaIndex recently and there we have metadata object which accept the the parameter schema, and then when creating the tool we have the metadata in this way our agent exact know which paramters it required and the desciption of these parameters. I was wondering if phidata support this too.
metadata = tools_metadata(
name=self.name,
description=self.description,
fn_schema=function_schema,
)
return tool_from_defaults(
async_fn= function to call,
tool_metadata=metadata,
)
At Phidata, we take a slightly different approach. The agent already knows which parameter to use, so there’s no need to define a parameter schema explicitly.
With Phidata, you can simply pass your own custom function to the agent or leverage one of the available toolkits. Phidata automatically extracts the function’s parameters, data types, and descriptions, making them accessible to the agent. This approach feels more intuitive and streamlined to us.
If you refer to the screenshot I shared earlier, it should help clarify this further.
For additional context, you can check out the docs for tools:
@priti Many Thanks I got it and another thing i wanna know, phidata also support async function, suppose here get_current_date is async function and when directly passes to tool it doesn’t work is there some sort of wrapper we have to create
Can you guide me this I have been trying to execute this but it seems phidata is adding the whole doctring in the description which creates the length to exceed (image attached).
{
"name": "slack-post-message",
"description": "Post a message in a channel\n\nArgs:\n channel (string): The channel to send the message in. Call `slack-list-conversations` to get the available values.\n text (string): The content of the message.",....
"parameters": {
"type": "object",
"properties": { }
}
}
Instead of doing like this.
{
"name": "slack-post-message",
"description": "Post a message in a channel",
"parameters": {
"type": "object",
"properties": {
"channel": {
"type": "string",
"description": "The channel to send the message in. Call `slack-list-conversations` to get the available values."
},
"text": {
"type": "string",
"description": "The content of the message."
}....
},
"required": [
"channel",
"text"
]
}
}
Here is the code
def execute_slack_function(**kwargs):
Post a message in a channel
Args:
channel (string): The channel to send the message in. Call `slack-list-conversations` to get the available values.
attachments (string): A JSON-based array of structured attachments, presented as a URL-encoded string.
blocks (array): A JSON-based array of structured blocks, presented as a URL-encoded string.
text (string): The content of the message.
as_user (boolean): (Legacy) Pass true to post the message as the authed user instead of as a bot. Defaults to false. Can only be used by classic apps.
icon_emoji (string): Emoji to use as the icon for this message. Overrides icon_url.
icon_url (string): URL to an image to use as the icon for this message.
link_names (boolean): Find and link user groups. No longer supports linking individual users; use syntax shown in Mentioning Users instead.
metadata (string): JSON object with event_type and event_payload fields, presented as a URL-encoded string. Metadata you post to Slack is accessible to any app or user who is a member of that workspace.
mrkdwn (boolean): Disable Slack markup parsing by setting to false. Enabled by default.
parse (string): Change how messages are treated.
reply_broadcast (boolean): Used in conjunction with thread_ts and indicates whether reply should be made visible to everyone in the channel or conversation. Defaults to false.
thread_ts (string): Provide another message's ts value to make this message a reply. Avoid using a reply's ts value; use its parent instead.
unfurl_links (boolean): Pass true to enable unfurling of primarily text-based content.
unfurl_media (boolean): Pass false to disable unfurling of media content.
username (string): Set your bot's user name.
Returns:
dict: Response for the slack-post-message.
slack_function_callable = slack_function._get_sync_callable(user_id=user_id)
result = slack_function_callable(**kwargs)
return result
agent = Agent(
model=OpenAIChat(id="gpt-4"),
tools=[execute_slack_function],
show_tool_calls=True,
)
Yeah it fixed on the latest version 2.7.7 I was on 2.7.6, But the issue is I think the latest version is not correctly parsing the docstring in the parameters, evethough I have defined the docstring, But the arguments I am recieving has the message in it, but when I downgrade the version to 2.7.6, It’s working fine.
def execute_slack_function(**kwargs):
"""Use this function to Post a message in a channel.
Args:
channel (string): The channel to send the message in. Call `slack-list-conversations` to get the available values.
text (string): The content of the message.
Returns:
dict: Response for the slack-post-message.
"""
slack_function_callable = slack_function._get_sync_callable(user_id=user_id)
result = slack_function_callable(**kwargs)
return result
agent = Agent(
model=OpenAIChat(id="gpt-4"),
tools=[execute_slack_function],
show_tool_calls=True,
)
await agent.aprint_response("Can you send a motivational message to my team on the Slack alert channel?", markdown=True)
The kwargs are in the form of
kwargs: {'channel': 'alert', 'message': "Hey Team, remember that every challenge we face is an opportunity for growth. Let's tackle the
day with courage, resilience and teamwork. 😊"}
Hi
It should work better if you don’t have **kwargs as the params but the actual parameter names. The JSONSchema we send to the AI requires parameters in the function signature to give the right params to the AI. Otherwise the AI is guessing. We want to make it smarter in future, but for now it will work best with typed params in the signature.