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

@sashimo/lib

v9.7.0

Published

Tool to integrate AI admin tools into your application

Readme

🌟 Sashi - Your Magical AI-Powered Admin Companion! 🤖

🚀 Welcome to the Enchanted World of Sashi

Sashi is the core TypeScript/JavaScript library that powers the Sashi workflow system. It runs inside your app or service and transforms complex admin tasks into simple conversations. With its AI-powered interface, you can perform admin tasks with the ease of a magical spell. 🪄

✨ Core Features

  • 🔹 Function Registration Interface: Declaratively expose your backend functions
  • 🔹 Workflow Execution Runtime: Run complex workflows with simple commands
  • 🔹 UI Metadata Hooks: Auto-generate beautiful interfaces
  • 🔹 SashiHub Integration: Connect with the external SashiHub API
  • 🔹 AI-Powered Chat: Execute admin tasks with natural language
  • 🔹 Secure & Reliable: Built-in support for sensitive function confirmation

🧩 Core Responsibilities

1. Function Registration

  • Provides a registerFunction() API to declare named functions, their parameters, and return types
  • Supports:
    • Zod-based parameter schemas
    • Sync and async functions
    • Visualization functions (with metadata)
    • Repository-scoped functions

2. Function Metadata

Functions are registered with:

  • Name/ID
  • Description (used for AI prompt/context)
  • Input parameter schema (Zod)
  • Return value type (for UI rendering)
  • Optional visibility/config flags (e.g., hidden, inactive)
  • Automatically generates metadata used by the AI layer and/or workflow editor

3. Workflow Execution

  • Accepts a serialized workflow object (steps + parameters) and executes them in sequence
  • Handles:
    • Parameter chaining
    • Type conversion
    • Error catching and reporting
    • Array mapping ([*] style execution)
    • Optionally runs in debug mode for step-by-step inspection

4. UI Metadata & Type Hints

  • Includes utility to infer UI types from data (e.g., table, badge, graph)
  • Used by the LLM and front-end UI generator to create input/output forms

5. Communication with SashiHub (sashihub)

  • Sends workflow save/load requests to sashihub via authenticated API calls
  • Relies on the developer to provide an x-api-token
  • Supports repository metadata sync via forward-call or metadata endpoints

🔒 Assumptions and Boundaries

  • sashilib is frontend-safe if used in limited exposure contexts
  • It does not persist workflows itself — all workflow state lives in sashihub
  • It does not handle user auth or rate limiting — this is up to the surrounding app or sashihub

🛠️ Use Cases

  • Register custom backend logic to be used in workflows
  • Create a shared interface for internal tools or ops automation
  • Power AI-driven workflows with securely validated parameters
  • Chain local and remote function calls in one workflow

📦 Installation

npm install @sashimo/lib

Important: This library requires zod version 3.25.67 or lower. Installing with a higher version may cause compatibility issues.

🔧 Basic Usage

import { createMiddleware, AIFunction } from "@sashimo/lib"

// Create a function
const getUsers = new AIFunction("get_users", "Get all users")
    .args()
    .returns({
        name: "users",
        type: "array",
        description: "Array of user objects",
    })
    .implement(async () => {
        return [
            { email: "[email protected]", name: "User 1" },
            { email: "[email protected]", name: "User 2" },
        ]
    })

// Create middleware
const router = createMiddleware({
    openAIKey: process.env.OPENAI_API_KEY,
    sashiServerUrl: "https://your-server.com",
    apiSecretKey: "your-secret-key",
})

// Use in Express app
app.use(router)

🏷️ Advanced Examples

Basic Example

import {
    AIArray,
    AIFunction,
    AIObject,
    registerFunctionIntoAI,
} from "@sashimo/lib"

const UserObject = new AIObject("User", "a user in the system", true).field({
    name: "email",
    description: "the email of the user",
    type: "string",
    required: true,
})

const GetUserByIdFunction = new AIFunction("get_user_by_id", "get a user by id")
    .args({
        name: "userId",
        description: "a user's id",
        type: "number",
        required: true,
    })
    .returns(UserObject)
    .implement(async (userId: number) => {
        const user = await getUserById(userId)
        return user
    })

