deepline 0.1.224 → 0.1.226
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/apps/play-runner-workers/src/entry.ts +8 -2
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/shared_libs/observability/tracing.ts +147 -22
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +15 -2
- package/dist/bundling-sources/shared_libs/play-runtime/live-state-contract.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-runtime/postgres-json.ts +66 -4
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +103 -15
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +8 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +36 -27
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-transition.ts +126 -8
- package/dist/bundling-sources/shared_libs/play-runtime/step-lifecycle-tracker.ts +3 -1
- package/dist/cli/index.js +22 -5
- package/dist/cli/index.mjs +22 -5
- package/dist/index.js +7 -2
- package/dist/index.mjs +7 -2
- package/package.json +1 -1
|
@@ -7836,6 +7836,9 @@ async function executeRunRequest(
|
|
|
7836
7836
|
occurredAt: event.at,
|
|
7837
7837
|
stepId: event.nodeId,
|
|
7838
7838
|
kind: event.type,
|
|
7839
|
+
...(event.transition === 'failed' && event.error
|
|
7840
|
+
? { error: event.error }
|
|
7841
|
+
: {}),
|
|
7839
7842
|
},
|
|
7840
7843
|
];
|
|
7841
7844
|
flushLedgerEvents(false);
|
|
@@ -8317,7 +8320,8 @@ async function executeRunRequest(
|
|
|
8317
8320
|
durationMs: nowMs() - startedAt,
|
|
8318
8321
|
};
|
|
8319
8322
|
} catch (error) {
|
|
8320
|
-
|
|
8323
|
+
const failure = normalizePlayRunFailure(error);
|
|
8324
|
+
stepLifecycle?.markStartedFailed(nowMs(), failure.message);
|
|
8321
8325
|
// A runtime-limit abort is a timeout failure, not a user cancellation, so
|
|
8322
8326
|
// it should be reported as run.failed with the limit message rather than
|
|
8323
8327
|
// run.cancelled.
|
|
@@ -8329,7 +8333,6 @@ async function executeRunRequest(
|
|
|
8329
8333
|
error instanceof Error ? error.message : 'Play run cancelled.',
|
|
8330
8334
|
);
|
|
8331
8335
|
}
|
|
8332
|
-
const failure = normalizePlayRunFailure(error);
|
|
8333
8336
|
const message = failure.message;
|
|
8334
8337
|
// Controlled run-fatal teardown: release the runtime-sheet row leases and
|
|
8335
8338
|
// work-receipt leases this attempt still holds so an immediate rerun is not
|
|
@@ -8369,6 +8372,9 @@ async function executeRunRequest(
|
|
|
8369
8372
|
retryable: failure.retryable,
|
|
8370
8373
|
...(errorBilling ? { billing: errorBilling } : {}),
|
|
8371
8374
|
...(failure.cause ? { cause: failure.cause } : {}),
|
|
8375
|
+
...(failure.name ? { name: failure.name } : {}),
|
|
8376
|
+
...(failure.stack ? { stack: failure.stack } : {}),
|
|
8377
|
+
...(failure.causes ? { causes: failure.causes } : {}),
|
|
8372
8378
|
},
|
|
8373
8379
|
],
|
|
8374
8380
|
});
|
|
@@ -108,10 +108,10 @@ export const SDK_RELEASE = {
|
|
|
108
108
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
109
109
|
// 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
|
|
110
110
|
// automatically without blocking their current command.
|
|
111
|
-
version: '0.1.
|
|
111
|
+
version: '0.1.226',
|
|
112
112
|
apiContract: '2026-06-dataset-handle-results-hard-cutover',
|
|
113
113
|
supportPolicy: {
|
|
114
|
-
latest: '0.1.
|
|
114
|
+
latest: '0.1.226',
|
|
115
115
|
minimumSupported: '0.1.53',
|
|
116
116
|
deprecatedBelow: '0.1.219',
|
|
117
117
|
commandMinimumSupported: [
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
INVALID_SPAN_CONTEXT,
|
|
2
3
|
SpanKind,
|
|
3
4
|
SpanStatusCode,
|
|
4
5
|
trace,
|
|
@@ -10,6 +11,97 @@ type PrimitiveAttribute = string | number | boolean | null | undefined;
|
|
|
10
11
|
|
|
11
12
|
type TraceAttributes = Record<string, PrimitiveAttribute>;
|
|
12
13
|
|
|
14
|
+
const NOOP_SPAN: Span = {
|
|
15
|
+
spanContext: () => INVALID_SPAN_CONTEXT,
|
|
16
|
+
setAttribute: () => NOOP_SPAN,
|
|
17
|
+
setAttributes: () => NOOP_SPAN,
|
|
18
|
+
addEvent: () => NOOP_SPAN,
|
|
19
|
+
addLink: () => NOOP_SPAN,
|
|
20
|
+
addLinks: () => NOOP_SPAN,
|
|
21
|
+
setStatus: () => NOOP_SPAN,
|
|
22
|
+
updateName: () => NOOP_SPAN,
|
|
23
|
+
end: () => undefined,
|
|
24
|
+
isRecording: () => false,
|
|
25
|
+
recordException: () => undefined,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
function discardTelemetryResult(invoke: () => unknown): void {
|
|
29
|
+
try {
|
|
30
|
+
const result = invoke();
|
|
31
|
+
if (
|
|
32
|
+
result === null ||
|
|
33
|
+
(typeof result !== 'object' && typeof result !== 'function')
|
|
34
|
+
) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
let then: unknown;
|
|
38
|
+
try {
|
|
39
|
+
then = Reflect.get(result, 'then');
|
|
40
|
+
} catch {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (typeof then === 'function') {
|
|
44
|
+
void Promise.resolve(result).catch(() => undefined);
|
|
45
|
+
}
|
|
46
|
+
} catch {}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function nonBlockingSpan(span: Span): Span {
|
|
50
|
+
const safeSpan: Span = {
|
|
51
|
+
spanContext() {
|
|
52
|
+
try {
|
|
53
|
+
return span.spanContext();
|
|
54
|
+
} catch {
|
|
55
|
+
return INVALID_SPAN_CONTEXT;
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
setAttribute(key, value) {
|
|
59
|
+
discardTelemetryResult(() => span.setAttribute(key, value));
|
|
60
|
+
return safeSpan;
|
|
61
|
+
},
|
|
62
|
+
setAttributes(attributes) {
|
|
63
|
+
discardTelemetryResult(() => span.setAttributes(attributes));
|
|
64
|
+
return safeSpan;
|
|
65
|
+
},
|
|
66
|
+
addEvent(name, attributesOrStartTime, startTime) {
|
|
67
|
+
discardTelemetryResult(() =>
|
|
68
|
+
span.addEvent(name, attributesOrStartTime, startTime),
|
|
69
|
+
);
|
|
70
|
+
return safeSpan;
|
|
71
|
+
},
|
|
72
|
+
addLink(link) {
|
|
73
|
+
discardTelemetryResult(() => span.addLink(link));
|
|
74
|
+
return safeSpan;
|
|
75
|
+
},
|
|
76
|
+
addLinks(links) {
|
|
77
|
+
discardTelemetryResult(() => span.addLinks(links));
|
|
78
|
+
return safeSpan;
|
|
79
|
+
},
|
|
80
|
+
setStatus(status) {
|
|
81
|
+
discardTelemetryResult(() => span.setStatus(status));
|
|
82
|
+
return safeSpan;
|
|
83
|
+
},
|
|
84
|
+
updateName(name) {
|
|
85
|
+
discardTelemetryResult(() => span.updateName(name));
|
|
86
|
+
return safeSpan;
|
|
87
|
+
},
|
|
88
|
+
end(endTime) {
|
|
89
|
+
discardTelemetryResult(() => span.end(endTime));
|
|
90
|
+
},
|
|
91
|
+
isRecording() {
|
|
92
|
+
try {
|
|
93
|
+
return span.isRecording();
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
recordException(exception, time) {
|
|
99
|
+
discardTelemetryResult(() => span.recordException(exception, time));
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
return safeSpan;
|
|
103
|
+
}
|
|
104
|
+
|
|
13
105
|
function normalizeAttributes(
|
|
14
106
|
attributes: TraceAttributes | undefined,
|
|
15
107
|
): Attributes | undefined {
|
|
@@ -60,34 +152,67 @@ export async function withActiveSpan<T>(
|
|
|
60
152
|
},
|
|
61
153
|
fn: (span: Span) => Promise<T> | T,
|
|
62
154
|
): Promise<T> {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
155
|
+
let operationPromise: Promise<T> | null = null;
|
|
156
|
+
const runOperation = async (span: Span): Promise<T> => {
|
|
157
|
+
const safeSpan = nonBlockingSpan(span);
|
|
158
|
+
try {
|
|
159
|
+
const result = await fn(safeSpan);
|
|
160
|
+
safeSpan.setStatus({ code: SpanStatusCode.OK });
|
|
161
|
+
return result;
|
|
162
|
+
} catch (error) {
|
|
71
163
|
try {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
} catch (error) {
|
|
76
|
-
recordError(span, error);
|
|
77
|
-
throw error;
|
|
78
|
-
} finally {
|
|
79
|
-
span.end();
|
|
164
|
+
recordError(safeSpan, error);
|
|
165
|
+
} catch {
|
|
166
|
+
// Error telemetry must not replace the operation's real error.
|
|
80
167
|
}
|
|
81
|
-
|
|
82
|
-
|
|
168
|
+
throw error;
|
|
169
|
+
} finally {
|
|
170
|
+
safeSpan.end();
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const startOperation = (span: Span): Promise<T> => {
|
|
174
|
+
if (operationPromise) return operationPromise;
|
|
175
|
+
let resolveOperation!: (value: T | PromiseLike<T>) => void;
|
|
176
|
+
let rejectOperation!: (reason?: unknown) => void;
|
|
177
|
+
operationPromise = new Promise<T>((resolve, reject) => {
|
|
178
|
+
resolveOperation = resolve;
|
|
179
|
+
rejectOperation = reject;
|
|
180
|
+
});
|
|
181
|
+
void runOperation(span).then(resolveOperation, rejectOperation);
|
|
182
|
+
return operationPromise;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
let tracerResult: unknown;
|
|
186
|
+
try {
|
|
187
|
+
const tracer = trace.getTracer(options.tracer ?? 'deepline');
|
|
188
|
+
tracerResult = tracer.startActiveSpan(
|
|
189
|
+
name,
|
|
190
|
+
{
|
|
191
|
+
kind: options.kind,
|
|
192
|
+
attributes: normalizeAttributes(options.attributes),
|
|
193
|
+
},
|
|
194
|
+
(span) => startOperation(span),
|
|
195
|
+
);
|
|
196
|
+
} catch {}
|
|
197
|
+
|
|
198
|
+
// A non-conforming exporter may return work unrelated to the callback.
|
|
199
|
+
// Drain its rejection without awaiting it; only execution owns latency and
|
|
200
|
+
// the returned success/failure contract.
|
|
201
|
+
discardTelemetryResult(() => tracerResult);
|
|
202
|
+
|
|
203
|
+
// A broken tracer may return without invoking the callback. Execution is
|
|
204
|
+
// authoritative, so run it once without telemetry in that case.
|
|
205
|
+
return await startOperation(NOOP_SPAN);
|
|
83
206
|
}
|
|
84
207
|
|
|
85
208
|
export function setSpanAttributes(
|
|
86
209
|
span: Span,
|
|
87
210
|
attributes: TraceAttributes,
|
|
88
211
|
): void {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
212
|
+
try {
|
|
213
|
+
const normalized = normalizeAttributes(attributes);
|
|
214
|
+
if (normalized) {
|
|
215
|
+
discardTelemetryResult(() => span.setAttributes(normalized));
|
|
216
|
+
}
|
|
217
|
+
} catch {}
|
|
93
218
|
}
|
|
@@ -33,6 +33,8 @@ import { createRuntimeReceiptHeartbeatSupervisor } from './receipt-heartbeat-sup
|
|
|
33
33
|
import { dispatchBoundedSettled } from './bounded-dispatch';
|
|
34
34
|
import type { PlayQueueHint } from './governor/rate-state-backend';
|
|
35
35
|
import type { MapRowOutcome } from './durability-store';
|
|
36
|
+
import { stringifyPostgresJson } from './postgres-json';
|
|
37
|
+
import { RUNTIME_ROW_OUTPUT_NOT_JSON_SERIALIZABLE } from './runtime-sheet-row-transition';
|
|
36
38
|
import type { WorkReceiptFailureKind } from './work-receipts';
|
|
37
39
|
import {
|
|
38
40
|
completedMapRowOutcome,
|
|
@@ -3090,9 +3092,19 @@ export class PlayContextImpl {
|
|
|
3090
3092
|
// are no-ops for any value that is not a tool result.
|
|
3091
3093
|
|
|
3092
3094
|
private serializeCellValue(value: unknown): unknown {
|
|
3093
|
-
|
|
3095
|
+
const serialized = isToolExecuteResult(value)
|
|
3094
3096
|
? serializeToolExecuteResult(value)
|
|
3095
3097
|
: value;
|
|
3098
|
+
try {
|
|
3099
|
+
stringifyPostgresJson(serialized);
|
|
3100
|
+
} catch (error) {
|
|
3101
|
+
throw new Error(
|
|
3102
|
+
`${RUNTIME_ROW_OUTPUT_NOT_JSON_SERIALIZABLE}: Dataset cell output is not JSON-serializable: ${
|
|
3103
|
+
error instanceof Error ? error.message : String(error)
|
|
3104
|
+
}`,
|
|
3105
|
+
);
|
|
3106
|
+
}
|
|
3107
|
+
return serialized;
|
|
3096
3108
|
}
|
|
3097
3109
|
|
|
3098
3110
|
private rehydrateCellValue(value: unknown): unknown {
|
|
@@ -5391,6 +5403,7 @@ export class PlayContextImpl {
|
|
|
5391
5403
|
});
|
|
5392
5404
|
|
|
5393
5405
|
let value: unknown;
|
|
5406
|
+
let cellValue: unknown;
|
|
5394
5407
|
try {
|
|
5395
5408
|
value = await rowContext.run(
|
|
5396
5409
|
{
|
|
@@ -5411,6 +5424,7 @@ export class PlayContextImpl {
|
|
|
5411
5424
|
this.previousCellForField(baseRow, fieldName),
|
|
5412
5425
|
),
|
|
5413
5426
|
);
|
|
5427
|
+
cellValue = this.serializeCellValue(value);
|
|
5414
5428
|
} catch (error) {
|
|
5415
5429
|
if (
|
|
5416
5430
|
isPlayRowExecutionSuspendedError(error) ||
|
|
@@ -5482,7 +5496,6 @@ export class PlayContextImpl {
|
|
|
5482
5496
|
});
|
|
5483
5497
|
return FAILED_ROW;
|
|
5484
5498
|
}
|
|
5485
|
-
const cellValue = this.serializeCellValue(value);
|
|
5486
5499
|
computedFields[fieldName] = cellValue;
|
|
5487
5500
|
this.rowStates.get(idx)?.results.set(fieldName, cellValue);
|
|
5488
5501
|
const currentCellMeta =
|
|
@@ -35,6 +35,7 @@ export type PlayVisualNodeProgressSnapshot = {
|
|
|
35
35
|
export type PlayVisualNodeStateSnapshot = {
|
|
36
36
|
nodeId: string;
|
|
37
37
|
status: PlayVisualNodeStatus;
|
|
38
|
+
error?: string | null;
|
|
38
39
|
artifactTableNamespace?: string | null;
|
|
39
40
|
progress?: PlayVisualNodeProgressSnapshot | null;
|
|
40
41
|
startedAt?: number | null;
|
|
@@ -1,9 +1,71 @@
|
|
|
1
|
-
const
|
|
1
|
+
const POSTGRES_JSON_REPLACEMENT_CHARACTER = '\uFFFD';
|
|
2
|
+
const POSTGRES_JSON_SUSPECT_CODE_UNIT_RE = /[\u0000\uD800-\uDFFF]/;
|
|
3
|
+
|
|
4
|
+
function sanitizePostgresJsonString(value: string): string {
|
|
5
|
+
if (!POSTGRES_JSON_SUSPECT_CODE_UNIT_RE.test(value)) return value;
|
|
6
|
+
|
|
7
|
+
let sanitized = '';
|
|
8
|
+
let changed = false;
|
|
9
|
+
|
|
10
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
11
|
+
const codeUnit = value.charCodeAt(index);
|
|
12
|
+
if (codeUnit === 0) {
|
|
13
|
+
changed = true;
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (codeUnit >= 0xd800 && codeUnit <= 0xdbff) {
|
|
18
|
+
const nextCodeUnit = value.charCodeAt(index + 1);
|
|
19
|
+
if (nextCodeUnit >= 0xdc00 && nextCodeUnit <= 0xdfff) {
|
|
20
|
+
sanitized += value[index] + value[index + 1];
|
|
21
|
+
index += 1;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
sanitized += POSTGRES_JSON_REPLACEMENT_CHARACTER;
|
|
25
|
+
changed = true;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (codeUnit >= 0xdc00 && codeUnit <= 0xdfff) {
|
|
30
|
+
sanitized += POSTGRES_JSON_REPLACEMENT_CHARACTER;
|
|
31
|
+
changed = true;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
sanitized += value[index];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return changed ? sanitized : value;
|
|
39
|
+
}
|
|
2
40
|
|
|
3
41
|
function postgresJsonReplacer(_key: string, value: unknown): unknown {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
42
|
+
if (typeof value === 'string') {
|
|
43
|
+
return sanitizePostgresJsonString(value);
|
|
44
|
+
}
|
|
45
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const keys = Object.keys(value);
|
|
50
|
+
if (!keys.some((key) => sanitizePostgresJsonString(key) !== key)) {
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
const sanitizedEntries: Array<[string, unknown]> = [];
|
|
54
|
+
const sanitizedKeys = new Set<string>();
|
|
55
|
+
for (const key of keys) {
|
|
56
|
+
const sanitizedKey = sanitizePostgresJsonString(key);
|
|
57
|
+
if (sanitizedKeys.has(sanitizedKey)) {
|
|
58
|
+
throw new TypeError(
|
|
59
|
+
'Postgres JSON key normalization produced a duplicate object key.',
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
sanitizedKeys.add(sanitizedKey);
|
|
63
|
+
sanitizedEntries.push([
|
|
64
|
+
sanitizedKey,
|
|
65
|
+
(value as Record<string, unknown>)[key],
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
return Object.fromEntries(sanitizedEntries);
|
|
7
69
|
}
|
|
8
70
|
|
|
9
71
|
export function sanitizePostgresJsonValue<T>(value: T): T {
|
|
@@ -12,6 +12,7 @@ import type { PreloadedRuntimeDbSession } from './db-session';
|
|
|
12
12
|
import type { PacingRule } from './governor/rate-state-backend';
|
|
13
13
|
import type { GovernanceSnapshot } from './governor/governor';
|
|
14
14
|
import type { PlayRunInputPayload } from './play-input';
|
|
15
|
+
import type { PlayRunFailureDetails } from './run-failure';
|
|
15
16
|
|
|
16
17
|
export type PlayRunnerRateStateBackendConfig =
|
|
17
18
|
| {
|
|
@@ -165,6 +166,7 @@ export interface PlayRunnerExecutionConfig {
|
|
|
165
166
|
artifactTransport?: {
|
|
166
167
|
bundledCodePath?: string | null;
|
|
167
168
|
bundledCodeEncoding?: 'utf8' | 'gzip';
|
|
169
|
+
sourceMapPath?: string | null;
|
|
168
170
|
} | null;
|
|
169
171
|
input: PlayRunInputPayload;
|
|
170
172
|
checkpoint?: PlayCheckpoint | null;
|
|
@@ -241,6 +243,7 @@ export type PlayRunnerResult =
|
|
|
241
243
|
| {
|
|
242
244
|
status: 'failed';
|
|
243
245
|
error: string;
|
|
246
|
+
errors?: PlayRunFailureDetails[];
|
|
244
247
|
logs: string[];
|
|
245
248
|
stats: Record<string, unknown>;
|
|
246
249
|
steps: PlayStep[];
|
|
@@ -6,6 +6,7 @@ const CLOUDFLARE_WORKFLOW_ENDPOINT_UNAVAILABLE_RE =
|
|
|
6
6
|
/The requested endpoint could not be found, or you don't have access to it\. Please check the provided ID and try again\./i;
|
|
7
7
|
const VERCEL_RUNTIME_API_DEPLOYMENT_MISSING_RE =
|
|
8
8
|
/runtime API 404:[\s\S]*(?:DeploymentNotFound|DEPLOYMENT_NOT_FOUND|requested deployment .*exist|deployment could not be found on Vercel)/i;
|
|
9
|
+
const RUNTIME_SANDBOX_LOST_RE = /\bRUNTIME_SANDBOX_LOST\b/i;
|
|
9
10
|
|
|
10
11
|
export const PLATFORM_DEPLOY_INTERRUPTED_MESSAGE =
|
|
11
12
|
'Run interrupted by a platform deploy. Deepline retries this automatically when possible; if this error is still visible, re-run the same command.';
|
|
@@ -16,6 +17,8 @@ export const PLATFORM_WORKFLOW_ENDPOINT_INTERRUPTED_MESSAGE =
|
|
|
16
17
|
|
|
17
18
|
export const INTERNAL_RUNTIME_STORAGE_ERROR_MESSAGE =
|
|
18
19
|
'Internal play runtime storage failed. Please retry the run; if this keeps happening, contact Deepline support with the run ID.';
|
|
20
|
+
export const RUNTIME_SANDBOX_LOST_MESSAGE =
|
|
21
|
+
'The execution sandbox became unreachable before returning a terminal result. Re-run the same command; if this keeps happening, contact Deepline support with the run ID.';
|
|
19
22
|
|
|
20
23
|
export const WORKSPACE_STORAGE_NOT_READY_CODE = 'WORKSPACE_STORAGE_NOT_READY';
|
|
21
24
|
|
|
@@ -90,11 +93,7 @@ export class ProviderExhaustedError extends Error {
|
|
|
90
93
|
readonly provider: string;
|
|
91
94
|
/** ISO 8601 retry deadline (from the server Retry-After / cooldown). */
|
|
92
95
|
readonly retryAt: string;
|
|
93
|
-
constructor(input: {
|
|
94
|
-
provider: string;
|
|
95
|
-
retryAtMs: number;
|
|
96
|
-
cause?: unknown;
|
|
97
|
-
}) {
|
|
96
|
+
constructor(input: { provider: string; retryAtMs: number; cause?: unknown }) {
|
|
98
97
|
// Prefix the code token so `String(error)` and any persisted error string
|
|
99
98
|
// carry it across the serialization boundary back to the CLI, exactly like
|
|
100
99
|
// WorkspaceStorageNotReadyError.
|
|
@@ -124,8 +123,7 @@ export class ProviderExhaustedError extends Error {
|
|
|
124
123
|
*/
|
|
125
124
|
export function providerNameFromBucketId(bucketId: string): string {
|
|
126
125
|
const separator = bucketId.indexOf(':');
|
|
127
|
-
const provider =
|
|
128
|
-
separator >= 0 ? bucketId.slice(separator + 1) : bucketId;
|
|
126
|
+
const provider = separator >= 0 ? bucketId.slice(separator + 1) : bucketId;
|
|
129
127
|
return provider.startsWith('tool:')
|
|
130
128
|
? provider.slice('tool:'.length)
|
|
131
129
|
: provider;
|
|
@@ -137,8 +135,66 @@ export type PlayRunFailureDetails = {
|
|
|
137
135
|
message: string;
|
|
138
136
|
retryable: boolean | null;
|
|
139
137
|
cause?: string;
|
|
138
|
+
name?: string;
|
|
139
|
+
stack?: string;
|
|
140
|
+
causes?: string[];
|
|
140
141
|
};
|
|
141
142
|
|
|
143
|
+
const PUBLIC_FAILURE_STACK_LINE_LIMIT = 12;
|
|
144
|
+
const PUBLIC_FAILURE_TEXT_BYTE_LIMIT = 64 * 1024;
|
|
145
|
+
const PUBLIC_FAILURE_CAUSE_LIMIT = 8;
|
|
146
|
+
const PUBLIC_FAILURE_CAUSE_LENGTH_LIMIT = 1_000;
|
|
147
|
+
|
|
148
|
+
function boundedFailureText(value: string): string {
|
|
149
|
+
const encoder = new TextEncoder();
|
|
150
|
+
if (encoder.encode(value).byteLength <= PUBLIC_FAILURE_TEXT_BYTE_LIMIT) {
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
let bytes = 0;
|
|
154
|
+
let output = '';
|
|
155
|
+
for (const character of value) {
|
|
156
|
+
const characterBytes = encoder.encode(character).byteLength;
|
|
157
|
+
if (bytes + characterBytes > PUBLIC_FAILURE_TEXT_BYTE_LIMIT) break;
|
|
158
|
+
output += character;
|
|
159
|
+
bytes += characterBytes;
|
|
160
|
+
}
|
|
161
|
+
return `${output}\n[truncated]`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function boundedFailureStack(error: Error): string | undefined {
|
|
165
|
+
if (typeof error.stack !== 'string' || !error.stack.trim()) return undefined;
|
|
166
|
+
return boundedFailureText(
|
|
167
|
+
error.stack.split('\n').slice(0, PUBLIC_FAILURE_STACK_LINE_LIMIT).join('\n'),
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function failureCauseTexts(error: Error): string[] {
|
|
172
|
+
const queue: unknown[] = [];
|
|
173
|
+
const seen = new Set<unknown>([error]);
|
|
174
|
+
const causes: string[] = [];
|
|
175
|
+
const withCause = error as Error & { cause?: unknown };
|
|
176
|
+
if (withCause.cause !== undefined) queue.push(withCause.cause);
|
|
177
|
+
if (error instanceof AggregateError) queue.push(...error.errors);
|
|
178
|
+
|
|
179
|
+
while (queue.length > 0 && causes.length < PUBLIC_FAILURE_CAUSE_LIMIT) {
|
|
180
|
+
const current = queue.shift();
|
|
181
|
+
if (current === undefined || current === null || seen.has(current)) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
seen.add(current);
|
|
185
|
+
const text = toErrorText(current).trim();
|
|
186
|
+
if (text && text !== error.message && !causes.includes(text)) {
|
|
187
|
+
causes.push(text.slice(0, PUBLIC_FAILURE_CAUSE_LENGTH_LIMIT));
|
|
188
|
+
}
|
|
189
|
+
if (current instanceof Error) {
|
|
190
|
+
const nested = current as Error & { cause?: unknown };
|
|
191
|
+
if (nested.cause !== undefined) queue.push(nested.cause);
|
|
192
|
+
if (current instanceof AggregateError) queue.push(...current.errors);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return causes;
|
|
196
|
+
}
|
|
197
|
+
|
|
142
198
|
function toErrorText(error: unknown): string {
|
|
143
199
|
if (error instanceof Error) {
|
|
144
200
|
return error.message;
|
|
@@ -147,8 +203,23 @@ function toErrorText(error: unknown): string {
|
|
|
147
203
|
}
|
|
148
204
|
|
|
149
205
|
export function normalizePlayRunFailure(error: unknown): PlayRunFailureDetails {
|
|
150
|
-
const
|
|
151
|
-
|
|
206
|
+
const rawCause = toErrorText(error);
|
|
207
|
+
const cause = boundedFailureText(rawCause);
|
|
208
|
+
if (RUNTIME_SANDBOX_LOST_RE.test(rawCause)) {
|
|
209
|
+
const stack = error instanceof Error ? boundedFailureStack(error) : null;
|
|
210
|
+
const causes = error instanceof Error ? failureCauseTexts(error) : [];
|
|
211
|
+
return {
|
|
212
|
+
code: 'RUNTIME_SANDBOX_LOST',
|
|
213
|
+
phase: 'infrastructure',
|
|
214
|
+
message: RUNTIME_SANDBOX_LOST_MESSAGE,
|
|
215
|
+
retryable: true,
|
|
216
|
+
cause,
|
|
217
|
+
...(error instanceof Error ? { name: error.name || 'Error' } : {}),
|
|
218
|
+
...(stack ? { stack } : {}),
|
|
219
|
+
...(causes.length > 0 ? { causes } : {}),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (CLOUDFLARE_DURABLE_OBJECT_RESET_RE.test(rawCause)) {
|
|
152
223
|
return {
|
|
153
224
|
code: 'PLATFORM_DEPLOY_INTERRUPTED',
|
|
154
225
|
phase: 'runtime',
|
|
@@ -157,7 +228,7 @@ export function normalizePlayRunFailure(error: unknown): PlayRunFailureDetails {
|
|
|
157
228
|
cause,
|
|
158
229
|
};
|
|
159
230
|
}
|
|
160
|
-
if (VERCEL_RUNTIME_API_DEPLOYMENT_MISSING_RE.test(
|
|
231
|
+
if (VERCEL_RUNTIME_API_DEPLOYMENT_MISSING_RE.test(rawCause)) {
|
|
161
232
|
return {
|
|
162
233
|
code: 'PLATFORM_DEPLOY_INTERRUPTED',
|
|
163
234
|
phase: 'runtime',
|
|
@@ -166,7 +237,7 @@ export function normalizePlayRunFailure(error: unknown): PlayRunFailureDetails {
|
|
|
166
237
|
cause,
|
|
167
238
|
};
|
|
168
239
|
}
|
|
169
|
-
if (CLOUDFLARE_WORKER_SUBREQUEST_LIMIT_RE.test(
|
|
240
|
+
if (CLOUDFLARE_WORKER_SUBREQUEST_LIMIT_RE.test(rawCause)) {
|
|
170
241
|
return {
|
|
171
242
|
code: 'PLATFORM_WORKER_SUBREQUEST_INTERRUPTED',
|
|
172
243
|
phase: 'runtime',
|
|
@@ -175,7 +246,7 @@ export function normalizePlayRunFailure(error: unknown): PlayRunFailureDetails {
|
|
|
175
246
|
cause,
|
|
176
247
|
};
|
|
177
248
|
}
|
|
178
|
-
if (CLOUDFLARE_WORKFLOW_ENDPOINT_UNAVAILABLE_RE.test(
|
|
249
|
+
if (CLOUDFLARE_WORKFLOW_ENDPOINT_UNAVAILABLE_RE.test(rawCause)) {
|
|
179
250
|
return {
|
|
180
251
|
code: 'PLATFORM_WORKFLOW_ENDPOINT_INTERRUPTED',
|
|
181
252
|
phase: 'runtime',
|
|
@@ -184,7 +255,7 @@ export function normalizePlayRunFailure(error: unknown): PlayRunFailureDetails {
|
|
|
184
255
|
cause,
|
|
185
256
|
};
|
|
186
257
|
}
|
|
187
|
-
const playDepthBudgetMatch =
|
|
258
|
+
const playDepthBudgetMatch = rawCause.match(
|
|
188
259
|
/Play execution playDepth budget exceeded \((\d+)\/(\d+)\)\./,
|
|
189
260
|
);
|
|
190
261
|
if (playDepthBudgetMatch) {
|
|
@@ -198,7 +269,7 @@ export function normalizePlayRunFailure(error: unknown): PlayRunFailureDetails {
|
|
|
198
269
|
}
|
|
199
270
|
if (
|
|
200
271
|
error instanceof ProviderExhaustedError ||
|
|
201
|
-
/\bPROVIDER_EXHAUSTED\b/.test(
|
|
272
|
+
/\bPROVIDER_EXHAUSTED\b/.test(rawCause)
|
|
202
273
|
) {
|
|
203
274
|
// The human message (provider + retry time) already lives in `cause` after
|
|
204
275
|
// the code token prefix; surface it verbatim minus the token so the run
|
|
@@ -218,7 +289,7 @@ export function normalizePlayRunFailure(error: unknown): PlayRunFailureDetails {
|
|
|
218
289
|
}
|
|
219
290
|
if (
|
|
220
291
|
error instanceof WorkspaceStorageNotReadyError ||
|
|
221
|
-
/\bWORKSPACE_STORAGE_NOT_READY\b/.test(
|
|
292
|
+
/\bWORKSPACE_STORAGE_NOT_READY\b/.test(rawCause)
|
|
222
293
|
) {
|
|
223
294
|
return {
|
|
224
295
|
code: WORKSPACE_STORAGE_NOT_READY_CODE,
|
|
@@ -242,10 +313,27 @@ export function normalizePlayRunFailure(error: unknown): PlayRunFailureDetails {
|
|
|
242
313
|
retryable: true,
|
|
243
314
|
};
|
|
244
315
|
}
|
|
316
|
+
const diagnostics =
|
|
317
|
+
error instanceof Error
|
|
318
|
+
? {
|
|
319
|
+
name: error.name || 'Error',
|
|
320
|
+
stack: boundedFailureStack(error),
|
|
321
|
+
causes: failureCauseTexts(error),
|
|
322
|
+
}
|
|
323
|
+
: null;
|
|
245
324
|
return {
|
|
246
325
|
code: 'RUN_FAILED',
|
|
247
326
|
phase: 'runtime',
|
|
248
327
|
message: cause,
|
|
249
328
|
retryable: null,
|
|
329
|
+
...(diagnostics
|
|
330
|
+
? {
|
|
331
|
+
name: diagnostics.name,
|
|
332
|
+
...(diagnostics.stack ? { stack: diagnostics.stack } : {}),
|
|
333
|
+
...(diagnostics.causes.length > 0
|
|
334
|
+
? { causes: diagnostics.causes }
|
|
335
|
+
: {}),
|
|
336
|
+
}
|
|
337
|
+
: {}),
|
|
250
338
|
};
|
|
251
339
|
}
|
|
@@ -78,6 +78,7 @@ export type PlayRunLedgerStepSnapshot = {
|
|
|
78
78
|
label?: string;
|
|
79
79
|
kind?: string;
|
|
80
80
|
status: PlayRunLedgerStepStatus;
|
|
81
|
+
error?: string | null;
|
|
81
82
|
artifactTableNamespace?: string | null;
|
|
82
83
|
startedAt?: number | null;
|
|
83
84
|
completedAt?: number | null;
|
|
@@ -480,6 +481,7 @@ export function normalizePlayRunLedgerSnapshot(
|
|
|
480
481
|
label: optionalString(rawStep.label),
|
|
481
482
|
kind: optionalString(rawStep.kind),
|
|
482
483
|
status,
|
|
484
|
+
error: optionalNullableString(rawStep.error),
|
|
483
485
|
artifactTableNamespace: optionalNullableString(
|
|
484
486
|
rawStep.artifactTableNamespace,
|
|
485
487
|
),
|
|
@@ -1255,6 +1257,7 @@ export function reducePlayRunLedgerEvent(
|
|
|
1255
1257
|
label: event.label ?? current?.label,
|
|
1256
1258
|
kind: event.kind ?? current?.kind,
|
|
1257
1259
|
status,
|
|
1260
|
+
error: current?.error ?? null,
|
|
1258
1261
|
artifactTableNamespace:
|
|
1259
1262
|
progress?.artifactTableNamespace ??
|
|
1260
1263
|
current?.artifactTableNamespace ??
|
|
@@ -1308,6 +1311,12 @@ export function reducePlayRunLedgerEvent(
|
|
|
1308
1311
|
label: event.label ?? current?.label,
|
|
1309
1312
|
kind: event.kind ?? current?.kind,
|
|
1310
1313
|
status,
|
|
1314
|
+
error:
|
|
1315
|
+
event.type === 'step.failed'
|
|
1316
|
+
? (event.error ?? current?.error ?? null)
|
|
1317
|
+
: preserveFailedStatus
|
|
1318
|
+
? (current?.error ?? null)
|
|
1319
|
+
: null,
|
|
1311
1320
|
artifactTableNamespace:
|
|
1312
1321
|
event.artifactTableNamespace ??
|
|
1313
1322
|
current?.artifactTableNamespace ??
|
|
@@ -46,6 +46,7 @@ export type PlayRunStreamNodeProgress = {
|
|
|
46
46
|
export type PlayRunStreamNodeState = {
|
|
47
47
|
nodeId: string;
|
|
48
48
|
status: 'idle' | 'running' | 'completed' | 'failed' | 'skipped';
|
|
49
|
+
error?: string | null;
|
|
49
50
|
artifactTableNamespace?: string | null;
|
|
50
51
|
progress?: PlayRunStreamNodeProgress | null;
|
|
51
52
|
startedAt?: number | null;
|
|
@@ -167,6 +168,7 @@ function buildSnapshotFromLedger(
|
|
|
167
168
|
.map((step) => ({
|
|
168
169
|
nodeId: step.stepId,
|
|
169
170
|
status: step.status,
|
|
171
|
+
error: step.error ?? null,
|
|
170
172
|
artifactTableNamespace: step.artifactTableNamespace ?? null,
|
|
171
173
|
progress: step.progress
|
|
172
174
|
? {
|
|
@@ -19,6 +19,7 @@ type DaytonaPayloadEnvelope = {
|
|
|
19
19
|
schemaVersion: 1;
|
|
20
20
|
runnerCode: string;
|
|
21
21
|
artifactBundledCode: string;
|
|
22
|
+
artifactSourceMap: string;
|
|
22
23
|
config: PlayRunnerExecutionConfig;
|
|
23
24
|
/** Crash-containment epilogue script (see buildDaytonaCrashTerminalPusherSource). */
|
|
24
25
|
crashPusherCode: string;
|
|
@@ -50,10 +51,11 @@ function nodeMaterializePayloadCommand(input: {
|
|
|
50
51
|
runnerPath: string;
|
|
51
52
|
configPath: string;
|
|
52
53
|
artifactCodePath: string;
|
|
54
|
+
artifactSourceMapPath: string;
|
|
53
55
|
crashPusherPath: string;
|
|
54
56
|
}): string {
|
|
55
57
|
const script =
|
|
56
|
-
"const fs=require('node:fs');const zlib=require('node:zlib');const p=JSON.parse(zlib.gunzipSync(fs.readFileSync(process.argv[1])));if(p.schemaVersion!==1)throw new Error('Unsupported Daytona payload envelope');fs.writeFileSync(process.argv[2],p.runnerCode);fs.writeFileSync(process.argv[3],JSON.stringify(p.config));fs.writeFileSync(process.argv[4],p.artifactBundledCode);fs.writeFileSync(process.argv[5],p.crashPusherCode);";
|
|
58
|
+
"const fs=require('node:fs');const zlib=require('node:zlib');const p=JSON.parse(zlib.gunzipSync(fs.readFileSync(process.argv[1])));if(p.schemaVersion!==1)throw new Error('Unsupported Daytona payload envelope');fs.writeFileSync(process.argv[2],p.runnerCode);fs.writeFileSync(process.argv[3],JSON.stringify(p.config));fs.writeFileSync(process.argv[4],p.artifactBundledCode);fs.writeFileSync(process.argv[5],p.artifactSourceMap);fs.writeFileSync(process.argv[6],p.crashPusherCode);";
|
|
57
59
|
return [
|
|
58
60
|
'node',
|
|
59
61
|
'-e',
|
|
@@ -62,6 +64,7 @@ function nodeMaterializePayloadCommand(input: {
|
|
|
62
64
|
shellQuote(input.runnerPath),
|
|
63
65
|
shellQuote(input.configPath),
|
|
64
66
|
shellQuote(input.artifactCodePath),
|
|
67
|
+
shellQuote(input.artifactSourceMapPath),
|
|
65
68
|
shellQuote(input.crashPusherPath),
|
|
66
69
|
].join(' ');
|
|
67
70
|
}
|
|
@@ -236,6 +239,7 @@ export async function stageDaytonaRunnerPayload(input: {
|
|
|
236
239
|
const envelopePath = `${workDir}/deepline-play-payload-${randomUUID()}.json.gz`;
|
|
237
240
|
const configPath = `${workDir}/deepline-play-config-${randomUUID()}.json`;
|
|
238
241
|
const artifactCodePath = `${workDir}/deepline-play-artifact-${randomUUID()}.cjs`;
|
|
242
|
+
const artifactSourceMapPath = `${artifactCodePath}.map`;
|
|
239
243
|
const crashPusherPath = `${workDir}/deepline-play-crash-terminal-${randomUUID()}.cjs`;
|
|
240
244
|
|
|
241
245
|
const remoteMaterializedFiles: Record<string, string> = {};
|
|
@@ -306,6 +310,7 @@ export async function stageDaytonaRunnerPayload(input: {
|
|
|
306
310
|
artifactTransport: {
|
|
307
311
|
bundledCodePath: artifactCodePath,
|
|
308
312
|
bundledCodeEncoding: 'utf8',
|
|
313
|
+
sourceMapPath: artifactSourceMapPath,
|
|
309
314
|
},
|
|
310
315
|
workspaceRoot: input.workDir,
|
|
311
316
|
csvSourcePath: hasInlineCsv
|
|
@@ -330,6 +335,7 @@ export async function stageDaytonaRunnerPayload(input: {
|
|
|
330
335
|
schemaVersion: 1,
|
|
331
336
|
runnerCode: bundle,
|
|
332
337
|
artifactBundledCode: compactedArtifact.bundledCode,
|
|
338
|
+
artifactSourceMap: input.config.artifact.sourceMap,
|
|
333
339
|
config: remoteConfig,
|
|
334
340
|
crashPusherCode: buildDaytonaCrashTerminalPusherSource(),
|
|
335
341
|
}),
|
|
@@ -355,6 +361,7 @@ export async function stageDaytonaRunnerPayload(input: {
|
|
|
355
361
|
runnerPath,
|
|
356
362
|
configPath,
|
|
357
363
|
artifactCodePath,
|
|
364
|
+
artifactSourceMapPath,
|
|
358
365
|
crashPusherPath,
|
|
359
366
|
})} && DEEPLINE_PLAY_RUNNER_READY_PATH=${shellQuote(readyPath)} DEEPLINE_PLAY_RUNNER_PROGRESS_EVENT_PATH=${shellQuote(progressEventPath)} DEEPLINE_PLAY_RUNNER_STDOUT_EVENT_MODE=compact ${runnerTraceEnv}node ${shellQuote(runnerPath)} ${shellQuote(configPath)}`;
|
|
360
367
|
// Crash-containment epilogue: runs UNCONDITIONALLY after the runner exits and
|
|
@@ -80,6 +80,7 @@ import {
|
|
|
80
80
|
import type { MapRowOutcome } from './durability-store';
|
|
81
81
|
import {
|
|
82
82
|
normalizeRuntimeMapInputIndex,
|
|
83
|
+
prepareRuntimeSheetRowsForJsonTransport,
|
|
83
84
|
prepareRuntimeSheetRowTransitions,
|
|
84
85
|
type RuntimePreparedCompletedRow,
|
|
85
86
|
type RuntimePreparedFailedRow,
|
|
@@ -614,10 +615,22 @@ async function postRuntimeApi<TResponse>(
|
|
|
614
615
|
typeof parsed?.error === 'string'
|
|
615
616
|
? parsed.error
|
|
616
617
|
: `Runtime API request failed with status ${response.status}.`;
|
|
618
|
+
const errorCode = typeof parsed?.code === 'string' ? parsed.code : null;
|
|
619
|
+
const errorAction =
|
|
620
|
+
typeof parsed?.action === 'string' ? parsed.action : body.action;
|
|
621
|
+
const requestId = response.headers.get('x-deepline-request-id');
|
|
622
|
+
const diagnosticContext = [
|
|
623
|
+
`status ${response.status}`,
|
|
624
|
+
errorCode ? `code=${errorCode}` : null,
|
|
625
|
+
errorAction ? `action=${errorAction}` : null,
|
|
626
|
+
requestId ? `request_id=${requestId}` : null,
|
|
627
|
+
]
|
|
628
|
+
.filter((value): value is string => Boolean(value))
|
|
629
|
+
.join(', ');
|
|
617
630
|
throw new Error(
|
|
618
631
|
details
|
|
619
|
-
? `${errorMessage} (
|
|
620
|
-
: `${errorMessage} (
|
|
632
|
+
? `${errorMessage} (${diagnosticContext}): ${details}`
|
|
633
|
+
: `${errorMessage} (${diagnosticContext}).`,
|
|
621
634
|
);
|
|
622
635
|
}
|
|
623
636
|
|
|
@@ -6151,12 +6164,8 @@ async function completeRuntimeMapRowChunks(
|
|
|
6151
6164
|
for (const chunk of input.chunks) {
|
|
6152
6165
|
const chunkKeys = chunk.map((row) => row.key);
|
|
6153
6166
|
const chunkInputIndexes = chunk.map((row) => row.input_index);
|
|
6154
|
-
const chunkDataPatches = chunk.map((row) =>
|
|
6155
|
-
|
|
6156
|
-
);
|
|
6157
|
-
const chunkCellMetaPatches = chunk.map((row) =>
|
|
6158
|
-
stringifyPostgresJson(row.cell_meta_patch),
|
|
6159
|
-
);
|
|
6167
|
+
const chunkDataPatches = chunk.map((row) => row.data_patch_json);
|
|
6168
|
+
const chunkCellMetaPatches = chunk.map((row) => row.cell_meta_patch_json);
|
|
6160
6169
|
const targetChangedPatchedCellSql = changedPatchedCellSql(
|
|
6161
6170
|
'target',
|
|
6162
6171
|
'updates.data_patch',
|
|
@@ -6418,12 +6427,8 @@ async function completeRuntimeMapRowChunksWithInputIndexRepair(
|
|
|
6418
6427
|
for (const chunk of input.chunks) {
|
|
6419
6428
|
const chunkKeys = chunk.map((row) => row.key);
|
|
6420
6429
|
const chunkInputIndexes = chunk.map((row) => row.input_index);
|
|
6421
|
-
const chunkDataPatches = chunk.map((row) =>
|
|
6422
|
-
|
|
6423
|
-
);
|
|
6424
|
-
const chunkCellMetaPatches = chunk.map((row) =>
|
|
6425
|
-
stringifyPostgresJson(row.cell_meta_patch),
|
|
6426
|
-
);
|
|
6430
|
+
const chunkDataPatches = chunk.map((row) => row.data_patch_json);
|
|
6431
|
+
const chunkCellMetaPatches = chunk.map((row) => row.cell_meta_patch_json);
|
|
6427
6432
|
const targetChangedPatchedCellSql = changedPatchedCellSql(
|
|
6428
6433
|
'target',
|
|
6429
6434
|
'updates.data_patch',
|
|
@@ -6661,12 +6666,8 @@ async function insertMissingCompletedMapRowChunks(
|
|
|
6661
6666
|
for (const chunk of input.chunks) {
|
|
6662
6667
|
const chunkKeys = chunk.map((row) => row.key);
|
|
6663
6668
|
const chunkInputIndexes = chunk.map((row) => row.input_index);
|
|
6664
|
-
const chunkDataPatches = chunk.map((row) =>
|
|
6665
|
-
|
|
6666
|
-
);
|
|
6667
|
-
const chunkCellMetaPatches = chunk.map((row) =>
|
|
6668
|
-
stringifyPostgresJson(row.cell_meta_patch),
|
|
6669
|
-
);
|
|
6669
|
+
const chunkDataPatches = chunk.map((row) => row.data_patch_json);
|
|
6670
|
+
const chunkCellMetaPatches = chunk.map((row) => row.cell_meta_patch_json);
|
|
6670
6671
|
const { rows } = await client.query<{ inserted: number }>(
|
|
6671
6672
|
`WITH input_rows AS (
|
|
6672
6673
|
SELECT key_values._key,
|
|
@@ -6833,12 +6834,8 @@ async function failRuntimeMapRowChunks(
|
|
|
6833
6834
|
for (const chunk of input.chunks) {
|
|
6834
6835
|
const chunkKeys = chunk.map((row) => row.key);
|
|
6835
6836
|
const chunkInputIndexes = chunk.map((row) => row.input_index);
|
|
6836
|
-
const chunkDataPatches = chunk.map((row) =>
|
|
6837
|
-
|
|
6838
|
-
);
|
|
6839
|
-
const chunkCellMetaPatches = chunk.map((row) =>
|
|
6840
|
-
stringifyPostgresJson(row.cell_meta_patch),
|
|
6841
|
-
);
|
|
6837
|
+
const chunkDataPatches = chunk.map((row) => row.data_patch_json);
|
|
6838
|
+
const chunkCellMetaPatches = chunk.map((row) => row.cell_meta_patch_json);
|
|
6842
6839
|
const chunkErrors = chunk.map((row) => row.error);
|
|
6843
6840
|
// Per-field failed-cell counts for the column summary, computed from the
|
|
6844
6841
|
// cell meta patches (a failed row records exactly which cell failed).
|
|
@@ -7064,9 +7061,21 @@ export async function completeRuntimeMapRows(
|
|
|
7064
7061
|
},
|
|
7065
7062
|
): Promise<RuntimeMapRowsWriteResult> {
|
|
7066
7063
|
if (context.dbSessionStrategy === 'gateway_only') {
|
|
7064
|
+
const keyedRows = input.rows.map((row) => {
|
|
7065
|
+
if (row.key) return row;
|
|
7066
|
+
const key = resolveMapRowOutcomeKey(
|
|
7067
|
+
row as unknown as Record<string, unknown>,
|
|
7068
|
+
);
|
|
7069
|
+
return key ? { ...row, key } : row;
|
|
7070
|
+
});
|
|
7071
|
+
const rows = prepareRuntimeSheetRowsForJsonTransport({
|
|
7072
|
+
rows: keyedRows,
|
|
7073
|
+
runId: input.runId,
|
|
7074
|
+
outputFields: input.outputFields ?? [],
|
|
7075
|
+
});
|
|
7067
7076
|
return await postRuntimeApi<RuntimeMapRowsWriteResult>(context, {
|
|
7068
7077
|
action: 'runtime_sheet_complete_map_rows',
|
|
7069
|
-
input,
|
|
7078
|
+
input: { ...input, rows },
|
|
7070
7079
|
});
|
|
7071
7080
|
}
|
|
7072
7081
|
if (input.rows.length === 0) {
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import type { MapRowOutcome } from './durability-store';
|
|
2
|
+
import { stringifyPostgresJson } from './postgres-json';
|
|
3
|
+
|
|
4
|
+
export const RUNTIME_ROW_OUTPUT_NOT_JSON_SERIALIZABLE =
|
|
5
|
+
'RUNTIME_ROW_OUTPUT_NOT_JSON_SERIALIZABLE';
|
|
6
|
+
|
|
7
|
+
const RUNTIME_ROW_OUTPUT_NOT_JSON_SERIALIZABLE_MESSAGE =
|
|
8
|
+
`${RUNTIME_ROW_OUTPUT_NOT_JSON_SERIALIZABLE}: Row output is not JSON-serializable. ` +
|
|
9
|
+
'Remove BigInt values, circular references, and throwing toJSON implementations.';
|
|
2
10
|
|
|
3
11
|
export type RuntimePreparedCompletedRow = {
|
|
4
12
|
key: string;
|
|
5
13
|
input_index: number | null;
|
|
6
14
|
data_patch: Record<string, unknown>;
|
|
7
15
|
cell_meta_patch: Record<string, unknown>;
|
|
16
|
+
/** Serialized once at the row boundary so SQL batching cannot re-run toJSON. */
|
|
17
|
+
data_patch_json: string;
|
|
18
|
+
/** Serialized once at the row boundary so SQL batching cannot re-run toJSON. */
|
|
19
|
+
cell_meta_patch_json: string;
|
|
8
20
|
};
|
|
9
21
|
|
|
10
22
|
export type RuntimePreparedFailedRow = RuntimePreparedCompletedRow & {
|
|
@@ -50,6 +62,51 @@ export function completedRuntimeCellMetaPatch(input: {
|
|
|
50
62
|
return patch;
|
|
51
63
|
}
|
|
52
64
|
|
|
65
|
+
function serializeRuntimeRowPatch(value: Record<string, unknown>): string {
|
|
66
|
+
const serialized = stringifyPostgresJson(value);
|
|
67
|
+
if (serialized === undefined) {
|
|
68
|
+
throw new TypeError('JSON.stringify returned undefined.');
|
|
69
|
+
}
|
|
70
|
+
return serialized;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function unserializableRuntimeRowFailure(input: {
|
|
74
|
+
key: string;
|
|
75
|
+
inputIndex: number | null;
|
|
76
|
+
runId: string;
|
|
77
|
+
outputFields: readonly string[];
|
|
78
|
+
}): RuntimePreparedFailedRow {
|
|
79
|
+
let cellMetaPatch = Object.fromEntries(
|
|
80
|
+
input.outputFields.map((field) => [
|
|
81
|
+
field,
|
|
82
|
+
{
|
|
83
|
+
status: 'failed',
|
|
84
|
+
runId: input.runId,
|
|
85
|
+
error: RUNTIME_ROW_OUTPUT_NOT_JSON_SERIALIZABLE_MESSAGE,
|
|
86
|
+
},
|
|
87
|
+
]),
|
|
88
|
+
);
|
|
89
|
+
let cellMetaPatchJson: string;
|
|
90
|
+
try {
|
|
91
|
+
cellMetaPatchJson = serializeRuntimeRowPatch(cellMetaPatch);
|
|
92
|
+
} catch {
|
|
93
|
+
// Authored output field names can themselves collide after PostgreSQL JSON
|
|
94
|
+
// normalization. Preserve the explicit row failure instead of allowing
|
|
95
|
+
// diagnostic metadata to turn it back into a batch-fatal exception.
|
|
96
|
+
cellMetaPatch = {};
|
|
97
|
+
cellMetaPatchJson = '{}';
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
key: input.key,
|
|
101
|
+
input_index: input.inputIndex,
|
|
102
|
+
data_patch: {},
|
|
103
|
+
cell_meta_patch: cellMetaPatch,
|
|
104
|
+
data_patch_json: '{}',
|
|
105
|
+
cell_meta_patch_json: cellMetaPatchJson,
|
|
106
|
+
error: RUNTIME_ROW_OUTPUT_NOT_JSON_SERIALIZABLE_MESSAGE,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
53
110
|
export function prepareRuntimeSheetRowTransitions(input: {
|
|
54
111
|
rows: Iterable<MapRowOutcome>;
|
|
55
112
|
runId: string;
|
|
@@ -62,12 +119,40 @@ export function prepareRuntimeSheetRowTransitions(input: {
|
|
|
62
119
|
const failedRows: RuntimePreparedFailedRow[] = [];
|
|
63
120
|
for (const row of input.rows) {
|
|
64
121
|
if (!row.key) continue;
|
|
122
|
+
const inputIndex = normalizeRuntimeMapInputIndex(row.inputIndex);
|
|
123
|
+
let cellMetaPatch: Record<string, unknown>;
|
|
124
|
+
let dataPatchJson: string;
|
|
125
|
+
let cellMetaPatchJson: string;
|
|
126
|
+
try {
|
|
127
|
+
cellMetaPatch =
|
|
128
|
+
row.status === 'failed'
|
|
129
|
+
? (row.cellMetaPatch ?? {})
|
|
130
|
+
: completedRuntimeCellMetaPatch({
|
|
131
|
+
runId: input.runId,
|
|
132
|
+
outputFields: input.outputFields,
|
|
133
|
+
rowPatch: row.cellMetaPatch,
|
|
134
|
+
});
|
|
135
|
+
dataPatchJson = serializeRuntimeRowPatch(row.data);
|
|
136
|
+
cellMetaPatchJson = serializeRuntimeRowPatch(cellMetaPatch);
|
|
137
|
+
} catch {
|
|
138
|
+
failedRows.push(
|
|
139
|
+
unserializableRuntimeRowFailure({
|
|
140
|
+
key: row.key,
|
|
141
|
+
inputIndex,
|
|
142
|
+
runId: input.runId,
|
|
143
|
+
outputFields: input.outputFields,
|
|
144
|
+
}),
|
|
145
|
+
);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
65
148
|
if (row.status === 'failed') {
|
|
66
149
|
failedRows.push({
|
|
67
150
|
key: row.key,
|
|
68
|
-
input_index:
|
|
151
|
+
input_index: inputIndex,
|
|
69
152
|
data_patch: row.data,
|
|
70
|
-
cell_meta_patch:
|
|
153
|
+
cell_meta_patch: cellMetaPatch,
|
|
154
|
+
data_patch_json: dataPatchJson,
|
|
155
|
+
cell_meta_patch_json: cellMetaPatchJson,
|
|
71
156
|
error:
|
|
72
157
|
typeof row.error === 'string' && row.error.trim()
|
|
73
158
|
? row.error
|
|
@@ -77,14 +162,47 @@ export function prepareRuntimeSheetRowTransitions(input: {
|
|
|
77
162
|
}
|
|
78
163
|
completedRows.push({
|
|
79
164
|
key: row.key,
|
|
80
|
-
input_index:
|
|
165
|
+
input_index: inputIndex,
|
|
81
166
|
data_patch: row.data,
|
|
82
|
-
cell_meta_patch:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
rowPatch: row.cellMetaPatch,
|
|
86
|
-
}),
|
|
167
|
+
cell_meta_patch: cellMetaPatch,
|
|
168
|
+
data_patch_json: dataPatchJson,
|
|
169
|
+
cell_meta_patch_json: cellMetaPatchJson,
|
|
87
170
|
});
|
|
88
171
|
}
|
|
89
172
|
return { completedRows, failedRows };
|
|
90
173
|
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Apply the row serialization boundary before a gateway-only runtime request.
|
|
177
|
+
* This prevents JSON.stringify on the transport envelope from turning one
|
|
178
|
+
* malformed row into a batch-fatal error before the gateway can persist the
|
|
179
|
+
* healthy siblings.
|
|
180
|
+
*/
|
|
181
|
+
export function prepareRuntimeSheetRowsForJsonTransport(input: {
|
|
182
|
+
rows: Iterable<MapRowOutcome>;
|
|
183
|
+
runId: string;
|
|
184
|
+
outputFields: readonly string[];
|
|
185
|
+
}): MapRowOutcome[] {
|
|
186
|
+
const rows: MapRowOutcome[] = [];
|
|
187
|
+
for (const row of input.rows) {
|
|
188
|
+
const { completedRows, failedRows } = prepareRuntimeSheetRowTransitions({
|
|
189
|
+
rows: [row],
|
|
190
|
+
runId: input.runId,
|
|
191
|
+
outputFields: input.outputFields,
|
|
192
|
+
});
|
|
193
|
+
const prepared = completedRows[0] ?? failedRows[0];
|
|
194
|
+
if (!prepared) continue;
|
|
195
|
+
const failed = failedRows[0];
|
|
196
|
+
rows.push({
|
|
197
|
+
key: prepared.key,
|
|
198
|
+
inputIndex: prepared.input_index,
|
|
199
|
+
data: JSON.parse(prepared.data_patch_json) as Record<string, unknown>,
|
|
200
|
+
cellMetaPatch: JSON.parse(prepared.cell_meta_patch_json) as Record<
|
|
201
|
+
string,
|
|
202
|
+
unknown
|
|
203
|
+
>,
|
|
204
|
+
...(failed ? { status: 'failed' as const, error: failed.error } : {}),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
return rows;
|
|
208
|
+
}
|
|
@@ -13,6 +13,7 @@ export type PlayStepLifecycleEvent = {
|
|
|
13
13
|
type: string;
|
|
14
14
|
transition: 'started' | 'completed' | 'failed';
|
|
15
15
|
at: number;
|
|
16
|
+
error?: string;
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
function isAutoStartedSetupNode(type: string): boolean {
|
|
@@ -191,7 +192,7 @@ export class PlayStepLifecycleTracker {
|
|
|
191
192
|
}
|
|
192
193
|
}
|
|
193
194
|
|
|
194
|
-
markStartedFailed(at = this.now()): void {
|
|
195
|
+
markStartedFailed(at = this.now(), error?: string): void {
|
|
195
196
|
for (let index = this.nodes.length - 1; index >= 0; index -= 1) {
|
|
196
197
|
const node = this.nodes[index]!;
|
|
197
198
|
const existing = this.getProgress()[node.nodeId];
|
|
@@ -202,6 +203,7 @@ export class PlayStepLifecycleTracker {
|
|
|
202
203
|
type: node.type,
|
|
203
204
|
transition: 'failed',
|
|
204
205
|
at,
|
|
206
|
+
...(error?.trim() ? { error: error.trim() } : {}),
|
|
205
207
|
});
|
|
206
208
|
return;
|
|
207
209
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -625,10 +625,10 @@ var SDK_RELEASE = {
|
|
|
625
625
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
626
626
|
// 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
|
|
627
627
|
// automatically without blocking their current command.
|
|
628
|
-
version: "0.1.
|
|
628
|
+
version: "0.1.226",
|
|
629
629
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
630
630
|
supportPolicy: {
|
|
631
|
-
latest: "0.1.
|
|
631
|
+
latest: "0.1.226",
|
|
632
632
|
minimumSupported: "0.1.53",
|
|
633
633
|
deprecatedBelow: "0.1.219",
|
|
634
634
|
commandMinimumSupported: [
|
|
@@ -1348,6 +1348,9 @@ function resolveTimingWindow(input2) {
|
|
|
1348
1348
|
};
|
|
1349
1349
|
}
|
|
1350
1350
|
|
|
1351
|
+
// ../shared_libs/play-runtime/run-failure.ts
|
|
1352
|
+
var PUBLIC_FAILURE_TEXT_BYTE_LIMIT = 64 * 1024;
|
|
1353
|
+
|
|
1351
1354
|
// ../shared_libs/play-runtime/run-terminal-source.ts
|
|
1352
1355
|
var PLAY_RUN_LEDGER_EVENT_SOURCES = [
|
|
1353
1356
|
"worker",
|
|
@@ -1576,6 +1579,7 @@ function normalizePlayRunLedgerSnapshot(value, fallback) {
|
|
|
1576
1579
|
label: optionalString(rawStep.label),
|
|
1577
1580
|
kind: optionalString(rawStep.kind),
|
|
1578
1581
|
status,
|
|
1582
|
+
error: optionalNullableString(rawStep.error),
|
|
1579
1583
|
artifactTableNamespace: optionalNullableString(
|
|
1580
1584
|
rawStep.artifactTableNamespace
|
|
1581
1585
|
),
|
|
@@ -1752,6 +1756,7 @@ function buildSnapshotFromLedger(snapshot) {
|
|
|
1752
1756
|
const nodeStates = snapshot.orderedStepIds.map((stepId) => snapshot.stepsById[stepId]).filter((step) => Boolean(step)).map((step) => ({
|
|
1753
1757
|
nodeId: step.stepId,
|
|
1754
1758
|
status: step.status,
|
|
1759
|
+
error: step.error ?? null,
|
|
1755
1760
|
artifactTableNamespace: step.artifactTableNamespace ?? null,
|
|
1756
1761
|
progress: step.progress ? {
|
|
1757
1762
|
completed: step.progress.completed,
|
|
@@ -13758,6 +13763,13 @@ function formatPackageValueOutputLines(packaged) {
|
|
|
13758
13763
|
}
|
|
13759
13764
|
return lines;
|
|
13760
13765
|
}
|
|
13766
|
+
function authoredPackageStackFrames(packaged) {
|
|
13767
|
+
const stack = readRecordArray(packaged.errors).map((entry) => typeof entry.stack === "string" ? entry.stack : null).find((candidate) => Boolean(candidate?.trim()));
|
|
13768
|
+
if (!stack) return [];
|
|
13769
|
+
return stack.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("at ")).filter(
|
|
13770
|
+
(line) => !line.includes("/virtual/deepline-plays/") && !line.includes("/apps/play-runner/") && !line.includes("/shared_libs/play-runtime/") && !line.includes("node:internal")
|
|
13771
|
+
).slice(0, 5);
|
|
13772
|
+
}
|
|
13761
13773
|
function buildRunPackageTextLines(packaged) {
|
|
13762
13774
|
const run = readRunPackageRun(packaged);
|
|
13763
13775
|
const runId = typeof run.id === "string" ? run.id : "unknown";
|
|
@@ -13769,6 +13781,11 @@ function buildRunPackageTextLines(packaged) {
|
|
|
13769
13781
|
const runError = typeof run.error === "string" && run.error.trim() ? run.error.trim() : null;
|
|
13770
13782
|
if (runError && (status === "failed" || status === "cancelled")) {
|
|
13771
13783
|
lines.push(` error: ${truncateErrorForDisplay(runError, runId)}`);
|
|
13784
|
+
const stackFrames = authoredPackageStackFrames(packaged);
|
|
13785
|
+
if (stackFrames.length > 0) {
|
|
13786
|
+
lines.push(" stack:");
|
|
13787
|
+
lines.push(...stackFrames.map((frame) => ` ${frame}`));
|
|
13788
|
+
}
|
|
13772
13789
|
}
|
|
13773
13790
|
const failedLogs = readRecord(packaged.failedLogs);
|
|
13774
13791
|
const failedLogEntries = Array.isArray(failedLogs?.entries) ? failedLogs.entries.filter(
|
|
@@ -17820,12 +17837,12 @@ function normalizeAlias(value) {
|
|
|
17820
17837
|
function renderExecuteStep(command, options = {
|
|
17821
17838
|
force: false
|
|
17822
17839
|
}) {
|
|
17823
|
-
if (command.play) {
|
|
17824
|
-
return renderPlayStep(command, options);
|
|
17825
|
-
}
|
|
17826
17840
|
if (command.tool === "run_javascript" && options.inlineRunJavascript && canInlineRunJavascript(command)) {
|
|
17827
17841
|
return renderInlineJavascriptStep(command, options);
|
|
17828
17842
|
}
|
|
17843
|
+
if (command.play) {
|
|
17844
|
+
return renderPlayStep(command, options);
|
|
17845
|
+
}
|
|
17829
17846
|
if (options.idiomaticGetters) {
|
|
17830
17847
|
return renderIdiomaticExecuteStep(command, options);
|
|
17831
17848
|
}
|
package/dist/cli/index.mjs
CHANGED
|
@@ -610,10 +610,10 @@ var SDK_RELEASE = {
|
|
|
610
610
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
611
611
|
// 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
|
|
612
612
|
// automatically without blocking their current command.
|
|
613
|
-
version: "0.1.
|
|
613
|
+
version: "0.1.226",
|
|
614
614
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
615
615
|
supportPolicy: {
|
|
616
|
-
latest: "0.1.
|
|
616
|
+
latest: "0.1.226",
|
|
617
617
|
minimumSupported: "0.1.53",
|
|
618
618
|
deprecatedBelow: "0.1.219",
|
|
619
619
|
commandMinimumSupported: [
|
|
@@ -1333,6 +1333,9 @@ function resolveTimingWindow(input2) {
|
|
|
1333
1333
|
};
|
|
1334
1334
|
}
|
|
1335
1335
|
|
|
1336
|
+
// ../shared_libs/play-runtime/run-failure.ts
|
|
1337
|
+
var PUBLIC_FAILURE_TEXT_BYTE_LIMIT = 64 * 1024;
|
|
1338
|
+
|
|
1336
1339
|
// ../shared_libs/play-runtime/run-terminal-source.ts
|
|
1337
1340
|
var PLAY_RUN_LEDGER_EVENT_SOURCES = [
|
|
1338
1341
|
"worker",
|
|
@@ -1561,6 +1564,7 @@ function normalizePlayRunLedgerSnapshot(value, fallback) {
|
|
|
1561
1564
|
label: optionalString(rawStep.label),
|
|
1562
1565
|
kind: optionalString(rawStep.kind),
|
|
1563
1566
|
status,
|
|
1567
|
+
error: optionalNullableString(rawStep.error),
|
|
1564
1568
|
artifactTableNamespace: optionalNullableString(
|
|
1565
1569
|
rawStep.artifactTableNamespace
|
|
1566
1570
|
),
|
|
@@ -1737,6 +1741,7 @@ function buildSnapshotFromLedger(snapshot) {
|
|
|
1737
1741
|
const nodeStates = snapshot.orderedStepIds.map((stepId) => snapshot.stepsById[stepId]).filter((step) => Boolean(step)).map((step) => ({
|
|
1738
1742
|
nodeId: step.stepId,
|
|
1739
1743
|
status: step.status,
|
|
1744
|
+
error: step.error ?? null,
|
|
1740
1745
|
artifactTableNamespace: step.artifactTableNamespace ?? null,
|
|
1741
1746
|
progress: step.progress ? {
|
|
1742
1747
|
completed: step.progress.completed,
|
|
@@ -13787,6 +13792,13 @@ function formatPackageValueOutputLines(packaged) {
|
|
|
13787
13792
|
}
|
|
13788
13793
|
return lines;
|
|
13789
13794
|
}
|
|
13795
|
+
function authoredPackageStackFrames(packaged) {
|
|
13796
|
+
const stack = readRecordArray(packaged.errors).map((entry) => typeof entry.stack === "string" ? entry.stack : null).find((candidate) => Boolean(candidate?.trim()));
|
|
13797
|
+
if (!stack) return [];
|
|
13798
|
+
return stack.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("at ")).filter(
|
|
13799
|
+
(line) => !line.includes("/virtual/deepline-plays/") && !line.includes("/apps/play-runner/") && !line.includes("/shared_libs/play-runtime/") && !line.includes("node:internal")
|
|
13800
|
+
).slice(0, 5);
|
|
13801
|
+
}
|
|
13790
13802
|
function buildRunPackageTextLines(packaged) {
|
|
13791
13803
|
const run = readRunPackageRun(packaged);
|
|
13792
13804
|
const runId = typeof run.id === "string" ? run.id : "unknown";
|
|
@@ -13798,6 +13810,11 @@ function buildRunPackageTextLines(packaged) {
|
|
|
13798
13810
|
const runError = typeof run.error === "string" && run.error.trim() ? run.error.trim() : null;
|
|
13799
13811
|
if (runError && (status === "failed" || status === "cancelled")) {
|
|
13800
13812
|
lines.push(` error: ${truncateErrorForDisplay(runError, runId)}`);
|
|
13813
|
+
const stackFrames = authoredPackageStackFrames(packaged);
|
|
13814
|
+
if (stackFrames.length > 0) {
|
|
13815
|
+
lines.push(" stack:");
|
|
13816
|
+
lines.push(...stackFrames.map((frame) => ` ${frame}`));
|
|
13817
|
+
}
|
|
13801
13818
|
}
|
|
13802
13819
|
const failedLogs = readRecord(packaged.failedLogs);
|
|
13803
13820
|
const failedLogEntries = Array.isArray(failedLogs?.entries) ? failedLogs.entries.filter(
|
|
@@ -17849,12 +17866,12 @@ function normalizeAlias(value) {
|
|
|
17849
17866
|
function renderExecuteStep(command, options = {
|
|
17850
17867
|
force: false
|
|
17851
17868
|
}) {
|
|
17852
|
-
if (command.play) {
|
|
17853
|
-
return renderPlayStep(command, options);
|
|
17854
|
-
}
|
|
17855
17869
|
if (command.tool === "run_javascript" && options.inlineRunJavascript && canInlineRunJavascript(command)) {
|
|
17856
17870
|
return renderInlineJavascriptStep(command, options);
|
|
17857
17871
|
}
|
|
17872
|
+
if (command.play) {
|
|
17873
|
+
return renderPlayStep(command, options);
|
|
17874
|
+
}
|
|
17858
17875
|
if (options.idiomaticGetters) {
|
|
17859
17876
|
return renderIdiomaticExecuteStep(command, options);
|
|
17860
17877
|
}
|
package/dist/index.js
CHANGED
|
@@ -424,10 +424,10 @@ var SDK_RELEASE = {
|
|
|
424
424
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
425
425
|
// 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
|
|
426
426
|
// automatically without blocking their current command.
|
|
427
|
-
version: "0.1.
|
|
427
|
+
version: "0.1.226",
|
|
428
428
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
429
429
|
supportPolicy: {
|
|
430
|
-
latest: "0.1.
|
|
430
|
+
latest: "0.1.226",
|
|
431
431
|
minimumSupported: "0.1.53",
|
|
432
432
|
deprecatedBelow: "0.1.219",
|
|
433
433
|
commandMinimumSupported: [
|
|
@@ -1147,6 +1147,9 @@ function resolveTimingWindow(input) {
|
|
|
1147
1147
|
};
|
|
1148
1148
|
}
|
|
1149
1149
|
|
|
1150
|
+
// ../shared_libs/play-runtime/run-failure.ts
|
|
1151
|
+
var PUBLIC_FAILURE_TEXT_BYTE_LIMIT = 64 * 1024;
|
|
1152
|
+
|
|
1150
1153
|
// ../shared_libs/play-runtime/run-terminal-source.ts
|
|
1151
1154
|
var PLAY_RUN_LEDGER_EVENT_SOURCES = [
|
|
1152
1155
|
"worker",
|
|
@@ -1375,6 +1378,7 @@ function normalizePlayRunLedgerSnapshot(value, fallback) {
|
|
|
1375
1378
|
label: optionalString(rawStep.label),
|
|
1376
1379
|
kind: optionalString(rawStep.kind),
|
|
1377
1380
|
status,
|
|
1381
|
+
error: optionalNullableString(rawStep.error),
|
|
1378
1382
|
artifactTableNamespace: optionalNullableString(
|
|
1379
1383
|
rawStep.artifactTableNamespace
|
|
1380
1384
|
),
|
|
@@ -1551,6 +1555,7 @@ function buildSnapshotFromLedger(snapshot) {
|
|
|
1551
1555
|
const nodeStates = snapshot.orderedStepIds.map((stepId) => snapshot.stepsById[stepId]).filter((step) => Boolean(step)).map((step) => ({
|
|
1552
1556
|
nodeId: step.stepId,
|
|
1553
1557
|
status: step.status,
|
|
1558
|
+
error: step.error ?? null,
|
|
1554
1559
|
artifactTableNamespace: step.artifactTableNamespace ?? null,
|
|
1555
1560
|
progress: step.progress ? {
|
|
1556
1561
|
completed: step.progress.completed,
|
package/dist/index.mjs
CHANGED
|
@@ -354,10 +354,10 @@ var SDK_RELEASE = {
|
|
|
354
354
|
// 0.1.175 ships loud `deepline enrich` empty-waterfall reporting.
|
|
355
355
|
// 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
|
|
356
356
|
// automatically without blocking their current command.
|
|
357
|
-
version: "0.1.
|
|
357
|
+
version: "0.1.226",
|
|
358
358
|
apiContract: "2026-06-dataset-handle-results-hard-cutover",
|
|
359
359
|
supportPolicy: {
|
|
360
|
-
latest: "0.1.
|
|
360
|
+
latest: "0.1.226",
|
|
361
361
|
minimumSupported: "0.1.53",
|
|
362
362
|
deprecatedBelow: "0.1.219",
|
|
363
363
|
commandMinimumSupported: [
|
|
@@ -1077,6 +1077,9 @@ function resolveTimingWindow(input) {
|
|
|
1077
1077
|
};
|
|
1078
1078
|
}
|
|
1079
1079
|
|
|
1080
|
+
// ../shared_libs/play-runtime/run-failure.ts
|
|
1081
|
+
var PUBLIC_FAILURE_TEXT_BYTE_LIMIT = 64 * 1024;
|
|
1082
|
+
|
|
1080
1083
|
// ../shared_libs/play-runtime/run-terminal-source.ts
|
|
1081
1084
|
var PLAY_RUN_LEDGER_EVENT_SOURCES = [
|
|
1082
1085
|
"worker",
|
|
@@ -1305,6 +1308,7 @@ function normalizePlayRunLedgerSnapshot(value, fallback) {
|
|
|
1305
1308
|
label: optionalString(rawStep.label),
|
|
1306
1309
|
kind: optionalString(rawStep.kind),
|
|
1307
1310
|
status,
|
|
1311
|
+
error: optionalNullableString(rawStep.error),
|
|
1308
1312
|
artifactTableNamespace: optionalNullableString(
|
|
1309
1313
|
rawStep.artifactTableNamespace
|
|
1310
1314
|
),
|
|
@@ -1481,6 +1485,7 @@ function buildSnapshotFromLedger(snapshot) {
|
|
|
1481
1485
|
const nodeStates = snapshot.orderedStepIds.map((stepId) => snapshot.stepsById[stepId]).filter((step) => Boolean(step)).map((step) => ({
|
|
1482
1486
|
nodeId: step.stepId,
|
|
1483
1487
|
status: step.status,
|
|
1488
|
+
error: step.error ?? null,
|
|
1484
1489
|
artifactTableNamespace: step.artifactTableNamespace ?? null,
|
|
1485
1490
|
progress: step.progress ? {
|
|
1486
1491
|
completed: step.progress.completed,
|