Skip to content

[4/8] refactor!: results and streams follow the AI SDK - #252

Merged
eric8810 merged 159 commits into
masterfrom
v4/4-results-and-streams-follow-the-ai-sdk
Oct 17, 2026
Merged

eric8810 merged 159 commits into
masterfrom
v4/4-results-and-streams-follow-the-ai-sdk

Conversation

@cunninghamcard-bit

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

Copy link
Copy Markdown
Contributor

Requested by li

Summary

Before: provider results do not carry request and response information, response metadata arrives as its own stream part, and applying a tool-call repair to a result leaves the result's content unchanged. Text results use aimux's own shapes: a nested usage, a finish-reason struct, raw, a separate StreamTextResultAggregated and generate_object, and no steps. The stream has aimux's own part set, with delta on text deltas. Response messages come from a builder that leaves out upstream rules, for example inputSchemaInput on approval requests. The retry count, timeout and session id ride on CallOptions, so every model sees them. Each video model sets its own polling, and a hanging status check is not bounded by the poll timeout. A non-finite Retry-After gives a hint of i64::MAX ms, and the RFC-0031 stream timeout tests are gone.

After: provider generate and stream results carry request and response as the upstream V4 result types do, and raw is the provider result itself. Response metadata is absorbed into the finish step. Text results follow ai 7.0.127: steps, finalStep, totalUsage and output, with a flat LanguageModelUsage and a string finish reason; text, tool calls, usage and the rest are derived from the steps. Object generation goes through output, and generate_object is a deprecated wrapper over it. The stream has upstream's 26 part types (framing, typed tool results and tool errors, tool-output-denied, tool-approval-response, ...), text and reasoning deltas carry text, and an invalid tool call is followed by a tool error. Response messages come from an accumulator plus to_response_messages with upstream's rules, and a tool-call repair also updates the result's content. A provider tool result without its call is an error. The retry count, timeout and session id are operation settings, scoped around the model call. Video polling follows generateVideo's poll option. Retry errors read as upstream's, a non-finite Retry-After gives no hint, and the stream timeout and pipeline tests are back.

This PR takes the largest block of new work in the series.

Type of change

  • Bug fix (non-breaking)
  • New feature (non-breaking)
  • Breaking change
  • New provider
  • New / updated binding
  • Docs / RFC

Checklist

  • cargo fmt --all -- --check passes
  • cargo clippy --workspace --all-targets -- -D warnings passes
  • cargo test --workspace passes (cassette playback — no network/keys)
  • Added or updated cassette tests / contract fixtures for behavior changes
  • Updated relevant docs (README.md, docs/, rfc/, bindings/README.md)
  • Commit messages follow Conventional Commits

Notes for reviewers

CI artifact (zip) master a8e3a99 [3/8] 35711cb this PR 4ce9aa0 change vs [3/8] change vs master
ffi-x86_64-unknown-linux-gnu 3.77 MB 4.01 MB 4.06 MB +41.8 KiB (+1.07%) +284.8 KiB (+7.74%)
ffi-aarch64-apple-darwin 3.12 MB 3.31 MB 3.35 MB +36.0 KiB (+1.11%) +226.5 KiB (+7.44%)
ffi-x86_64-pc-windows-msvc 3.03 MB 3.21 MB 3.25 MB +36.9 KiB (+1.18%) +217.9 KiB (+7.37%)
node-x86_64-unknown-linux-gnu 55.30 MB 57.58 MB 58.07 MB +477.9 KiB (+0.85%) +2710.2 KiB (+5.02%)
node-aarch64-unknown-linux-gnu 53.25 MB 55.42 MB 55.88 MB +448.1 KiB (+0.83%) +2569.5 KiB (+4.94%)
node-aarch64-apple-darwin 15.06 MB 15.91 MB 16.09 MB +180.3 KiB (+1.16%) +1004.0 KiB (+6.83%)
node-x86_64-apple-darwin 13.60 MB 14.36 MB 14.52 MB +158.4 KiB (+1.13%) +901.9 KiB (+6.79%)
node-x86_64-pc-windows-msvc 10.57 MB 11.21 MB 11.34 MB +128.9 KiB (+1.18%) +752.6 KiB (+7.29%)
node-aarch64-pc-windows-msvc 9.87 MB 10.48 MB 10.61 MB +122.1 KiB (+1.19%) +714.7 KiB (+7.41%)

