@shareai-lab/kode-sdk 2.7.1 → 2.7.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 (97) hide show
  1. package/dist/core/agent/breakpoint-manager.js +36 -0
  2. package/dist/core/agent/message-queue.js +57 -0
  3. package/dist/core/agent/permission-manager.js +32 -0
  4. package/dist/core/agent/todo-manager.js +91 -0
  5. package/dist/core/agent/tool-runner.js +45 -0
  6. package/dist/core/agent.js +2035 -0
  7. package/dist/core/config.js +2 -0
  8. package/dist/core/context-manager.js +241 -0
  9. package/dist/core/errors.js +49 -0
  10. package/dist/core/events.js +329 -0
  11. package/dist/core/file-pool.d.ts +2 -0
  12. package/dist/core/file-pool.js +125 -0
  13. package/dist/core/hooks.js +71 -0
  14. package/dist/core/permission-modes.js +61 -0
  15. package/dist/core/pool.js +301 -0
  16. package/dist/core/room.js +57 -0
  17. package/dist/core/scheduler.js +58 -0
  18. package/dist/core/skills/index.js +20 -0
  19. package/dist/core/skills/management-manager.js +557 -0
  20. package/dist/core/skills/manager.js +243 -0
  21. package/dist/core/skills/operation-queue.js +113 -0
  22. package/dist/core/skills/sandbox-file-manager.js +183 -0
  23. package/dist/core/skills/types.js +9 -0
  24. package/dist/core/skills/xml-generator.js +70 -0
  25. package/dist/core/template.js +35 -0
  26. package/dist/core/time-bridge.js +100 -0
  27. package/dist/core/todo.js +89 -0
  28. package/dist/core/types.js +3 -0
  29. package/dist/index.js +148 -60461
  30. package/dist/infra/db/postgres/postgres-store.js +1073 -0
  31. package/dist/infra/db/sqlite/sqlite-store.js +800 -0
  32. package/dist/infra/e2b/e2b-fs.js +128 -0
  33. package/dist/infra/e2b/e2b-sandbox.js +156 -0
  34. package/dist/infra/e2b/e2b-template.js +105 -0
  35. package/dist/infra/e2b/index.js +9 -0
  36. package/dist/infra/e2b/types.js +2 -0
  37. package/dist/infra/provider.js +67 -0
  38. package/dist/infra/providers/anthropic.js +308 -0
  39. package/dist/infra/providers/core/errors.js +353 -0
  40. package/dist/infra/providers/core/fork.js +418 -0
  41. package/dist/infra/providers/core/index.js +76 -0
  42. package/dist/infra/providers/core/logger.js +191 -0
  43. package/dist/infra/providers/core/retry.js +189 -0
  44. package/dist/infra/providers/core/usage.js +376 -0
  45. package/dist/infra/providers/gemini.js +493 -0
  46. package/dist/infra/providers/index.js +83 -0
  47. package/dist/infra/providers/openai.js +662 -0
  48. package/dist/infra/providers/types.js +20 -0
  49. package/dist/infra/providers/utils.js +400 -0
  50. package/dist/infra/sandbox-factory.js +30 -0
  51. package/dist/infra/sandbox.js +243 -0
  52. package/dist/infra/store/factory.js +80 -0
  53. package/dist/infra/store/index.js +26 -0
  54. package/dist/infra/store/json-store.js +606 -0
  55. package/dist/infra/store/types.js +2 -0
  56. package/dist/infra/store.js +29 -0
  57. package/dist/tools/bash_kill/index.js +35 -0
  58. package/dist/tools/bash_kill/prompt.js +14 -0
  59. package/dist/tools/bash_logs/index.js +40 -0
  60. package/dist/tools/bash_logs/prompt.js +14 -0
  61. package/dist/tools/bash_run/index.js +61 -0
  62. package/dist/tools/bash_run/prompt.js +18 -0
  63. package/dist/tools/builtin.js +26 -0
  64. package/dist/tools/define.js +214 -0
  65. package/dist/tools/fs_edit/index.js +62 -0
  66. package/dist/tools/fs_edit/prompt.js +15 -0
  67. package/dist/tools/fs_glob/index.js +40 -0
  68. package/dist/tools/fs_glob/prompt.js +15 -0
  69. package/dist/tools/fs_grep/index.js +66 -0
  70. package/dist/tools/fs_grep/prompt.js +16 -0
  71. package/dist/tools/fs_multi_edit/index.js +106 -0
  72. package/dist/tools/fs_multi_edit/prompt.js +16 -0
  73. package/dist/tools/fs_read/index.js +40 -0
  74. package/dist/tools/fs_read/prompt.js +16 -0
  75. package/dist/tools/fs_write/index.js +40 -0
  76. package/dist/tools/fs_write/prompt.js +15 -0
  77. package/dist/tools/index.js +61 -0
  78. package/dist/tools/mcp.js +185 -0
  79. package/dist/tools/registry.js +26 -0
  80. package/dist/tools/scripts.js +205 -0
  81. package/dist/tools/skills.js +115 -0
  82. package/dist/tools/task_run/index.js +58 -0
  83. package/dist/tools/task_run/prompt.js +25 -0
  84. package/dist/tools/todo_read/index.js +29 -0
  85. package/dist/tools/todo_read/prompt.js +18 -0
  86. package/dist/tools/todo_write/index.js +42 -0
  87. package/dist/tools/todo_write/prompt.js +23 -0
  88. package/dist/tools/tool.js +211 -0
  89. package/dist/tools/toolkit.js +98 -0
  90. package/dist/tools/type-inference.js +207 -0
  91. package/dist/utils/agent-id.js +28 -0
  92. package/dist/utils/logger.js +44 -0
  93. package/dist/utils/session-id.js +64 -0
  94. package/package.json +7 -38
  95. package/dist/index.js.map +0 -7
  96. package/dist/index.mjs +0 -60385
  97. package/dist/index.mjs.map +0 -7
