deepline 0.3.45 → 0.3.47

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 (88) hide show
  1. package/dist/bundling-sources/sdk/src/client.ts +2 -3
  2. package/dist/bundling-sources/sdk/src/errors.ts +2 -2
  3. package/dist/bundling-sources/sdk/src/http.ts +1 -1
  4. package/dist/bundling-sources/sdk/src/play.ts +7 -10
  5. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +3 -3
  6. package/dist/bundling-sources/sdk/src/release.ts +3 -3
  7. package/dist/bundling-sources/sdk/src/version.ts +2 -2
  8. package/dist/bundling-sources/shared_libs/play-data-plane/contracts.ts +25 -0
  9. package/dist/bundling-sources/shared_libs/play-data-plane/index.ts +1 -0
  10. package/dist/bundling-sources/shared_libs/play-data-plane/sheet-contract.ts +1 -1
  11. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +19 -19
  12. package/dist/bundling-sources/shared_libs/play-runtime/backend.ts +5 -6
  13. package/dist/bundling-sources/shared_libs/play-runtime/cell-staleness.ts +1 -66
  14. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +11 -11
  15. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +3 -3
  16. package/dist/bundling-sources/shared_libs/play-runtime/dataset-id.ts +4 -3
  17. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +3 -4
  18. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +2 -2
  19. package/dist/bundling-sources/shared_libs/play-runtime/email-status.ts +1 -275
  20. package/dist/bundling-sources/shared_libs/play-runtime/execution-ledger-store.ts +1 -1
  21. package/dist/bundling-sources/shared_libs/play-runtime/extractor-targets.ts +1 -106
  22. package/dist/bundling-sources/shared_libs/play-runtime/gateway-postgres-admission.ts +1 -2
  23. package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +13 -4
  24. package/dist/bundling-sources/shared_libs/play-runtime/live-events.ts +1 -5
  25. package/dist/bundling-sources/shared_libs/play-runtime/map-row-identity.ts +2 -3
  26. package/dist/bundling-sources/shared_libs/play-runtime/map-row-outcome.ts +2 -1
  27. package/dist/bundling-sources/shared_libs/play-runtime/modal-runtime-config.ts +1 -1
  28. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +1 -1
  29. package/dist/bundling-sources/shared_libs/play-runtime/projection.ts +5 -5
  30. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +3 -3
  31. package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +1 -1
  32. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +1 -1
  33. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +4 -4
  34. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-modal-fallback.ts +3 -3
  35. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +8 -8
  36. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +1 -1
  37. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +4 -4
  38. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/local-process.ts +7 -7
  39. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +7 -7
  40. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/bundle.ts +13 -2
  41. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/index.ts +2 -2
  42. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runner-events.ts +1 -1
  43. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +1 -1
  44. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +2 -2
  45. package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +1 -1
  46. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +6 -3
  47. package/dist/bundling-sources/shared_libs/play-runtime/runtime-constants.ts +1 -1
  48. package/dist/bundling-sources/shared_libs/play-runtime/runtime-constraints.ts +1 -2
  49. package/dist/bundling-sources/shared_libs/play-runtime/runtime-env.ts +55 -0
  50. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runtime-limits.ts +1 -109
  51. package/dist/bundling-sources/shared_libs/play-runtime/step-program-dataset-builder.ts +1 -1
  52. package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +1 -1
  53. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +1 -1
  54. package/dist/bundling-sources/shared_libs/play-runtime/tool-execution-outcome.ts +6 -5
  55. package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +1 -1
  56. package/dist/bundling-sources/shared_libs/play-runtime/tool-result-types.ts +1 -206
  57. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +10 -7
  58. package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +1 -1
  59. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +8 -3
  60. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +4 -4
  61. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +3 -6
  62. package/dist/bundling-sources/shared_libs/plays/cell-staleness.ts +66 -0
  63. package/dist/bundling-sources/shared_libs/plays/compiler-manifest.ts +1 -1
  64. package/dist/bundling-sources/shared_libs/plays/contracts.ts +2 -2
  65. package/dist/bundling-sources/shared_libs/plays/core.ts +466 -0
  66. package/dist/bundling-sources/shared_libs/plays/email-status.ts +287 -0
  67. package/dist/bundling-sources/shared_libs/plays/extractor-targets.ts +106 -0
  68. package/dist/bundling-sources/shared_libs/plays/row-identity.ts +1 -3
  69. package/dist/bundling-sources/shared_libs/plays/runtime-constraints.ts +2 -0
  70. package/dist/bundling-sources/shared_libs/plays/runtime-validation.ts +4 -2
  71. package/dist/bundling-sources/shared_libs/plays/sandbox-runtime-limits.ts +109 -0
  72. package/dist/bundling-sources/shared_libs/plays/tool-execution-error.ts +624 -0
  73. package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +206 -0
  74. package/dist/bundling-sources/shared_libs/security/safe-outbound-fetch.ts +1 -1
  75. package/dist/cli/index.js +181 -169
  76. package/dist/cli/index.mjs +189 -170
  77. package/dist/{compiler-manifest-DwYe2C2S.d.mts → compiler-manifest-BuoqasqI.d.mts} +585 -540
  78. package/dist/{compiler-manifest-DwYe2C2S.d.ts → compiler-manifest-BuoqasqI.d.ts} +585 -540
  79. package/dist/index.d.mts +9 -2
  80. package/dist/index.d.ts +9 -2
  81. package/dist/index.js +47 -40
  82. package/dist/index.mjs +47 -40
  83. package/dist/install-integrity.json +13 -3
  84. package/dist/plays/bundle-play-file.d.mts +4 -61
  85. package/dist/plays/bundle-play-file.d.ts +4 -61
  86. package/dist/plays/bundle-play-file.mjs +157 -155
  87. package/package.json +9 -6
  88. /package/dist/bundling-sources/shared_libs/{play-runtime → plays}/tool-response-contract.ts +0 -0
