Update agent orchestration and knowledge flow

Add sub-commander orchestration updates, align frontend integrations, and refine knowledge view behavior without including local data artifacts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 21:44:04 +08:00
parent aafa05dc1c
commit 0d89325b09
14 changed files with 529 additions and 650 deletions

View File

@@ -11,8 +11,16 @@ from app.agents.prompts import (
EXECUTOR_SYSTEM_PROMPT,
LIBRARIAN_SYSTEM_PROMPT,
ANALYST_SYSTEM_PROMPT,
PLANNER_SCOPE_PROMPT,
PLANNER_STEPS_PROMPT,
EXECUTOR_TASKS_PROMPT,
EXECUTOR_FORUM_PROMPT,
LIBRARIAN_RETRIEVAL_PROMPT,
LIBRARIAN_GRAPH_PROMPT,
ANALYST_PROGRESS_PROMPT,
ANALYST_INSIGHTS_PROMPT,
)
from app.agents.tools import ALL_TOOLS
from app.agents.tools import ALL_TOOLS, SUB_COMMANDER_TOOLSETS
from app.agents.skill_registry import build_skill_context
from app.services.llm_service import get_llm
from langchain_openai import ChatOpenAI
@@ -21,6 +29,32 @@ from langchain_ollama import ChatOllama
import httpx
SUB_COMMANDER_PROMPTS = {
"planner_scope": PLANNER_SCOPE_PROMPT,
"planner_steps": PLANNER_STEPS_PROMPT,
"executor_tasks": EXECUTOR_TASKS_PROMPT,
"executor_forum": EXECUTOR_FORUM_PROMPT,
"librarian_retrieval": LIBRARIAN_RETRIEVAL_PROMPT,
"librarian_graph": LIBRARIAN_GRAPH_PROMPT,
"analyst_progress": ANALYST_PROGRESS_PROMPT,
"analyst_insights": ANALYST_INSIGHTS_PROMPT,
}
ROLE_SUB_COMMANDERS = {
AgentRole.PLANNER: ["planner_scope", "planner_steps"],
AgentRole.EXECUTOR: ["executor_tasks", "executor_forum"],
AgentRole.LIBRARIAN: ["librarian_retrieval", "librarian_graph"],
AgentRole.ANALYST: ["analyst_progress", "analyst_insights"],
}
ROLE_SKILL_CONTEXT = {
AgentRole.PLANNER: "planner",
AgentRole.EXECUTOR: "executor",
AgentRole.LIBRARIAN: "librarian",
AgentRole.ANALYST: "analyst",
}
def _create_llm_from_config(config: dict):
"""根据用户模型配置创建 LLM 实例"""
provider = config.get("provider", "openai")
@@ -71,8 +105,9 @@ async def _ainvoke(llm, messages: list[BaseMessage]):
return await llm.invoke(messages)
async def _ainvoke_with_tools(llm, messages: list[BaseMessage]):
bound_llm = llm.bind_tools(ALL_TOOLS)
async def _ainvoke_with_tools(llm, messages: list[BaseMessage], tools=None):
toolset = tools if tools is not None else ALL_TOOLS
bound_llm = llm.bind_tools(toolset)
if hasattr(bound_llm, "ainvoke"):
return await bound_llm.ainvoke(messages)
return await bound_llm.invoke(messages)
@@ -116,6 +151,113 @@ def _is_capability_question(text: str) -> bool:
return normalized in {"你能做什么", "你可以做什么", "你会做什么"}
def _choose_sub_commander(role: AgentRole, user_query: str) -> str:
text = _normalize_user_text(user_query)
if role == AgentRole.PLANNER:
if any(keyword in text for keyword in ["步骤", "计划", "拆解", "排期", "优先级", "路线"]):
return "planner_steps"
return "planner_scope"
if role == AgentRole.EXECUTOR:
if any(keyword in text for keyword in ["论坛", "帖子", "发帖", "指令", "discussion", "instruction"]):
return "executor_forum"
return "executor_tasks"
if role == AgentRole.LIBRARIAN:
if any(keyword in text for keyword in ["图谱", "关系", "构建", "沉淀", "节点", "graph"]):
return "librarian_graph"
return "librarian_retrieval"
if role == AgentRole.ANALYST:
if any(keyword in text for keyword in ["趋势", "风险", "洞察", "建议", "机会", "insight"]):
return "analyst_insights"
return "analyst_progress"
return ROLE_SUB_COMMANDERS[role][0]
def _record_sub_commander(state: AgentState, sub_commander: str, user_query: str):
state["current_sub_commander"] = sub_commander
state["active_sub_commanders"] = state.get("active_sub_commanders", []) + [sub_commander]
state["sub_commander_trace"] = state.get("sub_commander_trace", []) + [{
"agent": state.get("current_agent", AgentRole.MASTER).value,
"sub_commander": sub_commander,
"query": user_query,
}]
def _build_system_messages(state: AgentState, system_prompt: str, role: AgentRole):
system_msgs: list[BaseMessage] = [SystemMessage(content=system_prompt)]
skill_ctx = build_skill_context(ROLE_SKILL_CONTEXT[role])
if skill_ctx:
system_msgs.append(SystemMessage(content=skill_ctx))
return system_msgs
async def _run_sub_commander(
state: AgentState,
role: AgentRole,
manager_prompt: str,
user_query: str,
*,
use_tools: bool,
summary_target: str | None = None,
):
llm = _get_llm_for_state(state)
sub_commander = _choose_sub_commander(role, user_query)
_record_sub_commander(state, sub_commander, user_query)
toolset = SUB_COMMANDER_TOOLSETS.get(sub_commander, [])
system_msgs = _build_system_messages(state, manager_prompt, role)
system_msgs.append(SystemMessage(content=f"本次应由子指挥官 `{sub_commander}` 接手。请严格按该角色职责输出。"))
system_msgs.append(SystemMessage(content=SUB_COMMANDER_PROMPTS[sub_commander]))
if use_tools and toolset:
response = await _ainvoke_with_tools(
llm,
system_msgs + [HumanMessage(content=f"用户请求: {user_query}")],
toolset,
)
tool_calls = getattr(response, "tool_calls", None) or []
if tool_calls:
results = []
for tc in tool_calls:
tool_name = tc.get("name")
args = tc.get("args", {})
for tool in toolset:
if tool.name == tool_name:
try:
result = tool.invoke(args)
results.append(f"[{tool_name}] {result}")
except Exception as e:
results.append(f"[{tool_name}] 执行失败: {e}")
break
state["tool_calls"] = tool_calls
state["last_tool_result"] = "\n".join(results)
follow_up = await _ainvoke(
llm,
[
SystemMessage(content=SUB_COMMANDER_PROMPTS[sub_commander]),
HumanMessage(content=f"工具执行结果:\n{state['last_tool_result']}")
]
)
state["final_response"] = follow_up.content
else:
state["final_response"] = response.content
else:
response = await _ainvoke(
llm,
system_msgs + [HumanMessage(content=f"用户请求: {user_query}")],
)
state["final_response"] = response.content
if summary_target:
state[summary_target] = state.get("final_response", "")
state["should_respond"] = True
return state
# ===================== 节点定义 (async) =====================
async def master_node(state: AgentState) -> AgentState:
@@ -142,14 +284,13 @@ async def master_node(state: AgentState) -> AgentState:
llm = _get_llm_for_state(state)
system_msgs: list[BaseMessage] = [SystemMessage(content=MASTER_SYSTEM_PROMPT)]
# 注入记忆上下文
memory_ctx = state.get("memory_context")
if memory_ctx:
system_msgs.append(
SystemMessage(content=f"\n\n【记忆上下文】\n{memory_ctx}\n\n---\n")
)
response: AIMessage = await _ainvoke(llm,system_msgs + messages)
response: AIMessage = await _ainvoke(llm, system_msgs + messages)
content = response.content.strip().lower()
if any(kw in content for kw in ["搜索", "查找", "知识", "检索"]):
@@ -166,6 +307,7 @@ async def master_node(state: AgentState) -> AgentState:
return state
state["current_agent"] = next_agent
state["current_sub_commander"] = None
state["active_agents"] = state.get("active_agents", [AgentRole.MASTER]) + [next_agent]
state["should_respond"] = True
return state
@@ -173,164 +315,30 @@ async def master_node(state: AgentState) -> AgentState:
async def planner_node(state: AgentState) -> AgentState:
"""规划Agent节点: 制定计划,拆解任务步骤"""
llm = _get_llm_for_state(state)
user_msgs = _filter_user_messages(state["messages"])
user_query = user_msgs[-1].content if user_msgs else ""
system_msgs = [SystemMessage(content=PLANNER_SYSTEM_PROMPT)]
skill_ctx = build_skill_context("planner")
if skill_ctx:
system_msgs.append(SystemMessage(content=skill_ctx))
response = await _ainvoke(llm,
system_msgs + [HumanMessage(content=f"用户请求: {user_query}")]
)
plan_text = response.content
steps = []
for i, line in enumerate(plan_text.split("\n")):
if line.strip() and (line[0].isdigit() or "- " in line):
steps.append({"step": i + 1, "description": line.strip()})
state["plan"] = plan_text
state["plan_steps"] = steps
state["final_response"] = plan_text
state["should_respond"] = True
return state
return await _run_sub_commander(state, AgentRole.PLANNER, PLANNER_SYSTEM_PROMPT, user_query, use_tools=False)
async def executor_node(state: AgentState) -> AgentState:
"""执行Agent节点: 调用工具执行具体任务"""
llm = _get_llm_for_state(state)
user_msgs = _filter_user_messages(state["messages"])
user_query = user_msgs[-1].content if user_msgs else ""
system_msgs = [SystemMessage(content=EXECUTOR_SYSTEM_PROMPT)]
skill_ctx = build_skill_context("executor")
if skill_ctx:
system_msgs.append(SystemMessage(content=skill_ctx))
response = await _ainvoke_with_tools(llm,
system_msgs + [HumanMessage(content=f"用户请求: {user_query}")]
)
tool_calls = getattr(response, "tool_calls", None) or []
if tool_calls:
results = []
for tc in tool_calls:
tool_name = tc.get("name")
args = tc.get("args", {})
for tool in ALL_TOOLS:
if tool.name == tool_name:
try:
result = tool.invoke(args)
results.append(f"[{tool_name}] {result}")
except Exception as e:
results.append(f"[{tool_name}] 执行失败: {e}")
break
state["tool_calls"] = tool_calls
state["last_tool_result"] = "\n".join(results)
follow_up = await _ainvoke(llm,
[SystemMessage(content=EXECUTOR_SYSTEM_PROMPT),
HumanMessage(content=f"工具执行结果:\n{state['last_tool_result']}")]
)
state["final_response"] = follow_up.content
else:
state["final_response"] = response.content
state["should_respond"] = True
return state
return await _run_sub_commander(state, AgentRole.EXECUTOR, EXECUTOR_SYSTEM_PROMPT, user_query, use_tools=True)
async def librarian_node(state: AgentState) -> AgentState:
"""知识管理员节点: 管理知识库和知识图谱"""
llm = _get_llm_for_state(state)
user_msgs = _filter_user_messages(state["messages"])
user_query = user_msgs[-1].content if user_msgs else ""
system_msgs = [SystemMessage(content=LIBRARIAN_SYSTEM_PROMPT)]
skill_ctx = build_skill_context("librarian")
if skill_ctx:
system_msgs.append(SystemMessage(content=skill_ctx))
response = await _ainvoke_with_tools(llm,
system_msgs + [HumanMessage(content=f"用户请求: {user_query}")]
)
tool_calls = getattr(response, "tool_calls", None) or []
if tool_calls:
results = []
for tc in tool_calls:
tool_name = tc.get("name")
args = tc.get("args", {})
for tool in ALL_TOOLS:
if tool.name == tool_name:
try:
result = tool.invoke(args)
results.append(f"[{tool_name}] {result}")
except Exception as e:
results.append(f"[{tool_name}] 执行失败: {e}")
break
state["tool_calls"] = tool_calls
state["last_tool_result"] = "\n".join(results)
follow_up = await _ainvoke(llm,
[SystemMessage(content=LIBRARIAN_SYSTEM_PROMPT),
HumanMessage(content=f"工具执行结果:\n{state['last_tool_result']}")]
)
state["final_response"] = follow_up.content
else:
state["final_response"] = response.content
state["knowledge_context"] = state.get("last_tool_result", "")
state["should_respond"] = True
return state
return await _run_sub_commander(state, AgentRole.LIBRARIAN, LIBRARIAN_SYSTEM_PROMPT, user_query, use_tools=True, summary_target="knowledge_context")
async def analyst_node(state: AgentState) -> AgentState:
"""分析师节点: 分析工作数据,生成报告"""
llm = _get_llm_for_state(state)
user_msgs = _filter_user_messages(state["messages"])
user_query = user_msgs[-1].content if user_msgs else ""
system_msgs = [SystemMessage(content=ANALYST_SYSTEM_PROMPT)]
skill_ctx = build_skill_context("analyst")
if skill_ctx:
system_msgs.append(SystemMessage(content=skill_ctx))
response = await _ainvoke_with_tools(llm,
system_msgs + [HumanMessage(content=f"用户请求: {user_query}")]
)
tool_calls = getattr(response, "tool_calls", None) or []
if tool_calls:
results = []
for tc in tool_calls:
tool_name = tc.get("name")
args = tc.get("args", {})
for tool in ALL_TOOLS:
if tool.name == tool_name:
try:
result = tool.invoke(args)
results.append(f"[{tool_name}] {result}")
except Exception as e:
results.append(f"[{tool_name}] 执行失败: {e}")
break
state["tool_calls"] = tool_calls
state["last_tool_result"] = "\n".join(results)
follow_up = await _ainvoke(llm,
[SystemMessage(content=ANALYST_SYSTEM_PROMPT),
HumanMessage(content=f"工具执行结果:\n{state['last_tool_result']}")]
)
state["final_response"] = follow_up.content
else:
state["final_response"] = response.content
state["analysis_report"] = state.get("final_response", "")
state["should_respond"] = True
return state
return await _run_sub_commander(state, AgentRole.ANALYST, ANALYST_SYSTEM_PROMPT, user_query, use_tools=True, summary_target="analysis_report")
def route_agent(state: AgentState) -> str:

