diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8bbd7a241..3fe0e8a75 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,15 @@ jobs: uses: actions/setup-python@v3 with: python-version: "3.9" + + - name: Cache Python dependencies + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Install dependencies run: | python -m pip install --upgrade pip @@ -76,6 +85,15 @@ jobs: uses: actions/setup-python@v3 with: python-version: "3.9" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/gui/package-lock.json b/gui/package-lock.json index ebb65645d..bc0dff7c8 100644 --- a/gui/package-lock.json +++ b/gui/package-lock.json @@ -18,6 +18,7 @@ "eslint-config-next": "13.4.2", "jszip": "^3.10.1", "mitt": "^3.0.0", + "mixpanel-browser": "^2.47.0", "moment": "^2.29.4", "moment-timezone": "^0.5.43", "next": "13.4.2", @@ -28,6 +29,7 @@ "react-grid-layout": "^1.3.4", "react-markdown": "^8.0.7", "react-spinners": "^0.13.8", + "react-tippy": "^1.4.0", "react-toastify": "^9.1.3" } }, @@ -43,6 +45,8 @@ }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.3.0" @@ -56,6 +60,8 @@ }, "node_modules/@eslint-community/regexpp": { "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -63,6 +69,8 @@ }, "node_modules/@eslint/eslintrc": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", "license": "MIT", "dependencies": { "ajv": "^6.12.4", @@ -84,6 +92,8 @@ }, "node_modules/@eslint/js": { "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", + "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -103,6 +113,8 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -114,14 +126,20 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "license": "BSD-3-Clause" }, "node_modules/@next/env": { "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.2.tgz", + "integrity": "sha512-Wqvo7lDeS0KGwtwg9TT9wKQ8raelmUxt+TQKWvG/xKfcmDXNOtCuaszcfCF8JzlBG1q0VhpI6CKaRMbVPMDWgw==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.4.2.tgz", + "integrity": "sha512-ZeFWgrxwckxTpYM+ANeUL9E7LOGPbZKmI94LJIjbDU69iEIgqd4WD0l2pVbOJMr/+vgoZmJ9Dx1m0WJ7WScXHA==", "license": "MIT", "dependencies": { "glob": "7.1.7" @@ -264,6 +282,8 @@ }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -275,6 +295,8 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "license": "MIT", "engines": { "node": ">= 8" @@ -282,6 +304,8 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -324,6 +348,8 @@ }, "node_modules/@swc/helpers": { "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", + "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.4.0" @@ -347,6 +373,8 @@ }, "node_modules/@types/json5": { "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "license": "MIT" }, "node_modules/@types/mdast": { @@ -482,6 +510,8 @@ }, "node_modules/acorn": { "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -492,6 +522,8 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -499,6 +531,8 @@ }, "node_modules/ajv": { "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -513,6 +547,8 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { "node": ">=8" @@ -520,6 +556,8 @@ }, "node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -533,10 +571,14 @@ }, "node_modules/argparse": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, "node_modules/aria-query": { "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", "license": "Apache-2.0", "dependencies": { "deep-equal": "^2.0.5" @@ -544,6 +586,8 @@ }, "node_modules/array-buffer-byte-length": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -555,6 +599,8 @@ }, "node_modules/array-includes": { "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -572,6 +618,8 @@ }, "node_modules/array-union": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "license": "MIT", "engines": { "node": ">=8" @@ -579,6 +627,8 @@ }, "node_modules/array.prototype.flat": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -595,6 +645,8 @@ }, "node_modules/array.prototype.flatmap": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -611,6 +663,8 @@ }, "node_modules/array.prototype.tosorted": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -622,14 +676,20 @@ }, "node_modules/ast-types-flow": { "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", "license": "ISC" }, "node_modules/asynckit": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, "node_modules/available-typed-arrays": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -647,6 +707,8 @@ }, "node_modules/axios": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.0", @@ -656,6 +718,8 @@ }, "node_modules/axobject-query": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", + "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", "license": "Apache-2.0", "dependencies": { "deep-equal": "^2.0.5" @@ -672,10 +736,14 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, "node_modules/big-integer": { "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", "license": "Unlicense", "engines": { "node": ">=0.6" @@ -700,6 +768,8 @@ }, "node_modules/bplist-parser": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", "license": "MIT", "dependencies": { "big-integer": "^1.6.44" @@ -710,6 +780,8 @@ }, "node_modules/brace-expansion": { "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -718,6 +790,8 @@ }, "node_modules/braces": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "license": "MIT", "dependencies": { "fill-range": "^7.0.1" @@ -728,6 +802,8 @@ }, "node_modules/bundle-name": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", "license": "MIT", "dependencies": { "run-applescript": "^5.0.0" @@ -741,6 +817,8 @@ }, "node_modules/busboy": { "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", "dependencies": { "streamsearch": "^1.1.0" }, @@ -750,6 +828,8 @@ }, "node_modules/call-bind": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "license": "MIT", "dependencies": { "function-bind": "^1.1.1", @@ -761,6 +841,8 @@ }, "node_modules/callsites": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "license": "MIT", "engines": { "node": ">=6" @@ -787,6 +869,8 @@ }, "node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -810,10 +894,14 @@ }, "node_modules/client-only": { "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, "node_modules/clsx": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", "license": "MIT", "engines": { "node": ">=6" @@ -821,6 +909,8 @@ }, "node_modules/color-convert": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -831,10 +921,14 @@ }, "node_modules/color-name": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -854,6 +948,8 @@ }, "node_modules/concat-map": { "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, "node_modules/core-util-is": { @@ -863,6 +959,8 @@ }, "node_modules/cross-spawn": { "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -881,10 +979,14 @@ }, "node_modules/damerau-levenshtein": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "license": "BSD-2-Clause" }, "node_modules/date-fns": { "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0" @@ -907,6 +1009,8 @@ }, "node_modules/debug": { "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -934,6 +1038,8 @@ }, "node_modules/deep-equal": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", + "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.0", @@ -961,10 +1067,14 @@ }, "node_modules/deep-is": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "license": "MIT" }, "node_modules/default-browser": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", "license": "MIT", "dependencies": { "bundle-name": "^3.0.0", @@ -981,6 +1091,8 @@ }, "node_modules/default-browser-id": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", "license": "MIT", "dependencies": { "bplist-parser": "^0.2.0", @@ -995,6 +1107,8 @@ }, "node_modules/define-lazy-prop": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "license": "MIT", "engines": { "node": ">=12" @@ -1005,6 +1119,8 @@ }, "node_modules/define-properties": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", "license": "MIT", "dependencies": { "has-property-descriptors": "^1.0.0", @@ -1019,6 +1135,8 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "license": "MIT", "engines": { "node": ">=0.4.0" @@ -1042,6 +1160,8 @@ }, "node_modules/dir-glob": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "license": "MIT", "dependencies": { "path-type": "^4.0.0" @@ -1052,6 +1172,8 @@ }, "node_modules/doctrine": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" @@ -1089,6 +1211,8 @@ }, "node_modules/emoji-regex": { "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "license": "MIT" }, "node_modules/enhanced-resolve": { @@ -1105,6 +1229,8 @@ }, "node_modules/es-abstract": { "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.0", @@ -1151,6 +1277,8 @@ }, "node_modules/es-get-iterator": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -1169,6 +1297,8 @@ }, "node_modules/es-set-tostringtag": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3", @@ -1181,6 +1311,8 @@ }, "node_modules/es-shim-unscopables": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", "license": "MIT", "dependencies": { "has": "^1.0.3" @@ -1188,6 +1320,8 @@ }, "node_modules/es-to-primitive": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "license": "MIT", "dependencies": { "is-callable": "^1.1.4", @@ -1203,6 +1337,8 @@ }, "node_modules/escape-string-regexp": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "license": "MIT", "engines": { "node": ">=10" @@ -1213,6 +1349,8 @@ }, "node_modules/eslint": { "version": "8.40.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", + "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -1268,6 +1406,8 @@ }, "node_modules/eslint-config-next": { "version": "13.4.2", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.4.2.tgz", + "integrity": "sha512-zjLJ9B9bbeWSo5q+iHfdt8gVYyT+y2BpWDfjR6XMBtFRSMKRGjllDKxnuKBV1q2Y/QpwLM2PXHJTMRyblCmRAg==", "license": "MIT", "dependencies": { "@next/eslint-plugin-next": "13.4.2", @@ -1292,6 +1432,8 @@ }, "node_modules/eslint-import-resolver-node": { "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "license": "MIT", "dependencies": { "debug": "^3.2.7", @@ -1301,6 +1443,8 @@ }, "node_modules/eslint-import-resolver-node/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "license": "MIT", "dependencies": { "ms": "^2.1.1" @@ -1308,6 +1452,8 @@ }, "node_modules/eslint-import-resolver-typescript": { "version": "3.5.5", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.5.tgz", + "integrity": "sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==", "license": "ISC", "dependencies": { "debug": "^4.3.4", @@ -1332,6 +1478,8 @@ }, "node_modules/eslint-import-resolver-typescript/node_modules/globby": { "version": "13.1.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", + "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", "license": "MIT", "dependencies": { "dir-glob": "^3.0.1", @@ -1349,6 +1497,8 @@ }, "node_modules/eslint-import-resolver-typescript/node_modules/slash": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "license": "MIT", "engines": { "node": ">=12" @@ -1359,6 +1509,8 @@ }, "node_modules/eslint-module-utils": { "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", "license": "MIT", "dependencies": { "debug": "^3.2.7" @@ -1374,6 +1526,8 @@ }, "node_modules/eslint-module-utils/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "license": "MIT", "dependencies": { "ms": "^2.1.1" @@ -1381,6 +1535,8 @@ }, "node_modules/eslint-plugin-import": { "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", "license": "MIT", "dependencies": { "array-includes": "^3.1.6", @@ -1408,6 +1564,8 @@ }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "license": "MIT", "dependencies": { "ms": "^2.1.1" @@ -1415,6 +1573,8 @@ }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" @@ -1425,6 +1585,8 @@ }, "node_modules/eslint-plugin-import/node_modules/semver": { "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1432,6 +1594,8 @@ }, "node_modules/eslint-plugin-jsx-a11y": { "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.7", @@ -1460,6 +1624,8 @@ }, "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1467,6 +1633,8 @@ }, "node_modules/eslint-plugin-react": { "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", "license": "MIT", "dependencies": { "array-includes": "^3.1.6", @@ -1494,6 +1662,8 @@ }, "node_modules/eslint-plugin-react-hooks": { "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", "license": "MIT", "engines": { "node": ">=10" @@ -1504,6 +1674,8 @@ }, "node_modules/eslint-plugin-react/node_modules/doctrine": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" @@ -1514,6 +1686,8 @@ }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", "license": "MIT", "dependencies": { "is-core-module": "^2.9.0", @@ -1529,6 +1703,8 @@ }, "node_modules/eslint-plugin-react/node_modules/semver": { "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1536,6 +1712,8 @@ }, "node_modules/eslint-scope": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -1550,6 +1728,8 @@ }, "node_modules/eslint-visitor-keys": { "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1560,6 +1740,8 @@ }, "node_modules/espree": { "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.8.0", @@ -1575,6 +1757,8 @@ }, "node_modules/esquery": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -1585,6 +1769,8 @@ }, "node_modules/esrecurse": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -1595,6 +1781,8 @@ }, "node_modules/estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -1602,6 +1790,8 @@ }, "node_modules/esutils": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -1609,6 +1799,8 @@ }, "node_modules/execa": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", @@ -1635,6 +1827,8 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, "node_modules/fast-glob": { @@ -1653,6 +1847,8 @@ }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -1663,14 +1859,20 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "license": "MIT" }, "node_modules/fastq": { "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -1678,6 +1880,8 @@ }, "node_modules/file-entry-cache": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" @@ -1688,6 +1892,8 @@ }, "node_modules/fill-range": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -1698,6 +1904,8 @@ }, "node_modules/find-up": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -1712,6 +1920,8 @@ }, "node_modules/flat-cache": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "license": "MIT", "dependencies": { "flatted": "^3.1.0", @@ -1723,10 +1933,14 @@ }, "node_modules/flatted": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "license": "ISC" }, "node_modules/follow-redirects": { "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "funding": [ { "type": "individual", @@ -1745,6 +1959,8 @@ }, "node_modules/for-each": { "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "license": "MIT", "dependencies": { "is-callable": "^1.1.3" @@ -1752,6 +1968,8 @@ }, "node_modules/form-data": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -1764,14 +1982,20 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "license": "ISC" }, "node_modules/function-bind": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "license": "MIT" }, "node_modules/function.prototype.name": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -1788,6 +2012,8 @@ }, "node_modules/functions-have-names": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1795,6 +2021,8 @@ }, "node_modules/get-intrinsic": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "license": "MIT", "dependencies": { "function-bind": "^1.1.1", @@ -1808,6 +2036,8 @@ }, "node_modules/get-stream": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "license": "MIT", "engines": { "node": ">=10" @@ -1818,6 +2048,8 @@ }, "node_modules/get-symbol-description": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -1839,6 +2071,8 @@ }, "node_modules/glob": { "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -1857,6 +2091,8 @@ }, "node_modules/glob-parent": { "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -1867,6 +2103,8 @@ }, "node_modules/globals": { "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "license": "MIT", "dependencies": { "type-fest": "^0.20.2" @@ -1880,6 +2118,8 @@ }, "node_modules/globalthis": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "license": "MIT", "dependencies": { "define-properties": "^1.1.3" @@ -1893,6 +2133,8 @@ }, "node_modules/globby": { "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "license": "MIT", "dependencies": { "array-union": "^2.1.0", @@ -1911,6 +2153,8 @@ }, "node_modules/gopd": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" @@ -1921,14 +2165,20 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, "node_modules/grapheme-splitter": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "license": "MIT" }, "node_modules/has": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "license": "MIT", "dependencies": { "function-bind": "^1.1.1" @@ -1939,6 +2189,8 @@ }, "node_modules/has-bigints": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1946,6 +2198,8 @@ }, "node_modules/has-flag": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", "engines": { "node": ">=8" @@ -1953,6 +2207,8 @@ }, "node_modules/has-property-descriptors": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.1" @@ -1963,6 +2219,8 @@ }, "node_modules/has-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -1973,6 +2231,8 @@ }, "node_modules/has-symbols": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -1983,6 +2243,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" @@ -2005,6 +2267,8 @@ }, "node_modules/human-signals": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", "license": "Apache-2.0", "engines": { "node": ">=14.18.0" @@ -2012,6 +2276,8 @@ }, "node_modules/ignore": { "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "license": "MIT", "engines": { "node": ">= 4" @@ -2024,6 +2290,8 @@ }, "node_modules/import-fresh": { "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -2038,6 +2306,8 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "license": "MIT", "engines": { "node": ">=0.8.19" @@ -2045,6 +2315,8 @@ }, "node_modules/inflight": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -2053,6 +2325,8 @@ }, "node_modules/inherits": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/inline-style-parser": { @@ -2062,6 +2336,8 @@ }, "node_modules/internal-slot": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.0", @@ -2074,6 +2350,8 @@ }, "node_modules/is-arguments": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -2088,6 +2366,8 @@ }, "node_modules/is-array-buffer": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -2100,6 +2380,8 @@ }, "node_modules/is-bigint": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "license": "MIT", "dependencies": { "has-bigints": "^1.0.1" @@ -2110,6 +2392,8 @@ }, "node_modules/is-boolean-object": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -2146,6 +2430,8 @@ }, "node_modules/is-callable": { "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -2156,6 +2442,8 @@ }, "node_modules/is-core-module": { "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", "license": "MIT", "dependencies": { "has": "^1.0.3" @@ -2166,6 +2454,8 @@ }, "node_modules/is-date-object": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" @@ -2179,6 +2469,8 @@ }, "node_modules/is-docker": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "license": "MIT", "bin": { "is-docker": "cli.js" @@ -2192,6 +2484,8 @@ }, "node_modules/is-extglob": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2199,6 +2493,8 @@ }, "node_modules/is-glob": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -2209,6 +2505,8 @@ }, "node_modules/is-inside-container": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "license": "MIT", "dependencies": { "is-docker": "^3.0.0" @@ -2225,6 +2523,8 @@ }, "node_modules/is-map": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2232,6 +2532,8 @@ }, "node_modules/is-negative-zero": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -2242,6 +2544,8 @@ }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "license": "MIT", "engines": { "node": ">=0.12.0" @@ -2249,6 +2553,8 @@ }, "node_modules/is-number-object": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" @@ -2262,6 +2568,8 @@ }, "node_modules/is-path-inside": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "license": "MIT", "engines": { "node": ">=8" @@ -2280,6 +2588,8 @@ }, "node_modules/is-regex": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -2294,6 +2604,8 @@ }, "node_modules/is-set": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2301,6 +2613,8 @@ }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2" @@ -2311,6 +2625,8 @@ }, "node_modules/is-stream": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -2321,6 +2637,8 @@ }, "node_modules/is-string": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" @@ -2334,6 +2652,8 @@ }, "node_modules/is-symbol": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" @@ -2347,6 +2667,8 @@ }, "node_modules/is-typed-array": { "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.5", @@ -2364,6 +2686,8 @@ }, "node_modules/is-weakmap": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2371,6 +2695,8 @@ }, "node_modules/is-weakref": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2" @@ -2381,6 +2707,8 @@ }, "node_modules/is-weakset": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -2392,6 +2720,8 @@ }, "node_modules/is-wsl": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "license": "MIT", "dependencies": { "is-docker": "^2.0.0" @@ -2402,6 +2732,8 @@ }, "node_modules/is-wsl/node_modules/is-docker": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "license": "MIT", "bin": { "is-docker": "cli.js" @@ -2415,10 +2747,14 @@ }, "node_modules/isarray": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/js-sdsl": { @@ -2431,10 +2767,14 @@ }, "node_modules/js-tokens": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -2445,14 +2785,20 @@ }, "node_modules/json-schema-traverse": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "license": "MIT" }, "node_modules/json5": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "license": "MIT", "dependencies": { "minimist": "^1.2.0" @@ -2463,6 +2809,8 @@ }, "node_modules/jsx-ast-utils": { "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", "license": "MIT", "dependencies": { "array-includes": "^3.1.5", @@ -2493,10 +2841,14 @@ }, "node_modules/language-subtag-registry": { "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", "license": "CC0-1.0" }, "node_modules/language-tags": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", "license": "MIT", "dependencies": { "language-subtag-registry": "~0.3.2" @@ -2504,6 +2856,8 @@ }, "node_modules/levn": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -2523,6 +2877,8 @@ }, "node_modules/locate-path": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -2541,10 +2897,14 @@ }, "node_modules/lodash.merge": { "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "license": "MIT" }, "node_modules/loose-envify": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -2555,6 +2915,8 @@ }, "node_modules/lru-cache": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -2633,10 +2995,14 @@ }, "node_modules/merge-stream": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "license": "MIT", "engines": { "node": ">= 8" @@ -3065,6 +3431,8 @@ }, "node_modules/micromatch": { "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "license": "MIT", "dependencies": { "braces": "^3.0.2", @@ -3076,6 +3444,8 @@ }, "node_modules/mime-db": { "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -3083,6 +3453,8 @@ }, "node_modules/mime-types": { "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -3093,6 +3465,8 @@ }, "node_modules/mimic-fn": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "license": "MIT", "engines": { "node": ">=12" @@ -3103,6 +3477,8 @@ }, "node_modules/minimatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -3113,6 +3489,8 @@ }, "node_modules/minimist": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3120,8 +3498,15 @@ }, "node_modules/mitt": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", + "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==", "license": "MIT" }, + "node_modules/mixpanel-browser": { + "version": "2.47.0", + "resolved": "https://registry.npmjs.org/mixpanel-browser/-/mixpanel-browser-2.47.0.tgz", + "integrity": "sha512-Ldrva0fRBEIFWmEibBQO1PulfpJVF3pf28Guk09lDirDaSQqqU/xs9zQLwN2rL5VwVtsP1aD3JaCgaa98EjojQ==" + }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -3151,10 +3536,14 @@ }, "node_modules/ms": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "funding": [ { "type": "github", @@ -3171,10 +3560,14 @@ }, "node_modules/natural-compare": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "license": "MIT" }, "node_modules/next": { "version": "13.4.2", + "resolved": "https://registry.npmjs.org/next/-/next-13.4.2.tgz", + "integrity": "sha512-aNFqLs3a3nTGvLWlO9SUhCuMUHVPSFQC0+tDNGAsDXqx+WJDFSbvc233gOJ5H19SBc7nw36A9LwQepOJ2u/8Kg==", "license": "MIT", "dependencies": { "@next/env": "13.4.2", @@ -3227,6 +3620,8 @@ }, "node_modules/npm-run-path": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "license": "MIT", "dependencies": { "path-key": "^4.0.0" @@ -3240,6 +3635,8 @@ }, "node_modules/npm-run-path/node_modules/path-key": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "license": "MIT", "engines": { "node": ">=12" @@ -3250,6 +3647,8 @@ }, "node_modules/object-assign": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3257,6 +3656,8 @@ }, "node_modules/object-inspect": { "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3264,6 +3665,8 @@ }, "node_modules/object-is": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -3278,6 +3681,8 @@ }, "node_modules/object-keys": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -3285,6 +3690,8 @@ }, "node_modules/object.assign": { "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -3301,6 +3708,8 @@ }, "node_modules/object.entries": { "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -3313,6 +3722,8 @@ }, "node_modules/object.fromentries": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -3328,6 +3739,8 @@ }, "node_modules/object.hasown": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", "license": "MIT", "dependencies": { "define-properties": "^1.1.4", @@ -3339,6 +3752,8 @@ }, "node_modules/object.values": { "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -3354,6 +3769,8 @@ }, "node_modules/once": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "license": "ISC", "dependencies": { "wrappy": "1" @@ -3361,6 +3778,8 @@ }, "node_modules/onetime": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "license": "MIT", "dependencies": { "mimic-fn": "^4.0.0" @@ -3374,6 +3793,8 @@ }, "node_modules/open": { "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", "license": "MIT", "dependencies": { "default-browser": "^4.0.0", @@ -3390,6 +3811,8 @@ }, "node_modules/optionator": { "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -3405,6 +3828,8 @@ }, "node_modules/p-limit": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -3418,6 +3843,8 @@ }, "node_modules/p-locate": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -3436,6 +3863,8 @@ }, "node_modules/parent-module": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -3446,6 +3875,8 @@ }, "node_modules/path-exists": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "license": "MIT", "engines": { "node": ">=8" @@ -3453,6 +3884,8 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3460,6 +3893,8 @@ }, "node_modules/path-key": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { "node": ">=8" @@ -3467,10 +3902,14 @@ }, "node_modules/path-parse": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "license": "MIT", "engines": { "node": ">=8" @@ -3478,10 +3917,14 @@ }, "node_modules/picocolors": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -3490,8 +3933,20 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/postcss": { "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", "funding": [ { "type": "opencollective", @@ -3514,6 +3969,8 @@ }, "node_modules/prelude-ls": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -3526,6 +3983,8 @@ }, "node_modules/prop-types": { "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -3544,10 +4003,14 @@ }, "node_modules/proxy-from-env": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, "node_modules/punycode": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "license": "MIT", "engines": { "node": ">=6" @@ -3555,6 +4018,8 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "funding": [ { "type": "github", @@ -3573,6 +4038,8 @@ }, "node_modules/react": { "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -3595,6 +4062,8 @@ }, "node_modules/react-dom": { "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", @@ -3635,6 +4104,8 @@ }, "node_modules/react-is": { "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, "node_modules/react-markdown": { @@ -3693,8 +4164,18 @@ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-tippy": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/react-tippy/-/react-tippy-1.4.0.tgz", + "integrity": "sha512-r/hM5XK9Ztr2ZY7IWKuRmISTlUPS/R6ddz6PO2EuxCgW+4JBcGZRPU06XcVPRDCOIiio8ryBQFrXMhFMhsuaHA==", + "dependencies": { + "popper.js": "^1.11.1" + } + }, "node_modules/react-toastify": { "version": "9.1.3", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", + "integrity": "sha512-fPfb8ghtn/XMxw3LkxQBk3IyagNpF/LIKjOBflbexr2AWxAH1MJgvnESwEwBn9liLFXgTKWgBSdZpw9m4OTHTg==", "license": "MIT", "dependencies": { "clsx": "^1.1.1" @@ -3725,10 +4206,14 @@ }, "node_modules/regenerator-runtime": { "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", "license": "MIT" }, "node_modules/regexp.prototype.flags": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -3773,6 +4258,8 @@ }, "node_modules/resolve": { "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", "license": "MIT", "dependencies": { "is-core-module": "^2.11.0", @@ -3788,6 +4275,8 @@ }, "node_modules/resolve-from": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "license": "MIT", "engines": { "node": ">=4" @@ -3795,6 +4284,8 @@ }, "node_modules/reusify": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -3803,6 +4294,8 @@ }, "node_modules/rimraf": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -3816,6 +4309,8 @@ }, "node_modules/run-applescript": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", "license": "MIT", "dependencies": { "execa": "^5.0.0" @@ -3829,6 +4324,8 @@ }, "node_modules/run-applescript/node_modules/execa": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", @@ -3850,6 +4347,8 @@ }, "node_modules/run-applescript/node_modules/human-signals": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "license": "Apache-2.0", "engines": { "node": ">=10.17.0" @@ -3857,6 +4356,8 @@ }, "node_modules/run-applescript/node_modules/is-stream": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "license": "MIT", "engines": { "node": ">=8" @@ -3867,6 +4368,8 @@ }, "node_modules/run-applescript/node_modules/mimic-fn": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "license": "MIT", "engines": { "node": ">=6" @@ -3874,6 +4377,8 @@ }, "node_modules/run-applescript/node_modules/npm-run-path": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "license": "MIT", "dependencies": { "path-key": "^3.0.0" @@ -3884,6 +4389,8 @@ }, "node_modules/run-applescript/node_modules/onetime": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -3897,6 +4404,8 @@ }, "node_modules/run-applescript/node_modules/strip-final-newline": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "license": "MIT", "engines": { "node": ">=6" @@ -3904,6 +4413,8 @@ }, "node_modules/run-parallel": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "funding": [ { "type": "github", @@ -3941,6 +4452,8 @@ }, "node_modules/safe-regex-test": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -3953,6 +4466,8 @@ }, "node_modules/scheduler": { "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -3960,6 +4475,8 @@ }, "node_modules/semver": { "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" @@ -3978,6 +4495,8 @@ }, "node_modules/shebang-command": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -3988,6 +4507,8 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { "node": ">=8" @@ -3995,6 +4516,8 @@ }, "node_modules/side-channel": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "license": "MIT", "dependencies": { "call-bind": "^1.0.0", @@ -4007,6 +4530,8 @@ }, "node_modules/signal-exit": { "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, "node_modules/size-sensor": { @@ -4016,6 +4541,8 @@ }, "node_modules/slash": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "license": "MIT", "engines": { "node": ">=8" @@ -4023,6 +4550,8 @@ }, "node_modules/source-map-js": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -4039,6 +4568,8 @@ }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", "license": "MIT", "dependencies": { "internal-slot": "^1.0.4" @@ -4049,6 +4580,8 @@ }, "node_modules/streamsearch": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", "engines": { "node": ">=10.0.0" } @@ -4063,6 +4596,8 @@ }, "node_modules/string.prototype.matchall": { "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -4080,6 +4615,8 @@ }, "node_modules/string.prototype.trim": { "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -4095,6 +4632,8 @@ }, "node_modules/string.prototype.trimend": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -4107,6 +4646,8 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -4119,6 +4660,8 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -4129,6 +4672,8 @@ }, "node_modules/strip-bom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "license": "MIT", "engines": { "node": ">=4" @@ -4136,6 +4681,8 @@ }, "node_modules/strip-final-newline": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "license": "MIT", "engines": { "node": ">=12" @@ -4146,6 +4693,8 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "license": "MIT", "engines": { "node": ">=8" @@ -4164,6 +4713,8 @@ }, "node_modules/styled-jsx": { "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", "license": "MIT", "dependencies": { "client-only": "0.0.1" @@ -4185,6 +4736,8 @@ }, "node_modules/supports-color": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -4195,6 +4748,8 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -4205,6 +4760,8 @@ }, "node_modules/synckit": { "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", "license": "MIT", "dependencies": { "@pkgr/utils": "^2.3.1", @@ -4219,6 +4776,8 @@ }, "node_modules/tapable": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "license": "MIT", "engines": { "node": ">=6" @@ -4226,10 +4785,14 @@ }, "node_modules/text-table": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "license": "MIT" }, "node_modules/titleize": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", "license": "MIT", "engines": { "node": ">=12" @@ -4240,6 +4803,8 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -4268,6 +4833,8 @@ }, "node_modules/tsconfig-paths": { "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", @@ -4282,6 +4849,8 @@ }, "node_modules/tsutils": { "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "license": "MIT", "dependencies": { "tslib": "^1.8.1" @@ -4295,10 +4864,14 @@ }, "node_modules/tsutils/node_modules/tslib": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -4309,6 +4882,8 @@ }, "node_modules/type-fest": { "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -4319,6 +4894,8 @@ }, "node_modules/typed-array-length": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -4343,6 +4920,8 @@ }, "node_modules/unbox-primitive": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -4446,6 +5025,8 @@ }, "node_modules/untildify": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "license": "MIT", "engines": { "node": ">=8" @@ -4453,6 +5034,8 @@ }, "node_modules/uri-js": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -4510,6 +5093,8 @@ }, "node_modules/which": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -4523,6 +5108,8 @@ }, "node_modules/which-boxed-primitive": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", @@ -4537,6 +5124,8 @@ }, "node_modules/which-collection": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", "license": "MIT", "dependencies": { "is-map": "^2.0.1", @@ -4550,6 +5139,8 @@ }, "node_modules/which-typed-array": { "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.5", @@ -4568,6 +5159,8 @@ }, "node_modules/word-wrap": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -4575,14 +5168,20 @@ }, "node_modules/wrappy": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, "node_modules/yallist": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" }, "node_modules/yocto-queue": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "license": "MIT", "engines": { "node": ">=10" @@ -4593,6 +5192,8 @@ }, "node_modules/zod": { "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/gui/package.json b/gui/package.json index f788aee8d..4825d1b8a 100644 --- a/gui/package.json +++ b/gui/package.json @@ -20,6 +20,7 @@ "eslint-config-next": "13.4.2", "jszip": "^3.10.1", "mitt": "^3.0.0", + "mixpanel-browser": "^2.47.0", "moment": "^2.29.4", "moment-timezone": "^0.5.43", "next": "13.4.2", @@ -30,6 +31,7 @@ "react-grid-layout": "^1.3.4", "react-markdown": "^8.0.7", "react-spinners": "^0.13.8", + "react-tippy": "^1.4.0", "react-toastify": "^9.1.3" } } diff --git a/gui/pages/Content/APM/ApmDashboard.js b/gui/pages/Content/APM/ApmDashboard.js index c82b9b820..535de9ad8 100644 --- a/gui/pages/Content/APM/ApmDashboard.js +++ b/gui/pages/Content/APM/ApmDashboard.js @@ -8,6 +8,7 @@ import {BarGraph} from "./BarGraph.js"; import {WidthProvider, Responsive} from 'react-grid-layout'; import 'react-grid-layout/css/styles.css'; import 'react-resizable/css/styles.css'; +import { Tooltip } from 'react-tippy'; const ResponsiveGridLayout = WidthProvider(Responsive); @@ -75,7 +76,7 @@ export default function ApmDashboard() { const fetchData = async () => { try { const [metricsResponse, agentsResponse, activeRunsResponse, toolsUsageResponse] = await Promise.all([getMetrics(), getAllAgents(), getActiveRuns(), getToolsUsage()]); - const models = ['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k', 'gpt-4-32k', 'google-palm-bison-001', 'replicate-llama13b-v2-chat']; + const models = ['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k', 'gpt-4-32k', 'google-palm-bison-001']; assignDefaultDataPerModel(metricsResponse.data.agent_details.model_metrics, models); assignDefaultDataPerModel(metricsResponse.data.tokens_details.model_metrics, models); @@ -97,6 +98,10 @@ export default function ApmDashboard() { return () => clearInterval(interval); }, []); + useEffect(() => { + console.log(toolsUsed) + }, [toolsUsed]); + const handleSelectedAgent = useCallback((index, name) => { setDropDown1(false) setDropDown2(false) @@ -227,8 +232,8 @@ export default function ApmDashboard() { src={returnToolkitIcon(tool.toolkit)} alt="tool-icon"/> {tool.tool_name} - {tool.unique_agents} - {tool.total_usage} + {tool.unique_agents} + {tool.total_usage} ))} @@ -250,20 +255,13 @@ export default function ApmDashboard() { Agent Name - Model - - Tokens Consumed - - Runs - - Avg tokens per run - - Tools - - Calls - - Avg Run Time - + Model + Tokens Consumed + Runs + Avg tokens per run + Tools + Calls + Avg Run Time @@ -274,31 +272,41 @@ export default function ApmDashboard() { {allAgents.map((run, i) => ( {run.name} - {run.model_name} - {formatNumber(run.total_tokens)} - {run.runs_completed} - - {run.runs_completed ? (run.total_tokens / run.runs_completed).toFixed(1) : '-'} + {run.model_name} + {formatNumber(run.total_tokens)} + {run.runs_completed} + + {run.runs_completed ? formatNumber((run.total_tokens / run.runs_completed).toFixed(1)) : '-'} - + {run.tools_used && run.tools_used.slice(0, 3).map((tool, index) => (
{tool}
))} {run.tools_used && run.tools_used.length > 3 &&
- {(showToolTip && toolTipIndex === i) &&
- {run.tools_used.slice(3).map((tool,index) => -
{tool}
- )} -
} -
setToolTipState(true,i)} onMouseLeave={() => setToolTipState(false,i)}> - +{run.tools_used.length - 3} -
+ +
+ {run.tools_used.slice(3).map((tool,index) => +
{tool}
+ )} +
+ + } + > +
+ +{run.tools_used.length - 3} +
+
} - {run.total_calls} - + {run.total_calls} + {run.avg_run_time === 0 ? '-' : `${parseFloat((run.avg_run_time / 60).toFixed(1))} mins`} ))} diff --git a/gui/pages/Content/Agents/ActivityFeed.js b/gui/pages/Content/Agents/ActivityFeed.js index 02bfb44e9..36b0b7c91 100644 --- a/gui/pages/Content/Agents/ActivityFeed.js +++ b/gui/pages/Content/Agents/ActivityFeed.js @@ -2,11 +2,11 @@ import React, {useEffect, useRef, useState} from 'react'; import styles from './Agents.module.css'; import {getExecutionFeeds, getDateTime} from "@/pages/api/DashboardService"; import Image from "next/image"; -import {loadingTextEffect, formatTimeDifference} from "@/utils/utils"; +import {loadingTextEffect, formatTimeDifference, convertWaitingPeriod, updateDateBasedOnValue} from "@/utils/utils"; import {EventBus} from "@/utils/eventBus"; import {ClipLoader} from 'react-spinners'; -export default function ActivityFeed({selectedRunId, selectedView, setFetchedData, agent}) { +export default function ActivityFeed({selectedRunId, selectedView, setFetchedData, agent, selectedRunStatus}) { const [loadingText, setLoadingText] = useState("Thinking"); const [feeds, setFeeds] = useState([]); const feedContainerRef = useRef(null); @@ -15,14 +15,18 @@ export default function ActivityFeed({selectedRunId, selectedView, setFetchedDat const [scheduleDate, setScheduleDate] = useState(null); const [scheduleTime, setScheduleTime] = useState(null); const [isLoading, setIsLoading] = useState(true); + const [waitingPeriod, setWaitingPeriod] = useState(null); + const [errorMsg, setErrorMsg] = useState(''); useEffect(() => { const interval = window.setInterval(function () { - fetchFeeds(); + if (selectedRunStatus !== "ERROR_PAUSED") { + fetchFeeds(); + } }, 5000); return () => clearInterval(interval); - }, [selectedRunId]); + }, [selectedRunId, selectedRunStatus]); function fetchDateTime() { getDateTime(agent.id) @@ -80,8 +84,10 @@ export default function ActivityFeed({selectedRunId, selectedView, setFetchedDat .then((response) => { const data = response.data; setFeeds(data.feeds); + setErrorMsg(data.errors) setRunStatus(data.status); setFetchedData(data.permissions); + setWaitingPeriod(data.waiting_period ? data.waiting_period : null) EventBus.emit('resetRunStatus', {executionId: selectedRunId, status: data.status}); setIsLoading(false); //add this line }) @@ -142,27 +148,41 @@ export default function ActivityFeed({selectedRunId, selectedView, setFetchedDat } ))} + {runStatus === 'WAIT_STEP' && +
+
+
+
Waiting Block Initiated. The Agent will wait for {convertWaitingPeriod(waitingPeriod) || null}
+
+
} {runStatus === 'RUNNING' && -
+
-
🧠
+
🧠
{loadingText}
} {runStatus === 'COMPLETED' && -
+
-
🏁
+
🏁
All goals completed successfully!
} {runStatus === 'ITERATION_LIMIT_EXCEEDED' && -
+
-
⚠️
+
⚠️
Stopped: Maximum iterations exceeded!
} + {runStatus === 'ERROR_PAUSED' && +
+
+
+
{errorMsg}
+
+
}
} {feeds.length < 1 && !agent?.is_running && !agent?.is_scheduled && diff --git a/gui/pages/Content/Agents/AgentCreate.js b/gui/pages/Content/Agents/AgentCreate.js index 1f5afa3d1..234d903e0 100644 --- a/gui/pages/Content/Agents/AgentCreate.js +++ b/gui/pages/Content/Agents/AgentCreate.js @@ -11,15 +11,9 @@ import { updateExecution, uploadFile, getAgentDetails, addAgentRun, fetchModels, - getAgentWorkflows, validateOrAddModels, publishTemplateToMarketplace + getAgentWorkflows, publishTemplateToMarketplace } from "@/pages/api/DashboardService"; -import { - formatBytes, - openNewTab, - removeTab, - setLocalStorageValue, - setLocalStorageArray, returnResourceIcon, getUserTimezone, createInternalId, preventDefault, excludedToolkits -} from "@/utils/utils"; +import {formatBytes, openNewTab, removeTab, setLocalStorageValue, setLocalStorageArray, returnResourceIcon, getUserTimezone, createInternalId, preventDefault, excludedToolkits, getUserClick} from "@/utils/utils"; import {EventBus} from "@/utils/eventBus"; import styles from "@/pages/Content/Agents/Agents.module.css"; import styles1 from "@/pages/Content/Knowledge/Knowledge.module.css"; @@ -536,6 +530,8 @@ export default function AgentCreate({ const name = response.data.name; const executionId = response.data.execution_id; fetchAgents(); + getUserClick('Agent Created Successfully', {}) + getUserClick('Agent Run created successfully', {}) uploadResources(agentId, name, executionId) }) .catch((error) => { @@ -1366,7 +1362,7 @@ export default function AgentCreate({
+ onClick={() => {handleAddAgent();}}>{createClickable ? 'Create and Run' : 'Creating Agent...'}
diff --git a/gui/pages/Content/Agents/RunHistory.js b/gui/pages/Content/Agents/RunHistory.js index 5f05abc3e..e2411ac45 100644 --- a/gui/pages/Content/Agents/RunHistory.js +++ b/gui/pages/Content/Agents/RunHistory.js @@ -35,7 +35,7 @@ export default function RunHistory({runs, setHistory, selectedRunId, setSelected
- {runs && runs.map((run) => (
setSelectedRun(run)} className={selectedRunId === run.id ? 'history_box_selected' : 'history_box'}> + {runs && runs.map((run) => (
setSelectedRun(run)} className={selectedRunId === run.id ? 'history_box_selected padding_10' : 'history_box padding_10'}>
{run.status === 'RUNNING' && loading-icon}
{run.name}
diff --git a/gui/pages/Content/Knowledge/Knowledge.js b/gui/pages/Content/Knowledge/Knowledge.js index a90a50b93..4522d9457 100644 --- a/gui/pages/Content/Knowledge/Knowledge.js +++ b/gui/pages/Content/Knowledge/Knowledge.js @@ -2,7 +2,7 @@ import React from 'react'; import Image from "next/image"; import styles from '../Toolkits/Tool.module.css'; import styles1 from '../Agents/Agents.module.css' -import {createInternalId} from "@/utils/utils"; +import {createInternalId, getUserClick} from "@/utils/utils"; export default function Knowledge({sendKnowledgeData, knowledge}) { return ( @@ -10,12 +10,12 @@ export default function Knowledge({sendKnowledgeData, knowledge}) {

Knowledges

-
diff --git a/gui/pages/Content/Knowledge/KnowledgeForm.js b/gui/pages/Content/Knowledge/KnowledgeForm.js index 3362c0c42..f11f5d46a 100644 --- a/gui/pages/Content/Knowledge/KnowledgeForm.js +++ b/gui/pages/Content/Knowledge/KnowledgeForm.js @@ -1,6 +1,6 @@ import React, {useState, useEffect, useRef} from 'react'; import styles1 from '@/pages/Content/Knowledge/Knowledge.module.css' -import {removeTab, setLocalStorageValue, setLocalStorageArray, createInternalId} from "@/utils/utils"; +import {removeTab, setLocalStorageValue, setLocalStorageArray, createInternalId, getUserClick} from "@/utils/utils"; import styles from "@/pages/Content/Agents/Agents.module.css"; import Image from "next/image"; import {ToastContainer, toast} from "react-toastify"; @@ -101,6 +101,7 @@ export default function KnowledgeForm({ internalId: createInternalId() }); EventBus.emit('reFetchKnowledge', {}); + getUserClick('Knowledge Added Successfully', {}) }) .catch((error) => { toast.error("Unable to add knowledge", {autoClose: 1800}); diff --git a/gui/pages/Content/Marketplace/AgentTemplate.js b/gui/pages/Content/Marketplace/AgentTemplate.js index d1b3cfade..b067b1638 100644 --- a/gui/pages/Content/Marketplace/AgentTemplate.js +++ b/gui/pages/Content/Marketplace/AgentTemplate.js @@ -8,7 +8,7 @@ import styles2 from "./Market.module.css" import {fetchAgentTemplateConfig, installAgentTemplate} from "@/pages/api/DashboardService"; import {EventBus} from "@/utils/eventBus"; import axios from 'axios'; -import {loadingTextEffect} from "@/utils/utils"; +import {getUserClick, loadingTextEffect} from "@/utils/utils"; export default function AgentTemplate({template, env}) { const [tools, setTools] = useState([]) @@ -60,6 +60,7 @@ export default function AgentTemplate({template, env}) { function handleInstallClick() { setIsInstalled(true) + getUserClick("Agent Template Installed",{"Agent Template Name": template.name}) if (window.location.href.toLowerCase().includes('marketplace')) { localStorage.setItem('agent_to_install', template.id); if (env === 'PROD') { diff --git a/gui/pages/Content/Marketplace/Market.js b/gui/pages/Content/Marketplace/Market.js index 9ab03a4ed..7d20b821a 100644 --- a/gui/pages/Content/Marketplace/Market.js +++ b/gui/pages/Content/Marketplace/Market.js @@ -12,7 +12,7 @@ import AgentTemplate from "./AgentTemplate"; import KnowledgeTemplate from "./KnowledgeTemplate"; import {setLocalStorageValue, setLocalStorageArray} from "@/utils/utils"; -export default function Market({env}) { +export default function Market({env, getModels, sendModelData}) { const [activeTab, setActiveTab] = useState('market_tools'); const [itemClicked, setItemClicked] = useState(false); const [templateData, setTemplateData] = useState([]); @@ -36,16 +36,6 @@ export default function Market({env}) { } } - const handleOpenTemplateDetails = ({item, contentType}) => { - setLocalStorageValue('market_detail_type', contentType, setDetailType); - setLocalStorageArray('market_item', item, setTemplateData); - setLocalStorageValue('market_item_clicked', true, setItemClicked); - }; - - const handleBackClick = () => { - setLocalStorageValue('market_item_clicked', false, setItemClicked); - } - EventBus.on('openTemplateDetails', handleOpenTemplateDetails); EventBus.on('goToMarketplace', handleBackClick); @@ -60,44 +50,67 @@ export default function Market({env}) { localStorage.setItem('marketplace_tab', tab); }; + const tabData = [ + { id: 'market_tools', label: 'Tools', image: '/images/tools_light.svg' }, + { id: 'market_knowledge', label: 'Knowledge', image: '/images/knowledge.svg' }, + { id: 'market_agents', label: 'Agent Templates', image: '/images/agents_light.svg' }, + { id: 'market_models', label: 'Models', image: '/images/models.svg' }, + ]; + + const renderTab = (tab) => { + return ( + + ); + }; + + const handleOpenTemplateDetails = ({ item, contentType }) => { + localStorage.setItem('market_detail_type', contentType); + setDetailType(contentType); + localStorage.setItem('market_item', JSON.stringify(item)); + setTemplateData(item); + localStorage.setItem('market_item_clicked', true); + setItemClicked(true); + }; + + const handleBackClick = () => { + localStorage.setItem('market_item_clicked', false); + setItemClicked(false); + }; + return ( -
- {!itemClicked ?
-
-
-
- - - - +
+ {!itemClicked ? ( +
+
+
+
+ {tabData.map(renderTab)} +
+
+
+ {activeTab === 'market_tools' && } + {activeTab === 'market_knowledge' && } + {activeTab === 'market_agents' && } + {activeTab === 'market_models' && } +
+
+
+ ) : ( +
+ {detailType === 'agent_template' && } + {detailType === 'knowledge_template' && } + {detailType === 'tool_template' && } + {detailType === 'model_template' && }
-
-
- {activeTab === 'market_tools' && } - {activeTab === 'market_knowledge' && } - {activeTab === 'market_agents' && } - {activeTab === 'market_models' && } -
-
-
:
- {detailType === 'agent_template' && } - {detailType === 'knowledge_template' && } - {detailType === 'tool_template' && } - {detailType === 'model_template' && } -
} -
+ )} +
); -}; +} diff --git a/gui/pages/Content/Marketplace/MarketAgent.js b/gui/pages/Content/Marketplace/MarketAgent.js index 3055ebd27..cff2cf6b0 100644 --- a/gui/pages/Content/Marketplace/MarketAgent.js +++ b/gui/pages/Content/Marketplace/MarketAgent.js @@ -2,7 +2,7 @@ import React, {useEffect, useState} from "react"; import Image from "next/image"; import {fetchAgentTemplateList} from "@/pages/api/DashboardService"; import {EventBus} from "@/utils/eventBus"; -import {loadingTextEffect} from "@/utils/utils"; +import {loadingTextEffect, getUserClick} from "@/utils/utils"; import axios from 'axios'; export default function MarketAgent() { @@ -39,6 +39,7 @@ export default function MarketAgent() { }, []); function handleTemplateClick(item) { + getUserClick("Marketplace Agent Template Viewed", {"Agent Template Name": item.name}) const contentType = 'agent_template'; EventBus.emit('openTemplateDetails', {item, contentType}); } diff --git a/gui/pages/Content/Models/AddModelMarketPlace.js b/gui/pages/Content/Models/AddModelMarketPlace.js index 6365c06ba..79981feef 100644 --- a/gui/pages/Content/Models/AddModelMarketPlace.js +++ b/gui/pages/Content/Models/AddModelMarketPlace.js @@ -1,15 +1,15 @@ import React, {useState, useEffect} from "react"; import Image from "next/image"; -import {openNewTab, modelIcon} from "@/utils/utils"; +import {openNewTab, modelIcon, modelGetAuth} from "@/utils/utils"; import {fetchApiKey, storeModel} from "@/pages/api/DashboardService"; import {toast} from "react-toastify"; -export default function AddModelMarketPlace(template){ +export default function AddModelMarketPlace({ template, getModels, sendModelData }){ const [modelTokenLimit, setModelTokenLimit] = useState(4096); const [modelVersion, setModelVersion] = useState(''); const [modelEndpoint, setModelEndpoint] = useState(''); const [tokenError, setTokenError] = useState(false); - const [templateData, setTemplateData] = useState(template.template); + const [templateData, setTemplateData] = useState(template); const [isLoading, setIsLoading] = useState(false); const [providerId, setProviderId] = useState(1); const [disableInstall, setDisableInstall] = useState(false); @@ -27,27 +27,32 @@ export default function AddModelMarketPlace(template){ },[]) const checkModelProvider = async () => { - const response = await fetchApiKey(templateData.provider); - console.log(response.data) - if(response.data.length === 0) { - setTokenError(true) - return true - } - else { - setTokenError(false) - setProviderId(response.data[0].id) - return false + if(templateData){ + const response = await fetchApiKey(templateData.provider); + console.log(response.data) + if(response.data.length === 0) { + setTokenError(true) + return true + } + else { + setTokenError(false) + setProviderId(response.data[0].id) + return false + } } } const storeModelDetails = () => { storeModel(templateData.model_name, templateData.description, modelEndpoint, providerId, modelTokenLimit, "Marketplace", modelVersion).then((response) =>{ setIsLoading(false) - console.log(response) - if (response.data.error) { - toast.error(response.data.error,{autoClose: 1800}); - } else if (response.data.success) { - toast.success(response.data.success,{autoClose: 1800}); + let data = response.data + if (data.error) { + toast.error(data.error,{autoClose: 1800}); + } else if (data.success) { + toast.success(data.success,{autoClose: 1800}); + getModels() + console.log(data) + handleModelSuccess({id: data.model_id, name: templateData.model_name}) } }).catch((error) => { console.log("SORRY, There was an error storing the model details" + error); @@ -55,21 +60,27 @@ export default function AddModelMarketPlace(template){ }); } + const handleModelSuccess = (model) => { + model.contentType = 'Model' + sendModelData(model) + } + return(
-
+ {templateData &&
Add Model
{templateData.model_name}
- By {templateData.provider} ·  - logo-icon + By {templateData.model_name.includes('/') ? templateData.model_name.split('/')[0] : templateData.provider}· + logo-icon {templateData.provider}
+ {templateData.provider === 'Hugging Face' &&
{templateData.provider} Model Endpoint The {templateData.provider} auth token is not added to your settings. In order to start using the model, you need to add the auth token to your settings. You can find the auth token in the {templateData.provider} dashboard.
- +
} @@ -108,7 +121,7 @@ export default function AddModelMarketPlace(template){ -
+
}
diff --git a/gui/pages/Content/Models/ModelForm.js b/gui/pages/Content/Models/ModelForm.js index 1318bbbc1..13ed87d82 100644 --- a/gui/pages/Content/Models/ModelForm.js +++ b/gui/pages/Content/Models/ModelForm.js @@ -6,12 +6,8 @@ import {BeatLoader, ClipLoader} from "react-spinners"; import {ToastContainer, toast} from 'react-toastify'; export default function ModelForm({internalId, getModels, sendModelData}){ - const models = [{'provider':'OpenAI','link':'https://platform.openai.com/account/api-keys'}, - {'provider':'Replicate','link':'https://replicate.com/account/api-tokens'}, - {'provider':'Hugging Face','link':'https://huggingface.co/settings/tokens'}, - {'provider':'Google Palm','link':'https://developers.generativeai.google/products/palm'}]; + const models = ['OpenAI', 'Replicate', 'Hugging Face', 'Google Palm']; const [selectedModel, setSelectedModel] = useState('Select a Model'); - const [selectedLink, setSelectedLink] = useState(''); const [modelName, setModelName] = useState(''); const [modelDescription, setModelDescription] = useState(''); const [modelTokenLimit, setModelTokenLimit] = useState(4096); @@ -44,8 +40,7 @@ export default function ModelForm({internalId, getModels, sendModelData}){ },[selectedModel]) const handleModelSelect = async (index) => { - setSelectedModel(models[index].provider) - setSelectedLink(models[index].link) + setSelectedModel(models[index]) setModelDropdown(false); } @@ -128,7 +123,7 @@ export default function ModelForm({internalId, getModels, sendModelData}){ {modelDropdown &&
{models.map((model, index) => (
handleModelSelect(index)} style={{padding: '12px 14px', maxWidth: '100%'}}> - {model.provider} + {model}
))}
}
@@ -139,9 +134,9 @@ export default function ModelForm({internalId, getModels, sendModelData}){
The {selectedModel} auth token is not added to your settings. In order to start using the model, you need to add the auth token to your settings. You can find the auth token in the {selectedModel} dashboard.
- + + onClick={() => window.open(modelGetAuth(selectedModel), "_blank")}>Get auth tokendeploy_icon
} diff --git a/gui/pages/Content/Models/ModelMetrics.js b/gui/pages/Content/Models/ModelMetrics.js index 377ab0e65..cc1a1d2f3 100644 --- a/gui/pages/Content/Models/ModelMetrics.js +++ b/gui/pages/Content/Models/ModelMetrics.js @@ -1,6 +1,6 @@ import React, {useState, useEffect} from "react"; import {fetchModelData} from "@/pages/api/DashboardService"; -import {formatNumber, returnToolkitIcon} from "@/utils/utils"; +import {formatDateTime, formatNumber, returnToolkitIcon} from "@/utils/utils"; import Image from "next/image"; export default function ModelMetrics(modelDetails) { @@ -69,15 +69,15 @@ export default function ModelMetrics(modelDetails) { {modelRunData.map((data, index) => ( - {data.created_at.slice(0, 19).replace('T', ' ')} - {data.agent_name} - {data.agent_execution_name} - + {formatDateTime(data.created_at)} + {data.agent_name} + {data.agent_execution_name} + {data.tool_used && tool-icon} {data.tool_used ? data.tool_used : '-NA-'} - {formatNumber(data.tokens_consumed)} + {formatNumber(data.tokens_consumed)} ))} diff --git a/gui/pages/Content/Models/ModelTemplate.js b/gui/pages/Content/Models/ModelTemplate.js index 8535beced..deb503767 100644 --- a/gui/pages/Content/Models/ModelTemplate.js +++ b/gui/pages/Content/Models/ModelTemplate.js @@ -3,7 +3,7 @@ import Image from "next/image"; import {EventBus} from "@/utils/eventBus"; import {getFormattedDate, modelIcon} from "@/utils/utils"; import AddModelMarketPlace from "./AddModelMarketPlace"; -export default function ModelTemplate({env, template}){ +export default function ModelTemplate({env, template, getModels, sendModelData}){ const [isInstalled, setIsInstalled] = useState(false); function handleBackClick() { @@ -54,7 +54,7 @@ export default function ModelTemplate({env, template}){
):( - + )}
) diff --git a/gui/pages/Content/Models/Models.js b/gui/pages/Content/Models/Models.js index 2c0c91e4e..49b4249ab 100644 --- a/gui/pages/Content/Models/Models.js +++ b/gui/pages/Content/Models/Models.js @@ -5,6 +5,7 @@ import {createInternalId} from "@/utils/utils"; export default function Models({sendModelData, models}){ const handleModelSelect = (model) => { + getUserClick('Existing Model Clicked', {}) model.contentType = 'Model' sendModelData(model) } @@ -15,7 +16,7 @@ export default function Models({sendModelData, models}){

Models

diff --git a/gui/pages/Content/Toolkits/Metrics.js b/gui/pages/Content/Toolkits/Metrics.js index 2887d5d10..27a0d3107 100644 --- a/gui/pages/Content/Toolkits/Metrics.js +++ b/gui/pages/Content/Toolkits/Metrics.js @@ -101,7 +101,7 @@ export default function Metrics({toolName, knowledgeName}) {
Call Logs - {callLogs.length > 0 ?
+ {callLogs.length > 0 ?
@@ -118,11 +118,11 @@ export default function Metrics({toolName, knowledgeName}) { {callLogs.map((item, index) => ( - - - - - + + + + + ))} diff --git a/gui/pages/Dashboard/Content.js b/gui/pages/Dashboard/Content.js index 945ee8b73..0611a7be0 100644 --- a/gui/pages/Dashboard/Content.js +++ b/gui/pages/Dashboard/Content.js @@ -30,7 +30,7 @@ import {useRouter} from 'next/router'; import querystring from 'querystring'; import styles1 from '../Content/Agents/Agents.module.css'; import AddTool from "@/pages/Content/Toolkits/AddTool"; -import {createInternalId, resetLocalStorage, preventDefault} from "@/utils/utils"; +import {createInternalId, resetLocalStorage, preventDefault, getUserClick} from "@/utils/utils"; import AddDatabase from "@/pages/Dashboard/Settings/AddDatabase"; import DatabaseDetails from "@/pages/Dashboard/Settings/DatabaseDetails"; @@ -168,6 +168,9 @@ export default function Content({env, selectedView, selectedProjectId, organisat updatedTabs.splice(index, 1); } + if(contentType === "APM") + getUserClick('APM Closed',{}) + resetLocalStorage(contentType, internalId); setTabs(updatedTabs); }; @@ -345,12 +348,12 @@ export default function Content({env, selectedView, selectedProjectId, organisat
- @@ -450,7 +453,7 @@ export default function Content({env, selectedView, selectedProjectId, organisat } {tab.contentType === 'Settings' && } - {tab.contentType === 'Marketplace' && } + {tab.contentType === 'Marketplace' && } {tab.contentType === 'Add_Toolkit' && } {tab.contentType === 'Add_Knowledge' && } diff --git a/gui/pages/Dashboard/Settings/Model.js b/gui/pages/Dashboard/Settings/Model.js index 77508ef32..672166f2c 100644 --- a/gui/pages/Dashboard/Settings/Model.js +++ b/gui/pages/Dashboard/Settings/Model.js @@ -4,7 +4,7 @@ import 'react-toastify/dist/ReactToastify.css'; import agentStyles from "@/pages/Content/Agents/Agents.module.css"; import {storeApiKey, fetchApiKeys, validateLLMApiKey, fetchApiKey} from "@/pages/api/DashboardService"; import {EventBus} from "@/utils/eventBus"; -import {removeTab} from "@/utils/utils"; +import {getUserClick, removeTab} from "@/utils/utils"; import Image from "next/image"; export default function Model({organisationId}) { @@ -40,7 +40,6 @@ export default function Model({organisationId}) { } validateLLMApiKey(model.source, model.api_key) .then((response) => { - console.log(response) if (response.data.status === "success") { storeKey(model.source, model.api_key) } @@ -55,8 +54,10 @@ export default function Model({organisationId}) { if(model_provider === 'OpenAi') model_provider = 'OpenAI' storeApiKey(model_provider,api_key).then((response) => { - if(response.status === 200) + if(response.status === 200) { + getUserClick('API Key Updated', {'Model': model_provider}) toast.success(`Successfully Stored the API Key of ${model_provider}`, {autoClose: 1800}) + } else toast.error("Error", {autoClose: 1800}) }) diff --git a/gui/pages/Dashboard/SideBar.js b/gui/pages/Dashboard/SideBar.js index d57843f01..ab2cc3ce1 100644 --- a/gui/pages/Dashboard/SideBar.js +++ b/gui/pages/Dashboard/SideBar.js @@ -1,7 +1,7 @@ import React, {useState} from 'react'; import Image from 'next/image'; import styles from './Dashboard.module.css'; -import {openNewTab} from "@/utils/utils"; +import {getUserClick, openNewTab} from "@/utils/utils"; export default function SideBar({onSelectEvent, env}) { const [sectionSelected, setSelection] = useState(''); @@ -15,6 +15,7 @@ export default function SideBar({onSelectEvent, env}) { ]; const handleClick = (value) => { + getUserClick(value + "SIDEBAR ICON", {}) setSelection(value); onSelectEvent(value); if (value === 'apm') { @@ -34,7 +35,7 @@ export default function SideBar({onSelectEvent, env}) {
-
{section.name.charAt(0).toUpperCase() + section.name.slice(1)}
+ {section.name === 'apm' ?
APM
:
{section.name.charAt(0).toUpperCase() + section.name.slice(1)}
}
))} diff --git a/gui/pages/Dashboard/TopBar.js b/gui/pages/Dashboard/TopBar.js index 165027643..917264e02 100644 --- a/gui/pages/Dashboard/TopBar.js +++ b/gui/pages/Dashboard/TopBar.js @@ -4,7 +4,7 @@ import styles from './Dashboard.module.css'; import {useRouter} from 'next/router'; import {ToastContainer, toast} from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; -import {refreshUrl, openNewTab} from "@/utils/utils"; +import {refreshUrl, openNewTab, getUserClick} from "@/utils/utils"; export default function TopBar({selectedProject, userName, env}) { const [dropdown, setDropdown] = useState(false); @@ -16,7 +16,7 @@ export default function TopBar({selectedProject, userName, env}) { if (typeof window === 'undefined') { return; } - + getUserClick('Logged Out',{}) localStorage.removeItem('accessToken'); refreshUrl(); router.reload(); @@ -38,7 +38,7 @@ export default function TopBar({selectedProject, userName, env}) {
-
window.open("https://superagi.com/docs", "_blank")}> +
{window.open("https://superagi.com/docs", "_blank"); getUserClick('SuperAGI Docs Visited', {})}}>

Docs

@@ -54,7 +54,7 @@ export default function TopBar({selectedProject, userName, env}) {
- openNewTab(-3, "Settings", "Settings", false)} className="top_right_icon" width={16} height={16} src="/images/settings.svg" alt="dropdown-icon"/> + {openNewTab(-3, "Settings", "Settings", false); getUserClick('Settings Viewed', {})}} className="top_right_icon" width={16} height={16} src="/images/settings.svg" alt="dropdown-icon"/>
setDropdown(true)} onMouseLeave={() => setDropdown(false)}> diff --git a/gui/pages/_app.css b/gui/pages/_app.css index 8698f03a3..479647a47 100644 --- a/gui/pages/_app.css +++ b/gui/pages/_app.css @@ -907,6 +907,14 @@ p { .fw_500{font-weight: 500;} +.br_4{border-radius: 4px} +.br_5{border-radius: 5px} +.br_6{border-radius: 6px} +.br_8{border-radius: 8px} + +.fs_10{font-size: 10px} +.fs_20{font-size: 20px} + .text_9{ color: #FFF; font-family: Inter; @@ -978,6 +986,14 @@ p { line-height: normal; } +.text_20 { + color: #FFF; + font-size: 20px; + font-style: normal; + font-weight: 400; + line-height: normal; +} + .text_20_bold{ color: #FFF; font-size: 20px; @@ -1138,13 +1154,12 @@ p { .gap_16{gap:16px;} .gap_20{gap:20px;} -.border_gray{border: 1px solid rgba(255, 255, 255, 0.08)} -.border_left_none{border-left: none;} +.br_left_grey{border-left: 1px solid rgba(255, 255, 255, 0.08)} .border_top_none{border-top: none;} .border_bottom_none{border-bottom: none;} .border_bottom_grey{border-bottom: 1px solid rgba(255, 255, 255, 0.08)} -.border_radius_8{border-radius: 8px;} -.border_radius_25{border-radius: 25px;} + +.bt_white{border-top: 1px solid rgba(255, 255, 255, 0.08);} .bt_white{border-top: 1px solid rgba(255, 255, 255, 0.08);} @@ -1154,13 +1169,16 @@ p { .lh_16{line-height: 16px;} .lh_17{line-height: 17px;} .lh_18{line-height: 18px;} +.lh_24{line-height: 24px;} .padding_0{padding: 0} .padding_5{padding: 5px;} +.padding_6{padding: 6px;} .padding_8{padding: 8px;} .padding_10{padding: 10px;} .padding_12{padding: 12px;} .padding_16{padding: 16px;} +.padding_20{padding: 20px;} .padding_8_6{padding: 8px 6px;} .padding_2_8{padding: 2px 8px;} @@ -1385,19 +1403,6 @@ tr{ margin: 2px; } -.tools_used_tooltip{ - position: absolute; - transform: translateX(-50%); - padding: 6px; - color: #fff; - font-size: 12px; - white-space: pre; - z-index: 100; - border-radius: 8px; - background: #2E293F; - margin-top: -40px; -} - .image_class{ background: #FFFFFF80; border-radius: 20px; @@ -1478,8 +1483,11 @@ tr{ } } -.bg_black{background: black} -.bg_white{background: white} +.bg_black{background: black;} +.bg_white{background: white;} +.bg_none{background: none;} +.bg_primary{background: #2E293F;} +.bg_secondary{background: #272335;} .bg_none{background: none} .container { @@ -1796,7 +1804,6 @@ tr{ .history_box, .history_box_selected { width: 100%; - padding: 10px; color: white; font-style: normal; font-weight: 400; @@ -1894,3 +1901,10 @@ tr{ flex-direction: row; justify-content: center; } + +.tooltip-class { + background-color: green; + border-radius: 6px; +} + + diff --git a/gui/pages/_app.js b/gui/pages/_app.js index 6fe6ec6a4..ad98f09bc 100644 --- a/gui/pages/_app.js +++ b/gui/pages/_app.js @@ -14,17 +14,19 @@ import { validateAccessToken, checkEnvironment, addUser, - installToolkitTemplate, installAgentTemplate, installKnowledgeTemplate + installToolkitTemplate, installAgentTemplate, installKnowledgeTemplate, getFirstSignup } from "@/pages/api/DashboardService"; -import {githubClientId} from "@/pages/api/apiConfig"; +import {githubClientId, mixpanelId} from "@/pages/api/apiConfig"; import { getGithubClientId } from "@/pages/api/DashboardService"; import {useRouter} from 'next/router'; import querystring from 'querystring'; -import {refreshUrl, loadingTextEffect} from "@/utils/utils"; +import {refreshUrl, loadingTextEffect, getUTMParametersFromURL, setLocalStorageValue, getUserClick} from "@/utils/utils"; import MarketplacePublic from "./Content/Marketplace/MarketplacePublic" import {toast} from "react-toastify"; +import mixpanel from 'mixpanel-browser'; + export default function App() { const [selectedView, setSelectedView] = useState(''); @@ -101,12 +103,7 @@ export default function App() { } useEffect(() => { - if (window.location.href.toLowerCase().includes('marketplace')) { - setShowMarketplace(true); - } else { - installFromMarketplace(); - } - + handleMarketplace() loadingTextEffect('Initializing SuperAGI', setLoadingText, 500); checkEnvironment() @@ -115,6 +112,8 @@ export default function App() { setEnv(env); if (typeof window !== 'undefined') { + if(response.data.env === 'PROD' && mixpanelId()) + mixpanel.init(mixpanelId(), { debug: false, track_pageview: true, persistence: 'localStorage' }); localStorage.setItem('applicationEnvironment', env); } @@ -123,35 +122,37 @@ export default function App() { const queryParams = router.asPath.split('?')[1]; const parsedParams = querystring.parse(queryParams); let access_token = parsedParams.access_token || null; + let first_login = parsedParams.first_time_login || false + + const utmParams = getUTMParametersFromURL(); + if (utmParams) + sessionStorage.setItem('utm_source', utmParams.utm_source); + const signupSource = sessionStorage.getItem('utm_source'); if (typeof window !== 'undefined' && access_token) { localStorage.setItem('accessToken', access_token); refreshUrl(); } - validateAccessToken() .then((response) => { setUserName(response.data.name || ''); + if(mixpanelId()) + mixpanel.identify(response.data.email) + if(first_login) + getUserClick('New Sign Up', {}) + else + getUserClick('User Logged In', {}) + + if(signupSource) { + handleSignUpSource(signupSource) + } fetchOrganisation(response.data.id); }) .catch((error) => { console.error('Error validating access token:', error); }); } else { - const userData = { - "name": "SuperAGI User", - "email": "super6@agi.com", - "password": "pass@123", - } - - addUser(userData) - .then((response) => { - setUserName(response.data.name); - fetchOrganisation(response.data.id); - }) - .catch((error) => { - console.error('Error adding user:', error); - }); + handleLocalEnviroment() } }) .catch((error) => { @@ -197,6 +198,40 @@ export default function App() { } } + const handleLocalEnviroment = () => { + const userData = { + "name": "SuperAGI User", + "email": "super6@agi.com", + "password": "pass@123", + } + + addUser(userData) + .then((response) => { + setUserName(response.data.name); + fetchOrganisation(response.data.id); + }) + .catch((error) => { + console.error('Error adding user:', error); + }); + }; + const handleSignUpSource = (signup) => { + getFirstSignup(signup) + .then((response) => { + sessionStorage.removeItem('utm_source'); + }) + .catch((error) => { + console.error('Error validating source:', error); + }) + }; + + const handleMarketplace = () => { + if (window.location.href.toLowerCase().includes('marketplace')) { + setShowMarketplace(true); + } else { + installFromMarketplace(); + } + }; + useEffect(() => { const clearLocalStorage = () => { Object.keys(localStorage).forEach((key) => { diff --git a/gui/pages/api/DashboardService.js b/gui/pages/api/DashboardService.js index c26330d25..38e13c698 100644 --- a/gui/pages/api/DashboardService.js +++ b/gui/pages/api/DashboardService.js @@ -389,10 +389,15 @@ export const getToolLogs = (toolName) => { export const publishTemplateToMarketplace = (agentData) => { return api.post(`/agent_templates/publish_template`, agentData); }; + export const getKnowledgeMetrics = (knowledgeName) => { return api.get(`analytics/knowledge/${knowledgeName}/usage`) } export const getKnowledgeLogs = (knowledgeName) => { return api.get(`analytics/knowledge/${knowledgeName}/logs`) -} \ No newline at end of file +} + +export const getFirstSignup = (source) => { + return api.post(`/users/first_login_source/${source}`,); +}; \ No newline at end of file diff --git a/gui/pages/api/apiConfig.js b/gui/pages/api/apiConfig.js index b7b3cdf20..8f6338e0c 100644 --- a/gui/pages/api/apiConfig.js +++ b/gui/pages/api/apiConfig.js @@ -2,6 +2,7 @@ import axios from 'axios'; const GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID; const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:8001'; +const MIXPANEL_AUTH_ID = process.env.MIXPANEL_AUTH_ID export const baseUrl = () => { return API_BASE_URL; @@ -11,6 +12,10 @@ export const githubClientId = () => { return GITHUB_CLIENT_ID; }; +export const mixpanelId = () => { + return MIXPANEL_AUTH_ID; +}; + const api = axios.create({ baseURL: API_BASE_URL, headers: { diff --git a/gui/utils/utils.js b/gui/utils/utils.js index f0e4d4cc6..ee46fb6bd 100644 --- a/gui/utils/utils.js +++ b/gui/utils/utils.js @@ -1,9 +1,10 @@ -import {formatDistanceToNow} from 'date-fns'; +import {formatDistanceToNow, format, addMinutes} from 'date-fns'; import {utcToZonedTime} from 'date-fns-tz'; -import {baseUrl} from "@/pages/api/apiConfig"; +import {baseUrl, mixpanelId} from "@/pages/api/apiConfig"; import {EventBus} from "@/utils/eventBus"; import JSZip from "jszip"; import moment from 'moment'; +import mixpanel from 'mixpanel-browser' const toolkitData = { 'Jira Toolkit': '/images/jira_icon.svg', @@ -481,4 +482,67 @@ export const modelIcon = (model) => { } return icons[model]; +} + +export const modelGetAuth = (modelProvider) => { + const externalLinks = { + 'Replicate': 'https://replicate.com/account/api-tokens', + 'Hugging Face': 'https://huggingface.co/settings/tokens', + 'OpenAI': 'https://platform.openai.com/account/api-keys', + 'Google Palm': 'https://developers.generativeai.google/products/palm', + } + + return externalLinks[modelProvider] +} + +export const formatDateTime = (dateTimeString) => { + const date = new Date(dateTimeString); + const adjustedDate = addMinutes(addMinutes(date, 5 * 60), 30); + const formattedDate = format(adjustedDate, 'd MMM yyyy HH:mm'); + + return formattedDate; +}; + +export const convertWaitingPeriod = (waitingPeriod) => { + let convertedValue = waitingPeriod; + let unit = 'seconds'; + + if (convertedValue >= 60 && convertedValue < 3600) { + convertedValue = Math.floor(convertedValue / 60); + unit = 'minutes'; + } else if (convertedValue >= 3600 && convertedValue < 86400) { + convertedValue = Math.floor(convertedValue / 3600); + unit = 'hours'; + } else if (convertedValue >= 86400 && convertedValue < 604800) { + convertedValue = Math.floor(convertedValue / 86400); + unit = 'days'; + } else if (convertedValue >= 604800) { + convertedValue = Math.floor(convertedValue / 604800); + unit = 'weeks'; + } + + return convertedValue + ' ' + unit; +} + +export const getUTMParametersFromURL = () => { + const params = new URLSearchParams(window.location.search); + + const utmParams = { + utm_source: params.get('utm_source') || '', + utm_medium: params.get('utm_medium') || '', + utm_campaign: params.get('utm_campaign') || '', + }; + + if (!utmParams.utm_source && !utmParams.utm_medium && !utmParams.utm_campaign) { + return null; + } + + return utmParams; +} + +export const getUserClick = (event, props) => { + const env = localStorage.getItem('applicationEnvironment'); + if(env === 'PROD' && mixpanelId()){ + mixpanel.track(event, props) + } } \ No newline at end of file diff --git a/main.py b/main.py index a0cd36223..2e4b11852 100644 --- a/main.py +++ b/main.py @@ -307,14 +307,14 @@ def github_auth_handler(code: str = Query(...), Authorize: AuthJWT = Depends()): db_user: User = db.session.query(User).filter(User.email == user_email).first() if db_user is not None: jwt_token = create_access_token(user_email, Authorize) - redirect_url_success = f"{frontend_url}?access_token={jwt_token}" + redirect_url_success = f"{frontend_url}?access_token={jwt_token}&first_time_login={False}" return RedirectResponse(url=redirect_url_success) user = User(name=user_data["name"], email=user_email) db.session.add(user) db.session.commit() jwt_token = create_access_token(user_email, Authorize) - redirect_url_success = f"{frontend_url}?access_token={jwt_token}" + redirect_url_success = f"{frontend_url}?access_token={jwt_token}&first_time_login={True}" return RedirectResponse(url=redirect_url_success) else: redirect_url_failure = "https://superagi.com/" diff --git a/migrations/versions/3867bb00a495_added_first_login_source.py b/migrations/versions/3867bb00a495_added_first_login_source.py new file mode 100644 index 000000000..eaf28f0ef --- /dev/null +++ b/migrations/versions/3867bb00a495_added_first_login_source.py @@ -0,0 +1,28 @@ +"""added_first_login_source + +Revision ID: 3867bb00a495 +Revises: 661ec8a4c32e +Create Date: 2023-09-15 02:06:24.006555 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '3867bb00a495' +down_revision = '661ec8a4c32e' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('users', sa.Column('first_login_source', sa.String(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('users', 'first_login_source') + # ### end Alembic commands ### diff --git a/migrations/versions/661ec8a4c32e_open_ai_error_handling.py b/migrations/versions/661ec8a4c32e_open_ai_error_handling.py new file mode 100644 index 000000000..210c1a51b --- /dev/null +++ b/migrations/versions/661ec8a4c32e_open_ai_error_handling.py @@ -0,0 +1,30 @@ +"""open_ai_error_handling + +Revision ID: 661ec8a4c32e +Revises: 40affbf3022b +Create Date: 2023-09-07 10:41:07.462436 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '661ec8a4c32e' +down_revision = 'c4f2f6ba602a' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('agent_execution_feeds', sa.Column('error_message', sa.String(), nullable=True)) + op.add_column('agent_executions', sa.Column('last_shown_error_id', sa.Integer(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('agent_executions', 'last_shown_error_id') + op.drop_column('agent_execution_feeds', 'error_message') + # ### end Alembic commands ### diff --git a/migrations/versions/c4f2f6ba602a_agent_workflow_wait_step.py b/migrations/versions/c4f2f6ba602a_agent_workflow_wait_step.py new file mode 100644 index 000000000..c37515c2b --- /dev/null +++ b/migrations/versions/c4f2f6ba602a_agent_workflow_wait_step.py @@ -0,0 +1,39 @@ +"""agent_workflow_wait_step + +Revision ID: c4f2f6ba602a +Revises: 40affbf3022b +Create Date: 2023-09-04 05:34:10.195248 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'c4f2f6ba602a' +down_revision = '40affbf3022b' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('agent_workflow_step_waits', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('unique_id', sa.String(), nullable=True), + sa.Column('delay', sa.Integer(), nullable=True), + sa.Column('wait_begin_time', sa.DateTime(), nullable=True), + sa.Column('status', sa.String(), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('agent_workflow_step_waits') + # ### end Alembic commands ### diff --git a/superagi/agent/agent_iteration_step_handler.py b/superagi/agent/agent_iteration_step_handler.py index 5ab21d4d6..0e2c4fcec 100644 --- a/superagi/agent/agent_iteration_step_handler.py +++ b/superagi/agent/agent_iteration_step_handler.py @@ -11,6 +11,7 @@ from superagi.agent.tool_builder import ToolBuilder from superagi.apm.event_handler import EventHandler from superagi.config.config import get_config +from superagi.helper.error_handler import ErrorHandler from superagi.helper.token_counter import TokenCounter from superagi.lib.logger import logger from superagi.models.agent import Agent @@ -73,6 +74,9 @@ def execute_step(self): current_tokens = TokenCounter.count_message_tokens(messages = messages, model = self.llm.get_model()) response = self.llm.chat_completion(messages, TokenCounter(session=self.session, organisation_id=organisation.id).token_limit(self.llm.get_model()) - current_tokens) + if 'error' in response and response['message'] is not None: + ErrorHandler.handle_openai_errors(self.session, self.agent_id, self.agent_execution_id, response['message']) + if 'content' not in response or response['content'] is None: raise RuntimeError(f"Failed to get response from llm") @@ -82,11 +86,12 @@ def execute_step(self): content = json.loads(response['content']) tool = content.get('tool', {}) tool_name = tool.get('name', '') if tool else '' - except Exception as e: - logger.error(f"Decoding JSON has failed {e}") + except json.JSONDecodeError: + print("Decoding JSON has failed") tool_name = '' - CallLogHelper(session=self.session, organisation_id=organisation.id).create_call_log(execution.name,agent_config['agent_id'],total_tokens, tool_name,agent_config['model']) + CallLogHelper(session=self.session, organisation_id=organisation.id).create_call_log(execution.name, + agent_config['agent_id'], total_tokens, tool_name, agent_config['model']) assistant_reply = response['content'] output_handler = get_output_handler(iteration_workflow_step.output_type, diff --git a/superagi/agent/agent_message_builder.py b/superagi/agent/agent_message_builder.py index 9008ef27c..63698b874 100644 --- a/superagi/agent/agent_message_builder.py +++ b/superagi/agent/agent_message_builder.py @@ -3,6 +3,7 @@ from sqlalchemy import asc from superagi.config.config import get_config +from superagi.helper.error_handler import ErrorHandler from superagi.helper.prompt_reader import PromptReader from superagi.helper.token_counter import TokenCounter from superagi.models.agent_execution import AgentExecution @@ -122,6 +123,9 @@ def _build_ltm_summary(self, past_messages, output_token_limit) -> str: {"role": "assistant", "content": ltm_prompt}] ltm_summary = self.llm.chat_completion(msgs) + if 'error' in ltm_summary and ltm_summary['message'] is not None: + ErrorHandler.handle_openai_errors(self.session, self.agent_id, self.agent_execution_id, ltm_summary['message']) + execution = AgentExecution(id=self.agent_execution_id) agent_execution_configs = {"ltm_summary": ltm_summary["content"]} AgentExecutionConfiguration.add_or_update_agent_execution_config(session=self.session, execution=execution, diff --git a/superagi/agent/agent_tool_step_handler.py b/superagi/agent/agent_tool_step_handler.py index 7aeb0d59b..5b8c1c127 100644 --- a/superagi/agent/agent_tool_step_handler.py +++ b/superagi/agent/agent_tool_step_handler.py @@ -7,6 +7,7 @@ from superagi.agent.output_parser import AgentSchemaToolOutputParser from superagi.agent.queue_step_handler import QueueStepHandler from superagi.agent.tool_builder import ToolBuilder +from superagi.helper.error_handler import ErrorHandler from superagi.helper.prompt_reader import PromptReader from superagi.helper.token_counter import TokenCounter from superagi.lib.logger import logger @@ -105,6 +106,9 @@ def _process_input_instruction(self, agent_config, agent_execution_config, step_ # print(messages) current_tokens = TokenCounter.count_message_tokens(messages, self.llm.get_model()) response = self.llm.chat_completion(messages, TokenCounter(session=self.session, organisation_id=self.organisation.id).token_limit(self.llm.get_model()) - current_tokens) + + if 'error' in response and response['message'] is not None: + ErrorHandler.handle_openai_errors(self.session, self.agent_id, self.agent_execution_id, response['message']) # ModelsHelper(session=self.session, organisation_id=organisation.id).create_call_log(execution.name,agent_config['agent_id'],response['response'].usage.total_tokens,json.loads(response['content'])['tool']['name'],agent_config['model']) if 'content' not in response or response['content'] is None: raise RuntimeError(f"Failed to get response from llm") @@ -137,6 +141,10 @@ def _process_output_instruction(self, final_response: str, step_tool: AgentWorkf current_tokens = TokenCounter.count_message_tokens(messages, self.llm.get_model()) response = self.llm.chat_completion(messages, TokenCounter(session=self.session, organisation_id=self.organisation.id).token_limit(self.llm.get_model()) - current_tokens) + + if 'error' in response and response['message'] is not None: + ErrorHandler.handle_openai_errors(self.session, self.agent_id, self.agent_execution_id, response['message']) + if 'content' not in response or response['content'] is None: raise RuntimeError(f"ToolWorkflowStepHandler: Failed to get output response from llm") total_tokens = current_tokens + TokenCounter.count_message_tokens(response, self.llm.get_model()) diff --git a/superagi/agent/agent_workflow_step_wait_handler.py b/superagi/agent/agent_workflow_step_wait_handler.py new file mode 100644 index 000000000..223859d31 --- /dev/null +++ b/superagi/agent/agent_workflow_step_wait_handler.py @@ -0,0 +1,45 @@ +from datetime import datetime + +from superagi.agent.types.agent_execution_status import AgentExecutionStatus +from superagi.lib.logger import logger +from superagi.models.agent_execution import AgentExecution +from superagi.models.workflows.agent_workflow_step import AgentWorkflowStep +from superagi.models.workflows.agent_workflow_step_wait import AgentWorkflowStepWait +from superagi.agent.types.wait_step_status import AgentWorkflowStepWaitStatus + +class AgentWaitStepHandler: + """Handle Agent Wait Step in the agent workflow.""" + + def __init__(self, session, agent_id, agent_execution_id): + self.session = session + self.agent_id = agent_id + self.agent_execution_id = agent_execution_id + + def execute_step(self): + """Execute the agent wait step.""" + + logger.info("Executing Wait Step") + execution = AgentExecution.get_agent_execution_from_id(self.session, self.agent_execution_id) + workflow_step = AgentWorkflowStep.find_by_id(self.session, execution.current_agent_step_id) + step_wait = AgentWorkflowStepWait.find_by_id(self.session, workflow_step.action_reference_id) + if step_wait is not None: + step_wait.wait_begin_time = datetime.now() + step_wait.status = AgentWorkflowStepWaitStatus.WAITING.value + execution.status = AgentExecutionStatus.WAIT_STEP.value + + self.session.commit() + + def handle_next_step(self): + """Handle next step of agent workflow in case of wait step.""" + + execution = AgentExecution.get_agent_execution_from_id(self.session, self.agent_execution_id) + workflow_step = AgentWorkflowStep.find_by_id(self.session, execution.current_agent_step_id) + step_response = "default" + next_step = AgentWorkflowStep.fetch_next_step(self.session, workflow_step.id, step_response) + if str(next_step) == "COMPLETE": + agent_execution = AgentExecution.get_agent_execution_from_id(self.session, self.agent_execution_id) + agent_execution.current_agent_step_id = -1 + agent_execution.status = "COMPLETED" + else: + AgentExecution.assign_next_step_id(self.session, self.agent_execution_id, next_step.id) + self.session.commit() diff --git a/superagi/agent/queue_step_handler.py b/superagi/agent/queue_step_handler.py index 1ce3d8313..fcd9baf1f 100644 --- a/superagi/agent/queue_step_handler.py +++ b/superagi/agent/queue_step_handler.py @@ -4,6 +4,7 @@ from superagi.agent.agent_message_builder import AgentLlmMessageBuilder from superagi.agent.task_queue import TaskQueue +from superagi.helper.error_handler import ErrorHandler from superagi.helper.json_cleaner import JsonCleaner from superagi.helper.prompt_reader import PromptReader from superagi.helper.token_counter import TokenCounter @@ -90,6 +91,10 @@ def _process_input_instruction(self, step_tool): completion_prompt=step_tool.completion_prompt) current_tokens = TokenCounter.count_message_tokens(messages, self.llm.get_model()) response = self.llm.chat_completion(messages, TokenCounter(session=self.session, organisation_id=self.organisation.id).token_limit(self.llm.get_model()) - current_tokens) + + if 'error' in response and response['message'] is not None: + ErrorHandler.handle_openai_errors(self.session, self.agent_id, self.agent_execution_id, response['message']) + if 'content' not in response or response['content'] is None: raise RuntimeError(f"Failed to get response from llm") total_tokens = current_tokens + TokenCounter.count_message_tokens(response, self.llm.get_model()) diff --git a/superagi/agent/tool_executor.py b/superagi/agent/tool_executor.py index 017094164..303b8364a 100644 --- a/superagi/agent/tool_executor.py +++ b/superagi/agent/tool_executor.py @@ -32,7 +32,7 @@ def execute(self, session, tool_name, tool_args): status = "SUCCESS" tool = tools[tool_name] retry = False - EventHandler(session=session).create_event('tool_used', {'tool_name': tool_name, 'agent_execution_id': self.agent_execution_id}, self.agent_id, + EventHandler(session=session).create_event('tool_used', {'tool_name': tool.name, 'agent_execution_id': self.agent_execution_id}, self.agent_id, self.organisation_id), try: parsed_args = self.clean_tool_args(tool_args) diff --git a/superagi/agent/types/__init__.py b/superagi/agent/types/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/superagi/agent/types/agent_execution_status.py b/superagi/agent/types/agent_execution_status.py new file mode 100644 index 000000000..c327c56ce --- /dev/null +++ b/superagi/agent/types/agent_execution_status.py @@ -0,0 +1,18 @@ +from enum import Enum + + +class AgentExecutionStatus(Enum): + RUNNING = 'RUNNING' + WAITING_FOR_PERMISSION = 'WAITING_FOR_PERMISSION' + ITERATION_LIMIT_EXCEEDED = 'ITERATION_LIMIT_EXCEEDED' + WAIT_STEP = 'WAIT_STEP' + COMPLETED = 'COMPLETED' + + @classmethod + def get_agent_execution_status(cls, store): + if store is None: + raise ValueError("Storage type cannot be None.") + store = store.upper() + if store in cls.__members__: + return cls[store] + raise ValueError(f"{store} is not a valid storage name.") diff --git a/superagi/agent/types/agent_workflow_step_action_types.py b/superagi/agent/types/agent_workflow_step_action_types.py new file mode 100644 index 000000000..dcce25fc1 --- /dev/null +++ b/superagi/agent/types/agent_workflow_step_action_types.py @@ -0,0 +1,17 @@ +from enum import Enum + + +class AgentWorkflowStepAction(Enum): + ITERATION_WORKFLOW = 'ITERATION_WORKFLOW' + TOOL = 'TOOL' + WAIT_STEP = 'WAIT_STEP' + + + @classmethod + def get_agent_workflow_action_type(cls, store): + if store is None: + raise ValueError("Storage type cannot be None.") + store = store.upper() + if store in cls.__members__: + return cls[store] + raise ValueError(f"{store} is not a valid storage name.") diff --git a/superagi/agent/types/wait_step_status.py b/superagi/agent/types/wait_step_status.py new file mode 100644 index 000000000..b81e72db1 --- /dev/null +++ b/superagi/agent/types/wait_step_status.py @@ -0,0 +1,16 @@ +from enum import Enum + + +class AgentWorkflowStepWaitStatus(Enum): + PENDING = 'PENDING' + WAITING = 'WAITING' + COMPLETED = 'COMPLETED' + + @classmethod + def get_agent_workflow_step_wait_status(cls, store): + if store is None: + raise ValueError("Storage type cannot be None.") + store = store.upper() + if store in cls.__members__: + return cls[store] + raise ValueError(f"{store} is not a valid storage name.") diff --git a/superagi/agent/workflow_seed.py b/superagi/agent/workflow_seed.py index 7f95b1244..2400faac8 100644 --- a/superagi/agent/workflow_seed.py +++ b/superagi/agent/workflow_seed.py @@ -37,16 +37,16 @@ def build_sales_workflow(cls, session): # "Search for leads based on the given goals", # step_type="TRIGGER") # - # step2 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id, - # str(agent_workflow.id) + "_step2", - # WriteFileTool().name, - # "Write the leads to a csv file") + step2 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id, + str(agent_workflow.id) + "_step2", + ListFileTool().name, + "list the files", + step_type="TRIGGER") step3 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id, str(agent_workflow.id) + "_step3", ReadFileTool().name, - "Read the leads from the file generated in the previous run", - step_type="TRIGGER") + "Read the leads from the file") # task queue ends when the elements gets over step4 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id, @@ -67,7 +67,7 @@ def build_sales_workflow(cls, session): step7 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id, str(agent_workflow.id) + "_step7", - GoogleSearchTool().name, + SearxSearchTool().name, "Search about the company given in the high-end goal only") step8 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id, @@ -75,8 +75,23 @@ def build_sales_workflow(cls, session): SendEmailTool().name, "Customize the Email according to the company information in the mail") + step9 = AgentWorkflowStep.find_or_create_wait_workflow_step(session, agent_workflow.id, + str(agent_workflow.id) + "_step9", + "Wait for 2 minutes", + 2*60) + + step10 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id, + str(agent_workflow.id) + "_step10", + ReadEmailTool().name, + "Read the email from adarshdeepmurari@gmail.com") + + step11 = AgentWorkflowStep.find_or_create_tool_workflow_step(session, agent_workflow.id, + str(agent_workflow.id) + "_step11", + SendEmailTool().name, + "Customize the Email according to the company information in the mail") + # AgentWorkflowStep.add_next_workflow_step(session, step1.id, step2.id) - # AgentWorkflowStep.add_next_workflow_step(session, step2.id, step3.id) + AgentWorkflowStep.add_next_workflow_step(session, step2.id, step3.id) AgentWorkflowStep.add_next_workflow_step(session, step3.id, step4.id) AgentWorkflowStep.add_next_workflow_step(session, step4.id, -1, "COMPLETE") AgentWorkflowStep.add_next_workflow_step(session, step4.id, step5.id) @@ -84,7 +99,10 @@ def build_sales_workflow(cls, session): AgentWorkflowStep.add_next_workflow_step(session, step6.id, step7.id, "YES") AgentWorkflowStep.add_next_workflow_step(session, step6.id, step5.id, "NO") AgentWorkflowStep.add_next_workflow_step(session, step7.id, step8.id) - AgentWorkflowStep.add_next_workflow_step(session, step8.id, step4.id) + AgentWorkflowStep.add_next_workflow_step(session, step8.id, step9.id) + AgentWorkflowStep.add_next_workflow_step(session, step9.id, step10.id) + AgentWorkflowStep.add_next_workflow_step(session, step10.id, step11.id) + AgentWorkflowStep.add_next_workflow_step(session, step11.id, step4.id) session.commit() @classmethod diff --git a/superagi/apm/call_log_helper.py b/superagi/apm/call_log_helper.py index 85d359d4e..03f183c0f 100644 --- a/superagi/apm/call_log_helper.py +++ b/superagi/apm/call_log_helper.py @@ -50,13 +50,11 @@ def fetch_data(self, model: str): 'runs': [] } - # Fetch all runs for this model - runs = self.session.query(CallLogs).filter(CallLogs.model == model, CallLogs.org_id == self.organisation_id).all() + runs = self.session.query(CallLogs).filter(CallLogs.model == model, + CallLogs.org_id == self.organisation_id).all() for run in runs: - # Get agent's name using agent_id as a foreign key agent = self.session.query(Agent).filter(Agent.id == run.agent_id).first() - # Get toolkit's name using tool_used as a linking key toolkit = None tool = self.session.query(Tool).filter(Tool.name == run.tool_used).first() if tool: @@ -66,15 +64,17 @@ def fetch_data(self, model: str): 'id': run.id, 'agent_execution_name': run.agent_execution_name, 'agent_id': run.agent_id, - 'agent_name': agent.name if agent is not None else None, # add agent_name to dictionary + 'agent_name': agent.name if agent is not None else None, 'tokens_consumed': run.tokens_consumed, 'tool_used': run.tool_used, - 'toolkit_name': toolkit.name if toolkit is not None else None, # add toolkit_name to dictionary + 'toolkit_name': toolkit.name if toolkit is not None else None, 'org_id': run.org_id, 'created_at': run.created_at, 'updated_at': run.updated_at, }) + model_data['runs'] = model_data['runs'][::-1] + return model_data except SQLAlchemyError as err: diff --git a/superagi/apm/knowledge_handler.py b/superagi/apm/knowledge_handler.py index 098791d4c..30347b01b 100644 --- a/superagi/apm/knowledge_handler.py +++ b/superagi/apm/knowledge_handler.py @@ -7,6 +7,7 @@ from sqlalchemy.sql import func from sqlalchemy.orm import aliased from superagi.models.agent_config import AgentConfiguration +from superagi.models.agent_execution_config import AgentExecutionConfiguration import pytz from datetime import datetime @@ -43,7 +44,7 @@ def get_knowledge_usage_by_name(self, knowledge_name: str) -> Dict[str, Dict[str 'knowledge_calls': self.session.query( EventAlias ).filter( - EventAlias.event_property['tool_name'].astext == 'knowledgesearch', + EventAlias.event_property['tool_name'].astext == 'Knowledge Search', EventAlias.event_name == 'tool_used', EventAlias.org_id == self.organisation_id, EventAlias.agent_id.in_(self.session.query(Event.agent_id).filter( @@ -89,6 +90,16 @@ def get_knowledge_events_by_name(self, knowledge_name: str) -> List[Dict[str, Un event_run = next((er for er in event_runs if er.agent_id == knowledge_event.agent_id and er.event_property['agent_execution_id'] == agent_execution_id), None) agent_created_event = next((ace for ace in agent_created_events if ace.agent_id == knowledge_event.agent_id), None) + + model_query = self.session.query(AgentExecutionConfiguration).filter( + AgentExecutionConfiguration.agent_execution_id == agent_execution_id, + AgentExecutionConfiguration.key == 'model' + ).first() + + if model_query and model_query.value != 'None': + model_value = model_query.value + else: + model_value = None try: user_timezone = AgentConfiguration.get_agent_config_by_key_and_agent_id(session=self.session, key='user_timezone', agent_id=knowledge_event.agent_id) if user_timezone and user_timezone.value != 'None': @@ -108,7 +119,7 @@ def get_knowledge_events_by_name(self, knowledge_name: str) -> List[Dict[str, Un 'calls': event_run.event_property['calls'], 'agent_execution_name': event_run.event_property['name'], 'agent_name': agent_created_event.event_property['agent_name'], - 'model': agent_created_event.event_property['model'] + 'model': model_value if model_value else agent_created_event.event_property['model'] } if agent_execution_id not in [i['agent_execution_id'] for i in results]: results.append(result_dict) diff --git a/superagi/apm/tools_handler.py b/superagi/apm/tools_handler.py index da3f97cc6..0e583548d 100644 --- a/superagi/apm/tools_handler.py +++ b/superagi/apm/tools_handler.py @@ -1,7 +1,7 @@ from typing import List, Dict, Union from sqlalchemy import func, distinct, and_ from sqlalchemy.orm import Session -from sqlalchemy import Integer +from sqlalchemy import Integer, String from fastapi import HTTPException from superagi.models.events import Event from superagi.models.tool import Tool @@ -10,6 +10,7 @@ from sqlalchemy.sql import label from datetime import datetime from superagi.models.agent_config import AgentConfiguration +from superagi.models.agent_execution_config import AgentExecutionConfiguration import pytz class ToolsHandler: @@ -19,10 +20,10 @@ def __init__(self, session: Session, organisation_id: int): def get_tool_and_toolkit(self): tools_and_toolkits = self.session.query( - Tool.name.label('tool_name'), Toolkit.name.label('toolkit_name')).join( + func.lower(Tool.name).label('tool_name'), Toolkit.name.label('toolkit_name')).join( Toolkit, Tool.toolkit_id == Toolkit.id).all() - return {item.tool_name: item.toolkit_name for item in tools_and_toolkits} + return {item.tool_name.lower(): item.toolkit_name for item in tools_and_toolkits} def calculate_tool_usage(self) -> List[Dict[str, int]]: tool_usage = [] @@ -55,9 +56,11 @@ def calculate_tool_usage(self) -> List[Dict[str, int]]: 'tool_name': row.tool_name, 'unique_agents': row.unique_agents, 'total_usage': row.total_usage, - 'toolkit': tool_and_toolkit.get(row.tool_name, None) + 'toolkit': tool_and_toolkit.get(row.tool_name.lower(), None) } for row in result] + tool_usage.sort(key=lambda tool: tool['total_usage'], reverse=True) + return tool_usage def get_tool_usage_by_name(self, tool_name: str) -> Dict[str, Dict[str, int]]: @@ -65,30 +68,34 @@ def get_tool_usage_by_name(self, tool_name: str) -> Dict[str, Dict[str, int]]: if not is_tool_name_valid: raise HTTPException(status_code=404, detail="Tool not found") - formatted_tool_name = tool_name.lower().replace(" ", "") - tool_used_event = self.session.query( - Event.event_property['tool_name'].label('tool_name'), + tool_name_event = self.session.query( + Event.event_property['tool_name'].cast(String).label('tool_name'), func.count(Event.id).label('tool_calls'), func.count(distinct(Event.agent_id)).label('tool_unique_agents') ).filter( - Event.event_name == 'tool_used', + Event.event_name == 'tool_used', Event.org_id == self.organisation_id, - Event.event_property['tool_name'].astext == formatted_tool_name + Event.event_property['tool_name'].astext == tool_name ).group_by( - Event.event_property['tool_name'] + Event.event_property['tool_name'].cast(String) ).first() - if tool_used_event is None: - return {} + tool_data = {} + tool_calls = 0 + tool_unique_agents = 0 + + if tool_name_event: + tool_calls += tool_name_event.tool_calls + tool_unique_agents += tool_name_event.tool_unique_agents tool_data = { - 'tool_calls': tool_used_event.tool_calls, - 'tool_unique_agents': tool_used_event.tool_unique_agents - } + 'tool_calls': tool_calls, + 'tool_unique_agents': tool_unique_agents + } return tool_data - + def get_tool_events_by_name(self, tool_name: str) -> List[Dict[str, Union[str, int, List[str]]]]: is_tool_name_valid = self.session.query(Tool).filter_by(name=tool_name).first() @@ -96,12 +103,10 @@ def get_tool_events_by_name(self, tool_name: str) -> List[Dict[str, Union[str, i if not is_tool_name_valid: raise HTTPException(status_code=404, detail="Tool not found") - formatted_tool_name = tool_name.lower().replace(" ", "") - tool_events = self.session.query(Event).filter( Event.org_id == self.organisation_id, Event.event_name == 'tool_used', - Event.event_property['tool_name'].astext == formatted_tool_name + Event.event_property['tool_name'].astext == tool_name ).all() tool_events = [te for te in tool_events if 'agent_execution_id' in te.event_property] @@ -123,6 +128,16 @@ def get_tool_events_by_name(self, tool_name: str) -> List[Dict[str, Union[str, i event_run = next((er for er in event_runs if er.agent_id == tool_event.agent_id and er.event_property['agent_execution_id'] == agent_execution_id), None) agent_created_event = next((ace for ace in agent_created_events if ace.agent_id == tool_event.agent_id), None) + + model_query = self.session.query(AgentExecutionConfiguration).filter( + AgentExecutionConfiguration.agent_execution_id == agent_execution_id, + AgentExecutionConfiguration.key == 'model' + ).first() + + if model_query and model_query.value != 'None': + model_value = model_query.value + else: + model_value = None try: user_timezone = AgentConfiguration.get_agent_config_by_key_and_agent_id(session=self.session, key='user_timezone', agent_id=tool_event.agent_id) if user_timezone and user_timezone.value != 'None': @@ -139,7 +154,7 @@ def get_tool_events_by_name(self, tool_name: str) -> List[Dict[str, Union[str, i ).filter( Event.org_id == self.organisation_id, Event.event_name == 'tool_used', - Event.event_property['tool_name'].astext != formatted_tool_name, + Event.event_property['tool_name'].astext != tool_name, Event.agent_id == tool_event.agent_id, Event.id.between(tool_event.id, event_run.id) ).all() @@ -154,7 +169,7 @@ def get_tool_events_by_name(self, tool_name: str) -> List[Dict[str, Union[str, i 'agent_execution_name': event_run.event_property['name'], 'other_tools': other_tools, 'agent_name': agent_created_event.event_property['agent_name'], - 'model': agent_created_event.event_property['model'] + 'model': model_value if model_value else agent_created_event.event_property['model'] } if agent_execution_id not in [i['agent_execution_id'] for i in results]: diff --git a/superagi/controllers/agent_execution_feed.py b/superagi/controllers/agent_execution_feed.py index e92f22fac..93cf47bb7 100644 --- a/superagi/controllers/agent_execution_feed.py +++ b/superagi/controllers/agent_execution_feed.py @@ -1,7 +1,9 @@ +import asyncio from datetime import datetime +import time from typing import Optional -from fastapi import APIRouter +from fastapi import APIRouter, BackgroundTasks from fastapi import HTTPException, Depends from fastapi_jwt_auth import AuthJWT from fastapi_sqlalchemy import db @@ -16,6 +18,10 @@ from superagi.helper.feed_parser import parse_feed from superagi.models.agent_execution import AgentExecution from superagi.models.agent_execution_feed import AgentExecutionFeed +from superagi.lib.logger import logger +from superagi.agent.types.agent_workflow_step_action_types import AgentWorkflowStepAction +from superagi.models.workflows.agent_workflow_step import AgentWorkflowStep +from superagi.models.workflows.agent_workflow_step_wait import AgentWorkflowStepWait import re # from superagi.types.db import AgentExecutionFeedOut, AgentExecutionFeedIn @@ -144,7 +150,7 @@ def update_agent_execution_feed(agent_execution_feed_id: int, @router.get("/get/execution/{agent_execution_id}") def get_agent_execution_feed(agent_execution_id: int, - Authorize: AuthJWT = Depends(check_auth)): + Authorize: AuthJWT = Depends(check_auth)): """ Get agent execution feed with other execution details. @@ -165,7 +171,17 @@ def get_agent_execution_feed(agent_execution_id: int, asc(AgentExecutionFeed.created_at)).all() # # parse json final_feeds = [] + error = "" for feed in feeds: + if feed.error_message: + if (agent_execution.last_shown_error_id is None) or (feed.id > agent_execution.last_shown_error_id): + #new error occured + error = feed.error_message + agent_execution.last_shown_error_id = feed.id + agent_execution.status = "ERROR_PAUSED" + db.session.commit() + if feed.id == agent_execution.last_shown_error_id and agent_execution.status == "ERROR_PAUSED": + error = feed.error_message if feed.feed != "" and re.search(r"The current time and date is\s(\w{3}\s\w{3}\s\s?\d{1,2}\s\d{2}:\d{2}:\d{2}\s\d{4})",feed.feed) == None : final_feeds.append(parse_feed(feed)) @@ -183,13 +199,22 @@ def get_agent_execution_feed(agent_execution_id: int, "tool_name": permission.tool_name, "question": permission.question, "user_feedback": permission.user_feedback, - "time_difference":get_time_difference(permission.created_at,str(datetime.now())) + "time_difference": get_time_difference(permission.created_at, str(datetime.now())) } for permission in execution_permissions ] + + waiting_period = None + + if agent_execution.status == AgentWorkflowStepAction.WAIT_STEP.value: + workflow_step = AgentWorkflowStep.find_by_id(db.session, agent_execution.current_agent_step_id) + waiting_period = (AgentWorkflowStepWait.find_by_id(db.session, workflow_step.action_reference_id)).delay + return { "status": agent_execution.status, "feeds": final_feeds, - "permissions": permissions + "permissions": permissions, + "waiting_period": waiting_period, + "errors": error } diff --git a/superagi/controllers/models_controller.py b/superagi/controllers/models_controller.py index 5aab5d207..2521f9abd 100644 --- a/superagi/controllers/models_controller.py +++ b/superagi/controllers/models_controller.py @@ -103,7 +103,7 @@ async def fetch_data(request: ModelName, organisation=Depends(get_user_organisat @router.get("/get/list", status_code=200) -def get_knowledge_list(page: int = 0, organisation=Depends(get_user_organisation)): +def get_models_list(page: int = 0, organisation=Depends(get_user_organisation)): """ Get Marketplace Model list. @@ -122,7 +122,7 @@ def get_knowledge_list(page: int = 0, organisation=Depends(get_user_organisation @router.get("/marketplace/list/{page}", status_code=200) -def get_marketplace_knowledge_list(page: int = 0): +def get_marketplace_models_list(page: int = 0): organisation_id = get_config("MARKETPLACE_ORGANISATION_ID") if organisation_id is not None: organisation_id = int(organisation_id) diff --git a/superagi/controllers/types/models_types.py b/superagi/controllers/types/models_types.py index 0a3b99ce1..4f6b9cc15 100644 --- a/superagi/controllers/types/models_types.py +++ b/superagi/controllers/types/models_types.py @@ -11,4 +11,4 @@ def get_models_types(cls, model_type): model_type = model_type.upper() if model_type in cls.__members__: return cls[model_type] - raise ValueError(f"{model_type} is not a valid storage name.") + raise ValueError(f"{model_type} is not a valid storage name.") \ No newline at end of file diff --git a/superagi/controllers/user.py b/superagi/controllers/user.py index 19bf2c935..c550fd889 100644 --- a/superagi/controllers/user.py +++ b/superagi/controllers/user.py @@ -11,12 +11,14 @@ from superagi.models.user import User from fastapi import APIRouter -from superagi.helper.auth import check_auth +from superagi.helper.auth import check_auth, get_current_user from superagi.lib.logger import logger + # from superagi.types.db import UserBase, UserIn, UserOut router = APIRouter() + class UserBase(BaseModel): name: str email: str @@ -42,6 +44,7 @@ class UserIn(UserBase): class Config: orm_mode = True + # CRUD Operations @router.post("/add", response_model=UserOut, status_code=201) def create_user(user: UserIn, @@ -126,3 +129,16 @@ def update_user(user_id: int, db.session.commit() return db_user + + +@router.post("/first_login_source/{source}") +def update_first_login_source(source: str, Authorize: AuthJWT = Depends(check_auth)): + """ Update first login source of the user """ + user = get_current_user(Authorize) + # valid_sources = ['google', 'github', 'email'] + if user.first_login_source is None or user.first_login_source == '': + user.first_login_source = source + db.session.commit() + db.session.flush() + logger.info("User : ",user) + return user diff --git a/superagi/helper/error_handler.py b/superagi/helper/error_handler.py new file mode 100644 index 000000000..839472574 --- /dev/null +++ b/superagi/helper/error_handler.py @@ -0,0 +1,10 @@ +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed + +class ErrorHandler: + + def handle_openai_errors(session, agent_id, agent_execution_id, error_message): + execution = session.query(AgentExecution).filter(AgentExecution.id == agent_execution_id).first() + agent_feed = AgentExecutionFeed(agent_execution_id=agent_execution_id, agent_id=agent_id, role="system", feed="", error_message=error_message, feed_group_id=execution.current_feed_group_id) + session.add(agent_feed) + session.commit() \ No newline at end of file diff --git a/superagi/helper/feed_parser.py b/superagi/helper/feed_parser.py index c05e217b5..c02040079 100644 --- a/superagi/helper/feed_parser.py +++ b/superagi/helper/feed_parser.py @@ -2,6 +2,7 @@ from datetime import datetime from superagi.helper.time_helper import get_time_difference +from superagi.lib.logger import logger def parse_feed(feed): @@ -40,7 +41,8 @@ def parse_feed(feed): return {"role": "assistant", "feed": final_output, "updated_at": feed.updated_at, "time_difference": feed.time_difference} except Exception: - return feed + return {"role": "assistant", "feed": feed.feed, "updated_at": feed.updated_at, + "time_difference": feed.time_difference} if feed.role == "system": final_output = feed.feed @@ -48,5 +50,9 @@ def parse_feed(feed): final_output = feed.feed.split("TOOLS:")[0] return {"role": "system", "feed": final_output, "updated_at": feed.updated_at, "time_difference": feed.time_difference} - + + if feed.role == "user": + return {"role": "user", "feed": feed.feed, "updated_at": feed.updated_at, + "time_difference": feed.time_difference} + return feed diff --git a/superagi/helper/s3_helper.py b/superagi/helper/s3_helper.py index a454db588..c084bd109 100644 --- a/superagi/helper/s3_helper.py +++ b/superagi/helper/s3_helper.py @@ -144,6 +144,7 @@ def list_files_from_s3(self, file_path): logger.info(f"Listing files from s3 with prefix: {file_path}") response = self.s3.list_objects_v2(Bucket=get_config("BUCKET_NAME"), Prefix=file_path) if 'Contents' in response: + logger.info(response['Contents']) file_list = [obj['Key'] for obj in response['Contents']] return file_list else: diff --git a/superagi/helper/validate_csv.py b/superagi/helper/validate_csv.py index 5e1c6fd46..882679ccf 100644 --- a/superagi/helper/validate_csv.py +++ b/superagi/helper/validate_csv.py @@ -11,7 +11,7 @@ def correct_csv_encoding(file_path): if encoding != 'utf-8': data = [] with open(file_path, 'r', encoding=encoding) as f: - reader = csv.reader(f, delimiter=';', quotechar='"') + reader = csv.reader(f, delimiter=',', quotechar='"') for row in reader: try: data.append(row) @@ -20,7 +20,6 @@ def correct_csv_encoding(file_path): continue df = pd.DataFrame(data) - df.to_csv(file_path, encoding='utf-8', index=False) logger.info("File is converted to utf-8 encoding.") else: diff --git a/superagi/jobs/agent_executor.py b/superagi/jobs/agent_executor.py index c3e52b3ba..4418dd86e 100644 --- a/superagi/jobs/agent_executor.py +++ b/superagi/jobs/agent_executor.py @@ -5,21 +5,28 @@ import superagi.worker from superagi.agent.agent_iteration_step_handler import AgentIterationStepHandler from superagi.agent.agent_tool_step_handler import AgentToolStepHandler +from superagi.agent.agent_workflow_step_wait_handler import AgentWaitStepHandler +from superagi.agent.types.wait_step_status import AgentWorkflowStepWaitStatus from superagi.apm.event_handler import EventHandler +from superagi.config.config import get_config from superagi.lib.logger import logger from superagi.llms.google_palm import GooglePalm from superagi.llms.hugging_face import HuggingFace from superagi.llms.replicate import Replicate from superagi.llms.llm_model_factory import get_model +from superagi.llms.replicate import Replicate from superagi.models.agent import Agent from superagi.models.agent_config import AgentConfiguration from superagi.models.agent_execution import AgentExecution from superagi.models.db import connect_db from superagi.models.workflows.agent_workflow_step import AgentWorkflowStep -from superagi.types.model_source_types import ModelSourceType +from superagi.models.workflows.agent_workflow_step_wait import AgentWorkflowStepWait from superagi.types.vector_store_types import VectorStoreType from superagi.vector_store.embedding.openai import OpenAiEmbedding from superagi.vector_store.vector_factory import VectorFactory +from superagi.worker import execute_agent +from superagi.agent.types.agent_workflow_step_action_types import AgentWorkflowStepAction +from superagi.agent.types.agent_execution_status import AgentExecutionStatus from superagi.vector_store.redis import Redis from superagi.config.config import get_config @@ -46,7 +53,7 @@ def execute_next_step(self, agent_execution_id): agent = session.query(Agent).filter(Agent.id == agent_execution.agent_id).first() agent_config = Agent.fetch_configuration(session, agent.id) if agent.is_deleted or ( - agent_execution.status != "RUNNING" and agent_execution.status != "WAITING_FOR_PERMISSION"): + agent_execution.status != AgentExecutionStatus.RUNNING.value and agent_execution.status != AgentExecutionStatus.WAITING_FOR_PERMISSION.value): logger.error(f"Agent execution stopped. {agent.id}: {agent_execution.status}") return @@ -56,7 +63,8 @@ def execute_next_step(self, agent_execution_id): return try: - model_config = AgentConfiguration.get_model_api_key(session, agent_execution.agent_id, agent_config["model"]) + model_config = AgentConfiguration.get_model_api_key(session, agent_execution.agent_id, + agent_config["model"]) model_api_key = model_config['api_key'] model_llm_source = model_config['provider'] except Exception as e: @@ -66,9 +74,10 @@ def execute_next_step(self, agent_execution_id): try: memory = None if "OpenAI" in model_llm_source: - vector_store_type = VectorStoreType.get_vector_store_type(get_config("LTM_DB","Redis")) + vector_store_type = VectorStoreType.get_vector_store_type(get_config("LTM_DB", "Redis")) memory = VectorFactory.get_vector_storage(vector_store_type, "super-agent-index1", - AgentExecutor.get_embedding(model_llm_source, model_api_key)) + AgentExecutor.get_embedding(model_llm_source, + model_api_key)) except Exception as e: logger.info(f"Unable to setup the connection...{e}") memory = None @@ -76,21 +85,9 @@ def execute_next_step(self, agent_execution_id): agent_workflow_step = session.query(AgentWorkflowStep).filter( AgentWorkflowStep.id == agent_execution.current_agent_step_id).first() try: - if agent_workflow_step.action_type == "TOOL": - tool_step_handler = AgentToolStepHandler(session, - llm=get_model(model=agent_config["model"], api_key=model_api_key, organisation_id=organisation.id) - , agent_id=agent.id, agent_execution_id=agent_execution_id, - memory=memory) - tool_step_handler.execute_step() - elif agent_workflow_step.action_type == "ITERATION_WORKFLOW": - iteration_step_handler = AgentIterationStepHandler(session, - llm=get_model(model=agent_config["model"], - api_key=model_api_key, - organisation_id=organisation.id) - , agent_id=agent.id, - agent_execution_id=agent_execution_id, memory=memory) - print(get_model(model=agent_config["model"], api_key=model_api_key, organisation_id=organisation.id)) - iteration_step_handler.execute_step() + self.__execute_workflow_step(agent, agent_config, agent_execution_id, agent_workflow_step, memory, + model_api_key, organisation, session) + except Exception as e: logger.info("Exception in executing the step: {}".format(e)) superagi.worker.execute_agent.apply_async((agent_execution_id, datetime.now()), countdown=15) @@ -107,6 +104,30 @@ def execute_next_step(self, agent_execution_id): session.close() engine.dispose() + def __execute_workflow_step(self, agent, agent_config, agent_execution_id, agent_workflow_step, memory, + model_api_key, organisation, session): + logger.info("Executing Workflow step : ", agent_workflow_step.action_type) + if agent_workflow_step.action_type == AgentWorkflowStepAction.TOOL.value: + tool_step_handler = AgentToolStepHandler(session, + llm=get_model(model=agent_config["model"], api_key=model_api_key, + organisation_id=organisation.id) + , agent_id=agent.id, agent_execution_id=agent_execution_id, + memory=memory) + tool_step_handler.execute_step() + elif agent_workflow_step.action_type == AgentWorkflowStepAction.ITERATION_WORKFLOW.value: + iteration_step_handler = AgentIterationStepHandler(session, + llm=get_model(model=agent_config["model"], + api_key=model_api_key, + organisation_id=organisation.id) + , agent_id=agent.id, + agent_execution_id=agent_execution_id, memory=memory) + print(get_model(model=agent_config["model"], api_key=model_api_key, organisation_id=organisation.id)) + iteration_step_handler.execute_step() + elif agent_workflow_step.action_type == AgentWorkflowStepAction.WAIT_STEP.value: + (AgentWaitStepHandler(session=session, agent_id=agent.id, + agent_execution_id=agent_execution_id) + .execute_step()) + @classmethod def get_embedding(cls, model_source, model_api_key): if "OpenAI" in model_source: @@ -122,7 +143,7 @@ def get_embedding(cls, model_source, model_api_key): def _check_for_max_iterations(self, session, organisation_id, agent_config, agent_execution_id): db_agent_execution = session.query(AgentExecution).filter(AgentExecution.id == agent_execution_id).first() if agent_config["max_iterations"] <= db_agent_execution.num_of_calls: - db_agent_execution.status = "ITERATION_LIMIT_EXCEEDED" + db_agent_execution.status = AgentExecutionStatus.ITERATION_LIMIT_EXCEEDED.value EventHandler(session=session).create_event('run_iteration_limit_crossed', {'agent_execution_id': db_agent_execution.id, @@ -133,4 +154,33 @@ def _check_for_max_iterations(self, session, organisation_id, agent_config, agen session.commit() logger.info("ITERATION_LIMIT_CROSSED") return True - return False \ No newline at end of file + return False + + def execute_waiting_workflows(self): + """Check if wait time of wait workflow step is over and can be resumed.""" + + session = Session() + waiting_agent_executions = session.query(AgentExecution).filter( + AgentExecution.status == AgentExecutionStatus.WAIT_STEP.value, + ).all() + for agent_execution in waiting_agent_executions: + workflow_step = session.query(AgentWorkflowStep).filter( + AgentWorkflowStep.id == agent_execution.current_agent_step_id).first() + step_wait = AgentWorkflowStepWait.find_by_id(session, workflow_step.action_reference_id) + if step_wait is not None: + wait_time = step_wait.delay if not None else 0 + logger.info(f"Agent Execution ID: {agent_execution.id}") + logger.info(f"Wait time: {wait_time}") + logger.info(f"Wait begin time: {step_wait.wait_begin_time}") + logger.info(f"Current time: {datetime.now()}") + logger.info(f"Wait Difference : {(datetime.now() - step_wait.wait_begin_time).total_seconds()}") + if ((datetime.now() - step_wait.wait_begin_time).total_seconds() > wait_time + and step_wait.status == AgentWorkflowStepWaitStatus.WAITING.value): + agent_execution.status = AgentExecutionStatus.RUNNING.value + step_wait.status = AgentWorkflowStepWaitStatus.COMPLETED.value + session.commit() + session.flush() + AgentWaitStepHandler(session=session, agent_id=agent_execution.agent_id, + agent_execution_id=agent_execution.id).handle_next_step() + execute_agent.delay(agent_execution.id, datetime.now()) + session.close() diff --git a/superagi/llms/openai.py b/superagi/llms/openai.py index b8a97a44a..454f7ce19 100644 --- a/superagi/llms/openai.py +++ b/superagi/llms/openai.py @@ -77,16 +77,16 @@ def chat_completion(self, messages, max_tokens=get_config("MAX_MODEL_TOKEN_LIMIT return {"response": response, "content": content} except AuthenticationError as auth_error: logger.info("OpenAi AuthenticationError:", auth_error) - return {"error": "ERROR_AUTHENTICATION", "message": "Authentication error please check the api keys.."} + return {"error": "ERROR_AUTHENTICATION", "message": "Authentication error please check the api keys: "+str(auth_error)} except RateLimitError as api_error: logger.info("OpenAi RateLimitError:", api_error) - return {"error": "ERROR_RATE_LIMIT", "message": "Openai rate limit exceeded.."} + return {"error": "ERROR_RATE_LIMIT", "message": "Openai rate limit exceeded: "+str(api_error)} except InvalidRequestError as invalid_request_error: logger.info("OpenAi InvalidRequestError:", invalid_request_error) - return {"error": "ERROR_INVALID_REQUEST", "message": "Openai invalid request error.."} + return {"error": "ERROR_INVALID_REQUEST", "message": "Openai invalid request error: "+str(invalid_request_error)} except Exception as exception: logger.info("OpenAi Exception:", exception) - return {"error": "ERROR_OPENAI", "message": "Open ai exception"} + return {"error": "ERROR_OPENAI", "message": "Open ai exception: "+str(exception)} def verify_access_key(self): """ diff --git a/superagi/models/agent_execution.py b/superagi/models/agent_execution.py index 5cba5f509..73e1f8f15 100644 --- a/superagi/models/agent_execution.py +++ b/superagi/models/agent_execution.py @@ -37,6 +37,7 @@ class AgentExecution(DBBaseModel): permission_id = Column(Integer) iteration_workflow_step_id = Column(Integer) current_feed_group_id = Column(String) + last_shown_error_id = Column(Integer) def __repr__(self): """ diff --git a/superagi/models/agent_execution_feed.py b/superagi/models/agent_execution_feed.py index 61f449585..84cc4fbc1 100644 --- a/superagi/models/agent_execution_feed.py +++ b/superagi/models/agent_execution_feed.py @@ -27,6 +27,7 @@ class AgentExecutionFeed(DBBaseModel): role = Column(String) extra_info = Column(String) feed_group_id = Column(String) + error_message = Column(String) def __repr__(self): """ diff --git a/superagi/models/user.py b/superagi/models/user.py index 519095756..6ef8bb694 100644 --- a/superagi/models/user.py +++ b/superagi/models/user.py @@ -24,6 +24,7 @@ class User(DBBaseModel): email = Column(String, unique=True) password = Column(String) organisation_id = Column(Integer) + first_login_source = Column(String) def __repr__(self): """ @@ -34,4 +35,4 @@ def __repr__(self): """ return f"User(id={self.id}, name='{self.name}', email='{self.email}', password='{self.password}'," \ - f"organisation_id={self.organisation_id})" + f"organisation_id={self.organisation_id}, first_login_source={self.first_login_source})" diff --git a/superagi/models/workflows/agent_workflow_step.py b/superagi/models/workflows/agent_workflow_step.py index 49af055d2..b7a3ada16 100644 --- a/superagi/models/workflows/agent_workflow_step.py +++ b/superagi/models/workflows/agent_workflow_step.py @@ -1,12 +1,12 @@ import json -from sqlalchemy import Column, Integer, String, Text, Boolean +from sqlalchemy import Column, Integer, String from sqlalchemy.dialects.postgresql import JSONB from superagi.lib.logger import logger -from superagi.models import db from superagi.models.base_model import DBBaseModel from superagi.models.workflows.agent_workflow_step_tool import AgentWorkflowStepTool +from superagi.models.workflows.agent_workflow_step_wait import AgentWorkflowStepWait from superagi.models.workflows.iteration_workflow import IterationWorkflow @@ -30,9 +30,9 @@ class AgentWorkflowStep(DBBaseModel): agent_workflow_id = Column(Integer) unique_id = Column(String) step_type = Column(String) # TRIGGER, NORMAL - action_type = Column(String) # TOOL, ITERATION_WORKFLOW, LLM + action_type = Column(String) # TOOL, ITERATION_WORKFLOW, LLM, WAIT_STEP action_reference_id = Column(Integer) # id of the action - next_steps = Column(JSONB) # edge_ref_id, response, step_id + next_steps = Column(JSONB) # edge_ref_id, response, step_id def __repr__(self): """ @@ -45,7 +45,7 @@ def __repr__(self): return f"AgentWorkflowStep(id={self.id}, status='{self.agent_workflow_id}', " \ f"prompt='{self.unique_id}', agent_id={self.step_type}, action_type={self.action_type}, " \ f"action_reference_id={self.action_reference_id}, next_steps={self.next_steps})" - + def to_dict(self): """ Converts the AgentWorkflowStep object to a dictionary. @@ -150,6 +150,29 @@ def find_or_create_tool_workflow_step(cls, session, agent_workflow_id: int, uniq session.commit() return workflow_step + @classmethod + def find_or_create_wait_workflow_step(cls, session, agent_workflow_id: int, unique_id: str, + wait_description: str, delay: int, step_type="NORMAL"): + """ Find or create a wait workflow step""" + logger.info("Finding or creating wait step") + workflow_step = session.query(AgentWorkflowStep).filter( + AgentWorkflowStep.agent_workflow_id == agent_workflow_id, AgentWorkflowStep.unique_id == unique_id).first() + + step_wait = AgentWorkflowStepWait.find_or_create_wait(session=session, step_unique_id=unique_id, + description=wait_description, delay=delay) + if workflow_step is None: + workflow_step = AgentWorkflowStep(unique_id=unique_id, step_type=step_type, + agent_workflow_id=agent_workflow_id) + session.add(workflow_step) + session.commit() + workflow_step.step_type = step_type + workflow_step.agent_workflow_id = agent_workflow_id + workflow_step.action_reference_id = step_wait.id + workflow_step.action_type = "WAIT_STEP" + workflow_step.next_steps = [] + session.commit() + return workflow_step + @classmethod def find_or_create_iteration_workflow_step(cls, session, agent_workflow_id: int, unique_id: str, iteration_workflow_name: str, step_type="NORMAL"): @@ -184,7 +207,8 @@ def find_or_create_iteration_workflow_step(cls, session, agent_workflow_id: int, return workflow_step @classmethod - def add_next_workflow_step(cls, session, current_agent_step_id: int, next_step_id: int, step_response: str = "default"): + def add_next_workflow_step(cls, session, current_agent_step_id: int, next_step_id: int, + step_response: str = "default"): """ Add Next workflow steps in the next_steps column Args: @@ -251,7 +275,3 @@ def fetch_next_step(cls, session, current_agent_step_id: int, step_response: str return "COMPLETE" return AgentWorkflowStep.find_by_unique_id(session, default_steps[0]["step_id"]) return None - - - - diff --git a/superagi/models/workflows/agent_workflow_step_wait.py b/superagi/models/workflows/agent_workflow_step_wait.py new file mode 100644 index 000000000..f24540b1f --- /dev/null +++ b/superagi/models/workflows/agent_workflow_step_wait.py @@ -0,0 +1,89 @@ +import json + +from sqlalchemy import Column, Integer, String, DateTime + +from superagi.models.base_model import DBBaseModel + + +class AgentWorkflowStepWait(DBBaseModel): + """ + Step for a Agent Workflow to wait + + Attributes: + id (int): The unique identifier of the wait block step. + name (str): The name of the wait block step. + description (str): The description of the wait block step. + delay (int): The delay time in seconds. + wait_begin_time (DateTime): The start time of the wait block. + """ + + __tablename__ = 'agent_workflow_step_waits' + + id = Column(Integer, primary_key=True) + name = Column(String) + description = Column(String) + unique_id = Column(String) + delay = Column(Integer) # Delay is stored in seconds + wait_begin_time = Column(DateTime) + status = Column(String) # 'PENDING', 'WAITING', 'COMPLETED' + + def __repr__(self): + """ + Returns a string representation of the WaitBlockStep object. + + Returns: + str: String representation of the WaitBlockStep. + """ + + return f"WaitBlockStep(id={self.id}, name='{self.name}', delay='{self.delay}', " \ + f"wait_begin_time='{self.wait_begin_time}'" + + def to_dict(self): + """ + Converts the WaitBlockStep object to a dictionary. + + Returns: + dict: Dictionary representation of the WaitBlockStep. + """ + + return { + 'id': self.id, + 'name': self.name, + 'delay': self.delay, + 'wait_begin_time': self.wait_begin_time + } + + def to_json(self): + """ + Converts the WaitBlockStep object to a JSON string. + + Returns: + str: JSON string representation of the WaitBlockStep. + """ + + return json.dumps(self.to_dict()) + + @classmethod + def find_by_id(cls, session, step_id: int): + return session.query(AgentWorkflowStepWait).filter(AgentWorkflowStepWait.id == step_id).first() + + @classmethod + def find_or_create_wait(cls, session, step_unique_id: str, description: str, delay: int): + unique_id = f"{step_unique_id}_wait" + wait = session.query(AgentWorkflowStepWait).filter(AgentWorkflowStepWait.unique_id == unique_id).first() + if wait is None: + wait = AgentWorkflowStepWait( + unique_id=unique_id, + name=unique_id, + delay=delay, + description=description, + status='PENDING' + ) + session.add(wait) + else: + wait.delay = delay + wait.description = description + wait.status = 'PENDING' + session.commit() + session.flush() + return wait diff --git a/superagi/tools/apollo/apollo_search.py b/superagi/tools/apollo/apollo_search.py index d9951a4e5..974638cc7 100644 --- a/superagi/tools/apollo/apollo_search.py +++ b/superagi/tools/apollo/apollo_search.py @@ -73,7 +73,7 @@ def _execute(self, person_titles: list[str], page: int = 1, per_page: int = 25, num_of_employees, person_location, organization_domains) logger.info(people_data) people_list = [] - if 'people' in people_data and len(people_data['people']) > 0: + if people_data and 'people' in people_data and len(people_data['people']) > 0: for person in people_data['people']: people_list.append({'first_name': person['first_name'], 'last_name': person['last_name'], @@ -130,3 +130,4 @@ def apollo_search_results(self, page, per_page, person_titles, num_of_employees return response.json() else: return None + diff --git a/superagi/tools/code/improve_code.py b/superagi/tools/code/improve_code.py index c54856811..a825ba47a 100644 --- a/superagi/tools/code/improve_code.py +++ b/superagi/tools/code/improve_code.py @@ -4,10 +4,13 @@ from pydantic import BaseModel, Field from superagi.agent.agent_prompt_builder import AgentPromptBuilder +from superagi.helper.error_handler import ErrorHandler from superagi.helper.prompt_reader import PromptReader from superagi.helper.token_counter import TokenCounter from superagi.lib.logger import logger from superagi.llms.base_llm import BaseLlm +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed from superagi.resource_manager.file_manager import FileManager from superagi.tools.base_tool import BaseTool from superagi.tools.tool_response_query_manager import ToolResponseQueryManager @@ -29,6 +32,7 @@ class ImproveCodeTool(BaseTool): """ llm: Optional[BaseLlm] = None agent_id: int = None + agent_execution_id: int = None name = "ImproveCodeTool" description = ( "This tool improves the generated code." @@ -71,6 +75,9 @@ def _execute(self) -> str: # Use LLM to generate improved code result = self.llm.chat_completion([{'role': 'system', 'content': prompt}]) + + if result is not None and 'error' in result and result['message'] is not None: + ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message']) # Extract the response first response = result.get('response') diff --git a/superagi/tools/code/write_code.py b/superagi/tools/code/write_code.py index 87fdca118..a799fc656 100644 --- a/superagi/tools/code/write_code.py +++ b/superagi/tools/code/write_code.py @@ -4,10 +4,13 @@ from pydantic import BaseModel, Field from superagi.agent.agent_prompt_builder import AgentPromptBuilder +from superagi.helper.error_handler import ErrorHandler from superagi.helper.prompt_reader import PromptReader from superagi.helper.token_counter import TokenCounter from superagi.lib.logger import logger from superagi.llms.base_llm import BaseLlm +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed from superagi.resource_manager.file_manager import FileManager from superagi.tools.base_tool import BaseTool from superagi.tools.tool_response_query_manager import ToolResponseQueryManager @@ -34,6 +37,7 @@ class CodingTool(BaseTool): """ llm: Optional[BaseLlm] = None agent_id: int = None + agent_execution_id: int = None name = "CodingTool" description = ( "You will get instructions for code to write. You will write a very long answer. " @@ -75,6 +79,9 @@ def _execute(self, code_description: str) -> str: token_limit = TokenCounter(session=self.toolkit_config.session, organisation_id=organisation.id).token_limit(self.llm.get_model()) result = self.llm.chat_completion(messages, max_tokens=(token_limit - total_tokens - 100)) + + if 'error' in result and result['message'] is not None: + ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message']) # Get all filenames and corresponding code blocks regex = r"(\S+?)\n```\S*\n(.+?)```" diff --git a/superagi/tools/code/write_spec.py b/superagi/tools/code/write_spec.py index 91b5bd843..9793d726e 100644 --- a/superagi/tools/code/write_spec.py +++ b/superagi/tools/code/write_spec.py @@ -3,10 +3,13 @@ from pydantic import BaseModel, Field from superagi.agent.agent_prompt_builder import AgentPromptBuilder +from superagi.helper.error_handler import ErrorHandler from superagi.helper.prompt_reader import PromptReader from superagi.helper.token_counter import TokenCounter from superagi.lib.logger import logger from superagi.llms.base_llm import BaseLlm +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed from superagi.resource_manager.file_manager import FileManager from superagi.tools.base_tool import BaseTool from superagi.models.agent import Agent @@ -37,6 +40,7 @@ class WriteSpecTool(BaseTool): """ llm: Optional[BaseLlm] = None agent_id: int = None + agent_execution_id: int = None name = "WriteSpecTool" description = ( "A tool to write the spec of a program." @@ -69,6 +73,9 @@ def _execute(self, task_description: str, spec_file_name: str) -> str: token_limit = TokenCounter(session=self.toolkit_config.session, organisation_id=organisation.id).token_limit(self.llm.get_model()) result = self.llm.chat_completion(messages, max_tokens=(token_limit - total_tokens - 100)) + + if 'error' in result and result['message'] is not None: + ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message']) # Save the specification to a file write_result = self.resource_manager.write_file(spec_file_name, result["content"]) diff --git a/superagi/tools/code/write_test.py b/superagi/tools/code/write_test.py index de0ece534..3b446fc36 100644 --- a/superagi/tools/code/write_test.py +++ b/superagi/tools/code/write_test.py @@ -4,10 +4,13 @@ from pydantic import BaseModel, Field from superagi.agent.agent_prompt_builder import AgentPromptBuilder +from superagi.helper.error_handler import ErrorHandler from superagi.helper.prompt_reader import PromptReader from superagi.helper.token_counter import TokenCounter from superagi.lib.logger import logger from superagi.llms.base_llm import BaseLlm +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed from superagi.resource_manager.file_manager import FileManager from superagi.tools.base_tool import BaseTool from superagi.tools.tool_response_query_manager import ToolResponseQueryManager @@ -38,6 +41,7 @@ class WriteTestTool(BaseTool): """ llm: Optional[BaseLlm] = None agent_id: int = None + agent_execution_id: int = None name = "WriteTestTool" description = ( "You are a super smart developer using Test Driven Development to write tests according to a specification.\n" @@ -86,6 +90,9 @@ def _execute(self, test_description: str, test_file_name: str) -> str: token_limit = TokenCounter(session=self.toolkit_config.session, organisation_id=organisation.id).token_limit(self.llm.get_model()) result = self.llm.chat_completion(messages, max_tokens=(token_limit - total_tokens - 100)) + + if 'error' in result and result['message'] is not None: + ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message']) regex = r"(\S+?)\n```\S*\n(.+?)```" matches = re.finditer(regex, result["content"], re.DOTALL) diff --git a/superagi/tools/duck_duck_go/duck_duck_go_search.py b/superagi/tools/duck_duck_go/duck_duck_go_search.py index 47223e4cc..43c0d2ec0 100644 --- a/superagi/tools/duck_duck_go/duck_duck_go_search.py +++ b/superagi/tools/duck_duck_go/duck_duck_go_search.py @@ -2,12 +2,15 @@ import requests from typing import Type, Optional,Union import time +from superagi.helper.error_handler import ErrorHandler from superagi.lib.logger import logger from pydantic import BaseModel, Field from duckduckgo_search import DDGS from itertools import islice from superagi.helper.token_counter import TokenCounter from superagi.llms.base_llm import BaseLlm +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed from superagi.tools.base_tool import BaseTool from superagi.helper.webpage_extractor import WebpageExtractor @@ -33,6 +36,8 @@ class DuckDuckGoSearchTool(BaseTool): """ llm: Optional[BaseLlm] = None name = "DuckDuckGoSearch" + agent_id: int = None + agent_execution_id: int = None description = ( "A tool for performing a DuckDuckGo search and extracting snippets and webpages." "Input should be a search query." @@ -169,4 +174,7 @@ def summarise_result(self, query, snippets): messages = [{"role": "system", "content": summarize_prompt}] result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit) + + if 'error' in result and result['message'] is not None: + ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message']) return result["content"] diff --git a/superagi/tools/github/review_pull_request.py b/superagi/tools/github/review_pull_request.py index a230c0701..c76a460b4 100644 --- a/superagi/tools/github/review_pull_request.py +++ b/superagi/tools/github/review_pull_request.py @@ -2,6 +2,7 @@ from typing import Type, Optional from pydantic import BaseModel, Field +from superagi.helper.error_handler import ErrorHandler from superagi.helper.github_helper import GithubHelper from superagi.helper.json_cleaner import JsonCleaner @@ -9,6 +10,8 @@ from superagi.helper.token_counter import TokenCounter from superagi.llms.base_llm import BaseLlm from superagi.models.agent import Agent +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed from superagi.tools.base_tool import BaseTool @@ -87,6 +90,9 @@ def run_code_review(self, github_helper, content, latest_commit_id, organisation token_limit = TokenCounter(session=self.toolkit_config.session, organisation_id=organisation.id).token_limit(self.llm.get_model()) result = self.llm.chat_completion(messages, max_tokens=(token_limit - total_tokens - 100)) + + if 'error' in result and result['message'] is not None: + ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message']) response = result["content"] if response.startswith("```") and response.endswith("```"): response = "```".join(response.split("```")[1:-1]) diff --git a/superagi/tools/google_search/google_search.py b/superagi/tools/google_search/google_search.py index c0c7e875b..9880266da 100644 --- a/superagi/tools/google_search/google_search.py +++ b/superagi/tools/google_search/google_search.py @@ -2,13 +2,15 @@ from typing import Type, Optional from pydantic import BaseModel, Field +from superagi.helper.error_handler import ErrorHandler from superagi.helper.google_search import GoogleSearchWrap from superagi.helper.token_counter import TokenCounter from superagi.llms.base_llm import BaseLlm +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed from superagi.tools.base_tool import BaseTool - class GoogleSearchSchema(BaseModel): query: str = Field( ..., @@ -26,6 +28,8 @@ class GoogleSearchTool(BaseTool): """ llm: Optional[BaseLlm] = None name = "GoogleSearch" + agent_id: int = None + agent_execution_id: int = None description = ( "A tool for performing a Google search and extracting snippets and webpages." "Input should be a search query." @@ -88,4 +92,7 @@ def summarise_result(self, query, snippets): messages = [{"role": "system", "content": summarize_prompt}] result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit) + + if 'error' in result and result['message'] is not None: + ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message']) return result["content"] diff --git a/superagi/tools/google_serp_search/google_serp_search.py b/superagi/tools/google_serp_search/google_serp_search.py index e3b0cb438..4f9d46c43 100644 --- a/superagi/tools/google_serp_search/google_serp_search.py +++ b/superagi/tools/google_serp_search/google_serp_search.py @@ -1,8 +1,11 @@ from typing import Type, Optional, Any from pydantic import BaseModel, Field import aiohttp +from superagi.helper.error_handler import ErrorHandler from superagi.helper.google_serp import GoogleSerpApiWrap from superagi.llms.base_llm import BaseLlm +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed from superagi.tools.base_tool import BaseTool import os @@ -28,6 +31,8 @@ class GoogleSerpTool(BaseTool): """ llm: Optional[BaseLlm] = None name = "GoogleSerp" + agent_id: int = None + agent_execution_id: int = None description = ( "A tool for performing a Google SERP search and extracting snippets and webpages." "Input should be a search query." @@ -66,4 +71,7 @@ def summarise_result(self, query, snippets): messages = [{"role": "system", "content": summarize_prompt}] result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit) + + if 'error' in result and result['message'] is not None: + ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message']) return result["content"] diff --git a/superagi/tools/instagram_tool/instagram.py b/superagi/tools/instagram_tool/instagram.py index bc423b6e9..5d9e68b35 100644 --- a/superagi/tools/instagram_tool/instagram.py +++ b/superagi/tools/instagram_tool/instagram.py @@ -3,11 +3,13 @@ import boto3 import os from superagi.config.config import get_config +from superagi.helper.error_handler import ErrorHandler from superagi.helper.resource_helper import ResourceHelper from typing import Type, Optional from pydantic import BaseModel, Field from superagi.helper.token_counter import TokenCounter from superagi.llms.base_llm import BaseLlm +from superagi.models.agent_execution_feed import AgentExecutionFeed from superagi.tools.base_tool import BaseTool import os import requests @@ -114,6 +116,8 @@ def create_caption(self, photo_description: str) -> str: messages = [{"role": "system", "content": caption_prompt}] result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit) + if 'error' in result and result['message'] is not None: + ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message']) caption=result["content"] encoded_caption=urllib. parse. quote(caption) diff --git a/superagi/tools/searx/searx.py b/superagi/tools/searx/searx.py index 49e09a072..6ba455511 100644 --- a/superagi/tools/searx/searx.py +++ b/superagi/tools/searx/searx.py @@ -1,6 +1,9 @@ from typing import Type, Optional from pydantic import BaseModel, Field +from superagi.helper.error_handler import ErrorHandler from superagi.llms.base_llm import BaseLlm +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed from superagi.tools.base_tool import BaseTool from superagi.tools.searx.search_scraper import search_results @@ -22,6 +25,8 @@ class SearxSearchTool(BaseTool): """ llm: Optional[BaseLlm] = None name = "SearxSearch" + agent_id:int =None + agent_execution_id:int =None description = ( "A tool for performing a Searx search and extracting snippets and webpages." "Input should be a search query." @@ -67,4 +72,7 @@ def summarise_result(self, query, snippets): messages = [{"role": "system", "content": summarize_prompt}] result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit) + + if 'error' in result and result['message'] is not None: + ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message']) return result["content"] diff --git a/superagi/tools/thinking/tools.py b/superagi/tools/thinking/tools.py index 8bdc38ca5..370eeee4f 100644 --- a/superagi/tools/thinking/tools.py +++ b/superagi/tools/thinking/tools.py @@ -3,9 +3,12 @@ from pydantic import BaseModel, Field from superagi.agent.agent_prompt_builder import AgentPromptBuilder +from superagi.helper.error_handler import ErrorHandler from superagi.helper.prompt_reader import PromptReader from superagi.lib.logger import logger from superagi.llms.base_llm import BaseLlm +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed from superagi.tools.base_tool import BaseTool from superagi.tools.tool_response_query_manager import ToolResponseQueryManager @@ -34,6 +37,7 @@ class ThinkingTool(BaseTool): args_schema: Type[ThinkingSchema] = ThinkingSchema goals: List[str] = [] agent_execution_id:int=None + agent_id:int = None permission_required: bool = False tool_response_manager: Optional[ToolResponseQueryManager] = None @@ -62,6 +66,9 @@ def _execute(self, task_description: str): prompt = prompt.replace("{relevant_tool_response}",relevant_tool_response) messages = [{"role": "system", "content": prompt}] result = self.llm.chat_completion(messages, max_tokens=self.max_token_limit) + + if 'error' in result and result['message'] is not None: + ErrorHandler.handle_openai_errors(self.toolkit_config.session, self.agent_id, self.agent_execution_id, result['message']) return result["content"] except Exception as e: logger.error(e) diff --git a/superagi/tools/tool_response_query_manager.py b/superagi/tools/tool_response_query_manager.py index 0bf708b39..2429945b1 100644 --- a/superagi/tools/tool_response_query_manager.py +++ b/superagi/tools/tool_response_query_manager.py @@ -15,8 +15,7 @@ def get_last_response(self, tool_name: str = None): def get_relevant_response(self, query: str,metadata:dict, top_k: int = 5): if self.memory is None: return "" - documents = self.memory.get_matching_text(query, metadata=metadata, - top_k=top_k) + documents = self.memory.get_matching_text(query, metadata=metadata) relevant_responses = "" for document in documents["documents"]: relevant_responses += document.text_content diff --git a/superagi/worker.py b/superagi/worker.py index f31e5fc96..b6c2cace4 100644 --- a/superagi/worker.py +++ b/superagi/worker.py @@ -34,6 +34,10 @@ 'task': 'initialize-schedule-agent', 'schedule': timedelta(minutes=5), }, + 'execute_waiting_workflows': { + 'task': 'execute_waiting_workflows', + 'schedule': timedelta(minutes=2), + }, } app.conf.beat_schedule = beat_schedule @@ -41,11 +45,19 @@ def agent_status_change(target, val,old_val,initiator): if not hasattr(sys, '_called_from_test'): webhook_callback.delay(target.id,val,old_val) - + +@app.task(name="execute_waiting_workflows", autoretry_for=(Exception,), retry_backoff=2, max_retries=5) +def execute_waiting_workflows(): + """Check if wait time of wait workflow step is over and can be resumed.""" + + from superagi.jobs.agent_executor import AgentExecutor + logger.info("Executing waiting workflows job") + AgentExecutor().execute_waiting_workflows() + @app.task(name="initialize-schedule-agent", autoretry_for=(Exception,), retry_backoff=2, max_retries=5) def initialize_schedule_agent_task(): """Executing agent scheduling in the background.""" - + schedule_helper = AgentScheduleHelper() schedule_helper.update_next_scheduled_time() schedule_helper.run_scheduled_agents() diff --git a/tests/unit_tests/agent/test_agent_workflow_step_wait_handler.py b/tests/unit_tests/agent/test_agent_workflow_step_wait_handler.py new file mode 100644 index 000000000..c0fb55440 --- /dev/null +++ b/tests/unit_tests/agent/test_agent_workflow_step_wait_handler.py @@ -0,0 +1,67 @@ +from datetime import datetime +from unittest.mock import MagicMock, patch + +import pytest + +from superagi.models.agent_execution import AgentExecution +from superagi.models.workflows.agent_workflow_step import AgentWorkflowStep +from superagi.agent.agent_workflow_step_wait_handler import AgentWaitStepHandler + + +# Mock datetime.now() for testing +@pytest.fixture +def mock_datetime_now(): + return datetime(2023, 9, 6, 12, 0, 0) + + +@pytest.fixture(autouse=True) +def mock_datetime_now_fixture(monkeypatch, mock_datetime_now): + monkeypatch.setattr("superagi.agent.agent_workflow_step_wait_handler.datetime", + MagicMock(now=MagicMock(return_value=mock_datetime_now))) + +# Test cases +@patch.object(AgentExecution, 'get_agent_execution_from_id') +@patch.object(AgentWorkflowStep, 'find_by_id') +@patch.object(AgentWorkflowStep, 'fetch_next_step') +def test_handle_next_step_complete(mock_fetch_next_step, mock_find_by_id, mock_get_agent_execution_from_id, mock_datetime_now_fixture): + mock_session = MagicMock() + mock_agent_execution = MagicMock(current_agent_step_id=1, status="WAIT_STEP") + + mock_get_agent_execution_from_id.return_value = mock_agent_execution + mock_find_by_id.return_value = MagicMock() + + mock_next_step = MagicMock(id=2) + mock_next_step.__str__.return_value = "COMPLETE" + mock_fetch_next_step.return_value = mock_next_step + + handler = AgentWaitStepHandler(mock_session, 1, 2) + + handler.handle_next_step() + + # Assertions + assert mock_agent_execution.current_agent_step_id == -1 + assert mock_agent_execution.status == "COMPLETED" + mock_session.commit.assert_called_once() + + +# Test cases +@patch.object(AgentExecution, 'get_agent_execution_from_id') +@patch.object(AgentWorkflowStep, 'find_by_id') +@patch.object(AgentWorkflowStep, 'fetch_next_step') +def test_execute_step(mock_fetch_next_step, mock_find_by_id, mock_get_agent_execution_from_id): + mock_session = MagicMock() + mock_agent_execution = MagicMock(current_agent_step_id=1, status="WAIT_STEP") + mock_step_wait = MagicMock(status="WAITING") + + mock_get_agent_execution_from_id.return_value = mock_agent_execution + mock_find_by_id.return_value = mock_step_wait + mock_fetch_next_step.return_value = MagicMock() + + handler = AgentWaitStepHandler(mock_session, 1, 2) + + handler.execute_step() + + # Assertions + assert mock_step_wait.status == "WAITING" + assert mock_agent_execution.status == "WAIT_STEP" + mock_session.commit.assert_called_once() \ No newline at end of file diff --git a/tests/unit_tests/apm/test_tools_handler.py b/tests/unit_tests/apm/test_tools_handler.py index f805bbdf1..da13bca1e 100644 --- a/tests/unit_tests/apm/test_tools_handler.py +++ b/tests/unit_tests/apm/test_tools_handler.py @@ -27,31 +27,29 @@ def test_calculate_tool_usage(tools_handler, mock_session): tool_used_subquery.c.tool_name = 'Tool1' tool_used_subquery.c.agent_id = 1 - agent_count_subquery.c.tool_name = 'Tool1' agent_count_subquery.c.unique_agents = 1 - total_usage_subquery.c.tool_name = 'Tool1' total_usage_subquery.c.total_usage = 5 - tools_handler.get_tool_and_toolkit = MagicMock() - tools_handler.get_tool_and_toolkit.return_value = {'Tool1': 'Toolkit1'} - - mock_session.query().filter_by().subquery.return_value = tool_used_subquery - mock_session.query().group_by().subquery.return_value = agent_count_subquery - mock_session.query().group_by().subquery.return_value = total_usage_subquery + mock_session.query.return_value.filter_by.return_value.subquery.return_value = tool_used_subquery + mock_session.query.return_value.group_by.return_value.subquery.side_effect = [agent_count_subquery, total_usage_subquery] result_obj = MagicMock() result_obj.tool_name = 'Tool1' result_obj.unique_agents = 1 result_obj.total_usage = 5 - mock_session.query().join().all.return_value = [result_obj] + + mock_session.query.return_value.join.return_value.all.return_value = [result_obj] + + tools_handler.get_tool_and_toolkit = MagicMock(return_value={'tool1': 'Toolkit1'}) result = tools_handler.calculate_tool_usage() assert isinstance(result, list) expected_output = [{'tool_name': 'Tool1', 'unique_agents': 1, 'total_usage': 5, 'toolkit': 'Toolkit1'}] + assert result == expected_output def test_get_tool_and_toolkit(tools_handler, mock_session): diff --git a/tests/unit_tests/controllers/test_agent_execution_feeds.py b/tests/unit_tests/controllers/test_agent_execution_feeds.py new file mode 100644 index 000000000..bb0322617 --- /dev/null +++ b/tests/unit_tests/controllers/test_agent_execution_feeds.py @@ -0,0 +1,43 @@ +from unittest.mock import MagicMock, Mock, create_autospec, patch +import pytest +from fastapi.testclient import TestClient +from fastapi import HTTPException +from main import app +from fastapi_sqlalchemy import db +from superagi.controllers.agent_execution_feed import get_agent_execution_feed + +@patch('superagi.controllers.agent_execution_feed.db') +def test_get_agent_execution_feed(mock_query): + mock_session = create_autospec(pytest.Session) + + AgentExecution = MagicMock() + agent_execution = AgentExecution() + agent_execution.status = "PAUSED" + agent_execution.last_shown_error_id = None + + AgentExecutionFeed = MagicMock() + agent_execution_feed = AgentExecutionFeed() + agent_execution_feed.error_message = None + + feeds = [agent_execution_feed] + + check_auth = MagicMock() + AuthJWT = MagicMock() + check_auth.return_value = AuthJWT + asc = MagicMock() + + AgentExecutionPermission = MagicMock() + agent_execution_permission = AgentExecutionPermission() + agent_execution_permission.id = 1 + agent_execution_permission.created_at = "2021-12-13T00:00:00" + agent_execution_permission.response = "Yes" + agent_execution_permission.status = "Completed" + agent_execution_permission.tool_name = "Tool1" + agent_execution_permission.question = "Question1" + agent_execution_permission.user_feedback = "Feedback1" + + permissions = [agent_execution_permission] + mock_agent_execution = Mock() + mock_query.return_value.filter.return_value.first.return_value = mock_agent_execution + mock_agent_execution_id = 1 + assert get_agent_execution_feed(mock_agent_execution_id) \ No newline at end of file diff --git a/tests/unit_tests/controllers/test_user.py b/tests/unit_tests/controllers/test_user.py new file mode 100644 index 000000000..0ab124dd7 --- /dev/null +++ b/tests/unit_tests/controllers/test_user.py @@ -0,0 +1,37 @@ +from unittest.mock import patch + +import pytest +from fastapi.testclient import TestClient + +from main import app +from superagi.models.user import User + +client = TestClient(app) + +# Define a fixture for an authenticated user +@pytest.fixture +def authenticated_user(): + # Create a mock user object with necessary attributes + user = User() + + # Set user attributes + user.id = 1 # User ID + user.username = "testuser" # User's username + user.email = "super6@agi.com" # User's email + user.first_login_source = None # User's first login source + user.token = "mock-jwt-token" + + return user + +# Test case for updating first login source when it's not set +def test_update_first_login_source(authenticated_user): + with patch('superagi.helper.auth.db') as mock_auth_db: + source = "github" # Specify the source you want to set + + mock_auth_db.session.query.return_value.filter.return_value.first.return_value = authenticated_user + response = client.post(f"users/first_login_source/{source}", headers={"Authorization": f"Bearer {authenticated_user.token}"}) + + # Verify the HTTP response + assert response.status_code == 200 + assert "first_login_source" in response.json() # Check if the "first_login_source" field is in the response + assert response.json()["first_login_source"] == "github" # Check if the "source" field equals "github" \ No newline at end of file diff --git a/tests/unit_tests/helper/test_error_handling.py b/tests/unit_tests/helper/test_error_handling.py new file mode 100644 index 000000000..924b227c7 --- /dev/null +++ b/tests/unit_tests/helper/test_error_handling.py @@ -0,0 +1,19 @@ +import pytest +from unittest.mock import Mock, patch +from superagi.models.agent_execution import AgentExecution +from superagi.models.agent_execution_feed import AgentExecutionFeed +from superagi.helper.error_handler import ErrorHandler + +def test_handle_error(): + session = Mock() + agent_id = 1 + agent_execution_id = 2 + error_message = 'Test error' + + mock_query = Mock() + mock_query.filter().first.return_value = AgentExecution(id=agent_execution_id) + session.query.return_value = mock_query + + ErrorHandler.handle_openai_errors(session, agent_id, agent_execution_id, error_message) + + session.query.assert_called_once_with(AgentExecution) diff --git a/tests/unit_tests/helper/test_feed_parser.py b/tests/unit_tests/helper/test_feed_parser.py index 0f321a054..2915949eb 100644 --- a/tests/unit_tests/helper/test_feed_parser.py +++ b/tests/unit_tests/helper/test_feed_parser.py @@ -1,22 +1,16 @@ import unittest from datetime import datetime - from superagi.helper.feed_parser import parse_feed from superagi.models.agent_execution_feed import AgentExecutionFeed - - class TestParseFeed(unittest.TestCase): - def test_parse_feed_system(self): current_time = datetime.now() + sample_feed = AgentExecutionFeed( + id=2, agent_execution_id=100, agent_id=200, role="user", + feed='System message', updated_at=current_time + ) - # Create a sample AgentExecutionFeed object with a system role - sample_feed = AgentExecutionFeed(id=2, agent_execution_id=100, agent_id=200, role="assistant", - feed='System message', - updated_at=current_time) - - # Call the parse_feed function with the sample_feed object result = parse_feed(sample_feed) - - # In this test case, we only ensure that the parse_feed function doesn't modify the given feed - self.assertEqual(result, sample_feed, "Incorrect output from parse_feed function for system role") + + self.assertEqual(result['feed'], sample_feed.feed, "Incorrect output from parse_feed function for system role") + self.assertEqual(result['role'], sample_feed.role, "Incorrect output from parse_feed function for system role") \ No newline at end of file diff --git a/tests/unit_tests/tools/file/test_list_files.py b/tests/unit_tests/tools/file/test_list_files.py index 3177ed2b9..f895e6d91 100644 --- a/tests/unit_tests/tools/file/test_list_files.py +++ b/tests/unit_tests/tools/file/test_list_files.py @@ -1,4 +1,4 @@ -from unittest.mock import patch +from unittest.mock import MagicMock, patch import pytest @@ -9,6 +9,9 @@ def list_file_tool(): list_file_tool = ListFileTool() list_file_tool.agent_id = 1 # Set a dummy agent ID for testing. + # list_file_tool = "test_agent" + mock_session = MagicMock(name="session") + list_file_tool.toolkit_config.session = mock_session yield list_file_tool @@ -23,9 +26,12 @@ def test_list_files(list_file_tool): assert files == ['file1.txt', 'file3.txt', 'file4.txt'] - def test_execute(list_file_tool): - with patch.object(ListFileTool, 'list_files', return_value=['file1.txt', 'file2.txt']): + mock_get_formatted_agent_level_path = MagicMock(return_value="SuperAGI/workspace/input/{agent_id}/") + + with patch.object(ListFileTool, 'list_files', return_value=['file1.txt', 'file2.txt']), \ + patch('superagi.helper.resource_helper.ResourceHelper.get_formatted_agent_level_path', new=mock_get_formatted_agent_level_path): + files = list_file_tool._execute() assert files == ['file1.txt', 'file2.txt'] \ No newline at end of file
{item.created_at}{item.agent_name}{item.agent_execution_name}{item.model}{item.tokens_consumed}{item.created_at}{item.agent_name}{item.agent_execution_name}{item.model}{item.tokens_consumed}