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

@ai-presence/adapters

v0.1.6

Published

Runtime signal adapters for AI Presence Kit.

Readme

@ai-presence/adapters

Starter adapter utilities for converting AI runtime events into AI Presence Kit events.

Adapters should stay upstream of any renderer. Their job is to translate signals like user input, stream open, first token, speech start, interruption, and errors into the canonical state machine exposed by @ai-presence/core.

Current adapters:

  • createRuntimeSignalAdapter: generic signal-to-presence bridge.
  • createAssistantLifecycleAdapter: maps framework-style thread/run/message lifecycle objects to presence.
  • createVercelAISDKAdapter: maps AI SDK chat statuses and callbacks to presence.
  • createOpenAIResponsesAdapter: maps OpenAI Responses streaming event objects to presence.
  • createOpenAIRealtimeAdapter: maps OpenAI Realtime server events to presence.
  • createChatEventAdapter: maps small generic chat lifecycle events to presence.

The adapters intentionally avoid importing framework packages. They accept plain objects so they can be wrapped by React, Svelte, Vue, server streams, WebRTC handlers, or custom chat runtimes later.

import { createVercelAISDKAdapter } from "@ai-presence/adapters";

const aiSdkPresence = createVercelAISDKAdapter(presenceRuntime);
aiSdkPresence.update({ status: "streaming", messages: [] });

Run the local adapter trace demo with:

npm run demo:adapters

The trace demo prints each adapter transition with the shared core control inputs, reference face frame evidence, and bounded six-channel decision-trace evidence that a renderer can consume, for example phase=before-output, attention=response, face=thinking, channels=gaze,blink,brows,mouth,posture,motion, trace=complete, decisions=6, safe=true, warnings=0, transition=thinking:stream-open+0ms, transitionReads=6/6, and reads=state,transitionEvent,transitionAgeMs.

Vercel AI SDK

Primary AI SDK docs checked for this adapter route:

https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat
https://ai-sdk.dev/docs/ai-sdk-ui/chatbot

The current AI SDK useChat status values are:

submitted
streaming
ready
error

Adapter mapping:

submitted -> model-waiting -> thinking
streaming with no assistant content -> stream-open -> waiting
streaming with assistant content -> token -> streaming
ready -> response-complete -> ready
error -> error -> error

The current useChat reference also documents messages as UIMessage[], message role, message parts, onFinish.isAbort, onFinish.isError, and onError. The chatbot guide renders assistant text from message.parts when part.type === "text".

This preserves the important distinction for presence before output: streaming means the response stream is active, while visible assistant text still depends on the message content. The presence state stays waiting until content arrives.

Run node examples/vercel-ai-sdk-presence.mjs for the named no-network proof. It prints framework=vercel-ai-sdk, statusPath, streamOpenMs, firstOutputMs, leadMs, presenceBeforeOutputMs, finalState=ready, hasOutput=true, complete=true, interrupted=false, abortState=interrupted, and errorState=error.

Assistant Lifecycle

createAssistantLifecycleAdapter is a framework-package-free bridge for assistant app shapes that already have threads, runs, messages, and streaming text deltas. It does not claim an exact external package event contract. Pass plain lifecycle objects from your app layer, or wrap framework callbacks into these names:

import { createAssistantLifecycleAdapter } from "@ai-presence/adapters";

const assistantPresence = createAssistantLifecycleAdapter(presenceRuntime);

assistantPresence.handleEvent({ type: "run-created", threadId, runId });
assistantPresence.handleEvent({ type: "message-created", threadId, runId, messageId });
assistantPresence.handleEvent({ type: "text-delta", threadId, runId, messageId, delta: "Hello" });
assistantPresence.handleEvent({ type: "run-completed", threadId, runId });

Adapter mapping:

composer-input -> user-input -> user-typing
composer-pause -> user-pause -> reading/thinking
run-created / run-started / submitted / running -> model-waiting -> thinking
message-created / content-block-start / stream-open -> stream-open -> waiting
streaming with no assistant content -> stream-open -> waiting
text-delta / message-delta / output -> token -> streaming
run-completed / message-completed / ready -> response-complete -> ready
run-cancelled / abort / interrupt -> interrupt -> interrupted
run-failed / error -> error -> error

Run node examples/assistant-lifecycle-presence.mjs for the no-network proof. It simulates a thread/run opening and an assistant message shell existing before text arrives, then prints statePath, eventPath, frameworkEventPath, streamOpenMs, firstOutputMs, leadMs, presenceBeforeOutputMs, finalState, hasOutput, complete, and interrupted.

assistant-ui ExternalStoreRuntime

The assistant lifecycle adapter can also be wrapped around assistant-ui's documented ExternalStoreRuntime route without importing assistant-ui. Primary assistant-ui docs expose onNew, isRunning, mutable messages, and assistant message status.type values such as running, complete, and incomplete.

examples/assistant-ui-external-store-presence.mjs maps:

onNew -> run-created -> model-waiting -> thinking
isRunning=true -> running -> model-waiting -> thinking
empty assistant message with status.type="running" -> message-created -> stream-open -> waiting
first assistant text chunk -> text-delta -> token -> streaming
assistant message status.type="complete" -> complete -> response-complete -> ready

Run node examples/assistant-ui-external-store-presence.mjs for the named no-network proof. It prints framework=assistant-ui, route=ExternalStoreRuntime, frameworkEventPath, frameworkStatusPath, streamOpenMs, firstOutputMs, leadMs, presenceBeforeOutputMs, finalState, hasOutput, complete, and interrupted.

OpenAI Responses

createOpenAIResponsesAdapter is an event-mapping helper, not an SDK wrapper. Pass each typed streaming event object from your Responses stream consumer to handleEvent(event). The adapter branches on event.type, copies text or function-call argument chunks into detail.delta and detail.text when present, and never imports the OpenAI SDK, calls the network, or reads environment config.

Adapter mapping:

response.created -> model-waiting -> thinking
response.in_progress -> stream-open -> waiting
response.output_item.added -> stream-open -> waiting
response.content_part.added -> stream-open -> waiting
response.output_text.delta -> token -> streaming
response.function_call_arguments.delta -> token -> streaming
response.output_text.done -> response-complete -> ready
response.function_call_arguments.done -> response-complete -> ready
response.completed -> response-complete -> ready
response.failed / error -> error -> error
response.incomplete -> interrupt -> interrupted

This preserves presence-before-output: response.created can move the runtime into thinking, stream-opening events can move it into waiting, and the first response.output_text.delta moves it into streaming.

OpenAI Realtime

Adapter mapping:

input_audio_buffer.speech_started -> local-read -> reading
input_audio_buffer.speech_stopped -> model-waiting -> thinking
response.created -> model-waiting -> thinking
response.output_item.created -> stream-open -> waiting
response.content_part.added -> stream-open -> waiting
response.output_text.delta -> token -> streaming
response.output_audio_transcript.delta -> token -> streaming
response.output_audio.delta -> speech-start -> speaking
response.output_audio.done -> speech-end -> ready
response.done -> response-complete -> ready
error / response.failed -> error -> error

Older alias events already used by the prototype, such as response.audio.delta and response.text.delta, are also accepted.