chenhaonan and others added 22 commits October 11, 2026 16:30
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
(cherry picked from commit 758d0bc)
The returned impl Iterator is already must_use, so clippy's
double_must_use rejected it.

(provider.rs part of commit 8397424)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
…e removal

- scripts/gen_providers_doc.py: the `provider_name` module no longer exists;
  the docstrings and the section-header guard now name only `provider`.
  `--check` output is unchanged.
- docs/internal/phase4-audit.md: add a follow-up note (same style as
  RFC-0020) so the historical audit no longer reads as if the generated
  ProviderName types and their drift tests still exist.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
(cherry picked from commit dfcd54f)
The A2 line said Node would keep a generated string-literal union for
completion. It does not: overlay-registered provider names can never be
part of a compile-time union, so keeping one would keep the second name
path this PR removes. Record the actual A2 scope.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
(cherry picked from commit 3e2d9fc)
Pull requests into a branch other than master got no CI, so a stacked PR
could not show it was green against the PR below it. The pull_request
trigger now has no branch filter. A new push to a PR cancels that PR's
run still in progress; pushes to master are never cancelled.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
…that pin Rust-only behaviour

The V4 migration that follows replaces these tests with tests ported from
the AI SDK. They are deleted first, on their own, so the PRs after this one
show only code changes. This commit removes only test files (Rust, the seven
bindings, the shared contract fixtures and their Node runner) and the CI
steps that ran the contract fixtures. No library code changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
…ia alias

- Wire*.ts were hand-maintained mirrors of wire.rs and had already drifted
  (WireContentPart lacked provider_executed). Derive TS on the wire structs
  and export them to web/src/types/generated/ through gen_ts_types.py, which
  now handles two targets and checks both in CI.
- Core types resolve through the @aimux/types tsconfig alias instead of
  five-level relative paths into bindings/node.
- gen_ts_types.py sync no longer rewrites files that differ only by ts-rs
  end-of-line spaces.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
(cherry picked from commit 69c1351)
No crate in the workspace referenced the tracker; providers accumulate
streamed tool-call deltas themselves. Drops the module, its 787-line test
file and the re-exported companion types. Breaking for aimux-stream's
public Rust API; noted in CHANGELOG under Unreleased.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015EYDYDWYcPsDmjBjFeuDVe
(cherry picked from commit fe8758f)
Re-adds the tracker as a port of the current
@ai-sdk/provider-utils streaming-tool-call-tracker.ts instead of the
older index-only version removed in the previous commit.

- Correlate deltas by wire id, index and function name; drop ambiguous ones
- Unique tool-call ids with bounded suffixes; blank generator output falls
  back to "tool-call"
- Ignore unmatched blank function names; retain blank-name continuations
- Flush in index order only when every call has an index
- New StreamingToolCallArgumentState / starts_with_structured_value port
- process_delta and flush return the emitted parts instead of buffering

Tests are ported case for case from the upstream suites (45 tracker cases,
9 argument-state cases). No caller in the workspace uses the tracker yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015EYDYDWYcPsDmjBjFeuDVe
(cherry picked from commit 6035201)
…nd wire the OpenAI stream to it

The AI SDK keeps StreamingToolCallTracker in @ai-sdk/provider-utils, where
every provider that speaks the OpenAI chat-completions wire format imports
it. aimux had the tracker in aimux-stream (the eventsource-parser role),
with its own ToolCallStreamPart event type and no callers, while
openai/model.rs kept an index-only accumulator. This commit puts the
pieces where the AI SDK has them.

aimux-stream
- StreamingToolCallTracker, StreamingToolCallArgumentState,
  starts_with_structured_value and ToolCallStreamPart move out; the crate
  is SSE decoding only. serde_json becomes a dev-dependency (test
  fixture); the `tool-calls` keyword is dropped.

