Skip to content

refactor(core)!: one type each for source, generated file, reasoning output and response metadata - #216

Draft
cunninghamcard-bit wants to merge 8 commits into
rfc-0036/tool-typesfrom
rfc-0036/output-content-types
Draft

cunninghamcard-bit wants to merge 8 commits into
rfc-0036/tool-typesfrom
rfc-0036/output-content-types

Conversation

@cunninghamcard-bit

@cunninghamcard-bit cunninghamcard-bit commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

What

Unify output content in aimux-core around the AI SDK's provider and text-generation types so providers, aggregation and bindings retain the same source, generated-file and reasoning information. This pull request follows rfc-0036/tool-types and precedes rfc-0036/provider-options-types in the stack. It adds the missing content variants, separates input and output usage details, adapts provider conversions and updates binding types.

Before and after

Concept Before After and upstream reference
Sources Repeated inline source fields and reduced SourcePart projections Source is a URL/document union reused by content, stream parts and result arrays, following LanguageModelV4Source. URL sources require url; document sources require media_type and title, with optional filename and metadata.
Generated files Repeated file fields and FilePart projections using the broader input-file union GeneratedFile uses GeneratedFileData, restricted to data or URL, following LanguageModelV4File and LanguageModelV4ReasoningFile. URL data can retain original_url, as in SharedV4FileDataUrl.
Reasoning Text-only projections could discard metadata ReasoningOutput retains metadata; aggregated reasoning can contain text or ReasoningFileOutput, following the ai reasoning-output module.
Content variants No custom content, reasoning files or approval requests Provider content and streams include these variants, following LanguageModelV4CustomContent, LanguageModelV4ReasoningFile and LanguageModelV4ToolApprovalRequest. Text-generation content uses parsed tool calls, approval outputs and wrapped reasoning files.
Usage One token-detail type shared by input and output InputTokenUsage and OutputTokenUsage have the separate fields in LanguageModelV4Usage; raw usage is restricted to a JSON object.
Response metadata and HTTP information Metadata repeated inline; request body and response headers stored separately Stream metadata wraps ResponseMetadata; Rust provider results carry request and response objects, following LanguageModelV4GenerateResult and LanguageModelV4StreamResult. The existing serialized adapter remains on this branch.
Provider output conversions Some document citations and thought output were missing or misclassified OpenAI Responses maps file, container-file and file-path citations to document sources. Google treats null web grounding as absent and maps retrieved documents; Vertex shares that conversion and emits inline files and thought text as file/reasoning output. These follow the corresponding upstream provider modules.

Upstream's dotted custom-kind constraint, URL and Date types, and numeric token types are TypeScript-only constraints without upstream runtime validation. Rust retains String and u32 for these values and Value for opaque bodies and metadata.

Tests

Hand-written tests that pin the old Rust shapes are deleted rather than rewritten. Existing upstream-ported tests and replay assertions are migrated where retained, and cassette replays remain. The branch also deletes upstream-ported DeepSeek request and Groq request-body cases; their restoration is fixed on rfc-0036/provider-factory-source, rather than being claimed as completed here. Cassette and fixture data are unchanged by this pull request. The self-generated contract-tests/ data and its reader tests were already deleted on rfc-0036/tool-types; they do not define the output contract.

Not in this pull request

  • Serialized provider result envelopes still use GenerateResultWire with top-level request_body and response_headers. Removing that adapter and carrying request/response information through text-generation results is fixed on rfc-0036/provider-result-types.

  • Anthropic document citations are not yet emitted as sources, and Bedrock still exposes a response body that upstream does not return. Both are fixed on rfc-0036/vendor-alignment.

  • Serde naming and binding representation remain pending maintainer decisions: snake_case fields, PascalCase external tags, absent Option values serialized as null where applicable, and generated Node fields that are required and nullable. This branch does not decide the cross-binding wire convention.

  • The call-layer ModelMessage tool-result shape remains pending the maintainer's decision; consolidating provider output types does not settle that separate message contract.

  • aimux-providers/tests/bedrock_remaining_test.rs, a translation of upstream Bedrock cases, is deleted here; it comes back adapted and un-ignored on vendor-alignment.

Not verified

