Skip to content

Empty reasoning_content chunks cause multiple <think> blocks / repeated Thoughts entries in chat UI #277

@utsumi-fj

Description

@utsumi-fj

Description

When an LLM response stream includes a chunk with an empty reasoning_content, the Dify chat UI ends up rendering multiple <think> blocks. As a result, multiple Thoughts (x.x s) entries are displayed.

Screenshots:

Image Image

Environment

  • Dify 1.11.2 self-hosted (Docker)
  • Dify Plugin SDK 0.7.1
  • OpenAI-API-Compatible plugin 0.0.30
  • Model: openai/gpt-oss-20b (served via vLLM)
  • Access path: LiteLLM endpoint registered to the OpenAI-API-Compatible plugin

Details

When sending a streaming request directly to the LiteLLM endpoint, the stream may include a chunk with an empty reasoning_content:

$ curl -H "Content-Type: application/json" -H "Authorization: Bearer $API_KEY" http://localhost:4000/v1/chat/completions -d '{"model":"openai/gpt-oss-20b","stream":true,"messages":[{"role":"user","content":"Please explain Euler-Lagrange equation."}]}'
...
data: {"id":"chatcmpl-a5b6f10276aae84e","created":1767852482,"model":"my-openai/gpt-oss-20b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"reasoning_content":"","reasoning":"","role":"assistant"}}]}

data: {"id":"chatcmpl-a5b6f10276aae84e","created":1767852482,"model":"my-openai/gpt-oss-20b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"reasoning_content":"We","reasoning":"We"}}]}

data: {"id":"chatcmpl-a5b6f10276aae84e","created":1767852482,"model":"my-openai/gpt-oss-20b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"reasoning_content":" need","reasoning":" need"}}]}

...

data: {"id":"chatcmpl-a5b6f10276aae84e","created":1767852482,"model":"my-openai/gpt-oss-20b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"reasoning_content":"t","reasoning":"t"}}]}

data: {"id":"chatcmpl-a5b6f10276aae84e","created":1767852482,"model":"my-openai/gpt-oss-20b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"reasoning_content":"(","reasoning":"("}}]}

data: {"id":"chatcmpl-a5b6f10276aae84e","created":1767852482,"model":"my-openai/gpt-oss-20b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"reasoning_content":"","reasoning":""}}]}

data: {"id":"chatcmpl-a5b6f10276aae84e","created":1767852482,"model":"my-openai/gpt-oss-20b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"reasoning_content":"∂","reasoning":"∂"}}]}

...

data: {"id":"chatcmpl-a5b6f10276aae84e","created":1767852482,"model":"my-openai/gpt-oss-20b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"##"}}]}

data: {"id":"chatcmpl-a5b6f10276aae84e","created":1767852482,"model":"my-openai/gpt-oss-20b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":" The"}}]}

...

It looks like the Dify Plugin SDK closes the current <think> block when it encounters a chunk like the following:

data: {"id":"chatcmpl-a5b6f10276aae84e","created":1767852482,"model":"my-openai/gpt-oss-20b","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"reasoning_content":"","reasoning":""}}]}

However, an empty reasoning_content chunk does not indicate the end of reasoning. Treating it as a boundary causes the SDK/UI to start a new <think> block for subsequent reasoning tokens, which results in multiple Thoughts (x.x s) entries.

Expected behavior

  • Empty reasoning_content (e.g. "delta":{"reasoning_content":""}) should not close the current <think> block.
  • The <think> block should be closed only when reasoning_content is absent or null.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions