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.
Files changed (149) hide show
  1. package/CHANGELOG.md +207 -0
  2. package/README.md +11 -5
  3. package/dist/agent.d.ts +17 -5
  4. package/dist/agent.d.ts.map +1 -1
  5. package/dist/cjs/agent.d.ts +33 -0
  6. package/dist/cjs/client.d.ts +533 -0
  7. package/dist/cjs/compat.d.ts +27 -0
  8. package/dist/cjs/endpoints/addThreadMessages.d.ts +25 -0
  9. package/dist/cjs/endpoints/clearThreadState.d.ts +14 -0
  10. package/dist/cjs/endpoints/deleteFile.d.ts +13 -0
  11. package/dist/cjs/endpoints/deleteMemory.d.ts +18 -0
  12. package/dist/cjs/endpoints/deleteThread.d.ts +18 -0
  13. package/dist/cjs/endpoints/deleteThreadMessage.d.ts +19 -0
  14. package/dist/cjs/endpoints/files.d.ts +115 -0
  15. package/dist/cjs/endpoints/fixGraph.d.ts +33 -0
  16. package/dist/cjs/endpoints/forgetMemories.d.ts +21 -0
  17. package/dist/cjs/endpoints/getMemory.d.ts +18 -0
  18. package/dist/cjs/endpoints/graph.d.ts +50 -0
  19. package/dist/cjs/endpoints/graphTools.d.ts +31 -0
  20. package/dist/cjs/endpoints/invoke.d.ts +66 -0
  21. package/dist/cjs/endpoints/listMemories.d.ts +24 -0
  22. package/dist/cjs/endpoints/metadata.d.ts +5 -0
  23. package/dist/cjs/endpoints/observability.d.ts +111 -0
  24. package/dist/cjs/endpoints/ping.d.ts +9 -0
  25. package/dist/cjs/endpoints/realtime.d.ts +154 -0
  26. package/dist/cjs/endpoints/searchMemory.d.ts +56 -0
  27. package/dist/cjs/endpoints/stateSchema.d.ts +49 -0
  28. package/dist/cjs/endpoints/stopGraph.d.ts +35 -0
  29. package/dist/cjs/endpoints/storeMemory.d.ts +32 -0
  30. package/dist/cjs/endpoints/stream.d.ts +67 -0
  31. package/dist/cjs/endpoints/threadDetails.d.ts +18 -0
  32. package/dist/cjs/endpoints/threadMessage.d.ts +16 -0
  33. package/dist/cjs/endpoints/threadMessages.d.ts +28 -0
  34. package/dist/cjs/endpoints/threadState.d.ts +13 -0
  35. package/dist/cjs/endpoints/threads.d.ts +35 -0
  36. package/dist/cjs/endpoints/updateMemory.d.ts +20 -0
  37. package/dist/cjs/endpoints/updateThreadMessageFeedback.d.ts +19 -0
  38. package/dist/cjs/endpoints/updateThreadState.d.ts +22 -0
  39. package/dist/cjs/endpoints/wsStream.d.ts +34 -0
  40. package/dist/cjs/errors.d.ts +212 -0
  41. package/dist/cjs/index.d.ts +41 -0
  42. package/dist/cjs/interrupt.d.ts +45 -0
  43. package/dist/cjs/message.d.ts +173 -0
  44. package/dist/cjs/package.json +1 -0
  45. package/dist/cjs/request.d.ts +60 -0
  46. package/dist/cjs/tools.d.ts +80 -0
  47. package/dist/cjs/ws.d.ts +47 -0
  48. package/dist/client.d.ts +95 -40
  49. package/dist/client.d.ts.map +1 -1
  50. package/dist/endpoints/addThreadMessages.d.ts +4 -0
  51. package/dist/endpoints/addThreadMessages.d.ts.map +1 -1
  52. package/dist/endpoints/clearThreadState.d.ts.map +1 -1
  53. package/dist/endpoints/deleteFile.d.ts +14 -0
  54. package/dist/endpoints/deleteFile.d.ts.map +1 -0
  55. package/dist/endpoints/deleteMemory.d.ts.map +1 -1
  56. package/dist/endpoints/deleteThread.d.ts.map +1 -1
  57. package/dist/endpoints/deleteThreadMessage.d.ts.map +1 -1
  58. package/dist/endpoints/files.d.ts +33 -0
  59. package/dist/endpoints/files.d.ts.map +1 -1
  60. package/dist/endpoints/fixGraph.d.ts +8 -3
  61. package/dist/endpoints/fixGraph.d.ts.map +1 -1
  62. package/dist/endpoints/forgetMemories.d.ts.map +1 -1
  63. package/dist/endpoints/getMemory.d.ts.map +1 -1
  64. package/dist/endpoints/graph.d.ts +20 -8
  65. package/dist/endpoints/graph.d.ts.map +1 -1
  66. package/dist/endpoints/graphTools.d.ts.map +1 -1
  67. package/dist/endpoints/invoke.d.ts +8 -0
  68. package/dist/endpoints/invoke.d.ts.map +1 -1
  69. package/dist/endpoints/listMemories.d.ts +6 -0
  70. package/dist/endpoints/listMemories.d.ts.map +1 -1
  71. package/dist/endpoints/observability.d.ts +54 -0
  72. package/dist/endpoints/observability.d.ts.map +1 -1
  73. package/dist/endpoints/ping.d.ts.map +1 -1
  74. package/dist/endpoints/realtime.d.ts +25 -4
  75. package/dist/endpoints/realtime.d.ts.map +1 -1
  76. package/dist/endpoints/searchMemory.d.ts.map +1 -1
  77. package/dist/endpoints/stateSchema.d.ts.map +1 -1
  78. package/dist/endpoints/stopGraph.d.ts +13 -3
  79. package/dist/endpoints/stopGraph.d.ts.map +1 -1
  80. package/dist/endpoints/storeMemory.d.ts.map +1 -1
  81. package/dist/endpoints/stream.d.ts +8 -0
  82. package/dist/endpoints/stream.d.ts.map +1 -1
  83. package/dist/endpoints/threadDetails.d.ts.map +1 -1
  84. package/dist/endpoints/threadMessage.d.ts.map +1 -1
  85. package/dist/endpoints/threadMessages.d.ts +6 -0
  86. package/dist/endpoints/threadMessages.d.ts.map +1 -1
  87. package/dist/endpoints/threadState.d.ts.map +1 -1
  88. package/dist/endpoints/threads.d.ts +6 -0
  89. package/dist/endpoints/threads.d.ts.map +1 -1
  90. package/dist/endpoints/updateMemory.d.ts.map +1 -1
  91. package/dist/endpoints/updateThreadMessageFeedback.d.ts +20 -0
  92. package/dist/endpoints/updateThreadMessageFeedback.d.ts.map +1 -0
  93. package/dist/endpoints/updateThreadState.d.ts +6 -1
  94. package/dist/endpoints/updateThreadState.d.ts.map +1 -1
  95. package/dist/endpoints/wsStream.d.ts +2 -0
  96. package/dist/endpoints/wsStream.d.ts.map +1 -1
  97. package/dist/errors.d.ts +60 -2
  98. package/dist/errors.d.ts.map +1 -1
  99. package/dist/index.cjs +3 -3
  100. package/dist/index.cjs.map +1 -1
  101. package/dist/index.d.ts +3 -0
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +1742 -1217
  104. package/dist/index.js.map +1 -1
  105. package/dist/interrupt.d.ts +46 -0
  106. package/dist/interrupt.d.ts.map +1 -0
  107. package/dist/request.d.ts +28 -0
  108. package/dist/request.d.ts.map +1 -1
  109. package/dist/tools.d.ts +14 -0
  110. package/dist/tools.d.ts.map +1 -1
  111. package/package.json +11 -6
  112. package/src/agent.ts +17 -4
  113. package/src/client.ts +248 -128
  114. package/src/endpoints/addThreadMessages.ts +15 -10
  115. package/src/endpoints/clearThreadState.ts +19 -20
  116. package/src/endpoints/deleteFile.ts +65 -0
  117. package/src/endpoints/deleteMemory.ts +9 -13
  118. package/src/endpoints/deleteThread.ts +9 -13
  119. package/src/endpoints/deleteThreadMessage.ts +9 -13
  120. package/src/endpoints/files.ts +164 -131
  121. package/src/endpoints/fixGraph.ts +15 -16
  122. package/src/endpoints/forgetMemories.ts +44 -60
  123. package/src/endpoints/getMemory.ts +9 -9
  124. package/src/endpoints/graph.ts +28 -21
  125. package/src/endpoints/graphTools.ts +7 -13
  126. package/src/endpoints/invoke.ts +105 -84
  127. package/src/endpoints/listMemories.ts +18 -13
  128. package/src/endpoints/observability.ts +77 -34
  129. package/src/endpoints/ping.ts +7 -13
  130. package/src/endpoints/realtime.ts +101 -39
  131. package/src/endpoints/searchMemory.ts +19 -13
  132. package/src/endpoints/stateSchema.ts +7 -13
  133. package/src/endpoints/stopGraph.ts +20 -16
  134. package/src/endpoints/storeMemory.ts +7 -8
  135. package/src/endpoints/stream.ts +179 -61
  136. package/src/endpoints/threadDetails.ts +9 -14
  137. package/src/endpoints/threadMessage.ts +9 -9
  138. package/src/endpoints/threadMessages.ts +15 -9
  139. package/src/endpoints/threadState.ts +19 -20
  140. package/src/endpoints/threads.ts +13 -12
  141. package/src/endpoints/updateMemory.ts +9 -9
  142. package/src/endpoints/updateThreadMessageFeedback.ts +80 -0
  143. package/src/endpoints/updateThreadState.ts +28 -22
  144. package/src/endpoints/wsStream.ts +167 -42
  145. package/src/errors.ts +332 -93
  146. package/src/index.ts +9 -0
  147. package/src/interrupt.ts +60 -0
  148. package/src/request.ts +134 -0
  149. 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 readonly endpoint?: string;
