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

@chatman-media/sales

v0.2.1

Published

LLM-powered sales funnel engine — persona composition, A/B testing, ELO rating, self-play evaluation for conversational bots.

Readme

@chatman-media/sales

npm CI TypeScript Bun License: MIT powered by @chatman-media/rag

LLM-powered sales funnel engine for conversational bots. Persona composition, funnel stage routing, A/B testing with ELO ratings, self-play evaluation, and a coach LLM that iterates on failing styles.

Built from the production sales layer of sales-guru — a Telegram recruitment bot that runs 24/7 qualifying inbound candidates for foreign work contracts.


What's inside

| Module | What it does | |--------|-------------| | Types | Style, FunnelStage, Hook, StageConfig — full Zod schema for a sales persona | | Prompt | composeSystemPrompt — builds multi-section system prompts: persona, tone, framework (AIDA/PAS/SPIN/NEPQ/Belfort), hooks, skills, stage guidance, KB context | | Stage router | nextStage — sub-ms Unicode-aware regex router for Cyrillic + English | | Stage classifier | classifyStage — LLM classifier with regex fallback, {stage, confidence, source} | | ELO | eloUpdate / eloUpdatePair — standard ELO math, K=32, symmetric pairwise | | A/B router | pickVariant — SHA-256 deterministic assignment, same user always gets same variant | | Skills | 25 persuasion techniques (Cialdini × 7, Voss × 5, NLP × 3, classical sales × 5, custom × 5) | | Built-in styles | 4 production-tested personas: marina-prime, cold-direct-pas, empathetic-nepq, flirty-belfort | | Self-play | runSelfPlayMatch — full RAG pipeline vs LLM-driven candidate; per-turn skill grading; reflect guard | | Pairwise | runPairwiseMatch — A vs B against same persona; comparative judge; symmetric ELO update | | Coach | proposeStyleEdits — reads losing transcripts, proposes concrete JSON edits to tone/hooks/guidance/few-shot | | Shadow eval | runShadowEval — Wilson 95% LB on B's win rate → keep / rollback / inconclusive | | Skill recommender | rankSkillRecommendations — Wilson LB ranking; draws count as 0.5 wins |


Install

bun add @chatman-media/sales     # Bun
npm install @chatman-media/sales # npm / pnpm / yarn

Peer dependency: @chatman-media/rag for ChatClient, EmbeddingClient, IKbStore, and answerWithRag.


Quick start — compose a prompt

import { composeSystemPrompt, getStyleOrThrow } from "@chatman-media/sales";

const style = getStyleOrThrow("marina-prime-v1");

const prompt = composeSystemPrompt(style, "qualify", kbContext, {
  userFacts: { city: "Москва", age: "24" },
  skills: attachedSkills,
});

Stage routing

import { nextStage, classifyStage } from "@chatman-media/sales";

// Fast regex (zero cost):
const stage = nextStage({ turnNumber: 3, currentStage: "qualify", lastUserMessage: msg });

// LLM with regex fallback:
const result = await classifyStage({ chat, userMessage: msg, currentStage: stage, turnNumber: 3 });
console.log(result.stage, result.confidence, result.source); // "pitch" 0.87 "llm"

A/B testing with ELO

import { pickVariant, eloUpdate } from "@chatman-media/sales";

// Deterministic assignment — same user always gets same style:
const styleSlug = pickVariant(
  { slug: "summer-2025", variants: [
    { styleSlug: "marina-prime-v1", weight: 50 },
    { styleSlug: "empathetic-nepq-v1", weight: 50 },
  ]},
  userId,
);

// Update ELO after a match:
const newRating = eloUpdate(currentRating, "won"); // K=32, baseline=1500

Self-play evaluation

import { runSelfPlayMatch, CANDIDATE_PERSONAS } from "@chatman-media/sales";

const result = await runSelfPlayMatch(deps, {
  style: myStyle,
  styleId: 42,
  persona: CANDIDATE_PERSONAS.find(p => p.slug === "skeptic-anya")!,
  maxTurns: 20,
});

console.log(result.outcome);          // "won" | "lost" | "draw"
console.log(result.transcript);       // full back-and-forth
console.log(result.skillsAttributed); // which skills the bot actually used
console.log(result.fabricationsCaught); // reflect guard catches

Coach LLM

import { proposeStyleEdits, applyEditsToStyle } from "@chatman-media/sales";

const proposal = await proposeStyleEdits({ style, matchesRepo, chat });
console.log(proposal.summary);   // "Bot too formal with price-sensitive personas"
console.log(proposal.edits);     // { voice_tone: "...", hooks_add: [...] }
console.log(proposal.rationale); // per-edit explanation

// Pure merge — returns new Style, nothing persisted:
const improved = applyEditsToStyle(style, proposal.edits);

Storage interfaces

All DB-heavy modules accept injected interfaces — no ORM dependency:

import type { ISelfPlayMatchesRepo, ISkillsRepo, IStyleRatingsRepo } from "@chatman-media/sales";

// Implement for your DB (Postgres, SQLite, in-memory):
class MyMatchesRepo implements ISelfPlayMatchesRepo {
  async insert(match) { /* ... */ }
  async byId(id) { /* ... */ }
  async list(opts) { /* ... */ }
}

Built-in styles

| Slug | Persona | Framework | Voice | |------|---------|-----------|-------| | marina-prime-v1 | Марина, PrimeConnect | NEPQ | Human recruiter, Telegram-native, warm | | cold-direct-pas-v1 | Менеджер | PAS | Direct, no fluff, fast pitch | | empathetic-nepq-v1 | Наталья | NEPQ | Warm, anxiety-aware, unhurried | | flirty-belfort-v1 | Виктория | Straight Line | Assertive, playful, confident |

Persuasion skills

25 atomic techniques from Cialdini, Voss, NLP, and classical sales — each with a promptFragment injected into the system prompt and an applicableStages filter:

import { SKILL_CATALOGUE, SKILL_BY_SLUG } from "@chatman-media/sales";

const mirroring = SKILL_BY_SLUG.get("mirroring");
// { slug: "mirroring", family: "voss", promptFragment: "...", applicableStages: ["qualify", "objection"] }

Architecture

@chatman-media/sales
├── types.ts          Style / FunnelStage / Hook schemas (zod)
├── prompt.ts         System prompt composition
├── stage-router.ts   Regex funnel stage router
├── stage-classifier.ts  LLM stage classifier
├── elo.ts            ELO rating engine
├── ab-router.ts      Deterministic A/B picker
├── skills/
│   └── catalogue.ts  25 persuasion techniques
├── styles/
│   └── *.ts          4 built-in personas
├── self-play/
│   ├── personas.ts   8 candidate archetypes
│   ├── judge.ts      LLM match judge
│   ├── orchestrator.ts  Full match loop
│   └── pairwise.ts   Head-to-head comparison
├── coach.ts          Style iteration from losses
├── shadow-eval.ts    Wilson-LB A/B shadow runner
├── skill-recommendations.ts  Wilson LB skill ranker
└── store.ts          Storage interfaces (IKbStore, ISelfPlayMatchesRepo, …)

Depends on @chatman-media/rag for ChatClient, EmbeddingClient, IKbStore, answerWithRag, and gradeSkills.


License

MIT — Alexander Kireev / chatman-media