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

推荐订阅源

P
Proofpoint News Feed
Martin Fowler
Martin Fowler
The GitHub Blog
The GitHub Blog
B
Blog RSS Feed
U
Unit 42
阮一峰的网络日志
阮一峰的网络日志
量子位
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
云风的 BLOG
云风的 BLOG
小众软件
小众软件
博客园 - 三生石上(FineUI控件)
L
LangChain Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园_首页
IT之家
IT之家
V
Visual Studio Blog
Y
Y Combinator Blog
Blog — PlanetScale
Blog — PlanetScale
宝玉的分享
宝玉的分享
Apple Machine Learning Research
Apple Machine Learning Research
I
InfoQ
D
Docker
V
V2EX

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
feat(providers): add provider index install metadata · op...
vincentkoc · 2026-04-26 · via Recent Commits to openclaw:main

@@ -1,3 +1,4 @@

1+

import { parseRegistryNpmSpec } from "../../infra/npm-registry-spec.js";

12

import { isBlockedObjectKey } from "../../infra/prototype-keys.js";

23

import { normalizeOptionalString } from "../../shared/string-coerce.js";

34

import { normalizeTrimmedStringList } from "../../shared/string-normalization.js";

@@ -7,7 +8,9 @@ import { normalizeModelCatalogProviderId } from "../refs.js";

78

import type { ModelCatalogProvider } from "../types.js";

89

import type {

910

OpenClawProviderIndex,

11+

OpenClawProviderIndexPluginInstall,

1012

OpenClawProviderIndexPlugin,

13+

OpenClawProviderIndexProviderAuthChoice,

1114

OpenClawProviderIndexProvider,

1215

} from "./types.js";

1316

@@ -18,6 +21,26 @@ function normalizeSafeKey(value: unknown): string {

1821

return key && !isBlockedObjectKey(key) ? key : "";

1922

}

202324+

function normalizeInstall(value: unknown): OpenClawProviderIndexPluginInstall | undefined {

25+

if (!isRecord(value)) {

26+

return undefined;

27+

}

28+

const npmSpec = normalizeOptionalString(value.npmSpec);

29+

const parsed = npmSpec ? parseRegistryNpmSpec(npmSpec) : null;

30+

if (!parsed) {

31+

return undefined;

32+

}

33+

const defaultChoice = value.defaultChoice === "npm" ? "npm" : undefined;

34+

const minHostVersion = normalizeOptionalString(value.minHostVersion);

35+

const expectedIntegrity = normalizeOptionalString(value.expectedIntegrity);

36+

return {

37+

npmSpec: parsed.raw,

38+

...(defaultChoice ? { defaultChoice } : {}),

39+

...(minHostVersion ? { minHostVersion } : {}),

40+

...(expectedIntegrity ? { expectedIntegrity } : {}),

41+

};

42+

}

43+2144

function normalizePlugin(value: unknown): OpenClawProviderIndexPlugin | undefined {

2245

if (!isRecord(value)) {

2346

return undefined;

@@ -28,10 +51,12 @@ function normalizePlugin(value: unknown): OpenClawProviderIndexPlugin | undefine

2851

}

2952

const packageName = normalizeOptionalString(value.package) ?? "";

3053

const source = normalizeOptionalString(value.source) ?? "";

54+

const install = normalizeInstall(value.install);

3155

return {

3256

id,

3357

...(packageName ? { package: packageName } : {}),

3458

...(source ? { source } : {}),

59+

...(install ? { install } : {}),

3560

};

3661

}

3762

