Compare commits
3 Commits
main
...
codex/wind
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f1953c170 | ||
|
|
4f9ab1b438 | ||
|
|
25a1f49c9c |
@ -13,6 +13,7 @@ beforeEach(() => {
|
|||||||
code: 1,
|
code: 1,
|
||||||
signal: null,
|
signal: null,
|
||||||
killed: false,
|
killed: false,
|
||||||
|
termination: "exit",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@ beforeEach(() => {
|
|||||||
warn: warnMock,
|
warn: warnMock,
|
||||||
child: () => logger,
|
child: () => logger,
|
||||||
};
|
};
|
||||||
return logger as ReturnType<typeof subsystemModule.createSubsystemLogger>;
|
return logger as unknown as ReturnType<typeof subsystemModule.createSubsystemLogger>;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -8,9 +8,9 @@ import {
|
|||||||
getChatChannelMeta,
|
getChatChannelMeta,
|
||||||
normalizeAccountId,
|
normalizeAccountId,
|
||||||
TelegramConfigSchema,
|
TelegramConfigSchema,
|
||||||
type ChannelPlugin,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/telegram";
|
} from "openclaw/plugin-sdk/telegram";
|
||||||
|
import type { ChannelPlugin } from "../../../src/channels/plugins/types.js";
|
||||||
import { inspectTelegramAccount } from "./account-inspect.js";
|
import { inspectTelegramAccount } from "./account-inspect.js";
|
||||||
import {
|
import {
|
||||||
listTelegramAccountIds,
|
listTelegramAccountIds,
|
||||||
|
|||||||
@ -28,10 +28,10 @@ import {
|
|||||||
resolveTelegramGroupToolPolicy,
|
resolveTelegramGroupToolPolicy,
|
||||||
TelegramConfigSchema,
|
TelegramConfigSchema,
|
||||||
type ChannelMessageActionAdapter,
|
type ChannelMessageActionAdapter,
|
||||||
type ChannelPlugin,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/telegram";
|
} from "openclaw/plugin-sdk/telegram";
|
||||||
import { parseTelegramTopicConversation } from "../../../src/acp/conversation-id.js";
|
import { parseTelegramTopicConversation } from "../../../src/acp/conversation-id.js";
|
||||||
|
import type { ChannelPlugin } from "../../../src/channels/plugins/types.js";
|
||||||
import { resolveExecApprovalCommandDisplay } from "../../../src/infra/exec-approval-command-display.js";
|
import { resolveExecApprovalCommandDisplay } from "../../../src/infra/exec-approval-command-display.js";
|
||||||
import { buildExecApprovalPendingReplyPayload } from "../../../src/infra/exec-approval-reply.js";
|
import { buildExecApprovalPendingReplyPayload } from "../../../src/infra/exec-approval-reply.js";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import {
|
import {
|
||||||
DEFAULT_ACCOUNT_ID,
|
DEFAULT_ACCOUNT_ID,
|
||||||
type DmPolicy,
|
type ChannelSetupDmPolicy,
|
||||||
formatCliCommand,
|
formatCliCommand,
|
||||||
formatDocsLink,
|
formatDocsLink,
|
||||||
normalizeAccountId,
|
normalizeAccountId,
|
||||||
@ -18,10 +18,14 @@ import { loginWeb } from "./login.js";
|
|||||||
import { whatsappSetupAdapter } from "./setup-core.js";
|
import { whatsappSetupAdapter } from "./setup-core.js";
|
||||||
|
|
||||||
const channel = "whatsapp" as const;
|
const channel = "whatsapp" as const;
|
||||||
|
type WhatsAppConfig = NonNullable<NonNullable<OpenClawConfig["channels"]>["whatsapp"]>;
|
||||||
|
type WhatsAppDmPolicy = ChannelSetupDmPolicy["getCurrent"] extends (...args: never[]) => infer T
|
||||||
|
? T
|
||||||
|
: never;
|
||||||
|
|
||||||
function mergeWhatsAppConfig(
|
function mergeWhatsAppConfig(
|
||||||
cfg: OpenClawConfig,
|
cfg: OpenClawConfig,
|
||||||
patch: Partial<NonNullable<OpenClawConfig["channels"]>["whatsapp"]>,
|
patch: Partial<WhatsAppConfig>,
|
||||||
options?: { unsetOnUndefined?: string[] },
|
options?: { unsetOnUndefined?: string[] },
|
||||||
): OpenClawConfig {
|
): OpenClawConfig {
|
||||||
const base = { ...(cfg.channels?.whatsapp ?? {}) } as Record<string, unknown>;
|
const base = { ...(cfg.channels?.whatsapp ?? {}) } as Record<string, unknown>;
|
||||||
@ -43,7 +47,7 @@ function mergeWhatsAppConfig(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setWhatsAppDmPolicy(cfg: OpenClawConfig, dmPolicy: DmPolicy): OpenClawConfig {
|
function setWhatsAppDmPolicy(cfg: OpenClawConfig, dmPolicy: WhatsAppDmPolicy): OpenClawConfig {
|
||||||
return mergeWhatsAppConfig(cfg, { dmPolicy });
|
return mergeWhatsAppConfig(cfg, { dmPolicy });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +206,7 @@ async function promptWhatsAppDmAccess(params: {
|
|||||||
{ value: "open", label: "Open (public inbound DMs)" },
|
{ value: "open", label: "Open (public inbound DMs)" },
|
||||||
{ value: "disabled", label: "Disabled (ignore WhatsApp DMs)" },
|
{ value: "disabled", label: "Disabled (ignore WhatsApp DMs)" },
|
||||||
],
|
],
|
||||||
})) as DmPolicy;
|
})) as WhatsAppDmPolicy;
|
||||||
|
|
||||||
let next = setWhatsAppSelfChatMode(params.cfg, false);
|
let next = setWhatsAppSelfChatMode(params.cfg, false);
|
||||||
next = setWhatsAppDmPolicy(next, policy);
|
next = setWhatsAppDmPolicy(next, policy);
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { resolveProviderAuths, type ProviderAuth } from "./provider-usage.auth.j
|
|||||||
describe("resolveProviderAuths key normalization", () => {
|
describe("resolveProviderAuths key normalization", () => {
|
||||||
let suiteRoot = "";
|
let suiteRoot = "";
|
||||||
let suiteCase = 0;
|
let suiteCase = 0;
|
||||||
|
const previousFastEnv = process.env.OPENCLAW_TEST_FAST;
|
||||||
const EMPTY_PROVIDER_ENV = {
|
const EMPTY_PROVIDER_ENV = {
|
||||||
ZAI_API_KEY: undefined,
|
ZAI_API_KEY: undefined,
|
||||||
Z_AI_API_KEY: undefined,
|
Z_AI_API_KEY: undefined,
|
||||||
@ -17,11 +18,17 @@ describe("resolveProviderAuths key normalization", () => {
|
|||||||
} satisfies Record<string, string | undefined>;
|
} satisfies Record<string, string | undefined>;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
process.env.OPENCLAW_TEST_FAST = "1";
|
||||||
suiteRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-provider-auth-suite-"));
|
suiteRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-provider-auth-suite-"));
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await fs.rm(suiteRoot, { recursive: true, force: true });
|
await fs.rm(suiteRoot, { recursive: true, force: true });
|
||||||
|
if (previousFastEnv === undefined) {
|
||||||
|
delete process.env.OPENCLAW_TEST_FAST;
|
||||||
|
} else {
|
||||||
|
process.env.OPENCLAW_TEST_FAST = previousFastEnv;
|
||||||
|
}
|
||||||
suiteRoot = "";
|
suiteRoot = "";
|
||||||
suiteCase = 0;
|
suiteCase = 0;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,27 +1,31 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||||
import type { ProviderPlugin } from "../types.js";
|
import {
|
||||||
import { providerContractRegistry } from "./registry.js";
|
|
||||||
|
|
||||||
function uniqueProviders(): ProviderPlugin[] {
|
|
||||||
return [
|
|
||||||
...new Map(
|
|
||||||
providerContractRegistry.map((entry) => [entry.provider.id, entry.provider]),
|
|
||||||
).values(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolvePluginProvidersMock = vi.fn();
|
|
||||||
|
|
||||||
vi.mock("../providers.js", () => ({
|
|
||||||
resolvePluginProviders: (...args: unknown[]) => resolvePluginProvidersMock(...args),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const {
|
|
||||||
buildProviderPluginMethodChoice,
|
buildProviderPluginMethodChoice,
|
||||||
resolveProviderModelPickerEntries,
|
resolveProviderModelPickerEntries,
|
||||||
resolveProviderPluginChoice,
|
resolveProviderPluginChoice,
|
||||||
resolveProviderWizardOptions,
|
resolveProviderWizardOptions,
|
||||||
} = await import("../provider-wizard.js");
|
} from "../provider-wizard.js";
|
||||||
|
import { resolvePluginProviders } from "../providers.js";
|
||||||
|
import type { ProviderPlugin } from "../types.js";
|
||||||
|
import { providerContractRegistry } from "./registry.js";
|
||||||
|
|
||||||
|
const fastModeEnv = vi.hoisted(() => {
|
||||||
|
const previous = process.env.OPENCLAW_TEST_FAST;
|
||||||
|
process.env.OPENCLAW_TEST_FAST = "1";
|
||||||
|
return { previous };
|
||||||
|
});
|
||||||
|
|
||||||
|
function createBundledProviderConfig() {
|
||||||
|
return {
|
||||||
|
plugins: {
|
||||||
|
enabled: true,
|
||||||
|
allow: [...new Set(providerContractRegistry.map((entry) => entry.pluginId))],
|
||||||
|
slots: {
|
||||||
|
memory: "none",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function resolveExpectedWizardChoiceValues(providers: ProviderPlugin[]) {
|
function resolveExpectedWizardChoiceValues(providers: ProviderPlugin[]) {
|
||||||
const values: string[] = [];
|
const values: string[] = [];
|
||||||
@ -80,27 +84,35 @@ function resolveExpectedModelPickerValues(providers: ProviderPlugin[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("provider wizard contract", () => {
|
describe("provider wizard contract", () => {
|
||||||
beforeEach(() => {
|
let providers: ProviderPlugin[] = [];
|
||||||
const providers = uniqueProviders();
|
let options: ReturnType<typeof resolveProviderWizardOptions> = [];
|
||||||
resolvePluginProvidersMock.mockReset();
|
let modelPickerEntries: ReturnType<typeof resolveProviderModelPickerEntries> = [];
|
||||||
resolvePluginProvidersMock.mockReturnValue(providers);
|
|
||||||
|
beforeAll(() => {
|
||||||
|
const config = createBundledProviderConfig();
|
||||||
|
providers = resolvePluginProviders({
|
||||||
|
config,
|
||||||
|
env: process.env,
|
||||||
|
});
|
||||||
|
options = resolveProviderWizardOptions({
|
||||||
|
config,
|
||||||
|
env: process.env,
|
||||||
|
});
|
||||||
|
modelPickerEntries = resolveProviderModelPickerEntries({
|
||||||
|
config,
|
||||||
|
env: process.env,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
if (fastModeEnv.previous === undefined) {
|
||||||
|
delete process.env.OPENCLAW_TEST_FAST;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
process.env.OPENCLAW_TEST_FAST = fastModeEnv.previous;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("exposes every registered provider setup choice through the shared wizard layer", () => {
|
it("exposes every registered provider setup choice through the shared wizard layer", () => {
|
||||||
const providers = uniqueProviders();
|
|
||||||
const options = resolveProviderWizardOptions({
|
|
||||||
config: {
|
|
||||||
plugins: {
|
|
||||||
enabled: true,
|
|
||||||
allow: [...new Set(providerContractRegistry.map((entry) => entry.pluginId))],
|
|
||||||
slots: {
|
|
||||||
memory: "none",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
env: process.env,
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
options.map((option) => option.value).toSorted((left, right) => left.localeCompare(right)),
|
options.map((option) => option.value).toSorted((left, right) => left.localeCompare(right)),
|
||||||
).toEqual(resolveExpectedWizardChoiceValues(providers));
|
).toEqual(resolveExpectedWizardChoiceValues(providers));
|
||||||
@ -110,9 +122,7 @@ describe("provider wizard contract", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("round-trips every shared wizard choice back to its provider and auth method", () => {
|
it("round-trips every shared wizard choice back to its provider and auth method", () => {
|
||||||
const providers = uniqueProviders();
|
for (const option of options) {
|
||||||
|
|
||||||
for (const option of resolveProviderWizardOptions({ config: {}, env: process.env })) {
|
|
||||||
const resolved = resolveProviderPluginChoice({
|
const resolved = resolveProviderPluginChoice({
|
||||||
providers,
|
providers,
|
||||||
choice: option.value,
|
choice: option.value,
|
||||||
@ -124,13 +134,12 @@ describe("provider wizard contract", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("exposes every registered model-picker entry through the shared wizard layer", () => {
|
it("exposes every registered model-picker entry through the shared wizard layer", () => {
|
||||||
const providers = uniqueProviders();
|
|
||||||
const entries = resolveProviderModelPickerEntries({ config: {}, env: process.env });
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
entries.map((entry) => entry.value).toSorted((left, right) => left.localeCompare(right)),
|
modelPickerEntries
|
||||||
|
.map((entry) => entry.value)
|
||||||
|
.toSorted((left, right) => left.localeCompare(right)),
|
||||||
).toEqual(resolveExpectedModelPickerValues(providers));
|
).toEqual(resolveExpectedModelPickerValues(providers));
|
||||||
for (const entry of entries) {
|
for (const entry of modelPickerEntries) {
|
||||||
const resolved = resolveProviderPluginChoice({
|
const resolved = resolveProviderPluginChoice({
|
||||||
providers,
|
providers,
|
||||||
choice: entry.value,
|
choice: entry.value,
|
||||||
|
|||||||
@ -153,9 +153,7 @@ describe("stageBundledPluginRuntime", () => {
|
|||||||
description: string;
|
description: string;
|
||||||
acceptsArgs: boolean;
|
acceptsArgs: boolean;
|
||||||
}>;
|
}>;
|
||||||
matchPluginCommand: (
|
matchPluginCommand: (commandBody: string) => {
|
||||||
commandBody: string,
|
|
||||||
) => {
|
|
||||||
command: { handler: ({ args }: { args?: string }) => Promise<{ text: string }> };
|
command: { handler: ({ args }: { args?: string }) => Promise<{ text: string }> };
|
||||||
args?: string;
|
args?: string;
|
||||||
} | null;
|
} | null;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user