Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
159 commits
Select commit Hold shift + click to select a range
103d23a
refactor(providers): remove generated provider name types
Sep 29, 2026
837aaaf
docs(changelog): record removal of generated ProviderName as breaking
Sep 29, 2026
9523030
fix(providers): drop the redundant #[must_use] on provider_names()
claude Oct 11, 2026
94c48ab
chore: drop stale provider_name references left after the ProviderNam…
cunninghamcard-bit Oct 1, 2026
1434ae1
docs(roadmap): Node drops the ProviderName string-literal union too
claude Oct 3, 2026
06db6c7
ci: run checks on every pull request and cancel superseded PR runs
claude Oct 12, 2026
7e9b5c2
test: delete self-generated contract fixtures and hand-written tests …
claude Oct 11, 2026
94630bf
refactor(web): consume generated core types directly
Sep 29, 2026
2f66709
refactor(web): generate wire types with ts-rs and import core types v…
Sep 29, 2026
25e678c
refactor(stream)!: remove unused StreamingToolCallTracker
claude Sep 29, 2026
22904a2
feat(stream)!: align StreamingToolCallTracker with the current AI SDK
claude Sep 29, 2026
028759b
feat(provider-utils)!: move the tool-call tracker next to its users a…
cunninghamcard-bit Oct 1, 2026
1922427
test(provider-utils): note the None/undefined mapping in the argument…
claude Oct 3, 2026
057e0bc
docs(changelog): record the tracker move to aimux-provider-utils
claude Oct 3, 2026
9f6bd17
refactor(provider-utils)!: rewrite the tool-call tracker in idiomatic…
Oct 9, 2026
7ffa66a
chore(stream): drop the tool-call tracker from the crate's dependenci…
claude Oct 11, 2026
043f88f
fix: address review findings on provider_names and wire export
Sep 29, 2026
cc5446f
refactor(core)!: messages, content, provider options and prompts foll…
claude Oct 12, 2026
25d28fb
refactor(core)!: provider results carry request and response informat…
claude Oct 12, 2026
ca115bc
refactor(core)!: tool types follow the AI SDK V4 tool types
claude Oct 12, 2026
27fc212
test(go): pass the prompt reasoning signature in provider_options
claude Oct 12, 2026
4140c69
fix(flutter): accept content in the StreamTextResultAggregated constr…
claude Oct 12, 2026
c81e221
test(flutter): drop the typed-call helper options no test passes any …
claude Oct 12, 2026
7646d84
Merge branch 'v4/3-messages-and-content-follow-the-ai-sdk' into v4/4-…
claude Oct 12, 2026
ae9ec6e
test(bindings): code 18 is NoOutputGenerated, 19 is the first unassig…
claude Oct 12, 2026
a9f7c7d
fix(swift): decode the FinishStep stream part
claude Oct 12, 2026
979f7bd
chore: remove the MIGRATION-NS.md scratch recipe
claude Oct 13, 2026
87c1b37
chore(fixtures): pin the AI SDK packages with sha512 integrity
claude Oct 13, 2026
7978920
chore(scripts): fetch the pinned AI SDK sources into target/aisdk
claude Oct 13, 2026
53b3dbe
chore(scripts): fetch all-or-nothing and keep the pinned integrity
claude Oct 13, 2026
6cc76f7
fix(provider-utils): keep parallel tool calls apart as provider-utils…
claude Oct 13, 2026
6195009
refactor(provider-utils)!: export only the tracker, keep its modules …
claude Oct 13, 2026
44e9820
test(provider-utils): differential tracker test against the pinned AI…
claude Oct 13, 2026
a3cb71b
fix(core): back-fill invalid tool input with the prototype-safe parse
claude Oct 13, 2026
3c3faa3
docs(core): say what TimeoutConfiguration mirrors
claude Oct 13, 2026
6f97d4b
docs: merge the migration into master layer by layer
claude Oct 13, 2026
ca19e38
docs: drop never-built aimux-only designs, move size gates to ROADMAP
claude Oct 13, 2026
a6c4fd5
test(core): restore the AiMuxError variant-set test
claude Oct 13, 2026
d053629
test(core): restore the RouterModel unit tests
claude Oct 13, 2026
d4caa28
fix(core)!: a repaired call that fails validation is not wrapped
claude Oct 13, 2026
90217da
test(core): tool-argument vectors checked against the AI SDK parse
claude Oct 13, 2026
606b9ee
fix(core)!: RetryError names the last error by its message
claude Oct 13, 2026
94501ec
docs(core): retry-count comments name the AI SDK default
claude Oct 13, 2026
4197573
refactor(core)!: provider namespace maps keep insertion order
claude Oct 13, 2026
c5200fd
refactor(core)!: video polling follows generateVideo's poll option
claude Oct 13, 2026
d41ffff
fix(core): ignore non-finite Retry-After values in retry_after_hint
claude Oct 13, 2026
0046bb9
refactor(core)!: model calls carry the V4 tool choice object union
claude Oct 13, 2026
ab3ad11
refactor(core)!: drop the reasoning part's top-level signature
claude Oct 13, 2026
d2c5e99
fix(core)!: a provider tool id must be namespaced
claude Oct 13, 2026
76eac2c
fix(core)!: a V4 tool result is never null
claude Oct 13, 2026
c2c7e68
docs: core tool results follow the AI SDK tool result family
claude Oct 13, 2026
77fb595
test(core): restore the MoA unit tests
claude Oct 13, 2026
e7e2291
test(core): restore the RFC-0026 OpenAI output converter tests
claude Oct 13, 2026
496ef24
Merge [1/8] into [2/8]: pinned AI SDK sources and the layer-by-layer …
claude Oct 13, 2026
f160c98
refactor(core)!: user messages are a union by role with per-role content
claude Oct 13, 2026
e34d4b4
Merge [2/8] into [3/8]: tool choice union, namespaced kinds, tracker …
claude Oct 13, 2026
067dc36
chore(node): regenerate call-option types for the retry-count comments
claude Oct 13, 2026
db927e9
feat(core)!: accept the AI SDK's deprecated tool output items (#229 C37)
claude Oct 13, 2026
d3fd820
refactor(core)!: results and streams follow the AI SDK's steps, usage…
claude Oct 13, 2026
252371b
feat(core)!: standardize the prompt and check tool results and tool c…
claude Oct 13, 2026
767e80c
refactor(core)!: text results carry the AI SDK's core ContentPart (#2…
claude Oct 13, 2026
7069574
fix(core)!: a custom content kind must be namespaced (#229 NP2-2)
claude Oct 13, 2026
45d6107
fix(bindings)!: bindings read the AI SDK-shaped results and stream parts
claude Oct 13, 2026
462af75
docs: API guides describe the step-based results and the full stream
claude Oct 13, 2026
97037c9
fix(core): stream_text drops empty text deltas without provider metadata
claude Oct 13, 2026
004f2a7
refactor(core)!: call options carry no call id or step helper (#230 C…
claude Oct 13, 2026
ed0e436
docs: scope note for part 2 and the speech and transcription tracing …
claude Oct 13, 2026
0b85e7e
fix(core): an approval request replays input_schema_input only when i…
claude Oct 13, 2026
20d7458
fix(core)!: a provider tool result without its call is an error unles…
claude Oct 13, 2026
9111473
refactor(core)!: stream tool results are the AI SDK's typed tool resu…
claude Oct 13, 2026
e01a6c6
feat(core): an invalid tool call in the stream is followed by a tool …
claude Oct 13, 2026
1a9c60a
feat(core): the stream's part set includes tool-output-denied and too…
claude Oct 13, 2026
75865e3
test(core): restore RFC-0031's stream timeout and pipeline tests (#23…
claude Oct 13, 2026
f9a31f4
test(core): acceptance tests for the stream part set, stream state an…
claude Oct 13, 2026
c4b089f
docs: RFC-0031 states where the AI SDK request pipeline differs (U2, …
claude Oct 13, 2026
4c00266
Merge [3/8] into [4/8]: core ContentPart steps, prompt and tool-choic…
claude Oct 13, 2026
8520201
docs: the alignment document follows ai 7.0.127 for results, jobs and…
claude Oct 13, 2026
822def8
refactor(core)!: the retry count, timeout and session id are operatio…
claude Oct 13, 2026
35711cb
test(node): the reasoning replay test gives its tool call a result
claude Oct 13, 2026
dcc11f8
Merge [3/8] into [4/8]: the reasoning replay test gives its tool call…
claude Oct 13, 2026
18e3e0e
test(bindings): the DeepSeek usage.raw tests read the step usage
claude Oct 13, 2026
4ce9aa0
docs(node): regenerate index.d.ts for applyToolCallRepair's doc
claude Oct 13, 2026
03b43b7
ci: speed up test builds, deduplicate caches, and use prebuilt cargo-ndk
Oct 14, 2026
9ab9dff
ci: keep uploaded artifacts unchanged and stop PR runs from evicting …
claude Oct 14, 2026
c9ade5f
ci: fewer jobs per run so pull requests stop queueing for runners
claude Oct 14, 2026
2e746cd
docs(alignment): the first-chunk timer start is a registered difference
claude Oct 14, 2026
df7a67c
Merge the CI speed-up (#262) into [1/8]
claude Oct 14, 2026
4e0bfe2
Merge [1/8] into [2/8]: the CI speed-up (#262)
claude Oct 14, 2026
0fe1a89
Merge [2/8] into [3/8]: the CI speed-up (#262)
claude Oct 14, 2026
2af8255
Merge [3/8] into [4/8]: the CI speed-up (#262)
claude Oct 14, 2026
8ab9abb
ci: restore the Flutter SDK cache everywhere, save it from master only
claude Oct 14, 2026
753b61b
ci: build test-only FFI libraries at opt-level 1, not 0
claude Oct 14, 2026
19b9e9f
Merge the CI fix (#262) into [1/8]: test libraries at opt-level 1
claude Oct 14, 2026
824f948
Merge [1/8] into [2/8]: the CI fix (#262)
claude Oct 14, 2026
515fb3d
Merge [2/8] into [3/8]: the CI fix (#262)
claude Oct 14, 2026
75e96c2
Merge [3/8] into [4/8]: the CI fix (#262)
claude Oct 14, 2026
8ccd560
Merge branch 'master' into ci/optimize-ci-speed-and-cache
claude Oct 15, 2026
ca886c1
ci: pin cargo-ndk and keep pull requests from saving two more caches
claude Oct 15, 2026
7c5ded7
Merge branch 'master' into ci/optimize-ci-speed-and-cache
claude Oct 15, 2026
3fcf1da
Merge master into the ProviderName removal: Bedrock SigV4 and secret …
claude Oct 15, 2026
ec7ab7c
chore: delete the web console's generated ProviderName copy
claude Oct 15, 2026
ea0384a
Merge master into the web wire types: tiered CI (#263), Bedrock SigV4…
claude Oct 15, 2026
1bd6a55
ci: type-check the web console against the generated types
claude Oct 15, 2026
d1005cf
Merge the CI speed-up branch (with master) into [1/8]: tiered CI (#26…
claude Oct 15, 2026
d482975
docs: size and performance gates follow RFC-0043
claude Oct 15, 2026
c1d10b5
docs: the alignment doc links back to RFC-0036 §12.2 and names the me…
claude Oct 15, 2026
b32dc0a
ci: run the AI SDK pin script tests
claude Oct 15, 2026
710fcd7
docs: note the retired contract fixtures in the RFCs and the changelog
claude Oct 15, 2026
be87f81
docs(web): note that cargo test rewrites the tracked node types
claude Oct 15, 2026
d30833d
Merge [1/8] into [2/8]: master (#205-#212, #248, #263), the RFC-0043 …
claude Oct 15, 2026
d005871
test(openai): tool calls are flushed after an error frame
claude Oct 15, 2026
f0ee302
refactor(provider-utils): bound the tracker's id suffix search
claude Oct 15, 2026
fb2f23f
Merge [2/8] into [3/8]: master (#205-#212, #248, #263), the RFC-0043 …
claude Oct 15, 2026
7a726e3
test(core): restore the OpenAI output tool-argument tests
claude Oct 15, 2026
88ce267
test(core): part metadata replays whole into providerOptions
claude Oct 15, 2026
750f9a0
test(ffi): restore the composite, frame-error and session-input tests
claude Oct 15, 2026
4b21206
fix(core): a stream that ends with Finish is traced as completed
claude Oct 15, 2026
bfd9fdd
test(core): restore the TraceLayer suite
claude Oct 15, 2026
6faea33
test(core): a traced call keeps the id of its recording
claude Oct 15, 2026
62e2967
test(google): restore the inlineData-to-file tests
claude Oct 15, 2026
9fd8905
test(core): restore the replay_with_model tests
claude Oct 15, 2026
95d9a3a
Merge [3/8] into [4/8]: master (#205-#212, #248, #263), the RFC-0043 …
claude Oct 15, 2026
a7efac0
test(core): pin an abort after a finished step and repeated tool-call…
claude Oct 15, 2026
d989330
docs(alignment): register recording_context and deferred provider res…
claude Oct 15, 2026
1aead53
refactor(stream_text): the chunk loop has no arm that cannot run
claude Oct 16, 2026
8f90ad6
feat(core): the recording context has an operation scope
claude Oct 16, 2026
13131b8
refactor(core)!: the recording context is an operation value, not a c…
claude Oct 16, 2026
2c86792
Merge the ProviderName removal (#246) into the web wire types
claude Oct 16, 2026
c749bf5
fix(core)!: a deferred tool result needs a provider tool that support…
claude Oct 16, 2026
9432c71
docs(core): the replay key and input record no longer name a recordin…
claude Oct 16, 2026
0b78344
build(core): ts-rs exports run only from the generator
claude Oct 16, 2026
e4104aa
fix(provider-utils): the tool call tracker generates ids as upstream
claude Oct 16, 2026
2f51e47
feat(bindings): typed provider tools carry supportsDeferredResults
claude Oct 16, 2026
79ea814
chore(node): regenerate InputRecord.ts for the corrected options comment
claude Oct 16, 2026
af67cb8
Merge [2/8] into [3/8]: the tracker generates ids as upstream
claude Oct 16, 2026
1e0a04d
Merge [3/8] into [4/8]: the tracker generates ids as upstream
claude Oct 16, 2026
c525525
Merge #247 into [1/8]: gated ts-rs exports and the ProviderName removal
claude Oct 16, 2026
020688d
Merge [1/8] into [2/8]: gated ts-rs exports and the ProviderName removal
claude Oct 16, 2026
21a4b2f
Merge [2/8] into [3/8]: gated ts-rs exports and the ProviderName removal
claude Oct 16, 2026
36a9e5c
Merge [3/8] into [4/8]: gated ts-rs exports and the ProviderName removal
claude Oct 16, 2026
b0dc009
docs(changelog): the deferred tool result rule is generate_text's
claude Oct 16, 2026
7a4b023
Merge master into #246: the #266 docs wording
claude Oct 16, 2026
453f611
Merge #246 into #247: master's #266 docs wording
claude Oct 16, 2026
796bd99
Merge #247 into [1/8]: master's #266 docs wording
claude Oct 16, 2026
36c8823
Merge [1/8] into [2/8]: master's #266 docs wording
claude Oct 16, 2026
59d9005
Merge [2/8] into [3/8]: master's #266 docs wording
claude Oct 16, 2026
2997346
Merge [3/8] into [4/8]: master's #266 docs wording
claude Oct 16, 2026
6ca248e
test(scripts): give the pin fetch test its own user and global npmrc
claude Oct 16, 2026
e572504
Merge [3/8] into [4/8]: the pin fetch test fix
claude Oct 16, 2026
7790a2b
Merge [1/8] into [2/8]: the pin fetch test fix
claude Oct 16, 2026
be39004
Merge [2/8] into [3/8]: the pin fetch test fix
claude Oct 16, 2026
38b6cde
docs(rfc): the retry count, timeout and session id are operation sett…
claude Oct 16, 2026
2a0b02b
Merge master into [1/8]: keep this layer ci.yml/CHANGELOG/local-ci
eric8810 Oct 17, 2026
057453e
Merge [1/8] into [2/8]: #262, #246 and #247 as eric merged them
claude Oct 17, 2026
bdeebad
Merge [2/8] into [3/8]: #262, #246 and #247 as eric merged them
claude Oct 17, 2026
6fec783
Merge [3/8] into [4/8]: #262, #246 and #247 as eric merged them
claude Oct 17, 2026
afd378f
Merge master into [4/8]: keep this layer versions
eric8810 Oct 17, 2026
8119c34
fix(bindings/node): restore this layer's generated types after the ma…
cunninghamcard-bit Oct 17, 2026
8b9224c
fix(bindings/node): drop GenerateResponse.ts, which this layer no lon…
cunninghamcard-bit Oct 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 173 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Breaking

- Provider results carry request and response information as the AI SDK does
(`aimux-core`). `GenerateResult` has `request: Option<RequestInfo>` and
`response: Option<ResponseInfo>`; `ResponseInfo` gains `id` and holds the
timestamp, model id, headers and body. `StreamResult` has `request` and
`response: Option<StreamResponseInfo>`. The flat `request_body` and
`response_headers` fields are removed and `response` is optional; the call
layer fills a missing id, timestamp and model id. The user-facing results and
their JSON are unchanged.

- The prompt a provider receives is modelled by role (`aimux-core`), as the AI
SDK's `LanguageModelV4Message`. `LanguageModelPrompt` is
`Vec<LanguageModelMessage>`: `System { content: String }`,
Expand Down Expand Up @@ -102,8 +111,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`InvalidPromptError` and `InvalidResponseDataError`.

- Text results carry the AI SDK's core `ContentPart` (`aimux-core`), eleven
kinds, instead of the provider's `GenerateContent`: `GenerateTextResult`
and `StreamTextResultAggregated` `content` is `Vec<ContentPart>`
kinds, instead of the provider's `GenerateContent`: `StepResult.content`
(and so `GenerateTextResult.content`) is `Vec<ContentPart>`
(`TextContent` is removed; Node exports `ContentPart`, Python keeps the
`TextContent` model name). New kinds: `ToolError(TypedToolError)` and
`ToolApprovalResponse(ToolApprovalResponseOutput)`. A provider tool result
Expand Down Expand Up @@ -174,11 +183,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- `CallOptions.call_id` and `CallOptions::for_step` are removed
(`aimux-core`); the V4 call options have no call id. The recording
correlation id is `recording_context.call_id`, and `HttpRequest::new` takes
it from there. Provider code that built `HttpRequest { call_id:
correlation id is the recording context's `call_id`, and `HttpRequest::new`
takes it from there. Provider code that built `HttpRequest { call_id:
options.call_id.clone(), .. }` uses `HttpRequest::new(url, headers,
options)`. The JSON is unchanged (both were internal and never serialized).

- `CallOptions.max_retries`, `CallOptions.timeout` and
`CallOptions.session_id` are removed (`aimux-core`), as in the V4 call
options. They are settings of the `generate_text` / `stream_text`
operation: `GenerateTextOptions` keeps all three, and the JSON bindings
are unchanged. The operation runs its model calls inside
`operation::OperationSettings::scope`. The router and MoA take the child
retry count from `OperationSettings::current()`, and `TraceLayer` takes
the session id from it. Code that calls `do_generate` / `do_stream` on a
router, MoA or trace layer directly wraps the call in
`OperationSettings { .. }.scope(..)`. Recordings keep the three keys in
`input.options`, and replay restores them.

- `generate_text` accepts a provider tool result without its call only for a
provider tool that sets `supportsDeferredResults: true` (new optional
`ProviderTool.supports_deferred_results`), as in the AI SDK
(`convert-language-model-content.ts:96-103`); before, any provider tool of
that name was enough. `stream_text` passes such a result on without its
input, as `streamText` does (`stream-language-model-call.ts:760-798`). The
flag is not sent to the provider.

- `CallOptions.recording_context` and `DecisionCallOptions.recording_context`
are removed (`aimux-core`): the V4 call options carry no recording context.
`generate_text`, `stream_text` and `decide` run the model call in
`recording::RecordingContext::scope`, and the stream in
`RecordingContext::scope_stream`; the router and MoA scope each child step
in a child context. `HttpRequest::new` and the trace layer read
`RecordingContext::current()`. Code that set the field on call options
wraps the call in `RecordingContext::scope(Some(context), ..)`. The JSON is
unchanged (the field was never serialized).

- `ProviderTool.id` is a `types::NamespacedKind`, the V4
`${string}.${string}` identifier: an id without a `.` (for example
`"web_search"` instead of `"openai.web_search"`) no longer deserializes,
Expand All @@ -196,6 +235,104 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[docs/api/providers.md](docs/api/providers.md); Rust also gains
`provider_names()`.

- `RetryError`'s text names the last attempt's message as the AI SDK's
`getErrorMessage` does: `Failed after 3 attempts. Last error: Too Many
Requests`, not `... Last error: API call error: HTTP 429: Too Many
Requests`. The HTTP status stays a field of the attempt error.

- Video poll settings belong to the operation, as the AI SDK's
`generateVideo` `poll` option (`aimux-core`, `aimux-providers`).
`VideoModel::poll_config()` and `VideoPollConfig` are removed; unset
`VideoCallOptions::poll` fields use the AI SDK defaults (5000 ms interval,
600000 ms timeout). `RunwaymlConfig` loses `poll_interval`, `timeout`,
`with_poll_interval` and `with_timeout` (RunwayML used 2 s / 300 s); pass
`poll` per call instead. Each status check, its retries included, now races
the time left in the poll budget and a hanging check fails with `Timeout`
"Video generation timed out after {timeoutMs}ms." as upstream.

- Call-level usage and finish reasons follow the AI SDK (`aimux-core`). The
results of `generate_text` / `stream_text` / `generate_object` and the
`TextStreamPart` finish parts report usage as `LanguageModelUsage`
(`input_tokens`, `input_token_details { no_cache_tokens,
cache_read_tokens, cache_write_tokens }`, `output_tokens`,
`output_token_details { text_tokens, reasoning_tokens }`, `total_tokens`,
`raw`) and the finish reason as the unified string (`"stop"`,
`"tool-calls"`, ...) with `raw_finish_reason` beside it. Usage is summed
over steps with `add_language_model_usage`. Provider results
(`GenerateResult`, `StreamPart`) keep `Usage` and `FinishReason`.
Recordings store the call-level usage for both the generate and the
stream path.

- `GenerateTextResult` is built from steps, as the AI SDK's
(`aimux-core`). It holds `steps: Vec<StepResult>`, the summed usage and the
parsed output; everything else is an accessor: `final_step()`, `content()`,
`text()`, `files()`, `sources()`, `tool_calls()`, `static_tool_calls()`,
`dynamic_tool_calls()`, `tool_results()` (and the static/dynamic
variants), `finish_reason()`, `raw_finish_reason()`, `usage()`,
`warnings()`, `response_messages()`, `output()`, and the deprecated
`reasoning()`, `reasoning_text()`, `total_usage()`, `request()`,
`response()`, `provider_metadata()` that the AI SDK also deprecates.
`StepResult` carries the step's call id, model, content, finish reason,
usage, performance, warnings, request, response (with its messages) and
provider metadata. The `raw` provider result is removed, and
`reasoning_text` is `None` when there is no reasoning. The JSON form is a
snapshot: it writes the derived values next to `steps`, `total_usage` and
`output`, and only those three are read back.

- Structured output is the `output` option, as the AI SDK's `Output`
(`aimux-core`). `GenerateTextOptions::response_format` is replaced by
`output: Option<Output>` (`Text`, `Object`, `Array`, `Choice`, `Json`); the
parsed and schema-checked value is `GenerateTextResult::output()`.
`generate_object` is deprecated, as upstream, and is a wrapper over
`generate_text` with `Output::Object`; its `GenerateObjectResult` has
`object`, `reasoning`, `finish_reason`, `usage`, `warnings`, `request`,
`response` (`GenerateObjectResponse`: id, timestamp, model id, headers,
body) and `provider_metadata`, and no `raw`. It no longer repairs
malformed JSON before parsing.

- `TextStreamPart` is the AI SDK's call-level stream part, its own enum and
no longer `StreamPart<ToolCall>` (`aimux-core`). The stream opens with
`Start` and `StartStep { request, warnings }` and closes with
`FinishStep { response, usage, performance, finish_reason,
raw_finish_reason, provider_metadata }` and
`Finish { finish_reason, raw_finish_reason, total_usage }`; the provider's
`StreamStart` and `ResponseMetadata` parts are not forwarded. `TextDelta`
and `ReasoningDelta` carry `text` (was `delta`). Aborting the call ends the
stream with `Abort { reason }`. `StreamTextResult::consume()` returns a
`GenerateTextResult`; `StreamTextResultAggregated` is removed.

- `stream_text` drops an empty `TextDelta` that carries no provider
metadata, as the AI SDK does (`aimux-core`); providers emit one, e.g. the
opening `"content": ""` chunk of OpenAI chat.

- `TextStreamPart` carries the AI SDK's tool parts (`aimux-core`,
stream-language-model-call.ts:760-792). `ToolResult` is a
`TypedToolResult` (`tool_call_id`, `tool_name`, `input?` from the call it
answers, `output`, `provider_executed`, `provider_metadata?`, `dynamic?`,
`preliminary?`) instead of the provider's `ToolResult`; a provider result
marked `is_error` arrives as `ToolError` (`TypedToolError`, with
`error`), and an invalid client tool call is followed by a `ToolError`
holding its error message and `dynamic: true`
(stream-language-model-call.ts:709-725). `ToolOutputDenied` and
`ToolApprovalResponse` are added to complete the AI SDK's set; aimux's
stream does not produce them yet. Unlike upstream, the provider's `preliminary` flag is kept, so
a preliminary result stays out of the step content, as on the generated
path. A consumed stream's step content records the tool results, tool
errors and approval responses as they arrive (stream-text.ts:1529-1538,
:1648-1650), so an invalid call's tool error is inline after its call
there, where `generate_text` puts it after the content, as upstream does.

- `generate_text` fails with `Tool call {id} not found.` when the model
returns a provider tool result whose call is not in the response and no
provider tool of that name was passed (`aimux-core`,
convert-language-model-content.ts:87-104). A result for a passed provider
tool is kept as a deferred result. The stream passes such results through,
without `input`, as upstream does.

- The response messages write a tool approval request's
`input_schema_input` only when it differs from the call's input under the
AI SDK's `isDeepEqualData` (`aimux-core`, to-response-messages.ts:133-146).

**Rust (aimux-stream)**

- `SseStream` is now a thin adapter over the `sse-stream` crate (WHATWG
Expand Down Expand Up @@ -269,6 +406,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`InvalidResponseData` (previously it started a call with an empty name).
`DeltaToolCall.index` is now `Option<usize>`.

**All bindings**

- Typed provider tools in Java, Kotlin, Swift, Python and Flutter carry
optional `supportsDeferredResults`, omitted from JSON when absent
(provider-utils@5.0.55 src/types/tool.ts:316-326).

- The typed results and stream parts follow the core's AI SDK shapes
(Go, Java, Kotlin, Swift, Flutter, Node, Python). `GenerateTextResult`
gains `steps`, `tool_results` and `output` and loses `raw`; its `content`
holds the final step's parsed parts; `usage` / `total_usage` are
`LanguageModelUsage` and `finish_reason` the unified string.
`GenerateObjectResult` loses `raw` and `raw_finish_reason`.
`consume_stream_text` returns a `GenerateTextResult`
(`StreamTextResultAggregated` is removed). The options' `response_format`
is replaced by `output`. Stream parts: `TextDelta` / `ReasoningDelta` carry
`text`; `StreamStart` and `ResponseMetadata` give way to `Start`,
`StartStep`, `FinishStep`, `Finish { finish_reason, raw_finish_reason,
total_usage }` and `Abort`; `ToolResult` carries `output` and the call's
`input` (was `result`, `is_error`), and `ToolError`, `ToolOutputDenied` and
`ToolApprovalResponse` are decoded. Tool-call
repair reads the top-level `tool_calls` only.

### Fixed

- Gated aimux-core's ts-rs exports behind `ts-export`, so plain `cargo test`
Expand Down Expand Up @@ -300,6 +459,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
fixes for released versions ship from a maintenance branch. `ROADMAP.md`
defers the ops protocol schema and L0 passthrough and no longer fixes C1
at nine exports.
- `docs/aisdk-architecture-alignment.md` and RFC-0031
(`docs/ai-sdk-request-pipeline.md`), against ai 7.0.127: object generation
is the deprecated wrapper over `output` (no separate object spans), async
jobs follow `generateVideo`'s start/status retries and poll budget, the
result convenience fields are marked deprecated as upstream marks them,
the response-message rules gain the empty-reasoning, invalid-input,
`inputSchemaInput`, tool-message order and tool-error encoding rows, and
the remaining differences are listed: stream retries, the first-chunk
timeout's start, `additionalRetryableError` and per-batch idempotency
keys.

## [0.5.0] - 2026-09-27

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ let result = stream_text(
let mut stream = result.stream;
while let Some(part) = stream.next().await {
match part? {
StreamPart::TextDelta { delta, .. } => print!("{}", delta),
StreamPart::Finish { .. } => println!("\n[done]"),
TextStreamPart::TextDelta { text, .. } => print!("{}", text),
TextStreamPart::Finish { .. } => println!("\n[done]"),
_ => {}
}
}
Expand Down
32 changes: 18 additions & 14 deletions aimux-core/src/composite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
//!
//! This module holds the pieces both share:
//! - [`ChildModel`] — the child-handle shape (`Arc<dyn LanguageModel>`).
//! - `step_options` — the call options of one child step.
//! - `step_context` — the recording context of one child step.
//! - `child_max_retries` — the operation's retry count for a child call.
//! - [`add_usage`] — per-field `Usage` accumulation.
//! - [`extract_text`] — pull text out of a `GenerateContent` list.
//! - [`build_aggregator_prompt`] — assemble the MoA aggregator prompt.
Expand All @@ -21,7 +22,8 @@ use std::sync::Arc;

use crate::language_model::LanguageModel;
use crate::language_model_message::{LanguageModelMessage, LanguageModelPrompt};
use crate::options::CallOptions;
use crate::operation::OperationSettings;
use crate::recording::RecordingContext;
use crate::result::GenerateContent;
use crate::types::{InputTokenUsage, OutputTokenUsage, Usage};

Expand All @@ -30,18 +32,20 @@ use crate::types::{InputTokenUsage, OutputTokenUsage, Usage};
/// dropped (shared by registry + composite).
pub type ChildModel = Arc<dyn LanguageModel>;

/// Clone `options` for one composite child step (Router child, MoA
/// reference or aggregator): the recording context, when present, is
/// replaced by a child context labeled `step`, so the child's exchanges and
/// retry attempts are recorded as their own step instead of blending into the
/// parent operation's.
pub(crate) fn step_options(options: &CallOptions, step: impl Into<String>) -> CallOptions {
let mut child = options.clone();
child.recording_context = options
.recording_context
.as_ref()
.map(|context| context.child(step.into()));
child
/// The recording context of one composite child step (Router child, MoA
/// reference or aggregator): a child of the current context labeled `step`,
/// so the child's exchanges and retry attempts are recorded as their own step
/// instead of blending into the parent operation's. The child call runs in
/// [`RecordingContext::scope`] of it. `None` when nothing is recorded.
pub(crate) fn step_context(step: impl Into<String>) -> Option<RecordingContext> {
RecordingContext::current().map(|context| context.child(step))
}

/// The retry count of a child call: the `max_retries` of the operation the
/// composite runs in ([`OperationSettings::current`]). `None` outside an
/// operation, or when the operation sets none, leaves the child's default.
pub(crate) fn child_max_retries() -> Option<u32> {
OperationSettings::current().and_then(|settings| settings.max_retries)
}

/// Add two `Usage` values field-by-field. `Usage::raw` (provider-opaque) is
Expand Down
Loading
Loading