@tangle-network/agent-eval 0.183.0 → 0.185.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/dist/adapters/http.d.ts +2 -2
- package/dist/{agent-profile-cell-s__adRnK.d.ts → agent-profile-cell-BHcB-mZX.d.ts} +8 -9
- package/dist/{agent-profile-cell-s__adRnK.d.ts.map → agent-profile-cell-BHcB-mZX.d.ts.map} +1 -1
- package/dist/{agent-profile-cell-Cv6UA-W_.js → agent-profile-cell-DcFW4vOc.js} +16 -15
- package/dist/agent-profile-cell-DcFW4vOc.js.map +1 -0
- package/dist/{agent-profile-CivaSsSy.d.ts → agent-profile-uAIQK3Nr.d.ts} +3 -3
- package/dist/{agent-profile-CivaSsSy.d.ts.map → agent-profile-uAIQK3Nr.d.ts.map} +1 -1
- package/dist/analyst/index.d.ts +11 -336
- package/dist/analyst/index.d.ts.map +1 -1
- package/dist/analyst/index.js +10 -8
- package/dist/analyst/index.js.map +1 -1
- package/dist/analyze-runs-CrYhqXop.d.ts +75 -0
- package/dist/analyze-runs-CrYhqXop.d.ts.map +1 -0
- package/dist/{define-agent-eval-CneiWyuA.js → analyze-runs-sTygaDyD.js} +6 -813
- package/dist/analyze-runs-sTygaDyD.js.map +1 -0
- package/dist/{benchmark-DQKzykkO.js → benchmark-BeQJyrRC.js} +3 -3
- package/dist/{benchmark-DQKzykkO.js.map → benchmark-BeQJyrRC.js.map} +1 -1
- package/dist/{benchmark-command-NBrqNwgy.js → benchmark-command-kvq7yFY4.js} +17 -54
- package/dist/benchmark-command-kvq7yFY4.js.map +1 -0
- package/dist/benchmarks/index.d.ts +4 -4
- package/dist/benchmarks/index.js +3 -3
- package/dist/builder-eval/index.js +1 -1
- package/dist/campaign/index.d.ts +6 -5
- package/dist/campaign/index.js +10 -9
- package/dist/{campaign-BwcEBC91.js → campaign-eJgtRs-W.js} +16 -15
- package/dist/{campaign-BwcEBC91.js.map → campaign-eJgtRs-W.js.map} +1 -1
- package/dist/{campaign-evidence-PYPUftRy.js → campaign-evidence-BsrCmBSE.js} +7 -258
- package/dist/campaign-evidence-BsrCmBSE.js.map +1 -0
- package/dist/{canonical-DPyQ_rpt.js → canonical-BsZVgBhW.js} +2 -4
- package/dist/canonical-BsZVgBhW.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/{client-kh2jOjTK.d.ts → client-Bc8LANCG.d.ts} +4 -4
- package/dist/{client-kh2jOjTK.d.ts.map → client-Bc8LANCG.d.ts.map} +1 -1
- package/dist/contract/index.d.ts +10 -10
- package/dist/contract/index.js +15 -284
- package/dist/contract/index.js.map +1 -1
- package/dist/{default-registry-BwDSWVzg.d.ts → default-registry-CXv9kHMt.d.ts} +6 -6
- package/dist/{default-registry-BwDSWVzg.d.ts.map → default-registry-CXv9kHMt.d.ts.map} +1 -1
- package/dist/{default-registry-C0-N4PkG.js → default-registry-xiHrldW8.js} +6 -4
- package/dist/{default-registry-C0-N4PkG.js.map → default-registry-xiHrldW8.js.map} +1 -1
- package/dist/define-agent-eval-D4uumjl3.js +813 -0
- package/dist/define-agent-eval-D4uumjl3.js.map +1 -0
- package/dist/{define-agent-eval-CwOWWQt_.d.ts → define-agent-eval-DE67ECH1.d.ts} +7 -7
- package/dist/{define-agent-eval-CwOWWQt_.d.ts.map → define-agent-eval-DE67ECH1.d.ts.map} +1 -1
- package/dist/diagnosis/index.d.ts +319 -0
- package/dist/diagnosis/index.d.ts.map +1 -0
- package/dist/diagnosis/index.js +1328 -0
- package/dist/diagnosis/index.js.map +1 -0
- package/dist/{dspy-rlm-engine-8pgBSiy7.js → dspy-rlm-engine-BE9lCzzL.js} +3 -3
- package/dist/{dspy-rlm-engine-8pgBSiy7.js.map → dspy-rlm-engine-BE9lCzzL.js.map} +1 -1
- package/dist/{engine-DS1cysJy.d.ts → engine-cXUK-WHS.d.ts} +5 -77
- package/dist/engine-cXUK-WHS.d.ts.map +1 -0
- package/dist/equal-terms-Blx9Zk5I.js +25 -0
- package/dist/equal-terms-Blx9Zk5I.js.map +1 -0
- package/dist/{eval-campaign-CCEkwzoH.js → eval-campaign-XFHEpN86.js} +4 -4
- package/dist/{eval-campaign-CCEkwzoH.js.map → eval-campaign-XFHEpN86.js.map} +1 -1
- package/dist/evaluation.d.ts +75 -0
- package/dist/evaluation.d.ts.map +1 -0
- package/dist/evaluation.js +137 -0
- package/dist/evaluation.js.map +1 -0
- package/dist/{exact-types-BZDe0W2D.d.ts → exact-types-BEHN7tnq.d.ts} +2 -2
- package/dist/{exact-types-BZDe0W2D.d.ts.map → exact-types-BEHN7tnq.d.ts.map} +1 -1
- package/dist/experiment/index.d.ts +2 -2
- package/dist/experiment/index.js +6 -5
- package/dist/experiment/index.js.map +1 -1
- package/dist/{experiment-tracker-C7PfnF4b.d.ts → experiment-tracker-URRGP9ek.d.ts} +2 -2
- package/dist/{experiment-tracker-C7PfnF4b.d.ts.map → experiment-tracker-URRGP9ek.d.ts.map} +1 -1
- package/dist/{external-optimizer-process-DIB4YWEe.js → external-optimizer-process-BbhvXTFx.js} +4 -4
- package/dist/{external-optimizer-process-DIB4YWEe.js.map → external-optimizer-process-BbhvXTFx.js.map} +1 -1
- package/dist/{external-optimizer-subprocess-CjguXN2e.js → external-optimizer-subprocess-DMgmqTB6.js} +3 -3
- package/dist/{external-optimizer-subprocess-CjguXN2e.js.map → external-optimizer-subprocess-DMgmqTB6.js.map} +1 -1
- package/dist/{feedback-trajectory-CXmtITBo.d.ts → feedback-trajectory-CytTR7u4.d.ts} +3 -3
- package/dist/{feedback-trajectory-CXmtITBo.d.ts.map → feedback-trajectory-CytTR7u4.d.ts.map} +1 -1
- package/dist/hosted/index.d.ts +2 -2
- package/dist/{index-DoykkxW0.d.ts → index-BQWfAFeH.d.ts} +11 -11
- package/dist/{index-DoykkxW0.d.ts.map → index-BQWfAFeH.d.ts.map} +1 -1
- package/dist/{index-DbG8QbH9.d.ts → index-C8_iU8KL.d.ts} +6 -6
- package/dist/{index-DbG8QbH9.d.ts.map → index-C8_iU8KL.d.ts.map} +1 -1
- package/dist/{index--_8_Nlpn.d.ts → index-CKZa_rnt.d.ts} +4 -121
- package/dist/index-CKZa_rnt.d.ts.map +1 -0
- package/dist/{index-Bp_6sj3x.d.ts → index-ww8736Am.d.ts} +20 -315
- package/dist/index-ww8736Am.d.ts.map +1 -0
- package/dist/index.d.ts +24 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -24
- package/dist/index.js.map +1 -1
- package/dist/{insight-report-D1qa0HWs.d.ts → insight-report-C3Bfl762.d.ts} +3 -3
- package/dist/{insight-report-D1qa0HWs.d.ts.map → insight-report-C3Bfl762.d.ts.map} +1 -1
- package/dist/jev-protocol.d.ts +74 -0
- package/dist/jev-protocol.d.ts.map +1 -0
- package/dist/jev-protocol.js +91 -0
- package/dist/jev-protocol.js.map +1 -0
- package/dist/jev.d.ts +131 -0
- package/dist/jev.d.ts.map +1 -0
- package/dist/jev.js +312 -0
- package/dist/jev.js.map +1 -0
- package/dist/{journal-Cs9f7385.js → journal-BuRLm6ho.js} +2 -2
- package/dist/{journal-Cs9f7385.js.map → journal-BuRLm6ho.js.map} +1 -1
- package/dist/{kind-factory-DxTzg32u.js → kind-factory-V79Hw0AU.js} +7 -84
- package/dist/kind-factory-V79Hw0AU.js.map +1 -0
- package/dist/ledger-core/index.js +2 -2
- package/dist/{llm-judge-FfaRgz9X.js → llm-judge-FWWhEb31.js} +11 -9
- package/dist/{llm-judge-FfaRgz9X.js.map → llm-judge-FWWhEb31.js.map} +1 -1
- package/dist/{matrix-CyhW-vgJ.d.ts → matrix-CPKsRY8Y.d.ts} +2 -2
- package/dist/{matrix-CyhW-vgJ.d.ts.map → matrix-CPKsRY8Y.d.ts.map} +1 -1
- package/dist/meta-eval/index.d.ts +54 -2
- package/dist/meta-eval/index.d.ts.map +1 -1
- package/dist/meta-eval/index.js +52 -3
- package/dist/meta-eval/index.js.map +1 -1
- package/dist/{mint-ySIIkKlV.js → mint-B4zgSAJW.js} +63 -14
- package/dist/mint-B4zgSAJW.js.map +1 -0
- package/dist/mint-BI14xehJ.d.ts +285 -0
- package/dist/mint-BI14xehJ.d.ts.map +1 -0
- package/dist/multishot/golden/index.d.ts +1 -1
- package/dist/multishot/index.d.ts +2 -2
- package/dist/openapi.json +1 -1
- package/dist/otel-spans-CQY1pNiN.js +275 -0
- package/dist/otel-spans-CQY1pNiN.js.map +1 -0
- package/dist/otlp-attributes-BpC_blLF.js +83 -0
- package/dist/otlp-attributes-BpC_blLF.js.map +1 -0
- package/dist/{run-record-DPa2PeHx.js → paired-promotion-decision-ClJh_9nK.js} +2 -215
- package/dist/paired-promotion-decision-ClJh_9nK.js.map +1 -0
- package/dist/pipelines/index.js +2 -2
- package/dist/prime-bridge-transport-Z3cpKGoV.js +43 -0
- package/dist/prime-bridge-transport-Z3cpKGoV.js.map +1 -0
- package/dist/prime-protocol-CDBcL9NM.d.ts +331 -0
- package/dist/prime-protocol-CDBcL9NM.d.ts.map +1 -0
- package/dist/{prime-protocol-6tZTVsWm.js → prime-protocol-DcAK9pC8.js} +2 -23
- package/dist/prime-protocol-DcAK9pC8.js.map +1 -0
- package/dist/{produced-state-CGoVInrl.js → produced-state-CmB02tr2.js} +23 -19
- package/dist/{produced-state-CGoVInrl.js.map → produced-state-CmB02tr2.js.map} +1 -1
- package/dist/profile-cell.d.ts +1 -1
- package/dist/profile-cell.js +1 -1
- package/dist/{promotion-policy-BKFrl7CC.js → promotion-policy-DdrYWHDh.js} +3 -3
- package/dist/{promotion-policy-BKFrl7CC.js.map → promotion-policy-DdrYWHDh.js.map} +1 -1
- package/dist/{query-D1nLIKt7.js → query-DlV0pdx4.js} +2 -2
- package/dist/{query-D1nLIKt7.js.map → query-DlV0pdx4.js.map} +1 -1
- package/dist/{registry-BRbB6Y0v.d.ts → registry-D5Ly3GRV.d.ts} +3 -3
- package/dist/{registry-BRbB6Y0v.d.ts.map → registry-D5Ly3GRV.d.ts.map} +1 -1
- package/dist/{release-confidence-BcqeQTHW.d.ts → release-confidence-DsETiO4f.d.ts} +3 -3
- package/dist/{release-confidence-BcqeQTHW.d.ts.map → release-confidence-DsETiO4f.d.ts.map} +1 -1
- package/dist/{release-confidence-DMg8n18l.js → release-confidence-RanRUXRW.js} +2 -2
- package/dist/{release-confidence-DMg8n18l.js.map → release-confidence-RanRUXRW.js.map} +1 -1
- package/dist/reporting.d.ts +3 -3
- package/dist/reporting.js +2 -2
- package/dist/{researcher-64T49THL.d.ts → researcher-CJkH-6Ty.d.ts} +4 -4
- package/dist/{researcher-64T49THL.d.ts.map → researcher-CJkH-6Ty.d.ts.map} +1 -1
- package/dist/{reward-hacking-uzO_ihep.d.ts → reward-hacking-BIQ2BWLG.d.ts} +2 -2
- package/dist/{reward-hacking-uzO_ihep.d.ts.map → reward-hacking-BIQ2BWLG.d.ts.map} +1 -1
- package/dist/rl.d.ts +10 -6
- package/dist/rl.d.ts.map +1 -1
- package/dist/rl.js +22 -7
- package/dist/rl.js.map +1 -1
- package/dist/rollout/index.d.ts +2 -2
- package/dist/rollout/index.js +2 -2
- package/dist/{rollout-D_54FZVu.js → rollout-C0Ifk3vK.js} +2 -2
- package/dist/{rollout-D_54FZVu.js.map → rollout-C0Ifk3vK.js.map} +1 -1
- package/dist/{rubric-predictive-validity-Bmj2_cll.d.ts → rubric-predictive-validity-CTU8y8Cv.d.ts} +2 -2
- package/dist/{rubric-predictive-validity-Bmj2_cll.d.ts.map → rubric-predictive-validity-CTU8y8Cv.d.ts.map} +1 -1
- package/dist/run-record-CNNzWGpB.js +216 -0
- package/dist/run-record-CNNzWGpB.js.map +1 -0
- package/dist/{run-record-BiTWauyO.d.ts → run-record-D9wS35fK.d.ts} +2 -2
- package/dist/{run-record-BiTWauyO.d.ts.map → run-record-D9wS35fK.d.ts.map} +1 -1
- package/dist/{run-record-DualPTn2.js → run-record-tg_5H2IK.js} +2 -2
- package/dist/{run-record-DualPTn2.js.map → run-record-tg_5H2IK.js.map} +1 -1
- package/dist/search-ledger-types-D7KDVg-o.d.ts +302 -0
- package/dist/search-ledger-types-D7KDVg-o.d.ts.map +1 -0
- package/dist/{semantic-concept-judge-_3Fp6Q_3.js → semantic-concept-judge-Cnt0TWp0.js} +4 -4
- package/dist/{semantic-concept-judge-_3Fp6Q_3.js.map → semantic-concept-judge-Cnt0TWp0.js.map} +1 -1
- package/dist/{sequential-D_xHrBZe.js → sequential-PgLEqcTJ.js} +3 -3
- package/dist/{sequential-D_xHrBZe.js.map → sequential-PgLEqcTJ.js.map} +1 -1
- package/dist/{server-BZQR1f0C.js → server-DmpcFiVK.js} +2 -2
- package/dist/{server-BZQR1f0C.js.map → server-DmpcFiVK.js.map} +1 -1
- package/dist/{skillopt-optimization-method-DY1aQ-aL.js → skillopt-optimization-method-FSk8b5FQ.js} +8 -7
- package/dist/{skillopt-optimization-method-DY1aQ-aL.js.map → skillopt-optimization-method-FSk8b5FQ.js.map} +1 -1
- package/dist/{statistical-heldout-CpVd6FmY.d.ts → statistical-heldout-Bu4oNOJh.d.ts} +3 -3
- package/dist/{statistical-heldout-CpVd6FmY.d.ts.map → statistical-heldout-Bu4oNOJh.d.ts.map} +1 -1
- package/dist/statistical-heldout-CeWT_W7y.js +256 -0
- package/dist/statistical-heldout-CeWT_W7y.js.map +1 -0
- package/dist/{store-otlp-DAaEbMLf.js → store-otlp-2gYCy-v0.js} +2 -2
- package/dist/{store-otlp-DAaEbMLf.js.map → store-otlp-2gYCy-v0.js.map} +1 -1
- package/dist/{store-tool-spans-BZ8MPKFe.js → store-tool-spans-B1e6Auc2.js} +69 -6
- package/dist/store-tool-spans-B1e6Auc2.js.map +1 -0
- package/dist/{store-tool-spans-Dt-YdAuE.d.ts → store-tool-spans-BrdfPaVh.d.ts} +54 -6
- package/dist/store-tool-spans-BrdfPaVh.d.ts.map +1 -0
- package/dist/{summary-report-IGAOtgPd.js → summary-report-BMvou2oZ.js} +2 -2
- package/dist/{summary-report-IGAOtgPd.js.map → summary-report-BMvou2oZ.js.map} +1 -1
- package/dist/{summary-report-D1h4dlrK.d.ts → summary-report-BzFS5UhZ.d.ts} +2 -2
- package/dist/{summary-report-D1h4dlrK.d.ts.map → summary-report-BzFS5UhZ.d.ts.map} +1 -1
- package/dist/{task-failure-attributes-B_JjrOVo.js → task-failure-attributes-B34TiMBe.js} +2 -2
- package/dist/{task-failure-attributes-B_JjrOVo.js.map → task-failure-attributes-B34TiMBe.js.map} +1 -1
- package/dist/{tool-groups-B2bSNaJB.d.ts → tool-groups-eOOgYGaM.d.ts} +3 -3
- package/dist/tool-groups-eOOgYGaM.d.ts.map +1 -0
- package/dist/{tool-waste-C7MU9u1e.js → tool-waste-nbHPAxei.js} +2 -2
- package/dist/{tool-waste-C7MU9u1e.js.map → tool-waste-nbHPAxei.js.map} +1 -1
- package/dist/trace-repair/index.d.ts +2 -2
- package/dist/trace-repair/index.js +5 -4
- package/dist/trace-repair/index.js.map +1 -1
- package/dist/traces.d.ts +5 -5
- package/dist/traces.js +8 -7
- package/dist/traces.js.map +1 -1
- package/dist/trajectory-replay/index.js +1 -1
- package/dist/{types-CS0qk_Yp.d.ts → types-BTRcIqFr.d.ts} +3 -3
- package/dist/{types-CS0qk_Yp.d.ts.map → types-BTRcIqFr.d.ts.map} +1 -1
- package/dist/{types-D7gEdPoQ.d.ts → types-BjB2wZM9.d.ts} +2 -2
- package/dist/{types-D7gEdPoQ.d.ts.map → types-BjB2wZM9.d.ts.map} +1 -1
- package/dist/types-C8VBbiw6.js +91 -0
- package/dist/types-C8VBbiw6.js.map +1 -0
- package/dist/{types-BvZoPTGa.d.ts → types-c3ZRTbw9.d.ts} +3 -3
- package/dist/{types-BvZoPTGa.d.ts.map → types-c3ZRTbw9.d.ts.map} +1 -1
- package/dist/{types-DQ0e2E7y.js → usage-receipt-Cx3xNeyB.js} +2 -89
- package/dist/usage-receipt-Cx3xNeyB.js.map +1 -0
- package/dist/{verdict-BQ3pCFf8.js → verdict-DhPoXApk.js} +2 -2
- package/dist/{verdict-BQ3pCFf8.js.map → verdict-DhPoXApk.js.map} +1 -1
- package/dist/{verdict-cache-B3eCVQtY.js → verdict-cache-BQEsVy9n.js} +2 -2
- package/dist/{verdict-cache-B3eCVQtY.js.map → verdict-cache-BQEsVy9n.js.map} +1 -1
- package/dist/wire/index.d.ts +1 -1
- package/dist/wire/index.js +1 -1
- package/docs/changes/evaluation-definition-identity.md +27 -0
- package/docs/changes/jev-evidence-review.md +18 -0
- package/docs/changes/jev-product-adoption.md +18 -0
- package/docs/changes/probability-policy-audit.md +81 -0
- package/docs/diagnosis.md +42 -0
- package/docs/jev-behavior-review.md +174 -0
- package/docs/jev-integrations.md +50 -0
- package/docs/jev.md +140 -0
- package/docs/produced-state.md +13 -0
- package/docs/profile-json-identity.md +33 -0
- package/package.json +22 -1
- package/dist/agent-profile-cell-Cv6UA-W_.js.map +0 -1
- package/dist/benchmark-command-NBrqNwgy.js.map +0 -1
- package/dist/campaign-evidence-PYPUftRy.js.map +0 -1
- package/dist/canonical-DPyQ_rpt.js.map +0 -1
- package/dist/define-agent-eval-CneiWyuA.js.map +0 -1
- package/dist/engine-DS1cysJy.d.ts.map +0 -1
- package/dist/exporters-D98GPi1n.d.ts +0 -161
- package/dist/exporters-D98GPi1n.d.ts.map +0 -1
- package/dist/index--_8_Nlpn.d.ts.map +0 -1
- package/dist/index-Bp_6sj3x.d.ts.map +0 -1
- package/dist/kind-factory-DxTzg32u.js.map +0 -1
- package/dist/mint-ySIIkKlV.js.map +0 -1
- package/dist/prime-protocol-6tZTVsWm.js.map +0 -1
- package/dist/run-record-DPa2PeHx.js.map +0 -1
- package/dist/store-tool-spans-BZ8MPKFe.js.map +0 -1
- package/dist/store-tool-spans-Dt-YdAuE.d.ts.map +0 -1
- package/dist/tool-groups-B2bSNaJB.d.ts.map +0 -1
- package/dist/types-DQ0e2E7y.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paired-promotion-decision-ClJh_9nK.js","names":[],"sources":["../src/paired-delta-test.ts","../src/paired-promotion-decision.ts"],"sourcesContent":["import {\n type PairedBootstrapOptions,\n type PairedBootstrapResult,\n pairedBootstrap,\n pairedSignTest,\n} from './statistics'\n\nexport interface PairedDeltaTestOptions extends PairedBootstrapOptions {\n /** Smallest candidate-minus-baseline delta that counts as improvement. Default 0. */\n threshold?: number\n /** Caller-required paired observations. The exact test may impose a higher minimum. */\n minPairs?: number\n}\n\nexport interface PairedDeltaTestResult {\n bootstrap: PairedBootstrapResult\n method: 'bootstrap-ci' | 'exact-sign'\n /** Exact one-sided p-value below the bootstrap minimum; otherwise null. */\n pValue: number | null\n /** Effective observation minimum after accounting for confidence. */\n minimumPairs: number\n sufficient: boolean\n /**\n * The bootstrap interval has zero width (or is non-finite), so it carries no\n * information about how far the estimate could be wrong and cannot support a\n * decision in either direction. See {@link pairedDeltaTest}.\n */\n indeterminate: boolean\n significant: boolean\n}\n\n/** Smallest all-positive sample that can clear a one-sided exact sign test. */\nexport function minimumPairsForPairedDeltaTest(confidence = 0.95): number {\n if (!Number.isFinite(confidence) || confidence <= 0 || confidence >= 1) {\n throw new Error(\n `minimumPairsForPairedDeltaTest: confidence must be in (0,1), got ${confidence}`,\n )\n }\n const oneSidedAlpha = (1 - confidence) / 2\n return Math.ceil(Math.log2(1 / oneSidedAlpha))\n}\n\n/**\n * Tests whether a paired candidate-minus-baseline delta clears a threshold.\n *\n * At 20 or more pairs, the percentile bootstrap lower bound carries the\n * decision. Below that point the interval is descriptive only, so the function\n * switches to a pre-registered one-sided exact sign test. The exact path is\n * deliberately conservative: it requires both a point estimate above the\n * threshold and enough consistently positive paired differences.\n *\n * ## A zero-width interval is never significant\n *\n * When every paired delta is identical the resample distribution is a point\n * mass and the interval collapses: `[0, 0]` when all pairs tie, `[g, g]` on n\n * identical deltas of g. Neither says the effect is certain — both say the\n * sample carries no information about how far the estimate could be wrong, and\n * `low > threshold` then answers on the point estimate alone. It fails in both\n * directions: `[0, 0]` clears every NEGATIVE threshold, which is how a\n * tie-dominated pass/fail comparison laundered a regression into a\n * noninferiority pass, and `[g, g]` clears every threshold below g with no\n * spread behind it. Under a bounded asymmetric null whose true mean paired\n * delta is exactly 0 — 2 % of pairs dropping by 1.0, the rest gaining 0.0204 —\n * every sample that misses the drop is exactly that shape, and deciding on\n * `low > 0` promoted 65.65 % of samples at n = 20 against a nominal 5 %.\n *\n * So `indeterminate` is reported and `significant` is false whenever the\n * interval has zero width, on BOTH paths: at small n the exact sign test is a\n * test of the MEDIAN and a zero-spread sample is precisely where it stops\n * saying anything about the mean the caller is thresholding.\n *\n * `threshold` may be negative — that is a noninferiority margin, and it is the\n * regime the zero-width hole is worst in. For a two-point (pass/fail) outcome\n * the percentile bootstrap is not a valid interval at a nonzero margin at all;\n * use {@link decidePairedPromotion}, which routes those to Tango's score\n * interval, rather than thresholding this function's bootstrap directly.\n */\nexport function pairedDeltaTest(\n before: number[],\n after: number[],\n options: PairedDeltaTestOptions = {},\n): PairedDeltaTestResult {\n const threshold = options.threshold ?? 0\n if (!Number.isFinite(threshold)) {\n throw new Error(`pairedDeltaTest: threshold must be finite, got ${threshold}`)\n }\n const confidence = options.confidence ?? 0.95\n const exactMinimum = minimumPairsForPairedDeltaTest(confidence)\n const requestedMinimum = options.minPairs ?? exactMinimum\n if (!Number.isInteger(requestedMinimum) || requestedMinimum < 1) {\n throw new Error(`pairedDeltaTest: minPairs must be a positive integer, got ${requestedMinimum}`)\n }\n const minimumPairs = Math.max(requestedMinimum, exactMinimum)\n const bootstrap = pairedBootstrap(before, after, options)\n const sufficient = bootstrap.n >= minimumPairs\n // A point-mass resample distribution is an absence of evidence, not a\n // certainty, and it is the shape that clears every negative threshold. Both\n // paths refuse it: see the \"zero-width\" section of this function's docs.\n const indeterminate =\n bootstrap.n > 0 &&\n (!Number.isFinite(bootstrap.low) ||\n !Number.isFinite(bootstrap.high) ||\n bootstrap.low === bootstrap.high)\n\n if (bootstrap.gateEligible) {\n return {\n bootstrap,\n method: 'bootstrap-ci',\n pValue: null,\n minimumPairs,\n sufficient,\n indeterminate,\n significant: sufficient && !indeterminate && bootstrap.low > threshold,\n }\n }\n\n const differences = before.map((value, index) => after[index]! - value - threshold)\n const exact = pairedSignTest(differences, 'greater')\n const estimate = options.statistic === 'mean' ? bootstrap.mean : bootstrap.median\n return {\n bootstrap,\n method: 'exact-sign',\n pValue: exact.pValue,\n minimumPairs,\n sufficient,\n indeterminate,\n significant:\n sufficient &&\n !indeterminate &&\n estimate > threshold &&\n exact.pValue <= (1 - bootstrap.confidence) / 2,\n }\n}\n","/**\n * @module\n * ONE rule for \"does this paired interval clear a promotion threshold\".\n *\n * The rule below was derived on `HeldOutGate` (#479) after the same estimator\n * bug shipped twice. It then turned out that a SECOND gate — the composable\n * `heldOutGate`, plus everything else routed through `heldoutSignificance` —\n * still carried the original defect, because the rule had been written into one\n * gate's method body rather than into a shared function. Two copies of a\n * statistical rule is how a defect survives in one of them, so there is now\n * exactly one copy and both gates call it.\n *\n * Three things the rule does that a bare `pairedBootstrap(...).low > threshold`\n * does not:\n *\n * 1. **Two-point (pass/fail) outcomes decide on Tango's SCORE interval.** On a\n * pass/fail eval the paired delta vector is dominated by ties, so the\n * bootstrap of the mean is a resample of a lattice with three atoms and its\n * percentile interval is not valid at a nonzero margin. The score interval\n * (`pairedRiskDifferenceScore`) re-estimates the nuisance loss rate under\n * each hypothesised margin instead of fixing it at the observed value, which\n * is the only construction that stays a confidence interval as the margin\n * moves off zero — the regime every noninferiority threshold lives in.\n * Measured on the composable gate before this change, at a true risk\n * difference sitting exactly on the production caller's -0.05 margin and a\n * nominal 5 %: 14.60 % false promotion at n = 40 and 10.10 % at n = 76.\n * 2. **McNemar's exact test holds a VETO at every non-negative threshold.**\n * Redundant with the interval by construction and kept anyway, so that\n * swapping the estimator for one without that duality cannot silently\n * reintroduce \"promotes what the exact test refuses\". Witness: n = 6, b = 5,\n * c = 0 — no exact argument reaches alpha = 0.05 with 5 discordant pairs\n * (two-sided floor 2/2^5 = 0.0625), whatever an interval says. A NEGATIVE\n * threshold is a noninferiority question, which McNemar's test of \"no\n * difference\" is not the right test for, so the veto does not apply there.\n * 3. **A ZERO-WIDTH interval is refused, wherever it sits.** At [0, 0] it\n * cannot tell a gain from a regression and clears every negative threshold.\n * Away from zero it fails the opposite way: n identical positive deltas give\n * [g, g], which clears threshold 0 on no spread at all. Both are an absence\n * of evidence. Measured on the composable gate before this change, under a\n * bounded asymmetric null whose true mean paired delta is exactly 0: 88.50 %\n * false promotion at n = 6 and 65.65 % at n = 20 against a nominal 5 %.\n *\n * Eligibility follows the requested target. A continuous mean needs the\n * bootstrap minimum; binary outcomes and explicit median targets use the\n * exact-test minimum. A small-sample sign diagnostic cannot certify a mean\n * effect. These floors establish estimator eligibility, not adequate power.\n */\n\nimport { minimumPairsForPairedDeltaTest, pairedDeltaTest } from './paired-delta-test'\nimport {\n BOOTSTRAP_GATE_MIN_N,\n type PairedBootstrapResult,\n pairedBinaryScale,\n pairedDeltaTieFraction,\n pairedRiskDifferenceExact,\n pairedRiskDifferenceScore,\n} from './statistics'\n\n/** Which paired estimator produced the deciding interval. */\nexport type PairedDecisionStatistic =\n | 'paired_risk_difference'\n | 'mean_bootstrap'\n | 'median_bootstrap'\n\n/** Which test carried the decision, given the estimator and the sample size. */\nexport type PairedDecisionMethod = 'score-interval' | 'bootstrap-ci' | 'exact-sign'\n\n/** McNemar's exact paired-binary evidence, on the two-point path only. */\nexport interface PairedMcNemarEvidence {\n /** Discordant pairs the treatment won. */\n b: number\n /** Discordant pairs the control won. */\n c: number\n /** b + c — the only pairs carrying information. */\n nDiscordant: number\n /** Two-sided exact p-value. */\n pValue: number\n}\n\nexport interface PairedPromotionDecisionOptions {\n /** Smallest candidate-minus-baseline delta that counts as improvement, in the\n * caller's native units. May be negative (a noninferiority margin). Default 0. */\n threshold?: number\n /** Confidence level. Default 0.95. */\n confidence?: number\n /** Bootstrap resamples, on the paths where a bootstrap decides. Default 2000. */\n resamples?: number\n /** Deterministic bootstrap seed. Omitted ⇒ derived from the deltas. */\n seed?: number\n /** Caller-required paired observations. The test also imposes its own\n * minimum: bootstrap eligibility for a continuous mean, or the exact-test\n * minimum for binary and explicit median targets. This is not a power guarantee. */\n minPairs?: number\n /**\n * `'mean'` (default) routes by SHAPE: a two-point (pass/fail) outcome on any\n * encoding decides on the score interval, everything else on the mean\n * bootstrap. `'median'` forces the median bootstrap on every input, including\n * shapes where it is structurally blind — kept for callers who want outlier\n * robustness on genuinely continuous outcomes and accept that cost.\n */\n statistic?: 'mean' | 'median'\n /** Declared binary support {0, binaryScale}, including when all observations\n * are zero. Must be finite and positive; every observation must use that\n * support. Uses the risk-difference mean, so cannot accompany 'median'.\n * Omitted: infer binary support from observed positive values. */\n binaryScale?: number\n}\n\nexport interface PairedPromotionDecision {\n /** Paired observations supplied. */\n n: number\n /** Threshold the interval was judged against, native units. */\n threshold: number\n confidence: number\n statistic: PairedDecisionStatistic\n method: PairedDecisionMethod\n /** Declared or inferred positive level ({0,1} ⇒ 1, {0,100} ⇒ 100),\n * or null when the outcome is not two-point. Non-null is exactly the\n * condition for the `paired_risk_difference` path, and it is the factor\n * `delta` / `low` / `high` were rescaled by. */\n binaryScale: number | null\n /** Exact-tie fraction over the paired deltas; null when there are no pairs. */\n tieFraction: number | null\n /** Point estimate of the DECIDING statistic, in the caller's native units. */\n delta: number\n /** Lower bound of the DECIDING interval, native units. */\n low: number\n /** Upper bound of the DECIDING interval, native units. */\n high: number\n /** The bootstrap that decided, or null when the score interval did. Callers\n * that need a bootstrap as a diagnostic on the two-point path compute their\n * own — it is not computed here, so the binary path costs no resamples. */\n bootstrap: PairedBootstrapResult | null\n /** McNemar's exact evidence, or null off the two-point path. */\n mcnemar: PairedMcNemarEvidence | null\n /** Exact one-sided sign-test p-value on the small-sample bootstrap path;\n * null otherwise. */\n pValue: number | null\n /** Effective observation minimum for the target, confidence, and caller floor. */\n minimumPairs: number\n /** n >= minimumPairs. */\n sufficient: boolean\n /** The deciding interval is zero-width at numeric precision or non-finite — no evidence in either\n * direction, so it cannot clear any threshold on evidence. */\n indeterminate: boolean\n /** McNemar's exact test refuses at a non-negative threshold. */\n exactTestVetoes: boolean\n /** The deciding interval clears the threshold, ignoring the other two guards. */\n clearsThreshold: boolean\n /** `sufficient && !indeterminate && clearsThreshold && !exactTestVetoes` —\n * the whole rule. */\n promote: boolean\n /** What `delta` measures, for a reason string. */\n label: 'success-rate' | 'mean' | 'median'\n /** Why a zero-width interval is zero-width; empty when it is not. */\n indeterminateCause: string\n /** Sentence naming the test when the exact sign test decided; else empty. */\n methodDetail: string\n}\n\n/** The shape facts that pick the estimator, without computing an interval. */\nexport interface PairedDecisionShape {\n statistic: PairedDecisionStatistic\n /** Declared or inferred positive binary level; null off the binary path. */\n binaryScale: number | null\n /** Exact-tie fraction over the paired deltas; null when there are no pairs. */\n tieFraction: number | null\n}\n\n/**\n * Which estimator {@link decidePairedPromotion} would use on this data, and the\n * shape facts behind it — for callers that must report the shape on a path\n * where no interval is computed at all (an early rejection, or zero pairs).\n * Cheap: no bootstrap, no interval.\n */\nexport function pairedDecisionShape(\n before: number[],\n after: number[],\n statistic: 'mean' | 'median' = 'mean',\n declaredBinaryScale?: number,\n): PairedDecisionShape {\n if (declaredBinaryScale !== undefined) {\n if (!Number.isFinite(declaredBinaryScale) || declaredBinaryScale <= 0) {\n throw new Error('pairedDecisionShape: binaryScale must be finite and positive')\n }\n if (statistic === 'median') {\n throw new Error('pairedDecisionShape: binaryScale requires the mean statistic, not median')\n }\n for (const [name, arm] of [\n ['before', before],\n ['after', after],\n ] as const) {\n for (let i = 0; i < arm.length; i++) {\n const value = arm[i]!\n if (value !== 0 && value !== declaredBinaryScale) {\n throw new Error(\n `pairedDecisionShape: ${name}[${i}] must be 0 or binaryScale (${declaredBinaryScale}); got ${value}`,\n )\n }\n }\n }\n }\n const tieFraction = before.length === 0 ? null : pairedDeltaTieFraction(before, after)\n if (statistic === 'median') {\n return { statistic: 'median_bootstrap', binaryScale: null, tieFraction }\n }\n const binaryScale = declaredBinaryScale ?? pairedBinaryScale(before, after)\n if (binaryScale !== null) {\n return { statistic: 'paired_risk_difference', binaryScale, tieFraction }\n }\n return { statistic: 'mean_bootstrap', binaryScale: null, tieFraction }\n}\n\n/**\n * Decide whether a paired candidate-minus-baseline delta clears a promotion\n * threshold. `before` is the baseline arm, `after` the candidate arm, paired by\n * position. Throws on unequal lengths.\n */\nexport function decidePairedPromotion(\n before: number[],\n after: number[],\n options: PairedPromotionDecisionOptions = {},\n): PairedPromotionDecision {\n if (before.length !== after.length) {\n throw new Error(\n `decidePairedPromotion: unequal sample sizes (${before.length} vs ${after.length})`,\n )\n }\n const threshold = options.threshold ?? 0\n if (!Number.isFinite(threshold)) {\n throw new Error(`decidePairedPromotion: threshold must be finite, got ${threshold}`)\n }\n const confidence = options.confidence ?? 0.95\n const exactMinimum = minimumPairsForPairedDeltaTest(confidence)\n const requestedMinimum = options.minPairs ?? exactMinimum\n if (!Number.isInteger(requestedMinimum) || requestedMinimum < 1) {\n throw new Error(\n `decidePairedPromotion: minPairs must be a positive integer, got ${requestedMinimum}`,\n )\n }\n const { binaryScale, tieFraction } = pairedDecisionShape(\n before,\n after,\n options.statistic,\n options.binaryScale,\n )\n const estimatorMinimum =\n binaryScale === null && options.statistic !== 'median' ? BOOTSTRAP_GATE_MIN_N : exactMinimum\n const minimumPairs = Math.max(requestedMinimum, exactMinimum, estimatorMinimum)\n const n = before.length\n const sufficient = n >= minimumPairs\n\n let core: {\n statistic: PairedDecisionStatistic\n method: PairedDecisionMethod\n delta: number\n low: number\n high: number\n bootstrap: PairedBootstrapResult | null\n mcnemar: PairedMcNemarEvidence | null\n pValue: number | null\n clearsThreshold: boolean\n label: PairedPromotionDecision['label']\n methodDetail: string\n }\n\n if (binaryScale !== null) {\n // Normalise the two-point encoding to {0,1} so the estimators see the\n // pass/fail structure, then rescale the answer back into the caller's\n // native units — the threshold is read in the units of the scores, so a\n // 0-100 pass/fail dimension must be gated in points, not in a rate.\n const unitControl = before.map((v) => v / binaryScale)\n const unitTreatment = after.map((v) => v / binaryScale)\n // TWO estimators with different jobs, because no single one does both.\n // `exact` is the authority on RD = 0 and supplies the veto; its\n // Clopper-Pearson interval conditions on the discordant count and is\n // therefore NOT a confidence interval at a nonzero margin. `score` is\n // Tango's, which is.\n const exact = pairedRiskDifferenceExact(unitControl, unitTreatment, confidence)\n const score = pairedRiskDifferenceScore(unitControl, unitTreatment, confidence)\n const low = score.lower * binaryScale\n core = {\n statistic: 'paired_risk_difference',\n method: 'score-interval',\n delta: score.riskDifference * binaryScale,\n low,\n high: score.upper * binaryScale,\n bootstrap: null,\n mcnemar: {\n b: exact.b,\n c: exact.c,\n nDiscordant: exact.nDiscordant,\n pValue: exact.pValue,\n },\n pValue: null,\n clearsThreshold: low > threshold,\n label: 'success-rate',\n methodDetail: '',\n }\n } else {\n const bootstrapStatistic = options.statistic === 'median' ? 'median' : 'mean'\n const test = pairedDeltaTest(before, after, {\n confidence,\n resamples: options.resamples,\n statistic: bootstrapStatistic,\n seed: options.seed,\n threshold,\n minPairs: minimumPairs,\n })\n const ci = test.bootstrap\n core = {\n statistic: bootstrapStatistic === 'mean' ? 'mean_bootstrap' : 'median_bootstrap',\n method: test.method,\n delta: bootstrapStatistic === 'mean' ? ci.mean : ci.median,\n low: ci.low,\n high: ci.high,\n bootstrap: ci,\n mcnemar: null,\n pValue: test.pValue,\n clearsThreshold: test.significant,\n label: bootstrapStatistic,\n methodDetail:\n test.method === 'exact-sign'\n ? bootstrapStatistic === 'mean'\n ? ` The mean requires ${minimumPairs} pairs for bootstrap eligibility;` +\n ` the exact sign-test p=${fmt(test.pValue ?? 1)} does not establish a mean effect.`\n : ` Below ${BOOTSTRAP_GATE_MIN_N} pairs the interval is descriptive only;` +\n ` the median decision uses the exact one-sided sign test, p=${fmt(test.pValue ?? 1)}.`\n : '',\n }\n }\n\n // Equivalent deltas can differ by rounding after subtraction and averaging.\n // Use the interval's own scale so tiny score units retain the same decision\n // as a rescaled copy of the evidence.\n const intervalScale = Math.max(Math.abs(core.low), Math.abs(core.high))\n const intervalTolerance = intervalScale * Number.EPSILON * 8\n const indeterminate =\n !Number.isFinite(core.low) ||\n !Number.isFinite(core.high) ||\n core.high - core.low <= intervalTolerance\n const indeterminateCause = !indeterminate\n ? ''\n : tieFraction === 1\n ? 'every paired delta is an exact tie'\n : core.mcnemar !== null && core.mcnemar.nDiscordant === 0\n ? 'every pair is concordant (0 discordant pairs)'\n : `the ${core.label} CI collapsed to a point at ${fmt(core.low)}`\n // Only at a non-negative threshold: a negative threshold asks a\n // noninferiority question, which McNemar's test of \"no difference\" does not\n // answer.\n const exactTestVetoes =\n core.mcnemar !== null && threshold >= 0 && !(core.mcnemar.pValue < 1 - confidence)\n\n return {\n n,\n threshold,\n confidence,\n binaryScale,\n tieFraction,\n minimumPairs,\n sufficient,\n indeterminate,\n indeterminateCause,\n exactTestVetoes,\n promote: sufficient && !indeterminate && core.clearsThreshold && !exactTestVetoes,\n ...core,\n }\n}\n\nfunction fmt(x: number): string {\n return x.toFixed(4)\n}\n"],"mappings":"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"}
|
package/dist/pipelines/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as budgetBreachView, i as failureClusterView, n as computeToolUseMetrics, r as judgeAgreementView, t as toolWasteView } from "../tool-waste-
|
|
1
|
+
import { a as budgetBreachView, i as failureClusterView, n as computeToolUseMetrics, r as judgeAgreementView, t as toolWasteView } from "../tool-waste-nbHPAxei.js";
|
|
2
2
|
import { t as compareToBaseline } from "../baseline-BC-eBZ7U.js";
|
|
3
3
|
import { a as isToolSpan } from "../schema-CSf6qWgZ.js";
|
|
4
|
-
import { a as hasCapturedToolArgs, r as argHash, u as runMetricExtractor } from "../query-
|
|
4
|
+
import { a as hasCapturedToolArgs, r as argHash, u as runMetricExtractor } from "../query-DlV0pdx4.js";
|
|
5
5
|
import { t as buildTrajectory } from "../trajectory-D_7rLrvE.js";
|
|
6
6
|
import { t as executionTrackByLane } from "../execution-tracks-CpgFPpS5.js";
|
|
7
7
|
//#region src/pipelines/first-divergence.ts
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { request } from "node:http";
|
|
2
|
+
import { request as request$1 } from "node:https";
|
|
3
|
+
//#region src/analyst/prime-bridge-transport.ts
|
|
4
|
+
/**
|
|
5
|
+
* Default transport on node:http/node:https rather than fetch: undici's fixed
|
|
6
|
+
* response-header timeout kills prime calls that legitimately run past five
|
|
7
|
+
* minutes, so the request's AbortSignal is the only deadline.
|
|
8
|
+
*/
|
|
9
|
+
function nodeHttpPrimeBridgeTransport() {
|
|
10
|
+
return ({ url, body, signal }) => {
|
|
11
|
+
const target = new URL(url);
|
|
12
|
+
if (target.protocol !== "http:" && target.protocol !== "https:") throw new TypeError(`bridge URL must be http: or https:, got ${target.protocol}`);
|
|
13
|
+
const send = target.protocol === "https:" ? request$1 : request;
|
|
14
|
+
const encoded = JSON.stringify(body);
|
|
15
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
16
|
+
const req = send({
|
|
17
|
+
hostname: target.hostname,
|
|
18
|
+
port: target.port,
|
|
19
|
+
path: `${target.pathname}${target.search}`,
|
|
20
|
+
method: "POST",
|
|
21
|
+
headers: {
|
|
22
|
+
"content-type": "application/json",
|
|
23
|
+
"content-length": Buffer.byteLength(encoded)
|
|
24
|
+
},
|
|
25
|
+
signal
|
|
26
|
+
}, (res) => {
|
|
27
|
+
const chunks = [];
|
|
28
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
29
|
+
res.on("end", () => resolvePromise({
|
|
30
|
+
status: res.statusCode ?? 0,
|
|
31
|
+
text: Buffer.concat(chunks).toString("utf8")
|
|
32
|
+
}));
|
|
33
|
+
res.on("error", rejectPromise);
|
|
34
|
+
});
|
|
35
|
+
req.on("error", rejectPromise);
|
|
36
|
+
req.end(encoded);
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { nodeHttpPrimeBridgeTransport as t };
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=prime-bridge-transport-Z3cpKGoV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prime-bridge-transport-Z3cpKGoV.js","names":["httpsRequest","httpRequest"],"sources":["../src/analyst/prime-bridge-transport.ts"],"sourcesContent":["import { request as httpRequest } from 'node:http'\nimport { request as httpsRequest } from 'node:https'\n\n/**\n * The bridge seam for the prime analyst protocol: one POST to an\n * OpenAI-compatible `/v1/chat/completions` endpoint, returning the raw status\n * and body text.\n *\n * Deliberately NOT `callLlm` from `../llm-client`, which serves a different\n * contract:\n * - it retries transient failures, and a prime turn holds a single model seat\n * for minutes — a silent second attempt doubles the seat time and the spend;\n * - it normalizes usage, while the protocol's receipt depends on the bridge's\n * non-standard `model_requests` and `estimated` fields;\n * - it composes sampling and response-format options the bridge's CLI backends\n * reject;\n * - it collapses HTTP status, unparseable body, and empty content into two\n * error classes, while the protocol classifies them as three distinct\n * terminal reasons.\n */\nexport interface PrimeBridgeTransportRequest {\n url: string\n body: {\n model: string\n messages: Array<{ role: 'user'; content: string }>\n }\n /**\n * The call's only deadline. The protocol aborts it on the per-call timeout\n * and on the caller's cancellation, so a transport that imposes a second\n * deadline of its own competes with this one.\n */\n signal: AbortSignal\n}\n\nexport interface PrimeBridgeTransportResult {\n status: number\n text: string\n}\n\n/** One POST to the bridge. Injectable so tests run against a fake bridge. */\nexport type PrimeBridgeTransport = (\n request: PrimeBridgeTransportRequest,\n) => Promise<PrimeBridgeTransportResult>\n\n/**\n * Default transport on node:http/node:https rather than fetch: undici's fixed\n * response-header timeout kills prime calls that legitimately run past five\n * minutes, so the request's AbortSignal is the only deadline.\n */\nexport function nodeHttpPrimeBridgeTransport(): PrimeBridgeTransport {\n return ({ url, body, signal }) => {\n const target = new URL(url)\n if (target.protocol !== 'http:' && target.protocol !== 'https:') {\n throw new TypeError(`bridge URL must be http: or https:, got ${target.protocol}`)\n }\n const send = target.protocol === 'https:' ? httpsRequest : httpRequest\n const encoded = JSON.stringify(body)\n return new Promise((resolvePromise, rejectPromise) => {\n const req = send(\n {\n hostname: target.hostname,\n port: target.port,\n // The query string is part of the caller's URL; dropping it would\n // send the request somewhere other than where the caller pointed.\n path: `${target.pathname}${target.search}`,\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n 'content-length': Buffer.byteLength(encoded),\n },\n signal,\n },\n (res) => {\n const chunks: Buffer[] = []\n res.on('data', (chunk: Buffer) => chunks.push(chunk))\n res.on('end', () =>\n resolvePromise({\n status: res.statusCode ?? 0,\n text: Buffer.concat(chunks).toString('utf8'),\n }),\n )\n res.on('error', rejectPromise)\n },\n )\n req.on('error', rejectPromise)\n req.end(encoded)\n })\n }\n}\n"],"mappings":";;;;;;;;AAiDA,SAAgB,+BAAqD;CACnE,QAAQ,EAAE,KAAK,MAAM,aAAa;EAChC,MAAM,SAAS,IAAI,IAAI,GAAG;EAC1B,IAAI,OAAO,aAAa,WAAW,OAAO,aAAa,UACrD,MAAM,IAAI,UAAU,2CAA2C,OAAO,UAAU;EAElF,MAAM,OAAO,OAAO,aAAa,WAAWA,YAAeC;EAC3D,MAAM,UAAU,KAAK,UAAU,IAAI;EACnC,OAAO,IAAI,SAAS,gBAAgB,kBAAkB;GACpD,MAAM,MAAM,KACV;IACE,UAAU,OAAO;IACjB,MAAM,OAAO;IAGb,MAAM,GAAG,OAAO,WAAW,OAAO;IAClC,QAAQ;IACR,SAAS;KACP,gBAAgB;KAChB,kBAAkB,OAAO,WAAW,OAAO;IAC7C;IACA;GACF,IACC,QAAQ;IACP,MAAM,SAAmB,CAAC;IAC1B,IAAI,GAAG,SAAS,UAAkB,OAAO,KAAK,KAAK,CAAC;IACpD,IAAI,GAAG,aACL,eAAe;KACb,QAAQ,IAAI,cAAc;KAC1B,MAAM,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,MAAM;IAC7C,CAAC,CACH;IACA,IAAI,GAAG,SAAS,aAAa;GAC/B,CACF;GACA,IAAI,GAAG,SAAS,aAAa;GAC7B,IAAI,IAAI,OAAO;EACjB,CAAC;CACH;AACF"}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { b as CustomTokenPricing } from "./cost-ledger-DbQdN3nO.js";
|
|
2
|
+
import { f as AnalystUsageReceipt } from "./types-BjB2wZM9.js";
|
|
3
|
+
import { t as PrimeBridgeTransport } from "./prime-bridge-transport-6feEglLf.js";
|
|
4
|
+
//#region src/analyst/reply-contract.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* The reply grammar an analyst arm holds a model to, independent of transport.
|
|
7
|
+
*
|
|
8
|
+
* One contract serves every arm shape: the inline bridge protocol
|
|
9
|
+
* (`runPrimeExchange`) reads the base fields, and one-shot JSON arms
|
|
10
|
+
* additionally use the strict-envelope and all-rejected knobs. `PrimeReplyContract`
|
|
11
|
+
* in ./prime-protocol is a type alias of this contract, so a consumer written
|
|
12
|
+
* against the prime protocol names the same grammar object.
|
|
13
|
+
*/
|
|
14
|
+
/** Verdict of decoding one raw reply row. */
|
|
15
|
+
type ReplyRowDecoded<TRow> = {
|
|
16
|
+
ok: true;
|
|
17
|
+
row: TRow;
|
|
18
|
+
} | {
|
|
19
|
+
ok: false;
|
|
20
|
+
reason: string;
|
|
21
|
+
};
|
|
22
|
+
/** A strictly parsed reply envelope: the row array plus retained extras. */
|
|
23
|
+
interface ReplyEnvelope {
|
|
24
|
+
rows: readonly unknown[];
|
|
25
|
+
/** Envelope fields beside the rows the arm retains (e.g. a `report` string). */
|
|
26
|
+
extras: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
interface ReplyContract<TRow> {
|
|
29
|
+
/** Name of the reply's row array, e.g. `blocks` or `findings`. */
|
|
30
|
+
rowsField: string;
|
|
31
|
+
/** Row-grammar lines spliced into the first-turn prompt. */
|
|
32
|
+
contractLines: readonly string[];
|
|
33
|
+
/**
|
|
34
|
+
* The same grammar restated for the repair turn, which never carries the
|
|
35
|
+
* evidence. Empty when the arm declares zero repair turns.
|
|
36
|
+
*/
|
|
37
|
+
repairContractLines: readonly string[];
|
|
38
|
+
/**
|
|
39
|
+
* Validate and convert one raw row in a single pass. One function rather than
|
|
40
|
+
* a separate validator and constructor, so the two can never disagree about
|
|
41
|
+
* what a valid row is.
|
|
42
|
+
*/
|
|
43
|
+
decodeRow(row: unknown, index: number): ReplyRowDecoded<TRow>;
|
|
44
|
+
/**
|
|
45
|
+
* Cap on ACCEPTED rows. The cap is applied after decoding, so malformed rows
|
|
46
|
+
* never consume an accepted slot; the surplus is reported as `overflow`.
|
|
47
|
+
* Omit when the consumer's own expansion owns the cap and records the drop.
|
|
48
|
+
*/
|
|
49
|
+
maxRows?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Strict envelope parse for one-shot JSON arms. Throws on an envelope defect
|
|
52
|
+
* (missing report, unknown key, over-cap row count). When absent, rows are
|
|
53
|
+
* read from `rowsField` on the parsed reply object.
|
|
54
|
+
*/
|
|
55
|
+
parseEnvelope?(value: unknown): ReplyEnvelope;
|
|
56
|
+
/**
|
|
57
|
+
* What a reply whose EVERY reported row was rejected means. `fail` throws a
|
|
58
|
+
* validation error carrying each rejection; `accept-empty` (the default)
|
|
59
|
+
* keeps the honest empty result beside the recorded rejections.
|
|
60
|
+
*/
|
|
61
|
+
whenAllRowsRejected?: 'fail' | 'accept-empty';
|
|
62
|
+
/**
|
|
63
|
+
* Message prefix for the `fail` case, in the contract's own row vocabulary
|
|
64
|
+
* (e.g. "every reported failure block was malformed").
|
|
65
|
+
*/
|
|
66
|
+
allRejectedMessage?: string;
|
|
67
|
+
}
|
|
68
|
+
/** One rejected row, indexed as the model reported it. */
|
|
69
|
+
interface ReplyRowRejection {
|
|
70
|
+
index: number;
|
|
71
|
+
reason: string;
|
|
72
|
+
}
|
|
73
|
+
interface DecodedReply<TRow> {
|
|
74
|
+
rows: TRow[];
|
|
75
|
+
/** Envelope fields beside the rows (empty when the contract has no envelope). */
|
|
76
|
+
extras: Record<string, unknown>;
|
|
77
|
+
rejected: ReplyRowRejection[];
|
|
78
|
+
/** Rows the model reported, before decoding or the count cap. */
|
|
79
|
+
reportedRows: number;
|
|
80
|
+
/** Valid rows dropped by `maxRows`. */
|
|
81
|
+
overflow: number;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Decode a parsed reply value under a contract: strict envelope when declared,
|
|
85
|
+
* then per-row decoding, then the all-rejected policy.
|
|
86
|
+
*/
|
|
87
|
+
declare function decodeReplyRows<TRow>(contract: ReplyContract<TRow>, value: unknown): DecodedReply<TRow>;
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/analyst/prime-protocol.d.ts
|
|
90
|
+
/**
|
|
91
|
+
* The prime analyst protocol: a one-shot RLM reached through an
|
|
92
|
+
* OpenAI-compatible bridge, given the whole trajectory inline because it has no
|
|
93
|
+
* REPL and no trace tools, answering in one fenced JSON block of short strings.
|
|
94
|
+
*
|
|
95
|
+
* This module owns every part of that protocol that does not depend on what the
|
|
96
|
+
* rows MEAN: prompt and contract composition, the bounded repair turn, reply
|
|
97
|
+
* extraction, row decoding order, the render-measure-fall-back-fail-loud
|
|
98
|
+
* projection ladder, usage normalization, and the protocol identity digest.
|
|
99
|
+
*
|
|
100
|
+
* The cut: the core speaks RAW ROWS and never names a finding type. It knows a
|
|
101
|
+
* prime reply carries an `answer` string plus an array of rows under a named
|
|
102
|
+
* field, and that each row is decoded by a caller-supplied function. Consumers
|
|
103
|
+
* — the CodeTraceBench benchmark runner here, a span-grounded trace analyzer
|
|
104
|
+
* elsewhere — map decoded rows into their own finding shape on the way out. So
|
|
105
|
+
* nothing in this file may import a block type, a finding type, or a trace
|
|
106
|
+
* store, and no consumer needs another copy of the protocol.
|
|
107
|
+
*/
|
|
108
|
+
/**
|
|
109
|
+
* The prime reply grammar is the general analyst reply contract: these aliases
|
|
110
|
+
* keep every prime-protocol consumer compiling against the shared type in
|
|
111
|
+
* ./reply-contract. The exchange below reads the base fields (`rowsField`,
|
|
112
|
+
* contract lines, `decodeRow`, `maxRows`); the strict-envelope knobs serve
|
|
113
|
+
* one-shot JSON arms and are inert here.
|
|
114
|
+
*/
|
|
115
|
+
type PrimeRowDecoded<TRow> = ReplyRowDecoded<TRow>;
|
|
116
|
+
type PrimeReplyContract<TRow> = ReplyContract<TRow>;
|
|
117
|
+
interface PrimePromptSpec {
|
|
118
|
+
question: string;
|
|
119
|
+
/** Task definition spliced under a `TASK DEFINITION:` heading. Omit when the question is the whole task. */
|
|
120
|
+
taskDefinition?: string;
|
|
121
|
+
contractLines: readonly string[];
|
|
122
|
+
/** Line introducing the trajectory, e.g. `TRAJECTORY (trace_id X; 12 assistant step spans; ...):`. */
|
|
123
|
+
trajectoryHeader: string;
|
|
124
|
+
renderedTrajectory: string;
|
|
125
|
+
/** Material appended after the trajectory, e.g. the final-verification spans. */
|
|
126
|
+
trailer?: string;
|
|
127
|
+
}
|
|
128
|
+
declare function buildPrimePrompt(spec: PrimePromptSpec): string;
|
|
129
|
+
interface PrimeRepairPromptSpec {
|
|
130
|
+
defect: string;
|
|
131
|
+
previousReply: string;
|
|
132
|
+
repairContractLines: readonly string[];
|
|
133
|
+
}
|
|
134
|
+
/** Carries the malformed reply and the contract — never the trajectory. */
|
|
135
|
+
declare function buildPrimeRepairPrompt(spec: PrimeRepairPromptSpec): string;
|
|
136
|
+
/**
|
|
137
|
+
* Recover the reply's JSON object.
|
|
138
|
+
*
|
|
139
|
+
* Distinct from `extractJsonPayload` in ../llm-client, which serves a response
|
|
140
|
+
* that DECLARES a JSON root and therefore must not scan onward. A prime reply
|
|
141
|
+
* is prose plus a fenced block, and when the model emits several fences the
|
|
142
|
+
* last one is its answer — so fences are scanned in reverse, and only then is a
|
|
143
|
+
* brace-to-brace slice tried.
|
|
144
|
+
*/
|
|
145
|
+
declare function extractPrimeJsonObject(text: string): Record<string, unknown> | null;
|
|
146
|
+
/** Why the reply cannot be read as a prime answer, or null when it can. */
|
|
147
|
+
declare function primeReplyDefect(parsed: Record<string, unknown> | null, rowsField: string): string | null;
|
|
148
|
+
/**
|
|
149
|
+
* Token accounting exactly as the bridge reported it. Lossless on purpose: a
|
|
150
|
+
* side the bridge did not report stays null rather than becoming a zero, and a
|
|
151
|
+
* side it DID report survives even when its partner is missing.
|
|
152
|
+
*/
|
|
153
|
+
interface PrimeRawUsage {
|
|
154
|
+
/**
|
|
155
|
+
* Model-usage records the bridge observed. NOT a count of bridge round trips:
|
|
156
|
+
* one prime turn routes several internal model calls, so a single turn
|
|
157
|
+
* typically reports 3-5.
|
|
158
|
+
*/
|
|
159
|
+
calls: number | null;
|
|
160
|
+
/** Prompt tokens the bridge reported; null when it reported none. */
|
|
161
|
+
inputTokens: number | null;
|
|
162
|
+
/** Completion tokens the bridge reported; null when it reported none. */
|
|
163
|
+
outputTokens: number | null;
|
|
164
|
+
/**
|
|
165
|
+
* True when the bridge DERIVED the counts (from character lengths) because
|
|
166
|
+
* the backend reported no usage of its own. Pricing derived counts produces a
|
|
167
|
+
* guess about a guess, which a reader must be able to tell apart from a
|
|
168
|
+
* rate-estimated cost over exact tokens.
|
|
169
|
+
*/
|
|
170
|
+
bridgeEstimated: boolean;
|
|
171
|
+
}
|
|
172
|
+
declare function emptyPrimeRawUsage(): PrimeRawUsage;
|
|
173
|
+
/** Read the bridge's OpenAI-shaped `usage` object. */
|
|
174
|
+
declare function normalizePrimeUsage(raw: unknown): PrimeRawUsage;
|
|
175
|
+
/**
|
|
176
|
+
* Sum two turns. Each side poisons independently: two turns that both report
|
|
177
|
+
* input and neither report output yield a real input total beside a null
|
|
178
|
+
* output, because discarding a measured count is as wrong as inventing one.
|
|
179
|
+
*/
|
|
180
|
+
declare function mergePrimeRawUsage(a: PrimeRawUsage, b: PrimeRawUsage): PrimeRawUsage;
|
|
181
|
+
/**
|
|
182
|
+
* Bind raw prime usage to agent-eval's typed receipt.
|
|
183
|
+
*
|
|
184
|
+
* `RunTokenUsage.input` and `.output` are non-nullable, so a one-sided count
|
|
185
|
+
* cannot round-trip through `tokens` without writing a zero nobody measured.
|
|
186
|
+
* The complete-accounting field therefore stays null, the reported side is
|
|
187
|
+
* carried verbatim in `partialTokens`, and its price becomes the receipt's
|
|
188
|
+
* `knownCostUsd` lower bound.
|
|
189
|
+
*
|
|
190
|
+
* Only agent-eval calls this; consumers with no pricing table read
|
|
191
|
+
* `PrimeRawUsage` directly.
|
|
192
|
+
*/
|
|
193
|
+
declare function analystUsageReceiptFromPrimeUsage(usage: PrimeRawUsage, pricing: CustomTokenPricing): AnalystUsageReceipt;
|
|
194
|
+
/**
|
|
195
|
+
* Why an exchange ended without a readable reply. `deadline` and `aborted` are
|
|
196
|
+
* separate members from `transport` on purpose: a model that ran past its
|
|
197
|
+
* deadline, a caller who cancelled, and a bridge that refused the connection
|
|
198
|
+
* demand three different responses, and a record that conflates them cannot be
|
|
199
|
+
* acted on.
|
|
200
|
+
*/
|
|
201
|
+
type PrimeFailure = {
|
|
202
|
+
kind: 'transport' | 'unparseable-json' | 'no-content' | 'deadline' | 'malformed-reply';
|
|
203
|
+
message: string;
|
|
204
|
+
} | {
|
|
205
|
+
kind: 'http-status';
|
|
206
|
+
message: string;
|
|
207
|
+
status: number;
|
|
208
|
+
bodySnippet: string;
|
|
209
|
+
} | {
|
|
210
|
+
kind: 'aborted';
|
|
211
|
+
message: string;
|
|
212
|
+
cause: unknown;
|
|
213
|
+
};
|
|
214
|
+
interface PrimeRepairState {
|
|
215
|
+
attempted: boolean;
|
|
216
|
+
/** Null when no repair turn ran, or when the repair turn never returned a reply. */
|
|
217
|
+
succeeded: boolean | null;
|
|
218
|
+
}
|
|
219
|
+
/** One completed bridge turn. A turn that failed produces no record. */
|
|
220
|
+
interface PrimeTurnRecord {
|
|
221
|
+
turn: 'first' | 'repair';
|
|
222
|
+
usage: PrimeRawUsage;
|
|
223
|
+
/** The reply's `usage` object verbatim; null when the bridge sent none. */
|
|
224
|
+
rawUsage: unknown;
|
|
225
|
+
}
|
|
226
|
+
interface PrimeRejectedRow {
|
|
227
|
+
index: number;
|
|
228
|
+
reason: string;
|
|
229
|
+
}
|
|
230
|
+
type PrimeExchangeOutcome<TRow> = {
|
|
231
|
+
ok: true;
|
|
232
|
+
/** The reply's `answer` field; null when absent or not a string. */
|
|
233
|
+
answer: string | null;
|
|
234
|
+
rows: TRow[];
|
|
235
|
+
rejected: PrimeRejectedRow[];
|
|
236
|
+
/** Rows the model reported, before decoding or the count cap. */
|
|
237
|
+
reportedRows: number;
|
|
238
|
+
/** Valid rows dropped by `contract.maxRows`. */
|
|
239
|
+
overflow: number;
|
|
240
|
+
usage: PrimeRawUsage;
|
|
241
|
+
turns: PrimeTurnRecord[];
|
|
242
|
+
repair: PrimeRepairState;
|
|
243
|
+
reply: string;
|
|
244
|
+
} | {
|
|
245
|
+
ok: false;
|
|
246
|
+
failure: PrimeFailure;
|
|
247
|
+
usage: PrimeRawUsage;
|
|
248
|
+
turns: PrimeTurnRecord[];
|
|
249
|
+
repair: PrimeRepairState;
|
|
250
|
+
/** The last reply received, when one arrived — the diagnostic artifact for a malformed case. */
|
|
251
|
+
reply?: string;
|
|
252
|
+
};
|
|
253
|
+
interface PrimeExchangeOptions<TRow> {
|
|
254
|
+
contract: PrimeReplyContract<TRow>;
|
|
255
|
+
prompt: string;
|
|
256
|
+
transport: PrimeBridgeTransport;
|
|
257
|
+
/** Full endpoint, e.g. `http://localhost:4181/v1/chat/completions`. */
|
|
258
|
+
url: string;
|
|
259
|
+
model: string;
|
|
260
|
+
/** Deadline for ONE turn. Prime analyses routinely exceed five minutes. */
|
|
261
|
+
timeoutMs: number;
|
|
262
|
+
/** Whether a structurally malformed reply gets one bounded repair turn. */
|
|
263
|
+
repair: boolean;
|
|
264
|
+
signal?: AbortSignal;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Run the protocol: one call, one bounded repair turn on a structurally
|
|
268
|
+
* malformed reply, then decode. Zero valid rows from a well-formed reply is an
|
|
269
|
+
* honest null, not a failure.
|
|
270
|
+
*/
|
|
271
|
+
declare function runPrimeExchange<TRow>(options: PrimeExchangeOptions<TRow>): Promise<PrimeExchangeOutcome<TRow>>;
|
|
272
|
+
/**
|
|
273
|
+
* Where the inlined trajectory comes from. The protocol needs only two moves —
|
|
274
|
+
* fetch it all, or fetch a reduced version — so no store, artifact path, or
|
|
275
|
+
* span type enters the shared signature.
|
|
276
|
+
*/
|
|
277
|
+
interface PrimeProjectionSource<TItem> {
|
|
278
|
+
/** The full projection, or null when the source declares itself oversized. */
|
|
279
|
+
full(): Promise<readonly TItem[] | null>;
|
|
280
|
+
/** A reduced projection of the same material. */
|
|
281
|
+
capped(): Promise<readonly TItem[]>;
|
|
282
|
+
/** How `capped` reduces, named for the failure message, e.g. `per-attribute cap 1200`. */
|
|
283
|
+
cappedDescription: string;
|
|
284
|
+
}
|
|
285
|
+
interface PrimeProjectionDelivery {
|
|
286
|
+
mode: 'inline-json';
|
|
287
|
+
fetch: 'full' | 'capped';
|
|
288
|
+
renderedChars: number;
|
|
289
|
+
}
|
|
290
|
+
type PrimeProjectionOutcome<TItem> = {
|
|
291
|
+
ok: true;
|
|
292
|
+
items: readonly TItem[];
|
|
293
|
+
rendered: string;
|
|
294
|
+
delivery: PrimeProjectionDelivery;
|
|
295
|
+
} | {
|
|
296
|
+
ok: false;
|
|
297
|
+
reason: string;
|
|
298
|
+
renderedChars: number;
|
|
299
|
+
};
|
|
300
|
+
/**
|
|
301
|
+
* Render, measure, fall back to the capped projection, re-measure, fail loud.
|
|
302
|
+
*
|
|
303
|
+
* Inline is the only delivery prime has, so an oversized trajectory is a
|
|
304
|
+
* refusal rather than a silent truncation: dropping spans would understate the
|
|
305
|
+
* trajectory and the analyst would answer a question about a different run.
|
|
306
|
+
*/
|
|
307
|
+
declare function projectPrimeTrajectory<TItem>(source: PrimeProjectionSource<TItem>, limits: {
|
|
308
|
+
maxInlineChars: number;
|
|
309
|
+
}): Promise<PrimeProjectionOutcome<TItem>>;
|
|
310
|
+
interface PrimeProtocolIdentity {
|
|
311
|
+
question: string;
|
|
312
|
+
taskDefinition?: string;
|
|
313
|
+
contractLines: readonly string[];
|
|
314
|
+
repairContractLines: readonly string[];
|
|
315
|
+
/** Numeric limits the contract states, e.g. row and width caps. */
|
|
316
|
+
limits: Readonly<Record<string, number>>;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Digest of everything a consumer can send to the bridge under the prime
|
|
320
|
+
* protocol, recorded per observation so a prime result names the exact contract
|
|
321
|
+
* that produced it.
|
|
322
|
+
*
|
|
323
|
+
* Computed over the ACTUALLY composed contract, so two consumers that both
|
|
324
|
+
* stamp `analyst_id: 'prime'` while asking materially different questions get
|
|
325
|
+
* different digests by construction. That is what makes 'prime' a reproducible
|
|
326
|
+
* claim rather than a label.
|
|
327
|
+
*/
|
|
328
|
+
declare function primeProtocolSha256(identity: PrimeProtocolIdentity): string;
|
|
329
|
+
//#endregion
|
|
330
|
+
export { ReplyRowDecoded as A, primeProtocolSha256 as C, DecodedReply as D, runPrimeExchange as E, decodeReplyRows as M, ReplyContract as O, normalizePrimeUsage as S, projectPrimeTrajectory as T, buildPrimePrompt as _, PrimeProjectionOutcome as a, extractPrimeJsonObject as b, PrimeProtocolIdentity as c, PrimeRepairPromptSpec as d, PrimeRepairState as f, analystUsageReceiptFromPrimeUsage as g, PrimeTurnRecord as h, PrimeProjectionDelivery as i, ReplyRowRejection as j, ReplyEnvelope as k, PrimeRawUsage as l, PrimeRowDecoded as m, PrimeExchangeOutcome as n, PrimeProjectionSource as o, PrimeReplyContract as p, PrimeFailure as r, PrimePromptSpec as s, PrimeExchangeOptions as t, PrimeRejectedRow as u, buildPrimeRepairPrompt as v, primeReplyDefect as w, mergePrimeRawUsage as x, emptyPrimeRawUsage as y };
|
|
331
|
+
//# sourceMappingURL=prime-protocol-CDBcL9NM.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prime-protocol-CDBcL9NM.d.ts","names":[],"sources":["../src/analyst/reply-contract.ts","../src/analyst/prime-protocol.ts"],"mappings":";;;;;;;;;;;;;;KAaY,gBAAgB;EAAU;EAAU,KAAK;;EAAW;EAAW;;;UAG1D;EACf;;EAEA,QAAQ;;UAGO,cAAc;;EAE7B;;EAEA;;;;;EAKA;;;;;;EAMA,UAAU,cAAc,gBAAgB,gBAAgB;;;;;;EAMxD;;;;;;EAMA,eAAe,iBAAiB;;;;;;EAMhC;;;;;EAKA;;;UAIe;EACf;EACA;;UAGe,aAAa;EAC5B,MAAM;;EAEN,QAAQ;EACR,UAAU;;EAEV;;EAEA;;;;;;iBAmCc,gBAAgB,MAC9B,UAAU,cAAc,OACxB,iBACC,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;KCjFJ,gBAAgB,QAAQ,gBAAgB;KAExC,mBAAmB,QAAQ,cAAc;UAIpC;EACf;;EAEA;EACA;;EAEA;EACA;;EAEA;;iBAGc,iBAAiB,MAAM;UAatB;EACf;EACA;EACA;;;iBAIc,uBAAuB,MAAM;;;;;;;;;;iBAuB7B,uBAAuB,eAAe;;iBAkBtC,iBACd,QAAQ,gCACR;;;;;;UAyBe;;;;;;EAMf;;EAEA;;EAEA;;;;;;;EAOA;;iBAGc,sBAAsB;;iBAKtB,oBAAoB,eAAe;;;;;;iBAgBnC,mBAAmB,GAAG,eAAe,GAAG,gBAAgB;;;;;;;;;;;;;iBA6BxD,kCACd,OAAO,eACP,SAAS,qBACR;;;;;;;;KAqCS;EAEN;EACA;;EAEA;EAAqB;EAAiB;EAAgB;;EACtD;EAAiB;EAAiB;;UAEvB;EACf;;EAEA;;;UAIe;EACf;EACA,OAAO;;EAEP;;UAGe;EACf;EACA;;KAGU,qBAAqB;EAE3B;;EAEA;EACA,MAAM;EACN,UAAU;;EAEV;;EAEA;EACA,OAAO;EACP,OAAO;EACP,QAAQ;EACR;;EAGA;EACA,SAAS;EACT,OAAO;EACP,OAAO;EACP,QAAQ;;EAER;;UAGW,qBAAqB;EACpC,UAAU,mBAAmB;EAC7B;EACA,WAAW;;EAEX;EACA;;EAEA;;EAEA;EACA,SAAS;;;;;;;iBAQW,iBAAiB,MACrC,SAAS,qBAAqB,QAC7B,QAAQ,qBAAqB;;;;;;UAyLf,sBAAsB;;EAErC,QAAQ,iBAAiB;;EAEzB,UAAU,iBAAiB;;EAE3B;;UAGe;EACf;EACA;EACA;;KAGU,uBAAuB;EAE7B;EACA,gBAAgB;EAChB;EACA,UAAU;;EAEV;EAAW;EAAgB;;;;;;;;;iBASX,uBAAuB,OAC3C,QAAQ,sBAAsB,QAC9B;EAAU;IACT,QAAQ,uBAAuB;UA8BjB;EACf;EACA;EACA;EACA;;EAEA,QAAQ,SAAS;;;;;;;;;;;;iBAaH,oBAAoB,UAAU"}
|
|
@@ -1,26 +1,5 @@
|
|
|
1
1
|
import { s as ValidationError } from "./errors-Dngq5h35.js";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
//#region src/analyst/equal-terms.ts
|
|
4
|
-
/**
|
|
5
|
-
* Refuses a comparison whose arms are not on equal terms: an empty set, a
|
|
6
|
-
* duplicated id, or unequal repair turns — a retry is a second sample the
|
|
7
|
-
* other arms never got. `noun` names the arm kind in every message so a
|
|
8
|
-
* refusal reads in the caller's vocabulary.
|
|
9
|
-
*/
|
|
10
|
-
function assertEqualDeclarativeTerms(noun, terms) {
|
|
11
|
-
if (terms.length === 0) throw new ValidationError(`a ${noun} comparison needs at least one ${noun}`);
|
|
12
|
-
const ids = terms.map((term) => term.id);
|
|
13
|
-
const duplicate = ids.find((id, index) => ids.indexOf(id) !== index);
|
|
14
|
-
if (duplicate !== void 0) throw new ValidationError(`${noun} '${duplicate}' is declared twice`);
|
|
15
|
-
const repairTurns = terms[0].repairTurns;
|
|
16
|
-
const unequal = terms.find((term) => term.repairTurns !== repairTurns);
|
|
17
|
-
if (unequal) throw new ValidationError(`${noun} '${unequal.id}' gets ${unequal.repairTurns} bounded repair turns and ${noun} '${terms[0].id}' gets ${repairTurns}; a retry is a second sample the other arms never got`);
|
|
18
|
-
return {
|
|
19
|
-
ids,
|
|
20
|
-
repairTurns
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
//#endregion
|
|
24
3
|
//#region src/analyst/reply-contract.ts
|
|
25
4
|
/**
|
|
26
5
|
* The reply grammar an analyst arm holds a model to, independent of transport.
|
|
@@ -499,6 +478,6 @@ function primeProtocolSha256(identity) {
|
|
|
499
478
|
})).digest("hex");
|
|
500
479
|
}
|
|
501
480
|
//#endregion
|
|
502
|
-
export { extractPrimeJsonObject as a, primeProtocolSha256 as c, runPrimeExchange as d, decodeReplyRows as f, emptyPrimeRawUsage as i, primeReplyDefect as l, buildPrimePrompt as n, mergePrimeRawUsage as o,
|
|
481
|
+
export { extractPrimeJsonObject as a, primeProtocolSha256 as c, runPrimeExchange as d, decodeReplyRows as f, emptyPrimeRawUsage as i, primeReplyDefect as l, buildPrimePrompt as n, mergePrimeRawUsage as o, buildPrimeRepairPrompt as r, normalizePrimeUsage as s, analystUsageReceiptFromPrimeUsage as t, projectPrimeTrajectory as u };
|
|
503
482
|
|
|
504
|
-
//# sourceMappingURL=prime-protocol-
|
|
483
|
+
//# sourceMappingURL=prime-protocol-DcAK9pC8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prime-protocol-DcAK9pC8.js","names":[],"sources":["../src/analyst/reply-contract.ts","../src/analyst/prime-protocol.ts"],"sourcesContent":["/**\n * The reply grammar an analyst arm holds a model to, independent of transport.\n *\n * One contract serves every arm shape: the inline bridge protocol\n * (`runPrimeExchange`) reads the base fields, and one-shot JSON arms\n * additionally use the strict-envelope and all-rejected knobs. `PrimeReplyContract`\n * in ./prime-protocol is a type alias of this contract, so a consumer written\n * against the prime protocol names the same grammar object.\n */\n\nimport { ValidationError } from '../errors'\n\n/** Verdict of decoding one raw reply row. */\nexport type ReplyRowDecoded<TRow> = { ok: true; row: TRow } | { ok: false; reason: string }\n\n/** A strictly parsed reply envelope: the row array plus retained extras. */\nexport interface ReplyEnvelope {\n rows: readonly unknown[]\n /** Envelope fields beside the rows the arm retains (e.g. a `report` string). */\n extras: Record<string, unknown>\n}\n\nexport interface ReplyContract<TRow> {\n /** Name of the reply's row array, e.g. `blocks` or `findings`. */\n rowsField: string\n /** Row-grammar lines spliced into the first-turn prompt. */\n contractLines: readonly string[]\n /**\n * The same grammar restated for the repair turn, which never carries the\n * evidence. Empty when the arm declares zero repair turns.\n */\n repairContractLines: readonly string[]\n /**\n * Validate and convert one raw row in a single pass. One function rather than\n * a separate validator and constructor, so the two can never disagree about\n * what a valid row is.\n */\n decodeRow(row: unknown, index: number): ReplyRowDecoded<TRow>\n /**\n * Cap on ACCEPTED rows. The cap is applied after decoding, so malformed rows\n * never consume an accepted slot; the surplus is reported as `overflow`.\n * Omit when the consumer's own expansion owns the cap and records the drop.\n */\n maxRows?: number\n /**\n * Strict envelope parse for one-shot JSON arms. Throws on an envelope defect\n * (missing report, unknown key, over-cap row count). When absent, rows are\n * read from `rowsField` on the parsed reply object.\n */\n parseEnvelope?(value: unknown): ReplyEnvelope\n /**\n * What a reply whose EVERY reported row was rejected means. `fail` throws a\n * validation error carrying each rejection; `accept-empty` (the default)\n * keeps the honest empty result beside the recorded rejections.\n */\n whenAllRowsRejected?: 'fail' | 'accept-empty'\n /**\n * Message prefix for the `fail` case, in the contract's own row vocabulary\n * (e.g. \"every reported failure block was malformed\").\n */\n allRejectedMessage?: string\n}\n\n/** One rejected row, indexed as the model reported it. */\nexport interface ReplyRowRejection {\n index: number\n reason: string\n}\n\nexport interface DecodedReply<TRow> {\n rows: TRow[]\n /** Envelope fields beside the rows (empty when the contract has no envelope). */\n extras: Record<string, unknown>\n rejected: ReplyRowRejection[]\n /** Rows the model reported, before decoding or the count cap. */\n reportedRows: number\n /** Valid rows dropped by `maxRows`. */\n overflow: number\n}\n\n/**\n * The per-row half of a decode: validate each raw row under the contract's\n * grammar and cap ACCEPTED rows. Shape before count — a malformed row never\n * consumes an accepted slot. Shared by every consumer of a `ReplyContract`\n * row array, whatever envelope handling surrounds it.\n */\nexport function decodeContractRows<TRow>(\n contract: Pick<ReplyContract<TRow>, 'decodeRow' | 'maxRows'>,\n rawRows: readonly unknown[],\n): { rows: TRow[]; rejected: ReplyRowRejection[]; overflow: number } {\n const rows: TRow[] = []\n const rejected: ReplyRowRejection[] = []\n let overflow = 0\n rawRows.forEach((row, index) => {\n const decoded = contract.decodeRow(row, index)\n if (!decoded.ok) {\n rejected.push({ index, reason: decoded.reason })\n return\n }\n if (contract.maxRows !== undefined && rows.length >= contract.maxRows) {\n overflow += 1\n return\n }\n rows.push(decoded.row)\n })\n return { rows, rejected, overflow }\n}\n\n/**\n * Decode a parsed reply value under a contract: strict envelope when declared,\n * then per-row decoding, then the all-rejected policy.\n */\nexport function decodeReplyRows<TRow>(\n contract: ReplyContract<TRow>,\n value: unknown,\n): DecodedReply<TRow> {\n let rawRows: readonly unknown[]\n let extras: Record<string, unknown> = {}\n if (contract.parseEnvelope) {\n const envelope = contract.parseEnvelope(value)\n rawRows = envelope.rows\n extras = envelope.extras\n } else {\n const record =\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n const field = record?.[contract.rowsField]\n if (!Array.isArray(field)) {\n throw new ValidationError(`reply has no \"${contract.rowsField}\" array`)\n }\n rawRows = field\n }\n const { rows, rejected, overflow } = decodeContractRows(contract, rawRows)\n if (rows.length === 0 && rawRows.length > 0 && contract.whenAllRowsRejected === 'fail') {\n throw new ValidationError(\n `${contract.allRejectedMessage ?? 'every reported row was malformed'}: ${rejected\n .map((entry) => entry.reason)\n .join(' | ')}`,\n )\n }\n return { rows, extras, rejected, reportedRows: rawRows.length, overflow }\n}\n","import { createHash } from 'node:crypto'\nimport type { CustomTokenPricing } from '../cost-ledger'\nimport type { PrimeBridgeTransport, PrimeBridgeTransportResult } from './prime-bridge-transport'\nimport { decodeContractRows, type ReplyContract, type ReplyRowDecoded } from './reply-contract'\nimport type { AnalystUsageReceipt } from './types'\n\n/**\n * The prime analyst protocol: a one-shot RLM reached through an\n * OpenAI-compatible bridge, given the whole trajectory inline because it has no\n * REPL and no trace tools, answering in one fenced JSON block of short strings.\n *\n * This module owns every part of that protocol that does not depend on what the\n * rows MEAN: prompt and contract composition, the bounded repair turn, reply\n * extraction, row decoding order, the render-measure-fall-back-fail-loud\n * projection ladder, usage normalization, and the protocol identity digest.\n *\n * The cut: the core speaks RAW ROWS and never names a finding type. It knows a\n * prime reply carries an `answer` string plus an array of rows under a named\n * field, and that each row is decoded by a caller-supplied function. Consumers\n * — the CodeTraceBench benchmark runner here, a span-grounded trace analyzer\n * elsewhere — map decoded rows into their own finding shape on the way out. So\n * nothing in this file may import a block type, a finding type, or a trace\n * store, and no consumer needs another copy of the protocol.\n */\n\n// ── Reply contract ───────────────────────────────────────────────────\n\n/**\n * The prime reply grammar is the general analyst reply contract: these aliases\n * keep every prime-protocol consumer compiling against the shared type in\n * ./reply-contract. The exchange below reads the base fields (`rowsField`,\n * contract lines, `decodeRow`, `maxRows`); the strict-envelope knobs serve\n * one-shot JSON arms and are inert here.\n */\nexport type PrimeRowDecoded<TRow> = ReplyRowDecoded<TRow>\n\nexport type PrimeReplyContract<TRow> = ReplyContract<TRow>\n\n// ── Prompt composition ───────────────────────────────────────────────\n\nexport interface PrimePromptSpec {\n question: string\n /** Task definition spliced under a `TASK DEFINITION:` heading. Omit when the question is the whole task. */\n taskDefinition?: string\n contractLines: readonly string[]\n /** Line introducing the trajectory, e.g. `TRAJECTORY (trace_id X; 12 assistant step spans; ...):`. */\n trajectoryHeader: string\n renderedTrajectory: string\n /** Material appended after the trajectory, e.g. the final-verification spans. */\n trailer?: string\n}\n\nexport function buildPrimePrompt(spec: PrimePromptSpec): string {\n return [\n `QUESTION: ${spec.question}`,\n '',\n ...(spec.taskDefinition === undefined ? [] : ['TASK DEFINITION:', spec.taskDefinition, '']),\n ...spec.contractLines,\n '',\n spec.trajectoryHeader,\n spec.renderedTrajectory,\n ...(spec.trailer === undefined ? [] : ['', spec.trailer]),\n ].join('\\n')\n}\n\nexport interface PrimeRepairPromptSpec {\n defect: string\n previousReply: string\n repairContractLines: readonly string[]\n}\n\n/** Carries the malformed reply and the contract — never the trajectory. */\nexport function buildPrimeRepairPrompt(spec: PrimeRepairPromptSpec): string {\n return [\n 'Your previous reply to a trace-analysis task was structurally malformed and could not be parsed',\n `(${spec.defect}). Below is your previous reply verbatim. Re-emit ONLY the corrected JSON — one`,\n 'fenced ```json block, no other text, no tools. The JSON object has exactly two fields:',\n ...spec.repairContractLines,\n '',\n 'PREVIOUS REPLY:',\n spec.previousReply,\n ].join('\\n')\n}\n\n// ── Reply extraction ─────────────────────────────────────────────────\n\n/**\n * Recover the reply's JSON object.\n *\n * Distinct from `extractJsonPayload` in ../llm-client, which serves a response\n * that DECLARES a JSON root and therefore must not scan onward. A prime reply\n * is prose plus a fenced block, and when the model emits several fences the\n * last one is its answer — so fences are scanned in reverse, and only then is a\n * brace-to-brace slice tried.\n */\nexport function extractPrimeJsonObject(text: string): Record<string, unknown> | null {\n const direct = parsePrimeJsonObject(text)\n if (direct) return direct\n const fenced = [...text.matchAll(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/g)]\n for (let index = fenced.length - 1; index >= 0; index -= 1) {\n const candidate = parsePrimeJsonObject(fenced[index]![1]!)\n if (candidate) return candidate\n }\n const start = text.indexOf('{')\n const end = text.lastIndexOf('}')\n if (start >= 0 && end > start) {\n const candidate = parsePrimeJsonObject(text.slice(start, end + 1))\n if (candidate) return candidate\n }\n return null\n}\n\n/** Why the reply cannot be read as a prime answer, or null when it can. */\nexport function primeReplyDefect(\n parsed: Record<string, unknown> | null,\n rowsField: string,\n): string | null {\n if (parsed === null) return 'no parseable JSON object'\n if (!Array.isArray(parsed[rowsField])) return `JSON has no \"${rowsField}\" array`\n return null\n}\n\nfunction parsePrimeJsonObject(text: string): Record<string, unknown> | null {\n try {\n const value: unknown = JSON.parse(text.trim())\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null\n } catch {\n return null\n }\n}\n\n// ── Usage ────────────────────────────────────────────────────────────\n\n/**\n * Token accounting exactly as the bridge reported it. Lossless on purpose: a\n * side the bridge did not report stays null rather than becoming a zero, and a\n * side it DID report survives even when its partner is missing.\n */\nexport interface PrimeRawUsage {\n /**\n * Model-usage records the bridge observed. NOT a count of bridge round trips:\n * one prime turn routes several internal model calls, so a single turn\n * typically reports 3-5.\n */\n calls: number | null\n /** Prompt tokens the bridge reported; null when it reported none. */\n inputTokens: number | null\n /** Completion tokens the bridge reported; null when it reported none. */\n outputTokens: number | null\n /**\n * True when the bridge DERIVED the counts (from character lengths) because\n * the backend reported no usage of its own. Pricing derived counts produces a\n * guess about a guess, which a reader must be able to tell apart from a\n * rate-estimated cost over exact tokens.\n */\n bridgeEstimated: boolean\n}\n\nexport function emptyPrimeRawUsage(): PrimeRawUsage {\n return { calls: null, inputTokens: null, outputTokens: null, bridgeEstimated: false }\n}\n\n/** Read the bridge's OpenAI-shaped `usage` object. */\nexport function normalizePrimeUsage(raw: unknown): PrimeRawUsage {\n if (typeof raw !== 'object' || raw === null) return emptyPrimeRawUsage()\n const record = raw as Record<string, unknown>\n return {\n calls: tokenCountOrNull(record.model_requests),\n inputTokens: tokenCountOrNull(record.prompt_tokens),\n outputTokens: tokenCountOrNull(record.completion_tokens),\n bridgeEstimated: record.estimated === true,\n }\n}\n\n/**\n * Sum two turns. Each side poisons independently: two turns that both report\n * input and neither report output yield a real input total beside a null\n * output, because discarding a measured count is as wrong as inventing one.\n */\nexport function mergePrimeRawUsage(a: PrimeRawUsage, b: PrimeRawUsage): PrimeRawUsage {\n return {\n calls: sumOrNull(a.calls, b.calls),\n inputTokens: sumOrNull(a.inputTokens, b.inputTokens),\n outputTokens: sumOrNull(a.outputTokens, b.outputTokens),\n bridgeEstimated: a.bridgeEstimated || b.bridgeEstimated,\n }\n}\n\nfunction sumOrNull(a: number | null, b: number | null): number | null {\n return a !== null && b !== null ? a + b : null\n}\n\nfunction tokenCountOrNull(value: unknown): number | null {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : null\n}\n\n/**\n * Bind raw prime usage to agent-eval's typed receipt.\n *\n * `RunTokenUsage.input` and `.output` are non-nullable, so a one-sided count\n * cannot round-trip through `tokens` without writing a zero nobody measured.\n * The complete-accounting field therefore stays null, the reported side is\n * carried verbatim in `partialTokens`, and its price becomes the receipt's\n * `knownCostUsd` lower bound.\n *\n * Only agent-eval calls this; consumers with no pricing table read\n * `PrimeRawUsage` directly.\n */\nexport function analystUsageReceiptFromPrimeUsage(\n usage: PrimeRawUsage,\n pricing: CustomTokenPricing,\n): AnalystUsageReceipt {\n const { calls, inputTokens, outputTokens, bridgeEstimated } = usage\n const estimatedTokens = bridgeEstimated ? { tokensEstimated: true } : {}\n if (inputTokens !== null && outputTokens !== null) {\n return {\n calls,\n tokens: { input: inputTokens, output: outputTokens },\n cost: { kind: 'estimated', usd: priceTokens(inputTokens, outputTokens, pricing) },\n ...estimatedTokens,\n }\n }\n if (inputTokens === null && outputTokens === null) {\n return { calls, tokens: null, cost: { kind: 'uncaptured', usd: null }, ...estimatedTokens }\n }\n return {\n calls,\n tokens: null,\n partialTokens: { input: inputTokens, output: outputTokens },\n cost: { kind: 'uncaptured', usd: null },\n knownCostUsd: priceTokens(inputTokens ?? 0, outputTokens ?? 0, pricing),\n ...estimatedTokens,\n }\n}\n\nfunction priceTokens(input: number, output: number, pricing: CustomTokenPricing): number {\n return (input * pricing.inputUsdPerMillion + output * pricing.outputUsdPerMillion) / 1_000_000\n}\n\n// ── Two-turn exchange ────────────────────────────────────────────────\n\n/**\n * Why an exchange ended without a readable reply. `deadline` and `aborted` are\n * separate members from `transport` on purpose: a model that ran past its\n * deadline, a caller who cancelled, and a bridge that refused the connection\n * demand three different responses, and a record that conflates them cannot be\n * acted on.\n */\nexport type PrimeFailure =\n | {\n kind: 'transport' | 'unparseable-json' | 'no-content' | 'deadline' | 'malformed-reply'\n message: string\n }\n | { kind: 'http-status'; message: string; status: number; bodySnippet: string }\n | { kind: 'aborted'; message: string; cause: unknown }\n\nexport interface PrimeRepairState {\n attempted: boolean\n /** Null when no repair turn ran, or when the repair turn never returned a reply. */\n succeeded: boolean | null\n}\n\n/** One completed bridge turn. A turn that failed produces no record. */\nexport interface PrimeTurnRecord {\n turn: 'first' | 'repair'\n usage: PrimeRawUsage\n /** The reply's `usage` object verbatim; null when the bridge sent none. */\n rawUsage: unknown\n}\n\nexport interface PrimeRejectedRow {\n index: number\n reason: string\n}\n\nexport type PrimeExchangeOutcome<TRow> =\n | {\n ok: true\n /** The reply's `answer` field; null when absent or not a string. */\n answer: string | null\n rows: TRow[]\n rejected: PrimeRejectedRow[]\n /** Rows the model reported, before decoding or the count cap. */\n reportedRows: number\n /** Valid rows dropped by `contract.maxRows`. */\n overflow: number\n usage: PrimeRawUsage\n turns: PrimeTurnRecord[]\n repair: PrimeRepairState\n reply: string\n }\n | {\n ok: false\n failure: PrimeFailure\n usage: PrimeRawUsage\n turns: PrimeTurnRecord[]\n repair: PrimeRepairState\n /** The last reply received, when one arrived — the diagnostic artifact for a malformed case. */\n reply?: string\n }\n\nexport interface PrimeExchangeOptions<TRow> {\n contract: PrimeReplyContract<TRow>\n prompt: string\n transport: PrimeBridgeTransport\n /** Full endpoint, e.g. `http://localhost:4181/v1/chat/completions`. */\n url: string\n model: string\n /** Deadline for ONE turn. Prime analyses routinely exceed five minutes. */\n timeoutMs: number\n /** Whether a structurally malformed reply gets one bounded repair turn. */\n repair: boolean\n signal?: AbortSignal\n}\n\n/**\n * Run the protocol: one call, one bounded repair turn on a structurally\n * malformed reply, then decode. Zero valid rows from a well-formed reply is an\n * honest null, not a failure.\n */\nexport async function runPrimeExchange<TRow>(\n options: PrimeExchangeOptions<TRow>,\n): Promise<PrimeExchangeOutcome<TRow>> {\n const { contract } = options\n const turns: PrimeTurnRecord[] = []\n const repair: PrimeRepairState = { attempted: false, succeeded: null }\n\n const first = await callPrimeTurn(options, options.prompt)\n if (!first.ok) {\n return { ok: false, failure: first.failure, usage: mergeTurns(turns), turns, repair }\n }\n turns.push({ turn: 'first', usage: first.usage, rawUsage: first.rawUsage })\n\n let reply = first.content\n let parsed = extractPrimeJsonObject(reply)\n let defect = primeReplyDefect(parsed, contract.rowsField)\n\n if (defect !== null && options.repair) {\n repair.attempted = true\n const second = await callPrimeTurn(\n options,\n buildPrimeRepairPrompt({\n defect,\n previousReply: reply,\n repairContractLines: contract.repairContractLines,\n }),\n )\n if (!second.ok) {\n return { ok: false, failure: second.failure, usage: mergeTurns(turns), turns, repair, reply }\n }\n turns.push({ turn: 'repair', usage: second.usage, rawUsage: second.rawUsage })\n reply = second.content\n parsed = extractPrimeJsonObject(reply)\n defect = primeReplyDefect(parsed, contract.rowsField)\n repair.succeeded = defect === null\n }\n\n const usage = mergeTurns(turns)\n if (defect !== null) {\n return {\n ok: false,\n failure: {\n kind: 'malformed-reply',\n message: `${defect} in prime reply${repair.attempted ? ' even after the bounded repair turn' : ''}`,\n },\n usage,\n turns,\n repair,\n reply,\n }\n }\n\n const rawRows = parsed![contract.rowsField] as unknown[]\n const { rows, rejected, overflow } = decodeContractRows(contract, rawRows)\n const answer = parsed!.answer\n return {\n ok: true,\n answer: typeof answer === 'string' ? answer : null,\n rows,\n rejected,\n reportedRows: rawRows.length,\n overflow,\n usage,\n turns,\n repair,\n reply,\n }\n}\n\ntype PrimeTurnOutcome =\n | { ok: true; content: string; usage: PrimeRawUsage; rawUsage: unknown }\n | { ok: false; failure: PrimeFailure }\n\nasync function callPrimeTurn<TRow>(\n options: PrimeExchangeOptions<TRow>,\n content: string,\n): Promise<PrimeTurnOutcome> {\n const { transport, url, model, timeoutMs, signal } = options\n const controller = new AbortController()\n const forwardAbort = () => controller.abort(signal?.reason)\n if (signal?.aborted) controller.abort(signal.reason)\n else signal?.addEventListener('abort', forwardAbort, { once: true })\n const deadline = setTimeout(() => controller.abort(), timeoutMs)\n let result: PrimeBridgeTransportResult\n try {\n result = await transport({\n url,\n body: { model, messages: [{ role: 'user', content }] },\n signal: controller.signal,\n })\n } catch (error) {\n if (signal?.aborted) {\n return {\n ok: false,\n failure: {\n kind: 'aborted',\n message: 'prime exchange cancelled by the caller',\n cause: error,\n },\n }\n }\n if (controller.signal.aborted) {\n return {\n ok: false,\n failure: { kind: 'deadline', message: `bridge call exceeded ${timeoutMs}ms` },\n }\n }\n return {\n ok: false,\n failure: {\n kind: 'transport',\n message: `bridge transport failure: ${error instanceof Error ? error.message : String(error)}`,\n },\n }\n } finally {\n clearTimeout(deadline)\n signal?.removeEventListener('abort', forwardAbort)\n }\n\n if (result.status !== 200) {\n const bodySnippet = result.text.slice(0, 500)\n return {\n ok: false,\n failure: {\n kind: 'http-status',\n message: `bridge HTTP ${result.status}: ${bodySnippet}`,\n status: result.status,\n bodySnippet,\n },\n }\n }\n let response: unknown\n try {\n response = JSON.parse(result.text)\n } catch {\n return {\n ok: false,\n failure: {\n kind: 'unparseable-json',\n message: `bridge returned unparseable JSON (${result.text.length} bytes)`,\n },\n }\n }\n const replyContent = primeReplyContent(response)\n if (replyContent === null) {\n return {\n ok: false,\n failure: { kind: 'no-content', message: 'bridge reply carries no message content' },\n }\n }\n const rawUsage = primeReplyUsage(response)\n return { ok: true, content: replyContent, usage: normalizePrimeUsage(rawUsage), rawUsage }\n}\n\n/**\n * Fold from the FIRST turn, never from an empty receipt: an all-null identity\n * would poison every side it merged with and erase counts the bridge reported.\n */\nfunction mergeTurns(turns: readonly PrimeTurnRecord[]): PrimeRawUsage {\n if (turns.length === 0) return emptyPrimeRawUsage()\n return turns\n .slice(1)\n .reduce<PrimeRawUsage>((total, turn) => mergePrimeRawUsage(total, turn.usage), turns[0]!.usage)\n}\n\nfunction primeReplyContent(response: unknown): string | null {\n if (typeof response !== 'object' || response === null) return null\n const choices = (response as { choices?: unknown }).choices\n if (!Array.isArray(choices) || choices.length === 0) return null\n const message = (choices[0] as { message?: unknown })?.message\n if (typeof message !== 'object' || message === null) return null\n const content = (message as { content?: unknown }).content\n return typeof content === 'string' && content.length > 0 ? content : null\n}\n\nfunction primeReplyUsage(response: unknown): unknown {\n if (typeof response !== 'object' || response === null) return null\n return (response as { usage?: unknown }).usage ?? null\n}\n\n// ── Trajectory projection ────────────────────────────────────────────\n\n/**\n * Where the inlined trajectory comes from. The protocol needs only two moves —\n * fetch it all, or fetch a reduced version — so no store, artifact path, or\n * span type enters the shared signature.\n */\nexport interface PrimeProjectionSource<TItem> {\n /** The full projection, or null when the source declares itself oversized. */\n full(): Promise<readonly TItem[] | null>\n /** A reduced projection of the same material. */\n capped(): Promise<readonly TItem[]>\n /** How `capped` reduces, named for the failure message, e.g. `per-attribute cap 1200`. */\n cappedDescription: string\n}\n\nexport interface PrimeProjectionDelivery {\n mode: 'inline-json'\n fetch: 'full' | 'capped'\n renderedChars: number\n}\n\nexport type PrimeProjectionOutcome<TItem> =\n | {\n ok: true\n items: readonly TItem[]\n rendered: string\n delivery: PrimeProjectionDelivery\n }\n | { ok: false; reason: string; renderedChars: number }\n\n/**\n * Render, measure, fall back to the capped projection, re-measure, fail loud.\n *\n * Inline is the only delivery prime has, so an oversized trajectory is a\n * refusal rather than a silent truncation: dropping spans would understate the\n * trajectory and the analyst would answer a question about a different run.\n */\nexport async function projectPrimeTrajectory<TItem>(\n source: PrimeProjectionSource<TItem>,\n limits: { maxInlineChars: number },\n): Promise<PrimeProjectionOutcome<TItem>> {\n let fetch: PrimeProjectionDelivery['fetch'] = 'full'\n let items = await source.full()\n if (items === null) {\n fetch = 'capped'\n items = await source.capped()\n }\n let rendered = JSON.stringify(items)\n if (rendered.length > limits.maxInlineChars && fetch === 'full') {\n fetch = 'capped'\n items = await source.capped()\n rendered = JSON.stringify(items)\n }\n if (rendered.length > limits.maxInlineChars) {\n return {\n ok: false,\n reason: `trajectory renders to ${rendered.length} chars even at ${source.cappedDescription}; inline delivery impossible`,\n renderedChars: rendered.length,\n }\n }\n return {\n ok: true,\n items,\n rendered,\n delivery: { mode: 'inline-json', fetch, renderedChars: rendered.length },\n }\n}\n\n// ── Protocol identity ────────────────────────────────────────────────\n\nexport interface PrimeProtocolIdentity {\n question: string\n taskDefinition?: string\n contractLines: readonly string[]\n repairContractLines: readonly string[]\n /** Numeric limits the contract states, e.g. row and width caps. */\n limits: Readonly<Record<string, number>>\n}\n\n/**\n * Digest of everything a consumer can send to the bridge under the prime\n * protocol, recorded per observation so a prime result names the exact contract\n * that produced it.\n *\n * Computed over the ACTUALLY composed contract, so two consumers that both\n * stamp `analyst_id: 'prime'` while asking materially different questions get\n * different digests by construction. That is what makes 'prime' a reproducible\n * claim rather than a label.\n */\nexport function primeProtocolSha256(identity: PrimeProtocolIdentity): string {\n return createHash('sha256')\n .update(\n JSON.stringify({\n kind: 'prime-analyst-protocol',\n question: identity.question,\n taskPrompt: identity.taskDefinition ?? null,\n outputContract: identity.contractLines,\n repairContract: buildPrimeRepairPrompt({\n defect: '<defect>',\n previousReply: '<previous-reply>',\n repairContractLines: identity.repairContractLines,\n }),\n limits: identity.limits,\n }),\n )\n .digest('hex')\n}\n"],"mappings":"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"}
|