fix(telegram): restore 30-char preview debounce

This commit is contained in:
Ayaan Zaidi
2026-02-21 17:56:39 +05:30
parent 36996628ac
commit bb14a34078
5 changed files with 38 additions and 9 deletions

View File

@@ -138,10 +138,7 @@ export async function runAgentTurnWithFallback(params: {
}
text = stripped.text;
}
if (
isSilentReplyText(text, SILENT_REPLY_TOKEN) ||
isSilentReplyPrefixText(text, SILENT_REPLY_TOKEN)
) {
if (isSilentReplyText(text, SILENT_REPLY_TOKEN)) {
return { skip: true };
}
if (!text) {
@@ -160,6 +157,9 @@ export async function runAgentTurnWithFallback(params: {
return { text: sanitized, skip: false };
};
const handlePartialForTyping = async (payload: ReplyPayload): Promise<string | undefined> => {
if (isSilentReplyPrefixText(payload.text, SILENT_REPLY_TOKEN)) {
return undefined;
}
const { text, skip } = normalizeStreamingText(payload);
if (skip || !text) {
return undefined;

View File

@@ -403,6 +403,30 @@ describe("runReplyAgent typing (heartbeat)", () => {
expect(typing.startTypingLoop).not.toHaveBeenCalled();
});
it("does not suppress partial streaming for normal 'No' prefixes", async () => {
const onPartialReply = vi.fn();
state.runEmbeddedPiAgentMock.mockImplementationOnce(async (params: AgentRunParams) => {
await params.onPartialReply?.({ text: "No" });
await params.onPartialReply?.({ text: "No, that is valid" });
return { payloads: [{ text: "No, that is valid" }], meta: {} };
});
const { run, typing } = createMinimalRun({
opts: { isHeartbeat: false, onPartialReply },
typingMode: "message",
});
await run();
expect(onPartialReply).toHaveBeenCalledTimes(2);
expect(onPartialReply).toHaveBeenNthCalledWith(1, { text: "No", mediaUrls: undefined });
expect(onPartialReply).toHaveBeenNthCalledWith(2, {
text: "No, that is valid",
mediaUrls: undefined,
});
expect(typing.startTypingOnText).toHaveBeenCalled();
expect(typing.startTypingLoop).not.toHaveBeenCalled();
});
it("does not start typing on assistant message start without prior text in message mode", async () => {
state.runEmbeddedPiAgentMock.mockImplementationOnce(async (params: AgentRunParams) => {
await params.onAssistantMessageStart?.();

View File

@@ -30,5 +30,11 @@ export function isSilentReplyPrefixText(
if (!normalized) {
return false;
}
if (!normalized.includes("_")) {
return false;
}
if (/[^A-Z_]/.test(normalized)) {
return false;
}
return token.toUpperCase().startsWith(normalized);
}

View File

@@ -191,7 +191,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
expect.objectContaining({
chatId: 123,
thread: { id: 777, scope: "dm" },
minInitialChars: 1,
minInitialChars: 30,
}),
);
expect(draftStream.update).toHaveBeenCalledWith("Hello");
@@ -212,7 +212,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
expect(draftStream.clear).toHaveBeenCalledTimes(1);
});
it("uses immediate preview updates for legacy block stream mode", async () => {
it("uses 30-char preview debounce for legacy block stream mode", async () => {
const draftStream = createDraftStream();
createTelegramDraftStream.mockReturnValue(draftStream);
dispatchReplyWithBufferedBlockDispatcher.mockImplementation(
@@ -228,7 +228,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
expect(createTelegramDraftStream).toHaveBeenCalledWith(
expect.objectContaining({
minInitialChars: 1,
minInitialChars: 30,
}),
);
});

View File

@@ -147,8 +147,7 @@ export const dispatchTelegramMessage = async ({
const canStreamReasoningDraft = canStreamAnswerDraft || streamReasoningDraft;
const draftReplyToMessageId =
replyToMode !== "off" && typeof msg.message_id === "number" ? msg.message_id : undefined;
const draftMinInitialChars =
previewStreamingEnabled || streamReasoningDraft ? 1 : DRAFT_MIN_INITIAL_CHARS;
const draftMinInitialChars = DRAFT_MIN_INITIAL_CHARS;
const mediaLocalRoots = getAgentScopedMediaLocalRoots(cfg, route.agentId);
type LaneName = "answer" | "reasoning";
type DraftLaneState = {