claude-gateway 2.0.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 (44) hide show
  1. package/CHANGELOG.md +329 -0
  2. package/LICENSE +21 -0
  3. package/README.md +272 -0
  4. package/dist/cli.d.ts +13 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +409 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/client.d.ts +30 -0
  9. package/dist/client.d.ts.map +1 -0
  10. package/dist/client.js +106 -0
  11. package/dist/client.js.map +1 -0
  12. package/dist/oauth.d.ts +44 -0
  13. package/dist/oauth.d.ts.map +1 -0
  14. package/dist/oauth.js +135 -0
  15. package/dist/oauth.js.map +1 -0
  16. package/dist/router/logger.d.ts +19 -0
  17. package/dist/router/logger.d.ts.map +1 -0
  18. package/dist/router/logger.js +104 -0
  19. package/dist/router/logger.js.map +1 -0
  20. package/dist/router/middleware.d.ts +9 -0
  21. package/dist/router/middleware.d.ts.map +1 -0
  22. package/dist/router/middleware.js +46 -0
  23. package/dist/router/middleware.js.map +1 -0
  24. package/dist/router/models.d.ts +11 -0
  25. package/dist/router/models.d.ts.map +1 -0
  26. package/dist/router/models.js +61 -0
  27. package/dist/router/models.js.map +1 -0
  28. package/dist/router/server.d.ts +14 -0
  29. package/dist/router/server.d.ts.map +1 -0
  30. package/dist/router/server.js +423 -0
  31. package/dist/router/server.js.map +1 -0
  32. package/dist/router/translator.d.ts +33 -0
  33. package/dist/router/translator.d.ts.map +1 -0
  34. package/dist/router/translator.js +302 -0
  35. package/dist/router/translator.js.map +1 -0
  36. package/dist/token-manager.d.ts +32 -0
  37. package/dist/token-manager.d.ts.map +1 -0
  38. package/dist/token-manager.js +79 -0
  39. package/dist/token-manager.js.map +1 -0
  40. package/dist/types.d.ts +247 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/types.js +12 -0
  43. package/dist/types.js.map +1 -0
  44. package/package.json +75 -0
