fix minimax oauth failed and upgrade openclaw to 2.26 (#206)
This commit is contained in:
committed by
GitHub
Unverified
parent
f70d5b0c28
commit
0fb1a1a78d
@@ -1167,8 +1167,8 @@ function registerProviderHandlers(gatewayManager: GatewayManager): void {
|
||||
: 'openai-completions';
|
||||
|
||||
let baseUrl = provider.baseUrl || defaultBaseUrl;
|
||||
if ((provider.type === 'minimax-portal' || provider.type === 'minimax-portal-cn') && baseUrl && !baseUrl.endsWith('/anthropic')) {
|
||||
baseUrl = baseUrl.replace(/\/$/, '') + '/anthropic';
|
||||
if ((provider.type === 'minimax-portal' || provider.type === 'minimax-portal-cn') && baseUrl) {
|
||||
baseUrl = baseUrl.replace(/\/v1$/, '').replace(/\/anthropic$/, '').replace(/\/$/, '') + '/anthropic';
|
||||
}
|
||||
|
||||
// To ensure the OpenClaw Gateway's internal token refresher works,
|
||||
@@ -1180,10 +1180,27 @@ function registerProviderHandlers(gatewayManager: GatewayManager): void {
|
||||
setOpenClawDefaultModelWithOverride(targetProviderKey, undefined, {
|
||||
baseUrl,
|
||||
api,
|
||||
authHeader: targetProviderKey === 'minimax-portal' ? true : undefined,
|
||||
// Relies on OpenClaw Gateway native auth-profiles syncing
|
||||
apiKeyEnv: targetProviderKey === 'minimax-portal' ? 'minimax-oauth' : 'qwen-oauth',
|
||||
});
|
||||
|
||||
logger.info(`Configured openclaw.json for OAuth provider "${provider.type}"`);
|
||||
|
||||
// Also write models.json directly so pi-ai picks up the correct baseUrl and
|
||||
// authHeader immediately, without waiting for Gateway to sync openclaw.json.
|
||||
try {
|
||||
const defaultModelId = provider.model?.split('/').pop();
|
||||
updateAgentModelProvider(targetProviderKey, {
|
||||
baseUrl,
|
||||
api,
|
||||
authHeader: targetProviderKey === 'minimax-portal' ? true : undefined,
|
||||
apiKey: targetProviderKey === 'minimax-portal' ? 'minimax-oauth' : 'qwen-oauth',
|
||||
models: defaultModelId ? [{ id: defaultModelId, name: defaultModelId }] : [],
|
||||
});
|
||||
} catch (err) {
|
||||
logger.warn(`Failed to update models.json for OAuth provider "${targetProviderKey}":`, err);
|
||||
}
|
||||
}
|
||||
|
||||
// For custom/ollama providers, also update the per-agent models.json
|
||||
|
||||
@@ -131,7 +131,7 @@ class DeviceOAuthManager extends EventEmitter {
|
||||
expires: token.expires,
|
||||
// MiniMax returns a per-account resourceUrl as the API base URL
|
||||
resourceUrl: token.resourceUrl,
|
||||
// MiniMax uses Anthropic Messages API format
|
||||
// Revert back to anthropic-messages
|
||||
api: 'anthropic-messages',
|
||||
region,
|
||||
});
|
||||
@@ -217,17 +217,15 @@ class DeviceOAuthManager extends EventEmitter {
|
||||
// This mirrors what the OpenClaw plugin's configPatch does after CLI login.
|
||||
// The baseUrl comes from token.resourceUrl (per-account URL from the OAuth server)
|
||||
// or falls back to the provider's default public endpoint.
|
||||
// Note: MiniMax Anthropic-compatible API requires the /anthropic suffix.
|
||||
const defaultBaseUrl = providerType === 'minimax-portal'
|
||||
? 'https://api.minimax.io/anthropic'
|
||||
: (providerType === 'minimax-portal-cn' ? 'https://api.minimaxi.com/anthropic' : 'https://portal.qwen.ai/v1');
|
||||
|
||||
let baseUrl = token.resourceUrl || defaultBaseUrl;
|
||||
|
||||
// If MiniMax returned a resourceUrl (e.g. https://api.minimax.io) but no /anthropic suffix,
|
||||
// we must append it because we use the 'anthropic-messages' API mode
|
||||
if (providerType.startsWith('minimax-portal') && baseUrl && !baseUrl.endsWith('/anthropic')) {
|
||||
baseUrl = baseUrl.replace(/\/$/, '') + '/anthropic';
|
||||
// Ensure the base URL ends with /anthropic
|
||||
if (providerType.startsWith('minimax-portal') && baseUrl) {
|
||||
baseUrl = baseUrl.replace(/\/v1$/, '').replace(/\/anthropic$/, '').replace(/\/$/, '') + '/anthropic';
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -235,11 +233,10 @@ class DeviceOAuthManager extends EventEmitter {
|
||||
setOpenClawDefaultModelWithOverride(tokenProviderId, undefined, {
|
||||
baseUrl,
|
||||
api: token.api,
|
||||
// Tells OpenClaw's anthropic adapter to use `Authorization: Bearer` instead of `x-api-key`
|
||||
authHeader: providerType.startsWith('minimax-portal') ? true : undefined,
|
||||
// OAuth placeholder — tells Gateway to resolve credentials
|
||||
// from auth-profiles.json (type: 'oauth') instead of a static API key.
|
||||
// This matches what the OpenClaw plugin's configPatch writes:
|
||||
// minimax-portal → apiKey: 'minimax-oauth'
|
||||
// qwen-portal → apiKey: 'qwen-oauth'
|
||||
apiKeyEnv: tokenProviderId === 'minimax-portal' ? 'minimax-oauth' : 'qwen-oauth',
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@@ -153,6 +153,32 @@ export function saveOAuthTokenToOpenClaw(
|
||||
console.log(`Saved OAuth token for provider "${provider}" to OpenClaw auth-profiles (agents: ${agentIds.join(', ')})`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an OAuth token from OpenClaw's auth-profiles.json.
|
||||
* Useful when the Gateway does not natively inject the Authorization header.
|
||||
*
|
||||
* @param provider - Provider type (e.g., 'minimax-portal')
|
||||
* @param agentId - Optional single agent ID to read from, defaults to 'main'
|
||||
* @returns The OAuth token access string or null if not found
|
||||
*/
|
||||
export function getOAuthTokenFromOpenClaw(
|
||||
provider: string,
|
||||
agentId = 'main'
|
||||
): string | null {
|
||||
try {
|
||||
const store = readAuthProfiles(agentId);
|
||||
const profileId = `${provider}:default`;
|
||||
const profile = store.profiles[profileId];
|
||||
|
||||
if (profile && profile.type === 'oauth' && 'access' in profile) {
|
||||
return (profile as OAuthProfileEntry).access;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(`[getOAuthToken] Failed to read token for ${provider}:`, err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a provider API key to OpenClaw's auth-profiles.json
|
||||
* This writes the key in the format OpenClaw expects so the gateway
|
||||
@@ -278,7 +304,25 @@ export function removeProviderFromOpenClaw(provider: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Remove from openclaw.json
|
||||
// 2. Remove from models.json (per-agent model registry used by pi-ai directly)
|
||||
for (const agentId of agentIds) {
|
||||
const modelsPath = join(homedir(), '.openclaw', 'agents', agentId, 'agent', 'models.json');
|
||||
try {
|
||||
if (existsSync(modelsPath)) {
|
||||
const data = JSON.parse(readFileSync(modelsPath, 'utf-8')) as Record<string, unknown>;
|
||||
const providers = data.providers as Record<string, unknown> | undefined;
|
||||
if (providers && providers[provider]) {
|
||||
delete providers[provider];
|
||||
writeFileSync(modelsPath, JSON.stringify(data, null, 2), 'utf-8');
|
||||
console.log(`Removed models.json entry for provider "${provider}" (agent "${agentId}")`);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(`Failed to remove provider ${provider} from models.json (agent "${agentId}"):`, err);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Remove from openclaw.json
|
||||
const configPath = join(homedir(), '.openclaw', 'openclaw.json');
|
||||
try {
|
||||
if (existsSync(configPath)) {
|
||||
@@ -447,6 +491,7 @@ interface RuntimeProviderConfigOverride {
|
||||
api?: string;
|
||||
apiKeyEnv?: string;
|
||||
headers?: Record<string, string>;
|
||||
authHeader?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -573,6 +618,9 @@ export function setOpenClawDefaultModelWithOverride(
|
||||
if (override.headers && Object.keys(override.headers).length > 0) {
|
||||
nextProvider.headers = override.headers;
|
||||
}
|
||||
if (override.authHeader !== undefined) {
|
||||
nextProvider.authHeader = override.authHeader;
|
||||
}
|
||||
|
||||
providers[provider] = nextProvider;
|
||||
models.providers = providers;
|
||||
@@ -766,6 +814,8 @@ export function updateAgentModelProvider(
|
||||
api?: string;
|
||||
models?: Array<{ id: string; name: string }>;
|
||||
apiKey?: string;
|
||||
/** When true, pi-ai sends Authorization: Bearer instead of x-api-key */
|
||||
authHeader?: boolean;
|
||||
}
|
||||
): void {
|
||||
const agentIds = discoverAgentIds();
|
||||
@@ -804,6 +854,7 @@ export function updateAgentModelProvider(
|
||||
if (entry.api !== undefined) existing.api = entry.api;
|
||||
if (mergedModels.length > 0) existing.models = mergedModels;
|
||||
if (entry.apiKey !== undefined) existing.apiKey = entry.apiKey;
|
||||
if (entry.authHeader !== undefined) existing.authHeader = entry.authHeader;
|
||||
|
||||
providers[providerType] = existing;
|
||||
data.providers = providers;
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
"i18next": "^25.8.11",
|
||||
"jsdom": "^28.1.0",
|
||||
"lucide-react": "^0.563.0",
|
||||
"openclaw": "2026.2.24",
|
||||
"openclaw": "2026.2.26",
|
||||
"png2icons": "^2.0.1",
|
||||
"postcss": "^8.5.6",
|
||||
"react": "^19.2.4",
|
||||
@@ -107,4 +107,4 @@
|
||||
"zx": "^8.8.5"
|
||||
},
|
||||
"packageManager": "pnpm@10.29.2+sha512.bef43fa759d91fd2da4b319a5a0d13ef7a45bb985a3d7342058470f9d2051a3ba8674e629672654686ef9443ad13a82da2beb9eeb3e0221c87b8154fff9d74b8"
|
||||
}
|
||||
}
|
||||
1299
pnpm-lock.yaml
generated
1299
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user