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

@athenaintel/react

v0.14.0

Published

Athena React SDK — Build AI-powered chat applications with the Athena platform

Readme

@athenaintel/react

React SDK for building AI-powered chat applications with the Athena platform.

Installation

npm install @athenaintel/react

If you use the PropelAuth-specific provider from @athenaintel/react/auth, also install:

npm install @propelauth/react

Quick Start

import { AthenaProvider, AthenaChat, Toolkits } from '@athenaintel/react';
import '@athenaintel/react/styles.css';

function App() {
  return (
    <AthenaProvider
      config={{ apiKey: 'your-api-key' }}
      tools={[Toolkits.DOCUMENT, Toolkits.WEB_SEARCH]}
    >
      <AthenaChat />
    </AthenaProvider>
  );
}

Provider Config

<AthenaProvider config={{ environment: 'staging' }}>
  <AthenaChat />
</AthenaProvider>

<AthenaProvider
  config={{
    apiUrl: 'https://sync.example.com/api/chat',
    backendUrl: 'https://api.example.com',
    appUrl: 'https://app.example.com',
  }}
>
  <AthenaChat />
</AthenaProvider>

config accepts apiKey, token, apiUrl, backendUrl, appUrl, trustedParentOrigins, environment, transport, and statewireSyncUrl. Top-level apiKey, token, apiUrl, backendUrl, appUrl, and environment props remain supported as compatibility aliases, but config is now the preferred API.

If config.appUrl is omitted, the provider resolves it from the parent bridge or from the matching Athena environment defaults. Known Athena staging and production apiUrl and backendUrl values automatically fall back to the corresponding frontend origin.

Use trustedParentOrigins when the SDK runs inside an iframe on a private-cloud or custom parent domain and you want to explicitly allow postMessage auth/config from that parent.

Statewire Transport (default as of 0.12.0)

Statewire is the default chat transport: the SDK attaches to the deep-agent statewire sync host, so the thread is hosted server-side and replicated live — history, reconnect, run scheduling, mid-run queueing, HITL approvals, and client tools (for recognized SDK hosts, e.g. computer-asset app_ids) all come from the server snapshot. Pass transport: 'legacy' to opt a deployment back onto the legacy Iris /api/chat stream:

<AthenaProvider config={{ environment: 'staging', transport: 'legacy' }}>
  <AthenaChat />
</AthenaProvider>

Migrating from ≤0.11.x (legacy default):

  • Threads are transport-scoped: conversations created on the legacy transport are read-only from statewire (and vice versa). Users keep their history but continue in new threads.
  • The statewire runtime applies the deep-agent model default when no model prop is set; pin model explicitly if you depended on the legacy default.
  • The agent prop's legacy agent names are not honored on statewire; use collab_agent:<id> refs (with transport: 'statewire' semantics) or the default agent.