registerFunctionIntoAI("get_user_by_id", GetUserByIdFunction)

Advanced Example: Handling Multiple Objects

const ProductObject = new AIObject(
    "Product",
    "a product in the inventory",
    true
)
    .field({
        name: "productId",
        description: "the unique identifier for a product",
        type: "number",
        required: true,
    })
    .field({
        name: "productName",
        description: "the name of the product",
        type: "string",
        required: true,
    })

const GetProductsFunction = new AIFunction(
    "get_products",
    "retrieve a list of products"
)
    .returns(new AIArray(ProductObject))
    .implement(async () => {
        const products = await getAllProducts()
        return products
    })

registerFunctionIntoAI("get_products", GetProductsFunction)

Example: Using Enums

import { AIFieldEnum, AIFunction, registerFunctionIntoAI } from "@sashimo/lib"

// Create a function that changes a user's role using an enum
const ChangeUserRoleFunction = new AIFunction(
    "change_user_type",
    "change a user type"
)
    .args(
        {
            name: "userId",
            description: "a users id",
            type: "string",
            required: true,
        },
        new AIFieldEnum(
            "type",
            "the type to change the user to",
            ["CASE_MANAGER", "COMMUNITY_ENGAGEMENT"],
            true
        )
    )
    .returns({
        name: "userid",
        description: "the user id",
        type: "string",
    })
    .implement(async (userId: string, role: string) => {
        // Implementation to change the user's role
        console.log("Changing role for user", userId, "to", role)
        return userId
    })

registerFunctionIntoAI("change_user_type", ChangeUserRoleFunction)

This example shows how to:

  • Use AIFieldEnum to create a dropdown selector in the UI
  • Define allowed values for the enum parameter
  • Handle enum validation automatically
  • Provide clear descriptions for the UI and AI

🛡️ Security

Protect your magical realm with robust security:

import { Request, Response, NextFunction } from "express"
import { createMiddleware } from "@sashimo/lib"

const verifySessionMiddleware = async (
    req: Request,
    res: Response,
    next: NextFunction
) => {
    const sessionToken = req.headers["x-sashi-session-token"]

    if (!sessionToken) {
        return res.status(401).send("Unauthorized")
    }

    if (sessionToken !== "userone-session-token") {
        return res.status(401).send("Unauthorized")
    }

    next()
}

app.use(
    "/sashi",
    verifySessionMiddleware,
    createMiddleware({
        openAIKey: process.env.OPENAI_API_KEY || "",
        getSession: async (req, res) => {
            return "userone-session-token"
        },
    })
)

🔍 API Reference

Middleware Options

interface MiddlewareOptions {
    openAIKey: string
    sashiServerUrl?: string // where the sashi server is hosted if you can't find it automatically
    apiSecretKey?: string // used to validate requests from and to the hub
    addStdLib?: boolean // add the standard library to the hub
    langFuseInfo?: {
        publicKey: string
        secretKey: string
        baseUrl: string
    }
    getSession?: (req: Request, res: Response) => Promise<string> // function to get the session id for a request
}

📚 Documentation

For more spells and incantations, visit our Sashi documentation.

🤝 Join the Sashi Fellowship

Are you ready to make admin tasks a breeze? Join us on this magical journey! Check out our Contributing Guide.

⚖️ License

Sashi is released under the MIT License.

🔄 Workflow System

This update introduces a powerful workflow system that enables users to create automated sequences of your registered functions.

📊 How Workflows Work

Once you register your functions with Sashi, they automatically become available for use in workflows. Users can then:

  1. Create sequences of actions using your registered functions
  2. Pass data between steps - Output from one function becomes input to another
  3. Save and reuse workflows for common tasks
  4. Execute workflows with a single click instead of multiple manual steps
graph TD
    A[Register Functions] --> B[Functions Available in Workflow System]
    B --> C[Users Create Workflows]
    C --> D[Workflows Executed When Needed]
    D --> E[Results Displayed to User]

    A1[Developer] --> A
    C1[End User] --> C

    style A fill:#a4c2f4
    style B fill:#b6d7a8
    style C fill:#f9d77e
    style D fill:#d5a6bd
    style E fill:#ea9999
    style A1,C1 fill:#d9d9d9

