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.
- package/.claude/settings.local.json +24 -0
- package/.claude/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-311.pyc +0 -0
- package/dist/.next/types/app/api/config/route.js +1 -1
- package/dist/.next/types/app/api/gateway/[...path]/route.js +1 -1
- package/dist/.next/types/app/api/gateway/route.js +1 -1
- package/dist/.next/types/app/api/ide/claude/apply/route.js +1 -1
- package/dist/.next/types/app/api/ide/claude/available-models/route.js +1 -1
- package/dist/.next/types/app/api/ide/claude/restore/route.js +1 -1
- package/dist/.next/types/app/api/ide/claude/save/route.js +52 -0
- package/dist/.next/types/app/api/ide/claude/status/route.js +1 -1
- package/dist/.next/types/app/api/ide/claude/test/route.js +1 -1
- package/dist/.next/types/app/api/logs/route.js +1 -1
- package/dist/.next/types/app/api/models/route.js +1 -1
- package/dist/.next/types/app/api/providers/route.js +1 -1
- package/dist/.next/types/app/api/providers/test/route.js +1 -1
- package/dist/.next/types/app/api/service/force-stop/route.js +52 -0
- package/dist/.next/types/app/api/service/start/route.js +1 -1
- package/dist/.next/types/app/api/service/status/route.js +1 -1
- package/dist/.next/types/app/api/service/stop/route.js +1 -1
- package/dist/.next/types/app/ide/page.js +1 -1
- package/dist/.next/types/app/layout.js +1 -1
- package/dist/.next/types/app/logs/page.js +1 -1
- package/dist/.next/types/app/models/page.js +1 -1
- package/dist/.next/types/app/page.js +1 -1
- package/dist/.next/types/app/providers/page.js +1 -1
- package/dist/docs/SDK_INTEGRATION.md +357 -0
- package/dist/src/app/api/gateway/[...path]/route.js +26 -18
- package/dist/src/app/api/ide/claude/apply/route.js +8 -7
- package/dist/src/app/api/ide/claude/save/route.js +151 -0
- package/dist/src/app/api/ide/claude/status/route.js +28 -0
- package/dist/src/app/api/ide/claude/test/route.js +176 -80
- package/dist/src/app/api/logs/route.js +4 -2
- package/dist/src/app/api/providers/test/route.js +10 -1
- package/dist/src/app/api/service/force-stop/route.js +32 -0
- package/dist/src/app/ide/page.jsx +168 -45
- package/dist/src/app/logs/page.jsx +392 -12
- package/dist/src/app/page.jsx +2 -313
- package/dist/src/db/queries.js +72 -15
- package/dist/src/diagnostic.mjs +126 -0
- package/dist/src/server/gateway-server.js +4 -3
- package/dist/src/server/gateway.js +41 -25
- package/dist/src/server/providers/anthropic.js +22 -7
- package/dist/src/server/providers/gemini.js +12 -4
- package/dist/src/server/providers/index.js +4 -2
- package/dist/src/server/providers/openai.js +1 -1
- package/dist/src/server/service-manager.js +115 -46
- package/package.json +2 -1
- package/src/app/api/gateway/[...path]/route.ts +35 -22
- package/src/app/api/ide/claude/apply/route.ts +9 -8
- package/src/app/api/ide/claude/save/route.ts +181 -0
- package/src/app/api/ide/claude/status/route.ts +31 -1
- package/src/app/api/ide/claude/test/route.ts +199 -81
- package/src/app/api/logs/route.ts +5 -2
- package/src/app/api/providers/test/route.ts +9 -1
- package/src/app/api/service/force-stop/route.ts +34 -0
- package/src/app/ide/page.tsx +235 -54
- package/src/app/logs/page.tsx +456 -17
- package/src/app/page.tsx +4 -442
- package/src/db/queries.ts +80 -15
- package/src/server/gateway-server.ts +6 -4
- package/src/server/gateway.ts +59 -29
- package/src/server/providers/anthropic.ts +28 -13
- package/src/server/providers/gemini.ts +14 -4
- package/src/server/providers/index.ts +5 -2
- package/src/server/providers/openai.ts +1 -1
- 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
|
+
}
|
|
Binary file
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// File: /Users/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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)
|