@tea-agent/loop-agent 0.38.2 → 0.38.4
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/AGENTS.md +4 -1
- package/CHANGELOG.md +171 -96
- package/README.md +11 -5
- package/bin/loop-agent.js +7 -3
- package/dist/application/task-lifecycle/advance.js +4 -0
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +16 -5
- package/dist/cli/program.js +16 -2
- package/dist/cli/update/notifier.js +2 -2
- package/dist/cli.js +2 -1
- package/dist/commands/dag-rerun.js +55 -1
- package/dist/commands/init-model-catalog.js +464 -0
- package/dist/commands/init-upgrade.js +265 -97
- package/dist/commands/init.js +428 -27
- package/dist/commands/inspect-next.js +8 -0
- package/dist/commands/task-advance.js +31 -0
- package/dist/executors/dag-pi-executor.js +76 -10
- package/dist/executors/pi-event-serializer.js +42 -1
- package/dist/executors/pi-executor.js +51 -0
- package/dist/executors/pi-extension-resolver.js +233 -0
- package/dist/executors/pi-playwright-cli-tool.js +51 -12
- package/dist/executors/pi-sdk-executor.js +187 -59
- package/dist/executors/shell-executor.js +265 -15
- package/dist/executors/shell-write-guard.js +7 -0
- package/dist/shared/dag-prompt-override.js +28 -0
- package/dist/shared/operator/capabilities.js +32 -0
- package/dist/shared/playwright-cli-command-policy.js +15 -0
- package/dist/shared/update/console-notifier.js +100 -0
- package/dist/{cli → shared}/update/npm-client.js +41 -8
- package/dist/{cli → shared}/update/state.js +41 -13
- package/dist/task/contract/constants.js +1 -0
- package/dist/task/contract/diff.js +26 -0
- package/dist/task/contract/project.js +5 -0
- package/dist/task/contract/schema.js +6 -1
- package/dist/task/source-prepare/build-draft.js +15 -0
- package/dist/task/source-prepare/parse-intent.js +24 -4
- package/dist/worker/cli.js +31 -1
- package/dist/worker/console/chat/routes.js +1 -0
- package/dist/worker/console/dag-execution-receipt.js +33 -0
- package/dist/worker/console/operator-actions.js +116 -0
- package/dist/worker/console/operator-user-error.js +2 -2
- package/dist/worker/console/pi-readiness.js +4 -4
- package/dist/worker/console/routes.js +43 -2
- package/dist/worker/console/security.js +63 -9
- package/dist/worker/console/server.js +36 -5
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4bmo3iY.js → abnfDiagram-N423BO3Z-gauhD9kD.js} +1 -1
- package/dist/worker/console/static/assets/{arc-SAD7McOS.js → arc-pm3c2Rsl.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DAVLUdK1.js → architectureDiagram-T3A2C74G-D_JAg3wH.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CPPdv4vj.js → blockDiagram-VBNYF7ZC-Dk7-ex52.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-D1GRGZax.js → c4Diagram-5PPSVZJV-Uval9oRI.js} +1 -1
- package/dist/worker/console/static/assets/channel-CVrnUdZl.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D_Bq2ZqK.js → chunk-2GRJ4B5K-BSYjHs-v.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CPLVtamK.js → chunk-2Q5K7J3B-KGUuBXI8.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DnaZWcL3.js → chunk-5RXB4S5H-JqAtxD9N.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BRTmFgnq.js → chunk-5VM5RSS4-D6EJOVQK.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BRlfYZoH.js → chunk-6Q2QTUOP-B1JriSjm.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CjNybD4u.js → chunk-GF5L2VYU-D62b96Jd.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-D3e-74fG.js → chunk-JWPE2WC7-BsNKEC_r.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-Br3ir6f2.js → chunk-KBJHAD2P-B56v6-ZP.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-1NgVuRbh.js → chunk-RYQCIY6F-D2KPnd8K.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-BTYuvuWN.js → chunk-XXDRQBXY-kzKSCaaL.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-aX91WTya.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-aX91WTya.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BC6Bgosf.js → cose-bilkent-JH36ORCC-C6N6KNJd.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-DV-HypfL.js → cynefin-VYW2F7L2-DiyymT2D.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-DhTaddO-.js → cynefinDiagram-MW4NZA55-BeKAXvf3.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BnEcOmiI.js → dagre-VZM6K2ZE-TkIdXfPF.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-xphGRVKp.js → diagram-7IWD3JNH-BFmSG3ks.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CrdD1mRG.js → diagram-B4RE2ZJO-DqpJT2Fs.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-D4YdLsaF.js → diagram-LBJQPF4R-r5ATN43t.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-LCKyGZ5U.js → diagram-Q27KOJAE-DEcSCMuR.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BeiTe7t0.js → diagram-UB23O5K3-VOvYRLVc.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-BO2cq8GS.js → ebnfDiagram-BXEA7PRR-D7f4Cb1u.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-CmWww3Nt.js → erDiagram-JOGREHBK-ziUf3U0G.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-C2kkUYg5.js → flowDiagram-UKHOOZJN-BoRdQ-1y.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DY_JZ2iQ.js → ganttDiagram-PKOTCBZU-B1-GncNm.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-BizhCSw9.js → gitGraphDiagram-DS77QQ5N-CTW-ph8W.js} +1 -1
- package/dist/worker/console/static/assets/index-C8rOIAJr.css +1 -0
- package/dist/worker/console/static/assets/{index-BXN89VPX.js → index-DEbyrEfW.js} +147 -68
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-Dlo2eK_d.js → infoDiagram-6WML65LV-BFA337tZ.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-3EIlIIuZ.js → ishikawaDiagram-WSZJBQD7-BtEujgRR.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DiMDe5Yh.js → journeyDiagram-NVQOT4AX-C8ZwD2Jp.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-sN553oIN.js → kanban-definition-27J2QSJJ-Ck-z8B11.js} +1 -1
- package/dist/worker/console/static/assets/{linear-D9Py31Ld.js → linear-CAyXjQjN.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-D7Occzk_.js → mermaid.core-CcWKn6tS.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-DjDRboiR.js → mindmap-definition-FAOFIHXS-C2NuDO7E.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-Cgc4qlzp.js → pegDiagram-VL7TDLO6-BFub3PDz.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-DxZj8pKd.js → pieDiagram-7S7Q4E2Y-BJx5THZ5.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-CJ50MngR.js → quadrantDiagram-CIZ2JOQS-DhalkDWV.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BY-OD8Tr.js → railroadDiagram-AXF67PYL-CVcBM36o.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-CQFButfK.js → requirementDiagram-LRYGKXZP-D_vy4n0w.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-BB_QUK_b.js → sankeyDiagram-W5VNT64P-DGYdJL1D.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-CqhXZjyx.js → sequenceDiagram-SI44F4Z6-C1xJFg3k.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-2l1U4rgJ.js → sizeCapture-X5ZJPWSS-D_Fc43df.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-BX1FbrhJ.js → stateDiagram-OKZ733FA-BhGbIjbu.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DUt1lyFL.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DOSnT7hb.js → swimlanes-SLNWSIFB-DVkNcO-V.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BM6SGr7j.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-DVJQA7AN.js → timeline-definition-Z64GVDOM-BQU9ufV0.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-74uxl9gx.js → vennDiagram-T6HMQDX7-BCQhRmYB.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DsBxlcg_.js → wardleyDiagram-T6FBY63Y-DWerOyHO.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-snuW9Mjw.js → xychartDiagram-ELKLHX3M-DxLeebQU.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/mutation-gate.js +1 -1
- package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +328 -0
- package/dist/worker/loop-agent/loop-agent-client.js +7 -3
- package/dist/worker/observe/node-input.js +74 -3
- package/dist/worker/observe/node-process.js +377 -0
- package/dist/worker/observe/routes.js +36 -3
- package/dist/worker/observe/shell-handler-keys.js +34 -0
- package/dist/worker/observe/static/api.js +66 -0
- package/dist/worker/observe/static/constants.js +8 -1
- package/dist/worker/observe/static/dag-history-labels.js +4 -0
- package/dist/worker/observe/static/format.js +23 -0
- package/dist/worker/observe/static/markdown-render.js +20 -1
- package/dist/worker/observe/static/operator-chrome.js +4 -0
- package/dist/worker/observe/static/state.js +13 -2
- package/dist/worker/observe/static/styles.css +73 -0
- package/dist/worker/observe/static/views/dag-inspector.js +612 -8
- package/dist/worker/observe/static/views/dag.js +8 -1
- package/dist/worker/observe/static/views/failures.js +5 -2
- package/dist/worker/observe/static/views/session-timeline.js +78 -9
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +76 -6
- package/dist/workflows/dag/backend-test-scenario-partitions.js +73 -1
- package/dist/workflows/dag/contract-output-registry.js +15 -0
- package/dist/workflows/dag/failure-category.js +12 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +145 -40
- package/dist/workflows/dag/frontend-prewrite-gate.js +87 -135
- package/dist/workflows/dag/frontend-repair.js +14 -0
- package/dist/workflows/dag/frontend-risk.js +15 -2
- package/dist/workflows/dag/frontend-test-case-checklist.js +26 -2
- package/dist/workflows/dag/frontend-test-case-manifest.js +5 -0
- package/dist/workflows/dag/frontend-test-case-quality.js +5 -13
- package/dist/workflows/dag/frontend-test-environment-probe.js +227 -0
- package/dist/workflows/dag/frontend-test-markdown.js +61 -0
- package/dist/workflows/dag/frontend-test-result-contract.js +160 -28
- package/dist/workflows/dag/frontend-test-standard-scenarios.js +68 -0
- package/dist/workflows/dag/frontend-verification-trace.js +29 -4
- package/dist/workflows/dag/init-hybrid.js +196 -117
- package/dist/workflows/dag/node-execution.js +139 -10
- package/dist/workflows/dag/prompt.js +15 -1
- package/dist/workflows/dag/rerun-plan.js +134 -3
- package/dist/workflows/dag/rerun-run.js +58 -6
- package/dist/workflows/dag/retry-policy.js +91 -0
- package/dist/workflows/dag/structured-output-repair.js +712 -0
- package/dist/workflows/dag/types.js +32 -1
- package/dist/workflows/dag/validate.js +41 -1
- package/docs/init-surface.manifest.json +5 -0
- package/docs/operations/README.md +1 -1
- package/docs/operations/local-development-environment.md +1 -5
- package/docs/skills/vetted-skill-registry.md +14 -0
- package/docs/templates/README.md +1 -1
- package/docs/templates/agent-dag.schema.json +44 -0
- package/docs/templates/backend-test-dag.json +2 -2
- package/docs/templates/frontend-test-dag.json +8 -10
- package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +1 -1
- package/docs/templates/init-managed-agents.md +13 -3
- package/harness.json +2 -2
- package/package.json +12 -4
- package/scripts/next-info.mjs +356 -0
- package/scripts/next-publish-gate.mjs +238 -0
- package/scripts/release-source-binding.mjs +251 -0
- package/skills/analyze-product-requirements/SKILL.md +8 -5
- package/skills/analyze-product-requirements/references/acceptance-criteria.md +1 -1
- package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +10 -6
- package/skills/analyze-product-requirements/references/example.md +50 -0
- package/skills/analyze-product-requirements/references/forward-test-cases.md +11 -7
- package/skills/analyze-product-requirements/references/kb-integration.md +5 -5
- package/skills/analyze-product-requirements/references/product-analysis-schema.md +8 -4
- package/skills/analyze-product-requirements/references/product-requirement-schema.md +2 -2
- package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +1 -1
- package/skills/analyze-product-requirements/scripts/test-validators.mjs +11 -1
- package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +20 -1
- package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +9 -0
- package/skills/codebase-scout/SKILL.md +1 -1
- package/skills/fe-test-ui-scout/SKILL.md +65 -0
- package/skills/fe-test-ui-scout/references/ledger-schema.md +62 -0
- package/skills/fe-test-ui-scout/references/recon-protocol.md +54 -0
- package/skills/improve-codebase-architecture/SKILL.md +81 -0
- package/skills/improve-codebase-architecture/deepening.md +37 -0
- package/skills/improve-codebase-architecture/html-report.md +123 -0
- package/skills/improve-codebase-architecture/interface-design.md +44 -0
- package/skills/improve-codebase-architecture/language.md +53 -0
- package/skills/loop-agent/references/command-reference.md +11 -4
- package/skills/playwright-cli/SKILL.md +22 -0
- package/skills/playwright-cli-case-generator/SKILL.md +20 -1
- package/dist/worker/console/static/assets/channel-R6oQIDkw.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BPXlmPWI.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BPXlmPWI.js +0 -1
- package/dist/worker/console/static/assets/index-CuH5CNFu.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DJKi0Qel.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-YYe7EEm5.js +0 -8
|
@@ -11,14 +11,22 @@ import {
|
|
|
11
11
|
} from "../constants.js";
|
|
12
12
|
import { clearNode, el } from "../dom.js";
|
|
13
13
|
import { attemptFailureLabel } from "../dag-history-labels.js";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
import {
|
|
15
|
+
fetchJson,
|
|
16
|
+
fetchSpecEvidenceFile,
|
|
17
|
+
fetchDagNodeInput,
|
|
18
|
+
fetchDagNodeProcess,
|
|
19
|
+
postOperatorAction,
|
|
20
|
+
fetchOperatorOperation,
|
|
21
|
+
} from "../api.js";
|
|
22
|
+
import { badge, formatMs, prettyJsonBlock } from "../format.js";
|
|
23
|
+
import { renderMarkdown, renderInspectorDocument } from "../markdown-render.js";
|
|
17
24
|
import {
|
|
18
25
|
uiState,
|
|
19
26
|
makeSessionEventIdentity,
|
|
20
27
|
makeDagNodeInputIdentity,
|
|
21
28
|
makeDagNodeExecutionOutputIdentity,
|
|
29
|
+
makeDagNodeProcessIdentity,
|
|
22
30
|
getDagNodeExecutionOutputCache,
|
|
23
31
|
setDagNodeExecutionOutputCache,
|
|
24
32
|
clearDagNodeExecutionOutputCache,
|
|
@@ -68,6 +76,10 @@ function resetInspectorNodeSelection(dagRunId, nodeId) {
|
|
|
68
76
|
uiState.dagNodeInputData = null;
|
|
69
77
|
uiState.dagNodeInputError = null;
|
|
70
78
|
uiState.dagNodeInputLoading = false;
|
|
79
|
+
uiState.dagNodeProcessData = null;
|
|
80
|
+
uiState.dagNodeProcessError = null;
|
|
81
|
+
uiState.dagNodeProcessLoading = false;
|
|
82
|
+
uiState.dagNodeProcessIdentity = null;
|
|
71
83
|
// Drop execution-output cache/identity so node A's bodies never leak into B.
|
|
72
84
|
clearDagNodeExecutionOutputCache();
|
|
73
85
|
// Bump the session-event identity token so any in-flight response for the
|
|
@@ -725,6 +737,11 @@ function renderDagNodeInputDetail(content, data) {
|
|
|
725
737
|
}
|
|
726
738
|
section.appendChild(dl);
|
|
727
739
|
appendCodeList(section, "skills", data.executorInput.skills);
|
|
740
|
+
appendCodeList(
|
|
741
|
+
section,
|
|
742
|
+
"piExtensions(声明)",
|
|
743
|
+
data.executorInput.piExtensions,
|
|
744
|
+
);
|
|
728
745
|
if (data.executorInput.shell) {
|
|
729
746
|
const shell = data.executorInput.shell;
|
|
730
747
|
const shellDl = el("dl", "node-input-summary");
|
|
@@ -743,6 +760,12 @@ function renderDagNodeInputDetail(content, data) {
|
|
|
743
760
|
(shell.gates ?? []).join(", ") || "(none)",
|
|
744
761
|
null,
|
|
745
762
|
);
|
|
763
|
+
appendMetaRow(
|
|
764
|
+
shellDl,
|
|
765
|
+
"handlers",
|
|
766
|
+
(shell.handlers ?? []).join(", ") || "(none)",
|
|
767
|
+
null,
|
|
768
|
+
);
|
|
746
769
|
section.appendChild(shellDl);
|
|
747
770
|
if ((shell.commands ?? []).length > 0) {
|
|
748
771
|
const list = el("ol", "node-input-command-list");
|
|
@@ -799,6 +822,52 @@ function renderDagNodeInputDetail(content, data) {
|
|
|
799
822
|
wrap.appendChild(section);
|
|
800
823
|
}
|
|
801
824
|
|
|
825
|
+
if (data.piExtensionRunFacts) {
|
|
826
|
+
const facts = data.piExtensionRunFacts;
|
|
827
|
+
const section = el("section", "node-input-section");
|
|
828
|
+
section.appendChild(el("h4", null, "Pi 扩展运行事实"));
|
|
829
|
+
if (!facts.exists) {
|
|
830
|
+
section.appendChild(
|
|
831
|
+
el(
|
|
832
|
+
"p",
|
|
833
|
+
"muted",
|
|
834
|
+
facts.parseError
|
|
835
|
+
? `产物 ${facts.artifact} 读取失败(${facts.parseError})。`
|
|
836
|
+
: `产物 ${facts.artifact} 尚未生成(节点未执行或缺失)。`,
|
|
837
|
+
),
|
|
838
|
+
);
|
|
839
|
+
} else {
|
|
840
|
+
const dl = el("dl", "node-input-summary");
|
|
841
|
+
appendMetaRow(
|
|
842
|
+
dl,
|
|
843
|
+
"resolved",
|
|
844
|
+
facts.resolved
|
|
845
|
+
.map((entry) => `${entry.id} → ${entry.packageName}@${entry.version}`)
|
|
846
|
+
.join(", ") || "(none)",
|
|
847
|
+
null,
|
|
848
|
+
);
|
|
849
|
+
section.appendChild(dl);
|
|
850
|
+
appendCodeList(
|
|
851
|
+
section,
|
|
852
|
+
"requested",
|
|
853
|
+
facts.requested,
|
|
854
|
+
);
|
|
855
|
+
for (const missingEntry of facts.missing ?? []) {
|
|
856
|
+
section.appendChild(
|
|
857
|
+
el(
|
|
858
|
+
"p",
|
|
859
|
+
"node-input-warning",
|
|
860
|
+
`降级:${missingEntry.id} 未加载(${missingEntry.reason || "unknown"})`,
|
|
861
|
+
),
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
if ((facts.missing ?? []).length === 0) {
|
|
865
|
+
section.appendChild(el("p", "muted", "全部声明扩展均已解析加载。"));
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
wrap.appendChild(section);
|
|
869
|
+
}
|
|
870
|
+
|
|
802
871
|
if (data.promptFingerprint?.exists) {
|
|
803
872
|
const section = el("section", "node-input-section");
|
|
804
873
|
section.appendChild(el("h4", null, "Assembled prompt 指纹"));
|
|
@@ -916,8 +985,304 @@ async function renderDagNodeInput(content, dagRunId, node) {
|
|
|
916
985
|
finishInputRender();
|
|
917
986
|
}
|
|
918
987
|
|
|
988
|
+
/**
|
|
989
|
+
* Experimental prompt-override rerun tab. Only reachable when the server
|
|
990
|
+
* injected the mutation token (switch on). Every node shows its frozen
|
|
991
|
+
* subtask_prompt here; only FAILED (ERROR) nodes additionally get the editor +
|
|
992
|
+
* restart flow: preflight (dagRerunPlan) binds the edit into planHash, dagRerun
|
|
993
|
+
* executes it as a Console operation, and on success we jump to the new run.
|
|
994
|
+
*/
|
|
995
|
+
async function renderPromptRestart(content, dagRunId, node) {
|
|
996
|
+
const nodeId = node.nodeId;
|
|
997
|
+
clearNode(content);
|
|
998
|
+
|
|
999
|
+
const loading = el("p", "muted", "正在加载冻结提示词…");
|
|
1000
|
+
loading.setAttribute("role", "status");
|
|
1001
|
+
loading.setAttribute("aria-live", "polite");
|
|
1002
|
+
content.appendChild(loading);
|
|
1003
|
+
const input = await fetchDagNodeInput(dagRunId, nodeId);
|
|
1004
|
+
if (
|
|
1005
|
+
!content.isConnected ||
|
|
1006
|
+
content.dataset.dagNodeId !== String(nodeId) ||
|
|
1007
|
+
content.dataset.dagRunId !== String(dagRunId) ||
|
|
1008
|
+
activeInspectorTab() !== "prompt-restart"
|
|
1009
|
+
) {
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
clearNode(content);
|
|
1013
|
+
|
|
1014
|
+
if (!input.ok || !input.body?.available) {
|
|
1015
|
+
const error = el("p", "node-input-error", "无法读取该节点的冻结提示词。");
|
|
1016
|
+
error.setAttribute("role", "alert");
|
|
1017
|
+
content.appendChild(error);
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
const basePrompt =
|
|
1021
|
+
typeof input.body.prompt?.text === "string" ? input.body.prompt.text : "";
|
|
1022
|
+
if (!basePrompt) {
|
|
1023
|
+
const error = el("p", "node-input-error", "该节点没有冻结提示词。");
|
|
1024
|
+
error.setAttribute("role", "alert");
|
|
1025
|
+
content.appendChild(error);
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
if (node.status !== "ERROR") {
|
|
1030
|
+
// Non-failed nodes still show their frozen prompt — read-only.
|
|
1031
|
+
const hint = el(
|
|
1032
|
+
"p",
|
|
1033
|
+
"muted",
|
|
1034
|
+
`当前节点状态为 ${node.status ?? "unknown"};仅失败(ERROR)节点支持编辑提示词并重启,以下为该节点冻结提示词(只读)。`,
|
|
1035
|
+
);
|
|
1036
|
+
hint.setAttribute("role", "status");
|
|
1037
|
+
content.appendChild(hint);
|
|
1038
|
+
const pre = document.createElement("pre");
|
|
1039
|
+
pre.className = "prompt-restart-readonly";
|
|
1040
|
+
pre.setAttribute("data-testid", "prompt-restart-readonly");
|
|
1041
|
+
pre.textContent = basePrompt;
|
|
1042
|
+
content.appendChild(pre);
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
if (input.body.prompt?.truncated === true) {
|
|
1047
|
+
const error = el(
|
|
1048
|
+
"p",
|
|
1049
|
+
"node-input-error",
|
|
1050
|
+
"冻结提示词被截断,为避免误替换请改用 CLI(dag rerun --prompt-override)。",
|
|
1051
|
+
);
|
|
1052
|
+
error.setAttribute("role", "alert");
|
|
1053
|
+
content.appendChild(error);
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
const box = el("div", "prompt-restart-box");
|
|
1058
|
+
box.appendChild(
|
|
1059
|
+
el(
|
|
1060
|
+
"p",
|
|
1061
|
+
"muted",
|
|
1062
|
+
"编辑该失败节点的提示词并从它重启:父 run spec 保持冻结,将创建带修改提示词的续跑 run(实验能力,仅 ERROR 节点)。",
|
|
1063
|
+
),
|
|
1064
|
+
);
|
|
1065
|
+
|
|
1066
|
+
const modeRow = el("div", "prompt-restart-mode");
|
|
1067
|
+
modeRow.appendChild(el("span", "muted", "编辑模式"));
|
|
1068
|
+
const modeSelect = document.createElement("select");
|
|
1069
|
+
modeSelect.className = "prompt-restart-mode-select";
|
|
1070
|
+
modeSelect.setAttribute("data-testid", "prompt-restart-mode");
|
|
1071
|
+
const appendOption = document.createElement("option");
|
|
1072
|
+
appendOption.value = "append";
|
|
1073
|
+
appendOption.textContent =
|
|
1074
|
+
"追加指令(推荐):保留原提示词,在末尾追加 operator_addendum 块";
|
|
1075
|
+
const replaceOption = document.createElement("option");
|
|
1076
|
+
replaceOption.value = "replace";
|
|
1077
|
+
replaceOption.textContent = "全文替换(高级):替换整个提示词";
|
|
1078
|
+
modeSelect.appendChild(appendOption);
|
|
1079
|
+
modeSelect.appendChild(replaceOption);
|
|
1080
|
+
modeSelect.value = "append";
|
|
1081
|
+
modeRow.appendChild(modeSelect);
|
|
1082
|
+
box.appendChild(modeRow);
|
|
1083
|
+
|
|
1084
|
+
const baseLabel = el("label", "prompt-restart-field");
|
|
1085
|
+
baseLabel.appendChild(
|
|
1086
|
+
el("span", "muted", `冻结提示词(只读底稿 · ${nodeId})`),
|
|
1087
|
+
);
|
|
1088
|
+
const baseBlock = document.createElement("pre");
|
|
1089
|
+
baseBlock.className = "prompt-restart-readonly";
|
|
1090
|
+
baseBlock.setAttribute("data-testid", "prompt-restart-base");
|
|
1091
|
+
baseBlock.textContent = basePrompt;
|
|
1092
|
+
baseLabel.appendChild(baseBlock);
|
|
1093
|
+
box.appendChild(baseLabel);
|
|
1094
|
+
|
|
1095
|
+
const addendumLabel = el("label", "prompt-restart-field");
|
|
1096
|
+
addendumLabel.appendChild(
|
|
1097
|
+
el(
|
|
1098
|
+
"span",
|
|
1099
|
+
"muted",
|
|
1100
|
+
"追加指令(将包裹为 <operator_addendum> 块附加到原提示词末尾)",
|
|
1101
|
+
),
|
|
1102
|
+
);
|
|
1103
|
+
const addendumArea = document.createElement("textarea");
|
|
1104
|
+
addendumArea.className = "prompt-restart-textarea";
|
|
1105
|
+
addendumArea.rows = 6;
|
|
1106
|
+
addendumArea.placeholder = "例如:重点检查 X 边界;输出前先自检 Y 约束…";
|
|
1107
|
+
addendumArea.setAttribute("data-testid", "prompt-restart-addendum");
|
|
1108
|
+
addendumLabel.appendChild(addendumArea);
|
|
1109
|
+
box.appendChild(addendumLabel);
|
|
1110
|
+
|
|
1111
|
+
const replaceLabel = el("label", "prompt-restart-field");
|
|
1112
|
+
replaceLabel.appendChild(el("span", "muted", `完整提示词(${nodeId})`));
|
|
1113
|
+
const replaceArea = document.createElement("textarea");
|
|
1114
|
+
replaceArea.className = "prompt-restart-textarea";
|
|
1115
|
+
replaceArea.rows = 16;
|
|
1116
|
+
replaceArea.value = basePrompt;
|
|
1117
|
+
replaceArea.setAttribute("data-testid", "prompt-restart-textarea");
|
|
1118
|
+
replaceLabel.appendChild(replaceArea);
|
|
1119
|
+
box.appendChild(replaceLabel);
|
|
1120
|
+
|
|
1121
|
+
const applyModeVisibility = () => {
|
|
1122
|
+
const append = modeSelect.value === "append";
|
|
1123
|
+
baseLabel.style.display = append ? "" : "none";
|
|
1124
|
+
addendumLabel.style.display = append ? "" : "none";
|
|
1125
|
+
replaceLabel.style.display = append ? "none" : "";
|
|
1126
|
+
};
|
|
1127
|
+
modeSelect.addEventListener("change", applyModeVisibility);
|
|
1128
|
+
applyModeVisibility();
|
|
1129
|
+
|
|
1130
|
+
const reasonLabel = el("label", "prompt-restart-field");
|
|
1131
|
+
reasonLabel.appendChild(el("span", "muted", "重启原因(结构化说明)"));
|
|
1132
|
+
const reasonArea = document.createElement("textarea");
|
|
1133
|
+
reasonArea.className = "prompt-restart-textarea";
|
|
1134
|
+
reasonArea.rows = 3;
|
|
1135
|
+
reasonArea.value = `operator-prompt-override / run=${dagRunId} / node=${nodeId} / 手工编辑失败节点提示词后重启`;
|
|
1136
|
+
reasonArea.setAttribute("data-testid", "prompt-restart-reason");
|
|
1137
|
+
reasonLabel.appendChild(reasonArea);
|
|
1138
|
+
box.appendChild(reasonLabel);
|
|
1139
|
+
|
|
1140
|
+
const row = el("div", "prompt-restart-actions");
|
|
1141
|
+
const submit = document.createElement("button");
|
|
1142
|
+
submit.type = "button";
|
|
1143
|
+
submit.className = "prompt-restart-submit";
|
|
1144
|
+
submit.textContent = "资格预检并重启";
|
|
1145
|
+
submit.setAttribute("data-testid", "prompt-restart-submit");
|
|
1146
|
+
row.appendChild(submit);
|
|
1147
|
+
box.appendChild(row);
|
|
1148
|
+
|
|
1149
|
+
const status = el("p", "prompt-restart-status", "");
|
|
1150
|
+
status.setAttribute("role", "status");
|
|
1151
|
+
status.setAttribute("aria-live", "polite");
|
|
1152
|
+
box.appendChild(status);
|
|
1153
|
+
|
|
1154
|
+
content.appendChild(box);
|
|
1155
|
+
|
|
1156
|
+
const setStatus = (text, isError = false) => {
|
|
1157
|
+
status.textContent = text ?? "";
|
|
1158
|
+
status.classList.toggle("prompt-restart-error", isError);
|
|
1159
|
+
};
|
|
1160
|
+
|
|
1161
|
+
submit.addEventListener("click", () => {
|
|
1162
|
+
void (async () => {
|
|
1163
|
+
const mode = modeSelect.value === "replace" ? "replace" : "append";
|
|
1164
|
+
const prompt =
|
|
1165
|
+
mode === "append" ? addendumArea.value : replaceArea.value;
|
|
1166
|
+
const reason = reasonArea.value.trim();
|
|
1167
|
+
if (!prompt.trim()) {
|
|
1168
|
+
setStatus(
|
|
1169
|
+
mode === "append" ? "追加指令不能为空。" : "提示词不能为空。",
|
|
1170
|
+
true,
|
|
1171
|
+
);
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
if (mode === "replace" && prompt === basePrompt) {
|
|
1175
|
+
setStatus("提示词未修改;如需按原提示词重跑请使用恢复工作台。", true);
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
if (!reason) {
|
|
1179
|
+
setStatus("需要填写重启原因。", true);
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
submit.disabled = true;
|
|
1183
|
+
try {
|
|
1184
|
+
setStatus("正在做重跑资格预检(dagRerunPlan)…");
|
|
1185
|
+
const overrides = [{ nodeId, prompt, mode }];
|
|
1186
|
+
const planRes = await postOperatorAction("dagRerunPlan", {
|
|
1187
|
+
runId: dagRunId,
|
|
1188
|
+
fromNode: nodeId,
|
|
1189
|
+
promptOverrides: overrides,
|
|
1190
|
+
});
|
|
1191
|
+
const plan = planRes.body?.result ?? null;
|
|
1192
|
+
if (!planRes.ok || plan?.eligible !== true || !plan?.planHash) {
|
|
1193
|
+
setStatus(
|
|
1194
|
+
planRes.body?.error?.message ??
|
|
1195
|
+
plan?.blockedReasons?.join(", ") ??
|
|
1196
|
+
"资格预检未通过。",
|
|
1197
|
+
true,
|
|
1198
|
+
);
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
const est = plan.estimatedExecution;
|
|
1203
|
+
const estText = est
|
|
1204
|
+
? `(将执行 ${est.nodeCount ?? "?"} 个节点 / ${est.piCallCount ?? "?"} 次 Pi 调用)`
|
|
1205
|
+
: "";
|
|
1206
|
+
setStatus(`预检通过${estText},正在提交续跑(dagRerun)…`);
|
|
1207
|
+
const clientRequestId = `inspect-prompt-restart-${Date.now()}-${Math.random()
|
|
1208
|
+
.toString(36)
|
|
1209
|
+
.slice(2, 10)}`;
|
|
1210
|
+
const runRes = await postOperatorAction(
|
|
1211
|
+
"dagRerun",
|
|
1212
|
+
{
|
|
1213
|
+
runId: dagRunId,
|
|
1214
|
+
fromNode: nodeId,
|
|
1215
|
+
planHash: plan.planHash,
|
|
1216
|
+
reason,
|
|
1217
|
+
promptOverrides: overrides,
|
|
1218
|
+
},
|
|
1219
|
+
clientRequestId,
|
|
1220
|
+
);
|
|
1221
|
+
const operationId = runRes.body?.operationId;
|
|
1222
|
+
if (!runRes.ok || !operationId) {
|
|
1223
|
+
setStatus(runRes.body?.error?.message ?? "提交续跑失败。", true);
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
const op = await pollOperationToTerminal(operationId, (text) =>
|
|
1228
|
+
setStatus(text),
|
|
1229
|
+
);
|
|
1230
|
+
if (op?.state === "succeeded") {
|
|
1231
|
+
const newRunId =
|
|
1232
|
+
op.dagRunId ?? op.result?.newRunId ?? op.runSummary?.runId ?? null;
|
|
1233
|
+
if (newRunId) {
|
|
1234
|
+
setStatus(`重启完成,新 run:${newRunId}`);
|
|
1235
|
+
const open = document.createElement("button");
|
|
1236
|
+
open.type = "button";
|
|
1237
|
+
open.className = "prompt-restart-submit";
|
|
1238
|
+
open.textContent = "打开新 run";
|
|
1239
|
+
open.addEventListener("click", () => {
|
|
1240
|
+
window.location.hash = `#/dag/${encodeURIComponent(String(newRunId))}`;
|
|
1241
|
+
});
|
|
1242
|
+
row.appendChild(open);
|
|
1243
|
+
} else {
|
|
1244
|
+
setStatus("重启完成(未能解析新 run id,请在 DAG 历史中查看)。");
|
|
1245
|
+
}
|
|
1246
|
+
} else if (op) {
|
|
1247
|
+
setStatus(
|
|
1248
|
+
`续跑操作终态:${op.state}${op.errorMessage ? ` — ${op.errorMessage}` : ""}`,
|
|
1249
|
+
true,
|
|
1250
|
+
);
|
|
1251
|
+
} else {
|
|
1252
|
+
setStatus("等待超时:操作仍在运行,可在操作台查看进度。", true);
|
|
1253
|
+
}
|
|
1254
|
+
} catch (err) {
|
|
1255
|
+
setStatus(err instanceof Error ? err.message : String(err), true);
|
|
1256
|
+
} finally {
|
|
1257
|
+
submit.disabled = false;
|
|
1258
|
+
}
|
|
1259
|
+
})();
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
/** Poll a Console operation until a terminal state; null on poll budget end. */
|
|
1264
|
+
async function pollOperationToTerminal(operationId, onProgress) {
|
|
1265
|
+
const terminal = new Set([
|
|
1266
|
+
"succeeded",
|
|
1267
|
+
"failed",
|
|
1268
|
+
"timed-out",
|
|
1269
|
+
"needs-reconcile",
|
|
1270
|
+
]);
|
|
1271
|
+
for (let attempt = 0; attempt < 1200; attempt += 1) {
|
|
1272
|
+
const res = await fetchOperatorOperation(operationId);
|
|
1273
|
+
const op = res.body?.operation ?? res.body;
|
|
1274
|
+
const state = op?.state ?? "";
|
|
1275
|
+
if (res.ok && terminal.has(state)) {
|
|
1276
|
+
return op;
|
|
1277
|
+
}
|
|
1278
|
+
onProgress(`续跑执行中…(${state || "queued"})`);
|
|
1279
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
1280
|
+
}
|
|
1281
|
+
return null;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
919
1284
|
function activeInspectorTab() {
|
|
920
|
-
return ["input", "timeline", "spec-evidence"].includes(
|
|
1285
|
+
return ["input", "timeline", "spec-evidence", "prompt-restart"].includes(
|
|
921
1286
|
uiState.dagInspectorTab,
|
|
922
1287
|
)
|
|
923
1288
|
? uiState.dagInspectorTab
|
|
@@ -1254,7 +1619,7 @@ function appendOutputBody(content, outputText, errorText, options = null) {
|
|
|
1254
1619
|
content.appendChild(el("p", "empty", UI_TEXT.noOutput));
|
|
1255
1620
|
return;
|
|
1256
1621
|
}
|
|
1257
|
-
if (outputText) content.appendChild(
|
|
1622
|
+
if (outputText) content.appendChild(renderInspectorDocument(outputText));
|
|
1258
1623
|
// Truncation note only for full/cached execution-output bodies (AC-003);
|
|
1259
1624
|
// preview path never invents truncated/maxBytes.
|
|
1260
1625
|
if (options?.truncated === true) {
|
|
@@ -1270,7 +1635,7 @@ function appendOutputBody(content, outputText, errorText, options = null) {
|
|
|
1270
1635
|
if (errorText) {
|
|
1271
1636
|
const error = el("section", "markdown-error");
|
|
1272
1637
|
error.appendChild(el("p", "markdown-error-title", "错误输出"));
|
|
1273
|
-
error.appendChild(
|
|
1638
|
+
error.appendChild(renderInspectorDocument(errorText));
|
|
1274
1639
|
content.appendChild(error);
|
|
1275
1640
|
}
|
|
1276
1641
|
}
|
|
@@ -1404,6 +1769,228 @@ function repaintOutputTabBody(content, dagRunId, node) {
|
|
|
1404
1769
|
restoreInspectorContentScroll(content, dagRunId, node.nodeId, "output");
|
|
1405
1770
|
}
|
|
1406
1771
|
|
|
1772
|
+
function processEmptyMessage(body) {
|
|
1773
|
+
const reason = body?.emptyReason;
|
|
1774
|
+
if (reason === "static-no-process") return UI_TEXT.staticNoProcess;
|
|
1775
|
+
if (reason === "shell-receipt-missing") return UI_TEXT.noShellProcess;
|
|
1776
|
+
if (reason === "shell-preset-pending") return UI_TEXT.noPresetProcess;
|
|
1777
|
+
if (reason === "pi-session") return UI_TEXT.noSessionEvents;
|
|
1778
|
+
return UI_TEXT.noSessionEvents;
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
function formatProcessBlock(text) {
|
|
1782
|
+
if (!text) return "";
|
|
1783
|
+
return prettyJsonBlock(text) ?? text;
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
function appendProcessPre(parent, text) {
|
|
1787
|
+
if (!text) return;
|
|
1788
|
+
const pre = el("pre", "process-timeline-code");
|
|
1789
|
+
pre.textContent = formatProcessBlock(text);
|
|
1790
|
+
parent.appendChild(pre);
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
function renderProcessCommandCard(command) {
|
|
1794
|
+
const failed = command.ok === false;
|
|
1795
|
+
const card = el(
|
|
1796
|
+
"div",
|
|
1797
|
+
`process-timeline-card process-timeline-tool-card${failed ? " is-error" : ""}`,
|
|
1798
|
+
);
|
|
1799
|
+
const details = document.createElement("details");
|
|
1800
|
+
details.className = "process-timeline-details";
|
|
1801
|
+
details.open = failed;
|
|
1802
|
+
const summary = el("summary", "process-timeline-summary");
|
|
1803
|
+
summary.appendChild(
|
|
1804
|
+
el("span", "process-timeline-summary-title", command.command || "command"),
|
|
1805
|
+
);
|
|
1806
|
+
summary.appendChild(
|
|
1807
|
+
el(
|
|
1808
|
+
"span",
|
|
1809
|
+
`process-timeline-summary-status status-${failed ? "failed" : "succeeded"}`,
|
|
1810
|
+
failed ? "失败" : command.reused ? "复用" : "成功",
|
|
1811
|
+
),
|
|
1812
|
+
);
|
|
1813
|
+
details.appendChild(summary);
|
|
1814
|
+
const body = el("div", "process-timeline-card-body");
|
|
1815
|
+
const meta = [
|
|
1816
|
+
command.exitCode != null ? `exit ${command.exitCode}` : null,
|
|
1817
|
+
command.durationMs != null ? `耗时 ${formatMs(command.durationMs)}` : null,
|
|
1818
|
+
command.failureCategory ? command.failureCategory : null,
|
|
1819
|
+
].filter(Boolean);
|
|
1820
|
+
if (meta.length > 0) {
|
|
1821
|
+
body.appendChild(el("div", "process-timeline-section-label", meta.join(" · ")));
|
|
1822
|
+
}
|
|
1823
|
+
if (command.stdout) {
|
|
1824
|
+
body.appendChild(el("div", "process-timeline-section-label", "stdout"));
|
|
1825
|
+
appendProcessPre(body, command.stdout);
|
|
1826
|
+
}
|
|
1827
|
+
if (command.stderr) {
|
|
1828
|
+
body.appendChild(el("div", "process-timeline-section-label", "stderr"));
|
|
1829
|
+
appendProcessPre(body, command.stderr);
|
|
1830
|
+
}
|
|
1831
|
+
if (command.truncated) {
|
|
1832
|
+
body.appendChild(el("p", "muted", "内容过长,已截断。"));
|
|
1833
|
+
}
|
|
1834
|
+
details.appendChild(body);
|
|
1835
|
+
card.appendChild(details);
|
|
1836
|
+
return card;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
function renderProcessStepCard(step) {
|
|
1840
|
+
const failed = step.ok === false;
|
|
1841
|
+
const card = el(
|
|
1842
|
+
"div",
|
|
1843
|
+
`process-timeline-card process-timeline-tool-card${failed ? " is-error" : ""}`,
|
|
1844
|
+
);
|
|
1845
|
+
const details = document.createElement("details");
|
|
1846
|
+
details.className = "process-timeline-details";
|
|
1847
|
+
details.open = true;
|
|
1848
|
+
const summary = el("summary", "process-timeline-summary");
|
|
1849
|
+
summary.appendChild(
|
|
1850
|
+
el("span", "process-timeline-summary-title", step.label || step.id || "step"),
|
|
1851
|
+
);
|
|
1852
|
+
summary.appendChild(
|
|
1853
|
+
el(
|
|
1854
|
+
"span",
|
|
1855
|
+
`process-timeline-summary-status status-${failed ? "failed" : "succeeded"}`,
|
|
1856
|
+
failed ? "失败" : "成功",
|
|
1857
|
+
),
|
|
1858
|
+
);
|
|
1859
|
+
details.appendChild(summary);
|
|
1860
|
+
const body = el("div", "process-timeline-card-body");
|
|
1861
|
+
if (step.durationMs != null) {
|
|
1862
|
+
body.appendChild(
|
|
1863
|
+
el("div", "process-timeline-section-label", `耗时 ${formatMs(step.durationMs)}`),
|
|
1864
|
+
);
|
|
1865
|
+
}
|
|
1866
|
+
if (step.detail) appendProcessPre(body, step.detail);
|
|
1867
|
+
if (step.truncated) {
|
|
1868
|
+
body.appendChild(el("p", "muted", "内容过长,已截断。"));
|
|
1869
|
+
}
|
|
1870
|
+
details.appendChild(body);
|
|
1871
|
+
card.appendChild(details);
|
|
1872
|
+
return card;
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
function renderNonPiProcess(content, body) {
|
|
1876
|
+
content.classList.add("process-timeline-scroll");
|
|
1877
|
+
if (!body || body.emptyReason || ((body.commands ?? []).length === 0 && (body.steps ?? []).length === 0)) {
|
|
1878
|
+
content.appendChild(el("p", "empty", processEmptyMessage(body)));
|
|
1879
|
+
return;
|
|
1880
|
+
}
|
|
1881
|
+
const heading =
|
|
1882
|
+
body.kind === "shell-preset"
|
|
1883
|
+
? UI_TEXT.shellPresetHeading
|
|
1884
|
+
: UI_TEXT.shellCommandsHeading;
|
|
1885
|
+
if (body.handler) {
|
|
1886
|
+
content.appendChild(
|
|
1887
|
+
el("p", "process-timeline-note", `${heading} · ${body.handler}`),
|
|
1888
|
+
);
|
|
1889
|
+
}
|
|
1890
|
+
const ul = el("ul", "process-timeline process-timeline-rich");
|
|
1891
|
+
const items = (body.commands ?? []).length > 0 ? body.commands : body.steps ?? [];
|
|
1892
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
1893
|
+
const item = items[index];
|
|
1894
|
+
const failed = item.ok === false;
|
|
1895
|
+
const li = el(
|
|
1896
|
+
"li",
|
|
1897
|
+
`process-timeline-item process-timeline-tool-end${failed ? " is-error" : ""}${index === 0 ? " is-first" : ""}${index === items.length - 1 ? " is-last" : ""}`,
|
|
1898
|
+
);
|
|
1899
|
+
const rail = el("span", "process-timeline-rail");
|
|
1900
|
+
rail.appendChild(el("span", "process-timeline-dot"));
|
|
1901
|
+
li.appendChild(rail);
|
|
1902
|
+
const cardBody = el("div", "process-timeline-body");
|
|
1903
|
+
cardBody.appendChild(
|
|
1904
|
+
body.kind === "shell-preset"
|
|
1905
|
+
? renderProcessStepCard(item)
|
|
1906
|
+
: renderProcessCommandCard(item),
|
|
1907
|
+
);
|
|
1908
|
+
li.appendChild(cardBody);
|
|
1909
|
+
ul.appendChild(li);
|
|
1910
|
+
}
|
|
1911
|
+
content.appendChild(ul);
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
export async function mergeNodeProcess(dagRunId, node) {
|
|
1915
|
+
if (!dagRunId || !node?.nodeId) return;
|
|
1916
|
+
const nodeId = node.nodeId;
|
|
1917
|
+
const key = effectiveExecutionKey(dagRunId, node);
|
|
1918
|
+
const identity = makeDagNodeProcessIdentity(dagRunId, nodeId, key);
|
|
1919
|
+
uiState.dagNodeProcessIdentity = identity;
|
|
1920
|
+
uiState.dagNodeProcessLoading = true;
|
|
1921
|
+
const result = await fetchDagNodeProcess(dagRunId, nodeId, key);
|
|
1922
|
+
if (uiState.dagNodeProcessIdentity !== identity) return;
|
|
1923
|
+
if (!result.ok || !result.body) {
|
|
1924
|
+
uiState.dagNodeProcessError =
|
|
1925
|
+
result.body?.error || UI_TEXT.processError;
|
|
1926
|
+
uiState.dagNodeProcessData = {
|
|
1927
|
+
schemaVersion: 1,
|
|
1928
|
+
dagRunId,
|
|
1929
|
+
nodeId,
|
|
1930
|
+
kind: "none",
|
|
1931
|
+
executor: node.executor ?? null,
|
|
1932
|
+
handler: null,
|
|
1933
|
+
emptyReason: "not-executed",
|
|
1934
|
+
key: key ?? null,
|
|
1935
|
+
commands: [],
|
|
1936
|
+
steps: [],
|
|
1937
|
+
};
|
|
1938
|
+
uiState.dagNodeProcessLoading = false;
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
uiState.dagNodeProcessError = null;
|
|
1942
|
+
uiState.dagNodeProcessData = result.body;
|
|
1943
|
+
uiState.dagNodeProcessLoading = false;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
function renderExecutorAwareTimeline(content, dagRunId, node) {
|
|
1947
|
+
content.dataset.dagRunId = String(dagRunId ?? "");
|
|
1948
|
+
content.dataset.nodeId = String(node.nodeId ?? "");
|
|
1949
|
+
const key = effectiveExecutionKey(dagRunId, node);
|
|
1950
|
+
const cached = uiState.dagNodeProcessData;
|
|
1951
|
+
const sameNode =
|
|
1952
|
+
cached &&
|
|
1953
|
+
cached.dagRunId === dagRunId &&
|
|
1954
|
+
cached.nodeId === node.nodeId &&
|
|
1955
|
+
(cached.key ?? null) === (key ?? null);
|
|
1956
|
+
if (sameNode && uiState.dagNodeProcessError) {
|
|
1957
|
+
content.appendChild(el("p", "empty", uiState.dagNodeProcessError));
|
|
1958
|
+
return;
|
|
1959
|
+
}
|
|
1960
|
+
if (sameNode && cached.kind === "pi-session") {
|
|
1961
|
+
renderSessionTimeline(content, node.nodeId, {
|
|
1962
|
+
executionKey: effectiveExecutionKey(dagRunId, node),
|
|
1963
|
+
});
|
|
1964
|
+
return;
|
|
1965
|
+
}
|
|
1966
|
+
if (sameNode && cached.kind !== "pi-session") {
|
|
1967
|
+
renderNonPiProcess(content, cached);
|
|
1968
|
+
return;
|
|
1969
|
+
}
|
|
1970
|
+
if ((node.executor ?? "pi") === "pi") {
|
|
1971
|
+
renderSessionTimeline(content, node.nodeId, {
|
|
1972
|
+
executionKey: effectiveExecutionKey(dagRunId, node),
|
|
1973
|
+
});
|
|
1974
|
+
return;
|
|
1975
|
+
}
|
|
1976
|
+
if (uiState.dagNodeProcessError && sameNode) {
|
|
1977
|
+
content.appendChild(el("p", "empty", uiState.dagNodeProcessError));
|
|
1978
|
+
return;
|
|
1979
|
+
}
|
|
1980
|
+
const loading = el("p", "muted", UI_TEXT.processLoading);
|
|
1981
|
+
loading.setAttribute("role", "status");
|
|
1982
|
+
content.appendChild(loading);
|
|
1983
|
+
void mergeNodeProcess(dagRunId, node).then(() => {
|
|
1984
|
+
if (
|
|
1985
|
+
uiState.dagInspectorTab === "timeline" &&
|
|
1986
|
+
uiState.selectedDagNodeId === node.nodeId &&
|
|
1987
|
+
uiState.currentDagRunId === dagRunId
|
|
1988
|
+
) {
|
|
1989
|
+
renderDagInspectorForCurrent();
|
|
1990
|
+
}
|
|
1991
|
+
});
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1407
1994
|
function fillDagInspectorContent(content, dagRunId, node) {
|
|
1408
1995
|
const previousRenderedNode = content.dataset.dagNodeId ?? "";
|
|
1409
1996
|
const previousRenderedRun = content.dataset.dagRunId ?? "";
|
|
@@ -1450,10 +2037,12 @@ function fillDagInspectorContent(content, dagRunId, node) {
|
|
|
1450
2037
|
);
|
|
1451
2038
|
if (activeTab === "spec-evidence") {
|
|
1452
2039
|
void renderSpecEvidence(content, dagRunId, node.nodeId);
|
|
2040
|
+
} else if (activeTab === "prompt-restart") {
|
|
2041
|
+
void renderPromptRestart(content, dagRunId, node);
|
|
1453
2042
|
} else if (activeTab === "timeline") {
|
|
1454
2043
|
const attemptBuilt = buildAttemptBar(dagRunId, node);
|
|
1455
2044
|
if (attemptBuilt?.bar) content.appendChild(attemptBuilt.bar);
|
|
1456
|
-
|
|
2045
|
+
renderExecutorAwareTimeline(content, dagRunId, node);
|
|
1457
2046
|
} else if (activeTab === "input") {
|
|
1458
2047
|
void renderDagNodeInput(content, dagRunId, node);
|
|
1459
2048
|
} else {
|
|
@@ -1517,6 +2106,14 @@ function buildDagInspectorHeader(dagRunId, node) {
|
|
|
1517
2106
|
["timeline", "执行过程", "ri-route-line"],
|
|
1518
2107
|
["spec-evidence", "规范证据", "ri-book-open-line"],
|
|
1519
2108
|
];
|
|
2109
|
+
// Experimental prompt-override rerun: the server injects the SCOPED
|
|
2110
|
+
// inspect mutation token into /inspect HTML only while
|
|
2111
|
+
// HARNESS_DAG_RERUN_PROMPT_OVERRIDE is enabled (and it only authorizes
|
|
2112
|
+
// dagRerunPlan/dagRerun). No token → no tab → the inspector stays
|
|
2113
|
+
// strictly read-only.
|
|
2114
|
+
if (globalThis.__INSPECT_MUTATION_TOKEN__) {
|
|
2115
|
+
tabDefs.push(["prompt-restart", "提示词重启", "ri-restart-line"]);
|
|
2116
|
+
}
|
|
1520
2117
|
const tabs = el("div", "dag-inspector-tabs");
|
|
1521
2118
|
tabs.setAttribute("role", "tablist");
|
|
1522
2119
|
tabs.setAttribute("aria-label", "节点检查器面板");
|
|
@@ -1606,7 +2203,14 @@ function dagInspectorSignature(dagRunId, node) {
|
|
|
1606
2203
|
uiState.dagNodeExecutionOutputLoading ? "loading" : "idle",
|
|
1607
2204
|
]
|
|
1608
2205
|
: tab === "timeline"
|
|
1609
|
-
? [
|
|
2206
|
+
? [
|
|
2207
|
+
uiState.sessionEventOffset,
|
|
2208
|
+
uiState.dagNodeProcessData?.kind ?? "",
|
|
2209
|
+
uiState.dagNodeProcessData?.emptyReason ?? "",
|
|
2210
|
+
(uiState.dagNodeProcessData?.commands ?? []).length,
|
|
2211
|
+
(uiState.dagNodeProcessData?.steps ?? []).length,
|
|
2212
|
+
uiState.dagNodeProcessLoading ? "loading" : "idle",
|
|
2213
|
+
]
|
|
1610
2214
|
: [node.status ?? ""];
|
|
1611
2215
|
// Attempt dimension: selection identity + history shape. Poll refreshes keep
|
|
1612
2216
|
// the DOM while selection/history are unchanged; switching attempt or a
|