修复BrowserController的截图缓存问题和浏览器权柄配置丢失问题

This commit is contained in:
minorQAQ committed 2026-06-21 11:44:14 +08:00
1 parent d97e1581a4
commit d4ad95b853
142 files changed
+2385 -1142

No files matched your search

Binary file not shown.
Binary file not shown.
View File
Whitespace-only changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+21 -5
View File
@@ -2,18 +2,24 @@
系统定位:
对外导出各 Agent 的 ``AgentRuntime`` 单例及多 Agent 运行时。
所有 Agent 实例均从 ``agent_config.json`` 动态构建,不再 hardcoded。
Agent 列表:
- main_agent_runtime: 主 Agent 运行时(单 Agent 模式)。
- main_agent_runtime: 主 Agent 运行时(从配置中 role="main" 的 agent 动态创建)。
- reload_all_agent_runtimes: 重新加载配置并重建所有 Agent 运行时。
- build_multi_agent_runtime: 构建一主多子 Agent 运行时。
- get_agent_graph_snapshot: 获取多 Agent 图状态快照。
可扩展性:
子 Agent 实现后在此追加导出,如::
from agent.agents.research_agent import research_agent_runtime
__all__ = ["main_agent_runtime", "research_agent_runtime"]
新增 Agent 只需在 agent_config.json 中添加配置项,无需编写 .py 文件。
"""
from agent.agents.main_agent import main_agent_runtime, reload_main_agent_runtime
from agent.agents.agent import (
build_all_agent_runtimes,
get_main_agent_runtime,
get_all_agent_runtimes,
get_agent_runtime,
reload_all_agent_runtimes,
)
from agent.agents.multi_agent_runtime import (
MultiAgentRuntime,
SubAgentConfig,
@@ -21,9 +27,19 @@ from agent.agents.multi_agent_runtime import (
get_agent_graph_snapshot,
)
# 首次导入时从配置构建,并暴露为模块级属性(向后兼容旧导入路径)
_built = build_all_agent_runtimes()
main_agent_runtime = get_main_agent_runtime()
reload_main_agent_runtime = reload_all_agent_runtimes # 向后兼容别名
__all__ = [
"main_agent_runtime",
"reload_main_agent_runtime",
"reload_all_agent_runtimes",
"build_all_agent_runtimes",
"get_main_agent_runtime",
"get_all_agent_runtimes",
"get_agent_runtime",
"MultiAgentRuntime",
"SubAgentConfig",
"build_multi_agent_runtime",
Binary file not shown.
+193
View File
@@ -0,0 +1,193 @@
"""动态 Agent 工厂:根据 agent_config.json 全动态创建 AgentRuntime。
系统定位:
替代原有的 hardcoded main_agent / code_agent / research_agent 等单文件,
实现从配置文件全动态加载 Agent 实例。所有 Agent 的运行参数(图类型、
模型、工具集、系统提示词、最大迭代次数)均由 agent_config.json 驱动。
使用方式:
from agent.agents.agent import get_main_agent_runtime, reload_all_agent_runtimes
runtime = get_main_agent_runtime()
"""
from __future__ import annotations
from agent.core.config_manager import load_agent_configs, load_models, AgentConfig
from agent.core.graph import build_graph_by_name
from agent.core.runtime import AgentRuntime
from agent.tools import get_tools
# ---------- 缓存 ----------
_all_agent_runtimes: dict[str, AgentRuntime] = {}
_main_agent_name: str = "main"
def _build_llm_for_agent(cfg: AgentConfig):
"""根据 Agent 配置中指定的 llm_model_id 构建 LLM 实例。
从 env_config.json 的 models 列表中查找匹配的模型配置,
用其参数构造 ChatQwen 实例。若未找到匹配模型则回退到环境变量默认值。
"""
from agent.core.llm import ChatQwen
models = load_models()
model_config = None
for m in models:
if m.get("id") == cfg.llm_model_id:
model_config = m
break
if model_config:
return ChatQwen(
model=model_config.get("model", ""),
api_key=model_config.get("api_key", ""),
base_url=model_config.get("base_url", ""),
timeout=float(model_config.get("timeout", 60)),
max_retries=int(model_config.get("max_retries", 0)),
)
# 回退:使用环境变量中已加载的默认 LLM 配置
from agent.core.llm import llm as _default_llm
return ChatQwen(
model=_default_llm.model_name,
api_key=_default_llm.openai_api_key or "",
base_url=_default_llm.openai_api_base or "",
)
def _build_agent_runtime(cfg: AgentConfig) -> AgentRuntime:
"""根据单个 AgentConfig 构建 AgentRuntime 实例。
输入:
cfg: Agent 配置(name/graph/tools/llm_model_id/system_prompt/max_iterations)。
输出:
完整的 AgentRuntime 实例,可被 execute_agent 直接使用。
"""
# 1. 构建 LLM
agent_llm = _build_llm_for_agent(cfg)
# 2. 获取所有可用工具并按配置过滤
all_tools = get_tools()
if cfg.tools:
agent_tools = [t for t in all_tools if t.name in cfg.tools]
else:
agent_tools = all_tools
# 3. bind_tools
model_with_tools = agent_llm.bind_tools(agent_tools, tool_choice="auto")
# 4. 根据 graph 配置动态构建图
graph = build_graph_by_name(
graph_name=cfg.graph,
tools=agent_tools,
model_with_tools=model_with_tools,
trajectory_rounds=cfg.trajectory_rounds,
parallel_tools=cfg.parallel_tools,
)
# 5. 组装 AgentRuntime
return AgentRuntime(
name=cfg.name,
graph=graph,
llm=agent_llm,
tools=agent_tools,
tools_by_name={tool.name: tool for tool in agent_tools},
system_prompt=cfg.system_prompt,
max_iterations=cfg.max_iterations,
trajectory_rounds=cfg.trajectory_rounds,
)
def build_all_agent_runtimes() -> dict[str, AgentRuntime]:
"""从 agent_config.json 读取所有启用 Agent 并构建运行时字典。
输出:
{agent_name: AgentRuntime} 字典,其中第一个 role="main" 的为 main_agent。
系统定位:
启动时调用一次,构建全局运行时缓存。
"""
global _all_agent_runtimes, _main_agent_name
configs = load_agent_configs()
_all_agent_runtimes = {}
_main_agent_name = "main"
for cfg in configs:
if not cfg.enabled:
continue
try:
runtime = _build_agent_runtime(cfg)
_all_agent_runtimes[cfg.name] = runtime
if cfg.role == "main":
_main_agent_name = cfg.name
except Exception as e:
print(f"[AgentFactory] 构建 Agent '{cfg.name}' 失败: {e}")
# 确保至少有一个 main agent
if _main_agent_name not in _all_agent_runtimes and _all_agent_runtimes:
first_name = next(iter(_all_agent_runtimes))
_main_agent_name = first_name
print(f"[AgentFactory] 未找到 role='main' 的 Agent,自动将 '{first_name}' 设为主 Agent。")
return _all_agent_runtimes
def get_main_agent_runtime() -> AgentRuntime | None:
"""获取当前配置中 role="main" 的 AgentRuntime。
若运行时缓存为空则自动构建。
"""
global _all_agent_runtimes
if not _all_agent_runtimes:
build_all_agent_runtimes()
return _all_agent_runtimes.get(_main_agent_name)
def get_all_agent_runtimes() -> dict[str, AgentRuntime]:
"""获取所有已构建的 Agent 运行时字典。"""
if not _all_agent_runtimes:
build_all_agent_runtimes()
return dict(_all_agent_runtimes)
def get_agent_runtime(name: str) -> AgentRuntime | None:
"""按名称获取指定 Agent 运行时。"""
if not _all_agent_runtimes:
build_all_agent_runtimes()
return _all_agent_runtimes.get(name)
def reload_all_agent_runtimes() -> dict:
"""重新加载配置并重建所有 Agent 运行时,返回当前状态。
输出:
{"agents": [{"name": str, "tools_count": int, "graph": str, "max_iterations": int}, ...],
"main_agent": str}
"""
global _all_agent_runtimes, _main_agent_name
_all_agent_runtimes.clear()
build_all_agent_runtimes()
# 同步更新 chatbot_agent 中的缓存引用
import agent.chatbot_agent as ca
main_rt = _all_agent_runtimes.get(_main_agent_name)
if main_rt:
ca.main_agent_runtime = main_rt
ca.agent_graph = main_rt.graph
ca.tools = main_rt.tools
ca.TOOLS_BY_NAME = main_rt.tools_by_name
ca.llm = main_rt.llm
agents_info = []
for name, rt in _all_agent_runtimes.items():
agents_info.append({
"name": name,
"tools_count": len(rt.tools),
"graph": rt.graph.__class__.__name__ if rt.graph else "unknown",
"max_iterations": rt.max_iterations,
})
return {
"agents": agents_info,
"main_agent": _main_agent_name,
}
-10
View File
@@ -1,10 +0,0 @@
"""代码子 Agent(预留)。
系统定位:
计划用于代码生成、静态分析、仓库操作等,可绑定代码执行沙箱工具
与目录读写类工具。
可扩展性:
可实现独立 AgentRuntime,或在 team 模式下由 main Agent 委派任务;
建议对执行类工具保持 confirm 策略。
"""
View File
Whitespace-only changes.
-11
View File
@@ -1,11 +0,0 @@
"""GUI子 Agent(预留)。
系统定位:
计划用于GUI自动化、页面理解与操作编排,工具以 gui_control
及 screen_capture 为主。
可扩展性:
实现时可单独配置 tool_policy 白名单、更严格的 confirm 策略,
并绑定专用 system_prompt 与较短上下文窗口。
"""
-77
View File
@@ -1,77 +0,0 @@
"""主 Agent 装配入口:工具、模型、图与运行时单例。
系统定位:
项目默认 Agent 实例 ``main_agent_runtime``,由 Web 层导入并调用
``core.runtime.execute_agent`` / ``continue_after_human_action``。
装配内容:
- get_tools(): 主 Agent 可用工具集
- llm.bind_tools: 工具调用能力
- build_agent_graph: 标准 ReAct 图
- MAIN_SYSTEM_PROMPT: 系统提示词
可扩展性:
- 可按环境变量切换工具子集或模型。
- 子 Agent(research/browser/code)可仿照本文件独立装配 AgentRuntime。
"""
from __future__ import annotations
from agent.core.graph_builder import build_agent_graph
from agent.core.llm import llm
from agent.core.runtime import AgentRuntime
from agent.memory.system_prompt import MAIN_SYSTEM_PROMPT
from agent.tools import get_tools
def _build_main_agent_runtime():
"""根据当前配置重新构建主 Agent 运行时。"""
from agent.core.llm import llm as _llm
_system_prompt = MAIN_SYSTEM_PROMPT
_max_iterations = 200
_tools = get_tools()
try:
from agent.core.config_manager import load_agent_configs
configs = load_agent_configs()
for cfg in configs:
if cfg.name == "main" and cfg.enabled:
if cfg.system_prompt:
_system_prompt = cfg.system_prompt
_max_iterations = cfg.max_iterations
# 根据 agent_config.json 中的 tools 列表过滤工具
if cfg.tools:
_tools = [t for t in _tools if t.name in cfg.tools]
break
except Exception:
pass
model_with_tools = _llm.bind_tools(_tools, tool_choice="auto")
return AgentRuntime(
name="main",
graph=build_agent_graph(_tools, model_with_tools),
llm=_llm,
tools=_tools,
tools_by_name={tool.name: tool for tool in _tools},
system_prompt=_system_prompt,
max_iterations=_max_iterations,
)
main_agent_runtime = _build_main_agent_runtime()
def reload_main_agent_runtime() -> dict:
"""重新加载配置并重建主 Agent 运行时,返回当前状态供调试。"""
global main_agent_runtime
import agent.chatbot_agent as ca
main_agent_runtime = _build_main_agent_runtime()
# 更新 chatbot_agent 中缓存的引用
ca.main_agent_runtime = main_agent_runtime
ca.agent_graph = main_agent_runtime.graph
ca.tools = main_agent_runtime.tools
ca.TOOLS_BY_NAME = main_agent_runtime.tools_by_name
ca.llm = main_agent_runtime.llm
return {
"name": main_agent_runtime.name,
"tools_count": len(main_agent_runtime.tools),
"max_iterations": main_agent_runtime.max_iterations,
}
+5 -5
View File
@@ -25,7 +25,7 @@ from agent.core.multi_agent_state import (
ToolCallEvent,
init_multi_agent_state,
)
from agent.tools.tool_agent_call import AgentCallTool
from agent.tools.tool_agent_call import CallSubAgentTool
@dataclass
@@ -92,9 +92,9 @@ def build_multi_agent_runtime(
示例::
from agent.agents.main_agent import main_agent_runtime
from agent.agents.agent import get_main_agent_runtime
runtime = build_multi_agent_runtime(
main_runtime=main_agent_runtime,
main_runtime=get_main_agent_runtime(),
sub_runtimes=[
{"runtime": code_agent_runtime, "icon": "💻"},
{"runtime": research_agent_runtime, "icon": "🔍"},
@@ -104,9 +104,9 @@ def build_multi_agent_runtime(
sub_runtimes = sub_runtimes or []
# 组装主 agent 工具(含 agent_call)
main_tools = list(main_runtime.tools) + [AgentCallTool()]
main_tools = list(main_runtime.tools) + [CallSubAgentTool()]
main_tools_by_name = dict(main_runtime.tools_by_name)
main_tools_by_name["agent_call"] = AgentCallTool()
main_tools_by_name["agent_call"] = CallSubAgentTool()
main_model_with_tools = main_runtime.llm.bind_tools(main_tools, tool_choice="auto")
# 子 agent 配置列表
-12
View File
@@ -1,12 +0,0 @@
"""研究子 Agent(预留)。
系统定位:
计划用于深度检索、文献综述等专用任务,与 main Agent 通过 team 模式
或子图委派协作。
可扩展性:
实现步骤建议:
1. 定义 RESEARCH_SYSTEM_PROMPT 与精简工具集(web_search、RAG 等)
2. build_agent_graph(tools, model) 或自定义图(含检索节点)
3. 导出 research_agent_runtime = AgentRuntime(...)
"""
+13 -7
View File
@@ -2,12 +2,24 @@ from __future__ import annotations
from typing import Any, Literal
from agent.agents.main_agent import main_agent_runtime
from agent.agents.agent import (
build_all_agent_runtimes,
get_main_agent_runtime,
reload_all_agent_runtimes,
)
from agent.core.runtime import continue_after_human_action as continue_runtime_after_human_action
from agent.core.runtime import execute_agent as execute_runtime_agent
AgentMode = Literal["agent", "team"]
# 首次导入时从配置构建主 Agent 运行时并缓存引用
_built = build_all_agent_runtimes()
main_agent_runtime = get_main_agent_runtime()
agent_graph = main_agent_runtime.graph
tools = main_agent_runtime.tools
TOOLS_BY_NAME = main_agent_runtime.tools_by_name
llm = main_agent_runtime.llm
def execute_agent(
chat_history: list[dict[str, Any]],
@@ -43,9 +55,3 @@ def continue_after_human_action(
instruction=instruction,
output_type=output_type,
)
agent_graph = main_agent_runtime.graph
tools = main_agent_runtime.tools
TOOLS_BY_NAME = main_agent_runtime.tools_by_name
llm = main_agent_runtime.llm
+3 -3
View File
@@ -1,12 +1,12 @@
"""Agent 核心运行时包。
包含:
- state / graph_builder: LangGraph 状态与图拓扑
- state / graph: LangGraph 状态与图拓扑
- nodes / routing: 图节点与条件路由
- runtime: 对外执行入口 execute_agent / continue_after_human_action
- llm: ChatQwen 多模态网关
- approvals / human_interaction / tool_policy: HITL 与安全策略
- plan: Plan 模式 UI 构建
- approvals: HITL 待确认管理(含 human_interaction 参数规范化)
- tool_policy: 工具执行安全策略
系统定位:
Agent 业务逻辑中枢,``agents`` 包在此之上组装具体 Agent 实例。
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+5 -8
View File
@@ -1,20 +1,17 @@
[
{
"name": "main",
"system_prompt": "你是一个多模态助手,能够直接理解用户上传的图片、语音等内容。\n 【关键行为准则】\n - 你的默认行为是直接回答用户问题,不要调用任何工具。\n - 只有当某个信息是你**绝对无法从当前对话或上传内容中获取**,且该信息必须通过外部工具才能获得时,才允许调用工具。\n - 对于任何图片/音频输入,请始终**直接**利用你的视觉/听觉能力回答,**绝对不要**调用截图、OCR、日期查询等无关工具。\n - 如果你不确定是否需要工具,选择**不调用**,直接给出你能给出的最佳答案。\n - 违反上述规则是一种严重错误。",
"system_prompt": "你是一个多模态助手,能够直接理解用户上传的图片、语音等内容。\n 【关键行为准则】\n - 你的默认行为是优先调用gui工具解决用户问题。\n - 只有当某个信息是你**绝对无法从当前对话或上传内容中获取**,且该信息必须通过外部工具才能获得时,才允许调用工具。\n - 对于任何图片/音频输入,请始终**直接**利用你的视觉/听觉能力回答,**绝对不要**调用截图、OCR、日期查询等无关工具。\n - 如果你不确定是否需要工具,选择**不调用**,直接给出你能给出的最佳答案。\n - 违反上述规则是一种严重错误。",
"max_iterations": 200,
"llm_model_id": "a44b226e",
"tools": [
"todo_list",
"gui_tool",
"directory_listing",
"web_search_class",
"date_query_class",
"human_interaction",
"software_control",
"browser_control"
],
"enabled": true,
"role": "main"
"role": "main",
"graph": "react",
"trajectory_rounds": 3,
"parallel_tools": true
}
]
+70 -46
View File
@@ -1,8 +1,13 @@
"""待确认操作(HITL)内存注册与 UI 元数据构建。
"""待确认操作(HITL):内存注册、UI 元数据构建、参数规范化与结果生成。
系统定位:
维护进程内 ``PENDING_TOOL_APPROVALS`` 字典,在图因需确认工具而暂停时
保存上下文;``runtime.continue_after_human_action`` 消费并清理。
维护进程内 ``PENDING_TOOL_APPROVALS`` 字典;在图因需确认工具而暂停时
保存上下文并构建前端 UI 元数据;在用户操作后生成 ToolMessage 供图继续执行。
内容分区:
- PENDING 存储与元数据构建(build_approval_meta / build_human_interaction_meta)
- UI 消息辅助(pending_assistant_message / remove_pending_ui_message)
- human_interaction 工具的参数规范化与结果文案(normalize / result)
注意:
当前为内存存储,进程重启后待确认项丢失;生产环境可改为 Redis/DB。
@@ -10,6 +15,7 @@
可扩展性:
- 增加 TTL、session 级清理、持久化后端。
- ``build_*_meta`` 可与前端组件协议版本化。
- 新增 interaction_type 时同步扩展 normalize / result 分支。
"""
from __future__ import annotations
@@ -20,12 +26,20 @@ from typing import Any, Sequence
from langchain_core.messages import BaseMessage
from langchain_core.messages import messages_to_dict
from agent.core.human_interaction import normalize_human_interaction_args
from agent.tools.tool import HumanInteraction
from agent.utils.tool_call_utils import json_safe
# ============================================================
# PENDING 存储
# ============================================================
PENDING_TOOL_APPROVALS: dict[str, dict[str, Any]] = {}
# ============================================================
# UI 元数据构建
# ============================================================
def build_approval_meta(session_id: str, tool_call: dict[str, Any], messages: Sequence[BaseMessage]) -> dict[str, Any]:
"""为需确认的普通工具调用构建 UI 元数据并注册 pending。
@@ -36,12 +50,6 @@ def build_approval_meta(session_id: str, tool_call: dict[str, Any], messages: Se
输出:
``{"pending_action": {...}}``,含 id、type=tool_call、args、options 等。
系统定位:
``routing.first_pending_tool_meta`` 对 confirm 类工具调用。
可扩展性:
可按工具名定制 title、风险提示、参数展示模板。
"""
approval_id = uuid.uuid4().hex
tool_name = tool_call.get("name") or "unknown_tool"
@@ -78,12 +86,6 @@ def build_human_interaction_meta(session_id: str, tool_call: dict[str, Any], mes
输出:
``{"pending_action": {...}}``,type=human_interaction,含 interaction_type 等。
系统定位:
模型主动请求用户补充信息/选择/审批时使用。
可扩展性:
可扩展表单 schema、多步向导式交互。
"""
approval_id = uuid.uuid4().hex
args = normalize_human_interaction_args(tool_call.get("args") or {})
@@ -120,21 +122,7 @@ def build_human_interaction_meta(session_id: str, tool_call: dict[str, Any], mes
def pending_assistant_message(meta: dict[str, Any], content: str = "需要你确认后继续执行。") -> dict[str, Any]:
"""构造带 pending_action 的 assistant 聊天消息 dict。
输入:
meta: 通常含 pending_action 的字典。
content: 展示给用户的提示文案。
输出:
Web UI 使用的 ``{"role": "assistant", "content": ..., "meta": ...}``。
系统定位:
``runtime.execute_agent`` 检测到待确认时追加到 chat_history。
可扩展性:
可统一 output_type、国际化 content 模板。
"""
"""构造带 pending_action 的 assistant 聊天消息 dict。"""
return {
"role": "assistant",
"content": content,
@@ -143,24 +131,60 @@ def pending_assistant_message(meta: dict[str, Any], content: str = "需要你确
def remove_pending_ui_message(chat_history: list[dict[str, Any]], approval_id: str) -> None:
"""在 chat_history 中将指定 approval_id 的 pending_action 标记为已解决。
输入:
chat_history: 可变聊天历史列表(原地修改)。
approval_id: 待确认项 ID。
输出:
无(副作用:匹配消息的 meta.pending_action.resolved = True)。
系统定位:
``runtime.continue_after_human_action`` 用户操作后更新 UI 状态。
可扩展性:
可改为从 history 中移除而非仅标记 resolved。
"""
"""在 chat_history 中将指定 approval_id 的 pending_action 标记为已解决(原地修改)。"""
for msg in reversed(chat_history):
pending = ((msg.get("meta") or {}).get("pending_action") or {}) if isinstance(msg, dict) else {}
if pending.get("id") == approval_id:
pending["resolved"] = True
msg.setdefault("meta", {})["pending_action"] = pending
return
# ============================================================
# human_interaction 工具的参数规范化与结果文案
# ============================================================
def normalize_human_interaction_args(args: dict[str, Any]) -> dict[str, Any]:
"""规范化 human_interaction 工具参数为固定 schema。
输入:
args: 模型传入的原始参数字典。
输出:
含 interaction_type、title、prompt、options、suggested_response 的字典;
interaction_type 限定为 information | selection | approval。
"""
normalized = dict(args or {})
normalized["interaction_type"] = str(normalized.get("interaction_type") or "information")
if normalized["interaction_type"] not in {"information", "selection", "approval"}:
normalized["interaction_type"] = "information"
normalized["title"] = str(normalized.get("title") or "需要人工处理")
normalized["prompt"] = str(normalized.get("prompt") or "请处理后继续。")
normalized["options"] = HumanInteraction.normalize_options(normalized.get("options"))
normalized["suggested_response"] = str(normalized.get("suggested_response") or "")
return normalized
def human_interaction_result(pending: dict[str, Any], decision: str, instruction: str | None) -> str:
"""根据用户决策生成写入 ToolMessage 的文本结果。
输入:
pending: PENDING_TOOL_APPROVALS 中 type=human_interaction 的条目。
decision: approve | reject | edit。
instruction: 用户输入文本(补充信息、选项、修改说明等)。
输出:
供 LangGraph 继续推理的 ToolMessage 字符串内容。
"""
tool_call = pending.get("tool_call") or {}
args = normalize_human_interaction_args(tool_call.get("args") or {})
interaction_type = args.get("interaction_type") or "information"
text = (instruction or "").strip()
if interaction_type == "approval":
if decision == "reject":
return "用户拒绝"
return "用户同意"
if interaction_type == "selection":
selected = text or args.get("suggested_response") or ""
return f"用户选择:{selected}"
return f"用户补充信息如下:{text}"
+99
View File
@@ -49,6 +49,9 @@ class AgentConfig:
tools: list[str] = field(default_factory=list)
enabled: bool = True
role: str = "sub" # "main" | "sub"
graph: str = "react" # 图名,对应 graph.py 中 GRAPH_REGISTRY 的 key
trajectory_rounds: int = 3 # 短期记忆:执行过程中保留最近 N 轮工具返回结果
parallel_tools: bool = False # 是否并行执行同一轮中的多个工具调用
@dataclass
@@ -99,6 +102,9 @@ def _default_agent_config() -> list[dict]:
"tools": get_all_available_tool_names(),
"enabled": True,
"role": "main",
"graph": "react",
"trajectory_rounds": 3,
"parallel_tools": False,
}
]
@@ -120,6 +126,9 @@ def load_agent_configs() -> list[AgentConfig]:
tools=item.get("tools", []),
enabled=item.get("enabled", True),
role=item.get("role", "sub"),
graph=item.get("graph", "react"),
trajectory_rounds=item.get("trajectory_rounds", 3),
parallel_tools=item.get("parallel_tools", False),
))
return configs
@@ -329,3 +338,93 @@ def get_registered_tool_names() -> list[str]:
"""返回所有可用工具名称(含数据库工具)。"""
from agent.tools import get_all_available_tool_names
return get_all_available_tool_names()
# ---------- GUI 显示器配置 ----------
GUI_CONFIG_PATH = _CORE_DIR / "gui_config.json"
def _default_gui_config() -> dict:
"""生成默认 GUI 显示器配置(主显示器)。"""
try:
from screeninfo import get_monitors
monitors = get_monitors()
primary = next((m for m in monitors if m.is_primary), monitors[0] if monitors else None)
if primary:
return {
"gui_monitor_name": primary.name or "",
"gui_monitor_index": 0,
"monitors_snapshot": _serialize_monitors(monitors),
}
except Exception:
pass
return {
"gui_monitor_name": "",
"gui_monitor_index": 0,
"monitors_snapshot": [],
}
def _serialize_monitors(monitors) -> list[dict]:
"""将 screeninfo Monitor 对象序列化为可 JSON 化的字典列表。"""
result = []
for m in monitors:
result.append({
"name": m.name or "",
"x": m.x,
"y": m.y,
"width": m.width,
"height": m.height,
"is_primary": m.is_primary,
})
return result
def _get_live_monitors() -> list[dict]:
"""实时获取当前连接的显示器列表(通过 screeninfo)。"""
from screeninfo import get_monitors
return _serialize_monitors(get_monitors())
def load_gui_config() -> dict:
"""从 gui_config.json 加载 GUI 显示器配置,无文件时返回默认。"""
raw = _read_json(GUI_CONFIG_PATH)
if not raw or not isinstance(raw, dict):
raw = _default_gui_config()
_write_json(GUI_CONFIG_PATH, raw)
return raw
def save_gui_config(config: dict) -> bool:
"""将 GUI 显示器配置写入 gui_config.json。"""
return _write_json(GUI_CONFIG_PATH, config)
def get_active_monitor_region() -> dict | None:
"""获取当前选中的 GUI 操作显示器的区域信息。
返回:
{"x": int, "y": int, "width": int, "height": int, "name": str} 或 None
系统定位:
供 gui_tool.py 截取指定显示器区域并做坐标变换。
"""
config = load_gui_config()
monitor_name = config.get("gui_monitor_name", "")
monitors = _get_live_monitors()
if not monitors:
return None
# 按名称模糊匹配
if monitor_name:
for m in monitors:
if monitor_name.lower() in (m.get("name", "") or "").lower():
return {"x": m["x"], "y": m["y"], "width": m["width"], "height": m["height"], "name": m["name"]}
# 回退:主显示器
primary = next((m for m in monitors if m.get("is_primary")), monitors[0] if monitors else None)
if primary:
return {"x": primary["x"], "y": primary["y"], "width": primary["width"], "height": primary["height"], "name": primary["name"]}
return None
+162
View File
@@ -0,0 +1,162 @@
"""LangGraph 工作流图构建与图注册中心。
系统定位:
将 LLM(已 bind_tools)、工具列表组装为可编译的 StateGraph,
供 ``agents/agent`` 及各子 Agent 的 ``AgentRuntime`` 使用。
图注册中心:
GRAPH_REGISTRY: {图名: 构建函数} 字典映射,供 agent_config.json 的 graph 字段
动态选择使用哪个图。用户可在此注册自定义图。
图结构:
react: START -> agent -> (tools | END)
tools -> process_tool_artifact -> agent
multi_agent: START -> supervisor -> main | sub_N | END
main -> supervisor, sub_N -> supervisor
可扩展性:
- 在 GRAPH_REGISTRY 中注册新图的 (build_fn, info) 元组。
- 可增加 checkpoint、interrupt 节点、子图路由。
- 可为不同 Agent 注入不同的 conditional_edges 或额外节点(如 RAG 检索)。
"""
from __future__ import annotations
from typing import Any
from langgraph.graph import END, START, StateGraph
from langgraph.prebuilt import ToolNode
from agent.core.nodes import make_call_model_node, process_tool_artifact
from agent.core.routing import should_continue
from agent.core.state import AgentState
def build_agent_graph(tools: list[Any], model_with_tools: Any, trajectory_rounds: int = 3, parallel_tools: bool = False):
"""构建并编译标准 ReAct Agent 图。
输入:
tools: LangChain BaseTool 列表,供 ToolNode 执行。
model_with_tools: 已 ``bind_tools`` 的聊天模型,供 agent 节点调用。
trajectory_rounds: 短期记忆保留最近 N 轮工具返回结果,默认 3。
parallel_tools: 是否启用并行工具执行(多个 tool_call 在同一轮并行执行)。
输出:
编译后的 LangGraph CompiledGraph,支持 ``invoke({"messages": ...})``。
系统定位:
默认图类型 "react",供各 Agent 使用。
可扩展性:
返回前可 ``workflow.compile(checkpointer=...)`` 启用持久化;
可参数化节点名以支持多 Agent 图合并。
"""
from agent.tools.tool_agent_call import make_parallel_tool_node
workflow = StateGraph(AgentState)
workflow.add_node("agent", make_call_model_node(model_with_tools, trajectory_rounds=trajectory_rounds))
# 根据 parallel_tools 选择工具执行节点
if parallel_tools:
workflow.add_node("tools", make_parallel_tool_node(tools))
else:
workflow.add_node("tools", ToolNode(tools))
workflow.add_node("process_tool_artifact", process_tool_artifact)
workflow.add_edge(START, "agent")
workflow.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END})
workflow.add_edge("tools", "process_tool_artifact")
workflow.add_edge("process_tool_artifact", "agent")
return workflow.compile()
# ---------- 图注册中心 ----------
# 格式: {图名: {"builder": 构建函数, "display_name": 显示名, "description": 描述}}
# 用户可在此追加自定义图定义。
# 图结构可视化通过 Mermaid PNG 自动生成,无需手动配置 nodes/edges。
GRAPH_REGISTRY: dict[str, dict[str, Any]] = {
"react": {
"builder": build_agent_graph,
"display_name": "ReAct (标准)",
"description": "标准 ReAct 循环:agent 推理 -> 工具执行 -> 结果处理 -> agent 继续推理,直至完成。适用于绝大多数单 Agent 场景。",
},
}
def get_available_graphs() -> list[dict]:
"""返回所有已注册图的信息列表,供前端下拉框与图可视化使用。
输出: [{"name": str, "display_name": str, "description": str}, ...]
"""
result = []
for name, info in GRAPH_REGISTRY.items():
result.append({
"name": name,
"display_name": info.get("display_name", name),
"description": info.get("description", ""),
})
return result
def get_graph_png_bytes(graph_name: str) -> bytes | None:
"""为指定图名构建编译图并生成 Mermaid PNG 字节。
输入:
graph_name: 图名(如 "react"),必须在 GRAPH_REGISTRY 中。
输出:
PNG 字节数据,失败返回 None。
系统定位:
供前端 /api/config/graphs/png/{graph_name} 接口使用,
动态生成图结构可视化图片。
如何新增图:
1. 在 GRAPH_REGISTRY 中注册: {"builder": your_build_fn, "display_name": "名称", "description": "描述"}
2. builder 函数签名为 (tools, model_with_tools, **extra_kwargs) -> CompiledGraph
3. PNG 自动生成,无需额外配置
"""
from unittest.mock import MagicMock
entry = GRAPH_REGISTRY.get(graph_name)
if entry is None:
return None
try:
# 使用 minimal mock 构建仅用于可视化的编译图
mock_llm = MagicMock()
mock_llm.bind_tools.return_value = MagicMock()
mock_tools: list = []
compiled = entry["builder"](mock_tools, mock_llm)
graph_obj = compiled.get_graph()
return graph_obj.draw_mermaid_png()
except Exception as e:
print(f"[GraphViz] 生成图 '{graph_name}' 的 PNG 失败: {e}")
return None
def build_graph_by_name(graph_name: str, tools: list[Any], model_with_tools: Any, **extra_kwargs):
"""根据图名从注册中心查找构建函数并构建编译后的图。
输入:
graph_name: 图名(如 "react"),必须在 GRAPH_REGISTRY 中。
tools: LangChain BaseTool 列表。
model_with_tools: 已 bind_tools 的 LLM。
**extra_kwargs: 传递给 builder 的额外参数(如 trajectory_rounds)。
输出:
编译后的 LangGraph CompiledGraph。
异常:
ValueError: graph_name 未在注册中心找到。
"""
entry = GRAPH_REGISTRY.get(graph_name)
if entry is None:
available = list(GRAPH_REGISTRY.keys())
raise ValueError(f"未找到图 '{graph_name}',可用图: {available}")
builder = entry["builder"]
return builder(tools, model_with_tools, **extra_kwargs)
-53
View File
@@ -1,53 +0,0 @@
"""LangGraph ReAct 工作流图构建。
系统定位:
将 LLM(已 bind_tools)、工具列表组装为可编译的 StateGraph,
供 ``agents/main_agent`` 及各子 Agent 的 ``AgentRuntime`` 使用。
图结构:
START -> agent -> (tools | END)
tools -> process_tool_artifact -> agent
可扩展性:
- 可增加 checkpoint、interrupt 节点、子图路由。
- 可为不同 Agent 注入不同的 conditional_edges 或额外节点(如 RAG 检索)。
"""
from __future__ import annotations
from typing import Any
from langgraph.graph import END, START, StateGraph
from langgraph.prebuilt import ToolNode
from agent.core.nodes import make_call_model_node, process_tool_artifact
from agent.core.routing import should_continue
from agent.core.state import AgentState
def build_agent_graph(tools: list[Any], model_with_tools: Any):
"""构建并编译标准 ReAct Agent 图。
输入:
tools: LangChain BaseTool 列表,供 ToolNode 执行。
model_with_tools: 已 ``bind_tools`` 的聊天模型,供 agent 节点调用。
输出:
编译后的 LangGraph CompiledGraph,支持 ``invoke({"messages": ...})``。
系统定位:
``agents/main_agent`` 入口;子 Agent 可复用同一拓扑并替换 tools/model。
可扩展性:
返回前可 ``workflow.compile(checkpointer=...)`` 启用持久化;
可参数化节点名以支持多 Agent 图合并。
"""
workflow = StateGraph(AgentState)
workflow.add_node("agent", make_call_model_node(model_with_tools))
workflow.add_node("tools", ToolNode(tools))
workflow.add_node("process_tool_artifact", process_tool_artifact)
workflow.add_edge(START, "agent")
workflow.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END})
workflow.add_edge("tools", "process_tool_artifact")
workflow.add_edge("process_tool_artifact", "agent")
return workflow.compile()
+22
View File
@@ -0,0 +1,22 @@
{
"gui_monitor_name": "\\\\.\\DISPLAY5",
"gui_monitor_index": 0,
"monitors_snapshot": [
{
"name": "\\\\.\\DISPLAY5",
"x": 0,
"y": 0,
"width": 2560,
"height": 1440,
"is_primary": true
},
{
"name": "\\\\.\\DISPLAY1",
"x": -1350,
"y": 149,
"width": 1350,
"height": 2400,
"is_primary": false
}
]
}
-75
View File
@@ -1,75 +0,0 @@
"""人工交互(HITL)参数规范化与结果文案生成。
系统定位:
连接 ``human_interaction`` 工具与 ``core/approvals`` / ``core/runtime``,
将模型发起的人工交互请求转为 UI 可展示结构,并在用户操作后生成
ToolMessage 内容供图继续执行。
可扩展性:
- 新增 interaction_type 时同步扩展 ``normalize_human_interaction_args``
与 ``human_interaction_result`` 的分支。
- 可与前端约定更丰富的 payload(表单字段、文件上传等)。
"""
from __future__ import annotations
from typing import Any
from agent.tools.tool import HumanInteraction
def normalize_human_interaction_args(args: dict[str, Any]) -> dict[str, Any]:
"""规范化 human_interaction 工具参数为固定 schema。
输入:
args: 模型传入的原始参数字典。
输出:
含 interaction_type、title、prompt、options、suggested_response 的字典;
interaction_type 限定为 information | selection | approval。
系统定位:
``approvals.build_human_interaction_meta`` 构建待确认 UI 前调用。
可扩展性:
可增加 locale、超时、默认值校验;options 可支持 label/value 结构。
"""
normalized = dict(args or {})
normalized["interaction_type"] = str(normalized.get("interaction_type") or "information")
if normalized["interaction_type"] not in {"information", "selection", "approval"}:
normalized["interaction_type"] = "information"
normalized["title"] = str(normalized.get("title") or "需要人工处理")
normalized["prompt"] = str(normalized.get("prompt") or "请处理后继续。")
normalized["options"] = HumanInteraction.normalize_options(normalized.get("options"))
normalized["suggested_response"] = str(normalized.get("suggested_response") or "")
return normalized
def human_interaction_result(pending: dict[str, Any], decision: str, instruction: str | None) -> str:
"""根据用户决策生成写入 ToolMessage 的文本结果。
输入:
pending: PENDING_TOOL_APPROVALS 中 type=human_interaction 的条目。
decision: approve | reject | edit。
instruction: 用户输入文本(补充信息、选项、修改说明等)。
输出:
供 LangGraph 继续推理的 ToolMessage 字符串内容。
系统定位:
``runtime.continue_after_human_action`` 在人工交互分支调用。
可扩展性:
可返回结构化 JSON 字符串,供下游节点解析;支持多语言模板。
"""
tool_call = pending.get("tool_call") or {}
args = normalize_human_interaction_args(tool_call.get("args") or {})
interaction_type = args.get("interaction_type") or "information"
text = (instruction or "").strip()
if interaction_type == "approval":
if decision == "reject":
return "用户拒绝"
return "用户同意"
if interaction_type == "selection":
selected = text or args.get("suggested_response") or ""
return f"用户选择:{selected}"
return f"用户补充信息如下:{text}"
-3
View File
@@ -476,13 +476,10 @@ class ChatQwen(ChatOpenAI):
# ---------- 打印原始 tool_calls ----------
try:
raw = response if isinstance(response, dict) else response.model_dump()
print("[RAW_RESPONSE]", json.dumps(raw, indent=2, ensure_ascii=False))
choices = raw.get("choices", [])
if choices:
msg = choices[0].get("message", {})
tool_calls = msg.get("tool_calls")
if tool_calls:
print("[RAW_TOOLCALLS]", json.dumps(tool_calls, indent=2, ensure_ascii=False))
except Exception:
pass
+8 -3
View File
@@ -350,6 +350,7 @@ def make_main_agent_node(
tools: list[Any],
agent_name: str = "main",
tools_by_name: dict[str, Any] | None = None,
trajectory_rounds: int = 3,
) -> Callable[[dict], dict]:
"""创建主 Agent 的图节点(含完整的 ReAct 循环 + 委派能力)。
@@ -362,6 +363,7 @@ def make_main_agent_node(
tools: 工具列表(含 agent_call 工具)。
agent_name: 主 agent 名称。
tools_by_name: 工具名映射。
trajectory_rounds: 短期记忆保留最近 N 轮工具返回结果。
输出:
LangGraph 节点函数。
@@ -377,8 +379,10 @@ def make_main_agent_node(
# 执行完整的 ReAct 循环(限制步数防止无限循环)
max_steps = 50
for step in range(max_steps):
# 调用 LLM
response = model_with_tools.invoke(messages)
# 过滤短期记忆后再调用 LLM
from agent.core.nodes import _filter_short_term_memory
filtered = _filter_short_term_memory(messages, trajectory_rounds)
response = model_with_tools.invoke(filtered)
messages.append(response)
# 记录工具调用事件
@@ -471,6 +475,7 @@ def build_multi_agent_graph(
main_tools_by_name: dict[str, Any],
sub_agents: list[dict[str, Any]],
main_agent_name: str = "main",
trajectory_rounds: int = 3,
) -> Any:
"""构建一主多子 SupervisorGraph。
@@ -505,7 +510,7 @@ def build_multi_agent_graph(
# 主 Agent 节点
workflow.add_node(
main_agent_name,
make_main_agent_node(main_model_with_tools, main_tools, main_agent_name, main_tools_by_name),
make_main_agent_node(main_model_with_tools, main_tools, main_agent_name, main_tools_by_name, trajectory_rounds=trajectory_rounds),
)
# 子 Agent 节点
+52 -7
View File
@@ -2,7 +2,7 @@
系统定位:
实现 ReAct 循环中的 ``agent`` 节点工厂与 ``process_tool_artifact`` 节点,
被 ``graph_builder`` 注册到 StateGraph。
被 ``graph`` 注册到 StateGraph。
可扩展性:
- ``make_call_model_node`` 可注入 streaming、重试、用量统计回调。
@@ -19,11 +19,59 @@ from agent.utils.image_utils import image_bytes_to_openai_image_url_part
from agent.utils.tool_call_utils import normalize_tool_call
def make_call_model_node(model_with_tools: Any) -> Callable[[AgentState], dict]:
def _filter_short_term_memory(messages: list, trajectory_rounds: int) -> list:
"""过滤短期记忆:保留所有工具调用,工具返回结果仅保留最近 trajectory_rounds 轮。
输入:
messages: 完整消息列表。
trajectory_rounds: 保留最近 N 轮的工具返回结果。0 或负数表示不过滤。
输出:
过滤后的消息列表。
系统定位:
call_model 节点在调用 LLM 前进行消息裁剪,避免 GUI 等多轮工具调用
场景下上下文过长。
规则:
- 保留所有非 ToolMessage 消息(SystemMessage、HumanMessage、AIMessage)
- ToolMessage 仅保留最近 trajectory_rounds 轮工具调用对应的返回结果
- 每轮由一个 AIMessage(含 tool_calls)定义,其后的 ToolMessage 属于该轮
"""
if trajectory_rounds <= 0:
return list(messages)
# 从后向前遍历,统计已遇到的含 tool_calls 的 AIMessage 轮数
rounds_seen = 0
kept_indices = set()
for i in range(len(messages) - 1, -1, -1):
msg = messages[i]
from langchain_core.messages import AIMessage, ToolMessage
if isinstance(msg, AIMessage) and getattr(msg, "tool_calls", None):
rounds_seen += 1
if isinstance(msg, ToolMessage):
if rounds_seen < trajectory_rounds:
kept_indices.add(i)
else:
kept_indices.add(i)
return [messages[i] for i in sorted(kept_indices)]
def make_call_model_node(
model_with_tools: Any,
trajectory_rounds: int = 3,
) -> Callable[[AgentState], dict]:
"""创建调用已绑定工具的 LLM 的图节点闭包。"""
def call_model(state: AgentState) -> dict:
response = model_with_tools.invoke(state["messages"])
# 过滤短期记忆后再传给 LLM
all_messages = list(state["messages"])
filtered_messages = _filter_short_term_memory(all_messages, trajectory_rounds)
response = model_with_tools.invoke(filtered_messages)
if hasattr(response, "tool_calls") and response.tool_calls:
for tc in response.tool_calls:
@@ -52,11 +100,8 @@ def make_call_model_node(model_with_tools: Any) -> Callable[[AgentState], dict]:
def process_tool_artifact(state: AgentState) -> dict:
last_msg = state["messages"][-1]
# ---- 实时记录工具结果到前端 ----
if isinstance(last_msg, ToolMessage):
content_preview = str(last_msg.content)
if len(content_preview) > 200:
content_preview = content_preview[:200] + "..."
try:
from agent.history.tool_call_recorder import record_tool_result_live, get_current_session
sid = get_current_session()
+2 -2
View File
@@ -1,7 +1,7 @@
"""LangGraph 条件路由:工具循环 vs 结束 vs 待确认暂停。
系统定位:
连接 ``graph_builder`` 的条件边与 ``runtime.execute_agent`` 的
连接 ``graph`` 的条件边与 ``runtime.execute_agent`` 的
后处理逻辑,在模型输出 tool_calls 时决定图走向或提取 UI 待确认元数据。
可扩展性:
@@ -31,7 +31,7 @@ def should_continue(state: AgentState) -> Literal["tools", "__end__"]:
``"tools"`` 进入 ToolNode;``"__end__"`` 结束图(含需确认工具场景)。
系统定位:
``graph_builder`` 中 agent 节点的 conditional_edges 路由函数。
``graph`` 中 agent 节点的 conditional_edges 路由函数。
若任一 tool_call 策略为 confirm,则直接 END,由 runtime 展示确认 UI。
可扩展性:
+52 -12
View File
@@ -18,11 +18,11 @@ from dataclasses import dataclass
from typing import Any, Literal
from langchain_core.messages import AIMessage, HumanMessage, ToolMessage
from langgraph.errors import GraphRecursionError
from langchain_core.messages import messages_from_dict
from langgraph.errors import GraphRecursionError
from agent.core.approvals import PENDING_TOOL_APPROVALS, pending_assistant_message, remove_pending_ui_message
from agent.core.human_interaction import human_interaction_result
from agent.core.approvals import PENDING_TOOL_APPROVALS, pending_assistant_message, remove_pending_ui_message, human_interaction_result
from agent.history.tool_call_recorder import save_turn, start_live_turn, end_live_turn, set_current_turn, set_current_session
from agent.memory.system_prompt import TEAM_MODE_PROMPT
from agent.core.routing import first_pending_tool_meta
@@ -61,6 +61,7 @@ class AgentRuntime:
tools_by_name: dict[str, Any]
system_prompt: str
max_iterations: int = 200
trajectory_rounds: int = 3
_OOM_MESSAGE = "OOM: 已达到最大迭代次数限制,任务未能完成。请简化任务或增加 max_iterations 配置后重试。"
@@ -196,15 +197,33 @@ def _invoke_after_manual_tool_result(
tool_call = normalize_tool_call(raw_tool_call)
tool_name = tool_call.get("name")
tool_args = tool_call.get("args") or {}
tool_call_id = tool_call.get("id") or f"manual_{session_id}_{len(next_messages)}"
if classify_tool_execution(tool_name, tool_args) != "direct":
continue
tool = runtime.tools_by_name.get(tool_name or "")
if not tool:
continue
result = tool.invoke(tool_args)
tool_content = result[0] if isinstance(result, tuple) else result
call_id = tool_call.get("id") or f"manual_{session_id}_{len(next_messages)}"
next_messages.append(ToolMessage(content=str(tool_content), tool_call_id=call_id, name=tool_name or "unknown_tool"))
# 构造完整 ToolCall 格式,确保 content_and_artifact 工具的 artifact 被保留
tool_call_input = {
"name": tool_name,
"args": tool_args,
"id": tool_call_id,
"type": "tool_call",
}
result = tool.invoke(tool_call_input)
if isinstance(result, ToolMessage):
tool_content = str(result.content) if result.content else ""
tool_artifact = getattr(result, "artifact", None)
elif isinstance(result, tuple):
tool_content = str(result[0]) if result[0] else ""
tool_artifact = result[1] if len(result) > 1 else None
else:
tool_content = str(result)
tool_artifact = None
msg_kwargs = {"content": tool_content, "tool_call_id": tool_call_id, "name": tool_name or "unknown_tool"}
if tool_artifact:
msg_kwargs["artifact"] = tool_artifact
next_messages.append(ToolMessage(**msg_kwargs))
progressed = True
if not progressed:
return all_messages, None
@@ -324,6 +343,7 @@ def execute_agent(
"output_type": output_type_from_config,
"autoplay": False,
"audio": audio_data.get("audio"),
"turn_id": turn_id,
}
if output_type_from_config == "audio" and assistant_meta.get("audio"):
@@ -423,7 +443,8 @@ def continue_after_human_action(
traceback.print_exc()
content = "处理人工交互结果时遇到问题。"
persisted_messages = messages_from_dict(pending.get("messages") or [])
chat_history.append({"role": "assistant", "content": content, "meta": {"output_type": output_type, "autoplay": False}})
human_turn_id = f"human_{approval_id}"
chat_history.append({"role": "assistant", "content": content, "meta": {"output_type": output_type, "autoplay": False, "turn_id": human_turn_id}})
_persist_messages_from_pending_turn(session_id, persisted_messages, pending)
if session_id:
@@ -441,11 +462,29 @@ def continue_after_human_action(
return chat_history
try:
result = tool.invoke(tool_args)
tool_content = result[0] if isinstance(result, tuple) else result
# 构造完整 ToolCall 格式,确保 content_and_artifact 工具的 artifact 被保留
tool_call_input = {
"name": tool_name,
"args": tool_args,
"id": tool_call.get("id", ""),
"type": "tool_call",
}
result = tool.invoke(tool_call_input)
if isinstance(result, ToolMessage):
tool_content = str(result.content) if result.content else ""
tool_artifact = getattr(result, "artifact", None)
elif isinstance(result, tuple):
tool_content = str(result[0]) if result[0] else ""
tool_artifact = result[1] if len(result) > 1 else None
else:
tool_content = str(result)
tool_artifact = None
prior_messages = messages_from_dict(pending.get("messages") or [])
call_id = tool_call.get("id") or f"manual_{approval_id}"
prior_messages.append(ToolMessage(content=str(tool_content), tool_call_id=call_id, name=tool_name))
msg_kwargs = {"content": tool_content, "tool_call_id": call_id, "name": tool_name}
if tool_artifact:
msg_kwargs["artifact"] = tool_artifact
prior_messages.append(ToolMessage(**msg_kwargs))
all_messages, pending_meta = _invoke_after_manual_tool_result(runtime, prior_messages, session_id)
if pending_meta:
_remember_pending_user_content(pending_meta, pending.get("user_content"))
@@ -468,9 +507,10 @@ def continue_after_human_action(
])
persisted_messages = prior_messages
chat_history.append({"role": "assistant", "content": content, "meta": {"output_type": output_type, "autoplay": False}})
manual_turn_id = f"human_{approval_id}"
chat_history.append({"role": "assistant", "content": content, "meta": {"output_type": output_type, "autoplay": False, "turn_id": manual_turn_id}})
_persist_messages_from_pending_turn(session_id, persisted_messages, pending)
if session_id:
save_turn(session_id, f"human_{approval_id}", {"role": "user", "content": pending.get("user_content") or ""}, persisted_messages)
save_turn(session_id, manual_turn_id, {"role": "user", "content": pending.get("user_content") or ""}, persisted_messages)
sync_manifest_from_chat_history(session_id, chat_history, "")
return chat_history
+1 -1
View File
@@ -1,7 +1,7 @@
"""LangGraph Agent 状态类型定义。
系统定位:
定义图运行时共享状态 ``AgentState``,被 ``graph_builder``、``nodes``、
定义图运行时共享状态 ``AgentState``,被 ``graph``、``nodes``、
``routing`` 作为 StateGraph 的 schema 使用。
可扩展性:
+16 -2
View File
@@ -11,7 +11,7 @@
"name": "date_query_class",
"display_name": "DateQuery",
"description": "一个日期查询工具,可以返回当前的日期信息。仅当需要查询当前时间时调用,其余任何情况严禁调用。",
"permission": "confirm",
"permission": "direct",
"auto_execute_rules": [],
"enabled": true
},
@@ -50,7 +50,13 @@
"display_name": "SoftwareControl",
"description": "操作本机已安装的软件。工具会自动扫描 Windows 开始菜单快捷方式、桌面快捷方式和 App Paths,建立软件索引后根据用户输入做模糊匹配。action=open 时打开软件;action=close 时仅做正常关闭;action=force_close 时才允许在正常关闭失败后强制结束进程。仅当用户明确要求打开、关闭或强制关闭某个本机软件时调用。",
"permission": "confirm",
"auto_execute_rules": [],
"auto_execute_rules": [
{
"parameter": "action",
"operator": "equals",
"value": "open"
}
],
"enabled": true
},
{
@@ -90,5 +96,13 @@
"permission": "direct",
"auto_execute_rules": [],
"enabled": true
},
{
"name": "call_subagent",
"display_name": "CallSubAgentTool",
"description": "调用已启用的子 Agent 执行指定任务。子 Agent 会独立运行并返回最终结果。",
"permission": "direct",
"auto_execute_rules": [],
"enabled": true
}
]
Binary file not shown.
@@ -1,80 +0,0 @@
{
"version": 3,
"messages": [
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "调用一次todolist生成一份详细的做西红柿炒鸡蛋计划"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "已为您生成详细的**西红柿炒鸡蛋**制作计划,共分为8个步骤:\n\n1. **准备食材**:2-3个鸡蛋、2个中等大小西红柿、葱花少许、食用油适量、盐适量、糖少许(可选)\n2. **处理食材**:将鸡蛋打入碗中,加少许盐打散;西红柿洗净切块;葱切成葱花备用\n3. **热锅倒油**:开中火加热炒锅,倒入适量食用油,待油微热\n4. **炒鸡蛋**:倒入蛋液,用筷子或铲子快速划散,炒至凝固后盛出备用\n5. **炒西红柿**:锅中留底油,放入西红柿块翻炒,可用铲子压一压帮助出汁,炒至软烂\n6. **调味**:根据口味加入适量盐和少许糖提鲜,翻炒均匀\n7. **混合**:将炒好的鸡蛋倒回锅中,与西红柿翻炒均匀,让鸡蛋吸收汤汁\n8. **出锅**:撒上葱花点缀,装盘即可享用\n\n祝您烹饪愉快!如果需要标记某一步骤完成,请告诉我。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
},
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "你的上下文中有什么"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "需要你确认后继续执行。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": {
"id": "b5de8b0742564742ba20ec9df9803b51",
"type": "tool_call",
"title": "待确认执行工具:rag_tool",
"tool_name": "rag_tool",
"args": {
"name": "rag_tool",
"args": {
"action_type": "list_sources"
}
},
"instruction": "{\n \"name\": \"rag_tool\",\n \"args\": {\n \"action_type\": \"list_sources\"\n }\n}",
"options": [
"approve",
"reject"
],
"resolved": true
},
"agent_mode": null
}
},
{
"role": "assistant",
"assistant": {
"text": "已拒绝,本次待确认操作不会执行。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
}
]
}
@@ -0,0 +1,120 @@
{
"version": 3,
"messages": [
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "帮我点击加号新建标签页"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "已成功点击加号,新建了一个标签页。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
},
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "帮我左键点击当前视频进行暂停"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "已成功左键点击当前视频画面,视频已暂停。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
},
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "帮我点击加号新建标签页"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "已成功点击加号,新建了一个标签页。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
},
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "帮我点击加号新建标签页"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "已成功点击加号,新建了一个标签页。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
},
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "截张图看看我再干啥,如果读不到图片请直接告诉我"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "根据截图,我可以看到你正在使用一个浏览器(看起来像是 Edge 浏览器),并且打开了多个标签页。\n\n当前屏幕显示的内容包括:\n1. **浏览器顶部**:有几个打开的标签页,包括“哔哩哔哩”、“【野火】这视频怎么讲?... ”和当前的“新建标签页”。\n2. **页面内容**:这是一个浏览器的新标签页界面,背景是雪山风景图。中间有一个搜索框,下方有一些快捷方式图标,例如“哔哩哔哩”、“京东直播”、“山东大学”等。\n3. **底部任务栏**:显示了 Windows 系统的任务栏,有开始菜单、搜索、文件资源管理器、Edge 浏览器、微信等图标。右下角显示时间是 11:24,日期是 2025/8/27。\n\n所以,你目前的状态是在电脑上使用浏览器浏览网页或准备搜索新的内容。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
}
]
}
@@ -0,0 +1,51 @@
{
"version": 3,
"messages": [
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "截张图看看我再干啥,如果读不到图片请直接告诉我"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "根据截图,你当前正在使用 **Google Chrome** 浏览器。\n\n屏幕上打开了两个标签页:\n1. **左侧标签页**:显示的是 **YouTube** 网站,页面标题是 \"YouTube\",看起来可能是在浏览视频列表或者首页。\n2. **右侧标签页(当前激活)**:显示的是 **Wikipedia(维基百科)** 的中文页面,具体是关于 **\"中国\"** (China) 的条目。页面内容展示了中国的地图、国旗以及相关的介绍文字。\n\n此外,任务栏上还可以看到其他已打开的应用程序图标,包括文件资源管理器、Edge 浏览器等。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
},
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "截张图看看我再干啥,如果读不到图片请直接告诉我"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "截图已获取。\n\n从截图中可以看到,你当前正在使用 **Google Chrome** 浏览器。\n1. **左侧标签页**:打开的是 **YouTube** 网站。\n2. **右侧标签页(当前激活)**:显示的是 **Wikipedia(维基百科)** 的中文页面,标题为“中国”。\n\n你似乎正在浏览关于中国的百科信息。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
}
]
}
@@ -7,7 +7,7 @@
"content": [
{
"type": "text",
"text": "帮我关掉DeepSeek开放平台的标签页"
"text": "帮我点击加号新建标签页"
}
]
}
@@ -15,7 +15,7 @@
{
"role": "assistant",
"assistant": {
"text": "已经帮您关闭了 DeepSeek 开放平台的标签页。现在浏览器显示的是 minor - Chatbot 页面。",
"text": "已为您点击新建标签页。现在应该已经打开了一个新的空白标签页。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
@@ -0,0 +1,51 @@
{
"version": 3,
"messages": [
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "截张图看看我在干啥,如果读不到图片请直接告诉我"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "根据截图,你正在使用 **DeepSeek 开放平台**(platform.deepseek.com)的网页界面。\n\n具体来说,你当前查看的是 **“用量信息”** 页面。页面上显示了以下关键信息:\n* **充值余额**:¥22.77 CNY\n* **六月消费**(按 UTC+0 时间):¥17.22 CNY\n* **每月用量图表**:展示了近期(6月1日至6月30日)的消费金额波动。\n* **模型使用情况**:下方还列出了 `deepseek-v4-pro` 模型的 API 请求次数和 Tokens 消耗量。\n\n简单来说,你正在查看自己在 DeepSeek 平台上的账户余额、消费记录以及 API 的使用情况。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
},
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "你现在的对话记录中有图片吗"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "根据刚才截取的屏幕截图,我**没有**在当前的对话记录中看到任何图片。\n\n这张截图显示的是你正在浏览 **DeepSeek 开放平台** 的“用量信息”页面,主要内容包括:\n1. **充值余额**:¥22.77 CNY\n2. **六月消费**(按 UTC+0 时间):¥17.22 CNY\n3. **每月用量图表**:展示了近期每天的消费金额波动。\n4. **模型使用情况**:下方列出了 `deepseek-v4-pro` 模型的 API 请求次数和 Tokens 消耗量。\n\n所以,目前的对话中只有文字交互,并没有上传图片。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
}
]
}
@@ -0,0 +1,51 @@
{
"version": 3,
"messages": [
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "能不能帮我打开虎牙直播"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "虎牙直播已经成功打开了!可以看到:\n\n- 页面顶部显示\"虎牙直播\"的Logo\n- 当前正在播放主播\"王子酱\"的直播间\n- 页面下方展示了各种游戏分类,包括网游竞技(LOL、CS2等)、单机热游等\n- 右侧还有其他推荐的主播和直播间\n\n你现在可以浏览你感兴趣的直播内容了。如果你想观看特定的主播或游戏类别,可以直接点击相应的选项。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
},
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "帮我打开b站"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "好的,B站(bilibili)已经成功打开。\n\n页面显示了:\n* **顶部导航栏**:包含首页、番剧、直播、游戏中心等主要分区。\n* **推荐内容**:首页展示了多个视频推荐,例如左侧的“BML-PLAY! 2025”活动预告,以及右侧的“GPT如何解决80年未解单位距离猜想?”等热门视频。\n* **分类标签**:可以看到动画、番剧、国创、音乐、舞蹈、游戏等多个内容分类。\n\n你现在可以浏览你感兴趣的内容了。",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
}
]
}
@@ -0,0 +1,28 @@
{
"version": 3,
"messages": [
{
"role": "user",
"user": {
"content": [
{
"type": "text",
"text": "帮我打开b站"
}
]
}
},
{
"role": "assistant",
"assistant": {
"text": "B站(哔哩哔哩)已经为您打开了。请问有什么我可以帮您的吗?",
"output_type": "text",
"autoplay": false,
"audio_duration_seconds": null,
"audio_relpath": null,
"pending_action": null,
"agent_mode": null
}
}
]
}
+70 -47
View File
@@ -176,28 +176,35 @@ def session_tool_dir(session_id: str) -> Path:
def extract_tool_calls_from_messages(messages: list[BaseMessage]) -> list[dict[str, Any]]:
"""从图执行后的消息列表中提取完整的工具调用链。"""
records: list[dict[str, Any]] = []
pending: dict[str, dict[str, Any]] = {}
pending: list[dict[str, Any]] = []
# 同名工具调用计数器,避免多张截图文件名冲突
name_counter: dict[str, int] = {}
for msg in messages:
if isinstance(msg, AIMessage) and msg.tool_calls:
for tc in msg.tool_calls:
d = tc if isinstance(tc, dict) else {"name": tc.name, "args": tc.args, "id": tc.id}
if d.get("id"):
pending[d["id"]] = {
"name": d.get("name", "unknown"),
"args": _json_safe(d.get("args", {})),
"result_text": "",
"result_files": [],
}
elif isinstance(msg, ToolMessage) and msg.tool_call_id:
cid = msg.tool_call_id
if cid in pending:
entry = pending.pop(cid)
pending.append({
"name": d.get("name", "unknown"),
"args": _json_safe(d.get("args", {})),
"result_text": "",
"result_files": [],
"result_images": [],
})
elif isinstance(msg, ToolMessage):
if pending:
entry = pending.pop(0)
entry["result_text"] = str(msg.content) if msg.content else ""
if msg.artifact:
entry["result_files"] = _save_artifact_files(msg.artifact, msg.tool_call_id)
artifact = getattr(msg, "artifact", None)
if artifact:
tool_name = msg.name or entry["name"]
idx = name_counter.get(tool_name, 0)
name_counter[tool_name] = idx + 1
unique_name = f"{tool_name}_{idx}"
result_files, image_bytes_map = _save_artifact_files(artifact, unique_name)
entry["result_files"] = result_files
entry["_image_bytes"] = image_bytes_map # 供 save_turn 落盘
records.append(entry)
for entry in pending.values():
records.append(entry)
records.extend(pending)
return records
@@ -213,36 +220,29 @@ def _json_safe(value: Any) -> Any:
return str(value)
def _save_artifact_files(artifact: Any, base_name: str) -> list[str]:
def _save_artifact_files(artifact: Any, base_name: str) -> tuple[list[str], dict[str, bytes]]:
"""从 artifact 中提取文件名列表和 {文件名: bytes} 映射。"""
files: list[str] = []
bytes_map: dict[str, bytes] = {}
if isinstance(artifact, dict) and "image_bytes" in artifact:
files.append(f"_artifact_{base_name}_0.png")
fname = f"_artifact_{base_name}_0.png"
files.append(fname)
bytes_map[fname] = artifact["image_bytes"]
elif isinstance(artifact, list):
for i, item in enumerate(artifact):
if isinstance(item, dict) and "image_bytes" in item:
files.append(f"_artifact_{base_name}_{i}.png")
fname = f"_artifact_{base_name}_{i}.png"
files.append(fname)
bytes_map[fname] = item["image_bytes"]
elif isinstance(item, bytes):
files.append(f"_artifact_{base_name}_{i}.png")
fname = f"_artifact_{base_name}_{i}.png"
files.append(fname)
bytes_map[fname] = item
elif isinstance(artifact, bytes):
files.append(f"_artifact_{base_name}.png")
return files
def _find_artifact_bytes(messages: list[BaseMessage], fname: str) -> bytes | None:
for msg in messages:
if isinstance(msg, ToolMessage) and msg.artifact:
a = msg.artifact
if isinstance(a, dict) and "image_bytes" in a:
return a["image_bytes"]
if isinstance(a, list):
for item in a:
if isinstance(item, dict) and "image_bytes" in item:
return item["image_bytes"]
if isinstance(item, bytes):
return item
if isinstance(a, bytes):
return a
return None
fname = f"_artifact_{base_name}.png"
files.append(fname)
bytes_map[fname] = artifact
return files, bytes_map
def save_turn(session_id: str, turn_id: str, user_message: dict[str, Any],
@@ -263,12 +263,9 @@ def save_turn(session_id: str, turn_id: str, user_message: dict[str, Any],
_ensure_dir(turn_dir)
for tc in tool_calls:
for fname in list(tc.get("result_files", [])):
img_bytes = _find_artifact_bytes(messages, fname)
if img_bytes:
(turn_dir / fname).write_bytes(img_bytes)
else:
tc["result_files"].remove(fname)
image_bytes_map = tc.pop("_image_bytes", {})
for fname, img_bytes in image_bytes_map.items():
(turn_dir / fname).write_bytes(img_bytes)
record = {
"session_id": session_id,
@@ -310,14 +307,40 @@ def get_tool_calls_for_latest_turn(session_id: str) -> list[dict[str, Any]]:
latest = get_latest_turn(session_id)
if not latest:
return []
turn_id = latest.get("turn_id", "")
return _tool_calls_from_turn_record(latest, session_id)
def get_tool_calls_for_turn(session_id: str, turn_id: str) -> list[dict[str, Any]]:
"""获取指定 turn_id 的工具调用(供 UI 按消息还原)。"""
if not turn_id:
return []
session_dir = session_tool_dir(session_id)
json_path = session_dir / f"turn_{turn_id}.json"
if not json_path.is_file():
return []
try:
with open(json_path, "r", encoding="utf-8") as f:
record = json.load(f)
except (json.JSONDecodeError, OSError):
return []
return _tool_calls_from_turn_record(record, session_id)
def _tool_calls_from_turn_record(record: dict[str, Any], session_id: str) -> list[dict[str, Any]]:
"""从 turn 记录中提取工具调用列表,补充图片路径。"""
turn_id = record.get("turn_id", "")
result = []
for tc in latest.get("tool_calls", []):
for tc in record.get("tool_calls", []):
entry = dict(tc)
full_files = []
for fname in tc.get("result_files", []):
full_files.append(str(session_tool_dir(session_id) / turn_id / fname))
entry["result_files_full"] = full_files
# result_images 存图片文件路径而非 base64,前端通过 /api/tool-image 读取
entry["result_images"] = [
f"/api/tool-image?path={fp}&session={turn_id}"
for fp in full_files
]
entry["turn_id"] = turn_id
result.append(entry)
return result
@@ -1,29 +0,0 @@
{
"session_id": "20260618_111759",
"turn_id": "20260618_111855",
"user_message": {
"role": "user",
"content": "调用一次todolist生成一份详细的做西红柿炒鸡蛋计划"
},
"tool_calls": [
{
"name": "todo_list",
"args": {
"steps": [
"准备食材:2-3个鸡蛋、2个中等大小西红柿、葱花少许、食用油适量、盐适量、糖少许(可选)",
"处理食材:将鸡蛋打入碗中,加少许盐打散;西红柿洗净切块;葱切成葱花备用",
"热锅倒油:开中火加热炒锅,倒入适量食用油,待油微热",
"炒鸡蛋:倒入蛋液,用筷子或铲子快速划散,炒至凝固后盛出备用",
"炒西红柿:锅中留底油,放入西红柿块翻炒,可用铲子压一压帮助出汁,炒至软烂",
"调味:根据口味加入适量盐和少许糖提鲜,翻炒均匀",
"混合:将炒好的鸡蛋倒回锅中,与西红柿翻炒均匀,让鸡蛋吸收汤汁",
"出锅:撒上葱花点缀,装盘即可享用"
]
},
"result_text": "{\"__todo_list__\": true, \"data\": {\"steps\": [\"\\u51c6\\u5907\\u98df\\u6750\\uff1a2-3\\u4e2a\\u9e21\\u86cb\\u30012\\u4e2a\\u4e2d\\u7b49\\u5927\\u5c0f\\u897f\\u7ea2\\u67ff\\u3001\\u8471\\u82b1\\u5c11\\u8bb8\\u3001\\u98df\\u7528\\u6cb9\\u9002\\u91cf\\u3001\\u76d0\\u9002\\u91cf\\u3001\\u7cd6\\u5c11\\u8bb8\\uff08\\u53ef\\u9009\\uff09\", \"\\u5904\\u7406\\u98df\\u6750\\uff1a\\u5c06\\u9e21\\u86cb\\u6253\\u5165\\u7897\\u4e2d\\uff0c\\u52a0\\u5c11\\u8bb8\\u76d0\\u6253\\u6563\\uff1b\\u897f\\u7ea2\\u67ff\\u6d17\\u51c0\\u5207\\u5757\\uff1b\\u8471\\u5207\\u6210\\u8471\\u82b1\\u5907\\u7528\", \"\\u70ed\\u9505\\u5012\\u6cb9\\uff1a\\u5f00\\u4e2d\\u706b\\u52a0\\u70ed\\u7092\\u9505\\uff0c\\u5012\\u5165\\u9002\\u91cf\\u98df\\u7528\\u6cb9\\uff0c\\u5f85\\u6cb9\\u5fae\\u70ed\", \"\\u7092\\u9e21\\u86cb\\uff1a\\u5012\\u5165\\u86cb\\u6db2\\uff0c\\u7528\\u7b77\\u5b50\\u6216\\u94f2\\u5b50\\u5feb\\u901f\\u5212\\u6563\\uff0c\\u7092\\u81f3\\u51dd\\u56fa\\u540e\\u76db\\u51fa\\u5907\\u7528\", \"\\u7092\\u897f\\u7ea2\\u67ff\\uff1a\\u9505\\u4e2d\\u7559\\u5e95\\u6cb9\\uff0c\\u653e\\u5165\\u897f\\u7ea2\\u67ff\\u5757\\u7ffb\\u7092\\uff0c\\u53ef\\u7528\\u94f2\\u5b50\\u538b\\u4e00\\u538b\\u5e2e\\u52a9\\u51fa\\u6c41\\uff0c\\u7092\\u81f3\\u8f6f\\u70c2\", \"\\u8c03\\u5473\\uff1a\\u6839\\u636e\\u53e3\\u5473\\u52a0\\u5165\\u9002\\u91cf\\u76d0\\u548c\\u5c11\\u8bb8\\u7cd6\\u63d0\\u9c9c\\uff0c\\u7ffb\\u7092\\u5747\\u5300\", \"\\u6df7\\u5408\\uff1a\\u5c06\\u7092\\u597d\\u7684\\u9e21\\u86cb\\u5012\\u56de\\u9505\\u4e2d\\uff0c\\u4e0e\\u897f\\u7ea2\\u67ff\\u7ffb\\u7092\\u5747\\u5300\\uff0c\\u8ba9\\u9e21\\u86cb\\u5438\\u6536\\u6c64\\u6c41\", \"\\u51fa\\u9505\\uff1a\\u6492\\u4e0a\\u8471\\u82b1\\u70b9\\u7f00\\uff0c\\u88c5\\u76d8\\u5373\\u53ef\\u4eab\\u7528\"], \"done_steps\": []}}\n[Todo List]\n- [1/8] [Pending]: 准备食材:2-3个鸡蛋、2个中等大小西红柿、葱花少许、食用油适量、盐适量、糖少许(可选)\n- [2/8] [Pending]: 处理食材:将鸡蛋打入碗中,加少许盐打散;西红柿洗净切块;葱切成葱花备用\n- [3/8] [Pending]: 热锅倒油:开中火加热炒锅,倒入适量食用油,待油微热\n- [4/8] [Pending]: 炒鸡蛋:倒入蛋液,用筷子或铲子快速划散,炒至凝固后盛出备用\n- [5/8] [Pending]: 炒西红柿:锅中留底油,放入西红柿块翻炒,可用铲子压一压帮助出汁,炒至软烂\n- [6/8] [Pending]: 调味:根据口味加入适量盐和少许糖提鲜,翻炒均匀\n- [7/8] [Pending]: 混合:将炒好的鸡蛋倒回锅中,与西红柿翻炒均匀,让鸡蛋吸收汤汁\n- [8/8] [Pending]: 出锅:撒上葱花点缀,装盘即可享用",
"result_files": []
}
],
"assistant_response": "已为您生成详细的**西红柿炒鸡蛋**制作计划,共分为8个步骤:\n\n1. **准备食材**:2-3个鸡蛋、2个中等大小西红柿、葱花少许、食用油适量、盐适量、糖少许(可选)\n2. **处理食材**:将鸡蛋打入碗中,加少许盐打散;西红柿洗净切块;葱切成葱花备用\n3. **热锅倒油**:开中火加热炒锅,倒入适量食用油,待油微热\n4. **炒鸡蛋**:倒入蛋液,用筷子或铲子快速划散,炒至凝固后盛出备用\n5. **炒西红柿**:锅中留底油,放入西红柿块翻炒,可用铲子压一压帮助出汁,炒至软烂\n6. **调味**:根据口味加入适量盐和少许糖提鲜,翻炒均匀\n7. **混合**:将炒好的鸡蛋倒回锅中,与西红柿翻炒均匀,让鸡蛋吸收汤汁\n8. **出锅**:撒上葱花点缀,装盘即可享用\n\n祝您烹饪愉快!如果需要标记某一步骤完成,请告诉我。",
"timestamp": "20260618_111855"
}
@@ -1,30 +0,0 @@
{
"session_id": "20260618_112443",
"turn_id": "20260618_112445",
"user_message": {
"role": "user",
"content": "调用一次todolist生成一份详细的做西红柿炒鸡蛋计划"
},
"tool_calls": [
{
"name": "todo_list",
"args": {
"steps": [
"准备食材:2-3个鸡蛋、2-3个中等大小西红柿、葱花适量",
"准备调料:食用油、盐、白糖(可选,用于提鲜)、番茄酱(可选)",
"处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用",
"热锅凉油:开中火加热炒锅,倒入适量食用油",
"炒鸡蛋:油热后倒入蛋液,快速划散至凝固,盛出备用",
"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁变软",
"调味:加入适量盐和少许白糖,喜欢浓郁口感可加一勺番茄酱",
"混合翻炒:将炒好的鸡蛋倒回锅中,与西红柿均匀翻炒混合",
"出锅装盘:撒上葱花点缀,即可享用美味的西红柿炒鸡蛋"
]
},
"result_text": "{\"__todo_list__\": true, \"data\": {\"steps\": [\"\\u51c6\\u5907\\u98df\\u6750\\uff1a2-3\\u4e2a\\u9e21\\u86cb\\u30012-3\\u4e2a\\u4e2d\\u7b49\\u5927\\u5c0f\\u897f\\u7ea2\\u67ff\\u3001\\u8471\\u82b1\\u9002\\u91cf\", \"\\u51c6\\u5907\\u8c03\\u6599\\uff1a\\u98df\\u7528\\u6cb9\\u3001\\u76d0\\u3001\\u767d\\u7cd6\\uff08\\u53ef\\u9009\\uff0c\\u7528\\u4e8e\\u63d0\\u9c9c\\uff09\\u3001\\u756a\\u8304\\u9171\\uff08\\u53ef\\u9009\\uff09\", \"\\u5904\\u7406\\u98df\\u6750\\uff1a\\u5c06\\u897f\\u7ea2\\u67ff\\u6d17\\u51c0\\u5207\\u5757\\uff1b\\u9e21\\u86cb\\u6253\\u5165\\u7897\\u4e2d\\u6405\\u6563\\u5907\\u7528\", \"\\u70ed\\u9505\\u51c9\\u6cb9\\uff1a\\u5f00\\u4e2d\\u706b\\u52a0\\u70ed\\u7092\\u9505\\uff0c\\u5012\\u5165\\u9002\\u91cf\\u98df\\u7528\\u6cb9\", \"\\u7092\\u9e21\\u86cb\\uff1a\\u6cb9\\u70ed\\u540e\\u5012\\u5165\\u86cb\\u6db2\\uff0c\\u5feb\\u901f\\u5212\\u6563\\u81f3\\u51dd\\u56fa\\uff0c\\u76db\\u51fa\\u5907\\u7528\", \"\\u7092\\u897f\\u7ea2\\u67ff\\uff1a\\u9505\\u4e2d\\u518d\\u52a0\\u5c11\\u8bb8\\u6cb9\\uff0c\\u653e\\u5165\\u897f\\u7ea2\\u67ff\\u5757\\u7ffb\\u7092\\u81f3\\u51fa\\u6c41\\u53d8\\u8f6f\", \"\\u8c03\\u5473\\uff1a\\u52a0\\u5165\\u9002\\u91cf\\u76d0\\u548c\\u5c11\\u8bb8\\u767d\\u7cd6\\uff0c\\u559c\\u6b22\\u6d53\\u90c1\\u53e3\\u611f\\u53ef\\u52a0\\u4e00\\u52fa\\u756a\\u8304\\u9171\", \"\\u6df7\\u5408\\u7ffb\\u7092\\uff1a\\u5c06\\u7092\\u597d\\u7684\\u9e21\\u86cb\\u5012\\u56de\\u9505\\u4e2d\\uff0c\\u4e0e\\u897f\\u7ea2\\u67ff\\u5747\\u5300\\u7ffb\\u7092\\u6df7\\u5408\", \"\\u51fa\\u9505\\u88c5\\u76d8\\uff1a\\u6492\\u4e0a\\u8471\\u82b1\\u70b9\\u7f00\\uff0c\\u5373\\u53ef\\u4eab\\u7528\\u7f8e\\u5473\\u7684\\u897f\\u7ea2\\u67ff\\u7092\\u9e21\\u86cb\"], \"done_steps\": []}}\n[Todo List]\n- [1/9] [Pending]: 准备食材:2-3个鸡蛋、2-3个中等大小西红柿、葱花适量\n- [2/9] [Pending]: 准备调料:食用油、盐、白糖(可选,用于提鲜)、番茄酱(可选)\n- [3/9] [Pending]: 处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用\n- [4/9] [Pending]: 热锅凉油:开中火加热炒锅,倒入适量食用油\n- [5/9] [Pending]: 炒鸡蛋:油热后倒入蛋液,快速划散至凝固,盛出备用\n- [6/9] [Pending]: 炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁变软\n- [7/9] [Pending]: 调味:加入适量盐和少许白糖,喜欢浓郁口感可加一勺番茄酱\n- [8/9] [Pending]: 混合翻炒:将炒好的鸡蛋倒回锅中,与西红柿均匀翻炒混合\n- [9/9] [Pending]: 出锅装盘:撒上葱花点缀,即可享用美味的西红柿炒鸡蛋",
"result_files": []
}
],
"assistant_response": "已为您生成详细的西红柿炒鸡蛋制作计划,共9个步骤:\n\n1. **准备食材**:2-3个鸡蛋、2-3个中等大小西红柿、葱花适量\n2. **准备调料**:食用油、盐、白糖(可选,用于提鲜)、番茄酱(可选)\n3. **处理食材**:将西红柿洗净切块;鸡蛋打入碗中搅散备用\n4. **热锅凉油**:开中火加热炒锅,倒入适量食用油\n5. **炒鸡蛋**:油热后倒入蛋液,快速划散至凝固,盛出备用\n6. **炒西红柿**:锅中再加少许油,放入西红柿块翻炒至出汁变软\n7. **调味**:加入适量盐和少许白糖,喜欢浓郁口感可加一勺番茄酱\n8. **混合翻炒**:将炒好的鸡蛋倒回锅中,与西红柿均匀翻炒混合\n9. **出锅装盘**:撒上葱花点缀,即可享用美味的西红柿炒鸡蛋\n\n祝您烹饪愉快!",
"timestamp": "20260618_112445"
}
@@ -1,147 +0,0 @@
{
"session_id": "20260618_113558",
"turn_id": "20260618_113615",
"user_message": {
"role": "user",
"content": "调用一次todolist生成一份详细的做西红柿炒鸡蛋计划,并逐步更新这份计划"
},
"tool_calls": [
{
"name": "todo_list",
"args": {
"steps": [
"准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量",
"处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用",
"热锅倒油:开中火加热炒锅,倒入适量食用油至微热",
"炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用",
"炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)",
"混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁",
"出锅装盘:撒上葱花点缀,即可享用"
]
},
"result_text": "{\"__todo_list__\": true, \"data\": {\"steps\": [\"\\u51c6\\u5907\\u98df\\u6750\\uff1a\\u897f\\u7ea2\\u67ff2-3\\u4e2a\\uff0c\\u9e21\\u86cb3\\u4e2a\\uff0c\\u8471\\u82b1\\u5c11\\u8bb8\\uff0c\\u76d0\\u3001\\u7cd6\\u3001\\u98df\\u7528\\u6cb9\\u9002\\u91cf\", \"\\u5904\\u7406\\u98df\\u6750\\uff1a\\u5c06\\u897f\\u7ea2\\u67ff\\u6d17\\u51c0\\u5207\\u5757\\uff1b\\u9e21\\u86cb\\u6253\\u5165\\u7897\\u4e2d\\u6405\\u6563\\u5907\\u7528\", \"\\u70ed\\u9505\\u5012\\u6cb9\\uff1a\\u5f00\\u4e2d\\u706b\\u52a0\\u70ed\\u7092\\u9505\\uff0c\\u5012\\u5165\\u9002\\u91cf\\u98df\\u7528\\u6cb9\\u81f3\\u5fae\\u70ed\", \"\\u7092\\u9e21\\u86cb\\uff1a\\u5012\\u5165\\u86cb\\u6db2\\uff0c\\u5feb\\u901f\\u5212\\u6563\\u81f3\\u51dd\\u56fa\\u540e\\u76db\\u51fa\\u5907\\u7528\", \"\\u7092\\u897f\\u7ea2\\u67ff\\uff1a\\u9505\\u4e2d\\u7559\\u5e95\\u6cb9\\uff0c\\u653e\\u5165\\u897f\\u7ea2\\u67ff\\u7ffb\\u7092\\u51fa\\u6c41\\uff08\\u53ef\\u52a0\\u5c11\\u8bb8\\u7cd6\\u63d0\\u9c9c\\uff09\", \"\\u6df7\\u5408\\u8c03\\u5473\\uff1a\\u5012\\u5165\\u7092\\u597d\\u7684\\u9e21\\u86cb\\uff0c\\u52a0\\u5165\\u9002\\u91cf\\u76d0\\uff0c\\u7ffb\\u7092\\u5747\\u5300\\u4f7f\\u9e21\\u86cb\\u5438\\u6ee1\\u6c64\\u6c41\", \"\\u51fa\\u9505\\u88c5\\u76d8\\uff1a\\u6492\\u4e0a\\u8471\\u82b1\\u70b9\\u7f00\\uff0c\\u5373\\u53ef\\u4eab\\u7528\"], \"done_steps\": []}}\n[Todo List]\n- [1/7] [Pending]: 准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量\n- [2/7] [Pending]: 处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用\n- [3/7] [Pending]: 热锅倒油:开中火加热炒锅,倒入适量食用油至微热\n- [4/7] [Pending]: 炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用\n- [5/7] [Pending]: 炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)\n- [6/7] [Pending]: 混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁\n- [7/7] [Pending]: 出锅装盘:撒上葱花点缀,即可享用",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": [
"准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量",
"处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用",
"热锅倒油:开中火加热炒锅,倒入适量食用油至微热",
"炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用",
"炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)",
"混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁",
"出锅装盘:撒上葱花点缀,即可享用"
],
"done_step": 1
},
"result_text": "{\"__todo_list__\": true, \"data\": {\"steps\": [\"\\u51c6\\u5907\\u98df\\u6750\\uff1a\\u897f\\u7ea2\\u67ff2-3\\u4e2a\\uff0c\\u9e21\\u86cb3\\u4e2a\\uff0c\\u8471\\u82b1\\u5c11\\u8bb8\\uff0c\\u76d0\\u3001\\u7cd6\\u3001\\u98df\\u7528\\u6cb9\\u9002\\u91cf\", \"\\u5904\\u7406\\u98df\\u6750\\uff1a\\u5c06\\u897f\\u7ea2\\u67ff\\u6d17\\u51c0\\u5207\\u5757\\uff1b\\u9e21\\u86cb\\u6253\\u5165\\u7897\\u4e2d\\u6405\\u6563\\u5907\\u7528\", \"\\u70ed\\u9505\\u5012\\u6cb9\\uff1a\\u5f00\\u4e2d\\u706b\\u52a0\\u70ed\\u7092\\u9505\\uff0c\\u5012\\u5165\\u9002\\u91cf\\u98df\\u7528\\u6cb9\\u81f3\\u5fae\\u70ed\", \"\\u7092\\u9e21\\u86cb\\uff1a\\u5012\\u5165\\u86cb\\u6db2\\uff0c\\u5feb\\u901f\\u5212\\u6563\\u81f3\\u51dd\\u56fa\\u540e\\u76db\\u51fa\\u5907\\u7528\", \"\\u7092\\u897f\\u7ea2\\u67ff\\uff1a\\u9505\\u4e2d\\u7559\\u5e95\\u6cb9\\uff0c\\u653e\\u5165\\u897f\\u7ea2\\u67ff\\u7ffb\\u7092\\u51fa\\u6c41\\uff08\\u53ef\\u52a0\\u5c11\\u8bb8\\u7cd6\\u63d0\\u9c9c\\uff09\", \"\\u6df7\\u5408\\u8c03\\u5473\\uff1a\\u5012\\u5165\\u7092\\u597d\\u7684\\u9e21\\u86cb\\uff0c\\u52a0\\u5165\\u9002\\u91cf\\u76d0\\uff0c\\u7ffb\\u7092\\u5747\\u5300\\u4f7f\\u9e21\\u86cb\\u5438\\u6ee1\\u6c64\\u6c41\", \"\\u51fa\\u9505\\u88c5\\u76d8\\uff1a\\u6492\\u4e0a\\u8471\\u82b1\\u70b9\\u7f00\\uff0c\\u5373\\u53ef\\u4eab\\u7528\"], \"done_steps\": [0]}}\n[Todo List]\n- [1/7] [Done]: 准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量\n- [2/7] [Pending]: 处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用\n- [3/7] [Pending]: 热锅倒油:开中火加热炒锅,倒入适量食用油至微热\n- [4/7] [Pending]: 炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用\n- [5/7] [Pending]: 炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)\n- [6/7] [Pending]: 混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁\n- [7/7] [Pending]: 出锅装盘:撒上葱花点缀,即可享用",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": [
"准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量",
"处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用",
"热锅倒油:开中火加热炒锅,倒入适量食用油至微热",
"炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用",
"炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)",
"混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁",
"出锅装盘:撒上葱花点缀,即可享用"
],
"done_step": 2
},
"result_text": "{\"__todo_list__\": true, \"data\": {\"steps\": [\"\\u51c6\\u5907\\u98df\\u6750\\uff1a\\u897f\\u7ea2\\u67ff2-3\\u4e2a\\uff0c\\u9e21\\u86cb3\\u4e2a\\uff0c\\u8471\\u82b1\\u5c11\\u8bb8\\uff0c\\u76d0\\u3001\\u7cd6\\u3001\\u98df\\u7528\\u6cb9\\u9002\\u91cf\", \"\\u5904\\u7406\\u98df\\u6750\\uff1a\\u5c06\\u897f\\u7ea2\\u67ff\\u6d17\\u51c0\\u5207\\u5757\\uff1b\\u9e21\\u86cb\\u6253\\u5165\\u7897\\u4e2d\\u6405\\u6563\\u5907\\u7528\", \"\\u70ed\\u9505\\u5012\\u6cb9\\uff1a\\u5f00\\u4e2d\\u706b\\u52a0\\u70ed\\u7092\\u9505\\uff0c\\u5012\\u5165\\u9002\\u91cf\\u98df\\u7528\\u6cb9\\u81f3\\u5fae\\u70ed\", \"\\u7092\\u9e21\\u86cb\\uff1a\\u5012\\u5165\\u86cb\\u6db2\\uff0c\\u5feb\\u901f\\u5212\\u6563\\u81f3\\u51dd\\u56fa\\u540e\\u76db\\u51fa\\u5907\\u7528\", \"\\u7092\\u897f\\u7ea2\\u67ff\\uff1a\\u9505\\u4e2d\\u7559\\u5e95\\u6cb9\\uff0c\\u653e\\u5165\\u897f\\u7ea2\\u67ff\\u7ffb\\u7092\\u51fa\\u6c41\\uff08\\u53ef\\u52a0\\u5c11\\u8bb8\\u7cd6\\u63d0\\u9c9c\\uff09\", \"\\u6df7\\u5408\\u8c03\\u5473\\uff1a\\u5012\\u5165\\u7092\\u597d\\u7684\\u9e21\\u86cb\\uff0c\\u52a0\\u5165\\u9002\\u91cf\\u76d0\\uff0c\\u7ffb\\u7092\\u5747\\u5300\\u4f7f\\u9e21\\u86cb\\u5438\\u6ee1\\u6c64\\u6c41\", \"\\u51fa\\u9505\\u88c5\\u76d8\\uff1a\\u6492\\u4e0a\\u8471\\u82b1\\u70b9\\u7f00\\uff0c\\u5373\\u53ef\\u4eab\\u7528\"], \"done_steps\": [0, 1]}}\n[Todo List]\n- [1/7] [Done]: 准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量\n- [2/7] [Done]: 处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用\n- [3/7] [Pending]: 热锅倒油:开中火加热炒锅,倒入适量食用油至微热\n- [4/7] [Pending]: 炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用\n- [5/7] [Pending]: 炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)\n- [6/7] [Pending]: 混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁\n- [7/7] [Pending]: 出锅装盘:撒上葱花点缀,即可享用",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": [
"准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量",
"处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用",
"热锅倒油:开中火加热炒锅,倒入适量食用油至微热",
"炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用",
"炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)",
"混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁",
"出锅装盘:撒上葱花点缀,即可享用"
],
"done_step": 3
},
"result_text": "{\"__todo_list__\": true, \"data\": {\"steps\": [\"\\u51c6\\u5907\\u98df\\u6750\\uff1a\\u897f\\u7ea2\\u67ff2-3\\u4e2a\\uff0c\\u9e21\\u86cb3\\u4e2a\\uff0c\\u8471\\u82b1\\u5c11\\u8bb8\\uff0c\\u76d0\\u3001\\u7cd6\\u3001\\u98df\\u7528\\u6cb9\\u9002\\u91cf\", \"\\u5904\\u7406\\u98df\\u6750\\uff1a\\u5c06\\u897f\\u7ea2\\u67ff\\u6d17\\u51c0\\u5207\\u5757\\uff1b\\u9e21\\u86cb\\u6253\\u5165\\u7897\\u4e2d\\u6405\\u6563\\u5907\\u7528\", \"\\u70ed\\u9505\\u5012\\u6cb9\\uff1a\\u5f00\\u4e2d\\u706b\\u52a0\\u70ed\\u7092\\u9505\\uff0c\\u5012\\u5165\\u9002\\u91cf\\u98df\\u7528\\u6cb9\\u81f3\\u5fae\\u70ed\", \"\\u7092\\u9e21\\u86cb\\uff1a\\u5012\\u5165\\u86cb\\u6db2\\uff0c\\u5feb\\u901f\\u5212\\u6563\\u81f3\\u51dd\\u56fa\\u540e\\u76db\\u51fa\\u5907\\u7528\", \"\\u7092\\u897f\\u7ea2\\u67ff\\uff1a\\u9505\\u4e2d\\u7559\\u5e95\\u6cb9\\uff0c\\u653e\\u5165\\u897f\\u7ea2\\u67ff\\u7ffb\\u7092\\u51fa\\u6c41\\uff08\\u53ef\\u52a0\\u5c11\\u8bb8\\u7cd6\\u63d0\\u9c9c\\uff09\", \"\\u6df7\\u5408\\u8c03\\u5473\\uff1a\\u5012\\u5165\\u7092\\u597d\\u7684\\u9e21\\u86cb\\uff0c\\u52a0\\u5165\\u9002\\u91cf\\u76d0\\uff0c\\u7ffb\\u7092\\u5747\\u5300\\u4f7f\\u9e21\\u86cb\\u5438\\u6ee1\\u6c64\\u6c41\", \"\\u51fa\\u9505\\u88c5\\u76d8\\uff1a\\u6492\\u4e0a\\u8471\\u82b1\\u70b9\\u7f00\\uff0c\\u5373\\u53ef\\u4eab\\u7528\"], \"done_steps\": [0, 1, 2]}}\n[Todo List]\n- [1/7] [Done]: 准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量\n- [2/7] [Done]: 处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用\n- [3/7] [Done]: 热锅倒油:开中火加热炒锅,倒入适量食用油至微热\n- [4/7] [Pending]: 炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用\n- [5/7] [Pending]: 炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)\n- [6/7] [Pending]: 混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁\n- [7/7] [Pending]: 出锅装盘:撒上葱花点缀,即可享用",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": [
"准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量",
"处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用",
"热锅倒油:开中火加热炒锅,倒入适量食用油至微热",
"炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用",
"炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)",
"混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁",
"出锅装盘:撒上葱花点缀,即可享用"
],
"done_step": 4
},
"result_text": "{\"__todo_list__\": true, \"data\": {\"steps\": [\"\\u51c6\\u5907\\u98df\\u6750\\uff1a\\u897f\\u7ea2\\u67ff2-3\\u4e2a\\uff0c\\u9e21\\u86cb3\\u4e2a\\uff0c\\u8471\\u82b1\\u5c11\\u8bb8\\uff0c\\u76d0\\u3001\\u7cd6\\u3001\\u98df\\u7528\\u6cb9\\u9002\\u91cf\", \"\\u5904\\u7406\\u98df\\u6750\\uff1a\\u5c06\\u897f\\u7ea2\\u67ff\\u6d17\\u51c0\\u5207\\u5757\\uff1b\\u9e21\\u86cb\\u6253\\u5165\\u7897\\u4e2d\\u6405\\u6563\\u5907\\u7528\", \"\\u70ed\\u9505\\u5012\\u6cb9\\uff1a\\u5f00\\u4e2d\\u706b\\u52a0\\u70ed\\u7092\\u9505\\uff0c\\u5012\\u5165\\u9002\\u91cf\\u98df\\u7528\\u6cb9\\u81f3\\u5fae\\u70ed\", \"\\u7092\\u9e21\\u86cb\\uff1a\\u5012\\u5165\\u86cb\\u6db2\\uff0c\\u5feb\\u901f\\u5212\\u6563\\u81f3\\u51dd\\u56fa\\u540e\\u76db\\u51fa\\u5907\\u7528\", \"\\u7092\\u897f\\u7ea2\\u67ff\\uff1a\\u9505\\u4e2d\\u7559\\u5e95\\u6cb9\\uff0c\\u653e\\u5165\\u897f\\u7ea2\\u67ff\\u7ffb\\u7092\\u51fa\\u6c41\\uff08\\u53ef\\u52a0\\u5c11\\u8bb8\\u7cd6\\u63d0\\u9c9c\\uff09\", \"\\u6df7\\u5408\\u8c03\\u5473\\uff1a\\u5012\\u5165\\u7092\\u597d\\u7684\\u9e21\\u86cb\\uff0c\\u52a0\\u5165\\u9002\\u91cf\\u76d0\\uff0c\\u7ffb\\u7092\\u5747\\u5300\\u4f7f\\u9e21\\u86cb\\u5438\\u6ee1\\u6c64\\u6c41\", \"\\u51fa\\u9505\\u88c5\\u76d8\\uff1a\\u6492\\u4e0a\\u8471\\u82b1\\u70b9\\u7f00\\uff0c\\u5373\\u53ef\\u4eab\\u7528\"], \"done_steps\": [0, 1, 2, 3]}}\n[Todo List]\n- [1/7] [Done]: 准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量\n- [2/7] [Done]: 处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用\n- [3/7] [Done]: 热锅倒油:开中火加热炒锅,倒入适量食用油至微热\n- [4/7] [Done]: 炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用\n- [5/7] [Pending]: 炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)\n- [6/7] [Pending]: 混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁\n- [7/7] [Pending]: 出锅装盘:撒上葱花点缀,即可享用",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": [
"准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量",
"处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用",
"热锅倒油:开中火加热炒锅,倒入适量食用油至微热",
"炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用",
"炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)",
"混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁",
"出锅装盘:撒上葱花点缀,即可享用"
],
"done_step": 5
},
"result_text": "{\"__todo_list__\": true, \"data\": {\"steps\": [\"\\u51c6\\u5907\\u98df\\u6750\\uff1a\\u897f\\u7ea2\\u67ff2-3\\u4e2a\\uff0c\\u9e21\\u86cb3\\u4e2a\\uff0c\\u8471\\u82b1\\u5c11\\u8bb8\\uff0c\\u76d0\\u3001\\u7cd6\\u3001\\u98df\\u7528\\u6cb9\\u9002\\u91cf\", \"\\u5904\\u7406\\u98df\\u6750\\uff1a\\u5c06\\u897f\\u7ea2\\u67ff\\u6d17\\u51c0\\u5207\\u5757\\uff1b\\u9e21\\u86cb\\u6253\\u5165\\u7897\\u4e2d\\u6405\\u6563\\u5907\\u7528\", \"\\u70ed\\u9505\\u5012\\u6cb9\\uff1a\\u5f00\\u4e2d\\u706b\\u52a0\\u70ed\\u7092\\u9505\\uff0c\\u5012\\u5165\\u9002\\u91cf\\u98df\\u7528\\u6cb9\\u81f3\\u5fae\\u70ed\", \"\\u7092\\u9e21\\u86cb\\uff1a\\u5012\\u5165\\u86cb\\u6db2\\uff0c\\u5feb\\u901f\\u5212\\u6563\\u81f3\\u51dd\\u56fa\\u540e\\u76db\\u51fa\\u5907\\u7528\", \"\\u7092\\u897f\\u7ea2\\u67ff\\uff1a\\u9505\\u4e2d\\u7559\\u5e95\\u6cb9\\uff0c\\u653e\\u5165\\u897f\\u7ea2\\u67ff\\u7ffb\\u7092\\u51fa\\u6c41\\uff08\\u53ef\\u52a0\\u5c11\\u8bb8\\u7cd6\\u63d0\\u9c9c\\uff09\", \"\\u6df7\\u5408\\u8c03\\u5473\\uff1a\\u5012\\u5165\\u7092\\u597d\\u7684\\u9e21\\u86cb\\uff0c\\u52a0\\u5165\\u9002\\u91cf\\u76d0\\uff0c\\u7ffb\\u7092\\u5747\\u5300\\u4f7f\\u9e21\\u86cb\\u5438\\u6ee1\\u6c64\\u6c41\", \"\\u51fa\\u9505\\u88c5\\u76d8\\uff1a\\u6492\\u4e0a\\u8471\\u82b1\\u70b9\\u7f00\\uff0c\\u5373\\u53ef\\u4eab\\u7528\"], \"done_steps\": [0, 1, 2, 3, 4]}}\n[Todo List]\n- [1/7] [Done]: 准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量\n- [2/7] [Done]: 处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用\n- [3/7] [Done]: 热锅倒油:开中火加热炒锅,倒入适量食用油至微热\n- [4/7] [Done]: 炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用\n- [5/7] [Done]: 炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)\n- [6/7] [Pending]: 混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁\n- [7/7] [Pending]: 出锅装盘:撒上葱花点缀,即可享用",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": [
"准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量",
"处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用",
"热锅倒油:开中火加热炒锅,倒入适量食用油至微热",
"炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用",
"炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)",
"混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁",
"出锅装盘:撒上葱花点缀,即可享用"
],
"done_step": 6
},
"result_text": "{\"__todo_list__\": true, \"data\": {\"steps\": [\"\\u51c6\\u5907\\u98df\\u6750\\uff1a\\u897f\\u7ea2\\u67ff2-3\\u4e2a\\uff0c\\u9e21\\u86cb3\\u4e2a\\uff0c\\u8471\\u82b1\\u5c11\\u8bb8\\uff0c\\u76d0\\u3001\\u7cd6\\u3001\\u98df\\u7528\\u6cb9\\u9002\\u91cf\", \"\\u5904\\u7406\\u98df\\u6750\\uff1a\\u5c06\\u897f\\u7ea2\\u67ff\\u6d17\\u51c0\\u5207\\u5757\\uff1b\\u9e21\\u86cb\\u6253\\u5165\\u7897\\u4e2d\\u6405\\u6563\\u5907\\u7528\", \"\\u70ed\\u9505\\u5012\\u6cb9\\uff1a\\u5f00\\u4e2d\\u706b\\u52a0\\u70ed\\u7092\\u9505\\uff0c\\u5012\\u5165\\u9002\\u91cf\\u98df\\u7528\\u6cb9\\u81f3\\u5fae\\u70ed\", \"\\u7092\\u9e21\\u86cb\\uff1a\\u5012\\u5165\\u86cb\\u6db2\\uff0c\\u5feb\\u901f\\u5212\\u6563\\u81f3\\u51dd\\u56fa\\u540e\\u76db\\u51fa\\u5907\\u7528\", \"\\u7092\\u897f\\u7ea2\\u67ff\\uff1a\\u9505\\u4e2d\\u7559\\u5e95\\u6cb9\\uff0c\\u653e\\u5165\\u897f\\u7ea2\\u67ff\\u7ffb\\u7092\\u51fa\\u6c41\\uff08\\u53ef\\u52a0\\u5c11\\u8bb8\\u7cd6\\u63d0\\u9c9c\\uff09\", \"\\u6df7\\u5408\\u8c03\\u5473\\uff1a\\u5012\\u5165\\u7092\\u597d\\u7684\\u9e21\\u86cb\\uff0c\\u52a0\\u5165\\u9002\\u91cf\\u76d0\\uff0c\\u7ffb\\u7092\\u5747\\u5300\\u4f7f\\u9e21\\u86cb\\u5438\\u6ee1\\u6c64\\u6c41\", \"\\u51fa\\u9505\\u88c5\\u76d8\\uff1a\\u6492\\u4e0a\\u8471\\u82b1\\u70b9\\u7f00\\uff0c\\u5373\\u53ef\\u4eab\\u7528\"], \"done_steps\": [0, 1, 2, 3, 4, 5]}}\n[Todo List]\n- [1/7] [Done]: 准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量\n- [2/7] [Done]: 处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用\n- [3/7] [Done]: 热锅倒油:开中火加热炒锅,倒入适量食用油至微热\n- [4/7] [Done]: 炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用\n- [5/7] [Done]: 炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)\n- [6/7] [Done]: 混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁\n- [7/7] [Pending]: 出锅装盘:撒上葱花点缀,即可享用",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": [
"准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量",
"处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用",
"热锅倒油:开中火加热炒锅,倒入适量食用油至微热",
"炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用",
"炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)",
"混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁",
"出锅装盘:撒上葱花点缀,即可享用"
],
"done_step": 7
},
"result_text": "{\"__todo_list__\": true, \"data\": {\"steps\": [\"\\u51c6\\u5907\\u98df\\u6750\\uff1a\\u897f\\u7ea2\\u67ff2-3\\u4e2a\\uff0c\\u9e21\\u86cb3\\u4e2a\\uff0c\\u8471\\u82b1\\u5c11\\u8bb8\\uff0c\\u76d0\\u3001\\u7cd6\\u3001\\u98df\\u7528\\u6cb9\\u9002\\u91cf\", \"\\u5904\\u7406\\u98df\\u6750\\uff1a\\u5c06\\u897f\\u7ea2\\u67ff\\u6d17\\u51c0\\u5207\\u5757\\uff1b\\u9e21\\u86cb\\u6253\\u5165\\u7897\\u4e2d\\u6405\\u6563\\u5907\\u7528\", \"\\u70ed\\u9505\\u5012\\u6cb9\\uff1a\\u5f00\\u4e2d\\u706b\\u52a0\\u70ed\\u7092\\u9505\\uff0c\\u5012\\u5165\\u9002\\u91cf\\u98df\\u7528\\u6cb9\\u81f3\\u5fae\\u70ed\", \"\\u7092\\u9e21\\u86cb\\uff1a\\u5012\\u5165\\u86cb\\u6db2\\uff0c\\u5feb\\u901f\\u5212\\u6563\\u81f3\\u51dd\\u56fa\\u540e\\u76db\\u51fa\\u5907\\u7528\", \"\\u7092\\u897f\\u7ea2\\u67ff\\uff1a\\u9505\\u4e2d\\u7559\\u5e95\\u6cb9\\uff0c\\u653e\\u5165\\u897f\\u7ea2\\u67ff\\u7ffb\\u7092\\u51fa\\u6c41\\uff08\\u53ef\\u52a0\\u5c11\\u8bb8\\u7cd6\\u63d0\\u9c9c\\uff09\", \"\\u6df7\\u5408\\u8c03\\u5473\\uff1a\\u5012\\u5165\\u7092\\u597d\\u7684\\u9e21\\u86cb\\uff0c\\u52a0\\u5165\\u9002\\u91cf\\u76d0\\uff0c\\u7ffb\\u7092\\u5747\\u5300\\u4f7f\\u9e21\\u86cb\\u5438\\u6ee1\\u6c64\\u6c41\", \"\\u51fa\\u9505\\u88c5\\u76d8\\uff1a\\u6492\\u4e0a\\u8471\\u82b1\\u70b9\\u7f00\\uff0c\\u5373\\u53ef\\u4eab\\u7528\"], \"done_steps\": [0, 1, 2, 3, 4, 5, 6]}}\n[Todo List]\n- [1/7] [Done]: 准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量\n- [2/7] [Done]: 处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用\n- [3/7] [Done]: 热锅倒油:开中火加热炒锅,倒入适量食用油至微热\n- [4/7] [Done]: 炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用\n- [5/7] [Done]: 炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)\n- [6/7] [Done]: 混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁\n- [7/7] [Done]: 出锅装盘:撒上葱花点缀,即可享用",
"result_files": []
}
],
"assistant_response": "太棒了!西红柿炒鸡蛋计划已全部完成。\n\n**最终状态:**\n- [x] 准备食材:西红柿2-3个,鸡蛋3个,葱花少许,盐、糖、食用油适量\n- [x] 处理食材:将西红柿洗净切块;鸡蛋打入碗中搅散备用\n- [x] 热锅倒油:开中火加热炒锅,倒入适量食用油至微热\n- [x] 炒鸡蛋:倒入蛋液,快速划散至凝固后盛出备用\n- [x] 炒西红柿:锅中留底油,放入西红柿翻炒出汁(可加少许糖提鲜)\n- [x] 混合调味:倒入炒好的鸡蛋,加入适量盐,翻炒均匀使鸡蛋吸满汤汁\n- [x] 出锅装盘:撒上葱花点缀,即可享用\n\n现在你可以享受这道美味的家常菜了!🍅🥚",
"timestamp": "20260618_113615"
}
@@ -1,84 +0,0 @@
{
"session_id": "20260618_120438",
"turn_id": "20260618_120441",
"user_message": {
"role": "user",
"content": "调用一次todolist生成一份详细的做西红柿炒鸡蛋计划,并逐步更新这份计划"
},
"tool_calls": [
{
"name": "todo_list",
"args": {
"steps": "[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]",
"done_step": -1
},
"result_text": "Error invoking tool 'todo_list' with kwargs {'steps': '[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]', 'done_step': -1} with error:\n steps: Input should be a valid list\n Please fix the error and try again.",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": "[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]",
"done_step": -1
},
"result_text": "Error invoking tool 'todo_list' with kwargs {'steps': '[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]', 'done_step': -1} with error:\n steps: Input should be a valid list\n Please fix the error and try again.",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": "[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]",
"done_step": 1
},
"result_text": "Error invoking tool 'todo_list' with kwargs {'steps': '[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]', 'done_step': 1} with error:\n steps: Input should be a valid list\n Please fix the error and try again.",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": "[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]",
"done_step": 1
},
"result_text": "Error invoking tool 'todo_list' with kwargs {'steps': '[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]', 'done_step': 1} with error:\n steps: Input should be a valid list\n Please fix the error and try again.",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": "[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]",
"done_step": 1
},
"result_text": "Error invoking tool 'todo_list' with kwargs {'steps': '[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]', 'done_step': 1} with error:\n steps: Input should be a valid list\n Please fix the error and try again.",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": "[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]",
"done_step": 1
},
"result_text": "Error invoking tool 'todo_list' with kwargs {'steps': '[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]', 'done_step': 1} with error:\n steps: Input should be a valid list\n Please fix the error and try again.",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": "[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]",
"done_step": 1
},
"result_text": "Error invoking tool 'todo_list' with kwargs {'steps': '[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]', 'done_step': 1} with error:\n steps: Input should be a valid list\n Please fix the error and try again.",
"result_files": []
},
{
"name": "todo_list",
"args": {
"steps": "[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]",
"done_step": 1
},
"result_text": "Error invoking tool 'todo_list' with kwargs {'steps': '[\"准备食材:2-3个西红柿、2-3个鸡蛋、葱花、盐、糖、食用油\", \"处理西红柿:洗净,去蒂,切成小块备用\", \"打散鸡蛋:将鸡蛋打入碗中,加入少许盐,充分搅打均匀\", \"热锅凉油(炒蛋):锅中倒适量油,油热后倒入蛋液,凝固后盛出备用\", \"炒西红柿:锅中再加少许油,放入西红柿块翻炒至出汁软烂\", \"调味:根据口味加入适量的盐和糖,翻炒均匀\", \"混合:将之前炒好的鸡蛋倒回锅中,与西红柿混合翻炒均匀\", \"出锅:撒上葱花,装盘即可\"]', 'done_step': 1} with error:\n steps: Input should be a valid list\n Please fix the error and try again.",
"result_files": []
}
],
"assistant_response": "",
"timestamp": "20260618_120441"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

