Thanks!
That was interesting unfortunately it does not cover the recursive cases.
Here is an example.
I’ve added the plain pydantic classes (with 1 suffixes) - you can test that they do produce the needed schemas.
import json
from langroid.agent.tool_message import ToolMessage
from typing import List, Optional, Type
from pydantic import BaseModel
from pprint import pprint
class Foo(ToolMessage):
request = ''
purpose = ''
count: int
size: Optional[float] = None
class Bar(ToolMessage):
request = ''
purpose = ''
apple: str = 'x'
banana: str = 'y'
class Spam(ToolMessage):
request = ''
purpose = ''
foo: Foo
bars: List[Bar]
class Foo1(BaseModel):
count: int
size: Optional[float] = None
class Bar1(BaseModel):
apple: str = 'x'
banana: str = 'y'
class Spam1(BaseModel):
foo: Foo1
bars: List[Bar1]
llmschema = Spam.llm_function_schema(request=True)
definitions = llmschema.parameters.get('definitions').get('Foo')
pprint(definitions)
for i in definitions:
print(i)
print(definitions.get(i))
print(json.dumps(definitions.get(i), indent=4))
print('---------------------')
The output of that is:
/home/zby/gpt/langroid/venv/bin/python /home/zby/gpt/langroid/schema_example.py
{'description': 'Abstract Class for a class that defines the structure of a '
'"Tool" message from an\n'
'LLM. Depending on context, "tools" are also referred to as '
'"plugins",\n'
'or "function calls" (in the context of OpenAI LLMs).\n'
'Essentially, they are a way for the LLM to express its intent '
'to run a special\n'
'function or method. Currently these "tools" are handled by '
'methods of the\n'
'agent.\n'
'\n'
'Attributes:\n'
' request (str): name of agent method to map to.\n'
' purpose (str): purpose of agent method, expressed in '
'general terms.\n'
' (This is used when auto-generating the tool '
'instruction to the LLM)\n'
' result (str): example of result of agent method.',
'exclude': {'result', 'purpose'},
'properties': {'count': {'type': 'integer'},
'purpose': {'default': '', 'type': 'string'},
'request': {'default': '', 'type': 'string'},
'result': {'default': '', 'type': 'string'},
'size': {'type': 'number'}},
'required': ['count'],
'type': 'object'}
description
Abstract Class for a class that defines the structure of a "Tool" message from an
LLM. Depending on context, "tools" are also referred to as "plugins",
or "function calls" (in the context of OpenAI LLMs).
Essentially, they are a way for the LLM to express its intent to run a special
function or method. Currently these "tools" are handled by methods of the
agent.
Attributes:
request (str): name of agent method to map to.
purpose (str): purpose of agent method, expressed in general terms.
(This is used when auto-generating the tool instruction to the LLM)
result (str): example of result of agent method.
"Abstract Class for a class that defines the structure of a \"Tool\" message from an\nLLM. Depending on context, \"tools\" are also referred to as \"plugins\",\nor \"function calls\" (in the context of OpenAI LLMs).\nEssentially, they are a way for the LLM to express its intent to run a special\nfunction or method. Currently these \"tools\" are handled by methods of the\nagent.\n\nAttributes:\n request (str): name of agent method to map to.\n purpose (str): purpose of agent method, expressed in general terms.\n (This is used when auto-generating the tool instruction to the LLM)\n result (str): example of result of agent method."
---------------------
type
object
"object"
---------------------
properties
{'request': {'default': '', 'type': 'string'}, 'purpose': {'default': '', 'type': 'string'}, 'result': {'default': '', 'type': 'string'}, 'count': {'type': 'integer'}, 'size': {'type': 'number'}}
{
"request": {
"default": "",
"type": "string"
},
"purpose": {
"default": "",
"type": "string"
},
"result": {
"default": "",
"type": "string"
},
"count": {
"type": "integer"
},
"size": {
"type": "number"
}
}
---------------------
required
['count']
[
"count"
]
---------------------
exclude
{'result', 'purpose'}
Traceback (most recent call last):
File "/home/zby/gpt/langroid/schema_example.py", line 48, in <module>
print(json.dumps(definitions.get(i), indent=4))
File "/usr/lib/python3.10/json/__init__.py", line 238, in dumps
**kw).encode(obj)
File "/usr/lib/python3.10/json/encoder.py", line 201, in encode
chunks = list(chunks)
File "/usr/lib/python3.10/json/encoder.py", line 438, in _iterencode
o = _default(o)
File "/usr/lib/python3.10/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type set is not JSON serializable
Process finished with exit code 1
The immediate problem is that excludes
is a set and is not serializable by json
- but the underlying problem is that excludes
is not removed in the definitions.
The recursive case is exactly the hard case that I would like to have covered by a library.