Actually usable transitive params - #34
Merged
Merged
Conversation
The previous approach yielded correct schemas, but if you tried to *use* these templates within a tool body, pyright would throw a fit. It would conclude that when you wrote: ``` @tool_family(...) class OtherType: ... @tool_family(...) class MyThing: my_field: OtherType = ... ``` that `my_field` was a `_TemplatedTool`, and thus only supported `with_template` calls; the natural use within the body of `MyThing` as an `OtherType` would cause pyright to complain. At runtime, this was all fine: after template instantion in `MyThing`, `my_field` would *actually* be an instance of (a subtype of) `OtherType`. Pyright had no way to know this, and I wasn't willing to gloss over it with the `type: ignore` comments that would be required everywhere. The solution is a new type of annotation: `family_param`. This decorator will rewrite the annotated type `T` to be a new subclass of `_TemplatedTool[T]` and `T` itself. Thus, the result of the annotation can be used like any other BaseModel. The black magic runtime subclassing checks in the "top level" `@tool_family` all still "just work"; the result of the `family_param` annotation triggers the subclassing check against `_TemplatedTool`; the only difference is that it just unwraps back to "itself". Verified against the motivating use case upstream in autoprover
ericeil
approved these changes
Aug 18, 2026
ericeil
left a comment
Contributor
There was a problem hiding this comment.
Looks as good as I'd expect this sort of thing to look. :)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The previous approach yielded correct schemas, but if you tried to use these templates within a tool body, pyright would throw a fit. It would conclude that when you wrote:
that
my_fieldwas a_TemplatedTool, and thus only supportedwith_templatecalls; the natural use within the body ofMyThingas anOtherTypewould cause pyright to complain. At runtime, this was all fine: after template instantion inMyThing,my_fieldwould actually be an instance of (a subtype of)OtherType. Pyright had no way to know this, and I wasn't willing to gloss over it with thetype: ignorecomments that would be required everywhere.The solution is a new type of annotation:
family_param. This decorator will rewrite the annotated typeTto be a new subclass of_TemplatedTool[T]andTitself. Thus, the result of the annotation can be used like any other BaseModel. The black magic runtime subclassing checks in the "top level"@tool_familyall still "just work"; the result of thefamily_paramannotation triggers the subclassing check against_TemplatedTool; the only difference is that it just unwraps back to "itself".Verified against the motivating use case upstream in autoprover