fix(step): using a Step instance as a decorator always raises TypeError - #3032
Open
Anai-Guo wants to merge 1 commit into
Open
fix(step): using a Step instance as a decorator always raises TypeError#3032Anai-Guo wants to merge 1 commit into
Anai-Guo wants to merge 1 commit into
Conversation
Step.__call__ forwards thread_id=self.thread_id to step(), but step() had no thread_id parameter, so decorating a function with a Step instance (@step(name=...)) always raised TypeError before the wrapped function ran. Add thread_id to step() and pass it through to the Step it builds in both the async and sync wrappers, matching the parameter Step.__init__ already accepts.
Anai-Guo
requested review from
asvishnyakov,
hayescode and
sandangel
as code owners
August 29, 2026 19:30
Contributor
There was a problem hiding this comment.
1 issue found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="backend/chainlit/step.py">
<violation number="1" location="backend/chainlit/step.py:113">
P3: The sync decorator path now forwards `thread_id` to `Step(...)` but has no test. Since the PR explicitly aims for sync/async symmetry and only exercises async in the new tests, add a sync-variant of `test_step_decorator_forwards_thread_id` (a plain `def` wrapped with `@step(thread_id=...)`) to cover `sync_wrapper`.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| name=name, | ||
| id=id, | ||
| parent_id=parent_id, | ||
| thread_id=thread_id, |
Contributor
There was a problem hiding this comment.
P3: The sync decorator path now forwards thread_id to Step(...) but has no test. Since the PR explicitly aims for sync/async symmetry and only exercises async in the new tests, add a sync-variant of test_step_decorator_forwards_thread_id (a plain def wrapped with @step(thread_id=...)) to cover sync_wrapper.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/chainlit/step.py, line 113:
<comment>The sync decorator path now forwards `thread_id` to `Step(...)` but has no test. Since the PR explicitly aims for sync/async symmetry and only exercises async in the new tests, add a sync-variant of `test_step_decorator_forwards_thread_id` (a plain `def` wrapped with `@step(thread_id=...)`) to cover `sync_wrapper`.</comment>
<file context>
@@ -109,6 +110,7 @@ async def async_wrapper(*args, **kwargs):
name=name,
id=id,
parent_id=parent_id,
+ thread_id=thread_id,
tags=tags,
language=language,
</file context>
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.
The bug
Step.__call__lets aStepinstance be used as a decorator. It forwardsthread_idto thestep()decorator factory:backend/chainlit/step.py:447-455
…but
step()does not declarethread_id. So any use of aStepinstance as a decorator raises before the wrapped function ever runs:Step.__init__does acceptthread_id(andtests/test_step.py::test_step_with_custom_thread_idalready covers it there), so the parameter is real everywhere except on the decorator path that tries to propagate it.The fix
Add
thread_id: Optional[str] = Nonetostep()and pass it to theStep(...)it constructs — in both the async and the sync wrapper, so the two branches stay symmetric.Step.__init__already doesself.thread_id = thread_id or context.session.thread_id, so the defaultNonepreserves today's behaviour for every existing caller.+3lines instep.py.Tests
Two tests added to
TestStepDecorator:test_step_instance_used_as_decorator— the crash itself:@Step(name=..., type="tool")on an async function.test_step_decorator_forwards_thread_id—@step(thread_id=...)actually reaches theStepthat gets created, so the new parameter is wired up rather than merely accepted.Both fail on
mainwith the exactTypeErrorabove, and pass with the fix:ruff checkandruff format --checkare clean on both files using the repo's rootpyproject.tomlconfig.🤖 Generated with Claude Code
Summary by cubic
Fixes using a Step instance as a decorator, which always raised TypeError because
step()didn't acceptthread_id; now it does and forwards it, so@Step(...)works again. Adds tests for decorator usage andthread_idforwarding.Written for commit f301816. Summary will update on new commits.