aimux-provider-utils
- streaming_tool_call_tracker.rs / streaming_tool_call_argument_state.rs
  land here, logic unchanged. The tracker emits aimux_core::StreamPart
  ToolInputStart / ToolInputDelta / ToolInputEnd / ToolCall directly, so
  there is no second event type (RFC-0036: ToolCallStreamPart must not be a
  second public protocol). The generic metadata parameter becomes
  serde_json::Value / ProviderMetadata; TrackerError converts into
  AiMuxError::InvalidResponseData. The ported upstream tests (45 + 9)
  move with it, projecting StreamPart back to the upstream event shape.

aimux-providers
- openai/model.rs replaces its HashMap<usize, ToolCallAccumulator> with the
  tracker: tool_calls deltas are correlated by wire id, index and function
  name instead of index alone; id-less continuations follow their call;
  indices reused across parallel calls stay distinct; ambiguous deltas are
  dropped; a call without a wire id gets a generated `tool-call` /
  `tool-call-N` id instead of an empty string; a new call without a
  function name ends the stream with InvalidResponseData (AI SDK
  behaviour) instead of starting a call with an empty name.
- DeltaToolCall.index is Option<usize> (the AI SDK schema is
  `index: z.number().nullish()`).

Every registry-backed provider goes through openai/model.rs, so this is
the one plug point until S4-2 folds the mistral and xai chat copies into
the same implementation.

Verification: cargo test -p aimux-stream -p aimux-provider-utils; cargo test
-p aimux-providers (129 suites, 3041 passed, 0 failed, including the
cassette replays); cargo clippy -p aimux-stream -p aimux-provider-utils
-p aimux-providers --all-targets -- -D warnings; cargo fmt --all -- --check.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
(cherry picked from commit df4d09f)
…-state port

Carried over from the SSE test port commit so the two split branches
leave the file identical.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
(cherry picked from commit 7bc200e)
Describes only the final API: the tracker lives in aimux-provider-utils
and emits StreamPart directly; the intermediate ToolCallStreamPart-
returning API from earlier commits is not mentioned.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGwanvo9WLU9HWD7sRR8TS
(cherry picked from commit 264ade3)
… Rust

Same behaviour as the upstream port (checked differentially against the
previous implementation on ~1.1M random deltas), with Rust structure:

- Correlate by linear scan over per-call wire ids and indices instead of
  id/index hash maps re-sorted on every delta; no per-delta allocations
  besides the emitted parts.
- `finish(self)` consumes the tracker, so the never-true-before-flush
  `has_finished` state is gone and post-flush use cannot compile.
- `StreamingToolCallDelta<'a>` borrows from the provider wire type and
  carries `provider_metadata`, replacing `StreamingToolCallFunction`, the
  untyped `extra` bag, the test-only builders and the two boxed metadata
  hooks.
- `process` / `finish` append to a caller-owned buffer.
- Drop the unreachable `TrackerError::IdExhausted`.
- The argument state scans bytes and models completion as its own state.

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a11e83-bf7b-75bb-900b-34851e6f12ee
(cherry picked from commit b0fd923)
…es and docs

With the tracker in aimux-provider-utils, aimux-stream only decodes SSE:
serde_json is needed by its tests alone, and the tool-calls keyword no
longer applies.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
- Drop the redundant #[must_use] on provider_names(); the returned
  impl Iterator is already must_use, so clippy::double_must_use failed CI.
- Gate the wire types' ts-rs export tests behind a ts-export feature that
  only gen_ts_types.py enables. A plain cargo test previously wrote
  Wire*.ts into bindings/node/src/types via the workspace-wide
  TS_RS_EXPORT_DIR, which made gen_ts_types.py --check fail on stale files.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
(cherry picked from commit 8397424)
…ow the AI SDK V4 types

- Content: one source, file and reasoning type per layer. A source is a
  url source or a document source; file citations and grounding documents
  map to document sources. The missing upstream content variants and usage
  fields are added.
- Provider options and provider metadata have one typed shape. Vendor
  packages build and read them; a provider option that is not an object is
  an error, unknown keys no longer leak, and option parse errors surface for
  Cohere, Google and Mistral. Bedrock reads amazonBedrock before bedrock.
