Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing bundle compilation #10

Merged
merged 5 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions .github/workflows/pr-validation-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ jobs:
build-and-test:
runs-on: ubuntu-latest
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
OPENAI_API_KEY: "fake-api-key-so-we-can-use-ci-in-forked-repositories"
ANTHROPIC_API_KEY: "fake-api-key-so-we-can-use-ci-in-forked-repositories"
GOOGLE_API_KEY: "fake-api-key-so-we-can-use-ci-in-forked-repositories"
MISTRAL_API_KEY: "fake-api-key-so-we-can-use-ci-in-forked-repositories"
steps:
- name: Checkout code
uses: actions/checkout@v2
Expand All @@ -29,9 +29,3 @@ jobs:

- name: Run integration tests
run: npm run test:integration

- name: Build production version
run: npm run build

- name: Run e2e tests
run: npm run test:e2e
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ yarn-error.log*
.DS_Store
*.pem

*storybook.log
*storybook.log
_todo.md
80 changes: 33 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,59 @@
![AgenticJS Logo](https://www.agenticjs.com/logo.svg)

AgenticJS is a JavaScript-native framework for building multi-agent AI systems.

[![Star on GitHub](https://img.shields.io/github/stars/AI-Champions/agenticjs.svg?style=social)](https://github.com/AI-Champions/AgenticJS)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/AI-Champions/agenticjs/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/agenticjs.svg?style=flat)](https://www.npmjs.com/package/agenticjs)
[![stability-alpha](https://img.shields.io/badge/stability-alpha-f4d03f.svg)](https://github.com/mkenney/software-guides/blob/master/STABILITY-BADGES.md#alpha)
[![Tests](https://github.com/AI-Champions/AgenticJS/actions/workflows/stable-main-check-workflow.yml/badge.svg)](https://github.com/AI-Champions/AgenticJS/actions/workflows/stable-main-check-workflow.yml)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/AI-Champions/AgenticJS/pulls)


**Powered by Claude**

AgenticJS utilizes [Claude](https://www.anthropic.com/api), the cutting-edge LLM from [Anthropic](https://www.anthropic.com/), across all examples. This integration allows AgenticJS to offer advanced AI agent functionalities and decision-making capabilities, making every interaction smarter. Discover how we use Claude to bring innovative AI solutions to life in our [interactive playground](https://agenticjs.com).
# AgenticJS
AgenticJS is a JavaScript-native framework for building multi-agent AI systems.

## Try It Out

[Explore the Playground](https://agenticjs.com)
[Explore the Playground](https://agenticjs.com) — *it's like Trello or Asana, but for AI Agents and humans.*

## Why AgenticJS?

In a landscape dominated by Python frameworks, JavaScript developers have often found themselves at a disadvantage. AgenticJS is here to change that by providing a robust, easy-to-use AI multi-agent framework tailored for the JavaScript ecosystem.
There are about 20 million JavaScript developers worldwide, yet most AI frameworks are originally written in Python. Others are mere adaptations for JavaScript.

This puts all of us **JavaScript developers at a disadvantage in the AI race**. But not anymore...

AgenticJS changes the game by aiming to offer a robust, easy-to-use AI multi-agent framework designed specifically for the JavaScript ecosystem.

```js
const writtenBy = `Another JS Dev Who Doesn't Want to Learn Python to do meaningful AI Stuff.`;
console.log(writtenBy);
```


### Key Features

- **Role-Based Agent Design:** Design agents with specific roles and goals.
- **Autonomous Inter-Agent Delegation:** Enable agents to delegate tasks autonomously.
- **Flexible Task Management:** Define and assign tasks dynamically to agents.
- **Redux-Inspired Architecture:** This architecture offers a unified approach to managing the states of all AI agents. As a big plus, it integrates effortlessly into your React applications.
- **Real-Time Visualizer:** Built-in UI visualizer for development and debugging.
- **Browser and Server Compatibility:** Works seamlessly across client and server environments.
- **Multi-Model Support:** Integrates with various AI models including OpenAI, Gemini, Claude, and Mistral, enhancing versatility and adaptability.

## Getting Started

Install AgenticJS via npm:
### Install AgenticJS via npm:

```bash
npm install agenticjs --save
```

Set your LLM API keys as environment variables:
```bash

# For Anthropic
export ANTHROPIC_API_KEY='your-api-key'
### Import AgenticJS in your JavaScript file:

# For OpenAI
export OPENAI_API_KEY='your-openai-api-key'
```js
// Using ES6 import syntax for NextJS, React, etc.
import { Agent, Task, Team } from 'agenticjs';
```

Import AgenticJS in your JavaScript file:

```js
import { Agent, Task, Team } from 'agenticjs';
// Using CommonJS syntax for NodeJS
const { Agent, Task, Team } = require("agenticjs");
```

## Example Usage
Expand All @@ -60,6 +63,9 @@ Define agents, tasks, and a team to manage them:
```js
import { Agent, Task, Team } from 'agenticjs';

// NodeJS
// const { Agent, Task, Team } = require('agenticjs');

// ╔══════════════════════════════════════════════════════╗
// ║ How to Use AgenticJS: ║
// ║ 1. Define your Agents with specific roles and goals ║
Expand All @@ -79,44 +85,23 @@ const profileAnalyst = new Agent({
role: 'Profile Analyst',
goal: 'Extract structured information from conversational user input.',
background: 'Data Processor',
tools: [], // Tools are omitted for now
llmConfig: {
provider: "anthropic", // or "openai"
model: "claude-3-5-sonnet-20240620",
temperature: 0.9,
maxTokens: 1024,
anthropicApiUrl: "https://www.agenticjs.com/proxy/anthropic",
}
tools: [], // Tools are omitted for now
});

const formatter = new Agent({
name: 'Formy',
role: 'Formatter',
goal: 'Format structured information into a professional resume.',
background: 'Document Formatter',
tools: [],
llmConfig: {
provider: "anthropic", // or "openai"
model: "claude-3-5-sonnet-20240620",
temperature: 0.9,
maxTokens: 1024,
anthropicApiUrl: "https://www.agenticjs.com/proxy/anthropic",
}
tools: [],
});

const reviewer = new Agent({
name: 'Revy',
role: 'Reviewer',
goal: 'Review and polish the final resume.',
background: 'Quality Assurance Specialist',
tools: [],
llmConfig: {
provider: "anthropic", // or "openai"
model: "claude-3-5-sonnet-20240620",
temperature: 0.9,
maxTokens: 1024,
anthropicApiUrl: "https://www.agenticjs.com/proxy/anthropic",
}
tools: [],
});

// ──── Tasks ─────────────────────────────────────────────
Expand Down Expand Up @@ -156,14 +141,15 @@ const team = new Team({
agents: [profileAnalyst, formatter, reviewer],
tasks: [processingTask, formattingTask, reviewTask],
inputs: { aboutMe: 'My name is Will, I have been a Javascript Developer for 3 years. I know React, NextJS, and REDUX. My latest job was as a Junior Developer at Disney creating UIs for the main landing page.' }, // Initial input for the first task
env: {OPENAI_API_KEY: 'your-open-ai-api-key'} // Environment variables for the team
});

// Note: Avoid hardcoding API keys; retrieve them from environment variables instead.

// ──── Listening to Changes────────────────────────────────────────────
//
// Listening to changes in the team's state is crucial for dynamic updates.
// Yup...AgenticJS utilizes a store similar to Redux for state management.
//
// You can subscribe to specific fields or any field on the store.
//──────────────────────────────────────────────────────────────────────

const unsubscribe = team.subscribeToChanges((updatedFields) => {
Expand All @@ -185,7 +171,7 @@ console.log("Final Output:", result);

### Compatibility

AgenticJS is compatible with major front-end frameworks like React, Vue, Angular, and NextJS, making it a versatile choice for developers.
AgenticJS aims to be compatible with major front-end frameworks like React, Vue, Angular, and NextJS, making it a versatile choice for developers. The JavaScript ecosystem is a "bit complex...". If you have any problems, please tell us and we'll help you fix them.

### Community and Support

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"build": "npx rollup -c",
"build:test": "TEST_ENV=mocked-llm-apis npx rollup -c",
"dev": "NODE_ENV=development npx rollup -c -w",
"test": "npm run build:test && test:integration",
"test": "npm run build:test && npm run test:integration",
"test:watch": "TEST_ENV=mocked-llm-apis jest --testPathPattern='tests/e2e' --watch",
"test:debug": "TEST_ENV=mocked-llm-apis node --inspect-brk node_modules/.bin/jest --runInBand --verbose",
"test:prod": "npm run build && jest",
Expand Down
84 changes: 38 additions & 46 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,47 @@ import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import { terser } from 'rollup-plugin-terser';
import sourcemaps from 'rollup-plugin-sourcemaps';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';

// Determine if we are in development mode based on the NODE_ENV environment variable
const isDevelopment = process.env.NODE_ENV === 'development';
const isTest = process.env.TEST_ENV === 'mocked-llm-apis';

export default {
input: 'src/index.js',
output: [
{
file: 'dist/bundle.cjs.js',
format: 'cjs',
function generateConfig(format) {

const isESM = format === 'es';
const external = isESM ? ['react', 'react-dom', 'uuid'] : ['uuid'];
return {
input: 'src/index.js',
output: {
file: `dist/bundle.${format === 'cjs' ? 'cjs' : format === 'es' ? 'esm' : 'umd'}.js`,
format: format,
inlineDynamicImports: true,
sourcemap: true // Enable sourcemap generation for CommonJS
sourcemap: true,
name: format === 'umd' ? 'AgenticJS' : undefined
},
{
file: 'dist/bundle.esm.js',
format: 'es',
inlineDynamicImports: true,
sourcemap: true // Enable sourcemap generation for ES Module
},
{
file: 'dist/bundle.umd.js',
format: 'umd',
inlineDynamicImports: true,
name: 'AgenticJS',
sourcemap: true // Enable sourcemap generation for UMD
}
],
plugins: [
peerDepsExternal(),
resolve({
browser: true, // Set to false to prioritize Node.js modules
preferBuiltins: false, // Ensure Node.js built-ins are used
mainFields: ['browser', 'module', 'main']
}),
commonjs(),
// Include the replace plugin only if isTest is true
...(isTest ? [replace({
'shims.fetch': `(...args) => { return global.fetch(...args); };\n`, // Include newline
preventAssignment: true
})] : []),
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**'
}),
// Only include terser (minification) if not in development mode
...(!isDevelopment ? [terser()] : []),
sourcemaps(), // Ensure sourcemaps from dependencies are handled
],
external: ['react', 'react-dom', 'uuid'],
};
external: external,
plugins: [
resolve({
browser: true,
preferBuiltins: false,
mainFields: ['browser', 'module', 'main']
}),
commonjs(),
...(isTest ? [replace({
'shims.fetch': `(...args) => { return global.fetch(...args); };\n`,
preventAssignment: true
})] : []),
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**'
}),
...(!isDevelopment ? [terser()] : []),
sourcemaps(),
]
};
}

export default [
generateConfig('cjs'),
generateConfig('es'),
generateConfig('umd')
];
42 changes: 18 additions & 24 deletions src/agents.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,17 @@ function interpolateDescription(description, inputs) {
return result;
}

function getApiKey(llmConfig, provider) {
function getApiKey(llmConfig, provider, env) {
if (llmConfig?.apiKey) return llmConfig.apiKey;

let env = {};

if (typeof process !== 'undefined' && process.env) {
env = process.env;
} else if (typeof window !== 'undefined') {
env = window?.process?.env || import.meta.env || {};
}

const apiKeys = {
anthropic: env.ANTHROPIC_API_KEY || env.NEXT_PUBLIC_ANTHROPIC_API_KEY || env.VITE_ANTHROPIC_API_KEY,
google: env.GOOGLE_API_KEY || env.NEXT_PUBLIC_GOOGLE_API_KEY || env.VITE_GOOGLE_API_KEY,
mistral: env.MISTRAL_API_KEY || env.NEXT_PUBLIC_MISTRAL_API_KEY || env.VITE_MISTRAL_API_KEY,
openai: env.OPENAI_API_KEY || env.NEXT_PUBLIC_OPENAI_API_KEY || env.VITE_OPENAI_API_KEY,
anthropic: env.ANTHROPIC_API_KEY,
google: env.GOOGLE_API_KEY,
mistral: env.MISTRAL_API_KEY,
openai: env.OPENAI_API_KEY
};

return apiKeys[provider] || apiKeys.openai || (() => { throw new Error('API key is missing. Please provide it through llmConfig or set the appropriate environment variables.'); })();
return apiKeys[provider] ||
(() => { throw new Error('API key is missing. Please provide it through the Agent llmConfig or throught the team env variable. E.g: new Team ({name: "My Team", env: {OPENAI_API_KEY: "your-api-key"}})') })();
}


Expand All @@ -65,22 +57,21 @@ class BaseAgent {
this.goal = goal;
this.background = background;
this.tools = tools;

const defaultConfig = {
model: "gpt-3.5-turbo-0125",
apiKey: getApiKey(llmConfig, llmConfig.provider || 'openai'),
apiKey: null,
};
this.llmConfig = { ...defaultConfig, ...llmConfig };

if (!this.llmConfig.apiKey) {
throw new Error('API key is missing. Please provide it through llmConfig or set the appropriate environment variables.');
}
}

async initAgent() {
throw new Error("initAgent must be implemented by subclasses.");
}

setEnv(env) {
this.env = env;
}

executeTask(task) {
throw new Error("executeTask must be implemented by subclasses.");
}
Expand All @@ -95,20 +86,20 @@ class BasicChatAgent extends BaseAgent {
this.llmConfig = { ...defaultConfig, ...config.llmConfig };
}

async initAgent() {
async initAgent() {
const providers = {
anthropic: ChatAnthropic,
google: ChatGoogleGenerativeAI,
mistral: ChatMistralAI,
openai: ChatOpenAI,
};

const provider = this.llmConfig.provider;
const provider = this.llmConfig.provider || 'openai';
const ChatClass = providers[provider] || providers.openai;

this.llmInstance = new ChatClass({
...this.llmConfig,
apiKey: getApiKey(this.llmConfig, provider),
apiKey: getApiKey(this.llmConfig, provider, this.env),
});
}

Expand Down Expand Up @@ -158,6 +149,9 @@ class ReActAgent extends BaseAgent {
}

async initAgent() {
if (!this.llmConfig.apiKey) {
throw new Error('API key is missing. Please provide it through the Agent llmConfig or throught the team env variable. E.g: new Team ({name: "My Team", env: {OPENAI_API_KEY: "your-api-key"}})');
}
this.llmInstance = new OpenAI({
...this.llmConfig,
apiKey: getApiKey(this.llmConfig, 'openai'),
Expand Down
Loading
Loading