@llblab/pi-telegram 0.28.0 → 0.29.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/AGENTS.md +2 -0
- package/CHANGELOG.md +5 -0
- package/README.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/outbound.md +2 -2
- package/docs/public-api.md +1 -1
- package/index.ts +2 -0
- package/lib/bindings.ts +0 -3
- package/lib/prompts.ts +3 -89
- package/lib/skills.ts +21 -0
- package/package.json +5 -1
- package/skills/button-console/SKILL.md +139 -0
- package/skills/telegram-bridge/SKILL.md +138 -0
package/AGENTS.md
CHANGED
|
@@ -42,6 +42,8 @@ Keep each fact in one authoritative layer:
|
|
|
42
42
|
- `/api/*.ts`: Stable public package membranes documented in `docs/public-api.md`.
|
|
43
43
|
- `/lib/*.ts`: Flat, cohesive runtime domains; package-private unless re-exported through `/api`.
|
|
44
44
|
- `/tests/*.test.ts`: Domain-mirrored suites; `tests/integration.test.ts` owns cross-domain runtime flows.
|
|
45
|
+
- `/skills/telegram-bridge`: Stable agent operating protocol for Telegram turns, delivery, actions, Threaded Mode, and diagnosis.
|
|
46
|
+
- `/skills/button-console`: Optional generated-button interface over truthful console evidence; it remains independent from the bridge skill.
|
|
45
47
|
- `/.agents/skills/telegram-bot`: Bot API lookup guidance and vendored `api.md`; keep the reference intact.
|
|
46
48
|
- `/.agents/skills/domain-dag`: Repository architecture guidance and validator.
|
|
47
49
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
> Each release keeps at most 8 outcome records of at most 512 characters.
|
|
4
4
|
|
|
5
|
+
## 0.29.0: Skill-First Agent Operation
|
|
6
|
+
|
|
7
|
+
- `Bundled Skills`: Added discoverable `telegram-bridge` and `button-console` Skills through package metadata and source-checkout resource discovery. Stable turn, delivery, action, Threaded Mode, formatting, handler, and diagnosis guidance now lives in the bridge Skill, while Button Console provides optional evidence-backed CLI navigation.
|
|
8
|
+
- `Model Context Contraction`: Removed the redundant `telegram_help` model tool and its repeated guidance implementation. Compact authority-aware prompts route agents to the bundled Skill, while disconnect/recovery now suppresses and restores only the two delivery tools without affecting foreign tools.
|
|
9
|
+
|
|
5
10
|
## 0.28.0: Durable Inbound And Protocol Reconstruction
|
|
6
11
|
|
|
7
12
|
- `Owned Polling Request`: Only `getUpdates` gets an automatic budget: Telegram long-poll timeout plus 10 seconds. Poller abort settles requests and API retry waits; broad ordinary, media, and follower budgets were removed.
|
package/README.md
CHANGED
|
@@ -257,7 +257,7 @@ Durable inbound admission is a **process-crash recovery** guarantee. Atomic priv
|
|
|
257
257
|
|
|
258
258
|
Telegram is a companion surface around a live Pi runtime, not a second runtime. It can compact the current session, but it cannot create, resume, fork, browse, or switch sessions until Pi exposes safe public extension APIs for those operations.
|
|
259
259
|
|
|
260
|
-
A Telegram prompt is a normal model turn in the active Pi session and therefore inherits that session's active post-compaction context; the bridge does not make token cost proportional only to the new mobile message.
|
|
260
|
+
A Telegram prompt is a normal model turn in the active Pi session and therefore inherits that session's active post-compaction context; the bridge does not make token cost proportional only to the new mobile message. The bundled `telegram-bridge` Skill owns agent operation and `button-console` provides optional generated-button CLI navigation. Disconnecting removes pi-telegram's delivery tools and transient routing guidance from later requests until direct ownership or follower registration returns, without changing other active Pi tools. Pi session JSONL contains model history; profile-scoped pi-telegram `logs*.jsonl` contains redacted operational events and is never model context.
|
|
261
261
|
|
|
262
262
|
## Documentation Map
|
|
263
263
|
|
package/docs/architecture.md
CHANGED
|
@@ -47,7 +47,7 @@ A Telegram destination follows a Pi instance, not an immutable Pi session file.
|
|
|
47
47
|
|
|
48
48
|
Pi session JSONL and pi-telegram runtime JSONL serve different purposes. Pi session files contain model conversation, tool, usage, branch, and compaction entries. Profile-scoped `logs.jsonl` / `logs.<profile>.jsonl` contain redacted bridge operations from one or more instances and never become model context. Sharing a Telegram profile or working directory does not by itself merge Pi session identities or model histories.
|
|
49
49
|
|
|
50
|
-
A Telegram prompt is a normal Pi model turn. It inherits the active post-compaction context just like a TUI prompt in the same session; pi-telegram does not promise context isolation or token cost proportional only to the new message.
|
|
50
|
+
A Telegram prompt is a normal Pi model turn. It inherits the active post-compaction context just like a TUI prompt in the same session; pi-telegram does not promise context isolation or token cost proportional only to the new message. The bundled `telegram-bridge` Skill owns agent operation, while a small authority-aware system note routes applicable turns to it. Existing session files created by older versions may still contain historical repeated guidance until session replacement or compaction removes it from active context.
|
|
51
51
|
|
|
52
52
|
The repository uses a **Flat Domain DAG**:
|
|
53
53
|
|
|
@@ -362,7 +362,7 @@ Complete intermediate assistant text blocks from Telegram-originated activity ar
|
|
|
362
362
|
|
|
363
363
|
`assistant.activity` is an independent bridge-owned projection over normalized Activity events. Each process reloads the shared file-backed setting at `agent-start` before activity admission, so multi-instance mode cannot continue projecting a stale broader process-local selection. Omitted values resolve to `verbose`, while invalid values fail closed to `quiet`; `thinking` and `tools` select one technical class, while `verbose` enables both. Provider-exposed thinking uses persistent ordinary HTML containing only a standard expandable blockquote with a bounded redacted latest-text window and inline Markdown rendered as Telegram HTML. Completed executed tools use native Rich Messages: each closed `<Tool>: <status>` root details node renders snake-case names as title words while preserving an uppercase two- or three-letter repeated prefix per word, then the native disclosure chevron reveals an open-by-default `arguments` child plus closed retained `update N` and `result`/`error` child details with lowercase monospaced, marker-free summaries and JSON pre blocks; known-safe Rich rejections fall back to the previous HTML disclosure. The projection captures the exact target and transport stamp at activity admission, serializes updates, preserves tool-start order, closes coalescing across assistant/thinking boundaries, bounds retained text/update memory plus edit frames and message/tool size, disables previews and HTTP(S) auto-link recognition inside technical evidence, and never replays a possibly committed send. Session generations own independent queues, so replacement drops queued old work without waiting on an old call. Both proactive prose and active-turn final delivery wait for the admitted activity queue inside their extension-owned delivery tasks, preserving technical-before-semantic ordering without delaying Pi lifecycle completion. Settlement, replacement, disconnect, failure, or stale authority clears only local ownership; already-sent activity messages remain in chat.
|
|
364
364
|
|
|
365
|
-
Telegram prompt guidance is context- and authority-aware. Only an exact direct owner or live registered follower exposes the
|
|
365
|
+
Telegram prompt guidance is context- and authority-aware. The package and source-checkout extension both contribute `telegram-bridge` plus the optional `button-console` Skill through Pi resource discovery. Only an exact direct owner or live registered follower exposes the two pi-telegram delivery tools, their active-tool metadata, and the compact routing suffix. Disconnect or authority loss removes those tool surfaces for subsequent requests without touching foreign tools; reconnect/recovery restores only the pi-telegram subset that was active before suspension, including across same-process reload. Telegram-originated turns route to the stable Skill contract and retain dynamic blocks such as `[voice] delivery: automatic voice`; the Skill and public documentation own syntax, target routing, Threaded Mode behavior, and diagnostics.
|
|
366
366
|
|
|
367
367
|
## In-Flight Model Switching
|
|
368
368
|
|
package/docs/outbound.md
CHANGED
|
@@ -176,8 +176,8 @@ Buttons are built in and do not need a command template because they are pure Te
|
|
|
176
176
|
The extension injects prompt guidance by context:
|
|
177
177
|
|
|
178
178
|
- If no bot token is configured, no Telegram bridge suffix is injected.
|
|
179
|
-
- For ordinary local/TUI prompts, the
|
|
180
|
-
- For Telegram-originated turns, the
|
|
179
|
+
- For ordinary local/TUI prompts, the compact routing note points to the bundled `telegram-bridge` Skill and forbids Telegram use unless explicitly requested.
|
|
180
|
+
- For Telegram-originated turns, the compact note routes the agent to `telegram-bridge`, which owns voice/button/direct-delivery/Threaded Mode/formatting/debug guidance.
|
|
181
181
|
- For Telegram-originated turns, write the full technical answer as normal Markdown.
|
|
182
182
|
- Add `telegram_voice` with either a JSON object or double-quoted attributes when a Telegram-native voice message is useful. A companion summary is optional, no specific summary format is required.
|
|
183
183
|
- Add `telegram_button` with either a JSON object or double-quoted attributes. Use `label` plus `prompt`, or `value` when they are identical; `selected_style` is optional. A button-only reply may omit parent text because the bridge supplies `☑️ **Choose an option:**` automatically.
|
package/docs/public-api.md
CHANGED
|
@@ -63,7 +63,7 @@ This command surface is a mobile companion subset, not a raw terminal-command br
|
|
|
63
63
|
|
|
64
64
|
- `telegram_attach(paths, chat_id?, thread_id?, caption?)` is the stable artifact delivery tool for generated files. During Telegram turns it queues files for the active reply; with `assistant.rendering: "rich"`, exactly one PNG/JPEG, MP4, or MP3 artifact plus non-empty final Markdown can become one reply-anchored Rich Message. HTML mode, multiple/unsupported files, Guest Mode, and voice outputs retain their established paths. Outside Telegram turns the tool sends files directly to the paired/default chat, the registered follower's assigned thread, or an explicit `chat_id` plus optional `thread_id` when this Pi instance owns `/telegram-connect` or is registered with the multi-instance bus.
|
|
65
65
|
- `telegram_message(text, chat_id?, thread_id?)` sends a direct Telegram Markdown message when this Pi instance owns `/telegram-connect` or is registered with the multi-instance bus. During an active Telegram turn, omitted targeting and an explicit target equal to that turn are rejected so the ordinary final-reply path remains the sole current-target response; an explicit different chat/thread target remains allowed for requested cross-target delivery. Outside active turns, paired/default local/TUI delivery remains unchanged. Top-level `telegram_button` comments inside `text` are parsed with the same planner used for normal replies and attached to that message; buttons are never standalone Telegram messages.
|
|
66
|
-
- `
|
|
66
|
+
- The bundled `telegram-bridge` Skill owns action syntax, target routing, Threaded Mode, formatting, and profile-specific debugging guidance. The regular prompt routes applicable turns to that Skill. `telegram_attach` and `telegram_message` remain registered but are model-active only while this instance owns direct transport or holds a live follower registration; disconnect/loss suppresses their schemas and prompt metadata, and recovery restores only the operator's previously active pi-telegram subset.
|
|
67
67
|
- `telegram_voice` hidden comments request Telegram-native voice delivery through either a JSON object or double-quoted attributes. Equivalent `text` or `value` supplies the spoken payload; explicit `text` takes precedence.
|
|
68
68
|
- `telegram_button` hidden comments create inline buttons whose taps enqueue prompts through the same two payload forms. Use `label` plus `prompt`, or `value` when both strings are identical. The colon after either action name is optional and does not select the format. Use top-level column-zero comments outside code, quotes, lists, and indented examples; do not emit standalone button actions.
|
|
69
69
|
|
package/index.ts
CHANGED
|
@@ -39,6 +39,7 @@ import * as Replies from "./lib/replies.ts";
|
|
|
39
39
|
import * as Routing from "./lib/routing.ts";
|
|
40
40
|
import * as Runtime from "./lib/runtime.ts";
|
|
41
41
|
import * as Sections from "./lib/sections.ts";
|
|
42
|
+
import * as Skills from "./lib/skills.ts";
|
|
42
43
|
import * as Status from "./lib/status.ts";
|
|
43
44
|
import * as Sync from "./lib/sync.ts";
|
|
44
45
|
import * as TelegramApi from "./lib/telegram-api.ts";
|
|
@@ -60,6 +61,7 @@ const telegramBusProtocolIdentity =
|
|
|
60
61
|
// --- Extension Runtime ---
|
|
61
62
|
|
|
62
63
|
export default function (pi: Pi.ExtensionAPI) {
|
|
64
|
+
Skills.registerTelegramSkillDiscovery(pi);
|
|
63
65
|
const piRuntime = Pi.createExtensionApiRuntimePorts(pi);
|
|
64
66
|
const {
|
|
65
67
|
getActiveTools,
|
package/lib/bindings.ts
CHANGED
|
@@ -404,9 +404,6 @@ export function registerTelegramCommandsAndTools({
|
|
|
404
404
|
sendMarkdownReply(chatId, undefined, markdown, options),
|
|
405
405
|
recordRuntimeEvent,
|
|
406
406
|
});
|
|
407
|
-
Prompts.registerTelegramHelpTool(pi, {
|
|
408
|
-
getActiveProfileName: configStore.getActiveProfileName,
|
|
409
|
-
});
|
|
410
407
|
Commands.registerTelegramBridgeCommands(pi, {
|
|
411
408
|
promptForConfig: async (ctx, profileName) => {
|
|
412
409
|
const nextProfileName = profileName ?? undefined;
|
package/lib/prompts.ts
CHANGED
|
@@ -4,19 +4,16 @@
|
|
|
4
4
|
* Owns Telegram-specific system prompt suffixes injected into pi agent turns
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import { getTelegramDiagnosticsDisplayPaths } from "./paths.ts";
|
|
10
|
-
import type { BeforeAgentStartEvent, ExtensionAPI } from "./pi.ts";
|
|
7
|
+
import type { BeforeAgentStartEvent } from "./pi.ts";
|
|
11
8
|
import { TELEGRAM_PREFIX } from "./turns.ts";
|
|
12
9
|
|
|
13
10
|
const LOCAL_SYSTEM_PROMPT_SUFFIX = `
|
|
14
11
|
|
|
15
|
-
Telegram bridge available. Do not use
|
|
12
|
+
Telegram bridge available. Load the \`telegram-bridge\` Skill for Telegram delivery, actions, Threaded Mode, or diagnosis. Do not use Telegram from local/TUI prompts unless explicitly asked.`;
|
|
16
13
|
|
|
17
14
|
const TELEGRAM_TURN_SYSTEM_PROMPT_SUFFIX = `
|
|
18
15
|
|
|
19
|
-
Telegram turn note:
|
|
16
|
+
Telegram turn note: Load and follow the \`telegram-bridge\` Skill.`;
|
|
20
17
|
|
|
21
18
|
export const TELEGRAM_ATTACH_PROMPT_SNIPPET =
|
|
22
19
|
"Queue files for the active Telegram reply; outside Telegram turns, send files directly to Telegram.";
|
|
@@ -37,7 +34,6 @@ export const TELEGRAM_MESSAGE_PROMPT_GUIDELINES = [
|
|
|
37
34
|
const TELEGRAM_MODEL_CONTEXT_TOOL_NAMES = new Set([
|
|
38
35
|
"telegram_attach",
|
|
39
36
|
"telegram_message",
|
|
40
|
-
"telegram_help",
|
|
41
37
|
]);
|
|
42
38
|
const TELEGRAM_MODEL_CONTEXT_MEMORY_KEY = Symbol.for(
|
|
43
39
|
"@llblab/pi-telegram:model-context-suspended-tools",
|
|
@@ -135,88 +131,6 @@ export function createTelegramModelContextAvailabilityRuntime(deps: {
|
|
|
135
131
|
};
|
|
136
132
|
}
|
|
137
133
|
|
|
138
|
-
function buildTelegramHelpText(profileName?: string): string {
|
|
139
|
-
const diagnosticsPaths = getTelegramDiagnosticsDisplayPaths(profileName);
|
|
140
|
-
return `--- TELEGRAM BRIDGE HELP ---
|
|
141
|
-
|
|
142
|
-
How to understand Telegram turns:
|
|
143
|
-
- \`[telegram|thread:name|from:user|guest:group]\` marks Telegram origin and attributes.
|
|
144
|
-
- \`thread\` is the visible Thread identity in Threaded Mode; it is not a bus role.
|
|
145
|
-
- \`[reply]\` is quoted context only; act on the user's current instruction.
|
|
146
|
-
- \`[attachments]\` are local files; \`[outputs]\` are handler results/transcripts; \`[time]\` is wall-clock context.
|
|
147
|
-
- \`[voice] delivery: automatic voice\` means pi-telegram will synthesize ordinary assistant text for this turn; no \`[voice]\` line means no automatic voice policy.
|
|
148
|
-
|
|
149
|
-
How to answer Telegram turns:
|
|
150
|
-
- Reply in concise, scannable mobile Telegram Rich Markdown.
|
|
151
|
-
- Use \`$...$\` for inline math and \`$$...$$\` for block math.
|
|
152
|
-
- Real code blocks must stay literal.
|
|
153
|
-
- For generated/requested files, call \`telegram_attach(local_path)\`; do not only mention the path.
|
|
154
|
-
|
|
155
|
-
Assistant-authored Telegram actions:
|
|
156
|
-
- \`telegram_voice\` and \`telegram_button\` are hidden top-level HTML comments, not Pi tools.
|
|
157
|
-
- Put action comments at column zero, outside code, quotes, lists, and indented examples.
|
|
158
|
-
- Action payloads use either JSON or double-quoted attributes; the colon after the action name is optional and does not affect parsing. Voice accepts equivalent \`text\` or \`value\`: \`<!-- telegram_voice: {"value":"Short summary","lang":"en"} -->\` or \`<!-- telegram_voice text="Short summary" lang="en" -->\`.
|
|
159
|
-
- Keep the complete action in one top-level comment and include non-empty \`text\` or \`value\`; encode line breaks inside JSON strings as \`\\n\`.
|
|
160
|
-
- Keep voice text TTS-friendly; avoid raw Markdown, code, and tables in voice text.
|
|
161
|
-
- Voice delivery generates and attaches OGG automatically; do not also call \`telegram_attach\` for the same audio.
|
|
162
|
-
- Voice reply modes are compact: \`hidden\` emits no automatic context, \`mirror\` emits it for voice/audio input, and \`always\` emits it for every Telegram turn. Explicit \`telegram_voice\` remains available for an intentionally distinct spoken payload.
|
|
163
|
-
- Button payloads use \`label\` plus \`prompt\`, or compact \`value\` when both are identical: \`<!-- telegram_button: {"label":"Continue","prompt":"Continue with the current plan."} -->\` or \`<!-- telegram_button value="Continue" -->\`.
|
|
164
|
-
- Optional \`selected_style\` in either payload form controls the button after queue admission: \`primary\` (default, blue), \`success\` (green), or \`danger\` (red). It never suppresses the prompt.
|
|
165
|
-
- If hidden button comments form the whole reply, the bridge supplies the standard \`☑️ **Choose an option:**\` heading automatically.
|
|
166
|
-
|
|
167
|
-
Local/TUI direct delivery:
|
|
168
|
-
- Do not send Telegram actions from local/TUI prompts unless explicitly asked.
|
|
169
|
-
- Use \`telegram_attach\` for files and \`telegram_message\` for direct Markdown text.
|
|
170
|
-
- Direct delivery requires this Pi instance to own \`/telegram-connect\` or be registered with the Threaded Mode bus.
|
|
171
|
-
- For explicit targets, pass \`chat_id\` plus optional \`thread_id\`; registered followers default to their assigned Thread target.
|
|
172
|
-
- Do not use \`telegram_message\` for ordinary Telegram-originated replies; answer normally and let the bridge deliver the active turn reply.
|
|
173
|
-
|
|
174
|
-
Threaded Mode:
|
|
175
|
-
- pi-telegram supports private-chat Threaded Mode when Telegram exposes thread support for the bot.
|
|
176
|
-
- Product/user language is Thread; Bot API primitive names may still say topic.
|
|
177
|
-
- Threaded Mode has one leader transport and visible follower Pi processes joined manually through \`/telegram-connect\`.
|
|
178
|
-
- Thread names are bridge-assigned or preserved identities; do not invent rename prompts or use a rename tool.
|
|
179
|
-
- The \`All\` surface is for routing/control, not hidden Pi process creation.
|
|
180
|
-
|
|
181
|
-
Configurable handlers:
|
|
182
|
-
- \`telegram.json\` can add no-code \`inboundHandlers\`/\`outboundHandlers\` using command templates before writing an extension.
|
|
183
|
-
- For speech-to-text, configure an \`inboundHandlers\` entry matching \`type: "voice"\` or \`mime: "audio/*"\`; stdout becomes \`[outputs]\` prompt context.
|
|
184
|
-
- If command-template config is not enough, build a companion extension through the public pi-telegram APIs; do not import package-private \`lib/*\` paths.
|
|
185
|
-
|
|
186
|
-
Debugging pi-telegram:
|
|
187
|
-
- Inspect \`${diagnosticsPaths.state}\` for runtime state, roster, bindings, slots, reservations, and diagnostics.
|
|
188
|
-
- Inspect \`${diagnosticsPaths.logs}\` for redacted runtime event evidence.
|
|
189
|
-
- Use terminal \`telegram-status\` for compact human health; use \`telegram-status --debug\` for the full human-readable diagnostic dump.`;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export function getTelegramHelpText(profileName?: string): string {
|
|
193
|
-
return buildTelegramHelpText(profileName);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export function registerTelegramHelpTool(
|
|
197
|
-
pi: ExtensionAPI,
|
|
198
|
-
options: { getActiveProfileName?: () => string | undefined } = {},
|
|
199
|
-
): void {
|
|
200
|
-
pi.registerTool({
|
|
201
|
-
name: "telegram_help",
|
|
202
|
-
label: "Telegram Help",
|
|
203
|
-
description:
|
|
204
|
-
"Read pi-telegram usage guidance for delivery actions, Threaded Mode, handlers, formatting, and debugging.",
|
|
205
|
-
parameters: Type.Object({}),
|
|
206
|
-
async execute() {
|
|
207
|
-
return {
|
|
208
|
-
content: [
|
|
209
|
-
{
|
|
210
|
-
type: "text",
|
|
211
|
-
text: getTelegramHelpText(options.getActiveProfileName?.()),
|
|
212
|
-
},
|
|
213
|
-
],
|
|
214
|
-
details: {},
|
|
215
|
-
};
|
|
216
|
-
},
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
|
|
220
134
|
export function buildTelegramBridgeSystemPrompt(options: {
|
|
221
135
|
prompt: string;
|
|
222
136
|
systemPrompt: string;
|
package/lib/skills.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundled Telegram skill discovery
|
|
3
|
+
* Zones: pi agent, telegram guidance
|
|
4
|
+
* Owns source-checkout and installed-package skill path contribution
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
import type { ExtensionAPI } from "./pi.ts";
|
|
10
|
+
|
|
11
|
+
export const TELEGRAM_SKILLS_PATH = fileURLToPath(
|
|
12
|
+
new URL("../skills", import.meta.url),
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export function registerTelegramSkillDiscovery(
|
|
16
|
+
pi: Pick<ExtensionAPI, "on">,
|
|
17
|
+
): void {
|
|
18
|
+
pi.on("resources_discover", () => ({
|
|
19
|
+
skillPaths: [TELEGRAM_SKILLS_PATH],
|
|
20
|
+
}));
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-telegram",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"CHANGELOG.md",
|
|
46
46
|
"docs/",
|
|
47
47
|
"scripts/",
|
|
48
|
+
"skills/",
|
|
48
49
|
"screenshot.png"
|
|
49
50
|
],
|
|
50
51
|
"exports": {
|
|
@@ -64,6 +65,9 @@
|
|
|
64
65
|
"extensions": [
|
|
65
66
|
"./index.ts"
|
|
66
67
|
],
|
|
68
|
+
"skills": [
|
|
69
|
+
"./skills"
|
|
70
|
+
],
|
|
67
71
|
"image": "https://raw.githubusercontent.com/llblab/pi-telegram/main/screenshot.png"
|
|
68
72
|
},
|
|
69
73
|
"peerDependencies": {
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: button-console
|
|
3
|
+
description: Turns terminal programs, filesystem navigation, system inspection, and operator workflows into contextual agent-generated button interfaces while preserving full or faithfully adapted console output. Use when a user asks for controls, menus, navigation, actions, or an operating-system/CLI interface through Telegram or another prompt-button transport.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Button Console
|
|
7
|
+
|
|
8
|
+
Build a temporary, truthful button interface over terminal and operating-system capabilities. The agent remains the interpreter and safety boundary; buttons are contextual prompts, not a second shell, static application, or hidden automation daemon.
|
|
9
|
+
|
|
10
|
+
## Concept
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
User intent → narrow inspection/action → console evidence → readable output → contextual buttons → next user intent
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Each response is one generated screen. Reinspect current reality and regenerate controls after every action rather than maintaining a parallel navigation model.
|
|
17
|
+
|
|
18
|
+
## Core Contract
|
|
19
|
+
|
|
20
|
+
- Inspect reality before rendering entries or controls that depend on current state.
|
|
21
|
+
- Use normal console programs as capability owners.
|
|
22
|
+
- Show complete output when reasonably sized; otherwise adapt it without changing material facts and offer pagination, filtering, raw output, or drill-down.
|
|
23
|
+
- Make every button prompt self-contained: name the exact target, operation, output expectation, and safety restriction.
|
|
24
|
+
- Treat button clicks as ordinary user requests subject to the same authority and validation rules as typed requests.
|
|
25
|
+
- Never infer permission for destructive, privileged, credential-bearing, external, or irreversible work merely because a button exists.
|
|
26
|
+
- Do not read secrets to populate navigation. Names and safe metadata may be listed; contents require justified, explicit authorization.
|
|
27
|
+
- Never place credentials, private keys, tokens, cookies, wallet material, or sensitive file contents in labels or prompts.
|
|
28
|
+
|
|
29
|
+
## Screen Model
|
|
30
|
+
|
|
31
|
+
A screen normally contains:
|
|
32
|
+
|
|
33
|
+
1. A short title naming the current target.
|
|
34
|
+
2. Console output or a faithful adaptation.
|
|
35
|
+
3. Optional provenance such as path, command class, timestamp, exit status, or truncation note.
|
|
36
|
+
4. Buttons for likely next actions.
|
|
37
|
+
5. `Back` or `Up` for hierarchy navigation.
|
|
38
|
+
6. `Refresh` when state may change.
|
|
39
|
+
|
|
40
|
+
Prefer 4–12 useful buttons. Split larger sets into categories or pages rather than creating a dense button wall.
|
|
41
|
+
|
|
42
|
+
## Console Fidelity
|
|
43
|
+
|
|
44
|
+
Complete output preserves ordering, names, identifiers, numeric values, units, warnings, errors, and relevant exit status. Use a code block only when formatting is semantically meaningful; use compact records for simple listings.
|
|
45
|
+
|
|
46
|
+
Adaptation may:
|
|
47
|
+
|
|
48
|
+
- Replace columns with labeled records.
|
|
49
|
+
- Normalize human-readable sizes.
|
|
50
|
+
- Group entries by type.
|
|
51
|
+
- Collapse repeated successful lines.
|
|
52
|
+
- Show a bounded head, tail, page, or ranked subset.
|
|
53
|
+
- Translate labels into the user's language.
|
|
54
|
+
|
|
55
|
+
Adaptation must not:
|
|
56
|
+
|
|
57
|
+
- Convert failure into success.
|
|
58
|
+
- Omit material warnings.
|
|
59
|
+
- Change identities, values, or ordering claims.
|
|
60
|
+
- Present a filtered subset as complete.
|
|
61
|
+
- Hide truncation, filtering, or an unavailable measurement.
|
|
62
|
+
|
|
63
|
+
State adaptation explicitly, for example: `Показаны 20 из 184 записей, по размеру`.
|
|
64
|
+
|
|
65
|
+
## Filesystem Navigation
|
|
66
|
+
|
|
67
|
+
- Resolve the requested path before listing it.
|
|
68
|
+
- List directories without reading file contents.
|
|
69
|
+
- Include every ordinary entry unless the user requested a filter.
|
|
70
|
+
- Do not silently omit a sensitive-looking entry; show its name when listing is safe, then handle its contents conservatively.
|
|
71
|
+
- Hidden directories default to names and metadata only.
|
|
72
|
+
- Use absolute or otherwise unambiguous paths in button prompts.
|
|
73
|
+
- Keep `Up`, `Home`, and `Refresh` where useful.
|
|
74
|
+
- Offer safe file operations first: metadata, non-sensitive preview, attach/send, or open with an appropriate application.
|
|
75
|
+
|
|
76
|
+
Never expose credential-file contents through a preview button. This includes `*.keys`, private SSH keys, credential stores, browser profiles, cookies, tokens, and wallets.
|
|
77
|
+
|
|
78
|
+
## System And Process Controls
|
|
79
|
+
|
|
80
|
+
Read-only controls may directly request system status, uptime, load, memory, temperatures, disk use, process ranking, service state, network state, application discovery, and bounded redacted logs.
|
|
81
|
+
|
|
82
|
+
Use a two-stage flow for high-impact actions:
|
|
83
|
+
|
|
84
|
+
1. An action button opens a confirmation screen naming the exact target and consequences.
|
|
85
|
+
2. A distinct confirmation button requests the exact operation.
|
|
86
|
+
|
|
87
|
+
This applies to shutdown, reboot, process termination, package removal, file deletion, permission changes, service mutation, disk operations, and similar work. Use danger styling when available. Re-check the target immediately before execution and report resulting console evidence.
|
|
88
|
+
|
|
89
|
+
## Button Generation
|
|
90
|
+
|
|
91
|
+
When the transport supports prompt buttons, emit its canonical button action syntax. For pi-telegram this is a top-level hidden `telegram_button` comment:
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<!-- telegram_button: {"label":"📂 Downloads","prompt":"Show the current contents of /home/user/Downloads without reading file contents, then provide contextual navigation buttons."} -->
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Button prompts must:
|
|
98
|
+
|
|
99
|
+
- Use an exact target where possible.
|
|
100
|
+
- Describe one coherent intent.
|
|
101
|
+
- Preserve the user's language.
|
|
102
|
+
- State important exclusions such as not reading secrets.
|
|
103
|
+
- Request fresh state after mutations.
|
|
104
|
+
- Avoid embedding volatile output that should be reinspected.
|
|
105
|
+
|
|
106
|
+
Labels stay short, distinct, and scannable. Emoji are optional semantic markers; do not rely on color alone. If buttons are unavailable, render the same interface as a numbered choice list.
|
|
107
|
+
|
|
108
|
+
## Action Procedure
|
|
109
|
+
|
|
110
|
+
1. Identify the current target and capability.
|
|
111
|
+
2. Classify the action as read-only, ordinary mutation, privileged, destructive, secret-bearing, or external.
|
|
112
|
+
3. Run the narrowest console inspection needed for a truthful screen.
|
|
113
|
+
4. Check exit status and stderr; never build a success menu from failed evidence.
|
|
114
|
+
5. Render complete or explicitly adapted output.
|
|
115
|
+
6. Generate only context-relevant next-action buttons.
|
|
116
|
+
7. On the next turn, reinspect when freshness matters and execute only the newly authorized action.
|
|
117
|
+
8. Report outcome evidence and regenerate the screen from retained reality.
|
|
118
|
+
|
|
119
|
+
## Failure And Empty States
|
|
120
|
+
|
|
121
|
+
- On command failure, show the concise error and offer diagnosis, retry, Back, or a narrower action.
|
|
122
|
+
- For an empty directory, say so and retain Up, Home, and Refresh.
|
|
123
|
+
- If a target disappeared, return to its nearest valid parent rather than reusing stale evidence.
|
|
124
|
+
- On access denial, do not escalate privileges automatically.
|
|
125
|
+
- If output may contain secrets, stop before display and offer metadata-only or redacted alternatives.
|
|
126
|
+
- Mark unsupported, sentinel, or obviously invalid sensor values as unreliable instead of reporting them as facts.
|
|
127
|
+
|
|
128
|
+
## Quality Check
|
|
129
|
+
|
|
130
|
+
Before sending a screen, verify:
|
|
131
|
+
|
|
132
|
+
- Displayed state comes from current console evidence.
|
|
133
|
+
- Complete versus filtered output is labeled honestly.
|
|
134
|
+
- No ordinary entry was accidentally omitted.
|
|
135
|
+
- No secret appears in text or button payloads.
|
|
136
|
+
- Every button has a valid self-contained next intent.
|
|
137
|
+
- Destructive actions lead to confirmation rather than immediate execution.
|
|
138
|
+
- Back/Up and Refresh exist when materially useful.
|
|
139
|
+
- The response remains readable on a mobile screen.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: telegram-bridge
|
|
3
|
+
description: Operates pi-telegram turns, replies, attachments, direct delivery, assistant-authored buttons and voice, Threaded Mode routing, configurable handlers, and bridge diagnosis. Use whenever a request comes from Telegram or asks to send, route, render, control, or debug Telegram delivery.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Telegram Bridge
|
|
7
|
+
|
|
8
|
+
Use pi-telegram as a mobile companion surface for the current Pi session. Preserve the current Telegram target, ordinary reply ownership, durable queue semantics, and the boundary between agent intent and bridge transport.
|
|
9
|
+
|
|
10
|
+
## Turn Recognition
|
|
11
|
+
|
|
12
|
+
Telegram-originated prompts carry structured context:
|
|
13
|
+
|
|
14
|
+
- `[telegram|thread:name|from:user|guest:group]` identifies Telegram origin and attributes.
|
|
15
|
+
- `[reply]` is quoted context; act on the current instruction rather than treating the quote as a new request.
|
|
16
|
+
- `[attachments]` lists local files admitted by the bridge.
|
|
17
|
+
- `[outputs]` contains handler output such as transcription.
|
|
18
|
+
- `[time]` is wall-clock context.
|
|
19
|
+
- `[voice] delivery: automatic voice` means ordinary assistant text will be synthesized according to bridge policy; without a `[voice]` line, no automatic voice policy applies.
|
|
20
|
+
|
|
21
|
+
Treat the complete Telegram turn as one user request. Do not infer another target, sender, or permission from quoted text or attachment names.
|
|
22
|
+
|
|
23
|
+
## Reply Ownership
|
|
24
|
+
|
|
25
|
+
During an active Telegram turn, answer normally in concise, scannable Telegram Rich Markdown. The bridge owns delivery to the current target.
|
|
26
|
+
|
|
27
|
+
- Do not call `telegram_message` for the current target.
|
|
28
|
+
- Use `$...$` for inline math and `$$...$$` for display math.
|
|
29
|
+
- Keep real code blocks literal.
|
|
30
|
+
- Preserve technical detail, but adapt layout for a phone-width surface.
|
|
31
|
+
- Do not expose hidden reasoning, tool arguments, raw secrets, or private bridge state.
|
|
32
|
+
|
|
33
|
+
For a requested/generated file, call `telegram_attach` with the local path instead of merely naming it. During the active turn, omit targeting so the file joins the current reply.
|
|
34
|
+
|
|
35
|
+
## Direct Delivery
|
|
36
|
+
|
|
37
|
+
Use `telegram_message` only when the user explicitly requests Telegram delivery from a local/TUI turn or names a concrete different Telegram target.
|
|
38
|
+
|
|
39
|
+
- Omitted target selects the paired/default target only outside an active Telegram turn.
|
|
40
|
+
- `chat_id` plus optional `thread_id` selects an explicit Bot API target.
|
|
41
|
+
- `thread` selects another live Pi Thread by name or id and admits one attributed turn there.
|
|
42
|
+
- Direct delivery requires this Pi instance to own transport or hold a live Threaded Mode registration.
|
|
43
|
+
- Unknown, ambiguous, same, offline, unauthorized, or cross-chat targets fail closed.
|
|
44
|
+
|
|
45
|
+
Use `telegram_attach` outside Telegram turns only when the user explicitly requests file delivery. Registered followers default to their assigned Thread.
|
|
46
|
+
|
|
47
|
+
## Assistant-Authored Actions
|
|
48
|
+
|
|
49
|
+
`telegram_button` and `telegram_voice` are hidden top-level HTML comments, not tools. Emit them at column zero, outside lists, quotes, code blocks, and indentation.
|
|
50
|
+
|
|
51
|
+
Button forms:
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<!-- telegram_button: {"label":"Continue","prompt":"Continue with the current plan."} -->
|
|
55
|
+
<!-- telegram_button value="Continue" -->
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- Payloads accept JSON after an optional colon or double-quoted attributes; keep the complete action in one top-level comment and encode JSON line breaks as `\n`.
|
|
59
|
+
- Use `label` plus a self-contained `prompt`, or non-empty `value` when both are identical.
|
|
60
|
+
- Optional `selected_style` is `primary` (default), `success`, or `danger`; style never suppresses prompt admission.
|
|
61
|
+
- If button comments form the whole reply, the bridge supplies the standard choice heading.
|
|
62
|
+
- A button click creates a new user request; it does not bypass authority or confirmation.
|
|
63
|
+
- Labels stay short and distinct. Prompts name the exact target, intended operation, and safety exclusions.
|
|
64
|
+
|
|
65
|
+
Voice forms:
|
|
66
|
+
|
|
67
|
+
```html
|
|
68
|
+
<!-- telegram_voice: {"text":"Short spoken message","lang":"en"} -->
|
|
69
|
+
<!-- telegram_voice text="Short spoken message" lang="en" -->
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- `text` and `value` are equivalent payload forms; explicit `text` wins.
|
|
73
|
+
- Keep speech TTS-friendly and omit Markdown syntax, tables, and raw code.
|
|
74
|
+
- Voice delivery creates OGG itself; do not attach a duplicate audio file.
|
|
75
|
+
- Automatic voice modes are `hidden` (no automatic context), `mirror` (voice/audio input), and `always` (every Telegram turn).
|
|
76
|
+
- Explicit voice remains available in every automatic voice mode for an intentionally distinct spoken payload.
|
|
77
|
+
|
|
78
|
+
This Skill is the canonical operating contract. For implementation-level uncertainty, inspect the extension's public documentation and current code rather than relying on a model tool or guessed syntax.
|
|
79
|
+
|
|
80
|
+
## Attachments And Secrets
|
|
81
|
+
|
|
82
|
+
- Inspect only what the request requires.
|
|
83
|
+
- Treat local attachment paths as admitted inputs, not proof that their contents are safe to expose.
|
|
84
|
+
- Never place tokens, private keys, cookies, credentials, wallet material, or sensitive file contents in text or button payloads.
|
|
85
|
+
- Sending a sensitive file requires an explicit user request naming that delivery intent.
|
|
86
|
+
- For generated artifacts, queue the file with `telegram_attach`; do not base64 or paste binary content into chat.
|
|
87
|
+
|
|
88
|
+
## Threaded Mode
|
|
89
|
+
|
|
90
|
+
Threaded Mode operates in private chats when Telegram exposes thread support for the bot. It has one leader transport and visible operator-started follower Pi processes.
|
|
91
|
+
|
|
92
|
+
- `Thread` is the product term; reserve `topic` for Bot API primitives.
|
|
93
|
+
- A Thread follows its assigned live Pi instance and current session.
|
|
94
|
+
- Do not invent hidden followers, launch shadow Pi processes, or expose internal bus roles as user identity.
|
|
95
|
+
- Do not rename Threads through guessed prompts or unsupported tools.
|
|
96
|
+
- The `All` surface is routing/control, not process creation.
|
|
97
|
+
|
|
98
|
+
Cross-Thread delivery must preserve the concrete target and current registration authority. Use ordinary reply delivery for the source turn and `telegram_message(thread=...)` only for an explicitly requested different live Thread.
|
|
99
|
+
|
|
100
|
+
## Configurable Handlers And Extensions
|
|
101
|
+
|
|
102
|
+
Prefer no-code command-template configuration in `telegram.json` before adding a companion extension:
|
|
103
|
+
|
|
104
|
+
- `inboundHandlers` transforms text/media before queueing.
|
|
105
|
+
- `outboundHandlers` transforms final replies.
|
|
106
|
+
- Voice transcription handlers can match `type: "voice"` or `mime: "audio/*"`; stdout becomes `[outputs]`.
|
|
107
|
+
|
|
108
|
+
When configuration is insufficient, use documented `@llblab/pi-telegram/*` public API subpaths. Never import package-private `lib/*`, start another polling loop, or bypass bridge ownership with raw Bot API access.
|
|
109
|
+
|
|
110
|
+
## Safety
|
|
111
|
+
|
|
112
|
+
- Read-only inspection may proceed when requested.
|
|
113
|
+
- Destructive, privileged, external, credential-bearing, or irreversible operations require explicit authorization under the active engineering contract.
|
|
114
|
+
- A button offering a dangerous action should open a consequence/confirmation screen before execution.
|
|
115
|
+
- Re-check volatile targets immediately before mutation.
|
|
116
|
+
- Report Telegram delivery failures honestly; do not claim a send from a queued comment or failed tool call.
|
|
117
|
+
|
|
118
|
+
## Diagnosis
|
|
119
|
+
|
|
120
|
+
Prefer:
|
|
121
|
+
|
|
122
|
+
1. `telegram-status` for compact health.
|
|
123
|
+
2. `telegram-status --debug` for bounded human-readable diagnostics.
|
|
124
|
+
3. `~/.pi/agent/tmp/telegram/state.json` and `logs.jsonl` for default-profile redacted evidence.
|
|
125
|
+
4. `state.<profile>.json` and `logs.<profile>.jsonl` in the same directory for a named profile.
|
|
126
|
+
|
|
127
|
+
When `PI_CODING_AGENT_DIR` selects another compatible runtime, resolve the equivalent `tmp/telegram` directory under that agent root. Do not mutate bridge state, ownership files, journals, bindings, or locks to force recovery. Use supported commands and exact current authority.
|
|
128
|
+
|
|
129
|
+
## Completion Check
|
|
130
|
+
|
|
131
|
+
Before sending a Telegram response, verify:
|
|
132
|
+
|
|
133
|
+
- The reply goes through the correct current or explicit target path.
|
|
134
|
+
- Requested files are attached rather than only mentioned.
|
|
135
|
+
- Action comments are top-level and syntactically complete.
|
|
136
|
+
- Buttons carry self-contained prompts and dangerous actions retain confirmation.
|
|
137
|
+
- No secret or hidden reasoning appears in text, actions, or attachments without explicit authorization.
|
|
138
|
+
- Direct delivery is not duplicating the ordinary current-turn reply.
|