@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.js CHANGED
@@ -2,7 +2,76 @@ import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import * as os from 'os';
4
4
 
5
- // src/types.ts
5
+ // src/types/errors.ts
6
+ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
7
+ ErrorCode2["AUTH_EXPIRED"] = "AUTH_EXPIRED";
8
+ ErrorCode2["AUTH_INVALID"] = "AUTH_INVALID";
9
+ ErrorCode2["RATE_LIMIT"] = "RATE_LIMIT";
10
+ ErrorCode2["NETWORK"] = "NETWORK";
11
+ ErrorCode2["TIMEOUT"] = "TIMEOUT";
12
+ ErrorCode2["PROVIDER_ERROR"] = "PROVIDER_ERROR";
13
+ ErrorCode2["MODEL_NOT_FOUND"] = "MODEL_NOT_FOUND";
14
+ ErrorCode2["MODEL_OVERLOADED"] = "MODEL_OVERLOADED";
15
+ ErrorCode2["CONTEXT_OVERFLOW"] = "CONTEXT_OVERFLOW";
16
+ ErrorCode2["INVALID_INPUT"] = "INVALID_INPUT";
17
+ ErrorCode2["INVALID_RESPONSE"] = "INVALID_RESPONSE";
18
+ ErrorCode2["REENTRANCY"] = "REENTRANCY";
19
+ ErrorCode2["DISPOSED"] = "DISPOSED";
20
+ ErrorCode2["ABORTED"] = "ABORTED";
21
+ ErrorCode2["INVALID_TRANSITION"] = "INVALID_TRANSITION";
22
+ ErrorCode2["DEPENDENCY_MISSING"] = "DEPENDENCY_MISSING";
23
+ ErrorCode2["BACKEND_NOT_INSTALLED"] = "BACKEND_NOT_INSTALLED";
24
+ ErrorCode2["TOOL_EXECUTION"] = "TOOL_EXECUTION";
25
+ ErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED";
26
+ ErrorCode2["SESSION_NOT_FOUND"] = "SESSION_NOT_FOUND";
27
+ ErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
28
+ ErrorCode2["PROVIDER_NOT_FOUND"] = "PROVIDER_NOT_FOUND";
29
+ ErrorCode2["AUTH_REQUIRED"] = "AUTH_REQUIRED";
30
+ ErrorCode2["STORAGE_ERROR"] = "STORAGE_ERROR";
31
+ ErrorCode2["STORAGE_NOT_FOUND"] = "STORAGE_NOT_FOUND";
32
+ ErrorCode2["STORAGE_DUPLICATE_KEY"] = "STORAGE_DUPLICATE_KEY";
33
+ ErrorCode2["STORAGE_IO_ERROR"] = "STORAGE_IO_ERROR";
34
+ ErrorCode2["STORAGE_SERIALIZATION_ERROR"] = "STORAGE_SERIALIZATION_ERROR";
35
+ return ErrorCode2;
36
+ })(ErrorCode || {});
37
+ var RECOVERABLE_CODES = /* @__PURE__ */ new Set([
38
+ "TIMEOUT" /* TIMEOUT */,
39
+ "RATE_LIMIT" /* RATE_LIMIT */,
40
+ "NETWORK" /* NETWORK */,
41
+ "TOOL_EXECUTION" /* TOOL_EXECUTION */,
42
+ "MODEL_OVERLOADED" /* MODEL_OVERLOADED */,
43
+ "PROVIDER_ERROR" /* PROVIDER_ERROR */
44
+ ]);
45
+ function isRecoverableErrorCode(code) {
46
+ return RECOVERABLE_CODES.has(code);
47
+ }
48
+ function classifyAgentError(error) {
49
+ const msg = (error instanceof Error ? error.message : error).toLowerCase();
50
+ if (msg.includes("timeout") || msg.includes("timed out") || msg.includes("timedout") || msg.includes("etimedout")) {
51
+ return "TIMEOUT" /* TIMEOUT */;
52
+ }
53
+ if (msg.includes("rate limit") || msg.includes("rate_limit") || msg.includes("429") || msg.includes("too many requests")) {
54
+ return "RATE_LIMIT" /* RATE_LIMIT */;
55
+ }
56
+ if (msg.includes("unauthorized") || msg.includes("401") || msg.includes("auth") && (msg.includes("expired") || msg.includes("invalid") || msg.includes("denied") || msg.includes("failed"))) {
57
+ return "AUTH_EXPIRED" /* AUTH_EXPIRED */;
58
+ }
59
+ if (msg.includes("econnrefused") || msg.includes("econnreset") || msg.includes("enotfound") || msg.includes("network") || msg.includes("fetch failed") || msg.includes("socket hang up")) {
60
+ return "NETWORK" /* NETWORK */;
61
+ }
62
+ if (msg.includes("subprocess") || msg.includes("process exited") || msg.includes("spawn") || msg.includes("enoent") || msg.includes("killed")) {
63
+ return "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */;
64
+ }
65
+ if (msg.includes("abort") || msg.includes("cancel")) {
66
+ return "ABORTED" /* ABORTED */;
67
+ }
68
+ 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")) {
69
+ return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
70
+ }
71
+ return "PROVIDER_ERROR" /* PROVIDER_ERROR */;
72
+ }
73
+
74
+ // src/types/guards.ts
6
75
  function isToolDefinition(tool) {
7
76
  return "execute" in tool && typeof tool.execute === "function";
8
77
  }