View File

@@ -114,85 +114,46 @@ MASTER_SYSTEM_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
PLANNER_SYSTEM_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 Jarvis 的规划Agent负责制定计划、拆解任务
你是 Jarvis 的规划Agent负责先判断问题该由哪位规划子指挥官接手
## 你的能力:
- 分析复杂请求,拆解成可执行的步骤
- 评估任务优先级
- 判断哪些步骤依赖前置条件
- 制定清晰的执行顺序
## 你的两个子指挥官:
1. **planner_scope (目标收束官)**: 负责澄清目标、边界、约束、缺失信息
2. **planner_steps (步骤拆解官)**: 负责把目标拆成步骤、优先级与依赖关系
## 工作流程:
1. 理解用户的最终目标
2. 判断任务复杂度与关键约束
3. 拆解成具体步骤
4. 标注优先级或先后顺序
5. 给出清晰计划
## 响应要求:
- 用编号列表展示计划步骤
- 每步都要具体,避免空泛词汇
- 必要时可标注 P1/P2/P3 或“先做/后做”
- 如果任务确实复杂,可以轻微指出复杂点,但马上收束到行动方案
- 如果需要执行,先输出计划,再等待用户确认
## 你的职责:
- 判断当前请求更适合收束目标,还是拆解步骤
- 在必要时收束子指挥官输出,面向用户给出清晰结果
- 保持结果可推进,不空泛
"""
EXECUTOR_SYSTEM_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 Jarvis 的执行Agent负责执行具体任务
你是 Jarvis 的执行Agent负责先判断问题该由哪位执行子指挥官接手
## 你可以使用的工具:
- create_task: 创建新任务
- update_task_status: 更新任务状态
- get_tasks: 查看任务列表
- create_forum_post: 在论坛发布帖子
- get_forum_posts: 查看论坛帖子
- scan_forum_for_instructions: 扫描论坛指令
## 你的两个子指挥官:
1. **executor_tasks (任务执行官)**: 只处理任务类工具调用
2. **executor_forum (论坛执行官)**: 只处理论坛/指令帖相关工具调用
## 工作流程:
1. 理解用户要执行什么
2. 判断是否已具备足够信息
3. 调用相应工具
4. 汇总执行结果
5. 明确是否还需要下一步
## 响应要求:
- 明确说明已执行什么
- 工具结果要结构化、可读
- 成功时给出简洁确认
- 失败时说明卡点与下一步
- 如果信息不足,直接指出缺什么,不要假设
## 你的职责:
- 识别用户要推进的是任务操作还是论坛/指令操作
- 把请求交给最合适的执行子指挥官
- 汇总执行结果并给出下一步
"""
LIBRARIAN_SYSTEM_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 Jarvis 的知识管理员,负责管理用户的私人知识库
你是 Jarvis 的知识管理员,负责先判断问题该由哪位知识子指挥官接手
## 你可以使用的工具:
- search_knowledge: 搜索知识库,返回相关文档片段
- get_knowledge_graph_context: 获取知识图谱上下文
- build_knowledge_graph: 从文档构建知识图谱
## 你的两个子指挥官:
1. **librarian_retrieval (检索问答官)**: 负责知识检索与证据综合
2. **librarian_graph (图谱沉淀官)**: 负责图谱上下文、关系串联与结构化沉淀
## 你的职责:
1. 理解用户关于知识的问题
2. 搜索相关知识
3. 综合多篇文档给出完整回答
4. 帮助用户整理和理解知识
## 工作流程:
1. 分析用户问题的关键概念
2. 搜索相关文档与图谱关系
3. 综合证据形成答案
4. 在证据不足时明确说明边界
## 响应要求:
- 回答要有依据,不靠猜测
- 引用时标注来源或依据范围
- 如果知识不足,诚实说明
- 可以补充必要背景,但不要离题
- 风格保持冷静、清楚、可信
- 判断当前需求更适合检索问答还是图谱沉淀
- 让回答建立在证据和结构之上
- 必要时收束子指挥官输出,给出最终回答
"""
@@ -200,28 +161,141 @@ ANALYST_SYSTEM_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 Jarvis 的分析师,负责分析数据和工作状态。
## 你可以使用的工具:
- get_tasks: 获取任务列表,统计工作进度
- get_forum_posts: 获取论坛帖子,分析讨论趋势
- scan_forum_for_instructions: 检查待执行指令
- search_knowledge: 结合知识进行分析
## 你有两个子指挥官:
1. **analyst_progress (进度研判官)**: 汇总任务、论坛、指令执行状态,判断当前推进情况
2. **analyst_insights (洞察建议官)**: 提炼趋势、风险、机会点,并给出建议
## 你的职责:
1. 统计任务完成情况
2. 分析工作进度和趋势
3. 生成结构化报告
4. 识别潜在问题和风险
1. 判断当前问题更适合哪位子指挥官处理
2. 在需要时汇总子指挥官结果,给出面向用户的结论
3. 保持先结论后展开的表达方式
"""
## 工作流程:
1. 收集相关数据(任务、论坛、知识)
2. 识别模式、异常与趋势
3. 形成结论
4. 给出建议
PLANNER_SCOPE_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 planner 体系下的目标收束官,负责先把问题边界、目标、约束和成功标准说清楚。
## 你的重点:
- 收束问题定义
- 明确目标与限制条件
- 识别缺失信息
- 帮用户建立可以继续规划的前提
## 响应要求:
- 用数据说话,有数字、有结论
- 报告结构清晰,先结论后展开
- 明确风险、影响和建议
- 如果数据不完整,要说明分析置信度
- 可以有一丝冷幽默,但结论必须严谨
- 先给出你理解的目标
- 再列出关键约束或缺口
- 不要直接展开长步骤清单
"""
PLANNER_STEPS_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 planner 体系下的步骤拆解官,负责把目标转成有顺序的执行路径。
## 你的重点:
- 拆解步骤
- 标注优先级与依赖
- 输出清晰的行动顺序
## 响应要求:
- 用编号列表
- 每步具体,不要空泛
- 必要时标注先后关系
"""
EXECUTOR_TASKS_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 executor 体系下的任务执行官,只负责任务相关工具调用。
## 允许使用的工具:
- get_tasks
- create_task
- update_task_status
## 要求:
- 只处理任务类操作
- 明确已执行动作、结果与下一步
- 信息不足时直接指出缺口
"""
EXECUTOR_FORUM_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 executor 体系下的论坛执行官,只负责论坛与指令帖相关工具调用。
## 允许使用的工具:
- get_forum_posts
- create_forum_post
- scan_forum_for_instructions
## 要求:
- 只处理论坛/指令类操作
- 结果要清楚说明是否执行成功
- 不要越权调用任务或知识工具
"""
LIBRARIAN_RETRIEVAL_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 librarian 体系下的检索问答官,负责从知识库与上下文中快速找到可靠信息。
## 允许使用的工具:
- search_knowledge
- hybrid_search
- get_knowledge_graph_context
## 要求:
- 优先检索与综合证据
- 证据不足时明确说明边界
- 以回答问题为主,不主动做图谱构建
"""
LIBRARIAN_GRAPH_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 librarian 体系下的图谱沉淀官,负责知识关系整理、图谱上下文与结构化沉淀。
## 允许使用的工具:
- get_knowledge_graph_context
- build_knowledge_graph
## 要求:
- 聚焦知识结构、关系串联与沉淀
- 明确说明构建/更新结果
- 不把自己变成泛检索问答器
"""
ANALYST_PROGRESS_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 analyst 体系下的进度研判官,负责汇总当前任务、论坛与指令执行状态。
## 允许使用的工具:
- get_tasks
- get_forum_posts
- scan_forum_for_instructions
## 要求:
- 先结论后展开
- 重点说明进度、阻塞、待处理项
- 不做泛泛趋势空谈
"""
ANALYST_INSIGHTS_PROMPT = f"""{JARVIS_PERSONA_PROMPT}
你是 analyst 体系下的洞察建议官,负责从任务、论坛和知识线索里提炼趋势、风险与建议。
## 允许使用的工具:
- get_tasks
- get_forum_posts
- search_knowledge
- hybrid_search
## 要求:
- 先给结论与判断
- 再说明依据与建议
- 重点输出趋势、风险、机会点
"""

View File

@@ -55,6 +55,9 @@ class AgentState(TypedDict):
# Agent routing
current_agent: AgentRole
active_agents: list[AgentRole]
current_sub_commander: str | None
active_sub_commanders: list[str]
sub_commander_trace: list[dict]
# Task tracking
pending_tasks: list[dict]
@@ -93,6 +96,9 @@ def initial_state(user_id: str, conversation_id: str) -> AgentState:
conversation_id=conversation_id,
current_agent=AgentRole.MASTER,
active_agents=[AgentRole.MASTER],
current_sub_commander=None,
active_sub_commanders=[],
sub_commander_trace=[],
pending_tasks=[],
completed_tasks=[],
tool_calls=[],

View File

@@ -5,18 +5,56 @@ from app.agents.tools.search import (
from app.agents.tools.task import get_tasks, create_task, update_task_status
from app.agents.tools.forum import get_forum_posts, create_forum_post, scan_forum_for_instructions
ALL_TOOLS = [
# 知识库工具
search_knowledge,
get_knowledge_graph_context,
build_knowledge_graph,
hybrid_search,
# 任务工具
TASK_TOOLS = [
get_tasks,
create_task,
update_task_status,
# 论坛工具
]
FORUM_TOOLS = [
get_forum_posts,
create_forum_post,
scan_forum_for_instructions,
]
KNOWLEDGE_RETRIEVAL_TOOLS = [
search_knowledge,
hybrid_search,
get_knowledge_graph_context,
]
KNOWLEDGE_GRAPH_TOOLS = [
get_knowledge_graph_context,
build_knowledge_graph,
]
ANALYST_PROGRESS_TOOLS = [
get_tasks,
get_forum_posts,
scan_forum_for_instructions,
]
ANALYST_INSIGHT_TOOLS = [
get_tasks,
get_forum_posts,
search_knowledge,
hybrid_search,
]
ALL_TOOLS = [
*KNOWLEDGE_RETRIEVAL_TOOLS,
build_knowledge_graph,
*TASK_TOOLS,
*FORUM_TOOLS,
]
SUB_COMMANDER_TOOLSETS = {
"planner_scope": [],
"planner_steps": [],
"executor_tasks": TASK_TOOLS,
"executor_forum": FORUM_TOOLS,
"librarian_retrieval": KNOWLEDGE_RETRIEVAL_TOOLS,
"librarian_graph": KNOWLEDGE_GRAPH_TOOLS,
"analyst_progress": ANALYST_PROGRESS_TOOLS,
"analyst_insights": ANALYST_INSIGHT_TOOLS,
}