1111from typing import Any , BinaryIO , Dict , Generator , List , Optional , Tuple , Union
1212
1313from .common import DifyBaseClient , DifyType
14+ from .chatbot import ChatbotClient
15+ class AgentEvent :
16+ """事件类型枚举
1417
18+ 定义了Dify Agent API中可能的事件类型,用于处理流式响应中的事件。
19+ """
1520
16- class AgentClient (DifyBaseClient ):
21+ MESSAGE = "message" # LLM返回文本块事件,包含分块输出的文本内容
22+ AGENT_MESSAGE = "agent_message" # Agent模式下返回文本块事件,包含分块输出的文本内容
23+ AGENT_THOUGHT = "agent_thought" # Agent思考步骤事件,包含工具调用相关信息
24+ MESSAGE_FILE = "message_file" # 文件事件,表示有新文件需要展示
25+ MESSAGE_END = "message_end" # 消息结束事件,表示流式返回结束
26+ TTS_MESSAGE = "tts_message" # TTS音频流事件,包含base64编码的音频块
27+ TTS_MESSAGE_END = "tts_message_end" # TTS音频流结束事件
28+ MESSAGE_REPLACE = "message_replace" # 消息内容替换事件,用于内容审查后的替换
29+ ERROR = "error" # 流式输出过程中出现的异常事件
30+ PING = "ping" # 保持连接存活的ping事件,每10秒一次
31+
32+
33+ class AgentClient (ChatbotClient ):
1734 """Dify Agent应用客户端类。
1835
1936 提供与Dify Agent应用API交互的方法,包括发送消息、获取历史消息、管理会话、
2037 上传文件、语音转文字、文字转语音等功能。Agent应用支持迭代式规划推理和自主工具调用。
2138 """
2239
2340 type = DifyType .Agent
24-
41+
42+ def __init__ (self , * args , ** kwargs ):
43+ super ().__init__ (* args , ** kwargs )
44+ self .task_id = None
45+
2546 def send_message (
2647 self ,
2748 query : str ,
@@ -32,7 +53,7 @@ def send_message(
3253 files : List [Dict [str , Any ]] = None ,
3354 auto_generate_name : bool = True ,
3455 ** kwargs , # 添加kwargs参数,用于接收额外的请求参数
35- ) -> Generator [Dict [str , Any ], None , None ]:
56+ ) -> Generator [Dict [str , Any ], None , None ] | Dict [ str , Any ] :
3657 """
3758 发送对话消息,创建会话消息。在Agent模式下,只支持streaming流式模式。
3859
@@ -55,7 +76,7 @@ def send_message(
5576 """
5677 if response_mode != "streaming" :
5778 raise ValueError ("Agent mode only supports streaming response mode" )
58-
79+
5980 payload = {
6081 "query" : query ,
6182 "user" : user ,
@@ -74,7 +95,7 @@ def send_message(
7495
7596 return self .post_stream (endpoint , json_data = payload , ** kwargs ) # 传递额外参数
7697
77- def stop_response (self , task_id : str , user : str ) -> Dict [str , Any ]:
98+ def stop_task (self , task_id : str , user : str ) -> Dict [str , Any ]:
7899 """
79100 停止正在进行的响应流。此方法仅在流式模式下有效。
80101
@@ -95,7 +116,7 @@ def stop_response(self, task_id: str, user: str) -> Dict[str, Any]:
95116 endpoint = f"chat-messages/{ task_id } /stop"
96117 payload = {"user" : user }
97118 return self .post (endpoint , json_data = payload )
98-
119+
99120 def get_meta (self ) -> Dict [str , Any ]:
100121 """
101122 获取应用Meta信息,用于获取工具icon等。
@@ -107,171 +128,4 @@ def get_meta(self) -> Dict[str, Any]:
107128 requests.HTTPError: 当API请求失败时
108129 """
109130 return self .get ("meta" )
110-
111- def process_streaming_response (
112- self ,
113- stream_generator : Generator [Dict [str , Any ], None , None ],
114- handle_message = None ,
115- handle_agent_message = None ,
116- handle_agent_thought = None ,
117- handle_message_file = None ,
118- handle_message_end = None ,
119- handle_tts_message = None ,
120- handle_tts_message_end = None ,
121- handle_message_replace = None ,
122- handle_error = None ,
123- handle_ping = None ,
124- break_on_error = True ,
125- ) -> Dict [str , Any ]:
126- """
127- 处理流式响应,调用相应事件处理器。
128-
129- Args:
130- stream_generator: 流式响应生成器
131- handle_message: LLM返回文本块事件处理函数
132- handle_agent_message: Agent模式下返回文本块事件处理函数
133- handle_agent_thought: Agent模式下思考步骤事件处理函数
134- handle_message_file: 文件事件处理函数
135- handle_message_end: 消息结束事件处理函数
136- handle_tts_message: TTS音频流事件处理函数
137- handle_tts_message_end: TTS音频流结束事件处理函数
138- handle_message_replace: 消息内容替换事件处理函数
139- handle_error: 错误事件处理函数
140- handle_ping: ping事件处理函数
141- break_on_error: 当遇到错误时是否中断处理,默认为True
142-
143- Returns:
144- Dict[str, Any]: 处理结果,包含消息ID、会话ID等信息
145-
146- 示例:
147- ```python
148- def on_agent_message(chunk):
149- # 打印Agent返回的文本块
150- print(f"{chunk['answer']}")
151-
152- def on_agent_thought(chunk):
153- print(f"Agent思考: {chunk['thought']}")
154- print(f"使用工具: {chunk['tool']}")
155- print(f"工具输入: {chunk['tool_input']}")
156- print(f"观察结果: {chunk['observation']}")
157-
158- def on_message_end(chunk):
159- print(f"消息结束: ID={chunk['message_id']}")
160-
161- client = AgentClient(api_key)
162- stream = client.send_message(
163- query="帮我分析最近的股市走势",
164- user="user123"
165- )
166- result = client.process_streaming_response(
167- stream,
168- handle_agent_message=on_agent_message,
169- handle_agent_thought=on_agent_thought,
170- handle_message_end=on_message_end
171- )
172- ```
173- """
174- result = {"agent_thoughts" : []}
175- answer_chunks = []
176-
177- for chunk in stream_generator :
178- event = chunk .get ("event" )
179-
180- if event == "message" and handle_message :
181- handle_message (chunk )
182- # 累积回答内容
183- if "answer" in chunk :
184- answer_chunks .append (chunk ["answer" ])
185- # 保存消息和会话ID
186- if "message_id" in chunk and not result .get ("message_id" ):
187- result ["message_id" ] = chunk ["message_id" ]
188- if "conversation_id" in chunk and not result .get ("conversation_id" ):
189- result ["conversation_id" ] = chunk ["conversation_id" ]
190- if "task_id" in chunk and not result .get ("task_id" ):
191- result ["task_id" ] = chunk ["task_id" ]
192-
193- elif event == "agent_message" and handle_agent_message :
194- handle_agent_message (chunk )
195- # 累积回答内容
196- if "answer" in chunk :
197- answer_chunks .append (chunk ["answer" ])
198- # 保存消息和会话ID
199- if "message_id" in chunk and not result .get ("message_id" ):
200- result ["message_id" ] = chunk ["message_id" ]
201- if "conversation_id" in chunk and not result .get ("conversation_id" ):
202- result ["conversation_id" ] = chunk ["conversation_id" ]
203- if "task_id" in chunk and not result .get ("task_id" ):
204- result ["task_id" ] = chunk ["task_id" ]
205-
206- elif event == "agent_thought" and handle_agent_thought :
207- if handle_agent_thought :
208- handle_agent_thought (chunk )
209- # 保存Agent思考内容
210- thought_data = {
211- "id" : chunk .get ("id" ),
212- "position" : chunk .get ("position" ),
213- "thought" : chunk .get ("thought" ),
214- "observation" : chunk .get ("observation" ),
215- "tool" : chunk .get ("tool" ),
216- "tool_input" : chunk .get ("tool_input" ),
217- "message_files" : chunk .get ("message_files" , []),
218- "created_at" : chunk .get ("created_at" ),
219- }
220- result ["agent_thoughts" ].append (thought_data )
221-
222- elif event == "message_file" and handle_message_file :
223- handle_message_file (chunk )
224- # 保存文件信息
225- if not result .get ("files" ):
226- result ["files" ] = []
227- result ["files" ].append (
228- {
229- "id" : chunk .get ("id" ),
230- "type" : chunk .get ("type" ),
231- "belongs_to" : chunk .get ("belongs_to" ),
232- "url" : chunk .get ("url" ),
233- }
234- )
235-
236- elif event == "message_end" and handle_message_end :
237- if handle_message_end :
238- handle_message_end (chunk )
239- # 保存元数据
240- if "metadata" in chunk :
241- result ["metadata" ] = chunk ["metadata" ]
242- if "message_id" in chunk and not result .get ("message_id" ):
243- result ["message_id" ] = chunk ["message_id" ]
244- if "conversation_id" in chunk and not result .get ("conversation_id" ):
245- result ["conversation_id" ] = chunk ["conversation_id" ]
246-
247- elif event == "tts_message" and handle_tts_message :
248- handle_tts_message (chunk )
249-
250- elif event == "tts_message_end" and handle_tts_message_end :
251- handle_tts_message_end (chunk )
252-
253- elif event == "message_replace" and handle_message_replace :
254- handle_message_replace (chunk )
255- # 替换回答内容
256- if "answer" in chunk :
257- answer_chunks = [chunk ["answer" ]]
258-
259- elif event == "error" and handle_error :
260- handle_error (chunk )
261- if break_on_error :
262- # 添加错误信息到结果中
263- result ["error" ] = {
264- "status" : chunk .get ("status" ),
265- "code" : chunk .get ("code" ),
266- "message" : chunk .get ("message" ),
267- }
268- break
269-
270- elif event == "ping" and handle_ping :
271- handle_ping (chunk )
272-
273- # 合并所有回答块
274- if answer_chunks :
275- result ["answer" ] = "" .join (answer_chunks )
276-
277- return result
131+
0 commit comments