deepline 0.3.247 → 0.3.248
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 +177 -13
- package/dist/bundling-sources/sdk/src/index.ts +8 -0
- package/dist/bundling-sources/sdk/src/plays/input-example.ts +40 -0
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/runs/overview.ts +457 -0
- package/dist/bundling-sources/sdk/src/runs/receipts.ts +23 -0
- package/dist/bundling-sources/sdk/src/tool-calls.ts +21 -1
- package/dist/bundling-sources/sdk/src/types.ts +16 -1
- package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +19 -1
- package/dist/bundling-sources/shared_libs/play-data-plane/column-names.ts +17 -3
- package/dist/bundling-sources/shared_libs/play-data-plane/sheet-contract.ts +40 -8
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +26 -1
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +142 -14
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +2 -1
- package/dist/bundling-sources/shared_libs/play-runtime/daytona-runtime-config.ts +6 -3
- package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-janitor.ts +26 -21
- package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-reaper.ts +23 -21
- package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +17 -0
- package/dist/bundling-sources/shared_libs/play-runtime/log-context.ts +105 -0
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +8 -1
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +9 -0
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger-event-transport.ts +40 -4
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +50 -5
- package/dist/bundling-sources/shared_libs/play-runtime/run-lifecycle-policy.ts +3 -1
- package/dist/bundling-sources/shared_libs/play-runtime/run-log-buffer.ts +28 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +14 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-terminal-push.ts +56 -16
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-control-transport.ts +184 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-launch-transport.ts +327 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +87 -30
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +24 -13
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-start-admission.ts +23 -6
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +76 -33
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +90 -35
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +16 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +62 -21
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +368 -66
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +22 -4
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +105 -121
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-event-search.ts +1347 -0
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-queue-health.ts +16 -19
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-value-storage.ts +14 -6
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +16 -0
- package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +40 -0
- package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +5 -2
- package/dist/bundling-sources/shared_libs/plays/dataset-summary.ts +11 -7
- package/dist/bundling-sources/shared_libs/plays/static-pipeline-storage-codec.ts +5 -2
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +11 -2
- package/dist/cli/index.js +3504 -2368
- package/dist/cli/index.mjs +3188 -2052
- package/dist/{compiler-manifest-n8ZtPv2h.d.mts → compiler-manifest-DavmLa8y.d.mts} +1 -0
- package/dist/{compiler-manifest-n8ZtPv2h.d.ts → compiler-manifest-DavmLa8y.d.ts} +1 -0
- package/dist/index.d.mts +97 -5
- package/dist/index.d.ts +97 -5
- package/dist/index.js +135 -15
- package/dist/index.mjs +135 -15
- package/dist/install-integrity.json +9 -2
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/dist/plays/bundle-play-file.mjs +1 -1
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +1 -1
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
|
@@ -3,9 +3,11 @@ import type {
|
|
|
3
3
|
PlayDatasetColumnTypes,
|
|
4
4
|
PlaySheetContract,
|
|
5
5
|
} from './contracts';
|
|
6
|
+
import { RUNTIME_SHEET_SYSTEM_COLUMNS } from './runtime-sheet-orm';
|
|
6
7
|
import {
|
|
7
8
|
legacyPostgresTruncatedPlayColumnName,
|
|
8
9
|
sqlSafePlayColumnName,
|
|
10
|
+
sqlSafePlayStepColumnName,
|
|
9
11
|
} from './column-names';
|
|
10
12
|
|
|
11
13
|
export type PhysicalSheetColumnProjection = {
|
|
@@ -20,6 +22,7 @@ export type LegacyPhysicalSheetColumnBackfill = {
|
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
const RUNTIME_SHEET_SYSTEM_FIELDS = new Set([
|
|
25
|
+
...RUNTIME_SHEET_SYSTEM_COLUMNS,
|
|
23
26
|
'_key',
|
|
24
27
|
'_status',
|
|
25
28
|
'_run_id',
|
|
@@ -51,8 +54,18 @@ export function physicalSheetColumnProjections(
|
|
|
51
54
|
const fieldName =
|
|
52
55
|
column.source === 'input' || column.source === 'datasetColumn'
|
|
53
56
|
? column.field?.trim() || column.id.trim() || sqlName
|
|
54
|
-
:
|
|
55
|
-
|
|
57
|
+
: column.source === 'waterfallStep' &&
|
|
58
|
+
column.stepId &&
|
|
59
|
+
sqlName ===
|
|
60
|
+
sqlSafePlayStepColumnName(
|
|
61
|
+
column.field ?? column.waterfallId ?? column.id,
|
|
62
|
+
column.stepId,
|
|
63
|
+
)
|
|
64
|
+
? // The runtime's logical patch/checkpoint keys are intentionally stable.
|
|
65
|
+
// Only newly compiled physical storage names use the debug prefix.
|
|
66
|
+
sqlSafePlayColumnName(column.id)
|
|
67
|
+
: sqlName;
|
|
68
|
+
if (!isDatasetPayloadField(sqlName) || seen.has(sqlName)) {
|
|
56
69
|
continue;
|
|
57
70
|
}
|
|
58
71
|
seen.add(sqlName);
|
|
@@ -65,7 +78,7 @@ export function physicalSheetColumnProjections(
|
|
|
65
78
|
// A prior run may have introduced fields absent from the current artifact.
|
|
66
79
|
// Keep their live storage projection so reads and writes do not hide them.
|
|
67
80
|
for (const sqlName of physicalColumns ?? []) {
|
|
68
|
-
if (!sqlName
|
|
81
|
+
if (!isDatasetPayloadField(sqlName) || seen.has(sqlName)) continue;
|
|
69
82
|
seen.add(sqlName);
|
|
70
83
|
columns.push({ sqlName, fieldName: sqlName });
|
|
71
84
|
}
|
|
@@ -90,7 +103,7 @@ export function legacyPhysicalSheetColumnBackfills(
|
|
|
90
103
|
const backfills: LegacyPhysicalSheetColumnBackfill[] = [];
|
|
91
104
|
for (const column of sheetContract.columns) {
|
|
92
105
|
const sqlName = column.sqlName.trim();
|
|
93
|
-
if (!sqlName
|
|
106
|
+
if (!isDatasetPayloadField(sqlName)) {
|
|
94
107
|
continue;
|
|
95
108
|
}
|
|
96
109
|
const candidates = [
|
|
@@ -99,6 +112,8 @@ export function legacyPhysicalSheetColumnBackfills(
|
|
|
99
112
|
];
|
|
100
113
|
for (const candidate of candidates) {
|
|
101
114
|
if (!candidate) continue;
|
|
115
|
+
// Prefix-preserving columns must not borrow an unrelated non-debug field.
|
|
116
|
+
if (candidate.startsWith('_') && sqlName.startsWith('_')) continue;
|
|
102
117
|
const legacySqlName = legacyPostgresTruncatedPlayColumnName(candidate);
|
|
103
118
|
const key = legacySqlName ? `${sqlName}:${legacySqlName}` : '';
|
|
104
119
|
if (!legacySqlName || legacySqlName === sqlName || seen.has(key)) {
|
|
@@ -148,8 +163,7 @@ export function outputPhysicalSheetColumnProjections(
|
|
|
148
163
|
if (
|
|
149
164
|
column.source === 'input' ||
|
|
150
165
|
typeof column.field !== 'string' ||
|
|
151
|
-
!sqlName ||
|
|
152
|
-
sqlName.startsWith('_') ||
|
|
166
|
+
!isDatasetPayloadField(sqlName) ||
|
|
153
167
|
seen.has(sqlName)
|
|
154
168
|
) {
|
|
155
169
|
continue;
|
|
@@ -194,6 +208,14 @@ export function augmentSheetContractWithDatasetFields(input: {
|
|
|
194
208
|
}
|
|
195
209
|
|
|
196
210
|
const existingDatasetPayloadFields = new Set<string>();
|
|
211
|
+
const existingPatchFields = new Set(
|
|
212
|
+
physicalSheetColumnProjections({
|
|
213
|
+
...input.contract,
|
|
214
|
+
columns: input.contract.columns.filter(
|
|
215
|
+
(column) => column.source === 'waterfallStep',
|
|
216
|
+
),
|
|
217
|
+
}).map((column) => column.fieldName),
|
|
218
|
+
);
|
|
197
219
|
const existingSqlNames = new Set<string>();
|
|
198
220
|
const inputColumns: PlaySheetContract['columns'] = [];
|
|
199
221
|
const outputColumns: PlaySheetContract['columns'] = [];
|
|
@@ -239,8 +261,18 @@ export function augmentSheetContractWithDatasetFields(input: {
|
|
|
239
261
|
}
|
|
240
262
|
|
|
241
263
|
for (const field of candidateFields) {
|
|
242
|
-
if (
|
|
243
|
-
|
|
264
|
+
if (
|
|
265
|
+
existingDatasetPayloadFields.has(field) ||
|
|
266
|
+
existingPatchFields.has(field)
|
|
267
|
+
)
|
|
268
|
+
continue;
|
|
269
|
+
// A stored contract is authoritative, including legacy underscore aliases.
|
|
270
|
+
const existingColumn = input.contract.columns.find(
|
|
271
|
+
(column) =>
|
|
272
|
+
(column.source === 'input' || column.source === 'datasetColumn') &&
|
|
273
|
+
(column.field ?? column.id) === field,
|
|
274
|
+
);
|
|
275
|
+
const sqlName = existingColumn?.sqlName ?? sqlSafePlayColumnName(field);
|
|
244
276
|
if (existingSqlNames.has(sqlName)) continue;
|
|
245
277
|
appendColumn(outputFields.has(field) ? outputColumns : inputColumns, {
|
|
246
278
|
id: `runtime:${input.contract.tableNamespace}:${field}`,
|
|
@@ -9,6 +9,7 @@ import type { AsyncPlayRunRef } from '../plays/authoring-contract';
|
|
|
9
9
|
import type { PlayRowUpdate } from './/ctx-types';
|
|
10
10
|
import type { PlayRunTimelineEntry } from './/live-events';
|
|
11
11
|
import type { PlayDatasetBornFrom } from './/cell-provenance';
|
|
12
|
+
import type { PlayLogContext } from './/log-context';
|
|
12
13
|
import {
|
|
13
14
|
routePlayActivityObservation,
|
|
14
15
|
type PlayActivityObservation,
|
|
@@ -104,6 +105,8 @@ export type RuntimeStatusUpdate = {
|
|
|
104
105
|
activeBoundaryId?: string | null;
|
|
105
106
|
lastCheckpointAt?: number | null;
|
|
106
107
|
liveLogs?: string[];
|
|
108
|
+
/** Search-only context aligned to `liveLogs`; stripped before Convex. */
|
|
109
|
+
liveLogContexts?: Array<PlayLogContext | null>;
|
|
107
110
|
/**
|
|
108
111
|
* Monotonic count of log lines the producer ever emitted on this run's
|
|
109
112
|
* channel. `liveLogs` is a rotating tail of those lines; the total lets the
|
|
@@ -148,6 +151,7 @@ export type RuntimeStatusUpdate = {
|
|
|
148
151
|
*/
|
|
149
152
|
terminalLogReplay?: {
|
|
150
153
|
lines: string[];
|
|
154
|
+
lineContexts?: Array<PlayLogContext | null>;
|
|
151
155
|
totalCount?: number;
|
|
152
156
|
dedupeMode?: 'semantic' | 'exact';
|
|
153
157
|
producerAttempt?: number;
|
|
@@ -254,6 +258,7 @@ type RuntimeApiRequest =
|
|
|
254
258
|
runtimeBackend?: string | null;
|
|
255
259
|
schedulerBackend?: string | null;
|
|
256
260
|
schedulerSchema?: string | null;
|
|
261
|
+
runLogStore?: 'planet_scale';
|
|
257
262
|
executionProfile?: string | null;
|
|
258
263
|
runtimeReleaseId?: string | null;
|
|
259
264
|
runtimeDeployVersion?: string | null;
|
|
@@ -2190,6 +2195,7 @@ async function updateRunStatusViaAppRuntimeUnlocked(
|
|
|
2190
2195
|
const logSlice = Array.isArray(update.liveLogs)
|
|
2191
2196
|
? slicePositionalLogLines({
|
|
2192
2197
|
bufferLines: update.liveLogs,
|
|
2198
|
+
bufferContexts: update.liveLogContexts,
|
|
2193
2199
|
bufferTotalCount: update.liveLogTotalCount ?? update.liveLogs.length,
|
|
2194
2200
|
sentCount,
|
|
2195
2201
|
})
|
|
@@ -2200,11 +2206,28 @@ async function updateRunStatusViaAppRuntimeUnlocked(
|
|
|
2200
2206
|
: isTerminalRuntimeStatus(update.status) && Array.isArray(update.liveLogs)
|
|
2201
2207
|
? {
|
|
2202
2208
|
lines: update.liveLogs,
|
|
2209
|
+
lineContexts: update.liveLogContexts,
|
|
2203
2210
|
totalCount: update.liveLogTotalCount,
|
|
2204
2211
|
producerAttempt: update.liveLogProducerAttempt,
|
|
2205
2212
|
}
|
|
2206
2213
|
: null;
|
|
2207
|
-
|
|
2214
|
+
let statusPatchLogSlice = terminalLogReplay ? null : logSlice;
|
|
2215
|
+
// A direct worker's terminal replay can contain only its summary suffix.
|
|
2216
|
+
// Do not discard live lines that were observed but have not yet been sent.
|
|
2217
|
+
// Preserve the non-overlapping prefix; recovery still owns the replay range.
|
|
2218
|
+
if (
|
|
2219
|
+
terminalLogReplay &&
|
|
2220
|
+
logSlice &&
|
|
2221
|
+
terminalLogReplay.totalCount !== undefined
|
|
2222
|
+
) {
|
|
2223
|
+
const replayOffset =
|
|
2224
|
+
terminalLogReplay.totalCount - terminalLogReplay.lines.length;
|
|
2225
|
+
const prefix = logSlice.lines.slice(
|
|
2226
|
+
0,
|
|
2227
|
+
Math.max(0, replayOffset - logSlice.channelOffset),
|
|
2228
|
+
);
|
|
2229
|
+
if (prefix.length) statusPatchLogSlice = { ...logSlice, lines: prefix };
|
|
2230
|
+
}
|
|
2208
2231
|
const events = buildPlayRunLedgerEventsFromStatusPatch({
|
|
2209
2232
|
patch: {
|
|
2210
2233
|
runId: update.playId,
|
|
@@ -2213,6 +2236,7 @@ async function updateRunStatusViaAppRuntimeUnlocked(
|
|
|
2213
2236
|
runtimeBackend: update.runtimeBackend ?? null,
|
|
2214
2237
|
lastCheckpointAt: update.lastCheckpointAt ?? null,
|
|
2215
2238
|
liveLogs: statusPatchLogSlice?.lines ?? null,
|
|
2239
|
+
liveLogContexts: statusPatchLogSlice?.lineContexts ?? null,
|
|
2216
2240
|
liveLogsChannelOffset: statusPatchLogSlice?.channelOffset ?? null,
|
|
2217
2241
|
liveLogsProducerAttempt: update.liveLogProducerAttempt ?? null,
|
|
2218
2242
|
liveNodeProgress: update.liveNodeProgress ?? null,
|
|
@@ -2297,6 +2321,7 @@ async function updateRunStatusViaAppRuntimeUnlocked(
|
|
|
2297
2321
|
source: 'worker',
|
|
2298
2322
|
occurredAt: update.lastCheckpointAt ?? Date.now(),
|
|
2299
2323
|
lines: terminalLogReplay.lines,
|
|
2324
|
+
lineContexts: terminalLogReplay.lineContexts,
|
|
2300
2325
|
liveLogTotalCount: terminalLogReplay.totalCount,
|
|
2301
2326
|
dedupeMode: terminalLogReplay.dedupeMode,
|
|
2302
2327
|
producerAttempt: terminalLogReplay.producerAttempt,
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - onBatchComplete: called after each provider batch for scheduler checkpointing
|
|
14
14
|
*/
|
|
15
15
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
16
|
+
import { isDatasetPayloadField } from '../play-data-plane/sheet-contract';
|
|
16
17
|
import {
|
|
17
18
|
createDeferredPlayDataset,
|
|
18
19
|
deserializeLegacyPlayDataset,
|
|
@@ -447,7 +448,12 @@ import type {
|
|
|
447
448
|
PlayAsyncCallOptions,
|
|
448
449
|
} from './ctx-types';
|
|
449
450
|
import { assertKnownResolvedBoundary } from './checkpoint-boundaries';
|
|
450
|
-
import {
|
|
451
|
+
import {
|
|
452
|
+
boundRunLogLine,
|
|
453
|
+
RunLogBuffer,
|
|
454
|
+
RUNNER_LOG_CONTEXT_MAX_BYTES,
|
|
455
|
+
} from './run-log-buffer';
|
|
456
|
+
import { normalizePlayLogContext, type PlayLogContext } from './log-context';
|
|
451
457
|
import type { AsyncPlayRunRef } from '../plays/authoring-contract';
|
|
452
458
|
import { admitAsyncPlayLineage } from './async-play-invocation';
|
|
453
459
|
import {
|
|
@@ -1896,7 +1902,7 @@ const ACTIVE_MAP_CHECKPOINT_ROW_META_LEDGER_KEY = Symbol(
|
|
|
1896
1902
|
);
|
|
1897
1903
|
|
|
1898
1904
|
function shouldPersistMapCellField(fieldName: string): boolean {
|
|
1899
|
-
return
|
|
1905
|
+
return isDatasetPayloadField(fieldName);
|
|
1900
1906
|
}
|
|
1901
1907
|
|
|
1902
1908
|
function runtimeSheetPatchFieldName(fieldName: string): string {
|
|
@@ -1991,6 +1997,7 @@ type RuntimeMapRowPersistence = {
|
|
|
1991
1997
|
function createRuntimeMapRowPersistence(
|
|
1992
1998
|
persistRows: (rows: PersistableMapRow[]) => Promise<void>,
|
|
1993
1999
|
options?: {
|
|
2000
|
+
prepareTerminalRow?: (row: PersistableMapRow) => PersistableMapRow;
|
|
1994
2001
|
persistCheckpoint?: (updates: PlayRowUpdate[]) => Promise<void>;
|
|
1995
2002
|
onFailure?: (error: unknown) => void;
|
|
1996
2003
|
/**
|
|
@@ -2066,7 +2073,9 @@ function createRuntimeMapRowPersistence(
|
|
|
2066
2073
|
continue;
|
|
2067
2074
|
}
|
|
2068
2075
|
if (identity) queued.add(identity);
|
|
2069
|
-
const settlement = writer.settle(
|
|
2076
|
+
const settlement = writer.settle(
|
|
2077
|
+
options?.prepareTerminalRow?.(row) ?? row,
|
|
2078
|
+
);
|
|
2070
2079
|
admissions.push(
|
|
2071
2080
|
settlement.admitted.catch((error) => {
|
|
2072
2081
|
clearQueuedState(identity);
|
|
@@ -2672,6 +2681,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
2672
2681
|
private readonly rootRuntimeContract: PlayArtifactRuntimeContract;
|
|
2673
2682
|
private readonly executionScope: RunExecutionScope;
|
|
2674
2683
|
private readonly logBuffer = new RunLogBuffer();
|
|
2684
|
+
private logContextBudgetWarningLogged = false;
|
|
2675
2685
|
private readonly logRateLimitState = new Map<
|
|
2676
2686
|
Exclude<LogLevel, 'warn' | 'error'>,
|
|
2677
2687
|
LogRateLimitState
|
|
@@ -3438,6 +3448,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
3438
3448
|
// read. Same reasoning as `__deeplineDocflowHit` above: injected at compile
|
|
3439
3449
|
// time, so the run is the only place left to decide.
|
|
3440
3450
|
if (!this.docflowCaptureEnabled) return execute();
|
|
3451
|
+
// Inline composition changes logical identity, but its gateway token and
|
|
3452
|
+
// durable observations remain owned by the executing receipt scope.
|
|
3453
|
+
const runId = this.currentReceiptOwnerRunId;
|
|
3441
3454
|
const attempt = this.currentRunAttempt;
|
|
3442
3455
|
const inputs = buildPlayDocflowNodeInputPreviewMap(inputCaptures, {
|
|
3443
3456
|
redactor: this.secretRedactor,
|
|
@@ -3455,7 +3468,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
3455
3468
|
at: Date.now(),
|
|
3456
3469
|
});
|
|
3457
3470
|
this.emitDocflowObservation({
|
|
3458
|
-
runId
|
|
3471
|
+
runId,
|
|
3459
3472
|
attempt,
|
|
3460
3473
|
nodeId: observationNodeId,
|
|
3461
3474
|
invocationSeq,
|
|
@@ -3501,7 +3514,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
3501
3514
|
at: Date.now(),
|
|
3502
3515
|
});
|
|
3503
3516
|
this.emitDocflowObservation({
|
|
3504
|
-
runId
|
|
3517
|
+
runId,
|
|
3505
3518
|
attempt,
|
|
3506
3519
|
nodeId: observationNodeId,
|
|
3507
3520
|
invocationSeq,
|
|
@@ -3533,7 +3546,7 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
3533
3546
|
at: Date.now(),
|
|
3534
3547
|
});
|
|
3535
3548
|
this.emitDocflowObservation({
|
|
3536
|
-
runId
|
|
3549
|
+
runId,
|
|
3537
3550
|
attempt,
|
|
3538
3551
|
nodeId: observationNodeId,
|
|
3539
3552
|
invocationSeq,
|
|
@@ -3770,6 +3783,19 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
3770
3783
|
});
|
|
3771
3784
|
}
|
|
3772
3785
|
|
|
3786
|
+
private withPendingMapRowData(
|
|
3787
|
+
row: PersistableMapRow,
|
|
3788
|
+
tableNamespace: string,
|
|
3789
|
+
): PersistableMapRow {
|
|
3790
|
+
const patch = this.activeMapCheckpointUpdates?.get(
|
|
3791
|
+
`${tableNamespace}\u0000${row.key}`,
|
|
3792
|
+
)?.dataPatch;
|
|
3793
|
+
// Nested step values exist in cell patches, not the authored return row.
|
|
3794
|
+
// Commit them with the terminal row before clearing its checkpoint state,
|
|
3795
|
+
// without adding internal fields to the immediate authored result snapshot.
|
|
3796
|
+
return patch ? { ...row, data: { ...row.data, ...patch } } : row;
|
|
3797
|
+
}
|
|
3798
|
+
|
|
3773
3799
|
private clearActiveMapCheckpointUpdate(
|
|
3774
3800
|
key: string,
|
|
3775
3801
|
tableNamespace: string,
|
|
@@ -8646,6 +8672,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8646
8672
|
if (!this.#options.onMapRowsCompleted || rows.length === 0) {
|
|
8647
8673
|
return;
|
|
8648
8674
|
}
|
|
8675
|
+
rows = rows.map((row) =>
|
|
8676
|
+
this.withPendingMapRowData(row, resolvedTableNamespace),
|
|
8677
|
+
);
|
|
8649
8678
|
for (const row of rows) {
|
|
8650
8679
|
assertPersistableMapRowWithinCustomerOutputLimits({
|
|
8651
8680
|
mapName: normalizedMapNamespace,
|
|
@@ -8870,6 +8899,8 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
8870
8899
|
const incrementalPersistence = createRuntimeMapRowPersistence(
|
|
8871
8900
|
persistMapRows,
|
|
8872
8901
|
{
|
|
8902
|
+
prepareTerminalRow: (row) =>
|
|
8903
|
+
this.withPendingMapRowData(row, resolvedTableNamespace),
|
|
8873
8904
|
persistCheckpoint: this.#options.onMapRowsCheckpoint
|
|
8874
8905
|
? (updates) =>
|
|
8875
8906
|
this.#options.onMapRowsCheckpoint!({
|
|
@@ -9717,6 +9748,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9717
9748
|
if (!this.#options.onMapRowsCompleted || rows.length === 0) {
|
|
9718
9749
|
return;
|
|
9719
9750
|
}
|
|
9751
|
+
rows = rows.map((row) =>
|
|
9752
|
+
this.withPendingMapRowData(row, resolvedTableNamespace),
|
|
9753
|
+
);
|
|
9720
9754
|
for (const row of rows) {
|
|
9721
9755
|
assertPersistableMapRowWithinCustomerOutputLimits({
|
|
9722
9756
|
mapName: normalizedMapNamespace,
|
|
@@ -9770,6 +9804,8 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
9770
9804
|
};
|
|
9771
9805
|
const incrementalPersistence = this.#options.onMapRowsCompleted
|
|
9772
9806
|
? createRuntimeMapRowPersistence(persistMapRows, {
|
|
9807
|
+
prepareTerminalRow: (row) =>
|
|
9808
|
+
this.withPendingMapRowData(row, resolvedTableNamespace),
|
|
9773
9809
|
persistCheckpoint: this.#options.onMapRowsCheckpoint
|
|
9774
9810
|
? (updates) =>
|
|
9775
9811
|
this.#options.onMapRowsCheckpoint!({
|
|
@@ -11750,12 +11786,12 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
11750
11786
|
key: rowStore.rowKey ?? null,
|
|
11751
11787
|
tableNamespace: rowStore.tableNamespace ?? null,
|
|
11752
11788
|
fieldName,
|
|
11753
|
-
status: 'completed',
|
|
11789
|
+
status: stageExecution.skipped ? 'skipped' : 'completed',
|
|
11754
11790
|
rowStatus: 'running',
|
|
11755
|
-
stage: 'completed',
|
|
11791
|
+
stage: stageExecution.skipped ? 'skipped' : 'completed',
|
|
11756
11792
|
provider: null,
|
|
11757
11793
|
error: null,
|
|
11758
|
-
completedAt: Date.now(),
|
|
11794
|
+
...(stageExecution.skipped ? {} : { completedAt: Date.now() }),
|
|
11759
11795
|
dataPatch: { [patchFieldName]: cellValue },
|
|
11760
11796
|
});
|
|
11761
11797
|
}
|
|
@@ -12773,6 +12809,62 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
12773
12809
|
toolId: string,
|
|
12774
12810
|
input: Record<string, unknown>,
|
|
12775
12811
|
options?: ToolCallOptions,
|
|
12812
|
+
): Promise<unknown> {
|
|
12813
|
+
const startedAt = Date.now();
|
|
12814
|
+
const row = rowContext.getStore();
|
|
12815
|
+
// Capture caller scope before asynchronous dispatch. Provider batches do
|
|
12816
|
+
// not own a single row, and direct calls have no dataset scope at all.
|
|
12817
|
+
const context = {
|
|
12818
|
+
run_id: this.currentRunId,
|
|
12819
|
+
...(row?.tableNamespace ? { dataset: row.tableNamespace } : {}),
|
|
12820
|
+
...(row?.rowKey ? { row_key: row.rowKey } : {}),
|
|
12821
|
+
...(row?.fieldName ? { column: row.fieldName } : {}),
|
|
12822
|
+
call_key: this.normalizeContextKey(key, 'tool'),
|
|
12823
|
+
tool: toolId,
|
|
12824
|
+
};
|
|
12825
|
+
let result: unknown;
|
|
12826
|
+
try {
|
|
12827
|
+
result = await this.executeToolInternal(key, toolId, input, options);
|
|
12828
|
+
} catch (error) {
|
|
12829
|
+
// Parking is control flow, not a failed tool execution.
|
|
12830
|
+
if (
|
|
12831
|
+
!isPlayExecutionSuspendedError(error) &&
|
|
12832
|
+
!isPlayRowExecutionSuspendedError(error) &&
|
|
12833
|
+
!(error instanceof PlayRowProviderBackpressureError)
|
|
12834
|
+
) {
|
|
12835
|
+
this.runtimeLog(
|
|
12836
|
+
JSON.stringify({
|
|
12837
|
+
event: 'tool_call_failed',
|
|
12838
|
+
...context,
|
|
12839
|
+
status: 'failed',
|
|
12840
|
+
duration_ms: Math.max(0, Date.now() - startedAt),
|
|
12841
|
+
}),
|
|
12842
|
+
);
|
|
12843
|
+
}
|
|
12844
|
+
throw error;
|
|
12845
|
+
}
|
|
12846
|
+
const toolResult = isToolExecuteResult(result) ? result : undefined;
|
|
12847
|
+
const execution = toolResult?._metadata?.execution;
|
|
12848
|
+
this.runtimeLog(
|
|
12849
|
+
JSON.stringify({
|
|
12850
|
+
event: 'tool_call_completed',
|
|
12851
|
+
...context,
|
|
12852
|
+
...(execution?.receiptKey ? { receipt_key: execution.receiptKey } : {}),
|
|
12853
|
+
...(execution?.source ? { execution_source: execution.source } : {}),
|
|
12854
|
+
status: toolResult?.status ?? 'completed',
|
|
12855
|
+
// Caller wall time includes queueing/reuse and result delivery. It is
|
|
12856
|
+
// deliberately not described as provider request duration.
|
|
12857
|
+
duration_ms: Math.max(0, Date.now() - startedAt),
|
|
12858
|
+
}),
|
|
12859
|
+
);
|
|
12860
|
+
return result;
|
|
12861
|
+
}
|
|
12862
|
+
|
|
12863
|
+
private async executeToolInternal(
|
|
12864
|
+
key: string,
|
|
12865
|
+
toolId: string,
|
|
12866
|
+
input: Record<string, unknown>,
|
|
12867
|
+
options?: ToolCallOptions,
|
|
12776
12868
|
): Promise<unknown> {
|
|
12777
12869
|
if (!rowContext.getStore()) this.assertRowAdmissionOpen();
|
|
12778
12870
|
this.assertNoPendingDurableSuspension();
|
|
@@ -14420,15 +14512,33 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
14420
14512
|
);
|
|
14421
14513
|
}
|
|
14422
14514
|
|
|
14423
|
-
private appendRunLog(
|
|
14424
|
-
|
|
14425
|
-
|
|
14515
|
+
private appendRunLog(
|
|
14516
|
+
line: string,
|
|
14517
|
+
terminal = false,
|
|
14518
|
+
context?: PlayLogContext | null,
|
|
14519
|
+
): void {
|
|
14520
|
+
const boundedLine = boundRunLogLine(line);
|
|
14521
|
+
const omittedBefore = this.logBuffer.snapshot().omittedLines;
|
|
14522
|
+
for (const retained of this.logBuffer.append(line, terminal, context)) {
|
|
14523
|
+
const originalLineWasRetained =
|
|
14524
|
+
retained === boundedLine &&
|
|
14525
|
+
this.logBuffer.snapshot().omittedLines === omittedBefore;
|
|
14526
|
+
this.#options.onLog?.(
|
|
14527
|
+
retained,
|
|
14528
|
+
originalLineWasRetained
|
|
14529
|
+
? (this.logBuffer.contexts.at(-1) ?? undefined)
|
|
14530
|
+
: undefined,
|
|
14531
|
+
);
|
|
14426
14532
|
if (this.#options.verbose) console.log(retained);
|
|
14427
14533
|
}
|
|
14428
14534
|
}
|
|
14429
14535
|
|
|
14430
|
-
log(
|
|
14536
|
+
log(
|
|
14537
|
+
msg: string,
|
|
14538
|
+
options?: { level?: LogLevel; context?: PlayLogContext },
|
|
14539
|
+
): void {
|
|
14431
14540
|
assertNoSecretTaint(msg, 'ctx.log');
|
|
14541
|
+
assertNoSecretTaint(options?.context, 'ctx.log context');
|
|
14432
14542
|
const requestedLevel = options?.level;
|
|
14433
14543
|
if (requestedLevel !== undefined && !LOG_LEVELS.includes(requestedLevel)) {
|
|
14434
14544
|
throw new Error(
|
|
@@ -14436,12 +14546,26 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
14436
14546
|
);
|
|
14437
14547
|
}
|
|
14438
14548
|
const level = requestedLevel ?? 'info';
|
|
14549
|
+
const context = normalizePlayLogContext(options?.context);
|
|
14550
|
+
const redactedContext = context
|
|
14551
|
+
? normalizePlayLogContext(this.secretRedactor.redact(context))
|
|
14552
|
+
: null;
|
|
14439
14553
|
const timestamped = `[${new Date().toISOString()}] ${this.secretRedactor.redactRegisteredSecrets(msg)}`;
|
|
14440
14554
|
// Stamp the default too: a customer message that happens to begin with
|
|
14441
14555
|
// "[error]" is still info unless the author selected a higher severity.
|
|
14442
14556
|
const line = tagLogEntry('user', level, timestamped);
|
|
14443
14557
|
if (!this.shouldKeepRateLimitedLog(level)) return;
|
|
14444
|
-
this.
|
|
14558
|
+
const omittedContextsBefore = this.logBuffer.snapshot().omittedContexts;
|
|
14559
|
+
this.appendRunLog(line, false, redactedContext);
|
|
14560
|
+
if (
|
|
14561
|
+
!this.logContextBudgetWarningLogged &&
|
|
14562
|
+
this.logBuffer.snapshot().omittedContexts > omittedContextsBefore
|
|
14563
|
+
) {
|
|
14564
|
+
this.logContextBudgetWarningLogged = true;
|
|
14565
|
+
this.appendRunLog(
|
|
14566
|
+
`[warn] [structured log context budget reached: later ctx.log messages are retained, but their context fields are omitted for this run; budget ${RUNNER_LOG_CONTEXT_MAX_BYTES} bytes.]`,
|
|
14567
|
+
);
|
|
14568
|
+
}
|
|
14445
14569
|
}
|
|
14446
14570
|
|
|
14447
14571
|
/**
|
|
@@ -15087,6 +15211,10 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
|
|
|
15087
15211
|
return this.logBuffer.lines;
|
|
15088
15212
|
}
|
|
15089
15213
|
|
|
15214
|
+
getLogContexts(): Array<PlayLogContext | null> {
|
|
15215
|
+
return this.logBuffer.contexts.slice();
|
|
15216
|
+
}
|
|
15217
|
+
|
|
15090
15218
|
assertRowAdmissionOpen(): void {
|
|
15091
15219
|
this.#options.rowAdmissionSignal?.throwIfAborted();
|
|
15092
15220
|
}
|
|
@@ -10,6 +10,7 @@ import type { PlayRunContractSnapshot } from '../plays/contracts';
|
|
|
10
10
|
import type { PlayDatasetColumnTypes } from '../play-data-plane/contracts';
|
|
11
11
|
import type { PlayStructuredDefinition } from '../plays/definition';
|
|
12
12
|
import type { PlayStaticPipeline } from '../plays/static-pipeline';
|
|
13
|
+
import type { PlayLogContext } from './log-context';
|
|
13
14
|
import type {
|
|
14
15
|
AsyncPlayRunRef,
|
|
15
16
|
DurableCallStaleAfterSeconds,
|
|
@@ -842,7 +843,7 @@ export interface ContextOptions {
|
|
|
842
843
|
/** Called after each durable batch completes for scheduler checkpointing. */
|
|
843
844
|
onBatchComplete?: (checkpoint: PlayCheckpoint) => void;
|
|
844
845
|
/** Called when the runtime emits a new execution log line. */
|
|
845
|
-
onLog?: (line: string) => void;
|
|
846
|
+
onLog?: (line: string, context?: PlayLogContext) => void;
|
|
846
847
|
/**
|
|
847
848
|
* Runtime-provided HTTP transport for ctx.fetch. Node runtimes should provide
|
|
848
849
|
* a transport that validates resolved IP addresses at connect time.
|
|
@@ -16,11 +16,14 @@ export type DaytonaRunnerPathsConfig = {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
export function daytonaClientOptions(apiKey: string): DaytonaClientOptions {
|
|
19
|
+
// Preserve the SDK's legacy URL fallback in the shared configuration owner,
|
|
20
|
+
// including for generated control clients that do not read SDK env files.
|
|
21
|
+
const apiUrl =
|
|
22
|
+
process.env.DAYTONA_API_URL?.trim() ||
|
|
23
|
+
process.env.DAYTONA_SERVER_URL?.trim();
|
|
19
24
|
return {
|
|
20
25
|
apiKey,
|
|
21
|
-
...(
|
|
22
|
-
? { apiUrl: process.env.DAYTONA_API_URL.trim() }
|
|
23
|
-
: {}),
|
|
26
|
+
...(apiUrl ? { apiUrl } : {}),
|
|
24
27
|
...(process.env.DAYTONA_TARGET?.trim()
|
|
25
28
|
? { target: process.env.DAYTONA_TARGET.trim() }
|
|
26
29
|
: {}),
|
|
@@ -44,38 +44,43 @@ export function startDaytonaSandboxJanitor(
|
|
|
44
44
|
running = true;
|
|
45
45
|
try {
|
|
46
46
|
const [
|
|
47
|
-
{
|
|
47
|
+
{ listDaytonaControlSandboxes },
|
|
48
48
|
{ loadDaytonaRequiredConfig },
|
|
49
49
|
{
|
|
50
50
|
createPostgresDaytonaJanitorOwnershipPort,
|
|
51
51
|
reapOrphanDaytonaSandboxes,
|
|
52
52
|
},
|
|
53
53
|
] = await Promise.all([
|
|
54
|
-
import('
|
|
54
|
+
import('./runner-backends/backends/daytona-control-transport'),
|
|
55
55
|
import('.//daytona-runtime-config'),
|
|
56
56
|
import('./daytona-sandbox-reaper'),
|
|
57
57
|
]);
|
|
58
58
|
const { clientOptions } = loadDaytonaRequiredConfig();
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
url: options.url,
|
|
63
|
-
applicationName: 'deepline-daytona-janitor',
|
|
64
|
-
maxClients:
|
|
65
|
-
options.maxClients ??
|
|
66
|
-
RUNTIME_CAPACITY_POLICY.runtimePostgres.schedulerPoolMaxClients,
|
|
59
|
+
await reapOrphanDaytonaSandboxes({
|
|
60
|
+
daytona: {
|
|
61
|
+
list: (query) => listDaytonaControlSandboxes(clientOptions, query),
|
|
67
62
|
},
|
|
68
|
-
(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
63
|
+
ownership: createPostgresDaytonaJanitorOwnershipPort({
|
|
64
|
+
// Provider pagination and per-sandbox work must never retain one of
|
|
65
|
+
// the controller's shared scheduler connections. Each ownership
|
|
66
|
+
// operation is one self-contained SQL statement (including its CTE).
|
|
67
|
+
client: {
|
|
68
|
+
query: (sql, params) =>
|
|
69
|
+
withRuntimeSchedulerClient(
|
|
70
|
+
{
|
|
71
|
+
url: options.url,
|
|
72
|
+
applicationName: 'deepline-daytona-janitor',
|
|
73
|
+
maxClients:
|
|
74
|
+
options.maxClients ??
|
|
75
|
+
RUNTIME_CAPACITY_POLICY.runtimePostgres
|
|
76
|
+
.schedulerPoolMaxClients,
|
|
77
|
+
},
|
|
78
|
+
(client) => client.query(sql, params),
|
|
79
|
+
),
|
|
80
|
+
},
|
|
81
|
+
schema: options.schema,
|
|
82
|
+
}),
|
|
83
|
+
});
|
|
79
84
|
} catch (error) {
|
|
80
85
|
// This is a best-effort resource backstop. A failed sweep must never
|
|
81
86
|
// terminate the controller that scales and recovers customer work.
|
|
@@ -66,8 +66,8 @@ export type ReapableSandbox = {
|
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
|
-
* Injected Daytona port. `list` yields our label-scoped sandboxes
|
|
70
|
-
*
|
|
69
|
+
* Injected Daytona port. `list` yields our label-scoped sandboxes through an
|
|
70
|
+
* async iterator that auto-pages, so we consume it lazily.
|
|
71
71
|
* Inventory is the only Daytona surface the janitor touches.
|
|
72
72
|
*/
|
|
73
73
|
export type DaytonaJanitorClientPort = {
|
|
@@ -659,7 +659,9 @@ export function createPostgresDaytonaJanitorOwnershipPort(input: {
|
|
|
659
659
|
// CLI entry.
|
|
660
660
|
// ---------------------------------------------------------------------------
|
|
661
661
|
|
|
662
|
-
export async function runDaytonaSandboxJanitorCli(
|
|
662
|
+
export async function runDaytonaSandboxJanitorCli(
|
|
663
|
+
argv: string[],
|
|
664
|
+
): Promise<void> {
|
|
663
665
|
const dryRun = argv.includes('--dry-run');
|
|
664
666
|
// Escape hatch for deliberate debugging only: reaping against an isolated
|
|
665
667
|
// schema is unsafe because the `source`-scoped fleet is shared across lanes
|
|
@@ -669,13 +671,13 @@ export async function runDaytonaSandboxJanitorCli(argv: string[]): Promise<void>
|
|
|
669
671
|
// Lazy imports so the pure core above stays free of heavy runtime deps and
|
|
670
672
|
// remains trivially unit-testable with fake ports.
|
|
671
673
|
const [
|
|
672
|
-
{
|
|
674
|
+
{ listDaytonaControlSandboxes },
|
|
673
675
|
{ loadDaytonaRequiredConfig },
|
|
674
676
|
poolModule,
|
|
675
677
|
schemaModule,
|
|
676
678
|
{ isIsolatedRuntimeSchedulerSchema },
|
|
677
679
|
] = await Promise.all([
|
|
678
|
-
import('
|
|
680
|
+
import('./runner-backends/backends/daytona-control-transport'),
|
|
679
681
|
import('.//daytona-runtime-config'),
|
|
680
682
|
import('.//scheduler-backends/postgres-pool'),
|
|
681
683
|
import('.//scheduler-backends/runtime-scheduler-schema'),
|
|
@@ -704,22 +706,22 @@ export async function runDaytonaSandboxJanitorCli(argv: string[]): Promise<void>
|
|
|
704
706
|
}
|
|
705
707
|
|
|
706
708
|
const { clientOptions } = loadDaytonaRequiredConfig();
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
(
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
);
|
|
709
|
+
const summary = await reapOrphanDaytonaSandboxes({
|
|
710
|
+
daytona: {
|
|
711
|
+
list: (query) => listDaytonaControlSandboxes(clientOptions, query),
|
|
712
|
+
},
|
|
713
|
+
ownership: createPostgresDaytonaJanitorOwnershipPort({
|
|
714
|
+
client: {
|
|
715
|
+
query: (sql, params) =>
|
|
716
|
+
poolModule.withRuntimeSchedulerClient(
|
|
717
|
+
{ url, applicationName: 'deepline-daytona-janitor' },
|
|
718
|
+
(client) => client.query(sql, params),
|
|
719
|
+
),
|
|
720
|
+
},
|
|
721
|
+
schema,
|
|
722
|
+
}),
|
|
723
|
+
options: { dryRun },
|
|
724
|
+
});
|
|
723
725
|
|
|
724
726
|
console.info('[daytona-janitor.cli_done]', { ...summary, schema, dryRun });
|
|
725
727
|
}
|