-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathstreaming_callback.py
More file actions
97 lines (83 loc) · 3.29 KB
/
Copy pathstreaming_callback.py
File metadata and controls
97 lines (83 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""
Streaming Callback Handler for WebSocket
Streams LangChain agent responses in real-time to WebSocket clients.
"""
from langchain.callbacks.base import AsyncCallbackHandler
from typing import Any, Dict, List, Optional
import asyncio
class WebSocketStreamingCallback(AsyncCallbackHandler):
"""
Custom callback handler to stream LangChain responses via WebSocket.
"""
def __init__(self, ws_manager, session_id: str):
"""
Args:
ws_manager: WebSocket manager instance
session_id: Target session ID
"""
self.ws_manager = ws_manager
self.session_id = session_id
self.current_tool = None
async def on_llm_start(
self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
) -> None:
"""Called when LLM starts."""
await self.ws_manager.send_typing(self.session_id)
async def on_llm_new_token(self, token: str, **kwargs: Any) -> None:
"""Called when a new token is generated - stream it!"""
await self.ws_manager.send_message(self.session_id, {
"type": "response_chunk",
"content": token
})
async def on_llm_end(self, response, **kwargs: Any) -> None:
"""Called when LLM finishes."""
pass
async def on_tool_start(
self, serialized: Dict[str, Any], input_str: str, **kwargs: Any
) -> None:
"""Called when a tool starts executing."""
tool_name = serialized.get("name", "unknown")
self.current_tool = tool_name
# Send tool execution notification
tool_descriptions = {
"planner": "Analyzing your request and preparing questions...",
"cad_generator": "Generating your CAD model...",
"modifier": "Modifying your design...",
"cad_qa": "Looking up information..."
}
description = tool_descriptions.get(tool_name, f"Running {tool_name}...")
await self.ws_manager.send_tool_executing(
self.session_id,
tool_name,
description
)
async def on_tool_end(self, output: str, **kwargs: Any) -> None:
"""Called when a tool finishes."""
# Optionally stream tool output
if output and len(output) < 500: # Only stream short outputs
await self.ws_manager.send_message(self.session_id, {
"type": "tool_output",
"content": output,
"tool": self.current_tool
})
async def on_tool_error(
self, error: Exception, **kwargs: Any
) -> None:
"""Called when a tool errors."""
await self.ws_manager.send_error(
self.session_id,
f"Tool error: {str(error)}"
)
async def on_agent_action(self, action, **kwargs: Any) -> None:
"""Called when agent decides on an action."""
# Can be used to show agent's thinking
pass
async def on_agent_finish(self, finish, **kwargs: Any) -> None:
"""Called when agent finishes."""
pass
async def on_chain_error(self, error: Exception, **kwargs: Any) -> None:
"""Called when chain errors."""
await self.ws_manager.send_error(
self.session_id,
f"Processing error: {str(error)}"
)