



























@@ -194,6 +194,33 @@ function createTestContext(label: string): GatewayRequestContext {
194194return { label } as unknown as GatewayRequestContext;
195195}
196196197+function isRecord(value: unknown): value is Record<string, unknown> {
198+return typeof value === "object" && value !== null && !Array.isArray(value);
199+}
200+201+function requireRecord(value: unknown, label: string): Record<string, unknown> {
202+if (!isRecord(value)) {
203+throw new Error(`Expected ${label} to be an object`);
204+}
205+return value;
206+}
207+208+function readRecordField(record: Record<string, unknown>, key: string, label: string) {
209+const value = record[key];
210+if (!isRecord(value)) {
211+throw new Error(`Expected ${label} to be an object`);
212+}
213+return value;
214+}
215+216+function getLastPluginLoadOptions(): Record<string, unknown> {
217+return requireRecord(loadOpenClawPlugins.mock.calls.at(-1)?.[0], "plugin load options");
218+}
219+220+function getLastPluginLoadOption(key: string) {
221+return getLastPluginLoadOptions()[key];
222+}
223+197224function getLastDispatchedContext(): GatewayRequestContext | undefined {
198225const call = handleGatewayRequest.mock.calls.at(-1)?.[0];
199226return call?.context;
@@ -204,6 +231,10 @@ function getLastDispatchedParams(): Record<string, unknown> | undefined {
204231return call?.req?.params as Record<string, unknown> | undefined;
205232}
206233234+function getRequiredLastDispatchedParams(): Record<string, unknown> {
235+return requireRecord(getLastDispatchedParams(), "dispatched params");
236+}
237+207238function getLastDispatchedClientScopes(): string[] {
208239const call = handleGatewayRequest.mock.calls.at(-1)?.[0];
209240const scopes = call?.client?.connect?.scopes;
@@ -386,12 +417,8 @@ describe("loadGatewayPlugins", () => {
386417workspaceDir: "/tmp",
387418env: process.env,
388419});
389-expect(loadOpenClawPlugins).toHaveBeenCalledWith(
390-expect.objectContaining({
391-onlyPluginIds: ["discord", "telegram"],
392-preferBuiltPluginArtifacts: true,
393-}),
394-);
420+expect(getLastPluginLoadOption("onlyPluginIds")).toEqual(["discord", "telegram"]);
421+expect(getLastPluginLoadOption("preferBuiltPluginArtifacts")).toBe(true);
395422});
396423397424test("routes plugin registration logs through the plugin logger", () => {
@@ -430,11 +457,7 @@ describe("loadGatewayPlugins", () => {
430457});
431458432459expect(loadPluginLookUpTable).not.toHaveBeenCalled();
433-expect(loadOpenClawPlugins).toHaveBeenCalledWith(
434-expect.objectContaining({
435-onlyPluginIds: ["browser"],
436-}),
437-);
460+expect(getLastPluginLoadOption("onlyPluginIds")).toEqual(["browser"]);
438461});
439462440463test("reuses a provided lookup table for startup scope and auto-enable manifests", () => {
@@ -454,12 +477,8 @@ describe("loadGatewayPlugins", () => {
454477env: process.env,
455478 manifestRegistry,
456479});
457-expect(loadOpenClawPlugins).toHaveBeenCalledWith(
458-expect.objectContaining({
459- manifestRegistry,
460-onlyPluginIds: ["telegram"],
461-}),
462-);
480+expect(getLastPluginLoadOption("manifestRegistry")).toBe(manifestRegistry);
481+expect(getLastPluginLoadOption("onlyPluginIds")).toEqual(["telegram"]);
463482});
464483465484test("pins the initial startup channel registry against later active-registry churn", () => {
@@ -502,16 +521,12 @@ describe("loadGatewayPlugins", () => {
502521config: rawConfig,
503522env: process.env,
504523});
505-expect(loadOpenClawPlugins).toHaveBeenCalledWith(
506-expect.objectContaining({
507-config: resolvedConfig,
508-activationSourceConfig: rawConfig,
509-onlyPluginIds: ["slack"],
510-autoEnabledReasons: {
511-slack: ["slack configured"],
512-},
513-}),
514-);
524+expect(getLastPluginLoadOption("config")).toStrictEqual(resolvedConfig);
525+expect(getLastPluginLoadOption("activationSourceConfig")).toStrictEqual(rawConfig);
526+expect(getLastPluginLoadOption("onlyPluginIds")).toEqual(["slack"]);
527+expect(getLastPluginLoadOption("autoEnabledReasons")).toEqual({
528+slack: ["slack configured"],
529+});
515530});
516531517532test("preserves runtime defaults while applying source activation to startup loads", () => {
@@ -582,41 +597,31 @@ describe("loadGatewayPlugins", () => {
582597pluginIds: ["telegram"],
583598});
584599585-expect(loadOpenClawPlugins).toHaveBeenCalledWith(
586-expect.objectContaining({
587-config: expect.objectContaining({
588-channels: expect.objectContaining({
589-telegram: expect.objectContaining({
590-enabled: true,
591-dmPolicy: "pairing",
592-groupPolicy: "allowlist",
593-}),
594-}),
595-plugins: expect.objectContaining({
596-allow: ["bench-plugin"],
597-entries: expect.objectContaining({
598-"bench-plugin": expect.objectContaining({
599-enabled: true,
600-config: {
601-runtimeDefault: true,
602-},
603-}),
604-"memory-core": {
605-config: {
606-dreaming: {
607-enabled: false,
608-},
609-},
610-},
611-}),
612-}),
613-}),
614-activationSourceConfig: rawConfig,
615-autoEnabledReasons: {
616-telegram: ["telegram configured"],
600+const config = requireRecord(getLastPluginLoadOption("config"), "plugin load config");
601+const channels = readRecordField(config, "channels", "plugin load channels");
602+const telegram = readRecordField(channels, "telegram", "telegram channel config");
603+expect(telegram.enabled).toBe(true);
604+expect(telegram.dmPolicy).toBe("pairing");
605+expect(telegram.groupPolicy).toBe("allowlist");
606+const plugins = readRecordField(config, "plugins", "plugin load plugins config");
607+expect(plugins.allow).toEqual(["bench-plugin"]);
608+const entries = readRecordField(plugins, "entries", "plugin load entries");
609+const benchPlugin = readRecordField(entries, "bench-plugin", "bench plugin entry");
610+expect(benchPlugin.enabled).toBe(true);
611+expect(benchPlugin.config).toEqual({
612+runtimeDefault: true,
613+});
614+expect(entries["memory-core"]).toEqual({
615+config: {
616+dreaming: {
617+enabled: false,
617618},
618-}),
619-);
619+},
620+});
621+expect(getLastPluginLoadOption("activationSourceConfig")).toStrictEqual(rawConfig);
622+expect(getLastPluginLoadOption("autoEnabledReasons")).toEqual({
623+telegram: ["telegram configured"],
624+});
620625});
621626622627test("treats an empty startup scope as no plugin load instead of an unscoped load", () => {
@@ -677,15 +682,11 @@ describe("loadGatewayPlugins", () => {
677682workspaceDir: "/tmp",
678683env: process.env,
679684});
680-expect(loadOpenClawPlugins).toHaveBeenCalledWith(
681-expect.objectContaining({
682-config: autoEnabledConfig,
683-activationSourceConfig: {},
684-autoEnabledReasons: {
685-slack: ["slack configured"],
686-},
687-}),
688-);
685+expect(getLastPluginLoadOption("config")).toStrictEqual(autoEnabledConfig);
686+expect(getLastPluginLoadOption("activationSourceConfig")).toEqual({});
687+expect(getLastPluginLoadOption("autoEnabledReasons")).toEqual({
688+slack: ["slack configured"],
689+});
689690});
690691691692test("re-derives auto-enable reasons when only activationSourceConfig is provided", () => {
@@ -715,27 +716,25 @@ describe("loadGatewayPlugins", () => {
715716workspaceDir: "/tmp",
716717env: process.env,
717718});
718-expect(loadOpenClawPlugins).toHaveBeenCalledWith(
719-expect.objectContaining({
720-config: resolvedConfig,
721-activationSourceConfig: rawConfig,
722-autoEnabledReasons: {
723-slack: ["slack configured"],
724-},
725-}),
726-);
719+expect(getLastPluginLoadOption("config")).toStrictEqual(resolvedConfig);
720+expect(getLastPluginLoadOption("activationSourceConfig")).toStrictEqual(rawConfig);
721+expect(getLastPluginLoadOption("autoEnabledReasons")).toEqual({
722+slack: ["slack configured"],
723+});
727724});
728725729726test("provides subagent runtime with sessions.get method aliases", async () => {
730727const runtime = await createSubagentRuntime(serverPluginsModule);
731728serverPluginsModule.setFallbackGatewayContext(createTestContext("sessions-get-aliases"));
732729handleGatewayRequest
733730.mockImplementationOnce(async (opts: HandleGatewayRequestOptions) => {
734-expect(opts.req).toMatchObject({ method: "sessions.get", params: { key: "s-read" } });
731+expect(opts.req.method).toBe("sessions.get");
732+expect(opts.req.params).toEqual({ key: "s-read" });
735733opts.respond(true, { messages: [{ id: "m-1" }] });
736734})
737735.mockImplementationOnce(async (opts: HandleGatewayRequestOptions) => {
738-expect(opts.req).toMatchObject({ method: "sessions.get", params: { key: "s-legacy" } });
736+expect(opts.req.method).toBe("sessions.get");
737+expect(opts.req.params).toEqual({ key: "s-legacy" });
739738opts.respond(true, { messages: [{ id: "m-2" }] });
740739});
741740@@ -793,13 +792,12 @@ describe("loadGatewayPlugins", () => {
793792}),
794793);
795794796-expect(getLastDispatchedParams()).toMatchObject({
797-sessionKey: "s-override",
798-message: "use the override",
799-provider: "anthropic",
800-model: "claude-haiku-4-5",
801-deliver: false,
802-});
795+const params = getRequiredLastDispatchedParams();
796+expect(params.sessionKey).toBe("s-override");
797+expect(params.message).toBe("use the override");
798+expect(params.provider).toBe("anthropic");
799+expect(params.model).toBe("claude-haiku-4-5");
800+expect(params.deliver).toBe(false);
803801});
804802805803test("forwards caller-supplied idempotencyKey on subagent run", async () => {
@@ -814,11 +812,10 @@ describe("loadGatewayPlugins", () => {
814812idempotencyKey: "caller-provided-key",
815813});
816814817-expect(getLastDispatchedParams()).toMatchObject({
818-sessionKey: "s-idem-forward",
819-message: "hello",
820-idempotencyKey: "caller-provided-key",
821-});
815+const params = getRequiredLastDispatchedParams();
816+expect(params.sessionKey).toBe("s-idem-forward");
817+expect(params.message).toBe("hello");
818+expect(params.idempotencyKey).toBe("caller-provided-key");
822819});
823820824821test("forwards lightContext as lightweight bootstrap context on subagent run", async () => {
@@ -834,13 +831,12 @@ describe("loadGatewayPlugins", () => {
834831deliver: false,
835832});
836833837-expect(getLastDispatchedParams()).toMatchObject({
838-sessionKey: "s-light-context",
839-message: "hello",
840-lane: "dreaming-narrative:s-light-context",
841-bootstrapContextMode: "lightweight",
842-deliver: false,
843-});
834+const params = getRequiredLastDispatchedParams();
835+expect(params.sessionKey).toBe("s-light-context");
836+expect(params.message).toBe("hello");
837+expect(params.lane).toBe("dreaming-narrative:s-light-context");
838+expect(params.bootstrapContextMode).toBe("lightweight");
839+expect(params.deliver).toBe(false);
844840});
845841846842test("generates a non-empty idempotencyKey when the caller omits it", async () => {
@@ -909,11 +905,10 @@ describe("loadGatewayPlugins", () => {
909905}),
910906);
911907912-expect(getLastDispatchedParams()).toMatchObject({
913-sessionKey: "s-trusted-override",
914-provider: "anthropic",
915-model: "claude-haiku-4-5",
916-});
908+const params = getRequiredLastDispatchedParams();
909+expect(params.sessionKey).toBe("s-trusted-override");
910+expect(params.provider).toBe("anthropic");
911+expect(params.model).toBe("claude-haiku-4-5");
917912});
918913919914test("tags plugin fallback subagent runs with the creating plugin id", async () => {
@@ -929,9 +924,7 @@ describe("loadGatewayPlugins", () => {
929924}),
930925);
931926932-expect(getLastDispatchedClientInternal()).toMatchObject({
933-pluginRuntimeOwnerId: "memory-core",
934-});
927+expect(getLastDispatchedClientInternal().pluginRuntimeOwnerId).toBe("memory-core");
935928});
936929937930test("includes docs guidance when a plugin fallback override is not trusted", async () => {
@@ -978,10 +971,9 @@ describe("loadGatewayPlugins", () => {
978971}),
979972);
980973981-expect(getLastDispatchedParams()).toMatchObject({
982-sessionKey: "s-model-only-override",
983-model: "anthropic/claude-haiku-4-5",
984-});
974+const params = getRequiredLastDispatchedParams();
975+expect(params.sessionKey).toBe("s-model-only-override");
976+expect(params.model).toBe("anthropic/claude-haiku-4-5");
985977expect(getLastDispatchedParams()).not.toHaveProperty("provider");
986978});
987979@@ -1119,9 +1111,7 @@ describe("loadGatewayPlugins", () => {
11191111).resolves.toBeUndefined();
1120111211211113expect(getLastDispatchedClientScopes()).toEqual(["operator.admin"]);
1122-expect(getLastDispatchedClientInternal()).toMatchObject({
1123-pluginRuntimeOwnerId: "memory-core",
1124-});
1114+expect(getLastDispatchedClientInternal().pluginRuntimeOwnerId).toBe("memory-core");
11251115});
1126111611271117test("allows session deletion when the request scope already has admin", async () => {
@@ -1174,9 +1164,7 @@ describe("loadGatewayPlugins", () => {
11741164).resolves.toBeUndefined();
1175116511761166expect(getLastDispatchedClientScopes()).toEqual(["operator.admin"]);
1177-expect(getLastDispatchedClientInternal()).toMatchObject({
1178-pluginRuntimeOwnerId: "memory-core",
1179-});
1167+expect(getLastDispatchedClientInternal().pluginRuntimeOwnerId).toBe("memory-core");
11801168});
1181116911821170test("can prefer setup-runtime channel plugins during startup loads", () => {
@@ -1185,11 +1173,7 @@ describe("loadGatewayPlugins", () => {
11851173preferSetupRuntimeForChannelPlugins: true,
11861174});
118711751188-expect(loadOpenClawPlugins).toHaveBeenCalledWith(
1189-expect.objectContaining({
1190-preferSetupRuntimeForChannelPlugins: true,
1191-}),
1192-);
1176+expect(getLastPluginLoadOption("preferSetupRuntimeForChannelPlugins")).toBe(true);
11931177});
1194117811951179test("primes configured bindings during gateway startup", () => {
@@ -1236,10 +1220,9 @@ describe("loadGatewayPlugins", () => {
12361220}),
12371221);
123812221239-expect(getLastDispatchedParams()).toMatchObject({
1240-sessionKey: "s-auto-enabled-bootstrap-policy",
1241-model: "openai/gpt-5.4",
1242-});
1223+const params = getRequiredLastDispatchedParams();
1224+expect(params.sessionKey).toBe("s-auto-enabled-bootstrap-policy");
1225+expect(params.model).toBe("openai/gpt-5.4");
12431226});
1244122712451228test("can suppress duplicate diagnostics when reloading full runtime plugins", () => {
@@ -1293,12 +1276,8 @@ describe("loadGatewayPlugins", () => {
12931276env: process.env,
12941277 manifestRegistry,
12951278});
1296-expect(loadOpenClawPlugins).toHaveBeenCalledWith(
1297-expect.objectContaining({
1298- manifestRegistry,
1299-onlyPluginIds: ["discord"],
1300-}),
1301-);
1279+expect(getLastPluginLoadOption("manifestRegistry")).toBe(manifestRegistry);
1280+expect(getLastPluginLoadOption("onlyPluginIds")).toEqual(["discord"]);
13021281});
1303128213041283test("runs registry hook before priming configured bindings", () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。