@llblab/pi-telegram 0.20.6 → 0.21.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 +7 -5
- package/BACKLOG.md +3 -45
- package/CHANGELOG.md +16 -0
- package/README.md +7 -1
- package/api/activity.ts +15 -0
- package/api/commands.ts +1 -1
- package/api/delivery.ts +21 -0
- package/api/inbound.ts +1 -1
- package/api/keyboard.ts +1 -1
- package/api/outbound.ts +1 -1
- package/api/sections.ts +1 -1
- package/api/status.ts +2 -2
- package/api/updates.ts +1 -1
- package/api/voice.ts +1 -1
- package/docs/README.md +2 -0
- package/docs/activity.md +294 -0
- package/docs/architecture.md +7 -1
- package/docs/delivery.md +224 -0
- package/docs/public-api.md +92 -1
- package/docs/sections.md +6 -5
- package/index.ts +53 -0
- package/lib/activity.ts +683 -0
- package/lib/bindings.ts +60 -8
- package/lib/bus-api.ts +2 -1
- package/lib/bus-leader.ts +4 -1
- package/lib/bus.ts +38 -0
- package/lib/delivery.ts +800 -0
- package/lib/lifecycle.ts +23 -4
- package/lib/model.ts +3 -1
- package/lib/pi.ts +21 -5
- package/lib/routing.ts +18 -3
- package/lib/sections.ts +1 -1
- package/lib/status.ts +2 -2
- package/lib/updates.ts +4 -4
- package/package.json +6 -4
package/lib/bindings.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Owns pi-facing tool, command, and lifecycle hook registration for the entrypoint
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import * as Activity from "./activity.ts";
|
|
7
8
|
import * as CommandTemplates from "./command-templates.ts";
|
|
8
9
|
import * as Commands from "./commands.ts";
|
|
9
10
|
import * as Config from "./config.ts";
|
|
@@ -200,6 +201,7 @@ export function registerTelegramCommandsAndTools({
|
|
|
200
201
|
|
|
201
202
|
interface TelegramLifecycleBindingDeps {
|
|
202
203
|
pi: Pi.ExtensionAPI;
|
|
204
|
+
activityRuntime: Activity.TelegramActivityRuntime;
|
|
203
205
|
sessionLifecycleRuntime: Pick<
|
|
204
206
|
Lifecycle.TelegramLifecycleRegistrationDeps,
|
|
205
207
|
"onSessionStart" | "onSessionShutdown" | "onModelSelect"
|
|
@@ -276,6 +278,7 @@ interface TelegramLifecycleBindingDeps {
|
|
|
276
278
|
|
|
277
279
|
export function registerTelegramLifecycleRuntimeHooks({
|
|
278
280
|
pi,
|
|
281
|
+
activityRuntime,
|
|
279
282
|
sessionLifecycleRuntime,
|
|
280
283
|
configStore,
|
|
281
284
|
abort,
|
|
@@ -517,6 +520,7 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
517
520
|
deferredQueueDispatchRuntime.request,
|
|
518
521
|
dispatchNextQueuedTelegramTurn,
|
|
519
522
|
recordRuntimeEvent,
|
|
523
|
+
onCompactionAbandoned: activityRuntime.onCompactionAbandoned,
|
|
520
524
|
});
|
|
521
525
|
const messageActivityTypingHooks =
|
|
522
526
|
Lifecycle.createTelegramMessageActivityTypingHooks({
|
|
@@ -530,29 +534,77 @@ export function registerTelegramLifecycleRuntimeHooks({
|
|
|
530
534
|
Lifecycle.registerTelegramLifecycleHooks(pi, {
|
|
531
535
|
...sessionLifecycleRuntime,
|
|
532
536
|
...agentLifecycleHooks,
|
|
537
|
+
onInput(event) {
|
|
538
|
+
activityRuntime.recordInputSource(event.source ?? "unknown");
|
|
539
|
+
},
|
|
540
|
+
async onSessionStart(event, ctx) {
|
|
541
|
+
activityRuntime.onSessionStart?.();
|
|
542
|
+
await sessionLifecycleRuntime.onSessionStart(event, ctx);
|
|
543
|
+
},
|
|
533
544
|
async onSessionShutdown(event, ctx) {
|
|
545
|
+
activityRuntime.onSessionShutdown();
|
|
534
546
|
compactionObserver.onSessionShutdown();
|
|
535
547
|
await sessionLifecycleRuntime.onSessionShutdown(event, ctx);
|
|
536
548
|
},
|
|
537
|
-
onSessionBeforeCompact
|
|
538
|
-
|
|
549
|
+
onSessionBeforeCompact(event, ctx) {
|
|
550
|
+
activityRuntime.onCompactionStart(Pi.getSessionCompactionReason(event));
|
|
551
|
+
compactionObserver.onSessionBeforeCompact(event, ctx);
|
|
552
|
+
},
|
|
553
|
+
onSessionCompact(event, ctx) {
|
|
554
|
+
activityRuntime.onCompactionEnd(Pi.getSessionCompactionReason(event));
|
|
555
|
+
compactionObserver.onSessionCompact(event, ctx);
|
|
556
|
+
},
|
|
539
557
|
async onAgentStart(event, ctx) {
|
|
540
558
|
await agentStartWithDedupReset(event, ctx);
|
|
559
|
+
activityRuntime.onAgentStart(activeTurnRuntime.get()?.target);
|
|
541
560
|
startAgentActivityTypingLoop(ctx);
|
|
542
561
|
},
|
|
543
|
-
async onToolExecutionStart(
|
|
562
|
+
async onToolExecutionStart(event, _ctx) {
|
|
544
563
|
agentLifecycleHooks.onToolExecutionStart();
|
|
564
|
+
activityRuntime.onToolStart({
|
|
565
|
+
toolCallId: event.toolCallId,
|
|
566
|
+
toolName: event.toolName,
|
|
567
|
+
args: event.args,
|
|
568
|
+
});
|
|
569
|
+
},
|
|
570
|
+
onToolExecutionUpdate(event) {
|
|
571
|
+
activityRuntime.onToolUpdate({
|
|
572
|
+
toolCallId: event.toolCallId,
|
|
573
|
+
toolName: event.toolName,
|
|
574
|
+
update: event.partialResult,
|
|
575
|
+
});
|
|
576
|
+
},
|
|
577
|
+
async onToolExecutionEnd(event, ctx) {
|
|
578
|
+
activityRuntime.onToolEnd({
|
|
579
|
+
toolCallId: event.toolCallId,
|
|
580
|
+
toolName: event.toolName,
|
|
581
|
+
result: event.result,
|
|
582
|
+
isError: event.isError,
|
|
583
|
+
});
|
|
584
|
+
agentLifecycleHooks.onToolExecutionEnd(event, ctx);
|
|
585
|
+
},
|
|
586
|
+
async onMessageStart(event, ctx) {
|
|
587
|
+
await messageActivityHooks.onMessageStart(event, ctx);
|
|
588
|
+
},
|
|
589
|
+
async onMessageUpdate(event, ctx) {
|
|
590
|
+
if (event.assistantMessageEvent) {
|
|
591
|
+
activityRuntime.onAssistantEvent(
|
|
592
|
+
event.assistantMessageEvent as Activity.TelegramAssistantStreamEvent,
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
await messageActivityHooks.onMessageUpdate(event, ctx);
|
|
596
|
+
},
|
|
597
|
+
async onAgentEnd(event, ctx) {
|
|
598
|
+
activityRuntime.onAgentEnd();
|
|
599
|
+
await agentLifecycleHooks.onAgentEnd(event, ctx);
|
|
545
600
|
},
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
agentLifecycleHooks.onToolExecutionEnd(_event, ctx);
|
|
601
|
+
onAgentSettled() {
|
|
602
|
+
activityRuntime.onAgentSettled();
|
|
549
603
|
},
|
|
550
|
-
onAgentEnd: agentLifecycleHooks.onAgentEnd,
|
|
551
604
|
onBeforeAgentStart: Prompts.createTelegramProactiveBeforeAgentStartHook({
|
|
552
605
|
isConfigured: configStore.hasBotToken,
|
|
553
606
|
isProactivePushEnabled,
|
|
554
607
|
isCurrentOwner: lockOwnershipGuard.ownsContext,
|
|
555
608
|
}),
|
|
556
|
-
...messageActivityHooks,
|
|
557
609
|
});
|
|
558
610
|
}
|
package/lib/bus-api.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Wraps the direct Telegram Bot API runtime so follower instances can route outbound calls through the bus leader
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { stripTelegramBusApiMetadata } from "./bus.ts";
|
|
7
8
|
import type {
|
|
8
9
|
TelegramAnswerGuestQueryOptions,
|
|
9
10
|
TelegramApiCallOptions,
|
|
@@ -224,7 +225,7 @@ export function createTelegramBusAwareApiRuntime(
|
|
|
224
225
|
},
|
|
225
226
|
sendMessage(body: TelegramSendMessageBody): Promise<TelegramSentMessage> {
|
|
226
227
|
return deps.ownsDirect()
|
|
227
|
-
? deps.directRuntime.sendMessage(body)
|
|
228
|
+
? deps.directRuntime.sendMessage(stripTelegramBusApiMetadata(body))
|
|
228
229
|
: deps
|
|
229
230
|
.callFollowerApi("call", ["sendMessage", body])
|
|
230
231
|
.then(asSentMessage);
|
package/lib/bus-leader.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
isTelegramBusEnvelopeAuthorized,
|
|
17
17
|
getTelegramBusFollowerSocketPath,
|
|
18
18
|
sendTelegramBusLocalEnvelope,
|
|
19
|
+
stripTelegramBusApiMetadata,
|
|
19
20
|
type TelegramBusEnvelope,
|
|
20
21
|
type TelegramBusFollowerRegistry,
|
|
21
22
|
type TelegramBusFollowerView,
|
|
@@ -795,7 +796,9 @@ export function createTelegramBusLeaderApiProxy(
|
|
|
795
796
|
): (method: string, args: unknown[]) => Promise<unknown> {
|
|
796
797
|
return async (method, args) => {
|
|
797
798
|
if (method === "call") {
|
|
798
|
-
const body =
|
|
799
|
+
const body = stripTelegramBusApiMetadata(
|
|
800
|
+
args[1] as Record<string, unknown>,
|
|
801
|
+
);
|
|
799
802
|
try {
|
|
800
803
|
return await deps.call(
|
|
801
804
|
args[0] as string,
|
package/lib/bus.ts
CHANGED
|
@@ -145,6 +145,38 @@ export function getTelegramFollowerTargetOwnership(input: {
|
|
|
145
145
|
return record?.instanceId ? { instanceId: record.instanceId } : undefined;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
const TELEGRAM_BUS_AGGREGATE_DELIVERY_FIELD =
|
|
149
|
+
"__piTelegramAggregateDelivery";
|
|
150
|
+
|
|
151
|
+
export function markTelegramBusAggregateDelivery<T extends Record<string, unknown>>(
|
|
152
|
+
body: T,
|
|
153
|
+
): T {
|
|
154
|
+
return {
|
|
155
|
+
...body,
|
|
156
|
+
[TELEGRAM_BUS_AGGREGATE_DELIVERY_FIELD]: true,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function isTelegramBusAggregateDelivery(body: unknown): boolean {
|
|
161
|
+
return Boolean(
|
|
162
|
+
body &&
|
|
163
|
+
typeof body === "object" &&
|
|
164
|
+
!Array.isArray(body) &&
|
|
165
|
+
(body as Record<string, unknown>)[
|
|
166
|
+
TELEGRAM_BUS_AGGREGATE_DELIVERY_FIELD
|
|
167
|
+
] === true,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function stripTelegramBusApiMetadata<T extends Record<string, unknown>>(
|
|
172
|
+
body: T,
|
|
173
|
+
): T {
|
|
174
|
+
if (!(TELEGRAM_BUS_AGGREGATE_DELIVERY_FIELD in body)) return body;
|
|
175
|
+
const clean = { ...body };
|
|
176
|
+
delete clean[TELEGRAM_BUS_AGGREGATE_DELIVERY_FIELD];
|
|
177
|
+
return clean;
|
|
178
|
+
}
|
|
179
|
+
|
|
148
180
|
export function isTelegramFollowerApiCallAllowed(input: {
|
|
149
181
|
follower: TelegramBusFollowerView;
|
|
150
182
|
method: string;
|
|
@@ -227,6 +259,12 @@ export function isTelegramFollowerApiCallAllowed(input: {
|
|
|
227
259
|
return isBotCommandRegistration(input.args[1]);
|
|
228
260
|
if (apiMethod === "sendChatAction")
|
|
229
261
|
return isTargetChatScoped(input.args[1]);
|
|
262
|
+
if (apiMethod === "sendMessage" && isTelegramBusAggregateDelivery(input.args[1])) {
|
|
263
|
+
const body = input.args[1] as Record<string, unknown>;
|
|
264
|
+
return (
|
|
265
|
+
body.message_thread_id === undefined && isTargetChatScoped(body)
|
|
266
|
+
);
|
|
267
|
+
}
|
|
230
268
|
if (apiMethod === "deleteMessage" || apiMethod === "editMessageText") {
|
|
231
269
|
return isTargetMessageScoped(input.args[1]);
|
|
232
270
|
}
|