prompt-kit-js
v1.0.0
Published
Lightweight, versioned prompt template manager for LLM apps — variable injection, template registry, and a rough token-count estimator. Framework/provider agnostic (OpenAI, Groq, Anthropic, anything).
Maintainers
Readme
prompt-kit-js
⚡ Why prompt-kit-js?
In most production AI applications, prompts start as messy string literals scattered across multiple backend files. When you want to iterate, A/B test a wording change, rollback a regression, or track which model a prompt was tuned for, things quickly get out of hand.
prompt-kit-js provides a centralized in-memory registry for your prompts:
- 🎯 Centralized Registry: Keep all your system prompts and few-shot templates organized in one place.
- 🗂️ Semantic Versioning: Store multiple versions (
1.0.0,1.1.0,2.0.0) of the same prompt and pin specific versions for specific models. - 🛡️ Variable Validation: Strict mode catches missing
{{placeholders}}at render time before wasting LLM API credits. - 📊 Token Estimation: Built-in zero-dependency heuristic to estimate token budgets before dispatching requests.
- 🤖 Provider Agnostic: Works seamlessly with OpenAI, Anthropic Claude, Google Gemini, Groq, Mistral, Ollama, or custom pipelines.
- 🪶 Zero Dependencies: Weighs less than ~2 KB minified with dual ESM & CJS support.
📦 Installation
# npm
npm install prompt-kit-js
# pnpm
pnpm add prompt-kit-js
# yarn
yarn add prompt-kit-js
# bun
bun add prompt-kit-js🚀 Quick Start
import { PromptRegistry } from "prompt-kit-js";
// 1. Create a prompt registry
const prompts = new PromptRegistry();
// 2. Register your templates
prompts.register({
id: "customer-support-summary",
version: "1.0.0",
description: "Summarizes user support ticket into bullet points",
template: `You are an AI assistant for {{companyName}}.
Summarize the following support conversation with priority level {{priority}}:
Ticket ID: {{ticketId}}
Conversation:
{{transcript}}
Output format: JSON { summary: string, actionItems: string[] }`,
variables: ["companyName", "priority", "ticketId", "transcript"],
tags: ["support", "summary", "gpt-4o"],
});
// 3. Render the prompt with inputs
const promptText = prompts.render("customer-support-summary", {
companyName: "Acme Corp",
priority: "HIGH",
ticketId: "TCK-8941",
transcript: "Customer: I cannot log in after password reset...",
});
console.log(promptText);🔄 Prompt Versioning & A/B Testing
You can register multiple iterations of a prompt under the same id. By default, render() always uses the most recently registered version, but you can explicitly pin an older version:
// Version 1.0.0
prompts.register({
id: "codegen-assistant",
version: "1.0.0",
template: "Write a {{language}} function that does: {{task}}",
});
// Version 2.0.0 (improved few-shot prompt tuned for newer models)
prompts.register({
id: "codegen-assistant",
version: "2.0.0",
template: "You are an expert {{language}} developer. Follow clean code and SOLID principles.\nTask: {{task}}\nProvide typed code with unit tests.",
});
// Uses latest version (2.0.0)
const latestPrompt = prompts.render("codegen-assistant", {
language: "TypeScript",
task: "parse ISO timestamp",
});
// Pin to older version (1.0.0) for legacy systems
const legacyPrompt = prompts.render("codegen-assistant", {
language: "TypeScript",
task: "parse ISO timestamp",
}, { version: "1.0.0" });📊 Token Estimation & Budget Hints
Estimate token counts before making expensive API calls:
const { prompt, estimatedTokens } = prompts.renderWithStats("codegen-assistant", {
language: "Python",
task: "implement a distributed priority queue with Redis",
});
console.log(`Estimated prompt size: ~${estimatedTokens} tokens`);
// Or use the standalone estimator directly:
import { estimateTokens } from "prompt-kit-js";
const tokens = estimateTokens("Analyze the following 50 pages of financial logs...");Note: This is a fast, zero-dependency heuristic (~4 characters per token + word-weight blending). It is ideal for rate-limit protection, context-window budgeting, and UI warnings.
🛡️ Strict vs Lenient Rendering
Strict Mode (Default)
Throws a MissingVariableError if any {{variable}} found in the template is omitted from the input:
try {
prompts.render("customer-support-summary", {
companyName: "Acme Corp",
// Missing ticketId, priority, transcript
});
} catch (err) {
if (err instanceof MissingVariableError) {
console.error(err.message);
// => prompt-kit: template "customer-support-summary" is missing required variable "priority"
}
}Lenient Mode
If you prefer missing variables to evaluate to empty strings "":
const result = prompts.render(
"customer-support-summary",
{ companyName: "Acme Corp" },
{ strict: false }
);🔍 Auto-Detecting Template Placeholders
Extract all placeholders dynamically from a registered template:
const vars = prompts.detectVariables("customer-support-summary");
console.log(vars);
// Output: ["companyName", "priority", "ticketId", "transcript"]🤖 Real-World LLM Example (OpenAI / Anthropic / Groq)
import OpenAI from "openai";
import { PromptRegistry } from "prompt-kit-js";
const openai = new OpenAI();
const prompts = new PromptRegistry();
prompts.register({
id: "sentiment-analyzer",
version: "1.0.0",
template: "Analyze the sentiment of the following customer feedback as positive, neutral, or negative.\nFeedback: {{feedback}}",
});
async function analyzeReview(reviewText: string) {
const prompt = prompts.render("sentiment-analyzer", { feedback: reviewText });
const completion = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: prompt }],
temperature: 0,
});
return completion.choices[0].message.content;
}📚 API Reference
PromptRegistry
| Method | Return Type | Description |
|---|---|---|
| register(template) | void | Adds a template version to the registry. |
| registerAll(templates[]) | void | Bulk registers multiple templates. |
| get(id, version?) | PromptTemplate | Retrieves raw template object (defaults to latest). |
| list() | string[] | Returns an array of all registered template IDs. |
| listVersions(id) | string[] | Returns all version strings registered for a template ID. |
| render(id, vars, options?) | string | Fills template placeholders. Supports { version, strict }. |
| renderWithStats(id, vars, options?) | { prompt, estimatedTokens } | Returns rendered prompt with token estimate. |
| detectVariables(id, version?) | string[] | Inspects template string and extracts all placeholder names. |
Standalone Helpers
| Function / Class | Description |
|---|---|
| estimateTokens(text: string) | Heuristic token estimator (~4 chars per token). |
| MissingVariableError | Thrown when a variable is absent during strict rendering. |
| TemplateNotFoundError | Thrown when an ID or specified version does not exist. |
