Files
Evandro Fonseca Junior d1d04001d0
Release / release (push) Failing after 5s
Validate / validate (push) Failing after 5m21s
chore: fork @llblab/[email protected] as @evandrodevbr/oh-my-pi-telegram
Fork of upstream llblab/[email protected].0 (SHA afe09c5) repackaged as a
drop-in extension for can1357/oh-my-pi (omp >= 16.5.2).

Changes vs upstream:
- Rename package: @llblab/pi-telegram -> @evandrodevbr/oh-my-pi-telegram
- Bump version: 0.22.0 -> 0.22.0-evandro.1
- Update repository/homepage/bugs URLs to evandrodevbr
- Add omp field in package.json (displayName + compatibleWith)
- README: prepend 'Oh My Pi (omp) Compatibility' section with install
  commands, verified-components table, upstream lineage, and rationale
- CHANGELOG: add '0.22.0-evandro.1' entry under Unreleased
- docs/: rename @llblab/pi-telegram imports to @evandrodevbr/oh-my-pi-telegram
- tests/public-api.test.ts: rename package import paths

Gates re-run on the fork:
- npm run typecheck  -> tsc --noEmit (success)
- npm test           -> 1229 pass / 0 fail / 1 platform-only skip
- npm run audit      -> found 0 vulnerabilities
- npm run pack:check -> evandrodevbr-oh-my-pi-telegram-0.22.0-evandro.1.tgz

Verified:
- omp install --link ./pi-telegram -> Linked OK
- omp plugin list -> @evandrodevbr/[email protected].0-evandro.1

Upstream lineage: badlogic/pi-telegram -> llblab/pi-telegram (0.22.0) -> evandrodevbr/oh-my-pi-telegram (this fork)
2026-07-15 14:18:16 -03:00

223 lines
5.3 KiB
TypeScript

/**
* Regression tests for Telegram status menu helpers
* Exercises status-menu reply markup, callback routing, and message render/update helpers
*/
import assert from "node:assert/strict";
import test from "node:test";
import {
buildStatusReplyMarkup,
buildTelegramStatusMenuRenderPayload,
handleTelegramStatusMenuCallbackAction,
openTelegramStatusMenu,
sendTelegramStatusMessage,
updateTelegramStatusMessage,
} from "../lib/menu-status.ts";
const reasoningModel = {
provider: "openai",
id: "gpt-5",
reasoning: true,
};
test("Status menu reply markup exposes model, thinking, queue, and settings rows", () => {
const markup = buildStatusReplyMarkup(reasoningModel, "medium", 2);
assert.deepEqual(
markup.inline_keyboard.map((row) => row[0]?.callback_data),
["menu:model", "menu:thinking", "menu:queue", "menu:settings"],
);
assert.equal(
markup.inline_keyboard[0]?.[0]?.text.startsWith("🤖 Model"),
true,
);
assert.equal(
markup.inline_keyboard[1]?.[0]?.text.startsWith("🧠 Thinking"),
true,
);
assert.equal(markup.inline_keyboard[2]?.[0]?.text, "⏳ Queue: 2");
});
test("Status menu hides thinking row for non-reasoning and voice-active states", () => {
assert.deepEqual(
buildStatusReplyMarkup(
{ provider: "x", id: "plain" },
"off",
0,
).inline_keyboard.map((row) => row[0]?.callback_data),
["menu:model", "menu:queue", "menu:settings"],
);
assert.deepEqual(
buildStatusReplyMarkup(
reasoningModel,
"medium",
0,
undefined,
true,
).inline_keyboard.map((row) => row[0]?.callback_data),
["menu:model", "menu:queue", "menu:settings"],
);
});
test("Status callback routing updates target menus and guards thinking controls", async () => {
const calls: string[] = [];
const deps = {
updateModelMenuMessage: async () => {
calls.push("model");
},
updateThinkingMenuMessage: async () => {
calls.push("thinking");
},
updateSettingsMenuMessage: async () => {
calls.push("settings");
},
answerCallbackQuery: async (_id: string, text?: string) => {
calls.push(text ?? "answered");
},
};
assert.equal(
await handleTelegramStatusMenuCallbackAction(
"q1",
"status:model",
reasoningModel,
deps,
),
true,
);
assert.equal(
await handleTelegramStatusMenuCallbackAction(
"q2",
"menu:thinking",
reasoningModel,
deps,
),
true,
);
assert.equal(
await handleTelegramStatusMenuCallbackAction(
"q3",
"menu:settings",
reasoningModel,
deps,
),
true,
);
assert.equal(
await handleTelegramStatusMenuCallbackAction(
"q4",
"menu:unknown",
reasoningModel,
deps,
),
false,
);
assert.deepEqual(calls, [
"model",
"answered",
"thinking",
"answered",
"settings",
"answered",
]);
const voiceCalls: string[] = [];
assert.equal(
await handleTelegramStatusMenuCallbackAction(
"q5",
"menu:thinking",
reasoningModel,
{
...deps,
isVoiceReplyActive: () => true,
answerCallbackQuery: async (_id, text) => {
voiceCalls.push(text ?? "");
},
},
),
true,
);
assert.deepEqual(voiceCalls, [
"Thinking controls are disabled during voice replies.",
]);
});
test("Status menu open, send, and update helpers apply status mode", async () => {
const state: any = {
chatId: 1,
threadId: 42,
messageId: 2,
mode: "model" as const,
page: 0,
scope: "all",
scopedModels: [],
allModels: [],
};
const stored: unknown[] = [];
await openTelegramStatusMenu({
isIdle: () => true,
sendBusyMessage: async () => {},
getModelMenuState: async () => state,
buildStatusHtml: () => "<b>Status</b>",
getActiveModel: () => reasoningModel,
getThinkingLevel: () => "medium",
getQueueItemCount: () => 1,
sendStatusMenu: async (_state, html, _model, thinking, queueCount) => {
stored.push({ html, thinking, queueCount });
return 99;
},
storeModelMenuState: (nextState) => stored.push(nextState),
});
assert.equal(state.messageId, 99);
assert.equal(state.mode, "status");
const payload = buildTelegramStatusMenuRenderPayload(
"status html",
reasoningModel,
"medium",
1,
);
assert.equal(payload.nextMode, "status");
assert.equal(payload.mode, "html");
const messages: unknown[] = [];
const deps = {
editInteractiveMessage: async (...args: unknown[]) => {
messages.push(["edit", ...args]);
},
sendInteractiveMessage: async (...args: unknown[]) => {
messages.push(["send", ...args]);
return 123;
},
};
await updateTelegramStatusMessage(
state,
"updated",
reasoningModel,
"medium",
deps,
0,
);
const sentId = await sendTelegramStatusMessage(
state,
"sent",
reasoningModel,
"medium",
deps,
0,
);
assert.equal(sentId, 123);
assert.equal(state.mode, "status");
assert.equal(messages.length, 2);
const sentMessage = messages[1] as unknown[];
assert.equal(sentMessage[0], "send");
assert.equal(sentMessage[1], 1);
assert.equal(sentMessage[3], "html");
assert.deepEqual(sentMessage[5], { target: { chatId: 1, threadId: 42 } });
});