ai-agent-router 0.1.8 → 0.1.9

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 (66) hide show
  1. package/.claude/settings.local.json +24 -0
  2. package/.claude/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-311.pyc +0 -0
  3. package/dist/.next/types/app/api/config/route.js +1 -1
  4. package/dist/.next/types/app/api/gateway/[...path]/route.js +1 -1
  5. package/dist/.next/types/app/api/gateway/route.js +1 -1
  6. package/dist/.next/types/app/api/ide/claude/apply/route.js +1 -1
  7. package/dist/.next/types/app/api/ide/claude/available-models/route.js +1 -1
  8. package/dist/.next/types/app/api/ide/claude/restore/route.js +1 -1
  9. package/dist/.next/types/app/api/ide/claude/save/route.js +52 -0
  10. package/dist/.next/types/app/api/ide/claude/status/route.js +1 -1
  11. package/dist/.next/types/app/api/ide/claude/test/route.js +1 -1
  12. package/dist/.next/types/app/api/logs/route.js +1 -1
  13. package/dist/.next/types/app/api/models/route.js +1 -1
  14. package/dist/.next/types/app/api/providers/route.js +1 -1
  15. package/dist/.next/types/app/api/providers/test/route.js +1 -1
  16. package/dist/.next/types/app/api/service/force-stop/route.js +52 -0
  17. package/dist/.next/types/app/api/service/start/route.js +1 -1
  18. package/dist/.next/types/app/api/service/status/route.js +1 -1
  19. package/dist/.next/types/app/api/service/stop/route.js +1 -1
  20. package/dist/.next/types/app/ide/page.js +1 -1
  21. package/dist/.next/types/app/layout.js +1 -1
  22. package/dist/.next/types/app/logs/page.js +1 -1
  23. package/dist/.next/types/app/models/page.js +1 -1
  24. package/dist/.next/types/app/page.js +1 -1
  25. package/dist/.next/types/app/providers/page.js +1 -1
  26. package/dist/docs/SDK_INTEGRATION.md +357 -0
  27. package/dist/src/app/api/gateway/[...path]/route.js +26 -18
  28. package/dist/src/app/api/ide/claude/apply/route.js +8 -7
  29. package/dist/src/app/api/ide/claude/save/route.js +151 -0
  30. package/dist/src/app/api/ide/claude/status/route.js +28 -0
  31. package/dist/src/app/api/ide/claude/test/route.js +176 -80
  32. package/dist/src/app/api/logs/route.js +4 -2
  33. package/dist/src/app/api/providers/test/route.js +10 -1
  34. package/dist/src/app/api/service/force-stop/route.js +32 -0
  35. package/dist/src/app/ide/page.jsx +168 -45
  36. package/dist/src/app/logs/page.jsx +392 -12
  37. package/dist/src/app/page.jsx +2 -313
  38. package/dist/src/db/queries.js +72 -15
  39. package/dist/src/diagnostic.mjs +126 -0
  40. package/dist/src/server/gateway-server.js +4 -3
  41. package/dist/src/server/gateway.js +41 -25
  42. package/dist/src/server/providers/anthropic.js +22 -7
  43. package/dist/src/server/providers/gemini.js +12 -4
  44. package/dist/src/server/providers/index.js +4 -2
  45. package/dist/src/server/providers/openai.js +1 -1
  46. package/dist/src/server/service-manager.js +115 -46
  47. package/package.json +2 -1
  48. package/src/app/api/gateway/[...path]/route.ts +35 -22
  49. package/src/app/api/ide/claude/apply/route.ts +9 -8
  50. package/src/app/api/ide/claude/save/route.ts +181 -0
  51. package/src/app/api/ide/claude/status/route.ts +31 -1
  52. package/src/app/api/ide/claude/test/route.ts +199 -81
  53. package/src/app/api/logs/route.ts +5 -2
  54. package/src/app/api/providers/test/route.ts +9 -1
  55. package/src/app/api/service/force-stop/route.ts +34 -0
  56. package/src/app/ide/page.tsx +235 -54
  57. package/src/app/logs/page.tsx +456 -17
  58. package/src/app/page.tsx +4 -442
  59. package/src/db/queries.ts +80 -15
  60. package/src/server/gateway-server.ts +6 -4
  61. package/src/server/gateway.ts +59 -29
  62. package/src/server/providers/anthropic.ts +28 -13
  63. package/src/server/providers/gemini.ts +14 -4
  64. package/src/server/providers/index.ts +5 -2
  65. package/src/server/providers/openai.ts +1 -1
  66. package/src/server/service-manager.ts +130 -45
