@llblab/pi-telegram 0.54.4 → 0.55.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 +4 -2
- package/BACKLOG.md +1 -1
- package/CHANGELOG.md +11 -0
- package/README.md +5 -3
- package/dist/lib/activity.d.ts +5 -1
- package/dist/lib/activity.js +31 -2
- package/dist/lib/bindings.d.ts +3 -1
- package/dist/lib/bindings.js +8 -2
- package/dist/lib/bus-api.d.ts +2 -2
- package/dist/lib/bus-api.js +7 -2
- package/dist/lib/bus-follower.d.ts +49 -3
- package/dist/lib/bus-follower.js +313 -146
- package/dist/lib/bus-leader.d.ts +3 -0
- package/dist/lib/bus-leader.js +99 -18
- package/dist/lib/bus.d.ts +5 -3
- package/dist/lib/bus.js +13 -10
- package/dist/lib/delivery.d.ts +4 -0
- package/dist/lib/delivery.js +48 -15
- package/dist/lib/extension.js +48 -6
- package/dist/lib/lifecycle.d.ts +68 -0
- package/dist/lib/lifecycle.js +178 -58
- package/dist/lib/machine.d.ts +23 -0
- package/dist/lib/machine.js +37 -0
- package/dist/lib/media.d.ts +114 -28
- package/dist/lib/media.js +292 -119
- package/dist/lib/model.d.ts +54 -15
- package/dist/lib/model.js +98 -53
- package/dist/lib/polling.js +2 -0
- package/dist/lib/preview.d.ts +128 -113
- package/dist/lib/preview.js +448 -366
- package/dist/lib/queue.d.ts +2 -2
- package/dist/lib/queue.js +3 -3
- package/dist/lib/routing.d.ts +6 -1
- package/dist/lib/routing.js +334 -210
- package/dist/lib/runtime.d.ts +77 -11
- package/dist/lib/runtime.js +174 -92
- package/dist/lib/sections.js +0 -1
- package/dist/lib/telegram-api.d.ts +11 -9
- package/dist/lib/telegram-api.js +53 -4
- package/dist/lib/text-groups.d.ts +0 -26
- package/dist/lib/text-groups.js +51 -98
- package/dist/lib/thread-display.js +14 -6
- package/dist/lib/threads.d.ts +18 -5
- package/dist/lib/threads.js +107 -30
- package/dist/lib/turns.d.ts +2 -0
- package/dist/lib/turns.js +6 -1
- package/dist/lib/updates.d.ts +11 -4
- package/dist/lib/updates.js +54 -19
- package/dist/package.json +1 -1
- package/docs/activity.md +1 -1
- package/docs/architecture.md +12 -11
- package/docs/delivery.md +7 -5
- package/docs/multi-instance-bus.md +18 -8
- package/docs/public-api.md +2 -2
- package/docs/ui-style.md +2 -2
- package/lib/activity.ts +29 -5
- package/lib/bindings.ts +9 -1
- package/lib/bus-api.ts +11 -3
- package/lib/bus-follower.ts +417 -203
- package/lib/bus-leader.ts +88 -14
- package/lib/bus.ts +17 -15
- package/lib/delivery.ts +47 -19
- package/lib/extension.ts +51 -9
- package/lib/lifecycle.ts +229 -55
- package/lib/machine.ts +60 -0
- package/lib/media.ts +438 -172
- package/lib/model.ts +169 -74
- package/lib/polling.ts +2 -0
- package/lib/preview.ts +715 -566
- package/lib/queue.ts +5 -5
- package/lib/routing.ts +325 -238
- package/lib/runtime.ts +260 -104
- package/lib/sections.ts +0 -2
- package/lib/telegram-api.ts +61 -8
- package/lib/text-groups.ts +75 -136
- package/lib/thread-display.ts +15 -4
- package/lib/threads.ts +120 -36
- package/lib/turns.ts +8 -1
- package/lib/updates.ts +58 -21
- package/package.json +1 -1
package/lib/model.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Owns model identity, thinking levels, scoped resolution, current-model state, and in-flight model switching
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import * as Machine from "./machine.ts";
|
|
7
8
|
import {
|
|
8
9
|
truncateTelegramQueueSummary,
|
|
9
10
|
type PendingTelegramTurn,
|
|
@@ -368,34 +369,11 @@ export function sortScopedModels<TModel extends MenuModel = MenuModel>(
|
|
|
368
369
|
|
|
369
370
|
// --- In-Flight Model Switching ---
|
|
370
371
|
|
|
371
|
-
export interface PendingModelSwitchStore<TSelection> {
|
|
372
|
-
get: () => TSelection | undefined;
|
|
373
|
-
set: (selection: TSelection | undefined) => void;
|
|
374
|
-
clear: () => void;
|
|
375
|
-
has: () => boolean;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
372
|
export interface TelegramInFlightModelSwitchState {
|
|
379
373
|
isIdle: boolean;
|
|
380
374
|
hasAbortHandler: boolean;
|
|
381
375
|
}
|
|
382
376
|
|
|
383
|
-
export function createPendingModelSwitchStore<
|
|
384
|
-
TSelection,
|
|
385
|
-
>(): PendingModelSwitchStore<TSelection> {
|
|
386
|
-
let selection: TSelection | undefined;
|
|
387
|
-
return {
|
|
388
|
-
get: () => selection,
|
|
389
|
-
set: (nextSelection) => {
|
|
390
|
-
selection = nextSelection;
|
|
391
|
-
},
|
|
392
|
-
clear: () => {
|
|
393
|
-
selection = undefined;
|
|
394
|
-
},
|
|
395
|
-
has: () => selection !== undefined,
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
|
|
399
377
|
export function canRestartAgentRunForTelegramModelSwitch(
|
|
400
378
|
state: TelegramInFlightModelSwitchState,
|
|
401
379
|
): boolean {
|
|
@@ -416,21 +394,6 @@ export function shouldTriggerPendingTelegramModelSwitchAbort(state: {
|
|
|
416
394
|
);
|
|
417
395
|
}
|
|
418
396
|
|
|
419
|
-
export function restartTelegramModelSwitchContinuation<
|
|
420
|
-
TTurn,
|
|
421
|
-
TSelection,
|
|
422
|
-
>(state: {
|
|
423
|
-
activeTurn: TTurn | undefined;
|
|
424
|
-
abort: (() => void) | undefined;
|
|
425
|
-
selection: TSelection;
|
|
426
|
-
queueContinuation: (turn: TTurn, selection: TSelection) => void;
|
|
427
|
-
}): boolean {
|
|
428
|
-
if (!state.activeTurn || !state.abort) return false;
|
|
429
|
-
state.queueContinuation(state.activeTurn, state.selection);
|
|
430
|
-
state.abort();
|
|
431
|
-
return true;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
397
|
export function buildTelegramModelSwitchContinuationText<
|
|
435
398
|
TModel extends MenuModel,
|
|
436
399
|
>(
|
|
@@ -554,8 +517,6 @@ export function createTelegramModelSwitchContinuationQueueRuntime<
|
|
|
554
517
|
|
|
555
518
|
export interface TelegramModelSwitchControllerDeps<TContext, TSelection> {
|
|
556
519
|
isIdle: (ctx: TContext) => boolean;
|
|
557
|
-
getPendingModelSwitch: () => TSelection | undefined;
|
|
558
|
-
setPendingModelSwitch: (selection: TSelection | undefined) => void;
|
|
559
520
|
getActiveTurn: () => PendingTelegramTurn | undefined;
|
|
560
521
|
getAbortHandler: () => (() => void) | undefined;
|
|
561
522
|
hasAbortHandler: () => boolean;
|
|
@@ -570,6 +531,8 @@ export interface TelegramModelSwitchControllerDeps<TContext, TSelection> {
|
|
|
570
531
|
|
|
571
532
|
export interface TelegramModelSwitchController<TContext, TSelection> {
|
|
572
533
|
canOfferInFlightSwitch: (ctx: TContext) => boolean;
|
|
534
|
+
/** A staged switch waits for its abort; queue dispatch and live-work observation treat it as pending control. */
|
|
535
|
+
hasPendingSwitch: () => boolean;
|
|
573
536
|
stagePendingSwitch: (
|
|
574
537
|
selection: TSelection,
|
|
575
538
|
ctx: TContext,
|
|
@@ -610,8 +573,6 @@ export function createTelegramModelSwitchControllerRuntime<
|
|
|
610
573
|
): TelegramModelSwitchController<TContext, TSelection> {
|
|
611
574
|
return createTelegramModelSwitchController({
|
|
612
575
|
isIdle: deps.isIdle,
|
|
613
|
-
getPendingModelSwitch: deps.getPendingModelSwitch,
|
|
614
|
-
setPendingModelSwitch: deps.setPendingModelSwitch,
|
|
615
576
|
getActiveTurn: deps.getActiveTurn,
|
|
616
577
|
getAbortHandler: deps.getAbortHandler,
|
|
617
578
|
hasAbortHandler: deps.hasAbortHandler,
|
|
@@ -626,31 +587,163 @@ export function createTelegramModelSwitchControllerRuntime<
|
|
|
626
587
|
});
|
|
627
588
|
}
|
|
628
589
|
|
|
590
|
+
/** The whole model-switch state; only `transitionTelegramModelSwitch` produces a new one. */
|
|
591
|
+
export interface TelegramModelSwitchMachineState<TSelection> {
|
|
592
|
+
/** One staged switch: the selection and the turn its continuation answers move and clear together. */
|
|
593
|
+
readonly pending: {
|
|
594
|
+
readonly selection: TSelection;
|
|
595
|
+
/** The active Telegram turn at staging, or the model menu's own target for a local run. */
|
|
596
|
+
readonly turn?: TelegramModelSwitchContinuationSource;
|
|
597
|
+
} | null;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/** Facts owned by other domains, sampled by the shell when the event is dispatched. */
|
|
601
|
+
interface TelegramModelSwitchRunFacts {
|
|
602
|
+
activeTurn?: TelegramModelSwitchContinuationSource;
|
|
603
|
+
hasAbortHandler: boolean;
|
|
604
|
+
activeToolExecutions: number;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
export type TelegramModelSwitchEvent<TSelection> =
|
|
608
|
+
| {
|
|
609
|
+
type: "staged";
|
|
610
|
+
selection: TSelection;
|
|
611
|
+
turn?: TelegramModelSwitchContinuationSource;
|
|
612
|
+
}
|
|
613
|
+
| ({ type: "abortRequested" } & TelegramModelSwitchRunFacts)
|
|
614
|
+
| {
|
|
615
|
+
type: "restartRequested";
|
|
616
|
+
selection: TSelection;
|
|
617
|
+
turn?: TelegramModelSwitchContinuationSource;
|
|
618
|
+
hasAbortHandler: boolean;
|
|
619
|
+
}
|
|
620
|
+
| { type: "cleared" };
|
|
621
|
+
|
|
622
|
+
export type TelegramModelSwitchEffect<TSelection> =
|
|
623
|
+
| {
|
|
624
|
+
type: "queueContinuation";
|
|
625
|
+
turn: TelegramModelSwitchContinuationSource;
|
|
626
|
+
selection: TSelection;
|
|
627
|
+
}
|
|
628
|
+
| { type: "abort" };
|
|
629
|
+
|
|
630
|
+
export interface TelegramModelSwitchStep<
|
|
631
|
+
TSelection,
|
|
632
|
+
> extends Machine.TelegramMachineStep<
|
|
633
|
+
TelegramModelSwitchMachineState<TSelection>,
|
|
634
|
+
TelegramModelSwitchEffect<TSelection>
|
|
635
|
+
> {
|
|
636
|
+
/** `abortRequested` / `restartRequested`: the run was stopped for a continuation. */
|
|
637
|
+
result: boolean;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
export function createTelegramModelSwitchMachineState<
|
|
641
|
+
TSelection,
|
|
642
|
+
>(): TelegramModelSwitchMachineState<TSelection> {
|
|
643
|
+
return { pending: null };
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/** The continuation is queued before the abort, so the stopped run always has its successor waiting. */
|
|
647
|
+
const restartFor = <TSelection>(
|
|
648
|
+
turn: TelegramModelSwitchContinuationSource,
|
|
649
|
+
selection: TSelection,
|
|
650
|
+
): TelegramModelSwitchStep<TSelection> => ({
|
|
651
|
+
state: { pending: null },
|
|
652
|
+
effects: [{ type: "queueContinuation", turn, selection }, { type: "abort" }],
|
|
653
|
+
result: true,
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Pure model-switch transition. A staged switch fires only once no tool runs and an abort handler exists; any restart
|
|
658
|
+
* or clear consumes the staged switch too, so a stale selection can never abort the continuation run it started.
|
|
659
|
+
*/
|
|
660
|
+
export function transitionTelegramModelSwitch<TSelection>(
|
|
661
|
+
state: TelegramModelSwitchMachineState<TSelection>,
|
|
662
|
+
event: TelegramModelSwitchEvent<TSelection>,
|
|
663
|
+
): TelegramModelSwitchStep<TSelection> {
|
|
664
|
+
const unchanged = { state, effects: [], result: false };
|
|
665
|
+
switch (event.type) {
|
|
666
|
+
case "staged":
|
|
667
|
+
return {
|
|
668
|
+
state: {
|
|
669
|
+
pending: {
|
|
670
|
+
selection: event.selection,
|
|
671
|
+
...(event.turn ? { turn: event.turn } : {}),
|
|
672
|
+
},
|
|
673
|
+
},
|
|
674
|
+
effects: [],
|
|
675
|
+
result: false,
|
|
676
|
+
};
|
|
677
|
+
case "abortRequested": {
|
|
678
|
+
const pending = state.pending;
|
|
679
|
+
const turn = pending?.turn ?? event.activeTurn;
|
|
680
|
+
if (
|
|
681
|
+
!pending ||
|
|
682
|
+
!turn ||
|
|
683
|
+
!shouldTriggerPendingTelegramModelSwitchAbort({
|
|
684
|
+
hasPendingModelSwitch: true,
|
|
685
|
+
hasContinuationTurn: true,
|
|
686
|
+
hasAbortHandler: event.hasAbortHandler,
|
|
687
|
+
activeToolExecutions: event.activeToolExecutions,
|
|
688
|
+
})
|
|
689
|
+
)
|
|
690
|
+
return unchanged;
|
|
691
|
+
return restartFor(turn, pending.selection);
|
|
692
|
+
}
|
|
693
|
+
case "restartRequested":
|
|
694
|
+
return event.turn && event.hasAbortHandler
|
|
695
|
+
? restartFor(event.turn, event.selection)
|
|
696
|
+
: unchanged;
|
|
697
|
+
case "cleared":
|
|
698
|
+
return { state: { pending: null }, effects: [], result: false };
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* The shell around `transitionTelegramModelSwitch`: it samples the active turn, abort handler and tool count into
|
|
704
|
+
* events, and runs the continuation and abort effects with the caller's context and the handler it sampled.
|
|
705
|
+
*/
|
|
629
706
|
export function createTelegramModelSwitchController<TContext, TSelection>(
|
|
630
707
|
deps: TelegramModelSwitchControllerDeps<TContext, TSelection>,
|
|
631
708
|
): TelegramModelSwitchController<TContext, TSelection> {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
const
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
709
|
+
// The context and abort handler of the call being dispatched; effects run synchronously inside that dispatch.
|
|
710
|
+
let call: { ctx: TContext; abort?: () => void } | undefined;
|
|
711
|
+
const machine = Machine.createTelegramMachineRunner<
|
|
712
|
+
TelegramModelSwitchMachineState<TSelection>,
|
|
713
|
+
TelegramModelSwitchEvent<TSelection>,
|
|
714
|
+
TelegramModelSwitchEffect<TSelection>,
|
|
715
|
+
TelegramModelSwitchStep<TSelection>
|
|
716
|
+
>({
|
|
717
|
+
initial: createTelegramModelSwitchMachineState<TSelection>(),
|
|
718
|
+
transition: transitionTelegramModelSwitch,
|
|
719
|
+
run(effect) {
|
|
720
|
+
if (!call) return;
|
|
721
|
+
if (effect.type === "queueContinuation")
|
|
722
|
+
deps.queueContinuation(effect.turn, effect.selection, call.ctx);
|
|
723
|
+
else call.abort?.();
|
|
724
|
+
},
|
|
725
|
+
});
|
|
726
|
+
const dispatchFor = (
|
|
727
|
+
ctx: TContext,
|
|
728
|
+
abort: (() => void) | undefined,
|
|
729
|
+
event: TelegramModelSwitchEvent<TSelection>,
|
|
730
|
+
): boolean => {
|
|
731
|
+
const preceding = call;
|
|
732
|
+
call = { ctx, abort };
|
|
733
|
+
try {
|
|
734
|
+
return machine.dispatch(event).result;
|
|
735
|
+
} finally {
|
|
736
|
+
call = preceding;
|
|
645
737
|
}
|
|
646
|
-
|
|
738
|
+
};
|
|
739
|
+
const triggerPendingAbort = (ctx: TContext): boolean => {
|
|
647
740
|
const abort = deps.getAbortHandler();
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
741
|
+
return dispatchFor(ctx, abort, {
|
|
742
|
+
type: "abortRequested",
|
|
743
|
+
activeTurn: deps.getActiveTurn(),
|
|
744
|
+
hasAbortHandler: deps.hasAbortHandler() && !!abort,
|
|
745
|
+
activeToolExecutions: deps.getActiveToolExecutions(),
|
|
746
|
+
});
|
|
654
747
|
};
|
|
655
748
|
return {
|
|
656
749
|
canOfferInFlightSwitch: (ctx) =>
|
|
@@ -658,9 +751,14 @@ export function createTelegramModelSwitchController<TContext, TSelection>(
|
|
|
658
751
|
isIdle: deps.isIdle(ctx),
|
|
659
752
|
hasAbortHandler: deps.hasAbortHandler(),
|
|
660
753
|
}),
|
|
754
|
+
hasPendingSwitch: () => machine.state.pending !== null,
|
|
661
755
|
stagePendingSwitch: (selection, ctx, continuationTurn) => {
|
|
662
|
-
|
|
663
|
-
|
|
756
|
+
const turn = deps.getActiveTurn() ?? continuationTurn;
|
|
757
|
+
machine.dispatch({
|
|
758
|
+
type: "staged",
|
|
759
|
+
selection,
|
|
760
|
+
...(turn ? { turn } : {}),
|
|
761
|
+
});
|
|
664
762
|
try {
|
|
665
763
|
deps.updateStatus(ctx);
|
|
666
764
|
} finally {
|
|
@@ -668,22 +766,19 @@ export function createTelegramModelSwitchController<TContext, TSelection>(
|
|
|
668
766
|
}
|
|
669
767
|
},
|
|
670
768
|
clearPendingSwitch: () => {
|
|
671
|
-
|
|
672
|
-
deps.setPendingModelSwitch(undefined);
|
|
769
|
+
machine.dispatch({ type: "cleared" });
|
|
673
770
|
},
|
|
674
771
|
queueContinuation: deps.queueContinuation,
|
|
675
772
|
triggerPendingAbort,
|
|
676
773
|
restartInterruptedTurn: (selection, ctx, continuationTurn) => {
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
774
|
+
const abort = deps.getAbortHandler();
|
|
775
|
+
const turn = deps.getActiveTurn() ?? continuationTurn;
|
|
776
|
+
return dispatchFor(ctx, abort, {
|
|
777
|
+
type: "restartRequested",
|
|
680
778
|
selection,
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
},
|
|
779
|
+
...(turn ? { turn } : {}),
|
|
780
|
+
hasAbortHandler: !!abort,
|
|
684
781
|
});
|
|
685
|
-
if (restarted) pendingContinuationTurn = undefined;
|
|
686
|
-
return restarted;
|
|
687
782
|
},
|
|
688
783
|
};
|
|
689
784
|
}
|
package/lib/polling.ts
CHANGED
|
@@ -1366,6 +1366,8 @@ export function createTelegramThreadCapabilityMonitor<TContext>(
|
|
|
1366
1366
|
return {
|
|
1367
1367
|
start(ctx) {
|
|
1368
1368
|
stop();
|
|
1369
|
+
// Disabled-mode confirmation counts consecutive probes of one run, never observations from before a restart.
|
|
1370
|
+
consecutiveDisabledProbes = 0;
|
|
1369
1371
|
const expectedGeneration = generation;
|
|
1370
1372
|
interval = setInterval(() => {
|
|
1371
1373
|
if (generation !== expectedGeneration) return;
|