Skip to content

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

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

cunninghamcard-bit wants to merge 10 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.

Stack refresh (2026-10-07)

Head 271c994a follows rfc-0036/tool-types at dbcc5be7. The stack includes master at 0b365b39 and the updated #203 (3e2d9fc7), #204 (b897cb21) and #213 (7c0933b1). Updated parents were merged into their children to preserve the existing public merge history; the PR base and Draft state are unchanged.

Jev from master now uses the separated input/output token usage and object-only raw usage types.

Verification

  • Relative to the updated immediate base: 127 files changed, 3896 insertions(+), 22622 deletions(-).
  • Rust formatting and workspace Clippy passed during this layer’s refresh. Final integration at local wire-format 415e37e1 passes cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings, and the provider boundary script.
  • Full cargo test --workspace at final wire-format: 2,819 passed, 0 failed, 6 ignored, including doctests. The intermediate factory-source integration also passed 2,434 tests before the final obsolete Decision hook removal. These are integration results, not a claim that the full suite was rerun at every PR head.
  • Generated TypeScript synchronization, Node build:typed, and web production build passed at the wire-format layer.

Not verified

No GitHub check runs are attached to this Draft stack head at the time of this update. Go, Java, Kotlin, Swift and Flutter bindings were not compiled locally in this refresh; Node npm test and Python pytest were not run. Live vendor calls and unported upstream cases remain outside this validation.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS

chenhaonan and others added 10 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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
@cunninghamcard-bit

Copy link
Copy Markdown
Contributor Author

Folded into #219 while consolidating the RFC-0036 stack from twelve pull requests into four. This branch is unchanged; its commits are part of the range #219 now shows (base rfc-0036/integration).

🤖 Generated with Claude Code

@cunninghamcard-bit
cunninghamcard-bit deleted the rfc-0036/output-content-types branch October 12, 2026 07:11
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