@tea-agent/loop-agent 0.42.0-next.9 → 0.42.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 +111 -45
- package/dist/application/dag/run-dag.js +8 -2
- package/dist/application/evaluation/budget.js +19 -1
- package/dist/application/task-lifecycle/advance.js +26 -8
- package/dist/application/task-lifecycle/observe.js +43 -29
- package/dist/application/task-lifecycle/plan-transitions.js +5 -4
- package/dist/build-stamp.json +3 -3
- package/dist/cli/program.js +1 -1
- package/dist/commands/dag-rerun-task.js +2 -0
- package/dist/commands/task-source-prepare.js +3 -1
- package/dist/executors/dag-pi-executor.js +2584 -600
- package/dist/executors/pi-executor.js +22 -1
- package/dist/executors/pi-extension-resolver.js +14 -2
- package/dist/executors/pi-sdk-executor.js +140 -39
- package/dist/executors/shell-executor.js +135 -55
- package/dist/shared/dag-failure-category.js +6 -0
- package/dist/shared/frontend-execution-policy.js +23 -0
- package/dist/task/config-types.js +4 -0
- package/dist/task/contract/apply.js +36 -2
- package/dist/task/source-prepare/ledger-reconciliation.js +2 -2
- package/dist/task/source-prepare/ledger-review.js +6 -9
- package/dist/task/source-prepare/parse-intent.js +7 -0
- package/dist/task/source-prepare/semantic-intake.js +16 -26
- package/dist/task/source-prepare/source-fidelity-pi.js +28 -9
- package/dist/task/source-references.js +48 -23
- package/dist/worker/console/chat/assistant-content.js +23 -2
- package/dist/worker/console/chat/browser-policy.js +143 -0
- package/dist/worker/console/chat/browser-routes.js +148 -0
- package/dist/worker/console/chat/chat-event-store.js +4 -2
- package/dist/worker/console/chat/explore-tools.js +13 -0
- package/dist/worker/console/chat/pi-runtime.js +173 -94
- package/dist/worker/console/chat/resource-loader.js +4 -1
- package/dist/worker/console/chat/routes.js +208 -66
- package/dist/worker/console/chat/scm-routes.js +217 -0
- package/dist/worker/console/chat/scm-service.js +283 -0
- package/dist/worker/console/chat/scm-tools.js +111 -0
- package/dist/worker/console/chat/sdd-data-alignment.js +78 -11
- package/dist/worker/console/chat/session-catalog.js +32 -0
- package/dist/worker/console/chat/session-mode-view.js +48 -0
- package/dist/worker/console/chat/session-mode.js +218 -0
- package/dist/worker/console/chat/session-store.js +27 -7
- package/dist/worker/console/chat/shortcuts.js +6 -0
- package/dist/worker/console/chat/subagents/agent-tool.js +62 -0
- package/dist/worker/console/chat/subagents/explore-agent.js +169 -0
- package/dist/worker/console/chat/subagents/index.js +5 -0
- package/dist/worker/console/chat/subagents/orchestrator.js +273 -0
- package/dist/worker/console/chat/subagents/tool-policy.js +53 -0
- package/dist/worker/console/chat/subagents/types.js +13 -0
- package/dist/worker/console/chat/terminal-routes.js +216 -0
- package/dist/worker/console/chat/terminal-sessions.js +284 -0
- package/dist/worker/console/chat/terminal-tools.js +199 -0
- package/dist/worker/console/chat/tool-preview.js +21 -0
- package/dist/worker/console/chat/tools.js +13 -1
- package/dist/worker/console/chat/turn-process.js +1 -0
- package/dist/worker/console/interview/tools.js +1 -0
- package/dist/worker/console/server.js +2 -28
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C6n9_m0P.js → abnfDiagram-N423BO3Z-C9eI7nEo.js} +1 -1
- package/dist/worker/console/static/assets/{arc-DQh-IfZ1.js → arc-VJWsxWhB.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-54NnrwUC.js → architectureDiagram-T3A2C74G-BGcyiMSo.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-pivRALGK.js → blockDiagram-VBNYF7ZC-BScnFwyi.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BR7OV2NJ.js → c4Diagram-5PPSVZJV-Bl9_BsLi.js} +1 -1
- package/dist/worker/console/static/assets/channel-B6sQYuOE.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-B1Aq6BcK.js → chunk-2GRJ4B5K-F1uKxiUt.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CbdU0rjo.js → chunk-2Q5K7J3B-rSRMynVu.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-Dqi2GJeD.js → chunk-5RXB4S5H-DAsJm1WD.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BYn1Hu4R.js → chunk-5VM5RSS4-DQIdVI0a.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DRLjDL0k.js → chunk-6Q2QTUOP-4A_8rJ-Q.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CY9Xx2jV.js → chunk-GF5L2VYU-BHnT-vjh.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BNCZs7_z.js → chunk-JWPE2WC7-Rq7QKBkn.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DZ8AStLL.js → chunk-KBJHAD2P-BXh-AI2u.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DsxjYrzz.js → chunk-RYQCIY6F-BblcLy8m.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-Ddx1KC1l.js → chunk-XXDRQBXY-zHZmVnB6.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-Z6s5QoeI.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-Z6s5QoeI.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-W9TveCnK.js → cose-bilkent-JH36ORCC-Cmwz0Wi4.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-l9j_ztZH.js → cynefin-VYW2F7L2-Dq76MHQU.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-BMJMKi4G.js → cynefinDiagram-MW4NZA55-zPahV1fM.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-Bb4mG9pH.js → dagre-VZM6K2ZE-DQJ3xPc_.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-BMgL_Qv0.js → diagram-7IWD3JNH-BwX7u6fv.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-Bvo2T4OQ.js → diagram-B4RE2ZJO-CodnDCco.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-_5kWRN9c.js → diagram-LBJQPF4R-gAjtWkxG.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DqdMrltM.js → diagram-Q27KOJAE-CGCqz0cS.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-CDDYsNkp.js → diagram-UB23O5K3-RHwYEywd.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-c4nfnZUV.js → ebnfDiagram-BXEA7PRR-B6seb_p_.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DnkUcNMs.js → erDiagram-JOGREHBK-CmwCKYe8.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-Dz0KGLZE.js → flowDiagram-UKHOOZJN-BfNsaZ0V.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Cj1t1uka.js → ganttDiagram-PKOTCBZU-zmYgi_Z3.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-tp2FrBHd.js → gitGraphDiagram-DS77QQ5N-BDEzzSKF.js} +1 -1
- package/dist/worker/console/static/assets/index-DgenUAfc.js +468 -0
- package/dist/worker/console/static/assets/index-aF4u-Y__.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DQwJS8DH.js → infoDiagram-6WML65LV-DeSz8l42.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-eimCQWD4.js → ishikawaDiagram-WSZJBQD7-B1LV29aH.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-Dd9Gbwgv.js → journeyDiagram-NVQOT4AX-CCw4W2oU.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Qve3cyft.js → kanban-definition-27J2QSJJ-BozaMoRJ.js} +1 -1
- package/dist/worker/console/static/assets/{linear-UXKSe36Z.js → linear-G1JR40SX.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-CWhj4JXN.js → mermaid.core-CCgPF0oA.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-yTcwf4SJ.js → mindmap-definition-FAOFIHXS-CEqnCHnD.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-_7qToaZP.js → pegDiagram-VL7TDLO6-DpmQPKuI.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-CXmrKmDm.js → pieDiagram-7S7Q4E2Y-BP501AxR.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-hMmrJyaS.js → quadrantDiagram-CIZ2JOQS-D1dBhl_A.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BXw8tCBe.js → railroadDiagram-AXF67PYL-DgZDS5pY.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BmjgnLZl.js → requirementDiagram-LRYGKXZP-BzB3pyIq.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Bj77SPpN.js → sankeyDiagram-W5VNT64P-B9ZprFFP.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-B2FDVysL.js → sequenceDiagram-SI44F4Z6-CC2-_XrA.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-UChNY9ZZ.js → sizeCapture-X5ZJPWSS-UVtAUqgB.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-wbAEkbd7.js → stateDiagram-OKZ733FA-CWcS5JYG.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BooX8u1Q.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DCEkU8HR.js → swimlanes-SLNWSIFB-C4p-dn06.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D64_eqqE.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-BGp7H06U.js → timeline-definition-Z64GVDOM-Dnz52OHX.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DsCIQuWR.js → vennDiagram-T6HMQDX7-CzTE0Nfu.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-cRZLP4Xe.js → wardleyDiagram-T6FBY63Y-NAR9cjQQ.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-CP0xLR9Y.js → xychartDiagram-ELKLHX3M-DVMk8413.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/chat-view-types.js +1 -1
- package/dist/worker/console/static-src/operator-chat/chat-link.js +94 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +142 -7
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +44 -0
- package/dist/worker/console/static-src/operator-chat/process-label.js +41 -0
- package/dist/worker/console/static-src/operator-chat/tools-catalog.js +21 -2
- package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +13 -0
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +2 -0
- package/dist/worker/console/static-src/operator-chat/use-searchable-hidden.js +51 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +33 -18
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +48 -16
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +170 -7
- package/dist/worker/console/static-src/operator-chat/useComposer.js +13 -7
- package/dist/worker/console/static-src/operator-chat/user-turn-anchor-equality.js +21 -0
- package/dist/worker/console/static-src/shell/workspace-route.js +4 -0
- package/dist/worker/console/workspace-context.js +15 -1
- package/dist/worker/observe/node-transparency.js +81 -72
- package/dist/worker/observe/routes.js +20 -1
- package/dist/worker/observe/static/constants.js +22 -22
- package/dist/worker/observe/static/dag-context-reason-labels.js +19 -0
- package/dist/worker/observe/static/dag-history-labels.js +1 -0
- package/dist/worker/observe/static/dag-inspector-humanize.d.ts +16 -0
- package/dist/worker/observe/static/dag-inspector-humanize.js +342 -0
- package/dist/worker/observe/static/dag-node-purpose.js +10 -10
- package/dist/worker/observe/static/dom.js +20 -1
- package/dist/worker/observe/static/format-pool.d.ts +2 -0
- package/dist/worker/observe/static/format-pool.js +6 -0
- package/dist/worker/observe/static/format.js +7 -0
- package/dist/worker/observe/static/index.html +4 -4
- package/dist/worker/observe/static/inspect-workspace.js +34 -7
- package/dist/worker/observe/static/inspector-submission.js +32 -0
- package/dist/worker/observe/static/kpi.js +1 -0
- package/dist/worker/observe/static/prompt-restart-candidates.js +4 -2
- package/dist/worker/observe/static/relations.js +7 -5
- package/dist/worker/observe/static/router.js +13 -0
- package/dist/worker/observe/static/run-processing.js +2 -0
- package/dist/worker/observe/static/shell-chrome.js +36 -3
- package/dist/worker/observe/static/state.js +35 -2
- package/dist/worker/observe/static/styles.css +431 -39
- package/dist/worker/observe/static/task-failure-labels.d.ts +4 -0
- package/dist/worker/observe/static/task-failure-labels.js +67 -0
- package/dist/worker/observe/static/task-history.js +12 -0
- package/dist/worker/observe/static/views/batch.js +6 -13
- package/dist/worker/observe/static/views/dag-graph.js +51 -4
- package/dist/worker/observe/static/views/dag-inspector.js +1069 -426
- package/dist/worker/observe/static/views/dag-trajectory.js +3 -0
- package/dist/worker/observe/static/views/dag.d.ts +6 -0
- package/dist/worker/observe/static/views/dag.js +64 -22
- package/dist/worker/observe/static/views/dags.js +2 -0
- package/dist/worker/observe/static/views/dashboard.js +21 -12
- package/dist/worker/observe/static/views/failures.js +21 -11
- package/dist/worker/observe/static/views/feature.js +11 -29
- package/dist/worker/observe/static/views/pool.js +37 -28
- package/dist/worker/observe/static/views/run.js +48 -5
- package/dist/worker/observe/static/views/session-timeline.js +194 -243
- package/dist/worker/observe/static/views/task.js +81 -62
- package/dist/workflows/dag/backend-test-plan-protocol.js +104 -0
- package/dist/workflows/dag/budget-enforcement.js +53 -3
- package/dist/workflows/dag/dag-retry-schema.js +3 -0
- package/dist/workflows/dag/frontend-capacity.js +9 -0
- package/dist/workflows/dag/frontend-contract-facts.js +130 -0
- package/dist/workflows/dag/frontend-design-policy.js +103 -17
- package/dist/workflows/dag/frontend-durable-tools.js +193 -0
- package/dist/workflows/dag/frontend-execution-groups.js +24 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +423 -41
- package/dist/workflows/dag/frontend-input-projection.js +76 -0
- package/dist/workflows/dag/frontend-plan-completeness.js +186 -0
- package/dist/workflows/dag/frontend-plan-recovery-policy.js +18 -0
- package/dist/workflows/dag/frontend-plan-render.js +21 -3
- package/dist/workflows/dag/frontend-prewrite-gate.js +1 -1
- package/dist/workflows/dag/frontend-recovery-controller.js +32 -8
- package/dist/workflows/dag/frontend-recovery-lineage.js +13 -0
- package/dist/workflows/dag/frontend-recovery-plan.js +4 -1
- package/dist/workflows/dag/frontend-recovery-run.js +146 -16
- package/dist/workflows/dag/frontend-review-scopes.js +139 -0
- package/dist/workflows/dag/frontend-risk.js +2 -0
- package/dist/workflows/dag/frontend-session-budget.js +249 -0
- package/dist/workflows/dag/frontend-shadow-dual-write.js +37 -3
- package/dist/workflows/dag/frontend-shape-facts.js +12 -2
- package/dist/workflows/dag/frontend-shape.js +46 -7
- package/dist/workflows/dag/frontend-test-execution-evidence.js +49 -0
- package/dist/workflows/dag/frontend-typed-event-store.js +14 -0
- package/dist/workflows/dag/frontend-verification-trace.js +38 -4
- package/dist/workflows/dag/frontend-writer-admission.js +2 -2
- package/dist/workflows/dag/init-hybrid.js +70 -35
- package/dist/workflows/dag/node-execution.js +225 -226
- package/dist/workflows/dag/prompt.js +4 -0
- package/dist/workflows/dag/recovery-lease.js +106 -16
- package/dist/workflows/dag/rerun-feedback.js +1 -0
- package/dist/workflows/dag/rerun-plan.js +96 -4
- package/dist/workflows/dag/rerun-run.js +28 -6
- package/dist/workflows/dag/rerun-task.js +221 -18
- package/dist/workflows/dag/retry-policy.js +27 -10
- package/dist/workflows/dag/runner-exit-diagnostics.js +125 -0
- package/dist/workflows/dag/runner.js +246 -19
- package/dist/workflows/dag/structured-output-repair.js +4 -1
- package/dist/workflows/dag/types.js +10 -3
- package/dist/workflows/dag/validate.js +10 -8
- package/dist/workflows/dag/workspace-checkpoint.js +66 -0
- package/docs/operations/README.md +2 -0
- package/docs/templates/agent-dag.schema.json +2 -2
- package/docs/templates/backend-test-dag.json +6 -4
- package/docs/templates/frontend-design-contract.md +4 -4
- package/docs/templates/frontend-implementation-contract.schema.json +68 -4
- package/docs/templates/frontend-implementation-dag.json +5 -5
- package/harness.json +1 -1
- package/package.json +8 -6
- package/skills/frontend-contract/SKILL.md +2 -1
- package/skills/frontend-contract/references/contract-protocol.md +19 -3
- package/skills/frontend-design-review/SKILL.md +12 -11
- package/skills/frontend-plan/SKILL.md +22 -2
- package/skills/frontend-plan/references/decision-contract.md +114 -5
- package/skills/frontend-plan/references/design-decisions.md +32 -0
- package/skills/frontend-review/SKILL.md +10 -11
- package/skills/frontend-scout/references/scout-evidence.md +4 -0
- package/dist/worker/console/static/assets/channel-DsZxrgqe.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-CuToPeGV.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-CuToPeGV.js +0 -1
- package/dist/worker/console/static/assets/index-D9Sc0f0y.js +0 -449
- package/dist/worker/console/static/assets/index-DDQc5a50.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-yPoT19ft.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-VWdarchG.js +0 -8
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { collectFrontendUsage, createFrontendReadObservation, observeFrontendAttempt } from "../workflows/dag/frontend-session-budget.js";
|
|
1
2
|
import { spawn, spawnSync } from "node:child_process";
|
|
2
3
|
import { existsSync } from "node:fs";
|
|
3
4
|
import { homedir } from "node:os";
|
|
@@ -453,6 +454,9 @@ export function extractPiEventStopReason(event) {
|
|
|
453
454
|
return undefined;
|
|
454
455
|
}
|
|
455
456
|
export class PiJsonlStreamCollector {
|
|
457
|
+
frontendReads = createFrontendReadObservation();
|
|
458
|
+
frontendUsageEvents = [];
|
|
459
|
+
frontendObservation() { return { readObservation: this.frontendReads.snapshot(), usageObservation: collectFrontendUsage(this.frontendUsageEvents) }; }
|
|
456
460
|
lineBuffer = "";
|
|
457
461
|
discardUntilNewline = false;
|
|
458
462
|
assistantText = "";
|
|
@@ -518,6 +522,13 @@ export class PiJsonlStreamCollector {
|
|
|
518
522
|
}
|
|
519
523
|
}
|
|
520
524
|
consumeEvent(event) {
|
|
525
|
+
try {
|
|
526
|
+
this.frontendReads.observe(event);
|
|
527
|
+
const message = isRecord(event.message) ? event.message : undefined;
|
|
528
|
+
if (event.usage || message?.usage || event.tokenUsage)
|
|
529
|
+
this.frontendUsageEvents.push({ responseId: event.responseId, messageId: event.messageId, usage: event.usage, tokenUsage: event.tokenUsage, message: message ? { role: message.role, id: message.id, responseId: message.responseId, usage: message.usage } : undefined });
|
|
530
|
+
}
|
|
531
|
+
catch { /* observation only */ }
|
|
521
532
|
const stopReason = extractPiEventStopReason(event);
|
|
522
533
|
if (stopReason === "length" || !this.stopReason) {
|
|
523
534
|
this.stopReason = stopReason ?? this.stopReason;
|
|
@@ -696,6 +707,8 @@ function shouldFallbackSdkToCli(sdkResult, validationIssues, options) {
|
|
|
696
707
|
return true;
|
|
697
708
|
if (!sdkResult.ok &&
|
|
698
709
|
(sdkResult.failureCategory === "auth" ||
|
|
710
|
+
sdkResult.failureCategory === "output-limit" ||
|
|
711
|
+
sdkResult.failureCategory === "cancelled" ||
|
|
699
712
|
sdkResult.failureCategory === "timeout" ||
|
|
700
713
|
sdkResult.failureCategory === "termination-unconfirmed")) {
|
|
701
714
|
return false;
|
|
@@ -730,6 +743,8 @@ function writerPolicyFailureResult(options, message, extras) {
|
|
|
730
743
|
export async function executePiStep(options) {
|
|
731
744
|
const backendMode = resolvePiBackend();
|
|
732
745
|
const writerRequiresSdk = options.writerToolPolicy?.requireSdk === true;
|
|
746
|
+
if (options.reserveProviderRequest && backendMode === "cli-only")
|
|
747
|
+
return { ...writerPolicyFailureResult(options, "FRONTEND_PROVIDER_BUDGET_UNSUPPORTED: actual request admission requires SDK", { sdkAttempted: false }), failureCategory: "budget_breach" };
|
|
733
748
|
if (backendMode === "cli-only") {
|
|
734
749
|
if (writerRequiresSdk) {
|
|
735
750
|
return writerPolicyFailureResult(options, "pi writer tool policy requires SDK backend; CODE_AGENT_PI_BACKEND=cli-only is fail-closed for writers", { sdkAttempted: false, backend: "cli" });
|
|
@@ -745,6 +760,8 @@ export async function executePiStep(options) {
|
|
|
745
760
|
const { checkPiSdkAvailability, executeSingleSdkAttempt, getActivePiSdkReuseScope, } = await import("./pi-sdk-executor.js");
|
|
746
761
|
const sdkCheck = await checkPiSdkAvailability(options.repoRoot);
|
|
747
762
|
if (!sdkCheck.ok) {
|
|
763
|
+
if (options.reserveProviderRequest)
|
|
764
|
+
return { ...writerPolicyFailureResult(options, `FRONTEND_PROVIDER_BUDGET_UNSUPPORTED: ${sdkCheck.detail}`, { sdkAttempted: false }), failureCategory: "budget_breach" };
|
|
748
765
|
if (writerRequiresSdk) {
|
|
749
766
|
return writerPolicyFailureResult(options, `pi writer tool policy requires SDK; ${sdkCheck.detail}`, { sdkAttempted: false });
|
|
750
767
|
}
|
|
@@ -773,7 +790,7 @@ export async function executePiStep(options) {
|
|
|
773
790
|
reuseRuntimeActive,
|
|
774
791
|
});
|
|
775
792
|
}
|
|
776
|
-
if (!shouldFallbackSdkToCli(sdkResult, validationIssues, options)) {
|
|
793
|
+
if (options.reserveProviderRequest || !shouldFallbackSdkToCli(sdkResult, validationIssues, options)) {
|
|
777
794
|
const failureCategory = validationIssues.length > 0
|
|
778
795
|
? "invalid-output"
|
|
779
796
|
: sdkResult.failureCategory;
|
|
@@ -798,6 +815,9 @@ export async function executePiStep(options) {
|
|
|
798
815
|
return { ...cliResult, reuseRuntimeActive };
|
|
799
816
|
}
|
|
800
817
|
async function executeSingleCliAttempt(options, modelConfig, promptFilePath) {
|
|
818
|
+
return observeFrontendAttempt({ backend: "cli", model: [modelConfig.provider, modelConfig.model].filter(Boolean).join("/"), observer: options.onAttemptObservation }, () => executeSingleCliAttemptInternal(options, modelConfig, promptFilePath));
|
|
819
|
+
}
|
|
820
|
+
async function executeSingleCliAttemptInternal(options, modelConfig, promptFilePath) {
|
|
801
821
|
const modelDisplay = modelConfig.provider && modelConfig.model
|
|
802
822
|
? `${modelConfig.provider}/${modelConfig.model}`
|
|
803
823
|
: (modelConfig.model ?? "default");
|
|
@@ -900,6 +920,7 @@ async function executeSingleCliAttempt(options, modelConfig, promptFilePath) {
|
|
|
900
920
|
});
|
|
901
921
|
resolve({
|
|
902
922
|
assistantText: collected.assistantText,
|
|
923
|
+
...stdoutCollector.frontendObservation(),
|
|
903
924
|
command: ["pi", ...recordedPiArgs],
|
|
904
925
|
durationMs,
|
|
905
926
|
exitCode: code,
|
|
@@ -62,9 +62,21 @@ function readSettingsPackages(settingsPath) {
|
|
|
62
62
|
return undefined;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Strip an `npm:` prefix and a trailing `@<version>`/`@<dist-tag>` suffix
|
|
67
|
+
* from a settings package spec, e.g. `npm:pi-lens@3.8.72` → `pi-lens`,
|
|
68
|
+
* `npm:@scope/pkg@1.0.0` → `@scope/pkg`. The leading `@` of a scoped
|
|
69
|
+
* package name is preserved (the version separator is the LAST `@` at a
|
|
70
|
+
* positive index). Mirrors the console-side spec parsing semantics so a
|
|
71
|
+
* version-pinned install (e.g. via `pi install npm:pi-lens@3.8.72`) resolves
|
|
72
|
+
* identically in both surfaces.
|
|
73
|
+
*/
|
|
66
74
|
export function packageNameFromSpec(spec) {
|
|
67
|
-
|
|
75
|
+
const base = spec.startsWith("npm:") ? spec.slice(4) : spec;
|
|
76
|
+
const at = base.lastIndexOf("@");
|
|
77
|
+
if (at > 0)
|
|
78
|
+
return base.slice(0, at);
|
|
79
|
+
return base;
|
|
68
80
|
}
|
|
69
81
|
function loadPackageInventories(repoRoot) {
|
|
70
82
|
const agentDir = getPiAgentDir();
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { collectFrontendUsage, createFrontendReadObservation, observeFrontendAttempt } from "../workflows/dag/frontend-session-budget.js";
|
|
2
|
+
import { frontendModelCapabilities, measureFrontendRequestEnvelope } from "../shared/frontend-execution-policy.js";
|
|
1
3
|
import { appendFile, mkdir } from "node:fs/promises";
|
|
2
4
|
import os from "node:os";
|
|
3
5
|
import path from "node:path";
|
|
@@ -7,6 +9,42 @@ import { BoundedTextPreview, classifyPiFailure, createPiJsonlStreamCollector, DE
|
|
|
7
9
|
import { serializeSessionEvent } from "./pi-event-serializer.js";
|
|
8
10
|
import { PI_RECOMMENDED_COMPACTION, PI_RECOMMENDED_RETRY, } from "../shared/pi-retry-settings.js";
|
|
9
11
|
import { createCompactionController, createContextPressureExtension, createSiftBridgeState, inMemoryCompactionSettings, isDagSiftEnabled, parseCompactionPolicy, parseSiftBridgeConfig, SIFT_RETRIEVE_TOOL_NAME, } from "../shared/pi-context-pressure/index.js";
|
|
12
|
+
/** Maximum number of same-session continuations after provider output truncation. */
|
|
13
|
+
export const PI_SDK_OUTPUT_LIMIT_CONTINUE_MAX = 3;
|
|
14
|
+
export const PI_SDK_OUTPUT_LIMIT_CONTINUE_PROMPT = "继续。上一轮因输出长度上限(stopReason=length)截断;当前会话、工具与已完成工作仍保留。只完成尚未完成的部分,不重做已成功的写入或事实提交。";
|
|
15
|
+
/** Wrap the actual stream seam: tool turns, retries and compaction all await it. */
|
|
16
|
+
export async function installPiProviderRequestBudget(session, reserve, onFailure, capacity) {
|
|
17
|
+
const agent = session.agent;
|
|
18
|
+
const original = agent?.streamFunction;
|
|
19
|
+
if (!agent || typeof original !== "function")
|
|
20
|
+
throw Error("FRONTEND_PROVIDER_BUDGET_UNSUPPORTED: SDK actual request stream unavailable");
|
|
21
|
+
const { createAssistantMessageEventStream } = await import("@earendil-works/pi-ai");
|
|
22
|
+
agent.streamFunction = async (...args) => {
|
|
23
|
+
try {
|
|
24
|
+
if (args[2]?.signal?.aborted)
|
|
25
|
+
throw Error("FRONTEND_PROVIDER_REQUEST_ABORTED");
|
|
26
|
+
if (capacity) {
|
|
27
|
+
const measurement = measureFrontendRequestEnvelope(args[1], args[0], capacity.policy);
|
|
28
|
+
capacity.observe(measurement);
|
|
29
|
+
if (measurement.exceedsEstimate)
|
|
30
|
+
throw Error(`FRONTEND_CONTEXT_ESTIMATE_EXCEEDED: estimated=${measurement.estimatedTokens} available=${measurement.availableInputTokens}; estimator=${measurement.estimatorVersion}; registry capability is not a measured gateway limit`);
|
|
31
|
+
}
|
|
32
|
+
await reserve();
|
|
33
|
+
if (args[2]?.signal?.aborted)
|
|
34
|
+
throw Error("FRONTEND_PROVIDER_REQUEST_ABORTED");
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
38
|
+
onFailure(message);
|
|
39
|
+
const stream = createAssistantMessageEventStream();
|
|
40
|
+
const model = args[0] ?? {};
|
|
41
|
+
stream.push({ type: "error", reason: "error", error: { role: "assistant", content: [], api: model.api ?? "unknown", provider: model.provider ?? "unknown", model: model.id ?? "unknown", usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } }, stopReason: "error", errorMessage: message, timestamp: Date.now() } });
|
|
42
|
+
stream.end();
|
|
43
|
+
return stream;
|
|
44
|
+
}
|
|
45
|
+
return original.apply(agent, args);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
10
48
|
/** Same-session recovery after a transport stall. Exactly one continue per SDK attempt. */
|
|
11
49
|
export const PI_SDK_STALL_CONTINUE_MAX = 1;
|
|
12
50
|
/**
|
|
@@ -544,6 +582,9 @@ function aggregateSdkTokenUsage(samples) {
|
|
|
544
582
|
* same session; that is in-attempt recovery, not cross-step session reuse.
|
|
545
583
|
*/
|
|
546
584
|
export async function executeSingleSdkAttempt(options) {
|
|
585
|
+
return observeFrontendAttempt({ backend: "sdk", model: [options.modelConfig.provider, options.modelConfig.model].filter(Boolean).join("/"), observer: options.onAttemptObservation }, () => executeSingleSdkAttemptInternal(options));
|
|
586
|
+
}
|
|
587
|
+
async function executeSingleSdkAttemptInternal(options) {
|
|
547
588
|
const modelConfig = options.modelConfig;
|
|
548
589
|
const modelDisplay = modelConfig.provider && modelConfig.model
|
|
549
590
|
? `${modelConfig.provider}/${modelConfig.model}`
|
|
@@ -568,9 +609,16 @@ export async function executeSingleSdkAttempt(options) {
|
|
|
568
609
|
let timedOut = false;
|
|
569
610
|
let terminationConfirmed = true;
|
|
570
611
|
let stderr = "";
|
|
612
|
+
let providerBudgetFailure;
|
|
613
|
+
let capabilitiesObservation = frontendModelCapabilities(undefined);
|
|
614
|
+
const requestEnvelopeObservation = { peakBytes: 0, peakEstimatedTokens: 0, estimatorVersion: "utf8-bytes-div3-v1-estimate" };
|
|
571
615
|
const stdoutPreview = new BoundedTextPreview("stdout");
|
|
572
616
|
const stdoutCollector = createPiJsonlStreamCollector();
|
|
617
|
+
let turnCollector = createPiJsonlStreamCollector();
|
|
618
|
+
let committedTerminalObserved = false;
|
|
573
619
|
const usageSamples = [];
|
|
620
|
+
const observationEvents = [];
|
|
621
|
+
const readObservation = createFrontendReadObservation();
|
|
574
622
|
let observedTurns = 0;
|
|
575
623
|
let contextBudgetExhausted = false;
|
|
576
624
|
let contextBudgetDetail = "";
|
|
@@ -579,6 +627,9 @@ export async function executeSingleSdkAttempt(options) {
|
|
|
579
627
|
// length-stopped thinking-only attempt with no persisted write tool calls is
|
|
580
628
|
// still distinguishable from generic empty output.
|
|
581
629
|
let stopReason;
|
|
630
|
+
let providerErrorMessage;
|
|
631
|
+
let promptIndex = 0;
|
|
632
|
+
let outputContinuesSent = 0;
|
|
582
633
|
let thinkingObserved = false;
|
|
583
634
|
let writeToolCallCount = 0;
|
|
584
635
|
const observeWriterThinkingExhaustionEvidence = (event) => {
|
|
@@ -660,6 +711,13 @@ export async function executeSingleSdkAttempt(options) {
|
|
|
660
711
|
? { additionalExtensionPaths: options.piExtensionPaths }
|
|
661
712
|
: {}),
|
|
662
713
|
});
|
|
714
|
+
capabilitiesObservation = frontendModelCapabilities(session.agent?.state?.model);
|
|
715
|
+
if (options.reserveProviderRequest || options.frontendExecutionPolicy)
|
|
716
|
+
await installPiProviderRequestBudget(session, options.reserveProviderRequest ?? (async () => { }), message => { providerBudgetFailure = message; appendStderr(message); }, options.frontendExecutionPolicy ? { policy: options.frontendExecutionPolicy, observe: measurement => {
|
|
717
|
+
capabilitiesObservation = measurement.capabilities;
|
|
718
|
+
requestEnvelopeObservation.peakBytes = Math.max(requestEnvelopeObservation.peakBytes, measurement.bytes);
|
|
719
|
+
requestEnvelopeObservation.peakEstimatedTokens = Math.max(requestEnvelopeObservation.peakEstimatedTokens, measurement.estimatedTokens);
|
|
720
|
+
} } : undefined);
|
|
663
721
|
let resolveStall;
|
|
664
722
|
let resolveSettlement;
|
|
665
723
|
let resolveContextBudget;
|
|
@@ -718,6 +776,8 @@ export async function executeSingleSdkAttempt(options) {
|
|
|
718
776
|
resolveContextBudget?.("context-budget");
|
|
719
777
|
};
|
|
720
778
|
unsubscribe = session.subscribe((event) => {
|
|
779
|
+
if (event.type === "tool_execution_end" && event.isError !== true && typeof event.toolName === "string" && options.outputLimitRecovery?.terminalToolNames.includes(event.toolName) && isRecord(event.result) && isRecord(event.result.details) && event.result.details.ok === true)
|
|
780
|
+
committedTerminalObserved = true;
|
|
721
781
|
if (event.type === "agent_settled" && !settled) {
|
|
722
782
|
settled = true;
|
|
723
783
|
resolveSettlement?.("settled");
|
|
@@ -737,9 +797,18 @@ export async function executeSingleSdkAttempt(options) {
|
|
|
737
797
|
// best-effort: activity must never change Pi result
|
|
738
798
|
}
|
|
739
799
|
}
|
|
800
|
+
const observationMessage = isRecord(event.message) ? event.message : undefined;
|
|
801
|
+
if (typeof observationMessage?.errorMessage === "string")
|
|
802
|
+
providerErrorMessage = observationMessage.errorMessage;
|
|
803
|
+
try {
|
|
804
|
+
readObservation.observe(event);
|
|
805
|
+
}
|
|
806
|
+
catch { /* observation must not change execution */ }
|
|
807
|
+
if (!(typeof observationMessage?.errorMessage === "string" && observationMessage.errorMessage.startsWith("FRONTEND_PROVIDER_")) && (event.usage || observationMessage?.usage || event.tokenUsage))
|
|
808
|
+
observationEvents.push({ responseId: event.responseId, messageId: event.messageId, usage: event.usage, tokenUsage: event.tokenUsage, message: observationMessage ? { role: observationMessage.role, id: observationMessage.id, responseId: observationMessage.responseId, usage: observationMessage.usage } : undefined });
|
|
740
809
|
const usageSample = extractSdkUsageSample(event);
|
|
741
810
|
if (usageSample)
|
|
742
|
-
usageSamples.push(usageSample);
|
|
811
|
+
usageSamples.push({ ...usageSample, responseKey: usageSample.responseKey ?? `turn-${promptIndex}` });
|
|
743
812
|
if (event.type === "turn_end")
|
|
744
813
|
observedTurns += 1;
|
|
745
814
|
checkContextBudget();
|
|
@@ -753,6 +822,7 @@ export async function executeSingleSdkAttempt(options) {
|
|
|
753
822
|
const line = serializeSessionEvent(event);
|
|
754
823
|
stdoutPreview.append(`${line}\n`);
|
|
755
824
|
stdoutCollector.append(`${line}\n`);
|
|
825
|
+
turnCollector.append(`${line}\n`);
|
|
756
826
|
sessionEventAppender?.append(line, event);
|
|
757
827
|
});
|
|
758
828
|
const timeoutPromise = timeoutMs > 0
|
|
@@ -763,6 +833,9 @@ export async function executeSingleSdkAttempt(options) {
|
|
|
763
833
|
})
|
|
764
834
|
: null;
|
|
765
835
|
const runTurn = async (userMessage) => {
|
|
836
|
+
promptIndex += 1;
|
|
837
|
+
stopReason = undefined;
|
|
838
|
+
turnCollector = createPiJsonlStreamCollector();
|
|
766
839
|
const settlementPromise = resetSettlement();
|
|
767
840
|
const stallPromise = resetStallPromise();
|
|
768
841
|
const contextBudgetPromise = options.contextBudget
|
|
@@ -808,48 +881,61 @@ export async function executeSingleSdkAttempt(options) {
|
|
|
808
881
|
: options.userMessage;
|
|
809
882
|
let continuesSent = 0;
|
|
810
883
|
let raced = await runTurn(promptMessage);
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
884
|
+
while (true) {
|
|
885
|
+
if (raced === "context-budget") {
|
|
886
|
+
appendStderr(contextBudgetDetail);
|
|
887
|
+
abortConfirmed = await runSessionActionWithGrace("abort", () => session.abort());
|
|
888
|
+
await disposeSession();
|
|
889
|
+
}
|
|
890
|
+
else if (raced === "stall") {
|
|
891
|
+
abortConfirmed = await runSessionActionWithGrace("abort", () => session.abort());
|
|
892
|
+
const withinAbsoluteTimeout = timeoutMs <= 0 || Date.now() - startedAt < timeoutMs;
|
|
893
|
+
const canContinue = abortConfirmed &&
|
|
894
|
+
writeToolCallCount === 0 &&
|
|
895
|
+
withinAbsoluteTimeout &&
|
|
896
|
+
continuesSent < PI_SDK_STALL_CONTINUE_MAX;
|
|
897
|
+
if (canContinue) {
|
|
898
|
+
// The aborted turn's stopReason must not leak onto a recovered continue.
|
|
899
|
+
stopReason = undefined;
|
|
900
|
+
continuesSent += 1;
|
|
901
|
+
persistRuntimeNote({
|
|
902
|
+
type: "loop-agent-stall-continue",
|
|
903
|
+
prompt: PI_SDK_STALL_CONTINUE_PROMPT,
|
|
904
|
+
maxContinues: PI_SDK_STALL_CONTINUE_MAX,
|
|
905
|
+
});
|
|
906
|
+
raced = await runTurn(PI_SDK_STALL_CONTINUE_PROMPT);
|
|
907
|
+
if (raced !== "done" && raced !== "settled") {
|
|
908
|
+
await failClosedAfterWait(raced === "stall" ? "stall" : "absolute-timeout", raced === "stall"
|
|
909
|
+
? "pi SDK stall continue did not recover; treating as timeout"
|
|
910
|
+
: "pi SDK stall continue hit the absolute timeout", true);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
else {
|
|
914
|
+
await failClosedAfterWait("stall", !abortConfirmed
|
|
915
|
+
? undefined
|
|
916
|
+
: writeToolCallCount > 0
|
|
917
|
+
? "pi SDK stall continue skipped because write tools already ran"
|
|
918
|
+
: "pi SDK stall continue skipped because absolute timeout elapsed", false);
|
|
837
919
|
}
|
|
838
920
|
}
|
|
839
|
-
else {
|
|
840
|
-
await failClosedAfterWait("
|
|
841
|
-
? undefined
|
|
842
|
-
: writeToolCallCount > 0
|
|
843
|
-
? "pi SDK stall continue skipped because write tools already ran"
|
|
844
|
-
: "pi SDK stall continue skipped because absolute timeout elapsed", false);
|
|
921
|
+
else if (raced === "absolute-timeout") {
|
|
922
|
+
await failClosedAfterWait("absolute-timeout");
|
|
845
923
|
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
924
|
+
if (options.outputLimitRecovery && stopReason === "length" && !committedTerminalObserved && !stderr && outputContinuesSent < PI_SDK_OUTPUT_LIMIT_CONTINUE_MAX && !timedOut) {
|
|
925
|
+
outputContinuesSent += 1;
|
|
926
|
+
const note = serializeSessionEvent({ type: "loop-agent-output-limit-continue", continue: outputContinuesSent, maxContinues: PI_SDK_OUTPUT_LIMIT_CONTINUE_MAX, prompt: PI_SDK_OUTPUT_LIMIT_CONTINUE_PROMPT });
|
|
927
|
+
stdoutPreview.append(`${note}\n`);
|
|
928
|
+
stdoutCollector.append(`${note}\n`);
|
|
929
|
+
raced = await runTurn(PI_SDK_OUTPUT_LIMIT_CONTINUE_PROMPT);
|
|
930
|
+
continue;
|
|
931
|
+
}
|
|
932
|
+
break;
|
|
849
933
|
}
|
|
850
934
|
}
|
|
851
935
|
catch (error) {
|
|
852
936
|
const message = error instanceof Error ? error.message : String(error);
|
|
937
|
+
if (options.reserveProviderRequest && message.startsWith("FRONTEND_PROVIDER_"))
|
|
938
|
+
providerBudgetFailure = message;
|
|
853
939
|
appendStderr(message);
|
|
854
940
|
}
|
|
855
941
|
finally {
|
|
@@ -872,20 +958,29 @@ export async function executeSingleSdkAttempt(options) {
|
|
|
872
958
|
}
|
|
873
959
|
}
|
|
874
960
|
}
|
|
961
|
+
if (providerErrorMessage && stopReason === "error" && !stderr)
|
|
962
|
+
appendStderr(providerErrorMessage);
|
|
963
|
+
if (options.outputLimitRecovery && stopReason === "length" && !committedTerminalObserved && outputContinuesSent >= PI_SDK_OUTPUT_LIMIT_CONTINUE_MAX) {
|
|
964
|
+
const note = serializeSessionEvent({ type: "loop-agent-output-limit-exhausted", maxContinues: PI_SDK_OUTPUT_LIMIT_CONTINUE_MAX });
|
|
965
|
+
stdoutPreview.append(`${note}\n`);
|
|
966
|
+
}
|
|
875
967
|
const stdout = stdoutPreview.text();
|
|
876
968
|
const durationMs = Date.now() - startedAt;
|
|
877
969
|
const collected = stdoutCollector.finish();
|
|
878
970
|
const fallbackParsed = collected.parsedEvents > 0
|
|
879
971
|
? undefined
|
|
880
972
|
: extractAssistantTextFromPiJson(stdout);
|
|
973
|
+
const finalTurn = turnCollector.finish();
|
|
881
974
|
const assistantText = collected.parsedEvents > 0
|
|
882
|
-
?
|
|
975
|
+
? finalTurn.assistantText
|
|
883
976
|
: (fallbackParsed?.assistantText ?? "");
|
|
884
977
|
const parsedEvents = collected.parsedEvents > 0
|
|
885
978
|
? collected.parsedEvents
|
|
886
979
|
: (fallbackParsed?.parsedEvents ?? 0);
|
|
887
980
|
const tokensUsed = aggregateSdkTokenUsage(usageSamples);
|
|
888
|
-
const
|
|
981
|
+
const cancelled = stopReason === "aborted";
|
|
982
|
+
const outputLimitExhausted = Boolean(options.outputLimitRecovery && stopReason === "length" && !committedTerminalObserved && !timedOut && !stderr);
|
|
983
|
+
const failureCategory = !terminationConfirmed ? "termination-unconfirmed" : stopReason === "aborted" ? "cancelled" : outputLimitExhausted ? "output-limit" : providerBudgetFailure ? (providerBudgetFailure.includes("REQUEST_ABORTED") ? "interrupted" : providerBudgetFailure.startsWith("FRONTEND_CONTEXT_ESTIMATE_EXCEEDED") ? "context-budget-exhausted" : "budget_breach") : terminationConfirmed
|
|
889
984
|
? classifyPiFailure({
|
|
890
985
|
assistantText,
|
|
891
986
|
exitCode: timedOut ? 1 : stderr ? 1 : 0,
|
|
@@ -900,12 +995,14 @@ export async function executeSingleSdkAttempt(options) {
|
|
|
900
995
|
backend: "sdk",
|
|
901
996
|
command: ["pi-sdk", ...piSdkArgs],
|
|
902
997
|
durationMs,
|
|
903
|
-
exitCode: timedOut || stderr ? 1 : 0,
|
|
998
|
+
exitCode: timedOut || stderr || outputLimitExhausted || cancelled ? 1 : 0,
|
|
904
999
|
failureCategory,
|
|
905
1000
|
modelDisplay,
|
|
906
1001
|
ok: terminationConfirmed &&
|
|
907
1002
|
!timedOut &&
|
|
908
1003
|
!stderr &&
|
|
1004
|
+
!outputLimitExhausted &&
|
|
1005
|
+
!cancelled &&
|
|
909
1006
|
assistantText.length > 0 &&
|
|
910
1007
|
!collected.outputTooLarge,
|
|
911
1008
|
parsedEvents,
|
|
@@ -915,6 +1012,10 @@ export async function executeSingleSdkAttempt(options) {
|
|
|
915
1012
|
outputTooLarge: collected.outputTooLarge,
|
|
916
1013
|
timedOut,
|
|
917
1014
|
tokensUsed,
|
|
1015
|
+
usageObservation: collectFrontendUsage(observationEvents),
|
|
1016
|
+
readObservation: readObservation.snapshot(),
|
|
1017
|
+
capabilitiesObservation,
|
|
1018
|
+
...(options.frontendExecutionPolicy ? { requestEnvelopeObservation } : {}),
|
|
918
1019
|
subagentStats: collected.subagentStats,
|
|
919
1020
|
// Writer-thinking-exhausted diagnosis evidence (AC-002). Carried through
|
|
920
1021
|
// the object spread in executePiStep so executeDagPiNode can read them
|