























@@ -27,6 +27,7 @@ type DispatchReplyWithBufferedBlockDispatcherResult = Awaited<
2727>;
2828type DeliverRepliesFn = typeof import("./bot/delivery.js").deliverReplies;
2929type DeliverRepliesParams = Parameters<DeliverRepliesFn>[0];
30+type MatchPluginCommandFn = typeof import("./bot-native-commands.runtime.js").matchPluginCommand;
30313132const dispatchReplyResult: DispatchReplyWithBufferedBlockDispatcherResult = {
3233queuedFinal: false,
@@ -45,11 +46,16 @@ const persistentBindingMocks = vi.hoisted(() => ({
4546const sessionMocks = vi.hoisted(() => ({
4647loadSessionStore: vi.fn(),
4748recordSessionMetaFromInbound: vi.fn(),
49+resolveAndPersistSessionFile: vi.fn(),
4850resolveStorePath: vi.fn(),
4951}));
5052const commandAuthMocks = vi.hoisted(() => ({
5153resolveCommandArgMenu: vi.fn(),
5254}));
55+const pluginRuntimeMocks = vi.hoisted(() => ({
56+executePluginCommand: vi.fn(async () => ({ text: "ok" })),
57+matchPluginCommand: vi.fn<MatchPluginCommandFn>(() => null),
58+}));
5359const replyMocks = vi.hoisted(() => ({
5460dispatchReplyWithBufferedBlockDispatcher: vi.fn<DispatchReplyWithBufferedBlockDispatcherFn>(
5561async () => dispatchReplyResult,
@@ -148,6 +154,7 @@ vi.mock("openclaw/plugin-sdk/session-store-runtime", async () => {
148154return {
149155 ...actual,
150156loadSessionStore: sessionMocks.loadSessionStore,
157+resolveAndPersistSessionFile: sessionMocks.resolveAndPersistSessionFile,
151158resolveStorePath: sessionMocks.resolveStorePath,
152159};
153160});
@@ -178,8 +185,8 @@ vi.mock("openclaw/plugin-sdk/plugin-runtime", async () => {
178185return {
179186 ...actual,
180187getPluginCommandSpecs: vi.fn(() => []),
181-matchPluginCommand: vi.fn(() => null),
182-executePluginCommand: vi.fn(async () => ({ text: "ok" })),
188+matchPluginCommand: pluginRuntimeMocks.matchPluginCommand,
189+executePluginCommand: pluginRuntimeMocks.executePluginCommand,
183190};
184191});
185192vi.mock("./bot/delivery.js", () => ({
@@ -192,6 +199,9 @@ vi.mock("./bot/delivery.replies.js", () => ({
192199let registerTelegramNativeCommands: typeof import("./bot-native-commands.js").registerTelegramNativeCommands;
193200194201type TelegramCommandHandler = (ctx: unknown) => Promise<void>;
202+type TelegramPluginCommandSpecs = ReturnType<
203+NonNullable<TelegramNativeCommandDeps["getPluginCommandSpecs"]>
204+>;
195205196206function registerAndResolveStatusHandler(params: {
197207cfg: OpenClawConfig;
@@ -233,6 +243,7 @@ function registerAndResolveCommandHandlerBase(params: {
233243useAccessGroups: boolean;
234244telegramCfg?: NativeCommandTestParams["telegramCfg"];
235245resolveTelegramGroupConfig?: RegisterTelegramHandlerParams["resolveTelegramGroupConfig"];
246+pluginCommandSpecs?: TelegramPluginCommandSpecs;
236247}): {
237248handler: TelegramCommandHandler;
238249sendMessage: ReturnType<typeof vi.fn>;
@@ -246,14 +257,15 @@ function registerAndResolveCommandHandlerBase(params: {
246257 useAccessGroups,
247258 telegramCfg,
248259 resolveTelegramGroupConfig,
260+ pluginCommandSpecs,
249261} = params;
250262const commandHandlers = new Map<string, TelegramCommandHandler>();
251263const sendMessage = vi.fn().mockResolvedValue(undefined);
252264const telegramDeps: TelegramNativeCommandDeps = {
253265getRuntimeConfig: vi.fn(() => cfg),
254266readChannelAllowFromStore: vi.fn(async () => storeAllowFrom ?? []),
255267dispatchReplyWithBufferedBlockDispatcher: replyMocks.dispatchReplyWithBufferedBlockDispatcher,
256-getPluginCommandSpecs: vi.fn(() => []),
268+getPluginCommandSpecs: vi.fn(() => pluginCommandSpecs ?? []),
257269listSkillCommandsForAgents: vi.fn(() => []),
258270syncTelegramMenuCommands: vi.fn(),
259271};
@@ -292,6 +304,7 @@ function registerAndResolveCommandHandler(params: {
292304useAccessGroups?: boolean;
293305telegramCfg?: NativeCommandTestParams["telegramCfg"];
294306resolveTelegramGroupConfig?: RegisterTelegramHandlerParams["resolveTelegramGroupConfig"];
307+pluginCommandSpecs?: TelegramPluginCommandSpecs;
295308}): {
296309handler: TelegramCommandHandler;
297310sendMessage: ReturnType<typeof vi.fn>;
@@ -305,6 +318,7 @@ function registerAndResolveCommandHandler(params: {
305318 useAccessGroups,
306319 telegramCfg,
307320 resolveTelegramGroupConfig,
321+ pluginCommandSpecs,
308322} = params;
309323return registerAndResolveCommandHandlerBase({
310324 commandName,
@@ -315,6 +329,7 @@ function registerAndResolveCommandHandler(params: {
315329useAccessGroups: useAccessGroups ?? true,
316330 telegramCfg,
317331 resolveTelegramGroupConfig,
332+ pluginCommandSpecs,
318333});
319334}
320335@@ -450,7 +465,22 @@ describe("registerTelegramNativeCommands — session metadata", () => {
450465commandAuthMocks.resolveCommandArgMenu.mockClear();
451466sessionMocks.loadSessionStore.mockClear().mockReturnValue({});
452467sessionMocks.recordSessionMetaFromInbound.mockClear().mockResolvedValue(undefined);
468+sessionMocks.resolveAndPersistSessionFile.mockClear().mockImplementation(async (params) => {
469+const sessionFile =
470+params.fallbackSessionFile ?? `/tmp/openclaw-sessions/${params.sessionId}.jsonl`;
471+return {
472+ sessionFile,
473+sessionEntry: {
474+ ...params.sessionEntry,
475+sessionId: params.sessionId,
476+ sessionFile,
477+updatedAt: Date.now(),
478+},
479+};
480+});
453481sessionMocks.resolveStorePath.mockClear().mockReturnValue("/tmp/openclaw-sessions.json");
482+pluginRuntimeMocks.executePluginCommand.mockClear().mockResolvedValue({ text: "ok" });
483+pluginRuntimeMocks.matchPluginCommand.mockClear().mockReturnValue(null);
454484replyMocks.dispatchReplyWithBufferedBlockDispatcher
455485.mockClear()
456486.mockResolvedValue(dispatchReplyResult);
@@ -1019,4 +1049,61 @@ describe("registerTelegramNativeCommands — session metadata", () => {
1019104910201050expectUnauthorizedNewCommandBlocked(sendMessage);
10211051});
1052+1053+it("passes a persisted topic session file to plugin commands", async () => {
1054+sessionMocks.resolveStorePath.mockReturnValue("/tmp/openclaw-sessions/sessions.json");
1055+sessionMocks.loadSessionStore.mockReturnValue({
1056+"agent:main:telegram:group:-1001234567890:topic:42": {
1057+sessionId: "sess-topic",
1058+updatedAt: 1,
1059+},
1060+});
1061+1062+const { handler } = registerAndResolveCommandHandler({
1063+commandName: "codex",
1064+cfg: { commands: { allowFrom: { telegram: ["200"] } } } as OpenClawConfig,
1065+groupAllowFrom: ["-1001234567890"],
1066+useAccessGroups: false,
1067+pluginCommandSpecs: [
1068+{
1069+name: "codex",
1070+description: "Codex",
1071+acceptsArgs: true,
1072+},
1073+] as TelegramPluginCommandSpecs,
1074+});
1075+pluginRuntimeMocks.matchPluginCommand.mockReturnValue({
1076+command: {
1077+name: "codex",
1078+description: "Codex",
1079+handler: vi.fn(),
1080+pluginId: "openclaw-codex-app-server",
1081+pluginName: "Codex",
1082+requireAuth: true,
1083+},
1084+args: "bind --cwd /tmp/work",
1085+});
1086+1087+await handler(
1088+createTelegramTopicCommandContext({ match: "bind --cwd /tmp/work", threadId: 42 }),
1089+);
1090+1091+expect(sessionMocks.resolveAndPersistSessionFile).toHaveBeenCalledWith(
1092+expect.objectContaining({
1093+sessionId: "sess-topic",
1094+sessionKey: "agent:main:telegram:group:-1001234567890:topic:42",
1095+storePath: "/tmp/openclaw-sessions/sessions.json",
1096+sessionsDir: "/tmp/openclaw-sessions",
1097+fallbackSessionFile: "/tmp/openclaw-sessions/sess-topic-topic-42.jsonl",
1098+}),
1099+);
1100+expect(pluginRuntimeMocks.executePluginCommand).toHaveBeenCalledWith(
1101+expect.objectContaining({
1102+sessionKey: "agent:main:telegram:group:-1001234567890:topic:42",
1103+sessionId: "sess-topic",
1104+sessionFile: "/tmp/openclaw-sessions/sess-topic-topic-42.jsonl",
1105+messageThreadId: 42,
1106+}),
1107+);
1108+});
10221109});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。