mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-03 20:13:02 +00:00
test(cliproxy): cover auto compact windows
This commit is contained in:
1 parent
b0732613a3
commit
c107a6752c
3 files changed
+203
-16
No files matched your search
@@ -75,6 +75,18 @@ describe('model-catalog compatibility lookups', () => {
|
||||
expect(catalog?.models[0]?.extendedContext).toBeUndefined();
|
||||
});
|
||||
|
||||
it('maps positive integer live context length into contextWindow metadata', () => {
|
||||
const catalog = mergeCatalog('xai', [
|
||||
{
|
||||
id: 'grok-4.3',
|
||||
display_name: 'Grok 4.3 Live',
|
||||
context_length: 1_000_000,
|
||||
},
|
||||
]);
|
||||
|
||||
expect(catalog?.models[0]?.contextWindow).toBe(1_000_000);
|
||||
});
|
||||
|
||||
it('does not re-add stale static-only models when live catalog data is present', () => {
|
||||
const catalog = mergeCatalog('gemini', [
|
||||
{
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
|
||||
|
||||
import { invalidateConfigCache } from '../../../config/config-loader-facade';
|
||||
import { clearConfigCache } from '../base-config-loader';
|
||||
import { applyClaudeAutoCompactWindow } from '../env-builder';
|
||||
import { buildClaudeEnvironment } from '../../executor/env-resolver';
|
||||
|
||||
describe('applyClaudeAutoCompactWindow', () => {
|
||||
it('injects the catalog window for the effective model after suffix normalization', () => {
|
||||
const env = applyClaudeAutoCompactWindow(
|
||||
{
|
||||
ANTHROPIC_MODEL: 'gpt-5.6-sol-xhigh[1m]',
|
||||
},
|
||||
'codex'
|
||||
);
|
||||
|
||||
expect(env.CLAUDE_CODE_AUTO_COMPACT_WINDOW).toBe('372000');
|
||||
});
|
||||
|
||||
it('uses the selected provider when the same model family exists in multiple catalogs', () => {
|
||||
const env = applyClaudeAutoCompactWindow(
|
||||
{
|
||||
ANTHROPIC_MODEL: 'claude-opus-4-6-thinking',
|
||||
},
|
||||
'agy'
|
||||
);
|
||||
|
||||
expect(env.CLAUDE_CODE_AUTO_COMPACT_WINDOW).toBe('200000');
|
||||
});
|
||||
|
||||
it('does not inject a value for unknown or custom models', () => {
|
||||
const env = applyClaudeAutoCompactWindow(
|
||||
{
|
||||
ANTHROPIC_MODEL: 'custom-model-with-unknown-window',
|
||||
},
|
||||
'codex'
|
||||
);
|
||||
|
||||
expect('CLAUDE_CODE_AUTO_COMPACT_WINDOW' in env).toBe(false);
|
||||
});
|
||||
|
||||
it('preserves an explicit user value', () => {
|
||||
const env = applyClaudeAutoCompactWindow(
|
||||
{
|
||||
ANTHROPIC_MODEL: 'gpt-5.6-sol',
|
||||
CLAUDE_CODE_AUTO_COMPACT_WINDOW: '123456',
|
||||
},
|
||||
'codex'
|
||||
);
|
||||
|
||||
expect(env.CLAUDE_CODE_AUTO_COMPACT_WINDOW).toBe('123456');
|
||||
});
|
||||
|
||||
it('treats an explicit empty value as authoritative', () => {
|
||||
const env = applyClaudeAutoCompactWindow(
|
||||
{
|
||||
ANTHROPIC_MODEL: 'gpt-5.6-sol',
|
||||
CLAUDE_CODE_AUTO_COMPACT_WINDOW: '',
|
||||
},
|
||||
'codex'
|
||||
);
|
||||
|
||||
expect(env.CLAUDE_CODE_AUTO_COMPACT_WINDOW).toBe('');
|
||||
});
|
||||
|
||||
it('does not mistake a differently cased variable for the Claude Code key', () => {
|
||||
const env = applyClaudeAutoCompactWindow(
|
||||
{
|
||||
ANTHROPIC_MODEL: 'gpt-5.6-sol',
|
||||
claude_code_auto_compact_window: '123456',
|
||||
},
|
||||
'codex'
|
||||
);
|
||||
|
||||
expect(env.claude_code_auto_compact_window).toBe('123456');
|
||||
expect(env.CLAUDE_CODE_AUTO_COMPACT_WINDOW).toBe('372000');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Claude launch auto-compact integration', () => {
|
||||
let tempHome: string;
|
||||
let originalCcsHome: string | undefined;
|
||||
let originalAutoCompactWindow: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
originalCcsHome = process.env.CCS_HOME;
|
||||
originalAutoCompactWindow = process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW;
|
||||
tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-auto-compact-'));
|
||||
process.env.CCS_HOME = tempHome;
|
||||
delete process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW;
|
||||
invalidateConfigCache();
|
||||
clearConfigCache();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (originalCcsHome === undefined) delete process.env.CCS_HOME;
|
||||
else process.env.CCS_HOME = originalCcsHome;
|
||||
|
||||
if (originalAutoCompactWindow === undefined) {
|
||||
delete process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW;
|
||||
} else {
|
||||
process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW = originalAutoCompactWindow;
|
||||
}
|
||||
|
||||
invalidateConfigCache();
|
||||
clearConfigCache();
|
||||
fs.rmSync(tempHome, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('injects the catalog window for the provider default model on Claude launches', () => {
|
||||
const env = buildClaudeEnvironment({
|
||||
provider: 'codex',
|
||||
useRemoteProxy: false,
|
||||
localPort: 8317,
|
||||
verbose: false,
|
||||
});
|
||||
|
||||
expect(env.ANTHROPIC_MODEL).toBe('gpt-5.4(high)');
|
||||
expect(env.CLAUDE_CODE_AUTO_COMPACT_WINDOW).toBe('1050000');
|
||||
});
|
||||
|
||||
it('preserves an inherited user value on Claude launches', () => {
|
||||
process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW = '';
|
||||
|
||||
const env = buildClaudeEnvironment({
|
||||
provider: 'codex',
|
||||
useRemoteProxy: false,
|
||||
localPort: 8317,
|
||||
verbose: false,
|
||||
});
|
||||
|
||||
expect(env.CLAUDE_CODE_AUTO_COMPACT_WINDOW).toBe('');
|
||||
});
|
||||
|
||||
it('uses the composite default tier provider for model lookup', () => {
|
||||
const env = buildClaudeEnvironment({
|
||||
provider: 'codex',
|
||||
useRemoteProxy: false,
|
||||
localPort: 8317,
|
||||
verbose: false,
|
||||
isComposite: true,
|
||||
compositeTiers: {
|
||||
opus: { provider: 'agy', model: 'claude-opus-4-6-thinking' },
|
||||
sonnet: { provider: 'codex', model: 'gpt-5.6-sol' },
|
||||
haiku: { provider: 'kimi', model: 'kimi-k2' },
|
||||
},
|
||||
compositeDefaultTier: 'opus',
|
||||
});
|
||||
|
||||
expect(env.CLAUDE_CODE_AUTO_COMPACT_WINDOW).toBe('200000');
|
||||
});
|
||||
|
||||
it('preserves an explicit empty value from a custom settings file', () => {
|
||||
const settingsPath = path.join(tempHome, 'codex-custom.settings.json');
|
||||
fs.writeFileSync(
|
||||
settingsPath,
|
||||
JSON.stringify({
|
||||
env: {
|
||||
ANTHROPIC_BASE_URL: 'http://127.0.0.1:8317',
|
||||
ANTHROPIC_AUTH_TOKEN: 'test-token',
|
||||
ANTHROPIC_MODEL: 'gpt-5.6-sol',
|
||||
CLAUDE_CODE_AUTO_COMPACT_WINDOW: '',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const env = buildClaudeEnvironment({
|
||||
provider: 'codex',
|
||||
useRemoteProxy: false,
|
||||
localPort: 8317,
|
||||
customSettingsPath: settingsPath,
|
||||
verbose: false,
|
||||
});
|
||||
|
||||
expect(env.CLAUDE_CODE_AUTO_COMPACT_WINDOW).toBe('');
|
||||
});
|
||||
});
|
||||
@@ -42,10 +42,7 @@ describe('cliproxy catalog --json output', () => {
|
||||
it('includes metadata fields when present on model entries', () => {
|
||||
handleCatalogJson();
|
||||
|
||||
const parsed = JSON.parse(capturedOutput[0]) as Record<
|
||||
string,
|
||||
Array<Record<string, unknown>>
|
||||
>;
|
||||
const parsed = JSON.parse(capturedOutput[0]) as Record<string, Array<Record<string, unknown>>>;
|
||||
const allModels = Object.values(parsed).flat();
|
||||
|
||||
// At least some models in the static catalog have tier set
|
||||
@@ -56,15 +53,19 @@ describe('cliproxy catalog --json output', () => {
|
||||
for (const model of withTier) {
|
||||
expect(['free', 'pro', 'ultra']).toContain(model.tier);
|
||||
}
|
||||
|
||||
const withContextWindow = allModels.filter((m) => m.contextWindow !== undefined);
|
||||
expect(withContextWindow.length).toBeGreaterThan(0);
|
||||
for (const model of withContextWindow) {
|
||||
expect(Number.isInteger(model.contextWindow)).toBe(true);
|
||||
expect(model.contextWindow as number).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('omits undefined optional fields instead of including nulls', () => {
|
||||
handleCatalogJson();
|
||||
|
||||
const parsed = JSON.parse(capturedOutput[0]) as Record<
|
||||
string,
|
||||
Array<Record<string, unknown>>
|
||||
>;
|
||||
const parsed = JSON.parse(capturedOutput[0]) as Record<string, Array<Record<string, unknown>>>;
|
||||
const allModels = Object.values(parsed).flat();
|
||||
|
||||
for (const model of allModels) {
|
||||
@@ -78,10 +79,7 @@ describe('cliproxy catalog --json output', () => {
|
||||
it('includes explicit false boolean values in output', () => {
|
||||
handleCatalogJson();
|
||||
|
||||
const parsed = JSON.parse(capturedOutput[0]) as Record<
|
||||
string,
|
||||
Array<Record<string, unknown>>
|
||||
>;
|
||||
const parsed = JSON.parse(capturedOutput[0]) as Record<string, Array<Record<string, unknown>>>;
|
||||
const allModels = Object.values(parsed).flat();
|
||||
|
||||
// Static catalog has models with extendedContext: false
|
||||
@@ -92,10 +90,7 @@ describe('cliproxy catalog --json output', () => {
|
||||
it('includes thinking configuration when present on models', () => {
|
||||
handleCatalogJson();
|
||||
|
||||
const parsed = JSON.parse(capturedOutput[0]) as Record<
|
||||
string,
|
||||
Array<Record<string, unknown>>
|
||||
>;
|
||||
const parsed = JSON.parse(capturedOutput[0]) as Record<string, Array<Record<string, unknown>>>;
|
||||
const allModels = Object.values(parsed).flat();
|
||||
|
||||
// Static catalog has thinking models (e.g. Claude Opus 4.6 Thinking)
|
||||
|
||||
Reference in new issue
Block a user