Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
103d23a
refactor(providers): remove generated provider name types
cunninghamcard-bit Sep 29, 2026
837aaaf
docs(changelog): record removal of generated ProviderName as breaking
cunninghamcard-bit 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
cunninghamcard-bit Sep 29, 2026
2f66709
refactor(web): generate wire types with ts-rs and import core types v…
cunninghamcard-bit 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…
cunninghamcard-bit 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
cunninghamcard-bit Sep 29, 2026
ca115bc
refactor(core)!: tool types follow the AI SDK V4 tool types
claude Oct 12, 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
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
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
0046bb9
refactor(core)!: model calls carry the V4 tool choice object union
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
03b43b7
ci: speed up test builds, deduplicate caches, and use prebuilt cargo-ndk
cunninghamcard-bit 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
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
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
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
2c86792
Merge the ProviderName removal (#246) into the web wire types
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
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
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
6ca248e
test(scripts): give the pin fetch test its own user and global npmrc
claude Oct 16, 2026
7790a2b
Merge [1/8] into [2/8]: the pin fetch test fix
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
8720f04
Merge master into [2/8]: keep this layer alignment doc and VERSIONS pin
eric8810 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
91 changes: 91 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Breaking

- Tool-call and tool-result types are unified, one per protocol layer
(`aimux-core`). A provider emits `tool::RawToolCall` (`input` is the raw
argument text) in `GenerateContent::ToolCall(..)` and
`StreamPart::ToolCall(..)`, and `tool::ToolResult` in the `ToolResult`
variants; these variants are newtype variants now. `StreamPart` is generic
over the tool-call type: a provider's `do_stream` yields `StreamPart`
(= `StreamPart<RawToolCall>`), `stream_text` and everything after it yield
`TextStreamPart` (= `StreamPart<ToolCall>`, parsed input with `invalid` /
`error`). `RawToolCall` moved from `parse_tool_call` to `tool`. Wire format:
enum variants keep their JSON shape; a provider-layer `StreamPart::ToolCall`
has a string `input` and no `invalid` / `error`; a
`GenerateContent::ToolCall` with a non-string `input` no longer
deserializes; the standalone `tool::ToolResult` gains a required
`tool_name` and optional `dynamic` / `provider_metadata`.

- A repaired tool call that still fails to parse or validate is reported as
the AI SDK reports it: the original call stays invalid and carries the
replacement's own `InvalidToolInput` / `NoSuchTool` error, no longer wrapped
in `ToolCallRepair` (only a failing repair function is wrapped). This holds
for the `repair_tool_call` closure and for a host's `repaired` reply in every
binding.

- `CallOptions.tool_choice` is the V4 object union
`LanguageModelV4ToolChoice` (`{"type":"auto"}`, `{"type":"none"}`,
`{"type":"required"}`, `{"type":"tool","toolName":..}`); the user-level
`ToolChoice` (`"auto"` | `"none"` | `"required"` | `{type:"tool",toolName}`)
stays on `GenerateTextOptions`. `prepare_tool_choice` converts one into the
other as the AI SDK's `prepareToolChoice` does, and `generate_text` /
`stream_text` now send `{"type":"auto"}` when no choice is given, with or
without tools (providers still drop it when there are no tools, except
open-responses, which sends it as upstream does). Provider authors match
on `LanguageModelV4ToolChoice`. Recordings store the object form, so an
`ExactMatcher` no longer matches recordings made before this change.

- `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,
and `NamespacedKind::new` / `parse` check it when built in Rust. The JSON
is still a plain string.

- A provider-executed `tool::ToolResult` whose `result` is `null` no longer
deserializes: the V4 `result` is `NonNullable<JSONValue>`.

- Removed the generated `ProviderName` type in every binding (Rust enum, TS
const object, Go/Java/Kotlin consts, Swift enum, Dart consts, Python
`Literal`) and `scripts/gen_provider_names.py`. Provider names are plain
Expand Down Expand Up @@ -41,6 +84,54 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Removed `NdjsonStream` / `NdjsonError`: nothing in the workspace used them
and the AI SDK has no counterpart. `tokio` is now a dev-dependency only and
the unused direct `serde` dependency is dropped.
- `StreamingToolCallTracker`, `ToolCallStreamPart` and `TrackerError` are no
longer exported from `aimux-stream`; nothing in the workspace used them and
the AI SDK keeps the tracker in `@ai-sdk/provider-utils`, next to the
provider code that drives it. See `aimux-provider-utils` below.

**Rust (aimux-provider-utils)**

- Gains `StreamingToolCallTracker` (plus `StreamingToolCallDelta`,
`TypeValidation` and `TrackerError`), a port of the current
`@ai-sdk/provider-utils` tracker, exported from the crate root only: the
`streaming_tool_call_tracker` and `streaming_tool_call_argument_state`
modules are private, and the argument state is internal, as upstream
exports only the tracker from its index. The previous `aimux-stream` version was
a port of an older, index-only tracker. Deltas are correlated by wire
`id`, `index` and function name (ambiguous deltas are dropped), ids are
de-duplicated with `-N` suffixes, generated ids come from the new
`generate_id` (upstream's default `generateId`; `tool-call` only when a
generator returns a blank id), blank function names are ignored, and
`finish` orders calls by index only when every call has one. It emits
`aimux_core::StreamPart` tool-input parts directly (`ToolInputStart` /
`ToolInputDelta` / `ToolInputEnd` / `ToolCall`); there is no separate
`ToolCallStreamPart` event type. `StreamingToolCallDelta` borrows from the
provider's wire type and flattens upstream's `function` object;
`process` and `finish` append to a caller-owned `Vec<StreamPart>`, and
`finish` consumes the tracker. The upstream `extractMetadata` /
`buildToolCallProviderMetadata` hooks are replaced by
`StreamingToolCallDelta::provider_metadata`, read from the delta that
starts a call. `TrackerError` converts into
`AiMuxError::InvalidResponseData`.
- The tracker follows `@ai-sdk/provider-utils` 5.0.55 (pinned in
`fixtures/aisdk/VERSIONS.json`): a named delta with an unseen id and empty
arguments continues an incomplete matching call, but starts a new call
once that call's structured arguments are complete; a continuation without
labels goes to the only matching call whose structured arguments are not
complete. Parallel same-name calls whose ids are missing or reused are no
longer merged into the first call.

**Rust (aimux-providers)**

- The OpenAI chat-completions stream (`openai/model.rs`, which serves every
registry-backed provider) correlates `tool_calls` deltas with the tracker
instead of by `index` alone: deltas are matched by wire id, index and
function name; a continuation without an id follows its call; indices
reused across parallel calls stay distinct; ambiguous deltas are dropped;
a call whose delta carries no id gets a generated id, as upstream, instead
of an empty string; a new call without a function name ends the stream with
`InvalidResponseData` (previously it started a call with an empty name).
`DeltaToolCall.index` is now `Option<usize>`.

### Fixed

Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ to set up a development environment, run the tests, and submit changes.
aimux/
├── aimux-core/ # Core abstractions: LanguageModel / Provider / Message / StreamPart
├── aimux-providers/ # provider implementations + cassettes (counts: docs/api/providers.md)
├── aimux-stream/ # SSE parsing, streamed tool-call tracking
├── aimux-provider-utils/ # HTTP utilities: retry, backoff, error parsing, API-key loading
├── aimux-stream/ # SSE parsing
├── aimux-provider-utils/ # HTTP utilities: retry, backoff, error parsing, API-key loading, streamed tool-call tracking
├── aimux-ffi/ # C ABI (opaque handle + JSON + push callback) for non-native bindings
├── bindings/ # Node, Python, Swift, Kotlin, Flutter, Go, C — share one Rust core
├── rfc/ # Design docs (RFCs)
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ middleware, and telemetry per request).
aimux/
├── aimux-core # Core abstractions: LanguageModel / Provider / Message / StreamPart
├── aimux-providers # Provider implementations — registry-backed + typed (docs/api/providers.md)
├── aimux-stream # SSE parsing, streamed tool-call tracking
├── aimux-provider-utils # One-exchange HTTP helpers, response handlers, API-key loading
├── aimux-stream # SSE parsing
├── aimux-provider-utils # One-exchange HTTP helpers, response handlers, API-key loading, streamed tool-call tracking
├── aimux-ffi # C ABI (opaque handles + JSON results + owned aimux_error_t *) for non-native bindings
└── tools/ # aimux-cli (cache probe) · aimux-replay · aimux-web (console)
```
Expand All @@ -124,8 +124,8 @@ cargo add aimux-core aimux-providers
|-------|-------------|-----------|
| `aimux-core` | Core abstractions: `LanguageModel` / `Provider` / `Message` / `StreamPart` | [crates.io](https://crates.io/crates/aimux-core) |
| `aimux-providers` | Provider implementations — [registry-backed + typed](docs/api/providers.md) | [crates.io](https://crates.io/crates/aimux-providers) |
| `aimux-stream` | SSE parsing, streamed tool-call tracking | [crates.io](https://crates.io/crates/aimux-stream) |
| `aimux-provider-utils` | One-exchange HTTP helpers and typed response handlers | [crates.io](https://crates.io/crates/aimux-provider-utils) |
| `aimux-stream` | SSE parsing | [crates.io](https://crates.io/crates/aimux-stream) |
| `aimux-provider-utils` | One-exchange HTTP helpers, typed response handlers, streamed tool-call tracking | [crates.io](https://crates.io/crates/aimux-provider-utils) |
| `aimux-ffi` | C ABI for non-native bindings | [crates.io](https://crates.io/crates/aimux-ffi) |

**Node.js**:
Expand Down
6 changes: 0 additions & 6 deletions aimux-core/src/content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,6 @@ pub enum ContentPart {
/// need it to replay server tool calls on a later turn.
#[serde(default, skip_serializing_if = "Option::is_none")]
provider_executed: Option<bool>,
/// Provider-assigned thought signature (e.g. Google Gemini
/// `thoughtSignature`). Must be echoed back verbatim on the follow-up
/// turn when the tool result is sent.
#[serde(default, skip_serializing_if = "Option::is_none")]
thought_signature: Option<String>,
/// Provider-specific options for this part (e.g.
/// `anthropic.cacheControl`).
#[serde(default, skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -167,7 +162,6 @@ impl ContentPart {
tool_name: tool_name.into(),
input,
provider_executed: None,
thought_signature: None,
provider_options: None,
}
}
Expand Down
Loading
Loading