mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-02 10:19:37 +00:00
feat(cliproxy): add 'max' thinking level for Claude Opus 4.7
Anthropic exposes `max` as a distinct adaptive-thinking effort above `xhigh` on Opus 4.7. Previously the validator aliased user input `max` down to `xhigh`, so users couldn't reach the real top-tier effort through CCS. Extend the validator: - Add `max` to VALID_THINKING_LEVELS and THINKING_LEVEL_RANK (rank 6, above xhigh) - Add `max` to THINKING_LEVEL_BUDGETS (65536, CCS-internal numeric mapping for closest-level lookups) - Widen ThinkingSupport.maxLevel union to include 'max' The existing `max: 'xhigh'` alias in findClosestLevel is kept as a graceful fallback for models whose levels list does not include `max` (e.g. Codex `gpt-5.4`), because exact-match on validLevels takes priority — so Opus 4.7 returns `max` directly while Codex still maps `max` -> `xhigh`. Update the claude.claude-opus-4-7 catalog entry to expose `['low', 'medium', 'high', 'xhigh', 'max']` with `maxLevel: 'max'`. Built [OnSteroids](https://onsteroids.ai) Co-Authored-By: OnSteroids <built@onsteroids.ai>
This commit is contained in:
co-authored by
OnSteroids
parent
46920dbc08
commit
45fe7ab086
@@ -33,7 +33,7 @@ export interface ThinkingSupport {
|
|||||||
/** Valid level names (for levels type) */
|
/** Valid level names (for levels type) */
|
||||||
levels?: string[];
|
levels?: string[];
|
||||||
/** Maximum reasoning effort level (caps effort at this level for levels type) */
|
/** Maximum reasoning effort level (caps effort at this level for levels type) */
|
||||||
maxLevel?: 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
|
maxLevel?: 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
||||||
/** Whether zero/disabled thinking is allowed */
|
/** Whether zero/disabled thinking is allowed */
|
||||||
zeroAllowed?: boolean;
|
zeroAllowed?: boolean;
|
||||||
/** Whether dynamic/auto thinking is allowed */
|
/** Whether dynamic/auto thinking is allowed */
|
||||||
@@ -298,10 +298,11 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
|
|||||||
// Opus 4.7 only supports adaptive thinking on the Anthropic API; manual
|
// Opus 4.7 only supports adaptive thinking on the Anthropic API; manual
|
||||||
// thinking.type: "enabled" with budget_tokens is rejected with 400.
|
// thinking.type: "enabled" with budget_tokens is rejected with 400.
|
||||||
// Expose effort levels; the proxy translates these into adaptive effort.
|
// Expose effort levels; the proxy translates these into adaptive effort.
|
||||||
|
// `max` is a distinct adaptive effort above `xhigh` exposed by Anthropic.
|
||||||
thinking: {
|
thinking: {
|
||||||
type: 'levels',
|
type: 'levels',
|
||||||
levels: ['low', 'medium', 'high', 'xhigh'],
|
levels: ['low', 'medium', 'high', 'xhigh', 'max'],
|
||||||
maxLevel: 'xhigh',
|
maxLevel: 'max',
|
||||||
dynamicAllowed: true,
|
dynamicAllowed: true,
|
||||||
},
|
},
|
||||||
extendedContext: true,
|
extendedContext: true,
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ export interface ThinkingValidationResult {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Named thinking level mappings to budget values (when converting level→budget)
|
* Named thinking level mappings to budget values (when converting level→budget)
|
||||||
|
*
|
||||||
|
* `max` sits above `xhigh` to represent unconstrained thinking (Claude Opus 4.7,
|
||||||
|
* Mythos). The numeric value is a CCS-internal mapping, not an Anthropic wire
|
||||||
|
* value: Opus 4.7 uses adaptive thinking with an effort string, and other
|
||||||
|
* max-capable models already treat the level as a qualitative cap.
|
||||||
*/
|
*/
|
||||||
export const THINKING_LEVEL_BUDGETS: Record<string, number> = {
|
export const THINKING_LEVEL_BUDGETS: Record<string, number> = {
|
||||||
minimal: 512,
|
minimal: 512,
|
||||||
@@ -39,6 +44,7 @@ export const THINKING_LEVEL_BUDGETS: Record<string, number> = {
|
|||||||
medium: 8192,
|
medium: 8192,
|
||||||
high: 24576,
|
high: 24576,
|
||||||
xhigh: 32768,
|
xhigh: 32768,
|
||||||
|
max: 65536,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,12 +56,21 @@ export const THINKING_LEVEL_RANK: Record<string, number> = {
|
|||||||
medium: 3,
|
medium: 3,
|
||||||
high: 4,
|
high: 4,
|
||||||
xhigh: 5,
|
xhigh: 5,
|
||||||
|
max: 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Valid thinking level names
|
* Valid thinking level names
|
||||||
*/
|
*/
|
||||||
export const VALID_THINKING_LEVELS = ['minimal', 'low', 'medium', 'high', 'xhigh', 'auto'] as const;
|
export const VALID_THINKING_LEVELS = [
|
||||||
|
'minimal',
|
||||||
|
'low',
|
||||||
|
'medium',
|
||||||
|
'high',
|
||||||
|
'xhigh',
|
||||||
|
'max',
|
||||||
|
'auto',
|
||||||
|
] as const;
|
||||||
export type ThinkingLevel = (typeof VALID_THINKING_LEVELS)[number];
|
export type ThinkingLevel = (typeof VALID_THINKING_LEVELS)[number];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -121,7 +136,12 @@ function findClosestLevel(input: string, validLevels: string[]): string | undefi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Common aliases
|
// Common aliases.
|
||||||
|
//
|
||||||
|
// `max: 'xhigh'` is a graceful fallback for models whose levels list does not
|
||||||
|
// include `max` (e.g. Codex `gpt-5.4`). Exact match above takes priority, so
|
||||||
|
// Opus 4.7 (which has `max` in its validLevels) returns `max` directly while
|
||||||
|
// Codex still maps `max` → `xhigh`.
|
||||||
const aliases: Record<string, string> = {
|
const aliases: Record<string, string> = {
|
||||||
min: 'minimal',
|
min: 'minimal',
|
||||||
lo: 'low',
|
lo: 'low',
|
||||||
|
|||||||
@@ -150,8 +150,8 @@ describe('Model Catalog', () => {
|
|||||||
// Opus 4.7 requires adaptive thinking (type: 'levels'); manual budget_tokens
|
// Opus 4.7 requires adaptive thinking (type: 'levels'); manual budget_tokens
|
||||||
// is rejected by the Anthropic API with 400. Extended (1M) context is available.
|
// is rejected by the Anthropic API with 400. Extended (1M) context is available.
|
||||||
assert.strictEqual(opus47.thinking.type, 'levels');
|
assert.strictEqual(opus47.thinking.type, 'levels');
|
||||||
assert.deepStrictEqual(opus47.thinking.levels, ['low', 'medium', 'high', 'xhigh']);
|
assert.deepStrictEqual(opus47.thinking.levels, ['low', 'medium', 'high', 'xhigh', 'max']);
|
||||||
assert.strictEqual(opus47.thinking.maxLevel, 'xhigh');
|
assert.strictEqual(opus47.thinking.maxLevel, 'max');
|
||||||
assert.strictEqual(opus47.extendedContext, true);
|
assert.strictEqual(opus47.extendedContext, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ describe('Thinking Validator', () => {
|
|||||||
expect(VALID_THINKING_LEVELS).toContain('medium');
|
expect(VALID_THINKING_LEVELS).toContain('medium');
|
||||||
expect(VALID_THINKING_LEVELS).toContain('high');
|
expect(VALID_THINKING_LEVELS).toContain('high');
|
||||||
expect(VALID_THINKING_LEVELS).toContain('xhigh');
|
expect(VALID_THINKING_LEVELS).toContain('xhigh');
|
||||||
|
expect(VALID_THINKING_LEVELS).toContain('max');
|
||||||
expect(VALID_THINKING_LEVELS).toContain('auto');
|
expect(VALID_THINKING_LEVELS).toContain('auto');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -38,6 +39,24 @@ describe('Thinking Validator', () => {
|
|||||||
expect(THINKING_LEVEL_BUDGETS.medium).toBe(8192);
|
expect(THINKING_LEVEL_BUDGETS.medium).toBe(8192);
|
||||||
expect(THINKING_LEVEL_BUDGETS.high).toBe(24576);
|
expect(THINKING_LEVEL_BUDGETS.high).toBe(24576);
|
||||||
expect(THINKING_LEVEL_BUDGETS.xhigh).toBe(32768);
|
expect(THINKING_LEVEL_BUDGETS.xhigh).toBe(32768);
|
||||||
|
// `max` sits above xhigh — unconstrained thinking on Opus 4.7 / Mythos
|
||||||
|
expect(THINKING_LEVEL_BUDGETS.max).toBeGreaterThan(THINKING_LEVEL_BUDGETS.xhigh);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should treat max as a distinct top tier on models that list it (Opus 4.7)', () => {
|
||||||
|
// Opus 4.7 exposes both xhigh and max; max must not collapse into xhigh.
|
||||||
|
const result = validateThinking('claude', 'claude-opus-4-7', 'max');
|
||||||
|
expect(result.valid).toBe(true);
|
||||||
|
expect(result.value).toBe('max');
|
||||||
|
expect(result.warning).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should still alias max -> xhigh for models without a max level (backcompat)', () => {
|
||||||
|
// Codex catalog uses ['low','medium','high','xhigh'] with maxLevel 'xhigh'.
|
||||||
|
// User input "max" should map down to xhigh rather than be rejected.
|
||||||
|
const result = validateThinking('codex', 'gpt-5.4', 'max');
|
||||||
|
expect(result.valid).toBe(true);
|
||||||
|
expect(result.value).toBe('xhigh');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should export off values', () => {
|
it('should export off values', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user