mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 04:18:05 +00:00
feat(proxy): support profile-scoped local proxy ports
This commit is contained in:
@@ -5,6 +5,7 @@ import { fail, info, ok } from '../utils/ui';
|
||||
import {
|
||||
buildOpenAICompatProxyEnv,
|
||||
getOpenAICompatProxyStatus,
|
||||
listOpenAICompatProxyStatuses,
|
||||
resolveOpenAICompatProfileConfig,
|
||||
startOpenAICompatProxy,
|
||||
stopOpenAICompatProxy,
|
||||
@@ -30,9 +31,9 @@ function showHelp(): number {
|
||||
console.log(
|
||||
' start <profile> Start the local proxy for an OpenAI-compatible settings profile'
|
||||
);
|
||||
console.log(' stop Stop the running proxy');
|
||||
console.log(' status Show daemon status and active profile');
|
||||
console.log(' activate Print shell exports for the running proxy');
|
||||
console.log(' stop [profile] Stop the running proxy (or all proxies when omitted)');
|
||||
console.log(' status [profile] Show daemon status');
|
||||
console.log(' activate [profile] Print shell exports for the running proxy');
|
||||
console.log('');
|
||||
console.log('Options:');
|
||||
console.log(' --port <n> Override the local proxy port (default: 3456)');
|
||||
@@ -100,35 +101,50 @@ async function handleStart(args: string[]): Promise<number> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
async function handleStatus(): Promise<number> {
|
||||
const status = await getOpenAICompatProxyStatus();
|
||||
if (!status.running) {
|
||||
async function handleStatus(args: string[] = []): Promise<number> {
|
||||
const profileName = args.find((arg) => !arg.startsWith('-'));
|
||||
const running = profileName
|
||||
? [await getOpenAICompatProxyStatus(profileName)].filter((status) => status.running)
|
||||
: (await listOpenAICompatProxyStatuses()).filter((status) => status.running);
|
||||
if (running.length === 0) {
|
||||
console.log(info('Proxy is not running'));
|
||||
return 0;
|
||||
}
|
||||
|
||||
console.log(ok(`Proxy running on port ${status.port}`));
|
||||
if (status.host) {
|
||||
console.log(` Host: ${status.host}`);
|
||||
console.log(` Local URL: http://${status.host}:${status.port}`);
|
||||
}
|
||||
console.log(` Profile: ${status.profileName}`);
|
||||
console.log(` Base URL: ${status.baseUrl}`);
|
||||
if (status.model) {
|
||||
console.log(` Model: ${status.model}`);
|
||||
}
|
||||
if (status.pid) {
|
||||
console.log(` PID: ${status.pid}`);
|
||||
for (const status of running) {
|
||||
console.log(ok(`Proxy running on port ${status.port}`));
|
||||
if (status.host) {
|
||||
console.log(` Host: ${status.host}`);
|
||||
console.log(` Local URL: http://${status.host}:${status.port}`);
|
||||
}
|
||||
console.log(` Profile: ${status.profileName}`);
|
||||
console.log(` Base URL: ${status.baseUrl}`);
|
||||
if (status.model) {
|
||||
console.log(` Model: ${status.model}`);
|
||||
}
|
||||
if (status.pid) {
|
||||
console.log(` PID: ${status.pid}`);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
async function handleActivate(args: string[]): Promise<number> {
|
||||
const status = await getOpenAICompatProxyStatus();
|
||||
const profileName = args.find((arg) => !arg.startsWith('-'));
|
||||
const status = await getOpenAICompatProxyStatus(profileName);
|
||||
if (!status.running || !status.profileName || !status.port || !status.authToken) {
|
||||
console.error(fail('Proxy is not running. Start it with: ccs proxy start <profile>'));
|
||||
return 1;
|
||||
}
|
||||
if (!profileName) {
|
||||
const running = (await listOpenAICompatProxyStatuses()).filter((entry) => entry.running);
|
||||
if (running.length > 1) {
|
||||
console.error(
|
||||
fail('Multiple proxies are running. Specify a profile: ccs proxy activate <profile>')
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
const shell = detectShell(args.includes('--fish') ? 'fish' : parseOptionValue(args, '--shell'));
|
||||
let profile;
|
||||
@@ -163,16 +179,17 @@ export async function handleProxyCommand(args: string[]): Promise<number> {
|
||||
case 'start':
|
||||
return handleStart(args.slice(1));
|
||||
case 'stop': {
|
||||
const result = await stopOpenAICompatProxy();
|
||||
const profileName = args[1] && !args[1]?.startsWith('-') ? args[1] : undefined;
|
||||
const result = await stopOpenAICompatProxy(profileName);
|
||||
if (!result.success) {
|
||||
console.error(fail(result.error || 'Failed to stop proxy'));
|
||||
return 1;
|
||||
}
|
||||
console.log(ok('Proxy stopped'));
|
||||
console.log(ok(profileName ? `Proxy stopped for profile ${profileName}` : 'Proxy stopped'));
|
||||
return 0;
|
||||
}
|
||||
case 'status':
|
||||
return handleStatus();
|
||||
return handleStatus(args.slice(1));
|
||||
case 'activate':
|
||||
return handleActivate(args.slice(1));
|
||||
default:
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
DEFAULT_GLOBAL_ENV,
|
||||
DEFAULT_CLIPROXY_SERVER_CONFIG,
|
||||
DEFAULT_CLIPROXY_SAFETY_CONFIG,
|
||||
DEFAULT_OPENAI_COMPAT_PROXY_CONFIG,
|
||||
DEFAULT_QUOTA_MANAGEMENT_CONFIG,
|
||||
DEFAULT_THINKING_CONFIG,
|
||||
DEFAULT_OFFICIAL_CHANNELS_CONFIG,
|
||||
@@ -414,6 +415,10 @@ function mergeWithDefaults(partial: Partial<UnifiedConfig>): UnifiedConfig {
|
||||
},
|
||||
},
|
||||
proxy: {
|
||||
port: partial.proxy?.port ?? DEFAULT_OPENAI_COMPAT_PROXY_CONFIG.port,
|
||||
profile_ports: partial.proxy?.profile_ports ?? {
|
||||
...DEFAULT_OPENAI_COMPAT_PROXY_CONFIG.profile_ports,
|
||||
},
|
||||
routing: {
|
||||
default: partial.proxy?.routing?.default ?? defaults.proxy?.routing?.default,
|
||||
background: partial.proxy?.routing?.background ?? defaults.proxy?.routing?.background,
|
||||
|
||||
@@ -508,6 +508,10 @@ export interface OpenAICompatProxyRoutingConfig {
|
||||
}
|
||||
|
||||
export interface OpenAICompatProxyConfig {
|
||||
/** Default local port for OpenAI-compatible proxy instances */
|
||||
port?: number;
|
||||
/** Optional profile-scoped local port overrides */
|
||||
profile_ports?: Record<string, number>;
|
||||
routing?: OpenAICompatProxyRoutingConfig;
|
||||
}
|
||||
|
||||
@@ -986,6 +990,8 @@ export const DEFAULT_CLIPROXY_SERVER_CONFIG: CliproxyServerConfig = {
|
||||
};
|
||||
|
||||
export const DEFAULT_OPENAI_COMPAT_PROXY_CONFIG: OpenAICompatProxyConfig = {
|
||||
port: 3456,
|
||||
profile_ports: {},
|
||||
routing: {
|
||||
longContextThreshold: 60_000,
|
||||
},
|
||||
@@ -1016,6 +1022,8 @@ export function createEmptyUnifiedConfig(): UnifiedConfig {
|
||||
},
|
||||
},
|
||||
proxy: {
|
||||
port: DEFAULT_OPENAI_COMPAT_PROXY_CONFIG.port,
|
||||
profile_ports: { ...DEFAULT_OPENAI_COMPAT_PROXY_CONFIG.profile_ports },
|
||||
routing: {
|
||||
...DEFAULT_OPENAI_COMPAT_PROXY_CONFIG.routing,
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ export * from './profile-router';
|
||||
export * from './proxy-daemon';
|
||||
export * from './proxy-daemon-paths';
|
||||
export * from './proxy-env';
|
||||
export * from './proxy-port-resolver';
|
||||
export * from './upstream-url';
|
||||
export * from './transformers/request-transformer';
|
||||
export * from './transformers/sse-stream-transformer';
|
||||
|
||||
@@ -8,10 +8,20 @@ export function getOpenAICompatProxyDir(): string {
|
||||
return path.join(getCcsDir(), 'proxy');
|
||||
}
|
||||
|
||||
export function getOpenAICompatProxyPidPath(): string {
|
||||
return path.join(getOpenAICompatProxyDir(), 'daemon.pid');
|
||||
export function getOpenAICompatProxyProfileKey(profileName: string): string {
|
||||
return encodeURIComponent(profileName.trim());
|
||||
}
|
||||
|
||||
export function getOpenAICompatProxySessionPath(): string {
|
||||
return path.join(getOpenAICompatProxyDir(), 'session.json');
|
||||
export function getOpenAICompatProxyPidPath(profileName: string): string {
|
||||
return path.join(
|
||||
getOpenAICompatProxyDir(),
|
||||
`${getOpenAICompatProxyProfileKey(profileName)}.daemon.pid`
|
||||
);
|
||||
}
|
||||
|
||||
export function getOpenAICompatProxySessionPath(profileName: string): string {
|
||||
return path.join(
|
||||
getOpenAICompatProxyDir(),
|
||||
`${getOpenAICompatProxyProfileKey(profileName)}.session.json`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ function ensureProxyDir(): void {
|
||||
fs.mkdirSync(getOpenAICompatProxyDir(), { recursive: true });
|
||||
}
|
||||
|
||||
export function getOpenAICompatProxyPid(): number | null {
|
||||
export function getOpenAICompatProxyPid(profileName: string): number | null {
|
||||
try {
|
||||
const raw = fs.readFileSync(getOpenAICompatProxyPidPath(), 'utf8').trim();
|
||||
const raw = fs.readFileSync(getOpenAICompatProxyPidPath(profileName), 'utf8').trim();
|
||||
const pid = Number.parseInt(raw, 10);
|
||||
return Number.isInteger(pid) ? pid : null;
|
||||
} catch {
|
||||
@@ -31,23 +31,23 @@ export function getOpenAICompatProxyPid(): number | null {
|
||||
}
|
||||
}
|
||||
|
||||
export function writeOpenAICompatProxyPid(pid: number): void {
|
||||
export function writeOpenAICompatProxyPid(profileName: string, pid: number): void {
|
||||
ensureProxyDir();
|
||||
fs.writeFileSync(getOpenAICompatProxyPidPath(), String(pid), 'utf8');
|
||||
fs.writeFileSync(getOpenAICompatProxyPidPath(profileName), String(pid), 'utf8');
|
||||
}
|
||||
|
||||
export function removeOpenAICompatProxyPid(): void {
|
||||
export function removeOpenAICompatProxyPid(profileName: string): void {
|
||||
try {
|
||||
fs.unlinkSync(getOpenAICompatProxyPidPath());
|
||||
fs.unlinkSync(getOpenAICompatProxyPidPath(profileName));
|
||||
} catch {
|
||||
// Best-effort cleanup.
|
||||
}
|
||||
}
|
||||
|
||||
export function readOpenAICompatProxySession(): OpenAICompatProxySession | null {
|
||||
export function readOpenAICompatProxySession(profileName: string): OpenAICompatProxySession | null {
|
||||
try {
|
||||
return JSON.parse(
|
||||
fs.readFileSync(getOpenAICompatProxySessionPath(), 'utf8')
|
||||
fs.readFileSync(getOpenAICompatProxySessionPath(profileName), 'utf8')
|
||||
) as OpenAICompatProxySession;
|
||||
} catch {
|
||||
return null;
|
||||
@@ -57,20 +57,48 @@ export function readOpenAICompatProxySession(): OpenAICompatProxySession | null
|
||||
export function writeOpenAICompatProxySession(session: OpenAICompatProxySession): void {
|
||||
ensureProxyDir();
|
||||
fs.writeFileSync(
|
||||
getOpenAICompatProxySessionPath(),
|
||||
getOpenAICompatProxySessionPath(session.profileName),
|
||||
JSON.stringify(session, null, 2) + '\n',
|
||||
'utf8'
|
||||
);
|
||||
}
|
||||
|
||||
export function removeOpenAICompatProxySession(): void {
|
||||
export function removeOpenAICompatProxySession(profileName: string): void {
|
||||
try {
|
||||
fs.unlinkSync(getOpenAICompatProxySessionPath());
|
||||
fs.unlinkSync(getOpenAICompatProxySessionPath(profileName));
|
||||
} catch {
|
||||
// Best-effort cleanup.
|
||||
}
|
||||
}
|
||||
|
||||
export function listOpenAICompatProxyProfileNames(): string[] {
|
||||
try {
|
||||
const entries = fs.readdirSync(getOpenAICompatProxyDir(), { withFileTypes: true });
|
||||
const profileKeys = new Set<string>();
|
||||
for (const entry of entries) {
|
||||
if (!entry.isFile() || !entry.name.endsWith('.session.json')) {
|
||||
continue;
|
||||
}
|
||||
profileKeys.add(entry.name.slice(0, -'.session.json'.length));
|
||||
}
|
||||
return [...profileKeys].map((profileKey) => decodeURIComponent(profileKey));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function cleanupLegacyOpenAICompatProxyState(): void {
|
||||
ensureProxyDir();
|
||||
const legacyNames = ['daemon.pid', 'session.json'];
|
||||
for (const legacyName of legacyNames) {
|
||||
try {
|
||||
fs.unlinkSync(path.join(getOpenAICompatProxyDir(), legacyName));
|
||||
} catch {
|
||||
// Best-effort cleanup.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveOpenAICompatProxyEntrypointCandidates(): string[] {
|
||||
const jsEntry = path.join(__dirname, 'proxy-daemon-entry.js');
|
||||
const tsEntry = path.join(__dirname, 'proxy-daemon-entry.ts');
|
||||
|
||||
+88
-37
@@ -13,7 +13,9 @@ import {
|
||||
} from './proxy-daemon-paths';
|
||||
import {
|
||||
getOpenAICompatProxyPid,
|
||||
listOpenAICompatProxyProfileNames,
|
||||
readOpenAICompatProxySession,
|
||||
cleanupLegacyOpenAICompatProxyState,
|
||||
removeOpenAICompatProxyPid,
|
||||
removeOpenAICompatProxySession,
|
||||
resolveOpenAICompatProxyEntrypointCandidates,
|
||||
@@ -21,6 +23,7 @@ import {
|
||||
writeOpenAICompatProxyPid,
|
||||
writeOpenAICompatProxySession,
|
||||
} from './proxy-daemon-state';
|
||||
import { resolveOpenAICompatProxyPreferredPort } from './proxy-port-resolver';
|
||||
|
||||
export interface OpenAICompatProxyStatus extends Partial<OpenAICompatProxySession> {
|
||||
running: boolean;
|
||||
@@ -101,6 +104,13 @@ async function findOpenAICompatProxyPort(): Promise<number> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
async function findOpenAICompatProxyPortNear(preferredPort: number): Promise<number> {
|
||||
if (!(await isPortOccupied(preferredPort))) {
|
||||
return preferredPort;
|
||||
}
|
||||
return findOpenAICompatProxyPort();
|
||||
}
|
||||
|
||||
async function resolveDaemonEntrypoint(): Promise<string | null> {
|
||||
for (const candidate of resolveOpenAICompatProxyEntrypointCandidates()) {
|
||||
try {
|
||||
@@ -144,21 +154,52 @@ export async function isOpenAICompatProxyRunning(port: number): Promise<boolean>
|
||||
});
|
||||
}
|
||||
|
||||
export async function getOpenAICompatProxyStatus(): Promise<OpenAICompatProxyStatus> {
|
||||
const session = readOpenAICompatProxySession();
|
||||
async function getOpenAICompatProxyStatusForProfile(
|
||||
profileName: string
|
||||
): Promise<OpenAICompatProxyStatus> {
|
||||
const session = readOpenAICompatProxySession(profileName);
|
||||
const port = session?.port ?? OPENAI_COMPAT_PROXY_DEFAULT_PORT;
|
||||
const running = await isOpenAICompatProxyRunning(port);
|
||||
return {
|
||||
running,
|
||||
pid: running ? getOpenAICompatProxyPid() || undefined : undefined,
|
||||
pid: running ? getOpenAICompatProxyPid(profileName) || undefined : undefined,
|
||||
...session,
|
||||
};
|
||||
}
|
||||
|
||||
async function stopOpenAICompatProxyUnlocked(): Promise<{ success: boolean; error?: string }> {
|
||||
const pid = getOpenAICompatProxyPid();
|
||||
export async function listOpenAICompatProxyStatuses(): Promise<OpenAICompatProxyStatus[]> {
|
||||
const profileNames = listOpenAICompatProxyProfileNames();
|
||||
const statuses = await Promise.all(
|
||||
profileNames.map((profileName) => getOpenAICompatProxyStatusForProfile(profileName))
|
||||
);
|
||||
return statuses.filter((status) => status.profileName);
|
||||
}
|
||||
|
||||
export async function getOpenAICompatProxyStatus(
|
||||
profileName?: string
|
||||
): Promise<OpenAICompatProxyStatus> {
|
||||
if (profileName) {
|
||||
return getOpenAICompatProxyStatusForProfile(profileName);
|
||||
}
|
||||
|
||||
const statuses = await listOpenAICompatProxyStatuses();
|
||||
const running = statuses.filter((status) => status.running);
|
||||
if (running.length === 1) {
|
||||
return running[0] || { running: false };
|
||||
}
|
||||
if (running.length > 1) {
|
||||
return { running: true };
|
||||
}
|
||||
const latestKnown = statuses[0];
|
||||
return latestKnown ?? { running: false };
|
||||
}
|
||||
|
||||
async function stopOpenAICompatProxyUnlocked(
|
||||
profileName: string
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const pid = getOpenAICompatProxyPid(profileName);
|
||||
if (!pid) {
|
||||
removeOpenAICompatProxySession();
|
||||
removeOpenAICompatProxySession(profileName);
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
@@ -170,7 +211,8 @@ async function stopOpenAICompatProxyUnlocked(): Promise<{ success: boolean; erro
|
||||
);
|
||||
|
||||
if (ownership === 'not-owned') {
|
||||
removeOpenAICompatProxyPid();
|
||||
removeOpenAICompatProxyPid(profileName);
|
||||
removeOpenAICompatProxySession(profileName);
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
@@ -182,8 +224,8 @@ async function stopOpenAICompatProxyUnlocked(): Promise<{ success: boolean; erro
|
||||
}
|
||||
|
||||
if (ownership === 'not-running') {
|
||||
removeOpenAICompatProxyPid();
|
||||
removeOpenAICompatProxySession();
|
||||
removeOpenAICompatProxyPid(profileName);
|
||||
removeOpenAICompatProxySession(profileName);
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
@@ -214,13 +256,32 @@ async function stopOpenAICompatProxyUnlocked(): Promise<{ success: boolean; erro
|
||||
}
|
||||
}
|
||||
|
||||
removeOpenAICompatProxyPid();
|
||||
removeOpenAICompatProxySession();
|
||||
removeOpenAICompatProxyPid(profileName);
|
||||
removeOpenAICompatProxySession(profileName);
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
export async function stopOpenAICompatProxy(): Promise<{ success: boolean; error?: string }> {
|
||||
return withOpenAICompatProxyLock(() => stopOpenAICompatProxyUnlocked());
|
||||
export async function stopOpenAICompatProxy(
|
||||
profileName?: string
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
return withOpenAICompatProxyLock(async () => {
|
||||
cleanupLegacyOpenAICompatProxyState();
|
||||
if (profileName) {
|
||||
return stopOpenAICompatProxyUnlocked(profileName);
|
||||
}
|
||||
|
||||
const statuses = await listOpenAICompatProxyStatuses();
|
||||
for (const status of statuses) {
|
||||
if (!status.profileName) {
|
||||
continue;
|
||||
}
|
||||
const stopped = await stopOpenAICompatProxyUnlocked(status.profileName);
|
||||
if (!stopped.success) {
|
||||
return stopped;
|
||||
}
|
||||
}
|
||||
return { success: true };
|
||||
});
|
||||
}
|
||||
|
||||
export async function startOpenAICompatProxy(
|
||||
@@ -228,30 +289,28 @@ export async function startOpenAICompatProxy(
|
||||
options: { port?: number; host?: string; insecure?: boolean } = {}
|
||||
): Promise<StartOpenAICompatProxyResult> {
|
||||
return withOpenAICompatProxyLock(async () => {
|
||||
const status = await getOpenAICompatProxyStatus();
|
||||
cleanupLegacyOpenAICompatProxyState();
|
||||
const status = await getOpenAICompatProxyStatus(profile.profileName);
|
||||
const host = options.host?.trim() || status.host || '127.0.0.1';
|
||||
const port =
|
||||
const preferredPort =
|
||||
typeof options.port === 'number'
|
||||
? options.port
|
||||
: status.running && status.profileName === profile.profileName && status.port
|
||||
? status.port
|
||||
: await findOpenAICompatProxyPort();
|
||||
: status.port || resolveOpenAICompatProxyPreferredPort(profile.profileName);
|
||||
const port =
|
||||
status.running && status.port && (status.host || '127.0.0.1') === host
|
||||
? status.port
|
||||
: await findOpenAICompatProxyPortNear(preferredPort);
|
||||
if (port === 0) {
|
||||
return {
|
||||
success: false,
|
||||
port: OPENAI_COMPAT_PROXY_DEFAULT_PORT,
|
||||
port: preferredPort,
|
||||
error: `No free proxy port found in range ${OPENAI_COMPAT_PROXY_DEFAULT_PORT}-${OPENAI_COMPAT_PROXY_DEFAULT_PORT + 10}`,
|
||||
};
|
||||
}
|
||||
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
||||
return { success: false, port, error: `Invalid port: ${port}` };
|
||||
}
|
||||
if (
|
||||
status.running &&
|
||||
status.profileName === profile.profileName &&
|
||||
status.port === port &&
|
||||
(status.host || '127.0.0.1') === host
|
||||
) {
|
||||
if (status.running && status.port === port && (status.host || '127.0.0.1') === host) {
|
||||
return {
|
||||
success: true,
|
||||
alreadyRunning: true,
|
||||
@@ -261,15 +320,7 @@ export async function startOpenAICompatProxy(
|
||||
};
|
||||
}
|
||||
if (status.running) {
|
||||
if (status.profileName !== profile.profileName) {
|
||||
return {
|
||||
success: false,
|
||||
port,
|
||||
error: `Proxy already running for profile "${status.profileName}" on port ${status.port}. Stop it before starting a different profile.`,
|
||||
};
|
||||
}
|
||||
|
||||
const stopped = await stopOpenAICompatProxyUnlocked();
|
||||
const stopped = await stopOpenAICompatProxyUnlocked(profile.profileName);
|
||||
if (!stopped.success) {
|
||||
return {
|
||||
success: false,
|
||||
@@ -298,8 +349,8 @@ export async function startOpenAICompatProxy(
|
||||
resolved = true;
|
||||
if (timeout) clearTimeout(timeout);
|
||||
if (!result.success) {
|
||||
removeOpenAICompatProxyPid();
|
||||
removeOpenAICompatProxySession();
|
||||
removeOpenAICompatProxyPid(profile.profileName);
|
||||
removeOpenAICompatProxySession(profile.profileName);
|
||||
}
|
||||
resolve(result);
|
||||
};
|
||||
@@ -326,7 +377,7 @@ export async function startOpenAICompatProxy(
|
||||
|
||||
proc.unref();
|
||||
if (proc.pid) {
|
||||
writeOpenAICompatProxyPid(proc.pid);
|
||||
writeOpenAICompatProxyPid(profile.profileName, proc.pid);
|
||||
}
|
||||
writeOpenAICompatProxySession({
|
||||
profileName: profile.profileName,
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { loadOrCreateUnifiedConfig } from '../config/unified-config-loader';
|
||||
import { OPENAI_COMPAT_PROXY_DEFAULT_PORT } from './proxy-daemon-paths';
|
||||
|
||||
export function resolveOpenAICompatProxyPreferredPort(profileName: string): number {
|
||||
const config = loadOrCreateUnifiedConfig();
|
||||
const profilePort = config.proxy?.profile_ports?.[profileName];
|
||||
if (typeof profilePort === 'number') {
|
||||
return profilePort;
|
||||
}
|
||||
return config.proxy?.port ?? OPENAI_COMPAT_PROXY_DEFAULT_PORT;
|
||||
}
|
||||
Reference in New Issue
Block a user