agents-library 1.1.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.

Potentially problematic release.


This version of agents-library might be problematic. Click here for more details.

Files changed (89) hide show
  1. package/dist/base-agent.d.ts +172 -0
  2. package/dist/base-agent.d.ts.map +1 -0
  3. package/dist/base-agent.js +255 -0
  4. package/dist/base-agent.js.map +1 -0
  5. package/dist/base-bot.d.ts +282 -0
  6. package/dist/base-bot.d.ts.map +1 -0
  7. package/dist/base-bot.js +375 -0
  8. package/dist/base-bot.js.map +1 -0
  9. package/dist/common/result.d.ts +51 -0
  10. package/dist/common/result.d.ts.map +1 -0
  11. package/dist/common/result.js +45 -0
  12. package/dist/common/result.js.map +1 -0
  13. package/dist/common/types.d.ts +57 -0
  14. package/dist/common/types.d.ts.map +1 -0
  15. package/dist/common/types.js +42 -0
  16. package/dist/common/types.js.map +1 -0
  17. package/dist/index.d.ts +94 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +108 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/kadi-event-publisher.d.ts +163 -0
  22. package/dist/kadi-event-publisher.d.ts.map +1 -0
  23. package/dist/kadi-event-publisher.js +286 -0
  24. package/dist/kadi-event-publisher.js.map +1 -0
  25. package/dist/memory/arcadedb-adapter.d.ts +159 -0
  26. package/dist/memory/arcadedb-adapter.d.ts.map +1 -0
  27. package/dist/memory/arcadedb-adapter.js +314 -0
  28. package/dist/memory/arcadedb-adapter.js.map +1 -0
  29. package/dist/memory/file-storage-adapter.d.ts +122 -0
  30. package/dist/memory/file-storage-adapter.d.ts.map +1 -0
  31. package/dist/memory/file-storage-adapter.js +352 -0
  32. package/dist/memory/file-storage-adapter.js.map +1 -0
  33. package/dist/memory/memory-service.d.ts +208 -0
  34. package/dist/memory/memory-service.d.ts.map +1 -0
  35. package/dist/memory/memory-service.js +410 -0
  36. package/dist/memory/memory-service.js.map +1 -0
  37. package/dist/memory/types.d.ts +126 -0
  38. package/dist/memory/types.d.ts.map +1 -0
  39. package/dist/memory/types.js +41 -0
  40. package/dist/memory/types.js.map +1 -0
  41. package/dist/producer-tool-utils.d.ts +474 -0
  42. package/dist/producer-tool-utils.d.ts.map +1 -0
  43. package/dist/producer-tool-utils.js +664 -0
  44. package/dist/producer-tool-utils.js.map +1 -0
  45. package/dist/providers/anthropic-provider.d.ts +160 -0
  46. package/dist/providers/anthropic-provider.d.ts.map +1 -0
  47. package/dist/providers/anthropic-provider.js +527 -0
  48. package/dist/providers/anthropic-provider.js.map +1 -0
  49. package/dist/providers/model-manager-provider.d.ts +91 -0
  50. package/dist/providers/model-manager-provider.d.ts.map +1 -0
  51. package/dist/providers/model-manager-provider.js +355 -0
  52. package/dist/providers/model-manager-provider.js.map +1 -0
  53. package/dist/providers/provider-manager.d.ts +111 -0
  54. package/dist/providers/provider-manager.d.ts.map +1 -0
  55. package/dist/providers/provider-manager.js +337 -0
  56. package/dist/providers/provider-manager.js.map +1 -0
  57. package/dist/providers/types.d.ts +145 -0
  58. package/dist/providers/types.d.ts.map +1 -0
  59. package/dist/providers/types.js +23 -0
  60. package/dist/providers/types.js.map +1 -0
  61. package/dist/shadow-agent-factory.d.ts +623 -0
  62. package/dist/shadow-agent-factory.d.ts.map +1 -0
  63. package/dist/shadow-agent-factory.js +1117 -0
  64. package/dist/shadow-agent-factory.js.map +1 -0
  65. package/dist/types/agent-config.d.ts +307 -0
  66. package/dist/types/agent-config.d.ts.map +1 -0
  67. package/dist/types/agent-config.js +15 -0
  68. package/dist/types/agent-config.js.map +1 -0
  69. package/dist/types/event-schemas.d.ts +358 -0
  70. package/dist/types/event-schemas.d.ts.map +1 -0
  71. package/dist/types/event-schemas.js +188 -0
  72. package/dist/types/event-schemas.js.map +1 -0
  73. package/dist/types/tool-schemas.d.ts +498 -0
  74. package/dist/types/tool-schemas.d.ts.map +1 -0
  75. package/dist/types/tool-schemas.js +457 -0
  76. package/dist/types/tool-schemas.js.map +1 -0
  77. package/dist/utils/logger.d.ts +135 -0
  78. package/dist/utils/logger.d.ts.map +1 -0
  79. package/dist/utils/logger.js +205 -0
  80. package/dist/utils/logger.js.map +1 -0
  81. package/dist/utils/timer.d.ts +186 -0
  82. package/dist/utils/timer.d.ts.map +1 -0
  83. package/dist/utils/timer.js +211 -0
  84. package/dist/utils/timer.js.map +1 -0
  85. package/dist/worker-agent-factory.d.ts +688 -0
  86. package/dist/worker-agent-factory.d.ts.map +1 -0
  87. package/dist/worker-agent-factory.js +1517 -0
  88. package/dist/worker-agent-factory.js.map +1 -0
  89. package/package.json +38 -0
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Anthropic Provider Implementation
3
+ *
4
+ * Implements LLMProvider interface for Anthropic Claude models.
5
+ * Provides chat completion, streaming, health checks, and model discovery.
6
+ */
7
+ import type { LLMProvider, Message, ChatOptions, ProviderError } from './types.js';
8
+ import type { Result } from '../common/result.js';
9
+ /**
10
+ * Anthropic Claude Provider
11
+ *
12
+ * Wraps the Anthropic SDK to provide standardized LLM provider interface.
13
+ * Supports both standard and streaming chat completions.
14
+ */
15
+ export declare class AnthropicProvider implements LLMProvider {
16
+ readonly name = "anthropic";
17
+ private client;
18
+ private consecutiveFailures;
19
+ private readonly maxConsecutiveFailures;
20
+ /**
21
+ * Default model configuration
22
+ */
23
+ private readonly defaultModel;
24
+ private readonly defaultMaxTokens;
25
+ /**
26
+ * Model name mapping for user-friendly aliases
27
+ * Maps shorthand names to full Anthropic model identifiers
28
+ */
29
+ private readonly modelAliases;
30
+ /**
31
+ * Model-specific maximum output token limits
32
+ * Maps model identifiers to their maximum allowed output tokens
33
+ */
34
+ private readonly modelMaxTokens;
35
+ /**
36
+ * Create Anthropic provider instance
37
+ *
38
+ * @param apiKey - Anthropic API key
39
+ */
40
+ constructor(apiKey: string);
41
+ /**
42
+ * Normalize model name using aliases
43
+ *
44
+ * Converts user-friendly model names to actual Anthropic model identifiers.
45
+ * Returns the input model name if no mapping is found (assumes it's already valid).
46
+ *
47
+ * @param model - User-provided model name
48
+ * @returns Normalized Anthropic model identifier
49
+ */
50
+ private normalizeModelName;
51
+ /**
52
+ * Get appropriate max tokens for a model
53
+ *
54
+ * Returns model-specific token limit or falls back to default.
55
+ * Prevents exceeding model's maximum output token capacity.
56
+ *
57
+ * @param normalizedModel - Normalized model identifier
58
+ * @param requestedMaxTokens - User-requested max tokens (optional)
59
+ * @returns Safe max tokens value for the model
60
+ */
61
+ private getMaxTokensForModel;
62
+ /**
63
+ * Generate chat completion
64
+ *
65
+ * @param messages - Conversation messages
66
+ * @param options - Optional chat configuration
67
+ * @returns Result with response text or error
68
+ */
69
+ /**
70
+ * Convert OpenAI tool format to Anthropic tool format
71
+ *
72
+ * OpenAI format:
73
+ * {
74
+ * type: "function",
75
+ * function: {
76
+ * name: "tool_name",
77
+ * description: "...",
78
+ * parameters: { type: "object", properties: {...}, required: [...] }
79
+ * }
80
+ * }
81
+ *
82
+ * Anthropic format:
83
+ * {
84
+ * name: "tool_name",
85
+ * description: "...",
86
+ * input_schema: { type: "object", properties: {...}, required: [...] }
87
+ * }
88
+ */
89
+ private convertOpenAIToolsToAnthropic;
90
+ /**
91
+ * Convert OpenAI tool_choice to Anthropic tool_choice
92
+ *
93
+ * OpenAI: "auto" | "none" | { type: "function", function: { name: string } }
94
+ * Anthropic: { type: "auto" } | { type: "any" } | { type: "tool", name: string }
95
+ */
96
+ private convertOpenAIToolChoiceToAnthropic;
97
+ /**
98
+ * Convert Anthropic tool use response to OpenAI format
99
+ *
100
+ * Returns special format: __TOOL_CALLS__<JSON>
101
+ * This allows the bot to parse and execute tools
102
+ */
103
+ private convertAnthropicToolCallsToOpenAI;
104
+ /**
105
+ * Convert OpenAI message format to Anthropic message format
106
+ *
107
+ * Handles conversion of tool messages (role: 'tool') to Anthropic's tool_result format.
108
+ * OpenAI uses separate tool messages, Anthropic embeds tool results in user messages.
109
+ *
110
+ * OpenAI format:
111
+ * { role: 'tool', content: '{"result": "..."}', tool_call_id: 'call_123' }
112
+ *
113
+ * Anthropic format:
114
+ * { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'toolu_123', content: '{"result": "..."}' }] }
115
+ */
116
+ private convertMessagesToAnthropicFormat;
117
+ chat(messages: Message[], options?: ChatOptions): Promise<Result<string, ProviderError>>;
118
+ /**
119
+ * Generate streaming chat completion
120
+ *
121
+ * @param messages - Conversation messages
122
+ * @param options - Optional chat configuration
123
+ * @returns Result with async iterator of text chunks or error
124
+ */
125
+ streamChat(messages: Message[], options?: ChatOptions): Promise<Result<AsyncIterable<string>, ProviderError>>;
126
+ /**
127
+ * Check if provider is healthy
128
+ *
129
+ * Uses passive health monitoring based on recent failures
130
+ * instead of making actual API calls to avoid costs and rate limits.
131
+ *
132
+ * @returns True if provider is responding correctly
133
+ */
134
+ isHealthy(): Promise<boolean>;
135
+ /**
136
+ * Reset provider health status
137
+ *
138
+ * Clears consecutive failure counter and marks provider as healthy.
139
+ */
140
+ resetHealth(): void;
141
+ /**
142
+ * Get list of available models
143
+ *
144
+ * @returns Result with array of model IDs or error
145
+ */
146
+ getAvailableModels(): Promise<Result<string[], ProviderError>>;
147
+ /**
148
+ * Create async iterator from Anthropic stream
149
+ */
150
+ private createStreamIterator;
151
+ /**
152
+ * Handle API errors and convert to ProviderError
153
+ */
154
+ private handleError;
155
+ /**
156
+ * Create standardized ProviderError
157
+ */
158
+ private createError;
159
+ }
160
+ //# sourceMappingURL=anthropic-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic-provider.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic-provider.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,WAAW,EACX,OAAO,EACP,WAAW,EACX,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAGlD;;;;;GAKG;AACH,qBAAa,iBAAkB,YAAW,WAAW;IACnD,SAAgB,IAAI,eAAe;IACnC,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAK;IAE5C;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgC;IAC7D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAQ;IAEzC;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAoC3B;IAEF;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAsB7B;IAEF;;;;OAIG;gBACS,MAAM,EAAE,MAAM;IAa1B;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAK1B;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IAa5B;;;;;;OAMG;IACH;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,6BAA6B;IAQrC;;;;;OAKG;IACH,OAAO,CAAC,kCAAkC;IAqB1C;;;;;OAKG;IACH,OAAO,CAAC,iCAAiC;IAkCzC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gCAAgC;IAwGlC,IAAI,CACR,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IA8EzC;;;;;;OAMG;IACG,UAAU,CACd,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC;IA+BxD;;;;;;;OAOG;IACG,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAMnC;;;;OAIG;IACH,WAAW,IAAI,IAAI;IAInB;;;;OAIG;IACG,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,aAAa,CAAC,CAAC;IA0BpE;;OAEG;YACY,oBAAoB;IAkBnC;;OAEG;IACH,OAAO,CAAC,WAAW;IAkCnB;;OAEG;IACH,OAAO,CAAC,WAAW;CAOpB"}
@@ -0,0 +1,527 @@
1
+ /**
2
+ * Anthropic Provider Implementation
3
+ *
4
+ * Implements LLMProvider interface for Anthropic Claude models.
5
+ * Provides chat completion, streaming, health checks, and model discovery.
6
+ */
7
+ import Anthropic from '@anthropic-ai/sdk';
8
+ import { ProviderErrorType } from './types.js';
9
+ import { ok, err } from '../common/result.js';
10
+ /**
11
+ * Anthropic Claude Provider
12
+ *
13
+ * Wraps the Anthropic SDK to provide standardized LLM provider interface.
14
+ * Supports both standard and streaming chat completions.
15
+ */
16
+ export class AnthropicProvider {
17
+ name = 'anthropic';
18
+ client;
19
+ consecutiveFailures = 0;
20
+ maxConsecutiveFailures = 3;
21
+ /**
22
+ * Default model configuration
23
+ */
24
+ defaultModel = 'claude-sonnet-4-5-20250929';
25
+ defaultMaxTokens = 8096;
26
+ /**
27
+ * Model name mapping for user-friendly aliases
28
+ * Maps shorthand names to full Anthropic model identifiers
29
+ */
30
+ modelAliases = {
31
+ // Claude 4 models (NEW - available in Tier 1)
32
+ 'claude-4-sonnet': 'claude-sonnet-4-20250514',
33
+ 'claude-sonnet-4': 'claude-sonnet-4-20250514',
34
+ 'sonnet-4': 'claude-sonnet-4-20250514',
35
+ 'claude-4.5-sonnet': 'claude-sonnet-4-5-20250929',
36
+ 'claude-sonnet-4.5': 'claude-sonnet-4-5-20250929',
37
+ 'sonnet-4.5': 'claude-sonnet-4-5-20250929',
38
+ 'claude-4-opus': 'claude-opus-4-20250514',
39
+ 'claude-opus-4': 'claude-opus-4-20250514',
40
+ 'opus-4': 'claude-opus-4-20250514',
41
+ 'claude-4.5-opus': 'claude-opus-4-5-20251101',
42
+ 'claude-opus-4.5': 'claude-opus-4-5-20251101',
43
+ 'opus-4.5': 'claude-opus-4-5-20251101',
44
+ 'claude-4-haiku': 'claude-haiku-4-20250514',
45
+ 'claude-haiku-4': 'claude-haiku-4-20250514',
46
+ 'haiku-4': 'claude-haiku-4-20250514',
47
+ // Claude 3.5 models (NOT available in Tier 1)
48
+ 'claude-3-5-sonnet': 'claude-3-5-sonnet-20241022',
49
+ 'claude-3.5-sonnet': 'claude-3-5-sonnet-20241022',
50
+ 'sonnet-3.5': 'claude-3-5-sonnet-20241022',
51
+ 'claude-3-5-haiku': 'claude-3-5-haiku-20241022',
52
+ 'claude-3.5-haiku': 'claude-3-5-haiku-20241022',
53
+ 'haiku-3.5': 'claude-3-5-haiku-20241022',
54
+ // Claude 3 models
55
+ 'claude-3-opus': 'claude-3-opus-20240229',
56
+ 'claude-3.0-opus': 'claude-3-opus-20240229',
57
+ 'opus': 'claude-3-opus-20240229',
58
+ 'claude-3-sonnet': 'claude-3-sonnet-20240229',
59
+ 'claude-3.0-sonnet': 'claude-3-sonnet-20240229',
60
+ 'sonnet': 'claude-3-sonnet-20240229',
61
+ 'claude-3-haiku': 'claude-3-haiku-20240307',
62
+ 'claude-3.0-haiku': 'claude-3-haiku-20240307',
63
+ 'haiku': 'claude-3-haiku-20240307',
64
+ };
65
+ /**
66
+ * Model-specific maximum output token limits
67
+ * Maps model identifiers to their maximum allowed output tokens
68
+ */
69
+ modelMaxTokens = {
70
+ // Claude 4 models (8192 max output tokens) - TESTED WORKING
71
+ 'claude-sonnet-4-20250514': 8192,
72
+ 'claude-4-sonnet-20250514': 8192,
73
+ 'claude-sonnet-4-5-20250929': 8192,
74
+ 'claude-opus-4-20250514': 8192,
75
+ 'claude-4-opus-20250514': 8192,
76
+ 'claude-opus-4-5-20251101': 8192,
77
+ 'claude-opus-4-5': 8192,
78
+ 'claude-haiku-4-20250514': 8192,
79
+ // Claude 3.7 models (8192 max output tokens) - TESTED WORKING
80
+ 'claude-3-7-sonnet-20250219': 8192,
81
+ // Claude 3.5 models (8192 max output tokens) - NOT AVAILABLE
82
+ 'claude-3-5-sonnet-20241022': 8192,
83
+ 'claude-3-5-haiku-20241022': 8192,
84
+ // Claude 3 models (4096 max output tokens)
85
+ 'claude-3-opus-20240229': 4096,
86
+ 'claude-3-sonnet-20240229': 4096,
87
+ 'claude-3-haiku-20240307': 4096,
88
+ };
89
+ /**
90
+ * Create Anthropic provider instance
91
+ *
92
+ * @param apiKey - Anthropic API key
93
+ */
94
+ constructor(apiKey) {
95
+ if (!apiKey || apiKey.trim() === '') {
96
+ throw new Error('Anthropic API key is required');
97
+ }
98
+ // IMPORTANT: Explicitly set baseURL to official Anthropic API
99
+ // This prevents proxies/gateways from intercepting the requests
100
+ this.client = new Anthropic({
101
+ apiKey,
102
+ baseURL: 'https://api.anthropic.com',
103
+ });
104
+ }
105
+ /**
106
+ * Normalize model name using aliases
107
+ *
108
+ * Converts user-friendly model names to actual Anthropic model identifiers.
109
+ * Returns the input model name if no mapping is found (assumes it's already valid).
110
+ *
111
+ * @param model - User-provided model name
112
+ * @returns Normalized Anthropic model identifier
113
+ */
114
+ normalizeModelName(model) {
115
+ const normalized = this.modelAliases[model.toLowerCase()];
116
+ return normalized || model;
117
+ }
118
+ /**
119
+ * Get appropriate max tokens for a model
120
+ *
121
+ * Returns model-specific token limit or falls back to default.
122
+ * Prevents exceeding model's maximum output token capacity.
123
+ *
124
+ * @param normalizedModel - Normalized model identifier
125
+ * @param requestedMaxTokens - User-requested max tokens (optional)
126
+ * @returns Safe max tokens value for the model
127
+ */
128
+ getMaxTokensForModel(normalizedModel, requestedMaxTokens) {
129
+ // Get model's maximum allowed tokens
130
+ const modelLimit = this.modelMaxTokens[normalizedModel] || this.defaultMaxTokens;
131
+ // If user didn't specify, use model's limit
132
+ if (!requestedMaxTokens) {
133
+ return modelLimit;
134
+ }
135
+ // If user specified, ensure it doesn't exceed model's limit
136
+ return Math.min(requestedMaxTokens, modelLimit);
137
+ }
138
+ /**
139
+ * Generate chat completion
140
+ *
141
+ * @param messages - Conversation messages
142
+ * @param options - Optional chat configuration
143
+ * @returns Result with response text or error
144
+ */
145
+ /**
146
+ * Convert OpenAI tool format to Anthropic tool format
147
+ *
148
+ * OpenAI format:
149
+ * {
150
+ * type: "function",
151
+ * function: {
152
+ * name: "tool_name",
153
+ * description: "...",
154
+ * parameters: { type: "object", properties: {...}, required: [...] }
155
+ * }
156
+ * }
157
+ *
158
+ * Anthropic format:
159
+ * {
160
+ * name: "tool_name",
161
+ * description: "...",
162
+ * input_schema: { type: "object", properties: {...}, required: [...] }
163
+ * }
164
+ */
165
+ convertOpenAIToolsToAnthropic(openaiTools) {
166
+ return openaiTools.map((tool) => ({
167
+ name: tool.function.name,
168
+ description: tool.function.description || '',
169
+ input_schema: tool.function.parameters,
170
+ }));
171
+ }
172
+ /**
173
+ * Convert OpenAI tool_choice to Anthropic tool_choice
174
+ *
175
+ * OpenAI: "auto" | "none" | { type: "function", function: { name: string } }
176
+ * Anthropic: { type: "auto" } | { type: "any" } | { type: "tool", name: string }
177
+ */
178
+ convertOpenAIToolChoiceToAnthropic(toolChoice) {
179
+ if (!toolChoice || toolChoice === 'auto') {
180
+ return { type: 'auto' };
181
+ }
182
+ if (toolChoice === 'none') {
183
+ return undefined; // Anthropic doesn't have explicit "none", just omit tools
184
+ }
185
+ if (typeof toolChoice === 'object' && toolChoice.type === 'function') {
186
+ return {
187
+ type: 'tool',
188
+ name: toolChoice.function.name,
189
+ };
190
+ }
191
+ return { type: 'auto' }; // Fallback
192
+ }
193
+ /**
194
+ * Convert Anthropic tool use response to OpenAI format
195
+ *
196
+ * Returns special format: __TOOL_CALLS__<JSON>
197
+ * This allows the bot to parse and execute tools
198
+ */
199
+ convertAnthropicToolCallsToOpenAI(content) {
200
+ const toolUseBlocks = content.filter((block) => block.type === 'tool_use');
201
+ if (toolUseBlocks.length === 0) {
202
+ return null;
203
+ }
204
+ // Convert to OpenAI format
205
+ const toolCalls = toolUseBlocks.map((block) => ({
206
+ id: block.id,
207
+ type: 'function',
208
+ function: {
209
+ name: block.name,
210
+ arguments: JSON.stringify(block.input),
211
+ },
212
+ }));
213
+ // Get text content if any
214
+ const textBlock = content.find((block) => block.type === 'text');
215
+ const message = textBlock ? textBlock.text : '';
216
+ // Return in the format the bot expects
217
+ const toolCallsData = {
218
+ tool_calls: toolCalls,
219
+ message,
220
+ };
221
+ return `__TOOL_CALLS__${JSON.stringify(toolCallsData)}`;
222
+ }
223
+ /**
224
+ * Convert OpenAI message format to Anthropic message format
225
+ *
226
+ * Handles conversion of tool messages (role: 'tool') to Anthropic's tool_result format.
227
+ * OpenAI uses separate tool messages, Anthropic embeds tool results in user messages.
228
+ *
229
+ * OpenAI format:
230
+ * { role: 'tool', content: '{"result": "..."}', tool_call_id: 'call_123' }
231
+ *
232
+ * Anthropic format:
233
+ * { role: 'user', content: [{ type: 'tool_result', tool_use_id: 'toolu_123', content: '{"result": "..."}' }] }
234
+ */
235
+ convertMessagesToAnthropicFormat(messages) {
236
+ const anthropicMessages = [];
237
+ for (let i = 0; i < messages.length; i++) {
238
+ const msg = messages[i];
239
+ // Skip system messages (Anthropic doesn't support them in messages array)
240
+ if (msg.role === 'system') {
241
+ continue;
242
+ }
243
+ // Convert tool messages to Anthropic's tool_result format
244
+ if (msg.role === 'tool') {
245
+ // Tool results should only be included if we're in the same request as the tool_use
246
+ // In subsequent requests (like streaming after tool execution), skip tool results
247
+ // because the corresponding tool_use is not in this request's messages
248
+ // Check if there's a previous assistant message with __TOOL_CALLS__ marker
249
+ // If so, this is a subsequent request and we should skip the tool result
250
+ let skipToolResult = false;
251
+ for (let j = i - 1; j >= 0; j--) {
252
+ if (anthropicMessages[j] && anthropicMessages[j].role === 'assistant') {
253
+ const assistantContent = anthropicMessages[j].content;
254
+ if (typeof assistantContent === 'string' && assistantContent.includes('__TOOL_CALLS__')) {
255
+ // This tool result corresponds to a tool call that was already processed
256
+ // Skip it in subsequent requests
257
+ skipToolResult = true;
258
+ }
259
+ break;
260
+ }
261
+ }
262
+ if (skipToolResult) {
263
+ continue;
264
+ }
265
+ const toolContent = (msg.content || '').trim();
266
+ const toolCallId = msg.tool_call_id || '';
267
+ // Skip tool messages with missing content or ID
268
+ if (!toolContent || !toolCallId) {
269
+ continue;
270
+ }
271
+ anthropicMessages.push({
272
+ role: 'user',
273
+ content: [
274
+ {
275
+ type: 'tool_result',
276
+ tool_use_id: toolCallId,
277
+ content: toolContent,
278
+ },
279
+ ],
280
+ });
281
+ continue;
282
+ }
283
+ // Handle assistant messages with tool_calls
284
+ if (msg.role === 'assistant' && msg.tool_calls && msg.tool_calls.length > 0) {
285
+ // Convert OpenAI tool_calls to Anthropic tool_use format
286
+ const toolUseBlocks = msg.tool_calls.map((toolCall) => ({
287
+ type: 'tool_use',
288
+ id: toolCall.id,
289
+ name: toolCall.function.name,
290
+ input: JSON.parse(toolCall.function.arguments),
291
+ }));
292
+ // Include text content if present, otherwise just tool_use blocks
293
+ const content = (msg.content || '').trim();
294
+ const contentBlocks = [];
295
+ if (content) {
296
+ contentBlocks.push({
297
+ type: 'text',
298
+ text: content,
299
+ });
300
+ }
301
+ contentBlocks.push(...toolUseBlocks);
302
+ anthropicMessages.push({
303
+ role: 'assistant',
304
+ content: contentBlocks,
305
+ });
306
+ continue;
307
+ }
308
+ // Regular user/assistant messages without tool calls
309
+ const content = (msg.content || '').trim();
310
+ // Skip messages with empty content
311
+ if (!content) {
312
+ continue;
313
+ }
314
+ anthropicMessages.push({
315
+ role: msg.role,
316
+ content,
317
+ });
318
+ }
319
+ return anthropicMessages;
320
+ }
321
+ async chat(messages, options) {
322
+ try {
323
+ // Normalize model name to handle user-friendly aliases
324
+ const requestedModel = options?.model || this.defaultModel;
325
+ const normalizedModel = this.normalizeModelName(requestedModel);
326
+ // Get appropriate max tokens for this model
327
+ const maxTokens = this.getMaxTokensForModel(normalizedModel, options?.maxTokens);
328
+ // Convert tools from OpenAI format to Anthropic format if provided
329
+ const anthropicTools = options?.tools
330
+ ? this.convertOpenAIToolsToAnthropic(options.tools)
331
+ : undefined;
332
+ const anthropicToolChoice = options?.tool_choice
333
+ ? this.convertOpenAIToolChoiceToAnthropic(options.tool_choice)
334
+ : undefined;
335
+ const response = await this.client.messages.create({
336
+ model: normalizedModel,
337
+ max_tokens: maxTokens,
338
+ temperature: options?.temperature,
339
+ stop_sequences: options?.stopSequences,
340
+ messages: this.convertMessagesToAnthropicFormat(messages),
341
+ ...(options?.system && { system: options.system }),
342
+ ...(anthropicTools && anthropicTools.length > 0 && { tools: anthropicTools }),
343
+ ...(anthropicToolChoice && { tool_choice: anthropicToolChoice }),
344
+ });
345
+ // Handle error responses that SDK didn't throw
346
+ // Some SDK versions or proxies return errors as response objects
347
+ if (response.type === 'error' || response.error) {
348
+ const errorObj = response.error;
349
+ if (errorObj?.type === 'authentication_error') {
350
+ return err(this.createError(ProviderErrorType.AUTH_FAILED, errorObj.message || 'Authentication failed'));
351
+ }
352
+ if (errorObj?.type === 'rate_limit_error') {
353
+ return err(this.createError(ProviderErrorType.RATE_LIMIT, errorObj.message || 'Rate limit exceeded'));
354
+ }
355
+ if (errorObj?.type === 'invalid_request_error') {
356
+ return err(this.createError(ProviderErrorType.INVALID_REQUEST, errorObj.message || 'Invalid request'));
357
+ }
358
+ return err(this.createError(ProviderErrorType.UNKNOWN, errorObj?.message || 'Unknown error from API'));
359
+ }
360
+ // Validate response structure
361
+ if (!response || !response.content || !Array.isArray(response.content)) {
362
+ return err(this.createError(ProviderErrorType.INVALID_REQUEST, 'Invalid response structure from Anthropic API'));
363
+ }
364
+ // Check if response contains tool calls
365
+ const toolCallsResponse = this.convertAnthropicToolCallsToOpenAI(response.content);
366
+ if (toolCallsResponse) {
367
+ // Reset failure counter on success
368
+ this.consecutiveFailures = 0;
369
+ return ok(toolCallsResponse);
370
+ }
371
+ // Extract text from response
372
+ const textContent = response.content.find((c) => c.type === 'text');
373
+ if (!textContent || textContent.type !== 'text') {
374
+ return err(this.createError(ProviderErrorType.INVALID_REQUEST, 'No text content in response'));
375
+ }
376
+ // Reset failure counter on success
377
+ this.consecutiveFailures = 0;
378
+ return ok(textContent.text);
379
+ }
380
+ catch (error) {
381
+ this.consecutiveFailures++;
382
+ return err(this.handleError(error));
383
+ }
384
+ }
385
+ /**
386
+ * Generate streaming chat completion
387
+ *
388
+ * @param messages - Conversation messages
389
+ * @param options - Optional chat configuration
390
+ * @returns Result with async iterator of text chunks or error
391
+ */
392
+ async streamChat(messages, options) {
393
+ try {
394
+ // Normalize model name to handle user-friendly aliases
395
+ const requestedModel = options?.model || this.defaultModel;
396
+ const normalizedModel = this.normalizeModelName(requestedModel);
397
+ // Get appropriate max tokens for this model
398
+ const maxTokens = this.getMaxTokensForModel(normalizedModel, options?.maxTokens);
399
+ const stream = await this.client.messages.stream({
400
+ model: normalizedModel,
401
+ max_tokens: maxTokens,
402
+ temperature: options?.temperature,
403
+ stop_sequences: options?.stopSequences,
404
+ messages: this.convertMessagesToAnthropicFormat(messages),
405
+ ...(options?.system && { system: options.system }),
406
+ });
407
+ // Create async iterator from stream
408
+ const iterator = this.createStreamIterator(stream);
409
+ // Reset failure counter on success
410
+ this.consecutiveFailures = 0;
411
+ return ok(iterator);
412
+ }
413
+ catch (error) {
414
+ this.consecutiveFailures++;
415
+ return err(this.handleError(error));
416
+ }
417
+ }
418
+ /**
419
+ * Check if provider is healthy
420
+ *
421
+ * Uses passive health monitoring based on recent failures
422
+ * instead of making actual API calls to avoid costs and rate limits.
423
+ *
424
+ * @returns True if provider is responding correctly
425
+ */
426
+ async isHealthy() {
427
+ // Passive health check: only monitor consecutive failures
428
+ // Don't make actual API calls to avoid costs and rate limits
429
+ return this.consecutiveFailures < this.maxConsecutiveFailures;
430
+ }
431
+ /**
432
+ * Reset provider health status
433
+ *
434
+ * Clears consecutive failure counter and marks provider as healthy.
435
+ */
436
+ resetHealth() {
437
+ this.consecutiveFailures = 0;
438
+ }
439
+ /**
440
+ * Get list of available models
441
+ *
442
+ * @returns Result with array of model IDs or error
443
+ */
444
+ async getAvailableModels() {
445
+ // Return models confirmed to work with the current API key
446
+ // Note: Anthropic SDK doesn't have a models.list() method
447
+ const knownModels = [
448
+ // Claude 4 Opus models (TESTED - WORKING - MOST POWERFUL)
449
+ 'claude-opus-4-5-20251101', // Claude Opus 4.5 (MOST CAPABLE)
450
+ 'claude-opus-4-5', // Claude Opus 4.5 (alias)
451
+ 'claude-opus-4-20250514', // Claude Opus 4
452
+ 'claude-4-opus-20250514', // Claude 4 Opus (alt format)
453
+ // Claude 4 Sonnet models (TESTED - WORKING)
454
+ 'claude-sonnet-4-5-20250929', // Claude Sonnet 4.5
455
+ 'claude-sonnet-4-20250514', // Claude Sonnet 4
456
+ 'claude-4-sonnet-20250514', // Claude 4 Sonnet (alt format)
457
+ // Claude 3.7 Sonnet (TESTED - WORKING)
458
+ 'claude-3-7-sonnet-20250219',
459
+ // Claude 3 Haiku (TESTED - WORKING - FASTEST)
460
+ 'claude-3-haiku-20240307',
461
+ // Note: Claude 3.5 models and Claude 4 Haiku are NOT available
462
+ ];
463
+ return ok(knownModels);
464
+ }
465
+ /**
466
+ * Create async iterator from Anthropic stream
467
+ */
468
+ async *createStreamIterator(stream) {
469
+ try {
470
+ for await (const chunk of stream) {
471
+ if (chunk.type === 'content_block_delta') {
472
+ const delta = chunk.delta;
473
+ if (delta.type === 'text_delta') {
474
+ yield delta.text;
475
+ }
476
+ }
477
+ }
478
+ }
479
+ catch (error) {
480
+ // Stream error - will be caught by caller
481
+ throw error;
482
+ }
483
+ }
484
+ /**
485
+ * Handle API errors and convert to ProviderError
486
+ */
487
+ handleError(error) {
488
+ // Anthropic SDK errors - check for APIError instance or status property
489
+ // The status is passed as first parameter to APIError constructor
490
+ const statusCode = error.status;
491
+ if (statusCode !== undefined) {
492
+ if (statusCode === 401 || statusCode === 403) {
493
+ return this.createError(ProviderErrorType.AUTH_FAILED, 'Authentication failed');
494
+ }
495
+ if (statusCode === 429) {
496
+ return this.createError(ProviderErrorType.RATE_LIMIT, 'Rate limit exceeded');
497
+ }
498
+ if (statusCode === 404) {
499
+ return this.createError(ProviderErrorType.MODEL_NOT_FOUND, 'Model not found');
500
+ }
501
+ if (statusCode === 400) {
502
+ return this.createError(ProviderErrorType.INVALID_REQUEST, error.message || 'Invalid request');
503
+ }
504
+ }
505
+ // Network errors
506
+ if (error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
507
+ return this.createError(ProviderErrorType.NETWORK_ERROR, 'Network connection failed');
508
+ }
509
+ // Timeout errors
510
+ if (error.code === 'ETIMEDOUT' || error.name === 'TimeoutError') {
511
+ return this.createError(ProviderErrorType.TIMEOUT, 'Request timeout');
512
+ }
513
+ // Unknown errors
514
+ return this.createError(ProviderErrorType.UNKNOWN, error.message || 'Unknown error occurred');
515
+ }
516
+ /**
517
+ * Create standardized ProviderError
518
+ */
519
+ createError(type, message) {
520
+ return {
521
+ type,
522
+ message,
523
+ provider: this.name,
524
+ };
525
+ }
526
+ }
527
+ //# sourceMappingURL=anthropic-provider.js.map