@llblab/pi-telegram 0.23.0 → 0.23.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/AGENTS.md +19 -12
- package/BACKLOG.md +1 -1
- package/CHANGELOG.md +42 -59
- package/README.md +3 -3
- package/docs/architecture.md +7 -8
- package/docs/multi-instance-bus.md +1 -1
- package/docs/outbound.md +1 -1
- package/docs/public-api.md +2 -2
- package/docs/ui-style.md +1 -1
- package/docs/voice.md +8 -9
- package/index.ts +8 -7
- package/lib/bindings.ts +15 -16
- package/lib/bus-leader.ts +11 -128
- package/lib/config.ts +32 -14
- package/lib/menu-settings.ts +37 -97
- package/lib/prompts.ts +4 -2
- package/lib/queue.ts +52 -8
- package/lib/routing.ts +10 -16
- package/lib/status.ts +1 -1
- package/lib/text-groups.ts +29 -15
- package/lib/thread-reconciler.ts +3 -71
- package/lib/threads.ts +0 -43
- package/lib/turns.ts +25 -21
- package/lib/voice.ts +6 -7
- package/package.json +3 -2
package/lib/thread-reconciler.ts
CHANGED
|
@@ -62,11 +62,6 @@ export interface TelegramReservedThreadMessageObservation {
|
|
|
62
62
|
leaderEpoch?: number | string;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
export interface ThreadReservationProbeResult {
|
|
66
|
-
target: ThreadTarget;
|
|
67
|
-
stale: boolean;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
65
|
export interface ReplacedInstanceBindingInput {
|
|
71
66
|
instanceId: string;
|
|
72
67
|
replacementTarget: ThreadTarget;
|
|
@@ -111,14 +106,6 @@ export type ThreadReconciliationAction =
|
|
|
111
106
|
instanceId?: string;
|
|
112
107
|
leaderEpoch?: number | string;
|
|
113
108
|
}
|
|
114
|
-
| {
|
|
115
|
-
kind: "close-delete-pruned-follower-topic";
|
|
116
|
-
target: TelegramTarget & { threadId: number };
|
|
117
|
-
reason: "pruned-follower";
|
|
118
|
-
instanceId?: string;
|
|
119
|
-
messageId?: number;
|
|
120
|
-
leaderEpoch?: number | string;
|
|
121
|
-
}
|
|
122
109
|
| {
|
|
123
110
|
kind: "close-delete-replaced-follower-topic";
|
|
124
111
|
target: TelegramTarget & { threadId: number };
|
|
@@ -150,11 +137,6 @@ export type ThreadReconciliationAction =
|
|
|
150
137
|
pendingProvisionId: string;
|
|
151
138
|
instanceId?: string;
|
|
152
139
|
leaderEpoch?: number | string;
|
|
153
|
-
}
|
|
154
|
-
| {
|
|
155
|
-
kind: "remove-reservation";
|
|
156
|
-
target: TelegramTarget & { threadId: number };
|
|
157
|
-
reason: "reservation-probe-stale";
|
|
158
140
|
};
|
|
159
141
|
|
|
160
142
|
export type ThreadReconciliationPhase =
|
|
@@ -203,7 +185,6 @@ export interface ThreadReconciliationApplyPorts {
|
|
|
203
185
|
lastSyncError?: string,
|
|
204
186
|
) => boolean;
|
|
205
187
|
persist?: () => Promise<void>;
|
|
206
|
-
removeReservationByTarget?: (target: ThreadTarget) => boolean;
|
|
207
188
|
removePendingProvisionById?: (id: string) => boolean;
|
|
208
189
|
getCurrentLeaderEpoch?: () => number | string | undefined;
|
|
209
190
|
recordRuntimeEvent?: (
|
|
@@ -223,8 +204,6 @@ export interface ThreadReconciliationInput {
|
|
|
223
204
|
unboundMessages?: readonly TelegramUnboundThreadMessageObservation[];
|
|
224
205
|
reservedMessages?: readonly TelegramReservedThreadMessageObservation[];
|
|
225
206
|
proactiveReservationCleanup?: boolean;
|
|
226
|
-
reservationProbeResults?: readonly ThreadReservationProbeResult[];
|
|
227
|
-
prunedFollowerInstanceIds?: readonly string[];
|
|
228
207
|
replacedBindings?: readonly ReplacedInstanceBindingInput[];
|
|
229
208
|
previousLeaderCleanup?: PreviousLeaderCleanupInput;
|
|
230
209
|
previousState?: ThreadReconciliationMachineState;
|
|
@@ -309,7 +288,6 @@ function isCleanupAction(action: ThreadReconciliationAction): boolean {
|
|
|
309
288
|
action.kind === "close-delete-unbound-topic" ||
|
|
310
289
|
action.kind === "close-delete-reserved-topic" ||
|
|
311
290
|
action.kind === "close-stale-replaced-topic" ||
|
|
312
|
-
action.kind === "close-delete-pruned-follower-topic" ||
|
|
313
291
|
action.kind === "close-delete-replaced-follower-topic" ||
|
|
314
292
|
action.kind === "close-delete-previous-leader-topic" ||
|
|
315
293
|
action.kind === "close-delete-disconnected-instance-topic" ||
|
|
@@ -318,11 +296,7 @@ function isCleanupAction(action: ThreadReconciliationAction): boolean {
|
|
|
318
296
|
}
|
|
319
297
|
|
|
320
298
|
function isSyncAction(action: ThreadReconciliationAction): boolean {
|
|
321
|
-
return
|
|
322
|
-
action.kind === "mark-topic-active" ||
|
|
323
|
-
action.kind === "mark-topic-stale" ||
|
|
324
|
-
action.kind === "remove-reservation"
|
|
325
|
-
);
|
|
299
|
+
return action.kind === "mark-topic-active" || action.kind === "mark-topic-stale";
|
|
326
300
|
}
|
|
327
301
|
|
|
328
302
|
function createThreadReconciliationMachineState(
|
|
@@ -520,11 +494,6 @@ export async function applyThreadReconciliationPlan(
|
|
|
520
494
|
const persistFences: ThreadReconciliationAction[] = [];
|
|
521
495
|
const incompleteActions: ThreadReconciliationAction[] = [];
|
|
522
496
|
for (const action of plan.actions) {
|
|
523
|
-
if (action.kind === "remove-reservation") {
|
|
524
|
-
shouldPersist =
|
|
525
|
-
ports.removeReservationByTarget?.(action.target) || shouldPersist;
|
|
526
|
-
continue;
|
|
527
|
-
}
|
|
528
497
|
if (action.kind === "mark-topic-active") {
|
|
529
498
|
shouldPersist =
|
|
530
499
|
ports.markActiveByTarget?.(action.target) || shouldPersist;
|
|
@@ -586,7 +555,6 @@ export async function applyThreadReconciliationPlan(
|
|
|
586
555
|
if (
|
|
587
556
|
action.kind === "close-delete-unbound-topic" ||
|
|
588
557
|
action.kind === "close-delete-reserved-topic" ||
|
|
589
|
-
action.kind === "close-delete-pruned-follower-topic" ||
|
|
590
558
|
action.kind === "close-delete-replaced-follower-topic" ||
|
|
591
559
|
action.kind === "close-delete-previous-leader-topic" ||
|
|
592
560
|
action.kind === "close-delete-disconnected-instance-topic" ||
|
|
@@ -658,7 +626,6 @@ export async function applyThreadReconciliationPlan(
|
|
|
658
626
|
if (shouldSkipForStaleLeaderEpoch(action, ports)) continue;
|
|
659
627
|
if (
|
|
660
628
|
action.kind !== "close-delete-previous-leader-topic" &&
|
|
661
|
-
action.kind !== "close-delete-pruned-follower-topic" &&
|
|
662
629
|
action.kind !== "close-delete-replaced-follower-topic" &&
|
|
663
630
|
action.kind !== "close-delete-disconnected-instance-topic" &&
|
|
664
631
|
action.kind !== "close-delete-expired-pending-provision-topic"
|
|
@@ -674,9 +641,7 @@ export async function applyThreadReconciliationPlan(
|
|
|
674
641
|
? "Unbound Telegram topic deleted"
|
|
675
642
|
: action.kind === "close-delete-reserved-topic"
|
|
676
643
|
? "Reserved Telegram topic deleted"
|
|
677
|
-
: action.kind === "close-delete-
|
|
678
|
-
? "Pruned follower Telegram topic deleted"
|
|
679
|
-
: action.kind === "close-delete-replaced-follower-topic"
|
|
644
|
+
: action.kind === "close-delete-replaced-follower-topic"
|
|
680
645
|
? "Replaced follower Telegram topic deleted"
|
|
681
646
|
: action.kind === "close-delete-previous-leader-topic"
|
|
682
647
|
? "Previous leader Telegram topic deleted"
|
|
@@ -689,9 +654,7 @@ export async function applyThreadReconciliationPlan(
|
|
|
689
654
|
? "thread-reconciler-unbound-topic-delete"
|
|
690
655
|
: action.kind === "close-delete-reserved-topic"
|
|
691
656
|
? "thread-reconciler-reserved-topic-delete"
|
|
692
|
-
: action.kind === "close-delete-
|
|
693
|
-
? "thread-reconciler-pruned-follower-topic-delete"
|
|
694
|
-
: action.kind === "close-delete-replaced-follower-topic"
|
|
657
|
+
: action.kind === "close-delete-replaced-follower-topic"
|
|
695
658
|
? "thread-reconciler-replaced-follower-topic-delete"
|
|
696
659
|
: action.kind === "close-delete-previous-leader-topic"
|
|
697
660
|
? "thread-reconciler-previous-leader-topic-delete"
|
|
@@ -746,11 +709,6 @@ export function planThreadReconciliation(
|
|
|
746
709
|
.filter(isCurrentRecord)
|
|
747
710
|
.map((record) => targetKey(record.target)),
|
|
748
711
|
);
|
|
749
|
-
const allReservationTargets = new Set(
|
|
750
|
-
(input.reservations ?? []).map((reservation) =>
|
|
751
|
-
targetKey(reservation.target),
|
|
752
|
-
),
|
|
753
|
-
);
|
|
754
712
|
const reservedTargets = new Set(
|
|
755
713
|
(input.reservations ?? [])
|
|
756
714
|
.filter((reservation) => isReservationAlive(reservation, input.nowMs))
|
|
@@ -826,22 +784,6 @@ export function planThreadReconciliation(
|
|
|
826
784
|
}
|
|
827
785
|
}
|
|
828
786
|
|
|
829
|
-
for (const prunedInstanceId of input.prunedFollowerInstanceIds ?? []) {
|
|
830
|
-
for (const record of input.records) {
|
|
831
|
-
if (record.instanceId !== prunedInstanceId) continue;
|
|
832
|
-
if (!isActiveOrStartingRecord(record)) continue;
|
|
833
|
-
actions.push({
|
|
834
|
-
kind: "close-delete-pruned-follower-topic",
|
|
835
|
-
target: record.target,
|
|
836
|
-
reason: "pruned-follower",
|
|
837
|
-
instanceId: prunedInstanceId,
|
|
838
|
-
...(input.currentLeaderEpoch !== undefined
|
|
839
|
-
? { leaderEpoch: input.currentLeaderEpoch }
|
|
840
|
-
: {}),
|
|
841
|
-
});
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
|
|
845
787
|
for (const replacement of input.replacedBindings ?? []) {
|
|
846
788
|
for (const record of input.records) {
|
|
847
789
|
if (record.instanceId !== replacement.instanceId) continue;
|
|
@@ -900,16 +842,6 @@ export function planThreadReconciliation(
|
|
|
900
842
|
}
|
|
901
843
|
}
|
|
902
844
|
|
|
903
|
-
for (const probe of input.reservationProbeResults ?? []) {
|
|
904
|
-
if (!probe.stale) continue;
|
|
905
|
-
if (!allReservationTargets.has(targetKey(probe.target))) continue;
|
|
906
|
-
actions.push({
|
|
907
|
-
kind: "remove-reservation",
|
|
908
|
-
target: probe.target,
|
|
909
|
-
reason: "reservation-probe-stale",
|
|
910
|
-
});
|
|
911
|
-
}
|
|
912
|
-
|
|
913
845
|
for (const message of input.reservedMessages ?? []) {
|
|
914
846
|
const key = targetKey(message.target);
|
|
915
847
|
if (!reservedTargets.has(key)) continue;
|
package/lib/threads.ts
CHANGED
|
@@ -237,7 +237,6 @@ export interface TelegramTopicTargetStore {
|
|
|
237
237
|
target: TelegramTarget & { threadId: number },
|
|
238
238
|
) => Promise<boolean>;
|
|
239
239
|
removePendingProvision: (id: string) => boolean;
|
|
240
|
-
removeReservationByTarget: (target: TelegramTarget) => boolean;
|
|
241
240
|
getBotState: () => TelegramBotStateSnapshot;
|
|
242
241
|
setBotState: (state: Partial<TelegramBotStateSnapshot>) => void;
|
|
243
242
|
setStatusSnapshot: (snapshot: {
|
|
@@ -1396,15 +1395,6 @@ export function createTelegramTopicTargetStore(
|
|
|
1396
1395
|
if (changed) markDirty();
|
|
1397
1396
|
return changed;
|
|
1398
1397
|
},
|
|
1399
|
-
removeReservationByTarget(target) {
|
|
1400
|
-
const before = reservations.length;
|
|
1401
|
-
reservations = reservations.filter(
|
|
1402
|
-
(reservation) => !targetMatches(reservation.target, target),
|
|
1403
|
-
);
|
|
1404
|
-
const changed = reservations.length !== before;
|
|
1405
|
-
if (changed) markDirty();
|
|
1406
|
-
return changed;
|
|
1407
|
-
},
|
|
1408
1398
|
getBotState() {
|
|
1409
1399
|
return Object.fromEntries(
|
|
1410
1400
|
Object.entries(botState).filter(([, value]) => value !== undefined),
|
|
@@ -1983,9 +1973,6 @@ export async function provisionOwnBusTopic(
|
|
|
1983
1973
|
syncStatus?: "closed" | "deleted",
|
|
1984
1974
|
lastSyncError?: string,
|
|
1985
1975
|
) => deps.store.markStaleByTarget(target, syncStatus, lastSyncError),
|
|
1986
|
-
removeReservationByTarget: (
|
|
1987
|
-
target: TelegramTarget & { threadId: number },
|
|
1988
|
-
) => deps.store.removeReservationByTarget(target),
|
|
1989
1976
|
removePendingProvisionById: (id: string) =>
|
|
1990
1977
|
deps.store.removePendingProvision(id),
|
|
1991
1978
|
persist: () => deps.store.persist(),
|
|
@@ -2024,36 +2011,6 @@ export async function provisionOwnBusTopic(
|
|
|
2024
2011
|
durationMs: Date.now() - reservationCleanupApplyStartedAtMs,
|
|
2025
2012
|
actions: reservationCleanupPlan.actions.length,
|
|
2026
2013
|
});
|
|
2027
|
-
const reservationProbeResults: ThreadReconciler.ThreadReservationProbeResult[] =
|
|
2028
|
-
[];
|
|
2029
|
-
deps.recordEvent("bus", "Bus leader reservation probes skipped", {
|
|
2030
|
-
phase: "leader-topic-reservation-probe-skipped",
|
|
2031
|
-
reservations: reservationsBeforeCleanup.length,
|
|
2032
|
-
});
|
|
2033
|
-
const reservationProbePlan = ThreadReconciler.planThreadReconciliation({
|
|
2034
|
-
nowMs: Date.now(),
|
|
2035
|
-
currentLeaderEpoch: deps.getCurrentLeaderEpoch?.(),
|
|
2036
|
-
previousState: deps.getThreadReconciliationMachineState?.(),
|
|
2037
|
-
records: deps.store.list(),
|
|
2038
|
-
reservations: deps.store.listReservations(),
|
|
2039
|
-
pendingProvisions: deps.store.listPendingProvisions(),
|
|
2040
|
-
reservationProbeResults,
|
|
2041
|
-
});
|
|
2042
|
-
deps.recordThreadReconciliationPlan?.(reservationProbePlan);
|
|
2043
|
-
const reservationProbeApplyStartedAtMs = Date.now();
|
|
2044
|
-
await ThreadReconciler.applyThreadReconciliationPlan(
|
|
2045
|
-
reservationProbePlan,
|
|
2046
|
-
reservationCleanupPorts,
|
|
2047
|
-
);
|
|
2048
|
-
deps.recordEvent(
|
|
2049
|
-
"bus",
|
|
2050
|
-
"Bus leader reservation probe reconciliation applied",
|
|
2051
|
-
{
|
|
2052
|
-
phase: "leader-topic-reservation-probe-apply-duration",
|
|
2053
|
-
durationMs: Date.now() - reservationProbeApplyStartedAtMs,
|
|
2054
|
-
actions: reservationProbePlan.actions.length,
|
|
2055
|
-
},
|
|
2056
|
-
);
|
|
2057
2014
|
const nowMs = Date.now();
|
|
2058
2015
|
const currentLeaderOwner: TelegramThreadOwner = {
|
|
2059
2016
|
kind: "leader",
|
package/lib/turns.ts
CHANGED
|
@@ -13,9 +13,9 @@ import {
|
|
|
13
13
|
collectTelegramMessageIds,
|
|
14
14
|
downloadTelegramMessageFiles,
|
|
15
15
|
extractTelegramForwardContextText,
|
|
16
|
-
extractTelegramMessageText,
|
|
17
16
|
extractTelegramMessagesPromptText,
|
|
18
17
|
extractTelegramMessagesText,
|
|
18
|
+
extractTelegramMessageText,
|
|
19
19
|
formatTelegramHistoryText,
|
|
20
20
|
guessMediaType,
|
|
21
21
|
type DownloadedTelegramMessageFile,
|
|
@@ -59,14 +59,19 @@ export interface TelegramTurnMessage {
|
|
|
59
59
|
|
|
60
60
|
export type DownloadedTelegramTurnFile = DownloadedTelegramMessageFile;
|
|
61
61
|
|
|
62
|
-
function getTelegramTurnTarget(
|
|
62
|
+
function getTelegramTurnTarget(
|
|
63
|
+
message: TelegramTurnMessage,
|
|
64
|
+
): TelegramTurnTarget {
|
|
63
65
|
return Number.isInteger(message.message_thread_id)
|
|
64
66
|
? { chatId: message.chat.id, threadId: message.message_thread_id }
|
|
65
67
|
: { chatId: message.chat.id };
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
function formatTelegramPrefixAttributeValue(value: string): string {
|
|
69
|
-
return value
|
|
71
|
+
return value
|
|
72
|
+
.replace(/[\]\n\r|]+/g, " ")
|
|
73
|
+
.replace(/\s+/g, " ")
|
|
74
|
+
.trim();
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
export function createTelegramTurnPrefix(
|
|
@@ -142,7 +147,6 @@ function appendTelegramSourceContext(
|
|
|
142
147
|
return text ? `${text}\n\n${sourceContext}` : sourceContext;
|
|
143
148
|
}
|
|
144
149
|
|
|
145
|
-
|
|
146
150
|
function buildTelegramForwardContextBlock(options: {
|
|
147
151
|
context: string;
|
|
148
152
|
text: string;
|
|
@@ -411,7 +415,6 @@ export interface BuildTelegramPromptTurnOptions {
|
|
|
411
415
|
readBinaryFile: (path: string) => Promise<Uint8Array>;
|
|
412
416
|
inferImageMimeType: (path: string) => string | undefined;
|
|
413
417
|
voiceReplyMode?: TelegramVoiceReplyMode;
|
|
414
|
-
voiceReplyModeConfigured?: boolean;
|
|
415
418
|
voicePromptContribution?: string;
|
|
416
419
|
}
|
|
417
420
|
|
|
@@ -435,9 +438,11 @@ export interface TelegramPromptTurnRuntimeBuilderDeps<
|
|
|
435
438
|
}>;
|
|
436
439
|
resolveTimeLine?: (chatId: number) => string | null;
|
|
437
440
|
getVoiceReplyMode?: () => TelegramVoiceReplyMode;
|
|
438
|
-
isVoiceReplyModeConfigured?: () => boolean;
|
|
439
441
|
/** Returns the visible thread label for a message target, used to add thread context to the prompt prefix. */
|
|
440
|
-
getTelegramThreadLabel?: (message: {
|
|
442
|
+
getTelegramThreadLabel?: (message: {
|
|
443
|
+
chat: { id: number };
|
|
444
|
+
message_thread_id?: number;
|
|
445
|
+
}) => string | undefined;
|
|
441
446
|
getAllowedUserId?: () => number | undefined;
|
|
442
447
|
}
|
|
443
448
|
|
|
@@ -475,9 +480,7 @@ export function createTelegramPromptTurnRuntimeBuilder<
|
|
|
475
480
|
text: extractTelegramMessageText(message),
|
|
476
481
|
message,
|
|
477
482
|
fileNames: new Set(
|
|
478
|
-
collectTelegramFileInfos(
|
|
479
|
-
(file) => file.fileName,
|
|
480
|
-
),
|
|
483
|
+
collectTelegramFileInfos([message]).map((file) => file.fileName),
|
|
481
484
|
),
|
|
482
485
|
},
|
|
483
486
|
]
|
|
@@ -567,7 +570,6 @@ export function createTelegramPromptTurnRuntimeBuilder<
|
|
|
567
570
|
timeLine,
|
|
568
571
|
inferImageMimeType: guessMediaType,
|
|
569
572
|
voiceReplyMode,
|
|
570
|
-
voiceReplyModeConfigured: deps.isVoiceReplyModeConfigured?.(),
|
|
571
573
|
voicePromptContribution: computeVoicePromptContribution(
|
|
572
574
|
voiceReplyMode,
|
|
573
575
|
files,
|
|
@@ -581,9 +583,13 @@ function getTelegramVoicePromptContext(
|
|
|
581
583
|
voiceReplyMode: TelegramVoiceReplyMode,
|
|
582
584
|
hasVoiceFile: boolean,
|
|
583
585
|
): Record<string, string> | undefined {
|
|
584
|
-
if (
|
|
585
|
-
|
|
586
|
-
|
|
586
|
+
if (
|
|
587
|
+
voiceReplyMode !== "always" &&
|
|
588
|
+
!(voiceReplyMode === "mirror" && hasVoiceFile)
|
|
589
|
+
) {
|
|
590
|
+
return undefined;
|
|
591
|
+
}
|
|
592
|
+
return { delivery: "automatic voice" };
|
|
587
593
|
}
|
|
588
594
|
|
|
589
595
|
export async function buildTelegramPromptTurn(
|
|
@@ -597,8 +603,6 @@ export async function buildTelegramPromptTurn(
|
|
|
597
603
|
(f) => f.kind === "voice" || f.kind === "audio",
|
|
598
604
|
);
|
|
599
605
|
const voiceReplyMode = options.voiceReplyMode ?? getTelegramVoiceReplyMode();
|
|
600
|
-
const showVoiceContext =
|
|
601
|
-
options.voiceReplyModeConfigured ?? options.voiceReplyMode !== undefined;
|
|
602
606
|
const content: TelegramPromptContent[] = [
|
|
603
607
|
{
|
|
604
608
|
type: "text",
|
|
@@ -615,9 +619,10 @@ export async function buildTelegramPromptTurn(
|
|
|
615
619
|
sourceContext: options.sourceContext,
|
|
616
620
|
historyTurns: options.historyTurns,
|
|
617
621
|
timeLine: options.timeLine,
|
|
618
|
-
voiceContext:
|
|
619
|
-
|
|
620
|
-
|
|
622
|
+
voiceContext: getTelegramVoicePromptContext(
|
|
623
|
+
voiceReplyMode,
|
|
624
|
+
hasVoiceFile,
|
|
625
|
+
),
|
|
621
626
|
}),
|
|
622
627
|
},
|
|
623
628
|
];
|
|
@@ -634,8 +639,7 @@ export async function buildTelegramPromptTurn(
|
|
|
634
639
|
}
|
|
635
640
|
if (options.voicePromptContribution?.trim()) {
|
|
636
641
|
const textItem = content.find((c) => c.type === "text") as
|
|
637
|
-
|
|
638
|
-
| undefined;
|
|
642
|
+
{ type: "text"; text: string } | undefined;
|
|
639
643
|
if (textItem) {
|
|
640
644
|
textItem.text = `${textItem.text}\n\n${options.voicePromptContribution.trim()}`;
|
|
641
645
|
}
|
package/lib/voice.ts
CHANGED
|
@@ -38,7 +38,7 @@ function getNextAvailableProviderId<T>(
|
|
|
38
38
|
return id;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export type TelegramVoiceReplyMode = "
|
|
41
|
+
export type TelegramVoiceReplyMode = "hidden" | "mirror" | "always";
|
|
42
42
|
|
|
43
43
|
export type TelegramVoiceSynthesisProviderResult =
|
|
44
44
|
| string
|
|
@@ -67,9 +67,7 @@ export interface TelegramVoiceSynthesisProvider {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export type TelegramVoiceTranscriptionProviderResult =
|
|
70
|
-
| string
|
|
71
|
-
| { text: string; language?: string }
|
|
72
|
-
| undefined;
|
|
70
|
+
string | { text: string; language?: string } | undefined;
|
|
73
71
|
|
|
74
72
|
export interface TelegramVoiceTranscriptionFile {
|
|
75
73
|
path: string;
|
|
@@ -217,16 +215,17 @@ export function clearTelegramVoiceTranscriptionProviders(): void {
|
|
|
217
215
|
// --- Voice Reply Modes ---
|
|
218
216
|
|
|
219
217
|
export const TELEGRAM_VOICE_REPLY_MODES = [
|
|
218
|
+
"hidden",
|
|
220
219
|
"mirror",
|
|
221
220
|
"always",
|
|
222
|
-
"manual",
|
|
223
221
|
] as const;
|
|
224
222
|
|
|
225
223
|
/**
|
|
226
224
|
* Returns the active voice reply mode for the current session.
|
|
227
225
|
*
|
|
228
226
|
* Pi-telegram owns reply-mode policy through telegram.json. If
|
|
229
|
-
* config.voice.replyMode is missing
|
|
227
|
+
* config.voice.replyMode is missing, invalid, or legacy `manual`, the effective
|
|
228
|
+
* mode is hidden.
|
|
230
229
|
*/
|
|
231
230
|
export function getTelegramVoiceReplyMode(config?: {
|
|
232
231
|
voice?: { replyMode?: string };
|
|
@@ -238,7 +237,7 @@ export function getTelegramVoiceReplyMode(config?: {
|
|
|
238
237
|
) {
|
|
239
238
|
return configMode as TelegramVoiceReplyMode;
|
|
240
239
|
}
|
|
241
|
-
return "
|
|
240
|
+
return "hidden";
|
|
242
241
|
}
|
|
243
242
|
|
|
244
243
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-telegram",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"node": ">=22.19.0"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
|
-
"test": "node --experimental-strip-types --test tests/*.test.ts",
|
|
30
|
+
"test": "node --experimental-strip-types --test --test-reporter=dot tests/*.test.ts",
|
|
31
|
+
"test:verbose": "node --experimental-strip-types --test --test-reporter=spec tests/*.test.ts",
|
|
31
32
|
"typecheck": "tsc --noEmit",
|
|
32
33
|
"audit": "npm audit",
|
|
33
34
|
"pack:check": "npm pack --dry-run",
|