deepline 0.3.407 → 0.3.409
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/dist/bundling-sources/sdk/src/client.ts +8 -1
- package/dist/bundling-sources/sdk/src/play.ts +13 -0
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +23 -0
- package/dist/bundling-sources/shared_libs/play-runtime/admission-timings.ts +64 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +11 -1
- package/dist/bundling-sources/shared_libs/play-runtime/modal-runtime-config.ts +1 -4
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/local-process.ts +15 -6
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +188 -45
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +22 -4
- package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +10 -4
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +72 -0
- package/dist/bundling-sources/shared_libs/play-runtime/webhook-receipt-source-commit-retry.ts +90 -0
- package/dist/bundling-sources/shared_libs/play-runtime/worker-api-types.ts +5 -0
- package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +6 -0
- package/dist/cli/{auth-WURWNNLE.mjs → auth-5HIIACF7.mjs} +4 -4
- package/dist/cli/auth-F6BX32XZ.js +40 -0
- package/dist/cli/{billing-2QJGXGJX.js → billing-4275N7FL.js} +92 -85
- package/dist/cli/{billing-BP3E6WIM.mjs → billing-EVZ3ZWKC.mjs} +23 -16
- package/dist/cli/{chunk-WXLOW623.mjs → chunk-264PC2RN.mjs} +14 -7
- package/dist/cli/{chunk-RMZAOYDN.js → chunk-2GI3QD3L.js} +53 -53
- package/dist/cli/{chunk-ZBCTXQ3P.mjs → chunk-2PRO2JTX.mjs} +1 -1
- package/dist/cli/{chunk-GAMFK2ZP.mjs → chunk-44ZTYHMQ.mjs} +10 -3
- package/dist/cli/{chunk-G4LJS2RE.js → chunk-53HN7WZN.js} +8 -8
- package/dist/cli/{chunk-URWF7NGQ.js → chunk-5MLCBXXU.js} +36 -15
- package/dist/cli/{chunk-XT6GG3QO.mjs → chunk-7AALNGTA.mjs} +3 -3
- package/dist/cli/{chunk-WJYPBHTE.js → chunk-ALD4COBH.js} +11 -4
- package/dist/cli/{chunk-RZLXVHNO.js → chunk-AU4OFDFX.js} +26 -26
- package/dist/cli/{chunk-N6OAMAO5.mjs → chunk-BEVLCKXG.mjs} +1 -1
- package/dist/cli/{chunk-7LKYHZVB.js → chunk-DEC3JECC.js} +1 -1
- package/dist/cli/{chunk-UFFSOV6I.mjs → chunk-FHPCKULR.mjs} +2 -2
- package/dist/cli/{chunk-THHM4DPE.js → chunk-FJCIUF34.js} +4 -4
- package/dist/cli/{chunk-H6EWQFPQ.js → chunk-GAICVLKL.js} +2 -2
- package/dist/cli/{chunk-4TV43THC.mjs → chunk-IT3XBJQR.mjs} +4 -4
- package/dist/cli/{chunk-UFS752TU.mjs → chunk-J6DCKJNM.mjs} +5 -1
- package/dist/cli/{chunk-AYHLUHE5.js → chunk-JGHG4NBA.js} +6 -2
- package/dist/cli/{chunk-BKC6VMYZ.mjs → chunk-JRAVVJ3T.mjs} +73 -4
- package/dist/cli/{chunk-ZI2ZNDJK.mjs → chunk-LFSHGNT2.mjs} +36 -15
- package/dist/cli/{chunk-L25GBGQU.mjs → chunk-N44JHMKY.mjs} +6 -6
- package/dist/cli/{chunk-QJAX7QN7.mjs → chunk-NZSF57UO.mjs} +2 -2
- package/dist/cli/{chunk-IY6GKJ4O.js → chunk-O3VSXP2F.js} +50 -50
- package/dist/cli/{chunk-J67NU4MQ.mjs → chunk-PBZYY7VZ.mjs} +5 -2
- package/dist/cli/{chunk-G6U74WNM.js → chunk-RTCDW2GU.js} +15 -15
- package/dist/cli/{chunk-UPEOEYZ3.mjs → chunk-TQNHMWUR.mjs} +1 -1
- package/dist/cli/{chunk-KUQAU5MG.js → chunk-V76R6HMV.js} +10 -7
- package/dist/cli/{chunk-6JZZNP5G.mjs → chunk-VWBTTJYQ.mjs} +2 -2
- package/dist/cli/{chunk-SOQIPKF2.js → chunk-WHG43Z67.js} +8 -8
- package/dist/cli/{chunk-Y6CX4QPR.js → chunk-WLOCMJWV.js} +67 -67
- package/dist/cli/{chunk-QJBJZVG6.js → chunk-WNUR6VP5.js} +15 -8
- package/dist/cli/{chunk-P7HOTKOK.mjs → chunk-WYQO2CBS.mjs} +4 -4
- package/dist/cli/{chunk-D2ZRMZKF.js → chunk-YD7B53RW.js} +99 -30
- package/dist/cli/command-docs.js +2 -2
- package/dist/cli/command-docs.mjs +1 -1
- package/dist/cli/{csv-N6KYTG7L.mjs → csv-A2MP6EFV.mjs} +3 -3
- package/dist/cli/{csv-7E5BE23B.js → csv-BBOTCGQY.js} +12 -12
- package/dist/cli/{db-XMBJNVBD.mjs → db-3W5DMTUX.mjs} +4 -4
- package/dist/cli/{db-4VLZP33O.js → db-G4CODDCA.js} +25 -25
- package/dist/cli/{describe-4I6EIVXD.js → describe-PQTQ5B6F.js} +11 -11
- package/dist/cli/{describe-WERH4TD2.mjs → describe-XYJ2ZT4M.mjs} +7 -7
- package/dist/cli/describe-core.d.mts +2 -2
- package/dist/cli/describe-core.d.ts +2 -2
- package/dist/cli/{executions-W7TWJRBK.js → executions-TLANVR7Y.js} +6 -6
- package/dist/cli/{executions-JWQXE7G6.mjs → executions-UR67CA5H.mjs} +4 -4
- package/dist/cli/{feedback-FMGRC6KO.js → feedback-6C2YTRJL.js} +7 -7
- package/dist/cli/{feedback-OEJFX4F7.mjs → feedback-WHCMGEIL.mjs} +3 -3
- package/dist/cli/{git-IVC4KHXX.mjs → git-GWLB6VSA.mjs} +4 -4
- package/dist/cli/git-VQFF6D7C.js +24 -0
- package/dist/cli/index.js +204 -127
- package/dist/cli/index.mjs +124 -47
- package/dist/cli/{legacy-noops-LT36CLWZ.mjs → legacy-noops-KF4XIFEF.mjs} +4 -4
- package/dist/cli/{legacy-noops-X3BQ7MUK.js → legacy-noops-ZUFA7RWI.js} +7 -7
- package/dist/cli/{monitors-MNLCELF7.mjs → monitors-6UOIDIMB.mjs} +4 -4
- package/dist/cli/{monitors-DLIIAVLW.js → monitors-TB3K2IVE.js} +84 -84
- package/dist/cli/{org-CYHDEW7P.js → org-CKWMBPIR.js} +64 -64
- package/dist/cli/{org-QV5LMUPT.mjs → org-WGHHMVDZ.mjs} +4 -4
- package/dist/cli/{play-5Z4ROZ3P.mjs → play-LYPAXCLD.mjs} +70 -18
- package/dist/cli/{play-MEFXC2QA.js → play-N2B3KAVS.js} +345 -293
- package/dist/cli/{providers-FJLYSHB3.mjs → providers-6DI5BVZJ.mjs} +4 -4
- package/dist/cli/{providers-2MKUNFBQ.js → providers-UR42MD6Z.js} +7 -7
- package/dist/cli/{quickstart-ULWXKAOT.js → quickstart-FCJG4XGB.js} +5 -5
- package/dist/cli/{quickstart-PQO3OQRT.mjs → quickstart-MNA2S6PO.mjs} +3 -3
- package/dist/cli/search-NCEEONMQ.js +30 -0
- package/dist/cli/{search-KGAAXMDG.mjs → search-VPPYUJ2M.mjs} +5 -5
- package/dist/cli/{secrets-PD5I3KAF.mjs → secrets-DRI4W7Z5.mjs} +4 -4
- package/dist/cli/{secrets-X2VGG2PO.js → secrets-QOSMVO36.js} +13 -13
- package/dist/cli/{sessions-R3XAKTBQ.js → sessions-3WYKQABW.js} +5 -5
- package/dist/cli/{sessions-3WVEU4PE.mjs → sessions-DQNUKP43.mjs} +4 -4
- package/dist/cli/{settings-645RSFQX.mjs → settings-DWDK3Y2R.mjs} +8 -8
- package/dist/cli/{settings-ZIDO3IP6.js → settings-JUGGCOPS.js} +75 -75
- package/dist/cli/{setup-LH5HOZ3D.js → setup-AWBHNYXK.js} +42 -42
- package/dist/cli/{setup-LISKIJKP.mjs → setup-D5DWVNY4.mjs} +7 -7
- package/dist/cli/skills-AKPAJVSO.js +29 -0
- package/dist/cli/{skills-VVQJHLSF.mjs → skills-YV2XR35J.mjs} +5 -5
- package/dist/cli/{tools-FTPJCNAM.js → tools-RBKEK6PM.js} +8 -8
- package/dist/cli/{tools-Y3LOMXFT.mjs → tools-VFJYHNV2.mjs} +7 -7
- package/dist/cli/{update-DOBNQNJI.mjs → update-IM6VOTGL.mjs} +7 -7
- package/dist/cli/update-VFNUBLDA.js +29 -0
- package/dist/cli/{workflow-ZMAA5VCN.mjs → workflow-26URBWPV.mjs} +5 -5
- package/dist/cli/{workflow-LGENKZBV.js → workflow-3BS6U6SL.js} +15 -15
- package/dist/{client-IrPHUE5J.d.ts → client-BMjJFpan.d.ts} +28 -2
- package/dist/{client-6rEB46Lv.d.mts → client-BfInrZPB.d.mts} +28 -2
- package/dist/{compiler-manifest-BHnXE43X.d.ts → compiler-manifest-Ycx-hoAr.d.mts} +2 -0
- package/dist/{compiler-manifest-BHnXE43X.d.mts → compiler-manifest-Ycx-hoAr.d.ts} +2 -0
- package/dist/{index-Da_Y8z5e.d.mts → index-CZXgiN3E.d.mts} +1 -1
- package/dist/{index-SODb2ROS.d.ts → index-NPG5pqxQ.d.ts} +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +26 -9
- package/dist/index.mjs +23 -6
- package/dist/install-integrity.json +86 -84
- package/dist/plays/bundle-play-file.d.mts +3 -3
- package/dist/plays/bundle-play-file.d.ts +3 -3
- package/dist/plays/play-description.d.mts +2 -2
- package/dist/plays/play-description.d.ts +2 -2
- package/dist/plays/run-request.d.mts +2 -2
- package/dist/plays/run-request.d.ts +2 -2
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +2 -2
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
- package/dist/cli/auth-4JTX6AGM.js +0 -40
- package/dist/cli/git-OFXE7G4X.js +0 -24
- package/dist/cli/search-ANKSJ224.js +0 -30
- package/dist/cli/skills-WLHYSVQA.js +0 -29
- package/dist/cli/update-A622H2DZ.js +0 -29
|
@@ -18598,8 +18598,8 @@ function runLedgerOutboxPrefixClaimSql(
|
|
|
18598
18598
|
const lockFence = fence
|
|
18599
18599
|
? `current_setting('deepline.run_ledger_outbox_lock', true) = ${escapeLiteral(fence.runId)}`
|
|
18600
18600
|
: undefined;
|
|
18601
|
-
const pending = (alias: string) =>
|
|
18602
|
-
`${alias}.delivered_at IS NULL${
|
|
18601
|
+
const pending = (alias: string, primaryKeyLookup = false) =>
|
|
18602
|
+
`${primaryKeyLookup ? `coalesce(${alias}.delivered_at IS NULL, false)` : `${alias}.delivered_at IS NULL`}${
|
|
18603
18603
|
acknowledgement ? ` AND NOT (${alias}.event_id = ANY($5::text[]))` : ''
|
|
18604
18604
|
}`;
|
|
18605
18605
|
// The dispatcher already chose this run. Seek its oldest pending fact
|
|
@@ -18628,11 +18628,20 @@ function runLedgerOutboxPrefixClaimSql(
|
|
|
18628
18628
|
? `(head.event_type = ${RUN_SCHEDULER_OUTBOX_EVENT_TYPE_SQL_LITERAL.runEvents})`
|
|
18629
18629
|
: 'false';
|
|
18630
18630
|
const findSearchBlockersOnce = seekRunHead && input.searchOnly === true;
|
|
18631
|
-
|
|
18631
|
+
// Only ordinary scoped lifecycle enumeration changes. Its existing limit
|
|
18632
|
+
// bounds candidate keys before the original eligibility/fence predicates;
|
|
18633
|
+
// a frozen terminal in that window retains complete receipt membership.
|
|
18634
|
+
// Carry the locked event type instead of fetching it again by primary key.
|
|
18635
|
+
// Recheck pending/run identity without inviting stale partial-index scans.
|
|
18636
|
+
// Predecessor checks share snapshot metadata; bounded keys own live row access.
|
|
18637
|
+
const inspectLifecycleCandidates = seekRunHead && input.searchOnly !== true;
|
|
18638
|
+
const claimFactColumnsSql = (alias: string) =>
|
|
18632
18639
|
`${alias}.event_id, ${alias}.run_id, ${alias}.event_type,
|
|
18633
18640
|
${alias}.created_at, ${alias}.failed_at, ${alias}.next_attempt_at,
|
|
18634
18641
|
${alias}.lease_owner, ${alias}.lease_expires_at,
|
|
18635
18642
|
${supportsTerminalBatchMarker ? `${alias}.delivery_batch_started_at` : 'NULL::timestamptz AS delivery_batch_started_at'}`;
|
|
18643
|
+
const lifecycleFactColumnsSql = (alias: string) =>
|
|
18644
|
+
`${claimFactColumnsSql(alias)}, ${alias}.delivered_at`;
|
|
18636
18645
|
const blockingPredecessorSql = (alias: string) => `(
|
|
18637
18646
|
(${alias}.event_type = ${RUN_SCHEDULER_OUTBOX_EVENT_TYPE_SQL_LITERAL.runEvents}
|
|
18638
18647
|
AND NOT (${ingressPrefixSql}))
|
|
@@ -18646,6 +18655,27 @@ function runLedgerOutboxPrefixClaimSql(
|
|
|
18646
18655
|
AND ${alias}.lease_owner IS DISTINCT FROM $3::text
|
|
18647
18656
|
)
|
|
18648
18657
|
)`;
|
|
18658
|
+
// A modern frozen head cannot cross an unmarked predecessor. A witness in
|
|
18659
|
+
// this snapshot's window therefore blocks every later key, even if a live
|
|
18660
|
+
// candidate is rejected after locking. Keep full membership without that
|
|
18661
|
+
// witness: an all-marked window can refill after a concurrent ACK.
|
|
18662
|
+
const lifecycleRequiresFullMembershipSql = inspectLifecycleCandidates
|
|
18663
|
+
? `EXISTS (
|
|
18664
|
+
SELECT 1 FROM lifecycle_window AS terminal
|
|
18665
|
+
WHERE terminal.delivery_batch_started_at IS NOT NULL
|
|
18666
|
+
AND terminal.event_type IN (${RUN_EVENT_KIND_SQL_LITERAL.runCompleted}, ${RUN_EVENT_KIND_SQL_LITERAL.runFailed}, ${RUN_EVENT_KIND_SQL_LITERAL.runCancelled})${
|
|
18667
|
+
supportsTerminalBatchMarker && input.allowIngressPrefix === true
|
|
18668
|
+
? `
|
|
18669
|
+
AND NOT EXISTS (
|
|
18670
|
+
SELECT 1 FROM head AS frozen_head
|
|
18671
|
+
CROSS JOIN lifecycle_window AS unmarked
|
|
18672
|
+
WHERE frozen_head.delivery_batch_started_at IS NOT NULL
|
|
18673
|
+
AND unmarked.delivery_batch_started_at IS NULL
|
|
18674
|
+
)`
|
|
18675
|
+
: ''
|
|
18676
|
+
}
|
|
18677
|
+
)`
|
|
18678
|
+
: 'false';
|
|
18649
18679
|
return `
|
|
18650
18680
|
WITH ${
|
|
18651
18681
|
acknowledgement
|
|
@@ -18681,9 +18711,8 @@ function runLedgerOutboxPrefixClaimSql(
|
|
|
18681
18711
|
${findSearchBlockersOnce ? 'candidate.created_at,' : ''}
|
|
18682
18712
|
${supportsTerminalBatchMarker ? 'candidate.delivery_batch_started_at' : 'NULL::timestamptz'} AS delivery_batch_started_at
|
|
18683
18713
|
FROM ${tableName('outbox', options)} AS candidate
|
|
18684
|
-
${seekRunHead ? 'JOIN
|
|
18685
|
-
${
|
|
18686
|
-
WHERE ${pending('candidate')}
|
|
18714
|
+
${seekRunHead ? '' : '\n '}${input.extendOwnedHead ? 'JOIN owned_run ON owned_run.run_id = candidate.run_id' : ''}
|
|
18715
|
+
WHERE ${seekRunHead ? `candidate.event_id = (SELECT event_id FROM pending_head) AND ${pending('candidate')}` : pending('candidate')}
|
|
18687
18716
|
${lockFence ? `AND (${lockFence})` : ''}
|
|
18688
18717
|
${fence?.expectedHeadEventId ? `AND candidate.event_id = ${escapeLiteral(fence.expectedHeadEventId)}` : ''}
|
|
18689
18718
|
AND ${searchLaneSql('candidate')} = ${input.searchOnly === true ? 'true' : 'false'}
|
|
@@ -18766,14 +18795,16 @@ function runLedgerOutboxPrefixClaimSql(
|
|
|
18766
18795
|
), ${
|
|
18767
18796
|
findSearchBlockersOnce
|
|
18768
18797
|
? `search_prefix AS MATERIALIZED (
|
|
18769
|
-
SELECT
|
|
18798
|
+
SELECT prefix.* FROM head
|
|
18799
|
+
CROSS JOIN LATERAL (
|
|
18800
|
+
SELECT ${claimFactColumnsSql('pending')}
|
|
18770
18801
|
FROM ${tableName('outbox', options)} AS pending
|
|
18771
|
-
|
|
18772
|
-
WHERE pending.run_id = $2::text
|
|
18802
|
+
WHERE pending.run_id = head.run_id
|
|
18773
18803
|
AND ${pending('pending')}
|
|
18774
18804
|
AND ${searchLaneSql('pending')} = true
|
|
18775
18805
|
ORDER BY ${runLedgerOrderSql('pending')}
|
|
18776
18806
|
LIMIT $1
|
|
18807
|
+
) AS prefix
|
|
18777
18808
|
), frozen_search_prefix AS MATERIALIZED (
|
|
18778
18809
|
SELECT EXISTS (
|
|
18779
18810
|
SELECT 1 FROM search_prefix AS fact
|
|
@@ -18791,7 +18822,7 @@ function runLedgerOutboxPrefixClaimSql(
|
|
|
18791
18822
|
-- A frozen terminal receipt can contain marked facts beyond newer
|
|
18792
18823
|
-- unmarked rows. Retain that full membership scan only for this case;
|
|
18793
18824
|
-- limiting its raw window would strand an already attempted receipt.
|
|
18794
|
-
SELECT ${
|
|
18825
|
+
SELECT ${claimFactColumnsSql('pending')}
|
|
18795
18826
|
FROM ${tableName('outbox', options)} AS pending
|
|
18796
18827
|
JOIN head ON head.run_id = pending.run_id
|
|
18797
18828
|
WHERE (SELECT has_terminal FROM frozen_search_prefix)
|
|
@@ -18826,13 +18857,49 @@ function runLedgerOutboxPrefixClaimSql(
|
|
|
18826
18857
|
LIMIT 1
|
|
18827
18858
|
),`
|
|
18828
18859
|
: ''
|
|
18860
|
+
}${
|
|
18861
|
+
inspectLifecycleCandidates
|
|
18862
|
+
? `lifecycle_window AS MATERIALIZED (
|
|
18863
|
+
SELECT prefix.* FROM head
|
|
18864
|
+
CROSS JOIN LATERAL (
|
|
18865
|
+
SELECT ${lifecycleFactColumnsSql('pending')}
|
|
18866
|
+
FROM ${tableName('outbox', options)} AS pending
|
|
18867
|
+
WHERE pending.run_id = head.run_id
|
|
18868
|
+
AND pending.run_id = $2::text
|
|
18869
|
+
AND ${pending('pending')}
|
|
18870
|
+
AND ${searchLaneSql('pending')} = false
|
|
18871
|
+
ORDER BY ${runLedgerOrderSql('pending')}
|
|
18872
|
+
LIMIT $1
|
|
18873
|
+
) AS prefix
|
|
18874
|
+
), lifecycle_facts AS MATERIALIZED (
|
|
18875
|
+
SELECT prefix.* FROM lifecycle_window AS prefix
|
|
18876
|
+
WHERE NOT ${lifecycleRequiresFullMembershipSql}
|
|
18877
|
+
UNION ALL
|
|
18878
|
+
SELECT ${lifecycleFactColumnsSql('pending')}
|
|
18879
|
+
FROM ${tableName('outbox', options)} AS pending
|
|
18880
|
+
JOIN head ON head.run_id = pending.run_id
|
|
18881
|
+
WHERE ${lifecycleRequiresFullMembershipSql}
|
|
18882
|
+
AND pending.run_id = $2::text
|
|
18883
|
+
AND ${pending('pending')}
|
|
18884
|
+
AND ${searchLaneSql('pending')} = false
|
|
18885
|
+
), `
|
|
18886
|
+
: ''
|
|
18829
18887
|
}candidates AS MATERIALIZED (
|
|
18830
|
-
|
|
18888
|
+
${
|
|
18889
|
+
runId !== null
|
|
18890
|
+
? `SELECT candidate.event_id${inspectLifecycleCandidates ? ', candidate.event_type' : ''} FROM head
|
|
18891
|
+
CROSS JOIN LATERAL (
|
|
18892
|
+
SELECT outbox.event_id${inspectLifecycleCandidates ? ', outbox.event_type' : ''}
|
|
18893
|
+
FROM ${tableName('outbox', options)} AS outbox
|
|
18894
|
+
WHERE ${pending('outbox', inspectLifecycleCandidates)}
|
|
18895
|
+
AND ${inspectLifecycleCandidates ? 'coalesce(outbox.run_id = head.run_id, false)' : 'outbox.run_id = head.run_id'}`
|
|
18896
|
+
: `SELECT outbox.event_id
|
|
18831
18897
|
FROM ${tableName('outbox', options)} AS outbox
|
|
18832
18898
|
JOIN head ON head.run_id = outbox.run_id
|
|
18833
18899
|
WHERE ${pending('outbox')}
|
|
18834
|
-
|
|
18835
|
-
|
|
18900
|
+
`
|
|
18901
|
+
}
|
|
18902
|
+
${findSearchBlockersOnce ? 'AND outbox.event_id = ANY(ARRAY(SELECT event_id FROM search_facts))' : ''}${inspectLifecycleCandidates ? '\n AND outbox.event_id = ANY(ARRAY(SELECT event_id FROM lifecycle_facts))' : ''}
|
|
18836
18903
|
AND ${searchLaneSql('outbox')} = ${input.searchOnly === true ? 'true' : 'false'}
|
|
18837
18904
|
AND ${outboxNotFailedSql('outbox')}
|
|
18838
18905
|
-- Admission is causally first and must be projected alone. A later
|
|
@@ -18881,8 +18948,8 @@ function runLedgerOutboxPrefixClaimSql(
|
|
|
18881
18948
|
)`
|
|
18882
18949
|
: ` AND NOT EXISTS (
|
|
18883
18950
|
SELECT 1
|
|
18884
|
-
FROM ${tableName('outbox', options)} AS terminal_predecessor
|
|
18885
|
-
WHERE terminal_predecessor.run_id = outbox.run_id
|
|
18951
|
+
FROM ${inspectLifecycleCandidates ? 'lifecycle_facts' : tableName('outbox', options)} AS terminal_predecessor
|
|
18952
|
+
WHERE terminal_predecessor.run_id = outbox.run_id${inspectLifecycleCandidates ? '\n AND terminal_predecessor.run_id = $2::text' : ''}
|
|
18886
18953
|
AND ${pending('terminal_predecessor')}
|
|
18887
18954
|
AND ${
|
|
18888
18955
|
supportsTerminalBatchMarker
|
|
@@ -18897,16 +18964,16 @@ function runLedgerOutboxPrefixClaimSql(
|
|
|
18897
18964
|
AND terminal_predecessor.event_type IN (
|
|
18898
18965
|
${RUN_EVENT_KIND_SQL_LITERAL.runCompleted}, ${RUN_EVENT_KIND_SQL_LITERAL.runFailed}, ${RUN_EVENT_KIND_SQL_LITERAL.runCancelled}
|
|
18899
18966
|
)
|
|
18900
|
-
AND ${runLedgerPrecedesSql('terminal_predecessor', 'outbox', false, input.searchOnly === true)}
|
|
18967
|
+
AND ${inspectLifecycleCandidates ? `${runLedgerPositionSql('terminal_predecessor')} < ${runLedgerPositionSql('outbox')}` : runLedgerPrecedesSql('terminal_predecessor', 'outbox', false, input.searchOnly === true)}
|
|
18901
18968
|
)
|
|
18902
18969
|
-- Claim only the contiguous due prefix. A delayed, leased, or failed
|
|
18903
18970
|
-- predecessor retains ownership of everything that follows it.
|
|
18904
18971
|
AND NOT EXISTS (
|
|
18905
18972
|
SELECT 1
|
|
18906
|
-
FROM ${tableName('outbox', options)} AS predecessor
|
|
18907
|
-
WHERE predecessor.run_id = outbox.run_id
|
|
18973
|
+
FROM ${inspectLifecycleCandidates ? 'lifecycle_facts' : tableName('outbox', options)} AS predecessor
|
|
18974
|
+
WHERE predecessor.run_id = outbox.run_id${inspectLifecycleCandidates ? '\n AND predecessor.run_id = $2::text' : ''}
|
|
18908
18975
|
AND ${pending('predecessor')}
|
|
18909
|
-
AND ${runLedgerPrecedesSql('predecessor', 'outbox', false, input.searchOnly === true)}
|
|
18976
|
+
AND ${inspectLifecycleCandidates ? `${runLedgerPositionSql('predecessor')} < ${runLedgerPositionSql('outbox')}` : runLedgerPrecedesSql('predecessor', 'outbox', false, input.searchOnly === true)}
|
|
18910
18977
|
AND ${blockingPredecessorSql('predecessor')}
|
|
18911
18978
|
)
|
|
18912
18979
|
`
|
|
@@ -18914,14 +18981,18 @@ function runLedgerOutboxPrefixClaimSql(
|
|
|
18914
18981
|
ORDER BY ${runLedgerOrderSql('outbox')}
|
|
18915
18982
|
FOR UPDATE OF outbox
|
|
18916
18983
|
LIMIT $1
|
|
18917
|
-
)
|
|
18984
|
+
${runId !== null ? ' ) AS candidate\n ' : ''}), ${
|
|
18985
|
+
inspectLifecycleCandidates
|
|
18986
|
+
? ''
|
|
18987
|
+
: `terminal_batch AS (
|
|
18918
18988
|
SELECT EXISTS (
|
|
18919
18989
|
SELECT 1
|
|
18920
18990
|
FROM ${tableName('outbox', options)} AS candidate
|
|
18921
18991
|
JOIN candidates ON candidates.event_id = candidate.event_id
|
|
18922
18992
|
WHERE candidate.event_type IN (${RUN_EVENT_KIND_SQL_LITERAL.runCompleted}, ${RUN_EVENT_KIND_SQL_LITERAL.runFailed}, ${RUN_EVENT_KIND_SQL_LITERAL.runCancelled})
|
|
18923
18993
|
) AS has_terminal
|
|
18924
|
-
),
|
|
18994
|
+
), `
|
|
18995
|
+
}claimed AS (
|
|
18925
18996
|
UPDATE ${tableName('outbox', options)} outbox
|
|
18926
18997
|
SET lease_owner = $3,
|
|
18927
18998
|
lease_expires_at = CASE
|
|
@@ -18931,14 +19002,14 @@ function runLedgerOutboxPrefixClaimSql(
|
|
|
18931
19002
|
${
|
|
18932
19003
|
supportsTerminalBatchMarker
|
|
18933
19004
|
? `, delivery_batch_started_at = CASE
|
|
18934
|
-
WHEN terminal_batch.has_terminal ${input.allowIngressPrefix === true ? `OR ${urgentLifecyclePendingSql('outbox')} OR EXISTS (SELECT 1 FROM head WHERE head.event_type = ${RUN_SCHEDULER_OUTBOX_EVENT_TYPE_SQL_LITERAL.runEvents})` : ''}
|
|
19005
|
+
WHEN ${inspectLifecycleCandidates ? `EXISTS (SELECT 1 FROM candidates AS terminal_candidate WHERE terminal_candidate.event_type IN (${RUN_EVENT_KIND_SQL_LITERAL.runCompleted}, ${RUN_EVENT_KIND_SQL_LITERAL.runFailed}, ${RUN_EVENT_KIND_SQL_LITERAL.runCancelled}))` : 'terminal_batch.has_terminal'} ${input.allowIngressPrefix === true ? `OR ${urgentLifecyclePendingSql('outbox')} OR EXISTS (SELECT 1 FROM head WHERE head.event_type = ${RUN_SCHEDULER_OUTBOX_EVENT_TYPE_SQL_LITERAL.runEvents})` : ''}
|
|
18935
19006
|
THEN COALESCE(outbox.delivery_batch_started_at, statement_timestamp())
|
|
18936
19007
|
ELSE outbox.delivery_batch_started_at
|
|
18937
19008
|
END`
|
|
18938
19009
|
: ''
|
|
18939
19010
|
}
|
|
18940
19011
|
FROM candidates
|
|
18941
|
-
CROSS JOIN terminal_batch
|
|
19012
|
+
${inspectLifecycleCandidates ? '' : 'CROSS JOIN terminal_batch'}
|
|
18942
19013
|
WHERE outbox.event_id = candidates.event_id
|
|
18943
19014
|
RETURNING outbox.event_id, outbox.run_id, outbox.event_type,
|
|
18944
19015
|
outbox.payload_json, outbox.created_at, outbox.lease_owner,
|
|
@@ -19002,9 +19073,34 @@ function runLedgerOutboxPrefixClaimBatchSql(input: {
|
|
|
19002
19073
|
lockStrength?: 'no_key_update';
|
|
19003
19074
|
transportHeadSql?: string;
|
|
19004
19075
|
}): string {
|
|
19005
|
-
|
|
19076
|
+
// Ordinary claims have four bounded primitive arguments. Give PostgreSQL
|
|
19077
|
+
// constants instead of a scalar InitPlan for every repeated argument. Keep
|
|
19078
|
+
// the JSON renderer for ACK arrays, transport/extension claims and values
|
|
19079
|
+
// whose existing JSON conversion or cast failure must remain unchanged.
|
|
19080
|
+
const directScalars =
|
|
19081
|
+
input.params.length === 4 &&
|
|
19082
|
+
!input.transportHeadSql &&
|
|
19083
|
+
input.params.every((value, index) =>
|
|
19084
|
+
index === 0 || index === 3
|
|
19085
|
+
? typeof value === 'number' &&
|
|
19086
|
+
Number.isInteger(value) &&
|
|
19087
|
+
value >= -2_147_483_648 &&
|
|
19088
|
+
value <= 2_147_483_647
|
|
19089
|
+
: value === null ||
|
|
19090
|
+
(typeof value === 'string' &&
|
|
19091
|
+
/^(?:[\u0001-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF])*$/.test(
|
|
19092
|
+
value,
|
|
19093
|
+
)),
|
|
19094
|
+
);
|
|
19095
|
+
const encoded = directScalars
|
|
19096
|
+
? undefined
|
|
19097
|
+
: escapeLiteral(JSON.stringify(input.params));
|
|
19006
19098
|
const parameter = (index: number) => {
|
|
19007
19099
|
const value = input.params[index - 1];
|
|
19100
|
+
if (directScalars) {
|
|
19101
|
+
const type = typeof value === 'number' ? 'integer' : 'text';
|
|
19102
|
+
return `(${value === null ? 'NULL' : escapeLiteral(String(value))}::${type})`;
|
|
19103
|
+
}
|
|
19008
19104
|
if (Array.isArray(value)) {
|
|
19009
19105
|
return `(SELECT ARRAY(SELECT jsonb_array_elements_text(values_json->${index - 1})) FROM run_ledger_parameters)`;
|
|
19010
19106
|
}
|
|
@@ -19022,9 +19118,11 @@ function runLedgerOutboxPrefixClaimBatchSql(input: {
|
|
|
19022
19118
|
(match, index: string | undefined) =>
|
|
19023
19119
|
index ? parameter(Number(index)) : match,
|
|
19024
19120
|
)
|
|
19025
|
-
.
|
|
19026
|
-
|
|
19027
|
-
|
|
19121
|
+
// Use a callback so replacement metacharacters inside generated IDs stay literal.
|
|
19122
|
+
.replace(/^\s*WITH\s/, (match) =>
|
|
19123
|
+
directScalars
|
|
19124
|
+
? match
|
|
19125
|
+
: `WITH run_ledger_parameters AS MATERIALIZED (SELECT ${encoded}::jsonb AS values_json), `,
|
|
19028
19126
|
);
|
|
19029
19127
|
return `BEGIN;
|
|
19030
19128
|
SELECT set_config('lock_timeout', '${RUNTIME_SCHEDULER_CANCEL_LOCK_TIMEOUT_MS}ms', true),
|
|
@@ -20025,8 +20123,9 @@ export async function markPostgresSchedulerOutboxDelivered(
|
|
|
20025
20123
|
|
|
20026
20124
|
/**
|
|
20027
20125
|
* Shared lease-fenced ACK, including the canonical retained-payload cleanup.
|
|
20028
|
-
* Known-run callers
|
|
20029
|
-
*
|
|
20126
|
+
* Known-run callers recheck scope and pending state without offering a second
|
|
20127
|
+
* index access path beside their exact IDs. Stale statistics otherwise favor a
|
|
20128
|
+
* full run bitmap or pending partial-index scan before filtering those IDs.
|
|
20030
20129
|
*/
|
|
20031
20130
|
function runLedgerAcknowledgeSql(
|
|
20032
20131
|
options: Pick<PostgresSchedulerOptions, 'schema'> | undefined,
|
|
@@ -20047,9 +20146,9 @@ function runLedgerAcknowledgeSql(
|
|
|
20047
20146
|
AND run.run_event_store = 'planet_scale'
|
|
20048
20147
|
) THEN '{}'::jsonb ELSE outbox.payload_json END
|
|
20049
20148
|
WHERE outbox.event_id = ANY(${eventIdsParameter}::text[])
|
|
20050
|
-
${runIdParameter ? `AND outbox.run_id = ${runIdParameter}::text` : ''}
|
|
20149
|
+
${runIdParameter ? `AND coalesce(outbox.run_id = ${runIdParameter}::text, false)` : ''}
|
|
20051
20150
|
${lockFence ? `AND (${lockFence})` : ''}
|
|
20052
|
-
AND outbox.delivered_at IS NULL
|
|
20151
|
+
AND ${runIdParameter ? 'coalesce(outbox.delivered_at IS NULL, false)' : 'outbox.delivered_at IS NULL'}
|
|
20053
20152
|
AND (${leaseOwnerParameter}::text IS NULL OR outbox.lease_owner = ${leaseOwnerParameter})
|
|
20054
20153
|
RETURNING outbox.event_id,
|
|
20055
20154
|
outbox.event_type,
|
|
@@ -21452,6 +21551,14 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
21452
21551
|
}
|
|
21453
21552
|
}
|
|
21454
21553
|
let events = claimed.events;
|
|
21554
|
+
const searchOnlyTerminalLogCarrier =
|
|
21555
|
+
input.searchOnly === true &&
|
|
21556
|
+
events.some(
|
|
21557
|
+
(event) =>
|
|
21558
|
+
event.eventType === RUN_SCHEDULER_OUTBOX_EVENT_TYPE.runnerLogs &&
|
|
21559
|
+
(event.eventId.startsWith('runner-terminal-logs:') ||
|
|
21560
|
+
event.eventId.startsWith('terminal-log-chunk:')),
|
|
21561
|
+
);
|
|
21455
21562
|
const unconfirmedTransportError = claimed.transportOwnershipUnconfirmed
|
|
21456
21563
|
? new RunLedgerProjectionLeaseLostError('delivery_lease_not_current')
|
|
21457
21564
|
: null;
|
|
@@ -21521,6 +21628,10 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
21521
21628
|
const appendAttempt: { transportAttemptId: string | null } = {
|
|
21522
21629
|
transportAttemptId: null,
|
|
21523
21630
|
};
|
|
21631
|
+
// Fixed-shape diagnostic timings for the search-only terminal-log carrier.
|
|
21632
|
+
// These are process-local observations and never enter durable run state.
|
|
21633
|
+
let terminalLogMaterializeTransactionCommitMs: number | null = null;
|
|
21634
|
+
let terminalLogAcknowledgeMs: number | null = null;
|
|
21524
21635
|
const callerOnRequestAttempt = input.runtimeApi?.onRequestAttempt;
|
|
21525
21636
|
const materializeDeferredObservability = async () => {
|
|
21526
21637
|
if (
|
|
@@ -21579,6 +21690,7 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
21579
21690
|
},
|
|
21580
21691
|
),
|
|
21581
21692
|
);
|
|
21693
|
+
const materializeStartedAtMs = performance.now();
|
|
21582
21694
|
const checkoutStartedAtMs = performance.now();
|
|
21583
21695
|
let materializeEnteredAtMs: number | null = null;
|
|
21584
21696
|
try {
|
|
@@ -21639,6 +21751,14 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
21639
21751
|
(searchPhaseTimingsMs.materializeAcquireAndRetry ?? 0) +
|
|
21640
21752
|
(materializeEnteredAtMs ?? performance.now()) -
|
|
21641
21753
|
checkoutStartedAtMs;
|
|
21754
|
+
if (searchOnlyTerminalLogCarrier) {
|
|
21755
|
+
const elapsedMs = Math.max(
|
|
21756
|
+
0,
|
|
21757
|
+
performance.now() - materializeStartedAtMs,
|
|
21758
|
+
);
|
|
21759
|
+
terminalLogMaterializeTransactionCommitMs =
|
|
21760
|
+
(terminalLogMaterializeTransactionCommitMs ?? 0) + elapsedMs;
|
|
21761
|
+
}
|
|
21642
21762
|
}
|
|
21643
21763
|
};
|
|
21644
21764
|
try {
|
|
@@ -21701,20 +21821,31 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
21701
21821
|
)
|
|
21702
21822
|
)
|
|
21703
21823
|
throw new Error('Search lease includes a lifecycle fact.');
|
|
21704
|
-
const
|
|
21705
|
-
|
|
21706
|
-
|
|
21707
|
-
|
|
21708
|
-
|
|
21709
|
-
|
|
21710
|
-
|
|
21711
|
-
|
|
21712
|
-
|
|
21713
|
-
|
|
21714
|
-
|
|
21715
|
-
|
|
21716
|
-
|
|
21717
|
-
|
|
21824
|
+
const acknowledgeStartedAtMs = performance.now();
|
|
21825
|
+
let delivered: RunLedgerOutboxDeliveredRow[];
|
|
21826
|
+
try {
|
|
21827
|
+
delivered = await observeSearchPhase('acknowledge', () =>
|
|
21828
|
+
withClient(
|
|
21829
|
+
(client) =>
|
|
21830
|
+
markPostgresSchedulerOutboxDeliveredRows(
|
|
21831
|
+
client,
|
|
21832
|
+
events.map((event) => event.eventId),
|
|
21833
|
+
{ ...options, leaseOwner },
|
|
21834
|
+
),
|
|
21835
|
+
{
|
|
21836
|
+
runId: events[0]!.runId,
|
|
21837
|
+
phase: 'run_ledger_outbox_search_acknowledge',
|
|
21838
|
+
},
|
|
21839
|
+
),
|
|
21840
|
+
);
|
|
21841
|
+
} finally {
|
|
21842
|
+
if (searchOnlyTerminalLogCarrier) {
|
|
21843
|
+
terminalLogAcknowledgeMs = Math.max(
|
|
21844
|
+
0,
|
|
21845
|
+
performance.now() - acknowledgeStartedAtMs,
|
|
21846
|
+
);
|
|
21847
|
+
}
|
|
21848
|
+
}
|
|
21718
21849
|
if (delivered.length !== events.length)
|
|
21719
21850
|
throw new RunLedgerProjectionLeaseLostError(
|
|
21720
21851
|
'delivery_lease_not_current',
|
|
@@ -22441,6 +22572,18 @@ async function dispatchRunLedgerOutboxBatchWithScope(
|
|
|
22441
22572
|
continuationMs:
|
|
22442
22573
|
acknowledgedAtMs === null ? null : settledAtMs - acknowledgedAtMs,
|
|
22443
22574
|
durationMs: settledAtMs - dispatchStartedAtMs,
|
|
22575
|
+
...(searchOnlyTerminalLogCarrier
|
|
22576
|
+
? {
|
|
22577
|
+
// Keep this fixed-shape scalar packet on the existing diagnostic;
|
|
22578
|
+
// no per-event payload, rows, or durable fields are added.
|
|
22579
|
+
searchOnlyTerminalLogPhaseTimingsMs: {
|
|
22580
|
+
claim: Math.max(0, claimElapsedMs),
|
|
22581
|
+
materializeTransactionCommit:
|
|
22582
|
+
terminalLogMaterializeTransactionCommitMs,
|
|
22583
|
+
acknowledge: terminalLogAcknowledgeMs,
|
|
22584
|
+
},
|
|
22585
|
+
}
|
|
22586
|
+
: {}),
|
|
22444
22587
|
...(input.searchOnly ? { searchPhaseTimingsMs } : {}),
|
|
22445
22588
|
// Which platform requests served the two app hops, so a slow
|
|
22446
22589
|
// authority or append stage can be found in the app's request log.
|
|
@@ -119,6 +119,21 @@ export type RunLedgerOutboxRecoveryDeps = {
|
|
|
119
119
|
logger?: RunLedgerOutboxRecoveryLogger;
|
|
120
120
|
};
|
|
121
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Production runs two projector replicas at eight deliveries each. An
|
|
124
|
+
* isolated Preview estate has one replica, so use the existing bounded
|
|
125
|
+
* 32-delivery ceiling there to keep fixture admission and its catalog
|
|
126
|
+
* projection inside the same latency budget. This does not change Production
|
|
127
|
+
* capacity or the controller's hard maximum.
|
|
128
|
+
*/
|
|
129
|
+
export function runLedgerOutboxRecoveryParallelism(
|
|
130
|
+
environment: 'preview' | 'production',
|
|
131
|
+
): number {
|
|
132
|
+
return environment === 'preview'
|
|
133
|
+
? RUN_LEDGER_OUTBOX_RECOVERY_MAX_IN_FLIGHT
|
|
134
|
+
: RUN_LEDGER_OUTBOX_RECOVERY_PRODUCTION_IN_FLIGHT;
|
|
135
|
+
}
|
|
136
|
+
|
|
122
137
|
export type RunLedgerOutboxRecoveryController = {
|
|
123
138
|
/**
|
|
124
139
|
* Ask the singleton projector to re-read durable outbox work. This is
|
|
@@ -1011,6 +1026,7 @@ export async function deliverRunCreatedOutboxEventInline(input: {
|
|
|
1011
1026
|
export function startRunLedgerOutboxRecoveryController(input: {
|
|
1012
1027
|
poolOptions: RuntimeSchedulerPoolOptions;
|
|
1013
1028
|
schedulerOptions?: Pick<PostgresSchedulerOptions, 'schema'>;
|
|
1029
|
+
environment?: 'preview' | 'production';
|
|
1014
1030
|
/** Direct LISTEN is a latency hint and may be disabled for isolated schemas. */
|
|
1015
1031
|
useDirectNotify?: boolean;
|
|
1016
1032
|
/** Observation hook for acknowledged rows (lag metrics). */
|
|
@@ -1071,10 +1087,12 @@ export function startRunLedgerOutboxRecoveryController(input: {
|
|
|
1071
1087
|
dispatchObservabilityOnce: (runId) => dispatch('oldest_ready', true, runId),
|
|
1072
1088
|
observabilityParallelism: RUN_LEDGER_OUTBOX_RECOVERY_INDEX_IN_FLIGHT,
|
|
1073
1089
|
// `dispatchRunLedgerOutboxToLedgerBatchOnceWithClientScope` releases each
|
|
1074
|
-
// short scheduler checkout before it calls the Vercel gateway.
|
|
1075
|
-
// replicas
|
|
1076
|
-
//
|
|
1077
|
-
parallelism:
|
|
1090
|
+
// short scheduler checkout before it calls the Vercel gateway. Production
|
|
1091
|
+
// retains two replicas at eight slots each; one isolated Preview replica
|
|
1092
|
+
// uses the same controller's existing hard ceiling of 32.
|
|
1093
|
+
parallelism: runLedgerOutboxRecoveryParallelism(
|
|
1094
|
+
input.environment ?? 'production',
|
|
1095
|
+
),
|
|
1078
1096
|
notifyUnavailableSafetyWakeMs: runLedgerOutboxNotifySafetyWakeMs(
|
|
1079
1097
|
schedulerOptions.schema,
|
|
1080
1098
|
),
|
|
@@ -335,7 +335,13 @@ function formatInsufficientCreditsMessage(input: {
|
|
|
335
335
|
getStringField(input.billing, 'operation_id') ??
|
|
336
336
|
getStringField(input.billing, 'operation') ??
|
|
337
337
|
input.toolId;
|
|
338
|
-
|
|
338
|
+
// The explicit field is authoritative, including null. The older
|
|
339
|
+
// balance_credits field remains a fallback for already persisted errors.
|
|
340
|
+
const spendableBalance =
|
|
341
|
+
input.billing.spendable_balance_credits !== undefined
|
|
342
|
+
? input.billing.spendable_balance_credits
|
|
343
|
+
: input.billing.balance_credits;
|
|
344
|
+
const balance = formatCreditAmount(spendableBalance);
|
|
339
345
|
const required = formatCreditAmount(input.billing.required_credits);
|
|
340
346
|
const recommended = formatCreditAmount(
|
|
341
347
|
input.billing.recommended_add_credits ?? input.billing.needed_credits,
|
|
@@ -357,7 +363,7 @@ function formatInsufficientCreditsMessage(input: {
|
|
|
357
363
|
typeof minimum === 'number' &&
|
|
358
364
|
input.billing.required_credits === minimum
|
|
359
365
|
) {
|
|
360
|
-
return `
|
|
366
|
+
return `Spendable workspace balance ${balance} credits is below the ${formatCreditAmount(minimum)}-credit workspace minimum for starting a billable call (${operation}); this is a workspace-wide minimum, separate from the tool's own price.${estimatedPrice} Spendable credits exclude pending spending and can be lower than the posted balance shown by billing balance.${addSuffix}`;
|
|
361
367
|
}
|
|
362
368
|
// A required balance above the call's estimate is headroom, not a price.
|
|
363
369
|
if (
|
|
@@ -365,9 +371,9 @@ function formatInsufficientCreditsMessage(input: {
|
|
|
365
371
|
typeof input.billing.required_credits === 'number' &&
|
|
366
372
|
input.billing.required_credits > estimate
|
|
367
373
|
) {
|
|
368
|
-
return `
|
|
374
|
+
return `Spendable workspace balance ${balance} credits is below the ${required}-credit balance required to start ${operation}; this is a required balance, not the price.${estimatedPrice} Spendable credits exclude pending spending and can be lower than the posted balance shown by billing balance.${addSuffix}`;
|
|
369
375
|
}
|
|
370
|
-
return `
|
|
376
|
+
return `Spendable workspace balance ${balance} credits < required ${required} for ${operation}. Spendable credits exclude pending spending and can be lower than the posted balance shown by billing balance.${addSuffix}`;
|
|
371
377
|
}
|
|
372
378
|
|
|
373
379
|
/** An HTML document, as an edge proxy (Cloudflare, Vercel) serves for a 5xx. */
|
|
@@ -561,6 +561,16 @@ function parseExecuteToolMetadata(
|
|
|
561
561
|
extractors: readExtractors(record.extractors),
|
|
562
562
|
targetGetters: readGetters(record.targetGetters),
|
|
563
563
|
listExtractorPaths,
|
|
564
|
+
...(isRecord(record.listExtractorAliases)
|
|
565
|
+
? {
|
|
566
|
+
listExtractorAliases: Object.fromEntries(
|
|
567
|
+
Object.entries(record.listExtractorAliases).filter(
|
|
568
|
+
(entry): entry is [string, string] =>
|
|
569
|
+
typeof entry[1] === 'string' && entry[1].length > 0,
|
|
570
|
+
),
|
|
571
|
+
),
|
|
572
|
+
}
|
|
573
|
+
: {}),
|
|
564
574
|
listIdentityGetters: readGetters(record.listIdentityGetters),
|
|
565
575
|
};
|
|
566
576
|
}
|
|
@@ -725,6 +735,9 @@ function candidateResultPaths(path: string): string[] {
|
|
|
725
735
|
providerPath,
|
|
726
736
|
normalizeResultPath(path),
|
|
727
737
|
toV2RawToolOutputPathPreservingProviderData(path),
|
|
738
|
+
...(path.startsWith('result.data.')
|
|
739
|
+
? [`toolResponse.raw.${path.slice('result.data.'.length)}`]
|
|
740
|
+
: []),
|
|
728
741
|
];
|
|
729
742
|
return candidates.filter(
|
|
730
743
|
(candidate, index, all) =>
|
|
@@ -1142,6 +1155,7 @@ function coerceToEnum(
|
|
|
1142
1155
|
function resolveListRows(
|
|
1143
1156
|
result: unknown,
|
|
1144
1157
|
listExtractorPaths: readonly string[] | undefined,
|
|
1158
|
+
aliases?: Readonly<Record<string, string>>,
|
|
1145
1159
|
): Record<string, { path: string; rows: Record<string, unknown>[] }> {
|
|
1146
1160
|
const lists: Record<
|
|
1147
1161
|
string,
|
|
@@ -1178,6 +1192,9 @@ function resolveListRows(
|
|
|
1178
1192
|
}
|
|
1179
1193
|
lists[listName] = resolved;
|
|
1180
1194
|
}
|
|
1195
|
+
for (const [alias, source] of Object.entries(aliases ?? {})) {
|
|
1196
|
+
if (!lists[alias] && lists[source]) lists[alias] = lists[source];
|
|
1197
|
+
}
|
|
1181
1198
|
return lists;
|
|
1182
1199
|
}
|
|
1183
1200
|
|
|
@@ -1546,6 +1563,7 @@ export function createToolExecuteResult<TResult = unknown>(input: {
|
|
|
1546
1563
|
const resolvedLists = resolveListRows(
|
|
1547
1564
|
resultRoot,
|
|
1548
1565
|
input.metadata.listExtractorPaths,
|
|
1566
|
+
input.metadata.listExtractorAliases,
|
|
1549
1567
|
);
|
|
1550
1568
|
const lists = buildLists(resolvedLists, input.metadata);
|
|
1551
1569
|
const metadata = {
|
|
@@ -1553,6 +1571,9 @@ export function createToolExecuteResult<TResult = unknown>(input: {
|
|
|
1553
1571
|
execution: input.execution,
|
|
1554
1572
|
targets,
|
|
1555
1573
|
listExtractorPaths: [...(input.metadata.listExtractorPaths ?? [])],
|
|
1574
|
+
...(input.metadata.listExtractorAliases
|
|
1575
|
+
? { listExtractorAliases: { ...input.metadata.listExtractorAliases } }
|
|
1576
|
+
: {}),
|
|
1556
1577
|
...(input.metadata.extractors
|
|
1557
1578
|
? { extractors: input.metadata.extractors }
|
|
1558
1579
|
: {}),
|
|
@@ -1849,6 +1870,7 @@ function serializedListRowsFromRaw(input: {
|
|
|
1849
1870
|
const resolved = resolveListRows(
|
|
1850
1871
|
{ toolResponse: { raw: input.raw } },
|
|
1851
1872
|
input.metadata.listExtractorPaths,
|
|
1873
|
+
input.metadata.listExtractorAliases,
|
|
1852
1874
|
);
|
|
1853
1875
|
const entries = Object.entries(resolved).map(([name, list]) => [
|
|
1854
1876
|
name,
|
|
@@ -2134,6 +2156,9 @@ function metadataInputFromToolExecuteResult(
|
|
|
2134
2156
|
listExtractorPaths:
|
|
2135
2157
|
value._metadata.listExtractorPaths ??
|
|
2136
2158
|
Object.values(value._metadata.lists).map((list) => list.path),
|
|
2159
|
+
...(value._metadata.listExtractorAliases
|
|
2160
|
+
? { listExtractorAliases: { ...value._metadata.listExtractorAliases } }
|
|
2161
|
+
: {}),
|
|
2137
2162
|
listIdentityGetters: Object.fromEntries(
|
|
2138
2163
|
Object.values(value._metadata.lists)
|
|
2139
2164
|
.flatMap((list) => Object.entries(list.keys))
|
|
@@ -2479,6 +2504,53 @@ export function cloneToolExecuteResultWithExecution<TResult>(
|
|
|
2479
2504
|
}) as ToolExecuteResult<TResult>;
|
|
2480
2505
|
}
|
|
2481
2506
|
|
|
2507
|
+
/**
|
|
2508
|
+
* Add current list getter declarations when replaying a result written by an
|
|
2509
|
+
* older catalog. Stored declarations keep their precedence; the canonical
|
|
2510
|
+
* provider response remains the source for any newly exposed getters.
|
|
2511
|
+
*/
|
|
2512
|
+
export function mergeToolExecuteResultListGetterMetadata(
|
|
2513
|
+
value: ToolExecuteResult,
|
|
2514
|
+
currentMetadata: Pick<
|
|
2515
|
+
ToolResultMetadataInput,
|
|
2516
|
+
'listExtractorPaths' | 'listExtractorAliases'
|
|
2517
|
+
>,
|
|
2518
|
+
): ToolExecuteResult {
|
|
2519
|
+
const serialized = serializeToolExecuteResult(value);
|
|
2520
|
+
const storedMetadata = serialized.metadata;
|
|
2521
|
+
const listExtractorPaths = [
|
|
2522
|
+
...new Set([
|
|
2523
|
+
...(storedMetadata.listExtractorPaths ?? []),
|
|
2524
|
+
...(currentMetadata.listExtractorPaths ?? []),
|
|
2525
|
+
]),
|
|
2526
|
+
];
|
|
2527
|
+
const listExtractorAliases = {
|
|
2528
|
+
...(currentMetadata.listExtractorAliases ?? {}),
|
|
2529
|
+
...(storedMetadata.listExtractorAliases ?? {}),
|
|
2530
|
+
};
|
|
2531
|
+
const hasAliases = Object.keys(listExtractorAliases).length > 0;
|
|
2532
|
+
if (
|
|
2533
|
+
sameJsonValue(
|
|
2534
|
+
listExtractorPaths,
|
|
2535
|
+
storedMetadata.listExtractorPaths ?? [],
|
|
2536
|
+
) &&
|
|
2537
|
+
sameJsonValue(
|
|
2538
|
+
hasAliases ? listExtractorAliases : undefined,
|
|
2539
|
+
storedMetadata.listExtractorAliases,
|
|
2540
|
+
)
|
|
2541
|
+
) {
|
|
2542
|
+
return value;
|
|
2543
|
+
}
|
|
2544
|
+
return deserializeToolExecuteResult({
|
|
2545
|
+
...serialized,
|
|
2546
|
+
metadata: {
|
|
2547
|
+
...storedMetadata,
|
|
2548
|
+
listExtractorPaths,
|
|
2549
|
+
...(hasAliases ? { listExtractorAliases } : {}),
|
|
2550
|
+
},
|
|
2551
|
+
});
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2482
2554
|
/**
|
|
2483
2555
|
* Native splitters return the logical source response; the historical adapter
|
|
2484
2556
|
* stores it inside an extra `{ data }` layer. Keep that immutable receipt and
|