stitchkit 0.108.5 → 0.109.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 +38 -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/http.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
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Upgrading 0.37.0 → 0.37.0 — stitchkit docs slice
|
|
2
|
+
|
|
3
|
+
> Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
|
|
4
|
+
> `llms.txt` in this package.
|
|
5
|
+
|
|
6
|
+
Contains: Guide: Upgrading, 0.37.0 → 0.37.0 (docs/guide/upgrading.md)
|
|
7
|
+
|
|
8
|
+
==============================================================================
|
|
9
|
+
# Guide: Upgrading, 0.37.0 → 0.37.0 (docs/guide/upgrading.md)
|
|
10
|
+
==============================================================================
|
|
11
|
+
|
|
12
|
+
## The 0.37 migration
|
|
13
|
+
|
|
14
|
+
Tool presentation is no longer an executable Zod parser. Replace the removed
|
|
15
|
+
flatten helpers with the JSON Schema compiler, and choose the explicit
|
|
16
|
+
`MountableTool` surface when using the advanced collection API:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// before
|
|
20
|
+
const flat = flattenUnionsDeep(zodSchema)
|
|
21
|
+
mountable.schema
|
|
22
|
+
|
|
23
|
+
// after
|
|
24
|
+
const flat = flattenToolJsonSchema(
|
|
25
|
+
z.toJSONSchema(zodSchema, { target: 'draft-07', io: 'input' }),
|
|
26
|
+
)
|
|
27
|
+
mountable.presentationSchema // model/MCP/manifest JSON Schema
|
|
28
|
+
mountable.argumentSchema // executable CLI argument adapter only
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Contract and native handlers keep their original Zod schemas; MCP and agent SDK
|
|
32
|
+
adapters now forward raw arguments so defaults, coercions, refinements and
|
|
33
|
+
transforms execute exactly once inside Stitchkit. There are no compatibility
|
|
34
|
+
exports for `flattenDiscriminatedUnion`, `flattenUnionsDeep` or
|
|
35
|
+
`MountableTool.schema`. → ADR 0050
|
|
36
|
+
|
|
37
|
+
Tool-call hooks now take one options object. Migrate all three callbacks; there
|
|
38
|
+
are no positional overloads:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// before
|
|
42
|
+
beforeToolCall: (toolName, args, context, endpoint) => {}
|
|
43
|
+
afterToolCall: (toolName, args, result, durationMs, context, endpoint, error) => {}
|
|
44
|
+
onToolError: (toolName, error, context, endpoint) => {}
|
|
45
|
+
|
|
46
|
+
// after
|
|
47
|
+
beforeToolCall: ({ toolName, args, context, endpoint }) => {}
|
|
48
|
+
afterToolCall: ({ toolName, args, result, durationMs, context, endpoint, error }) => {}
|
|
49
|
+
onToolError: ({ toolName, error, context, endpoint }) => {}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### MCP schema validation
|
|
53
|
+
|
|
54
|
+
The standalone validator now takes one object and live MCP configs carry the
|
|
55
|
+
same rules under `schemaValidation`. Migrate every positional call and every
|
|
56
|
+
`onIncompatibleSchema` field; there is no old-shape overload:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// before
|
|
60
|
+
validateMcpSchemas(services, 'throw', logger, { requireTypedProperties: true })
|
|
61
|
+
createMcpHandler({ services, onIncompatibleSchema: 'throw' })
|
|
62
|
+
|
|
63
|
+
// after
|
|
64
|
+
validateMcpSchemas({ services, policy: 'throw', logger, requireTypedProperties: true })
|
|
65
|
+
createMcpHandler({ services, schemaValidation: { policy: 'throw' } })
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Put `extend` and `flattenUnionInput` beside `services`, not inside
|
|
69
|
+
`schemaValidation`. The handler applies the profile to the exact prepared schema
|
|
70
|
+
it advertises. Add `requirePortableFormats: true` when every custom JSON Schema
|
|
71
|
+
format must be rejected before a client sees it.
|
|
72
|
+
|
|
73
|
+
Native MCP registration also changed shape in 0.37. Move protected tools to the
|
|
74
|
+
framework registrar; keep an SDK-raw tool only by naming the opt-out:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
// before
|
|
78
|
+
nativeTools: (server, auth) => server.registerTool(name, config, handler)
|
|
79
|
+
|
|
80
|
+
// after — lifecycle, hooks and schema policy apply
|
|
81
|
+
nativeTools: ({ registerTool }, auth) => registerTool({
|
|
82
|
+
name, description, identity, input, output, handler,
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// after — intentionally raw
|
|
86
|
+
nativeTools: ({ rawServer }, auth) => rawServer.registerTool(name, config, handler)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If a tool hook annotated `endpoint` as `MethodDef`, remove that annotation or
|
|
90
|
+
use `OperationIdentity`: native operations have service/action/scope/method but
|
|
91
|
+
no HTTP path.
|
|
92
|
+
|
|
93
|
+
### Node-facing server types
|
|
94
|
+
|
|
95
|
+
`stitchkit/server` remains Bun-concrete: an explicitly annotated `RawRoute`
|
|
96
|
+
still receives `BunServer`. `stitchkit/node` no longer drags Bun declarations
|
|
97
|
+
into a Node project. Its raw routes default the host server to `unknown`, and
|
|
98
|
+
its Socket.IO handle exposes only Node capabilities:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// before — Node entry still leaked Bun-only fields and ambient types
|
|
102
|
+
const route: RawRoute = { handler: (_req, ctx) => ctx.server?.upgrade(...) }
|
|
103
|
+
const socket = await createSocketIOServer(config)
|
|
104
|
+
socket.websocket
|
|
105
|
+
|
|
106
|
+
// after — name a custom embedding host only when one exists
|
|
107
|
+
const route: RawRoute<MyHostServer> = {
|
|
108
|
+
handler: (_req, ctx) => useHost(ctx.server),
|
|
109
|
+
}
|
|
110
|
+
const socket = await createSocketIOServer(config)
|
|
111
|
+
socket.io
|
|
112
|
+
socket.attach(nodeHttpServer)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Node consumers can remove `@types/bun` unless another dependency independently
|
|
116
|
+
requires it.
|
|
117
|
+
|
|
118
|
+
### Managed server shutdown
|
|
119
|
+
|
|
120
|
+
`createServer()` and `serveNode()` now return the same structural managed
|
|
121
|
+
lifecycle. Replace every direct runtime stop and parallel Socket.IO close:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
// before — split ownership
|
|
125
|
+
const socket = await createSocketIOServer(config)
|
|
126
|
+
const server = createServer({
|
|
127
|
+
services,
|
|
128
|
+
websocket: socket.websocket,
|
|
129
|
+
rawRoutes: [socket.route],
|
|
130
|
+
})
|
|
131
|
+
server.stop()
|
|
132
|
+
await socket.io.close()
|
|
133
|
+
|
|
134
|
+
// after — one owner and one total deadline
|
|
135
|
+
const socket = await createSocketIOServer(config)
|
|
136
|
+
const server = createServer({ services, socket })
|
|
137
|
+
const result = await server.shutdown({ gracePeriodMs: 30_000 })
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
On Node, keep the same `socket` field and replace `handle.close()` with
|
|
141
|
+
`handle.shutdown()`. Runtime-specific diagnostics move under `handle.runtime`;
|
|
142
|
+
do not use it as a second shutdown path. Standalone CLI/tools that create a
|
|
143
|
+
Socket.IO handle without an HTTP server call `await socket.close()`.
|
|
144
|
+
|
|
145
|
+
If Bun Socket.IO shares the port with a raw lane, keep the explicit composition
|
|
146
|
+
but let the server mount the Socket.IO route:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
createServer({
|
|
150
|
+
services,
|
|
151
|
+
socket,
|
|
152
|
+
websocket: composeWebSocketHandlers([
|
|
153
|
+
webSocketLane({ match: isRaw, handlers: rawHandlers }),
|
|
154
|
+
socketIoLane(socket.websocket),
|
|
155
|
+
]),
|
|
156
|
+
rawRoutes: [rawUpgradeRoute],
|
|
157
|
+
})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Move native Bun `routes` entries to `rawRoutes`. Native routes run before the
|
|
161
|
+
Fetch handler and therefore cannot participate in admission or drain. Wire
|
|
162
|
+
`SIGTERM`/`SIGINT` in the application; the first signal starts `shutdown()`, and
|
|
163
|
+
a later signal may abort the same controller. Close MCP, databases and queues
|
|
164
|
+
after the server result—those resources remain application-owned.
|
|
165
|
+
|
|
166
|
+
Move a handshake policy from the Node-only callback shape inside
|
|
167
|
+
`serverOptions` to the runtime-neutral top-level policy. It receives a Web
|
|
168
|
+
`Request`, may be async, and returns whether to admit the handshake:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
// before
|
|
172
|
+
serverOptions: { allowRequest: (request, done) => done(null, allowed(request)) }
|
|
173
|
+
|
|
174
|
+
// after
|
|
175
|
+
allowRequest: (request) => allowed(request)
|
|
176
|
+
```
|
|
@@ -1,14 +1,240 @@
|
|
|
1
|
-
# Upgrading 0.
|
|
1
|
+
# Upgrading 0.44.0 → 0.60.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.44.0 → 0.60.0 (docs/guide/upgrading.md)
|
|
7
7
|
|
|
8
8
|
==============================================================================
|
|
9
|
-
# Guide: Upgrading, 0.
|
|
9
|
+
# Guide: Upgrading, 0.44.0 → 0.60.0 (docs/guide/upgrading.md)
|
|
10
10
|
==============================================================================
|
|
11
11
|
|
|
12
|
+
## Released migration: 0.60.0
|
|
13
|
+
|
|
14
|
+
### close() says what it achieved
|
|
15
|
+
|
|
16
|
+
`AgentRuntime.close()` returned `Promise<void>` and its contract promised three
|
|
17
|
+
things that cannot hold together. It now returns
|
|
18
|
+
`{ settled, timedOut, remaining }`.
|
|
19
|
+
|
|
20
|
+
Nothing breaks if you ignore the value:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
await runtime.close({ gracePeriodMs: 30_000, forceTimeoutMs: 5_000 })
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
What DOES change is any code that relied on the old sentence "`close()` never
|
|
27
|
+
returns while a run is still in flight" while naming a `forceTimeoutMs`. That
|
|
28
|
+
was never true — the force budget exists precisely to stop waiting — so if your
|
|
29
|
+
process exits straight after `close()`, read the result:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
const closed = await runtime.close({ gracePeriodMs: 30_000, forceTimeoutMs: 5_000 })
|
|
33
|
+
if (!closed.settled) {
|
|
34
|
+
// `closed.remaining` runs were still in flight. They stay recoverable
|
|
35
|
+
// through `scanRecoverable`; close never marks them terminal on its own.
|
|
36
|
+
logger.warn({ remaining: closed.remaining }, 'exiting with runs in flight')
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If you want the old guarantee, omit `forceTimeoutMs`: that is the one
|
|
41
|
+
combination in which `close()` cannot return with a run in flight — and its wait
|
|
42
|
+
is unbounded, which is the trade.
|
|
43
|
+
|
|
44
|
+
A TypeScript consumer that wrote `const done: void = await runtime.close()` is
|
|
45
|
+
the only shape that stops compiling.
|
|
46
|
+
|
|
47
|
+
### one name per concept
|
|
48
|
+
|
|
49
|
+
`AgentModelDeclaration` was a bare alias of `AgentModelDescriptor`, so the same
|
|
50
|
+
type reached consumers under two exported names:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// before
|
|
54
|
+
defineModelRegistry<Record<string, AgentModelDeclaration>>({ … })
|
|
55
|
+
// after
|
|
56
|
+
defineModelRegistry<Record<string, AgentModelDescriptor>>({ … })
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
A find-and-replace covers it; there is no behavioural change. Kept name is
|
|
60
|
+
`AgentModelDescriptor`, the one paired with `AgentModelDescriptorSchema` and
|
|
61
|
+
returned by `registry.descriptor()`.
|
|
62
|
+
|
|
63
|
+
Two names that look like the same case and are **not** being merged:
|
|
64
|
+
`SocketEventMap` aliases Socket.IO's `EventsMap` so a vendor's name stays out of
|
|
65
|
+
our signatures, and `AgentRun.ownerId` holds the same value a runtime publishes
|
|
66
|
+
as `runtimeEpoch` on its events. The latter is one identity in two roles — "who
|
|
67
|
+
owns this run" and "which runtime emitted this event" — and both declarations
|
|
68
|
+
now say so. Renaming either would make the fencing comparison read worse.
|
|
69
|
+
|
|
70
|
+
### a reachable public surface
|
|
71
|
+
|
|
72
|
+
Three exports that the public API required and did not provide, plus one option
|
|
73
|
+
it accepted and ignored.
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
// before — identified by string, because the class was exported nowhere
|
|
77
|
+
if (error instanceof Error && error.name === 'AgentRuntimeConflictError') …
|
|
78
|
+
// after
|
|
79
|
+
import { AgentRuntimeConflictError } from 'stitchkit/agent-runtime'
|
|
80
|
+
if (error instanceof AgentRuntimeConflictError) …
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`ActivityTokenBrand` is exported, so `ActivityProjection` can be implemented by
|
|
84
|
+
a test double. `STITCH_ERROR_STATUS` gained `APPLICATION_NOT_ACCEPTING` (503) —
|
|
85
|
+
only an exhaustive `satisfies Record<StitchErrorCode, …>` map stops compiling,
|
|
86
|
+
and the fix is one line. (`GRAMMY_WEBHOOK_NOT_ACCEPTING` joined it in 0.60.1,
|
|
87
|
+
under the same rule — see ADR 0105. This section briefly said the opposite: that
|
|
88
|
+
an adapter's code stays out of the registry. It does not, and leaving it out was
|
|
89
|
+
the worse of the two, because `isStitchErrorCode` then answered `false` and the
|
|
90
|
+
code reached the wire spelled stitchkit's way, past both `codeMap` and
|
|
91
|
+
`unmappedCode`.)
|
|
92
|
+
|
|
93
|
+
`application.shutdown()` no longer accepts `retryAfterSeconds`. Delete it from
|
|
94
|
+
the call — the kernel never read it. If you meant the HTTP `Retry-After` a
|
|
95
|
+
draining server sends, that lives on `managedServerResource({ retryAfterSeconds })`,
|
|
96
|
+
where it always did the work.
|
|
97
|
+
|
|
98
|
+
### one shutdown vocabulary
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// before
|
|
102
|
+
await runtime.close({ drainTimeoutMs: 30_000, forceTimeoutMs: 5_000 })
|
|
103
|
+
// after
|
|
104
|
+
await runtime.close({ gracePeriodMs: 30_000, forceTimeoutMs: 5_000 })
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The rename is mechanical. The behaviour change under it is not, and it is the
|
|
108
|
+
reason the rename waited: two combinations were traps.
|
|
109
|
+
`close({ drainTimeoutMs })` with no force budget aborted the runs and returned
|
|
110
|
+
**without waiting for them to settle** — so naming a budget gave a weaker
|
|
111
|
+
guarantee than naming none — and `close({ forceTimeoutMs })` with no drain
|
|
112
|
+
budget never read the force budget, leaving an unbounded wait. Both now behave
|
|
113
|
+
as their names say.
|
|
114
|
+
|
|
115
|
+
> **Superseded.** This section once ended "and `close()` never returns while a
|
|
116
|
+
> run is in flight". That was never true with a force budget — the budget exists
|
|
117
|
+
> to stop waiting — and `close()` now returns `{ settled, timedOut, remaining }`
|
|
118
|
+
> instead of promising it. See *Released migration: 0.60.0 → close() says what
|
|
119
|
+
> it achieved*, above.
|
|
120
|
+
|
|
121
|
+
If your shutdown path measured how long `close()` took, expect it to take
|
|
122
|
+
longer in exactly the case where it used to return early — that is the fix, not
|
|
123
|
+
a regression. Defaults stay per-surface: `ShutdownOptions.gracePeriodMs`
|
|
124
|
+
defaults to 30 seconds, and the runtime's omitted budget still means "abort
|
|
125
|
+
immediately", the behaviour `close()` has always had.
|
|
126
|
+
|
|
127
|
+
### unresolved attachments are omitted
|
|
128
|
+
|
|
129
|
+
`history.unresolvedFile` defaulted to `text`, and the placeholder it produced
|
|
130
|
+
carried the storage reference:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
// before — the provider received your object key
|
|
134
|
+
// "[attachment: s3://bucket/tenants/42/invoice.pdf]"
|
|
135
|
+
history: {}
|
|
136
|
+
// after — omitted entirely by default; ask for a placeholder explicitly
|
|
137
|
+
history: { unresolvedFile: 'text' } // "[attachment: invoice.pdf]"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Two things to check. If a prompt relied on the model seeing *something* where an
|
|
141
|
+
unresolved file was, set `unresolvedFile: 'text'` — behaviour otherwise changes
|
|
142
|
+
silently, since an omitted part produces no error. And if any stored transcript
|
|
143
|
+
or provider log contains the old placeholder, it contains your storage layout;
|
|
144
|
+
treat those as disclosed. The `error` policy still names the reference, because
|
|
145
|
+
it is thrown into your process rather than sent upstream.
|
|
146
|
+
|
|
147
|
+
### one bounded recoverable scan
|
|
148
|
+
|
|
149
|
+
`AgentRuntimeStore` had two scans: a mandatory unbounded one and an optional
|
|
150
|
+
paged one. The runtime only ever called the optional one, so implementing the
|
|
151
|
+
interface as written produced a store that threw on its first `recover()`:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
// before — the mandatory member was dead, the needed one was optional
|
|
155
|
+
{
|
|
156
|
+
scanRecoverable: () => loadEveryRecoverableSnapshot(),
|
|
157
|
+
scanRecoverablePage: ({ cursor, limit }) => page(cursor, limit),
|
|
158
|
+
}
|
|
159
|
+
// after — one member, the bounded signature the driver already used
|
|
160
|
+
{ scanRecoverable: ({ cursor, limit }) => page(cursor, limit) }
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Delete the unbounded implementation rather than porting it: loading every
|
|
164
|
+
recoverable conversation to start is the shape 0.59.0 and ADR 0101 moved away
|
|
165
|
+
from, and nothing calls it now. If you built on `createAgentRuntimeStore()` you
|
|
166
|
+
have nothing to do **if you only pass it to the runtime** — it implements the
|
|
167
|
+
bounded page for you from the same driver member. If you CALL it yourself, the
|
|
168
|
+
member changed shape: `scanRecoverable()` took no argument and returned
|
|
169
|
+
snapshots; it now takes `{ cursor?, limit }` — `limit` is required — and returns
|
|
170
|
+
one page of descriptors.
|
|
171
|
+
```ts
|
|
172
|
+
// before: const stale = await store.scanRecoverable()
|
|
173
|
+
// after: const { items, nextCursor } = await store.scanRecoverable({ limit: 100 })
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### published application status
|
|
177
|
+
|
|
178
|
+
`createApplicationHealthHandler` and `createApplicationOperationalHandlers` no
|
|
179
|
+
longer serialise the whole `ApplicationSnapshot`. They publish
|
|
180
|
+
`ApplicationStatusProjection` — the verdict plus resource counts:
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
// before — the response named every resource and its dependency edges
|
|
184
|
+
const { resources } = await fetch('/status').then((r) => r.json())
|
|
185
|
+
resources[0].dependsOn
|
|
186
|
+
// after — the topology is read in-process, where it always belonged
|
|
187
|
+
app.getSnapshot().resources[0].dependsOn
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The consequence to check is not compilation — it is whatever already consumes
|
|
191
|
+
these routes. A dashboard that drew the dependency graph from `/status`, or an
|
|
192
|
+
alert keyed on `admission.pending`, goes blank rather than red: the fields are
|
|
193
|
+
absent, not zero. Both are available from `getSnapshot()`, so the fix is to read
|
|
194
|
+
them in the process that owns the application and publish them on a channel you
|
|
195
|
+
control. If a route was reachable from outside your network, treat the previous
|
|
196
|
+
payload as disclosed and rotate nothing but assume the topology is known.
|
|
197
|
+
|
|
198
|
+
## Released migration: 0.59.0
|
|
199
|
+
|
|
200
|
+
### Normalized agent runtime persistence
|
|
201
|
+
|
|
202
|
+
`AgentRuntimeStoreDriver` no longer reads and rewrites a lifetime `AgentStoredState` JSON
|
|
203
|
+
aggregate. Migrate that row and its recoverable/archive projections once:
|
|
204
|
+
|
|
205
|
+
1. Copy `conversationId` and `version` into the bounded runtime head.
|
|
206
|
+
2. Write every `AgentStoredState.runs[]` entry as one normalized run record.
|
|
207
|
+
3. Write every `AgentStoredState.admissions[]` entry as one admission receipt and copy its
|
|
208
|
+
canonical input into that receipt.
|
|
209
|
+
4. For terminal runs, retain the canonical assistant on the run record before deleting any old
|
|
210
|
+
history/archive rows.
|
|
211
|
+
5. Replace the recoverable projection with an index over normalized run `state`.
|
|
212
|
+
6. Cut the adapter over atomically; there is no compatibility driver or dual-write mode.
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
// before
|
|
216
|
+
createAgentRuntimeStore({
|
|
217
|
+
state: { load, compareAndSwap },
|
|
218
|
+
history: { load, loadById, apply },
|
|
219
|
+
scanRecoverable,
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
// after
|
|
223
|
+
createAgentRuntimeStore({
|
|
224
|
+
head: { load, compareAndSwap },
|
|
225
|
+
runs: { load, loadByAssistantMessageId, loadMany, listActive, save },
|
|
226
|
+
admissions: { load, loadByInputMessageId, create },
|
|
227
|
+
history: { load, apply },
|
|
228
|
+
scanRecoverable,
|
|
229
|
+
})
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
`AgentRuntimeHeadSchema`, `AgentStoredRunSchema` and `AgentAdmissionReceiptSchema` replace
|
|
233
|
+
`AgentStoredStateSchema` and `AgentAdmissionIdentitySchema`. Run
|
|
234
|
+
`runAgentStoreConformance()` against the migrated adapter before switching production traffic.
|
|
235
|
+
If an application implements `AgentRuntimeStore` directly, its duplicate result must also include
|
|
236
|
+
the canonical `run` and the retained `assistant` for a terminal run.
|
|
237
|
+
|
|
12
238
|
## Released migration: 0.58.0
|
|
13
239
|
|
|
14
240
|
### The default history projection rejects invalid chronology
|
|
@@ -1007,169 +1233,3 @@ createHttpClient({
|
|
|
1007
1233
|
|
|
1008
1234
|
There is no implicit `/auth/` suppression. Omit `suppressUnauthorizedFor` when
|
|
1009
1235
|
every 401 should emit the global `unauthorized` event.
|
|
1010
|
-
|
|
1011
|
-
## The 0.37 migration
|
|
1012
|
-
|
|
1013
|
-
Tool presentation is no longer an executable Zod parser. Replace the removed
|
|
1014
|
-
flatten helpers with the JSON Schema compiler, and choose the explicit
|
|
1015
|
-
`MountableTool` surface when using the advanced collection API:
|
|
1016
|
-
|
|
1017
|
-
```ts
|
|
1018
|
-
// before
|
|
1019
|
-
const flat = flattenUnionsDeep(zodSchema)
|
|
1020
|
-
mountable.schema
|
|
1021
|
-
|
|
1022
|
-
// after
|
|
1023
|
-
const flat = flattenToolJsonSchema(
|
|
1024
|
-
z.toJSONSchema(zodSchema, { target: 'draft-07', io: 'input' }),
|
|
1025
|
-
)
|
|
1026
|
-
mountable.presentationSchema // model/MCP/manifest JSON Schema
|
|
1027
|
-
mountable.argumentSchema // executable CLI argument adapter only
|
|
1028
|
-
```
|
|
1029
|
-
|
|
1030
|
-
Contract and native handlers keep their original Zod schemas; MCP and agent SDK
|
|
1031
|
-
adapters now forward raw arguments so defaults, coercions, refinements and
|
|
1032
|
-
transforms execute exactly once inside Stitchkit. There are no compatibility
|
|
1033
|
-
exports for `flattenDiscriminatedUnion`, `flattenUnionsDeep` or
|
|
1034
|
-
`MountableTool.schema`. → ADR 0050
|
|
1035
|
-
|
|
1036
|
-
Tool-call hooks now take one options object. Migrate all three callbacks; there
|
|
1037
|
-
are no positional overloads:
|
|
1038
|
-
|
|
1039
|
-
```ts
|
|
1040
|
-
// before
|
|
1041
|
-
beforeToolCall: (toolName, args, context, endpoint) => {}
|
|
1042
|
-
afterToolCall: (toolName, args, result, durationMs, context, endpoint, error) => {}
|
|
1043
|
-
onToolError: (toolName, error, context, endpoint) => {}
|
|
1044
|
-
|
|
1045
|
-
// after
|
|
1046
|
-
beforeToolCall: ({ toolName, args, context, endpoint }) => {}
|
|
1047
|
-
afterToolCall: ({ toolName, args, result, durationMs, context, endpoint, error }) => {}
|
|
1048
|
-
onToolError: ({ toolName, error, context, endpoint }) => {}
|
|
1049
|
-
```
|
|
1050
|
-
|
|
1051
|
-
### MCP schema validation
|
|
1052
|
-
|
|
1053
|
-
The standalone validator now takes one object and live MCP configs carry the
|
|
1054
|
-
same rules under `schemaValidation`. Migrate every positional call and every
|
|
1055
|
-
`onIncompatibleSchema` field; there is no old-shape overload:
|
|
1056
|
-
|
|
1057
|
-
```ts
|
|
1058
|
-
// before
|
|
1059
|
-
validateMcpSchemas(services, 'throw', logger, { requireTypedProperties: true })
|
|
1060
|
-
createMcpHandler({ services, onIncompatibleSchema: 'throw' })
|
|
1061
|
-
|
|
1062
|
-
// after
|
|
1063
|
-
validateMcpSchemas({ services, policy: 'throw', logger, requireTypedProperties: true })
|
|
1064
|
-
createMcpHandler({ services, schemaValidation: { policy: 'throw' } })
|
|
1065
|
-
```
|
|
1066
|
-
|
|
1067
|
-
Put `extend` and `flattenUnionInput` beside `services`, not inside
|
|
1068
|
-
`schemaValidation`. The handler applies the profile to the exact prepared schema
|
|
1069
|
-
it advertises. Add `requirePortableFormats: true` when every custom JSON Schema
|
|
1070
|
-
format must be rejected before a client sees it.
|
|
1071
|
-
|
|
1072
|
-
Native MCP registration also changed shape in 0.37. Move protected tools to the
|
|
1073
|
-
framework registrar; keep an SDK-raw tool only by naming the opt-out:
|
|
1074
|
-
|
|
1075
|
-
```ts
|
|
1076
|
-
// before
|
|
1077
|
-
nativeTools: (server, auth) => server.registerTool(name, config, handler)
|
|
1078
|
-
|
|
1079
|
-
// after — lifecycle, hooks and schema policy apply
|
|
1080
|
-
nativeTools: ({ registerTool }, auth) => registerTool({
|
|
1081
|
-
name, description, identity, input, output, handler,
|
|
1082
|
-
})
|
|
1083
|
-
|
|
1084
|
-
// after — intentionally raw
|
|
1085
|
-
nativeTools: ({ rawServer }, auth) => rawServer.registerTool(name, config, handler)
|
|
1086
|
-
```
|
|
1087
|
-
|
|
1088
|
-
If a tool hook annotated `endpoint` as `MethodDef`, remove that annotation or
|
|
1089
|
-
use `OperationIdentity`: native operations have service/action/scope/method but
|
|
1090
|
-
no HTTP path.
|
|
1091
|
-
|
|
1092
|
-
### Node-facing server types
|
|
1093
|
-
|
|
1094
|
-
`stitchkit/server` remains Bun-concrete: an explicitly annotated `RawRoute`
|
|
1095
|
-
still receives `BunServer`. `stitchkit/node` no longer drags Bun declarations
|
|
1096
|
-
into a Node project. Its raw routes default the host server to `unknown`, and
|
|
1097
|
-
its Socket.IO handle exposes only Node capabilities:
|
|
1098
|
-
|
|
1099
|
-
```ts
|
|
1100
|
-
// before — Node entry still leaked Bun-only fields and ambient types
|
|
1101
|
-
const route: RawRoute = { handler: (_req, ctx) => ctx.server?.upgrade(...) }
|
|
1102
|
-
const socket = await createSocketIOServer(config)
|
|
1103
|
-
socket.websocket
|
|
1104
|
-
|
|
1105
|
-
// after — name a custom embedding host only when one exists
|
|
1106
|
-
const route: RawRoute<MyHostServer> = {
|
|
1107
|
-
handler: (_req, ctx) => useHost(ctx.server),
|
|
1108
|
-
}
|
|
1109
|
-
const socket = await createSocketIOServer(config)
|
|
1110
|
-
socket.io
|
|
1111
|
-
socket.attach(nodeHttpServer)
|
|
1112
|
-
```
|
|
1113
|
-
|
|
1114
|
-
Node consumers can remove `@types/bun` unless another dependency independently
|
|
1115
|
-
requires it.
|
|
1116
|
-
|
|
1117
|
-
### Managed server shutdown
|
|
1118
|
-
|
|
1119
|
-
`createServer()` and `serveNode()` now return the same structural managed
|
|
1120
|
-
lifecycle. Replace every direct runtime stop and parallel Socket.IO close:
|
|
1121
|
-
|
|
1122
|
-
```ts
|
|
1123
|
-
// before — split ownership
|
|
1124
|
-
const socket = await createSocketIOServer(config)
|
|
1125
|
-
const server = createServer({
|
|
1126
|
-
services,
|
|
1127
|
-
websocket: socket.websocket,
|
|
1128
|
-
rawRoutes: [socket.route],
|
|
1129
|
-
})
|
|
1130
|
-
server.stop()
|
|
1131
|
-
await socket.io.close()
|
|
1132
|
-
|
|
1133
|
-
// after — one owner and one total deadline
|
|
1134
|
-
const socket = await createSocketIOServer(config)
|
|
1135
|
-
const server = createServer({ services, socket })
|
|
1136
|
-
const result = await server.shutdown({ gracePeriodMs: 30_000 })
|
|
1137
|
-
```
|
|
1138
|
-
|
|
1139
|
-
On Node, keep the same `socket` field and replace `handle.close()` with
|
|
1140
|
-
`handle.shutdown()`. Runtime-specific diagnostics move under `handle.runtime`;
|
|
1141
|
-
do not use it as a second shutdown path. Standalone CLI/tools that create a
|
|
1142
|
-
Socket.IO handle without an HTTP server call `await socket.close()`.
|
|
1143
|
-
|
|
1144
|
-
If Bun Socket.IO shares the port with a raw lane, keep the explicit composition
|
|
1145
|
-
but let the server mount the Socket.IO route:
|
|
1146
|
-
|
|
1147
|
-
```ts
|
|
1148
|
-
createServer({
|
|
1149
|
-
services,
|
|
1150
|
-
socket,
|
|
1151
|
-
websocket: composeWebSocketHandlers([
|
|
1152
|
-
webSocketLane({ match: isRaw, handlers: rawHandlers }),
|
|
1153
|
-
socketIoLane(socket.websocket),
|
|
1154
|
-
]),
|
|
1155
|
-
rawRoutes: [rawUpgradeRoute],
|
|
1156
|
-
})
|
|
1157
|
-
```
|
|
1158
|
-
|
|
1159
|
-
Move native Bun `routes` entries to `rawRoutes`. Native routes run before the
|
|
1160
|
-
Fetch handler and therefore cannot participate in admission or drain. Wire
|
|
1161
|
-
`SIGTERM`/`SIGINT` in the application; the first signal starts `shutdown()`, and
|
|
1162
|
-
a later signal may abort the same controller. Close MCP, databases and queues
|
|
1163
|
-
after the server result—those resources remain application-owned.
|
|
1164
|
-
|
|
1165
|
-
Move a handshake policy from the Node-only callback shape inside
|
|
1166
|
-
`serverOptions` to the runtime-neutral top-level policy. It receives a Web
|
|
1167
|
-
`Request`, may be async, and returns whether to admit the handshake:
|
|
1168
|
-
|
|
1169
|
-
```ts
|
|
1170
|
-
// before
|
|
1171
|
-
serverOptions: { allowRequest: (request, done) => done(null, allowed(request)) }
|
|
1172
|
-
|
|
1173
|
-
// after
|
|
1174
|
-
allowRequest: (request) => allowed(request)
|
|
1175
|
-
```
|