Skip to content

Commit

Permalink
Merge pull request #8 from yashpokar/re-architect
Browse files Browse the repository at this point in the history
Re Architect - low level web socket ❌ GraphQL subscriptions ✅
  • Loading branch information
yashpokar authored Apr 22, 2024
2 parents 7a4b410 + d0cde48 commit 024a46f
Show file tree
Hide file tree
Showing 150 changed files with 15,670 additions and 6,482 deletions.
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ indent_style = space
indent_size = 2
trim_trailing_whitespace = true

[*.yaml]
insert_final_newline = false

[*.md]
trim_trailing_whitespace = false

Expand Down
9 changes: 8 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
API_PORT=6287
API_URL=http://localhost:6287
API_WS_URL=ws://localhost:6287
API_DEBUG_TOOLS=true

SANDBOX_IMAGE_NAME=manasai-sandbox
SANDBOX_IMAGE_TAG=latest

OPENAI_API_KEY=
OPENAI_API_ORG=

UI_PORT=6288
UI_HOST=http://localhost:6288
UI_WEB_SOCKET_URL=ws://localhost:6287/ws
2 changes: 0 additions & 2 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ jobs:
run: |
npm install -g pnpm
pnpm install
pnpm add @manasai/common --filter ui --workspace
pnpm add @manasai/common --filter api --workspace
- name: 🧹 Lint
run: pnpm lint
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile.sandbox
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ RUN apt-get update && apt-get upgrade -y && apt-get install -y \
software-properties-common \
&& rm -rf /var/lib/apt/lists/*

RUN useradd -m manasai && echo "manasai:manasai" | chpasswd && adduser manasai sudo \
&& echo "manasai ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/manasai
RUN useradd -m ubuntu && echo "ubuntu:ubuntu" | chpasswd && adduser ubuntu sudo \
&& echo "ubuntu ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/ubuntu

USER manasai
USER ubuntu

CMD ["/bin/bash"]
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,26 @@ To run ManasAI, execute the following command:
```shell
make run
```

## Roadmap

- [x] Multi project
- [ ] Multi model
- [ ] Multi agent
- [x] Dedeicated sandbox to test the code in isolation
- [x] Terminal tool to display the commands (ran by the agent) and the output
- [ ] Allow the user to run the commands
- [ ] Dedicated web browser to test web based code in isolation
- [x] Browser tool to display the output
- [ ] Multiple driver support (Chrome, Firefox, Safari, etc.)
- [ ] Dedicated mobile amulator to test mobile based code in isolation
- [ ] Mobile tool to display the output
- [ ] Dedicated desktop amulator to test desktop based code in isolation
- [ ] Desktop tool to display the output
- [ ] Code editor
- [ ] Display the code written by the agent
- [ ] Allow the user to edit the code

## Contributing

We welcome contributions to ManasAI! Please refer to the [Contributing Guidelines](docs/CONTRIBUTING.md) for more information on how to get involved.
48 changes: 29 additions & 19 deletions apps/api/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
const fs = require('fs')
const path = require('path')

module.exports = {
env: {
browser: true,
es2021: true
},
ignorePatterns: ['**/dist/**', '**/node_modules/**', '.eslintrc.*'],
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
overrides: [
{
env: {
node: true
},
files: ['.eslintrc.{js,cjs}'],
parserOptions: {
sourceType: 'script'
}
}
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module'
},
rules: {}
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended'
],
root: true,
env: {
node: true,
jest: true
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'prettier/prettier': [
'error',
JSON.parse(
fs.readFileSync(path.resolve(__dirname, '../..', '.prettierrc'), 'utf8')
)
]
}
}
74 changes: 68 additions & 6 deletions apps/api/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,73 @@
# API
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="200" alt="Nest Logo" /></a>
</p>

Express-based API for the ManasAI.
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
[circleci-url]: https://circleci.com/gh/nestjs/nest

## Development
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
<p align="center">
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->

To start the development server, run:
## Description

```shell
pnpm dev
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.

## Installation

```bash
$ pnpm install
```

## Running the app

```bash
# development
$ pnpm run start

# watch mode
$ pnpm run start:dev

# production mode
$ pnpm run start:prod
```

## Test

```bash
# unit tests
$ pnpm run test

# e2e tests
$ pnpm run test:e2e

# test coverage
$ pnpm run test:cov
```

## Support

Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).

## Stay in touch

- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
- Website - [https://nestjs.com](https://nestjs.com/)
- Twitter - [@nestframework](https://twitter.com/nestframework)

## License

Nest is [MIT licensed](LICENSE).
39 changes: 39 additions & 0 deletions apps/api/libs/core/src/agents/agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import * as path from 'path'
import * as fs from 'fs'
import {
ChatPromptTemplate,
MessagesPlaceholder,
ParamsFromFString
} from '@langchain/core/prompts'
import { Logger } from '@nestjs/common'
import * as yaml from 'js-yaml'
import { Prompt } from '../types/agent'

abstract class Agent<State> {
protected readonly logger = new Logger(this.constructor.name)

protected getPromptTemplate(
filename: string
): ChatPromptTemplate<ParamsFromFString<string>, any> {
const promptContent = fs.readFileSync(
path.resolve(__dirname, `../libs/core/src/prompts/${filename}.yaml`),
'utf8'
)

const data = yaml.load(promptContent) as Prompt

return ChatPromptTemplate.fromMessages(
data.template.map(prompt => {
if ('placeholder' in prompt) {
return new MessagesPlaceholder(prompt.placeholder)
}

return [prompt.author, prompt.prompt]
})
)
}

abstract act(state: State): Promise<Partial<State>>
}

export default Agent
70 changes: 70 additions & 0 deletions apps/api/libs/core/src/agents/openai.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { AgentExecutor, createOpenAIToolsAgent } from 'langchain/agents'
import { Injectable } from '@nestjs/common'
import { DynamicStructuredTool } from '@langchain/core/tools'
import Agent from './agent'
import { PlanExecuteState } from '../types/agent'
import { ChatOpenAI } from '@langchain/openai'
import EditorTool from '../tools/editor'
import TerminalTool from '../tools/terminal'
import BrowserTool from '../tools/browser'
import SearchTool from '../tools/search'
import { toStructuredTools } from '../tools/tool'
import AgentEventsHandler from '../handlers/agent-events-handler'

@Injectable()
class OpenAIAgent extends Agent<PlanExecuteState> {
private tools: DynamicStructuredTool[]

constructor(
readonly editor: EditorTool,
readonly browser: BrowserTool,
readonly terminal: TerminalTool,
readonly search: SearchTool,

private readonly eventsHandler: AgentEventsHandler
) {
super()

this.tools = toStructuredTools([editor, browser, terminal, search])
}

async act({
input,
projectId
}: PlanExecuteState): Promise<Partial<PlanExecuteState>> {
const prompt = this.getPromptTemplate('agent')

const llm = new ChatOpenAI({
modelName: 'gpt-4-turbo-preview'
})

const { tools } = this

const agent = await createOpenAIToolsAgent({
llm,
tools,
prompt
})

const executor = AgentExecutor.fromAgentAndTools({
agent,
tools
})

const response = await executor.invoke(
{
input,
projectId
},
{
callbacks: [this.eventsHandler]
}
)

return {
pastSteps: [input, response.output]
}
}
}

export default OpenAIAgent
42 changes: 42 additions & 0 deletions apps/api/libs/core/src/agents/planner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Injectable } from '@nestjs/common'
import { JsonOutputFunctionsParser } from 'langchain/output_parsers'
import { ChatOpenAI } from '@langchain/openai'
import Agent from './agent'
import { AgentOutput, PlanExecuteState } from '../types/agent'
import planFunction from '../functions/plan'
import { PREVIEW_EVENT, TOPIC_PLAN } from '../constants'
import { EventEmitter2 } from '@nestjs/event-emitter'

@Injectable()
class PlannerAgent extends Agent<PlanExecuteState> {
constructor(private readonly eventEmitter: EventEmitter2) {
super()
}

async act(state: PlanExecuteState): Promise<Partial<PlanExecuteState>> {
this.logger.debug(`Acting the given state: `, state)

const llm = new ChatOpenAI({
modelName: 'gpt-4-turbo-preview'
}).bind({
functions: [planFunction],
function_call: planFunction
})

const planner = this.getPromptTemplate('planner')
.pipe(llm)
.pipe(new JsonOutputFunctionsParser({ argsOnly: true }))

const plan: AgentOutput = await planner.invoke({
objective: state.input
})

this.eventEmitter.emit(PREVIEW_EVENT, TOPIC_PLAN, {
onPlanPreview: plan
})

return { plan: plan.steps }
}
}

export default PlannerAgent
Loading

0 comments on commit 024a46f

Please sign in to comment.