Repository navigation
Conversation
The streamed JSON is keyed by the alias model_json_schema() advertises while model_fields is keyed by the attribute name, so _build_partial_object looked up aliased fields by the wrong name and stored the raw payload under the alias key. Nested models behind an alias therefore reached the caller as plain dicts, and model_construct() left the declared attribute unset.
|
Hi — anything you'd like changed before this can go in? Both GitHub Actions workflows on the fork PR are parked at The change resolves partial-streaming fields that arrive under a validation alias rather than dropping them, and the regression test streams a chunk that carries only the alias and asserts the resolved field reaches the model. Happy to switch to a different shape if you would rather it error than resolve. |
|
Correction to the line about a clean local What I can state is the rest: both workflows are parked at |
## Current Candidate: Jev and OpenAI Decisions Exact head: `9e7a61a9d85aacd812ec8e77a68b9d2adaecef66`. OpenAI Decisions support and the same sync/async provider/configuration contract family as OpenRouter and TypeSafe are included. Shared suite: **294 passed, 1 existing skip**. Decision source has **373/373 statements covered**; source unchanged since coverage measurement. Full source typing, test typing, and normal commit hooks passed. Six opt-in live provider cases were skipped without explicit opt-in; no billed API calls. Native OpenAI image input and live OpenAI compatibility remain unverified. Documentation: complete MkDocs build passed (13.17s; existing navigation/docstring warnings), primary example model definitions executed without API calls, guide linked in navigation, and OpenAI entry included in 1.18 release notes. Guide documents all three routes, raw wire differences, text-only support and shared/live test configuration. Fresh exact-head CI and required independent approval remain mandatory. Old-head auto-merge was disabled before updates. Previous-head checks below are historical evidence, not current proof. No merge or publication in this continuation. [Implementation and earlier validation details](#2708 (comment)). ## Prior Integration Evidence ## Summary Curated Instructor 1.18 integration from main `e12f8b49203b0c1f253d27c1e709d0a09b9fc5a8`, current candidate `b76939ea652202842ae26aec4663ef52d13356d7`. Ready for independent review; this is not approval to merge or publish. - Include the reviewed typed Jev/TypeSafe and OpenRouter decision-mode feature and 1.18.0 metadata from #2707. - Consolidate hook dispatch (#2634), custom batch IDs (#2691), UTF-8 batch I/O (#2667), cache round-trips (#2688), citation validation (#2699), GenAI retry history (#2632), custom-type compatibility (#2629), and example corrections (#2697). - Revise IPv6 SSRF filtering (#2673) and symmetric streaming JSON bounds (#2638); preserve incremental streaming and public network policy. - Unify declared parallel tool names and reject unknown calls across providers (#2675/#2698), including actual retry boundaries and native xAI transport. Preserve the public generator contract and VertexAI class-name wire exception. - Isolate request histories in public retry/reask helpers (#2646) and fix incomplete Responses validation/cache acceptance (issue #2705). - Repair Python 3.9 generic-alias traversal without weakening async-validator rejection; remove redundant helper wrappers, obsolete version-specific test hacks and a duplicate negative test. The selected patches were revised where needed, not merged blindly. New transport contracts use real SDKs and loopback HTTP/gRPC, not new mocked provider clients. Existing legacy mocks are not claimed as live provider evidence. ## Validation Current candidate: `b76939ea652202842ae26aec4663ef52d13356d7`. Earlier local results below are for head `a3137a76159611c080ebcc0c36ccf0383901e2f2` unless a different head is named. - Normal commit hooks: Ruff lint/format and source typing passed. - Whole-test-tree typing passed with the SDK-complete environment. - Read-only final runtime review identified a Python 3.9 nested-generic class-check defect; fixed and independently reverified locally. This is not GitHub approval. - Minimum-version OpenAI loopback retry/cache/parallel contracts: 36 passed. Other SDKs are absent from this temporary core-only environment; their contracts passed in the full SDK-complete Python 3.13 suite, not in the minimum environment. - Focused Python 3.9/Pydantic 2.8.2 compatibility: 174 passed, 6 version skips. - Isolated wheel built from sdist: Python 3.9.25/OpenAI 2.0.0/Pydantic 2.8.0 contracts and credential-free CLI help passed. - Isolated wheel built from sdist: Python 3.13.11/OpenAI 3.3.0/Pydantic 2.13.5 contracts and credential-free CLI help passed. - Release metadata/changelog extraction validates 1.18.0. - All **29 runnable remote checks passed** at `a3137a76159611c080ebcc0c36ccf0383901e2f2`; publication was intentionally skipped. Required independent review remains unsatisfied. - Cursor Bugbot found that parallel parsing of an empty/prose response could escape the retry boundary as an unhandled exception. Head `9bcef9849fa609040c65fec30f1d3869e64d415e` adds `ResponseParsingError` guards and a missing-tool-calls regression test. Its full offline suite passed **3,963 tests**, but the zero-missing-statements gate failed on the untested empty-choices branch. Head `ba0db64bad4d9112fdcaef082bfd9a382a25e57c` adds that SDK-validated regression test; the complete focused parallel suite passed **54 tests**, plus Ruff lint/format and focused test typing. - At `ba0db64bad4d9112fdcaef082bfd9a382a25e57c`, **all 29 runnable CI checks passed** and publication was intentionally skipped. Full offline coverage ran **3,964 passed, 200 skipped, 859 deselected**, with **zero missing statements** and 4 missing branches. No threshold was reduced. - The current head changes only the decisions example and changelog accuracy: its primary example constructs under Python 3.9, and a full `mkdocs build --clean` passed. At `b76939ea652202842ae26aec4663ef52d13356d7`, **all 29 runnable CI checks passed**, publication was intentionally skipped, and full offline coverage reported **3,964 passed, 200 skipped, 859 deselected**, **zero missing statements**, and 4 missing branches. Independent maintainer approval remains outstanding. - Full credential-free offline suite: **3,962 passed, 200 skipped, 859 deselected**, with runtime/unraisable/thread warnings treated as errors. - Combined statement/branch coverage: **99.9700%**, **0 missing statements**, 4 missing branches; unchanged >=99% and zero-missing-statement gates passed. Existing version/optional/runtime exceptions remain disclosed; no threshold reductions. - Focused decision-mode contracts at the same head: **240 passed, 1 skipped** with credentials removed and localhost transport enabled. The initial sandbox-only run could not bind loopback sockets; the unchanged suite passed when loopback binding was permitted. - Opt-in live OpenRouter Jev model (`typesafe/jev-1.13`): **sync and async contracts passed** using the configured local key. No credential or response payload was added to this PR. Direct TypeSafe/Jev live calls remain unverified because `TYPESAFE_API_KEY` is unavailable. - Full `mkdocs build --clean` passed at the same head, writing only to a temporary site directory. It reported existing nav omissions and two griffe annotation warnings; no documentation build errors. No other live provider calls were made in this integration validation. Exhaustive repository security certification is not claimed. The Bugbot finding was addressed and its review thread resolved. Current-head CI passed; required independent maintainer approval remains the merge gate. No publication, tag, deployment, main merge or issue closure. ## Security and Compatibility - Reject the entire local-use NAT64 `64:ff9b:1::/48` prefix. Its translation layout is network-specific; assuming a fixed embedded destination is unsafe for this fetcher's public-network-only policy ([RFC 8215, section 5](https://www.rfc-editor.org/rfc/rfc8215.html#section-5)). Known well-known NAT64/mapped/compatible/6to4/Teredo destinations are checked as well as their IPv6 wrapper. - Streaming input limits are 1,048,576 characters and 128 nested containers, sync/async. Errors remain `ValueError`; complete objects can still emit before EOF. - Unknown parallel calls now raise `ResponseParsingError` inside retry rather than silently losing results. Nonstream validation is eager while the returned public generator type is preserved. - Incomplete Responses raise `IncompleteOutputException` before defaults or caches can turn partial output into an accepted answer. SDK metadata/reason remain attached. - Citation context accepts strings or lists/tuples of strings; malformed supplied sources fail closed. Missing context preserves existing behavior. - Decision mode is opt-in and currently does not support retries, caching, streaming or completion hooks. OpenRouter Jev sync/async compatibility passed live; direct TypeSafe/Jev compatibility is still supported by shared offline contracts only. ## Overlaps and Deferrals Reviewed the current 78-PR/28-issue queue. Compact selected changes received detailed source review; large providers/features/architecture received scope triage, not blanket approval. Absent CI is not passing. The table below records every source head inspected; these heads are not independently certified merge-ready. ## Every Open PR | PR / Inspected Head | Decision | | --- | --- | | [#2707](#2707) `a2f0b309464b70b8936054466e6a365d16c9cb39` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2704](#2704) `5061c6866f2c94f46eedd4336753e9db8215fd9b` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2703](#2703) `248effa5c97e5c046685d7c6b144c4cbc7863702` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2701](#2701) `82a083207fe45993e339d74a96c5d2b0cba634fc` | Blocked: recursive described $ref causes infinite recursion; mappings change meaning. | | [#2700](#2700) `79aa81e1dec364422dcac7401e67c150a547250c` | Deferred: buffers valid streaming output until EOF, breaking incremental behavior. | | [#2699](#2699) `27dd66315794394a9c471c6a75c2ad4b538abae6` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2698](#2698) `59316edcbe5c1f3cc094d70f042a9d43a26a8db5` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2697](#2697) `692433fa8e04c21274232d83d042a27f37113924` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2693](#2693) `bfd56e7dda4d3444fd4d866f1c7399a5bee58b55` | Deferred: reconcile strict-schema required/defaulted fields and mapping policy together. | | [#2692](#2692) `89f9db983865175e92a7096615ce2bcc454bfb07` | Separate dependency maintenance: compatibility and supply-chain review required. | | [#2691](#2691) `81f28eb416c206c1b8ae702705e66007ac5e107d` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2690](#2690) `7c829eb06297d07bcd1ff957c481d8c042ef64da` | Deferred editorial: patch still leaves incorrect provider spelling/capitalization. | | [#2689](#2689) `9688857ccba01dbebc4d3f5db0c1d158780c6c73` | Deferred docs/examples: maintenance/product choice; no correctness-release necessity. | | [#2688](#2688) `f47161c87b872e13e54aecb9aed24e1a131a938b` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2686](#2686) `545232b6ff01f78fb938e84daeec4e876dfb45da` | Next compact batch: promising fixes, require exact-head runtime and combined validation. | | [#2685](#2685) `7782155fc19e435173fa32ab7d5f78815bf99111` | Blocked: rejects native Converse tool histories and loses multiple system blocks. | | [#2683](#2683) `3b09a98e768bfd2955164fe320cf0994a6f4b2a5` | Next compact batch: promising fixes, require exact-head runtime and combined validation. | | [#2680](#2680) `7f70d2099a4b598f67a1b09e00ad7bed15cb832b` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2678](#2678) `0bed63816628aec034f5fc965b8d719d48bb0b8e` | Deferred: broader mapping-field response model construction. | | [#2677](#2677) `2c0276aea1b25f061b3949b9883bd482ddd183cc` | Next compact batch: promising fixes, require exact-head runtime and combined validation. | | [#2675](#2675) `e69a43d3cd7b8a3a8df758c946af510ef036e917` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2673](#2673) `06d34c3039faf530296960d24d50e8df8f9d9a6b` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2672](#2672) `4df16706ab588da537f76edec57b33ae9ff6141b` | Deferred: Mistral batch needs failure/error-file retrieval and provider evidence. | | [#2671](#2671) `c3d95dccd28e803fa08cd89c87f5692ea044701a` | Deferred: global StrictUndefined is a deliberate compatibility change. | | [#2670](#2670) `9763946ad1795ad6428daf277df06a07ee3c5dda` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2668](#2668) `2b028330d359994d3cd6c7ee6f2274bb950b2310` | Blocked: AliasChoices/AliasPath are unhashable in proposed alias set. | | [#2667](#2667) `137b253c9e8b50602c39466c135b2e3c7400e3e0` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2666](#2666) `f2a1c390cd605c9928029d937c860b22456d26f2` | Next compact batch: promising fixes, require exact-head runtime and combined validation. | | [#2664](#2664) `77f427ad196bed5c3bd6d61b3bd0855285d8e8e1` | Split first: useful Mistral usage-only fix, but Google empty candidates can erase safety refusal. | | [#2662](#2662) `4c6e06613fc30a3ef6d29374e8df92bfb2a4122d` | Next compact batch: promising fixes, require exact-head runtime and combined validation. | | [#2660](#2660) `1207effdd29b1aa1da9e0a283eda5551835f1a01` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2657](#2657) `8f619b3ab20d5cc6914b42c38bba80f6aa8c4585` | Next compact batch: promising fixes, require exact-head runtime and combined validation. | | [#2656](#2656) `01c7bee784497eb87c7edab13ff1c64095f2c93c` | Deferred docs/examples: maintenance/product choice; no correctness-release necessity. | | [#2655](#2655) `f4ce1943f2d666c465728062bc342d8934c55e66` | Next compact batch: promising fixes, require exact-head runtime and combined validation. | | [#2652](#2652) `4bd39745d0ba809e293973697aa7a0be8ab64c81` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2651](#2651) `68786153500ce306f5bd65bb051aedd080e48a73` | Next compact batch: promising fixes, require exact-head runtime and combined validation. | | [#2649](#2649) `f704f3530caef4891214a00dac7abd8496e92e96` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2647](#2647) `9bfaa3b75f83568063fa38dbd84d28a0a0848c0d` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2646](#2646) `a6dce755f054b1b2088faf8fffaea7dbfac05db7` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2644](#2644) `eda57883460ed8329775e9de4ede4a87b2786c67` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2643](#2643) `0fd74545d374afb249d01667a280115fa75b1156` | Deferred: main rejects async validators; set traversal is not a release necessity. | | [#2642](#2642) `f208aec71909a7b27358bbdbfc2638a574585776` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2641](#2641) `2506e18dd4ed4e12bcc25069a4ce449138cf03b1` | Deferred: reconcile strict-schema required/defaulted fields and mapping policy together. | | [#2640](#2640) `ca1fe9e902abdb5a1aea9eab04afdb133ae39c83` | Separate maintainer metadata hygiene. | | [#2639](#2639) `e91095777cf4d031e7414bcaa427ab989c42f96e` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2638](#2638) `54ee418cad55aa93d9b6d1623a2e1b5ba066796e` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2637](#2637) `8b580fe0f2503dfa758a2d5be5957db81794c6ef` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2636](#2636) `3152a697f423b32bbe25af8021a948c35d8af41c` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2634](#2634) `aab02eaba1215a0f1e6ccf2139e88b1cc5539a8d` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2633](#2633) `2f337b3148717a76209616b72052ff1d4fb95709` | Deferred: timeout contract needs regression proof; current CI red. | | [#2632](#2632) `ad3e32283f0ae51b3f06f5e06dc0415be282c5f5` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2630](#2630) `e5515c629eb4a94fab9953a1647de0ee66797132` | Overlap: selected broader alternatives; older variants regress Python 3.9 or metadata. | | [#2629](#2629) `438debe231c3a49c9168b478ec82a82055983f47` | Integrate/revise: reviewed compact fixes; preserve compatibility and repair tests. | | [#2605](#2605) `7e7d33a821b1b1593257a820ab52e656317405a8` | Blocked: cache values inherit and retain weak keys; GC test does not prove collection. | | [#2604](#2604) `ce322502e3f4ba1f0ff62d5524965fec5233806a` | Deferred: markdown sanitization needs adversarial regression oracle. | | [#2602](#2602) `a1229322d2b865d0224a2a94d222375eae4396bc` | Deferred providers/auth: scope-triaged, need ownership, SDK/wire contracts and live evidence. | | [#2598](#2598) `6b153c8ba75e25461c43cd05c9b52f67ae3cb830` | Deferred providers/auth: scope-triaged, need ownership, SDK/wire contracts and live evidence. | | [#2574](#2574) `0df33ba1111a6dc9da6788429bab9d4106bef2ae` | Separate dependency maintenance: compatibility and supply-chain review required. | | [#2573](#2573) `2485aa6f4b9d7b7cb445214547968e1a7e61b564` | Separate dependency maintenance: compatibility and supply-chain review required. | | [#2572](#2572) `c152a36b244b5e2618bd5e06e13ee1ce1876fa65` | Separate dependency maintenance: compatibility and supply-chain review required. | | [#2571](#2571) `db4abe9654e386acbe9e64585b56bda419b0daa7` | Separate dependency maintenance: compatibility and supply-chain review required. | | [#2570](#2570) `47caa02a3a924ee4f889e6cba9572da58ff40398` | Separate dependency maintenance: compatibility and supply-chain review required. | | [#2531](#2531) `4f0a66465f96f08e256cdc3f0608e7578cf2ad9d` | Deferred docs/examples: maintenance/product choice; no correctness-release necessity. | | [#2468](#2468) `6e68201124bca8957d4fe5ca42bd4ef5203e77c6` | Deferred docs/examples: maintenance/product choice; no correctness-release necessity. | | [#2435](#2435) `bb31451d31df1220509538fbf4e4a01c0d7a79ca` | Deferred providers/auth: scope-triaged, need ownership, SDK/wire contracts and live evidence. | | [#2423](#2423) `3b4389f70fdefd30f0be65219d27e981ff4cd98a` | Deferred providers/auth: scope-triaged, need ownership, SDK/wire contracts and live evidence. | | [#2409](#2409) `87a9bf8a3a1579b0d394e92226cb315440c79427` | Deferred providers/auth: scope-triaged, need ownership, SDK/wire contracts and live evidence. | | [#2405](#2405) `82e90e9bea0da26e20d2d37add94b9cc29b42af7` | Deferred docs/examples: maintenance/product choice; no correctness-release necessity. | | [#2394](#2394) `bc55f4f639ad352fd9314b9f6f477971b6ee4e83` | Deferred product/security design: routing and injection-defense guarantees need evaluation/threat model. | | [#2384](#2384) `b7371363d705acb8c1cd344efc293cd42369ea69` | Deferred providers/auth: scope-triaged, need ownership, SDK/wire contracts and live evidence. | | [#2357](#2357) `182609c2e4789ebb40430ecba3407c27b50ebd52` | Deferred architecture stack: separate migration and release; tests/docs target parent branch. | | [#2356](#2356) `913a6053a0047b2c97c07768f9374c8a5243c9a9` | Deferred architecture stack: separate migration and release; tests/docs target parent branch. | | [#2355](#2355) `b3c44096ecd5f92619743bf3182ce21a3aef6e1d` | Deferred architecture stack: separate migration and release; tests/docs target parent branch. | | [#2322](#2322) `222c4f12430eea028f5895a68c96f15cbcd7513e` | Deferred providers/auth: scope-triaged, need ownership, SDK/wire contracts and live evidence. | | [#2321](#2321) `b70f25defed4c8e0927b836fdb9ea01a9b5c1d9f` | Deferred product/security design: routing and injection-defense guarantees need evaluation/threat model. | | [#2311](#2311) `d5df24eb3a973a0462c04988a69e05baddd3ad79` | Deferred docs/examples: maintenance/product choice; no correctness-release necessity. | | [#2306](#2306) `a960f6462a22a559f05ae14e9159c84e71bae19f` | Deferred providers/auth: scope-triaged, need ownership, SDK/wire contracts and live evidence. | | [#2283](#2283) `5bbaa6217e83b5d69d862fd12470aef57a77c5ca` | Deferred providers/auth: scope-triaged, need ownership, SDK/wire contracts and live evidence. | ## All Open Issues - [#2260](#2260): #2306 provider ownership needed. - [#2272](#2272): no matching PR; benefits unverified. - [#2316](#2316): #2321 needs threat model. - [#2383](#2383): #2384 broader Azure provider deferred. - [#2393](#2393): #2394 routing product choice. - [#2403](#2403): memory feature, related #2405 but not duplicate of #2404. - [#2404](#2404): #2405 cookbook product choice deferred. - [#2408](#2408): #2409 authentication deferred. - [#2603](#2603): #2605 does not prove leak fixed; sustained leak not reproduced. - [#2613](#2613): #2629 selected, preserve supported schemas/scalars. - [#2631](#2631): #2632 selected; #2637/#2639 overlapping. - [#2645](#2645): #2646 selected; #2647/#2652/#2704 overlaps. - [#2650](#2650): #2651 next batch. - [#2654](#2654): #2655 next batch. - [#2659](#2659): #2673 selected; #2660/#2680 alternatives. - [#2661](#2661): #2662 next batch. - [#2665](#2665): #2666 next batch. - [#2669](#2669): #2671 deliberate policy deferred. - [#2674](#2674): #2675 selected and unified. - [#2676](#2676): #2677 next batch. - [#2681](#2681): #2686 next batch; forced default remains limitation. - [#2682](#2682): #2683 next batch. - [#2684](#2684): #2685 blocked on native history. - [#2687](#2687): #2688 selected. - [#2694](#2694): #2700 policy deferred. - [#2695](#2695): #2701 blocked. - [#2696](#2696): #2698 selected; #2703 duplicate. - [#2705](#2705): new coordinator fix. No superseded item is closed yet: consolidation must receive review first. Use this PR rather than merging overlapping patches separately. Strict-schema #2701 is blocked by recursive $ref overflow and mapping semantics; #2700's EOF buffering is excluded because it breaks streaming. The deferred dependency/provider/architecture groups require separate validation and ownership.
…ng-alias-fields # Conflicts: # CHANGELOG.md
|
The string-alias coverage here fixes the plain Minimal reproduction on current main (Python 3.12, Pydantic 2.12.5): from pydantic import AliasPath, BaseModel, Field
from instructor.dsl.partial import Partial
class Inner(BaseModel):
value: int
class Outer(BaseModel):
payload: Inner = Field(validation_alias=AliasPath("container", "payload"))
snapshot = list(Partial[Outer].model_from_chunks(['{"container":{"payload":{"value":1}']))[-1]
assert isinstance(snapshot.payload, Inner) # current: dict
|
|
Good catch — that is a real limitation, but it is a different mechanism from what this PR fixes, not a missing branch in the alias-key set.
I have added an explicit "Known limitations" note to the PR description pointing at |
A validation alias may be an AliasChoices or AliasPath, and _alias_keys collected them in a set literal, raising TypeError for unhashable objects before canonical_field_name could map the parsed key. Collect into a list/tuple, keep only strings, expand AliasChoices string choices, and ignore AliasPath (documented limitation; nested path lifting is a separate change). Add partial-streaming regressions for AliasChoices keys and AliasPath not crashing.
|
Thanks for splitting the AliasPath behavior out — #2668 stays scoped to string aliases (and now resolves |
…-alias-fields # Conflicts: # CHANGELOG.md
AI-assisted development (investigation, patch and tests written by an agent, verified and reviewed by the account owner).
Describe your changes
Partial[Model].model_from_chunks()loses nested model instances for any field declared with a validation alias._build_partial_object()iterated the parsed JSON keys and used them twice: as the lookup key intomodel.model_fields, and as the key of the dict handed tomodel.model_construct().model_fieldsis keyed by the Python attribute name, while the streamed JSON is keyed by the alias thatmodel_json_schema()advertises, so both uses miss for an aliased field. The consequence is two-fold:dictinstead of being validated;model_construct()populates__dict__withlocand the declared attributelocationfalls through to the "missing fields" branch and is replaced by an empty model.Callers therefore get
obj.location == {}plus a strayobj.locdict, andobj.location.cityraisesAttributeError. Same for aliasedlist[Model]andOptional[Model]fields.The patch resolves the parsed key to the attribute name once per field (
canonical_field_name, coveringalias,validation_aliasandAliasChoices), keeps the raw key for the completeness tracker because the tracker works on the JSON text, and stores under the attribute name. Models without aliases take thekey in model.model_fieldsfast path and behave exactly as before.Repro (no API key needed, this is what the provider streaming handlers call):
Issue ticket number and link
No existing issue or open PR covers this — I searched
repo:567-labs/instructorforalias,partial aliasandmodel_from_chunksacross issues and PRs before opening. #2600 changed the same function for nullable list fields, which is the behaviour this extends to aliased fields.Checklist before requesting a review
docs/concepts/streaming.md.How this was verified
details
Environment: python 3.11,
PYTHONPATHpointing at the checked-out tree,instructor.__file__confirmed to resolve inside the tree,-p no:opikto keep conda's unrelated plugin from aborting collection.Base control (
e12f8b49203b0c1f253d27c1e709d0a09b9fc5a8,instructor/v2/dsl/partial.pyrestored from that commit,git statusfor the file empty):The passing case is the deliberate non-alias control, which shows the harness measures the real path rather than failing for an unrelated reason.
Same file, same command, with the patch applied:
No regression in the surrounding suites:
Static checks, both clean:
Per
CLAUDE.mda behavior change needs a[Unreleased]entry inCHANGELOG.md; that entry links the PR number, so it follows in a second commit as soon as this PR is open.Known limitations
details
validation_alias=AliasPath(...)is not resolved in partial snapshots:_alias_keys()only collects string aliases andAliasChoices, and an alias path would need its nested value lifted while the object is still incomplete. Covered here only as a documented scope boundary; the reproduction lives in the review thread. String aliases (the plainalias=case that dropped fields before this PR) are covered.