polygram 0.10.0-rc.36 → 0.10.0-rc.38
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.10.0-rc.
|
|
4
|
+
"version": "0.10.0-rc.38",
|
|
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/sdk/callbacks.js
CHANGED
|
@@ -344,13 +344,27 @@ function createSdkCallbacks({
|
|
|
344
344
|
}
|
|
345
345
|
},
|
|
346
346
|
|
|
347
|
-
// 0.10.0 H1 (observer-only): tmux backend
|
|
348
|
-
//
|
|
349
|
-
//
|
|
347
|
+
// 0.10.0 H1 (observer-only) + H2 (reactor wiring): tmux backend
|
|
348
|
+
// hook-based turn observability + status.
|
|
349
|
+
//
|
|
350
|
+
// H1: TmuxProcess emits `hook-event` with normalized HookEvent
|
|
351
|
+
// records for every claude-CLI hook firing (PreToolUse,
|
|
350
352
|
// PostToolUse, UserPromptSubmit, Stop, SubagentStop, Notification,
|
|
351
|
-
// plus `unknown` for any schema drift). Persisted compact
|
|
352
|
-
// soak
|
|
353
|
-
//
|
|
353
|
+
// plus `unknown` for any schema drift). Persisted compact for
|
|
354
|
+
// forensic soak analysis.
|
|
355
|
+
//
|
|
356
|
+
// H2: routes hook events to the head pending's reactor so the
|
|
357
|
+
// Telegram emoji reflects what claude is actually doing — incl.
|
|
358
|
+
// subagent-inner tool fires (PreToolUse with `agent_id`) that
|
|
359
|
+
// JSONL `tool-use` never surfaces. The win: long subagent turns
|
|
360
|
+
// stop tripping the 🥱→😨→🤯 escalation because each inner
|
|
361
|
+
// PostToolUse / SubagentStop / Notification heartbeats the
|
|
362
|
+
// reactor, proving the agent is alive.
|
|
363
|
+
//
|
|
364
|
+
// Augments — does NOT replace — the existing JSONL-driven
|
|
365
|
+
// `onToolUse` setState and stream-chunk heartbeats. Duplicate
|
|
366
|
+
// setState for the same state is a no-op in the reactor; the
|
|
367
|
+
// throttle/cascade timers are unchanged.
|
|
354
368
|
//
|
|
355
369
|
// Fields persisted are intentionally narrow: identity + tool/
|
|
356
370
|
// subagent scoping + `duration_ms` (free per-tool latency from
|
|
@@ -359,8 +373,9 @@ function createSdkCallbacks({
|
|
|
359
373
|
// (`tool_input`, full `tool_response`, `last_assistant_message`)
|
|
360
374
|
// are NOT persisted to the events DB — they'd inflate row size
|
|
361
375
|
// without informing the soak.
|
|
362
|
-
onHookEvent: (sessionKey, payload
|
|
376
|
+
onHookEvent: (sessionKey, payload, entry) => {
|
|
363
377
|
try {
|
|
378
|
+
// ── H1: DB persist ────────────────────────────────────────
|
|
364
379
|
const detail = {
|
|
365
380
|
chat_id: getChatIdFromKey(sessionKey),
|
|
366
381
|
session_key: sessionKey,
|
|
@@ -387,6 +402,58 @@ function createSdkCallbacks({
|
|
|
387
402
|
detail.parse_error = payload?.error ?? null;
|
|
388
403
|
}
|
|
389
404
|
logEvent('hook-event', detail);
|
|
405
|
+
|
|
406
|
+
// ── H2: route to reactor ──────────────────────────────────
|
|
407
|
+
//
|
|
408
|
+
// The reactor lives on the HEAD pending's per-turn context
|
|
409
|
+
// (same shape as `onToolUse` and `onStreamChunk`). Hook
|
|
410
|
+
// events from claude can land in three windows relative to
|
|
411
|
+
// a polygram turn:
|
|
412
|
+
// 1. Mid-turn (the normal case) — head exists, reactor
|
|
413
|
+
// lives, route the event.
|
|
414
|
+
// 2. Between turns / before head is set — head is null,
|
|
415
|
+
// skip silently. The next setState from polygram-side
|
|
416
|
+
// turn lifecycle will recover.
|
|
417
|
+
// 3. UserPromptSubmit fires BEFORE polygram's
|
|
418
|
+
// reactor.setState('THINKING') in some races; that's
|
|
419
|
+
// fine because UserPromptSubmit is intentionally a
|
|
420
|
+
// no-op here (the existing turn-start path owns it).
|
|
421
|
+
const head = entry?.pendingQueue?.[0];
|
|
422
|
+
const reactor = head?.context?.reactor;
|
|
423
|
+
if (!reactor) return;
|
|
424
|
+
|
|
425
|
+
switch (payload?.type) {
|
|
426
|
+
case 'PreToolUse':
|
|
427
|
+
// PreToolUse fires for main-agent AND subagent-inner
|
|
428
|
+
// tools (the latter scoped by `agent_id`). The reactor
|
|
429
|
+
// doesn't care WHO ran the tool, only WHAT — so
|
|
430
|
+
// classifyToolName drives the state regardless of
|
|
431
|
+
// agent context.
|
|
432
|
+
if (payload.toolName) {
|
|
433
|
+
reactor.setState(classifyToolName(payload.toolName));
|
|
434
|
+
}
|
|
435
|
+
break;
|
|
436
|
+
|
|
437
|
+
case 'PostToolUse':
|
|
438
|
+
case 'SubagentStop':
|
|
439
|
+
case 'Notification':
|
|
440
|
+
// Liveness signals — each one proves the agent is still
|
|
441
|
+
// making progress. Heartbeat resets the STALL (🥱) and
|
|
442
|
+
// TIMEOUT (😨) timers, killing the fear escalation on
|
|
443
|
+
// long healthy turns that was the motivating msg-884
|
|
444
|
+
// incident.
|
|
445
|
+
if (typeof reactor.heartbeat === 'function') {
|
|
446
|
+
reactor.heartbeat();
|
|
447
|
+
}
|
|
448
|
+
break;
|
|
449
|
+
|
|
450
|
+
// UserPromptSubmit, Stop, unknown, parse-error: no
|
|
451
|
+
// reactor routing. Turn lifecycle owns start/clear; the
|
|
452
|
+
// observer-only H1 DB persist above still records them
|
|
453
|
+
// for forensics.
|
|
454
|
+
default:
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
390
457
|
} catch (err) {
|
|
391
458
|
logger.error?.(`[${botName}] hook-event handler: ${err.message}`);
|
|
392
459
|
}
|
|
@@ -57,6 +57,17 @@ const POLYGRAM_DISPLAY_HINT = [
|
|
|
57
57
|
'- Headers `#`, `##`, `###` render as plain text — use **bold** for emphasis.',
|
|
58
58
|
'- Horizontal rules render as a thin divider line.',
|
|
59
59
|
'- Long replies stream in chunks; prefer concise structure over walls of text.',
|
|
60
|
+
'',
|
|
61
|
+
'### NEVER emit shell-context canned strings — HARD RULE',
|
|
62
|
+
'',
|
|
63
|
+
'You are running as a Telegram chat bot, NOT as a script being piped into a shell. Certain phrases are CLI-context boilerplate from the underlying environment and MUST NEVER appear in a reply, because the user sees them as a literal message from you and they look like a system error:',
|
|
64
|
+
'',
|
|
65
|
+
'- `No response requested.`',
|
|
66
|
+
'- `No response needed.`',
|
|
67
|
+
'- `Continuing...` as a standalone reply',
|
|
68
|
+
'- Any other shell-prompt-style filler that acknowledges silence',
|
|
69
|
+
'',
|
|
70
|
+
'If a user message is short, ambiguous, or feels like a no-op acknowledgement (e.g. `okay`, `ok`, `yes`, `got it`, `thanks`), reply with a brief substantive line — acknowledge what you understood and what (if anything) you will do next. If you genuinely have nothing useful to say, ask ONE specific clarifying question. NEVER emit a placeholder or a shell-style canned string — the chat surface has no silent-no-op state. Every reply must be intentional content.',
|
|
60
71
|
].join('\n');
|
|
61
72
|
|
|
62
73
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polygram",
|
|
3
|
-
"version": "0.10.0-rc.
|
|
3
|
+
"version": "0.10.0-rc.38",
|
|
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": {
|