@ratel-ai/sdk
v0.2.0
Published
TypeScript SDK for Ratel — context engineering platform for AI agents. BM25 tool retrieval, MCP ingestion, framework-neutral gateway tools.
Downloads
1,289
Maintainers
Readme
TypeScript SDK for Ratel. Bundles ratel-ai-core (Rust) via NAPI-RS so JS/TS agents can drop Ratel in with one dependency — no Rust toolchain, no service to deploy.
Install
pnpm add @ratel-ai/sdk
# or
npm install @ratel-ai/sdkFrom 0.1.4, prebuilt native bindings ship for darwin-arm64, darwin-x64, linux-x64-gnu, linux-arm64-gnu, and win32-x64-msvc — no Rust toolchain required to install. The right per-platform binary is selected automatically via npm optionalDependencies. See ADR 0002 for the rationale.
Usage
The SDK exposes two layers, both framework-neutral.
ToolRegistry — metadata-only BM25 index
Use this when you just need ranking and you'll dispatch tool calls yourself.
import { ToolRegistry, type Tool } from "@ratel-ai/sdk";
const registry = new ToolRegistry();
registry.register({
id: "read_file",
name: "read_file",
description: "Read a file from local disk and return its textual contents.",
inputSchema: { properties: { path: { type: "string" } } },
outputSchema: { properties: { contents: { type: "string" } } },
});
const hits = registry.search("read a text file", 5);
// [{ toolId: "read_file", score: 1.42 }, ...]ToolCatalog + gateway tools — register once, dispatch by id
ToolCatalog extends the registry with executable handlers (id → execute), and searchCapabilitiesTool / invokeToolTool give your agent a self-service gateway over the catalog. Pair them with any agent framework — see examples/ai-sdk/ for a Vercel AI SDK wiring.
import {
ToolCatalog,
searchCapabilitiesTool,
invokeToolTool,
type ExecutableTool,
} from "@ratel-ai/sdk";
const catalog = new ToolCatalog();
catalog.register({
id: "read_file",
name: "read_file",
description: "Read a file from local disk.",
inputSchema: { properties: { path: { type: "string" } } },
outputSchema: { properties: { contents: { type: "string" } } },
execute: async ({ path }) => ({ contents: await fs.readFile(path, "utf8") }),
});
// Gateway tools — wrap them into your framework's tool type.
// Each returns ExecutableTool ({ id, name, description, inputSchema, outputSchema, execute }).
const search = searchCapabilitiesTool(catalog);
const invoke = invokeToolTool(catalog);Tool injection (replace vs suggest, ADR 0003) is layered on later when the SDK exposes a higher-level adapter.
SkillCatalog + getSkillContentTool — reusable playbooks, on demand
Skills are Markdown playbooks ranked by a separate BM25 corpus. Pass a SkillCatalog as the second argument to searchCapabilitiesTool and the search returns a skills bucket alongside tools — each with its own result budget, so a relevant skill is never crowded out by matching tools. The agent loads a skill's full body on demand via getSkillContentTool.
A skill can also declare the tools its instructions call: when the skill matches, those tools are pulled into the tools bucket (additively, deduped), so the agent gets the playbook and the tools it needs in a single turn instead of a second search.
import {
SkillCatalog,
searchCapabilitiesTool,
getSkillContentTool,
type Skill,
} from "@ratel-ai/sdk";
const skills = new SkillCatalog();
skills.register({
id: "vercel-deploy",
name: "vercel-deploy",
description: "How to deploy to Vercel: env vars, preview vs production, rollbacks.",
tags: ["deploy", "ship to production"], // indexed for ranking
tools: ["vercel__deploy", "fs__read_file"], // surfaced with the skill
metadata: { stacks: ["next", "vercel"] }, // non-indexed context (push ranker)
body: "## Deploying to Vercel\n1. ...", // returned by getSkillContentTool
});
// Pass the skill catalog as the 2nd arg → result: { tools: {...}, skills: [...] }
const search = searchCapabilitiesTool(catalog, skills);
const load = getSkillContentTool(skills); // id == "get_skill_content"Only id, name, and description are required; tags, tools, metadata, and body are optional (parity with the Python SDK).
registerMcpServer — index an MCP server's tools into the catalog
Hand the catalog a connected MCP transport and Ratel will call tools/list, register each upstream tool with a server-namespaced id (<name>__<toolName>), and wire its executor to tools/call over the same connection. Use any transport from @modelcontextprotocol/sdk — stdio, Streamable HTTP, or SSE.
import { ToolCatalog, registerMcpServer } from "@ratel-ai/sdk";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const catalog = new ToolCatalog();
const handle = await registerMcpServer(catalog, {
name: "fs",
transport: new StdioClientTransport({
command: "npx",
args: ["-y", "@modelcontextprotocol/server-everything"],
}),
});
// handle.toolIds → ["fs__echo", "fs__add", ...]
// catalog.search / catalog.invoke now see the upstream tools alongside any local ones.
await handle.close(); // disconnect on shutdownErrors from the upstream tools/call propagate as rejected promises from catalog.invoke, so they slot into the same handling as local executors.
Telemetry
Pass trace to the ToolCatalog constructor to capture every search / invoke / gateway / upstream / auth event into a sink owned by the Rust core (ADR 0009). Default is no-op — nothing is captured unless you opt in.
const catalog = new ToolCatalog({
trace: { kind: "jsonl", sessionId: "session-1", path: "/tmp/ratel.jsonl" },
});
// every catalog.invoke, searchCapabilitiesTool, registerMcpServer call now writes
// one JSON line per event to /tmp/ratel.jsonl.Sink kinds:
{ kind: "noop" }— drop everything (default).{ kind: "memory"; sessionId }— keep events in memory; drain viacatalog.drainTraceEvents(). Useful for tests.{ kind: "jsonl"; sessionId; path }— append one JSON line per event topath(mode0600on Unix). Best-effort, lossy on backpressure — see ADR-0009 for the reliability profile.
searchCapabilitiesTool tags its emitted search event with origin: "agent"; direct callers (catalog.search(query, k)) default to "direct". Override per call via catalog.search(query, k, "agent").
Package shape
- Package name:
@ratel-ai/sdk - ESM entry (
dist/index.js); the underlying NAPI loader is CJS, statically bridged at build time. - Native binding lives in
native/(Rust + NAPI-RS).
Build & test
Part of the pnpm workspace at the repo root. From this folder:
pnpm build:native # cargo + napi → native/{*.node, index.cjs, index.d.cts}
pnpm build:ts # tsc → dist/
pnpm build # both
pnpm typecheck
pnpm lint # biome
pnpm test # vitest (rebuilds native first)Or run against the whole workspace from the repo root with pnpm -r <script>.
