diff --git a/backend/app/agent_subgraphs/common/__init__.py b/backend/app/agent_subgraphs/common/__init__.py index 37a83b9..f1dd6e3 100644 --- a/backend/app/agent_subgraphs/common/__init__.py +++ b/backend/app/agent_subgraphs/common/__init__.py @@ -3,10 +3,10 @@ 提供可复用的基础组件 导出: -- formatter: 格式化输出工具 -- intent: 意图理解工具 -- human_review: 人工审核工具 -- state_base: 状态基类工具 +- formatter.py: 格式化输出工具 +- intent.py: 意图理解工具 +- human_review.py: 人工审核工具 +- state_base.py: 状态基类工具 """ from .formatter import ( diff --git a/backend/app/agent_subgraphs/contact/api_client.py b/backend/app/agent_subgraphs/contact/api_client.py index cce155f..4dbaef0 100644 --- a/backend/app/agent_subgraphs/contact/api_client.py +++ b/backend/app/agent_subgraphs/contact/api_client.py @@ -192,6 +192,45 @@ class ContactAPIClient: "suggestion": "是否添加这些联系人?" } + # 公共方法 + def list_contacts(self, user_id: str = "default") -> List[Contact]: + """查询联系人列表""" + return self.list_contacts_mock(user_id) + + def add_contact(self, user_id: str, contact: Contact) -> bool: + """添加联系人""" + return self.save_contact_mock(user_id, contact) + + def list_emails(self, user_id: str = "default") -> List[Email]: + """查询邮件列表""" + return self.list_emails_mock() + + def generate_email_draft(self, query: str) -> Dict[str, str]: + """生成邮件草稿""" + return self.generate_email_draft_mock(query) + + def send_email(self, user_id: str, recipient: str, subject: str, body: str) -> bool: + """发送邮件""" + result = self.send_email_mock(recipient, subject, body) + return result.get("success", False) + + def sniff_contacts(self, query: str) -> List[Contact]: + """智能嗅探联系人""" + result = self.sniff_contacts_mock(query) + contact_dicts = result.get("contacts", []) + return [ + Contact( + id=str(i+1), + name=c.get("name", ""), + phone=c.get("phone", ""), + email=c.get("email", ""), + company="", + position="", + created_at=datetime.now().isoformat() + ) + for i, c in enumerate(contact_dicts) + ] + # 单例实例 contact_api = ContactAPIClient() diff --git a/backend/app/agent_subgraphs/contact/nodes.py b/backend/app/agent_subgraphs/contact/nodes.py index 718ca2f..571fb44 100644 --- a/backend/app/agent_subgraphs/contact/nodes.py +++ b/backend/app/agent_subgraphs/contact/nodes.py @@ -172,5 +172,59 @@ def format_result(state: ContactState) -> ContactState: state.final_result = "\n".join(output_lines) state.success = True state.current_phase = "completed" - + return state + + +def human_review(state: ContactState) -> ContactState: + """ + 人工审核节点(用于邮件草稿) + """ + state.current_phase = "reviewing" + # 标记需要审核,等待用户决定 + state.needs_approval = True + return state + + +def send_email(state: ContactState) -> ContactState: + """ + 发送邮件节点 + """ + state.current_phase = "executing" + # 使用 API 客户端发送邮件 + success = contact_api.send_email( + state.user_id, + state.draft_recipient, + state.draft_subject, + state.draft_body + ) + state.success = success + return state + + +def should_continue(state: ContactState) -> str: + """ + 条件路由函数:根据 action 和状态决定下一个节点 + """ + # 如果是从 human_review 来的,根据审核状态决定 + if state.current_phase == "reviewing": + if state.needs_approval: + # 这里会等待用户操作,实际运行时通过 checkpointer 或后端 API 处理 + return "format_result" + else: + return "send_email" + + # 普通路由 + action = state.action + if action == ContactAction.CONTACT_LIST: + return "list_contacts" + elif action == ContactAction.CONTACT_ADD: + return "add_contact" + elif action == ContactAction.EMAIL_LIST: + return "list_emails" + elif action == ContactAction.EMAIL_SEND: + return "generate_email_draft" + elif action == ContactAction.SNIFF_CONTACTS: + return "sniff_contacts" + else: + return "format_result" diff --git a/backend/app/agent_subgraphs/dictionary/nodes.py b/backend/app/agent_subgraphs/dictionary/nodes.py index 0e4dfc4..f804a38 100644 --- a/backend/app/agent_subgraphs/dictionary/nodes.py +++ b/backend/app/agent_subgraphs/dictionary/nodes.py @@ -250,5 +250,28 @@ def format_result(state: DictionaryState) -> DictionaryState: state.final_result = "\n".join(output_lines) state.success = True state.current_phase = "completed" + + return state + + +def should_continue(state: DictionaryState) -> str: + """ + 条件路由函数:根据 action 决定下一个节点 + """ + action = state.action + if action == DictionaryAction.QUERY: + return "query_word" + elif action == DictionaryAction.TRANSLATE: + return "translate_text" + elif action == DictionaryAction.EXTRACT: + return "extract_terms" + elif action == DictionaryAction.DAILY_WORD: + return "get_daily_word" + elif action == DictionaryAction.LOOKUP_WORD_BOOK: + return "lookup_word_book" + elif action == DictionaryAction.ADD_TO_WORD_BOOK: + return "add_to_word_book" + else: + return "format_result" return state diff --git a/backend/app/agent_subgraphs/news_analysis/nodes.py b/backend/app/agent_subgraphs/news_analysis/nodes.py index dafa849..bd8e9d9 100644 --- a/backend/app/agent_subgraphs/news_analysis/nodes.py +++ b/backend/app/agent_subgraphs/news_analysis/nodes.py @@ -164,5 +164,22 @@ def format_result(state: NewsAnalysisState) -> NewsAnalysisState: state.final_result = "\n".join(output_lines) state.success = True state.current_phase = "completed" - + return state + + +def should_continue(state: NewsAnalysisState) -> str: + """ + 条件路由函数:根据 action 决定下一个节点 + """ + action = state.action + if action == NewsAction.QUERY: + return "query_news" + elif action == NewsAction.ANALYZE_URL: + return "analyze_url" + elif action == NewsAction.EXTRACT_KEYWORDS: + return "extract_keywords" + elif action == NewsAction.GENERATE_REPORT: + return "generate_report" + else: + return "format_result"