Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
409 commits
Select commit Hold shift + click to select a range
21f1457
docs(rfc): add the RFC-0023 revision line for the V4 recording layer
claude Oct 13, 2026
73012b0
feat(core)!: speech results carry the provider's usage
claude Oct 13, 2026
907393f
refactor(core)!: decision recordings carry no capability snapshot
claude Oct 13, 2026
37255a7
Merge [6/8] into [7/8]: per-package user-agents and upstream error/he…
claude Oct 13, 2026
3386ec5
fix(open-responses): send the ai-sdk-open-responses user-agent part
claude Oct 13, 2026
96a6a4f
fix(openai): chat logprobs metadata drops bytes as upstream
claude Oct 13, 2026
4c00266
Merge [3/8] into [4/8]: core ContentPart steps, prompt and tool-choic…
claude Oct 13, 2026
ee18247
fix(vertex): a partner provider user-agent header replaces the whole one
claude Oct 13, 2026
8520201
docs: the alignment document follows ai 7.0.127 for results, jobs and…
claude Oct 13, 2026
dcaf474
fix(provider-utils): URL downloads send no user-agent, as downloadBlob
claude Oct 13, 2026
fb416f9
fix(openai): image edits download URL files through the download guard
claude Oct 13, 2026
a87b9ca
fix(google): files upload sends no provider-utils user-agent part
claude Oct 13, 2026
822def8
refactor(core)!: the retry count, timeout and session id are operatio…
claude Oct 13, 2026
e0996ce
Merge [6/8] into [8/8]: vendor alignment and the lower layers' fixes
claude Oct 13, 2026
e6f88ba
Merge [4/8] into [5/8]: AI SDK steps, stream parts and operation sett…
claude Oct 13, 2026
92e86a9
fix(core): tests and comments follow the merged retry and error sets
claude Oct 13, 2026
4b662a5
fix(providers): layer 5 provider code takes layers 2 to 4 types
claude Oct 13, 2026
9bfa1e9
chore(fixtures): the recorder pins provider-utils 5.0.55 as VERSIONS.…
claude Oct 13, 2026
bbbc72a
refactor(core)!: decisions follow DecisionModelV4
claude Oct 13, 2026
ed192ea
docs: video polling, retry comments and generated types after the merge
claude Oct 13, 2026
b647fb8
fix(core)!: bytes are base64 strings in the public JSON (#232 C33)
claude Oct 13, 2026
8f9bcca
fix(decision): decision image bytes are a base64 string (#232 C33a)
claude Oct 13, 2026
06bb478
feat(core)!: the operations take an injectable download, as the AI SD…
claude Oct 13, 2026
52bd723
fix(core)!: JSON null is kept apart from a missing value (#232 C34)
claude Oct 13, 2026
0b1908d
docs(changelog): note that JSON null is kept apart from missing (#232…
claude Oct 13, 2026
d2c82df
Merge [5/8] into [6/8]: providers are AI SDK factories
claude Oct 13, 2026
8b23a16
fix(providers): layer 6 provider code takes layer 5's types
claude Oct 13, 2026
f4c5fe0
fix(providers): the layer 6 transcription models refuse URL audio
claude Oct 13, 2026
87544a5
fix(core)!: file content parts are the AI SDK FilePart (#232 C35)
claude Oct 13, 2026
c3846ba
test(anthropic): an unparsable stream chunk is an error part
claude Oct 13, 2026
ac0d061
fix(providers): Cohere, Open Responses and xAI Responses declare thei…
claude Oct 13, 2026
19a9a3c
fix(core)!: generated files are {base64, mediaType} (#232 C46)
claude Oct 13, 2026
317ebcd
test: restore the hand-written unit tests 48a92aaf deleted that still…
claude Oct 13, 2026
d062be3
fix(codex): Codex models declare the OpenAI Responses supported URLs
claude Oct 13, 2026
3f389ba
fix(huggingface): pin @ai-sdk/huggingface 2.0.62 and declare its supp…
claude Oct 13, 2026
97c6fbc
fix(core)!: timestamps are toISOString() strings (#232 C48)
claude Oct 13, 2026
bc013ad
chore(node): export the generated Timestamp type (#232 C48)
claude Oct 13, 2026
c71fae0
Merge [6/8] into [7/8]: layer 6 with layers 2-5 (V4 types, operation …
claude Oct 13, 2026
21719b5
fix(core)!: text and reasoning stream deltas carry text (#229 B9)
claude Oct 13, 2026
e8279c4
fix: layer 7 code takes layers 2-6's types
claude Oct 13, 2026
635a3f4
test(providers): the layer 7 transcription models refuse URL audio
claude Oct 13, 2026
f94eadb
fix(core): decide runs its model call in the operation settings
claude Oct 13, 2026
3d78123
refactor(core)!: provider namespace maps keep insertion order (#229 N…
claude Oct 13, 2026
efd10d6
test(kotlin): the OpenAI decision test sends the fixture's options in…
claude Oct 13, 2026
6aa327d
docs(node): regenerate index.d.ts for applyToolCallRepair's doc
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
cfe290a
Merge [4/8] into [5/8]: binding tests follow layers 3 and 4
claude Oct 13, 2026
8bef2c9
Merge [5/8] into [6/8]: binding tests follow layers 3 and 4
claude Oct 13, 2026
1602ed8
Merge [6/8] into [7/8]: binding tests follow layers 3 and 4
claude Oct 13, 2026
5415fea
test(swift): the OpenAI decision test sends the fixture's options in …
claude Oct 13, 2026
f69a33f
fix(core)!: standalone tool calls and sources carry their type tag (#…
claude Oct 13, 2026
af252bb
fix(core)!: integral tool input numbers are written as JavaScript wri…
claude Oct 13, 2026
f42526b
docs(rfc): RFC-0035 shows the final repair wire and upstream's contro…
claude Oct 13, 2026
4b200a5
test(node,python): decision usage omits unknown totals, never null
claude Oct 13, 2026
38770b5
fix(core): keep recording schema 2 and read the recordings master writes
claude Oct 13, 2026
9d01eb5
chore(core): keep the removed key-source field name out of code
claude Oct 13, 2026
a382242
Merge [5/8] into [6/8]: recording schema 2, master recordings load
claude Oct 13, 2026
7294e13
Merge [6/8] into [7/8]: recording schema 2, master recordings load
claude Oct 13, 2026
370f077
docs(changelog): legacy vertex and bedrock keys are still read and wr…
claude Oct 13, 2026
4cb1e53
Merge [5/8] into [6/8]: CHANGELOG wording for legacy namespace keys
claude Oct 13, 2026
9fcc401
Merge [6/8] into [7/8]: CHANGELOG wording for legacy namespace keys
claude Oct 13, 2026
3bae669
docs(changelog): decision recordings carry no capability snapshot
claude Oct 13, 2026
3949042
Merge [7/8] into [8/8]: layer 7 (decisions, speech usage, layers 2-6)…
claude Oct 13, 2026
2da6fa9
fix(go)!: Error.Data keeps a null API call error data apart from none
claude Oct 13, 2026
7a9a4e7
docs: RFC-0035 names the tests that pin repair; RFC-0026 deltas carry…
claude Oct 13, 2026
c9d99c9
refactor!: text results' usage, steps, tool outputs and Output follow…
claude Oct 13, 2026
1f6d61e
docs(rfc): RFC-0036's stream example writes the public JSON
claude Oct 13, 2026
a8fb12f
Merge [7/8] into [8/8]: recording schema 2, master recordings load
claude Oct 13, 2026
6b214ac
refactor!: decisions follow the public JSON
claude Oct 13, 2026
87e652c
docs: fix two rustdoc links that fail cargo doc -D warnings
claude Oct 13, 2026
ee60e4e
Merge [6/8] into [7/8]: rustdoc link fixes
claude Oct 13, 2026
58572b3
Merge [5/8] into [6/8]: rustdoc link fixes
claude Oct 13, 2026
48083ff
docs: plain code spans for the private stream_transcription methods
claude Oct 13, 2026
6d51fe7
Merge [7/8] into [8/8]: rustdoc link fixes
claude Oct 13, 2026
e2e9ca4
Merge branch 'v4/8-public-json-equals-the-ai-sdk-json' into v4/9-rewr…
claude Oct 14, 2026
75cfef6
Merge branch 'v4/9-rewrite-json-repair-in-idiomatic-rust' into v4/10-…
claude Oct 14, 2026
2b42899
Merge branch 'v4/10-tool-call-repair-is-a-trait' into v4/11-provider-…
claude Oct 14, 2026
03b43b7
ci: speed up test builds, deduplicate caches, and use prebuilt cargo-ndk
cunninghamcard-bit Oct 14, 2026
f755c28
test(flutter): typed stream fixtures are JSON maps; the chat mock is …
claude Oct 14, 2026
9ab9dff
ci: keep uploaded artifacts unchanged and stop PR runs from evicting …
claude Oct 14, 2026
c75e37f
test(swift): the plain-text result's content part is type-tagged
claude Oct 14, 2026
c9ade5f
ci: fewer jobs per run so pull requests stop queueing for runners
claude Oct 14, 2026
e27c13c
Merge branch 'v4/8-public-json-equals-the-ai-sdk-json' into v4/9-rewr…
claude Oct 14, 2026
ba3f923
Merge branch 'v4/9-rewrite-json-repair-in-idiomatic-rust' into v4/10-…
claude Oct 14, 2026
fc67f42
Merge branch 'v4/10-tool-call-repair-is-a-trait' into v4/11-provider-…
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
8ecea4e
Merge [4/8] into [5/8]: the CI speed-up (#262)
claude Oct 14, 2026
777e358
Merge [5/8] into [6/8]: the CI speed-up (#262)
claude Oct 14, 2026
008859c
Merge [7/8] into [8/8]: the CI speed-up (#262)
claude Oct 14, 2026
f80fff2
Merge [6/8] into [7/8]: the CI speed-up (#262)
claude Oct 14, 2026
ee0b00e
Merge branch 'v4/8-public-json-equals-the-ai-sdk-json' into v4/9-rewr…
claude Oct 14, 2026
ecbfc3e
Merge branch 'v4/9-rewrite-json-repair-in-idiomatic-rust' into v4/10-…
claude Oct 14, 2026
c5c84f2
Merge branch 'v4/10-tool-call-repair-is-a-trait' into v4/11-provider-…
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
5aadb1c
Merge [4/8] into [5/8]: the CI fix (#262)
claude Oct 14, 2026
dd13b04
Merge [5/8] into [6/8]: the CI fix (#262)
claude Oct 14, 2026
ca181dd
Merge [7/8] into [8/8]: the CI fix (#262)
claude Oct 14, 2026
22db086
Merge [6/8] into [7/8]: the CI fix (#262)
claude Oct 14, 2026
540fef5
Merge branch 'v4/8-public-json-equals-the-ai-sdk-json' into v4/9-rewr…
claude Oct 14, 2026
4166bf0
Merge branch 'v4/9-rewrite-json-repair-in-idiomatic-rust' into v4/10-…
claude Oct 14, 2026
cdf678a
Merge branch 'v4/10-tool-call-repair-is-a-trait' into v4/11-provider-…
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
73626fe
Merge [4/8] into [5/8]: master (#205-#212, #248, #263), #262's CI fol…
claude Oct 16, 2026
5fa4045
test(provider-utils): the default-transport test keeps 127.0.0.1 off …
claude Oct 15, 2026
e03b5f1
docs(web): a blank key at a custom base_url goes out as an empty key
claude Oct 15, 2026
20a0ee5
test(provider-utils): pin the redirect cap and re-signing on a same-o…
claude Oct 15, 2026
b7f1b7f
docs(rfc): RFC-0040 §3.2 follows the implemented redirect rule
claude Oct 15, 2026
a2ba419
test(providers): a preset's base-URL and optional-key variables
claude Oct 15, 2026
636b4ca
Merge [5/8] into [6/8]: master (#205-#212, #248, #263), #262's CI fol…
claude Oct 16, 2026
a693548
test(mistral): model_length is a length finish
claude Oct 15, 2026
bd2d041
test(providers): non-object input of a past tool call
claude Oct 15, 2026
007ad30
fix(anthropic): toolset member calls go back as upstream sends them
claude Oct 16, 2026
ed69b7e
test(preset): the registry checks run on any input
claude Oct 16, 2026
a9a97fd
fix(anthropic): provider tool args are checked as upstream checks them
claude Oct 16, 2026
78d7b90
Merge [7/8] into [8/8]: master (#205-#212, #248, #263), #262's CI fol…
claude Oct 16, 2026
13845e1
test(provider-utils): say how the botocore SigV4 pins were made
claude Oct 15, 2026
9db6427
Merge [6/8] into [7/8]: master (#205-#212, #248, #263), #262's CI fol…
claude Oct 16, 2026
272a70b
docs(core): a tool result carries only output
claude Oct 15, 2026
e899de9
feat(anthropic): decision_model is upstream's evaluationModel
claude Oct 15, 2026
8f1eaf4
test(google): restore the thought-signature replay tests
claude Oct 15, 2026
7511ff4
test(providers): a failed decision is recorded and replays as the fai…
claude Oct 15, 2026
f275cdf
fix(core): request options reject unknown keys
claude Oct 15, 2026
7c3bb6a
docs(core): replay's question types and the video status key
claude Oct 15, 2026
d365388
fix(core): a prompt part with an unknown type names it
claude Oct 15, 2026
72e4fb9
docs(core): cite upstream for the snake_case video frame type
claude Oct 15, 2026
586235f
test(anthropic): compare usage JSON with what the AI SDK wrote
claude Oct 15, 2026
0e2ffc3
Merge branch 'v4/8-public-json-equals-the-ai-sdk-json' into v4/9-rewr…
claude Oct 16, 2026
1e60857
test(aimux-core): replace the in-test legacy json_repair port with re…
claude Oct 14, 2026
f0b17f6
docs(core): say why json_repair stays public
claude Oct 15, 2026
b1fd1b3
Merge branch 'v4/9-rewrite-json-repair-in-idiomatic-rust' into v4/10-…
claude Oct 16, 2026
0eeb671
refactor(providers): keep vendor endpoints out of shared and openai_c…
claude Oct 14, 2026
bd6c67e
test(searxng): the instance URL comes from SEARXNG_URL per request
claude Oct 15, 2026
8676f29
Merge branch 'v4/10-tool-call-repair-is-a-trait' into v4/11-provider-…
claude Oct 16, 2026
2574772
fix(core): fix_json steps through UTF-16 code units like upstream
claude Oct 16, 2026
563d65c
test(dataforseo): the login comes from DATAFORSEO_LOGIN per request
cunninghamcard-bit 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
36b91bc
Merge [4/8] into [5/8]: deferred tool results and the recording scope
claude Oct 16, 2026
46e974a
Merge [5/8] into [6/8]: deferred tool results and the recording scope
claude Oct 16, 2026
aad72e8
Merge [6/8] into [7/8]: deferred tool results and the recording scope
claude Oct 16, 2026
67c7f1d
Merge [7/8] into [8/8]: deferred tool results and the recording scope
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
85e65d8
Merge [4/8] into [5/8]: tracker ids, binding provider tools, InputRec…
claude Oct 16, 2026
2eef03b
Merge [5/8] into [6/8]: tracker ids, binding provider tools, InputRec…
claude Oct 16, 2026
31fb8fe
Merge [6/8] into [7/8]: tracker ids, binding provider tools, InputRec…
claude Oct 16, 2026
eb24c62
Merge [7/8] into [8/8]: tracker ids, binding provider tools, InputRec…
claude Oct 16, 2026
c6382f1
fix(core)!: MoA failMode and the recording operation are kebab-case
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
2c477ce
Merge [4/8] into [5/8]: gated ts-rs exports and the ProviderName removal
claude Oct 16, 2026
4ba56b0
Merge [5/8] into [6/8]: gated ts-rs exports and the ProviderName removal
claude Oct 16, 2026
e661f11
Merge [6/8] into [7/8]: gated ts-rs exports and the ProviderName removal
claude Oct 16, 2026
564cfff
Merge [7/8] into [8/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
e347e8c
feat(go): provider tools carry supportsDeferredResults
claude Oct 16, 2026
6422a37
Merge [4/8] into [5/8]: the deferred tool result rule is generate_text's
claude Oct 16, 2026
7da96b4
Merge [5/8] into [6/8]: the deferred tool result rule is generate_text's
claude Oct 16, 2026
de9e9a0
Merge [6/8] into [7/8]: the deferred tool result rule is generate_text's
claude Oct 16, 2026
095ee27
Merge [7/8] into [8/8]: 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
857b29d
Merge [4/8] into [5/8]: master's #266 docs wording
claude Oct 16, 2026
bed5ca7
Merge [5/8] into [6/8]: master's #266 docs wording
claude Oct 16, 2026
cd55182
Merge [6/8] into [7/8]: master's #266 docs wording
claude Oct 16, 2026
8eaa63d
Merge [7/8] into [8/8]: master's #266 docs wording
claude Oct 16, 2026
f390ff4
Merge branch 'v4/8-public-json-equals-the-ai-sdk-json' into v4/9-rewr…
claude Oct 16, 2026
adec25f
Merge branch 'v4/9-rewrite-json-repair-in-idiomatic-rust' into v4/10-…
claude Oct 16, 2026
5330a48
Merge branch 'v4/10-tool-call-repair-is-a-trait' into v4/11-provider-…
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
9a9056c
Merge [4/8] into [5/8]: the pin fetch test fix
claude Oct 16, 2026
f88bd61
Merge [5/8] into [6/8]: the pin fetch test fix
claude Oct 16, 2026
dc656f8
Merge [6/8] into [7/8]: the pin fetch test fix
claude Oct 16, 2026
5ee53e2
Merge [7/8] into [8/8]: the pin fetch test fix
claude Oct 16, 2026
f89c989
Merge branch 'v4/8-public-json-equals-the-ai-sdk-json' into v4/9-rewr…
claude Oct 16, 2026
27901f1
Merge branch 'v4/9-rewrite-json-repair-in-idiomatic-rust' into v4/10-…
claude Oct 16, 2026
6e2b132
Merge branch 'v4/10-tool-call-repair-is-a-trait' into v4/11-provider-…
claude Oct 16, 2026
38b6cde
docs(rfc): the retry count, timeout and session id are operation sett…
claude Oct 16, 2026
f039e50
Merge [4/8] into [5/8]: RFC text for the operation settings
claude Oct 16, 2026
7be67e6
Merge [5/8] into [6/8]: RFC text for the operation settings
claude Oct 16, 2026
593b5e5
Merge [6/8] into [7/8]: RFC text for the operation settings
claude Oct 16, 2026
9cef9bf
Merge [7/8] into [8/8]: RFC text for the operation settings
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
79c2efc
Merge [4/8] into [5/8]: #262, #246 and #247 as eric merged them
claude Oct 17, 2026
dbf852f
Merge [5/8] into [6/8]: #262, #246 and #247 as eric merged them
claude Oct 17, 2026
fa3d877
Merge [6/8] into [7/8]: #262, #246 and #247 as eric merged them
claude Oct 17, 2026
f8a4287
Merge [7/8] into [8/8]: #262, #246 and #247 as eric merged them
claude Oct 17, 2026
8c8eb61
Merge branch 'v4/8-public-json-equals-the-ai-sdk-json' into v4/9-rewr…
claude Oct 17, 2026
50a6fb7
Merge branch 'v4/9-rewrite-json-repair-in-idiomatic-rust' into v4/10-…
claude Oct 17, 2026
4e7afd8
Merge branch 'v4/10-tool-call-repair-is-a-trait' into v4/11-provider-…
claude Oct 17, 2026
151a96e
Merge master into [11/13]: converge to the layer tree
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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
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.
- `SigV4Fetch::with_clock` takes a plain function (`fn() -> DateTime<Utc>`)
instead of a closure.

**Rust (aimux-providers)**

Expand All @@ -727,6 +729,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`type` is validated when present, ids missing from the wire come from the
provider's `generate_id`, and `DeltaToolCall.index` is required again, so a
chunk without it fails to parse.
- The private per-model configs hold data where they held closures: base
URLs (`OpenAIUrl`, `MessagesUrl`, `BaseUrl`), provider headers
(`ProviderHeaders`, `EndpointHeaders`), endpoint sources (Vertex, Bedrock,
Polly) and supported-URL rules. A registry row selects its chat usage
accounting with `profile.convert_usage` (`"alibaba"`, `"moonshotai"`)
instead of a name match. Public settings, requests and errors are
unchanged; the closures callers pass in settings (`transform_request_body`,
`generate_id`, the compatible `supported_urls`, `convert_usage` and
`metadata_extractor`) are kept as given.
- `PresetDescriptor` gains a crate-private field (the row's usage converter),
so code outside the crate can no longer build one with a struct literal;
descriptors come from the registry JSON.

**Rust (provider factory, RFC-0036)**

Expand Down
13 changes: 7 additions & 6 deletions aimux-provider-utils/src/sigv4_fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
//! Reference: <https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html>

use std::fmt;
use std::sync::Arc;

use async_trait::async_trait;
use chrono::{DateTime, Utc};
Expand Down Expand Up @@ -344,7 +343,9 @@ fn hmac_sha256(key: &[u8], data: &[u8]) -> Vec<u8> {
mac.finalize().into_bytes().to_vec()
}

type Clock = Arc<dyn Fn() -> DateTime<Utc> + Send + Sync>;
/// The signing clock: a plain function, so a fixed time in tests is a named
/// function or a non-capturing closure.
type Clock = fn() -> DateTime<Utc>;

/// A [`Fetch`] decorator that signs every request with SigV4 and forwards it
/// to the wrapped transport. A request marked [`RequestCredentials::Omit`] is
Expand Down Expand Up @@ -396,15 +397,15 @@ impl SigV4Fetch {
inner,
credentials,
service: service.into(),
clock: Arc::new(Utc::now),
clock: Utc::now,
signing,
}
}

/// Replace the signing clock (deterministic signatures in tests).
#[must_use]
pub fn with_clock(mut self, clock: impl Fn() -> DateTime<Utc> + Send + Sync + 'static) -> Self {
self.clock = Arc::new(clock);
pub fn with_clock(mut self, clock: fn() -> DateTime<Utc>) -> Self {
self.clock = clock;
self
}
}
Expand Down Expand Up @@ -467,7 +468,7 @@ impl Fetch for SigV4Fetch {

#[cfg(test)]
mod tests {
use std::sync::Mutex;
use std::sync::{Arc, Mutex};

use bytes::Bytes;
use chrono::TimeZone;
Expand Down
143 changes: 104 additions & 39 deletions aimux-providers/src/anthropic/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,76 @@
use std::collections::{BTreeSet, HashMap};
use std::sync::Arc;

use futures::future::BoxFuture;
use serde_json::Value;

use crate::shared::{Credential, ProviderHeaders};
use aimux_core::AiMuxError;
use aimux_core::language_model::SupportedUrls;
use aimux_provider_utils::{
ExchangeContext, FetchFunction, HeaderMapOpt, HeadersFn, HttpRequest, ResponseHandler,
combine_headers, normalize_headers,
ExchangeContext, FetchFunction, HeaderMapOpt, HttpRequest, ResponseHandler, combine_headers,
normalize_headers,
};

use super::convert::RequestProfile;
use crate::shared::Endpoint;
pub use crate::shared::TransformRequestBody;

/// Maps an endpoint path (`"/messages"`) to the full request URL.
pub(crate) type UrlFn = Arc<dyn Fn(&str) -> String + Send + Sync>;
/// Where the messages call of a model goes.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub(crate) enum MessagesUrl {
/// `url("/messages")`: the first-party API and hosts that mirror it.
#[default]
Messages,
/// `{base_url}/{model id}:rawPredict`, or `:streamRawPredict` when
/// streaming: Anthropic on Vertex AI.
RawPredict,
}

/// `(model id, streaming)` to the full URL of the messages call, for hosts
/// that put the model and the mode in the path.
pub(crate) type RequestUrlFn = Arc<dyn Fn(&str, bool) -> String + Send + Sync>;
/// Where a model's endpoint (base URL and provider headers) comes from.
#[derive(Clone, Default)]
pub(crate) enum AnthropicEndpoint {
/// The config's own `base_url` and `headers`.
#[default]
Fixed,
/// The Vertex endpoint of Anthropic's models, resolved for every request:
/// the project, location and credentials are only known when a call is
/// made. The config's own `base_url` and `headers` then only describe the
/// model's static identity.
Vertex(Arc<crate::vertex::Resolver>),
/// Claude Platform on AWS with no explicit base URL: every request goes
/// to `https://aws-external-anthropic.{region}.api.aws/v1` for the region
/// resolved then (`getBaseURL`, anthropic-aws-provider.ts:229-231).
AwsRegional(Arc<crate::anthropic_aws::Auth>),
/// An invalid base URL setting (`ANTHROPIC_BASE_URL`): every request
/// fails with this error before it is sent.
Invalid(AiMuxError),
}

/// Rewrites the request body a host-specific way.
pub(crate) type BodyFn = Arc<dyn Fn(Value) -> Value + Send + Sync>;
/// Where the provider headers of a request come from.
#[derive(Clone)]
pub(crate) enum AnthropicHeaders {
/// Credential, fixed and user headers (the common case).
Provider(ProviderHeaders),
/// Claude Platform on AWS: `anthropic-version`, the workspace id, the
/// caller's headers and, on the API-key path, `x-api-key` last, all
/// resolved on every request.
Aws(crate::anthropic_aws::AwsHeaders),
}

impl From<ProviderHeaders> for AnthropicHeaders {
fn from(headers: ProviderHeaders) -> Self {
Self::Provider(headers)
}
}

/// Builds the configuration of one request, for hosts whose endpoint or
/// credentials (a Vertex project and location, say) can only be known when a
/// call is made.
pub(crate) type ResolveFn =
Arc<dyn Fn() -> BoxFuture<'static, Result<AnthropicModelConfig, AiMuxError>> + Send + Sync>;
impl AnthropicHeaders {
async fn resolve(&self) -> Result<HeaderMapOpt, AiMuxError> {
match self {
Self::Provider(headers) => headers.resolve().await,
Self::Aws(headers) => headers.resolve().await,
}
}
}

/// Builds the host's error handler for non-2xx responses.
pub(crate) type ErrorHandlerFn = fn() -> ResponseHandler<AiMuxError>;
Expand All @@ -49,12 +91,11 @@ pub(crate) type ErrorHandlerFn = fn() -> ResponseHandler<AiMuxError>;
/// and `supportsStrictTools` config members, plus its error shape).
#[derive(Clone)]
pub(crate) struct AnthropicModelHooks {
/// The messages URL when it depends on the model and the mode. `None`:
/// `url("/messages")`.
pub(crate) request_url: Option<RequestUrlFn>,
/// Where the messages call goes.
pub(crate) messages_url: MessagesUrl,
/// Applied to the finished request body before the provider's own
/// `transform_request_body`.
pub(crate) prepare_body: Option<BodyFn>,
pub(crate) prepare_body: Option<fn(Value) -> Value>,
/// Parses a failed response.
pub(crate) failed_response_handler: ErrorHandlerFn,
/// Structured outputs and their beta header.
Expand All @@ -67,7 +108,7 @@ impl Default for AnthropicModelHooks {
/// The first-party API.
fn default() -> Self {
Self {
request_url: None,
messages_url: MessagesUrl::Messages,
prepare_body: None,
failed_response_handler: super::anthropic_failed_response_handler,
supports_native_structured_output: true,
Expand All @@ -83,55 +124,79 @@ impl Default for AnthropicModelHooks {
pub(crate) struct AnthropicModelConfig {
/// The identity the model reports from `provider()`.
pub(crate) provider: String,
/// Endpoint path to full URL.
pub(crate) url: UrlFn,
/// Provider headers (credential, `anthropic-version`, user headers),
/// resolved on every request.
pub(crate) headers: HeadersFn,
pub(crate) headers: AnthropicHeaders,
/// Transport; `None` uses the process default, resolved per request.
pub(crate) fetch: Option<FetchFunction>,
/// URLs the model fetches itself. Empty: the caller downloads them.
pub(crate) supported_urls: SupportedUrls,
/// Provider-level request-body rewrite.
pub(crate) transform_request_body: Option<TransformRequestBody>,
/// The origin credentialed headers may be sent to. Never read for URLs.
/// The URL every endpoint path is appended to; also the origin
/// credentialed headers may be sent to.
pub(crate) base_url: String,
/// The providerOptions key read in addition to `anthropic` and written
/// on response metadata.
pub(crate) provider_options_name: String,
/// Host differences.
pub(crate) hooks: AnthropicModelHooks,
/// Late binding: when set, every request uses the configuration this
/// returns (its own `resolve` is `None`) instead of the fields above,
/// which then only describe the model's static identity.
pub(crate) resolve: Option<ResolveFn>,
/// Where `base_url` and `headers` of a request come from.
pub(crate) endpoint: AnthropicEndpoint,
}

impl AnthropicModelConfig {
/// The configuration to use for one request: itself, or what the host's
/// `resolve` builds now.
/// The configuration to use for one request: itself, or itself with the
/// endpoint the host resolves now.
///
/// # Errors
///
/// Returns the error of the host's setting or credential loading, for
/// instance `AiMuxError::LoadSetting` for an unset Vertex project.
pub(crate) async fn resolved(&self) -> Result<Self, AiMuxError> {
match &self.resolve {
Some(resolve) => resolve().await,
None => Ok(self.clone()),
match &self.endpoint {
AnthropicEndpoint::Fixed => Ok(self.clone()),
AnthropicEndpoint::Invalid(error) => Err(error.clone()),
AnthropicEndpoint::Vertex(resolver) => {
let Endpoint { base_url, headers } = resolver
.endpoint(crate::vertex::Publisher::Anthropic)
.await?;
Ok(Self {
base_url,
headers: ProviderHeaders::bearer(Credential::None, Vec::new(), Some(headers))
.into(),
endpoint: AnthropicEndpoint::Fixed,
..self.clone()
})
}
AnthropicEndpoint::AwsRegional(auth) => {
let region = auth.host_region()?;
Ok(Self {
base_url: format!("https://aws-external-anthropic.{region}.api.aws/v1"),
endpoint: AnthropicEndpoint::Fixed,
..self.clone()
})
}
}
}

/// The full URL of an endpoint path.
/// The full URL of an endpoint path: `base_url` followed by `path`.
pub(crate) fn url(&self, path: &str) -> String {
(self.url)(path)
format!("{}{path}", self.base_url)
}

/// The URL of the messages call for a model.
pub(crate) fn messages_url(&self, model_id: &str, stream: bool) -> String {
match &self.hooks.request_url {
Some(request_url) => request_url(model_id, stream),
None => self.url("/messages"),
match self.hooks.messages_url {
MessagesUrl::Messages => self.url("/messages"),
MessagesUrl::RawPredict => {
let method = if stream {
"streamRawPredict"
} else {
"rawPredict"
};
format!("{}/{model_id}:{method}", self.base_url)
}
}
}

Expand Down Expand Up @@ -218,7 +283,7 @@ impl AnthropicModelConfig {

/// Run the host's body preparation, then the provider-level rewrite.
pub(crate) fn transform_body(&self, mut body: Value) -> Value {
if let Some(prepare) = &self.hooks.prepare_body {
if let Some(prepare) = self.hooks.prepare_body {
body = prepare(body);
}
match &self.transform_request_body {
Expand Down
37 changes: 17 additions & 20 deletions aimux-providers/src/anthropic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use std::sync::{Arc, OnceLock};
use futures::future::BoxFuture;
use serde_json::Value;

use crate::shared::ProviderHeaders;
use aimux_core::decision_model::DecisionModel;
use aimux_core::embedding_model::EmbeddingModel;
use aimux_core::error::AiMuxError;
Expand All @@ -44,12 +45,12 @@ use aimux_core::language_model::{LanguageModel, SupportedUrls};
use aimux_core::model_catalogue::RuntimeModel;
use aimux_core::provider::{Provider, ProviderDiscovery};
use aimux_provider_utils::{
DecisionLanguageModel, FetchFunction, HeaderMapOpt, HeadersFn, Resolvable, validate_base_url,
DecisionLanguageModel, FetchFunction, HeaderMapOpt, Resolvable, validate_base_url,
};

use crate::shared::{AuthScheme, Credential, credential_headers};
use crate::shared::{AuthScheme, Credential};

use config::{AnthropicModelConfig, AnthropicModelHooks};
use config::{AnthropicEndpoint, AnthropicModelConfig, AnthropicModelHooks};

pub(crate) fn anthropic_failed_response_handler()
-> aimux_provider_utils::ResponseHandler<AiMuxError> {
Expand Down Expand Up @@ -201,13 +202,13 @@ pub fn create_anthropic(
Ok(AnthropicProvider {
name: settings.name.unwrap_or_else(|| DEFAULT_NAME.to_string()),
base_url,
headers: aimux_provider_utils::headers::with_user_agent_suffix_fn(
credential_headers(
credential,
scheme,
vec![("anthropic-version".to_string(), API_VERSION.to_string())],
settings.headers,
),
headers: ProviderHeaders::new(
credential,
scheme,
vec![("anthropic-version".to_string(), API_VERSION.to_string())],
settings.headers,
)
.with_user_agent(
crate::shared::aisdk_pins::ANTHROPIC.name,
crate::shared::aisdk_pins::ANTHROPIC.version,
),
Expand Down Expand Up @@ -238,7 +239,7 @@ pub struct AnthropicProvider {
/// The normalized base URL, or the error of an invalid
/// `ANTHROPIC_BASE_URL`, which every request reports.
base_url: Result<String, AiMuxError>,
headers: HeadersFn,
headers: ProviderHeaders,
fetch: Option<FetchFunction>,
supported_urls: SupportedUrls,
generate_id: Option<Arc<dyn Fn() -> String + Send + Sync>>,
Expand All @@ -248,11 +249,9 @@ impl AnthropicProvider {
/// The model configuration reporting `provider` as its identity.
fn model_config(&self, provider: String) -> AnthropicModelConfig {
let base_url = self.base_url.clone().unwrap_or_default();
let base = base_url.clone();
AnthropicModelConfig {
provider,
url: Arc::new(move |path| format!("{base}{path}")),
headers: self.headers.clone(),
headers: self.headers.clone().into(),
fetch: self.fetch.clone(),
supported_urls: self.supported_urls.clone(),
transform_request_body: None,
Expand All @@ -261,12 +260,10 @@ impl AnthropicProvider {
hooks: AnthropicModelHooks::default(),
// Every request resolves its configuration first; an invalid
// `ANTHROPIC_BASE_URL` fails it there.
resolve: self.base_url.as_ref().err().map(|error| {
let error = error.clone();
let resolve: config::ResolveFn =
Arc::new(move || Box::pin(std::future::ready(Err(error.clone()))));
resolve
}),
endpoint: match &self.base_url {
Ok(_) => AnthropicEndpoint::Fixed,
Err(error) => AnthropicEndpoint::Invalid(error.clone()),
},
}
}

Expand Down
Loading
Loading