任务列表 task-list 标记 + 首轮项目上下文注入
This commit is contained in:
1 parent
73288f08db
commit
2fd73c1121
5 files changed
+510
-13
No files matched your search
+75
-3
@@ -1,6 +1,6 @@
|
||||
"""任务内标记工具(marker tools):task-create / task-poll / task-read /
|
||||
wait-threads / task-cancel / task-retry / todo-list / todo-create /
|
||||
todo-update。
|
||||
todo-update / task-list。
|
||||
|
||||
设计(与 peer_messages、task_spawn 同款原则,不另起一套):
|
||||
|
||||
@@ -52,12 +52,16 @@ todo-update。
|
||||
查已完成项须显式传 status;写操作只在本项目内生效,
|
||||
跨项目待办一律按“不存在”拒绝;删除不走标记块(硬删除
|
||||
只在控制台 / REST DELETE 里做,避免模型误删整条)。
|
||||
- task-list:列出本项目任务(新建倒序),让模型在不知道
|
||||
任务 id 时也能分诊——查运行中与失败的任务、捡失败任务
|
||||
重试。不传 status 时查全部状态并附各状态计数;只读,
|
||||
跨项目任务不出现,报告最多列 limit 条(默认 20,上限 50)。
|
||||
|
||||
上限口径(本模块最终定的值,文档与代码一致):
|
||||
|
||||
- 每轮创建、轮询、取消、重试各最多 5 块;todo-list、
|
||||
todo-create、todo-update 各最多 5 块;wait 每轮最多
|
||||
2 块,每块最多 8 个目标。8 这个数是刻意与服务端
|
||||
todo-create、todo-update、task-list 各最多 5 块;wait
|
||||
每轮最多 2 块,每块最多 8 个目标。8 这个数是刻意与服务端
|
||||
POST /tasks/{id}/wait 的“一次最多 8 个线程”对齐的;
|
||||
spawn 分支原先的每块 10 个在此收紧到 8 个,不要再用 10。
|
||||
- 超时口径与服务端 /wait 不同,且是故意的:服务端 /wait
|
||||
@@ -122,6 +126,11 @@ MAX_TODO_UPDATES_PER_TURN = 5
|
||||
MAX_TODO_TITLE_CHARS = 500
|
||||
MAX_TODO_DESCRIPTION_CHARS = 20000
|
||||
MAX_TODO_QUERY_CHARS = 500
|
||||
TASK_STATUSES = ("queued", "running", "completed", "failed",
|
||||
"interrupted", "merged", "merge-failed")
|
||||
MAX_TASK_LISTS_PER_TURN = 5
|
||||
DEFAULT_TASK_LIST_LIMIT = 20
|
||||
MAX_TASK_LIST_LIMIT = 50
|
||||
|
||||
_CREATE_RE = re.compile(r"```task-create\s*\n(.*?)\n```", re.DOTALL)
|
||||
_POLL_RE = re.compile(
|
||||
@@ -139,6 +148,8 @@ _TODO_CREATE_RE = re.compile(
|
||||
r"```(todo-create|todo_create)\s*\n(.*?)\n```", re.DOTALL)
|
||||
_TODO_UPDATE_RE = re.compile(
|
||||
r"```(todo-update|todo_update)\s*\n(.*?)\n```", re.DOTALL)
|
||||
_TASK_LIST_RE = re.compile(
|
||||
r"```(task-list|task_list)\s*\n(.*?)\n```", re.DOTALL)
|
||||
|
||||
|
||||
def row_get(row, name):
|
||||
@@ -384,6 +395,45 @@ def extract_todo_updates(text):
|
||||
return out
|
||||
|
||||
|
||||
def extract_task_lists(text):
|
||||
"""提取 task-list 块;不传 status 时查全部状态(与 todo-list
|
||||
默认只查未完成不同——任务分诊首先要看到失败与运行中的,
|
||||
全部状态的计数与截断报告才是可用的概览)。q 是 prompt
|
||||
子串,limit 钳制 1-50(默认 20);status 非法、q 非字符
|
||||
串或超长、limit 非整数时整块跳过;每轮最多 5 块。"""
|
||||
if not text:
|
||||
return []
|
||||
out = []
|
||||
for match in _TASK_LIST_RE.finditer(str(text)):
|
||||
if len(out) >= MAX_TASK_LISTS_PER_TURN:
|
||||
break
|
||||
try:
|
||||
payload = json.loads(match.group(2))
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
if not isinstance(payload, dict):
|
||||
continue
|
||||
status = payload.get("status")
|
||||
if status is not None and status not in TASK_STATUSES:
|
||||
continue
|
||||
q = payload.get("q")
|
||||
if q is not None:
|
||||
if not isinstance(q, str) or not q.strip():
|
||||
continue
|
||||
q = q.strip()
|
||||
if len(q) > MAX_TODO_QUERY_CHARS:
|
||||
continue
|
||||
limit = payload.get("limit")
|
||||
if limit is None:
|
||||
limit = DEFAULT_TASK_LIST_LIMIT
|
||||
elif isinstance(limit, bool) or not isinstance(limit, int):
|
||||
continue
|
||||
else:
|
||||
limit = max(1, min(MAX_TASK_LIST_LIMIT, limit))
|
||||
out.append({"status": status, "q": q, "limit": limit})
|
||||
return out
|
||||
|
||||
|
||||
_SPAWN_SUBJECT_ZH = ("新建的任务", "派生任务", "新建任务",
|
||||
"子任务", "子代理", "新任务", "新会话")
|
||||
_SPAWN_SUBJECT_EN = ("child tasks", "spawned tasks", "new tasks",
|
||||
@@ -866,3 +916,25 @@ def format_todo(todo, max_title=100):
|
||||
if task_id:
|
||||
parts.append("task_id=%s" % task_id)
|
||||
return " ".join(parts)
|
||||
|
||||
|
||||
def format_task(task, max_prompt=80):
|
||||
"""任务单行(task-list 报告用):状态 + id + 创建人 + prompt
|
||||
截断;prompt 里的换行压成空格,避免一行任务撑开多行报告;
|
||||
创建时间有值时附 UTC 时间。"""
|
||||
prompt = str(task.get("prompt") or "").replace("\n", " ").strip()
|
||||
if len(prompt) > max_prompt:
|
||||
prompt = prompt[:max_prompt] + "…"
|
||||
line = ("• [%s] %s (by=%s)"
|
||||
% (task.get("status"), task.get("id"),
|
||||
task.get("created_by") or ""))
|
||||
created_at = task.get("created_at")
|
||||
if created_at:
|
||||
try:
|
||||
line += " created=%s" % time.strftime(
|
||||
"%Y-%m-%dT%H:%M:%SZ", time.gmtime(float(created_at)))
|
||||
except (TypeError, ValueError, OverflowError):
|
||||
pass
|
||||
if prompt:
|
||||
line += " " + prompt
|
||||
return line
|
||||
Reference in new issue
Block a user