@@ -0,0 +1,24 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(find:*)",
5
+ "Bash(npx tsc:*)",
6
+ "Bash(npm run build)",
7
+ "Bash(timeout 3 npm run start:*)",
8
+ "Bash(node:*)",
9
+ "Bash(curl:*)",
10
+ "Bash(npm install:*)",
11
+ "Bash(chmod:*)",
12
+ "Bash(npx typescript:*)",
13
+ "Bash(lsof:*)",
14
+ "Bash(xargs kill:*)",
15
+ "Skill(ui-ux-pro-max)",
16
+ "Bash(python3:*)",
17
+ "Bash(git diff:*)",
18
+ "Bash(git add:*)",
19
+ "Bash(git commit:*)",
20
+ "WebFetch(domain:heroicons.com)",
21
+ "WebSearch"
22
+ ]
23
+ }
24
+ }
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/config/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/config/route.ts
2
2
  import * as entry from '../../../../../src/app/api/config/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/gateway/[...path]/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/gateway/[...path]/route.ts
2
2
  import * as entry from '../../../../../../src/app/api/gateway/[...path]/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/gateway/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/gateway/route.ts
2
2
  import * as entry from '../../../../../src/app/api/gateway/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/ide/claude/apply/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/ide/claude/apply/route.ts
2
2
  import * as entry from '../../../../../../../src/app/api/ide/claude/apply/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/ide/claude/available-models/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/ide/claude/available-models/route.ts
2
2
  import * as entry from '../../../../../../../src/app/api/ide/claude/available-models/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/ide/claude/restore/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/ide/claude/restore/route.ts
2
2
  import * as entry from '../../../../../../../src/app/api/ide/claude/restore/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -0,0 +1,52 @@
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/ide/claude/save/route.ts
2
+ import * as entry from '../../../../../../../src/app/api/ide/claude/save/route.js';
3
+ // Check that the entry is a valid entry
4
+ checkFields();
5
+ // Check the prop type of the entry function
6
+ if ('GET' in entry) {
7
+ checkFields();
8
+ checkFields();
9
+ checkFields();
10
+ }
11
+ // Check the prop type of the entry function
12
+ if ('HEAD' in entry) {
13
+ checkFields();
14
+ checkFields();
15
+ checkFields();
16
+ }
17
+ // Check the prop type of the entry function
18
+ if ('OPTIONS' in entry) {
19
+ checkFields();
20
+ checkFields();
21
+ checkFields();
22
+ }
23
+ // Check the prop type of the entry function
24
+ if ('POST' in entry) {
25
+ checkFields();
26
+ checkFields();
27
+ checkFields();
28
+ }
29
+ // Check the prop type of the entry function
30
+ if ('PUT' in entry) {
31
+ checkFields();
32
+ checkFields();
33
+ checkFields();
34
+ }
35
+ // Check the prop type of the entry function
36
+ if ('DELETE' in entry) {
37
+ checkFields();
38
+ checkFields();
39
+ checkFields();
40
+ }
41
+ // Check the prop type of the entry function
42
+ if ('PATCH' in entry) {
43
+ checkFields();
44
+ checkFields();
45
+ checkFields();
46
+ }
47
+ // Check the arguments and return type of the generateStaticParams function
48
+ if ('generateStaticParams' in entry) {
49
+ checkFields();
50
+ checkFields();
51
+ }
52
+ function checkFields() { }
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/ide/claude/status/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/ide/claude/status/route.ts
2
2
  import * as entry from '../../../../../../../src/app/api/ide/claude/status/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/ide/claude/test/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/ide/claude/test/route.ts
