@nodetool-ai/telegram 0.8.1

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.
Files changed (59) hide show
  1. package/README.md +49 -0
  2. package/dist/.nodetool-build-stamp +1 -0
  3. package/dist/bot-api.d.ts +115 -0
  4. package/dist/bot-api.d.ts.map +1 -0
  5. package/dist/bot-api.js +145 -0
  6. package/dist/bot-api.js.map +1 -0
  7. package/dist/chunk.d.ts +36 -0
  8. package/dist/chunk.d.ts.map +1 -0
  9. package/dist/chunk.js +280 -0
  10. package/dist/chunk.js.map +1 -0
  11. package/dist/cli.d.ts +10 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +62 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/commands.d.ts +83 -0
  16. package/dist/commands.d.ts.map +1 -0
  17. package/dist/commands.js +191 -0
  18. package/dist/commands.js.map +1 -0
  19. package/dist/config.d.ts +65 -0
  20. package/dist/config.d.ts.map +1 -0
  21. package/dist/config.js +139 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/frame-renderer.d.ts +135 -0
  24. package/dist/frame-renderer.d.ts.map +1 -0
  25. package/dist/frame-renderer.js +407 -0
  26. package/dist/frame-renderer.js.map +1 -0
  27. package/dist/identity-client.d.ts +132 -0
  28. package/dist/identity-client.d.ts.map +1 -0
  29. package/dist/identity-client.js +204 -0
  30. package/dist/identity-client.js.map +1 -0
  31. package/dist/index.d.ts +56 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +90 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/markdown-html.d.ts +32 -0
  36. package/dist/markdown-html.d.ts.map +1 -0
  37. package/dist/markdown-html.js +251 -0
  38. package/dist/markdown-html.js.map +1 -0
  39. package/dist/nodetool-client.d.ts +32 -0
  40. package/dist/nodetool-client.d.ts.map +1 -0
  41. package/dist/nodetool-client.js +127 -0
  42. package/dist/nodetool-client.js.map +1 -0
  43. package/dist/register-commands.d.ts +24 -0
  44. package/dist/register-commands.d.ts.map +1 -0
  45. package/dist/register-commands.js +29 -0
  46. package/dist/register-commands.js.map +1 -0
  47. package/dist/strings.d.ts +7 -0
  48. package/dist/strings.d.ts.map +1 -0
  49. package/dist/strings.js +13 -0
  50. package/dist/strings.js.map +1 -0
  51. package/dist/telegram-adapter.d.ts +100 -0
  52. package/dist/telegram-adapter.d.ts.map +1 -0
  53. package/dist/telegram-adapter.js +366 -0
  54. package/dist/telegram-adapter.js.map +1 -0
  55. package/dist/turn-router.d.ts +167 -0
  56. package/dist/turn-router.d.ts.map +1 -0
  57. package/dist/turn-router.js +360 -0
  58. package/dist/turn-router.js.map +1 -0
  59. package/package.json +68 -0
