@intentface/latch-channels 0.9.1 → 0.10.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentface/latch-channels",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Latch channels — bring a Latch agent to chat platforms (Slack first). A generic run→render-event projection plus per-platform adapters, reusing the core runtime, storage and durability (no separate state store).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"registry": "https://registry.npmjs.org"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@intentface/latch-core": "^0.
|
|
47
|
+
"@intentface/latch-core": "^0.10.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"ai": ">=7.0.0"
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { RenderEvent } from "../types.js";
|
|
2
|
-
import { type TelegramClient } from "./api.js";
|
|
3
|
-
/**
|
|
4
|
-
* The streaming-edit engine: Telegram (unlike Slack) can edit a sent message,
|
|
5
|
-
* so the answer streams as progressive `editMessageText` calls on one message.
|
|
6
|
-
*
|
|
7
|
-
* sendChatAction("typing") on start.
|
|
8
|
-
* First text-delta → sendMessage; keep the message_id.
|
|
9
|
-
* Buffer deltas; flush when ≥`minEditIntervalMs` since the last edit OR
|
|
10
|
-
* ≥`minEditChars` new chars. On 429, honor `retry_after` and resume.
|
|
11
|
-
* tool-start folds a status line into the draft; tool-end clears it.
|
|
12
|
-
* At `maxChars` stop growing, append the truncation notice (one message,
|
|
13
|
-
* never a spill-over second one), and keep draining events without editing.
|
|
14
|
-
* finish/error → final flush (status line removed, error appended).
|
|
15
|
-
*
|
|
16
|
-
* Renders HTML (`parse_mode: "HTML"`); if Telegram rejects the entity parse
|
|
17
|
-
* (400), the same content is retried as plain text and the message stays
|
|
18
|
-
* plain for the rest of the turn.
|
|
19
|
-
*/
|
|
20
|
-
export declare const MAX_TELEGRAM_TEXT_CHARS = 4000;
|
|
21
|
-
export declare const TELEGRAM_TEXT_TRUNCATION_NOTICE = "\n\n_Response truncated for Telegram. The full turn is available in Latch._";
|
|
22
|
-
export interface TelegramStreamOptions {
|
|
23
|
-
api: Pick<TelegramClient, "sendMessage" | "editMessageText" | "sendChatAction">;
|
|
24
|
-
chatId: number | string;
|
|
25
|
-
maxChars?: number;
|
|
26
|
-
truncationNotice?: string;
|
|
27
|
-
minEditIntervalMs?: number;
|
|
28
|
-
minEditChars?: number;
|
|
29
|
-
/** Injectable clock/sleep for tests. */
|
|
30
|
-
now?: () => number;
|
|
31
|
-
sleep?: (ms: number) => Promise<void>;
|
|
32
|
-
}
|
|
33
|
-
export interface TelegramStreamResult {
|
|
34
|
-
/** The full accumulated answer text (pre-truncation). */
|
|
35
|
-
text: string;
|
|
36
|
-
errorMessage?: string;
|
|
37
|
-
messageId?: number;
|
|
38
|
-
}
|
|
39
|
-
export declare function renderTelegramStream(events: AsyncIterable<RenderEvent>, opts: TelegramStreamOptions): Promise<TelegramStreamResult>;
|
|
40
|
-
/** Compose the approval-prompt text (HTML) for a tool awaiting approval. */
|
|
41
|
-
export declare function approvalPromptHtml(toolName: string, input: unknown): string;
|
|
42
|
-
/** Button caption for an option — ticked marker for multi-select, length-capped. */
|
|
43
|
-
export declare function optionButtonText(label: string, ticked?: boolean): string;
|
|
44
|
-
/**
|
|
45
|
-
* Compose one question of a questionnaire (HTML). Option *labels* go on the
|
|
46
|
-
* buttons; the descriptions only fit in the body, numbered so a typed "2" is an
|
|
47
|
-
* unambiguous answer.
|
|
48
|
-
*/
|
|
49
|
-
export declare function questionPromptHtml(question: {
|
|
50
|
-
question: string;
|
|
51
|
-
header?: string;
|
|
52
|
-
options: {
|
|
53
|
-
label: string;
|
|
54
|
-
description: string;
|
|
55
|
-
}[];
|
|
56
|
-
}, index: number, total: number): string;
|
|
57
|
-
/** Collapse an answered question card to a one-line receipt. */
|
|
58
|
-
export declare function answeredQuestionHtml(question: string, answer: string): string;
|
|
59
|
-
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/telegram/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAGjE;;;;;;;;;;;;;;;;GAgBG;AAEH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,+BAA+B,gFACmC,CAAC;AAEhF,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,aAAa,GAAG,iBAAiB,GAAG,gBAAgB,CAAC,CAAC;IAChF,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,oBAAoB;IACnC,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,EAClC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,oBAAoB,CAAC,CAiH/B;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAS3E;AAKD,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAIxE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,EAClG,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,MAAM,CAYR;AAED,gEAAgE;AAChE,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE7E"}
|
package/dist/telegram/stream.js
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import { TelegramApiError } from "./api.js";
|
|
2
|
-
import { escapeHtml, gfmToTelegramHtml } from "./html.js";
|
|
3
|
-
/**
|
|
4
|
-
* The streaming-edit engine: Telegram (unlike Slack) can edit a sent message,
|
|
5
|
-
* so the answer streams as progressive `editMessageText` calls on one message.
|
|
6
|
-
*
|
|
7
|
-
* sendChatAction("typing") on start.
|
|
8
|
-
* First text-delta → sendMessage; keep the message_id.
|
|
9
|
-
* Buffer deltas; flush when ≥`minEditIntervalMs` since the last edit OR
|
|
10
|
-
* ≥`minEditChars` new chars. On 429, honor `retry_after` and resume.
|
|
11
|
-
* tool-start folds a status line into the draft; tool-end clears it.
|
|
12
|
-
* At `maxChars` stop growing, append the truncation notice (one message,
|
|
13
|
-
* never a spill-over second one), and keep draining events without editing.
|
|
14
|
-
* finish/error → final flush (status line removed, error appended).
|
|
15
|
-
*
|
|
16
|
-
* Renders HTML (`parse_mode: "HTML"`); if Telegram rejects the entity parse
|
|
17
|
-
* (400), the same content is retried as plain text and the message stays
|
|
18
|
-
* plain for the rest of the turn.
|
|
19
|
-
*/
|
|
20
|
-
export const MAX_TELEGRAM_TEXT_CHARS = 4000;
|
|
21
|
-
export const TELEGRAM_TEXT_TRUNCATION_NOTICE = "\n\n_Response truncated for Telegram. The full turn is available in Latch._";
|
|
22
|
-
const defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
23
|
-
export async function renderTelegramStream(events, opts) {
|
|
24
|
-
const maxChars = opts.maxChars ?? MAX_TELEGRAM_TEXT_CHARS;
|
|
25
|
-
const notice = opts.truncationNotice ?? TELEGRAM_TEXT_TRUNCATION_NOTICE;
|
|
26
|
-
const minInterval = opts.minEditIntervalMs ?? 1500;
|
|
27
|
-
const minChars = opts.minEditChars ?? 500;
|
|
28
|
-
const now = opts.now ?? Date.now;
|
|
29
|
-
const sleep = opts.sleep ?? defaultSleep;
|
|
30
|
-
let text = "";
|
|
31
|
-
let truncated = false;
|
|
32
|
-
let statusLine = "";
|
|
33
|
-
let errorMessage;
|
|
34
|
-
let messageId;
|
|
35
|
-
let lastSent = "";
|
|
36
|
-
let lastFlushAt = 0;
|
|
37
|
-
let charsSinceFlush = 0;
|
|
38
|
-
let plainFallback = false;
|
|
39
|
-
function compose(final) {
|
|
40
|
-
let body = truncated ? text.slice(0, maxChars) + notice : text;
|
|
41
|
-
if (!final && statusLine)
|
|
42
|
-
body += `\n\n⏳ ${statusLine}`;
|
|
43
|
-
if (final && errorMessage)
|
|
44
|
-
body += `${body ? "\n\n" : ""}⚠️ ${errorMessage.slice(0, 500)}`;
|
|
45
|
-
return { html: gfmToTelegramHtml(body), plain: body };
|
|
46
|
-
}
|
|
47
|
-
async function send(content) {
|
|
48
|
-
const attempt = async () => {
|
|
49
|
-
const input = plainFallback
|
|
50
|
-
? { chat_id: opts.chatId, text: content.plain }
|
|
51
|
-
: {
|
|
52
|
-
chat_id: opts.chatId,
|
|
53
|
-
text: content.html,
|
|
54
|
-
parse_mode: "HTML",
|
|
55
|
-
link_preview_options: { is_disabled: true },
|
|
56
|
-
};
|
|
57
|
-
if (messageId === undefined) {
|
|
58
|
-
messageId = (await opts.api.sendMessage(input)).messageId;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
await opts.api.editMessageText({ ...input, message_id: messageId });
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
try {
|
|
65
|
-
await attempt();
|
|
66
|
-
}
|
|
67
|
-
catch (e) {
|
|
68
|
-
if (e instanceof TelegramApiError && e.status === 429) {
|
|
69
|
-
await sleep((e.retryAfter ?? 3) * 1000);
|
|
70
|
-
await attempt();
|
|
71
|
-
}
|
|
72
|
-
else if (e instanceof TelegramApiError && e.status === 400 && !plainFallback) {
|
|
73
|
-
// Almost always an entity-parse failure on partial markdown → go plain.
|
|
74
|
-
plainFallback = true;
|
|
75
|
-
await attempt();
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
throw e;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
async function flush(final) {
|
|
83
|
-
const content = compose(final);
|
|
84
|
-
const key = plainFallback ? content.plain : content.html;
|
|
85
|
-
if (!key.trim() || key === lastSent)
|
|
86
|
-
return;
|
|
87
|
-
try {
|
|
88
|
-
await send(content);
|
|
89
|
-
lastSent = plainFallback ? content.plain : content.html;
|
|
90
|
-
lastFlushAt = now();
|
|
91
|
-
charsSinceFlush = 0;
|
|
92
|
-
}
|
|
93
|
-
catch (e) {
|
|
94
|
-
if (final)
|
|
95
|
-
throw e;
|
|
96
|
-
console.error("[telegram] stream flush failed (will retry on next flush):", e);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
await opts.api.sendChatAction(opts.chatId, "typing");
|
|
100
|
-
for await (const ev of events) {
|
|
101
|
-
switch (ev.type) {
|
|
102
|
-
case "text-delta":
|
|
103
|
-
if (!truncated) {
|
|
104
|
-
text += ev.text;
|
|
105
|
-
charsSinceFlush += ev.text.length;
|
|
106
|
-
if (text.length > maxChars)
|
|
107
|
-
truncated = true;
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
text += ev.text; // keep accumulating for the caller; stop editing
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
break;
|
|
114
|
-
case "tool-start":
|
|
115
|
-
statusLine = `Running ${ev.toolName}…`;
|
|
116
|
-
charsSinceFlush += minChars; // status changes flush on the next check
|
|
117
|
-
break;
|
|
118
|
-
case "tool-end":
|
|
119
|
-
statusLine = "";
|
|
120
|
-
charsSinceFlush += minChars;
|
|
121
|
-
break;
|
|
122
|
-
case "error":
|
|
123
|
-
errorMessage = ev.message;
|
|
124
|
-
continue;
|
|
125
|
-
default:
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
const due = now() - lastFlushAt >= minInterval || charsSinceFlush >= minChars;
|
|
129
|
-
// Create the message promptly on first content; then throttle edits.
|
|
130
|
-
if ((messageId === undefined && text.trim()) || (messageId !== undefined && due)) {
|
|
131
|
-
await flush(false);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
statusLine = "";
|
|
135
|
-
await flush(true);
|
|
136
|
-
const result = { text };
|
|
137
|
-
if (errorMessage !== undefined)
|
|
138
|
-
result.errorMessage = errorMessage;
|
|
139
|
-
if (messageId !== undefined)
|
|
140
|
-
result.messageId = messageId;
|
|
141
|
-
return result;
|
|
142
|
-
}
|
|
143
|
-
/** Compose the approval-prompt text (HTML) for a tool awaiting approval. */
|
|
144
|
-
export function approvalPromptHtml(toolName, input) {
|
|
145
|
-
let json;
|
|
146
|
-
try {
|
|
147
|
-
json = JSON.stringify(input, null, 2) ?? String(input);
|
|
148
|
-
}
|
|
149
|
-
catch {
|
|
150
|
-
json = String(input);
|
|
151
|
-
}
|
|
152
|
-
if (json.length > 2500)
|
|
153
|
-
json = `${json.slice(0, 2500)}\n… (truncated)`;
|
|
154
|
-
return `🔒 Approve <b>${escapeHtml(toolName)}</b>?\n\n<pre>${escapeHtml(json)}</pre>`;
|
|
155
|
-
}
|
|
156
|
-
/** Longest option label Telegram renders comfortably on a button. */
|
|
157
|
-
const MAX_BUTTON_LABEL = 40;
|
|
158
|
-
/** Button caption for an option — ticked marker for multi-select, length-capped. */
|
|
159
|
-
export function optionButtonText(label, ticked) {
|
|
160
|
-
const short = label.length > MAX_BUTTON_LABEL ? `${label.slice(0, MAX_BUTTON_LABEL - 1)}…` : label;
|
|
161
|
-
return ticked === undefined ? short : `${ticked ? "✓ " : " "}${short}`;
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Compose one question of a questionnaire (HTML). Option *labels* go on the
|
|
165
|
-
* buttons; the descriptions only fit in the body, numbered so a typed "2" is an
|
|
166
|
-
* unambiguous answer.
|
|
167
|
-
*/
|
|
168
|
-
export function questionPromptHtml(question, index, total) {
|
|
169
|
-
const head = total > 1 ? `<b>Question ${index + 1} of ${total}</b>\n` : "";
|
|
170
|
-
const title = question.header
|
|
171
|
-
? `<i>${escapeHtml(question.header)}</i>\n${escapeHtml(question.question)}`
|
|
172
|
-
: escapeHtml(question.question);
|
|
173
|
-
const opts = question.options
|
|
174
|
-
.map((o, i) => {
|
|
175
|
-
const desc = o.description ? ` — ${escapeHtml(o.description)}` : "";
|
|
176
|
-
return `${i + 1}. <b>${escapeHtml(o.label)}</b>${desc}`;
|
|
177
|
-
})
|
|
178
|
-
.join("\n");
|
|
179
|
-
return `${head}${title}\n\n${opts}`;
|
|
180
|
-
}
|
|
181
|
-
/** Collapse an answered question card to a one-line receipt. */
|
|
182
|
-
export function answeredQuestionHtml(question, answer) {
|
|
183
|
-
return `✓ ${escapeHtml(question)}\n<b>${escapeHtml(answer)}</b>`;
|
|
184
|
-
}
|
|
185
|
-
//# sourceMappingURL=stream.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/telegram/stream.ts"],"names":[],"mappings":"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"}
|