From 534fa60b2ac719d08be92187bdeed46e448fcc66 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Fri, 10 Oct 2025 20:44:05 +0800 Subject: [PATCH] Fix: Agent.reset() argument wrong #10463 & Unable to converse with agent through Python API. #10415 (#10472) ### What problem does this PR solve? Fix: Agent.reset() argument wrong #10463 & Unable to converse with agent through Python API. #10415 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) --- agent/canvas.py | 3 -- agent/component/agent_with_tools.py | 2 +- deepdoc/parser/pdf_parser.py | 2 +- rag/flow/parser/parser.py | 4 +- sdk/python/ragflow_sdk/modules/session.py | 49 +++++++++++++++-------- 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/agent/canvas.py b/agent/canvas.py index a22391deb..d1cbc48ae 100644 --- a/agent/canvas.py +++ b/agent/canvas.py @@ -203,7 +203,6 @@ class Canvas(Graph): self.history = [] self.retrieval = [] self.memory = [] - for k in self.globals.keys(): if isinstance(self.globals[k], str): self.globals[k] = "" @@ -292,7 +291,6 @@ class Canvas(Graph): "thoughts": self.get_component_thoughts(self.path[i]) }) _run_batch(idx, to) - # post processing of components invocation for i in range(idx, to): cpn = self.get_component(self.path[i]) @@ -393,7 +391,6 @@ class Canvas(Graph): self.path = path yield decorate("user_inputs", {"inputs": another_inputs, "tips": tips}) return - self.path = self.path[:idx] if not self.error: yield decorate("workflow_finished", diff --git a/agent/component/agent_with_tools.py b/agent/component/agent_with_tools.py index a85df4029..aa1ac296d 100644 --- a/agent/component/agent_with_tools.py +++ b/agent/component/agent_with_tools.py @@ -346,7 +346,7 @@ Respond immediately with your final comprehensive answer. return "Error occurred." - def reset(self): + def reset(self, temp=False): for k, cpn in self.tools.items(): cpn.reset() diff --git a/deepdoc/parser/pdf_parser.py b/deepdoc/parser/pdf_parser.py index 2cf14b88a..2fb041e87 100644 --- a/deepdoc/parser/pdf_parser.py +++ b/deepdoc/parser/pdf_parser.py @@ -997,7 +997,7 @@ class RAGFlowPdfParser: self.__ocr(i + 1, img, chars, zoomin, id) if callback and i % 6 == 5: - callback(prog=(i + 1) * 0.6 / len(self.page_images), msg="") + callback((i + 1) * 0.6 / len(self.page_images), msg="") async def __img_ocr_launcher(): def __ocr_preprocess(): diff --git a/rag/flow/parser/parser.py b/rag/flow/parser/parser.py index e08629f3d..004d4bc91 100644 --- a/rag/flow/parser/parser.py +++ b/rag/flow/parser/parser.py @@ -404,8 +404,8 @@ class Parser(ProcessBase): _add_content(msg, msg.get_content_type()) - email_content["text"] = body_text - email_content["text_html"] = body_html + email_content["text"] = "\n".join(body_text) + email_content["text_html"] = "\n".join(body_html) # get attachment if "attachments" in target_fields: attachments = [] diff --git a/sdk/python/ragflow_sdk/modules/session.py b/sdk/python/ragflow_sdk/modules/session.py index d534c782b..899a48fa9 100644 --- a/sdk/python/ragflow_sdk/modules/session.py +++ b/sdk/python/ragflow_sdk/modules/session.py @@ -33,35 +33,52 @@ class Session(Base): self.__session_type = "agent" super().__init__(rag, res_dict) - def ask(self, question="", stream=True, **kwargs): + + def ask(self, question="", stream=False, **kwargs): + """ + Ask a question to the session. If stream=True, yields Message objects as they arrive (SSE streaming). + If stream=False, returns a single Message object for the final answer. + """ if self.__session_type == "agent": res = self._ask_agent(question, stream) elif self.__session_type == "chat": res = self._ask_chat(question, stream, **kwargs) + else: + raise Exception(f"Unknown session type: {self.__session_type}") if stream: - for line in res.iter_lines(): - line = line.decode("utf-8") - if line.startswith("{"): - json_data = json.loads(line) - raise Exception(json_data["message"]) - if not line.startswith("data:"): - continue - json_data = json.loads(line[5:]) - if json_data["data"] is True or json_data["data"].get("running_status"): - continue - message = self._structure_answer(json_data) - yield message + for line in res.iter_lines(decode_unicode=True): + if not line: + continue # Skip empty lines + line = line.strip() + + if line.startswith("data:"): + content = line[len("data:"):].strip() + if content == "[DONE]": + break # End of stream + else: + content = line + + try: + json_data = json.loads(content) + except json.JSONDecodeError: + continue # Skip lines that are not valid JSON + + event = json_data.get("event") + if event == "message": + yield self._structure_answer(json_data) + elif event == "message_end": + return # End of message stream else: try: - json_data = json.loads(res.text) + json_data = res.json() except ValueError: raise Exception(f"Invalid response {res}") - return self._structure_answer(json_data) + yield self._structure_answer(json_data["data"]) def _structure_answer(self, json_data): - answer = json_data["data"]["answer"] + answer = json_data["data"]["content"] reference = json_data["data"].get("reference", {}) temp_dict = { "content": answer,