10xgraph-client 0.6.0 → 1.0.0-rc.2
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/CHANGELOG.md +207 -0
- package/README.md +11 -5
- package/dist/agent.d.ts +17 -5
- package/dist/agent.d.ts.map +1 -1
- package/dist/cjs/agent.d.ts +33 -0
- package/dist/cjs/client.d.ts +533 -0
- package/dist/cjs/compat.d.ts +27 -0
- package/dist/cjs/endpoints/addThreadMessages.d.ts +25 -0
- package/dist/cjs/endpoints/clearThreadState.d.ts +14 -0
- package/dist/cjs/endpoints/deleteFile.d.ts +13 -0
- package/dist/cjs/endpoints/deleteMemory.d.ts +18 -0
- package/dist/cjs/endpoints/deleteThread.d.ts +18 -0
- package/dist/cjs/endpoints/deleteThreadMessage.d.ts +19 -0
- package/dist/cjs/endpoints/files.d.ts +115 -0
- package/dist/cjs/endpoints/fixGraph.d.ts +33 -0
- package/dist/cjs/endpoints/forgetMemories.d.ts +21 -0
- package/dist/cjs/endpoints/getMemory.d.ts +18 -0
- package/dist/cjs/endpoints/graph.d.ts +50 -0
- package/dist/cjs/endpoints/graphTools.d.ts +31 -0
- package/dist/cjs/endpoints/invoke.d.ts +66 -0
- package/dist/cjs/endpoints/listMemories.d.ts +24 -0
- package/dist/cjs/endpoints/metadata.d.ts +5 -0
- package/dist/cjs/endpoints/observability.d.ts +111 -0
- package/dist/cjs/endpoints/ping.d.ts +9 -0
- package/dist/cjs/endpoints/realtime.d.ts +154 -0
- package/dist/cjs/endpoints/searchMemory.d.ts +56 -0
- package/dist/cjs/endpoints/stateSchema.d.ts +49 -0
- package/dist/cjs/endpoints/stopGraph.d.ts +35 -0
- package/dist/cjs/endpoints/storeMemory.d.ts +32 -0
- package/dist/cjs/endpoints/stream.d.ts +67 -0
- package/dist/cjs/endpoints/threadDetails.d.ts +18 -0
- package/dist/cjs/endpoints/threadMessage.d.ts +16 -0
- package/dist/cjs/endpoints/threadMessages.d.ts +28 -0
- package/dist/cjs/endpoints/threadState.d.ts +13 -0
- package/dist/cjs/endpoints/threads.d.ts +35 -0
- package/dist/cjs/endpoints/updateMemory.d.ts +20 -0
- package/dist/cjs/endpoints/updateThreadMessageFeedback.d.ts +19 -0
- package/dist/cjs/endpoints/updateThreadState.d.ts +22 -0
- package/dist/cjs/endpoints/wsStream.d.ts +34 -0
- package/dist/cjs/errors.d.ts +212 -0
- package/dist/cjs/index.d.ts +41 -0
- package/dist/cjs/interrupt.d.ts +45 -0
- package/dist/cjs/message.d.ts +173 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/request.d.ts +60 -0
- package/dist/cjs/tools.d.ts +80 -0
- package/dist/cjs/ws.d.ts +47 -0
- package/dist/client.d.ts +95 -40
- package/dist/client.d.ts.map +1 -1
- package/dist/endpoints/addThreadMessages.d.ts +4 -0
- package/dist/endpoints/addThreadMessages.d.ts.map +1 -1
- package/dist/endpoints/clearThreadState.d.ts.map +1 -1
- package/dist/endpoints/deleteFile.d.ts +14 -0
- package/dist/endpoints/deleteFile.d.ts.map +1 -0
- package/dist/endpoints/deleteMemory.d.ts.map +1 -1
- package/dist/endpoints/deleteThread.d.ts.map +1 -1
- package/dist/endpoints/deleteThreadMessage.d.ts.map +1 -1
- package/dist/endpoints/files.d.ts +33 -0
- package/dist/endpoints/files.d.ts.map +1 -1
- package/dist/endpoints/fixGraph.d.ts +8 -3
- package/dist/endpoints/fixGraph.d.ts.map +1 -1
- package/dist/endpoints/forgetMemories.d.ts.map +1 -1
- package/dist/endpoints/getMemory.d.ts.map +1 -1
- package/dist/endpoints/graph.d.ts +20 -8
- package/dist/endpoints/graph.d.ts.map +1 -1
- package/dist/endpoints/graphTools.d.ts.map +1 -1
- package/dist/endpoints/invoke.d.ts +8 -0
- package/dist/endpoints/invoke.d.ts.map +1 -1
- package/dist/endpoints/listMemories.d.ts +6 -0
- package/dist/endpoints/listMemories.d.ts.map +1 -1
- package/dist/endpoints/observability.d.ts +54 -0
- package/dist/endpoints/observability.d.ts.map +1 -1
- package/dist/endpoints/ping.d.ts.map +1 -1
- package/dist/endpoints/realtime.d.ts +25 -4
- package/dist/endpoints/realtime.d.ts.map +1 -1
- package/dist/endpoints/searchMemory.d.ts.map +1 -1
- package/dist/endpoints/stateSchema.d.ts.map +1 -1
- package/dist/endpoints/stopGraph.d.ts +13 -3
- package/dist/endpoints/stopGraph.d.ts.map +1 -1
- package/dist/endpoints/storeMemory.d.ts.map +1 -1
- package/dist/endpoints/stream.d.ts +8 -0
- package/dist/endpoints/stream.d.ts.map +1 -1
- package/dist/endpoints/threadDetails.d.ts.map +1 -1
- package/dist/endpoints/threadMessage.d.ts.map +1 -1
- package/dist/endpoints/threadMessages.d.ts +6 -0
- package/dist/endpoints/threadMessages.d.ts.map +1 -1
- package/dist/endpoints/threadState.d.ts.map +1 -1
- package/dist/endpoints/threads.d.ts +6 -0
- package/dist/endpoints/threads.d.ts.map +1 -1
- package/dist/endpoints/updateMemory.d.ts.map +1 -1
- package/dist/endpoints/updateThreadMessageFeedback.d.ts +20 -0
- package/dist/endpoints/updateThreadMessageFeedback.d.ts.map +1 -0
- package/dist/endpoints/updateThreadState.d.ts +6 -1
- package/dist/endpoints/updateThreadState.d.ts.map +1 -1
- package/dist/endpoints/wsStream.d.ts +2 -0
- package/dist/endpoints/wsStream.d.ts.map +1 -1
- package/dist/errors.d.ts +60 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1742 -1217
- package/dist/index.js.map +1 -1
- package/dist/interrupt.d.ts +46 -0
- package/dist/interrupt.d.ts.map +1 -0
- package/dist/request.d.ts +28 -0
- package/dist/request.d.ts.map +1 -1
- package/dist/tools.d.ts +14 -0
- package/dist/tools.d.ts.map +1 -1
- package/package.json +11 -6
- package/src/agent.ts +17 -4
- package/src/client.ts +248 -128
- package/src/endpoints/addThreadMessages.ts +15 -10
- package/src/endpoints/clearThreadState.ts +19 -20
- package/src/endpoints/deleteFile.ts +65 -0
- package/src/endpoints/deleteMemory.ts +9 -13
- package/src/endpoints/deleteThread.ts +9 -13
- package/src/endpoints/deleteThreadMessage.ts +9 -13
- package/src/endpoints/files.ts +164 -131
- package/src/endpoints/fixGraph.ts +15 -16
- package/src/endpoints/forgetMemories.ts +44 -60
- package/src/endpoints/getMemory.ts +9 -9
- package/src/endpoints/graph.ts +28 -21
- package/src/endpoints/graphTools.ts +7 -13
- package/src/endpoints/invoke.ts +105 -84
- package/src/endpoints/listMemories.ts +18 -13
- package/src/endpoints/observability.ts +77 -34
- package/src/endpoints/ping.ts +7 -13
- package/src/endpoints/realtime.ts +101 -39
- package/src/endpoints/searchMemory.ts +19 -13
- package/src/endpoints/stateSchema.ts +7 -13
- package/src/endpoints/stopGraph.ts +20 -16
- package/src/endpoints/storeMemory.ts +7 -8
- package/src/endpoints/stream.ts +179 -61
- package/src/endpoints/threadDetails.ts +9 -14
- package/src/endpoints/threadMessage.ts +9 -9
- package/src/endpoints/threadMessages.ts +15 -9
- package/src/endpoints/threadState.ts +19 -20
- package/src/endpoints/threads.ts +13 -12
- package/src/endpoints/updateMemory.ts +9 -9
- package/src/endpoints/updateThreadMessageFeedback.ts +80 -0
- package/src/endpoints/updateThreadState.ts +28 -22
- package/src/endpoints/wsStream.ts +167 -42
- package/src/errors.ts +332 -93
- package/src/index.ts +9 -0
- package/src/interrupt.ts +60 -0
- package/src/request.ts +134 -0
- package/src/tools.ts +95 -0
package/src/errors.ts
CHANGED
|
@@ -20,6 +20,8 @@ export interface ApiErrorResponse {
|
|
|
20
20
|
code: string;
|
|
21
21
|
message: string;
|
|
22
22
|
details: ErrorDetail[];
|
|
23
|
+
/** Present on 429 replies. */
|
|
24
|
+
retry_after_seconds?: number;
|
|
23
25
|
};
|
|
24
26
|
}
|
|
25
27
|
|
|
@@ -33,9 +35,15 @@ export class TenxGraphError extends Error {
|
|
|
33
35
|
public readonly timestamp: string;
|
|
34
36
|
public readonly details: ErrorDetail[];
|
|
35
37
|
public readonly context?: Record<string, any>;
|
|
36
|
-
public
|
|
37
|
-
public
|
|
38
|
+
public endpoint?: string;
|
|
39
|
+
public method?: string;
|
|
38
40
|
public readonly recoverySuggestion?: string;
|
|
41
|
+
/** Underlying error (fetch rejection, socket error) when there is one. */
|
|
42
|
+
public cause?: unknown;
|
|
43
|
+
/** Response headers of the failed HTTP reply, lowercased names. Absent for transport errors. */
|
|
44
|
+
public responseHeaders?: Record<string, string>;
|
|
45
|
+
/** Parsed JSON body (or raw text) of the failed HTTP reply, before any normalisation. */
|
|
46
|
+
public responseBody?: unknown;
|
|
39
47
|
|
|
40
48
|
constructor(
|
|
41
49
|
message: string,
|
|
@@ -148,6 +156,18 @@ export class NotFoundError extends TenxGraphError {
|
|
|
148
156
|
}
|
|
149
157
|
}
|
|
150
158
|
|
|
159
|
+
/**
|
|
160
|
+
* 409 Conflict Error
|
|
161
|
+
* Thrown when the thread is busy with another run, or when a resume's
|
|
162
|
+
* `interrupt_id` does not match the open interrupt. Never retried automatically.
|
|
163
|
+
*/
|
|
164
|
+
export class ConflictError extends TenxGraphError {
|
|
165
|
+
constructor(message: string, requestId: string, timestamp: string, details: ErrorDetail[] = []) {
|
|
166
|
+
super(message, 409, 'CONFLICT', requestId, timestamp, details);
|
|
167
|
+
this.name = 'ConflictError';
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
151
171
|
/**
|
|
152
172
|
* 422 Validation Error
|
|
153
173
|
* Thrown when the request data fails validation
|
|
@@ -417,19 +437,248 @@ export class SerializationError extends TenxGraphError {
|
|
|
417
437
|
}
|
|
418
438
|
|
|
419
439
|
/**
|
|
420
|
-
*
|
|
440
|
+
* 429 Too Many Requests
|
|
441
|
+
* Carries the server's retry hint in seconds (Retry-After header, else the body's
|
|
442
|
+
* `retry_after_seconds`), or undefined when the server sent none.
|
|
421
443
|
*/
|
|
422
|
-
export
|
|
444
|
+
export class RateLimitError extends TenxGraphError {
|
|
445
|
+
public readonly retryAfterSeconds?: number;
|
|
446
|
+
|
|
447
|
+
constructor(
|
|
448
|
+
message: string,
|
|
449
|
+
requestId: string,
|
|
450
|
+
timestamp: string,
|
|
451
|
+
details: ErrorDetail[] = [],
|
|
452
|
+
retryAfterSeconds?: number
|
|
453
|
+
) {
|
|
454
|
+
super(
|
|
455
|
+
message,
|
|
456
|
+
429,
|
|
457
|
+
'RATE_LIMIT_EXCEEDED',
|
|
458
|
+
requestId,
|
|
459
|
+
timestamp,
|
|
460
|
+
details,
|
|
461
|
+
undefined,
|
|
462
|
+
undefined,
|
|
463
|
+
undefined,
|
|
464
|
+
'Wait for the retry-after period before sending the request again.'
|
|
465
|
+
);
|
|
466
|
+
this.name = 'RateLimitError';
|
|
467
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Request Timeout Error
|
|
473
|
+
* Thrown client-side when a request exceeds the configured `timeout`. statusCode is 0.
|
|
474
|
+
*/
|
|
475
|
+
export class RequestTimeoutError extends TenxGraphError {
|
|
476
|
+
public readonly timeoutMs: number;
|
|
477
|
+
|
|
478
|
+
constructor(timeoutMs: number, endpoint?: string, method?: string, cause?: unknown) {
|
|
479
|
+
super(
|
|
480
|
+
`Request timeout after ${timeoutMs}ms`,
|
|
481
|
+
0,
|
|
482
|
+
'REQUEST_TIMEOUT',
|
|
483
|
+
'unknown',
|
|
484
|
+
new Date().toISOString(),
|
|
485
|
+
[],
|
|
486
|
+
undefined,
|
|
487
|
+
endpoint,
|
|
488
|
+
method,
|
|
489
|
+
'Increase the client timeout or check that the server is reachable and not overloaded.'
|
|
490
|
+
);
|
|
491
|
+
this.name = 'RequestTimeoutError';
|
|
492
|
+
this.timeoutMs = timeoutMs;
|
|
493
|
+
if (cause !== undefined) this.cause = cause;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Network Error
|
|
499
|
+
* Thrown when the request never got an HTTP reply (DNS failure, connection refused, offline,
|
|
500
|
+
* CORS block). `cause` holds the underlying fetch error. statusCode is 0.
|
|
501
|
+
*/
|
|
502
|
+
export class NetworkError extends TenxGraphError {
|
|
503
|
+
constructor(message: string, endpoint?: string, method?: string, cause?: unknown) {
|
|
504
|
+
super(
|
|
505
|
+
message,
|
|
506
|
+
0,
|
|
507
|
+
'NETWORK_ERROR',
|
|
508
|
+
'unknown',
|
|
509
|
+
new Date().toISOString(),
|
|
510
|
+
[],
|
|
511
|
+
undefined,
|
|
512
|
+
endpoint,
|
|
513
|
+
method,
|
|
514
|
+
'Check that the server is running, the base URL is correct and the network is reachable.'
|
|
515
|
+
);
|
|
516
|
+
this.name = 'NetworkError';
|
|
517
|
+
if (cause !== undefined) this.cause = cause;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* WebSocket Error
|
|
523
|
+
* Thrown for WebSocket failures: connection errors, unexpected close, handshake rejection.
|
|
524
|
+
* `closeCode` is the close frame code when the failure was a close.
|
|
525
|
+
*/
|
|
526
|
+
export class WebSocketError extends TenxGraphError {
|
|
527
|
+
public readonly closeCode?: number;
|
|
528
|
+
|
|
529
|
+
constructor(message: string, closeCode?: number, endpoint?: string, cause?: unknown) {
|
|
530
|
+
super(
|
|
531
|
+
message,
|
|
532
|
+
0,
|
|
533
|
+
'WEBSOCKET_ERROR',
|
|
534
|
+
'unknown',
|
|
535
|
+
new Date().toISOString(),
|
|
536
|
+
[],
|
|
537
|
+
undefined,
|
|
538
|
+
endpoint,
|
|
539
|
+
'WS'
|
|
540
|
+
);
|
|
541
|
+
this.name = 'WebSocketError';
|
|
542
|
+
this.closeCode = closeCode;
|
|
543
|
+
if (cause !== undefined) this.cause = cause;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Stream Error
|
|
549
|
+
* Thrown when an HTTP or WebSocket run stream fails after it started: an error chunk from the
|
|
550
|
+
* server, a malformed chunk, or a stream that ended before completion.
|
|
551
|
+
*/
|
|
552
|
+
export class StreamError extends TenxGraphError {
|
|
553
|
+
constructor(
|
|
554
|
+
message: string,
|
|
555
|
+
errorCode: string = 'STREAM_ERROR',
|
|
556
|
+
requestId: string = 'unknown',
|
|
557
|
+
endpoint?: string,
|
|
558
|
+
method?: string,
|
|
559
|
+
cause?: unknown
|
|
560
|
+
) {
|
|
561
|
+
super(
|
|
562
|
+
message,
|
|
563
|
+
0,
|
|
564
|
+
errorCode,
|
|
565
|
+
requestId,
|
|
566
|
+
new Date().toISOString(),
|
|
567
|
+
[],
|
|
568
|
+
undefined,
|
|
569
|
+
endpoint,
|
|
570
|
+
method
|
|
571
|
+
);
|
|
572
|
+
this.name = 'StreamError';
|
|
573
|
+
if (cause !== undefined) this.cause = cause;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function asRecord(value: unknown): Record<string, unknown> | null {
|
|
578
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
579
|
+
? (value as Record<string, unknown>)
|
|
580
|
+
: null;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Normalise any JSON error body into the envelope shape. Handles the 10xGraph envelope,
|
|
585
|
+
* `{"error": "state_conflict", "detail": "..."}` (409), `{"detail": "..."}` and FastAPI's
|
|
586
|
+
* `{"detail": [{loc, msg, type}]}`. Returns null for a body that carries no usable error.
|
|
587
|
+
*/
|
|
588
|
+
function normalizeErrorBody(body: unknown): ApiErrorResponse | null {
|
|
589
|
+
const record = asRecord(body);
|
|
590
|
+
if (!record) return null;
|
|
591
|
+
|
|
592
|
+
const meta = asRecord(record.metadata) ?? {};
|
|
593
|
+
const metadata = {
|
|
594
|
+
message: typeof meta.message === 'string' ? meta.message : '',
|
|
595
|
+
request_id: typeof meta.request_id === 'string' ? meta.request_id : '',
|
|
596
|
+
timestamp: typeof meta.timestamp === 'string' ? meta.timestamp : '',
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
const err = asRecord(record.error);
|
|
600
|
+
if (err) {
|
|
601
|
+
return {
|
|
602
|
+
metadata,
|
|
603
|
+
error: {
|
|
604
|
+
code: typeof err.code === 'string' ? err.code : '',
|
|
605
|
+
message: typeof err.message === 'string' ? err.message : '',
|
|
606
|
+
details: Array.isArray(err.details) ? (err.details as ErrorDetail[]) : [],
|
|
607
|
+
...(typeof err.retry_after_seconds === 'number'
|
|
608
|
+
? { retry_after_seconds: err.retry_after_seconds }
|
|
609
|
+
: {}),
|
|
610
|
+
},
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
if (typeof record.error === 'string') {
|
|
615
|
+
const detail = typeof record.detail === 'string' ? record.detail : record.error;
|
|
616
|
+
return { metadata, error: { code: record.error, message: detail, details: [] } };
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (typeof record.detail === 'string') {
|
|
620
|
+
return { metadata, error: { code: '', message: record.detail, details: [] } };
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (Array.isArray(record.detail)) {
|
|
624
|
+
const details = record.detail.filter((d) => asRecord(d) !== null) as ErrorDetail[];
|
|
625
|
+
return {
|
|
626
|
+
metadata,
|
|
627
|
+
error: { code: '', message: details[0]?.msg || 'Validation error', details },
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
async function readErrorBody(
|
|
635
|
+
response: Response
|
|
636
|
+
): Promise<{ parsed: ApiErrorResponse | null; raw: unknown }> {
|
|
423
637
|
try {
|
|
424
|
-
const contentType = response.headers
|
|
638
|
+
const contentType = response.headers?.get('content-type');
|
|
425
639
|
if (contentType && contentType.includes('application/json')) {
|
|
426
|
-
|
|
640
|
+
const raw: unknown = await response.json();
|
|
641
|
+
return { parsed: normalizeErrorBody(raw), raw };
|
|
427
642
|
}
|
|
428
|
-
return null;
|
|
643
|
+
return { parsed: null, raw: undefined };
|
|
429
644
|
} catch {
|
|
430
645
|
// If we can't parse the error response, return null
|
|
431
|
-
return null;
|
|
646
|
+
return { parsed: null, raw: undefined };
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Parse error response from API
|
|
652
|
+
*/
|
|
653
|
+
export async function parseErrorResponse(response: Response): Promise<ApiErrorResponse | null> {
|
|
654
|
+
return (await readErrorBody(response)).parsed;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function headersToRecord(response: Response): Record<string, string> {
|
|
658
|
+
const out: Record<string, string> = {};
|
|
659
|
+
try {
|
|
660
|
+
response.headers?.forEach((value, name) => {
|
|
661
|
+
out[name.toLowerCase()] = value;
|
|
662
|
+
});
|
|
663
|
+
} catch {
|
|
664
|
+
// ignore unreadable headers
|
|
432
665
|
}
|
|
666
|
+
return out;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/** Parse a Retry-After header (delta-seconds or HTTP date) into whole seconds. */
|
|
670
|
+
function parseRetryAfter(value: string | null | undefined): number | undefined {
|
|
671
|
+
if (!value) return undefined;
|
|
672
|
+
const seconds = Number(value);
|
|
673
|
+
if (Number.isFinite(seconds) && seconds >= 0) return seconds;
|
|
674
|
+
const date = Date.parse(value);
|
|
675
|
+
if (!Number.isNaN(date)) return Math.max(0, Math.ceil((date - Date.now()) / 1000));
|
|
676
|
+
return undefined;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function codeMatches(code: string, prefixes: string[]): boolean {
|
|
680
|
+
const upper = code.toUpperCase();
|
|
681
|
+
return prefixes.some((prefix) => upper.startsWith(prefix));
|
|
433
682
|
}
|
|
434
683
|
|
|
435
684
|
/**
|
|
@@ -441,113 +690,103 @@ export async function createErrorFromResponse(
|
|
|
441
690
|
endpoint?: string,
|
|
442
691
|
method?: string
|
|
443
692
|
): Promise<TenxGraphError> {
|
|
444
|
-
const errorData = await
|
|
445
|
-
|
|
446
|
-
// If we successfully parsed the error response
|
|
447
|
-
if (errorData) {
|
|
448
|
-
const { metadata, error } = errorData;
|
|
449
|
-
const message = error.message || fallbackMessage || `HTTP error ${response.status}`;
|
|
450
|
-
const requestId = metadata.request_id || 'unknown';
|
|
451
|
-
const timestamp = metadata.timestamp || new Date().toISOString();
|
|
452
|
-
const details = error.details || [];
|
|
453
|
-
const errorCode = error.code || '';
|
|
454
|
-
|
|
455
|
-
// Try to match specific error types by error code first (takes priority)
|
|
456
|
-
if (errorCode.startsWith('GRAPH_RECURSION')) {
|
|
457
|
-
return new GraphRecursionError(message, requestId, timestamp, details);
|
|
458
|
-
} else if (errorCode.startsWith('GRAPH')) {
|
|
459
|
-
return new GraphError(message, requestId, timestamp, details);
|
|
460
|
-
} else if (errorCode.startsWith('NODE')) {
|
|
461
|
-
return new NodeError(message, requestId, timestamp, details);
|
|
462
|
-
} else if (errorCode.startsWith('TRANSIENT_STORAGE')) {
|
|
463
|
-
return new TransientStorageError(message, requestId, timestamp, details);
|
|
464
|
-
} else if (errorCode.startsWith('STORAGE')) {
|
|
465
|
-
return new StorageError(message, requestId, timestamp, details);
|
|
466
|
-
} else if (errorCode.startsWith('METRICS')) {
|
|
467
|
-
return new MetricsError(message, requestId, timestamp, details);
|
|
468
|
-
} else if (errorCode.startsWith('SCHEMA_VERSION')) {
|
|
469
|
-
return new SchemaVersionError(message, requestId, timestamp, details);
|
|
470
|
-
} else if (errorCode.startsWith('SERIALIZATION')) {
|
|
471
|
-
return new SerializationError(message, requestId, timestamp, details);
|
|
472
|
-
}
|
|
693
|
+
const { parsed: errorData, raw } = await readErrorBody(response);
|
|
694
|
+
const headerRequestId = response.headers?.get('x-request-id') || '';
|
|
473
695
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
696
|
+
const message =
|
|
697
|
+
errorData?.error.message || fallbackMessage || `HTTP error! status: ${response.status}`;
|
|
698
|
+
const requestId = errorData?.metadata.request_id || headerRequestId || 'unknown';
|
|
699
|
+
const timestamp = errorData?.metadata.timestamp || new Date().toISOString();
|
|
700
|
+
const details = errorData?.error.details || [];
|
|
701
|
+
const errorCode = errorData?.error.code || '';
|
|
702
|
+
|
|
703
|
+
const error = buildError(response.status, errorCode, message, requestId, timestamp, details, {
|
|
704
|
+
retryAfter:
|
|
705
|
+
parseRetryAfter(response.headers?.get('retry-after')) ?? errorData?.error.retry_after_seconds,
|
|
706
|
+
endpoint,
|
|
707
|
+
method,
|
|
708
|
+
});
|
|
709
|
+
error.endpoint = endpoint;
|
|
710
|
+
error.method = method;
|
|
711
|
+
error.responseHeaders = headersToRecord(response);
|
|
712
|
+
if (raw !== undefined) error.responseBody = raw;
|
|
713
|
+
return error;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function buildError(
|
|
717
|
+
status: number,
|
|
718
|
+
errorCode: string,
|
|
719
|
+
message: string,
|
|
720
|
+
requestId: string,
|
|
721
|
+
timestamp: string,
|
|
722
|
+
details: ErrorDetail[],
|
|
723
|
+
extra: { retryAfter?: number; endpoint?: string; method?: string }
|
|
724
|
+
): TenxGraphError {
|
|
725
|
+
// Core error codes first (they take priority over the HTTP status). The server sends
|
|
726
|
+
// RECURSION_001, STORAGE_TRANSIENT_000, STORAGE_SCHEMA_000 and STORAGE_SERIALIZATION_000;
|
|
727
|
+
// the older GRAPH_RECURSION / TRANSIENT_STORAGE / SCHEMA_VERSION / SERIALIZATION spellings
|
|
728
|
+
// are still accepted. Specific storage codes must be tested before the STORAGE prefix.
|
|
729
|
+
if (codeMatches(errorCode, ['RECURSION', 'GRAPH_RECURSION'])) {
|
|
730
|
+
return new GraphRecursionError(message, requestId, timestamp, details);
|
|
731
|
+
} else if (codeMatches(errorCode, ['GRAPH'])) {
|
|
732
|
+
return new GraphError(message, requestId, timestamp, details);
|
|
733
|
+
} else if (codeMatches(errorCode, ['NODE'])) {
|
|
734
|
+
return new NodeError(message, requestId, timestamp, details);
|
|
735
|
+
} else if (codeMatches(errorCode, ['STORAGE_TRANSIENT', 'TRANSIENT_STORAGE'])) {
|
|
736
|
+
return new TransientStorageError(message, requestId, timestamp, details);
|
|
737
|
+
} else if (codeMatches(errorCode, ['STORAGE_SCHEMA', 'SCHEMA_VERSION'])) {
|
|
738
|
+
return new SchemaVersionError(message, requestId, timestamp, details);
|
|
739
|
+
} else if (codeMatches(errorCode, ['STORAGE_SERIALIZATION', 'SERIALIZATION'])) {
|
|
740
|
+
return new SerializationError(message, requestId, timestamp, details);
|
|
741
|
+
} else if (codeMatches(errorCode, ['STORAGE'])) {
|
|
742
|
+
return new StorageError(message, requestId, timestamp, details);
|
|
743
|
+
} else if (codeMatches(errorCode, ['METRICS'])) {
|
|
744
|
+
return new MetricsError(message, requestId, timestamp, details);
|
|
511
745
|
}
|
|
512
746
|
|
|
513
|
-
//
|
|
514
|
-
|
|
515
|
-
|
|
747
|
+
// VALIDATION_ERROR (and the older AGENTFLOW_VALIDATION_ERROR spelling) are validation errors
|
|
748
|
+
if (errorCode === 'VALIDATION_ERROR' || errorCode === 'AGENTFLOW_VALIDATION_ERROR') {
|
|
749
|
+
return new ValidationError(message, requestId, timestamp, details);
|
|
750
|
+
}
|
|
516
751
|
|
|
517
|
-
switch (
|
|
752
|
+
switch (status) {
|
|
518
753
|
case 400:
|
|
519
|
-
return new BadRequestError(message,
|
|
754
|
+
return new BadRequestError(message, requestId, timestamp, details);
|
|
520
755
|
case 401:
|
|
521
|
-
return new AuthenticationError(message,
|
|
756
|
+
return new AuthenticationError(message, requestId, timestamp, details);
|
|
522
757
|
case 403:
|
|
523
|
-
return new PermissionError(message,
|
|
758
|
+
return new PermissionError(message, requestId, timestamp, details);
|
|
524
759
|
case 404:
|
|
525
|
-
return new NotFoundError(message,
|
|
760
|
+
return new NotFoundError(message, requestId, timestamp, details);
|
|
761
|
+
case 409:
|
|
762
|
+
return new ConflictError(message, requestId, timestamp, details);
|
|
526
763
|
case 422:
|
|
527
|
-
return new ValidationError(message,
|
|
764
|
+
return new ValidationError(message, requestId, timestamp, details);
|
|
765
|
+
case 429:
|
|
766
|
+
return new RateLimitError(message, requestId, timestamp, details, extra.retryAfter);
|
|
528
767
|
case 500:
|
|
529
768
|
case 502:
|
|
530
769
|
case 503:
|
|
531
770
|
case 504:
|
|
532
771
|
return new ServerError(
|
|
533
772
|
message,
|
|
534
|
-
|
|
773
|
+
requestId,
|
|
535
774
|
timestamp,
|
|
536
|
-
'INTERNAL_SERVER_ERROR',
|
|
537
|
-
|
|
538
|
-
|
|
775
|
+
errorCode || 'INTERNAL_SERVER_ERROR',
|
|
776
|
+
details,
|
|
777
|
+
status
|
|
539
778
|
);
|
|
540
779
|
default:
|
|
541
780
|
return new TenxGraphError(
|
|
542
781
|
message,
|
|
543
|
-
|
|
544
|
-
'UNKNOWN_ERROR',
|
|
545
|
-
|
|
782
|
+
status,
|
|
783
|
+
errorCode || 'UNKNOWN_ERROR',
|
|
784
|
+
requestId,
|
|
546
785
|
timestamp,
|
|
547
|
-
|
|
786
|
+
details,
|
|
548
787
|
undefined,
|
|
549
|
-
endpoint,
|
|
550
|
-
method
|
|
788
|
+
extra.endpoint,
|
|
789
|
+
extra.method
|
|
551
790
|
);
|
|
552
791
|
}
|
|
553
792
|
}
|
package/src/index.ts
CHANGED
|
@@ -22,6 +22,8 @@ export * from './endpoints/graphTools.js';
|
|
|
22
22
|
// Export observability Response types
|
|
23
23
|
export * from './endpoints/observability.js';
|
|
24
24
|
|
|
25
|
+
// Export eval report types
|
|
26
|
+
|
|
25
27
|
// Export stop graph Response types
|
|
26
28
|
export * from './endpoints/stopGraph.js';
|
|
27
29
|
|
|
@@ -50,6 +52,8 @@ export * from './endpoints/addThreadMessages.js';
|
|
|
50
52
|
export * from './endpoints/threadMessage.js';
|
|
51
53
|
// Export delete thread message Response types
|
|
52
54
|
export * from './endpoints/deleteThreadMessage.js';
|
|
55
|
+
// Export update thread message feedback types
|
|
56
|
+
export * from './endpoints/updateThreadMessageFeedback.js';
|
|
53
57
|
// Export delete thread Response types
|
|
54
58
|
export * from './endpoints/deleteThread.js';
|
|
55
59
|
// Export threads list Response types
|
|
@@ -63,6 +67,9 @@ export * from './endpoints/invoke.js';
|
|
|
63
67
|
// Export stream types
|
|
64
68
|
export * from './endpoints/stream.js';
|
|
65
69
|
|
|
70
|
+
// Export interrupt payload type and approve/reject helpers
|
|
71
|
+
export * from './interrupt.js';
|
|
72
|
+
|
|
66
73
|
// Export WebSocket stream types
|
|
67
74
|
export * from './endpoints/wsStream.js';
|
|
68
75
|
|
|
@@ -95,6 +102,8 @@ export * from './endpoints/forgetMemories.js';
|
|
|
95
102
|
|
|
96
103
|
// Export file upload / multimodal types
|
|
97
104
|
export * from './endpoints/files.js';
|
|
105
|
+
// Export delete file types
|
|
106
|
+
export * from './endpoints/deleteFile.js';
|
|
98
107
|
|
|
99
108
|
// Export shared metadata types
|
|
100
109
|
export * from './endpoints/metadata.js';
|
package/src/interrupt.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { StreamChunk } from './endpoints/stream.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A pause raised by `interrupt()` in a graph node or tool, waiting for a resume value.
|
|
5
|
+
* Mirrors the server payload at `chunk.data.interrupt` of an `updates` chunk whose
|
|
6
|
+
* `status` is `"interrupted"`.
|
|
7
|
+
*/
|
|
8
|
+
export interface Interrupt {
|
|
9
|
+
/** Unique id of this pause; echo it as `interrupt_id` when resuming. */
|
|
10
|
+
id: string;
|
|
11
|
+
/** Stable position of the call within its node or tool call. */
|
|
12
|
+
key: string;
|
|
13
|
+
/** Node that was running when the graph paused. */
|
|
14
|
+
node: string;
|
|
15
|
+
/** Payload passed to `interrupt()`: what to approve or choose from. */
|
|
16
|
+
value?: unknown;
|
|
17
|
+
/** Human-readable prompt. */
|
|
18
|
+
message?: string | null;
|
|
19
|
+
/** Machine-readable reason, for example `"tool_approval"`. */
|
|
20
|
+
reason: string;
|
|
21
|
+
/** JSON Schema the resume value must follow. */
|
|
22
|
+
response_schema?: Record<string, unknown> | null;
|
|
23
|
+
/** Tool call that paused, when `interrupt()` ran inside a tool. */
|
|
24
|
+
tool_call_id?: string | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Spread into the `options` of `invoke`, `stream` or `wsStream` to answer an interrupt. */
|
|
28
|
+
export interface InterruptResume {
|
|
29
|
+
resume: unknown;
|
|
30
|
+
interrupt_id: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The pending interrupt carried by a stream chunk, or null when the chunk has none. */
|
|
34
|
+
export function getInterrupt(chunk: Pick<StreamChunk, 'event' | 'data'>): Interrupt | null {
|
|
35
|
+
const data = chunk.data;
|
|
36
|
+
if (chunk.event !== 'updates' || data === null || typeof data !== 'object') return null;
|
|
37
|
+
const found = (data as { interrupt?: unknown }).interrupt;
|
|
38
|
+
if (found === null || typeof found !== 'object') return null;
|
|
39
|
+
return typeof (found as Interrupt).id === 'string' ? (found as Interrupt) : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Answer an interrupt with approval. `value` is what the interrupted code receives; it
|
|
44
|
+
* defaults to `true`. When the interrupt sets `response_schema`, pass a value that matches it.
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* await client.invoke([], { config: { thread_id }, ...approveInterrupt(interrupt) });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function approveInterrupt(interrupt: Interrupt, value: unknown = true): InterruptResume {
|
|
51
|
+
return { resume: value, interrupt_id: interrupt.id };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Answer an interrupt with a cancel. The server resumes the interrupted code with `null`
|
|
56
|
+
* and does not check it against `response_schema`.
|
|
57
|
+
*/
|
|
58
|
+
export function rejectInterrupt(interrupt: Interrupt): InterruptResume {
|
|
59
|
+
return { resume: null, interrupt_id: interrupt.id };
|
|
60
|
+
}
|