@@ -57,6 +82,83 @@ function normalizePreviewCatalog(params: {

5782

return provider;

5883

}

598485+

function normalizeOnboardingScopes(

86+

value: unknown,

87+

): OpenClawProviderIndexProviderAuthChoice["onboardingScopes"] | undefined {

88+

const scopes = normalizeTrimmedStringList(value).filter(

89+

(scope): scope is "text-inference" | "image-generation" =>

90+

scope === "text-inference" || scope === "image-generation",

91+

);

92+

return scopes.length > 0 ? [...new Set(scopes)] : undefined;

93+

}

94+95+

function normalizeAssistantVisibility(

96+

value: unknown,

97+

): OpenClawProviderIndexProviderAuthChoice["assistantVisibility"] | undefined {

98+

return value === "visible" || value === "manual-only" ? value : undefined;

99+

}

100+101+

function normalizeFiniteNumber(value: unknown): number | undefined {

102+

return typeof value === "number" && Number.isFinite(value) ? value : undefined;

103+

}

104+105+

function normalizeAuthChoice(params: {

106+

providerId: string;

107+

providerName: string;

108+

value: unknown;

109+

}): OpenClawProviderIndexProviderAuthChoice | undefined {

110+

if (!isRecord(params.value)) {

111+

return undefined;

112+

}

113+

const method = normalizeSafeKey(params.value.method);

114+

const choiceId = normalizeSafeKey(params.value.choiceId);

115+

const choiceLabel = normalizeOptionalString(params.value.choiceLabel) ?? "";

116+

if (!method || !choiceId || !choiceLabel) {

117+

return undefined;

118+

}

119+

const choiceHint = normalizeOptionalString(params.value.choiceHint);

120+

const groupId = normalizeSafeKey(params.value.groupId) || params.providerId;

121+

const groupLabel = normalizeOptionalString(params.value.groupLabel) ?? params.providerName;

122+

const groupHint = normalizeOptionalString(params.value.groupHint);

123+

const optionKey = normalizeSafeKey(params.value.optionKey);

124+

const cliFlag = normalizeOptionalString(params.value.cliFlag);

125+

const cliOption = normalizeOptionalString(params.value.cliOption);

126+

const cliDescription = normalizeOptionalString(params.value.cliDescription);

127+

const assistantPriority = normalizeFiniteNumber(params.value.assistantPriority);

128+

const assistantVisibility = normalizeAssistantVisibility(params.value.assistantVisibility);

129+

const onboardingScopes = normalizeOnboardingScopes(params.value.onboardingScopes);

130+

return {

131+

method,

132+

choiceId,

133+

choiceLabel,

134+

...(choiceHint ? { choiceHint } : {}),

135+

...(assistantPriority !== undefined ? { assistantPriority } : {}),

136+

...(assistantVisibility ? { assistantVisibility } : {}),

137+

...(groupId ? { groupId } : {}),

138+

...(groupLabel ? { groupLabel } : {}),

139+

...(groupHint ? { groupHint } : {}),

140+

...(optionKey ? { optionKey } : {}),

141+

...(cliFlag ? { cliFlag } : {}),

142+

...(cliOption ? { cliOption } : {}),

143+

...(cliDescription ? { cliDescription } : {}),

144+

...(onboardingScopes ? { onboardingScopes } : {}),

145+

};

146+

}

147+148+

function normalizeAuthChoices(params: {

149+

providerId: string;

150+

providerName: string;

151+

value: unknown;

152+

}): readonly OpenClawProviderIndexProviderAuthChoice[] | undefined {

153+

if (!Array.isArray(params.value)) {

154+

return undefined;

155+

}

156+

const choices = params.value

157+

.map((value) => normalizeAuthChoice({ ...params, value }))

158+

.filter((choice): choice is OpenClawProviderIndexProviderAuthChoice => Boolean(choice));

159+

return choices.length > 0 ? choices : undefined;

160+

}

161+60162

function normalizeProvider(

61163

rawProviderId: string,

62164

value: unknown,

@@ -79,6 +181,11 @@ function normalizeProvider(

79181

}

80182

const docs = normalizeOptionalString(value.docs) ?? "";

81183

const categories = normalizeCategories(value.categories);

184+

const authChoices = normalizeAuthChoices({

185+

providerId,

186+

providerName: name,

187+

value: value.authChoices,

188+

});

82189

const previewCatalog = normalizePreviewCatalog({

83190

providerId,

84191

value: value.previewCatalog,

@@ -89,6 +196,7 @@ function normalizeProvider(

89196

plugin,

90197

...(docs ? { docs } : {}),

91198

...(categories.length > 0 ? { categories } : {}),

199+

...(authChoices ? { authChoices } : {}),

92200

...(previewCatalog ? { previewCatalog } : {}),

93201

};

94202

}