@tea-agent/loop-agent 0.30.0 → 0.31.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/CHANGELOG.md +30 -0
- package/dist/executors/dag-pi-executor.js +3 -2
- package/dist/worker/observability/dag-execution-trajectory.js +591 -0
- package/dist/worker/observability/read-model.js +258 -31
- package/dist/worker/observe/dag-node-execution-output.js +180 -0
- package/dist/worker/observe/routes.js +53 -6
- package/dist/worker/observe/static/dag-edge-routing.js +368 -0
- package/dist/worker/observe/static/dag-history-labels.js +95 -0
- package/dist/worker/observe/static/dag-layout.d.ts +12 -7
- package/dist/worker/observe/static/dag-layout.js +101 -21
- package/dist/worker/observe/static/favicon.svg +37 -0
- package/dist/worker/observe/static/format.js +31 -1
- package/dist/worker/observe/static/index.html +1 -1
- package/dist/worker/observe/static/state.js +102 -0
- package/dist/worker/observe/static/styles.css +267 -7
- package/dist/worker/observe/static/views/dag-graph.js +414 -154
- package/dist/worker/observe/static/views/dag-inspector.js +478 -27
- package/dist/worker/observe/static/views/dag-trajectory.js +313 -0
- package/dist/worker/observe/static/views/dag.js +20 -3
- package/dist/workflows/dag/init-hybrid.js +2 -2
- package/docs/architecture/README.md +4 -0
- package/docs/architecture/dag-execution.md +1 -1
- package/docs/architecture/worker-and-feature.md +1 -1
- package/docs/governance/README.md +3 -0
- package/docs/operations/README.md +1 -0
- package/docs/templates/frontend-test-dag.json +1 -1
- package/harness.json +3 -3
- package/package.json +3 -2
- package/scripts/kb-bootstrap-init-skeleton.sh +1 -1
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DAG 执行轨迹 storyboard(Observe UI R5 / P1)。
|
|
3
|
+
*
|
|
4
|
+
* 将 detail 响应内嵌的有界 executionTrajectory 渲染为自上而下的 lane:
|
|
5
|
+
* 「初始执行」「修复轮次 N-1」「最终收敛」(仅内容 lane)。raw pass=1(scope
|
|
6
|
+
* base 或 convergence-pass)均显示「初始执行」,raw pass>=2 显示「修复轮次
|
|
7
|
+
* N-1」;raw pass 编号仅保留在 occurrence 卡 hover/title 诊断(AC-001/AC-002)。
|
|
8
|
+
* lane 内按真实
|
|
9
|
+
* sequence 左→右;occurrence 卡含节点名/状态/耗时/语义 verdict;多 attempt
|
|
10
|
+
* 显示中文紧凑尝试条;lane 间短箭头加中文原因;不画跨 lane 回环(P2 路由
|
|
11
|
+
* 算法不在 P1 范围)。布局异常降级为纵向事件列表,不空白页。
|
|
12
|
+
*/
|
|
13
|
+
import { el } from "../dom.js";
|
|
14
|
+
import { statusLabel, formatMs } from "../format.js";
|
|
15
|
+
import {
|
|
16
|
+
attemptFailureLabel,
|
|
17
|
+
semanticVerdictLabel,
|
|
18
|
+
transitionReasonLabel,
|
|
19
|
+
} from "../dag-history-labels.js";
|
|
20
|
+
import { setDagGraphViewMode } from "../state.js";
|
|
21
|
+
import { selectDagExecution } from "./dag-inspector.js";
|
|
22
|
+
|
|
23
|
+
export const TRAJECTORY_EMPTY_TEXT = "本次运行没有可展开的执行轨迹";
|
|
24
|
+
export const TRAJECTORY_UNAVAILABLE_TEXT = "执行历史暂不可用";
|
|
25
|
+
export const TRAJECTORY_PARTIAL_TEXT = "历史证据不完整";
|
|
26
|
+
|
|
27
|
+
const SUCCESS_STATUSES = new Set([
|
|
28
|
+
"finished",
|
|
29
|
+
"completed",
|
|
30
|
+
"succeeded",
|
|
31
|
+
"done",
|
|
32
|
+
"success",
|
|
33
|
+
]);
|
|
34
|
+
const FAILURE_STATUSES = new Set([
|
|
35
|
+
"error",
|
|
36
|
+
"failed",
|
|
37
|
+
"partial_failed",
|
|
38
|
+
"partial-failed",
|
|
39
|
+
"interrupted",
|
|
40
|
+
"failure",
|
|
41
|
+
"superseded",
|
|
42
|
+
]);
|
|
43
|
+
const RUNNING_STATUSES = new Set(["running", "started", "paused", "queued"]);
|
|
44
|
+
|
|
45
|
+
function occurrenceStatusBadge(status) {
|
|
46
|
+
const normalized = String(status ?? "").toLowerCase();
|
|
47
|
+
if (SUCCESS_STATUSES.has(normalized)) {
|
|
48
|
+
return { cls: "succeeded", label: "成功" };
|
|
49
|
+
}
|
|
50
|
+
if (FAILURE_STATUSES.has(normalized)) {
|
|
51
|
+
return { cls: "failed", label: "失败" };
|
|
52
|
+
}
|
|
53
|
+
if (RUNNING_STATUSES.has(normalized)) {
|
|
54
|
+
return { cls: "pending", label: "运行中" };
|
|
55
|
+
}
|
|
56
|
+
return { cls: "pending", label: statusLabel(status) ?? status ?? "未知" };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Lane grouping key from an occurrence (pre-sorted by the projection). */
|
|
60
|
+
function laneKeyOf(occurrence) {
|
|
61
|
+
if (occurrence.scope === "final") return "final";
|
|
62
|
+
if (occurrence.scope === "base") return "base";
|
|
63
|
+
return `pass-${occurrence.pass ?? 0}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function laneTitle(laneKey, occurrence) {
|
|
67
|
+
if (laneKey === "base") return "初始执行";
|
|
68
|
+
if (laneKey === "final") return "最终收敛";
|
|
69
|
+
// raw pass=1 的 convergence-pass lane 也显示「初始执行」;raw pass>=2
|
|
70
|
+
// 映射为人类修复轮次 N-1(AC-001/AC-002),主文案不出现 raw 轮次直译。
|
|
71
|
+
const pass = occurrence.pass ?? 0;
|
|
72
|
+
if (pass <= 1) return "初始执行";
|
|
73
|
+
return `修复轮次 ${pass - 1}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** 中文紧凑尝试条:首次尝试 / 第 N 次尝试(AC-002,主 UI 不出现裸 A1/A2)。 */
|
|
77
|
+
function attemptStripLabel(occurrence) {
|
|
78
|
+
const attempts = occurrence.attempts;
|
|
79
|
+
if (!Array.isArray(attempts) || attempts.length <= 1) return null;
|
|
80
|
+
return attempts
|
|
81
|
+
.map((attempt) => {
|
|
82
|
+
const name =
|
|
83
|
+
attempt.attempt === 1 ? "首次尝试" : `第 ${attempt.attempt} 次尝试`;
|
|
84
|
+
// 失败 attempt 显示表一中文原因(AC-001),未知/缺失分类
|
|
85
|
+
// fail-closed 为「其他失败原因」;成功 attempt 保持「成功」。
|
|
86
|
+
const outcome =
|
|
87
|
+
attempt.status === "success"
|
|
88
|
+
? "成功"
|
|
89
|
+
: attemptFailureLabel(attempt.failureCategory);
|
|
90
|
+
return `${name} ${outcome}`;
|
|
91
|
+
})
|
|
92
|
+
.join(" → ");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function buildOccurrenceCard(dagRunId, occurrence) {
|
|
96
|
+
const badge = occurrenceStatusBadge(occurrence.status);
|
|
97
|
+
const recovered =
|
|
98
|
+
occurrence.recovered === true ||
|
|
99
|
+
occurrence.supersededBy?.length > 0 ||
|
|
100
|
+
false;
|
|
101
|
+
const card = document.createElement("button");
|
|
102
|
+
card.type = "button";
|
|
103
|
+
const extraClasses = [
|
|
104
|
+
recovered ? "is-recovered" : "",
|
|
105
|
+
occurrence.availability === "partial" ? "is-partial" : "",
|
|
106
|
+
]
|
|
107
|
+
.filter(Boolean)
|
|
108
|
+
.join(" ");
|
|
109
|
+
card.className = extraClasses
|
|
110
|
+
? `dag-trajectory-occurrence ${extraClasses}`
|
|
111
|
+
: "dag-trajectory-occurrence";
|
|
112
|
+
// 原始 pass/attempt 编号仅出现在 hover/title 诊断中,不作主标题(AC-003)。
|
|
113
|
+
const diagnostic = [
|
|
114
|
+
occurrence.executionId,
|
|
115
|
+
occurrence.status,
|
|
116
|
+
...(occurrence.pass ? [`pass ${occurrence.pass}`] : []),
|
|
117
|
+
...(occurrence.failureCategory
|
|
118
|
+
? [`failureCategory ${occurrence.failureCategory}`]
|
|
119
|
+
: []),
|
|
120
|
+
].join("\n");
|
|
121
|
+
card.setAttribute("title", diagnostic);
|
|
122
|
+
// 语义 verdict 主文案与 aria-label 均显示表二中文(AC-002)。
|
|
123
|
+
const verdictLabel = semanticVerdictLabel(occurrence.semanticVerdict);
|
|
124
|
+
card.setAttribute(
|
|
125
|
+
"aria-label",
|
|
126
|
+
`${occurrence.nodeId},${badge.label}${occurrence.semanticVerdict ? `,语义 ${verdictLabel}` : ""}${recovered ? ",历史失败 · 已恢复/已覆盖" : ""}`,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const nodeLine = el("span", "dag-trajectory-occurrence-node", occurrence.nodeId);
|
|
130
|
+
card.appendChild(nodeLine);
|
|
131
|
+
const statusBadge = el(
|
|
132
|
+
"span",
|
|
133
|
+
`badge badge-${badge.cls} dag-trajectory-occurrence-status`,
|
|
134
|
+
badge.label,
|
|
135
|
+
);
|
|
136
|
+
card.appendChild(statusBadge);
|
|
137
|
+
if (occurrence.durationMs !== undefined) {
|
|
138
|
+
card.appendChild(
|
|
139
|
+
el(
|
|
140
|
+
"span",
|
|
141
|
+
"dag-trajectory-occurrence-meta",
|
|
142
|
+
formatMs(occurrence.durationMs),
|
|
143
|
+
),
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
if (occurrence.semanticVerdict) {
|
|
147
|
+
card.appendChild(
|
|
148
|
+
el("span", "dag-trajectory-occurrence-verdict", verdictLabel),
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
const strip = attemptStripLabel(occurrence);
|
|
152
|
+
if (strip) {
|
|
153
|
+
card.appendChild(el("span", "dag-trajectory-attempt-strip", strip));
|
|
154
|
+
}
|
|
155
|
+
if (recovered) {
|
|
156
|
+
const label =
|
|
157
|
+
occurrence.supersededBy?.length > 0
|
|
158
|
+
? "历史失败 · 已覆盖"
|
|
159
|
+
: "历史失败 · 已恢复";
|
|
160
|
+
card.appendChild(el("span", "dag-trajectory-recovered", label));
|
|
161
|
+
}
|
|
162
|
+
if (occurrence.availability === "partial") {
|
|
163
|
+
card.appendChild(
|
|
164
|
+
el("span", "dag-trajectory-partial", TRAJECTORY_PARTIAL_TEXT),
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
card.addEventListener("click", () => {
|
|
168
|
+
// @pass-<n> 映射为 Inspector 既有 pass-<n> key;@base/@final 默认最新。
|
|
169
|
+
selectDagExecution(
|
|
170
|
+
dagRunId,
|
|
171
|
+
occurrence.nodeId,
|
|
172
|
+
occurrence.pass ? `pass-${occurrence.pass}` : null,
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
return card;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function buildEmptyState(dagRunId, rerender) {
|
|
179
|
+
const root = el("div", "dag-trajectory-empty");
|
|
180
|
+
root.appendChild(el("p", "dag-trajectory-empty-text", TRAJECTORY_EMPTY_TEXT));
|
|
181
|
+
const back = document.createElement("button");
|
|
182
|
+
back.type = "button";
|
|
183
|
+
back.className = "dag-trajectory-back";
|
|
184
|
+
back.textContent = "返回逻辑拓扑";
|
|
185
|
+
back.addEventListener("click", () => {
|
|
186
|
+
setDagGraphViewMode(dagRunId, "topology");
|
|
187
|
+
rerender();
|
|
188
|
+
});
|
|
189
|
+
root.appendChild(back);
|
|
190
|
+
return root;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* 渲染执行轨迹视图到图区域 viewport。`rerender` 由 dag-graph 注入,用于
|
|
195
|
+
* 空态「返回逻辑拓扑」就地切回拓扑(避免模块环)。
|
|
196
|
+
*/
|
|
197
|
+
export function renderTrajectoryStoryboard(dag, dagRunId, viewport, rerender) {
|
|
198
|
+
const trajectory = dag.executionTrajectory;
|
|
199
|
+
const fallback = (occurrences) => {
|
|
200
|
+
const list = el("ul", "dag-trajectory-fallback");
|
|
201
|
+
const items = Array.isArray(occurrences)
|
|
202
|
+
? occurrences
|
|
203
|
+
: trajectory?.occurrences ?? [];
|
|
204
|
+
if (items.length === 0) {
|
|
205
|
+
list.appendChild(
|
|
206
|
+
el("li", "dag-trajectory-fallback-item", TRAJECTORY_UNAVAILABLE_TEXT),
|
|
207
|
+
);
|
|
208
|
+
} else {
|
|
209
|
+
let rendered = 0;
|
|
210
|
+
for (const occurrence of items) {
|
|
211
|
+
if (!occurrence || typeof occurrence !== "object") continue;
|
|
212
|
+
// 纵向降级列表同样经表三/表二映射拼接,不出现裸英文 token(AC-002)。
|
|
213
|
+
const reason =
|
|
214
|
+
transitionReasonLabel(occurrence.nextReason) ||
|
|
215
|
+
semanticVerdictLabel(occurrence.semanticVerdict) ||
|
|
216
|
+
"";
|
|
217
|
+
list.appendChild(
|
|
218
|
+
el(
|
|
219
|
+
"li",
|
|
220
|
+
"dag-trajectory-fallback-item",
|
|
221
|
+
`${occurrence.nodeId} · ${statusLabel(occurrence.status)}${reason ? ` · ${reason}` : ""}`,
|
|
222
|
+
),
|
|
223
|
+
);
|
|
224
|
+
rendered += 1;
|
|
225
|
+
}
|
|
226
|
+
if (rendered === 0) {
|
|
227
|
+
list.appendChild(
|
|
228
|
+
el(
|
|
229
|
+
"li",
|
|
230
|
+
"dag-trajectory-fallback-item",
|
|
231
|
+
TRAJECTORY_UNAVAILABLE_TEXT,
|
|
232
|
+
),
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
viewport.appendChild(list);
|
|
237
|
+
};
|
|
238
|
+
try {
|
|
239
|
+
if (!trajectory || !Array.isArray(trajectory.occurrences)) {
|
|
240
|
+
// 无 executionTrajectory 或空轨迹:空态 + 返回逻辑拓扑入口。
|
|
241
|
+
viewport.appendChild(buildEmptyState(dagRunId, rerender));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const root = el("div", "dag-trajectory");
|
|
245
|
+
if (trajectory.projectionError === true) {
|
|
246
|
+
root.appendChild(
|
|
247
|
+
el("div", "dag-trajectory-banner is-error", TRAJECTORY_UNAVAILABLE_TEXT),
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
if (Array.isArray(trajectory.warnings) && trajectory.warnings.length > 0) {
|
|
251
|
+
root.appendChild(
|
|
252
|
+
el(
|
|
253
|
+
"div",
|
|
254
|
+
"dag-trajectory-banner",
|
|
255
|
+
`${TRAJECTORY_PARTIAL_TEXT}:${trajectory.warnings.join(";")}`,
|
|
256
|
+
),
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
if (trajectory.occurrences.length === 0) {
|
|
260
|
+
root.appendChild(buildEmptyState(dagRunId, rerender));
|
|
261
|
+
viewport.appendChild(root);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
// 按投影排序连续分组为 lane(仅内容 lane),lane 间插入带中文原因的短箭头。
|
|
265
|
+
const lanes = [];
|
|
266
|
+
let currentLaneKey = null;
|
|
267
|
+
for (const occurrence of trajectory.occurrences) {
|
|
268
|
+
const laneKey = laneKeyOf(occurrence);
|
|
269
|
+
if (laneKey !== currentLaneKey) {
|
|
270
|
+
currentLaneKey = laneKey;
|
|
271
|
+
lanes.push({
|
|
272
|
+
laneKey,
|
|
273
|
+
title: laneTitle(laneKey, occurrence),
|
|
274
|
+
occurrences: [],
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
lanes[lanes.length - 1].occurrences.push(occurrence);
|
|
278
|
+
}
|
|
279
|
+
for (const [index, lane] of lanes.entries()) {
|
|
280
|
+
const laneRoot = el("div", "dag-trajectory-lane");
|
|
281
|
+
const head = el("div", "dag-trajectory-lane-head");
|
|
282
|
+
head.appendChild(el("span", "dag-trajectory-lane-title", lane.title));
|
|
283
|
+
head.appendChild(
|
|
284
|
+
el("span", "dag-trajectory-lane-meta", `${lane.occurrences.length} 次执行`),
|
|
285
|
+
);
|
|
286
|
+
laneRoot.appendChild(head);
|
|
287
|
+
const laneCards = el("div", "dag-trajectory-lane-cards");
|
|
288
|
+
for (const occurrence of lane.occurrences) {
|
|
289
|
+
laneCards.appendChild(buildOccurrenceCard(dagRunId, occurrence));
|
|
290
|
+
}
|
|
291
|
+
laneRoot.appendChild(laneCards);
|
|
292
|
+
root.appendChild(laneRoot);
|
|
293
|
+
if (index < lanes.length - 1) {
|
|
294
|
+
const lastOccurrence = lane.occurrences[lane.occurrences.length - 1];
|
|
295
|
+
const reason = transitionReasonLabel(lastOccurrence?.nextReason);
|
|
296
|
+
if (reason) {
|
|
297
|
+
const transition = el("div", "dag-trajectory-transition");
|
|
298
|
+
transition.appendChild(
|
|
299
|
+
el("span", "dag-trajectory-transition-arrow", "↓"),
|
|
300
|
+
);
|
|
301
|
+
transition.appendChild(
|
|
302
|
+
el("span", "dag-trajectory-transition-reason", reason),
|
|
303
|
+
);
|
|
304
|
+
root.appendChild(transition);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
viewport.appendChild(root);
|
|
309
|
+
} catch {
|
|
310
|
+
// 布局/渲染异常降级:纵向事件列表,不空白页(AC-006)。
|
|
311
|
+
fallback(null);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
@@ -62,7 +62,7 @@ import {
|
|
|
62
62
|
mountViewState,
|
|
63
63
|
makeSessionEventIdentity,
|
|
64
64
|
} from "../state.js";
|
|
65
|
-
import { uiState, dagGraphViewportStates } from "../state.js";
|
|
65
|
+
import { uiState, dagGraphViewportStates, dagGraphViewModes } from "../state.js";
|
|
66
66
|
import { sortPoolTasks } from "../format-pool.js";
|
|
67
67
|
import {
|
|
68
68
|
dagMetaVisibility,
|
|
@@ -108,9 +108,12 @@ export async function renderDagDetail(dagRunId, initial = true) {
|
|
|
108
108
|
uiState.sessionEventIdentity = null;
|
|
109
109
|
uiState.dagInspectorOpen = false;
|
|
110
110
|
uiState.dagInspectorTab = "output";
|
|
111
|
+
uiState.dagInspectorAttempt = null;
|
|
111
112
|
uiState.dagGraphViewportState = null;
|
|
112
113
|
uiState.dagTimelineViewportState = null;
|
|
113
114
|
}
|
|
115
|
+
// AC-001:同会话内重新进入同一 dagRunId 保持当前图视图模式(不切回逻辑拓扑)。
|
|
116
|
+
uiState.dagGraphViewMode = dagGraphViewModes.get(dagRunId) ?? "topology";
|
|
114
117
|
|
|
115
118
|
const metaEl = document.getElementById("dag-meta");
|
|
116
119
|
const ranksEl = document.getElementById("dag-ranks");
|
|
@@ -167,6 +170,7 @@ export async function renderDagDetail(dagRunId, initial = true) {
|
|
|
167
170
|
) {
|
|
168
171
|
uiState.selectedDagNodeId = null;
|
|
169
172
|
uiState.dagInspectorOpen = false;
|
|
173
|
+
uiState.dagInspectorAttempt = null;
|
|
170
174
|
if (initial) {
|
|
171
175
|
uiState.sessionEventOffset = 0;
|
|
172
176
|
uiState.sessionEvents = [];
|
|
@@ -325,17 +329,30 @@ export async function renderDagDetail(dagRunId, initial = true) {
|
|
|
325
329
|
node.model ?? "—",
|
|
326
330
|
node.status ? badge(node.status) : "—",
|
|
327
331
|
formatMs(node.durationMs),
|
|
332
|
+
(typeof node.executionSummary?.historyLabel === "string" &&
|
|
333
|
+
node.executionSummary.historyLabel.trim()) ||
|
|
334
|
+
"—",
|
|
328
335
|
node.errorPreview ?? node.label ?? "—",
|
|
329
336
|
],
|
|
330
337
|
};
|
|
331
338
|
});
|
|
332
339
|
const nodeTable = buildTable(
|
|
333
|
-
[
|
|
340
|
+
[
|
|
341
|
+
"序号",
|
|
342
|
+
"节点 ID",
|
|
343
|
+
"依赖层",
|
|
344
|
+
"执行方式",
|
|
345
|
+
"模型",
|
|
346
|
+
"状态",
|
|
347
|
+
"耗时",
|
|
348
|
+
"执行历史",
|
|
349
|
+
"备注",
|
|
350
|
+
],
|
|
334
351
|
rows,
|
|
335
352
|
);
|
|
336
353
|
nodeTable.classList.add("dag-node-table");
|
|
337
354
|
for (const row of nodeTable.tBodies[0]?.rows ?? []) {
|
|
338
|
-
for (const columnIndex of [1, 4,
|
|
355
|
+
for (const columnIndex of [1, 4, 8]) {
|
|
339
356
|
const cell = row.cells[columnIndex];
|
|
340
357
|
if (cell?.textContent) cell.title = cell.textContent;
|
|
341
358
|
}
|
|
@@ -561,7 +561,7 @@ export function hasApiDependency(sources) {
|
|
|
561
561
|
/**
|
|
562
562
|
* Resolve frontend Mock mode from capability seed, task config, and interface dependency analysis.
|
|
563
563
|
*
|
|
564
|
-
* Decision matrix (
|
|
564
|
+
* Decision matrix (historical design: docs/design/archive/frontend-mock-data-workflow.md):
|
|
565
565
|
*
|
|
566
566
|
* | 接口/异步数据依赖 | 既有 Mock 服务 | policy | 结果 |
|
|
567
567
|
* |---|---|---|---|
|
|
@@ -4553,7 +4553,7 @@ function buildFrontendTestHybridDag(sources) {
|
|
|
4553
4553
|
"Use only the declared isolated test environment. Production URLs, real credentials, and unauthorized data are blocked.",
|
|
4554
4554
|
`Browser startup for generated cases must be playwright-cli open --browser=chrome ${controllerFrontend.baseUrl}; this origin is frozen by the controller from ${controllerFrontend.baseUrlSource}, and model-authored files cannot establish or override it; generated operations stay in the default browser session and must not use unverified named-session flags.`,
|
|
4555
4555
|
"Browser-tool preflight runs before any frontend-test Pi node; cli-only rollback, missing/incompatible Pi SDK custom-tool capability, missing verified playwright-cli launcher, or incompatible --help fails with zero Pi calls.",
|
|
4556
|
-
"Browser case children use commandPolicy capability-allowlist playwright-cli and structured playwright_cli tool; ordinary writers
|
|
4556
|
+
"Browser case children use commandPolicy capability-allowlist playwright-cli and structured playwright_cli tool; playwright-cli stays capability-gated while ordinary writers have bash.",
|
|
4557
4557
|
"Passed cases require same-child ordered controller receipts: successful open → successful find → successful post-execution cleanup. Pre-start cleanup, snapshot/goto/screenshot/request/console and ordinary interactions are insufficient; missing or unordered receipts convert to blocked (browser-command-evidence-missing).",
|
|
4558
4558
|
"playwright-cli-only: generators and executors may call only skill-declared playwright-cli commands; bare playwright / npx playwright / @playwright/test / Playwright source are forbidden with no native Playwright fallback.",
|
|
4559
4559
|
"Environment preflight must curl-probe the frozen non-production baseUrl before generate; unreachable or curl-unavailable ends preflight as blocked (frontend-base-url-unreachable|curl-unavailable) so generate/map do not run.",
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
5. `worker-and-feature.md` — agent-worker 子进程边界、controller identity、Task Pool、Feature、Observe 与 Console。
|
|
16
16
|
6. `facts-and-state.md` — `.harness/` 各根目录、canonical facts、derived read models 与不可变规则。
|
|
17
17
|
7. `evolution.md` — 当前已实现能力 vs 第 3–6 月未来方向(明确标注规划/未实现)。
|
|
18
|
+
8. `state-and-failure-taxonomy.md` — Task Pool、DAG、Loop 与报告共用的 canonical 状态/失败分类。
|
|
19
|
+
9. `taskspec-to-loop-agent-mapping.md` / `.yaml` — TaskSpec 到 worker/runtime 的兼容合同与机器可读镜像。
|
|
20
|
+
10. `knowledge-graph-and-query-spec.md` — 业务知识图谱、knowledge-links 与查询协议。
|
|
21
|
+
11. `testing-knowledge-base-impl-spec.md` — 测试知识库 schema、ID、读写矩阵和校验规则。
|
|
18
22
|
|
|
19
23
|
## 事实与规划的区分
|
|
20
24
|
|
|
@@ -44,7 +44,7 @@ src/commands/dag-validate.ts runDagValidate
|
|
|
44
44
|
### 专用 taskKind 与模板选择(架构摘要)
|
|
45
45
|
|
|
46
46
|
- `initHybridDagFromTask` 按 `task.json.taskKind`(及前端需求自动分类)选择专用拓扑:`frontend-implementation`、`frontend-test`、`backend-test`、`knowledge-sync`、`knowledge-graph-bootstrap` 等;默认 `standard` 走 governance profile 通用实现链。
|
|
47
|
-
- **backend-test(0.17.x)**:Markdown-first 固定短链(环境硬门 → Markdown 用例/Review → 单次 pytest + HTML → 报告与 L-5);不在本页展开节点清单,见 `docs/
|
|
47
|
+
- **backend-test(0.17.x)**:Markdown-first 固定短链(环境硬门 → Markdown 用例/Review → 单次 pytest + HTML → 报告与 L-5);不在本页展开节点清单,见 `docs/runtime/backend-test-workflow.md` 与 completed markdown-first plan。
|
|
48
48
|
- 专用模板不是新的 governance profile:风险等级仍由 profile 规则判断;写边界仍受 `allowedPaths` / `forbiddenPaths` / `writeSet` 约束。
|
|
49
49
|
|
|
50
50
|
## rank 调度
|
|
@@ -62,7 +62,7 @@ controller identity 与 DAG skill snapshot 是两个不同冻结层(前者跨
|
|
|
62
62
|
- schema/validate:`src/worker/task-spec/{schema,validate}.ts`。
|
|
63
63
|
- 校验验收条件、依赖、验证命令;`agent-worker task validate-feature` 等用之。
|
|
64
64
|
- **0.16.0+**:可选 `execution.workflow` 映射到 loop-agent `taskKind`(如 agent-dag / frontend-implementation / backend-test / frontend-test);typed Task Outcome 与 artifact-aware Ready 门禁见 completed `2026-07-19-taskspec-workflow-routing.md`。
|
|
65
|
-
- 文档映射镜像:`docs/
|
|
65
|
+
- 文档映射镜像:`docs/architecture/taskspec-to-loop-agent-mapping.md`(runtime 真源仍在 `src/worker/` 与 materialize 路径)。
|
|
66
66
|
|
|
67
67
|
### Task Pool
|
|
68
68
|
|
|
@@ -11,5 +11,8 @@
|
|
|
11
11
|
- [`harness-methodology-verification.md`](harness-methodology-verification.md):如何用新鲜命令结果支持完成声明。
|
|
12
12
|
- [`harness-methodology-debugging.md`](harness-methodology-debugging.md):系统化定位故障,不用猜测代替证据。
|
|
13
13
|
- [`document-review-policy.md`](document-review-policy.md):文档 freshness、`reviewTier` 与 `lastReviewed` 更新边界。
|
|
14
|
+
- [`lightweight-github-collaboration.md`](lightweight-github-collaboration.md):短分支、简短 PR、CI 与 Squash Merge 的轻量协作规则。
|
|
15
|
+
- [`研发模式.md`](研发模式.md):Feature 团队推进、交付和知识回写方法论。
|
|
16
|
+
- [`腾讯实践对当前项目的指引.md`](腾讯实践对当前项目的指引.md):外部工程实践与本仓库治理/能力边界的映射。
|
|
14
17
|
|
|
15
18
|
架构事实见 [`../architecture/README.md`](../architecture/README.md),运行手册见 [`../runtime/README.md`](../runtime/README.md),日常维护操作见 [`../operations/README.md`](../operations/README.md)。
|
|
@@ -8,5 +8,6 @@
|
|
|
8
8
|
- [`branch-merge-guideline.md`](branch-merge-guideline.md):按风险选择合并模式并留下 source-SHA 证据。
|
|
9
9
|
- [`github-collaboration.md`](github-collaboration.md):仓库内 GitHub 协作约定及自动/人工发布通道。
|
|
10
10
|
- [`production-readiness.md`](production-readiness.md):交付前的生产就绪判断。
|
|
11
|
+
- [`backend-test-jacoco-coverage.md`](backend-test-jacoco-coverage.md):Java 被测服务挂载 JaCoCo tcpserver agent 的 Maven、`java -jar` 与 Docker 操作手册。
|
|
11
12
|
|
|
12
13
|
验证命令仍以 [`../governance/verification-matrix.md`](../governance/verification-matrix.md) 为准。
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"Default frontendTest.reviewMode=off uses mechanical checklist-shell before materialize; set reviewMode=blocking for legacy dual LLM review gate.",
|
|
19
19
|
"playwright-cli-only: generators and executors may call only skill-declared playwright-cli commands; bare playwright / npx playwright / @playwright/test / Playwright source are forbidden with no native Playwright fallback.",
|
|
20
20
|
"Browser-tool preflight (preflight-frontend-browser-tool-shell) must reject CODE_AGENT_PI_BACKEND=cli-only, verify the Pi SDK structured custom-tool surface, freeze baseUrl from hash-bound task source config.md (or controller default localhost), and confirm the verified playwright-cli launcher + --help contract before any frontend-test Pi node; missing capability/CLI fails with zero Pi calls.",
|
|
21
|
-
"Case executors use structured playwright_cli custom tool under commandPolicy capability-allowlist; ordinary writers
|
|
21
|
+
"Case executors use structured playwright_cli custom tool under commandPolicy capability-allowlist; playwright-cli stays capability-gated while ordinary writers have bash.",
|
|
22
22
|
"File outputs use canonical --filename: playwright-cli screenshot --filename final.png (a real target/ref may precede it), playwright-cli pdf --filename final.pdf, and playwright-cli snapshot --filename snapshot.txt only when a snapshot file is needed; a snapshot without filename is response-only. Never use --path, --output, --file, or an output path as a positional target.",
|
|
23
23
|
"Passed cases require same-child ordered controller receipts: successful open → successful find → successful post-execution cleanup. Pre-start cleanup, snapshot/goto/screenshot/request/console, and ordinary interactions cannot establish passed authority; model prose cannot fake green.",
|
|
24
24
|
"Environment preflight must curl-probe the frozen non-production baseUrl before generate; unreachable or curl-unavailable ends preflight as blocked (frontend-base-url-unreachable|curl-unavailable) so generate/map do not run.",
|
package/harness.json
CHANGED
|
@@ -80,9 +80,9 @@
|
|
|
80
80
|
"executors": {
|
|
81
81
|
"pi": {
|
|
82
82
|
"description": "Pi planning, review, diagnosis, and bounded writing when DAG toolProfile=write",
|
|
83
|
-
"LOW": "
|
|
84
|
-
"MED": "
|
|
85
|
-
"HIGH": "
|
|
83
|
+
"LOW": "minimax-m3",
|
|
84
|
+
"MED": "grok-4.5",
|
|
85
|
+
"HIGH": "gpt-5.6-sol"
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tea-agent/loop-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.31.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"loop-agent": "bin/loop-agent.js",
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"cursor": "node --import tsx/esm src/cli.ts cursor-prompt",
|
|
45
45
|
"pi-prompt": "node --import tsx/esm src/cli.ts pi-prompt",
|
|
46
46
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
47
|
-
"
|
|
47
|
+
"brand:sync": "node scripts/sync-brand-assets.mjs",
|
|
48
|
+
"build": "npm run brand:sync && npm run clean && tsc -p tsconfig.build.json && node -e \"const fs=require('node:fs');const p='dist/worker/observe/static';fs.mkdirSync(p,{recursive:true});fs.cpSync('src/worker/observe/static',p,{recursive:true});\" && npm run console:build",
|
|
48
49
|
"console:build": "vite build --config src/worker/console/vite.config.ts",
|
|
49
50
|
"prepack": "npm run build",
|
|
50
51
|
"prepublishOnly": "node scripts/check-npm-publish-policy.mjs && npm run typecheck && npm test && npm run build",
|
|
@@ -168,7 +168,7 @@ loop-agent task advance <id> --task-kind knowledge-graph-bootstrap --allowed-pat
|
|
|
168
168
|
# bash scripts/kb-query.sh --mode by_feature --feature F-2026-004 --json
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
See `docs/
|
|
171
|
+
See `docs/architecture/knowledge-graph-and-query-spec.md` and `docs/design/active/knowledge-graph-ai-bootstrap.md`.
|
|
172
172
|
EOF
|
|
173
173
|
)
|
|
174
174
|
|