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

@osirus/agent

v1.8.0

Published

Embeddable multi-mode AI agent widget for web apps (chat, code, search, image, video, speech).

Readme

Osirus Agent is a web widget you can embed in any site or app. It supports multiple interaction modes: chat, code, search, image, video, and speech.

Quickstart (60 Seconds)

Fastest (NPM)

npm i @osirus/agent
import OsirusAgent from '@osirus/agent'

OsirusAgent.init({
  agentId: 'YOUR_AGENT_ID',
  mode: 'search', // chat | code | search | image | video | speech
})

Fastest (CDN)

<script src="https://agent.osirus.ai/lib/umd/osirusai.min.js" type="text/javascript"></script>
<script type="text/javascript">
  OsirusAgent.init({
    agentId: 'YOUR_AGENT_ID',
    mode: 'chat'
  })
</script>

Installation

You install one package/script for all widget types, then choose the widget behavior with mode.

Local Test Harness (Before Push)

Run the local dev harness page:

npm run dev

Then open:

  • http://localhost:4000

Optional URL presets:

  • http://localhost:4000/?agentId=YOUR_AGENT_ID&mode=chat
  • http://localhost:4000/?agentId=YOUR_AGENT_ID&mode=search&searchPlaceholder=Search%20docs
  • http://localhost:4000/?agentId=YOUR_AGENT_ID&mode=speech
  • http://localhost:4000/?agentId=YOUR_AGENT_ID&baseApiUrl=https://osirus.ai/api

The page includes controls to:

  • Switch mode (chat, code, search, image, video, speech)
  • Override agentId
  • Override baseApiUrl
  • Set searchPlaceholder
  • Apply/reload or unmount/mount the widget

NPM

npm i @osirus/agent
import OsirusAgent from '@osirus/agent'

OsirusAgent.init({
  agentId: 'YOUR_AGENT_ID',
})

CDN

<script src="https://agent.osirus.ai/lib/umd/osirusai.min.js" type="text/javascript"></script>
<script type="text/javascript">
  OsirusAgent.init({
    agentId: 'YOUR_AGENT_ID'
  })
</script>

Multi-Agent Init (One Call)

You can mount many agents at once by passing an array to init.

import OsirusAgent from '@osirus/agent'

OsirusAgent.init([
  { agentId: 'AGENT_CHAT_ID', mode: 'chat' },
  { agentId: 'AGENT_CODE_ID', mode: 'code' },
  { agentId: 'AGENT_IMAGE_ID', mode: 'image' },
])

instanceId is optional in array mode. If omitted, it is auto-generated from agentId/name.

Mount Into Tab/Div Containers

Use mountTo to render inside a specific host element (for CMS tab systems, side panels, modals, etc.).

<div id="tab-code"></div>
<div id="tab-media"></div>
OsirusAgent.init([
  {
    agentId: 'AGENT_CODE_ID',
    mode: 'code',
    mountTo: '#tab-code',
    placement: { position: 'absolute', top: '0', right: '0', left: '0', bottom: '0' },
  },
  {
    agentId: 'AGENT_IMAGE_ID',
    mode: 'image',
    mountTo: '#tab-media',
    placement: { position: 'absolute', top: '0', right: '0', left: '0', bottom: '0' },
  },
])

mountTo accepts either a CSS selector string or an HTMLElement.

Host Callbacks (onOutput, onClose)

Use callbacks to receive generated output in the host app and react when users close the widget.

import type { AgentOutputEvent, AgentCloseEvent } from '@osirus/agent'

OsirusAgent.init({
  agentId: 'AGENT_IMAGE_ID',
  mode: 'image',
  mountTo: '#tab-media',
  onOutput: (event: AgentOutputEvent) => {
    // event.type: 'code' | 'image' | 'video' | ...
    // event.output contains payload from the mode panel
    // Example image payload: { urls, primaryUrl, generationId, prompt, source }
    console.log('output', event)
  },
  onClose: (event: AgentCloseEvent) => {
    // Example: hide active tab or persist draft state
    console.log('closed', event.reason, event.instanceId)
  },
})

agentId is always included in onOutput/onClose payloads for app-backed widgets and should be used as the host-side auth token when handling callback actions.

Current mode outputs:

  • code: emits updated HTML after apply.
  • image: emits generated media URLs when create/status returns outputs.
  • video: emits generated media URLs when create/status returns outputs.

React Host Tab Example

import { useEffect } from 'react'
import OsirusAgent from '@osirus/agent'

