@witqq/agent-sdk 0.6.1 → 0.8.0

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 (145) hide show
  1. package/README.md +539 -6
  2. package/dist/{types-BvwNzZCj.d.cts → agent-CW9XbmG_.d.ts} +148 -95
  3. package/dist/{types-BvwNzZCj.d.ts → agent-DxY68NZL.d.cts} +148 -95
  4. package/dist/auth/index.cjs +260 -2
  5. package/dist/auth/index.cjs.map +1 -1
  6. package/dist/auth/index.d.cts +21 -138
  7. package/dist/auth/index.d.ts +21 -138
  8. package/dist/auth/index.js +260 -3
  9. package/dist/auth/index.js.map +1 -1
  10. package/dist/backends/claude.cjs +653 -140
  11. package/dist/backends/claude.cjs.map +1 -1
  12. package/dist/backends/claude.d.cts +4 -1
  13. package/dist/backends/claude.d.ts +4 -1
  14. package/dist/backends/claude.js +653 -140
  15. package/dist/backends/claude.js.map +1 -1
  16. package/dist/backends/copilot.cjs +428 -88
  17. package/dist/backends/copilot.cjs.map +1 -1
  18. package/dist/backends/copilot.d.cts +13 -4
  19. package/dist/backends/copilot.d.ts +13 -4
  20. package/dist/backends/copilot.js +428 -88
  21. package/dist/backends/copilot.js.map +1 -1
  22. package/dist/backends/vercel-ai.cjs +349 -77
  23. package/dist/backends/vercel-ai.cjs.map +1 -1
  24. package/dist/backends/vercel-ai.d.cts +3 -1
  25. package/dist/backends/vercel-ai.d.ts +3 -1
  26. package/dist/backends/vercel-ai.js +349 -77
  27. package/dist/backends/vercel-ai.js.map +1 -1
  28. package/dist/backends-BSrsBYFn.d.cts +39 -0
  29. package/dist/backends-BSrsBYFn.d.ts +39 -0
  30. package/dist/chat/accumulator.cjs +147 -0
  31. package/dist/chat/accumulator.cjs.map +1 -0
  32. package/dist/chat/accumulator.d.cts +64 -0
  33. package/dist/chat/accumulator.d.ts +64 -0
  34. package/dist/chat/accumulator.js +145 -0
  35. package/dist/chat/accumulator.js.map +1 -0
  36. package/dist/chat/backends.cjs +3524 -0
  37. package/dist/chat/backends.cjs.map +1 -0
  38. package/dist/chat/backends.d.cts +66 -0
  39. package/dist/chat/backends.d.ts +66 -0
  40. package/dist/chat/backends.js +3512 -0
  41. package/dist/chat/backends.js.map +1 -0
  42. package/dist/chat/context.cjs +280 -0
  43. package/dist/chat/context.cjs.map +1 -0
  44. package/dist/chat/context.d.cts +191 -0
  45. package/dist/chat/context.d.ts +191 -0
  46. package/dist/chat/context.js +277 -0
  47. package/dist/chat/context.js.map +1 -0
  48. package/dist/chat/core.cjs +305 -0
  49. package/dist/chat/core.cjs.map +1 -0
  50. package/dist/chat/core.d.cts +84 -0
  51. package/dist/chat/core.d.ts +84 -0
  52. package/dist/chat/core.js +282 -0
  53. package/dist/chat/core.js.map +1 -0
  54. package/dist/chat/errors.cjs +273 -0
  55. package/dist/chat/errors.cjs.map +1 -0
  56. package/dist/chat/errors.d.cts +97 -0
  57. package/dist/chat/errors.d.ts +97 -0
  58. package/dist/chat/errors.js +266 -0
  59. package/dist/chat/errors.js.map +1 -0
  60. package/dist/chat/events.cjs +203 -0
  61. package/dist/chat/events.cjs.map +1 -0
  62. package/dist/chat/events.d.cts +245 -0
  63. package/dist/chat/events.d.ts +245 -0
  64. package/dist/chat/events.js +196 -0
  65. package/dist/chat/events.js.map +1 -0
  66. package/dist/chat/index.cjs +5550 -0
  67. package/dist/chat/index.cjs.map +1 -0
  68. package/dist/chat/index.d.cts +77 -0
  69. package/dist/chat/index.d.ts +77 -0
  70. package/dist/chat/index.js +5505 -0
  71. package/dist/chat/index.js.map +1 -0
  72. package/dist/chat/react/theme.css +2517 -0
  73. package/dist/chat/react.cjs +3589 -0
  74. package/dist/chat/react.cjs.map +1 -0
  75. package/dist/chat/react.d.cts +1088 -0
  76. package/dist/chat/react.d.ts +1088 -0
  77. package/dist/chat/react.js +3547 -0
  78. package/dist/chat/react.js.map +1 -0
  79. package/dist/chat/runtime.cjs +1245 -0
  80. package/dist/chat/runtime.cjs.map +1 -0
  81. package/dist/chat/runtime.d.cts +182 -0
  82. package/dist/chat/runtime.d.ts +182 -0
  83. package/dist/chat/runtime.js +1243 -0
  84. package/dist/chat/runtime.js.map +1 -0
  85. package/dist/chat/server.cjs +2668 -0
  86. package/dist/chat/server.cjs.map +1 -0
  87. package/dist/chat/server.d.cts +648 -0
  88. package/dist/chat/server.d.ts +648 -0
  89. package/dist/chat/server.js +2628 -0
  90. package/dist/chat/server.js.map +1 -0
  91. package/dist/chat/sessions.cjs +380 -0
  92. package/dist/chat/sessions.cjs.map +1 -0
  93. package/dist/chat/sessions.d.cts +158 -0
  94. package/dist/chat/sessions.d.ts +158 -0
  95. package/dist/chat/sessions.js +376 -0
  96. package/dist/chat/sessions.js.map +1 -0
  97. package/dist/chat/sqlite.cjs +441 -0
  98. package/dist/chat/sqlite.cjs.map +1 -0
  99. package/dist/chat/sqlite.d.cts +128 -0
  100. package/dist/chat/sqlite.d.ts +128 -0
  101. package/dist/chat/sqlite.js +435 -0
  102. package/dist/chat/sqlite.js.map +1 -0
  103. package/dist/chat/state.cjs +190 -0
  104. package/dist/chat/state.cjs.map +1 -0
  105. package/dist/chat/state.d.cts +95 -0
  106. package/dist/chat/state.d.ts +95 -0
  107. package/dist/chat/state.js +180 -0
  108. package/dist/chat/state.js.map +1 -0
  109. package/dist/chat/storage.cjs +249 -0
  110. package/dist/chat/storage.cjs.map +1 -0
  111. package/dist/chat/storage.d.cts +197 -0
  112. package/dist/chat/storage.d.ts +197 -0
  113. package/dist/chat/storage.js +245 -0
  114. package/dist/chat/storage.js.map +1 -0
  115. package/dist/errors-C-so0M4t.d.cts +33 -0
  116. package/dist/errors-C-so0M4t.d.ts +33 -0
  117. package/dist/errors-CmVvczxZ.d.cts +28 -0
  118. package/dist/errors-CmVvczxZ.d.ts +28 -0
  119. package/dist/in-process-transport-C1JnJGVR.d.ts +228 -0
  120. package/dist/in-process-transport-C7DSqPyX.d.cts +228 -0
  121. package/dist/index.cjs +365 -59
  122. package/dist/index.cjs.map +1 -1
  123. package/dist/index.d.cts +322 -125
  124. package/dist/index.d.ts +322 -125
  125. package/dist/index.js +359 -60
  126. package/dist/index.js.map +1 -1
  127. package/dist/provider-types-PTSlRPNB.d.cts +39 -0
  128. package/dist/provider-types-PTSlRPNB.d.ts +39 -0
  129. package/dist/refresh-manager-B81PpYBr.d.cts +153 -0
  130. package/dist/refresh-manager-Dlv_iNZi.d.ts +153 -0
  131. package/dist/testing.cjs +383 -0
  132. package/dist/testing.cjs.map +1 -0
  133. package/dist/testing.d.cts +132 -0
  134. package/dist/testing.d.ts +132 -0
  135. package/dist/testing.js +377 -0
  136. package/dist/testing.js.map +1 -0
  137. package/dist/token-store-CSUBgYwn.d.ts +48 -0
  138. package/dist/token-store-CuC4hB9Z.d.cts +48 -0
  139. package/dist/transport-Cdh3M0tS.d.cts +68 -0
  140. package/dist/transport-Ciap4PWK.d.ts +68 -0
  141. package/dist/types-4vbcmPTp.d.cts +143 -0
  142. package/dist/types-BxggH0Yh.d.ts +143 -0
  143. package/dist/types-DRgd_9R7.d.cts +363 -0
  144. package/dist/types-ajANVzf7.d.ts +363 -0
  145. package/package.json +178 -6
