@zmzai/agent-framework 0.5.2 → 0.9.0
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/core/events/bus.js +3 -3
- package/dist/core/events/bus.js.map +1 -1
- package/dist/core/events/manifest.d.ts +178 -0
- package/dist/core/events/manifest.d.ts.map +1 -1
- package/dist/core/events/manifest.js +106 -0
- package/dist/core/events/manifest.js.map +1 -1
- package/dist/core/events/sqlite-event-log.js +3 -3
- package/dist/core/events/sqlite-event-log.js.map +1 -1
- package/dist/core/runtime/attachments.d.ts +110 -0
- package/dist/core/runtime/attachments.d.ts.map +1 -1
- package/dist/core/runtime/attachments.js +124 -0
- package/dist/core/runtime/attachments.js.map +1 -1
- package/dist/core/runtime/extraction.d.ts +117 -0
- package/dist/core/runtime/extraction.d.ts.map +1 -0
- package/dist/core/runtime/extraction.js +256 -0
- package/dist/core/runtime/extraction.js.map +1 -0
- package/dist/core/runtime/lease-recovery.d.ts.map +1 -1
- package/dist/core/runtime/lease-recovery.js +50 -0
- package/dist/core/runtime/lease-recovery.js.map +1 -1
- package/dist/core/runtime/pi-bridge.d.ts +1 -1
- package/dist/core/runtime/pi-bridge.d.ts.map +1 -1
- package/dist/core/runtime/pi-bridge.js +19 -1
- package/dist/core/runtime/pi-bridge.js.map +1 -1
- package/dist/core/runtime/runner.d.ts +174 -0
- package/dist/core/runtime/runner.d.ts.map +1 -1
- package/dist/core/runtime/runner.js +795 -34
- package/dist/core/runtime/runner.js.map +1 -1
- package/dist/core/session/jsonl-store.d.ts.map +1 -1
- package/dist/core/session/jsonl-store.js +77 -0
- package/dist/core/session/jsonl-store.js.map +1 -1
- package/dist/core/session/sqlite-store.d.ts.map +1 -1
- package/dist/core/session/sqlite-store.js +87 -3
- package/dist/core/session/sqlite-store.js.map +1 -1
- package/dist/core/session/store.d.ts +6 -0
- package/dist/core/session/store.d.ts.map +1 -1
- package/dist/core/session/types.d.ts +30 -13
- package/dist/core/session/types.d.ts.map +1 -1
- package/dist/core/session/workflow.d.ts +30 -1
- package/dist/core/session/workflow.d.ts.map +1 -1
- package/dist/core/session/workflow.js.map +1 -1
- package/dist/core/task/completion.d.ts +142 -0
- package/dist/core/task/completion.d.ts.map +1 -0
- package/dist/core/task/completion.js +273 -0
- package/dist/core/task/completion.js.map +1 -0
- package/dist/core/task/contract.d.ts +26 -0
- package/dist/core/task/contract.d.ts.map +1 -0
- package/dist/core/task/contract.js +103 -0
- package/dist/core/task/contract.js.map +1 -0
- package/dist/core/task/index.d.ts +20 -0
- package/dist/core/task/index.d.ts.map +1 -0
- package/dist/core/task/index.js +16 -0
- package/dist/core/task/index.js.map +1 -0
- package/dist/core/task/plan.d.ts +121 -0
- package/dist/core/task/plan.d.ts.map +1 -0
- package/dist/core/task/plan.js +216 -0
- package/dist/core/task/plan.js.map +1 -0
- package/dist/core/task/progress.d.ts +43 -0
- package/dist/core/task/progress.d.ts.map +1 -0
- package/dist/core/task/progress.js +66 -0
- package/dist/core/task/progress.js.map +1 -0
- package/dist/core/task/store.d.ts +36 -0
- package/dist/core/task/store.d.ts.map +1 -0
- package/dist/core/task/store.js +104 -0
- package/dist/core/task/store.js.map +1 -0
- package/dist/core/task/types.d.ts +156 -0
- package/dist/core/task/types.d.ts.map +1 -0
- package/dist/core/task/types.js +26 -0
- package/dist/core/task/types.js.map +1 -0
- package/dist/core/tools/attachments.d.ts +4 -0
- package/dist/core/tools/attachments.d.ts.map +1 -0
- package/dist/core/tools/attachments.js +195 -0
- package/dist/core/tools/attachments.js.map +1 -0
- package/dist/core/tools/builtins.d.ts.map +1 -1
- package/dist/core/tools/builtins.js +6 -1
- package/dist/core/tools/builtins.js.map +1 -1
- package/dist/core/tools/task-block.d.ts +44 -0
- package/dist/core/tools/task-block.d.ts.map +1 -0
- package/dist/core/tools/task-block.js +76 -0
- package/dist/core/tools/task-block.js.map +1 -0
- package/dist/core/tools/task-deliver.d.ts +55 -0
- package/dist/core/tools/task-deliver.d.ts.map +1 -0
- package/dist/core/tools/task-deliver.js +98 -0
- package/dist/core/tools/task-deliver.js.map +1 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/package.json +11 -12
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
export const DEFAULT_NO_PROGRESS_POLICY = { blockedAt: 3, switchStrategyAt: 2 };
|
|
2
|
+
/** 单次 Attempt 的硬上限(规格 §10.1 / §16 阶段 D「最大 Attempt 数配置」)。 */
|
|
3
|
+
export const DEFAULT_MAX_ATTEMPTS = 24;
|
|
4
|
+
/** 单次任务的时间预算:累计执行时间的上限(规格 §10.2 / §16 阶段 D
|
|
5
|
+
* 「最长运行时间」)。默认一小时。
|
|
6
|
+
*
|
|
7
|
+
* 【计量口径】累加各 Attempt 的 durationMs,不是 `now - createdAt`。任务阻塞
|
|
8
|
+
* 期间(等授权、等用户补信息)run 已经结束,那段空白不计入——按墙钟算会让
|
|
9
|
+
* 「停了一夜的任务第二天点继续立刻超时」,把恢复通路堵死。 */
|
|
10
|
+
export const DEFAULT_MAX_DURATION_MS = 60 * 60 * 1000;
|
|
11
|
+
/** 时间预算的硬上限:24 小时。宿主调不到「永不拦截」。 */
|
|
12
|
+
export const MAX_DURATION_CEILING_MS = 24 * 60 * 60 * 1000;
|
|
13
|
+
/** 归一化宿主传入的时间预算。非正数 / NaN 一律回落默认值,而不是当成
|
|
14
|
+
* 「不限」——0 和负数在这里最可能的意思是配置写错了。 */
|
|
15
|
+
export function normalizeMaxDurationMs(value) {
|
|
16
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0
|
|
17
|
+
? Math.min(MAX_DURATION_CEILING_MS, Math.floor(value))
|
|
18
|
+
: DEFAULT_MAX_DURATION_MS;
|
|
19
|
+
}
|
|
20
|
+
/** 时间预算判定:还有余量返回 null,超了给一个 blocked(budget) 的 blocker。
|
|
21
|
+
*
|
|
22
|
+
* 与 Attempt 数上限并列,两者防的是不同形态的失控:轮数上限挡「每次都有一点
|
|
23
|
+
* 进展但永远做不完」,时间预算挡「单轮本身就很慢,轮数不多但总时长失控」。 */
|
|
24
|
+
export function durationBudgetBlocker(task, maxDurationMs) {
|
|
25
|
+
const spent = task.activeMs ?? 0;
|
|
26
|
+
if (spent <= maxDurationMs)
|
|
27
|
+
return null;
|
|
28
|
+
const minutes = (value) => Math.max(1, Math.round(value / 60_000));
|
|
29
|
+
return {
|
|
30
|
+
kind: "budget",
|
|
31
|
+
message: `任务已累计执行 ${minutes(spent)} 分钟,超过了单次任务的时间预算(${minutes(maxDurationMs)} 分钟)。`,
|
|
32
|
+
requiredAction: "看一眼执行轨迹,确认目标是否需要收窄或拆成几次;确认后可以继续。",
|
|
33
|
+
resumable: true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** 归一化宿主传入的策略:clamp 到 [1, 8],越界一律回落默认值而不是
|
|
37
|
+
* 悄悄放行——「把 blockedAt 设成 1e9 就不会被拦」正是要防的。 */
|
|
38
|
+
export function normalizeNoProgressPolicy(policy) {
|
|
39
|
+
const clamp = (value, fallback) => typeof value === "number" && Number.isFinite(value) ? Math.min(8, Math.max(1, Math.floor(value))) : fallback;
|
|
40
|
+
return {
|
|
41
|
+
blockedAt: clamp(policy?.blockedAt, DEFAULT_NO_PROGRESS_POLICY.blockedAt),
|
|
42
|
+
switchStrategyAt: clamp(policy?.switchStrategyAt, DEFAULT_NO_PROGRESS_POLICY.switchStrategyAt),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** 阻塞类判定:这些条件一旦成立,无论任务看起来多像完成了都**不能**返回
|
|
46
|
+
* delivered(规格 §9 条件 4)。顺序即优先级——越靠前的越具体,提示越有用。 */
|
|
47
|
+
function firstBlocker(task, state) {
|
|
48
|
+
if (state.unknownSideEffect) {
|
|
49
|
+
return {
|
|
50
|
+
kind: "unsafe_replay",
|
|
51
|
+
message: `上一个动作可能已经产生副作用,但没有拿到明确结果:${state.unknownSideEffect}`,
|
|
52
|
+
// 规格 §10.2:写操作结果未知时先核验外部状态,不许自动重放
|
|
53
|
+
requiredAction: "先确认外部系统的实际状态(文件、提交、远端页面等),再决定继续或重试。",
|
|
54
|
+
resumable: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (state.unsafeReplay) {
|
|
58
|
+
return {
|
|
59
|
+
kind: "unsafe_replay",
|
|
60
|
+
message: `有一个写操作结果不确定,重放可能造成重复提交或覆盖:${state.unsafeReplay}`,
|
|
61
|
+
requiredAction: "核验该操作在外部系统里的实际结果后,再选择重试或跳过。",
|
|
62
|
+
resumable: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (state.budgetExhausted) {
|
|
66
|
+
return {
|
|
67
|
+
kind: "budget",
|
|
68
|
+
message: `已用尽本次任务的执行预算:${state.budgetExhausted}`,
|
|
69
|
+
requiredAction: "确认是否继续投入(增加预算或缩小目标),然后重新发起。",
|
|
70
|
+
resumable: false,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
if (state.externalAuthRequired) {
|
|
74
|
+
return {
|
|
75
|
+
kind: "external_auth",
|
|
76
|
+
message: state.externalAuthRequired.message,
|
|
77
|
+
requiredAction: state.externalAuthRequired.requiredAction,
|
|
78
|
+
resumable: true,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (state.choiceRequired) {
|
|
82
|
+
return {
|
|
83
|
+
kind: "choice",
|
|
84
|
+
message: state.choiceRequired.message,
|
|
85
|
+
requiredAction: state.choiceRequired.requiredAction,
|
|
86
|
+
resumable: true,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (state.inputRequired) {
|
|
90
|
+
return {
|
|
91
|
+
kind: "input",
|
|
92
|
+
message: state.inputRequired.message,
|
|
93
|
+
requiredAction: state.inputRequired.requiredAction,
|
|
94
|
+
resumable: true,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (state.pendingPermissions > 0) {
|
|
98
|
+
return {
|
|
99
|
+
kind: "permission",
|
|
100
|
+
message: `有 ${state.pendingPermissions} 个操作在等待授权。`,
|
|
101
|
+
requiredAction: "处理授权卡片后任务会自动继续。",
|
|
102
|
+
resumable: true,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
/** 未完成的步骤:pending / in_progress / blocked。`cancelled` 不算未完成——
|
|
108
|
+
* 用户或模型明确放弃的步骤不该拦住交付(规格 §9 条件 2 说的是「必要步骤」)。 */
|
|
109
|
+
function openSteps(task) {
|
|
110
|
+
return task.steps.filter((step) => step.status === "pending" || step.status === "in_progress" || step.status === "blocked");
|
|
111
|
+
}
|
|
112
|
+
/** §9 条件 1:所有 required 验收条件 passed。 */
|
|
113
|
+
function unmetRequiredCriteria(task) {
|
|
114
|
+
return task.acceptanceCriteria
|
|
115
|
+
.filter((criterion) => criterion.required && criterion.status !== "passed")
|
|
116
|
+
.map((criterion) => ({ id: criterion.id, description: criterion.description, status: criterion.status }));
|
|
117
|
+
}
|
|
118
|
+
/** §9 条件 3:每个关键验收条件至少关联一条有效 evidence。
|
|
119
|
+
* 「有效」= evidence id 能在 task.evidence 里找到——悬空引用不算数。 */
|
|
120
|
+
function criteriaMissingEvidence(task) {
|
|
121
|
+
const known = new Set(task.evidence.map((item) => item.id));
|
|
122
|
+
return task.acceptanceCriteria
|
|
123
|
+
.filter((criterion) => criterion.required && criterion.status === "passed")
|
|
124
|
+
.filter((criterion) => !criterion.evidenceIds.some((id) => known.has(id)))
|
|
125
|
+
.map((criterion) => ({ id: criterion.id, description: criterion.description }));
|
|
126
|
+
}
|
|
127
|
+
/** 无进展时的恢复指令(规格 §10.1 的 1/2 档)。 */
|
|
128
|
+
function noProgressAdvisory(task, count, policy) {
|
|
129
|
+
if (count <= 0)
|
|
130
|
+
return undefined;
|
|
131
|
+
const open = openSteps(task);
|
|
132
|
+
const remaining = open.length ? open.map((step) => step.title).join("、") : "(未拆解出明确步骤)";
|
|
133
|
+
if (count >= policy.switchStrategyAt) {
|
|
134
|
+
return (`[任务未推进] 你已经连续 ${count} 轮没有让任务前进一步。换做同一件事的做法没有用。` +
|
|
135
|
+
`现在改变策略:先做诊断(读取现场、复现问题、确认假设),或把「${remaining}」缩成更小的可验证一步。` +
|
|
136
|
+
`不要重复上一轮的动作。`);
|
|
137
|
+
}
|
|
138
|
+
return (`[任务未推进] 上一轮结束时任务状态与开始时相同。先重新读取现场(文件、命令输出、外部状态),` +
|
|
139
|
+
`再说清楚是什么挡住了「${remaining}」。如果前提不成立,直接说明并给出替代路径。`);
|
|
140
|
+
}
|
|
141
|
+
/** 交付相关的恢复指令。
|
|
142
|
+
*
|
|
143
|
+
* 这两条 advisory 是「显式交付」能落地的关键:门把交付打回去的时候,必须让模型
|
|
144
|
+
* 知道**缺的是那一次声明**,否则它看到「验收条件未通过」只会重复做已经做完的事,
|
|
145
|
+
* 一路空转到 no_progress——把一次本可以一轮解决的问题变成三倍成本。
|
|
146
|
+
*
|
|
147
|
+
* 【为什么不能说「输出一段总结就算交付」】那正是被删掉的那条推导。这里的措辞刻意
|
|
148
|
+
* 指向工具:`task_deliver`。 */
|
|
149
|
+
function deliveryAdvisory(task, unmetIds) {
|
|
150
|
+
if (task.result === undefined) {
|
|
151
|
+
return ("[交付未声明] 你还没有提交交付声明,所以任务不能结束——结束本轮、说一句「已完成」、把 todo 标记完成都不算。" +
|
|
152
|
+
"如果目标已经达成,现在调用 `task_deliver`,按四个问题回答:做成了什么、改了哪些主要内容、怎么验证的、还有哪些没做完" +
|
|
153
|
+
"(无剩余项也要显式给空数组),并逐条给出验收条件的结论。" +
|
|
154
|
+
"如果还没达成,继续做,不要调用它。");
|
|
155
|
+
}
|
|
156
|
+
if (unmetIds.length) {
|
|
157
|
+
return (`[验收未完成] 你的交付声明里这些验收条件没有拿到通过结论:${unmetIds.join("、")}。` +
|
|
158
|
+
"两种可能:工作还没做完(那就继续做,做完再交付一次);或者你只是漏写了结论" +
|
|
159
|
+
"(那就补齐 `task_deliver` 的 `criteria`,id 用任务契约里印出的那一个)。" +
|
|
160
|
+
"注意 required 条件不能用 `not_applicable` 绕过。");
|
|
161
|
+
}
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
/** 把阻塞原因映射到任务生命周期状态。
|
|
165
|
+
*
|
|
166
|
+
* `waiting_*` 与 `blocked` 的分界是「谁该动」:等用户做一件明确的事 →
|
|
167
|
+
* waiting_*(界面给对应按钮);系统自己搞不定、需要判断 → blocked。 */
|
|
168
|
+
export function lifecycleForBlocker(kind) {
|
|
169
|
+
switch (kind) {
|
|
170
|
+
case "permission":
|
|
171
|
+
return "waiting_permission";
|
|
172
|
+
case "input":
|
|
173
|
+
case "choice":
|
|
174
|
+
return "waiting_input";
|
|
175
|
+
case "external_auth":
|
|
176
|
+
return "waiting_external";
|
|
177
|
+
// unsafe_replay / budget / no_progress 都属于「不能自动继续」,需要人判断
|
|
178
|
+
default:
|
|
179
|
+
return "blocked";
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* 可信完成判定(规格 §9)。纯函数。
|
|
184
|
+
*
|
|
185
|
+
* 判定顺序是有讲究的:**先阻塞、后完成**。一个任务即使所有步骤都完成了,
|
|
186
|
+
* 只要还有一个未回应的授权请求或结果未知的写操作,就不能说自己交付了。
|
|
187
|
+
* 反过来先判完成,这些悬空状态就会被步骤的完成态掩盖掉——那正是规格
|
|
188
|
+
* §19「不得把『无法验证』包装成『已完成但建议用户检查』」要禁止的行为。
|
|
189
|
+
*/
|
|
190
|
+
export function evaluateTaskCompletion(task, state, policyInput) {
|
|
191
|
+
const policy = normalizeNoProgressPolicy(policyInput);
|
|
192
|
+
if (state.cancelled)
|
|
193
|
+
return { status: "cancelled", reason: "用户已停止任务。" };
|
|
194
|
+
// 1) 阻塞优先(§9 条件 4)
|
|
195
|
+
const blocker = firstBlocker(task, state);
|
|
196
|
+
if (blocker)
|
|
197
|
+
return { status: "blocked", blocker };
|
|
198
|
+
// 2) 确定性失败先于无进展保护:no_progress 是策略性停止(可恢复),
|
|
199
|
+
// 用它盖住一个「已经没救」的真实原因会误导用户去重试。
|
|
200
|
+
if (state.fatalError) {
|
|
201
|
+
return { status: "failed", reason: state.fatalError };
|
|
202
|
+
}
|
|
203
|
+
// 3) 无进展保护(§10.1):先于完成判定,但晚于真实阻塞——
|
|
204
|
+
// 权限等待会让状态停住,那是「在等」不是「卡住」。
|
|
205
|
+
if (task.noProgressCount >= policy.blockedAt) {
|
|
206
|
+
// 上游持续失败是最常见的「无进展」成因,那时「换个做法」是错误的建议——
|
|
207
|
+
// 模型什么都没做错。把真实错误带上,用户才知道该等一会儿还是该查配置。
|
|
208
|
+
const causedBy = state.lastError ? `最后一次运行失败:${state.lastError}` : null;
|
|
209
|
+
return {
|
|
210
|
+
status: "blocked",
|
|
211
|
+
blocker: {
|
|
212
|
+
kind: "no_progress",
|
|
213
|
+
message: causedBy
|
|
214
|
+
? `连续 ${task.noProgressCount} 轮没有实质进展。${causedBy}`
|
|
215
|
+
: `连续 ${task.noProgressCount} 轮没有实质进展,已停止自动续跑。`,
|
|
216
|
+
requiredAction: causedBy
|
|
217
|
+
? "确认上游可用(网络、额度、模型配置)后继续;任务会从中断处接着做。"
|
|
218
|
+
: "查看上面的执行轨迹,确认目标是否需要调整,或直接指出下一步该做什么。",
|
|
219
|
+
resumable: true,
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// 4) 一次运行没跑完(上游断流、工具崩溃、进程被杀)不等于任务失败。规格 §10.2
|
|
224
|
+
// 把这类归为 recovering,只有重试耗尽才升级。这里返回 continue,由任务层
|
|
225
|
+
// 按 Attempt 上限决定什么时候放弃。
|
|
226
|
+
if (!state.attemptSettled) {
|
|
227
|
+
return {
|
|
228
|
+
status: "continue",
|
|
229
|
+
reason: "上一轮运行未能正常结束。",
|
|
230
|
+
advisory: (state.lastError ? `上一轮运行中断了:${state.lastError}\n` : "上一轮运行中断了。") +
|
|
231
|
+
"先确认工作区当前的实际状态(哪些文件已经改过、外部系统处于什么状态)," +
|
|
232
|
+
"再从中断的地方继续——不要从头再做一遍,那会产生重复副作用。",
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
// 5) 完成判定(§9 五条件)
|
|
236
|
+
const unmet = unmetRequiredCriteria(task);
|
|
237
|
+
const open = openSteps(task);
|
|
238
|
+
const missingEvidence = criteriaMissingEvidence(task);
|
|
239
|
+
// 6) 显式交付声明(§9 条件 6)。交付是一次动作,不是一个可以被推断出来的语气。
|
|
240
|
+
//
|
|
241
|
+
// 【为什么单列一条而不是并进条件 1】任务可能一条 required 验收条件都没有
|
|
242
|
+
// (宿主显式添加的条件全为 optional 时),此时条件 1/2/3/5 会**全部平凡通过**,
|
|
243
|
+
// 交付又退回到「文本非空即完成」。单列之后,「交付必须由模型明确声明」这条
|
|
244
|
+
// 不变量与条件集无关地成立——它是 §3.1 那条根因(一次运行正常结束 ≠ 目标已实现)
|
|
245
|
+
// 的最终落点。`task.result` 由 `applyDelivery` 写入,那是它的唯一生产者。
|
|
246
|
+
const deliveryDeclared = task.result !== undefined;
|
|
247
|
+
const reasons = [];
|
|
248
|
+
if (unmet.length)
|
|
249
|
+
reasons.push(`验收条件未通过:${unmet.map((item) => item.description).join("、")}`);
|
|
250
|
+
if (open.length)
|
|
251
|
+
reasons.push(`仍有未完成的步骤:${open.map((step) => step.title).join("、")}`);
|
|
252
|
+
if (missingEvidence.length)
|
|
253
|
+
reasons.push(`验收条件缺少验证证据:${missingEvidence.map((item) => item.description).join("、")}`);
|
|
254
|
+
if (!state.finalTextPresent)
|
|
255
|
+
reasons.push("尚未生成最终交付说明");
|
|
256
|
+
if (!deliveryDeclared)
|
|
257
|
+
reasons.push("尚未提交交付声明");
|
|
258
|
+
if (reasons.length === 0) {
|
|
259
|
+
return { status: "delivered", reason: "全部验收条件已通过、留有条目证据,并由模型显式声明交付。" };
|
|
260
|
+
}
|
|
261
|
+
// 5) 未完成 → 内部续跑(不创建用户消息)
|
|
262
|
+
const advisory = noProgressAdvisory(task, task.noProgressCount, policy);
|
|
263
|
+
const delivery = deliveryAdvisory(task, unmet.map((item) => item.id));
|
|
264
|
+
const unresolved = state.unresolvedToolErrors.length
|
|
265
|
+
? `上一轮有工具调用以失败告终(${state.unresolvedToolErrors.join(";")}),如果它们挡在路上,先换一条路。`
|
|
266
|
+
: "";
|
|
267
|
+
return {
|
|
268
|
+
status: "continue",
|
|
269
|
+
reason: reasons.join(";"),
|
|
270
|
+
...(advisory || delivery || unresolved ? { advisory: [delivery, advisory, unresolved].filter(Boolean).join("\n") } : {}),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=completion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion.js","sourceRoot":"","sources":["../../../src/core/task/completion.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { TaskRecord, TaskResult, TaskStep } from "./types.js";
|
|
2
|
+
/** 剩余步骤(非终态的)。cancelled/completed 不进「剩余」。 */
|
|
3
|
+
export declare function remainingSteps(task: TaskRecord): TaskStep[];
|
|
4
|
+
/** 渲染任务契约。`advisory` 传入时追加在末尾——续跑指令与契约同源,
|
|
5
|
+
* 避免出现两处互相矛盾的指示。 */
|
|
6
|
+
export declare function taskContractText(task: TaskRecord, advisory?: string): string;
|
|
7
|
+
/** 首次 Attempt 的任务契约(无 advisory)。 */
|
|
8
|
+
export declare function initialTaskContract(task: TaskRecord): string;
|
|
9
|
+
/** 交付摘要的兜底文本。
|
|
10
|
+
*
|
|
11
|
+
* 【2026-09-19 起它基本不可达】`task_deliver` 是 `TaskRecord.result` 的唯一生产者,
|
|
12
|
+
* 而 Completion Gate 的条件 6 要求没有 `result` 就不能交付——所以走到交付那一步时
|
|
13
|
+
* `result` 一定在。保留它是为了两种残留:升级前就已 delivered 的旧记录(读回来渲染
|
|
14
|
+
* 历史卡片),以及宿主自己写入 result 的极端情况。
|
|
15
|
+
*
|
|
16
|
+
* 措辞刻意**不含任何完成性描述**:规格 §18.7 要求交付信息包含结果/改动/验证/剩余项,
|
|
17
|
+
* 而一段编出来的「已全部完成」比一段朴实的统计更糟——旧版本那句「完成了 0 个步骤、
|
|
18
|
+
* 0 次工具调用。」正是被用户当场抓到的那一行。 */
|
|
19
|
+
export declare function fallbackResult(input: {
|
|
20
|
+
task: TaskRecord;
|
|
21
|
+
filesEdited: readonly string[];
|
|
22
|
+
toolCalls: number;
|
|
23
|
+
}): TaskResult;
|
|
24
|
+
/** 把结构化交付信息渲染成给用户看的文本(规格 §21 最终交付示例)。 */
|
|
25
|
+
export declare function renderResult(result: TaskResult): string;
|
|
26
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/core/task/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAkBnE,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,QAAQ,EAAE,CAE3D;AAED;qBACqB;AACrB,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CA8C5E;AAED,oCAAoC;AACpC,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAE5D;AAED;;;;;;;;;8BAS8B;AAC9B,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,UAAU,CAUb;AAED,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAMvD"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/** 任务契约的上下文表达(规格 3 §8.2 / §6)。
|
|
2
|
+
*
|
|
3
|
+
* 【为什么放进 systemPrompt 而不是一条 user 消息】规格 §19 明文禁止「用新增
|
|
4
|
+
* 一条伪用户消息作为内部 continuation」。除了「不许伪造用户说过的话」这条
|
|
5
|
+
* 原则,还有三个实际后果:伪用户消息会落库、会出现在聊天记录里(用户看到
|
|
6
|
+
* 自己没发过的话)、会被计入 token 与消息序号、rewind 时会跟着一起被截断。
|
|
7
|
+
* 作为系统指令注入则完全不碰消息流。
|
|
8
|
+
*
|
|
9
|
+
* 每个 Attempt 重新注入一次,因此上下文被压缩掉也不影响任务契约的存续
|
|
10
|
+
* (规格 §6「必须进入上下文压缩后的恢复上下文」)。 */
|
|
11
|
+
function stepLine(step) {
|
|
12
|
+
const mark = step.status === "completed" ? "[x]" : step.status === "in_progress" ? "[~]" : step.status === "cancelled" ? "[-]" : "[ ]";
|
|
13
|
+
return `${mark} ${step.title}`;
|
|
14
|
+
}
|
|
15
|
+
/** 剩余步骤(非终态的)。cancelled/completed 不进「剩余」。 */
|
|
16
|
+
export function remainingSteps(task) {
|
|
17
|
+
return task.steps.filter((step) => step.status === "pending" || step.status === "in_progress" || step.status === "blocked");
|
|
18
|
+
}
|
|
19
|
+
/** 渲染任务契约。`advisory` 传入时追加在末尾——续跑指令与契约同源,
|
|
20
|
+
* 避免出现两处互相矛盾的指示。 */
|
|
21
|
+
export function taskContractText(task, advisory) {
|
|
22
|
+
const lines = [];
|
|
23
|
+
lines.push("<task-contract>");
|
|
24
|
+
lines.push(`目标:${task.goal}`);
|
|
25
|
+
if (task.constraints.length) {
|
|
26
|
+
lines.push("用户追加的约束:");
|
|
27
|
+
for (const constraint of task.constraints)
|
|
28
|
+
lines.push(`- ${constraint}`);
|
|
29
|
+
}
|
|
30
|
+
const required = task.acceptanceCriteria.filter((criterion) => criterion.required);
|
|
31
|
+
if (required.length) {
|
|
32
|
+
// id 印出来是**功能必需**的:`task_deliver` 的 `criteria[].id` 要引用它。
|
|
33
|
+
// 不印 id 的话模型只能猜,而猜错的后果是那条条件的结论落不到契约上、
|
|
34
|
+
// 任务被门无限打回。方括号的形式与 steps 的 checkbox 区分开。
|
|
35
|
+
lines.push("验收条件(逐条给出结论才算完成;方括号里是交付时要引用的 id):");
|
|
36
|
+
for (const criterion of required) {
|
|
37
|
+
lines.push(`- [${criterion.id}] ${criterion.description}${criterion.status === "passed" ? "(已通过)" : ""}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (task.steps.length) {
|
|
41
|
+
lines.push("任务计划:");
|
|
42
|
+
for (const step of task.steps)
|
|
43
|
+
lines.push(stepLine(step));
|
|
44
|
+
}
|
|
45
|
+
const remaining = remainingSteps(task);
|
|
46
|
+
if (remaining.length) {
|
|
47
|
+
lines.push(`剩余步骤:${remaining.map((step) => step.title).join("、")}`);
|
|
48
|
+
}
|
|
49
|
+
if (task.evidence.length) {
|
|
50
|
+
lines.push("已有验证证据:");
|
|
51
|
+
for (const item of task.evidence.slice(-8))
|
|
52
|
+
lines.push(`- [${item.kind}] ${item.summary}`);
|
|
53
|
+
}
|
|
54
|
+
if (task.blocker) {
|
|
55
|
+
lines.push(`当前阻塞(${task.blocker.kind}):${task.blocker.message}`);
|
|
56
|
+
lines.push(`需要做的事:${task.blocker.requiredAction}`);
|
|
57
|
+
}
|
|
58
|
+
lines.push("继续执行这件事,直到验收条件全部满足并留下证据。不要在中途把控制权交回用户——", "只有确实需要用户授权、补充信息或处理外部状态(登录、验证码、付款)时才停下(用 `task_block`),并说明卡在哪里、需要用户做什么。",
|
|
59
|
+
// 显式交付的指示必须每次 Attempt 都出现:它是交付的唯一入口,模型忘了它,
|
|
60
|
+
// 任务会一路空转到 no_progress,用户看到的是一个「什么都没做就卡住」的任务。
|
|
61
|
+
"做完之后**必须调用 `task_deliver`** 提交交付信息(做成了什么 / 改了哪些内容 / 怎么验证的 / 还有哪些没做完,"
|
|
62
|
+
+ "并逐条给出上面每个验收条件的结论)。结束一轮、说一句「已完成」、把 todo 勾完都**不能**让任务结束——", "没有这次声明,任务不会交付。如果你发现还有没做完的,先别调用它,继续做。");
|
|
63
|
+
if (advisory)
|
|
64
|
+
lines.push("", advisory);
|
|
65
|
+
lines.push("</task-contract>");
|
|
66
|
+
return lines.join("\n");
|
|
67
|
+
}
|
|
68
|
+
/** 首次 Attempt 的任务契约(无 advisory)。 */
|
|
69
|
+
export function initialTaskContract(task) {
|
|
70
|
+
return taskContractText(task);
|
|
71
|
+
}
|
|
72
|
+
/** 交付摘要的兜底文本。
|
|
73
|
+
*
|
|
74
|
+
* 【2026-09-19 起它基本不可达】`task_deliver` 是 `TaskRecord.result` 的唯一生产者,
|
|
75
|
+
* 而 Completion Gate 的条件 6 要求没有 `result` 就不能交付——所以走到交付那一步时
|
|
76
|
+
* `result` 一定在。保留它是为了两种残留:升级前就已 delivered 的旧记录(读回来渲染
|
|
77
|
+
* 历史卡片),以及宿主自己写入 result 的极端情况。
|
|
78
|
+
*
|
|
79
|
+
* 措辞刻意**不含任何完成性描述**:规格 §18.7 要求交付信息包含结果/改动/验证/剩余项,
|
|
80
|
+
* 而一段编出来的「已全部完成」比一段朴实的统计更糟——旧版本那句「完成了 0 个步骤、
|
|
81
|
+
* 0 次工具调用。」正是被用户当场抓到的那一行。 */
|
|
82
|
+
export function fallbackResult(input) {
|
|
83
|
+
const { task, filesEdited, toolCalls } = input;
|
|
84
|
+
const completed = task.steps.filter((step) => step.status === "completed");
|
|
85
|
+
const remaining = remainingSteps(task).map((step) => step.title);
|
|
86
|
+
return {
|
|
87
|
+
outcome: `这条任务没有留下交付说明(记录到 ${completed.length} 个已完成步骤、${toolCalls} 次工具调用)。`,
|
|
88
|
+
changes: [...filesEdited],
|
|
89
|
+
verification: task.evidence.slice(-6).map((item) => item.summary),
|
|
90
|
+
remaining,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** 把结构化交付信息渲染成给用户看的文本(规格 §21 最终交付示例)。 */
|
|
94
|
+
export function renderResult(result) {
|
|
95
|
+
const lines = [result.outcome];
|
|
96
|
+
if (result.changes.length)
|
|
97
|
+
lines.push(`改动:${result.changes.join("、")}`);
|
|
98
|
+
if (result.verification.length)
|
|
99
|
+
lines.push(`验证:${result.verification.join(";")}`);
|
|
100
|
+
lines.push(`剩余项:${result.remaining.length ? result.remaining.join("、") : "无"}`);
|
|
101
|
+
return lines.join("\n");
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/core/task/contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** 持续任务执行(规格 3)的公开面。
|
|
2
|
+
*
|
|
3
|
+
* 模块划分:
|
|
4
|
+
* - `types` 领域模型与状态枚举——唯一的真源
|
|
5
|
+
* - `plan` 运行时事实(todo / 工具结果)→ 任务契约的投影
|
|
6
|
+
* - `completion` Completion Gate:可信完成判定(纯函数)
|
|
7
|
+
* - `progress` 跨 Attempt 的进度指纹与空转检测
|
|
8
|
+
* - `contract` 任务契约的上下文表达与交付文本
|
|
9
|
+
* - `store` TaskStore 接口 + CAS 不变量 + 内存参考实现 */
|
|
10
|
+
export type { TaskLifecycleStatus, TaskStepStatus, AcceptanceCriterionStatus, AcceptanceCriterion, TaskStep, TaskEvidence, TaskEvidenceKind, TaskBlocker, TaskBlockerKind, TaskRecord, TaskResult, TaskDeliveryDeclaration, TaskPatch, CreateTaskInput, } from "./types.js";
|
|
11
|
+
export { newTaskId, newTaskStepId, newCriterionId, newEvidenceId, isTerminalStatus, isWaitingStatus, isActiveStatus, } from "./types.js";
|
|
12
|
+
export type { TaskStore } from "./store.js";
|
|
13
|
+
export { createMemoryTaskStore, createTaskRecord, applyTaskPatch, TASK_REVISION_CONFLICT } from "./store.js";
|
|
14
|
+
export { IMPLICIT_CRITERION_ID, MAX_EVIDENCE, defaultCriteriaFor, stepIdForContent, projectTodos, applyDelivery, evidenceKindForTool, appendEvidence, pruneEvidenceRefs, newTaskRecord, fallbackStep, } from "./plan.js";
|
|
15
|
+
export type { CompletionRuntimeState, CompletionVerdict, NoProgressPolicy } from "./completion.js";
|
|
16
|
+
export { evaluateTaskCompletion, lifecycleForBlocker, normalizeNoProgressPolicy, normalizeMaxDurationMs, durationBudgetBlocker, DEFAULT_NO_PROGRESS_POLICY, DEFAULT_MAX_ATTEMPTS, DEFAULT_MAX_DURATION_MS, MAX_DURATION_CEILING_MS, } from "./completion.js";
|
|
17
|
+
export type { ProgressFingerprintInput, ProgressAdvance } from "./progress.js";
|
|
18
|
+
export { taskFingerprint, advanceProgress } from "./progress.js";
|
|
19
|
+
export { taskContractText, initialTaskContract, fallbackResult, renderResult, remainingSteps } from "./contract.js";
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/task/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;kDAQkD;AAElD,YAAY,EACV,mBAAmB,EACnB,cAAc,EACd,yBAAyB,EACzB,mBAAmB,EACnB,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,UAAU,EACV,UAAU,EACV,uBAAuB,EACvB,SAAS,EACT,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,SAAS,EACT,aAAa,EACb,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAE7G,OAAO,EACL,qBAAqB,EACrB,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,YAAY,GACb,MAAM,WAAW,CAAC;AAEnB,YAAY,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnG,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,0BAA0B,EAC1B,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** 持续任务执行(规格 3)的公开面。
|
|
2
|
+
*
|
|
3
|
+
* 模块划分:
|
|
4
|
+
* - `types` 领域模型与状态枚举——唯一的真源
|
|
5
|
+
* - `plan` 运行时事实(todo / 工具结果)→ 任务契约的投影
|
|
6
|
+
* - `completion` Completion Gate:可信完成判定(纯函数)
|
|
7
|
+
* - `progress` 跨 Attempt 的进度指纹与空转检测
|
|
8
|
+
* - `contract` 任务契约的上下文表达与交付文本
|
|
9
|
+
* - `store` TaskStore 接口 + CAS 不变量 + 内存参考实现 */
|
|
10
|
+
export { newTaskId, newTaskStepId, newCriterionId, newEvidenceId, isTerminalStatus, isWaitingStatus, isActiveStatus, } from "./types.js";
|
|
11
|
+
export { createMemoryTaskStore, createTaskRecord, applyTaskPatch, TASK_REVISION_CONFLICT } from "./store.js";
|
|
12
|
+
export { IMPLICIT_CRITERION_ID, MAX_EVIDENCE, defaultCriteriaFor, stepIdForContent, projectTodos, applyDelivery, evidenceKindForTool, appendEvidence, pruneEvidenceRefs, newTaskRecord, fallbackStep, } from "./plan.js";
|
|
13
|
+
export { evaluateTaskCompletion, lifecycleForBlocker, normalizeNoProgressPolicy, normalizeMaxDurationMs, durationBudgetBlocker, DEFAULT_NO_PROGRESS_POLICY, DEFAULT_MAX_ATTEMPTS, DEFAULT_MAX_DURATION_MS, MAX_DURATION_CEILING_MS, } from "./completion.js";
|
|
14
|
+
export { taskFingerprint, advanceProgress } from "./progress.js";
|
|
15
|
+
export { taskContractText, initialTaskContract, fallbackResult, renderResult, remainingSteps } from "./contract.js";
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/task/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;kDAQkD;AAkBlD,OAAO,EACL,SAAS,EACT,aAAa,EACb,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAE7G,OAAO,EACL,qBAAqB,EACrB,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,YAAY,GACb,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,0BAA0B,EAC1B,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { type AcceptanceCriterion, type TaskDeliveryDeclaration, type TaskEvidence, type TaskEvidenceKind, type TaskRecord, type TaskResult, type TaskStep, type TaskStepStatus } from "./types.js";
|
|
2
|
+
/** 运行时事实 → 任务契约的投影(规格 3 §6「`todo.updated` 可暂时作为步骤投影,
|
|
3
|
+
* 但不能继续作为唯一的任务来源」)。
|
|
4
|
+
*
|
|
5
|
+
* 分工:
|
|
6
|
+
* - 模型通过 `todo` 工具表达**计划**;这里把它投影成 `TaskRecord.steps`,
|
|
7
|
+
* 但 TaskRecord 是权威——todo 事件没了、乱序了、被压缩掉了,任务仍完整。
|
|
8
|
+
* - 工具调用结果由运行时(runner)观测后投影成 `TaskEvidence`。**模型不能
|
|
9
|
+
* 自己声明证据**,这也是「可信完成」里「可信」二字的落点。
|
|
10
|
+
*
|
|
11
|
+
* 本模块同样是纯函数,便于单测。 */
|
|
12
|
+
/** 隐式验收条件的固定 id。简单问答不强制拆计划(规格 §4.2),它只有这
|
|
13
|
+
* 一条条件:用户的目标本身。id 固定是为了让「步骤全部完成 → 目标达成」
|
|
14
|
+
* 这条推导能在任意一次投影里被识别出来。 */
|
|
15
|
+
export declare const IMPLICIT_CRITERION_ID = "crit_implicit";
|
|
16
|
+
/** 任务没有显式验收条件时的隐式条件(规格 §6「简单问答可以只有一个隐式
|
|
17
|
+
* 验收条件,不强制生成复杂计划」)。 */
|
|
18
|
+
export declare function defaultCriteriaFor(goal: string): AcceptanceCriterion[];
|
|
19
|
+
/** 步骤 id 由 (taskId, todo 内容) 决定而不是随机生成:模型每轮重发整份
|
|
20
|
+
* todo 列表是常态,随机 id 会让同一个步骤在每轮里「变成新步骤」,步骤数
|
|
21
|
+
* 无限膨胀、已完成的又对不上号。 */
|
|
22
|
+
export declare function stepIdForContent(taskId: string, content: string): string;
|
|
23
|
+
type TodoLike = {
|
|
24
|
+
content: string;
|
|
25
|
+
status: TaskStepStatus | "pending" | "in_progress" | "completed" | "cancelled";
|
|
26
|
+
};
|
|
27
|
+
/** 把一份 todo 列表投影到步骤数组上。
|
|
28
|
+
*
|
|
29
|
+
* 【为什么消失的步骤标 cancelled 而不是删除】规格 §10.3 要求重启恢复时
|
|
30
|
+
* 「保留 TaskRecord 和已完成步骤」。已完成的必须留(那是交付依据);没完成
|
|
31
|
+
* 但模型不再提及的,说明它被重新规划掉了——留成 pending 会让任务永远无法
|
|
32
|
+
* 通过 Completion Gate 的条件 2,删掉又丢掉了「曾经计划过」的信息。
|
|
33
|
+
* 标 cancelled 两者兼顾。 */
|
|
34
|
+
export declare function projectTodos(input: {
|
|
35
|
+
taskId: string;
|
|
36
|
+
steps: readonly TaskStep[];
|
|
37
|
+
todos: readonly TodoLike[];
|
|
38
|
+
now: string;
|
|
39
|
+
}): TaskStep[];
|
|
40
|
+
/** 让隐式条件跟随步骤推进。
|
|
41
|
+
*
|
|
42
|
+
* 【2026-09-19 已删除】这里原来有一个 `projectImplicitCriterion`:看「本轮有没有
|
|
43
|
+
* 输出文本」/「步骤是否都做完了」,据此把隐式条件判 passed。它是一条从**可观测
|
|
44
|
+
* 的弱事实**到**只有当事人知道的结论**之间的跳跃,而且跳得没有依据——
|
|
45
|
+
*
|
|
46
|
+
* 事故:用户发「继续执行」,模型回「继续。跑自检验证前面改动的正确性:」,一句话
|
|
47
|
+
* 停在冒号上、零工具调用、28 个输出 token;`answerPresent` 为真,隐式条件判 passed,
|
|
48
|
+
* Completion Gate 五条件全过,`task.delivered` 照发,交付卡写着「完成了 0 个步骤、
|
|
49
|
+
* 0 次工具调用」「剩余项:无」。任务进终态,用户那句「继续执行」被吞掉。
|
|
50
|
+
*
|
|
51
|
+
* 规格 §3.1 的根因就是「一次运行正常结束 ≠ 用户目标已实现」,而这条推导犯的是同一个
|
|
52
|
+
* 错,只是把「运行结束」换成了「文本非空」。替代方案是 `applyDelivery`:验收条件的
|
|
53
|
+
* 结论只有一个来源——模型在 `task_deliver` 里的**显式声明**;框架不再从任何东西推导
|
|
54
|
+
* 它。这与 `task_block` 注释里那条判断(不猜最终文本,让模型显式声明)是同一条原则
|
|
55
|
+
* 在交付侧的应用。 */
|
|
56
|
+
export type DeliveryProjection = {
|
|
57
|
+
criteria: AcceptanceCriterion[];
|
|
58
|
+
result: TaskResult;
|
|
59
|
+
/** 声明里提到、但任务契约里不存在的条件 id(模型写错了)。 */
|
|
60
|
+
unknownCriterionIds: string[];
|
|
61
|
+
/** 仍没有拿到 passed 结论的 required 条件 id——门会据此打回续跑并点名。 */
|
|
62
|
+
unfulfilledRequiredIds: string[];
|
|
63
|
+
};
|
|
64
|
+
/** 把一次交付声明投影进任务契约(规格 §9 条件 1/3、§14.1 四问)。
|
|
65
|
+
*
|
|
66
|
+
* 【为什么证据是「整份任务集合」而不是按条件挑】工具调用与验收条件之间没有可靠
|
|
67
|
+
* 映射:框架不知道第 3 次 `pnpm build` 服务的是哪一条条件。后果只有两种:全都挂
|
|
68
|
+
* 上,或都不挂。都不挂会让条件 3 永远不满足(每个 passed 条件至少要一条有效证据),
|
|
69
|
+
* 完成判定直接失效;全都挂是保守的那一侧——它不会让**不该通过**的条件通过,只会
|
|
70
|
+
* 让「有证据」这条判定比理想情况宽一点。而真正会骗人的那一步(把模型自己的话当
|
|
71
|
+
* 证据)另有约束:只有任务里**一条别的证据都没有**时,才用声明本身顶上。 */
|
|
72
|
+
export declare function applyDelivery(input: {
|
|
73
|
+
criteria: readonly AcceptanceCriterion[];
|
|
74
|
+
delivery: TaskDeliveryDeclaration;
|
|
75
|
+
evidence: readonly TaskEvidence[];
|
|
76
|
+
/** 交付声明自身被记成的证据 id(仅当任务没有任何工具证据时存在)。 */
|
|
77
|
+
declarationEvidenceId?: string;
|
|
78
|
+
/** 本轮实际编辑过的文件。模型没给 `changes` 时用它兜底。 */
|
|
79
|
+
observedChanges: readonly string[];
|
|
80
|
+
}): DeliveryProjection;
|
|
81
|
+
export declare function evidenceKindForTool(tool: string): TaskEvidenceKind | null;
|
|
82
|
+
/** 证据上限。超出后淘汰最老的,并同步清掉一切指向它的引用(否则
|
|
83
|
+
* Completion Gate 的条件 3 会因为悬空引用而永远不满足)。 */
|
|
84
|
+
export declare const MAX_EVIDENCE = 96;
|
|
85
|
+
export type EvidenceAppend = {
|
|
86
|
+
evidence: TaskEvidence[];
|
|
87
|
+
/** 被淘汰的证据 id,调用方需要从 criteria/steps 的 evidenceIds 里剔除。 */
|
|
88
|
+
dropped: string[];
|
|
89
|
+
};
|
|
90
|
+
export declare function appendEvidence(input: {
|
|
91
|
+
evidence: readonly TaskEvidence[];
|
|
92
|
+
kind: TaskEvidenceKind;
|
|
93
|
+
summary: string;
|
|
94
|
+
ref?: string;
|
|
95
|
+
now: string;
|
|
96
|
+
}): EvidenceAppend;
|
|
97
|
+
/** 从 evidenceIds 里剔除被淘汰的证据 id。 */
|
|
98
|
+
export declare function pruneEvidenceRefs<T extends {
|
|
99
|
+
evidenceIds: string[];
|
|
100
|
+
}>(items: readonly T[], dropped: readonly string[]): T[];
|
|
101
|
+
/** 新建一个空任务。`status` 从 `queued` 起——`running` 由 runner 认领时置位,
|
|
102
|
+
* 这样「任务已创建但还没被任何 runner 接管」是个可观测的中间态。 */
|
|
103
|
+
export declare function newTaskRecord(input: {
|
|
104
|
+
id: string;
|
|
105
|
+
sessionId: string;
|
|
106
|
+
rootRequestId: string;
|
|
107
|
+
rootUserMessageId: string;
|
|
108
|
+
goal: string;
|
|
109
|
+
now: string;
|
|
110
|
+
}): Omit<TaskRecord, "revision"> & {
|
|
111
|
+
revision: number;
|
|
112
|
+
};
|
|
113
|
+
/** 由目标文本推导一个后备步骤(模型没有调 todo 工具时)。
|
|
114
|
+
*
|
|
115
|
+
* 必要性:Completion Gate 的条件 2 在有步骤时要求全部完成。若模型从不拆解
|
|
116
|
+
* 步骤,`steps` 恒为空,条件 2 自动通过——这没问题;但这样一来「任务做到
|
|
117
|
+
* 哪了」在 UI 上没有任何可展示的进度。给一条与目标同名的单步,让进度条至少
|
|
118
|
+
* 有一个真实的锚点。 */
|
|
119
|
+
export declare function fallbackStep(taskId: string, goal: string): TaskStep;
|
|
120
|
+
export {};
|
|
121
|
+
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/core/task/plan.ts"],"names":[],"mappings":"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"}
|