export function CmsAiTabs() {
  useEffect(() => {
    OsirusAgent.init([
      {
        agentId: 'AGENT_CODE_ID',
        mode: 'code',
        mountTo: '#tab-code',
        onOutput: (event) => console.log('code output', event.output),
      },
      {
        agentId: 'AGENT_IMAGE_ID',
        mode: 'image',
        mountTo: '#tab-media-generate',
        onOutput: (event) => console.log('media output', event.output),
      },
    ])

    return () => {
      OsirusAgent.destroy()
    }
  }, [])

  return (
    <>
      <div id="tab-code" />
      <div id="tab-media-generate" />
    </>
  )
}

Lifecycle Methods

Use these methods when your host controls tab lifecycle explicitly.

// Update an existing mounted widget instance
OsirusAgent.update({
  instanceId: 'AGENT_CODE_ID',
  searchPlaceholder: 'Search CMS docs...',
})

// Destroy one instance
OsirusAgent.destroy('AGENT_CODE_ID')

// Destroy all instances
OsirusAgent.destroy()

Install Each Widget Type

Use mode in your init config to force widget behavior per embed.

If your agent already has a type configured in the app, you can omit mode. If both are present, mode in OsirusAgent.init(...) overrides the agent default.

Supported values:

  • chat
  • code
  • search
  • image
  • video
  • speech

Legacy alias:

  • voice is normalized to speech

1. Chat Widget

OsirusAgent.init({
  agentId: 'YOUR_AGENT_ID',
  mode: 'chat',
})

2. Code Widget

code mode provides an HTML/code editor panel with prompt + attachment apply flow.

OsirusAgent.init({
  agentId: 'YOUR_AGENT_ID',
  mode: 'code',
})

3. Search Widget

search mode replaces the floating chat icon with a floating search bar launcher.

OsirusAgent.init({
  agentId: 'YOUR_AGENT_ID',
  mode: 'search',
  searchPlaceholder: 'Search docs, API, pricing...',
})

4. Image Widget

image mode includes a Generate tab with a canvas preview and prompt input.

OsirusAgent.init({
  agentId: 'YOUR_AGENT_ID',
  mode: 'image',
})

5. Video Widget

video mode includes a Generate tab with video-focused prompting and preview.

OsirusAgent.init({
  agentId: 'YOUR_AGENT_ID',
  mode: 'video',
})

6. Speech Widget

speech runs inside chat and supports a fullscreen speech view.

OsirusAgent.init({
  agentId: 'YOUR_AGENT_ID',
  mode: 'speech',
})

Local Configuration Example

Use local configuration when you are not loading agent settings by agentId.

OsirusAgent.init({
  name: 'OsirusAgent',
  mode: 'chat',
  searchPlaceholder: 'Search...',
  companyName: 'Osirus',
  companyIconUrl: 'https://agent.osirus.ai/images/Osirus-Icon.svg',
  customColor: '#006FE5',
  description: 'Embedded support and AI agent widget.',
  phoneNumber: '123-456-7890',
  email: '[email protected]',
  docUrl: 'https://osirus.ai/docs',
  apiDocUrl: 'https://osirus.ai/docs/api',
  support: {
    type: 'page',
    value: 'https://osirus.ai/support',
  },
  schedule: 'M - F, 8:30AM - 5:30PM EDT',
  address: {
    streetAddress: '123 Orange Ave',
    city: 'Orlando',
    state: 'FL',
    postalCode: '38235',
    country: 'USA',
  },
  showMap: true,
  googleMapApiKey: 'AIzaS...x2E_k',
  greeting: 'Hi, how can I help you today?',
  customOptions: [
    {
      icon: 'people',
      label: 'Careers',
      link: 'https://www.solodev.com/careers',
      openNewTab: true,
    },
  ],
})

React Export (@osirus/agent/react)

For React apps, you can import reusable UI components directly (in addition to OsirusAgentProvider).

import {
  CodeHtmlEditor,
  FieldAssistantBar,
  HTMLEditor,
  MediaGeneratePanel,
} from '@osirus/agent/react'
import { useRef, useState } from 'react'

export function Example() {
  const inputRef = useRef<HTMLInputElement | null>(null)
  const [visible, setVisible] = useState(true)

  return (
    <>
      <CodeHtmlEditor
        value="<p>Hello</p>"
        onApply={async ({ prompt, html }) => {
          // Call your API here and return updated HTML.
          return html
        }}
      />

      <HTMLEditor
        name="content"
        value="<p>Hello world</p>"
        onChange={(nextHtml) => console.log(nextHtml)}
        onApplyPrompt={async ({ prompt, html, files }) => {
          // Call your API and return updated html.
          return { html }
        }}
      />

      <div style={{ position: 'relative', marginTop: 24 }}>
        <input
          ref={inputRef}
          onFocus={() => setVisible(true)}
          placeholder="Edit this text with AI"
        />
        <FieldAssistantBar
          targetRef={inputRef}
          visible={visible}
          onAssist={async ({ mode, text, prompt }) => {
            // Call your API here and return updated text.
            return { text: mode === 'prompt' ? `${text} ${prompt || ''}` : text }
          }}
        />
      </div>

      <MediaGeneratePanel
        agentId="YOUR_IMAGE_AGENT_ID"
        prompt="cinematic sunset mountain"
        onPromptChange={(value) => console.log(value)}
        onGenerate={({ prompt, aspectRatio, agentId }) => {
          console.log('generate', prompt, aspectRatio, agentId)
        }}
        onAddToLibrary={({ url, agentId }) => {
          console.log('add-to-library', url, agentId)
        }}
        generatedUrls={['https://example.com/generated.png']}
      />
    </>
  )
}

