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

@ulam/halohalo

v0.3.3

Published

AI service adapters, model configuration, and provider abstraction.

Readme

@ulam/halohalo

AI service adapters, model configuration, and provider abstraction. Vanilla core with React, Vue, and Angular adapters.

Named for halo-halo, the Filipino shaved ice dessert: a mix of many things that somehow works together.

Purpose & Scope

What halohalo does:

  • Provider abstraction for Anthropic, OpenAI, and Google
  • API key management (localStorage-backed, never sent to server)
  • Model selection and configuration per provider
  • Completion calls with consistent interface across providers
  • Tool calling and agentic mode for complex operations
  • Framework-agnostic vanilla core with framework adapters
  • Zero build-time provider detection or configuration

What halohalo doesn't do:

  • Message history or conversation management (bring your own state)
  • Streaming response handling (returns complete results)
  • Rate limiting or retry logic (use middleware patterns for these)
  • Token counting or pricing calculation (external concerns)
  • API key validation or rotation (user responsibility)
  • Multi-user authentication or access control

Who should use halohalo:

  • Apps that need multiple AI provider support with runtime switching
  • Projects storing API keys client-side (browser-only, no backend)
  • Vanilla JavaScript, React, Vue, or Angular apps using AI features
  • Applications wanting provider-agnostic completion calls
  • Teams integrating AI features without external API servers

The ulam Framework

Halohalo is one of six independent packages in the ulam framework. See docs/ARCHITECTURE.md for the complete framework structure and dependency graph.

Install

npm install @ulam/halohalo

Peer dependencies: fuse.js >= 7 (for search). Framework adapters add react >= 18, vue >= 3, or @angular/core >= 17 as needed.

Supported providers

  • Anthropic (Claude)
  • OpenAI (GPT)
  • Google (Gemini)

Bring your own API key. Keys stay in the browser via localStorage and are sent directly to the provider, never to a server.

Usage

Initialize

import { initApiKeys, initModels, getAiProvider } from '@ulam/halohalo'

initApiKeys({ anthropic: 'sk-ant-...', openai: 'sk-...' })
initModels({ anthropic: 'claude-sonnet-4-6', openai: 'gpt-4o' })

const provider = getAiProvider() // 'anthropic' | 'openai' | 'google'

Call a provider

import { createCompletion } from '@ulam/halohalo'

const result = await createCompletion({
  prompt: 'Rewrite this finding for a mobile context.',
  systemPrompt: 'You are an accessibility audit assistant.',
})

Anthropic with tool use

import { callAnthropicWithTools } from '@ulam/halohalo'

const result = await callAnthropicWithTools({
  messages,
  tools,
  system: 'You are an accessibility audit assistant.',
})

Agentic mode

Agentic mode uses tool calling to search the corpus for similar past revisions before rewriting, matching the tone and depth of established work.

import { getAgenticRefinement } from '@ulam/halohalo'

const revised = await getAgenticRefinement({
  finding,
  notes: 'This is specific to mobile, element is a tooltip',
})

React hooks adapter

import { useProviderConfig, useCompletion } from '@ulam/halohalo/react'

function AISettings() {
  const { provider, model, setProvider } = useProviderConfig()
  const { complete, loading } = useCompletion()

  return (
    <button onClick={() => complete('Rewrite this for mobile.')}>
      {loading ? 'Revising...' : 'Rewrite'}
    </button>
  )
}

Vue composables adapter

@ulam/halohalo/vue provides composables that wrap the vanilla createCompletion and createProviderConfig with Vue reactivity. Loading and animating state are readonly refs that update as the completion runs.

import { useCompletion, useProviderConfig } from '@ulam/halohalo/vue'
import { onUnmounted } from 'vue'

// In setup()
const { loading, animating, complete, cancel, cleanup } = useCompletion()
onUnmounted(cleanup)

// loading.value and animating.value are reactive
await complete({ prompt: 'Rewrite this for mobile.' })

useProviderConfig() returns reactive refs for provider, models, and mode, plus all setter functions from the vanilla config store.

const { provider, setProvider } = useProviderConfig()
// provider.value is reactive
setProvider('openai')

Both composables return a cleanup function. Call it in onUnmounted() if the composable is used inside a component. For app-level use outside a component, cleanup is optional.

Angular services adapter

@ulam/halohalo/angular provides two injectable services backed by Angular signals.

CompletionService is not providedIn: 'root'. Each injection creates a separate completion instance with its own loading state. Provide it at the component level for scoped instances, or at the application level for a shared one.

import { CompletionService, ProviderConfigService, provideHalohalo } from '@ulam/halohalo/angular'

// Application root (shared singleton):
bootstrapApplication(AppComponent, {
  providers: [provideHalohalo()]
})

// Or component-level (scoped per component):
@Component({
  providers: [CompletionService],
  template: `
    <button (click)="rewrite()" [disabled]="completion.loading()">
      {{ completion.loading() ? 'Revising...' : 'Rewrite' }}
    </button>
  `
})
export class RewriteButtonComponent {
  completion = inject(CompletionService)

  async rewrite() {
    await this.completion.complete({ prompt: 'Rewrite for mobile.' })
  }
}

completion.loading() and completion.animating() are Angular computed signals that work directly in templates and in effect() calls.

ProviderConfigService is providedIn: 'root', giving you one config store for the whole app.

@Component({ ... })
export class SettingsComponent {
  providerConfig = inject(ProviderConfigService)

  // In template:
  // {{ providerConfig.provider() }}
  // (click)="providerConfig.setProvider('openai')"
}

Design

Bring your own key. No proxy, no server, no account. API keys are stored in localStorage and sent directly to the provider.

Provider-agnostic core. createCompletion works the same regardless of which provider is active. Switch providers without changing call sites.

Vanilla-first. The core has no framework dependency. Import from /react, /vue, or /angular only when you need framework reactivity.

Subpath exports

| Import | Contents | | ------ | -------- | | @ulam/halohalo | Vanilla core: createCompletion, createProviderConfig, callProvider, callAnthropicWithTools, getAgenticRefinement, searchItems, makeSearchTool, and more | | @ulam/halohalo/react | useCompletion, useProviderConfig | | @ulam/halohalo/vue | useCompletion, useProviderConfig | | @ulam/halohalo/angular | CompletionService, ProviderConfigService, provideHalohalo |

See the root README for a complete framework support overview across all ulam packages.