🔗 Function Integration in Workflows

Your registered functions become building blocks that users can connect together:

graph LR
    A[Function: Get Users] --> B[Function: Filter Active Users]
    B --> C[Function: Send Notification]

    A1[Output: User List] --> B1[Input: Users]
    B2[Output: Filtered Users] --> C1[Input: Recipients]

    style A,B,C fill:#a4c2f4
    style A1,B1,B2,C1 fill:#d5a6bd

🌐 Data Flow Between Systems

The workflow system handles all the data flow between your registered functions and external systems without you needing to implement any additional code:

sequenceDiagram
    participant Dev as Developer
    participant Sashi as Sashi System
    participant User as User
    participant Ext as External Services

    Dev->>Sashi: Register functions
    User->>Sashi: Create workflows using functions
    User->>Sashi: Execute workflow
    Sashi->>Ext: Call external APIs if needed
    Ext-->>Sashi: Return results
    Sashi->>Sashi: Process data between steps
    Sashi-->>User: Display final results

📝 What You Need To Do

As a developer, you only need to:

  1. Register your functions using the AIFunction system (as shown in previous examples)
  2. Ensure proper input/output typing so the workflow system knows what data can be passed between steps
  3. Document your functions well so users understand what each function does

The workflow storage, execution, and visualization are all handled automatically by the Sashi system.

For more information on how users can use the workflows you enable, direct them to our Workflow Documentation.

Default Functions

Sashi includes a set of built-in utility functions that are hidden from the UI by default but always available for AI processing. These functions are automatically included in the tools schema and split into multiple messages if they exceed 8000 characters to prevent token limits.

Automatic Loading

Default functions are automatically available to the AI without any manual loading:

import express from "express"
import { createMiddleware } from "@sashimo/lib"

const app = express()

app.use(
    "/sashi",
    createMiddleware({
        openAIKey: process.env.OPENAI_API_KEY || "",
        // Default functions are automatically available to AI
        // but hidden from the UI dropdown
    })
)

Manual Loading (Optional)

If you want to load specific categories of default functions, you can still do so:

import express from "express"
import { createMiddleware, loadDefaultFunctionsOnDemand } from "@sashimo/lib"

const app = express()

// Load specific categories (optional - they're available anyway)
loadDefaultFunctionsOnDemand(["math", "text"])

app.use(
    "/sashi",
    createMiddleware({
        openAIKey: process.env.OPENAI_API_KEY || "",
    })
)

Available Categories

  • math - Basic math operations (add, subtract, multiply, divide, round)
  • data - Data manipulation (extract, replace, split, join, filter)
  • datetime - Date and time operations (format_date, add_days)
  • system - System utilities (get_current_time, generate_uuid)
  • text - Text processing (to_uppercase, to_lowercase, trim)

How It Works

  1. Always Available: Default functions are always included in the tools schema sent to the AI
  2. Smart Splitting: If the schema exceeds 8000 characters, it's automatically split into multiple system messages
  3. UI Hidden: Functions don't appear in the UI dropdown to keep it clean
  4. Full Access: AI can use all default functions in workflows and processing

Making Functions Visible

If you want to make specific default functions visible in the UI, you can create custom wrapper functions:

import { AIFunction, registerFunctionIntoAI } from "@sashimo/lib"

// Create a visible wrapper for a hidden function
const VisibleAddFunction = new AIFunction(
    "add_numbers",
    "add two or more numbers together"
)
    .args({
        name: "numbers",
        description: "array of numbers to add together",
        type: "array",
        required: true,
    })
    .returns({
        name: "result",
        description: "the sum of the numbers",
        type: "number",
    })
    .implement(async (numbers: number[]) => {
        // Call the hidden function
        const result = await callFunctionFromRegistry("add", numbers)
        return result.result
    })

registerFunctionIntoAI("add_numbers", VisibleAddFunction)