Delivery & visibility: - per-chunk retry with capped backoff on rich/HTML sends; rich failure now falls back to HTML instead of dropping the reply - typing heartbeat: refresh sendChatAction every 4s for the whole turn (a single action expires in ~5s, long turns looked dead) - turn/end error / abort / crash-recovery notices reach Telegram (API failures were previously invisible) - tool/call progress summaries, tool/result failure notices, todo progress - thinking indicator (one notice per reasoning phase, status only) - notices prefixed '> ' render as Telegram blockquotes; plain-text fallback - non-text messages get a hint instead of being silently dropped - busy feedback: a followup queued mid-turn gets an explicit ack TG-side answering (dual-path race; UI path untouched, first answer wins): - ask_user_question questions render with letter options on TG; reply A / [A] / A,B (multi) / free text / '1: A' per-line for multi-question - approval requests (approval/request waterfall) answerable from TG: [A] allow once / [B] reject; /cancel closes only the TG side Commands: /stop (cancel current turn), /mission (todo snapshot + busy state), /new (create a session in the current workspace and attach) Persistence: chat→session bindings stored at $DSH_HOME/ telegram-channel-bindings.json (override: DSH_TELEGRAM_BINDINGS_FILE) and restored on start — hot reloads and restarts no longer drop attachments. Host seams without public surface yet are reached with documented structural casts (userQuestions provider wrap, approval/request waterfall). Tests: 41/41 pass. Two pre-existing environment failures in bridge.test.ts (/last history mirror, assistant mirror) now pass: the former was fixed by the rich→HTML fallback, the latter needed an event-loop flush after the (void) listener call since resilient delivery lengthens the chain.
69 lines
2.5 KiB
TypeScript
69 lines
2.5 KiB
TypeScript
export declare const MSG: {
|
|
readonly DENIED: "无权限。";
|
|
readonly WELCOME: string;
|
|
readonly HELP: string;
|
|
readonly NEED_BIND: "尚未绑定本机会话。请先发送 /sessions 选择一个。";
|
|
readonly NO_SESSIONS: "当前没有可附着的本机会话(已排除归档与空白会话)。请先在 Web(dsh web)打开或继续一个对话,再发 /sessions。";
|
|
readonly NO_SESSIONS_IN_WS: (title: string) => string;
|
|
/** @deprecated use NO_SESSIONS */
|
|
readonly NO_LIVE: "当前没有可附着的本机会话。请先在 Web(dsh web)打开或继续一个对话,再发 /sessions。";
|
|
readonly PICKER_STALE: "列表已过期,请重新发送 /sessions。";
|
|
readonly RESUME_FAILED: "无法附着该会话(resume 失败)。请确认会话存在于 Web,或先在电脑打开后再试。";
|
|
readonly BOUND: (label: string) => string;
|
|
readonly UNBOUND: "已断开绑定。本机会话仍在运行。";
|
|
readonly STATUS_NONE: "当前未绑定任何本机会话。发送 /sessions 选择。";
|
|
readonly STATUS_BOUND: (label: string) => string;
|
|
readonly STATUS_BOUND_COLD: (label: string) => string;
|
|
readonly GONE: "绑定的会话已不可用。请重新 /sessions。";
|
|
readonly LAST_FAILED: "无法读取上次对话。请确认已绑定,且本机 dsh web / apiProxy 可用。";
|
|
readonly MODEL_UNAVAILABLE: (detail?: string) => string;
|
|
readonly MODEL_UNROUTABLE: (current: string) => string;
|
|
readonly MODEL_EMPTY: (current: string) => string;
|
|
readonly MODEL_SET: (selected: string) => string;
|
|
readonly MODEL_FAILED: (detail?: string) => string;
|
|
readonly unknown: (command: string) => string;
|
|
};
|
|
export type ParsedCommand = {
|
|
type: 'start';
|
|
text: string;
|
|
} | {
|
|
type: 'help';
|
|
text: string;
|
|
} | {
|
|
type: 'sessions';
|
|
text: string;
|
|
} | {
|
|
type: 'last';
|
|
text: string;
|
|
} | {
|
|
type: 'model';
|
|
text: string;
|
|
} | {
|
|
type: 'status';
|
|
text: string;
|
|
} | {
|
|
type: 'unbind';
|
|
text: string;
|
|
} | {
|
|
type: 'stop';
|
|
text: string;
|
|
} | {
|
|
type: 'mission';
|
|
text: string;
|
|
} | {
|
|
type: 'new';
|
|
text: string;
|
|
} | {
|
|
type: 'unknown';
|
|
command: string;
|
|
text: string;
|
|
} | {
|
|
type: 'plain';
|
|
text: string;
|
|
};
|
|
export declare function parseCommand(text: string): ParsedCommand;
|
|
/** @deprecated Prefer short index callbacks (ws:/sid:); kept for old messages. */
|
|
export declare const BIND_CB_PREFIX = "bind:";
|
|
/** Inline button: fetch last Q/A for the bound session. */
|
|
export declare const LAST_CB = "last";
|