- The provider prompt is modelled by role with one file part. Part tags use
  upstream's hyphenated names; references, files and tool output convert as
  upstream does, and file parts keep upstream's media-type and text-data
  rules.
- The #226 decision adapters and Jev follow the typed options, metadata and
  split usage types.
- Hand-written tests that built provider prompts by hand or pinned
  Rust-only behaviour are deleted; ported upstream tests are restored.
  FFI, bindings and their generated types follow.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
…ion as upstream does

- Provider generate and stream results carry request and response
  information, as the upstream V4 result types do; raw is the provider
  result itself.
- The response metadata stream part is absorbed into the finish step, and
  request and response are carried onto the call-layer results.
- A tool-call repair applied to a result also updates the result's content.

CHANGELOG records the result fields as breaking; the migration notes
describe tool-call metadata on StreamingToolCallDelta.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
One tool struct per layer, field for field with the pinned upstream types:
- CallOptions.tool_choice is optional. Vendors omit an unset choice, as
  their upstream packages do; generate_text and stream_text default it to
  auto when tools are given, as upstream prepare-tool-choice does.
- FunctionTool.input_examples is a list of { input: object } and
  ProviderTool.args is a JSON object.
- Tool calls carry no separate thought signature. The value travels in
  provider metadata on output and provider options on input, under the
  vendor namespace, where each upstream vendor package reads and writes it.
- Call sites pass the tool structs instead of their field lists.

The fifteen tool-choice tests ported from upstream (OpenAI, Groq, Mistral,
Bedrock) are kept and adapted; hand-written tests that pinned the old
shapes are deleted. CHANGELOG and docs/api/gaps.md record the wire-format
changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Since messages follow the AI SDK V4 types, a reasoning part keeps its
signature in provider_options.anthropic.signature, as the Node test already
does. The Go round-trip test still sent the removed top-level `signature`, so
no thinking block reached the wire.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
…uctor

The content field was added to StreamTextResultAggregated and to its generated
fromJson, but not to the constructor, so lib/types.g.dart did not compile and
every test file importing the types failed to load.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
…more

Deleting the hand-written typed GenerateTextResult test left
_TypedArgs.maxOutputTokens and .temperature without a caller, which flutter
analyze reports as unused_element_parameter warnings and fails the job.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
…ned code

The results layer adds AIMUX_E_NO_OUTPUT_GENERATED = 18 (the AI SDK's
NoOutputGeneratedError) and every binding maps it, but the Go, Java, Kotlin
and Flutter tests still used 18 as the first value outside the enum. They now
check that 18 resolves to NoOutputGenerated and that 19 is rejected.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
stream_text now emits a FinishStep part (finish reason, usage, provider
metadata and the step's response metadata) before Finish, as the AI SDK's
finish-step part. The Swift StreamPart decoder threw "unknown stream-part tag
FinishStep", which failed every typed stream. It is a first-class case now,
as in the Python wrapper.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
@cunninghamcard-bit cunninghamcard-bit changed the title [V4 4/8] refactor!: results and streams follow the AI SDK refactor!: results and streams follow the AI SDK Oct 12, 2026
@cunninghamcard-bit cunninghamcard-bit changed the title refactor!: results and streams follow the AI SDK [4/8] refactor!: results and streams follow the AI SDK Oct 12, 2026
The file is a working note for the provider options / metadata namespace
migration and says on line 3 that it must not be committed. Nothing in
the tree links to it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
claude added 14 commits October 16, 2026 08:31
The InputRecord.options comment no longer names a recording_context field
(docs(core) commit before); the generated Node type carries the same text.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in the tool call tracker's default generate_id. No conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in the tool call tracker's default generate_id. No conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Stacks the series on #247 (which carries #246): aimux-core's ts-rs exports
run only under the ts-export feature that scripts/gen_ts_types.py enables,
and the generated ProviderName types are gone. Each later layer gates the
exports it adds in its own merge, so no layer leaves an ungated export.

Resolution: scripts/local-ci.sh keeps this layer's version without the
retired contract section; CHANGELOG keeps both sides, the ts-rs entry as
a Fixed section before Removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in #247 (with #246) through the layer below: ts-rs exports run
only under the ts-export feature, and the generated ProviderName types
are gone.

Resolution: the aimux-core files keep this layer's code, and every
export in them, including the ones this layer adds (ToolChoice, the
tool and stream-part types), is gated as #[cfg_attr(feature =
"ts-export", ts(export))]; CHANGELOG keeps both sides.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in #247 (with #246) through the layer below: ts-rs exports run
only under the ts-export feature, and the generated ProviderName types
are gone.

