stitchkit 0.108.5 → 0.109.1
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 +47 -0
- package/dist/browser/cancellation.d.ts +4 -5
- package/dist/browser/cancellation.d.ts.map +1 -1
- package/dist/browser/client-executors.d.ts.map +1 -1
- package/dist/browser/client.d.ts +1 -1
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/browser/http.d.ts +1 -1
- package/dist/browser/http.d.ts.map +1 -1
- package/dist/browser/session.d.ts +1 -1
- package/dist/browser/session.d.ts.map +1 -1
- package/dist/browser/transport.d.ts +1 -1
- package/dist/browser/transport.d.ts.map +1 -1
- package/dist/entrypoints/cli.js +1 -1
- package/dist/entrypoints/index.js +2 -2
- package/dist/entrypoints/react.js +1 -1
- package/dist/entrypoints/remote.js +2 -2
- package/dist/entrypoints/telegram.d.ts +2 -2
- package/dist/entrypoints/telegram.d.ts.map +1 -1
- package/dist/entrypoints/telegram.js +868 -137
- package/dist/entrypoints/testing.js +2 -2
- package/dist/entrypoints/tools.js +1 -1
- package/dist/{index-7jvwrjqa.js → index-00v1qz76.js} +20 -17
- package/dist/{index-05s01c94.js → index-5cw390s6.js} +96 -16
- package/dist/{index-p5kx5vqd.js → index-e32vy8jw.js} +22 -11
- package/dist/telegram/update-intake-work.d.ts +39 -0
- package/dist/telegram/update-intake-work.d.ts.map +1 -0
- package/dist/telegram/update-intake.d.ts +47 -9
- package/dist/telegram/update-intake.d.ts.map +1 -1
- package/dist/telegram/update-store-check.d.ts.map +1 -1
- package/dist/telegram/update-store-postgres.d.ts +2 -2
- package/dist/telegram/update-store-postgres.d.ts.map +1 -1
- package/dist/telegram/update-store-sqlite.d.ts +2 -2
- package/dist/telegram/update-store-sqlite.d.ts.map +1 -1
- package/dist/telegram/update-store.d.ts +52 -3
- package/dist/telegram/update-store.d.ts.map +1 -1
- package/dist/tools/cli/args-fields.d.ts +7 -1
- package/dist/tools/cli/args-fields.d.ts.map +1 -1
- package/dist/tools/cli/args.d.ts.map +1 -1
- package/llms/cli.txt +9 -1
- package/llms/stitchkit.txt +10 -3
- package/llms/telegram.txt +59 -8
- package/llms/{upgrading-0.100.0-0.108.0.txt → upgrading-0.101.0-0.109.0.txt} +70 -72
- package/llms/upgrading-0.37.0.txt +176 -0
- package/llms/{upgrading-0.37.0-0.58.0.txt → upgrading-0.44.0-0.60.0.txt} +229 -169
- package/llms/{upgrading-0.59.0-0.71.0.txt → upgrading-0.61.0-0.73.0.txt} +122 -229
- package/llms/{upgrading-0.72.0-0.99.0.txt → upgrading-0.74.0-0.100.0.txt} +72 -122
- package/llms/upgrading.txt +5 -4
- package/llms-full.txt +145 -12
- package/llms.txt +9 -8
- package/package.json +1 -1
|
@@ -1,14 +1,133 @@
|
|
|
1
|
-
# Upgrading 0.
|
|
1
|
+
# Upgrading 0.61.0 → 0.73.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.61.0 → 0.73.0 (docs/guide/upgrading.md)
|
|
7
7
|
|
|
8
8
|
==============================================================================
|
|
9
|
-
# Guide: Upgrading, 0.
|
|
9
|
+
# Guide: Upgrading, 0.61.0 → 0.73.0 (docs/guide/upgrading.md)
|
|
10
10
|
==============================================================================
|
|
11
11
|
|
|
12
|
+
## Released migration: 0.73.0
|
|
13
|
+
|
|
14
|
+
Two breaking changes. Nothing you send to a server changed, and only one of these
|
|
15
|
+
can reach a call site the compiler already checks.
|
|
16
|
+
|
|
17
|
+
### If you call `withOptions` from a call site that lost its types
|
|
18
|
+
|
|
19
|
+
`withOptions` takes one argument on an endpoint with no contract input, two when
|
|
20
|
+
there is one. Passing two to a no-input endpoint used to succeed and silently
|
|
21
|
+
drop the options: the request went out **uncancelled**, the caller still received
|
|
22
|
+
`REQUEST_ABORTED` — cancellation is decided from the signal it was handed, not
|
|
23
|
+
from what the transport did — and the server ran the operation to its own
|
|
24
|
+
deadline. Every symptom then points at the transport, and the investigation goes
|
|
25
|
+
there. It now throws a `TypeError` naming the endpoint and the correct shape.
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
// before — the options were dropped and the request was never cancelled
|
|
29
|
+
api.ping.withOptions({}, { signal })
|
|
30
|
+
|
|
31
|
+
// after
|
|
32
|
+
api.ping.withOptions({ signal })
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
A typed call site already refused the wrong arity, so this reaches only code that
|
|
36
|
+
does not have the types: a `Record<string, …>` view of the client, a hand-written
|
|
37
|
+
double, a dynamic dispatch. The guard counts arguments and never reads them, so a
|
|
38
|
+
method handed to a callback API behaves exactly as before.
|
|
39
|
+
|
|
40
|
+
### If you match on `ApiError.message`
|
|
41
|
+
|
|
42
|
+
An `ApiError` that nothing explained used to carry `API Error: ${code}` — a
|
|
43
|
+
string that reads like an explanation while only restating the code, so a caller
|
|
44
|
+
could not tell an origin that explained a failure from one that said nothing. It
|
|
45
|
+
now says which it is.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
// before
|
|
49
|
+
err.message === 'API Error: INVALID_INPUT'
|
|
50
|
+
|
|
51
|
+
// after
|
|
52
|
+
err.message === 'INVALID_INPUT (no message supplied)' // better: match err.code
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Match `err.code` instead: it is the contract, and it did not change. An error
|
|
56
|
+
carrying a real message is untouched. An empty message now counts as no message,
|
|
57
|
+
for the same reason — an empty string is not an explanation either.
|
|
58
|
+
|
|
59
|
+
### If a diagnostic journal lock file is already on disk
|
|
60
|
+
|
|
61
|
+
One operator step, and only on a host that has been **renamed** since its lock was written.
|
|
62
|
+
|
|
63
|
+
A lock written before this version carries no machine identity, so there is nothing to compare and
|
|
64
|
+
the host name is all that is left. If the name still matches, the lock reclaims exactly as it always
|
|
65
|
+
did and there is nothing to do. If the name has changed, the lock is `unattributable` and is refused
|
|
66
|
+
— the same refusal this release exists to end, except that this particular file predates the fix and
|
|
67
|
+
cannot be repaired from the inside. Delete it once:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
rm <journal path>.lock # only when the host was renamed since the file was written
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Locks written from this version on carry the machine identity, so the situation cannot recur. To see
|
|
74
|
+
which case you are in without guessing, read the refusal instead of the file:
|
|
75
|
+
`readDiagnosticJournalLockDiagnosis(err)` returns `attribution: 'unattributable'` for exactly this
|
|
76
|
+
one, and `'another-machine'` for a lock that genuinely belongs elsewhere and must **not** be deleted.
|
|
77
|
+
|
|
78
|
+
Two related fixes need no migration, but change what you will see. An error the
|
|
79
|
+
transport raised through `createHttpClient` now carries the transport's own text
|
|
80
|
+
in `message` and the original error as `cause`, where before it carried neither
|
|
81
|
+
and filed the text under `details.message` alone; if you followed the retry rule
|
|
82
|
+
in [the client guide](./client.md) — inspect the adapter's `cause`, retry only
|
|
83
|
+
when it proves dispatch did not happen — that rule was not executable on this
|
|
84
|
+
transport and now is. And the client guide now states which direction validation
|
|
85
|
+
runs: responses are checked against `output`, arguments are **not** checked
|
|
86
|
+
before being sent.
|
|
87
|
+
|
|
88
|
+
## Released migration: 0.72.0
|
|
89
|
+
|
|
90
|
+
Nothing you *pass* changed. Both items are about types you read or build, and
|
|
91
|
+
both stop the compiler rather than surprising you at runtime.
|
|
92
|
+
|
|
93
|
+
### If you read `perKey` off `BoundedAdmissionPolicy`
|
|
94
|
+
|
|
95
|
+
`perKey` is now a union: the flat ceiling it always was, or `{ maxKeys, limits }`
|
|
96
|
+
where the ceiling is resolved from the key. Declaring one is unchanged; reading
|
|
97
|
+
one needs a narrowing.
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
// before
|
|
101
|
+
const ceiling = policy.perKey?.maxConcurrent
|
|
102
|
+
|
|
103
|
+
// after
|
|
104
|
+
const ceiling =
|
|
105
|
+
policy.perKey && !('limits' in policy.perKey) ? policy.perKey.maxConcurrent : undefined
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
A shape carrying members of both branches — `{ maxKeys, maxConcurrent, limits }` —
|
|
109
|
+
is refused. **In 0.72.0 and 0.72.1 that refusal came only from
|
|
110
|
+
`createBoundedAdmission`**, not from `tsc`: an excess-property check against a
|
|
111
|
+
union admits any property some member declares, so the mixed shape typechecked
|
|
112
|
+
and threw when the admission was built. From **0.72.2** each branch declares the
|
|
113
|
+
other's members as `never`, so it is a compile error. Nothing about the runtime
|
|
114
|
+
changed — both branches always refused it — but on a path your tests do not
|
|
115
|
+
construct, the earlier versions would have told you in production.
|
|
116
|
+
|
|
117
|
+
### If you build a snapshot or a status by hand
|
|
118
|
+
|
|
119
|
+
`CreditWindowSnapshot` gained `waiting` (producers parked in the new waiting
|
|
120
|
+
`acquire`) and `DiagnosticJournalStatus` gained `lock`. Both are produced by the
|
|
121
|
+
framework, so reading them is unaffected — but a test double stops compiling:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
// before
|
|
125
|
+
const snapshot: CreditWindowSnapshot = { state: 'open', capacityBytes: 100, /* … */ }
|
|
126
|
+
|
|
127
|
+
// after
|
|
128
|
+
const snapshot: CreditWindowSnapshot = { state: 'open', capacityBytes: 100, /* … */ waiting: 0 }
|
|
129
|
+
```
|
|
130
|
+
|
|
12
131
|
## Released migration: 0.71.0
|
|
13
132
|
|
|
14
133
|
The Agent coding tools. Two of the three changes are visible to the compiler;
|
|
@@ -914,229 +1033,3 @@ The refusals now say which of the two happened: a resource that was never
|
|
|
914
1033
|
healthy is told it "is not healthy" and pointed at `required: false`; one that
|
|
915
1034
|
was healthy and stopped is told it "lost readiness" and pointed at
|
|
916
1035
|
`onResourceFailure`.
|
|
917
|
-
|
|
918
|
-
## Released migration: 0.60.0
|
|
919
|
-
|
|
920
|
-
### close() says what it achieved
|
|
921
|
-
|
|
922
|
-
`AgentRuntime.close()` returned `Promise<void>` and its contract promised three
|
|
923
|
-
things that cannot hold together. It now returns
|
|
924
|
-
`{ settled, timedOut, remaining }`.
|
|
925
|
-
|
|
926
|
-
Nothing breaks if you ignore the value:
|
|
927
|
-
|
|
928
|
-
```ts
|
|
929
|
-
await runtime.close({ gracePeriodMs: 30_000, forceTimeoutMs: 5_000 })
|
|
930
|
-
```
|
|
931
|
-
|
|
932
|
-
What DOES change is any code that relied on the old sentence "`close()` never
|
|
933
|
-
returns while a run is still in flight" while naming a `forceTimeoutMs`. That
|
|
934
|
-
was never true — the force budget exists precisely to stop waiting — so if your
|
|
935
|
-
process exits straight after `close()`, read the result:
|
|
936
|
-
|
|
937
|
-
```ts
|
|
938
|
-
const closed = await runtime.close({ gracePeriodMs: 30_000, forceTimeoutMs: 5_000 })
|
|
939
|
-
if (!closed.settled) {
|
|
940
|
-
// `closed.remaining` runs were still in flight. They stay recoverable
|
|
941
|
-
// through `scanRecoverable`; close never marks them terminal on its own.
|
|
942
|
-
logger.warn({ remaining: closed.remaining }, 'exiting with runs in flight')
|
|
943
|
-
}
|
|
944
|
-
```
|
|
945
|
-
|
|
946
|
-
If you want the old guarantee, omit `forceTimeoutMs`: that is the one
|
|
947
|
-
combination in which `close()` cannot return with a run in flight — and its wait
|
|
948
|
-
is unbounded, which is the trade.
|
|
949
|
-
|
|
950
|
-
A TypeScript consumer that wrote `const done: void = await runtime.close()` is
|
|
951
|
-
the only shape that stops compiling.
|
|
952
|
-
|
|
953
|
-
### one name per concept
|
|
954
|
-
|
|
955
|
-
`AgentModelDeclaration` was a bare alias of `AgentModelDescriptor`, so the same
|
|
956
|
-
type reached consumers under two exported names:
|
|
957
|
-
|
|
958
|
-
```ts
|
|
959
|
-
// before
|
|
960
|
-
defineModelRegistry<Record<string, AgentModelDeclaration>>({ … })
|
|
961
|
-
// after
|
|
962
|
-
defineModelRegistry<Record<string, AgentModelDescriptor>>({ … })
|
|
963
|
-
```
|
|
964
|
-
|
|
965
|
-
A find-and-replace covers it; there is no behavioural change. Kept name is
|
|
966
|
-
`AgentModelDescriptor`, the one paired with `AgentModelDescriptorSchema` and
|
|
967
|
-
returned by `registry.descriptor()`.
|
|
968
|
-
|
|
969
|
-
Two names that look like the same case and are **not** being merged:
|
|
970
|
-
`SocketEventMap` aliases Socket.IO's `EventsMap` so a vendor's name stays out of
|
|
971
|
-
our signatures, and `AgentRun.ownerId` holds the same value a runtime publishes
|
|
972
|
-
as `runtimeEpoch` on its events. The latter is one identity in two roles — "who
|
|
973
|
-
owns this run" and "which runtime emitted this event" — and both declarations
|
|
974
|
-
now say so. Renaming either would make the fencing comparison read worse.
|
|
975
|
-
|
|
976
|
-
### a reachable public surface
|
|
977
|
-
|
|
978
|
-
Three exports that the public API required and did not provide, plus one option
|
|
979
|
-
it accepted and ignored.
|
|
980
|
-
|
|
981
|
-
```ts
|
|
982
|
-
// before — identified by string, because the class was exported nowhere
|
|
983
|
-
if (error instanceof Error && error.name === 'AgentRuntimeConflictError') …
|
|
984
|
-
// after
|
|
985
|
-
import { AgentRuntimeConflictError } from 'stitchkit/agent-runtime'
|
|
986
|
-
if (error instanceof AgentRuntimeConflictError) …
|
|
987
|
-
```
|
|
988
|
-
|
|
989
|
-
`ActivityTokenBrand` is exported, so `ActivityProjection` can be implemented by
|
|
990
|
-
a test double. `STITCH_ERROR_STATUS` gained `APPLICATION_NOT_ACCEPTING` (503) —
|
|
991
|
-
only an exhaustive `satisfies Record<StitchErrorCode, …>` map stops compiling,
|
|
992
|
-
and the fix is one line. (`GRAMMY_WEBHOOK_NOT_ACCEPTING` joined it in 0.60.1,
|
|
993
|
-
under the same rule — see ADR 0105. This section briefly said the opposite: that
|
|
994
|
-
an adapter's code stays out of the registry. It does not, and leaving it out was
|
|
995
|
-
the worse of the two, because `isStitchErrorCode` then answered `false` and the
|
|
996
|
-
code reached the wire spelled stitchkit's way, past both `codeMap` and
|
|
997
|
-
`unmappedCode`.)
|
|
998
|
-
|
|
999
|
-
`application.shutdown()` no longer accepts `retryAfterSeconds`. Delete it from
|
|
1000
|
-
the call — the kernel never read it. If you meant the HTTP `Retry-After` a
|
|
1001
|
-
draining server sends, that lives on `managedServerResource({ retryAfterSeconds })`,
|
|
1002
|
-
where it always did the work.
|
|
1003
|
-
|
|
1004
|
-
### one shutdown vocabulary
|
|
1005
|
-
|
|
1006
|
-
```ts
|
|
1007
|
-
// before
|
|
1008
|
-
await runtime.close({ drainTimeoutMs: 30_000, forceTimeoutMs: 5_000 })
|
|
1009
|
-
// after
|
|
1010
|
-
await runtime.close({ gracePeriodMs: 30_000, forceTimeoutMs: 5_000 })
|
|
1011
|
-
```
|
|
1012
|
-
|
|
1013
|
-
The rename is mechanical. The behaviour change under it is not, and it is the
|
|
1014
|
-
reason the rename waited: two combinations were traps.
|
|
1015
|
-
`close({ drainTimeoutMs })` with no force budget aborted the runs and returned
|
|
1016
|
-
**without waiting for them to settle** — so naming a budget gave a weaker
|
|
1017
|
-
guarantee than naming none — and `close({ forceTimeoutMs })` with no drain
|
|
1018
|
-
budget never read the force budget, leaving an unbounded wait. Both now behave
|
|
1019
|
-
as their names say.
|
|
1020
|
-
|
|
1021
|
-
> **Superseded.** This section once ended "and `close()` never returns while a
|
|
1022
|
-
> run is in flight". That was never true with a force budget — the budget exists
|
|
1023
|
-
> to stop waiting — and `close()` now returns `{ settled, timedOut, remaining }`
|
|
1024
|
-
> instead of promising it. See *Released migration: 0.60.0 → close() says what
|
|
1025
|
-
> it achieved*, above.
|
|
1026
|
-
|
|
1027
|
-
If your shutdown path measured how long `close()` took, expect it to take
|
|
1028
|
-
longer in exactly the case where it used to return early — that is the fix, not
|
|
1029
|
-
a regression. Defaults stay per-surface: `ShutdownOptions.gracePeriodMs`
|
|
1030
|
-
defaults to 30 seconds, and the runtime's omitted budget still means "abort
|
|
1031
|
-
immediately", the behaviour `close()` has always had.
|
|
1032
|
-
|
|
1033
|
-
### unresolved attachments are omitted
|
|
1034
|
-
|
|
1035
|
-
`history.unresolvedFile` defaulted to `text`, and the placeholder it produced
|
|
1036
|
-
carried the storage reference:
|
|
1037
|
-
|
|
1038
|
-
```ts
|
|
1039
|
-
// before — the provider received your object key
|
|
1040
|
-
// "[attachment: s3://bucket/tenants/42/invoice.pdf]"
|
|
1041
|
-
history: {}
|
|
1042
|
-
// after — omitted entirely by default; ask for a placeholder explicitly
|
|
1043
|
-
history: { unresolvedFile: 'text' } // "[attachment: invoice.pdf]"
|
|
1044
|
-
```
|
|
1045
|
-
|
|
1046
|
-
Two things to check. If a prompt relied on the model seeing *something* where an
|
|
1047
|
-
unresolved file was, set `unresolvedFile: 'text'` — behaviour otherwise changes
|
|
1048
|
-
silently, since an omitted part produces no error. And if any stored transcript
|
|
1049
|
-
or provider log contains the old placeholder, it contains your storage layout;
|
|
1050
|
-
treat those as disclosed. The `error` policy still names the reference, because
|
|
1051
|
-
it is thrown into your process rather than sent upstream.
|
|
1052
|
-
|
|
1053
|
-
### one bounded recoverable scan
|
|
1054
|
-
|
|
1055
|
-
`AgentRuntimeStore` had two scans: a mandatory unbounded one and an optional
|
|
1056
|
-
paged one. The runtime only ever called the optional one, so implementing the
|
|
1057
|
-
interface as written produced a store that threw on its first `recover()`:
|
|
1058
|
-
|
|
1059
|
-
```ts
|
|
1060
|
-
// before — the mandatory member was dead, the needed one was optional
|
|
1061
|
-
{
|
|
1062
|
-
scanRecoverable: () => loadEveryRecoverableSnapshot(),
|
|
1063
|
-
scanRecoverablePage: ({ cursor, limit }) => page(cursor, limit),
|
|
1064
|
-
}
|
|
1065
|
-
// after — one member, the bounded signature the driver already used
|
|
1066
|
-
{ scanRecoverable: ({ cursor, limit }) => page(cursor, limit) }
|
|
1067
|
-
```
|
|
1068
|
-
|
|
1069
|
-
Delete the unbounded implementation rather than porting it: loading every
|
|
1070
|
-
recoverable conversation to start is the shape 0.59.0 and ADR 0101 moved away
|
|
1071
|
-
from, and nothing calls it now. If you built on `createAgentRuntimeStore()` you
|
|
1072
|
-
have nothing to do **if you only pass it to the runtime** — it implements the
|
|
1073
|
-
bounded page for you from the same driver member. If you CALL it yourself, the
|
|
1074
|
-
member changed shape: `scanRecoverable()` took no argument and returned
|
|
1075
|
-
snapshots; it now takes `{ cursor?, limit }` — `limit` is required — and returns
|
|
1076
|
-
one page of descriptors.
|
|
1077
|
-
```ts
|
|
1078
|
-
// before: const stale = await store.scanRecoverable()
|
|
1079
|
-
// after: const { items, nextCursor } = await store.scanRecoverable({ limit: 100 })
|
|
1080
|
-
```
|
|
1081
|
-
|
|
1082
|
-
### published application status
|
|
1083
|
-
|
|
1084
|
-
`createApplicationHealthHandler` and `createApplicationOperationalHandlers` no
|
|
1085
|
-
longer serialise the whole `ApplicationSnapshot`. They publish
|
|
1086
|
-
`ApplicationStatusProjection` — the verdict plus resource counts:
|
|
1087
|
-
|
|
1088
|
-
```ts
|
|
1089
|
-
// before — the response named every resource and its dependency edges
|
|
1090
|
-
const { resources } = await fetch('/status').then((r) => r.json())
|
|
1091
|
-
resources[0].dependsOn
|
|
1092
|
-
// after — the topology is read in-process, where it always belonged
|
|
1093
|
-
app.getSnapshot().resources[0].dependsOn
|
|
1094
|
-
```
|
|
1095
|
-
|
|
1096
|
-
The consequence to check is not compilation — it is whatever already consumes
|
|
1097
|
-
these routes. A dashboard that drew the dependency graph from `/status`, or an
|
|
1098
|
-
alert keyed on `admission.pending`, goes blank rather than red: the fields are
|
|
1099
|
-
absent, not zero. Both are available from `getSnapshot()`, so the fix is to read
|
|
1100
|
-
them in the process that owns the application and publish them on a channel you
|
|
1101
|
-
control. If a route was reachable from outside your network, treat the previous
|
|
1102
|
-
payload as disclosed and rotate nothing but assume the topology is known.
|
|
1103
|
-
|
|
1104
|
-
## Released migration: 0.59.0
|
|
1105
|
-
|
|
1106
|
-
### Normalized agent runtime persistence
|
|
1107
|
-
|
|
1108
|
-
`AgentRuntimeStoreDriver` no longer reads and rewrites a lifetime `AgentStoredState` JSON
|
|
1109
|
-
aggregate. Migrate that row and its recoverable/archive projections once:
|
|
1110
|
-
|
|
1111
|
-
1. Copy `conversationId` and `version` into the bounded runtime head.
|
|
1112
|
-
2. Write every `AgentStoredState.runs[]` entry as one normalized run record.
|
|
1113
|
-
3. Write every `AgentStoredState.admissions[]` entry as one admission receipt and copy its
|
|
1114
|
-
canonical input into that receipt.
|
|
1115
|
-
4. For terminal runs, retain the canonical assistant on the run record before deleting any old
|
|
1116
|
-
history/archive rows.
|
|
1117
|
-
5. Replace the recoverable projection with an index over normalized run `state`.
|
|
1118
|
-
6. Cut the adapter over atomically; there is no compatibility driver or dual-write mode.
|
|
1119
|
-
|
|
1120
|
-
```ts
|
|
1121
|
-
// before
|
|
1122
|
-
createAgentRuntimeStore({
|
|
1123
|
-
state: { load, compareAndSwap },
|
|
1124
|
-
history: { load, loadById, apply },
|
|
1125
|
-
scanRecoverable,
|
|
1126
|
-
})
|
|
1127
|
-
|
|
1128
|
-
// after
|
|
1129
|
-
createAgentRuntimeStore({
|
|
1130
|
-
head: { load, compareAndSwap },
|
|
1131
|
-
runs: { load, loadByAssistantMessageId, loadMany, listActive, save },
|
|
1132
|
-
admissions: { load, loadByInputMessageId, create },
|
|
1133
|
-
history: { load, apply },
|
|
1134
|
-
scanRecoverable,
|
|
1135
|
-
})
|
|
1136
|
-
```
|
|
1137
|
-
|
|
1138
|
-
`AgentRuntimeHeadSchema`, `AgentStoredRunSchema` and `AgentAdmissionReceiptSchema` replace
|
|
1139
|
-
`AgentStoredStateSchema` and `AgentAdmissionIdentitySchema`. Run
|
|
1140
|
-
`runAgentStoreConformance()` against the migrated adapter before switching production traffic.
|
|
1141
|
-
If an application implements `AgentRuntimeStore` directly, its duplicate result must also include
|
|
1142
|
-
the canonical `run` and the retained `assistant` for a terminal run.
|
|
@@ -1,14 +1,83 @@
|
|
|
1
|
-
# Upgrading 0.
|
|
1
|
+
# Upgrading 0.74.0 → 0.100.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.74.0 → 0.100.0 (docs/guide/upgrading.md)
|
|
7
7
|
|
|
8
8
|
==============================================================================
|
|
9
|
-
# Guide: Upgrading, 0.
|
|
9
|
+
# Guide: Upgrading, 0.74.0 → 0.100.0 (docs/guide/upgrading.md)
|
|
10
10
|
==============================================================================
|
|
11
11
|
|
|
12
|
+
## Released migration: 0.100.0
|
|
13
|
+
|
|
14
|
+
### watch capacity and session/live/delivery adoption
|
|
15
|
+
|
|
16
|
+
**Who must act:** watch consumers exceeding 1024 hub sources, 1024 hub subscribers,
|
|
17
|
+
1024 client keys or 128 listeners per key. These previously unbounded collections
|
|
18
|
+
now refuse excess admission. Choose explicit positive finite limits, for example:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
// Before: no hub-wide capacity bounds.
|
|
22
|
+
createWatchHub({ read, watchable });
|
|
23
|
+
// After: explicitly budget a larger workload.
|
|
24
|
+
createWatchHub({ read, watchable, maxSources: 4096, maxSubscribers: 4096 });
|
|
25
|
+
// Client limits are configured independently.
|
|
26
|
+
createWatchClient({ ...clientConfig, maxKeys: 2048, maxListenersPerKey: 256 });
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The remaining steps apply only to applications opting into session lifetimes,
|
|
30
|
+
scoped watched reads, managed subscriptions or multi-action notification delivery.
|
|
31
|
+
Existing clients within the limits and single-send outboxes need no migration.
|
|
32
|
+
|
|
33
|
+
Replace local session generation counters with one `createSessionScope`; share it
|
|
34
|
+
with `createSessionCredentials`. Guard transport attempts, complete asynchronous
|
|
35
|
+
operations and final synchronous delivery. Route credential persistence through
|
|
36
|
+
one coordinator. Keep provider-specific error classification and bounded command
|
|
37
|
+
retry in the application. Coordination is per client instance.
|
|
38
|
+
|
|
39
|
+
Upgrade both watch endpoints before enabling session-scoped watches: strict older
|
|
40
|
+
servers reject the new optional `WatchKey.instance`. Server-verified scope controls
|
|
41
|
+
sharing; the client instance is only routing identity. Bind exact watched handles
|
|
42
|
+
to session-qualified cache keys. Existing delta/reconnect behavior stays in place.
|
|
43
|
+
For applications needing more than 1024 hub sources/subscribers or client keys, set
|
|
44
|
+
explicit finite capacity options. Enable a reconciliation interval when lost hints
|
|
45
|
+
must recover without a reconnect.
|
|
46
|
+
|
|
47
|
+
For multi-action outboxes, enqueue new items with a versioned delivery plan and
|
|
48
|
+
return small JSON receipts from `send`. Existing queued single-send items should
|
|
49
|
+
be drained before enabling a delivery executor on that queue, or migrated under
|
|
50
|
+
the store's atomic transition. When a new executor version ships, list the old
|
|
51
|
+
version's projection in `delivery.retiredVersions` until its queued items drain;
|
|
52
|
+
a plan version with no executor waits, reported to `onError` as
|
|
53
|
+
`NotificationPlanVersionError` (from 0.100.1).
|
|
54
|
+
Make projection idempotent. Provider idempotency/reconciliation remains necessary
|
|
55
|
+
for a crash between remote success and checkpoint. These APIs are available starting with 0.100.0.
|
|
56
|
+
|
|
57
|
+
### exclusive lock recovery
|
|
58
|
+
|
|
59
|
+
New lock and reclaim-guard records include `owner.process`: kernel boot identity,
|
|
60
|
+
process birth token and namespace. `readDiagnosticJournalLockDiagnosis(error)`
|
|
61
|
+
adds `identity` to distinguish matched lifetime evidence, PID reuse, a different
|
|
62
|
+
boot, an absent PID, a legacy record or unavailable identity. Legacy `alive` only
|
|
63
|
+
means the PID is present; it does not prove that the recorded writer still exists.
|
|
64
|
+
|
|
65
|
+
**Who must act:** deployments recovering a legacy lock with a reused live PID,
|
|
66
|
+
or bundling file-lock consumers into a standalone Darwin executable. Legacy
|
|
67
|
+
records cannot safely infer their missing boot/start identity from `acquiredAt`.
|
|
68
|
+
Stop all writers to that resource, verify exclusive ownership, preserve the old
|
|
69
|
+
lock for incident evidence outside the active lock path, and restart with the
|
|
70
|
+
new package. Never delete a lock merely because it is old. New acquisitions
|
|
71
|
+
write the modern record; no journal data migration is needed.
|
|
72
|
+
|
|
73
|
+
Darwin distributions must retain the package's architecture-matched native
|
|
74
|
+
`.node` asset for process birth measurement, as for contained filesystem access.
|
|
75
|
+
If native/proc identity cannot be read, new locks explicitly record null and
|
|
76
|
+
recovery refuses rather than treating unknown ownership as death. From 0.100.1 a
|
|
77
|
+
Linux kernel without time namespaces (before 5.6) records the PID namespace alone
|
|
78
|
+
instead of null, so its locks recover like any other. Existing
|
|
79
|
+
`refuse` policy and the separately configured ownerless-file grace are unchanged.
|
|
80
|
+
|
|
12
81
|
## Released migration: 0.99.0
|
|
13
82
|
|
|
14
83
|
### structural alternatives in flattened tool schemas
|
|
@@ -1018,122 +1087,3 @@ Not a migration, but worth knowing: a missing multipart file used to be reported
|
|
|
1018
1087
|
`UNKNOWN_ERROR`, the code that means *this client cannot tell you what happened*, on the one refusal
|
|
1019
1088
|
where it is certain nothing was sent. → ADR 0148 carries the reasoning, including why argument
|
|
1020
1089
|
validation stays on the server.
|
|
1021
|
-
|
|
1022
|
-
## Released migration: 0.73.0
|
|
1023
|
-
|
|
1024
|
-
Two breaking changes. Nothing you send to a server changed, and only one of these
|
|
1025
|
-
can reach a call site the compiler already checks.
|
|
1026
|
-
|
|
1027
|
-
### If you call `withOptions` from a call site that lost its types
|
|
1028
|
-
|
|
1029
|
-
`withOptions` takes one argument on an endpoint with no contract input, two when
|
|
1030
|
-
there is one. Passing two to a no-input endpoint used to succeed and silently
|
|
1031
|
-
drop the options: the request went out **uncancelled**, the caller still received
|
|
1032
|
-
`REQUEST_ABORTED` — cancellation is decided from the signal it was handed, not
|
|
1033
|
-
from what the transport did — and the server ran the operation to its own
|
|
1034
|
-
deadline. Every symptom then points at the transport, and the investigation goes
|
|
1035
|
-
there. It now throws a `TypeError` naming the endpoint and the correct shape.
|
|
1036
|
-
|
|
1037
|
-
```ts
|
|
1038
|
-
// before — the options were dropped and the request was never cancelled
|
|
1039
|
-
api.ping.withOptions({}, { signal })
|
|
1040
|
-
|
|
1041
|
-
// after
|
|
1042
|
-
api.ping.withOptions({ signal })
|
|
1043
|
-
```
|
|
1044
|
-
|
|
1045
|
-
A typed call site already refused the wrong arity, so this reaches only code that
|
|
1046
|
-
does not have the types: a `Record<string, …>` view of the client, a hand-written
|
|
1047
|
-
double, a dynamic dispatch. The guard counts arguments and never reads them, so a
|
|
1048
|
-
method handed to a callback API behaves exactly as before.
|
|
1049
|
-
|
|
1050
|
-
### If you match on `ApiError.message`
|
|
1051
|
-
|
|
1052
|
-
An `ApiError` that nothing explained used to carry `API Error: ${code}` — a
|
|
1053
|
-
string that reads like an explanation while only restating the code, so a caller
|
|
1054
|
-
could not tell an origin that explained a failure from one that said nothing. It
|
|
1055
|
-
now says which it is.
|
|
1056
|
-
|
|
1057
|
-
```ts
|
|
1058
|
-
// before
|
|
1059
|
-
err.message === 'API Error: INVALID_INPUT'
|
|
1060
|
-
|
|
1061
|
-
// after
|
|
1062
|
-
err.message === 'INVALID_INPUT (no message supplied)' // better: match err.code
|
|
1063
|
-
```
|
|
1064
|
-
|
|
1065
|
-
Match `err.code` instead: it is the contract, and it did not change. An error
|
|
1066
|
-
carrying a real message is untouched. An empty message now counts as no message,
|
|
1067
|
-
for the same reason — an empty string is not an explanation either.
|
|
1068
|
-
|
|
1069
|
-
### If a diagnostic journal lock file is already on disk
|
|
1070
|
-
|
|
1071
|
-
One operator step, and only on a host that has been **renamed** since its lock was written.
|
|
1072
|
-
|
|
1073
|
-
A lock written before this version carries no machine identity, so there is nothing to compare and
|
|
1074
|
-
the host name is all that is left. If the name still matches, the lock reclaims exactly as it always
|
|
1075
|
-
did and there is nothing to do. If the name has changed, the lock is `unattributable` and is refused
|
|
1076
|
-
— the same refusal this release exists to end, except that this particular file predates the fix and
|
|
1077
|
-
cannot be repaired from the inside. Delete it once:
|
|
1078
|
-
|
|
1079
|
-
```sh
|
|
1080
|
-
rm <journal path>.lock # only when the host was renamed since the file was written
|
|
1081
|
-
```
|
|
1082
|
-
|
|
1083
|
-
Locks written from this version on carry the machine identity, so the situation cannot recur. To see
|
|
1084
|
-
which case you are in without guessing, read the refusal instead of the file:
|
|
1085
|
-
`readDiagnosticJournalLockDiagnosis(err)` returns `attribution: 'unattributable'` for exactly this
|
|
1086
|
-
one, and `'another-machine'` for a lock that genuinely belongs elsewhere and must **not** be deleted.
|
|
1087
|
-
|
|
1088
|
-
Two related fixes need no migration, but change what you will see. An error the
|
|
1089
|
-
transport raised through `createHttpClient` now carries the transport's own text
|
|
1090
|
-
in `message` and the original error as `cause`, where before it carried neither
|
|
1091
|
-
and filed the text under `details.message` alone; if you followed the retry rule
|
|
1092
|
-
in [the client guide](./client.md) — inspect the adapter's `cause`, retry only
|
|
1093
|
-
when it proves dispatch did not happen — that rule was not executable on this
|
|
1094
|
-
transport and now is. And the client guide now states which direction validation
|
|
1095
|
-
runs: responses are checked against `output`, arguments are **not** checked
|
|
1096
|
-
before being sent.
|
|
1097
|
-
|
|
1098
|
-
## Released migration: 0.72.0
|
|
1099
|
-
|
|
1100
|
-
Nothing you *pass* changed. Both items are about types you read or build, and
|
|
1101
|
-
both stop the compiler rather than surprising you at runtime.
|
|
1102
|
-
|
|
1103
|
-
### If you read `perKey` off `BoundedAdmissionPolicy`
|
|
1104
|
-
|
|
1105
|
-
`perKey` is now a union: the flat ceiling it always was, or `{ maxKeys, limits }`
|
|
1106
|
-
where the ceiling is resolved from the key. Declaring one is unchanged; reading
|
|
1107
|
-
one needs a narrowing.
|
|
1108
|
-
|
|
1109
|
-
```ts
|
|
1110
|
-
// before
|
|
1111
|
-
const ceiling = policy.perKey?.maxConcurrent
|
|
1112
|
-
|
|
1113
|
-
// after
|
|
1114
|
-
const ceiling =
|
|
1115
|
-
policy.perKey && !('limits' in policy.perKey) ? policy.perKey.maxConcurrent : undefined
|
|
1116
|
-
```
|
|
1117
|
-
|
|
1118
|
-
A shape carrying members of both branches — `{ maxKeys, maxConcurrent, limits }` —
|
|
1119
|
-
is refused. **In 0.72.0 and 0.72.1 that refusal came only from
|
|
1120
|
-
`createBoundedAdmission`**, not from `tsc`: an excess-property check against a
|
|
1121
|
-
union admits any property some member declares, so the mixed shape typechecked
|
|
1122
|
-
and threw when the admission was built. From **0.72.2** each branch declares the
|
|
1123
|
-
other's members as `never`, so it is a compile error. Nothing about the runtime
|
|
1124
|
-
changed — both branches always refused it — but on a path your tests do not
|
|
1125
|
-
construct, the earlier versions would have told you in production.
|
|
1126
|
-
|
|
1127
|
-
### If you build a snapshot or a status by hand
|
|
1128
|
-
|
|
1129
|
-
`CreditWindowSnapshot` gained `waiting` (producers parked in the new waiting
|
|
1130
|
-
`acquire`) and `DiagnosticJournalStatus` gained `lock`. Both are produced by the
|
|
1131
|
-
framework, so reading them is unaffected — but a test double stops compiling:
|
|
1132
|
-
|
|
1133
|
-
```ts
|
|
1134
|
-
// before
|
|
1135
|
-
const snapshot: CreditWindowSnapshot = { state: 'open', capacityBytes: 100, /* … */ }
|
|
1136
|
-
|
|
1137
|
-
// after
|
|
1138
|
-
const snapshot: CreditWindowSnapshot = { state: 'open', capacityBytes: 100, /* … */ waiting: 0 }
|
|
1139
|
-
```
|
package/llms/upgrading.txt
CHANGED
|
@@ -11,10 +11,11 @@ Contains: Guide: Upgrading, general (docs/guide/upgrading.md)
|
|
|
11
11
|
|
|
12
12
|
Load this slice, then every range slice between your installed version and the target:
|
|
13
13
|
|
|
14
|
-
- 0.
|
|
15
|
-
- 0.
|
|
16
|
-
- 0.
|
|
17
|
-
- 0.
|
|
14
|
+
- 0.101.0 → 0.109.0: `llms/upgrading-0.101.0-0.109.0.txt`
|
|
15
|
+
- 0.74.0 → 0.100.0: `llms/upgrading-0.74.0-0.100.0.txt`
|
|
16
|
+
- 0.61.0 → 0.73.0: `llms/upgrading-0.61.0-0.73.0.txt`
|
|
17
|
+
- 0.44.0 → 0.60.0: `llms/upgrading-0.44.0-0.60.0.txt`
|
|
18
|
+
- 0.37.0 → 0.37.0: `llms/upgrading-0.37.0.txt`
|
|
18
19
|
|
|
19
20
|
# Upgrading stitchkit
|
|
20
21
|
|