Changelog
Release history of @ratel-ai/sdk.
@ratel-ai/sdk release history · npm · source
Synced verbatim from the package's
CHANGELOG.mdatratel-ai/ratel@d8635d5— do not edit by hand. Regenerate withpnpm sync:apiinapps/docs.
All notable changes to @ratel-ai/sdk are documented here.
The format follows Keep a Changelog and this package adheres to Semantic Versioning.
[0.7.0] - 2026-08-07
On npm's
rcchannel? The0.6.1-rc.*and0.7.0-rc.0prereleases on npm were cut off experimental branches that never landed, so they are not ancestors of this release.0.7.0does not contain their seed-first intent-graph APIs (experimentalBuildIntentGraph,experimentalBaselineTurn, the"callback"trace sink) orexperimentalExposePassthrough; moving fromrctolatestdrops them. Upgrades from0.6.0are unaffected — for them this release is purely additive.
Added
- Whole-catalog skill reload:
SkillCatalog.replaceAll(ADR-0015). For a source that fetches the full skill catalog rather than individual changes — the batch is the catalog, so ids missing from it are removed, including ones registered in-process (a host mixing local and remote skills composes the batch itself). It mutates in place, so the oneSkillCatalogbehindr.skills, every adapted view, and every capability tool frommodelTools()all see the reload. Two-phase likeregister: the corpus swap commits synchronously and the embedding pass is the awaitable, so a reload whose embedding pass fails still reports what the swap changed —replaceAllreturns aPendingReplacecarrying theReplaceOutcomecounts (added / removed / updated / unchanged) and awaitable separately. On embedding failure the new corpus is live and BM25 ranks it while semantic search reportsEmbeddingsNotBuiltuntil a later pass succeeds; a reload started while a dense operation owns the registry is rejected rather than blended. Reloading an unchanged catalog costs zero embeddings, andadvertiseSkillsalready pins thesearch_capabilitiesdescription, so a reload can't bust the prompt cache.PendingReplaceandReplaceOutcomeare exported. registerMcpServerfollows everytools/listpage. Ingestion previously read only the first page, silently dropping every tool past it on a paginated server. It now walksnextCursorto exhaustion (treating""as a valid cursor, per MCP — only an absentnextCursorends pagination) across bothmcp1.x and 2.x clients, capped at 64 pages.McpToolsListError(with a stablecodeof"RepeatedCursor"or"PaginationExceeded") and theMcpToolsListErrorCodetype are exported, so a cursor loop or a runaway server is a typed failure rather than a hang.McpServerHandle.toolIdsnow spans all pages in upstream list order.
Fixed
registerMcpServercloses the MCP client when connecting, listing, or catalog registration throws. It previously leaked the live connection on any failure afterconnect.
[0.6.0] - 2026-07-28
Coming from
0.6.0-rc.0? That RC was tagged off a branch that predated 0.5.3, so it still shippedconfigureTelemetry()and pinned@ratel-ai/telemetry@^0.1.2. Read the 0.5.3 entry below as part of this upgrade — its breaking changes land for you here. Upgrades from 0.5.3 are unaffected: for them this release is purely additive.
Added
- Experimental adaptive usage ranking (ADR-0014).
IntentGraphplusexperimentalEnableAdaptiveRanking,experimentalRebuildIntentGraph,experimentalDisableAdaptiveRanking, andexperimentalAdaptiveRankingStatusonToolCatalog/SkillCatalog(and the underlying registries). The catalog learns from each search-then-invoke and boosts future rankings; persist and reload the learning viaIntentGraph.toJson/fromJson, and track writes viagraph.rev. Shipped behind anexperimentalprefix — the API may change until it graduates. rankandfusedon search hits: order onrank, and branch onfusedto know whether the usage arm changed the ranking.- Opt-in recovery after an embedding-model change:
experimentalEnableAdaptiveRanking(graph, { rebuildOnModelChange: true })re-embeds a paused graph on the next dense search. Default off; explicitexperimentalRebuildIntentGraph()otherwise.experimentalAdaptiveRankingStatusreports the paused/active state and the mismatched model detail.
[0.5.3] - 2026-07-26
Read this before upgrading from 0.5.2. Despite the patch version, this release removes
configureTelemetry(). The number is patch because 0.5.3 was already cut in the repo before the removal landed and the two shipped together; treat the upgrade as breaking if you called that function. Everything else is additive.
Added
- Content capture emits structured OpenTelemetry Logs
EventRecords.EVENT_ONLYandSPAN_AND_EVENTnow produce real records (in 0.5.2 the event half of those modes emitted nothing), carryinggen_ai.system_instructions,gen_ai.input_messages,gen_ai.output_messages, andratel.tool.execution_details. Tool results stay out of inference-output messages, which are reserved for model output with afinish_reason.
Changed
- BREAKING: the telemetry bootstrap
configureTelemetry()is gone, with itsTelemetryHandle,InitOptions, andConfigureTelemetryOptionstypes. The SDK ships no OpenTelemetry provider wiring — it emitsratel.*/gen_ai.*to whatever providers the host has registered, and the host owns the provider (new NodeSDK({ spanProcessors })), its composition, and its flush/shutdown. The content-capture gate (ContentCapture,setContentCapture,clearContentCapture) and the emitted spans andEventRecords are unchanged. To migrate, build the provider yourself and register it before importing the SDK; see the package README. - BREAKING: the optional
@ratel-ai/telemetry-otlppeer dependency is gone, along with therequire()-an-ES-module machinery that loaded it.@ratel-ai/telemetry-otlpis discontinued, and 0.4.0'sratelSpanProcessorrecipe with it: build the OTLP exporter onto the provider you register. engines.nodeis now>=20.6.0(0.5.2 declared>=20.0.0), matching the@ratel-ai/telemetryruntime dependency.- New runtime dependency
@opentelemetry/api-logs(^0.220.0), the API-only Logs surface theEventRecordemission needs. Like@opentelemetry/apiit is inert until the host registers a provider. - The
@ratel-ai/telemetrydependency floor moves to^0.2.0, the vocabulary version that defines theEventRecordcontract.
[0.5.2] - 2026-07-24
Changed
- Ship the native addon built with symbol stripping and thin LTO (
[profile.release]), shrinking the.nodebinary ~26% (9.90 MB → 7.36 MB on the sdk-ts cdylib). No API or behavior change.
[0.5.1] - 2026-07-23
Added
- Framework-adapter SPI +
ratel()factory (ADR-0013).ratel(config)is a standalone, framework-free core:r.toolsis a handle over its one sharedToolCatalog(register nativeExecutableTools any time — also after exposure, since the capability tools search the live catalog),r.skillsthe sharedSkillCatalog,modelTools()returns the three capability tools (always all three, so the set never depends on registration order), andrecall(query)is an async pure query resolving to the canonicalsearch_capabilitiesresult ornull.adaptTo(adapter)layers a framework-shaped view over the same state:tools.register(...)ingests framework tools (first registration of an id wins across views; provider-run tools pass through per view),modelTools()returns the model-facing set in framework shape,recall(query)resolves to the synthetic message pair with a call id from the core's private counter (never a transcript position).RatelConfigforwardsmethodandembeddingto both catalogs, so a"semantic"/"hybrid"core is fully configurable through the factory (ADR-0012's models).r.tools.register(...)is async: it validates synchronously (a missingexecute, a reserved id, or a framework-shaped tool throws at the call site) and returns a promise that resolves once the batch is indexed and — on a semantic/hybrid core — embedded, rejecting if embedding fails, so errors surface at registration (await r.tools.register(...)before searching a dense core). The handle'ssearch(...)is synchronous BM25-only (a dense method points tosearchAsyncinstead of leaking the native error);searchAsync(...)ranks any method off the event loop. Types are inferred from the adapter (AdaptedRatel<A>), so app code needs no casts. ARatelAdapteris three codecs —ingest(framework tool → catalog registration, or"passthrough"),expose(capability tool → framework tool),recallMessages(syntheticsearch_capabilitiespair) — plus an optionalextendfor framework idioms; the framework packages (@ratel-ai/vercel-ai-sdk,@ratel-ai/mastra) ship separately. Guards are core-owned: reserved capability-tool ids throw on registration, recall top-K is capped at 50 (invalid values fall back to the default 5), and a framework-shaped tool on the native path throws an actionable install-the-adapter error, probing known frameworks viaisPeerInstalled(message only). The existing piecemeal API (ToolCatalog, capability-tool builders) is unchanged, except one additive option:SearchCapabilitiesOptions.advertiseSkillspins the skills clause of thesearch_capabilitiesdescription on or off (the size-gated default is untouched);modelTools()uses it so the exposed payload is byte-identical whether skills register before or after it is taken. runCapabilitiesSearch(toolCatalog, query, opts)— the exported single source of truth for thesearch_capabilitiesresult shape, shared bysearchCapabilitiesTool(originagent) and the host-driven recall path (origindirect). Async, matching the catalog'ssearchAsyncretrieval.JSONSchema7is re-exported as the SDK's public JSON-Schema spelling so adapters type their registrations without casts.- Adapter conformance testkit (
@ratel-ai/sdk/testkit). A runner-agnostic battery every framework adapter must pass, pinning the whole SPI contract: ingest/expose round-trip, the reserved-id guard, recall top-K clamp, passthrough semantics, and recall-pair shape (validated through framework-supplied hooks).adapterConformanceCases(options)returns named cases (assertions vianode:assert, so no test-runner dependency leaks into shipped types);describeAdapterConformance(options, { describe, it })registers them as first-class tests under Vitest/Jest/node:test. ShipsreferenceAdapter/referenceConformanceOptionsas the worked example a real adapter's options copy. Reached via a newexportsmap whose.entry is byte-identical to today'smain/types; the map also seals hypothetical deep imports of package internals. - Framework adapters can attach an
InputValidatortoCatalogRegistration/ExecutableTool; the sharedToolCatalogkeeps that parser authoritative across adapted views and native hot-swaps.validateInput()exposes the live parser, andinvokeValidatedRaw()preserves a prevalidated executor's immediate scalar, promise, orAsyncIterableshape.invokeRaw()provides the same preservation after synchronous validation, whileinvoke()remains the Promise-based public convenience path. invoke_tooltarget failures remain structured for generic hosts and now carry their original cause under a non-enumerable symbol for framework adapters.
Changed
- Add an optional opaque invocation context to
Executor,CatalogRegistration.execute, andToolCatalog.invoke, and forward it unchanged throughinvokeToolTool. Framework adapters can now preserve request-scoped execution state without the core inspecting, storing, or tracing it; existing one-argument executors retain their source compatibility and runtime call arity.
Fixed
invoke_toolno longer collapses streamed tool results into an opaque object; local trace events andexecute_toolspans now settle when iteration completes, is cancelled, or fails, including cancellation-cleanup failures.
[0.5.0] - 2026-07-20
Added
register()accepts a single item or an array across tool/skill registries and catalogs.- Configurable default, HuggingFace, local Candle, Ollama, and OpenAI-compatible
endpoint embedding sources, with public
EmbeddingSpecandEmbeddingModelConfigtypes. - Typed embedding errors:
EmbedderError(with a stablecode) and itsDimensionMismatchErrorsubclass are thrown fromregister()/searchAsync()on a semantic/hybrid catalog, so callers can branch oninstanceof/codeinstead of matching message text — parity with the Python SDK. Invalid embedding config still throws at construction.
Changed
- BREAKING:
register()now returns a promise and accepts a single tool/skill or an array of them, and folds embedding in: on a"semantic"/"hybrid"catalog it embeds the batch on a libuv worker (never blocking the event loop), so embedding errors (model load / endpoint / auth / dimension) surface fromawait register(...). A"bm25"catalog registers metadata only and never loads a model.search()stays synchronous BM25-only;searchAsync()covers BM25/semantic/hybrid. There is noregisterMany(),buildEmbeddings(), orrebuildEmbeddings()—register()embeds, and recovery from a model/dimension change is to construct a new catalog and re-register. - Capability tools await async retrieval; MCP ingestion embeds ingested tools during
register. - Embedding configuration is validated and retained on BM25-default catalogs for later async semantic/hybrid overrides; source unions are mutually exclusive.
Fixed
- A
"semantic"/"hybrid"searchAsync()whose corpus was never embedded (the signature of a forgottenawait register(...)) now reports an actionable "did you await register()?" hint, not just the bare "embeddings not computed" message.
[0.4.1] - 2026-07-10
Added
configureTelemetryopts into message/tool content capture programmatically:captureContentsets the exactContentCapturemode (validated like the env var — case-insensitive, legacy boolean forms accepted — throwing aTypeErroron garbage before any exporter is wired), andincludeSpanAndEventsis boolean sugar (true→SPAN_AND_EVENT,false→NO_CONTENT).captureContentwins overincludeSpanAndEvents; when neither is provided,OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENTkeeps ruling (a provided option beats the env var, as in OTel code-over-env precedence). The handle'sshutdown()restores env-driven behavior via a generation-scoped clear (clearContentCapture), so a stale handle shutting down late never clobbers an override a newerconfigureTelemetryinstalled.ContentCapture,setContentCapture, andclearContentCaptureare re-exported from@ratel-ai/sdk(newConfigureTelemetryOptionstype).
[0.4.0] - 2026-07-07
Added
- OpenTelemetry emission. The SDK now opens an OTel span at each funnel boundary —
execute_tool(gen_ai.operation.name,gen_ai.tool.name,ratel.tool.args_size_bytes, plusratel.upstream.serverfor MCP-proxied tools),ratel.search(target,top_k, origin,hit_count),ratel.skill.load,ratel.upstream.register, andratel.auth.flow— alongside the existing localrecordEventstream, which is unchanged. Emission is transparent and free by default: spans flow to whatever OpenTelemetry provider is registered and are a no-op until one is, so a host already running OTel sees Ratel's funnel on its traces with no setup. Built on@opentelemetry/api+ the OTel-free@ratel-ai/telemetryvocabulary, so the base install stays OTel-SDK-free. configureTelemetry({ apiKey })convenience wiring (withTelemetryHandle/InitOptions): lazily loads the optional@ratel-ai/telemetry-otlppeer to ship the SDK's spans to Ratel Cloud (or any OTLP endpoint). Hosts already running OpenTelemetry skip it and addratelSpanProcessorfrom@ratel-ai/telemetry-otlpinstead.- Message/tool content (
ratel.search.query,gen_ai.tool.call.arguments/.result) rides span attributes only whenOTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENTselects a span mode (SPAN_ONLY/SPAN_AND_EVENT); default off.ratel.tool.args_size_bytesis measured in UTF-8 bytes.
[0.3.0] - 2026-07-06
Added
ToolCatalog/SkillCatalogaccept a defaultmethod("bm25"|"semantic"|"hybrid") andsearch(query, topK, origin?, method?)takes a per-call override."bm25"(default) is unchanged and model-free;"semantic"/"hybrid"load a local embedding model and throw if it fails to load. Exposed via the nativesearchWithMethodbinding and theSearchMethodtype.- A
"semantic"/"hybrid"catalog embeds each tool/skill eagerly atregister(incrementally), so searches never pay the corpus-embedding cost. Newcatalog.buildEmbeddings()pre-computes embeddings on demand (e.g. after a bulk register). BM25 catalogs do neither. A semantic/hybrid search on a catalog with no embeddings built throws (embeddings not computed) rather than embedding during the search.
[0.2.1-rc.1] - 2026-07-04
Changed
- First release cut under the per-package release scheme (ADR-0008):
@ratel-ai/sdk(loader + platform packages) now versions and ships independently, taggedsdk-js-v*. No API changes since 0.2.0.
[0.2.0] - 2026-06-16
Changed
- BREAKING: the discovery gateway tool is renamed
search_tools→search_capabilities. It now returns two independently-ranked, separately-budgeted buckets —{ tools, skills }— so a relevant skill is never crowded out by matching tools. New surface:searchCapabilitiesTool/SEARCH_CAPABILITIES_ID. The oldsearchToolsTool/SEARCH_TOOLS_IDare kept as deprecated aliases (see Deprecated), so0.1.xcode keeps working after upgrading.
Added
- First-class skills:
SkillCatalog,getSkillContentTool(get_skill_content), andSkill/SkillHit/SkillRegistry. Skills are reusable playbooks ranked by a separate BM25 corpus and loaded on demand. - Skill–tool coupling: a
Skillcan declare atoolslist, andsearch_capabilitiespulls a matched skill's declared tools into thetoolsbucket — additively (beyondtopKTools) and deduped against query hits — so the agent gets the playbook and the tools it needs in one turn.
Deprecated
searchToolsTool,SEARCH_TOOLS_ID, and theSearchToolHit/SearchToolsGroup/SearchToolsResult/SearchToolsToolOptionstypes. They retain their pre-0.2.0 behaviour — a tools-only{ groups }result and thesearch_toolsid — so upgrading from0.1.xdoes not break existing callers. Migrate tosearchCapabilitiesTool; the aliases will be removed in a future release.
Fixed
- Gateway error payloads (
invoke_tool,get_skill_content) carryisError: true, so a host can flag a failed call rather than read it as content. invoke_toolrejects a non-objectargsinstead of forwarding stray top-level keys.search_capabilitiesvalidatestopKTools/topKSkills(declaredinteger, positive):0, negative, and fractional values fall back to the default instead of returning zero results — or, via a negative wrapping tou32in the native layer, an unbounded set. TypeScript and Python behave identically.search_capabilitiesadvertises theskillsbucket andget_skill_contentin its description only when a non-empty skill catalog is wired in.Skill.tagsandSkill.bodyare optional (default[]/""), matching the Python SDK — a minimal{ id, name, description }skill is valid.
[0.1.6] - 2026-06-10
Fixed
- TypeScript typehint for JSON-schema tool input/output (#54).
[0.1.5] - 2026-05-10
Added
- Initial release on the v1 (revamp) line. TypeScript SDK over the Rust core: BM25 tool retrieval, MCP ingestion, framework-neutral gateway tools. See the package README for the full surface.
ToolCatalogaccepts{ trace }config in its constructor —noop(default),memory, orjsonl. Captured events flow through the Rust core sink (ADR-0007). NewrecordEvent,drainTraceEvents, and an optional thirdoriginargument onsearch.searchToolsToolemitsgateway_searchwithorigin: "agent".invokeToolToolemitsgateway_invokeon success andgateway_errorfor unknown ids,needs_auth, and underlying throws.ToolCatalog.invokeemitsinvoke_start/invoke_end/invoke_erroraround the executor withargs_size_bytesandtook_ms.registerMcpServeremitsupstream_registeron connect andupstream_invoke/upstream_errorper upstream call. NewsearchWithOriginand trace plumbing on the underlying NAPIToolRegistry.SearchOriginis now"direct" | "agent"(was"user" | "agent"); the union is exported from the package entry point.
Changed
- Rewrote
search_toolsdescription to nudge agents toward discovery before falling back to broad listing.