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

推荐订阅源

MyScale Blog
MyScale Blog
Jina AI
Jina AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
P
Proofpoint News Feed
Last Week in AI
Last Week in AI
博客园 - 司徒正美
Martin Fowler
Martin Fowler
T
Tailwind CSS Blog
B
Blog RSS Feed
Vercel News
Vercel News
博客园 - 聂微东
I
InfoQ
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
M
MIT News - Artificial intelligence
Recent Announcements
Recent Announcements
GbyAI
GbyAI
L
LangChain Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Security Blog
Microsoft Security Blog
C
Check Point Blog
MongoDB | Blog
MongoDB | Blog
B
Blog

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(plugins): surface manifest provider setup choices (#...
vincentkoc · 2026-04-25 · via Recent Commits to openclaw:main

@@ -2,6 +2,8 @@ import { beforeEach, describe, expect, it, vi } from "vitest";

2233

type ResolveProviderInstallCatalogEntries =

44

typeof import("../plugins/provider-install-catalog.js").resolveProviderInstallCatalogEntries;

5+

type ResolveManifestProviderAuthChoices =

6+

typeof import("../plugins/provider-auth-choices.js").resolveManifestProviderAuthChoices;

57

type ResolveProviderWizardOptions =

68

typeof import("../plugins/provider-wizard.js").resolveProviderWizardOptions;

79

type ResolveProviderModelPickerEntries =

@@ -16,6 +18,13 @@ vi.mock("../plugins/provider-install-catalog.js", () => ({

1618

resolveProviderInstallCatalogEntries,

1719

}));

182021+

const resolveManifestProviderAuthChoices = vi.hoisted(() =>

22+

vi.fn<ResolveManifestProviderAuthChoices>(() => []),

23+

);

24+

vi.mock("../plugins/provider-auth-choices.js", () => ({

25+

resolveManifestProviderAuthChoices,

26+

}));

27+1928

const resolveProviderWizardOptions = vi.hoisted(() =>

2029

vi.fn<ResolveProviderWizardOptions>(() => []),

2130

);

@@ -39,7 +48,117 @@ import {

39484049

describe("provider flow install catalog contributions", () => {

4150

beforeEach(() => {

42-

vi.clearAllMocks();

51+

resolveManifestProviderAuthChoices.mockReset();

52+

resolveManifestProviderAuthChoices.mockReturnValue([]);

53+

resolveProviderInstallCatalogEntries.mockReset();

54+

resolveProviderInstallCatalogEntries.mockReturnValue([]);

55+

resolveProviderWizardOptions.mockReset();

56+

resolveProviderWizardOptions.mockReturnValue([]);

57+

resolveProviderModelPickerEntries.mockReset();

58+

resolveProviderModelPickerEntries.mockReturnValue([]);

59+

resolvePluginProviders.mockReset();

60+

resolvePluginProviders.mockReturnValue([]);

61+

});

62+63+

it("surfaces manifest provider auth choices before setup runtime loads", () => {

64+

resolveManifestProviderAuthChoices.mockReturnValue([

65+

{

66+

pluginId: "openai-compatible",

67+

providerId: "openai-compatible",

68+

methodId: "api-key",

69+

choiceId: "openai-compatible-api-key",

70+

choiceLabel: "OpenAI-compatible API key",

71+

choiceHint: "Use a compatible endpoint",

72+

assistantPriority: -5,

73+

assistantVisibility: "visible",

74+

groupId: "openai-compatible",

75+

groupLabel: "OpenAI-compatible",

76+

groupHint: "Self-hosted and compatible providers",

77+

onboardingScopes: ["text-inference"],

78+

},

79+

]);

80+81+

expect(resolveProviderSetupFlowContributions()).toEqual([

82+

{

83+

id: "provider:setup:openai-compatible-api-key",

84+

kind: "provider",

85+

surface: "setup",

86+

providerId: "openai-compatible",

87+

pluginId: "openai-compatible",

88+

option: {

89+

value: "openai-compatible-api-key",

90+

label: "OpenAI-compatible API key",

91+

hint: "Use a compatible endpoint",

92+

assistantPriority: -5,

93+

assistantVisibility: "visible",

94+

group: {

95+

id: "openai-compatible",

96+

label: "OpenAI-compatible",

97+

hint: "Self-hosted and compatible providers",

98+

},

99+

},

100+

onboardingScopes: ["text-inference"],

101+

source: "manifest",

102+

},

103+

]);

104+

expect(resolveManifestProviderAuthChoices).toHaveBeenCalledWith(

105+

expect.objectContaining({

106+

includeUntrustedWorkspacePlugins: false,

107+

}),

108+

);

109+

});

110+111+

it("prefers manifest setup contributions over duplicate runtime and install-catalog entries", () => {

112+

resolveManifestProviderAuthChoices.mockReturnValue([

113+

{

114+

pluginId: "openai",

115+

providerId: "openai",

116+

methodId: "api-key",

117+

choiceId: "openai-api-key",

118+

choiceLabel: "OpenAI API key",

119+

},

120+

]);

121+

resolveProviderWizardOptions.mockReturnValue([

122+

{

123+

value: "openai-api-key",

124+

label: "Runtime OpenAI API key",

125+

groupId: "openai",

126+

groupLabel: "OpenAI",

127+

},

128+

]);

129+

resolveProviderInstallCatalogEntries.mockReturnValue([

130+

{

131+

pluginId: "openai",

132+

providerId: "openai",

133+

methodId: "api-key",

134+

choiceId: "openai-api-key",

135+

choiceLabel: "Catalog OpenAI API key",

136+

label: "OpenAI",

137+

origin: "bundled",

138+

install: {

139+

npmSpec: "@openclaw/openai",

140+

},

141+

},

142+

]);

143+144+

expect(resolveProviderSetupFlowContributions()).toEqual([

145+

{

146+

id: "provider:setup:openai-api-key",

147+

kind: "provider",

148+

surface: "setup",

149+

providerId: "openai",

150+

pluginId: "openai",

151+

option: {

152+

value: "openai-api-key",

153+

label: "OpenAI API key",

154+

group: {

155+

id: "openai",

156+

label: "OpenAI API key",

157+

},

158+

},

159+

source: "manifest",

160+

},

161+

]);

43162

});

4416345164

it("surfaces install-catalog provider choices when runtime setup options are absent", () => {