Skip to content

feat(api): add WebSocket endpoints for real-time streaming#33543

Open
Olauge-Secret wants to merge 1 commit intolanggenius:mainfrom
Olauge-Secret:feat/websocket-support
Open

feat(api): add WebSocket endpoints for real-time streaming#33543
Olauge-Secret wants to merge 1 commit intolanggenius:mainfrom
Olauge-Secret:feat/websocket-support

Conversation

@Olauge-Secret
Copy link
Copy Markdown

@Olauge-Secret Olauge-Secret commented Mar 16, 2026

Important

  1. Make sure you have read our contribution guidelines
  2. Ensure there is an associated issue and you have been assigned to it
  3. Use the correct syntax to link this PR: Fixes #<issue number>.

Summary

Fixes #33542

Add WebSocket support alongside existing SSE (Server-Sent Events) for chat and completion message streaming. This enables persistent bidirectional connections for messaging platform integrations such as WhatsApp, Telegram, Feishu/Lark, and Slack, which require long-lived tunnels rather than traditional webhook-based request/response cycles.

Changes

  • New dependency: flask-sock~=0.7.0 for lightweight WebSocket support on Flask
  • api/libs/websocket.py: Utility that bridges the existing Redis pub/sub event streaming generator to WebSocket frames
  • api/controllers/service_api/app/websocket.py: Service API WebSocket endpoints at /v1/ws/chat-messages and /v1/ws/completion-messages
  • api/controllers/web/websocket.py: Web App WebSocket endpoints at /api/ws/chat-messages and /api/ws/completion-messages
  • api/extensions/ext_blueprints.py: Register new WebSocket blueprints
  • api/tests/unit_tests/libs/test_websocket.py: Unit tests for the WebSocket streaming utility

How it works

  1. Client opens a WebSocket connection with auth token (via Authorization header or ?token= query param)
  2. Client sends a JSON payload matching the existing ChatRequestPayload / CompletionRequestPayload schema
  3. Server streams the same events as SSE but as individual JSON text frames over the WebSocket
  4. Connection closes automatically after the terminal event

Usage

Service API:

ws://<host>/v1/ws/chat-messages?token=<api_key>&user=<user_id>
ws://<host>/v1/ws/completion-messages?token=<api_key>&user=<user_id>

Web App:

ws://<host>/api/ws/chat-messages
ws://<host>/api/ws/completion-messages

Screenshots

Before After
SSE-only streaming SSE + WebSocket streaming available

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint and make type-check (backend) and cd web && npx lint-staged (frontend) to appease the lint gods

Add WebSocket support alongside existing SSE for chat and completion
message streaming, enabling persistent bidirectional connections for
messaging platform integrations (WhatsApp, Telegram, Feishu, Slack).

Closes langgenius#33542

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. dependencies Pull requests that update a dependency file labels Mar 16, 2026
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the API's real-time capabilities by integrating WebSocket support. This addition allows for more robust and persistent communication channels, which are crucial for seamless integration with various messaging platforms. The change provides a flexible alternative to Server-Sent Events, catering to applications that demand long-lived, bidirectional data streams.

