chore: fork @llblab/[email protected].0 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)
This commit is contained in:
commit
d1d04001d0
155 files changed
+107848
No files matched your search
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* Telegram thinking menu UI helpers
|
||||
* Zones: telegram ui, thinking controls, menu composition
|
||||
* Owns thinking-menu text, reply markup, callback handling, and thinking-menu message rendering
|
||||
*/
|
||||
|
||||
import type {
|
||||
TelegramMenuMessageRuntimeDeps,
|
||||
TelegramMenuRenderPayload,
|
||||
TelegramModelMenuState,
|
||||
TelegramReplyMarkup,
|
||||
} from "./menu-model.ts";
|
||||
import {
|
||||
isThinkingLevel,
|
||||
type MenuModel,
|
||||
THINKING_LEVELS,
|
||||
type ThinkingLevel,
|
||||
} from "./model.ts";
|
||||
|
||||
export interface TelegramThinkingMenuCallbackDeps {
|
||||
setThinkingLevel: (level: ThinkingLevel) => void;
|
||||
getCurrentThinkingLevel: () => ThinkingLevel;
|
||||
updateStatusMessage: () => Promise<void>;
|
||||
answerCallbackQuery: (
|
||||
callbackQueryId: string,
|
||||
text?: string,
|
||||
) => Promise<void>;
|
||||
isVoiceReplyActive?: () => boolean;
|
||||
}
|
||||
|
||||
export interface TelegramThinkingMenuOpenDeps<
|
||||
TModel extends MenuModel = MenuModel,
|
||||
> extends TelegramMenuMessageRuntimeDeps {
|
||||
getModelMenuState: () => Promise<TelegramModelMenuState<TModel>>;
|
||||
getActiveModel: () => TModel | undefined;
|
||||
getThinkingLevel: () => ThinkingLevel;
|
||||
storeModelMenuState: (state: TelegramModelMenuState<TModel>) => void;
|
||||
isVoiceReplyActive?: () => boolean;
|
||||
}
|
||||
|
||||
function parseTelegramThinkingMenuCallbackAction(
|
||||
data: string | undefined,
|
||||
): { kind: "thinking:set"; level: string } | undefined {
|
||||
if (!data?.startsWith("thinking:set:")) return undefined;
|
||||
return { kind: "thinking:set", level: data.slice("thinking:set:".length) };
|
||||
}
|
||||
|
||||
function applyTelegramMenuRenderPayload(
|
||||
state: TelegramModelMenuState,
|
||||
payload: TelegramMenuRenderPayload,
|
||||
): TelegramMenuRenderPayload {
|
||||
state.mode = payload.nextMode;
|
||||
return payload;
|
||||
}
|
||||
|
||||
async function editTelegramMenuMessage(
|
||||
state: TelegramModelMenuState,
|
||||
payload: TelegramMenuRenderPayload,
|
||||
deps: TelegramMenuMessageRuntimeDeps,
|
||||
): Promise<void> {
|
||||
const appliedPayload = applyTelegramMenuRenderPayload(state, payload);
|
||||
await deps.editInteractiveMessage(
|
||||
state.chatId,
|
||||
state.messageId,
|
||||
appliedPayload.text,
|
||||
appliedPayload.mode,
|
||||
appliedPayload.replyMarkup,
|
||||
);
|
||||
}
|
||||
|
||||
function sendTelegramMenuMessage(
|
||||
state: TelegramModelMenuState,
|
||||
payload: TelegramMenuRenderPayload,
|
||||
deps: TelegramMenuMessageRuntimeDeps,
|
||||
): Promise<number | undefined> {
|
||||
const appliedPayload = applyTelegramMenuRenderPayload(state, payload);
|
||||
return deps.sendInteractiveMessage(
|
||||
state.chatId,
|
||||
appliedPayload.text,
|
||||
appliedPayload.mode,
|
||||
appliedPayload.replyMarkup,
|
||||
state.threadId !== undefined
|
||||
? { target: { chatId: state.chatId, threadId: state.threadId } }
|
||||
: undefined,
|
||||
);
|
||||
}
|
||||
|
||||
export async function handleTelegramThinkingMenuCallbackAction(
|
||||
callbackQueryId: string,
|
||||
data: string | undefined,
|
||||
activeModel: MenuModel | undefined,
|
||||
deps: TelegramThinkingMenuCallbackDeps,
|
||||
): Promise<boolean> {
|
||||
const action = parseTelegramThinkingMenuCallbackAction(data);
|
||||
if (!action) return false;
|
||||
if (!isThinkingLevel(action.level)) {
|
||||
await deps.answerCallbackQuery(callbackQueryId, "Invalid thinking level.");
|
||||
return true;
|
||||
}
|
||||
if (deps.isVoiceReplyActive?.()) {
|
||||
await deps.answerCallbackQuery(
|
||||
callbackQueryId,
|
||||
"Thinking controls are disabled during voice replies.",
|
||||
);
|
||||
return true;
|
||||
}
|
||||
if (!activeModel?.reasoning) {
|
||||
await deps.answerCallbackQuery(
|
||||
callbackQueryId,
|
||||
"This model has no reasoning controls.",
|
||||
);
|
||||
return true;
|
||||
}
|
||||
deps.setThinkingLevel(action.level);
|
||||
await deps.updateStatusMessage();
|
||||
await deps.answerCallbackQuery(
|
||||
callbackQueryId,
|
||||
`Thinking: ${deps.getCurrentThinkingLevel()}`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
export function buildThinkingMenuText(): string {
|
||||
return "<b>🧠 Choose a thinking level:</b>";
|
||||
}
|
||||
|
||||
export function buildThinkingMenuReplyMarkup(
|
||||
currentThinkingLevel: ThinkingLevel,
|
||||
): TelegramReplyMarkup {
|
||||
const rows = [[{ text: "⬆️ Main menu", callback_data: "menu:back" }]];
|
||||
rows.push(
|
||||
...THINKING_LEVELS.map((level) => [
|
||||
{
|
||||
text: level === currentThinkingLevel ? `🟢 ${level}` : level,
|
||||
callback_data: `thinking:set:${level}`,
|
||||
},
|
||||
]),
|
||||
);
|
||||
return { inline_keyboard: rows };
|
||||
}
|
||||
|
||||
export function buildTelegramThinkingMenuRenderPayload(
|
||||
_activeModel: MenuModel | undefined,
|
||||
currentThinkingLevel: ThinkingLevel,
|
||||
): TelegramMenuRenderPayload {
|
||||
return {
|
||||
nextMode: "thinking",
|
||||
text: buildThinkingMenuText(),
|
||||
mode: "html",
|
||||
replyMarkup: buildThinkingMenuReplyMarkup(currentThinkingLevel),
|
||||
};
|
||||
}
|
||||
|
||||
export async function openTelegramThinkingMenu<
|
||||
TModel extends MenuModel = MenuModel,
|
||||
>(deps: TelegramThinkingMenuOpenDeps<TModel>): Promise<void> {
|
||||
if (deps.isVoiceReplyActive?.()) return;
|
||||
const state = await deps.getModelMenuState();
|
||||
const messageId = await sendTelegramMenuMessage(
|
||||
state,
|
||||
buildTelegramThinkingMenuRenderPayload(
|
||||
deps.getActiveModel(),
|
||||
deps.getThinkingLevel(),
|
||||
),
|
||||
deps,
|
||||
);
|
||||
if (messageId === undefined) return;
|
||||
state.messageId = messageId;
|
||||
state.mode = "thinking";
|
||||
deps.storeModelMenuState(state);
|
||||
}
|
||||
|
||||
export async function updateTelegramThinkingMenuMessage(
|
||||
state: TelegramModelMenuState,
|
||||
activeModel: MenuModel | undefined,
|
||||
currentThinkingLevel: ThinkingLevel,
|
||||
deps: TelegramMenuMessageRuntimeDeps & { isVoiceReplyActive?: () => boolean },
|
||||
): Promise<void> {
|
||||
if (deps.isVoiceReplyActive?.()) return;
|
||||
await editTelegramMenuMessage(
|
||||
state,
|
||||
buildTelegramThinkingMenuRenderPayload(activeModel, currentThinkingLevel),
|
||||
deps,
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user