@hung319/opencode-iflow-cli
Advanced tools
| /** | ||
| * Auto-update models from iFlow API | ||
| * Fetches available models from https://apis.iflow.cn/v1/models | ||
| */ | ||
| export interface IFlowModel { | ||
| id: string; | ||
| name: string; | ||
| context_window: number; | ||
| max_tokens: number; | ||
| modalities: { | ||
| input: string[]; | ||
| output: string[]; | ||
| }; | ||
| supports_thinking?: boolean; | ||
| variants?: Record<string, any>; | ||
| } | ||
| export interface IFlowModelsResponse { | ||
| data: IFlowModel[]; | ||
| last_updated: string; | ||
| } | ||
| /** | ||
| * Fetch models from iFlow API | ||
| * @param apiKey - API key or OAuth token | ||
| * @param authType - 'oauth' | 'apikey' | ||
| */ | ||
| export declare function fetchModelsFromAPI(apiKey: string, authType?: 'oauth' | 'apikey'): Promise<IFlowModel[] | null>; | ||
| /** | ||
| * Fetch models from web scraping (fallback) | ||
| * Note: This is a fallback method if API fails | ||
| */ | ||
| export declare function fetchModelsFromWeb(): Promise<IFlowModel[] | null>; | ||
| /** | ||
| * Transform iFlow models to OpenCode format | ||
| */ | ||
| export declare function transformModelsToOpenCode(models: IFlowModel[]): Record<string, any>; | ||
| /** | ||
| * Get cached models or fetch new ones | ||
| */ | ||
| export declare function getModels(apiKey: string | undefined, authType: 'oauth' | 'apikey' | undefined): Promise<Record<string, any>>; |
| /** | ||
| * Auto-update models from iFlow API | ||
| * Fetches available models from https://apis.iflow.cn/v1/models | ||
| */ | ||
| import * as logger from '../plugin/logger.js'; | ||
| /** | ||
| * Fetch models from iFlow API | ||
| * @param apiKey - API key or OAuth token | ||
| * @param authType - 'oauth' | 'apikey' | ||
| */ | ||
| export async function fetchModelsFromAPI(apiKey, authType = 'apikey') { | ||
| try { | ||
| const headers = { | ||
| 'Content-Type': 'application/json', | ||
| }; | ||
| if (authType === 'oauth') { | ||
| headers['Authorization'] = `Bearer ${apiKey}`; | ||
| } | ||
| else { | ||
| headers['Authorization'] = `Bearer ${apiKey}`; | ||
| } | ||
| const response = await fetch('https://apis.iflow.cn/v1/models', { | ||
| method: 'GET', | ||
| headers, | ||
| }); | ||
| if (!response.ok) { | ||
| logger.warn(`Failed to fetch models: ${response.status} ${response.statusText}`); | ||
| return null; | ||
| } | ||
| const data = await response.json(); | ||
| return data.data || null; | ||
| } | ||
| catch (error) { | ||
| logger.warn(`Error fetching models from API: ${error.message}`); | ||
| return null; | ||
| } | ||
| } | ||
| /** | ||
| * Fetch models from web scraping (fallback) | ||
| * Note: This is a fallback method if API fails | ||
| */ | ||
| export async function fetchModelsFromWeb() { | ||
| try { | ||
| const response = await fetch('https://platform.iflow.cn/en/models', { | ||
| method: 'GET', | ||
| headers: { | ||
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', | ||
| }, | ||
| }); | ||
| if (!response.ok) { | ||
| return null; | ||
| } | ||
| const html = await response.text(); | ||
| // Parse models from HTML (basic implementation) | ||
| // In production, this would use a proper HTML parser | ||
| // Try to extract model data from JSON-LD or script tags | ||
| const scriptMatch = html.match(/window\.__MODELS__\s*=\s*(\[.*?\]);/s); | ||
| if (scriptMatch && scriptMatch[1]) { | ||
| try { | ||
| const parsed = JSON.parse(scriptMatch[1]); | ||
| return parsed.map((m) => ({ | ||
| id: m.id, | ||
| name: m.name, | ||
| context_window: m.context_window || 128000, | ||
| max_tokens: m.max_tokens || 32000, | ||
| modalities: m.modalities || { input: ['text'], output: ['text'] }, | ||
| supports_thinking: m.supports_thinking || false, | ||
| })); | ||
| } | ||
| catch { | ||
| // Fall through to default | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| catch (error) { | ||
| logger.warn(`Error fetching models from web: ${error.message}`); | ||
| return null; | ||
| } | ||
| } | ||
| /** | ||
| * Transform iFlow models to OpenCode format | ||
| */ | ||
| export function transformModelsToOpenCode(models) { | ||
| const result = {}; | ||
| for (const model of models) { | ||
| result[model.id] = { | ||
| name: model.name, | ||
| limit: { | ||
| context: model.context_window, | ||
| output: model.max_tokens, | ||
| }, | ||
| modalities: model.modalities, | ||
| ...(model.variants && { variants: model.variants }), | ||
| }; | ||
| } | ||
| return result; | ||
| } | ||
| /** | ||
| * Get cached models or fetch new ones | ||
| */ | ||
| export async function getModels(apiKey, authType) { | ||
| // Try to fetch from API if credentials available | ||
| if (apiKey && authType) { | ||
| const apiModels = await fetchModelsFromAPI(apiKey, authType); | ||
| if (apiModels) { | ||
| return transformModelsToOpenCode(apiModels); | ||
| } | ||
| } | ||
| // Fallback to web scraping | ||
| const webModels = await fetchModelsFromWeb(); | ||
| if (webModels) { | ||
| return transformModelsToOpenCode(webModels); | ||
| } | ||
| // Final fallback: use default models | ||
| return {}; | ||
| } |
+1
-1
@@ -1,2 +0,2 @@ | ||
| export declare const IFLOW_PROVIDER_ID = "iflow-oauth"; | ||
| export declare const IFLOW_PROVIDER_ID = "iflow"; | ||
| export declare const createIFlowPlugin: (id: string) => ({ client, directory }: any) => Promise<{ | ||
@@ -3,0 +3,0 @@ config: (config: any) => Promise<void>; |
+32
-2
@@ -8,2 +8,3 @@ import { loadConfig } from './plugin/config'; | ||
| import { validateApiKey } from './iflow/apikey'; | ||
| import { getModels } from './iflow/models'; | ||
| import { startOAuthServer } from './plugin/server'; | ||
@@ -13,3 +14,3 @@ import { promptAddAnotherAccount, promptLoginMode, promptApiKey, promptEmail, promptOAuthCallback } from './plugin/cli'; | ||
| import * as logger from './plugin/logger'; | ||
| export const IFLOW_PROVIDER_ID = 'iflow-oauth'; | ||
| export const IFLOW_PROVIDER_ID = 'iflow'; | ||
| const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); | ||
@@ -161,3 +162,32 @@ const isNetworkError = (e) => e instanceof Error && /econnreset|etimedout|enotfound|network|fetch failed/i.test(e.message); | ||
| config.provider[id] = config.provider[id] || {}; | ||
| config.provider[id].models = { ...DEFAULT_MODELS, ...(config.provider[id].models || {}) }; | ||
| // Try to fetch models from API | ||
| let fetchedModels = {}; | ||
| try { | ||
| const am = await AccountManager.loadFromDisk(config.account_selection_strategy); | ||
| const accounts = am.getAccounts(); | ||
| if (accounts.length > 0) { | ||
| // Use first available account to fetch models | ||
| const firstAccount = accounts[0]; | ||
| if (firstAccount) { | ||
| const authType = firstAccount.authMethod === 'oauth' ? 'oauth' : 'apikey'; | ||
| const token = firstAccount.authMethod === 'oauth' | ||
| ? firstAccount.accessToken | ||
| : firstAccount.apiKey; | ||
| if (token) { | ||
| logger.log('Fetching models from iFlow API...'); | ||
| fetchedModels = await getModels(token, authType); | ||
| logger.log(`Fetched ${Object.keys(fetchedModels).length} models from API`); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| catch (error) { | ||
| logger.warn(`Failed to fetch models from API: ${error.message}`); | ||
| } | ||
| // Merge: fetched models > default models > existing config | ||
| config.provider[id].models = { | ||
| ...DEFAULT_MODELS, | ||
| ...fetchedModels, | ||
| ...(config.provider[id].models || {}) | ||
| }; | ||
| }, | ||
@@ -164,0 +194,0 @@ auth: { |
+1
-1
| { | ||
| "name": "@hung319/opencode-iflow-cli", | ||
| "version": "4.1.0", | ||
| "version": "5.0.0", | ||
| "description": "OpenCode plugin for iFlow providing access to Qwen, DeepSeek, Kimi, GLM, and iFlow ROME models with auto-config and headless OAuth support", | ||
@@ -5,0 +5,0 @@ "type": "module", |
+2
-1
@@ -11,2 +11,3 @@ # OpenCode iFlow CLI Plugin | ||
| - **Auto-update models**: Automatically fetches latest models from iFlow API every time OpenCode runs | ||
| - **Auto-configuration**: Models are automatically configured, no manual setup needed. | ||
@@ -34,3 +35,3 @@ - **Dual authentication**: OAuth 2.0 (PKCE) and API Key support. | ||
| Then select **"iflow-oauth"** from the provider list when logging in (this is the enhanced iFlow with OAuth support). | ||
| Then select **"iflow"** from the provider list when logging in. | ||
@@ -37,0 +38,0 @@ That's it! Models are automatically configured. No manual provider configuration needed. |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
107793
6.33%38
5.56%2580
7.77%191
0.53%10
25%