@@ -19,27 +88,47 @@ function getTextContent(content) {
19
88
 
20
89
  // src/errors.ts
21
90
  var AgentSDKError = class extends Error {
91
+ /** @internal Marker for cross-bundle identity checks */
92
+ _agentSDKError = true;
93
+ /** Machine-readable error code. Prefer values from the ErrorCode enum. */
94
+ code;
95
+ /** Whether this error is safe to retry */
96
+ retryable;
97
+ /** HTTP status code hint for error classification */
98
+ httpStatus;
22
99
  constructor(message, options) {
23
100
  super(message, options);
24
101
  this.name = "AgentSDKError";
102
+ this.code = options?.code;
103
+ this.retryable = options?.retryable ?? false;
104
+ this.httpStatus = options?.httpStatus;
105
+ }
106
+ /** Check if an error is an AgentSDKError (works across bundled copies) */
107
+ static is(error) {
108
+ return error instanceof Error && "_agentSDKError" in error && error._agentSDKError === true;
25
109
  }
26
110
  };
27
111
  var ReentrancyError = class extends AgentSDKError {
28
112
  constructor() {
29
- super("Agent is already running. Await the current run before starting another.");
113
+ super("Agent is already running. Await the current run before starting another.", {
114
+ code: "REENTRANCY" /* REENTRANCY */
115
+ });
30
116
  this.name = "ReentrancyError";
31
117
  }
32
118
  };
33
119
  var DisposedError = class extends AgentSDKError {
34
120
  constructor(entity) {
35
- super(`${entity} has been disposed and cannot be used.`);
121
+ super(`${entity} has been disposed and cannot be used.`, {
122
+ code: "DISPOSED" /* DISPOSED */
123
+ });
36
124
  this.name = "DisposedError";
37
125
  }
38
126
  };
39
127
  var BackendNotFoundError = class extends AgentSDKError {
40
128
  constructor(backend) {
41
129
  super(
42
- `Unknown backend: "${backend}". Built-in: copilot, claude, vercel-ai. Custom: use registerBackend() first.`
130
+ `Unknown backend: "${backend}". Built-in: copilot, claude, vercel-ai. Custom: use registerBackend() first.`,
131
+ { code: "BACKEND_NOT_INSTALLED" /* BACKEND_NOT_INSTALLED */ }
43
132
  );
44
133
  this.name = "BackendNotFoundError";
45
134
  }
@@ -52,41 +141,56 @@ var BackendAlreadyRegisteredError = class extends AgentSDKError {
52
141
  };
53
142
  var SubprocessError = class extends AgentSDKError {
54
143
  constructor(message, options) {
55
- super(message, options);
144
+ super(message, { ...options, code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */ });
56
145
  this.name = "SubprocessError";
57
146
  }
58
147
  };
59
148
  var DependencyError = class extends AgentSDKError {
60
149
  packageName;
61
150
  constructor(packageName) {
62
- super(`${packageName} is not installed. Install it: npm install ${packageName}`);
151
+ super(`${packageName} is not installed. Install it: npm install ${packageName}`, {
152
+ code: "DEPENDENCY_MISSING" /* DEPENDENCY_MISSING */
153
+ });
63
154
  this.name = "DependencyError";
64
155
  this.packageName = packageName;
65
156
  }
66
157
  };
67
158
  var AbortError = class extends AgentSDKError {
68
159
  constructor() {
69
- super("Agent run was aborted.");
160
+ super("Agent run was aborted.", { code: "ABORTED" /* ABORTED */ });
70
161
  this.name = "AbortError";
71
162
  }
72
163
  };
73
164
  var ToolExecutionError = class extends AgentSDKError {
74
165
  toolName;
75
166
  constructor(toolName, message, options) {
76
- super(`Tool "${toolName}" failed: ${message}`, options);
167
+ super(`Tool "${toolName}" failed: ${message}`, { ...options, code: "TOOL_EXECUTION" /* TOOL_EXECUTION */ });
77
168
  this.name = "ToolExecutionError";
78
169
  this.toolName = toolName;
79
170
  }
80
171
  };
172
+ var ActivityTimeoutError = class extends AgentSDKError {
173
+ constructor(timeoutMs) {
174
+ super(`Stream activity timeout: no event received within ${timeoutMs}ms.`, {
175
+ code: "TIMEOUT" /* TIMEOUT */,
176
+ retryable: true
177
+ });
178
+ this.name = "ActivityTimeoutError";
179
+ }
180
+ };
81
181
  var StructuredOutputError = class extends AgentSDKError {
82
182
  constructor(message, options) {
83
- super(`Structured output error: ${message}`, options);
183
+ super(`Structured output error: ${message}`, { ...options, code: "INVALID_RESPONSE" /* INVALID_RESPONSE */ });
84
184
  this.name = "StructuredOutputError";
85
185
  }
86
186
  };
87
187
 
88
188
  // src/registry.ts
89
189
  var registry = /* @__PURE__ */ new Map();
190
+ var serviceCache = /* @__PURE__ */ new Map();
191
+ function configCacheKey(name, configId) {
192
+ return `${name}:${configId}`;
193
+ }
90
194
  function registerBackend(name, factory) {
91
195
  if (registry.has(name)) {
92
196
  throw new BackendAlreadyRegisteredError(name);
@@ -97,49 +201,94 @@ function unregisterBackend(name) {
97
201
  return registry.delete(name);
98
202
  }
99
203
  function hasBackend(name) {
100
- return registry.has(name) || isBuiltinName(name);
204
+ return registry.has(name) || lazyLoaders.has(name);
101
205
  }
102
206
  function listBackends() {
103
207
  const names = new Set(registry.keys());
104
- for (const builtin of BUILTIN_BACKENDS) {
105
- names.add(builtin);
208
+ for (const name of lazyLoaders.keys()) {
209
+ names.add(name);
106
210
  }
107
211
  return [...names];
108
212
  }
109
213
  function resetRegistry() {
110
214
  registry.clear();
215
+ serviceCache.clear();
111
216
  }
112
- var BUILTIN_BACKENDS = /* @__PURE__ */ new Set([
113
- "copilot",
114
- "claude",
115
- "vercel-ai"
116
- ]);
117
- function isBuiltinName(name) {
118
- return BUILTIN_BACKENDS.has(name);
217
+ async function disposeBackend(name, configId) {
218
+ if (configId !== void 0) {
219
+ const key = configCacheKey(name, configId);
220
+ const svc = serviceCache.get(key);
221
+ if (!svc) return 0;
222
+ serviceCache.delete(key);
223
+ await svc.dispose();
224
+ return 1;
225
+ }
226
+ const prefix = `${name}:`;
227
+ const toDispose = [];
228
+ for (const [key, svc] of serviceCache) {
229
+ if (key.startsWith(prefix)) {
230
+ toDispose.push(svc);
231
+ serviceCache.delete(key);
232
+ }
233
+ }
234
+ await Promise.all(toDispose.map((s) => s.dispose()));
235
+ return toDispose.length;
236
+ }
237
+ function listConfigs(name) {
238
+ const prefix = `${name}:`;
239
+ const ids = [];
240
+ for (const key of serviceCache.keys()) {
241
+ if (key.startsWith(prefix)) {
242
+ ids.push(key.slice(prefix.length));
243
+ }
244
+ }
245
+ return ids;
119
246
  }
120
- async function loadBuiltinFactory(name) {
121
- switch (name) {
122
- case "copilot": {
247
+ var lazyLoaders = /* @__PURE__ */ new Map([
248
+ [
249
+ "copilot",
250
+ async () => {
123
251
  const mod = await import('./backends/copilot.js');
124
252
  return (opts) => mod.createCopilotService(opts);
125
253
  }
126
- case "claude": {
254
+ ],
255
+ [
256
+ "claude",
257
+ async () => {
127
258
  const mod = await import('./backends/claude.js');
128
259
  return (opts) => mod.createClaudeService(opts);
129
260
  }
130
- case "vercel-ai": {
261
+ ],
262
+ [
263
+ "vercel-ai",
264
+ async () => {
131
265
  const mod = await import('./backends/vercel-ai.js');
132
266
  return (opts) => mod.createVercelAIService(opts);
133
267
  }
134
- }
268
+ ]
269
+ ]);
270
+ function registerLazyBackend(name, loader) {
271
+ lazyLoaders.set(name, loader);
135
272
  }
136
- async function createAgentService(name, options) {
273
+ async function createAgentService(name, options, configId) {
274
+ if (configId !== void 0) {
275
+ const key = configCacheKey(name, configId);
276
+ const cached = serviceCache.get(key);
277
+ if (cached) return cached;
278
+ const service = await createServiceInstance(name, options);
279
+ serviceCache.set(key, service);
280
+ return service;
281
+ }
282
+ return createServiceInstance(name, options);
283
+ }
284
+ async function createServiceInstance(name, options) {
137
285
  const entry = registry.get(name);
138
286
  if (entry) {
139
287
  return entry.factory(options);
140
288
  }
141
- if (isBuiltinName(name)) {
142
- const factory = await loadBuiltinFactory(name);
289
+ const loader = lazyLoaders.get(name);
290
+ if (loader) {
291
+ const factory = await loader();
143
292
  registry.set(name, { factory, builtin: true });
144
293
  return factory(options);
145
294
  }
@@ -151,6 +300,8 @@ var BaseAgent = class {
151
300
  state = "idle";
152
301
  abortController = null;
153
302
  config;
303
+ _cleanupExternalSignal = null;
304
+ _streamMiddleware = [];
154
305
  /** CLI session ID for persistent mode. Override in backends that support it. */
155
306
  get sessionId() {
156
307
  return void 0;
@@ -166,12 +317,14 @@ var BaseAgent = class {
166
317
  this.state = "running";
167
318
  try {
168
319
  const messages = [{ role: "user", content: prompt }];
169
- const result = await this.executeRun(messages, options, ac.signal);
170
- this.enrichAndNotifyUsage(result);
320
+ const result = await this.withRetry(
321
+ () => this.executeRun(messages, options, ac.signal),
322
+ options
323
+ );
324
+ this.enrichAndNotifyUsage(result, options);
171
325
  return result;
172
326
  } finally {
173
- this.state = "idle";
174
- this.abortController = null;
327
+ this.cleanupRun();
175
328
  }
176
329
  }
177
330
  async runWithContext(messages, options) {
@@ -180,12 +333,14 @@ var BaseAgent = class {
180
333
  const ac = this.createAbortController(options?.signal);
181
334
  this.state = "running";
182
335
  try {
183
- const result = await this.executeRun(messages, options, ac.signal);
184
- this.enrichAndNotifyUsage(result);
336
+ const result = await this.withRetry(
337
+ () => this.executeRun(messages, options, ac.signal),
338
+ options
339
+ );
340
+ this.enrichAndNotifyUsage(result, options);
185
341
  return result;
186
342
  } finally {
187
- this.state = "idle";
188
- this.abortController = null;
343
+ this.cleanupRun();
189
344
  }
190
345
  }
191
346
  async runStructured(prompt, schema, options) {
@@ -195,17 +350,14 @@ var BaseAgent = class {
195
350
  this.state = "running";
196
351
  try {
197
352
  const messages = [{ role: "user", content: prompt }];
198
- const result = await this.executeRunStructured(
199
- messages,
200
- schema,
201
- options,
202
- ac.signal
353
+ const result = await this.withRetry(
354
+ () => this.executeRunStructured(messages, schema, options, ac.signal),
355
+ options
203
356
  );
204
- this.enrichAndNotifyUsage(result);
357
+ this.enrichAndNotifyUsage(result, options);
205
358
  return result;
206
359
  } finally {
207
- this.state = "idle";
208
- this.abortController = null;
360
+ this.cleanupRun();
209
361
  }
210
362
  }
211
363
  async *stream(prompt, options) {
@@ -215,11 +367,12 @@ var BaseAgent = class {
215
367
  this.state = "streaming";
216
368
  try {
217
369
  const messages = [{ role: "user", content: prompt }];
218
- const enriched = this.enrichStream(this.executeStream(messages, options, ac.signal));
219
- yield* this.heartbeatStream(enriched);
370
+ yield* this.streamWithRetry(
371
+ () => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
372
+ options
373
+ );
220
374
  } finally {
221
- this.state = "idle";
222
- this.abortController = null;
375
+ this.cleanupRun();
223
376
  }
224
377
  }
225
378
  async *streamWithContext(messages, options) {
@@ -228,12 +381,36 @@ var BaseAgent = class {
228
381
  const ac = this.createAbortController(options?.signal);
229
382
  this.state = "streaming";
230
383
  try {
231
- const enriched = this.enrichStream(this.executeStream(messages, options, ac.signal));
232
- yield* this.heartbeatStream(enriched);
384
+ yield* this.streamWithRetry(
385
+ () => this.applyStreamPipeline(this.executeStream(messages, options, ac.signal), options, ac),
386
+ options
387
+ );
233
388
  } finally {
234
- this.state = "idle";
235
- this.abortController = null;
389
+ this.cleanupRun();
390
+ }
391
+ }
392
+ /** Register a stream middleware. Applied in registration order after built-in transforms. */
393
+ addStreamMiddleware(middleware) {
394
+ this.guardDisposed();
395
+ this._streamMiddleware.push(middleware);
396
+ }
397
+ /** Apply built-in transforms (enrich→timeout→heartbeat) then custom middleware */
398
+ async *applyStreamPipeline(source, options, ac) {
399
+ let stream = this.enrichStream(source, options);
400
+ stream = this.activityTimeoutStream(stream, options?.activityTimeoutMs, ac);
401
+ stream = this.heartbeatStream(stream);
402
+ if (this._streamMiddleware.length > 0) {
403
+ const ctx = {
404
+ model: options.model,
405
+ backend: this.backendName,
406
+ abortController: ac,
407
+ config: Object.freeze({ ...this.config })
408
+ };
409
+ for (const mw of this._streamMiddleware) {
410
+ stream = mw(stream, ctx);
411
+ }
236
412
  }
413
+ yield* stream;
237
414
  }
238
415
  abort() {
239
416
  if (this.abortController) {
@@ -252,29 +429,114 @@ var BaseAgent = class {
252
429
  }
253
430
  /** Mark agent as disposed. Override to add cleanup. */
254
431
  dispose() {
432
+ this._cleanupExternalSignal?.();
433
+ this._cleanupExternalSignal = null;
255
434
  this.abort();
256
435
  this.state = "disposed";
257
436
  }
437
+ // ─── Retry Logic ─────────────────────────────────────────────
438
+ /** Check if an error should be retried given the retry configuration. */
439
+ isRetryableError(error, retry) {
440
+ if (error instanceof AbortError || error instanceof ReentrancyError || error instanceof DisposedError) {
441
+ return false;
442
+ }
443
+ if (AgentSDKError.is(error)) {
444
+ if (retry.retryableErrors && retry.retryableErrors.length > 0 && error.code) {
445
+ return retry.retryableErrors.includes(error.code);
446
+ }
447
+ if (error.retryable) return true;
448
+ if (error.code) return isRecoverableErrorCode(error.code);
449
+ }
450
+ return false;
451
+ }
452
+ /** Execute a function with retry logic per RetryConfig. */
453
+ async withRetry(fn, options) {
454
+ const retry = options?.retry;
455
+ if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
456
+ return fn();
457
+ }
458
+ const maxRetries = retry.maxRetries;
459
+ const initialDelay = retry.initialDelayMs ?? 1e3;
460
+ const multiplier = retry.backoffMultiplier ?? 2;
461
+ let lastError;
462
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
463
+ try {
464
+ return await fn();
465
+ } catch (err) {
466
+ lastError = err;
467
+ if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
468
+ throw err;
469
+ }
470
+ const delay = initialDelay * Math.pow(multiplier, attempt);
471
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
472
+ if (options?.signal?.aborted || this.abortController?.signal.aborted) {
473
+ throw err;
474
+ }
475
+ }
476
+ }
477
+ throw lastError;
478
+ }
479
+ /** Execute a stream factory with pre-stream retry: retries until first event, then committed. */
480
+ async *streamWithRetry(factory, options) {
481
+ const retry = options?.retry;
482
+ if (!retry || !retry.maxRetries || retry.maxRetries <= 0) {
483
+ yield* factory();
484
+ return;
485
+ }
486
+ const maxRetries = retry.maxRetries;
487
+ const initialDelay = retry.initialDelayMs ?? 1e3;
488
+ const multiplier = retry.backoffMultiplier ?? 2;
489
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
490
+ try {
491
+ const stream = factory();
492
+ const iterator = stream[Symbol.asyncIterator]();
493
+ const first = await iterator.next();
494
+ if (first.done) return;
495
+ yield first.value;
496
+ while (true) {
497
+ const next = await iterator.next();
498
+ if (next.done) break;
499
+ yield next.value;
500
+ }
501
+ return;
502
+ } catch (err) {
503
+ if (attempt >= maxRetries || !this.isRetryableError(err, retry)) {
504
+ throw err;
505
+ }
506
+ const delay = initialDelay * Math.pow(multiplier, attempt);
507
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
508
+ if (options?.signal?.aborted || this.abortController?.signal.aborted) {
509
+ throw err;
510
+ }
511
+ }
512
+ }
513
+ }
514
+ // ─── CallOptions Resolution ──────────────────────────────────
515
+ /** Resolve tools to use for this call (per-call override > config default) */
516
+ resolveTools(options) {
517
+ return options?.tools ?? this.config.tools ?? [];
518
+ }
258
519
  // ─── Usage Enrichment ───────────────────────────────────────────
259
520
  /** Enrich result usage with model/backend and fire onUsage callback */
260
- enrichAndNotifyUsage(result) {
521
+ enrichAndNotifyUsage(result, options) {
261
522
  if (result.usage) {
262
523
  result.usage = {
263
524
  ...result.usage,
264
- model: this.config.model,
525
+ model: options.model,
265
526
  backend: this.backendName
266
527
  };
267
528
  this.callOnUsage(result.usage);
268
529
  }
269
530
  }
270
531
  /** Wrap a stream to enrich usage_update events and fire onUsage callback */
271
- async *enrichStream(source) {
532
+ async *enrichStream(source, options) {
533
+ const model = options.model;
272
534
  for await (const event of source) {
273
535
  if (event.type === "usage_update") {
274
536
  const usage = {
275
537
  promptTokens: event.promptTokens,
276
538
  completionTokens: event.completionTokens,
277
- model: this.config.model,
539
+ model,
278
540
  backend: this.backendName
279
541
  };
280
542
  this.callOnUsage(usage);
@@ -344,6 +606,35 @@ var BaseAgent = class {
344
606
  heartbeatResolve = null;
345
607
  }
346
608
  }
609
+ // ─── Activity Timeout ────────────────────────────────────────
610
+ /** Wrap a stream to abort on inactivity. Resets timer on every event.
611
+ * When timeoutMs is not set, passes through directly. */
612
+ async *activityTimeoutStream(source, timeoutMs, ac) {
613
+ if (!timeoutMs || timeoutMs <= 0) {
614
+ yield* source;
615
+ return;
616
+ }
617
+ const iterator = source[Symbol.asyncIterator]();
618
+ let timerId;
619
+ try {
620
+ while (true) {
621
+ const timeoutPromise = new Promise((_, reject) => {
622
+ timerId = setTimeout(() => reject(new ActivityTimeoutError(timeoutMs)), timeoutMs);
623
+ });
624
+ const result = await Promise.race([iterator.next(), timeoutPromise]);
625
+ clearTimeout(timerId);
626
+ if (result.done) break;
627
+ yield result.value;
628
+ }
629
+ } catch (err) {
630
+ if (err instanceof ActivityTimeoutError) {
631
+ ac.abort(err);
632
+ }
633
+ throw err;
634
+ } finally {
635
+ clearTimeout(timerId);
636
+ }
637
+ }
347
638
  // ─── Guards ───────────────────────────────────────────────────
348
639
  guardReentrancy() {
349
640
  if (this.state === "running" || this.state === "streaming") {
@@ -362,16 +653,24 @@ var BaseAgent = class {
362
653
  }
363
654
  }
364
655
  // ─── Internal Helpers ─────────────────────────────────────────
656
+ /** Clean up after a run completes (success, error, or abort). */
657
+ cleanupRun() {
658
+ this._cleanupExternalSignal?.();
659
+ this._cleanupExternalSignal = null;
660
+ this.state = "idle";
661
+ this.abortController = null;
662
+ }
365
663
  createAbortController(externalSignal) {
366
664
  const ac = new AbortController();
367
665
  this.abortController = ac;
666
+ this._cleanupExternalSignal = null;
368
667
  if (externalSignal) {
369
668
  if (externalSignal.aborted) {
370
669
  ac.abort();
371
670
  } else {
372
- externalSignal.addEventListener("abort", () => ac.abort(), {
373
- once: true
374
- });
671
+ const listener = () => ac.abort();
672
+ externalSignal.addEventListener("abort", listener, { once: true });
673
+ this._cleanupExternalSignal = () => externalSignal.removeEventListener("abort", listener);
375
674
  }
376
675
  }
377
676
  return ac;
@@ -568,6 +867,6 @@ function createDefaultPermissionStore(projectDir) {
568
867
  return new CompositePermissionStore(sessionStore, projectStore, userStore);
569
868
  }
570
869
 
571
- export { AbortError, AgentSDKError, BackendAlreadyRegisteredError, BackendNotFoundError, BaseAgent, CompositePermissionStore, DependencyError, DisposedError, FilePermissionStore, InMemoryPermissionStore, ReentrancyError, StructuredOutputError, SubprocessError, ToolExecutionError, buildSystemPrompt, contentToText, createAgentService, createDefaultPermissionStore, getTextContent, hasBackend, isMultiPartContent, isTextContent, isToolDefinition, listBackends, messagesToPrompt, registerBackend, resetRegistry, unregisterBackend, zodToJsonSchema };
870
+ export { AbortError, ActivityTimeoutError, AgentSDKError, BackendAlreadyRegisteredError, BackendNotFoundError, BaseAgent, CompositePermissionStore, DependencyError, DisposedError, ErrorCode, FilePermissionStore, InMemoryPermissionStore, ReentrancyError, StructuredOutputError, SubprocessError, ToolExecutionError, buildSystemPrompt, classifyAgentError, contentToText, createAgentService, createDefaultPermissionStore, disposeBackend, getTextContent, hasBackend, isMultiPartContent, isRecoverableErrorCode, isTextContent, isToolDefinition, listBackends, listConfigs, messagesToPrompt, registerBackend, registerLazyBackend, resetRegistry, unregisterBackend, zodToJsonSchema };
572
871
  //# sourceMappingURL=index.js.map
573
872
  //# sourceMappingURL=index.js.map