@adriangalilea/utils 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bot/draft.d.ts +88 -0
- package/dist/bot/draft.d.ts.map +1 -0
- package/dist/bot/draft.js +186 -0
- package/dist/bot/draft.js.map +1 -0
- package/dist/bot/index.d.ts +1 -0
- package/dist/bot/index.d.ts.map +1 -1
- package/dist/bot/index.js +1 -0
- package/dist/bot/index.js.map +1 -1
- package/dist/bot/llm.d.ts +6 -79
- package/dist/bot/llm.d.ts.map +1 -1
- package/dist/bot/llm.js +14 -180
- package/dist/bot/llm.js.map +1 -1
- package/dist/tg-md/index.d.ts +73 -0
- package/dist/tg-md/index.d.ts.map +1 -0
- package/dist/tg-md/index.js +246 -0
- package/dist/tg-md/index.js.map +1 -0
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -449,7 +449,7 @@ Then `pnpm install`. Every `ctx.send` / `ctx.sendDocument` / `ctx.reply` / etc.
|
|
|
449
449
|
| `@adriangalilea/utils/bot/user` | `userLabel(u)` — the conditional "[name] [@username] [id]" line every bot re-rolls for admin DMs and logs: `Ada Lovelace (@ada · 42)` / `Ada (42)` / `@ada (42)` / `id 42`, missing pieces drop instead of padding. Reads both gramio spellings (`firstName` / `first_name`); plain text by design. |
|
|
450
450
|
| `@adriangalilea/utils/bot/coalesce` | Joins client-split inbound messages back into one. When a user pastes >4096 chars, Telegram clients fragment it into separate `message` updates with no marker. Middleware detects the burst and emits one combined event. |
|
|
451
451
|
| `@adriangalilea/utils/llm` | Multi-provider LLM caller on the Vercel AI SDK — the policy layer the SDK doesn't ship. `createLlm({ providers, health? })` → `.stream(req)` (typed events: `delta` / `reasoning` / `reset` / `tool-call` / `end`) and `.complete(req)`. **Failover:** priority-ordered across OpenAI-compatible, Anthropic-compatible, and OpenRouter endpoints; multiple keys per provider (health tracked per key fingerprint); per-key circuit breaker with exponential cool-down persisted in any KV-shaped `HealthStore`; an attempt that dies after emitting yields `reset` (discard, next candidate regenerates); empty completions count as failures. **Accounting:** tokens summed across billed attempts; `costUsd` is the ACTUAL charge (OpenRouter usage accounting via `providerMetadata`, or a `cost` field on the raw usage frame) — never a price-table estimate. **Knobs:** per-model temperature, maxTokens caps, `disableThinking` mapped to each dialect. **Tools:** AI SDK `tool()` + `toolChoice` pass through (re-exported). Worker-safe; peers: `ai`, `@ai-sdk/openai-compatible`, `@ai-sdk/anthropic`, `@openrouter/ai-sdk-provider`. |
|
|
452
|
-
| `@adriangalilea/utils/bot/llm` | The Telegram side of an LLM chatbot; the model side is `@adriangalilea/utils/llm`. **Output:** `streamChatReply(ctx, events, opts?)` consumes an `AsyncIterable<LlmStreamEvent>` and paints it with Telegram's native message-draft streaming (`sendMessageDraft` full-frame repaints, throttled ~1/s, keepalive under the ~30s draft TTL), then persists the finished markdown via `ctx.send`, entity-split across 4096 by `@gramio/split`. Reasoning models get a thinking phase — streams into the ephemeral draft and evaporates (`reasoning: 'preview'`, default), persists as an expandable blockquote (`'message'`), or never renders (`'hidden'`). Upstream `reset` (provider failover) repaints the draft from scratch. Drafts are private-chat-only (+ BotFather forum-topic mode); elsewhere the preview phase is skipped and only the final send happens. Returns `{ content, reasoning, toolCalls, usage, messages }`. `createDraftPreview(ctx, { render
|
|
452
|
+
| `@adriangalilea/utils/bot/llm` | The Telegram side of an LLM chatbot; the model side is `@adriangalilea/utils/llm`. **Output:** `streamChatReply(ctx, events, opts?)` consumes an `AsyncIterable<LlmStreamEvent>` and paints it with Telegram's native message-draft streaming (`sendMessageDraft` full-frame repaints, throttled ~1/s, keepalive under the ~30s draft TTL), then persists the finished markdown via `ctx.send`, entity-split across 4096 by `@gramio/split`. Reasoning models get a thinking phase — streams into the ephemeral draft and evaporates (`reasoning: 'preview'`, default), persists as an expandable blockquote (`'message'`), or never renders (`'hidden'`). Upstream `reset` (provider failover) repaints the draft from scratch. Drafts are private-chat-only (+ BotFather forum-topic mode); elsewhere the preview phase is skipped and only the final send happens. Returns `{ content, reasoning, toolCalls, usage, messages }`. The painter underneath is `@adriangalilea/utils/bot/draft` (`createDraftPreview(ctx, { render, throttleMs? })`): dependency-light (no markdown machinery), for producers that push deltas or own their per-frame rendering (plain or rich-message frames) and persist path, with `streamForensics` (render-regression + reset warnings) built in and exported standalone. **History:** `llmHistory({...})` returns `.plugin` (decorates `ctx.llm` with `.add() / .get() / .clear() / .all() / .clearAll()`, per-(user, thread) OpenAI `ChatMessage` shape, persisted in the shared session record so the menu's 🗑 Forget wipes it automatically) AND `.menuItem` (drop-in "🗑 Delete this thread" for `botMenu` — wipes the LLM history AND calls `deleteForumTopic` so the Telegram thread + all its messages disappear from the chat; falls back to history-only clear when no `threadId` is present). |
|
|
453
453
|
| `@adriangalilea/utils/bot/menu` | `botMenu({ command, description, items, privacy?, personalData?, adminContact })` — `/settings` command + InlineKeyboard router. Root view always renders a `🛡️ Privacy & data` submenu button that wraps the privacy policy link plus (if `personalData: { storage }`) 🗑 Forget + 📥 Export buttons. Items take `keepRow` (render on the same row as the next item — e.g. a two-per-row language picker) and `rootExtra` (render at the bottom of the root menu, below Privacy & data). `label` / `header` / `style` / `visible` resolvers may be **async** (read your db at render time — never cache render strings in the session); `parseMode: 'HTML'` renders the header formatted (you own escaping); `personalData.onForget(ctx, userId)` wipes YOUR tables inside the same try as the session delete, so Forget either forgets everything or reports failure. `toggleMenuItem({ id, read, write, label: { off, on }, toast? })` — convenience factory for boolean-toggle items with dynamic label + optional toast, storage-agnostic via `read`/`write` closures. |
|
|
454
454
|
| `@adriangalilea/utils/bot/payments` | `botPayments({ session, storage, paysupport, paysupportHint?, legal, waiver, vip?, credits?, perks? })` — Telegram Stars monetization in one drop-in plugin. **Three axes, all optional:** `vip` (positional tier ladder — single rung in v1 is just `vip: [{...}]`, ladder is `vip: [{...}, {...}]`; ids are `vip.1`, `vip.2`, …), `credits` (consumable balance + top-up packs `credits.1`, `credits.2`, …), `perks` (orthogonal one-shot unlocks `perks.<key>`). **Surface:** `ctx.payments.atLeast('vip')` / `atLeast('vip.2')` (typed rank check), `ctx.payments.tier()` / `.tier.level()` / `.tier.label()`, `ctx.payments.credits.{balance, consume, tryConsume}` (throws `InsufficientCredits`), `ctx.payments.has(perkId)`, `await ctx.payments.require('vip', { feature? })` (gate that sends a localized upgrade prompt deep-linked to `/settings → 💎 VIP`), `await ctx.payments.invoice(productKey)` (threads Art. 103(m) TRLGDCU consent inline before `sendInvoice`). **Owns:** waiver consent flow (versioned text → forces re-consent on bump, snapshotted on every charge for audit), `/paysupport` slash command (Telegram ToS §6.5; `paysupportHint` overrides the where-to-manage-charges line when your menu isn't `/settings`), idempotent `successful_payment` fulfillment via `pay:idempotency:{chargeId}` sentinel, lazy subscription expiry (no cron needed), tier upgrade auto-cancel of the lower rung's renewal, and admin-DM refund approval (mirror of `accessControl`'s [✅ Aprobar][❌ Denegar] pattern). **Returns:** `{ plugin, menuItem, payouts, onFulfilled }` — `menuItem` is the drop-in `💎 VIP` entry for `botMenu`; `payouts.{record, list, export, exportForUsers}` is the Fragment payout ledger (you receive TON, log the EUR conversion, export time-windowed CSV/JSON for your gestor); `onFulfilled(productKey \| '*', handler)` / `onRefunded(...)` register fire-and-forget hooks (purchase applied / admin-approved refund — a revenue ledger writes on one, reverses on the other). **Stars-only by design** — Telegram ToS §6.2 forbids third-party payment providers for digital goods. Crypto Pay deferred (MiCA risk); Stripe-outside-Telegram is a future v2 channel. Full compliance memo (Spanish-autónomo seller-of-record analysis, Verifactu vs Crea y Crece, MiCA, Art. 103(m) waiver text, GDPR retention) in `src/bot/payments/CLAUDE.md`. |
|
|
455
455
|
| `@adriangalilea/utils/bot/create` | `createBot<S>({ token?, storage?, initial?, admins?, language?, menu?, access?, payments?, handlers?, worker? })` — the composer (see "One bot file, ideation → production" above). Returns `{ build, session, poll, isMain, fetch }`: `poll()` long-polls, `export default app` is a complete Worker, `app.session(ctx)` / the `handlers` callback's `session(ctx)` is the TYPED accessor for your `S` fields. Owns storage+session wiring; resolves storage per environment (D1 binding → `bot/storage-d1`; `BOT_PERSIST` path → sqlite, `redis://` → redis, lazily-imported optional peers; else announced-ephemeral memory) — or pass `storage: (env) => Storage` when the choice is env-dependent (e.g. a D1 binding not named `DB`). Boot NARRATES the composition (`session: memory …`, `features: language(en,es) · menu(/settings)`) so every implicit decision is visible where you're looking. Runnable demo: `pnpm demo:bot`. |
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram message-draft painter — the lifecycle primitive under
|
|
3
|
+
* `bot/llm`'s `streamChatReply`, dependency-light on purpose (gramio types +
|
|
4
|
+
* `@gramio/format` types only) so a bot with its own rendering pipeline pulls
|
|
5
|
+
* no markdown machinery into its bundle.
|
|
6
|
+
*
|
|
7
|
+
* `createDraftPreview(ctx, { render, throttleMs? })` owns the whole draft
|
|
8
|
+
* lifecycle: throttled FULL-FRAME repaints (drafts replace, never append),
|
|
9
|
+
* the anti-expiry keepalive under Telegram's ~30s draft TTL, serialized
|
|
10
|
+
* sends, reset, quiesce, and {@link streamForensics} (render-regression +
|
|
11
|
+
* upstream-reset warnings, also exported standalone for edit-based viewers).
|
|
12
|
+
* `render` is required: a painter doesn't know markdown — it paints whatever
|
|
13
|
+
* frame you render, plain (`sendMessageDraft`) or rich (`sendRichMessageDraft`).
|
|
14
|
+
* Previews exist in PRIVATE chats only; elsewhere every method no-ops.
|
|
15
|
+
*/
|
|
16
|
+
import type { FormattableString } from "@gramio/format";
|
|
17
|
+
import type { Bot, MessageContext } from "gramio";
|
|
18
|
+
/**
|
|
19
|
+
* Jitter forensics for a streamed preview: a healthy stream only GROWS. A
|
|
20
|
+
* render that shrinks while the accumulated markdown grew means the
|
|
21
|
+
* partial-markdown tail parsed differently between frames (the renderer);
|
|
22
|
+
* accumulated text shrinking is an upstream provider reset. Neither warning
|
|
23
|
+
* firing while a user still sees back-and-forth points at their CLIENT's own
|
|
24
|
+
* draft rendering. Built into {@link createDraftPreview}; exported standalone
|
|
25
|
+
* for edit-based viewers that repaint outside the painter.
|
|
26
|
+
*/
|
|
27
|
+
export declare function streamForensics(label: string): {
|
|
28
|
+
/** Call per outgoing frame with the accumulated-markdown and rendered lengths. */
|
|
29
|
+
frame(accLen: number, renderedLen: number): void;
|
|
30
|
+
/** Call from the upstream reset path with the length being dropped. */
|
|
31
|
+
reset(droppedChars: number): void;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* One rendered preview frame. `text` goes out via `sendMessageDraft` (a
|
|
35
|
+
* FormattableString carries entities; a raw string may carry `parseMode`);
|
|
36
|
+
* `rich` goes out via `sendRichMessageDraft` (Telegram's rich-message HTML).
|
|
37
|
+
*/
|
|
38
|
+
export type DraftFrame = {
|
|
39
|
+
kind: "text";
|
|
40
|
+
text: string | FormattableString;
|
|
41
|
+
parseMode?: "HTML" | "MarkdownV2" | "Markdown";
|
|
42
|
+
} | {
|
|
43
|
+
kind: "rich";
|
|
44
|
+
html: string;
|
|
45
|
+
};
|
|
46
|
+
export interface DraftPreviewOptions {
|
|
47
|
+
/** Ms between repaints. Default 1000. */
|
|
48
|
+
throttleMs?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Render one FULL frame from the accumulated markdown — drafts replace,
|
|
51
|
+
* never append, which is what makes resets and phase switches one cheap
|
|
52
|
+
* frame. Return null to skip (nothing renderable yet).
|
|
53
|
+
*/
|
|
54
|
+
render: (markdown: string) => DraftFrame | null;
|
|
55
|
+
/** Forensics label. Default `draft <id>`. */
|
|
56
|
+
label?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A live message-draft preview: the push-driven primitive under
|
|
60
|
+
* {@link streamChatReply}, exposed for callers whose producer pushes deltas
|
|
61
|
+
* (rather than handing over an event iterable) or whose render/persist paths
|
|
62
|
+
* are their own. Owns the whole draft lifecycle: throttled full-frame
|
|
63
|
+
* repaints, the anti-expiry keepalive, serialized sends, reset, and quiesce.
|
|
64
|
+
* Previews exist in PRIVATE chats only — elsewhere every method no-ops and
|
|
65
|
+
* the caller's persist path is all that happens.
|
|
66
|
+
*/
|
|
67
|
+
export interface DraftPreview {
|
|
68
|
+
/** Accumulated markdown of the current attempt. */
|
|
69
|
+
readonly text: string;
|
|
70
|
+
/** Append a delta and schedule a repaint. */
|
|
71
|
+
append(text: string): void;
|
|
72
|
+
/** Replace the buffer (phase switches); schedules a repaint. */
|
|
73
|
+
set(markdown: string): void;
|
|
74
|
+
/** Upstream failover: drop the buffer with a forensics note; the next tokens repaint from scratch. */
|
|
75
|
+
reset(): void;
|
|
76
|
+
/** Force a repaint of the current frame (render inputs changed, e.g. a cover arrived). */
|
|
77
|
+
repaint(): void;
|
|
78
|
+
/**
|
|
79
|
+
* Paint one last complete frame and stop. Call right before persisting:
|
|
80
|
+
* the preview shows the finished text (not a throttle-stale partial) and
|
|
81
|
+
* its ~30s TTL resets, so the handoff to the real message can't blank.
|
|
82
|
+
*/
|
|
83
|
+
finish(markdown?: string): Promise<void>;
|
|
84
|
+
/** Stop painting without a final frame; the ephemeral draft expires on its own. */
|
|
85
|
+
abort(): Promise<void>;
|
|
86
|
+
}
|
|
87
|
+
export declare function createDraftPreview(ctx: MessageContext<Bot>, opts: DraftPreviewOptions): DraftPreview;
|
|
88
|
+
//# sourceMappingURL=draft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/bot/draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAelD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM;IAI3C,kFAAkF;kBACpE,MAAM,eAAe,MAAM;IAQzC,uEAAuE;wBACnD,MAAM;EAM3B;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GACnB;IACA,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,UAAU,CAAC;CAC9C,GACD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC,MAAM,WAAW,mBAAmB;IACnC,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,UAAU,GAAG,IAAI,CAAC;IAChD,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC5B,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gEAAgE;IAChE,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,sGAAsG;IACtG,KAAK,IAAI,IAAI,CAAC;IACd,0FAA0F;IAC1F,OAAO,IAAI,IAAI,CAAC;IAChB;;;;OAIG;IACH,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,mFAAmF;IACnF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,wBAAgB,kBAAkB,CACjC,GAAG,EAAE,cAAc,CAAC,GAAG,CAAC,EACxB,IAAI,EAAE,mBAAmB,GACvB,YAAY,CA8Hd"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram message-draft painter — the lifecycle primitive under
|
|
3
|
+
* `bot/llm`'s `streamChatReply`, dependency-light on purpose (gramio types +
|
|
4
|
+
* `@gramio/format` types only) so a bot with its own rendering pipeline pulls
|
|
5
|
+
* no markdown machinery into its bundle.
|
|
6
|
+
*
|
|
7
|
+
* `createDraftPreview(ctx, { render, throttleMs? })` owns the whole draft
|
|
8
|
+
* lifecycle: throttled FULL-FRAME repaints (drafts replace, never append),
|
|
9
|
+
* the anti-expiry keepalive under Telegram's ~30s draft TTL, serialized
|
|
10
|
+
* sends, reset, quiesce, and {@link streamForensics} (render-regression +
|
|
11
|
+
* upstream-reset warnings, also exported standalone for edit-based viewers).
|
|
12
|
+
* `render` is required: a painter doesn't know markdown — it paints whatever
|
|
13
|
+
* frame you render, plain (`sendMessageDraft`) or rich (`sendRichMessageDraft`).
|
|
14
|
+
* Previews exist in PRIVATE chats only; elsewhere every method no-ops.
|
|
15
|
+
*/
|
|
16
|
+
// Telegram animates draft repaints; one frame per second is smooth and stays
|
|
17
|
+
// clear of rate limits.
|
|
18
|
+
const THROTTLE_MS = 1000;
|
|
19
|
+
// A streamed draft is ephemeral: Telegram drops it after ~30s. A quiet stretch
|
|
20
|
+
// (LLM latency, an upstream failover) sends no frames, so the preview would
|
|
21
|
+
// age out mid-generation. Re-emit the current frame comfortably under the TTL.
|
|
22
|
+
const KEEPALIVE_MS = 20_000;
|
|
23
|
+
// Non-zero, ever-incrementing draft id per stream so a chat's concurrent /
|
|
24
|
+
// sequential previews don't share an animation timeline. Per-isolate;
|
|
25
|
+
// collisions across isolates are harmless (draft ids are chat-scoped).
|
|
26
|
+
let draftSeq = 0;
|
|
27
|
+
/**
|
|
28
|
+
* Jitter forensics for a streamed preview: a healthy stream only GROWS. A
|
|
29
|
+
* render that shrinks while the accumulated markdown grew means the
|
|
30
|
+
* partial-markdown tail parsed differently between frames (the renderer);
|
|
31
|
+
* accumulated text shrinking is an upstream provider reset. Neither warning
|
|
32
|
+
* firing while a user still sees back-and-forth points at their CLIENT's own
|
|
33
|
+
* draft rendering. Built into {@link createDraftPreview}; exported standalone
|
|
34
|
+
* for edit-based viewers that repaint outside the painter.
|
|
35
|
+
*/
|
|
36
|
+
export function streamForensics(label) {
|
|
37
|
+
let lastAccLen = 0;
|
|
38
|
+
let lastRenderedLen = 0;
|
|
39
|
+
return {
|
|
40
|
+
/** Call per outgoing frame with the accumulated-markdown and rendered lengths. */
|
|
41
|
+
frame(accLen, renderedLen) {
|
|
42
|
+
if (renderedLen < lastRenderedLen && accLen >= lastAccLen)
|
|
43
|
+
console.warn(`[bot/llm] ${label} render regressed · rendered ${lastRenderedLen}→${renderedLen} · acc ${accLen}`);
|
|
44
|
+
lastAccLen = accLen;
|
|
45
|
+
lastRenderedLen = renderedLen;
|
|
46
|
+
},
|
|
47
|
+
/** Call from the upstream reset path with the length being dropped. */
|
|
48
|
+
reset(droppedChars) {
|
|
49
|
+
console.warn(`[bot/llm] ${label} reset (provider failover) · dropped ${droppedChars} chars`);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function createDraftPreview(ctx, opts) {
|
|
54
|
+
const active = ctx.chat.type === "private";
|
|
55
|
+
const chatId = ctx.chat.id;
|
|
56
|
+
const threadId = ctx.threadId;
|
|
57
|
+
const draftId = ++draftSeq;
|
|
58
|
+
const throttle = opts.throttleMs ?? THROTTLE_MS;
|
|
59
|
+
const render = opts.render;
|
|
60
|
+
const forensics = streamForensics(opts.label ?? `draft ${draftId}`);
|
|
61
|
+
let acc = "";
|
|
62
|
+
let dirty = false;
|
|
63
|
+
let stopped = !active;
|
|
64
|
+
let lastFlushAt = 0;
|
|
65
|
+
let timer;
|
|
66
|
+
let flushing;
|
|
67
|
+
let keepalive;
|
|
68
|
+
// Send the current accumulated markdown as one full frame. Best-effort: a
|
|
69
|
+
// rejected preview (rate limit, empty render) is swallowed — the caller's
|
|
70
|
+
// persist path is what matters.
|
|
71
|
+
const sendFrame = async () => {
|
|
72
|
+
const frame = render(acc);
|
|
73
|
+
if (frame === null)
|
|
74
|
+
return;
|
|
75
|
+
if (frame.kind === "rich") {
|
|
76
|
+
forensics.frame(acc.length, frame.html.length);
|
|
77
|
+
await ctx.bot.api
|
|
78
|
+
.sendRichMessageDraft({
|
|
79
|
+
chat_id: chatId,
|
|
80
|
+
draft_id: draftId,
|
|
81
|
+
rich_message: { html: frame.html },
|
|
82
|
+
...(threadId !== undefined ? { message_thread_id: threadId } : {}),
|
|
83
|
+
})
|
|
84
|
+
.catch(() => { });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const rendered = typeof frame.text === "string" ? frame.text : frame.text.text;
|
|
88
|
+
forensics.frame(acc.length, rendered.length);
|
|
89
|
+
await ctx.bot.api
|
|
90
|
+
.sendMessageDraft({
|
|
91
|
+
chat_id: chatId,
|
|
92
|
+
draft_id: draftId,
|
|
93
|
+
text: frame.text,
|
|
94
|
+
...(frame.parseMode ? { parse_mode: frame.parseMode } : {}),
|
|
95
|
+
...(threadId !== undefined ? { message_thread_id: threadId } : {}),
|
|
96
|
+
})
|
|
97
|
+
.catch(() => { });
|
|
98
|
+
};
|
|
99
|
+
const flush = async () => {
|
|
100
|
+
if (!dirty || stopped)
|
|
101
|
+
return;
|
|
102
|
+
if (flushing)
|
|
103
|
+
await flushing.catch(() => { });
|
|
104
|
+
if (!dirty || stopped)
|
|
105
|
+
return;
|
|
106
|
+
dirty = false;
|
|
107
|
+
lastFlushAt = Date.now();
|
|
108
|
+
flushing = sendFrame();
|
|
109
|
+
await flushing.catch(() => { });
|
|
110
|
+
flushing = undefined;
|
|
111
|
+
if (dirty && !stopped)
|
|
112
|
+
schedule();
|
|
113
|
+
};
|
|
114
|
+
const schedule = () => {
|
|
115
|
+
dirty = true;
|
|
116
|
+
if (stopped || timer)
|
|
117
|
+
return;
|
|
118
|
+
const wait = Math.max(0, throttle - (Date.now() - lastFlushAt));
|
|
119
|
+
timer = setTimeout(() => {
|
|
120
|
+
timer = undefined;
|
|
121
|
+
void flush();
|
|
122
|
+
}, wait);
|
|
123
|
+
};
|
|
124
|
+
// Start the anti-expiry heartbeat once streaming has actually begun. Each
|
|
125
|
+
// tick reuses the normal flush path to re-paint the current frame, but only
|
|
126
|
+
// when the stream has gone quiet — an in-flight or pending flush already
|
|
127
|
+
// refreshes the draft.
|
|
128
|
+
const ensureKeepalive = () => {
|
|
129
|
+
if (keepalive || stopped)
|
|
130
|
+
return;
|
|
131
|
+
keepalive = setInterval(() => {
|
|
132
|
+
if (stopped || dirty || timer || flushing || !acc.trim())
|
|
133
|
+
return;
|
|
134
|
+
schedule();
|
|
135
|
+
}, KEEPALIVE_MS);
|
|
136
|
+
};
|
|
137
|
+
// Stop scheduling and let any in-flight frame settle. Shared by finish and abort.
|
|
138
|
+
const quiesce = async () => {
|
|
139
|
+
stopped = true;
|
|
140
|
+
if (timer) {
|
|
141
|
+
clearTimeout(timer);
|
|
142
|
+
timer = undefined;
|
|
143
|
+
}
|
|
144
|
+
if (keepalive) {
|
|
145
|
+
clearInterval(keepalive);
|
|
146
|
+
keepalive = undefined;
|
|
147
|
+
}
|
|
148
|
+
if (flushing)
|
|
149
|
+
await flushing.catch(() => { });
|
|
150
|
+
};
|
|
151
|
+
return {
|
|
152
|
+
get text() {
|
|
153
|
+
return acc;
|
|
154
|
+
},
|
|
155
|
+
append(text) {
|
|
156
|
+
if (stopped)
|
|
157
|
+
return;
|
|
158
|
+
acc += text;
|
|
159
|
+
ensureKeepalive();
|
|
160
|
+
schedule();
|
|
161
|
+
},
|
|
162
|
+
set(markdown) {
|
|
163
|
+
acc = markdown;
|
|
164
|
+
if (!stopped)
|
|
165
|
+
schedule();
|
|
166
|
+
},
|
|
167
|
+
reset() {
|
|
168
|
+
forensics.reset(acc.length);
|
|
169
|
+
acc = "";
|
|
170
|
+
},
|
|
171
|
+
repaint() {
|
|
172
|
+
if (!stopped && acc.trim())
|
|
173
|
+
schedule();
|
|
174
|
+
},
|
|
175
|
+
async finish(markdown) {
|
|
176
|
+
if (markdown !== undefined)
|
|
177
|
+
acc = markdown;
|
|
178
|
+
const wasActive = !stopped;
|
|
179
|
+
await quiesce();
|
|
180
|
+
if (wasActive)
|
|
181
|
+
await sendFrame().catch(() => { });
|
|
182
|
+
},
|
|
183
|
+
abort: quiesce,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=draft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draft.js","sourceRoot":"","sources":["../../src/bot/draft.ts"],"names":[],"mappings":"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"}
|
package/dist/bot/index.d.ts
CHANGED
package/dist/bot/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
|
package/dist/bot/index.js
CHANGED
package/dist/bot/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
|
package/dist/bot/llm.d.ts
CHANGED
|
@@ -17,13 +17,12 @@
|
|
|
17
17
|
* mode enabled in BotFather); elsewhere the preview phase is skipped and
|
|
18
18
|
* only the final send happens.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* {@link streamForensics} (also exported standalone).
|
|
20
|
+
* The draft LIFECYCLE (throttle, anti-expiry keepalive, serialized
|
|
21
|
+
* full-frame sends, reset, quiesce, forensics) is `bot/draft`'s
|
|
22
|
+
* `createDraftPreview` — dependency-light on purpose; import it from
|
|
23
|
+
* there when your producer pushes deltas or your rendering / persist
|
|
24
|
+
* paths are your own. This module supplies the markdown render and the
|
|
25
|
+
* split-send persist on top.
|
|
27
26
|
*
|
|
28
27
|
* `ctx.llm.add / .get / …` — HISTORY. Per-(user, thread) conversation
|
|
29
28
|
* buffer in OpenAI `ChatMessage` shape, persisted in the shared
|
|
@@ -49,83 +48,11 @@
|
|
|
49
48
|
* ctx.llm.add({ role: 'assistant', content })
|
|
50
49
|
* })
|
|
51
50
|
*/
|
|
52
|
-
import { type FormattableString } from "@gramio/format";
|
|
53
51
|
import type { session } from "@gramio/session";
|
|
54
52
|
import { type Bot, type DeriveDefinitions, type MessageContext, Plugin } from "gramio";
|
|
55
53
|
import type { LlmStreamEvent, LlmToolCall, LlmUsage, ModelMessage } from "../llm/index.js";
|
|
56
54
|
import type { Polyglot } from "../say/index.js";
|
|
57
55
|
import type { MenuItem } from "./menu.js";
|
|
58
|
-
/**
|
|
59
|
-
* Jitter forensics for a streamed preview: a healthy stream only GROWS. A
|
|
60
|
-
* render that shrinks while the accumulated markdown grew means the
|
|
61
|
-
* partial-markdown tail parsed differently between frames (the renderer);
|
|
62
|
-
* accumulated text shrinking is an upstream provider reset. Neither warning
|
|
63
|
-
* firing while a user still sees back-and-forth points at their CLIENT's own
|
|
64
|
-
* draft rendering. Built into {@link createDraftPreview}; exported standalone
|
|
65
|
-
* for edit-based viewers that repaint outside the painter.
|
|
66
|
-
*/
|
|
67
|
-
export declare function streamForensics(label: string): {
|
|
68
|
-
/** Call per outgoing frame with the accumulated-markdown and rendered lengths. */
|
|
69
|
-
frame(accLen: number, renderedLen: number): void;
|
|
70
|
-
/** Call from the upstream reset path with the length being dropped. */
|
|
71
|
-
reset(droppedChars: number): void;
|
|
72
|
-
};
|
|
73
|
-
/**
|
|
74
|
-
* One rendered preview frame. `text` goes out via `sendMessageDraft` (a
|
|
75
|
-
* FormattableString carries entities; a raw string may carry `parseMode`);
|
|
76
|
-
* `rich` goes out via `sendRichMessageDraft` (Telegram's rich-message HTML).
|
|
77
|
-
*/
|
|
78
|
-
export type DraftFrame = {
|
|
79
|
-
kind: "text";
|
|
80
|
-
text: string | FormattableString;
|
|
81
|
-
parseMode?: "HTML" | "MarkdownV2" | "Markdown";
|
|
82
|
-
} | {
|
|
83
|
-
kind: "rich";
|
|
84
|
-
html: string;
|
|
85
|
-
};
|
|
86
|
-
export interface DraftPreviewOptions {
|
|
87
|
-
/** Ms between repaints. Default 1000. */
|
|
88
|
-
throttleMs?: number;
|
|
89
|
-
/**
|
|
90
|
-
* Render one FULL frame from the accumulated markdown — drafts replace,
|
|
91
|
-
* never append, which is what makes resets and phase switches one cheap
|
|
92
|
-
* frame. Return null to skip (nothing renderable yet). Default:
|
|
93
|
-
* `markdownToFormattable`.
|
|
94
|
-
*/
|
|
95
|
-
render?: (markdown: string) => DraftFrame | null;
|
|
96
|
-
/** Forensics label. Default `draft <id>`. */
|
|
97
|
-
label?: string;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* A live message-draft preview: the push-driven primitive under
|
|
101
|
-
* {@link streamChatReply}, exposed for callers whose producer pushes deltas
|
|
102
|
-
* (rather than handing over an event iterable) or whose render/persist paths
|
|
103
|
-
* are their own. Owns the whole draft lifecycle: throttled full-frame
|
|
104
|
-
* repaints, the anti-expiry keepalive, serialized sends, reset, and quiesce.
|
|
105
|
-
* Previews exist in PRIVATE chats only — elsewhere every method no-ops and
|
|
106
|
-
* the caller's persist path is all that happens.
|
|
107
|
-
*/
|
|
108
|
-
export interface DraftPreview {
|
|
109
|
-
/** Accumulated markdown of the current attempt. */
|
|
110
|
-
readonly text: string;
|
|
111
|
-
/** Append a delta and schedule a repaint. */
|
|
112
|
-
append(text: string): void;
|
|
113
|
-
/** Replace the buffer (phase switches); schedules a repaint. */
|
|
114
|
-
set(markdown: string): void;
|
|
115
|
-
/** Upstream failover: drop the buffer with a forensics note; the next tokens repaint from scratch. */
|
|
116
|
-
reset(): void;
|
|
117
|
-
/** Force a repaint of the current frame (render inputs changed, e.g. a cover arrived). */
|
|
118
|
-
repaint(): void;
|
|
119
|
-
/**
|
|
120
|
-
* Paint one last complete frame and stop. Call right before persisting:
|
|
121
|
-
* the preview shows the finished text (not a throttle-stale partial) and
|
|
122
|
-
* its ~30s TTL resets, so the handoff to the real message can't blank.
|
|
123
|
-
*/
|
|
124
|
-
finish(markdown?: string): Promise<void>;
|
|
125
|
-
/** Stop painting without a final frame; the ephemeral draft expires on its own. */
|
|
126
|
-
abort(): Promise<void>;
|
|
127
|
-
}
|
|
128
|
-
export declare function createDraftPreview(ctx: MessageContext<Bot>, opts?: DraftPreviewOptions): DraftPreview;
|
|
129
56
|
export interface StreamChatReplyOptions {
|
|
130
57
|
/**
|
|
131
58
|
* What happens to a reasoning model's thinking text.
|
package/dist/bot/llm.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/bot/llm.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/bot/llm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EACN,KAAK,GAAG,EACR,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,MAAM,EACN,MAAM,QAAQ,CAAC;AAEhB,OAAO,KAAK,EACX,cAAc,EACd,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAI1C,MAAM,WAAW,sBAAsB;IACtC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC7C,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,aAAa,CAAC,EAAE,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,eAAe;IAC/B,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,qEAAqE;IACrE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,wGAAwG;IACxG,QAAQ,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACpC,GAAG,EAAE,cAAc,CAAC,GAAG,CAAC,EACxB,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,EACrC,IAAI,GAAE,sBAA2B,GAC/B,OAAO,CAAC,eAAe,CAAC,CA+E1B;AAeD;;;;GAIG;AACH,MAAM,MAAM,WAAW,GACpB,MAAM,GACN,KAAK,CACH;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAClD,CAAC;AAEL;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IACzB,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,WAAW,CAAC;IACrB,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC,GACjC,YAAY,EAAE,CAqBhB;AAUD,qEAAqE;AACrE,KAAK,UAAU,GAAG;IACjB,MAAM,EAAE;QAAE,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CAAA;KAAE,CAAC;CAC/C,CAAC;AAEF,sEAAsE;AACtE,KAAK,cAAc,GAAG;IAAE,GAAG,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC;AAE3C,wEAAwE;AACxE,KAAK,mBAAmB,GAAG,UAAU,CACpC,OAAO,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC,CACzC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B;;;OAGG;IACH,OAAO,EAAE,mBAAmB,CAAC;IAC7B,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,UAAU,CAAC,EAAE;QACZ,2FAA2F;QAC3F,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QACxB;;;;WAIG;QACH,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3B;;;;;;;WAOG;QACH,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,yEAAyE;QACzE,aAAa,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;KACjC,CAAC;CACF,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,MAAM,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;IAC9C;;;;;;;;OAQG;IACH,QAAQ,EAAE,QAAQ,CAAC;CACnB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG;IAC3B,wDAAwD;IACxD,GAAG,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACtE,2DAA2D;IAC3D,GAAG,EAAE,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;IACtC,uCAAuC;IACvC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB;;;OAGG;IACH,GAAG,EAAE,MAAM,QAAQ,CAAC;QAAE,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,WAAW,CAAC,CAAA;KAAE,CAAC,CAAC;IACzE,sCAAsC;IACtC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,KAAK,iBAAiB,GAAG;IAAE,GAAG,EAAE,aAAa,CAAA;CAAE,CAAC;AAoChD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,iBAAiB,KAAG,iBA4GpD,CAAC;AAEF,QAAA,MAAM,kBAAkB,GAAI,MAAM;IACjC,aAAa,EAAE,mBAAmB,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACtB;YAK+B,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA4ChD,CAAC"}
|
package/dist/bot/llm.js
CHANGED
|
@@ -17,13 +17,12 @@
|
|
|
17
17
|
* mode enabled in BotFather); elsewhere the preview phase is skipped and
|
|
18
18
|
* only the final send happens.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* {@link streamForensics} (also exported standalone).
|
|
20
|
+
* The draft LIFECYCLE (throttle, anti-expiry keepalive, serialized
|
|
21
|
+
* full-frame sends, reset, quiesce, forensics) is `bot/draft`'s
|
|
22
|
+
* `createDraftPreview` — dependency-light on purpose; import it from
|
|
23
|
+
* there when your producer pushes deltas or your rendering / persist
|
|
24
|
+
* paths are your own. This module supplies the markdown render and the
|
|
25
|
+
* split-send persist on top.
|
|
27
26
|
*
|
|
28
27
|
* `ctx.llm.add / .get / …` — HISTORY. Per-(user, thread) conversation
|
|
29
28
|
* buffer in OpenAI `ChatMessage` shape, persisted in the shared
|
|
@@ -53,178 +52,7 @@ import { expandableBlockquote } from "@gramio/format";
|
|
|
53
52
|
import { markdownToFormattable } from "@gramio/format/markdown";
|
|
54
53
|
import { splitMessage } from "@gramio/split";
|
|
55
54
|
import { Plugin, } from "gramio";
|
|
56
|
-
|
|
57
|
-
// Telegram animates draft repaints; one frame per second is smooth and stays
|
|
58
|
-
// clear of rate limits.
|
|
59
|
-
const THROTTLE_MS = 1000;
|
|
60
|
-
// A streamed draft is ephemeral: Telegram drops it after ~30s. A quiet stretch
|
|
61
|
-
// (LLM latency, an upstream failover) sends no frames, so the preview would
|
|
62
|
-
// age out mid-generation. Re-emit the current frame comfortably under the TTL.
|
|
63
|
-
const KEEPALIVE_MS = 20_000;
|
|
64
|
-
// Non-zero, ever-incrementing draft id per stream so a chat's concurrent /
|
|
65
|
-
// sequential previews don't share an animation timeline. Per-isolate;
|
|
66
|
-
// collisions across isolates are harmless (draft ids are chat-scoped).
|
|
67
|
-
let draftSeq = 0;
|
|
68
|
-
/**
|
|
69
|
-
* Jitter forensics for a streamed preview: a healthy stream only GROWS. A
|
|
70
|
-
* render that shrinks while the accumulated markdown grew means the
|
|
71
|
-
* partial-markdown tail parsed differently between frames (the renderer);
|
|
72
|
-
* accumulated text shrinking is an upstream provider reset. Neither warning
|
|
73
|
-
* firing while a user still sees back-and-forth points at their CLIENT's own
|
|
74
|
-
* draft rendering. Built into {@link createDraftPreview}; exported standalone
|
|
75
|
-
* for edit-based viewers that repaint outside the painter.
|
|
76
|
-
*/
|
|
77
|
-
export function streamForensics(label) {
|
|
78
|
-
let lastAccLen = 0;
|
|
79
|
-
let lastRenderedLen = 0;
|
|
80
|
-
return {
|
|
81
|
-
/** Call per outgoing frame with the accumulated-markdown and rendered lengths. */
|
|
82
|
-
frame(accLen, renderedLen) {
|
|
83
|
-
if (renderedLen < lastRenderedLen && accLen >= lastAccLen)
|
|
84
|
-
console.warn(`[bot/llm] ${label} render regressed · rendered ${lastRenderedLen}→${renderedLen} · acc ${accLen}`);
|
|
85
|
-
lastAccLen = accLen;
|
|
86
|
-
lastRenderedLen = renderedLen;
|
|
87
|
-
},
|
|
88
|
-
/** Call from the upstream reset path with the length being dropped. */
|
|
89
|
-
reset(droppedChars) {
|
|
90
|
-
console.warn(`[bot/llm] ${label} reset (provider failover) · dropped ${droppedChars} chars`);
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
export function createDraftPreview(ctx, opts = {}) {
|
|
95
|
-
const active = ctx.chat.type === "private";
|
|
96
|
-
const chatId = ctx.chat.id;
|
|
97
|
-
const threadId = ctx.threadId;
|
|
98
|
-
const draftId = ++draftSeq;
|
|
99
|
-
const throttle = opts.throttleMs ?? THROTTLE_MS;
|
|
100
|
-
const render = opts.render ??
|
|
101
|
-
((markdown) => ({ kind: "text", text: markdownToFormattable(markdown) }));
|
|
102
|
-
const forensics = streamForensics(opts.label ?? `draft ${draftId}`);
|
|
103
|
-
let acc = "";
|
|
104
|
-
let dirty = false;
|
|
105
|
-
let stopped = !active;
|
|
106
|
-
let lastFlushAt = 0;
|
|
107
|
-
let timer;
|
|
108
|
-
let flushing;
|
|
109
|
-
let keepalive;
|
|
110
|
-
// Send the current accumulated markdown as one full frame. Best-effort: a
|
|
111
|
-
// rejected preview (rate limit, empty render) is swallowed — the caller's
|
|
112
|
-
// persist path is what matters.
|
|
113
|
-
const sendFrame = async () => {
|
|
114
|
-
const frame = render(acc);
|
|
115
|
-
if (frame === null)
|
|
116
|
-
return;
|
|
117
|
-
if (frame.kind === "rich") {
|
|
118
|
-
forensics.frame(acc.length, frame.html.length);
|
|
119
|
-
await ctx.bot.api
|
|
120
|
-
.sendRichMessageDraft({
|
|
121
|
-
chat_id: chatId,
|
|
122
|
-
draft_id: draftId,
|
|
123
|
-
rich_message: { html: frame.html },
|
|
124
|
-
...(threadId !== undefined ? { message_thread_id: threadId } : {}),
|
|
125
|
-
})
|
|
126
|
-
.catch(() => { });
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
const rendered = typeof frame.text === "string" ? frame.text : frame.text.text;
|
|
130
|
-
forensics.frame(acc.length, rendered.length);
|
|
131
|
-
await ctx.bot.api
|
|
132
|
-
.sendMessageDraft({
|
|
133
|
-
chat_id: chatId,
|
|
134
|
-
draft_id: draftId,
|
|
135
|
-
text: frame.text,
|
|
136
|
-
...(frame.parseMode ? { parse_mode: frame.parseMode } : {}),
|
|
137
|
-
...(threadId !== undefined ? { message_thread_id: threadId } : {}),
|
|
138
|
-
})
|
|
139
|
-
.catch(() => { });
|
|
140
|
-
};
|
|
141
|
-
const flush = async () => {
|
|
142
|
-
if (!dirty || stopped)
|
|
143
|
-
return;
|
|
144
|
-
if (flushing)
|
|
145
|
-
await flushing.catch(() => { });
|
|
146
|
-
if (!dirty || stopped)
|
|
147
|
-
return;
|
|
148
|
-
dirty = false;
|
|
149
|
-
lastFlushAt = Date.now();
|
|
150
|
-
flushing = sendFrame();
|
|
151
|
-
await flushing.catch(() => { });
|
|
152
|
-
flushing = undefined;
|
|
153
|
-
if (dirty && !stopped)
|
|
154
|
-
schedule();
|
|
155
|
-
};
|
|
156
|
-
const schedule = () => {
|
|
157
|
-
dirty = true;
|
|
158
|
-
if (stopped || timer)
|
|
159
|
-
return;
|
|
160
|
-
const wait = Math.max(0, throttle - (Date.now() - lastFlushAt));
|
|
161
|
-
timer = setTimeout(() => {
|
|
162
|
-
timer = undefined;
|
|
163
|
-
void flush();
|
|
164
|
-
}, wait);
|
|
165
|
-
};
|
|
166
|
-
// Start the anti-expiry heartbeat once streaming has actually begun. Each
|
|
167
|
-
// tick reuses the normal flush path to re-paint the current frame, but only
|
|
168
|
-
// when the stream has gone quiet — an in-flight or pending flush already
|
|
169
|
-
// refreshes the draft.
|
|
170
|
-
const ensureKeepalive = () => {
|
|
171
|
-
if (keepalive || stopped)
|
|
172
|
-
return;
|
|
173
|
-
keepalive = setInterval(() => {
|
|
174
|
-
if (stopped || dirty || timer || flushing || !acc.trim())
|
|
175
|
-
return;
|
|
176
|
-
schedule();
|
|
177
|
-
}, KEEPALIVE_MS);
|
|
178
|
-
};
|
|
179
|
-
// Stop scheduling and let any in-flight frame settle. Shared by finish and abort.
|
|
180
|
-
const quiesce = async () => {
|
|
181
|
-
stopped = true;
|
|
182
|
-
if (timer) {
|
|
183
|
-
clearTimeout(timer);
|
|
184
|
-
timer = undefined;
|
|
185
|
-
}
|
|
186
|
-
if (keepalive) {
|
|
187
|
-
clearInterval(keepalive);
|
|
188
|
-
keepalive = undefined;
|
|
189
|
-
}
|
|
190
|
-
if (flushing)
|
|
191
|
-
await flushing.catch(() => { });
|
|
192
|
-
};
|
|
193
|
-
return {
|
|
194
|
-
get text() {
|
|
195
|
-
return acc;
|
|
196
|
-
},
|
|
197
|
-
append(text) {
|
|
198
|
-
if (stopped)
|
|
199
|
-
return;
|
|
200
|
-
acc += text;
|
|
201
|
-
ensureKeepalive();
|
|
202
|
-
schedule();
|
|
203
|
-
},
|
|
204
|
-
set(markdown) {
|
|
205
|
-
acc = markdown;
|
|
206
|
-
if (!stopped)
|
|
207
|
-
schedule();
|
|
208
|
-
},
|
|
209
|
-
reset() {
|
|
210
|
-
forensics.reset(acc.length);
|
|
211
|
-
acc = "";
|
|
212
|
-
},
|
|
213
|
-
repaint() {
|
|
214
|
-
if (!stopped && acc.trim())
|
|
215
|
-
schedule();
|
|
216
|
-
},
|
|
217
|
-
async finish(markdown) {
|
|
218
|
-
if (markdown !== undefined)
|
|
219
|
-
acc = markdown;
|
|
220
|
-
const wasActive = !stopped;
|
|
221
|
-
await quiesce();
|
|
222
|
-
if (wasActive)
|
|
223
|
-
await sendFrame().catch(() => { });
|
|
224
|
-
},
|
|
225
|
-
abort: quiesce,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
55
|
+
import { createDraftPreview } from "./draft.js";
|
|
228
56
|
/**
|
|
229
57
|
* Render an LLM event stream into the chat: live draft previews while
|
|
230
58
|
* generating (via {@link createDraftPreview}), entity-split persisted
|
|
@@ -233,7 +61,13 @@ export function createDraftPreview(ctx, opts = {}) {
|
|
|
233
61
|
*/
|
|
234
62
|
export async function streamChatReply(ctx, events, opts = {}) {
|
|
235
63
|
const reasoningMode = opts.reasoning ?? "preview";
|
|
236
|
-
const preview = createDraftPreview(ctx, {
|
|
64
|
+
const preview = createDraftPreview(ctx, {
|
|
65
|
+
throttleMs: opts.throttleMs,
|
|
66
|
+
render: (markdown) => ({
|
|
67
|
+
kind: "text",
|
|
68
|
+
text: markdownToFormattable(markdown),
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
237
71
|
let content = "";
|
|
238
72
|
let reasoning = "";
|
|
239
73
|
const toolCalls = [];
|
package/dist/bot/llm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/bot/llm.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/bot/llm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tg-md — the opinionated Telegram-Markdown formatter (xtldr's house style,
|
|
3
|
+
* grown from theSummaryBot's tg-html lineage). ONE input dialect, the
|
|
4
|
+
* markdown LLMs actually emit, rendered to every shape a bot sends:
|
|
5
|
+
*
|
|
6
|
+
* markdownToRichHtml(md, coverUrl?) rich-message HTML (Bot API 10.1): real
|
|
7
|
+
* headings/lists, optional cover <img>
|
|
8
|
+
* spliced after the title
|
|
9
|
+
* markdownToTelegramHtml(md) strict parse_mode=HTML subset: # title
|
|
10
|
+
* -> bold underlined line, ## headings ->
|
|
11
|
+
* bold lines with breathing room, ######
|
|
12
|
+
* footer -> quiet plain line, bullets -> •
|
|
13
|
+
* toPlainText(md) last-ditch fallback (quotes keep their
|
|
14
|
+
* > marker so they still read as quotes)
|
|
15
|
+
* tidyRichMarkdown(md) strip the stray ```fence``` models add
|
|
16
|
+
*
|
|
17
|
+
* The dialect contract, load-bearing and deliberate:
|
|
18
|
+
* - `_` is NEVER emphasis — snake_case in model output survives verbatim.
|
|
19
|
+
* Only `*italic*` / `**bold**` are honored.
|
|
20
|
+
* - Every tag is balanced by construction: a render can never produce a
|
|
21
|
+
* message Telegram rejects; unmatched markers stay literal.
|
|
22
|
+
* - Pure functions of the whole string — safe for full-frame draft repaints
|
|
23
|
+
* (bot/draft): malformed mid-stream markdown degrades to literal text
|
|
24
|
+
* this frame and renders correctly the next.
|
|
25
|
+
*
|
|
26
|
+
* Typography (heading air, bullet glyph, the title underline) IS the opinion;
|
|
27
|
+
* it becomes configurable when a second consumer needs a different look, not
|
|
28
|
+
* before. Zero deps, worker-safe.
|
|
29
|
+
*/
|
|
30
|
+
/** Unwrap a leading/trailing ```…``` code fence (some models add one) and trim. */
|
|
31
|
+
export declare function tidyRichMarkdown(raw: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Render the model's rich Markdown into Telegram's strict `parse_mode=HTML` subset,
|
|
34
|
+
* which has no headings or lists:
|
|
35
|
+
* `#` title -> a bold UNDERLINED line + blank line (the wordmark look)
|
|
36
|
+
* `##`..`#####` headings -> a bold line + blank line after (air between head and body)
|
|
37
|
+
* `######` footer heading -> a bold line, no forced air (it's the last line)
|
|
38
|
+
* bullets (`- `/`* `/`+ `) -> a `• ` prefix
|
|
39
|
+
* blockquote (`> `) -> `<blockquote>` (consecutive lines merged)
|
|
40
|
+
* `**bold**`/`*italic*` -> `<b>`/`<i>`; `` `code` `` -> `<code>`; links -> `<a>`
|
|
41
|
+
* Only `*`-based emphasis is honored (never `_`), so `snake_case` survives. Every tag
|
|
42
|
+
* is balanced, so Telegram can't reject the message; unmatched markers stay literal.
|
|
43
|
+
* The spacing is the legacy tghtml contract (now @adriangalilea/utils/tg-html): every
|
|
44
|
+
* heading is followed by a blank line so sections breathe — a heading hugging its
|
|
45
|
+
* bullets reads as a wall.
|
|
46
|
+
*/
|
|
47
|
+
export declare function markdownToTelegramHtml(markdown: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Render the model's rich Markdown into rich-message HTML (the `rich_message.html`
|
|
50
|
+
* field, Bot API 10.1), which supports tags `parse_mode=HTML` lacks, so headings and
|
|
51
|
+
* lists survive as real structure instead of flattening:
|
|
52
|
+
* headings (`#`..`######`) -> `<h1>`..`<h6>` (level = count of `#`)
|
|
53
|
+
* bullets (`- `/`* `/`+ `) -> `<ul><li>…</li></ul>` (consecutive items merged)
|
|
54
|
+
* blockquote (`> `) -> `<blockquote>` (consecutive lines merged)
|
|
55
|
+
* Inline emphasis/code/links reuse {@link inlineMd}. Every tag is balanced, so Telegram
|
|
56
|
+
* can't reject the message; unmatched markers stay literal.
|
|
57
|
+
*
|
|
58
|
+
* `coverUrl` (rich path only) embeds a cover image as a standalone `<img>` block right after
|
|
59
|
+
* the title heading (title, cover, then body), matching the rich-message photo block, which
|
|
60
|
+
* accepts HTTP(S) URLs only. Ignored unless it's a well-formed http(s) URL. The strict-HTML and
|
|
61
|
+
* plain fallbacks have no image support, so they never carry a cover.
|
|
62
|
+
*/
|
|
63
|
+
export declare function markdownToRichHtml(markdown: string, coverUrl?: string): string;
|
|
64
|
+
/** Escape text/code content for Telegram HTML. */
|
|
65
|
+
export declare function escapeHtml(s: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Strip Markdown to plain text: the fallback when Telegram rejects the rich message.
|
|
68
|
+
* Removes heading/bullet markers and emphasis, unwraps links to their text, but KEEPS
|
|
69
|
+
* the `>` blockquote marker on every quote line so quotes still read as quotes with no
|
|
70
|
+
* formatting to lean on. Best-effort, not a full parser.
|
|
71
|
+
*/
|
|
72
|
+
export declare function toPlainText(markdown: string): string;
|
|
73
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tg-md/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAkD/D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,GACf,MAAM,CA+DR;AA+DD,kDAAkD;AAClD,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAWD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAYpD"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tg-md — the opinionated Telegram-Markdown formatter (xtldr's house style,
|
|
3
|
+
* grown from theSummaryBot's tg-html lineage). ONE input dialect, the
|
|
4
|
+
* markdown LLMs actually emit, rendered to every shape a bot sends:
|
|
5
|
+
*
|
|
6
|
+
* markdownToRichHtml(md, coverUrl?) rich-message HTML (Bot API 10.1): real
|
|
7
|
+
* headings/lists, optional cover <img>
|
|
8
|
+
* spliced after the title
|
|
9
|
+
* markdownToTelegramHtml(md) strict parse_mode=HTML subset: # title
|
|
10
|
+
* -> bold underlined line, ## headings ->
|
|
11
|
+
* bold lines with breathing room, ######
|
|
12
|
+
* footer -> quiet plain line, bullets -> •
|
|
13
|
+
* toPlainText(md) last-ditch fallback (quotes keep their
|
|
14
|
+
* > marker so they still read as quotes)
|
|
15
|
+
* tidyRichMarkdown(md) strip the stray ```fence``` models add
|
|
16
|
+
*
|
|
17
|
+
* The dialect contract, load-bearing and deliberate:
|
|
18
|
+
* - `_` is NEVER emphasis — snake_case in model output survives verbatim.
|
|
19
|
+
* Only `*italic*` / `**bold**` are honored.
|
|
20
|
+
* - Every tag is balanced by construction: a render can never produce a
|
|
21
|
+
* message Telegram rejects; unmatched markers stay literal.
|
|
22
|
+
* - Pure functions of the whole string — safe for full-frame draft repaints
|
|
23
|
+
* (bot/draft): malformed mid-stream markdown degrades to literal text
|
|
24
|
+
* this frame and renders correctly the next.
|
|
25
|
+
*
|
|
26
|
+
* Typography (heading air, bullet glyph, the title underline) IS the opinion;
|
|
27
|
+
* it becomes configurable when a second consumer needs a different look, not
|
|
28
|
+
* before. Zero deps, worker-safe.
|
|
29
|
+
*/
|
|
30
|
+
/** Unwrap a leading/trailing ```…``` code fence (some models add one) and trim. */
|
|
31
|
+
export function tidyRichMarkdown(raw) {
|
|
32
|
+
const trimmed = raw.trim();
|
|
33
|
+
const fenced = /^```[a-zA-Z]*\n([\s\S]*?)\n?```$/.exec(trimmed);
|
|
34
|
+
return (fenced ? fenced[1] : trimmed).trim();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Render the model's rich Markdown into Telegram's strict `parse_mode=HTML` subset,
|
|
38
|
+
* which has no headings or lists:
|
|
39
|
+
* `#` title -> a bold UNDERLINED line + blank line (the wordmark look)
|
|
40
|
+
* `##`..`#####` headings -> a bold line + blank line after (air between head and body)
|
|
41
|
+
* `######` footer heading -> a bold line, no forced air (it's the last line)
|
|
42
|
+
* bullets (`- `/`* `/`+ `) -> a `• ` prefix
|
|
43
|
+
* blockquote (`> `) -> `<blockquote>` (consecutive lines merged)
|
|
44
|
+
* `**bold**`/`*italic*` -> `<b>`/`<i>`; `` `code` `` -> `<code>`; links -> `<a>`
|
|
45
|
+
* Only `*`-based emphasis is honored (never `_`), so `snake_case` survives. Every tag
|
|
46
|
+
* is balanced, so Telegram can't reject the message; unmatched markers stay literal.
|
|
47
|
+
* The spacing is the legacy tghtml contract (now @adriangalilea/utils/tg-html): every
|
|
48
|
+
* heading is followed by a blank line so sections breathe — a heading hugging its
|
|
49
|
+
* bullets reads as a wall.
|
|
50
|
+
*/
|
|
51
|
+
export function markdownToTelegramHtml(markdown) {
|
|
52
|
+
const lines = tidyRichMarkdown(markdown).split(/\r?\n/);
|
|
53
|
+
const out = [];
|
|
54
|
+
let quote = [];
|
|
55
|
+
const flushQuote = () => {
|
|
56
|
+
if (quote.length) {
|
|
57
|
+
out.push(`<blockquote>${quote.join("\n")}</blockquote>`);
|
|
58
|
+
quote = [];
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
for (const raw of lines) {
|
|
62
|
+
const line = raw.replace(/\s+$/, "");
|
|
63
|
+
const q = /^\s{0,3}>\s?(.*)$/.exec(line);
|
|
64
|
+
if (q) {
|
|
65
|
+
quote.push(inlineMd(q[1]));
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
flushQuote();
|
|
69
|
+
if (!line.trim()) {
|
|
70
|
+
out.push("");
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const heading = /^\s{0,3}(#{1,6})\s+(.*)$/.exec(line);
|
|
74
|
+
if (heading) {
|
|
75
|
+
const level = heading[1].length;
|
|
76
|
+
const text = inlineMd(heading[2]);
|
|
77
|
+
// ###### is the source footer: metadata, not a heading — it renders as a quiet
|
|
78
|
+
// plain line (the legacy look), never bold.
|
|
79
|
+
if (level === 1)
|
|
80
|
+
out.push(`<b><u>${text}</u></b>`, "");
|
|
81
|
+
else if (level === 6)
|
|
82
|
+
out.push(text);
|
|
83
|
+
else
|
|
84
|
+
out.push(`<b>${text}</b>`, "");
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const bullet = /^\s{0,3}[-*+]\s+(.*)$/.exec(line);
|
|
88
|
+
if (bullet) {
|
|
89
|
+
out.push(`• ${inlineMd(bullet[1])}`);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
out.push(inlineMd(line));
|
|
93
|
+
}
|
|
94
|
+
flushQuote();
|
|
95
|
+
return tidyHtml(out.join("\n"));
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Render the model's rich Markdown into rich-message HTML (the `rich_message.html`
|
|
99
|
+
* field, Bot API 10.1), which supports tags `parse_mode=HTML` lacks, so headings and
|
|
100
|
+
* lists survive as real structure instead of flattening:
|
|
101
|
+
* headings (`#`..`######`) -> `<h1>`..`<h6>` (level = count of `#`)
|
|
102
|
+
* bullets (`- `/`* `/`+ `) -> `<ul><li>…</li></ul>` (consecutive items merged)
|
|
103
|
+
* blockquote (`> `) -> `<blockquote>` (consecutive lines merged)
|
|
104
|
+
* Inline emphasis/code/links reuse {@link inlineMd}. Every tag is balanced, so Telegram
|
|
105
|
+
* can't reject the message; unmatched markers stay literal.
|
|
106
|
+
*
|
|
107
|
+
* `coverUrl` (rich path only) embeds a cover image as a standalone `<img>` block right after
|
|
108
|
+
* the title heading (title, cover, then body), matching the rich-message photo block, which
|
|
109
|
+
* accepts HTTP(S) URLs only. Ignored unless it's a well-formed http(s) URL. The strict-HTML and
|
|
110
|
+
* plain fallbacks have no image support, so they never carry a cover.
|
|
111
|
+
*/
|
|
112
|
+
export function markdownToRichHtml(markdown, coverUrl) {
|
|
113
|
+
const lines = tidyRichMarkdown(markdown).split(/\r?\n/);
|
|
114
|
+
const out = [];
|
|
115
|
+
let quote = [];
|
|
116
|
+
let bullets = [];
|
|
117
|
+
const flushQuote = () => {
|
|
118
|
+
if (quote.length) {
|
|
119
|
+
out.push(`<blockquote>${quote.join("\n")}</blockquote>`);
|
|
120
|
+
quote = [];
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const flushBullets = () => {
|
|
124
|
+
if (bullets.length) {
|
|
125
|
+
out.push(`<ul>${bullets.map((b) => `<li>${b}</li>`).join("")}</ul>`);
|
|
126
|
+
bullets = [];
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
for (const raw of lines) {
|
|
130
|
+
const line = raw.replace(/\s+$/, "");
|
|
131
|
+
const q = /^\s{0,3}>\s?(.*)$/.exec(line);
|
|
132
|
+
if (q) {
|
|
133
|
+
flushBullets();
|
|
134
|
+
quote.push(inlineMd(q[1]));
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const bullet = /^\s{0,3}[-*+]\s+(.*)$/.exec(line);
|
|
138
|
+
if (bullet) {
|
|
139
|
+
flushQuote();
|
|
140
|
+
bullets.push(inlineMd(bullet[1]));
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
flushQuote();
|
|
144
|
+
flushBullets();
|
|
145
|
+
if (!line.trim()) {
|
|
146
|
+
out.push("");
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const heading = /^\s{0,3}(#{1,6})\s+(.*)$/.exec(line);
|
|
150
|
+
if (heading) {
|
|
151
|
+
const level = heading[1].length;
|
|
152
|
+
out.push(`<h${level}>${inlineMd(heading[2])}</h${level}>`);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
out.push(inlineMd(line));
|
|
156
|
+
}
|
|
157
|
+
flushQuote();
|
|
158
|
+
flushBullets();
|
|
159
|
+
insertCover(out, coverUrl);
|
|
160
|
+
return out
|
|
161
|
+
.join("\n")
|
|
162
|
+
.replace(/[ \t]+\n/g, "\n")
|
|
163
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
164
|
+
.trim();
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Insert a cover `<img>` block into the rendered rich-HTML lines: right after the title heading
|
|
168
|
+
* (so it reads title → cover → body), or at the very top when there's no title. Anchors on `<h1>`
|
|
169
|
+
* only, since the summary's title is `#` (h1) while section headings are `##` (h2) and the source
|
|
170
|
+
* footer is `######` (h6): matching any `<h[1-6]>` would splice the cover below the footer when the
|
|
171
|
+
* model omits the title. A blank line surrounds it so it stays its own block (media blocks can't be
|
|
172
|
+
* inline). No-op unless `url` is a well-formed http(s) URL, since the rich photo block accepts only those.
|
|
173
|
+
*/
|
|
174
|
+
function insertCover(out, url) {
|
|
175
|
+
if (!url || !/^https?:\/\/\S+$/i.test(url.trim()))
|
|
176
|
+
return;
|
|
177
|
+
const img = `<img src="${escapeAttr(url.trim())}"/>`;
|
|
178
|
+
const titleAt = out.findIndex((line) => /^<h1>/.test(line));
|
|
179
|
+
const at = titleAt === -1 ? 0 : titleAt + 1;
|
|
180
|
+
out.splice(at, 0, "", img, "");
|
|
181
|
+
}
|
|
182
|
+
/** Normalize rendered HTML: strip trailing whitespace, collapse blank-line runs. Blank lines
|
|
183
|
+
* around lists stay — that air is the layout (the legacy look); only runs of 3+ collapse. */
|
|
184
|
+
function tidyHtml(html) {
|
|
185
|
+
return html
|
|
186
|
+
.replace(/[ \t]+\n/g, "\n")
|
|
187
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
188
|
+
.trim();
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Inline Markdown to Telegram HTML for one line. Code spans and links are pulled out
|
|
192
|
+
* first (so their contents aren't escaped twice or treated as emphasis) and stashed;
|
|
193
|
+
* the rest is escaped, `**bold**`/`*italic*` become tags, then the fragments are restored.
|
|
194
|
+
*/
|
|
195
|
+
function inlineMd(text) {
|
|
196
|
+
const tokens = [];
|
|
197
|
+
const stash = (html) => {
|
|
198
|
+
tokens.push(html);
|
|
199
|
+
return `${tokens.length - 1}`;
|
|
200
|
+
};
|
|
201
|
+
// Code spans first: their contents are literal (no emphasis, no nested links).
|
|
202
|
+
let s = text.replace(/`([^`]+)`/g, (_, code) => stash(`<code>${escapeHtml(code)}</code>`));
|
|
203
|
+
// Then links: drop the href unless it's a trusted scheme, keeping the label.
|
|
204
|
+
s = s.replace(/\[([^\]]*)\]\(([^)\s]+)\)/g, (_, label, url) => {
|
|
205
|
+
const safe = /^(https?:|tg:|mailto:)/i.test(url) ? url : null;
|
|
206
|
+
return stash(safe
|
|
207
|
+
? `<a href="${escapeAttr(safe)}">${escapeHtml(label)}</a>`
|
|
208
|
+
: escapeHtml(label));
|
|
209
|
+
});
|
|
210
|
+
s = escapeHtml(s);
|
|
211
|
+
s = s.replace(/\*\*([^*]+)\*\*/g, "<b>$1</b>"); // bold before italic so `**` wins over `*`
|
|
212
|
+
s = s.replace(/(^|[^*])\*(?!\s)([^*]+?)\*/g, "$1<i>$2</i>");
|
|
213
|
+
return s.replace(/(\d+)/g, (_, i) => tokens[Number(i)]);
|
|
214
|
+
}
|
|
215
|
+
/** Escape text/code content for Telegram HTML. */
|
|
216
|
+
export function escapeHtml(s) {
|
|
217
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
218
|
+
}
|
|
219
|
+
/** Escape an href for a Telegram HTML attribute. */
|
|
220
|
+
function escapeAttr(s) {
|
|
221
|
+
return s
|
|
222
|
+
.replace(/&/g, "&")
|
|
223
|
+
.replace(/"/g, """)
|
|
224
|
+
.replace(/</g, "<")
|
|
225
|
+
.replace(/>/g, ">");
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Strip Markdown to plain text: the fallback when Telegram rejects the rich message.
|
|
229
|
+
* Removes heading/bullet markers and emphasis, unwraps links to their text, but KEEPS
|
|
230
|
+
* the `>` blockquote marker on every quote line so quotes still read as quotes with no
|
|
231
|
+
* formatting to lean on. Best-effort, not a full parser.
|
|
232
|
+
*/
|
|
233
|
+
export function toPlainText(markdown) {
|
|
234
|
+
return tidyRichMarkdown(markdown)
|
|
235
|
+
.replace(/```[a-zA-Z]*\n?([\s\S]*?)```/g, "$1") // fenced code -> its contents
|
|
236
|
+
.replace(/^\s{0,3}#{1,6}\s+/gm, "") // heading markers
|
|
237
|
+
.replace(/^\s{0,3}>\s?/gm, "> ") // normalize blockquote markers, keep them
|
|
238
|
+
.replace(/^(\s*)[-*+]\s+/gm, "$1• ") // bullet markers -> •
|
|
239
|
+
.replace(/\[([^\]]*)\]\([^)]*\)/g, "$1") // [text](url) -> text
|
|
240
|
+
.replace(/(\*\*|__)(.*?)\1/g, "$2") // bold
|
|
241
|
+
.replace(/(\*|_)(.*?)\1/g, "$2") // italic
|
|
242
|
+
.replace(/`([^`]*)`/g, "$1") // inline code
|
|
243
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
244
|
+
.trim();
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tg-md/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adriangalilea/utils",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "TypeScript utilities - logger, currency, formatter, GramIO bot plugins, and more",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -44,6 +44,10 @@
|
|
|
44
44
|
"types": "./dist/tg-html/index.d.ts",
|
|
45
45
|
"default": "./dist/tg-html/index.js"
|
|
46
46
|
},
|
|
47
|
+
"./tg-md": {
|
|
48
|
+
"types": "./dist/tg-md/index.d.ts",
|
|
49
|
+
"default": "./dist/tg-md/index.js"
|
|
50
|
+
},
|
|
47
51
|
"./bot": {
|
|
48
52
|
"types": "./dist/bot/index.d.ts",
|
|
49
53
|
"default": "./dist/bot/index.js"
|
|
@@ -64,6 +68,10 @@
|
|
|
64
68
|
"types": "./dist/bot/coalesce.d.ts",
|
|
65
69
|
"default": "./dist/bot/coalesce.js"
|
|
66
70
|
},
|
|
71
|
+
"./bot/draft": {
|
|
72
|
+
"types": "./dist/bot/draft.d.ts",
|
|
73
|
+
"default": "./dist/bot/draft.js"
|
|
74
|
+
},
|
|
67
75
|
"./bot/language": {
|
|
68
76
|
"types": "./dist/bot/language.d.ts",
|
|
69
77
|
"default": "./dist/bot/language.js"
|