diff --git a/extensions/anthropic-vertex/region.ts b/extensions/anthropic-vertex/region.ts index 544ec83bbc02..0aa43f8c6311 100644 --- a/extensions/anthropic-vertex/region.ts +++ b/extensions/anthropic-vertex/region.ts @@ -120,6 +120,7 @@ function resolveAnthropicVertexProjectIdFromAdc( return undefined; } try { + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- ADC credentials are external JSON; only optional project ids are consumed. const parsed = JSON.parse(readFileSync(credentialsPath, "utf8")) as AdcProjectFile; return ( normalizeOptionalSecretInput(parsed.project_id) || diff --git a/extensions/anthropic-vertex/stream-runtime.ts b/extensions/anthropic-vertex/stream-runtime.ts index f9b4ae0cc263..c49e2b2cd86a 100644 --- a/extensions/anthropic-vertex/stream-runtime.ts +++ b/extensions/anthropic-vertex/stream-runtime.ts @@ -115,6 +115,7 @@ function createAnthropicVertexOnPayload(params: { function applyPolicy(payload: unknown): unknown { if (payload && typeof payload === "object" && !Array.isArray(payload)) { + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Anthropic payload policy mutates open provider JSON params. applyAnthropicPayloadPolicyToParams(payload as Record, policy); } return payload; @@ -149,6 +150,7 @@ export function createAnthropicVertexStreamFn( }); return (model, context, options) => { + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- This stream adapter is registered only for Anthropic Messages models. const transportModel = model as Model<"anthropic-messages"> & { api: string; baseUrl?: string; @@ -188,7 +190,8 @@ export function createAnthropicVertexStreamFn( const budgets = options.thinkingBudgets; opts.thinkingBudgetTokens = (budgets && options.reasoning in budgets - ? budgets[options.reasoning as keyof typeof budgets] + ? // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- The key presence check above narrows runtime indexing for configured budgets. + budgets[options.reasoning as keyof typeof budgets] : undefined) ?? 10000; } } else { diff --git a/extensions/mattermost/src/mattermost/accounts.ts b/extensions/mattermost/src/mattermost/accounts.ts index 74131bdffb74..02b3ab4abd4d 100644 --- a/extensions/mattermost/src/mattermost/accounts.ts +++ b/extensions/mattermost/src/mattermost/accounts.ts @@ -67,7 +67,9 @@ function mergeMattermostAccountConfig( accountId: string, ): MattermostAccountConfig { return resolveMergedAccountConfig({ + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Mattermost channel config is plugin-owned open config merged by the account resolver. channelConfig: cfg.channels?.mattermost as MattermostAccountConfig | undefined, + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Mattermost account entries are plugin-owned open config records. accounts: cfg.channels?.mattermost?.accounts as | Record> | undefined, diff --git a/extensions/mattermost/src/mattermost/client.ts b/extensions/mattermost/src/mattermost/client.ts index affc62850ddf..70322a17c48e 100644 --- a/extensions/mattermost/src/mattermost/client.ts +++ b/extensions/mattermost/src/mattermost/client.ts @@ -82,6 +82,7 @@ function buildMattermostApiUrl(baseUrl: string, path: string): string { export async function readMattermostError(res: Response): Promise { const contentType = res.headers.get("content-type") ?? ""; if (contentType.includes("application/json")) { + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Mattermost error payloads are external JSON; only optional message is consumed. const data = (await res.json()) as { message?: string } | undefined; if (data?.message) { return data.message; @@ -151,14 +152,17 @@ export function createMattermostClient(params: { } if (res.status === 204) { + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Generic request callers type the expected endpoint body; 204 has no body. return undefined as T; } const contentType = res.headers.get("content-type") ?? ""; if (contentType.includes("application/json")) { + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Generic request callers type the expected Mattermost endpoint body. return (await res.json()) as T; } + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Generic request callers type the expected Mattermost endpoint body. return (await res.text()) as T; }; @@ -594,6 +598,7 @@ export async function uploadMattermostFile( throw new Error(`Mattermost API ${res.status} ${res.statusText}: ${detail || "unknown error"}`); } + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Mattermost upload response is external JSON; required file id is checked below. const data = (await res.json()) as { file_infos?: MattermostFileInfo[] }; const info = data.file_infos?.[0]; if (!info?.id) { diff --git a/extensions/microsoft/speech-provider.ts b/extensions/microsoft/speech-provider.ts index 78023ec3b26b..d895a50d2c63 100644 --- a/extensions/microsoft/speech-provider.ts +++ b/extensions/microsoft/speech-provider.ts @@ -165,6 +165,7 @@ export async function listMicrosoftVoices(): Promise { }); } await assertOkOrThrowProviderError(response, "Microsoft voices API error"); + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Microsoft voice-list payload is external JSON filtered before returning options. const voices = (await response.json()) as MicrosoftVoiceListEntry[]; return Array.isArray(voices) ? voices diff --git a/extensions/vydra/shared.ts b/extensions/vydra/shared.ts index 04681915fb5e..8cd399c9c912 100644 --- a/extensions/vydra/shared.ts +++ b/extensions/vydra/shared.ts @@ -42,7 +42,8 @@ type VydraJobPayload = { function asObject(value: unknown): Record | undefined { return typeof value === "object" && value !== null && !Array.isArray(value) - ? (value as Record) + ? // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Vydra webhook payloads are external JSON objects walked defensively by key. + (value as Record) : undefined; } diff --git a/packages/speech-core/src/tts.ts b/packages/speech-core/src/tts.ts index 0a99a6fd0770..d2071edec0d6 100644 --- a/packages/speech-core/src/tts.ts +++ b/packages/speech-core/src/tts.ts @@ -351,13 +351,15 @@ function resolveTtsRuntimeConfig(cfg: OpenClawConfig): OpenClawConfig { function asProviderConfig(value: unknown): SpeechProviderConfig { return typeof value === "object" && value !== null && !Array.isArray(value) - ? (value as SpeechProviderConfig) + ? // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Speech provider configs are open JSON records normalized at the plugin boundary. + (value as SpeechProviderConfig) : {}; } function asProviderConfigMap(value: unknown): Record { return typeof value === "object" && value !== null && !Array.isArray(value) - ? (value as Record) + ? // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- TTS provider config maps are open JSON records keyed by provider id. + (value as Record) : {}; } @@ -728,6 +730,7 @@ function readPrefs(prefsPath: string): TtsUserPrefs { if (!existsSync(prefsPath)) { return {}; } + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- User prefs are trusted local JSON and unknown keys are ignored by readers. return JSON.parse(readFileSync(prefsPath, "utf8")) as TtsUserPrefs; } catch { return {}; @@ -900,12 +903,14 @@ export function resolveExplicitTtsOverrides(params: { `TTS provider "${selectedProvider}" ignored the requested model or voice overrides.`, ); } + if (!providerOverrides) { + throw new Error(`TTS provider "${selectedProvider}" did not return talk overrides.`); + } - const overridesRecord = providerOverrides as SpeechProviderOverrides; return { provider: selectedProvider, providerOverrides: { - [provider.id]: overridesRecord, + [provider.id]: providerOverrides, }, }; } @@ -1815,9 +1820,10 @@ export async function textToSpeechTelephony(params: { config, provider: resolvedProvider.provider, }); - const synthesizeTelephony = resolvedProvider.provider.synthesizeTelephony as NonNullable< - typeof resolvedProvider.provider.synthesizeTelephony - >; + const synthesizeTelephony = resolvedProvider.provider.synthesizeTelephony; + if (!synthesizeTelephony) { + throw new Error(`TTS provider "${resolvedProvider.provider.id}" lost telephony support`); + } const prepared = await prepareSpeechSynthesis({ provider: resolvedProvider.provider, text: params.text, @@ -2044,6 +2050,7 @@ export async function maybeApplyTtsToPayload(params: { textForAudio = `${textForAudio.slice(0, config.maxTextLength - 3)}...`; } } catch (err) { + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Only the message is used for verbose diagnostics after a caught summarizer failure. const error = err as Error; logVerbose(`TTS: summarization failed, truncating instead: ${error.message}`); textForAudio = `${textForAudio.slice(0, maxLength - 3)}...`; diff --git a/packages/speech-core/voice-models.ts b/packages/speech-core/voice-models.ts index a22b83be5097..6c8e5c940bcc 100644 --- a/packages/speech-core/voice-models.ts +++ b/packages/speech-core/voice-models.ts @@ -101,6 +101,7 @@ export function voiceProviderSupportsModel( } export function resolveVoiceModelRefs(config: unknown): VoiceModelRef[] { + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Voice model config is an open config object; fields are normalized individually below. const voiceModel = config as VoiceModelConfig | undefined; if (typeof voiceModel === "string") { const parsed = parseVoiceModelRef(voiceModel); @@ -212,6 +213,7 @@ export function getVoiceProviderConfig>( const configuredKeys = Object.keys(params.providerConfigs); for (const candidate of candidates) { if (Object.hasOwn(params.providerConfigs, candidate)) { + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Empty provider config preserves the caller-specific config record type. return params.providerConfigs[candidate] ?? ({} as TConfig); } const normalizedCandidate = normalizeLowercaseString(candidate); @@ -219,9 +221,11 @@ export function getVoiceProviderConfig>( (key) => normalizeLowercaseString(key) === normalizedCandidate, ); if (matchingKey) { + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Empty provider config preserves the caller-specific config record type. return params.providerConfigs[matchingKey] ?? ({} as TConfig); } } + // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Empty provider config preserves the caller-specific config record type. return {} as TConfig; }