2
2
  import * as entry from '../../../../../../../src/app/api/ide/claude/test/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/logs/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/logs/route.ts
2
2
  import * as entry from '../../../../../src/app/api/logs/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/models/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/models/route.ts
2
2
  import * as entry from '../../../../../src/app/api/models/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/providers/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/providers/route.ts
2
2
  import * as entry from '../../../../../src/app/api/providers/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/providers/test/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/providers/test/route.ts
2
2
  import * as entry from '../../../../../../src/app/api/providers/test/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -0,0 +1,52 @@
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/service/force-stop/route.ts
2
+ import * as entry from '../../../../../../src/app/api/service/force-stop/route.js';
3
+ // Check that the entry is a valid entry
4
+ checkFields();
5
+ // Check the prop type of the entry function
6
+ if ('GET' in entry) {
7
+ checkFields();
8
+ checkFields();
9
+ checkFields();
10
+ }
11
+ // Check the prop type of the entry function
12
+ if ('HEAD' in entry) {
13
+ checkFields();
14
+ checkFields();
15
+ checkFields();
16
+ }
17
+ // Check the prop type of the entry function
18
+ if ('OPTIONS' in entry) {
19
+ checkFields();
20
+ checkFields();
21
+ checkFields();
22
+ }
23
+ // Check the prop type of the entry function
24
+ if ('POST' in entry) {
25
+ checkFields();
26
+ checkFields();
27
+ checkFields();
28
+ }
29
+ // Check the prop type of the entry function
30
+ if ('PUT' in entry) {
31
+ checkFields();
32
+ checkFields();
33
+ checkFields();
34
+ }
35
+ // Check the prop type of the entry function
36
+ if ('DELETE' in entry) {
37
+ checkFields();
38
+ checkFields();
39
+ checkFields();
40
+ }
41
+ // Check the prop type of the entry function
42
+ if ('PATCH' in entry) {
43
+ checkFields();
44
+ checkFields();
45
+ checkFields();
46
+ }
47
+ // Check the arguments and return type of the generateStaticParams function
48
+ if ('generateStaticParams' in entry) {
49
+ checkFields();
50
+ checkFields();
51
+ }
52
+ function checkFields() { }
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/service/start/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/service/start/route.ts
2
2
  import * as entry from '../../../../../../src/app/api/service/start/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/service/status/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/service/status/route.ts
2
2
  import * as entry from '../../../../../../src/app/api/service/status/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/api/service/stop/route.ts
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/api/service/stop/route.ts
2
2
  import * as entry from '../../../../../../src/app/api/service/stop/route.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/ide/page.tsx
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/ide/page.tsx
2
2
  import * as entry from '../../../../src/app/ide/page.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/layout.tsx
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/layout.tsx
2
2
  import * as entry from '../../../src/app/layout.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/logs/page.tsx
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/logs/page.tsx
2
2
  import * as entry from '../../../../src/app/logs/page.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/models/page.tsx
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/models/page.tsx
2
2
  import * as entry from '../../../../src/app/models/page.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/page.tsx
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/page.tsx
2
2
  import * as entry from '../../../src/app/page.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -1,4 +1,4 @@
1
- // File: /Users/plucky/own/ai-agent-router/src/app/providers/page.tsx
1
+ // File: /Users/pluckypan/own/AI/ai-agent-router/src/app/providers/page.tsx
2
2
  import * as entry from '../../../../src/app/providers/page.js';
3
3
  // Check that the entry is a valid entry
4
4
  checkFields();
