@llblab/pi-telegram 0.36.1 → 0.36.3
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 +0 -1
- package/CHANGELOG.md +9 -1
- package/README.md +1 -1
- package/docs/ui-style.md +7 -6
- package/lib/generative-apps.ts +8 -15
- package/lib/lifecycle.ts +19 -3
- package/lib/menu-thinking.ts +7 -6
- package/lib/prompts.ts +50 -18
- package/package.json +1 -1
package/BACKLOG.md
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
_This file owns unresolved project work only. Completed behavior belongs in `CHANGELOG.md`; durable contracts belong in `AGENTS.md` and `/docs`._
|
|
4
4
|
|
|
5
|
-
- [ ] `Automated release publication live proof`: Exercise the implemented tag-triggered release path on `v0.36.1` and verify reusable full validation, exact tag/version/lock/changelog preflight, npm Trusted Publisher provenance, idempotent package identity, public tarball contents, and one workflow-owned GitHub Release before declaring manual npm publication retired.
|
|
6
5
|
- [ ] `Operator-confirmed pairing`: Replace first-contact automatic ownership with an explicit pending request that the trusted Pi interface can allow or reject before `allowedUserId` is persisted or any Telegram prompt executes; retain manual preconfiguration, bound pending-request lifetime and multiplicity, fail closed across session/transport replacement, and cover unauthorized-first-contact races.
|
|
7
6
|
- [ ] `Environment-backed bot tokens`: Let each profile store an exact Pi-native `$ENV_VAR` or `${ENV_VAR}` reference in `telegram.json` instead of copying the resolved secret; preserve the originating alias when `/telegram-setup` prefills from a supported environment variable, resolve only at validation/activation boundaries, fail closed with a redacted named-variable diagnostic when unresolved, retain literal-token compatibility, and cover named profiles, reload, persistence, status, and secret-redaction paths.
|
|
8
7
|
- [ ] [`Inference bypass Generative Apps`](./docs/generative-apps.md): Let the agent install and bind one managed JavaScript app owner for a generated-prompt prefix so deterministic controls can bypass model inference without creating another button grammar.
|
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
> Each release keeps at most 8 outcome records of at most 512 characters.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 0.36.3: Ordered Prompt Compatibility
|
|
6
|
+
|
|
7
|
+
- `Prompt Compatibility`: Preserves plain and ordered-block system prompts across Pi-compatible runtimes; Telegram guidance remains a distinct block when the host supplies blocks, while unavailable transport strips only Telegram tool metadata without collapsing unrelated prompt context.
|
|
8
|
+
|
|
9
|
+
## 0.36.2: Provider-Compatible Controls
|
|
10
|
+
|
|
11
|
+
- `Provider-Compatible Bind Schema`: Exposes `telegram_bind` through one top-level JSON object schema while retaining runtime enforcement of mutually exclusive install and invocation forms, avoiding providers that reject top-level union schemas before any tool call can run.
|
|
12
|
+
- `Reaction Shortcut Naming`: Removes obsolete reaction-action labels from setup guidance now that queue reaction semantics use their current naming.
|
|
13
|
+
- `Compact Thinking Picker`: Keeps `off` on a distinct full-width row and groups the six ordered reasoning intensities into two three-button rows, reducing menu height without changing thinking-level values or callbacks.
|
|
6
14
|
|
|
7
15
|
## 0.36.1: Adaptive Control Surfaces
|
|
8
16
|
|
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ Enable the optional capabilities the bridge needs in the [@BotFather](https://t.
|
|
|
86
86
|
|
|
87
87
|
1. Enable guest mode so the bot can answer mentions and replies in chats where it is not a member.
|
|
88
88
|
2. Enable private-chat Threaded Mode; when it is available, one live instance becomes the profile's leader and later visible Pi instances register as followers. Without it, the bridge stays in classic single-owner DM mode.
|
|
89
|
-
3. Make the bot an administrator in any chat where the queue reaction shortcuts
|
|
89
|
+
3. Make the bot an administrator in any chat where the queue reaction shortcuts should work. Reaction updates require admin rights, so the shortcuts silently do nothing in non-admin chats; private chats deliver reactions without admin rights.
|
|
90
90
|
|
|
91
91
|
## What It Feels Like
|
|
92
92
|
|
package/docs/ui-style.md
CHANGED
|
@@ -168,22 +168,23 @@ Examples:
|
|
|
168
168
|
- `⚫️ Priority` / `🟣 Normal`
|
|
169
169
|
- `1` / `🟣 2` / `3`
|
|
170
170
|
|
|
171
|
-
##
|
|
171
|
+
## Option Lists
|
|
172
172
|
|
|
173
|
-
|
|
173
|
+
Option lists choose one value from a fixed set, for example model selection, thinking level, voice reply mode, or time injection mode.
|
|
174
174
|
|
|
175
175
|
Rules:
|
|
176
176
|
|
|
177
|
-
- Put each option on its own row.
|
|
177
|
+
- Put each option on its own row when labels are long, the set may grow, or scanning benefits from full width.
|
|
178
|
+
- A fixed set of short, ordered peer values may use compact rows of up to three buttons.
|
|
179
|
+
- Keep a semantically distinct value such as thinking `off` on its own full-width row before grouped intensity values.
|
|
178
180
|
- Mark only the current value with `🟢`.
|
|
179
181
|
- Leave non-current values without emoji.
|
|
180
182
|
- Use lowercase labels when the option is a value.
|
|
181
183
|
|
|
182
184
|
Examples:
|
|
183
185
|
|
|
184
|
-
- `hidden`
|
|
185
|
-
- `🟢
|
|
186
|
-
- `always`
|
|
186
|
+
- Vertical: `hidden`, `🟢 mirror`, `always`.
|
|
187
|
+
- Thinking: full-width `off`, then `minimal` / `low` / `🟢 medium`, then `high` / `xhigh` / `max`.
|
|
187
188
|
|
|
188
189
|
## Generated Prompt Buttons
|
|
189
190
|
|
package/lib/generative-apps.ts
CHANGED
|
@@ -871,21 +871,14 @@ export function registerTelegramBindTool(
|
|
|
871
871
|
label: "Telegram Bind",
|
|
872
872
|
description:
|
|
873
873
|
"Install, explicitly replace, or invoke one named method on a managed Generative App; successful output displays directly in the active Telegram turn unless display is false.",
|
|
874
|
-
parameters: Type.
|
|
875
|
-
Type.
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
Type.Object({
|
|
883
|
-
app: Type.String(),
|
|
884
|
-
method: Type.String(),
|
|
885
|
-
display: Type.Optional(Type.Boolean()),
|
|
886
|
-
argument: Type.Optional(Type.Unknown()),
|
|
887
|
-
}, { additionalProperties: false }),
|
|
888
|
-
]),
|
|
874
|
+
parameters: Type.Object({
|
|
875
|
+
app: Type.String(),
|
|
876
|
+
script: Type.Optional(Type.String()),
|
|
877
|
+
method: Type.Optional(Type.String()),
|
|
878
|
+
replace: Type.Optional(Type.Boolean()),
|
|
879
|
+
display: Type.Optional(Type.Boolean()),
|
|
880
|
+
argument: Type.Optional(Type.Unknown()),
|
|
881
|
+
}, { additionalProperties: false }),
|
|
889
882
|
async execute(_toolCallId, params) {
|
|
890
883
|
try {
|
|
891
884
|
const result = await bindGenerativeApp({
|
package/lib/lifecycle.ts
CHANGED
|
@@ -40,8 +40,15 @@ export function createAgentStartDedupHook(
|
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
type TelegramBeforeAgentStartEvent = Omit<
|
|
44
|
+
BeforeAgentStartEvent,
|
|
45
|
+
"systemPrompt"
|
|
46
|
+
> & {
|
|
47
|
+
systemPrompt: string | string[];
|
|
48
|
+
};
|
|
49
|
+
|
|
43
50
|
export interface TelegramBeforeAgentStartResult {
|
|
44
|
-
systemPrompt?: string;
|
|
51
|
+
systemPrompt?: string | string[];
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
type TelegramBeforeAgentStartReturn =
|
|
@@ -72,7 +79,7 @@ export interface TelegramLifecycleRegistrationDeps {
|
|
|
72
79
|
ctx: ExtensionContext,
|
|
73
80
|
) => Promise<void> | void;
|
|
74
81
|
onBeforeAgentStart: (
|
|
75
|
-
event:
|
|
82
|
+
event: TelegramBeforeAgentStartEvent,
|
|
76
83
|
ctx: ExtensionContext,
|
|
77
84
|
) => TelegramBeforeAgentStartReturn;
|
|
78
85
|
onModelSelect: (
|
|
@@ -581,7 +588,16 @@ export function registerTelegramLifecycleHooks(
|
|
|
581
588
|
if (!isActive(ctx)) return;
|
|
582
589
|
await deps.onSessionCompact?.(event, ctx);
|
|
583
590
|
});
|
|
584
|
-
|
|
591
|
+
// The Pi SDK still types this result as a string; compatible runtimes may
|
|
592
|
+
// preserve ordered system prompt blocks through the same public hook.
|
|
593
|
+
const registerBeforeAgentStart = pi.on.bind(pi) as unknown as (
|
|
594
|
+
event: "before_agent_start",
|
|
595
|
+
handler: (
|
|
596
|
+
event: TelegramBeforeAgentStartEvent,
|
|
597
|
+
ctx: ExtensionContext,
|
|
598
|
+
) => TelegramBeforeAgentStartReturn,
|
|
599
|
+
) => void;
|
|
600
|
+
registerBeforeAgentStart("before_agent_start", async (event, ctx) => {
|
|
585
601
|
return deps.onBeforeAgentStart(event, ctx);
|
|
586
602
|
});
|
|
587
603
|
pi.on("model_select", async (event, ctx) => {
|
package/lib/menu-thinking.ts
CHANGED
|
@@ -128,13 +128,14 @@ export function buildThinkingMenuReplyMarkup(
|
|
|
128
128
|
currentThinkingLevel: ThinkingLevel,
|
|
129
129
|
): TelegramReplyMarkup {
|
|
130
130
|
const rows = [[{ text: "⬆️ Main menu", callback_data: "menu:back" }]];
|
|
131
|
+
const levelButtons = THINKING_LEVELS.map((level) => ({
|
|
132
|
+
text: level === currentThinkingLevel ? `🟢 ${level}` : level,
|
|
133
|
+
callback_data: `thinking:set:${level}`,
|
|
134
|
+
}));
|
|
131
135
|
rows.push(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
callback_data: `thinking:set:${level}`,
|
|
136
|
-
},
|
|
137
|
-
]),
|
|
136
|
+
levelButtons.slice(0, 1),
|
|
137
|
+
levelButtons.slice(1, 4),
|
|
138
|
+
levelButtons.slice(4, 7),
|
|
138
139
|
);
|
|
139
140
|
return { inline_keyboard: rows };
|
|
140
141
|
}
|
package/lib/prompts.ts
CHANGED
|
@@ -31,6 +31,15 @@ export const TELEGRAM_MESSAGE_PROMPT_GUIDELINES = [
|
|
|
31
31
|
"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.",
|
|
32
32
|
] as const;
|
|
33
33
|
|
|
34
|
+
const TELEGRAM_TOOL_METADATA_LINES = Object.fromEntries(
|
|
35
|
+
[
|
|
36
|
+
`- telegram_attach: ${TELEGRAM_ATTACH_PROMPT_SNIPPET}`,
|
|
37
|
+
`- telegram_message: ${TELEGRAM_MESSAGE_PROMPT_SNIPPET}`,
|
|
38
|
+
...TELEGRAM_ATTACH_PROMPT_GUIDELINES.map((line) => `- ${line}`),
|
|
39
|
+
...TELEGRAM_MESSAGE_PROMPT_GUIDELINES.map((line) => `- ${line}`),
|
|
40
|
+
].map((line) => [line, true]),
|
|
41
|
+
) as Record<string, true>;
|
|
42
|
+
|
|
34
43
|
const TELEGRAM_MODEL_CONTEXT_TOOL_NAMES = new Set([
|
|
35
44
|
"telegram_attach",
|
|
36
45
|
"telegram_bind",
|
|
@@ -132,13 +141,30 @@ export function createTelegramModelContextAvailabilityRuntime(deps: {
|
|
|
132
141
|
};
|
|
133
142
|
}
|
|
134
143
|
|
|
144
|
+
export type TelegramSystemPrompt = string | string[];
|
|
145
|
+
|
|
146
|
+
type TelegramBeforeAgentStartEvent = Omit<
|
|
147
|
+
BeforeAgentStartEvent,
|
|
148
|
+
"systemPrompt"
|
|
149
|
+
> & {
|
|
150
|
+
systemPrompt: TelegramSystemPrompt;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
type TelegramBeforeAgentStartResult = {
|
|
154
|
+
systemPrompt: TelegramSystemPrompt;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
type TelegramBeforeAgentStartHook = (
|
|
158
|
+
event: TelegramBeforeAgentStartEvent,
|
|
159
|
+
) => TelegramBeforeAgentStartResult;
|
|
160
|
+
|
|
135
161
|
export function buildTelegramBridgeSystemPrompt(options: {
|
|
136
162
|
prompt: string;
|
|
137
|
-
systemPrompt:
|
|
163
|
+
systemPrompt: TelegramSystemPrompt;
|
|
138
164
|
telegramPrefix?: string;
|
|
139
165
|
localSystemPromptSuffix: string;
|
|
140
166
|
telegramTurnSystemPromptSuffix: string;
|
|
141
|
-
}):
|
|
167
|
+
}): TelegramBeforeAgentStartResult {
|
|
142
168
|
const telegramPrefix = options.telegramPrefix ?? TELEGRAM_PREFIX;
|
|
143
169
|
const telegramHead = telegramPrefix.endsWith("]")
|
|
144
170
|
? telegramPrefix.slice(0, -1)
|
|
@@ -151,8 +177,14 @@ export function buildTelegramBridgeSystemPrompt(options: {
|
|
|
151
177
|
? `${options.telegramTurnSystemPromptSuffix}\n- The current user message came from Telegram.`
|
|
152
178
|
: "";
|
|
153
179
|
return {
|
|
154
|
-
systemPrompt:
|
|
155
|
-
|
|
180
|
+
systemPrompt: Array.isArray(options.systemPrompt)
|
|
181
|
+
? [
|
|
182
|
+
...options.systemPrompt,
|
|
183
|
+
options.localSystemPromptSuffix + telegramSuffix,
|
|
184
|
+
]
|
|
185
|
+
: options.systemPrompt +
|
|
186
|
+
options.localSystemPromptSuffix +
|
|
187
|
+
telegramSuffix,
|
|
156
188
|
};
|
|
157
189
|
}
|
|
158
190
|
|
|
@@ -162,7 +194,7 @@ export function createTelegramBeforeAgentStartHook(
|
|
|
162
194
|
localSystemPromptSuffix?: string;
|
|
163
195
|
telegramTurnSystemPromptSuffix?: string;
|
|
164
196
|
} = {},
|
|
165
|
-
):
|
|
197
|
+
): TelegramBeforeAgentStartHook {
|
|
166
198
|
return (event) =>
|
|
167
199
|
buildTelegramBridgeSystemPrompt({
|
|
168
200
|
prompt: event.prompt,
|
|
@@ -176,23 +208,23 @@ export function createTelegramBeforeAgentStartHook(
|
|
|
176
208
|
});
|
|
177
209
|
}
|
|
178
210
|
|
|
179
|
-
function
|
|
180
|
-
systemPrompt: string,
|
|
181
|
-
): string {
|
|
182
|
-
const telegramLines = new Set([
|
|
183
|
-
`- telegram_attach: ${TELEGRAM_ATTACH_PROMPT_SNIPPET}`,
|
|
184
|
-
`- telegram_message: ${TELEGRAM_MESSAGE_PROMPT_SNIPPET}`,
|
|
185
|
-
...TELEGRAM_ATTACH_PROMPT_GUIDELINES.map((line) => `- ${line}`),
|
|
186
|
-
...TELEGRAM_MESSAGE_PROMPT_GUIDELINES.map((line) => `- ${line}`),
|
|
187
|
-
]);
|
|
211
|
+
function stripTelegramToolMetadataFromString(systemPrompt: string): string {
|
|
188
212
|
return systemPrompt
|
|
189
213
|
.split("\n")
|
|
190
|
-
.filter((line) =>
|
|
214
|
+
.filter((line) => TELEGRAM_TOOL_METADATA_LINES[line] !== true)
|
|
191
215
|
.join("\n");
|
|
192
216
|
}
|
|
193
217
|
|
|
218
|
+
function stripTelegramToolMetadataFromSystemPrompt(
|
|
219
|
+
systemPrompt: TelegramSystemPrompt,
|
|
220
|
+
): TelegramSystemPrompt {
|
|
221
|
+
return Array.isArray(systemPrompt)
|
|
222
|
+
? systemPrompt.map(stripTelegramToolMetadataFromString)
|
|
223
|
+
: stripTelegramToolMetadataFromString(systemPrompt);
|
|
224
|
+
}
|
|
225
|
+
|
|
194
226
|
export interface TelegramProactivePromptHookDeps<TContext> {
|
|
195
|
-
baseHook?:
|
|
227
|
+
baseHook?: TelegramBeforeAgentStartHook;
|
|
196
228
|
reconcileAvailability?: () => void;
|
|
197
229
|
isAvailable: (ctx: TContext) => boolean;
|
|
198
230
|
}
|
|
@@ -200,9 +232,9 @@ export interface TelegramProactivePromptHookDeps<TContext> {
|
|
|
200
232
|
export function createTelegramProactiveBeforeAgentStartHook<TContext>(
|
|
201
233
|
deps: TelegramProactivePromptHookDeps<TContext>,
|
|
202
234
|
): (
|
|
203
|
-
event:
|
|
235
|
+
event: TelegramBeforeAgentStartEvent,
|
|
204
236
|
ctx: TContext,
|
|
205
|
-
) => Promise<
|
|
237
|
+
) => Promise<TelegramBeforeAgentStartResult> {
|
|
206
238
|
const baseHook = deps.baseHook ?? createTelegramBeforeAgentStartHook();
|
|
207
239
|
return async (event, ctx) => {
|
|
208
240
|
deps.reconcileAvailability?.();
|