feat: 会话内 LLM 自判 goal / 自动化标记工具,不靠关键词

agent 在回合输出里写 goal-convert 块,worker 在轮次边界
排成 /goal 自后续消息、走已有 followup 转换路径把本会话
转成 goal;写 automation-create 块,worker 在轮次边界
创建自动化定义(权限 create_task、配额整轮门、创建人跟
父任务走、name 缺失自动生成、首次时刻已过去单块拒绝、
bind heartbeat 可绑回本会话)。

automations 新增 first_run_at / run_once:首次时刻只管
首次、之后按间隔算;只跑一次跑过后 is_due / due / claim
三处都不再到期(SQL 到期条件与 Python 口径共用同一
_DUE_SQL);API 创建与更新同步接受这两个字段。

刻意不向 LLM 自动注入工具指南:避免 prompt 臃肿,格式
只写进 docs/marker-tools.md 与 README,需要时由用户在
会话里手动告诉 agent;服务端不按关键词再猜意图。

单测 cloud/tests/test_session_goal_automation.py 12 项,
相关回归 218 项全过。
This commit is contained in:
host committed 2026-10-30 07:15:05 +08:00
1 parent f1aab5415c
commit e81ba8d2bf
8 files changed
+892 -51

No files matched your search

+18
View File
@@ -23,6 +23,10 @@ import sys
import time
from cloud.marker_tools import extract_quota_status as _extract_quota_status
from cloud.marker_tools import extract_automation_creates as \
_extract_automation_creates
from cloud.marker_tools import extract_goal_converts as \
_extract_goal_converts
from cloud.marker_tools import extract_task_cancels as _extract_task_cancels
from cloud.marker_tools import extract_task_costs as _extract_task_costs
from cloud.marker_tools import extract_task_creates as _extract_task_creates
@@ -418,6 +422,8 @@ class LocalExecutor(Executor):
todo_lists = []
todo_creates = []
todo_updates = []
goal_converts = []
automation_creates = []
turn_id = None
root_turn_id = None
parsed = None
@@ -465,6 +471,9 @@ class LocalExecutor(Executor):
todo_lists = _extract_todo_lists(parsed.get("text"))
todo_creates = _extract_todo_creates(parsed.get("text"))
todo_updates = _extract_todo_updates(parsed.get("text"))
goal_converts = _extract_goal_converts(parsed.get("text"))
automation_creates = _extract_automation_creates(
parsed.get("text"))
else:
host_status = None
else:
@@ -496,6 +505,8 @@ class LocalExecutor(Executor):
"todo_lists": todo_lists,
"todo_creates": todo_creates,
"todo_updates": todo_updates,
"goal_converts": goal_converts,
"automation_creates": automation_creates,
"turn_id": turn_id,
"root_turn_id": root_turn_id,
}
@@ -1944,6 +1955,8 @@ def _parse_host_result(task_id, fake):
todo_lists = []
todo_creates = []
todo_updates = []
goal_converts = []
automation_creates = []
turn_id = None
root_turn_id = None
parsed = None
@@ -1978,6 +1991,9 @@ def _parse_host_result(task_id, fake):
todo_lists = _extract_todo_lists(parsed.get("text"))
todo_creates = _extract_todo_creates(parsed.get("text"))
todo_updates = _extract_todo_updates(parsed.get("text"))
goal_converts = _extract_goal_converts(parsed.get("text"))
automation_creates = _extract_automation_creates(
parsed.get("text"))
# 任务列表显示 turn 用:与 Local 版同款语义,取不到
# 时保持 None,worker 写回时不覆盖旧值。
turn_id = parsed.get("turn_id")
@@ -2006,6 +2022,8 @@ def _parse_host_result(task_id, fake):
"todo_lists": todo_lists,
"todo_creates": todo_creates,
"todo_updates": todo_updates,
"goal_converts": goal_converts,
"automation_creates": automation_creates,
"turn_id": turn_id,
"root_turn_id": root_turn_id,
}