@agent-api/sdk 1.2.1 → 1.2.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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog — @agent-api/sdk
2
2
 
3
+ ## 1.2.2
4
+
5
+ ### Added
6
+
7
+ - Added `RequestOptions.signal` so CLI, TUI, and desktop integrations can abort in-flight HTTP requests and response streams before a response ID is available.
8
+ - Documented and tested response cancellation behavior alongside the existing `responses.cancel(responseID)` backend cancellation API.
9
+
3
10
  ## 1.2.1
4
11
 
5
12
  ### Added
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Production JavaScript/TypeScript SDK for the Managed Agent API.
4
4
 
5
- **Published on npm:** [`@agent-api/sdk`](https://www.npmjs.com/package/@agent-api/sdk) (v1.2.1)
5
+ **Published on npm:** [`@agent-api/sdk`](https://www.npmjs.com/package/@agent-api/sdk) (v1.2.2)
6
6
 
7
7
  ## Install
8
8
 
@@ -257,6 +257,7 @@ const context = await createLocalContextPackage(project, {
257
257
 
258
258
  - **Retries:** automatic exponential backoff for network failures, 429, and 5xx (default 2 retries).
259
259
  - **Timeouts:** 10 minute default for requests; 1 hour for streaming agent runs (configurable via `timeout` / `streamTimeout`).
260
+ - **Cancellation:** pass `signal` in request options to abort local HTTP waiting, and call `client.responses.cancel(responseID)` for backend best-effort cancellation after a response ID exists.
260
261
  - **Typed errors:** `AuthenticationError`, `RateLimitError`, `NotFoundError`, `BadRequestError`, etc.
261
262
  - **Pagination:** `listPage` returns a cursor page; `listIterator` auto-fetches all pages.
262
263
 
@@ -273,7 +274,7 @@ const stream = await client.responses.create({
273
274
  preset: "fast-search",
274
275
  input: "Summarize today's AI news.",
275
276
  stream: true,
276
- });
277
+ }, { signal: abortController.signal });
277
278
 
278
279
  for await (const event of stream) {
279
280
  if (event.type === "response.output_text.delta") {
@@ -33,6 +33,9 @@ export class HTTPClient {
33
33
  return await this.fetchOnce(method, path, body, options, stream, rawBody);
34
34
  }
35
35
  catch (error) {
36
+ if (options.signal?.aborted) {
37
+ throw error;
38
+ }
36
39
  if (!(error instanceof APIError) || attempt >= maxRetries) {
37
40
  throw error;
38
41
  }
@@ -43,14 +46,29 @@ export class HTTPClient {
43
46
  }
44
47
  attempt += 1;
45
48
  const delayMs = retryDelayMs(error, attempt);
46
- await sleep(delayMs);
49
+ await sleep(delayMs, options.signal);
47
50
  }
48
51
  }
49
52
  }
50
53
  async fetchOnce(method, path, body, options, stream, rawBody) {
51
54
  const controller = new AbortController();
52
55
  const timeout = options.timeout ?? (stream ? this.options.streamTimeout : this.options.timeout);
53
- const timeoutID = setTimeout(() => controller.abort(), timeout);
56
+ let timedOut = false;
57
+ let callerAborted = options.signal?.aborted ?? false;
58
+ const timeoutID = setTimeout(() => {
59
+ timedOut = true;
60
+ controller.abort();
61
+ }, timeout);
62
+ const abortFromCaller = () => {
63
+ callerAborted = true;
64
+ controller.abort();
65
+ };
66
+ if (options.signal?.aborted) {
67
+ controller.abort();
68
+ }
69
+ else {
70
+ options.signal?.addEventListener("abort", abortFromCaller, { once: true });
71
+ }
54
72
  try {
55
73
  const headers = {
56
74
  Accept: stream ? "text/event-stream" : "application/json",
@@ -80,12 +98,19 @@ export class HTTPClient {
80
98
  throw error;
81
99
  }
82
100
  if (error instanceof Error && error.name === "AbortError") {
83
- throw new APIConnectionError(`Request timed out after ${timeout}ms`, error);
101
+ if (callerAborted || options.signal?.aborted) {
102
+ throw new APIConnectionError("Request aborted", error);
103
+ }
104
+ if (timedOut) {
105
+ throw new APIConnectionError(`Request timed out after ${timeout}ms`, error);
106
+ }
107
+ throw new APIConnectionError("Request aborted", error);
84
108
  }
85
109
  throw new APIConnectionError("Request failed", error);
86
110
  }
87
111
  finally {
88
112
  clearTimeout(timeoutID);
113
+ options.signal?.removeEventListener("abort", abortFromCaller);
89
114
  }
90
115
  }
91
116
  }
@@ -99,6 +124,23 @@ function retryDelayMs(error, attempt) {
99
124
  const jitter = Math.floor(Math.random() * 100);
100
125
  return exponential + jitter;
101
126
  }
102
- function sleep(ms) {
103
- return new Promise((resolve) => setTimeout(resolve, ms));
127
+ function sleep(ms, signal) {
128
+ if (!signal) {
129
+ return new Promise((resolve) => setTimeout(resolve, ms));
130
+ }
131
+ if (signal.aborted) {
132
+ return Promise.reject(new APIConnectionError("Request aborted"));
133
+ }
134
+ return new Promise((resolve, reject) => {
135
+ const timeout = setTimeout(() => {
136
+ signal.removeEventListener("abort", abort);
137
+ resolve();
138
+ }, ms);
139
+ const abort = () => {
140
+ clearTimeout(timeout);
141
+ signal.removeEventListener("abort", abort);
142
+ reject(new APIConnectionError("Request aborted"));
143
+ };
144
+ signal.addEventListener("abort", abort, { once: true });
145
+ });
104
146
  }
@@ -20,6 +20,8 @@ export interface ClientOptions {
20
20
  export interface RequestOptions {
21
21
  headers?: Record<string, string>;
22
22
  timeout?: number;
23
+ /** Abort the underlying HTTP request or stream from caller-controlled UI/runtime state. */
24
+ signal?: AbortSignal;
23
25
  /** Override automatic retries for this request. */
24
26
  maxRetries?: number;
25
27
  }
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "1.2.1";
2
- export declare const USER_AGENT = "@agent-api/sdk/1.2.1";
1
+ export declare const VERSION = "1.2.2";
2
+ export declare const USER_AGENT = "@agent-api/sdk/1.2.2";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
- export const VERSION = "1.2.1";
1
+ export const VERSION = "1.2.2";
2
2
  export const USER_AGENT = `@agent-api/sdk/${VERSION}`;
@@ -36,6 +36,9 @@ class HTTPClient {
36
36
  return await this.fetchOnce(method, path, body, options, stream, rawBody);
37
37
  }
38
38
  catch (error) {
39
+ if (options.signal?.aborted) {
40
+ throw error;
41
+ }
39
42
  if (!(error instanceof errors_js_1.APIError) || attempt >= maxRetries) {
40
43
  throw error;
41
44
  }
@@ -46,14 +49,29 @@ class HTTPClient {
46
49
  }
47
50
  attempt += 1;
48
51
  const delayMs = retryDelayMs(error, attempt);
49
- await sleep(delayMs);
52
+ await sleep(delayMs, options.signal);
50
53
  }
51
54
  }
52
55
  }
53
56
  async fetchOnce(method, path, body, options, stream, rawBody) {
54
57
  const controller = new AbortController();
55
58
  const timeout = options.timeout ?? (stream ? this.options.streamTimeout : this.options.timeout);
56
- const timeoutID = setTimeout(() => controller.abort(), timeout);
59
+ let timedOut = false;
60
+ let callerAborted = options.signal?.aborted ?? false;
61
+ const timeoutID = setTimeout(() => {
62
+ timedOut = true;
63
+ controller.abort();
64
+ }, timeout);
65
+ const abortFromCaller = () => {
66
+ callerAborted = true;
67
+ controller.abort();
68
+ };
69
+ if (options.signal?.aborted) {
70
+ controller.abort();
71
+ }
72
+ else {
73
+ options.signal?.addEventListener("abort", abortFromCaller, { once: true });
74
+ }
57
75
  try {
58
76
  const headers = {
59
77
  Accept: stream ? "text/event-stream" : "application/json",
@@ -83,12 +101,19 @@ class HTTPClient {
83
101
  throw error;
84
102
  }
85
103
  if (error instanceof Error && error.name === "AbortError") {
86
- throw new errors_js_1.APIConnectionError(`Request timed out after ${timeout}ms`, error);
104
+ if (callerAborted || options.signal?.aborted) {
105
+ throw new errors_js_1.APIConnectionError("Request aborted", error);
106
+ }
107
+ if (timedOut) {
108
+ throw new errors_js_1.APIConnectionError(`Request timed out after ${timeout}ms`, error);
109
+ }
110
+ throw new errors_js_1.APIConnectionError("Request aborted", error);
87
111
  }
88
112
  throw new errors_js_1.APIConnectionError("Request failed", error);
89
113
  }
90
114
  finally {
91
115
  clearTimeout(timeoutID);
116
+ options.signal?.removeEventListener("abort", abortFromCaller);
92
117
  }
93
118
  }
94
119
  }
@@ -103,6 +128,23 @@ function retryDelayMs(error, attempt) {
103
128
  const jitter = Math.floor(Math.random() * 100);
104
129
  return exponential + jitter;
105
130
  }
106
- function sleep(ms) {
107
- return new Promise((resolve) => setTimeout(resolve, ms));
131
+ function sleep(ms, signal) {
132
+ if (!signal) {
133
+ return new Promise((resolve) => setTimeout(resolve, ms));
134
+ }
135
+ if (signal.aborted) {
136
+ return Promise.reject(new errors_js_1.APIConnectionError("Request aborted"));
137
+ }
138
+ return new Promise((resolve, reject) => {
139
+ const timeout = setTimeout(() => {
140
+ signal.removeEventListener("abort", abort);
141
+ resolve();
142
+ }, ms);
143
+ const abort = () => {
144
+ clearTimeout(timeout);
145
+ signal.removeEventListener("abort", abort);
146
+ reject(new errors_js_1.APIConnectionError("Request aborted"));
147
+ };
148
+ signal.addEventListener("abort", abort, { once: true });
149
+ });
108
150
  }
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.USER_AGENT = exports.VERSION = void 0;
4
- exports.VERSION = "1.2.1";
4
+ exports.VERSION = "1.2.2";
5
5
  exports.USER_AGENT = `@agent-api/sdk/${exports.VERSION}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-api/sdk",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Production JavaScript SDK for the Managed Agent API",
5
5
  "license": "MIT",
6
6
  "repository": {