stitchkit 0.95.2 → 0.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +118 -0
- package/dist/agent-runtime/runtime-internals.d.ts +6 -0
- package/dist/agent-runtime/runtime-internals.d.ts.map +1 -1
- package/dist/application/grammy-bot.d.ts +44 -0
- package/dist/application/grammy-bot.d.ts.map +1 -0
- package/dist/application/grammy-update-admission.d.ts +35 -0
- package/dist/application/grammy-update-admission.d.ts.map +1 -0
- package/dist/application/grammy.d.ts +23 -4
- package/dist/application/grammy.d.ts.map +1 -1
- package/dist/application/kernel-admission.d.ts +11 -0
- package/dist/application/kernel-admission.d.ts.map +1 -1
- package/dist/application/kernel-resource-context.d.ts.map +1 -1
- package/dist/application/resource.d.ts +22 -0
- package/dist/application/resource.d.ts.map +1 -1
- package/dist/entrypoints/agent-runtime/harness.js +1 -1
- package/dist/entrypoints/agent-runtime.js +1 -1
- package/dist/entrypoints/application/grammy.d.ts +2 -1
- package/dist/entrypoints/application/grammy.d.ts.map +1 -1
- package/dist/entrypoints/application/grammy.js +139 -5
- package/dist/entrypoints/application.d.ts +1 -1
- package/dist/entrypoints/application.d.ts.map +1 -1
- package/dist/entrypoints/application.js +1 -1
- package/dist/entrypoints/live.js +6 -1
- package/dist/entrypoints/observability.d.ts +1 -0
- package/dist/entrypoints/observability.d.ts.map +1 -1
- package/dist/entrypoints/observability.js +46 -4
- package/dist/entrypoints/telegram.d.ts +4 -0
- package/dist/entrypoints/telegram.d.ts.map +1 -1
- package/dist/entrypoints/telegram.js +680 -88
- package/dist/entrypoints/testing.js +1 -1
- package/dist/{index-w906953s.js → index-5qn1kx34.js} +48 -0
- package/dist/{index-8zja4pkf.js → index-nts4a2br.js} +5 -1
- package/dist/live/watch-client.d.ts.map +1 -1
- package/dist/observability/json-logger.d.ts +38 -0
- package/dist/observability/json-logger.d.ts.map +1 -0
- package/dist/telegram/bot-api.d.ts +50 -0
- package/dist/telegram/bot-api.d.ts.map +1 -0
- package/dist/telegram/broadcast-state.d.ts +67 -0
- package/dist/telegram/broadcast-state.d.ts.map +1 -0
- package/dist/telegram/broadcast.d.ts +93 -0
- package/dist/telegram/broadcast.d.ts.map +1 -0
- package/dist/telegram/local-files.d.ts +63 -0
- package/dist/telegram/local-files.d.ts.map +1 -0
- package/dist/telegram/operator-channel.d.ts +72 -0
- package/dist/telegram/operator-channel.d.ts.map +1 -0
- package/llms/application-grammy.txt +5 -0
- package/llms/application.2.txt +1 -0
- package/llms/application.txt +51 -13
- package/llms/observability.txt +5 -0
- package/llms/server.4.txt +3 -0
- package/llms/stitchkit.txt +5 -5
- package/llms/telegram.txt +159 -3
- package/llms/{upgrading-0.37.0-0.53.0.txt → upgrading-0.37.0-0.56.0.txt} +130 -3
- package/llms/{upgrading-0.55.0-0.68.0.txt → upgrading-0.57.0-0.69.0.txt} +44 -130
- package/llms/{upgrading-0.69.0-0.95.0.txt → upgrading-0.70.0-0.96.0.txt} +40 -44
- package/llms/upgrading.txt +3 -3
- package/llms-full.txt +265 -23
- package/llms.txt +10 -9
- package/package.json +1 -1
package/llms/observability.txt
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
Contains: Guide: Observability (docs/guide/observability.md) · API reference: `stitchkit/observability` (docs/api/reference.md)
|
|
7
7
|
|
|
8
|
+
Also read:
|
|
9
|
+
- see `llms/telegram.txt` for the Telegram bots guide
|
|
10
|
+
|
|
8
11
|
==============================================================================
|
|
9
12
|
# Guide: Observability (docs/guide/observability.md)
|
|
10
13
|
==============================================================================
|
|
@@ -831,6 +834,8 @@ audit event. See the [Observability guide](../guide/observability.md).
|
|
|
831
834
|
| `DimensionCollision` / `SetRequestDimensionsOptions` | _type_ | explicit overwrite, preserve or error policy for dimension keys |
|
|
832
835
|
| `createBoundedLogger` | function | decorate a `StitchLogger` with request context, shared sanitisation, redaction and total bounds |
|
|
833
836
|
| `DEFAULT_REDACT_PATHS` | constant | baseline credential/token paths added to the sanitizer's sensitive-key policy |
|
|
837
|
+
| `createJsonLogger` | function | the process journal: one JSON line per call in pino's shape (numeric `level`, epoch `time`, `msg`) on standard output, through `createBoundedLogger` — an `Error` in any field keeps name, message, stack and cause; secrets masked; `level` threshold, static `fields`, injectable `write` |
|
|
838
|
+
| `JsonLoggerOptions` / `JsonLogLevel` / `JSON_LOG_LEVELS` | _type_ / constant | the bounded-logger options plus `level`, `fields`, `write`, `now`; pino's numbers `debug` 20 … `error` 50, which a line reader matches on |
|
|
834
839
|
| `BoundedLoggerBounds` / `BoundedLoggerOptions` | _type_ | per-value and total record ceilings (`stringLengthByKey` raises the string bound for named keys such as `stack`) plus sink/redaction configuration |
|
|
835
840
|
| `RequestEvent` | _type_ | the normalised audit event handed to the sink; opt-in HTTP cancellation rows carry `outcome: 'cancelled'` |
|
|
836
841
|
| `runUnitOfWork` / `RunUnitOfWorkOptions` | function / _type_ | run work that did not arrive over a transport — an agent loop, a scheduled broadcast — inside one context, with the same completion record a request gets |
|
package/llms/server.4.txt
CHANGED
|
@@ -386,6 +386,9 @@ and our payload is wrong, which is the case a list of substrings quietly counts
|
|
|
386
386
|
against the user. An unrecognised refusal leaves the recipient reachable: losing
|
|
387
387
|
a working subscriber forever costs more than one wasted send.
|
|
388
388
|
|
|
389
|
+
The rest of what a bot is assembled from — its resources, journal, operator
|
|
390
|
+
channel, broadcasts and local Bot API files — is in [Telegram bots](telegram.md).
|
|
391
|
+
|
|
389
392
|
## Cookies
|
|
390
393
|
|
|
391
394
|
```ts
|
package/llms/stitchkit.txt
CHANGED
|
@@ -69,7 +69,7 @@ own, recorded as an ADR.
|
|
|
69
69
|
| `stitchkit/cli` | server | stable | `createCli` — the CLI transport, light (no MCP SDK / `ai`) |
|
|
70
70
|
| `stitchkit/remote` | browser **and** server | stable | peer-free `implementRemote` for thin HTTP proxy processes |
|
|
71
71
|
| `stitchkit/files` | server (Bun or Node) | stable | peer-free managed local-file boundary |
|
|
72
|
-
| `stitchkit/telegram` | server (Bun or Node) | evolving | peer-free Telegram platform primitives — Mini App `initData` verification and Bot API
|
|
72
|
+
| `stitchkit/telegram` | server (Bun or Node) | evolving | peer-free Telegram platform primitives — Mini App `initData` verification, send-failure classification, resumable broadcasts, the operator channel and local Bot API files |
|
|
73
73
|
| `stitchkit/tracking` | browser **and** server | evolving | visitor-tracking mechanics — `createTrackingClient`, the tab-shared outbox, the page-leave beacon, attribution, the contract factory; no event vocabulary, no React |
|
|
74
74
|
| `stitchkit/tracking/server` | server (Bun or Node) | evolving | the decisions a tracking backend makes — dispositions, visit lease over an application-owned store, active intervals, presence; no database |
|
|
75
75
|
| `stitchkit/release` | browser **and** server | evolving | a page follows the release it was built for — `createReleaseMarker` on the server, `createReleaseWatcher` in the browser, the `X-Build-Id` header and a socket event between them |
|
|
@@ -77,11 +77,11 @@ own, recorded as an ADR.
|
|
|
77
77
|
| `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
|
|
78
78
|
| `stitchkit/oauth` | browser **and** server | evolving | provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics |
|
|
79
79
|
| `stitchkit/google` | server (Bun or Node) | evolving | optional Google code exchange and verified OIDC identity adapter |
|
|
80
|
-
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the
|
|
80
|
+
| `stitchkit/observability` | server | stable<br>_redefined in 2 of the 41 minors since 0.56.2, most recently 0.92.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
|
|
81
81
|
| `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler, plus the managed-resource conformance kit |
|
|
82
82
|
| `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
|
|
83
83
|
| `stitchkit/react` | browser + server rendering | stable | `createCursorQuery`, `createCacheBridge`, QueryClient and `ApiError` retry policy |
|
|
84
|
-
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 21 of the
|
|
84
|
+
| `stitchkit/agent-runtime` | server | evolving<br>_redefined in 21 of the 41 minors since 0.56.2, most recently 0.94.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
|
|
85
85
|
| `stitchkit/agent-runtime/sandbox` | server | evolving | optional Linux Bubblewrap sessions, durable workspaces and a host HTTP credential gateway; see [sandbox guide](sandbox.md) |
|
|
86
86
|
| `stitchkit/agent-runtime/testing` | tests on Bun or Node | evolving | credential-free replay, scripted provider faults, deterministic race controls and the agent-store conformance kit |
|
|
87
87
|
| `stitchkit/agent-runtime/harness` | server | evolving | resource-aware process-local facade over the canonical Agent runtime; supervision stays outside |
|
|
@@ -91,8 +91,8 @@ own, recorded as an ADR.
|
|
|
91
91
|
| `stitchkit/agent-runtime/sqlite/bun` | server (Bun) | evolving | durable built-in SQLite store for the agent runtime |
|
|
92
92
|
| `stitchkit/agent-runtime/sqlite/node` | server (Node ≥ 22.5) | evolving | durable built-in SQLite store for the agent runtime |
|
|
93
93
|
| `stitchkit-tui` | terminal (Bun) | evolving | optional official OpenTUI host over a caller-composed headless runtime |
|
|
94
|
-
| `stitchkit/application` | browser + server | evolving<br>_redefined in
|
|
95
|
-
| `stitchkit/application/grammy` | server | evolving |
|
|
94
|
+
| `stitchkit/application` | browser + server | evolving<br>_redefined in 9 of the 41 minors since 0.56.2, most recently 0.96.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
|
|
95
|
+
| `stitchkit/application/grammy` | server | evolving | a grammY bot as application resources — configuration, then polling with updates admitted by batch — and the webhook adapter |
|
|
96
96
|
| `stitchkit/application/opentelemetry` | server | evolving | maps application snapshots onto an injected OpenTelemetry `Meter` |
|
|
97
97
|
| `stitchkit/application/schemas` | browser + server | evolving | the application's snapshot, health and shutdown schemas alone, without the kernel |
|
|
98
98
|
| `stitchkit/application/diagnostic-journal` | server | evolving | the local diagnostic journal — the one part of the kernel that spawns, locks and writes files |
|
package/llms/telegram.txt
CHANGED
|
@@ -3,7 +3,152 @@
|
|
|
3
3
|
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
4
|
> `llms.txt` in this package.
|
|
5
5
|
|
|
6
|
-
Contains: API reference: `stitchkit/telegram` (docs/api/reference.md)
|
|
6
|
+
Contains: Guide: Telegram bots (docs/guide/telegram.md) · API reference: `stitchkit/telegram` (docs/api/reference.md)
|
|
7
|
+
|
|
8
|
+
==============================================================================
|
|
9
|
+
# Guide: Telegram bots (docs/guide/telegram.md)
|
|
10
|
+
==============================================================================
|
|
11
|
+
|
|
12
|
+
# Telegram bots
|
|
13
|
+
|
|
14
|
+
`stitchkit/telegram` holds what the Bot API itself asks of every bot, with no
|
|
15
|
+
bot library; `stitchkit/application/grammy` makes a grammY bot a set of
|
|
16
|
+
application resources. Together they are what a bot is assembled from, so that
|
|
17
|
+
a bot's own code is its product and nothing else. A generated bot to start from:
|
|
18
|
+
`bun create stitchkit my-bot --template telegram-bot`. Why it is shaped this
|
|
19
|
+
way: [ADR 0201](../decisions/0201-a-telegram-bot-is-assembled-from-primitives.md).
|
|
20
|
+
|
|
21
|
+
| Job | Where |
|
|
22
|
+
|---|---|
|
|
23
|
+
| the bot as resources: command menu, then long polling with updates admitted by batch | `grammyBotResources` — [application kernel](application-kernel.md#optional-grammy-adapter) |
|
|
24
|
+
| the process journal | `createJsonLogger` from `stitchkit/observability` |
|
|
25
|
+
| the operator's chat: product events, apart from the journal | `createTelegramOperatorChannel` |
|
|
26
|
+
| a broadcast that survives crashes, deploys and Ctrl-C | `runTelegramBroadcast` |
|
|
27
|
+
| a file the local Bot API server wrote to disk | `createTelegramLocalFiles` |
|
|
28
|
+
| why a send was refused | `classifyTelegramSendFailure` — [auth and errors](auth-and-errors.md#telegram-mini-apps) |
|
|
29
|
+
| Mini App `initData` | `verifyTelegramInitData` — [auth and errors](auth-and-errors.md#telegram-mini-apps) |
|
|
30
|
+
| one Bot API call without a bot library | `callTelegramBotApi` |
|
|
31
|
+
|
|
32
|
+
## The journal
|
|
33
|
+
|
|
34
|
+
A bot's journal is `createJsonLogger`: one JSON object per line on standard
|
|
35
|
+
output, in pino's shape — numeric `level` (`debug` 20, `info` 30, `warn` 40,
|
|
36
|
+
`error` 50), `time` in epoch milliseconds, `msg` — so `pino-pretty` reads it on
|
|
37
|
+
a terminal and a supervisor matching `"level":50` sees errors. Unlike pino, an
|
|
38
|
+
`Error` under *any* key is written with its name, message, stack and cause; an
|
|
39
|
+
error logged as `{ error }` does not become `"error":{}`.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { createJsonLogger } from 'stitchkit/observability'
|
|
43
|
+
import { TELEGRAM_BOT_TOKEN_PATTERN } from 'stitchkit/telegram'
|
|
44
|
+
|
|
45
|
+
export const logger = createJsonLogger({
|
|
46
|
+
level: env.LOG_LEVEL,
|
|
47
|
+
fields: { service: 'my-bot' },
|
|
48
|
+
sensitiveUrlPatterns: [TELEGRAM_BOT_TOKEN_PATTERN],
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
logger.error('Application startup failed', { error })
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The error line contract, for whatever recognises a failure from the journal: a
|
|
55
|
+
line whose `level` is `50` or more is an error. There is no separate `fatal`;
|
|
56
|
+
an unrecoverable end is an `error` line followed by a non-zero exit.
|
|
57
|
+
|
|
58
|
+
## The operator channel
|
|
59
|
+
|
|
60
|
+
The chat where people read about new users, payments and failures is not the
|
|
61
|
+
journal. The journal must not lose a line to a slow network; the chat must not
|
|
62
|
+
slow the bot down. `post` returns at once and never throws; sends are paced
|
|
63
|
+
below Telegram's per-chat limit (one every 3 s by default), 429s wait the time
|
|
64
|
+
Telegram named, and when the chat cannot keep up the oldest message is dropped
|
|
65
|
+
and reported.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { createTelegramOperatorChannel, telegramOperatorSender } from 'stitchkit/telegram'
|
|
69
|
+
|
|
70
|
+
const operators = createTelegramOperatorChannel<'users' | 'payments' | 'errors'>({
|
|
71
|
+
chatId: env.OPERATOR_CHAT_ID,
|
|
72
|
+
topics: { users: 2, payments: 3, errors: 4 }, // forum message_thread_id
|
|
73
|
+
send: telegramOperatorSender({ token: env.BOT_TOKEN }),
|
|
74
|
+
onDropped: (drop) => logger.warn('Operator message dropped', { ...drop }),
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
operators.post(`New user ${user.id}`, 'users')
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
What to post stays the bot's. On the way down, drain it within the grace period
|
|
81
|
+
and close it: `drain: (context) => operators.drain(context.signal)`,
|
|
82
|
+
`close: () => operators.close()` in a resource.
|
|
83
|
+
|
|
84
|
+
## Broadcasts
|
|
85
|
+
|
|
86
|
+
A broadcast is a job with an end, so it is a function, not a resource:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { runTelegramBroadcast, telegramBroadcastSender } from 'stitchkit/telegram'
|
|
90
|
+
|
|
91
|
+
const report = await runTelegramBroadcast({
|
|
92
|
+
name: '2026-04-28-price-lock',
|
|
93
|
+
directory: env.STATE_DIRECTORY, // a state root, never the release tree
|
|
94
|
+
recipients: () => audience.activeSubscribers(),
|
|
95
|
+
send: telegramBroadcastSender({
|
|
96
|
+
token: env.BOT_TOKEN,
|
|
97
|
+
message: { copyFrom: { chatId: env.DRAFTS_CHAT_ID, messageId: 42 } },
|
|
98
|
+
}),
|
|
99
|
+
signal: stop.signal,
|
|
100
|
+
onProgress: (progress) => logger.info('Broadcast', { ...progress }),
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- **Resumable by name.** The audience is written once on the first run; running
|
|
105
|
+
the same name again continues with that list. Progress is an append-only
|
|
106
|
+
journal beside it, one line before and one after each send.
|
|
107
|
+
- **Nobody twice.** A send that was in flight when the process died is recorded
|
|
108
|
+
`uncertain` and not repeated. A signal stops between sends, after the one in
|
|
109
|
+
flight is recorded.
|
|
110
|
+
- **Refusals by meaning.** A blocked, deactivated or never-started recipient is
|
|
111
|
+
`unreachable` and never addressed again. A 429 waits Telegram's
|
|
112
|
+
`retry_after` and sends the same recipient again; a server error is retried
|
|
113
|
+
with backoff up to `maxAttempts`, then `failed`. A message Telegram cannot
|
|
114
|
+
parse is not the recipient's fault: the run **halts** with them still pending,
|
|
115
|
+
so the run after the fix reaches them. So does Telegram being unreachable.
|
|
116
|
+
- **Pacing** is `ratePerSecond`, 25 by default. `dryRun` counts and writes
|
|
117
|
+
nothing. One runner per name: a second concurrent run is refused.
|
|
118
|
+
|
|
119
|
+
The same call works from a script (the process's signal) and inside a live
|
|
120
|
+
application (the application's signal, with admission held by the caller).
|
|
121
|
+
The recipient state contains Telegram ids: keep it in the state directory, out
|
|
122
|
+
of git.
|
|
123
|
+
|
|
124
|
+
## Files from a local Bot API server
|
|
125
|
+
|
|
126
|
+
A local `telegram-bot-api` keeps downloaded files under `<dir>/<bot token>/`,
|
|
127
|
+
and a bot sharing that directory reads them from disk and deletes them when
|
|
128
|
+
done. `file_path` comes from a server over the network, so it is resolved only
|
|
129
|
+
inside the bot's directory — `../`, an absolute path elsewhere and a link
|
|
130
|
+
pointing out are refused, judged on real paths.
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { createTelegramLocalFiles } from 'stitchkit/telegram'
|
|
134
|
+
|
|
135
|
+
const files = createTelegramLocalFiles({ root: env.BOT_API_FILES_ROOT, token: env.BOT_TOKEN })
|
|
136
|
+
|
|
137
|
+
const { file_path } = await ctx.getFile()
|
|
138
|
+
const path = await files.resolve(file_path) // throws TelegramLocalFileError
|
|
139
|
+
// … process it …
|
|
140
|
+
await files.remove(file_path)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The recommended variable for the root is **`BOT_API_FILES_ROOT`** — the
|
|
144
|
+
server's `--dir`, absolute, as the bot's process sees it. A relative `file_path`
|
|
145
|
+
(a server without `--local`) and an absolute one inside the bot's directory (a
|
|
146
|
+
server with `--local`) both resolve. A refusal carries a reason
|
|
147
|
+
(`root-not-absolute`, `bot-directory-unavailable`, `outside-bot-directory`,
|
|
148
|
+
`missing`, `not-a-file`) and never the path or the token. `files.check()`
|
|
149
|
+
answers whether the directory is there to read and delete from; a resource that
|
|
150
|
+
throws on `{ ready: false }` in `start` keeps the bot from answering before it
|
|
151
|
+
can read its media.
|
|
7
152
|
|
|
8
153
|
==============================================================================
|
|
9
154
|
# API reference: `stitchkit/telegram` (docs/api/reference.md)
|
|
@@ -11,9 +156,10 @@ Contains: API reference: `stitchkit/telegram` (docs/api/reference.md)
|
|
|
11
156
|
|
|
12
157
|
## `stitchkit/telegram`
|
|
13
158
|
|
|
14
|
-
Peer-free server-only Telegram platform primitives
|
|
159
|
+
Peer-free server-only Telegram platform primitives — the Bot API's own
|
|
160
|
+
protocols and the jobs every bot rewrote around them. Importing this resolves no
|
|
15
161
|
bot library; `stitchkit/application/grammy` remains the lifecycle adapter for an
|
|
16
|
-
injected grammY bot. → ADR 0143
|
|
162
|
+
injected grammY bot. → ADR 0143, ADR 0201 — [guide](../guide/telegram.md)
|
|
17
163
|
|
|
18
164
|
| Export | Kind | Summary |
|
|
19
165
|
|--------|------|---------|
|
|
@@ -26,5 +172,15 @@ injected grammY bot. → ADR 0143
|
|
|
26
172
|
| `classifyTelegramSendFailure` | function | name a refused Bot API send and separate "retry this send" from "stop addressing this recipient" |
|
|
27
173
|
| `TelegramSendFailure` | _type_ | reason, `status`, Telegram-stated `retryAfterSeconds`, `retryable`, `recipientUnreachable` and which evidence produced the answer |
|
|
28
174
|
| `TelegramSendFailureReason` | _type_ | `blocked-by-user` / `user-deactivated` / `chat-not-found` / `not-started` / `rate-limited` / `message-invalid` / `server-error` / `unknown` |
|
|
175
|
+
| `runTelegramBroadcast` | function | a resumable broadcast by `name` under a state `directory`: audience written once, an append-only journal, pacing at `ratePerSecond` (25), 429 waits `retry_after`, unreachable recipients never addressed again, a `message-invalid` or unreachable Telegram halts without charging the recipient, a send in flight at a crash is `uncertain` and not repeated, `dryRun`, one runner per name |
|
|
176
|
+
| `TelegramBroadcastConfig` / `TelegramBroadcastSend` / `TelegramBroadcastReport` / `TelegramBroadcastRunOutcome` / `TelegramBroadcastOutcome` / `TelegramBroadcastRecipient` | _type_ | `name`, `directory`, `recipients()`, `send({ recipient, attempt })`, `maxAttempts`, `signal`, `onProgress`; counts `delivered` / `unreachable` / `failed` / `uncertain` / `pending` and `finished` / `stopped` / `halted` / `dry-run` |
|
|
177
|
+
| `telegramBroadcastSender` / `TelegramBroadcastSenderConfig` / `TelegramBroadcastMessage` | function / _type_ | the standard `send`: `sendMessage` with a text or `copyMessage` of a prepared message, through the Bot API |
|
|
178
|
+
| `createTelegramOperatorChannel` | function | the operator chat, apart from the journal: `post(text, topic?)` returns at once and never throws; paced sends into forum topics, 429 honoured, oldest dropped on overflow, `drain(signal)` and `close()` for the way down |
|
|
179
|
+
| `TelegramOperatorChannelConfig` / `TelegramOperatorChannel` / `TelegramOperatorMessage` / `TelegramOperatorDrop` / `TelegramChatId` | _type_ | `chatId`, `topics`, `send`, `maxQueued`, `minIntervalMs`, `maxAttempts`, `onDropped`; a drop is `overflow` / `refused` / `attempts` / `closed` with its classification |
|
|
180
|
+
| `telegramOperatorSender` / `TelegramOperatorSenderConfig` | function / _type_ | the standard `send`: `sendMessage` into the chat and topic, plain text unless `parseMode` |
|
|
181
|
+
| `createTelegramLocalFiles` | function | files the local Bot API server wrote under `<root>/<token>/`: `resolve(file_path)` and `remove(file_path)` only inside the bot's directory, judged on real paths so a link is judged by where it leads; `check()` for readiness. Recommended root variable: `BOT_API_FILES_ROOT` |
|
|
182
|
+
| `TelegramLocalFilesConfig` / `TelegramLocalFiles` / `TelegramLocalFilesCheck` / `TelegramLocalFileError` / `TelegramLocalFileRefusal` | _type_ / class | `root`, `token`; refusals `root-not-absolute` / `bot-directory-unavailable` / `outside-bot-directory` / `missing` / `not-a-file`, never carrying the path or the token |
|
|
183
|
+
| `callTelegramBotApi` / `TelegramBotApiCall` / `TelegramBotApiError` | function / _type_ / class | one Bot API method over `fetch`; a refusal keeps `error_code`, `description` and `parameters` for the classifier, and no error names the URL |
|
|
184
|
+
| `TELEGRAM_BOT_TOKEN_PATTERN` | constant | the shape of a bot token, for a logger's `sensitiveUrlPatterns` |
|
|
29
185
|
|
|
30
186
|
---
|
|
@@ -1,14 +1,141 @@
|
|
|
1
|
-
# Upgrading 0.37.0 → 0.
|
|
1
|
+
# Upgrading 0.37.0 → 0.56.0 — stitchkit docs slice
|
|
2
2
|
|
|
3
3
|
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
4
|
> `llms.txt` in this package.
|
|
5
5
|
|
|
6
|
-
Contains: Guide: Upgrading, 0.37.0 → 0.
|
|
6
|
+
Contains: Guide: Upgrading, 0.37.0 → 0.56.0 (docs/guide/upgrading.md)
|
|
7
7
|
|
|
8
8
|
==============================================================================
|
|
9
|
-
# Guide: Upgrading, 0.37.0 → 0.
|
|
9
|
+
# Guide: Upgrading, 0.37.0 → 0.56.0 (docs/guide/upgrading.md)
|
|
10
10
|
==============================================================================
|
|
11
11
|
|
|
12
|
+
## Released migration: 0.56.0
|
|
13
|
+
|
|
14
|
+
### Surface manifests are version 2
|
|
15
|
+
|
|
16
|
+
`operation.tools` could not describe a role-selected MCP surface, a different
|
|
17
|
+
Agent or CLI selection, or an advertised `extend` schema, so projections moved
|
|
18
|
+
out of the canonical operation:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
// before
|
|
22
|
+
manifest.operations[0].tools.MCP
|
|
23
|
+
// after
|
|
24
|
+
manifest.toolSurfaces.find((s) => s.transport === 'MCP' && s.surface === null)?.tools
|
|
25
|
+
|
|
26
|
+
// before
|
|
27
|
+
buildSurfaceManifest({ mcpSurfaces: { admin: { services, extend } } })
|
|
28
|
+
// after
|
|
29
|
+
buildSurfaceManifest({ mcpSurfaces: { admin: { services } }, mcpPreparation: { extend } })
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
A committed snapshot is regenerated once, deliberately: `manifestVersion` is
|
|
33
|
+
`2`, and `ConformanceTransport` gained `REALTIME`, so any exhaustive
|
|
34
|
+
`Record<ConformanceTransport, …>` must handle it.
|
|
35
|
+
|
|
36
|
+
### `FILE_*` codes joined the error registry
|
|
37
|
+
|
|
38
|
+
`StitchErrorCode` gained `FILE_INVALID_PATH`, `FILE_OUTSIDE_ROOT`,
|
|
39
|
+
`FILE_NOT_FOUND`, `FILE_NOT_REGULAR`, `FILE_INSPECTION_REJECTED`,
|
|
40
|
+
`FILE_TOO_LARGE` and `FILE_EXISTS`. Only exhaustive maps break:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// before — compiled while the registry had no file codes
|
|
44
|
+
const copy: Record<StitchErrorCode, string> = { …, RATE_LIMITED: '…' }
|
|
45
|
+
// after — add the seven managed-file codes (or use Partial<Record<…>>)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Unexpected IO stays scrubbed as `INTERNAL_SERVER_ERROR`: the new codes are the
|
|
49
|
+
caller-safe ones only.
|
|
50
|
+
|
|
51
|
+
### `ScopedAuthHook` is nominal
|
|
52
|
+
|
|
53
|
+
A hand-written function shaped like an auth hook is no longer assignable —
|
|
54
|
+
identity now comes from the factory, so scope ownership and the inferred
|
|
55
|
+
context cannot drift apart:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
// before — a structural stand-in
|
|
59
|
+
const auth: ScopedAuthHook<Scopes> = async (ctx, endpoint) => { … }
|
|
60
|
+
// after — create it, then compose domains
|
|
61
|
+
const auth = createAuthHook({ resolve, rules })
|
|
62
|
+
const composed = composeAuthHooks({ hooks: [auth, billingAuth], defaultScope: 'public' })
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Managed-file inspectors also run on reads
|
|
66
|
+
|
|
67
|
+
An inspector is no longer write-only, and it has a finite default deadline
|
|
68
|
+
(15 s). Make it read-aware and idempotent — a read carries no
|
|
69
|
+
`declaredMediaType`:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
// before
|
|
73
|
+
inspect: ({ declaredMediaType }) => inspectDeclaredType(declaredMediaType!)
|
|
74
|
+
// after
|
|
75
|
+
inspect: ({ prefix, declaredMediaType, signal }) =>
|
|
76
|
+
inspectBytes(prefix, { declaredMediaType, signal })
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Set `inspectionTimeoutMs` explicitly when 15 seconds is the wrong budget.
|
|
80
|
+
|
|
81
|
+
### Direct async-operation binding needs a wire-stable ID
|
|
82
|
+
|
|
83
|
+
A direct binding reuses the start output as the follow-up wire input, so the ID
|
|
84
|
+
schema must parse to itself (`z.input` equals `z.output`, no transform,
|
|
85
|
+
coercion, default or overwrite). Anything else is parsed twice:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
// before — a transform silently ran on start and again on every follow-up
|
|
89
|
+
defineAsyncOperationContract({ binding: 'direct', id: z.string().transform(Number) })
|
|
90
|
+
// after — keep the wire shape, adapt explicitly
|
|
91
|
+
defineAsyncOperationContract({
|
|
92
|
+
binding: 'adapted',
|
|
93
|
+
id,
|
|
94
|
+
adapters: { idFromStart, inputFor },
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Released migration: 0.55.0
|
|
99
|
+
|
|
100
|
+
### Peer-free `implementRemote`
|
|
101
|
+
|
|
102
|
+
`implementRemote` now has one canonical, optional-peer-free owner. This keeps
|
|
103
|
+
MCP SDK and AI SDK modules out of CLI bundles that only proxy HTTP calls:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
// before
|
|
107
|
+
import { implementRemote } from 'stitchkit/tools'
|
|
108
|
+
// after
|
|
109
|
+
import { implementRemote } from 'stitchkit/remote'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Managed file boundary and strict auth returns
|
|
113
|
+
|
|
114
|
+
Create one boundary during application bootstrap and pass the capability, never
|
|
115
|
+
a per-call directory or host path:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { createManagedFileBoundary } from 'stitchkit/files'
|
|
119
|
+
|
|
120
|
+
const files = await createManagedFileBoundary({ root: '/srv/app-files' })
|
|
121
|
+
|
|
122
|
+
// before
|
|
123
|
+
defineDownloadTool({ defaultDir: '/srv/app-files', resolveUrl, ...common })
|
|
124
|
+
defineUploadTool({ upload: (path) => provider.uploadFile(path), ...common })
|
|
125
|
+
defineViewFileTool({ baseDir: '/srv/app-files', ...common })
|
|
126
|
+
|
|
127
|
+
// after
|
|
128
|
+
defineDownloadTool({ files, resolveUrl, ...common })
|
|
129
|
+
defineUploadTool({ files, upload: ({ bytes }) => provider.upload(bytes), ...common })
|
|
130
|
+
defineViewFileTool({ files, ...common })
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Downloaded `path` is now relative to the boundary and MIME metadata is named
|
|
134
|
+
`mediaType`. Update raw `mountDownload`/`mountUpload`/`mountViewFile` configs the
|
|
135
|
+
same way. Auth predicates must explicitly return `true`, `false`, or a plain
|
|
136
|
+
object of context fields; replace accidental `undefined` fallthroughs with the
|
|
137
|
+
intended boolean.
|
|
138
|
+
|
|
12
139
|
## Released migration: 0.53.0
|
|
13
140
|
|
|
14
141
|
### Realtime `emit` returns `boolean` instead of `void`
|
|
@@ -1,14 +1,55 @@
|
|
|
1
|
-
# Upgrading 0.
|
|
1
|
+
# Upgrading 0.57.0 → 0.69.0 — stitchkit docs slice
|
|
2
2
|
|
|
3
3
|
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
4
|
> `llms.txt` in this package.
|
|
5
5
|
|
|
6
|
-
Contains: Guide: Upgrading, 0.
|
|
6
|
+
Contains: Guide: Upgrading, 0.57.0 → 0.69.0 (docs/guide/upgrading.md)
|
|
7
7
|
|
|
8
8
|
==============================================================================
|
|
9
|
-
# Guide: Upgrading, 0.
|
|
9
|
+
# Guide: Upgrading, 0.57.0 → 0.69.0 (docs/guide/upgrading.md)
|
|
10
10
|
==============================================================================
|
|
11
11
|
|
|
12
|
+
## Released migration: 0.69.0
|
|
13
|
+
|
|
14
|
+
### Direct coding-tool operation names
|
|
15
|
+
|
|
16
|
+
`createAgentCodingTools` no longer prefixes durable operation identity with `coding_`, and the
|
|
17
|
+
unguarded exact-string edit tool is gone. Update approval maps, presenters and tests together:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// before
|
|
21
|
+
{ coding_read_file: 'approved', coding_search: 'approved', coding_patch_file: 'user-approval' }
|
|
22
|
+
|
|
23
|
+
// after
|
|
24
|
+
{ read_file: 'approved', search_files: 'approved', apply_patch: 'user-approval' }
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The full mapping is `coding_read_file → read_file`, `coding_write_file → write_file`,
|
|
28
|
+
`coding_search → search_files`, `coding_patch_file → apply_patch`, `coding_shell → run_command`,
|
|
29
|
+
`coding_read_artifact → read_output` and `harness_read_resource → read_resource`. Replace
|
|
30
|
+
`coding_edit_file` with `read_file` followed by guarded `apply_patch`; `read_file` now returns the
|
|
31
|
+
required SHA-256. If the host declares no executable aliases, expect `run_command` to be absent.
|
|
32
|
+
|
|
33
|
+
### Durable Agent approval message variants
|
|
34
|
+
|
|
35
|
+
If a renderer, store adapter or export pipeline exhaustively switches over
|
|
36
|
+
`AgentMessage.role`, add the `tool` branch. If it switches over
|
|
37
|
+
`AgentMessagePart.type`, add `tool-approval-request` and `tool-approval-response`.
|
|
38
|
+
They are durable provider-continuation evidence: preserve them in storage and provider history;
|
|
39
|
+
a UI may render them as approval state or intentionally omit their visual row.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
// before
|
|
43
|
+
const unreachable: never = message.role
|
|
44
|
+
|
|
45
|
+
// after
|
|
46
|
+
if (message.role === 'tool') renderToolContinuation(message.parts)
|
|
47
|
+
else renderExistingRole(message)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
No data migration is needed. The schema still accepts all earlier records, and applications that
|
|
51
|
+
do not exhaustively branch over these unions compile unchanged.
|
|
52
|
+
|
|
12
53
|
## Released migration: 0.68.0
|
|
13
54
|
|
|
14
55
|
### Make Unix transport selection explicit outside Bun
|
|
@@ -1073,130 +1114,3 @@ The consequence for an exhaustive switch written without a `default` branch is a
|
|
|
1073
1114
|
compile error, which is the point. The consequence for a switch that *has* a
|
|
1074
1115
|
`default` is worse and silent: post-commit admissions fall into it and are
|
|
1075
1116
|
projected as an unknown event. Grep for publisher switches before upgrading.
|
|
1076
|
-
|
|
1077
|
-
## Released migration: 0.56.0
|
|
1078
|
-
|
|
1079
|
-
### Surface manifests are version 2
|
|
1080
|
-
|
|
1081
|
-
`operation.tools` could not describe a role-selected MCP surface, a different
|
|
1082
|
-
Agent or CLI selection, or an advertised `extend` schema, so projections moved
|
|
1083
|
-
out of the canonical operation:
|
|
1084
|
-
|
|
1085
|
-
```ts
|
|
1086
|
-
// before
|
|
1087
|
-
manifest.operations[0].tools.MCP
|
|
1088
|
-
// after
|
|
1089
|
-
manifest.toolSurfaces.find((s) => s.transport === 'MCP' && s.surface === null)?.tools
|
|
1090
|
-
|
|
1091
|
-
// before
|
|
1092
|
-
buildSurfaceManifest({ mcpSurfaces: { admin: { services, extend } } })
|
|
1093
|
-
// after
|
|
1094
|
-
buildSurfaceManifest({ mcpSurfaces: { admin: { services } }, mcpPreparation: { extend } })
|
|
1095
|
-
```
|
|
1096
|
-
|
|
1097
|
-
A committed snapshot is regenerated once, deliberately: `manifestVersion` is
|
|
1098
|
-
`2`, and `ConformanceTransport` gained `REALTIME`, so any exhaustive
|
|
1099
|
-
`Record<ConformanceTransport, …>` must handle it.
|
|
1100
|
-
|
|
1101
|
-
### `FILE_*` codes joined the error registry
|
|
1102
|
-
|
|
1103
|
-
`StitchErrorCode` gained `FILE_INVALID_PATH`, `FILE_OUTSIDE_ROOT`,
|
|
1104
|
-
`FILE_NOT_FOUND`, `FILE_NOT_REGULAR`, `FILE_INSPECTION_REJECTED`,
|
|
1105
|
-
`FILE_TOO_LARGE` and `FILE_EXISTS`. Only exhaustive maps break:
|
|
1106
|
-
|
|
1107
|
-
```ts
|
|
1108
|
-
// before — compiled while the registry had no file codes
|
|
1109
|
-
const copy: Record<StitchErrorCode, string> = { …, RATE_LIMITED: '…' }
|
|
1110
|
-
// after — add the seven managed-file codes (or use Partial<Record<…>>)
|
|
1111
|
-
```
|
|
1112
|
-
|
|
1113
|
-
Unexpected IO stays scrubbed as `INTERNAL_SERVER_ERROR`: the new codes are the
|
|
1114
|
-
caller-safe ones only.
|
|
1115
|
-
|
|
1116
|
-
### `ScopedAuthHook` is nominal
|
|
1117
|
-
|
|
1118
|
-
A hand-written function shaped like an auth hook is no longer assignable —
|
|
1119
|
-
identity now comes from the factory, so scope ownership and the inferred
|
|
1120
|
-
context cannot drift apart:
|
|
1121
|
-
|
|
1122
|
-
```ts
|
|
1123
|
-
// before — a structural stand-in
|
|
1124
|
-
const auth: ScopedAuthHook<Scopes> = async (ctx, endpoint) => { … }
|
|
1125
|
-
// after — create it, then compose domains
|
|
1126
|
-
const auth = createAuthHook({ resolve, rules })
|
|
1127
|
-
const composed = composeAuthHooks({ hooks: [auth, billingAuth], defaultScope: 'public' })
|
|
1128
|
-
```
|
|
1129
|
-
|
|
1130
|
-
### Managed-file inspectors also run on reads
|
|
1131
|
-
|
|
1132
|
-
An inspector is no longer write-only, and it has a finite default deadline
|
|
1133
|
-
(15 s). Make it read-aware and idempotent — a read carries no
|
|
1134
|
-
`declaredMediaType`:
|
|
1135
|
-
|
|
1136
|
-
```ts
|
|
1137
|
-
// before
|
|
1138
|
-
inspect: ({ declaredMediaType }) => inspectDeclaredType(declaredMediaType!)
|
|
1139
|
-
// after
|
|
1140
|
-
inspect: ({ prefix, declaredMediaType, signal }) =>
|
|
1141
|
-
inspectBytes(prefix, { declaredMediaType, signal })
|
|
1142
|
-
```
|
|
1143
|
-
|
|
1144
|
-
Set `inspectionTimeoutMs` explicitly when 15 seconds is the wrong budget.
|
|
1145
|
-
|
|
1146
|
-
### Direct async-operation binding needs a wire-stable ID
|
|
1147
|
-
|
|
1148
|
-
A direct binding reuses the start output as the follow-up wire input, so the ID
|
|
1149
|
-
schema must parse to itself (`z.input` equals `z.output`, no transform,
|
|
1150
|
-
coercion, default or overwrite). Anything else is parsed twice:
|
|
1151
|
-
|
|
1152
|
-
```ts
|
|
1153
|
-
// before — a transform silently ran on start and again on every follow-up
|
|
1154
|
-
defineAsyncOperationContract({ binding: 'direct', id: z.string().transform(Number) })
|
|
1155
|
-
// after — keep the wire shape, adapt explicitly
|
|
1156
|
-
defineAsyncOperationContract({
|
|
1157
|
-
binding: 'adapted',
|
|
1158
|
-
id,
|
|
1159
|
-
adapters: { idFromStart, inputFor },
|
|
1160
|
-
})
|
|
1161
|
-
```
|
|
1162
|
-
|
|
1163
|
-
## Released migration: 0.55.0
|
|
1164
|
-
|
|
1165
|
-
### Peer-free `implementRemote`
|
|
1166
|
-
|
|
1167
|
-
`implementRemote` now has one canonical, optional-peer-free owner. This keeps
|
|
1168
|
-
MCP SDK and AI SDK modules out of CLI bundles that only proxy HTTP calls:
|
|
1169
|
-
|
|
1170
|
-
```ts
|
|
1171
|
-
// before
|
|
1172
|
-
import { implementRemote } from 'stitchkit/tools'
|
|
1173
|
-
// after
|
|
1174
|
-
import { implementRemote } from 'stitchkit/remote'
|
|
1175
|
-
```
|
|
1176
|
-
|
|
1177
|
-
### Managed file boundary and strict auth returns
|
|
1178
|
-
|
|
1179
|
-
Create one boundary during application bootstrap and pass the capability, never
|
|
1180
|
-
a per-call directory or host path:
|
|
1181
|
-
|
|
1182
|
-
```ts
|
|
1183
|
-
import { createManagedFileBoundary } from 'stitchkit/files'
|
|
1184
|
-
|
|
1185
|
-
const files = await createManagedFileBoundary({ root: '/srv/app-files' })
|
|
1186
|
-
|
|
1187
|
-
// before
|
|
1188
|
-
defineDownloadTool({ defaultDir: '/srv/app-files', resolveUrl, ...common })
|
|
1189
|
-
defineUploadTool({ upload: (path) => provider.uploadFile(path), ...common })
|
|
1190
|
-
defineViewFileTool({ baseDir: '/srv/app-files', ...common })
|
|
1191
|
-
|
|
1192
|
-
// after
|
|
1193
|
-
defineDownloadTool({ files, resolveUrl, ...common })
|
|
1194
|
-
defineUploadTool({ files, upload: ({ bytes }) => provider.upload(bytes), ...common })
|
|
1195
|
-
defineViewFileTool({ files, ...common })
|
|
1196
|
-
```
|
|
1197
|
-
|
|
1198
|
-
Downloaded `path` is now relative to the boundary and MIME metadata is named
|
|
1199
|
-
`mediaType`. Update raw `mountDownload`/`mountUpload`/`mountViewFile` configs the
|
|
1200
|
-
same way. Auth predicates must explicitly return `true`, `false`, or a plain
|
|
1201
|
-
object of context fields; replace accidental `undefined` fallthroughs with the
|
|
1202
|
-
intended boolean.
|