deepline 0.1.10 → 0.1.12

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.
Files changed (34) hide show
  1. package/README.md +4 -4
  2. package/dist/cli/index.js +509 -353
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/cli/index.mjs +513 -358
  5. package/dist/cli/index.mjs.map +1 -1
  6. package/dist/index.d.mts +250 -305
  7. package/dist/index.d.ts +250 -305
  8. package/dist/index.js +174 -286
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +174 -285
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +23 -13
  13. package/dist/repo/apps/play-runner-workers/src/entry.ts +581 -1220
  14. package/dist/repo/sdk/src/cli/commands/play.ts +381 -247
  15. package/dist/repo/sdk/src/cli/commands/tools.ts +1 -1
  16. package/dist/repo/sdk/src/cli/dataset-stats.ts +86 -12
  17. package/dist/repo/sdk/src/client.ts +54 -51
  18. package/dist/repo/sdk/src/index.ts +7 -16
  19. package/dist/repo/sdk/src/play.ts +122 -135
  20. package/dist/repo/sdk/src/plays/bundle-play-file.ts +6 -3
  21. package/dist/repo/sdk/src/tool-output.ts +0 -111
  22. package/dist/repo/sdk/src/types.ts +2 -0
  23. package/dist/repo/sdk/src/version.ts +1 -1
  24. package/dist/repo/sdk/src/worker-play-entry.ts +3 -0
  25. package/dist/repo/shared_libs/play-runtime/context.ts +510 -267
  26. package/dist/repo/shared_libs/play-runtime/csv-rename.ts +180 -0
  27. package/dist/repo/shared_libs/play-runtime/ctx-types.ts +13 -1
  28. package/dist/repo/shared_libs/play-runtime/tool-result.ts +139 -114
  29. package/dist/repo/shared_libs/plays/bundling/index.ts +68 -5
  30. package/dist/repo/shared_libs/plays/compiler-manifest.ts +1 -1
  31. package/dist/repo/shared_libs/plays/dataset.ts +1 -1
  32. package/dist/repo/shared_libs/plays/runtime-validation.ts +8 -28
  33. package/package.json +1 -1
  34. package/dist/repo/apps/play-runner-workers/src/runtime/tool-result.ts +0 -184