@@ -0,0 +1,624 @@
1
+ const DEEPLINE_ERROR_BRAND = Symbol.for('deepline.error.v1');
2
+ export const TOOL_EXECUTION_ERROR_BRAND = Symbol.for(
3
+ 'deepline.tool-execution-error.v1',
4
+ );
5
+ const PROVIDER_TRANSIENT_ERROR_BRAND = Symbol.for(
6
+ 'deepline.provider-transient-error.v1',
7
+ );
8
+
9
+ export const LEGACY_TOOL_EXECUTION_ERROR_SCHEMA_VERSION = 0 as const;
10
+ export const TOOL_EXECUTION_ERROR_SCHEMA_VERSION = 1 as const;
11
+ export const SUPPORTED_TOOL_EXECUTION_ERROR_SCHEMA_VERSIONS = [
12
+ LEGACY_TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
13
+ TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
14
+ ] as const;
15
+ export type ToolExecutionErrorSchemaVersion =
16
+ (typeof SUPPORTED_TOOL_EXECUTION_ERROR_SCHEMA_VERSIONS)[number];
17
+ export const TOOL_EXECUTION_ERROR_SCHEMA_HEADER =
18
+ 'x-deepline-tool-error-schema';
19
+
20
+ const MAX_IDENTIFIER_LENGTH = 200;
21
+ const MAX_CODE_LENGTH = 160;
22
+
23
+ /**
24
+ * The boundary responsible for a failed tool call.
25
+ *
26
+ * Use `provider` to distinguish a provider answer from caller input and
27
+ * Deepline infrastructure. `unknown` fails closed and must not trigger a
28
+ * waterfall fallback.
29
+ *
30
+ * @sdkReference errors 020
31
+ */
32
+ export type ToolExecutionErrorOrigin =
33
+ | 'caller'
34
+ | 'provider'
35
+ | 'deepline'
36
+ | 'unknown';
37
+
38
+ /**
39
+ * The stable reason family for a failed tool call.
40
+ *
41
+ * Branch on this field only after narrowing to `ToolExecutionError`. Catch
42
+ * `ProviderTransientError` when the policy is simply “try the next read
43
+ * provider”; it is the safer and shorter waterfall contract.
44
+ *
45
+ * @sdkReference errors 030
46
+ */
47
+ export type ToolExecutionErrorCategory =
48
+ | 'validation'
49
+ | 'authentication'
50
+ | 'authorization'
51
+ | 'rate_limit'
52
+ | 'network'
53
+ | 'upstream'
54
+ | 'billing'
55
+ | 'conflict'
56
+ | 'internal'
57
+ | 'unknown';
58
+
59
+ /**
60
+ * The transport failure observed when `category` is `network`.
61
+ *
62
+ * This is `null` for failures that are not network failures.
63
+ *
64
+ * @sdkReference errors 040
65
+ */
66
+ export type ToolExecutionNetworkKind =
67
+ | 'timeout'
68
+ | 'dns'
69
+ | 'connect'
70
+ | 'reset'
71
+ | 'unavailable'
72
+ | 'unknown';
73
+
74
+ /**
75
+ * The request boundary on which a network failure occurred.
76
+ *
77
+ * `deepline_to_provider` is provider-side. Client and runtime scopes are
78
+ * Deepline transport failures and never qualify as provider fallthrough.
79
+ *
80
+ * @sdkReference errors 050
81
+ */
82
+ export type ToolExecutionNetworkScope =
83
+ | 'client_to_deepline'
84
+ | 'runtime_to_deepline'
85
+ | 'deepline_to_provider';
86
+
87
+ /**
88
+ * Portable version-1 `tool_error` payload.
89
+ *
90
+ * This allowlisted shape crosses the API, runtime, and SDK boundaries.
91
+ * `message` remains on the Error object and is deliberately not a policy
92
+ * field.
93
+ *
94
+ * @sdkReference errors 064
95
+ */
96
+ export type ToolExecutionFailureV1 = {
97
+ /** Payload version. */
98
+ schemaVersion: typeof TOOL_EXECUTION_ERROR_SCHEMA_VERSION;
99
+ /** Public tool id passed to `tools.execute`. */
100
+ toolId: string;
101
+ /** Provider responsible for the operation, or `null`. */
102
+ provider: string | null;
103
+ /** Provider operation name, or `null`. */
104
+ operation: string | null;
105
+ /** Stable machine-readable failure code, or `null`. */
106
+ code: string | null;
107
+ /** Boundary responsible for the failure. */
108
+ origin: ToolExecutionErrorOrigin;
109
+ /** Stable reason family. */
110
+ category: ToolExecutionErrorCategory;
111
+ /** Whether repeating the same semantic call is delivery-safe. */
112
+ retryable: boolean;
113
+ /** HTTP status when one exists, or `null`. */
114
+ statusCode: number | null;
115
+ /** Provider or Deepline request id, or `null`. */
116
+ requestId: string | null;
117
+ /** Suggested same-call retry delay in milliseconds, or `null`. */
118
+ retryAfterMs: number | null;
119
+ /** Network failure kind, or `null`. */
120
+ networkKind: ToolExecutionNetworkKind | null;
121
+ /** Network boundary that failed, or `null`. */
122
+ networkScope: ToolExecutionNetworkScope | null;
123
+ };
124
+
125
+ /**
126
+ * Constructor input for a structured tool failure.
127
+ *
128
+ * Deepline creates these values while decoding the versioned wire payload.
129
+ * Customer code normally reads `ToolExecutionError` fields instead of
130
+ * constructing an error.
131
+ *
132
+ * @sdkReference errors 065
133
+ */
134
+ export type ToolExecutionErrorOptions = Omit<
135
+ ToolExecutionFailureV1,
136
+ 'schemaVersion'
137
+ > & {
138
+ /**
139
+ * Local diagnostic context inherited from DeeplineError. This is not part of
140
+ * the portable failure payload and is intentionally omitted by serialization.
141
+ */
142
+ details?: Record<string, unknown>;
143
+ };
144
+
145
+ /**
146
+ * Provider-owned failure categories that may fall through to another read
147
+ * provider.
148
+ *
149
+ * @sdkReference errors 060
150
+ */
151
+ export type ProviderTransientErrorCategory =
152
+ | 'rate_limit'
153
+ | 'network'
154
+ | 'upstream';
155
+
156
+ function nativeInstanceOf(constructor: object, value: unknown): boolean {
157
+ return Reflect.apply(Function.prototype[Symbol.hasInstance], constructor, [
158
+ value,
159
+ ]) as boolean;
160
+ }
161
+
162
+ function hasBrand(value: unknown, brand: symbol): boolean {
163
+ return (
164
+ typeof value === 'object' &&
165
+ value !== null &&
166
+ (value as Record<symbol, unknown>)[brand] === true
167
+ );
168
+ }
169
+
170
+ function applyBrand(value: object, brand: symbol): void {
171
+ if (hasBrand(value, brand)) return;
172
+ Object.defineProperty(value, brand, {
173
+ configurable: false,
174
+ enumerable: false,
175
+ writable: false,
176
+ value: true,
177
+ });
178
+ }
179
+
180
+ /**
181
+ * Base error class shared by the SDK and play runtime.
182
+ *
183
+ * The global brand preserves `instanceof DeeplineError` when a bundled play
184
+ * and the runtime load separate physical copies of this module.
185
+ *
186
+ * @sdkReference errors 010
187
+ */
188
+ export class DeeplineError extends Error {
189
+ /** HTTP status when the failure crossed an HTTP boundary. */
190
+ statusCode?: number;
191
+ /** Stable machine-readable error code when one exists. */
192
+ code?: string;
193
+ /** Local diagnostic context; not a portable error contract. */
194
+ details?: Record<string, unknown>;
195
+
196
+ /**
197
+ * Construct a Deepline error.
198
+ *
199
+ * SDK and runtime code construct these errors. Application and Play code
200
+ * normally catches the public subclasses instead.
201
+ *
202
+ * @param message Human-readable failure summary.
203
+ * @param statusCode HTTP status when one exists.
204
+ * @param code Stable machine-readable code when one exists.
205
+ * @param details Local diagnostic context; never a portable error contract.
206
+ */
207
+ constructor(
208
+ message: string,
209
+ statusCode?: number,
210
+ code?: string,
211
+ details?: Record<string, unknown>,
212
+ ) {
213
+ super(message);
214
+ this.name = 'DeeplineError';
215
+ this.statusCode = statusCode;
216
+ this.code = code;
217
+ this.details = details;
218
+ applyBrand(this, DEEPLINE_ERROR_BRAND);
219
+ }
220
+
221
+ static [Symbol.hasInstance](value: unknown): boolean {
222
+ // Subclasses inherit static methods. Delegate subclass checks to the native
223
+ // prototype algorithm so AuthError never accidentally matches ConfigError.
224
+ if (this !== DeeplineError) return nativeInstanceOf(this, value);
225
+ return hasBrand(value, DEEPLINE_ERROR_BRAND);
226
+ }
227
+ }
228
+
229
+ /**
230
+ * A failed `tools.execute` call with stable, allowlisted provenance.
231
+ *
232
+ * `retryable` means Deepline's delivery/idempotency contract says it is safe
233
+ * to repeat the same semantic call. It does not describe durable receipt
234
+ * repairability and does not make arbitrary side-effecting fallbacks safe.
235
+ *
236
+ * In a Play, catch `ProviderTransientError` to continue a read waterfall and
237
+ * let every other `ToolExecutionError` remain loud. In an SDK client, catch
238
+ * this base class when you need structured diagnostics for every tool failure.
239
+ *
240
+ * @sdkReference errors 070
241
+ */
242
+ export class ToolExecutionError extends DeeplineError {
243
+ /** Public tool id passed to `tools.execute`. */
244
+ readonly toolId: string;
245
+ /** Provider responsible for the operation, or `null` when unattributed. */
246
+ readonly provider: string | null;
247
+ /** Provider operation name, or `null` when unavailable. */
248
+ readonly operation: string | null;
249
+ /** Boundary responsible for the failure. */
250
+ readonly origin: ToolExecutionErrorOrigin;
251
+ /** Stable reason family for policy and diagnostics. */
252
+ readonly category: ToolExecutionErrorCategory;
253
+ /**
254
+ * Whether repeating the same semantic call is delivery-safe.
255
+ *
256
+ * This does not mean the error may be ignored. Waterfall fallthrough is
257
+ * represented by `ProviderTransientError`.
258
+ */
259
+ readonly retryable: boolean;
260
+ /** Provider or Deepline request id, or `null` when unavailable. */
261
+ readonly requestId: string | null;
262
+ /** Suggested same-call retry delay in milliseconds, or `null`. */
263
+ readonly retryAfterMs: number | null;
264
+ /** Network failure kind, or `null` for non-network failures. */
265
+ readonly networkKind: ToolExecutionNetworkKind | null;
266
+ /** Network boundary that failed, or `null` for non-network failures. */
267
+ readonly networkScope: ToolExecutionNetworkScope | null;
268
+
269
+ /**
270
+ * Construct a structured tool error.
271
+ *
272
+ * Deepline constructs this from the versioned `tool_error` payload.
273
+ * Application and Play code should catch it rather than create it.
274
+ */
275
+ constructor(message: string, options: ToolExecutionErrorOptions) {
276
+ super(
277
+ message,
278
+ options.statusCode ?? undefined,
279
+ options.code ?? undefined,
280
+ options.details,
281
+ );
282
+ this.name = 'ToolExecutionError';
283
+ this.toolId = options.toolId;
284
+ this.provider = options.provider;
285
+ this.operation = options.operation;
286
+ this.origin = options.origin;
287
+ this.category = options.category;
288
+ this.retryable = options.retryable;
289
+ this.requestId = options.requestId;
290
+ this.retryAfterMs = options.retryAfterMs;
291
+ this.networkKind = options.networkKind;
292
+ this.networkScope = options.networkScope;
293
+ applyBrand(this, TOOL_EXECUTION_ERROR_BRAND);
294
+ if (isProviderTransientFailure(options)) {
295
+ applyBrand(this, PROVIDER_TRANSIENT_ERROR_BRAND);
296
+ }
297
+ }
298
+
299
+ static [Symbol.hasInstance](value: unknown): boolean {
300
+ if (this !== ToolExecutionError) return nativeInstanceOf(this, value);
301
+ return hasBrand(value, TOOL_EXECUTION_ERROR_BRAND);
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Brands a compatibility subclass (notably SDK ToolRateLimitError) as a tool
307
+ * failure without changing its existing prototype chain.
308
+ */
309
+ export function brandAsToolExecutionError(value: object): void {
310
+ applyBrand(value, TOOL_EXECUTION_ERROR_BRAND);
311
+ }
312
+
313
+ export function isProviderTransientFailure(input: {
314
+ origin: ToolExecutionErrorOrigin;
315
+ category: ToolExecutionErrorCategory;
316
+ retryable: boolean;
317
+ }): input is {
318
+ origin: 'provider';
319
+ category: ProviderTransientErrorCategory;
320
+ retryable: boolean;
321
+ } {
322
+ return (
323
+ input.origin === 'provider' &&
324
+ (input.category === 'rate_limit' ||
325
+ input.category === 'network' ||
326
+ input.category === 'upstream')
327
+ );
328
+ }
329
+
330
+ /**
331
+ * A provider-owned transient failure that is safe to handle as an empty
332
+ * waterfall leg. Validation, auth, billing, Deepline, and unknown failures
333
+ * never satisfy this type.
334
+ *
335
+ * `retryable` remains independent: it says whether the same semantic call may
336
+ * be repeated safely. Falling through to a different read provider depends on
337
+ * this class, not on `retryable`.
338
+ *
339
+ * @sdkReference errors 080
340
+ */
341
+ export class ProviderTransientError extends ToolExecutionError {
342
+ /** Provider attribution is guaranteed for this subtype. */
343
+ override readonly origin = 'provider' as const;
344
+ /** Provider failure category that made this error eligible for fallthrough. */
345
+ declare readonly category: ProviderTransientErrorCategory;
346
+
347
+ /** Constructed by Deepline when a provider-owned transient failure arrives. */
348
+ constructor(
349
+ message: string,
350
+ options: Omit<ToolExecutionErrorOptions, 'origin' | 'category'> & {
351
+ category: ProviderTransientErrorCategory;
352
+ },
353
+ ) {
354
+ super(message, {
355
+ ...options,
356
+ origin: 'provider',
357
+ category: options.category,
358
+ });
359
+ this.name = 'ProviderTransientError';
360
+ this.category = options.category;
361
+ applyBrand(this, PROVIDER_TRANSIENT_ERROR_BRAND);
362
+ }
363
+
364
+ static [Symbol.hasInstance](value: unknown): boolean {
365
+ if (this !== ProviderTransientError) return nativeInstanceOf(this, value);
366
+ return hasBrand(value, PROVIDER_TRANSIENT_ERROR_BRAND);
367
+ }
368
+ }
369
+
370
+ /** Why a provider cannot serve the current read request. */
371
+ export type ProviderUnavailableReason =
372
+ | ProviderTransientErrorCategory
373
+ | 'account_capacity'
374
+ | 'credentials_missing';
375
+
376
+ /**
377
+ * A provider failure that permits a read waterfall to try its next provider.
378
+ * A missing provider connection is included because another provider may still
379
+ * serve the read. Invalid credentials, caller input, and Deepline billing
380
+ * failures remain loud.
381
+ */
382
+ export type ProviderUnavailableError =
383
+ | ProviderTransientError
384
+ | (ToolExecutionError & {
385
+ readonly origin: 'provider';
386
+ readonly code: 'PROVIDER_ACCOUNT_CAPACITY';
387
+ })
388
+ | (ToolExecutionError & {
389
+ readonly origin: 'caller';
390
+ readonly code: 'INTEGRATION_CREDENTIALS_MISSING';
391
+ });
392
+
393
+ /**
394
+ * Return the provider-specific reason a read cannot run right now.
395
+ *
396
+ * `null` means this error must stay loud: it is caller input, an invalid
397
+ * customer credential, Deepline billing, or an internal failure. A missing
398
+ * provider connection is different: an explicit read waterfall may continue
399
+ * to a configured fallback and record the unavailable leg.
400
+ */
401
+ export function getProviderUnavailableReason(
402
+ error: unknown,
403
+ ): ProviderUnavailableReason | null {
404
+ if (error instanceof ProviderTransientError) return error.category;
405
+ if (
406
+ error instanceof ToolExecutionError &&
407
+ error.origin === 'provider' &&
408
+ error.code === 'PROVIDER_ACCOUNT_CAPACITY'
409
+ ) {
410
+ return 'account_capacity';
411
+ }
412
+ if (
413
+ error instanceof ToolExecutionError &&
414
+ error.origin === 'caller' &&
415
+ error.code === 'INTEGRATION_CREDENTIALS_MISSING'
416
+ ) {
417
+ return 'credentials_missing';
418
+ }
419
+ return null;
420
+ }
421
+
422
+ /**
423
+ * Whether a provider cannot serve this read right now.
424
+ *
425
+ * Use this in an explicit `catch` to advance a read-only waterfall. For
426
+ * diagnostics, use `getProviderUnavailableReason(error)`.
427
+ */
428
+ export function isProviderUnavailable(
429
+ error: unknown,
430
+ ): error is ProviderUnavailableError {
431
+ return getProviderUnavailableReason(error) !== null;
432
+ }
433
+
434
+ /** @deprecated Use isProviderUnavailable. */
435
+ export const isProviderWaterfallUnavailableError = isProviderUnavailable;
436
+
437
+ /** Brand an internal compatibility error after its normalized fields exist. */
438
+ export function brandAsProviderTransientError(value: object): void {
439
+ applyBrand(value, PROVIDER_TRANSIENT_ERROR_BRAND);
440
+ }
441
+
442
+ function boundedString(
443
+ value: unknown,
444
+ maxLength = MAX_IDENTIFIER_LENGTH,
445
+ ): string | null {
446
+ if (typeof value !== 'string') return null;
447
+ const normalized = value.trim();
448
+ return normalized ? normalized.slice(0, maxLength) : null;
449
+ }
450
+
451
+ function finiteNonNegativeInteger(value: unknown): number | null {
452
+ return typeof value === 'number' &&
453
+ Number.isFinite(value) &&
454
+ value >= 0 &&
455
+ Number.isInteger(value)
456
+ ? value
457
+ : null;
458
+ }
459
+
460
+ export function normalizeToolExecutionOrigin(
461
+ value: unknown,
462
+ input?: { provider?: string | null; operation?: string | null },
463
+ ): ToolExecutionErrorOrigin {
464
+ const normalized = boundedString(value)?.toLowerCase();
465
+ if (normalized === 'caller') return 'caller';
466
+ if (normalized === 'provider' || normalized === 'provider_network') {
467
+ return 'provider';
468
+ }
469
+ // Older integration adapters use "upstream" for a provider-owned failure.
470
+ // Only accept that alias when the execution boundary identifies the provider
471
+ // action; an unscoped upstream error fails closed.
472
+ if (
473
+ normalized === 'upstream' &&
474
+ boundedString(input?.provider) &&
475
+ boundedString(input?.operation)
476
+ ) {
477
+ return 'provider';
478
+ }
479
+ if (
480
+ normalized === 'deepline' ||
481
+ normalized === 'deepline_billing' ||
482
+ normalized === 'deepline_rate_limit' ||
483
+ normalized === 'internal' ||
484
+ normalized === 'server'
485
+ ) {
486
+ return 'deepline';
487
+ }
488
+ if (normalized === 'provider_account') return 'provider';
489
+ return 'unknown';
490
+ }
491
+
492
+ export function normalizeToolExecutionCategory(
493
+ value: unknown,
494
+ ): ToolExecutionErrorCategory {
495
+ switch (boundedString(value)?.toLowerCase()) {
496
+ case 'validation':
497
+ case 'authorization':
498
+ case 'rate_limit':
499
+ case 'network':
500
+ case 'upstream':
501
+ case 'billing':
502
+ case 'conflict':
503
+ case 'internal':
504
+ return boundedString(value)!.toLowerCase() as ToolExecutionErrorCategory;
505
+ case 'authentication':
506
+ case 'provider_auth':
507
+ case 'provider_account':
508
+ return 'authentication';
509
+ case 'execution':
510
+ case 'parse':
511
+ case 'stub':
512
+ case 'internal_native_search_performance':
513
+ return 'internal';
514
+ default:
515
+ return 'unknown';
516
+ }
517
+ }
518
+
519
+ function normalizeNetworkKind(value: unknown): ToolExecutionNetworkKind | null {
520
+ switch (boundedString(value)?.toLowerCase()) {
521
+ case 'timeout':
522
+ case 'dns':
523
+ case 'connect':
524
+ case 'reset':
525
+ case 'unavailable':
526
+ case 'unknown':
527
+ return boundedString(value)!.toLowerCase() as ToolExecutionNetworkKind;
528
+ default:
529
+ return null;
530
+ }
531
+ }
532
+
533
+ function normalizeNetworkScope(
534
+ value: unknown,
535
+ ): ToolExecutionNetworkScope | null {
536
+ switch (boundedString(value)?.toLowerCase()) {
537
+ case 'client_to_deepline':
538
+ case 'runtime_to_deepline':
539
+ case 'deepline_to_provider':
540
+ return boundedString(value)!.toLowerCase() as ToolExecutionNetworkScope;
541
+ default:
542
+ return null;
543
+ }
544
+ }
545
+
546
+ function isRecord(value: unknown): value is Record<string, unknown> {
547
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
548
+ }
549
+
550
+ export function normalizeToolExecutionFailure(
551
+ value: unknown,
552
+ ): ToolExecutionFailureV1 | null {
553
+ if (
554
+ !isRecord(value) ||
555
+ value.schemaVersion !== TOOL_EXECUTION_ERROR_SCHEMA_VERSION
556
+ ) {
557
+ return null;
558
+ }
559
+ const toolId = boundedString(value.toolId);
560
+ if (!toolId) return null;
561
+ const provider = boundedString(value.provider);
562
+ const operation = boundedString(value.operation);
563
+ const origin = normalizeToolExecutionOrigin(value.origin, {
564
+ provider,
565
+ operation,
566
+ });
567
+ const category = normalizeToolExecutionCategory(value.category);
568
+ const trustworthy =
569
+ origin !== 'unknown' &&
570
+ category !== 'unknown' &&
571
+ typeof value.retryable === 'boolean';
572
+ return {
573
+ schemaVersion: TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
574
+ toolId,
575
+ provider,
576
+ operation,
577
+ code: boundedString(value.code, MAX_CODE_LENGTH),
578
+ origin,
579
+ category,
580
+ retryable: trustworthy ? value.retryable === true : false,
581
+ statusCode: finiteNonNegativeInteger(value.statusCode),
582
+ requestId: boundedString(value.requestId),
583
+ retryAfterMs: finiteNonNegativeInteger(value.retryAfterMs),
584
+ networkKind: normalizeNetworkKind(value.networkKind),
585
+ networkScope: normalizeNetworkScope(value.networkScope),
586
+ };
587
+ }
588
+
589
+ export function serializeToolExecutionFailure(
590
+ error: unknown,
591
+ ): ToolExecutionFailureV1 | null {
592
+ if (!(error instanceof ToolExecutionError)) return null;
593
+ return normalizeToolExecutionFailure({
594
+ schemaVersion: TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
595
+ toolId: error.toolId,
596
+ provider: error.provider,
597
+ operation: error.operation,
598
+ code: error.code ?? null,
599
+ origin: error.origin,
600
+ category: error.category,
601
+ retryable: error.retryable,
602
+ statusCode: error.statusCode ?? null,
603
+ requestId: error.requestId,
604
+ retryAfterMs: error.retryAfterMs,
605
+ networkKind: error.networkKind,
606
+ networkScope: error.networkScope,
607
+ });
608
+ }
609
+
610
+ export function deserializeToolExecutionFailure(
611
+ message: string,
612
+ value: unknown,
613
+ acceptedSchemaVersion: ToolExecutionErrorSchemaVersion,
614
+ ): ToolExecutionError | null {
615
+ if (acceptedSchemaVersion === LEGACY_TOOL_EXECUTION_ERROR_SCHEMA_VERSION) {
616
+ return null;
617
+ }
618
+ const failure = normalizeToolExecutionFailure(value);
619
+ if (!failure) return null;
620
+ if (isProviderTransientFailure(failure)) {
621
+ return new ProviderTransientError(message, failure);
622
+ }
623
+ return new ToolExecutionError(message, failure);
624
+ }