mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-16 09:13:21 +08:00
重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
This commit is contained in:
parent
4a23b715a2
commit
dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions
239
openclaw/test/helpers/plugins/provider-wizard-contract-suites.ts
Normal file
239
openclaw/test/helpers/plugins/provider-wizard-contract-suites.ts
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
buildProviderPluginMethodChoice,
|
||||
resolveProviderModelPickerEntries,
|
||||
resolveProviderPluginChoice,
|
||||
resolveProviderWizardOptions,
|
||||
} from "../../../src/plugins/provider-wizard.js";
|
||||
import type { ProviderAuthMethod, ProviderPlugin } from "../../../src/plugins/types.js";
|
||||
|
||||
const resolvePluginProvidersMock = vi.fn();
|
||||
|
||||
vi.mock("../../../src/plugins/providers.runtime.js", () => ({
|
||||
isPluginProvidersLoadInFlight: () => false,
|
||||
resolvePluginProviders: (...args: unknown[]) => resolvePluginProvidersMock(...args),
|
||||
}));
|
||||
|
||||
function createAuthMethod(
|
||||
params: Pick<ProviderAuthMethod, "id" | "label"> &
|
||||
Partial<Pick<ProviderAuthMethod, "hint" | "wizard">>,
|
||||
): ProviderAuthMethod {
|
||||
return {
|
||||
id: params.id,
|
||||
label: params.label,
|
||||
...(params.hint ? { hint: params.hint } : {}),
|
||||
...(params.wizard ? { wizard: params.wizard } : {}),
|
||||
kind: "api_key",
|
||||
run: async () => ({ profiles: [] }),
|
||||
};
|
||||
}
|
||||
|
||||
const TEST_PROVIDERS: ProviderPlugin[] = [
|
||||
{
|
||||
id: "alpha",
|
||||
label: "Alpha",
|
||||
auth: [
|
||||
createAuthMethod({
|
||||
id: "api-key",
|
||||
label: "API key",
|
||||
wizard: {
|
||||
choiceLabel: "Alpha key",
|
||||
choiceHint: "Use an API key",
|
||||
groupId: "alpha",
|
||||
groupLabel: "Alpha",
|
||||
onboardingScopes: ["text-inference"],
|
||||
},
|
||||
}),
|
||||
createAuthMethod({
|
||||
id: "oauth",
|
||||
label: "OAuth",
|
||||
wizard: {
|
||||
choiceId: "alpha-oauth",
|
||||
choiceLabel: "Alpha OAuth",
|
||||
groupId: "alpha",
|
||||
groupLabel: "Alpha",
|
||||
groupHint: "Recommended",
|
||||
},
|
||||
}),
|
||||
],
|
||||
wizard: {
|
||||
modelPicker: {
|
||||
label: "Alpha custom",
|
||||
hint: "Pick Alpha models",
|
||||
methodId: "oauth",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "beta",
|
||||
label: "Beta",
|
||||
auth: [createAuthMethod({ id: "token", label: "Token" })],
|
||||
wizard: {
|
||||
setup: {
|
||||
choiceLabel: "Beta setup",
|
||||
groupId: "beta",
|
||||
groupLabel: "Beta",
|
||||
},
|
||||
modelPicker: {
|
||||
label: "Beta custom",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "gamma",
|
||||
label: "Gamma",
|
||||
auth: [
|
||||
createAuthMethod({ id: "default", label: "Default auth" }),
|
||||
createAuthMethod({ id: "alt", label: "Alt auth" }),
|
||||
],
|
||||
wizard: {
|
||||
setup: {
|
||||
methodId: "alt",
|
||||
choiceId: "gamma-alt",
|
||||
choiceLabel: "Gamma alt",
|
||||
groupId: "gamma",
|
||||
groupLabel: "Gamma",
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const TEST_PROVIDER_IDS = TEST_PROVIDERS.map((provider) => provider.id).toSorted((left, right) =>
|
||||
left.localeCompare(right),
|
||||
);
|
||||
|
||||
function sortedValues(values: readonly string[]) {
|
||||
return [...values].toSorted((left, right) => left.localeCompare(right));
|
||||
}
|
||||
|
||||
function expectUniqueValues(values: readonly string[]) {
|
||||
expect(values).toEqual([...new Set(values)]);
|
||||
}
|
||||
|
||||
function resolveExpectedWizardChoiceValues(providers: ProviderPlugin[]) {
|
||||
return sortedValues(
|
||||
providers.flatMap((provider) => {
|
||||
const methodSetups = provider.auth.filter((method) => method.wizard);
|
||||
if (methodSetups.length > 0) {
|
||||
return methodSetups.map(
|
||||
(method) =>
|
||||
method.wizard?.choiceId?.trim() ||
|
||||
buildProviderPluginMethodChoice(provider.id, method.id),
|
||||
);
|
||||
}
|
||||
|
||||
const setup = provider.wizard?.setup;
|
||||
if (!setup) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const explicitMethodId = setup.methodId?.trim();
|
||||
if (explicitMethodId && provider.auth.some((method) => method.id === explicitMethodId)) {
|
||||
return [
|
||||
setup.choiceId?.trim() || buildProviderPluginMethodChoice(provider.id, explicitMethodId),
|
||||
];
|
||||
}
|
||||
|
||||
if (provider.auth.length === 1) {
|
||||
return [setup.choiceId?.trim() || provider.id];
|
||||
}
|
||||
|
||||
return provider.auth.map((method) => buildProviderPluginMethodChoice(provider.id, method.id));
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function resolveExpectedModelPickerValues(providers: ProviderPlugin[]) {
|
||||
return sortedValues(
|
||||
providers.flatMap((provider) => {
|
||||
const modelPicker = provider.wizard?.modelPicker;
|
||||
if (!modelPicker) {
|
||||
return [];
|
||||
}
|
||||
const explicitMethodId = modelPicker.methodId?.trim();
|
||||
if (explicitMethodId) {
|
||||
return [buildProviderPluginMethodChoice(provider.id, explicitMethodId)];
|
||||
}
|
||||
if (provider.auth.length === 1) {
|
||||
return [provider.id];
|
||||
}
|
||||
return [buildProviderPluginMethodChoice(provider.id, provider.auth[0]?.id ?? "default")];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function expectAllChoicesResolve(
|
||||
values: readonly string[],
|
||||
resolver: (choice: string) => ReturnType<typeof resolveProviderPluginChoice>,
|
||||
) {
|
||||
expect(
|
||||
values.every((value) => Boolean(resolver(value))),
|
||||
values.join(", "),
|
||||
).toBe(true);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
resolvePluginProvidersMock.mockReset();
|
||||
resolvePluginProvidersMock.mockReturnValue(TEST_PROVIDERS);
|
||||
});
|
||||
|
||||
export function describeProviderWizardSetupOptionsContract() {
|
||||
describe("provider wizard setup options contract", () => {
|
||||
it("exposes every wizard setup choice through the shared wizard layer", () => {
|
||||
const options = resolveProviderWizardOptions({
|
||||
config: {
|
||||
plugins: {
|
||||
enabled: true,
|
||||
allow: TEST_PROVIDER_IDS,
|
||||
slots: {
|
||||
memory: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
env: process.env,
|
||||
});
|
||||
|
||||
expect(sortedValues(options.map((option) => option.value))).toEqual(
|
||||
resolveExpectedWizardChoiceValues(TEST_PROVIDERS),
|
||||
);
|
||||
expectUniqueValues(options.map((option) => option.value));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function describeProviderWizardChoiceResolutionContract() {
|
||||
describe("provider wizard choice resolution contract", () => {
|
||||
it("round-trips every shared wizard choice back to its provider and auth method", () => {
|
||||
const options = resolveProviderWizardOptions({ config: {}, env: process.env });
|
||||
|
||||
expectAllChoicesResolve(
|
||||
options.map((option) => option.value),
|
||||
(choice) =>
|
||||
resolveProviderPluginChoice({
|
||||
providers: TEST_PROVIDERS,
|
||||
choice,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function describeProviderWizardModelPickerContract() {
|
||||
describe("provider wizard model picker contract", () => {
|
||||
it("exposes every model-picker entry through the shared wizard layer", () => {
|
||||
const entries = resolveProviderModelPickerEntries({ config: {}, env: process.env });
|
||||
|
||||
expect(sortedValues(entries.map((entry) => entry.value))).toEqual(
|
||||
resolveExpectedModelPickerValues(TEST_PROVIDERS),
|
||||
);
|
||||
expectAllChoicesResolve(
|
||||
entries.map((entry) => entry.value),
|
||||
(choice) =>
|
||||
resolveProviderPluginChoice({
|
||||
providers: TEST_PROVIDERS,
|
||||
choice,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue