mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-03 13:12:09 +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 os from 'os';
|
||||
import * as path from 'path';
|
||||
|
||||
import type { CLIProxyBackend } from '../../types';
|
||||
describe('cliproxy routing strategy service', () => {
|
||||
let tempHome = '';
|
||||
let scopedConfigDir = '';
|
||||
@@ -15,6 +15,10 @@ describe('cliproxy routing strategy service', () => {
|
||||
protocol: 'http' as const,
|
||||
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;
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -28,6 +32,10 @@ describe('cliproxy routing strategy service', () => {
|
||||
};
|
||||
responseFactory = null;
|
||||
originalCcsDir = process.env.CCS_DIR;
|
||||
binaryBackend = 'original';
|
||||
binaryVersion = '7.2.127-7';
|
||||
installedVersionQueriedBackend = undefined;
|
||||
loggedWarnings = [];
|
||||
originalCcsHome = process.env.CCS_HOME;
|
||||
process.env.CCS_DIR = scopedConfigDir;
|
||||
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()}`);
|
||||
}
|
||||
|
||||
@@ -365,4 +393,65 @@ describe('cliproxy routing strategy service', () => {
|
||||
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,
|
||||
getRoutingErrorMessage,
|
||||
} from './routing-strategy-http';
|
||||
import type { CliproxyRoutingStrategy } from '../types';
|
||||
import type { CLIProxyBackend, CliproxyRoutingStrategy } from '../types';
|
||||
import { loadOrCreateUnifiedConfig, mutateConfig } from '../../config/config-loader-facade';
|
||||
import { getInstalledCliproxyVersion } from '../binary-manager';
|
||||
import { compareVersions } from '../../utils/update-checker';
|
||||
import { getConfiguredBackend, getInstalledCliproxyVersion } from '../binary-manager';
|
||||
import {
|
||||
type CLIProxyBackendMinVersions,
|
||||
meetsBackendMinimumVersion,
|
||||
} from '../binary/version-checker';
|
||||
import { getConfigYamlPath } from '../../config/loader/io-locks';
|
||||
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.
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* forces fill-first/affinity/cooling and ignores the stored strategy/affinity, so
|
||||
@@ -205,20 +214,21 @@ export function enablePoolRouting(
|
||||
|
||||
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 {
|
||||
const installedVersion = getInstalledCliproxyVersion();
|
||||
if (compareVersions(installedVersion, POOL_ROUTING_MIN_VERSION) < 0) {
|
||||
const backend = getConfiguredBackend();
|
||||
const installedVersion = getInstalledCliproxyVersion(backend);
|
||||
if (!isPoolRoutingSupported(backend, installedVersion)) {
|
||||
const minimumVersion = POOL_ROUTING_MIN_VERSION[backend];
|
||||
const backendLabel = backend === 'plus' ? 'CLIProxy Plus' : 'CLIProxy';
|
||||
logger.warn(
|
||||
'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. ` +
|
||||
`Run 'ccs cliproxy --latest' to update CLIProxy, then restart with 'ccs cliproxy restart'.`,
|
||||
{
|
||||
backend,
|
||||
installedVersion,
|
||||
minimumVersion: POOL_ROUTING_MIN_VERSION,
|
||||
minimumVersion,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user