@arke-institute/sdk 2.5.0 → 2.6.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.
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * Source: Arke v1 API
8
8
  * Version: 1.0.0
9
- * Generated: 2026-01-25T03:52:16.348Z
9
+ * Generated: 2026-01-26T22:08:41.056Z
10
10
  */
11
11
  type paths = {
12
12
  "/ops-reference": {
@@ -2123,6 +2123,9 @@ type paths = {
2123
2123
  *
2124
2124
  * **Performance:** Preview expansion is recommended for most use cases. Full expansion with many large entities can result in multi-MB payloads.
2125
2125
  *
2126
+ * **Expansion Limit:**
2127
+ * Use `?expand_limit=N` to control maximum relationships expanded (1-500, default 100). When truncated, the response includes `_expansion_metadata` with counts.
2128
+ *
2126
2129
  * ---
2127
2130
  * **Permission:** `entity:view`
2128
2131
  * **Auth:** optional
@@ -2132,6 +2135,8 @@ type paths = {
2132
2135
  query?: {
2133
2136
  /** @description Comma-separated list of fields to expand. Supports: relationships[:preview|full] */
2134
2137
  expand?: string;
2138
+ /** @description Maximum number of relationships to expand (1-500, default 100). When exceeded, relationships beyond the limit are returned without peer data. */
2139
+ expand_limit?: number;
2135
2140
  };
2136
2141
  header?: never;
2137
2142
  path: {
@@ -6610,7 +6615,7 @@ type paths = {
6610
6615
  patch?: never;
6611
6616
  trace?: never;
6612
6617
  };
6613
- "/jobs/{id}": {
6618
+ "/agents/{id}/jobs/{job_id}/status": {
6614
6619
  parameters: {
6615
6620
  query?: never;
6616
6621
  header?: never;
@@ -6618,68 +6623,110 @@ type paths = {
6618
6623
  cookie?: never;
6619
6624
  };
6620
6625
  /**
6621
- * Get job status
6622
- * @description Returns focused job status and summary. Use this endpoint for quick status polling.
6626
+ * Get job status from agent
6627
+ * @description Proxies to the agent's `/status/:job_id` endpoint and returns the response.
6628
+ *
6629
+ * Use this endpoint to poll job status after invoking an agent. The `agent_id` and `job_id`
6630
+ * are both returned in the invoke response.
6623
6631
  *
6624
- * Returns 404 if the entity is not a job collection.
6632
+ * **Query Parameters (passed through to agent):**
6633
+ * - `detail=full` - Include detailed sub-job/dispatch information (orchestrators/workflows)
6634
+ * - `errors=N` - Include last N errors (orchestrators only)
6625
6635
  *
6626
- * **Response includes:**
6627
- * - Current status (running/done/error)
6628
- * - Timestamps (started_at, completed_at)
6629
- * - Agent references (agent, main_agent, target)
6630
- * - Counts (files_count, sub_jobs_count)
6636
+ * **Response:** Returns the agent's status response directly. Schema varies by agent type
6637
+ * (service, workflow, orchestrator) but always includes:
6638
+ * - `job_id` - Job identifier
6639
+ * - `status` - Current status (pending/running/done/error)
6640
+ * - `progress` - Progress counters (total/pending/done/error)
6641
+ * - `started_at` - When the job started
6642
+ * - `completed_at` - When the job completed (if done/error)
6643
+ * - `updated_at` - Last state modification
6644
+ *
6645
+ * Agent-specific fields (phase, stages, sub_jobs, folders, dispatches) are also included
6646
+ * when applicable.
6631
6647
  *
6632
6648
  * ---
6633
- * **Permission:** `collection:view`
6649
+ * **Permission:** `agent:view`
6634
6650
  * **Auth:** optional
6635
6651
  */
6636
6652
  get: {
6637
6653
  parameters: {
6638
- query?: never;
6654
+ query?: {
6655
+ detail?: "full";
6656
+ errors?: number | null;
6657
+ };
6639
6658
  header?: never;
6640
6659
  path: {
6641
- /** @description Entity ID (ULID) */
6642
6660
  id: string;
6661
+ job_id: string;
6643
6662
  };
6644
6663
  cookie?: never;
6645
6664
  };
6646
6665
  requestBody?: never;
6647
6666
  responses: {
6648
- /** @description Job status */
6667
+ /** @description Job status from agent */
6649
6668
  200: {
6650
6669
  headers: {
6651
6670
  [name: string]: unknown;
6652
6671
  };
6653
6672
  content: {
6654
- "application/json": components["schemas"]["JobStatusResponse"];
6673
+ "application/json": {
6674
+ /**
6675
+ * @description Unique job identifier
6676
+ * @example job_01KFXPQ3ABCDEFGHIJKLMN
6677
+ */
6678
+ job_id: string;
6679
+ /**
6680
+ * @description Current job status
6681
+ * @example running
6682
+ * @enum {string}
6683
+ */
6684
+ status: "pending" | "running" | "done" | "error";
6685
+ progress: components["schemas"]["JobProgress"];
6686
+ /**
6687
+ * @description When this job started (ISO timestamp)
6688
+ * @example 2026-01-26T17:48:15.000Z
6689
+ */
6690
+ started_at: string;
6691
+ /**
6692
+ * @description When this job completed (ISO timestamp)
6693
+ * @example 2026-01-26T17:49:30.000Z
6694
+ */
6695
+ completed_at?: string;
6696
+ /**
6697
+ * @description Last state modification (ISO timestamp)
6698
+ * @example 2026-01-26T17:49:27.000Z
6699
+ */
6700
+ updated_at?: string;
6701
+ /** @description Final result data (only when status is done) */
6702
+ result?: {
6703
+ [key: string]: unknown;
6704
+ };
6705
+ error?: components["schemas"]["JobError"];
6706
+ };
6655
6707
  };
6656
6708
  };
6657
- /** @description Forbidden - Insufficient permissions */
6658
- 403: {
6709
+ /** @description Not Found - Resource does not exist */
6710
+ 404: {
6659
6711
  headers: {
6660
6712
  [name: string]: unknown;
6661
6713
  };
6662
6714
  content: {
6663
6715
  /**
6664
6716
  * @example {
6665
- * "error": "Forbidden: You do not have permission to perform this action"
6717
+ * "error": "Entity not found"
6666
6718
  * }
6667
6719
  */
6668
6720
  "application/json": components["schemas"]["ErrorResponse"];
6669
6721
  };
6670
6722
  };
6671
- /** @description Not Found - Resource does not exist */
6672
- 404: {
6723
+ /** @description Agent unreachable or returned an error */
6724
+ 502: {
6673
6725
  headers: {
6674
6726
  [name: string]: unknown;
6675
6727
  };
6676
6728
  content: {
6677
- /**
6678
- * @example {
6679
- * "error": "Entity not found"
6680
- * }
6681
- */
6682
- "application/json": components["schemas"]["ErrorResponse"];
6729
+ "application/json": components["schemas"]["AgentUnreachableError"];
6683
6730
  };
6684
6731
  };
6685
6732
  };
@@ -11416,57 +11463,51 @@ type components = {
11416
11463
  */
11417
11464
  confirm?: boolean;
11418
11465
  };
11419
- EntityRef: {
11466
+ JobProgress: {
11420
11467
  /**
11421
- * @description Entity ID (ULID format)
11422
- * @example 01KDETYWYWM0MJVKM8DK3AEXPY
11468
+ * @description Total items to process
11469
+ * @example 10
11423
11470
  */
11424
- pi: string;
11425
- type?: string;
11426
- label?: string;
11427
- };
11428
- JobStatusResponse: {
11471
+ total: number;
11429
11472
  /**
11430
- * @description Entity ID (ULID format)
11431
- * @example 01KDETYWYWM0MJVKM8DK3AEXPY
11473
+ * @description Items not yet started
11474
+ * @example 3
11432
11475
  */
11433
- id: string;
11476
+ pending: number;
11434
11477
  /**
11435
- * @description Content Identifier (CID) - content-addressed hash
11436
- * @example bafyreibug443cnd4endcwinwttw3c3dzmcl2ikht64xzn5qg56bix3usfy
11478
+ * @description Items dispatched but not complete
11479
+ * @example 2
11437
11480
  */
11438
- cid: string;
11481
+ dispatched?: number;
11439
11482
  /**
11440
- * @description Job collection status
11441
- * @example running
11442
- * @enum {string}
11483
+ * @description Successfully completed items
11484
+ * @example 4
11443
11485
  */
11444
- status: "running" | "done" | "error";
11486
+ done: number;
11445
11487
  /**
11446
- * Format: date-time
11447
- * @description ISO 8601 datetime
11448
- * @example 2025-12-26T12:00:00.000Z
11488
+ * @description Failed items
11489
+ * @example 1
11449
11490
  */
11450
- started_at: string;
11491
+ error: number;
11492
+ };
11493
+ JobError: {
11451
11494
  /**
11452
- * Format: date-time
11453
- * @description ISO 8601 datetime
11454
- * @example 2025-12-26T12:00:00.000Z
11495
+ * @description Error code
11496
+ * @example TIMEOUT
11455
11497
  */
11456
- completed_at: string | null;
11457
- agent: components["schemas"]["EntityRef"];
11458
- target?: components["schemas"]["EntityRef"];
11459
- main_agent?: components["schemas"]["EntityRef"];
11498
+ code: string;
11460
11499
  /**
11461
- * @description Number of files contained in this job collection
11462
- * @example 5
11500
+ * @description Human-readable error message
11501
+ * @example Request timed out after 30 seconds
11463
11502
  */
11464
- files_count: number;
11503
+ message: string;
11504
+ };
11505
+ AgentUnreachableError: {
11465
11506
  /**
11466
- * @description Number of sub-job collections
11467
- * @example 2
11507
+ * @description Error message
11508
+ * @example Failed to reach agent: Connection refused
11468
11509
  */
11469
- sub_jobs_count: number;
11510
+ error: string;
11470
11511
  };
11471
11512
  Event: {
11472
11513
  /**
package/dist/index.cjs CHANGED
@@ -57,6 +57,147 @@ var DEFAULT_CONFIG = {
57
57
  network: "main"
58
58
  };
59
59
 
60
+ // src/client/retry.ts
61
+ var DEFAULT_RETRY_CONFIG = {
62
+ maxRetries: 3,
63
+ initialDelay: 100,
64
+ maxDelay: 5e3,
65
+ retryOn5xx: true,
66
+ retryOnNetworkError: true
67
+ };
68
+ var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([
69
+ 500,
70
+ // Internal Server Error
71
+ 502,
72
+ // Bad Gateway
73
+ 503,
74
+ // Service Unavailable
75
+ 504,
76
+ // Gateway Timeout
77
+ 520,
78
+ // Cloudflare: Unknown Error
79
+ 521,
80
+ // Cloudflare: Web Server Is Down
81
+ 522,
82
+ // Cloudflare: Connection Timed Out
83
+ 523,
84
+ // Cloudflare: Origin Is Unreachable
85
+ 524,
86
+ // Cloudflare: A Timeout Occurred
87
+ 525,
88
+ // Cloudflare: SSL Handshake Failed
89
+ 526,
90
+ // Cloudflare: Invalid SSL Certificate
91
+ 527,
92
+ // Cloudflare: Railgun Error
93
+ 530
94
+ // Cloudflare: Origin DNS Error
95
+ ]);
96
+ var NON_RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([
97
+ 400,
98
+ // Bad Request
99
+ 401,
100
+ // Unauthorized
101
+ 403,
102
+ // Forbidden
103
+ 404,
104
+ // Not Found
105
+ 405,
106
+ // Method Not Allowed
107
+ 409,
108
+ // Conflict (CAS errors)
109
+ 410,
110
+ // Gone
111
+ 422,
112
+ // Unprocessable Entity
113
+ 429
114
+ // Too Many Requests (should be handled separately with rate limiting)
115
+ ]);
116
+ function isRetryableStatus(status) {
117
+ if (NON_RETRYABLE_STATUS_CODES.has(status)) {
118
+ return false;
119
+ }
120
+ return RETRYABLE_STATUS_CODES.has(status);
121
+ }
122
+ function isNetworkError(error) {
123
+ if (!(error instanceof Error)) {
124
+ return false;
125
+ }
126
+ if (error instanceof TypeError) {
127
+ const message = error.message.toLowerCase();
128
+ return message.includes("failed to fetch") || message.includes("network") || message.includes("fetch failed") || message.includes("econnrefused") || message.includes("econnreset") || message.includes("etimedout") || message.includes("enotfound") || message.includes("dns") || message.includes("socket");
129
+ }
130
+ if (error.name === "AbortError") {
131
+ return true;
132
+ }
133
+ return false;
134
+ }
135
+ function isCloudflareErrorResponse(response) {
136
+ const contentType = response.headers.get("content-type") || "";
137
+ if (contentType.includes("text/html") && !response.ok) {
138
+ return true;
139
+ }
140
+ return false;
141
+ }
142
+ function calculateDelay(attempt, initialDelay, maxDelay) {
143
+ const exponentialDelay = initialDelay * Math.pow(2, attempt);
144
+ const cappedDelay = Math.min(exponentialDelay, maxDelay);
145
+ const jitter = Math.random() * cappedDelay;
146
+ return Math.floor(cappedDelay + jitter);
147
+ }
148
+ function sleep(ms) {
149
+ return new Promise((resolve) => setTimeout(resolve, ms));
150
+ }
151
+ function createRetryFetch(config = {}) {
152
+ const {
153
+ maxRetries = DEFAULT_RETRY_CONFIG.maxRetries,
154
+ initialDelay = DEFAULT_RETRY_CONFIG.initialDelay,
155
+ maxDelay = DEFAULT_RETRY_CONFIG.maxDelay,
156
+ retryOn5xx = DEFAULT_RETRY_CONFIG.retryOn5xx,
157
+ retryOnNetworkError = DEFAULT_RETRY_CONFIG.retryOnNetworkError,
158
+ onRetry
159
+ } = config;
160
+ return async function retryFetch(input, init) {
161
+ let lastError;
162
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
163
+ try {
164
+ const response = await fetch(input, init);
165
+ if (isCloudflareErrorResponse(response) && attempt < maxRetries) {
166
+ const error = new Error(
167
+ `Cloudflare error (status ${response.status})`
168
+ );
169
+ lastError = error;
170
+ const delay = calculateDelay(attempt, initialDelay, maxDelay);
171
+ onRetry?.(attempt + 1, error, delay);
172
+ await sleep(delay);
173
+ continue;
174
+ }
175
+ if (retryOn5xx && isRetryableStatus(response.status) && attempt < maxRetries) {
176
+ const error = new Error(
177
+ `Server error (status ${response.status})`
178
+ );
179
+ lastError = error;
180
+ const delay = calculateDelay(attempt, initialDelay, maxDelay);
181
+ onRetry?.(attempt + 1, error, delay);
182
+ await sleep(delay);
183
+ continue;
184
+ }
185
+ return response;
186
+ } catch (error) {
187
+ if (retryOnNetworkError && isNetworkError(error) && attempt < maxRetries) {
188
+ lastError = error;
189
+ const delay = calculateDelay(attempt, initialDelay, maxDelay);
190
+ onRetry?.(attempt + 1, error, delay);
191
+ await sleep(delay);
192
+ continue;
193
+ }
194
+ throw error;
195
+ }
196
+ }
197
+ throw lastError ?? new Error("Request failed after retries");
198
+ };
199
+ }
200
+
60
201
  // src/client/errors.ts
61
202
  var ArkeError = class extends Error {
62
203
  constructor(message, code2, status, details) {
@@ -166,9 +307,11 @@ var ArkeClient = class {
166
307
  if (this.config.network === "test") {
167
308
  headers["X-Arke-Network"] = "test";
168
309
  }
310
+ const customFetch = this.config.retry === false ? void 0 : createRetryFetch(this.config.retry ?? {});
169
311
  return (0, import_openapi_fetch.default)({
170
312
  baseUrl: this.config.baseUrl ?? DEFAULT_CONFIG.baseUrl,
171
- headers
313
+ headers,
314
+ ...customFetch && { fetch: customFetch }
172
315
  });
173
316
  }
174
317
  /**
@@ -269,6 +412,46 @@ var ArkeClient = class {
269
412
  });
270
413
  return { data, error };
271
414
  }
415
+ /**
416
+ * Upload file content
417
+ *
418
+ * This is a convenience method that handles the binary body serialization
419
+ * that openapi-fetch doesn't handle automatically for non-JSON bodies.
420
+ *
421
+ * @example
422
+ * ```typescript
423
+ * // Upload from a Blob
424
+ * const blob = new Blob(['Hello, world!'], { type: 'text/plain' });
425
+ * const { data, error } = await arke.uploadFileContent('01ABC...', blob, 'text/plain');
426
+ *
427
+ * // Upload from an ArrayBuffer
428
+ * const buffer = new TextEncoder().encode('Hello, world!').buffer;
429
+ * const { data, error } = await arke.uploadFileContent('01ABC...', buffer, 'text/plain');
430
+ *
431
+ * // Upload from a Uint8Array
432
+ * const bytes = new TextEncoder().encode('Hello, world!');
433
+ * const { data, error } = await arke.uploadFileContent('01ABC...', bytes, 'text/plain');
434
+ * ```
435
+ */
436
+ async uploadFileContent(fileId, content, contentType) {
437
+ let body;
438
+ if (content instanceof Blob) {
439
+ body = content;
440
+ } else if (content instanceof Uint8Array) {
441
+ const buffer = new ArrayBuffer(content.byteLength);
442
+ new Uint8Array(buffer).set(content);
443
+ body = new Blob([buffer], { type: contentType });
444
+ } else {
445
+ body = new Blob([content], { type: contentType });
446
+ }
447
+ const { data, error } = await this.api.POST("/files/{id}/content", {
448
+ params: { path: { id: fileId } },
449
+ body,
450
+ bodySerializer: (b) => b,
451
+ headers: { "Content-Type": contentType }
452
+ });
453
+ return { data, error };
454
+ }
272
455
  };
273
456
  function createArkeClient(config) {
274
457
  return new ArkeClient(config);