deepline 0.1.301 → 0.1.302
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/bundling-sources/sdk/src/client.ts +8 -0
- package/dist/bundling-sources/sdk/src/errors.ts +57 -15
- package/dist/bundling-sources/sdk/src/http.ts +82 -5
- package/dist/bundling-sources/sdk/src/index.ts +4 -0
- package/dist/bundling-sources/sdk/src/play.ts +29 -1
- package/dist/bundling-sources/sdk/src/release.ts +5 -3
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +120 -14
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +10 -0
- package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +59 -11
- package/dist/bundling-sources/shared_libs/play-runtime/execution-ledger-store.ts +3 -3
- package/dist/bundling-sources/shared_libs/play-runtime/execution-plan.ts +0 -15
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-actions.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +136 -36
- package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +17 -12
- package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +210 -5
- package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +4 -0
- package/dist/bundling-sources/shared_libs/plays/artifact-contract-version.ts +6 -0
- package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +4 -0
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +159 -12
- package/dist/bundling-sources/shared_libs/plays/contracts.ts +69 -1
- package/dist/bundling-sources/shared_libs/tool-execution-error.ts +428 -0
- package/dist/cli/index.js +501 -179
- package/dist/cli/index.mjs +501 -179
- package/dist/index.d.mts +39 -18
- package/dist/index.d.ts +39 -18
- package/dist/index.js +394 -59
- package/dist/index.mjs +391 -59
- package/dist/plays/bundle-play-file.d.mts +4 -2
- package/dist/plays/bundle-play-file.d.ts +4 -2
- package/dist/plays/bundle-play-file.mjs +116 -19
- package/dist/{compiler-manifest-BjopNIqx.d.mts → tool-execution-error-9mH4i-mJ.d.mts} +79 -1
- package/dist/{compiler-manifest-BjopNIqx.d.ts → tool-execution-error-9mH4i-mJ.d.ts} +79 -1
- package/package.json +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/completed-receipt-cache.ts +0 -166
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LEGACY_TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
|
|
3
|
+
SUPPORTED_TOOL_EXECUTION_ERROR_SCHEMA_VERSIONS,
|
|
4
|
+
TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
|
|
5
|
+
type ToolExecutionErrorSchemaVersion,
|
|
6
|
+
} from '../tool-execution-error';
|
|
7
|
+
import { CURRENT_PLAY_ARTIFACT_CONTRACT_VERSION } from './artifact-contract-version';
|
|
8
|
+
|
|
1
9
|
export type PlayContractSource = 'ad_hoc' | 'draft' | 'published';
|
|
2
10
|
|
|
3
11
|
export type PlayRuntimeFeature =
|
|
@@ -7,7 +15,7 @@ export type PlayRuntimeFeature =
|
|
|
7
15
|
| 'packaged_files';
|
|
8
16
|
|
|
9
17
|
export const PLAY_PUBLIC_API_VERSION = 1;
|
|
10
|
-
export const PLAY_ARTIFACT_VERSION =
|
|
18
|
+
export const PLAY_ARTIFACT_VERSION = CURRENT_PLAY_ARTIFACT_CONTRACT_VERSION;
|
|
11
19
|
export const PLAY_MIN_RUNNER_VERSION = 1;
|
|
12
20
|
export const PLAY_RUNTIME_FEATURES: PlayRuntimeFeature[] = [
|
|
13
21
|
'artifact_storage',
|
|
@@ -22,10 +30,68 @@ export type PlayContractCompatibilitySnapshot = {
|
|
|
22
30
|
minRunnerVersion: number;
|
|
23
31
|
runtimeFeatures: PlayRuntimeFeature[];
|
|
24
32
|
runtimeBackend?: string | null;
|
|
33
|
+
/** Missing preserves the legacy contract used by artifacts stored before this field existed. */
|
|
34
|
+
toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
|
|
25
35
|
};
|
|
26
36
|
|
|
37
|
+
export type NormalizedPlayContractCompatibilitySnapshot =
|
|
38
|
+
PlayContractCompatibilitySnapshot & {
|
|
39
|
+
toolErrorSchemaVersion: ToolExecutionErrorSchemaVersion;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export class UnsupportedPlayToolErrorSchemaVersionError extends Error {
|
|
43
|
+
constructor(value: unknown) {
|
|
44
|
+
super(
|
|
45
|
+
`Unsupported Play tool error schema version ${String(value)}. Supported versions: ${SUPPORTED_TOOL_EXECUTION_ERROR_SCHEMA_VERSIONS.join(', ')}.`,
|
|
46
|
+
);
|
|
47
|
+
this.name = 'UnsupportedPlayToolErrorSchemaVersionError';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class InvalidPlayContractCompatibilityError extends Error {
|
|
52
|
+
constructor() {
|
|
53
|
+
super('Play artifact compatibility must be an object.');
|
|
54
|
+
this.name = 'InvalidPlayContractCompatibilityError';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Normalize the artifact-pinned compatibility facts without regenerating them.
|
|
60
|
+
* A missing field is the historical production contract, not an opt-in to the
|
|
61
|
+
* current runtime behavior.
|
|
62
|
+
*/
|
|
63
|
+
export function normalizePlayContractCompatibility(
|
|
64
|
+
compatibility: PlayContractCompatibilitySnapshot | null | undefined,
|
|
65
|
+
): NormalizedPlayContractCompatibilitySnapshot {
|
|
66
|
+
if (
|
|
67
|
+
!compatibility ||
|
|
68
|
+
typeof compatibility !== 'object' ||
|
|
69
|
+
Array.isArray(compatibility)
|
|
70
|
+
) {
|
|
71
|
+
throw new InvalidPlayContractCompatibilityError();
|
|
72
|
+
}
|
|
73
|
+
const toolErrorSchemaVersion =
|
|
74
|
+
compatibility.toolErrorSchemaVersion ??
|
|
75
|
+
LEGACY_TOOL_EXECUTION_ERROR_SCHEMA_VERSION;
|
|
76
|
+
if (
|
|
77
|
+
!SUPPORTED_TOOL_EXECUTION_ERROR_SCHEMA_VERSIONS.includes(
|
|
78
|
+
toolErrorSchemaVersion as ToolExecutionErrorSchemaVersion,
|
|
79
|
+
)
|
|
80
|
+
) {
|
|
81
|
+
throw new UnsupportedPlayToolErrorSchemaVersionError(
|
|
82
|
+
toolErrorSchemaVersion,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
...compatibility,
|
|
87
|
+
toolErrorSchemaVersion:
|
|
88
|
+
toolErrorSchemaVersion as ToolExecutionErrorSchemaVersion,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
27
92
|
export function buildPlayContractCompatibility(input?: {
|
|
28
93
|
runtimeBackend?: string | null;
|
|
94
|
+
toolErrorSchemaVersion?: ToolExecutionErrorSchemaVersion;
|
|
29
95
|
}): PlayContractCompatibilitySnapshot {
|
|
30
96
|
return {
|
|
31
97
|
apiVersion: PLAY_PUBLIC_API_VERSION,
|
|
@@ -33,6 +99,8 @@ export function buildPlayContractCompatibility(input?: {
|
|
|
33
99
|
minRunnerVersion: PLAY_MIN_RUNNER_VERSION,
|
|
34
100
|
runtimeFeatures: [...PLAY_RUNTIME_FEATURES],
|
|
35
101
|
runtimeBackend: input?.runtimeBackend ?? null,
|
|
102
|
+
toolErrorSchemaVersion:
|
|
103
|
+
input?.toolErrorSchemaVersion ?? TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
|
|
36
104
|
};
|
|
37
105
|
}
|
|
38
106
|
|
|
@@ -0,0 +1,428 @@
|
|
|
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
|
+
export type ToolExecutionErrorOrigin =
|
|
24
|
+
| 'caller'
|
|
25
|
+
| 'provider'
|
|
26
|
+
| 'deepline'
|
|
27
|
+
| 'unknown';
|
|
28
|
+
|
|
29
|
+
export type ToolExecutionErrorCategory =
|
|
30
|
+
| 'validation'
|
|
31
|
+
| 'authentication'
|
|
32
|
+
| 'authorization'
|
|
33
|
+
| 'rate_limit'
|
|
34
|
+
| 'network'
|
|
35
|
+
| 'upstream'
|
|
36
|
+
| 'billing'
|
|
37
|
+
| 'conflict'
|
|
38
|
+
| 'internal'
|
|
39
|
+
| 'unknown';
|
|
40
|
+
|
|
41
|
+
export type ToolExecutionNetworkKind =
|
|
42
|
+
| 'timeout'
|
|
43
|
+
| 'dns'
|
|
44
|
+
| 'connect'
|
|
45
|
+
| 'reset'
|
|
46
|
+
| 'unavailable'
|
|
47
|
+
| 'unknown';
|
|
48
|
+
|
|
49
|
+
export type ToolExecutionNetworkScope =
|
|
50
|
+
| 'client_to_deepline'
|
|
51
|
+
| 'runtime_to_deepline'
|
|
52
|
+
| 'deepline_to_provider';
|
|
53
|
+
|
|
54
|
+
export type ToolExecutionFailureV1 = {
|
|
55
|
+
schemaVersion: typeof TOOL_EXECUTION_ERROR_SCHEMA_VERSION;
|
|
56
|
+
toolId: string;
|
|
57
|
+
provider: string | null;
|
|
58
|
+
operation: string | null;
|
|
59
|
+
code: string | null;
|
|
60
|
+
origin: ToolExecutionErrorOrigin;
|
|
61
|
+
category: ToolExecutionErrorCategory;
|
|
62
|
+
retryable: boolean;
|
|
63
|
+
statusCode: number | null;
|
|
64
|
+
requestId: string | null;
|
|
65
|
+
retryAfterMs: number | null;
|
|
66
|
+
networkKind: ToolExecutionNetworkKind | null;
|
|
67
|
+
networkScope: ToolExecutionNetworkScope | null;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export type ToolExecutionErrorOptions = Omit<
|
|
71
|
+
ToolExecutionFailureV1,
|
|
72
|
+
'schemaVersion'
|
|
73
|
+
> & {
|
|
74
|
+
/**
|
|
75
|
+
* Local diagnostic context inherited from DeeplineError. This is not part of
|
|
76
|
+
* the portable failure payload and is intentionally omitted by serialization.
|
|
77
|
+
*/
|
|
78
|
+
details?: Record<string, unknown>;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export type ProviderTransientErrorCategory =
|
|
82
|
+
| 'rate_limit'
|
|
83
|
+
| 'network'
|
|
84
|
+
| 'upstream';
|
|
85
|
+
|
|
86
|
+
function nativeInstanceOf(constructor: object, value: unknown): boolean {
|
|
87
|
+
return Reflect.apply(Function.prototype[Symbol.hasInstance], constructor, [
|
|
88
|
+
value,
|
|
89
|
+
]) as boolean;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function hasBrand(value: unknown, brand: symbol): boolean {
|
|
93
|
+
return (
|
|
94
|
+
typeof value === 'object' &&
|
|
95
|
+
value !== null &&
|
|
96
|
+
(value as Record<symbol, unknown>)[brand] === true
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function applyBrand(value: object, brand: symbol): void {
|
|
101
|
+
if (hasBrand(value, brand)) return;
|
|
102
|
+
Object.defineProperty(value, brand, {
|
|
103
|
+
configurable: false,
|
|
104
|
+
enumerable: false,
|
|
105
|
+
writable: false,
|
|
106
|
+
value: true,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Base error class shared by the SDK and play runtime.
|
|
112
|
+
*
|
|
113
|
+
* The global brand preserves `instanceof DeeplineError` when a bundled play
|
|
114
|
+
* and the runtime load separate physical copies of this module.
|
|
115
|
+
*/
|
|
116
|
+
export class DeeplineError extends Error {
|
|
117
|
+
constructor(
|
|
118
|
+
message: string,
|
|
119
|
+
public statusCode?: number,
|
|
120
|
+
public code?: string,
|
|
121
|
+
public details?: Record<string, unknown>,
|
|
122
|
+
) {
|
|
123
|
+
super(message);
|
|
124
|
+
this.name = 'DeeplineError';
|
|
125
|
+
applyBrand(this, DEEPLINE_ERROR_BRAND);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static [Symbol.hasInstance](value: unknown): boolean {
|
|
129
|
+
// Subclasses inherit static methods. Delegate subclass checks to the native
|
|
130
|
+
// prototype algorithm so AuthError never accidentally matches ConfigError.
|
|
131
|
+
if (this !== DeeplineError) return nativeInstanceOf(this, value);
|
|
132
|
+
return hasBrand(value, DEEPLINE_ERROR_BRAND);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* A failed `tools.execute` call with stable, allowlisted provenance.
|
|
138
|
+
*
|
|
139
|
+
* `retryable` means Deepline's delivery/idempotency contract says it is safe
|
|
140
|
+
* to repeat the same semantic call. It does not describe durable receipt
|
|
141
|
+
* repairability and does not make arbitrary side-effecting fallbacks safe.
|
|
142
|
+
*/
|
|
143
|
+
export class ToolExecutionError extends DeeplineError {
|
|
144
|
+
readonly toolId: string;
|
|
145
|
+
readonly provider: string | null;
|
|
146
|
+
readonly operation: string | null;
|
|
147
|
+
readonly origin: ToolExecutionErrorOrigin;
|
|
148
|
+
readonly category: ToolExecutionErrorCategory;
|
|
149
|
+
readonly retryable: boolean;
|
|
150
|
+
readonly requestId: string | null;
|
|
151
|
+
readonly retryAfterMs: number | null;
|
|
152
|
+
readonly networkKind: ToolExecutionNetworkKind | null;
|
|
153
|
+
readonly networkScope: ToolExecutionNetworkScope | null;
|
|
154
|
+
|
|
155
|
+
constructor(message: string, options: ToolExecutionErrorOptions) {
|
|
156
|
+
super(
|
|
157
|
+
message,
|
|
158
|
+
options.statusCode ?? undefined,
|
|
159
|
+
options.code ?? undefined,
|
|
160
|
+
options.details,
|
|
161
|
+
);
|
|
162
|
+
this.name = 'ToolExecutionError';
|
|
163
|
+
this.toolId = options.toolId;
|
|
164
|
+
this.provider = options.provider;
|
|
165
|
+
this.operation = options.operation;
|
|
166
|
+
this.origin = options.origin;
|
|
167
|
+
this.category = options.category;
|
|
168
|
+
this.retryable = options.retryable;
|
|
169
|
+
this.requestId = options.requestId;
|
|
170
|
+
this.retryAfterMs = options.retryAfterMs;
|
|
171
|
+
this.networkKind = options.networkKind;
|
|
172
|
+
this.networkScope = options.networkScope;
|
|
173
|
+
applyBrand(this, TOOL_EXECUTION_ERROR_BRAND);
|
|
174
|
+
if (isProviderTransientFailure(options)) {
|
|
175
|
+
applyBrand(this, PROVIDER_TRANSIENT_ERROR_BRAND);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static [Symbol.hasInstance](value: unknown): boolean {
|
|
180
|
+
if (this !== ToolExecutionError) return nativeInstanceOf(this, value);
|
|
181
|
+
return hasBrand(value, TOOL_EXECUTION_ERROR_BRAND);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Brands a compatibility subclass (notably SDK ToolRateLimitError) as a tool
|
|
187
|
+
* failure without changing its existing prototype chain.
|
|
188
|
+
*/
|
|
189
|
+
export function brandAsToolExecutionError(value: object): void {
|
|
190
|
+
applyBrand(value, TOOL_EXECUTION_ERROR_BRAND);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function isProviderTransientFailure(input: {
|
|
194
|
+
origin: ToolExecutionErrorOrigin;
|
|
195
|
+
category: ToolExecutionErrorCategory;
|
|
196
|
+
retryable: boolean;
|
|
197
|
+
}): input is {
|
|
198
|
+
origin: 'provider';
|
|
199
|
+
category: ProviderTransientErrorCategory;
|
|
200
|
+
retryable: boolean;
|
|
201
|
+
} {
|
|
202
|
+
return (
|
|
203
|
+
input.origin === 'provider' &&
|
|
204
|
+
(input.category === 'rate_limit' ||
|
|
205
|
+
input.category === 'network' ||
|
|
206
|
+
input.category === 'upstream')
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* A provider-owned transient failure that is safe to handle as an empty
|
|
212
|
+
* waterfall leg. Validation, auth, billing, Deepline, and unknown failures
|
|
213
|
+
* never satisfy this type.
|
|
214
|
+
*/
|
|
215
|
+
export class ProviderTransientError extends ToolExecutionError {
|
|
216
|
+
override readonly origin = 'provider' as const;
|
|
217
|
+
declare readonly category: ProviderTransientErrorCategory;
|
|
218
|
+
|
|
219
|
+
constructor(
|
|
220
|
+
message: string,
|
|
221
|
+
options: Omit<ToolExecutionErrorOptions, 'origin' | 'category'> & {
|
|
222
|
+
category: ProviderTransientErrorCategory;
|
|
223
|
+
},
|
|
224
|
+
) {
|
|
225
|
+
super(message, {
|
|
226
|
+
...options,
|
|
227
|
+
origin: 'provider',
|
|
228
|
+
category: options.category,
|
|
229
|
+
});
|
|
230
|
+
this.name = 'ProviderTransientError';
|
|
231
|
+
this.category = options.category;
|
|
232
|
+
applyBrand(this, PROVIDER_TRANSIENT_ERROR_BRAND);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
static [Symbol.hasInstance](value: unknown): boolean {
|
|
236
|
+
if (this !== ProviderTransientError) return nativeInstanceOf(this, value);
|
|
237
|
+
return hasBrand(value, PROVIDER_TRANSIENT_ERROR_BRAND);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** Brand an internal compatibility error after its normalized fields exist. */
|
|
242
|
+
export function brandAsProviderTransientError(value: object): void {
|
|
243
|
+
applyBrand(value, PROVIDER_TRANSIENT_ERROR_BRAND);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function boundedString(
|
|
247
|
+
value: unknown,
|
|
248
|
+
maxLength = MAX_IDENTIFIER_LENGTH,
|
|
249
|
+
): string | null {
|
|
250
|
+
if (typeof value !== 'string') return null;
|
|
251
|
+
const normalized = value.trim();
|
|
252
|
+
return normalized ? normalized.slice(0, maxLength) : null;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function finiteNonNegativeInteger(value: unknown): number | null {
|
|
256
|
+
return typeof value === 'number' &&
|
|
257
|
+
Number.isFinite(value) &&
|
|
258
|
+
value >= 0 &&
|
|
259
|
+
Number.isInteger(value)
|
|
260
|
+
? value
|
|
261
|
+
: null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function normalizeToolExecutionOrigin(
|
|
265
|
+
value: unknown,
|
|
266
|
+
input?: { provider?: string | null; operation?: string | null },
|
|
267
|
+
): ToolExecutionErrorOrigin {
|
|
268
|
+
const normalized = boundedString(value)?.toLowerCase();
|
|
269
|
+
if (normalized === 'caller') return 'caller';
|
|
270
|
+
if (normalized === 'provider' || normalized === 'provider_network') {
|
|
271
|
+
return 'provider';
|
|
272
|
+
}
|
|
273
|
+
// Older integration adapters use "upstream" for a provider-owned failure.
|
|
274
|
+
// Only accept that alias when the execution boundary identifies the provider
|
|
275
|
+
// action; an unscoped upstream error fails closed.
|
|
276
|
+
if (
|
|
277
|
+
normalized === 'upstream' &&
|
|
278
|
+
boundedString(input?.provider) &&
|
|
279
|
+
boundedString(input?.operation)
|
|
280
|
+
) {
|
|
281
|
+
return 'provider';
|
|
282
|
+
}
|
|
283
|
+
if (
|
|
284
|
+
normalized === 'deepline' ||
|
|
285
|
+
normalized === 'deepline_billing' ||
|
|
286
|
+
normalized === 'deepline_rate_limit' ||
|
|
287
|
+
normalized === 'internal' ||
|
|
288
|
+
normalized === 'server'
|
|
289
|
+
) {
|
|
290
|
+
return 'deepline';
|
|
291
|
+
}
|
|
292
|
+
if (normalized === 'provider_account') return 'provider';
|
|
293
|
+
return 'unknown';
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function normalizeToolExecutionCategory(
|
|
297
|
+
value: unknown,
|
|
298
|
+
): ToolExecutionErrorCategory {
|
|
299
|
+
switch (boundedString(value)?.toLowerCase()) {
|
|
300
|
+
case 'validation':
|
|
301
|
+
case 'authorization':
|
|
302
|
+
case 'rate_limit':
|
|
303
|
+
case 'network':
|
|
304
|
+
case 'upstream':
|
|
305
|
+
case 'billing':
|
|
306
|
+
case 'conflict':
|
|
307
|
+
case 'internal':
|
|
308
|
+
return boundedString(value)!.toLowerCase() as ToolExecutionErrorCategory;
|
|
309
|
+
case 'authentication':
|
|
310
|
+
case 'provider_auth':
|
|
311
|
+
case 'provider_account':
|
|
312
|
+
return 'authentication';
|
|
313
|
+
case 'execution':
|
|
314
|
+
case 'parse':
|
|
315
|
+
case 'stub':
|
|
316
|
+
case 'internal_native_search_performance':
|
|
317
|
+
return 'internal';
|
|
318
|
+
default:
|
|
319
|
+
return 'unknown';
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function normalizeNetworkKind(value: unknown): ToolExecutionNetworkKind | null {
|
|
324
|
+
switch (boundedString(value)?.toLowerCase()) {
|
|
325
|
+
case 'timeout':
|
|
326
|
+
case 'dns':
|
|
327
|
+
case 'connect':
|
|
328
|
+
case 'reset':
|
|
329
|
+
case 'unavailable':
|
|
330
|
+
case 'unknown':
|
|
331
|
+
return boundedString(value)!.toLowerCase() as ToolExecutionNetworkKind;
|
|
332
|
+
default:
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function normalizeNetworkScope(
|
|
338
|
+
value: unknown,
|
|
339
|
+
): ToolExecutionNetworkScope | null {
|
|
340
|
+
switch (boundedString(value)?.toLowerCase()) {
|
|
341
|
+
case 'client_to_deepline':
|
|
342
|
+
case 'runtime_to_deepline':
|
|
343
|
+
case 'deepline_to_provider':
|
|
344
|
+
return boundedString(value)!.toLowerCase() as ToolExecutionNetworkScope;
|
|
345
|
+
default:
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
351
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export function normalizeToolExecutionFailure(
|
|
355
|
+
value: unknown,
|
|
356
|
+
): ToolExecutionFailureV1 | null {
|
|
357
|
+
if (
|
|
358
|
+
!isRecord(value) ||
|
|
359
|
+
value.schemaVersion !== TOOL_EXECUTION_ERROR_SCHEMA_VERSION
|
|
360
|
+
) {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
const toolId = boundedString(value.toolId);
|
|
364
|
+
if (!toolId) return null;
|
|
365
|
+
const provider = boundedString(value.provider);
|
|
366
|
+
const operation = boundedString(value.operation);
|
|
367
|
+
const origin = normalizeToolExecutionOrigin(value.origin, {
|
|
368
|
+
provider,
|
|
369
|
+
operation,
|
|
370
|
+
});
|
|
371
|
+
const category = normalizeToolExecutionCategory(value.category);
|
|
372
|
+
const trustworthy =
|
|
373
|
+
origin !== 'unknown' &&
|
|
374
|
+
category !== 'unknown' &&
|
|
375
|
+
typeof value.retryable === 'boolean';
|
|
376
|
+
return {
|
|
377
|
+
schemaVersion: TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
|
|
378
|
+
toolId,
|
|
379
|
+
provider,
|
|
380
|
+
operation,
|
|
381
|
+
code: boundedString(value.code, MAX_CODE_LENGTH),
|
|
382
|
+
origin,
|
|
383
|
+
category,
|
|
384
|
+
retryable: trustworthy ? value.retryable === true : false,
|
|
385
|
+
statusCode: finiteNonNegativeInteger(value.statusCode),
|
|
386
|
+
requestId: boundedString(value.requestId),
|
|
387
|
+
retryAfterMs: finiteNonNegativeInteger(value.retryAfterMs),
|
|
388
|
+
networkKind: normalizeNetworkKind(value.networkKind),
|
|
389
|
+
networkScope: normalizeNetworkScope(value.networkScope),
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export function serializeToolExecutionFailure(
|
|
394
|
+
error: unknown,
|
|
395
|
+
): ToolExecutionFailureV1 | null {
|
|
396
|
+
if (!(error instanceof ToolExecutionError)) return null;
|
|
397
|
+
return normalizeToolExecutionFailure({
|
|
398
|
+
schemaVersion: TOOL_EXECUTION_ERROR_SCHEMA_VERSION,
|
|
399
|
+
toolId: error.toolId,
|
|
400
|
+
provider: error.provider,
|
|
401
|
+
operation: error.operation,
|
|
402
|
+
code: error.code ?? null,
|
|
403
|
+
origin: error.origin,
|
|
404
|
+
category: error.category,
|
|
405
|
+
retryable: error.retryable,
|
|
406
|
+
statusCode: error.statusCode ?? null,
|
|
407
|
+
requestId: error.requestId,
|
|
408
|
+
retryAfterMs: error.retryAfterMs,
|
|
409
|
+
networkKind: error.networkKind,
|
|
410
|
+
networkScope: error.networkScope,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export function deserializeToolExecutionFailure(
|
|
415
|
+
message: string,
|
|
416
|
+
value: unknown,
|
|
417
|
+
acceptedSchemaVersion: ToolExecutionErrorSchemaVersion,
|
|
418
|
+
): ToolExecutionError | null {
|
|
419
|
+
if (acceptedSchemaVersion === LEGACY_TOOL_EXECUTION_ERROR_SCHEMA_VERSION) {
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
const failure = normalizeToolExecutionFailure(value);
|
|
423
|
+
if (!failure) return null;
|
|
424
|
+
if (isProviderTransientFailure(failure)) {
|
|
425
|
+
return new ProviderTransientError(message, failure);
|
|
426
|
+
}
|
|
427
|
+
return new ToolExecutionError(message, failure);
|
|
428
|
+
}
|