修复: gen_stream判重+重试分类+状态机最短路径+既有测试修复
This commit is contained in:
@@ -38,7 +38,7 @@ pub fn register(registry: &mut AiToolRegistry, db: &Arc<Database>) {
|
||||
registry,
|
||||
db: Arc<Database>,
|
||||
"list_tasks",
|
||||
"列出任务,可按 project_id/status 筛选(status: todo/in_progress/in_review/testing/blocked/done/cancelled),支持 offset/limit 分页。返回 items、total、has_more。默认 limit=50",
|
||||
"列出任务,可按 project_id/status 筛选(status: todo/in_progress/in_review/testing/blocked/done/cancelled/deferred),支持 offset/limit 分页。返回 items、total、has_more。默认 limit=50",
|
||||
RiskLevel::Low,
|
||||
schema: object_schema(vec![("project_id", "string", false), ("status", "string", false), ("offset", "integer", false), ("limit", "integer", false)]),
|
||||
args => {
|
||||
@@ -48,7 +48,7 @@ pub fn register(registry: &mut AiToolRegistry, db: &Arc<Database>) {
|
||||
} else {
|
||||
repo.list_all().await?
|
||||
};
|
||||
// 按状态过滤(可选):todo/in_progress/in_review/testing/blocked/done/cancelled
|
||||
// 按状态过滤(可选):todo/in_progress/in_review/testing/blocked/done/cancelled/deferred
|
||||
if let Some(status) = args.get("status").and_then(|v| v.as_str()) {
|
||||
tasks.retain(|t| t.status.as_str() == status);
|
||||
}
|
||||
@@ -127,7 +127,7 @@ pub fn register(registry: &mut AiToolRegistry, db: &Arc<Database>) {
|
||||
registry,
|
||||
db: Arc<Database>,
|
||||
"update_task",
|
||||
"更新任务的指定字段(title/description/priority/assignee 等),需要提供任务 ID、字段名和新值。注意:status 改动须走 advance_task 工具(状态机推进,7 态 todo/in_progress/in_review/testing/blocked/done/cancelled,按 target_status 推进不可跳跃),本工具不接受 status 字段(防绕过状态机)",
|
||||
"更新任务的指定字段(title/description/priority/assignee 等),需要提供任务 ID、字段名和新值。注意:status 改动须走 advance_task 工具(状态机推进,8 态 todo/in_progress/in_review/testing/blocked/done/cancelled/deferred,按 target_status 推进不可跳跃),本工具不接受 status 字段(防绕过状态机)",
|
||||
RiskLevel::Medium,
|
||||
schema: object_schema(vec![("id", "string", true), ("field", "string", true), ("value", "string", true)]),
|
||||
args => {
|
||||
@@ -139,7 +139,7 @@ pub fn register(registry: &mut AiToolRegistry, db: &Arc<Database>) {
|
||||
// 对齐 Agent B df-storage tasks 白名单移 status——双重防御(schema 拒绝 + 白名单拒绝)。
|
||||
if field == "status" {
|
||||
anyhow::bail!(
|
||||
"status 改动须走 advance_task 工具(状态机推进,7 态不可跳跃),本工具不接受 status 字段"
|
||||
"status 改动须走 advance_task 工具(状态机推进,8 态不可跳跃),本工具不接受 status 字段"
|
||||
);
|
||||
}
|
||||
// 复用 df-storage CRUD 白名单(按表隔离),与 update_field 校验同源
|
||||
@@ -166,7 +166,7 @@ pub fn register(registry: &mut AiToolRegistry, db: &Arc<Database>) {
|
||||
registry,
|
||||
db: Arc<Database>,
|
||||
"advance_task",
|
||||
"推进任务状态,必须走状态机(7 态: todo/in_progress/in_review/testing/blocked/done/cancelled),按 target_status 推进,不可跳跃(非法转换会被状态机拦截)。退回转换(in_review→in_progress 等)自动累加 review_rounds。返回推进后的最新 TaskRecord",
|
||||
"推进任务状态,必须走状态机(8 态: todo/in_progress/in_review/testing/blocked/done/cancelled/deferred),按 target_status 推进,不可跳跃(非法转换会被状态机拦截)。退回转换(in_review→in_progress 等)自动累加 review_rounds。返回推进后的最新 TaskRecord",
|
||||
RiskLevel::Medium,
|
||||
schema: object_schema(vec![("id", "string", true), ("target_status", "string", true)]),
|
||||
args => {
|
||||
@@ -177,11 +177,29 @@ pub fn register(registry: &mut AiToolRegistry, db: &Arc<Database>) {
|
||||
// 与 commands::task::advance_task IPC 同源,避免双轨。设计 D3:子任务推进后
|
||||
// 自动触发父 status 聚合(advance_task_with_parent,父聚合失败仅 warn 不阻断)。
|
||||
let repo = df_storage::crud::TaskRepo::new(&db);
|
||||
// 推进前读 from(供 applied 断言对比,推进链内部也读,多一次轻量读可接受)。
|
||||
// 读失败不阻断推进 — from 缺失时 applied.from 留 null(向后兼容)。
|
||||
let from_status = repo.get_by_id(id).await
|
||||
.ok().flatten().map(|t| t.status.as_str().to_string());
|
||||
let updated = df_nodes::task_advance_node::advance_task_with_parent(
|
||||
&repo, id, target_status,
|
||||
).await?;
|
||||
// 返回推进后的 TaskRecord(含新 status / 累加后的 review_rounds),供 LLM 确认推进结果。
|
||||
Ok(serde_json::to_value(&updated)?)
|
||||
// 返回推进后的 TaskRecord + applied 结构化断言。matched_target = 实际 to 是否
|
||||
// 等于调用方传的 target(CAS 冲突后状态可能≠预期,matched_target=false 暴露真相)。
|
||||
// loop 收敛判定(阶段1-2)据此判目标达成,而非只看"LLM 停止调工具"。
|
||||
let to_status = updated.status.as_str();
|
||||
let matched = to_status == target_status;
|
||||
// TaskRecord 字段平铺在顶层(前端 formatAdvanceTask 直接读 r.title/r.status 等,
|
||||
// 零破坏);applied 作为附加嵌套字段供 loop 收敛判定读取(阶段1-2)。
|
||||
let mut value = serde_json::to_value(&updated)?;
|
||||
if let Some(obj) = value.as_object_mut() {
|
||||
obj.insert("applied".to_string(), serde_json::json!({
|
||||
"from": from_status,
|
||||
"to": to_status,
|
||||
"matched_target": matched,
|
||||
}));
|
||||
}
|
||||
Ok(value)
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user