diff --git a/agent/README.md b/agent/README.md deleted file mode 100644 index 250149b84..000000000 --- a/agent/README.md +++ /dev/null @@ -1,45 +0,0 @@ -English | [简体中文](./README_zh.md) - -# *Graph* - - -## Introduction - -*Graph* is a mathematical concept which is composed of nodes and edges. -It is used to compose a complex work flow or agent. -And this graph is beyond the DAG that we can use circles to describe our agent or work flow. -Under this folder, we propose a test tool ./test/client.py which can test the DSLs such as json files in folder ./test/dsl_examples. -Please use this client at the same folder you start RAGFlow. If it's run by Docker, please go into the container before running the client. -Otherwise, correct configurations in service_conf.yaml is essential. - -```bash -PYTHONPATH=path/to/ragflow python graph/test/client.py -h -usage: client.py [-h] -s DSL -t TENANT_ID -m - -options: - -h, --help show this help message and exit - -s DSL, --dsl DSL input dsl - -t TENANT_ID, --tenant_id TENANT_ID - Tenant ID - -m, --stream Stream output -``` -
- -
- - -## How to gain a TENANT_ID in command line? -
- -
-💡 We plan to display it here in the near future. -
- -
- - -## How to set 'kb_ids' for component 'Retrieval' in DSL? -
- -
- diff --git a/agent/README_zh.md b/agent/README_zh.md deleted file mode 100644 index 411e31e2b..000000000 --- a/agent/README_zh.md +++ /dev/null @@ -1,46 +0,0 @@ -[English](./README.md) | 简体中文 - -# *Graph* - - -## 简介 - -"Graph"是一个由节点和边组成的数学概念。 -它被用来构建复杂的工作流或代理。 -这个图超越了有向无环图(DAG),我们可以使用循环来描述我们的代理或工作流。 -在这个文件夹下,我们提出了一个测试工具 ./test/client.py, -它可以测试像文件夹./test/dsl_examples下一样的DSL文件。 -请在启动 RAGFlow 的同一文件夹中使用此客户端。如果它是通过 Docker 运行的,请在运行客户端之前进入容器。 -否则,正确配置 service_conf.yaml 文件是必不可少的。 - -```bash -PYTHONPATH=path/to/ragflow python graph/test/client.py -h -usage: client.py [-h] -s DSL -t TENANT_ID -m - -options: - -h, --help show this help message and exit - -s DSL, --dsl DSL input dsl - -t TENANT_ID, --tenant_id TENANT_ID - Tenant ID - -m, --stream Stream output -``` -
- -
- - -## 命令行中的TENANT_ID如何获得? -
- -
-💡 后面会展示在这里: -
- -
- - -## DSL里面的Retrieval组件的kb_ids怎么填? -
- -
- diff --git a/agent/canvas.py b/agent/canvas.py index 36da7a403..75f736f62 100644 --- a/agent/canvas.py +++ b/agent/canvas.py @@ -272,6 +272,7 @@ class Canvas: "component_id": self.path[i], "component_name": self.get_component_name(self.path[i]), "component_type": self.get_component_type(self.path[i]), + "thoughts": self.get_component_thoughts(self.path[i]) }) _run_batch(idx, to) @@ -523,3 +524,6 @@ class Canvas: def get_memory(self) -> list[Tuple]: return self.memory + def get_component_thoughts(self, cpn_id) -> str: + return self.components.get(cpn_id)["obj"].thoughts() + diff --git a/agent/component/__init__.py b/agent/component/__init__.py index 45dc5f694..9de7ff453 100644 --- a/agent/component/__init__.py +++ b/agent/component/__init__.py @@ -48,10 +48,10 @@ __all__ = list(__all_classes.keys()) + ["__all_classes"] del _package_path, _import_submodules, _extract_classes_from_module + def component_class(class_name): m = importlib.import_module("agent.component") try: return getattr(m, class_name) except Exception: return getattr(importlib.import_module("agent.tools"), class_name) - diff --git a/agent/component/agent_with_tools.py b/agent/component/agent_with_tools.py index 119f51206..d4efc73ce 100644 --- a/agent/component/agent_with_tools.py +++ b/agent/component/agent_with_tools.py @@ -23,7 +23,6 @@ from typing import Any import json_repair -from agent.component.llm import LLMParam, LLM from agent.tools.base import LLMToolPluginCallSession, ToolParamBase, ToolBase, ToolMeta from api.db.services.llm_service import LLMBundle, TenantLLMService from api.db.services.mcp_server_service import MCPServerService @@ -32,6 +31,7 @@ from rag.prompts import message_fit_in from rag.prompts.prompts import next_step, COMPLETE_TASK, analyze_task, \ citation_prompt, reflect, rank_memories, kb_prompt, citation_plus, full_question from rag.utils.mcp_tool_call_conn import MCPToolCallSession, mcp_tool_metadata_to_openai_tool +from agent.component.llm import LLMParam, LLM class AgentParam(LLMParam, ToolParamBase): @@ -330,3 +330,4 @@ Respond immediately with your final comprehensive answer. logging.exception(e) return "Error occurred." + diff --git a/agent/component/base.py b/agent/component/base.py index c36b747bb..dba14a3de 100644 --- a/agent/component/base.py +++ b/agent/component/base.py @@ -13,9 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. # + import re import time -from abc import ABC +from abc import ABC, abstractmethod import builtins import json import os @@ -535,3 +536,6 @@ class ComponentBase(ABC): def get_exception_default_value(self): return self._param.exception_default_value + @abstractmethod + def thoughts(self) -> str: + ... diff --git a/agent/component/begin.py b/agent/component/begin.py index 34fbbd2d2..6a997d400 100644 --- a/agent/component/begin.py +++ b/agent/component/begin.py @@ -44,3 +44,6 @@ class Begin(UserFillUp): v = v.get("value") self.set_output(k, v) self.set_input_value(k, v) + + def thoughts(self) -> str: + return "☕ Here we go..." diff --git a/agent/component/categorize.py b/agent/component/categorize.py index 4e79c81f2..d25518d09 100644 --- a/agent/component/categorize.py +++ b/agent/component/categorize.py @@ -20,7 +20,7 @@ from abc import ABC from api.db import LLMType from api.db.services.llm_service import LLMBundle -from agent.component import LLMParam, LLM +from agent.component.llm import LLMParam, LLM from api.utils.api_utils import timeout from rag.llm.chat_model import ERROR_PREFIX @@ -133,3 +133,5 @@ class Categorize(LLM, ABC): self.set_output("category_name", max_category) self.set_output("_next", cpn_ids) + def thoughts(self) -> str: + return "Which should it falls into {}? ...".format(",".join([f"`{c}`" for c, _ in self._param.category_description.items()])) \ No newline at end of file diff --git a/agent/component/fillup.py b/agent/component/fillup.py index d39cfa2f6..5b57bed80 100644 --- a/agent/component/fillup.py +++ b/agent/component/fillup.py @@ -34,6 +34,7 @@ class UserFillUp(ComponentBase): for k, v in kwargs.get("inputs", {}).items(): self.set_output(k, v) - + def thoughts(self) -> str: + return "Waiting for your input..." diff --git a/agent/component/invoke.py b/agent/component/invoke.py index 0a535c9d9..a4aa98191 100644 --- a/agent/component/invoke.py +++ b/agent/component/invoke.py @@ -137,3 +137,6 @@ class Invoke(ComponentBase, ABC): return f"Http request error: {last_e}" assert False, self.output() + + def thoughts(self) -> str: + return "Waiting for the server respond..." \ No newline at end of file diff --git a/agent/component/iteration.py b/agent/component/iteration.py index a65735cc7..460969d7e 100644 --- a/agent/component/iteration.py +++ b/agent/component/iteration.py @@ -53,6 +53,8 @@ class Iteration(ComponentBase, ABC): if not isinstance(arr, list): self.set_output("_ERROR", self._param.items_ref + " must be an array, but its type is "+str(type(arr))) + def thoughts(self) -> str: + return "Need to process {} items.".format(len(self._canvas.get_variable_value(self._param.items_ref))) diff --git a/agent/component/iterationitem.py b/agent/component/iterationitem.py index 20187e0ef..6c4d0bae7 100644 --- a/agent/component/iterationitem.py +++ b/agent/component/iterationitem.py @@ -79,3 +79,5 @@ class IterationItem(ComponentBase, ABC): def end(self): return self._idx == -1 + def thoughts(self) -> str: + return "Next turn..." \ No newline at end of file diff --git a/agent/component/llm.py b/agent/component/llm.py index 7418d9006..fb9a4c85c 100644 --- a/agent/component/llm.py +++ b/agent/component/llm.py @@ -240,3 +240,7 @@ class LLM(ComponentBase): summ = tool_call_summary(self.chat_mdl, func_name, params, results) logging.info(f"[MEMORY]: {summ}") self._canvas.add_memory(user, assist, summ) + + def thoughts(self) -> str: + _, msg = self._prepare_prompt_variables() + return f"I’m thinking and planning the next move, starting from the prompt:
“{msg[-1]['content']}” (tap to see full text)" \ No newline at end of file diff --git a/agent/component/message.py b/agent/component/message.py index e0ab9d578..b836e3cc4 100644 --- a/agent/component/message.py +++ b/agent/component/message.py @@ -142,3 +142,5 @@ class Message(ComponentBase): self.set_output("content", content) + def thoughts(self) -> str: + return "Thinking ..." diff --git a/agent/component/string_transform.py b/agent/component/string_transform.py index 5c445aeb0..06ab7bf21 100644 --- a/agent/component/string_transform.py +++ b/agent/component/string_transform.py @@ -94,5 +94,7 @@ class StringTransform(Message, ABC): self.set_output("result", script) + def thoughts(self) -> str: + return f"It's {self._param.method}ing." diff --git a/agent/component/switch.py b/agent/component/switch.py index c0533a66c..99685e9a7 100644 --- a/agent/component/switch.py +++ b/agent/component/switch.py @@ -125,4 +125,7 @@ class Switch(ComponentBase, ABC): except Exception: return True if input <= value else False - raise ValueError('Not supported operator' + operator) \ No newline at end of file + raise ValueError('Not supported operator' + operator) + + def thoughts(self) -> str: + return "I’m weighing a few options and will pick the next step shortly." \ No newline at end of file diff --git a/agent/tools/__init__.py b/agent/tools/__init__.py index dcce4f448..e002614c8 100644 --- a/agent/tools/__init__.py +++ b/agent/tools/__init__.py @@ -1,3 +1,18 @@ +# +# Copyright 2025 The InfiniFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# import os import importlib import inspect diff --git a/agent/tools/arxiv.py b/agent/tools/arxiv.py index 08a3d1c66..be9715cc5 100644 --- a/agent/tools/arxiv.py +++ b/agent/tools/arxiv.py @@ -94,3 +94,9 @@ class ArXiv(ToolBase, ABC): return f"ArXiv error: {last_e}" assert False, self.output() + + def thoughts(self) -> str: + return """ +Keywords: {} +Looking for the most relevant articles. + """.format(self.get_input().get("query", "-_-!")) \ No newline at end of file diff --git a/agent/tools/base.py b/agent/tools/base.py index 5db9cf573..0c1823c59 100644 --- a/agent/tools/base.py +++ b/agent/tools/base.py @@ -165,3 +165,6 @@ class ToolBase(ComponentBase): }) self._canvas.add_refernce(chunks, aggs) self.set_output("formalized_content", "\n".join(kb_prompt({"chunks": chunks, "doc_aggs": aggs}, 200000, True))) + + def thoughts(self) -> str: + return self._canvas.get_component_name(self._id) + " is running..." \ No newline at end of file diff --git a/agent/tools/code_exec.py b/agent/tools/code_exec.py index 191ca320e..1c5cae24d 100644 --- a/agent/tools/code_exec.py +++ b/agent/tools/code_exec.py @@ -189,4 +189,5 @@ class CodeExec(ToolBase, ABC): def _encode_code(self, code: str) -> str: return base64.b64encode(code.encode("utf-8")).decode("utf-8") - + def thoughts(self) -> str: + return "Running a short script to process data." diff --git a/agent/tools/duckduckgo.py b/agent/tools/duckduckgo.py index da903c069..34c2e66ec 100644 --- a/agent/tools/duckduckgo.py +++ b/agent/tools/duckduckgo.py @@ -112,3 +112,9 @@ class DuckDuckGo(ToolBase, ABC): return f"DuckDuckGo error: {last_e}" assert False, self.output() + + def thoughts(self) -> str: + return """ +Keywords: {} +Looking for the most relevant articles. + """.format(self.get_input().get("query", "-_-!")) \ No newline at end of file diff --git a/agent/tools/email.py b/agent/tools/email.py index 89a3113c3..e9f6eaed8 100644 --- a/agent/tools/email.py +++ b/agent/tools/email.py @@ -204,4 +204,12 @@ class Email(ToolBase, ABC): self.set_output("_ERROR", str(last_e)) return False - assert False, self.output() \ No newline at end of file + assert False, self.output() + + def thoughts(self) -> str: + inputs = self.get_input() + return """ +To: {} +Subject: {} +Your email is on its way—sit tight! +""".format(inputs.get("to_email", "-_-!"), inputs.get("subject", "-_-!")) \ No newline at end of file diff --git a/agent/tools/exesql.py b/agent/tools/exesql.py index 087abcc1d..63cd3d0be 100644 --- a/agent/tools/exesql.py +++ b/agent/tools/exesql.py @@ -128,6 +128,5 @@ class ExeSQL(ToolBase, ABC): self.set_output("formalized_content", "\n\n".join(formalized_content)) return self.output("formalized_content") - - def debug(self, **kwargs): - return self._run([], **kwargs) + def thoughts(self) -> str: + return "Query sent—waiting for the data." \ No newline at end of file diff --git a/agent/tools/github.py b/agent/tools/github.py index 385b88b02..d19a434b6 100644 --- a/agent/tools/github.py +++ b/agent/tools/github.py @@ -86,3 +86,6 @@ class GitHub(ToolBase, ABC): return f"GitHub error: {last_e}" assert False, self.output() + + def thoughts(self) -> str: + return "Scanning GitHub repos related to `{}`.".format(self.get_input().get("query", "-_-!")) \ No newline at end of file diff --git a/agent/tools/google.py b/agent/tools/google.py index 1d1bd86f7..f68b51f91 100644 --- a/agent/tools/google.py +++ b/agent/tools/google.py @@ -152,3 +152,8 @@ class Google(ToolBase, ABC): assert False, self.output() + def thoughts(self) -> str: + return """ +Keywords: {} +Looking for the most relevant articles. + """.format(self.get_input().get("query", "-_-!")) \ No newline at end of file diff --git a/agent/tools/googlescholar.py b/agent/tools/googlescholar.py index d26a68a9c..cfc32d63e 100644 --- a/agent/tools/googlescholar.py +++ b/agent/tools/googlescholar.py @@ -91,3 +91,6 @@ class GoogleScholar(ToolBase, ABC): return f"GoogleScholar error: {last_e}" assert False, self.output() + + def thoughts(self) -> str: + return "Looking for scholarly papers on `{}`,” prioritising reputable sources.".format(self.get_input().get("query", "-_-!")) \ No newline at end of file diff --git a/agent/tools/pubmed.py b/agent/tools/pubmed.py index 8af7c1435..c939b2fab 100644 --- a/agent/tools/pubmed.py +++ b/agent/tools/pubmed.py @@ -103,3 +103,6 @@ class PubMed(ToolBase, ABC): return f"PubMed error: {last_e}" assert False, self.output() + + def thoughts(self) -> str: + return "Looking for scholarly papers on `{}`,” prioritising reputable sources.".format(self.get_input().get("query", "-_-!")) \ No newline at end of file diff --git a/agent/tools/retrieval.py b/agent/tools/retrieval.py index d25061f60..cffbc75ea 100644 --- a/agent/tools/retrieval.py +++ b/agent/tools/retrieval.py @@ -159,3 +159,9 @@ class Retrieval(ToolBase, ABC): form_cnt = "\n".join(kb_prompt(kbinfos, 200000, True)) self.set_output("formalized_content", form_cnt) return form_cnt + + def thoughts(self) -> str: + return """ +Keywords: {} +Looking for the most relevant articles. + """.format(self.get_input().get("query", "-_-!")) \ No newline at end of file diff --git a/agent/tools/tavily.py b/agent/tools/tavily.py index 8072d3eb3..fa9a266ab 100644 --- a/agent/tools/tavily.py +++ b/agent/tools/tavily.py @@ -134,6 +134,12 @@ class TavilySearch(ToolBase, ABC): assert False, self.output() + def thoughts(self) -> str: + return """ +Keywords: {} +Looking for the most relevant articles. + """.format(self.get_input().get("query", "-_-!")) + class TavilyExtractParam(ToolParamBase): """ @@ -216,3 +222,6 @@ class TavilyExtract(ToolBase, ABC): return f"Tavily error: {last_e}" assert False, self.output() + + def thoughts(self) -> str: + return "Opened {}—pulling out the main text…".format(self.get_input().get("urls", "-_-!")) \ No newline at end of file diff --git a/agent/tools/wencai.py b/agent/tools/wencai.py index b751b92d9..66213a08b 100644 --- a/agent/tools/wencai.py +++ b/agent/tools/wencai.py @@ -109,3 +109,6 @@ class WenCai(ToolBase, ABC): return f"WenCai error: {last_e}" assert False, self.output() + + def thoughts(self) -> str: + return "Pulling live financial data for `{}`.".format(self.get_input().get("query", "-_-!")) \ No newline at end of file diff --git a/agent/tools/wikipedia.py b/agent/tools/wikipedia.py index d073fb7d8..93bb6cfc0 100644 --- a/agent/tools/wikipedia.py +++ b/agent/tools/wikipedia.py @@ -96,3 +96,9 @@ class Wikipedia(ToolBase, ABC): return f"Wikipedia error: {last_e}" assert False, self.output() + + def thoughts(self) -> str: + return """ +Keywords: {} +Looking for the most relevant articles. + """.format(self.get_input().get("query", "-_-!")) \ No newline at end of file diff --git a/agent/tools/yahoofinance.py b/agent/tools/yahoofinance.py index 2b70f9616..6e2dc0e62 100644 --- a/agent/tools/yahoofinance.py +++ b/agent/tools/yahoofinance.py @@ -109,3 +109,6 @@ class YahooFinance(ToolBase, ABC): return f"YahooFinance error: {last_e}" assert False, self.output() + + def thoughts(self) -> str: + return "Pulling live financial data for `{}`.".format(self.get_input().get("stock_code", "-_-!")) \ No newline at end of file