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

@mpilot/openai

v0.1.0

Published

Raw-shape OpenAI adapter for the framework-agnostic [`@mpilot/tools`](../tools) registry. Wraps **no SDK**: `getOpenAITools` returns the Chat Completions wire-format tool array plus a `dispatch()` executor, so the same toolkit drives the `openai` client *

Readme

@mpilot/openai

Raw-shape OpenAI adapter for the framework-agnostic @mpilot/tools registry. Wraps no SDK: getOpenAITools returns the Chat Completions wire-format tool array plus a dispatch() executor, so the same toolkit drives the openai client and Anthropic Messages raw tool-use — one adapter, two runtimes.

import { getOpenAITools } from '@mpilot/openai';
import { aaveTools, dexTools } from '@mpilot/providers'; // example factories

const toolkit = getOpenAITools({ chainId: 5000 }, [aaveTools, dexTools]);

Quickstart — OpenAI Chat Completions

import OpenAI from 'openai';
import { bigintSafeStringify, getOpenAITools } from '@mpilot/openai';

const client = new OpenAI();
const toolkit = getOpenAITools(agent, factories);

const messages: OpenAI.ChatCompletionMessageParam[] = [
  { role: 'user', content: 'Propose my next portfolio move.' },
];
const completion = await client.chat.completions.create({
  model: 'gpt-5.2',
  messages,
  tools: toolkit.tools, // assignable to ChatCompletionFunctionTool[]
});

// Handle EVERY tool call — parallel tool calls are the model's default, and
// the follow-up create() 400s unless each tool_call_id gets a tool message.
const reply = completion.choices[0]?.message;
if (reply?.tool_calls?.length) {
  messages.push(reply);
  for (const call of reply.tool_calls) {
    if (call.type !== 'function') continue;
    const result = await toolkit.dispatch(call.function.name, call.function.arguments);
    messages.push({
      role: 'tool',
      tool_call_id: call.id,
      content: bigintSafeStringify(result),
    });
  }
}

Quickstart — Anthropic Messages (raw tool-use)

The Chat Completions parameters content is Anthropic's input_schema — only the envelope keys differ:

import Anthropic from '@anthropic-ai/sdk';
import { bigintSafeStringify, getOpenAITools } from '@mpilot/openai';

const client = new Anthropic();
const toolkit = getOpenAITools(agent, factories);

const tools: Anthropic.Messages.Tool[] = toolkit.tools.map((t) => ({
  name: t.function.name,
  description: t.function.description,
  input_schema: t.function.parameters, // carries the literal type: 'object'
}));

const message = await client.messages.create({
  model: 'claude-opus-4-7',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Propose my next portfolio move.' }],
  tools,
});

// A single assistant message can carry MULTIPLE tool_use blocks — answer
// every one, or the follow-up messages.create() rejects the conversation.
for (const block of message.content) {
  if (block.type !== 'tool_use') continue;
  const result = await toolkit.dispatch(block.name, block.input as object);
  // reply with { type: 'tool_result', tool_use_id: block.id, content: bigintSafeStringify(result) }
}

dispatch semantics

  • args accepts the raw JSON string from tool_calls[].function.arguments or an already-parsed object from Anthropic's tool_use.input.
  • Input is validated with the tool's own inputSchema before invoke runs — defaults applied, unknown keys stripped, invalid input rejects with a ZodError. Malformed JSON rejects with SyntaxError; unknown tool names reject with an error listing the known tools. Nothing fails silently.
  • dispatch returns the raw invoke() value. Serialize it for the tool-result message with the re-exported bigintSafeStringify — plain JSON.stringify throws on the wei-scale bigints Concierge tools emit.

Gotchas

  • Zero tools? Omitted factories AND an unsupported chainId both yield tools: [] silently — check both before debugging the model.
  • No abort propagation. Cancelling the model request does NOT cancel an in-flight tool call: ConciergeTool.invoke takes no abort signal, so a started execution (e.g. an on-chain transaction) runs to completion.
  • A failed dispatch mid-loop leaves messages inconsistent. The assistant message is pushed before the tool replies, so if one call's dispatch rejects, the calls already answered orphan their siblings and a retried create() 400s on the unanswered tool_call_ids. Either reply with an error-string tool message for the failed call, or drop the assistant message before retrying.
  • Not strict-mode ready with optionals. OpenAI strict: true requires additionalProperties: false (emitted — fine) AND every property required.optional() properties are omitted from required, so schemas with optionals fail strict validation. .default() properties are fine: they STAY in required (parse fills them). Leave strict unset (the default) unless your schemas avoid .optional().
  • .transform()/.pipe()/z.custom() input schemas throw at construction time.transform() and z.custom() cannot be represented in JSON Schema at all, and a plain .pipe() would silently advertise what parse() returns instead of what it accepts. Normalize inside invoke() instead.
  • .refine() is invisible to the model. Refinements are stripped from the emitted JSON Schema (they still validate at dispatch) — the model can't see the constraint and will violate it. Put the rule in .describe() text too.