deepline 0.1.33 → 0.1.35
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 +959 -207
- package/dist/cli/index.mjs +892 -140
- package/dist/index.d.mts +127 -63
- package/dist/index.d.ts +127 -63
- package/dist/index.js +516 -45
- package/dist/index.mjs +516 -45
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +212 -1
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +129 -2
- package/dist/repo/apps/play-runner-workers/src/entry.ts +147 -64
- package/dist/repo/apps/play-runner-workers/src/workflow-retry.ts +50 -0
- package/dist/repo/sdk/src/client.ts +46 -33
- package/dist/repo/sdk/src/http.ts +44 -4
- package/dist/repo/sdk/src/index.ts +8 -5
- package/dist/repo/sdk/src/play.ts +124 -45
- package/dist/repo/sdk/src/plays/harness-stub.ts +2 -2
- package/dist/repo/sdk/src/tool-output.ts +26 -7
- package/dist/repo/sdk/src/types.ts +45 -11
- package/dist/repo/sdk/src/version.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/run-failure.ts +49 -0
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +138 -35
- package/package.json +1 -1
|
@@ -28,7 +28,10 @@
|
|
|
28
28
|
*
|
|
29
29
|
* export default definePlay('my-play', async (ctx, input: { domain: string }) => {
|
|
30
30
|
* ctx.log(`Looking up ${input.domain}`);
|
|
31
|
-
* const company = await ctx.tools.execute(
|
|
31
|
+
* const company = await ctx.tools.execute({
|
|
32
|
+
* id: 'company_search',
|
|
33
|
+
* tool: 'test_company_search',
|
|
34
|
+
* input: { domain: input.domain },
|
|
32
35
|
* description: 'Look up company details by domain.',
|
|
33
36
|
* });
|
|
34
37
|
* return company;
|
|
@@ -42,8 +45,8 @@
|
|
|
42
45
|
* ```typescript
|
|
43
46
|
* import { Deepline } from 'deepline';
|
|
44
47
|
*
|
|
45
|
-
* const
|
|
46
|
-
* const job = await
|
|
48
|
+
* const deepline = await Deepline.connect();
|
|
49
|
+
* const job = await deepline.play('my-play').run({ domain: 'stripe.com' });
|
|
47
50
|
* const result = await job.get(); // Polls until complete
|
|
48
51
|
* ```
|
|
49
52
|
*
|
|
@@ -53,7 +56,10 @@
|
|
|
53
56
|
* import { definePlay } from 'deepline';
|
|
54
57
|
*
|
|
55
58
|
* export default definePlay('daily-sync', async (ctx) => {
|
|
56
|
-
* const data = await ctx.tools.execute(
|
|
59
|
+
* const data = await ctx.tools.execute({
|
|
60
|
+
* id: 'crm_export',
|
|
61
|
+
* tool: 'crm_export',
|
|
62
|
+
* input: {},
|
|
57
63
|
* description: 'Export CRM records for the daily sync.',
|
|
58
64
|
* });
|
|
59
65
|
* return data;
|
|
@@ -66,6 +72,7 @@
|
|
|
66
72
|
*/
|
|
67
73
|
import { DeeplineClient } from './client.js';
|
|
68
74
|
import { DeeplineError } from './errors.js';
|
|
75
|
+
import { createToolExecuteResult } from '../../shared_libs/play-runtime/tool-result.js';
|
|
69
76
|
import type {
|
|
70
77
|
PlayDataset,
|
|
71
78
|
PlayDatasetInput,
|
|
@@ -83,6 +90,7 @@ import type {
|
|
|
83
90
|
ToolDefinition,
|
|
84
91
|
ToolMetadata,
|
|
85
92
|
} from './types.js';
|
|
93
|
+
import type { ToolExecution } from './client.js';
|
|
86
94
|
|
|
87
95
|
/**
|
|
88
96
|
* Optional trigger bindings for a play.
|
|
@@ -275,7 +283,10 @@ export type CsvOptions = {
|
|
|
275
283
|
* ```typescript
|
|
276
284
|
* definePlay('example', async (ctx, input: { domain: string }) => {
|
|
277
285
|
* // Call a tool
|
|
278
|
-
* const company = await ctx.tools.execute(
|
|
286
|
+
* const company = await ctx.tools.execute({
|
|
287
|
+
* id: 'company_search',
|
|
288
|
+
* tool: 'test_company_search',
|
|
289
|
+
* input: { domain: input.domain },
|
|
279
290
|
* description: 'Look up company details by domain.',
|
|
280
291
|
* });
|
|
281
292
|
*
|
|
@@ -348,24 +359,30 @@ export interface DeeplinePlayRuntimeContext {
|
|
|
348
359
|
*
|
|
349
360
|
* @example Single tool per row
|
|
350
361
|
* ```typescript
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
362
|
+
* const results = await ctx
|
|
363
|
+
* .map('companies', leads)
|
|
364
|
+
* .step('company', (row, ctx) =>
|
|
365
|
+
* ctx.tools.execute({
|
|
366
|
+
* id: 'company_search',
|
|
367
|
+
* tool: 'test_company_search',
|
|
368
|
+
* input: { domain: row.domain },
|
|
369
|
+
* description: 'Look up company details by domain.',
|
|
370
|
+
* }))
|
|
357
371
|
* .run({ description: 'Look up companies.' });
|
|
358
372
|
* // [{ domain: 'stripe.com', company: { name: 'Stripe', ... } }, ...]
|
|
359
373
|
* ```
|
|
360
374
|
*
|
|
361
375
|
* @example Multiple columns with pre/post logic
|
|
362
376
|
* ```typescript
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
377
|
+
* const results = await ctx
|
|
378
|
+
* .map('leads', leads)
|
|
379
|
+
* .step('company', (row, ctx) =>
|
|
380
|
+
* ctx.tools.execute({
|
|
381
|
+
* id: 'company_search',
|
|
382
|
+
* tool: 'test_company_search',
|
|
383
|
+
* input: { domain: row.domain },
|
|
384
|
+
* description: 'Look up company details by domain.',
|
|
385
|
+
* }))
|
|
369
386
|
* .step('score', (row) =>
|
|
370
387
|
* row.company?.employeeCount > 100 ? 'enterprise' : 'smb')
|
|
371
388
|
* .run({ description: 'Enrich leads.' });
|
|
@@ -379,22 +396,16 @@ export interface DeeplinePlayRuntimeContext {
|
|
|
379
396
|
/** Tool execution namespace. */
|
|
380
397
|
tools: {
|
|
381
398
|
/**
|
|
382
|
-
* Execute a single tool
|
|
399
|
+
* Execute a single tool with a keyword-style request object.
|
|
383
400
|
*
|
|
384
|
-
* @param
|
|
385
|
-
* @param
|
|
386
|
-
* @param input - Tool-specific input parameters
|
|
401
|
+
* @param request.id - Stable step key for idempotent execution
|
|
402
|
+
* @param request.tool - Tool identifier (e.g. `'test_company_search'`)
|
|
403
|
+
* @param request.input - Tool-specific input parameters
|
|
387
404
|
* @returns The tool's output
|
|
388
405
|
*/
|
|
389
406
|
execute<TOutput = LoosePlayObject>(
|
|
390
407
|
request: ToolExecutionRequest,
|
|
391
408
|
): Promise<ToolExecuteResult<TOutput>>;
|
|
392
|
-
execute<TOutput = LoosePlayObject>(
|
|
393
|
-
key: string,
|
|
394
|
-
toolId: string,
|
|
395
|
-
input: Record<string, unknown>,
|
|
396
|
-
options?: { description?: string },
|
|
397
|
-
): Promise<ToolExecuteResult<TOutput>>;
|
|
398
409
|
};
|
|
399
410
|
/**
|
|
400
411
|
* Execute a single tool by stable step key and tool ID.
|
|
@@ -736,7 +747,10 @@ export function when<Row, Value>(
|
|
|
736
747
|
* import { definePlay } from 'deepline';
|
|
737
748
|
*
|
|
738
749
|
* const myPlay = definePlay('my-play', async (ctx, input: { domain: string }) => {
|
|
739
|
-
* return await ctx.tools.execute(
|
|
750
|
+
* return await ctx.tools.execute({
|
|
751
|
+
* id: 'company_search',
|
|
752
|
+
* tool: 'test_company_search',
|
|
753
|
+
* input: { domain: input.domain },
|
|
740
754
|
* description: 'Look up company details by domain.',
|
|
741
755
|
* });
|
|
742
756
|
* });
|
|
@@ -886,14 +900,14 @@ function createNamedPlayHandle<
|
|
|
886
900
|
*
|
|
887
901
|
* @example
|
|
888
902
|
* ```typescript
|
|
889
|
-
* const
|
|
903
|
+
* const deepline = await Deepline.connect();
|
|
890
904
|
*
|
|
891
905
|
* // Tools
|
|
892
|
-
* const tools = await
|
|
893
|
-
* const result = await
|
|
906
|
+
* const tools = await deepline.tools.list();
|
|
907
|
+
* const result = await deepline.tools.execute('test_company_search', { domain: 'stripe.com' });
|
|
894
908
|
*
|
|
895
909
|
* // Plays
|
|
896
|
-
* const job = await
|
|
910
|
+
* const job = await deepline.play('email-waterfall').run({ domain: 'stripe.com' });
|
|
897
911
|
* const output = await job.get();
|
|
898
912
|
* ```
|
|
899
913
|
*/
|
|
@@ -909,10 +923,10 @@ export class DeeplineContext {
|
|
|
909
923
|
*
|
|
910
924
|
* @example
|
|
911
925
|
* ```typescript
|
|
912
|
-
* const tools = await
|
|
913
|
-
* const meta = await
|
|
914
|
-
* const companyLookup = await
|
|
915
|
-
* const company = companyLookup.
|
|
926
|
+
* const tools = await deepline.tools.list();
|
|
927
|
+
* const meta = await deepline.tools.get('apollo_people_search');
|
|
928
|
+
* const companyLookup = await deepline.tools.execute('test_company_search', { domain: 'stripe.com' });
|
|
929
|
+
* const company = companyLookup.toolOutput.raw;
|
|
916
930
|
* ```
|
|
917
931
|
*/
|
|
918
932
|
get tools() {
|
|
@@ -926,12 +940,14 @@ export class DeeplineContext {
|
|
|
926
940
|
execute: async (
|
|
927
941
|
toolId: string,
|
|
928
942
|
input: Record<string, unknown>,
|
|
929
|
-
): Promise<ToolExecuteResult> =>
|
|
930
|
-
this.client.executeTool(
|
|
943
|
+
): Promise<ToolExecuteResult> => {
|
|
944
|
+
const response = await this.client.executeTool(
|
|
931
945
|
toolId,
|
|
932
946
|
input,
|
|
933
947
|
{ includeToolMetadata: true },
|
|
934
|
-
)
|
|
948
|
+
);
|
|
949
|
+
return toolExecutionEnvelopeToResult(toolId, response);
|
|
950
|
+
},
|
|
935
951
|
};
|
|
936
952
|
}
|
|
937
953
|
|
|
@@ -1023,9 +1039,9 @@ export class DeeplineContext {
|
|
|
1023
1039
|
* ```typescript
|
|
1024
1040
|
* import { Deepline } from 'deepline';
|
|
1025
1041
|
*
|
|
1026
|
-
* const
|
|
1027
|
-
* const tools = await
|
|
1028
|
-
* const result = await
|
|
1042
|
+
* const deepline = await Deepline.connect();
|
|
1043
|
+
* const tools = await deepline.tools.list();
|
|
1044
|
+
* const result = await deepline.tools.execute('test_company_search', { domain: 'stripe.com' });
|
|
1029
1045
|
* ```
|
|
1030
1046
|
*/
|
|
1031
1047
|
export class Deepline {
|
|
@@ -1058,6 +1074,60 @@ export class Deepline {
|
|
|
1058
1074
|
}
|
|
1059
1075
|
}
|
|
1060
1076
|
|
|
1077
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
1078
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
function stringArrayRecord(value: unknown): Record<string, string[]> {
|
|
1082
|
+
if (!isRecord(value)) return {};
|
|
1083
|
+
return Object.fromEntries(
|
|
1084
|
+
Object.entries(value).map(([key, paths]) => [
|
|
1085
|
+
key,
|
|
1086
|
+
Array.isArray(paths) ? paths.map(String) : [],
|
|
1087
|
+
]),
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
function stringArray(value: unknown): string[] {
|
|
1092
|
+
return Array.isArray(value) ? value.map(String) : [];
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
function toolExecutionEnvelopeToResult(
|
|
1096
|
+
fallbackToolId: string,
|
|
1097
|
+
response: ToolExecution,
|
|
1098
|
+
): ToolExecuteResult {
|
|
1099
|
+
const raw = response.toolExecutionResult?.toolOutput?.raw ?? null;
|
|
1100
|
+
const meta = response.toolExecutionResult?.toolOutput?.meta;
|
|
1101
|
+
const metadata = isRecord(response._metadata)
|
|
1102
|
+
? response._metadata.tool
|
|
1103
|
+
: null;
|
|
1104
|
+
const toolMetadata = isRecord(metadata) ? metadata : {};
|
|
1105
|
+
|
|
1106
|
+
return createToolExecuteResult({
|
|
1107
|
+
status: typeof response.status === 'string' ? response.status : 'completed',
|
|
1108
|
+
result: {
|
|
1109
|
+
data: raw,
|
|
1110
|
+
...(isRecord(meta) ? { meta } : {}),
|
|
1111
|
+
},
|
|
1112
|
+
metadata: {
|
|
1113
|
+
toolId:
|
|
1114
|
+
typeof toolMetadata.toolId === 'string'
|
|
1115
|
+
? toolMetadata.toolId
|
|
1116
|
+
: fallbackToolId,
|
|
1117
|
+
resultIdentityGetters: stringArrayRecord(
|
|
1118
|
+
toolMetadata.resultIdentityGetters,
|
|
1119
|
+
),
|
|
1120
|
+
listExtractorPaths: stringArray(toolMetadata.listExtractorPaths),
|
|
1121
|
+
listIdentityGetters: stringArrayRecord(toolMetadata.listIdentityGetters),
|
|
1122
|
+
},
|
|
1123
|
+
execution: {
|
|
1124
|
+
idempotent: true,
|
|
1125
|
+
cached: false,
|
|
1126
|
+
source: 'live',
|
|
1127
|
+
},
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1061
1131
|
export function defineInput<TInput>(
|
|
1062
1132
|
schema: Record<string, unknown>,
|
|
1063
1133
|
): PlayInputContract<TInput> {
|
|
@@ -1092,7 +1162,10 @@ export function defineInput<TInput>(
|
|
|
1092
1162
|
*
|
|
1093
1163
|
* export default definePlay('company-lookup', async (ctx, input: { domain: string }) => {
|
|
1094
1164
|
* ctx.log(`Searching for ${input.domain}`);
|
|
1095
|
-
* const company = await ctx.tools.execute(
|
|
1165
|
+
* const company = await ctx.tools.execute({
|
|
1166
|
+
* id: 'company_search',
|
|
1167
|
+
* tool: 'test_company_search',
|
|
1168
|
+
* input: { domain: input.domain },
|
|
1096
1169
|
* description: 'Look up company details by domain.',
|
|
1097
1170
|
* });
|
|
1098
1171
|
* return company;
|
|
@@ -1107,7 +1180,10 @@ export function defineInput<TInput>(
|
|
|
1107
1180
|
* const results = await ctx
|
|
1108
1181
|
* .map('companies', leads)
|
|
1109
1182
|
* .step('company', (row, ctx) =>
|
|
1110
|
-
* ctx.tools.execute(
|
|
1183
|
+
* ctx.tools.execute({
|
|
1184
|
+
* id: 'company_search',
|
|
1185
|
+
* tool: 'test_company_search',
|
|
1186
|
+
* input: { domain: row.domain },
|
|
1111
1187
|
* description: 'Look up company details by domain.',
|
|
1112
1188
|
* }))
|
|
1113
1189
|
* .run({ description: 'Enrich lead companies.' });
|
|
@@ -1118,7 +1194,10 @@ export function defineInput<TInput>(
|
|
|
1118
1194
|
* @example With cron binding
|
|
1119
1195
|
* ```typescript
|
|
1120
1196
|
* export default definePlay('daily-report', async (ctx) => {
|
|
1121
|
-
* const data = await ctx.tools.execute(
|
|
1197
|
+
* const data = await ctx.tools.execute({
|
|
1198
|
+
* id: 'crm_export',
|
|
1199
|
+
* tool: 'crm_export',
|
|
1200
|
+
* input: { since: 'yesterday' },
|
|
1122
1201
|
* description: 'Export yesterday CRM records.',
|
|
1123
1202
|
* });
|
|
1124
1203
|
* return data;
|
|
@@ -155,6 +155,7 @@ export async function harnessPrewarmPostgresSessions(input: {
|
|
|
155
155
|
export async function harnessStartSheetDataset(input: {
|
|
156
156
|
baseUrl: string;
|
|
157
157
|
executorToken: string;
|
|
158
|
+
preloadedDbSessions?: PreloadedRuntimeDbSessionInput[] | null;
|
|
158
159
|
playName: string;
|
|
159
160
|
tableNamespace: string;
|
|
160
161
|
sheetContract: unknown;
|
|
@@ -162,7 +163,6 @@ export async function harnessStartSheetDataset(input: {
|
|
|
162
163
|
runId: string;
|
|
163
164
|
inputOffset?: number;
|
|
164
165
|
userEmail?: string | null;
|
|
165
|
-
preloadedDbSessions?: PreloadedRuntimeDbSessionInput[] | null;
|
|
166
166
|
}): Promise<{
|
|
167
167
|
inserted: number;
|
|
168
168
|
skipped: number;
|
|
@@ -181,6 +181,7 @@ export async function harnessStartSheetDataset(input: {
|
|
|
181
181
|
export async function harnessPersistCompletedSheetRows(input: {
|
|
182
182
|
baseUrl: string;
|
|
183
183
|
executorToken: string;
|
|
184
|
+
preloadedDbSessions?: PreloadedRuntimeDbSessionInput[] | null;
|
|
184
185
|
playName: string;
|
|
185
186
|
tableNamespace: string;
|
|
186
187
|
sheetContract: unknown;
|
|
@@ -188,7 +189,6 @@ export async function harnessPersistCompletedSheetRows(input: {
|
|
|
188
189
|
outputFields: string[];
|
|
189
190
|
runId: string;
|
|
190
191
|
userEmail?: string | null;
|
|
191
|
-
preloadedDbSessions?: PreloadedRuntimeDbSessionInput[] | null;
|
|
192
192
|
}): Promise<{ ok: true; rowsWritten: number; tableNamespace: string }> {
|
|
193
193
|
return requireBinding().persistCompletedMapRows(input);
|
|
194
194
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Tool output processing utilities.
|
|
3
3
|
*
|
|
4
4
|
* Tools return data in varied shapes — some return flat objects, others
|
|
5
|
-
* wrap results in `{
|
|
5
|
+
* wrap results in `{ output: { body: [...] } }` envelopes, and list
|
|
6
6
|
* responses can be nested at different depths. This module provides
|
|
7
7
|
* utilities to normalize, extract, and persist tool outputs.
|
|
8
8
|
*
|
|
@@ -33,7 +33,7 @@ import { join } from 'node:path';
|
|
|
33
33
|
* @example
|
|
34
34
|
* ```typescript
|
|
35
35
|
* const conversion = tryConvertToList(toolResponse, {
|
|
36
|
-
* listExtractorPaths: ['people', '
|
|
36
|
+
* listExtractorPaths: ['people', 'output.body'],
|
|
37
37
|
* });
|
|
38
38
|
* if (conversion) {
|
|
39
39
|
* console.log(`Found ${conversion.rows.length} rows via ${conversion.strategy}`);
|
|
@@ -50,7 +50,7 @@ export type ListConversionResult = {
|
|
|
50
50
|
* - `'auto_detected'` — found via recursive DFS (longest array wins)
|
|
51
51
|
*/
|
|
52
52
|
strategy: 'configured_paths' | 'auto_detected';
|
|
53
|
-
/** Dotted path to where the list was found (e.g. `"
|
|
53
|
+
/** Dotted path to where the list was found (e.g. `"output.body"`, `"people"`). */
|
|
54
54
|
sourcePath: string | null;
|
|
55
55
|
};
|
|
56
56
|
|
|
@@ -75,7 +75,7 @@ function normalizeScalarString(value: unknown): string | null {
|
|
|
75
75
|
* Traverse a nested object by a dotted path string.
|
|
76
76
|
*
|
|
77
77
|
* @param root - Object to traverse
|
|
78
|
-
* @param dottedPath - Path like `"
|
|
78
|
+
* @param dottedPath - Path like `"output.body.items"`
|
|
79
79
|
* @returns Value at the path, or `null` if not found
|
|
80
80
|
*
|
|
81
81
|
* @example
|
|
@@ -109,10 +109,29 @@ function normalizeRows(value: unknown): Array<Record<string, unknown>> | null {
|
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
111
|
* Generate candidate root objects to search for lists.
|
|
112
|
-
* Tries: raw payload → payload.result → payload.result.data.
|
|
112
|
+
* Tries: raw payload → V2 toolExecutionResult.toolOutput.raw → legacy payload.output.body → legacy payload.result → legacy payload.result.data.
|
|
113
113
|
*/
|
|
114
114
|
function candidateRoots(payload: unknown): Array<{ path: string | null; value: unknown }> {
|
|
115
115
|
const roots: Array<{ path: string | null; value: unknown }> = [{ path: null, value: payload }];
|
|
116
|
+
if (isPlainObject(payload) && isPlainObject(payload.toolExecutionResult)) {
|
|
117
|
+
roots.push({ path: 'toolExecutionResult', value: payload.toolExecutionResult });
|
|
118
|
+
const toolOutput = payload.toolExecutionResult.toolOutput;
|
|
119
|
+
if (isPlainObject(toolOutput)) {
|
|
120
|
+
roots.push({ path: 'toolExecutionResult.toolOutput', value: toolOutput });
|
|
121
|
+
if (Object.prototype.hasOwnProperty.call(toolOutput, 'raw')) {
|
|
122
|
+
roots.push({
|
|
123
|
+
path: 'toolExecutionResult.toolOutput.raw',
|
|
124
|
+
value: toolOutput.raw,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (isPlainObject(payload) && isPlainObject(payload.output)) {
|
|
130
|
+
roots.push({ path: 'output', value: payload.output });
|
|
131
|
+
if (Object.prototype.hasOwnProperty.call(payload.output, 'body')) {
|
|
132
|
+
roots.push({ path: 'output.body', value: payload.output.body });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
116
135
|
if (isPlainObject(payload) && isPlainObject(payload.result)) {
|
|
117
136
|
roots.push({ path: 'result', value: payload.result });
|
|
118
137
|
if (isPlainObject(payload.result.data)) {
|
|
@@ -167,7 +186,7 @@ function findBestArrayCandidate(
|
|
|
167
186
|
* ## Extraction strategy
|
|
168
187
|
*
|
|
169
188
|
* 1. **Configured paths** — If `listExtractorPaths` is provided, each path is
|
|
170
|
-
* tried against multiple candidate roots (raw payload, `.result`, `.result.data`).
|
|
189
|
+
* tried against multiple candidate roots (raw payload, `.output.body`, legacy `.result`, legacy `.result.data`).
|
|
171
190
|
* First match wins.
|
|
172
191
|
*
|
|
173
192
|
* 2. **Auto-detection** — If no configured path matches, recursively searches
|
|
@@ -344,7 +363,7 @@ export function writeCsvOutputFile(
|
|
|
344
363
|
/**
|
|
345
364
|
* Extract scalar (non-nested) fields from a tool response for summary display.
|
|
346
365
|
*
|
|
347
|
-
* Searches through candidate roots (raw → `.result` → `.result.data`) and
|
|
366
|
+
* Searches through candidate roots (raw → `.output.body` → legacy `.result` → legacy `.result.data`) and
|
|
348
367
|
* returns the first set of scalar fields found. Useful for displaying a
|
|
349
368
|
* quick summary of single-record responses.
|
|
350
369
|
*
|
|
@@ -103,17 +103,51 @@ export interface ToolDefinition {
|
|
|
103
103
|
inputSchema?: Record<string, unknown>;
|
|
104
104
|
/** JSON Schema describing the tool's output shape. */
|
|
105
105
|
outputSchema?: Record<string, unknown>;
|
|
106
|
-
/**
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
106
|
+
/** Copyable play-runtime guidance for V2 tool execution results. */
|
|
107
|
+
usageGuidance?: {
|
|
108
|
+
execute?: string;
|
|
109
|
+
toolExecutionResult?: {
|
|
110
|
+
type?: 'ToolExecutionResult';
|
|
111
|
+
toolOutput?: {
|
|
112
|
+
raw?: string | { path?: string; schema?: Record<string, unknown> };
|
|
113
|
+
meta?: string | { path?: string; schema?: Record<string, unknown> };
|
|
114
|
+
};
|
|
115
|
+
meta?: string;
|
|
116
|
+
extractedLists?: Array<{
|
|
117
|
+
name: string;
|
|
118
|
+
expression: string;
|
|
119
|
+
details?: {
|
|
120
|
+
strategy?: string;
|
|
121
|
+
rawToolOutputPaths?: string[];
|
|
122
|
+
candidatePaths?: string[];
|
|
123
|
+
};
|
|
124
|
+
}> | Record<string, {
|
|
125
|
+
expression: string;
|
|
126
|
+
details?: {
|
|
127
|
+
strategy?: string;
|
|
128
|
+
rawToolOutputPaths?: string[];
|
|
129
|
+
candidatePaths?: string[];
|
|
130
|
+
};
|
|
131
|
+
}>;
|
|
132
|
+
extractedValues?: Array<{
|
|
133
|
+
name: string;
|
|
134
|
+
expression: string;
|
|
135
|
+
details?: {
|
|
136
|
+
strategy?: string;
|
|
137
|
+
rawToolOutputPaths?: string[];
|
|
138
|
+
candidatePaths?: string[];
|
|
139
|
+
};
|
|
140
|
+
}> | Record<string, {
|
|
141
|
+
expression: string;
|
|
142
|
+
details?: {
|
|
143
|
+
strategy?: string;
|
|
144
|
+
rawToolOutputPaths?: string[];
|
|
145
|
+
candidatePaths?: string[];
|
|
146
|
+
};
|
|
147
|
+
}>;
|
|
148
|
+
[key: string]: unknown;
|
|
149
|
+
};
|
|
150
|
+
};
|
|
117
151
|
/** Search relevance score returned by ranked tool search. */
|
|
118
152
|
search_score?: number;
|
|
119
153
|
/** Search match snippets returned by ranked tool search. */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.1.
|
|
2
|
-
export const SDK_API_CONTRACT = "2026-05-
|
|
1
|
+
export const SDK_VERSION = "0.1.35";
|
|
2
|
+
export const SDK_API_CONTRACT = "2026-05-v2-tool-result-contract";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export const CLOUDFLARE_DURABLE_OBJECT_CODE_UPDATED_ERROR =
|
|
2
|
+
'Durable Object reset because its code was updated.';
|
|
3
|
+
|
|
4
|
+
export const PLATFORM_DEPLOY_INTERRUPTED_MESSAGE =
|
|
5
|
+
'Run interrupted by a platform deploy and was not retried automatically. Re-run the same command; the input is unchanged.';
|
|
6
|
+
|
|
7
|
+
export type PlayRunFailureDetails = {
|
|
8
|
+
code: string;
|
|
9
|
+
phase: string;
|
|
10
|
+
message: string;
|
|
11
|
+
retryable: boolean | null;
|
|
12
|
+
cause?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function toErrorText(error: unknown): string {
|
|
16
|
+
if (error instanceof Error) {
|
|
17
|
+
return error.message;
|
|
18
|
+
}
|
|
19
|
+
return String(error);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isCloudflareDurableObjectCodeUpdatedError(
|
|
23
|
+
error: unknown,
|
|
24
|
+
): boolean {
|
|
25
|
+
return toErrorText(error).includes(
|
|
26
|
+
CLOUDFLARE_DURABLE_OBJECT_CODE_UPDATED_ERROR,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function normalizePlayRunFailure(
|
|
31
|
+
error: unknown,
|
|
32
|
+
): PlayRunFailureDetails {
|
|
33
|
+
const cause = toErrorText(error);
|
|
34
|
+
if (isCloudflareDurableObjectCodeUpdatedError(cause)) {
|
|
35
|
+
return {
|
|
36
|
+
code: 'PLATFORM_DEPLOY_INTERRUPTED',
|
|
37
|
+
phase: 'runtime',
|
|
38
|
+
message: PLATFORM_DEPLOY_INTERRUPTED_MESSAGE,
|
|
39
|
+
retryable: true,
|
|
40
|
+
cause: CLOUDFLARE_DURABLE_OBJECT_CODE_UPDATED_ERROR,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
code: 'RUN_FAILED',
|
|
45
|
+
phase: 'runtime',
|
|
46
|
+
message: cause,
|
|
47
|
+
retryable: null,
|
|
48
|
+
};
|
|
49
|
+
}
|