@llblab/pi-telegram 0.45.11 → 0.47.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/BACKLOG.md +5 -1
- package/CHANGELOG.md +12 -0
- package/README.md +6 -6
- package/dist/api/activity.d.ts +6 -0
- package/dist/api/activity.js +6 -0
- package/dist/api/commands.d.ts +6 -0
- package/dist/api/commands.js +6 -0
- package/dist/api/delivery.d.ts +6 -0
- package/dist/api/delivery.js +6 -0
- package/dist/api/inbound.d.ts +6 -0
- package/dist/api/inbound.js +6 -0
- package/dist/api/keyboard.d.ts +6 -0
- package/dist/api/keyboard.js +6 -0
- package/dist/api/outbound.d.ts +6 -0
- package/dist/api/outbound.js +6 -0
- package/dist/api/sections.d.ts +7 -0
- package/dist/api/sections.js +6 -0
- package/dist/api/status.d.ts +6 -0
- package/dist/api/status.js +6 -0
- package/dist/api/updates.d.ts +6 -0
- package/dist/api/updates.js +6 -0
- package/dist/api/voice.d.ts +6 -0
- package/dist/api/voice.js +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/lib/activity-verbosity.d.ts +52 -0
- package/dist/lib/activity-verbosity.js +596 -0
- package/dist/lib/activity.d.ts +220 -0
- package/dist/lib/activity.js +574 -0
- package/dist/lib/agent-messages.d.ts +28 -0
- package/dist/lib/agent-messages.js +86 -0
- package/dist/lib/bindings.d.ts +250 -0
- package/dist/lib/bindings.js +936 -0
- package/dist/lib/bus-api.d.ts +18 -0
- package/dist/lib/bus-api.js +254 -0
- package/dist/lib/bus-follower.d.ts +464 -0
- package/dist/lib/bus-follower.js +1686 -0
- package/dist/lib/bus-leader.d.ts +292 -0
- package/dist/lib/bus-leader.js +2242 -0
- package/dist/lib/bus-transport.d.ts +64 -0
- package/dist/lib/bus-transport.js +140 -0
- package/dist/lib/bus.d.ts +518 -0
- package/dist/lib/bus.js +2055 -0
- package/dist/lib/channel-posts.d.ts +170 -0
- package/dist/lib/channel-posts.js +611 -0
- package/dist/lib/command-templates.d.ts +70 -0
- package/dist/lib/command-templates.js +744 -0
- package/dist/lib/commands.d.ts +541 -0
- package/dist/lib/commands.js +1155 -0
- package/dist/lib/config.d.ts +252 -0
- package/dist/lib/config.js +889 -0
- package/dist/lib/delivery.d.ts +163 -0
- package/dist/lib/delivery.js +542 -0
- package/dist/lib/extension.d.ts +7 -0
- package/dist/lib/extension.js +1608 -0
- package/dist/lib/generative-app-worker.mjs +104 -0
- package/dist/lib/generative-apps.d.ts +212 -0
- package/dist/lib/generative-apps.js +1006 -0
- package/dist/lib/inbound.d.ts +91 -0
- package/dist/lib/inbound.js +502 -0
- package/dist/lib/journal.d.ts +665 -0
- package/dist/lib/journal.js +3701 -0
- package/dist/lib/keyboard.d.ts +23 -0
- package/dist/lib/keyboard.js +37 -0
- package/dist/lib/lifecycle.d.ts +157 -0
- package/dist/lib/lifecycle.js +395 -0
- package/dist/lib/locks.d.ts +164 -0
- package/dist/lib/locks.js +1208 -0
- package/dist/lib/logging.d.ts +50 -0
- package/dist/lib/logging.js +274 -0
- package/dist/lib/media.d.ts +181 -0
- package/dist/lib/media.js +602 -0
- package/dist/lib/menu-model.d.ts +217 -0
- package/dist/lib/menu-model.js +663 -0
- package/dist/lib/menu-queue.d.ts +37 -0
- package/dist/lib/menu-queue.js +408 -0
- package/dist/lib/menu-settings.d.ts +116 -0
- package/dist/lib/menu-settings.js +595 -0
- package/dist/lib/menu-status.d.ts +32 -0
- package/dist/lib/menu-status.js +112 -0
- package/dist/lib/menu-thinking.d.ts +29 -0
- package/dist/lib/menu-thinking.js +82 -0
- package/dist/lib/menu.d.ts +171 -0
- package/dist/lib/menu.js +323 -0
- package/dist/lib/model.d.ts +127 -0
- package/dist/lib/model.js +409 -0
- package/dist/lib/outbound-attachments.d.ts +241 -0
- package/dist/lib/outbound-attachments.js +639 -0
- package/dist/lib/outbound-buttons.d.ts +69 -0
- package/dist/lib/outbound-buttons.js +248 -0
- package/dist/lib/outbound-markup.d.ts +42 -0
- package/dist/lib/outbound-markup.js +678 -0
- package/dist/lib/outbound-voice.d.ts +55 -0
- package/dist/lib/outbound-voice.js +152 -0
- package/dist/lib/outbound.d.ts +185 -0
- package/dist/lib/outbound.js +516 -0
- package/dist/lib/ownership.d.ts +77 -0
- package/dist/lib/ownership.js +174 -0
- package/dist/lib/paths.d.ts +40 -0
- package/dist/lib/paths.js +94 -0
- package/dist/lib/pi.d.ts +72 -0
- package/dist/lib/pi.js +121 -0
- package/dist/lib/polling.d.ts +351 -0
- package/dist/lib/polling.js +1196 -0
- package/dist/lib/preview.d.ts +192 -0
- package/dist/lib/preview.js +614 -0
- package/dist/lib/prompt-templates.d.ts +24 -0
- package/dist/lib/prompt-templates.js +118 -0
- package/dist/lib/prompts.d.ts +57 -0
- package/dist/lib/prompts.js +167 -0
- package/dist/lib/queue.d.ts +766 -0
- package/dist/lib/queue.js +1965 -0
- package/dist/lib/recovery.d.ts +86 -0
- package/dist/lib/recovery.js +285 -0
- package/dist/lib/rendering.d.ts +20 -0
- package/dist/lib/rendering.js +983 -0
- package/dist/lib/replies.d.ts +214 -0
- package/dist/lib/replies.js +737 -0
- package/dist/lib/routing.d.ts +207 -0
- package/dist/lib/routing.js +2282 -0
- package/dist/lib/runtime.d.ts +172 -0
- package/dist/lib/runtime.js +402 -0
- package/dist/lib/sections.d.ts +165 -0
- package/dist/lib/sections.js +327 -0
- package/dist/lib/setup.d.ts +82 -0
- package/dist/lib/setup.js +150 -0
- package/dist/lib/skills.d.ts +8 -0
- package/dist/lib/skills.js +12 -0
- package/dist/lib/status.d.ts +442 -0
- package/dist/lib/status.js +1006 -0
- package/dist/lib/sync.d.ts +179 -0
- package/dist/lib/sync.js +782 -0
- package/dist/lib/target.d.ts +20 -0
- package/dist/lib/target.js +27 -0
- package/dist/lib/telegram-api.d.ts +541 -0
- package/dist/lib/telegram-api.js +1159 -0
- package/dist/lib/text-groups.d.ts +89 -0
- package/dist/lib/text-groups.js +317 -0
- package/dist/lib/thread-cleanup-manager.d.ts +288 -0
- package/dist/lib/thread-cleanup-manager.js +560 -0
- package/dist/lib/thread-display.d.ts +46 -0
- package/dist/lib/thread-display.js +257 -0
- package/dist/lib/thread-naming.d.ts +46 -0
- package/dist/lib/thread-naming.js +78 -0
- package/dist/lib/thread-reconciler.d.ts +239 -0
- package/dist/lib/thread-reconciler.js +644 -0
- package/dist/lib/threads.d.ts +621 -0
- package/dist/lib/threads.js +3679 -0
- package/dist/lib/time-injection.d.ts +15 -0
- package/dist/lib/time-injection.js +56 -0
- package/dist/lib/turns.d.ts +109 -0
- package/dist/lib/turns.js +500 -0
- package/dist/lib/updates.d.ts +1290 -0
- package/dist/lib/updates.js +3634 -0
- package/dist/lib/voice.d.ts +117 -0
- package/dist/lib/voice.js +174 -0
- package/dist/lib/workspace-admission.d.ts +264 -0
- package/dist/lib/workspace-admission.js +1136 -0
- package/dist/lib/workspace-retirement.d.ts +219 -0
- package/dist/lib/workspace-retirement.js +587 -0
- package/dist/lib/workspace-slots.d.ts +30 -0
- package/dist/lib/workspace-slots.js +54 -0
- package/dist/package.json +126 -0
- package/dist/pi-telegram/index.js +1 -0
- package/dist/skills/generated-control-surface/SKILL.md +107 -0
- package/dist/skills/generated-control-surface/references/capability-adapters.md +27 -0
- package/dist/skills/generated-control-surface/references/layout-and-state.md +37 -0
- package/dist/skills/generative-apps/SKILL.md +115 -0
- package/dist/skills/show-me/SKILL.md +166 -0
- package/dist/skills/show-me/references/telegram-surfaces.md +43 -0
- package/dist/skills/telegram-bridge/SKILL.md +129 -0
- package/dist/skills/telegram-bridge/references/configuration.md +15 -0
- package/dist/skills/telegram-bridge/references/delivery-and-threads.md +27 -0
- package/dist/skills/telegram-bridge/references/diagnosis.md +18 -0
- package/docs/architecture.md +1 -1
- package/docs/compact-matrix-literal.md +10 -3
- package/docs/generative-apps.md +15 -13
- package/docs/multi-instance-bus.md +17 -3
- package/docs/outbound.md +1 -1
- package/docs/public-api.md +2 -2
- package/lib/bindings.ts +89 -6
- package/lib/bus-follower.ts +11 -3
- package/lib/bus-leader.ts +57 -20
- package/lib/bus.ts +12 -2
- package/lib/commands.ts +2 -2
- package/lib/config.ts +14 -7
- package/lib/delivery.ts +38 -6
- package/lib/extension.ts +26 -1
- package/lib/generative-apps.ts +379 -13
- package/lib/menu-settings.ts +21 -5
- package/lib/outbound-markup.ts +16 -7
- package/lib/pi.ts +4 -0
- package/lib/sync.ts +3 -0
- package/lib/telegram-api.ts +12 -1
- package/lib/thread-cleanup-manager.ts +36 -6
- package/lib/thread-display.ts +96 -18
- package/lib/threads.ts +150 -30
- package/package.json +56 -13
- package/scripts/build-dist.mjs +44 -0
- package/scripts/measure-bus.mjs +8 -1
- package/scripts/measure-workspace.mjs +8 -1
- package/skills/generative-apps/SKILL.md +1 -1
- package/skills/show-me/SKILL.md +1 -1
- package/skills/telegram-bridge/SKILL.md +1 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pi prompt-template bridge helpers
|
|
3
|
+
* Zones: pi agent prompts, telegram controls, filesystem
|
|
4
|
+
* Discovers Pi prompt-template slash commands and expands them before Telegram queue dispatch
|
|
5
|
+
*/
|
|
6
|
+
import { readFileSync } from "node:fs";
|
|
7
|
+
const TELEGRAM_BOT_COMMAND_NAME_PATTERN = /^[a-z0-9_]{1,32}$/;
|
|
8
|
+
function stripPromptTemplateFrontmatter(content) {
|
|
9
|
+
if (!content.startsWith("---"))
|
|
10
|
+
return content;
|
|
11
|
+
const lines = content.split("\n");
|
|
12
|
+
if (lines[0]?.trim() !== "---")
|
|
13
|
+
return content;
|
|
14
|
+
for (let index = 1; index < lines.length; index += 1) {
|
|
15
|
+
if (lines[index]?.trim() === "---")
|
|
16
|
+
return lines.slice(index + 1).join("\n");
|
|
17
|
+
}
|
|
18
|
+
return content;
|
|
19
|
+
}
|
|
20
|
+
export function parsePromptTemplateArgs(argsString) {
|
|
21
|
+
const args = [];
|
|
22
|
+
let current = "";
|
|
23
|
+
let quote;
|
|
24
|
+
for (const char of argsString) {
|
|
25
|
+
if (quote) {
|
|
26
|
+
if (char === quote) {
|
|
27
|
+
quote = undefined;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
current += char;
|
|
31
|
+
}
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (char === '"' || char === "'") {
|
|
35
|
+
quote = char;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (char === " " || char === "\t") {
|
|
39
|
+
if (current)
|
|
40
|
+
args.push(current);
|
|
41
|
+
current = "";
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
current += char;
|
|
45
|
+
}
|
|
46
|
+
if (current)
|
|
47
|
+
args.push(current);
|
|
48
|
+
return args;
|
|
49
|
+
}
|
|
50
|
+
export function substitutePromptTemplateArgs(content, args) {
|
|
51
|
+
let result = content.replace(/\$(\d+)/g, (_, num) => {
|
|
52
|
+
const index = Number.parseInt(num, 10) - 1;
|
|
53
|
+
return args[index] ?? "";
|
|
54
|
+
});
|
|
55
|
+
result = result.replace(/\$\{@:(\d+)(?::(\d+))?\}/g, (_, startValue, lengthValue) => {
|
|
56
|
+
const start = Math.max(Number.parseInt(startValue, 10) - 1, 0);
|
|
57
|
+
if (lengthValue) {
|
|
58
|
+
const length = Number.parseInt(lengthValue, 10);
|
|
59
|
+
return args.slice(start, start + length).join(" ");
|
|
60
|
+
}
|
|
61
|
+
return args.slice(start).join(" ");
|
|
62
|
+
});
|
|
63
|
+
const allArgs = args.join(" ");
|
|
64
|
+
return result.replace(/\$ARGUMENTS/g, allArgs).replace(/\$@/g, allArgs);
|
|
65
|
+
}
|
|
66
|
+
export function isTelegramPromptTemplateCommandName(name) {
|
|
67
|
+
return TELEGRAM_BOT_COMMAND_NAME_PATTERN.test(name);
|
|
68
|
+
}
|
|
69
|
+
export function mapPiPromptTemplateNameToTelegramCommandName(name) {
|
|
70
|
+
const command = name
|
|
71
|
+
.toLowerCase()
|
|
72
|
+
.replace(/[^a-z0-9_]+/g, "_")
|
|
73
|
+
.replace(/_+/g, "_")
|
|
74
|
+
.replace(/^_+|_+$/g, "")
|
|
75
|
+
.slice(0, 32)
|
|
76
|
+
.replace(/_+$/g, "");
|
|
77
|
+
return isTelegramPromptTemplateCommandName(command) ? command : undefined;
|
|
78
|
+
}
|
|
79
|
+
export function getTelegramPromptTemplateCommands(commands, reservedNames = new Set()) {
|
|
80
|
+
const seen = new Set();
|
|
81
|
+
const promptCommands = [];
|
|
82
|
+
for (const command of commands) {
|
|
83
|
+
if (command.source !== "prompt")
|
|
84
|
+
continue;
|
|
85
|
+
const telegramCommand = mapPiPromptTemplateNameToTelegramCommandName(command.name);
|
|
86
|
+
if (!telegramCommand)
|
|
87
|
+
continue;
|
|
88
|
+
if (reservedNames.has(telegramCommand))
|
|
89
|
+
continue;
|
|
90
|
+
if (seen.has(telegramCommand))
|
|
91
|
+
continue;
|
|
92
|
+
const sourcePath = command.sourceInfo?.path;
|
|
93
|
+
if (!sourcePath)
|
|
94
|
+
continue;
|
|
95
|
+
seen.add(telegramCommand);
|
|
96
|
+
promptCommands.push({
|
|
97
|
+
command: telegramCommand,
|
|
98
|
+
description: command.description,
|
|
99
|
+
path: sourcePath,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return promptCommands.sort((a, b) => a.command.localeCompare(b.command));
|
|
103
|
+
}
|
|
104
|
+
export function createTelegramPromptTemplateCommandGetter(deps) {
|
|
105
|
+
return () => {
|
|
106
|
+
return getTelegramPromptTemplateCommands(deps.getCommands(), new Set([
|
|
107
|
+
...(deps.reservedCommandNames ?? []),
|
|
108
|
+
...(deps.getReservedCommandNames?.() ?? []),
|
|
109
|
+
]));
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export function expandTelegramPromptTemplateCommand(commandName, args, commands, readTemplate = (path) => readFileSync(path, "utf-8")) {
|
|
113
|
+
const command = commands.find((candidate) => candidate.command === commandName);
|
|
114
|
+
if (!command)
|
|
115
|
+
return undefined;
|
|
116
|
+
const content = stripPromptTemplateFrontmatter(readTemplate(command.path));
|
|
117
|
+
return substitutePromptTemplateArgs(content, parsePromptTemplateArgs(args));
|
|
118
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram prompt injection helpers
|
|
3
|
+
* Zones: pi agent prompts, telegram guidance
|
|
4
|
+
* Owns Telegram-specific system prompt suffixes injected into pi agent turns
|
|
5
|
+
*/
|
|
6
|
+
import type { BeforeAgentStartEvent } from "./pi.ts";
|
|
7
|
+
export declare const TELEGRAM_CONNECTED_CONTEXT_MESSAGE = "Telegram session connected. Use Telegram features for Telegram-originated turns or explicit Telegram requests; connectivity alone is not user intent.";
|
|
8
|
+
export declare const TELEGRAM_DISCONNECTED_CONTEXT_MESSAGE = "Telegram session disconnected. Do not use Telegram delivery, actions, or Telegram-specific reply features unless the user reconnects it.";
|
|
9
|
+
export declare const TELEGRAM_ATTACH_PROMPT_SNIPPET = "Queue files for the active Telegram reply; outside Telegram turns, send files directly to Telegram.";
|
|
10
|
+
export declare const TELEGRAM_ATTACH_PROMPT_GUIDELINES: readonly ["When handling a [telegram] message and the user asked for a file or generated artifact, call telegram_attach with the local path instead of only mentioning the path in text.", "When a local/TUI user explicitly asks to send a generated file to Telegram, telegram_attach can deliver it to the paired/default Telegram chat even without an active Telegram turn.", "For an explicit thread target, provide chat_id plus thread_id; registered multi-instance followers default to their assigned thread target."];
|
|
11
|
+
export declare const TELEGRAM_MESSAGE_PROMPT_SNIPPET = "Send direct Telegram Markdown text when the user explicitly asks for Telegram delivery to a concrete chat, channel, or live Pi Thread outside the normal reply flow.";
|
|
12
|
+
export declare const TELEGRAM_MESSAGE_PROMPT_GUIDELINES: readonly ["Use telegram_message only when the user explicitly asks to send a message to Telegram from the local/TUI side, or names a concrete Telegram delivery target.", "For an explicitly requested channel post, pass its exact numeric id or public @username as chat_id; no local channel registry is required, and Telegram remains the authority on the bot's posting permission.", "For an explicitly requested channel media post, pass one local .jpg/.jpeg/.png/.webp photo or .mp4 video as media; the text becomes its caption (max 1024 characters), and albums or other media types are rejected.", "For a live Pi thread target, provide thread as its case-insensitive name or numeric id; the bridge sends visibly and admits one attributed turn to that live instance. Unknown, ambiguous, same, or offline targets fail before sending.", "Add buttons by embedding the same top-level telegram_button HTML comments used in normal Telegram replies; Telegram does not support standalone buttons.", "During an active Telegram turn, omit telegram_message for the current target and answer normally; use thread only when the user requests delivery to a different live Pi thread."];
|
|
13
|
+
export interface TelegramModelContextAvailabilityMemory {
|
|
14
|
+
suspended: boolean;
|
|
15
|
+
toolNames: Set<string>;
|
|
16
|
+
}
|
|
17
|
+
export interface TelegramModelContextAvailabilityRuntime {
|
|
18
|
+
reconcile: () => void;
|
|
19
|
+
}
|
|
20
|
+
export interface TelegramModelContextAvailabilityBinding extends TelegramModelContextAvailabilityRuntime {
|
|
21
|
+
bind: (runtime: TelegramModelContextAvailabilityRuntime) => void;
|
|
22
|
+
}
|
|
23
|
+
export declare function createTelegramModelContextAvailabilityBinding(): TelegramModelContextAvailabilityBinding;
|
|
24
|
+
export declare function createTelegramModelContextAvailabilityRuntime(deps: {
|
|
25
|
+
getActiveTools: () => string[];
|
|
26
|
+
setActiveTools: (names: string[]) => void;
|
|
27
|
+
isAvailable: () => boolean;
|
|
28
|
+
canReconcile?: () => boolean;
|
|
29
|
+
memory?: TelegramModelContextAvailabilityMemory;
|
|
30
|
+
}): TelegramModelContextAvailabilityRuntime;
|
|
31
|
+
export type TelegramSystemPrompt = string | string[];
|
|
32
|
+
type TelegramBeforeAgentStartEvent = Omit<BeforeAgentStartEvent, "systemPrompt"> & {
|
|
33
|
+
systemPrompt?: TelegramSystemPrompt | null;
|
|
34
|
+
};
|
|
35
|
+
type TelegramBeforeAgentStartResult = {
|
|
36
|
+
systemPrompt: TelegramSystemPrompt;
|
|
37
|
+
};
|
|
38
|
+
type TelegramBeforeAgentStartHook = (event: TelegramBeforeAgentStartEvent) => TelegramBeforeAgentStartResult;
|
|
39
|
+
export declare function buildTelegramBridgeSystemPrompt(options: {
|
|
40
|
+
prompt: string;
|
|
41
|
+
systemPrompt?: TelegramSystemPrompt | null;
|
|
42
|
+
telegramPrefix?: string;
|
|
43
|
+
localSystemPromptSuffix: string;
|
|
44
|
+
telegramTurnSystemPromptSuffix: string;
|
|
45
|
+
}): TelegramBeforeAgentStartResult;
|
|
46
|
+
export declare function createTelegramBeforeAgentStartHook(options?: {
|
|
47
|
+
telegramPrefix?: string;
|
|
48
|
+
localSystemPromptSuffix?: string;
|
|
49
|
+
telegramTurnSystemPromptSuffix?: string;
|
|
50
|
+
}): TelegramBeforeAgentStartHook;
|
|
51
|
+
export interface TelegramProactivePromptHookDeps<TContext> {
|
|
52
|
+
baseHook?: TelegramBeforeAgentStartHook;
|
|
53
|
+
reconcileAvailability?: () => void;
|
|
54
|
+
isAvailable: (ctx: TContext) => boolean;
|
|
55
|
+
}
|
|
56
|
+
export declare function createTelegramProactiveBeforeAgentStartHook<TContext>(deps: TelegramProactivePromptHookDeps<TContext>): (event: TelegramBeforeAgentStartEvent, ctx: TContext) => Promise<TelegramBeforeAgentStartResult>;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram prompt injection helpers
|
|
3
|
+
* Zones: pi agent prompts, telegram guidance
|
|
4
|
+
* Owns Telegram-specific system prompt suffixes injected into pi agent turns
|
|
5
|
+
*/
|
|
6
|
+
import { TELEGRAM_PREFIX } from "./turns.js";
|
|
7
|
+
export const TELEGRAM_CONNECTED_CONTEXT_MESSAGE = "Telegram session connected. Use Telegram features for Telegram-originated turns or explicit Telegram requests; connectivity alone is not user intent.";
|
|
8
|
+
export const TELEGRAM_DISCONNECTED_CONTEXT_MESSAGE = "Telegram session disconnected. Do not use Telegram delivery, actions, or Telegram-specific reply features unless the user reconnects it.";
|
|
9
|
+
const LOCAL_SYSTEM_PROMPT_SUFFIX = `
|
|
10
|
+
|
|
11
|
+
${TELEGRAM_CONNECTED_CONTEXT_MESSAGE} For Telegram work, consult bundled Skills in routing order: \`telegram-bridge\` for the transport and turn protocol, \`show-me\` when a user needs a truthful visual explanation of work or behavior, \`generated-control-surface\` when contextual controls materially shorten feedback, then \`generative-apps\` when the interaction warrants a reusable deterministic app. Load a Skill only if its instructions are not already present in the current context. Do not use Telegram-specific features from unrelated local/TUI prompts.`;
|
|
12
|
+
const TELEGRAM_TURN_SYSTEM_PROMPT_SUFFIX = `
|
|
13
|
+
|
|
14
|
+
Telegram turn note: Follow the applicable bundled Telegram Skills in routing order; load only missing instructions.`;
|
|
15
|
+
export const TELEGRAM_ATTACH_PROMPT_SNIPPET = "Queue files for the active Telegram reply; outside Telegram turns, send files directly to Telegram.";
|
|
16
|
+
export const TELEGRAM_ATTACH_PROMPT_GUIDELINES = [
|
|
17
|
+
"When handling a [telegram] message and the user asked for a file or generated artifact, call telegram_attach with the local path instead of only mentioning the path in text.",
|
|
18
|
+
"When a local/TUI user explicitly asks to send a generated file to Telegram, telegram_attach can deliver it to the paired/default Telegram chat even without an active Telegram turn.",
|
|
19
|
+
"For an explicit thread target, provide chat_id plus thread_id; registered multi-instance followers default to their assigned thread target.",
|
|
20
|
+
];
|
|
21
|
+
export const TELEGRAM_MESSAGE_PROMPT_SNIPPET = "Send direct Telegram Markdown text when the user explicitly asks for Telegram delivery to a concrete chat, channel, or live Pi Thread outside the normal reply flow.";
|
|
22
|
+
export const TELEGRAM_MESSAGE_PROMPT_GUIDELINES = [
|
|
23
|
+
"Use telegram_message only when the user explicitly asks to send a message to Telegram from the local/TUI side, or names a concrete Telegram delivery target.",
|
|
24
|
+
"For an explicitly requested channel post, pass its exact numeric id or public @username as chat_id; no local channel registry is required, and Telegram remains the authority on the bot's posting permission.",
|
|
25
|
+
"For an explicitly requested channel media post, pass one local .jpg/.jpeg/.png/.webp photo or .mp4 video as media; the text becomes its caption (max 1024 characters), and albums or other media types are rejected.",
|
|
26
|
+
"For a live Pi thread target, provide thread as its case-insensitive name or numeric id; the bridge sends visibly and admits one attributed turn to that live instance. Unknown, ambiguous, same, or offline targets fail before sending.",
|
|
27
|
+
"Add buttons by embedding the same top-level telegram_button HTML comments used in normal Telegram replies; Telegram does not support standalone buttons.",
|
|
28
|
+
"During an active Telegram turn, omit telegram_message for the current target and answer normally; use thread only when the user requests delivery to a different live Pi thread.",
|
|
29
|
+
];
|
|
30
|
+
const TELEGRAM_TOOL_METADATA_LINES = Object.fromEntries([
|
|
31
|
+
`- telegram_attach: ${TELEGRAM_ATTACH_PROMPT_SNIPPET}`,
|
|
32
|
+
`- telegram_message: ${TELEGRAM_MESSAGE_PROMPT_SNIPPET}`,
|
|
33
|
+
...TELEGRAM_ATTACH_PROMPT_GUIDELINES.map((line) => `- ${line}`),
|
|
34
|
+
...TELEGRAM_MESSAGE_PROMPT_GUIDELINES.map((line) => `- ${line}`),
|
|
35
|
+
].map((line) => [line, true]));
|
|
36
|
+
const TELEGRAM_MODEL_CONTEXT_TOOL_NAMES = new Set([
|
|
37
|
+
"telegram_attach",
|
|
38
|
+
"telegram_bind",
|
|
39
|
+
"telegram_channel_post",
|
|
40
|
+
"telegram_channel_posts",
|
|
41
|
+
"telegram_message",
|
|
42
|
+
]);
|
|
43
|
+
const TELEGRAM_MODEL_CONTEXT_MEMORY_KEY = Symbol.for("@llblab/pi-telegram:model-context-suspended-tools");
|
|
44
|
+
function getTelegramModelContextAvailabilityMemory() {
|
|
45
|
+
const globals = globalThis;
|
|
46
|
+
const existing = globals[TELEGRAM_MODEL_CONTEXT_MEMORY_KEY];
|
|
47
|
+
if (existing &&
|
|
48
|
+
typeof existing === "object" &&
|
|
49
|
+
"toolNames" in existing &&
|
|
50
|
+
existing.toolNames instanceof Set) {
|
|
51
|
+
return existing;
|
|
52
|
+
}
|
|
53
|
+
const memory = {
|
|
54
|
+
suspended: false,
|
|
55
|
+
toolNames: new Set(),
|
|
56
|
+
};
|
|
57
|
+
globals[TELEGRAM_MODEL_CONTEXT_MEMORY_KEY] = memory;
|
|
58
|
+
return memory;
|
|
59
|
+
}
|
|
60
|
+
export function createTelegramModelContextAvailabilityBinding() {
|
|
61
|
+
let runtime;
|
|
62
|
+
return {
|
|
63
|
+
bind(next) {
|
|
64
|
+
runtime = next;
|
|
65
|
+
},
|
|
66
|
+
reconcile() {
|
|
67
|
+
runtime?.reconcile();
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function createTelegramModelContextAvailabilityRuntime(deps) {
|
|
72
|
+
const memory = deps.memory ?? getTelegramModelContextAvailabilityMemory();
|
|
73
|
+
return {
|
|
74
|
+
reconcile() {
|
|
75
|
+
if (deps.canReconcile && !deps.canReconcile())
|
|
76
|
+
return;
|
|
77
|
+
const activeTools = deps.getActiveTools();
|
|
78
|
+
if (!deps.isAvailable()) {
|
|
79
|
+
if (!memory.suspended) {
|
|
80
|
+
memory.toolNames.clear();
|
|
81
|
+
for (const name of activeTools) {
|
|
82
|
+
if (TELEGRAM_MODEL_CONTEXT_TOOL_NAMES.has(name)) {
|
|
83
|
+
memory.toolNames.add(name);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
memory.suspended = true;
|
|
87
|
+
}
|
|
88
|
+
const nextTools = activeTools.filter((name) => !TELEGRAM_MODEL_CONTEXT_TOOL_NAMES.has(name));
|
|
89
|
+
if (nextTools.length !== activeTools.length) {
|
|
90
|
+
deps.setActiveTools(nextTools);
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (!memory.suspended)
|
|
95
|
+
return;
|
|
96
|
+
const nextTools = [...activeTools];
|
|
97
|
+
for (const name of TELEGRAM_MODEL_CONTEXT_TOOL_NAMES) {
|
|
98
|
+
if (memory.toolNames.has(name) && !nextTools.includes(name)) {
|
|
99
|
+
nextTools.push(name);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
memory.toolNames.clear();
|
|
103
|
+
memory.suspended = false;
|
|
104
|
+
if (nextTools.length !== activeTools.length) {
|
|
105
|
+
deps.setActiveTools(nextTools);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
export function buildTelegramBridgeSystemPrompt(options) {
|
|
111
|
+
const basePrompt = options.systemPrompt ?? "";
|
|
112
|
+
const telegramPrefix = options.telegramPrefix ?? TELEGRAM_PREFIX;
|
|
113
|
+
const telegramHead = telegramPrefix.endsWith("]")
|
|
114
|
+
? telegramPrefix.slice(0, -1)
|
|
115
|
+
: telegramPrefix;
|
|
116
|
+
const trimmedPrompt = options.prompt.trimStart();
|
|
117
|
+
const telegramTurn = trimmedPrompt.startsWith(`${telegramHead}]`) ||
|
|
118
|
+
trimmedPrompt.startsWith(`${telegramHead}|`);
|
|
119
|
+
const telegramSuffix = telegramTurn
|
|
120
|
+
? `${options.telegramTurnSystemPromptSuffix}\n- The current user message came from Telegram.`
|
|
121
|
+
: "";
|
|
122
|
+
return {
|
|
123
|
+
systemPrompt: Array.isArray(basePrompt)
|
|
124
|
+
? [
|
|
125
|
+
...basePrompt,
|
|
126
|
+
options.localSystemPromptSuffix + telegramSuffix,
|
|
127
|
+
]
|
|
128
|
+
: basePrompt +
|
|
129
|
+
options.localSystemPromptSuffix +
|
|
130
|
+
telegramSuffix,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
export function createTelegramBeforeAgentStartHook(options = {}) {
|
|
134
|
+
return (event) => buildTelegramBridgeSystemPrompt({
|
|
135
|
+
prompt: event.prompt,
|
|
136
|
+
systemPrompt: event.systemPrompt,
|
|
137
|
+
telegramPrefix: options.telegramPrefix,
|
|
138
|
+
localSystemPromptSuffix: options.localSystemPromptSuffix ?? LOCAL_SYSTEM_PROMPT_SUFFIX,
|
|
139
|
+
telegramTurnSystemPromptSuffix: options.telegramTurnSystemPromptSuffix ??
|
|
140
|
+
TELEGRAM_TURN_SYSTEM_PROMPT_SUFFIX,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
function stripTelegramToolMetadataFromString(systemPrompt) {
|
|
144
|
+
return systemPrompt
|
|
145
|
+
.split("\n")
|
|
146
|
+
.filter((line) => TELEGRAM_TOOL_METADATA_LINES[line] !== true)
|
|
147
|
+
.join("\n");
|
|
148
|
+
}
|
|
149
|
+
function stripTelegramToolMetadataFromSystemPrompt(systemPrompt) {
|
|
150
|
+
if (!systemPrompt)
|
|
151
|
+
return "";
|
|
152
|
+
return Array.isArray(systemPrompt)
|
|
153
|
+
? systemPrompt.map(stripTelegramToolMetadataFromString)
|
|
154
|
+
: stripTelegramToolMetadataFromString(systemPrompt);
|
|
155
|
+
}
|
|
156
|
+
export function createTelegramProactiveBeforeAgentStartHook(deps) {
|
|
157
|
+
const baseHook = deps.baseHook ?? createTelegramBeforeAgentStartHook();
|
|
158
|
+
return async (event, ctx) => {
|
|
159
|
+
deps.reconcileAvailability?.();
|
|
160
|
+
if (!deps.isAvailable(ctx)) {
|
|
161
|
+
return {
|
|
162
|
+
systemPrompt: stripTelegramToolMetadataFromSystemPrompt(event.systemPrompt),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return baseHook(event);
|
|
166
|
+
};
|
|
167
|
+
}
|