mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-06 21:25:34 +08:00
Compare commits
4 Commits
fix/tool-r
...
chore/upda
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3d0f9037d | ||
|
|
957f53fb99 | ||
|
|
cdcac182d4 | ||
|
|
94785bfa57 |
@@ -11,7 +11,8 @@ export const CLAUDE_MODELS = {
|
|||||||
{
|
{
|
||||||
value: "default",
|
value: "default",
|
||||||
label: "Default (recommended)",
|
label: "Default (recommended)",
|
||||||
description: "Use the default model (currently Opus 4.8 (1M context)) · $5/$25 per Mtok",
|
description:
|
||||||
|
"Use the default model (currently Opus 4.8 (1M context)) · $5/$25 per Mtok",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "sonnet",
|
value: "sonnet",
|
||||||
@@ -23,6 +24,12 @@ export const CLAUDE_MODELS = {
|
|||||||
label: "Sonnet (1M context)",
|
label: "Sonnet (1M context)",
|
||||||
description: "Sonnet 4.6 for long sessions · $3/$15 per Mtok",
|
description: "Sonnet 4.6 for long sessions · $3/$15 per Mtok",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: "opus[1m]",
|
||||||
|
label: "Opus 4.8 (1M context)",
|
||||||
|
description:
|
||||||
|
"Opus 4.8 with 1M context · Most capable for complex work · $5/$25 per Mtok",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: "haiku",
|
value: "haiku",
|
||||||
label: "Haiku",
|
label: "Haiku",
|
||||||
|
|||||||
@@ -18,18 +18,23 @@ export const CLAUDE_FALLBACK_MODELS: ProviderModelsDefinition = {
|
|||||||
{
|
{
|
||||||
value: 'default',
|
value: 'default',
|
||||||
label: 'Default (recommended)',
|
label: 'Default (recommended)',
|
||||||
description: 'Use the default model (currently Opus 4.7 (1M context)) · $5/$25 per Mtok',
|
description: 'Use the default model (currently Opus 4.8 (1M context)) · $5/$25 per Mtok',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'sonnet',
|
value: "sonnet",
|
||||||
label: 'Sonnet',
|
label: "Sonnet",
|
||||||
description: 'Sonnet 4.6 · Best for everyday tasks · $3/$15 per Mtok',
|
description: "Sonnet 4.6 · Best for everyday tasks · $3/$15 per Mtok",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'sonnet[1m]',
|
value: 'sonnet[1m]',
|
||||||
label: 'Sonnet (1M context)',
|
label: 'Sonnet (1M context)',
|
||||||
description: 'Sonnet 4.6 for long sessions · $3/$15 per Mtok',
|
description: 'Sonnet 4.6 for long sessions · $3/$15 per Mtok',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: 'opus[1m]',
|
||||||
|
label: 'Opus 4.8 (1M context)',
|
||||||
|
description: 'Opus 4.8 with 1M context · Most capable for complex work · $5/$25 per Mtok',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: 'haiku',
|
value: 'haiku',
|
||||||
label: 'Haiku',
|
label: 'Haiku',
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { readProviderSessionActiveModelChange } from '@/shared/utils.js';
|
|||||||
|
|
||||||
export const PROVIDER_MODELS_CACHE_TTL_MS = 3 * 24 * 60 * 60 * 1000;
|
export const PROVIDER_MODELS_CACHE_TTL_MS = 3 * 24 * 60 * 60 * 1000;
|
||||||
const PROVIDER_MODELS_CACHE_VERSION = 1;
|
const PROVIDER_MODELS_CACHE_VERSION = 1;
|
||||||
|
const UNCACHED_PROVIDERS = new Set<LLMProvider>(['claude']);
|
||||||
|
|
||||||
type ProviderModelsServiceDependencies = {
|
type ProviderModelsServiceDependencies = {
|
||||||
resolveProvider?: (provider: LLMProvider) => Pick<IProvider, 'models'>;
|
resolveProvider?: (provider: LLMProvider) => Pick<IProvider, 'models'>;
|
||||||
@@ -232,10 +233,42 @@ export const createProviderModelsService = (dependencies: ProviderModelsServiceD
|
|||||||
return request;
|
return request;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadDirectModels = (
|
||||||
|
provider: LLMProvider,
|
||||||
|
): Promise<ProviderModelsResult> => {
|
||||||
|
const request = resolveProvider(provider).models.getSupportedModels()
|
||||||
|
.then((models) => {
|
||||||
|
const currentTime = now();
|
||||||
|
return {
|
||||||
|
models,
|
||||||
|
cache: {
|
||||||
|
updatedAt: new Date(currentTime).toISOString(),
|
||||||
|
expiresAt: new Date(currentTime).toISOString(),
|
||||||
|
source: 'fresh' as const,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
pendingRequests.delete(provider);
|
||||||
|
});
|
||||||
|
|
||||||
|
pendingRequests.set(provider, request);
|
||||||
|
return request;
|
||||||
|
};
|
||||||
|
|
||||||
const getProviderModels = async (
|
const getProviderModels = async (
|
||||||
provider: LLMProvider,
|
provider: LLMProvider,
|
||||||
options: ProviderModelsOptions = {},
|
options: ProviderModelsOptions = {},
|
||||||
): Promise<ProviderModelsResult> => {
|
): Promise<ProviderModelsResult> => {
|
||||||
|
if (UNCACHED_PROVIDERS.has(provider)) {
|
||||||
|
const pendingRequest = pendingRequests.get(provider);
|
||||||
|
if (pendingRequest) {
|
||||||
|
return pendingRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadDirectModels(provider);
|
||||||
|
}
|
||||||
|
|
||||||
if (options.bypassCache) {
|
if (options.bypassCache) {
|
||||||
const pendingRequest = pendingRequests.get(provider);
|
const pendingRequest = pendingRequests.get(provider);
|
||||||
if (pendingRequest) {
|
if (pendingRequest) {
|
||||||
|
|||||||
@@ -130,6 +130,37 @@ test('provider models are cached for the three-day ttl', async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('claude provider models are always loaded directly from the provider', async () => {
|
||||||
|
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'provider-model-cache-claude-direct-'));
|
||||||
|
let loadCount = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const service = createProviderModelsService({
|
||||||
|
cachePath: path.join(tempRoot, 'models-cache.json'),
|
||||||
|
resolveProvider: (provider) => ({
|
||||||
|
models: {
|
||||||
|
getSupportedModels: async () => {
|
||||||
|
loadCount += 1;
|
||||||
|
return createModels(`${provider}-${loadCount}`);
|
||||||
|
},
|
||||||
|
getCurrentActiveModel: async () => createCurrentActiveModel(`${provider}-active`),
|
||||||
|
changeActiveModel: async (input) => createSessionActiveModelChange(provider, input),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const first = await service.getProviderModels('claude');
|
||||||
|
const second = await service.getProviderModels('claude');
|
||||||
|
|
||||||
|
assert.equal(loadCount, 2);
|
||||||
|
assert.equal(first.models.DEFAULT, 'claude-1');
|
||||||
|
assert.equal(second.models.DEFAULT, 'claude-2');
|
||||||
|
assert.equal(second.cache.source, 'fresh');
|
||||||
|
} finally {
|
||||||
|
await rm(tempRoot, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('provider model cache is persisted across service instances', async () => {
|
test('provider model cache is persisted across service instances', async () => {
|
||||||
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'provider-model-cache-file-'));
|
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'provider-model-cache-file-'));
|
||||||
const cachePath = path.join(tempRoot, 'models-cache.json');
|
const cachePath = path.join(tempRoot, 'models-cache.json');
|
||||||
|
|||||||
Reference in New Issue
Block a user