deepline 0.1.83 → 0.1.85
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/cli/index.js +64 -11
- package/dist/cli/index.mjs +64 -11
- package/dist/index.d.mts +230 -10
- package/dist/index.d.ts +230 -10
- package/dist/index.js +115 -2
- package/dist/index.mjs +110 -2
- package/dist/repo/apps/play-runner-workers/src/entry.ts +123 -26
- package/dist/repo/sdk/src/index.ts +11 -0
- package/dist/repo/sdk/src/play.ts +61 -5
- package/dist/repo/sdk/src/plays/harness-stub.ts +2 -1
- package/dist/repo/sdk/src/release.ts +2 -2
- package/dist/repo/sdk/src/types.ts +4 -0
- package/dist/repo/shared_libs/play-runtime/cell-staleness.ts +156 -7
- package/dist/repo/shared_libs/play-runtime/execution-plan.ts +3 -3
- package/dist/repo/shared_libs/play-runtime/extractor-targets.ts +106 -0
- package/dist/repo/shared_libs/play-runtime/providers.ts +28 -0
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +11 -0
- package/dist/repo/shared_libs/play-runtime/step-program-dataset-builder.ts +96 -6
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +82 -0
- package/dist/repo/shared_libs/plays/static-pipeline.ts +133 -24
- package/package.json +1 -1
|
@@ -1,15 +1,55 @@
|
|
|
1
|
+
import type { AuthoredStaleAfterSeconds, PreviousCell } from './cell-staleness';
|
|
2
|
+
|
|
1
3
|
export type StepProgramDatasetOptions = {
|
|
2
4
|
runIf?: (
|
|
3
5
|
row: Record<string, unknown>,
|
|
4
6
|
index: number,
|
|
5
7
|
) => boolean | Promise<boolean>;
|
|
6
|
-
staleAfterSeconds?:
|
|
8
|
+
staleAfterSeconds?: AuthoredStaleAfterSeconds;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type StepProgramDatasetColumnRunInput<Value = unknown> = {
|
|
12
|
+
row: Record<string, unknown>;
|
|
13
|
+
ctx: unknown;
|
|
14
|
+
index: number;
|
|
15
|
+
previousCell?: PreviousCell<Value>;
|
|
7
16
|
};
|
|
8
17
|
|
|
18
|
+
export type StepProgramDatasetColumnDefinition<Value = unknown> =
|
|
19
|
+
StepProgramDatasetOptions & {
|
|
20
|
+
run: (
|
|
21
|
+
input: StepProgramDatasetColumnRunInput<Value>,
|
|
22
|
+
) => Value | Promise<Value>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type StepProgramDatasetColumnInput<TResolver> =
|
|
26
|
+
| TResolver
|
|
27
|
+
| StepProgramDatasetColumnDefinition;
|
|
28
|
+
|
|
29
|
+
function isStepProgramDatasetColumnDefinition(
|
|
30
|
+
value: unknown,
|
|
31
|
+
): value is StepProgramDatasetColumnDefinition {
|
|
32
|
+
return (
|
|
33
|
+
value !== null &&
|
|
34
|
+
typeof value === 'object' &&
|
|
35
|
+
typeof (value as { run?: unknown }).run === 'function'
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
40
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isPreviousCell(value: unknown): value is PreviousCell {
|
|
44
|
+
return (
|
|
45
|
+
isRecord(value) && Object.prototype.hasOwnProperty.call(value, 'value')
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
9
49
|
export type StepProgramDatasetStep<TResolver> = {
|
|
10
50
|
name: string;
|
|
11
51
|
resolver: TResolver;
|
|
12
|
-
staleAfterSeconds?:
|
|
52
|
+
staleAfterSeconds?: AuthoredStaleAfterSeconds;
|
|
13
53
|
};
|
|
14
54
|
|
|
15
55
|
export type StepProgramDatasetProgram<TStep> = {
|
|
@@ -75,19 +115,23 @@ export class StepProgramDatasetBuilder<
|
|
|
75
115
|
|
|
76
116
|
withColumn(
|
|
77
117
|
name: string,
|
|
78
|
-
|
|
118
|
+
columnInput: StepProgramDatasetColumnInput<TResolver>,
|
|
79
119
|
options?: StepProgramDatasetOptions,
|
|
80
120
|
): this {
|
|
81
121
|
if (!name.trim()) {
|
|
82
122
|
throw new Error(this.messages.emptyColumnName);
|
|
83
123
|
}
|
|
124
|
+
const normalized = this.normalizeColumnInput(columnInput, options);
|
|
84
125
|
this.program.steps = [
|
|
85
126
|
...this.program.steps,
|
|
86
127
|
{
|
|
87
128
|
name,
|
|
88
|
-
resolver: this.applyDerivationOptions(
|
|
89
|
-
|
|
90
|
-
|
|
129
|
+
resolver: this.applyDerivationOptions(
|
|
130
|
+
normalized.resolver,
|
|
131
|
+
normalized.options,
|
|
132
|
+
),
|
|
133
|
+
...(normalized.options?.staleAfterSeconds !== undefined
|
|
134
|
+
? { staleAfterSeconds: normalized.options.staleAfterSeconds }
|
|
91
135
|
: {}),
|
|
92
136
|
} as TStep,
|
|
93
137
|
];
|
|
@@ -127,4 +171,50 @@ export class StepProgramDatasetBuilder<
|
|
|
127
171
|
elseValue: null,
|
|
128
172
|
} as TResolver;
|
|
129
173
|
}
|
|
174
|
+
|
|
175
|
+
private normalizeColumnInput(
|
|
176
|
+
columnInput: StepProgramDatasetColumnInput<TResolver>,
|
|
177
|
+
options?: StepProgramDatasetOptions,
|
|
178
|
+
): { resolver: TResolver; options?: StepProgramDatasetOptions } {
|
|
179
|
+
if (!isStepProgramDatasetColumnDefinition(columnInput)) {
|
|
180
|
+
return { resolver: columnInput, options };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const { run, ...definitionOptions } = columnInput;
|
|
184
|
+
const resolver = ((
|
|
185
|
+
row: Record<string, unknown>,
|
|
186
|
+
ctx: unknown,
|
|
187
|
+
third?: unknown,
|
|
188
|
+
fourth?: unknown,
|
|
189
|
+
fifth?: unknown,
|
|
190
|
+
) => {
|
|
191
|
+
const index =
|
|
192
|
+
typeof third === 'number'
|
|
193
|
+
? third
|
|
194
|
+
: typeof fourth === 'number'
|
|
195
|
+
? fourth
|
|
196
|
+
: 0;
|
|
197
|
+
const rowForRun =
|
|
198
|
+
isRecord(third) && typeof fourth === 'number' ? third : row;
|
|
199
|
+
const previousCell = isPreviousCell(fifth)
|
|
200
|
+
? fifth
|
|
201
|
+
: isPreviousCell(fourth)
|
|
202
|
+
? fourth
|
|
203
|
+
: undefined;
|
|
204
|
+
return run({
|
|
205
|
+
row: rowForRun,
|
|
206
|
+
ctx,
|
|
207
|
+
index,
|
|
208
|
+
...(previousCell ? { previousCell } : {}),
|
|
209
|
+
});
|
|
210
|
+
}) as TResolver;
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
resolver,
|
|
214
|
+
options: {
|
|
215
|
+
...definitionOptions,
|
|
216
|
+
...(options ?? {}),
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
}
|
|
130
220
|
}
|
|
@@ -18,6 +18,11 @@ export type {
|
|
|
18
18
|
} from './email-status';
|
|
19
19
|
|
|
20
20
|
import { buildEmailStatus } from './email-status';
|
|
21
|
+
import {
|
|
22
|
+
JOB_CHANGE_STATUS_VALUES,
|
|
23
|
+
type JobChangeGetterValue,
|
|
24
|
+
type JobChangeStatus,
|
|
25
|
+
} from './extractor-targets';
|
|
21
26
|
import type {
|
|
22
27
|
SerializedToolExecuteResult,
|
|
23
28
|
ToolExecuteResult,
|
|
@@ -428,6 +433,80 @@ function normalizePhoneStatus(value: unknown): unknown {
|
|
|
428
433
|
return normalized;
|
|
429
434
|
}
|
|
430
435
|
|
|
436
|
+
function normalizeJobChangeStatus(value: unknown): unknown {
|
|
437
|
+
if (typeof value === 'boolean') return value ? 'moved' : 'no_change';
|
|
438
|
+
const normalized = normalizeString(value)
|
|
439
|
+
?.toLowerCase()
|
|
440
|
+
.replace(/[\s-]+/g, '_');
|
|
441
|
+
if (!normalized) return 'unknown';
|
|
442
|
+
if (['true', 'yes', 'moved', 'changed', 'new_company'].includes(normalized)) {
|
|
443
|
+
return 'moved';
|
|
444
|
+
}
|
|
445
|
+
if (['false', 'no', 'same', 'no_change'].includes(normalized))
|
|
446
|
+
return 'no_change';
|
|
447
|
+
if (['left', 'left_company'].includes(normalized)) return 'left_company';
|
|
448
|
+
if (
|
|
449
|
+
(JOB_CHANGE_STATUS_VALUES as readonly string[]).includes(normalized)
|
|
450
|
+
) {
|
|
451
|
+
return normalized;
|
|
452
|
+
}
|
|
453
|
+
return 'unknown';
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function firstExperienceDate(value: unknown): string | null {
|
|
457
|
+
if (!Array.isArray(value)) return null;
|
|
458
|
+
for (const entry of value) {
|
|
459
|
+
if (!isRecord(entry)) continue;
|
|
460
|
+
const date = normalizeString(
|
|
461
|
+
entry.start_date ?? entry.started_at ?? entry.startDate,
|
|
462
|
+
);
|
|
463
|
+
if (date) return date;
|
|
464
|
+
}
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function normalizeJobChange(value: unknown): JobChangeGetterValue {
|
|
469
|
+
const record = isRecord(value) ? value : {};
|
|
470
|
+
const nested = isRecord(record.job_change) ? record.job_change : record;
|
|
471
|
+
const output = isRecord(nested.output) ? nested.output : nested;
|
|
472
|
+
const person = isRecord(output.person) ? output.person : {};
|
|
473
|
+
const status = normalizeJobChangeStatus(
|
|
474
|
+
output.status ??
|
|
475
|
+
output.job_change_status ??
|
|
476
|
+
output.job_changed ??
|
|
477
|
+
output.changed,
|
|
478
|
+
) as JobChangeStatus;
|
|
479
|
+
const moved = status === 'moved';
|
|
480
|
+
|
|
481
|
+
return {
|
|
482
|
+
status,
|
|
483
|
+
date: moved
|
|
484
|
+
? normalizeString(
|
|
485
|
+
output.date ??
|
|
486
|
+
output.job_change_date ??
|
|
487
|
+
output.change_date ??
|
|
488
|
+
output.changed_at,
|
|
489
|
+
) ?? firstExperienceDate(person.experiences)
|
|
490
|
+
: null,
|
|
491
|
+
new_company: moved
|
|
492
|
+
? normalizeString(
|
|
493
|
+
output.new_company ??
|
|
494
|
+
output.current_company ??
|
|
495
|
+
person.company_name ??
|
|
496
|
+
person.current_company,
|
|
497
|
+
)
|
|
498
|
+
: null,
|
|
499
|
+
new_title: moved
|
|
500
|
+
? normalizeString(
|
|
501
|
+
output.new_title ??
|
|
502
|
+
output.current_title ??
|
|
503
|
+
person.title ??
|
|
504
|
+
person.headline,
|
|
505
|
+
)
|
|
506
|
+
: null,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
|
|
431
510
|
function applyExtractorTransforms(
|
|
432
511
|
value: unknown,
|
|
433
512
|
descriptor: ToolResultExtractorDescriptor,
|
|
@@ -435,6 +514,9 @@ function applyExtractorTransforms(
|
|
|
435
514
|
return (descriptor.transforms ?? []).reduce((current, transform) => {
|
|
436
515
|
if (transform.endsWith('emailStatus')) return normalizeEmailStatus(current);
|
|
437
516
|
if (transform.endsWith('phoneStatus')) return normalizePhoneStatus(current);
|
|
517
|
+
if (transform === 'jobChange') return normalizeJobChange(current);
|
|
518
|
+
if (transform === 'jobChangeStatus')
|
|
519
|
+
return normalizeJobChangeStatus(current);
|
|
438
520
|
return current;
|
|
439
521
|
}, value);
|
|
440
522
|
}
|
|
@@ -63,6 +63,7 @@ export type PlayStaticColumnProducerKind =
|
|
|
63
63
|
| 'waterfall'
|
|
64
64
|
| 'stepProgram'
|
|
65
65
|
| 'playCall'
|
|
66
|
+
| 'controlFlow'
|
|
66
67
|
| 'transform';
|
|
67
68
|
|
|
68
69
|
export interface PlayStaticColumnProducer {
|
|
@@ -71,6 +72,7 @@ export interface PlayStaticColumnProducer {
|
|
|
71
72
|
field: string;
|
|
72
73
|
toolId?: string;
|
|
73
74
|
playId?: string;
|
|
75
|
+
dependsOnFields?: string[];
|
|
74
76
|
staleAfterSeconds?: number;
|
|
75
77
|
conditional?: boolean;
|
|
76
78
|
sourceRange?: PlayStaticSourceRange;
|
|
@@ -154,10 +156,16 @@ function truncateStaticSubstepsForStorage(
|
|
|
154
156
|
...column,
|
|
155
157
|
producers: column.producers.map((producer) => ({
|
|
156
158
|
...producer,
|
|
159
|
+
dependsOnFields: producer.dependsOnFields
|
|
160
|
+
? [...producer.dependsOnFields]
|
|
161
|
+
: undefined,
|
|
157
162
|
sourceRange: cloneStorageSafeSourceRange(producer.sourceRange),
|
|
158
163
|
steps: producer.steps
|
|
159
164
|
? producer.steps.map((stepProducer) => ({
|
|
160
165
|
...stepProducer,
|
|
166
|
+
dependsOnFields: stepProducer.dependsOnFields
|
|
167
|
+
? [...stepProducer.dependsOnFields]
|
|
168
|
+
: undefined,
|
|
161
169
|
sourceRange: cloneStorageSafeSourceRange(
|
|
162
170
|
stepProducer.sourceRange,
|
|
163
171
|
),
|
|
@@ -179,6 +187,13 @@ function truncateStaticSubstepsForStorage(
|
|
|
179
187
|
};
|
|
180
188
|
}
|
|
181
189
|
|
|
190
|
+
if (base.type === 'control_flow') {
|
|
191
|
+
return {
|
|
192
|
+
...base,
|
|
193
|
+
steps: truncateStaticSubstepsForStorage(base.steps, input),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
182
197
|
if (base.type !== 'play_call') {
|
|
183
198
|
return base;
|
|
184
199
|
}
|
|
@@ -259,6 +274,7 @@ export interface PlayStaticSourceRange {
|
|
|
259
274
|
|
|
260
275
|
type PlayStaticSubstepMetadata = {
|
|
261
276
|
conditional?: boolean;
|
|
277
|
+
dependsOnFields?: string[];
|
|
262
278
|
staleAfterSeconds?: number;
|
|
263
279
|
};
|
|
264
280
|
|
|
@@ -346,6 +362,16 @@ export type PlayStaticSubstep = PlayStaticSubstepMetadata &
|
|
|
346
362
|
callDepth?: number;
|
|
347
363
|
callPath?: string[];
|
|
348
364
|
}
|
|
365
|
+
| {
|
|
366
|
+
type: 'control_flow';
|
|
367
|
+
kind: 'conditional' | 'loop';
|
|
368
|
+
field: string;
|
|
369
|
+
steps: PlayStaticSubstep[];
|
|
370
|
+
description?: string;
|
|
371
|
+
sourceRange?: PlayStaticSourceRange;
|
|
372
|
+
callDepth?: number;
|
|
373
|
+
callPath?: string[];
|
|
374
|
+
}
|
|
349
375
|
| {
|
|
350
376
|
type: 'run_javascript';
|
|
351
377
|
alias: string;
|
|
@@ -389,7 +415,7 @@ function getRawTopLevelPipelineSubsteps(
|
|
|
389
415
|
}
|
|
390
416
|
const topLevel = [...(pipeline.stages ?? [])];
|
|
391
417
|
const tableNamespace = pipeline.tableNamespace?.trim();
|
|
392
|
-
if (pipeline.csvArg && !topLevel
|
|
418
|
+
if (pipeline.csvArg && !substepsContainType(topLevel, 'csv')) {
|
|
393
419
|
topLevel.unshift({
|
|
394
420
|
type: 'csv',
|
|
395
421
|
field: 'csv',
|
|
@@ -397,10 +423,7 @@ function getRawTopLevelPipelineSubsteps(
|
|
|
397
423
|
description: pipeline.csvDescription,
|
|
398
424
|
});
|
|
399
425
|
}
|
|
400
|
-
if (
|
|
401
|
-
tableNamespace &&
|
|
402
|
-
!topLevel.some((substep) => substep.type === 'dataset')
|
|
403
|
-
) {
|
|
426
|
+
if (tableNamespace && !substepsContainType(topLevel, 'dataset')) {
|
|
404
427
|
topLevel.push({
|
|
405
428
|
type: 'dataset',
|
|
406
429
|
field: tableNamespace,
|
|
@@ -415,6 +438,34 @@ function getRawTopLevelPipelineSubsteps(
|
|
|
415
438
|
return [...pipeline.substeps];
|
|
416
439
|
}
|
|
417
440
|
|
|
441
|
+
function substepsContainType(
|
|
442
|
+
substeps: readonly PlayStaticSubstep[],
|
|
443
|
+
type: PlayStaticSubstep['type'],
|
|
444
|
+
): boolean {
|
|
445
|
+
for (const substep of substeps) {
|
|
446
|
+
if (substep.type === type) {
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
if (
|
|
450
|
+
(substep.type === 'dataset' ||
|
|
451
|
+
substep.type === 'step_suite' ||
|
|
452
|
+
substep.type === 'control_flow') &&
|
|
453
|
+
substep.steps?.length &&
|
|
454
|
+
substepsContainType(substep.steps, type)
|
|
455
|
+
) {
|
|
456
|
+
return true;
|
|
457
|
+
}
|
|
458
|
+
if (
|
|
459
|
+
substep.type === 'play_call' &&
|
|
460
|
+
substep.pipeline &&
|
|
461
|
+
substepsContainType(getCompiledPipelineSubsteps(substep.pipeline), type)
|
|
462
|
+
) {
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
|
|
418
469
|
export function flattenStaticSubsteps(
|
|
419
470
|
substeps: PlayStaticSubstep[],
|
|
420
471
|
): PlayStaticSubstep[] {
|
|
@@ -430,6 +481,10 @@ export function flattenStaticSubsteps(
|
|
|
430
481
|
flattened.push(...flattenStaticSubsteps(substep.steps));
|
|
431
482
|
continue;
|
|
432
483
|
}
|
|
484
|
+
if (substep.type === 'control_flow') {
|
|
485
|
+
flattened.push(...flattenStaticSubsteps(substep.steps));
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
433
488
|
if (substep.type === 'play_call' && substep.pipeline) {
|
|
434
489
|
const nestedSubsteps = getCompiledPipelineSubsteps(substep.pipeline);
|
|
435
490
|
if (nestedSubsteps.length > 0) {
|
|
@@ -452,11 +507,19 @@ export function compileStaticGraph(
|
|
|
452
507
|
): PlayCompiledStaticGraph {
|
|
453
508
|
const rawTopLevel = getRawTopLevelPipelineSubsteps(pipeline);
|
|
454
509
|
const datasets: PlayCompiledStaticGraph['datasets'] = [];
|
|
455
|
-
const topLevel = rawTopLevel.map((substep) =>
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
510
|
+
const topLevel = rawTopLevel.map((substep) =>
|
|
511
|
+
compileStaticGraphSubstep(substep, pipeline?.substeps ?? [], datasets),
|
|
512
|
+
);
|
|
513
|
+
return { topLevel, datasets };
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function compileStaticGraphSubstep(
|
|
517
|
+
substep: PlayStaticSubstep,
|
|
518
|
+
pipelineSubsteps: PlayStaticSubstep[],
|
|
519
|
+
datasets: PlayCompiledStaticGraph['datasets'],
|
|
520
|
+
): PlayStaticSubstep {
|
|
521
|
+
if (substep.type === 'dataset') {
|
|
522
|
+
const columns = compileDatasetColumns(substep, pipelineSubsteps);
|
|
460
523
|
const tableNamespace = (substep.tableNamespace ?? substep.field).trim();
|
|
461
524
|
if (tableNamespace) {
|
|
462
525
|
datasets.push({ tableNamespace, columns });
|
|
@@ -464,9 +527,22 @@ export function compileStaticGraph(
|
|
|
464
527
|
return {
|
|
465
528
|
...substep,
|
|
466
529
|
columns,
|
|
530
|
+
steps: substep.steps?.map((nested) =>
|
|
531
|
+
compileStaticGraphSubstep(nested, pipelineSubsteps, datasets),
|
|
532
|
+
),
|
|
467
533
|
} satisfies PlayStaticSubstep;
|
|
468
|
-
}
|
|
469
|
-
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (substep.type === 'step_suite' || substep.type === 'control_flow') {
|
|
537
|
+
return {
|
|
538
|
+
...substep,
|
|
539
|
+
steps: substep.steps.map((nested) =>
|
|
540
|
+
compileStaticGraphSubstep(nested, pipelineSubsteps, datasets),
|
|
541
|
+
),
|
|
542
|
+
} satisfies PlayStaticSubstep;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return substep;
|
|
470
546
|
}
|
|
471
547
|
|
|
472
548
|
function compileDatasetColumns(
|
|
@@ -562,7 +638,7 @@ function columnProducerFromSubstep(
|
|
|
562
638
|
field: string,
|
|
563
639
|
): PlayStaticColumnProducer {
|
|
564
640
|
const steps =
|
|
565
|
-
substep.type === 'step_suite'
|
|
641
|
+
substep.type === 'step_suite' || substep.type === 'control_flow'
|
|
566
642
|
? substep.steps
|
|
567
643
|
.map((step) => {
|
|
568
644
|
const stepField = fieldForColumnProducer(step) ?? field;
|
|
@@ -577,15 +653,20 @@ function columnProducerFromSubstep(
|
|
|
577
653
|
? 'waterfall'
|
|
578
654
|
: substep.type === 'step_suite'
|
|
579
655
|
? 'stepProgram'
|
|
580
|
-
: substep.type === '
|
|
581
|
-
? '
|
|
582
|
-
: '
|
|
656
|
+
: substep.type === 'control_flow'
|
|
657
|
+
? 'controlFlow'
|
|
658
|
+
: substep.type === 'play_call'
|
|
659
|
+
? 'playCall'
|
|
660
|
+
: 'transform';
|
|
583
661
|
return {
|
|
584
662
|
id: producerId(substep, field),
|
|
585
663
|
kind,
|
|
586
664
|
field,
|
|
587
665
|
...(substep.type === 'tool' ? { toolId: substep.toolId } : {}),
|
|
588
666
|
...(substep.type === 'play_call' ? { playId: substep.playId } : {}),
|
|
667
|
+
...(substep.dependsOnFields?.length
|
|
668
|
+
? { dependsOnFields: [...substep.dependsOnFields] }
|
|
669
|
+
: {}),
|
|
589
670
|
...(substep.staleAfterSeconds !== undefined
|
|
590
671
|
? { staleAfterSeconds: substep.staleAfterSeconds }
|
|
591
672
|
: {}),
|
|
@@ -603,11 +684,21 @@ function producerId(substep: PlayStaticSubstep, field: string): string {
|
|
|
603
684
|
}
|
|
604
685
|
if (substep.type === 'play_call') return `${field}:play:${substep.playId}`;
|
|
605
686
|
if (substep.type === 'step_suite') return `${field}:steps`;
|
|
687
|
+
if (substep.type === 'control_flow')
|
|
688
|
+
return `${field}:control:${substep.kind}:${sourceRangeKey(substep.sourceRange)}`;
|
|
606
689
|
if (substep.type === 'run_javascript')
|
|
607
690
|
return `${field}:transform:${substep.alias}`;
|
|
608
691
|
return `${field}:transform`;
|
|
609
692
|
}
|
|
610
693
|
|
|
694
|
+
function sourceRangeKey(
|
|
695
|
+
sourceRange: PlayStaticSourceRange | undefined,
|
|
696
|
+
): string {
|
|
697
|
+
return sourceRange
|
|
698
|
+
? `${sourceRange.startLine}:${sourceRange.startColumn}:${sourceRange.endLine}:${sourceRange.endColumn}`
|
|
699
|
+
: 'unknown';
|
|
700
|
+
}
|
|
701
|
+
|
|
611
702
|
export function resolveSheetContractForTableNamespace(
|
|
612
703
|
pipeline: PlayStaticPipeline | null | undefined,
|
|
613
704
|
tableNamespace: string | null | undefined,
|
|
@@ -685,8 +776,7 @@ export function resolveStaticDatasetColumnsForTableNamespace(
|
|
|
685
776
|
const compiled = compileStaticGraph(currentPipeline);
|
|
686
777
|
const matchingDataset = compiled.datasets.find(
|
|
687
778
|
(dataset) =>
|
|
688
|
-
normalizeTableNamespace(dataset.tableNamespace) ===
|
|
689
|
-
normalizedNamespace,
|
|
779
|
+
normalizeTableNamespace(dataset.tableNamespace) === normalizedNamespace,
|
|
690
780
|
);
|
|
691
781
|
if (matchingDataset) {
|
|
692
782
|
return matchingDataset.columns;
|
|
@@ -762,23 +852,23 @@ export function compileSheetContract(pipeline: PlayStaticPipeline): {
|
|
|
762
852
|
addColumn({ id: field, source: 'datasetColumn', field });
|
|
763
853
|
}
|
|
764
854
|
|
|
765
|
-
|
|
855
|
+
const processSubstep = (substep: PlayStaticSubstep) => {
|
|
766
856
|
if (substep.type === 'waterfall') {
|
|
767
857
|
if (!substep.id) {
|
|
768
858
|
if (substep.tool) {
|
|
769
|
-
|
|
859
|
+
return;
|
|
770
860
|
}
|
|
771
861
|
errors.push(
|
|
772
862
|
`Sheet contract cannot compile waterfall field "${substep.field}" without a literal waterfall id.`,
|
|
773
863
|
);
|
|
774
|
-
|
|
864
|
+
return;
|
|
775
865
|
}
|
|
776
866
|
if (!substep.steps?.length) {
|
|
777
867
|
errors.push(
|
|
778
868
|
`Sheet contract cannot compile waterfall "${substep.id}" because its steps are not statically known. ` +
|
|
779
869
|
'Use an inline array, a local const array, or a local no-arg function that returns an array of step("id", "tool", ...) calls.',
|
|
780
870
|
);
|
|
781
|
-
|
|
871
|
+
return;
|
|
782
872
|
}
|
|
783
873
|
for (const step of substep.steps) {
|
|
784
874
|
addColumn({
|
|
@@ -794,7 +884,7 @@ export function compileSheetContract(pipeline: PlayStaticPipeline): {
|
|
|
794
884
|
toolId: step.toolId,
|
|
795
885
|
});
|
|
796
886
|
}
|
|
797
|
-
|
|
887
|
+
return;
|
|
798
888
|
}
|
|
799
889
|
|
|
800
890
|
if (substep.type === 'step_suite') {
|
|
@@ -825,10 +915,25 @@ export function compileSheetContract(pipeline: PlayStaticPipeline): {
|
|
|
825
915
|
if (step.type === 'step_suite') {
|
|
826
916
|
addStepSuiteColumns(step, rootField);
|
|
827
917
|
}
|
|
918
|
+
if (step.type === 'control_flow') {
|
|
919
|
+
for (const nested of step.steps) {
|
|
920
|
+
if (nested.type === 'step_suite') {
|
|
921
|
+
addStepSuiteColumns(nested, rootField);
|
|
922
|
+
} else {
|
|
923
|
+
processSubstep(nested);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
828
927
|
}
|
|
829
928
|
};
|
|
830
929
|
addStepSuiteColumns(substep, substep.field);
|
|
831
|
-
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
if (substep.type === 'control_flow') {
|
|
933
|
+
for (const nested of substep.steps) {
|
|
934
|
+
processSubstep(nested);
|
|
935
|
+
}
|
|
936
|
+
return;
|
|
832
937
|
}
|
|
833
938
|
if (substep.type === 'play_call') {
|
|
834
939
|
if (substep.cycleDetected || substep.resolutionError) {
|
|
@@ -864,6 +969,10 @@ export function compileSheetContract(pipeline: PlayStaticPipeline): {
|
|
|
864
969
|
}
|
|
865
970
|
}
|
|
866
971
|
}
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
for (const substep of pipeline.substeps) {
|
|
975
|
+
processSubstep(substep);
|
|
867
976
|
}
|
|
868
977
|
|
|
869
978
|
return {
|