Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/converters/register-converters.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ClaudeConverter } from './strategies/ClaudeConverter.js';
import { GeminiConverter } from './strategies/GeminiConverter.js';
import { CodexConverter } from './strategies/CodexConverter.js';
import { GrokConverter } from './strategies/GrokConverter.js';
import { SuperGrokConverter } from './strategies/SuperGrokConverter.js';

/**
* 注册所有转换器到工厂
Expand All @@ -23,7 +24,8 @@ export function registerAllConverters() {
ConverterFactory.registerConverter(MODEL_PROTOCOL_PREFIX.GEMINI, GeminiConverter);
ConverterFactory.registerConverter(MODEL_PROTOCOL_PREFIX.CODEX, CodexConverter);
ConverterFactory.registerConverter(MODEL_PROTOCOL_PREFIX.GROK, GrokConverter);
ConverterFactory.registerConverter(MODEL_PROTOCOL_PREFIX.SUPERGROK, SuperGrokConverter);
}

// 自动注册所有转换器
registerAllConverters();
registerAllConverters();
1 change: 1 addition & 0 deletions src/converters/strategies/SuperGrokConverter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { GrokConverter as SuperGrokConverter } from './GrokConverter.js';
51 changes: 50 additions & 1 deletion src/providers/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { IFlowApiService } from './openai/iflow-core.js';
import { CodexApiService } from './openai/codex-core.js';
import { ForwardApiService } from './forward/forward-core.js';
import { GrokApiService } from './grok/grok-core.js';
import { SuperGrokApiService } from './grok/supergrok-core.js';
import { MODEL_PROVIDER } from '../utils/common.js';
import logger from '../utils/logger.js';

Expand Down Expand Up @@ -688,6 +689,54 @@ export class GrokApiServiceAdapter extends ApiServiceAdapter {
}
}

// SuperGrok API 服务适配器
export class SuperGrokApiServiceAdapter extends ApiServiceAdapter {
constructor(config) {
super();
this.superGrokApiService = new SuperGrokApiService(config);
}

async generateContent(model, requestBody) {
if (!this.superGrokApiService.isInitialized) {
await this.superGrokApiService.initialize();
}
return this.superGrokApiService.generateContent(model, requestBody);
}

async *generateContentStream(model, requestBody) {
if (!this.superGrokApiService.isInitialized) {
await this.superGrokApiService.initialize();
}
yield* this.superGrokApiService.generateContentStream(model, requestBody);
}

async listModels() {
if (!this.superGrokApiService.isInitialized) {
await this.superGrokApiService.initialize();
}
return this.superGrokApiService.listModels();
}

async refreshToken() {
return this.superGrokApiService.refreshToken();
}

async forceRefreshToken() {
return this.superGrokApiService.refreshToken();
}

isExpiryDateNear() {
return this.superGrokApiService.isExpiryDateNear();
}

async getUsageLimits() {
if (!this.superGrokApiService.isInitialized) {
await this.superGrokApiService.initialize();
}
return this.superGrokApiService.getUsageLimits();
}
}

// 注册所有内置适配器
registerAdapter(MODEL_PROVIDER.OPENAI_CUSTOM, OpenAIApiServiceAdapter);
registerAdapter(MODEL_PROVIDER.OPENAI_CUSTOM_RESPONSES, OpenAIResponsesApiServiceAdapter);
Expand All @@ -699,6 +748,7 @@ registerAdapter(MODEL_PROVIDER.QWEN_API, QwenApiServiceAdapter);
// registerAdapter(MODEL_PROVIDER.IFLOW_API, IFlowApiServiceAdapter);
registerAdapter(MODEL_PROVIDER.CODEX_API, CodexApiServiceAdapter);
registerAdapter(MODEL_PROVIDER.GROK_CUSTOM, GrokApiServiceAdapter);
registerAdapter(MODEL_PROVIDER.SUPERGROK_CUSTOM, SuperGrokApiServiceAdapter);
// registerAdapter(MODEL_PROVIDER.FORWARD_API, ForwardApiServiceAdapter);

// 用于存储服务适配器单例的映射
Expand All @@ -721,4 +771,3 @@ export function getServiceAdapter(config) {
}
return serviceInstances[providerKey];
}

11 changes: 10 additions & 1 deletion src/providers/grok/grok-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ const CORE_MODEL_MAPPING = {
'grok-4.1-fast': { name: 'grok-4-1-thinking-1129', mode: 'MODEL_MODE_FAST' },
'grok-4.1-expert': { name: 'grok-4-1-thinking-1129', mode: 'MODEL_MODE_EXPERT' },
'grok-4.1-thinking': { name: 'grok-4-1-thinking-1129', mode: 'MODEL_MODE_GROK_4_1_THINKING' },
'grok-4.20-beta': { name: 'grok-420', mode: 'MODEL_MODE_GROK_420' },
'grok-4.20-beta': { name: 'grok-420', mode: 'MODEL_MODE_EXPERT', modeId: 'expert' },
'grok-4.20-fast': { name: 'grok-420', mode: 'MODEL_MODE_FAST', modeId: 'fast' },
'grok-imagine-1.0': { name: 'grok-3', mode: 'MODEL_MODE_FAST' },
'grok-imagine-1.0-edit': { name: 'imagine-image-edit', mode: 'MODEL_MODE_FAST' },
'grok-imagine-1.0-video': { name: 'grok-3', mode: 'MODEL_MODE_FAST' }
Expand Down Expand Up @@ -421,6 +422,14 @@ export class GrokApiService {
"returnImageBytes": false, "returnRawGrokInXaiRequest": false, "sendFinalMetadata": true, "temporary": true, "toolOverrides": toolOverrides,
};

if (mapping.name === 'grok-420') {
payload.responseMetadata = {};
delete payload.modelName;
delete payload.modelMode;
payload.modeId = mapping.modeId || 'expert';
payload.enable420 = true;
}

if (isMediaModel && !modelLower.includes('video')) {
payload.enable_nsfw = isNsfw;
if (requestBody.aspect_ratio || requestBody.aspectRatio) {
Expand Down
14 changes: 14 additions & 0 deletions src/providers/grok/supergrok-core.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { GrokApiService } from './grok-core.js';

export class SuperGrokApiService extends GrokApiService {
constructor(config) {
const mergedConfig = {
...config,
GROK_COOKIE_TOKEN: config.GROK_COOKIE_TOKEN || config.SUPERGROK_COOKIE_TOKEN,
GROK_CF_CLEARANCE: config.GROK_CF_CLEARANCE || config.SUPERGROK_CF_CLEARANCE,
GROK_USER_AGENT: config.GROK_USER_AGENT || config.SUPERGROK_USER_AGENT,
GROK_BASE_URL: config.GROK_BASE_URL || config.SUPERGROK_BASE_URL,
};
super(mergedConfig);
}
}
1 change: 1 addition & 0 deletions src/providers/grok/supergrok-strategy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { GrokStrategy as SuperGrokStrategy } from './grok-strategy.js';
19 changes: 19 additions & 0 deletions src/providers/provider-models.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,25 @@ export const PROVIDER_MODELS = {
'grok-4.1-expert',
'grok-4.1-thinking',
'grok-4.20-beta',
'grok-4.20-fast',
'grok-imagine-1.0',
'grok-imagine-1.0-edit',
'grok-imagine-1.0-video'
],
'supergrok-custom': [
'grok-3',
'grok-3-mini',
'grok-3-thinking',
'grok-4',
'grok-4-mini',
'grok-4-thinking',
'grok-4-heavy',
'grok-4.1-mini',
'grok-4.1-fast',
'grok-4.1-expert',
'grok-4.1-thinking',
'grok-4.20-beta',
'grok-4.20-fast',
'grok-imagine-1.0',
'grok-imagine-1.0-edit',
'grok-imagine-1.0-video'
Expand Down
3 changes: 2 additions & 1 deletion src/providers/provider-pool-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export class ProviderPoolManager {
'openai-codex-oauth': 'gpt-5-codex-mini',
'openaiResponses-custom': 'gpt-4o-mini',
'forward-api': 'gpt-4o-mini',
'grok-custom': 'grok-3',
'supergrok-custom': 'grok-3',
};

constructor(providerPools, options = {}) {
Expand Down Expand Up @@ -1911,4 +1913,3 @@ export class ProviderPoolManager {
}

}

3 changes: 2 additions & 1 deletion src/services/service-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,8 @@ export async function getProviderStatus(config, options = {}) {
'gemini-antigravity': 'ANTIGRAVITY_OAUTH_CREDS_FILE_PATH',
'openai-iflow': 'IFLOW_TOKEN_FILE_PATH',
'forward-api': 'FORWARD_BASE_URL',
'grok-custom': 'GROK_COOKIE_TOKEN'
'grok-custom': 'GROK_COOKIE_TOKEN',
'supergrok-custom': 'SUPERGROK_COOKIE_TOKEN'
};
let providerPoolsSlim = [];
let unhealthyProvideIdentifyList = [];
Expand Down
22 changes: 22 additions & 0 deletions src/services/usage-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export class UsageService {
[MODEL_PROVIDER.ANTIGRAVITY]: this.getAntigravityUsage.bind(this),
[MODEL_PROVIDER.CODEX_API]: this.getCodexUsage.bind(this),
[MODEL_PROVIDER.GROK_CUSTOM]: this.getGrokUsage.bind(this),
[MODEL_PROVIDER.SUPERGROK_CUSTOM]: this.getSuperGrokUsage.bind(this),
};
}

Expand Down Expand Up @@ -208,6 +209,27 @@ export class UsageService {
throw new Error(`Grok 服务实例不支持用量查询: ${providerKey}`);
}

/**
* 获取 SuperGrok 提供商的用量信息
* @param {string} [uuid] - 可选的提供商实例 UUID
* @returns {Promise<Object>} SuperGrok 用量信息
*/
async getSuperGrokUsage(uuid = null) {
const providerKey = uuid ? MODEL_PROVIDER.SUPERGROK_CUSTOM + uuid : MODEL_PROVIDER.SUPERGROK_CUSTOM;
const adapter = serviceInstances[providerKey];

if (!adapter) {
throw new Error(`SuperGrok 服务实例未找到: ${providerKey}`);
}

if (typeof adapter.getUsageLimits === 'function') {
const rawUsage = await adapter.getUsageLimits();
return formatGrokUsage(rawUsage);
}

throw new Error(`SuperGrok 服务实例不支持用量查询: ${providerKey}`);
}

