feat(proxy): add adaptive local port selection for OpenAI-compatible profiles

This commit is contained in:
Tam Nhu Tran committed 2026-04-23 14:47:01 -04:00
1 parent 5ddf130223
commit 15751e2db5
11 files changed
+337 -103

No files matched your search

+2 -1
View File
@@ -1,5 +1,6 @@
import { loadSettings } from '../utils/config-manager';
import { resolveOpenAICompatProfileConfig } from './profile-router';
import { OPENAI_COMPAT_PROXY_DEFAULT_PORT } from './proxy-daemon-paths';
import { startOpenAICompatProxyServer } from './server/proxy-server';
interface RuntimeOptions {
@@ -12,7 +13,7 @@ interface RuntimeOptions {
}
function parseArgs(argv: string[]): RuntimeOptions {
let port = 3456;
let port = OPENAI_COMPAT_PROXY_DEFAULT_PORT;
let host = '127.0.0.1';
let profileName = '';
let settingsPath = '';
+4 -1
View File
@@ -1,7 +1,10 @@
import * as path from 'path';
import { getCcsDir } from '../utils/config-manager';
export const OPENAI_COMPAT_PROXY_DEFAULT_PORT = 3456;
export const OPENAI_COMPAT_PROXY_LEGACY_DEFAULT_PORT = 3456;
export const OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_START = 43_456;
export const OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_END = 43_555;
export const OPENAI_COMPAT_PROXY_DEFAULT_PORT = OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_START;
export const OPENAI_COMPAT_PROXY_SERVICE_NAME = 'ccs-openai-compat-proxy';
export function getOpenAICompatProxyDir(): string {
+18 -22
View File
@@ -6,7 +6,9 @@ import * as lockfile from 'proper-lockfile';
import { verifyProcessOwnership } from '../cursor/daemon-process-ownership';
import type { OpenAICompatProfileConfig } from './profile-router';
import {
OPENAI_COMPAT_PROXY_DEFAULT_PORT,
OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_END,
OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_START,
OPENAI_COMPAT_PROXY_LEGACY_DEFAULT_PORT,
OPENAI_COMPAT_PROXY_SERVICE_NAME,
getOpenAICompatProxyDir,
} from './proxy-daemon-paths';
@@ -25,7 +27,10 @@ import {
writeOpenAICompatProxyPid,
writeOpenAICompatProxySession,
} from './proxy-daemon-state';
import { resolveOpenAICompatProxyPortPreference } from './proxy-port-resolver';
import {
listOpenAICompatProxyCandidatePorts as listFlexibleOpenAICompatProxyCandidatePorts,
resolveOpenAICompatProxyPortPreference,
} from './proxy-port-resolver';
export interface OpenAICompatProxyStatus extends Partial<OpenAICompatProxySession> {
running: boolean;
@@ -131,6 +136,7 @@ async function terminateDaemonProcess(pid?: number): Promise<void> {
}
function listOpenAICompatProxyCandidatePorts(
profileName: string,
preferredPort: number,
exact: boolean,
excludedPorts: ReadonlySet<number> = new Set()
@@ -139,22 +145,7 @@ function listOpenAICompatProxyCandidatePorts(
return excludedPorts.has(preferredPort) ? [] : [preferredPort];
}
const candidates = new Set<number>();
if (!excludedPorts.has(preferredPort)) {
candidates.add(preferredPort);
}
for (
let candidate = OPENAI_COMPAT_PROXY_DEFAULT_PORT;
candidate <= OPENAI_COMPAT_PROXY_DEFAULT_PORT + 10;
candidate += 1
) {
if (!excludedPorts.has(candidate)) {
candidates.add(candidate);
}
}
return [...candidates];
return listFlexibleOpenAICompatProxyCandidatePorts(profileName, preferredPort, excludedPorts);
}
function isPortBindConflictMessage(message?: string): boolean {
@@ -494,11 +485,15 @@ export async function startOpenAICompatProxy(
const host = options.host?.trim() || status.host || '127.0.0.1';
const portPreference = resolveOpenAICompatProxyPortPreference(profile.profileName);
const explicitPort = typeof options.port === 'number' ? options.port : undefined;
const preferredPort =
const rawPreferredPort =
explicitPort ??
(portPreference.source === 'profile'
? portPreference.port
: status.port || portPreference.port);
: portPreference.source === 'adaptive' &&
status.port === OPENAI_COMPAT_PROXY_LEGACY_DEFAULT_PORT
? portPreference.port
: status.port || portPreference.port);
const preferredPort = rawPreferredPort;
const requiresExactPort = explicitPort !== undefined || portPreference.source === 'profile';
if (status.running && status.port === preferredPort && (status.host || '127.0.0.1') === host) {
return {
@@ -670,6 +665,7 @@ export async function startOpenAICompatProxy(
const attemptedPorts = new Set<number>();
let lastResult: OpenAICompatProxyLaunchResult | null = null;
const candidates = listOpenAICompatProxyCandidatePorts(
profile.profileName,
preferredPort,
requiresExactPort,
attemptedPorts
@@ -678,7 +674,7 @@ export async function startOpenAICompatProxy(
return {
success: false,
port: preferredPort,
error: `No free proxy port found in range ${OPENAI_COMPAT_PROXY_DEFAULT_PORT}-${OPENAI_COMPAT_PROXY_DEFAULT_PORT + 10}`,
error: `No free proxy port found in adaptive range ${OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_START}-${OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_END}`,
};
}
@@ -707,7 +703,7 @@ export async function startOpenAICompatProxy(
port: preferredPort,
error: requiresExactPort
? `Requested proxy port ${preferredPort} is already in use`
: 'No free proxy port found in the proxy port range',
: 'No free proxy port found in the adaptive proxy port range',
}
);
};
+53 -4
View File
@@ -1,9 +1,54 @@
import { loadOrCreateUnifiedConfig } from '../config/unified-config-loader';
import { OPENAI_COMPAT_PROXY_DEFAULT_PORT } from './proxy-daemon-paths';
import {
OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_END,
OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_START,
} from './proxy-daemon-paths';
export interface OpenAICompatProxyPortPreference {
port: number;
source: 'default' | 'profile';
source: 'adaptive' | 'profile' | 'shared';
}
const ADAPTIVE_PORT_RANGE_SIZE =
OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_END - OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_START + 1;
function hashProfileName(profileName: string): number {
let hash = 0;
for (const char of profileName.trim()) {
hash = (hash * 31 + char.charCodeAt(0)) >>> 0;
}
return hash;
}
export function resolveOpenAICompatProxyAdaptivePort(profileName: string): number {
return (
OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_START +
(hashProfileName(profileName) % ADAPTIVE_PORT_RANGE_SIZE)
);
}
export function listOpenAICompatProxyCandidatePorts(
profileName: string,
preferredPort: number,
excludedPorts: ReadonlySet<number> = new Set()
): number[] {
const candidates = new Set<number>();
if (!excludedPorts.has(preferredPort)) {
candidates.add(preferredPort);
}
const adaptiveStart = resolveOpenAICompatProxyAdaptivePort(profileName);
for (let offset = 0; offset < ADAPTIVE_PORT_RANGE_SIZE; offset += 1) {
const candidate =
OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_START +
((adaptiveStart - OPENAI_COMPAT_PROXY_ADAPTIVE_PORT_START + offset) %
ADAPTIVE_PORT_RANGE_SIZE);
if (!excludedPorts.has(candidate)) {
candidates.add(candidate);
}
}
return [...candidates];
}
export function resolveOpenAICompatProxyPortPreference(
@@ -14,9 +59,13 @@ export function resolveOpenAICompatProxyPortPreference(
if (typeof profilePort === 'number') {
return { port: profilePort, source: 'profile' };
}
const sharedPort = config.proxy?.port;
if (typeof sharedPort === 'number') {
return { port: sharedPort, source: 'shared' };
}
return {
port: config.proxy?.port ?? OPENAI_COMPAT_PROXY_DEFAULT_PORT,
source: 'default',
port: resolveOpenAICompatProxyAdaptivePort(profileName),
source: 'adaptive',
};
}