* ✨ feat: Add `defaultPinnedTools` interface config for default tool & MCP pinning
Adds an `interface.defaultPinnedTools` string array letting admins pin tools and the MCP servers dropdown to the prompt bar by default for all users.
- Tool keys (artifacts, execute_code, web_search, file_search, skills) pin their badge via `useToolToggle`.
- The keyword `'mcp'` or a configured MCP server name pins the MCP dropdown via `useMCPSelect`.
- Only seeds initial state; a user's stored pin preference always wins. When unset, tools start unpinned and the MCP dropdown keeps its legacy default (pinned).
Unifies the approaches from #11646 (pinnedTools) and #9251 (defaultPinMcp) into one config key.
* 🐛 fix: Apply defaultPinnedTools pin once startupConfig resolves
On a cold load, useToolToggle can mount before useGetStartupConfig() resolves, so defaultPinned starts false and useLocalStorageAlt eagerly persists it; its init effect never re-runs for the later config-driven default. Fresh users would then miss the admin-configured default pin whenever startup config was not already cached.
Capture whether a pin preference existed before mount (pre-seed) and, once startupConfig arrives, apply the real default for users with no prior preference. Runs once and never overrides an existing stored pin, so the conservative behavior for existing users is preserved.
* 🐛 fix: Preserve pin clicks made before startupConfig resolves
The cold-load default-seeding effect captured the stored-pin state only at mount, so a pin toggled before startupConfig resolved was treated as no-preference and overwritten when the admin default applied.
Track explicit pin toggles via a ref (set through the returned setter) and skip the default application when the user has interacted in-session — in addition to the existing stored-preference guard.
* 🕐 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.
Server-side resolution of {{current_date}} and {{current_datetime}} for
agent instructions used the server's timezone, so agents received UTC
instead of the user's local time the variables are documented to provide.
The browser's IANA timezone is now sent with each request and threaded
through replaceSpecialVars, anchoring those variables to the user's local
wall clock. {{iso_datetime}} stays UTC. Invalid or missing zones fall back
to the previous behavior.
* feat: Add GitHub skill sync
* fix: Address GitHub skill sync CI
* fix: Harden GitHub skill sync review paths
* fix: Prevent overlapping skill sync runs
* fix: Address GitHub skill sync review findings
* fix: Satisfy Git ref lint rule
* fix: Address GitHub sync review follow-ups
* fix: Match skill frontmatter closing fence
* fix: Address GitHub sync review cycle
* fix: Address GitHub sync review follow-ups
* fix: Harden GitHub skill sync worker
* fix: Format GitHub sync rollback log
* fix: Address GitHub sync review feedback
* fix: Format skill import parse handling
* fix: Coerce scalar skill frontmatter and correct scheduler timer clear
- parse: coerce numeric/boolean name and description scalars to strings instead of dropping them to empty (restores pre-refactor behavior; preserves absent-vs-empty distinction for the when-to-use fallback)
- scheduler: clear the setTimeout handle with clearTimeout rather than clearInterval
- test: cover non-string scalar frontmatter coercion
* fix: Tolerate trailing whitespace after SKILL.md opening frontmatter fence
extractFrontmatterBlock required the opening fence to be exactly '---\n', so an opener with trailing spaces/tabs (e.g. '--- \n') silently dropped all frontmatter even though the closing-fence regex already tolerates it. Match the opener with /^---[ \t]*\n/ for symmetry. Addresses Codex P3 (parse.ts:24).
* feat: Run GitHub skill sync under a per-source tenant context
Under TENANT_ISOLATION_STRICT, the sync ran with no async tenant context, so the tenant-isolation mongoose hooks threw on every Skill/SkillFile/AclEntry operation; in non-strict mode synced skills were written tenant-less and never matched tenant-scoped reads. Add an optional per-source tenantId to the skillSync config; when set, each source sync runs inside tenantStorage.run({ tenantId }) so skills, files, and public ACL grants are created and listed within that tenant, and the skill row is stamped with the tenantId for correct dedup. Sources without tenantId keep the prior single-tenant behavior. Avoids runAsSystem. Addresses Codex P2 (sync.js:70).
Lock/status/credential bookkeeping stays outside the tenant context (those collections are intentionally global).
* test: Restore dropped tenant-context coverage for GitHub skill sync
The prior commit shipped the getTenantId import in github.spec.ts without the tenant tests that use it (lost in an interrupted edit), which failed the eslint --max-warnings=0 CI job on an unused import. Restore both github.spec.ts tenant tests (tenant-scoped run stamps tenantId and executes inside the tenant ALS context; no-tenant run stays ambient) and the two config-schemas tenant tests (accepts tenantId, rejects __SYSTEM__).
* test: Restore dropped github.spec tenant-context tests
The previous commit's github.spec.ts edit did not apply (anchor mismatch), so the getTenantId import remained unused and failed eslint --max-warnings=0. Add the two tenant tests that use it: a tenant-scoped run stamps tenantId and executes inside the tenant ALS context, and a no-tenant run stays ambient.
* feat: Scope synced skill author to tenant and harden tenant-context sync
Addresses the latest Codex review on the per-source tenant change:
- makeSourceAuthorId now folds tenantId into the synthetic author hash so the
same source mirrored into different tenants gets distinct author ids (clearer
audits, no cross-tenant author collisions). Single-tenant author ids stay
stable (suffix omitted when tenantId is absent).
- syncSourceInTenantContext uses an async callback per the tenant-context
contract so the ALS store propagates across awaited Mongoose calls.
- Tests: same-source/different-tenant yields distinct authors; mirror cleanup
is scoped to the source and deletes only its absent-upstream skills.
* fix: Repair tsc error and guard external edits in github skill sync
- Fix TS2352 in github.spec mirror-cleanup test: build the existing-skill mock via makeSkill with authorName instead of an under-typed 'as CreateSkillInput' cast (this was the failing TypeScript CI check on f00ce3c5a).
- 808: commitExistingRemoteSkillAfterFileSync re-reads to clear our own file-sync version bumps, but now compares refreshed content against the pre-sync snapshot (body/name/description/always-apply) and throws SKILL_CONFLICT on a concurrent external edit instead of overwriting it.
* docs: Note skillSync source tenantId is effectively immutable
Changing/adding/removing a source's tenantId orphans previously mirrored skills in the old tenant (a tenant-scoped sync cannot clean another tenant's data without runAsSystem, which is intentionally avoided).
* fix: Key GitHub skill upstream identity on source id and path only
Addresses Codex finding (github.ts:217): makeUpstreamId previously included owner/repo, so repointing a source to a renamed or replacement repository (same source id) changed the upstreamId, made findSkillBySourceIdentity miss the existing mirror, and then collided on the (name, author, tenantId) uniqueness constraint — leaving the source stuck failing. Identity now keys on the stable source id + root path only. The feature is unreleased, so there is no stored-id migration. Updated spec upstreamId fixtures to the new format; the existing ref-independent identity test now also covers repo moves.
* fix: Scope GitHub skill mirror deletion to the source tenant
Addresses Codex P1 (github.ts:1047/1057): an ambient source (no tenantId) runs listSkillsBySource without tenant context, which under non-strict isolation returns github-synced skills across all tenants. The mirror-deletion pass then treated other tenants' skills as absent-upstream and could delete them. Filter existingSyncedSkills to rows whose tenantId matches the source's configured tenantId (absent = its own ambient bucket) before deleting, so a sync never removes another tenant's mirrored skills. Covered by a test where an ambient run leaves a tenant-b-owned skill untouched.
* fix: Apply tenant-scoped mirror deletion implementation
The prior commit (75ccfa3fc) added the test but the source change to github.ts was lost in an interrupted edit, leaving a failing test with no implementation. This adds the actual guard: the mirror-deletion pass skips skills whose tenantId does not match the source's configured tenantId (absent = ambient bucket), so an ambient source whose listSkillsBySource returns cross-tenant rows under non-strict isolation cannot delete another tenant's mirrored skills.
* fix: Resolve global access role outside tenant context for synced skill grants
Addresses Codex P2 (github.ts:1166): default access roles (incl. skill_viewer) are seeded globally with no tenantId under runAsSystem, but a tenant-scoped sync wraps ensurePublicViewer in the source's tenant context. The PermissionService grantPermission resolved the role via a tenant-isolated AccessRole query, so the global role did not match and tenant-scoped syncs failed with 'Role skill_viewer not found'. The sync adapter now resolves the role inside runAsSystem (matching the global seed) and writes the ACL entry in the active tenant context, so the AclEntry is tenant-scoped (visible to tenant users) while the role lookup still succeeds. Covered by service tests for the resolve-vs-write split and the missing-role failure.
* fix: Strip placeholder frontmatter booleans and check skill conflict before file sync
- 1083 (github.ts:759): toCleanFrontmatter now drops a non-boolean always-apply (e.g. the 'always-apply:' / 'always-apply: # TODO' placeholder, which js-yaml yields as null). The boolean is already captured in the dedicated alwaysApply field; persisting null left ambiguous frontmatter on the synced skill.
- 1080 (github.ts:1057): for an existing mirrored skill, check for an external content edit (via getSkillById + hasExternalSkillEdit) BEFORE syncSkillFiles mutates the bundled files, so a concurrently edited skill fails fast with SKILL_CONFLICT without partial file rewrites. The post-file-sync check still guards edits that land during the file sync window.
Tests: placeholder always-apply is dropped from synced frontmatter; concurrent-edit conflict leaves files unmutated (no upsert/delete).
* fix: Harden GitHub skill sync review paths
* fix: Reuse moved GitHub skill mirrors
* fix: Scope GitHub sync identity conflicts
* test: Fix GitHub sync conflict mock typing
* fix: Support nested env-backed skill sync
* fix: Keep skill sync config base-only
* fix: Scope GitHub skill identity lookup by tenant
* fix: Harden GitHub skill sync admin gates
* fix: Guard existing skill sync permission grants
* feat: Trigger skill sync from resolved config
* fix: Scope resolved skill sync by tenant
* test: Allow manual skill sync status tenant scoping
* refactor: Extract skill sync trigger orchestrator
* test: Complete orchestrator status fixture
* chore: Bump data provider version
* fix: Restrict skill sync server credentials
* test: Complete admin skill sync status fixtures
* fix: tighten skill sync trigger safeguards
* fix: preserve alwaysApply skill sync alias
* chore: sort skill sync imports
* fix: preserve skill sync request scope
* fix: harden skill sync review edges
* refactor: move skill sync admin access to api package
* fix: add skill sync declaration return types
* fix: satisfy skill sync type checks
* fix: resolve codex skill sync review findings
* fix: harden skill sync review edges
* fix: resolve codex skill sync edge findings
* fix: satisfy API declaration build after rebase
* 📖 feat: Add Claude Fable 5 Support
Claude Fable 5 (`claude-fable-5`) is Anthropic's most capable widely
released model (GA 2026-06-09). Its naming drops the opus/sonnet/haiku
tier, so LibreChat's name-parsing helpers miss it; this teaches them the
Mythos-class family (Fable / Mythos) and registers the model.
- Add `parseMythosClassVersion` and route Fable/Mythos through
`supportsAdaptiveThinking`, `omitsThinkingByDefault`,
`omitsSamplingParameters`, and `supportsContext1m`
- Extend the Bedrock detection regexes (beta headers + adaptive-thinking
branch) and `checkPromptCacheSupport` to match `claude-(fable|mythos)`
- Return 128K max output for Fable/Mythos in `maxOutputTokens.reset`/`set`
- Register `claude-fable-5` in shared Anthropic + Bedrock model lists,
1M context / 128K output token maps, and $10/$50 pricing with 12.5/1
cache rates (`claude-mythos-5` added to token + pricing maps only,
since it is limited-availability)
- Update `.env.example` and the Vertex `librechat.example.yaml` examples
- Add parallel tests across tokens, Anthropic llm config, the Bedrock
parser, and tx pricing
* 🧹 refactor: Centralize Mythos-class detection; address review feedback
- Add `isMythosClassModel` + `MYTHOS_CLASS_FAMILIES` in schemas.ts as the
single source of truth for the Fable/Mythos family; route every gate
(adaptive thinking, omit-thinking, omit-sampling, 1M context, prompt cache,
128K max-output reset/set) through it. A future sibling class is now a
one-line edit.
- [Codex P2] Exclude Mythos-class from getBedrockAnthropicBetaHeaders: Fable/
Mythos ship 128K output + fine-grained tool streaming by default, and the
legacy output-128k-2025-02-19 beta is 3.7-Sonnet-only on Bedrock and risks
request rejection. They still get adaptive thinking + effort.
- [Copilot] Add Mythos 5 test parity (name variations, cache rates, pinned
$10/$50) in tx.spec; add Mythos context/max-output/name-match in tokens.spec;
fix the stale claude-3-7-sonnet-only comment in bedrock.ts.
- Add isMythosClassModel unit tests covering all declared families.
* 📝 docs: Clarify Mythos-class Bedrock requirements; correct beta-omit rationale
Verified live against Bedrock (acct 951834775723, us-west-2):
- anthropic.claude-fable-5 IS a real Bedrock catalog model, INFERENCE_PROFILE-only
exactly like the existing anthropic.claude-opus-4-7/4-8 and claude-sonnet-4-6
default entries (refutes the "invalid model id" review claim).
- Mythos-class also requires opting into Anthropic data sharing (Bedrock Data
Retention API) before invocation.
Changes:
- .env.example: note that Mythos-class (Fable/Mythos) is inference-profile-only on
Bedrock and needs the data-sharing opt-in.
- bedrock.ts: reword the beta-omit comment to the verified rationale — output-128k /
fine-grained-tool-streaming are built-in/no-op for the 4.7+ generation, so omitting
them is lossless (dropped the unverified "Bedrock may reject" wording).
* 🔄 refactor: Reorganize imports in schemas.ts and tx.spec.ts
- Moved `TFeedback` and `Tools` imports to the top of `schemas.ts` for better readability.
- Adjusted import order in `tx.spec.ts` to maintain consistency and improve clarity.
* fix: resolve env variables in MCP OAuth URL fields before validation
Apply the extractEnvVariable transform to authorization_url, token_url,
redirect_uri, and revocation_endpoint in OAuthOptionsBaseSchema. Without
this, ${ENV_VAR} syntax in these fields caused a Zod URL validation error
at startup before any env substitution could happen.
The same .transform().pipe() pattern is already used on all transport url
fields (SSE, WebSocket, StreamableHTTP) and ProxyUrlSchema.
Closes#13572
* fix: block env var expansion in user OAuth URL fields
Override redirect_uri and revocation_endpoint in UserOAuthOptionsSchema
with userOAuthEndpointUrlSchema, matching the existing overrides for
authorization_url and token_url. Without this, user-submitted configs
could inherit the extractEnvVariable transform added to the base schema
and resolve env vars like ${OPENAI_API_KEY} in those fields.
Add envVarPattern rejection to userOAuthEndpointUrlSchema so that
valid-URL-shaped payloads containing ${VAR} patterns are also blocked,
not just bare non-URL strings. Move envVarPattern declaration above the
schema to make it available at module evaluation time.
Add regression tests for all four OAuth URL fields on the user path,
using structurally valid URLs with embedded ${VAR} patterns to confirm
it is the env var guard — not URL shape — that rejects them.
* Add OBO (On-Behalf-Of) token exchange support for MCP server connections
Enables transparent authentication to Entra ID-backed MCP servers using the logged-in user's federated token via the OAuth 2.0 jwt-bearer grant. Configured via obo.scopes in librechat.yaml server config.
- Extract generic OboTokenService from GraphTokenService (jwt-bearer grant + cache)
- Refactor GraphTokenService to thin wrapper delegating to OboTokenService
- Add obo schema field to BaseOptionsSchema in data-provider
- Add resolveOboToken in packages/api/src/mcp/oauth/obo.ts (validates federated token, calls resolver, returns MCPOAuthTokens)
- Wire oboTokenResolver through MCPConnectionFactory, MCPManager, UserConnectionManager
- OBO tokens injected via request headers (not OAuth transport), refreshed on each tool call
- Explicit error on OBO failure (no fallthrough to standard OAuth redirect)
- Add unit tests for both resolveOboToken (9 tests) and exchangeOboToken (14 tests)
* Add OBO authentication option to MCP server UI configuration
Enable users to configure On-Behalf-Of (OBO) token exchange for MCP servers created via the UI (MongoDB-stored), in addition to the existing YAML-based configuration.
- Add "On-Behalf-Of (OBO)" radio option to MCP server auth section with scopes input field
- Remove obo from omitServerManagedFields so the field passes UI schema validation
- Add OBO to AuthTypeEnum, obo_scopes to AuthConfig, and OBO handling in form defaults and submission
- Add .min(1) validation on obo.scopes to reject empty strings
- Add English localization keys: com_ui_obo, com_ui_obo_scopes, com_ui_obo_scopes_description
- Add 5 schema validation tests for OBO field acceptance, transport compatibility, and edge cases
* 🧊 fix: Add obo to safe properties in redactServerSecrets. Fixes the OBO configuration not showing up in the MCP UI after app restart
* Address linter errors
* 🧊 fix: fail closed on OBO refresh errors and retry transient token exchange failures
- stop tool calls from falling back to stale Authorization headers when per-call OBO refresh fails
- add one-time retry for transient Entra OBO exchange failures (network/429/5xx)
- preserve structured OBO failure reasons and retryability in resolveOboToken
- improve OBO auth error messaging for connection setup and tool execution
- add tests for transient vs permanent OBO failure paths
* Addressing linting errors / warnings
* 🧊 fix: isolate OBO MCP auth to user-scoped connections
- block OBO-enabled servers from app-level shared MCP connections
- bypass shared connection lookup for OBO servers in MCPManager.getConnection
- add regressions covering OBO connection scoping and preserve non-OBO app connection reuse
* 🛠️ refactor: centralize MCP user-scoped connection policy
- add shared requiresUserScopedConnection helper for OAuth, OBO, and customUserVars
- use the shared predicate in MCPManager and ConnectionsRepository
- add utils coverage for user-scoped connection policy
* 🧊 fix: restrict MCP OBO config to header-capable transports
- Move OBO configuration out of the shared MCP base options schema and allow it
only on SSE and streamable-http transports, where request headers are applied.
- Explicitly reject OBO on stdio and websocket configs to avoid accepted-but-
nonfunctional server definitions. Add schema coverage for admin/config parsing
and user-input websocket validation.
* 🧊 fix: single-flight concurrent OBO token exchanges
Concurrent tool calls that arrive on a cache miss were each issuing
their own jwt-bearer request to the IdP. Under that fan-out, Entra
intermittently returned errors that the retry classifier saw as
non-retryable, surfacing as:
"The identity provider rejected the OBO token exchange.
Cannot execute tool <name>. Re-authenticate the user or
verify the configured OBO scopes and retry."
A user retry then hit the populated cache and succeeded, which matches
the observed flakiness — the cache was empty at the moment of fan-out
but populated by the time the user clicked retry.
- Coalesce concurrent exchanges in `OboTokenService.exchangeOboToken`
keyed by `${openidId}:${scopes}`. Callers that arrive while an exchange
is in flight share the same upstream request and receive the same
result. `fromCache=false` continues to force a fresh, independent
exchange (and is not joined by `fromCache=true` callers). The IdP
call, single-retry path, and cache write are unchanged — they were
moved into a `performOboExchange` helper so the coalescing wrapper
stays small.
- Tests cover: coalescing on the same key, isolation between different
keys, cleanup on success, cleanup on failure, and the
`fromCache=false` bypass.
* 🔒 feat: gate MCP OBO config behind MCP_SERVERS.CONFIGURE_OBO permission
OBO silently mints per-user delegated tokens from the caller's federated
access token and forwards them to whatever URL the server config points at.
Previously, anyone with MCP_SERVERS.CREATE could configure obo.scopes — so
if server creation is ever delegated beyond admins, a user could stand up
an attacker-controlled server, attach it to a shared agent, and exfiltrate
other users' downstream tokens on tool invocation.
Add a dedicated MCP_SERVERS.CONFIGURE_OBO permission (ADMIN: true, USER:
false by default) and enforce it at three layers so the safety property
no longer depends on CREATE staying admin-only:
- Create/update: POST/PATCH /api/mcp/servers returns 403 when the body
carries `obo` and the caller's role lacks the permission.
- Runtime fail-closed: for DB-sourced configs, MCPConnectionFactory and
MCPManager.callTool re-check the original author's role before each
OBO exchange. If the author has been downgraded, the exchange is
skipped (factory) or refused (callTool) — retained configs lose their
privileges automatically.
- UI: the OBO option is hidden in the MCP server dialog for users
without the permission; a CONFIGURE_OBO toggle is exposed in the MCP
admin role editor.
Existing role docs receive the new sub-key via the permission backfill
in updateInterfacePermissions on next startup, preserving any
operator-set values. YAML/Config-sourced server configs are unaffected
since they're admin-controlled at the deployment level.
* 🧊 fix: wire OBO machinery for servers with requiresOAuth: false
The discovery and user-connection paths gated OAuth wiring (flow
manager, token methods, oboTokenResolver, oboTrustChecker) behind
isOAuthServer(), which only considers requiresOAuth/oauth fields.
A DB-stored OBO server with requiresOAuth: false therefore landed in
the non-OAuth branch, never received an oboTokenResolver, and the
factory's usesObo getter evaluated to false — sending a bare request
that the upstream rejected with invalid_token.
Add requiresOAuthMachinery() (OAuth OR OBO) and use it at those two
gates. isOAuthServer remains for the OAuth-handshake-only check
(shouldInitiateOAuthBeforeConnect), where OBO must not initiate a
handshake. Plumb the OBO resolver/trust-checker through
ToolDiscoveryOptions so reinitMCPServer can pass them on the
discovery path.
* 🧊 fix: lock all OBO-target fields (URL, proxy, headers, auth) without CONFIGURE_OBO
The CONFIGURE_OBO permission was meant to gate control of the endpoint
that receives OBO-minted per-user delegated tokens and the scopes that
are requested. The previous frontend lock + backend gate only covered
obo.scopes and the auth section, leaving url/proxy/headers/etc. editable
by anyone with UPDATE — meaning a non-permission user could still
redirect an existing OBO server's token flow to an attacker endpoint.
Switch to an allowlist policy: when editing an OBO server without
CONFIGURE_OBO, only title/description/iconPath are mutable. Backend
rejects any other field change with 403; frontend disables the
non-allowlist sections (URL, transport, auth, trust) via fieldset.
The comparison surface (MCP_USER_INPUT_FIELDS) is derived from
MCPServerUserInputSchema's union members so it stays in sync with the
schema. New schema fields land in the locked set by default — adding to
the allowlist is the only way to unlock them, which preserves the
security-review boundary.
* 🧊 fix: skip unauthenticated MCP inspection for OBO-only servers
MCPServerInspector.inspectServer() ran an unauthenticated temp connection
unless the config had requiresOAuth or customUserVars set. For OBO-only
servers without standard MCP OAuth advertisement, this caused
MCPConnectionFactory.create to attempt the connection without a user or
oboTokenResolver — failing on servers that reject the MCP initialize
handshake without a valid bearer token, which surfaced as
MCP_INSPECTION_FAILED on create/update.
Add `obo` to the skip list alongside requiresOAuth and customUserVars,
matching the existing pattern for user-scoped auth modes.
* Addressed linting error: watchedTitle is declared but never referenced (the auto-fill logic at line 156 uses getValues('title') instead). Deleted constant.
* feat(mcp/oauth): support audience parameter for Auth0/Cognito-style providers
LibreChat already follows RFC 9728 (Protected Resource Metadata discovery)
and RFC 8707 (resource indicators on /authorize). However, authorization
servers that pre-date RFC 8707 — most prominently Auth0 — issue
API-scoped access tokens only when an Auth0-specific 'audience' parameter
is supplied on /authorize and /token. Without it, refresh_token responses
strip the API audience and the next MCP call 401s.
This change adds an optional 'audience' field to OAuthOptionsSchema and
forwards it on:
* pre-configured authorize URL build
* discovered (DCR + RFC 9728) authorize URL build
* refresh_token grant body
'resource' (RFC 8707) is left untouched and remains the
standards-conformant route; 'audience' covers providers that ignore
'resource'. The two are independent — providers may accept either, both,
or neither, so we forward whichever the operator configures.
Schema tests added; no behavioral change for existing configs (field is
optional with no default).
Refs: MCP Authorization Spec 2025-06-18, RFC 9728, RFC 8707.
* ci: build audience-fix branch image to ghcr.io/freudator86/librechat:audience-fix
* Revert "ci: build audience-fix branch image to ghcr.io/freudator86/librechat:audience-fix"
This reverts commit 7b3dfa6cd7.
* tests: assert audience param in authorize URL + refresh body; tighten schema (.min(1)); refine comment to reflect actual code paths
Adresses PR review:
- audience: z.string().min(1).optional() rejects empty strings
- schema comment now precisely lists the two code paths (authorize + refresh_token grant); explicitly notes the authorization_code exchange intentionally does not receive audience because Auth0 binds it from the initial /authorize request
- new MCPOAuthAudience.test.ts: 4 cases — authorize URL with/without audience, refresh body with/without audience — using a local recording HTTP server (no shared helper changes)
- new schema test: empty-string audience is rejected
* style: inline two logger.debug calls (prettier)
* style: inline third audience-debug log (prettier)
* feat(mcp/oauth): add forward_audience_on_refresh opt-out for strict token endpoints (Cognito)
Addresses Codex review P2 'Avoid sending audience on refresh grants':
the previous behavior forwarded audience on every refresh_token grant,
which is correct for Auth0 (strips the audience claim otherwise) but is
non-standard for Cognito and other strict OAuth 2.0 token endpoints that
document refresh as grant_type + client_id + refresh_token only.
New optional boolean 'forward_audience_on_refresh' (default: true)
preserves the existing Auth0-friendly default while letting operators
of strict tenants opt out cleanly. Schema + handler tests cover both
cases.
No behavioral change for existing configs.
* style: format MCP OAuth refresh audience log
---------
Co-authored-by: Tim Freudenthal <tim@allesknut.de>
Co-authored-by: Danny Avila <danny@librechat.ai>
* feat: add Claude Opus 4.8 support
* fix: omit sampling params for Claude Opus 4.8
* fix: flatten Bedrock beta header merge
* fix: strip Bedrock sampling params for Opus 4.8
* 🛟 fix: Allow empty modelSpecs.list to unstick admin-panel saves
The unconditional `.min(1)` on `specsConfigSchema.list` rejected an empty
list even when `enforce: false`, leaving admin panels (which save fields
path-granularly) with no atomic way to clear the list once it had been
populated. Once an admin reached `list: [entry]` and deleted the only
entry, every subsequent save failed schema validation and the section
became stuck.
Relax the schema to `.default([])`. The `.min(1)` was added in #5218 as
part of bundled cleanup, not as a deliberate rule. Every consumer of
`modelSpecs.list` already handles the empty/undefined case (`?.list`,
`?? []`, length-checked), and `processModelSpecs` short-circuits to
`undefined` when the list is empty so the runtime treats it as "no
specs configured." No call site is load-bearing on length >= 1.
Tighten the `buildEndpointOption.js` enforce guard from
`?.list && ?.enforce` to `?.list?.length && ?.enforce`. Empty arrays
are truthy in JS, so the existing guard would have entered the enforce
branch on `list: []` and returned "No model spec selected" or "Invalid
model spec" had `processModelSpecs` ever been bypassed.
Add a runtime warn in `processModelSpecs` when `enforce: true` is
configured alongside an empty list, so operators see the resulting
"enforcement disabled" state in logs rather than silently getting a
permissive runtime.
Add coverage for the empty-list parse path in `config-schemas.spec.ts`
and for the empty-list-with-enforce branch in `buildEndpointOption.spec.js`.
* chore: update import order in config-schemas.spec.ts
`tModelSpecPresetSchema` was omitting `greeting` and `iconURL`, so
`configSchema.strict().safeParse()` stripped these admin-configured
fields from `modelSpecs.list[].preset` before the server sent the
startup config to the client — breaking the landing greeting and the
`preset.iconURL` fallback in `getModelSpecIconURL`.
Keep `spec` and `presetOverride` omitted (those are truly
client-managed), and flip the schema test to assert `greeting`/`iconURL`
are preserved.
Fixes#12803
* 🐛 fix: accept documented `summarization.trigger.type` values
The Zod schema for `summarization.trigger.type` only accepted
`'token_count'`, but:
- the documentation lists `token_ratio`, `remaining_tokens`, and
`messages_to_refine` as valid
- the `@librechat/agents` runtime only evaluates those three types and
silently no-ops on anything else
The result was a double failure: any user following the docs hit a
startup Zod error, and anyone who matched the schema by using
`token_count` got a silent no-op at runtime where summarization never
fired.
Align the schema with the documented, runtime-supported trigger types.
Closes#12721
* 🧹 fix: bound `token_ratio` trigger value to (0, 1]
Per Codex review: the previous schema accepted `value: z.number().positive()`
for every trigger type. That meant `trigger: { type: 'token_ratio', value: 80 }`
(presumably meant as "80%") passed validation and then silently never fired —
because `usedRatio = 1 - remaining/max` is bounded at 1, so `>= 80` is always
false. That is exactly the silent-no-op pattern this PR is trying to eliminate.
Switch to a discriminated union so each trigger type has its own value
constraint:
- `token_ratio`: `(0, 1]` — documented as a fraction, so 80 is nonsense
- `remaining_tokens`: positive — token counts can be large
- `messages_to_refine`: positive — message counts can be > 1
Added tests for the upper-bound rejection and the inclusive upper bound
(`value: 1` still accepted as a valid "fire at 100%" extreme).
* 🧹 fix: accept `token_ratio: 0` per documented 0.0–1.0 inclusive range
Per Codex review: `.positive()` rejected `value: 0`, but the docs
describe the `token_ratio` range as `0.0–1.0` (both inclusive). Admins
who copy the documented lower bound into their YAML would fail schema
validation at startup.
Switch `token_ratio` to `.min(0).max(1)`. `0` is a valid (if extreme)
setting — the agents SDK's `usedRatio >= 0` check will fire as soon as
there is anything to refine, which is a legitimate "always summarize
when pruning happens" configuration.
`remaining_tokens` and `messages_to_refine` keep `.positive()`: both
are counts, and `0` there produces no meaningful behavior (the SDK
has an early return for `messagesToRefineCount <= 0`).
* 🐛 fix: preserve `token_ratio` trigger when `value: 0`
Per Codex review: now that the schema accepts `token_ratio: 0`,
`shapeSummarizationConfig` would silently drop it because of a truthy
check on `config?.trigger?.value`. The trigger would disappear and the
runtime would fall back to "no trigger configured" — which fires on any
pruning rather than honoring the explicit ratio.
Switch to `typeof value === 'number'`, which preserves `0` while still
rejecting `undefined`/`null`.
Added a regression test that asserts `{ type: 'token_ratio', value: 0 }`
survives the shaping function untouched.
* 🧹 fix: reject non-finite trigger values at schema level
Per Codex review: `z.number().positive()` still accepts `Infinity` and
`NaN` (via YAML `.inf`, `.nan`). Config validation would succeed, but
the agents SDK guards every trigger path with `Number.isFinite(...)` and
silently returns `false` — summarization never fires while the server
starts cleanly. That is the exact schema/runtime split this PR is trying
to eliminate.
Add `.finite()` to every trigger value. `token_ratio` already had an
implicit guard via `.max(1)`, but applying `.finite()` uniformly keeps
the intent obvious and catches `NaN` (which `.max(1)` does not).
* 🧹 fix: integer counts + targeted token_count migration warning
Two findings from the comprehensive review:
1. `remaining_tokens` and `messages_to_refine` are token/message counts
and are always integers in the runtime (`Number.isFinite(...)` guards
already assume integer semantics). `z.number().positive()` accepted
fractional values like `2.5`, which was semantically confusing and
would round oddly against the runtime's `>=` / `<=` comparisons. Add
`.int()` to both count-based branches; `token_ratio` stays fractional.
2. Anyone upgrading with `trigger.type: 'token_count'` in their YAML got
the generic "Invalid summarization config" warning plus a flattened
Zod error. Detect that specific case in `loadSummarizationConfig` and
emit a migration-friendly message that names the three valid
replacements. Export the function so the behavior is unit-testable.
Also added a parameterized passthrough test covering `remaining_tokens`
and `messages_to_refine` shaping, complementing the existing
`token_ratio` coverage.
* 🧹 fix: accurate fallback wording + bare-string trigger test
Two nits from the follow-up audit:
1. The legacy-`token_count` warning claimed "Summarization will be
disabled," but `shapeSummarizationConfig` treats a missing
summarization config as self-summarize mode (fires on every pruning
event using the agent's own provider/model). "Disabled" would
mislead an admin into stopping investigation. Reword to describe the
actual fallback and assert the new wording in the spec.
2. Add a regression test for the `trigger: 'bare-string'` YAML case, so
the `typeof raw.trigger === 'object'` guard is exercised rather than
implied.
3. Swap the en-dash in `(0–1)` for an ASCII hyphen so the log message
is safe in every terminal/aggregator regardless of UTF-8 handling.
* 🔇 fix: cast `raw.trigger.type` to inspect legacy value past narrowed union
CI TS check failed: after the schema tightening, `raw.trigger.type` is
narrowed to `"token_ratio" | "remaining_tokens" | "messages_to_refine"
| undefined`, so the runtime comparison to `"token_count"` is a
TS2367 ("no overlap") error even though that's exactly the comparison
we want for the migration guard.
Widen just that one access via `as { type?: unknown }` so the migration
check reads runtime-shaped YAML input without the type system folding
it back into the narrowed union.
* 🫧 fix: Restore Claude Opus 4.7 Reasoning Visibility
Claude Opus 4.7 omits `thinking` content from Messages API responses by
default — empty thinking blocks still stream, but the `thinking` field is
blank unless the caller passes `display: "summarized"` in the adaptive
thinking config. This silenced the LibreChat "Thoughts" UI for Anthropic
(and Anthropic-on-Bedrock) adaptive models.
- Extend `ThinkingConfigAdaptive` in `packages/api/src/types/anthropic.ts`
with an optional `display: 'summarized' | 'omitted'` field
- Emit `{ type: 'adaptive', display: 'summarized' }` from
`configureReasoning` in `packages/api/src/endpoints/anthropic/helpers.ts`
- Emit `{ type: 'adaptive', display: 'summarized' }` from
`bedrockInputParser` in `packages/data-provider/src/bedrock.ts` and
update the local `ThinkingConfig` union
- Update existing adaptive-thinking assertions to include the new field
- Add dedicated tests asserting `display: 'summarized'` flows through
both the Anthropic endpoint and the Bedrock parser
See https://platform.claude.com/docs/en/about-claude/models/whats-new-claude-4-7#thinking-content-omitted-by-default
* refactor: Gate `display: summarized` on Opus 4.7+
Narrow the reasoning-visibility opt-in to the models that actually omit
thinking content by default, instead of applying it to every adaptive
model. Pre-Opus-4.7 adaptive models (Opus 4.6, Sonnet 4.6) already return
summaries, so sending the field is unnecessary noise.
- Add `omitsThinkingByDefault(model)` in `packages/data-provider/src/bedrock.ts`
that returns true only for Opus 4.7+ (including future majors like Opus 5+)
- Bedrock parser now only attaches `display: 'summarized'` when the helper
matches, keeping the adaptive object unchanged for older models
- Anthropic endpoint `configureReasoning` uses the same helper so its emit
path matches the Bedrock one
- Tests: replace the blanket `display: 'summarized'` assertions with
model-specific ones (Opus 4.7 gets it, Opus 4.6 / Sonnet 4.6 do not),
add a dedicated `omitsThinkingByDefault` suite covering naming variants
and future versions
* feat: Configurable Thought Visibility for Anthropic Adaptive Models
Expose the Anthropic `thinking.display` API field as a user-facing
parameter so users can override the `auto` default (which stays as the
Opus-4.7+ opt-in added earlier in this PR). Also fixes the CI type error
by widening the adaptive thinking type assignment via a resolver helper
that returns a properly-typed object.
- Add `ThinkingDisplay` enum (`auto` | `summarized` | `omitted`) and
matching zod schema in `packages/data-provider/src/schemas.ts`
- Add `thinkingDisplay` to `tConversationSchema`, `anthropicSettings`, and
the pick lists for Bedrock input/parser + Anthropic agent params
- Add `resolveThinkingDisplay(model, explicit)` helper in
`packages/data-provider/src/bedrock.ts` that returns the wire value or
undefined (auto → model default, explicit → always honored)
- `bedrockInputParser` now reads `thinkingDisplay` from input and emits
`display` only when the resolver returns a value; strips the field
on non-adaptive-model branches so it does not leak
- `configureReasoning` in the Anthropic endpoint threads
`thinkingDisplay` through, uses the resolver, and casts the adaptive
config to `AnthropicClientOptions['thinking']` so the widened shape
compiles against the stale installed SDK types
- Add UI slider for `thinkingDisplay` in `parameterSettings.ts` next to
`effort`, with three-position `com_ui_auto` / `com_ui_summarized` /
`com_ui_omitted` labels
- Add translation keys `com_endpoint_anthropic_thinking_display`,
`com_endpoint_anthropic_thinking_display_desc`, `com_ui_summarized`,
`com_ui_omitted`
- Add tests: `resolveThinkingDisplay` suite (5 cases covering auto /
explicit / unknown input), parser round-trip tests for all three
modes on Opus 4.6 and Opus 4.7, Anthropic endpoint tests for explicit
summarized/omitted overrides
* fix: Drop `thinkingDisplay` When Adaptive Thinking Is Disabled
If a user turns adaptive thinking off but had previously selected a
`thinkingDisplay` value, the stale field was left in `additionalFields`
and ended up merged into the Bedrock request's
`additionalModelRequestFields`. That leaks a non-Bedrock key into the
payload and can round-trip back into `llmConfig`.
- Delete `additionalFields.thinkingDisplay` alongside `thinking` and
`thinkingBudget` in the `thinking === false` branch of
`bedrockInputParser`
- Add a regression test asserting `thinking`, `thinkingBudget`, and
`thinkingDisplay` are all absent when adaptive thinking is disabled on
an Opus 4.7 request
Reported by chatgpt-codex-connector on PR #12701.
* refactor: Consolidate `ThinkingDisplay` Types and Preserve Persisted Display
Address review findings on PR #12701:
- [Codex P2] `bedrockInputSchema.transform` now extracts
`thinking.display` from persisted `additionalModelRequestFields` back
into the top-level `thinkingDisplay` field so explicit `'omitted'`
round-trips through storage instead of being silently reverted to
`'summarized'` on the next parse.
- [Codex P2] `getLLMConfig` in the Anthropic endpoint now reads
`.display` from a persisted `thinking` object (agents store the full
Anthropic shape) and uses it as the fallback for `thinkingDisplay`
when no top-level override is present.
- [Audit #2] Collapse the three parallel wire-value types into a single
`ThinkingDisplayWireValue = Exclude<ThinkingDisplay, 'auto'>` exported
from `schemas.ts`; remove the duplicate `ThinkingDisplay` alias in
`packages/api/src/types/anthropic.ts` (which collided with the enum
name) and the `ThinkingDisplayValue` alias in `bedrock.ts`.
- [Audit #3] Add `thinkingDisplay` to the `TEndpointOption` pick list
next to `effort`.
- [Audit #4] Add a TODO comment next to the `as
AnthropicClientOptions['thinking']` cast explaining the stale
`@librechat/agents` SDK types that require it.
- Add tests: four round-trip cases asserting `bedrockInputSchema`
recovers `display` from persisted AMRF (Opus 4.7 omitted, pre-4.7
summarized, unknown-value ignore, explicit top-level wins), and two
`getLLMConfig` cases asserting the Anthropic endpoint preserves and
overrides persisted `thinking.display`.
* fix: Preserve Persisted `thinking.display` in bedrockInputParser
The parser constructed a fresh adaptive thinking config without looking at
any `display` already embedded in the incoming
`additionalModelRequestFields.thinking`. On round-trip through
`initializeBedrock`, a persisted user choice of `'omitted'` on Opus 4.7+
was silently reverted to `'summarized'` by the auto fallback.
- Extract `extractPersistedDisplay` helper and reuse it in both the
schema transform (form-state round-trip) and the parser (wire-request
round-trip)
- `bedrockInputParser` now feeds the persisted display as the resolver's
explicit value when no top-level `thinkingDisplay` override is set
- Add regression tests: parser preserves `display: 'omitted'` for
persisted Opus 4.7 AMRF, and top-level `thinkingDisplay` still wins
over persisted AMRF display
Reported by chatgpt-codex-connector (P1) on PR #12701.
* 🦉 feat: Claude Opus 4.7 Model Support
- Add `claude-opus-4-7` to shared Anthropic models and `anthropic.claude-opus-4-7` to Bedrock models
- Register 1M context window and 128K max output in anthropic token maps
- Add token pricing ($5/$25), cache rates (6.25/0.5), and premium tier ($10/$37.50 above 200K) in tx.ts
- Update `.env.example` with Opus 4.7 IDs in `ANTHROPIC_MODELS` and `BEDROCK_AWS_MODELS` examples
- Add parallel Opus 4.7 test cases for token/cache/premium rates, context length, max output, name-variation matching, and 1M-context qualification
* feat: Add `xhigh` Effort Level for Opus 4.7
- Add `xhigh` variant to `AnthropicEffort` enum between `high` and `max`
- Expose `xhigh` in `anthropicSettings.effort.options` and the UI slider `enumMappings`
- Reuse existing `com_ui_xhigh` translation key
* test: Cover `xhigh` Effort and Exact Opus 4.7 Premium Rates
- Assert `xhigh` position (between high and max), inclusion in
`anthropicSettings.effort.options`, zod acceptance, and rejection of
unknown values in schemas.spec.ts
- Verify bedrockInputParser emits `output_config: { effort: 'xhigh' }`
for adaptive `anthropic.claude-opus-4-7`
- Verify getLLMConfig sets adaptive thinking and `output_config.effort =
'xhigh'` for `claude-opus-4-7`
- Pin Opus 4.7 premium pricing to exact threshold/prompt/completion
values (200000 / 10 / 37.5) so silent rate drift fails the test
* chore: remove unused `interface.endpointsMenu` config field
* chore: address review — restore JSDoc UI-only example, add Zod strip test
* chore: remove unused `interface.sidePanel` config field
* chore: restrict fileStrategy/fileStrategies schema to valid storage backends
* fix: use valid FileStorage value in AppService test
* chore: address review — version bump, exhaustiveness guard, JSDoc, configSchema test
* chore: remove debug logger.log from MessageIcon render path
* fix: rewrite MessageIcon render tests to use render counting instead of logger spying
* chore: bump librechat-data-provider to 0.8.407
* chore: sync example YAML version to 1.3.7
* refactor: Remove deprecated and unused fields from endpoint schemas
- Remove summarize, summaryModel from endpointSchema and azureEndpointSchema
- Remove plugins from azureEndpointSchema
- Remove customOrder from endpointSchema and azureEndpointSchema
- Remove baseURL from all and agents endpoint schemas
- Type paramDefinitions with full SettingDefinition-based schema
- Clean up summarize/summaryModel references in initialize.ts and config.spec.ts
* refactor: Improve MCP transport schema typing
- Add defaults to transport type discriminators (stdio, websocket, sse)
- Type stderr field as IOType union instead of z.any()
* refactor: Add narrowed preset schema for model specs
- Create tModelSpecPresetSchema omitting system/DB/deprecated fields
- Update tModelSpecSchema to use the narrowed preset schema
* test: Add explicit type field to MCP test fixtures
Add transport type discriminator to test objects that construct
MCPOptions/ParsedServerConfig directly, required after type field
changed from optional to default in schema definitions.
* chore: Bump librechat-data-provider to 0.8.404
* refactor: Tighten z.record(z.any()) fields to precise value types
- Type headers fields as z.record(z.string()) in endpoint, assistant, and azure schemas
- Type addParams as z.record(z.union([z.string(), z.number(), z.boolean(), z.null()]))
- Type azure additionalHeaders as z.record(z.string())
- Type memory model_parameters as z.record(z.union([z.string(), z.number(), z.boolean()]))
- Type firecrawl changeTrackingOptions.schema as z.record(z.string())
* refactor: Type supportedMimeTypes schema as z.array(z.string())
Replace z.array(z.any()).refine() with z.array(z.string()) since config
input is always strings that get converted to RegExp via
convertStringsToRegex() after parsing. Destructure supportedMimeTypes
from spreads to avoid string[]/RegExp[] type mismatch.
* refactor: Tighten enum, role, and numeric constraint schemas
- Type engineSTT as enum ['openai', 'azureOpenAI']
- Type engineTTS as enum ['openai', 'azureOpenAI', 'elevenlabs', 'localai']
- Constrain playbackRate to 0.25–4 range
- Type titleMessageRole as enum ['system', 'user', 'assistant']
- Add int().nonnegative() to MCP timeout and firecrawl timeout
* chore: Bump librechat-data-provider to 0.8.405
* fix: Accept both string and RegExp in supportedMimeTypes schema
The schema must accept both string[] (config input) and RegExp[]
(post-merge runtime) since tests validate merged output against the
schema. Use z.union([z.string(), z.instanceof(RegExp)]) to handle both.
* refactor: Address review findings for schema tightening PR
- Revert changeTrackingOptions.schema to z.record(z.unknown()) (JSON Schema is nested, not flat strings)
- Remove dead contextStrategy code from BaseClient.js and cleanup.js
- Extract paramDefinitionSchema to named exported constant
- Add .int() constraint to columnSpan and columns
- Apply consistent .int().nonnegative() to initTimeout, sseReadTimeout, scraperTimeout
- Update stale stderr JSDoc to match actual accepted types
- Add comprehensive tests for paramDefinitionSchema, tModelSpecPresetSchema,
endpointSchema deprecated field stripping, and azureEndpointSchema
* fix: Address second review pass findings
- Revert supportedMimeTypesSchema to z.array(z.string()) and remove
as string[] casts — fix tests to not validate merged RegExp[] output
against the config input schema
- Remove unused tModelSpecSchema import from test file
- Consolidate duplicate '../src/schemas' imports
- Add expiredAt coverage to tModelSpecPresetSchema test
- Assert plugins is absent in azureEndpointSchema test
- Add sync comments for engineSTT/engineTTS enum literals
* refactor: Omit preset-management fields from tModelSpecPresetSchema
Omit conversationId, presetId, title, defaultPreset, and order from the
model spec preset schema — these are preset-management fields that don't
belong in model spec configuration.
* 🔒 fix: Resolve env vars before body placeholder expansion to prevent secret exfiltration
Body placeholders ({{LIBRECHAT_BODY_*}}) were substituted before
extractEnvVariable ran, allowing user-controlled body fields containing
${SECRET} patterns to be expanded into real environment values in
outbound headers. Reorder so env vars resolve first, preventing
untrusted input from triggering env expansion.
* 🛡️ fix: Block sensitive infrastructure env vars from placeholder resolution
Add isSensitiveEnvVar blocklist to extractEnvVariable so that internal
infrastructure secrets (JWT_SECRET, JWT_REFRESH_SECRET, CREDS_KEY,
CREDS_IV, MEILI_MASTER_KEY, MONGO_URI, REDIS_URI, REDIS_PASSWORD)
can never be resolved via ${VAR} expansion — even if an attacker
manages to inject a placeholder pattern.
Uses exact-match set (not substring patterns) to avoid breaking
legitimate operator config that references OAuth/API secrets in
MCP and custom endpoint configurations.
* 🧹 test: Rename ANOTHER_SECRET test fixture to ANOTHER_VALUE
Avoid using SECRET-containing names for non-sensitive test fixtures
to prevent confusion with the new isSensitiveEnvVar blocklist.
* 🔒 fix: Resolve env vars before all user-controlled substitutions in processSingleValue
Move extractEnvVariable to run on the raw admin-authored template
BEFORE customUserVars, user fields, OIDC tokens, and body placeholders.
Previously env resolution ran after customUserVars, so a user setting
a custom MCP variable to "${SECRET}" could still trigger env expansion.
Now env vars are resolved strictly on operator config, and all
subsequent user-controlled substitutions cannot introduce ${VAR} patterns
that would be expanded.
Gated by !dbSourced so DB-stored servers continue to skip env resolution.
Adds a security-invariant comment documenting the ordering requirement.
* 🧪 test: Comprehensive security regression tests for placeholder injection
- Cover all three body fields (conversationId, parentMessageId, messageId)
- Add user-field injection test (user.name containing ${VAR})
- Add customUserVars injection test (MY_TOKEN = "${VAR}")
- Add processMCPEnv injection tests for body and customUserVars paths
- Remove redundant process.env setup/teardown already handled by beforeEach/afterEach
* 🧹 chore: Add REDIS_PASSWORD to blocklist integration test; document customUserVars gate
* fix: MCP server configuration validation and schema
- Added tests to reject URLs containing environment variable references for SSE, streamable-http, and websocket types in the MCP routes.
- Introduced a new schema in the data provider to ensure user input URLs do not resolve environment variables, enhancing security against potential leaks.
- Updated existing MCP server user input schema to utilize the new validation logic, ensuring consistent handling of user-supplied URLs across the application.
* fix: MCP URL validation to reject env variable references
- Updated tests to ensure that URLs for SSE, streamable-http, and websocket types containing environment variable patterns are rejected, improving security against potential leaks.
- Refactored the MCP server user input schema to enforce stricter validation rules, preventing the resolution of environment variables in user-supplied URLs.
- Introduced new test cases for various URL types to validate the rejection logic, ensuring consistent handling across the application.
* test: Enhance MCPServerUserInputSchema tests for environment variable handling
- Introduced new test cases to validate the prevention of environment variable exfiltration through user input URLs in the MCPServerUserInputSchema.
- Updated existing tests to confirm that URLs containing environment variable patterns are correctly resolved or rejected, improving security against potential leaks.
- Refactored test structure to better organize environment variable handling scenarios, ensuring comprehensive coverage of edge cases.
* fix: subdirectory redirects
* fix: use path-segment boundary check when stripping BASE_URL prefix
A bare `startsWith(BASE_URL)` matches on character prefix, not path
segments. With BASE_URL="/chat", a path like "/chatroom/c/abc" would
incorrectly strip to "room/c/abc" (no leading slash). Guard with an
exact-match-or-slash check: `p === BASE_URL || p.startsWith(BASE_URL + '/')`.
Also removes the dead `BASE_URL !== '/'` guard — module init already
converts '/' to ''.
* test: add path-segment boundary tests and clarify subdirectory coverage
- Add /chatroom, /chatbot, /app/chatroom regression tests to verify
BASE_URL stripping only matches on segment boundaries
- Clarify useAuthRedirect subdirectory test documents React Router
basename behavior (BASE_URL stripping tested in api-endpoints-subdir)
- Use `delete proc.browser` instead of undefined assignment for cleanup
- Add rationale to eslint-disable comment for isolateModules require
* fix: use relative path and correct instructions in subdirectory test script
- Replace hardcoded /home/danny/LibreChat/.env with repo-root-relative
path so the script works from any checkout location
- Update instructions to use production build (npm run build && npm run
backend) since nginx proxies to :3080 which only serves the SPA after
a full build, not during frontend:dev on :3090
* fix: skip pointless redirect_to=/ for root path and fix jsdom 26+ compat
buildLoginRedirectUrl now returns plain /login when the resolved path
is root — redirect_to=/ adds no value since / immediately redirects
to /c/new after login anyway.
Also rewrites api-endpoints.spec.ts to use window.history.replaceState
instead of Object.defineProperty(window, 'location', ...) which jsdom
26+ no longer allows.
* test: fix request-interceptor.spec.ts for jsdom 26+ compatibility
Switch from jsdom to happy-dom environment which allows
Object.defineProperty on window.location. jsdom 26+ made
location non-configurable, breaking all 8 tests in this file.
* chore: update browser property handling in api-endpoints-subdir test
Changed the handling of the `proc.browser` property from deletion to setting it to false, ensuring compatibility with the current testing environment.
* chore: update backend restart instructions in test subdirectory setup script
Changed the instruction for restarting the backend from "npm run backend:dev" to "npm run backend" to reflect the correct command for the current setup.
* refactor: ensure proper cleanup in loadModuleWithBase function
Wrapped the module loading logic in a try-finally block to guarantee that the `proc.browser` property is reset to false and the base element is removed, improving reliability in the testing environment.
* refactor: improve browser property handling in loadModuleWithBase function
Revised the management of the `proc.browser` property to store the original value before modification, ensuring it is restored correctly after module loading. This enhances the reliability of the testing environment.
* ♻️ refactor: Centralize `buildLoginRedirectUrl` in data-provider
Move `buildLoginRedirectUrl` from `client/src/utils/redirect.ts` into
`packages/data-provider/src/api-endpoints.ts` so the axios 401
interceptor (and any other data-provider consumer) can use the canonical
implementation with the LOGIN_PATH_RE guard and BASE_URL awareness.
The client module now re-exports from `librechat-data-provider`, keeping
all existing imports working unchanged.
* 🔒 fix: Shared link 401 interceptor bypass and redirect loop (#12033)
Fixes three issues in the axios 401 response interceptor that prevented
private shared links (ALLOW_SHARED_LINKS_PUBLIC=false) from working:
1. `window.location.href.includes('share/')` matched the full URL
(including query params and hash), causing false positives. Changed
to `window.location.pathname.startsWith('/share/')`.
2. When token refresh returned no token on a share page, the
interceptor logged and fell through without redirecting, causing an
infinite retry loop via React Query. Now redirects to login using
`buildLoginRedirectUrl()` which preserves the share URL for
post-login navigation.
3. `processQueue` was never called in the no-token branch, leaving
queued requests with dangling promise callbacks. Added
`processQueue(error, null)` before the redirect.
* ✅ test: Comprehensive 401 interceptor tests for shared link auth flow
Rewrite interceptor test suite to cover all shared link auth scenarios:
- Unauthenticated user on share page with failed refresh → redirect
- Authenticated user on share page with failed refresh → redirect
- share/ in query params does NOT bypass the auth header guard
- Login path guard: redirect to plain /login (no redirect_to loop)
- Refresh success: assert exact call count (toBe(3) vs toBeGreaterThan)
Test reliability improvements:
- window.location teardown moved to afterEach (no state leak on failure)
- expect.assertions(N) on all tests (catch silent false passes)
- Shared setWindowLocation helper for consistent location mocking
* ♻️ refactor: Import `buildLoginRedirectUrl` directly from data-provider
Update `AuthContext.tsx` and `useAuthRedirect.ts` to import
`buildLoginRedirectUrl` from `librechat-data-provider` instead of
re-exporting through `~/utils/redirect.ts`.
Convert `redirect.ts` to ESM-style inline exports and remove the
re-export of `buildLoginRedirectUrl`.
* ✅ test: Move `buildLoginRedirectUrl` tests to data-provider
Tests for `buildLoginRedirectUrl` now live alongside the implementation
in `packages/data-provider/specs/api-endpoints.spec.ts`.
Removed the duplicate describe block from the client redirect test file
since it no longer owns that function.
* fix: complete OIDC logout implementation
The OIDC logout feature added in #5626 was incomplete:
1. Backend: Missing id_token_hint/client_id parameters required by the
RP-Initiated Logout spec. Keycloak 18+ rejects logout without these.
2. Frontend: The logout redirect URL was passed through isSafeRedirect()
which rejects all absolute URLs. The redirect was silently dropped.
Backend: Add id_token_hint (preferred) or client_id (fallback) to the
logout URL for OIDC spec compliance.
Frontend: Use window.location.replace() for logout redirects from the
backend, bypassing isSafeRedirect() which was designed for user-input
validation.
Fixes#5506
* fix: accept undefined in setTokenHeader to properly clear Authorization header
When token is undefined, delete the Authorization header instead of
setting it to "Bearer undefined". Removes the @ts-ignore workaround
in AuthContext.
* fix: skip axios 401 refresh when Authorization header is cleared
When the Authorization header has been removed (e.g. during logout),
the response interceptor now skips the token refresh flow. This
prevents a successful refresh from canceling an in-progress OIDC
external redirect via window.location.replace().
* fix: guard against undefined OPENID_CLIENT_ID in logout URL
Prevent literal "client_id=undefined" in the OIDC end-session URL
when OPENID_CLIENT_ID is not set. Log a warning when neither
id_token_hint nor client_id is available.
* fix: prevent race condition canceling OIDC logout redirect
The logout mutation wrapper's cleanup (clearStates, removeQueries)
triggers re-renders and 401s on in-flight requests. The axios
interceptor would refresh the token successfully, firing
dispatchTokenUpdatedEvent which cancels the window.location.replace()
navigation to the IdP's end_session_endpoint.
Fix:
- Clear Authorization header synchronously before redirect so the
axios interceptor skips refresh for post-logout 401s
- Add isExternalRedirectRef to suppress silentRefresh and useEffect
side effects during the redirect
- Add JSDoc explaining why isSafeRedirect is bypassed
* test: add LogoutController and AuthContext logout test coverage
LogoutController.spec.js (13 tests):
- id_token_hint from session and cookie fallback
- client_id fallback, including undefined OPENID_CLIENT_ID guard
- Disabled endpoint, missing issuer, non-OpenID user
- post_logout_redirect_uri (custom and default)
- Missing OpenID config and end_session_endpoint
- Error handling and cookie clearing
AuthContext.spec.tsx (3 tests):
- OIDC redirect calls window.location.replace + setTokenHeader
- Non-redirect logout path
- Logout error handling
* test: add coverage for setTokenHeader, axios interceptor guard, and silentRefresh suppression
headers-helpers.spec.ts (3 tests):
- Sets Authorization header with Bearer token
- Deletes Authorization header when called with undefined
- No-op when clearing an already absent header
request-interceptor.spec.ts (2 tests):
- Skips refresh when Authorization header is cleared (the race fix)
- Attempts refresh when Authorization header is present
AuthContext.spec.tsx (1 new test):
- Verifies silentRefresh is not triggered after OIDC redirect
* test: enhance request-interceptor tests with adapter restoration and refresh verification
- Store the original axios adapter before tests and restore it after all tests to prevent side effects.
- Add verification for the refresh endpoint call in the interceptor tests to ensure correct behavior during token refresh attempts.
* test: enhance AuthContext tests with live rendering and improved logout error handling
- Introduced a new `renderProviderLive` function to facilitate testing with silentRefresh.
- Updated tests to use the live rendering function, ensuring accurate simulation of authentication behavior.
- Enhanced logout error handling test to verify that auth state is cleared without external redirects.
* test: update LogoutController tests for OpenID config error handling
- Renamed test suite to clarify that it handles cases when OpenID config is not available.
- Modified test to check for error thrown by getOpenIdConfig instead of returning null, ensuring proper logging of the error message.
* refactor: improve OpenID config error handling in LogoutController
- Simplified error handling for OpenID configuration retrieval by using a try-catch block.
- Updated logging to provide clearer messages when the OpenID config is unavailable.
- Ensured that the end session endpoint is only accessed if the OpenID config is successfully retrieved.
---------
Co-authored-by: cloudspinner <stijn.tastenhoye@gmail.com>
* feat(data-provider): include timezone and weekday label in current_datetime
* fix(data-provider): use named weekday for both date variables and single dayjs instance
Use a single `const now = dayjs()` instead of 5 separate instantiations,
apply named weekday to `{{current_date}}` (not just `{{current_datetime}}`),
simplify weekday format from `(weekday=Monday)` to `(Monday)`, and
harden test mock fallback to throw on unhandled format strings.
* chore(data-provider): remove dead day() mock from parsers spec
---------
Co-authored-by: Peter Rothlaender <peter.rothlaender@ginkgo.com>
* 🧠 feat: Add reasoning_effort configuration for Bedrock models
- Introduced a new `reasoning_effort` setting in the Bedrock configuration, allowing users to specify the reasoning level for supported models.
- Updated the input parser to map `reasoning_effort` to `reasoning_config` for Moonshot and ZAI models, ensuring proper handling of reasoning levels.
- Enhanced tests to validate the mapping of `reasoning_effort` to `reasoning_config` and to ensure correct behavior for various model types, including Anthropic models.
- Updated translation files to include descriptions for the new configuration option.
* chore: Update translation keys for Bedrock reasoning configuration
- Renamed translation key from `com_endpoint_bedrock_reasoning_config` to `com_endpoint_bedrock_reasoning_effort` for consistency with the new configuration setting.
- Updated the parameter settings to reflect the change in the description key, ensuring accurate mapping in the application.
* 🧪 test: Enhance bedrockInputParser tests for reasoning_config handling
- Added tests to ensure that stale `reasoning_config` is stripped when switching models from Moonshot to Meta and ZAI to DeepSeek.
- Included additional tests to verify that `reasoning_effort` values of "none", "minimal", and "xhigh" do not forward to `reasoning_config` for Moonshot and ZAI models.
- Improved coverage for the bedrockInputParser functionality to ensure correct behavior across various model configurations.
* feat: Introduce Bedrock reasoning configuration and update input parser
- Added a new `BedrockReasoningConfig` enum to define reasoning levels: low, medium, and high.
- Updated the `bedrockInputParser` to utilize the new reasoning configuration, ensuring proper handling of `reasoning_effort` values.
- Enhanced logic to validate `reasoning_effort` against the defined configuration values before assigning to `reasoning_config`.
- Improved code clarity with additional comments and refactored conditions for better readability.
* 🤖 feat: Claude Sonnet 4.6 support
- Updated .env.example to include claude-sonnet-4-6 in the list of available models.
- Enhanced token value assignments in api/models/tx.js and packages/api/src/utils/tokens.ts to accommodate claude-sonnet-4-6.
- Added tests in packages/data-provider/specs/bedrock.spec.ts to verify support for claude-sonnet-4-6 in adaptive thinking and context-1m functionalities.
- Modified bedrock.ts to correctly parse and identify the version of claude-sonnet-4-6 for adaptive thinking checks.
- Included claude-sonnet-4-6 in sharedAnthropicModels and bedrockModels for consistent model availability.
* chore: additional Claude Sonnet 4.6 tests
- Added unit tests for Claude Sonnet 4.6 in `tokens.spec.js` to verify context length and max output tokens.
- Updated `helpers.ts` documentation to reflect adaptive thinking support for Sonnet 4.6.
- Enhanced `llm.spec.ts` with tests for context headers and adaptive thinking configurations for Claude Sonnet 4.6.
- Improved `bedrock.spec.ts` to ensure correct parsing and handling of Claude Sonnet 4.6 model variations with adaptive thinking.
* 🔧 refactor: Simplify payload parsing and enhance getSaveOptions logic
- Removed unused bedrockInputSchema from payloadParser, streamlining the function.
- Updated payloadParser to handle optional chaining for model parameters.
- Enhanced getSaveOptions to ensure runOptions defaults to an empty object if parsing fails, improving robustness.
- Adjusted the assignment of maxContextTokens to use the instance variable for consistency.
* 🔧 fix: Update maxContextTokens assignment logic in initializeAgent function
- Enhanced the maxContextTokens assignment to allow for user-defined values, ensuring it defaults to a calculated value only when not provided or invalid. This change improves flexibility in agent initialization.
* 🧪 test: Add unit tests for initializeAgent function
- Introduced comprehensive unit tests for the initializeAgent function, focusing on maxContextTokens behavior.
- Tests cover scenarios for user-defined values, fallback calculations, and edge cases such as zero and negative values, enhancing overall test coverage and reliability of agent initialization logic.
* refactor: default params Endpoint Configuration Handling
- Integrated `getEndpointsConfig` to fetch endpoint configurations, allowing for dynamic handling of `defaultParamsEndpoint`.
- Updated `buildEndpointOption` to pass `defaultParamsEndpoint` to `parseCompactConvo`, ensuring correct parameter handling based on endpoint type.
- Added comprehensive unit tests for `buildDefaultConvo` and `cleanupPreset` to validate behavior with `defaultParamsEndpoint`, covering various scenarios and edge cases.
- Refactored related hooks and utility functions to support the new configuration structure, improving overall flexibility and maintainability.
* refactor: Centralize defaultParamsEndpoint retrieval
- Introduced `getDefaultParamsEndpoint` function to streamline the retrieval of `defaultParamsEndpoint` across various hooks and middleware.
- Updated multiple files to utilize the new function, enhancing code consistency and maintainability.
- Removed redundant logic for fetching `defaultParamsEndpoint`, simplifying the codebase.
* refactor: better SSRF Protection in Action and Tool Services
- Added `createSSRFSafeAgents` function to create HTTP/HTTPS agents that block connections to private/reserved IP addresses, enhancing security against SSRF attacks.
- Updated `createActionTool` to accept a `useSSRFProtection` parameter, allowing the use of SSRF-safe agents during tool execution.
- Modified `processRequiredActions` and `loadAgentTools` to utilize the new SSRF protection feature based on allowed domains configuration.
- Introduced `resolveHostnameSSRF` function to validate resolved IPs against private ranges, preventing potential SSRF vulnerabilities.
- Enhanced tests for domain resolution and private IP detection to ensure robust SSRF protection mechanisms are in place.
* feat: Implement SSRF protection in MCP connections
- Added `createSSRFSafeUndiciConnect` function to provide SSRF-safe DNS lookup options for undici agents.
- Updated `MCPConnection`, `MCPConnectionFactory`, and `ConnectionsRepository` to include `useSSRFProtection` parameter, enabling SSRF protection based on server configuration.
- Enhanced `MCPManager` and `UserConnectionManager` to utilize SSRF protection when establishing connections.
- Updated tests to validate the integration of SSRF protection across various components, ensuring robust security measures are in place.
* refactor: WS MCPConnection with SSRF protection and async transport construction
- Added `resolveHostnameSSRF` to validate WebSocket hostnames against private IP addresses, enhancing SSRF protection.
- Updated `constructTransport` method to be asynchronous, ensuring proper handling of SSRF checks before establishing connections.
- Improved error handling for WebSocket transport to prevent connections to potentially unsafe addresses.
* test: Enhance ActionRequest tests for SSRF-safe agent passthrough
- Added tests to verify that httpAgent and httpsAgent are correctly passed to axios.create when provided in ActionRequest.
- Included scenarios to ensure agents are not included when no options are specified.
- Enhanced coverage for POST requests to confirm agent passthrough functionality.
- Improved overall test robustness for SSRF protection in ActionRequest execution.
* feat: Add support for Apache Parquet MIME types
- Introduced 'application/x-parquet' to the full MIME types list and code interpreter MIME types list.
- Updated application MIME types regex to include 'x-parquet' and 'vnd.apache.parquet'.
- Added mapping for '.parquet' files to 'application/x-parquet' in code type mapping, enhancing file format support.
* feat: Implement atomic file claiming for code execution outputs
- Added a new `claimCodeFile` function to atomically claim a file_id for code execution outputs, preventing duplicates by using a compound key of filename and conversationId.
- Updated `processCodeOutput` to utilize the new claiming mechanism, ensuring that concurrent calls for the same filename converge on a single record.
- Refactored related tests to validate the new atomic claiming behavior and its impact on file usage tracking and versioning.
* fix: Update image file handling to use cache-busting filepath
- Modified the `processCodeOutput` function to generate a cache-busting filepath for updated image files, improving browser caching behavior.
- Adjusted related tests to reflect the change from versioned filenames to cache-busted filepaths, ensuring accurate validation of image updates.
* fix: Update step handler to prevent undefined content for non-tool call types
- Modified the condition in useStepHandler to ensure that undefined content is only assigned for specific content types, enhancing the robustness of content handling.
* fix: Update bedrockOutputParser to handle maxTokens for adaptive models
- Modified the bedrockOutputParser logic to ensure that maxTokens is not set for adaptive models when neither maxTokens nor maxOutputTokens are provided, improving the handling of adaptive thinking configurations.
- Updated related tests to reflect these changes, ensuring accurate validation of the output for adaptive models.
* chore: Update @librechat/agents to version 3.1.38 in package.json and package-lock.json
* fix: Enhance file claiming and error handling in code processing
- Updated the `processCodeOutput` function to use a consistent file ID for claiming files, preventing duplicates and improving concurrency handling.
- Refactored the `createFileMethods` to include error handling for failed file claims, ensuring robust behavior when claiming files for conversations.
- These changes enhance the reliability of file management in the application.
* fix: Update adaptive thinking test for Opus 4.6 model
- Modified the test for configuring adaptive thinking to reflect that no default maxTokens should be set for the Opus 4.6 model.
- Updated assertions to ensure that maxTokens is undefined, aligning with the expected behavior for adaptive models.
* fix: Update parseTextParts to handle undefined content parts
- Modified the parseTextParts function to accept an array of content parts that may include undefined values.
- Implemented optional chaining to safely check for the type of each part, preventing potential runtime errors when accessing properties of undefined elements.
* refactor: Tool Call Configuration with Session Context
- Added support for including session ID and injected files in the tool call configuration when a code session context is present.
- Improved handling of tool call configurations to accommodate additional context data, enhancing the functionality of the tool execution handler.
* chore: Update @librechat/agents to version 3.1.37 in package.json and package-lock.json
* test: Add unit tests for createToolExecuteHandler
- Introduced a new test suite for the createToolExecuteHandler function, validating the handling of session context in tool calls.
- Added tests to ensure correct passing of session IDs and injected files based on the presence of codeSessionContext.
- Included scenarios for handling multiple tool calls and ensuring non-code execution tools are unaffected by session context.
* test: Update createToolExecuteHandler tests for session context handling
- Renamed test to clarify that it checks for the absence of session context in non-code-execution tools.
- Updated assertions to ensure that session_id and _injected_files are undefined when non-code-execution tools are invoked, enhancing test accuracy.
* feat: Implement new features for Claude Opus 4.6 model
- Added support for tiered pricing based on input token count for the Claude Opus 4.6 model.
- Updated token value calculations to include inputTokenCount for accurate pricing.
- Enhanced transaction handling to apply premium rates when input tokens exceed defined thresholds.
- Introduced comprehensive tests to validate pricing logic for both standard and premium rates across various scenarios.
- Updated related utility functions and models to accommodate new pricing structure.
This change improves the flexibility and accuracy of token pricing for the Claude Opus 4.6 model, ensuring users are charged appropriately based on their usage.
* feat: Add effort field to conversation and preset schemas
- Introduced a new optional `effort` field of type `String` in both the `IPreset` and `IConversation` interfaces.
- Updated the `conversationPreset` schema to include the `effort` field, enhancing the data structure for better context management.
* chore: Clean up unused variable and comments in initialize function
* chore: update dependencies and SDK versions
- Updated @anthropic-ai/sdk to version 0.73.0 in package.json and overrides.
- Updated @anthropic-ai/vertex-sdk to version 0.14.3 in packages/api/package.json.
- Updated @librechat/agents to version 3.1.34 in packages/api/package.json.
- Refactored imports in packages/api/src/endpoints/anthropic/vertex.ts for consistency.
* chore: remove postcss-loader from dependencies
* feat: Bedrock model support for adaptive thinking configuration
- Updated .env.example to include new Bedrock model IDs for Claude Opus 4.6.
- Refactored bedrockInputParser to support adaptive thinking for Opus models, allowing for dynamic thinking configurations.
- Introduced a new function to check model compatibility with adaptive thinking.
- Added an optional `effort` field to the input schemas and updated related configurations.
- Enhanced tests to validate the new adaptive thinking logic and model configurations.
* feat: Add tests for Opus 4.6 adaptive thinking configuration
* feat: Update model references for Opus 4.6 by removing version suffix
* feat: Update @librechat/agents to version 3.1.35 in package.json and package-lock.json
* chore: @librechat/agents to version 3.1.36 in package.json and package-lock.json
* feat: Normalize inputTokenCount for spendTokens and enhance transaction handling
- Introduced normalization for promptTokens to ensure inputTokenCount does not go negative.
- Updated transaction logic to reflect normalized inputTokenCount in pricing calculations.
- Added comprehensive tests to validate the new normalization logic and its impact on transaction rates for both standard and premium models.
- Refactored related functions to improve clarity and maintainability of token value calculations.
* chore: Simplify adaptive thinking configuration in helpers.ts
- Removed unnecessary type casting for the thinking property in updatedOptions.
- Ensured that adaptive thinking is directly assigned when conditions are met, improving code clarity.
* refactor: Replace hard-coded token values with dynamic retrieval from maxTokensMap in model tests
* fix: Ensure non-negative token values in spendTokens calculations
- Updated token value retrieval to use Math.max for prompt and completion tokens, preventing negative values.
- Enhanced clarity in token calculations for both prompt and completion transactions.
* test: Add test for normalization of negative structured token values in spendStructuredTokens
- Implemented a test to ensure that negative structured token values are normalized to zero during token spending.
- Verified that the transaction rates remain consistent with the expected standard values after normalization.
* refactor: Bedrock model support for adaptive thinking and context handling
- Added tests for various alternate naming conventions of Claude models to validate adaptive thinking and context support.
- Refactored `supportsAdaptiveThinking` and `supportsContext1m` functions to utilize new parsing methods for model version extraction.
- Updated `bedrockInputParser` to handle effort configurations more effectively and strip unnecessary fields for non-adaptive models.
- Improved handling of anthropic model configurations in the input parser.
* fix: Improve token value retrieval in getMultiplier function
- Updated the token value retrieval logic to use optional chaining for better safety against undefined values.
- Added a test case to ensure that the function returns the default rate when the provided valueKey does not exist in tokenValues.
* 🪨 feat: Anthropic Beta Support for Bedrock
- Updated the Bedrock input parser to dynamically generate `anthropic_beta` headers based on the model identifier.
- Added a new utility function `getBedrockAnthropicBetaHeaders` to determine applicable headers for various Anthropic models.
- Modified existing tests to reflect changes in expected `anthropic_beta` values, including new test cases for full model IDs.
* test: Update Bedrock Input Parser Tests for Beta Headers
- Modified the test case for explicit thinking configuration to reflect the addition of `anthropic_beta` headers.
- Ensured that the test now verifies the presence of specific beta header values in the additional model request fields.
* feat(bedrock): add Moonshot Kimi K2 Thinking model support
- Add Moonshot provider to BedrockProviders enum
- Add Moonshot-specific parameter settings with 16384 default max tokens
- Add conditional for anthropic_beta to only apply to Anthropic models
- Kimi K2 Thinking model: moonshot.kimi-k2-thinking (256K context)
* Delete add-kimi-bedrock.md
* Remove comment on anthropic_beta condition
Remove comment about adding anthropic_beta for Anthropic models.
* chore: enum order
* feat(bedrock): add tests to ensure anthropic_beta is not added to Moonshot Kimi K2 and DeepSeek models
---------
Co-authored-by: Danny Avila <danacordially@gmail.com>
Co-authored-by: Danny Avila <danny@librechat.ai>
* 🔒 fix: `iconURL` in conversation parsing
- Updated the `buildEndpointOption` middleware to derive `iconURL` from model specs when not provided by the client, improving security by preventing malicious URLs.
- Modified the `parseCompactConvo` function to strip `iconURL` from conversation inputs, ensuring it is only set server-side.
- Added comprehensive tests to validate the stripping of `iconURL` across various endpoint types, enhancing overall input sanitization.
* ✨ feat: Add ESLint rule for unused variables
- Introduced a new ESLint rule to warn about unused variables, allowing for better code quality and maintainability.
- Configured the rule to ignore variables and arguments that start with an underscore, accommodating common coding practices.