mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-11 12:09:03 +00:00
fix(cliproxy): correct pool routing version capability map (#1726)
This commit is contained in:
1 parent
87f1d9b4e8
commit
b9601cb913
2 files changed
+114
-15
No files matched your search
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, mock } from 'bun:test';
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import type { CLIProxyBackend } from '../../types';
|
||||||
describe('cliproxy routing strategy service', () => {
|
describe('cliproxy routing strategy service', () => {
|
||||||
let tempHome = '';
|
let tempHome = '';
|
||||||
let scopedConfigDir = '';
|
let scopedConfigDir = '';
|
||||||
@@ -15,6 +15,10 @@ describe('cliproxy routing strategy service', () => {
|
|||||||
protocol: 'http' as const,
|
protocol: 'http' as const,
|
||||||
isRemote: false,
|
isRemote: false,
|
||||||
};
|
};
|
||||||
|
let binaryBackend: CLIProxyBackend = 'original';
|
||||||
|
let binaryVersion = '7.2.127-7';
|
||||||
|
let installedVersionQueriedBackend: CLIProxyBackend | undefined = undefined;
|
||||||
|
let loggedWarnings: Array<{ event: string; message: string; context?: Record<string, unknown> }> = [];
|
||||||
let responseFactory: (() => Promise<Response>) | null = null;
|
let responseFactory: (() => Promise<Response>) | null = null;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@@ -28,6 +32,10 @@ describe('cliproxy routing strategy service', () => {
|
|||||||
};
|
};
|
||||||
responseFactory = null;
|
responseFactory = null;
|
||||||
originalCcsDir = process.env.CCS_DIR;
|
originalCcsDir = process.env.CCS_DIR;
|
||||||
|
binaryBackend = 'original';
|
||||||
|
binaryVersion = '7.2.127-7';
|
||||||
|
installedVersionQueriedBackend = undefined;
|
||||||
|
loggedWarnings = [];
|
||||||
originalCcsHome = process.env.CCS_HOME;
|
originalCcsHome = process.env.CCS_HOME;
|
||||||
process.env.CCS_DIR = scopedConfigDir;
|
process.env.CCS_DIR = scopedConfigDir;
|
||||||
process.env.CCS_HOME = tempHome;
|
process.env.CCS_HOME = tempHome;
|
||||||
@@ -74,6 +82,26 @@ describe('cliproxy routing strategy service', () => {
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
mock.module('../../binary-manager', () => ({
|
||||||
|
getConfiguredBackend: () => binaryBackend,
|
||||||
|
getInstalledCliproxyVersion: (backend?: CLIProxyBackend) => {
|
||||||
|
installedVersionQueriedBackend = backend;
|
||||||
|
return binaryVersion;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
mock.module('../../../services/logging', () => ({
|
||||||
|
createLogger: () => ({
|
||||||
|
debug: () => {},
|
||||||
|
info: () => {},
|
||||||
|
warn: (event: string, message: string, context?: Record<string, unknown>) => {
|
||||||
|
loggedWarnings.push({ event, message, context });
|
||||||
|
},
|
||||||
|
error: () => {},
|
||||||
|
child: () => ({ warn: () => {} }),
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
return import(`../routing-strategy?test=${Date.now()}-${Math.random()}`);
|
return import(`../routing-strategy?test=${Date.now()}-${Math.random()}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,4 +393,65 @@ describe('cliproxy routing strategy service', () => {
|
|||||||
expect(result.message).not.toContain('Pool routing is active');
|
expect(result.message).not.toContain('Pool routing is active');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('pool routing version compatibility (#1726)', () => {
|
||||||
|
it('defines backend-specific minimum versions for pool routing', async () => {
|
||||||
|
const mod = await loadRoutingModule();
|
||||||
|
expect(mod.POOL_ROUTING_MIN_VERSION).toEqual({
|
||||||
|
original: '6.8.34',
|
||||||
|
plus: '6.8.34-0',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('evaluates isPoolRoutingSupported correctly across original and plus thresholds', async () => {
|
||||||
|
const mod = await loadRoutingModule();
|
||||||
|
expect(mod.isPoolRoutingSupported('original', '6.8.33')).toBe(false);
|
||||||
|
expect(mod.isPoolRoutingSupported('original', '6.8.34')).toBe(true);
|
||||||
|
expect(mod.isPoolRoutingSupported('original', '6.9.0')).toBe(true);
|
||||||
|
|
||||||
|
expect(mod.isPoolRoutingSupported('plus', '6.8.33-9')).toBe(false);
|
||||||
|
expect(mod.isPoolRoutingSupported('plus', '6.8.34-0')).toBe(true);
|
||||||
|
expect(mod.isPoolRoutingSupported('plus', '7.2.127-7')).toBe(true);
|
||||||
|
|
||||||
|
expect(mod.isPoolRoutingSupported('original', '')).toBe(false);
|
||||||
|
expect(mod.isPoolRoutingSupported('plus', 'not-a-version')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('warns with backend-specific metadata when plus binary is below minimum', async () => {
|
||||||
|
await withScopedConfig(async () => {
|
||||||
|
binaryBackend = 'plus';
|
||||||
|
binaryVersion = '6.8.33-9';
|
||||||
|
loggedWarnings = [];
|
||||||
|
|
||||||
|
const mod = await loadRoutingModule();
|
||||||
|
const result = mod.enablePoolRouting(8317);
|
||||||
|
|
||||||
|
expect(result.changed).toBe(true);
|
||||||
|
expect(installedVersionQueriedBackend).toBe('plus');
|
||||||
|
expect(loggedWarnings).toHaveLength(1);
|
||||||
|
expect(loggedWarnings[0].event).toBe('pool_routing.binary_below_minimum');
|
||||||
|
expect(loggedWarnings[0].message).toContain('CLIProxy Plus');
|
||||||
|
expect(loggedWarnings[0].context).toEqual({
|
||||||
|
backend: 'plus',
|
||||||
|
installedVersion: '6.8.33-9',
|
||||||
|
minimumVersion: '6.8.34-0',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not warn when plus binary meets the minimum version', async () => {
|
||||||
|
await withScopedConfig(async () => {
|
||||||
|
binaryBackend = 'plus';
|
||||||
|
binaryVersion = '6.8.34-0';
|
||||||
|
loggedWarnings = [];
|
||||||
|
|
||||||
|
const mod = await loadRoutingModule();
|
||||||
|
const result = mod.enablePoolRouting(8317);
|
||||||
|
|
||||||
|
expect(result.changed).toBe(true);
|
||||||
|
expect(installedVersionQueriedBackend).toBe('plus');
|
||||||
|
expect(loggedWarnings).toHaveLength(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -7,10 +7,13 @@ import {
|
|||||||
getCliproxyRoutingTarget,
|
getCliproxyRoutingTarget,
|
||||||
getRoutingErrorMessage,
|
getRoutingErrorMessage,
|
||||||
} from './routing-strategy-http';
|
} from './routing-strategy-http';
|
||||||
import type { CliproxyRoutingStrategy } from '../types';
|
import type { CLIProxyBackend, CliproxyRoutingStrategy } from '../types';
|
||||||
import { loadOrCreateUnifiedConfig, mutateConfig } from '../../config/config-loader-facade';
|
import { loadOrCreateUnifiedConfig, mutateConfig } from '../../config/config-loader-facade';
|
||||||
import { getInstalledCliproxyVersion } from '../binary-manager';
|
import { getConfiguredBackend, getInstalledCliproxyVersion } from '../binary-manager';
|
||||||
import { compareVersions } from '../../utils/update-checker';
|
import {
|
||||||
|
type CLIProxyBackendMinVersions,
|
||||||
|
meetsBackendMinimumVersion,
|
||||||
|
} from '../binary/version-checker';
|
||||||
import { getConfigYamlPath } from '../../config/loader/io-locks';
|
import { getConfigYamlPath } from '../../config/loader/io-locks';
|
||||||
import { createLogger } from '../../services/logging';
|
import { createLogger } from '../../services/logging';
|
||||||
|
|
||||||
@@ -46,12 +49,18 @@ export const POOL_ROUTING_VERIFIED_PROVIDERS = new Set(['claude', 'agy']);
|
|||||||
* max-retry-credentials and the cooling flip.
|
* max-retry-credentials and the cooling flip.
|
||||||
* Older binaries silently ignore unknown keys — pool rails would appear active
|
* Older binaries silently ignore unknown keys — pool rails would appear active
|
||||||
* but have no effect. Warn the user at enable time if below this version.
|
* but have no effect. Warn the user at enable time if below this version.
|
||||||
*
|
|
||||||
* NOTE: Update this constant when upstream first ships these keys.
|
|
||||||
* Current best estimate based on spec; adjust after spike Test D confirms.
|
|
||||||
*/
|
*/
|
||||||
export const POOL_ROUTING_MIN_VERSION = '6.9.45';
|
export const POOL_ROUTING_MIN_VERSION: CLIProxyBackendMinVersions = {
|
||||||
|
original: '6.8.34',
|
||||||
|
plus: '6.8.34-0',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isPoolRoutingSupported(
|
||||||
|
backend: CLIProxyBackend,
|
||||||
|
installedVersion: string
|
||||||
|
): boolean {
|
||||||
|
return meetsBackendMinimumVersion(installedVersion, backend, POOL_ROUTING_MIN_VERSION);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Pool-active override warning text. When pool routing is enabled the generator
|
* Pool-active override warning text. When pool routing is enabled the generator
|
||||||
* forces fill-first/affinity/cooling and ignores the stored strategy/affinity, so
|
* forces fill-first/affinity/cooling and ignores the stored strategy/affinity, so
|
||||||
@@ -205,20 +214,21 @@ export function enablePoolRouting(
|
|||||||
|
|
||||||
const preservedExplicitSetting = hasExplicitRoutingStrategy() || hasExplicitSessionAffinity();
|
const preservedExplicitSetting = hasExplicitRoutingStrategy() || hasExplicitSessionAffinity();
|
||||||
|
|
||||||
// Spec step 3 / architecture: assert minimum CLIProxy version at enable time.
|
|
||||||
// Stale binaries silently ignore max-retry-credentials and the cooling flip,
|
|
||||||
// so pool rails would appear active but have no effect. Warn and proceed.
|
|
||||||
try {
|
try {
|
||||||
const installedVersion = getInstalledCliproxyVersion();
|
const backend = getConfiguredBackend();
|
||||||
if (compareVersions(installedVersion, POOL_ROUTING_MIN_VERSION) < 0) {
|
const installedVersion = getInstalledCliproxyVersion(backend);
|
||||||
|
if (!isPoolRoutingSupported(backend, installedVersion)) {
|
||||||
|
const minimumVersion = POOL_ROUTING_MIN_VERSION[backend];
|
||||||
|
const backendLabel = backend === 'plus' ? 'CLIProxy Plus' : 'CLIProxy';
|
||||||
logger.warn(
|
logger.warn(
|
||||||
'pool_routing.binary_below_minimum',
|
'pool_routing.binary_below_minimum',
|
||||||
`CLIProxy v${installedVersion} is older than the pool routing minimum (v${POOL_ROUTING_MIN_VERSION}). ` +
|
`${backendLabel} v${installedVersion} is older than the pool routing minimum (v${minimumVersion}). ` +
|
||||||
`The max-retry-credentials and cooling keys may be silently ignored by the running binary. ` +
|
`The max-retry-credentials and cooling keys may be silently ignored by the running binary. ` +
|
||||||
`Run 'ccs cliproxy --latest' to update CLIProxy, then restart with 'ccs cliproxy restart'.`,
|
`Run 'ccs cliproxy --latest' to update CLIProxy, then restart with 'ccs cliproxy restart'.`,
|
||||||
{
|
{
|
||||||
|
backend,
|
||||||
installedVersion,
|
installedVersion,
|
||||||
minimumVersion: POOL_ROUTING_MIN_VERSION,
|
minimumVersion,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user