fix(telegram): honor human delay for streamed replies (#69022)

Punchcard-Session: calm-brook-harbor-jm
This commit is contained in:
Han Yang
2026-08-25 18:25:35 +08:00
committed by GitHub
parent 4dad2e6571
commit 15826de945
4 changed files with 32 additions and 0 deletions
@@ -41,6 +41,7 @@ import {
handleReplySkip,
resetReasoningStepState,
} from "./bot-message-dispatch-reply.js";
import { resolveHumanDelayConfig } from "./bot-message-dispatch.agent.runtime.js";
import type { TelegramDispatchTurn as Turn } from "./bot-message-dispatch.types.js";
import { TELEGRAM_CHAT_ACTION_INTERVAL_MS } from "./chat-action-timing.js";
import { telegramInboundEventDelivery } from "./inbound-event-delivery.js";
@@ -134,6 +135,7 @@ export async function runTelegramDispatchTurn(turn: Turn) {
},
dispatcherOptions: {
...replyPipeline,
humanDelay: resolveHumanDelayConfig(turn.cfg, context.route.agentId),
beforeDeliver: async (payload) => payload,
onBeforeDeliverCancelled: (payload, info) =>
handleBeforeDeliverCancelled(turn, payload, info),
@@ -5,4 +5,5 @@ export {
modelSupportsVision,
resolveAgentDir,
resolveDefaultModelForAgent,
resolveHumanDelayConfig,
} from "openclaw/plugin-sdk/agent-runtime";
@@ -16,6 +16,7 @@ import {
mockDefaultSessionEntry,
readLatestAssistantTextByIdentity,
recordOutboundMessageForPromptContext,
resolveHumanDelayConfig,
setupDraftStreams,
telegramDepsForTest,
} from "./bot-message-dispatch.test-harness.js";
@@ -25,6 +26,29 @@ import type {
} from "./bot-message-dispatch.test-harness.js";
describeTelegramDispatch("dispatchTelegramMessage delivery-basics", () => {
it("forwards route-scoped humanDelay to the block dispatcher", async () => {
const humanDelay = { mode: "custom" as const, minMs: 800, maxMs: 2_500 };
const cfg = { agents: { defaults: { humanDelay } } } as Parameters<
typeof dispatchWithContext
>[0]["cfg"];
resolveHumanDelayConfig.mockReturnValue(humanDelay);
await dispatchWithContext({
context: createContext({
route: {
agentId: "ops",
accountId: "default",
} as unknown as TelegramMessageContext["route"],
}),
cfg,
streamMode: "off",
});
expect(resolveHumanDelayConfig).toHaveBeenCalledWith(cfg, "ops");
const dispatch = expectRecordFields(mockCallArg(dispatchReplyWithBufferedBlockDispatcher), {});
expectRecordFields(dispatch.dispatcherOptions, { humanDelay });
});
it("forwards cfg to direct reply delivery", async () => {
dispatchReplyWithBufferedBlockDispatcher.mockImplementation(async ({ dispatcherOptions }) => {
await dispatcherOptions.deliver({ text: "Hello" }, { kind: "final" });
@@ -110,6 +110,7 @@ const resolveAgentWorkspaceDirHoisted = vi.hoisted(() => vi.fn(() => "/tmp/works
const resolveDefaultModelForAgentHoisted = vi.hoisted(() =>
vi.fn(() => ({ provider: "openai", model: "gpt-test" })),
);
const resolveHumanDelayConfigHoisted = vi.hoisted(() => vi.fn());
const getAgentScopedMediaLocalRootsHoisted = vi.hoisted(() =>
vi.fn((_cfg: unknown, agentId: string) => [`/tmp/.openclaw/workspace-${agentId}`]),
);
@@ -154,6 +155,7 @@ const findModelInCatalog = findModelInCatalogHoisted;
const modelSupportsVision = modelSupportsVisionHoisted;
const resolveAgentDir = resolveAgentDirHoisted;
const resolveDefaultModelForAgent = resolveDefaultModelForAgentHoisted;
export const resolveHumanDelayConfig = resolveHumanDelayConfigHoisted;
const getAgentScopedMediaLocalRoots = getAgentScopedMediaLocalRootsHoisted;
const resolveChunkMode = resolveChunkModeHoisted;
export const resolveMarkdownTableMode = resolveMarkdownTableModeHoisted;
@@ -301,6 +303,7 @@ vi.mock("./bot-message-dispatch.agent.runtime.js", () => ({
resolveAgentDir: resolveAgentDirHoisted,
resolveAgentWorkspaceDir: resolveAgentWorkspaceDirHoisted,
resolveDefaultModelForAgent: resolveDefaultModelForAgentHoisted,
resolveHumanDelayConfig: resolveHumanDelayConfigHoisted,
}));
vi.mock("./sticker-cache.js", () => ({
@@ -411,6 +414,7 @@ function resetTelegramDispatchTestState() {
modelSupportsVision.mockReset();
resolveAgentDir.mockReset();
resolveDefaultModelForAgent.mockReset();
resolveHumanDelayConfig.mockReset();
loadConfig.mockReturnValue({});
dispatchReplyWithBufferedBlockDispatcher.mockResolvedValue({
queuedFinal: false,
@@ -473,6 +477,7 @@ function resetTelegramDispatchTestState() {
provider: "openai",
model: "gpt-test",
});
resolveHumanDelayConfig.mockReturnValue(undefined);
getGlobalHookRunner.mockReturnValue(null);
}