polygram 0.9.0-rc.4 → 0.9.0-rc.5
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/.claude-plugin/plugin.json +1 -1
- package/lib/db.js +14 -0
- package/lib/handlers/edit-correction.js +77 -0
- package/package.json +1 -1
- package/polygram.js +17 -0
|
@@ -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.
|
|
4
|
+
"version": "0.9.0-rc.5",
|
|
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",
|
package/lib/db.js
CHANGED
|
@@ -521,6 +521,20 @@ function wrap(db) {
|
|
|
521
521
|
`).run(status, chat_id, msg_id);
|
|
522
522
|
},
|
|
523
523
|
|
|
524
|
+
// 0.9.0: True when a specific inbound msg is still being processed
|
|
525
|
+
// by the SDK turn loop (handler_status in dispatched/processing).
|
|
526
|
+
// Used by the edit-correction injector — only inject a typo-fix
|
|
527
|
+
// note when the SDK actually still has the turn in flight.
|
|
528
|
+
isInboundLive({ chat_id, msg_id }) {
|
|
529
|
+
const row = db.prepare(`
|
|
530
|
+
SELECT 1 FROM messages
|
|
531
|
+
WHERE chat_id = ? AND msg_id = ? AND direction = 'in'
|
|
532
|
+
AND handler_status IN ('dispatched', 'processing')
|
|
533
|
+
LIMIT 1
|
|
534
|
+
`).get(chat_id, msg_id);
|
|
535
|
+
return !!row;
|
|
536
|
+
},
|
|
537
|
+
|
|
524
538
|
// Find inbound messages that were being processed when polygram stopped.
|
|
525
539
|
// Scoped by bot_name via the chat_id → config mapping, so each bot only
|
|
526
540
|
// replays its own turns on boot. Scoped by olderThanMs (default 3 min)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Edit-correction injector.
|
|
5
|
+
*
|
|
6
|
+
* When the user edits a Telegram message that's still being processed
|
|
7
|
+
* by the SDK turn loop, inject a correction note into the active turn
|
|
8
|
+
* via the same hook channel autosteer uses (pm.injectUserMessage,
|
|
9
|
+
* priority: 'next'). Lets users fix typos mid-turn without /stop +
|
|
10
|
+
* resend.
|
|
11
|
+
*
|
|
12
|
+
* Skipped when the turn already finished — at that point the
|
|
13
|
+
* conversation has moved on and re-opening it would confuse Claude
|
|
14
|
+
* more than help. Also skipped when the SDK session has been
|
|
15
|
+
* LRU-evicted (no live target to inject into).
|
|
16
|
+
*
|
|
17
|
+
* Architectural note: there's no polygram-side "buffer" to replace.
|
|
18
|
+
* pm.send and pm.injectUserMessage push the message text directly into
|
|
19
|
+
* the SDK's inputController AsyncIterable; once pushed, polygram has
|
|
20
|
+
* no way to retract it. So edit handling is always "inject correction
|
|
21
|
+
* note as additional context" — Claude reconciles.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
function createEditCorrectionInjector({
|
|
25
|
+
pm,
|
|
26
|
+
db,
|
|
27
|
+
getSessionKey,
|
|
28
|
+
config,
|
|
29
|
+
logEvent,
|
|
30
|
+
logger = console,
|
|
31
|
+
} = {}) {
|
|
32
|
+
|
|
33
|
+
return function maybeInjectEditCorrection(editedMsg) {
|
|
34
|
+
if (!editedMsg?.chat) return false;
|
|
35
|
+
const chatId = editedMsg.chat.id.toString();
|
|
36
|
+
const chatConfig = config.chats[chatId];
|
|
37
|
+
if (!chatConfig) return false;
|
|
38
|
+
|
|
39
|
+
// Per-chat / bot-level opt-out. Default on.
|
|
40
|
+
const optOut = chatConfig.editCorrection != null
|
|
41
|
+
? chatConfig.editCorrection === false
|
|
42
|
+
: config.bot?.editCorrection === false;
|
|
43
|
+
if (optOut) return false;
|
|
44
|
+
|
|
45
|
+
const threadIdStr = editedMsg.message_thread_id?.toString() || null;
|
|
46
|
+
const sessionKey = getSessionKey(chatId, threadIdStr, chatConfig);
|
|
47
|
+
|
|
48
|
+
// Three skip gates — all must be true for an injection:
|
|
49
|
+
// 1. SDK session exists (not LRU-evicted)
|
|
50
|
+
// 2. session has a turn in flight
|
|
51
|
+
// 3. the edited msg is still in the dispatched/processing pipeline
|
|
52
|
+
if (!pm.has(sessionKey)) return false;
|
|
53
|
+
if (!pm.get(sessionKey)?.inFlight) return false;
|
|
54
|
+
if (!db.isInboundLive({ chat_id: chatId, msg_id: editedMsg.message_id })) return false;
|
|
55
|
+
|
|
56
|
+
const newText = editedMsg.text || editedMsg.caption || '';
|
|
57
|
+
if (!newText) return false;
|
|
58
|
+
|
|
59
|
+
const ok = pm.injectUserMessage(sessionKey, {
|
|
60
|
+
content: `[edit] I corrected my previous message — it now reads: ${newText}`,
|
|
61
|
+
priority: 'next',
|
|
62
|
+
});
|
|
63
|
+
if (!ok) {
|
|
64
|
+
logger.error?.(`[${chatConfig.name || chatId}] edit-correction inject failed`);
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
logEvent('message-edit-injected', {
|
|
68
|
+
chat_id: chatId,
|
|
69
|
+
msg_id: editedMsg.message_id,
|
|
70
|
+
session_key: sessionKey,
|
|
71
|
+
text_len: newText.length,
|
|
72
|
+
});
|
|
73
|
+
return true;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = { createEditCorrectionInjector };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polygram",
|
|
3
|
-
"version": "0.9.0-rc.
|
|
3
|
+
"version": "0.9.0-rc.5",
|
|
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
|
@@ -44,6 +44,7 @@ const { createDownloadAttachments } = require('./lib/handlers/download');
|
|
|
44
44
|
const { createHandleConfigCallback } = require('./lib/handlers/config-callback');
|
|
45
45
|
const { createHandleAbort } = require('./lib/handlers/abort');
|
|
46
46
|
const { createAutosteerHandlers } = require('./lib/handlers/autosteer');
|
|
47
|
+
const { createEditCorrectionInjector } = require('./lib/handlers/edit-correction');
|
|
47
48
|
const { createSlashCommands } = require('./lib/handlers/slash-commands');
|
|
48
49
|
const { createApprovals } = require('./lib/handlers/approvals');
|
|
49
50
|
const { canonicalizeToolInput } = require('./lib/canonical-json');
|
|
@@ -525,6 +526,7 @@ let handleConfigCallback = null;
|
|
|
525
526
|
let handleAbortIfRequested = null;
|
|
526
527
|
let autosteer = null;
|
|
527
528
|
let dispatchSlashCommand = null;
|
|
529
|
+
let maybeInjectEditCorrection = null;
|
|
528
530
|
|
|
529
531
|
// rc.20: approvalCardText + safeParse moved to lib/approvals/ui.js.
|
|
530
532
|
// 0.9.0 commit 29: makeCanUseTool / handleApprovalCallback /
|
|
@@ -1702,6 +1704,18 @@ function createBot(token) {
|
|
|
1702
1704
|
user_id: ctx.editedMessage.from?.id || null,
|
|
1703
1705
|
});
|
|
1704
1706
|
console.log(`[${BOT_NAME}] edited ${chatId}/${ctx.editedMessage.message_id}`);
|
|
1707
|
+
|
|
1708
|
+
// 0.9.0: typo-correction injection. If the SDK still has this turn
|
|
1709
|
+
// in flight (handler_status in dispatched/processing AND
|
|
1710
|
+
// pm.get(sk).inFlight), inject a `[edit] corrected: <NEW>` note
|
|
1711
|
+
// via the same channel autosteer uses. Lets users fix typos
|
|
1712
|
+
// mid-turn without /stop + resend. No-op when the turn already
|
|
1713
|
+
// completed.
|
|
1714
|
+
try {
|
|
1715
|
+
maybeInjectEditCorrection?.(ctx.editedMessage);
|
|
1716
|
+
} catch (err) {
|
|
1717
|
+
console.error(`[${BOT_NAME}] edit-correction injector error: ${err.message}`);
|
|
1718
|
+
}
|
|
1705
1719
|
});
|
|
1706
1720
|
|
|
1707
1721
|
bot.on('message:migrate_to_chat_id', async (ctx) => {
|
|
@@ -1955,6 +1969,9 @@ async function main() {
|
|
|
1955
1969
|
autosteer = createAutosteerHandlers({
|
|
1956
1970
|
config, pm, autosteeredRefs, logEvent,
|
|
1957
1971
|
});
|
|
1972
|
+
maybeInjectEditCorrection = createEditCorrectionInjector({
|
|
1973
|
+
pm, db, getSessionKey, config, logEvent, logger: console,
|
|
1974
|
+
});
|
|
1958
1975
|
recordInbound = createRecordInbound({
|
|
1959
1976
|
db, dbWrite, config, botName: BOT_NAME, extractAttachments,
|
|
1960
1977
|
});
|