The sync endpoint defaults to the effective apiUrl host + /v2/threads (e.g. staging resolves to https://iris.stg.athenaintel.com/v2/threads, the same statewire base the mobile app and Chrome extension ship); pass statewireSyncUrl to override it for custom hosts whose sync mount lives on a different origin. If neither yields a URL (e.g. an unparseable custom apiUrl), the provider throws instead of falling back to an Athena default — credentials are never sent to a host you didn't configure. Auth reuses the provider's existing credential plumbing: tokens ride Authorization: Bearer and API keys ride X-API-KEY.

What the statewire transport wires up in AthenaChat:

  • Approvals (HITL): when the backend parks a run on an approval-gated tool call, an approval card renders above the composer with Approve/Reject (or Continue for a generic pause) and resumes the run through the statewire run/input command. Hosts that build their own thread UI should mount the exported StatewireApprovalCard themselves — without it an approval-gated run stays parked with no way to answer it.
  • Frontend tools: tools in frontendTools with a local execute are declared to the backend as client_tools and executed by the mounted client-tool bridge, which resumes the run with each tool's result.
  • Mid-run sends and the queue: a message sent while a run is active queues on the server. The queue panel above the composer lists queued entries with remove and "Send now" (steer), plus Continue for a stopped run's steer lane.
  • Errors and connection state: transport errors (send rejections, paywall refusals) render as a dismissible banner; a degraded connection shows a reconnect strip; a read-only pre-cutover thread shows a read-only notice. Custom hosts can read all of it via useAthenaStatewireLifecycle.
  • Thread list: enableThreadList works with statewire. The list is the same persisted Agora session list; switching threads re-attaches the statewire session to the selected thread. ThreadList and useAthenaThreadManager work in both modes.

Remaining limitations: on statewire the agent prop only accepts collab_agent:<asset_id> refs (see below) — any other value is ignored, because the statewire host always runs the Athena deep agent. model defaults to the deep-agent default model unless a collab agent supplies one.

Collab Agents

A collab agent is an agent configuration authored in Athena (prompt, model, toolkits, behavior) and addressed as collab_agent:<asset_id>. Point the provider at one and the chat runs as that agent:

<AthenaProvider
  transport="statewire"
  agent="collab_agent:asset_432af46f-293d-480b-a518-30b1f42a9ef7"
  channel="askbob_web"
>
  <AthenaChat />
</AthenaProvider>

Copy the snippet with real ids from the agent's Channels tab in Athena.

channel is optional. It selects a channel override layer — a built-in channel (email, sms, …) or a custom channel defined on that agent — so one agent can present different prompts, models, and tools per surface. Omit it to run the agent's base configuration.

Requirements

  • transport="statewire". The legacy transport ignores collab_agent: refs.
  • Publish the agent. Resolution reads the published snapshot, not the live draft, so a channel that exists only in the editor is rejected with collab_agent_channel_unknown.
  • The acting user needs VIEW access to the agent asset (admins bypass). Running as an agent exposes its prompt and tool policy, so the same gate that governs opening the asset governs running it.

Do not also pass model, systemPrompt, or tools

Request keys override the agent definition, so anything you pass here silently replaces what the agent's author configured — the run succeeds and returns a plausible answer using your config instead of theirs.

// ❌ the agent's prompt, model, and tools are all discarded
<AthenaProvider
  transport="statewire"
  agent="collab_agent:asset_1234"
  model="claude-opus-4-6"
  systemPrompt="You are a helpful assistant."
  tools={['web_search_browse_toolkit']}
/>

// ✅ the agent's own configuration wins
<AthenaProvider transport="statewire" agent="collab_agent:asset_1234" />

Pass them only when you deliberately want to override the agent — an explicit model is honoured as a caller override, with the agent's model as the default beneath it.

Failure codes

A refused selection surfaces as an AthenaSdkError with code: 'collab_agent_rejected'; the specific reason below rides in the error's detail. Subscribe with onError (see Debugging) rather than guessing from messages:

| Code | Meaning | |---|---| | collab_agent_not_found | No such asset, or it is not a collab_agent | | collab_agent_forbidden | The acting user lacks VIEW on the asset | | collab_agent_channel_unknown | No such channel (the message lists the known ones) | | collab_agent_channel_disabled | The channel exists but is toggled off | | collab_agent_channel_kind_mismatch | A voice channel was selected for a text run | | collab_agent_runs_disabled | The deployment has the SDK seam turned off |

Authentication

Same-origin SSO defaults

import { AthenaSSOProvider } from '@athenaintel/react/auth';
import { AthenaChat, AthenaProvider } from '@athenaintel/react';

function App() {
  return (
    <AthenaSSOProvider>
      <AthenaProvider enableThreadList>
        <AthenaChat />
      </AthenaProvider>
    </AthenaSSOProvider>
  );
}

By default, AthenaSSOProvider uses same-origin SSO endpoints:

  • /api/sso/userinfo
  • /api/sso/initiate
  • /api/sso/logout

This makes the SSO URLs optional when your frontend is reverse-proxied with the backend.

Cross-origin SSO backend

import { AthenaSSOProvider } from '@athenaintel/react/auth';

<AthenaSSOProvider ssoBaseUrl="https://api.example.com">
  <AthenaProvider
    config={{
      backendUrl: 'https://api.example.com/api/assistant-ui',
      apiUrl: 'https://sync.example.com/api/chat',
      trustedParentOrigins: ['https://app.example.com'],
    }}
    enableThreadList
  >
    <AthenaChat />
  </AthenaProvider>
</AthenaSSOProvider>

If you need full control, ssoUserInfoUrl, ssoLoginUrl, and ssoLogoutUrl remain available as explicit overrides.

Citation Links

When you render chat inside <AthenaLayout>, Athena citation links (app.athenaintel.com/dashboard/spaces?...) now open the referenced asset in the SDK asset pane by default instead of navigating away.

If your host app wants different behavior, configure linkClicks on <AthenaProvider> or use useAthenaLinkClickHandler() inside a custom message renderer. The hook runs for every rendered link; only Athena citation links are intercepted by default.

import { useMemo } from 'react';
import { AthenaChat, AthenaLayout, AthenaProvider } from '@athenaintel/react';

function App() {
  const linkClicks = useMemo(
    () => ({
      onClick: (link) => {
        if (link.kind !== 'athena-citation' || !link.openInAssetPanel) {
          return false;
        }

        console.log('Citation clicked:', link.citation?.assetId);
        link.openInAssetPanel();
        return true;
      },
    }),
    [],
  );

  return (
    <AthenaProvider linkClicks={linkClicks}>
      <AthenaLayout>
        <AthenaChat />
      </AthenaLayout>
    </AthenaProvider>
  );
}

Set linkClicks={{ interceptAthenaCitations: false }} to keep Athena citation links opening in the browser while still letting your app observe all link clicks.

Standalone Asset Embeds

Use AthenaAssetEmbed to render a native Athena asset without chat, thread history, tabs, or the SDK split-pane layout. It defaults to the editable, full native asset experience (readOnly={false} and displayMode="full"). The embed token and the current user must still have edit permission; otherwise Athena renders the asset read-only.

import { useState } from 'react';
import {
  AthenaAssetEmbed,
  AthenaProvider,
  type AthenaAssetCitationReference,
} from '@athenaintel/react';

function AssetView() {
  const [linkedReference, setLinkedReference] =
    useState<AthenaAssetCitationReference | null>(null);

  return (
    <AthenaProvider config={{ token: accessToken }}>
      <div style={{ height: 800 }}>
        <AthenaAssetEmbed
          assetId="asset_123"
          displayMode="full"
          readOnly={false}
          onCitationClick={({ reference, sourceAssetId }) => {
            console.log('Citation clicked', { reference, sourceAssetId });
          }}
          onCitationAction={({ action, reference }) => {
            if (action === 'open-in-spaces') {
              setLinkedReference(reference);
            }
          }}
        />
        {linkedReference && (
          <AthenaAssetEmbed
            assetId={linkedReference.id}
            reference={linkedReference}
            displayMode="full"
            readOnly={false}
          />
        )}
      </div>
    </AthenaProvider>
  );
}

When onCitationClick is provided, citation navigation is delegated to the host by default. Set citationBehavior="browser" to observe the event while preserving Athena's default new-tab navigation. Host mode requires onCitationClick; without a handler, the SDK safely falls back to browser navigation.

onCitationAction handles actions initiated from a citation popover. It currently receives action: 'open-in-spaces' when the user clicks the (+) button. Providing the handler delegates that action to the host by default. Set citationActionBehavior="browser" to observe the event while preserving Athena's default navigation; requesting host mode without a handler safely falls back to browser behavior.

Pass the callback's complete reference to the linked AthenaAssetEmbed, rather than storing only reference.id. The embed uses the reference anchor to navigate PDFs to the cited page and highlight the cited excerpt or rectangular region. Updating the reference also navigates when the host opens another citation in the same asset.

If the host starts with an Athena citation URL/string instead of an onCitationAction event, parse it and pass the returned reference directly to the embed:

import {
  AthenaAssetEmbed,
  parseAthenaCitationLink,
} from '@athenaintel/react';

const citation = parseAthenaCitationLink({
  href: citationString,
  appUrl: 'https://app.athenaintel.com',
});

return citation ? (
  <AthenaAssetEmbed
    assetId={citation.assetId}
    reference={citation.reference}
    displayMode="full"
    readOnly={false}
  />
) : null;

For example, this citation opens the PDF directly at page 34:

https://app.athenaintel.com/dashboard/spaces/?asset_ids=asset_pdf&anchor=page&page=34&excerpt=Term%20debt

The important query parameters are asset_ids, anchor=page, page, and excerpt. Page ranges, text anchors, and positioned citations are also preserved by parseAthenaCitationLink. A page_rect may include unit=percent (the default) or unit=point; retain the unit so the region maps to the correct PDF coordinates.

Styling

styles.css is a self-contained stylesheet compiled at package build time. One import styles every SDK component — the host app does not need Tailwind:

import '@athenaintel/react/styles.css';

It contains the design tokens, the Tailwind utilities the SDK components use, and an element reset (preflight) scoped to the SDK's own chrome (.aui-root trees and .athena-sdk-chrome roots, including portaled tooltips/popups). It never restyles the host page — not even host components you nest inside AthenaProvider to use hooks like useSendMessage: the reset only reaches SDK-rendered roots, design tokens live on the provider's .athena-sdk wrapper (inert custom properties) rather than :root, and everything ships in CSS cascade layers so any unlayered host rule wins on conflict.

Hosts that already run Tailwind v4 (like the athena-app template) may instead — or additionally — compile the SDK's classes themselves:

@source "../node_modules/@athenaintel/react/dist";

Importing styles.css alongside a host Tailwind build is harmless (utilities are identical and layered). One caveat for themed Tailwind hosts: token values set on the .athena-sdk element shadow values inherited from :root, so define your app's token overrides on .athena-sdk too (:root, .athena-sdk { --primary: …; }) — or use the theme prop below, which always wins.

Theming

import { themes } from '@athenaintel/react';

<AthenaProvider theme={themes.dark}>
<AthenaProvider theme={{ ...themes.dark, primary: '#8b5cf6' }}>
<AthenaProvider theme={{ primary: '#e11d48', radius: '1rem' }}>

Preset themes: light, dark, midnight, warm, purple, green.

For CSS-level theming without the theme prop, set the design-token custom properties on .athena-sdk (unlayered rules override the SDK's layered defaults):

.athena-sdk {
  --primary: oklch(0.4 0.15 260);
  --radius: 1rem;
}

Key Components

  • <AthenaProvider> — Runtime, auth, theming, and configuration
  • <AthenaChat> — Full chat UI with composer, messages, and tool rendering
  • <AthenaLayout> — Split-pane layout with asset panel
  • <ThreadList> — Conversation history sidebar
  • Toolkits — Constants for all available backend toolkits

Composer Hooks

Use useAppendToComposer() when you want to prefill a draft without sending it.

Use useSendMessage() for workflow buttons, sidebar shortcuts, and other UI that lives outside <AthenaChat> but still needs to submit a prompt.

import { useSendMessage } from '@athenaintel/react';

function WorkflowButton() {
  const sendMessage = useSendMessage();

  return (
    <button onClick={() => void sendMessage('Run the quarterly workflow')}>
      Run workflow
    </button>
  );
}

Debugging and Diagnostics

The SDK emits structured diagnostic events — auth handshake, thread list, statewire attach, sends, errors — with timings. Nothing is logged by default; turn it on with the debug prop:

<AthenaProvider
  debug                        // or 'debug' | 'info' | { console: 'debug', posthog: true }
  onDiagnostic={(event) => console.log(event.name, event.durationMs)}
  onError={(error) => reportToSentry(error)}
>

onError receives an AthenaSdkError with a stable code, a human hint, and the originating status/detail — match on code, never on message text:

import { ATHENA_SDK_ERROR_CODES } from '@athenaintel/react';

onError={(error) => {
  if (error.code === ATHENA_SDK_ERROR_CODES.collab_agent_rejected) {
    // the backend's granular reason rides in `detail`, e.g.
    // 'collab_agent_channel_unknown' — whose message lists the known channels
    console.warn(error.detail, error.hint);
  }
}}

Each provider registers its own consumer, so multiple mounted providers all receive every event; a callback that throws is caught and cannot break the chat.

Without a rebuild, from the browser console:

localStorage.setItem('athena:debug', 'debug');  // console echo on, survives reload
__ATHENA_SDK__.diagnostics.snapshot();          // recent events + timings
__ATHENA_SDK__.diagnostics.export();            // JSON, for attaching to a bug report

Credentials are redacted everywhere (buffer, console, PostHog): any key matching token, secret, api[-_]?key, authorization, cookie, or password is stripped before an event is recorded. Spans also emit performance.mark/measure entries prefixed athena-sdk:, so they show up on the browser Performance timeline.

License

Proprietary. For licensed enterprise customers only.