mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-19 09:01:39 -06:00
da44d52ac6
* feat(gateway): add transient question runtime (question.* methods + broadcasts) * feat(agents): add blocking ask_user question tool with chat prompt delivery and text-reply claim * feat(ui): interactive in-thread question cards for ask_user * feat(channels): native tap-to-answer buttons for ask_user on Telegram, Discord, and Slack * feat(ui): unify codex and gateway question cards with interactive gateway answering * refactor(agents): collapse ask_user pending state to one registry; docs for ask_user * fix(agents): include ask_user in normal gateway runs; add question-flow control-ui e2e * test(ui): avoid credential-shaped fixture in question card test * refactor(ui): reorder stream-group context keys * fix(gateway,ui): validate question answers at resolve; reject secret/duplicate-label questions; UI retry and reconnect hardening * fix(gateway,agents): canonicalize accepted option answers; bound ask_user option labels to 64 chars * chore(ci): prune unused question exports, allowlist mobile question events, fix discord lint * chore(ci): regenerate protocol/i18n/docs/tool-display artifacts for question surface * fix(protocol): flatten QuestionRecord for native codegen; drop TS-only alias from schema registry * chore(android): regenerate ask-user localization resources * docs: regenerate docs map after rebase * fix(ci): avoid stale read-only dependency disks * test: remove stale reef lint suppression ratchet * fix(ci): keep source locale drift advisory in release gates * fix(ci): scope locale advisory handling to parity check
43 lines
1.4 KiB
TypeScript
43 lines
1.4 KiB
TypeScript
// Telegram-private ask_user callback envelope.
|
|
const TELEGRAM_QUESTION_CALLBACK_PREFIX = "tgq1:";
|
|
const TELEGRAM_CALLBACK_DATA_MAX_BYTES = 64;
|
|
const QUESTION_RECORD_ID_PATTERN = /^ask_[a-f0-9]{32}$/u;
|
|
|
|
export type TelegramQuestionCallback = {
|
|
questionId: string;
|
|
optionIndex: number;
|
|
};
|
|
|
|
export function hasTelegramQuestionCallbackPrefix(data?: string | null): boolean {
|
|
return data?.startsWith(TELEGRAM_QUESTION_CALLBACK_PREFIX) === true;
|
|
}
|
|
|
|
export function buildTelegramQuestionCallbackData(
|
|
callback: TelegramQuestionCallback,
|
|
): string | undefined {
|
|
if (
|
|
!QUESTION_RECORD_ID_PATTERN.test(callback.questionId) ||
|
|
!Number.isInteger(callback.optionIndex) ||
|
|
callback.optionIndex < 0 ||
|
|
callback.optionIndex > 3
|
|
) {
|
|
return undefined;
|
|
}
|
|
const data = `${TELEGRAM_QUESTION_CALLBACK_PREFIX}${callback.questionId}:${callback.optionIndex}`;
|
|
return Buffer.byteLength(data, "utf8") <= TELEGRAM_CALLBACK_DATA_MAX_BYTES ? data : undefined;
|
|
}
|
|
|
|
export function parseTelegramQuestionCallbackData(
|
|
data?: string | null,
|
|
): TelegramQuestionCallback | null {
|
|
if (
|
|
!hasTelegramQuestionCallbackPrefix(data) ||
|
|
!data ||
|
|
Buffer.byteLength(data, "utf8") > TELEGRAM_CALLBACK_DATA_MAX_BYTES
|
|
) {
|
|
return null;
|
|
}
|
|
const match = /^tgq1:(ask_[a-f0-9]{32}):([0-3])$/u.exec(data);
|
|
return match?.[1] && match[2] ? { questionId: match[1], optionIndex: Number(match[2]) } : null;
|
|
}
|