Telegram: threaded conversation support (#1597)

* Telegram: isolate dm topic sessions

* Tests: cap vitest workers

* Tests: cap Vitest workers on CI macOS

* Tests: avoid timer-based pi-ai stream mock

* Tests: increase embedded runner timeout

* fix: harden telegram dm thread handling (#1597) (thanks @rohannagpal)

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
Rohan Nagpal
2026-01-25 10:18:51 +05:30
committed by GitHub
parent 9eaaadf8ee
commit 06a7e1e8ce
10 changed files with 256 additions and 11 deletions

View File

@@ -121,6 +121,26 @@ describe("getDmHistoryLimitFromSessionKey", () => {
} as ClawdbotConfig;
expect(getDmHistoryLimitFromSessionKey("agent:main:telegram:dm:123", config)).toBe(10);
});
it("strips thread suffix from dm session keys", () => {
const config = {
channels: { telegram: { dmHistoryLimit: 10, dms: { "123": { historyLimit: 7 } } } },
} as ClawdbotConfig;
expect(getDmHistoryLimitFromSessionKey("agent:main:telegram:dm:123:thread:999", config)).toBe(
7,
);
expect(getDmHistoryLimitFromSessionKey("agent:main:telegram:dm:123:topic:555", config)).toBe(7);
expect(getDmHistoryLimitFromSessionKey("telegram:dm:123:thread:999", config)).toBe(7);
});
it("keeps non-numeric thread markers in dm ids", () => {
const config = {
channels: {
telegram: { dms: { "user:thread:abc": { historyLimit: 9 } } },
},
} as ClawdbotConfig;
expect(getDmHistoryLimitFromSessionKey("agent:main:telegram:dm:user:thread:abc", config)).toBe(
9,
);
});
it("returns undefined for non-dm session kinds", () => {
const config = {
channels: {

View File

@@ -70,7 +70,7 @@ vi.mock("@mariozechner/pi-ai", async () => {
},
streamSimple: (model: { api: string; provider: string; id: string }) => {
const stream = new actual.AssistantMessageEventStream();
setTimeout(() => {
queueMicrotask(() => {
stream.push({
type: "done",
reason: "stop",
@@ -80,7 +80,7 @@ vi.mock("@mariozechner/pi-ai", async () => {
: buildAssistantMessage(model),
});
stream.end();
}, 0);
});
return stream;
},
};
@@ -213,7 +213,7 @@ describe("runEmbeddedPiAgent", () => {
itIfNotWin32(
"persists the first user message before assistant output",
{ timeout: 60_000 },
{ timeout: 120_000 },
async () => {
const sessionFile = nextSessionFile();
const cfg = makeOpenAiConfig(["mock-1"]);

View File

@@ -2,6 +2,13 @@ import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { ClawdbotConfig } from "../../config/config.js";
const THREAD_SUFFIX_REGEX = /^(.*)(?::(?:thread|topic):\d+)$/i;
function stripThreadSuffix(value: string): string {
const match = value.match(THREAD_SUFFIX_REGEX);
return match?.[1] ?? value;
}
/**
* Limits conversation history to the last N user turns (and their associated
* assistant responses). This reduces token usage for long-running DM sessions.
@@ -44,7 +51,8 @@ export function getDmHistoryLimitFromSessionKey(
if (!provider) return undefined;
const kind = providerParts[1]?.toLowerCase();
const userId = providerParts.slice(2).join(":");
const userIdRaw = providerParts.slice(2).join(":");
const userId = stripThreadSuffix(userIdRaw);
if (kind !== "dm") return undefined;
const getLimit = (