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

@smooai/smooth-operator

v1.23.0

Published

TypeScript SDK for the smooth-operator WebSocket protocol: the native client (`.`), React bindings (`./react`), and the embeddable web-component chat widget (`./widget`). Generated from the language-neutral JSON Schemas in spec/.

Downloads

11,561

Readme


What is this?

The native TypeScript client for the smooth-operator WebSocket protocol — and the one the smooai monorepo dogfoods. It connects to a running smooth-operator service (create a session, send a message, stream the agent's events back) — not the agent engine itself. Types are generated from the language-neutral JSON Schemas in spec/ (and committed, so consumers don't need the generator), with an ergonomic layer — discriminated unions + type guards — on top. It's Lambda-native and transport-injectable, so it runs in a browser, on Node, or inside a Lambda handler unchanged.


30-second quickstart

pnpm add @smooai/smooth-operator

Requires Node ≥ 22, ESM only.

One package, three subpath exports

@smooai/smooth-operator is the whole TypeScript SDK — install once, import the layer you need. react / react-dom are optional peer deps (only the ./react subpath needs them), so a client-only or widget-only consumer never pulls React into their bundle.

| Import | What | | --- | --- | | @smooai/smooth-operator | the protocol client (SmoothAgentClient, streaming turns, HITL) | | @smooai/smooth-operator/react | React bindings — useConversation hook + <SmoothChat> (see the guide) | | @smooai/smooth-operator/react/styles.css | default stylesheet for the React components | | @smooai/smooth-operator/widget | the embeddable web-component chat widget (mountChatWidget, <smooth-agent-chat>) | | @smooai/smooth-operator/widget/standalone | the prebuilt IIFE bundle for a no-build <script> embed | | @smooai/smooth-operator/validate | the Node-only ProtocolValidator (pulls ajv + node:fs; keep it off the browser path) |

import { SmoothAgentClient } from '@smooai/smooth-operator';

const client = new SmoothAgentClient({ url: 'ws://127.0.0.1:8787/ws' });
await client.connect();

const session = await client.createConversationSession({ agentId, userName: 'Alice' });
const turn = client.sendMessage({ sessionId: session.sessionId, message: 'How long is your return window?' });

const final = await turn; // EventualResponse — cost, tokens, messageId
console.log(final.data.payload.messageId);

(Point url at your own smooth-operator-server, or at the hosted endpoint.)


Watch it stream

sendMessage returns a MessageTurn that is both an async-iterable of events and awaitable for the authoritative terminal state. Iterate tokens as they arrive; await the same handle for the final response.

const turn = client.sendMessage({ sessionId: session.sessionId, message: 'Where is my order?' });

for await (const ev of turn) {
  if (ev.type === 'stream_chunk') console.error(`  ↳ node: ${ev.node}`);     // workflow node boundary
  if (ev.type === 'stream_token') process.stdout.write(ev.token ?? '');       // tokens, live
  if (ev.type === 'write_confirmation_required') {
    // HITL: a tool wants to write. Approve, and the resumed stream flows back into THIS turn.
    client.confirmToolAction({ sessionId: session.sessionId, requestId: turn.requestId, approved: true });
  }
}

const final = await turn; // EventualResponse — the authoritative terminal state
%%{init: {'theme':'base','themeVariables':{'background':'#020618','primaryColor':'#0b1426','primaryTextColor':'#e6edf6','primaryBorderColor':'#2b3a52','lineColor':'#7c8aa0','actorBkg':'#0b1426','actorBorder':'#2b3a52','actorTextColor':'#e6edf6','signalColor':'#7c8aa0','signalTextColor':'#e6edf6','noteBkgColor':'#f49f0a','noteTextColor':'#1a0f00','noteBorderColor':'#ff6b6c','fontFamily':'ui-sans-serif, system-ui, sans-serif'}}}%%
sequenceDiagram
  participant App
  participant C as SmoothAgentClient
  participant S as Service
  App->>C: sendMessage(...)
  C->>S: { action: send_message }
  S-->>C: immediate_response (202)
  S-->>C: stream_token "Our" "return" "window" …
  S-->>C: stream_chunk { node: response_gen }
  S-->>C: eventual_response (200)
  C-->>App: for-await yields events · await resolves final

Transport injection

The client never touches a real socket directly — it talks to an injectable Transport. The default uses the global WebSocket. On Node, inject the ws package; in tests, inject a mock — which is how the conformance suite exercises real client code (correlation, parsing, HITL routing) without a network.

