fix: tool call arguments#896
fix: tool call arguments#896akihikokuroda wants to merge 8 commits intogenerative-computing:mainfrom
Conversation
|
The PR description has been updated. Please fill out the template for your PR to be reviewed. |
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
0a6b036 to
e1bec38
Compare
planetf1
left a comment
There was a problem hiding this comment.
I think the Optional fix is needed - the nested issue isn't a regresion, but worth tracking in a new issue at least
Can we add test cases for the function to prevent regressions?
- def f(email: Email) — required BaseModel param
Confirms the core fix works: email is inlined in the schema (no $ref in the output), and validate_tool_arguments accepts {"to": "a@b.com", "subject": "hi"} without error. - def f(x: str, y: str | None = None) — Optional scalar
Confirms Optional params still work: y must be absent from required and the schema type must be "string", not a raw anyOf structure. - def f(person: Person) where Person has address: Address
Confirms nested models work end-to-end: both Person and Address fully inlined in the schema, and validate_tool_arguments accepts a nested dict without a ValidationError.
ajbozarth
left a comment
There was a problem hiding this comment.
Fixes the $ref inlining problem and extends validate_tool_arguments to handle the resulting nested schemas — the approach makes sense. Main blocker before merge is missing tests — the PR template has "Tests added" unchecked. The fix touches a pure function that's straightforward to unit test. Three cases would give good coverage:
def f(email: Email)— required BaseModel param; confirms$refis resolved andvalidate_tool_argumentsaccepts{"to": "a@b.com", "subject": "hi", "body": "..."}def f(x: str, y: str | None = None)— Optional scalar regression;ymust be absent fromrequiredand schema type must be"string", not rawanyOfdef f(person: Person)wherePersonhasaddress: Address— confirms two-level nesting works end-to-end
|
My Claude review hit a lot of the same points as @planetf1 's review did, but overall this is looking good outside the missing tests |
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
ajbozarth
left a comment
There was a problem hiding this comment.
Both reviews addressed, two nits below.
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
| reason="Nested model resolution not yet implemented. " | ||
| "This test documents the expected behavior once recursive $ref resolution is added. " | ||
| "Currently fails because Address remains as a dangling $ref inside Person's schema. " | ||
| "https://github.com/generative-computing/mellea/issues/404 for implementation details." |
There was a problem hiding this comment.
isn't this url for the issue this will close?
There was a problem hiding this comment.
The "NESTED_MODEL_RESOLUTION_ISSUE.md" is attached to the issue.
There was a problem hiding this comment.
why not open a GitHub issue for that? having a md plan file linked in an issue is pretty sub-par. Or if keeping that md file is important for some reason putting it in the repo's dev docs in this PR would still be better.
There was a problem hiding this comment.
I too think we should raise an issue to track this - I expect as mellea usage increases having nested models is going to be more relevant.
There was a problem hiding this comment.
Looking at the current state: the URL has been updated from #404 (the issue this PR closes) to #911 (the tracking issue for the nested-model follow-up), so the substantive concern here is addressed — the skip reason now points to an issue that'll remain open after merge.
One small cosmetic thing left over from the earlier iterations: the phrasing "NESTED_MODEL_RESOLUTION_ISSUE.md in https://github.com/generative-computing/mellea/issues/911" reads a bit oddly since that .md file isn't in the repo. Could be tightened to just "See #911 for implementation details." before merge. Not a blocker.
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
|
Thanks for the updates @akihikokuroda looking good - I think we need to track the nested model aspect, and also the commits still refer to 'Assisted-By Bob' - that should be in the commit message but it seems odd as the first line. That could be fixed when merging via the squash commit, but it's probably safer to update the commits before? |
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
| out, _ = await react( | ||
| goal="Write an email about the Mellea python library to Jake with the subject 'cool library'.", | ||
| context=ChatContext(), | ||
| backend=m.backend, | ||
| tools=[search_tool], | ||
| format=Email, | ||
| loop_budget=20, | ||
| ) | ||
| print(out) |
There was a problem hiding this comment.
I think this should remain commented out. It's just showing that there's another way of using the function; unless you explicitly want to run both and compare the output.
| An ``OllamaTool`` instance representing the function as an OpenAI-compatible | ||
| tool schema. | ||
| """ | ||
| import copy |
There was a problem hiding this comment.
Is there a reason this isn't a top level import?
| def resolve_ref(ref_path: str, defs: dict) -> dict: | ||
| """Resolve a $ref path like '#/$defs/Email' to the actual schema.""" | ||
| if ref_path.startswith("#/$defs/"): | ||
| def_name = ref_path.split("/")[-1] | ||
| return defs.get(def_name, {}) | ||
| elif ref_path.startswith("#/definitions/"): | ||
| def_name = ref_path.split("/")[-1] | ||
| return defs.get(def_name, {}) | ||
| return {} | ||
|
|
||
| # Helper to check if anyOf represents a complex union (not just Optional[primitive]) | ||
| def _is_complex_anyof(v: dict) -> bool: | ||
| """Check if anyOf contains complex types (refs or nested objects).""" | ||
| any_of_schemas = v.get("anyOf", []) | ||
| for sub_schema in any_of_schemas: | ||
| # Skip null types - they just indicate optionality | ||
| if sub_schema.get("type") == "null": | ||
| continue | ||
| # Check for references or nested properties | ||
| if "$ref" in sub_schema or "properties" in sub_schema: | ||
| return True | ||
| return False |
There was a problem hiding this comment.
Should these be defined within this function? Is there a reason they aren't top level declarations?
There was a problem hiding this comment.
That way we can have unit tests for these functions as well.
There was a problem hiding this comment.
I'll move it out and add unit tests for it.
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
| # For nested objects, we expect either: | ||
| # 1. type: "object" with nested properties | ||
| # 2. A reference to the Email schema | ||
| if email_schema["type"] == "object": |
There was a problem hiding this comment.
Minor: now that the fix guarantees email_schema["type"] == "object" (the whole point of the PR is that the $ref is inlined), this if is dead code — and if a future change regressed the type, the inner assertions would be silently skipped and the test would still pass. Same pattern a few lines below in test_nested_basemodel_schema at line 164 (if person_schema["type"] == "object":) and line 173 (if address_schema.get("type") == "object":).
Suggest making all three unconditional assert so the tests actually fail on regression. Happy for this to land as-is and file a follow-up if you'd prefer — just flagging since the current shape won't catch what I think it's meant to catch.
(Unrelated to this test but for reference while you're in the area: the discriminator-union gap I mentioned on the allOf thread is tracked in #989.)
Misc PR
Type of PR
Description
Testing
Attribution