deepline 0.1.131 → 0.1.132
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 +163 -97
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +22 -12
- package/dist/bundling-sources/sdk/src/release.ts +2 -2
- package/dist/bundling-sources/shared_libs/play-runtime/batch-runtime.ts +30 -23
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +277 -100
- package/dist/cli/index.js +37 -9
- package/dist/cli/index.mjs +37 -9
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
|
@@ -1466,6 +1466,9 @@ type WorkerToolBatchRequest = {
|
|
|
1466
1466
|
|
|
1467
1467
|
const WORKER_TOOL_BATCH_GRACE_MS = 250;
|
|
1468
1468
|
const MAP_EXECUTION_HEARTBEAT_INTERVAL_MS = 5_000;
|
|
1469
|
+
const MAP_INCREMENTAL_PERSIST_CHUNK_ROWS = 100;
|
|
1470
|
+
const MAP_INCREMENTAL_PERSIST_CHUNK_BYTES = 1 * 1024 * 1024;
|
|
1471
|
+
const MAP_INCREMENTAL_PERSIST_INTERVAL_MS = 100;
|
|
1469
1472
|
/**
|
|
1470
1473
|
* Bounded number of per-row failure samples carried in chunk summaries and the
|
|
1471
1474
|
* map's terminal partial-failure log. Every failed row is persisted with its
|
|
@@ -3850,6 +3853,153 @@ function createMinimalWorkerCtx(
|
|
|
3850
3853
|
reportSettledToolRequests,
|
|
3851
3854
|
);
|
|
3852
3855
|
const generatedOutputFields = new Set<string>();
|
|
3856
|
+
const persistedExecutedIndexes = new Set<number>();
|
|
3857
|
+
const persistedFailedIndexes = new Set<number>();
|
|
3858
|
+
let pendingPersistRows = 0;
|
|
3859
|
+
let pendingPersistBytes = 0;
|
|
3860
|
+
let scheduledPersistTimer: ReturnType<typeof setTimeout> | null = null;
|
|
3861
|
+
let persistFlushChain: Promise<void> = Promise.resolve();
|
|
3862
|
+
let persistFailure: unknown = null;
|
|
3863
|
+
|
|
3864
|
+
const clearScheduledPersistTimer = () => {
|
|
3865
|
+
if (scheduledPersistTimer) {
|
|
3866
|
+
clearTimeout(scheduledPersistTimer);
|
|
3867
|
+
scheduledPersistTimer = null;
|
|
3868
|
+
}
|
|
3869
|
+
};
|
|
3870
|
+
|
|
3871
|
+
const persistExecutedRows = async () => {
|
|
3872
|
+
const rowsToPersist = executedRows
|
|
3873
|
+
.map((row, executedIndex) =>
|
|
3874
|
+
row && !persistedExecutedIndexes.has(executedIndex)
|
|
3875
|
+
? {
|
|
3876
|
+
row,
|
|
3877
|
+
executedIndex,
|
|
3878
|
+
}
|
|
3879
|
+
: null,
|
|
3880
|
+
)
|
|
3881
|
+
.filter(
|
|
3882
|
+
(
|
|
3883
|
+
entry,
|
|
3884
|
+
): entry is {
|
|
3885
|
+
row: T & Record<string, unknown>;
|
|
3886
|
+
executedIndex: number;
|
|
3887
|
+
} => entry !== null,
|
|
3888
|
+
);
|
|
3889
|
+
const allFailedRowsToPersist = failedRowEntries
|
|
3890
|
+
.map((failure, executedIndex) =>
|
|
3891
|
+
failure && !persistedFailedIndexes.has(executedIndex)
|
|
3892
|
+
? {
|
|
3893
|
+
failure,
|
|
3894
|
+
executedIndex,
|
|
3895
|
+
}
|
|
3896
|
+
: null,
|
|
3897
|
+
)
|
|
3898
|
+
.filter(
|
|
3899
|
+
(
|
|
3900
|
+
entry,
|
|
3901
|
+
): entry is {
|
|
3902
|
+
failure: { row: T & Record<string, unknown>; error: string };
|
|
3903
|
+
executedIndex: number;
|
|
3904
|
+
} => entry !== null,
|
|
3905
|
+
);
|
|
3906
|
+
// Under the default isolation, every failed row persists as a
|
|
3907
|
+
// recoverable `_status='failed'` row (it re-executes free next run).
|
|
3908
|
+
// Under `onRowError: 'fail'` the run dies, so a failed row's partial
|
|
3909
|
+
// data is persisted ONLY as a last-resort recovery: when this chunk has
|
|
3910
|
+
// no other recoverable rows (no successful executed rows and no
|
|
3911
|
+
// already-completed rows). That keeps a partial fail-fast run's export
|
|
3912
|
+
// to the rows that fully committed before the failure, while an
|
|
3913
|
+
// all-rows-failed fail-fast run still exposes the persisted partial
|
|
3914
|
+
// cells instead of advertising an empty, unrecoverable dataset.
|
|
3915
|
+
const failedRowsToPersist =
|
|
3916
|
+
failFastRowErrors &&
|
|
3917
|
+
(rowsToPersist.length > 0 ||
|
|
3918
|
+
persistedExecutedIndexes.size > 0 ||
|
|
3919
|
+
prepared.completedRows.length > 0)
|
|
3920
|
+
? []
|
|
3921
|
+
: allFailedRowsToPersist;
|
|
3922
|
+
if (rowsToPersist.length === 0 && failedRowsToPersist.length === 0) {
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
await persistCompletedMapRows({
|
|
3926
|
+
req,
|
|
3927
|
+
tableNamespace: name,
|
|
3928
|
+
outputFields,
|
|
3929
|
+
extraOutputFields: Array.from(generatedOutputFields),
|
|
3930
|
+
rows: [
|
|
3931
|
+
...rowsToPersist.map(({ row, executedIndex }) => ({
|
|
3932
|
+
...row,
|
|
3933
|
+
...(executedCellMetaPatches[executedIndex]
|
|
3934
|
+
? {
|
|
3935
|
+
__deeplineCellMetaPatch:
|
|
3936
|
+
executedCellMetaPatches[executedIndex],
|
|
3937
|
+
}
|
|
3938
|
+
: {}),
|
|
3939
|
+
__deeplineRowKey:
|
|
3940
|
+
uniqueRowsToExecuteEntries[executedIndex]!.rowKey,
|
|
3941
|
+
})),
|
|
3942
|
+
// Failed rows persist as recoverable `_status='failed'` sheet
|
|
3943
|
+
// rows: partial data + per-cell failure meta + the row error.
|
|
3944
|
+
...failedRowsToPersist.map(({ failure, executedIndex }) => ({
|
|
3945
|
+
...failure.row,
|
|
3946
|
+
...(executedCellMetaPatches[executedIndex]
|
|
3947
|
+
? {
|
|
3948
|
+
__deeplineCellMetaPatch:
|
|
3949
|
+
executedCellMetaPatches[executedIndex],
|
|
3950
|
+
}
|
|
3951
|
+
: {}),
|
|
3952
|
+
__deeplineRowKey:
|
|
3953
|
+
uniqueRowsToExecuteEntries[executedIndex]!.rowKey,
|
|
3954
|
+
__deeplineRowStatus: 'failed',
|
|
3955
|
+
__deeplineRowError: failure.error,
|
|
3956
|
+
})),
|
|
3957
|
+
],
|
|
3958
|
+
});
|
|
3959
|
+
for (const { executedIndex } of rowsToPersist) {
|
|
3960
|
+
persistedExecutedIndexes.add(executedIndex);
|
|
3961
|
+
}
|
|
3962
|
+
for (const { executedIndex } of failedRowsToPersist) {
|
|
3963
|
+
persistedFailedIndexes.add(executedIndex);
|
|
3964
|
+
}
|
|
3965
|
+
};
|
|
3966
|
+
|
|
3967
|
+
const enqueuePersistExecutedRows = (): Promise<void> => {
|
|
3968
|
+
clearScheduledPersistTimer();
|
|
3969
|
+
pendingPersistRows = 0;
|
|
3970
|
+
pendingPersistBytes = 0;
|
|
3971
|
+
const task = persistFlushChain.then(async () => {
|
|
3972
|
+
if (persistFailure) throw persistFailure;
|
|
3973
|
+
await persistExecutedRows();
|
|
3974
|
+
});
|
|
3975
|
+
persistFlushChain = task.catch((error) => {
|
|
3976
|
+
persistFailure ??= error;
|
|
3977
|
+
});
|
|
3978
|
+
return task;
|
|
3979
|
+
};
|
|
3980
|
+
|
|
3981
|
+
const schedulePersistExecutedRows = () => {
|
|
3982
|
+
if (persistFailure) return;
|
|
3983
|
+
if (
|
|
3984
|
+
pendingPersistRows >= MAP_INCREMENTAL_PERSIST_CHUNK_ROWS ||
|
|
3985
|
+
pendingPersistBytes >= MAP_INCREMENTAL_PERSIST_CHUNK_BYTES
|
|
3986
|
+
) {
|
|
3987
|
+
void enqueuePersistExecutedRows().catch(() => undefined);
|
|
3988
|
+
return;
|
|
3989
|
+
}
|
|
3990
|
+
if (scheduledPersistTimer) return;
|
|
3991
|
+
scheduledPersistTimer = setTimeout(() => {
|
|
3992
|
+
scheduledPersistTimer = null;
|
|
3993
|
+
void enqueuePersistExecutedRows().catch(() => undefined);
|
|
3994
|
+
}, MAP_INCREMENTAL_PERSIST_INTERVAL_MS);
|
|
3995
|
+
};
|
|
3996
|
+
|
|
3997
|
+
const notePersistableRow = (row: Record<string, unknown>) => {
|
|
3998
|
+
pendingPersistRows += 1;
|
|
3999
|
+
pendingPersistBytes += JSON.stringify(row).length;
|
|
4000
|
+
schedulePersistExecutedRows();
|
|
4001
|
+
};
|
|
4002
|
+
|
|
3853
4003
|
let idx = 0;
|
|
3854
4004
|
const workers: Array<Promise<void>> = [];
|
|
3855
4005
|
for (let w = 0; w < concurrency; w += 1) {
|
|
@@ -4025,6 +4175,7 @@ function createMinimalWorkerCtx(
|
|
|
4025
4175
|
executedRows[myIndex] = enriched as T &
|
|
4026
4176
|
Record<string, unknown>;
|
|
4027
4177
|
completedExecutedRows += 1;
|
|
4178
|
+
notePersistableRow(enriched);
|
|
4028
4179
|
reportChunkProgress(false);
|
|
4029
4180
|
} catch (rowError) {
|
|
4030
4181
|
// Abort/budget errors stay run-fatal and leave no partial
|
|
@@ -4045,19 +4196,19 @@ function createMinimalWorkerCtx(
|
|
|
4045
4196
|
Object.keys(cellMetaPatch).length > 0
|
|
4046
4197
|
? cellMetaPatch
|
|
4047
4198
|
: undefined;
|
|
4048
|
-
// Keep the partially-enriched row
|
|
4049
|
-
//
|
|
4050
|
-
//
|
|
4051
|
-
//
|
|
4052
|
-
//
|
|
4053
|
-
// 'fail'`: the chunk still persists every recorded row, so the
|
|
4054
|
-
// failed run advertises a working recovered export even when
|
|
4055
|
-
// every row fails (see the runMap-level fail-fast throw).
|
|
4199
|
+
// Keep the partially-enriched row. Default isolation persists
|
|
4200
|
+
// it as `_status='failed'` so the row can re-execute free on
|
|
4201
|
+
// the next run. Fail-fast persists failed rows only after the
|
|
4202
|
+
// chunk settles and only when every row failed; otherwise only
|
|
4203
|
+
// fully committed successful rows are recoverable.
|
|
4056
4204
|
failedRowEntries[myIndex] = {
|
|
4057
4205
|
row: enriched as T & Record<string, unknown>,
|
|
4058
4206
|
error: message,
|
|
4059
4207
|
};
|
|
4060
4208
|
failedExecutedRows += 1;
|
|
4209
|
+
if (!failFastRowErrors) {
|
|
4210
|
+
notePersistableRow(enriched);
|
|
4211
|
+
}
|
|
4061
4212
|
// Bounded per-chunk samples: every failure is persisted on
|
|
4062
4213
|
// its row, but only the first few get a log line so a wide
|
|
4063
4214
|
// outage cannot flood the Run Log Stream.
|
|
@@ -4069,7 +4220,7 @@ function createMinimalWorkerCtx(
|
|
|
4069
4220
|
`Row ${absoluteIndex} of ctx.dataset("${name}") failed` +
|
|
4070
4221
|
`${activeField ? ` at column "${activeField}"` : ''}: ${message} ` +
|
|
4071
4222
|
(failFastRowErrors
|
|
4072
|
-
? '(row
|
|
4223
|
+
? '(row recorded as failed; onRowError:"fail" persists it only if every row fails)'
|
|
4073
4224
|
: '(row recorded as failed; sibling rows continue and the row re-executes on the next run)'),
|
|
4074
4225
|
ts: nowMs(),
|
|
4075
4226
|
});
|
|
@@ -4098,93 +4249,6 @@ function createMinimalWorkerCtx(
|
|
|
4098
4249
|
})(),
|
|
4099
4250
|
);
|
|
4100
4251
|
}
|
|
4101
|
-
const persistExecutedRows = async () => {
|
|
4102
|
-
const rowsToPersist = executedRows
|
|
4103
|
-
.map((row, executedIndex) =>
|
|
4104
|
-
row
|
|
4105
|
-
? {
|
|
4106
|
-
row,
|
|
4107
|
-
executedIndex,
|
|
4108
|
-
}
|
|
4109
|
-
: null,
|
|
4110
|
-
)
|
|
4111
|
-
.filter(
|
|
4112
|
-
(
|
|
4113
|
-
entry,
|
|
4114
|
-
): entry is {
|
|
4115
|
-
row: T & Record<string, unknown>;
|
|
4116
|
-
executedIndex: number;
|
|
4117
|
-
} => entry !== null,
|
|
4118
|
-
);
|
|
4119
|
-
const allFailedRowsToPersist = failedRowEntries
|
|
4120
|
-
.map((failure, executedIndex) =>
|
|
4121
|
-
failure
|
|
4122
|
-
? {
|
|
4123
|
-
failure,
|
|
4124
|
-
executedIndex,
|
|
4125
|
-
}
|
|
4126
|
-
: null,
|
|
4127
|
-
)
|
|
4128
|
-
.filter(
|
|
4129
|
-
(
|
|
4130
|
-
entry,
|
|
4131
|
-
): entry is {
|
|
4132
|
-
failure: { row: T & Record<string, unknown>; error: string };
|
|
4133
|
-
executedIndex: number;
|
|
4134
|
-
} => entry !== null,
|
|
4135
|
-
);
|
|
4136
|
-
// Under the default isolation, every failed row persists as a
|
|
4137
|
-
// recoverable `_status='failed'` row (it re-executes free next run).
|
|
4138
|
-
// Under `onRowError: 'fail'` the run dies, so a failed row's partial
|
|
4139
|
-
// data is persisted ONLY as a last-resort recovery: when this chunk has
|
|
4140
|
-
// no other recoverable rows (no successful executed rows and no
|
|
4141
|
-
// already-completed rows). That keeps a partial fail-fast run's export
|
|
4142
|
-
// to the rows that fully committed before the failure, while an
|
|
4143
|
-
// all-rows-failed fail-fast run still exposes the persisted partial
|
|
4144
|
-
// cells instead of advertising an empty, unrecoverable dataset.
|
|
4145
|
-
const failedRowsToPersist =
|
|
4146
|
-
failFastRowErrors &&
|
|
4147
|
-
(rowsToPersist.length > 0 || prepared.completedRows.length > 0)
|
|
4148
|
-
? []
|
|
4149
|
-
: allFailedRowsToPersist;
|
|
4150
|
-
if (rowsToPersist.length === 0 && failedRowsToPersist.length === 0) {
|
|
4151
|
-
return;
|
|
4152
|
-
}
|
|
4153
|
-
await persistCompletedMapRows({
|
|
4154
|
-
req,
|
|
4155
|
-
tableNamespace: name,
|
|
4156
|
-
outputFields,
|
|
4157
|
-
extraOutputFields: Array.from(generatedOutputFields),
|
|
4158
|
-
rows: [
|
|
4159
|
-
...rowsToPersist.map(({ row, executedIndex }) => ({
|
|
4160
|
-
...row,
|
|
4161
|
-
...(executedCellMetaPatches[executedIndex]
|
|
4162
|
-
? {
|
|
4163
|
-
__deeplineCellMetaPatch:
|
|
4164
|
-
executedCellMetaPatches[executedIndex],
|
|
4165
|
-
}
|
|
4166
|
-
: {}),
|
|
4167
|
-
__deeplineRowKey:
|
|
4168
|
-
uniqueRowsToExecuteEntries[executedIndex]!.rowKey,
|
|
4169
|
-
})),
|
|
4170
|
-
// Failed rows persist as recoverable `_status='failed'` sheet
|
|
4171
|
-
// rows: partial data + per-cell failure meta + the row error.
|
|
4172
|
-
...failedRowsToPersist.map(({ failure, executedIndex }) => ({
|
|
4173
|
-
...failure.row,
|
|
4174
|
-
...(executedCellMetaPatches[executedIndex]
|
|
4175
|
-
? {
|
|
4176
|
-
__deeplineCellMetaPatch:
|
|
4177
|
-
executedCellMetaPatches[executedIndex],
|
|
4178
|
-
}
|
|
4179
|
-
: {}),
|
|
4180
|
-
__deeplineRowKey:
|
|
4181
|
-
uniqueRowsToExecuteEntries[executedIndex]!.rowKey,
|
|
4182
|
-
__deeplineRowStatus: 'failed',
|
|
4183
|
-
__deeplineRowError: failure.error,
|
|
4184
|
-
})),
|
|
4185
|
-
],
|
|
4186
|
-
});
|
|
4187
|
-
};
|
|
4188
4252
|
const workersStartedAt = nowMs();
|
|
4189
4253
|
// Track completion with a boolean flag rather than narrowing a
|
|
4190
4254
|
// closure-assigned `| null` variable: TypeScript's control-flow analysis
|
|
@@ -4230,7 +4294,9 @@ function createMinimalWorkerCtx(
|
|
|
4230
4294
|
},
|
|
4231
4295
|
});
|
|
4232
4296
|
try {
|
|
4233
|
-
await
|
|
4297
|
+
await enqueuePersistExecutedRows();
|
|
4298
|
+
await persistFlushChain;
|
|
4299
|
+
if (persistFailure) throw persistFailure;
|
|
4234
4300
|
recordRunnerPerfTrace({
|
|
4235
4301
|
req,
|
|
4236
4302
|
phase: 'runner.map_chunk.persist_rows',
|
|
@@ -30,19 +30,29 @@ export async function executeChunkedRequests<TRequest, TResult>(input: {
|
|
|
30
30
|
const results: Array<ChunkExecutionResult<TRequest, TResult>> = [];
|
|
31
31
|
for (let start = 0; start < input.requests.length; start += input.batchSize) {
|
|
32
32
|
const chunk = input.requests.slice(start, start + input.batchSize);
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
let notifyChain: Promise<void> = Promise.resolve();
|
|
34
|
+
const notify = async (
|
|
35
|
+
entry: ChunkExecutionResult<TRequest, TResult>,
|
|
36
|
+
): Promise<void> => {
|
|
37
|
+
results.push(entry);
|
|
38
|
+
notifyChain = notifyChain.then(
|
|
39
|
+
async () => await input.onChunkComplete?.([entry]),
|
|
40
|
+
);
|
|
41
|
+
await notifyChain;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
await Promise.all(
|
|
45
|
+
chunk.map(async (request) => {
|
|
46
|
+
let entry: ChunkExecutionResult<TRequest, TResult>;
|
|
47
|
+
try {
|
|
48
|
+
entry = { request, result: await input.execute(request) };
|
|
49
|
+
} catch (error) {
|
|
50
|
+
entry = { request, result: null, error };
|
|
51
|
+
}
|
|
52
|
+
await notify(entry);
|
|
53
|
+
}),
|
|
35
54
|
);
|
|
36
|
-
|
|
37
|
-
const request = chunk[index]!;
|
|
38
|
-
const outcome = settled[index]!;
|
|
39
|
-
if (outcome.status === 'rejected') {
|
|
40
|
-
results.push({ request, result: null, error: outcome.reason });
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
results.push({ request, result: outcome.value });
|
|
44
|
-
}
|
|
45
|
-
await input.onChunkComplete?.(results.slice(results.length - chunk.length));
|
|
55
|
+
await notifyChain;
|
|
46
56
|
}
|
|
47
57
|
return results;
|
|
48
58
|
}
|
|
@@ -101,10 +101,10 @@ export const SDK_RELEASE = {
|
|
|
101
101
|
// 0.1.108 ships explicit dataset column/tool recompute policy and removes
|
|
102
102
|
// the SDK enrich generator's one-second stale policy.
|
|
103
103
|
// 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
|
|
104
|
-
version: '0.1.
|
|
104
|
+
version: '0.1.132',
|
|
105
105
|
apiContract: '2026-06-dataset-column-cell-stale-hard-cutover',
|
|
106
106
|
supportPolicy: {
|
|
107
|
-
latest: '0.1.
|
|
107
|
+
latest: '0.1.132',
|
|
108
108
|
minimumSupported: '0.1.53',
|
|
109
109
|
deprecatedBelow: '0.1.53',
|
|
110
110
|
commandMinimumSupported: [
|
|
@@ -45,30 +45,37 @@ export async function executeChunkedRequests<TRequest, TResult>(input: {
|
|
|
45
45
|
|
|
46
46
|
for (let start = 0; start < input.requests.length; start += input.batchSize) {
|
|
47
47
|
const chunk = input.requests.slice(start, start + input.batchSize);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
request,
|
|
59
|
-
result: null,
|
|
60
|
-
error: formatChunkExecutionError(outcome.reason),
|
|
61
|
-
});
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
results.push({
|
|
65
|
-
request,
|
|
66
|
-
result: outcome.value,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
48
|
+
let notifyChain: Promise<void> = Promise.resolve();
|
|
49
|
+
const notify = async (
|
|
50
|
+
entry: ChunkExecutionResult<TRequest, TResult>,
|
|
51
|
+
): Promise<void> => {
|
|
52
|
+
results.push(entry);
|
|
53
|
+
notifyChain = notifyChain.then(
|
|
54
|
+
async () => await input.onChunkComplete?.([entry]),
|
|
55
|
+
);
|
|
56
|
+
await notifyChain;
|
|
57
|
+
};
|
|
69
58
|
|
|
70
|
-
|
|
71
|
-
|
|
59
|
+
await Promise.all(
|
|
60
|
+
chunk.map(async (request) => {
|
|
61
|
+
let entry: ChunkExecutionResult<TRequest, TResult>;
|
|
62
|
+
try {
|
|
63
|
+
entry = {
|
|
64
|
+
request,
|
|
65
|
+
result: await input.execute(request),
|
|
66
|
+
};
|
|
67
|
+
} catch (error) {
|
|
68
|
+
input.onRequestError?.(request, error);
|
|
69
|
+
entry = {
|
|
70
|
+
request,
|
|
71
|
+
result: null,
|
|
72
|
+
error: formatChunkExecutionError(error),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
await notify(entry);
|
|
76
|
+
}),
|
|
77
|
+
);
|
|
78
|
+
await notifyChain;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
return results;
|
|
@@ -168,6 +168,9 @@ const MAP_FRAME_FLUSH_ROW_INTERVAL = 100;
|
|
|
168
168
|
/** Executed-row sheet persistence chunking: rows AND bytes, whichever first. */
|
|
169
169
|
const MAP_PERSIST_CHUNK_ROWS = 2_000;
|
|
170
170
|
const MAP_PERSIST_CHUNK_BYTES = 8 * 1024 * 1024;
|
|
171
|
+
const MAP_INCREMENTAL_PERSIST_CHUNK_ROWS = 100;
|
|
172
|
+
const MAP_INCREMENTAL_PERSIST_CHUNK_BYTES = 1 * 1024 * 1024;
|
|
173
|
+
const MAP_INCREMENTAL_PERSIST_INTERVAL_MS = 100;
|
|
171
174
|
const MAP_FRAME_FLUSH_INTERVAL_MS = 250;
|
|
172
175
|
const TOOL_RETRY_AFTER_FALLBACK_MS = 1_000;
|
|
173
176
|
const TOOL_RETRY_HEARTBEAT_INTERVAL_MS = 30_000;
|
|
@@ -219,11 +222,143 @@ function comparePersistableMapRowsByInputIndex(
|
|
|
219
222
|
return leftIndex - rightIndex;
|
|
220
223
|
}
|
|
221
224
|
|
|
225
|
+
function persistableMapRowIdentity(row: PersistableMapRow): string | null {
|
|
226
|
+
if (row.key) return `key:${row.key}`;
|
|
227
|
+
return typeof row.inputIndex === 'number' && Number.isFinite(row.inputIndex)
|
|
228
|
+
? `index:${Math.floor(row.inputIndex)}`
|
|
229
|
+
: null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function persistableMapRowBytes(row: PersistableMapRow): number {
|
|
233
|
+
return JSON.stringify(row).length;
|
|
234
|
+
}
|
|
235
|
+
|
|
222
236
|
type FieldMapRunResult = {
|
|
223
237
|
completedRows: PersistableMapRow[];
|
|
224
238
|
failedRows: PersistableMapRow[];
|
|
225
239
|
};
|
|
226
240
|
|
|
241
|
+
type IncrementalMapRowPersistence = {
|
|
242
|
+
persistRows: (rows: PersistableMapRow[]) => Promise<void>;
|
|
243
|
+
isPersisted: (row: PersistableMapRow) => boolean;
|
|
244
|
+
flush: () => Promise<void>;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
function createIncrementalMapRowPersistence(
|
|
248
|
+
persistRows: (rows: PersistableMapRow[]) => Promise<void>,
|
|
249
|
+
): IncrementalMapRowPersistence {
|
|
250
|
+
const persisted = new Set<string>();
|
|
251
|
+
const queued = new Set<string>();
|
|
252
|
+
let pendingRows: PersistableMapRow[] = [];
|
|
253
|
+
let pendingBytes = 0;
|
|
254
|
+
let pendingResolvers: Array<{
|
|
255
|
+
resolve: () => void;
|
|
256
|
+
reject: (error: unknown) => void;
|
|
257
|
+
}> = [];
|
|
258
|
+
let scheduledTimer: ReturnType<typeof setTimeout> | null = null;
|
|
259
|
+
let flushChain: Promise<void> = Promise.resolve();
|
|
260
|
+
|
|
261
|
+
const clearScheduledTimer = (): void => {
|
|
262
|
+
if (scheduledTimer) {
|
|
263
|
+
clearTimeout(scheduledTimer);
|
|
264
|
+
scheduledTimer = null;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
const flushPendingRows = (): Promise<void> => {
|
|
269
|
+
clearScheduledTimer();
|
|
270
|
+
const rows = pendingRows;
|
|
271
|
+
const resolvers = pendingResolvers;
|
|
272
|
+
pendingRows = [];
|
|
273
|
+
pendingBytes = 0;
|
|
274
|
+
pendingResolvers = [];
|
|
275
|
+
if (rows.length === 0) {
|
|
276
|
+
resolvers.forEach(({ resolve }) => resolve());
|
|
277
|
+
return flushChain;
|
|
278
|
+
}
|
|
279
|
+
flushChain = flushChain
|
|
280
|
+
.then(async () => {
|
|
281
|
+
await persistRows(rows);
|
|
282
|
+
for (const row of rows) {
|
|
283
|
+
const identity = persistableMapRowIdentity(row);
|
|
284
|
+
if (identity) {
|
|
285
|
+
persisted.add(identity);
|
|
286
|
+
queued.delete(identity);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
.then(
|
|
291
|
+
() => {
|
|
292
|
+
resolvers.forEach(({ resolve }) => resolve());
|
|
293
|
+
},
|
|
294
|
+
(error) => {
|
|
295
|
+
for (const row of rows) {
|
|
296
|
+
const identity = persistableMapRowIdentity(row);
|
|
297
|
+
if (identity) queued.delete(identity);
|
|
298
|
+
}
|
|
299
|
+
resolvers.forEach(({ reject }) => reject(error));
|
|
300
|
+
throw error;
|
|
301
|
+
},
|
|
302
|
+
);
|
|
303
|
+
return flushChain;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const scheduleFlush = (): void => {
|
|
307
|
+
if (scheduledTimer) return;
|
|
308
|
+
scheduledTimer = setTimeout(() => {
|
|
309
|
+
scheduledTimer = null;
|
|
310
|
+
void flushPendingRows().catch(() => {
|
|
311
|
+
// Each queued caller is rejected by flushPendingRows; this scheduled
|
|
312
|
+
// fire-and-forget path must not create a second unhandled rejection.
|
|
313
|
+
});
|
|
314
|
+
}, MAP_INCREMENTAL_PERSIST_INTERVAL_MS);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
persistRows: async (rows) => {
|
|
319
|
+
const freshRows: PersistableMapRow[] = [];
|
|
320
|
+
for (const row of rows) {
|
|
321
|
+
const identity = persistableMapRowIdentity(row);
|
|
322
|
+
if (identity && (persisted.has(identity) || queued.has(identity))) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (identity) queued.add(identity);
|
|
326
|
+
freshRows.push(row);
|
|
327
|
+
}
|
|
328
|
+
if (freshRows.length === 0) return;
|
|
329
|
+
await new Promise<void>((resolve, reject) => {
|
|
330
|
+
pendingRows.push(...freshRows);
|
|
331
|
+
pendingBytes += freshRows.reduce(
|
|
332
|
+
(total, row) => total + persistableMapRowBytes(row),
|
|
333
|
+
0,
|
|
334
|
+
);
|
|
335
|
+
pendingResolvers.push({ resolve, reject });
|
|
336
|
+
if (
|
|
337
|
+
pendingRows.length >= MAP_INCREMENTAL_PERSIST_CHUNK_ROWS ||
|
|
338
|
+
pendingBytes >= MAP_INCREMENTAL_PERSIST_CHUNK_BYTES
|
|
339
|
+
) {
|
|
340
|
+
void flushPendingRows().catch(() => {
|
|
341
|
+
// Each queued caller is rejected by flushPendingRows.
|
|
342
|
+
});
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
scheduleFlush();
|
|
346
|
+
});
|
|
347
|
+
},
|
|
348
|
+
isPersisted: (row) => {
|
|
349
|
+
const identity = persistableMapRowIdentity(row);
|
|
350
|
+
return identity ? persisted.has(identity) : false;
|
|
351
|
+
},
|
|
352
|
+
flush: async () => {
|
|
353
|
+
if (pendingRows.length > 0) {
|
|
354
|
+
clearScheduledTimer();
|
|
355
|
+
await flushPendingRows();
|
|
356
|
+
}
|
|
357
|
+
await flushChain;
|
|
358
|
+
},
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
227
362
|
class FailFastMapRowsError extends Error {
|
|
228
363
|
readonly completedRows: PersistableMapRow[];
|
|
229
364
|
readonly failedRows: PersistableMapRow[];
|
|
@@ -1819,6 +1954,7 @@ export class PlayContextImpl {
|
|
|
1819
1954
|
let totalInputCount = 0;
|
|
1820
1955
|
let rawItems: Record<string, unknown>[] = [];
|
|
1821
1956
|
let itemsToProcess: Array<Record<string, unknown>> = [];
|
|
1957
|
+
let itemOriginalIndexes: number[] = [];
|
|
1822
1958
|
let completedItemsByKey: Map<string, Record<string, unknown>> | null = null;
|
|
1823
1959
|
const datasetColumnNames = Object.keys(input);
|
|
1824
1960
|
const stripFieldOutputs = (row: Record<string, unknown>) => {
|
|
@@ -1923,6 +2059,7 @@ export class PlayContextImpl {
|
|
|
1923
2059
|
itemsToProcess = materializedItems.map((item) =>
|
|
1924
2060
|
this.toOutputRow(item as Record<string, unknown>),
|
|
1925
2061
|
);
|
|
2062
|
+
itemOriginalIndexes = materializedItems.map((_item, index) => index);
|
|
1926
2063
|
if (this.#options.onMapStart) {
|
|
1927
2064
|
const shouldPassRowKey = explicitKeyResolver != null;
|
|
1928
2065
|
// toSerializableCsvAliasedRow (not a plain spread): projected CSV
|
|
@@ -1968,7 +2105,7 @@ export class PlayContextImpl {
|
|
|
1968
2105
|
const rowKey = persistedRowIdentity(row, index);
|
|
1969
2106
|
if (rowKey) pendingRowsByKey.set(rowKey, row);
|
|
1970
2107
|
}
|
|
1971
|
-
|
|
2108
|
+
const pendingItems = materializedItems
|
|
1972
2109
|
.map((item, index) => ({
|
|
1973
2110
|
row: this.toOutputRow(item as Record<string, unknown>),
|
|
1974
2111
|
index,
|
|
@@ -1981,8 +2118,13 @@ export class PlayContextImpl {
|
|
|
1981
2118
|
// the sheet round-trip. Merge the persisted data/meta over the
|
|
1982
2119
|
// in-memory row so key functions and column resolvers keep seeing
|
|
1983
2120
|
// projected aliases.
|
|
1984
|
-
return
|
|
2121
|
+
return {
|
|
2122
|
+
row: persisted ? cloneCsvAliasedRow(row, persisted) : row,
|
|
2123
|
+
index,
|
|
2124
|
+
};
|
|
1985
2125
|
});
|
|
2126
|
+
itemsToProcess = pendingItems.map((item) => item.row);
|
|
2127
|
+
itemOriginalIndexes = pendingItems.map((item) => item.index);
|
|
1986
2128
|
if (mapStartResult.completedRows.length > 0) {
|
|
1987
2129
|
completedItemsByKey = new Map();
|
|
1988
2130
|
for (
|
|
@@ -2008,7 +2150,7 @@ export class PlayContextImpl {
|
|
|
2008
2150
|
const completedRowKeys =
|
|
2009
2151
|
completedItemsByKey != null ? [...completedItemsByKey.keys()] : [];
|
|
2010
2152
|
const pendingRowKeys = itemsToProcess.map((item, index) =>
|
|
2011
|
-
rowIdentity(this.toOutputRow(item), index),
|
|
2153
|
+
rowIdentity(this.toOutputRow(item), itemOriginalIndexes[index] ?? index),
|
|
2012
2154
|
);
|
|
2013
2155
|
this.setMapFrame({
|
|
2014
2156
|
mapInvocationId: mapScope.mapInvocationId,
|
|
@@ -2040,9 +2182,10 @@ export class PlayContextImpl {
|
|
|
2040
2182
|
>();
|
|
2041
2183
|
for (let index = 0; index < itemsToProcess.length; index += 1) {
|
|
2042
2184
|
const row = itemsToProcess[index]!;
|
|
2043
|
-
const
|
|
2185
|
+
const originalIndex = itemOriginalIndexes[index] ?? index;
|
|
2186
|
+
const rowKey = rowIdentity(row, originalIndex);
|
|
2044
2187
|
if (!rowsToExecuteByKey.has(rowKey)) {
|
|
2045
|
-
rowsToExecuteByKey.set(rowKey, { row, originalIndex
|
|
2188
|
+
rowsToExecuteByKey.set(rowKey, { row, originalIndex });
|
|
2046
2189
|
}
|
|
2047
2190
|
}
|
|
2048
2191
|
const rowsToExecuteEntries = [...rowsToExecuteByKey.entries()].map(
|
|
@@ -2090,6 +2233,9 @@ export class PlayContextImpl {
|
|
|
2090
2233
|
}
|
|
2091
2234
|
await flushChunk();
|
|
2092
2235
|
};
|
|
2236
|
+
const incrementalPersistence = this.#options.onMapRowsCompleted
|
|
2237
|
+
? createIncrementalMapRowPersistence(persistMapRows)
|
|
2238
|
+
: null;
|
|
2093
2239
|
|
|
2094
2240
|
let mapResult: FieldMapRunResult;
|
|
2095
2241
|
try {
|
|
@@ -2108,6 +2254,7 @@ export class PlayContextImpl {
|
|
|
2108
2254
|
executionRowIndexes: rowsToExecuteEntries.map(
|
|
2109
2255
|
(entry) => entry.originalIndex,
|
|
2110
2256
|
),
|
|
2257
|
+
incrementalPersistence,
|
|
2111
2258
|
},
|
|
2112
2259
|
);
|
|
2113
2260
|
} catch (error) {
|
|
@@ -2116,11 +2263,17 @@ export class PlayContextImpl {
|
|
|
2116
2263
|
error.completedRows.length > 0
|
|
2117
2264
|
? error.completedRows
|
|
2118
2265
|
: error.failedRows;
|
|
2266
|
+
await incrementalPersistence?.flush();
|
|
2267
|
+
const unpersistedRows = incrementalPersistence
|
|
2268
|
+
? rowsToPersist.filter(
|
|
2269
|
+
(row) => !incrementalPersistence.isPersisted(row),
|
|
2270
|
+
)
|
|
2271
|
+
: rowsToPersist;
|
|
2119
2272
|
const persistStartedAt = Date.now();
|
|
2120
|
-
await persistMapRows(
|
|
2121
|
-
if (
|
|
2273
|
+
await persistMapRows(unpersistedRows);
|
|
2274
|
+
if (unpersistedRows.length > 0) {
|
|
2122
2275
|
this.log(
|
|
2123
|
-
`Persisted ${
|
|
2276
|
+
`Persisted ${unpersistedRows.length} fail-fast rows to sheet ${resolvedTableNamespace} in ${Date.now() - persistStartedAt}ms`,
|
|
2124
2277
|
);
|
|
2125
2278
|
}
|
|
2126
2279
|
this.activeMapCellMeta = null;
|
|
@@ -2164,9 +2317,11 @@ export class PlayContextImpl {
|
|
|
2164
2317
|
// source of truth, not this in-memory results array. Chunked by rows AND
|
|
2165
2318
|
// bytes so large cells (scraped pages) never produce oversized writes.
|
|
2166
2319
|
if (resultsByKey.size > 0 || mapResult.failedRows.length > 0) {
|
|
2320
|
+
await incrementalPersistence?.flush();
|
|
2167
2321
|
const mapCellMeta = this.activeMapCellMeta;
|
|
2168
2322
|
const persistRows: PersistableMapRow[] = [];
|
|
2169
2323
|
for (const row of mapResult.completedRows) {
|
|
2324
|
+
if (incrementalPersistence?.isPersisted(row)) continue;
|
|
2170
2325
|
const rowKey = row.key;
|
|
2171
2326
|
const meta = mapCellMeta?.get(rowKey);
|
|
2172
2327
|
persistRows.push({
|
|
@@ -2178,12 +2333,18 @@ export class PlayContextImpl {
|
|
|
2178
2333
|
},
|
|
2179
2334
|
});
|
|
2180
2335
|
}
|
|
2181
|
-
persistRows.push(
|
|
2336
|
+
persistRows.push(
|
|
2337
|
+
...mapResult.failedRows.filter(
|
|
2338
|
+
(row) => !incrementalPersistence?.isPersisted(row),
|
|
2339
|
+
),
|
|
2340
|
+
);
|
|
2182
2341
|
const persistStartedAt = Date.now();
|
|
2183
2342
|
await persistMapRows(persistRows);
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2343
|
+
if (persistRows.length > 0) {
|
|
2344
|
+
this.log(
|
|
2345
|
+
`Persisted ${persistRows.length} executed rows to sheet ${resolvedTableNamespace} in ${Date.now() - persistStartedAt}ms`,
|
|
2346
|
+
);
|
|
2347
|
+
}
|
|
2187
2348
|
}
|
|
2188
2349
|
this.activeMapCellMeta = null;
|
|
2189
2350
|
|
|
@@ -2255,6 +2416,7 @@ export class PlayContextImpl {
|
|
|
2255
2416
|
* want to throttle a wide map.
|
|
2256
2417
|
*/
|
|
2257
2418
|
concurrency?: number;
|
|
2419
|
+
incrementalPersistence?: IncrementalMapRowPersistence | null;
|
|
2258
2420
|
},
|
|
2259
2421
|
): Promise<FieldMapRunResult> {
|
|
2260
2422
|
const fieldEntries = Object.entries(definition);
|
|
@@ -2299,6 +2461,14 @@ export class PlayContextImpl {
|
|
|
2299
2461
|
const failFastOnRowError = runtimeOptions?.onRowError === 'fail';
|
|
2300
2462
|
const completedRowsToPersist: PersistableMapRow[] = [];
|
|
2301
2463
|
const failedRowsToPersist: PersistableMapRow[] = [];
|
|
2464
|
+
const incrementalPersistence =
|
|
2465
|
+
runtimeOptions?.incrementalPersistence ?? null;
|
|
2466
|
+
const enqueueIncrementalPersist = (row: PersistableMapRow): void => {
|
|
2467
|
+
void incrementalPersistence?.persistRows([row]).catch(() => {
|
|
2468
|
+
// The final map-level flush awaits the same chain and surfaces the
|
|
2469
|
+
// persistence failure loudly without holding a completed row slot open.
|
|
2470
|
+
});
|
|
2471
|
+
};
|
|
2302
2472
|
|
|
2303
2473
|
if (completedRows > 0 || pendingRows !== totalRows) {
|
|
2304
2474
|
this.log(
|
|
@@ -2605,7 +2775,7 @@ export class PlayContextImpl {
|
|
|
2605
2775
|
: {},
|
|
2606
2776
|
});
|
|
2607
2777
|
if (failFastOnRowError) {
|
|
2608
|
-
|
|
2778
|
+
const failedRow: PersistableMapRow = {
|
|
2609
2779
|
key: rowKey,
|
|
2610
2780
|
inputIndex: rowIndex,
|
|
2611
2781
|
data: this.toPersistedOutputRow(
|
|
@@ -2616,21 +2786,23 @@ export class PlayContextImpl {
|
|
|
2616
2786
|
: {}),
|
|
2617
2787
|
status: 'failed',
|
|
2618
2788
|
error: formattedError,
|
|
2619
|
-
}
|
|
2789
|
+
};
|
|
2790
|
+
failedRowsToPersist.push(failedRow);
|
|
2620
2791
|
throw error;
|
|
2621
2792
|
}
|
|
2622
2793
|
const failedData = this.toPersistedOutputRow(
|
|
2623
2794
|
cloneCsvAliasedRow(baseRow, computedFields),
|
|
2624
2795
|
);
|
|
2625
2796
|
const cellMetaPatch = this.activeMapCellMeta?.get(rowKey);
|
|
2626
|
-
|
|
2797
|
+
const failedRow: PersistableMapRow = {
|
|
2627
2798
|
key: rowKey,
|
|
2628
2799
|
inputIndex: rowIndex,
|
|
2629
2800
|
data: failedData,
|
|
2630
2801
|
...(cellMetaPatch ? { cellMetaPatch } : {}),
|
|
2631
2802
|
status: 'failed',
|
|
2632
2803
|
error: formattedError,
|
|
2633
|
-
}
|
|
2804
|
+
};
|
|
2805
|
+
failedRowsToPersist.push(failedRow);
|
|
2634
2806
|
updateMapFrameProgress({
|
|
2635
2807
|
failedRowKey: rowKey,
|
|
2636
2808
|
});
|
|
@@ -2642,6 +2814,7 @@ export class PlayContextImpl {
|
|
|
2642
2814
|
error: formattedError,
|
|
2643
2815
|
dataPatch: {},
|
|
2644
2816
|
});
|
|
2817
|
+
enqueueIncrementalPersist(failedRow);
|
|
2645
2818
|
return FAILED_ROW;
|
|
2646
2819
|
}
|
|
2647
2820
|
const cellValue = this.serializeCellValue(value);
|
|
@@ -2682,14 +2855,16 @@ export class PlayContextImpl {
|
|
|
2682
2855
|
dataPatch: {},
|
|
2683
2856
|
});
|
|
2684
2857
|
const publicRow = this.toPublicOutputRow(merged);
|
|
2685
|
-
|
|
2858
|
+
const completedRow: PersistableMapRow = {
|
|
2686
2859
|
key: rowKey,
|
|
2687
2860
|
inputIndex: rowIndex,
|
|
2688
2861
|
data: this.toPersistedOutputRow(merged),
|
|
2689
2862
|
...(this.activeMapCellMeta?.get(rowKey)
|
|
2690
2863
|
? { cellMetaPatch: this.activeMapCellMeta.get(rowKey) }
|
|
2691
2864
|
: {}),
|
|
2692
|
-
}
|
|
2865
|
+
};
|
|
2866
|
+
completedRowsToPersist.push(completedRow);
|
|
2867
|
+
enqueueIncrementalPersist(completedRow);
|
|
2693
2868
|
return publicRow;
|
|
2694
2869
|
} catch (error) {
|
|
2695
2870
|
if (isPlayRowExecutionSuspendedError(error)) {
|
|
@@ -2807,6 +2982,7 @@ export class PlayContextImpl {
|
|
|
2807
2982
|
).values(),
|
|
2808
2983
|
];
|
|
2809
2984
|
this.pendingRowEventBoundaries = [];
|
|
2985
|
+
await incrementalPersistence?.flush();
|
|
2810
2986
|
this.#options.onBatchComplete?.(this.checkpoint);
|
|
2811
2987
|
throw new PlayExecutionSuspendedError({
|
|
2812
2988
|
kind: 'integration_event_batch',
|
|
@@ -4960,7 +5136,42 @@ export class PlayContextImpl {
|
|
|
4960
5136
|
[...byTool.entries()].map(async ([toolId, requests]) => {
|
|
4961
5137
|
this.log(`Executing tool batch ${toolId}: ${requests.length} calls`);
|
|
4962
5138
|
|
|
5139
|
+
const recordToolStep = (stepRequests: ToolCallRequest[]): void => {
|
|
5140
|
+
if (stepRequests.length === 0) return;
|
|
5141
|
+
const stepResults: PlayStepRowResult[] = stepRequests.map((req) => {
|
|
5142
|
+
const cachedResult = this.getCachedToolResult(
|
|
5143
|
+
toolId,
|
|
5144
|
+
this.buildToolResultCacheKey({
|
|
5145
|
+
rowId: req.rowId,
|
|
5146
|
+
tableNamespace: req.tableNamespace,
|
|
5147
|
+
rowKey: req.rowKey ?? undefined,
|
|
5148
|
+
callId: req.callId,
|
|
5149
|
+
}),
|
|
5150
|
+
);
|
|
5151
|
+
return {
|
|
5152
|
+
rowId: req.rowId,
|
|
5153
|
+
status: cachedResult?.result != null ? 'completed' : 'failed',
|
|
5154
|
+
success: cachedResult?.result != null,
|
|
5155
|
+
value: cachedResult?.result,
|
|
5156
|
+
error: cachedResult?.result != null ? null : 'Tool call failed',
|
|
5157
|
+
};
|
|
5158
|
+
});
|
|
5159
|
+
const toolStep = {
|
|
5160
|
+
type: 'tool' as const,
|
|
5161
|
+
toolId,
|
|
5162
|
+
// Keep the step trace preview-sized for large map pages.
|
|
5163
|
+
results: compactRowResultsPreview(stepResults),
|
|
5164
|
+
description: normalizeStepDescription(stepRequests[0]?.description),
|
|
5165
|
+
};
|
|
5166
|
+
if (this.activeDatasetStep) {
|
|
5167
|
+
this.activeDatasetStep.substeps.push(toolStep);
|
|
5168
|
+
} else {
|
|
5169
|
+
this.steps.push(toolStep);
|
|
5170
|
+
}
|
|
5171
|
+
};
|
|
5172
|
+
|
|
4963
5173
|
const pendingRequests: ToolCallRequest[] = [];
|
|
5174
|
+
const recoveredRequests: ToolCallRequest[] = [];
|
|
4964
5175
|
for (const req of requests) {
|
|
4965
5176
|
const cached = this.getCachedToolResult(
|
|
4966
5177
|
toolId,
|
|
@@ -4978,10 +5189,12 @@ export class PlayContextImpl {
|
|
|
4978
5189
|
resolver.resolve(cached.result);
|
|
4979
5190
|
this.toolCallResolvers.delete(req.callId);
|
|
4980
5191
|
}
|
|
5192
|
+
recoveredRequests.push(req);
|
|
4981
5193
|
} else {
|
|
4982
5194
|
pendingRequests.push(req);
|
|
4983
5195
|
}
|
|
4984
5196
|
}
|
|
5197
|
+
recordToolStep(recoveredRequests);
|
|
4985
5198
|
|
|
4986
5199
|
if (pendingRequests.length > 0) {
|
|
4987
5200
|
const strategy =
|
|
@@ -5001,49 +5214,47 @@ export class PlayContextImpl {
|
|
|
5001
5214
|
4,
|
|
5002
5215
|
)
|
|
5003
5216
|
: 4;
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
chunk.map((batch) =>
|
|
5012
|
-
this.callToolAPI(batch.batchOperation, batch.batchPayload),
|
|
5217
|
+
await executeChunkedRequests({
|
|
5218
|
+
requests: compiledBatches,
|
|
5219
|
+
batchSize,
|
|
5220
|
+
execute: async (batch) =>
|
|
5221
|
+
await this.callToolAPI(
|
|
5222
|
+
batch.batchOperation,
|
|
5223
|
+
batch.batchPayload,
|
|
5013
5224
|
),
|
|
5014
|
-
)
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5225
|
+
onChunkComplete: async (chunkResults) => {
|
|
5226
|
+
for (const entry of chunkResults) {
|
|
5227
|
+
if (entry.error !== undefined) {
|
|
5228
|
+
for (const request of entry.request.memberRequests) {
|
|
5229
|
+
this.rejectToolCall(toolId, request, entry.error);
|
|
5230
|
+
}
|
|
5231
|
+
continue;
|
|
5232
|
+
}
|
|
5020
5233
|
const splitResults =
|
|
5021
|
-
|
|
5022
|
-
?
|
|
5023
|
-
:
|
|
5234
|
+
entry.result != null
|
|
5235
|
+
? entry.request.splitResults(entry.result)
|
|
5236
|
+
: entry.request.memberRequests.map(() => null);
|
|
5024
5237
|
|
|
5025
5238
|
for (
|
|
5026
5239
|
let index = 0;
|
|
5027
|
-
index <
|
|
5240
|
+
index < entry.request.memberRequests.length;
|
|
5028
5241
|
index += 1
|
|
5029
5242
|
) {
|
|
5030
|
-
const request =
|
|
5243
|
+
const request = entry.request.memberRequests[index]!;
|
|
5031
5244
|
await this.resolveToolCall(
|
|
5032
5245
|
toolId,
|
|
5033
5246
|
request,
|
|
5034
5247
|
splitResults[index] ?? null,
|
|
5035
5248
|
);
|
|
5036
5249
|
}
|
|
5037
|
-
continue;
|
|
5038
5250
|
}
|
|
5039
5251
|
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
}
|
|
5252
|
+
recordToolStep(
|
|
5253
|
+
chunkResults.flatMap((entry) => entry.request.memberRequests),
|
|
5254
|
+
);
|
|
5255
|
+
this.#options.onBatchComplete?.(this.checkpoint);
|
|
5256
|
+
},
|
|
5257
|
+
});
|
|
5047
5258
|
} else {
|
|
5048
5259
|
const batchSize = await this.governor.suggestedParallelism(
|
|
5049
5260
|
toolId,
|
|
@@ -5055,66 +5266,32 @@ export class PlayContextImpl {
|
|
|
5055
5266
|
start += batchSize
|
|
5056
5267
|
) {
|
|
5057
5268
|
const chunk = pendingRequests.slice(start, start + batchSize);
|
|
5058
|
-
|
|
5059
|
-
chunk.map((request) =>
|
|
5060
|
-
|
|
5061
|
-
|
|
5269
|
+
await Promise.allSettled(
|
|
5270
|
+
chunk.map(async (request) => {
|
|
5271
|
+
try {
|
|
5272
|
+
const execution = await this.callToolExecutionAPI(
|
|
5273
|
+
toolId,
|
|
5274
|
+
request.input,
|
|
5275
|
+
);
|
|
5276
|
+
await this.resolveToolCall(
|
|
5277
|
+
toolId,
|
|
5278
|
+
request,
|
|
5279
|
+
execution?.result ?? null,
|
|
5280
|
+
execution?.metadata ?? null,
|
|
5281
|
+
execution?.jobId,
|
|
5282
|
+
execution?.meta,
|
|
5283
|
+
);
|
|
5284
|
+
} catch (error) {
|
|
5285
|
+
this.rejectToolCall(toolId, request, error);
|
|
5286
|
+
}
|
|
5287
|
+
}),
|
|
5062
5288
|
);
|
|
5063
5289
|
|
|
5064
|
-
|
|
5065
|
-
const request = chunk[index]!;
|
|
5066
|
-
const outcome = settled[index]!;
|
|
5067
|
-
if (outcome.status === 'fulfilled') {
|
|
5068
|
-
await this.resolveToolCall(
|
|
5069
|
-
toolId,
|
|
5070
|
-
request,
|
|
5071
|
-
outcome.value?.result ?? null,
|
|
5072
|
-
outcome.value?.metadata ?? null,
|
|
5073
|
-
outcome.value?.jobId,
|
|
5074
|
-
outcome.value?.meta,
|
|
5075
|
-
);
|
|
5076
|
-
continue;
|
|
5077
|
-
}
|
|
5078
|
-
|
|
5079
|
-
this.rejectToolCall(toolId, request, outcome.reason);
|
|
5080
|
-
}
|
|
5081
|
-
|
|
5290
|
+
recordToolStep(chunk);
|
|
5082
5291
|
this.#options.onBatchComplete?.(this.checkpoint);
|
|
5083
5292
|
}
|
|
5084
5293
|
}
|
|
5085
5294
|
}
|
|
5086
|
-
|
|
5087
|
-
// Record step — nest under map if inside one
|
|
5088
|
-
const stepResults: PlayStepRowResult[] = requests.map((req) => {
|
|
5089
|
-
const cachedResult = this.getCachedToolResult(
|
|
5090
|
-
toolId,
|
|
5091
|
-
this.buildToolResultCacheKey({
|
|
5092
|
-
rowId: req.rowId,
|
|
5093
|
-
tableNamespace: req.tableNamespace,
|
|
5094
|
-
rowKey: req.rowKey ?? undefined,
|
|
5095
|
-
callId: req.callId,
|
|
5096
|
-
}),
|
|
5097
|
-
);
|
|
5098
|
-
return {
|
|
5099
|
-
rowId: req.rowId,
|
|
5100
|
-
status: cachedResult?.result != null ? 'completed' : 'failed',
|
|
5101
|
-
success: cachedResult?.result != null,
|
|
5102
|
-
value: cachedResult?.result,
|
|
5103
|
-
error: cachedResult?.result != null ? null : 'Tool call failed',
|
|
5104
|
-
};
|
|
5105
|
-
});
|
|
5106
|
-
const toolStep = {
|
|
5107
|
-
type: 'tool' as const,
|
|
5108
|
-
toolId,
|
|
5109
|
-
// Keep the step trace preview-sized for large map pages.
|
|
5110
|
-
results: compactRowResultsPreview(stepResults),
|
|
5111
|
-
description: normalizeStepDescription(requests[0]?.description),
|
|
5112
|
-
};
|
|
5113
|
-
if (this.activeDatasetStep) {
|
|
5114
|
-
this.activeDatasetStep.substeps.push(toolStep);
|
|
5115
|
-
} else {
|
|
5116
|
-
this.steps.push(toolStep);
|
|
5117
|
-
}
|
|
5118
5295
|
}),
|
|
5119
5296
|
);
|
|
5120
5297
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -413,10 +413,10 @@ var SDK_RELEASE = {
|
|
|
413
413
|
// 0.1.108 ships explicit dataset column/tool recompute policy and removes
|
|
414
414
|
// the SDK enrich generator's one-second stale policy.
|
|
415
415
|
// 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
|
|
416
|
-
version: "0.1.
|
|
416
|
+
version: "0.1.132",
|
|
417
417
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
418
418
|
supportPolicy: {
|
|
419
|
-
latest: "0.1.
|
|
419
|
+
latest: "0.1.132",
|
|
420
420
|
minimumSupported: "0.1.53",
|
|
421
421
|
deprecatedBelow: "0.1.53",
|
|
422
422
|
commandMinimumSupported: [
|
|
@@ -5027,8 +5027,14 @@ function recentUsageLines(entries) {
|
|
|
5027
5027
|
const op = `${humanize(entry.provider)} ${humanize(entry.operation)}`.trim();
|
|
5028
5028
|
const charge = entry.billing_mode === "no_bill" ? "free" : `${entry.credits ?? 0} cr`;
|
|
5029
5029
|
const state = entry.charge_state === "temporary_hold" ? "temporary hold, awaiting actual usage" : entry.status || "completed";
|
|
5030
|
+
const auditBits = [
|
|
5031
|
+
entry.outcome ? `outcome=${entry.outcome}` : null,
|
|
5032
|
+
entry.pricing_basis ? `priced_by=${entry.pricing_basis}` : null,
|
|
5033
|
+
entry.run_id ? `run=${entry.run_id}` : null,
|
|
5034
|
+
entry.request_id ? `request=${entry.request_id}` : null
|
|
5035
|
+
].filter(Boolean);
|
|
5030
5036
|
lines.push(
|
|
5031
|
-
`${op} | ${charge} | ${state} | ${entry.created_at || "unknown"}`
|
|
5037
|
+
`${op} | ${charge} | ${state}${auditBits.length > 0 ? ` | ${auditBits.join(" | ")}` : ""} | ${entry.created_at || "unknown"}`
|
|
5032
5038
|
);
|
|
5033
5039
|
}
|
|
5034
5040
|
return lines;
|
|
@@ -5045,14 +5051,24 @@ function summarizeLedgerRows(summary, rows) {
|
|
|
5045
5051
|
}
|
|
5046
5052
|
function ledgerApiEntryToRow(entry) {
|
|
5047
5053
|
const metadata = typeof entry.metadata === "object" && entry.metadata !== null ? entry.metadata : {};
|
|
5054
|
+
const audit = typeof entry.billing_audit === "object" && entry.billing_audit !== null ? entry.billing_audit : {};
|
|
5048
5055
|
return {
|
|
5049
5056
|
created_at: entry.created_at ?? "",
|
|
5050
5057
|
delta_credits: entry.delta ?? "",
|
|
5051
5058
|
reason: entry.reason ?? "",
|
|
5052
|
-
provider: metadata.provider ?? "",
|
|
5053
|
-
operation: metadata.operation ?? "",
|
|
5054
|
-
request_id: metadata.requestId ?? metadata.request_id ?? "",
|
|
5055
|
-
run_id: metadata.runId ?? metadata.run_id ?? "",
|
|
5059
|
+
provider: entry.provider ?? audit.provider ?? metadata.provider ?? "",
|
|
5060
|
+
operation: entry.operation ?? audit.operation ?? metadata.operation ?? "",
|
|
5061
|
+
request_id: entry.request_id ?? audit.request_id ?? metadata.requestId ?? metadata.request_id ?? "",
|
|
5062
|
+
run_id: entry.run_id ?? audit.run_id ?? metadata.runId ?? metadata.run_id ?? "",
|
|
5063
|
+
billing_stage: entry.billing_stage ?? audit.billing_stage ?? metadata.billingStage ?? "",
|
|
5064
|
+
charge_state: entry.charge_state ?? audit.charge_state ?? "",
|
|
5065
|
+
billing_mode: entry.billing_mode ?? audit.billing_mode ?? metadata.billingMode ?? metadata.chargeMode ?? "",
|
|
5066
|
+
pricing_model: entry.pricing_model ?? audit.pricing_model ?? metadata.pricingModel ?? "",
|
|
5067
|
+
pricing_basis: entry.pricing_basis ?? audit.pricing_basis ?? "",
|
|
5068
|
+
charge_credits: entry.charge_credits ?? audit.charge_credits ?? "",
|
|
5069
|
+
outcome: entry.outcome ?? audit.outcome ?? "",
|
|
5070
|
+
result_count: entry.result_count ?? audit.result_count ?? "",
|
|
5071
|
+
deepline_rough_usd: entry.deepline_rough_usd ?? "",
|
|
5056
5072
|
api_key_id: entry.api_key_id ?? "",
|
|
5057
5073
|
stripe_session_id: entry.stripe_session_id ?? ""
|
|
5058
5074
|
};
|
|
@@ -5068,6 +5084,15 @@ function ledgerRowsToCsv(rows, header) {
|
|
|
5068
5084
|
"operation",
|
|
5069
5085
|
"request_id",
|
|
5070
5086
|
"run_id",
|
|
5087
|
+
"billing_stage",
|
|
5088
|
+
"charge_state",
|
|
5089
|
+
"billing_mode",
|
|
5090
|
+
"pricing_model",
|
|
5091
|
+
"pricing_basis",
|
|
5092
|
+
"charge_credits",
|
|
5093
|
+
"outcome",
|
|
5094
|
+
"result_count",
|
|
5095
|
+
"deepline_rough_usd",
|
|
5071
5096
|
"api_key_id",
|
|
5072
5097
|
"stripe_session_id"
|
|
5073
5098
|
]
|
|
@@ -5246,6 +5271,7 @@ async function handleLedgerExportAll(options) {
|
|
|
5246
5271
|
for (; ; ) {
|
|
5247
5272
|
const params = new URLSearchParams({ limit: "5000" });
|
|
5248
5273
|
if (cursor !== null) params.set("cursor", cursor);
|
|
5274
|
+
if (options.runId) params.set("run_id", options.runId);
|
|
5249
5275
|
const payload = await http.get(
|
|
5250
5276
|
`/api/v2/billing/ledger?${params.toString()}`
|
|
5251
5277
|
);
|
|
@@ -5273,13 +5299,14 @@ async function handleLedgerExportAll(options) {
|
|
|
5273
5299
|
row_count: summary.row_count,
|
|
5274
5300
|
net_delta_credits: summary.net_delta_credits,
|
|
5275
5301
|
scope: "current_auth_context",
|
|
5302
|
+
...options.runId ? { run_id: options.runId } : {},
|
|
5276
5303
|
render: {
|
|
5277
5304
|
sections: [
|
|
5278
5305
|
{
|
|
5279
5306
|
title: "billing ledger",
|
|
5280
5307
|
lines: [
|
|
5281
5308
|
`Billing ledger written to ${outputPath}`,
|
|
5282
|
-
`${summary.row_count} row(s) exported for the current auth context.`,
|
|
5309
|
+
`${summary.row_count} row(s) exported for the current auth context${options.runId ? ` and run ${options.runId}` : ""}.`,
|
|
5283
5310
|
`Net ledger delta: ${summary.net_delta_credits} Deepline Credits`
|
|
5284
5311
|
]
|
|
5285
5312
|
}
|
|
@@ -5703,6 +5730,7 @@ Notes:
|
|
|
5703
5730
|
Examples:
|
|
5704
5731
|
deepline billing ledger export all
|
|
5705
5732
|
deepline billing ledger export all --output ./ledger.csv
|
|
5733
|
+
deepline billing ledger export all --run-id play/demo/run/abc123
|
|
5706
5734
|
deepline billing ledger export all --json
|
|
5707
5735
|
`
|
|
5708
5736
|
).addCommand(
|
|
@@ -5724,7 +5752,7 @@ Examples:
|
|
|
5724
5752
|
deepline billing ledger export all
|
|
5725
5753
|
deepline billing ledger export all --json
|
|
5726
5754
|
`
|
|
5727
|
-
).option("--output <path>", "Write CSV to an explicit path").option(
|
|
5755
|
+
).option("--output <path>", "Write CSV to an explicit path").option("--run-id <run_id>", "Export ledger rows for one play run.").option(
|
|
5728
5756
|
"--json",
|
|
5729
5757
|
"Emit JSON output. Also automatic when stdout is piped"
|
|
5730
5758
|
).action(handleLedgerExportAll)
|
package/dist/cli/index.mjs
CHANGED
|
@@ -390,10 +390,10 @@ var SDK_RELEASE = {
|
|
|
390
390
|
// 0.1.108 ships explicit dataset column/tool recompute policy and removes
|
|
391
391
|
// the SDK enrich generator's one-second stale policy.
|
|
392
392
|
// 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
|
|
393
|
-
version: "0.1.
|
|
393
|
+
version: "0.1.132",
|
|
394
394
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
395
395
|
supportPolicy: {
|
|
396
|
-
latest: "0.1.
|
|
396
|
+
latest: "0.1.132",
|
|
397
397
|
minimumSupported: "0.1.53",
|
|
398
398
|
deprecatedBelow: "0.1.53",
|
|
399
399
|
commandMinimumSupported: [
|
|
@@ -5016,8 +5016,14 @@ function recentUsageLines(entries) {
|
|
|
5016
5016
|
const op = `${humanize(entry.provider)} ${humanize(entry.operation)}`.trim();
|
|
5017
5017
|
const charge = entry.billing_mode === "no_bill" ? "free" : `${entry.credits ?? 0} cr`;
|
|
5018
5018
|
const state = entry.charge_state === "temporary_hold" ? "temporary hold, awaiting actual usage" : entry.status || "completed";
|
|
5019
|
+
const auditBits = [
|
|
5020
|
+
entry.outcome ? `outcome=${entry.outcome}` : null,
|
|
5021
|
+
entry.pricing_basis ? `priced_by=${entry.pricing_basis}` : null,
|
|
5022
|
+
entry.run_id ? `run=${entry.run_id}` : null,
|
|
5023
|
+
entry.request_id ? `request=${entry.request_id}` : null
|
|
5024
|
+
].filter(Boolean);
|
|
5019
5025
|
lines.push(
|
|
5020
|
-
`${op} | ${charge} | ${state} | ${entry.created_at || "unknown"}`
|
|
5026
|
+
`${op} | ${charge} | ${state}${auditBits.length > 0 ? ` | ${auditBits.join(" | ")}` : ""} | ${entry.created_at || "unknown"}`
|
|
5021
5027
|
);
|
|
5022
5028
|
}
|
|
5023
5029
|
return lines;
|
|
@@ -5034,14 +5040,24 @@ function summarizeLedgerRows(summary, rows) {
|
|
|
5034
5040
|
}
|
|
5035
5041
|
function ledgerApiEntryToRow(entry) {
|
|
5036
5042
|
const metadata = typeof entry.metadata === "object" && entry.metadata !== null ? entry.metadata : {};
|
|
5043
|
+
const audit = typeof entry.billing_audit === "object" && entry.billing_audit !== null ? entry.billing_audit : {};
|
|
5037
5044
|
return {
|
|
5038
5045
|
created_at: entry.created_at ?? "",
|
|
5039
5046
|
delta_credits: entry.delta ?? "",
|
|
5040
5047
|
reason: entry.reason ?? "",
|
|
5041
|
-
provider: metadata.provider ?? "",
|
|
5042
|
-
operation: metadata.operation ?? "",
|
|
5043
|
-
request_id: metadata.requestId ?? metadata.request_id ?? "",
|
|
5044
|
-
run_id: metadata.runId ?? metadata.run_id ?? "",
|
|
5048
|
+
provider: entry.provider ?? audit.provider ?? metadata.provider ?? "",
|
|
5049
|
+
operation: entry.operation ?? audit.operation ?? metadata.operation ?? "",
|
|
5050
|
+
request_id: entry.request_id ?? audit.request_id ?? metadata.requestId ?? metadata.request_id ?? "",
|
|
5051
|
+
run_id: entry.run_id ?? audit.run_id ?? metadata.runId ?? metadata.run_id ?? "",
|
|
5052
|
+
billing_stage: entry.billing_stage ?? audit.billing_stage ?? metadata.billingStage ?? "",
|
|
5053
|
+
charge_state: entry.charge_state ?? audit.charge_state ?? "",
|
|
5054
|
+
billing_mode: entry.billing_mode ?? audit.billing_mode ?? metadata.billingMode ?? metadata.chargeMode ?? "",
|
|
5055
|
+
pricing_model: entry.pricing_model ?? audit.pricing_model ?? metadata.pricingModel ?? "",
|
|
5056
|
+
pricing_basis: entry.pricing_basis ?? audit.pricing_basis ?? "",
|
|
5057
|
+
charge_credits: entry.charge_credits ?? audit.charge_credits ?? "",
|
|
5058
|
+
outcome: entry.outcome ?? audit.outcome ?? "",
|
|
5059
|
+
result_count: entry.result_count ?? audit.result_count ?? "",
|
|
5060
|
+
deepline_rough_usd: entry.deepline_rough_usd ?? "",
|
|
5045
5061
|
api_key_id: entry.api_key_id ?? "",
|
|
5046
5062
|
stripe_session_id: entry.stripe_session_id ?? ""
|
|
5047
5063
|
};
|
|
@@ -5057,6 +5073,15 @@ function ledgerRowsToCsv(rows, header) {
|
|
|
5057
5073
|
"operation",
|
|
5058
5074
|
"request_id",
|
|
5059
5075
|
"run_id",
|
|
5076
|
+
"billing_stage",
|
|
5077
|
+
"charge_state",
|
|
5078
|
+
"billing_mode",
|
|
5079
|
+
"pricing_model",
|
|
5080
|
+
"pricing_basis",
|
|
5081
|
+
"charge_credits",
|
|
5082
|
+
"outcome",
|
|
5083
|
+
"result_count",
|
|
5084
|
+
"deepline_rough_usd",
|
|
5060
5085
|
"api_key_id",
|
|
5061
5086
|
"stripe_session_id"
|
|
5062
5087
|
]
|
|
@@ -5235,6 +5260,7 @@ async function handleLedgerExportAll(options) {
|
|
|
5235
5260
|
for (; ; ) {
|
|
5236
5261
|
const params = new URLSearchParams({ limit: "5000" });
|
|
5237
5262
|
if (cursor !== null) params.set("cursor", cursor);
|
|
5263
|
+
if (options.runId) params.set("run_id", options.runId);
|
|
5238
5264
|
const payload = await http.get(
|
|
5239
5265
|
`/api/v2/billing/ledger?${params.toString()}`
|
|
5240
5266
|
);
|
|
@@ -5262,13 +5288,14 @@ async function handleLedgerExportAll(options) {
|
|
|
5262
5288
|
row_count: summary.row_count,
|
|
5263
5289
|
net_delta_credits: summary.net_delta_credits,
|
|
5264
5290
|
scope: "current_auth_context",
|
|
5291
|
+
...options.runId ? { run_id: options.runId } : {},
|
|
5265
5292
|
render: {
|
|
5266
5293
|
sections: [
|
|
5267
5294
|
{
|
|
5268
5295
|
title: "billing ledger",
|
|
5269
5296
|
lines: [
|
|
5270
5297
|
`Billing ledger written to ${outputPath}`,
|
|
5271
|
-
`${summary.row_count} row(s) exported for the current auth context.`,
|
|
5298
|
+
`${summary.row_count} row(s) exported for the current auth context${options.runId ? ` and run ${options.runId}` : ""}.`,
|
|
5272
5299
|
`Net ledger delta: ${summary.net_delta_credits} Deepline Credits`
|
|
5273
5300
|
]
|
|
5274
5301
|
}
|
|
@@ -5692,6 +5719,7 @@ Notes:
|
|
|
5692
5719
|
Examples:
|
|
5693
5720
|
deepline billing ledger export all
|
|
5694
5721
|
deepline billing ledger export all --output ./ledger.csv
|
|
5722
|
+
deepline billing ledger export all --run-id play/demo/run/abc123
|
|
5695
5723
|
deepline billing ledger export all --json
|
|
5696
5724
|
`
|
|
5697
5725
|
).addCommand(
|
|
@@ -5713,7 +5741,7 @@ Examples:
|
|
|
5713
5741
|
deepline billing ledger export all
|
|
5714
5742
|
deepline billing ledger export all --json
|
|
5715
5743
|
`
|
|
5716
|
-
).option("--output <path>", "Write CSV to an explicit path").option(
|
|
5744
|
+
).option("--output <path>", "Write CSV to an explicit path").option("--run-id <run_id>", "Export ledger rows for one play run.").option(
|
|
5717
5745
|
"--json",
|
|
5718
5746
|
"Emit JSON output. Also automatic when stdout is piped"
|
|
5719
5747
|
).action(handleLedgerExportAll)
|
package/dist/index.js
CHANGED
|
@@ -284,10 +284,10 @@ var SDK_RELEASE = {
|
|
|
284
284
|
// 0.1.108 ships explicit dataset column/tool recompute policy and removes
|
|
285
285
|
// the SDK enrich generator's one-second stale policy.
|
|
286
286
|
// 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
|
|
287
|
-
version: "0.1.
|
|
287
|
+
version: "0.1.132",
|
|
288
288
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
289
289
|
supportPolicy: {
|
|
290
|
-
latest: "0.1.
|
|
290
|
+
latest: "0.1.132",
|
|
291
291
|
minimumSupported: "0.1.53",
|
|
292
292
|
deprecatedBelow: "0.1.53",
|
|
293
293
|
commandMinimumSupported: [
|
package/dist/index.mjs
CHANGED
|
@@ -206,10 +206,10 @@ var SDK_RELEASE = {
|
|
|
206
206
|
// 0.1.108 ships explicit dataset column/tool recompute policy and removes
|
|
207
207
|
// the SDK enrich generator's one-second stale policy.
|
|
208
208
|
// 0.1.110 ships authored V2 prebuilts and required top-level play descriptions.
|
|
209
|
-
version: "0.1.
|
|
209
|
+
version: "0.1.132",
|
|
210
210
|
apiContract: "2026-06-dataset-column-cell-stale-hard-cutover",
|
|
211
211
|
supportPolicy: {
|
|
212
|
-
latest: "0.1.
|
|
212
|
+
latest: "0.1.132",
|
|
213
213
|
minimumSupported: "0.1.53",
|
|
214
214
|
deprecatedBelow: "0.1.53",
|
|
215
215
|
commandMinimumSupported: [
|