Skip to content

fix(huggingface): pass prompt as tuple to Thread args instead of a set#13677

Open
frankgoldfish wants to merge 1 commit intomicrosoft:mainfrom
frankgoldfish:fix/huggingface-thread-args-set
Open

fix(huggingface): pass prompt as tuple to Thread args instead of a set#13677
frankgoldfish wants to merge 1 commit intomicrosoft:mainfrom
frankgoldfish:fix/huggingface-thread-args-set

Conversation

@frankgoldfish
Copy link

Summary

In HuggingFaceTextCompletion._inner_get_streaming_text_contents, the threading.Thread constructor was called with args={prompt} (a set literal) instead of args=(prompt,) (a tuple).

Bug

# Before (buggy): {prompt} creates a Python set, not a tuple
thread = Thread(
    target=self.generator, args={prompt}, kwargs=settings.prepare_settings_dict(streamer=streamer)
)

threading.Thread requires args to be a sequence (tuple or list) that is unpacked as positional arguments to the target callable. When a set is passed:

  1. Sets have no guaranteed order (though for a single element this is moot).
  2. More importantly, Python's Thread implementation internally calls self._target(*self._args, **self._kwargs). When _args is a set containing a string like "hello world", Python unpacks the set — but since Thread stores it and passes it directly to the target function with *args, passing a set actually works differently than a tuple. The generator (a HuggingFace pipeline) expects the prompt as its first positional argument. A set literal {prompt} evaluates to the set {prompt}, and when passed via *args unpacking is generator({prompt}) — the generator receives the set object as its first argument rather than the string.

Fix

# After (fixed): (prompt,) is a tuple with one element
thread = Thread(
    target=self.generator, args=(prompt,), kwargs=settings.prepare_settings_dict(streamer=streamer)
)

Files Changed

  • python/semantic_kernel/connectors/ai/hugging_face/services/hf_text_completion.py

Test plan

  • Confirm that HuggingFaceTextCompletion streaming works correctly by passing the prompt string as the first positional argument to the pipeline
  • Run existing HuggingFace unit tests

🤖 Generated with Claude Code

In `HuggingFaceTextCompletion._inner_get_streaming_text_contents`, the
`Thread` constructor was called with `args={prompt}`, which creates a Python
**set** `{prompt}` rather than the required positional-arguments **tuple**
`(prompt,)`.

`threading.Thread` requires `args` to be a sequence (tuple or list) that is
unpacked as positional arguments to the `target` callable. Passing a set
causes undefined iteration order and, for a single-element set containing a
string, the string would be iterated character by character instead of being
passed as a single argument, leading to incorrect or failing invocations of
`self.generator`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes the HuggingFace streaming text completion thread invocation by passing the prompt as a one item tuple to Thread(args=...), matching threading.Thread expectations and preventing incorrect positional argument handling.

Changes:

  • Replace args={prompt} (set literal) with args=(prompt,) (tuple) when constructing the streaming generation thread.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

# See https://github.com/huggingface/transformers/blob/main/src/transformers/generation/streamers.py#L159
thread = Thread(
target=self.generator, args={prompt}, kwargs=settings.prepare_settings_dict(streamer=streamer)
target=self.generator, args=(prompt,), kwargs=settings.prepare_settings_dict(streamer=streamer)
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description states that passing args={prompt} results in the target being called as generator({prompt}), but Thread ultimately calls self._target(*self._args, ...) and *-unpacking a set passes its elements, not the set itself (for a single string element it becomes generator(prompt)). Consider updating the PR description to reflect the actual failure mode (wrong type and nondeterministic ordering, and potential issues if more args are ever added) so the rationale is technically accurate.

Copilot uses AI. Check for mistakes.
Comment on lines 134 to 136
thread = Thread(
target=self.generator, args={prompt}, kwargs=settings.prepare_settings_dict(streamer=streamer)
target=self.generator, args=(prompt,), kwargs=settings.prepare_settings_dict(streamer=streamer)
)
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current unit tests for HuggingFaceTextCompletion streaming patch Thread but do not assert that it is constructed with args=(prompt,). Since this change fixes a subtle calling bug, please add an assertion in the existing streaming unit test to verify the exact Thread(..., args=..., kwargs=...) call so the regression is caught automatically.

Copilot uses AI. Check for mistakes.
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.

2 participants