package/dist/index.cjs CHANGED
@@ -26,7 +26,76 @@ var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
26
26
  var path__namespace = /*#__PURE__*/_interopNamespace(path);
27
27
  var os__namespace = /*#__PURE__*/_interopNamespace(os);
28
28
 
29
- // src/types.ts
29
+ // src/types/errors.ts
30
+ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
31
+ ErrorCode2["AUTH_EXPIRED"] = "AUTH_EXPIRED";
32
+ ErrorCode2["AUTH_INVALID"] = "AUTH_INVALID";
33
+ ErrorCode2["RATE_LIMIT"] = "RATE_LIMIT";
34
+ ErrorCode2["NETWORK"] = "NETWORK";
35
+ ErrorCode2["TIMEOUT"] = "TIMEOUT";
36
+ ErrorCode2["PROVIDER_ERROR"] = "PROVIDER_ERROR";
37
+ ErrorCode2["MODEL_NOT_FOUND"] = "MODEL_NOT_FOUND";
38
+ ErrorCode2["MODEL_OVERLOADED"] = "MODEL_OVERLOADED";
39
+ ErrorCode2["CONTEXT_OVERFLOW"] = "CONTEXT_OVERFLOW";
40
+ ErrorCode2["INVALID_INPUT"] = "INVALID_INPUT";
41
+ ErrorCode2["INVALID_RESPONSE"] = "INVALID_RESPONSE";
42
+ ErrorCode2["REENTRANCY"] = "REENTRANCY";
43
+ ErrorCode2["DISPOSED"] = "DISPOSED";
44
+ ErrorCode2["ABORTED"] = "ABORTED";
45
+ ErrorCode2["INVALID_TRANSITION"] = "INVALID_TRANSITION";
46
+ ErrorCode2["DEPENDENCY_MISSING"] = "DEPENDENCY_MISSING";
47
+ ErrorCode2["BACKEND_NOT_INSTALLED"] = "BACKEND_NOT_INSTALLED";
48
+ ErrorCode2["TOOL_EXECUTION"] = "TOOL_EXECUTION";
49
+ ErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED";
50
+ ErrorCode2["SESSION_NOT_FOUND"] = "SESSION_NOT_FOUND";
51
+ ErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
52
+ ErrorCode2["PROVIDER_NOT_FOUND"] = "PROVIDER_NOT_FOUND";
53
+ ErrorCode2["AUTH_REQUIRED"] = "AUTH_REQUIRED";
54
+ ErrorCode2["STORAGE_ERROR"] = "STORAGE_ERROR";
55
+ ErrorCode2["STORAGE_NOT_FOUND"] = "STORAGE_NOT_FOUND";
56
+ ErrorCode2["STORAGE_DUPLICATE_KEY"] = "STORAGE_DUPLICATE_KEY";
57
+ ErrorCode2["STORAGE_IO_ERROR"] = "STORAGE_IO_ERROR";
58
+ ErrorCode2["STORAGE_SERIALIZATION_ERROR"] = "STORAGE_SERIALIZATION_ERROR";
59
+ return ErrorCode2;
60
+ })(ErrorCode || {});
61
+ var RECOVERABLE_CODES = /* @__PURE__ */ new Set([
62
+ "TIMEOUT" /* TIMEOUT */,
63
+ "RATE_LIMIT" /* RATE_LIMIT */,
64
+ "NETWORK" /* NETWORK */,
65
+ "TOOL_EXECUTION" /* TOOL_EXECUTION */,
66
+ "MODEL_OVERLOADED" /* MODEL_OVERLOADED */,
67
+ "PROVIDER_ERROR" /* PROVIDER_ERROR */
68
+ ]);
69
+ function isRecoverableErrorCode(code) {
70
+ return RECOVERABLE_CODES.has(code);
71
+ }
72
+ function classifyAgentError(error) {
73
+ const msg = (error instanceof Error ? error.message : error).toLowerCase();
74
+ if (msg.includes("timeout") || msg.includes("timed out") || msg.includes("timedout") || msg.includes("etimedout")) {
75
+ return "TIMEOUT" /* TIMEOUT */;
76
+ }
77
+ if (msg.includes("rate limit") || msg.includes("rate_limit") || msg.includes("429") || msg.includes("too many requests")) {
78
+ return "RATE_LIMIT" /* RATE_LIMIT */;
79
+ }
80
+ if (msg.includes("unauthorized") || msg.includes("401") || msg.includes("auth") && (msg.includes("expired") || msg.includes("invalid") || msg.includes("denied") || msg.includes("failed"))) {
81
+ return "AUTH_EXPIRED" /* AUTH_EXPIRED */;
82
+ }
83
+ if (msg.includes("econnrefused") || msg.includes("econnreset") || msg.includes("enotfound") || msg.includes("network") || msg.includes("fetch failed") || msg.includes("socket hang up")) {
84
+ return "NETWORK" /* NETWORK */;
85
+ }
86
+ if (msg.includes("subprocess") || msg.includes("process exited") || msg.includes("spawn") || msg.includes("enoent") || msg.includes("killed")) {
87
+ return "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */;
88
+ }
89
+ if (msg.includes("abort") || msg.includes("cancel")) {
90
+ return "ABORTED" /* ABORTED */;
91
+ }
92
+ if (msg.includes("500") || msg.includes("502") || msg.includes("503") || msg.includes("internal server error") || msg.includes("service unavailable") || msg.includes("bad gateway") || msg.includes("overloaded")) {
93
+ return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
94
+ }
95
+ return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
96
+ }
97
+
98
+ // src/types/guards.ts
30
99
  function isToolDefinition(tool) {
31
100
  return "execute" in tool && typeof tool.execute === "function";
32
101
  }
