@ai-setting/roy-agent-core 1.7.72 → 1.7.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/env/agent/agent-component.js +6 -6
- package/dist/env/agent/agent-registry.d.ts +4 -1
- package/dist/env/agent/index.js +6 -6
- package/dist/env/error-reply.d.ts +46 -0
- package/dist/env/error-reply.js +3 -1
- package/dist/env/event-source/event-source-handlers.js +13 -12
- package/dist/env/event-source/index.js +14 -13
- package/dist/env/index.js +31 -30
- package/dist/env/llm/index.js +2 -2
- package/dist/env/llm/orphan-toolcall.d.ts +107 -0
- package/dist/env/plugin/index.js +3 -3
- package/dist/env/prompt/index.js +4 -3
- package/dist/env/prompt/prompts-index.d.ts +27 -3
- package/dist/env/session/index.js +4 -4
- package/dist/env/session/storage/index.js +3 -3
- package/dist/env/task/backend/index.js +9 -1
- package/dist/env/task/delegate/delegate-tool.d.ts +8 -0
- package/dist/env/task/delegate/delegate-tool.js +5 -4
- package/dist/env/task/delegate/index.js +5 -4
- package/dist/env/task/hooks/contexts.d.ts +12 -1
- package/dist/env/task/hooks/task-hook-points.d.ts +8 -3
- package/dist/env/task/index.d.ts +1 -0
- package/dist/env/task/index.js +17 -7
- package/dist/env/task/mcp/index.js +3 -2
- package/dist/env/task/plugins/index.d.ts +3 -0
- package/dist/env/task/plugins/index.js +33 -9
- package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +61 -0
- package/dist/env/task/plugins/lark-card-patch-notifier.js +6 -2
- package/dist/env/task/plugins/lark-cli-task-notify-plugin.d.ts +42 -0
- package/dist/env/task/prompt/index.js +2 -1
- package/dist/env/task/prompt/task-discipline.d.ts +9 -3
- package/dist/env/task/task-component.d.ts +79 -0
- package/dist/env/task/tools/cancel-tool.d.ts +36 -0
- package/dist/env/task/tools/completion-copy.d.ts +92 -0
- package/dist/env/task/tools/index.d.ts +2 -0
- package/dist/env/task/tools/index.js +7 -2
- package/dist/env/task/tools/pre-complete-tool.d.ts +32 -0
- package/dist/env/task/tools/task-types.d.ts +71 -17
- package/dist/env/task/types.d.ts +13 -1
- package/dist/env/tool/built-in/compact-session-tool.d.ts +120 -0
- package/dist/env/tool/built-in/index.d.ts +2 -0
- package/dist/env/tool/built-in/index.js +6 -2
- package/dist/env/tool/index.js +4 -4
- package/dist/env/workflow/engine/index.js +6 -6
- package/dist/env/workflow/index.js +15 -13
- package/dist/env/workflow/plugins/index.js +2 -2
- package/dist/env/workflow/tools/ask-user-tool.d.ts +88 -0
- package/dist/env/workflow/tools/index.js +11 -9
- package/dist/env/workflow/tools/run-workflow.d.ts +2 -2
- package/dist/env/workflow/types/index.js +2 -2
- package/dist/env/workflow/types/workflow-hil.d.ts +25 -1
- package/dist/env/workflow/utils/index.js +5 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +43 -33
- package/dist/shared/@ai-setting/{roy-agent-core-sm0sf6sb.js → roy-agent-core-0qyrk5k0.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-kmbct9yg.js → roy-agent-core-0snm5hc5.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-yr1mryb8.js → roy-agent-core-1v4g0d4x.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-rxb00gjm.js → roy-agent-core-264qexac.js} +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-2akfd64z.js +374 -0
- package/dist/shared/@ai-setting/{roy-agent-core-skyc30qx.js → roy-agent-core-3fh1f7s7.js} +2 -2
- package/dist/shared/@ai-setting/roy-agent-core-4rtg69cn.js +26 -0
- package/dist/shared/@ai-setting/{roy-agent-core-add1zqsh.js → roy-agent-core-6cy43nss.js} +22 -1
- package/dist/shared/@ai-setting/{roy-agent-core-vah6g5yx.js → roy-agent-core-6rh8k6ba.js} +5 -5
- package/dist/shared/@ai-setting/{roy-agent-core-kpg25s2q.js → roy-agent-core-8ez6mccb.js} +4 -2
- package/dist/shared/@ai-setting/{roy-agent-core-yhwxpj12.js → roy-agent-core-9vxh6f8h.js} +233 -16
- package/dist/shared/@ai-setting/{roy-agent-core-7qvw65jt.js → roy-agent-core-aa2j7bk9.js} +11 -8
- package/dist/shared/@ai-setting/{roy-agent-core-sjr1kmfz.js → roy-agent-core-acj8ag08.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-mds8tqd0.js → roy-agent-core-cgtq6427.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-34jz9mgh.js → roy-agent-core-cmprygrp.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-wr7mv7k3.js → roy-agent-core-cxy143m4.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-pakhchy7.js → roy-agent-core-ddyk1rc0.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-attpry6g.js → roy-agent-core-dqxec05w.js} +4 -3
- package/dist/shared/@ai-setting/{roy-agent-core-vm8h5zyj.js → roy-agent-core-ed233k5z.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-jrj30vq3.js → roy-agent-core-er070zjq.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-40rv283c.js → roy-agent-core-fghc2m8z.js} +152 -2
- package/dist/shared/@ai-setting/{roy-agent-core-5gw0qa8m.js → roy-agent-core-ghnagzrh.js} +557 -92
- package/dist/shared/@ai-setting/{roy-agent-core-4jjwewvw.js → roy-agent-core-m46fe3x4.js} +41 -30
- package/dist/shared/@ai-setting/{roy-agent-core-e25xkv53.js → roy-agent-core-mkc3zshb.js} +3 -1
- package/dist/shared/@ai-setting/{roy-agent-core-hfyfavp3.js → roy-agent-core-mww0mnd9.js} +231 -27
- package/dist/shared/@ai-setting/{roy-agent-core-46rv4d7d.js → roy-agent-core-nmx9934r.js} +92 -2
- package/dist/shared/@ai-setting/{roy-agent-core-1w9y7mxj.js → roy-agent-core-p3zv1mx5.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-jgb3bb42.js → roy-agent-core-q5r75vev.js} +17 -8
- package/dist/shared/@ai-setting/{roy-agent-core-y12kyxwa.js → roy-agent-core-t3rrb959.js} +33 -9
- package/dist/shared/@ai-setting/{roy-agent-core-dt104qa1.js → roy-agent-core-v85n42ve.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-gr48c89p.js → roy-agent-core-v87njmq7.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-7sj9xs9c.js → roy-agent-core-vffccgf6.js} +252 -25
- package/dist/shared/@ai-setting/{roy-agent-core-2gzt2q8c.js → roy-agent-core-z43aj03k.js} +134 -29
- package/dist/shared/@ai-setting/roy-agent-core-zycadbpx.js +662 -0
- package/package.json +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-1p6syv85.js +0 -1083
- package/dist/shared/@ai-setting/roy-agent-core-58804s3j.js +0 -155
|
@@ -3,11 +3,16 @@ import {
|
|
|
3
3
|
NEW_TASK_ID_PLACEHOLDER
|
|
4
4
|
} from "./roy-agent-core-tr3ep81v.js";
|
|
5
5
|
import {
|
|
6
|
+
TASK_DISCIPLINE_GOALS
|
|
7
|
+
} from "./roy-agent-core-m46fe3x4.js";
|
|
8
|
+
import {
|
|
9
|
+
TASK_ARCHIVED_STATUS_WORD,
|
|
10
|
+
TASK_CANCELLED_STATUS_WORD,
|
|
6
11
|
TASK_COMPLETE_ITEM_BY_ITEM,
|
|
7
12
|
TASK_COMPLETE_VERIFY_DUTY,
|
|
8
13
|
TASK_COMPLETION_HINT_ANCHOR,
|
|
9
|
-
|
|
10
|
-
} from "./roy-agent-core-
|
|
14
|
+
TERMINAL_NON_ACCEPTABLE_STATUSES
|
|
15
|
+
} from "./roy-agent-core-4rtg69cn.js";
|
|
11
16
|
import {
|
|
12
17
|
getEnvContextOrEmpty,
|
|
13
18
|
init_env_context,
|
|
@@ -63,7 +68,7 @@ var GetTaskToolSchema = withLegacyTaskId({
|
|
|
63
68
|
include_operations: z.boolean().optional().default(true).describe("Include operation records (milestones / process log) with the task. " + "Defaults to true — the task's operation history is part of its detail. " + "Pass false for a lean task-only response.")
|
|
64
69
|
});
|
|
65
70
|
var ListTasksToolSchema = z.object({
|
|
66
|
-
status: z.enum(["todo", "active", "completed", "paused", "cancelled", "archived"]).optional(),
|
|
71
|
+
status: z.enum(["todo", "active", "to_validate", "completed", "paused", "cancelled", "archived"]).optional(),
|
|
67
72
|
priority: z.enum(["low", "medium", "high"]).optional(),
|
|
68
73
|
type: z.enum(["normal", "cycle", "longterm"]).optional().describe("Filter by task type"),
|
|
69
74
|
limit: z.number().optional().default(20),
|
|
@@ -75,7 +80,7 @@ var SearchTasksToolSchema = z.object({
|
|
|
75
80
|
keywords: z.array(z.string()).describe("关键词列表(AND 逻辑,匹配 title/description/goals/tags/operations)"),
|
|
76
81
|
limit: z.number().optional().default(20).describe("返回数量"),
|
|
77
82
|
offset: z.number().optional().default(0).describe("偏移量"),
|
|
78
|
-
status: z.enum(["todo", "active", "completed", "paused", "cancelled", "archived"]).optional().describe("按状态筛选"),
|
|
83
|
+
status: z.enum(["todo", "active", "to_validate", "completed", "paused", "cancelled", "archived"]).optional().describe("按状态筛选"),
|
|
79
84
|
priority: z.enum(["low", "medium", "high"]).optional().describe("按优先级筛选"),
|
|
80
85
|
type: z.enum(["normal", "cycle", "longterm"]).optional().describe("按类型筛选"),
|
|
81
86
|
exclude_task_id: z.number().optional().describe("排除的 task ID"),
|
|
@@ -85,7 +90,7 @@ var SearchTasksToolSchema = z.object({
|
|
|
85
90
|
var UpdateTaskToolSchema = withLegacyTaskId({
|
|
86
91
|
title: z.string().optional(),
|
|
87
92
|
description: z.string().optional(),
|
|
88
|
-
status: z.enum(["todo", "active", "completed", "paused", "cancelled", "archived"]).optional(),
|
|
93
|
+
status: z.enum(["todo", "active", "to_validate", "completed", "paused", "cancelled", "archived"]).optional(),
|
|
89
94
|
priority: z.enum(["low", "medium", "high"]).optional(),
|
|
90
95
|
type: z.enum(["normal", "cycle", "longterm"]).optional().describe("Task type"),
|
|
91
96
|
progress: z.number().min(0).max(100).optional(),
|
|
@@ -100,8 +105,13 @@ var UpdateTaskToolSchema = withLegacyTaskId({
|
|
|
100
105
|
var DeleteTaskToolSchema = z.object({
|
|
101
106
|
task_id: z.number().describe("Task ID")
|
|
102
107
|
});
|
|
103
|
-
var CompleteTaskToolSchema = withLegacyTaskId({
|
|
104
|
-
|
|
108
|
+
var CompleteTaskToolSchema = withLegacyTaskId({});
|
|
109
|
+
var PreCompleteTaskToolSchema = withLegacyTaskId({
|
|
110
|
+
deliverable_storage_path: z.string().optional().describe("交付物的寻址地址(路径 / URL / 分支名等)。" + "会持久化到 task.context.deliverable_storage_path," + "并写入 operation 记录(Deliverable 行),供验收方 task_complete 时逐条对照。"),
|
|
111
|
+
current_status: z.string().optional().describe("本次交付的进展摘要(可选)。" + "会拼进「待验证:」文案,作为任务当前状态展示给验收方(default agent)。")
|
|
112
|
+
});
|
|
113
|
+
var CancelTaskToolSchema = withLegacyTaskId({
|
|
114
|
+
reason: z.string().optional().describe("取消原因(可选)。会写入该任务的 operation 记录,便于事后追溯验收结论。")
|
|
105
115
|
});
|
|
106
116
|
var BatchArchiveToolSchema = z.object({
|
|
107
117
|
task_ids: z.array(z.number()).describe("要归档的任务 ID 列表"),
|
|
@@ -113,7 +123,7 @@ var BatchDeleteToolSchema = z.object({
|
|
|
113
123
|
var TreeTasksToolSchema = z.object({
|
|
114
124
|
depth: z.number().optional().default(2).describe("树的展开深度。默认 2 (根 + 一层子任务 + 二层孙任务)。" + "0 = 只返回根任务,不展开任何子节点。" + "-1 或负数 = 无限层级(全部展开)。"),
|
|
115
125
|
parent_task_id: z.number().optional().describe("只看指定父任务的子树。不传则从所有根任务(forest)开始。"),
|
|
116
|
-
status: z.enum(["todo", "active", "completed", "paused", "cancelled", "archived"]).optional().describe("按状态过滤(与 task_list 一致)。"),
|
|
126
|
+
status: z.enum(["todo", "active", "to_validate", "completed", "paused", "cancelled", "archived"]).optional().describe("按状态过滤(与 task_list 一致)。"),
|
|
117
127
|
priority: z.enum(["low", "medium", "high"]).optional().describe("按优先级过滤。"),
|
|
118
128
|
type: z.enum(["normal", "cycle", "longterm"]).optional().describe("按任务类型过滤。"),
|
|
119
129
|
include_archived: z.boolean().optional().default(false).describe("是否包含已归档任务(默认 false,与 task_list 一致)。")
|
|
@@ -699,7 +709,10 @@ function batchArchiveTaskTool(taskComponent) {
|
|
|
699
709
|
let archivedCount = 0;
|
|
700
710
|
for (const taskId of taskIds) {
|
|
701
711
|
try {
|
|
702
|
-
const task = await taskComponent.updateTask(taskId, {
|
|
712
|
+
const task = await taskComponent.updateTask(taskId, {
|
|
713
|
+
status: "archived",
|
|
714
|
+
current_status: params.reason ? `${TASK_ARCHIVED_STATUS_WORD}:${params.reason}` : TASK_ARCHIVED_STATUS_WORD
|
|
715
|
+
});
|
|
703
716
|
if (task) {
|
|
704
717
|
await taskComponent.createOperation({
|
|
705
718
|
taskId,
|
|
@@ -828,6 +841,22 @@ function updateTaskTool(taskComponent) {
|
|
|
828
841
|
};
|
|
829
842
|
}
|
|
830
843
|
}
|
|
844
|
+
const callerAgentType = ctx.metadata?.agentType ?? undefined;
|
|
845
|
+
const callerAgentName = ctx.metadata?.agentName ?? undefined;
|
|
846
|
+
if (params.status === "completed" && callerAgentType === "sub") {
|
|
847
|
+
const agentComponent = taskComponent.env?.getComponent?.("agent");
|
|
848
|
+
const callerAgent = callerAgentName && agentComponent?.getAgent ? agentComponent.getAgent(callerAgentName) : undefined;
|
|
849
|
+
const cfg = callerAgent?.config;
|
|
850
|
+
const hasCompletePermission = cfg ? Array.isArray(cfg.allowedTools) && cfg.allowedTools.includes("task_complete") || !Array.isArray(cfg.allowedTools) && !(Array.isArray(cfg.deniedTools) && cfg.deniedTools.includes("task_complete")) : false;
|
|
851
|
+
if (!hasCompletePermission) {
|
|
852
|
+
return {
|
|
853
|
+
success: false,
|
|
854
|
+
output: "",
|
|
855
|
+
error: `Cannot set status="completed" without acceptance permission (Task #5007 — 验收权分离). ` + `执行方只能推进进度:用 task_update(progress=100) 表示"我这边干完了",` + `再 task_operation_create 记录结论,然后结束返回;` + `任务终态必须由验收方(default agent / 主智能体)调用 task_complete 落定。`,
|
|
856
|
+
metadata: { execution_time_ms: 0 }
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
}
|
|
831
860
|
const task = await taskComponent.updateTask(params.task_id, {
|
|
832
861
|
title: params.title,
|
|
833
862
|
description: params.description,
|
|
@@ -921,7 +950,11 @@ init_env_context();
|
|
|
921
950
|
init_logger();
|
|
922
951
|
var logger4 = createLogger("task:tools:complete");
|
|
923
952
|
var TASK_COMPLETE_DESCRIPTION = `
|
|
924
|
-
|
|
953
|
+
Final acceptance of a submitted task: set status=completed, progress=100
|
|
954
|
+
(two-phase acceptance, Task #5073).
|
|
955
|
+
|
|
956
|
+
**Who should call this** — the **acceptance side** (default agent). The
|
|
957
|
+
executor (sub-agent) has NO permission to call it (deniedTools, Task #5007).
|
|
925
958
|
|
|
926
959
|
**Before calling this tool**, you MUST:
|
|
927
960
|
|
|
@@ -949,21 +982,27 @@ Mark a task as completed (progress=100, status=completed). Creates an operation
|
|
|
949
982
|
(milestone_type=decision) — the reason **must** land in the
|
|
950
983
|
operation record (必须落到操作记录里), not merely a line in
|
|
951
984
|
your final report (不能只在报告里带一句).
|
|
952
|
-
3.
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
-
|
|
956
|
-
|
|
957
|
-
- Cloud drive URL (e.g., https://my.feishu.cn/file/abc)
|
|
958
|
-
- Or any other locator that points to where the work product lives
|
|
959
|
-
|
|
960
|
-
The \`deliverable_storage_path\` will be persisted to the task's \`context.deliverable_storage_path\` for future reference and traceability.
|
|
985
|
+
3. Deliverables were already submitted by the executor via
|
|
986
|
+
\`task_pre_complete\` (they live in \`context.deliverable_storage_path\`
|
|
987
|
+
and the operation trail — Task #5073 design: task_complete takes **no**
|
|
988
|
+
deliverable parameter). Cross-check them in step 2; do NOT ask the
|
|
989
|
+
executor to resubmit.
|
|
961
990
|
|
|
962
991
|
**Restrictions**:
|
|
963
992
|
- Cannot complete cycle-type tasks (they are periodic). Use \`task_update\` to reset progress instead.
|
|
964
993
|
- Marks the task as 100% complete; use \`task_update\` to record partial progress first if needed.
|
|
965
994
|
|
|
966
|
-
**
|
|
995
|
+
**Side effects**:
|
|
996
|
+
- Sets \`status = "completed"\`, \`progress = 100\` **and refreshes \`current_status\`**
|
|
997
|
+
to the completed wording. You do **NOT** need a follow-up
|
|
998
|
+
\`task_update(current_status=...)\` call — a task must never keep a stale
|
|
999
|
+
pre-completion progress sentence (e.g. "paused, not committed") that would
|
|
1000
|
+
contradict \`status = "completed"\`.
|
|
1001
|
+
- The goal-check decision model does **NOT** run here — it already ran at
|
|
1002
|
+
\`task_pre_complete\` time (Task #5073 design v2). This tool is the final
|
|
1003
|
+
state commit by the acceptance side.
|
|
1004
|
+
- Cannot complete a task that is already in a terminal state (cancelled /
|
|
1005
|
+
archived) — reopen it first via \`task_update(status="active")\`.
|
|
967
1006
|
`.trim();
|
|
968
1007
|
function completeTaskTool(taskComponent) {
|
|
969
1008
|
return {
|
|
@@ -991,7 +1030,18 @@ function completeTaskTool(taskComponent) {
|
|
|
991
1030
|
metadata: { execution_time_ms: 0 }
|
|
992
1031
|
};
|
|
993
1032
|
}
|
|
994
|
-
const
|
|
1033
|
+
const TERMINAL_NON_ACCEPTABLE = new Set([
|
|
1034
|
+
...TERMINAL_NON_ACCEPTABLE_STATUSES
|
|
1035
|
+
]);
|
|
1036
|
+
if (TERMINAL_NON_ACCEPTABLE.has(currentTask.status)) {
|
|
1037
|
+
return {
|
|
1038
|
+
success: false,
|
|
1039
|
+
output: "",
|
|
1040
|
+
error: `Cannot complete task #${params.task_id}: it is already in terminal status "${currentTask.status}". Reopen it first via task_update(status="active") if acceptance should proceed.`,
|
|
1041
|
+
metadata: { execution_time_ms: 0 }
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
const task = await taskComponent.completeTask(params.task_id, sessionId);
|
|
995
1045
|
if (!task) {
|
|
996
1046
|
return {
|
|
997
1047
|
success: false,
|
|
@@ -1001,11 +1051,188 @@ function completeTaskTool(taskComponent) {
|
|
|
1001
1051
|
};
|
|
1002
1052
|
}
|
|
1003
1053
|
setCurrentTaskId(undefined);
|
|
1004
|
-
logger4.info(`[completeTask] Trace: Task #${params.task_id} completed
|
|
1054
|
+
logger4.info(`[completeTask] Trace: Task #${params.task_id} completed (acceptance committed), currentTaskId cleared from EnvContext`);
|
|
1055
|
+
return {
|
|
1056
|
+
success: true,
|
|
1057
|
+
output: `Task completed: #${task.id} - ${task.title}`,
|
|
1058
|
+
metadata: { execution_time_ms: 0, task }
|
|
1059
|
+
};
|
|
1060
|
+
} catch (error) {
|
|
1061
|
+
return {
|
|
1062
|
+
success: false,
|
|
1063
|
+
output: "",
|
|
1064
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1065
|
+
metadata: { execution_time_ms: 0 }
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
// src/env/task/tools/cancel-tool.ts
|
|
1072
|
+
init_logger();
|
|
1073
|
+
var logger5 = createLogger("tool:cancel-task");
|
|
1074
|
+
var NON_CANCELLABLE_STATUSES = new Set(["completed", "cancelled", "archived"]);
|
|
1075
|
+
var TASK_CANCEL_DESCRIPTION = `
|
|
1076
|
+
Cancel a task (task.status = "cancelled"). This is the **acceptance-side** cancel.
|
|
1077
|
+
|
|
1078
|
+
**When to use** — ONLY when the user explicitly asks (用户明令):
|
|
1079
|
+
- The user asks to cancel / stop / drop the task (用户明令取消 / 停掉 / 放弃这个任务)
|
|
1080
|
+
|
|
1081
|
+
**When NOT to use**:
|
|
1082
|
+
- ❌ A sub-agent failed / timed out / went off-track — that is NOT a cancellation.
|
|
1083
|
+
Find the root cause, propose a fix, and re-delegate (with \`sub_session_id\` to resume).
|
|
1084
|
+
If it truly cannot be moved forward, report the situation to the user and **wait for
|
|
1085
|
+
the user's decision** — do NOT cancel it on your own.
|
|
1086
|
+
- ❌ Acceptance found gaps but re-delegation is still possible — re-delegate instead.
|
|
1087
|
+
|
|
1088
|
+
**What it does NOT do**:
|
|
1089
|
+
- It does **NOT** stop a running background process — that is \`stop_task\`
|
|
1090
|
+
(which takes a bg-process id from \`delegate_task\`). If the sub-agent is still
|
|
1091
|
+
running, call \`stop_task\` **first**, then \`task_cancel\` to close the record.
|
|
1092
|
+
|
|
1093
|
+
**Side effects**:
|
|
1094
|
+
- Sets \`status = "cancelled"\` and fires the task terminal-state hooks
|
|
1095
|
+
(notifications / card state machine converge to the cancelled state).
|
|
1096
|
+
- Also refreshes \`current_status\` to the cancelled wording (with your \`reason\`
|
|
1097
|
+
appended when given) — the task no longer keeps a stale pre-cancel progress
|
|
1098
|
+
sentence that would contradict \`status = "cancelled"\`.
|
|
1099
|
+
- Writes an operation record so the cancellation reason stays auditable.
|
|
1100
|
+
- A cancelled task can be reopened later with \`task_update(status="active")\`.
|
|
1101
|
+
|
|
1102
|
+
**Parameters**:
|
|
1103
|
+
- \`task_id\` (required): the task to cancel
|
|
1104
|
+
- \`reason\` (optional): why it is being cancelled — recorded in the operation trail
|
|
1105
|
+
`.trim();
|
|
1106
|
+
function cancelTaskTool(taskComponent) {
|
|
1107
|
+
return {
|
|
1108
|
+
name: "task_cancel",
|
|
1109
|
+
description: TASK_CANCEL_DESCRIPTION,
|
|
1110
|
+
parameters: CancelTaskToolSchema,
|
|
1111
|
+
execute: async (args, ctx) => {
|
|
1112
|
+
const params = CancelTaskToolSchema.parse(args);
|
|
1113
|
+
const sessionId = ctx.session_id || "unknown";
|
|
1114
|
+
try {
|
|
1115
|
+
const current = await taskComponent.getTask(params.task_id);
|
|
1116
|
+
if (!current) {
|
|
1117
|
+
return {
|
|
1118
|
+
success: false,
|
|
1119
|
+
output: "",
|
|
1120
|
+
error: `Task not found: ${params.task_id}`,
|
|
1121
|
+
metadata: { execution_time_ms: 0 }
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
if (NON_CANCELLABLE_STATUSES.has(current.status)) {
|
|
1125
|
+
return {
|
|
1126
|
+
success: false,
|
|
1127
|
+
output: "",
|
|
1128
|
+
error: `Cannot cancel task #${params.task_id}: it is already in terminal status "${current.status}".`,
|
|
1129
|
+
metadata: { execution_time_ms: 0, task_id: params.task_id }
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
const task = await taskComponent.updateTask(params.task_id, {
|
|
1133
|
+
status: "cancelled",
|
|
1134
|
+
current_status: params.reason ? `${TASK_CANCELLED_STATUS_WORD}:${params.reason}` : TASK_CANCELLED_STATUS_WORD
|
|
1135
|
+
});
|
|
1136
|
+
if (!task) {
|
|
1137
|
+
return {
|
|
1138
|
+
success: false,
|
|
1139
|
+
output: "",
|
|
1140
|
+
error: `Task not found: ${params.task_id}`,
|
|
1141
|
+
metadata: { execution_time_ms: 0 }
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
await taskComponent.createOperation({
|
|
1145
|
+
taskId: params.task_id,
|
|
1146
|
+
sessionId,
|
|
1147
|
+
milestoneType: "decision",
|
|
1148
|
+
milestoneTitle: `Task cancelled: #${params.task_id}`,
|
|
1149
|
+
milestoneDescription: params.reason ? `Cancelled by acceptance side. Reason: ${params.reason}` : "Cancelled by acceptance side (no reason given)."
|
|
1150
|
+
});
|
|
1151
|
+
logger5.info(`[cancelTask] Task #${params.task_id} cancelled (previous status: ${current.status})`);
|
|
1152
|
+
return {
|
|
1153
|
+
success: true,
|
|
1154
|
+
output: `Task cancelled: #${params.task_id} - ${task.title}`,
|
|
1155
|
+
metadata: { execution_time_ms: 0, task }
|
|
1156
|
+
};
|
|
1157
|
+
} catch (error) {
|
|
1158
|
+
return {
|
|
1159
|
+
success: false,
|
|
1160
|
+
output: "",
|
|
1161
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1162
|
+
metadata: { execution_time_ms: 0 }
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
// src/env/task/tools/pre-complete-tool.ts
|
|
1169
|
+
init_logger();
|
|
1170
|
+
var logger6 = createLogger("task:tools:pre-complete");
|
|
1171
|
+
var TASK_PRE_COMPLETE_DESCRIPTION = `
|
|
1172
|
+
Submit a task for acceptance (two-phase acceptance, Task #5073).
|
|
1173
|
+
|
|
1174
|
+
**Who should call this** — the **executor** (sub-agent) when it believes
|
|
1175
|
+
the work is done and deliverables are ready.
|
|
1176
|
+
|
|
1177
|
+
**What it does**:
|
|
1178
|
+
- Sets \`status = "to_validate"\` (待验证) — the task enters the
|
|
1179
|
+
acceptance queue. This is **NOT** a terminal state.
|
|
1180
|
+
- Persists \`deliverable_storage_path\` to \`task.context.deliverable_storage_path\`
|
|
1181
|
+
and writes a \`Deliverable: <path>\` line into the operation trail.
|
|
1182
|
+
- Refreshes \`current_status\` to the to-validate wording
|
|
1183
|
+
(with your progress summary appended when given).
|
|
1184
|
+
- Creates an operation record so the submission stays auditable.
|
|
1185
|
+
|
|
1186
|
+
**What it does NOT do**:
|
|
1187
|
+
- It does **NOT** mark the task completed — final acceptance
|
|
1188
|
+
(\`task_complete\`) belongs to the **default agent** (验收权分离, Task #5007).
|
|
1189
|
+
|
|
1190
|
+
**Goal self-check (design v2)**:
|
|
1191
|
+
- Submitting **does** fire the completion goal-check hook once
|
|
1192
|
+
(\`terminalStatus="to_validate"\`) as a self-check gate — the
|
|
1193
|
+
decision model reviews your goals/operations at submission time.
|
|
1194
|
+
If it produces a hint, read it and address the gaps **before**
|
|
1195
|
+
ending your turn. The final acceptance (\`task_complete\`) does
|
|
1196
|
+
**not** re-run the goal check.
|
|
1197
|
+
|
|
1198
|
+
**After calling**:
|
|
1199
|
+
- Push progress to 100 via \`task_update(progress=100)\` if not already,
|
|
1200
|
+
then **end your turn and return the result** to the main agent.
|
|
1201
|
+
- The default agent will pick up the notification, verify the goals
|
|
1202
|
+
item-by-item, and call \`task_complete\` (or re-delegate on gaps).
|
|
1203
|
+
|
|
1204
|
+
**Parameters**:
|
|
1205
|
+
- \`task_id\` (required): the task to submit
|
|
1206
|
+
- \`deliverable_storage_path\` (optional): where the work product lives
|
|
1207
|
+
(file path / Feishu doc URL / git branch / PR URL ...)
|
|
1208
|
+
- \`current_status\` (optional): a one-line progress summary shown to the
|
|
1209
|
+
acceptance side (e.g. "实现完成,测试全绿")
|
|
1210
|
+
|
|
1211
|
+
**Restrictions**:
|
|
1212
|
+
- Cannot pre-complete cycle-type tasks (they are periodic).
|
|
1213
|
+
`.trim();
|
|
1214
|
+
function preCompleteTaskTool(taskComponent) {
|
|
1215
|
+
return {
|
|
1216
|
+
name: "task_pre_complete",
|
|
1217
|
+
description: TASK_PRE_COMPLETE_DESCRIPTION,
|
|
1218
|
+
parameters: PreCompleteTaskToolSchema,
|
|
1219
|
+
execute: async (args, ctx) => {
|
|
1220
|
+
const params = PreCompleteTaskToolSchema.parse(args);
|
|
1221
|
+
const sessionId = ctx.session_id || "unknown";
|
|
1222
|
+
try {
|
|
1223
|
+
const task = await taskComponent.preCompleteTask(params.task_id, sessionId, params.deliverable_storage_path, params.current_status);
|
|
1224
|
+
if (!task) {
|
|
1225
|
+
return {
|
|
1226
|
+
success: false,
|
|
1227
|
+
output: "",
|
|
1228
|
+
error: `Task not found: ${params.task_id}`,
|
|
1229
|
+
metadata: { execution_time_ms: 0 }
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1005
1232
|
return {
|
|
1006
1233
|
success: true,
|
|
1007
|
-
output: params.deliverable_storage_path ? `Task
|
|
1008
|
-
Deliverable (context + operation): ${params.deliverable_storage_path}` : `Task
|
|
1234
|
+
output: params.deliverable_storage_path ? `Task submitted for acceptance (to_validate): #${task.id} - ${task.title}
|
|
1235
|
+
Deliverable (context + operation): ${params.deliverable_storage_path}` : `Task submitted for acceptance (to_validate): #${task.id} - ${task.title}
|
|
1009
1236
|
Deliverable: (no path provided)`,
|
|
1010
1237
|
metadata: { execution_time_ms: 0, task }
|
|
1011
1238
|
};
|
|
@@ -1158,4 +1385,4 @@ function treeTasksTool(taskComponent) {
|
|
|
1158
1385
|
}
|
|
1159
1386
|
};
|
|
1160
1387
|
}
|
|
1161
|
-
export { createTaskTool, getTaskTool, listTasksTool, searchTasksTool, batchArchiveTaskTool, batchDeleteTaskTool, updateTaskTool, deleteTaskTool, completeTaskTool, treeTasksTool };
|
|
1388
|
+
export { createTaskTool, getTaskTool, listTasksTool, searchTasksTool, batchArchiveTaskTool, batchDeleteTaskTool, updateTaskTool, deleteTaskTool, completeTaskTool, cancelTaskTool, preCompleteTaskTool, treeTasksTool };
|
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
import {
|
|
2
|
+
compactSessionTool,
|
|
3
|
+
createCompactSessionTool,
|
|
2
4
|
createQueryBackgroundProcessTool
|
|
3
|
-
} from "./roy-agent-core-
|
|
5
|
+
} from "./roy-agent-core-2akfd64z.js";
|
|
4
6
|
import {
|
|
5
7
|
createStopTool
|
|
6
8
|
} from "./roy-agent-core-jm136jzh.js";
|
|
7
9
|
import {
|
|
8
10
|
BackgroundTaskManager,
|
|
9
11
|
createDelegateTool
|
|
10
|
-
} from "./roy-agent-core-
|
|
12
|
+
} from "./roy-agent-core-aa2j7bk9.js";
|
|
11
13
|
import {
|
|
12
14
|
TaskEntityEventTypes
|
|
13
15
|
} from "./roy-agent-core-8gxth0eh.js";
|
|
14
16
|
import {
|
|
15
17
|
batchArchiveTaskTool,
|
|
16
18
|
batchDeleteTaskTool,
|
|
19
|
+
cancelTaskTool,
|
|
17
20
|
completeTaskTool,
|
|
18
21
|
createTaskTool,
|
|
19
22
|
deleteTaskTool,
|
|
20
23
|
getTaskTool,
|
|
21
24
|
listTasksTool,
|
|
25
|
+
preCompleteTaskTool,
|
|
22
26
|
searchTasksTool,
|
|
23
27
|
treeTasksTool,
|
|
24
28
|
updateTaskTool
|
|
25
|
-
} from "./roy-agent-core-
|
|
29
|
+
} from "./roy-agent-core-vffccgf6.js";
|
|
26
30
|
import {
|
|
27
31
|
createOperationTool,
|
|
28
32
|
deleteOperationTool,
|
|
@@ -37,6 +41,16 @@ import {
|
|
|
37
41
|
import {
|
|
38
42
|
TaskHookPoints
|
|
39
43
|
} from "./roy-agent-core-1pg0fepg.js";
|
|
44
|
+
import {
|
|
45
|
+
TASK_ARCHIVED_STATUS_WORD,
|
|
46
|
+
TASK_CANCELLED_STATUS_WORD,
|
|
47
|
+
TASK_COMPLETED_STATUS_WORD,
|
|
48
|
+
TASK_DELIVERABLE_RECORDED,
|
|
49
|
+
TASK_REOPENED_STATUS_WORD,
|
|
50
|
+
TASK_TERMINAL_STATUS_WORDS,
|
|
51
|
+
TASK_TO_VALIDATE_STATUS_WORD,
|
|
52
|
+
TERMINAL_NON_ACCEPTABLE_STATUSES
|
|
53
|
+
} from "./roy-agent-core-4rtg69cn.js";
|
|
40
54
|
import {
|
|
41
55
|
envKeyToConfigKey
|
|
42
56
|
} from "./roy-agent-core-7hh0brvs.js";
|
|
@@ -84,16 +98,6 @@ var TASK_CONFIG_REGISTRATION = {
|
|
|
84
98
|
|
|
85
99
|
// src/env/task/task-component.ts
|
|
86
100
|
init_global_hook_manager();
|
|
87
|
-
|
|
88
|
-
// src/env/task/hooks/contexts.ts
|
|
89
|
-
var TASK_COMPLETE_TERMINAL_STATUSES = [
|
|
90
|
-
"completed",
|
|
91
|
-
"failed",
|
|
92
|
-
"cancelled",
|
|
93
|
-
"timeout"
|
|
94
|
-
];
|
|
95
|
-
|
|
96
|
-
// src/env/task/task-component.ts
|
|
97
101
|
init_env_context();
|
|
98
102
|
|
|
99
103
|
// src/env/task/tag-service.ts
|
|
@@ -184,6 +188,17 @@ class DefaultTagService {
|
|
|
184
188
|
// src/env/task/task-component.ts
|
|
185
189
|
init_decorator();
|
|
186
190
|
var logger2 = createLogger("task");
|
|
191
|
+
function isTerminalTaskStatus(status) {
|
|
192
|
+
return status === "completed" || status === "cancelled" || status === "archived";
|
|
193
|
+
}
|
|
194
|
+
function looksLikeSystemTerminalWording(currentStatus) {
|
|
195
|
+
if (!currentStatus)
|
|
196
|
+
return false;
|
|
197
|
+
const trimmed = currentStatus.trim();
|
|
198
|
+
if (!trimmed)
|
|
199
|
+
return false;
|
|
200
|
+
return TASK_TERMINAL_STATUS_WORDS.some((word) => trimmed.startsWith(word));
|
|
201
|
+
}
|
|
187
202
|
var DELIVERABLE_OPERATION_PREFIX = "Deliverable: ";
|
|
188
203
|
function formatDeliverableForOperation(deliverableStoragePath) {
|
|
189
204
|
if (!deliverableStoragePath)
|
|
@@ -336,6 +351,9 @@ class TaskComponent extends BaseComponent {
|
|
|
336
351
|
await this.registerTools();
|
|
337
352
|
this.toolComponent.register(createQueryBackgroundProcessTool(this.backgroundTaskManager), "built-in");
|
|
338
353
|
logger2.debug("[TaskComponent] Injected BackgroundTaskManager into query_background_process tool (factory pattern)");
|
|
354
|
+
const sessionComponent = this.env?.getComponent("session");
|
|
355
|
+
this.toolComponent.register(createCompactSessionTool(this.backgroundTaskManager, sessionComponent ?? null), "built-in");
|
|
356
|
+
logger2.debug("[TaskComponent] Registered compact_session tool (factory pattern)");
|
|
339
357
|
} else {
|
|
340
358
|
logger2.warn("[TaskComponent] ToolComponent not found, skipping tool registration");
|
|
341
359
|
}
|
|
@@ -352,6 +370,12 @@ class TaskComponent extends BaseComponent {
|
|
|
352
370
|
} catch (err) {
|
|
353
371
|
logger2.warn(`[TaskComponent] Failed to reset query_background_process tool: ${err.message}`);
|
|
354
372
|
}
|
|
373
|
+
try {
|
|
374
|
+
this.toolComponent.register(compactSessionTool, "built-in");
|
|
375
|
+
logger2.debug("[TaskComponent] Reset compact_session tool to no-deps default (cleanup)");
|
|
376
|
+
} catch (err) {
|
|
377
|
+
logger2.warn(`[TaskComponent] Failed to reset compact_session tool: ${err.message}`);
|
|
378
|
+
}
|
|
355
379
|
}
|
|
356
380
|
if (this.backgroundTaskManager) {
|
|
357
381
|
await this.backgroundTaskManager.dispose(this.skipAbortRunningTasksOnDispose ? {
|
|
@@ -378,7 +402,9 @@ class TaskComponent extends BaseComponent {
|
|
|
378
402
|
batchDeleteTaskTool(this),
|
|
379
403
|
updateTaskTool(this),
|
|
380
404
|
deleteTaskTool(this),
|
|
381
|
-
completeTaskTool(this)
|
|
405
|
+
completeTaskTool(this),
|
|
406
|
+
cancelTaskTool(this),
|
|
407
|
+
preCompleteTaskTool(this)
|
|
382
408
|
];
|
|
383
409
|
const operationToolsList = [
|
|
384
410
|
createOperationTool(this),
|
|
@@ -452,6 +478,31 @@ class TaskComponent extends BaseComponent {
|
|
|
452
478
|
const operations = await this.store.listOperations({ taskId: id });
|
|
453
479
|
return { ...task, operations, task };
|
|
454
480
|
}
|
|
481
|
+
withTerminalCurrentStatus(options, previousTask) {
|
|
482
|
+
const status = options.status;
|
|
483
|
+
if (!status)
|
|
484
|
+
return options;
|
|
485
|
+
if (options.current_status !== undefined)
|
|
486
|
+
return options;
|
|
487
|
+
let terminalWord;
|
|
488
|
+
switch (status) {
|
|
489
|
+
case "completed":
|
|
490
|
+
terminalWord = TASK_COMPLETED_STATUS_WORD;
|
|
491
|
+
break;
|
|
492
|
+
case "cancelled":
|
|
493
|
+
terminalWord = TASK_CANCELLED_STATUS_WORD;
|
|
494
|
+
break;
|
|
495
|
+
case "archived":
|
|
496
|
+
terminalWord = TASK_ARCHIVED_STATUS_WORD;
|
|
497
|
+
break;
|
|
498
|
+
default:
|
|
499
|
+
if (previousTask && isTerminalTaskStatus(previousTask.status) && looksLikeSystemTerminalWording(previousTask.current_status)) {
|
|
500
|
+
return { ...options, current_status: TASK_REOPENED_STATUS_WORD };
|
|
501
|
+
}
|
|
502
|
+
return options;
|
|
503
|
+
}
|
|
504
|
+
return { ...options, current_status: terminalWord };
|
|
505
|
+
}
|
|
455
506
|
async updateTask(id, options) {
|
|
456
507
|
const updateCtx = {
|
|
457
508
|
id,
|
|
@@ -459,7 +510,13 @@ class TaskComponent extends BaseComponent {
|
|
|
459
510
|
tagService: this.tagService
|
|
460
511
|
};
|
|
461
512
|
await this.executeHook(TaskHookPoints.BEFORE_UPDATE, updateCtx);
|
|
462
|
-
const
|
|
513
|
+
const requestedStatus = updateCtx.options.status;
|
|
514
|
+
let previousTask;
|
|
515
|
+
if (requestedStatus && !isTerminalTaskStatus(requestedStatus)) {
|
|
516
|
+
previousTask = await this.store.getTask(id);
|
|
517
|
+
}
|
|
518
|
+
const effectiveOptions = this.withTerminalCurrentStatus(updateCtx.options, previousTask);
|
|
519
|
+
const task = await this.store.updateTask(id, effectiveOptions);
|
|
463
520
|
if (task) {
|
|
464
521
|
const resultCtx = {
|
|
465
522
|
task,
|
|
@@ -469,18 +526,6 @@ class TaskComponent extends BaseComponent {
|
|
|
469
526
|
await this.executeHook(TaskHookPoints.AFTER_UPDATE, resultCtx);
|
|
470
527
|
this.publishEvent(TaskEntityEventTypes.UPDATED, { task, changes: options, sessionId: "" }, "");
|
|
471
528
|
logger2.info(`[TaskComponent] Task updated: ${id}`);
|
|
472
|
-
if (options.status && TASK_COMPLETE_TERMINAL_STATUSES.includes(options.status)) {
|
|
473
|
-
const env = getEnvContextOrEmpty();
|
|
474
|
-
const completeCtx = {
|
|
475
|
-
task,
|
|
476
|
-
changes: options,
|
|
477
|
-
terminalStatus: options.status,
|
|
478
|
-
sessionId: env.sessionId ?? "",
|
|
479
|
-
tagService: this.tagService
|
|
480
|
-
};
|
|
481
|
-
await this.executeHook(TaskHookPoints.AFTER_COMPLETE, completeCtx);
|
|
482
|
-
logger2.info(`[TaskComponent] Task completed (AFTER_COMPLETE fired): ${id} -> ${options.status}`);
|
|
483
|
-
}
|
|
484
529
|
}
|
|
485
530
|
return task;
|
|
486
531
|
}
|
|
@@ -513,9 +558,13 @@ class TaskComponent extends BaseComponent {
|
|
|
513
558
|
if (existing && existing.type === "cycle") {
|
|
514
559
|
throw new Error(`Cannot complete cycle task: #${id} - ${existing.title}. Cycle tasks are not meant to be completed.`);
|
|
515
560
|
}
|
|
561
|
+
if (existing && TERMINAL_NON_ACCEPTABLE_STATUSES.includes(existing.status)) {
|
|
562
|
+
throw new Error(`Cannot complete task: #${id} - ${existing.title}. ` + `It is already in terminal status "${existing.status}". ` + `Reopen it first via task_update(status="active") if acceptance should proceed.`);
|
|
563
|
+
}
|
|
516
564
|
const updateOptions = {
|
|
517
565
|
status: "completed",
|
|
518
|
-
progress: 100
|
|
566
|
+
progress: 100,
|
|
567
|
+
current_status: deliverableStoragePath ? `${TASK_COMPLETED_STATUS_WORD}(${TASK_DELIVERABLE_RECORDED}:${deliverableStoragePath})` : TASK_COMPLETED_STATUS_WORD
|
|
519
568
|
};
|
|
520
569
|
if (deliverableStoragePath) {
|
|
521
570
|
let existingContext = {};
|
|
@@ -549,6 +598,59 @@ class TaskComponent extends BaseComponent {
|
|
|
549
598
|
async updateTaskContext(id, context) {
|
|
550
599
|
return this.store.updateTask(id, { context });
|
|
551
600
|
}
|
|
601
|
+
async preCompleteTask(id, sessionId, deliverableStoragePath, progressSummary) {
|
|
602
|
+
const existing = await this.store.getTask(id);
|
|
603
|
+
if (existing && existing.type === "cycle") {
|
|
604
|
+
throw new Error(`Cannot pre-complete cycle task: #${id} - ${existing.title}. Cycle tasks are not meant to be completed or submitted for acceptance.`);
|
|
605
|
+
}
|
|
606
|
+
const toValidateWording = progressSummary ? `${TASK_TO_VALIDATE_STATUS_WORD}:${progressSummary}` : TASK_TO_VALIDATE_STATUS_WORD;
|
|
607
|
+
const updateOptions = {
|
|
608
|
+
status: "to_validate",
|
|
609
|
+
current_status: toValidateWording
|
|
610
|
+
};
|
|
611
|
+
if (deliverableStoragePath) {
|
|
612
|
+
let existingContext = {};
|
|
613
|
+
if (existing?.context) {
|
|
614
|
+
try {
|
|
615
|
+
const parsed = JSON.parse(existing.context);
|
|
616
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
617
|
+
existingContext = parsed;
|
|
618
|
+
}
|
|
619
|
+
} catch {
|
|
620
|
+
logger2.warn(`[TaskComponent] Task #${id} context is not valid JSON, ignoring when merging deliverable`);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
existingContext.deliverable_storage_path = deliverableStoragePath;
|
|
624
|
+
updateOptions.context = JSON.stringify(existingContext);
|
|
625
|
+
}
|
|
626
|
+
const task = await this.updateTask(id, updateOptions);
|
|
627
|
+
if (task) {
|
|
628
|
+
const env = getEnvContextOrEmpty();
|
|
629
|
+
const completeCtx = {
|
|
630
|
+
task,
|
|
631
|
+
changes: updateOptions,
|
|
632
|
+
terminalStatus: "to_validate",
|
|
633
|
+
sessionId: env.sessionId ?? sessionId,
|
|
634
|
+
tagService: this.tagService
|
|
635
|
+
};
|
|
636
|
+
await this.executeHook(TaskHookPoints.AFTER_COMPLETE, completeCtx);
|
|
637
|
+
const descParts = [];
|
|
638
|
+
const deliverableLine = formatDeliverableForOperation(deliverableStoragePath);
|
|
639
|
+
if (deliverableLine)
|
|
640
|
+
descParts.push(deliverableLine);
|
|
641
|
+
if (progressSummary)
|
|
642
|
+
descParts.push(progressSummary);
|
|
643
|
+
await this.createOperation({
|
|
644
|
+
taskId: id,
|
|
645
|
+
sessionId,
|
|
646
|
+
milestoneType: "milestone",
|
|
647
|
+
milestoneTitle: `${TASK_TO_VALIDATE_STATUS_WORD}(to_validate):Task #${id} submitted for acceptance`,
|
|
648
|
+
milestoneDescription: descParts.join(" / ") || TASK_TO_VALIDATE_STATUS_WORD
|
|
649
|
+
});
|
|
650
|
+
logger2.info(`[TaskComponent] Task submitted for acceptance (to_validate): ${id}, deliverable=${deliverableStoragePath || "(none)"}`);
|
|
651
|
+
}
|
|
652
|
+
return task;
|
|
653
|
+
}
|
|
552
654
|
async createOperation(options) {
|
|
553
655
|
const createCtx = {
|
|
554
656
|
options: { ...options }
|
|
@@ -617,12 +719,15 @@ __legacyDecorateClassTS([
|
|
|
617
719
|
__legacyDecorateClassTS([
|
|
618
720
|
TracedAs("task.component.completeTask", { recordParams: true, recordResult: true, log: true })
|
|
619
721
|
], TaskComponent.prototype, "completeTask", null);
|
|
722
|
+
__legacyDecorateClassTS([
|
|
723
|
+
TracedAs("task.component.preCompleteTask", { recordParams: true, recordResult: true, log: true })
|
|
724
|
+
], TaskComponent.prototype, "preCompleteTask", null);
|
|
620
725
|
__legacyDecorateClassTS([
|
|
621
726
|
TracedAs("task.component.createOperation", { recordParams: true, recordResult: true, log: true })
|
|
622
727
|
], TaskComponent.prototype, "createOperation", null);
|
|
623
728
|
// src/env/task/types.ts
|
|
624
729
|
import { z } from "zod";
|
|
625
|
-
var TaskStatusEnum = z.enum(["todo", "active", "completed", "paused", "cancelled", "archived"]);
|
|
730
|
+
var TaskStatusEnum = z.enum(["todo", "active", "to_validate", "completed", "paused", "cancelled", "archived"]);
|
|
626
731
|
var TaskPriorityEnum = z.enum(["low", "medium", "high"]);
|
|
627
732
|
var TaskTypeEnum = z.enum(["normal", "cycle", "longterm"]);
|
|
628
733
|
var ActionTypeEnum = z.enum([
|