@@ -0,0 +1,135 @@
1
+ /**
2
+ * FrameRenderer — the pure fold from server frames to render operations
3
+ * (design §6).
4
+ *
5
+ * A turn's visible state in a Telegram chat is two messages: a **status line**
6
+ * that reports what the agent is doing, and a **stream message** that grows as
7
+ * text arrives. This module owns the rules that decide when each is created,
8
+ * edited, rolled over and finalized. It performs no I/O, imports no Telegram
9
+ * types, and reads no clock — `nowMs` is a parameter — so the whole streaming
10
+ * UX is exercised by scripted frame sequences in tests.
11
+ *
12
+ * The adapter maps each op onto one Bot API call.
13
+ */
14
+ import type { Message, ProcessingMessage } from "@nodetool-ai/protocol";
15
+ import { TELEGRAM_MESSAGE_LIMIT } from "./chunk.js";
16
+ /** Which of the turn's two messages an op acts on. */
17
+ export type RenderTarget = "status" | "stream";
18
+ /** How the adapter must ask Telegram to parse the text. */
19
+ export type ParseMode = "html" | "none";
20
+ /** An asset the turn produced, to be sent as a photo or document. */
21
+ export interface AssetAttachment {
22
+ /** Where the bytes live — `asset://…` or an absolute URL. */
23
+ readonly uri: string;
24
+ /** Display name, when the frame carried one. */
25
+ readonly name: string | null;
26
+ /** Content type, when the frame carried one. */
27
+ readonly contentType: string | null;
28
+ }
29
+ export interface TypingOp {
30
+ readonly kind: "typing";
31
+ }
32
+ export interface SendOp {
33
+ readonly kind: "send";
34
+ readonly target: RenderTarget;
35
+ readonly text: string;
36
+ readonly parseMode: ParseMode;
37
+ }
38
+ export interface EditOp {
39
+ readonly kind: "edit";
40
+ readonly target: RenderTarget;
41
+ readonly text: string;
42
+ readonly parseMode: ParseMode;
43
+ }
44
+ /**
45
+ * The message reaches its final content and stops being edited. `create` is
46
+ * true when no message exists yet, so the adapter sends instead of edits.
47
+ */
48
+ export interface FinalizeOp {
49
+ readonly kind: "finalize";
50
+ readonly target: RenderTarget;
51
+ readonly text: string;
52
+ readonly parseMode: ParseMode;
53
+ readonly create: boolean;
54
+ }
55
+ export interface AttachOp {
56
+ readonly kind: "attach";
57
+ readonly asset: AssetAttachment;
58
+ }
59
+ export interface StopNoteOp {
60
+ readonly kind: "stop-note";
61
+ readonly text: string;
62
+ }
63
+ export type RenderOp = TypingOp | SendOp | EditOp | FinalizeOp | AttachOp | StopNoteOp;
64
+ /** The final assistant message the server persists at the end of a turn. */
65
+ export interface FinalMessageFrame extends Message {
66
+ readonly type: "message";
67
+ }
68
+ /** Ack for a `stop` command. */
69
+ export interface GenerationStoppedFrame {
70
+ readonly type: "generation_stopped";
71
+ readonly thread_id?: string | null;
72
+ readonly message?: string | null;
73
+ }
74
+ /**
75
+ * Frames carry an optional monotonic sequence number. `resume_chat` replays
76
+ * everything after `last_seq`, and a replay that overlaps must not re-emit ops
77
+ * — the fold drops any frame whose seq it has already applied.
78
+ */
79
+ export interface FrameEnvelope {
80
+ readonly seq?: number | null;
81
+ }
82
+ export type RenderFrame = (ProcessingMessage | FinalMessageFrame | GenerationStoppedFrame) & FrameEnvelope;
83
+ export interface RendererOptions {
84
+ /** Minimum gap between edits of the stream message. Default 1500 ms. */
85
+ readonly editThrottleMs?: number;
86
+ /** Rendered length at which the stream message rolls over. Default 3800. */
87
+ readonly rolloverChars?: number;
88
+ }
89
+ export interface RendererState {
90
+ /** Markdown for the currently open stream message. */
91
+ readonly carry: string;
92
+ /** A stream message exists in the chat. */
93
+ readonly streamOpen: boolean;
94
+ /** Length of `carry` as last rendered, so a no-op edit is skipped. */
95
+ readonly renderedLength: number;
96
+ /** `nowMs` of the last stream edit, for the throttle. */
97
+ readonly lastEditMs: number;
98
+ /** A typing action has been requested for this turn. */
99
+ readonly typingSent: boolean;
100
+ /** Latest status line, or null when nothing has been reported. */
101
+ readonly status: string | null;
102
+ /** A status message exists in the chat. */
103
+ readonly statusOpen: boolean;
104
+ /** Status text as last rendered. */
105
+ readonly statusRendered: string | null;
106
+ /** The turn has ended — later frames render nothing. */
107
+ readonly ended: boolean;
108
+ /** Highest applied sequence number, for replay suppression. */
109
+ readonly lastSeq: number | null;
110
+ readonly editThrottleMs: number;
111
+ readonly rolloverChars: number;
112
+ }
113
+ export declare const DEFAULT_EDIT_THROTTLE_MS = 1500;
114
+ export declare function createRendererState(options?: RendererOptions): RendererState;
115
+ export interface FoldResult {
116
+ readonly state: RendererState;
117
+ readonly ops: readonly RenderOp[];
118
+ }
119
+ /** Every asset reference nested anywhere in an `output_update` value. */
120
+ export declare function collectAssetRefs(value: unknown, found?: AssetAttachment[]): AssetAttachment[];
121
+ /**
122
+ * Apply one frame to the renderer state.
123
+ *
124
+ * @param state Renderer state from `createRendererState` or a previous fold.
125
+ * @param frame The server frame.
126
+ * @param nowMs Caller's clock, in milliseconds. The only time source.
127
+ */
128
+ export declare function foldFrame(state: RendererState, frame: RenderFrame, nowMs: number): FoldResult;
129
+ /** Fold a whole sequence of frames, for tests and replay. */
130
+ export declare function foldFrames(state: RendererState, frames: readonly {
131
+ frame: RenderFrame;
132
+ nowMs: number;
133
+ }[]): FoldResult;
134
+ export { TELEGRAM_MESSAGE_LIMIT };
135
+ //# sourceMappingURL=frame-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-renderer.d.ts","sourceRoot":"","sources":["../src/frame-renderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,407 @@
1
+ /**
2
+ * FrameRenderer — the pure fold from server frames to render operations
3
+ * (design §6).
4
+ *
5
+ * A turn's visible state in a Telegram chat is two messages: a **status line**
6
+ * that reports what the agent is doing, and a **stream message** that grows as
7
+ * text arrives. This module owns the rules that decide when each is created,
8
+ * edited, rolled over and finalized. It performs no I/O, imports no Telegram
9
+ * types, and reads no clock — `nowMs` is a parameter — so the whole streaming
10
+ * UX is exercised by scripted frame sequences in tests.
11
+ *
12
+ * The adapter maps each op onto one Bot API call.
13
+ */
14
+ import { DEFAULT_CHUNK_MAX, TELEGRAM_MESSAGE_LIMIT, splitOnce } from "./chunk.js";
15
+ import { markdownToTelegramHtml } from "./markdown-html.js";
16
+ export const DEFAULT_EDIT_THROTTLE_MS = 1500;
17
+ export function createRendererState(options = {}) {
18
+ return {
19
+ carry: "",
20
+ streamOpen: false,
21
+ renderedLength: 0,
22
+ lastEditMs: Number.NEGATIVE_INFINITY,
23
+ typingSent: false,
24
+ status: null,
25
+ statusOpen: false,
26
+ statusRendered: null,
27
+ ended: false,
28
+ lastSeq: null,
29
+ editThrottleMs: options.editThrottleMs ?? DEFAULT_EDIT_THROTTLE_MS,
30
+ rolloverChars: options.rolloverChars ?? DEFAULT_CHUNK_MAX
31
+ };
32
+ }
33
+ function present(markdown) {
34
+ const result = markdownToTelegramHtml(markdown);
35
+ return result.ok
36
+ ? { text: result.html, parseMode: "html" }
37
+ : { text: result.text, parseMode: "none" };
38
+ }
39
+ /**
40
+ * Split `markdown` so the rendered head fits in `limit`. Escaping expands the
41
+ * text (`&` becomes five characters), so the budget is walked down by the
42
+ * measured expansion ratio rather than assumed.
43
+ */
44
+ function splitForRender(markdown, limit) {
45
+ let budget = Math.min(markdown.length, limit);
46
+ for (let attempt = 0; attempt < 12; attempt += 1) {
47
+ const { head, rest } = splitOnce(markdown, budget);
48
+ if (head.length === 0) {
49
+ break;
50
+ }
51
+ const rendered = present(head).text.length;
52
+ if (rendered <= limit) {
53
+ return { head, rest };
54
+ }
55
+ const next = Math.floor((budget * limit) / rendered) - 1;
56
+ if (next < 1 || next >= budget) {
57
+ budget = budget - 1;
58
+ }
59
+ else {
60
+ budget = next;
61
+ }
62
+ if (budget < 1) {
63
+ break;
64
+ }
65
+ }
66
+ return { head: markdown.slice(0, limit), rest: markdown.slice(limit) };
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // Status line
70
+ // ---------------------------------------------------------------------------
71
+ function statusOps(state, line) {
72
+ if (state.statusRendered === line) {
73
+ return { state, ops: [] };
74
+ }
75
+ const rendered = present(line);
76
+ const op = state.statusOpen
77
+ ? { kind: "edit", target: "status", text: rendered.text, parseMode: rendered.parseMode }
78
+ : { kind: "send", target: "status", text: rendered.text, parseMode: rendered.parseMode };
79
+ return {
80
+ state: { ...state, status: line, statusOpen: true, statusRendered: line },
81
+ ops: [op]
82
+ };
83
+ }
84
+ function toolLine(frame) {
85
+ const detail = frame.message != null && frame.message.length > 0 ? ` — ${frame.message}` : "";
86
+ const done = /(^|\b)(completed|finished|done|success)/i.test(frame.message ?? "");
87
+ const failed = /(^|\b)(failed|error)/i.test(frame.message ?? "");
88
+ const icon = failed ? "❌" : done ? "✅" : "🔧";
89
+ return `${icon} ${frame.name}${detail}`;
90
+ }
91
+ function taskLine(frame) {
92
+ const label = frame.step?.title ?? frame.task?.title ?? frame.event;
93
+ return `📋 ${label}`;
94
+ }
95
+ function planningLine(frame) {
96
+ const detail = frame.content != null && frame.content.length > 0 ? ` — ${frame.content}` : "";
97
+ return `🧠 ${frame.phase} (${frame.status})${detail}`;
98
+ }
99
+ function nodeLine(frame) {
100
+ return `⚙️ ${frame.node_name} (${frame.status})`;
101
+ }
102
+ function jobLine(frame) {
103
+ return `▶️ job ${frame.status}`;
104
+ }
105
+ // ---------------------------------------------------------------------------
106
+ // Text stream
107
+ // ---------------------------------------------------------------------------
108
+ /**
109
+ * Close the status message when a text message takes over as the visible
110
+ * surface. Only a *new* stream message replaces it — editing one that already
111
+ * exists changes nothing about which message the user is watching.
112
+ */
113
+ function closeStatus(state, ops) {
114
+ if (!state.statusOpen || state.status === null || state.streamOpen) {
115
+ return state;
116
+ }
117
+ const rendered = present(state.status);
118
+ ops.push({
119
+ kind: "finalize",
120
+ target: "status",
121
+ text: rendered.text,
122
+ parseMode: rendered.parseMode,
123
+ create: false
124
+ });
125
+ return { ...state, statusOpen: false, statusRendered: null };
126
+ }
127
+ /**
128
+ * Finalize every full message's worth of buffered text, leaving `carry` at
129
+ * whatever still fits in one message.
130
+ */
131
+ function rollOver(state, nowMs, ops) {
132
+ let next = state;
133
+ while (present(next.carry).text.length > next.rolloverChars) {
134
+ next = closeStatus(next, ops);
135
+ const { head, rest } = splitForRender(next.carry, next.rolloverChars);
136
+ if (head.length === 0) {
137
+ break;
138
+ }
139
+ const rendered = present(head);
140
+ ops.push({
141
+ kind: "finalize",
142
+ target: "stream",
143
+ text: rendered.text,
144
+ parseMode: rendered.parseMode,
145
+ create: !next.streamOpen
146
+ });
147
+ next = { ...next, carry: rest, streamOpen: false, renderedLength: 0, lastEditMs: nowMs };
148
+ }
149
+ return next;
150
+ }
151
+ /**
152
+ * Emit whatever the accumulated text requires: rollover of anything past the
153
+ * message limit, then a create or a throttled edit for the remainder.
154
+ */
155
+ function flushText(state, nowMs, force) {
156
+ const ops = [];
157
+ let next = rollOver(state, nowMs, ops);
158
+ if (next.carry.length === 0) {
159
+ return { state: next, ops };
160
+ }
161
+ if (!next.streamOpen) {
162
+ next = closeStatus(next, ops);
163
+ const rendered = present(next.carry);
164
+ ops.push({
165
+ kind: "send",
166
+ target: "stream",
167
+ text: rendered.text,
168
+ parseMode: rendered.parseMode
169
+ });
170
+ return {
171
+ state: { ...next, streamOpen: true, renderedLength: next.carry.length, lastEditMs: nowMs },
172
+ ops
173
+ };
174
+ }
175
+ const unchanged = next.renderedLength === next.carry.length;
176
+ const throttled = nowMs - next.lastEditMs < next.editThrottleMs;
177
+ if (unchanged || (throttled && !force)) {
178
+ return { state: next, ops };
179
+ }
180
+ const rendered = present(next.carry);
181
+ ops.push({
182
+ kind: "edit",
183
+ target: "stream",
184
+ text: rendered.text,
185
+ parseMode: rendered.parseMode
186
+ });
187
+ return {
188
+ state: { ...next, renderedLength: next.carry.length, lastEditMs: nowMs },
189
+ ops
190
+ };
191
+ }
192
+ /** Finalize the stream message and everything still buffered behind it. */
193
+ function finishText(state, nowMs) {
194
+ const ops = [];
195
+ let next = rollOver(state, nowMs, ops);
196
+ if (next.carry.length > 0) {
197
+ next = closeStatus(next, ops);
198
+ const rendered = present(next.carry);
199
+ ops.push({
200
+ kind: "finalize",
201
+ target: "stream",
202
+ text: rendered.text,
203
+ parseMode: rendered.parseMode,
204
+ create: !next.streamOpen
205
+ });
206
+ next = { ...next, streamOpen: true, renderedLength: next.carry.length, lastEditMs: nowMs };
207
+ }
208
+ return { state: next, ops };
209
+ }
210
+ // ---------------------------------------------------------------------------
211
+ // Assets
212
+ // ---------------------------------------------------------------------------
213
+ function isRecord(value) {
214
+ return typeof value === "object" && value !== null && !Array.isArray(value);
215
+ }
216
+ function stringField(record, field) {
217
+ const value = record[field];
218
+ return typeof value === "string" && value.length > 0 ? value : null;
219
+ }
220
+ /** Every asset reference nested anywhere in an `output_update` value. */
221
+ export function collectAssetRefs(value, found = []) {
222
+ if (typeof value === "string") {
223
+ if (value.startsWith("asset://")) {
224
+ found.push({ uri: value, name: null, contentType: null });
225
+ }
226
+ return found;
227
+ }
228
+ if (Array.isArray(value)) {
229
+ for (const item of value) {
230
+ collectAssetRefs(item, found);
231
+ }
232
+ return found;
233
+ }
234
+ if (!isRecord(value)) {
235
+ return found;
236
+ }
237
+ const uri = stringField(value, "uri") ?? stringField(value, "url");
238
+ if (uri !== null) {
239
+ found.push({
240
+ uri,
241
+ name: stringField(value, "name") ?? stringField(value, "filename"),
242
+ contentType: stringField(value, "content_type") ?? stringField(value, "type")
243
+ });
244
+ return found;
245
+ }
246
+ for (const nested of Object.values(value)) {
247
+ collectAssetRefs(nested, found);
248
+ }
249
+ return found;
250
+ }
251
+ // ---------------------------------------------------------------------------
252
+ // Final message text
253
+ // ---------------------------------------------------------------------------
254
+ /**
255
+ * Whether this `message` frame is the turn's answer, and so ends the render.
256
+ *
257
+ * The wire carries several `message` frames per turn that are not the answer,
258
+ * and folding any of them as final hands the user the wrong text and drops
259
+ * everything after it (the fold ignores frames once `ended`):
260
+ *
261
+ * - the compaction echo, `role: "user"` with `execution_event_type:
262
+ * "compaction"`, sent *before* the turn streams — its content is a summary
263
+ * of the earlier conversation;
264
+ * - the mid-turn assistant echo and the synthetic tool-call card, both
265
+ * `role: "assistant"` carrying `tool_calls` and often no text at all;
266
+ * - tool results, `role: "tool"`.
267
+ *
268
+ * So: an assistant message, with no execution event on it, that is not calling
269
+ * a tool. The text of the answer also arrives as chunks, so a frame this
270
+ * refuses costs the render nothing.
271
+ */
272
+ function isFinalMessage(frame) {
273
+ if (frame.role !== "assistant") {
274
+ return false;
275
+ }
276
+ if (typeof frame.execution_event_type === "string" && frame.execution_event_type.length > 0) {
277
+ return false;
278
+ }
279
+ return !Array.isArray(frame.tool_calls) || frame.tool_calls.length === 0;
280
+ }
281
+ function textOfMessage(frame) {
282
+ const content = frame.content;
283
+ if (typeof content === "string") {
284
+ return content;
285
+ }
286
+ if (!Array.isArray(content)) {
287
+ return "";
288
+ }
289
+ return content
290
+ .filter((part) => isRecord(part) && part.type === "text" && typeof part.text === "string")
291
+ .map((part) => part.text)
292
+ .join("");
293
+ }
294
+ // ---------------------------------------------------------------------------
295
+ // Fold
296
+ // ---------------------------------------------------------------------------
297
+ /**
298
+ * Apply one frame to the renderer state.
299
+ *
300
+ * @param state Renderer state from `createRendererState` or a previous fold.
301
+ * @param frame The server frame.
302
+ * @param nowMs Caller's clock, in milliseconds. The only time source.
303
+ */
304
+ export function foldFrame(state, frame, nowMs) {
305
+ const seq = frame.seq;
306
+ if (typeof seq === "number" && state.lastSeq !== null && seq <= state.lastSeq) {
307
+ return { state, ops: [] };
308
+ }
309
+ const seen = typeof seq === "number" ? { ...state, lastSeq: Math.max(seq, state.lastSeq ?? seq) } : state;
310
+ if (seen.ended) {
311
+ return { state: seen, ops: [] };
312
+ }
313
+ switch (frame.type) {
314
+ case "chunk": {
315
+ const content = frame.content;
316
+ if (typeof content !== "string" || content.length === 0) {
317
+ return { state: seen, ops: [] };
318
+ }
319
+ if (frame.thinking === true) {
320
+ return { state: seen, ops: [] };
321
+ }
322
+ const ops = [];
323
+ let next = seen;
324
+ if (!next.typingSent && !next.streamOpen) {
325
+ ops.push({ kind: "typing" });
326
+ next = { ...next, typingSent: true };
327
+ }
328
+ next = { ...next, carry: next.carry + content };
329
+ const flushed = flushText(next, nowMs, frame.done === true);
330
+ return { state: flushed.state, ops: [...ops, ...flushed.ops] };
331
+ }
332
+ case "tool_call_update":
333
+ return statusOps(seen, toolLine(frame));
334
+ case "task_update":
335
+ return statusOps(seen, taskLine(frame));
336
+ case "planning_update":
337
+ return statusOps(seen, planningLine(frame));
338
+ case "node_update":
339
+ return statusOps(seen, nodeLine(frame));
340
+ case "job_update":
341
+ return statusOps(seen, jobLine(frame));
342
+ case "output_update": {
343
+ const assets = collectAssetRefs(frame.value);
344
+ return {
345
+ state: seen,
346
+ ops: assets.map((asset) => ({ kind: "attach", asset }))
347
+ };
348
+ }
349
+ case "message": {
350
+ if (!isFinalMessage(frame)) {
351
+ return { state: seen, ops: [] };
352
+ }
353
+ const finalText = textOfMessage(frame);
354
+ const withText = seen.carry.length === 0 && finalText.length > 0
355
+ ? { ...seen, carry: finalText }
356
+ : seen;
357
+ const finished = finishText(withText, nowMs);
358
+ const ops = [...finished.ops];
359
+ const closed = closeStatus(finished.state, ops);
360
+ return { state: { ...closed, ended: true }, ops };
361
+ }
362
+ case "error": {
363
+ const ops = [];
364
+ let next = seen;
365
+ if (next.carry.length > 0) {
366
+ const flushed = finishText(next, nowMs);
367
+ ops.push(...flushed.ops);
368
+ next = flushed.state;
369
+ }
370
+ const line = `⚠️ ${frame.message}`;
371
+ const rendered = present(line);
372
+ ops.push({
373
+ kind: "finalize",
374
+ target: "status",
375
+ text: rendered.text,
376
+ parseMode: rendered.parseMode,
377
+ create: !next.statusOpen
378
+ });
379
+ return {
380
+ state: { ...next, ended: true, statusOpen: false, status: line, statusRendered: null },
381
+ ops
382
+ };
383
+ }
384
+ case "generation_stopped": {
385
+ const finished = finishText(seen, nowMs);
386
+ const ops = [...finished.ops];
387
+ const closed = closeStatus(finished.state, ops);
388
+ ops.push({ kind: "stop-note", text: "⏹ stopped" });
389
+ return { state: { ...closed, ended: true }, ops };
390
+ }
391
+ default:
392
+ return { state: seen, ops: [] };
393
+ }
394
+ }
395
+ /** Fold a whole sequence of frames, for tests and replay. */
396
+ export function foldFrames(state, frames) {
397
+ const ops = [];
398
+ let next = state;
399
+ for (const entry of frames) {
400
+ const result = foldFrame(next, entry.frame, entry.nowMs);
401
+ next = result.state;
402
+ ops.push(...result.ops);
403
+ }
404
+ return { state: next, ops };
405
+ }
406
+ export { TELEGRAM_MESSAGE_LIMIT };
407
+ //# sourceMappingURL=frame-renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-renderer.js","sourceRoot":"","sources":["../src/frame-renderer.ts"],"names":[],"mappings":"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"}