@llblab/pi-kit 0.5.0 → 0.5.2
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/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/node_modules/@llblab/pi-telegram/BACKLOG.md +1 -0
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +21 -0
- package/node_modules/@llblab/pi-telegram/README.md +2 -0
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +6 -4
- package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +5 -1
- package/node_modules/@llblab/pi-telegram/docs/outbound.md +19 -3
- package/node_modules/@llblab/pi-telegram/index.ts +10 -0
- package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +43 -25
- package/node_modules/@llblab/pi-telegram/lib/activity.ts +60 -1
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +101 -90
- package/node_modules/@llblab/pi-telegram/lib/lifecycle.ts +7 -2
- package/node_modules/@llblab/pi-telegram/lib/locks.ts +99 -16
- package/node_modules/@llblab/pi-telegram/lib/outbound-attachments.ts +18 -7
- package/node_modules/@llblab/pi-telegram/lib/outbound-voice.ts +11 -0
- package/node_modules/@llblab/pi-telegram/lib/outbound.ts +10 -3
- package/node_modules/@llblab/pi-telegram/lib/polling.ts +142 -30
- package/node_modules/@llblab/pi-telegram/lib/preview.ts +19 -3
- package/node_modules/@llblab/pi-telegram/lib/prompts.ts +8 -6
- package/node_modules/@llblab/pi-telegram/lib/queue.ts +101 -66
- package/node_modules/@llblab/pi-telegram/lib/routing.ts +192 -58
- package/node_modules/@llblab/pi-telegram/lib/status.ts +4 -0
- package/node_modules/@llblab/pi-telegram/lib/updates.ts +33 -35
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/references/diagnosis.md +2 -0
- package/package.json +2 -2
|
@@ -291,6 +291,7 @@ export interface TelegramStatusBarTheme {
|
|
|
291
291
|
export interface TelegramStatusBarState {
|
|
292
292
|
hasBotToken: boolean;
|
|
293
293
|
pollingActive: boolean;
|
|
294
|
+
pollingStopReason?: string;
|
|
294
295
|
paired: boolean;
|
|
295
296
|
busRole?: TelegramBridgeBusRole;
|
|
296
297
|
busLifecyclePhase?: TelegramBridgeBusLifecyclePhase;
|
|
@@ -699,6 +700,7 @@ export function createTelegramBridgeStatusRuntime<
|
|
|
699
700
|
queuedItems: queuedItemCount,
|
|
700
701
|
}),
|
|
701
702
|
queuedStatus: deps.formatQueuedStatus(queuedItems),
|
|
703
|
+
pollingStopReason: deps.getPollingState?.().stopReason,
|
|
702
704
|
error,
|
|
703
705
|
};
|
|
704
706
|
},
|
|
@@ -889,6 +891,8 @@ export function buildTelegramStatusBarText(
|
|
|
889
891
|
: "";
|
|
890
892
|
if (!state.hasBotToken)
|
|
891
893
|
return `${label} ${theme.fg("muted", "not configured")}${queued}`;
|
|
894
|
+
if (state.pollingStopReason === "persistent-conflict" && state.busRole !== "follower")
|
|
895
|
+
return `${label} ${theme.fg("error", "error")}`;
|
|
892
896
|
if (!state.paired)
|
|
893
897
|
return `${label} ${theme.fg("warning", "awaiting pairing")}${queued}`;
|
|
894
898
|
if (state.busLifecyclePhase === "electing")
|
|
@@ -481,12 +481,7 @@ const TELEGRAM_UPDATE_ADMISSION_BINDING = Symbol(
|
|
|
481
481
|
|
|
482
482
|
interface TelegramUpdateAdmissionBinding {
|
|
483
483
|
sourceUpdateId: number;
|
|
484
|
-
report: (
|
|
485
|
-
outcome: Extract<
|
|
486
|
-
TelegramUpdateAdmissionOutcome,
|
|
487
|
-
{ kind: "deferred" | "queued" }
|
|
488
|
-
>,
|
|
489
|
-
) => void;
|
|
484
|
+
report: (outcome: TelegramUpdateAdmissionOutcome) => void;
|
|
490
485
|
}
|
|
491
486
|
|
|
492
487
|
export type TelegramQueueAdmissionReceiptLike = TelegramQueueAdmissionReceipt;
|
|
@@ -589,6 +584,16 @@ export function collectTelegramAdmissionSourceUpdateIds(
|
|
|
589
584
|
return [...sourceUpdateIds].sort((left, right) => left - right);
|
|
590
585
|
}
|
|
591
586
|
|
|
587
|
+
/** Report source completion; true means reported, not a durable settlement acknowledgement. */
|
|
588
|
+
export function reportTelegramUpdateCompleted(value: unknown): boolean {
|
|
589
|
+
const binding = getTelegramUpdateAdmissionBinding(value);
|
|
590
|
+
if (!binding) return false;
|
|
591
|
+
const execution = getTelegramUpdateExecutionFence(value);
|
|
592
|
+
if (execution && !execution.isCurrent()) return false;
|
|
593
|
+
binding.report({ kind: "complete" });
|
|
594
|
+
return true;
|
|
595
|
+
}
|
|
596
|
+
|
|
592
597
|
export function reportTelegramUpdateDeferred(value: unknown): boolean {
|
|
593
598
|
const binding = getTelegramUpdateAdmissionBinding(value);
|
|
594
599
|
if (!binding) return false;
|
|
@@ -1810,10 +1815,7 @@ export interface TelegramUpdateWorkerRuntime<TContext> {
|
|
|
1810
1815
|
signal: () => void;
|
|
1811
1816
|
settleDeferred: (input: {
|
|
1812
1817
|
updateId: number;
|
|
1813
|
-
outcome:
|
|
1814
|
-
TelegramUpdateAdmissionOutcome,
|
|
1815
|
-
{ kind: "deferred" | "queued" }
|
|
1816
|
-
>;
|
|
1818
|
+
outcome: TelegramUpdateAdmissionOutcome;
|
|
1817
1819
|
signal: AbortSignal;
|
|
1818
1820
|
}) => void;
|
|
1819
1821
|
isQueueReceiptCommitted: (
|
|
@@ -2160,6 +2162,7 @@ export function createTelegramUpdateWorkerRuntime<TContext>(
|
|
|
2160
2162
|
failurePhase: string,
|
|
2161
2163
|
error: unknown,
|
|
2162
2164
|
currentUpdateId?: number,
|
|
2165
|
+
extraDetails?: Record<string, unknown>,
|
|
2163
2166
|
): "blocked" => {
|
|
2164
2167
|
blocked = true;
|
|
2165
2168
|
state.lastFailureAtMs = getNowMs();
|
|
@@ -2168,6 +2171,7 @@ export function createTelegramUpdateWorkerRuntime<TContext>(
|
|
|
2168
2171
|
phase: failurePhase,
|
|
2169
2172
|
generation: owner?.generation,
|
|
2170
2173
|
...(currentUpdateId !== undefined ? { updateId: currentUpdateId } : {}),
|
|
2174
|
+
...extraDetails,
|
|
2171
2175
|
});
|
|
2172
2176
|
transition("blocked", currentUpdateId, blockedReason);
|
|
2173
2177
|
return "blocked";
|
|
@@ -2553,6 +2557,10 @@ export function createTelegramUpdateWorkerRuntime<TContext>(
|
|
|
2553
2557
|
`Telegram queue receipt ${normalized.receiptId} conflicts with committed authority.`,
|
|
2554
2558
|
),
|
|
2555
2559
|
currentUpdateId,
|
|
2560
|
+
{
|
|
2561
|
+
receiptId: normalized.receiptId,
|
|
2562
|
+
sourceUpdateIds: normalized.sourceUpdateIds,
|
|
2563
|
+
},
|
|
2556
2564
|
);
|
|
2557
2565
|
}
|
|
2558
2566
|
return "duplicate";
|
|
@@ -3012,6 +3020,13 @@ export function createTelegramUpdateWorkerRuntime<TContext>(
|
|
|
3012
3020
|
return;
|
|
3013
3021
|
}
|
|
3014
3022
|
const claim = claims.get(input.updateId);
|
|
3023
|
+
if (input.outcome.kind === "complete") {
|
|
3024
|
+
// Expiry may retire only a still-deferred source, never accepted queue work.
|
|
3025
|
+
if (claim !== "deferred") return;
|
|
3026
|
+
const result = commitCompletedBatch(expectedOwner, [input.updateId]);
|
|
3027
|
+
if (!result) transition("idle", input.updateId);
|
|
3028
|
+
return;
|
|
3029
|
+
}
|
|
3015
3030
|
if (input.outcome.kind === "deferred") {
|
|
3016
3031
|
if (claim === "queued") return;
|
|
3017
3032
|
if (claim !== "deferred") {
|
|
@@ -3447,10 +3462,7 @@ export interface TelegramUpdateAdmissionHandleDeps<
|
|
|
3447
3462
|
) => Promise<void>;
|
|
3448
3463
|
registry?: TelegramUpdateHandlerRegistry;
|
|
3449
3464
|
onLateOutcome?: (
|
|
3450
|
-
outcome:
|
|
3451
|
-
TelegramUpdateAdmissionOutcome,
|
|
3452
|
-
{ kind: "deferred" | "queued" }
|
|
3453
|
-
>,
|
|
3465
|
+
outcome: TelegramUpdateAdmissionOutcome,
|
|
3454
3466
|
details: {
|
|
3455
3467
|
updateId: number;
|
|
3456
3468
|
ctx: TContext;
|
|
@@ -3461,24 +3473,15 @@ export interface TelegramUpdateAdmissionHandleDeps<
|
|
|
3461
3473
|
}
|
|
3462
3474
|
|
|
3463
3475
|
function mergeTelegramReportedAdmissionOutcome(
|
|
3464
|
-
current:
|
|
3465
|
-
|
|
3466
|
-
TelegramUpdateAdmissionOutcome,
|
|
3467
|
-
{ kind: "deferred" | "queued" }
|
|
3468
|
-
>
|
|
3469
|
-
| undefined,
|
|
3470
|
-
next: Extract<
|
|
3471
|
-
TelegramUpdateAdmissionOutcome,
|
|
3472
|
-
{ kind: "deferred" | "queued" }
|
|
3473
|
-
>,
|
|
3476
|
+
current: TelegramUpdateAdmissionOutcome | undefined,
|
|
3477
|
+
next: TelegramUpdateAdmissionOutcome,
|
|
3474
3478
|
updateId: number,
|
|
3475
|
-
):
|
|
3476
|
-
TelegramUpdateAdmissionOutcome,
|
|
3477
|
-
{ kind: "deferred" | "queued" }
|
|
3478
|
-
> {
|
|
3479
|
+
): TelegramUpdateAdmissionOutcome {
|
|
3479
3480
|
if (!current || current.kind === "deferred") return next;
|
|
3480
3481
|
if (next.kind === "deferred") return current;
|
|
3481
|
-
if (
|
|
3482
|
+
if (current.kind === "complete" && next.kind === "complete") return current;
|
|
3483
|
+
if (current.kind === "queued" && next.kind === "queued" &&
|
|
3484
|
+
areTelegramQueueAdmissionReceiptsEqual(current, next)) return current;
|
|
3482
3485
|
throw new TelegramUpdateAdmissionOutcomeError(
|
|
3483
3486
|
`Telegram update ${updateId} reported conflicting queue outcomes.`,
|
|
3484
3487
|
);
|
|
@@ -3523,12 +3526,7 @@ export function createTelegramUpdateAdmissionHandle<
|
|
|
3523
3526
|
execution.assertCurrent();
|
|
3524
3527
|
if (verdict === "consume") return { kind: "complete" };
|
|
3525
3528
|
let immediate = true;
|
|
3526
|
-
let outcome:
|
|
3527
|
-
| Extract<
|
|
3528
|
-
TelegramUpdateAdmissionOutcome,
|
|
3529
|
-
{ kind: "deferred" | "queued" }
|
|
3530
|
-
>
|
|
3531
|
-
| undefined;
|
|
3529
|
+
let outcome: TelegramUpdateAdmissionOutcome | undefined;
|
|
3532
3530
|
const boundUpdate = bindTelegramUpdateExecutionFence(
|
|
3533
3531
|
bindTelegramUpdateAdmissionSource(update, (next) => {
|
|
3534
3532
|
if (immediate) {
|
|
@@ -13,4 +13,6 @@ These slash commands are registered Pi commands, not shell executables or agent
|
|
|
13
13
|
|
|
14
14
|
When `PI_CODING_AGENT_DIR` selects another compatible runtime, resolve its equivalent `tmp/telegram` directory.
|
|
15
15
|
|
|
16
|
+
A `persistent-conflict` polling stop means the bounded competing-`getUpdates` threshold triggered full transport stand-down, not cancellation of accepted local Pi work. The terminal diagnostic distinguishes lost local ownership from a competing client despite an apparently owned lock. Check other profiles, agent directories, installations, or non-Pi clients sharing the bot; after removing the competition, reconnect through the supported Pi command. Do not restart repeatedly or alter lock files to compete for the stream.
|
|
17
|
+
|
|
16
18
|
Do not mutate ownership files, bridge state, journals, bindings, or locks to force recovery. Use supported commands and preserve exact profile, target, transport, and session authority. Never claim successful delivery without transport evidence.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-kit",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@llblab/pi-codex-usage": "0.9.4",
|
|
46
46
|
"@llblab/pi-grow-loop": "0.7.4",
|
|
47
47
|
"@llblab/pi-state-flow": "0.3.0",
|
|
48
|
-
"@llblab/pi-telegram": "0.43.
|
|
48
|
+
"@llblab/pi-telegram": "0.43.2",
|
|
49
49
|
"@llblab/skills": "1.14.0"
|
|
50
50
|
},
|
|
51
51
|
"bundledDependencies": [
|