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

@citysage/ai-sdk

v0.1.0

Published

Unified AI SDK provider that routes provider/model-id strings to the right underlying provider

Downloads

29

Readme

@citysage/ai-sdk

A tiny, type-safe routing provider for the Vercel AI SDK that unifies OpenAI, Anthropic, Azure OpenAI, and Google Vertex AI behind a single provider/model-id interface.

Quick Start

bun add @citysage/ai-sdk ai @ai-sdk/openai @ai-sdk/anthropic
import { generateText } from "ai";
import { citysage } from "@citysage/ai-sdk";

const result = await generateText({
  model: citysage("openai/gpt-4.1"),
  prompt: "Hello!",
});

console.log(result.text);

Features

  • Single interface — Route to any provider with "provider/model-id" strings
  • Type-safe — Full TypeScript support with branded model ID type
  • Lazy loading — Only loads provider packages you actually use
  • Clear errors — Helpful env var validation with actionable messages
  • Optional peers — Install only the providers you need
  • Runtime-friendly — Works in Node.js and Bun with lazy peer loading

Supported Providers

| Prefix | Package | Auth | |--------|---------|------| | openai | @ai-sdk/openai | OPENAI_API_KEY | | anthropic | @ai-sdk/anthropic | ANTHROPIC_API_KEY | | azure | @ai-sdk/azure | AZURE_API_KEY + AZURE_RESOURCE_NAME | | vertex | @ai-sdk/google-vertex | GOOGLE_VERTEX_PROJECT + GOOGLE_VERTEX_LOCATION | | vertex-anthropic | @ai-sdk/google-vertex/anthropic | Same as vertex |

Usage Examples

Chat with OpenAI

import { streamText } from "ai";
import { citysage } from "@citysage/ai-sdk";

const { textStream } = await streamText({
  model: citysage("openai/gpt-4.1"),
  prompt: "Write a haiku about TypeScript",
});

for await (const chunk of textStream) {
  process.stdout.write(chunk);
}

Anthropic Claude

import { generateText } from "ai";
import { citysage } from "@citysage/ai-sdk";

const result = await generateText({
  model: citysage("anthropic/claude-opus-4.6"),
  messages: [
    { role: "user", content: "What is TypeScript?" },
  ],
});

Azure OpenAI

import { citysage } from "@citysage/ai-sdk";
import { generateText } from "ai";

// deployment name as the model ID
const result = await generateText({
  model: citysage("azure/my-gpt4-deployment"),
  prompt: "Explain quantum computing",
});

Google Vertex AI

import { citysage } from "@citysage/ai-sdk";
import { generateText } from "ai";

const result = await generateText({
  model: citysage("vertex/gemini-2.5-pro"),
  prompt: "List 5 AI breakthroughs in 2025",
});

Anthropic on Vertex

import { citysage } from "@citysage/ai-sdk";
import { streamText } from "ai";

const { textStream } = await streamText({
  model: citysage("vertex-anthropic/claude-sonnet-4.6"),
  prompt: "Design a TypeScript API",
});

With AI SDK Tools & Agents

import { citysage } from "@citysage/ai-sdk";
import { ToolLoopAgent } from "ai";

const agent = new ToolLoopAgent({
  model: citysage("openai/gpt-4.1"),
  tools: {
    getCurrentWeather: {
      description: "Get the current weather in a location",
      parameters: {
        type: "object",
        properties: {
          location: { type: "string" },
        },
      },
      execute: async ({ location }) => `Sunny in ${location}`,
    },
  },
});

const response = await agent.run("What's the weather in SF?");

Environment Variables

OpenAI

OPENAI_API_KEY=sk-...

Anthropic

ANTHROPIC_API_KEY=sk-ant-...

Azure OpenAI

AZURE_RESOURCE_NAME=your-resource-name
AZURE_API_KEY=...

Google Vertex (all modes)

GOOGLE_VERTEX_PROJECT=your-project-id
GOOGLE_VERTEX_LOCATION=us-central1

Choose one authentication method:

# Option 1: API key (simplest)
GOOGLE_VERTEX_API_KEY=...

# Option 2: Service account JSON
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json

# Option 3: Direct service account (edge/Node.js)
[email protected]
GOOGLE_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----...

# Option 4: Default application credentials (local dev)
gcloud auth application-default login

API

citysage

Default provider instance. Callable function or use .languageModel().

import { citysage } from "@citysage/ai-sdk";

// These are equivalent:
const m1 = citysage("openai/gpt-4.1");
const m2 = citysage.languageModel("openai/gpt-4.1");

createCitysage()

Factory function for creating independent provider instances (useful for tests, DI).

import { createCitysage } from "@citysage/ai-sdk";

const citysage = createCitysage();
const model = citysage("openai/gpt-4.1");

Type Definitions

import type { CitysageModelId, CitysageProvider, SupportedProvider } from "@citysage/ai-sdk";

// Branded type for model IDs — TypeScript enforces the format at compile time
type MyModelId = CitysageModelId; // "openai/gpt-4.1" ✓, "openai" ✗

// Provider type
type MyProvider = CitysageProvider;

// Union of supported prefixes
type Prefix = SupportedProvider; // "openai" | "anthropic" | "azure" | ...

Error Handling

Missing Environment Variables

try {
  citysage("openai/gpt-4.1");
} catch (e) {
  // [citysage] Missing environment variable for "openai" provider:
  //   OPENAI_API_KEY
  // Set it in your environment or .env file.
}

Invalid Model ID Format

citysage("openai"); // throws: Invalid model ID "openai". Expected format: "provider/model-id"

Unknown Provider

citysage("groq/llama-3" as any); 
// throws: Unknown provider "groq". Supported: openai | anthropic | azure | vertex | vertex-anthropic

Fine-Tuned Model IDs

Model IDs are passed through unchanged after the first /, so fine-tuned models work:

// OpenAI fine-tuned model
citysage("openai/ft:gpt-4.1:org:custom:id")

// Azure deployment (use your deployment name, not raw model name)
citysage("azure/my-finetuned-deployment")

Contributing

Issues and PRs welcome. Run tests:

bun test
bun run typecheck

License

MIT