@dawn-ai/sdk@0.8.21
Patch Changes
-
c2c19da: New
honobuild target — a Dawn app that deploys to Cloudflare Workers.build: { targets: ["node", "hono"] }makesdawn buildemit an edge deploy
alongside the usual ones:.dawn/build/app.mjs(a Hono app whose single
catch-all hands every request to Dawn's web-standard fetch handler,
export defaulted — the shape Workers, Vercel and Bun all accept),
modules.edge.mjs(the static module manifest, free of node builtins),
stores.mjs(a per-request Postgres store factory), and awrangler.toml
scaffold at the app root.wrangler deployis how you ship it; a gated CI lane
boots those same artifacts under local workerd and shows them serving Agent
Protocol and AG-UI with durable state in Postgres. No deploy to Cloudflare's
platform has been exercised — see the caveats at the end of this note.The scaffold carries a bare
name/main/compatibility_dateand no
nodejs_compat: the bundle links zeronode:specifiers, so the flag would
buy nothing, and setting it would mask a regression in the work that made the
bundle node-free. A gatededge-workerdCI lane boots the emitted artifacts
under real workerd — the same binary Cloudflare runs — with thatwrangler.toml
untouched, and drives four sequential AG-UI turns against Postgres over a
@neondatabase/serverlessWebSocket pool.The target is opt-in and never a default, because the edge serves a subset
of Dawn rather than all of it.- The stores are built per request, and that is not stylistic. A pool held at
module scope hands request N+1 an idle WebSocket bound to request N's dead I/O
context; the request then hangs until workerd cancels it, in an alternating
pattern that fails about half of all requests with nothing thrown. So
stores.mjsbuilds the pool and all three stores inside the factory and ends
the pool on dispose, with a module-scope flag recording that this isolate has
already migrated so per-request instances do not re-run three migration
transactions each time. That pool also gets an'error'listener:
@neondatabase/serverlessvendorspg-pooland theeventspolyfill, so an
idle client's failure re-emits on the pool and the shim throws when nothing is
listening — the same uncaught-exception hazard nodepghas, and one that
nodejs_compatbeing off does nothing to remove. A per-request pool is still
exposed: a client sits idle between every pair of store queries, and pg-pool's
idle listener outlivesend(). requestStores, a new option oncreateRuntimeFetchHandler, is the seam
that makes that possible: a(request) => RequestStoresfactory whose every
field is optional and falls through to the boot-resolved store when omitted.
RequestStoresis exported from@dawn-ai/cli/fetch.- The build fails, by name, on anything the edge cannot serve — with the new
DAWN_E1005, and reporting every offending feature at once rather than one
build at a time:sandbox,backends.filesystem/backends.exec, a
config-suppliedcheckpointer/threadsStore/permissions.store/
memory.store, aworkspace/directory, route skills, and route-level
long-term memory. The store cases matter most: those handles cannot cross a
build boundary, so before the gate the generated Postgres store quietly took
their place.dawn checkapplies the identical gate wheneverhonois a
configured target. - The provider import map is exhaustive or the build fails. A bundler cannot
follow a variable import specifier, soapp.mjsemits a staticswitchover
the model packages the app can reach; whatever is missing from it is missing
from the bundle. A route that will not import, or an agent whose provider
cannot be inferred, is therefore an error rather than a silently narrower map,
andsummarization.modelis included. dawn buildwarns on stderr when@dawn-ai/cli,@dawn-ai/postgres-storage,
@neondatabase/serverlessorhonois missing from the app'spackage.json.
None of them is a dependency of@dawn-ai/cli, deliberately: the CLI does not
import them, the app it generates does.- Your config is inlined into
app.mjsat build time, minus every field that
cannot survive a build boundary, rather than loaded fromdawn.config.tsat
runtime as thenodetarget does. Keep secrets in bindings, not in config.
Also new, both in service of the emitted entry:
seedModelImporterand
providerPackagesfrom@dawn-ai/langchain(re-exported from
@dawn-ai/cli/fetch), andDAWN_E5301on a runtime that reaches a store no
layer supplied.Full walkthrough, the supported subset, and an explicit list of what the CI lane
does not settle — no real Cloudflare deploy, Hyperdrive, production
connection limits, per-query latency, cross-isolate cold starts, and the bundle
size and startup CPU thatwrangler deployenforces andwrangler dev --local
does not — are in the Deployment docs under Edge runtimes. - The stores are built per request, and that is not stylistic. A pool held at
-
c2c19da: Per-request stores are now disposed only after BOTH the response body has
settled and the run that request started has released its slot. Route work
outlives its response on three paths — an aborted AG-UI stream, an abandoned
/runs/wait, a cancelled AP stream — and all three keep writing through the
stores a response-triggered teardown would have closed.close()also waits
for in-flight disposals, so a host awaiting shutdown knows the pools are shut.A runtime that reaches a store no layer supplied now answers with a 500 that
names the missing store and carries the newDAWN_E5301code, instead of a
generic failure with nothing to diagnose.