@tea-agent/loop-agent 0.41.1-beta.0 → 0.42.0-next.1
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 +61 -207
- package/dist/adapters/context-transfer/optional-pi-handoff.js +31 -0
- package/dist/adapters/context-transfer/pi-session.js +61 -0
- package/dist/application/dag/generate-task-dag.js +19 -75
- package/dist/application/task-lifecycle/advance.js +5 -24
- package/dist/application/task-lifecycle/observe.js +17 -171
- package/dist/application/task-lifecycle/plan-transitions.js +7 -42
- package/dist/application/task-lifecycle/recommendations.js +2 -13
- package/dist/build-stamp.json +3 -3
- package/dist/cli/command-definitions.js +12 -7
- package/dist/cli/program.js +23 -6
- package/dist/commands/client-recovery.js +0 -3
- package/dist/commands/dag-artifact.js +284 -0
- package/dist/commands/dag-context.js +184 -0
- package/dist/commands/dag-rerun.js +206 -1
- package/dist/commands/init.js +1 -27
- package/dist/commands/task-advance.js +0 -19
- package/dist/executors/dag-pi-executor.js +266 -3792
- package/dist/executors/pi-executor.js +4 -15
- package/dist/executors/pi-sdk-executor.js +3 -0
- package/dist/executors/shell-executor.js +217 -945
- package/dist/executors/shell-write-guard.js +0 -7
- package/dist/{worker → infrastructure}/console/app-data.js +4 -0
- package/dist/infrastructure/console/artifact-revision-store.js +430 -0
- package/dist/infrastructure/console/context-export-store.js +160 -0
- package/dist/infrastructure/console/dir-lock.js +132 -0
- package/dist/infrastructure/console/operation-store.js +197 -0
- package/dist/infrastructure/harness/artifact-store.js +10 -1
- package/dist/infrastructure/harness/atomic-write.js +12 -2
- package/dist/shared/context-transfer/artifact-revision.js +172 -0
- package/dist/shared/context-transfer.js +418 -0
- package/dist/shared/dag-failure-category.js +0 -12
- package/dist/shared/openspec-spec.js +4 -70
- package/dist/shared/operator/capabilities.js +14 -7
- package/dist/shared/operator/safe-run-summary.js +1 -0
- package/dist/shared/path-safety.js +93 -0
- package/dist/shared/preview.js +28 -4
- package/dist/task/config-types.js +9 -35
- package/dist/task/contract/adopt.js +0 -4
- package/dist/task/contract/import-revision.js +0 -4
- package/dist/task/contract/project.js +0 -3
- package/dist/task/contract/schema.js +1 -2
- package/dist/task/frontend-project-capability.js +20 -203
- package/dist/task/runtime.js +2 -5
- package/dist/task/source-prepare/build-draft.js +3 -3
- package/dist/task/source-prepare/fragment-inventory.js +9 -15
- package/dist/task/source-prepare/prepare.js +1 -89
- package/dist/task/source-prepare/semantic-intake.js +2 -6
- package/dist/task/source-references.js +1 -22
- package/dist/task/task-demand-routing.js +3 -0
- package/dist/worker/console/chat/chat-event-store.js +2 -2
- package/dist/worker/console/chat/pi-runtime.js +3 -2
- package/dist/worker/console/chat/resource-preferences-store.js +1 -1
- package/dist/worker/console/chat/routes.js +13 -4
- package/dist/worker/console/chat/semantic-activity.js +12 -11
- package/dist/worker/console/chat/session-stats.js +96 -0
- package/dist/worker/console/chat/session-store.js +1 -1
- package/dist/worker/console/chat/turn-process.js +28 -4
- package/dist/worker/console/chat/user-questions.js +1 -1
- package/dist/worker/console/console-update-runtime.js +1 -1
- package/dist/worker/console/context-transfer-diagnostics.js +198 -0
- package/dist/worker/console/dag-confirmation.js +1 -1
- package/dist/worker/console/dag-execution-receipt.js +1 -1
- package/dist/worker/console/doctor.js +1 -1
- package/dist/worker/console/draft-store.js +1 -1
- package/dist/worker/console/human-gate-token.js +1 -1
- package/dist/worker/console/index.js +3 -6
- package/dist/worker/console/interview/assessment.js +1 -1
- package/dist/worker/console/interview/session.js +1 -1
- package/dist/worker/console/operation-runner.js +45 -4
- package/dist/worker/console/operation-sse.js +1 -1
- package/dist/worker/console/operation-wait.js +1 -1
- package/dist/worker/console/operator-actions.js +107 -168
- package/dist/worker/console/operator-surface-health.js +1 -1
- package/dist/worker/console/operator-user-error.js +169 -0
- package/dist/worker/console/pi-plugins.js +60 -1
- package/dist/worker/console/routes.js +637 -8
- package/dist/worker/console/security.js +35 -0
- package/dist/worker/console/server.js +6 -6
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Bho4we4c.js → abnfDiagram-N423BO3Z-DZZ8m3PO.js} +1 -1
- package/dist/worker/console/static/assets/{arc-TBDkTeK0.js → arc-D6PvaVd-.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BF_fZrn2.js → architectureDiagram-T3A2C74G-B_OTOiI8.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CCnPgUe2.js → blockDiagram-VBNYF7ZC-Bv6rqHBg.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BCYZJLAT.js → c4Diagram-5PPSVZJV-B8eHr0oz.js} +1 -1
- package/dist/worker/console/static/assets/channel-BU5gOilw.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D8K6adhU.js → chunk-2GRJ4B5K-DYwR0im2.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DkT1Q78b.js → chunk-2Q5K7J3B-D2WPGqXt.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DuhvpIr7.js → chunk-5RXB4S5H-CQISJ_I7.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BnK6dC49.js → chunk-5VM5RSS4-C0o2Du1e.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DPz__z7r.js → chunk-6Q2QTUOP-4f8kr-U7.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-0kkppM2j.js → chunk-GF5L2VYU-D_OWvXzX.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BB41iK5t.js → chunk-JWPE2WC7-CasdPz5X.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CiVrxKHU.js → chunk-KBJHAD2P-Cj8lRrla.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-C2h9Xje1.js → chunk-RYQCIY6F-CUvD1FSd.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-3iOSHdbM.js → chunk-XXDRQBXY-CqLw_eqB.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DIzKJGHr.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DIzKJGHr.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BN3A7tkk.js → cose-bilkent-JH36ORCC-ku-WqJPx.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-CTuBy0Or.js → cynefin-VYW2F7L2-Bq_PYDhl.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-wb6tUlMN.js → cynefinDiagram-MW4NZA55-BiGZV641.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-GP1Ivx8B.js → dagre-VZM6K2ZE-C4JRlglF.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-ejrcK6L0.js → diagram-7IWD3JNH-B0dNeWYG.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-YFkCCvUU.js → diagram-B4RE2ZJO-Cj35YvYM.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-B4rrvIaL.js → diagram-LBJQPF4R-uzQoJ2-8.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-C-YIZcUf.js → diagram-Q27KOJAE-D1a-Buoz.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPF5wcL1.js → diagram-UB23O5K3-XjRrLRSs.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CU5SzXjO.js → ebnfDiagram-BXEA7PRR-Da_O24cW.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-CpL414DE.js → erDiagram-JOGREHBK-BLJ8jrYU.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-MrhLzNau.js → flowDiagram-UKHOOZJN-B9GrLjM0.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Bg4qFuUo.js → ganttDiagram-PKOTCBZU-CeJ0TqiK.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-ColxSXLR.js → gitGraphDiagram-DS77QQ5N-Bm2eNNFX.js} +1 -1
- package/dist/worker/console/static/assets/index-H9rFJiGL.css +1 -0
- package/dist/worker/console/static/assets/index-xwu9GxEc.js +451 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-Czvtm6gc.js → infoDiagram-6WML65LV-DB26i3d8.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-B7Xp8HyJ.js → ishikawaDiagram-WSZJBQD7-BOGRyeZT.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DWYZcvph.js → journeyDiagram-NVQOT4AX-CZRoBO_6.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-KTLZRUjx.js → kanban-definition-27J2QSJJ-qlWhJyoB.js} +1 -1
- package/dist/worker/console/static/assets/{linear-_Exn7bfl.js → linear-CfUiDDB3.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-Cxg8kX8V.js → mermaid.core-BQe6fpqj.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-oKrlo2Bt.js → mindmap-definition-FAOFIHXS-zFzWHw64.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-XAeteiNd.js → pegDiagram-VL7TDLO6-DFGUqjZO.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BTf1K-lp.js → pieDiagram-7S7Q4E2Y-BB5i0l8Z.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-C0IlY0Jf.js → quadrantDiagram-CIZ2JOQS-obbVZ_X5.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BVbKtZhW.js → railroadDiagram-AXF67PYL-BwdaNzc1.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-C5e4JFcr.js → requirementDiagram-LRYGKXZP-CkTJaugh.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cz30hc29.js → sankeyDiagram-W5VNT64P-BwJ-hIgq.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DS33n6d0.js → sequenceDiagram-SI44F4Z6-BzSgmm7w.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-46w7v-9T.js → sizeCapture-X5ZJPWSS-Bn3oj5Q1.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-pbcD5SsZ.js → stateDiagram-OKZ733FA-dxhGtL8K.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cld2qK9v.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DuivYBSj.js → swimlanes-SLNWSIFB-BLpEInya.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-TIHpiT7w.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Cb9VZVIl.js → timeline-definition-Z64GVDOM-ChJGYcXy.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-D2-mfOgR.js → vennDiagram-T6HMQDX7-DK-qjRer.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DeS2aC76.js → wardleyDiagram-T6FBY63Y-3qeaWAg-.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-WGsrFjxH.js → xychartDiagram-ELKLHX3M-CootlyP9.js} +1 -1
- package/dist/worker/console/static/index.html +7 -2
- package/dist/worker/console/static-src/app/useOperatorActions.js +3 -2
- package/dist/worker/console/static-src/app/useRunProgress.js +9 -2
- package/dist/worker/console/static-src/operator-chat/dag-progress-link.js +22 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +2 -0
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -0
- package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +28 -3
- package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +106 -0
- package/dist/worker/console/static-src/shell/console-update-reload.js +25 -0
- package/dist/worker/console/workspace-context.js +28 -112
- package/dist/worker/console/workspace-registry.js +2 -2
- package/dist/worker/continuation/worker-continuation.js +278 -0
- package/dist/worker/observability/read-model.js +4 -0
- package/dist/worker/observe/health.js +1 -1
- package/dist/worker/observe/node-transparency.js +572 -0
- package/dist/worker/observe/routes.js +51 -1
- package/dist/worker/observe/static/api.js +69 -5
- package/dist/worker/observe/static/dag-context-reason-labels.d.ts +9 -0
- package/dist/worker/observe/static/dag-context-reason-labels.js +120 -0
- package/dist/worker/observe/static/dag-node-purpose.js +0 -5
- package/dist/worker/observe/static/state.js +3 -1
- package/dist/worker/observe/static/styles.css +1037 -126
- package/dist/worker/observe/static/views/dag-inspector.js +1217 -65
- package/dist/worker/observe/static/views/session-timeline.js +121 -25
- package/dist/worker/outcomes/adapters.js +19 -0
- package/dist/worker/outcomes/types.js +1 -0
- package/dist/worker/pool/attempt-lease.js +97 -66
- package/dist/worker/pool/begin-attempt-with-lease.js +1 -0
- package/dist/worker/pool/reconcile.js +46 -1
- package/dist/worker/pool/run-store.js +2 -0
- package/dist/worker/pool/state-projection.js +2 -0
- package/dist/worker/task-spec/workflow-routing.js +8 -3
- package/dist/workflows/dag/artifact-bindings.js +149 -0
- package/dist/workflows/dag/artifact-revision-schema-registry.js +31 -0
- package/dist/workflows/dag/backend-test-result-contract.js +1 -1
- package/dist/workflows/dag/budget-enforcement.js +10 -0
- package/dist/workflows/dag/context-receipt.js +305 -0
- package/dist/workflows/dag/context-transfer/context-bundle.js +423 -0
- package/dist/workflows/dag/context-transfer/operator-actions.js +61 -0
- package/dist/workflows/dag/context-transfer/renderers.js +93 -0
- package/dist/workflows/dag/contract-validator-registrations.js +2 -1
- package/dist/workflows/dag/frontend-implementation-contract.js +162 -932
- package/dist/workflows/dag/frontend-plan-render.js +1 -2
- package/dist/workflows/dag/frontend-prewrite-gate.js +349 -255
- package/dist/workflows/dag/frontend-recovery-plan.js +10 -17
- package/dist/workflows/dag/frontend-recovery-run.js +20 -33
- package/dist/workflows/dag/frontend-repair.js +432 -1
- package/dist/workflows/dag/frontend-review-context.js +15 -261
- package/dist/workflows/dag/frontend-verification-trace.js +24 -249
- package/dist/workflows/dag/frontend-worktree-diff.js +17 -250
- package/dist/workflows/dag/frontend-writer-rollback.js +32 -0
- package/dist/workflows/dag/init-hybrid.js +640 -685
- package/dist/workflows/dag/interrupt-request.js +0 -7
- package/dist/workflows/dag/node-execution.js +116 -759
- package/dist/workflows/dag/path-safety.js +1 -0
- package/dist/workflows/dag/prompt.js +30 -38
- package/dist/workflows/dag/report.js +1 -37
- package/dist/workflows/dag/rerun-feedback.js +1 -256
- package/dist/workflows/dag/rerun-plan.js +557 -11
- package/dist/workflows/dag/rerun-run.js +601 -38
- package/dist/workflows/dag/rerun-task.js +0 -29
- package/dist/workflows/dag/retry-policy.js +104 -214
- package/dist/workflows/dag/runner.js +142 -430
- package/dist/workflows/dag/scheduler.js +16 -114
- package/dist/workflows/dag/skill-snapshot.js +17 -0
- package/dist/workflows/dag/types.js +195 -246
- package/dist/workflows/dag/validate.js +12 -28
- package/docs/architecture/runtime-boundaries.md +6 -6
- package/docs/architecture/worker-and-feature.md +1 -1
- package/docs/init-surface.manifest.json +12 -30
- package/docs/skills/vetted-skill-registry.md +2 -4
- package/docs/templates/README.md +0 -2
- package/docs/templates/agent-dag-report.schema.json +2 -8
- package/docs/templates/agent-dag.schema.json +33 -1
- package/docs/templates/frontend-implementation-contract.schema.json +1 -4
- package/docs/templates/product-line/task.yaml +1 -1
- package/harness.json +3 -3
- package/package.json +3 -1
- package/skills/frontend-bounded-implement/SKILL.md +14 -15
- package/skills/frontend-design-review/SKILL.md +41 -22
- package/skills/frontend-implementation/SKILL.md +52 -0
- package/skills/frontend-implementation/references/code-standards.md +33 -0
- package/skills/frontend-implementation/references/design-spec.md +56 -0
- package/skills/frontend-implementation/references/node-contracts.md +31 -0
- package/skills/frontend-review/SKILL.md +15 -20
- package/skills/frontend-review/references/review-findings.md +7 -6
- package/skills/frontend-verification/SKILL.md +1 -1
- package/skills/loop-agent/references/command-reference.md +6 -1
- package/skills/loop-agent/references/hybrid-dag.md +2 -2
- package/dist/commands/dag-follow-up.js +0 -138
- package/dist/executors/pi-read-budget-policy.js +0 -239
- package/dist/worker/console/frontend-human-decision-adapter.js +0 -19
- package/dist/worker/console/frontend-split-operation-adapter.js +0 -20
- package/dist/worker/console/operation-store.js +0 -389
- package/dist/worker/console/static/assets/channel-bnXW0U3C.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-rZpq_twR.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-rZpq_twR.js +0 -1
- package/dist/worker/console/static/assets/index-D3CC4eUz.css +0 -1
- package/dist/worker/console/static/assets/index-DLt4ZFvD.js +0 -437
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-zBMYiUyi.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-d_rms-5i.js +0 -8
- package/dist/worker/console/static-src/active-run-badge.js +0 -17
- package/dist/worker/materialize/frontend-split-task-materializer.js +0 -72
- package/dist/workflows/dag/dag-retry-schema.js +0 -138
- package/dist/workflows/dag/frontend-closeout.js +0 -221
- package/dist/workflows/dag/frontend-design-policy.js +0 -400
- package/dist/workflows/dag/frontend-human-decision.js +0 -182
- package/dist/workflows/dag/frontend-provider-capability-matrix.js +0 -159
- package/dist/workflows/dag/frontend-read-budgets.js +0 -12
- package/dist/workflows/dag/frontend-recovery-capsule.js +0 -455
- package/dist/workflows/dag/frontend-recovery-controller.js +0 -202
- package/dist/workflows/dag/frontend-recovery-lineage.js +0 -178
- package/dist/workflows/dag/frontend-review-findings.js +0 -270
- package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -914
- package/dist/workflows/dag/frontend-shape-capsule-store.js +0 -191
- package/dist/workflows/dag/frontend-shape-facts.js +0 -409
- package/dist/workflows/dag/frontend-shape.js +0 -427
- package/dist/workflows/dag/frontend-source-fidelity-ledger.js +0 -108
- package/dist/workflows/dag/frontend-split-application-service.js +0 -203
- package/dist/workflows/dag/frontend-split-orchestrator.js +0 -899
- package/dist/workflows/dag/frontend-typed-event-store.js +0 -452
- package/dist/workflows/dag/frontend-typed-event-transaction.js +0 -180
- package/dist/workflows/dag/frontend-writer-admission.js +0 -285
- package/dist/workflows/dag/frontend-writer-status.js +0 -256
- package/dist/workflows/dag/recovery-lease.js +0 -80
- package/docs/templates/frontend-implementation-dag.json +0 -89
- package/docs/templates/spec-registry.schema.json +0 -45
- package/skills/frontend-bounded-implement/references/code-standards.md +0 -19
- package/skills/frontend-contract/SKILL.md +0 -23
- package/skills/frontend-contract/references/contract-protocol.md +0 -34
- package/skills/frontend-plan/SKILL.md +0 -26
- package/skills/frontend-plan/references/decision-contract.md +0 -37
- package/skills/frontend-plan/references/design-decisions.md +0 -17
- package/skills/frontend-scout/SKILL.md +0 -25
- package/skills/frontend-scout/references/design-evidence.md +0 -16
- package/skills/frontend-scout/references/scout-evidence.md +0 -23
- /package/dist/{worker → infrastructure}/console/repo-fingerprint.js +0 -0
|
@@ -5,9 +5,6 @@ import { ContractMutationError, applyTaskContract, logicalRevisionForState, obse
|
|
|
5
5
|
import { TASK_CONTRACT_DRAFT_SCHEMA_VERSION } from "../contract/constants.js";
|
|
6
6
|
import { getTaskContractPaths } from "../contract/paths.js";
|
|
7
7
|
import { loadTaskConfig } from "../runtime.js";
|
|
8
|
-
import { discoverFrontendProjectCapability, resolveFrontendSpecRootAliases, } from "../frontend-project-capability.js";
|
|
9
|
-
import { classifyTaskDemand } from "../task-demand-routing.js";
|
|
10
|
-
import { DEFAULT_FRONTEND_SPEC_ROOTS, extractDeclaredFrontendSpecRoots, } from "../../shared/openspec-spec.js";
|
|
11
8
|
import { buildPrepareDraft } from "./build-draft.js";
|
|
12
9
|
import { hasBlockingGaps, hasBlockingRisks, isFreshLegacyUnversioned, listPrepareGaps, appendLedgerGaps, } from "./completeness.js";
|
|
13
10
|
import { detectProductArtifactMeta, isIntakeSoftGapCode, } from "./artifact-meta.js";
|
|
@@ -684,7 +681,7 @@ export async function prepareTaskSource(input) {
|
|
|
684
681
|
facts = importedFacts ?? mergedSupplemental;
|
|
685
682
|
}
|
|
686
683
|
}
|
|
687
|
-
|
|
684
|
+
const built = buildPrepareDraft({
|
|
688
685
|
taskId,
|
|
689
686
|
existingTaskConfig,
|
|
690
687
|
baseDraft,
|
|
@@ -692,91 +689,6 @@ export async function prepareTaskSource(input) {
|
|
|
692
689
|
flags: input.flags,
|
|
693
690
|
references,
|
|
694
691
|
});
|
|
695
|
-
// Resolve an implicit frontend workflow before the first managed contract is
|
|
696
|
-
// projected. Explicit taskKind (including explicit standard) remains a hard
|
|
697
|
-
// contract; only a standard task with strong source/path/project evidence may
|
|
698
|
-
// be promoted here. This keeps task.json, contract.json, and the first DAG
|
|
699
|
-
// generation on the same workflow without a later hash-changing re-projection.
|
|
700
|
-
if (built.draft.taskKind === "standard" &&
|
|
701
|
-
!built.draft.taskKindExplicit) {
|
|
702
|
-
const routingRequirement = [
|
|
703
|
-
...(sourceIntegrity?.documents ?? [])
|
|
704
|
-
.map((document) => document.content)
|
|
705
|
-
.filter((content) => Boolean(content?.trim())),
|
|
706
|
-
...(input.intent.kind === "facts" && input.intent.text
|
|
707
|
-
? [input.intent.text]
|
|
708
|
-
: []),
|
|
709
|
-
built.draft.requirement.objective,
|
|
710
|
-
...built.draft.requirement.scope,
|
|
711
|
-
...built.draft.requirement.acceptanceCriteria.map((item) => item.text),
|
|
712
|
-
].join("\n");
|
|
713
|
-
let frontendProject;
|
|
714
|
-
try {
|
|
715
|
-
frontendProject = await discoverFrontendProjectCapability(repoRoot);
|
|
716
|
-
}
|
|
717
|
-
catch {
|
|
718
|
-
// Capability discovery is advisory for routing. A failed probe must not
|
|
719
|
-
// turn an otherwise valid standard contract preparation into an error.
|
|
720
|
-
}
|
|
721
|
-
const classification = classifyTaskDemand({
|
|
722
|
-
title: built.draft.title,
|
|
723
|
-
requirementMarkdown: routingRequirement,
|
|
724
|
-
allowedPaths: built.draft.constraints.allowedPaths,
|
|
725
|
-
frontendProject: frontendProject
|
|
726
|
-
? {
|
|
727
|
-
framework: frontendProject.framework,
|
|
728
|
-
evidencePaths: frontendProject.evidencePaths,
|
|
729
|
-
}
|
|
730
|
-
: undefined,
|
|
731
|
-
});
|
|
732
|
-
if (classification.kind === "frontend") {
|
|
733
|
-
built = buildPrepareDraft({
|
|
734
|
-
taskId,
|
|
735
|
-
existingTaskConfig,
|
|
736
|
-
baseDraft,
|
|
737
|
-
facts,
|
|
738
|
-
flags: {
|
|
739
|
-
...input.flags,
|
|
740
|
-
taskKind: "frontend-implementation",
|
|
741
|
-
},
|
|
742
|
-
references,
|
|
743
|
-
});
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
// A user can explicitly name a non-default normative directory in the task
|
|
747
|
-
// prompt (for example “规范目录 `design-system`”). Freeze that root into
|
|
748
|
-
// the managed task config before the DAG exists; normal DAG selection consumes
|
|
749
|
-
// the already-resolved task kind instead of mutating task.json later.
|
|
750
|
-
if (built.draft.taskKind === "frontend-implementation") {
|
|
751
|
-
// An imported PRD is materialized under sourceIntegrity rather than copied
|
|
752
|
-
// into intent.text. Use both inputs so a `--prd` invocation can declare a
|
|
753
|
-
// task-owned spec root just like supplemental free-form text can.
|
|
754
|
-
const sourceText = [
|
|
755
|
-
...(sourceIntegrity?.documents ?? []).flatMap((document) => document.content ? [document.content] : []),
|
|
756
|
-
...(input.intent.kind === "facts" && input.intent.text
|
|
757
|
-
? [input.intent.text]
|
|
758
|
-
: []),
|
|
759
|
-
].join("\n");
|
|
760
|
-
const inferredRoots = extractDeclaredFrontendSpecRoots(sourceText);
|
|
761
|
-
if (inferredRoots.length > 0) {
|
|
762
|
-
const current = existingTaskConfig?.frontendOpenspec;
|
|
763
|
-
const configuredRoots = current?.specRoots ?? [...DEFAULT_FRONTEND_SPEC_ROOTS];
|
|
764
|
-
// Include roots declared by this source before resolving physical-target
|
|
765
|
-
// aliases. A newly declared root may itself be a symlink (for example
|
|
766
|
-
// `project-specs -> .../ai_doc`), so resolving aliases against only the
|
|
767
|
-
// previous config cannot map `ai_doc/rules.md` back to project-specs.
|
|
768
|
-
const provisionalRoots = [
|
|
769
|
-
...new Set([...configuredRoots, ...inferredRoots]),
|
|
770
|
-
].sort();
|
|
771
|
-
const aliases = await resolveFrontendSpecRootAliases(repoRoot, provisionalRoots);
|
|
772
|
-
const aliasMap = new Map(aliases.map(({ alias, logicalRoot }) => [alias, logicalRoot]));
|
|
773
|
-
built.draft.frontendOpenspec = {
|
|
774
|
-
policy: current?.policy ?? "cited",
|
|
775
|
-
specRoots: [...new Set([...configuredRoots, ...inferredRoots.map((root) => aliasMap.get(root) ?? root)])].sort(),
|
|
776
|
-
requiredReadPaths: current?.requiredReadPaths ?? [],
|
|
777
|
-
};
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
692
|
const { gaps, risks } = listPrepareGaps({
|
|
781
693
|
draft: built.draft,
|
|
782
694
|
state,
|
|
@@ -457,12 +457,8 @@ async function buildPrompt(input) {
|
|
|
457
457
|
"Do NOT invent product behavior that is not supported by the documents.",
|
|
458
458
|
"You MAY recommend an optional engineering block when the repo layout hint supports it:",
|
|
459
459
|
"- allowedPaths / forbiddenPaths as minimal precise globs (e.g. source/packages/**/*.test.ts)",
|
|
460
|
-
"- verifyCommands as real package scripts (e.g. pnpm -C source test)
|
|
461
|
-
"- taskKind when clearly implied
|
|
462
|
-
" - frontend-implementation: the deliverable is a frontend component/page/UI feature (even when it ships with its own tests)",
|
|
463
|
-
" - frontend-test: the deliverable is a browser/UI automation test suite for EXISTING functionality (no implementation work)",
|
|
464
|
-
" - backend-test: pytest/backend test suite; standard: general repo implementation",
|
|
465
|
-
" A task that IMPLEMENTS a component and adds tests for it is frontend-implementation, never frontend-test.",
|
|
460
|
+
"- verifyCommands as real package scripts (e.g. pnpm -C source test)",
|
|
461
|
+
"- taskKind when clearly implied (backend-test / frontend-test / standard / …)",
|
|
466
462
|
"Prefer smallest correct write boundary; do not invent product paths that are not in the layout hint.",
|
|
467
463
|
"Do NOT rewrite or suggest editing the original PRD files.",
|
|
468
464
|
"Prefer explicit text; use provenance derived for rephrasing; use inferred only when clearly implied — if you must invent ACs, leave acceptanceCriteria empty so the system can stop for clarification.",
|
|
@@ -22,18 +22,6 @@ function slugifyName(value) {
|
|
|
22
22
|
.replace(/-{2,}/g, "-");
|
|
23
23
|
return slug || "requirement";
|
|
24
24
|
}
|
|
25
|
-
/** Stable identity of a manifest document for change detection. Timestamps and
|
|
26
|
-
* byte sizes are excluded: identical content re-imported later must not appear
|
|
27
|
-
* "changed" (the canonical hash includes manifest bytes). */
|
|
28
|
-
function documentIdentity(doc) {
|
|
29
|
-
return `${doc.role}|${doc.name}|${doc.materializedPath}|${doc.sha256}`;
|
|
30
|
-
}
|
|
31
|
-
function sameDocumentSet(left, right) {
|
|
32
|
-
if (left.length !== right.length)
|
|
33
|
-
return false;
|
|
34
|
-
const rightIds = new Set(right.map(documentIdentity));
|
|
35
|
-
return left.every((doc) => rightIds.has(documentIdentity(doc)));
|
|
36
|
-
}
|
|
37
25
|
function ensureUniqueReferenceName(existing, baseName, extension) {
|
|
38
26
|
const used = new Set(existing);
|
|
39
27
|
const candidate = `${baseName}${extension}`;
|
|
@@ -161,19 +149,10 @@ export async function importPrdDocument(input) {
|
|
|
161
149
|
const documents = [...(existingManifest?.documents ?? [])].filter((entry) => entry.materializedPath !== materializedRelativePath);
|
|
162
150
|
documents.push(document);
|
|
163
151
|
documents.sort((left, right) => left.materializedPath.localeCompare(right.materializedPath));
|
|
164
|
-
// Keep `updatedAt` stable across re-imports of the same content: the
|
|
165
|
-
// canonical contract hash includes the manifest bytes, so a fresh
|
|
166
|
-
// timestamp on every identical re-import would make the observed
|
|
167
|
-
// canonical hash drift and fail task verification. Only bump it when the
|
|
168
|
-
// document set actually changed (a new/changed materialized file).
|
|
169
|
-
const documentSetChanged = !existingManifest ||
|
|
170
|
-
!sameDocumentSet(existingManifest.documents, documents);
|
|
171
152
|
const manifest = {
|
|
172
153
|
schemaVersion: 1,
|
|
173
154
|
taskId: input.taskId,
|
|
174
|
-
updatedAt:
|
|
175
|
-
? importedAt
|
|
176
|
-
: (existingManifest?.updatedAt ?? importedAt),
|
|
155
|
+
updatedAt: importedAt,
|
|
177
156
|
documents,
|
|
178
157
|
};
|
|
179
158
|
await writeSourceManifest(paths.sourceDir, manifest);
|
|
@@ -76,6 +76,7 @@ const SPECIAL_TEMPLATE_BY_TASK_KIND = {
|
|
|
76
76
|
"frontend-implementation": "frontend-implementation",
|
|
77
77
|
"frontend-test": "frontend-test-dag",
|
|
78
78
|
"backend-test": "backend-test-dag",
|
|
79
|
+
"backend-test-analysis": "backend-test-analysis-dag",
|
|
79
80
|
"knowledge-sync": "knowledge-sync-dag",
|
|
80
81
|
"knowledge-graph-bootstrap": "knowledge-graph-bootstrap-dag",
|
|
81
82
|
};
|
|
@@ -83,6 +84,7 @@ const TASK_KIND_ROUTING_REASON = {
|
|
|
83
84
|
"frontend-implementation": 'taskKind "frontend-implementation" selects the dedicated frontend DAG template',
|
|
84
85
|
"frontend-test": 'taskKind "frontend-test" selects the dedicated frontend test DAG template',
|
|
85
86
|
"backend-test": 'taskKind "backend-test" selects the dedicated backend test DAG template',
|
|
87
|
+
"backend-test-analysis": 'taskKind "backend-test-analysis" selects the read-only backend test analysis DAG template',
|
|
86
88
|
"knowledge-sync": 'taskKind "knowledge-sync" selects the dedicated knowledge-sync DAG template',
|
|
87
89
|
"knowledge-graph-bootstrap": 'taskKind "knowledge-graph-bootstrap" selects the dedicated knowledge-graph bootstrap DAG template',
|
|
88
90
|
};
|
|
@@ -90,6 +92,7 @@ const SPECIAL_REQUESTED_TEMPLATES = new Set([
|
|
|
90
92
|
"frontend-implementation",
|
|
91
93
|
"frontend-test-dag",
|
|
92
94
|
"backend-test-dag",
|
|
95
|
+
"backend-test-analysis-dag",
|
|
93
96
|
"knowledge-sync-dag",
|
|
94
97
|
"knowledge-graph-bootstrap-dag",
|
|
95
98
|
]);
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
import { createHash } from "node:crypto";
|
|
20
20
|
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
21
21
|
import path from "node:path";
|
|
22
|
-
import { ensureSecureDir, writeSecureJsonSync, } from "
|
|
23
|
-
import { isTerminalOperationState, } from "
|
|
22
|
+
import { ensureSecureDir, writeSecureJsonSync, } from "../../../infrastructure/console/app-data.js";
|
|
23
|
+
import { isTerminalOperationState, } from "../../../infrastructure/console/operation-store.js";
|
|
24
24
|
import { scrubSecrets } from "./explore-tools.js";
|
|
25
25
|
const OPERATION_PREVIEW_MAX_CHARS = 1200;
|
|
26
26
|
function boundedRedactedText(value, maxChars = OPERATION_PREVIEW_MAX_CHARS) {
|
|
@@ -67,10 +67,11 @@ export const OPERATOR_CHAT_SYSTEM_PROMPT_BASE = [
|
|
|
67
67
|
"You are General Operator Chat.",
|
|
68
68
|
"Use operator tools first (dagReport, dagRerunPlan, dagRerun). Pi read/write/edit/bash/grep/find/ls are available; obey repository AGENTS.md. apply_patch, full-tools, shell and coding-chat are denied. Prefer safe-read/safe-grep for probes.",
|
|
69
69
|
"No harness and asked to init: `loop-agent init instructions --repo-root .`, then `loop-agent init --repo-root . --profile full --merge`; verify with doctor, inspect and docs audit. Updates: `loop-agent init upgrade --repo-root . --json` until stable; `loop-agent init check-update` is read-only.",
|
|
70
|
-
"Long DAGs: prepareDagExecution → runDag → operationId. Never foreground-Bash task advance, tail/head pipes or nohup/Start-Process/start; do not end on accepted/queued/running or an operationId — NOT completion. Supervise operationGet/status/dagReport/dagDoctor/operationWait
|
|
71
|
-
"
|
|
70
|
+
"Long DAGs: prepareDagExecution → runDag → operationId. Never foreground-Bash task advance, tail/head pipes or nohup/Start-Process/start; do not end on accepted/queued/running or an operationId — NOT completion. Supervise operationGet/status/dagReport/dagDoctor/operationWait at 60s → 90s → 120s → 180s; reset to 60s on state change; 30-60s re-checks when stall suspected. operationWait MUST use afterSeq=previous nextSeq (recommendedNextCall). Heartbeats: not meaningful progress. Run id ≠ task id.",
|
|
71
|
+
"Failure: terminal runSummary first. With progress wait; else dagRerunPlan(fromNode=primaryFailure.nodeId); eligible → dagRerun: reruns the failed subgraph, keeps prior successes. Ineligible: Worker → workerTaskRetry; standalone → standaloneTaskRerun after contract adopt (regenerates the whole task, not node continue). Do not call dagResume; do not re-advance a run-failed task. Pre-run identical state twice: stop and report; never loop identical bash/read/grep. Approve only bounded writeSet inside allowedPaths, outside forbiddenPaths, with structured verification.",
|
|
72
72
|
"Iterate toward the goal in bounded rounds: first summarize the previous round's error in one line, fix its root cause — not the symptom — then rerun the failed node with a fresh plan. Never resubmit an unchanged fix; after two rounds failing the same way, stop and report evidence and remaining routes.",
|
|
73
73
|
"Continue until success, user stop, or no safe recovery remains; then stop and report failure/evidence. Never create a new task for a transient failure or replace repair-pi with direct edits.",
|
|
74
|
+
"Narrate long-DAG progress briefly at start, meaningful phase changes/findings, verification failure/recovery, prolonged quiet and terminal state: say what finished and what is next. Never narrate unchanged operationWait polls or heartbeats, or claim beyond structured facts.",
|
|
74
75
|
].join("\n");
|
|
75
76
|
/** Compose the inspectable system prompt actually injected into Operator Chat. */
|
|
76
77
|
export function composeOperatorChatSystemPrompt(input) {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
9
|
import { existsSync, lstatSync } from "node:fs";
|
|
10
|
-
import { readJsonIfExists, writeSecureJson, } from "
|
|
10
|
+
import { readJsonIfExists, writeSecureJson, } from "../../../infrastructure/console/app-data.js";
|
|
11
11
|
export const RESOURCE_PREFERENCES_SCHEMA_VERSION = 1;
|
|
12
12
|
export class ResourcePreferencesError extends Error {
|
|
13
13
|
code;
|
|
@@ -34,14 +34,14 @@ import { dispatchOperatorAction } from "../operator-actions.js";
|
|
|
34
34
|
import { makeHumanGateCard, } from "./human-gate-card.js";
|
|
35
35
|
import { ContractApplyReceiptStore } from "./contract-apply-receipt-store.js";
|
|
36
36
|
import { projectTaskContext } from "./context-panel.js";
|
|
37
|
-
import { deriveChatSessionTelemetry } from "./session-stats.js";
|
|
37
|
+
import { deriveChatSessionTelemetry, deriveChatTurnTelemetry } from "./session-stats.js";
|
|
38
38
|
import { contractApplyPayloadHash, issueHumanGateToken, verifyHumanGateToken, } from "../human-gate-token.js";
|
|
39
39
|
import { sendJson } from "../routes.js";
|
|
40
40
|
import { openSseResponse, writeSseEvent } from "../operation-sse.js";
|
|
41
41
|
import { buildTodoCompactionInstructions, projectCurrentTodos } from "./todos.js";
|
|
42
42
|
import { buildGoalCompactionInstructions, buildGoalContinuationContext, } from "./goals.js";
|
|
43
43
|
import { classifyGoalRoundAdmission, } from "./goal-round-driver.js";
|
|
44
|
-
import { isTerminalOperationState } from "
|
|
44
|
+
import { isTerminalOperationState } from "../../../infrastructure/console/operation-store.js";
|
|
45
45
|
/**
|
|
46
46
|
* Reattach the durable event-ring order to session-store rows. The session
|
|
47
47
|
* store remains the content authority; the ring only supplies chronology.
|
|
@@ -99,8 +99,16 @@ export function projectStoredMessagesWithEventOrder(messages, events) {
|
|
|
99
99
|
}
|
|
100
100
|
return {
|
|
101
101
|
...message,
|
|
102
|
-
...(start
|
|
103
|
-
|
|
102
|
+
...(start
|
|
103
|
+
? {
|
|
104
|
+
eventSeq: start.seq,
|
|
105
|
+
turnId: start.turnId,
|
|
106
|
+
startedAt: start.at,
|
|
107
|
+
}
|
|
108
|
+
: {}),
|
|
109
|
+
...(finish
|
|
110
|
+
? { finishedSeq: finish.seq, finishedAt: finish.at }
|
|
111
|
+
: {}),
|
|
104
112
|
};
|
|
105
113
|
});
|
|
106
114
|
}
|
|
@@ -828,6 +836,7 @@ export async function handleGetChatSession(_req, res, deps, sessionId) {
|
|
|
828
836
|
hasBash: true,
|
|
829
837
|
sessionStats: telemetry.stats,
|
|
830
838
|
usage: telemetry.usage,
|
|
839
|
+
turnTelemetry: deriveChatTurnTelemetry(snapshot),
|
|
831
840
|
contextPressure: typeof deps.runtime.getContextPressureTelemetry === "function"
|
|
832
841
|
? deps.runtime.getContextPressureTelemetry(sessionId)
|
|
833
842
|
: undefined,
|
|
@@ -296,13 +296,6 @@ function operationIdFromArgs(args) {
|
|
|
296
296
|
const operationId = record?.operationId;
|
|
297
297
|
return typeof operationId === "string" && operationId ? operationId : undefined;
|
|
298
298
|
}
|
|
299
|
-
function maxWaitSeconds(args) {
|
|
300
|
-
const record = parseJsonRecord(args);
|
|
301
|
-
const raw = record?.maxWaitMs;
|
|
302
|
-
if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0)
|
|
303
|
-
return undefined;
|
|
304
|
-
return Math.max(1, Math.round(raw / 1000));
|
|
305
|
-
}
|
|
306
299
|
function activityRefForTool(tool) {
|
|
307
300
|
// Plan A (2026-08-16): server backfills operationId on the persisted tool
|
|
308
301
|
// entry (and live tool_result frames carry it in the result payload), so
|
|
@@ -313,6 +306,17 @@ function activityRefForTool(tool) {
|
|
|
313
306
|
operationIdFromArgs(tool.resultText);
|
|
314
307
|
return operationId ? `operation:${operationId}` : `tool:${tool.id}`;
|
|
315
308
|
}
|
|
309
|
+
export function dagProgressActivityForTool(tool) {
|
|
310
|
+
if (tool.toolName !== "operationWait")
|
|
311
|
+
return undefined;
|
|
312
|
+
const activityRef = activityRefForTool(tool);
|
|
313
|
+
if (!activityRef.startsWith("operation:"))
|
|
314
|
+
return undefined;
|
|
315
|
+
return {
|
|
316
|
+
id: `dag-progress:${activityRef}`,
|
|
317
|
+
activityRef,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
316
320
|
function semanticKindForStatus(status) {
|
|
317
321
|
if (status === "running")
|
|
318
322
|
return "progress";
|
|
@@ -377,14 +381,11 @@ function nodeActivityFromMessages(messages, id, activityRef) {
|
|
|
377
381
|
function operationWaitActivity(tool) {
|
|
378
382
|
const activityRef = activityRefForTool(tool);
|
|
379
383
|
const id = `activity:${tool.id}`;
|
|
380
|
-
const seconds = maxWaitSeconds(tool.args);
|
|
381
384
|
if (tool.status === "running") {
|
|
382
385
|
return {
|
|
383
386
|
id,
|
|
384
387
|
kind: "progress",
|
|
385
|
-
title:
|
|
386
|
-
? `正在等待新的执行进展,最长等待时间 ${seconds} 秒`
|
|
387
|
-
: "正在等待新的执行进展",
|
|
388
|
+
title: "正在等待新的执行进展",
|
|
388
389
|
activityRef,
|
|
389
390
|
};
|
|
390
391
|
}
|
|
@@ -156,6 +156,102 @@ export function deriveChatSessionTelemetry(events) {
|
|
|
156
156
|
export function billedInputTokens(usage) {
|
|
157
157
|
return usage.inputTokens + usage.cacheReadTokens + usage.cacheWriteTokens;
|
|
158
158
|
}
|
|
159
|
+
export function deriveChatTurnTelemetry(events) {
|
|
160
|
+
const byTurn = new Map();
|
|
161
|
+
const turnOf = (turnId) => {
|
|
162
|
+
let entry = byTurn.get(turnId);
|
|
163
|
+
if (!entry) {
|
|
164
|
+
entry = {
|
|
165
|
+
turnId,
|
|
166
|
+
steps: 0,
|
|
167
|
+
llmMs: 0,
|
|
168
|
+
toolMs: 0,
|
|
169
|
+
toolCalls: 0,
|
|
170
|
+
samples: [],
|
|
171
|
+
};
|
|
172
|
+
byTurn.set(turnId, entry);
|
|
173
|
+
}
|
|
174
|
+
return entry;
|
|
175
|
+
};
|
|
176
|
+
const toolStarts = new Map();
|
|
177
|
+
for (const event of events) {
|
|
178
|
+
const at = eventTime(event);
|
|
179
|
+
const turn = turnOf(event.turnId);
|
|
180
|
+
if (event.kind === "usage") {
|
|
181
|
+
const sample = usageSample(event.data);
|
|
182
|
+
if (sample)
|
|
183
|
+
turn.samples.push(sample);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (event.kind === "user_message") {
|
|
187
|
+
if (turn.startedAt === undefined && at !== undefined)
|
|
188
|
+
turn.startedAt = at;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (event.kind === "agent_start") {
|
|
192
|
+
if (at !== undefined)
|
|
193
|
+
turn.stepStart = at;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (event.kind === "tool_call") {
|
|
197
|
+
turn.toolCalls += 1;
|
|
198
|
+
const toolCallId = event.data.toolCallId;
|
|
199
|
+
if (typeof toolCallId === "string" && toolCallId && at !== undefined) {
|
|
200
|
+
toolStarts.set(`${event.turnId}\u0000${toolCallId}`, at);
|
|
201
|
+
}
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (event.kind === "tool_result") {
|
|
205
|
+
const toolCallId = event.data.toolCallId;
|
|
206
|
+
if (typeof toolCallId === "string" && toolCallId && at !== undefined) {
|
|
207
|
+
const key = `${event.turnId}\u0000${toolCallId}`;
|
|
208
|
+
const startedAt = toolStarts.get(key);
|
|
209
|
+
if (startedAt !== undefined && at >= startedAt) {
|
|
210
|
+
turn.toolMs += at - startedAt;
|
|
211
|
+
}
|
|
212
|
+
toolStarts.delete(key);
|
|
213
|
+
// Next assistant step within the same turn starts after this tool.
|
|
214
|
+
turn.stepStart = at;
|
|
215
|
+
}
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (event.kind !== "message_end")
|
|
219
|
+
continue;
|
|
220
|
+
turn.steps += 1;
|
|
221
|
+
const recorded = stepTiming(event.data);
|
|
222
|
+
if (recorded?.llmMs !== undefined)
|
|
223
|
+
turn.llmMs += recorded.llmMs;
|
|
224
|
+
else if (at !== undefined &&
|
|
225
|
+
turn.stepStart !== undefined &&
|
|
226
|
+
at >= turn.stepStart) {
|
|
227
|
+
turn.llmMs += at - turn.stepStart;
|
|
228
|
+
}
|
|
229
|
+
if (recorded?.ttftMs !== undefined) {
|
|
230
|
+
turn.ttftMs = (turn.ttftMs ?? 0) + recorded.ttftMs;
|
|
231
|
+
}
|
|
232
|
+
if (recorded?.decodeMs !== undefined &&
|
|
233
|
+
recorded.decodeMs > 0 &&
|
|
234
|
+
recorded.outputTokens !== undefined) {
|
|
235
|
+
turn.decodeMs = (turn.decodeMs ?? 0) + recorded.decodeMs;
|
|
236
|
+
turn.decodeTokens = (turn.decodeTokens ?? 0) + recorded.outputTokens;
|
|
237
|
+
}
|
|
238
|
+
turn.stepStart = undefined;
|
|
239
|
+
}
|
|
240
|
+
return [...byTurn.values()].map((entry) => ({
|
|
241
|
+
turnId: entry.turnId,
|
|
242
|
+
steps: entry.steps,
|
|
243
|
+
llmMs: entry.llmMs,
|
|
244
|
+
toolMs: entry.toolMs,
|
|
245
|
+
toolCalls: entry.toolCalls,
|
|
246
|
+
...(entry.ttftMs !== undefined ? { ttftMs: entry.ttftMs } : {}),
|
|
247
|
+
...(entry.decodeMs !== undefined ? { decodeMs: entry.decodeMs } : {}),
|
|
248
|
+
...(entry.decodeTokens !== undefined
|
|
249
|
+
? { decodeTokens: entry.decodeTokens }
|
|
250
|
+
: {}),
|
|
251
|
+
usage: aggregateUsage(entry.samples),
|
|
252
|
+
...(entry.startedAt !== undefined ? { startedAt: entry.startedAt } : {}),
|
|
253
|
+
}));
|
|
254
|
+
}
|
|
159
255
|
export function cacheHitPercent(usage) {
|
|
160
256
|
const billed = billedInputTokens(usage);
|
|
161
257
|
return billed > 0 ? Math.round((usage.cacheReadTokens / billed) * 100) : null;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import path from "node:path";
|
|
14
14
|
import { readdir, rm } from "node:fs/promises";
|
|
15
|
-
import { readJsonIfExists, writeSecureJson, } from "
|
|
15
|
+
import { readJsonIfExists, writeSecureJson, } from "../../../infrastructure/console/app-data.js";
|
|
16
16
|
import { dispatchOperatorAction } from "../operator-actions.js";
|
|
17
17
|
import { authorizeOperatorChatTool } from "./tools.js";
|
|
18
18
|
import { projectOperationForChat } from "./chat-event-store.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Turn grouping for Operator Chat inline process UX (pi-web ProcessDetails mind).
|
|
3
3
|
*/
|
|
4
4
|
import { getDisplayableAssistantBlocks, joinAssistantText, parseAssistantContent, splitFinalAssistantBlocks, } from "./assistant-content.js";
|
|
5
|
-
import { semanticActivityForTool, } from "./semantic-activity.js";
|
|
5
|
+
import { dagProgressActivityForTool, semanticActivityForTool, } from "./semantic-activity.js";
|
|
6
6
|
function emptyGroup(key) {
|
|
7
7
|
return {
|
|
8
8
|
key,
|
|
@@ -72,14 +72,22 @@ export function hydrateSessionThread(raw) {
|
|
|
72
72
|
turnId = item.turnId;
|
|
73
73
|
if (!turnId)
|
|
74
74
|
turnId = `restored-tool-${item.id}`;
|
|
75
|
+
// Prefer event-ring timestamps (tool_call at → tool_result at) so
|
|
76
|
+
// refreshed sessions keep real elapsed durations instead of 0ms.
|
|
77
|
+
const startedAtMs = item.startedAt ? Date.parse(item.startedAt) : NaN;
|
|
78
|
+
const finishedAtMs = item.finishedAt ? Date.parse(item.finishedAt) : NaN;
|
|
75
79
|
const entry = {
|
|
76
80
|
id: item.toolCallId || item.id,
|
|
77
81
|
toolName: item.toolName || "tool",
|
|
78
82
|
status: item.isError === true ? "error" : "ok",
|
|
79
83
|
resultText: item.text,
|
|
80
84
|
result: item.text,
|
|
81
|
-
createdAt
|
|
82
|
-
|
|
85
|
+
createdAt: Number.isFinite(startedAtMs)
|
|
86
|
+
? startedAtMs
|
|
87
|
+
: createdAt,
|
|
88
|
+
finishedAt: Number.isFinite(finishedAtMs)
|
|
89
|
+
? finishedAtMs
|
|
90
|
+
: createdAt,
|
|
83
91
|
turnId: item.turnId ?? turnId,
|
|
84
92
|
...(item.eventSeq === undefined ? {} : { eventSeq: item.eventSeq }),
|
|
85
93
|
...(item.finishedSeq === undefined
|
|
@@ -118,6 +126,11 @@ function flushToolBuffer(processItems, buffer) {
|
|
|
118
126
|
return;
|
|
119
127
|
const sorted = sortToolsStable(buffer);
|
|
120
128
|
for (const tool of sorted) {
|
|
129
|
+
const dagProgress = dagProgressActivityForTool(tool);
|
|
130
|
+
if (dagProgress) {
|
|
131
|
+
processItems.push({ kind: "dag-progress", progress: dagProgress });
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
121
134
|
const activity = semanticActivityForTool(tool);
|
|
122
135
|
if (activity) {
|
|
123
136
|
processItems.push({ kind: "activity", activity });
|
|
@@ -127,6 +140,17 @@ function flushToolBuffer(processItems, buffer) {
|
|
|
127
140
|
}
|
|
128
141
|
}
|
|
129
142
|
}
|
|
143
|
+
function collapseDagProgressItems(items) {
|
|
144
|
+
const seen = new Set();
|
|
145
|
+
return items.filter((item) => {
|
|
146
|
+
if (item.kind !== "dag-progress")
|
|
147
|
+
return true;
|
|
148
|
+
if (seen.has(item.progress.activityRef))
|
|
149
|
+
return false;
|
|
150
|
+
seen.add(item.progress.activityRef);
|
|
151
|
+
return true;
|
|
152
|
+
});
|
|
153
|
+
}
|
|
130
154
|
function emitProcessBlocks(blocks, group, processItems, usedToolIds) {
|
|
131
155
|
let buffer = [];
|
|
132
156
|
for (const block of blocks) {
|
|
@@ -201,7 +225,7 @@ function fillProcessDetails(group) {
|
|
|
201
225
|
const orphans = group.tools.filter((tool) => !usedToolIds.has(tool.id));
|
|
202
226
|
if (orphans.length > 0)
|
|
203
227
|
flushToolBuffer(processItems, orphans);
|
|
204
|
-
group.processItems = processItems;
|
|
228
|
+
group.processItems = collapseDagProgressItems(processItems);
|
|
205
229
|
if (!finalAssistant)
|
|
206
230
|
return;
|
|
207
231
|
if (blocks.length === 0) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { readJsonIfExists, writeSecureJson } from "
|
|
3
|
+
import { readJsonIfExists, writeSecureJson, } from "../../../infrastructure/console/app-data.js";
|
|
4
4
|
function questionFile(root, sessionId) {
|
|
5
5
|
const safe = sessionId.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 180);
|
|
6
6
|
return path.join(root, `${safe}.json`);
|
|
@@ -4,7 +4,7 @@ import { createNpmUpdateClient } from "../../shared/update/npm-client.js";
|
|
|
4
4
|
import { acquireUpdateLock, updateLockPath } from "../../shared/update/state.js";
|
|
5
5
|
import { readInitRuntimeActivity } from "../observability/init-runtime-activity.js";
|
|
6
6
|
import { performConsoleUpdateAndInit, } from "./console-update-and-init.js";
|
|
7
|
-
import { TERMINAL_OPERATION_STATES } from "
|
|
7
|
+
import { TERMINAL_OPERATION_STATES } from "../../infrastructure/console/operation-store.js";
|
|
8
8
|
export function createConsoleUpdateExecutor(input) {
|
|
9
9
|
return async (channel) => {
|
|
10
10
|
const currentVersion = readPackageVersion(input.packageRoot);
|