@@ -0,0 +1,180 @@
1
+ export type CsvRenameMap = Record<string, string | readonly string[]>;
2
+
3
+ export type CsvRenameOptions = {
4
+ columns?: CsvRenameMap;
5
+ rename?: CsvRenameMap;
6
+ required?: readonly string[];
7
+ };
8
+
9
+ const CSV_PROJECTED_FIELDS = Symbol.for('deepline.play.csv.projected_fields');
10
+ const CSV_PROJECTED_FIELDS_KEY = '__deeplineCsvProjectedFields';
11
+
12
+ type ProjectedRow = Record<string, unknown> & {
13
+ [CSV_PROJECTED_FIELDS]?: ReadonlySet<string>;
14
+ [CSV_PROJECTED_FIELDS_KEY]?: readonly string[];
15
+ };
16
+
17
+ function normalizeCsvHeader(header: string): string {
18
+ return header
19
+ .trim()
20
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
21
+ .toLowerCase()
22
+ .replace(/[^a-z0-9]+/g, '_')
23
+ .replace(/^_+|_+$/g, '');
24
+ }
25
+
26
+ function readString(value: unknown): string {
27
+ if (typeof value === 'string') return value.trim();
28
+ if (typeof value === 'number' && Number.isFinite(value)) return String(value);
29
+ return '';
30
+ }
31
+
32
+ function buildRowLookup(row: Record<string, unknown>): Map<string, unknown> {
33
+ const lookup = new Map<string, unknown>();
34
+ for (const [field, value] of Object.entries(row)) {
35
+ lookup.set(field, value);
36
+ lookup.set(normalizeCsvHeader(field), value);
37
+ }
38
+ return lookup;
39
+ }
40
+
41
+ function sourceAliases(target: string, aliases: string | readonly string[]) {
42
+ return [target, ...(Array.isArray(aliases) ? aliases : [aliases])];
43
+ }
44
+
45
+ export function applyCsvRenameProjection<T extends Record<string, unknown>>(
46
+ rows: readonly T[],
47
+ options?: CsvRenameOptions,
48
+ ): Array<T & Record<string, unknown>> {
49
+ const aliases = {
50
+ ...(options?.rename ?? {}),
51
+ ...(options?.columns ?? {}),
52
+ };
53
+ if (Object.keys(aliases).length === 0) {
54
+ return [...rows];
55
+ }
56
+
57
+ const required = new Set(options?.required ?? []);
58
+ return rows.map((row, index) => {
59
+ const lookup = buildRowLookup(row);
60
+ const projectedFields = new Set<string>();
61
+ const projected: Record<string, unknown> = { ...row };
62
+
63
+ for (const [target, sourceNames] of Object.entries(aliases)) {
64
+ let selected: unknown;
65
+ for (const alias of sourceAliases(target, sourceNames)) {
66
+ const exact = lookup.get(alias);
67
+ const normalized = lookup.get(normalizeCsvHeader(alias));
68
+ const candidate = exact ?? normalized;
69
+ if (readString(candidate)) {
70
+ selected = candidate;
71
+ break;
72
+ }
73
+ }
74
+
75
+ if (readString(selected)) {
76
+ if (!Object.prototype.hasOwnProperty.call(row, target)) {
77
+ Object.defineProperty(projected, target, {
78
+ value: selected,
79
+ enumerable: false,
80
+ configurable: true,
81
+ writable: true,
82
+ });
83
+ projectedFields.add(target);
84
+ } else {
85
+ projected[target] = selected;
86
+ }
87
+ } else if (required.has(target)) {
88
+ throw new Error(
89
+ `ctx.csv(..., { rename }) row ${index + 1} is missing required column "${target}".`,
90
+ );
91
+ }
92
+ }
93
+
94
+ Object.defineProperty(projected, CSV_PROJECTED_FIELDS, {
95
+ value: projectedFields,
96
+ enumerable: false,
97
+ configurable: true,
98
+ });
99
+ return projected as T & Record<string, unknown>;
100
+ });
101
+ }
102
+
103
+ export function cloneCsvAliasedRow<T extends Record<string, unknown>>(
104
+ row: T,
105
+ extra?: Record<string, unknown>,
106
+ ): Record<string, unknown> {
107
+ const cloned: Record<string, unknown> = { ...row, ...(extra ?? {}) };
108
+ const projectedFields = getCsvProjectedFields(row);
109
+ if (!projectedFields?.size) {
110
+ return cloned;
111
+ }
112
+
113
+ const clonedProjectedFields = new Set<string>();
114
+ for (const field of projectedFields) {
115
+ if (Object.prototype.hasOwnProperty.call(cloned, field)) {
116
+ continue;
117
+ }
118
+ const descriptor = Object.getOwnPropertyDescriptor(row, field);
119
+ if (descriptor) {
120
+ Object.defineProperty(cloned, field, {
121
+ ...descriptor,
122
+ enumerable: false,
123
+ configurable: true,
124
+ });
125
+ } else {
126
+ Object.defineProperty(cloned, field, {
127
+ value: row[field],
128
+ enumerable: false,
129
+ configurable: true,
130
+ writable: true,
131
+ });
132
+ }
133
+ clonedProjectedFields.add(field);
134
+ }
135
+
136
+ if (clonedProjectedFields.size > 0) {
137
+ Object.defineProperty(cloned, CSV_PROJECTED_FIELDS, {
138
+ value: clonedProjectedFields,
139
+ enumerable: false,
140
+ configurable: true,
141
+ });
142
+ }
143
+ return cloned;
144
+ }
145
+
146
+ export function stripCsvProjectedFields<T extends Record<string, unknown>>(
147
+ row: T,
148
+ ): T {
149
+ const projectedFields = getCsvProjectedFields(row);
150
+ if (!projectedFields?.size) return row;
151
+ const stripped = { ...row };
152
+ for (const field of projectedFields) {
153
+ delete stripped[field];
154
+ }
155
+ delete stripped[CSV_PROJECTED_FIELDS_KEY];
156
+ return stripped as T;
157
+ }
158
+
159
+ export function getCsvProjectedFields(
160
+ row: Record<string, unknown>,
161
+ ): ReadonlySet<string> | null {
162
+ const symbolFields = (row as ProjectedRow)[CSV_PROJECTED_FIELDS];
163
+ if (symbolFields?.size) return symbolFields;
164
+ const serializedFields = (row as ProjectedRow)[CSV_PROJECTED_FIELDS_KEY];
165
+ if (!Array.isArray(serializedFields) || serializedFields.length === 0) {
166
+ return null;
167
+ }
168
+ return new Set(serializedFields.filter((field) => typeof field === 'string'));
169
+ }
170
+
171
+ export function stripCsvProjectionMetadata<T extends Record<string, unknown>>(
172
+ row: T,
173
+ ): T {
174
+ if (!Object.prototype.hasOwnProperty.call(row, CSV_PROJECTED_FIELDS_KEY)) {
175
+ return row;
176
+ }
177
+ const stripped = { ...row };
178
+ delete stripped[CSV_PROJECTED_FIELDS_KEY];
179
+ return stripped as T;
180
+ }
@@ -103,6 +103,9 @@ export interface WaterfallOptions {
103
103
 
104
104
  export interface CsvOptions {
105
105
  description?: string;
106
+ columns?: Record<string, string | readonly string[]>;
107
+ rename?: Record<string, string | readonly string[]>;
108
+ required?: readonly string[];
106
109
  }
107
110
 
108
111
  export interface MapOptions<TItem = Record<string, unknown>> {
@@ -115,6 +118,12 @@ export interface MapOptions<TItem = Record<string, unknown>> {
115
118
  * inside the same window still hit the cache. Daily refreshes use 86400.
116
119
  */
117
120
  staleAfterSeconds?: number;
121
+ /**
122
+ * Maximum row resolvers to execute concurrently. Use 1 when a map calls a
123
+ * map-backed child play via ctx.runPlay, because those child tables share
124
+ * durable row identity.
125
+ */
126
+ concurrency?: number;
118
127
  /**
119
128
  * Optional stable key per row. When provided, row identity is derived from
120
129
  * the selected input field(s) or returned value instead of hashing the full
@@ -139,7 +148,10 @@ export type MapDefinitionOptions<TItem = Record<string, unknown>> = Omit<
139
148
  'description'
140
149
  >;
141
150
 
142
- export type MapRunOptions = Pick<MapOptions, 'description'>;
151
+ export type MapRunOptions<TItem = Record<string, unknown>> = Pick<
152
+ MapOptions<TItem>,
153
+ 'description' | 'staleAfterSeconds' | 'concurrency' | 'key'
154
+ >;
143
155
 
144
156
  export interface ToolCallOptions {
145
157
  description?: string;
@@ -6,7 +6,6 @@ export type ToolResultExecutionMetadata = {
6
6
  };
7
7
 
8
8
  export type ToolResultTargetMetadata = {
9
- value: unknown;
10
9
  path: string;
11
10
  };
12
11
 
@@ -16,6 +15,19 @@ export type ToolResultListMetadata = {
16
15
  keys: Record<string, string>;
17
16
  };
18
17
 
18
+ export type ToolExtractedValue<T = unknown> = {
19
+ path: string;
20
+ get(): T | null;
21
+ };
22
+
23
+ export type ToolResultEnvelope<
24
+ TData = unknown,
25
+ TMeta = Record<string, unknown>,
26
+ > = {
27
+ data: TData;
28
+ meta?: TMeta;
29
+ };
30
+
19
31
  export type ToolResultMetadata = {
20
32
  toolId: string;
21
33
  execution: ToolResultExecutionMetadata;
@@ -30,30 +42,30 @@ export type ToolResultMetadataInput = {
30
42
  listIdentityGetters?: Record<string, readonly string[]>;
31
43
  };
32
44
 
33
- export type ToolExecuteResult<TResult = unknown> = {
45
+ export type ToolExecuteResult<
46
+ TData = unknown,
47
+ TMeta = Record<string, unknown>,
48
+ > = {
34
49
  status: string;
35
- result: TResult;
36
- _metadata: ToolResultMetadata;
37
- get<T = unknown>(target: string): T | null;
38
- getEmail(): string | null;
39
- getPhone(): string | null;
40
- getLinkedin(): string | null;
41
- list<T = Record<string, unknown>>(name?: string): T[] | null;
42
- listPick<const TKeys extends readonly string[]>(
43
- keys: TKeys,
44
- name?: string,
45
- ): Array<Record<TKeys[number], unknown>> | null;
46
- listKeys(name?: string): Record<string, string>;
50
+ result: ToolResultEnvelope<TData, TMeta>;
51
+ extracted: Record<string, ToolExtractedValue>;
52
+ lists: Record<
53
+ string,
54
+ ToolResultListMetadata & {
55
+ get(): Record<string, unknown>[];
56
+ }
57
+ >;
47
58
  };
48
59
 
49
60
  type PathSegment = string | number;
50
61
 
51
62
  const TARGET_FALLBACK_KEYS: Record<string, readonly RegExp[]> = {
52
- email: [/^email$/i, /email/i],
63
+ email: [/^email$/i, /^address$/i, /email/i],
53
64
  phone: [/^phone$/i, /mobile/i, /phone/i, /telephone/i],
54
65
  linkedin: [/^linkedin_url$/i, /^linkedin$/i, /linkedin/i],
55
66
  domain: [/^domain$/i, /company_domain/i, /domain/i],
56
67
  status: [/^email_status$/i, /^status$/i],
68
+ email_status: [/^email_status$/i, /^status$/i],
57
69
  };
58
70
 
59
71
  function isRecord(value: unknown): value is Record<string, unknown> {
@@ -114,6 +126,22 @@ function getAtPath(root: unknown, path: string): unknown {
114
126
  return current;
115
127
  }
116
128
 
129
+ function asResultPath(path: string): string {
130
+ const normalized = path.trim().replace(/^result\./, '');
131
+ return normalized ? `result.${normalized}` : 'result';
132
+ }
133
+
134
+ function toResultEnvelope(value: unknown): ToolResultEnvelope {
135
+ if (isRecord(value) && 'data' in value) {
136
+ const envelope: ToolResultEnvelope = { data: value.data };
137
+ if ('meta' in value) {
138
+ envelope.meta = value.meta as Record<string, unknown>;
139
+ }
140
+ return envelope;
141
+ }
142
+ return { data: value };
143
+ }
144
+
117
145
  function normalizeRows(value: unknown): Record<string, unknown>[] | null {
118
146
  if (!Array.isArray(value)) return null;
119
147
  return value.map((entry) => (isRecord(entry) ? entry : { value: entry }));
@@ -124,11 +152,13 @@ function findFirstTargetByPath(
124
152
  paths: readonly string[] | undefined,
125
153
  ): ToolResultTargetMetadata | null {
126
154
  for (const path of paths ?? []) {
127
- const normalizedPath = String(path || '').trim().replace(/^result\./, '');
155
+ const normalizedPath = String(path || '')
156
+ .trim()
157
+ .replace(/^result\./, '');
128
158
  if (!normalizedPath) continue;
129
159
  const value = getAtPath(result, normalizedPath);
130
160
  if (isMeaningfulValue(value)) {
131
- return { value, path: normalizedPath };
161
+ return { path: asResultPath(normalizedPath) };
132
162
  }
133
163
  }
134
164
  return null;
@@ -157,12 +187,18 @@ function findFirstTargetByKey(
157
187
  new RegExp(`^${target}$`, 'i'),
158
188
  ];
159
189
  for (const [key, value] of Object.entries(result)) {
160
- if (patterns.some((pattern) => pattern.test(key)) && isMeaningfulValue(value)) {
161
- return { value, path: pathToString([...path, key]) };
190
+ if (
191
+ patterns.some((pattern) => pattern.test(key)) &&
192
+ isMeaningfulValue(value)
193
+ ) {
194
+ return { path: asResultPath(pathToString([...path, key])) };
162
195
  }
163
196
  }
164
197
  for (const [key, value] of Object.entries(result)) {
165
- const found = findFirstTargetByKey(value, target, depth + 1, [...path, key]);
198
+ const found = findFirstTargetByKey(value, target, depth + 1, [
199
+ ...path,
200
+ key,
201
+ ]);
166
202
  if (found) return found;
167
203
  }
168
204
  return null;
@@ -177,12 +213,23 @@ function resolveListRows(
177
213
  { path: string; rows: Record<string, unknown>[] }
178
214
  > = {};
179
215
  for (const rawPath of listExtractorPaths ?? []) {
180
- const path = String(rawPath || '').trim().replace(/^result\./, '');
216
+ const path = String(rawPath || '')
217
+ .trim()
218
+ .replace(/^result\./, '');
181
219
  if (!path) continue;
182
- const rows = normalizeRows(getAtPath(result, path));
220
+ let resolvedPath = path;
221
+ let rows = normalizeRows(getAtPath(result, resolvedPath));
222
+ if (!rows && !path.startsWith('data.')) {
223
+ resolvedPath = `data.${path}`;
224
+ rows = normalizeRows(getAtPath(result, resolvedPath));
225
+ }
183
226
  if (!rows) continue;
184
- const name = path.split('.').filter(Boolean).at(-1)?.replace(/\[\d+\]$/, '');
185
- lists[name || path] = { path, rows };
227
+ const name = resolvedPath
228
+ .split('.')
229
+ .filter(Boolean)
230
+ .at(-1)
231
+ ?.replace(/\[\d+\]$/, '');
232
+ lists[name || resolvedPath] = { path: resolvedPath, rows };
186
233
  }
187
234
  return lists;
188
235
  }
@@ -194,9 +241,15 @@ function deriveListKeys(input: {
194
241
  listIdentityGetters?: Record<string, readonly string[]>;
195
242
  }): Record<string, string> {
196
243
  const keys: Record<string, string> = {};
197
- for (const [target, paths] of Object.entries(input.listIdentityGetters ?? {})) {
244
+ for (const [target, paths] of Object.entries(
245
+ input.listIdentityGetters ?? {},
246
+ )) {
198
247
  const firstPath = paths
199
- .map((rawPath) => String(rawPath || '').trim().replace(/^result\./, ''))
248
+ .map((rawPath) =>
249
+ String(rawPath || '')
250
+ .trim()
251
+ .replace(/^result\./, ''),
252
+ )
200
253
  .find(Boolean);
201
254
  if (firstPath) {
202
255
  keys[target] = firstPath;
@@ -207,13 +260,19 @@ function deriveListKeys(input: {
207
260
  }
208
261
 
209
262
  const listPrefix = input.listPath.replace(/\[\d+\]$/, '');
210
- for (const [target, paths] of Object.entries(input.resultIdentityGetters ?? {})) {
263
+ for (const [target, paths] of Object.entries(
264
+ input.resultIdentityGetters ?? {},
265
+ )) {
211
266
  for (const rawPath of paths) {
212
- const path = String(rawPath || '').trim().replace(/^result\./, '');
267
+ const path = String(rawPath || '')
268
+ .trim()
269
+ .replace(/^result\./, '');
213
270
  if (!path) continue;
214
271
  const directPrefix = `${listPrefix}.`;
215
272
  if (path.startsWith(directPrefix)) {
216
- keys[target] = path.slice(directPrefix.length).replace(/^\[\d+\]\.?/, '');
273
+ keys[target] = path
274
+ .slice(directPrefix.length)
275
+ .replace(/^\[\d+\]\.?/, '');
217
276
  break;
218
277
  }
219
278
  const indexedPrefix = `${listPrefix}[0].`;
@@ -249,6 +308,11 @@ function buildTargets(
249
308
  );
250
309
  if (fromMetadata) {
251
310
  targets[target] = fromMetadata;
311
+ continue;
312
+ }
313
+ const fallback = findFirstTargetByKey(result, target);
314
+ if (fallback) {
315
+ targets[target] = fallback;
252
316
  }
253
317
  }
254
318
  if (metadataTargets.size > 0) return targets;
@@ -268,7 +332,7 @@ function buildLists(
268
332
  const resolved = resolveListRows(result, metadata.listExtractorPaths);
269
333
  for (const [name, list] of Object.entries(resolved)) {
270
334
  lists[name] = {
271
- path: list.path,
335
+ path: asResultPath(list.path),
272
336
  count: list.rows.length,
273
337
  keys: deriveListKeys({
274
338
  listPath: list.path,
@@ -281,80 +345,61 @@ function buildLists(
281
345
  return lists;
282
346
  }
283
347
 
348
+ function attachDescriptorMethods<TResult>(
349
+ wrapper: ToolExecuteResult<TResult>,
350
+ ): ToolExecuteResult<TResult> {
351
+ for (const descriptor of Object.values(wrapper.extracted)) {
352
+ Object.defineProperty(descriptor, 'get', {
353
+ configurable: true,
354
+ enumerable: false,
355
+ value: () => {
356
+ const value = getAtPath(wrapper, descriptor.path);
357
+ return isMeaningfulValue(value) ? value : null;
358
+ },
359
+ });
360
+ }
361
+
362
+ for (const descriptor of Object.values(wrapper.lists)) {
363
+ Object.defineProperty(descriptor, 'get', {
364
+ configurable: true,
365
+ enumerable: false,
366
+ value: () => normalizeRows(getAtPath(wrapper, descriptor.path)) ?? [],
367
+ });
368
+ }
369
+
370
+ return wrapper;
371
+ }
372
+
284
373
  export function createToolExecuteResult<TResult = unknown>(input: {
285
374
  status: string;
286
375
  result: TResult;
287
376
  metadata: ToolResultMetadataInput;
288
377
  execution: ToolResultExecutionMetadata;
289
378
  }): ToolExecuteResult<TResult> {
290
- const targets = buildTargets(input.result, input.metadata.resultIdentityGetters);
291
- const lists = buildLists(input.result, input.metadata);
292
- const wrapper = {
379
+ void input.execution;
380
+ const result = toResultEnvelope(input.result) as ToolResultEnvelope<TResult>;
381
+ const extracted = buildTargets(result, input.metadata.resultIdentityGetters);
382
+ const lists = buildLists(result, input.metadata);
383
+ const wrapper: ToolExecuteResult<TResult> = {
293
384
  status: input.status,
294
- result: input.result,
295
- _metadata: {
296
- toolId: input.metadata.toolId,
297
- execution: input.execution,
298
- targets,
299
- lists,
300
- },
301
- get<T = unknown>(target: string): T | null {
302
- return (this._metadata.targets[target]?.value as T | undefined) ?? null;
303
- },
304
- getEmail(): string | null {
305
- const value = this.get('email');
306
- return typeof value === 'string' && value.trim() ? value : null;
307
- },
308
- getPhone(): string | null {
309
- const value = this.get('phone');
310
- return typeof value === 'string' && value.trim() ? value : null;
311
- },
312
- getLinkedin(): string | null {
313
- const value = this.get('linkedin');
314
- return typeof value === 'string' && value.trim() ? value : null;
315
- },
316
- list<T = Record<string, unknown>>(name?: string): T[] | null {
317
- const entryName = name ?? Object.keys(this._metadata.lists)[0];
318
- if (!entryName) return null;
319
- const list = this._metadata.lists[entryName];
320
- if (!list) return null;
321
- return (normalizeRows(getAtPath(this.result, list.path)) as T[] | null) ?? null;
322
- },
323
- listPick<const TKeys extends readonly string[]>(
324
- keys: TKeys,
325
- name?: string,
326
- ): Array<Record<TKeys[number], unknown>> | null {
327
- const entryName = name ?? Object.keys(this._metadata.lists)[0];
328
- if (!entryName) return null;
329
- const listMetadata = this._metadata.lists[entryName];
330
- if (!listMetadata) return null;
331
- const rows = normalizeRows(getAtPath(this.result, listMetadata.path));
332
- if (!rows) return null;
333
- return rows.map((row) => {
334
- const picked: Record<string, unknown> = {};
335
- for (const key of keys) {
336
- const path = listMetadata.keys[key];
337
- picked[key] = path ? getAtPath(row, path) ?? null : null;
338
- }
339
- return picked as Record<TKeys[number], unknown>;
340
- });
341
- },
342
- listKeys(name?: string): Record<string, string> {
343
- const entryName = name ?? Object.keys(this._metadata.lists)[0];
344
- if (!entryName) return {};
345
- return this._metadata.lists[entryName]?.keys ?? {};
346
- },
347
- } satisfies ToolExecuteResult<TResult>;
348
- return wrapper;
385
+ result,
386
+ extracted: extracted as Record<string, ToolExtractedValue>,
387
+ lists: lists as ToolExecuteResult<TResult>['lists'],
388
+ };
389
+ return attachDescriptorMethods(wrapper);
349
390
  }
350
391
 
351
- export function isToolExecuteResult(value: unknown): value is ToolExecuteResult {
392
+ export function isToolExecuteResult(
393
+ value: unknown,
394
+ ): value is ToolExecuteResult {
352
395
  return (
353
396
  isRecord(value) &&
354
397
  typeof value.status === 'string' &&
355
- '_metadata' in value &&
356
- isRecord(value._metadata) &&
357
- 'result' in value
398
+ 'result' in value &&
399
+ isRecord(value.result) &&
400
+ 'data' in value.result &&
401
+ 'extracted' in value &&
402
+ isRecord(value.extracted)
358
403
  );
359
404
  }
360
405
 
@@ -362,26 +407,6 @@ export function cloneToolExecuteResultWithExecution<TResult>(
362
407
  value: ToolExecuteResult<TResult>,
363
408
  execution: ToolResultExecutionMetadata,
364
409
  ): ToolExecuteResult<TResult> {
365
- return createToolExecuteResult({
366
- status: value.status,
367
- result: value.result,
368
- metadata: {
369
- toolId: value._metadata.toolId,
370
- resultIdentityGetters: Object.fromEntries(
371
- Object.entries(value._metadata.targets).map(([target, info]) => [
372
- target,
373
- [info.path],
374
- ]),
375
- ),
376
- listExtractorPaths: Object.values(value._metadata.lists).map(
377
- (list) => list.path,
378
- ),
379
- listIdentityGetters: Object.fromEntries(
380
- Object.values(value._metadata.lists)
381
- .flatMap((list) => Object.entries(list.keys))
382
- .map(([target, path]) => [target, [path]]),
383
- ),
384
- },
385
- execution,
386
- });
410
+ void execution;
411
+ return attachDescriptorMethods(value);
387
412
  }