Repository navigation
Releases
v0.12.0
v0.11.0
v0.10.0
What's Changed
- fix(build): ship no test fixtures, and fail the build on one only tests reach by @saadahmed95 in #202
- chore(build): remove four unused layer index files, and ship nothing the root doesn't reach by @saadahmed95 in #203
- feat(transport)!: forward no caller header to tools when auth.forwardHeaders is unset by @saadahmed95 in #204
- build(build): release 0.10.0 by @saadahmed95 in #205
Full Changelog: v0.9.0...v0.10.0
v0.9.0
What's Changed
- feat(transport): record which persona wrote an assistant entry by @saadahmed95 in #181
- feat(testing): export the recorded protocol frames as a consumer fixture by @saadahmed95 in #182
- feat(providers): fail over to a second provider when one is unavailable by @saadahmed95 in #183
- feat(transport): let a consumer set the text of the connect frame by @saadahmed95 in #184
- feat(providers): add a reversible prompt mask at the provider boundary by @saadahmed95 in #185
- lore: onboard re-cinq/halengine by @lore-agent[bot] in #196
- docs(spec): describe the shipped tool-response contract by @saadahmed95 in #190
- feat(types): give session state a creation time to measure age from by @saadahmed95 in #186
- feat(providers): make the mock provider scriptable by @saadahmed95 in #187
- feat(providers): report token usage from the Bedrock provider by @saadahmed95 in #188
- fix(transport): refuse an authenticated id the engine cannot use as an identity by @saadahmed95 in #189
- feat(orchestration): read the tool list every turn, not at construction by @saadahmed95 in #191
- feat(transport): carry the authenticated user into the tool context by @saadahmed95 in #192
- feat(transport): let a consumer choose which caller headers reach a tool by @saadahmed95 in #193
- ci(lore): bring the ingest workflow to v7, keeping local hardening by @gedaiu in #199
- build: Bump eslint from 10.12.0 to 10.13.0 in the development group across 1 directory by @dependabot[bot] in #180
- feat(session): support mongodb driver 7 by @vvondruska in #169
- feat(tools): mark a failed tool result as an error on the provider wire by @saadahmed95 in #195
- fix(orchestration): give each tool call its own copy of the caller's headers by @saadahmed95 in #200
- build(build): release 0.9.0 by @saadahmed95 in #201
Full Changelog: v0.8.0...v0.9.0
v0.8.0
What's Changed
- feat(providers): run the Vertex provider on @google/genai by @saadahmed95 in #178
- build(build): release 0.8.0 by @saadahmed95 in #179
Full Changelog: v0.7.0...v0.8.0
v0.7.0
What's Changed
- stop save from resurrecting erased conversations by @lore-agent[bot] in #168
- build: Bump the development group across 1 directory with 6 updates by @dependabot[bot] in #167
- build: Bump the production group across 1 directory with 4 updates by @dependabot[bot] in #166
- build: Bump mongodb-memory-server from 10.4.3 to 11.3.0 by @dependabot[bot] in #138
- build: Bump actions/setup-node from 7.0.0 to 7.1.0 by @dependabot[bot] in #159
- fix(transport): answer unhandled HTTP errors with a safe JSON response by @saadahmed95 in #170
- fix(tools): refuse a duplicate tool name in ToolRegistry by @saadahmed95 in #171
- fix(transport): close an upgraded WebSocket with 1011 instead of writing HTTP 500 into it by @saadahmed95 in #172
- fix(session): break a tie on session activity by one rule in both stores by @saadahmed95 in #173
- feat(transport): map every AIError to a client error through one table by @saadahmed95 in #174
- fix(transport): blank every model-authored entry when a tool suppresses the response by @saadahmed95 in #175
- fix(transport): bind the credential the engine authenticates to the one it forwards by @saadahmed95 in #176
- build(build): release 0.7.0 by @saadahmed95 in #177
Full Changelog: v0.6.1...v0.7.0
v0.6.1
What's Changed
- chore(docs): reference public issues in the specs, not internal ones by @vvondruska in #157
- chore(build): update re-lint to 1.8.0 by @vvondruska in #158
- chore(deps): patch handlebars by @saadahmed95 in #164
- fix(providers): send Gemini's thought signature back with each tool call on Vertex by @saadahmed95 in #163
- build(build): release 0.6.1 by @saadahmed95 in #165
Full Changelog: v0.6.0...v0.6.1
v0.6.0
What's Changed
- chore(deps): patch proxy-addr by @saadahmed95 in #142
- test(transport): pin criteria left untested by @saadahmed95 in #141
- feat(session): list a user's conversations from the store by @vvondruska in #146
- feat(transport): answer a client's conversation list over the socket by @vvondruska in #152
- test(transport): pin rootRoutes content type by @saadahmed95 in #153
- feat(session): label a listed conversation with its opening question by @vvondruska in #154
- build(build): release 0.6.0 by @vvondruska in #156
Full Changelog: v0.5.0...v0.6.0
v0.5.0
Session resume, a cancellation chain from the socket through the provider to every tool call, tools that run on Vertex, and failing tool calls answered to the model. One thing is removed and several behaviours an existing consumer observes change: see Upgrading from 0.4.x below. Every release up to and including 0.4.0 has two defects that end the process (see Security and Fixed), so upgrade even if you use none of the new features.
Upgrading from 0.4.x
- Every client must offer
hal.v1beside its token,new WebSocket(url, ['hal.v1', token]). A bare-token offer, accepted with a deprecation warning since 0.3.0, now fails to connect, andcredentialFromSubprotocolreturnsundefinedfor it. - Closing a socket abandons its turn. The run stops reading from the model and abandons its tool calls, no
stream_endfollows the close, andafterModelResponseandonErrordo not fire for it, whileafterSessionstill does. A missed heartbeat andstop()close sockets too, so drain connections before a deploy. - Every tool call now has 30 seconds to settle, a
beforeToolCallpolicy included. A tool that legitimately runs longer needs a largertoolTimeoutMs, or0for the old unbounded wait. ToolRegistry.executeno longer throws for a tool name the model invented, or rejects when an executor throws: the model is answered instead. It throws aTypeErrorfor an input that is not an object, whatever the tool's schema.- Messages in one session are answered one at a time, so a message sent while another is streaming starts after that one's
stream_end. - Tools now run on Vertex, where a function-calling turn ends
tool_useinstead ofend_turn. If you readstopReasonyourself, expect the new value. - Two new
errorlog lines:authenticator failedfor aWsAuthenticatorthat throws or rejects, andtool executor threwfor a tool executor that does. - Resume is opt-in and changes nothing until you enable it. With it on, do not erase a conversation in
onDisconnect: the socket a resume replaced can reportonDisconnectafter the resume.
Added
- Session resume, opt-in via
transport: {resume: {enabled: true}}. A client that reconnects with?sessionId=<id>gets its conversation back, but only the session's own user; any other id gets a fresh session, indistinguishable from one that never existed. - Continue the latest session with
resume: {enabled: true, latest: true}: a refresh or a new tab rejoins the user's most recently active conversation, and?new=1starts a new one. Stores supply it through the optionalSessionStore.latestFor. - An expired session told apart from a missing one, through the optional
SessionStore.lookupandresumeFailureon theconnectedframe, which readsexpiredonly for the session's owner. - Cancel a model call with
SendMessageParams.signal. Bedrock closes the request;@google-cloud/vertexaicannot cancel, so on Vertex the engine stops reading while the vendor request runs on. - A deadline on every tool call,
toolTimeoutMs(default30000,0waits forever), and aToolContext.signalaborted at the deadline with aTimeoutError, so a tool that passes it tofetchstops its own request too. - Stored entries a tool suppressed carry
suppressed: true, so a resumed session never shows text a tool hid.
Removed
- The bare-token subprotocol offer. It put the access token in the 101 response headers; clients have offered
['hal.v1', token]since 0.3.0.
Changed
- Closing a socket abandons its turn, as above. The session keeps the answer as it stood, committed and flagged
truncated, so a resumed session shows it cut off.processMessageStreamtakes an optional{signal}that does the same for a caller of its own. credentialFromSubprotocolreturnsundefinedunless the offer includeshal.v1.- A failing
WsAuthenticatoris logged aterror, with its error type only, never its message.
Fixed
- Messages in one session are answered one at a time, in the order they arrived, instead of interleaving two runs.
- A Vertex stream that failed mid-way ended the process, through an unobserved promise inside
@google-cloud/vertexai. Every release up to and including 0.4.0 is affected. - No tool ever ran on Vertex: the provider reported a function-calling turn as
end_turn, so the call was dropped. Every release up to and including 0.4.0 is affected. - A failing tool call no longer fails the turn. An invented tool name or a throwing executor is answered to the model, and the round's other results survive. The thrown message is logged, cut to 500 characters, and never shown to the model; a throw after the user left is logged at
infoastool call abandoned. - An answer still streaming when a tool suppresses the response is committed and retracted like one already sent.
Security
- One malformed WebSocket upgrade could end the process. An empty or missing
Hostheader, or a request-target such as//, threw where nothing catches it, so a single request with no credentials ended the process and every conversation on it. It is now answered400 Bad Request. Every release up to and including 0.4.0 is affected.
Full detail is in CHANGELOG.md.
v0.4.0
Durable sessions, provider retries, and three hook-reliability fixes. Nothing is removed and no existing signature changes, but three behaviours an existing consumer observes do change — see Upgrading from 0.3.x below.
Upgrading from 0.3.x
- A closed socket no longer erases the conversation. The WebSocket close handler used to call
sessionStore.delete(sessionId)unconditionally, so behind a durable store every conversation was written and then destroyed the moment the customer closed their tab.deletenow has no engine-internal caller and is purely your erasure primitive. To restore the old behaviour, passonDisconnect: sessionId => store.delete(sessionId)— but do not point that atMongoSessionStore, wheredeletedestroys the document. afterModelResponsenow reports the whole turn's usage. It receivestotalUsage, the sum across every provider call in the turn, rather than the last round alone. Billing and audit consumers will see totals rise on tool-heavy turns; that is the corrected figure.onErrornow fires for rejections that are notErrorinstances. A non-Errorvalue is wrapped in anErrorwhosecauseis the original, so a hook typed againstErrorkeeps compiling and a hook that wants the raw value can reach it.SessionStoremembers are nowAwaitable<T>. A synchronous store needs no change.- New optional peer dependency:
mongodb, loaded only ifMongoSessionStoreactually connects.
Added
MongoSessionStore— a durable session store, exported asMongoSessionStoreandcreateMongoSessionStore. Takes a collection, a client with a database name, or a connection URL; nothing reads the environment for you. No credential is ever written:authHeaders,authorization,cookieandhostare stripped at any depth, and the samestripCredentialKeysis exported for stores you write yourself.SessionStore.save(session)— the write signal a durable store needs, called once per processed user message from the same path that runsafterSession, so it fires for a turn that ended in a provider error as well as one that succeeded. What it throws is logged and the turn continues: a database outage is not a reason for the agent to stop answering.SessionStore.evict(sessionId)and a boundedInMemorySessionStore, which now takes{maxAgeMs}(eight hours by default). There is no timer — a library-owned interval would keep your process alive.withRetry(provider, policy)— wraps anyAIProviderwith per-attempt retry and two separate deadlines. Retries stop once the first chunk has been handed off, because streamed output cannot be un-sent; a stalled stream surfaces as anAIErrorwith codeTIMEOUT. Defaults:maxAttempts: 3,baseDelayMs: 500,maxDelayMs: 5000,firstChunkTimeoutMs: 30000,idleChunkTimeoutMs: 30000, exponential backoff with full jitter.HalEngineConfig.resilience?: RetryPolicy— when present,createHalEnginewraps the configured provider; when absent, behaviour is unchanged.
Fixed
onErrorandafterSessionnow run whenbeforeSessionthrows. The call sat above thetry, so a failure during session setup skipped both hooks — and leaked whateverbeforeSessionhad allocated on exactly the path where the allocation failed.
Full detail, including the entries not repeated here, is in CHANGELOG.md.