Highlights

  • New WebSocket Endpoints: Introduced new WebSocket endpoints for both the Service API (/v1/ws/chat-messages, /v1/ws/completion-messages) and the Web App (/api/ws/chat-messages, /api/ws/completion-messages) to enable real-time streaming.
  • Persistent Bidirectional Communication: Enabled persistent bidirectional connections for messaging platform integrations (e.g., WhatsApp, Telegram, Feishu/Lark, Slack) which require long-lived tunnels, complementing the existing SSE (Server-Sent Events) functionality.
  • New Dependency and Utility: Added flask-sock~=0.7.0 for lightweight WebSocket support in Flask and a new utility (api/libs/websocket.py) to bridge existing Redis pub/sub event streaming to WebSocket frames.
  • Authentication and Payload Handling: Implemented authentication mechanisms for WebSocket connections via Authorization header or token query parameter, and defined how clients send JSON payloads matching ChatRequestPayload and CompletionRequestPayload schemas.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • api/controllers/service_api/app/websocket.py
    • Added new file to define WebSocket endpoints for chat and completion messages in the Service API.
    • Implemented _authenticate_ws function for token-based authentication for WebSocket connections.
    • Included error handling for invalid app modes, payloads, and exceptions during message generation.
  • api/controllers/web/websocket.py
    • Added new file to define WebSocket endpoints for chat and completion messages in the Web App.
    • Implemented _authenticate_web_ws function for JWT token-based authentication for web app WebSocket connections.
    • Included error handling for invalid app modes, payloads, and exceptions during message generation.
  • api/extensions/ext_blueprints.py
    • Imported and registered the new WebSocket blueprints (service_api_ws and web_ws) and initialized their respective flask-sock instances with the main Flask app.
  • api/libs/websocket.py
    • Added new file containing stream_events_to_websocket utility function.
    • Implemented logic to convert existing event generators (dict or streaming) into JSON text frames for WebSocket transmission.
    • Included graceful handling for client disconnections.
  • api/pyproject.toml
    • Added flask-sock~=0.7.0 to the project's dependencies.
  • api/tests/unit_tests/libs/test_websocket.py
    • Added new file containing unit tests for the stream_events_to_websocket utility.
    • Tested blocking dict responses, streaming dict events, streaming string events, mixed events, and graceful client disconnect handling.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces WebSocket support for real-time streaming of chat and completion messages, complementing the existing SSE implementation. This is a significant feature that enables better integration with messaging platforms requiring persistent connections. The implementation adds new WebSocket endpoints for both the service and web APIs, a utility for streaming events, and corresponding unit tests.

The overall approach is solid. However, there are a few areas for improvement:

  • The error handling in the new WebSocket controllers constructs JSON responses using f-strings, which is unsafe and can lead to malformed JSON and potential information leaks. This should be changed to use json.dumps.
  • The exception handling in the WebSocket streaming utility is too broad and could mask non-connection related errors.

Comment on lines +95 to +98
except Exception as exc:
ws.send(f'{{"error": "{exc}"}}')
ws.close()
return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Sending error messages using an f-string is unsafe as it can lead to invalid JSON if the exception message contains special characters (e.g., quotes). It can also leak sensitive information. It's better to use json.dumps to properly serialize the error data. This issue is present in multiple error handling blocks within this file (e.g., lines 117-118, 136-138, 154-155, 174-175, 194-196) and should be fixed in all occurrences.

Ideally, json should be imported at the top of the file.

Suggested change
except Exception as exc:
ws.send(f'{{"error": "{exc}"}}')
ws.close()
return
except Exception as exc:
import json
ws.send(json.dumps({"error": str(exc)}))
ws.close()
return

Comment on lines +43 to +46
except Exception as exc:
ws.send(f'{{"error": "{exc}"}}')
ws.close()
return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Sending error messages using an f-string is unsafe. It can produce invalid JSON if the exception message contains special characters, and it might leak internal implementation details. Please use json.dumps to ensure the error message is always correctly formatted as a JSON string. This should be applied to all similar error handling blocks in this file.

Ideally, json should be imported at the top of the file.

Suggested change
except Exception as exc:
ws.send(f'{{"error": "{exc}"}}')
ws.close()
return
except Exception as exc:
import json
ws.send(json.dumps({"error": str(exc)}))
ws.close()
return

Comment thread api/libs/websocket.py
Comment on lines +47 to +48
except Exception:
logger.debug("WebSocket connection closed by client")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Catching a broad Exception here might hide bugs that are not related to the client disconnecting, such as serialization errors from orjson_dumps. It would be safer to catch a more specific exception related to connection errors. The corresponding test test_client_disconnect_handled_gracefully uses ConnectionError, which would be a good, more specific exception to catch here.

Suggested change
except Exception:
logger.debug("WebSocket connection closed by client")
except ConnectionError:
logger.debug("WebSocket connection closed by client")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Need support websocket using when whatsapp\telegram\feishu\slack app can keep longalive tunnel

1 participant