@@ -0,0 +1,308 @@
1
+ "use strict";
2
+ /**
3
+ * Anthropic Provider Adapter
4
+ *
5
+ * Converts internal Anthropic-style messages to Anthropic API format.
6
+ * Supports:
7
+ * - Extended thinking with interleaved-thinking-2025-05-14 beta
8
+ * - Files API with files-api-2025-04-14 beta
9
+ * - Streaming with SSE
10
+ * - Signature preservation for multi-turn conversations
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.AnthropicProvider = void 0;
14
+ const utils_1 = require("./utils");
15
+ class AnthropicProvider {
16
+ constructor(apiKey, model = 'claude-3-5-sonnet-20241022', baseUrl = 'https://api.anthropic.com', proxyUrl, options) {
17
+ this.apiKey = apiKey;
18
+ this.maxWindowSize = 200000;
19
+ this.maxOutputTokens = 4096;
20
+ this.temperature = 0.7;
21
+ this.model = model;
22
+ this.baseUrl = (0, utils_1.normalizeAnthropicBaseUrl)(baseUrl);
23
+ this.dispatcher = (0, utils_1.getProxyDispatcher)(proxyUrl);
24
+ this.reasoningTransport = options?.reasoningTransport ?? 'provider';
25
+ this.extraHeaders = options?.extraHeaders;
26
+ this.extraBody = options?.extraBody;
27
+ this.providerOptions = options?.providerOptions;
28
+ this.multimodal = options?.multimodal;
29
+ this.thinking = options?.thinking;
30
+ }
31
+ async complete(messages, opts) {
32
+ const body = {
33
+ ...(this.extraBody || {}),
34
+ model: this.model,
35
+ messages: this.formatMessages(messages),
36
+ max_tokens: opts?.maxTokens || 4096,
37
+ };
38
+ if (opts?.temperature !== undefined)
39
+ body.temperature = opts.temperature;
40
+ if (opts?.system)
41
+ body.system = opts.system;
42
+ if (opts?.tools && opts.tools.length > 0)
43
+ body.tools = opts.tools;
44
+ const thinkingConfig = opts?.thinking ?? this.thinking;
45
+ if (this.reasoningTransport === 'provider' && !body.thinking) {
46
+ body.thinking = this.buildThinkingConfig(thinkingConfig);
47
+ }
48
+ const betaEntries = [];
49
+ if (this.reasoningTransport === 'provider') {
50
+ betaEntries.push('interleaved-thinking-2025-05-14');
51
+ }
52
+ if ((0, utils_1.hasAnthropicFileBlocks)(messages)) {
53
+ betaEntries.push('files-api-2025-04-14');
54
+ }
55
+ const headers = {
56
+ 'Content-Type': 'application/json',
57
+ 'x-api-key': this.apiKey,
58
+ 'anthropic-version': '2023-06-01',
59
+ ...(this.extraHeaders || {}),
60
+ };
61
+ const mergedBeta = (0, utils_1.mergeAnthropicBetaHeader)(headers['anthropic-beta'], betaEntries);
62
+ if (mergedBeta) {
63
+ headers['anthropic-beta'] = mergedBeta;
64
+ }
65
+ const response = await fetch(`${this.baseUrl}/v1/messages`, (0, utils_1.withProxy)({
66
+ method: 'POST',
67
+ headers,
68
+ body: JSON.stringify(body),
69
+ }, this.dispatcher));
70
+ if (!response.ok) {
71
+ const error = await response.text();
72
+ throw new Error(`Anthropic API error: ${response.status} ${error}`);
73
+ }
74
+ const data = await response.json();
75
+ const content = (0, utils_1.normalizeAnthropicContent)(data.content, this.reasoningTransport);
76
+ return {
77
+ role: 'assistant',
78
+ content,
79
+ usage: data.usage,
80
+ stop_reason: data.stop_reason,
81
+ };
82
+ }
83
+ async *stream(messages, opts) {
84
+ const body = {
85
+ model: this.model,
86
+ messages: this.formatMessages(messages),
87
+ max_tokens: opts?.maxTokens || 4096,
88
+ stream: true,
89
+ ...(this.extraBody || {}),
90
+ };
91
+ if (opts?.temperature !== undefined)
92
+ body.temperature = opts.temperature;
93
+ if (opts?.system)
94
+ body.system = opts.system;
95
+ if (opts?.tools && opts.tools.length > 0)
96
+ body.tools = opts.tools;
97
+ const thinkingConfig = opts?.thinking ?? this.thinking;
98
+ if (this.reasoningTransport === 'provider' && !body.thinking) {
99
+ body.thinking = this.buildThinkingConfig(thinkingConfig);
100
+ }
101
+ const betaEntries = [];
102
+ if (this.reasoningTransport === 'provider') {
103
+ betaEntries.push('interleaved-thinking-2025-05-14');
104
+ }
105
+ if ((0, utils_1.hasAnthropicFileBlocks)(messages)) {
106
+ betaEntries.push('files-api-2025-04-14');
107
+ }
108
+ const headers = {
109
+ 'Content-Type': 'application/json',
110
+ 'x-api-key': this.apiKey,
111
+ 'anthropic-version': '2023-06-01',
112
+ ...(this.extraHeaders || {}),
113
+ };
114
+ const mergedBeta = (0, utils_1.mergeAnthropicBetaHeader)(headers['anthropic-beta'], betaEntries);
115
+ if (mergedBeta) {
116
+ headers['anthropic-beta'] = mergedBeta;
117
+ }
118
+ const response = await fetch(`${this.baseUrl}/v1/messages`, (0, utils_1.withProxy)({
119
+ method: 'POST',
120
+ headers,
121
+ body: JSON.stringify(body),
122
+ }, this.dispatcher));
123
+ if (!response.ok) {
124
+ const error = await response.text();
125
+ throw new Error(`Anthropic API error: ${response.status} ${error}`);
126
+ }
127
+ const reader = response.body?.getReader();
128
+ if (!reader)
129
+ throw new Error('No response body');
130
+ const decoder = new TextDecoder();
131
+ let buffer = '';
132
+ while (true) {
133
+ const { done, value } = await reader.read();
134
+ if (done)
135
+ break;
136
+ buffer += decoder.decode(value, { stream: true });
137
+ const lines = buffer.split('\n');
138
+ buffer = lines.pop() || '';
139
+ for (const line of lines) {
140
+ if (!line.trim() || !line.startsWith('data: '))
141
+ continue;
142
+ const data = line.slice(6);
143
+ if (data === '[DONE]')
144
+ continue;
145
+ try {
146
+ const event = JSON.parse(data);
147
+ if (event.type === 'content_block_start') {
148
+ const block = (0, utils_1.normalizeAnthropicContentBlock)(event.content_block, this.reasoningTransport);
149
+ if (!block) {
150
+ continue;
151
+ }
152
+ yield { type: 'content_block_start', index: event.index, content_block: block };
153
+ }
154
+ else if (event.type === 'content_block_delta') {
155
+ const delta = (0, utils_1.normalizeAnthropicDelta)(event.delta);
156
+ yield { type: 'content_block_delta', index: event.index, delta };
157
+ }
158
+ else if (event.type === 'content_block_stop') {
159
+ yield { type: 'content_block_stop', index: event.index };
160
+ }
161
+ else if (event.type === 'message_delta') {
162
+ yield { type: 'message_delta', delta: event.delta, usage: event.usage };
163
+ }
164
+ else if (event.type === 'message_stop') {
165
+ yield { type: 'message_stop' };
166
+ }
167
+ }
168
+ catch {
169
+ // Skip invalid JSON
170
+ }
171
+ }
172
+ }
173
+ }
174
+ formatMessages(messages) {
175
+ return messages.map((msg) => {
176
+ const blocks = (0, utils_1.getMessageBlocks)(msg);
177
+ let degraded = false;
178
+ const content = blocks.map((block) => {
179
+ if (block.type === 'text') {
180
+ return { type: 'text', text: block.text };
181
+ }
182
+ if (block.type === 'reasoning') {
183
+ if (this.reasoningTransport === 'text') {
184
+ return { type: 'text', text: `<think>${block.reasoning}</think>` };
185
+ }
186
+ const result = { type: 'thinking', thinking: block.reasoning };
187
+ if (block.meta?.signature) {
188
+ result.signature = block.meta.signature;
189
+ }
190
+ return result;
191
+ }
192
+ if (block.type === 'image') {
193
+ if (block.base64 && block.mime_type) {
194
+ return {
195
+ type: 'image',
196
+ source: {
197
+ type: 'base64',
198
+ media_type: block.mime_type,
199
+ data: block.base64,
200
+ },
201
+ };
202
+ }
203
+ degraded = true;
204
+ return { type: 'text', text: utils_1.IMAGE_UNSUPPORTED_TEXT };
205
+ }
206
+ if (block.type === 'audio') {
207
+ degraded = true;
208
+ return { type: 'text', text: utils_1.AUDIO_UNSUPPORTED_TEXT };
209
+ }
210
+ if (block.type === 'file') {
211
+ if (block.file_id) {
212
+ return {
213
+ type: 'document',
214
+ source: { type: 'file', file_id: block.file_id },
215
+ };
216
+ }
217
+ degraded = true;
218
+ return { type: 'text', text: utils_1.FILE_UNSUPPORTED_TEXT };
219
+ }
220
+ if (block.type === 'tool_use') {
221
+ return {
222
+ type: 'tool_use',
223
+ id: block.id,
224
+ name: block.name,
225
+ input: block.input ?? {},
226
+ };
227
+ }
228
+ if (block.type === 'tool_result') {
229
+ return {
230
+ type: 'tool_result',
231
+ tool_use_id: block.tool_use_id,
232
+ content: (0, utils_1.formatToolResult)(block.content),
233
+ is_error: block.is_error,
234
+ };
235
+ }
236
+ return block;
237
+ });
238
+ if (degraded) {
239
+ (0, utils_1.markTransportIfDegraded)(msg, blocks);
240
+ }
241
+ return {
242
+ role: msg.role === 'system' ? 'user' : msg.role,
243
+ content,
244
+ };
245
+ });
246
+ }
247
+ buildThinkingConfig(thinking) {
248
+ if (!thinking?.enabled && !thinking?.budgetTokens) {
249
+ return { type: 'enabled' };
250
+ }
251
+ const config = { type: 'enabled' };
252
+ if (thinking?.budgetTokens) {
253
+ config.budget_tokens = thinking.budgetTokens;
254
+ }
255
+ return config;
256
+ }
257
+ async uploadFile(input) {
258
+ if (input.kind !== 'file') {
259
+ return null;
260
+ }
261
+ const FormDataCtor = globalThis.FormData;
262
+ const BlobCtor = globalThis.Blob;
263
+ if (!FormDataCtor || !BlobCtor) {
264
+ return null;
265
+ }
266
+ const endpoint = `${(0, utils_1.normalizeAnthropicBaseUrl)(this.baseUrl)}/v1/files`;
267
+ const form = new FormDataCtor();
268
+ form.append('file', new BlobCtor([input.data], { type: input.mimeType }), input.filename || 'file.pdf');
269
+ form.append('purpose', 'document');
270
+ const response = await fetch(endpoint, (0, utils_1.withProxy)({
271
+ method: 'POST',
272
+ headers: {
273
+ 'x-api-key': this.apiKey,
274
+ 'anthropic-version': '2023-06-01',
275
+ 'anthropic-beta': 'files-api-2025-04-14',
276
+ ...(this.extraHeaders || {}),
277
+ },
278
+ body: form,
279
+ }, this.dispatcher));
280
+ if (!response.ok) {
281
+ const error = await response.text();
282
+ throw new Error(`Anthropic file upload error: ${response.status} ${error}`);
283
+ }
284
+ const data = await response.json();
285
+ const fileId = data?.id ?? data?.file_id;
286
+ if (!fileId) {
287
+ return null;
288
+ }
289
+ return { fileId };
290
+ }
291
+ toConfig() {
292
+ return {
293
+ provider: 'anthropic',
294
+ model: this.model,
295
+ baseUrl: this.baseUrl,
296
+ apiKey: this.apiKey,
297
+ maxTokens: this.maxOutputTokens,
298
+ temperature: this.temperature,
299
+ reasoningTransport: this.reasoningTransport,
300
+ extraHeaders: this.extraHeaders,
301
+ extraBody: this.extraBody,
302
+ providerOptions: this.providerOptions,
303
+ multimodal: this.multimodal,
304
+ thinking: this.thinking,
305
+ };
306
+ }
307
+ }
308
+ exports.AnthropicProvider = AnthropicProvider;
@@ -0,0 +1,353 @@
1
+ "use strict";
2
+ /**
3
+ * Provider Error Hierarchy
4
+ *
5
+ * Typed error classes for all provider operations with retry support.
6
+ * Each error type has a unique code and retryable flag.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.ParseError = exports.StreamError = exports.ThinkingSignatureError = exports.ServiceUnavailableError = exports.QuotaExceededError = exports.ModelNotFoundError = exports.ContentFilterError = exports.NetworkError = exports.TimeoutError = exports.ServerError = exports.InvalidRequestError = exports.ContextLengthError = exports.AuthenticationError = exports.RateLimitError = exports.ProviderError = void 0;
10
+ exports.parseProviderError = parseProviderError;
11
+ exports.isRetryableError = isRetryableError;
12
+ exports.isRateLimitError = isRateLimitError;
13
+ exports.isAuthError = isAuthError;
14
+ exports.isContextLengthError = isContextLengthError;
15
+ exports.isContentFilterError = isContentFilterError;
16
+ /**
17
+ * Base class for all provider errors.
18
+ * Provides common properties and JSON serialization.
19
+ */
20
+ class ProviderError extends Error {
21
+ constructor(message, provider, options) {
22
+ super(message);
23
+ this.name = this.constructor.name;
24
+ this.provider = provider;
25
+ this.requestId = options?.requestId;
26
+ this.statusCode = options?.statusCode;
27
+ this.timestamp = Date.now();
28
+ // Maintain proper stack trace in V8
29
+ if (Error.captureStackTrace) {
30
+ Error.captureStackTrace(this, this.constructor);
31
+ }
32
+ }
33
+ toJSON() {
34
+ return {
35
+ name: this.name,
36
+ code: this.code,
37
+ message: this.message,
38
+ provider: this.provider,
39
+ requestId: this.requestId,
40
+ retryable: this.retryable,
41
+ timestamp: this.timestamp,
42
+ statusCode: this.statusCode,
43
+ };
44
+ }
45
+ }
46
+ exports.ProviderError = ProviderError;
47
+ /**
48
+ * Rate limit exceeded (429).
49
+ * Retryable after the specified delay.
50
+ */
51
+ class RateLimitError extends ProviderError {
52
+ constructor(provider, options) {
53
+ super(`Rate limit exceeded${options?.retryAfter ? `, retry after ${options.retryAfter}s` : ''}`, provider, { requestId: options?.requestId, statusCode: 429 });
54
+ this.code = 'RATE_LIMIT';
55
+ this.retryable = true;
56
+ this.retryAfter = options?.retryAfter;
57
+ this.limitType = options?.limitType;
58
+ }
59
+ }
60
+ exports.RateLimitError = RateLimitError;
61
+ /**
62
+ * Authentication failed (401/403).
63
+ * Not retryable - API key or permissions issue.
64
+ */
65
+ class AuthenticationError extends ProviderError {
66
+ constructor(provider, options) {
67
+ super('Authentication failed - check API key and permissions', provider, { requestId: options?.requestId, statusCode: options?.statusCode || 401 });
68
+ this.code = 'AUTH_FAILED';
69
+ this.retryable = false;
70
+ }
71
+ }
72
+ exports.AuthenticationError = AuthenticationError;
73
+ /**
74
+ * Context/token length exceeded.
75
+ * Not retryable - need to reduce input size.
76
+ */
77
+ class ContextLengthError extends ProviderError {
78
+ constructor(provider, maxTokens, requestedTokens, options) {
79
+ super(`Context length ${requestedTokens} exceeds maximum ${maxTokens}`, provider, { requestId: options?.requestId, statusCode: 400 });
80
+ this.code = 'CONTEXT_LENGTH';
81
+ this.retryable = false;
82
+ this.maxTokens = maxTokens;
83
+ this.requestedTokens = requestedTokens;
84
+ }
85
+ }
86
+ exports.ContextLengthError = ContextLengthError;
87
+ /**
88
+ * Invalid request (400).
89
+ * Not retryable - request format issue.
90
+ */
91
+ class InvalidRequestError extends ProviderError {
92
+ constructor(provider, message, options) {
93
+ super(message, provider, { requestId: options?.requestId, statusCode: 400 });
94
+ this.code = 'INVALID_REQUEST';
95
+ this.retryable = false;
96
+ this.details = options?.details;
97
+ }
98
+ }
99
+ exports.InvalidRequestError = InvalidRequestError;
100
+ /**
101
+ * Server error (500/502/503/529).
102
+ * Retryable with exponential backoff.
103
+ */
104
+ class ServerError extends ProviderError {
105
+ constructor(provider, options) {
106
+ super(options?.message || `Server error${options?.statusCode ? ` (${options.statusCode})` : ''}`, provider, { requestId: options?.requestId, statusCode: options?.statusCode || 500 });
107
+ this.code = 'SERVER_ERROR';
108
+ this.retryable = true;
109
+ }
110
+ }
111
+ exports.ServerError = ServerError;
112
+ /**
113
+ * Request timeout.
114
+ * Retryable - may be transient.
115
+ */
116
+ class TimeoutError extends ProviderError {
117
+ constructor(provider, timeoutMs, options) {
118
+ super(`Request timed out after ${timeoutMs}ms`, provider, { requestId: options?.requestId });
119
+ this.code = 'TIMEOUT';
120
+ this.retryable = true;
121
+ this.timeoutMs = timeoutMs;
122
+ }
123
+ }
124
+ exports.TimeoutError = TimeoutError;
125
+ /**
126
+ * Network error (connection failed, DNS, etc).
127
+ * Retryable - may be transient.
128
+ */
129
+ class NetworkError extends ProviderError {
130
+ constructor(provider, message, options) {
131
+ super(message, provider, { requestId: options?.requestId });
132
+ this.code = 'NETWORK_ERROR';
133
+ this.retryable = true;
134
+ this.cause = options?.cause;
135
+ }
136
+ }
137
+ exports.NetworkError = NetworkError;
138
+ /**
139
+ * Content filtered by provider safety systems.
140
+ * Not retryable - content policy violation.
141
+ */
142
+ class ContentFilterError extends ProviderError {
143
+ constructor(provider, options) {
144
+ super(`Content filtered${options?.category ? `: ${options.category}` : ''}`, provider, { requestId: options?.requestId });
145
+ this.code = 'CONTENT_FILTER';
146
+ this.retryable = false;
147
+ this.category = options?.category;
148
+ this.severity = options?.severity;
149
+ }
150
+ }
151
+ exports.ContentFilterError = ContentFilterError;
152
+ /**
153
+ * Model not found or not available.
154
+ * Not retryable - model doesn't exist.
155
+ */
156
+ class ModelNotFoundError extends ProviderError {
157
+ constructor(provider, modelId, options) {
158
+ super(`Model not found: ${modelId}`, provider, { requestId: options?.requestId, statusCode: 404 });
159
+ this.code = 'MODEL_NOT_FOUND';
160
+ this.retryable = false;
161
+ this.modelId = modelId;
162
+ }
163
+ }
164
+ exports.ModelNotFoundError = ModelNotFoundError;
165
+ /**
166
+ * Quota exceeded (different from rate limit).
167
+ * Not retryable without billing action.
168
+ */
169
+ class QuotaExceededError extends ProviderError {
170
+ constructor(provider, options) {
171
+ super(`Quota exceeded${options?.quotaType ? ` (${options.quotaType})` : ''}`, provider, { requestId: options?.requestId, statusCode: 402 });
172
+ this.code = 'QUOTA_EXCEEDED';
173
+ this.retryable = false;
174
+ this.quotaType = options?.quotaType;
175
+ }
176
+ }
177
+ exports.QuotaExceededError = QuotaExceededError;
178
+ /**
179
+ * Service temporarily unavailable.
180
+ * Retryable - usually overload or maintenance.
181
+ */
182
+ class ServiceUnavailableError extends ProviderError {
183
+ constructor(provider, options) {
184
+ super('Service temporarily unavailable', provider, { requestId: options?.requestId, statusCode: 503 });
185
+ this.code = 'SERVICE_UNAVAILABLE';
186
+ this.retryable = true;
187
+ this.retryAfter = options?.retryAfter;
188
+ }
189
+ }
190
+ exports.ServiceUnavailableError = ServiceUnavailableError;
191
+ /**
192
+ * Thinking signature invalid (Anthropic/Gemini multi-turn).
193
+ * Not retryable - message history was modified.
194
+ */
195
+ class ThinkingSignatureError extends ProviderError {
196
+ constructor(provider, options) {
197
+ super('Thinking signature invalid - thinking blocks may have been modified', provider, { requestId: options?.requestId, statusCode: 400 });
198
+ this.code = 'THINKING_SIGNATURE_INVALID';
199
+ this.retryable = false;
200
+ }
201
+ }
202
+ exports.ThinkingSignatureError = ThinkingSignatureError;
203
+ /**
204
+ * Stream error during SSE processing.
205
+ * Retryable - stream may have been interrupted.
206
+ */
207
+ class StreamError extends ProviderError {
208
+ constructor(provider, message, options) {
209
+ super(message, provider, { requestId: options?.requestId });
210
+ this.code = 'STREAM_ERROR';
211
+ this.retryable = true;
212
+ this.cause = options?.cause;
213
+ }
214
+ }
215
+ exports.StreamError = StreamError;
216
+ /**
217
+ * Parse error in response.
218
+ * Not retryable - unexpected response format.
219
+ */
220
+ class ParseError extends ProviderError {
221
+ constructor(provider, message, options) {
222
+ super(message, provider, { requestId: options?.requestId });
223
+ this.code = 'PARSE_ERROR';
224
+ this.retryable = false;
225
+ this.rawResponse = options?.rawResponse;
226
+ }
227
+ }
228
+ exports.ParseError = ParseError;
229
+ /**
230
+ * Parse error response from provider API and return appropriate ProviderError.
231
+ */
232
+ function parseProviderError(error, provider) {
233
+ const statusCode = error.status || error.statusCode || error.response?.status;
234
+ const requestId = error.request_id || error.requestId ||
235
+ error.headers?.['x-request-id'] ||
236
+ error.response?.headers?.['x-request-id'];
237
+ const message = error.message || error.error?.message || 'Unknown error';
238
+ // Rate limit (429)
239
+ if (statusCode === 429) {
240
+ const retryAfter = parseRetryAfter(error);
241
+ return new RateLimitError(provider, { retryAfter, requestId });
242
+ }
243
+ // Auth errors (401/403)
244
+ if (statusCode === 401 || statusCode === 403) {
245
+ return new AuthenticationError(provider, { requestId, statusCode });
246
+ }
247
+ // Server overload (529 - Anthropic specific)
248
+ if (statusCode === 529) {
249
+ return new ServerError(provider, {
250
+ statusCode,
251
+ requestId,
252
+ message: 'API temporarily overloaded',
253
+ });
254
+ }
255
+ // Server errors (500+)
256
+ if (statusCode && statusCode >= 500) {
257
+ if (statusCode === 503) {
258
+ const retryAfter = parseRetryAfter(error);
259
+ return new ServiceUnavailableError(provider, { retryAfter, requestId });
260
+ }
261
+ return new ServerError(provider, { statusCode, requestId });
262
+ }
263
+ // Context length / token errors
264
+ if (error.code === 'context_length_exceeded' ||
265
+ message.toLowerCase().includes('context') ||
266
+ message.toLowerCase().includes('token limit') ||
267
+ message.toLowerCase().includes('too many tokens')) {
268
+ return new ContextLengthError(provider, error.max_tokens || 0, error.requested_tokens || 0, { requestId });
269
+ }
270
+ // Content filter
271
+ if (error.code === 'content_policy_violation' ||
272
+ message.toLowerCase().includes('safety') ||
273
+ message.toLowerCase().includes('content filter') ||
274
+ message.toLowerCase().includes('blocked')) {
275
+ return new ContentFilterError(provider, {
276
+ category: error.category,
277
+ requestId,
278
+ });
279
+ }
280
+ // Thinking signature (Anthropic)
281
+ if (message.toLowerCase().includes('signature')) {
282
+ return new ThinkingSignatureError(provider, { requestId });
283
+ }
284
+ // Model not found (404)
285
+ if (statusCode === 404 || message.toLowerCase().includes('model not found')) {
286
+ return new ModelNotFoundError(provider, error.model || 'unknown', { requestId });
287
+ }
288
+ // Quota exceeded (402)
289
+ if (statusCode === 402 || message.toLowerCase().includes('quota')) {
290
+ return new QuotaExceededError(provider, { requestId });
291
+ }
292
+ // Network errors
293
+ if (error.code === 'ECONNREFUSED' ||
294
+ error.code === 'ENOTFOUND' ||
295
+ error.code === 'ETIMEDOUT' ||
296
+ error.code === 'ECONNRESET') {
297
+ return new NetworkError(provider, message, { cause: error, requestId });
298
+ }
299
+ // Timeout
300
+ if (error.code === 'TIMEOUT' || message.toLowerCase().includes('timeout')) {
301
+ return new TimeoutError(provider, error.timeout || 0, { requestId });
302
+ }
303
+ // Default to invalid request for 400
304
+ if (statusCode === 400) {
305
+ return new InvalidRequestError(provider, message, {
306
+ requestId,
307
+ details: error.error || error.details,
308
+ });
309
+ }
310
+ // Fallback to server error
311
+ return new ServerError(provider, { statusCode, requestId, message });
312
+ }
313
+ /**
314
+ * Parse retry-after header value.
315
+ */
316
+ function parseRetryAfter(error) {
317
+ const header = error.headers?.['retry-after'] ||
318
+ error.response?.headers?.['retry-after'];
319
+ if (header) {
320
+ const seconds = parseInt(header, 10);
321
+ if (!isNaN(seconds))
322
+ return seconds;
323
+ }
324
+ // Some providers include retry info in error body
325
+ if (error.retry_after) {
326
+ return error.retry_after;
327
+ }
328
+ return undefined;
329
+ }
330
+ /**
331
+ * Check if an error is retryable.
332
+ */
333
+ function isRetryableError(error) {
334
+ if (error instanceof ProviderError) {
335
+ return error.retryable;
336
+ }
337
+ return false;
338
+ }
339
+ /**
340
+ * Check if error is a specific type.
341
+ */
342
+ function isRateLimitError(error) {
343
+ return error instanceof RateLimitError;
344
+ }
345
+ function isAuthError(error) {
346
+ return error instanceof AuthenticationError;
347
+ }
348
+ function isContextLengthError(error) {
349
+ return error instanceof ContextLengthError;
350
+ }
351
+ function isContentFilterError(error) {
352
+ return error instanceof ContentFilterError;
353
+ }