@agent-os-sdk/client 0.3.15 → 0.4.1
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/client/config.d.ts +49 -0
- package/dist/client/config.d.ts.map +1 -0
- package/dist/client/config.js +62 -0
- package/dist/client/pagination.d.ts +105 -0
- package/dist/client/pagination.d.ts.map +1 -0
- package/dist/client/pagination.js +117 -0
- package/dist/client/raw.d.ts +67 -2
- package/dist/client/raw.d.ts.map +1 -1
- package/dist/client/raw.js +78 -17
- package/dist/client/retry.d.ts +37 -0
- package/dist/client/retry.d.ts.map +1 -0
- package/dist/client/retry.js +108 -0
- package/dist/client/timeout.d.ts +26 -0
- package/dist/client/timeout.d.ts.map +1 -0
- package/dist/client/timeout.js +51 -0
- package/dist/errors/factory.d.ts +20 -0
- package/dist/errors/factory.d.ts.map +1 -0
- package/dist/errors/factory.js +97 -0
- package/dist/errors/index.d.ts +210 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +283 -0
- package/dist/index.d.ts +37 -29
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +48 -22
- package/dist/modules/audit.d.ts +27 -4
- package/dist/modules/audit.d.ts.map +1 -1
- package/dist/modules/audit.js +58 -2
- package/dist/modules/builder.d.ts +6 -0
- package/dist/modules/builder.d.ts.map +1 -1
- package/dist/modules/checkpoints.d.ts +1 -1
- package/dist/modules/checkpoints.d.ts.map +1 -1
- package/dist/modules/info.d.ts +49 -0
- package/dist/modules/info.d.ts.map +1 -1
- package/dist/modules/info.js +66 -0
- package/dist/modules/members.d.ts +50 -2
- package/dist/modules/members.d.ts.map +1 -1
- package/dist/modules/members.js +61 -0
- package/dist/modules/runs.d.ts +103 -0
- package/dist/modules/runs.d.ts.map +1 -1
- package/dist/modules/runs.js +258 -0
- package/dist/modules/tenants.d.ts +4 -1
- package/dist/modules/tenants.d.ts.map +1 -1
- package/dist/modules/tenants.js +3 -0
- package/dist/modules/threads.d.ts +24 -0
- package/dist/modules/threads.d.ts.map +1 -1
- package/dist/modules/threads.js +48 -1
- package/dist/sse/client.d.ts.map +1 -1
- package/dist/sse/client.js +17 -5
- package/package.json +49 -50
- package/src/client/config.ts +100 -0
- package/src/client/pagination.ts +218 -0
- package/src/client/raw.ts +141 -20
- package/src/client/retry.ts +150 -0
- package/src/client/timeout.ts +59 -0
- package/src/errors/factory.ts +135 -0
- package/src/errors/index.ts +365 -0
- package/src/index.ts +97 -76
- package/src/modules/audit.ts +77 -6
- package/src/modules/builder.ts +7 -0
- package/src/modules/checkpoints.ts +1 -1
- package/src/modules/info.ts +108 -0
- package/src/modules/members.ts +80 -2
- package/src/modules/runs.ts +333 -0
- package/src/modules/tenants.ts +5 -2
- package/src/modules/threads.ts +57 -1
- package/src/sse/client.ts +21 -5
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent OS SDK - Timeout Logic
|
|
3
|
+
*
|
|
4
|
+
* Wraps async operations with per-attempt timeout.
|
|
5
|
+
* Proper abort signal propagation without listener leaks.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { TimeoutError } from "../errors/index.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Wraps an async function with a timeout.
|
|
12
|
+
*
|
|
13
|
+
* The timeout is per-attempt, not global. This ensures that slow attempts
|
|
14
|
+
* don't consume the entire retry budget.
|
|
15
|
+
*
|
|
16
|
+
* @param fn - Function to execute (receives an AbortSignal)
|
|
17
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
18
|
+
* @param parentSignal - Optional parent AbortSignal for cancellation
|
|
19
|
+
*/
|
|
20
|
+
export async function withTimeout<T>(
|
|
21
|
+
fn: (signal: AbortSignal) => Promise<T>,
|
|
22
|
+
timeoutMs: number,
|
|
23
|
+
parentSignal?: AbortSignal
|
|
24
|
+
): Promise<T> {
|
|
25
|
+
const controller = new AbortController();
|
|
26
|
+
|
|
27
|
+
// Propagate parent abort
|
|
28
|
+
const onAbort = () => controller.abort();
|
|
29
|
+
parentSignal?.addEventListener("abort", onAbort, { once: true });
|
|
30
|
+
|
|
31
|
+
// Set timeout
|
|
32
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
return await fn(controller.signal);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
// If our timeout triggered the abort (not parent), throw TimeoutError
|
|
38
|
+
if (controller.signal.aborted && !parentSignal?.aborted) {
|
|
39
|
+
throw new TimeoutError(timeoutMs);
|
|
40
|
+
}
|
|
41
|
+
throw err;
|
|
42
|
+
} finally {
|
|
43
|
+
clearTimeout(timeoutId);
|
|
44
|
+
parentSignal?.removeEventListener("abort", onAbort);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Creates an AbortController that times out after the specified duration.
|
|
50
|
+
* Useful for creating deadline-aware operations.
|
|
51
|
+
*
|
|
52
|
+
* @param timeoutMs - Timeout in milliseconds
|
|
53
|
+
* @returns AbortController that will abort after timeout
|
|
54
|
+
*/
|
|
55
|
+
export function createTimeoutController(timeoutMs: number): AbortController {
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
setTimeout(() => controller.abort(), timeoutMs);
|
|
58
|
+
return controller;
|
|
59
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent OS SDK - Error Factory
|
|
3
|
+
*
|
|
4
|
+
* Creates typed errors from HTTP responses.
|
|
5
|
+
* Preserves backend error codes and details for debugging.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
AgentOsError,
|
|
10
|
+
UnauthorizedError,
|
|
11
|
+
ForbiddenError,
|
|
12
|
+
NotFoundError,
|
|
13
|
+
ConflictError,
|
|
14
|
+
ValidationError,
|
|
15
|
+
RateLimitError,
|
|
16
|
+
ServerError,
|
|
17
|
+
type FieldError,
|
|
18
|
+
type ErrorOptions,
|
|
19
|
+
} from "./index.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates a typed error from an HTTP response.
|
|
23
|
+
*
|
|
24
|
+
* @param response - The fetch Response object
|
|
25
|
+
* @param body - Parsed JSON body (if available)
|
|
26
|
+
* @param requestPath - The original request path (for 404 errors)
|
|
27
|
+
*/
|
|
28
|
+
export function createErrorFromResponse(
|
|
29
|
+
response: Response,
|
|
30
|
+
body?: { code?: string; message?: string; details?: unknown },
|
|
31
|
+
requestPath?: string
|
|
32
|
+
): AgentOsError {
|
|
33
|
+
const status = response.status;
|
|
34
|
+
const message = body?.message || response.statusText || `HTTP ${status}`;
|
|
35
|
+
const requestId = response.headers.get("x-request-id") ?? undefined;
|
|
36
|
+
const opts: ErrorOptions = {
|
|
37
|
+
requestId,
|
|
38
|
+
backendCode: body?.code,
|
|
39
|
+
details: body?.details,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
switch (status) {
|
|
43
|
+
case 401:
|
|
44
|
+
return new UnauthorizedError(message, opts);
|
|
45
|
+
|
|
46
|
+
case 403:
|
|
47
|
+
return new ForbiddenError(message, opts);
|
|
48
|
+
|
|
49
|
+
case 404:
|
|
50
|
+
return new NotFoundError(message, requestPath, opts);
|
|
51
|
+
|
|
52
|
+
case 409:
|
|
53
|
+
return new ConflictError(message, opts);
|
|
54
|
+
|
|
55
|
+
case 400:
|
|
56
|
+
case 422:
|
|
57
|
+
return new ValidationError(
|
|
58
|
+
message,
|
|
59
|
+
status as 400 | 422,
|
|
60
|
+
parseFieldErrors(body?.details),
|
|
61
|
+
opts
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
case 429:
|
|
65
|
+
const retryAfterHeader = response.headers.get("Retry-After");
|
|
66
|
+
let retryAfterMs: number | undefined;
|
|
67
|
+
|
|
68
|
+
if (retryAfterHeader) {
|
|
69
|
+
// Retry-After can be seconds or a date
|
|
70
|
+
const seconds = parseInt(retryAfterHeader, 10);
|
|
71
|
+
if (!isNaN(seconds)) {
|
|
72
|
+
retryAfterMs = seconds * 1000;
|
|
73
|
+
} else {
|
|
74
|
+
// Try parsing as date
|
|
75
|
+
const date = new Date(retryAfterHeader);
|
|
76
|
+
if (!isNaN(date.getTime())) {
|
|
77
|
+
retryAfterMs = Math.max(0, date.getTime() - Date.now());
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return new RateLimitError(message, retryAfterMs, opts);
|
|
83
|
+
|
|
84
|
+
default:
|
|
85
|
+
if (status >= 500) {
|
|
86
|
+
return new ServerError(message, status, opts);
|
|
87
|
+
}
|
|
88
|
+
// Fallback for unknown 4xx errors
|
|
89
|
+
return new ServerError(message, status, opts);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Parses field errors from various backend formats.
|
|
95
|
+
*/
|
|
96
|
+
function parseFieldErrors(details: unknown): FieldError[] | undefined {
|
|
97
|
+
if (!details || typeof details !== "object") {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Format 1: Array of { field, message } objects
|
|
102
|
+
if (Array.isArray(details)) {
|
|
103
|
+
const errors = details.filter(
|
|
104
|
+
(d): d is FieldError =>
|
|
105
|
+
typeof d === "object" &&
|
|
106
|
+
d !== null &&
|
|
107
|
+
typeof d.field === "string" &&
|
|
108
|
+
typeof d.message === "string"
|
|
109
|
+
);
|
|
110
|
+
return errors.length > 0 ? errors : undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Format 2: { errors: [...] }
|
|
114
|
+
if ("errors" in details && Array.isArray((details as { errors: unknown }).errors)) {
|
|
115
|
+
return parseFieldErrors((details as { errors: unknown[] }).errors);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Format 3: { field: [messages] } (Rails/Django style)
|
|
119
|
+
const entries = Object.entries(details);
|
|
120
|
+
if (entries.every(([, v]) => Array.isArray(v))) {
|
|
121
|
+
const errors: FieldError[] = [];
|
|
122
|
+
for (const [field, messages] of entries) {
|
|
123
|
+
if (Array.isArray(messages)) {
|
|
124
|
+
for (const message of messages) {
|
|
125
|
+
if (typeof message === "string") {
|
|
126
|
+
errors.push({ field, message });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return errors.length > 0 ? errors : undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent OS SDK - Typed Errors
|
|
3
|
+
*
|
|
4
|
+
* Enterprise-grade error classification for predictable error handling.
|
|
5
|
+
* All errors extend AgentOsError and include semantic information.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Options for constructing typed errors
|
|
10
|
+
*/
|
|
11
|
+
export interface ErrorOptions {
|
|
12
|
+
/** Request ID from x-request-id header */
|
|
13
|
+
requestId?: string;
|
|
14
|
+
/** Original error code from backend (preserves backend semantics) */
|
|
15
|
+
backendCode?: string;
|
|
16
|
+
/** Raw details object from backend response */
|
|
17
|
+
details?: unknown;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Base class for all Agent OS SDK errors.
|
|
22
|
+
* Provides consistent structure for error handling and classification.
|
|
23
|
+
*/
|
|
24
|
+
export abstract class AgentOsError extends Error {
|
|
25
|
+
/** Error code for programmatic handling */
|
|
26
|
+
abstract readonly code: string;
|
|
27
|
+
|
|
28
|
+
/** HTTP status code (0 for network/timeout errors) */
|
|
29
|
+
abstract readonly status: number;
|
|
30
|
+
|
|
31
|
+
/** Request ID from x-request-id header */
|
|
32
|
+
readonly requestId?: string;
|
|
33
|
+
|
|
34
|
+
/** Original error code from backend (preserves backend semantics) */
|
|
35
|
+
readonly backendCode?: string;
|
|
36
|
+
|
|
37
|
+
/** Raw details object from backend response */
|
|
38
|
+
readonly details?: unknown;
|
|
39
|
+
|
|
40
|
+
/** Timestamp when error occurred */
|
|
41
|
+
readonly timestamp: string = new Date().toISOString();
|
|
42
|
+
|
|
43
|
+
constructor(message: string, options?: ErrorOptions) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = this.constructor.name;
|
|
46
|
+
this.requestId = options?.requestId;
|
|
47
|
+
this.backendCode = options?.backendCode;
|
|
48
|
+
this.details = options?.details;
|
|
49
|
+
|
|
50
|
+
// Maintains proper stack trace (V8 engines only)
|
|
51
|
+
if ("captureStackTrace" in Error && typeof Error.captureStackTrace === "function") {
|
|
52
|
+
Error.captureStackTrace(this, this.constructor);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Whether this error is retryable with the same request.
|
|
58
|
+
* Override in subclasses for specific behavior.
|
|
59
|
+
*/
|
|
60
|
+
isRetryable(): boolean {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Convert to JSON for logging/serialization */
|
|
65
|
+
toJSON(): Record<string, unknown> {
|
|
66
|
+
return {
|
|
67
|
+
name: this.name,
|
|
68
|
+
code: this.code,
|
|
69
|
+
status: this.status,
|
|
70
|
+
message: this.message,
|
|
71
|
+
requestId: this.requestId,
|
|
72
|
+
backendCode: this.backendCode,
|
|
73
|
+
details: this.details,
|
|
74
|
+
timestamp: this.timestamp,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Authentication & Authorization Errors
|
|
81
|
+
// ============================================================================
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 401 Unauthorized - Invalid or missing authentication.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* if (error instanceof UnauthorizedError) {
|
|
88
|
+
* // Redirect to login
|
|
89
|
+
* }
|
|
90
|
+
*/
|
|
91
|
+
export class UnauthorizedError extends AgentOsError {
|
|
92
|
+
readonly code = "UNAUTHORIZED";
|
|
93
|
+
readonly status = 401;
|
|
94
|
+
|
|
95
|
+
constructor(message = "Authentication required", options?: ErrorOptions) {
|
|
96
|
+
super(message, options);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 403 Forbidden - Valid auth but insufficient permissions.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* if (error instanceof ForbiddenError) {
|
|
105
|
+
* showToast("You don't have permission to perform this action");
|
|
106
|
+
* }
|
|
107
|
+
*/
|
|
108
|
+
export class ForbiddenError extends AgentOsError {
|
|
109
|
+
readonly code = "FORBIDDEN";
|
|
110
|
+
readonly status = 403;
|
|
111
|
+
|
|
112
|
+
constructor(message = "Access denied", options?: ErrorOptions) {
|
|
113
|
+
super(message, options);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ============================================================================
|
|
118
|
+
// Resource Errors
|
|
119
|
+
// ============================================================================
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 404 Not Found - Resource does not exist.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* if (error instanceof NotFoundError) {
|
|
126
|
+
* console.log(`Not found at: ${error.path}`);
|
|
127
|
+
* }
|
|
128
|
+
*/
|
|
129
|
+
export class NotFoundError extends AgentOsError {
|
|
130
|
+
readonly code = "NOT_FOUND";
|
|
131
|
+
readonly status = 404;
|
|
132
|
+
|
|
133
|
+
constructor(
|
|
134
|
+
message = "Resource not found",
|
|
135
|
+
/** The request path that returned 404 */
|
|
136
|
+
readonly path?: string,
|
|
137
|
+
options?: ErrorOptions
|
|
138
|
+
) {
|
|
139
|
+
super(message, options);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* 409 Conflict - Resource already exists or state conflict.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* if (error instanceof ConflictError) {
|
|
148
|
+
* // Handle duplicate or version mismatch
|
|
149
|
+
* }
|
|
150
|
+
*/
|
|
151
|
+
export class ConflictError extends AgentOsError {
|
|
152
|
+
readonly code = "CONFLICT";
|
|
153
|
+
readonly status = 409;
|
|
154
|
+
|
|
155
|
+
constructor(message = "Resource conflict", options?: ErrorOptions) {
|
|
156
|
+
super(message, options);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ============================================================================
|
|
161
|
+
// Validation Errors
|
|
162
|
+
// ============================================================================
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Field-level validation error detail.
|
|
166
|
+
*/
|
|
167
|
+
export interface FieldError {
|
|
168
|
+
field: string;
|
|
169
|
+
message: string;
|
|
170
|
+
code?: string;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* 400/422 Validation Error - Invalid request data.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* if (error instanceof ValidationError) {
|
|
178
|
+
* error.fieldErrors?.forEach(fe => {
|
|
179
|
+
* showFieldError(fe.field, fe.message);
|
|
180
|
+
* });
|
|
181
|
+
* }
|
|
182
|
+
*/
|
|
183
|
+
export class ValidationError extends AgentOsError {
|
|
184
|
+
readonly code = "VALIDATION_ERROR";
|
|
185
|
+
readonly status: 400 | 422;
|
|
186
|
+
|
|
187
|
+
constructor(
|
|
188
|
+
message = "Validation failed",
|
|
189
|
+
status: 400 | 422 = 400,
|
|
190
|
+
readonly fieldErrors?: FieldError[],
|
|
191
|
+
options?: ErrorOptions
|
|
192
|
+
) {
|
|
193
|
+
super(message, options);
|
|
194
|
+
this.status = status;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Get error message for a specific field */
|
|
198
|
+
getFieldError(field: string): string | undefined {
|
|
199
|
+
return this.fieldErrors?.find(fe => fe.field === field)?.message;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Check if a specific field has an error */
|
|
203
|
+
hasFieldError(field: string): boolean {
|
|
204
|
+
return this.fieldErrors?.some(fe => fe.field === field) ?? false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ============================================================================
|
|
209
|
+
// Rate Limiting
|
|
210
|
+
// ============================================================================
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 429 Too Many Requests - Rate limit exceeded.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* if (error instanceof RateLimitError) {
|
|
217
|
+
* if (error.retryAfterMs) {
|
|
218
|
+
* await sleep(error.retryAfterMs);
|
|
219
|
+
* // Retry request
|
|
220
|
+
* }
|
|
221
|
+
* }
|
|
222
|
+
*/
|
|
223
|
+
export class RateLimitError extends AgentOsError {
|
|
224
|
+
readonly code = "RATE_LIMITED";
|
|
225
|
+
readonly status = 429;
|
|
226
|
+
|
|
227
|
+
constructor(
|
|
228
|
+
message = "Rate limit exceeded",
|
|
229
|
+
/** Time to wait before retrying (milliseconds) */
|
|
230
|
+
readonly retryAfterMs?: number,
|
|
231
|
+
options?: ErrorOptions
|
|
232
|
+
) {
|
|
233
|
+
super(message, options);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
isRetryable(): boolean {
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** Get retry delay or default */
|
|
241
|
+
getRetryDelay(defaultMs = 1000): number {
|
|
242
|
+
return this.retryAfterMs ?? defaultMs;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// ============================================================================
|
|
247
|
+
// Server Errors
|
|
248
|
+
// ============================================================================
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* 5xx Server Error - Backend failure.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* if (error instanceof ServerError) {
|
|
255
|
+
* if (error.isRetryable()) {
|
|
256
|
+
* // Retry with backoff
|
|
257
|
+
* }
|
|
258
|
+
* }
|
|
259
|
+
*/
|
|
260
|
+
export class ServerError extends AgentOsError {
|
|
261
|
+
readonly code = "SERVER_ERROR";
|
|
262
|
+
|
|
263
|
+
constructor(
|
|
264
|
+
message = "Internal server error",
|
|
265
|
+
readonly status: number = 500,
|
|
266
|
+
options?: ErrorOptions
|
|
267
|
+
) {
|
|
268
|
+
super(message, options);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
isRetryable(): boolean {
|
|
272
|
+
// 500, 502, 503, 504 are typically retryable
|
|
273
|
+
return [500, 502, 503, 504].includes(this.status);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// ============================================================================
|
|
278
|
+
// Network & Timeout Errors
|
|
279
|
+
// ============================================================================
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Network Error - Fetch failed (no response received).
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* if (error instanceof NetworkError) {
|
|
286
|
+
* showToast("Network connection failed. Check your internet.");
|
|
287
|
+
* }
|
|
288
|
+
*/
|
|
289
|
+
export class NetworkError extends AgentOsError {
|
|
290
|
+
readonly code = "NETWORK_ERROR";
|
|
291
|
+
readonly status = 0;
|
|
292
|
+
|
|
293
|
+
constructor(
|
|
294
|
+
message = "Network request failed",
|
|
295
|
+
readonly cause?: Error
|
|
296
|
+
) {
|
|
297
|
+
super(message);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
isRetryable(): boolean {
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Timeout Error - Request exceeded time limit.
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* if (error instanceof TimeoutError) {
|
|
310
|
+
* console.log(`Request timed out after ${error.timeoutMs}ms`);
|
|
311
|
+
* }
|
|
312
|
+
*/
|
|
313
|
+
export class TimeoutError extends AgentOsError {
|
|
314
|
+
readonly code = "TIMEOUT";
|
|
315
|
+
readonly status = 0;
|
|
316
|
+
|
|
317
|
+
constructor(
|
|
318
|
+
/** Timeout duration in milliseconds */
|
|
319
|
+
readonly timeoutMs: number
|
|
320
|
+
) {
|
|
321
|
+
super(`Request timed out after ${timeoutMs}ms`);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
isRetryable(): boolean {
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// ============================================================================
|
|
330
|
+
// Error Type Guards
|
|
331
|
+
// ============================================================================
|
|
332
|
+
|
|
333
|
+
/** Check if error is any Agent OS SDK error */
|
|
334
|
+
export function isAgentOsError(error: unknown): error is AgentOsError {
|
|
335
|
+
return error instanceof AgentOsError;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** Check if error is retryable */
|
|
339
|
+
export function isRetryableError(error: unknown): boolean {
|
|
340
|
+
if (error instanceof AgentOsError) {
|
|
341
|
+
return error.isRetryable();
|
|
342
|
+
}
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** Check if error is an auth error (401 or 403) */
|
|
347
|
+
export function isAuthError(error: unknown): error is UnauthorizedError | ForbiddenError {
|
|
348
|
+
return error instanceof UnauthorizedError || error instanceof ForbiddenError;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** Check if error is a client error (4xx) */
|
|
352
|
+
export function isClientError(error: unknown): boolean {
|
|
353
|
+
if (error instanceof AgentOsError) {
|
|
354
|
+
return error.status >= 400 && error.status < 500;
|
|
355
|
+
}
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** Check if error is a server error (5xx) */
|
|
360
|
+
export function isServerError(error: unknown): boolean {
|
|
361
|
+
if (error instanceof AgentOsError) {
|
|
362
|
+
return error.status >= 500 && error.status < 600;
|
|
363
|
+
}
|
|
364
|
+
return false;
|
|
365
|
+
}
|