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

@codehz/conversation

v0.2.4

Published

`@codehz/conversation` is a Bun-first conversation sync library for AI applications. It provides:

Readme

@codehz/conversation

@codehz/conversation is a Bun-first conversation sync library for AI applications. It provides:

  • canonical message history with branching active-path state
  • run lifecycle and durable streaming events
  • snapshot + event-log recovery
  • audience-aware projection (public / protected / private)
  • structured input request / submission envelope
  • host event channel (shared seq axis with conversation events)
  • trace sidecar with independent TraceStore
  • plugin pipeline (command/event interception, projection, lifecycle hooks)
  • run driver host (driver registration, match, HostAPI facade)
  • Bun WebSocket sync with audience-aware projection
  • React client/hooks for vNext conversation state

The library owns protocol and synchronization. The host owns agent execution, routing, auth, storage partitioning, and tool implementations.

Install

bun install

Build and test

bun run build
bun run typecheck
bun test

Package surfaces

| Import path | Description | | ----------------------------------- | -------------------------------------------------------------------- | | @codehz/conversation | vNext — all exported types, engine, server, react, trace | | @codehz/conversation/vnext | Same as default (vNext entry point) | | @codehz/conversation/vnext/core | Core types, reducer, projection, commands | | @codehz/conversation/vnext/server | ConversationEngine, storage contracts, sync server, plugin, driver | | @codehz/conversation/vnext/react | ConversationClient, React hooks, ConversationProvider | | @codehz/conversation/vnext/trace | Trace types, store contract, projection helpers |

Core concepts

Messages

Canonical history is stored as Message nodes:

  • roles: system | user | assistant | tool
  • tree shape via parentId
  • optional runId
  • ordered structured parts
  • protocol-level Visibility: "public" | "protected" | "private"

MessagePart is a closed union:

  • text
  • reasoning
  • tool-call
  • tool-result
  • file
  • source
  • data
  • step-marker

Runs

Runs are first-class records with status, checkpoints, visibility, and output message ids. A single run may materialize multiple messages.

Visibility & Audience

Messages, parts, runs, host events, and traces carry Visibility:

  • public: visible to all audiences
  • protected: visible to controlled / host / system audiences
  • private: visible only to host / system audiences

The host provides a ProjectionPolicy to determine per-audience visibility and field-level projection. The Audience is declared at connection time.

Persistence

Storage is host-owned through three separate contracts:

  • EventStore: append-only event log with atomic batch writes
  • SnapshotStore: full-state snapshot storage
  • TraceStore: independent trace record storage
interface EventStore {
  append(envelopes: readonly EventEnvelope[]): Promise<void>;
  getEvents(fromSeq: number): Promise<readonly EventEnvelope[]>;
  getLastSeq(): Promise<number>;
}

Snapshots are part of the protocol contract. Recovery loads the latest snapshot, then replays tail events.

Structured Input

RunInputRequest supports message | form | approval | selection | custom kinds. Submissions use an InputSubmissionEnvelope that wraps typed payloads.

Host Events

HostEvent shares the same seq axis as ConversationEvent, ensuring deterministic replay order. Host events are projected through the same ProjectionPolicy as conversation events.

Trace

Trace records are stored in an independent TraceStore. Summaries are emitted into the main sync stream as trace.summaryAppended events for real-time client delivery.

Typical host flow

Client submission creates a user message and a pending run. A registered RunDriver (or manual subscribe) handles run.requested:

Recommended high-level entry points:

  • engine.startRun(...) for host-initiated runs
  • host.beginAssistantMessage(...) for streaming assistant output

Using a RunDriver (vNext)

const driverHost = new DriverHost();
driverHost.register(
  new CallbackDriver("echo-agent", async (ctx) => {
    const { run, host } = ctx;
    await host.transitionRun(run.id, "running");
    const writer = await host.beginAssistantMessage({
      runId: run.id,
      parentId: ctx.trigger.id,
    });
    await writer.text("Hello!");
    await writer.done();
    await host.transitionRun(run.id, "completed");
  }),
);

const engine = new ConversationEngine({
  eventStore,
  snapshotStore,
  traceStore,
  compactionPolicy,
  metrics,
  driverHost,
});

Using subscribe (manual)

engine.subscribe((envelope) => {
  if (envelope.kind === "conversation" && envelope.event.type === "run.requested") {
    void startAgent(envelope.event.payload.runId);
  }
});

React client

ConversationClient handles:

  • WebSocket connection and reconnect
  • lastSeq persistence
  • sync.snapshot + incremental replay
  • gap/reset handling
  • generic sendCommand for all command types

In React, mount the client under ConversationProvider. The provider owns connect() / disconnect() by default, so components do not need a manual useEffect just to open the socket.

Hooks expose projected state:

  • useConversation<T>(selector), useMessage(id), useActiveMessageIds()
  • useRun(runId), useActiveRun(), useRunsByStatus(status)
  • useMessageBlocks(messageId), usePendingInput(runId), useRunToolEvents(runId)
  • useVariantGroup(messageId)
  • useHostEvents(), useHostEventsByNamespace(namespace)
  • useTraceSummaries(), useTraceSummariesByRun(runId)
  • useConnectionStatus(), useSendCommand(), useReconnect()

Minimal host example

The example under examples/minimal-host demonstrates vNext:

  • structured message input
  • host events (agent lifecycle)
  • trace sidecar (agent traces)
  • driver registration (CallbackDriver)
  • audience-aware sync

Run it with:

cd examples/minimal-host
bun install
bun start

Then open http://localhost:3000.

References