/**
* 获取支持用量查询的提供商列表

Expand Down
12 changes: 10 additions & 2 deletions src/ui-modules/usage-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { readUsageCache, writeUsageCache, readProviderUsageCache, updateProvider
import { PROVIDER_MAPPINGS } from '../utils/provider-utils.js';
import path from 'path';

const supportedProviders = ['claude-kiro-oauth', 'gemini-cli-oauth', 'gemini-antigravity', 'openai-codex-oauth', 'grok-custom'];
const supportedProviders = ['claude-kiro-oauth', 'gemini-cli-oauth', 'gemini-antigravity', 'openai-codex-oauth', 'grok-custom', 'supergrok-custom'];


/**
Expand Down Expand Up @@ -190,6 +190,14 @@ async function getAdapterUsage(adapter, providerType) {
}
throw new Error('This adapter does not support usage query');
}

if (providerType === 'supergrok-custom') {
if (typeof adapter.getUsageLimits === 'function') {
const rawUsage = await adapter.getUsageLimits();
return formatGrokUsage(rawUsage);
}
throw new Error('This adapter does not support usage query');
}

throw new Error(`Unsupported provider type: ${providerType}`);
}
Expand Down Expand Up @@ -353,4 +361,4 @@ export async function handleGetProviderUsage(req, res, currentConfig, providerPo
}));
return true;
}
}
}
2 changes: 2 additions & 0 deletions src/utils/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const MODEL_PROTOCOL_PREFIX = {
CODEX: 'codex',
FORWARD: 'forward',
GROK: 'grok',
SUPERGROK: 'supergrok',
}

export const MODEL_PROVIDER = {
Expand All @@ -73,6 +74,7 @@ export const MODEL_PROVIDER = {
CODEX_API: 'openai-codex-oauth',
FORWARD_API: 'forward-api',
GROK_CUSTOM: 'grok-custom',
SUPERGROK_CUSTOM: 'supergrok-custom',
AUTO: 'auto',
}

Expand Down
3 changes: 3 additions & 0 deletions src/utils/provider-strategies.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ResponsesAPIStrategy } from '../providers/openai/openai-responses-strat
import { CodexResponsesAPIStrategy } from '../providers/openai/codex-responses-strategy.js';
import { ForwardStrategy } from '../providers/forward/forward-strategy.js';
import { GrokStrategy } from '../providers/grok/grok-strategy.js';
import { SuperGrokStrategy } from '../providers/grok/supergrok-strategy.js';

/**
* Strategy factory that returns the appropriate strategy instance based on the provider protocol.
Expand All @@ -27,6 +28,8 @@ class ProviderStrategyFactory {
return new ForwardStrategy();
case MODEL_PROTOCOL_PREFIX.GROK:
return new GrokStrategy();
case MODEL_PROTOCOL_PREFIX.SUPERGROK:
return new SuperGrokStrategy();
default:
throw new Error(`Unsupported provider protocol: ${providerProtocol}`);
}
Expand Down
13 changes: 12 additions & 1 deletion src/utils/provider-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ export const PROVIDER_MAPPINGS = [
displayName: 'Grok Reverse',
needsProjectId: false,
urlKeys: ['GROK_BASE_URL', 'GROK_CF_CLEARANCE', 'GROK_USER_AGENT']
},
{
// SuperGrok Reverse 配置
dirName: 'supergrok',
patterns: ['configs/supergrok/', '/supergrok/'],
providerType: 'supergrok-custom',
credPathKey: 'SUPERGROK_COOKIE_TOKEN',
defaultCheckModel: 'grok-3',
displayName: 'SuperGrok Reverse',
needsProjectId: false,
urlKeys: ['SUPERGROK_BASE_URL', 'SUPERGROK_CF_CLEARANCE', 'SUPERGROK_USER_AGENT']
}
];

Expand Down Expand Up @@ -385,4 +396,4 @@ export function isPathLinked(relativePath, linkedPaths) {
return linkedPaths.has(relativePath) ||
linkedPaths.has('./' + relativePath) ||
linkedPaths.has(relativePath.replace(/^\.\//, ''));
}
}
2 changes: 2 additions & 0 deletions static/app/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ const translations = {
'dashboard.routing.nodeName.iflow': 'iFlow OAuth',
'dashboard.routing.nodeName.codex': 'OpenAI Codex OAuth',
'dashboard.routing.nodeName.grok': 'Grok Reverse',
'dashboard.routing.nodeName.supergrok': 'SuperGrok Reverse',
'dashboard.contact.title': '联系与赞助',
'dashboard.contact.wechat': '扫码进群,注明来意',
'dashboard.contact.wechatDesc': '添加微信获取更多技术支持和交流',
Expand Down Expand Up @@ -936,6 +937,7 @@ const translations = {
'dashboard.routing.nodeName.iflow': 'iFlow OAuth',
'dashboard.routing.nodeName.codex': 'OpenAI Codex OAuth',
'dashboard.routing.nodeName.grok': 'Grok Reverse',
'dashboard.routing.nodeName.supergrok': 'SuperGrok Reverse',
'dashboard.contact.title': 'Contact & Support',
'dashboard.contact.wechat': 'Scan to Join Group',
'dashboard.contact.wechatDesc': 'Add WeChat for more technical support and communication',
Expand Down
5 changes: 4 additions & 1 deletion static/app/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,7 @@ function getFieldOrder(provider) {
'openai-iflow': ['IFLOW_OAUTH_CREDS_FILE_PATH', 'IFLOW_BASE_URL'],
'openai-codex-oauth': ['CODEX_OAUTH_CREDS_FILE_PATH', 'CODEX_EMAIL', 'CODEX_BASE_URL'],
'grok-custom': ['GROK_COOKIE_TOKEN', 'GROK_CF_CLEARANCE', 'GROK_USER_AGENT', 'GROK_BASE_URL'],
'supergrok-custom': ['SUPERGROK_COOKIE_TOKEN', 'SUPERGROK_CF_CLEARANCE', 'SUPERGROK_USER_AGENT', 'SUPERGROK_BASE_URL'],
'forward-api': ['FORWARD_API_KEY', 'FORWARD_BASE_URL', 'FORWARD_HEADER_NAME', 'FORWARD_HEADER_VALUE_PREFIX']
};

Expand All @@ -713,6 +714,8 @@ function getFieldOrder(provider) {
providerType = 'openai-codex-oauth';
} else if (provider.GROK_COOKIE_TOKEN) {
providerType = 'grok-custom';
} else if (provider.SUPERGROK_COOKIE_TOKEN) {
providerType = 'supergrok-custom';
} else if (provider.FORWARD_API_KEY) {
providerType = 'forward-api';
}
Expand Down Expand Up @@ -1638,4 +1641,4 @@ window.performHealthCheck = performHealthCheck;
window.deleteUnhealthyProviders = deleteUnhealthyProviders;
window.refreshUnhealthyUuids = refreshUnhealthyUuids;
window.goToProviderPage = goToProviderPage;
window.refreshProviderUuid = refreshProviderUuid;
window.refreshProviderUuid = refreshProviderUuid;
8 changes: 5 additions & 3 deletions static/app/usage-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,8 @@ function getProviderDisplayName(providerType) {
'gemini-antigravity': 'Gemini Antigravity',
'openai-codex-oauth': 'Codex OAuth',
'openai-qwen-oauth': 'Qwen OAuth',
'grok-custom': 'Grok Reverse'
'grok-custom': 'Grok Reverse',
'supergrok-custom': 'SuperGrok Reverse'
};
return names[providerType] || providerType;
}
Expand All @@ -924,7 +925,8 @@ function getProviderIcon(providerType) {
'gemini-antigravity': 'fas fa-rocket',
'openai-codex-oauth': 'fas fa-terminal',
'openai-qwen-oauth': 'fas fa-code',
'grok-custom': 'fas fa-brain'
'grok-custom': 'fas fa-brain',
'supergrok-custom': 'fas fa-user-astronaut'
};
return icons[providerType] || 'fas fa-server';
}
Expand Down Expand Up @@ -996,4 +998,4 @@ function formatDate(dateStr) {
} catch (e) {
return dateStr;
}
}
}
Loading