diff --git a/open-sse/config/providerModels.js b/open-sse/config/providerModels.js index 07b0dbd..40a3207 100644 --- a/open-sse/config/providerModels.js +++ b/open-sse/config/providerModels.js @@ -45,13 +45,13 @@ export const PROVIDER_MODELS = { if: [ // iFlow AI { id: "qwen3-coder-plus", name: "Qwen3 Coder Plus" }, { id: "kimi-k2", name: "Kimi K2" }, - // { id: "kimi-k2-thinking", name: "Kimi K2 Thinking" }, - // { id: "kimi-k2.5", name: "Kimi K2.5" }, + { id: "kimi-k2-thinking", name: "Kimi K2 Thinking" }, + { id: "kimi-k2.5", name: "Kimi K2.5" }, { id: "deepseek-r1", name: "DeepSeek R1" }, - // { id: "deepseek-v3.2-chat", name: "DeepSeek V3.2 Chat" }, + { id: "deepseek-v3.2-chat", name: "DeepSeek V3.2 Chat" }, // { id: "deepseek-v3.2-reasoner", name: "DeepSeek V3.2 Reasoner" }, - // { id: "minimax-m2.1", name: "MiniMax M2.1" }, - // { id: "glm-4.7", name: "GLM 4.7" }, + { id: "minimax-m2.1", name: "MiniMax M2.1" }, + { id: "glm-4.7", name: "GLM 4.7" }, { id: "glm-4.6", name: "GLM 4.6" }, ], ag: [ // Antigravity - special case: models call different backends diff --git a/open-sse/executors/iflow.js b/open-sse/executors/iflow.js new file mode 100644 index 0000000..f18753b --- /dev/null +++ b/open-sse/executors/iflow.js @@ -0,0 +1,104 @@ +import crypto from "crypto"; +import { BaseExecutor } from "./base.js"; +import { PROVIDERS } from "../config/constants.js"; + +/** + * IFlowExecutor - Executor for iFlow API with HMAC-SHA256 signature + */ +export class IFlowExecutor extends BaseExecutor { + constructor() { + super("iflow", PROVIDERS.iflow); + } + + /** + * Generate UUID v4 + * @returns {string} UUID v4 string + */ + generateUUID() { + return crypto.randomUUID(); + } + + /** + * Create iFlow signature using HMAC-SHA256 + * @param {string} userAgent - User agent string + * @param {string} sessionID - Session ID + * @param {number} timestamp - Unix timestamp in milliseconds + * @param {string} apiKey - API key for signing + * @returns {string} Hex-encoded signature + */ + createIFlowSignature(userAgent, sessionID, timestamp, apiKey) { + if (!apiKey) return ""; + const payload = `${userAgent}:${sessionID}:${timestamp}`; + const hmac = crypto.createHmac("sha256", apiKey); + hmac.update(payload); + return hmac.digest("hex"); + } + + /** + * Build headers with iFlow-specific signature + * @param {object} credentials - Provider credentials + * @param {boolean} stream - Whether streaming is enabled + * @returns {object} Headers object + */ + buildHeaders(credentials, stream = true) { + // Generate session ID and timestamp + const sessionID = `session-${this.generateUUID()}`; + const timestamp = Date.now(); + + // Get user agent from config + const userAgent = this.config.headers["User-Agent"] || "iFlow-Cli"; + + // Get API key (prefer apiKey, fallback to accessToken) + const apiKey = credentials.apiKey || credentials.accessToken || ""; + + // Create signature + const signature = this.createIFlowSignature(userAgent, sessionID, timestamp, apiKey); + + // Build headers + const headers = { + "Content-Type": "application/json", + ...this.config.headers, + "session-id": sessionID, + "x-iflow-timestamp": timestamp.toString(), + "x-iflow-signature": signature + }; + + // Add authorization + if (credentials.apiKey) { + headers["Authorization"] = `Bearer ${credentials.apiKey}`; + } + + // Add streaming header + if (stream) { + headers["Accept"] = "text/event-stream"; + } + + return headers; + } + + /** + * Build URL for iFlow API + * @param {string} model - Model name + * @param {boolean} stream - Whether streaming is enabled + * @param {number} urlIndex - URL index for fallback + * @param {object} credentials - Provider credentials + * @returns {string} API URL + */ + buildUrl(model, stream, urlIndex = 0, credentials = null) { + return this.config.baseUrl; + } + + /** + * Transform request body (passthrough for iFlow) + * @param {string} model - Model name + * @param {object} body - Request body + * @param {boolean} stream - Whether streaming is enabled + * @param {object} credentials - Provider credentials + * @returns {object} Transformed body + */ + transformRequest(model, body, stream, credentials) { + return body; + } +} + +export default IFlowExecutor; diff --git a/open-sse/executors/index.js b/open-sse/executors/index.js index 08440bc..49a4c27 100644 --- a/open-sse/executors/index.js +++ b/open-sse/executors/index.js @@ -1,6 +1,7 @@ import { AntigravityExecutor } from "./antigravity.js"; import { GeminiCLIExecutor } from "./gemini-cli.js"; import { GithubExecutor } from "./github.js"; +import { IFlowExecutor } from "./iflow.js"; import { KiroExecutor } from "./kiro.js"; import { CodexExecutor } from "./codex.js"; import { CursorExecutor } from "./cursor.js"; @@ -10,6 +11,7 @@ const executors = { antigravity: new AntigravityExecutor(), "gemini-cli": new GeminiCLIExecutor(), github: new GithubExecutor(), + iflow: new IFlowExecutor(), kiro: new KiroExecutor(), codex: new CodexExecutor(), cursor: new CursorExecutor(), @@ -32,6 +34,7 @@ export { BaseExecutor } from "./base.js"; export { AntigravityExecutor } from "./antigravity.js"; export { GeminiCLIExecutor } from "./gemini-cli.js"; export { GithubExecutor } from "./github.js"; +export { IFlowExecutor } from "./iflow.js"; export { KiroExecutor } from "./kiro.js"; export { CodexExecutor } from "./codex.js"; export { CursorExecutor } from "./cursor.js";