npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@relyio/agents

v0.4.0

Published

RelyIO tools for AI agents: framework-neutral tool definitions over @relyio/sdk, with the same names and argument schemas as the RelyIO MCP server.

Readme

@relyio/agents

RelyIO tools for AI agents, over the @relyio/sdk client you already create.

Each tool is a plain object — name, description, inputSchema (JSON Schema) and execute(args) — so any agent framework can take it. The names and argument schemas are the ones the RelyIO MCP server uses, so a model sees the same tools on both.

import { createClient } from '@relyio/sdk'
import { relyioTools } from '@relyio/agents'

const tools = relyioTools(createClient({ apiKey: process.env.RELYIO_API_KEY! }))

const result = await tools.getEntry.execute({ contentType: 'post', entryUid: 'welcome' })
// { success: true, entry } or { success: false, error: { code, messages, details } }

What ships

  • getEntry — read one entry by content type and id, optionally from another dataset (datasetId) or in one locale (locale).
  • searchEntries — list one content type with filters and sorting, search across types, or find entries similar to one. status must be active; every filter operator works on a list and a search alike.
  • countEntries — count one content type's entries, with filters. Requires contentType.
  • getSchema and explainContentType — read the schema your key is bound to. getSchema lists each fieldset once with where it is placed — a section, the shape of a list's items or an object's value, a rich-text block or inline element. branch is refused: the key binds it. Unlike the MCP server, explainContentType returns no writeSchema and no authoring guidance.
  • proposeEntryUpdate (one PATCH per locale) and proposeCreateEntries (one atomic batch) keep the MCP server's names, but here the write commits: there is no proposal and no review. A create is published. An update is published only when it names no locale and the default locale is published; naming a published locale — the default included — saves a draft that readers do not see and that the public API cannot publish or discard. The result reports published per locale, read from what the API served back. alias / $alias and reason are refused by name.

Every tool goes through your client, under your API key's permissions. An argument the public API cannot honour is refused by name, never dropped.

Writing structured values

The write tools take values in the forms the MCP server's do:

  • Rich text is RelyIO Markdown — headings, lists, **bold**, tables, fenced code, and directives for the rest (:entryLink[the guide]{to=<entryUid>}, a declared block as ::::callout{tone=tip} …). It is parsed into the rich-text tree before it is sent, wherever it stands: the field itself, a rich-text field of a list item or an object, a block's own rich text. A table field takes one Markdown table, a code field one fenced block. Markdown holding HTML, an image or a footnote is refused with CONTENT_INVALID, naming where, and nothing is written.
  • A list's items and an object's value are objects carrying _type (given for you when the field allows one shape) and _key to keep an existing item.
  • An update addresses one item by its key: fieldPath: 'sections[_key=="k1"].heading', at any depth, or an object's field as cover.alt. The tool reads the entry, finds the item by key wherever the list holds it now, and writes the field back with that item changed, guarded by the entity tag it read: if the entry changed in between, the API refuses with RESOURCE_CONFLICT and nothing lands. A key the entry does not hold is refused by name; an index is no address. This API reads published content, so where a locale has a pending draft, an edit by key is refused — write the whole field there.
  • Entries cannot name each other by alias in one call, in a field or in Markdown: create the referenced entry first and pass its entryUid.

With an agent framework

Two adapters take the tools relyioTools returned — or any record of tools in the same shape — and hand them to a framework. Each is its own entry point, and its framework is an optional peer dependency: install the one you use; @relyio/agents itself loads neither.

Vercel AI SDK (ai 6 or 7)

import { generateText } from 'ai'
import { toVercelAI } from '@relyio/agents/vercel-ai'

const { text } = await generateText({
  model,
  tools: toVercelAI(tools),
  prompt: 'Summarise the welcome post.',
})

toVercelAI(tools) is the AI SDK's tools option: each tool keyed by its name, its schema passed through jsonSchema().

Anthropic SDK (@anthropic-ai/sdk 0.63 or later)

import Anthropic from '@anthropic-ai/sdk'
import { toAnthropicRunnable } from '@relyio/agents/anthropic'

const message = await new Anthropic().beta.messages.toolRunner({
  model: 'claude-opus-5',
  max_tokens: 16000,
  tools: toAnthropicRunnable(tools),
  messages: [{ role: 'user', content: 'Summarise the welcome post.' }],
})

toAnthropicRunnable(tools) gives the tool runner each tool through the SDK's own betaTool(); the runner sends the result back to the model as JSON text. To run the loop yourself, toAnthropic(tools) is the plain tools array for client.messages.create — { name, description, input_schema } — and you call tools[name].execute(input) for each tool_use block.

Neither framework checks the model's arguments against a JSON Schema tool's schema, and this package carries no validator. The RelyIO API checks them.

Errors

When the API refuses — a missing entry, a key that may not read, a quota — execute resolves with { success: false, error: { code, messages, details } }, the same object the MCP server returns, so the model can decide what to do next. Through an adapter, that object is the tool's result.

A network failure is thrown. Called directly, your code sees it; through an adapter, the framework catches it and tells the model the tool failed — the AI SDK as a tool-error, the Anthropic tool runner as an is_error result reading Error: <message>. Neither retries it.

Requirements

@relyio/sdk as a peer dependency; a write holding Markdown at a rich-text place loads its @relyio/sdk/markdown entry, and nothing else does. ai (6.x or 7.x) for @relyio/agents/vercel-ai and @anthropic-ai/sdk (0.63 or later, before 1.0) for @relyio/agents/anthropic, both optional peers. No schema library: the schemas are JSON Schema.