Repository navigation
fix: Hugging Face stream errors end with an error finish - #307
Merged
eric8810 merged 9 commits intoOct 25, 2026
Merged
Conversation
…ce@2.0.62 doGenerate pushes mcp_call and mcp_list_tools as provider-executed tool-calls and tool-results without a dynamic flag (huggingface-responses-language-model.ts:264-301). aimux set dynamic: true on all four parts. Without a local tool of that name, Core now returns the call marked invalid, as parseToolCall does. Tests: should_handle_mcp_tools_with_annotations (tests/huggingface_responses_test.rs) now expects the invalid call. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RoxcKU4zBD64Lri3e4Lrq5
…ggingface@2.0.62 doGenerate pushes a tool-result after a function_call or mcp_call when part.output is truthy, with the output string as the result (huggingface-responses-language-model.ts:273, :312). aimux dropped the function_call output and, for mcp_call, also gave a tool-result for an empty string. Both now follow `if (part.output)`, and so does the stream's function_call (:489). Tests: should_handle_function_call_tool_responses now expects the tool-result; mcp_call_with_empty_output_has_no_tool_result is new (tests/huggingface_responses_test.rs). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RoxcKU4zBD64Lri3e4Lrq5
…sdk/huggingface@2.0.62
createHuggingFaceResponsesStreamError (huggingface-responses-language-model.ts:562-590)
reads only `error` and `response.failed` events: the details are
response.error for response.failed, else the event's error object or the
event itself, and the message must be a string. The transform then sets
finishReason { unified: 'error', raw: code or type } (:406-419); a chunk
that fails to parse sets { unified: 'error' } (:396-404).
aimux read only a top-level `error` field, so an `error` event with the
message on the event and every `response.failed` event went unnoticed,
and the finish reason stayed other. A first-event error is still returned
by do_stream (registered SSE pre-read).
Tests: reads_mid_stream_error_events, malformed_chunk_ends_with_an_error_finish
(tests/huggingface_responses_test.rs).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RoxcKU4zBD64Lri3e4Lrq5
cunninghamcard-bit
added a commit
that referenced
this pull request
Oct 20, 2026
The three behaviour fixes now live in their own PRs (#305, #306, #307); this branch stacks on the last one. responses.rs and CHANGELOG.md are the same on both sides; the old test file keeps the markers and takes the two aimux tests the fix PRs added. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RoxcKU4zBD64Lri3e4Lrq5
This was referenced Oct 20, 2026
cunninghamcard-bit
pushed a commit
that referenced
this pull request
Oct 20, 2026
The test branch now stacks on the fix PRs #305-#307, which add two aimux-own tests at the end of tests/huggingface_responses_test.rs. That file is already merged into src/huggingface/tests/responses/responses_language_model.rs, so the two tests land there at the same places. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
This was referenced Oct 20, 2026
cunninghamcard-bit
changed the base branch from
fix/hugging-face-output-items-yield-a-tool-result
to
master
October 20, 2026 11:06
This was referenced Oct 20, 2026
…nish Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RoxcKU4zBD64Lri3e4Lrq5
cunninghamcard-bit
marked this pull request as ready for review
October 24, 2026 10:10
eric8810
reviewed
Oct 25, 2026
eric8810
left a comment
Contributor
There was a problem hiding this comment.
stream error → error part → finish 的顺序和 message 校验符合 pinned huggingface 2.0.62;但本 PR 还顺带改了 function_call tool-result 和 mcp_call/mcp_list_tools 的 dynamic 字段,测试也重写了。行为本身正确,建议在 PR 描述说明或拆成独立 PR,便于定位回归。
…nish Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RoxcKU4zBD64Lri3e4Lrq5
Contributor
Author
另:master 前进后本分支又和 CHANGELOG 冲突,合并 master 的提交检查通过后推送。 Generated by Claude Code Generated by Claude Code |
…ream-errors-end-with-an-error-finish # Conflicts: # CHANGELOG.md
…ream-errors-end-with-an-error-finish # Conflicts: # CHANGELOG.md
…ream-errors-end-with-an-error-finish # Conflicts: # CHANGELOG.md
eric8810
approved these changes
Oct 25, 2026
eric8810
left a comment
Contributor
There was a problem hiding this comment.
三项 HF 行为差异已在 PR body 按 commit 拆分并补 Before/After;error/response.failed parse、finish raw、malformed chunk 与 @ai-sdk/huggingface@2.0.62 对齐,新增测试通过。Approve。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the 3 behaviour differences in Hugging Face found while porting the upstream tests. Each difference is its own commit (listed below) and adds a test that fails on master and a CHANGELOG
Fixedentry. They were separate PRs (#305, #306 and this one). To keep one fix PR per vendor, the others are closed and this PR carries all of them. The Hugging Face test PR (#303) stacks on this branch. Part of the #276 list.26cf0a83fcdc9c0aa35198801. Hugging Face MCP calls are not dynamic
Before: Hugging Face
do_generatemarked everymcp_call/mcp_list_toolstool-call and tool-resultdynamic: true.@ai-sdk/huggingface2.0.62 sets no dynamic flag on them.After: the four parts carry no dynamic flag, as upstream. Without a local tool of that name,
generate_textnow returns the MCP call marked invalid (NoSuchTool), which is what the AI SDK'sparseToolCalldoes for a provider-executed call that is not dynamic.Found while porting the upstream Hugging Face tests (#303, case
doGenerate › basic text response › should handle MCP tools with annotations).How it works today
What this PR changes
Tests:
should_handle_mcp_tools_with_annotations(tests/huggingface_responses_test.rs) asserted that the call passes Core validation without local tools; it now expects the invalid call. The full upstream case is in #303.Docs: CHANGELOG
Fixed.Note: A caller that relied on the MCP call passing validation without a local tool now gets an invalid tool call, the same result the AI SDK gives.
2. Hugging Face output items yield a tool-result
Before: a non-streaming Hugging Face
function_callitem with anoutputgave only the tool-call; the output was dropped. Anmcp_callwhoseoutputwas an empty string still gave a tool-result.After: both follow upstream's
if (part.output): a non-emptyoutputstring adds a tool-result holding that string, an empty or missing one adds nothing. The stream'sfunction_calluses the same check.Found while porting the upstream Hugging Face tests (#303, case
tool calls › should handle function call tool responses).How it works today
What this PR changes
Tests (
tests/huggingface_responses_test.rs):should_handle_function_call_tool_responsesasserted the dropped output; it now expects tool-call, tool-result, text.mcp_call_with_empty_output_has_no_tool_resultis new. The full upstream case is in #303.Docs: CHANGELOG
Fixed.Note: The
mcp_callresult is now always the output string (upstream'sresult: part.output); before, a non-string JSON output was passed through as is.3. Hugging Face stream errors end with an error finish
Before: the Hugging Face stream read an in-stream error only from a top-level
errorfield. Anerrorevent that carries its message on the event itself ({"type":"error","code":"503","message":…}) and everyresponse.failedevent (response.error) passed unnoticed. After an error part or a chunk that fails to parse, the finish reason stayedother.After: errors are read as upstream
createHuggingFaceResponsesStreamErrordoes: onlyerrorandresponse.failedevents, details fromresponse.error, the event'serrorobject or the event itself, and a string message. Such an event is an error part, and the finish reason becomes{ unified: error, raw: code, else the event type }. A chunk that fails to parse sets{ unified: error }with no raw value. An error as the first event is still returned bydo_streamasErr(the registered SSE pre-read).Found while porting the upstream Hugging Face tests (#303, cases
doStream › should handle streaming errorsandpreserves $expectedType stream errors).How it works today
What this PR changes
A later
response.completedstill sets the finish reason again, as upstream.Tests (
tests/huggingface_responses_test.rs):reads_mid_stream_error_eventssends each event kind afterresponse.created;malformed_chunk_ends_with_an_error_finishchecks the parse-error finish. Upstream's own cases put the error first, which aimux returns fromdo_stream; they are ported in #303 (the first-event one as a registered exclusion).Docs: CHANGELOG
Fixed.Note: An event with a top-level
errorfield but anothertype(noterrororresponse.failed) is no longer treated as an error, as upstream.Type of change
Checklist
cargo +1.99 fmt -p aimux-providers -- --checkpassescargo +1.99 clippy -p aimux-providers --lib --tests -- -D warningspassescargo +1.99 test -p aimux-providers --test huggingface_responses_testpasses (35, after merging master)scripts/check_provider_boundaries.shpassesNotes for reviewers
🤖 Generated with Claude Code
https://claude.ai/code/session_01RoxcKU4zBD64Lri3e4Lrq5