@llblab/pi-telegram 0.35.1 → 0.36.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 +2 -1
- package/BACKLOG.md +11 -0
- package/CHANGELOG.md +18 -0
- package/README.md +36 -7
- package/docs/README.md +2 -1
- package/docs/architecture.md +29 -2
- package/docs/compact-matrix-literal.md +23 -13
- package/docs/generative-apps.md +310 -0
- package/docs/multi-instance-bus.md +1 -1
- package/docs/outbound.md +2 -2
- package/docs/public-api.md +3 -2
- package/docs/ui-style.md +14 -7
- package/index.ts +14 -0
- package/lib/bindings.ts +118 -8
- package/lib/generative-app-worker.mjs +103 -0
- package/lib/generative-apps.ts +953 -0
- package/lib/menu-queue.ts +105 -112
- package/lib/outbound-buttons.ts +51 -2
- package/lib/outbound-markup.ts +18 -14
- package/lib/outbound.ts +5 -1
- package/lib/prompts.ts +1 -0
- package/lib/queue.ts +98 -42
- package/lib/routing.ts +15 -0
- package/lib/runtime.ts +0 -23
- package/lib/updates.ts +49 -18
- package/package.json +1 -1
- package/skills/generated-control-surface/SKILL.md +13 -5
- package/skills/generative-apps/SKILL.md +110 -0
- package/skills/telegram-bridge/SKILL.md +5 -1
package/AGENTS.md
CHANGED
|
@@ -44,6 +44,7 @@ Keep each fact in one authoritative layer:
|
|
|
44
44
|
- `/tests/*.test.ts`: Domain-mirrored suites; `tests/integration.test.ts` owns cross-domain runtime flows.
|
|
45
45
|
- `/skills/telegram-bridge`: Stable agent operating protocol for Telegram turns, delivery, actions, Threaded Mode, and diagnosis.
|
|
46
46
|
- `/skills/generated-control-surface`: Optional state-derived, late-bound interface over truthful domain evidence, capabilities, workflows, and choices; it remains renderer-neutral, independent from the bridge skill, and owns no parallel state.
|
|
47
|
+
- `/skills/generative-apps`: Agent operating contract for compiling stable repeated Telegram interaction into deterministic standalone applications or bounded view/controller adapters whose buttons bypass model inference.
|
|
47
48
|
- `/.agents/skills/telegram-bot`: Bot API lookup guidance and vendored `api.md`; keep the reference intact.
|
|
48
49
|
- `/.agents/skills/domain-dag`: Repository architecture guidance and validator.
|
|
49
50
|
|
|
@@ -86,7 +87,7 @@ Use the relevant local skill before non-trivial work in its domain. Keep skill o
|
|
|
86
87
|
|
|
87
88
|
### 4.4 Queue, Delivery, And User Surfaces
|
|
88
89
|
|
|
89
|
-
- Queue lane/kind admission is explicit. Dispatch waits for active-turn, pending-dispatch, control, compaction, `ctx.isIdle()`, and Pi pending-message guards; a dispatched prompt stays queued until `agent_start` consumes it.
|
|
90
|
+
- Queue lane/kind admission is explicit. Dispatch waits for active-turn, pending-dispatch, control, compaction, `ctx.isIdle()`, and Pi pending-message guards; a dispatched prompt stays queued until `agent_start` consumes it. Each prompt is one object with one active lane and no reserved return slot. Normal and Priority are separate FIFO lanes: crossing lanes removes it from the source and appends it at the destination tail, while Keep/Skip and same-category emoji changes preserve lane position. Complete reaction sets independently derive Priority from recognized positive emoji and Skip from recognized negative emoji; both may coexist, Skip wins only at dispatch, and suppressed turns remain visible without blocking unrelated work.
|
|
90
91
|
- `/stop`, `/abort`, `/next`, and `/continue` respectively reset+abort, abort while preserving queue, force the next turn, and enqueue a control-lane continuation. Abort-history folding applies only to Telegram-owned active turns.
|
|
91
92
|
- Telegram extension side effects must not hold Pi's core lifecycle hostage after semantic completion. Preserve ordering in extension-owned background work, record failures, and fence target/profile/transport/session authority.
|
|
92
93
|
- Complete assistant/guest model answers use Telegram-native Rich Markdown. Harness-owned menus, status, diagnostics, thinking, and tool evidence remain explicit HTML/plain or their documented native surface. Preserve literal code and structurally safe chunking; never split invalid markup.
|
package/BACKLOG.md
CHANGED
|
@@ -2,3 +2,14 @@
|
|
|
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
|
+
- [ ] `Operator-confirmed pairing`: Replace first-contact automatic ownership with an explicit pending request that the trusted Pi interface can allow or reject before `allowedUserId` is persisted or any Telegram prompt executes; retain manual preconfiguration, bound pending-request lifetime and multiplicity, fail closed across session/transport replacement, and cover unauthorized-first-contact races.
|
|
6
|
+
- [ ] `Unauthorized denial consistency`: Align unauthorized Guest Mode answers and direct private-message replies so both begin with the same denial emoji and apply equivalent explicit bold emphasis to their denial copy through each surface's supported renderer; centralize the copy/style owner and protect both paths with focused regressions without pretending callback popups support rich text.
|
|
7
|
+
- [ ] `Environment-backed bot tokens`: Let each profile store an exact Pi-native `$ENV_VAR` or `${ENV_VAR}` reference in `telegram.json` instead of copying the resolved secret; preserve the originating alias when `/telegram-setup` prefills from a supported environment variable, resolve only at validation/activation boundaries, fail closed with a redacted named-variable diagnostic when unresolved, retain literal-token compatibility, and cover named profiles, reload, persistence, status, and secret-redaction paths.
|
|
8
|
+
- [ ] [`Inference bypass Generative Apps`](./docs/generative-apps.md): Let the agent install and bind one managed JavaScript app owner for a generated-prompt prefix so deterministic controls can bypass model inference without creating another button grammar.
|
|
9
|
+
- [ ] Harden the implemented `telegram_bind` installation/invocation kernel with removal operations, stronger cross-process replacement recovery, and bounded diagnostics while preserving lifecycle cancellation, worker-isolated methods, explicit staged replacement, canonical `<agent-dir>/genapps/<app>/<app>.mjs` identity, mandatory named `init`, no manifest/package metadata, non-symlink roots/sources, and fail-closed silent replacement.
|
|
10
|
+
- [ ] 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.
|
|
11
|
+
- [ ] 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.
|
|
12
|
+
- [ ] 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.
|
|
13
|
+
- [ ] 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.
|
|
14
|
+
- [ ] 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.
|
|
15
|
+
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
> Each release keeps at most 8 outcome records of at most 512 characters.
|
|
4
4
|
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
## 0.36.0: Generative Apps
|
|
8
|
+
|
|
9
|
+
- `Generative App Kernel`: Adds `telegram_bind` for canonical `.mjs` install/replace/invoke with mandatory `init`, strict JSON, bounded output/processes, transactional snapshots, repaired partial-tail recovery, non-symlink root/app/module/source containment, and worker-isolated terminable methods. Lifecycle cancellation stops child processes and fences state commit; failed staging or `init` preserves the installed app.
|
|
10
|
+
- `Inference Bypass`: Parses complete `app::method` and strict-JSON argument prompts after one-shot `tgbtn` resolution, invokes the installed app before Pi queue admission, plans returned Markdown/buttons through the current outbound surface, preserves native callbacks and ordinary prompts, marks successful controls, and fails malformed or unsuccessful bound actions without model fallback.
|
|
11
|
+
- `Transition Fencing`: Serializes transitions with stable locks outside replaceable app directories, reclaims dead owners, reconciles current state from the last complete snapshot, and carries immutable installation generation plus revision on buttons. Replacement, stale callbacks, and lifecycle loss fail before method effects, state commit, or Telegram delivery.
|
|
12
|
+
- `Compact Queue Controls`: Adds strict CML selected styles with atomic validation. Queue detail replaces Delete with independent Priority/Normal and Keep/Skip. Lane transitions append at the destination FIFO tail; Keep/Skip preserves position. Positive and negative reaction categories may coexist; Skip stays reversible, shows only its emoji, and wins at dispatch by dropping the marked head without inference and continuing.
|
|
13
|
+
- `Generated Music Player`: Validates a capability-owned Generative App over the public Actor control surface while `pi-telegram` ships only the generic runtime. Live `ffplay` checks confirmed no-model-turn navigation, pause/play, seek, absolute volume, status, and stop with exact terminal Controls and no pending backlog. The app reports Actor availability and uses symmetric seven-button progress and volume scales.
|
|
14
|
+
- `Dual Action Views`: Keeps fresh-message delivery as the simple default so prior interfaces and selected buttons remain visible, while `viewMode: "edit"` opts a method into replacing its callback message and keyboard. An explicit edit failure records diagnostics and sends one fresh view; automatic refresh remains a separate lifecycle slice.
|
|
15
|
+
- `Direct Initial View`: During an active Telegram turn, `telegram_bind` plans and delivers successful output to the exact target, marks it displayed so the model does not repeat it, and supports `display: false`. Outside turns it returns exact output; delivery failure preserves the app result. Tool success, direct-display, and error text use one leading line break, and failed old-message restyling cannot turn a completed action into failure.
|
|
16
|
+
- `Generative Apps Skill`: Adds an operating Skill for compiling repeated interaction into reusable standalone apps or bounded adapters with generated JSON button views. One surface may mix deterministic bound methods with ordinary model prompts; the Skill covers authorship, review, install/replace/invoke, stale actions, and validation while Generated Control Surface retains ephemeral model-mediated interfaces.
|
|
17
|
+
|
|
18
|
+
## 0.35.2: Independent Surface Dimensions
|
|
19
|
+
|
|
20
|
+
- `Horizontal Boundary`: Establishes eight controls as the Generated Control Surface phone-width UX maximum regardless of the parser's uncapped row grammar; nine or more controls must regroup, and six-to-eight remains limited to minimal position-bearing labels.
|
|
21
|
+
- `Vertical Continuity`: Treats height independently from width so true spatial surfaces may preserve substantially more rows—including an `8×16` field—when coordinates and topology matter, while non-spatial button walls still yield to semantic grouping, progressive disclosure, or pagination.
|
|
22
|
+
|
|
5
23
|
## 0.35.1: Semantic Ragged Control Layouts
|
|
6
24
|
|
|
7
25
|
- `Row Composition`: Teaches Generated Control Surface to model Telegram controls as an ordered ragged sequence of independently sized semantic rows rather than filling a rectangular matrix: compact rows hold genuine peers, singleton rows isolate independent actions, and symmetry is admitted only when equal relationships or real spatial topology provide evidence for it.
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ The 0.21 extension platform requires Pi `0.80.6` or newer. Its Activity API uses
|
|
|
32
32
|
|
|
33
33
|
### 1. Create a Telegram bot
|
|
34
34
|
|
|
35
|
-
1. Open [@BotFather](https://t.me/BotFather).
|
|
35
|
+
1. Open [@BotFather](https://t.me/BotFather). BotFather's chat commands and Mini App are different surfaces; Telegram Desktop supports the Mini App through **Open App** / **Menu** in the BotFather profile.
|
|
36
36
|
2. Run `/newbot`.
|
|
37
37
|
3. Pick a name and username.
|
|
38
38
|
4. Copy the bot token.
|
|
@@ -65,11 +65,24 @@ Open the bot DM and send:
|
|
|
65
65
|
/start
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
The first Telegram user to message the bot becomes the allowed owner. Other users are ignored.
|
|
68
|
+
The first Telegram user to message the bot becomes the allowed owner. Other users are ignored. This is a first-contact security boundary: keep the bot private and send `/start` immediately after connecting. For stricter setup, restrict access to your account in the BotFather Mini App when that control is available, or preconfigure your numeric Telegram user id as `profiles.default.allowedUserId` in the existing `~/.pi/agent/telegram.json` before connecting (preserve the saved `botToken` and any other settings):
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"profiles": {
|
|
73
|
+
"default": {
|
|
74
|
+
"botToken": "<existing-token>",
|
|
75
|
+
"allowedUserId": 123456789
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
After required pairing state is persisted, `/start` is admitted independently from best-effort menu rendering and BotFather command-list synchronization, so either Telegram side effect can fail or remain in flight without stopping later inbound updates.
|
|
69
82
|
|
|
70
83
|
### 5. Enable optional bot capabilities in BotFather
|
|
71
84
|
|
|
72
|
-
Enable the optional capabilities the bridge needs in [@BotFather](https://t.me/BotFather). The bridge does not fail loudly when a capability is off; the feature simply never triggers.
|
|
85
|
+
Enable the optional capabilities the bridge needs in the [@BotFather](https://t.me/BotFather) Mini App. On Telegram Desktop, open the BotFather profile and use **Open App** / **Menu**, select the configured bot, open **Settings**, and toggle **Threaded Mode** there rather than relying only on the inline chat-command interface. The bridge does not fail loudly when a capability is off; the feature simply never triggers.
|
|
73
86
|
|
|
74
87
|
1. Enable guest mode so the bot can answer mentions and replies in chats where it is not a member.
|
|
75
88
|
2. Enable private-chat Threaded Mode; when it is available, one live instance becomes the profile's leader and later visible Pi instances register as followers. Without it, the bridge stays in classic single-owner DM mode.
|
|
@@ -103,7 +116,7 @@ Enable the optional capabilities the bridge needs in [@BotFather](https://t.me/B
|
|
|
103
116
|
| Surface | What you can do | Why it matters |
|
|
104
117
|
| --- | --- | --- |
|
|
105
118
|
| Prompt intake | Send text, replies, edits, images, files, albums, voice notes, forwards with adjacent comments, and handler output into Pi. | Telegram becomes a real mobile input surface; one forward-plus-comment gesture stays one attributed prompt even for photo-only forwards. |
|
|
106
|
-
| Queue control | Inspect waiting turns,
|
|
119
|
+
| Queue control | Inspect waiting turns, keep or skip stale work, promote important prompts, continue, abort, stop, or force the next queued item. | Long Pi tasks keep running while new mobile prompts stay visible and controllable instead of interrupting or disappearing. |
|
|
107
120
|
| Operator menu | Use `/start` for status, prompt templates, model, thinking, settings, queue, extension sections, and diagnostics. | The bot is an operator panel, not a command cheat sheet. |
|
|
108
121
|
| Prompt templates | Run Pi prompt templates as Telegram-safe commands such as `/fix_tests`. | Reusable local workflows become phone-accessible without exposing arbitrary terminal commands. |
|
|
109
122
|
| 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. |
|
|
@@ -117,6 +130,7 @@ Enable the optional capabilities the bridge needs in [@BotFather](https://t.me/B
|
|
|
117
130
|
| Voice input | Route audio through configured command-template handlers, programmatic handlers, or STT providers. | Voice notes become usable prompt context. |
|
|
118
131
|
| Voice output | Choose `hidden`, `mirror`, or `always`; active automatic turns carry one compact `[voice] delivery: automatic voice` line, while explicit `telegram_voice` remains available. | Voice policy stays dynamic and model-legible without duplicating the full action contract in every prompt. |
|
|
119
132
|
| Buttons | Turn top-level `telegram_button` comments into inline buttons. | Assistant-authored choices become native Telegram interactions. |
|
|
133
|
+
| Generative Apps | Install or explicitly replace a reviewed `.mjs` application whose generated JSON button view may mix direct `app::method` actions with ordinary model prompts. | Repeated games, controls, tutors, and adapters compile routine interaction without losing selective model interpretation, explanation, or adaptation. |
|
|
120
134
|
| Callback routing | Route known callbacks to the owner extension and unknown callbacks back into Pi. | Companion extensions can build UI without polling Telegram themselves. |
|
|
121
135
|
| Threaded Mode | Run one leader plus visible follower Pi instances through named private-chat threads. | One bot can host a local multi-instance Pi organism without hidden process spawning. |
|
|
122
136
|
| Reroute and restore | Give unknown and command-created temporary threads explicit forward and replace/restore choices. | Forward removes the temporary tab; restore rebinds it and removes only the replaced old tab, so Telegram client state repairs without orphan controls. |
|
|
@@ -176,7 +190,21 @@ Named profile identifiers contain only lowercase ASCII letters and digits (maxim
|
|
|
176
190
|
|
|
177
191
|
### Queue Runtime
|
|
178
192
|
|
|
179
|
-
Messages sent while Pi is busy become queued turns.
|
|
193
|
+
Messages sent while Pi is busy become queued turns. Queue controls let you inspect, prioritize, keep or skip, and dispatch work without touching the terminal.
|
|
194
|
+
|
|
195
|
+
Queue policy:
|
|
196
|
+
|
|
197
|
+
- One prompt is one queue object with exactly one current lane and one current position; it never reserves a shadow place in the other lane.
|
|
198
|
+
- Priority and Normal are separate FIFO lanes; Priority dispatches first.
|
|
199
|
+
- Moving `Normal → Priority` removes the prompt from Normal and places it at the Priority tail. Moving `Priority → Normal` removes it from Priority and places it at the Normal tail; no former position is restored.
|
|
200
|
+
- Keep/Skip never changes lane position. Skip remains reversible while waiting and drops the prompt without a model turn only when dispatch reaches it.
|
|
201
|
+
- Reactions control two independent dimensions; changing one category preserves the other:
|
|
202
|
+
- `Positive`: `👍`, `⚡️`, `❤️`, `🕊`, `🔥` — controls Priority.
|
|
203
|
+
- `Negative`: `👎`, `👻`, `💔`, `💩`, `🗑` — controls Skip.
|
|
204
|
+
- Priority and Skip can coexist—for example `👍 + 💩`. Skip wins at dispatch, regardless of which negative emoji is selected.
|
|
205
|
+
- Menu selectors and reactions share queue state, but the bot cannot remove a user's reaction; Keep may clear internal Skip while the user's emoji remains visible until they remove it.
|
|
206
|
+
|
|
207
|
+
The detailed contract lives in [Priority, Reactions, Keep, and Skip](./docs/architecture.md#priority-reactions-keep-and-skip). If Pi automatically retries a transient provider failure, the active Telegram turn stays bound until the successful reply arrives or Pi confirms that the run has settled.
|
|
180
208
|
|
|
181
209
|
### Native Rich Markdown
|
|
182
210
|
|
|
@@ -192,7 +220,7 @@ Voice notes, audio, images, PDFs, and other media can pass through configured in
|
|
|
192
220
|
|
|
193
221
|
### Buttons And Callbacks
|
|
194
222
|
|
|
195
|
-
Assistant replies can include top-level hidden `telegram_button` comments using a JSON object, JSON matrix, Compact Matrix Literal (CML), or compact double-quoted attributes; `telegram_buttons` is a plural alias. In JSON and CML matrices, top-level cells become full-width rows while nested rows group one or more buttons horizontally without an artificial parser-level width cap; generated surfaces default to five columns and use six to eight only for short position-bearing labels. CML uses `{value}` or `{label|prompt}`, 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 action marker is colon-free for every payload form. The bridge strips the comments from visible text, renders 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.
|
|
223
|
+
Assistant replies can include top-level hidden `telegram_button` comments using a JSON object, JSON matrix, Compact Matrix Literal (CML), or compact double-quoted attributes; `telegram_buttons` is a plural alias. In JSON and CML matrices, top-level cells become full-width rows while nested rows group one or more buttons horizontally without an artificial parser-level width cap; generated surfaces default to five columns and use six to eight only for short position-bearing labels. CML uses `{value}`, `{label|prompt}`, or `{label|prompt|selected_style}` with `primary`, `success`, or `danger`; the optional style requires an explicit prompt. 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 action marker is colon-free for every payload form. The bridge strips the comments from visible text, renders 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.
|
|
196
224
|
|
|
197
225
|
### Threaded Mode And Multi-Instance Bus
|
|
198
226
|
|
|
@@ -257,7 +285,7 @@ Durable inbound admission is a **process-crash recovery** guarantee. Atomic priv
|
|
|
257
285
|
|
|
258
286
|
Telegram is a companion surface around a live Pi runtime, not a second runtime. It can compact the current session, but it cannot create, resume, fork, browse, or switch sessions until Pi exposes safe public extension APIs for those operations.
|
|
259
287
|
|
|
260
|
-
A Telegram prompt is a normal model turn in the active Pi session and therefore inherits that session's active post-compaction context; the bridge does not make token cost proportional only to the new mobile message. The bundled `telegram-bridge` Skill owns agent operation
|
|
288
|
+
A Telegram prompt is a normal model turn in the active Pi session and therefore inherits that session's active post-compaction context; the bridge does not make token cost proportional only to the new mobile message. The bundled `telegram-bridge` Skill owns general agent operation, `generated-control-surface` proactively compiles optional evidence-backed ephemeral controls when model interpretation remains useful, and `generative-apps` compiles stable repeated interaction into reviewed reusable applications whose bound buttons bypass model inference while ordinary prompt buttons retain it. Generative Apps may own a closed state machine or adapt another authoritative tool, service, Actor Run, or application through bounded methods. Disconnecting removes pi-telegram's delivery tools and transient routing guidance from later requests until direct ownership or follower registration returns, without changing other active Pi tools. Pi session JSONL contains model history; profile-scoped pi-telegram `logs*.jsonl` contains redacted operational events and is never model context.
|
|
261
289
|
|
|
262
290
|
## Documentation Map
|
|
263
291
|
|
|
@@ -274,6 +302,7 @@ A Telegram prompt is a normal model turn in the active Pi session and therefore
|
|
|
274
302
|
- [UI Style](./docs/ui-style.md) — menu, emoji, labels, dialogs, and inline keyboard standards.
|
|
275
303
|
- [Callback Namespaces](./docs/callback-namespaces.md) — callback ownership and routing.
|
|
276
304
|
- [Command Templates](./docs/command-templates.md) — handler command-template conventions.
|
|
305
|
+
- [Generative Apps](./docs/generative-apps.md) — reusable application identity, state, generated button views, hybrid action routing, replacement, and bounded execution contract.
|
|
277
306
|
|
|
278
307
|
The docs index lives at [docs/README.md](./docs/README.md).
|
|
279
308
|
|
package/docs/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Living index of project documentation in `/docs`.
|
|
|
6
6
|
|
|
7
7
|
## Documents
|
|
8
8
|
|
|
9
|
-
- [architecture.md](./architecture.md) — Overview of the Telegram bridge runtime, optional profile isolation, queueing model, native Rich Markdown delivery, UI/compat rendering, and interactive controls
|
|
9
|
+
- [architecture.md](./architecture.md) — Overview of the Telegram bridge runtime, optional profile isolation, queueing model and Priority/Normal plus Keep/Skip reaction policy, native Rich Markdown delivery, UI/compat rendering, and interactive controls
|
|
10
10
|
- [public-api.md](./public-api.md) — Stable public API map: package entrypoints, commands, config, assistant markup, extension APIs, smoke examples, and compatibility boundaries
|
|
11
11
|
- [delivery.md](./delivery.md) — Target-aware companion delivery contract for operational views, logical message handles, target scopes, lifecycle fencing, and leader/follower transport
|
|
12
12
|
- [activity.md](./activity.md) — Normalized Pi lifecycle API for extension-owned reasoning, intermediate prose, tool activity, source identity, delivery contexts, and consumer policy examples
|
|
@@ -16,6 +16,7 @@ Living index of project documentation in `/docs`.
|
|
|
16
16
|
- [inbound.md](./inbound.md) — Local `pi-telegram` inbound text/media handler bus, programmatic inbound handlers, registered STT provider fallbacks, legacy `attachmentHandlers` compatibility, placeholders, and fallbacks
|
|
17
17
|
- [outbound.md](./outbound.md) — Local `pi-telegram` outbound-handler config, text/voice/button behavior, single-artifact Rich results, voice synthesis provider fallback priority, artifact outputs, and callback routing
|
|
18
18
|
- [compact-matrix-literal.md](./compact-matrix-literal.md) — Portable Compact Matrix Literal v1 standard for trimmed key-value cells, minimal escapes, bounded-depth rows, JSON coexistence, and renderer-owned width policy
|
|
19
|
+
- [generative-apps.md](./generative-apps.md) — Generative Apps runtime and wire contract for managed `.mjs` identity, inference-bypass bindings, persistent state timelines, bounded adapters, replacement, and lifecycle; agent operation lives in the bundled `generative-apps` Skill
|
|
19
20
|
- [callback-namespaces.md](./callback-namespaces.md) — Shared Telegram `callback_data` namespace standard for layered extensions
|
|
20
21
|
- [updates.md](./updates.md) — Update classification and runtime handler registry that lets layered extensions observe and consume Telegram updates without owning their own polling connection
|
|
21
22
|
- [multi-instance-bus.md](./multi-instance-bus.md) — Optional multi-instance Telegram bus architecture: profile-scoped transport, leader/follower routing, thread targets, instance slots, manual follower registration, and recovery semantics
|
package/docs/architecture.md
CHANGED
|
@@ -22,6 +22,7 @@ This document is the architectural map. Focused behavior standards live in sibli
|
|
|
22
22
|
- [Updates](./updates.md) — update classification, default-routing plans, and raw Telegram update interception.
|
|
23
23
|
- [Voice Integration](./voice.md) — voice reply policy and STT/TTS provider surface.
|
|
24
24
|
- [Command Templates](./command-templates.md) — shell-free command-template contract.
|
|
25
|
+
- [Generative Apps](./generative-apps.md) — managed reusable application identity, state, generated button views, hybrid action routing, replacement, and bounded execution contract.
|
|
25
26
|
- [Telegram Multi-Instance Bus](./multi-instance-bus.md) — Threaded Mode bus leadership, Telegram UI thread targets, instance identity, and leader/follower routing.
|
|
26
27
|
|
|
27
28
|
## Runtime Topology
|
|
@@ -81,6 +82,7 @@ The repository uses a **Flat Domain DAG**:
|
|
|
81
82
|
- `activity`: public normalized Pi lifecycle registration, activity/source identity, assistant segment and reasoning normalization, executed-tool events, non-blocking per-handler queues, delivery contexts, compatibility adapters, and shutdown fencing. The same domain extends assistant-output observation for proactive push: eligible completed local/autonomous public segments retain source order and deduplicate event identity. `bindings` assembles observation, authority, sender, and failure-projection ports; routing owns exact delivery authority, outbound composes established transformations and reply delivery, and Bot API domains implement transport. No separate proactive state-machine domain exists.
|
|
82
83
|
- `outbound-markup`: top-level assistant action comment parsing, attribute parsing, voice reply planning, and preview/delivery stripping.
|
|
83
84
|
- `outbound`: outbound text transformations, voice/button artifact delivery, and generated callback actions.
|
|
85
|
+
- `generative-apps`: managed deterministic application identity, canonical installation and explicit replacement, content-addressed module loading, state timelines, cross-process transition serialization, bounded executable-plus-argv adaptation, `telegram_bind`, and pre-model-queue `app::method` invocation. It does not own Telegram transport, arbitrary shell execution, or the external application adapted by one Generative App.
|
|
84
86
|
- `outbound-attachments`: `telegram_attach`, queued outbound files, stat/limit checks, ordinary photo/document delivery, and narrow single-artifact Rich Message planning/sending for probe-confirmed photo/video/audio formats. It owns known-failure fallback eligibility and ambiguous-send no-replay classification through structural error contracts without importing Bot API helpers.
|
|
85
87
|
- `status` / `logs`: status bar/status-message rendering, queue-lane summaries, the structural redacted event ring, profile-aware JSONL scope/reset/append behavior, exact-owner destructive commits, fail-soft synchronous and queued diagnostics persistence, status snapshot scheduling, and grouped diagnostics. `status` remains a structural leaf; `logs` composes filesystem evidence with status projections and contains every persistence failure so diagnostics cannot terminate or poison the runtime queue.
|
|
86
88
|
- `bindings` / `lifecycle` / `prompts` / `prompt-templates` / `pi`: Pi-facing command/tool/hook registration and cohesive cross-domain binding assembly, including queue mutation/dispatch/watchdog composition over admission and transport ports; session-generation fencing and start/shutdown sequencing across Queue, grouped input, Delivery, polling, capability monitor, follower refresh, and assistant-output projection; Telegram prompt guidance; prompt-template discovery/expansion; and centralized direct Pi SDK imports.
|
|
@@ -247,6 +249,21 @@ Dispatch rank:
|
|
|
247
249
|
2. `priority` prompt lane.
|
|
248
250
|
3. `default` prompt lane.
|
|
249
251
|
|
|
252
|
+
#### Priority, Reactions, Keep, and Skip
|
|
253
|
+
|
|
254
|
+
Waiting prompts expose two independent dimensions:
|
|
255
|
+
|
|
256
|
+
- `Priority` / `Normal` selects the FIFO lane and therefore scheduling order.
|
|
257
|
+
- `Keep` / `Skip` selects whether the prompt executes when dispatch reaches it.
|
|
258
|
+
|
|
259
|
+
A prompt is one queue object with exactly one active lane membership and one current position. It has no duplicate, shadow entry, or reserved return slot in the other lane. Each prompt admitted directly to a lane joins that lane's tail. A `Normal → Priority` transition removes it from Normal and appends that same object to the Priority tail; a later `Priority → Normal` transition removes it from Priority and appends it to the current Normal tail rather than restoring any historical position. The immutable `queueOrder` records original admission identity only and is never a return address; `laneOrder` records the current destination-lane position. Keep/Skip changes and emoji changes within the same reaction category preserve both lane and lane position exactly.
|
|
260
|
+
|
|
261
|
+
Telegram reactions are shortcut controls over those dimensions. Positive reactions (`👍`, `⚡️`, `❤️`, `🕊`, `🔥`) control Priority; negative reactions (`👎`, `👻`, `💔`, `💩`, `🗑`) control Skip. The runtime compares the complete old and new reaction sets and mutates only categories that changed, so adding or removing a negative reaction cannot silently change Priority, and changing a positive reaction cannot silently change Skip. The listed order selects the retained display emoji when several recognized emoji from one category coexist; it does not let one category override the other.
|
|
262
|
+
|
|
263
|
+
Priority and Skip may coexist, including `👍 + 💩`. The prompt remains at its Priority-lane position while waiting, but Skip wins when dispatch reaches it: the dispatcher drops it without a model turn and continues. A skipped prompt remains visible with only its negative emoji, survives authenticated queue handoff, and can return to Keep until it reaches the head. Queue item detail exposes symmetric Priority/Normal and Keep/Skip selectors instead of an irreversible Delete action.
|
|
264
|
+
|
|
265
|
+
Menu and reaction controls share the same canonical queue state. A menu Keep can clear internal Skip without changing Priority or queue position, but Telegram's Bot API cannot remove a reaction created by the user; the visible user reaction can therefore remain until that user removes it. Once Pi has consumed or dropped a prompt, later reactions cannot retract or restore it.
|
|
266
|
+
|
|
250
267
|
Admission and planning validate lane contracts. Invalid lane/kind pairings fail predictably instead of being silently coerced.
|
|
251
268
|
|
|
252
269
|
Dispatch requires:
|
|
@@ -333,6 +350,16 @@ Preview delivery strips top-level action comments before streaming draft Markdow
|
|
|
333
350
|
|
|
334
351
|
Unknown callback data outside owned prefixes is forwarded as `[callback] <data>` only after built-in and extension handlers decline it.
|
|
335
352
|
|
|
353
|
+
### Generative Apps
|
|
354
|
+
|
|
355
|
+
The `generative-apps` Skill owns the general Generative Apps concept, application shapes, and hybrid method/prompt model. This section records only how the `pi-telegram` runtime composes that concept into the bridge.
|
|
356
|
+
|
|
357
|
+
The bridge owns canonical `<agent-dir>/genapps/<app>/<app>.mjs` identity, installation/replacement, bounded runtime ports, state revision/timeline integrity, `app::method` routing before Pi queue admission, ordinary prompt routing through Pi, and Telegram delivery of returned Markdown/buttons. External capability ownership remains outside the bridge.
|
|
358
|
+
|
|
359
|
+
`telegram_bind` is the agent-facing lifecycle surface. Installation and explicit replacement invoke mandatory `init`; replacement stages and initializes a complete candidate before publishing it under the same app name. During an active Telegram turn, successful Tool output is planned and delivered directly to that exact target by default, and the Tool result suppresses model duplication; `display: false` retains agent-only diagnosis. Outside an active turn no implicit target is chosen. Buttons emitted as `app::method` or `app::method(<strict JSON>)` take the inference-bypass route. Missing apps, malformed actions, stale revisions, invalid output, or method failure fail closed without becoming ordinary prompts.
|
|
360
|
+
|
|
361
|
+
The concrete runtime and wire reference remains in [Generative Apps Runtime For Telegram](./generative-apps.md). The bundled `generative-apps` Skill owns the concept and agent workflow; `generated-control-surface` owns its separate ephemeral interface protocol; `telegram-bridge` owns transport, target authority, delivery, and general turn operation.
|
|
362
|
+
|
|
336
363
|
## Extension Surfaces
|
|
337
364
|
|
|
338
365
|
`pi-telegram` intentionally owns one `getUpdates` loop per bot. `polling` owns that internal loop; `updates` owns classification/default-routing plans plus the public handler registry layered extensions use to observe or consume updates without opening a competing polling connection. Layered extensions should integrate through extension surfaces instead of polling the same bot independently.
|
|
@@ -354,7 +381,7 @@ The bridge does not mirror arbitrary `ctx.ui.confirm/input/select/custom` prompt
|
|
|
354
381
|
|
|
355
382
|
Status rendering distinguishes connected, active, dispatching, queued, tool-running, model-switching, and compacting states; the Telegram status menu gives compaction precedence over generic active or pending work. Observed automatic compaction sends the same start and completion notices as the manual command without duplicating notices for command-owned compaction. If a queue mutation removes the last waiting item while Telegram-owned work still has running tools, status remains active instead of degrading to connected.
|
|
356
383
|
|
|
357
|
-
Queue
|
|
384
|
+
Queue reaction behavior, lane-tail transitions, Keep/Skip independence, multi-reaction precedence, and the Bot API reaction-removal limitation are defined in [Priority, Reactions, Keep, and Skip](#priority-reactions-keep-and-skip). Reaction changes first flush a matching delayed text or media group so the governed turn exists before mutation, and dropping marked heads cannot leave status permanently queued.
|
|
358
385
|
|
|
359
386
|
`/telegram-status` records grouped diagnostics for transport/API, polling/update, prompt dispatch, controls, typing, compaction, setup, session lifecycle, attachment queue/delivery, and recent redacted runtime events. Polling diagnostics expose the exact phase, phase start, current update, last successful `getUpdates` response, and stop reason; outbound success never substitutes for inbound progress. Expected preview noise such as unchanged edit responses is filtered out. The compact TUI status renders only `error`; detailed failure text remains in diagnostics and profile-scoped logs instead of expanding the status line.
|
|
360
387
|
|
|
@@ -362,7 +389,7 @@ Complete intermediate assistant text blocks from Telegram-originated activity ar
|
|
|
362
389
|
|
|
363
390
|
`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. Both proactive prose and active-turn final delivery wait for the admitted activity queue inside their extension-owned delivery tasks, preserving technical-before-semantic ordering without delaying Pi lifecycle completion. Settlement, replacement, disconnect, failure, or stale authority clears only local ownership; already-sent activity messages remain in chat.
|
|
364
391
|
|
|
365
|
-
Telegram prompt guidance is context- and authority-aware. The package and source-checkout extension
|
|
392
|
+
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.
|
|
366
393
|
|
|
367
394
|
## In-Flight Model Switching
|
|
368
395
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Compact Matrix Literal
|
|
2
2
|
|
|
3
|
-
> Status: Portable
|
|
3
|
+
> Status: Portable v2 standard implemented by the unreleased `pi-telegram` control-surface parser.
|
|
4
4
|
|
|
5
5
|
Compact Matrix Literal (CML) is a bounded-depth text format for ordered key-value cells arranged as singleton or compact rows. It optimizes repeated interactive controls where JSON field names, quotes, and commas dominate the payload.
|
|
6
6
|
|
|
7
|
-
CML is transport-neutral. An embedding maps each decoded cell's `key` and `
|
|
7
|
+
CML is transport-neutral. An embedding maps each decoded cell's `key`, `value`, and optional `variant` to its own domain. The `pi-telegram` profile maps them to button label, prompt, and selected style.
|
|
8
8
|
|
|
9
9
|
## Goals
|
|
10
10
|
|
|
@@ -17,7 +17,7 @@ CML is transport-neutral. An embedding maps each decoded cell's `key` and `value
|
|
|
17
17
|
|
|
18
18
|
## Non-Goals
|
|
19
19
|
|
|
20
|
-
- Replacing JSON for arbitrary objects,
|
|
20
|
+
- Replacing JSON for arbitrary objects, multiline values, non-positional metadata, or extensible schemas.
|
|
21
21
|
- Defining callback ownership, application state, rendering policy, or transport behavior.
|
|
22
22
|
- Recovering partial intent from malformed input.
|
|
23
23
|
- Defining one universal visual row-width limit for every renderer.
|
|
@@ -27,7 +27,7 @@ CML is transport-neutral. An embedding maps each decoded cell's `key` and `value
|
|
|
27
27
|
A decoded payload is an ordered non-empty list of non-empty rows:
|
|
28
28
|
|
|
29
29
|
```text
|
|
30
|
-
Cell = { key: string, value: string }
|
|
30
|
+
Cell = { key: string, value: string, variant?: string }
|
|
31
31
|
Rows = Cell[][]
|
|
32
32
|
```
|
|
33
33
|
|
|
@@ -45,6 +45,13 @@ A cell with two atoms separates key and value with one unescaped vertical bar:
|
|
|
45
45
|
{🟥|2,5} == { key: "🟥", value: "2,5" }
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
+
A cell with three atoms adds one optional positional variant. The variant is valid only when the explicit value atom is present:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
{Stop|music-player::stop|danger}
|
|
52
|
+
== { key: "Stop", value: "music-player::stop", variant: "danger" }
|
|
53
|
+
```
|
|
54
|
+
|
|
48
55
|
## Grammar
|
|
49
56
|
|
|
50
57
|
The normative structural grammar is:
|
|
@@ -56,6 +63,7 @@ element := cell | row
|
|
|
56
63
|
row := "[" ws cell (ws cell)* ws "]"
|
|
57
64
|
cell := "{" atom "}"
|
|
58
65
|
| "{" atom "|" atom "}"
|
|
66
|
+
| "{" atom "|" atom "|" atom "}"
|
|
59
67
|
atom := atom-unit+
|
|
60
68
|
atom-unit := ordinary | "\\|" | "\\}" | "\\\\"
|
|
61
69
|
ws := *(SP | HTAB | CR | LF)
|
|
@@ -71,9 +79,10 @@ Examples:
|
|
|
71
79
|
[{Up|/}[{Prev|page-1}{Next|page-3}]{etc|/etc}]
|
|
72
80
|
[[{1}{2}{3}{4}{5}{6}{7}{8}]]
|
|
73
81
|
{A \| B|C:\\Games\}}
|
|
82
|
+
{Stop|music-player::stop|danger}
|
|
74
83
|
```
|
|
75
84
|
|
|
76
|
-
These normalize respectively to one copied singleton cell, one key-value singleton cell, a mixed singleton/compact matrix, one eight-cell row,
|
|
85
|
+
These normalize respectively to one copied singleton cell, one key-value singleton cell, a mixed singleton/compact matrix, one eight-cell row, `{ key: "A | B", value: "C:\\Games}" }`, and one key-value cell with the `danger` variant.
|
|
77
86
|
|
|
78
87
|
## Atoms, Whitespace, And Escapes
|
|
79
88
|
|
|
@@ -95,7 +104,7 @@ Every other printable character is literal inside a cell, including:
|
|
|
95
104
|
{ [ ] " : , / emoji and ordinary spaces
|
|
96
105
|
```
|
|
97
106
|
|
|
98
|
-
An opening `{` has no structural meaning after a cell has begun. Square brackets are structural only outside a cell.
|
|
107
|
+
An opening `{` has no structural meaning after a cell has begun. Square brackets are structural only outside a cell. One or two unescaped vertical bars select the two- or three-atom form; a third is invalid. Every selected atom must remain non-empty after trimming. When multiline text or non-positional metadata is needed, the producer uses the embedding's JSON or other full-fidelity form.
|
|
99
108
|
|
|
100
109
|
## Width Policy
|
|
101
110
|
|
|
@@ -111,7 +120,7 @@ A conforming parser:
|
|
|
111
120
|
2. Parses exactly one `payload` and rejects trailing non-whitespace input.
|
|
112
121
|
3. Rejects empty atoms, empty matrices, empty rows, and nesting deeper than one row inside the top-level matrix.
|
|
113
122
|
4. Rejects missing, extra, crossed, or mismatched delimiters.
|
|
114
|
-
5.
|
|
123
|
+
5. Accepts at most two unescaped vertical bars in a cell and rejects a third.
|
|
115
124
|
6. Decodes only `\|`, `\}`, and `\\`; unknown or trailing escapes fail.
|
|
116
125
|
7. Trims atom boundaries, then rejects empty values and remaining control characters.
|
|
117
126
|
8. Returns no partial rows or cells after any failure.
|
|
@@ -140,8 +149,9 @@ For `telegram_button` and its exact `telegram_buttons` alias:
|
|
|
140
149
|
- A nested row becomes one horizontal row.
|
|
141
150
|
- `{value}` is equivalent to JSON `{"value":"value"}`.
|
|
142
151
|
- `{label|prompt}` is equivalent to JSON `{"label":"label","prompt":"prompt"}`.
|
|
143
|
-
-
|
|
144
|
-
-
|
|
152
|
+
- `{label|prompt|selected_style}` is equivalent to JSON `{"label":"label","prompt":"prompt","selected_style":"selected_style"}`.
|
|
153
|
+
- The third atom is accepted only when the prompt atom is present and its exact value is `primary`, `success`, or `danger`.
|
|
154
|
+
- JSON and double-quoted attributes remain the full-fidelity forms for Generative App script output, multiline values, and other metadata.
|
|
145
155
|
- Invalid CML is stripped with its enclosing recognized action comment and registers no callbacks, matching existing fail-closed action behavior.
|
|
146
156
|
|
|
147
157
|
Example embedding:
|
|
@@ -158,7 +168,7 @@ A conformance suite covers properties rather than incident-specific strings.
|
|
|
158
168
|
|
|
159
169
|
### Accepted
|
|
160
170
|
|
|
161
|
-
- Singular copied and key-value cells.
|
|
171
|
+
- Singular copied, key-value, and key-value-variant cells.
|
|
162
172
|
- Top-level singleton rows.
|
|
163
173
|
- Nested rows at widths one, five, and eight.
|
|
164
174
|
- Mixed singleton and compact rows.
|
|
@@ -173,7 +183,7 @@ A conformance suite covers properties rather than incident-specific strings.
|
|
|
173
183
|
- Empty payload, matrix, row, key, or value.
|
|
174
184
|
- Deeper nesting.
|
|
175
185
|
- Missing or mismatched delimiters.
|
|
176
|
-
- A
|
|
186
|
+
- A third unescaped separator, an empty positional atom, or a profile-invalid variant.
|
|
177
187
|
- Unknown or trailing escapes.
|
|
178
188
|
- Internal control characters.
|
|
179
189
|
- Commas between cells.
|
|
@@ -184,6 +194,6 @@ Every rejected case proves zero callback registration.
|
|
|
184
194
|
|
|
185
195
|
## Versioning
|
|
186
196
|
|
|
187
|
-
This document defines CML v1. Compatible embeddings may impose documented host-level byte, cell-count, or width limits without changing the core grammar, but must preserve bounded-depth and fail-closed semantics.
|
|
197
|
+
This document defines CML v2. The three-atom cell is the explicit syntactic discriminator from v1: v1 parsers reject it atomically, while v2 parsers cannot reinterpret a valid v1 cell. Compatible embeddings may impose documented host-level byte, cell-count, variant-enum, or width limits without changing the core grammar, but must preserve bounded-depth and fail-closed semantics.
|
|
188
198
|
|
|
189
|
-
Future versions must not assign new meaning to input rejected by a security or ownership boundary without an explicit
|
|
199
|
+
Future versions must not assign new meaning to input rejected by a security or ownership boundary without an explicit syntactic discriminator. Non-positional metadata and deeper structures require a revised standard rather than permissive recovery.
|