@@ -0,0 +1,357 @@
1
+ # Claude SDK 集成指南
2
+
3
+ 本文档介绍如何使用官方 `@anthropic-ai/sdk` 连接到 AI Agent Router 网关。
4
+
5
+ ## 核心概念
6
+
7
+ AI Agent Router 网关提供了统一的 API 入口,支持多种 AI 模型供应商。使用 Claude SDK 连接到网关时,您只需要:
8
+
9
+ 1. **配置网关地址**:将 SDK 的 `baseURL` 指向网关地址(如 `http://localhost:1357`)
10
+ 2. **提供网关 API Key**:使用网关的 API Key 进行认证
11
+ 3. **指定模型 ID**:使用在网关中配置的模型 ID
12
+
13
+ ## 快速开始
14
+
15
+ ### 1. 启动网关
16
+
17
+ ```bash
18
+ aar start --port 1357
19
+ ```
20
+
21
+ ### 2. 配置供应商和模型
22
+
23
+ 访问 `http://localhost:9527` 并配置:
24
+ - 添加 Anthropic 供应商
25
+ - 添加模型(如 `claude-3-5-sonnet-20241022`)
26
+
27
+ ### 3. 使用 SDK 连接
28
+
29
+ ```typescript
30
+ import { createAnthropicClient, sendMessage } from '@ai-agent-router/sdk';
31
+
32
+ const client = createAnthropicClient({
33
+ gatewayUrl: 'http://localhost:1357',
34
+ apiKey: 'your-gateway-api-key',
35
+ });
36
+
37
+ const response = await sendMessage(client, {
38
+ model: 'claude-3-5-sonnet-20241022',
39
+ max_tokens: 1024,
40
+ messages: [{ role: 'user', content: 'Hello!' }],
41
+ });
42
+
43
+ console.log(response.content);
44
+ ```
45
+
46
+ ## API 参考
47
+
48
+ ### `createAnthropicClient(config)`
49
+
50
+ 创建 Claude SDK 客户端实例。
51
+
52
+ #### 参数
53
+
54
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
55
+ |------|------|------|----------|------|
56
+ | `gatewayUrl` | `string` | 否 | `http://localhost:1357` | 网关基础 URL |
57
+ | `apiKey` | `string` | 是 | - | 网关 API Key |
58
+ | `timeout` | `number` | 否 | `60000` | 请求超时时间(毫秒) |
59
+ | `maxRetries` | `number` | 否 | `3` | 最大重试次数 |
60
+ | `enableLogging` | `boolean` | 否 | `false` | 启用详细日志 |
61
+
62
+ #### 返回值
63
+
64
+ 返回一个标准的 `Anthropic` SDK 实例。
65
+
66
+ ### `sendMessage(client, params)`
67
+
68
+ 发送非流式消息。
69
+
70
+ #### 参数
71
+
72
+ | 参数 | 类型 | 必填 | 说明 |
73
+ |------|------|------|------|
74
+ | `client` | `Anthropic` | 是 | SDK 客户端实例 |
75
+ | `params` | `MessageCreateParamsNonStreaming` | 是 | 消息参数(不包括 `stream: true`) |
76
+
77
+ #### 返回值
78
+
79
+ 返回 `Promise<Message>`。
80
+
81
+ ### `sendMessageStream(client, params)`
82
+
83
+ 发送流式消息。
84
+
85
+ #### 参数
86
+
87
+ | 参数 | 类型 | 必填 | 说明 |
88
+ |------|------|------|------|
89
+ | `client` | `Anthropic` | 是 | SDK 客户端实例 |
90
+ | `params` | `MessageCreateParamsStreaming` | 是 | 消息参数(包括 `stream: true`) |
91
+
92
+ #### 返回值
93
+
94
+ 返回 `Promise<AsyncIterable<MessageStreamEvent>>`。
95
+
96
+ ## 使用示例
97
+
98
+ ### 基础对话
99
+
100
+ ```typescript
101
+ import { createAnthropicClient } from '@ai-agent-router/sdk';
102
+
103
+ const client = createAnthropicClient({
104
+ gatewayUrl: 'http://localhost:1357',
105
+ apiKey: process.env.GATEWAY_API_KEY,
106
+ });
107
+
108
+ const response = await client.messages.create({
109
+ model: 'claude-3-5-sonnet-20241022',
110
+ max_tokens: 1024,
111
+ messages: [{ role: 'user', content: 'What is 2+2?' }],
112
+ });
113
+
114
+ console.log(response.content[0].text);
115
+ ```
116
+
117
+ ### 多轮对话
118
+
119
+ ```typescript
120
+ const response = await client.messages.create({
121
+ model: 'claude-3-5-sonnet-20241022',
122
+ max_tokens: 1024,
123
+ messages: [
124
+ { role: 'user', content: 'My name is Alice' },
125
+ { role: 'assistant', content: 'Hello Alice!' },
126
+ { role: 'user', content: 'What is my name?' },
127
+ ],
128
+ });
129
+
130
+ console.log(response.content[0].text);
131
+ ```
132
+
133
+ ### 流式响应
134
+
135
+ ```typescript
136
+ const stream = await client.messages.create({
137
+ model: 'claude-3-5-sonnet-20241022',
138
+ max_tokens: 1024,
139
+ stream: true,
140
+ messages: [{ role: 'user', content: 'Count to 10' }],
141
+ });
142
+
143
+ for await (const chunk of stream) {
144
+ if (chunk.type === 'content_block_delta') {
145
+ if (chunk.delta.type === 'text_delta') {
146
+ process.stdout.write(chunk.delta.text || '');
147
+ }
148
+ }
149
+ }
150
+ ```
151
+
152
+ ### 错误处理
153
+
154
+ ```typescript
155
+ try {
156
+ const response = await client.messages.create({
157
+ model: 'claude-3-5-sonnet-20241022',
158
+ max_tokens: 1024,
159
+ messages: [{ role: 'user', content: 'Hello' }],
160
+ });
161
+ } catch (error) {
162
+ if (error instanceof Anthropic.APIError) {
163
+ console.error('API 错误:', {
164
+ status: error.status,
165
+ message: error.message,
166
+ });
167
+ } else if (error instanceof Anthropic.APIConnectionError) {
168
+ console.error('连接错误:', error.message);
169
+ } else {
170
+ console.error('未知错误:', error);
171
+ }
172
+ }
173
+ ```
174
+
175
+ ### 启用日志
176
+
177
+ ```typescript
178
+ const client = createAnthropicClient({
179
+ gatewayUrl: 'http://localhost:1357',
180
+ apiKey: 'your-gateway-api-key',
181
+ enableLogging: true,
182
+ });
183
+ ```
184
+
185
+ ## 运行示例
186
+
187
+ 项目包含多个示例脚本,可以直接运行:
188
+
189
+ ```bash
190
+ # 运行测试套件
191
+ npm run test:sdk
192
+
193
+ # 运行使用示例
194
+ npm run example:sdk
195
+ ```
196
+
197
+ ## 工作原理
198
+
199
+ ### 网关请求流程
200
+
201
+ 1. **客户端请求**:SDK 发送请求到网关,携带网关 API Key
202
+ 2. **自定义 Fetch**:SDK 的自定义 `fetch` 函数注入正确的认证头
203
+ 3. **网关路由**:网关根据模型 ID 自动路由到对应的供应商
204
+ 4. **供应商转发**:网关解密供应商 API Key 并转发请求
205
+ 5. **响应返回**:响应通过网关返回给 SDK
206
+
207
+ ### 认证头
208
+
209
+ SDK 的自定义 `fetch` 函数会自动添加以下头:
210
+
211
+ ```typescript
212
+ {
213
+ 'Authorization': 'Bearer {gateway-api-key}',
214
+ 'x-api-key': '{gateway-api-key}',
215
+ 'Content-Type': 'application/json',
216
+ }
217
+ ```
218
+
219
+ ### URL 重写
220
+
221
+ 自定义 `fetch` 函数会智能处理 URL:
222
+
223
+ - 如果 URL 已经是完整的 HTTP/HTTPS 地址,直接使用
224
+ - 否则,自动添加网关基础 URL
225
+
226
+ ## 最佳实践
227
+
228
+ ### 1. 环境变量配置
229
+
230
+ ```bash
231
+ # .env 文件
232
+ GATEWAY_URL=http://localhost:1357
233
+ GATEWAY_API_KEY=your-gateway-api-key
234
+ ```
235
+
236
+ ```typescript
237
+ const client = createAnthropicClient({
238
+ gatewayUrl: process.env.GATEWAY_URL,
239
+ apiKey: process.env.GATEWAY_API_KEY,
240
+ });
241
+ ```
242
+
243
+ ### 2. 重试和超时
244
+
245
+ ```typescript
246
+ const client = createAnthropicClient({
247
+ gatewayUrl: 'http://localhost:1357',
248
+ apiKey: 'your-gateway-api-key',
249
+ timeout: 120000, // 2 分钟超时
250
+ maxRetries: 5, // 最多重试 5 次
251
+ });
252
+ ```
253
+
254
+ ### 3. 使用流式响应
255
+
256
+ 对于较长的响应,建议使用流式响应以获得更好的用户体验:
257
+
258
+ ```typescript
259
+ const stream = await client.messages.create({
260
+ model: 'claude-3-5-sonnet-20241022',
261
+ max_tokens: 4096,
262
+ stream: true,
263
+ messages: [{ role: 'user', content: 'Write a long story...' }],
264
+ });
265
+ ```
266
+
267
+ ### 4. Token 计数
268
+
269
+ 响应包含 `usage` 字段,显示 token 使用情况:
270
+
271
+ ```typescript
272
+ const response = await client.messages.create({ ... });
273
+
274
+ console.log('Input tokens:', response.usage.input_tokens);
275
+ console.log('Output tokens:', response.usage.output_tokens);
276
+ console.log('Total tokens:', response.usage.input_tokens + response.usage.output_tokens);
277
+ ```
278
+
279
+ ## 故障排查
280
+
281
+ ### 问题 1: 连接被拒绝
282
+
283
+ **症状**:收到 401 或 403 错误
284
+
285
+ **解决方案**:
286
+ - 检查网关 API Key 是否正确
287
+ - 确认网关服务是否正在运行
288
+ - 检查网关配置是否允许 API Key 访问
289
+
290
+ ### 问题 2: 模型未找到
291
+
292
+ **症状**:收到 404 错误,提示 "Model not found"
293
+
294
+ **解决方案**:
295
+ - 确认模型 ID 是否在网关中配置
296
+ - 检查模型是否已启用
297
+ - 查看网关日志了解详细错误
298
+
299
+ ### 问题 3: 请求超时
300
+
301
+ **症状**:收到 "Request timeout" 错误
302
+
303
+ **解决方案**:
304
+ - 增加 `timeout` 配置
305
+ - 检查网络连接
306
+ - 尝试使用流式响应
307
+
308
+ ### 问题 4: 网关连接失败
309
+
310
+ **症状**:收到 "Connection refused" 错误
311
+
312
+ **解决方案**:
313
+ - 确认网关服务是否正在运行
314
+ - 检查网关地址和端口
315
+ - 检查防火墙设置
316
+
317
+ ## 高级用法
318
+
319
+ ### 多供应商切换
320
+
321
+ 网关支持自动路由,也可以手动指定供应商:
322
+
323
+ ```typescript
324
+ // 方法 1:使用不同模型 ID(自动路由)
325
+ await client.messages.create({
326
+ model: 'claude-3-5-sonnet-20241022', // Anthropic 模型
327
+ ...
328
+ });
329
+
330
+ await client.messages.create({
331
+ model: 'gpt-4', // OpenAI 模型
332
+ ...
333
+ });
334
+
335
+ // 方法 2:在 URL 中指定供应商(需要自定义 fetch)
336
+ // 注意:需要修改 SDK 以支持 ?provider= 查询参数
337
+ ```
338
+
339
+ ### 使用多个客户端实例
340
+
341
+ ```typescript
342
+ const client1 = createAnthropicClient({
343
+ gatewayUrl: 'http://gateway1.example.com:1357',
344
+ apiKey: 'key1',
345
+ });
346
+
347
+ const client2 = createAnthropicClient({
348
+ gatewayUrl: 'http://gateway2.example.com:1357',
349
+ apiKey: 'key2',
350
+ });
351
+ ```
352
+
353
+ ## 相关文档
354
+
355
+ - [主 README](../README.md)
356
+ - [API 端点](../docs/api-endpoints.md)
357
+ - [供应商配置](../docs/providers.md)