You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Persist elicited answers as raw wire content; reject ambiguous Elicit returns
request_state entries now store exactly the content the client sent (which
already passed validation) instead of re-deriving it from the validated model
with model_dump - persistence and restore previously used two codecs that
diverge whenever validation and serialization aliases differ, dropping a
legitimate stored answer on the third round and re-asking forever. Encode and
restore are now the identity on the client's bytes, so no serialization knob
can break the round-trip; the earlier by-alias dump is gone with the rest of
the model-dumping path.
A return annotation with more than one distinct Elicit arm now raises
InvalidSignature at registration: the restore path validates against the
single statically-known schema, so `-> Elicit[A] | Elicit[B]` either never
converges (the stored B answer fails A validation each round) or silently
injects a wrong-typed model when the shapes happen to overlap. Like cycles
and unclassifiable parameters, the ambiguous shape is rejected up front.
Legacy parity: elicit_with_validation wraps a schema-mismatched accepted
answer in the same stable error the 2026 path uses, instead of letting the
raw pydantic ValidationError text reach the client; noted in the migration
guide since callers catching ValidationError see ValueError now.
Copy file name to clipboardExpand all lines: docs/migration.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -786,6 +786,8 @@ Positional calls (`await ctx.info("hello")`) are unaffected.
786
786
787
787
`Context.elicit()` (and `elicit_with_validation()`) now render the schema first and validate each property against the spec's `PrimitiveSchemaDefinition`, raising `TypeError` at the call site for anything outside it. `Optional[T]` fields render as `{"type": ...}` with the field omitted from `required` (previously the non-spec `anyOf` shape). A bare `list[str]` field is rejected because it renders without the required enum items; use `list[Literal[...]]` or `list[str]` with `json_schema_extra` supplying the items. Unions of multiple primitives (e.g. `int | str`) and nested models are rejected.
788
788
789
+
A schema-mismatched *accepted* answer also fails differently: the call now raises `ValueError` with a stable message ("Received an accepted elicitation whose content does not match the requested schema") instead of letting pydantic's `ValidationError` escape with its internals. Code that caught `ValidationError` around `ctx.elicit()` should catch `ValueError` (or rely on the tool's error result).
790
+
789
791
### Replace `RootModel` by union types with `TypeAdapter` validation
790
792
791
793
The following union types are no longer `RootModel` subclasses:
0 commit comments