Skip to content

Commit 5d7813d

Browse files
authored
Merge pull request #126 from MiniMax-AI/feat/proxy-support
feat: add HTTP/HTTPS proxy support via undici ProxyAgent
2 parents 10507df + 64a4146 commit 5d7813d

8 files changed

Lines changed: 45 additions & 7 deletions

File tree

build.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ await Bun.build({
1313
naming: 'mmx.mjs',
1414
target: 'node',
1515
minify: !DEV_BUILD,
16+
external: ['undici'],
1617
define: { 'process.env.CLI_VERSION': JSON.stringify(VERSION) },
1718
});
1819

bun.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
"dependencies": {
3535
"@clack/prompts": "^0.7.0",
3636
"bun-plugin-dts": "^0.4.0",
37-
"es-toolkit": "^1.46.1"
37+
"es-toolkit": "^1.46.1",
38+
"undici": "^6.21.1"
3839
},
3940
"devDependencies": {
4041
"@eslint/js": "^9.0.0",

src/commands/config/set.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { readConfigFile, writeConfigFile } from '../../config/loader';
66
import type { Config } from '../../config/schema';
77
import type { GlobalFlags } from '../../types/flags';
88

9-
const VALID_KEYS = ['region', 'base_url', 'output', 'timeout', 'api_key', 'default_text_model', 'default_speech_model', 'default_video_model', 'default_music_model'];
9+
const VALID_KEYS = ['region', 'base_url', 'output', 'timeout', 'api_key', 'proxy', 'default_text_model', 'default_speech_model', 'default_video_model', 'default_music_model'];
1010

1111
// Allow hyphen-style keys (e.g. default-text-model → default_text_model)
1212
const KEY_ALIASES: Record<string, string> = {
@@ -21,12 +21,13 @@ export default defineCommand({
2121
description: 'Set a config value',
2222
usage: 'mmx config set --key <key> --value <value>',
2323
options: [
24-
{ flag: '--key <key>', description: 'Config key (region, base_url, output, timeout, api_key, default_text_model, default_speech_model, default_video_model, default_music_model)' },
24+
{ flag: '--key <key>', description: 'Config key (region, base_url, output, timeout, api_key, proxy, default_text_model, default_speech_model, default_video_model, default_music_model)' },
2525
{ flag: '--value <value>', description: 'Value to set' },
2626
],
2727
examples: [
2828
'mmx config set --key output --value json',
2929
'mmx config set --key timeout --value 600',
30+
'mmx config set --key proxy --value http://127.0.0.1:7890',
3031
'mmx config set --key base_url --value https://api-uw.minimax.io',
3132
],
3233
async run(config: Config, flags: GlobalFlags) {
@@ -67,6 +68,20 @@ export default defineCommand({
6768
);
6869
}
6970

71+
if (resolvedKey === 'base_url' && !value.startsWith('http')) {
72+
throw new CLIError(
73+
`Invalid base_url "${value}". Must start with http.`,
74+
ExitCode.USAGE,
75+
);
76+
}
77+
78+
if (resolvedKey === 'proxy' && !value.startsWith('http')) {
79+
throw new CLIError(
80+
`Invalid proxy "${value}". Must be a URL starting with http (e.g. http://127.0.0.1:7890).`,
81+
ExitCode.USAGE,
82+
);
83+
}
84+
7085
if (resolvedKey === 'timeout') {
7186
const num = Number(value);
7287
if (isNaN(num) || num <= 0) {

src/commands/config/show.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export default defineCommand({
3636
if (file.default_speech_model) result.default_speech_model = file.default_speech_model;
3737
if (file.default_video_model) result.default_video_model = file.default_video_model;
3838
if (file.default_music_model) result.default_music_model = file.default_music_model;
39+
if (file.proxy) result.proxy = file.proxy;
3940

4041
console.log(formatOutput(result, format));
4142
},

src/config/schema.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface ConfigFile {
1616
base_url?: string;
1717
output?: 'text' | 'json';
1818
timeout?: number;
19+
proxy?: string;
1920
default_text_model?: string;
2021
default_speech_model?: string;
2122
default_video_model?: string;
@@ -35,6 +36,7 @@ export function parseConfigFile(raw: unknown): ConfigFile {
3536
if (typeof obj.base_url === 'string' && obj.base_url.startsWith('http')) out.base_url = obj.base_url;
3637
if (typeof obj.output === 'string' && VALID_OUTPUTS.has(obj.output)) out.output = obj.output as ConfigFile['output'];
3738
if (typeof obj.timeout === 'number' && obj.timeout > 0) out.timeout = obj.timeout;
39+
if (typeof obj.proxy === 'string' && obj.proxy.startsWith('http')) out.proxy = obj.proxy;
3840
if (typeof obj.default_text_model === 'string' && obj.default_text_model.length > 0) out.default_text_model = obj.default_text_model;
3941
if (typeof obj.default_speech_model === 'string' && obj.default_speech_model.length > 0) out.default_speech_model = obj.default_speech_model;
4042
if (typeof obj.default_video_model === 'string' && obj.default_video_model.length > 0) out.default_video_model = obj.default_video_model;

src/errors/handler.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ export function handleError(err: unknown): never {
4040
const networkErr = new CLIError(
4141
"Network request failed.",
4242
ExitCode.NETWORK,
43-
"Check your network connection and proxy settings. Also verify MINIMAX_BASE_URL is a valid URL.",
43+
"Check your network connection.\n" +
44+
"To use a proxy: set HTTPS_PROXY env var, or run: mmx config set --key proxy --value http://HOST:PORT",
4445
);
4546
return handleError(networkErr);
4647
}
@@ -63,10 +64,13 @@ export function handleError(err: unknown): never {
6364
msg.includes("eai_AGAIN");
6465

6566
if (isNetworkError) {
66-
let hint = "Check your network connection and proxy settings.";
67+
let hint =
68+
"Check your network connection.\n" +
69+
"To use a proxy: set HTTPS_PROXY env var, or run: mmx config set --key proxy --value http://HOST:PORT";
6770
if (msg.includes("proxy")) {
6871
hint =
69-
"Proxy error — check HTTP_PROXY / HTTPS_PROXY environment variables and proxy authentication.";
72+
"Proxy connection failed — verify your proxy URL and authentication.\n" +
73+
"Check: HTTPS_PROXY / HTTP_PROXY env vars, or mmx config show for configured proxy.";
7074
}
7175
const networkErr = new CLIError(
7276
"Network request failed.",

src/main.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { checkForUpdate, getPendingUpdateNotification } from './update/checker';
99
import { loadCredentials } from './auth/credentials';
1010
import { ensureApiKey } from './auth/setup';
1111
import { CLI_VERSION } from './version';
12+
import { ProxyAgent, setGlobalDispatcher } from 'undici';
1213

1314
// Handle Ctrl+C gracefully
1415
process.on('SIGINT', () => {
@@ -42,9 +43,19 @@ async function main() {
4243

4344
const commandPath = scanCommandPath(argv, GLOBAL_OPTIONS);
4445

46+
// Proxy: env vars take precedence over config file
47+
const rawConfig = readConfigFile();
48+
const proxyUrl = process.env.HTTPS_PROXY || process.env.https_proxy
49+
|| process.env.HTTP_PROXY || process.env.http_proxy
50+
|| process.env.ALL_PROXY || process.env.all_proxy
51+
|| rawConfig.proxy;
52+
if (proxyUrl) {
53+
setGlobalDispatcher(new ProxyAgent(proxyUrl));
54+
}
55+
4556
if (argv.includes('--help') || argv.includes('-h')) {
4657
const ri = argv.indexOf('--region');
47-
const region = ((ri >= 0 && argv[ri + 1]) || process.env.MINIMAX_REGION || readConfigFile().region || 'global') as Region;
58+
const region = ((ri >= 0 && argv[ri + 1]) || process.env.MINIMAX_REGION || rawConfig.region || 'global') as Region;
4859
registry.printHelp(commandPath, process.stderr, region);
4960
process.exit(0);
5061
}

0 commit comments

Comments
 (0)