@@ -43,27 +112,47 @@ function getTextContent(content) {
43
112
 
44
113
  // src/errors.ts
45
114
  var AgentSDKError = class extends Error {
115
+ /** @internal Marker for cross-bundle identity checks */
116
+ _agentSDKError = true;
117
+ /** Machine-readable error code. Prefer values from the ErrorCode enum. */
118
+ code;
119
+ /** Whether this error is safe to retry */
120
+ retryable;
121
+ /** HTTP status code hint for error classification */
122
+ httpStatus;
46
123
  constructor(message, options) {
47
124
  super(message, options);
48
125
  this.name = "AgentSDKError";
126
+ this.code = options?.code;
127
+ this.retryable = options?.retryable ?? false;
128
+ this.httpStatus = options?.httpStatus;
129
+ }
130
+ /** Check if an error is an AgentSDKError (works across bundled copies) */
131
+ static is(error) {
132
+ return error instanceof Error && "_agentSDKError" in error && error._agentSDKError === true;
49
133
  }
50
134
  };
51
135
  var ReentrancyError = class extends AgentSDKError {
52
136
  constructor() {
53
- super("Agent is already running. Await the current run before starting another.");
137
+ super("Agent is already running. Await the current run before starting another.", {
138
+ code: "REENTRANCY" /* REENTRANCY */
139
+ });
54
140
  this.name = "ReentrancyError";
55
141
  }
56
142
  };
57
143
  var DisposedError = class extends AgentSDKError {
58
144
  constructor(entity) {
59
- super(`${entity} has been disposed and cannot be used.`);
145
+ super(`${entity} has been disposed and cannot be used.`, {
146
+ code: "DISPOSED" /* DISPOSED */
147
+ });
60
148
  this.name = "DisposedError";
61
149
  }
62
150
  };
63
151
  var BackendNotFoundError = class extends AgentSDKError {
64
152
  constructor(backend) {
65
153
  super(
66
- `Unknown backend: "${backend}". Built-in: copilot, claude, vercel-ai. Custom: use registerBackend() first.`
154
+ `Unknown backend: "${backend}". Built-in: copilot, claude, vercel-ai. Custom: use registerBackend() first.`,
155
+ { code: "BACKEND_NOT_INSTALLED" /* BACKEND_NOT_INSTALLED */ }
67
156
  );
68
157
  this.name = "BackendNotFoundError";
69
158
  }
@@ -76,41 +165,56 @@ var BackendAlreadyRegisteredError = class extends AgentSDKError {
76
165
  };
77
166
  var SubprocessError = class extends AgentSDKError {
78
167
  constructor(message, options) {
79
- super(message, options);
168
+ super(message, { ...options, code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */ });
80
169
  this.name = "SubprocessError";
81
170
  }
82
171
  };
83
172
  var DependencyError = class extends AgentSDKError {
84
173
  packageName;
85
174
  constructor(packageName) {
86
- super(`${packageName} is not installed. Install it: npm install ${packageName}`);
175
+ super(`${packageName} is not installed. Install it: npm install ${packageName}`, {
176
+ code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */
177
+ });
87
178
  this.name = "DependencyError";
88
179
  this.packageName = packageName;
89
180
  }
90
181
  };
91
182
  var AbortError = class extends AgentSDKError {
92
183
  constructor() {
93
- super("Agent run was aborted.");
184
+ super("Agent run was aborted.", { code: "ABORTED" /* ABORTED */ });
94
185
  this.name = "AbortError";
95
186
  }
96
187
  };
97
188
  var ToolExecutionError = class extends AgentSDKError {
98
189
  toolName;
99
190
  constructor(toolName, message, options) {
100
- super(`Tool "${toolName}" failed: ${message}`, options);
191
+ super(`Tool "${toolName}" failed: ${message}`, { ...options, code: "TOOL_EXECUTION" /* TOOL_EXECUTION */ });
101
192
  this.name = "ToolExecutionError";
102
193
  this.toolName = toolName;
103
194
  }
104
195
  };
196
+ var ActivityTimeoutError = class extends AgentSDKError {
197
+ constructor(timeoutMs) {
198
+ super(`Stream activity timeout: no event received within ${timeoutMs}ms.`, {
199
+ code: "TIMEOUT" /* TIMEOUT */,
200
+ retryable: true
201
+ });
202
+ this.name = "ActivityTimeoutError";
203
+ }
204
+ };
105
205
  var StructuredOutputError = class extends AgentSDKError {
106
206
  constructor(message, options) {
107
- super(`Structured output error: ${message}`, options);
207
+ super(`Structured output error: ${message}`, { ...options, code: "INVALID_RESPONSE" /* INVALID_RESPONSE */ });
108
208
  this.name = "StructuredOutputError";
109
209
  }
110
210
  };
111
211
 
112
212
  // src/registry.ts
113
213
  var registry = /* @__PURE__ */ new Map();
214
+ var serviceCache = /* @__PURE__ */ new Map();
215
+ function configCacheKey(name, configId) {
216
+ return `${name}:${configId}`;
217
+ }
114
218
  function registerBackend(name, factory) {
115
219
  if (registry.has(name)) {
116
220
  throw new BackendAlreadyRegisteredError(name);
@@ -121,49 +225,94 @@ function unregisterBackend(name) {
121
225
  return registry.delete(name);
122
226
  }
123
227
  function hasBackend(name) {
124
- return registry.has(name) || isBuiltinName(name);
228
+ return registry.has(name) || lazyLoaders.has(name);
125
229
  }
126
230
  function listBackends() {
127
231
  const names = new Set(registry.keys());
128
- for (const builtin of BUILTIN_BACKENDS) {
129
- names.add(builtin);
232
+ for (const name of lazyLoaders.keys()) {
233
+ names.add(name);
130
234
  }
131
235
  return [...names];
132
236
  }
133
237
  function resetRegistry() {
134
238
  registry.clear();
239
+ serviceCache.clear();
135
240
  }
136
- var BUILTIN_BACKENDS = /* @__PURE__ */ new Set([
137
- "copilot",
138
- "claude",
139
- "vercel-ai"
140
- ]);
141
- function isBuiltinName(name) {
142
- return BUILTIN_BACKENDS.has(name);
241
+ async function disposeBackend(name, configId) {
242
+ if (configId !== void 0) {
243
+ const key = configCacheKey(name, configId);
244
+ const svc = serviceCache.get(key);
245
+ if (!svc) return 0;
246
+ serviceCache.delete(key);
247
+ await svc.dispose();
248
+ return 1;
249
+ }
250
+ const prefix = `${name}:`;
251
+ const toDispose = [];
252
+ for (const [key, svc] of serviceCache) {
253
+ if (key.startsWith(prefix)) {
254
+ toDispose.push(svc);
255
+ serviceCache.delete(key);
256
+ }
257
+ }
258
+ await Promise.all(toDispose.map((s) => s.dispose()));
259
+ return toDispose.length;
143
260
  }
144
- async function loadBuiltinFactory(name) {
145
- switch (name) {
146
- case "copilot": {
261
+ function listConfigs(name) {
262
+ const prefix = `${name}:`;
263
+ const ids = [];
264
+ for (const key of serviceCache.keys()) {
265
+ if (key.startsWith(prefix)) {
266
+ ids.push(key.slice(prefix.length));
267
+ }
268
+ }
269
+ return ids;
270
+ }
271
+ var lazyLoaders = /* @__PURE__ */ new Map([
272
+ [
273
+ "copilot",
274
+ async () => {
147
275
  const mod = await import('./backends/copilot.js');
148
276
  return (opts) => mod.createCopilotService(opts);
149
277
  }
150
- case "claude": {
278
+ ],
279
+ [
280
+ "claude",
281
+ async () => {
151
282
  const mod = await import('./backends/claude.js');
152
283
  return (opts) => mod.createClaudeService(opts);
153
284
  }
154
- case "vercel-ai": {
285
+ ],
286
+ [
287
+ "vercel-ai",
288
+ async () => {
155
289
  const mod = await import('./backends/vercel-ai.js');
156
290
  return (opts) => mod.createVercelAIService(opts);
157
291
  }
158
- }
292
+ ]
293
+ ]);
294
+ function registerLazyBackend(name, loader) {
295
+ lazyLoaders.set(name, loader);
296
+ }
297
+ async function createAgentService(name, options, configId) {
298
+ if (configId !== void 0) {
299
+ const key = configCacheKey(name, configId);
300
+ const cached = serviceCache.get(key);
301
+ if (cached) return cached;
302
+ const service = await createServiceInstance(name, options);
303
+ serviceCache.set(key, service);
304
+ return service;
305
+ }
306
+ return createServiceInstance(name, options);
159
307
  }
160
- async function createAgentService(name, options) {
308
+ async function createServiceInstance(name, options) {
161
309
  const entry = registry.get(name);
162
310
  if (entry) {
163
311
  return entry.factory(options);
164
312
  }
165
- if (isBuiltinName(name)) {
166
- const factory = await loadBuiltinFactory(name);
313
+ const loader = lazyLoaders.get(name);
314
+ if (loader) {
315
+ const factory = await loader();
167
316
  registry.set(name, { factory, builtin: true });
168
317
  return factory(options);
169
318
  }
@@ -175,6 +324,8 @@ var BaseAgent = class {
175
324
  state = "idle";
176
325
  abortController = null;
177
326
  config;
327
+ _cleanupExternalSignal = null;
328
+ _streamMiddleware = [];
178
329
  /** CLI session ID for persistent mode. Override in backends that support it. */
179
330
  get sessionId() {
180
331
  return void 0;
@@ -190,12 +341,14 @@ var BaseAgent = class {
190
341
  this.state = "running";
191
342
  try {
192
343
  const messages = [{ role: "user", content: prompt }];
193
- const result = await this.executeRun(messages, options, ac.signal);
194
- this.enrichAndNotifyUsage(result);
344
+ const result = await this.withRetry(
345
+ () => this.executeRun(messages, options, ac.signal),
346
+ options
347
+ );
348
+ this.enrichAndNotifyUsage(result, options);
195
349
  return result;
196
350
  } finally {
197
- this.state = "idle";
198
- this.abortController = null;
351
+ this.cleanupRun();
199
352
  }
200
353
  }
201
354
  async runWithContext(messages, options) {
@@ -204,12 +357,14 @@ var BaseAgent = class {
204
357
  const ac = this.createAbortController(options?.signal);
205
358
  this.state = "running";
206
359
  try {
207
- const result = await this.executeRun(messages, options, ac.signal);
208
- this.enrichAndNotifyUsage(result);
360
+ const result = await this.withRetry(
361
+ () => this.executeRun(messages, options, ac.signal),
362
+ options
363
+ );
364
+ this.enrichAndNotifyUsage(result, options);
209
365
  return result;
210
366
  } finally {
211
- this.state = "idle";
212
- this.abortController = null;
367
+ this.cleanupRun();
213
368
  }
214
369
  }
215
370
  async runStructured(prompt, schema, options) {
@@ -219,17 +374,14 @@ var BaseAgent = class {
219
374
  this.state = "running";
220
375
  try {
221
376
  const messages = [{ role: "user", content: prompt }];
222
- const result = await this.executeRunStructured(
223
- messages,
224
- schema,
225
- options,
226
- ac.signal
377
+ const result = await this.withRetry(
378
+ () => this.executeRunStructured(messages, schema, options, ac.signal),
379
+ options
227
380
  );
228
- this.enrichAndNotifyUsage(result);
381
+ this.enrichAndNotifyUsage(result, options);
229
382
  return result;
230
383
  } finally {
231
- this.state = "idle";
232
- this.abortController = null;
384
+ this.cleanupRun();
233
385
  }
234
386
  }
235
387
  async *stream(prompt, options) {
@@ -239,11 +391,12 @@ var BaseAgent = class {
239
391
  this.state = "streaming";
240
392
  try {
241
393
  const messages = [{ role: "user", content: prompt }];
242
- const enriched = this.enrichStream(this.executeStream(messages, options, ac.signal));
243
- yield* this.heartbeatStream(enriched);
394
+ yield* this.streamWithRetry(
395
+ () => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
396
+ options
397
+ );
244
398
  } finally {
245
- this.state = "idle";
246
- this.abortController = null;
399
+ this.cleanupRun();
247
400
  }
248
401
  }
249
402
  async *streamWithContext(messages, options) {
@@ -252,13 +405,37 @@ var BaseAgent = class {
252
405
  const ac = this.createAbortController(options?.signal);
253
406
  this.state = "streaming";
254
407
  try {
255
- const enriched = this.enrichStream(this.executeStream(messages, options, ac.signal));
256
- yield* this.heartbeatStream(enriched);
408
+ yield* this.streamWithRetry(
409
+ () => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
410
+ options
411
+ );
257
412
  } finally {
258
- this.state = "idle";
259
- this.abortController = null;
413
+ this.cleanupRun();
260
414
  }
261
415
  }
416
+ /** Register a stream middleware. Applied in registration order after built-in transforms. */
417
+ addStreamMiddleware(middleware) {
418
+ this.guardDisposed();
419
+ this._streamMiddleware.push(middleware);
420
+ }
421
+ /** Apply built-in transforms (enrich→timeout→heartbeat) then custom middleware */
422
+ async *applyStreamPipeline(source, options, ac) {
423
+ let stream = this.enrichStream(source, options);
424
+ stream = this.activityTimeoutStream(stream, options?.activityTimeoutMs, ac);
425
+ stream = this.heartbeatStream(stream);
426
+ if (this._streamMiddleware.length > 0) {
427
+ const ctx = {
428
+ model: options.model,
429
+ backend: this.backendName,
430
+ abortController: ac,
431
+ config: Object.freeze({ ...this.config })
432
+ };
433
+ for (const mw of this._streamMiddleware) {
434
+ stream = mw(stream, ctx);
435
+ }
436
+ }
437
+ yield* stream;
438
+ }
262
439
  abort() {
263
440
  if (this.abortController) {
264
441
  this.abortController.abort();
@@ -276,29 +453,114 @@ var BaseAgent = class {
276
453
  }
277
454
  /** Mark agent as disposed. Override to add cleanup. */
278
455
  dispose() {
456
+ this._cleanupExternalSignal?.();
457
+ this._cleanupExternalSignal = null;
279
458
  this.abort();
280
459
  this.state = "disposed";
281
460
  }
461
+ // ─── Retry Logic ─────────────────────────────────────────────
462
+ /** Check if an error should be retried given the retry configuration. */
463
+ isRetryableError(error, retry) {
464
+ if (error instanceof AbortError || error instanceof ReentrancyError || error instanceof DisposedError) {
465
+ return false;
466
+ }
467
+ if (AgentSDKError.is(error)) {
468
+ if (retry.retryableErrors && retry.retryableErrors.length > 0 && error.code) {
469
+ return retry.retryableErrors.includes(error.code);
470
+ }
471
+ if (error.retryable) return true;
472
+ if (error.code) return isRecoverableErrorCode(error.code);
473
+ }
474
+ return false;
475
+ }
476
+ /** Execute a function with retry logic per RetryConfig. */
477
+ async withRetry(fn, options) {
478
+ const retry = options?.retry;
479
+ if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
480
+ return fn();
481
+ }
482
+ const maxRetries = retry.maxRetries;
483
+ const initialDelay = retry.initialDelayMs ?? 1e3;
484
+ const multiplier = retry.backoffMultiplier ?? 2;
485
+ let lastError;
486
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
487
+ try {
488
+ return await fn();
489
+ } catch (err) {
490
+ lastError = err;
491
+ if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
492
+ throw err;
493
+ }
494
+ const delay = initialDelay * Math.pow(multiplier, attempt);
495
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
496
+ if (options?.signal?.aborted || this.abortController?.signal.aborted) {
497
+ throw err;
498
+ }
499
+ }
500
+ }
501
+ throw lastError;
502
+ }
503
+ /** Execute a stream factory with pre-stream retry: retries until first event, then committed. */
504
+ async *streamWithRetry(factory, options) {
505
+ const retry = options?.retry;
506
+ if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
507
+ yield* factory();
508
+ return;
509
+ }
510
+ const maxRetries = retry.maxRetries;
511
+ const initialDelay = retry.initialDelayMs ?? 1e3;
512
+ const multiplier = retry.backoffMultiplier ?? 2;
513
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
514
+ try {
515
+ const stream = factory();
516
+ const iterator = stream[Symbol.asyncIterator]();
517
+ const first = await iterator.next();
518
+ if (first.done) return;
519
+ yield first.value;
520
+ while (true) {
521
+ const next = await iterator.next();
522
+ if (next.done) break;
523
+ yield next.value;
524
+ }
525
+ return;
526
+ } catch (err) {
527
+ if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
528
+ throw err;
529
+ }
530
+ const delay = initialDelay * Math.pow(multiplier, attempt);
531
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
532
+ if (options?.signal?.aborted || this.abortController?.signal.aborted) {
533
+ throw err;
534
+ }
535
+ }
536
+ }
537
+ }
538
+ // ─── CallOptions Resolution ──────────────────────────────────
539
+ /** Resolve tools to use for this call (per-call override > config default) */
540
+ resolveTools(options) {
541
+ return options?.tools ?? this.config.tools ?? [];
542
+ }
282
543
  // ─── Usage Enrichment ───────────────────────────────────────────
283
544
  /** Enrich result usage with model/backend and fire onUsage callback */
284
- enrichAndNotifyUsage(result) {
545
+ enrichAndNotifyUsage(result, options) {
285
546
  if (result.usage) {
286
547
  result.usage = {
287
548
  ...result.usage,
288
- model: this.config.model,
549
+ model: options.model,
289
550
  backend: this.backendName
290
551
  };
291
552
  this.callOnUsage(result.usage);
292
553
  }
293
554
  }
294
555
  /** Wrap a stream to enrich usage_update events and fire onUsage callback */
295
- async *enrichStream(source) {
556
+ async *enrichStream(source, options) {
557
+ const model = options.model;
296
558
  for await (const event of source) {
297
559
  if (event.type === "usage_update") {
298
560
  const usage = {
299
561
  promptTokens: event.promptTokens,
300
562
  completionTokens: event.completionTokens,
301
- model: this.config.model,
563
+ model,
302
564
  backend: this.backendName
303
565
  };
304
566
  this.callOnUsage(usage);
@@ -368,6 +630,35 @@ var BaseAgent = class {
368
630
  heartbeatResolve = null;
369
631
  }
370
632
  }
633
+ // ─── Activity Timeout ────────────────────────────────────────
634
+ /** Wrap a stream to abort on inactivity. Resets timer on every event.
635
+ * When timeoutMs is not set, passes through directly. */
636
+ async *activityTimeoutStream(source, timeoutMs, ac) {
637
+ if (!timeoutMs || timeoutMs <= 0) {
638
+ yield* source;
639
+ return;
640
+ }
641
+ const iterator = source[Symbol.asyncIterator]();
642
+ let timerId;
643
+ try {
644
+ while (true) {
645
+ const timeoutPromise = new Promise((_, reject) => {
646
+ timerId = setTimeout(() => reject(new ActivityTimeoutError(timeoutMs)), timeoutMs);
647
+ });
648
+ const result = await Promise.race([iterator.next(), timeoutPromise]);
649
+ clearTimeout(timerId);
650
+ if (result.done) break;
651
+ yield result.value;
652
+ }
653
+ } catch (err) {
654
+ if (err instanceof ActivityTimeoutError) {
655
+ ac.abort(err);
656
+ }
657
+ throw err;
658
+ } finally {
659
+ clearTimeout(timerId);
660
+ }
661
+ }
371
662
  // ─── Guards ───────────────────────────────────────────────────
372
663
  guardReentrancy() {
373
664
  if (this.state === "running" || this.state === "streaming") {
@@ -386,16 +677,24 @@ var BaseAgent = class {
386
677
  }
387
678
  }
388
679
  // ─── Internal Helpers ─────────────────────────────────────────
680
+ /** Clean up after a run completes (success, error, or abort). */
681
+ cleanupRun() {
682
+ this._cleanupExternalSignal?.();
683
+ this._cleanupExternalSignal = null;
684
+ this.state = "idle";
685
+ this.abortController = null;
686
+ }
389
687
  createAbortController(externalSignal) {
390
688
  const ac = new AbortController();
391
689
  this.abortController = ac;
690
+ this._cleanupExternalSignal = null;
392
691
  if (externalSignal) {
393
692
  if (externalSignal.aborted) {
394
693
  ac.abort();
395
694
  } else {
396
- externalSignal.addEventListener("abort", () => ac.abort(), {
397
- once: true
398
- });
695
+ const listener = () => ac.abort();
696
+ externalSignal.addEventListener("abort", listener, { once: true });
697
+ this._cleanupExternalSignal = () => externalSignal.removeEventListener("abort", listener);
399
698
  }
400
699
  }
401
700
  return ac;
@@ -593,6 +892,7 @@ function createDefaultPermissionStore(projectDir) {
593
892
  }
594
893
 
595
894
  exports.AbortError = AbortError;
895
+ exports.ActivityTimeoutError = ActivityTimeoutError;
596
896
  exports.AgentSDKError = AgentSDKError;
597
897
  exports.BackendAlreadyRegisteredError = BackendAlreadyRegisteredError;
598
898
  exports.BackendNotFoundError = BackendNotFoundError;
@@ -600,6 +900,7 @@ exports.BaseAgent = BaseAgent;
600
900
  exports.CompositePermissionStore = CompositePermissionStore;
601
901
  exports.DependencyError = DependencyError;
602
902
  exports.DisposedError = DisposedError;
903
+ exports.ErrorCode = ErrorCode;
603
904
  exports.FilePermissionStore = FilePermissionStore;
604
905
  exports.InMemoryPermissionStore = InMemoryPermissionStore;
605
906
  exports.ReentrancyError = ReentrancyError;
@@ -607,17 +908,22 @@ exports.StructuredOutputError = StructuredOutputError;
607
908
  exports.SubprocessError = SubprocessError;
608
909
  exports.ToolExecutionError = ToolExecutionError;
609
910
  exports.buildSystemPrompt = buildSystemPrompt;
911
+ exports.classifyAgentError = classifyAgentError;
610
912
  exports.contentToText = contentToText;
611
913
  exports.createAgentService = createAgentService;
612
914
  exports.createDefaultPermissionStore = createDefaultPermissionStore;
915
+ exports.disposeBackend = disposeBackend;
613
916
  exports.getTextContent = getTextContent;
614
917
  exports.hasBackend = hasBackend;
615
918
  exports.isMultiPartContent = isMultiPartContent;
919
+ exports.isRecoverableErrorCode = isRecoverableErrorCode;
616
920
  exports.isTextContent = isTextContent;
617
921
  exports.isToolDefinition = isToolDefinition;
618
922
  exports.listBackends = listBackends;
923
+ exports.listConfigs = listConfigs;
619
924
  exports.messagesToPrompt = messagesToPrompt;
620
925
  exports.registerBackend = registerBackend;
926
+ exports.registerLazyBackend = registerLazyBackend;
621
927
  exports.resetRegistry = resetRegistry;
622
928
  exports.unregisterBackend = unregisterBackend;
623
929
  exports.zodToJsonSchema = zodToJsonSchema;