@@ -1,23 +0,0 @@
{
"session_id": "20260618_173653",
"turn_id": "20260618_173727",
"user_message": {
"role": "user",
"content": "帮我关掉DeepSeek开放平台的标签页"
},
"tool_calls": [
{
"name": "gui_tool",
"args": {
"action": "click",
"element_description": "DeepSeek开放平台的标签页关闭按钮(X)"
},
"result_text": "Clicked target. grounded (308,21)",
"result_files": [
"_artifact_call_fd502781107945c7a6880635_0.png"
]
}
],
"assistant_response": "已经帮您关闭了 DeepSeek 开放平台的标签页。现在浏览器显示的是 minor - Chatbot 页面。",
"timestamp": "20260618_173727"
}
@@ -0,0 +1,22 @@
{
"session_id": "20260620_174454",
"turn_id": "20260620_174456",
"user_message": {
"role": "user",
"content": "帮我点击加号新建标签页"
},
"tool_calls": [
{
"name": "gui_tool",
"args": {
"action": "click",
"element_description": "浏览器标签栏右侧的加号图标,用于新建标签页"
},
"result_text": "",
"result_files": [],
"result_images": []
}
],
"assistant_response": "已为您点击新建标签页。现在应该已经打开了一个新的空白标签页。",
"timestamp": "20260620_174456"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

@@ -0,0 +1,23 @@
{
"session_id": "20260620_183029",
"turn_id": "20260620_183034",
"user_message": {
"role": "user",
"content": "截张图看看我在干啥,如果读不到图片请直接告诉我"
},
"tool_calls": [
{
"name": "gui_tool",
"args": {
"action": "screenshot"
},
"result_text": "",
"result_files": [
"_artifact_gui_tool_0_0.png"
],
"result_images": []
}
],
"assistant_response": "根据截图,你正在使用 **DeepSeek 开放平台**(platform.deepseek.com)的网页界面。\n\n具体来说,你当前查看的是 **“用量信息”** 页面。页面上显示了以下关键信息:\n* **充值余额**:¥22.77 CNY\n* **六月消费**(按 UTC+0 时间):¥17.22 CNY\n* **每月用量图表**:展示了近期(6月1日至6月30日)的消费金额波动。\n* **模型使用情况**:下方还列出了 `deepseek-v4-pro` 模型的 API 请求次数和 Tokens 消耗量。\n\n简单来说,你正在查看自己在 DeepSeek 平台上的账户余额、消费记录以及 API 的使用情况。",
"timestamp": "20260620_183034"
}
@@ -0,0 +1,23 @@
{
"session_id": "20260620_183029",
"turn_id": "20260620_183128",
"user_message": {
"role": "user",
"content": "你现在的对话记录中有图片吗"
},
"tool_calls": [
{
"name": "gui_tool",
"args": {
"action": "screenshot"
},
"result_text": "",
"result_files": [
"_artifact_gui_tool_0_0.png"
],
"result_images": []
}
],
"assistant_response": "根据刚才截取的屏幕截图,我**没有**在当前的对话记录中看到任何图片。\n\n这张截图显示的是你正在浏览 **DeepSeek 开放平台** 的“用量信息”页面,主要内容包括:\n1. **充值余额**:¥22.77 CNY\n2. **六月消费**(按 UTC+0 时间):¥17.22 CNY\n3. **每月用量图表**:展示了近期每天的消费金额波动。\n4. **模型使用情况**:下方列出了 `deepseek-v4-pro` 模型的 API 请求次数和 Tokens 消耗量。\n\n所以,目前的对话中只有文字交互,并没有上传图片。",
"timestamp": "20260620_183128"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

@@ -0,0 +1,36 @@
{
"session_id": "20260620_205109",
"turn_id": "20260620_205218",
"user_message": {
"role": "user",
"content": "能不能帮我打开虎牙直播"
},
"tool_calls": [
{
"name": "browser_control",
"args": {
"action": "open",
"url": "https://www.huya.com"
},
"result_text": "已尝试打开 URL: https://www.huya.com",
"result_files": [
"_artifact_browser_control_0_0.png"
],
"result_images": []
},
{
"name": "browser_control",
"args": {
"action": "open",
"url": "https://www.huya.com"
},
"result_text": "已尝试打开 URL: https://www.huya.com",
"result_files": [
"_artifact_browser_control_1_0.png"
],
"result_images": []
}
],
"assistant_response": "虎牙直播已经成功打开了!可以看到:\n\n- 页面顶部显示\"虎牙直播\"的Logo\n- 当前正在播放主播\"王子酱\"的直播间\n- 页面下方展示了各种游戏分类,包括网游竞技(LOL、CS2等)、单机热游等\n- 右侧还有其他推荐的主播和直播间\n\n你现在可以浏览你感兴趣的直播内容了。如果你想观看特定的主播或游戏类别,可以直接点击相应的选项。",
"timestamp": "20260620_205218"
}
Loaded 100 of 142 files, more files were not shown because too many files have changed in this diff. Show more