mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-11 09:11:13 +00:00
fix(ci): repair main type and boundary regressions
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import * as acpSessionManager from "../acp/control-plane/manager.js";
|
||||
import type {
|
||||
AcpCloseSessionInput,
|
||||
AcpInitializeSessionInput,
|
||||
} from "../acp/control-plane/manager.types.js";
|
||||
import {
|
||||
clearRuntimeConfigSnapshot,
|
||||
setRuntimeConfigSnapshot,
|
||||
@@ -180,16 +184,12 @@ describe("spawnAcpDirect", () => {
|
||||
metaCleared: false,
|
||||
});
|
||||
getAcpSessionManagerSpy.mockReset().mockReturnValue({
|
||||
initializeSession: async (params: unknown) => await hoisted.initializeSessionMock(params),
|
||||
closeSession: async (params: unknown) => await hoisted.closeSessionMock(params),
|
||||
initializeSession: async (params: AcpInitializeSessionInput) =>
|
||||
await hoisted.initializeSessionMock(params),
|
||||
closeSession: async (params: AcpCloseSessionInput) => await hoisted.closeSessionMock(params),
|
||||
} as unknown as ReturnType<typeof acpSessionManager.getAcpSessionManager>);
|
||||
hoisted.initializeSessionMock.mockReset().mockImplementation(async (argsUnknown: unknown) => {
|
||||
const args = argsUnknown as {
|
||||
sessionKey: string;
|
||||
agent: string;
|
||||
mode: "persistent" | "oneshot";
|
||||
cwd?: string;
|
||||
};
|
||||
const args = argsUnknown as AcpInitializeSessionInput;
|
||||
const runtimeSessionName = `${args.sessionKey}:runtime`;
|
||||
const cwd = typeof args.cwd === "string" ? args.cwd : undefined;
|
||||
return {
|
||||
@@ -386,7 +386,6 @@ describe("spawnAcpDirect", () => {
|
||||
matrix: {
|
||||
threadBindings: {
|
||||
enabled: true,
|
||||
spawnAcpSessions: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -6,12 +6,14 @@ import {
|
||||
type OpenClawConfig,
|
||||
} from "../config/config.js";
|
||||
import * as configSessions from "../config/sessions.js";
|
||||
import type { SessionEntry } from "../config/sessions/types.js";
|
||||
import * as gatewayCall from "../gateway/call.js";
|
||||
import {
|
||||
__testing as sessionBindingServiceTesting,
|
||||
registerSessionBindingAdapter,
|
||||
} from "../infra/outbound/session-binding-service.js";
|
||||
import * as hookRunnerGlobal from "../plugins/hook-runner-global.js";
|
||||
import type { HookRunner } from "../plugins/hooks.js";
|
||||
import { setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
import { createTestRegistry } from "../test-utils/channel-plugins.js";
|
||||
import * as piEmbedded from "./pi-embedded.js";
|
||||
@@ -65,11 +67,23 @@ const waitForEmbeddedPiRunEndSpy = vi.spyOn(piEmbedded, "waitForEmbeddedPiRunEnd
|
||||
const readLatestAssistantReplyMock = vi.fn(
|
||||
async (_sessionKey?: string): Promise<string | undefined> => "raw subagent reply",
|
||||
);
|
||||
const embeddedPiRunActiveMock = vi.fn<typeof piEmbedded.isEmbeddedPiRunActive>(
|
||||
(_sessionId: string) => false,
|
||||
);
|
||||
const embeddedPiRunStreamingMock = vi.fn<typeof piEmbedded.isEmbeddedPiRunStreaming>(
|
||||
(_sessionId: string) => false,
|
||||
);
|
||||
const queueEmbeddedPiMessageMock = vi.fn<typeof piEmbedded.queueEmbeddedPiMessage>(
|
||||
(_sessionId: string, _text: string) => false,
|
||||
);
|
||||
const waitForEmbeddedPiRunEndMock = vi.fn<typeof piEmbedded.waitForEmbeddedPiRunEnd>(
|
||||
async (_sessionId: string, _timeoutMs?: number) => true,
|
||||
);
|
||||
const embeddedRunMock = {
|
||||
isEmbeddedPiRunActive: vi.fn(() => false),
|
||||
isEmbeddedPiRunStreaming: vi.fn(() => false),
|
||||
queueEmbeddedPiMessage: vi.fn((_: string, __: string) => false),
|
||||
waitForEmbeddedPiRunEnd: vi.fn(async (_: string, __?: number) => true),
|
||||
isEmbeddedPiRunActive: embeddedPiRunActiveMock,
|
||||
isEmbeddedPiRunStreaming: embeddedPiRunStreamingMock,
|
||||
queueEmbeddedPiMessage: queueEmbeddedPiMessageMock,
|
||||
waitForEmbeddedPiRunEnd: waitForEmbeddedPiRunEndMock,
|
||||
};
|
||||
const { subagentRegistryMock } = vi.hoisted(() => ({
|
||||
subagentRegistryMock: {
|
||||
@@ -92,18 +106,21 @@ const subagentDeliveryTargetHookMock = vi.fn(
|
||||
undefined,
|
||||
);
|
||||
let hasSubagentDeliveryTargetHook = false;
|
||||
const hookHasHooksMock = vi.fn<HookRunner["hasHooks"]>(
|
||||
(hookName) => hookName === "subagent_delivery_target" && hasSubagentDeliveryTargetHook,
|
||||
);
|
||||
const hookRunSubagentDeliveryTargetMock = vi.fn<HookRunner["runSubagentDeliveryTarget"]>(
|
||||
async (event, ctx) => await subagentDeliveryTargetHookMock(event, ctx),
|
||||
);
|
||||
const hookRunnerMock = {
|
||||
hasHooks: vi.fn(
|
||||
(hookName: string) => hookName === "subagent_delivery_target" && hasSubagentDeliveryTargetHook,
|
||||
),
|
||||
runSubagentDeliveryTarget: vi.fn((event: unknown, ctx: unknown) =>
|
||||
subagentDeliveryTargetHookMock(event, ctx),
|
||||
),
|
||||
};
|
||||
hasHooks: hookHasHooksMock,
|
||||
runSubagentDeliveryTarget: hookRunSubagentDeliveryTargetMock,
|
||||
} as unknown as HookRunner;
|
||||
const chatHistoryMock = vi.fn(async (_sessionKey?: string) => ({
|
||||
messages: [] as Array<unknown>,
|
||||
}));
|
||||
let sessionStore: Record<string, Record<string, unknown>> = {};
|
||||
type TestSessionStore = Record<string, Partial<SessionEntry>>;
|
||||
let sessionStore: TestSessionStore = {};
|
||||
let configOverride: OpenClawConfig = {
|
||||
session: {
|
||||
mainKey: "main",
|
||||
@@ -131,19 +148,34 @@ function setConfigOverride(next: OpenClawConfig): void {
|
||||
setRuntimeConfigSnapshot(configOverride);
|
||||
}
|
||||
|
||||
function loadSessionStoreFixture(): ReturnType<typeof configSessions.loadSessionStore> {
|
||||
return new Proxy(sessionStore as ReturnType<typeof configSessions.loadSessionStore>, {
|
||||
get(target, key: string | symbol) {
|
||||
if (typeof key === "string" && !(key in target) && key.includes(":subagent:")) {
|
||||
return {
|
||||
sessionId: key,
|
||||
updatedAt: Date.now(),
|
||||
function toSessionEntry(
|
||||
sessionKey: string,
|
||||
entry?: Partial<SessionEntry>,
|
||||
): SessionEntry | undefined {
|
||||
if (!entry) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
sessionId: entry.sessionId ?? sessionKey,
|
||||
updatedAt: entry.updatedAt ?? Date.now(),
|
||||
...entry,
|
||||
};
|
||||
}
|
||||
|
||||
function loadSessionStoreFixture(): Record<string, SessionEntry> {
|
||||
return new Proxy({} as Record<string, SessionEntry>, {
|
||||
get(_target, key: string | symbol) {
|
||||
if (typeof key !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
if (!(key in sessionStore) && key.includes(":subagent:")) {
|
||||
return toSessionEntry(key, {
|
||||
inputTokens: 1,
|
||||
outputTokens: 1,
|
||||
totalTokens: 2,
|
||||
};
|
||||
});
|
||||
}
|
||||
return target[key as keyof typeof target];
|
||||
return toSessionEntry(key, sessionStore[key]);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -223,17 +255,20 @@ describe("subagent announce formatting", () => {
|
||||
.mockImplementation(async (params) => await readLatestAssistantReplyMock(params?.sessionKey));
|
||||
isEmbeddedPiRunActiveSpy
|
||||
.mockReset()
|
||||
.mockImplementation(() => embeddedRunMock.isEmbeddedPiRunActive());
|
||||
.mockImplementation((sessionId) => embeddedRunMock.isEmbeddedPiRunActive(sessionId));
|
||||
isEmbeddedPiRunStreamingSpy
|
||||
.mockReset()
|
||||
.mockImplementation(() => embeddedRunMock.isEmbeddedPiRunStreaming());
|
||||
.mockImplementation((sessionId) => embeddedRunMock.isEmbeddedPiRunStreaming(sessionId));
|
||||
queueEmbeddedPiMessageSpy
|
||||
.mockReset()
|
||||
.mockImplementation((...args) => embeddedRunMock.queueEmbeddedPiMessage(...args));
|
||||
.mockImplementation((sessionId, text) =>
|
||||
embeddedRunMock.queueEmbeddedPiMessage(sessionId, text),
|
||||
);
|
||||
waitForEmbeddedPiRunEndSpy
|
||||
.mockReset()
|
||||
.mockImplementation(
|
||||
async (...args) => await embeddedRunMock.waitForEmbeddedPiRunEnd(...args),
|
||||
async (sessionId, timeoutMs) =>
|
||||
await embeddedRunMock.waitForEmbeddedPiRunEnd(sessionId, timeoutMs),
|
||||
);
|
||||
embeddedRunMock.isEmbeddedPiRunActive.mockClear().mockReturnValue(false);
|
||||
embeddedRunMock.isEmbeddedPiRunStreaming.mockClear().mockReturnValue(false);
|
||||
@@ -258,8 +293,8 @@ describe("subagent announce formatting", () => {
|
||||
subagentRegistryMock.replaceSubagentRunAfterSteer.mockClear().mockReturnValue(true);
|
||||
subagentRegistryMock.resolveRequesterForChildSession.mockClear().mockReturnValue(null);
|
||||
hasSubagentDeliveryTargetHook = false;
|
||||
hookRunnerMock.hasHooks.mockClear();
|
||||
hookRunnerMock.runSubagentDeliveryTarget.mockClear();
|
||||
hookHasHooksMock.mockClear();
|
||||
hookRunSubagentDeliveryTargetMock.mockClear();
|
||||
subagentDeliveryTargetHookMock.mockReset().mockResolvedValue(undefined);
|
||||
readLatestAssistantReplyMock.mockClear().mockResolvedValue("raw subagent reply");
|
||||
chatHistoryMock.mockReset().mockResolvedValue({ messages: [] });
|
||||
|
||||
@@ -53,6 +53,7 @@ export const CHANNEL_MESSAGE_ACTION_NAMES = [
|
||||
"ban",
|
||||
"set-profile",
|
||||
"set-presence",
|
||||
"set-profile",
|
||||
"download-file",
|
||||
] as const;
|
||||
|
||||
|
||||
@@ -350,15 +350,15 @@ export async function channelsAddCommand(
|
||||
|
||||
await writeConfigFile(nextConfig);
|
||||
runtime.log(`Added ${channelLabel(channel)} account "${accountId}".`);
|
||||
const setup = plugin.setup;
|
||||
if (setup?.afterAccountConfigWritten) {
|
||||
const afterAccountConfigWritten = plugin.setup?.afterAccountConfigWritten;
|
||||
if (afterAccountConfigWritten) {
|
||||
await runCollectedChannelOnboardingPostWriteHooks({
|
||||
hooks: [
|
||||
{
|
||||
channel,
|
||||
accountId,
|
||||
run: async ({ cfg: writtenCfg, runtime: hookRuntime }) =>
|
||||
await setup.afterAccountConfigWritten?.({
|
||||
await afterAccountConfigWritten({
|
||||
previousCfg: cfg,
|
||||
cfg: writtenCfg,
|
||||
accountId,
|
||||
|
||||
@@ -119,7 +119,6 @@ export async function channelsRemoveCommand(
|
||||
runtime.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
const resolvedAccountId =
|
||||
normalizeAccountId(accountId) ?? resolveChannelDefaultAccountId({ plugin, cfg });
|
||||
const accountKey = resolvedAccountId || DEFAULT_ACCOUNT_ID;
|
||||
@@ -164,14 +163,14 @@ export async function channelsRemoveCommand(
|
||||
if (useWizard && prompter) {
|
||||
await prompter.outro(
|
||||
deleteConfig
|
||||
? `Deleted ${channelLabel(channel)} account "${accountKey}".`
|
||||
: `Disabled ${channelLabel(channel)} account "${accountKey}".`,
|
||||
? `Deleted ${channelLabel(resolvedChannel)} account "${accountKey}".`
|
||||
: `Disabled ${channelLabel(resolvedChannel)} account "${accountKey}".`,
|
||||
);
|
||||
} else {
|
||||
runtime.log(
|
||||
deleteConfig
|
||||
? `Deleted ${channelLabel(channel)} account "${accountKey}".`
|
||||
: `Disabled ${channelLabel(channel)} account "${accountKey}".`,
|
||||
? `Deleted ${channelLabel(resolvedChannel)} account "${accountKey}".`
|
||||
: `Disabled ${channelLabel(resolvedChannel)} account "${accountKey}".`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ import type {
|
||||
OpenClawPluginCommandDefinition,
|
||||
OpenClawPluginConfigSchema,
|
||||
OpenClawPluginDefinition,
|
||||
PluginInteractiveTelegramHandlerContext,
|
||||
PluginCommandContext,
|
||||
PluginInteractiveTelegramHandlerContext,
|
||||
} from "../plugins/types.js";
|
||||
|
||||
export type {
|
||||
|
||||
@@ -6,7 +6,10 @@ export type { SecretInput } from "../config/types.secrets.js";
|
||||
export type { WizardPrompter } from "../wizard/prompts.js";
|
||||
export type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js";
|
||||
export type { ChannelSetupInput } from "../channels/plugins/types.core.js";
|
||||
export type { ChannelSetupDmPolicy } from "../channels/plugins/setup-wizard-types.js";
|
||||
export type {
|
||||
ChannelSetupDmPolicy,
|
||||
ChannelSetupWizardAdapter,
|
||||
} from "../channels/plugins/setup-wizard-types.js";
|
||||
export type {
|
||||
ChannelSetupWizard,
|
||||
ChannelSetupWizardAllowFromEntry,
|
||||
|
||||
Reference in New Issue
Block a user