@@ -0,0 +1,302 @@
1
+ /**
2
+ * EDUCATIONAL AND ENTERTAINMENT PURPOSES ONLY
3
+ *
4
+ * This software is provided for educational, research, and entertainment purposes only.
5
+ * It is not affiliated with, endorsed by, or sponsored by Anthropic PBC.
6
+ * Use at your own risk. No warranties provided. Users are solely responsible for
7
+ * ensuring compliance with Anthropic's Terms of Service and all applicable laws.
8
+ *
9
+ * Copyright (c) 2025 - Licensed under MIT License
10
+ */
11
+ /**
12
+ * Map OpenAI model name to Anthropic model name
13
+ * Default to claude-sonnet-4-5 for best balance on MAX Plan
14
+ */
15
+ function mapModelName(openaiModel) {
16
+ const model = openaiModel.toLowerCase();
17
+ // Low-tier patterns → Haiku (fast/cheap models)
18
+ const lowTierPatterns = ['-nano', 'gpt-3.5', 'gpt-3'];
19
+ if (lowTierPatterns.some((pattern) => model.includes(pattern))) {
20
+ return 'claude-haiku-4-5';
21
+ }
22
+ // Default to Sonnet for everything else (best balance for MAX Plan)
23
+ return 'claude-sonnet-4-5';
24
+ }
25
+ /**
26
+ * Translate OpenAI Chat Completion request to Anthropic Messages API request
27
+ */
28
+ export function translateOpenAIToAnthropic(openaiRequest) {
29
+ // Extract and combine all system messages
30
+ const systemMessages = [];
31
+ const conversationMessages = [];
32
+ for (const msg of openaiRequest.messages) {
33
+ if (msg.role === 'system') {
34
+ systemMessages.push(msg.content || '');
35
+ }
36
+ else {
37
+ conversationMessages.push(msg);
38
+ }
39
+ }
40
+ // Consolidate consecutive same-role messages for Anthropic's alternation requirement
41
+ const anthropicMessages = [];
42
+ let currentRole = null;
43
+ let currentContent = [];
44
+ for (const msg of conversationMessages) {
45
+ if (msg.role === 'tool') {
46
+ // Skip tool messages for now - they need special handling
47
+ continue;
48
+ }
49
+ const role = msg.role;
50
+ if (role === currentRole) {
51
+ // Same role, accumulate content
52
+ currentContent.push(msg.content || '');
53
+ }
54
+ else {
55
+ // Role changed, flush current message
56
+ if (currentRole && currentContent.length > 0) {
57
+ anthropicMessages.push({
58
+ role: currentRole,
59
+ content: currentContent.join('\n\n'),
60
+ });
61
+ }
62
+ currentRole = role;
63
+ currentContent = [msg.content || ''];
64
+ }
65
+ }
66
+ // Flush final message
67
+ if (currentRole && currentContent.length > 0) {
68
+ anthropicMessages.push({
69
+ role: currentRole,
70
+ content: currentContent.join('\n\n'),
71
+ });
72
+ }
73
+ // Translate tools if present
74
+ let anthropicTools;
75
+ if (openaiRequest.tools && openaiRequest.tools.length > 0) {
76
+ anthropicTools = openaiRequest.tools.map(translateOpenAIToolToAnthropic);
77
+ }
78
+ // Build the Anthropic request
79
+ const anthropicRequest = {
80
+ model: mapModelName(openaiRequest.model),
81
+ max_tokens: openaiRequest.max_tokens || 4096,
82
+ messages: anthropicMessages,
83
+ stream: openaiRequest.stream || false,
84
+ };
85
+ // Add system messages if present
86
+ if (systemMessages.length > 0) {
87
+ anthropicRequest.system = [
88
+ {
89
+ type: 'text',
90
+ text: systemMessages.join('\n\n'),
91
+ },
92
+ ];
93
+ }
94
+ // Add tools if present
95
+ if (anthropicTools && anthropicTools.length > 0) {
96
+ anthropicRequest.tools = anthropicTools;
97
+ }
98
+ return anthropicRequest;
99
+ }
100
+ /**
101
+ * Translate OpenAI tool to Anthropic tool
102
+ */
103
+ function translateOpenAIToolToAnthropic(openaiTool) {
104
+ return {
105
+ name: openaiTool.function.name,
106
+ description: openaiTool.function.description,
107
+ input_schema: {
108
+ type: 'object',
109
+ properties: openaiTool.function.parameters.properties,
110
+ required: openaiTool.function.parameters.required,
111
+ },
112
+ };
113
+ }
114
+ /**
115
+ * Translate Anthropic response to OpenAI Chat Completion response
116
+ */
117
+ export function translateAnthropicToOpenAI(anthropicResponse, originalModel) {
118
+ // Extract text content from Anthropic's content blocks
119
+ const textBlocks = anthropicResponse.content.filter((block) => block.type === 'text');
120
+ const content = textBlocks.map((block) => block.text).join('');
121
+ // Map stop_reason to finish_reason
122
+ let finishReason = null;
123
+ if (anthropicResponse.stop_reason === 'end_turn') {
124
+ finishReason = 'stop';
125
+ }
126
+ else if (anthropicResponse.stop_reason === 'max_tokens') {
127
+ finishReason = 'length';
128
+ }
129
+ else if (anthropicResponse.stop_reason === 'tool_use') {
130
+ finishReason = 'tool_calls';
131
+ }
132
+ // Check if there are tool uses
133
+ const toolUseBlocks = anthropicResponse.content.filter((block) => block.type === 'tool_use');
134
+ const toolCalls = toolUseBlocks.length > 0
135
+ ? toolUseBlocks.map((block) => ({
136
+ id: block.id,
137
+ type: 'function',
138
+ function: {
139
+ name: block.name,
140
+ arguments: JSON.stringify(block.input),
141
+ },
142
+ }))
143
+ : undefined;
144
+ return {
145
+ id: anthropicResponse.id,
146
+ object: 'chat.completion',
147
+ created: Math.floor(Date.now() / 1000),
148
+ model: originalModel,
149
+ choices: [
150
+ {
151
+ index: 0,
152
+ message: {
153
+ role: 'assistant',
154
+ content: content || null,
155
+ ...(toolCalls && { tool_calls: toolCalls }),
156
+ },
157
+ finish_reason: finishReason,
158
+ },
159
+ ],
160
+ usage: {
161
+ prompt_tokens: anthropicResponse.usage.input_tokens,
162
+ completion_tokens: anthropicResponse.usage.output_tokens,
163
+ total_tokens: anthropicResponse.usage.input_tokens + anthropicResponse.usage.output_tokens,
164
+ },
165
+ };
166
+ }
167
+ /**
168
+ * Translate Anthropic streaming events to OpenAI streaming format
169
+ * This returns a generator that yields OpenAI-formatted SSE strings
170
+ */
171
+ export async function* translateAnthropicStreamToOpenAI(anthropicStream, originalModel, messageId) {
172
+ const decoder = new TextDecoder();
173
+ let buffer = '';
174
+ let totalInputTokens = 0;
175
+ let totalOutputTokens = 0;
176
+ // Send initial chunk with role
177
+ yield `data: ${JSON.stringify({
178
+ id: messageId,
179
+ object: 'chat.completion.chunk',
180
+ created: Math.floor(Date.now() / 1000),
181
+ model: originalModel,
182
+ choices: [
183
+ {
184
+ index: 0,
185
+ delta: { role: 'assistant' },
186
+ finish_reason: null,
187
+ },
188
+ ],
189
+ })}\n\n`;
190
+ for await (const chunk of anthropicStream) {
191
+ buffer += decoder.decode(chunk, { stream: true });
192
+ const lines = buffer.split('\n');
193
+ buffer = lines.pop() || '';
194
+ for (const line of lines) {
195
+ if (!line.trim() || line.startsWith(':'))
196
+ continue;
197
+ if (line.startsWith('data: ')) {
198
+ const data = line.slice(6);
199
+ try {
200
+ const event = JSON.parse(data);
201
+ if (event.type === 'content_block_delta' && event.delta?.type === 'text_delta') {
202
+ // Text content delta
203
+ yield `data: ${JSON.stringify({
204
+ id: messageId,
205
+ object: 'chat.completion.chunk',
206
+ created: Math.floor(Date.now() / 1000),
207
+ model: originalModel,
208
+ choices: [
209
+ {
210
+ index: 0,
211
+ delta: { content: event.delta.text },
212
+ finish_reason: null,
213
+ },
214
+ ],
215
+ })}\n\n`;
216
+ }
217
+ else if (event.type === 'message_delta' && event.usage) {
218
+ // Update token counts
219
+ totalOutputTokens = event.usage.output_tokens || totalOutputTokens;
220
+ }
221
+ else if (event.type === 'message_start' && event.message?.usage) {
222
+ // Initial token count
223
+ totalInputTokens = event.message.usage.input_tokens || 0;
224
+ }
225
+ }
226
+ catch {
227
+ // Ignore parse errors for streaming events
228
+ }
229
+ }
230
+ }
231
+ }
232
+ // Send final chunk with usage information
233
+ yield `data: ${JSON.stringify({
234
+ id: messageId,
235
+ object: 'chat.completion.chunk',
236
+ created: Math.floor(Date.now() / 1000),
237
+ model: originalModel,
238
+ choices: [
239
+ {
240
+ index: 0,
241
+ delta: {},
242
+ finish_reason: 'stop',
243
+ },
244
+ ],
245
+ usage: {
246
+ prompt_tokens: totalInputTokens,
247
+ completion_tokens: totalOutputTokens,
248
+ total_tokens: totalInputTokens + totalOutputTokens,
249
+ },
250
+ })}\n\n`;
251
+ // Send [DONE] marker
252
+ yield 'data: [DONE]\n\n';
253
+ }
254
+ /**
255
+ * Translate Anthropic error to OpenAI error format
256
+ */
257
+ export function translateAnthropicErrorToOpenAI(error) {
258
+ // If it's already an Anthropic error format, translate it
259
+ const err = error;
260
+ if (err.error?.type && err.error?.message) {
261
+ return {
262
+ error: {
263
+ message: err.error.message,
264
+ type: err.error.type,
265
+ param: null,
266
+ code: null,
267
+ },
268
+ };
269
+ }
270
+ // Generic error
271
+ return {
272
+ error: {
273
+ message: err.message || 'An error occurred',
274
+ type: 'internal_error',
275
+ param: null,
276
+ code: null,
277
+ },
278
+ };
279
+ }
280
+ /**
281
+ * Validate OpenAI request and throw errors for unsupported features
282
+ */
283
+ export function validateOpenAIRequest(request) {
284
+ // Error on unsupported features that would change behavior
285
+ if (request.n && request.n > 1) {
286
+ throw new Error('Multiple completions (n > 1) are not supported. Anthropic only returns one completion.');
287
+ }
288
+ if (request.logprobs) {
289
+ throw new Error('Log probabilities (logprobs) are not supported by Anthropic API.');
290
+ }
291
+ // Warn about ignored parameters (these won't cause errors but won't work as expected)
292
+ if (request.presence_penalty !== undefined) {
293
+ console.warn('Warning: presence_penalty is not supported by Anthropic and will be ignored');
294
+ }
295
+ if (request.frequency_penalty !== undefined) {
296
+ console.warn('Warning: frequency_penalty is not supported by Anthropic and will be ignored');
297
+ }
298
+ if (request.logit_bias !== undefined) {
299
+ console.warn('Warning: logit_bias is not supported by Anthropic and will be ignored');
300
+ }
301
+ }
302
+ //# sourceMappingURL=translator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translator.js","sourceRoot":"","sources":["../../src/router/translator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * EDUCATIONAL AND ENTERTAINMENT PURPOSES ONLY
3
+ *
4
+ * This software is provided for educational, research, and entertainment purposes only.
5
+ * It is not affiliated with, endorsed by, or sponsored by Anthropic PBC.
6
+ * Use at your own risk. No warranties provided. Users are solely responsible for
7
+ * ensuring compliance with Anthropic's Terms of Service and all applicable laws.
8
+ *
9
+ * Copyright (c) 2025 - Licensed under MIT License
10
+ */
11
+ import type { OAuthTokens } from './types.js';
12
+ /**
13
+ * Save tokens to global config
14
+ */
15
+ export declare function saveTokens(tokens: OAuthTokens): Promise<void>;
16
+ /**
17
+ * Load tokens from global config
18
+ */
19
+ export declare function loadTokens(): Promise<OAuthTokens | null>;
20
+ /**
21
+ * Check if token is expired (with 5 minute buffer)
22
+ */
23
+ export declare function isTokenExpired(tokens: OAuthTokens): boolean;
24
+ /**
25
+ * Delete tokens from global config
26
+ */
27
+ export declare function deleteTokens(): Promise<void>;
28
+ /**
29
+ * Get valid access token, refreshing if necessary
30
+ */
31
+ export declare function getValidAccessToken(): Promise<string>;
32
+ //# sourceMappingURL=token-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../src/token-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAc9C;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAGnE;AAED;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAI9D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAO3D;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAGlD;AAED;;GAEG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAsB3D"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * EDUCATIONAL AND ENTERTAINMENT PURPOSES ONLY
3
+ *
4
+ * This software is provided for educational, research, and entertainment purposes only.
5
+ * It is not affiliated with, endorsed by, or sponsored by Anthropic PBC.
6
+ * Use at your own risk. No warranties provided. Users are solely responsible for
7
+ * ensuring compliance with Anthropic's Terms of Service and all applicable laws.
8
+ *
9
+ * Copyright (c) 2025 - Licensed under MIT License
10
+ */
11
+ /**
12
+ * Token management - save, load, and refresh tokens
13
+ */
14
+ import Conf from 'conf';
15
+ import { refreshAccessToken } from './oauth.js';
16
+ // Global config store - tokens are saved in OS-specific config directory
17
+ // Linux/Mac: ~/.config/claude-gateway/
18
+ // Windows: %APPDATA%\claude-gateway\
19
+ const config = new Conf({
20
+ projectName: 'claude-gateway',
21
+ projectSuffix: '',
22
+ // Use JSON for human readability
23
+ serialize: (value) => JSON.stringify(value, null, 2),
24
+ deserialize: JSON.parse,
25
+ });
26
+ /**
27
+ * Save tokens to global config
28
+ */
29
+ export async function saveTokens(tokens) {
30
+ config.set('tokens', tokens);
31
+ console.log(`✅ Tokens saved to global config: ${config.path}`);
32
+ }
33
+ /**
34
+ * Load tokens from global config
35
+ */
36
+ export async function loadTokens() {
37
+ // First try to load from global config
38
+ const tokens = config.get('tokens');
39
+ return tokens || null;
40
+ }
41
+ /**
42
+ * Check if token is expired (with 5 minute buffer)
43
+ */
44
+ export function isTokenExpired(tokens) {
45
+ if (!tokens.expires_at) {
46
+ return true;
47
+ }
48
+ const buffer = 5 * 60 * 1000; // 5 minutes
49
+ return Date.now() >= tokens.expires_at - buffer;
50
+ }
51
+ /**
52
+ * Delete tokens from global config
53
+ */
54
+ export async function deleteTokens() {
55
+ config.delete('tokens');
56
+ console.log(`✅ Tokens deleted from global config: ${config.path}`);
57
+ }
58
+ /**
59
+ * Get valid access token, refreshing if necessary
60
+ */
61
+ export async function getValidAccessToken() {
62
+ const tokens = await loadTokens();
63
+ if (!tokens) {
64
+ throw new Error('No tokens found. Please run OAuth flow first: npm run oauth');
65
+ }
66
+ if (isTokenExpired(tokens)) {
67
+ console.log('🔄 Token expired, refreshing...');
68
+ const newTokens = await refreshAccessToken(tokens.refresh_token);
69
+ // Preserve refresh token if not returned
70
+ if (!newTokens.refresh_token) {
71
+ newTokens.refresh_token = tokens.refresh_token;
72
+ }
73
+ await saveTokens(newTokens);
74
+ console.log('✅ Token refreshed');
75
+ return newTokens.access_token;
76
+ }
77
+ return tokens.access_token;
78
+ }
79
+ //# sourceMappingURL=token-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../src/token-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;GAEG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhD,yEAAyE;AACzE,uCAAuC;AACvC,qCAAqC;AACrC,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC;IACtB,WAAW,EAAE,gBAAgB;IAC7B,aAAa,EAAE,EAAE;IACjB,iCAAiC;IACjC,SAAS,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,WAAW,EAAE,IAAI,CAAC,KAAK;CACxB,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAmB;IAClD,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,oCAAoC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,uCAAuC;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAA4B,CAAC;IAC/D,OAAO,MAAM,IAAI,IAAI,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAAmB;IAChD,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;IAC1C,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,CAAC,GAAG,CAAC,wCAAwC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAElC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IAED,IAAI,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAEjE,yCAAyC;QACzC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC;YAC7B,SAAS,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;QACjD,CAAC;QAED,MAAM,UAAU,CAAC,SAAS,CAAC,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACjC,OAAO,SAAS,CAAC,YAAY,CAAC;IAChC,CAAC;IAED,OAAO,MAAM,CAAC,YAAY,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,247 @@
1
+ /**
2
+ * EDUCATIONAL AND ENTERTAINMENT PURPOSES ONLY
3
+ *
4
+ * This software is provided for educational, research, and entertainment purposes only.
5
+ * It is not affiliated with, endorsed by, or sponsored by Anthropic PBC.
6
+ * Use at your own risk. No warranties provided. Users are solely responsible for
7
+ * ensuring compliance with Anthropic's Terms of Service and all applicable laws.
8
+ *
9
+ * Copyright (c) 2025 - Licensed under MIT License
10
+ */
11
+ /**
12
+ * OAuth token response from Anthropic
13
+ */
14
+ export interface OAuthTokens {
15
+ access_token: string;
16
+ refresh_token: string;
17
+ expires_in: number;
18
+ token_type: string;
19
+ scope: string;
20
+ expires_at?: number;
21
+ created_at?: string;
22
+ }
23
+ /**
24
+ * Anthropic API request configuration
25
+ */
26
+ export interface AnthropicRequest {
27
+ model: string;
28
+ max_tokens: number;
29
+ system?: SystemMessage[];
30
+ messages: Message[];
31
+ tools?: Tool[];
32
+ tool_choice?: ToolChoice;
33
+ stream?: boolean;
34
+ }
35
+ /**
36
+ * System message structure
37
+ */
38
+ export interface SystemMessage {
39
+ type: 'text';
40
+ text: string;
41
+ cache_control?: {
42
+ type: 'ephemeral';
43
+ };
44
+ }
45
+ /**
46
+ * User/Assistant message
47
+ */
48
+ export interface Message {
49
+ role: 'user' | 'assistant';
50
+ content: string | ContentBlock[];
51
+ }
52
+ /**
53
+ * Content block for messages
54
+ */
55
+ export interface ContentBlock {
56
+ type: 'text' | 'tool_use' | 'tool_result';
57
+ text?: string;
58
+ [key: string]: unknown;
59
+ }
60
+ /**
61
+ * Tool definition
62
+ */
63
+ export interface Tool {
64
+ name: string;
65
+ description: string;
66
+ input_schema: {
67
+ type: 'object';
68
+ properties: Record<string, unknown>;
69
+ required?: string[];
70
+ };
71
+ }
72
+ /**
73
+ * Tool choice configuration
74
+ */
75
+ export interface ToolChoice {
76
+ type: 'auto' | 'any' | 'tool';
77
+ name?: string;
78
+ }
79
+ /**
80
+ * Anthropic API response
81
+ */
82
+ export interface AnthropicResponse {
83
+ id: string;
84
+ type: 'message';
85
+ role: 'assistant';
86
+ content: ContentBlock[];
87
+ model: string;
88
+ stop_reason: string | null;
89
+ stop_sequence: string | null;
90
+ usage: {
91
+ input_tokens: number;
92
+ output_tokens: number;
93
+ cache_creation_input_tokens?: number;
94
+ cache_read_input_tokens?: number;
95
+ };
96
+ }
97
+ /**
98
+ * OAuth configuration
99
+ */
100
+ export interface OAuthConfig {
101
+ client_id: string;
102
+ authorize_url: string;
103
+ token_url: string;
104
+ redirect_uri: string;
105
+ scope: string;
106
+ }
107
+ /**
108
+ * OpenAI Chat Completion Message
109
+ */
110
+ export interface OpenAIMessage {
111
+ role: 'system' | 'user' | 'assistant' | 'tool';
112
+ content: string | null;
113
+ name?: string;
114
+ tool_calls?: OpenAIToolCall[];
115
+ tool_call_id?: string;
116
+ }
117
+ /**
118
+ * OpenAI Tool Call
119
+ */
120
+ export interface OpenAIToolCall {
121
+ id: string;
122
+ type: 'function';
123
+ function: {
124
+ name: string;
125
+ arguments: string;
126
+ };
127
+ }
128
+ /**
129
+ * OpenAI Tool Definition
130
+ */
131
+ export interface OpenAITool {
132
+ type: 'function';
133
+ function: {
134
+ name: string;
135
+ description: string;
136
+ parameters: {
137
+ type: 'object';
138
+ properties: Record<string, unknown>;
139
+ required?: string[];
140
+ };
141
+ };
142
+ }
143
+ /**
144
+ * OpenAI Chat Completion Request
145
+ */
146
+ export interface OpenAIChatCompletionRequest {
147
+ model: string;
148
+ messages: OpenAIMessage[];
149
+ temperature?: number;
150
+ top_p?: number;
151
+ n?: number;
152
+ stream?: boolean;
153
+ stop?: string | string[];
154
+ max_tokens?: number;
155
+ presence_penalty?: number;
156
+ frequency_penalty?: number;
157
+ logit_bias?: Record<string, number>;
158
+ user?: string;
159
+ tools?: OpenAITool[];
160
+ tool_choice?: 'none' | 'auto' | {
161
+ type: 'function';
162
+ function: {
163
+ name: string;
164
+ };
165
+ };
166
+ logprobs?: boolean;
167
+ top_logprobs?: number;
168
+ }
169
+ /**
170
+ * OpenAI Chat Completion Response Choice
171
+ */
172
+ export interface OpenAIChoice {
173
+ index: number;
174
+ message: {
175
+ role: 'assistant';
176
+ content: string | null;
177
+ tool_calls?: OpenAIToolCall[];
178
+ };
179
+ finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | null;
180
+ }
181
+ /**
182
+ * OpenAI Chat Completion Response
183
+ */
184
+ export interface OpenAIChatCompletionResponse {
185
+ id: string;
186
+ object: 'chat.completion';
187
+ created: number;
188
+ model: string;
189
+ choices: OpenAIChoice[];
190
+ usage: {
191
+ prompt_tokens: number;
192
+ completion_tokens: number;
193
+ total_tokens: number;
194
+ };
195
+ system_fingerprint?: string;
196
+ }
197
+ /**
198
+ * OpenAI Streaming Delta
199
+ */
200
+ export interface OpenAIStreamDelta {
201
+ role?: 'assistant';
202
+ content?: string;
203
+ tool_calls?: Array<{
204
+ index: number;
205
+ id?: string;
206
+ type?: 'function';
207
+ function?: {
208
+ name?: string;
209
+ arguments?: string;
210
+ };
211
+ }>;
212
+ }
213
+ /**
214
+ * OpenAI Streaming Choice
215
+ */
216
+ export interface OpenAIStreamChoice {
217
+ index: number;
218
+ delta: OpenAIStreamDelta;
219
+ finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | null;
220
+ }
221
+ /**
222
+ * OpenAI Chat Completion Stream Chunk
223
+ */
224
+ export interface OpenAIChatCompletionChunk {
225
+ id: string;
226
+ object: 'chat.completion.chunk';
227
+ created: number;
228
+ model: string;
229
+ choices: OpenAIStreamChoice[];
230
+ usage?: {
231
+ prompt_tokens: number;
232
+ completion_tokens: number;
233
+ total_tokens: number;
234
+ };
235
+ }
236
+ /**
237
+ * OpenAI Error Response
238
+ */
239
+ export interface OpenAIErrorResponse {
240
+ error: {
241
+ message: string;
242
+ type: string;
243
+ param?: string | null;
244
+ code?: string | null;
245
+ };
246
+ }
247
+ //# sourceMappingURL=types.d.ts.map