@userdaoo/iflow-api-bridge 0.1.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 ADDED
@@ -0,0 +1,195 @@
1
+ # iFlow API Bridge
2
+
3
+ 将 iFlow(心流)CLI 的无限 LLM 服务暴露为 OpenAI 兼容的 API,使 Claude Code、OpenCode 等 Agent 可以直接使用。
4
+
5
+ ## 特性
6
+
7
+ - 🚀 **OpenAI API 兼容**:支持 `OPENAI_BASE_URL` 环境变量配置
8
+ - 🔄 **流式输出**:完整的 SSE 流式响应支持
9
+ - 🔌 **零配置**:自动检测和启动 iFlow 进程
10
+ - 🌐 **CORS 支持**:开箱即用的跨域支持
11
+ - 🔐 **可选认证**:支持 API Key 认证
12
+ - 📦 **无状态**:不存储会话状态,每次请求独立处理
13
+
14
+ ## 安装
15
+
16
+ ```bash
17
+ npm install -g @iflow-ai/iflow-api-bridge
18
+ ```
19
+
20
+ ## 快速开始
21
+
22
+ ### 1. 启动服务
23
+
24
+ ```bash
25
+ # 使用默认配置(端口 8080)
26
+ iflow-api-server
27
+
28
+ # 自定义端口
29
+ iflow-api-server --port 3000
30
+
31
+ # 指定模型(用于API标识,需在iFlow中预先配置)
32
+ iflow-api-server --model claude
33
+
34
+ # 启用 API Key 认证
35
+ iflow-api-server --api-key sk-your-secret-key
36
+ ```
37
+
38
+ ### 2. 在其他 Agent 中配置
39
+
40
+ ```bash
41
+ # 设置环境变量
42
+ export OPENAI_BASE_URL=http://localhost:8080/v1
43
+ export OPENAI_API_KEY=sk-anything # 如果没有启用认证,可以填任意值
44
+
45
+ # 启动 Claude Code
46
+ claude
47
+
48
+ # 或使用 OpenCode
49
+ opencode
50
+ ```
51
+
52
+ ## API 端点
53
+
54
+ ### 聊天完成
55
+
56
+ ```bash
57
+ curl http://localhost:8080/v1/chat/completions \
58
+ -H "Content-Type: application/json" \
59
+ -H "Authorization: Bearer sk-anything" \
60
+ -d '{
61
+ "model": "iflow-default",
62
+ "messages": [{"role": "user", "content": "Hello!"}],
63
+ "stream": false
64
+ }'
65
+ ```
66
+
67
+ ### 流式响应
68
+
69
+ ```bash
70
+ curl http://localhost:8080/v1/chat/completions \
71
+ -H "Content-Type: application/json" \
72
+ -H "Authorization: Bearer sk-anything" \
73
+ -d '{
74
+ "model": "iflow-default",
75
+ "messages": [{"role": "user", "content": "讲个故事"}],
76
+ "stream": true
77
+ }'
78
+ ```
79
+
80
+ ### 模型列表
81
+
82
+ ```bash
83
+ curl http://localhost:8080/v1/models
84
+ ```
85
+
86
+ ### 健康检查
87
+
88
+ ```bash
89
+ curl http://localhost:8080/health
90
+ ```
91
+
92
+ ## CLI 选项
93
+
94
+ ```
95
+ 选项:
96
+ -p, --port <port> 服务端口 (默认: 8080)
97
+ -h, --host <host> 服务主机 (默认: 0.0.0.0)
98
+ --no-cors 禁用 CORS
99
+ -k, --api-key <key> API Key 认证
100
+ -m, --model <model> 指定使用的模型 (如 claude, gpt-4)
101
+ -c, --config <path> 配置文件路径
102
+ --log-level <level> 日志级别 (DEBUG|INFO|WARN|ERROR) (默认: INFO)
103
+ -V, --version 显示版本号
104
+ --help 显示帮助信息
105
+ ```
106
+
107
+ ## 配置文件
108
+
109
+ 创建 `iflow-api.config.json`:
110
+
111
+ ```json
112
+ {
113
+ "port": 8080,
114
+ "host": "0.0.0.0",
115
+ "cors": true,
116
+ "apiKey": "sk-your-secret-key",
117
+ "model": "claude",
118
+ "logLevel": "INFO"
119
+ }
120
+ ```
121
+
122
+ 配置文件优先级(从高到低):
123
+ 1. CLI 参数
124
+ 2. 环境变量
125
+ 3. 配置文件
126
+ 4. 默认值
127
+
128
+ ## 环境变量
129
+
130
+ | 变量名 | 说明 | 默认值 |
131
+ |--------|------|--------|
132
+ | `IFLOW_API_PORT` | 服务端口 | `8080` |
133
+ | `IFLOW_API_HOST` | 服务主机 | `0.0.0.0` |
134
+ | `IFLOW_API_KEY` | API Key | - |
135
+ | `IFLOW_API_MODEL` | 指定模型名称 | - |
136
+ | `IFLOW_API_LOG_LEVEL` | 日志级别 | `INFO` |
137
+ | `IFLOW_API_CORS` | 启用 CORS | `true` |
138
+
139
+ ## 模型配置
140
+
141
+ **注意**:`--model` 参数(或 `IFLOW_API_MODEL` 环境变量)主要用于 API 响应标识,实际的模型选择需要在 iFlow CLI 中配置:
142
+
143
+ 1. **启动桥接服务时指定模型名称**(用于 API 响应):
144
+ ```bash
145
+ iflow-api-server --model claude-3-opus
146
+ ```
147
+
148
+ 2. **在 iFlow CLI 中配置实际模型**:
149
+ - 运行 `iflow` 进入交互界面
150
+ - 使用 `/model` 或相关命令切换模型
151
+ - 或使用 iFlow 的配置文件指定默认模型
152
+
153
+ 3. **客户端请求时指定模型**:
154
+ ```bash
155
+ curl http://localhost:8080/v1/chat/completions \
156
+ -H "Content-Type: application/json" \
157
+ -d '{
158
+ "model": "claude-3-opus",
159
+ "messages": [{"role": "user", "content": "Hello!"}]
160
+ }'
161
+ ```
162
+
163
+ 桥接服务会将模型信息传递给 iFlow,但实际使用的模型取决于 iFlow 的配置。
164
+
165
+ ## 与 Claude Code 集成
166
+
167
+ 1. 启动 iflow-api-server:
168
+ ```bash
169
+ iflow-api-server --port 8080
170
+ ```
171
+
172
+ 2. 配置 Claude Code:
173
+ ```bash
174
+ export OPENAI_BASE_URL=http://localhost:8080/v1
175
+ export OPENAI_API_KEY=sk-iflow
176
+ ```
177
+
178
+ 3. 启动 Claude Code 并选择 OpenAI 模型:
179
+ ```bash
180
+ claude
181
+ # 在 Claude Code 中选择使用 OpenAI 模型
182
+ ```
183
+
184
+ ## 架构
185
+
186
+ ```
187
+ ┌─────────────┐ HTTP/OpenAI API ┌─────────────┐ WebSocket ┌─────────┐
188
+ │ Claude Code │ ─────────────────────────> │ iflow-api │ ──────────────────> │ iFlow │
189
+ │ OpenCode │ │ -server │ │ CLI │
190
+ └─────────────┘ └─────────────┘ └─────────┘
191
+ ```
192
+
193
+ ## 许可证
194
+
195
+ MIT
@@ -0,0 +1,59 @@
1
+ /**
2
+ * iFlow SDK 适配器(使用子进程模式)
3
+ * 封装与 iFlow CLI 的通信
4
+ */
5
+ export interface IFlowResponse {
6
+ content: string;
7
+ toolCalls?: Array<{
8
+ name: string;
9
+ status: string;
10
+ }>;
11
+ stopReason: 'end_turn' | 'max_tokens' | 'error';
12
+ }
13
+ export interface StreamChunk {
14
+ type: 'content' | 'tool_call' | 'done' | 'error';
15
+ content?: string;
16
+ toolName?: string;
17
+ toolStatus?: string;
18
+ error?: string;
19
+ }
20
+ export interface IFlowAdapterOptions {
21
+ model?: string;
22
+ apiKey?: string;
23
+ baseUrl?: string;
24
+ timeout?: number;
25
+ }
26
+ /**
27
+ * iFlow 适配器 - 使用子进程模式
28
+ */
29
+ export declare class IFlowAdapter {
30
+ private options;
31
+ private defaultTimeout;
32
+ constructor(options?: IFlowAdapterOptions);
33
+ /**
34
+ * 发送消息并获取完整响应(非流式)
35
+ */
36
+ sendMessage(prompt: string): Promise<IFlowResponse>;
37
+ /**
38
+ * 发送消息并获取流式响应
39
+ */
40
+ sendMessageStream(prompt: string): AsyncGenerator<StreamChunk>;
41
+ /**
42
+ * 解析 iFlow 输出,提取实际回复内容
43
+ */
44
+ private parseResponse;
45
+ /**
46
+ * 连接到 iFlow
47
+ */
48
+ connect(): Promise<void>;
49
+ /**
50
+ * 断开连接
51
+ */
52
+ disconnect(): void;
53
+ /**
54
+ * 检查是否已连接
55
+ */
56
+ isConnected(): boolean;
57
+ }
58
+ export default IFlowAdapter;
59
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IACH,UAAU,EAAE,UAAU,GAAG,YAAY,GAAG,OAAO,CAAC;CACjD;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,cAAc,CAAU;gBAEpB,OAAO,GAAE,mBAAwB;IAI7C;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAoDzD;;OAEG;IACI,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC,WAAW,CAAC;IA2ErE;;OAEG;IACH,OAAO,CAAC,aAAa;IAsBrB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B;;OAEG;IACH,UAAU,IAAI,IAAI;IAKlB;;OAEG;IACH,WAAW,IAAI,OAAO;CAIvB;AAED,eAAe,YAAY,CAAC"}
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ /**
3
+ * iFlow SDK 适配器(使用子进程模式)
4
+ * 封装与 iFlow CLI 的通信
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.IFlowAdapter = void 0;
8
+ const child_process_1 = require("child_process");
9
+ /**
10
+ * iFlow 适配器 - 使用子进程模式
11
+ */
12
+ class IFlowAdapter {
13
+ options;
14
+ defaultTimeout = 120000; // 2分钟默认超时
15
+ constructor(options = {}) {
16
+ this.options = options;
17
+ }
18
+ /**
19
+ * 发送消息并获取完整响应(非流式)
20
+ */
21
+ async sendMessage(prompt) {
22
+ console.log('[Adapter] 发送消息(非流式):', prompt.substring(0, 100));
23
+ return new Promise((resolve, reject) => {
24
+ const args = ['-p', prompt];
25
+ if (this.options.model) {
26
+ args.push('-m', this.options.model);
27
+ }
28
+ console.log('[Adapter] 启动 iflow:', args.join(' '));
29
+ const child = (0, child_process_1.spawn)('iflow', args, {
30
+ stdio: ['ignore', 'pipe', 'pipe'],
31
+ });
32
+ let stdout = '';
33
+ let stderr = '';
34
+ const timeout = setTimeout(() => {
35
+ child.kill('SIGTERM');
36
+ reject(new Error(`iFlow 响应超时 (${this.defaultTimeout}ms)`));
37
+ }, this.options.timeout || this.defaultTimeout);
38
+ child.stdout?.on('data', (data) => {
39
+ stdout += data.toString();
40
+ });
41
+ child.stderr?.on('data', (data) => {
42
+ stderr += data.toString();
43
+ });
44
+ child.on('error', (err) => {
45
+ clearTimeout(timeout);
46
+ reject(new Error(`启动 iFlow 失败: ${err.message}`));
47
+ });
48
+ child.on('exit', (code) => {
49
+ clearTimeout(timeout);
50
+ console.log('[Adapter] iFlow 退出,code:', code);
51
+ if (code !== 0 && code !== null) {
52
+ console.error('[Adapter] iFlow stderr:', stderr);
53
+ }
54
+ // 解析响应
55
+ const content = this.parseResponse(stdout);
56
+ resolve({
57
+ content,
58
+ stopReason: code === 0 ? 'end_turn' : 'error',
59
+ });
60
+ });
61
+ });
62
+ }
63
+ /**
64
+ * 发送消息并获取流式响应
65
+ */
66
+ async *sendMessageStream(prompt) {
67
+ console.log('[Adapter] 发送消息(流式):', prompt.substring(0, 100));
68
+ const args = ['-p', prompt];
69
+ if (this.options.model) {
70
+ args.push('-m', this.options.model);
71
+ }
72
+ console.log('[Adapter] 启动 iflow:', args.join(' '));
73
+ const child = (0, child_process_1.spawn)('iflow', args, {
74
+ stdio: ['ignore', 'pipe', 'pipe'],
75
+ });
76
+ let buffer = '';
77
+ let isDone = false;
78
+ const timeout = setTimeout(() => {
79
+ if (!isDone) {
80
+ child.kill('SIGTERM');
81
+ isDone = true;
82
+ console.error('[Adapter] 流式响应超时');
83
+ }
84
+ }, this.options.timeout || this.defaultTimeout);
85
+ child.stdout?.on('data', (data) => {
86
+ buffer += data.toString();
87
+ });
88
+ child.stderr?.on('data', (data) => {
89
+ const msg = data.toString();
90
+ console.log('[Adapter] iFlow stderr:', msg.trim());
91
+ });
92
+ // 模拟流式输出 - 逐字符发送
93
+ let lastSentIndex = 0;
94
+ while (!isDone) {
95
+ // 检查进程是否结束
96
+ if (child.exitCode !== null) {
97
+ isDone = true;
98
+ }
99
+ // 发送新内容
100
+ if (buffer.length > lastSentIndex) {
101
+ const newContent = buffer.slice(lastSentIndex);
102
+ lastSentIndex = buffer.length;
103
+ // 逐行或逐字符发送
104
+ const lines = newContent.split('\n');
105
+ for (const line of lines) {
106
+ if (line.trim()) {
107
+ yield {
108
+ type: 'content',
109
+ content: line + '\n',
110
+ };
111
+ }
112
+ }
113
+ }
114
+ if (!isDone) {
115
+ await new Promise((resolve) => setTimeout(resolve, 50));
116
+ }
117
+ }
118
+ clearTimeout(timeout);
119
+ // 发送剩余内容
120
+ if (buffer.length > lastSentIndex) {
121
+ yield {
122
+ type: 'content',
123
+ content: buffer.slice(lastSentIndex),
124
+ };
125
+ }
126
+ yield { type: 'done' };
127
+ }
128
+ /**
129
+ * 解析 iFlow 输出,提取实际回复内容
130
+ */
131
+ parseResponse(stdout) {
132
+ // 尝试提取 <Execution Info> 之前的内容作为回复
133
+ const executionInfoMatch = stdout.match(/<Execution Info>[\s\S]*$/);
134
+ if (executionInfoMatch) {
135
+ return stdout.substring(0, executionInfoMatch.index).trim();
136
+ }
137
+ // 如果没有 Execution Info,返回全部内容(去掉开头的警告)
138
+ const lines = stdout.split('\n');
139
+ const startIndex = lines.findIndex((line) => !line.includes('DeprecationWarning') &&
140
+ !line.includes('node:') &&
141
+ line.trim());
142
+ if (startIndex >= 0) {
143
+ return lines.slice(startIndex).join('\n').trim();
144
+ }
145
+ return stdout.trim();
146
+ }
147
+ /**
148
+ * 连接到 iFlow
149
+ */
150
+ async connect() {
151
+ // 子进程模式不需要持久连接
152
+ console.log('[Adapter] 子进程模式已就绪');
153
+ }
154
+ /**
155
+ * 断开连接
156
+ */
157
+ disconnect() {
158
+ // 子进程模式不需要断开连接
159
+ console.log('[Adapter] 子进程模式断开(无操作)');
160
+ }
161
+ /**
162
+ * 检查是否已连接
163
+ */
164
+ isConnected() {
165
+ // 子进程模式总是"已连接"
166
+ return true;
167
+ }
168
+ }
169
+ exports.IFlowAdapter = IFlowAdapter;
170
+ exports.default = IFlowAdapter;
171
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI 入口
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;GAEG"}
package/dist/cli.js ADDED
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * CLI 入口
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const server_js_1 = require("./server.js");
9
+ const config_js_1 = require("./config.js");
10
+ const program = new commander_1.Command();
11
+ program
12
+ .name('iflow-api-server')
13
+ .description('将 iFlow LLM 服务暴露为 OpenAI 兼容 API')
14
+ .version('0.1.0');
15
+ program
16
+ .option('-p, --port <port>', '服务端口', '8080')
17
+ .option('-h, --host <host>', '服务主机', '0.0.0.0')
18
+ .option('--no-cors', '禁用 CORS')
19
+ .option('-k, --api-key <key>', 'API Key 认证')
20
+ .option('-m, --model <model>', '指定使用的模型 (如 claude, gpt-4)', 'kimi-k2.5')
21
+ .option('-c, --config <path>', '配置文件路径')
22
+ .option('--log-level <level>', '日志级别 (DEBUG|INFO|WARN|ERROR)', 'INFO')
23
+ .action(async (options) => {
24
+ try {
25
+ // 加载配置
26
+ const fileConfig = (0, config_js_1.loadConfig)(options.config);
27
+ const envConfig = (0, config_js_1.loadEnvConfig)();
28
+ const cliConfig = {
29
+ port: options.port ? parseInt(options.port, 10) : undefined,
30
+ host: options.host,
31
+ cors: options.cors,
32
+ apiKey: options.apiKey,
33
+ model: options.model,
34
+ logLevel: options.logLevel,
35
+ };
36
+ // 合并配置
37
+ const config = (0, config_js_1.mergeConfig)(fileConfig, envConfig, cliConfig);
38
+ // 创建并启动服务器
39
+ const server = new server_js_1.IFlowAPIServer(config);
40
+ // 处理退出信号
41
+ const shutdown = async (signal) => {
42
+ console.log(`\n${signal} 收到,正在关闭服务器...`);
43
+ await server.stop();
44
+ process.exit(0);
45
+ };
46
+ process.on('SIGINT', () => shutdown('SIGINT'));
47
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
48
+ // 启动
49
+ await server.start();
50
+ }
51
+ catch (error) {
52
+ console.error('启动失败:', error);
53
+ process.exit(1);
54
+ }
55
+ });
56
+ program.parse();
57
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AAEA;;GAEG;;AAEH,yCAAoC;AACpC,2CAA6C;AAC7C,2CAAkF;AAElF,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,kBAAkB,CAAC;KACxB,WAAW,CAAC,iCAAiC,CAAC;KAC9C,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,MAAM,CAAC,mBAAmB,EAAE,MAAM,EAAE,MAAM,CAAC;KAC3C,MAAM,CAAC,mBAAmB,EAAE,MAAM,EAAE,SAAS,CAAC;KAC9C,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC;KAC9B,MAAM,CAAC,qBAAqB,EAAE,YAAY,CAAC;KAC3C,MAAM,CAAC,qBAAqB,EAAE,2BAA2B,EAAE,WAAW,CAAC;KACvE,MAAM,CAAC,qBAAqB,EAAE,QAAQ,CAAC;KACvC,MAAM,CAAC,qBAAqB,EAAE,8BAA8B,EAAE,MAAM,CAAC;KACrE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,OAAO;QACP,MAAM,UAAU,GAAG,IAAA,sBAAU,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,IAAA,yBAAa,GAAE,CAAC;QAClC,MAAM,SAAS,GAAoB;YACjC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;YAC3D,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC;QAEF,OAAO;QACP,MAAM,MAAM,GAAG,IAAA,uBAAW,EAAC,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAE7D,WAAW;QACX,MAAM,MAAM,GAAG,IAAI,0BAAc,CAAC,MAAM,CAAC,CAAC;QAE1C,SAAS;QACT,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;YACxC,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,gBAAgB,CAAC,CAAC;YACzC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC;QAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;QAEjD,KAAK;QACL,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 配置管理
3
+ */
4
+ export interface Config {
5
+ port: number;
6
+ host: string;
7
+ cors: boolean;
8
+ apiKey?: string;
9
+ model?: string;
10
+ logLevel: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
11
+ }
12
+ export declare const DEFAULT_CONFIG: Config;
13
+ /**
14
+ * 从文件加载配置
15
+ */
16
+ export declare function loadConfig(configPath?: string): Partial<Config>;
17
+ /**
18
+ * 从环境变量加载配置
19
+ */
20
+ export declare function loadEnvConfig(): Partial<Config>;
21
+ /**
22
+ * 合并配置
23
+ */
24
+ export declare function mergeConfig(fileConfig: Partial<Config>, envConfig: Partial<Config>, cliConfig: Partial<Config>): Config;
25
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAC/C;AAED,eAAO,MAAM,cAAc,EAAE,MAM5B,CAAC;AAEF;;GAEG;AACH,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsB/D;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CA+B/C;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,EAC3B,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,EAC1B,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,GACzB,MAAM,CAOR"}
package/dist/config.js ADDED
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ /**
3
+ * 配置管理
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DEFAULT_CONFIG = void 0;
7
+ exports.loadConfig = loadConfig;
8
+ exports.loadEnvConfig = loadEnvConfig;
9
+ exports.mergeConfig = mergeConfig;
10
+ const fs_1 = require("fs");
11
+ const path_1 = require("path");
12
+ exports.DEFAULT_CONFIG = {
13
+ port: 8080,
14
+ host: '0.0.0.0',
15
+ cors: true,
16
+ model: 'kimi-k2.5',
17
+ logLevel: 'INFO',
18
+ };
19
+ /**
20
+ * 从文件加载配置
21
+ */
22
+ function loadConfig(configPath) {
23
+ const paths = configPath
24
+ ? [configPath]
25
+ : [
26
+ './iflow-api.config.json',
27
+ './.iflow-api.json',
28
+ '~/.iflow-api/config.json',
29
+ ];
30
+ for (const path of paths) {
31
+ const fullPath = (0, path_1.resolve)(path.replace(/^~/, process.env.HOME || ''));
32
+ if ((0, fs_1.existsSync)(fullPath)) {
33
+ try {
34
+ const content = (0, fs_1.readFileSync)(fullPath, 'utf-8');
35
+ return JSON.parse(content);
36
+ }
37
+ catch (error) {
38
+ console.warn(`无法加载配置文件 ${path}:`, error);
39
+ }
40
+ }
41
+ }
42
+ return {};
43
+ }
44
+ /**
45
+ * 从环境变量加载配置
46
+ */
47
+ function loadEnvConfig() {
48
+ const config = {};
49
+ if (process.env.IFLOW_API_PORT) {
50
+ config.port = parseInt(process.env.IFLOW_API_PORT, 10);
51
+ }
52
+ if (process.env.IFLOW_API_HOST) {
53
+ config.host = process.env.IFLOW_API_HOST;
54
+ }
55
+ if (process.env.IFLOW_API_KEY) {
56
+ config.apiKey = process.env.IFLOW_API_KEY;
57
+ }
58
+ if (process.env.IFLOW_API_LOG_LEVEL) {
59
+ const level = process.env.IFLOW_API_LOG_LEVEL;
60
+ if (['DEBUG', 'INFO', 'WARN', 'ERROR'].includes(level)) {
61
+ config.logLevel = level;
62
+ }
63
+ }
64
+ if (process.env.IFLOW_API_CORS) {
65
+ config.cors = process.env.IFLOW_API_CORS === 'true';
66
+ }
67
+ if (process.env.IFLOW_API_MODEL) {
68
+ config.model = process.env.IFLOW_API_MODEL;
69
+ }
70
+ return config;
71
+ }
72
+ /**
73
+ * 合并配置
74
+ */
75
+ function mergeConfig(fileConfig, envConfig, cliConfig) {
76
+ return {
77
+ ...exports.DEFAULT_CONFIG,
78
+ ...fileConfig,
79
+ ...envConfig,
80
+ ...cliConfig,
81
+ };
82
+ }
83
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAyBH,gCAsBC;AAKD,sCA+BC;AAKD,kCAWC;AAjGD,2BAA8C;AAC9C,+BAA+B;AAWlB,QAAA,cAAc,GAAW;IACpC,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,WAAW;IAClB,QAAQ,EAAE,MAAM;CACjB,CAAC;AAEF;;GAEG;AACH,SAAgB,UAAU,CAAC,UAAmB;IAC5C,MAAM,KAAK,GAAG,UAAU;QACtB,CAAC,CAAC,CAAC,UAAU,CAAC;QACd,CAAC,CAAC;YACE,yBAAyB;YACzB,mBAAmB;YACnB,0BAA0B;SAC3B,CAAC;IAEN,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAA,cAAO,EAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;QACrE,IAAI,IAAA,eAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAChD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,YAAY,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,SAAgB,aAAa;IAC3B,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC3C,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC5C,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAyC,CAAC;QACpE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACvD,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,MAAM,CAAC;IACtD,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC;QAChC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC7C,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CACzB,UAA2B,EAC3B,SAA0B,EAC1B,SAA0B;IAE1B,OAAO;QACL,GAAG,sBAAc;QACjB,GAAG,UAAU;QACb,GAAG,SAAS;QACZ,GAAG,SAAS;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * iFlow API Bridge
3
+ * 将 iFlow LLM 服务暴露为 OpenAI 兼容 API
4
+ */
5
+ export { IFlowAdapter, type IFlowResponse, type StreamChunk } from './adapter.js';
6
+ export { IFlowAPIServer, type ServerOptions } from './server.js';
7
+ export { loadConfig, loadEnvConfig, mergeConfig, DEFAULT_CONFIG, type Config, } from './config.js';
8
+ export * from './openai/types.js';
9
+ export { generateId, getTimestamp, messagesToIFlowPrompt, createCompletionResponse, createStreamChunk, calculateUsage, formatSSE, SSE_DONE, AVAILABLE_MODELS, getDefaultModel, } from './openai/transformer.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EACL,UAAU,EACV,aAAa,EACb,WAAW,EACX,cAAc,EACd,KAAK,MAAM,GACZ,MAAM,aAAa,CAAC;AACrB,cAAc,mBAAmB,CAAC;AAClC,OAAO,EACL,UAAU,EACV,YAAY,EACZ,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,eAAe,GAChB,MAAM,yBAAyB,CAAC"}