import WebSocket from 'ws';
new SmoothAgentClient({ url, webSocketFactory: (u) => new WebSocket(u) });

Runtime validation (optional, Node-only)

import { ProtocolValidator } from '@smooai/smooth-operator';
const v = await ProtocolValidator.load();
v.validateEvent(incomingEvent); // { valid, errors } — ajv-compiled from the spec schemas

Polyglot — one spec, five clients

This is one of five native clients generated from the same protocol. Need C# / Microsoft.Extensions.AI? The IChatClient facade lives in the .NET client (it's a .NET-ecosystem feature). This TypeScript package is the native streaming client.

%%{init: {'theme':'base','themeVariables':{'background':'#020618','primaryColor':'#0b1426','primaryTextColor':'#e6edf6','primaryBorderColor':'#2b3a52','lineColor':'#7c8aa0','secondaryColor':'#0b1426','tertiaryColor':'#0b1426','fontFamily':'ui-sans-serif, system-ui, sans-serif','clusterBkg':'#0b1426','clusterBorder':'#22304a'}}}%%
flowchart LR
  SPEC["spec/ (JSON Schema)"] --> TS["TypeScript<br/>@smooai/smooth-operator"]
  SPEC --> GO["Go"]
  SPEC --> NET[".NET (+ MEAI IChatClient facade)"]
  SPEC --> PY["Python"]
  SPEC --> RS["Rust"]

Test-driven by default

Nothing here is vibe-coded — it's verified against a real LLM gateway.

%%{init: {'theme':'base','themeVariables':{'background':'#020618','primaryColor':'#0b1426','primaryTextColor':'#e6edf6','primaryBorderColor':'#2b3a52','lineColor':'#7c8aa0','secondaryColor':'#0b1426','tertiaryColor':'#0b1426','fontFamily':'ui-sans-serif, system-ui, sans-serif','clusterBkg':'#0b1426','clusterBorder':'#22304a'}}}%%
flowchart TD
  J["🎯 LLM-as-judge quality evals (Rust harness)"]
  E["🌐 Live cross-language E2E — this client boots the real server + drives a real claude-haiku-4-5 turn"]
  C["🧪 Conformance fixtures (shared across all 5 clients)"]
  U["⚡ Unit + type-level tests (discrimination, guards, correlation)"]
  J --> E --> C --> U

16 tests cover the conformance fixtures, the client (with a mock transport so real parsing/correlation/HITL run), and type-level checks. In the live cross-language E2E, this client boots a real smooth-operator-server subprocess (KB seeded), drives a real claude-haiku-4-5 turn over WebSocket, and asserts ≥1 streamed event, a knowledge-grounded "17", and per-session memory.

The proof story: an LLM-as-judge scored a multi-turn answer 1/5 (the runtime forgot turn 1's context); the failing eval drove a per-session-memory fix; it now scores 5/5 — a regression a substring test would have missed. See docs/EVALS.md.

Live tests are gated, never silently skipped: they run with SMOOTH_AGENT_E2E=1 + SMOOAI_GATEWAY_KEY and skip cleanly otherwise.

pnpm test          # conformance + client + type-level — no creds
pnpm test:e2e      # live cross-language E2E (needs gateway key)

Scripts

| Script | Purpose | | --- | --- | | pnpm generate | Regenerate src/generated/types.ts from ../spec. | | pnpm build | tscdist/. | | pnpm typecheck | Type-check src/ + test/ without emitting. | | pnpm test | Vitest (conformance + client + type-level). |

The generated types are committed; CI runs pnpm generate + git diff --exit-code to catch schemas that changed without a regenerate.

Smoo-powered or bring-your-own

Point the client at the hosted lom.smoo.ai endpoint, or at your own self-hosted smooth-operator-server (AWS Lambda or k8s) — same protocol, same client, same code.

🧩 Part of Smoo AI

@smooai/smooth-operator is built and open-sourced by Smoo AI — the AI-powered business platform with AI built into every product. It's the TypeScript member of the polyglot SDK set (TypeScript · Python · Go · .NET · Rust) for the smooth-operator service.

  • 🌐 The servicesmooth-operator (protocol, server, the five clients, AWS/k8s deploy)
  • 🧰 More open source from Smoo AIsmoo.ai/open-source
  • ☁️ Hostedlom.smoo.ai runs smooth-operator for you, managed and multi-tenant

🔗 Links

📄 License

MIT © 2026 Smoo AI. See LICENSE.