polygram 0.9.0-rc.5 → 0.9.0-rc.6

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
3
  "name": "polygram",
4
- "version": "0.9.0-rc.5",
4
+ "version": "0.9.0-rc.6",
5
5
  "description": "Telegram integration for Claude Code that preserves the OpenClaw per-chat session model. Migration target for OpenClaw users. Multi-bot, multi-chat, per-topic isolation; SQLite transcripts; inline-keyboard approvals. Bundles /polygram:status|logs|pair-code|approvals admin commands plus history (transcript queries) and polygram-send (out-of-turn IPC sends with file-upload validation) skills.",
6
6
  "keywords": [
7
7
  "telegram",
@@ -41,7 +41,13 @@ function createDispatcher({
41
41
  autoResumeTracker, // lib/db/auto-resume.js instance
42
42
  chunkMarkdownText, // lib/telegram/chunk.js
43
43
  deliverReplies, // lib/telegram/deliver.js
44
- TG_MAX_LEN = 4096,
44
+ // Raw-markdown size budget for chunkMarkdownText. Set BELOW Telegram's
45
+ // 4096 hard limit to leave headroom for HTML inflation (toTelegramHtml
46
+ // adds <b>/<i>/<code> tags + entity escapes; ~10-15% in practice).
47
+ // Polygram passes TG_CHUNK_BUDGET (default 3500). Test default keeps
48
+ // the historic 4096 for back-compat in synthetic test runs that pass
49
+ // pre-formatted text.
50
+ chunkBudget = 4096,
45
51
  // State accessors (need late binding because polygram.js mutates):
46
52
  getIsShuttingDown, // () → boolean
47
53
  logger = console,
@@ -119,7 +125,7 @@ function createDispatcher({
119
125
 
120
126
  // 4. Send the continuation reply as regular Telegram messages,
121
127
  // threaded under the original user message.
122
- const chunks = chunkMarkdownText(result.text, TG_MAX_LEN);
128
+ const chunks = chunkMarkdownText(result.text, chunkBudget);
123
129
  await deliverReplies({
124
130
  bot,
125
131
  send: (b, method, params, m) => tg(b, method, params, m),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polygram",
3
- "version": "0.9.0-rc.5",
3
+ "version": "0.9.0-rc.6",
4
4
  "description": "Telegram daemon for Claude Code that preserves the OpenClaw per-chat session model. Migration path for OpenClaw users moving to Claude Code.",
5
5
  "main": "lib/ipc/client.js",
6
6
  "bin": {
package/polygram.js CHANGED
@@ -109,6 +109,15 @@ const CLAUDE_BIN = process.env.POLYGRAM_CLAUDE_BIN
109
109
  || path.join(process.env.HOME || '', '.npm-global/bin/claude');
110
110
  const CHILD_HOME = process.env.POLYGRAM_CHILD_HOME || process.env.HOME || '';
111
111
  const TG_MAX_LEN = 4096;
112
+ // 0.9.0-rc.6: chunker budget is intentionally lower than TG_MAX_LEN to
113
+ // leave HTML headroom. toTelegramHtml converts markdown to HTML for
114
+ // parse_mode=HTML — that conversion adds <b>/<i>/<code>/<a> tags and
115
+ // entity-escapes &/</> chars, inflating length by ~10-15% for realistic
116
+ // markdown. 2026-05-11 incident proved a 4044-char chunk inflated to
117
+ // 4506 HTML chars and Telegram rejected. 3500 raw → max ~4030 HTML on
118
+ // observed inputs, with headroom for adversarial code-heavy text.
119
+ // Override via POLYGRAM_CHUNK_BUDGET if your traffic profile differs.
120
+ const TG_CHUNK_BUDGET = Number.parseInt(process.env.POLYGRAM_CHUNK_BUDGET, 10) || 3500;
112
121
  const DEFAULT_MAX_WARM_PROCS = 10;
113
122
 
114
123
  let stickerMap = {}; // name → file_id
@@ -1253,7 +1262,7 @@ async function handleMessage(sessionKey, chatId, msg, bot) {
1253
1262
  // send the body as proper chunks.
1254
1263
  try { await streamer.discard(); }
1255
1264
  catch (err) { console.error(`[${label}] discard failed: ${err.message}`); }
1256
- const chunks = chunkMarkdownText(parsed.text, TG_MAX_LEN);
1265
+ const chunks = chunkMarkdownText(parsed.text, TG_CHUNK_BUDGET);
1257
1266
  const r = await deliverReplies({
1258
1267
  bot,
1259
1268
  send: (b, method, params, m) => tg(b, method, params, m),
@@ -1319,7 +1328,7 @@ async function handleMessage(sessionKey, chatId, msg, bot) {
1319
1328
  // 0.7.0: use markdown-aware chunker + deliverReplies primitive.
1320
1329
  // The old chunkText was newline/byte-only; chunkMarkdownText also
1321
1330
  // respects code-fence boundaries (closes + reopens across chunks).
1322
- const chunks = chunkMarkdownText(parsed.text, TG_MAX_LEN);
1331
+ const chunks = chunkMarkdownText(parsed.text, TG_CHUNK_BUDGET);
1323
1332
  await deliverReplies({
1324
1333
  bot,
1325
1334
  send: (b, method, params, m) => tg(b, method, params, m),
@@ -1990,7 +1999,7 @@ async function main() {
1990
1999
  classifyError, isAutoResumable,
1991
2000
  abortGrace, autoResumeTracker,
1992
2001
  chunkMarkdownText, deliverReplies,
1993
- TG_MAX_LEN,
2002
+ chunkBudget: TG_CHUNK_BUDGET,
1994
2003
  getIsShuttingDown: () => isShuttingDown,
1995
2004
  logger: console,
1996
2005
  }));