mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-07-10 00:03:03 +00:00
🕐 feat: Add promptCacheTtl model parameter for 1h/5m cache duration (#13835)
Some checks failed
Publish `librechat-data-provider` to NPM / pack (push) Waiting to run
Publish `librechat-data-provider` to NPM / publish-npm (push) Blocked by required conditions
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions
Sync Helm Chart Tags / Ignore non-main push (push) Waiting to run
Sync Helm Chart Tags / Sync chart tags (push) Waiting to run
Publish `@librechat/data-schemas` to NPM / pack (push) Has been cancelled
Publish `@librechat/data-schemas` to NPM / publish-npm (push) Has been cancelled
Some checks failed
Publish `librechat-data-provider` to NPM / pack (push) Waiting to run
Publish `librechat-data-provider` to NPM / publish-npm (push) Blocked by required conditions
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions
Sync Helm Chart Tags / Ignore non-main push (push) Waiting to run
Sync Helm Chart Tags / Sync chart tags (push) Waiting to run
Publish `@librechat/data-schemas` to NPM / pack (push) Has been cancelled
Publish `@librechat/data-schemas` to NPM / publish-npm (push) Has been cancelled
* 🕐 feat: Add promptCacheTtl model parameter for 1h/5m cache duration Adds a user-configurable `promptCacheTtl` parameter (dropdown: 5m | 1h) alongside the existing `promptCache` toggle for Anthropic, Bedrock, and OpenRouter endpoints. Default is undefined so the agents SDK applies its own default (1h), letting users opt down to the legacy 5m TTL. - data-provider: schema, parameterSettings dropdown, types, bedrock picks - data-schemas: convo/preset types + mongoose defaults - api: thread promptCacheTtl into anthropic + openai(OpenRouter) llmConfig - i18n: en translation keys for label/description/default placeholder - tests: anthropic llm.spec coverage for set + unset cases * 🔧 fix: Tie Bedrock promptCacheTtl to promptCache + thread OpenRouter TTL params (Codex review) - bedrock.ts: clear promptCacheTtl whenever promptCache is off/unsupported, so an unsupported 1h is never sent on a non-caching Bedrock request - openai/llm.ts: resolve promptCacheTtl through the same defaultParams/ addParams/dropParams machinery as promptCache (via promptCacheTtlValue) so OpenRouter custom endpoints can configure/override/drop it - tests: bedrock TTL-tied-to-promptCache cases; OpenRouter TTL default/add/drop * 🎨 style: Sort imports in openai/llm.spec.ts (CI sort-imports) * ✅ test: Prove OpenRouter TTL-only selection honors promptCache default (Codex review) OPENROUTER_DEFAULT_PARAMS injects promptCache:true into defaultParams, so a TTL-only dropdown selection (promptCacheTtl set, promptCache switch untouched) still resolves caching on and forwards the TTL. Add regression tests via the real getOpenAIConfig entry point: TTL-only -> promptCache+TTL both set; explicit promptCache:false -> both dropped. * 🔖 chore: Bump librechat-data-provider to 0.8.506 * 🔧 fix: Drop Anthropic promptCacheTtl when promptCache is dropped (Codex review) dropParams: ['promptCache'] deleted requestOptions.promptCache but left promptCacheTtl behind, so the admin opt-out path could still carry a TTL on a request with caching disabled. Clear the TTL alongside promptCache.
This commit is contained in:
parent
6a63531eb4
commit
268fcbb78d
17 changed files with 263 additions and 7 deletions
|
|
@ -226,6 +226,7 @@
|
|||
"com_endpoint_anthropic_effort": "Controls how much computational effort Claude applies. Lower effort saves tokens and reduces latency; higher effort produces more thorough responses. 'Max' enables the deepest reasoning on supported adaptive-thinking models.",
|
||||
"com_endpoint_anthropic_maxoutputtokens": "Maximum number of tokens that can be generated in the response. Specify a lower value for shorter responses and a higher value for longer responses. Note: models may stop before reaching this maximum.",
|
||||
"com_endpoint_anthropic_prompt_cache": "Prompt caching allows reusing large context or instructions across API calls, reducing costs and latency",
|
||||
"com_endpoint_anthropic_prompt_cache_ttl": "How long a cached prompt prefix stays warm between requests. Leave unset to use the provider default (1 hour). The 1-hour cache keeps the prefix warm across longer gaps at a higher one-time write cost; choose 5 minutes for the legacy behavior.",
|
||||
"com_endpoint_anthropic_temp": "Ranges from 0 to 1. Use temp closer to 0 for analytical / multiple choice, and closer to 1 for creative and generative tasks. We recommend altering this or Top P but not both.",
|
||||
"com_endpoint_anthropic_thinking": "Enables internal reasoning for supported Claude models. For newer models (Opus 4.6+), uses adaptive thinking controlled by the Effort parameter. For legacy models, requires \"Thinking Budget\" to be set and lower than \"Max Output Tokens\".",
|
||||
"com_endpoint_anthropic_thinking_budget": "Determines the max number of tokens Claude is allowed use for its internal reasoning process. Larger budgets can improve response quality by enabling more thorough analysis for complex problems, although Claude may not use the entire budget allocated, especially at ranges above 32K. This setting must be lower than \"Max Output Tokens.\"",
|
||||
|
|
@ -336,6 +337,8 @@
|
|||
"com_endpoint_presets": "presets",
|
||||
"com_endpoint_presets_clear_warning": "Are you sure you want to clear all presets? This is irreversible.",
|
||||
"com_endpoint_prompt_cache": "Use Prompt Caching",
|
||||
"com_endpoint_prompt_cache_ttl": "Prompt Cache Duration",
|
||||
"com_endpoint_prompt_cache_ttl_default": "Default (1 hour)",
|
||||
"com_endpoint_prompt_prefix": "Custom Instructions",
|
||||
"com_endpoint_prompt_prefix_assistants": "Additional Instructions",
|
||||
"com_endpoint_prompt_prefix_assistants_placeholder": "Set additional instructions or context on top of the Assistant's main instructions. Ignored if empty.",
|
||||
|
|
|
|||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -44177,7 +44177,7 @@
|
|||
},
|
||||
"packages/data-provider": {
|
||||
"name": "librechat-data-provider",
|
||||
"version": "0.8.505",
|
||||
"version": "0.8.506",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"axios": "^1.16.0",
|
||||
|
|
|
|||
|
|
@ -356,6 +356,46 @@ describe('getLLMConfig', () => {
|
|||
expect(result.llmConfig.promptCache).toBe(true);
|
||||
});
|
||||
|
||||
it('should pass promptCacheTtl to llmConfig when configured', () => {
|
||||
const result = getLLMConfig('test-api-key', {
|
||||
modelOptions: {
|
||||
model: 'claude-3-5-sonnet',
|
||||
promptCache: true,
|
||||
promptCacheTtl: '1h',
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.llmConfig.promptCache).toBe(true);
|
||||
expect((result.llmConfig as Record<string, unknown>).promptCacheTtl).toBe('1h');
|
||||
});
|
||||
|
||||
it('should omit promptCacheTtl when unset so the agents SDK applies its default', () => {
|
||||
const result = getLLMConfig('test-api-key', {
|
||||
modelOptions: {
|
||||
model: 'claude-3-5-sonnet',
|
||||
promptCache: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.llmConfig.promptCache).toBe(true);
|
||||
expect((result.llmConfig as Record<string, unknown>).promptCacheTtl).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should drop promptCacheTtl when promptCache is dropped via dropParams', () => {
|
||||
const result = getLLMConfig('test-api-key', {
|
||||
modelOptions: {
|
||||
model: 'claude-3-5-sonnet',
|
||||
promptCache: true,
|
||||
promptCacheTtl: '1h',
|
||||
},
|
||||
dropParams: ['promptCache'],
|
||||
});
|
||||
|
||||
/** A dropped cache must not leave an orphaned TTL on the request. */
|
||||
expect(result.llmConfig.promptCache).toBeUndefined();
|
||||
expect((result.llmConfig as Record<string, unknown>).promptCacheTtl).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle thinking and thinkingBudget options', () => {
|
||||
const result = getLLMConfig('test-api-key', {
|
||||
modelOptions: {
|
||||
|
|
|
|||
|
|
@ -114,6 +114,8 @@ function getLLMConfig(
|
|||
const systemOptions = {
|
||||
thinking: options.modelOptions?.thinking ?? anthropicSettings.thinking.default,
|
||||
promptCache: options.modelOptions?.promptCache ?? anthropicSettings.promptCache.default,
|
||||
promptCacheTtl:
|
||||
options.modelOptions?.promptCacheTtl ?? anthropicSettings.promptCacheTtl.default,
|
||||
thinkingBudget:
|
||||
options.modelOptions?.thinkingBudget ?? anthropicSettings.thinkingBudget.default,
|
||||
effort: options.modelOptions?.effort ?? anthropicSettings.effort.default,
|
||||
|
|
@ -126,6 +128,7 @@ function getLLMConfig(
|
|||
if (options.modelOptions) {
|
||||
delete options.modelOptions.thinking;
|
||||
delete options.modelOptions.promptCache;
|
||||
delete options.modelOptions.promptCacheTtl;
|
||||
delete options.modelOptions.thinkingBudget;
|
||||
delete options.modelOptions.effort;
|
||||
delete options.modelOptions.thinkingDisplay;
|
||||
|
|
@ -222,6 +225,10 @@ function getLLMConfig(
|
|||
/** Pass promptCache boolean for downstream cache_control application */
|
||||
if (supportsCacheControl) {
|
||||
(requestOptions as Record<string, unknown>).promptCache = true;
|
||||
/** Pass an explicit TTL when configured; otherwise the agents SDK defaults to 1h */
|
||||
if (systemOptions.promptCacheTtl != null) {
|
||||
(requestOptions as Record<string, unknown>).promptCacheTtl = systemOptions.promptCacheTtl;
|
||||
}
|
||||
}
|
||||
|
||||
const headers = getClaudeHeaders(requestOptions.model ?? '', supportsCacheControl);
|
||||
|
|
@ -297,6 +304,11 @@ function getLLMConfig(
|
|||
delete (requestOptions.invocationKwargs as Record<string, unknown>)[param];
|
||||
}
|
||||
});
|
||||
|
||||
/** A TTL is meaningless without caching — drop it alongside promptCache. */
|
||||
if (options.dropParams.includes('promptCache')) {
|
||||
delete (requestOptions as Record<string, unknown>).promptCacheTtl;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldOmitSamplingParameters) {
|
||||
|
|
|
|||
|
|
@ -920,6 +920,46 @@ describe('getOpenAIConfig', () => {
|
|||
expect(result.provider).toBe('openrouter');
|
||||
});
|
||||
|
||||
it('should honor a TTL-only selection for OpenRouter (promptCache defaulted on)', () => {
|
||||
/**
|
||||
* Reproduces selecting only the promptCacheTtl dropdown without toggling
|
||||
* the promptCache switch: modelOptions carries the TTL but not promptCache.
|
||||
* OPENROUTER_DEFAULT_PARAMS still resolves caching on, so the TTL survives.
|
||||
*/
|
||||
const result = getOpenAIConfig(
|
||||
mockApiKey,
|
||||
{
|
||||
modelOptions: {
|
||||
model: 'anthropic/claude-sonnet-4.6',
|
||||
promptCacheTtl: '1h',
|
||||
} as Record<string, unknown>,
|
||||
},
|
||||
'openrouter',
|
||||
);
|
||||
|
||||
expect(result.llmConfig.promptCache).toBe(true);
|
||||
expect((result.llmConfig as Record<string, unknown>).promptCacheTtl).toBe('1h');
|
||||
expect(result.provider).toBe('openrouter');
|
||||
});
|
||||
|
||||
it('should drop the OpenRouter TTL when promptCache is explicitly disabled', () => {
|
||||
const result = getOpenAIConfig(
|
||||
mockApiKey,
|
||||
{
|
||||
modelOptions: {
|
||||
model: 'anthropic/claude-sonnet-4.6',
|
||||
promptCache: false,
|
||||
promptCacheTtl: '1h',
|
||||
} as Record<string, unknown>,
|
||||
},
|
||||
'openrouter',
|
||||
);
|
||||
|
||||
expect(result.llmConfig.promptCache).toBeUndefined();
|
||||
expect((result.llmConfig as Record<string, unknown>).promptCacheTtl).toBeUndefined();
|
||||
expect(result.provider).toBe('openrouter');
|
||||
});
|
||||
|
||||
it('should handle web_search with OpenRouter using plugins format', () => {
|
||||
const modelOptions = {
|
||||
model: 'gpt-4',
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import {
|
|||
ReasoningSummary,
|
||||
ReasoningParameterFormat,
|
||||
} from 'librechat-data-provider';
|
||||
import { getOpenAILLMConfig, extractDefaultParams, applyDefaultParams } from './llm';
|
||||
import type * as t from '~/types';
|
||||
import { getOpenAILLMConfig, extractDefaultParams, applyDefaultParams } from './llm';
|
||||
|
||||
describe('getOpenAILLMConfig', () => {
|
||||
describe('Basic Configuration', () => {
|
||||
|
|
@ -1100,6 +1100,44 @@ describe('getOpenAILLMConfig', () => {
|
|||
expect(dropped.llmConfig).not.toHaveProperty('promptCache');
|
||||
});
|
||||
|
||||
it('should resolve OpenRouter promptCacheTtl default/add/drop params', () => {
|
||||
const fromDefault = getOpenAILLMConfig({
|
||||
apiKey: 'test-api-key',
|
||||
streaming: true,
|
||||
useOpenRouter: true,
|
||||
defaultParams: { promptCache: true, promptCacheTtl: '1h' },
|
||||
modelOptions: {
|
||||
model: 'anthropic/claude-sonnet-4.6',
|
||||
},
|
||||
});
|
||||
const overridden = getOpenAILLMConfig({
|
||||
apiKey: 'test-api-key',
|
||||
streaming: true,
|
||||
useOpenRouter: true,
|
||||
defaultParams: { promptCache: true, promptCacheTtl: '1h' },
|
||||
addParams: { promptCacheTtl: '5m' },
|
||||
modelOptions: {
|
||||
model: 'anthropic/claude-sonnet-4.6',
|
||||
},
|
||||
});
|
||||
const dropped = getOpenAILLMConfig({
|
||||
apiKey: 'test-api-key',
|
||||
streaming: true,
|
||||
useOpenRouter: true,
|
||||
defaultParams: { promptCache: true, promptCacheTtl: '1h' },
|
||||
dropParams: ['promptCacheTtl'],
|
||||
modelOptions: {
|
||||
model: 'anthropic/claude-sonnet-4.6',
|
||||
},
|
||||
});
|
||||
|
||||
expect((fromDefault.llmConfig as Record<string, unknown>).promptCacheTtl).toBe('1h');
|
||||
expect((overridden.llmConfig as Record<string, unknown>).promptCacheTtl).toBe('5m');
|
||||
/** promptCache stays on, but the TTL is dropped so the SDK applies its default */
|
||||
expect(dropped.llmConfig).toHaveProperty('promptCache', true);
|
||||
expect((dropped.llmConfig as Record<string, unknown>).promptCacheTtl).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should set includeReasoningContent for DeepSeek models via OpenRouter', () => {
|
||||
const result = getOpenAILLMConfig({
|
||||
apiKey: 'test-api-key',
|
||||
|
|
|
|||
|
|
@ -454,10 +454,13 @@ export function getOpenAILLMConfig({
|
|||
verbosity,
|
||||
web_search,
|
||||
promptCache,
|
||||
promptCacheTtl,
|
||||
frequency_penalty,
|
||||
presence_penalty,
|
||||
...modelOptions
|
||||
} = cleanedModelOptions as Partial<t.OpenAIParameters & { promptCache?: boolean }>;
|
||||
} = cleanedModelOptions as Partial<
|
||||
t.OpenAIParameters & { promptCache?: boolean; promptCacheTtl?: '5m' | '1h' }
|
||||
>;
|
||||
|
||||
const llmConfig = Object.assign(
|
||||
{
|
||||
|
|
@ -488,6 +491,7 @@ export function getOpenAILLMConfig({
|
|||
|
||||
let enableWebSearch = web_search;
|
||||
let enablePromptCache = promptCache;
|
||||
let promptCacheTtlValue = promptCacheTtl;
|
||||
|
||||
/** Apply defaultParams first - only if fields are undefined */
|
||||
if (defaultParams && typeof defaultParams === 'object') {
|
||||
|
|
@ -504,6 +508,12 @@ export function getOpenAILLMConfig({
|
|||
}
|
||||
continue;
|
||||
}
|
||||
if (key === 'promptCacheTtl') {
|
||||
if (promptCacheTtlValue === undefined && (value === '5m' || value === '1h')) {
|
||||
promptCacheTtlValue = value;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (key === 'reasoning_effort') {
|
||||
if (!reasoningEffort && typeof value === 'string') {
|
||||
reasoningEffort = value as OpenAILLMConfig['reasoning_effort'];
|
||||
|
|
@ -555,6 +565,12 @@ export function getOpenAILLMConfig({
|
|||
}
|
||||
continue;
|
||||
}
|
||||
if (key === 'promptCacheTtl') {
|
||||
if (value === '5m' || value === '1h') {
|
||||
promptCacheTtlValue = value;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (key === 'reasoning_effort') {
|
||||
if (typeof value === 'string' || value == null) {
|
||||
reasoningEffort = value as OpenAILLMConfig['reasoning_effort'];
|
||||
|
|
@ -617,6 +633,9 @@ export function getOpenAILLMConfig({
|
|||
if (dropParams && dropParams.includes('promptCache')) {
|
||||
enablePromptCache = false;
|
||||
}
|
||||
if (dropParams && dropParams.includes('promptCacheTtl')) {
|
||||
promptCacheTtlValue = undefined;
|
||||
}
|
||||
|
||||
if (useOpenRouter && enableWebSearch) {
|
||||
/** OpenRouter expects web search as a plugins parameter */
|
||||
|
|
@ -629,6 +648,10 @@ export function getOpenAILLMConfig({
|
|||
}
|
||||
if (useOpenRouter && enablePromptCache === true) {
|
||||
llmConfig.promptCache = true;
|
||||
/** Pass an explicit TTL when configured; otherwise the agents SDK defaults to 1h */
|
||||
if (promptCacheTtlValue != null) {
|
||||
llmConfig.promptCacheTtl = promptCacheTtlValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!useOpenRouter) {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ export type OAIClientOptions = Omit<OpenAIClientOptions, 'verbosity'> & {
|
|||
/** Replays `reasoning_content` on tool-bearing turns (DeepSeek thinking-mode, #13366). */
|
||||
includeReasoningContent?: boolean;
|
||||
promptCache?: boolean;
|
||||
promptCacheTtl?: '5m' | '1h';
|
||||
_lc_stream_delay?: number;
|
||||
verbosity?: string | null;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "librechat-data-provider",
|
||||
"version": "0.8.505",
|
||||
"version": "0.8.506",
|
||||
"description": "data services for librechat apps",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.mjs",
|
||||
|
|
|
|||
|
|
@ -1271,4 +1271,34 @@ describe('bedrockInputParser', () => {
|
|||
expect(amrf.reasoning_config).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('promptCacheTtl tied to promptCache', () => {
|
||||
test('preserves promptCacheTtl when caching is enabled (claude default)', () => {
|
||||
const result = bedrockInputParser.parse({
|
||||
model: 'anthropic.claude-opus-4-6-v1',
|
||||
promptCacheTtl: '1h',
|
||||
}) as Record<string, unknown>;
|
||||
expect(result.promptCache).toBe(true);
|
||||
expect(result.promptCacheTtl).toBe('1h');
|
||||
});
|
||||
|
||||
test('clears promptCacheTtl when promptCache is explicitly disabled', () => {
|
||||
const result = bedrockInputParser.parse({
|
||||
model: 'anthropic.claude-opus-4-6-v1',
|
||||
promptCache: false,
|
||||
promptCacheTtl: '1h',
|
||||
}) as Record<string, unknown>;
|
||||
expect(result.promptCacheTtl).toBeUndefined();
|
||||
});
|
||||
|
||||
test('clears promptCache and promptCacheTtl for non-caching models', () => {
|
||||
const result = bedrockInputParser.parse({
|
||||
model: 'meta.llama3-1-70b-instruct-v1:0',
|
||||
promptCache: true,
|
||||
promptCacheTtl: '1h',
|
||||
}) as Record<string, unknown>;
|
||||
expect(result.promptCache).toBeUndefined();
|
||||
expect(result.promptCacheTtl).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ export const bedrockInputSchema = s.tConversationSchema
|
|||
thinkingDisplay: true,
|
||||
reasoning_effort: true,
|
||||
promptCache: true,
|
||||
promptCacheTtl: true,
|
||||
/* Catch-all fields */
|
||||
topK: true,
|
||||
additionalModelRequestFields: true,
|
||||
|
|
@ -312,6 +313,7 @@ export const bedrockInputParser = s.tConversationSchema
|
|||
thinkingDisplay: true,
|
||||
reasoning_effort: true,
|
||||
promptCache: true,
|
||||
promptCacheTtl: true,
|
||||
/* Catch-all fields */
|
||||
topK: true,
|
||||
additionalModelRequestFields: true,
|
||||
|
|
@ -336,6 +338,7 @@ export const bedrockInputParser = s.tConversationSchema
|
|||
'topP',
|
||||
'stop',
|
||||
'promptCache',
|
||||
'promptCacheTtl',
|
||||
];
|
||||
|
||||
const additionalFields: Record<string, unknown> = {};
|
||||
|
|
@ -503,6 +506,15 @@ export const bedrockInputParser = s.tConversationSchema
|
|||
typedData.promptCache = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A cache TTL is meaningless without caching — tie it to promptCache. When
|
||||
* caching is off or unsupported for the model (cleared above), drop the TTL
|
||||
* so an unsupported `1h` is never sent on a non-caching Bedrock request.
|
||||
*/
|
||||
if (typedData.promptCache !== true) {
|
||||
typedData.promptCacheTtl = undefined;
|
||||
}
|
||||
|
||||
if (Object.keys(additionalFields).length > 0) {
|
||||
typedData.additionalModelRequestFields = {
|
||||
...((typedData.additionalModelRequestFields as Record<string, unknown> | undefined) || {}),
|
||||
|
|
|
|||
|
|
@ -406,6 +406,22 @@ const anthropic: Record<string, SettingDefinition> = {
|
|||
showDefault: false,
|
||||
columnSpan: 2,
|
||||
},
|
||||
promptCacheTtl: {
|
||||
key: 'promptCacheTtl',
|
||||
label: 'com_endpoint_prompt_cache_ttl',
|
||||
labelCode: true,
|
||||
description: 'com_endpoint_anthropic_prompt_cache_ttl',
|
||||
descriptionCode: true,
|
||||
type: 'enum',
|
||||
default: anthropicSettings.promptCacheTtl.default,
|
||||
options: ['5m', '1h'],
|
||||
component: 'dropdown',
|
||||
optionType: 'conversation',
|
||||
showDefault: false,
|
||||
placeholder: 'com_endpoint_prompt_cache_ttl_default',
|
||||
placeholderCode: true,
|
||||
columnSpan: 2,
|
||||
},
|
||||
thinking: {
|
||||
key: 'thinking',
|
||||
label: 'com_endpoint_thinking',
|
||||
|
|
@ -552,6 +568,22 @@ const bedrock: Record<string, SettingDefinition> = {
|
|||
showDefault: false,
|
||||
columnSpan: 2,
|
||||
},
|
||||
promptCacheTtl: {
|
||||
key: 'promptCacheTtl',
|
||||
label: 'com_endpoint_prompt_cache_ttl',
|
||||
labelCode: true,
|
||||
description: 'com_endpoint_anthropic_prompt_cache_ttl',
|
||||
descriptionCode: true,
|
||||
type: 'enum',
|
||||
default: undefined,
|
||||
options: ['5m', '1h'],
|
||||
component: 'dropdown',
|
||||
optionType: 'conversation',
|
||||
showDefault: false,
|
||||
placeholder: 'com_endpoint_prompt_cache_ttl_default',
|
||||
placeholderCode: true,
|
||||
columnSpan: 2,
|
||||
},
|
||||
reasoning_effort: {
|
||||
key: 'reasoning_effort',
|
||||
label: 'com_endpoint_reasoning_effort',
|
||||
|
|
@ -792,7 +824,11 @@ const openAI: SettingsConfiguration = [
|
|||
librechat.fileTokenLimit,
|
||||
];
|
||||
|
||||
const openRouter: SettingsConfiguration = [...openAI, anthropic.promptCache];
|
||||
const openRouter: SettingsConfiguration = [
|
||||
...openAI,
|
||||
anthropic.promptCache,
|
||||
anthropic.promptCacheTtl,
|
||||
];
|
||||
|
||||
const openAICol1: SettingsConfiguration = [
|
||||
baseDefinitions.model as SettingDefinition,
|
||||
|
|
@ -829,6 +865,7 @@ const anthropicConfig: SettingsConfiguration = [
|
|||
anthropic.topK,
|
||||
librechat.resendFiles,
|
||||
anthropic.promptCache,
|
||||
anthropic.promptCacheTtl,
|
||||
anthropic.thinking,
|
||||
anthropic.thinkingBudget,
|
||||
anthropic.effort,
|
||||
|
|
@ -851,6 +888,7 @@ const anthropicCol2: SettingsConfiguration = [
|
|||
anthropic.topK,
|
||||
librechat.resendFiles,
|
||||
anthropic.promptCache,
|
||||
anthropic.promptCacheTtl,
|
||||
anthropic.thinking,
|
||||
anthropic.thinkingBudget,
|
||||
anthropic.effort,
|
||||
|
|
@ -871,6 +909,7 @@ const bedrockAnthropic: SettingsConfiguration = [
|
|||
librechat.resendFiles,
|
||||
bedrock.region,
|
||||
bedrock.promptCache,
|
||||
bedrock.promptCacheTtl,
|
||||
anthropic.thinking,
|
||||
anthropic.thinkingBudget,
|
||||
anthropic.effort,
|
||||
|
|
@ -911,6 +950,7 @@ const bedrockGeneral: SettingsConfiguration = [
|
|||
librechat.resendFiles,
|
||||
bedrock.region,
|
||||
bedrock.promptCache,
|
||||
bedrock.promptCacheTtl,
|
||||
librechat.fileTokenLimit,
|
||||
];
|
||||
|
||||
|
|
@ -930,6 +970,7 @@ const bedrockAnthropicCol2: SettingsConfiguration = [
|
|||
librechat.resendFiles,
|
||||
bedrock.region,
|
||||
bedrock.promptCache,
|
||||
bedrock.promptCacheTtl,
|
||||
anthropic.thinking,
|
||||
anthropic.thinkingBudget,
|
||||
anthropic.effort,
|
||||
|
|
@ -982,6 +1023,7 @@ const bedrockGeneralCol2: SettingsConfiguration = [
|
|||
librechat.resendFiles,
|
||||
bedrock.region,
|
||||
bedrock.promptCache,
|
||||
bedrock.promptCacheTtl,
|
||||
librechat.fileTokenLimit,
|
||||
];
|
||||
|
||||
|
|
@ -1092,7 +1134,7 @@ export const presetSettings: Record<
|
|||
[EModelEndpoint.custom]: openAIColumns,
|
||||
[Providers.OPENROUTER]: {
|
||||
col1: openAICol1,
|
||||
col2: [...openAICol2, anthropic.promptCache],
|
||||
col2: [...openAICol2, anthropic.promptCache, anthropic.promptCacheTtl],
|
||||
},
|
||||
[EModelEndpoint.anthropic]: {
|
||||
col1: anthropicCol1,
|
||||
|
|
|
|||
|
|
@ -520,6 +520,9 @@ export const anthropicSettings = {
|
|||
promptCache: {
|
||||
default: true as const,
|
||||
},
|
||||
promptCacheTtl: {
|
||||
default: undefined,
|
||||
},
|
||||
thinking: {
|
||||
default: true as const,
|
||||
},
|
||||
|
|
@ -909,6 +912,7 @@ export const tConversationSchema = z.object({
|
|||
max_tokens: coerceNumber.optional(),
|
||||
/* Anthropic */
|
||||
promptCache: z.boolean().optional(),
|
||||
promptCacheTtl: z.enum(['5m', '1h']).optional(),
|
||||
system: z.string().optional(),
|
||||
thinking: z.boolean().optional(),
|
||||
thinkingBudget: coerceNumber.optional(),
|
||||
|
|
@ -1062,6 +1066,7 @@ export const tQueryParamsSchema = tConversationSchema
|
|||
maxOutputTokens: true,
|
||||
/** @endpoints anthropic */
|
||||
promptCache: true,
|
||||
promptCacheTtl: true,
|
||||
thinking: true,
|
||||
thinkingBudget: true,
|
||||
thinkingLevel: true,
|
||||
|
|
@ -1368,7 +1373,7 @@ export const openAISchema = openAIBaseSchema
|
|||
.catch(() => ({}));
|
||||
|
||||
export const openRouterSchema = openAIBaseSchema
|
||||
.merge(tConversationSchema.pick({ promptCache: true }))
|
||||
.merge(tConversationSchema.pick({ promptCache: true, promptCacheTtl: true }))
|
||||
.transform((obj: Partial<TConversation>) => removeNullishValues(obj, true))
|
||||
.catch(() => ({}));
|
||||
|
||||
|
|
@ -1403,6 +1408,7 @@ export const anthropicBaseSchema = tConversationSchema.pick({
|
|||
topK: true,
|
||||
resendFiles: true,
|
||||
promptCache: true,
|
||||
promptCacheTtl: true,
|
||||
thinking: true,
|
||||
thinkingBudget: true,
|
||||
effort: true,
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ export type TEndpointOption = Pick<
|
|||
| 'additionalModelRequestFields'
|
||||
// Anthropic-specific
|
||||
| 'promptCache'
|
||||
| 'promptCacheTtl'
|
||||
| 'thinking'
|
||||
| 'thinkingBudget'
|
||||
| 'thinkingLevel'
|
||||
|
|
|
|||
|
|
@ -87,6 +87,9 @@ export const conversationPreset: {
|
|||
promptCache: {
|
||||
type: BooleanConstructor;
|
||||
};
|
||||
promptCacheTtl: {
|
||||
type: StringConstructor;
|
||||
};
|
||||
thinking: {
|
||||
type: BooleanConstructor;
|
||||
};
|
||||
|
|
@ -256,6 +259,9 @@ export const conversationPreset: {
|
|||
promptCache: {
|
||||
type: Boolean,
|
||||
},
|
||||
promptCacheTtl: {
|
||||
type: String,
|
||||
},
|
||||
thinking: {
|
||||
type: Boolean,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ export interface IPreset extends Document {
|
|||
file_ids?: string[];
|
||||
resendImages?: boolean;
|
||||
promptCache?: boolean;
|
||||
promptCacheTtl?: '5m' | '1h';
|
||||
thinking?: boolean;
|
||||
thinkingBudget?: number;
|
||||
effort?: string;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export interface IConversation extends Document {
|
|||
file_ids?: string[];
|
||||
resendImages?: boolean;
|
||||
promptCache?: boolean;
|
||||
promptCacheTtl?: '5m' | '1h';
|
||||
thinking?: boolean;
|
||||
thinkingBudget?: number;
|
||||
effort?: string;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue