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

ai-structured-tooling

v1.0.3

Published

A flexible library for using AI providers with structured outputs. Supports OpenAI, Anthropic, Google, and custom providers.

Readme

AI Structured Tooling

A flexible, type-safe library for using AI providers with structured outputs. Supports OpenAI, Anthropic, Google Gemini, and custom providers.

Features

  • 🔌 Multiple Built-in Providers: OpenAI, Anthropic (Claude), Google Gemini
  • 🛠️ Custom Provider Support: Register your own AI providers
  • 📦 Structured Outputs: Type-safe responses using Zod schemas
  • ⚙️ Config-Driven Agents: Create agents from serializable JSON config files
  • 🔑 Simple API Key Management: Register and manage API keys for multiple providers
  • 📘 Full TypeScript Support: Complete type definitions included
  • 🎯 Minimal Dependencies: Only requires Zod, provider SDKs are optional

Installation

npm install ai-structured-tooling zod

Provider SDKs (Optional)

Install only the providers you need:

# For OpenAI
npm install openai

# For Anthropic (Claude)
npm install @anthropic-ai/sdk

# For Google (Gemini)
npm install @google/genai

Quick Start

1. Register API Keys

import { registerAPIKeys } from "ai-structured-tooling";

registerAPIKeys({
  openai: process.env.OPENAI_API_KEY,
  anthropic: process.env.ANTHROPIC_API_KEY,
  google: process.env.GEMINI_API_KEY,
});

2. Use Built-in Providers

import { useAI } from "ai-structured-tooling";
import { z } from "zod";

// Simple text response
const response = await useAI({
  system: "You are a helpful assistant.",
  content: "What is the capital of France?",
  provider: "anthropic",
});

const answer = await response.chat();
console.log(answer);

// Structured output with Zod schema
const WeatherSchema = z.object({
  location: z.string(),
  temperature: z.number(),
  condition: z.string(),
});

const weatherResponse = await useAI(
  {
    system: "You are a weather assistant.",
    content: "What is the weather in New York?",
    provider: "openai",
  },
  WeatherSchema,
);

const weather = weatherResponse.parsed();
console.log(`Temperature: ${weather.temperature}°F`);

3. Config-Driven Agents

Create an agent from a JSON-serializable config that can target either provider mode or framework mode.

import {
  createAgentFromConfig,
  registerAgentSchema,
  registerAgentTool,
} from "ai-structured-tooling";
import { z } from "zod";

const TicketSchema = z.object({
  title: z.string(),
  priority: z.enum(["low", "medium", "high"]),
});

registerAgentSchema("ticket", TicketSchema);

registerAgentTool("searchDocs", {
  name: "searchDocs",
  description: "Search docs",
  parameters: z.object({ query: z.string() }),
  execute: async ({ query }) => [{ title: "result", query }],
});

const agent = createAgentFromConfig({
  version: 1,
  runtime: { kind: "provider" },
  io: { mode: "structured", schemaRef: "ticket" },
  defaults: { provider: "openai", model: "gpt-4o-mini" },
  apiKeys: { openai: "${OPENAI_API_KEY}" },
});

const output = await agent.runStructured("Summarize this issue");

Config shape

  • runtime.kind: "provider" or "framework"
  • runtime.framework: required when kind is "framework"
  • io.mode: "simple" or "structured"
  • io.schemaRef: required in structured mode
  • io.toolRefs: optional tool names to resolve from registry
  • defaults.provider: required in provider mode
  • apiKeys: optional provider-to-key map, supports ${ENV_VAR} token syntax

Important behavior notes

  • apiKeys in config are applied per request for configured agents (no global key registration side effects).
  • If no per-request key is supplied for a provider, built-in providers fall back to globally registered keys (registerAPIKey / registerAPIKeys).
  • Schema and tool refs must be registered before running an agent via registerAgentSchema and registerAgentTool.

See examples/config-agent-demo.js for complete provider/framework/tooling examples.

Custom Provider Registration

Create and register your own AI providers:

import {
  registerProvider,
  registerAPIKey,
  getRequiredAPIKey,
  type ProviderFactory,
} from "ai-structured-tooling";

// Define your custom provider
const myCustomProvider: ProviderFactory = async (request, zodSchema) => {
  const apiKey = getRequiredAPIKey("mycustom");

  // Your custom API implementation
  const response = await fetch("https://api.myai.com/generate", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      prompt: request.content,
      system: request.system,
    }),
  });

  const data = await response.json();

  // Parse and validate with the provided schema
  const parsed = zodSchema.parse(data);

  return {
    input: request,
    output: parsed,
  };
};

// Register your provider
registerProvider("mycustom", myCustomProvider);
registerAPIKey("mycustom", "your-api-key");

// Use it like any built-in provider
const result = await useAI({
  system: "You are helpful.",
  content: "Hello!",
  provider: "mycustom",
});

API Reference

Provider Management

registerAPIKey(provider: string, apiKey: string): void

Register an API key for a provider.

registerAPIKeys(keys: Record<string, string>): void

Register multiple API keys at once.

getAPIKey(provider: string): string | undefined

Get a registered API key.

hasAPIKey(provider: string): boolean

Check if an API key is registered.

clearAPIKey(provider: string): void

Remove an API key.

getRegisteredProviders(): string[]

Get list of providers with registered API keys.

getAvailableProviders(): string[]

Get list of all available providers (built-in + custom).

Custom Providers

registerProvider(name: string, factory: ProviderFactory): void

Register a custom AI provider.

Parameters:

  • name: Unique provider name (cannot conflict with built-in providers)
  • factory: Function implementing the provider logic

Example:

registerProvider("myai", async (request, zodSchema) => {
  // Your implementation
  return {
    input: request,
    output: parsedResponse,
  };
});

unregisterProvider(name: string): boolean

Unregister a custom provider.

isProviderAvailable(name: string): boolean

Check if a provider is available (built-in or custom).

AI Requests

useAI<T>(request: UseAIRequest, zodSchema?: ZodType): Promise<AIResponse<T>>

Make an AI request with optional structured output.

Parameters:

  • request.system: System prompt (default: "You are a helpful assistant.")
  • request.content: User message/prompt
  • request.provider: Provider name (default: "anthropic")
  • request.model: Optional model override
  • zodSchema: Optional Zod schema for structured output

Returns:

  • chat(): Get response as string
  • parsed(): Get typed, validated response

Built-in Provider Functions

You can also use provider-specific functions directly:

import { useOpenAi, useAnthropic, useGoogle } from "ai-structured-tooling";

const response = await useOpenAi(request, schema);

Types

import type {
  UseAIRequest,
  ProviderResponse,
  ProviderFactory,
  LLMProvider,
  LLMMessage,
  LLMConfig,
} from "ai-structured-tooling";

Examples

Multi-Provider Example

const providers = ["openai", "anthropic", "google"];

for (const provider of providers) {
  if (hasAPIKey(provider)) {
    const response = await useAI({
      system: "You are a comedian.",
      content: "Tell me a joke.",
      provider,
    });
    console.log(`${provider}:`, await response.chat());
  }
}

Complex Structured Output

const AnalysisSchema = z.object({
  sentiment: z.enum(["positive", "negative", "neutral"]),
  confidence: z.number().min(0).max(1),
  keywords: z.array(z.string()),
  summary: z.string(),
});

const response = await useAI(
  {
    system: "You are a text analysis expert.",
    content: 'Analyze this review: "Great product, highly recommend!"',
    provider: "anthropic",
  },
  AnalysisSchema,
);

const analysis = response.parsed();
console.log(`Sentiment: ${analysis.sentiment} (${analysis.confidence})`);

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.