惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
V
V2EX
WordPress大学
WordPress大学
Google DeepMind News
Google DeepMind News
Martin Fowler
Martin Fowler
小众软件
小众软件
Blog — PlanetScale
Blog — PlanetScale
月光博客
月光博客
The Cloudflare Blog
T
Tailwind CSS Blog
H
Help Net Security
腾讯CDC
爱范儿
爱范儿
人人都是产品经理
人人都是产品经理
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The GitHub Blog
The GitHub Blog
Microsoft Security Blog
Microsoft Security Blog
Stack Overflow Blog
Stack Overflow Blog
D
DataBreaches.Net
C
Check Point Blog
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
美团技术团队
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
refactor(normalization): remove record coercion facades ·...
vincentkoc · 2026-06-18 · via Recent Commits to openclaw:main
11

// Gateway RPC handlers for Talk voice, transcription, and speech synthesis surfaces.

2+

import { asOptionalRecord } from "@openclaw/normalization-core/record-coerce";

23

import {

34

normalizeLowercaseStringOrEmpty,

45

normalizeOptionalLowercaseString,

@@ -45,7 +46,6 @@ import {

4546

} from "../../tts/tts.js";

4647

import { ADMIN_SCOPE, TALK_SECRETS_SCOPE } from "../operator-scopes.js";

4748

import { formatForLog } from "../ws-log.js";

48-

import { asRecord } from "./record-shared.js";

4949

import { talkClientHandlers } from "./talk-client.js";

5050

import { talkSessionHandlers } from "./talk-session.js";

5151

import {

@@ -72,7 +72,7 @@ function canReadTalkSecrets(client: { connect?: { scopes?: string[] } } | null):

7272

}

73737474

function asStringRecord(value: unknown): Record<string, string> | undefined {

75-

const record = asRecord(value);

75+

const record = asOptionalRecord(value);

7676

if (!record) {

7777

return undefined;

7878

}

@@ -113,20 +113,20 @@ function withTalkBaseTtsSpeakerSelectionCompat(

113113

baseTts: Record<string, unknown>,

114114

): Record<string, unknown> {

115115

const next = withSpeakerSelectionCompat(baseTts);

116-

const providers = asRecord(baseTts.providers);

116+

const providers = asOptionalRecord(baseTts.providers);

117117

if (providers) {

118118

next.providers = Object.fromEntries(

119119

Object.entries(providers).map(([providerId, providerConfig]) => [

120120

providerId,

121-

withSpeakerSelectionCompat(asRecord(providerConfig) ?? {}),

121+

withSpeakerSelectionCompat(asOptionalRecord(providerConfig) ?? {}),

122122

]),

123123

);

124124

}

125125

for (const [key, value] of Object.entries(baseTts)) {

126126

if (key === "providers") {

127127

continue;

128128

}

129-

const record = asRecord(value);

129+

const record = asOptionalRecord(value);

130130

if (record) {

131131

next[key] = withSpeakerSelectionCompat(record);

132132

}

@@ -157,7 +157,7 @@ function buildTalkTtsConfig(

157157

}

158158159159

const baseTts = withTalkBaseTtsSpeakerSelectionCompat(

160-

asRecord(config.messages?.tts) ?? {},

160+

asOptionalRecord(config.messages?.tts) ?? {},

161161

) as TtsConfig;

162162

const providerConfig = withSpeakerSelectionFallbackCompat(resolved.config);

163163

const resolvedProviderConfig =

@@ -172,7 +172,7 @@ function buildTalkTtsConfig(

172172

auto: "always",

173173

provider,

174174

providers: {

175-

...((asRecord(baseTts.providers) ?? {}) as TtsProviderConfigMap),

175+

...((asOptionalRecord(baseTts.providers) ?? {}) as TtsProviderConfigMap),

176176

[provider]: resolvedProviderConfig,

177177

},

178178

};

@@ -425,10 +425,10 @@ function resolveTalkResponseFromConfig(params: {

425425426426

const speechProvider = getSpeechProvider(provider, params.runtimeConfig);

427427

const sourceBaseTts = withTalkBaseTtsSpeakerSelectionCompat(

428-

asRecord(params.sourceConfig.messages?.tts) ?? {},

428+

asOptionalRecord(params.sourceConfig.messages?.tts) ?? {},

429429

);

430430

const runtimeBaseTts = withTalkBaseTtsSpeakerSelectionCompat(

431-

asRecord(params.runtimeConfig.messages?.tts) ?? {},

431+

asOptionalRecord(params.runtimeConfig.messages?.tts) ?? {},

432432

);

433433

const sourceProviderConfig = withSpeakerSelectionFallbackCompat(sourceResolved?.config);

434434

const runtimeProviderConfig = withSpeakerSelectionFallbackCompat(runtimeResolved?.config);

@@ -474,7 +474,7 @@ function stripUnresolvedSecretApiKey(config: TalkProviderConfig): TalkProviderCo

474474

function stripUnresolvedSecretApiKeysFromBaseTtsProviders(

475475

base: Record<string, unknown>,

476476

): Record<string, unknown> {

477-

const providers = asRecord(base.providers);

477+

const providers = asOptionalRecord(base.providers);

478478

if (!providers) {

479479

return base;

480480

}

@@ -486,7 +486,7 @@ function stripUnresolvedSecretApiKeysFromBaseTtsProviders(

486486

// they're already validated upstream.

487487

const cleaned: Record<string, unknown> = Object.create(null);

488488

for (const [providerId, providerConfig] of Object.entries(providers)) {

489-

const cfg = asRecord(providerConfig);

489+

const cfg = asOptionalRecord(providerConfig);

490490

if (!cfg) {

491491

cleaned[providerId] = providerConfig;

492492

continue;