Resolution: the aimux-core files keep this layer's code, and every
export in them, including the ones this layer adds to the message,
content, result and stream types, is gated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in #247 (with #246) through the layer below: ts-rs exports run
only under the ts-export feature, and the generated ProviderName types
are gone.

Resolution: the aimux-core files keep this layer's code with every
export gated, including the result, step and output types this layer
adds. The web console's copies of the core types, which this layer had
updated, stay deleted as #247 deletes them; engine.ts and client.ts
import TextStreamPart and the other core types from @aimux/types and
the wire types from @/types/generated, and the web typecheck passes.
docs/api/reference.md keeps this layer's rows without the ProviderName
row; CHANGELOG keeps both sides.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
The entry for supportsDeferredResults read as if every tool result without
its call were checked. Only generate_text checks it, as upstream's
generateText does (ai@7.0.127 convert-language-model-content.ts:96-103);
stream_text, like streamText, passes the result on without its input
(stream-language-model-call.ts:760-798), which
stream_tool_results_and_errors_follow_the_ai_sdk already pins.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in #266 (a blank key on a custom base URL is sent as an empty
key, as the AI SDK does for apiKey: '').

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in #266 (a blank key on a custom base URL is sent as an empty
key, as the AI SDK does for apiKey: '').

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in #266 (a blank key on a custom base URL is sent as an empty
key, as the AI SDK does for apiKey: '').

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in #266 (a blank key on a custom base URL is sent as an empty
key, as the AI SDK does for apiKey: '').

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in #266 (a blank key on a custom base URL is sent as an empty
key, as the AI SDK does for apiKey: '').

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in #266 (a blank key on a custom base URL is sent as an empty
key, as the AI SDK does for apiKey: '').

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa

Copy link
Copy Markdown
Contributor Author
eric 的意见 我们的处理 位置
流式循环里两处 unreachable! 依赖分支顺序 改成结构性写法:split_payload() 先拆出带泛型载荷的分片,其余分片的载荷类型是 Infallible,兜底分支不再需要。以后再加带载荷的变体,编译期就会报错(1aead537) aimux-core/src/stream_part.rs:394
consume() 里,abort 落在 FinishStep 之后、Finish 之前会返回 Ok 核对后 Ok 是对的:上游 stream-text.ts 的 flush 只在一个 step 都没记录时才 reject。加了注释和测试 an_abort_after_a_finished_step_keeps_the_step(a7efac02) aimux-core/src/generate/tests.rs:1326
CallOptions 里还留着 recording_context 和 include_raw_chunks recording_context 已从 CallOptions 和 DecisionCallOptions 删掉,录制上下文改成操作级的 task-local 作用域:RecordingContext::scope 和 scope_stream,provider-utils 的 HTTP 交换和 trace 层用 RecordingContext::current() 取 call_id;原来设字段的调用方改成把调用包进作用域,CHANGELOG 的 Breaking 写了(8f90ad69、13131b84、9432c710)。include_raw_chunks 就是上游的 includeRawChunks,保留 aimux-core/src/recording.rs:548-561
疑问:deferred provider tool result 的放行条件比上游宽 按上游补齐。ProviderTool 加了可选的 supports_deferred_results(JSON 键 supportsDeferredResults,不发给厂商)。generate_text 里,没有对应调用的 provider 工具结果只有在同名 provider 工具标记为 true 时才放行,和上游 generateText 一样(convert-language-model-content.ts:96-103);stream_text 和上游 streamText 一样不查这一条,结果照样往下传、不带 input(stream-language-model-call.ts:760-798),已有测试锁定。各绑定的 provider 工具类型都带上这个字段(c749bf5e、2f51e47f;Go 绑定到 [8/8] 才有 provider 工具,在那里补上,e347e8c3)。[6/8] 的 openai::tools::programmatic_tool_calling() 设为 true,和上游一样 aimux-core/src/tool.rs:101、aimux-core/src/generate.rs:1218、aimux-core/src/generate/tests.rs:816;[8/8] bindings/go/types.go:543
疑问:流里出现两个相同 id 的工具调用时行为未定义 和上游一样:流式取后一个,非流式取第一个。加了两条测试锁定(a7efac02) aimux-core/src/generate/tests.rs:1358

