Files
Dorod-Sky/skyvern/forge/sdk/routes/streaming/messages.py

146 lines
4.3 KiB
Python
Raw Normal View History

2025-06-25 02:37:26 +08:00
"""
2025-11-21 15:12:26 -05:00
Provides WS endpoints for streaming messages to/from our frontend application.
2025-06-25 02:37:26 +08:00
"""
import structlog
2025-11-21 15:12:26 -05:00
from fastapi import WebSocket
2025-06-25 02:37:26 +08:00
from skyvern.config import settings
2025-07-09 15:31:02 -04:00
from skyvern.forge.sdk.routes.routers import base_router, legacy_base_router
from skyvern.forge.sdk.routes.streaming.auth import _auth as local_auth
from skyvern.forge.sdk.routes.streaming.auth import auth as real_auth
2025-11-21 15:12:26 -05:00
from skyvern.forge.sdk.routes.streaming.channels.message import (
Loops,
MessageChannel,
get_message_channel_for_browser_session,
get_message_channel_for_workflow_run,
2025-07-09 15:31:02 -04:00
)
2025-06-25 02:37:26 +08:00
from skyvern.forge.sdk.utils.aio import collect
LOG = structlog.get_logger()
2025-11-21 15:12:26 -05:00
@base_router.websocket("/stream/messages/browser_session/{browser_session_id}")
async def browser_session_messages(
2025-07-09 15:31:02 -04:00
websocket: WebSocket,
2025-11-21 15:12:26 -05:00
browser_session_id: str,
apikey: str | None = None,
client_id: str | None = None,
token: str | None = None,
) -> None:
return await messages(
websocket=websocket,
2025-07-09 15:31:02 -04:00
browser_session_id=browser_session_id,
2025-11-21 15:12:26 -05:00
apikey=apikey,
2025-07-09 15:31:02 -04:00
client_id=client_id,
2025-11-21 15:12:26 -05:00
token=token,
2025-07-09 15:31:02 -04:00
)
2025-11-21 15:12:26 -05:00
@legacy_base_router.websocket("/stream/messages/workflow_run/{workflow_run_id}")
async def workflow_run_messages(
2025-06-25 02:37:26 +08:00
websocket: WebSocket,
2025-11-21 15:12:26 -05:00
workflow_run_id: str,
apikey: str | None = None,
client_id: str | None = None,
token: str | None = None,
) -> None:
return await messages(
websocket=websocket,
2025-06-25 02:37:26 +08:00
workflow_run_id=workflow_run_id,
2025-11-21 15:12:26 -05:00
apikey=apikey,
2025-06-25 02:37:26 +08:00
client_id=client_id,
2025-11-21 15:12:26 -05:00
token=token,
2025-06-25 02:37:26 +08:00
)
2025-11-21 15:12:26 -05:00
async def messages(
2025-07-09 15:31:02 -04:00
websocket: WebSocket,
2025-11-21 15:12:26 -05:00
browser_session_id: str | None = None,
workflow_run_id: str | None = None,
2025-07-09 15:31:02 -04:00
apikey: str | None = None,
client_id: str | None = None,
token: str | None = None,
) -> None:
auth = local_auth if settings.ENV == "local" else real_auth
2025-07-09 15:31:02 -04:00
organization_id = await auth(apikey=apikey, token=token, websocket=websocket)
if not organization_id:
2025-11-26 18:59:53 -07:00
LOG.warning(
2025-11-21 15:12:26 -05:00
"Authentication failed.",
browser_session_id=browser_session_id,
workflow_run_id=workflow_run_id,
)
2025-07-09 15:31:02 -04:00
return
if not client_id:
LOG.error(
2025-11-21 15:12:26 -05:00
"No client ID provided.",
2025-07-09 15:31:02 -04:00
browser_session_id=browser_session_id,
2025-11-21 15:12:26 -05:00
workflow_run_id=workflow_run_id,
2025-07-09 15:31:02 -04:00
)
await websocket.close(code=1002)
2025-07-09 15:31:02 -04:00
return
2025-11-21 15:12:26 -05:00
message_channel: MessageChannel
loops: Loops = []
2025-07-09 15:31:02 -04:00
2025-11-21 15:12:26 -05:00
if browser_session_id:
result = await get_message_channel_for_browser_session(
client_id=client_id,
2025-07-09 15:31:02 -04:00
browser_session_id=browser_session_id,
organization_id=organization_id,
2025-11-21 15:12:26 -05:00
websocket=websocket,
2025-07-09 15:31:02 -04:00
)
2025-11-21 15:12:26 -05:00
elif workflow_run_id:
result = await get_message_channel_for_workflow_run(
client_id=client_id,
workflow_run_id=workflow_run_id,
2025-07-09 15:31:02 -04:00
organization_id=organization_id,
2025-11-21 15:12:26 -05:00
websocket=websocket,
2025-07-09 15:31:02 -04:00
)
2025-11-21 15:12:26 -05:00
else:
LOG.error(
"[WS] messages: no browser_session_id or workflow_run_id provided",
2025-11-21 15:12:26 -05:00
client_id=client_id,
2025-07-09 15:31:02 -04:00
organization_id=organization_id,
)
2025-11-21 15:12:26 -05:00
await websocket.close(code=1002)
2025-06-25 02:37:26 +08:00
return
if not result:
2026-01-01 21:15:29 -08:00
LOG.debug(
2025-11-21 15:12:26 -05:00
"No message channel found.",
browser_session_id=browser_session_id,
2025-06-25 02:37:26 +08:00
workflow_run_id=workflow_run_id,
organization_id=organization_id,
)
await websocket.close(code=1013)
return
message_channel, loops = result
2025-06-25 02:37:26 +08:00
try:
LOG.info(
2025-11-21 15:12:26 -05:00
"Starting message channel loops.",
browser_session_id=browser_session_id,
2025-06-25 02:37:26 +08:00
workflow_run_id=workflow_run_id,
organization_id=organization_id,
)
await collect(loops)
except Exception:
LOG.exception(
2025-11-21 15:12:26 -05:00
"An exception occurred in the message loop function(s).",
browser_session_id=browser_session_id,
2025-06-25 02:37:26 +08:00
workflow_run_id=workflow_run_id,
organization_id=organization_id,
)
finally:
LOG.info(
2025-11-21 15:12:26 -05:00
"Closing the message channel.",
browser_session_id=browser_session_id,
2025-06-25 02:37:26 +08:00
workflow_run_id=workflow_run_id,
organization_id=organization_id,
)
2025-11-21 15:12:26 -05:00
await message_channel.close(reason="message-stream-closed")