deepline 0.1.36 → 0.1.38
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 +220 -34
- package/dist/cli/index.mjs +220 -34
- package/dist/index.d.mts +18 -2
- package/dist/index.d.ts +18 -2
- package/dist/index.js +12 -8
- package/dist/index.mjs +12 -8
- package/dist/repo/apps/play-runner-workers/src/entry.ts +89 -17
- package/dist/repo/sdk/src/types.ts +17 -0
- package/dist/repo/sdk/src/version.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +79 -23
- package/package.json +1 -1
|
@@ -52,7 +52,10 @@ import {
|
|
|
52
52
|
import {
|
|
53
53
|
adaptV2ExecuteResponseToToolResult,
|
|
54
54
|
createToolExecuteResult,
|
|
55
|
+
deserializeToolExecuteResult,
|
|
56
|
+
isSerializedToolExecuteResult,
|
|
55
57
|
isToolExecuteResult,
|
|
58
|
+
serializeToolExecuteResult,
|
|
56
59
|
type ToolExecuteResult,
|
|
57
60
|
type ToolResultMetadataInput,
|
|
58
61
|
} from '../../../shared_libs/play-runtime/tool-result';
|
|
@@ -448,7 +451,7 @@ async function probeHarnessOnce(
|
|
|
448
451
|
*/
|
|
449
452
|
const RUNTIME_API_TIMEOUT_MS = 30_000;
|
|
450
453
|
const RUNTIME_API_PLAY_RUN_TIMEOUT_MS = 75_000;
|
|
451
|
-
const RUNTIME_API_RETRY_DELAYS_MS = [250, 750, 1500] as const;
|
|
454
|
+
const RUNTIME_API_RETRY_DELAYS_MS = [250, 750, 1500, 3000, 5000, 10000] as const;
|
|
452
455
|
let loggedMissingRuntimeApiBinding = false;
|
|
453
456
|
|
|
454
457
|
async function fetchRuntimeApi(
|
|
@@ -461,7 +464,17 @@ async function fetchRuntimeApi(
|
|
|
461
464
|
? RUNTIME_API_PLAY_RUN_TIMEOUT_MS
|
|
462
465
|
: RUNTIME_API_TIMEOUT_MS;
|
|
463
466
|
const controller = new AbortController();
|
|
464
|
-
|
|
467
|
+
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
468
|
+
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
469
|
+
timeout = setTimeout(() => {
|
|
470
|
+
controller.abort();
|
|
471
|
+
reject(
|
|
472
|
+
new Error(
|
|
473
|
+
`[play-harness] runtime API call timed out after ${timeoutMs}ms. path=${path} baseUrl=${baseUrl}`,
|
|
474
|
+
),
|
|
475
|
+
);
|
|
476
|
+
}, timeoutMs);
|
|
477
|
+
});
|
|
465
478
|
try {
|
|
466
479
|
const mergedInit: RequestInit = {
|
|
467
480
|
...init,
|
|
@@ -475,11 +488,15 @@ async function fetchRuntimeApi(
|
|
|
475
488
|
`[play-harness] RUNTIME_API binding missing; using public runtime API transport. path=${path}`,
|
|
476
489
|
);
|
|
477
490
|
}
|
|
478
|
-
return await
|
|
491
|
+
return await Promise.race([
|
|
492
|
+
fetch(`${baseUrl.replace(/\/$/, '')}${path}`, mergedInit),
|
|
493
|
+
timeoutPromise,
|
|
494
|
+
]);
|
|
479
495
|
}
|
|
480
|
-
|
|
496
|
+
const responsePromise = cachedRuntimeApiBinding.fetch(
|
|
481
497
|
new Request(`${baseUrl.replace(/\/$/, '')}${path}`, mergedInit),
|
|
482
498
|
);
|
|
499
|
+
return await Promise.race([responsePromise, timeoutPromise]);
|
|
483
500
|
} catch (err) {
|
|
484
501
|
if (err instanceof Error && err.name === 'AbortError') {
|
|
485
502
|
throw new Error(
|
|
@@ -488,7 +505,7 @@ async function fetchRuntimeApi(
|
|
|
488
505
|
}
|
|
489
506
|
throw err;
|
|
490
507
|
} finally {
|
|
491
|
-
clearTimeout(
|
|
508
|
+
if (timeout) clearTimeout(timeout);
|
|
492
509
|
}
|
|
493
510
|
}
|
|
494
511
|
|
|
@@ -724,7 +741,8 @@ function isRetryableRuntimeApiResponse(status: number, body: string): boolean {
|
|
|
724
741
|
status === 429 ||
|
|
725
742
|
status === 502 ||
|
|
726
743
|
status === 503 ||
|
|
727
|
-
status === 504
|
|
744
|
+
status === 504 ||
|
|
745
|
+
status === 530
|
|
728
746
|
) {
|
|
729
747
|
return true;
|
|
730
748
|
}
|
|
@@ -1454,6 +1472,21 @@ function executeSyntheticTransientRetry(
|
|
|
1454
1472
|
function executeSyntheticTestRateLimit(
|
|
1455
1473
|
input: Record<string, unknown>,
|
|
1456
1474
|
): Record<string, unknown> {
|
|
1475
|
+
if (
|
|
1476
|
+
typeof input.key === 'string' &&
|
|
1477
|
+
input.key.startsWith('public-error-message-regression')
|
|
1478
|
+
) {
|
|
1479
|
+
throw new ToolHttpError(
|
|
1480
|
+
[
|
|
1481
|
+
'tool test_rate_limit 422 attempt 1/1:',
|
|
1482
|
+
'Synthetic public test error with a redacted token=[REDACTED].',
|
|
1483
|
+
'code=TEST_PUBLIC_ERROR.',
|
|
1484
|
+
'failure_description=The fake test provider intentionally raised a typed public error so V2 runner output preserves actionable details.',
|
|
1485
|
+
'operator_hint=Use this no-bill test provider fixture when verifying play runner error rendering.',
|
|
1486
|
+
].join(' '),
|
|
1487
|
+
null,
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1457
1490
|
const rowNumber =
|
|
1458
1491
|
typeof input.row_number === 'number' && Number.isInteger(input.row_number)
|
|
1459
1492
|
? input.row_number
|
|
@@ -1850,8 +1883,39 @@ type WorkerMapChunkSummary<T extends Record<string, unknown>> = {
|
|
|
1850
1883
|
cachedRows?: T[];
|
|
1851
1884
|
};
|
|
1852
1885
|
|
|
1853
|
-
function
|
|
1854
|
-
|
|
1886
|
+
function serializeDurableStepValue<T>(value: T, depth = 0): T {
|
|
1887
|
+
if (depth > 20 || value == null) return value;
|
|
1888
|
+
if (isToolExecuteResult(value)) return serializeToolExecuteResult(value) as T;
|
|
1889
|
+
if (isDatasetHandle(value)) return serializeValue(value, depth) as T;
|
|
1890
|
+
if (Array.isArray(value)) {
|
|
1891
|
+
return value.map((entry) => serializeDurableStepValue(entry, depth + 1)) as T;
|
|
1892
|
+
}
|
|
1893
|
+
if (typeof value !== 'object') return value;
|
|
1894
|
+
return Object.fromEntries(
|
|
1895
|
+
Object.entries(value as Record<string, unknown>).map(([key, child]) => [
|
|
1896
|
+
key,
|
|
1897
|
+
serializeDurableStepValue(child, depth + 1),
|
|
1898
|
+
]),
|
|
1899
|
+
) as T;
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
function deserializeDurableStepValue<T>(value: T, depth = 0): T {
|
|
1903
|
+
if (depth > 20 || value == null) return value;
|
|
1904
|
+
if (isSerializedToolExecuteResult(value)) {
|
|
1905
|
+
return deserializeToolExecuteResult(value) as T;
|
|
1906
|
+
}
|
|
1907
|
+
if (Array.isArray(value)) {
|
|
1908
|
+
return value.map((entry) =>
|
|
1909
|
+
deserializeDurableStepValue(entry, depth + 1),
|
|
1910
|
+
) as T;
|
|
1911
|
+
}
|
|
1912
|
+
if (typeof value !== 'object') return value;
|
|
1913
|
+
return Object.fromEntries(
|
|
1914
|
+
Object.entries(value as Record<string, unknown>).map(([key, child]) => [
|
|
1915
|
+
key,
|
|
1916
|
+
deserializeDurableStepValue(child, depth + 1),
|
|
1917
|
+
]),
|
|
1918
|
+
) as T;
|
|
1855
1919
|
}
|
|
1856
1920
|
|
|
1857
1921
|
type WorkerStepResolver = (
|
|
@@ -1973,8 +2037,8 @@ async function executeWorkerStepProgram(
|
|
|
1973
2037
|
let currentRow: Record<string, unknown> = cloneCsvAliasedRow(inputRow);
|
|
1974
2038
|
for (const step of program.steps) {
|
|
1975
2039
|
const stepPath = [...(recorder?.path ?? []), step.name];
|
|
1976
|
-
const runStep = async () =>
|
|
1977
|
-
await executeWorkerStepResolver(
|
|
2040
|
+
const runStep = async (): Promise<WorkerStepResolution> => {
|
|
2041
|
+
const resolution = await executeWorkerStepResolver(
|
|
1978
2042
|
step.resolver,
|
|
1979
2043
|
currentRow,
|
|
1980
2044
|
ctx,
|
|
@@ -1982,10 +2046,15 @@ async function executeWorkerStepProgram(
|
|
|
1982
2046
|
recorder
|
|
1983
2047
|
? {
|
|
1984
2048
|
...recorder,
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
2049
|
+
path: stepPath,
|
|
2050
|
+
}
|
|
2051
|
+
: undefined,
|
|
1988
2052
|
);
|
|
2053
|
+
return {
|
|
2054
|
+
value: serializeDurableStepValue(resolution.value),
|
|
2055
|
+
...(resolution.status ? { status: resolution.status } : {}),
|
|
2056
|
+
};
|
|
2057
|
+
};
|
|
1989
2058
|
const resolution = workflowStep
|
|
1990
2059
|
? await (
|
|
1991
2060
|
workflowStep.do as unknown as (
|
|
@@ -1994,7 +2063,7 @@ async function executeWorkerStepProgram(
|
|
|
1994
2063
|
) => Promise<WorkerStepResolution>
|
|
1995
2064
|
)(stepPath.join('.'), runStep)
|
|
1996
2065
|
: await runStep();
|
|
1997
|
-
const value = resolution.value;
|
|
2066
|
+
const value = deserializeDurableStepValue(resolution.value);
|
|
1998
2067
|
currentRow = cloneCsvAliasedRow(currentRow, { [step.name]: value });
|
|
1999
2068
|
if (recorder) {
|
|
2000
2069
|
const stepId = stepPath.join('.');
|
|
@@ -3553,10 +3622,10 @@ function createMinimalWorkerCtx(
|
|
|
3553
3622
|
rowsSkipped,
|
|
3554
3623
|
outputDatasetId: `map:${name}`,
|
|
3555
3624
|
hash,
|
|
3556
|
-
preview:
|
|
3625
|
+
preview: serializeDurableStepValue(out.slice(0, 5)),
|
|
3557
3626
|
cachedRows:
|
|
3558
3627
|
out.length <= WORKER_DATASET_IN_MEMORY_ROWS
|
|
3559
|
-
?
|
|
3628
|
+
? serializeDurableStepValue(out)
|
|
3560
3629
|
: undefined,
|
|
3561
3630
|
};
|
|
3562
3631
|
};
|
|
@@ -3784,13 +3853,16 @@ function createMinimalWorkerCtx(
|
|
|
3784
3853
|
ts: nowMs(),
|
|
3785
3854
|
});
|
|
3786
3855
|
}
|
|
3856
|
+
// Static pipeline JS blocks already execute inside a Workflow step.
|
|
3857
|
+
// Wrapping each generated waterfall step in another step.do can leave
|
|
3858
|
+
// Workers preview runs parked after the last provider callback.
|
|
3787
3859
|
return (await executeWorkerStepProgram(
|
|
3788
3860
|
program,
|
|
3789
3861
|
input,
|
|
3790
3862
|
ctx,
|
|
3791
3863
|
0,
|
|
3792
3864
|
undefined,
|
|
3793
|
-
|
|
3865
|
+
undefined,
|
|
3794
3866
|
)) as T;
|
|
3795
3867
|
},
|
|
3796
3868
|
async csv<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
@@ -626,10 +626,27 @@ export interface PlayCheckResult {
|
|
|
626
626
|
valid: boolean;
|
|
627
627
|
errors: string[];
|
|
628
628
|
staticPipeline?: Record<string, unknown> | null;
|
|
629
|
+
toolGetterHints?: PlayCheckToolGetterHint[];
|
|
629
630
|
artifactHash?: string | null;
|
|
630
631
|
graphHash?: string | null;
|
|
631
632
|
}
|
|
632
633
|
|
|
634
|
+
export interface PlayCheckToolGetterHint {
|
|
635
|
+
toolId: string;
|
|
636
|
+
lists: Array<{
|
|
637
|
+
name: string;
|
|
638
|
+
expression: string;
|
|
639
|
+
raw?: string;
|
|
640
|
+
}>;
|
|
641
|
+
values: Array<{
|
|
642
|
+
name: string;
|
|
643
|
+
expression: string;
|
|
644
|
+
raw?: string;
|
|
645
|
+
}>;
|
|
646
|
+
raw?: string;
|
|
647
|
+
unavailable?: string;
|
|
648
|
+
}
|
|
649
|
+
|
|
633
650
|
/**
|
|
634
651
|
* Request body for starting a play run via {@link DeeplineClient.startPlayRun}.
|
|
635
652
|
*
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.1.
|
|
2
|
-
export const SDK_API_CONTRACT = "2026-05-v2-tool-response";
|
|
1
|
+
export const SDK_VERSION = "0.1.38";
|
|
2
|
+
export const SDK_API_CONTRACT = "2026-05-v2-tool-response-play-guardrails";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type {
|
|
2
|
+
SerializedToolExecuteResult,
|
|
2
3
|
ToolExecuteResult,
|
|
3
4
|
ToolResultExecutionMetadata,
|
|
4
5
|
ToolResultMetadata,
|
|
@@ -10,6 +11,7 @@ export type {
|
|
|
10
11
|
} from './tool-result-types';
|
|
11
12
|
|
|
12
13
|
import type {
|
|
14
|
+
SerializedToolExecuteResult,
|
|
13
15
|
ToolExecuteResult,
|
|
14
16
|
ToolResultExecutionMetadata,
|
|
15
17
|
ToolResultListAccessor,
|
|
@@ -22,6 +24,8 @@ import type {
|
|
|
22
24
|
|
|
23
25
|
type PathSegment = string | number | '*';
|
|
24
26
|
|
|
27
|
+
const SERIALIZED_TOOL_EXECUTE_RESULT_KIND = 'deepline.tool_execute_result.v1';
|
|
28
|
+
|
|
25
29
|
const TARGET_FALLBACK_KEYS: Record<string, readonly RegExp[]> = {
|
|
26
30
|
email: [/^email$/i, /^address$/i, /email/i],
|
|
27
31
|
phone: [/^phone$/i, /mobile/i, /phone/i, /telephone/i],
|
|
@@ -455,11 +459,10 @@ function buildTargets(
|
|
|
455
459
|
}
|
|
456
460
|
|
|
457
461
|
function buildLists(
|
|
458
|
-
|
|
462
|
+
resolved: Record<string, { path: string; rows: Record<string, unknown>[] }>,
|
|
459
463
|
metadata: ToolResultMetadataInput,
|
|
460
464
|
): Record<string, ToolResultListMetadata> {
|
|
461
465
|
const lists: Record<string, ToolResultListMetadata> = {};
|
|
462
|
-
const resolved = resolveListRows(result, metadata.listExtractorPaths);
|
|
463
466
|
for (const [name, list] of Object.entries(resolved)) {
|
|
464
467
|
lists[name] = {
|
|
465
468
|
path: list.path,
|
|
@@ -499,11 +502,12 @@ function buildExtractedAccessors(
|
|
|
499
502
|
}
|
|
500
503
|
|
|
501
504
|
function buildListAccessors(
|
|
502
|
-
|
|
505
|
+
resolved: Record<string, { path: string; rows: Record<string, unknown>[] }>,
|
|
503
506
|
lists: Record<string, ToolResultListMetadata>,
|
|
504
507
|
): Record<string, ToolResultListAccessor> {
|
|
505
508
|
return Object.fromEntries(
|
|
506
509
|
Object.entries(lists).map(([name, metadata]) => {
|
|
510
|
+
const rows = resolved[name]?.rows ?? [];
|
|
507
511
|
const accessor = {
|
|
508
512
|
path: metadata.path,
|
|
509
513
|
count: metadata.count,
|
|
@@ -511,7 +515,7 @@ function buildListAccessors(
|
|
|
511
515
|
} as ToolResultListAccessor;
|
|
512
516
|
Object.defineProperty(accessor, 'get', {
|
|
513
517
|
value() {
|
|
514
|
-
return
|
|
518
|
+
return rows;
|
|
515
519
|
},
|
|
516
520
|
enumerable: false,
|
|
517
521
|
});
|
|
@@ -539,7 +543,11 @@ export function createToolExecuteResult<TResult = unknown>(input: {
|
|
|
539
543
|
resultRoot,
|
|
540
544
|
input.metadata.resultIdentityGetters,
|
|
541
545
|
);
|
|
542
|
-
const
|
|
546
|
+
const resolvedLists = resolveListRows(
|
|
547
|
+
resultRoot,
|
|
548
|
+
input.metadata.listExtractorPaths,
|
|
549
|
+
);
|
|
550
|
+
const lists = buildLists(resolvedLists, input.metadata);
|
|
543
551
|
const metadata = {
|
|
544
552
|
toolId: input.metadata.toolId,
|
|
545
553
|
execution: input.execution,
|
|
@@ -551,7 +559,7 @@ export function createToolExecuteResult<TResult = unknown>(input: {
|
|
|
551
559
|
...(result.meta ? { meta: result.meta } : {}),
|
|
552
560
|
};
|
|
553
561
|
const extractedValues = buildExtractedAccessors(targets);
|
|
554
|
-
const extractedLists = buildListAccessors(
|
|
562
|
+
const extractedLists = buildListAccessors(resolvedLists, lists);
|
|
555
563
|
const wrapper = {
|
|
556
564
|
status: input.status,
|
|
557
565
|
...(input.jobId ? { job_id: input.jobId } : {}),
|
|
@@ -586,6 +594,70 @@ export function isToolExecuteResult(
|
|
|
586
594
|
);
|
|
587
595
|
}
|
|
588
596
|
|
|
597
|
+
function metadataInputFromToolExecuteResult(
|
|
598
|
+
value: ToolExecuteResult,
|
|
599
|
+
): ToolResultMetadataInput {
|
|
600
|
+
return {
|
|
601
|
+
toolId: value._metadata.toolId,
|
|
602
|
+
resultIdentityGetters: Object.fromEntries(
|
|
603
|
+
Object.entries(value._metadata.targets).map(([target, info]) => [
|
|
604
|
+
target,
|
|
605
|
+
[info.path],
|
|
606
|
+
]),
|
|
607
|
+
),
|
|
608
|
+
listExtractorPaths: Object.values(value._metadata.lists).map(
|
|
609
|
+
(list) => list.path,
|
|
610
|
+
),
|
|
611
|
+
listIdentityGetters: Object.fromEntries(
|
|
612
|
+
Object.values(value._metadata.lists)
|
|
613
|
+
.flatMap((list) => Object.entries(list.keys))
|
|
614
|
+
.map(([target, path]) => [target, [path]]),
|
|
615
|
+
),
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
export function serializeToolExecuteResult(
|
|
620
|
+
value: ToolExecuteResult,
|
|
621
|
+
): SerializedToolExecuteResult {
|
|
622
|
+
return {
|
|
623
|
+
__kind: SERIALIZED_TOOL_EXECUTE_RESULT_KIND,
|
|
624
|
+
status: value.status,
|
|
625
|
+
toolResponse: {
|
|
626
|
+
raw: value.toolResponse.raw,
|
|
627
|
+
...(value.toolResponse.meta ? { meta: value.toolResponse.meta } : {}),
|
|
628
|
+
},
|
|
629
|
+
metadata: metadataInputFromToolExecuteResult(value),
|
|
630
|
+
execution: value._metadata.execution,
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
export function isSerializedToolExecuteResult(
|
|
635
|
+
value: unknown,
|
|
636
|
+
): value is SerializedToolExecuteResult {
|
|
637
|
+
return (
|
|
638
|
+
isRecord(value) &&
|
|
639
|
+
value.__kind === SERIALIZED_TOOL_EXECUTE_RESULT_KIND &&
|
|
640
|
+
typeof value.status === 'string' &&
|
|
641
|
+
isRecord(value.toolResponse) &&
|
|
642
|
+
isRecord(value.metadata) &&
|
|
643
|
+
isRecord(value.execution)
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
export function deserializeToolExecuteResult(
|
|
648
|
+
value: SerializedToolExecuteResult,
|
|
649
|
+
): ToolExecuteResult {
|
|
650
|
+
return createToolExecuteResult({
|
|
651
|
+
status: value.status,
|
|
652
|
+
result: {
|
|
653
|
+
data: value.toolResponse.raw,
|
|
654
|
+
...(value.toolResponse.meta ? { meta: value.toolResponse.meta } : {}),
|
|
655
|
+
},
|
|
656
|
+
metadata: value.metadata,
|
|
657
|
+
execution: value.execution,
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
|
|
589
661
|
export function cloneToolExecuteResultWithExecution<TResult>(
|
|
590
662
|
value: ToolExecuteResult<TResult>,
|
|
591
663
|
execution: ToolResultExecutionMetadata,
|
|
@@ -600,23 +672,7 @@ export function cloneToolExecuteResultWithExecution<TResult>(
|
|
|
600
672
|
data: value.toolResponse.raw,
|
|
601
673
|
...(value.toolResponse.meta ? { meta: value.toolResponse.meta } : {}),
|
|
602
674
|
} as TResult,
|
|
603
|
-
metadata:
|
|
604
|
-
toolId: value._metadata.toolId,
|
|
605
|
-
resultIdentityGetters: Object.fromEntries(
|
|
606
|
-
Object.entries(value._metadata.targets).map(([target, info]) => [
|
|
607
|
-
target,
|
|
608
|
-
[info.path],
|
|
609
|
-
]),
|
|
610
|
-
),
|
|
611
|
-
listExtractorPaths: Object.values(value._metadata.lists).map(
|
|
612
|
-
(list) => list.path,
|
|
613
|
-
),
|
|
614
|
-
listIdentityGetters: Object.fromEntries(
|
|
615
|
-
Object.values(value._metadata.lists)
|
|
616
|
-
.flatMap((list) => Object.entries(list.keys))
|
|
617
|
-
.map(([target, path]) => [target, [path]]),
|
|
618
|
-
),
|
|
619
|
-
},
|
|
675
|
+
metadata: metadataInputFromToolExecuteResult(value),
|
|
620
676
|
execution,
|
|
621
677
|
meta: isRecord(value.meta) ? value.meta : undefined,
|
|
622
678
|
});
|