@llblab/pi-kit 0.1.13 → 0.2.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/CHANGELOG.md +5 -0
- package/README.md +2 -2
- package/node_modules/@llblab/pi-actors/AGENTS.md +5 -3
- package/node_modules/@llblab/pi-actors/BACKLOG.md +1 -1
- package/node_modules/@llblab/pi-actors/CHANGELOG.md +15 -0
- package/node_modules/@llblab/pi-actors/README.md +5 -3
- package/node_modules/@llblab/pi-actors/dist/index.js +4 -1
- package/node_modules/@llblab/pi-actors/dist/lib/async-runs.d.ts +2 -2
- package/node_modules/@llblab/pi-actors/dist/lib/async-runs.js +42 -19
- package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.d.ts +2 -1
- package/node_modules/@llblab/pi-actors/dist/lib/extension-runtime.js +7 -2
- package/node_modules/@llblab/pi-actors/dist/lib/limits.d.ts +9 -0
- package/node_modules/@llblab/pi-actors/dist/lib/limits.js +9 -0
- package/node_modules/@llblab/pi-actors/dist/lib/observability.d.ts +10 -11
- package/node_modules/@llblab/pi-actors/dist/lib/observability.js +81 -56
- package/node_modules/@llblab/pi-actors/dist/lib/pi.d.ts +31 -0
- package/node_modules/@llblab/pi-actors/dist/lib/pi.js +180 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.d.ts +115 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-delivery.js +623 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.d.ts +3 -0
- package/node_modules/@llblab/pi-actors/dist/lib/run-ui-runtime.js +341 -13
- package/node_modules/@llblab/pi-actors/dist/lib/runs-trace.d.ts +1 -1
- package/node_modules/@llblab/pi-actors/dist/lib/runs-trace.js +5 -3
- package/node_modules/@llblab/pi-actors/dist/lib/session-evidence.d.ts +16 -0
- package/node_modules/@llblab/pi-actors/dist/lib/session-evidence.js +143 -0
- package/node_modules/@llblab/pi-actors/dist/lib/temp.js +1 -1
- package/node_modules/@llblab/pi-actors/dist/lib/tools-inspect.js +3 -1
- package/node_modules/@llblab/pi-actors/dist/scripts/async-runner.mjs +5 -19
- package/node_modules/@llblab/pi-actors/dist/skills/actors/SKILL.md +2 -2
- package/node_modules/@llblab/pi-actors/dist/skills/actors/references/runs.md +1 -1
- package/node_modules/@llblab/pi-actors/dist/skills/swarm/SKILL.md +1 -1
- package/node_modules/@llblab/pi-actors/docs/README.md +1 -0
- package/node_modules/@llblab/pi-actors/docs/async-runs.md +8 -4
- package/node_modules/@llblab/pi-actors/docs/coordinator-delivery.md +207 -0
- package/node_modules/@llblab/pi-actors/index.ts +4 -1
- package/node_modules/@llblab/pi-actors/lib/async-runs.ts +42 -21
- package/node_modules/@llblab/pi-actors/lib/extension-runtime.ts +8 -3
- package/node_modules/@llblab/pi-actors/lib/limits.ts +9 -0
- package/node_modules/@llblab/pi-actors/lib/observability.ts +97 -78
- package/node_modules/@llblab/pi-actors/lib/pi.ts +210 -0
- package/node_modules/@llblab/pi-actors/lib/run-delivery.ts +800 -0
- package/node_modules/@llblab/pi-actors/lib/run-ui-runtime.ts +370 -18
- package/node_modules/@llblab/pi-actors/lib/runs-trace.ts +6 -4
- package/node_modules/@llblab/pi-actors/lib/session-evidence.ts +153 -0
- package/node_modules/@llblab/pi-actors/lib/temp.ts +1 -1
- package/node_modules/@llblab/pi-actors/lib/tools-inspect.ts +4 -1
- package/node_modules/@llblab/pi-actors/package.json +3 -3
- package/node_modules/@llblab/pi-actors/scripts/async-runner.mjs +5 -19
- package/node_modules/@llblab/pi-actors/skills/actors/SKILL.md +2 -2
- package/node_modules/@llblab/pi-actors/skills/actors/references/runs.md +1 -1
- package/node_modules/@llblab/pi-actors/skills/swarm/SKILL.md +1 -1
- package/node_modules/@llblab/pi-telegram/AGENTS.md +4 -4
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +11 -0
- package/node_modules/@llblab/pi-telegram/README.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/activity.md +4 -4
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +5 -5
- package/node_modules/@llblab/pi-telegram/docs/outbound.md +2 -2
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +3 -4
- package/node_modules/@llblab/pi-telegram/docs/ui-style.md +4 -5
- package/node_modules/@llblab/pi-telegram/docs/voice.md +12 -2
- package/node_modules/@llblab/pi-telegram/index.ts +0 -1
- package/node_modules/@llblab/pi-telegram/lib/activity.ts +3 -5
- package/node_modules/@llblab/pi-telegram/lib/bindings.ts +13 -17
- package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +1 -1
- package/node_modules/@llblab/pi-telegram/lib/config.ts +25 -25
- package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +10 -73
- package/node_modules/@llblab/pi-telegram/lib/status.ts +11 -1
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/skills/generated-control-surface/SKILL.md +5 -3
- package/package.json +3 -3
|
@@ -105,7 +105,6 @@ export interface TelegramConfig {
|
|
|
105
105
|
assistant?: {
|
|
106
106
|
draftPreviews?: boolean;
|
|
107
107
|
rendering?: TelegramAssistantRenderingMode;
|
|
108
|
-
proactivePush?: boolean;
|
|
109
108
|
activity?: TelegramActivityVerbosity;
|
|
110
109
|
timeInjection?: TelegramTimeMode;
|
|
111
110
|
/** @deprecated use activity */
|
|
@@ -454,10 +453,32 @@ function omitTelegramRootProfileFields(config: TelegramConfig): TelegramConfig {
|
|
|
454
453
|
return sharedConfig;
|
|
455
454
|
}
|
|
456
455
|
|
|
456
|
+
function omitRetiredProactivePush(config: TelegramConfig): {
|
|
457
|
+
config: TelegramConfig;
|
|
458
|
+
changed: boolean;
|
|
459
|
+
} {
|
|
460
|
+
const assistant = config.assistant as
|
|
461
|
+
| (NonNullable<TelegramConfig["assistant"]> & { proactivePush?: unknown })
|
|
462
|
+
| undefined;
|
|
463
|
+
if (!assistant || !Object.hasOwn(assistant, "proactivePush")) {
|
|
464
|
+
return { config, changed: false };
|
|
465
|
+
}
|
|
466
|
+
const { proactivePush: _proactivePush, ...remainingAssistant } = assistant;
|
|
467
|
+
const next = { ...config };
|
|
468
|
+
if (Object.keys(remainingAssistant).length > 0) {
|
|
469
|
+
next.assistant = remainingAssistant;
|
|
470
|
+
} else {
|
|
471
|
+
delete next.assistant;
|
|
472
|
+
}
|
|
473
|
+
return { config: next, changed: true };
|
|
474
|
+
}
|
|
475
|
+
|
|
457
476
|
export function normalizeTelegramDefaultProfileConfig(config: TelegramConfig): {
|
|
458
477
|
config: TelegramConfig;
|
|
459
478
|
changed: boolean;
|
|
460
479
|
} {
|
|
480
|
+
const retiredProactivePush = omitRetiredProactivePush(config);
|
|
481
|
+
config = retiredProactivePush.config;
|
|
461
482
|
const hasLegacyRootProfile = [
|
|
462
483
|
"botToken",
|
|
463
484
|
"botUsername",
|
|
@@ -465,7 +486,9 @@ export function normalizeTelegramDefaultProfileConfig(config: TelegramConfig): {
|
|
|
465
486
|
"allowedUserId",
|
|
466
487
|
"lastUpdateId",
|
|
467
488
|
].some((field) => Object.hasOwn(config, field));
|
|
468
|
-
if (!hasLegacyRootProfile)
|
|
489
|
+
if (!hasLegacyRootProfile) {
|
|
490
|
+
return { config, changed: retiredProactivePush.changed };
|
|
491
|
+
}
|
|
469
492
|
const canonicalProfile = config.profiles?.[TELEGRAM_DEFAULT_PROFILE_NAME];
|
|
470
493
|
const legacyToken = config.botToken?.trim();
|
|
471
494
|
if (Object.hasOwn(config, "botToken") && !legacyToken) {
|
|
@@ -712,27 +735,6 @@ export function createTelegramConfigStore(
|
|
|
712
735
|
};
|
|
713
736
|
}
|
|
714
737
|
|
|
715
|
-
export function createTelegramProactivePushChecker(
|
|
716
|
-
configStore: Pick<TelegramConfigStore, "get">,
|
|
717
|
-
): () => boolean {
|
|
718
|
-
return () => configStore.get().assistant?.proactivePush ?? true;
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
export function createTelegramProactivePushSetter(
|
|
722
|
-
configStore: TelegramMutableConfigStore,
|
|
723
|
-
): (enabled: boolean) => Promise<void> {
|
|
724
|
-
return async (enabled) => {
|
|
725
|
-
await loadLatestTelegramConfig(configStore);
|
|
726
|
-
const current = configStore.get();
|
|
727
|
-
const config: TelegramConfig = {
|
|
728
|
-
...current,
|
|
729
|
-
assistant: { ...current.assistant, proactivePush: enabled },
|
|
730
|
-
};
|
|
731
|
-
configStore.set(config);
|
|
732
|
-
await configStore.persist(config);
|
|
733
|
-
};
|
|
734
|
-
}
|
|
735
|
-
|
|
736
738
|
export function createTelegramDraftPreviewsChecker(
|
|
737
739
|
configStore: Pick<TelegramConfigStore, "get">,
|
|
738
740
|
): () => boolean {
|
|
@@ -1019,8 +1021,6 @@ export function createTelegramConfigControls(
|
|
|
1019
1021
|
configStore: TelegramMutableConfigStore,
|
|
1020
1022
|
) {
|
|
1021
1023
|
return {
|
|
1022
|
-
isProactivePushEnabled: createTelegramProactivePushChecker(configStore),
|
|
1023
|
-
setProactivePushEnabled: createTelegramProactivePushSetter(configStore),
|
|
1024
1024
|
areDraftPreviewsEnabled: createTelegramDraftPreviewsChecker(configStore),
|
|
1025
1025
|
setDraftPreviewsEnabled: createTelegramDraftPreviewsSetter(configStore),
|
|
1026
1026
|
getAssistantRenderingMode:
|
|
@@ -21,7 +21,6 @@ import type { TelegramVoiceReplyMode } from "./voice.ts";
|
|
|
21
21
|
export type TelegramSettingsMenuReplyMarkup = TelegramInlineKeyboardMarkup;
|
|
22
22
|
|
|
23
23
|
export interface TelegramSettingsStateDeps {
|
|
24
|
-
isProactivePushEnabled: () => boolean;
|
|
25
24
|
areDraftPreviewsEnabled: () => boolean;
|
|
26
25
|
getAssistantRenderingMode: () => TelegramAssistantRenderingMode;
|
|
27
26
|
getActivityVerbosity: () => TelegramActivityVerbosity;
|
|
@@ -32,7 +31,6 @@ export interface TelegramSettingsStateDeps {
|
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
export interface TelegramSettingsMutationDeps extends TelegramSettingsStateDeps {
|
|
35
|
-
setProactivePushEnabled: (enabled: boolean) => Promise<void>;
|
|
36
34
|
setDraftPreviewsEnabled: (enabled: boolean) => Promise<void>;
|
|
37
35
|
setAssistantRenderingMode: (
|
|
38
36
|
mode: TelegramAssistantRenderingMode,
|
|
@@ -139,7 +137,6 @@ export interface TelegramSettingsMenuRuntimeDeps<
|
|
|
139
137
|
export const SETTINGS_MENU_TITLE = "<b>⚙️ Settings:</b>";
|
|
140
138
|
export const AUTOMATIC_THREAD_CLEANUP_SETTINGS_TITLE =
|
|
141
139
|
"<b>🧹 Thread cleanup:</b>";
|
|
142
|
-
export const PROACTIVE_PUSH_SETTINGS_TITLE = "<b>📌 Proactive push:</b>";
|
|
143
140
|
export const DRAFT_PREVIEWS_SETTINGS_TITLE = "<b>📝 Draft previews:</b>";
|
|
144
141
|
export const ASSISTANT_RENDERING_SETTINGS_TITLE =
|
|
145
142
|
"<b>🧾 Assistant rendering:</b>";
|
|
@@ -181,19 +178,6 @@ export function buildAutomaticThreadCleanupSettingsText(
|
|
|
181
178
|
].join("\n");
|
|
182
179
|
}
|
|
183
180
|
|
|
184
|
-
export function buildProactivePushSettingsText(
|
|
185
|
-
proactivePushEnabled: boolean,
|
|
186
|
-
): string {
|
|
187
|
-
return [
|
|
188
|
-
`${PROACTIVE_PUSH_SETTINGS_TITLE} <code>${proactivePushEnabled ? "on" : "off"}</code>`,
|
|
189
|
-
"",
|
|
190
|
-
"Control whether public assistant output from local/autonomous work is projected to Telegram.",
|
|
191
|
-
"",
|
|
192
|
-
"<code>-</code> <code>on</code> (default): send each completed public block, including visible checkpoints and the final answer, while connected.",
|
|
193
|
-
"<code>-</code> <code>off</code>: keep local/autonomous assistant blocks in Pi; Telegram-originated replies still use their normal delivery path.",
|
|
194
|
-
].join("\n");
|
|
195
|
-
}
|
|
196
|
-
|
|
197
181
|
export function buildDraftPreviewsSettingsText(enabled: boolean): string {
|
|
198
182
|
return [
|
|
199
183
|
`${DRAFT_PREVIEWS_SETTINGS_TITLE} <code>${enabled ? "on" : "off"}</code>`,
|
|
@@ -265,7 +249,6 @@ export function buildTimeInjectionModeSettingsText(
|
|
|
265
249
|
}
|
|
266
250
|
|
|
267
251
|
export function buildTelegramSettingsMenuReplyMarkup(
|
|
268
|
-
proactivePushEnabled: boolean,
|
|
269
252
|
draftPreviewsEnabled: boolean,
|
|
270
253
|
assistantRenderingModeOrVoiceReplyMode:
|
|
271
254
|
TelegramAssistantRenderingMode | TelegramVoiceReplyMode,
|
|
@@ -325,10 +308,6 @@ export function buildTelegramSettingsMenuReplyMarkup(
|
|
|
325
308
|
text: `🔬 Activity: ${activityVerbosity}`,
|
|
326
309
|
callback_data: "settings:open:activity-verbosity",
|
|
327
310
|
},
|
|
328
|
-
{
|
|
329
|
-
text: `📌 Proactive push: ${proactivePushEnabled ? "on" : "off"}`,
|
|
330
|
-
callback_data: "settings:open:proactive",
|
|
331
|
-
},
|
|
332
311
|
{
|
|
333
312
|
text: `🕒 Time injection: ${getTelegramSettingsStateValueLabel(timeInjectionMode)}`,
|
|
334
313
|
callback_data: "settings:open:time-injection",
|
|
@@ -362,7 +341,6 @@ export async function openTelegramSettingsMenu<
|
|
|
362
341
|
state,
|
|
363
342
|
buildTelegramSettingsMenuText(),
|
|
364
343
|
buildTelegramSettingsMenuReplyMarkup(
|
|
365
|
-
deps.isProactivePushEnabled(),
|
|
366
344
|
deps.areDraftPreviewsEnabled(),
|
|
367
345
|
deps.getAssistantRenderingMode(),
|
|
368
346
|
deps.getVoiceReplyMode(),
|
|
@@ -399,26 +377,6 @@ export function buildAutomaticThreadCleanupSettingsReplyMarkup(
|
|
|
399
377
|
};
|
|
400
378
|
}
|
|
401
379
|
|
|
402
|
-
export function buildProactivePushSettingsReplyMarkup(
|
|
403
|
-
proactivePushEnabled: boolean,
|
|
404
|
-
): TelegramSettingsMenuReplyMarkup {
|
|
405
|
-
return {
|
|
406
|
-
inline_keyboard: [
|
|
407
|
-
[{ text: "⬆️ Back", callback_data: "settings:list" }],
|
|
408
|
-
[
|
|
409
|
-
{
|
|
410
|
-
text: proactivePushEnabled ? "🟢 On" : "⚫️ On",
|
|
411
|
-
callback_data: "settings:set:proactive:on",
|
|
412
|
-
},
|
|
413
|
-
{
|
|
414
|
-
text: proactivePushEnabled ? "⚫️ Off" : "🟡 Off",
|
|
415
|
-
callback_data: "settings:set:proactive:off",
|
|
416
|
-
},
|
|
417
|
-
],
|
|
418
|
-
],
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
|
|
422
380
|
export function buildDraftPreviewsSettingsReplyMarkup(
|
|
423
381
|
enabled: boolean,
|
|
424
382
|
): TelegramSettingsMenuReplyMarkup {
|
|
@@ -521,7 +479,6 @@ export async function updateTelegramSettingsMenuMessage(
|
|
|
521
479
|
await deps.updateSettingsMessage(
|
|
522
480
|
buildTelegramSettingsMenuText(),
|
|
523
481
|
buildTelegramSettingsMenuReplyMarkup(
|
|
524
|
-
deps.isProactivePushEnabled(),
|
|
525
482
|
deps.areDraftPreviewsEnabled(),
|
|
526
483
|
deps.getAssistantRenderingMode(),
|
|
527
484
|
deps.getVoiceReplyMode(),
|
|
@@ -544,16 +501,6 @@ export async function updateAutomaticThreadCleanupSettingsMessage(
|
|
|
544
501
|
);
|
|
545
502
|
}
|
|
546
503
|
|
|
547
|
-
export async function updateProactivePushSettingsMessage(
|
|
548
|
-
deps: TelegramSettingsMenuCallbackDeps,
|
|
549
|
-
): Promise<void> {
|
|
550
|
-
const proactivePushEnabled = deps.isProactivePushEnabled();
|
|
551
|
-
await deps.updateSettingsMessage(
|
|
552
|
-
buildProactivePushSettingsText(proactivePushEnabled),
|
|
553
|
-
buildProactivePushSettingsReplyMarkup(proactivePushEnabled),
|
|
554
|
-
);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
504
|
export async function updateDraftPreviewsSettingsMessage(
|
|
558
505
|
deps: TelegramSettingsMenuCallbackDeps,
|
|
559
506
|
): Promise<void> {
|
|
@@ -621,9 +568,16 @@ export async function handleTelegramSettingsMenuCallbackAction(
|
|
|
621
568
|
await deps.answerCallbackQuery(callbackQueryId);
|
|
622
569
|
return true;
|
|
623
570
|
}
|
|
624
|
-
if (
|
|
625
|
-
|
|
626
|
-
|
|
571
|
+
if (
|
|
572
|
+
data === "settings:open:proactive" ||
|
|
573
|
+
data === "settings:set:proactive:on" ||
|
|
574
|
+
data === "settings:set:proactive:off"
|
|
575
|
+
) {
|
|
576
|
+
await updateTelegramSettingsMenuMessage(deps, deps.sectionRegistry);
|
|
577
|
+
await deps.answerCallbackQuery(
|
|
578
|
+
callbackQueryId,
|
|
579
|
+
"Public assistant output is always delivered while Telegram is connected.",
|
|
580
|
+
);
|
|
627
581
|
return true;
|
|
628
582
|
}
|
|
629
583
|
if (
|
|
@@ -751,19 +705,6 @@ export async function handleTelegramSettingsMenuCallbackAction(
|
|
|
751
705
|
);
|
|
752
706
|
return true;
|
|
753
707
|
}
|
|
754
|
-
if (
|
|
755
|
-
data === "settings:set:proactive:on" ||
|
|
756
|
-
data === "settings:set:proactive:off"
|
|
757
|
-
) {
|
|
758
|
-
const enabled = data.endsWith(":on");
|
|
759
|
-
await deps.setProactivePushEnabled(enabled);
|
|
760
|
-
await updateProactivePushSettingsMessage(deps);
|
|
761
|
-
await deps.answerCallbackQuery(
|
|
762
|
-
callbackQueryId,
|
|
763
|
-
`Proactive push ${enabled ? "enabled" : "disabled"}`,
|
|
764
|
-
);
|
|
765
|
-
return true;
|
|
766
|
-
}
|
|
767
708
|
await deps.answerCallbackQuery(callbackQueryId);
|
|
768
709
|
return true;
|
|
769
710
|
}
|
|
@@ -781,7 +722,6 @@ export function createTelegramSettingsMenuRuntime<
|
|
|
781
722
|
return openTelegramSettingsMenu(
|
|
782
723
|
{
|
|
783
724
|
getModelMenuState: () => deps.getModelMenuState(chatId, ctx),
|
|
784
|
-
isProactivePushEnabled: deps.isProactivePushEnabled,
|
|
785
725
|
areDraftPreviewsEnabled: deps.areDraftPreviewsEnabled,
|
|
786
726
|
getAssistantRenderingMode: deps.getAssistantRenderingMode,
|
|
787
727
|
getActivityVerbosity: deps.getActivityVerbosity,
|
|
@@ -805,7 +745,6 @@ export function createTelegramSettingsMenuRuntime<
|
|
|
805
745
|
await deps.reloadConfig?.();
|
|
806
746
|
return updateTelegramSettingsMenuMessage(
|
|
807
747
|
{
|
|
808
|
-
isProactivePushEnabled: deps.isProactivePushEnabled,
|
|
809
748
|
areDraftPreviewsEnabled: deps.areDraftPreviewsEnabled,
|
|
810
749
|
getAssistantRenderingMode: deps.getAssistantRenderingMode,
|
|
811
750
|
getActivityVerbosity: deps.getActivityVerbosity,
|
|
@@ -849,7 +788,6 @@ export function createTelegramSettingsMenuRuntime<
|
|
|
849
788
|
deps.storeModelMenuState(state);
|
|
850
789
|
}
|
|
851
790
|
return handleTelegramSettingsMenuCallbackAction(query.id, query.data, {
|
|
852
|
-
isProactivePushEnabled: deps.isProactivePushEnabled,
|
|
853
791
|
areDraftPreviewsEnabled: deps.areDraftPreviewsEnabled,
|
|
854
792
|
getAssistantRenderingMode: deps.getAssistantRenderingMode,
|
|
855
793
|
getActivityVerbosity: deps.getActivityVerbosity,
|
|
@@ -857,7 +795,6 @@ export function createTelegramSettingsMenuRuntime<
|
|
|
857
795
|
isVoiceReplyModeConfigured: deps.isVoiceReplyModeConfigured,
|
|
858
796
|
getTimeInjectionMode: deps.getTimeInjectionMode,
|
|
859
797
|
isAutomaticThreadCleanupEnabled: deps.isAutomaticThreadCleanupEnabled,
|
|
860
|
-
setProactivePushEnabled: deps.setProactivePushEnabled,
|
|
861
798
|
setDraftPreviewsEnabled: deps.setDraftPreviewsEnabled,
|
|
862
799
|
setAssistantRenderingMode: deps.setAssistantRenderingMode,
|
|
863
800
|
setActivityVerbosity: deps.setActivityVerbosity,
|
|
@@ -14,6 +14,7 @@ export interface TelegramUsageStats {
|
|
|
14
14
|
totalCacheRead: number;
|
|
15
15
|
totalCacheWrite: number;
|
|
16
16
|
totalCost: number;
|
|
17
|
+
latestCacheHitRate?: number;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
interface TelegramUsageMessage {
|
|
@@ -1473,6 +1474,9 @@ function collectUsageStats(ctx: TelegramStatusContext): TelegramUsageStats {
|
|
|
1473
1474
|
stats.totalCacheRead += usage.cacheRead;
|
|
1474
1475
|
stats.totalCacheWrite += usage.cacheWrite;
|
|
1475
1476
|
stats.totalCost += usage.cost.total;
|
|
1477
|
+
const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
1478
|
+
stats.latestCacheHitRate =
|
|
1479
|
+
promptTokens > 0 ? (usage.cacheRead / promptTokens) * 100 : undefined;
|
|
1476
1480
|
}
|
|
1477
1481
|
return stats;
|
|
1478
1482
|
}
|
|
@@ -1494,6 +1498,12 @@ function buildUsageSummary(stats: TelegramUsageStats): string | undefined {
|
|
|
1494
1498
|
tokenParts.push(`R${formatTokens(stats.totalCacheRead)}`);
|
|
1495
1499
|
if (stats.totalCacheWrite)
|
|
1496
1500
|
tokenParts.push(`W${formatTokens(stats.totalCacheWrite)}`);
|
|
1501
|
+
if (
|
|
1502
|
+
(stats.totalCacheRead > 0 || stats.totalCacheWrite > 0) &&
|
|
1503
|
+
stats.latestCacheHitRate !== undefined
|
|
1504
|
+
) {
|
|
1505
|
+
tokenParts.push(`CH${stats.latestCacheHitRate.toFixed(1)}%`);
|
|
1506
|
+
}
|
|
1497
1507
|
return tokenParts.length > 0 ? tokenParts.join(" ") : undefined;
|
|
1498
1508
|
}
|
|
1499
1509
|
|
|
@@ -1549,7 +1559,7 @@ export function buildStatusHtml(
|
|
|
1549
1559
|
const usageSummary = buildUsageSummary(stats);
|
|
1550
1560
|
const costSummary = buildCostSummary(stats, usesSubscription);
|
|
1551
1561
|
if (usageSummary) {
|
|
1552
|
-
lines.push(buildStatusRow("
|
|
1562
|
+
lines.push(buildStatusRow("Tokens", usageSummary));
|
|
1553
1563
|
}
|
|
1554
1564
|
if (costSummary) {
|
|
1555
1565
|
lines.push(buildStatusRow("Cost", costSummary));
|
|
@@ -136,11 +136,11 @@ Use the transport's canonical prompt-button syntax. For pi-telegram, one top-lev
|
|
|
136
136
|
|
|
137
137
|
Model the control surface as an ordered ragged sequence of independently sized rows, not as a rectangular matrix to fill. Rectangular grids are one specialization for genuinely spatial or coordinate-bearing state; most interfaces should vary row width according to hierarchy, grouping, label pressure, and action priority.
|
|
138
138
|
|
|
139
|
-
- Default to one full-width button per row for non-spatial controls.
|
|
139
|
+
- Default to one full-width button per row for non-spatial controls. In pi-telegram matrix syntax, emit these vertical controls as top-level cells without wrapping them in a nested row array. A nested array explicitly opts into horizontal grouping and is justified only when the controls are genuine peers and every label is unmistakably compact—roughly no more than 15 visible characters including its emoji and space. This is a judgment heuristic, not a request to mechanically count characters: if fit is uncertain, wording is multi-phrase, or truncation is plausible, keep top-level vertical buttons.
|
|
140
140
|
- Use a singleton full-width row for a structurally independent, pinned, primary, summary, or high-consequence action, and whenever label length makes horizontal grouping cramped or ambiguous.
|
|
141
141
|
- Vary row widths intentionally—for example `1 → 2 → 4 → 1 → 2`—and never pad a row with empty, duplicate, or no-op controls merely to produce uniform dimensions.
|
|
142
142
|
- Preserve reading order across rows: orientation and structural navigation first, primary content or choices next, secondary controls afterward, and destructive actions visibly separated when present.
|
|
143
|
-
- Treat two columns as an earned compact
|
|
143
|
+
- Treat two columns as an earned compact exception, never the default: a pair normally fits only when each label is unmistakably short—approximately one emoji plus one or two short words and roughly 15 visible characters or fewer. Do not count mechanically to justify density. If either label has more words, unusually long words, qualifiers, or any plausible wrapping or ellipsis risk, place each button on its own top-level row. Use at most two columns for readable text labels; move additional peer choices into more semantic rows rather than compressing textual buttons across a phone-width line. Three through five columns are for short symbols, glyphs, coordinates, or compact codes whose position carries meaning. Six through eight may be used only for single-glyph or similarly minimal position-bearing labels whose grouping materially improves the interaction; a row of emoji-only controls may therefore legitimately use up to eight columns. Eight is the phone-width UX maximum: never generate a row of nine or more controls even though the parser has no artificial width cap. Never shorten necessary wording merely to increase row density; regroup or use full-width rows when labels need explanation, wrap ambiguously, or lose meaning without prose.
|
|
144
144
|
|
|
145
145
|
Treat vertical extent independently from horizontal density. A genuinely spatial surface may retain many rows—such as an `8×16` field—when vertical continuity, coordinates, and one-glance topology matter; do not paginate merely to make its height match its width. For non-spatial collections, however, a tall button wall should yield to semantic grouping, progressive disclosure, or pagination. Keep compact state and instructions above a tall surface, preserve stable coordinates across regeneration, and avoid repeating prose between rows.
|
|
146
146
|
|
|
@@ -187,7 +187,7 @@ Button prompts must:
|
|
|
187
187
|
- Request fresh inspection when state may have changed.
|
|
188
188
|
- Avoid embedding volatile output that should be rediscovered.
|
|
189
189
|
|
|
190
|
-
Labels stay short, distinct, and scannable. Prefer an explicit `label` over exposing a long prompt as button text.
|
|
190
|
+
Labels stay short, distinct, and scannable. Prefer an explicit `label` over exposing a long prompt as button text. Every generated human-readable action label must start with the most semantically appropriate emoji, followed by one ASCII space and concise action text; selecting that emoji is a required design step, not optional polish. When label and prompt are intentionally identical, use the same emoji-prefixed value rather than dropping the marker through compact syntax. Keep emoji meaning consistent across sibling controls, avoid decorative noise, and do not rely on emoji or color alone. An emoji-free text label remains a transport-compatible fallback only when no honest semantic emoji can be identified after considering the action, domain, and state; convenience, label pressure, or uncertainty between several reasonable candidates is not sufficient. Genuine coordinates, established symbolic controls, and intentionally emoji-only spatial cells keep their domain grammar. If buttons are unavailable, render the same control surface as a numbered choice list.
|
|
191
191
|
|
|
192
192
|
## Capability Adapters
|
|
193
193
|
|
|
@@ -243,6 +243,8 @@ Before sending a surface, verify:
|
|
|
243
243
|
- Complete versus filtered or adapted output is labeled honestly.
|
|
244
244
|
- No secret appears in visible text or button payloads.
|
|
245
245
|
- Every button carries a valid self-contained next intent and measurably shortens likely feedback.
|
|
246
|
+
- Every human-readable action label uses `emoji + space + text`; an emoji-free fallback has an explicit semantic reason rather than mere convenience.
|
|
247
|
+
- Non-spatial action buttons are top-level vertical cells by default; every nested row has an obvious compact-peer justification with no plausible truncation risk.
|
|
246
248
|
- The surface preserves free-form feedback when choices are not exhaustive.
|
|
247
249
|
- High-impact operations route through confirmation.
|
|
248
250
|
- Back/Up and Refresh appear only when useful.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"LICENSE"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@llblab/pi-actors": "0.
|
|
43
|
+
"@llblab/pi-actors": "0.52.0",
|
|
44
44
|
"@llblab/pi-codex-usage": "0.9.4",
|
|
45
45
|
"@llblab/pi-grow-loop": "0.7.3",
|
|
46
|
-
"@llblab/pi-telegram": "0.
|
|
46
|
+
"@llblab/pi-telegram": "0.41.0"
|
|
47
47
|
},
|
|
48
48
|
"bundledDependencies": [
|
|
49
49
|
"@llblab/pi-actors",
|