Generated by Claude Code

claude and others added 9 commits October 16, 2026 11:18
The fetch test pointed npm's user and global config at the same empty
file. npm refuses that ("double-loading config ... as global, previously
loaded as user") and exits before any request, so on CI every test that
downloads failed with "npm pack failed". It passed in the cloud only
because the environment's NPM_CONFIG_USERCONFIG overrode the test's own
setting.

The test now writes two files, and drops inherited npm_config_* variables
in any case before setting its own, so it runs the same everywhere.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in 6ca248e: the fetch test gives npm separate user and global config files, so the AI SDK pin scripts step in the generator drift job passes on CI.

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in 6ca248e: the fetch test gives npm separate user and global config files, so the AI SDK pin scripts step in the generator drift job passes on CI.

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in 6ca248e: the fetch test gives npm separate user and global config files, so the AI SDK pin scripts step in the generator drift job passes on CI.

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
…ings

#252 took max_retries, timeout and session_id off CallOptions and made
them operation settings, but RFC-0015, RFC-0016, RFC-0017, RFC-0023,
RFC-0024, RFC-0029 and RFC-0041 still named them as CallOptions fields.

Each of those RFCs gets a later-change line in its header: the three are
set on GenerateTextOptions, generate_text and stream_text put them in
OperationSettings, and code below the model interface reads them with
OperationSettings::current(), as the AI SDK keeps maxRetries and timeout
on generateText and not in LanguageModelV4CallOptions; recordings still
write them under the old keys. The passages that describe the current
shape are rewritten (RFC-0015 §5 and §8, RFC-0017 §2.4, the RFC-0023 §1
table, RFC-0024 §1.2 and §3.1, RFC-0029 §5.4, the RFC-0041 §10.2 row);
dated implementation records keep the field where it was then.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
master 带入 #262/#246/#247 的 squash;三个冲突文件取本分支版本
(ci.yml 为已调和 #262 任务表 + web-typecheck + pin 脚本测试的超集),
gen_ts_types.py 自动合并。
Brings in master at ec338c9 (#262, #246 and #247, each squashed into one
commit) through [1/8], whose master merge eric made (2a0b02b). The tree
is unchanged: this branch already had all three.

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in master at ec338c9 (#262, #246 and #247, each squashed into one
commit) through [2/8]. The tree is unchanged: this branch already had
all three.

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
Brings in master at ec338c9 (#262, #246 and #247, each squashed into one
commit) through [3/8]. The tree is unchanged: this branch already had
all three.

Resolution: no conflicts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
@eric8810 eric8810 mentioned this pull request Oct 17, 2026
7 of 12 tasks
@eric8810
eric8810 changed the base branch from v4/3-messages-and-content-follow-the-ai-sdk to master October 17, 2026 13:27
eric8810 and others added 3 commits October 17, 2026 21:29
master 带入 #249/#250/#251 的 squash;82 个冲突取本分支版本,
其中 3 个 node 类型文件按本层意图删除(Role/StreamResponse/
StreamTextResultAggregated 为 delete/modify 冲突,git rm)。
…ster merge

The master merge (afd378f) left a conflict block in StepModel.ts and
master's trailing spaces in OutcomeRecord.ts, so the Generator drift check
failed. Both files are back to what scripts/gen_ts_types.py generates on
this layer; the next commit removes GenerateResponse.ts, which this layer
no longer generates. The tree then equals the layer before the merge.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
…ger generates

The master merge (afd378f) brought it back from master; on this layer
the type is gone, and the Generator drift check reports it as stale.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3WxDBWBA4ituJjXsHaEAa
@eric8810
eric8810 merged commit 472497c into master Oct 17, 2026
20 checks passed
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.

3 participants