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 🙏

© 2024 – Pkg Stats / Ryan Hefner

ts-ai-agent

v0.1.7

Published

A TypeScript library for constructing and utilizing AI agents with OpenAI's API, enabling the chaining of multiple requests and responses using RxJS, and generating runtime type information for the 'function_call' feature.

Downloads

19

Readme

AI Agent

AI Agent is a TypeScript library designed to leverage OpenAI's API, enabling developers to create and manage AI agents. With this library, you can seamlessly chain multiple requests and responses into a single API call. The most powerful feature of AI Agent is its ability to generate runtime type information (RTTI) for the 'function_call' feature of OpenAI's API, all thanks to TypeScript's RTTI.

NPM | Github

The library heavily relies on the RxJS library, allowing users to take advantage of its powerful features such as observables and operators to chain and manage responses from multiple agents, creating complex workflows and pipelines with ease.

Function calling

AI Agent introduces an innovative approach to working with API calls. You can define functions for the AI models (gpt-3.5-turbo-0613 and gpt-4-0613) and have the model intelligently generate a JSON object containing the required arguments for those functions. You can then utilize the generated JSON to invoke those functions in your codebase.

The beauty of this approach is that these models have been fine-tuned to intelligently detect when a function should be called based on the input and respond with JSON that matches the function signature. This opens up new possibilities for creating more dynamic and responsive applications with AI at their core.

However, with the increased potential also come risks. As the models are capable of making decisions that can have real-world impacts (such as sending an email, posting something online, or making a purchase), we strongly recommend implementing user confirmation flows before carrying out such operations.

The AI Agent library has been created to make it easier and more efficient for developers to utilize these new features, with TypeScript's RTTI being central to this. The generated RTTI enables developers to create more robust and reliable code when working with the 'function_call' feature.

Explore AI Agent and see how it can enhance your OpenAI API experience.

Setup

Prerequisites

  • TypeScript 4.8 - 5.1
  • Node.js v14 or newer

Installation

Install the necessary packages:

npm install typescript-rtti reflect-metadata rxjs ts-ai-agent
npm install ttypescript -D

Set up tsconfig.json to use the transformer:

// tsconfig.json
"compilerOptions": {
    "plugins": [{ "transform": "typescript-rtti/dist/transformer" }]
}

Update your build script in package.json to use ttsc instead of tsc:

// package.json
{
    "scripts": {
        "build": "ttsc -b"
    }
}

Lastly, import reflect-metadata and Agent at the start of your application:

import "reflect-metadata";
import { Agent } from "ts-ai-agent";

ts-node

You can also use ts-node, just pass -C ttypescript to make sure ts-node uses typescript compiler which respects compiler transforms.

Usage

Here are examples showcasing the AI Agent's capabilities.

Simple example:

This simple example involves an AI agent tasked with generating and explaining a sentence about the moon and bacteria. It also includes error handling for each step.

import "reflect-metadata";
import { map, mergeMap, toArray, lastValueFrom, catchError, tap } from "rxjs";
import { OpenAIApi, Configuration } from "openai";
import { Agent, AgentPrompt, AgentOptions, AgentInterruptException, AgentRequestBuilder } from "./agent";

class TaskAgent extends Agent {
  static PROMPT:string = 'Agent: Perform a given task';
  constructor(api: OpenAIApi, options: AgentOptions = AgentOptions.DEFAULT) {
    super(api, AgentPrompt.fromString(TaskAgent.PROMPT), options);
  }
}

