@asframe/opencode-iflow-auth 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/README.md +278 -0
- package/dist/constants.d.ts +33 -0
- package/dist/constants.js +303 -0
- package/dist/iflow/apikey.d.ts +6 -0
- package/dist/iflow/apikey.js +17 -0
- package/dist/iflow/oauth.d.ts +20 -0
- package/dist/iflow/oauth.js +113 -0
- package/dist/iflow/proxy.d.ts +23 -0
- package/dist/iflow/proxy.js +435 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/plugin/accounts.d.ts +24 -0
- package/dist/plugin/accounts.js +205 -0
- package/dist/plugin/auth-page.d.ts +3 -0
- package/dist/plugin/auth-page.js +573 -0
- package/dist/plugin/cli.d.ts +11 -0
- package/dist/plugin/cli.js +77 -0
- package/dist/plugin/config/index.d.ts +2 -0
- package/dist/plugin/config/index.js +2 -0
- package/dist/plugin/config/loader.d.ts +3 -0
- package/dist/plugin/config/loader.js +110 -0
- package/dist/plugin/config/schema.d.ts +35 -0
- package/dist/plugin/config/schema.js +22 -0
- package/dist/plugin/errors.d.ts +14 -0
- package/dist/plugin/errors.js +25 -0
- package/dist/plugin/logger.d.ts +8 -0
- package/dist/plugin/logger.js +63 -0
- package/dist/plugin/server.d.ts +7 -0
- package/dist/plugin/server.js +98 -0
- package/dist/plugin/storage.d.ts +4 -0
- package/dist/plugin/storage.js +91 -0
- package/dist/plugin/token.d.ts +3 -0
- package/dist/plugin/token.js +26 -0
- package/dist/plugin/types.d.ts +58 -0
- package/dist/plugin/types.js +1 -0
- package/dist/plugin-iflow.d.ts +2 -0
- package/dist/plugin-iflow.js +141 -0
- package/dist/plugin-proxy.d.ts +2 -0
- package/dist/plugin-proxy.js +155 -0
- package/dist/plugin.d.ts +2 -0
- package/dist/plugin.js +2 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# OpenCode iFlow Auth Plugin
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@asframe/opencode-iflow-auth)
|
|
4
|
+
[](https://www.npmjs.com/package/@asframe/opencode-iflow-auth)
|
|
5
|
+
[](https://www.npmjs.com/package/@asframe/opencode-iflow-auth)
|
|
6
|
+
[](https://github.com/asframe/opencode-iflow-auth)
|
|
7
|
+
|
|
8
|
+
OpenCode plugin for iFlow.cn providing access to Qwen, DeepSeek, Kimi, GLM, and iFlow ROME models with dual authentication and CLI Proxy support.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Dual authentication**: OAuth 2.0 (PKCE) and API Key support.
|
|
13
|
+
- **CLI Proxy mode**: Support GLM-5 through iflow CLI with automatic proxy server.
|
|
14
|
+
- **Multi-account rotation**: Sticky and round-robin strategies.
|
|
15
|
+
- **Automated token refresh**: Rate limit handling with exponential backoff.
|
|
16
|
+
- **Native thinking mode**: Support for GLM-4.x, GLM-5 and DeepSeek R1 models.
|
|
17
|
+
- **Configurable timeout**: Request timeout and iteration limits to prevent hangs.
|
|
18
|
+
- **Automatic port selection**: OAuth callback server port conflict avoidance.
|
|
19
|
+
|
|
20
|
+
## Two Plugin Modes
|
|
21
|
+
|
|
22
|
+
This package exports two plugins:
|
|
23
|
+
|
|
24
|
+
### 1. `IFlowPlugin` - Direct API Mode
|
|
25
|
+
|
|
26
|
+
Direct API calls to iFlow.cn for standard models.
|
|
27
|
+
|
|
28
|
+
| Property | Value |
|
|
29
|
+
|----------|-------|
|
|
30
|
+
| Provider | `iflow` |
|
|
31
|
+
| baseURL | `https://apis.iflow.cn/v1` |
|
|
32
|
+
| Models | deepseek-v3.2, glm-4.6, kimi-k2.5, qwen3-coder-plus, etc. |
|
|
33
|
+
|
|
34
|
+
### 2. `IFlowProxyPlugin` - CLI Proxy Mode
|
|
35
|
+
|
|
36
|
+
Routes requests through iflow CLI for GLM-5 support. The proxy server starts automatically when OpenCode loads the plugin.
|
|
37
|
+
|
|
38
|
+
| Property | Value |
|
|
39
|
+
|----------|-------|
|
|
40
|
+
| Provider | `iflow-proxy` |
|
|
41
|
+
| Proxy Port | `127.0.0.1:19998` |
|
|
42
|
+
| Models | glm-5, glm-5-free, glm-5-thinking |
|
|
43
|
+
|
|
44
|
+
**How it works:**
|
|
45
|
+
1. Plugin detects if model requires CLI (glm-5, glm-5-free, glm-5-thinking)
|
|
46
|
+
2. Starts a local proxy server on port 19998
|
|
47
|
+
3. Routes CLI-required models through `iflow` CLI via stdin
|
|
48
|
+
4. Routes other models directly to iFlow API
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
Add the plugin to your `opencode.json` or `opencode.jsonc`:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"plugin": ["@asframe/opencode-iflow-auth"],
|
|
57
|
+
"provider": {
|
|
58
|
+
"iflow": {
|
|
59
|
+
"npm": "@ai-sdk/openai-compatible",
|
|
60
|
+
"options": {
|
|
61
|
+
"baseURL": "https://apis.iflow.cn/v1"
|
|
62
|
+
},
|
|
63
|
+
"models": {
|
|
64
|
+
"deepseek-v3.2": {
|
|
65
|
+
"name": "DeepSeek V3.2",
|
|
66
|
+
"limit": { "context": 128000, "output": 64000 },
|
|
67
|
+
"modalities": { "input": ["text"], "output": ["text"] }
|
|
68
|
+
},
|
|
69
|
+
"glm-4.6": {
|
|
70
|
+
"name": "GLM-4.6",
|
|
71
|
+
"limit": { "context": 128000, "output": 64000 },
|
|
72
|
+
"modalities": { "input": ["text"], "output": ["text"] }
|
|
73
|
+
},
|
|
74
|
+
"kimi-k2.5": {
|
|
75
|
+
"name": "Kimi K2.5",
|
|
76
|
+
"limit": { "context": 256000, "output": 64000 },
|
|
77
|
+
"modalities": { "input": ["text"], "output": ["text"] }
|
|
78
|
+
},
|
|
79
|
+
"qwen3-coder-plus": {
|
|
80
|
+
"name": "Qwen3 Coder Plus",
|
|
81
|
+
"limit": { "context": 1000000, "output": 64000 },
|
|
82
|
+
"modalities": { "input": ["text"], "output": ["text"] }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"iflow-proxy": {
|
|
87
|
+
"npm": "@ai-sdk/openai-compatible",
|
|
88
|
+
"options": {
|
|
89
|
+
"baseURL": "http://127.0.0.1:19998/v1"
|
|
90
|
+
},
|
|
91
|
+
"models": {
|
|
92
|
+
"glm-5": {
|
|
93
|
+
"name": "GLM-5 (via CLI Proxy)",
|
|
94
|
+
"limit": { "context": 202000, "output": 64000 },
|
|
95
|
+
"modalities": { "input": ["text"], "output": ["text"] }
|
|
96
|
+
},
|
|
97
|
+
"glm-5-free": {
|
|
98
|
+
"name": "GLM-5 Free (via CLI Proxy)",
|
|
99
|
+
"limit": { "context": 202000, "output": 64000 },
|
|
100
|
+
"modalities": { "input": ["text"], "output": ["text"] }
|
|
101
|
+
},
|
|
102
|
+
"glm-5-thinking": {
|
|
103
|
+
"name": "GLM-5 Thinking (via CLI Proxy)",
|
|
104
|
+
"limit": { "context": 202000, "output": 64000 },
|
|
105
|
+
"modalities": { "input": ["text"], "output": ["text"] }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Setup
|
|
114
|
+
|
|
115
|
+
### Direct API Mode
|
|
116
|
+
|
|
117
|
+
1. Run `opencode auth login`.
|
|
118
|
+
2. Select `Other`, type `iflow`, and press enter.
|
|
119
|
+
3. Choose authentication method:
|
|
120
|
+
- **OAuth 2.0**: Follow browser flow for secure token-based authentication.
|
|
121
|
+
- **API Key**: Enter your iFlow API key (starts with `sk-`).
|
|
122
|
+
|
|
123
|
+
### CLI Proxy Mode (for GLM-5)
|
|
124
|
+
|
|
125
|
+
1. Install iflow CLI: `npm install -g iflow-cli`
|
|
126
|
+
2. Login to iflow CLI: `iflow login`
|
|
127
|
+
3. The proxy server will start automatically when using `iflow-proxy` provider.
|
|
128
|
+
|
|
129
|
+
**Auto-install CLI:**
|
|
130
|
+
|
|
131
|
+
If iflow CLI is not installed, the plugin can automatically install it for you. Enable this feature by setting the environment variable:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# PowerShell
|
|
135
|
+
$env:IFLOW_AUTO_INSTALL_CLI = "true"
|
|
136
|
+
|
|
137
|
+
# Bash
|
|
138
|
+
export IFLOW_AUTO_INSTALL_CLI=true
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Requirements for CLI Proxy:**
|
|
142
|
+
- Node.js 18+
|
|
143
|
+
- iflow CLI installed and logged in (or set `IFLOW_AUTO_INSTALL_CLI=true` to auto-install)
|
|
144
|
+
- Port 19998 available (or will use existing proxy if already running)
|
|
145
|
+
|
|
146
|
+
## Usage
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Direct API mode
|
|
150
|
+
opencode run "你好" --model iflow/deepseek-v3.2
|
|
151
|
+
opencode run "你好" --model iflow/glm-4.6
|
|
152
|
+
opencode run "你好" --model iflow/kimi-k2.5
|
|
153
|
+
|
|
154
|
+
# CLI Proxy mode (GLM-5)
|
|
155
|
+
opencode run "你好" --model iflow-proxy/glm-5
|
|
156
|
+
opencode run "你好" --model iflow-proxy/glm-5-thinking
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Configuration
|
|
160
|
+
|
|
161
|
+
Edit `~/.config/opencode/iflow.json`:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"default_auth_method": "oauth",
|
|
166
|
+
"account_selection_strategy": "round-robin",
|
|
167
|
+
"auth_server_port_start": 8087,
|
|
168
|
+
"auth_server_port_range": 10,
|
|
169
|
+
"max_request_iterations": 50,
|
|
170
|
+
"request_timeout_ms": 300000,
|
|
171
|
+
"enable_log_api_request": false
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Configuration Options
|
|
176
|
+
|
|
177
|
+
- `default_auth_method`: Default authentication method (`oauth`, `apikey`)
|
|
178
|
+
- `account_selection_strategy`: Account rotation strategy (`sticky`, `round-robin`)
|
|
179
|
+
- `auth_server_port_start`: Starting port for OAuth callback server (1024-65535)
|
|
180
|
+
- `auth_server_port_range`: Number of ports to try (1-100)
|
|
181
|
+
- `max_request_iterations`: Maximum loop iterations to prevent hangs (10-1000)
|
|
182
|
+
- `request_timeout_ms`: Request timeout in milliseconds (60000-600000ms)
|
|
183
|
+
- `enable_log_api_request`: Enable API request/response logging (errors always logged)
|
|
184
|
+
|
|
185
|
+
### Environment Variables
|
|
186
|
+
|
|
187
|
+
- `IFLOW_AUTH_DEBUG`: Enable debug logging for auth plugin (`true`/`false`)
|
|
188
|
+
- `IFLOW_PROXY_DEBUG`: Enable debug logging for proxy plugin (`true`/`false`)
|
|
189
|
+
- `IFLOW_AUTO_INSTALL_CLI`: Auto-install iflow CLI if not installed (`true`/`false`)
|
|
190
|
+
- `IFLOW_DEFAULT_AUTH_METHOD`
|
|
191
|
+
- `IFLOW_ACCOUNT_SELECTION_STRATEGY`
|
|
192
|
+
- `IFLOW_AUTH_SERVER_PORT_START`
|
|
193
|
+
- `IFLOW_AUTH_SERVER_PORT_RANGE`
|
|
194
|
+
- `IFLOW_MAX_REQUEST_ITERATIONS`
|
|
195
|
+
- `IFLOW_REQUEST_TIMEOUT_MS`
|
|
196
|
+
- `IFLOW_ENABLE_LOG_API_REQUEST`
|
|
197
|
+
|
|
198
|
+
## Storage
|
|
199
|
+
|
|
200
|
+
**Linux/macOS:**
|
|
201
|
+
- Credentials: `~/.config/opencode/iflow-accounts.json`
|
|
202
|
+
- Plugin Config: `~/.config/opencode/iflow.json`
|
|
203
|
+
|
|
204
|
+
**Windows:**
|
|
205
|
+
- Credentials: `%APPDATA%\opencode\iflow-accounts.json`
|
|
206
|
+
- Plugin Config: `%APPDATA%\opencode\iflow.json`
|
|
207
|
+
|
|
208
|
+
## Thinking Models
|
|
209
|
+
|
|
210
|
+
iFlow supports thinking models with customizable thinking budgets via variants:
|
|
211
|
+
|
|
212
|
+
### GLM-4.6, GLM-5 & DeepSeek R1
|
|
213
|
+
|
|
214
|
+
```json
|
|
215
|
+
{
|
|
216
|
+
"variants": {
|
|
217
|
+
"low": { "thinkingConfig": { "thinkingBudget": 1024 } },
|
|
218
|
+
"medium": { "thinkingConfig": { "thinkingBudget": 8192 } },
|
|
219
|
+
"max": { "thinkingConfig": { "thinkingBudget": 32768 } }
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Troubleshooting
|
|
225
|
+
|
|
226
|
+
### CLI Proxy Issues
|
|
227
|
+
|
|
228
|
+
If you encounter issues with the CLI proxy:
|
|
229
|
+
|
|
230
|
+
1. **Check if iflow CLI is installed:**
|
|
231
|
+
```bash
|
|
232
|
+
iflow --version
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
2. **Check if you're logged in:**
|
|
236
|
+
```bash
|
|
237
|
+
iflow login
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
3. **Test iflow CLI directly:**
|
|
241
|
+
```bash
|
|
242
|
+
echo "你好" | iflow -m glm-5
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
4. **Enable debug logging:**
|
|
246
|
+
```bash
|
|
247
|
+
$env:IFLOW_PROXY_DEBUG = "true"
|
|
248
|
+
opencode run "你好" --model iflow-proxy/glm-5
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Port Already in Use
|
|
252
|
+
|
|
253
|
+
If port 19998 is already in use, the plugin will detect it and use the existing proxy. If you need to restart the proxy:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# Kill existing process on port 19998
|
|
257
|
+
# Windows
|
|
258
|
+
Get-Process -Id (Get-NetTCPConnection -LocalPort 19998).OwningProcess | Stop-Process -Force
|
|
259
|
+
|
|
260
|
+
# Linux/macOS
|
|
261
|
+
lsof -i :19998 | grep LISTEN | awk '{print $2}' | xargs kill -9
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
267
|
+
|
|
268
|
+
## Disclaimer
|
|
269
|
+
|
|
270
|
+
This plugin is provided strictly for learning and educational purposes. It is an independent implementation and is not affiliated with, endorsed by, or supported by iFlow.cn. Use of this plugin is at your own risk.
|
|
271
|
+
|
|
272
|
+
Feel free to open a PR to optimize this plugin further.
|
|
273
|
+
|
|
274
|
+
## Links
|
|
275
|
+
|
|
276
|
+
- [GitHub Repository](https://github.com/asframe/opencode-iflow-auth)
|
|
277
|
+
- [npm Package](https://www.npmjs.com/package/@asframe/opencode-iflow-auth)
|
|
278
|
+
- [iFlow.cn](https://iflow.cn)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type IFlowAuthMethod = 'oauth' | 'apikey';
|
|
2
|
+
export declare function isValidAuthMethod(method: string): method is IFlowAuthMethod;
|
|
3
|
+
export declare const IFLOW_CONSTANTS: {
|
|
4
|
+
BASE_URL: string;
|
|
5
|
+
OAUTH_TOKEN_URL: string;
|
|
6
|
+
OAUTH_AUTHORIZE_URL: string;
|
|
7
|
+
USER_INFO_URL: string;
|
|
8
|
+
SUCCESS_REDIRECT: string;
|
|
9
|
+
CLIENT_ID: string;
|
|
10
|
+
CLIENT_SECRET: string;
|
|
11
|
+
AXIOS_TIMEOUT: number;
|
|
12
|
+
USER_AGENT: string;
|
|
13
|
+
CALLBACK_PORT_START: number;
|
|
14
|
+
CALLBACK_PORT_RANGE: number;
|
|
15
|
+
};
|
|
16
|
+
export declare const THINKING_MODELS: string[];
|
|
17
|
+
export declare function isThinkingModel(model: string): boolean;
|
|
18
|
+
export declare function applyThinkingConfig(body: any, model: string): any;
|
|
19
|
+
export interface IFlowModelConfig {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
context: number;
|
|
23
|
+
output: number;
|
|
24
|
+
inputModalities: ('text' | 'image' | 'audio' | 'video' | 'pdf')[];
|
|
25
|
+
outputModalities: ('text' | 'image' | 'audio' | 'video' | 'pdf')[];
|
|
26
|
+
reasoning?: boolean;
|
|
27
|
+
toolcall?: boolean;
|
|
28
|
+
temperature?: boolean;
|
|
29
|
+
family?: string;
|
|
30
|
+
variants?: Record<string, Record<string, any>>;
|
|
31
|
+
}
|
|
32
|
+
export declare const IFLOW_MODELS: IFlowModelConfig[];
|
|
33
|
+
export declare function registerIFlowModels(provider: any): void;
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
export function isValidAuthMethod(method) {
|
|
2
|
+
return method === 'oauth' || method === 'apikey';
|
|
3
|
+
}
|
|
4
|
+
export const IFLOW_CONSTANTS = {
|
|
5
|
+
BASE_URL: 'https://apis.iflow.cn/v1',
|
|
6
|
+
OAUTH_TOKEN_URL: 'https://iflow.cn/oauth/token',
|
|
7
|
+
OAUTH_AUTHORIZE_URL: 'https://iflow.cn/oauth',
|
|
8
|
+
USER_INFO_URL: 'https://iflow.cn/api/oauth/getUserInfo',
|
|
9
|
+
SUCCESS_REDIRECT: 'https://iflow.cn/oauth/success',
|
|
10
|
+
CLIENT_ID: '10009311001',
|
|
11
|
+
CLIENT_SECRET: '4Z3YjXycVsQvyGF1etiNlIBB4RsqSDtW',
|
|
12
|
+
AXIOS_TIMEOUT: 120000,
|
|
13
|
+
USER_AGENT: 'OpenCode-iFlow',
|
|
14
|
+
CALLBACK_PORT_START: 8087,
|
|
15
|
+
CALLBACK_PORT_RANGE: 10
|
|
16
|
+
};
|
|
17
|
+
export const THINKING_MODELS = ['glm-4.6', 'glm-5', 'qwen3-235b-a22b-thinking-2507', 'deepseek-r1'];
|
|
18
|
+
export function isThinkingModel(model) {
|
|
19
|
+
return THINKING_MODELS.some((m) => model.startsWith(m));
|
|
20
|
+
}
|
|
21
|
+
export function applyThinkingConfig(body, model) {
|
|
22
|
+
const thinkingBudget = body.providerOptions?.thinkingConfig?.thinkingBudget;
|
|
23
|
+
const isThinkingEnabled = body.providerOptions?.thinkingConfig?.enabled !== false;
|
|
24
|
+
if (model.startsWith('glm-5')) {
|
|
25
|
+
const result = {
|
|
26
|
+
...body,
|
|
27
|
+
temperature: 1,
|
|
28
|
+
top_p: 0.95,
|
|
29
|
+
};
|
|
30
|
+
if (isThinkingEnabled) {
|
|
31
|
+
result.chat_template_kwargs = { enable_thinking: true };
|
|
32
|
+
result.enable_thinking = true;
|
|
33
|
+
result.thinking = { type: 'enabled' };
|
|
34
|
+
if (thinkingBudget) {
|
|
35
|
+
result.thinking_budget = thinkingBudget;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
result.chat_template_kwargs = { enable_thinking: false };
|
|
40
|
+
result.enable_thinking = false;
|
|
41
|
+
result.thinking = { type: 'disabled' };
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
if (model.startsWith('glm-4')) {
|
|
46
|
+
const result = {
|
|
47
|
+
...body,
|
|
48
|
+
chat_template_kwargs: {
|
|
49
|
+
enable_thinking: true,
|
|
50
|
+
clear_thinking: false
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
if (thinkingBudget) {
|
|
54
|
+
result.thinking_budget = thinkingBudget;
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
if (model.startsWith('deepseek-r1')) {
|
|
59
|
+
const result = { ...body };
|
|
60
|
+
if (thinkingBudget) {
|
|
61
|
+
result.thinking_budget = thinkingBudget;
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
return body;
|
|
66
|
+
}
|
|
67
|
+
export const IFLOW_MODELS = [
|
|
68
|
+
{
|
|
69
|
+
id: 'glm-5',
|
|
70
|
+
name: 'GLM-5',
|
|
71
|
+
context: 256000,
|
|
72
|
+
output: 64000,
|
|
73
|
+
inputModalities: ['text', 'image'],
|
|
74
|
+
outputModalities: ['text'],
|
|
75
|
+
reasoning: true,
|
|
76
|
+
toolcall: true,
|
|
77
|
+
family: 'glm',
|
|
78
|
+
variants: {
|
|
79
|
+
low: { thinkingConfig: { thinkingBudget: 1024 } },
|
|
80
|
+
medium: { thinkingConfig: { thinkingBudget: 8192 } },
|
|
81
|
+
max: { thinkingConfig: { thinkingBudget: 32768 } }
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'glm-4.6',
|
|
86
|
+
name: 'GLM-4.6 Thinking',
|
|
87
|
+
context: 200000,
|
|
88
|
+
output: 128000,
|
|
89
|
+
inputModalities: ['text', 'image'],
|
|
90
|
+
outputModalities: ['text'],
|
|
91
|
+
reasoning: true,
|
|
92
|
+
toolcall: true,
|
|
93
|
+
family: 'glm',
|
|
94
|
+
variants: {
|
|
95
|
+
low: { thinkingConfig: { thinkingBudget: 1024 } },
|
|
96
|
+
medium: { thinkingConfig: { thinkingBudget: 8192 } },
|
|
97
|
+
max: { thinkingConfig: { thinkingBudget: 32768 } }
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: 'qwen3-max',
|
|
102
|
+
name: 'Qwen3 Max',
|
|
103
|
+
context: 256000,
|
|
104
|
+
output: 32000,
|
|
105
|
+
inputModalities: ['text'],
|
|
106
|
+
outputModalities: ['text'],
|
|
107
|
+
toolcall: true,
|
|
108
|
+
family: 'qwen3'
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 'qwen3-max-preview',
|
|
112
|
+
name: 'Qwen3 Max Preview',
|
|
113
|
+
context: 256000,
|
|
114
|
+
output: 32000,
|
|
115
|
+
inputModalities: ['text'],
|
|
116
|
+
outputModalities: ['text'],
|
|
117
|
+
toolcall: true,
|
|
118
|
+
family: 'qwen3'
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 'qwen3-coder-plus',
|
|
122
|
+
name: 'Qwen3 Coder Plus',
|
|
123
|
+
context: 1000000,
|
|
124
|
+
output: 64000,
|
|
125
|
+
inputModalities: ['text'],
|
|
126
|
+
outputModalities: ['text'],
|
|
127
|
+
toolcall: true,
|
|
128
|
+
family: 'qwen3-coder'
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: 'qwen3-vl-plus',
|
|
132
|
+
name: 'Qwen3 VL Plus',
|
|
133
|
+
context: 256000,
|
|
134
|
+
output: 32000,
|
|
135
|
+
inputModalities: ['text', 'image'],
|
|
136
|
+
outputModalities: ['text'],
|
|
137
|
+
family: 'qwen3-vl'
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: 'qwen3-32b',
|
|
141
|
+
name: 'Qwen3 32B',
|
|
142
|
+
context: 128000,
|
|
143
|
+
output: 32000,
|
|
144
|
+
inputModalities: ['text'],
|
|
145
|
+
outputModalities: ['text'],
|
|
146
|
+
toolcall: true,
|
|
147
|
+
family: 'qwen3'
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: 'qwen3-235b',
|
|
151
|
+
name: 'Qwen3 235B',
|
|
152
|
+
context: 256000,
|
|
153
|
+
output: 64000,
|
|
154
|
+
inputModalities: ['text'],
|
|
155
|
+
outputModalities: ['text'],
|
|
156
|
+
toolcall: true,
|
|
157
|
+
family: 'qwen3'
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: 'qwen3-235b-a22b-thinking-2507',
|
|
161
|
+
name: 'Qwen3 235B Thinking',
|
|
162
|
+
context: 256000,
|
|
163
|
+
output: 64000,
|
|
164
|
+
inputModalities: ['text'],
|
|
165
|
+
outputModalities: ['text'],
|
|
166
|
+
reasoning: true,
|
|
167
|
+
toolcall: true,
|
|
168
|
+
family: 'qwen3-thinking',
|
|
169
|
+
variants: {
|
|
170
|
+
low: { thinkingConfig: { thinkingBudget: 1024 } },
|
|
171
|
+
medium: { thinkingConfig: { thinkingBudget: 8192 } },
|
|
172
|
+
max: { thinkingConfig: { thinkingBudget: 32768 } }
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
id: 'qwen3-235b-a22b-instruct',
|
|
177
|
+
name: 'Qwen3 235B Instruct',
|
|
178
|
+
context: 256000,
|
|
179
|
+
output: 64000,
|
|
180
|
+
inputModalities: ['text'],
|
|
181
|
+
outputModalities: ['text'],
|
|
182
|
+
toolcall: true,
|
|
183
|
+
family: 'qwen3'
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: 'kimi-k2',
|
|
187
|
+
name: 'Kimi K2',
|
|
188
|
+
context: 128000,
|
|
189
|
+
output: 64000,
|
|
190
|
+
inputModalities: ['text'],
|
|
191
|
+
outputModalities: ['text'],
|
|
192
|
+
toolcall: true,
|
|
193
|
+
family: 'kimi'
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
id: 'kimi-k2-0905',
|
|
197
|
+
name: 'Kimi K2 0905',
|
|
198
|
+
context: 256000,
|
|
199
|
+
output: 64000,
|
|
200
|
+
inputModalities: ['text'],
|
|
201
|
+
outputModalities: ['text'],
|
|
202
|
+
toolcall: true,
|
|
203
|
+
family: 'kimi'
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: 'deepseek-v3',
|
|
207
|
+
name: 'DeepSeek V3',
|
|
208
|
+
context: 128000,
|
|
209
|
+
output: 32000,
|
|
210
|
+
inputModalities: ['text'],
|
|
211
|
+
outputModalities: ['text'],
|
|
212
|
+
toolcall: true,
|
|
213
|
+
family: 'deepseek'
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
id: 'deepseek-v3.2',
|
|
217
|
+
name: 'DeepSeek V3.2',
|
|
218
|
+
context: 128000,
|
|
219
|
+
output: 64000,
|
|
220
|
+
inputModalities: ['text'],
|
|
221
|
+
outputModalities: ['text'],
|
|
222
|
+
toolcall: true,
|
|
223
|
+
family: 'deepseek'
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
id: 'deepseek-r1',
|
|
227
|
+
name: 'DeepSeek R1',
|
|
228
|
+
context: 128000,
|
|
229
|
+
output: 32000,
|
|
230
|
+
inputModalities: ['text'],
|
|
231
|
+
outputModalities: ['text'],
|
|
232
|
+
reasoning: true,
|
|
233
|
+
toolcall: true,
|
|
234
|
+
family: 'deepseek-r',
|
|
235
|
+
variants: {
|
|
236
|
+
low: { thinkingConfig: { thinkingBudget: 1024 } },
|
|
237
|
+
medium: { thinkingConfig: { thinkingBudget: 8192 } },
|
|
238
|
+
max: { thinkingConfig: { thinkingBudget: 32768 } }
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
id: 'iflow-rome-30ba3b',
|
|
243
|
+
name: 'iFlow ROME 30B',
|
|
244
|
+
context: 256000,
|
|
245
|
+
output: 64000,
|
|
246
|
+
inputModalities: ['text'],
|
|
247
|
+
outputModalities: ['text'],
|
|
248
|
+
family: 'iflow-rome'
|
|
249
|
+
}
|
|
250
|
+
];
|
|
251
|
+
export function registerIFlowModels(provider) {
|
|
252
|
+
for (const modelConfig of IFLOW_MODELS) {
|
|
253
|
+
const actualApiId = modelConfig.id;
|
|
254
|
+
if (!provider.models[modelConfig.id]) {
|
|
255
|
+
provider.models[modelConfig.id] = {
|
|
256
|
+
id: modelConfig.id,
|
|
257
|
+
providerID: 'iflow',
|
|
258
|
+
api: {
|
|
259
|
+
id: actualApiId,
|
|
260
|
+
url: IFLOW_CONSTANTS.BASE_URL,
|
|
261
|
+
npm: '@ai-sdk/openai-compatible'
|
|
262
|
+
},
|
|
263
|
+
name: modelConfig.name,
|
|
264
|
+
family: modelConfig.family || modelConfig.id.split('-')[0],
|
|
265
|
+
capabilities: {
|
|
266
|
+
temperature: modelConfig.temperature ?? true,
|
|
267
|
+
reasoning: modelConfig.reasoning ?? false,
|
|
268
|
+
attachment: modelConfig.inputModalities.includes('image'),
|
|
269
|
+
toolcall: modelConfig.toolcall ?? false,
|
|
270
|
+
input: {
|
|
271
|
+
text: modelConfig.inputModalities.includes('text'),
|
|
272
|
+
audio: modelConfig.inputModalities.includes('audio'),
|
|
273
|
+
image: modelConfig.inputModalities.includes('image'),
|
|
274
|
+
video: modelConfig.inputModalities.includes('video'),
|
|
275
|
+
pdf: modelConfig.inputModalities.includes('pdf')
|
|
276
|
+
},
|
|
277
|
+
output: {
|
|
278
|
+
text: modelConfig.outputModalities.includes('text'),
|
|
279
|
+
audio: modelConfig.outputModalities.includes('audio'),
|
|
280
|
+
image: modelConfig.outputModalities.includes('image'),
|
|
281
|
+
video: modelConfig.outputModalities.includes('video'),
|
|
282
|
+
pdf: modelConfig.outputModalities.includes('pdf')
|
|
283
|
+
},
|
|
284
|
+
interleaved: modelConfig.reasoning ?? false
|
|
285
|
+
},
|
|
286
|
+
cost: {
|
|
287
|
+
input: 0,
|
|
288
|
+
output: 0,
|
|
289
|
+
cache: { read: 0, write: 0 }
|
|
290
|
+
},
|
|
291
|
+
limit: {
|
|
292
|
+
context: modelConfig.context,
|
|
293
|
+
output: modelConfig.output
|
|
294
|
+
},
|
|
295
|
+
status: 'active',
|
|
296
|
+
options: {},
|
|
297
|
+
headers: {},
|
|
298
|
+
release_date: '2025-01-01',
|
|
299
|
+
variants: modelConfig.variants || {}
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IFLOW_CONSTANTS } from '../constants.js';
|
|
2
|
+
export async function validateApiKey(apiKey) {
|
|
3
|
+
const response = await fetch(`${IFLOW_CONSTANTS.BASE_URL}/models`, {
|
|
4
|
+
headers: {
|
|
5
|
+
Authorization: `Bearer ${apiKey}`,
|
|
6
|
+
'User-Agent': IFLOW_CONSTANTS.USER_AGENT
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
if (!response.ok) {
|
|
10
|
+
throw new Error(`API key validation failed: ${response.status}`);
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
apiKey,
|
|
14
|
+
email: 'api-key-user',
|
|
15
|
+
authMethod: 'apikey'
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface IFlowOAuthAuthorization {
|
|
2
|
+
authUrl: string;
|
|
3
|
+
state: string;
|
|
4
|
+
redirectUri: string;
|
|
5
|
+
}
|
|
6
|
+
export interface IFlowOAuthTokenResult {
|
|
7
|
+
accessToken: string;
|
|
8
|
+
refreshToken: string;
|
|
9
|
+
expiresAt: number;
|
|
10
|
+
apiKey: string;
|
|
11
|
+
email: string;
|
|
12
|
+
authMethod: 'oauth';
|
|
13
|
+
}
|
|
14
|
+
export declare function authorizeIFlowOAuth(port: number): Promise<IFlowOAuthAuthorization>;
|
|
15
|
+
export declare function exchangeOAuthCode(code: string, redirectUri: string): Promise<IFlowOAuthTokenResult>;
|
|
16
|
+
export declare function refreshOAuthToken(refreshToken: string): Promise<IFlowOAuthTokenResult>;
|
|
17
|
+
export declare function fetchUserInfo(accessToken: string): Promise<{
|
|
18
|
+
apiKey: string;
|
|
19
|
+
email: string;
|
|
20
|
+
}>;
|