backend/frontend/runtime: 训练面板 / session 隔离 / agent runtime 调整

- backend/api/server.py:训练 step-detail / pipeline 卡片排序逻辑
- frontend:thread-list / thread / training-pipeline-panel / step-detail-sheet 配套调整,新增 metrics-chart-panel
- src/agent_*:tool spec / runtime / prompting 配套
- .gitignore 加 .logs/

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
hupenglong1
2026-05-25 11:43:10 +08:00
parent 57f5b60a3e
commit f068311cac
17 changed files with 1571 additions and 270 deletions
+2 -2
View File
@@ -162,8 +162,8 @@ def get_doing_tasks_section() -> str:
'不要为了单次操作创建 helper 或抽象。优先使用能完整解决问题的最简单实现。',
'除非确实需要新文件,否则优先编辑现有文件。',
'对于文件解析、表格转换、JSON 或 JSONL 处理、日志分析、批量校验、数据抽样等任务,如果小型 Python 脚本比手工文本处理更可靠,可以编写小型 Python 脚本。',
'小脚本应短小、可读,并明确输入和输出。需要执行 Python 代码或 Python 脚本时,使用 python_exec;不要通过 bash 执行 python、python3 或 .venv/bin/python',
'一次性 Python 分析优先直接传给 python_exec.code,不要为了临时分析创建项目文件',
'小脚本应短小、可读,并明确输入和输出。需要执行 Python 时,把代码写到 session/scratchpad 下的 .py 文件,再用 bash 跑 `python3 -u <script> 2>&1 | tee <log>``-u` 关 stdout 缓冲、`tee` 让进度行实时落盘,超时被 kill 时仍能 tail 日志看到死在哪。不要把多行 Python 代码以 `-c` 字符串方式塞进 bash command',
'一次性 Python 分析也走脚本文件 + bash,不要为了临时分析在项目根目录创建脚本,scratchpad 是默认临时区',
'如果确实需要临时脚本、缓存或中间产物,必须写入当前 session/scratchpad;交付产物必须优先写入当前 session/output。',
'只有用户明确要求长期复用或该脚本属于产品代码时,才把 Python 脚本加入项目源码目录。',
'当事情失败时,先诊断原因再改变方向。不要对同一个失败动作反复循环。',
+3 -3
View File
@@ -1620,9 +1620,9 @@ class LocalCodingAgent:
'请回复“继续”,我会要求模型重新生成合法 JSON 参数;'
'如果是 write_file 写短文本/Markdown,应改用 content_lines'
'如果是很小的 JSON/JSONL/CSV,可用 json_content、jsonl_records 或 csv_rows'
'如果是脚本、长文本、大 JSON、JSONL、CSV 或生成数据,应直接改用 python_exec 写文件'
'如果是生成/转换结构化数据,应优先调用对应 skill 脚本或 python_exec'
'不要把大段内容直接塞进工具参数bash 仅作为最后兜底'
'如果是脚本、长文本、大 JSON、JSONL、CSV 或生成数据,应改用 bash 配合 quoted heredoc 写文件'
'或先 write_file 落地一个小 .py 再用 bash 跑;'
'不要把大段内容直接塞进工具参数。'
) from exc
if not isinstance(arguments, dict):
raise OpenAICompatError(
+7 -49
View File
@@ -10,51 +10,6 @@ def build_execution_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool
"""构建本地命令、Python 执行与短等待工具声明。"""
return [
AgentTool(
name='python_exec',
description=(
'优先用本工具执行小型 Python 代码或项目内 Python 脚本,用于结构化文件分析、'
'JSON/JSONL 处理、批量校验、数据抽样和快速计算。默认使用当前用户独立 Python venv'
'不要用 bash 运行 python/python3/.venv/bin/python。不要用本工具安装依赖。'
'缺包时应向用户确认后再处理依赖。一次性分析优先传 code;项目或 skill 内已有脚本优先传 script_path'
'不要在 code 里用 subprocess 二次调用 Python 脚本。如需写临时文件,'
'必须写入环境变量 PYTHON_EXEC_SCRATCHPAD 指向的会话隔离目录,'
'不要在项目根目录创建临时 .py 脚本。'
),
parameters={
'type': 'object',
'properties': {
'code': {
'type': 'string',
'description': '要通过 python -c 执行的 Python 代码。code 和 script_path 必须二选一;一次性分析优先使用 code。',
},
'script_path': {
'type': 'string',
'description': '工作区内已有、需要长期复用的 Python 脚本路径。code 和 script_path 必须二选一;不要为一次性分析在项目根目录新建脚本。',
},
'args': {
'type': 'array',
'items': {'type': 'string'},
'description': '传给脚本的命令行参数。仅在 script_path 模式下使用。',
},
'stdin': {
'type': 'string',
'description': '可选标准输入内容。',
},
'timeout_seconds': {
'type': 'number',
'minimum': 1,
'description': '可选超时时间,默认 30 秒。读大 CSV/JSONL、pandas 分析、批量校验、训练评测脚本等可能 >30s 的任务必须显式传值(常规 120-300、训练/长跑 600+)。',
},
'max_output_chars': {
'type': 'integer',
'minimum': 100,
'description': '可选输出截断长度,默认使用当前会话输出限制。',
},
},
},
handler=resolve_handler(handlers, 'python_exec', 'execution'),
),
AgentTool(
name='python_package',
description=(
@@ -94,10 +49,13 @@ def build_execution_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool
AgentTool(
name='bash',
description=(
'运行真实 shell 命令,例如系统命令、进程控制、git 只读检查用户已确认的依赖安装'
'不要用 bash 执行 python、python3、pip 或 .venv/bin/python;结构化文件分析、'
'JSON/JSONL 处理、批量校验、数据抽样和快速计算必须优先使用 python_exec。'
'Python 包安装必须优先使用 python_package。'
'运行真实 shell 命令,包括系统命令、进程控制、git 只读检查用户已确认的依赖安装'
'以及所有 Python 脚本执行。'
'执行 Python 时,把代码先写到 scratchpad 下的 .py 文件,'
'再用本工具跑 `python3 -u <script> 2>&1 | tee <log>`'
'`-u` 关掉 stdout 缓冲,`tee` 让进度行实时落盘,超时被 kill 时仍能 `tail` 日志看到死在哪个 phase。'
'不要把多行 Python 代码以 `-c` 字符串方式塞进 command。'
'Python 包安装必须优先使用 python_package;不要通过 bash 执行 pip。'
'需要等待远端长任务(>30s 的训练、文件落盘、外部 API 回调)时,'
'设置 run_in_background=true 让命令在后台 detach 跑、立刻返回 task_id'
'默认 wait_for_completion=true 时进程结束后会自动起新一轮把结果送回。'
+5 -5
View File
@@ -41,8 +41,8 @@ def build_file_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool]:
description=(
'Write or append a SMALL UTF-8 file inside the workspace. Creates parent directories when needed. '
'Use this for short notes, lightweight markdown, and small config files. '
'For Python scripts, JSONL, large JSON/CSV, generated datasets, or quote-heavy/multi-line content, prefer python_exec '
'to write the file with pathlib/json/csv; do not pack large content into tool arguments.'
'For Python scripts, JSONL, large JSON/CSV, generated datasets, or quote-heavy/multi-line content, prefer bash with a quoted heredoc '
"(e.g. `cat > scratchpad/foo.py <<'EOF' ... EOF`); do not pack large content into tool arguments."
),
parameters={
'type': 'object',
@@ -51,7 +51,7 @@ def build_file_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool]:
'content_lines': {
'type': 'array',
'items': {'type': 'string'},
'description': 'Lines to join with "\\n"; use only for short text/markdown or small scripts. For long scripts use python_exec to create the file.',
'description': 'Lines to join with "\\n"; use only for short text/markdown or small scripts. For long scripts use bash with a quoted heredoc to create the file.',
},
'content': {
'type': 'string',
@@ -63,12 +63,12 @@ def build_file_tools(handlers: Mapping[str, ToolHandler]) -> list[AgentTool]:
},
'json_content': {
'type': 'object',
'description': 'Small JSON value to serialize with ensure_ascii=false and indent=2. For large JSON use python_exec streaming write.',
'description': 'Small JSON value to serialize with ensure_ascii=false and indent=2. For large JSON write a small Python script to scratchpad and run it via bash.',
},
'jsonl_records': {
'type': 'array',
'items': {'type': 'object'},
'description': 'Small list of objects to serialize as compact JSONL. For more than a few dozen records or generated datasets use python_exec.',
'description': 'Small list of objects to serialize as compact JSONL. For more than a few dozen records or generated datasets, write a Python script to scratchpad and run it via bash.',
},
'csv_headers': {
'type': 'array',
-1
View File
@@ -117,7 +117,6 @@ def default_tool_registry() -> dict[str, AgentTool]:
'grep_search': _grep_search,
}),
*build_execution_tools({
'python_exec': _run_python_exec,
'python_package': _run_python_package,
'bash': _run_bash,
'bash_status': _run_bash_status,