async function test() {
  const api = new OpenAIApi(new Configuration({
    apiKey: process.env.OPENAI_API_KEY,
  }));
  const agent = new TaskAgent(api, AgentOptions.DEFAULT);
  try {
    const pipe = AgentRequestBuilder.create<string>(agent).n(2).request('Write a sentence about the moon and bacteria')
      .pipe(
        tap(res => console.log(`Step: 1: ${res.value}`)),
        mergeMap(res => AgentRequestBuilder.create<string>(agent).request(`Explain what it is about?: ${res.value}`)),
        catchError(error => {
          console.error(`Error: ${error}`);
          throw error;
        }),
        tap(res => console.log(`Step: 2: ${res.value}`)),
        mergeMap(res => AgentRequestBuilder.create<string>(agent).request(`Make a conclusion from: ${res.value}`)),
        catchError(error => {
          console.error(`Error: ${error}`);
          throw error;
        }),
        tap(res => console.log(`Step: 3: ${res.value}`)),
        map(res => res.value),
        toArray()
      );
    
    const res = await lastValueFrom(pipe);
    console.log(JSON.stringify(res, null, 2));

    return res;
  } catch (error) {
    console.error(`Error occurred in pipeline: ${error}`);
    // Here you can handle how your function reacts to an error in the pipeline.
    // You could decide to return a default value, re-throw the error, etc.
    throw error;
  }
}

Example with a function call

In this example, the AI agent is tasked with selecting truthful records from a given list.

import "reflect-metadata";
import { OpenAIApi, Configuration } from "openai";
import { Agent, AgentPrompt, AgentOptions, AgentInterruptException, AgentRequestBuilder } from "../src";
import {  map, lastValueFrom } from "rxjs";

class FunctionAgent extends Agent {
    static PROMPT:string = `Agent: You are presented with a list of records. Your task is to analyze each record and select the IDs that correspond to records that are truthful and make logical sense.`;
    constructor(api: OpenAIApi, options: AgentOptions = AgentOptions.DEFAULT) {
        super(api, AgentPrompt.fromString(FunctionAgent.PROMPT), options);
        this.registerFunction(this.select_records, "select_records", "Call this function to select record IDs that are truthful");
        this.registerFunction(this.async_select_records, "async_select_records", "Call this function to select record IDs that are truthful");
    }

    //AI function
    //Arguments ids: number[] - will generate JSON schema for the input automatically
    select_records(truthful_ids: number[], untruthful_ids:number[]): number[] {
      //validate result
      for (const id of truthful_ids) {
        if (id < 0 || id > 4) {
            throw new AgentInterruptException(`Rejected ${id}`);
        }
      }
      for (const id of untruthful_ids) {
        if (id < 0 || id > 4) {
            throw new AgentInterruptException(`Rejected ${id}`);
        }
      }
      //make sure that they are not intersecting
      for (const id of truthful_ids) {
        if (untruthful_ids.includes(id)) {
            throw new AgentInterruptException(`Rejected ${id}`);
        }
      }
      return truthful_ids;
    }

    //AI function
    //You can use async functions as well
    async async_select_records(truthful: number[], untruthful:number[]): Promise<number[]> {
        return this.select_records(truthful, untruthful);
    }
}

async function test() {
  const api = new OpenAIApi(new Configuration({
      apiKey: process.env.OPENAI_API_KEY,
  }));
  const agent = new FunctionAgent(api, AgentOptions.DEFAULT);
  const sample_records = [
      {id: 1, text: 'The moon is made of cheese'},
      {id: 2, text: 'The moon is made of rock'},
      {id: 3, text: 'The moon is made of bacteria'},
      {id: 4, text: 'The moon orbits the earth'},
  ]
  try {
      const pipe = AgentRequestBuilder.create<number[]>(agent).function('async_select_records')
                                      .request(sample_records)
                                      .pipe(map(res => res.value))
                                      .pipe(map(res => sample_records.filter(record => res.includes(record.id)).map(s => s.text)))
      const res = await lastValueFrom(pipe);
      console.log(JSON.stringify(res, null, 2));
      return res;
  } catch (error) {
      console.error(`Error occurred in pipeline: ${error}`);
      // Here you can handle how your function reacts to an error in the pipeline.
      // You could decide to return a default value, re-throw the error, etc.
      throw error;
  }
}