@llblab/pi-kit 0.17.1 → 0.18.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 +6 -0
- package/README.md +1 -1
- package/node_modules/@llblab/pi-telegram/AGENTS.md +1 -1
- package/node_modules/@llblab/pi-telegram/CHANGELOG.md +5 -0
- package/node_modules/@llblab/pi-telegram/README.md +1 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.d.ts +3 -1
- package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.js +40 -9
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +3 -2
- package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +32 -30
- package/node_modules/@llblab/pi-telegram/dist/package.json +1 -1
- package/node_modules/@llblab/pi-telegram/docs/architecture.md +1 -1
- package/node_modules/@llblab/pi-telegram/docs/public-api.md +1 -1
- package/node_modules/@llblab/pi-telegram/lib/activity-verbosity.ts +46 -9
- package/node_modules/@llblab/pi-telegram/lib/commands.ts +39 -29
- package/node_modules/@llblab/pi-telegram/package.json +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@llblab/pi-kit` are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.18.0 - 2026-09-18
|
|
6
|
+
|
|
7
|
+
- `Telegram Lifecycle Gateway`: Advances the exact Telegram pin to `0.50.0`, replacing the session-specific technical command with one guarded internal gateway for runtime-armed lifecycle actions while preserving `/new` settlement, continuity, and terminal-result guarantees.
|
|
8
|
+
- `Thinking Cadence`: Buffers the first Telegram thinking frame for two seconds and throttles later updates to the same two-second cadence as answer drafts, while still flushing remaining reasoning when the block completes.
|
|
9
|
+
- `Package Cohort`: Keeps every other bundled package at its current exact version; the package set, resource inventory, and explicit load order remain unchanged.
|
|
10
|
+
|
|
5
11
|
## 0.17.1 - 2026-09-18
|
|
6
12
|
|
|
7
13
|
- `State Flow Activation Hotfixes`: Advances the exact State Flow pin to `0.16.2`, allowing resumed activation to reassert its selected session cohort and allowing passive global memory before a new CWD has materialized, while retaining fail-closed handling for genuinely incomplete ownership.
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Package links lead to the owning repositories for usage, documentation, issues,
|
|
|
15
15
|
| [`@llblab/pi-codex-usage`](https://github.com/llblab/pi-codex-usage) | `0.10.0` | Compact Codex/Spark subscription-limit and Business credit-usage status |
|
|
16
16
|
| [`@llblab/pi-grow-loop`](https://github.com/llblab/pi-grow-loop) | `0.8.1` | Visible continuation scheduling and bounded worker Skills |
|
|
17
17
|
| [`@llblab/pi-state-flow`](https://github.com/llblab/pi-state-flow) | `0.16.2` | Incremental scoped state/context/memory compiler with proportional operational guidance, intentional agency, reactive dangling-reference diagnostics, compiled runtime delivery, safe compaction, and exact publication |
|
|
18
|
-
| [`@llblab/pi-telegram`](https://github.com/llblab/pi-telegram) | `0.
|
|
18
|
+
| [`@llblab/pi-telegram`](https://github.com/llblab/pi-telegram) | `0.50.0` | Telegram companion with native fresh-session replacement, a guarded internal lifecycle gateway, buffered thinking cadence, adaptive Thread continuity, exact queues, files, voice, controls, and Generative Apps guidance |
|
|
19
19
|
| [`@llblab/skills`](https://github.com/llblab/skills) | `1.15.0` | Portable workflows for engineering, review, design, context maintenance, and other focused tasks |
|
|
20
20
|
|
|
21
21
|
Versions are exact by design. An upstream release does not change an installed kit until this repository explicitly advances the dependency and publishes a new kit version. Runtime defects and package-specific feature requests belong in the linked repository; package selection and kit installation issues belong here.
|
|
@@ -121,7 +121,7 @@ The detailed map is canonical in [`docs/architecture.md`](./docs/architecture.md
|
|
|
121
121
|
- Command templates remain compact and shell-free. Use string leaves or ordered `template` arrays; shell operators are not an execution contract. Examples use portable executable placeholders, never machine-local paths.
|
|
122
122
|
- `telegram_attach` is the canonical file path and `telegram_message` the direct Markdown text/buttons path. Both require current direct or registered-follower authority and must not replace the normal active-turn reply.
|
|
123
123
|
- Inbound handlers transform text/media before queueing; outbound handlers precede programmatic/provider fallbacks. Public contracts and ordering live in `docs/inbound.md`, `docs/outbound.md`, and `docs/public-api.md`.
|
|
124
|
-
- Pi integration uses public hooks and APIs. Telegram `/new` is scheduled against the exact durable update, dispatched only after that update is removed from the journal, and then routed through
|
|
124
|
+
- Pi integration uses public hooks and APIs. Telegram `/new` is scheduled against the exact durable update, dispatched only after that update is removed from the journal, and then routed through the single `/telegram-internal` Pi gateway via `pi.sendUserMessage(..., { expandPromptTemplates: true })`; only a runtime-armed typed action may execute, manual invocation reports that the command cannot be run manually, and the handler receives the real `ExtensionCommandContext` before calling `ctx.newSession()`. Before replacement, CAS-publish one exact expiring handoff in the profile target snapshot. `workspace-thread` successors re-key the matching Workspace binding; `classic-chat` successors preserve Profile/CWD/session/chat continuity without creating a binding or invoking topic APIs. Both atomically claim the intent before one terminal result, and the old `withSession` path never publishes the same success. Never replace the session while inbound authority is unsettled, store stale command contexts, accept an expired or mismatched handoff, inject terminal input, spawn a shadow Pi process, or mutate session files.
|
|
125
125
|
|
|
126
126
|
## 7. Engineering Conventions
|
|
127
127
|
|
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.50.0: Internal lifecycle gateway and thinking cadence
|
|
8
|
+
|
|
9
|
+
- `Internal lifecycle gateway`: Replaces the session-specific technical command with one `/telegram-internal` gateway for runtime-armed typed actions. Manual invocation performs no action and explains that the command cannot be run manually; settled `/new` replacement retains the same lifecycle and terminal-result guarantees.
|
|
10
|
+
- `Thinking cadence`: Thinking now follows the same cadence as answer drafts: it accumulates the opening frame for two seconds, then updates at most once every two seconds while still flushing buffered reasoning when the block completes.
|
|
11
|
+
|
|
7
12
|
## 0.49.0: Unified fresh-session continuity
|
|
8
13
|
|
|
9
14
|
- `/new`: Classic and Threaded Mode now share one confirmed fresh-session flow. The settled callback deletes its dialog and publishes an expiring exact-target intent; a same- or cross-process successor preserves the classic chat or re-keys the Thread/slot/name, atomically claims once, then sends one terminal result. Identity mismatches fail closed.
|
|
@@ -126,7 +126,7 @@ Enable the optional capabilities the bridge needs in the [@BotFather](https://t.
|
|
|
126
126
|
| Model and thinking | Switch model or thinking level from Telegram through safe continuation flows. | Mobile control can adjust execution strategy without tearing down the current session. |
|
|
127
127
|
| Compaction | Confirm `/compact`, show native active status during compaction, and preserve Telegram-owned turn semantics. | Context maintenance is visible and safe from the phone. |
|
|
128
128
|
| Draft previews | Show Telegram's native `…typing` indicator whenever the connected instance is doing agent work, or enable Rich Draft previews for streamed answer text. | Local prompts, Telegram turns, and autonomous continuations remain visibly active while draft visibility stays independent from final rendering. |
|
|
129
|
-
| Activity | Keep the default `verbose` technical surface, show only `thinking`, show only `tools`, or select `quiet` for answer-only delivery. Every instance reloads this shared file-backed choice before a new agent run; thinking
|
|
129
|
+
| Activity | Keep the default `verbose` technical surface, show only `thinking`, show only `tools`, or select `quiet` for answer-only delivery. Every instance reloads this shared file-backed choice before a new agent run; thinking accumulates for two seconds and then updates at most every two seconds in a headerless expandable quote, while each tool uses one iconless closed root row containing nested evidence details. | Persistent collapsed technical activity minimizes chat height and stays bounded, redacted, target-fenced, free of URL previews, and visually separate from semantic assistant answers. |
|
|
130
130
|
| Assistant rendering | Choose Native Rich Markdown or legacy Markdown-to-HTML for final assistant replies. | Renderer compatibility is explicit instead of being conflated with draft previews. |
|
|
131
131
|
| Bridge UI rendering | Render thinking through headerless expandable HTML with inline emphasis/code, render each tool as an iconless native Rich root details tree with immediately visible arguments and collapsed secondary evidence, and keep menus, queue controls, status, settings, diagnostics, and sections on Telegram HTML/plain UI. | Harness-owned surfaces remain operationally predictable and visually distinct from model-authored answers. |
|
|
132
132
|
| Inbound files | Download inbound files to the Pi agent temp directory with size limits. | Screenshots, PDFs, datasets, and artifacts enter Pi as inspectable local files. |
|
|
@@ -11,7 +11,7 @@ export declare const TELEGRAM_ACTIVITY_MESSAGE_MAX_CHARS = 3900;
|
|
|
11
11
|
export declare const TELEGRAM_ACTIVITY_MESSAGE_MAX_TOOLS = 6;
|
|
12
12
|
export declare const TELEGRAM_REASONING_MESSAGE_MAX_FRAMES = 24;
|
|
13
13
|
export declare const TELEGRAM_REASONING_BUFFER_MAX_CHARS = 1200;
|
|
14
|
-
export declare const TELEGRAM_REASONING_MIN_INTERVAL_MS =
|
|
14
|
+
export declare const TELEGRAM_REASONING_MIN_INTERVAL_MS = 2000;
|
|
15
15
|
export declare const TELEGRAM_TOOL_UPDATE_MAX_ENTRIES = 4;
|
|
16
16
|
interface ToolActivity {
|
|
17
17
|
id: string;
|
|
@@ -41,6 +41,8 @@ export declare function createTelegramActivityVerbosityRuntime<TAuthority>(deps:
|
|
|
41
41
|
getActivityMode: () => "quiet" | "thinking" | "tools" | "verbose";
|
|
42
42
|
refreshActivityMode?: () => Promise<void>;
|
|
43
43
|
getNowMs?: () => number;
|
|
44
|
+
setReasoningTimeout?: (callback: () => void, delayMs: number) => ReturnType<typeof setTimeout>;
|
|
45
|
+
clearReasoningTimeout?: (timer: ReturnType<typeof setTimeout>) => void;
|
|
44
46
|
resolveTarget: (event: TelegramActivityEvent) => TelegramTarget | undefined;
|
|
45
47
|
captureAuthority: () => TAuthority;
|
|
46
48
|
isAuthorityActive: (authority: TAuthority) => boolean;
|
|
@@ -9,7 +9,9 @@ export const TELEGRAM_ACTIVITY_MESSAGE_MAX_CHARS = 3_900;
|
|
|
9
9
|
export const TELEGRAM_ACTIVITY_MESSAGE_MAX_TOOLS = 6;
|
|
10
10
|
export const TELEGRAM_REASONING_MESSAGE_MAX_FRAMES = 24;
|
|
11
11
|
export const TELEGRAM_REASONING_BUFFER_MAX_CHARS = 1_200;
|
|
12
|
-
|
|
12
|
+
// Match native answer drafts: accumulate the opening frame for one full
|
|
13
|
+
// interval, then publish at most one updated frame per interval.
|
|
14
|
+
export const TELEGRAM_REASONING_MIN_INTERVAL_MS = 2_000;
|
|
13
15
|
export const TELEGRAM_TOOL_UPDATE_MAX_ENTRIES = 4;
|
|
14
16
|
function targetEquals(left, right) {
|
|
15
17
|
return left.chatId === right.chatId && left.threadId === right.threadId;
|
|
@@ -234,10 +236,18 @@ export function createTelegramActivityVerbosityRuntime(deps) {
|
|
|
234
236
|
let reasoningMessage;
|
|
235
237
|
let reasoningBlocked = false;
|
|
236
238
|
let lastReasoningPublishMs = 0;
|
|
239
|
+
let reasoningFlushTimer;
|
|
237
240
|
let toolMessage;
|
|
238
241
|
const tools = new Map();
|
|
239
242
|
const toolOrder = [];
|
|
243
|
+
const clearReasoningFlushTimer = () => {
|
|
244
|
+
if (!reasoningFlushTimer)
|
|
245
|
+
return;
|
|
246
|
+
(deps.clearReasoningTimeout ?? clearTimeout)(reasoningFlushTimer);
|
|
247
|
+
reasoningFlushTimer = undefined;
|
|
248
|
+
};
|
|
240
249
|
const clearActivity = () => {
|
|
250
|
+
clearReasoningFlushTimer();
|
|
241
251
|
activityId = undefined;
|
|
242
252
|
authority = undefined;
|
|
243
253
|
target = undefined;
|
|
@@ -330,6 +340,30 @@ export function createTelegramActivityVerbosityRuntime(deps) {
|
|
|
330
340
|
deps.recordFailure?.(canEdit ? "reasoning-edit" : "reasoning-send", event, error);
|
|
331
341
|
}
|
|
332
342
|
};
|
|
343
|
+
const scheduleReasoningPublish = (event, acceptedGeneration) => {
|
|
344
|
+
if (reasoningFlushTimer || reasoningBlocked)
|
|
345
|
+
return;
|
|
346
|
+
const elapsed = reasoningMessageFrames === 0
|
|
347
|
+
? 0
|
|
348
|
+
: getNowMs() - lastReasoningPublishMs;
|
|
349
|
+
const delayMs = Math.max(0, TELEGRAM_REASONING_MIN_INTERVAL_MS - elapsed);
|
|
350
|
+
const schedule = deps.setReasoningTimeout ?? setTimeout;
|
|
351
|
+
reasoningFlushTimer = schedule(() => {
|
|
352
|
+
reasoningFlushTimer = undefined;
|
|
353
|
+
const admittedAuthority = authority;
|
|
354
|
+
const task = async () => {
|
|
355
|
+
if (!isCurrent(acceptedGeneration, admittedAuthority) ||
|
|
356
|
+
reasoningChars <= lastReasoningMessageChars)
|
|
357
|
+
return;
|
|
358
|
+
await publishReasoning(event, acceptedGeneration);
|
|
359
|
+
};
|
|
360
|
+
const enqueue = deps.enqueue ?? ((next) => tail.then(next));
|
|
361
|
+
tail = enqueue(task).catch((error) => {
|
|
362
|
+
deps.recordFailure?.("reasoning-send", event, error);
|
|
363
|
+
});
|
|
364
|
+
}, delayMs);
|
|
365
|
+
reasoningFlushTimer?.unref?.();
|
|
366
|
+
};
|
|
333
367
|
const publishTool = async (event, tool, acceptedGeneration) => {
|
|
334
368
|
const admittedAuthority = authority;
|
|
335
369
|
if (!isCurrent(acceptedGeneration, admittedAuthority) || !target) {
|
|
@@ -461,12 +495,8 @@ export function createTelegramActivityVerbosityRuntime(deps) {
|
|
|
461
495
|
return;
|
|
462
496
|
reasoningChars += event.delta.length;
|
|
463
497
|
reasoningBuffer = `${reasoningBuffer}${event.delta}`.slice(-TELEGRAM_REASONING_BUFFER_MAX_CHARS);
|
|
464
|
-
if (reasoningMessageFrames < TELEGRAM_REASONING_MESSAGE_MAX_FRAMES
|
|
465
|
-
(
|
|
466
|
-
(getNowMs() - lastReasoningPublishMs >=
|
|
467
|
-
TELEGRAM_REASONING_MIN_INTERVAL_MS &&
|
|
468
|
-
reasoningChars - lastReasoningMessageChars >= 160))) {
|
|
469
|
-
await publishReasoning(event, acceptedGeneration);
|
|
498
|
+
if (reasoningMessageFrames < TELEGRAM_REASONING_MESSAGE_MAX_FRAMES) {
|
|
499
|
+
scheduleReasoningPublish(event, acceptedGeneration);
|
|
470
500
|
}
|
|
471
501
|
return;
|
|
472
502
|
}
|
|
@@ -477,6 +507,7 @@ export function createTelegramActivityVerbosityRuntime(deps) {
|
|
|
477
507
|
reasoningChars = event.text.length;
|
|
478
508
|
reasoningBuffer = event.text.slice(-TELEGRAM_REASONING_BUFFER_MAX_CHARS);
|
|
479
509
|
}
|
|
510
|
+
clearReasoningFlushTimer();
|
|
480
511
|
if (reasoningChars > 0 &&
|
|
481
512
|
reasoningChars > lastReasoningMessageChars &&
|
|
482
513
|
!reasoningBlocked) {
|
|
@@ -550,8 +581,8 @@ export function createTelegramActivityVerbosityRuntime(deps) {
|
|
|
550
581
|
return;
|
|
551
582
|
}
|
|
552
583
|
if (event.type === "agent-end" || event.type === "agent-settled") {
|
|
553
|
-
|
|
554
|
-
|
|
584
|
+
clearReasoningFlushTimer();
|
|
585
|
+
if (reasoningChars > lastReasoningMessageChars &&
|
|
555
586
|
!reasoningBlocked) {
|
|
556
587
|
await publishReasoning(event, acceptedGeneration);
|
|
557
588
|
}
|
|
@@ -574,8 +574,9 @@ export declare function createTelegramCommandHandler<TMessage extends TelegramCo
|
|
|
574
574
|
export declare function createTelegramCommandOrPromptRuntime<TMessage, TContext>(deps: TelegramCommandOrPromptRuntimeDeps<TMessage, TContext>): {
|
|
575
575
|
dispatchMessages: (messages: TMessage[], ctx: TContext) => Promise<void>;
|
|
576
576
|
};
|
|
577
|
-
export declare const
|
|
578
|
-
export declare const
|
|
577
|
+
export declare const TELEGRAM_INTERNAL_COMMAND_NAME = "telegram-internal";
|
|
578
|
+
export declare const TELEGRAM_INTERNAL_COMMAND_DESCRIPTION = "(internal) dispatch one settled Telegram lifecycle action";
|
|
579
|
+
export declare const TELEGRAM_INTERNAL_MANUAL_USE_MESSAGE = "This internal Telegram command cannot be run manually.";
|
|
579
580
|
export declare function delayTelegramSessionAction(delayMs: number): Promise<void>;
|
|
580
581
|
export interface TelegramSessionActionRuntimeDeps {
|
|
581
582
|
registerCommand: Pi.ExtensionAPI["registerCommand"];
|
|
@@ -1232,8 +1232,9 @@ async function handleTelegramCommandRuntime(commandName, message, ctx, deps, com
|
|
|
1232
1232
|
},
|
|
1233
1233
|
}, commandArgs);
|
|
1234
1234
|
}
|
|
1235
|
-
export const
|
|
1236
|
-
export const
|
|
1235
|
+
export const TELEGRAM_INTERNAL_COMMAND_NAME = "telegram-internal";
|
|
1236
|
+
export const TELEGRAM_INTERNAL_COMMAND_DESCRIPTION = "(internal) dispatch one settled Telegram lifecycle action";
|
|
1237
|
+
export const TELEGRAM_INTERNAL_MANUAL_USE_MESSAGE = "This internal Telegram command cannot be run manually.";
|
|
1237
1238
|
export function delayTelegramSessionAction(delayMs) {
|
|
1238
1239
|
return new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1239
1240
|
}
|
|
@@ -1364,8 +1365,7 @@ export function createTelegramSessionActionAssembly(deps) {
|
|
|
1364
1365
|
export function createTelegramSessionActionRuntime(deps) {
|
|
1365
1366
|
let pendingUpdateId;
|
|
1366
1367
|
let pendingTarget;
|
|
1367
|
-
let
|
|
1368
|
-
let commandUpdateId;
|
|
1368
|
+
let pendingAction;
|
|
1369
1369
|
let registered = false;
|
|
1370
1370
|
const reportFailure = (error) => {
|
|
1371
1371
|
try {
|
|
@@ -1380,33 +1380,34 @@ export function createTelegramSessionActionRuntime(deps) {
|
|
|
1380
1380
|
if (registered)
|
|
1381
1381
|
return;
|
|
1382
1382
|
registered = true;
|
|
1383
|
-
deps.registerCommand(
|
|
1384
|
-
description:
|
|
1383
|
+
deps.registerCommand(TELEGRAM_INTERNAL_COMMAND_NAME, {
|
|
1384
|
+
description: TELEGRAM_INTERNAL_COMMAND_DESCRIPTION,
|
|
1385
1385
|
handler: async (_args, ctx) => {
|
|
1386
|
-
|
|
1386
|
+
const action = pendingAction;
|
|
1387
|
+
if (!action) {
|
|
1388
|
+
ctx.ui.notify(TELEGRAM_INTERNAL_MANUAL_USE_MESSAGE, "warning");
|
|
1387
1389
|
return;
|
|
1388
|
-
commandPending = false;
|
|
1389
|
-
const target = pendingTarget;
|
|
1390
|
-
const updateId = commandUpdateId;
|
|
1391
|
-
pendingTarget = undefined;
|
|
1392
|
-
commandUpdateId = undefined;
|
|
1393
|
-
if (!target || updateId === undefined)
|
|
1394
|
-
return;
|
|
1395
|
-
try {
|
|
1396
|
-
await deps.prepareReplacement?.(ctx, updateId, target);
|
|
1397
|
-
const result = await ctx.newSession();
|
|
1398
|
-
if (result.cancelled)
|
|
1399
|
-
await deps.notifyResult(target, "cancelled");
|
|
1400
1390
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1391
|
+
pendingAction = undefined;
|
|
1392
|
+
switch (action.kind) {
|
|
1393
|
+
case "replace-session":
|
|
1394
|
+
try {
|
|
1395
|
+
await deps.prepareReplacement?.(ctx, action.updateId, action.target);
|
|
1396
|
+
const result = await ctx.newSession();
|
|
1397
|
+
if (result.cancelled)
|
|
1398
|
+
await deps.notifyResult(action.target, "cancelled");
|
|
1399
|
+
}
|
|
1400
|
+
catch (error) {
|
|
1401
|
+
reportFailure(error);
|
|
1402
|
+
await deps.notifyResult(action.target, "failure");
|
|
1403
|
+
}
|
|
1404
|
+
return;
|
|
1404
1405
|
}
|
|
1405
1406
|
},
|
|
1406
1407
|
});
|
|
1407
1408
|
},
|
|
1408
1409
|
scheduleAfterUpdate(updateId, target) {
|
|
1409
|
-
if (pendingUpdateId !== undefined ||
|
|
1410
|
+
if (pendingUpdateId !== undefined || pendingAction !== undefined)
|
|
1410
1411
|
return false;
|
|
1411
1412
|
pendingUpdateId = updateId;
|
|
1412
1413
|
pendingTarget = { ...target };
|
|
@@ -1416,21 +1417,22 @@ export function createTelegramSessionActionRuntime(deps) {
|
|
|
1416
1417
|
if (pendingUpdateId !== updateId)
|
|
1417
1418
|
return;
|
|
1418
1419
|
pendingUpdateId = undefined;
|
|
1419
|
-
|
|
1420
|
-
|
|
1420
|
+
const target = pendingTarget;
|
|
1421
|
+
pendingTarget = undefined;
|
|
1422
|
+
if (!target)
|
|
1423
|
+
return;
|
|
1424
|
+
pendingAction = { kind: "replace-session", updateId, target };
|
|
1421
1425
|
void Promise.resolve()
|
|
1422
|
-
.then(() => deps.sendUserMessage(`/${
|
|
1426
|
+
.then(() => deps.sendUserMessage(`/${TELEGRAM_INTERNAL_COMMAND_NAME}`, {
|
|
1423
1427
|
expandPromptTemplates: true,
|
|
1424
1428
|
}))
|
|
1425
1429
|
.catch((error) => {
|
|
1426
|
-
|
|
1427
|
-
commandUpdateId = undefined;
|
|
1428
|
-
pendingTarget = undefined;
|
|
1430
|
+
pendingAction = undefined;
|
|
1429
1431
|
reportFailure(error);
|
|
1430
1432
|
});
|
|
1431
1433
|
},
|
|
1432
1434
|
hasPending() {
|
|
1433
|
-
return pendingUpdateId !== undefined ||
|
|
1435
|
+
return pendingUpdateId !== undefined || pendingAction !== undefined;
|
|
1434
1436
|
},
|
|
1435
1437
|
};
|
|
1436
1438
|
}
|
|
@@ -610,7 +610,7 @@ Queue reaction behavior, lane-tail transitions, Keep/Skip independence, multi-re
|
|
|
610
610
|
|
|
611
611
|
Complete intermediate assistant text blocks from Telegram-originated activity are sent once to the immutable originating target before active-turn final delivery; final and terminal-partial segments stay with settlement so replies are not duplicated. While this instance has exact direct or follower transport authority, completed public blocks from local/autonomous work are always sent once and in source order to the instance's authorized target. Connected companion projection is not configurable; disconnect or authority loss is its boundary. Both paths use the configured Rich or HTML renderer and exclude reasoning, tool traffic, token deltas, local prompt text, unknown sources, and stale generations. Each admitted block remains fenced to its exact target, profile/token stamp, leader epoch or follower registration generation, and session generation; non-idempotent acknowledgement ambiguity never authorizes replay.
|
|
612
612
|
|
|
613
|
-
`assistant.activity` is an independent bridge-owned projection over normalized Activity events. Each process reloads the shared file-backed setting at `agent-start` before activity admission, so multi-instance mode cannot continue projecting a stale broader process-local selection. Omitted values resolve to `verbose`, while invalid values fail closed to `quiet`; `thinking` and `tools` select one technical class, while `verbose` enables both. Provider-exposed thinking uses persistent ordinary HTML containing only a standard expandable blockquote with a bounded redacted latest-text window and inline Markdown rendered as Telegram HTML. Completed executed tools use native Rich Messages: each closed `<Tool>: <status>` root details node renders snake-case names as title words while preserving an uppercase two- or three-letter repeated prefix per word, then the native disclosure chevron reveals an open-by-default `arguments` child plus closed retained `update N` and `result`/`error` child details with lowercase monospaced, marker-free summaries and JSON pre blocks; known-safe Rich rejections fall back to the previous HTML disclosure. The projection captures the exact target and transport stamp at activity admission, serializes updates, preserves tool-start order, closes coalescing across assistant/thinking boundaries, bounds retained text/update memory plus edit frames and message/tool size, disables previews and HTTP(S) auto-link recognition inside technical evidence, and never replays a possibly committed send. Session generations own independent queues, so replacement drops queued old work without waiting on an old call. Bridge-owned assistant output and activity projection share one activity-publication sequence admitted synchronously from the activity bus, so later tool disclosures cannot overtake earlier assistant blocks. Activity targets and transport authority are captured before queued work starts. Active Telegram-turn final replies/artifacts and automatic compaction notices use that same publication owner before the existing direct/follower transport split, without mutually waiting on separate output tails. Final settlement captures the exact active turn and assistant result and reserves its publication position before config loading. Empty outcomes without a publication candidate reserve no position. Replacement, preparation failure, or an unused reservation releases the position without resetting or replying for a replacement turn. Final errors also publish through this owner. Reservations accept one task; cancellation cannot undo a published task, and session reset releases unresolved reservations while fencing old queued tasks. Terminal assistant messages with a publication candidate reserve the final position synchronously; settlement consumes that reservation only for the exact originating turn. Compaction notices enter the same queue immediately, behind the reserved final rather than through a separate notice buffer. Settlement, a new agent run, or session replacement cancels an unconsumed reservation. Notice target and authority are captured when the event is observed. Pi lifecycle completion does not wait for network publication. This order is process-local and does not serialize unrelated instances or independent registered activity handlers. Settlement, replacement, disconnect, failure, or stale authority clears only local ownership; already-sent activity messages remain in chat.
|
|
613
|
+
`assistant.activity` is an independent bridge-owned projection over normalized Activity events. Each process reloads the shared file-backed setting at `agent-start` before activity admission, so multi-instance mode cannot continue projecting a stale broader process-local selection. Omitted values resolve to `verbose`, while invalid values fail closed to `quiet`; `thinking` and `tools` select one technical class, while `verbose` enables both. Provider-exposed thinking uses persistent ordinary HTML containing only a standard expandable blockquote with a bounded redacted latest-text window and inline Markdown rendered as Telegram HTML. Like answer drafts, it accumulates for two seconds before the first frame, publishes at most one update every two seconds, and flushes remaining buffered reasoning on terminal completion. Completed executed tools use native Rich Messages: each closed `<Tool>: <status>` root details node renders snake-case names as title words while preserving an uppercase two- or three-letter repeated prefix per word, then the native disclosure chevron reveals an open-by-default `arguments` child plus closed retained `update N` and `result`/`error` child details with lowercase monospaced, marker-free summaries and JSON pre blocks; known-safe Rich rejections fall back to the previous HTML disclosure. The projection captures the exact target and transport stamp at activity admission, serializes updates, preserves tool-start order, closes coalescing across assistant/thinking boundaries, bounds retained text/update memory plus edit frames and message/tool size, disables previews and HTTP(S) auto-link recognition inside technical evidence, and never replays a possibly committed send. Session generations own independent queues, so replacement drops queued old work without waiting on an old call. Bridge-owned assistant output and activity projection share one activity-publication sequence admitted synchronously from the activity bus, so later tool disclosures cannot overtake earlier assistant blocks. Activity targets and transport authority are captured before queued work starts. Active Telegram-turn final replies/artifacts and automatic compaction notices use that same publication owner before the existing direct/follower transport split, without mutually waiting on separate output tails. Final settlement captures the exact active turn and assistant result and reserves its publication position before config loading. Empty outcomes without a publication candidate reserve no position. Replacement, preparation failure, or an unused reservation releases the position without resetting or replying for a replacement turn. Final errors also publish through this owner. Reservations accept one task; cancellation cannot undo a published task, and session reset releases unresolved reservations while fencing old queued tasks. Terminal assistant messages with a publication candidate reserve the final position synchronously; settlement consumes that reservation only for the exact originating turn. Compaction notices enter the same queue immediately, behind the reserved final rather than through a separate notice buffer. Settlement, a new agent run, or session replacement cancels an unconsumed reservation. Notice target and authority are captured when the event is observed. Pi lifecycle completion does not wait for network publication. This order is process-local and does not serialize unrelated instances or independent registered activity handlers. Settlement, replacement, disconnect, failure, or stale authority clears only local ownership; already-sent activity messages remain in chat.
|
|
614
614
|
|
|
615
615
|
Telegram prompt guidance is context- and authority-aware. The package and source-checkout extension contribute `telegram-bridge`, optional `generated-control-surface`, and `generative-apps` Skills through Pi resource discovery. Generated Control Surface treats `interface = f(state, capabilities, intent)` as a renderer-neutral primitive, compiling transient evidence-backed controls over domain-owned workflows, systems, navigation, supervision, and decisions without creating parallel application state. It composes an ordered ragged sequence of independently sized semantic rows rather than filling a rectangular grid: compact rows contain genuine peers, singleton rows isolate structurally independent actions, and rectangular layouts remain reserved for genuinely spatial state. Text-bearing controls use at most two columns and flow into additional rows, while denser rows are reserved for short position-bearing glyphs or codes and never exceed the eight-column phone-width UX maximum. Vertical extent is independent: a true spatial surface may retain substantially more rows, while non-spatial button walls route to grouping, disclosure, or pagination. Symmetry is treated as an evidence claim about equal relationships or real spatial topology; an abstract layout catalog supplies adaptable singleton, peer, staged, navigational, repeated-pair, and rectangular shapes without forcing tasks into preset grids. Repeated controls carry the smallest sufficient action delta when visible conversation is unambiguous; larger or error-prone state moves to a deterministic task-owned Markdown artifact, correctness-sensitive transitions move to a small domain-owned transition implementation, and repeated clicks are adjudicated against current state rather than stale button appearance. Its filesystem adapter reserves the first full-width row for parent traversal outside root, places available Previous/Next controls together in one compact row immediately afterward, orders visible directories, hidden directories, visible files, and hidden files alphabetically within each category before fixed ten-entry pagination, renders path/range metadata as stacked status-style key-value rows instead of middle-dot prose, emits the complete Telegram control set through one JSON-matrix action, suppresses duplicate plain/monospaced listings and default Refresh unless user preference overrides presentation, and retains an ordinary numbered fallback when buttons are unavailable. Only an exact direct owner or live registered follower exposes the two pi-telegram delivery tools, their active-tool metadata, and the compact routing suffix. Disconnect or authority loss removes those tool surfaces for subsequent requests without touching foreign tools; reconnect/recovery restores only the pi-telegram subset that was active before suspension, including across same-process reload. Repeated stable interactions may graduate from that model-mediated surface into a reviewed Generative App whose deterministic bound methods bypass Pi queue admission; the `generative-apps` Skill owns this compilation and operating workflow while the underlying capability retains domain authority. Telegram-originated turns route to the stable Skill contracts and retain dynamic blocks such as `[voice] delivery: automatic voice`; the Skills and public documentation own syntax, target routing, Threaded Mode behavior, Generative App operation, and diagnostics.
|
|
616
616
|
|
|
@@ -51,7 +51,7 @@ Stable commands inside Pi:
|
|
|
51
51
|
Stable commands inside the paired Telegram DM:
|
|
52
52
|
|
|
53
53
|
- `/start` — pair when needed and open the main application menu.
|
|
54
|
-
- `/new` — after idle and empty-queue checks, request a new Pi session in the current classic chat or Thread. The bridge acknowledges the callback, deletes its confirmation, completes and removes the exact durable update, then dispatches
|
|
54
|
+
- `/new` — after idle and empty-queue checks, request a new Pi session in the current classic chat or Thread. The bridge acknowledges the callback, deletes its confirmation, completes and removes the exact durable update, then dispatches one runtime-armed typed action through the internal `/telegram-internal` Pi gateway using `pi.sendUserMessage(..., { expandPromptTemplates: true })`. Manual invocation reports that the gateway cannot be run manually; the armed handler receives a real `ExtensionCommandContext` and calls `ctx.newSession()`; one discriminated durable intent preserves either exact classic Profile/CWD/session/chat continuity or the Thread binding with slot/name re-key. The successor CAS-claims that intent before sending one terminal result. Busy, identity-mismatch, and unavailable-host paths fail closed.
|
|
55
55
|
- `/compact` — open confirmation and compact when idle.
|
|
56
56
|
- `/next` — abort active work first when needed, let the interrupted prompt receive its abort notice, then reply `Dispatching next queued turn.` to the exact queued prompt selected for the next model turn. The command itself is never the lifecycle-notice reply target, and aborted pending assistant text is suppressed.
|
|
57
57
|
- `/continue` — enqueue a priority `continue` prompt.
|
|
@@ -24,7 +24,9 @@ export const TELEGRAM_ACTIVITY_MESSAGE_MAX_CHARS = 3_900;
|
|
|
24
24
|
export const TELEGRAM_ACTIVITY_MESSAGE_MAX_TOOLS = 6;
|
|
25
25
|
export const TELEGRAM_REASONING_MESSAGE_MAX_FRAMES = 24;
|
|
26
26
|
export const TELEGRAM_REASONING_BUFFER_MAX_CHARS = 1_200;
|
|
27
|
-
|
|
27
|
+
// Match native answer drafts: accumulate the opening frame for one full
|
|
28
|
+
// interval, then publish at most one updated frame per interval.
|
|
29
|
+
export const TELEGRAM_REASONING_MIN_INTERVAL_MS = 2_000;
|
|
28
30
|
export const TELEGRAM_TOOL_UPDATE_MAX_ENTRIES = 4;
|
|
29
31
|
|
|
30
32
|
interface ToolActivity {
|
|
@@ -325,6 +327,11 @@ export function createTelegramActivityVerbosityRuntime<TAuthority>(deps: {
|
|
|
325
327
|
getActivityMode: () => "quiet" | "thinking" | "tools" | "verbose";
|
|
326
328
|
refreshActivityMode?: () => Promise<void>;
|
|
327
329
|
getNowMs?: () => number;
|
|
330
|
+
setReasoningTimeout?: (
|
|
331
|
+
callback: () => void,
|
|
332
|
+
delayMs: number,
|
|
333
|
+
) => ReturnType<typeof setTimeout>;
|
|
334
|
+
clearReasoningTimeout?: (timer: ReturnType<typeof setTimeout>) => void;
|
|
328
335
|
resolveTarget: (event: TelegramActivityEvent) => TelegramTarget | undefined;
|
|
329
336
|
captureAuthority: () => TAuthority;
|
|
330
337
|
isAuthorityActive: (authority: TAuthority) => boolean;
|
|
@@ -360,11 +367,18 @@ export function createTelegramActivityVerbosityRuntime<TAuthority>(deps: {
|
|
|
360
367
|
let reasoningMessage: ReasoningMessage | undefined;
|
|
361
368
|
let reasoningBlocked = false;
|
|
362
369
|
let lastReasoningPublishMs = 0;
|
|
370
|
+
let reasoningFlushTimer: ReturnType<typeof setTimeout> | undefined;
|
|
363
371
|
let toolMessage: ToolMessage | undefined;
|
|
364
372
|
const tools = new Map<string, ToolActivity>();
|
|
365
373
|
const toolOrder: string[] = [];
|
|
366
374
|
|
|
375
|
+
const clearReasoningFlushTimer = () => {
|
|
376
|
+
if (!reasoningFlushTimer) return;
|
|
377
|
+
(deps.clearReasoningTimeout ?? clearTimeout)(reasoningFlushTimer);
|
|
378
|
+
reasoningFlushTimer = undefined;
|
|
379
|
+
};
|
|
367
380
|
const clearActivity = () => {
|
|
381
|
+
clearReasoningFlushTimer();
|
|
368
382
|
activityId = undefined;
|
|
369
383
|
authority = undefined;
|
|
370
384
|
target = undefined;
|
|
@@ -466,6 +480,33 @@ export function createTelegramActivityVerbosityRuntime<TAuthority>(deps: {
|
|
|
466
480
|
);
|
|
467
481
|
}
|
|
468
482
|
};
|
|
483
|
+
const scheduleReasoningPublish = (
|
|
484
|
+
event: TelegramActivityEvent,
|
|
485
|
+
acceptedGeneration: number,
|
|
486
|
+
) => {
|
|
487
|
+
if (reasoningFlushTimer || reasoningBlocked) return;
|
|
488
|
+
const elapsed = reasoningMessageFrames === 0
|
|
489
|
+
? 0
|
|
490
|
+
: getNowMs() - lastReasoningPublishMs;
|
|
491
|
+
const delayMs = Math.max(0, TELEGRAM_REASONING_MIN_INTERVAL_MS - elapsed);
|
|
492
|
+
const schedule = deps.setReasoningTimeout ?? setTimeout;
|
|
493
|
+
reasoningFlushTimer = schedule(() => {
|
|
494
|
+
reasoningFlushTimer = undefined;
|
|
495
|
+
const admittedAuthority = authority;
|
|
496
|
+
const task = async () => {
|
|
497
|
+
if (
|
|
498
|
+
!isCurrent(acceptedGeneration, admittedAuthority) ||
|
|
499
|
+
reasoningChars <= lastReasoningMessageChars
|
|
500
|
+
) return;
|
|
501
|
+
await publishReasoning(event, acceptedGeneration);
|
|
502
|
+
};
|
|
503
|
+
const enqueue = deps.enqueue ?? ((next: () => Promise<void>) => tail.then(next));
|
|
504
|
+
tail = enqueue(task).catch((error) => {
|
|
505
|
+
deps.recordFailure?.("reasoning-send", event, error);
|
|
506
|
+
});
|
|
507
|
+
}, delayMs) as ReturnType<typeof setTimeout>;
|
|
508
|
+
reasoningFlushTimer?.unref?.();
|
|
509
|
+
};
|
|
469
510
|
const publishTool = async (
|
|
470
511
|
event: TelegramActivityEvent,
|
|
471
512
|
tool: ToolActivity,
|
|
@@ -602,13 +643,8 @@ export function createTelegramActivityVerbosityRuntime<TAuthority>(deps: {
|
|
|
602
643
|
reasoningBuffer = `${reasoningBuffer}${event.delta}`.slice(
|
|
603
644
|
-TELEGRAM_REASONING_BUFFER_MAX_CHARS,
|
|
604
645
|
);
|
|
605
|
-
if (reasoningMessageFrames < TELEGRAM_REASONING_MESSAGE_MAX_FRAMES
|
|
606
|
-
(
|
|
607
|
-
(getNowMs() - lastReasoningPublishMs >=
|
|
608
|
-
TELEGRAM_REASONING_MIN_INTERVAL_MS &&
|
|
609
|
-
reasoningChars - lastReasoningMessageChars >= 160))
|
|
610
|
-
) {
|
|
611
|
-
await publishReasoning(event, acceptedGeneration);
|
|
646
|
+
if (reasoningMessageFrames < TELEGRAM_REASONING_MESSAGE_MAX_FRAMES) {
|
|
647
|
+
scheduleReasoningPublish(event, acceptedGeneration);
|
|
612
648
|
}
|
|
613
649
|
return;
|
|
614
650
|
}
|
|
@@ -620,6 +656,7 @@ export function createTelegramActivityVerbosityRuntime<TAuthority>(deps: {
|
|
|
620
656
|
-TELEGRAM_REASONING_BUFFER_MAX_CHARS,
|
|
621
657
|
);
|
|
622
658
|
}
|
|
659
|
+
clearReasoningFlushTimer();
|
|
623
660
|
if (
|
|
624
661
|
reasoningChars > 0 &&
|
|
625
662
|
reasoningChars > lastReasoningMessageChars &&
|
|
@@ -687,8 +724,8 @@ export function createTelegramActivityVerbosityRuntime<TAuthority>(deps: {
|
|
|
687
724
|
return;
|
|
688
725
|
}
|
|
689
726
|
if (event.type === "agent-end" || event.type === "agent-settled") {
|
|
727
|
+
clearReasoningFlushTimer();
|
|
690
728
|
if (
|
|
691
|
-
reasoningMessage &&
|
|
692
729
|
reasoningChars > lastReasoningMessageChars &&
|
|
693
730
|
!reasoningBlocked
|
|
694
731
|
) {
|
|
@@ -2335,9 +2335,11 @@ async function handleTelegramCommandRuntime<
|
|
|
2335
2335
|
);
|
|
2336
2336
|
}
|
|
2337
2337
|
|
|
2338
|
-
export const
|
|
2339
|
-
export const
|
|
2340
|
-
"(internal)
|
|
2338
|
+
export const TELEGRAM_INTERNAL_COMMAND_NAME = "telegram-internal";
|
|
2339
|
+
export const TELEGRAM_INTERNAL_COMMAND_DESCRIPTION =
|
|
2340
|
+
"(internal) dispatch one settled Telegram lifecycle action";
|
|
2341
|
+
export const TELEGRAM_INTERNAL_MANUAL_USE_MESSAGE =
|
|
2342
|
+
"This internal Telegram command cannot be run manually.";
|
|
2341
2343
|
|
|
2342
2344
|
export function delayTelegramSessionAction(delayMs: number): Promise<void> {
|
|
2343
2345
|
return new Promise<void>((resolve) => setTimeout(resolve, delayMs));
|
|
@@ -2538,6 +2540,12 @@ export function createTelegramSessionActionAssembly(
|
|
|
2538
2540
|
return { action, settlement };
|
|
2539
2541
|
}
|
|
2540
2542
|
|
|
2543
|
+
type TelegramPendingInternalAction = {
|
|
2544
|
+
kind: "replace-session";
|
|
2545
|
+
updateId: number;
|
|
2546
|
+
target: { chatId: number; threadId?: number; messageId: number };
|
|
2547
|
+
};
|
|
2548
|
+
|
|
2541
2549
|
export interface TelegramSessionActionRuntime {
|
|
2542
2550
|
register: () => void;
|
|
2543
2551
|
scheduleAfterUpdate: (
|
|
@@ -2557,8 +2565,7 @@ export function createTelegramSessionActionRuntime(
|
|
|
2557
2565
|
threadId?: number;
|
|
2558
2566
|
messageId: number;
|
|
2559
2567
|
} | undefined;
|
|
2560
|
-
let
|
|
2561
|
-
let commandUpdateId: number | undefined;
|
|
2568
|
+
let pendingAction: TelegramPendingInternalAction | undefined;
|
|
2562
2569
|
let registered = false;
|
|
2563
2570
|
|
|
2564
2571
|
const reportFailure = (error: unknown): void => {
|
|
@@ -2573,29 +2580,32 @@ export function createTelegramSessionActionRuntime(
|
|
|
2573
2580
|
register() {
|
|
2574
2581
|
if (registered) return;
|
|
2575
2582
|
registered = true;
|
|
2576
|
-
deps.registerCommand(
|
|
2577
|
-
description:
|
|
2583
|
+
deps.registerCommand(TELEGRAM_INTERNAL_COMMAND_NAME, {
|
|
2584
|
+
description: TELEGRAM_INTERNAL_COMMAND_DESCRIPTION,
|
|
2578
2585
|
handler: async (_args, ctx) => {
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2586
|
+
const action = pendingAction;
|
|
2587
|
+
if (!action) {
|
|
2588
|
+
ctx.ui.notify(TELEGRAM_INTERNAL_MANUAL_USE_MESSAGE, "warning");
|
|
2589
|
+
return;
|
|
2590
|
+
}
|
|
2591
|
+
pendingAction = undefined;
|
|
2592
|
+
switch (action.kind) {
|
|
2593
|
+
case "replace-session":
|
|
2594
|
+
try {
|
|
2595
|
+
await deps.prepareReplacement?.(ctx, action.updateId, action.target);
|
|
2596
|
+
const result = await ctx.newSession();
|
|
2597
|
+
if (result.cancelled) await deps.notifyResult(action.target, "cancelled");
|
|
2598
|
+
} catch (error) {
|
|
2599
|
+
reportFailure(error);
|
|
2600
|
+
await deps.notifyResult(action.target, "failure");
|
|
2601
|
+
}
|
|
2602
|
+
return;
|
|
2593
2603
|
}
|
|
2594
2604
|
},
|
|
2595
2605
|
});
|
|
2596
2606
|
},
|
|
2597
2607
|
scheduleAfterUpdate(updateId, target) {
|
|
2598
|
-
if (pendingUpdateId !== undefined ||
|
|
2608
|
+
if (pendingUpdateId !== undefined || pendingAction !== undefined) return false;
|
|
2599
2609
|
pendingUpdateId = updateId;
|
|
2600
2610
|
pendingTarget = { ...target };
|
|
2601
2611
|
return true;
|
|
@@ -2603,23 +2613,23 @@ export function createTelegramSessionActionRuntime(
|
|
|
2603
2613
|
onUpdateCompleted(updateId) {
|
|
2604
2614
|
if (pendingUpdateId !== updateId) return;
|
|
2605
2615
|
pendingUpdateId = undefined;
|
|
2606
|
-
|
|
2607
|
-
|
|
2616
|
+
const target = pendingTarget;
|
|
2617
|
+
pendingTarget = undefined;
|
|
2618
|
+
if (!target) return;
|
|
2619
|
+
pendingAction = { kind: "replace-session", updateId, target };
|
|
2608
2620
|
void Promise.resolve()
|
|
2609
2621
|
.then(() =>
|
|
2610
|
-
deps.sendUserMessage(`/${
|
|
2622
|
+
deps.sendUserMessage(`/${TELEGRAM_INTERNAL_COMMAND_NAME}`, {
|
|
2611
2623
|
expandPromptTemplates: true,
|
|
2612
2624
|
}),
|
|
2613
2625
|
)
|
|
2614
2626
|
.catch((error) => {
|
|
2615
|
-
|
|
2616
|
-
commandUpdateId = undefined;
|
|
2617
|
-
pendingTarget = undefined;
|
|
2627
|
+
pendingAction = undefined;
|
|
2618
2628
|
reportFailure(error);
|
|
2619
2629
|
});
|
|
2620
2630
|
},
|
|
2621
2631
|
hasPending() {
|
|
2622
|
-
return pendingUpdateId !== undefined ||
|
|
2632
|
+
return pendingUpdateId !== undefined || pendingAction !== undefined;
|
|
2623
2633
|
},
|
|
2624
2634
|
};
|
|
2625
2635
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llblab/pi-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@llblab/pi-codex-usage": "0.10.0",
|
|
46
46
|
"@llblab/pi-grow-loop": "0.8.1",
|
|
47
47
|
"@llblab/pi-state-flow": "0.16.2",
|
|
48
|
-
"@llblab/pi-telegram": "0.
|
|
48
|
+
"@llblab/pi-telegram": "0.50.0",
|
|
49
49
|
"@llblab/skills": "1.15.0"
|
|
50
50
|
},
|
|
51
51
|
"bundledDependencies": [
|