-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improving BaseTool
classes for more control and additional convenience
#294
Comments
While you're thinking about this, I think it might also be worthwhile to think about stateful tools. This goes for both the tool schema and the tool fn implementation. As a very simple example, let's say I have a chatbot that stores information about the user it's talking to in a scratchpad. The content of the scratchpad and the ID of the user will not always be constant, so the tool description and implementation need to be dynamic based on the session user. |
100%. I think #278 is along these lines? Essentially dynamically update the tool based on the state. Seems to me like that state might be stored in the call/agent and not the tool itself where the tool then updates dynamically based on that state? |
@willbakst this is what I was talking about yesterday, with trying to pass methods that are defined on a class (and therefore require self) as tools |
Yeah we need to be able to use tools that are defined internally to your class for colocation (and also the ability to edit internal state easily through tools). Without enabling this natively, every current solution smells. |
Opting not to implement this unless heavily requested since the new interface in #322 allows for this. Really the only reason to have a tool with access to |
After working on it for a little, I realized that the Instead we'll need to generate all of the tool message parameters at once. I'm thinking a good flow would be something like: response = my_call.call()
tools_and_outputs = []
if tools := response.tools:
tool_outputs = []
for tool in tools:
output = tool.call()
tools_and_outputs.append((tool, output))
...
tool_message_params = response.tool_message_params(tools_and_outputs) For streaming, we would do the same thing (for providers that support streaming tools): stream = ProviderStream(my_call.stream())
tools_and_outputs = []
for chunk, tool in stream:
if tool:
output = tool.call()
tools_and_outputs.append((tool, output))
...
tool_message_params = stream.tool_message_params(tools_and_outputs) |
Description
There are a few things from various discussions that I think would help improve tools in Mirascope. I'll use this issue to track progress on the improvements:
Right now the generated tool schemas use the class name and docstring, but this is a bit restrictive. What if you want to use a name that wouldn't be a valid class or method name? What if you want to have the description for the tool be separate from the docstring? Idea here would be to add new
name
anddescription
class methods that will use__name__
and__doc__
respectively by default but allow for the user to overwrite the method if desired. For example:As part of this improvement, we should also ensure that tools auto-generated from functions actually use the original function name. I noticed while digging that we convert into the proper tool name in pascal case, but that's really bad and needs to be fixed.
The current way users are expected to call tools right now is
tool.fn(**tool.args)
, but this means that you either need to write the tool as a function or you need to write the function and attach it to the tool. It seems like a better recommendation / interface to instead have acall
method that internally callstool.fn(**tool.args)
by default but then can be overridden by the user for a better interface for writing more complex tools. For example:Toolkit
class for organizing a set of tools under a namespaceConsider a bunch of functions / tools for interacting with a file system. It would be nice to be able to organize these tools under a single namespace and provide the LLM with the namespaced tools so it has more context around where the tools are coming from an how to use them. For example:
It's fairly clear how to add examples for normal calls (just insert them into the prompt), but for tool calls there are slightly better ways by using the JSON schema examples directly. We should better document how to do this so it's clear without additional digging.
Users currently need to reconstruct the tool call message manually, which is annoying. Instead we should provide something like
tool.message_param
that automatically generates the message parameter to insert.The text was updated successfully, but these errors were encountered: