任务列表 task-list 标记 + 首轮项目上下文注入
This commit is contained in:
1 parent
73288f08db
commit
2fd73c1121
5 files changed
+510
-13
No files matched your search
+138
-10
@@ -154,6 +154,7 @@ from cloud.marker_tools import check_control_gate as _marker_gate
|
||||
from cloud.marker_tools import count_direct_spawn_children as _marker_count_direct
|
||||
from cloud.marker_tools import fetch_task_snapshot as _marker_snapshot
|
||||
from cloud.marker_tools import format_snapshot as _marker_format
|
||||
from cloud.marker_tools import format_task as _format_task
|
||||
from cloud.marker_tools import format_todo as _format_todo
|
||||
from cloud.marker_tools import marker_report_header as _marker_header
|
||||
from cloud.todos import create_todo as _todo_create_db
|
||||
@@ -1741,6 +1742,80 @@ class Worker:
|
||||
task["id"])
|
||||
return new_task
|
||||
|
||||
def _apply_project_injection(self, task):
|
||||
"""首轮注入项目上下文:只改内存副本,原 prompt/goal 不落库。
|
||||
|
||||
跳过:协调员任务(不跑模型回合)、续跑与断点续跑(已有
|
||||
会话历史)。goal 任务不跳过——项目上下文是数据不是目标,
|
||||
与自动记忆同款同时改内存里的 goal(执行器取 goal 优先
|
||||
于 prompt,只改 prompt 的话 goal 任务看不到)。
|
||||
贴三行数据:项目名、仓库(未绑定时明写未绑定,不编一个
|
||||
地址)、环境(有 environment_id 时写环境名/分支/状态,
|
||||
否则写无);再加一行 task-list 格式示例,让模型在不知道
|
||||
任务 id 时也能查本项目任务。项目行查不到、查询失败时
|
||||
原样返回,不贴半截上下文、不炸认领。"""
|
||||
if task.get("coordinator_parts"):
|
||||
return task
|
||||
if task.get("_resume") or task.get("_goal_resume_breakpoint"):
|
||||
return task
|
||||
try:
|
||||
conn = _db_connect(self.db_path)
|
||||
try:
|
||||
row = conn.execute(
|
||||
"SELECT name, repo_url FROM projects WHERE id = ?",
|
||||
(task["project_id"],)).fetchone()
|
||||
finally:
|
||||
conn.close()
|
||||
except Exception as exc:
|
||||
try:
|
||||
self.logger.warning("project injection failed: %s", exc)
|
||||
except Exception:
|
||||
pass
|
||||
return task
|
||||
if row is None:
|
||||
return task
|
||||
try:
|
||||
project_name = row["name"] or task["project_id"]
|
||||
except (KeyError, IndexError, TypeError):
|
||||
project_name = task["project_id"]
|
||||
try:
|
||||
repo_url = row["repo_url"] or None
|
||||
except (KeyError, IndexError, TypeError):
|
||||
repo_url = None
|
||||
env_line = "无(使用默认仓库)"
|
||||
env_id = task.get("environment_id")
|
||||
if env_id:
|
||||
env = self._fetch_environment(env_id)
|
||||
if env is not None:
|
||||
env_line = "%s(分支 %s,状态 %s)" % (
|
||||
env.get("name") or env_id,
|
||||
env.get("branch") or "未指定",
|
||||
env.get("status") or "未知")
|
||||
if env.get("repo_url"):
|
||||
repo_url = env["repo_url"]
|
||||
else:
|
||||
env_line = "%s(查不到该环境)" % env_id
|
||||
lines = ["[项目上下文]",
|
||||
"项目:%s(id=%s)" % (project_name,
|
||||
task["project_id"]),
|
||||
"仓库:%s" % (repo_url or "未绑定"),
|
||||
"环境:%s" % env_line,
|
||||
"查本项目任务用 task-list 标记块,例如:",
|
||||
"```task-list",
|
||||
'{"status": "failed"}',
|
||||
"```",
|
||||
"(不传 status 时查全部状态并附各状态计数。)"]
|
||||
prefix = "\n".join(lines)
|
||||
new_task = dict(task)
|
||||
new_task["prompt"] = prefix + "\n\n" + (task.get("prompt") or "")
|
||||
if task.get("goal_mode") or task.get("verify_command"):
|
||||
new_task["goal"] = prefix + "\n\n" + (
|
||||
task.get("goal") or task.get("prompt") or "")
|
||||
new_task["_project_injected"] = True
|
||||
self._audit(task["project_id"], "worker_project_injected",
|
||||
task["id"])
|
||||
return new_task
|
||||
|
||||
def process_auto_memories(self, now=None, force=False,
|
||||
owner_id=None):
|
||||
"""扫 completed 任务并提取记忆(run_loop 轮次边界调用)。
|
||||
@@ -3297,12 +3372,13 @@ class Worker:
|
||||
只执行 completed 轮次的块;goal 任务与协调员任务不解析
|
||||
(只收不发,与 peer 同款);父任务被取消时不执行。
|
||||
执行顺序:创建 → 取消 → 重试 → 待办创建 → 待办更新 →
|
||||
待办列表 → 轮询 → 等待——创建在前让同一轮刚创建的任务
|
||||
立刻能被轮询,控制操作在快照之前让轮询/等待读到取消
|
||||
或重试后的新状态;待办列表放在待办写操作之后,让同
|
||||
一轮刚建/刚改的待办立刻能在列表里看到。全部报告拼
|
||||
成一条系统后续消息排给父任务自己,由排空循环在轮次
|
||||
边界跑下一轮;拒绝只记报告与审计,不炸 run_one。"""
|
||||
待办列表 → 任务列表 → 轮询 → 等待——创建在前让同一轮
|
||||
刚创建的任务立刻能被轮询,控制操作在快照之前让轮询/
|
||||
等待读到取消或重试后的新状态;待办列表放在待办写操作
|
||||
之后,让同一轮刚建/刚改的待办立刻能在列表里看到。
|
||||
全部报告拼成一条系统后续消息排给父任务自己,由排空
|
||||
循环在轮次边界跑下一轮;拒绝只记报告与审计,不炸
|
||||
run_one。"""
|
||||
if not result or result.get("status") != "completed":
|
||||
return
|
||||
if self._was_cancelled(task["id"]):
|
||||
@@ -3319,8 +3395,10 @@ class Worker:
|
||||
todo_lists = result.get("todo_lists") or []
|
||||
todo_creates = result.get("todo_creates") or []
|
||||
todo_updates = result.get("todo_updates") or []
|
||||
task_lists = result.get("task_lists") or []
|
||||
if not (creates or polls or waits or cancels or retries
|
||||
or todo_lists or todo_creates or todo_updates):
|
||||
or todo_lists or todo_creates or todo_updates
|
||||
or task_lists):
|
||||
return
|
||||
reports = []
|
||||
created = 0
|
||||
@@ -3503,7 +3581,7 @@ class Worker:
|
||||
# 一律拒绝,不静默放宽。跨项目待办按“不存在”拒绝;
|
||||
# 关联任务 id 跨项目时同样拒绝,避免把别的项目的任务
|
||||
# 挂到本项目待办上。
|
||||
if todo_lists or todo_creates or todo_updates:
|
||||
if todo_lists or todo_creates or todo_updates or task_lists:
|
||||
read_ok, _read_reason = self._marker_auth(task, "read")
|
||||
write_ok, _write_reason = self._marker_auth(
|
||||
task, "create_task")
|
||||
@@ -3623,6 +3701,52 @@ class Worker:
|
||||
lines.append("(还有 %d 条未列出。)"
|
||||
% (len(todos) - 20))
|
||||
reports.append("\n".join(lines))
|
||||
for block in task_lists:
|
||||
if read_ok is not True:
|
||||
reports.append("查任务列表:拒绝(发送方创建"
|
||||
"人无 read 权限)。")
|
||||
rejected += 1
|
||||
continue
|
||||
try:
|
||||
conn = _db_connect(self.db_path)
|
||||
try:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM tasks"
|
||||
" WHERE project_id = ?"
|
||||
" ORDER BY created_at DESC",
|
||||
(task["project_id"],)).fetchall()
|
||||
finally:
|
||||
conn.close()
|
||||
except Exception as exc:
|
||||
reports.append("查任务列表失败:%s" % exc)
|
||||
rejected += 1
|
||||
continue
|
||||
tasks = [_task_from_row(row) if not isinstance(
|
||||
row, dict) else row for row in rows]
|
||||
counts = {}
|
||||
for t in tasks:
|
||||
counts[t.get("status")] = counts.get(
|
||||
t.get("status"), 0) + 1
|
||||
if block.get("status"):
|
||||
tasks = [t for t in tasks
|
||||
if t.get("status") == block["status"]]
|
||||
if block.get("q"):
|
||||
ql = block["q"].lower()
|
||||
tasks = [t for t in tasks
|
||||
if ql in (t.get("prompt") or "").lower()]
|
||||
if not tasks:
|
||||
reports.append("任务列表:无匹配项。")
|
||||
else:
|
||||
lines = ["任务列表(共 %d 条,状态计数:%s):"
|
||||
% (len(tasks), ", ".join(
|
||||
"%s=%d" % kv for kv in sorted(
|
||||
counts.items())))]
|
||||
for t in tasks[:block["limit"]]:
|
||||
lines.append(_format_task(t))
|
||||
if len(tasks) > block["limit"]:
|
||||
lines.append("(还有 %d 条未列出。)"
|
||||
% (len(tasks) - block["limit"]))
|
||||
reports.append("\n".join(lines))
|
||||
for poll in polls:
|
||||
try:
|
||||
reports.append(self._poll_task_snapshot(task, poll))
|
||||
@@ -3639,11 +3763,11 @@ class Worker:
|
||||
self._queue_self_followup(task, body)
|
||||
detail = ("%s: spawned=%d rejected=%d polls=%d waits=%d "
|
||||
"cancels=%d retries=%d todo_lists=%d "
|
||||
"todo_creates=%d todo_updates=%d"
|
||||
"todo_creates=%d todo_updates=%d task_lists=%d"
|
||||
% (task["id"], created, rejected, len(polls),
|
||||
len(waits), len(cancels), len(retries),
|
||||
len(todo_lists), len(todo_creates),
|
||||
len(todo_updates)))
|
||||
len(todo_updates), len(task_lists)))
|
||||
self._audit(task["project_id"], "worker_marker_tools", detail)
|
||||
|
||||
def _deliver_peer_messages(self, task, result):
|
||||
@@ -4896,6 +5020,10 @@ class Worker:
|
||||
# 待办注入:首轮才注入未完成待办,见
|
||||
# _apply_todo_injection 的跳过规则;只改内存副本。
|
||||
task = self._apply_todo_injection(task)
|
||||
# 项目注入:首轮才注入项目上下文,见
|
||||
# _apply_project_injection 的跳过规则;只改内存副本;
|
||||
# 最后贴,排在待办与记忆之前(最通用上下文在最前)。
|
||||
task = self._apply_project_injection(task)
|
||||
self._audit(task["project_id"], "worker_claim",
|
||||
"%s executor=%s" % (task_id, self._executor_name()))
|
||||
# log_event 只接受 task_id/project_id/status/message 四个
|
||||
|
||||
Reference in new issue
Block a user