MediaGeneratePanel callback payloads always include agentId so host systems can enforce agent-scoped authorization. For HTMLEditor and FieldAssistantBar, pass aiContext/context.agentId so callback requests include the same token.

Configuration Reference

App-Backed Config (agentId)

| Property | Type | Required | Description | Example | |---|---|---|---|---| | agentId | string | Yes | Agent ID created in the Osirus app. | "abc123" | | baseApiUrl | string | No | API base URL override. | "https://osirus.ai/api" | | mode | 'chat' \| 'code' \| 'search' \| 'image' \| 'video' \| 'speech' | No | Overrides widget mode for this embed. | "search" | | searchPlaceholder | string | No | Search input placeholder for search mode. | "Search docs..." | | instanceId | string | No | Unique widget instance key used by update/destroy. | "cms-code-tab" | | mountTo | string \| HTMLElement | No | Mount target selector or element instead of default floating root. | "#tab-code" | | placement | object | No | Inline placement style for widget overlay. | { position: 'absolute', top: '0', left: '0' } | | onOutput | (event) => void | No | Receives generated outputs (code, image, video, etc.). | (e) => console.log(e.output) | | onClose | (event) => void | No | Called when widget closes. | (e) => console.log(e.reason) |

Local Config

| Property | Type | Required | Description | Example | |---|---|---|---|---| | name | string | Yes | Agent display name. | "OsirusAgent" | | mode | 'chat' \| 'code' \| 'search' \| 'image' \| 'video' \| 'speech' | No | Widget mode. | "speech" | | searchPlaceholder | string | No | Search input placeholder for search mode. | "Search..." | | instanceId | string | No | Unique widget instance key used by update/destroy. | "cms-local-widget" | | mountTo | string \| HTMLElement | No | Mount target selector or element instead of default floating root. | "#assistant-tab" | | placement | object | No | Inline placement style for widget overlay. | { position: 'absolute', top: '0', left: '0' } | | onOutput | (event) => void | No | Receives generated outputs (code, image, video, etc.). | (e) => console.log(e.output) | | onClose | (event) => void | No | Called when widget closes. | (e) => console.log(e.reason) | | companyName | string | No | Replaces agent name in UI. | "Osirus" | | companyIconUrl | string | No | Company logo URL shown in widget header. | "https://agent.osirus.ai/images/Osirus-Icon.svg" | | customColor | string | No | Hex color for widget actions. | "#006FE5" | | description | string | No | Company/agent description text. | "Embedded support and AI agent widget." | | phoneNumber | string | No | Enables call button. | "123-456-7890" | | email | string | No | Support email. | "[email protected]" | | docUrl | string | No | Enables docs panel button. | "https://osirus.ai/docs" | | apiDocUrl | string | No | Enables API docs panel button. | "https://osirus.ai/docs/api" | | support | { type: 'page' \| 'email', value: string } | No | Support button behavior and target. | { type: 'page', value: 'https://osirus.ai/support' } | | schedule | string | No | Operating hours. | "M - F, 8:30AM - 5:30PM EDT" | | address | object | No | Business address object. | { streetAddress, city, state, postalCode, country } | | showMap | boolean | No | Shows map preview (requires googleMapApiKey). | true | | googleMapApiKey | string | No | Google Maps API key for map rendering. | "AIzaS...x2E_k" | | greeting | string | No | Initial greeting and popup message text. | "Hi, how can I help you today?" | | customOptions | Array<{ icon, label, link, openNewTab }> | No | Custom action buttons. | [{ icon: 'telephone-plus', label: 'Sales', link: 'https://example.com', openNewTab: true }] |

Callback Event Shapes

onOutput(event):

  • event.type: 'chat' | 'code' | 'image' | 'video' | 'speech' | 'search'
  • event.output: mode-specific payload (for example html for code, urls for image/video)
  • event.agentId, event.instanceId, event.mode, event.timestamp

onClose(event):

  • event.reason: close reason string (for example 'widget-close')
  • event.agentId, event.instanceId, event.mode, event.timestamp

Icon Notes

customOptions[].icon uses Bootstrap Icons names (without the bi- prefix). Example: "telephone-plus" renders bi bi-telephone-plus.