├── requirements.txt ├── ag2studio ├── web │ └── __init__.py ├── database │ ├── migrations │ │ ├── __init__.py │ │ ├── README │ │ ├── script.py.mako │ │ └── env.py │ ├── __init__.py │ └── alembic.ini ├── utils │ └── __init__.py ├── __init__.py ├── version.py ├── cli.py ├── chatmanager.py ├── datamodel.py └── workflowmanager.py ├── frontend ├── .env.default ├── src │ ├── images │ │ └── icon.png │ ├── app │ │ ├── providers.tsx │ │ ├── build │ │ │ └── page.tsx │ │ ├── page.tsx │ │ ├── gallery │ │ │ └── page.tsx │ │ ├── layout.tsx │ │ ├── not-found.tsx │ │ └── client-layout.tsx │ ├── hooks │ │ ├── store.tsx │ │ └── provider.tsx │ ├── components │ │ ├── footer.tsx │ │ ├── layout.tsx │ │ ├── views │ │ │ ├── playground │ │ │ │ ├── sidebar.tsx │ │ │ │ ├── ra.tsx │ │ │ │ ├── utils │ │ │ │ │ └── selectors.tsx │ │ │ │ └── metadata.tsx │ │ │ ├── builder │ │ │ │ ├── build.tsx │ │ │ │ ├── utils │ │ │ │ │ ├── workflowconfig.tsx │ │ │ │ │ └── modelconfig.tsx │ │ │ │ ├── agents.tsx │ │ │ │ ├── workflow.tsx │ │ │ │ └── models.tsx │ │ │ └── gallery │ │ │ │ └── gallery.tsx │ │ ├── types.ts │ │ └── header.tsx │ └── styles │ │ └── global.css ├── .gitignore ├── postcss.config.js ├── next-env.d.ts ├── next.config.js ├── tsconfig.json ├── static │ └── images │ │ └── svgs │ │ ├── ag2logo.svg │ │ └── welcome.svg ├── LICENSE ├── tailwind.config.js ├── package.json └── README.md ├── docs ├── readme_stockprices.png └── faq.md ├── MANIFEST.in ├── .gitignore ├── Dockerfile ├── .vscode └── launch.json ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── setup.py ├── notebooks ├── agent_spec.json └── groupchat_spec.json ├── pyproject.toml ├── PyPiREADME.md ├── README.md └── LICENSE /requirements.txt: -------------------------------------------------------------------------------- 1 | . 2 | -------------------------------------------------------------------------------- /ag2studio/web/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ag2studio/database/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/.env.default: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_API_URL=/api -------------------------------------------------------------------------------- /ag2studio/database/migrations/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. 2 | -------------------------------------------------------------------------------- /docs/readme_stockprices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ag2ai/ag2studio/HEAD/docs/readme_stockprices.png -------------------------------------------------------------------------------- /frontend/src/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ag2ai/ag2studio/HEAD/frontend/src/images/icon.png -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .cache/ 3 | public/ 4 | 5 | .env.development 6 | .env.production 7 | 8 | yarn.lock 9 | -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include ag2studio/web/ui * 2 | recursive-include ag2studio/web/database.sqlite 3 | recursive-exclude notebooks * 4 | 5 | recursive-exclude frontend * 6 | recursive-exclude docs * 7 | recursive-exclude tests * 8 | -------------------------------------------------------------------------------- /frontend/src/app/providers.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { AppProvider } from '../hooks/provider' 4 | 5 | export function Providers({ children }: { children: React.ReactNode }) { 6 | return {children} 7 | } 8 | -------------------------------------------------------------------------------- /frontend/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /ag2studio/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Portions derived from https://github.com/microsoft/autogen are under the MIT License. 6 | # SPDX-License-Identifier: MIT 7 | from .utils import * 8 | -------------------------------------------------------------------------------- /frontend/src/app/build/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import BuildView from '../../components/views/builder/build' 4 | 5 | export default function BuildPage() { 6 | return ( 7 |
8 | 9 |
10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Python virtualenv 2 | .venv* 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *.pyc 8 | *$py.class 9 | 10 | *.egg-info/ 11 | dist/ 12 | 13 | # Environments 14 | test_env/ 15 | /ag2studio/web/ui 16 | /venv 17 | /frontend/.next 18 | /frontend/out 19 | .env 20 | /frontend/out 21 | -------------------------------------------------------------------------------- /ag2studio/database/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Portions derived from https://github.com/microsoft/autogen are under the MIT License. 6 | # SPDX-License-Identifier: MIT 7 | # from .dbmanager import * 8 | from .dbmanager import * 9 | from .utils import * 10 | -------------------------------------------------------------------------------- /ag2studio/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Portions derived from https://github.com/microsoft/autogen are under the MIT License. 6 | # SPDX-License-Identifier: MIT 7 | from .chatmanager import * 8 | from .datamodel import * 9 | from .version import __version__ 10 | from .workflowmanager import * 11 | -------------------------------------------------------------------------------- /ag2studio/version.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025, Owners of https://github.com/ag2ai 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Portions derived from https://github.com/microsoft/autogen are under the MIT License. 6 | # SPDX-License-Identifier: MIT 7 | VERSION = "0.0.1-rc5" 8 | __version__ = VERSION 9 | APP_NAME = "ag2studio" 10 | AUTHOR = "Chi Wang & Qingyun Wu" 11 | LICENSE = "Apache-2.0" 12 | -------------------------------------------------------------------------------- /frontend/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import dynamic from 'next/dynamic' 4 | 5 | const RAView = dynamic(() => import('../components/views/playground/ra'), { 6 | ssr: false, 7 | loading: () =>
Loading...
8 | }) 9 | 10 | export default function Home() { 11 | return ( 12 |
13 | 14 |
15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10 2 | 3 | WORKDIR /code 4 | 5 | RUN pip install -U gunicorn ag2studio 6 | 7 | RUN useradd -m -u 1000 user 8 | USER user 9 | ENV HOME=/home/user \ 10 | PATH=/home/user/.local/bin:$PATH \ 11 | AG2STUDIO_APPDIR=/home/user/app 12 | 13 | WORKDIR $HOME/app 14 | 15 | COPY --chown=user . $HOME/app 16 | 17 | CMD gunicorn -w $((2 * $(getconf _NPROCESSORS_ONLN) + 1)) --timeout 12600 -k uvicorn.workers.UvicornWorker ag2studio.web.app:app --bind "0.0.0.0:8081" 18 | -------------------------------------------------------------------------------- /frontend/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | trailingSlash: true, 5 | output: 'export', 6 | images: { 7 | unoptimized: true, 8 | }, 9 | // Maintaining similar prefix path behavior as Gatsby 10 | basePath: process.env.PREFIX_PATH_VALUE || '', 11 | transpilePackages: ['react-syntax-highlighter'], 12 | webpack: (config) => { 13 | config.resolve.fallback = { fs: false }; 14 | return config; 15 | } 16 | } 17 | 18 | module.exports = nextConfig -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "AG2Studio Debug", 6 | "type": "debugpy", 7 | "request": "launch", 8 | "module": "uvicorn", 9 | "args": [ 10 | "ag2studio.web.app:app", 11 | "--host", 12 | "127.0.0.1", 13 | "--port", 14 | "8081", 15 | "--reload" 16 | ], 17 | "justMyCode": false, 18 | "env": { 19 | "PYTHONPATH": "${workspaceFolder}", 20 | "AG2STUDIO_API_DOCS": "false" 21 | } 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /frontend/src/app/gallery/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Suspense } from 'react' 4 | import { useSearchParams } from 'next/navigation' 5 | import GalleryView from '../../components/views/gallery/gallery' 6 | import { BounceLoader } from '../../components/atoms' 7 | 8 | export default function GalleryPage() { 9 | return ( 10 | }> 11 | 12 | 13 | ) 14 | } 15 | 16 | function GalleryContent() { 17 | const searchParams = useSearchParams() 18 | 19 | return ( 20 |
21 | 22 |
23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import '../styles/global.css' 2 | import 'antd/dist/reset.css' 3 | import { Metadata } from 'next' 4 | import ClientLayout from './client-layout' 5 | import { AppProvider } from '../hooks/provider' 6 | 7 | export const metadata: Metadata = { 8 | title: 'AG2 Studio', 9 | description: 'Build LLM Enabled Agents', 10 | } 11 | 12 | export default function RootLayout({ 13 | children, 14 | }: { 15 | children: React.ReactNode 16 | }) { 17 | return ( 18 | 19 | 20 | 21 | 22 | {children} 23 | 24 | 25 | 26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "allowSyntheticDefaultImports": true, 11 | "module": "esnext", 12 | "moduleResolution": "bundler", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./src/*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"], 28 | 29 | } 30 | -------------------------------------------------------------------------------- /ag2studio/database/migrations/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from typing import Sequence, Union 9 | 10 | from alembic import op 11 | import sqlalchemy as sa 12 | import sqlmodel 13 | ${imports if imports else ""} 14 | 15 | # revision identifiers, used by Alembic. 16 | revision: str = ${repr(up_revision)} 17 | down_revision: Union[str, None] = ${repr(down_revision)} 18 | branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)} 19 | depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} 20 | 21 | 22 | def upgrade() -> None: 23 | ${upgrades if upgrades else "pass"} 24 | 25 | 26 | def downgrade() -> None: 27 | ${downgrades if downgrades else "pass"} 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /frontend/src/hooks/store.tsx: -------------------------------------------------------------------------------- 1 | import { create } from "zustand"; 2 | import { v4 as uuidv4 } from "uuid"; 3 | 4 | import { IChatMessage, IChatSession } from "../components/types"; 5 | 6 | interface ConfigState { 7 | messages: IChatMessage[] | null; 8 | setMessages: (messages: IChatMessage[]) => void; 9 | session: IChatSession | null; 10 | setSession: (session: IChatSession | null) => void; 11 | sessions: IChatSession[]; 12 | setSessions: (sessions: IChatSession[]) => void; 13 | version: string | null; 14 | setVersion: (version: string) => void; 15 | connectionId: string; 16 | setConnectionId: (connectionId: string) => void; 17 | } 18 | 19 | export const useConfigStore = create()((set) => ({ 20 | messages: null, 21 | setMessages: (messages) => set({ messages }), 22 | session: null, 23 | setSession: (session) => set({ session }), 24 | sessions: [], 25 | setSessions: (sessions) => set({ sessions }), 26 | version: null, 27 | setVersion: (version) => set({ version }), 28 | connectionId: uuidv4(), 29 | setConnectionId: (connectionId) => set({ connectionId }), 30 | })); 31 | -------------------------------------------------------------------------------- /frontend/static/images/svgs/ag2logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Victor Dibia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /frontend/src/app/not-found.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import Link from 'next/link' 4 | 5 | const pageStyles = { 6 | color: "#232129", 7 | padding: "96px", 8 | fontFamily: "-apple-system, Roboto, sans-serif, serif", 9 | } 10 | 11 | const headingStyles = { 12 | marginTop: 0, 13 | marginBottom: 64, 14 | maxWidth: 320, 15 | } 16 | 17 | const paragraphStyles = { 18 | marginBottom: 48, 19 | } 20 | 21 | const codeStyles = { 22 | color: "#8A6534", 23 | padding: 4, 24 | backgroundColor: "#FFF4DB", 25 | fontSize: "1.25rem", 26 | borderRadius: 4, 27 | } 28 | 29 | export default function NotFound() { 30 | return ( 31 |
32 |

Page not found

33 |

34 | Sorry 😔, we couldn't find what you were looking for. 35 |
36 | {process.env.NODE_ENV === "development" ? ( 37 | 38 | Try creating a page in src/app/ 39 |
40 |
41 | ) : null} 42 |
43 | Go home 44 |

45 |
46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2025, Owners of https://github.com/ag2ai 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | from setuptools import setup 5 | from setuptools.command.develop import develop 6 | from setuptools.command.install import install 7 | from subprocess import check_call 8 | import os 9 | import sys 10 | 11 | class PreInstallCommand(install): 12 | """Pre-installation for installation mode.""" 13 | def run(self): 14 | try: 15 | check_call([sys.executable, 'build_frontend.py']) 16 | except Exception as e: 17 | print(f"Error building frontend: {e}") 18 | print("Continuing with installation...") 19 | install.run(self) 20 | 21 | class PreDevelopCommand(develop): 22 | """Pre-installation for development mode.""" 23 | def run(self): 24 | try: 25 | check_call([sys.executable, 'build_frontend.py']) 26 | except Exception as e: 27 | print(f"Error building frontend: {e}") 28 | print("Continuing with installation...") 29 | develop.run(self) 30 | 31 | setup( 32 | cmdclass={ 33 | 'install': PreInstallCommand, 34 | 'develop': PreDevelopCommand, 35 | } 36 | ) -------------------------------------------------------------------------------- /frontend/src/components/footer.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import Icon from "./icons"; 3 | import { useConfigStore } from "../hooks/store"; 4 | import { fetchVersion } from "./utils"; 5 | 6 | const Footer = () => { 7 | const version = useConfigStore((state) => state.version); 8 | const setVersion = useConfigStore((state) => state.setVersion); 9 | 10 | React.useEffect(() => { 11 | if (version === null) { 12 | fetchVersion().then((data) => { 13 | if (data && data.data) { 14 | setVersion(data.data.version); 15 | } 16 | }); 17 | } 18 | }, []); 19 | return ( 20 |
21 |
22 | Maintained by the AG2{" "} 23 | 29 | {" "} 30 | Team. 31 | 32 |
33 | {version && ( 34 |
v{version}
35 | )} 36 |
37 | ); 38 | }; 39 | export default Footer; 40 | -------------------------------------------------------------------------------- /frontend/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ["./src/**/*.{js,jsx,ts,tsx}"], 3 | darkMode: "class", 4 | theme: { 5 | extend: { 6 | fontFamily: { 7 | mono: ['"JetBrains Mono"', 'monospace'], 8 | }, 9 | typography: { 10 | DEFAULT: { 11 | css: { 12 | maxWidth: "100ch", // add required value here 13 | }, 14 | }, 15 | }, 16 | transitionProperty: { 17 | height: "height", 18 | spacing: "margin, padding", 19 | }, 20 | backgroundColor: { 21 | primary: "var(--color-bg-primary)", 22 | secondary: "var(--color-bg-secondary)", 23 | accent: "var(--color-bg-accent)", 24 | light: "var(--color-bg-light)", 25 | tertiary: "var(--color-bg-tertiary)", 26 | }, 27 | textColor: { 28 | accent: "var(--color-text-accent)", 29 | primary: "var(--color-text-primary)", 30 | secondary: "var(--color-text-secondary)", 31 | }, 32 | borderColor: { 33 | accent: "var(--color-border-accent)", 34 | primary: "var(--color-border-primary)", 35 | secondary: "var(--color-border-secondary)", 36 | }, 37 | }, 38 | }, 39 | plugins: [require("@tailwindcss/typography")], 40 | }; 41 | -------------------------------------------------------------------------------- /frontend/src/components/layout.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import Header from "./header"; 3 | import { appContext } from "../hooks/provider"; 4 | import Footer from "./footer"; 5 | 6 | /// import ant css 7 | import "antd/dist/reset.css"; 8 | 9 | type Props = { 10 | title: string; 11 | link: string; 12 | children?: React.ReactNode; 13 | showHeader?: boolean; 14 | restricted?: boolean; 15 | meta?: any; 16 | }; 17 | 18 | const Layout = ({ 19 | meta, 20 | title, 21 | link, 22 | children, 23 | showHeader = true, 24 | restricted = false, 25 | }: Props) => { 26 | const layoutContent = ( 27 |
31 | {showHeader &&
} 32 |
33 | {meta?.title + " | " + title} 34 |
{children}
35 |
36 |
37 |
38 | ); 39 | 40 | const { darkMode } = React.useContext(appContext); 41 | React.useEffect(() => { 42 | document.getElementsByTagName("html")[0].className = `${ 43 | darkMode === "dark" ? "dark bg-primary" : "light bg-primary" 44 | } `; 45 | }, [darkMode]); 46 | 47 | return ( 48 | 49 | {(context: any) => { 50 | if (restricted) { 51 | return
{context.user && layoutContent}
; 52 | } else { 53 | return layoutContent; 54 | } 55 | }} 56 |
57 | ); 58 | }; 59 | 60 | export default Layout; 61 | -------------------------------------------------------------------------------- /frontend/src/components/views/playground/sidebar.tsx: -------------------------------------------------------------------------------- 1 | import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/24/outline"; 2 | import * as React from "react"; 3 | import SessionsView from "./sessions"; 4 | 5 | const SideBarView = () => { 6 | const [isOpen, setIsOpen] = React.useState(true); 7 | const minWidth = isOpen ? "270px" : "50px"; 8 | 9 | let windowHeight, sidebarMaxHeight; 10 | if (typeof window !== "undefined") { 11 | windowHeight = window.innerHeight; 12 | sidebarMaxHeight = windowHeight - 180 + "px"; 13 | } 14 | 15 | return ( 16 |
24 |
25 |
26 | {/* */} 27 | {} 28 |
29 |
30 |
setIsOpen(!isOpen)} 32 | role="button" 33 | className=" hover:text-accent duration-150 " 34 | > 35 | {isOpen ? ( 36 |
37 | {" "} 38 | {" "} 39 | close sidebar 40 |
41 | ) : ( 42 | 43 | )} 44 |
45 |
46 | ); 47 | }; 48 | 49 | export default SideBarView; 50 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ag2studio", 3 | "version": "0.1.0", 4 | "private": true, 5 | "description": "AG2 Studio - Build LLM Enabled Agents", 6 | "author": "SPIRAL Team", 7 | "scripts": { 8 | "dev": "next dev", 9 | "clean": "rimraf .next out", 10 | "build": "npm run clean && next build && rimraf ../ag2studio/web/ui && rsync -a --delete out/ ../ag2studio/web/ui/", 11 | "build-windows": "npm run clean && next build && rimraf ../ag2studio/web/ui && xcopy /E /I /Y out ..\\ag2studio\\web\\ui", 12 | "start": "npx serve@latest out", 13 | "lint": "next lint", 14 | "typecheck": "tsc --noEmit" 15 | }, 16 | "dependencies": { 17 | "@ant-design/charts": "^1.3.6", 18 | "@headlessui/react": "^1.7.16", 19 | "@heroicons/react": "^2.0.18", 20 | "@monaco-editor/react": "^4.6.0", 21 | "@tailwindcss/typography": "^0.5.9", 22 | "@types/lodash.debounce": "^4.0.9", 23 | "@types/node": "^20.17.10", 24 | "@types/react": "^18.3.17", 25 | "@types/react-dom": "^18.3.5", 26 | "@types/uuid": "^10.0.0", 27 | "antd": "^5.1.0", 28 | "autoprefixer": "^10.4.7", 29 | "jszip": "^3.10.1", 30 | "lodash.debounce": "^4.0.8", 31 | "next": "^15.1.0", 32 | "papaparse": "^5.4.1", 33 | "postcss": "^8.4.13", 34 | "react": "^18.2.0", 35 | "react-contenteditable": "^3.3.6", 36 | "react-dom": "^18.2.0", 37 | "react-inner-image-zoom": "^3.0.2", 38 | "react-markdown": "^9.0.1", 39 | "react-syntax-highlighter": "^15.6.1", 40 | "remark-gfm": "^4.0.0", 41 | "tailwindcss": "^3.3.0", 42 | "typescript": "^5.7.2", 43 | "uuid": "^11.0.3", 44 | "zustand": "^5.0.2" 45 | }, 46 | "devDependencies": { 47 | "@types/papaparse": "^5.3.15", 48 | "@types/react-syntax-highlighter": "^15.5.13", 49 | "rimraf": "^6.0.1" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /notebooks/agent_spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "General Agent Workflow", 3 | "description": "A general agent workflow", 4 | "sender": { 5 | "type": "userproxy", 6 | "config": { 7 | "name": "userproxy", 8 | "human_input_mode": "NEVER", 9 | "max_consecutive_auto_reply": 5, 10 | "system_message": "", 11 | "llm_config": false, 12 | "code_execution_config": { 13 | "work_dir": null, 14 | "use_docker": false 15 | } 16 | } 17 | }, 18 | "receiver": { 19 | "type": "assistant", 20 | "config": { 21 | "name": "primary_assistant", 22 | "llm_config": { 23 | "config_list": [ 24 | { 25 | "model": "gpt-4-1106-preview" 26 | } 27 | ], 28 | "temperature": 0.1, 29 | "timeout": 600, 30 | "cache_seed": 42 31 | }, 32 | "human_input_mode": "NEVER", 33 | "max_consecutive_auto_reply": 8, 34 | "system_message": "You are a helpful assistant that can use available functions when needed to solve problems. At each point, do your best to determine if the user's request has been addressed. IF THE REQUEST HAS NOT BEEN ADDRESSED, RESPOND WITH CODE TO ADDRESS IT. IF A FAILURE OCCURRED (e.g., due to a missing library) AND SOME ADDITIONAL CODE WAS WRITTEN (e.g. code to install the library), ENSURE THAT THE ORIGINAL CODE TO ADDRESS THE TASK STILL GETS EXECUTED. If the request HAS been addressed, respond with a summary of the result. The summary must be written as a coherent helpful response to the user request e.g. 'Sure, here is result to your request ' or 'The tallest mountain in Africa is ..' etc. The summary MUST end with the word TERMINATE. If the user request is pleasantry or greeting, you should respond with a pleasantry or greeting and TERMINATE." 35 | } 36 | }, 37 | "type": "twoagents" 38 | } 39 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools>=45", 4 | "setuptools-scm[toml]>=6.2", 5 | "wheel" 6 | ] 7 | build-backend = "setuptools.build_meta" 8 | 9 | [project] 10 | name = "ag2studio" 11 | authors = [ 12 | { name="Chi Wang & Jingyun Wu", email="support@ag2.ai" }, 13 | ] 14 | dynamic = ["version"] 15 | description = "AG2 Studio" 16 | readme = "PyPiREADME.md" 17 | license = { file="LICENSE" } 18 | requires-python = ">=3.9" 19 | classifiers = [ 20 | "Programming Language :: Python :: 3", 21 | "License :: OSI Approved :: Apache Software License", 22 | "Operating System :: OS Independent", 23 | ] 24 | 25 | 26 | dependencies = [ 27 | "pydantic", 28 | "fastapi", 29 | "typer", 30 | "uvicorn", 31 | "arxiv", 32 | "ag2[gemini]>=0.2.0", 33 | "python-dotenv", 34 | "websockets", 35 | "numpy>=2.1.0", 36 | "sqlmodel", 37 | "psycopg", 38 | "alembic", 39 | "loguru", 40 | ] 41 | 42 | [project.optional-dependencies] 43 | web = ["fastapi", "uvicorn"] 44 | database = ["psycopg"] 45 | all = ["ag2studio[web]", "ag2studio[database]"] 46 | 47 | [tool.setuptools] 48 | include-package-data = true 49 | 50 | [tool.setuptools.dynamic] 51 | version = {attr = "ag2studio.version.VERSION"} 52 | readme = {file = ["PyPiREADME.md"]} 53 | 54 | [tool.setuptools.packages.find] 55 | include = ["ag2studio*"] 56 | exclude = ["*.tests*"] 57 | namespaces = false 58 | 59 | [tool.setuptools.package-data] 60 | "ag2studio" = ["*.*"] 61 | 62 | [tool.pytest.ini_options] 63 | filterwarnings = [ 64 | "ignore:Deprecated call to `pkg_resources\\.declare_namespace\\('.*'\\):DeprecationWarning", 65 | "ignore::DeprecationWarning:google.rpc", 66 | ] 67 | 68 | 69 | [project.urls] 70 | "Homepage" = "https://github.com/ag2ai/ag2" 71 | "Bug Tracker" = "https://github.com/ag2ai/ag2/issues" 72 | 73 | [project.scripts] 74 | ag2studio = "ag2studio.cli:run" 75 | -------------------------------------------------------------------------------- /frontend/src/app/client-layout.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { useContext } from 'react' 4 | import { ConfigProvider, theme } from 'antd' 5 | import { appContext } from '../hooks/provider' 6 | import Header from '../components/header' 7 | import Footer from '../components/footer' 8 | 9 | // Use same color for buttons in both themes 10 | const buttonColor = '#22c55e'; 11 | 12 | const themeConfig = { 13 | light: { 14 | token: { 15 | colorPrimary: buttonColor, 16 | colorBgContainer: '#ffffff', 17 | colorText: '#334155', 18 | colorBgBase: '#ffffff', 19 | }, 20 | components: { 21 | Button: { 22 | colorPrimary: buttonColor, 23 | colorPrimaryHover: '#1ea352', 24 | algorithm: false, 25 | }, 26 | }, 27 | }, 28 | dark: { 29 | token: { 30 | colorPrimary: buttonColor, 31 | colorBgContainer: '#111827', 32 | colorText: '#f7fafc', 33 | colorBgBase: '#111827', 34 | }, 35 | components: { 36 | Button: { 37 | colorPrimary: buttonColor, 38 | colorPrimaryHover: '#1ea352', 39 | algorithm: false, 40 | }, 41 | }, 42 | } 43 | }; 44 | 45 | export default function ClientLayout({ 46 | children, 47 | }: { 48 | children: React.ReactNode 49 | }) { 50 | const { darkMode } = useContext(appContext); 51 | const currentTheme = darkMode === "dark" ? themeConfig.dark : themeConfig.light; 52 | 53 | return ( 54 | 61 |
62 |
63 |
64 | {children} 65 |
66 |
67 |
68 |
69 | ); 70 | } 71 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | ## 🚀 Running UI in Dev Mode 2 | 3 | Run the UI in dev mode (make changes and see them reflected in the browser with hotreloading): 4 | 5 | - npm install 6 | - npm run start 7 | 8 | This should start the server on port 8000. 9 | 10 | ## Design Elements 11 | 12 | - **Gatsby**: The app is created in Gatsby. A guide on bootstrapping a Gatsby app can be found here - https://www.gatsbyjs.com/docs/quick-start/. 13 | This provides an overview of the project file structure include functionality of files like `gatsby-config.js`, `gatsby-node.js`, `gatsby-browser.js` and `gatsby-ssr.js`. 14 | - **TailwindCSS**: The app uses TailwindCSS for styling. A guide on using TailwindCSS with Gatsby can be found here - https://tailwindcss.com/docs/guides/gatsby.https://tailwindcss.com/docs/guides/gatsby . This will explain the functionality in tailwind.config.js and postcss.config.js. 15 | 16 | ## Modifying the UI, Adding Pages 17 | 18 | The core of the app can be found in the `src` folder. To add pages, add a new folder in `src/pages` and add a `index.js` file. This will be the entry point for the page. For example to add a route in the app like `/about`, add a folder `about` in `src/pages` and add a `index.tsx` file. You can follow the content style in `src/pages/index.tsx` to add content to the page. 19 | 20 | Core logic for each component should be written in the `src/components` folder and then imported in pages as needed. 21 | 22 | ## connecting to front end 23 | 24 | the front end makes request to the backend api and expects it at /api on localhost port 8081 25 | 26 | ## setting env variables for the UI 27 | 28 | - please look at `.env.default` 29 | - make a copy of this file and name it `.env.development` 30 | - set the values for the variables in this file 31 | - The main variable here is `GATSBY_API_URL` which should be set to `http://localhost:8081/api` for local development. This tells the UI where to make requests to the backend. 32 | -------------------------------------------------------------------------------- /ag2studio/cli.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Portions derived from https://github.com/microsoft/autogen are under the MIT License. 6 | # SPDX-License-Identifier: MIT 7 | import os 8 | from typing import Optional 9 | 10 | import typer 11 | import uvicorn 12 | from typing_extensions import Annotated 13 | 14 | from .version import VERSION 15 | 16 | app = typer.Typer() 17 | 18 | 19 | @app.command() 20 | def ui( 21 | host: str = "127.0.0.1", 22 | port: int = 8081, 23 | workers: int = 1, 24 | reload: Annotated[bool, typer.Option("--reload")] = True, 25 | docs: bool = False, 26 | appdir: str = None, 27 | database_uri: Optional[str] = None, 28 | ): 29 | """ 30 | Run the AG2 Studio UI. 31 | 32 | Args: 33 | host (str, optional): Host to run the UI on. Defaults to 127.0.0.1 (localhost). 34 | port (int, optional): Port to run the UI on. Defaults to 8081. 35 | workers (int, optional): Number of workers to run the UI with. Defaults to 1. 36 | reload (bool, optional): Whether to reload the UI on code changes. Defaults to False. 37 | docs (bool, optional): Whether to generate API docs. Defaults to False. 38 | appdir (str, optional): Path to the AG2 Studio app directory. Defaults to None. 39 | database-uri (str, optional): Database URI to connect to. Defaults to None. Examples include sqlite:///ag2studio.db, postgresql://user:password@localhost/ag2studio. 40 | """ 41 | 42 | os.environ["AG2STUDIO_API_DOCS"] = str(docs) 43 | if appdir: 44 | os.environ["AG2STUDIO_APPDIR"] = appdir 45 | if database_uri: 46 | os.environ["AG2STUDIO_DATABASE_URI"] = database_uri 47 | 48 | uvicorn.run( 49 | "ag2studio.web.app:app", 50 | host=host, 51 | port=port, 52 | workers=workers, 53 | reload=reload, 54 | ) 55 | 56 | 57 | @app.command() 58 | def version(): 59 | """ 60 | Print the version of the AG2 Studio UI CLI. 61 | """ 62 | 63 | typer.echo(f"AG2 Studio CLI version: {VERSION}") 64 | 65 | 66 | def run(): 67 | app() 68 | 69 | 70 | if __name__ == "__main__": 71 | app() 72 | -------------------------------------------------------------------------------- /frontend/src/components/views/builder/build.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import SkillsView from "./skills"; 3 | import AgentsView from "./agents"; 4 | import WorkflowView from "./workflow"; 5 | import { Tabs } from "antd"; 6 | import { 7 | BugAntIcon, 8 | CpuChipIcon, 9 | Square2StackIcon, 10 | Square3Stack3DIcon, 11 | } from "@heroicons/react/24/outline"; 12 | import ModelsView from "./models"; 13 | 14 | const BuildView = () => { 15 | return ( 16 |
17 | {/*
Build
*/} 18 |
19 | {" "} 20 | Create skills, agents and workflows for building multiagent capabilities{" "} 21 |
22 | 23 |
24 | {" "} 25 | 33 | {" "} 34 | 35 | Skills 36 |
37 | ), 38 | key: "1", 39 | children: , 40 | }, 41 | { 42 | label: ( 43 |
44 | {" "} 45 | 46 | Models 47 |
48 | ), 49 | key: "2", 50 | children: , 51 | }, 52 | { 53 | label: ( 54 | <> 55 | 56 | Agents 57 | 58 | ), 59 | key: "3", 60 | children: , 61 | }, 62 | { 63 | label: ( 64 | <> 65 | 66 | Workflows 67 | 68 | ), 69 | key: "4", 70 | children: , 71 | }, 72 | ]} 73 | /> 74 |
75 | 76 |
77 | 78 | ); 79 | }; 80 | 81 | export default BuildView; 82 | -------------------------------------------------------------------------------- /frontend/src/hooks/provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import React, { useState, useEffect } from "react"; 4 | import { 5 | eraseCookie, 6 | getLocalStorage, 7 | setLocalStorage, 8 | } from "../components/utils"; 9 | import { message } from "antd"; 10 | 11 | export interface IUser { 12 | name: string; 13 | email?: string; 14 | username?: string; 15 | avatar_url?: string; 16 | metadata?: any; 17 | } 18 | 19 | interface IAppContext { 20 | user: IUser | null; 21 | setUser: (user: IUser | null) => void; 22 | logout: () => void; 23 | cookie_name: string; 24 | darkMode: string; 25 | setDarkMode: (mode: string) => void; 26 | } 27 | 28 | const cookie_name = "coral_app_cookie_"; 29 | 30 | export const appContext = React.createContext({ 31 | user: null, 32 | setUser: () => {}, 33 | logout: () => {}, 34 | cookie_name: "", 35 | darkMode: "dark", 36 | setDarkMode: () => {}, 37 | }); 38 | 39 | export function AppProvider({ children }: { children: React.ReactNode }) { 40 | const [darkMode, setDarkMode] = useState('dark'); 41 | const [user, setUser] = useState({ 42 | name: "Guest User", 43 | email: "guestuser@gmail.com", 44 | }); 45 | 46 | const logout = () => { 47 | setUser(null); 48 | eraseCookie(cookie_name); 49 | console.log("Please implement your own Sign out logic"); 50 | message.info("Please implement your own Sign out logic"); 51 | }; 52 | 53 | const handleDarkModeChange = (mode: string) => { 54 | console.log('Setting dark mode to:', mode); 55 | setDarkMode(mode); 56 | setLocalStorage("darkmode", mode); 57 | if (typeof document !== 'undefined') { 58 | document.documentElement.classList.toggle('dark', mode === 'dark'); 59 | document.documentElement.classList.toggle('light', mode === 'light'); 60 | document.body.style.backgroundColor = mode === 'dark' ? '#111827' : '#ffffff'; 61 | } 62 | }; 63 | 64 | useEffect(() => { 65 | if (typeof window === 'undefined') return; 66 | const storedValue = getLocalStorage("darkmode", false); 67 | const initialMode = storedValue === null ? "dark" : storedValue === "dark" ? "dark" : "light"; 68 | handleDarkModeChange(initialMode); 69 | }, []); 70 | 71 | const contextValue: IAppContext = { 72 | user, 73 | setUser, 74 | logout, 75 | cookie_name, 76 | darkMode, 77 | setDarkMode: handleDarkModeChange, 78 | }; 79 | 80 | return ( 81 | 82 | {children} 83 | 84 | ); 85 | } 86 | -------------------------------------------------------------------------------- /ag2studio/database/migrations/env.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Portions derived from https://github.com/microsoft/autogen are under the MIT License. 6 | # SPDX-License-Identifier: MIT 7 | from logging.config import fileConfig 8 | 9 | from alembic import context 10 | from sqlalchemy import engine_from_config, pool 11 | from sqlmodel import SQLModel 12 | 13 | from ag2studio.datamodel import * 14 | from ag2studio.utils import get_db_uri 15 | 16 | # this is the Alembic Config object, which provides 17 | # access to the values within the .ini file in use. 18 | config = context.config 19 | config.set_main_option("sqlalchemy.url", get_db_uri()) 20 | 21 | # Interpret the config file for Python logging. 22 | # This line sets up loggers basically. 23 | if config.config_file_name is not None: 24 | fileConfig(config.config_file_name) 25 | 26 | # add your model's MetaData object here 27 | # for 'autogenerate' support 28 | # from myapp import mymodel 29 | # target_metadata = mymodel.Base.metadata 30 | target_metadata = SQLModel.metadata 31 | 32 | # other values from the config, defined by the needs of env.py, 33 | # can be acquired: 34 | # my_important_option = config.get_main_option("my_important_option") 35 | # ... etc. 36 | 37 | 38 | def run_migrations_offline() -> None: 39 | """Run migrations in 'offline' mode. 40 | 41 | This configures the context with just a URL 42 | and not an Engine, though an Engine is acceptable 43 | here as well. By skipping the Engine creation 44 | we don't even need a DBAPI to be available. 45 | 46 | Calls to context.execute() here emit the given string to the 47 | script output. 48 | 49 | """ 50 | url = config.get_main_option("sqlalchemy.url") 51 | context.configure( 52 | url=url, 53 | target_metadata=target_metadata, 54 | literal_binds=True, 55 | dialect_opts={"paramstyle": "named"}, 56 | ) 57 | 58 | with context.begin_transaction(): 59 | context.run_migrations() 60 | 61 | 62 | def run_migrations_online() -> None: 63 | """Run migrations in 'online' mode. 64 | 65 | In this scenario we need to create an Engine 66 | and associate a connection with the context. 67 | 68 | """ 69 | connectable = engine_from_config( 70 | config.get_section(config.config_ini_section, {}), 71 | prefix="sqlalchemy.", 72 | poolclass=pool.NullPool, 73 | ) 74 | 75 | with connectable.connect() as connection: 76 | context.configure(connection=connection, target_metadata=target_metadata) 77 | 78 | with context.begin_transaction(): 79 | context.run_migrations() 80 | 81 | 82 | if context.is_offline_mode(): 83 | run_migrations_offline() 84 | else: 85 | run_migrations_online() 86 | -------------------------------------------------------------------------------- /frontend/src/components/views/playground/ra.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { IChatSession, IMessage, IStatus } from "../../types"; 3 | import { fetchJSON, getServerUrl, setLocalStorage } from "../../utils"; 4 | import ChatBox from "./chatbox"; 5 | import { appContext } from "../../../hooks/provider"; 6 | import { message } from "antd"; 7 | import SideBarView from "./sidebar"; 8 | import { useConfigStore } from "../../../hooks/store"; 9 | import SessionsView from "./sessions"; 10 | 11 | const RAView = () => { 12 | const session: IChatSession | null = useConfigStore((state) => state.session); 13 | const [loading, setLoading] = React.useState(false); 14 | const [messages, setMessages] = React.useState(null); 15 | 16 | const [config, setConfig] = React.useState(null); 17 | 18 | React.useEffect(() => { 19 | setLocalStorage("ara_config", config); 20 | }, [config]); 21 | 22 | const [error, setError] = React.useState({ 23 | status: true, 24 | message: "All good", 25 | }); 26 | 27 | const { user } = React.useContext(appContext); 28 | const serverUrl = getServerUrl(); 29 | const fetchMessagesUrl = `${serverUrl}/sessions/${session?.id}/messages?user_id=${user?.email}`; 30 | 31 | const fetchMessages = () => { 32 | setError(null); 33 | setLoading(true); 34 | setMessages(null); 35 | const payLoad = { 36 | method: "GET", 37 | headers: { 38 | "Content-Type": "application/json", 39 | }, 40 | }; 41 | const onSuccess = (data: any) => { 42 | if (data && data.status) { 43 | setMessages(data.data); 44 | } else { 45 | message.error(data.message); 46 | } 47 | setLoading(false); 48 | }; 49 | const onError = (err: any) => { 50 | setError(err); 51 | message.error(err.message); 52 | setLoading(false); 53 | }; 54 | fetchJSON(fetchMessagesUrl, payLoad, onSuccess, onError); 55 | }; 56 | 57 | React.useEffect(() => { 58 | if (user && session) { 59 | fetchMessages(); 60 | } 61 | }, [session]); 62 | 63 | return ( 64 |
65 |
66 |
67 | 68 |
69 |
70 | {!session && ( 71 |
72 |
73 |
74 | {" "} 75 | welcome 80 |
81 | 82 |
83 |
84 | )} 85 | 86 | {session !== null && ( 87 | 88 | )} 89 |
90 |
91 |
92 | ); 93 | }; 94 | export default RAView; 95 | -------------------------------------------------------------------------------- /frontend/src/components/types.ts: -------------------------------------------------------------------------------- 1 | export type NotificationType = "success" | "info" | "warning" | "error"; 2 | 3 | export interface IMessage { 4 | user_id: string; 5 | role: string; 6 | content: string; 7 | created_at?: string; 8 | updated_at?: string; 9 | session_id?: number; 10 | connection_id?: string; 11 | workflow_id?: number; 12 | } 13 | 14 | export interface IStatus { 15 | message: string; 16 | status: boolean; 17 | data?: any; 18 | } 19 | 20 | export interface IChatMessage { 21 | text: string; 22 | sender: "user" | "bot"; 23 | meta?: any; 24 | msg_id: string; 25 | } 26 | 27 | export interface ILLMConfig { 28 | config_list: Array; 29 | timeout?: number; 30 | cache_seed?: number | null; 31 | temperature: number; 32 | max_tokens: number; 33 | } 34 | 35 | export interface IAgentConfig { 36 | name: string; 37 | llm_config?: ILLMConfig | false; 38 | human_input_mode: string; 39 | max_consecutive_auto_reply: number; 40 | system_message: string | ""; 41 | is_termination_msg?: boolean | string; 42 | default_auto_reply?: string | null; 43 | code_execution_config?: "none" | "local" | "docker"; 44 | description?: string; 45 | 46 | admin_name?: string; 47 | messages?: Array; 48 | max_round?: number; 49 | speaker_selection_method?: string; 50 | allow_repeat_speaker?: boolean; 51 | } 52 | 53 | export interface IAgent { 54 | type?: "assistant" | "userproxy" | "groupchat"; 55 | config: IAgentConfig; 56 | created_at?: string; 57 | updated_at?: string; 58 | id?: number; 59 | skills?: Array; 60 | user_id?: string; 61 | } 62 | 63 | export interface IWorkflow { 64 | name: string; 65 | description: string; 66 | sender: IAgent; 67 | receiver: IAgent; 68 | type: "twoagents" | "groupchat"; 69 | created_at?: string; 70 | updated_at?: string; 71 | summary_method?: "none" | "last" | "llm"; 72 | id?: number; 73 | user_id?: string; 74 | } 75 | 76 | export interface IModelConfig { 77 | model: string; 78 | api_key?: string; 79 | api_version?: string; 80 | base_url?: string; 81 | api_type?: "open_ai" | "azure" | "google"; 82 | user_id?: string; 83 | created_at?: string; 84 | updated_at?: string; 85 | description?: string; 86 | id?: number; 87 | } 88 | 89 | export interface IMetadataFile { 90 | name: string; 91 | path: string; 92 | extension: string; 93 | content: string; 94 | type: string; 95 | } 96 | 97 | export interface IChatSession { 98 | id?: number; 99 | user_id: string; 100 | workflow_id?: number; 101 | created_at?: string; 102 | updated_at?: string; 103 | name: string; 104 | } 105 | 106 | export interface IGalleryItem { 107 | id: number; 108 | messages: Array; 109 | session: IChatSession; 110 | tags: Array; 111 | created_at: string; 112 | updated_at: string; 113 | } 114 | 115 | export interface ISkill { 116 | name: string; 117 | content: string; 118 | id?: number; 119 | description?: string; 120 | user_id?: string; 121 | created_at?: string; 122 | updated_at?: string; 123 | } 124 | -------------------------------------------------------------------------------- /docs/faq.md: -------------------------------------------------------------------------------- 1 | ## Q: How do I specify the directory where files(e.g. database) are stored? 2 | 3 | A: You can specify the directory where files are stored by setting the `--appdir` argument when running the application. For example, `ag2studio ui --appdir /path/to/folder`. This will store the database (default) and other files in the specified directory e.g. `/path/to/folder/database.sqlite`. 4 | 5 | ## Q: Where can I adjust the default skills, agent and workflow configurations? 6 | 7 | A: You can modify agent configurations directly from the UI or by editing the `init_db_samples` function in the `ag2studio/database/utils.py` file which is used to initialize the database. 8 | 9 | ## Q: If I want to reset the entire conversation with an agent, how do I go about it? 10 | 11 | A: To reset your conversation history, you can delete the `database.sqlite` file in the `--appdir` directory. This will reset the entire conversation history. To delete user files, you can delete the `files` directory in the `--appdir` directory. 12 | 13 | ## Q: Is it possible to view the output and messages generated by the agents during interactions? 14 | 15 | A: Yes, you can view the generated messages in the debug console of the web UI, providing insights into the agent interactions. Alternatively, you can inspect the `database.sqlite` file for a comprehensive record of messages. 16 | 17 | ## Q: Can I use other models with AG2 Studio? 18 | 19 | Yes. AG2 standardizes on the openai model api format, and you can use any api server that offers an openai compliant endpoint. In the AG2 Studio UI, each agent has an `llm_config` field where you can input your model endpoint details including `model`, `api key`, `base url`, `model type` and `api version`. For Azure OpenAI models, you can find these details in the Azure portal. Note that for Azure OpenAI, the `model name` is the deployment id or engine, and the `model type` is "azure". 20 | For other OSS models, we recommend using a server such as vllm, LMStudio, Ollama, to instantiate an openai compliant endpoint. 21 | 22 | ## Q: The server starts but I can't access the UI 23 | 24 | A: If you are running the server on a remote machine (or a local machine that fails to resolve localhost correctly), you may need to specify the host address. By default, the host address is set to `localhost`. You can specify the host address using the `--host ` argument. For example, to start the server on port 8081 and local address such that it is accessible from other machines on the network, you can run the following command: 25 | 26 | ```bash 27 | ag2studio ui --port 8081 --host 0.0.0.0 28 | ``` 29 | 30 | ## Q: Can I export my agent workflows for use in a python app? 31 | 32 | Yes. In the Build view, you can click the export button to save your agent workflow as a JSON file. This file can be imported in a python application using the `WorkflowManager` class. For example: 33 | 34 | ```python 35 | 36 | from ag2studio import WorkflowManager 37 | # load workflow from exported json workflow file. 38 | workflow_manager = WorkflowManager(workflow="path/to/your/workflow_.json") 39 | 40 | # run the workflow on a task 41 | task_query = "What is the height of the Eiffel Tower?. Dont write code, just respond to the question." 42 | workflow_manager.run(message=task_query) 43 | 44 | ``` 45 | 46 | ## Q: Can I deploy my agent workflows as APIs? 47 | 48 | Yes. You can launch the workflow as an API endpoint from the command line using the `ag2studio` commandline tool. For example: 49 | 50 | ```bash 51 | ag2studio serve --workflow=workflow.json --port=5000 52 | ``` 53 | 54 | Similarly, the workflow launch command above can be wrapped into a Dockerfile that can be deployed on cloud services like Azure Container Apps or Azure Web Apps. 55 | -------------------------------------------------------------------------------- /frontend/src/components/views/playground/utils/selectors.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import { Select, message } from "antd"; 4 | import * as React from "react"; 5 | import { LoadingOverlay } from "../../../atoms"; 6 | import { IWorkflow, IStatus } from "../../../types"; 7 | import { fetchJSON, getServerUrl } from "../../../utils"; 8 | import { appContext } from "../../../../hooks/provider"; 9 | import Link from "next/link"; 10 | 11 | const WorkflowSelector = ({ 12 | workflow, 13 | setWorkflow, 14 | disabled, 15 | }: { 16 | workflow: IWorkflow | null; 17 | setWorkflow: (workflow: IWorkflow) => void; 18 | disabled?: boolean; 19 | }) => { 20 | const [error, setError] = React.useState({ 21 | status: true, 22 | message: "All good", 23 | }); 24 | 25 | const [loading, setLoading] = React.useState(false); 26 | const [workflows, setWorkflows] = React.useState([]); 27 | const [selectedWorkflow, setSelectedWorkflow] = React.useState(0); 28 | 29 | const { user } = React.useContext(appContext); 30 | const serverUrl = getServerUrl(); 31 | const listWorkflowsUrl = `${serverUrl}/workflows?user_id=${user?.email}`; 32 | const fetchWorkFlow = () => { 33 | setError(null); 34 | setLoading(true); 35 | const payLoad = { 36 | method: "GET", 37 | headers: { 38 | "Content-Type": "application/json", 39 | }, 40 | }; 41 | 42 | const onSuccess = (data: any) => { 43 | if (data && data.status) { 44 | // message.success(data.message); 45 | setWorkflows(data.data); 46 | if (data.data.length > 0) { 47 | setWorkflow(data.data[0]); 48 | } 49 | } else { 50 | message.error(data.message); 51 | } 52 | setLoading(false); 53 | }; 54 | const onError = (err: any) => { 55 | setError(err); 56 | message.error(err.message); 57 | setLoading(false); 58 | }; 59 | fetchJSON(listWorkflowsUrl, payLoad, onSuccess, onError); 60 | }; 61 | 62 | React.useEffect(() => { 63 | if (user) { 64 | fetchWorkFlow(); 65 | } 66 | }, []); 67 | 68 | return ( 69 |
70 |
71 | {" "} 72 | Please select an agent workflow to begin.{" "} 73 |
74 | 75 |
76 | 77 | 78 | {workflows && workflows.length > 0 && ( 79 |