deepline 0.2.45 → 0.2.47
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/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +6 -32
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-sql.ts +2 -46
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +4 -4
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-state-machine.ts +1 -53
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +14 -0
- package/dist/cli/index.js +8 -3
- package/dist/cli/index.mjs +8 -3
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -160,7 +160,7 @@ export const SDK_RELEASE = {
|
|
|
160
160
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
161
161
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
162
162
|
// release keeps lazy paging semantics independent of row residency.
|
|
163
|
-
version: '0.2.
|
|
163
|
+
version: '0.2.47',
|
|
164
164
|
contracts: {
|
|
165
165
|
api: {
|
|
166
166
|
name: 'sdk-http-api',
|
|
@@ -11,8 +11,6 @@ import {
|
|
|
11
11
|
isPlayExecutionSuspendedError,
|
|
12
12
|
isPlayRowExecutionSuspendedError,
|
|
13
13
|
} from './suspension';
|
|
14
|
-
import { getToolHttpErrorReceiptFailureKind } from './tool-http-errors';
|
|
15
|
-
import { isLegacyRepairableWorkReceiptError } from './work-receipt-state-machine';
|
|
16
14
|
import type { WorkReceiptFailureKind } from './work-receipts';
|
|
17
15
|
import {
|
|
18
16
|
PLAY_RUNTIME_WORK_RECEIPT_LEASE_TTL_MS,
|
|
@@ -68,37 +66,13 @@ function isInFlightRuntimeReceipt(
|
|
|
68
66
|
}
|
|
69
67
|
|
|
70
68
|
export function runtimeReceiptFailureKindForError(
|
|
71
|
-
|
|
69
|
+
_error: unknown,
|
|
72
70
|
): WorkReceiptFailureKind {
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const toolFailureKind = getToolHttpErrorReceiptFailureKind(error);
|
|
80
|
-
if (toolFailureKind) return toolFailureKind;
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
isPlayExecutionSuspendedError(error) ||
|
|
84
|
-
isPlayRowExecutionSuspendedError(error)
|
|
85
|
-
) {
|
|
86
|
-
return 'repairable';
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Transport/timeout failures never reach a `ToolHttpError` (there was no HTTP
|
|
90
|
-
// response to classify), so they would otherwise default to `terminal` and
|
|
91
|
-
// poison the durable receipt: the next run would replay the cached transport
|
|
92
|
-
// failure instead of re-executing. These are transient infra failures, so
|
|
93
|
-
// mark them repairable. `isLegacyRepairableWorkReceiptError` already encodes
|
|
94
|
-
// the exact transient-string contract (5xx, "transport failed calling",
|
|
95
|
-
// "runtime api call timed out") while excluding hard billing caps, and the
|
|
96
|
-
// read-side SQL predicate uses the same rules, so write and read stay aligned.
|
|
97
|
-
const message =
|
|
98
|
-
error instanceof Error ? error.message : error != null ? String(error) : '';
|
|
99
|
-
return isLegacyRepairableWorkReceiptError(message)
|
|
100
|
-
? 'repairable'
|
|
101
|
-
: 'terminal';
|
|
71
|
+
// Current-run retry and cross-run repair are separate contracts. The tool
|
|
72
|
+
// policy still decides whether this call retries inside the owning run. Once
|
|
73
|
+
// that run stores a failure, however, a later explicit run may always try the
|
|
74
|
+
// semantic call again. The claim state machine keeps the owning run blocked.
|
|
75
|
+
return 'repairable';
|
|
102
76
|
}
|
|
103
77
|
|
|
104
78
|
export function resolveRuntimeToolReceiptWaitTimeoutMs(
|
|
@@ -1,45 +1,4 @@
|
|
|
1
1
|
import { RECEIPT_STATUS_CODE } from './receipt-status';
|
|
2
|
-
import { workReceiptFailureKindCode } from './work-receipts';
|
|
3
|
-
|
|
4
|
-
// This predicate MUST stay behaviorally identical to
|
|
5
|
-
// `isLegacyRepairableWorkReceiptError` in ./work-receipt-state-machine.ts.
|
|
6
|
-
// Write-side classification and this read-side reclaim gate share one contract:
|
|
7
|
-
// a receipt is repairable if its failure_kind is repairable, OR it is a legacy
|
|
8
|
-
// terminal receipt whose error text proves a later-run-repairable failure (5xx,
|
|
9
|
-
// transport, timeout, a transient billing-plane outage, or the structured
|
|
10
|
-
// insufficient-balance snapshot). These narrow legacy clauses are checked
|
|
11
|
-
// BEFORE the hard-billing exclusions so poisoned receipts re-execute on the
|
|
12
|
-
// next run instead of replaying stale mutable state.
|
|
13
|
-
export function workReceiptRepairableFailurePredicateSql(
|
|
14
|
-
receiptTable: string,
|
|
15
|
-
): string {
|
|
16
|
-
return `(
|
|
17
|
-
${receiptTable}.failure_kind = ${workReceiptFailureKindCode('repairable')}::smallint
|
|
18
|
-
OR (
|
|
19
|
-
${receiptTable}.failure_kind = ${workReceiptFailureKindCode('terminal')}::smallint
|
|
20
|
-
AND ${receiptTable}.error IS NOT NULL
|
|
21
|
-
AND (
|
|
22
|
-
lower(${receiptTable}.error) LIKE '%billing_unavailable%'
|
|
23
|
-
OR lower(${receiptTable}.error) LIKE '%billing is temporarily unavailable%'
|
|
24
|
-
OR lower(${receiptTable}.error) LIKE '%billing temporarily unavailable%'
|
|
25
|
-
OR (
|
|
26
|
-
lower(${receiptTable}.error) LIKE '%workspace balance %'
|
|
27
|
-
AND lower(${receiptTable}.error) LIKE '% < required %'
|
|
28
|
-
)
|
|
29
|
-
OR (
|
|
30
|
-
lower(${receiptTable}.error) NOT LIKE '%billing cap%'
|
|
31
|
-
AND lower(${receiptTable}.error) NOT LIKE '%insufficient credits%'
|
|
32
|
-
AND lower(${receiptTable}.error) NOT LIKE '%monthly billing limit%'
|
|
33
|
-
AND (
|
|
34
|
-
${receiptTable}.error ~* '(^|[^0-9])5[0-9]{2}([^0-9]|$)'
|
|
35
|
-
OR lower(${receiptTable}.error) LIKE '%transport failed calling%'
|
|
36
|
-
OR lower(${receiptTable}.error) LIKE '%runtime api call timed out%'
|
|
37
|
-
)
|
|
38
|
-
)
|
|
39
|
-
)
|
|
40
|
-
)
|
|
41
|
-
)`;
|
|
42
|
-
}
|
|
43
2
|
|
|
44
3
|
export function workReceiptClaimableStatusCodes(input: {
|
|
45
4
|
forceRefresh?: boolean;
|
|
@@ -96,11 +55,8 @@ export function workReceiptClaimConflictPredicateSql(input: {
|
|
|
96
55
|
)
|
|
97
56
|
OR ${table}.status <> ${RECEIPT_STATUS_CODE.failed}::smallint
|
|
98
57
|
OR (
|
|
99
|
-
${
|
|
100
|
-
AND
|
|
101
|
-
${table}.run_id IS DISTINCT FROM ${input.claimantRunIdSql}
|
|
102
|
-
OR COALESCE(${table}.lease_owner_attempt, 0) < ${claimantRunAttemptSql}::integer
|
|
103
|
-
)
|
|
58
|
+
${table}.status = ${RECEIPT_STATUS_CODE.failed}::smallint
|
|
59
|
+
AND ${table}.run_id IS DISTINCT FROM ${input.claimantRunIdSql}
|
|
104
60
|
)
|
|
105
61
|
)
|
|
106
62
|
AND (
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
isReusableWorkReceipt,
|
|
56
56
|
type WorkReceipt,
|
|
57
57
|
type WorkReceiptClaim,
|
|
58
|
-
|
|
58
|
+
workReceiptFailureKindCodeForWrite,
|
|
59
59
|
workReceiptFailureKindFromCode,
|
|
60
60
|
type WorkReceiptFailureKind,
|
|
61
61
|
} from './work-receipts';
|
|
@@ -249,7 +249,7 @@ async function forceFailRuntimeWorkReceiptForRuntimeTestFault(
|
|
|
249
249
|
RECEIPT_STATUS_FAILED,
|
|
250
250
|
input.error,
|
|
251
251
|
input.runId,
|
|
252
|
-
|
|
252
|
+
workReceiptFailureKindCodeForWrite(input.failureKind),
|
|
253
253
|
RECEIPT_STATUS_COMPLETED,
|
|
254
254
|
runAttempt,
|
|
255
255
|
],
|
|
@@ -5620,7 +5620,7 @@ export async function failRuntimeWorkReceipt(
|
|
|
5620
5620
|
input.error,
|
|
5621
5621
|
input.runId,
|
|
5622
5622
|
leaseId,
|
|
5623
|
-
|
|
5623
|
+
workReceiptFailureKindCodeForWrite(input.failureKind),
|
|
5624
5624
|
runAttempt,
|
|
5625
5625
|
input.errorPayload ? JSON.stringify(input.errorPayload) : null,
|
|
5626
5626
|
],
|
|
@@ -5855,7 +5855,7 @@ export async function failRuntimeWorkReceipts(
|
|
|
5855
5855
|
),
|
|
5856
5856
|
receipts.map((receipt) => receipt.error),
|
|
5857
5857
|
receipts.map((receipt) =>
|
|
5858
|
-
|
|
5858
|
+
workReceiptFailureKindCodeForWrite(receipt.failureKind),
|
|
5859
5859
|
),
|
|
5860
5860
|
receipts.map((receipt) =>
|
|
5861
5861
|
receipt.errorPayload ? JSON.stringify(receipt.errorPayload) : null,
|
|
@@ -17,50 +17,6 @@ export type WorkReceiptStateInput = {
|
|
|
17
17
|
leaseExpiresAt?: string | null;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
export function isLegacyRepairableWorkReceiptError(
|
|
21
|
-
error: string | null | undefined,
|
|
22
|
-
): boolean {
|
|
23
|
-
const message = error?.trim().toLowerCase() ?? '';
|
|
24
|
-
if (!message) return false;
|
|
25
|
-
// Transient billing-PLANE outages (503 BILLING_UNAVAILABLE) were historically
|
|
26
|
-
// formatted with the hard "billing cap exceeded" template (see
|
|
27
|
-
// formatHardBillingFailureMessage), so the receipts written during a
|
|
28
|
-
// billing-plane incident carry a "billing cap" string even though they are
|
|
29
|
-
// retryable infra failures that charged nothing. Recognize them BEFORE the
|
|
30
|
-
// hard-billing exclusion below so the poisoned backlog re-executes on the next
|
|
31
|
-
// run instead of replaying the cached failure. Real hard denials never carry a
|
|
32
|
-
// BILLING_UNAVAILABLE code or "temporarily unavailable" text.
|
|
33
|
-
if (
|
|
34
|
-
message.includes('billing_unavailable') ||
|
|
35
|
-
message.includes('billing is temporarily unavailable') ||
|
|
36
|
-
message.includes('billing temporarily unavailable')
|
|
37
|
-
) {
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
// Before insufficient-credit failures were written as repairable, the
|
|
41
|
-
// structured billing formatter persisted the balance snapshot in this
|
|
42
|
-
// stable shape. A later run must re-check the now-mutable balance while the
|
|
43
|
-
// same run attempt remains fenced by the claim decision below.
|
|
44
|
-
if (
|
|
45
|
-
message.includes('workspace balance ') &&
|
|
46
|
-
message.includes(' < required ')
|
|
47
|
-
) {
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
if (
|
|
51
|
-
message.includes('billing cap') ||
|
|
52
|
-
message.includes('insufficient credits') ||
|
|
53
|
-
message.includes('monthly billing limit')
|
|
54
|
-
) {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
return (
|
|
58
|
-
/(?:^|\D)5\d\d(?:\D|$)/.test(message) ||
|
|
59
|
-
message.includes('transport failed calling') ||
|
|
60
|
-
message.includes('runtime api call timed out')
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
20
|
export type WorkReceiptLeaseState =
|
|
65
21
|
| { kind: 'none' }
|
|
66
22
|
| {
|
|
@@ -312,15 +268,7 @@ export function decideWorkReceiptClaim(input: {
|
|
|
312
268
|
}
|
|
313
269
|
const claimantRunId = normalize(input.claimantRunId);
|
|
314
270
|
const ownerRunId = normalize(input.receipt.runId);
|
|
315
|
-
|
|
316
|
-
const ownerAttempt = normalizeAttempt(input.receipt.leaseOwnerAttempt);
|
|
317
|
-
if (
|
|
318
|
-
(input.receipt.failureKind === 'repairable' ||
|
|
319
|
-
isLegacyRepairableWorkReceiptError(input.receipt.error)) &&
|
|
320
|
-
claimantRunId !== null &&
|
|
321
|
-
ownerRunId !== null &&
|
|
322
|
-
(claimantRunId !== ownerRunId || ownerAttempt < claimantRunAttempt)
|
|
323
|
-
) {
|
|
271
|
+
if (claimantRunId !== null && claimantRunId !== ownerRunId) {
|
|
324
272
|
return { kind: 'claim' };
|
|
325
273
|
}
|
|
326
274
|
return { kind: 'blocked_failed' };
|
|
@@ -25,6 +25,20 @@ export function workReceiptFailureKindCode(
|
|
|
25
25
|
return WORK_RECEIPT_FAILURE_KIND_CODE[value ?? 'terminal'];
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Failure writes are always reclaimable by a later explicit Play Run.
|
|
30
|
+
*
|
|
31
|
+
* The input remains accepted at compatibility boundaries because older
|
|
32
|
+
* runners still send `terminal`, but new storage state must never make a
|
|
33
|
+
* failed semantic call permanent. Claim fencing, not this bit, prevents the
|
|
34
|
+
* owning run from automatically repeating the failure.
|
|
35
|
+
*/
|
|
36
|
+
export function workReceiptFailureKindCodeForWrite(
|
|
37
|
+
_value?: WorkReceiptFailureKind | null,
|
|
38
|
+
): number {
|
|
39
|
+
return WORK_RECEIPT_FAILURE_KIND_CODE.repairable;
|
|
40
|
+
}
|
|
41
|
+
|
|
28
42
|
export type WorkReceiptStatus =
|
|
29
43
|
| 'queued'
|
|
30
44
|
| 'pending'
|
package/dist/cli/index.js
CHANGED
|
@@ -1044,7 +1044,7 @@ var SDK_RELEASE = {
|
|
|
1044
1044
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
1045
1045
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
1046
1046
|
// release keeps lazy paging semantics independent of row residency.
|
|
1047
|
-
version: "0.2.
|
|
1047
|
+
version: "0.2.47",
|
|
1048
1048
|
contracts: {
|
|
1049
1049
|
api: {
|
|
1050
1050
|
name: "sdk-http-api",
|
|
@@ -31485,11 +31485,16 @@ Examples:
|
|
|
31485
31485
|
"after",
|
|
31486
31486
|
`
|
|
31487
31487
|
Notes:
|
|
31488
|
-
|
|
31489
|
-
|
|
31488
|
+
Mutates workspace state. <patch> is a JSON object of fields to update. Pass it
|
|
31489
|
+
positionally, via --file <path>, or from stdin with --file -.
|
|
31490
|
+
|
|
31491
|
+
When <patch> includes payload, its top-level fields are merged with the stored
|
|
31492
|
+
payload before validation. This lets you change one filter without resending
|
|
31493
|
+
domain or radar_type; nested values and arrays replace atomically.
|
|
31490
31494
|
|
|
31491
31495
|
Examples:
|
|
31492
31496
|
deepline monitors update my-monitor '{"name":"Interested replies"}' --json
|
|
31497
|
+
deepline monitors update job-openings '{"payload":{"job_titles":"CEO OR CFO"}}' --json
|
|
31493
31498
|
deepline monitors update my-monitor --file patch.json
|
|
31494
31499
|
`
|
|
31495
31500
|
).option(
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1030,7 +1030,7 @@ var SDK_RELEASE = {
|
|
|
1030
1030
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
1031
1031
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
1032
1032
|
// release keeps lazy paging semantics independent of row residency.
|
|
1033
|
-
version: "0.2.
|
|
1033
|
+
version: "0.2.47",
|
|
1034
1034
|
contracts: {
|
|
1035
1035
|
api: {
|
|
1036
1036
|
name: "sdk-http-api",
|
|
@@ -31536,11 +31536,16 @@ Examples:
|
|
|
31536
31536
|
"after",
|
|
31537
31537
|
`
|
|
31538
31538
|
Notes:
|
|
31539
|
-
|
|
31540
|
-
|
|
31539
|
+
Mutates workspace state. <patch> is a JSON object of fields to update. Pass it
|
|
31540
|
+
positionally, via --file <path>, or from stdin with --file -.
|
|
31541
|
+
|
|
31542
|
+
When <patch> includes payload, its top-level fields are merged with the stored
|
|
31543
|
+
payload before validation. This lets you change one filter without resending
|
|
31544
|
+
domain or radar_type; nested values and arrays replace atomically.
|
|
31541
31545
|
|
|
31542
31546
|
Examples:
|
|
31543
31547
|
deepline monitors update my-monitor '{"name":"Interested replies"}' --json
|
|
31548
|
+
deepline monitors update job-openings '{"payload":{"job_titles":"CEO OR CFO"}}' --json
|
|
31544
31549
|
deepline monitors update my-monitor --file patch.json
|
|
31545
31550
|
`
|
|
31546
31551
|
).option(
|
package/dist/index.js
CHANGED
|
@@ -763,7 +763,7 @@ var SDK_RELEASE = {
|
|
|
763
763
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
764
764
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
765
765
|
// release keeps lazy paging semantics independent of row residency.
|
|
766
|
-
version: "0.2.
|
|
766
|
+
version: "0.2.47",
|
|
767
767
|
contracts: {
|
|
768
768
|
api: {
|
|
769
769
|
name: "sdk-http-api",
|
package/dist/index.mjs
CHANGED
|
@@ -689,7 +689,7 @@ var SDK_RELEASE = {
|
|
|
689
689
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
690
690
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
691
691
|
// release keeps lazy paging semantics independent of row residency.
|
|
692
|
-
version: "0.2.
|
|
692
|
+
version: "0.2.47",
|
|
693
693
|
contracts: {
|
|
694
694
|
api: {
|
|
695
695
|
name: "sdk-http-api",
|