-
Notifications
You must be signed in to change notification settings - Fork 843
Passing Functions as Tools #321
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
Conversation
6f8cd93 to
93c7a63
Compare
ab402d3 to
7148520
Compare
4e8bd4b to
4fcdf70
Compare
4fcdf70 to
8ec5123
Compare
|
|
23548ce to
1f089f7
Compare
efd3ee9 to
e7bb55f
Compare
65db34a to
ed3ba8a
Compare
tests/test_client.py
Outdated
| # Test missing required fields | ||
| incomplete_tool = { | ||
| 'type': 'function', | ||
| 'function': {'name': 'test'}, # missing description and parameters |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is parameters required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So in the previous behavior - no.
But since the last Pydantic PR you have to provide Parameters. Tested out both the OpenAI Python SDK with Ollama and the current published version of ollama-python. I think it might be worthwhile to have the Tool class have optional on all params to make sure it is backwards compatible.
Seems like function calling still works with not a fully-fledged JSON (I'm sure it's flakey but not our job).
Proposed Tool def'n:
class Tool(SubscriptableBaseModel):
type: Optional[Literal['function']] = 'function'
class Function(SubscriptableBaseModel):
name: Optional[str] = None
description: Optional[str] = None
class Parameters(SubscriptableBaseModel):
type: Optional[Literal['object']] = 'object'
required: Optional[Sequence[str]] = None
class Property(SubscriptableBaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
type: Optional[str] = None
description: Optional[str] = None
properties: Optional[Mapping[str, Property]] = None
parameters: Optional[Parameters] = None
function: Optional[Function] = Nonee8a4950 to
6d9c156
Compare
3a994b2 to
c5c61a3
Compare
| # 1. A parenthetical expression like (integer) - captured in group 1 | ||
| # 2. A colon : | ||
| # Followed by optional whitespace. Only split on first occurrence. | ||
| parts = re.split(r'(?:\(([^)]*)\)|:)\s*', line, maxsplit=1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to avoid regexp when possible since it's hard to grok. In this scenario, a simpler solution would be to split on the mandatory : than parse the pre-colon and post-colon sections independently. Here's an example that passes your tests
for line in parsed_docstring['args'].splitlines():
pre, _, post = line.partition(':')
if not pre.strip():
continue
if not post.strip() and last_key:
parsed_docstring[last_key] += ' ' + pre
continue
arg_name, _, _ = pre.replace('(', ' ').partition(' ')
last_key = arg_name.strip()
parsed_docstring[last_key] = post.strip()There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO @ParthSareen to spin out issue
| types = {t.get('type', 'string') for t in v.get('anyOf')} if 'anyOf' in v else {v.get('type', 'string')} | ||
| if 'null' in types: | ||
| schema['required'].remove(k) | ||
| types.discard('null') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If null is the only type (for some reason), this will be an empty string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is okay, IMO something like:
def (a:None, b:type(None)):
...is extremely unlikely
* Fix image serialization
|
I found that the ollama-Python/examples/tools.py script cannot specify an IP address. |
Features:
.chat(tools=[python_func,...])🥳Examples to come on follow up for both Pydantic and Functions as Tools