feat(task): 添加任务修订功能和超时处理机制

添加了 `revise_task` 路由动作类型,允许用户修改、纠正或重新执行最新活动任务结果。
实现了工具失败指导原则,防止相同类别工具重复失败。
为任务规划器添加了超时处理机制,避免长时间等待。

BREAKING CHANGE: 任务路由逻辑已更新,新增 `revise_task` 动作类型。

fix(api): 修复任务详情API返回完整流程投影

修复了任务详情API端点,现在会包含过滤后的流程运行、事件和工件信息,
并确保时间戳字段正确序列化。

refactor(engine): 优化任务技能解析器摘要节点处理

改进了任务技能解析器对摘要节点的处理逻辑,对于仅依赖文本生成功能的摘要节
点不再分配具体技能,直接使用依赖项输出进行汇总。

test: 增加任务修订和超时处理测试用例

添加了测试用例验证任务修订输入记录反馈、超时回退到单模式以及
摘要节点技能解析等新功能。
This commit is contained in:
2026-05-21 16:40:44 +08:00
parent 0caca8db8a
commit a27560102b
22 changed files with 855 additions and 93 deletions

View File

@ -581,8 +581,96 @@ class AgentService:
if active_task is None or decision.starts_new_task
else active_task
)
if active_task is not None and decision.action == "revise_task" and task.task_id == active_task.task_id:
task = self._record_revision_feedback_for_task(
loaded,
task=task,
session_id=session_id,
comment=message,
)
return await self._run_task_mode(message, runner=runner, kwargs=kwargs, task=task)
def _record_revision_feedback_for_task(
self,
loaded: Any,
*,
task: TaskRecord,
session_id: str,
comment: str,
) -> TaskRecord:
"""Mark the latest feedback-eligible run as revised before continuing a task."""
if task.status not in {"awaiting_feedback", "needs_revision"}:
return task
run_id = next((item for item in reversed(task.run_ids) if item), None)
if not run_id:
return task
existing = next((item for item in task.feedback if item.get("run_id") == run_id), None)
if existing is not None:
if existing.get("feedback_type") != "revise":
return task
updated = task
already_recorded = True
else:
task_service = self._require_loaded(loaded, "task_service")
updated = task_service.add_feedback(
task.task_id,
feedback_type="revise",
comment=comment,
run_id=run_id,
)
already_recorded = False
session_manager = self._require_loaded(loaded, "session_manager")
session_manager.update_latest_assistant_event_payload(
session_id,
run_id,
{
"task_id": updated.task_id,
"task_status": updated.status,
"feedback_state": "revise",
},
)
if already_recorded:
return updated
session_manager.append_message(
session_id,
run_id=run_id,
role="system",
event_type="task_feedback_recorded",
event_payload={
"task_id": updated.task_id,
"feedback_type": "revise",
"comment": comment,
"task_status": updated.status,
"auto_recorded": True,
},
content=comment,
context_visible=False,
)
validation = ValidationResult.from_dict(updated.validation_result)
run_memory_store = self._require_loaded(loaded, "run_memory_store")
run_memory_store.update_run_record(
run_id,
success=False,
feedback={
"feedback_type": "revise",
"comment": comment,
"task_status": updated.status,
},
)
run_memory_store.update_skill_effects_for_run(
run_id,
success=False,
feedback_score=self._feedback_score_for_learning("revise", validation),
notes=comment.strip() or "revise",
)
skill_learning_service = self._require_loaded(loaded, "skill_learning_service")
skill_learning_service.rescore_skill_versions()
return updated
async def _run_task_mode(
self,
message: str,
@ -1018,7 +1106,11 @@ class AgentService:
if plan.final_synthesis_instruction
else None
),
"Use the team outputs as internal evidence. Produce the final user-facing answer yourself.",
(
"Use successful team outputs as internal evidence. If one or more nodes failed, "
"do not blindly repeat failed tool calls. Produce a user-visible fallback answer "
"with available evidence and clearly state any missing or uncertain data."
),
]
if item
)
@ -1031,7 +1123,11 @@ class AgentService:
f"Planner reason: {plan.reason}",
f"Strategy: {plan.graph.strategy if plan.graph else ''}",
f"Error: {error}",
"Proceed as the main agent and produce the best possible final answer.",
(
"Proceed as the main agent. Do not blindly repeat failed tool calls; "
"produce a user-visible fallback answer with available evidence and clearly "
"state any missing or uncertain data."
),
]
)