No build or runtime checks were rerun for this documentation rewrite. The edited Go, Java, Kotlin, Swift and Flutter files were not compiled locally. Node npm test and Python pytest were not run. CI YAML was only syntax-checked, not exercised as a workflow. Historical gate totals are omitted; the author must fill the final gate below.

Verification

Gate on the final commit 1568a7cb: cargo fmt --check, cargo clippy --workspace --all-targets -D warnings, cargo doc, tests of core, provider-utils, providers, ffi, web, replay and cli: 2,832 passed, 0 failed; Node and Python bindings cargo check; provider boundary script; gen_ts_types.py --check, gen_providers_doc.py --check. Cassettes and fixtures/aisdk unchanged relative to the base. 125 files, +3884 / −22616.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS

chenhaonan and others added 8 commits October 4, 2026 22:58
aimux-core defined a source, a generated file and a reasoning segment twice
each: inline in `GenerateContent`/`StreamPart` and again as the lossy
`SourcePart`/`FilePart`/`ReasoningPart` of the text results, which dropped
`provider_metadata` (so the reasoning signature never reached the top level).
`StreamPart::ResponseMetadata` repeated the fields of `types::ResponseMetadata`.
Mirror the AI SDK: one type, reused in content, stream parts and the result
projections.

- `result::Source`, `result::GeneratedFile`, `result::ReasoningOutput` are the
  payloads of `GenerateContent::{Source,File,Reasoning}` and
  `StreamPart::{Source,File}`, and the elements of `sources`, `files` and
  `reasoning` on `GenerateTextResult` and `StreamTextResultAggregated`.
- `StreamPart::ResponseMetadata` wraps `types::ResponseMetadata`.
- Deleted `SourcePart`, `FilePart`, `ReasoningPart`.
- `ResponseMessageBuilder::reasoning` takes the `ReasoningOutput`.

Variant JSON is unchanged; the top-level `sources`/`files`/`reasoning` arrays
now carry the full element (additive `provider_metadata`, and `url`/`title`
serialize as null when absent). aimux-providers, aimux-ffi, bindings and tools
are intentionally not updated here.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
…ent types

Follow-up to the aimux-core change: providers and their tests build
`Source`, `GeneratedFile`, `ReasoningOutput` and `ResponseMetadata` payloads in
the newtype variants instead of repeating the field lists. TypeScript types are
regenerated (`SourcePart`/`FilePart`/`ReasoningPart` become `Source`,
`GeneratedFile`, `ReasoningOutput`; `StreamPart` and `GenerateContent` reference
them), the Node API doc names the new types, and the changelog records the
change as breaking.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
…fields

What: provider content and stream parts gain custom, reasoning-file and
tool-approval-request. A generated file holds data or a URL only. Input
and output token details are separate types with upstream's fields, and
raw usage is a JSON object. Request and response information carry body
and headers, and a URL file keeps its original URL. Hand-written tests
that pinned the old shapes are deleted rather than rewritten.

Why: an independent field-by-field comparison with the pinned upstream
content, stream-part, usage and result types found these differences.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
Why: carry the tool type changes up the stack. Conflicts were confined to
hand-written test files both branches had trimmed; files that the prompt
types branch deletes anyway are removed here, the rest keep this branch's
side.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
What: Source becomes upstream's union: a url source with a required url,
or a document source with required media type and title and an optional
filename. The source_type tag is kept, so url-source JSON is unchanged.
Vendors that emit sources build the matching variant. The language
bindings' types and decoders follow.

Why: upstream has exactly these two kinds; the flat type with every field
optional could express sources that cannot exist. The Go, Java, Kotlin,
Swift and Flutter changes are not compiled here.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
…leted

Why: carry the thought-signature removal and the deletion of the
self-generated contract fixtures up the stack.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
…t sources; align binding types

What: OpenAI Responses maps file_citation, container_file_citation and
file_path annotations to document sources in generate and stream; Google
grounding treats `web: null` as absent and maps retrievedContext to a
document source (Vertex shares the path); Vertex emits thought files as
reasoning-file and thought text as reasoning like Google. Java, Kotlin,
Go, Swift and Flutter type files follow the Rust shapes for response
body, reasoning-file data and the tool approval request.

Why: review of this branch against the pinned upstream found these
source variants unmapped and the binding types diverging from Rust.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
Why: carry up the stack the fixes made after the third independent
review on the branches below; this branch's code is converted to them.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant