Repository navigation
Add experimental shared Documents abstractions - #7835
luisquintanilla merged 11 commits into
Conversation
Introduce the provider-neutral Documents hierarchy, ownership and artifact lifetime contracts as a standalone prerequisite for document extraction. Include experimental diagnostic registration, API baseline, documentation and focused tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
Mutation, ownership rollback, disposal, and Markdown projection paths contain correctness issues that should be resolved before approval.
8 open findings
Artifact disposal stops after the first disposal exception · New Failed recursive attachment leaves descendants partially attached · New Self-assignment of root section incorrectly throws · New Mutation changes backing value before disposal check · New Empty extension type reports the wrong argument exception · New Same-slot element assignment is incorrectly rejected · New Same-artifact replacement incorrectly increments document version · New Projection emits invalid Markdown table syntax · New
What changed in this PR
Adds experimental provider-neutral document abstractions for future extraction and ingestion integrations.
Changes:
- Introduces document hierarchies, elements, tables, references, and owned artifacts.
- Adds versioning, Markdown projection, ownership, and disposal behavior.
- Registers
EXTEXP0019with API baselines, documentation, and tests.
| File | Description |
|---|---|
Directory.Build.targets |
Suppresses the new experimental diagnostic internally. |
docs/list-of-diagnostics.md |
Documents EXTEXP0019. |
src/Shared/DiagnosticIds/DiagnosticIds.cs |
Registers the Documents diagnostic constant. |
src/Libraries/Microsoft.Extensions.Documents.Abstractions/README.md |
Documents scope, behavior, and usage. |
src/Libraries/Microsoft.Extensions.Documents.Abstractions/Microsoft.Extensions.Documents.Abstractions.json |
Defines the experimental API baseline. |
src/Libraries/Microsoft.Extensions.Documents.Abstractions/Microsoft.Extensions.Documents.Abstractions.csproj |
Configures the new library. |
src/Libraries/Microsoft.Extensions.Documents.Abstractions/Document.cs |
Implements document ownership, traversal, versioning, and disposal. |
src/Libraries/Microsoft.Extensions.Documents.Abstractions/DocumentElement.cs |
Implements the element hierarchy and collections. |
src/Libraries/Microsoft.Extensions.Documents.Abstractions/DocumentReferences.cs |
Adds references and owned artifacts. |
src/Libraries/Microsoft.Extensions.Documents.Abstractions/DocumentTable.cs |
Adds addressable tables and Markdown projection. |
test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests/Microsoft.Extensions.Documents.Abstractions.Tests.csproj |
Configures the test project. |
test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests/DocumentTests.cs |
Tests document lifecycle and hierarchy behavior. |
test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests/DocumentElementTests.cs |
Tests common element behavior. |
test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests/DocumentExtensionElementTests.cs |
Tests opaque extension elements. |
test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests/DocumentImageElementTests.cs |
Tests image elements. |
test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests/DocumentReferencesTests.cs |
Tests references and artifacts. |
test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests/DocumentSectionTests.cs |
Tests nested sections. |
test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests/DocumentTableCellCollectionTests.cs |
Tests table-cell ownership and mutation. |
test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests/DocumentTableCellTests.cs |
Tests cell addressing. |
test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests/DocumentTableElementTests.cs |
Tests table projection and dimensions. |
test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests/DocumentTextElementTests.cs |
Tests text kinds and header levels. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Recover the 23-file Extraction slice from 2d28dfd57712b55f941fbb1dbf41311eeaee8c8b, replacing obsolete semantic/geometry/options/usage/metadata/OTel contracts and their tests. Retain MEDE0001, forward-port all supported targets, fix artifact failure cleanup and cancellation, and validate the focused Documents/Extraction solution. Temporary Documents prerequisite: ff1b5ac from PR dotnet#7835, imported unchanged as 4888286. Its four production files match canonical d35d5cb74695c4ba970d6ad198006b84354badc0. Reconcile after dotnet#7835 merges; no MEDI/provider bridge is included. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1634013&view=codecoverage-tab |
Add source frames, ordered polygon regions, reported confidence, structured annotations, merged and empty table cells, and operation-scoped break-glass output with explicit ownership. Include scoped regression tests, API baseline and documentation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Import the shared Documents correction from canonical commit 37dad1a, keeping production, API baseline, documentation and regression tests identical. This remains the explicit temporary prerequisite for the existing Extraction PR. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Transfer source frames, annotations, confidence, merged and empty table cells, structured extension values and operation-scoped native/original output into shared Documents. Add isolated per-call overrides, default raw retention with opt-out enforcement, safe cleanup, regression tests and API documentation. The shared Documents prerequisite is isolated in d830ad6, matching dotnet#7835 commit 37dad1a. The runtime README also removes the obsolete prerequisite SHA; existing local candidates predate that documentation-only follow-up. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1635121&view=codecoverage-tab |
Pin producer roles, literal contents, spans, source frames, raw ownership, and distinct stored/structural Markdown views without changing core behavior or APIs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1635677&view=codecoverage-tab |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved ownership, disposal, mutation, rendering, and performance defects block approval.
12 open findings
Preflight content artifacts before registering annotations · New Failed recursive attachment leaves descendants partially attached Artifact disposal stops after the first disposal exception Avoid re-registering all sources for each annotation · New Validate disposal before assigning markdown · New Use an indexed coverage map for table lookups · New Projection emits invalid Markdown table syntax Same-artifact replacement incorrectly increments document version Same-slot element assignment is incorrectly rejected Empty extension type reports the wrong argument exception Mutation changes backing value before disposal check Self-assignment of root section incorrectly throws
🧠 Review effort: Balanced
Preserve cleanup failures and attachment ownership, enforce disposed mutation guards, and add registration and table coverage regressions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep supplied provider-native objects inspectable when original response-content capture is disabled, and scope disabled status to content only. Add focused availability and borrowing regressions and regenerate the Documents API baseline. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1649717&view=codecoverage-tab |
Replace generalized annotations and opaque evidence/page references with a typed page association and optional polygon. Keep native inspection and explicit resource ownership; internalize bookkeeping helpers. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep canonical content and typed source ownership while removing unused element bags, extension envelopes and redundant authoring helpers. Use optional text/cell roles and explicit supplied Markdown. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove core rendering, adopt the complete ExtractionDocument family, and migrate payload, hierarchy, source and byte-retention contracts and tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1658891&view=codecoverage-tab |
Retain interpretable source layout and borrowed native inspection while removing the operation/artifact graph. Make TextContent authoritative and preserve image transcription and structural safety. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
luisquintanilla
left a comment
There was a problem hiding this comment.
@adamsitnik can I please get a review on this.
Thanks!
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1660145&view=codecoverage-tab |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1664674&view=codecoverage-tab |
…ns (#7588) * Add IOcrClient OCR/document-extraction capability to Microsoft.Extensions.AI Introduces IOcrClient as a provider-neutral OCR/document-parsing capability in Microsoft.Extensions.AI.Abstractions, following the same abstraction + builder + middleware + DI shape as the existing capability family (IChatClient, ISpeechToTextClient, etc.). Abstractions (Microsoft.Extensions.AI.Abstractions): - IOcrClient, DelegatingOcrClient, OcrClientExtensions, OcrClientMetadata - OcrOptions, OcrResult, OcrPage, OcrTable, OcrTableCell, OcrBlock, OcrBoundingRegion, OcrUsage, OcrProgress Middleware + DI (Microsoft.Extensions.AI): - OcrClientBuilder, AsBuilder, AddOcrClient/AddKeyedOcrClient - LoggingOcrClient, OpenTelemetryOcrClient, ConfigureOptionsOcrClient and their builder extensions, mirroring the ISpeechToTextClient template All public surface is marked [Experimental] under the MEAI001 (AIOcr) diagnostic id. Includes unit tests for both libraries and updated API baselines. * Add OcrImage type and OcrPage.Images for extracted figures Adds an optional OcrImage sink so engines can return page images/figures when OcrOptions.IncludeImages is requested. Every member is optional: document-native engines (Mistral OCR inline images, Azure Document Intelligence figures) populate Content with rendered bytes; a vision-LLM transcriber may populate only Caption. One shape serves both provider archetypes. * Add UriContent overload to OcrClientExtensions Symmetric with the existing DataContent overload. Handles self-contained data: URIs by delegating to the DataContent path and does no file/network IO. For file: and remote URIs it throws NotSupportedException, leaving native URL passthrough (Mistral document_url, Azure DI uriSource) as an explicit open design question. * Rename IOcrClient.GetTextAsync to ExtractAsync The method returns a rich OcrResult (markdown, tables, figures/images, blocks, confidence, language), not plain text, so GetTextAsync was a misnomer. ExtractAsync names the document-extraction operation accurately. Scoped to the Ocr/ types only; ISpeechToTextClient.GetTextAsync is unrelated and unchanged. Alternatives considered for maintainer discussion: GetDocumentAsync, AnalyzeAsync. * Add OcrImage to IngestionDocumentImage reader mapping * Add ExtractFromUriAsync opt-in remote downloader to IOcrClient extensions * Finish GetTextAsync to ExtractAsync rename in OCR tests and API baselines Complete the source rename across the OCR test suites in both Microsoft.Extensions.AI.Abstractions.Tests and Microsoft.Extensions.AI.Tests, and regenerate the two API baselines (which also reflect the round-2 members ExtractFromUriAsync, OcrImage, and OcrPage.Images). Also fix pre-existing StyleCop/Sonar violations in the OCR tests that were blocking the core test project from compiling. * Fix net462 build: use buffered Stream.CopyToAsync overload in OCR test Stream.CopyToAsync(Stream, CancellationToken) does not exist on net462/ netstandard2.0, so the 2-arg call failed to compile (CS1503) on the net462 leg. Use the #if !NET conditional buffer-size overload, matching the existing DataContent.cs convention. * Shape OCR bounding geometry as points and 1-base page numbers Introduce OcrPoint and OcrBoundingBox readonly record structs and retype OcrBoundingRegion.Polygon as IReadOnlyList<OcrPoint> with a typed OcrBoundingBox GetBounds() return. This makes odd or empty vertex lists unrepresentable (fixing the GetBounds inverted-bounds edge case) and reads self-documenting, while still carrying a rotation-skewed quadrilateral. Rename OcrPage.Index (zero-based) to OcrPage.PageNumber (one-based) so it correlates directly with OcrBoundingRegion.PageNumber, matching Azure Document Intelligence, PdfPig, and human page conventions, and removing the off-by-one adjustments providers had to make. Update the internal OcrDocumentReader and the OCR tests, and regenerate the Microsoft.Extensions.AI.Abstractions API baseline. * Align IOcrClient surface with the MEAI family ahead of API review Family-consistency changes surfaced by an API-review rehearsal against the sibling abstractions (IChatClient, ISpeechToTextClient): - Streaming: add IAsyncEnumerable<OcrResponseUpdate> via ExtractStreamingAsync (the unary/streaming/GetService triad, matching IChatClient) plus a ToOcrResult/ToOcrResultAsync reducer; retire IProgress<OcrProgress> and the OcrProgress type (progress folds onto OcrResponseUpdate). - Unseal the OCR DTOs (OcrOptions, OcrResult, OcrPage, OcrBlock, OcrTable, OcrTableCell, OcrImage, OcrBoundingRegion, OcrUsage) to mirror the unsealed ChatResponse/ChatOptions family shape. - Geometry units: add OcrPage.Width/Height and an OcrCoordinateUnit (ChatRole-style open struct: Pixel/Inch/Normalized) so bounding coordinates are interpretable across engines. - Model OcrBlock.Kind and OcrTableCell.Kind as ChatRole-style open structs (OcrBlockKind, OcrTableCellKind) instead of raw strings. - OcrBoundingRegion.GetBounds() now returns OcrBoundingBox? (null on empty polygon) instead of an ambiguous all-zero default. - Remove the leaky OcrResult.OcrSource; document OcrTable.Cells as authoritative when non-null. - Add <exception> docs to the AddOcrClient/AddKeyedOcrClient overloads. Updates the middleware (Logging/OpenTelemetry/ConfigureOptions), the MEDI OcrDocumentReader consumer, OCR tests, and both API baselines accordingly. * Reshape OCR result model: reading-order elements, doc-level coordinates, usage tokens Continue the IOcrClient reshape ahead of API review (#7587/#7588). - Replace parallel OcrPage.Blocks/Tables/Images with a single reading-order Elements list over a new polymorphic OcrElement base (OcrBlock/OcrTable/OcrImage derive); consumers project with OfType<T>(). - Add optional nested OcrTableCell.Elements for structured cell content; keep the Content string as a flat-text convenience. - Convert OcrCoordinateUnit to a closed enum and add Point; add an OcrCoordinateOrigin enum; move both to document level (OcrResult/OcrPageResult) and remove the per-page CoordinateUnit. - Keep OcrBlockKind and OcrTableCellKind as open structs; add RowHeader and RowSection well-known cell kinds. - Add nullable Input/Output/TotalTokenCount to OcrUsage for the vision-LLM path. - Rename Markdown to Text on OcrPage/OcrResult; drop response ModelId, OcrPage.Confidence, and OcrOptions.IncludeImages; FromRectangle takes float. - Keep ToOcrResult/ToOcrResultAsync reducers and the convenience overloads as extension methods, matching the MEAI ChatResponseExtensions precedent. - Regenerate the ApiChief baselines for the reshaped surface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19ea13dd-f444-4942-b751-162711478580 * Move OCR coordinate frame per-page; add OcrPageDimensions (SPIKE-07/08) SPIKE-07/08 primary-source verification refuted the round-1 assumption that a document uses one uniform coordinate unit. Google Document AI models Page.Dimension{width,height,unit} per page, and Azure DI's per-page DocumentPage.Unit is "pixel" for image inputs and "inch" for PDF, so one analyze call over a mixed batch returns different units on different pages. - Group OcrPage.Width/Height into a new OcrPageDimensions readonly record struct (the extent; an atomic pair several engines bundle). - Move CoordinateUnit + CoordinateOrigin from the document level (OcrResult, OcrPageResult) onto OcrPage; they are siblings to the dimensions extent, together describing the per-page coordinate system. - Drop the reducer's last-non-null coordinate carry-forward: pages already carry their own unit/origin. - Defer continuous page-rotation angle (Azure-family-only) to AdditionalProperties for v1; element rotation is already carried losslessly by the polygon OcrBoundingRegion. - Update per-page tests and regenerate the ApiChief baseline (32 public types). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19ea13dd-f444-4942-b751-162711478580 * Add per-cell geometry and OcrPage.RawRepresentation (SPIKE-06) SPIKE-06 built an exhaustive 14-engine raw-output inventory to justify the RawRepresentation/AdditionalProperties escape hatches, then a promote interview resolved which recurring un-homed fields become first-class. - Add BoundingRegion, Confidence, RawRepresentation, and AdditionalProperties to OcrTableCell, mirrored member-for-member from OcrElement. Five engines (Textract, Google Document AI, Azure DI, Adobe, Docling) emit per-cell geometry, and a cell has its own rectangle even when empty or padded. OcrTableCell deliberately does not derive from OcrElement (a cell is not a page-reading-order element) and no shared base type is extracted yet; mirroring the members keeps that a reversible way-station under [Experimental]. - Add [JsonIgnore] object? RawRepresentation to OcrPage. Every other node carries it; the page node was the lone exception. Because the page rides through ToOcrResult reduction, provider-native page data now survives into OcrResult.Pages, closing a silent per-page raw data-loss. - Detected language is deferred (not promoted) to a standardized AdditionalProperties key rather than a lossy typed field. - Add OCR tests for cell geometry round-trip and per-page raw survival; regenerate the ApiChief baseline (five additive members, no new types). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19ea13dd-f444-4942-b751-162711478580 * Extract OCR into Microsoft.Extensions.DocumentExtraction peer library Move the reshaped OCR surface out of Microsoft.Extensions.AI(.Abstractions) into a standalone peer library, Microsoft.Extensions.DocumentExtraction, mirroring VectorData / DataIngestion. OCR is document extraction rather than an AI-branded concern, so it gets its own package + namespace (Microsoft.Extensions.DocumentExtraction) with domain-noun naming (Document*/DocumentExtraction*) instead of the MEAI-internal verb scheme. - New Microsoft.Extensions.DocumentExtraction.Abstractions: the Document* model, IDocumentExtractionClient, DocumentExtractionResult/Options/ ClientMetadata/PageResult, extensions, DelegatingDocumentExtractionClient. - New Microsoft.Extensions.DocumentExtraction: builder + Logging/ OpenTelemetry/ConfigureOptions delegating clients + DI/builder extensions, with self-contained internal telemetry helpers (no MEAI-core coupling). - Remove the OCR types from Microsoft.Extensions.AI(.Abstractions) and shrink both API baselines accordingly (only OCR type-blocks removed; the manual params edits and JSONC comments are preserved byte-for-byte). - Populate the two new Stage=normal baselines (peer precedent: VectorData ships a populated baseline for its [Experimental] surface). - Repoint Microsoft.Extensions.DataIngestion's OcrDocumentReader onto DocumentExtraction.Abstractions. - Add DiagnosticIds MEDE0001 for the new [Experimental] surface. - Retarget all OCR tests to two new DocumentExtraction test projects. Green across all five TFMs (netstandard2.0, net462, net8.0, net9.0, net10.0); DocumentExtraction tests 31/31 + 29/29 on net8/9/10; the MEDI OcrDocumentReader test stays green after the repoint. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19ea13dd-f444-4942-b751-162711478580 * Fix CI: remove dangling TestOcrClient.cs <Compile> link The OCR test helper moved to Microsoft.Extensions.DocumentExtraction.Abstractions.Tests (TestDocumentExtractionClient.cs) during the extraction, but Microsoft.Extensions.AI.Tests.csproj still linked the moved-away ..\Microsoft.Extensions.AI.Abstractions.Tests\TestOcrClient.cs, causing error CS2001 (source file not found) on all TFMs in CI. No MEAI test references any Ocr type, so the link is safe to delete. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19ea13dd-f444-4942-b751-162711478580 * Add README.md for the DocumentExtraction packages Every packable library in the repo ships a README.md (auto-included as PackageReadmeFile on pack); the two new DocumentExtraction packages were missing theirs, so packing failed with NU5019. Add READMEs mirroring the DataIngestion peers, describing the document-extraction capability and the Abstractions-vs-core package split. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19ea13dd-f444-4942-b751-162711478580 * Add experimental shared Documents abstractions Introduce the provider-neutral Documents hierarchy, ownership and artifact lifetime contracts as a standalone prerequisite for document extraction. Include experimental diagnostic registration, API baseline, documentation and focused tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Recover selected Extraction contract over shared Documents Recover the 23-file Extraction slice from 2d28dfd57712b55f941fbb1dbf41311eeaee8c8b, replacing obsolete semantic/geometry/options/usage/metadata/OTel contracts and their tests. Retain MEDE0001, forward-port all supported targets, fix artifact failure cleanup and cancellation, and validate the focused Documents/Extraction solution. Temporary Documents prerequisite: ff1b5ac from PR #7835, imported unchanged as 4888286. Its four production files match canonical d35d5cb74695c4ba970d6ad198006b84354badc0. Reconcile after #7835 merges; no MEDI/provider bridge is included. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Exclude obsolete unrelated AI baseline whitespace Keep the Extraction recovery diff limited to its own contracts and the explicit Documents prerequisite; drop the old PR's unrelated AI baseline newline-only change. Validated production source is unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Sync Documents layout fidelity prerequisite from #7835 Import the shared Documents correction from canonical commit 37dad1a, keeping production, API baseline, documentation and regression tests identical. This remains the explicit temporary prerequisite for the existing Extraction PR. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Preserve extraction layout, structured values and raw-output controls Transfer source frames, annotations, confidence, merged and empty table cells, structured extension values and operation-scoped native/original output into shared Documents. Add isolated per-call overrides, default raw retention with opt-out enforcement, safe cleanup, regression tests and API documentation. The shared Documents prerequisite is isolated in d830ad6, matching #7835 commit 37dad1a. The runtime README also removes the obsolete prerequisite SHA; existing local candidates predate that documentation-only follow-up. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Fix extraction cleanup and per-build logging correctness Preserve initiating extraction failures while attempting all eligible artifact cleanup; leave foreign-owned artifacts untouched. Resolve logging factories independently per pipeline build and document the existing shared-instance DI lifetime behavior with independent factory regressions. Synchronize the already-verified canonical Documents prerequisite repairs and fidelity tests without changing public APIs, raw defaults, registration lifetimes, package placement, or table projection. Exact 18-path tree matches frozen tested tree 2d8def9. Fresh bounded validation: five production targets, zero build warnings/errors; 87 abstraction, 12 middleware, and 197 prerequisite cases per net10/net9/net8/net472 target, all passing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Separate native inspection from response-content capture Keep supplied provider-native objects inspectable when original response-content capture is disabled, and scope disabled status to content only. Add focused availability and borrowing regressions and regenerate the Documents API baseline. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Separate Extraction native inspection from optional response content Default CaptureRawContent to false without gating native source or annotation objects. Reject retained body-policy violations while preserving existing ownership and cleanup. Regenerate the API baseline and document availability and non-redaction semantics. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Preserve Extraction primary failures and verify raw-content policy Cover capture defaults, native identity, exact opt-in body bytes, nested policy violations, ownership and cleanup across all supported test targets. Preserve enumeration errors and cancellation when artifact or enumerator cleanup also fails. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Reduce Documents to typed content and source references Replace generalized annotations and opaque evidence/page references with a typed page association and optional polygon. Keep native inspection and explicit resource ownership; internalize bookkeeping helpers. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Reduce Extraction associations to typed sources and metadata snapshots Align the reduced shared Documents prerequisite, replace generalized annotations and evidence with source references, and transfer provider-specific metadata snapshots without introducing normalized schemas. Preserve blank-page/source registration, independent native inspection, nested body-policy enforcement, ownership and primary-failure cleanup guarantees. Regenerate the real API baseline. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Internalize Extraction result disposal bookkeeping Keep disposal behavior public without exposing an unconsumed bookkeeping flag in the reduced contract. Regenerate the real API baseline. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Migrate Extraction regressions to reduced source and metadata contract Verify typed source ordering and snapshots, metadata transfer and borrowing, reduced public API, native access independent of content capture, recursive policy enforcement and existing cleanup guarantees across supported test targets. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Migrate Documents regressions to reduced source references Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Keep reduced Extraction lifetime fixtures analyzer-clean Use explicit fixture ownership and test-context task creation while preserving primary-error, cancellation and borrowed-native lifetime assertions. Leave pre-existing file-size style warnings outside this bounded correction. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Simplify Documents to an exchange-first contract Keep canonical content and typed source ownership while removing unused element bags, extension envelopes and redundant authoring helpers. Use optional text/cell roles and explicit supplied Markdown. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Use a direct Documents exchange boundary for extraction Compile-prerequisite snapshot, not final acceptance: return Task<Document> directly, remove public staging and finalization protocol, snapshot delegation options and log lifecycle without serializing payloads. Preserve caller input and returned document ownership, including cleanup when completion logging fails. Regenerate real API baselines and document independent Documents/Extraction/consumer composition. Final direct-contract regression validation follows separately. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Validate direct document extraction and composition ownership Replace retired staging-only regressions with direct canonical-document exchange, source-body/native lifetime, options snapshot, cancellation/error and middleware composition tests. Verify unreturned documents are released when completion logging fails and preserve primary errors on cleanup or failure logging. Actual four-target runners and integrated build pass; staging retirements and quality review are recorded in isolated session artifacts. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Apply surgical document extraction API review corrections Preserve the reviewed data model, remove structural rendering, and correct client lifetime and cleanup contracts. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Simplify preview document and extraction contracts Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Replace extraction interface with an evolvable abstract client Migrate composition and DI to the abstract client, preserve extraction and cleanup semantics, qualify logging failures, and remove the unused logging configuration callback. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Sync accepted Documents prerequisite from locked public snapshot Copy exactly six reviewed Documents source, API inventory, documentation and regression-test blobs from e08fe2e so Extraction provides one coherent public bootstrap source snapshot. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * Make extraction package READMEs consumer-focused Document package selection, installation and practical extraction, logging and DI examples without development history or PR lifecycle guidance. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19ea13dd-f444-4942-b751-162711478580


Summary
Introduce a shared, provider-neutral document model that extraction engines, applications and ingestion pipelines can exchange without translating between competing element hierarchies.
The model lives in
Microsoft.Extensions.Documents.Abstractions, underMicrosoft.Extensions.Documents. Applications can construct it directly; an extraction client is not required.What the model provides
List<T>.AIContent, not an aggregate copy of descendants. Text nodes useTextContent.Textas their single authority. Image OCR/transcription and alternative description remain separate facts.RawRepresentationfor provider-specific inspection. It is excluded from default JSON, but that is not redaction or a durable raw-response archive.How the PRs fit together
This PR owns the document model. #7588 adds extraction clients that return it. #7904 lets MEDI process it inside the retained
IngestionDocumentenvelope, sharing the exact graph rather than replacing the ingestion root or copying the document.This package does not provide extraction engines, rendering, ingestion orchestration or provider-operation tracking. Native objects are not implicitly disposed or deep-cloned; their usability depends on the real provider lifetime.
Suggested review focus
ExtractionDocument*, while the package/namespace remain Documents. Naming and API approval are still review decisions.Original PR description (preserved verbatim)
Why this change
Propose an independent, provider-neutral document exchange boundary shared by extraction engines and ingestion consumers. Applications can construct the model directly; it is not an OCR engine, editor, ingestion pipeline or rendering framework.
Simplified first-preview contract
ExtractionDocument*types in unchanged packageMicrosoft.Extensions.Documents.Abstractions/ namespaceMicrosoft.Extensions.Documents. Naming/package/API approval remains a team decision.AIContentis not an aggregate copy of descendants.TextContent.Text; no competing general-elementText. Nonnull TextContent is enforced even through base-reference assignments; rejected mutations retain the old payload. Provider Markdown is preserved, not reinterpreted as promised plain text.Textis genuine OCR/transcription. AlternativeText is independent description/caption. Original asset Source and current payload URI are distinct; neither is fetched by the model.This revision deliberately does not standardize original wire bytes, detached raw-response storage, capture status, per-operation identity or output provider/model metadata. Native inspection is subject to real provider lifetimes. JSON exclusion is not redaction.
Review map
Published head
ee9ee634c9f1e649f409e0d2cf0efd9318437d90, treec90ee4da7d7098f930329c7cbede3f6e1316ff46.src/Libraries/Microsoft.Extensions.Documents.Abstractions.test/Libraries/Microsoft.Extensions.Documents.Abstractions.Tests, including PreviewContractTests.Executed acceptance and limits
Exact sealed-source Documents tests: 211 on each of net10/net9/net8/net472 = 844 passed, zero failed/skipped. Parent integration independently reproduced the sealed tree and reran all four targets, also 844 passed; these overlap, not additional distinct cases. Production covers net10/net9/net8/net462/netstandard2.0 with zero warnings/errors.
Actual ApiChief inventory changes 17→14 types and 89→71 members. Native delta retains the known string ApiStage parser defect; independent member comparison is not represented as a native-tool pass. Reduced counts retire tests of the intentionally deleted graph; structural/layout/lifetime/mutation coverage remains. All 40 legacy multiargument core text calls were reconciled; all 106 current calls explicitly name role arguments to avoid silent migration into the new second parameter.
Fresh immutable review version
10.10.0-review.20261102.1is packed from public full core commit0f69c5cd069e2a8bc53e5bc0021c6825b4d35726/ tree102a40f1bfb67efc0746bad6b64faa08c65fe169. Actual nupkg-only parent acceptance passes 38 checks and all four runtime DLL hashes match canonical archives. Canonical receipt SHA256bb66839bd51050f92ec5c342912827cdcc022363986aa80e21ef77252851fe4e.See MEDI/bridge #7904 for its current ingestion-envelope reconciliation, owning acceptance and prerequisite integration gate; earlier migration receipts do not certify a later owning API revision. Toolkit passes512 canonical-package cases plus512 on each hosted Windows/Ubuntu platform in run41472886642. Those validate synthetic/offline boundaries, not live service certification. Old review packages remain unchanged. The canonical core candidate is not on a public package feed; Toolkit records its actual immutable public-source bootstrap.
Exact-head Azure build 1660145 completed/success: Ubuntu, Windows, coverage and aggregate checks all succeed; CLA succeeds. Its PR merge revision
c514813dc45a902af9546c7163ecbcc56904367ahas this published head as a parent. This check result is distinct from downstream prerequisite landing and API approval.No merge, official release, API approval, demo migration, paid/live service request or repository-wide validation claim. Related design discussion: #7587. Experimental diagnostic:
EXTEXP0019.Microsoft Reviewers: Open in CodeFlow
Microsoft Reviewers: Open in CodeFlow