@llblab/pi-telegram 0.46.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -2
- package/BACKLOG.md +0 -6
- package/CHANGELOG.md +14 -0
- package/README.md +5 -2
- package/dist/api/activity.d.ts +6 -0
- package/dist/api/activity.js +6 -0
- package/dist/api/commands.d.ts +6 -0
- package/dist/api/commands.js +6 -0
- package/dist/api/delivery.d.ts +6 -0
- package/dist/api/delivery.js +6 -0
- package/dist/api/inbound.d.ts +6 -0
- package/dist/api/inbound.js +6 -0
- package/dist/api/keyboard.d.ts +6 -0
- package/dist/api/keyboard.js +6 -0
- package/dist/api/outbound.d.ts +6 -0
- package/dist/api/outbound.js +6 -0
- package/dist/api/sections.d.ts +7 -0
- package/dist/api/sections.js +6 -0
- package/dist/api/status.d.ts +6 -0
- package/dist/api/status.js +6 -0
- package/dist/api/updates.d.ts +6 -0
- package/dist/api/updates.js +6 -0
- package/dist/api/voice.d.ts +6 -0
- package/dist/api/voice.js +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/lib/activity-verbosity.d.ts +52 -0
- package/dist/lib/activity-verbosity.js +596 -0
- package/dist/lib/activity.d.ts +220 -0
- package/dist/lib/activity.js +574 -0
- package/dist/lib/agent-messages.d.ts +28 -0
- package/dist/lib/agent-messages.js +86 -0
- package/dist/lib/bindings.d.ts +250 -0
- package/dist/lib/bindings.js +936 -0
- package/dist/lib/bus-api.d.ts +18 -0
- package/dist/lib/bus-api.js +254 -0
- package/dist/lib/bus-follower.d.ts +464 -0
- package/dist/lib/bus-follower.js +1686 -0
- package/dist/lib/bus-leader.d.ts +292 -0
- package/dist/lib/bus-leader.js +2242 -0
- package/dist/lib/bus-transport.d.ts +64 -0
- package/dist/lib/bus-transport.js +140 -0
- package/dist/lib/bus.d.ts +518 -0
- package/dist/lib/bus.js +2055 -0
- package/dist/lib/channel-posts.d.ts +170 -0
- package/dist/lib/channel-posts.js +611 -0
- package/dist/lib/command-templates.d.ts +70 -0
- package/dist/lib/command-templates.js +744 -0
- package/dist/lib/commands.d.ts +541 -0
- package/dist/lib/commands.js +1155 -0
- package/dist/lib/config.d.ts +252 -0
- package/dist/lib/config.js +889 -0
- package/dist/lib/delivery.d.ts +163 -0
- package/dist/lib/delivery.js +542 -0
- package/dist/lib/extension.d.ts +7 -0
- package/dist/lib/extension.js +1604 -0
- package/dist/lib/generative-app-worker.mjs +104 -0
- package/dist/lib/generative-apps.d.ts +212 -0
- package/dist/lib/generative-apps.js +1006 -0
- package/dist/lib/inbound.d.ts +91 -0
- package/dist/lib/inbound.js +502 -0
- package/dist/lib/journal.d.ts +665 -0
- package/dist/lib/journal.js +3701 -0
- package/dist/lib/keyboard.d.ts +23 -0
- package/dist/lib/keyboard.js +37 -0
- package/dist/lib/lifecycle.d.ts +157 -0
- package/dist/lib/lifecycle.js +395 -0
- package/dist/lib/locks.d.ts +164 -0
- package/dist/lib/locks.js +1208 -0
- package/dist/lib/logging.d.ts +50 -0
- package/dist/lib/logging.js +274 -0
- package/dist/lib/media.d.ts +181 -0
- package/dist/lib/media.js +602 -0
- package/dist/lib/menu-model.d.ts +217 -0
- package/dist/lib/menu-model.js +663 -0
- package/dist/lib/menu-queue.d.ts +37 -0
- package/dist/lib/menu-queue.js +408 -0
- package/dist/lib/menu-settings.d.ts +115 -0
- package/dist/lib/menu-settings.js +595 -0
- package/dist/lib/menu-status.d.ts +32 -0
- package/dist/lib/menu-status.js +112 -0
- package/dist/lib/menu-thinking.d.ts +29 -0
- package/dist/lib/menu-thinking.js +82 -0
- package/dist/lib/menu.d.ts +171 -0
- package/dist/lib/menu.js +323 -0
- package/dist/lib/model.d.ts +127 -0
- package/dist/lib/model.js +409 -0
- package/dist/lib/outbound-attachments.d.ts +241 -0
- package/dist/lib/outbound-attachments.js +639 -0
- package/dist/lib/outbound-buttons.d.ts +69 -0
- package/dist/lib/outbound-buttons.js +248 -0
- package/dist/lib/outbound-markup.d.ts +42 -0
- package/dist/lib/outbound-markup.js +678 -0
- package/dist/lib/outbound-voice.d.ts +55 -0
- package/dist/lib/outbound-voice.js +152 -0
- package/dist/lib/outbound.d.ts +185 -0
- package/dist/lib/outbound.js +516 -0
- package/dist/lib/ownership.d.ts +77 -0
- package/dist/lib/ownership.js +174 -0
- package/dist/lib/paths.d.ts +40 -0
- package/dist/lib/paths.js +94 -0
- package/dist/lib/pi.d.ts +72 -0
- package/dist/lib/pi.js +121 -0
- package/dist/lib/polling.d.ts +351 -0
- package/dist/lib/polling.js +1196 -0
- package/dist/lib/preview.d.ts +192 -0
- package/dist/lib/preview.js +614 -0
- package/dist/lib/prompt-templates.d.ts +24 -0
- package/dist/lib/prompt-templates.js +118 -0
- package/dist/lib/prompts.d.ts +57 -0
- package/dist/lib/prompts.js +167 -0
- package/dist/lib/queue.d.ts +766 -0
- package/dist/lib/queue.js +1965 -0
- package/dist/lib/recovery.d.ts +86 -0
- package/dist/lib/recovery.js +285 -0
- package/dist/lib/rendering.d.ts +20 -0
- package/dist/lib/rendering.js +983 -0
- package/dist/lib/replies.d.ts +214 -0
- package/dist/lib/replies.js +737 -0
- package/dist/lib/routing.d.ts +207 -0
- package/dist/lib/routing.js +2282 -0
- package/dist/lib/runtime.d.ts +172 -0
- package/dist/lib/runtime.js +402 -0
- package/dist/lib/sections.d.ts +165 -0
- package/dist/lib/sections.js +327 -0
- package/dist/lib/setup.d.ts +82 -0
- package/dist/lib/setup.js +150 -0
- package/dist/lib/skills.d.ts +8 -0
- package/dist/lib/skills.js +12 -0
- package/dist/lib/status.d.ts +442 -0
- package/dist/lib/status.js +1008 -0
- package/dist/lib/sync.d.ts +179 -0
- package/dist/lib/sync.js +782 -0
- package/dist/lib/target.d.ts +20 -0
- package/dist/lib/target.js +27 -0
- package/dist/lib/telegram-api.d.ts +541 -0
- package/dist/lib/telegram-api.js +1159 -0
- package/dist/lib/text-groups.d.ts +89 -0
- package/dist/lib/text-groups.js +317 -0
- package/dist/lib/thread-cleanup-manager.d.ts +288 -0
- package/dist/lib/thread-cleanup-manager.js +560 -0
- package/dist/lib/thread-display.d.ts +46 -0
- package/dist/lib/thread-display.js +257 -0
- package/dist/lib/thread-naming.d.ts +46 -0
- package/dist/lib/thread-naming.js +78 -0
- package/dist/lib/thread-reconciler.d.ts +239 -0
- package/dist/lib/thread-reconciler.js +644 -0
- package/dist/lib/threads.d.ts +621 -0
- package/dist/lib/threads.js +3679 -0
- package/dist/lib/time-injection.d.ts +15 -0
- package/dist/lib/time-injection.js +56 -0
- package/dist/lib/turns.d.ts +109 -0
- package/dist/lib/turns.js +500 -0
- package/dist/lib/updates.d.ts +1290 -0
- package/dist/lib/updates.js +3634 -0
- package/dist/lib/voice.d.ts +117 -0
- package/dist/lib/voice.js +174 -0
- package/dist/lib/workspace-admission.d.ts +264 -0
- package/dist/lib/workspace-admission.js +1136 -0
- package/dist/lib/workspace-retirement.d.ts +219 -0
- package/dist/lib/workspace-retirement.js +587 -0
- package/dist/lib/workspace-slots.d.ts +30 -0
- package/dist/lib/workspace-slots.js +54 -0
- package/dist/package.json +126 -0
- package/dist/pi-telegram/index.js +1 -0
- package/dist/skills/generated-control-surface/SKILL.md +107 -0
- package/dist/skills/generated-control-surface/references/capability-adapters.md +27 -0
- package/dist/skills/generated-control-surface/references/layout-and-state.md +37 -0
- package/dist/skills/generative-apps/SKILL.md +115 -0
- package/dist/skills/show-me/SKILL.md +166 -0
- package/dist/skills/show-me/references/telegram-surfaces.md +43 -0
- package/dist/skills/telegram-bridge/SKILL.md +129 -0
- package/dist/skills/telegram-bridge/references/configuration.md +15 -0
- package/dist/skills/telegram-bridge/references/delivery-and-threads.md +27 -0
- package/dist/skills/telegram-bridge/references/diagnosis.md +18 -0
- package/docs/README.md +2 -0
- package/docs/architecture.md +1 -1
- package/docs/compact-matrix-literal.md +10 -3
- package/docs/generative-apps.md +15 -13
- package/docs/multi-instance-bus.md +6 -4
- package/docs/outbound.md +1 -1
- package/docs/public-api.md +3 -3
- package/lib/bindings.ts +89 -6
- package/lib/bus-follower.ts +7 -3
- package/lib/bus-leader.ts +44 -19
- package/lib/bus.ts +4 -1
- package/lib/commands.ts +2 -2
- package/lib/config.ts +14 -7
- package/lib/delivery.ts +38 -6
- package/lib/extension.ts +7 -0
- package/lib/generative-apps.ts +379 -13
- package/lib/menu-settings.ts +20 -6
- package/lib/outbound-markup.ts +16 -7
- package/lib/status.ts +15 -12
- package/lib/telegram-api.ts +12 -1
- package/lib/thread-display.ts +96 -18
- package/package.json +56 -13
- package/scripts/build-dist.mjs +44 -0
- package/scripts/measure-bus.mjs +8 -1
- package/scripts/measure-workspace.mjs +8 -1
- package/skills/generative-apps/SKILL.md +1 -1
- package/skills/show-me/SKILL.md +1 -1
- package/skills/show-me/references/telegram-surfaces.md +1 -1
- package/skills/telegram-bridge/SKILL.md +1 -1
package/AGENTS.md
CHANGED
|
@@ -38,7 +38,7 @@ Keep each fact in one authoritative layer:
|
|
|
38
38
|
|
|
39
39
|
## 3. Repository Topology And Local Skills
|
|
40
40
|
|
|
41
|
-
- `/index.ts`: Thin
|
|
41
|
+
- `/index.ts`: Thin source entrypoint re-exporting the default extension. The installed/runtime entrypoint is generated under `/dist/pi-telegram`; after every project change, run `npm run build` before reload, restart, or live verification so Pi does not execute stale compiled output.
|
|
42
42
|
- `/lib/extension.ts`: Sole extension composition root.
|
|
43
43
|
- `/api/*.ts`: Stable public package membranes documented in `docs/public-api.md`.
|
|
44
44
|
- `/lib/*.ts`: Flat, cohesive runtime domains; package-private unless re-exported through `/api`.
|
|
@@ -99,7 +99,7 @@ Use the relevant local skill before non-trivial work in its domain. Keep skill o
|
|
|
99
99
|
- `preview` owns streaming lifecycle only, not assistant rendering. Finalization waits for active preview flushes and must not issue pre/post-final draft-clear calls that create transient Telegram draft UI. Turns that already answer as one atomic reply (voice replies, Guest Mode queries) never stream previews.
|
|
100
100
|
- Native `sendChatAction(typing)` is the automatic activity signal for unsettled agent and compaction work while Telegram transport is authorized. Extension-owned blocking UI prompts pause it and completion resumes it while either work owner remains active. Do not invent extra in-chat work indicators or emit activity for startup/connect/reload/recovery alone.
|
|
101
101
|
- Public activity handlers and connected companion delivery are asynchronous, target-bound, generation-fenced surfaces. Connected companion projection has no independent opt-out: disconnect or authority loss is its boundary. Token deltas, hidden reasoning, unknown sources, and stale authority never enter public projection.
|
|
102
|
-
- Thread display defaults to the profile-scoped Letters strategy, with Names and
|
|
102
|
+
- Thread display defaults to the profile-scoped Letters strategy, with Names, Directory Snake, and Directory Title as the other automatic choices; Names projects the generated dictionary name for the slot. Unsupported retained display keys resolve to Letters without rewriting persisted configuration. A durable manual Thread display name retained on its Workspace binding overrides any automatic projection until exact reset; keep generated/recovery identity separate from manual and acknowledged display fields. UI labels, emoji semantics, navigation, settings controls, callback namespaces, voice behavior, command templates, and assistant markup follow the linked `/docs` contracts. Generated human-readable prompt-button labels use `emoji + space + text`; emoji-free text is only a reasoned no-semantic-marker fallback. Non-spatial generated controls default to top-level vertical cells, with nested rows reserved for unmistakably compact peers. Do not restate other evolving UI details here.
|
|
103
103
|
|
|
104
104
|
## 5. Domain Ownership Index
|
|
105
105
|
|
|
@@ -148,12 +148,14 @@ Before non-trivial work:
|
|
|
148
148
|
While working:
|
|
149
149
|
|
|
150
150
|
- Keep changes inside this repository; updating an installed Pi checkout is a separate operator action.
|
|
151
|
+
- Rebuild the package with `npm run build` after edits. Pi loads `dist/pi-telegram/index.js`, so source-only changes are not live and `/reload` or process restart alone will reload stale compiled output.
|
|
151
152
|
- Read large artifacts search-first and range-bounded. For `CHANGELOG.md`, inspect only the current release section unless older history is relevant.
|
|
152
153
|
- Keep successful validation output compact; inspect focused failure tails. Prefer focused tests/typecheck during iteration and broad validation at a stable gate.
|
|
153
154
|
- Preserve unrelated work and do not commit, publish, tag, deploy, or perform external actions without explicit authorization.
|
|
154
155
|
|
|
155
156
|
Before completion:
|
|
156
157
|
|
|
158
|
+
- Run `npm run build` after the final edit and before any `/reload`, restart, live check, or handoff; never report a source change as live while `/dist` is stale.
|
|
157
159
|
- Run the smallest decisive validation for the affected closure. Queue/rendering/lifecycle changes normally require `npm run typecheck` and `npm test` at the stable gate.
|
|
158
160
|
- For Domain DAG changes, run `SKILL_DIR=.agents/skills/domain-dag bash .agents/skills/domain-dag/scripts/validate-domain-dag.sh --root .`.
|
|
159
161
|
- Keep strict unused-local/parameter checking. Validate queue dispatch around abort, compaction, pending dispatch, and Pi pending-message guards; validate rendering around literal code, nesting, and long-message chunks.
|
package/BACKLOG.md
CHANGED
|
@@ -2,11 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
_This file owns unresolved project work only. Completed behavior belongs in `CHANGELOG.md`; durable contracts belong in `AGENTS.md` and `/docs`._
|
|
4
4
|
|
|
5
|
-
- [ ] `Session-aware Thread binding` (`next minor`, primary outcome): Replace profile-scoped exact-`cwd` reuse as the sole Workspace identity with a durable composite of normalized exact `cwd` and Pi's stable public session identity. `/telegram-connect` must persist that session-to-Thread binding so reopening, resuming, or continuing the same Pi session automatically restores the same Telegram Thread and letter slot when the retained binding has not been validly displaced. Different sessions in one directory must receive distinct live slots, while the same session must not allocate a duplicate after process restart. Session number/name are bounded lookup or presentation aliases only, never routing authority. Preserve authenticated live-owner, accepted-work, displacement, retirement, and slot-pressure fences. This is the principal deliverable of the next minor release.
|
|
6
|
-
- [x] `Identity and migration contract`: [`docs/multi-instance-bus.md`](./docs/multi-instance-bus.md#approved-next-contract-session-aware-workspace-identity) now fixes the public session source, composite authority, binding-key derivation, lifecycle semantics, exact legacy `{ cwd, ∅ }` coexistence, fail-closed malformed present identity behavior, mixed-version fence, and non-ownership boundaries.
|
|
7
|
-
- [x] `Store and allocation foundation`: Session-qualified identity, persistence, independent same-cwd claims/slots, strict digest validation, cleanup and retirement snapshots, and exact legacy cwd-only coexistence are locally implemented. The former staged-adoption claim state and commit exceptions have been removed, so no latent mutation path can consume a cwd-only binding. Absence of session identity remains its own key across reload and stale status persistence; same-session restore retains its letter while another session cannot reuse it.
|
|
8
|
-
- [x] `Leader/follower lifecycle wiring`: Leader assembly now reads public `ctx.sessionManager.getSessionId()`, passes it through sync provisioning, and restores the matching session-qualified Workspace without creating a duplicate Thread; cwd-only legacy state remains an independent `{ cwd, ∅ }` identity and is never exposed through a session lookup. Authenticated follower registration now carries a strict bounded session ID over the bus, preserves it in the live registry, and passes it into leader-owned provisioning; fresh same-cwd follower sessions therefore commit distinct session-qualified bindings. Production follower assembly sources the value from the current Pi context, independently of process instance and session generation. Follower-to-leader promotion now resolves the exact current session binding and preserves its target, slot, generated name, and acknowledged display title through leader handoff. Startup restore and `/telegram-connect` share the session-bearing registration envelope and leader provisioner. Protocol v2 makes session identity mandatory for every cwd-scoped participant and rejects protocol-v1 0.45.x peers before provisioning; the supported upgrade path stops all instances, updates them together, then starts a fresh session-native leader. Session-aware stale-target replacement is now regression-covered: replacing session A updates only A's binding and leaves same-cwd session B untouched. Capability rejection is covered independently from the older durable-admission gate. Startup restore eligibility now checks the current session exactly and never treats a legacy cwd-only binding as that session, so neither a sibling nor `{ cwd, ∅ }` can make a fresh session auto-connect. Explicit `/telegram-connect`, restore-only registration, and reconnect handoff all use the same session-bearing registration runtime; focused tests cover restore-only and handoff transmission. The production integration harness now supplies a distinct stable `sessionManager.getSessionId()` per mocked context, and the lifecycle/cleanup integration regression passes with session-aware leader provisioning. Legacy `{ cwd, ∅ }` records remain readable but inert and independent: they are never adopted, migrated, or used for a v2 session. Full-suite closure is green: the bundled Show Me wording is compressed within its disclosure budget, integration contexts preserve one session manager across idle/active phases, and the complete test command passes.
|
|
9
|
-
- [ ] `Compatibility and acceptance` (`local-actionable` plus live gate, current): Exact lookup now treats both presence and absence of session ID symmetrically: `{ cwd, ∅ }` cannot match a session binding, and `{ cwd, session }` cannot match legacy. Focused store, follower, leader, and polling suites pass across coexistence, restore-only, same-session process replacement, follower reload/handoff, distinct same-cwd session allocation (the `/fork`/`/new` identity effect), promotion, session-isolated rename, stale-target replacement, malformed identity, and rolling-upgrade capability behavior. Full slot-pressure retirement now selects the oldest eligible exact binding across legacy and session-qualified identities and persists the victim's session component; protection and exact-intent fences remain unchanged. The Pi adapter now has explicit evidence that restart/reload/resume/continue-recent aliases do not influence authority: only the public stable session ID is read, while a forked ID remains distinct. Local acceptance is complete: generation-fenced stale ownership cannot mutate a replacement; target displacement is exact-session isolated; strict legacy and session-qualified snapshots coexist without aliasing or stale resurrection; protocol-v1 peers are explicitly rejected, while all protocol-v2 cwd participants use session-qualified identity. Update the current-contract docs only with locally validated behavior. Remaining gate: a separately operator-authorized live smoke for same-session restoration and two concurrent sessions in one directory.
|
|
10
5
|
- [ ] `Prompt enqueue hotfix` (`optional`, `operator-gated`): Optional nonblocking operator-authorized disposable-follower smoke: overlap delayed voice processing with turn completion and confirm one-time ordered consumption and truthful counts against the [queue contract](./docs/architecture.md#queue-and-dispatch-safety). Separately authorized supported recovery investigation remains open: prevention does not repair an already-wedged in-memory queue; establish the exact recovery path and preservation/discard consequences before mutation, otherwise report the blocker. No journal/ownership edits, replay of settled input, implicit queue clearing, or restart; live activation requires separate operator authorization.
|
|
11
6
|
- [ ] `Channel multimedia posts` (`0.45.1`, live-acceptance-gated): `telegram_message` channel delivery accepts one local `.jpg`/`.jpeg`/`.png`/`.webp` photo or `.mp4` video, uploads it through the multipart transport as `sendPhoto`/`sendVideo` with `text` as the HTML caption, validates kind and size (photo ≤ 10 MiB, video ≤ 50 MiB) plus ≤ 1024 visible caption characters before issuance, and rejects unsupported types and albums instead of downgrading them to links. The channel-post journal binds kind/file name/byte size/SHA-256 and caption, so duplicate requests and lost acknowledgements never re-upload; media-post edits replace the caption through `editMessageCaption`, and Markdown spoilers render as `<tg-spoiler>`. Live image publication passed on `@llb_log`. Regressions cover confirmed publication, duplicate requests, lost ACK, pre-issuance rejection, caption edits, and reconnect replacement. Remaining: operator-authorized disposable-channel acceptance of rejected upload, duplicate request, and caption edit.
|
|
12
7
|
- [ ] `Manual Thread naming` (`gated-but-preparable`, release priority): Local bot-owned `/name Name` and bare `/name` flows avoid model dispatch. One expiring exact-target input dialog immediately accepts the next valid name, always offers cancel, and offers **Reset to automatic** only while a manual override exists; duplicate/stale callbacks cannot repeat mutation. Durable manual override supersedes every automatic display mode, reset is leader/follower generation- and target-fenced, and Letters remains the default without rewriting recovery identity. Local review findings are remediated, including Bot-API-wait target-replacement regressions for leader/follower rename and reset. Remaining: disposable live acceptance for command-menu ordering, dialog, invalid input, duplicate callbacks, leader/follower rename and reset.
|
|
@@ -37,5 +32,4 @@ _This file owns unresolved project work only. Completed behavior belongs in `CHA
|
|
|
37
32
|
- [ ] Harden the implemented pre-queue `app::method` / strict-JSON bound-action route with revision capture for agent-mediated initial surfaces, profile/target authority, follower transport evidence, voice output delivery, and commit-unknown diagnostics while preserving generation-plus-revision stale-click rejection, fail-closed malformed/absent methods, ordinary model prompts, and native single-colon callbacks.
|
|
38
33
|
- [ ] Harden the implemented cross-process transition lock, dead-owner recovery, expected-generation/revision comparison, repaired partial-tail/current-state recovery, transactional `init` reset, and output-only methods with process-birth proof, bounded lock diagnostics, more interruption points, and explicit commit-unknown evidence.
|
|
39
34
|
- [ ] Complete the capability-owned Music Player adapter evidence beyond the successful real `ffplay` singleton install and no-model-turn bound `next`, `pause`, resume/`play`, and terminal `stop` Controls: exercise generated relative-volume controls over arbitrary absolute Actor percentages, `toggle`, `previous`, `status`, compatible singleton reuse, checkpoint restart, missing/terminal Run, unavailable backend, process timeout/cancellation/stream bounds, and redacted errors while keeping actor reality authoritative and rejecting generic remote-terminal methods.
|
|
40
|
-
- [ ] Extend the implemented new-message default plus opt-in `viewMode: "edit"` bound-action update into optional output-only `refresh` scheduling from `refreshAfterMs`, clamped to at least two seconds and serialized after prior completion; retain one latest logical view handle per app/profile/target, skip unchanged frame digests, honor Telegram retry/backoff, cancel on lifecycle replacement, stop and forget the handle on known deletion or message-not-found, and never recreate a deleted live view without a fresh user action.
|
|
41
35
|
- [ ] Cover CML and JSON equivalence, both mutually exclusive Tool shapes, direct agent-authored app discovery, install/copy and existing-app `init`, scalar/object/no-argument methods, agent-side diagnostic invocation, bounded CLI adaptation, refresh coalescing/rate limits/backoff/deletion, identity/path traversal, duplicate/overlapping prefixes, state recovery, handler failure, stale clicks, session replacement, follower routing, and the invariant that bound actions perform no model turn. `tests/generative-apps.test.ts` now covers scalar/object/no-argument argument shapes, throwing-method failure containment (state and journal untouched), and bounded argument/output/state/module limits before durable mutation; the remaining items stay open.
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.48.0: Unified activity and Thread display
|
|
8
|
+
|
|
9
|
+
- `Unified activity`: The terminal keeps its stable `connected`, `leader`, or `follower` identity while work runs. Active work uses the same green Queue count as queued items, while Telegram typing projects every agent run—including local or autonomous work—into the assigned Thread and aggregate `All` target.
|
|
10
|
+
- `Thread display`: Settings now present the exact profile configuration values `letters`, `names`, `directory-title`, and `directory-snake`, place title case first, and omit the redundant live-preview block. Concurrent `directory-title` slot suffixes use one plain space instead of a middle-dot separator.
|
|
11
|
+
- `Session-aware Thread binding`: Operator live smoke confirmed same-session restoration and distinct concurrent sessions in one directory without duplicate Threads or letter slots, completing the remaining acceptance gate.
|
|
12
|
+
|
|
13
|
+
## 0.47.0: Built runtime and live surfaces
|
|
14
|
+
|
|
15
|
+
- `Startup`: npm installs now load a compiled JavaScript extension from a nested `dist/pi-telegram` entrypoint while source checkouts retain `index.ts`. Stable public subpath exports ship compiled JavaScript plus declarations, packaged Skills follow the distributive root, and validation checks the built extension import.
|
|
16
|
+
- `Button authoring`: Native `telegram_button` fences now accept adjacent top-level JSON/CML objects without an outer array or commas as vertical singleton rows. Explicit outer matrices remain equivalent, nested arrays still own horizontal layout, and malformed sequences activate no controls.
|
|
17
|
+
- `Activity`: Native typing remains continuously re-armed during agent/message work, pauses only for local UI prompts, resumes for unsettled agent or compaction work, and retargets queued turns without leaking keepalive ticks across Threads; transport and session fences still suppress stale actions.
|
|
18
|
+
- `Live views`: Validated `refreshAfterMs` drives non-overlapping timers after hinted `telegram_bind` delivery. Refreshes and current-surface actions edit one generation-fenced Delivery handle through the Markdown/button planner across classic, leader, and follower targets; hints reschedule and omission closes. Retryable failures retain one frame; unavailable messages invalidate with a bounded diagnostic. Take, shutdown, and replacement fence late refreshes and cancel memory-only surfaces.
|
|
19
|
+
- `Thread display`: Adds `directory-snake` and `directory-title` with Unicode-aware path tokenization, uppercase-abbreviation preservation, live previews, title projection, and peer capability fencing. Slot suffixes now follow authenticated concurrent same-directory ownership; dormant bindings and sticky legacy metadata are ignored. The retired `directories` key resolves to Letters and is omitted from Settings, leaving exactly Letters, Names, Directory Snake, and Directory Title.
|
|
20
|
+
|
|
7
21
|
## 0.46.0: Session-aware Workspace Threads
|
|
8
22
|
|
|
9
23
|
- `Session-aware Thread binding`: Workspace identity restored session-qualified bindings from Pi's stable public session identity, so reopening, resuming, or replacing a process reclaims the same Telegram Thread and letter while distinct sessions in one directory keep independent targets. Strict legacy cwd-only records remain inert and coexist safely; protocol v2 rejects mixed 0.45.x peers before provisioning, and exact-session cleanup, displacement, rename, promotion, and slot-pressure fences are preserved.
|
package/README.md
CHANGED
|
@@ -226,7 +226,7 @@ Voice notes, audio, images, PDFs, and other media can pass through configured in
|
|
|
226
226
|
|
|
227
227
|
### Buttons And Callbacks
|
|
228
228
|
|
|
229
|
-
Assistant replies can place controls between paragraphs using standalone triple-backtick `telegram_button` blocks, or keep them in the footer using top-level hidden `telegram_button` comments. Both wrappers accept singleton cells and mixed JSON/CML matrices. Native in-body rows allow up to eight buttons; HTML compatibility moves these rows to the footer. In-body clicks acknowledge without recoloring the Rich body, while footer selection styles remain unchanged. Hidden comments accept a JSON object, adaptive JSON/CML matrix, or positional Compact Matrix Literal (CML). One adaptive matrix may mix named JSON objects with positional CML cells; separators are optional and one trailing comma is tolerated, including inside JSON objects. Top-level cells become full-width rows while nested rows group one or more buttons horizontally without an artificial parser-level width cap;
|
|
229
|
+
Assistant replies can place controls between paragraphs using standalone triple-backtick `telegram_button` blocks, or keep them in the footer using top-level hidden `telegram_button` comments. Both wrappers accept singleton cells and mixed JSON/CML matrices. Native in-body rows allow up to eight buttons; HTML compatibility moves these rows to the footer. In-body clicks acknowledge without recoloring the Rich body, while footer selection styles remain unchanged. Hidden comments accept a JSON object, adaptive JSON/CML matrix, or positional Compact Matrix Literal (CML). One adaptive matrix may mix named JSON objects with positional CML cells; separators are optional and one trailing comma is tolerated, including inside JSON objects. Top-level cells become full-width rows while nested rows group one or more buttons horizontally without an artificial parser-level width cap; inside a fenced block, adjacent top-level JSON/CML objects may omit the outer array and commas. Generated surfaces default to five columns and use six to eight only for short position-bearing labels. CML uses `{value}`, `{label|prompt}`, `{|prompt}`, or the corresponding three-atom form with `selected_style` set to `primary`, `success`, or `danger`; omitting the first atom leaves the existing prompt-as-label fallback in charge, while the optional style still requires a non-empty prompt. A fourth atom adds disabled state: `{|Next||1}` or `{|Next||true}` disables, `0` or `false` enables (exact lowercase), and omission stays enabled; the third atom may be empty in this form. JSON uses boolean `disabled`. Disabled controls require no prompt or selected style: `{Next|||1}` shows only a label, while `{|||1}` is a blank disabled cell. Disabled controls remain visible without registering callbacks or invoking prompts/app methods. It trims atom boundaries, preserves non-structural text literally, and decodes only `\|`, `\}`, and `\\`. Prefer one matrix comment for multiple buttons. Buttons use `label` plus `prompt`, or the compact `value` key when both are identical. The bridge strips every assistant-authored HTML comment from Telegram previews and final replies regardless of Markdown position or owning extension, while only recognized top-level comments activate buttons or voice; comment-only output sends no text message and the Pi terminal transcript remains unchanged. It renders valid inline buttons and routes callbacks back into Pi as queued prompts or extension-owned callback actions. Button-only replies receive the standard `☑️ **Choose an option:**` heading as automatic visible fallback text. Once a generated prompt button is accepted, only that exact button switches to its optional `selected_style` (`primary` blue by default, `success` green, or `danger` red) without altering its agent-authored label or emoji; every style still queues the selected prompt.
|
|
230
230
|
|
|
231
231
|
### Threaded Mode And Multi-Instance Bus
|
|
232
232
|
|
|
@@ -240,7 +240,7 @@ Classic private DM mode is the base product mode. When Telegram private-chat Thr
|
|
|
240
240
|
- Unknown threads are preserved and offered explicit reroute/restore choices.
|
|
241
241
|
- Telegram never launches hidden Pi processes.
|
|
242
242
|
|
|
243
|
-
In Threaded Mode, open Settings → **🧵 Thread display** to choose
|
|
243
|
+
In Threaded Mode, open Settings → **🧵 Thread display** to choose `letters` (default), `names`, `directory-title`, or `directory-snake` for this bot profile; a retained **directories** value remains available as an unchanged legacy presentation. Fresh tabs are created with the active mode's title instead of being visibly renamed afterward. Telegram tab titles, Pi terminal status, live Thread choosers/notices, prompt attribution, and named `telegram_message` targeting use the same acknowledged display name; target IDs and live registrations still own routing. Names shows the generated dictionary name chosen for the slot, such as `Anchor` for slot `A`; the directory formats produce `api_tools` or `Api Tools` and append `_a` or ` A` only while two or more authenticated live instances share that exact directory. Dormant retained bindings do not keep those suffixes visible. `/name` sets a manual Thread display name; **Reset to automatic** restores the selected automatic projection. Switching preserves Thread IDs, slots, generated recovery identity, and queue ownership. Partial application reports an error and can be retried without recreating Threads.
|
|
244
244
|
|
|
245
245
|
| Mode | Best for | Runtime shape |
|
|
246
246
|
| --- | --- | --- |
|
|
@@ -316,7 +316,10 @@ The docs index lives at [docs/README.md](./docs/README.md).
|
|
|
316
316
|
|
|
317
317
|
## Development
|
|
318
318
|
|
|
319
|
+
Pi loads the compiled `dist/pi-telegram/index.js` entrypoint. After every project change, run `npm run build` before `/reload`, restart, or live verification; reloading source without rebuilding can leave the running extension on stale compiled code.
|
|
320
|
+
|
|
319
321
|
```bash
|
|
322
|
+
npm run build
|
|
320
323
|
npm run typecheck
|
|
321
324
|
npm test
|
|
322
325
|
npm run audit
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram activity API
|
|
3
|
+
* Zones: package boundary, pi agent lifecycle, extension interop
|
|
4
|
+
* Exposes normalized non-blocking activity registration while keeping lifecycle wiring and dispatch internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { registerTelegramActivityHandler, type TelegramActivityContext, type TelegramActivityEnvelope, type TelegramActivityEvent, type TelegramActivityHandlerRegistration, type TelegramActivitySource, type TelegramActivityTarget, } from "../lib/activity.ts";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram activity API
|
|
3
|
+
* Zones: package boundary, pi agent lifecycle, extension interop
|
|
4
|
+
* Exposes normalized non-blocking activity registration while keeping lifecycle wiring and dispatch internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { registerTelegramActivityHandler, } from "../lib/activity.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram commands API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes the stable Telegram slash-command registration surface while keeping registry internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { registerTelegramCommand, type TelegramExtensionCommandContext, type TelegramExtensionCommandRegistration, } from "../lib/commands.ts";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram delivery API
|
|
3
|
+
* Zones: package boundary, telegram delivery, extension interop
|
|
4
|
+
* Exposes target-aware operational view delivery while keeping transport and runtime binding internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { deleteTelegramView, editTelegramView, sendTelegramChatAction, sendTelegramView, type SendTelegramViewOptions, type TelegramDeliveryChatAction, type TelegramDeliveryFailureReason, type TelegramDeliveryHandle, type TelegramDeliveryParseMode, type TelegramDeliveryResult, type TelegramDeliveryScope, type TelegramDeliveryTarget, type TelegramDeliveryView, } from "../lib/delivery.ts";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram delivery API
|
|
3
|
+
* Zones: package boundary, telegram delivery, extension interop
|
|
4
|
+
* Exposes target-aware operational view delivery while keeping transport and runtime binding internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { deleteTelegramView, editTelegramView, sendTelegramChatAction, sendTelegramView, } from "../lib/delivery.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram inbound API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes the stable programmatic inbound handler surface while keeping handler runtime internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { registerTelegramInboundHandler, type TelegramInboundHandlerFile, type TelegramInboundHandlerOutput, type TelegramInboundProgrammaticHandler, type TelegramInboundProgrammaticHandlerInput, type TelegramInboundProgrammaticHandlerResult, } from "../lib/inbound.ts";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram inbound API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes the stable programmatic inbound handler surface while keeping handler runtime internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { registerTelegramInboundHandler, } from "../lib/inbound.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram keyboard API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes shared inline-keyboard structural types without runtime exports
|
|
5
|
+
*/
|
|
6
|
+
export type { TelegramInlineKeyboardButton, TelegramInlineKeyboardButtonStyle, TelegramInlineKeyboardMarkup, } from "../lib/keyboard.ts";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram outbound API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes stable outbound handler and diagnostics surfaces while keeping delivery internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { recordTelegramRuntimeEvent, registerTelegramOutboundHandler, type TelegramOutboundProgrammaticHandler, } from "../lib/outbound.ts";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram outbound API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes stable outbound handler and diagnostics surfaces while keeping delivery internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { recordTelegramRuntimeEvent, registerTelegramOutboundHandler, } from "../lib/outbound.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram sections API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes the stable managed Telegram menu-section surface while keeping registry internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export type { TelegramInputRichBlock, TelegramInputRichMessage, TelegramRichText } from "../lib/telegram-api.ts";
|
|
7
|
+
export { getTelegramSectionDiagnostics, registerTelegramSection, type TelegramSectionCallbackContext, type TelegramSectionCallbackResult, type TelegramSectionContext, type TelegramSectionDiagnostic, type TelegramSectionRegistration, type TelegramSectionSettingsRegistration, type TelegramSectionView, } from "../lib/sections.ts";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram sections API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes the stable managed Telegram menu-section surface while keeping registry internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { getTelegramSectionDiagnostics, registerTelegramSection, } from "../lib/sections.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram status API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes compact status-menu line registration for extension consumers while keeping status rendering internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { registerTelegramStatusLineProvider, type TelegramStatusLineProvider, type TelegramStatusLineProviderContext, type TelegramStatusLineProviderResult, } from "../lib/status.ts";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram status API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes compact status-menu line registration for extension consumers while keeping status rendering internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { registerTelegramStatusLineProvider, } from "../lib/status.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram updates API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes the stable raw-update handler surface while keeping update routing internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { assertTelegramUpdateExecutionCurrent, carryTelegramUpdateExecutionFence, createTelegramUpdateExecutionFenceGuard, getTelegramUpdateExecutionFence, registerTelegramUpdateHandler, type TelegramUpdateExecutionFence, type TelegramUpdateHandler, type TelegramUpdateHandlerVerdict, } from "../lib/updates.ts";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram updates API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes the stable raw-update handler surface while keeping update routing internals package-private
|
|
5
|
+
*/
|
|
6
|
+
export { assertTelegramUpdateExecutionCurrent, carryTelegramUpdateExecutionFence, createTelegramUpdateExecutionFenceGuard, getTelegramUpdateExecutionFence, registerTelegramUpdateHandler, } from "../lib/updates.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram voice API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes the stable STT/TTS provider surface and voice policy helpers
|
|
5
|
+
*/
|
|
6
|
+
export { TELEGRAM_VOICE_REPLY_MODES, computeVoicePromptContribution, computeVoiceTurnFlags, getTelegramVoiceReplyMode, isVoiceTurn, registerTelegramVoiceSynthesisProvider, registerTelegramVoiceTranscriptionProvider, shouldSuppressPreviewForVoice, type TelegramVoiceReplyMode, type TelegramVoiceSynthesisProvider, type TelegramVoiceSynthesisProviderResult, type TelegramVoiceTranscriptionFile, type TelegramVoiceTranscriptionProvider, type TelegramVoiceTranscriptionProviderResult, type TelegramVoiceTurnView, } from "../lib/voice.ts";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Telegram voice API
|
|
3
|
+
* Zones: package boundary, extension interop
|
|
4
|
+
* Exposes the stable STT/TTS provider surface and voice policy helpers
|
|
5
|
+
*/
|
|
6
|
+
export { TELEGRAM_VOICE_REPLY_MODES, computeVoicePromptContribution, computeVoiceTurnFlags, getTelegramVoiceReplyMode, isVoiceTurn, registerTelegramVoiceSynthesisProvider, registerTelegramVoiceTranscriptionProvider, shouldSuppressPreviewForVoice, } from "../lib/voice.js";
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge-owned Telegram activity verbosity projection
|
|
3
|
+
* Zones: telegram activity, rich rendering, operational delivery
|
|
4
|
+
* Owns persistent bounded thinking and tool disclosures; excludes activity normalization, assistant answer rendering, and transport authority policy
|
|
5
|
+
*/
|
|
6
|
+
import type { TelegramActivityEvent, TelegramActivityPublicationRuntime } from "./activity.ts";
|
|
7
|
+
import type { TelegramEditMessageTextBody, TelegramInputRichMessage, TelegramSendMessageBody, TelegramSendRichMessageBody, TelegramSentMessage } from "./telegram-api.ts";
|
|
8
|
+
import type { TelegramTarget } from "./target.ts";
|
|
9
|
+
export declare const TELEGRAM_ACTIVITY_DETAIL_MAX_CHARS = 1200;
|
|
10
|
+
export declare const TELEGRAM_ACTIVITY_MESSAGE_MAX_CHARS = 3900;
|
|
11
|
+
export declare const TELEGRAM_ACTIVITY_MESSAGE_MAX_TOOLS = 6;
|
|
12
|
+
export declare const TELEGRAM_REASONING_MESSAGE_MAX_FRAMES = 24;
|
|
13
|
+
export declare const TELEGRAM_REASONING_BUFFER_MAX_CHARS = 1200;
|
|
14
|
+
export declare const TELEGRAM_REASONING_MIN_INTERVAL_MS = 1200;
|
|
15
|
+
export declare const TELEGRAM_TOOL_UPDATE_MAX_ENTRIES = 4;
|
|
16
|
+
interface ToolActivity {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
args: string;
|
|
20
|
+
updates: string[];
|
|
21
|
+
droppedUpdates: number;
|
|
22
|
+
result?: string;
|
|
23
|
+
isError?: boolean;
|
|
24
|
+
complete: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function renderTelegramToolActivityHtml(tools: readonly ToolActivity[]): string;
|
|
27
|
+
export declare function renderTelegramToolActivityRichMessage(tools: readonly ToolActivity[]): TelegramInputRichMessage;
|
|
28
|
+
export declare function renderTelegramThinkingActivityHtml(text: string): string;
|
|
29
|
+
export interface TelegramActivityVerbosityRuntime {
|
|
30
|
+
accept: (event: TelegramActivityEvent) => void;
|
|
31
|
+
reset: () => void;
|
|
32
|
+
stop: () => void;
|
|
33
|
+
waitForIdle: () => Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export interface TelegramActivityVerbosityBinding extends TelegramActivityVerbosityRuntime {
|
|
36
|
+
bind: (runtime: TelegramActivityVerbosityRuntime) => void;
|
|
37
|
+
}
|
|
38
|
+
export declare function createTelegramActivityVerbosityBinding(): TelegramActivityVerbosityBinding;
|
|
39
|
+
export declare function createTelegramActivityVerbosityRuntime<TAuthority>(deps: {
|
|
40
|
+
enqueue?: TelegramActivityPublicationRuntime["enqueue"];
|
|
41
|
+
getActivityMode: () => "quiet" | "thinking" | "tools" | "verbose";
|
|
42
|
+
refreshActivityMode?: () => Promise<void>;
|
|
43
|
+
getNowMs?: () => number;
|
|
44
|
+
resolveTarget: (event: TelegramActivityEvent) => TelegramTarget | undefined;
|
|
45
|
+
captureAuthority: () => TAuthority;
|
|
46
|
+
isAuthorityActive: (authority: TAuthority) => boolean;
|
|
47
|
+
sendMessage: (body: TelegramSendMessageBody) => Promise<TelegramSentMessage>;
|
|
48
|
+
sendRichMessage: (body: TelegramSendRichMessageBody) => Promise<TelegramSentMessage>;
|
|
49
|
+
editMessageText: (body: TelegramEditMessageTextBody) => Promise<"edited" | "unchanged">;
|
|
50
|
+
recordFailure?: (operation: "config-refresh" | "reasoning-send" | "reasoning-edit" | "tool-send" | "tool-edit", event: TelegramActivityEvent, error: unknown) => void;
|
|
51
|
+
}): TelegramActivityVerbosityRuntime;
|
|
52
|
+
export {};
|