37
- public readonly method?: string;
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
- * Parse error response from API
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 async function parseErrorResponse(response: Response): Promise<ApiErrorResponse | null> {
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.get('content-type');
638
+ const contentType = response.headers?.get('content-type');
425
639
  if (contentType && contentType.includes('application/json')) {
426
- return (await response.json()) as ApiErrorResponse;
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 parseErrorResponse(response);
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
- // Match by HTTP status code
475
- switch (response.status) {
476
- case 400:
477
- return new BadRequestError(message, requestId, timestamp, details);
478
- case 401:
479
- return new AuthenticationError(message, requestId, timestamp, details);
480
- case 403:
481
- return new PermissionError(message, requestId, timestamp, details);
482
- case 404:
483
- return new NotFoundError(message, requestId, timestamp, details);
484
- case 422:
485
- return new ValidationError(message, requestId, timestamp, details);
486
- case 500:
487
- case 502:
488
- case 503:
489
- case 504:
490
- return new ServerError(
491
- message,
492
- requestId,
493
- timestamp,
494
- errorCode || 'INTERNAL_SERVER_ERROR',
495
- details,
496
- response.status
497
- );
498
- default:
499
- return new TenxGraphError(
500
- message,
501
- response.status,
502
- errorCode || 'UNKNOWN_ERROR',
503
- requestId,
504
- timestamp,
505
- details,
506
- undefined,
507
- endpoint,
508
- method
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
- // Fallback if we couldn't parse the error response
514
- const message = fallbackMessage || `HTTP error! status: ${response.status}`;
515
- const timestamp = new Date().toISOString();
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 (response.status) {
752
+ switch (status) {
518
753
  case 400:
519
- return new BadRequestError(message, 'unknown', timestamp);
754
+ return new BadRequestError(message, requestId, timestamp, details);
520
755
  case 401:
521
- return new AuthenticationError(message, 'unknown', timestamp);
756
+ return new AuthenticationError(message, requestId, timestamp, details);
522
757
  case 403:
523
- return new PermissionError(message, 'unknown', timestamp);
758
+ return new PermissionError(message, requestId, timestamp, details);
524
759
  case 404:
525
- return new NotFoundError(message, 'unknown', timestamp);
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, 'unknown', timestamp);
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
- 'unknown',
773
+ requestId,
535
774
  timestamp,
536
- 'INTERNAL_SERVER_ERROR',
537
- [],
538
- response.status
775
+ errorCode || 'INTERNAL_SERVER_ERROR',
776
+ details,
777
+ status
539
778
  );
540
779
  default:
541
780
  return new TenxGraphError(
542
781
  message,
543
- response.status,
544
- 'UNKNOWN_ERROR',
545
- 'unknown',
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';
@@ -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
+ }