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

@kontourai/thread

v0.5.0

Published

Canonical AI conversation schema — a portable message format for agent threads

Downloads

27,206

Readme

@kontourai/thread

Canonical Zod schema for AI conversations — messages, tool calls and results, reasoning, attachments, token usage — plus type guards, factories, and validated JSON serialization.

Schema 1.2.0 also supports owner-issued tool-result identity. Legacy imported results remain valid, but only results carrying both resultId and terminalStatus can be safely retained for later dereference. Use projectToolResult when passing one to another consumer: it produces a bounded inert view (32 parts, 64 KiB of UTF-8 text, and 72 KiB of projected string data) and intentionally omits payload bytes, URLs, annotations, and structured result data. Any dropped text or projected metadata is declared by the mandatory omission counters on the projection.

Assistant-answer references

ThreadAnswerRef is an exact, portable identity for one owner-issued assistant message: { authority: "@kontourai/thread", schemaVersion: "1.2.0", kind: "assistant-message", standing: "observed", threadId, messageId }. It is separate from the serialized Thread/Message schema, so this additive API does not change the Thread schema version or require Ferry adapters to invent source identities.

The producer creates createObservedMessageIdentity(threadId, messageId) only when it byte-observed the owner-issued tuple, then passes that fact to createThreadAnswerRef(identity). Thread never infers observation from an ID's shape, a correlation, an adapter position, or an ID that happens to match. Synthetic, adapter-fallback, and unknown identity facts cannot create or parse as a ThreadAnswerRef.

IDs are opaque Unicode strings: they may look like paths, URLs, or percent encodings. Thread never normalizes or dereferences them, so %2f and %2F remain different IDs.

Use the total projectAssistantAnswer(ref, unknownMessage) at a consumer boundary. It returns a typed unavailable reason for bad input, a non-assistant message, an identity mismatch, corrupt text, or an answer with no visible text; it does not throw a Zod error for those inputs.

The available form retains ordered, inert text parts only. It never exposes reasoning, tool calls or arguments, structured results, image/file payloads, annotations, attachment paths or bytes, or source/private metadata. Markdown, HTML, and URLs remain strings. The contract caps visible text at 32 parts, 16 KiB per part, 64 KiB total text, and 72 KiB across the ref plus content. truncated, omittedParts, and omittedTextBytes describe capacity loss among visible text candidates only; intentionally excluded reasoning/tools are not misreported as truncation. Source metadata has an explicit zero-byte budget.

import { createObservedMessageIdentity, createThreadAnswerRef, projectAssistantAnswer } from "@kontourai/thread/answer";

const observed = createObservedMessageIdentity("source-thread-42", "source-message-7");
const ref = createThreadAnswerRef(observed);
const outcome = projectAssistantAnswer(ref, importedMessage);
if (outcome.state === "available") {
  // Render outcome.answer.content as plain inert text, not executable markup.
  console.log(outcome.answer.content);
}
import { threadFromJson, getToolCalls, isAssistantMessage } from "@kontourai/thread";

const thread = threadFromJson(json); // validates, throws on schema violations
for (const msg of thread.messages) {
  if (isAssistantMessage(msg)) console.log(getToolCalls(msg));
}
import { createToolResult, projectToolResult } from "@kontourai/thread";

const result = createToolResult({
  resultId: "provider-result-42", // supplied by the result owner
  terminalStatus: "cancelled",
  toolCallId: "provider-call-9",
  name: "shell",
  content: [{ type: "text", text: "cancelled by user" }],
});

const projection = projectToolResult(result);
// { state: "available", result: { resultId, terminalStatus, content, ... } }

Use @kontourai/ferry to import transcripts from Claude Code, Codex, OpenCode, or ChatGPT exports into this format, and to export back out to provider API formats.

License: Apache-2.0