diff --git a/extensions/elevenlabs/doctor-contract.ts b/extensions/elevenlabs/doctor-contract.ts index 5fd533c549d..2676ee84a1d 100644 --- a/extensions/elevenlabs/doctor-contract.ts +++ b/extensions/elevenlabs/doctor-contract.ts @@ -1,10 +1,10 @@ import type { ChannelDoctorLegacyConfigRule } from "openclaw/plugin-sdk/channel-contract"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; -import { - ELEVENLABS_TALK_PROVIDER_ID, - isRecord, - migrateElevenLabsLegacyTalkConfig, -} from "./config-compat.js"; +import { ELEVENLABS_TALK_PROVIDER_ID, migrateElevenLabsLegacyTalkConfig } from "./config-compat.js"; + +function isRecord(value: unknown): value is Record { + return Boolean(value) && typeof value === "object" && !Array.isArray(value); +} export function hasLegacyTalkFields(value: unknown): boolean { const talk = isRecord(value) ? value : null; diff --git a/src/cron/isolated-agent.skips-delivery-without-whatsapp-recipient-besteffortdeliver-true.test.ts b/src/cron/isolated-agent.skips-delivery-without-whatsapp-recipient-besteffortdeliver-true.test.ts index a9de163005d..ccd86d02dcc 100644 --- a/src/cron/isolated-agent.skips-delivery-without-whatsapp-recipient-besteffortdeliver-true.test.ts +++ b/src/cron/isolated-agent.skips-delivery-without-whatsapp-recipient-besteffortdeliver-true.test.ts @@ -243,58 +243,12 @@ async function runSignalDeliveryResult(bestEffort: boolean) { return outcome; } -async function assertExplicitTelegramTargetDelivery(params: { - home: string; - storePath: string; - deps: CliDeps; - payloads: Array>; - expectedTexts: string[]; -}): Promise { - mockAgentPayloads(params.payloads); - const res = await runExplicitTelegramAnnounceTurn({ - home: params.home, - storePath: params.storePath, - deps: params.deps, - }); - - expectDeliveredOk(res); - expect(runSubagentAnnounceFlow).not.toHaveBeenCalled(); - if (params.expectedTexts.length === 1) { - expectDirectTelegramDelivery(params.deps, { - chatId: "123", - text: params.expectedTexts[0] ?? "", - }); - return; - } - expect(params.deps.sendMessageTelegram).toHaveBeenCalledTimes(params.expectedTexts.length); - for (const [index, text] of params.expectedTexts.entries()) { - expect(params.deps.sendMessageTelegram).toHaveBeenNthCalledWith( - index + 1, - "123", - text, - expect.objectContaining({ cfg: expect.any(Object) }), - ); - } -} - describe("runCronIsolatedAgentTurn", () => { beforeEach(() => { vi.spyOn(modelSelection, "resolveThinkingDefault").mockReturnValue("off"); setupIsolatedAgentTurnMocks({ fast: true }); }); - it("delivers explicit targets with direct text", async () => { - await withTelegramAnnounceFixture(async ({ home, storePath, deps }) => { - await assertExplicitTelegramTargetDelivery({ - home, - storePath, - deps, - payloads: [{ text: "hello from cron" }], - expectedTexts: ["hello from cron"], - }); - }); - }); - it("delivers explicit targets directly with per-channel-peer session scoping", async () => { await withTelegramAnnounceFixture(async ({ home, storePath, deps }) => { mockAgentPayloads([{ text: "hello from cron" }]); diff --git a/src/cron/isolated-agent/delivery-dispatch.double-announce.test.ts b/src/cron/isolated-agent/delivery-dispatch.double-announce.test.ts index 4e92ddc1a5d..03f27b7594c 100644 --- a/src/cron/isolated-agent/delivery-dispatch.double-announce.test.ts +++ b/src/cron/isolated-agent/delivery-dispatch.double-announce.test.ts @@ -666,6 +666,30 @@ describe("dispatchCronDelivery — double-announce guard", () => { ).toBe(false); }); + it("delivers explicit targets with direct text through the outbound adapter", async () => { + vi.mocked(countActiveDescendantRuns).mockReturnValue(0); + vi.mocked(isLikelyInterimCronMessage).mockReturnValue(false); + + const params = makeBaseParams({ synthesizedText: "hello from cron" }); + const state = await dispatchCronDelivery(params); + + expect(state.result).toBeUndefined(); + expect(state.delivered).toBe(true); + expect(state.deliveryAttempted).toBe(true); + expect(deliverOutboundPayloads).toHaveBeenCalledTimes(1); + expect(deliverOutboundPayloads).toHaveBeenCalledWith( + expect.objectContaining({ + channel: "telegram", + to: "123456", + accountId: undefined, + threadId: undefined, + bestEffort: false, + skipQueue: true, + payloads: [{ text: "hello from cron" }], + }), + ); + }); + it("suppresses NO_REPLY payload with surrounding whitespace", async () => { vi.mocked(countActiveDescendantRuns).mockReturnValue(0); vi.mocked(isLikelyInterimCronMessage).mockReturnValue(false);