diff --git a/extensions/telegram/src/bot-handlers.agent.runtime.ts b/extensions/telegram/src/bot-handlers.agent.runtime.ts new file mode 100644 index 00000000000..afe9ab7eab5 --- /dev/null +++ b/extensions/telegram/src/bot-handlers.agent.runtime.ts @@ -0,0 +1,5 @@ +export { + resolveAgentDir, + resolveDefaultAgentId, + resolveDefaultModelForAgent, +} from "openclaw/plugin-sdk/agent-runtime"; diff --git a/extensions/telegram/src/bot-handlers.runtime.ts b/extensions/telegram/src/bot-handlers.runtime.ts index 200e48aabc3..c22426e2cfa 100644 --- a/extensions/telegram/src/bot-handlers.runtime.ts +++ b/extensions/telegram/src/bot-handlers.runtime.ts @@ -1,6 +1,4 @@ import type { Message, ReactionTypeEmoji } from "@grammyjs/types"; -import { resolveAgentDir, resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime"; -import { resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime"; import { resolveChannelConfigWrites } from "openclaw/plugin-sdk/channel-config-helpers"; import { shouldDebounceTextInbound } from "openclaw/plugin-sdk/channel-inbound"; import { @@ -44,6 +42,11 @@ import { type NormalizedAllowFrom, } from "./bot-access.js"; import { defaultTelegramBotDeps } from "./bot-deps.js"; +import { + resolveAgentDir, + resolveDefaultAgentId, + resolveDefaultModelForAgent, +} from "./bot-handlers.agent.runtime.js"; import { hasInboundMedia, hasReplyTargetMedia, diff --git a/extensions/telegram/src/bot-message-dispatch.agent.runtime.ts b/extensions/telegram/src/bot-message-dispatch.agent.runtime.ts new file mode 100644 index 00000000000..856bedc994e --- /dev/null +++ b/extensions/telegram/src/bot-message-dispatch.agent.runtime.ts @@ -0,0 +1,7 @@ +export { + findModelInCatalog, + loadModelCatalog, + modelSupportsVision, + resolveAgentDir, + resolveDefaultModelForAgent, +} from "openclaw/plugin-sdk/agent-runtime"; diff --git a/extensions/telegram/src/bot-message-dispatch.runtime.ts b/extensions/telegram/src/bot-message-dispatch.runtime.ts index 70944cd2791..93cc3a63bad 100644 --- a/extensions/telegram/src/bot-message-dispatch.runtime.ts +++ b/extensions/telegram/src/bot-message-dispatch.runtime.ts @@ -4,7 +4,7 @@ export { resolveSessionStoreEntry, resolveStorePath, } from "openclaw/plugin-sdk/config-runtime"; -export { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime"; +export { getAgentScopedMediaLocalRoots } from "./telegram-media.runtime.js"; export { generateTopicLabel, resolveAutoTopicLabelConfig, diff --git a/extensions/telegram/src/bot-message-dispatch.ts b/extensions/telegram/src/bot-message-dispatch.ts index 7529a9cfcbb..b79349e25f9 100644 --- a/extensions/telegram/src/bot-message-dispatch.ts +++ b/extensions/telegram/src/bot-message-dispatch.ts @@ -1,11 +1,4 @@ import type { Bot } from "grammy"; -import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime"; -import { - findModelInCatalog, - loadModelCatalog, - modelSupportsVision, -} from "openclaw/plugin-sdk/agent-runtime"; -import { resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime"; import { logAckFailure, logTypingFailure, @@ -25,6 +18,13 @@ import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env"; import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env"; import { defaultTelegramBotDeps, type TelegramBotDeps } from "./bot-deps.js"; import type { TelegramMessageContext } from "./bot-message-context.js"; +import { + findModelInCatalog, + loadModelCatalog, + modelSupportsVision, + resolveAgentDir, + resolveDefaultModelForAgent, +} from "./bot-message-dispatch.agent.runtime.js"; import { loadSessionStore, resolveMarkdownTableMode, diff --git a/extensions/telegram/src/bot.agent.runtime.ts b/extensions/telegram/src/bot.agent.runtime.ts new file mode 100644 index 00000000000..9ac75c05a97 --- /dev/null +++ b/extensions/telegram/src/bot.agent.runtime.ts @@ -0,0 +1 @@ +export { resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime"; diff --git a/extensions/telegram/src/bot.media.e2e-harness.ts b/extensions/telegram/src/bot.media.e2e-harness.ts index ad9702b6a1c..0d6b182800d 100644 --- a/extensions/telegram/src/bot.media.e2e-harness.ts +++ b/extensions/telegram/src/bot.media.e2e-harness.ts @@ -127,6 +127,7 @@ const mediaHarnessReplySpy = vi.hoisted(() => return undefined; }), ); +export { mediaHarnessReplySpy }; const mediaHarnessDispatchReplyWithBufferedBlockDispatcher = vi.hoisted(() => vi.fn(async (params: DispatchReplyHarnessParams) => { @@ -179,45 +180,29 @@ vi.doMock("./bot.runtime.js", () => ({ ...telegramBotRuntimeForTest, })); -vi.mock("undici", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - fetch: (...args: Parameters) => undiciFetchSpy(...args), - }; -}); +vi.mock("undici", () => ({ + Agent: vi.fn(function MockAgent(this: { options?: unknown }, options?: unknown) { + this.options = options; + }), + EnvHttpProxyAgent: vi.fn(function MockEnvHttpProxyAgent( + this: { options?: unknown }, + options?: unknown, + ) { + this.options = options; + }), + ProxyAgent: vi.fn(function MockProxyAgent(this: { options?: unknown }, options?: unknown) { + this.options = options; + }), + fetch: (...args: Parameters) => undiciFetchSpy(...args), + setGlobalDispatcher: vi.fn(), +})); -export async function mockMediaRuntimeModuleForTest( - importOriginal: () => Promise, -) { - const actual = await importOriginal(); - const mockModule = Object.create(null) as Record; - Object.defineProperties(mockModule, Object.getOwnPropertyDescriptors(actual)); - Object.defineProperty(mockModule, "fetchRemoteMedia", { - configurable: true, - enumerable: true, - writable: true, - value: (...args: Parameters) => fetchRemoteMediaSpy(...args), - }); - Object.defineProperty(mockModule, "saveMediaBuffer", { - configurable: true, - enumerable: true, - writable: true, - value: (...args: Parameters) => saveMediaBufferSpy(...args), - }); - return mockModule; -} - -vi.mock("openclaw/plugin-sdk/media-runtime", mockMediaRuntimeModuleForTest); - -vi.doMock("openclaw/plugin-sdk/config-runtime", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - loadConfig: telegramBotDepsForTest.loadConfig, - updateLastRoute: vi.fn(async () => undefined), - }; -}); +vi.mock("./telegram-media.runtime.js", () => ({ + fetchRemoteMedia: (...args: Parameters) => + fetchRemoteMediaSpy(...args), + getAgentScopedMediaLocalRoots: vi.fn(() => []), + saveMediaBuffer: (...args: Parameters) => saveMediaBufferSpy(...args), +})); vi.doMock("./bot-message-context.session.runtime.js", async (importOriginal) => { const actual = await importOriginal(); @@ -228,37 +213,26 @@ vi.doMock("./bot-message-context.session.runtime.js", async (importOriginal) => }; }); -vi.doMock("openclaw/plugin-sdk/agent-runtime", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - findModelInCatalog: vi.fn(() => undefined), - loadModelCatalog: vi.fn(async () => []), - modelSupportsVision: vi.fn(() => false), - resolveDefaultModelForAgent: vi.fn(() => ({ - provider: "openai", - model: "gpt-test", - })), - }; -}); +vi.mock("./bot.agent.runtime.js", () => ({ + resolveDefaultAgentId: vi.fn(() => "default"), +})); -vi.doMock("openclaw/plugin-sdk/conversation-runtime", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - readChannelAllowFromStore: telegramBotDepsForTest.readChannelAllowFromStore, - upsertChannelPairingRequest: vi.fn(async () => ({ - code: "PAIRCODE", - created: true, - })), - }; -}); +vi.mock("./bot-handlers.agent.runtime.js", () => ({ + resolveAgentDir: vi.fn(() => "/tmp/agent"), + resolveDefaultAgentId: vi.fn(() => "default"), + resolveDefaultModelForAgent: vi.fn(() => ({ + provider: "openai", + model: "gpt-test", + })), +})); -vi.doMock("openclaw/plugin-sdk/reply-runtime", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - getReplyFromConfig: mediaHarnessReplySpy, - __replySpy: mediaHarnessReplySpy, - }; -}); +vi.mock("./bot-message-dispatch.agent.runtime.js", () => ({ + findModelInCatalog: vi.fn(() => undefined), + loadModelCatalog: vi.fn(async () => []), + modelSupportsVision: vi.fn(() => false), + resolveAgentDir: vi.fn(() => "/tmp/agent"), + resolveDefaultModelForAgent: vi.fn(() => ({ + provider: "openai", + model: "gpt-test", + })), +})); diff --git a/extensions/telegram/src/bot.media.test-utils.ts b/extensions/telegram/src/bot.media.test-utils.ts index 444a8a12198..01d7b3facd5 100644 --- a/extensions/telegram/src/bot.media.test-utils.ts +++ b/extensions/telegram/src/bot.media.test-utils.ts @@ -1,5 +1,5 @@ import * as ssrf from "openclaw/plugin-sdk/ssrf-runtime"; -import { afterEach, beforeEach, expect, vi, type Mock } from "vitest"; +import { afterEach, beforeAll, beforeEach, expect, vi, type Mock } from "vitest"; import * as harness from "./bot.media.e2e-harness.js"; type StickerSpy = Mock<(...args: unknown[]) => unknown>; @@ -132,13 +132,17 @@ async function loadTelegramBotHarness() { ...opts, telegramDeps: harness.telegramBotDepsForTest, }); - const replyModule = await import("openclaw/plugin-sdk/reply-runtime"); - replySpyRef = (replyModule as unknown as { __replySpy: ReturnType }).__replySpy; + replySpyRef = harness.mediaHarnessReplySpy; } -beforeEach(async () => { - vi.resetModules(); +beforeAll(async () => { await loadTelegramBotHarness(); +}); + +beforeEach(() => { + onSpyRef.mockClear(); + replySpyRef.mockClear(); + sendChatActionSpyRef.mockClear(); vi.useRealTimers(); lookupMock.mockResolvedValue([{ address: "93.184.216.34", family: 4 }]); resolvePinnedHostnameSpy = vi @@ -152,12 +156,11 @@ afterEach(() => { resolvePinnedHostnameSpy = null; }); -vi.mock("./sticker-cache.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - cacheSticker: (...args: unknown[]) => cacheStickerSpy(...args), - getCachedSticker: (...args: unknown[]) => getCachedStickerSpy(...args), - describeStickerImage: (...args: unknown[]) => describeStickerImageSpy(...args), - }; -}); +vi.mock("./sticker-cache.js", () => ({ + cacheSticker: (...args: unknown[]) => cacheStickerSpy(...args), + getCachedSticker: (...args: unknown[]) => getCachedStickerSpy(...args), + describeStickerImage: (...args: unknown[]) => describeStickerImageSpy(...args), + getAllCachedStickers: vi.fn(() => []), + getCacheStats: vi.fn(() => ({ count: 0 })), + searchStickers: vi.fn(() => []), +})); diff --git a/extensions/telegram/src/bot.ts b/extensions/telegram/src/bot.ts index 3e36bfaa52f..3f0dedf0cdb 100644 --- a/extensions/telegram/src/bot.ts +++ b/extensions/telegram/src/bot.ts @@ -1,4 +1,3 @@ -import { resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime"; import { isNativeCommandsExplicitlyDisabled, resolveNativeCommandsEnabled, @@ -32,6 +31,7 @@ import { resolveTelegramUpdateId, type TelegramUpdateKeyContext, } from "./bot-updates.js"; +import { resolveDefaultAgentId } from "./bot.agent.runtime.js"; import { apiThrottler, Bot, sequentialize, type ApiClientOptions } from "./bot.runtime.js"; import { buildTelegramGroupPeerId, resolveTelegramStreamMode } from "./bot/helpers.js"; import { resolveTelegramTransport, type TelegramTransport } from "./fetch.js"; diff --git a/extensions/telegram/src/bot/delivery.resolve-media.runtime.ts b/extensions/telegram/src/bot/delivery.resolve-media.runtime.ts index d966179387f..d7f2fdb3ba1 100644 --- a/extensions/telegram/src/bot/delivery.resolve-media.runtime.ts +++ b/extensions/telegram/src/bot/delivery.resolve-media.runtime.ts @@ -1,7 +1,7 @@ -import { fetchRemoteMedia, saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime"; import { logVerbose, retryAsync, warn } from "openclaw/plugin-sdk/runtime-env"; import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime"; import { resolveTelegramApiBase, shouldRetryTelegramTransportFallback } from "../fetch.js"; +import { fetchRemoteMedia, saveMediaBuffer } from "../telegram-media.runtime.js"; export { fetchRemoteMedia, diff --git a/extensions/telegram/src/telegram-media.runtime.ts b/extensions/telegram/src/telegram-media.runtime.ts new file mode 100644 index 00000000000..1dbe3fb8877 --- /dev/null +++ b/extensions/telegram/src/telegram-media.runtime.ts @@ -0,0 +1,5 @@ +export { + fetchRemoteMedia, + getAgentScopedMediaLocalRoots, + saveMediaBuffer, +} from "openclaw/plugin-sdk/media-runtime";