Files
openclaw/extensions/lmstudio/src/provider-auth.ts
Rugved Somwanshi 0cfb83edfa feat: LM Studio Integration (#53248)
* Feat: LM Studio Integration

* Format

* Support usage in streaming true

Fix token count

* Add custom window check

* Drop max tokens fallback

* tweak docs

Update generated

* Avoid error if stale header does not resolve

* Fix test

* Fix test

* Fix rebase issues

Trim code

* Fix tests

Drop keyless

Fixes

* Fix linter issues in tests

* Update generated artifacts

* Do not have fatal header resoltuion for discovery

* Do the same for API key as well

* fix: honor lmstudio preload runtime auth

* fix: clear stale lmstudio header auth

* fix: lazy-load lmstudio runtime facade

* fix: preserve lmstudio shared synthetic auth

* fix: clear stale lmstudio header auth in discovery

* fix: prefer lmstudio header auth for discovery

* fix: honor lmstudio header auth in warmup paths

* fix: clear stale lmstudio profile auth

* fix: ignore lmstudio env auth on header migration

* fix: use local lmstudio setup seam

* fix: resolve lmstudio rebase fallout

---------

Co-authored-by: Frank Yang <frank.ekn@gmail.com>
2026-04-13 15:22:44 +08:00

60 lines
1.9 KiB
TypeScript

import {
CUSTOM_LOCAL_AUTH_MARKER,
hasConfiguredSecretInput,
normalizeOptionalSecretInput,
} from "openclaw/plugin-sdk/provider-auth";
import type { ModelProviderConfig } from "openclaw/plugin-sdk/provider-model-shared";
import { LMSTUDIO_LOCAL_API_KEY_PLACEHOLDER } from "./defaults.js";
export function hasLmstudioAuthorizationHeader(headers: unknown): boolean {
if (!headers || typeof headers !== "object" || Array.isArray(headers)) {
return false;
}
for (const [headerName, headerValue] of Object.entries(headers)) {
if (headerName.trim().toLowerCase() !== "authorization") {
continue;
}
if (hasConfiguredSecretInput(headerValue)) {
return true;
}
}
return false;
}
export function resolveLmstudioProviderAuthMode(
apiKey: ModelProviderConfig["apiKey"] | undefined,
): ModelProviderConfig["auth"] | undefined {
const normalized = normalizeOptionalSecretInput(apiKey);
if (normalized !== undefined) {
const trimmed = normalized.trim();
if (
!trimmed ||
trimmed === LMSTUDIO_LOCAL_API_KEY_PLACEHOLDER ||
trimmed === CUSTOM_LOCAL_AUTH_MARKER
) {
return undefined;
}
return "api-key";
}
return hasConfiguredSecretInput(apiKey) ? "api-key" : undefined;
}
export function shouldUseLmstudioApiKeyPlaceholder(params: {
hasModels: boolean;
resolvedApiKey: ModelProviderConfig["apiKey"] | undefined;
hasAuthorizationHeader?: boolean;
}): boolean {
return params.hasModels && !params.resolvedApiKey && !params.hasAuthorizationHeader;
}
export function shouldUseLmstudioSyntheticAuth(
providerConfig: ModelProviderConfig | undefined,
): boolean {
const hasModels = Array.isArray(providerConfig?.models) && providerConfig.models.length > 0;
return (
hasModels &&
!resolveLmstudioProviderAuthMode(providerConfig?.apiKey) &&
!hasLmstudioAuthorizationHeader(providerConfig?.headers)
);
}