qwen-adapter 1.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.
package/.env.example ADDED
@@ -0,0 +1,11 @@
1
+ # 通义千问 API Key (必需)
2
+ # 获取地址: https://dashscope.console.aliyun.com/
3
+ QWEN_API_KEY=sk-9fa7dfeabef54f2d956392cebfbd8da6
4
+
5
+ # 服务配置 (可选)
6
+ PORT=3000
7
+ HOST=localhost
8
+
9
+ # 模型配置 (可选)
10
+ # 可选: qwen-2.5-max, qwen-2.5-plus, qwen-2.5-turbo
11
+ MODEL=qwen-2.5-max
package/README.md ADDED
@@ -0,0 +1,227 @@
1
+ # qwen-adapter
2
+
3
+ > 使用通义千问模型与 Claude Code - Anthropic 兼容 API 适配器
4
+
5
+ [![npm version](https://img.shields.io/npm/v/qwen-adapter.svg)](https://www.npmjs.com/package/qwen-adapter)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## 🎯 功能
9
+
10
+ - ✅ 将通义千问 API 转换为 Anthropic 兼容格式
11
+ - ✅ 支持 Claude Code 完整功能
12
+ - ✅ 支持流式响应
13
+ - ✅ 支持 Tool Calling
14
+ - ✅ 支持多模态(图片)
15
+
16
+ ## 📦 安装
17
+
18
+ ```bash
19
+ npm install -g qwen-adapter
20
+ ```
21
+
22
+ 或使用 npx:
23
+
24
+ ```bash
25
+ npx qwen-adapter start
26
+ ```
27
+
28
+ ## 🚀 快速开始
29
+
30
+ ### 1. 获取通义千问 API Key
31
+
32
+ 访问 [阿里云 DashScope](https://dashscope.console.aliyun.com/) 开通服务并创建 API Key。
33
+
34
+ ### 2. 自动配置 Claude Code(推荐)
35
+
36
+ ```bash
37
+ # 一键安装配置
38
+ npx qwen-adapter install
39
+
40
+ # 设置 API Key
41
+ export QWEN_API_KEY=your_api_key
42
+
43
+ # 启动代理
44
+ npx qwen-adapter start
45
+ ```
46
+
47
+ ### 3. 启动代理服务
48
+
49
+ **方式一: 使用 .env 配置文件(推荐)**
50
+
51
+ 在项目目录或用户目录创建 `.env` 文件:
52
+
53
+ ```bash
54
+ # 创建配置文件
55
+ cp .env.example .env
56
+
57
+ # 编辑 .env 文件,填入你的 API Key
58
+ # QWEN_API_KEY=your_api_key_here
59
+
60
+ # 启动服务
61
+ npx qwen-adapter start
62
+ ```
63
+
64
+ 配置文件搜索路径(按优先级):
65
+ 1. 当前工作目录的 `.env`
66
+ 2. 项目目录的 `.env`
67
+ 3. `~/.qwen-adapter/.env`
68
+
69
+ **方式二: 使用环境变量**
70
+
71
+ ```bash
72
+ export QWEN_API_KEY=your_api_key
73
+ npx qwen-adapter start
74
+ ```
75
+
76
+ **方式三: 使用命令行参数**
77
+
78
+ ```bash
79
+ npx qwen-adapter start -k your_api_key
80
+ ```
81
+
82
+ **方式四: 指定配置文件路径**
83
+
84
+ ```bash
85
+ npx qwen-adapter start -c /path/to/.env
86
+ ```
87
+
88
+ ### 3. 配置 Claude Code
89
+
90
+ 编辑 `~/.claude/settings.json`:
91
+
92
+ ```json
93
+ {
94
+ "env": {
95
+ "ANTHROPIC_AUTH_TOKEN": "qwen-key",
96
+ "ANTHROPIC_BASE_URL": "http://localhost:3000/v1"
97
+ }
98
+ }
99
+ ```
100
+
101
+ ### 4. 启动 Claude Code
102
+
103
+ ```bash
104
+ claude
105
+ ```
106
+
107
+ ## 📖 命令
108
+
109
+ ```bash
110
+ # 启动代理服务
111
+ npx qwen-adapter start
112
+
113
+ # 自动配置 Claude Code(推荐)
114
+ npx qwen-adapter install
115
+
116
+ # 移除配置
117
+ npx qwen-adapter uninstall
118
+
119
+ # 显示配置说明
120
+ npx qwen-adapter config
121
+
122
+ # 测试 API 连接
123
+ npx qwen-adapter test
124
+ ```
125
+
126
+ ### 启动选项
127
+
128
+ | 选项 | 说明 | 默认值 |
129
+ |------|------|--------|
130
+ | `-k, --api-key <key>` | 通义千问 API Key | `QWEN_API_KEY` 环境变量 |
131
+ | `-m, --model <model>` | 使用的模型 | `qwen-2.5-max` |
132
+ | `-p, --port <port>` | 服务端口 | `3000` |
133
+ | `-h, --host <host>` | 服务地址 | `localhost` |
134
+
135
+ ## 🤖 支持的模型
136
+
137
+ ### 通义千问原生模型
138
+
139
+ | 模型 | 说明 |
140
+ |------|------|
141
+ | `qwen-2.5-max` | 最强模型,推荐使用 |
142
+ | `qwen-2.5-plus` | 平衡性能和成本 |
143
+ | `qwen-2.5-turbo` | 快速响应 |
144
+
145
+ ### Claude 模型别名
146
+
147
+ 以下 Claude 模型名称会被自动映射到对应的通义千问模型:
148
+
149
+ | Claude 模型 | 映射到 |
150
+ |------------|--------|
151
+ | `claude-opus-4-6`、`claude-opus-4` | `qwen-max` |
152
+ | `claude-sonnet-4-6`、`claude-sonnet-4` | `qwen-plus` |
153
+ | `claude-haiku-4-5`、`claude-haiku-4` | `qwen-turbo` |
154
+
155
+ ## 🔧 高级用法
156
+
157
+ ### 作为库使用
158
+
159
+ ```javascript
160
+ import { startServer } from 'qwen-adapter';
161
+
162
+ await startServer({
163
+ apiKey: 'your_api_key',
164
+ port: 3000,
165
+ host: 'localhost',
166
+ model: 'qwen-2.5-max'
167
+ });
168
+ ```
169
+
170
+ ### 自定义转换
171
+
172
+ ```javascript
173
+ import { claudeToOpenAI, openAIToClaude } from 'qwen-adapter';
174
+
175
+ // Claude 请求 → OpenAI 格式
176
+ const openaiReq = claudeToOpenAI(claudeRequest);
177
+
178
+ // OpenAI 响应 → Claude 格式
179
+ const claudeRes = openAIToClaude(openaiResponse);
180
+ ```
181
+
182
+ ## 📊 与其他模型对比
183
+
184
+ | 模型 | 代码能力 | 推理能力 | 中文能力 | 成本 |
185
+ |------|---------|---------|---------|------|
186
+ | Claude 4.6 Opus | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 💰💰💰 |
187
+ | GPT-4o | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | 💰💰 |
188
+ | **Qwen-2.5-Max** | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 💰 |
189
+ | GLM-4 | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 💰 |
190
+
191
+ ## ⚠️ 已知限制
192
+
193
+ 1. **Tool Calling 差异**: 通义千问的 Function Calling 格式与 Claude 略有不同,大部分场景可正常工作
194
+ 2. **上下文长度**: 通义千问 128K vs Claude 200K,超长对话可能受限
195
+ 3. **响应速度**: 可能比 Claude 原生 API 稍慢
196
+
197
+ ## 🛠️ 故障排除
198
+
199
+ ### API Key 无效
200
+
201
+ ```
202
+ Error: Qwen API error: 401
203
+ ```
204
+
205
+ 检查:
206
+ - API Key 是否正确
207
+ - 是否已开通通义千问服务
208
+ - API Key 是否有余额
209
+
210
+ ### 端口被占用
211
+
212
+ ```
213
+ Error: listen EADDRINUSE
214
+ ```
215
+
216
+ 使用其他端口:
217
+ ```bash
218
+ npx qwen-adapter start -p 3001
219
+ ```
220
+
221
+ ## 📝 License
222
+
223
+ MIT
224
+
225
+ ## 🤝 贡献
226
+
227
+ 欢迎提交 Issue 和 Pull Request!
package/bin/cli.js ADDED
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @anthropic-ai/qwen-adapter CLI
5
+ *
6
+ * 用法:
7
+ * npx qwen-adapter start # 启动代理服务
8
+ * npx qwen-adapter config # 显示配置说明
9
+ * npx qwen-adapter test # 测试连接
10
+ */
11
+
12
+ import { Command } from 'commander';
13
+ import chalk from 'chalk';
14
+ import dotenv from 'dotenv';
15
+ import { fileURLToPath } from 'url';
16
+ import { dirname, join } from 'path';
17
+ import { existsSync } from 'fs';
18
+ import { startServer } from '../src/server.js';
19
+ import { showConfig } from '../src/commands/config.js';
20
+ import { testConnection } from '../src/commands/test.js';
21
+ import { install, uninstall } from '../src/commands/install.js';
22
+
23
+ // 加载 .env 文件(从当前工作目录和项目目录)
24
+ const __dirname = dirname(fileURLToPath(import.meta.url));
25
+ const envPaths = [
26
+ join(process.cwd(), '.env'), // 当前工作目录
27
+ join(__dirname, '..', '.env'), // 项目目录
28
+ join(process.env.HOME || '~', '.qwen-adapter', '.env'), // 用户目录
29
+ ];
30
+
31
+ for (const envPath of envPaths) {
32
+ if (existsSync(envPath)) {
33
+ dotenv.config({ path: envPath });
34
+ break;
35
+ }
36
+ }
37
+
38
+ const program = new Command();
39
+
40
+ program
41
+ .name('qwen-adapter')
42
+ .description('Use Qwen models with Claude Code - An Anthropic-compatible API adapter')
43
+ .version('1.0.0');
44
+
45
+ // start 命令
46
+ program
47
+ .command('start')
48
+ .description('Start the proxy server')
49
+ .option('-p, --port <port>', 'Server port', process.env.PORT || '3000')
50
+ .option('-k, --api-key <key>', 'Qwen API Key', process.env.QWEN_API_KEY)
51
+ .option('-m, --model <model>', 'Qwen model to use', process.env.MODEL || 'qwen-2.5-max')
52
+ .option('-h, --host <host>', 'Server host', process.env.HOST || 'localhost')
53
+ .option('-c, --config <path>', 'Path to .env config file')
54
+ .action(async (options) => {
55
+ // 如果指定了配置文件,加载它
56
+ if (options.config) {
57
+ dotenv.config({ path: options.config });
58
+ // 重新读取配置
59
+ options.apiKey = options.apiKey || process.env.QWEN_API_KEY;
60
+ options.port = options.port !== '3000' ? options.port : (process.env.PORT || '3000');
61
+ options.model = options.model !== 'qwen-2.5-max' ? options.model : (process.env.MODEL || 'qwen-2.5-max');
62
+ options.host = options.host !== 'localhost' ? options.host : (process.env.HOST || 'localhost');
63
+ }
64
+
65
+ const apiKey = options.apiKey;
66
+
67
+ if (!apiKey) {
68
+ console.error(chalk.red('Error: QWEN_API_KEY is required'));
69
+ console.error(chalk.yellow('Set it via:'));
70
+ console.error(' - Command line: --api-key YOUR_KEY');
71
+ console.error(' - Environment: export QWEN_API_KEY=YOUR_KEY');
72
+ console.error(' - .env file: QWEN_API_KEY=YOUR_KEY');
73
+ console.error(' - Config file: --config /path/to/.env');
74
+ process.exit(1);
75
+ }
76
+
77
+ console.log(chalk.cyan.bold('\n🚀 Qwen Adapter for Claude Code\n'));
78
+ console.log(chalk.gray('━'.repeat(40)));
79
+ console.log(chalk.white(` Model: `) + chalk.green(options.model));
80
+ console.log(chalk.white(` Port: `) + chalk.green(options.port));
81
+ console.log(chalk.white(` Host: `) + chalk.green(options.host));
82
+ console.log(chalk.gray('━'.repeat(40)));
83
+ console.log(chalk.yellow('\nClaude Code 配置:'));
84
+ console.log(chalk.white(' ANTHROPIC_BASE_URL: ') + chalk.cyan(`http://${options.host}:${options.port}/v1`));
85
+ console.log(chalk.white(' ANTHROPIC_AUTH_TOKEN: ') + chalk.cyan('任意值(如: qwen-key)'));
86
+ console.log();
87
+
88
+ await startServer({
89
+ port: parseInt(options.port),
90
+ host: options.host,
91
+ apiKey,
92
+ model: options.model
93
+ });
94
+ });
95
+
96
+ // config 命令
97
+ program
98
+ .command('config')
99
+ .description('Show configuration instructions')
100
+ .action(() => {
101
+ showConfig();
102
+ });
103
+
104
+ // test 命令
105
+ program
106
+ .command('test')
107
+ .description('Test Qwen API connection')
108
+ .option('-k, --api-key <key>', 'Qwen API Key')
109
+ .action(async (options) => {
110
+ const apiKey = options.apiKey || process.env.QWEN_API_KEY;
111
+ if (!apiKey) {
112
+ console.error(chalk.red('Error: QWEN_API_KEY is required'));
113
+ process.exit(1);
114
+ }
115
+ await testConnection(apiKey);
116
+ });
117
+
118
+ // install 命令 - 自动配置 Claude Code
119
+ program
120
+ .command('install')
121
+ .description('Configure Claude Code to use Qwen Adapter')
122
+ .option('-p, --port <port>', 'Proxy server port', '3000')
123
+ .option('-h, --host <host>', 'Proxy server host', 'localhost')
124
+ .action(async (options) => {
125
+ await install(options);
126
+ });
127
+
128
+ // uninstall 命令 - 移除配置
129
+ program
130
+ .command('uninstall')
131
+ .description('Remove Qwen Adapter configuration from Claude Code')
132
+ .action(async () => {
133
+ await uninstall();
134
+ });
135
+
136
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "qwen-adapter",
3
+ "version": "1.0.0",
4
+ "description": "Use Qwen models with Claude Code - An Anthropic-compatible API adapter",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "bin": {
8
+ "qwen-adapter": "./bin/cli.js"
9
+ },
10
+ "exports": {
11
+ ".": "./src/index.js",
12
+ "./server": "./src/server.js",
13
+ "./converters": "./src/converters/index.js"
14
+ },
15
+ "scripts": {
16
+ "start": "node bin/cli.js start",
17
+ "dev": "node --watch bin/cli.js start",
18
+ "test": "node tests/test.js"
19
+ },
20
+ "keywords": [
21
+ "claude",
22
+ "claude-code",
23
+ "qwen",
24
+ "anthropic",
25
+ "openai-compatible",
26
+ "proxy",
27
+ "adapter"
28
+ ],
29
+ "author": "Tie Zi",
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "commander": "^11.1.0",
33
+ "dotenv": "^16.3.1",
34
+ "express": "^4.18.2",
35
+ "node-fetch": "^3.3.2",
36
+ "chalk": "^5.3.0"
37
+ },
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/renyanfeng/qwen-adapter.git"
44
+ },
45
+ "homepage": "https://github.com/renyanfeng/qwen-adapter#readme"
46
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * 配置说明命令
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+
7
+ export function showConfig() {
8
+ console.log();
9
+ console.log(chalk.cyan.bold('═══════════════════════════════════════════════════════════'));
10
+ console.log(chalk.cyan.bold(' Qwen Adapter for Claude Code - 配置说明'));
11
+ console.log(chalk.cyan.bold('═══════════════════════════════════════════════════════════'));
12
+ console.log();
13
+
14
+ console.log(chalk.yellow.bold('1. 获取通义千问 API Key'));
15
+ console.log(chalk.white(' 访问: ') + chalk.cyan('https://dashscope.console.aliyun.com/'));
16
+ console.log(chalk.gray(' → 开通服务 → 创建 API Key'));
17
+ console.log();
18
+
19
+ console.log(chalk.yellow.bold('2. 启动代理服务'));
20
+ console.log(chalk.white(' 方式一: 命令行参数'));
21
+ console.log(chalk.green(' npx @anthropic-ai/qwen-adapter start -k YOUR_API_KEY'));
22
+ console.log();
23
+ console.log(chalk.white(' 方式二: 环境变量'));
24
+ console.log(chalk.green(' export QWEN_API_KEY=YOUR_API_KEY'));
25
+ console.log(chalk.green(' npx @anthropic-ai/qwen-adapter start'));
26
+ console.log();
27
+ console.log(chalk.white(' 方式三: .env 文件'));
28
+ console.log(chalk.gray(' 在项目根目录创建 .env 文件:'));
29
+ console.log(chalk.green(' QWEN_API_KEY=YOUR_API_KEY'));
30
+ console.log();
31
+
32
+ console.log(chalk.yellow.bold('3. 配置 Claude Code'));
33
+ console.log(chalk.white(' 编辑 ~/.claude/settings.json:'));
34
+ console.log();
35
+ console.log(chalk.cyan(' {'));
36
+ console.log(chalk.cyan(' "env": {'));
37
+ console.log(chalk.cyan(' "ANTHROPIC_AUTH_TOKEN": "qwen-key",'));
38
+ console.log(chalk.cyan(' "ANTHROPIC_BASE_URL": "http://localhost:3000/v1"'));
39
+ console.log(chalk.cyan(' }'));
40
+ console.log(chalk.cyan(' }'));
41
+ console.log();
42
+
43
+ console.log(chalk.yellow.bold('4. 重启 Claude Code'));
44
+ console.log(chalk.green(' claude'));
45
+ console.log();
46
+
47
+ console.log(chalk.yellow.bold('5. 验证配置'));
48
+ console.log(chalk.white(' 在 Claude Code 中运行:'));
49
+ console.log(chalk.green(' /model'));
50
+ console.log(chalk.gray(' 应该显示 qwen-2.5-max 或你配置的模型'));
51
+ console.log();
52
+
53
+ console.log(chalk.cyan.bold('═══════════════════════════════════════════════════════════'));
54
+ console.log();
55
+
56
+ console.log(chalk.yellow('可用模型:'));
57
+ console.log(chalk.white(' • qwen-2.5-max ') + chalk.gray('- 最强模型,推荐'));
58
+ console.log(chalk.white(' • qwen-2.5-plus ') + chalk.gray('- 平衡模型'));
59
+ console.log(chalk.white(' • qwen-2.5-turbo ') + chalk.gray('- 快速模型'));
60
+ console.log();
61
+
62
+ console.log(chalk.yellow('命令行选项:'));
63
+ console.log(chalk.white(' -k, --api-key <key> ') + chalk.gray('API Key'));
64
+ console.log(chalk.white(' -m, --model <model> ') + chalk.gray('模型名称 (default: qwen-2.5-max)'));
65
+ console.log(chalk.white(' -p, --port <port> ') + chalk.gray('服务端口 (default: 3000)'));
66
+ console.log(chalk.white(' -h, --host <host> ') + chalk.gray('服务地址 (default: localhost)'));
67
+ console.log();
68
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * 安装/配置命令 - 自动配置 Claude Code
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+ import { homedir } from 'os';
7
+ import { join } from 'path';
8
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
9
+
10
+ const CLAUDE_DIR = join(homedir(), '.claude');
11
+ const SETTINGS_FILE = join(CLAUDE_DIR, 'settings.local.json');
12
+
13
+ export async function install(options) {
14
+ console.log();
15
+ console.log(chalk.cyan.bold('═══════════════════════════════════════════════════════════'));
16
+ console.log(chalk.cyan.bold(' 配置 Claude Code 使用 Qwen Adapter'));
17
+ console.log(chalk.cyan.bold('═══════════════════════════════════════════════════════════'));
18
+ console.log();
19
+
20
+ const port = options.port || '3000';
21
+ const host = options.host || 'localhost';
22
+ const baseUrl = `http://${host}:${port}/v1`;
23
+
24
+ // 读取现有配置
25
+ let settings = {};
26
+ if (existsSync(SETTINGS_FILE)) {
27
+ try {
28
+ const content = readFileSync(SETTINGS_FILE, 'utf-8');
29
+ settings = JSON.parse(content);
30
+ console.log(chalk.gray(' 找到现有配置文件'));
31
+ } catch (e) {
32
+ console.log(chalk.yellow(' 现有配置文件格式错误,将创建新配置'));
33
+ }
34
+ } else {
35
+ // 确保目录存在
36
+ if (!existsSync(CLAUDE_DIR)) {
37
+ mkdirSync(CLAUDE_DIR, { recursive: true });
38
+ console.log(chalk.gray(' 创建配置目录: ~/.claude'));
39
+ }
40
+ }
41
+
42
+ // 合并配置
43
+ const newEnv = {
44
+ ...settings.env,
45
+ ANTHROPIC_BASE_URL: baseUrl,
46
+ ANTHROPIC_AUTH_TOKEN: 'qwen-adapter',
47
+ };
48
+
49
+ const newSettings = {
50
+ ...settings,
51
+ env: newEnv,
52
+ };
53
+
54
+ // 写入配置
55
+ writeFileSync(SETTINGS_FILE, JSON.stringify(newSettings, null, 2));
56
+
57
+ console.log(chalk.green(' ✓ 配置已更新'));
58
+ console.log();
59
+ console.log(chalk.yellow.bold(' 配置内容:'));
60
+ console.log(chalk.white(' 文件: ') + chalk.cyan(SETTINGS_FILE));
61
+ console.log();
62
+ console.log(chalk.cyan(' {'));
63
+ console.log(chalk.cyan(' "env": {'));
64
+ console.log(chalk.cyan(' "ANTHROPIC_BASE_URL": "') + chalk.green(baseUrl) + chalk.cyan('",'));
65
+ console.log(chalk.cyan(' "ANTHROPIC_AUTH_TOKEN": "qwen-adapter"'));
66
+ console.log(chalk.cyan(' }'));
67
+ console.log(chalk.cyan(' }'));
68
+ console.log();
69
+ console.log(chalk.yellow.bold(' 下一步:'));
70
+ console.log(chalk.white(' 1. 启动 Qwen Adapter:'));
71
+ console.log(chalk.green(' npx @anthropic-ai/qwen-adapter start'));
72
+ console.log();
73
+ console.log(chalk.white(' 2. 重启 Claude Code'));
74
+ console.log();
75
+ console.log(chalk.white(' 3. 验证配置:'));
76
+ console.log(chalk.green(' /model'));
77
+ console.log();
78
+ console.log(chalk.cyan.bold('═══════════════════════════════════════════════════════════'));
79
+ console.log();
80
+ }
81
+
82
+ export async function uninstall() {
83
+ console.log();
84
+ console.log(chalk.cyan.bold('═══════════════════════════════════════════════════════════'));
85
+ console.log(chalk.cyan.bold(' 移除 Qwen Adapter 配置'));
86
+ console.log(chalk.cyan.bold('═══════════════════════════════════════════════════════════'));
87
+ console.log();
88
+
89
+ if (!existsSync(SETTINGS_FILE)) {
90
+ console.log(chalk.yellow(' 未找到配置文件'));
91
+ return;
92
+ }
93
+
94
+ const content = readFileSync(SETTINGS_FILE, 'utf-8');
95
+ const settings = JSON.parse(content);
96
+
97
+ // 移除 Qwen Adapter 相关配置
98
+ const newEnv = { ...settings.env };
99
+ delete newEnv.ANTHROPIC_BASE_URL;
100
+ delete newEnv.ANTHROPIC_AUTH_TOKEN;
101
+
102
+ const newSettings = {
103
+ ...settings,
104
+ env: Object.keys(newEnv).length > 0 ? newEnv : undefined,
105
+ };
106
+
107
+ if (Object.keys(newEnv).length === 0) {
108
+ delete newSettings.env;
109
+ }
110
+
111
+ writeFileSync(SETTINGS_FILE, JSON.stringify(newSettings, null, 2));
112
+
113
+ console.log(chalk.green(' ✓ 配置已移除'));
114
+ console.log(chalk.white(' 文件: ') + chalk.cyan(SETTINGS_FILE));
115
+ console.log();
116
+ console.log(chalk.yellow(' 重启 Claude Code 使更改生效'));
117
+ console.log();
118
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * 测试连接命令
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+
7
+ const QWEN_API = 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions';
8
+
9
+ export async function testConnection(apiKey) {
10
+ console.log();
11
+ console.log(chalk.cyan('测试通义千问 API 连接...'));
12
+ console.log();
13
+
14
+ try {
15
+ console.log(chalk.white(' → 发送测试请求...'));
16
+
17
+ const response = await fetch(QWEN_API, {
18
+ method: 'POST',
19
+ headers: {
20
+ 'Content-Type': 'application/json',
21
+ 'Authorization': `Bearer ${apiKey}`,
22
+ },
23
+ body: JSON.stringify({
24
+ model: process.env.MODEL || 'qwen-max',
25
+ messages: [{ role: 'user', content: 'Hello, respond with just "OK"' }],
26
+ max_tokens: 10,
27
+ }),
28
+ });
29
+
30
+ if (!response.ok) {
31
+ const errorText = await response.text();
32
+ console.log(chalk.red(' ✗ 连接失败'));
33
+ console.log(chalk.red(` Status: ${response.status}`));
34
+ console.log(chalk.red(` Error: ${errorText}`));
35
+ console.log();
36
+ console.log(chalk.yellow(' 可能的原因:'));
37
+ console.log(chalk.gray(' • API Key 无效或已过期'));
38
+ console.log(chalk.gray(' • 未开通通义千问服务'));
39
+ console.log(chalk.gray(' • 网络连接问题'));
40
+ return false;
41
+ }
42
+
43
+ const data = await response.json();
44
+ const content = data.choices?.[0]?.message?.content || '';
45
+
46
+ console.log(chalk.green(' ✓ 连接成功!'));
47
+ console.log();
48
+ console.log(chalk.white(' 模型响应: ') + chalk.cyan(content));
49
+ console.log();
50
+ console.log(chalk.white(' Token 使用:'));
51
+ console.log(chalk.gray(` 输入: ${data.usage?.prompt_tokens || 0}`));
52
+ console.log(chalk.gray(` 输出: ${data.usage?.completion_tokens || 0}`));
53
+ console.log();
54
+
55
+ console.log(chalk.green.bold('✓ API Key 有效,可以开始使用!'));
56
+ return true;
57
+
58
+ } catch (error) {
59
+ console.log(chalk.red(' ✗ 连接失败'));
60
+ console.log(chalk.red(` Error: ${error.message}`));
61
+ console.log();
62
+ console.log(chalk.yellow(' 请检查:'));
63
+ console.log(chalk.gray(' • 网络连接是否正常'));
64
+ console.log(chalk.gray(' • API Key 是否正确'));
65
+ return false;
66
+ }
67
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * 转换器模块导出
3
+ */
4
+
5
+ export { claudeToOpenAI } from './request.js';
6
+ export { openAIToClaude } from './response.js';
7
+ export { StreamConverter, formatSSE } from './stream.js';