LLM text chunks are streamed as message_file when assistant message has files

Open Beginner friendly
#36,990 6 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
72/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
python
Domain
api, backend

Research direction

Start with api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py and trace QueueLLMChunkEvent handling into message_cycle_manager.py. Compare that path with QueueMessageFileEvent handling and review the unit test added in related PR #31414. Done means text chunks consistently produce message events while file metadata remains message_file events.

Written by the indexing model from the issue text.

Description

project#dify
Self Checks
  • I have read the Contributing Guide and Language Policy.
  • This is only for bug report, if you would like to ask a question, please head to Discussions.
  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report, otherwise it will be closed.
  • 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :)
  • Please do not modify this template :) and fill in all the required fields.
Dify version

main branch at b96ea94505e3abe00daba69faa8bba9bcf9deb0a.

Cloud or Self Hosted

Self Hosted (Source) / upstream main code path.

Steps to reproduce
  1. Use a chat/completion flow that streams an assistant response and also produces an assistant-side message file for the same message. For example, a workflow/tool path that emits QueueMessageFileEvent before or during LLM token streaming.
  2. The file event is handled by MessageCycleManager.message_file_to_stream_response(), which caches the message id in _message_has_file and correctly emits a message_file event for the file metadata.
  3. When a later QueueLLMChunkEvent is processed in EasyUIBasedGenerateTaskPipeline._process_stream_response(), the code calls MessageCycleManager.get_message_event_type(message_id=...) and reuses that event type for LLM text chunks.
  4. Since the same message already has an assistant file, get_message_event_type() returns StreamEvent.MESSAGE_FILE.
  5. The LLM text chunk is therefore emitted through message_to_stream_response(..., event_type=StreamEvent.MESSAGE_FILE) instead of StreamEvent.MESSAGE.

Current code evidence on main:

  • api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py still precomputes the event type for QueueLLMChunkEvent by calling get_message_event_type(message_id=self._message_id) and passes it to message_to_stream_response().
  • api/core/app/task_pipeline/message_cycle_manager.py returns StreamEvent.MESSAGE_FILE from get_message_event_type() when the message id is present in _message_has_file or when an assistant MessageFile exists for that message.

Related previously closed PR with a small fix and unit test: https://github.com/langgenius/dify/pull/31414

✔️ Expected Behavior

QueueLLMChunkEvent text chunks should always be streamed as event: message, regardless of whether the same assistant message also has files.

File metadata should continue to be streamed separately as event: message_file via QueueMessageFileEvent.

❌ Actual Behavior

When the assistant message has a file, LLM text chunks can be streamed as event: message_file. The web client may treat those chunks as file events instead of normal message text, so streamed answer text can be dropped or not rendered correctly.

Dominant language
TypeScript
Stars
157k
Forks
24.7k
Avg merge
22h 32m
Merged PRs (30d)
611

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from langgenius/dify

All issues in langgenius/dify

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.