From 130e2ea946ee52b9327fd37c76fc7cebfb15e64b Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Sun, 18 Jun 2023 16:28:52 -0700 Subject: initial code --- extension/react-app/package-lock.json | 402 +++++++++++++++++++++- extension/react-app/package.json | 3 + extension/react-app/src/components/CodeBlock.tsx | 4 +- extension/react-app/src/components/StyledCode.tsx | 14 + 4 files changed, 418 insertions(+), 5 deletions(-) create mode 100644 extension/react-app/src/components/StyledCode.tsx (limited to 'extension') diff --git a/extension/react-app/package-lock.json b/extension/react-app/package-lock.json index 64440da6..18ef3ee6 100644 --- a/extension/react-app/package-lock.json +++ b/extension/react-app/package-lock.json @@ -12,16 +12,19 @@ "@types/vscode-webview": "^1.57.1", "downshift": "^7.6.0", "posthog-js": "^1.58.0", + "prismjs": "^1.29.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-markdown": "^8.0.5", "react-redux": "^8.0.5", + "react-syntax-highlighter": "^15.5.0", "styled-components": "^5.3.6", "vscode-webview": "^1.0.1-beta.1" }, "devDependencies": { "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", + "@types/react-syntax-highlighter": "^15.5.7", "@types/styled-components": "^5.1.26", "@vitejs/plugin-react-swc": "^3.0.0", "autoprefixer": "^10.4.13", @@ -951,6 +954,15 @@ "@types/react": "*" } }, + "node_modules/@types/react-syntax-highlighter": { + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.7.tgz", + "integrity": "sha512-bo5fEO5toQeyCp0zVHBeggclqf5SQ/Z5blfFmjwO5dkMVGPgmiwZsJh9nu/Bo5L7IHTuGWrja6LxJVE2uB5ZrQ==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", @@ -1222,6 +1234,24 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -1533,6 +1563,18 @@ "reusify": "^1.0.4" } }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/fflate": { "version": "0.4.8", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", @@ -1550,6 +1592,14 @@ "node": ">=8" } }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/fraction.js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", @@ -1641,6 +1691,15 @@ "node": ">=4" } }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-whitespace": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", @@ -1650,6 +1709,60 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript/node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hastscript/node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hastscript/node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "engines": { + "node": "*" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -1668,6 +1781,28 @@ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" }, + "node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1714,6 +1849,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1735,6 +1879,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -1815,6 +1968,19 @@ "loose-envify": "cli.js" } }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/mdast-util-definitions": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", @@ -2402,6 +2568,32 @@ "node": ">= 6" } }, + "node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -2569,6 +2761,14 @@ "rrweb-snapshot": "^1.1.14" } }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -2721,6 +2921,21 @@ } } }, + "node_modules/react-syntax-highlighter": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz", + "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.4.1", + "lowlight": "^1.17.0", + "prismjs": "^1.27.0", + "refractor": "^3.6.0" + }, + "peerDependencies": { + "react": ">= 0.14.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -2742,6 +2957,28 @@ "node": ">=8.10.0" } }, + "node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", + "engines": { + "node": ">=6" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -3291,7 +3528,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, "engines": { "node": ">=0.4" } @@ -3846,6 +4082,15 @@ "@types/react": "*" } }, + "@types/react-syntax-highlighter": { + "version": "15.5.7", + "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.7.tgz", + "integrity": "sha512-bo5fEO5toQeyCp0zVHBeggclqf5SQ/Z5blfFmjwO5dkMVGPgmiwZsJh9nu/Bo5L7IHTuGWrja6LxJVE2uB5ZrQ==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", @@ -4028,6 +4273,16 @@ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==" }, + "character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==" + }, + "character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==" + }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -4271,6 +4526,14 @@ "reusify": "^1.0.4" } }, + "fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "requires": { + "format": "^0.2.0" + } + }, "fflate": { "version": "0.4.8", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", @@ -4285,6 +4548,11 @@ "to-regex-range": "^5.0.1" } }, + "format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==" + }, "fraction.js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", @@ -4347,11 +4615,53 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, + "hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==" + }, "hast-util-whitespace": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", "integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==" }, + "hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "requires": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "dependencies": { + "comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==" + }, + "property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "requires": { + "xtend": "^4.0.0" + } + }, + "space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==" + } + } + }, + "highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" + }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -4372,6 +4682,20 @@ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" }, + "is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==" + }, + "is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "requires": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -4395,6 +4719,11 @@ "has": "^1.0.3" } }, + "is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==" + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4410,6 +4739,11 @@ "is-extglob": "^2.1.1" } }, + "is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==" + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4464,6 +4798,15 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "requires": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + } + }, "mdast-util-definitions": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", @@ -4795,6 +5138,26 @@ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", "dev": true }, + "parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "requires": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "dependencies": { + "character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==" + } + } + }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -4892,6 +5255,11 @@ "rrweb-snapshot": "^1.1.14" } }, + "prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==" + }, "prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -4983,6 +5351,18 @@ "use-sync-external-store": "^1.0.0" } }, + "react-syntax-highlighter": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz", + "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==", + "requires": { + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.4.1", + "lowlight": "^1.17.0", + "prismjs": "^1.27.0", + "refractor": "^3.6.0" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -5001,6 +5381,23 @@ "picomatch": "^2.2.1" } }, + "refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "requires": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "dependencies": { + "prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==" + } + } + }, "regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", @@ -5348,8 +5745,7 @@ "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "yaml": { "version": "1.10.2", diff --git a/extension/react-app/package.json b/extension/react-app/package.json index a53fbec8..d43ec55e 100644 --- a/extension/react-app/package.json +++ b/extension/react-app/package.json @@ -13,16 +13,19 @@ "@types/vscode-webview": "^1.57.1", "downshift": "^7.6.0", "posthog-js": "^1.58.0", + "prismjs": "^1.29.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-markdown": "^8.0.5", "react-redux": "^8.0.5", + "react-syntax-highlighter": "^15.5.0", "styled-components": "^5.3.6", "vscode-webview": "^1.0.1-beta.1" }, "devDependencies": { "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", + "@types/react-syntax-highlighter": "^15.5.7", "@types/styled-components": "^5.1.26", "@vitejs/plugin-react-swc": "^3.0.0", "autoprefixer": "^10.4.13", diff --git a/extension/react-app/src/components/CodeBlock.tsx b/extension/react-app/src/components/CodeBlock.tsx index c4524a51..a720a6ce 100644 --- a/extension/react-app/src/components/CodeBlock.tsx +++ b/extension/react-app/src/components/CodeBlock.tsx @@ -5,6 +5,8 @@ import { defaultBorderRadius, secondaryDark, vscBackground } from "."; import { Clipboard, CheckCircle } from "@styled-icons/heroicons-outline"; +import StyledCode from "./StyledCode"; + const StyledPre = styled.pre` overflow-y: scroll; word-wrap: normal; @@ -16,8 +18,6 @@ const StyledPre = styled.pre` padding-bottom: 16px; `; -const StyledCode = styled.code``; - const StyledCopyButton = styled.button<{ visible: boolean }>` /* position: relative; */ float: right; diff --git a/extension/react-app/src/components/StyledCode.tsx b/extension/react-app/src/components/StyledCode.tsx new file mode 100644 index 00000000..16183e7f --- /dev/null +++ b/extension/react-app/src/components/StyledCode.tsx @@ -0,0 +1,14 @@ +import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; +import { synthwave84 } from "react-syntax-highlighter/dist/esm/styles/prism"; + +interface StyledCodeProps { + children: string; +} + +const StyledCode = (props: (StyledCodeProps)) => ( + + {props.children} + +); + +export default StyledCode; \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 93c7f35759726aaf58d14dae36fc39afd3419b3b Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Sun, 18 Jun 2023 17:35:27 -0700 Subject: making autodetect work --- extension/react-app/src/components/StyledCode.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'extension') diff --git a/extension/react-app/src/components/StyledCode.tsx b/extension/react-app/src/components/StyledCode.tsx index 16183e7f..2f8428dc 100644 --- a/extension/react-app/src/components/StyledCode.tsx +++ b/extension/react-app/src/components/StyledCode.tsx @@ -6,7 +6,7 @@ interface StyledCodeProps { } const StyledCode = (props: (StyledCodeProps)) => ( - + {props.children} ); -- cgit v1.2.3-70-g09d2 From f403bbe26b8864ff5367eab08afe4a01fdde8e72 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 18 Jun 2023 18:57:51 -0700 Subject: correctly get string from children --- extension/react-app/src/components/StyledCode.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'extension') diff --git a/extension/react-app/src/components/StyledCode.tsx b/extension/react-app/src/components/StyledCode.tsx index 2f8428dc..66135d65 100644 --- a/extension/react-app/src/components/StyledCode.tsx +++ b/extension/react-app/src/components/StyledCode.tsx @@ -2,13 +2,13 @@ import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { synthwave84 } from "react-syntax-highlighter/dist/esm/styles/prism"; interface StyledCodeProps { - children: string; + children: string; } -const StyledCode = (props: (StyledCodeProps)) => ( +const StyledCode = (props: StyledCodeProps) => ( - {props.children} + {(props.children as any).props.children} ); -export default StyledCode; \ No newline at end of file +export default StyledCode; -- cgit v1.2.3-70-g09d2 From bb5fc9624a940fe499f4748ca6df7d91e06edac4 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Tue, 20 Jun 2023 21:51:38 -0700 Subject: function calling! many changes here --- continuedev/poetry.lock | 74 ++++++- continuedev/pyproject.toml | 2 + continuedev/src/continuedev/core/abstract_sdk.py | 4 - continuedev/src/continuedev/core/main.py | 95 ++++++++- continuedev/src/continuedev/core/policy.py | 5 +- continuedev/src/continuedev/core/sdk.py | 60 +++--- continuedev/src/continuedev/libs/llm/__init__.py | 8 +- continuedev/src/continuedev/libs/llm/openai.py | 215 ++++----------------- .../src/continuedev/libs/llm/proxy_server.py | 98 +++++----- .../src/continuedev/libs/util/count_tokens.py | 84 ++++++++ continuedev/src/continuedev/steps/chat.py | 196 ++++++++++++++++++- continuedev/src/continuedev/steps/core/core.py | 6 +- continuedev/src/continuedev/steps/main.py | 1 + continuedev/src/continuedev/steps/on_traceback.py | 8 +- extension/react-app/src/tabs/gui.tsx | 8 +- 15 files changed, 570 insertions(+), 294 deletions(-) create mode 100644 continuedev/src/continuedev/libs/util/count_tokens.py (limited to 'extension') diff --git a/continuedev/poetry.lock b/continuedev/poetry.lock index 017f12f9..a49a570f 100644 --- a/continuedev/poetry.lock +++ b/continuedev/poetry.lock @@ -359,6 +359,21 @@ files = [ [package.extras] dev = ["attribution (==1.6.2)", "black (==23.3.0)", "flit (==3.8.0)", "mypy (==1.2.0)", "ufmt (==2.1.0)", "usort (==1.0.6)"] +[[package]] +name = "directory-tree" +version = "0.0.3.1" +description = "Utility Package that Displays out the Tree Structure of a Particular Directory." +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "directory_tree-0.0.3.1-py3-none-any.whl", hash = "sha256:72411e4f1534afaaccadb21fc082c727a680b6a74e8d21a1406ffbe51389cd85"}, + {file = "directory_tree-0.0.3.1.tar.gz", hash = "sha256:e4f40d60a45c4cdc0bc8e9ee29311f554dee6c969241c0eef8bcd92b4d4bcd4a"}, +] + +[package.extras] +dev = ["pytest (>=3.7)"] + [[package]] name = "fastapi" version = "0.95.1" @@ -597,6 +612,26 @@ files = [ {file = "jsonref-1.1.0.tar.gz", hash = "sha256:32fe8e1d85af0fdefbebce950af85590b22b60f9e95443176adbde4e1ecea552"}, ] +[[package]] +name = "jsonschema" +version = "4.17.3" +description = "An implementation of JSON Schema validation for Python" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jsonschema-4.17.3-py3-none-any.whl", hash = "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6"}, + {file = "jsonschema-4.17.3.tar.gz", hash = "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d"}, +] + +[package.dependencies] +attrs = ">=17.4.0" +pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + [[package]] name = "langchain" version = "0.0.171" @@ -1066,6 +1101,43 @@ typing-extensions = ">=4.2.0" dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] +[[package]] +name = "pyrsistent" +version = "0.19.3" +description = "Persistent/Functional/Immutable data structures" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyrsistent-0.19.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:20460ac0ea439a3e79caa1dbd560344b64ed75e85d8703943e0b66c2a6150e4a"}, + {file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c18264cb84b5e68e7085a43723f9e4c1fd1d935ab240ce02c0324a8e01ccb64"}, + {file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b774f9288dda8d425adb6544e5903f1fb6c273ab3128a355c6b972b7df39dcf"}, + {file = "pyrsistent-0.19.3-cp310-cp310-win32.whl", hash = "sha256:5a474fb80f5e0d6c9394d8db0fc19e90fa540b82ee52dba7d246a7791712f74a"}, + {file = "pyrsistent-0.19.3-cp310-cp310-win_amd64.whl", hash = "sha256:49c32f216c17148695ca0e02a5c521e28a4ee6c5089f97e34fe24163113722da"}, + {file = "pyrsistent-0.19.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f0774bf48631f3a20471dd7c5989657b639fd2d285b861237ea9e82c36a415a9"}, + {file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab2204234c0ecd8b9368dbd6a53e83c3d4f3cab10ecaf6d0e772f456c442393"}, + {file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e42296a09e83028b3476f7073fcb69ffebac0e66dbbfd1bd847d61f74db30f19"}, + {file = "pyrsistent-0.19.3-cp311-cp311-win32.whl", hash = "sha256:64220c429e42a7150f4bfd280f6f4bb2850f95956bde93c6fda1b70507af6ef3"}, + {file = "pyrsistent-0.19.3-cp311-cp311-win_amd64.whl", hash = "sha256:016ad1afadf318eb7911baa24b049909f7f3bb2c5b1ed7b6a8f21db21ea3faa8"}, + {file = "pyrsistent-0.19.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4db1bd596fefd66b296a3d5d943c94f4fac5bcd13e99bffe2ba6a759d959a28"}, + {file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aeda827381f5e5d65cced3024126529ddc4289d944f75e090572c77ceb19adbf"}, + {file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42ac0b2f44607eb92ae88609eda931a4f0dfa03038c44c772e07f43e738bcac9"}, + {file = "pyrsistent-0.19.3-cp37-cp37m-win32.whl", hash = "sha256:e8f2b814a3dc6225964fa03d8582c6e0b6650d68a232df41e3cc1b66a5d2f8d1"}, + {file = "pyrsistent-0.19.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9bb60a40a0ab9aba40a59f68214eed5a29c6274c83b2cc206a359c4a89fa41b"}, + {file = "pyrsistent-0.19.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a2471f3f8693101975b1ff85ffd19bb7ca7dd7c38f8a81701f67d6b4f97b87d8"}, + {file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc5d149f31706762c1f8bda2e8c4f8fead6e80312e3692619a75301d3dbb819a"}, + {file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3311cb4237a341aa52ab8448c27e3a9931e2ee09561ad150ba94e4cfd3fc888c"}, + {file = "pyrsistent-0.19.3-cp38-cp38-win32.whl", hash = "sha256:f0e7c4b2f77593871e918be000b96c8107da48444d57005b6a6bc61fb4331b2c"}, + {file = "pyrsistent-0.19.3-cp38-cp38-win_amd64.whl", hash = "sha256:c147257a92374fde8498491f53ffa8f4822cd70c0d85037e09028e478cababb7"}, + {file = "pyrsistent-0.19.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b735e538f74ec31378f5a1e3886a26d2ca6351106b4dfde376a26fc32a044edc"}, + {file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99abb85579e2165bd8522f0c0138864da97847875ecbd45f3e7e2af569bfc6f2"}, + {file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a8cb235fa6d3fd7aae6a4f1429bbb1fec1577d978098da1252f0489937786f3"}, + {file = "pyrsistent-0.19.3-cp39-cp39-win32.whl", hash = "sha256:c74bed51f9b41c48366a286395c67f4e894374306b197e62810e0fdaf2364da2"}, + {file = "pyrsistent-0.19.3-cp39-cp39-win_amd64.whl", hash = "sha256:878433581fc23e906d947a6814336eee031a00e6defba224234169ae3d3d6a98"}, + {file = "pyrsistent-0.19.3-py3-none-any.whl", hash = "sha256:ccf0d6bd208f8111179f0c26fdf84ed7c3891982f2edaeae7422575f47e66b64"}, + {file = "pyrsistent-0.19.3.tar.gz", hash = "sha256:1a2994773706bbb4995c31a97bc94f1418314923bd1048c6d964837040376440"}, +] + [[package]] name = "python-dateutil" version = "2.8.2" @@ -1749,4 +1821,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "9406bc70d0463b354c294bd9548897a33270b8a04f55141a763d45af8d6928b8" +content-hash = "3ba2a7278fda36a059d76e227be94b0cb5e2efc9396b47a9642b916680214d9f" diff --git a/continuedev/pyproject.toml b/continuedev/pyproject.toml index bbd8a687..64d88b8c 100644 --- a/continuedev/pyproject.toml +++ b/continuedev/pyproject.toml @@ -22,6 +22,8 @@ gpt-index = "^0.6.8" posthog = "^3.0.1" tiktoken = "^0.4.0" jsonref = "^1.1.0" +jsonschema = "^4.17.3" +directory-tree = "^0.0.3.1" [tool.poetry.scripts] typegen = "src.continuedev.models.generate_json_schema:main" diff --git a/continuedev/src/continuedev/core/abstract_sdk.py b/continuedev/src/continuedev/core/abstract_sdk.py index 017e75ef..7bd3da6c 100644 --- a/continuedev/src/continuedev/core/abstract_sdk.py +++ b/continuedev/src/continuedev/core/abstract_sdk.py @@ -84,10 +84,6 @@ class AbstractContinueSDK(ABC): def set_loading_message(self, message: str): pass - @abstractmethod - def add_chat_context(self, content: str, role: ChatMessageRole = "assistant"): - pass - @abstractmethod async def get_chat_context(self) -> List[ChatMessage]: pass diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py index efb91488..0dd5bb64 100644 --- a/continuedev/src/continuedev/core/main.py +++ b/continuedev/src/continuedev/core/main.py @@ -1,18 +1,96 @@ +import json from textwrap import dedent from typing import Callable, Coroutine, Dict, Generator, List, Literal, Tuple, Union from ..models.main import ContinueBaseModel from pydantic import validator from .observation import Observation +from pydantic.schema import schema -ChatMessageRole = Literal["assistant", "user", "system"] +ChatMessageRole = Literal["assistant", "user", "system", "function"] + + +class FunctionCall(ContinueBaseModel): + name: str + arguments: str class ChatMessage(ContinueBaseModel): role: ChatMessageRole - content: str + content: str | None + name: str | None # A summary for pruning chat context to fit context window. Often the Step name. summary: str + function_call: FunctionCall | None = None + + def to_dict(self, with_functions: bool) -> Dict: + d = self.dict() + del d["summary"] + if d["function_call"] is not None: + d["function_call"]["name"] = d["function_call"]["name"].replace( + " ", "") + + if d["content"] is None: + d["content"] = "" + for key, value in list(d.items()): + if value is None: + del d[key] + + if not with_functions: + d["role"] = "assistant" + if "name" in d: + del d["name"] + if "function_call" in d: + del d["function_call"] + return d + + +def resolve_refs(schema_data): + def traverse(obj): + if isinstance(obj, dict): + if '$ref' in obj: + ref = obj['$ref'] + parts = ref.split('/') + ref_obj = schema_data + for part in parts[1:]: + ref_obj = ref_obj[part] + return traverse(ref_obj) + else: + for key, value in obj.items(): + obj[key] = traverse(value) + elif isinstance(obj, list): + for i in range(len(obj)): + obj[i] = traverse(obj[i]) + return obj + + return traverse(schema_data) + + +unincluded_parameters = ["system_message", "chat_context", + "manage_own_chat_context", "hide", "name", "description"] + + +def step_to_json_schema(step) -> str: + pydantic_class = step.__class__ + schema_data = schema([pydantic_class]) + resolved_schema = resolve_refs(schema_data) + parameters = resolved_schema["definitions"][pydantic_class.__name__] + for parameter in unincluded_parameters: + if parameter in parameters["properties"]: + del parameters["properties"][parameter] + return { + "name": step.name.replace(" ", ""), + "description": step.description or "", + "parameters": parameters + } + + +def step_to_fn_call_arguments(step: "Step") -> str: + args = step.dict() + for parameter in unincluded_parameters: + if parameter in args: + del args[parameter] + return json.dumps(args) class HistoryNode(ContinueBaseModel): @@ -24,9 +102,17 @@ class HistoryNode(ContinueBaseModel): active: bool = True def to_chat_messages(self) -> List[ChatMessage]: - if self.step.description is None: + if self.step.description is None or self.step.manage_own_chat_context: return self.step.chat_context - return self.step.chat_context + [ChatMessage(role="assistant", content=self.step.description, summary=self.step.name)] + return self.step.chat_context + [ + ChatMessage( + role="function", + name=self.step.__class__.__name__, + content=json.dumps({ + "description": self.step.description or "Function complete", + }), + summary=f"Ran function {self.step.name}" + )] class History(ContinueBaseModel): @@ -143,6 +229,7 @@ class Step(ContinueBaseModel): system_message: Union[str, None] = None chat_context: List[ChatMessage] = [] + manage_own_chat_context: bool = False class Config: copy_on_model_validation = False diff --git a/continuedev/src/continuedev/core/policy.py b/continuedev/src/continuedev/core/policy.py index fb13dd27..0b417959 100644 --- a/continuedev/src/continuedev/core/policy.py +++ b/continuedev/src/continuedev/core/policy.py @@ -15,7 +15,7 @@ from ..recipes.WritePytestsRecipe.main import WritePytestsRecipe from ..recipes.ContinueRecipeRecipe.main import ContinueStepStep from ..steps.comment_code import CommentCodeStep from ..steps.react import NLDecisionStep -from ..steps.chat import SimpleChatStep +from ..steps.chat import SimpleChatStep, ChatWithFunctions, EditFileStep, AddFileStep from ..recipes.DDtoBQRecipe.main import DDtoBQRecipe from ..steps.core.core import MessageStep from ..libs.util.step_name_to_steps import get_step_from_name @@ -28,7 +28,7 @@ class DemoPolicy(Policy): # At the very start, run initial Steps spcecified in the config if history.get_current() is None: return ( - MessageStep(name="Welcome to Continue!", message=dedent("""\ + MessageStep(name="Welcome to Continue", message=dedent("""\ Type '/' to see the list of available slash commands. If you highlight code, edits and explanations will be localized to the highlighted range. Otherwise, the currently open file is used. In both cases, the code is combined with the previous steps to construct the context.""")) >> WelcomeStep() >> # SetupContinueWorkspaceStep() >> @@ -50,6 +50,7 @@ class DemoPolicy(Policy): return get_step_from_name(slash_command.step_name, params) # return EditHighlightedCodeStep(user_input=user_input) + return ChatWithFunctions(user_input=user_input) return NLDecisionStep(user_input=user_input, steps=[ (EditHighlightedCodeStep(user_input=user_input), "Edit the highlighted code"), diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py index d6acc404..30e48ad9 100644 --- a/continuedev/src/continuedev/core/sdk.py +++ b/continuedev/src/continuedev/core/sdk.py @@ -26,6 +26,15 @@ class Models: def __init__(self, sdk: "ContinueSDK"): self.sdk = sdk + def __load_openai_model(self, model: str) -> OpenAI: + async def load_openai_model(): + api_key = await self.sdk.get_user_secret( + 'OPENAI_API_KEY', 'Enter your OpenAI API key, OR press enter to try for free') + if api_key == "": + return ProxyServer(self.sdk.ide.unique_id, model) + return OpenAI(api_key=api_key, default_model=model) + return asyncio.get_event_loop().run_until_complete(load_openai_model()) + @cached_property def starcoder(self): async def load_starcoder(): @@ -36,33 +45,19 @@ class Models: @cached_property def gpt35(self): - async def load_gpt35(): - api_key = await self.sdk.get_user_secret( - 'OPENAI_API_KEY', 'Enter your OpenAI API key, OR press enter to try for free') - if api_key == "": - return ProxyServer(self.sdk.ide.unique_id, "gpt-3.5-turbo") - return OpenAI(api_key=api_key, default_model="gpt-3.5-turbo") - return asyncio.get_event_loop().run_until_complete(load_gpt35()) + return self.__load_openai_model("gpt-3.5") + + @cached_property + def gpt350613(self): + return self.__load_openai_model("gpt-3.5-turbo-0613") @cached_property def gpt3516k(self): - async def load_gpt3516k(): - api_key = await self.sdk.get_user_secret( - 'OPENAI_API_KEY', 'Enter your OpenAI API key, OR press enter to try for free') - if api_key == "": - return ProxyServer(self.sdk.ide.unique_id, "gpt-3.5-turbo-16k") - return OpenAI(api_key=api_key, default_model="gpt-3.5-turbo-16k") - return asyncio.get_event_loop().run_until_complete(load_gpt3516k()) + return self.__load_openai_model("gpt-3.5-turbo-16k") @cached_property def gpt4(self): - async def load_gpt4(): - api_key = await self.sdk.get_user_secret( - 'OPENAI_API_KEY', 'Enter your OpenAI API key, OR press enter to try for free') - if api_key == "": - return ProxyServer(self.sdk.ide.unique_id, "gpt-4") - return OpenAI(api_key=api_key, default_model="gpt-4") - return asyncio.get_event_loop().run_until_complete(load_gpt4()) + return self.__load_openai_model("gpt-4") def __model_from_name(self, model_name: str): if model_name == "starcoder": @@ -102,7 +97,7 @@ class ContinueSDK(AbstractContinueSDK): async def _ensure_absolute_path(self, path: str) -> str: if os.path.isabs(path): return path - return os.path.join(await self.ide.getWorkspaceDirectory(), path) + return os.path.join(self.ide.workspace_directory, path) async def run_step(self, step: Step) -> Coroutine[Observation, None, None]: return await self.__autopilot._run_singular_step(step) @@ -144,15 +139,15 @@ class ContinueSDK(AbstractContinueSDK): return await self.run_step(FileSystemEditStep(edit=AddFile(filepath=filepath, content=content))) async def delete_file(self, filename: str): - filepath = await self._ensure_absolute_path(filename) + filename = await self._ensure_absolute_path(filename) return await self.run_step(FileSystemEditStep(edit=DeleteFile(filepath=filename))) async def add_directory(self, path: str): - filepath = await self._ensure_absolute_path(path) + path = await self._ensure_absolute_path(path) return await self.run_step(FileSystemEditStep(edit=AddDirectory(path=path))) async def delete_directory(self, path: str): - filepath = await self._ensure_absolute_path(path) + path = await self._ensure_absolute_path(path) return await self.run_step(FileSystemEditStep(edit=DeleteDirectory(path=path))) async def get_user_secret(self, env_var: str, prompt: str) -> str: @@ -177,10 +172,6 @@ class ContinueSDK(AbstractContinueSDK): def raise_exception(self, message: str, title: str, with_step: Union[Step, None] = None): raise ContinueCustomException(message, title, with_step) - def add_chat_context(self, content: str, summary: Union[str, None] = None, role: ChatMessageRole = "assistant"): - self.history.timeline[self.history.current_index].step.chat_context.append( - ChatMessage(content=content, role=role, summary=summary)) - async def get_chat_context(self) -> List[ChatMessage]: history_context = self.history.to_chat_history() highlighted_code = await self.ide.getHighlightedCode() @@ -198,8 +189,15 @@ class ContinueSDK(AbstractContinueSDK): for rif in highlighted_code: code = await self.ide.readRangeInFile(rif) - history_context.append(ChatMessage( - content=f"{preface} ({rif.filepath}):\n```\n{code}\n```", role="user", summary=f"{preface}: {rif.filepath}")) + msg = ChatMessage(content=f"{preface} ({rif.filepath}):\n```\n{code}\n```", + role="user", summary=f"{preface}: {rif.filepath}") + + # Don't insert after latest user message or function call + i = -1 + if history_context[i].role == "user" or history_context[i].role == "function": + i -= 1 + history_context.insert(i, msg) + return history_context async def update_ui(self): diff --git a/continuedev/src/continuedev/libs/llm/__init__.py b/continuedev/src/continuedev/libs/llm/__init__.py index 108eedf1..4c4de213 100644 --- a/continuedev/src/continuedev/libs/llm/__init__.py +++ b/continuedev/src/continuedev/libs/llm/__init__.py @@ -13,12 +13,12 @@ class LLM(ABC): """Return the completion of the text with the given temperature.""" raise NotImplementedError - def stream_chat(self, prompt, with_history: List[ChatMessage] = [], **kwargs) -> Generator[Union[Any, List, Dict], None, None]: - """Yield a stream of chat messages.""" + def stream_complete(self, prompt, with_history: List[ChatMessage] = [], **kwargs) -> Generator[Union[Any, List, Dict], None, None]: + """Stream the completion through generator.""" raise NotImplementedError - def with_system_message(self, system_message: Union[str, None]): - """Return a new model with the given system message.""" + async def stream_chat(self, messages: List[ChatMessage] = [], **kwargs) -> Generator[Union[Any, List, Dict], None, None]: + """Stream the chat through generator.""" raise NotImplementedError def count_tokens(self, text: str): diff --git a/continuedev/src/continuedev/libs/llm/openai.py b/continuedev/src/continuedev/libs/llm/openai.py index 095cbe51..aa12d70a 100644 --- a/continuedev/src/continuedev/libs/llm/openai.py +++ b/continuedev/src/continuedev/libs/llm/openai.py @@ -1,34 +1,21 @@ -import asyncio from functools import cached_property import time from typing import Any, Coroutine, Dict, Generator, List, Union from ...core.main import ChatMessage import openai -import aiohttp from ..llm import LLM -from pydantic import BaseModel, validator -import tiktoken - -DEFAULT_MAX_TOKENS = 2048 -MAX_TOKENS_FOR_MODEL = { - "gpt-3.5-turbo": 4096 - DEFAULT_MAX_TOKENS, - "gpt-3.5-turbo-16k": 16384 - DEFAULT_MAX_TOKENS, - "gpt-4": 8192 - DEFAULT_MAX_TOKENS -} -CHAT_MODELS = { - "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4" -} +from ..util.count_tokens import DEFAULT_MAX_TOKENS, compile_chat_messages, CHAT_MODELS, DEFAULT_ARGS, count_tokens class OpenAI(LLM): api_key: str - completion_count: int = 0 default_model: str def __init__(self, api_key: str, default_model: str, system_message: str = None): self.api_key = api_key self.default_model = default_model - self.system_message = system_message + self.system_message = (system_message or "") + \ + "\nDo not ever call the 'python' function." openai.api_key = api_key @@ -36,190 +23,58 @@ class OpenAI(LLM): def name(self): return self.default_model - @cached_property - def __encoding_for_model(self): - aliases = {} - return tiktoken.encoding_for_model(self.default_model) + @property + def default_args(self): + return DEFAULT_ARGS | {"model": self.default_model} def count_tokens(self, text: str): - return len(self.__encoding_for_model.encode(text, disallowed_special=())) - - def __prune_chat_history(self, chat_history: List[ChatMessage], max_tokens: int, tokens_for_completion: int): - total_tokens = tokens_for_completion + \ - sum(self.count_tokens(message.content) for message in chat_history) - - # 1. Replace beyond last 5 messages with summary - i = 0 - while total_tokens > max_tokens and i < len(chat_history) - 5: - message = chat_history[0] - total_tokens -= self.count_tokens(message.content) - total_tokens += self.count_tokens(message.summary) - message.content = message.summary - i += 1 - - # 2. Remove entire messages until the last 5 - while len(chat_history) > 5 and total_tokens > max_tokens: - message = chat_history.pop(0) - total_tokens -= self.count_tokens(message.content) + return count_tokens(self.default_model, text) - # 3. Truncate message in the last 5 - i = 0 - while total_tokens > max_tokens: - message = chat_history[0] - total_tokens -= self.count_tokens(message.content) - total_tokens += self.count_tokens(message.summary) - message.content = message.summary - i += 1 - - # 4. Remove entire messages in the last 5 - while total_tokens > max_tokens and len(chat_history) > 0: - message = chat_history.pop(0) - total_tokens -= self.count_tokens(message.content) - - return chat_history + async def stream_complete(self, prompt, with_history: List[ChatMessage] = [], **kwargs) -> Generator[Union[Any, List, Dict], None, None]: + args = self.default_args | kwargs + args["stream"] = True - def with_system_message(self, system_message: Union[str, None]): - return OpenAI(api_key=self.api_key, default_model=self.default_model, system_message=system_message) + if args["model"] in CHAT_MODELS: + async for chunk in await openai.ChatCompletion.acreate( + messages=compile_chat_messages( + args["model"], with_history, prompt, with_functions=False), + **args, + ): + if "content" in chunk.choices[0].delta: + yield chunk.choices[0].delta.content + else: + continue + else: + async for chunk in await openai.Completion.acreate(prompt=prompt, **args): + yield chunk.choices[0].text - async def stream_chat(self, prompt, with_history: List[ChatMessage] = [], **kwargs) -> Generator[Union[Any, List, Dict], None, None]: - self.completion_count += 1 - args = {"max_tokens": DEFAULT_MAX_TOKENS, "temperature": 0.5, "top_p": 1, - "frequency_penalty": 0, "presence_penalty": 0} | kwargs + async def stream_chat(self, messages: List[ChatMessage] = [], **kwargs) -> Generator[Union[Any, List, Dict], None, None]: + args = self.default_args | kwargs args["stream"] = True - args["model"] = self.default_model + args["model"] = self.default_model if self.default_model in CHAT_MODELS else "gpt-3.5-turbo-0613" + if not args["model"].endswith("0613") and "functions" in args: + del args["functions"] async for chunk in await openai.ChatCompletion.acreate( - messages=self.compile_chat_messages(with_history, prompt), + messages=compile_chat_messages( + args["model"], messages, with_functions=args["model"].endswith("0613")), **args, ): - if "content" in chunk.choices[0].delta: - yield chunk.choices[0].delta.content - else: - continue - - def compile_chat_messages(self, msgs: List[ChatMessage], prompt: str) -> List[Dict]: - msgs = self.__prune_chat_history(msgs, MAX_TOKENS_FOR_MODEL[self.default_model], self.count_tokens( - prompt) + 1000 + self.count_tokens(self.system_message or "")) - history = [] - if self.system_message: - history.append({ - "role": "system", - "content": self.system_message - }) - history += [{"role": msg.role, "content": msg.content} for msg in msgs] - history.append({ - "role": "user", - "content": prompt - }) - - return history - - def stream_complete(self, prompt: str, with_history: List[ChatMessage] = [], **kwargs) -> Generator[Union[Any, List, Dict], None, None]: - self.completion_count += 1 - args = {"model": self.default_model, "max_tokens": DEFAULT_MAX_TOKENS, "temperature": 0.5, - "top_p": 1, "frequency_penalty": 0, "presence_penalty": 0, "suffix": None} | kwargs - args["stream"] = True - - if args["model"] in CHAT_MODELS: - generator = openai.ChatCompletion.create( - messages=self.compile_chat_messages(with_history, prompt), - **args, - ) - for chunk in generator: - yield chunk.choices[0].message.content - else: - generator = openai.Completion.create( - prompt=prompt, - **args, - ) - for chunk in generator: - yield chunk.choices[0].text + yield chunk.choices[0].delta async def complete(self, prompt: str, with_history: List[ChatMessage] = [], **kwargs) -> Coroutine[Any, Any, str]: - t1 = time.time() - - self.completion_count += 1 - args = {"model": self.default_model, "max_tokens": DEFAULT_MAX_TOKENS, "temperature": 0.5, "top_p": 1, - "frequency_penalty": 0, "presence_penalty": 0, "stream": False} | kwargs + args = self.default_args | kwargs if args["model"] in CHAT_MODELS: resp = (await openai.ChatCompletion.acreate( - messages=self.compile_chat_messages(with_history, prompt), + messages=compile_chat_messages( + args["model"], with_history, prompt, with_functions=False), **args, - )).choices[0].message.content + )).choices[0].message else: resp = (await openai.Completion.acreate( prompt=prompt, **args, )).choices[0].text - t2 = time.time() - print("Completion time:", t2 - t1) return resp - - def edit(self, inp: str, instruction: str) -> str: - try: - resp = openai.Edit.create( - input=inp, - instruction=instruction, - model='text-davinci-edit-001' - ).choices[0].text - return resp - except Exception as e: - print("OpenAI error:", e) - raise e - - def parallel_edit(self, inputs: list[str], instructions: Union[List[str], str], **kwargs) -> list[str]: - args = {"temperature": 0.5, "top_p": 1} | kwargs - args['model'] = 'text-davinci-edit-001' - - async def fn(): - async with aiohttp.ClientSession() as session: - tasks = [] - - async def get(input, instruction): - async with session.post("https://api.openai.com/v1/edits", headers={ - "Content-Type": "application/json", - "Authorization": "Bearer " + self.api_key - }, json={"model": args["model"], "input": input, "instruction": instruction, "temperature": args["temperature"], "max_tokens": args["max_tokens"], "suffix": args["suffix"]}) as resp: - json = await resp.json() - if "error" in json: - print("ERROR IN GPT-3 RESPONSE: ", json) - return None - return json["choices"][0]["text"] - - for i in range(len(inputs)): - tasks.append(get(inputs[i], instructions[i] if isinstance( - instructions, list) else instructions)) - - return await asyncio.gather(*tasks) - - return asyncio.run(fn()) - - def parallel_complete(self, prompts: list[str], suffixes: Union[list[str], None] = None, **kwargs) -> list[str]: - self.completion_count += len(prompts) - args = {"model": self.default_model, "max_tokens": DEFAULT_MAX_TOKENS, "temperature": 0.5, - "top_p": 1, "frequency_penalty": 0, "presence_penalty": 0} | kwargs - - async def fn(): - async with aiohttp.ClientSession() as session: - tasks = [] - - async def get(prompt, suffix): - async with session.post("https://api.openai.com/v1/completions", headers={ - "Content-Type": "application/json", - "Authorization": "Bearer " + self.api_key - }, json={"model": args["model"], "prompt": prompt, "temperature": args["temperature"], "max_tokens": args["max_tokens"], "suffix": suffix}) as resp: - json = await resp.json() - if "error" in json: - print("ERROR IN GPT-3 RESPONSE: ", json) - return None - return json["choices"][0]["text"] - - for i in range(len(prompts)): - tasks.append(asyncio.ensure_future( - get(prompts[i], suffixes[i] if suffixes else None))) - - return await asyncio.gather(*tasks) - - return asyncio.run(fn()) diff --git a/continuedev/src/continuedev/libs/llm/proxy_server.py b/continuedev/src/continuedev/libs/llm/proxy_server.py index a29f5c89..6b0336a7 100644 --- a/continuedev/src/continuedev/libs/llm/proxy_server.py +++ b/continuedev/src/continuedev/libs/llm/proxy_server.py @@ -1,24 +1,13 @@ from functools import cached_property import json from typing import Any, Coroutine, Dict, Generator, List, Literal, Union -import requests -import tiktoken import aiohttp - from ...core.main import ChatMessage from ..llm import LLM +from ..util.count_tokens import DEFAULT_ARGS, DEFAULT_MAX_TOKENS, compile_chat_messages, CHAT_MODELS, count_tokens -MAX_TOKENS_FOR_MODEL = { - "gpt-3.5-turbo": 4097, - "gpt-4": 4097, -} -DEFAULT_MAX_TOKENS = 2048 -CHAT_MODELS = { - "gpt-3.5-turbo", "gpt-4" -} - -# SERVER_URL = "http://127.0.0.1:8080" -SERVER_URL = "https://proxy-server-l6vsfbzhba-uw.a.run.app" +SERVER_URL = "http://127.0.0.1:8080" +# SERVER_URL = "https://proxy-server-l6vsfbzhba-uw.a.run.app" class ProxyServer(LLM): @@ -29,67 +18,66 @@ class ProxyServer(LLM): def __init__(self, unique_id: str, default_model: Literal["gpt-3.5-turbo", "gpt-4"], system_message: str = None): self.unique_id = unique_id self.default_model = default_model - self.system_message = system_message + self.system_message = (system_message or "") + \ + "\nDo not ever call the 'python' function." self.name = default_model - @cached_property - def __encoding_for_model(self): - aliases = { - "gpt-3.5-turbo": "gpt3" - } - return tiktoken.encoding_for_model(self.default_model) + @property + def default_args(self): + return DEFAULT_ARGS | {"model": self.default_model} def count_tokens(self, text: str): - return len(self.__encoding_for_model.encode(text, disallowed_special=())) - - def __prune_chat_history(self, chat_history: List[ChatMessage], max_tokens: int, tokens_for_completion: int): - tokens = tokens_for_completion - for i in range(len(chat_history) - 1, -1, -1): - message = chat_history[i] - tokens += self.count_tokens(message.content) - if tokens > max_tokens: - return chat_history[i + 1:] - return chat_history - - def compile_chat_messages(self, msgs: List[ChatMessage], prompt: str) -> List[Dict]: - msgs = self.__prune_chat_history(msgs, MAX_TOKENS_FOR_MODEL[self.default_model], self.count_tokens( - prompt) + 1000 + self.count_tokens(self.system_message or "")) - history = [] - if self.system_message: - history.append({ - "role": "system", - "content": self.system_message - }) - history += [{"role": msg.role, "content": msg.content} for msg in msgs] - history.append({ - "role": "user", - "content": prompt - }) - - return history + return count_tokens(self.default_model, text) async def complete(self, prompt: str, with_history: List[ChatMessage] = [], **kwargs) -> Coroutine[Any, Any, str]: + args = self.default_args | kwargs + async with aiohttp.ClientSession() as session: async with session.post(f"{SERVER_URL}/complete", json={ - "chat_history": self.compile_chat_messages(with_history, prompt), - "model": self.default_model, + "messages": compile_chat_messages(args["model"], with_history, prompt, with_functions=False), "unique_id": self.unique_id, + **args }) as resp: try: return json.loads(await resp.text()) - except json.JSONDecodeError: + except: raise Exception(await resp.text()) - async def stream_chat(self, prompt, with_history: List[ChatMessage] = [], **kwargs) -> Generator[Union[Any, List, Dict], None, None]: + async def stream_chat(self, messages: List[ChatMessage] = [], **kwargs) -> Coroutine[Any, Any, Generator[Any | List | Dict, None, None]]: + args = self.default_args | kwargs + messages = compile_chat_messages( + self.default_model, messages, None, with_functions=args["model"].endswith("0613")) + + async with aiohttp.ClientSession() as session: + async with session.post(f"{SERVER_URL}/stream_chat", json={ + "messages": messages, + "unique_id": self.unique_id, + **args + }) as resp: + # This is streaming application/json instaed of text/event-stream + async for line in resp.content.iter_chunks(): + if line[1]: + try: + json_chunk = line[0].decode("utf-8") + json_chunk = "{}" if json_chunk == "" else json_chunk + yield json.loads(json_chunk) + except: + raise Exception(str(line[0])) + + async def stream_complete(self, prompt, with_history: List[ChatMessage] = [], **kwargs) -> Generator[Union[Any, List, Dict], None, None]: + args = self.default_args | kwargs + messages = compile_chat_messages( + self.default_model, with_history, prompt, with_functions=args["model"].endswith("0613")) + async with aiohttp.ClientSession() as session: async with session.post(f"{SERVER_URL}/stream_complete", json={ - "chat_history": self.compile_chat_messages(with_history, prompt), - "model": self.default_model, + "messages": messages, "unique_id": self.unique_id, + **args }) as resp: async for line in resp.content.iter_any(): if line: try: yield line.decode("utf-8") - except json.JSONDecodeError: + except: raise Exception(str(line)) diff --git a/continuedev/src/continuedev/libs/util/count_tokens.py b/continuedev/src/continuedev/libs/util/count_tokens.py new file mode 100644 index 00000000..6038b68d --- /dev/null +++ b/continuedev/src/continuedev/libs/util/count_tokens.py @@ -0,0 +1,84 @@ +from typing import Dict, List, Union +from ...core.main import ChatMessage +import tiktoken + +aliases = {} +DEFAULT_MAX_TOKENS = 2048 +MAX_TOKENS_FOR_MODEL = { + "gpt-3.5-turbo": 4096 - DEFAULT_MAX_TOKENS, + "gpt-3.5-turbo-0613": 4096 - DEFAULT_MAX_TOKENS, + "gpt-3.5-turbo-16k": 16384 - DEFAULT_MAX_TOKENS, + "gpt-4": 8192 - DEFAULT_MAX_TOKENS +} +CHAT_MODELS = { + "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4", "gpt-3.5-turbo-0613" +} +DEFAULT_ARGS = {"max_tokens": DEFAULT_MAX_TOKENS, "temperature": 0.5, "top_p": 1, + "frequency_penalty": 0, "presence_penalty": 0} + + +def encoding_for_model(model: str): + return tiktoken.encoding_for_model(aliases.get(model, model)) + + +def count_tokens(model: str, text: str | None): + if text is None: + return 0 + encoding = encoding_for_model(model) + return len(encoding.encode(text, disallowed_special=())) + + +def prune_chat_history(model: str, chat_history: List[ChatMessage], max_tokens: int, tokens_for_completion: int): + total_tokens = tokens_for_completion + \ + sum(count_tokens(model, message.content) + for message in chat_history) + + # 1. Replace beyond last 5 messages with summary + i = 0 + while total_tokens > max_tokens and i < len(chat_history) - 5: + message = chat_history[0] + total_tokens -= count_tokens(model, message.content) + total_tokens += count_tokens(model, message.summary) + message.content = message.summary + i += 1 + + # 2. Remove entire messages until the last 5 + while len(chat_history) > 5 and total_tokens > max_tokens: + message = chat_history.pop(0) + total_tokens -= count_tokens(model, message.content) + + # 3. Truncate message in the last 5 + i = 0 + while total_tokens > max_tokens: + message = chat_history[0] + total_tokens -= count_tokens(model, message.content) + total_tokens += count_tokens(model, message.summary) + message.content = message.summary + i += 1 + + # 4. Remove entire messages in the last 5 + while total_tokens > max_tokens and len(chat_history) > 0: + message = chat_history.pop(0) + total_tokens -= count_tokens(model, message.content) + + return chat_history + + +def compile_chat_messages(model: str, msgs: List[ChatMessage], prompt: str | None = None, with_functions: bool = False, system_message: Union[str, None] = None) -> List[Dict]: + prompt_tokens = count_tokens(model, prompt) + msgs = prune_chat_history(model, + msgs, MAX_TOKENS_FOR_MODEL[model], prompt_tokens + 1000 + count_tokens(model, system_message)) + history = [] + if system_message: + history.append({ + "role": "system", + "content": system_message + }) + history += [msg.to_dict(with_functions=with_functions) for msg in msgs] + if prompt: + history.append({ + "role": "user", + "content": prompt + }) + + return history diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py index fd7457d9..fee8f40e 100644 --- a/continuedev/src/continuedev/steps/chat.py +++ b/continuedev/src/continuedev/steps/chat.py @@ -1,8 +1,19 @@ -from textwrap import dedent -from typing import List -from ..core.main import Step -from ..core.sdk import ContinueSDK +import json +from typing import Any, Coroutine, List + +from .main import EditHighlightedCodeStep from .core.core import MessageStep +from ..core.main import FunctionCall, Models +from ..core.main import ChatMessage, Step, step_to_json_schema +from ..core.sdk import ContinueSDK +import openai +import os +from dotenv import load_dotenv +from directory_tree import display_tree + +load_dotenv() +OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") +openai.api_key = OPENAI_API_KEY class SimpleChatStep(Step): @@ -13,9 +24,184 @@ class SimpleChatStep(Step): self.description = f"```{self.user_input}```\n\n" await sdk.update_ui() - async for chunk in sdk.models.default.stream_chat(self.user_input, with_history=await sdk.get_chat_context()): + async for chunk in sdk.models.default.stream_complete(self.user_input, with_history=await sdk.get_chat_context()): self.description += chunk await sdk.update_ui() self.name = (await sdk.models.gpt35.complete( f"Write a short title for the following chat message: {self.description}")).strip() + + +class AddFileStep(Step): + name: str = "Add File" + description = "Add a file to the workspace." + filename: str + file_contents: str + + async def describe(self, models: Models) -> Coroutine[Any, Any, Coroutine[str, None, None]]: + return f"Added a file named {self.filename} to the workspace." + + async def run(self, sdk: ContinueSDK): + try: + await sdk.add_file(self.filename, self.file_contents) + except FileNotFoundError: + self.description = f"File {self.filename} does not exist." + return + currently_open_file = (await sdk.ide.getOpenFiles())[0] + await sdk.ide.setFileOpen(os.path.join(sdk.ide.workspace_directory, self.filename)) + await sdk.ide.setFileOpen(currently_open_file) + + +class DeleteFileStep(Step): + name: str = "Delete File" + description = "Delete a file from the workspace." + filename: str + + async def describe(self, models: Models) -> Coroutine[Any, Any, Coroutine[str, None, None]]: + return f"Deleted a file named {self.filename} from the workspace." + + async def run(self, sdk: ContinueSDK): + await sdk.delete_file(self.filename) + + +class AddDirectoryStep(Step): + name: str = "Add Directory" + description = "Add a directory to the workspace." + directory_name: str + + async def describe(self, models: Models) -> Coroutine[Any, Any, Coroutine[str, None, None]]: + return f"Added a directory named {self.directory_name} to the workspace." + + async def run(self, sdk: ContinueSDK): + try: + await sdk.add_directory(self.directory_name) + except FileExistsError: + self.description = f"Directory {self.directory_name} already exists." + + +class RunTerminalCommandStep(Step): + name: str = "Run Terminal Command" + description: str = "Run a terminal command." + command: str + + async def describe(self, models: Models) -> Coroutine[Any, Any, Coroutine[str, None, None]]: + return f"Ran the terminal command {self.command}." + + async def run(self, sdk: ContinueSDK): + await sdk.wait_for_user_confirmation(f"Run the terminal command {self.command}?") + await sdk.run(self.command) + + +class ViewDirectoryTreeStep(Step): + name: str = "View Directory Tree" + description: str = "View the directory tree to learn which folder and files exist." + + async def describe(self, models: Models) -> Coroutine[Any, Any, Coroutine[str, None, None]]: + return f"Viewed the directory tree." + + async def run(self, sdk: ContinueSDK): + self.description = f"```\n{display_tree(sdk.ide.workspace_directory, True)}\n```" + + +class EditFileStep(Step): + name: str = "Edit File" + description: str = "Edit a file in the workspace." + filename: str + instructions: str + hide: bool = True + + async def run(self, sdk: ContinueSDK): + await sdk.edit_file(self.filename, self.instructions) + + +class ChatWithFunctions(Step): + user_input: str + functions: List[Step] = [AddFileStep(filename="", file_contents=""), + EditFileStep(filename="", instructions=""), + EditHighlightedCodeStep(user_input=""), + ViewDirectoryTreeStep(), AddDirectoryStep(directory_name=""), + DeleteFileStep(filename=""), RunTerminalCommandStep(command="")] + name: str = "Chat" + manage_own_chat_context: bool = True + + async def run(self, sdk: ContinueSDK): + self.description = f"```{self.user_input}```\n\nDeciding next steps...\n\n" + await sdk.update_ui() + + step_name_step_class_map = { + step.name.replace(" ", ""): step.__class__ for step in self.functions} + + functions = [step_to_json_schema( + function) for function in self.functions] + + self.chat_context.append(ChatMessage( + role="user", + content=self.user_input, + summary=self.user_input + )) + + last_function_called_index_in_history = None + while True: + was_function_called = False + func_args = "" + func_name = "" + msg_content = "" + msg_step = None + + async for msg_chunk in sdk.models.gpt350613.stream_chat(await sdk.get_chat_context(), functions=functions): + if "content" in msg_chunk and msg_chunk["content"] is not None: + msg_content += msg_chunk["content"] + # if last_function_called_index_in_history is not None: + # while sdk.history.timeline[last_function_called_index].step.hide: + # last_function_called_index += 1 + # sdk.history.timeline[last_function_called_index_in_history].step.description = msg_content + if msg_step is None: + msg_step = MessageStep( + name="Chat", + message=msg_chunk["content"] + ) + await sdk.run_step(msg_step) + else: + msg_step.description = msg_content + await sdk.update_ui() + elif "function_call" in msg_chunk or func_name != "": + was_function_called = True + if "function_call" in msg_chunk: + if "arguments" in msg_chunk["function_call"]: + func_args += msg_chunk["function_call"]["arguments"] + if "name" in msg_chunk["function_call"]: + func_name += msg_chunk["function_call"]["name"] + + if not was_function_called: + self.chat_context.append(ChatMessage( + role="assistant", + content=msg_content, + summary=msg_content + )) + break + else: + if func_name == "python" and "python" not in step_name_step_class_map: + # GPT must be fine-tuned to believe this exists, but it doesn't always + self.chat_context.append(ChatMessage( + role="user", + content="The 'python' function does not exist. Don't call it.", + summary="'python' function does not exist." + )) + continue + # Call the function, then continue to chat + func_args = "{}" if func_args == "" else func_args + fn_call_params = json.loads(func_args) + self.chat_context.append(ChatMessage( + role="assistant", + content=None, + function_call=FunctionCall( + name=func_name, + arguments=func_args + ), + summary=f"Ran function {func_name}" + )) + last_function_called_index_in_history = sdk.history.current_index + 1 + await sdk.run_step(step_name_step_class_map[func_name]( + **fn_call_params)) + self.description += f"`Running function {func_name}`\n\n" + await sdk.update_ui() diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 71a5b5b2..7ccf82cb 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -10,7 +10,7 @@ from ...models.filesystem_edit import EditDiff, FileEdit, FileEditWithFullConten from ...models.filesystem import FileSystem, RangeInFile, RangeInFileWithContents from ...core.observation import Observation, TextObservation, TracebackObservation, UserInputObservation from ...core.main import Step, SequentialStep -from ...libs.llm.openai import MAX_TOKENS_FOR_MODEL +from ...libs.util.count_tokens import MAX_TOKENS_FOR_MODEL import difflib @@ -160,7 +160,7 @@ class DefaultModelEditCodeStep(Step): return f"`{self.user_input}`\n\n" + description async def run(self, sdk: ContinueSDK) -> Coroutine[Observation, None, None]: - self.description = f"`{self.user_input}`" + self.description = f"{self.user_input}" await sdk.update_ui() rif_with_contents = [] @@ -316,7 +316,7 @@ class DefaultModelEditCodeStep(Step): lines_of_prefix_copied = 0 line_below_highlighted_range = segs[1].lstrip().split("\n")[0] should_stop = False - async for chunk in model_to_use.stream_chat(prompt, with_history=await sdk.get_chat_context(), temperature=0): + async for chunk in model_to_use.stream_complete(prompt, with_history=await sdk.get_chat_context(), temperature=0): if should_stop: break chunk_lines = chunk.split("\n") diff --git a/continuedev/src/continuedev/steps/main.py b/continuedev/src/continuedev/steps/main.py index 5ba86c53..bb48dce9 100644 --- a/continuedev/src/continuedev/steps/main.py +++ b/continuedev/src/continuedev/steps/main.py @@ -248,6 +248,7 @@ class StarCoderEditHighlightedCodeStep(Step): class EditHighlightedCodeStep(Step): user_input: str hide = True + description: str = "Change the contents of the currently highlighted code or open file" async def describe(self, models: Models) -> Coroutine[str, None, None]: return "Editing code" diff --git a/continuedev/src/continuedev/steps/on_traceback.py b/continuedev/src/continuedev/steps/on_traceback.py index 053b4ef4..3f8c5a76 100644 --- a/continuedev/src/continuedev/steps/on_traceback.py +++ b/continuedev/src/continuedev/steps/on_traceback.py @@ -1,5 +1,5 @@ import os -from ..core.main import Step +from ..core.main import ChatMessage, Step from ..core.sdk import ContinueSDK from .chat import SimpleChatStep @@ -16,7 +16,11 @@ class DefaultOnTracebackStep(Step): for seg in segs: if seg.startswith(os.path.sep) and os.path.exists(seg) and os.path.commonprefix([seg, sdk.ide.workspace_directory]) == sdk.ide.workspace_directory: file_contents = await sdk.ide.readFile(seg) - await sdk.add_chat_context(f"The contents of {seg}:\n```\n{file_contents}\n```", "", "user") + self.chat_context.append(ChatMessage( + role="user", + content=f"The contents of {seg}:\n```\n{file_contents}\n```", + summary="" + )) await sdk.run_step(SimpleChatStep( name="Help With Traceback", diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index f0e3ffd4..24529967 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -426,9 +426,9 @@ function GUI(props: GUIProps) { }} hidden={!showDataSharingInfo} > - By turning on this switch, you signal that you would - contribute this software development data to a publicly - accessible, open-source dataset in the future. + By turning on this switch, you signal that you would contribute this + software development data to a publicly accessible, open-source dataset + in the future.

@@ -485,6 +485,8 @@ function GUI(props: GUIProps) { { client?.sendClear(); + // Reload the window to get completely fresh session + window.location.reload(); }} text="Clear All" > -- cgit v1.2.3-70-g09d2 From f8bc06261464cd46c31a23cc8cbc0e76fb642d18 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Wed, 21 Jun 2023 08:47:06 -0700 Subject: purging old extension code --- extension/src/activation/activate.ts | 4 +- extension/src/commands.ts | 91 +-------------- extension/src/debugPanel.ts | 170 +--------------------------- extension/src/decorations.ts | 97 ---------------- extension/src/lang-server/codeLens.ts | 34 +----- extension/src/languages/index.d.ts | 13 --- extension/src/languages/index.ts | 19 ---- extension/src/languages/javascript/index.ts | 16 --- extension/src/languages/notImplemented.ts | 10 -- extension/src/languages/python/index.ts | 74 ------------ 10 files changed, 6 insertions(+), 522 deletions(-) delete mode 100644 extension/src/languages/index.d.ts delete mode 100644 extension/src/languages/index.ts delete mode 100644 extension/src/languages/javascript/index.ts delete mode 100644 extension/src/languages/notImplemented.ts delete mode 100644 extension/src/languages/python/index.ts (limited to 'extension') diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index 32726c86..bfe9ab3f 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -2,12 +2,10 @@ import * as vscode from "vscode"; import { registerAllCommands } from "../commands"; import { registerAllCodeLensProviders } from "../lang-server/codeLens"; import { sendTelemetryEvent, TelemetryEvent } from "../telemetry"; -import { getExtensionUri } from "../util/vscode"; -import * as path from "path"; // import { openCapturedTerminal } from "../terminal/terminalEmulator"; import IdeProtocolClient from "../continueIdeClient"; import { getContinueServerUrl } from "../bridge"; -import { setupDebugPanel, ContinueGUIWebviewViewProvider } from "../debugPanel"; +import { ContinueGUIWebviewViewProvider } from "../debugPanel"; import { CapturedTerminal } from "../terminal/terminalEmulator"; export let extensionContext: vscode.ExtensionContext | undefined = undefined; diff --git a/extension/src/commands.ts b/extension/src/commands.ts index 22e15c43..13357c99 100644 --- a/extension/src/commands.ts +++ b/extension/src/commands.ts @@ -3,7 +3,6 @@ import { decorationManager, showAnswerInTextEditor, showGutterSpinner, - writeAndShowUnitTest, } from "./decorations"; import { acceptSuggestionCommand, @@ -12,19 +11,9 @@ import { suggestionUpCommand, } from "./suggestions"; import * as bridge from "./bridge"; -import { debugPanelWebview, setupDebugPanel } from "./debugPanel"; -// import { openCapturedTerminal } from "./terminal/terminalEmulator"; -import { getRightViewColumn } from "./util/vscode"; -import { - findSuspiciousCode, - runPythonScript, - writeUnitTestForFunction, -} from "./bridge"; +import { debugPanelWebview } from "./debugPanel"; +import { writeUnitTestForFunction } from "./bridge"; import { sendTelemetryEvent, TelemetryEvent } from "./telemetry"; -import { getLanguageLibrary } from "./languages"; -import { SerializedDebugContext } from "./client"; -import { addFileSystemToDebugContext } from "./util/util"; -import { ideProtocolClient } from "./activation/activate"; // Copy everything over from extension.ts const commandsMap: { [command: string]: (...args: any) => any } = { @@ -71,68 +60,9 @@ const commandsMap: { [command: string]: (...args: any) => any } = { // Happens in webview resolution function // openCapturedTerminal(); }, - "continue.findSuspiciousCode": async ( - debugContext: SerializedDebugContext - ) => { - vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, - title: "Finding suspicious code", - cancellable: false, - }, - async (progress, token) => { - let suspiciousCode = await findSuspiciousCode(debugContext); - debugContext.rangesInFiles = suspiciousCode; - let { filesystem } = addFileSystemToDebugContext(debugContext); - debugPanelWebview?.postMessage({ - type: "findSuspiciousCode", - codeLocations: suspiciousCode, - filesystem, - }); - } - ); - }, - "continue.debugTest": async (fileAndFunctionSpecifier: string) => { - sendTelemetryEvent(TelemetryEvent.AutoDebugThisTest); - let editor = vscode.window.activeTextEditor; - if (editor) editor.document.save(); - let { stdout } = await runPythonScript("run_unit_test.py", [ - fileAndFunctionSpecifier, - ]); - let traceback = getLanguageLibrary( - fileAndFunctionSpecifier.split("::")[0] - ).parseFirstStacktrace(stdout); - if (!traceback) { - vscode.window.showInformationMessage("The test passes!"); - return; - } - vscode.commands.executeCommand("continue.openContinueGUI").then(() => { - setTimeout(() => { - debugPanelWebview?.postMessage({ - type: "traceback", - value: traceback, - }); - }, 500); - }); - }, }; const textEditorCommandsMap: { [command: string]: (...args: any) => {} } = { - "continue.writeUnitTest": async (editor: vscode.TextEditor) => { - let position = editor.selection.active; - - let gutterSpinnerKey = showGutterSpinner(editor, position.line); - try { - let test = await writeUnitTestForFunction( - editor.document.fileName, - position - ); - writeAndShowUnitTest(editor.document.fileName, test); - } catch { - } finally { - decorationManager.deleteDecoration(gutterSpinnerKey); - } - }, "continue.writeDocstring": async (editor: vscode.TextEditor, _) => { sendTelemetryEvent(TelemetryEvent.GenerateDocstring); let gutterSpinnerKey = showGutterSpinner( @@ -199,20 +129,3 @@ async function answerQuestion( } ); } - -// async function suggestFixForAllWorkspaceProblems() { -// Something like this, just figure out the loops for diagnostics vs problems -// let problems = vscode.languages.getDiagnostics(); -// let codeSuggestions = await Promise.all(problems.map((problem) => { -// return bridge.suggestFixForProblem(problem[0].fsPath, problem[1]); -// })); -// for (const [uri, diagnostics] of problems) { -// for (let i = 0; i < diagnostics.length; i++) { -// let diagnostic = diagnostics[i]; -// let suggestedCode = codeSuggestions[i]; -// // If you're going to do this for a bunch of files at once, it will show the unsaved icon in the tab -// // BUT it would be better to have a single window to review all edits -// showSuggestion(uri.fsPath, diagnostic.range, suggestedCode) -// } -// } -// } diff --git a/extension/src/debugPanel.ts b/extension/src/debugPanel.ts index bb98eb46..232203b9 100644 --- a/extension/src/debugPanel.ts +++ b/extension/src/debugPanel.ts @@ -1,21 +1,11 @@ import * as vscode from "vscode"; -import { - debugApi, - getContinueServerUrl, - runPythonScript, - unittestApi, -} from "./bridge"; -import { writeAndShowUnitTest } from "./decorations"; -import { showSuggestion } from "./suggestions"; -import { getLanguageLibrary } from "./languages"; +import { getContinueServerUrl } from "./bridge"; import { getExtensionUri, getNonce, openEditorAndRevealRange, } from "./util/vscode"; -import { sendTelemetryEvent, TelemetryEvent } from "./telemetry"; -import { RangeInFile, SerializedDebugContext } from "./client"; -import { addFileSystemToDebugContext } from "./util/util"; +import { RangeInFile } from "./client"; const WebSocket = require("ws"); class StreamManager { @@ -273,71 +263,6 @@ export function setupDebugPanel( connection.send(data.message); break; } - case "listTenThings": { - sendTelemetryEvent(TelemetryEvent.GenerateIdeas); - let resp = await debugApi.listtenDebugListPost({ - serializedDebugContext: data.debugContext, - }); - panel.webview.postMessage({ - type: "listTenThings", - value: resp.completion, - }); - break; - } - case "suggestFix": { - let completion: string; - let codeSelection = data.debugContext.rangesInFiles?.at(0); - if (codeSelection) { - completion = ( - await debugApi.inlineDebugInlinePost({ - inlineBody: { - filecontents: await vscode.workspace.fs - .readFile(vscode.Uri.file(codeSelection.filepath)) - .toString(), - startline: codeSelection.range.start.line, - endline: codeSelection.range.end.line, - traceback: data.debugContext.traceback, - }, - }) - ).completion; - } else if (data.debugContext.traceback) { - completion = ( - await debugApi.suggestionDebugSuggestionGet({ - traceback: data.debugContext.traceback, - }) - ).completion; - } else { - break; - } - panel.webview.postMessage({ - type: "suggestFix", - value: completion, - }); - break; - } - case "findSuspiciousCode": { - let traceback = getLanguageLibrary(".py").parseFirstStacktrace( - data.debugContext.traceback - ); - if (traceback === undefined) return; - vscode.commands.executeCommand( - "continue.findSuspiciousCode", - data.debugContext - ); - break; - } - case "queryEmbeddings": { - let { results } = await runPythonScript("index.py query", [ - data.query, - 2, - vscode.workspace.workspaceFolders?.[0].uri.fsPath, - ]); - panel.webview.postMessage({ - type: "queryEmbeddings", - results, - }); - break; - } case "openFile": { openEditorAndRevealRange(data.path, undefined, vscode.ViewColumn.One); break; @@ -351,20 +276,6 @@ export function setupDebugPanel( streamManager.closeStream(); break; } - case "explainCode": { - sendTelemetryEvent(TelemetryEvent.ExplainCode); - let debugContext: SerializedDebugContext = addFileSystemToDebugContext( - data.debugContext - ); - let resp = await debugApi.explainDebugExplainPost({ - serializedDebugContext: debugContext, - }); - panel.webview.postMessage({ - type: "explainCode", - value: resp.completion, - }); - break; - } case "withProgress": { // This message allows withProgress to be used in the webview if (data.done) { @@ -395,83 +306,6 @@ export function setupDebugPanel( ); break; } - case "makeEdit": { - sendTelemetryEvent(TelemetryEvent.SuggestFix); - let suggestedEdits = data.edits; - - if ( - typeof suggestedEdits === "undefined" || - suggestedEdits.length === 0 - ) { - vscode.window.showInformationMessage( - "Continue couldn't find a fix for this error." - ); - return; - } - - for (let i = 0; i < suggestedEdits.length; i++) { - let edit = suggestedEdits[i]; - await showSuggestion( - edit.filepath, - new vscode.Range( - edit.range.start.line, - edit.range.start.character, - edit.range.end.line, - edit.range.end.character - ), - edit.replacement - ); - } - break; - } - case "generateUnitTest": { - sendTelemetryEvent(TelemetryEvent.CreateTest); - vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, - title: "Generating Unit Test...", - cancellable: false, - }, - async () => { - for (let i = 0; i < data.debugContext.rangesInFiles?.length; i++) { - let codeSelection = data.debugContext.rangesInFiles?.at(i); - if ( - codeSelection && - codeSelection.filepath && - codeSelection.range - ) { - try { - let filecontents = ( - await vscode.workspace.fs.readFile( - vscode.Uri.file(codeSelection.filepath) - ) - ).toString(); - let resp = - await unittestApi.failingtestUnittestFailingtestPost({ - failingTestBody: { - fp: { - filecontents, - lineno: codeSelection.range.end.line, - }, - description: data.debugContext.description || "", - }, - }); - - if (resp.completion) { - let decorationKey = await writeAndShowUnitTest( - codeSelection.filepath, - resp.completion - ); - break; - } - } catch {} - } - } - } - ); - - break; - } } }); diff --git a/extension/src/decorations.ts b/extension/src/decorations.ts index d2c94135..0587110c 100644 --- a/extension/src/decorations.ts +++ b/extension/src/decorations.ts @@ -1,7 +1,5 @@ import * as vscode from "vscode"; -import { getRightViewColumn, getTestFile } from "./util/vscode"; import * as path from "path"; -import { getLanguageLibrary } from "./languages"; export function showAnswerInTextEditor( filename: string, @@ -223,98 +221,3 @@ export function highlightCode( return key; } - -// Show unit test -const pythonImportDistinguisher = (line: string): boolean => { - if (line.startsWith("from") || line.startsWith("import")) { - return true; - } - return false; -}; -const javascriptImportDistinguisher = (line: string): boolean => { - if (line.startsWith("import")) { - return true; - } - return false; -}; -const importDistinguishersMap: { - [fileExtension: string]: (line: string) => boolean; -} = { - js: javascriptImportDistinguisher, - ts: javascriptImportDistinguisher, - py: pythonImportDistinguisher, -}; -function getImportsFromFileString( - fileString: string, - importDistinguisher: (line: string) => boolean -): Set { - let importLines = new Set(); - for (let line of fileString.split("\n")) { - if (importDistinguisher(line)) { - importLines.add(line); - } - } - return importLines; -} -function removeRedundantLinesFrom( - fileContents: string, - linesToRemove: Set -): string { - let fileLines = fileContents.split("\n"); - fileLines = fileLines.filter((line: string) => { - return !linesToRemove.has(line); - }); - return fileLines.join("\n"); -} - -export async function writeAndShowUnitTest( - filename: string, - test: string -): Promise { - return new Promise((resolve, reject) => { - let testFilename = getTestFile(filename, true); - vscode.workspace.openTextDocument(testFilename).then((doc) => { - let fileContent = doc.getText(); - let fileEmpty = fileContent.trim() === ""; - let existingImportLines = getImportsFromFileString( - fileContent, - importDistinguishersMap[doc.fileName.split(".").at(-1) || ".py"] - ); - - // Remove redundant imports, make sure pytest is there - test = removeRedundantLinesFrom(test, existingImportLines); - test = - (fileEmpty - ? `${getLanguageLibrary(".py").writeImport( - testFilename, - filename - )}\nimport pytest\n\n` - : "\n\n") + - test.trim() + - "\n"; - - vscode.window - .showTextDocument(doc, getRightViewColumn()) - .then((editor) => { - let lastLine = editor.document.lineAt(editor.document.lineCount - 1); - let testRange = new vscode.Range( - lastLine.range.end, - new vscode.Position( - test.split("\n").length + lastLine.range.end.line, - 0 - ) - ); - editor - .edit((edit) => { - edit.insert(lastLine.range.end, test); - return true; - }) - .then((success) => { - if (!success) reject("Failed to insert test"); - let key = highlightCode(editor, testRange); - resolve(key); - }); - }); - }); - }); -} diff --git a/extension/src/lang-server/codeLens.ts b/extension/src/lang-server/codeLens.ts index 2a362b62..26528d96 100644 --- a/extension/src/lang-server/codeLens.ts +++ b/extension/src/lang-server/codeLens.ts @@ -1,5 +1,4 @@ import * as vscode from "vscode"; -import { getLanguageLibrary } from "../languages"; import { editorToSuggestions } from "../suggestions"; class SuggestionsCodeLensProvider implements vscode.CodeLensProvider { @@ -52,40 +51,9 @@ class SuggestionsCodeLensProvider implements vscode.CodeLensProvider { } } -class PytestCodeLensProvider implements vscode.CodeLensProvider { - public provideCodeLenses( - document: vscode.TextDocument, - token: vscode.CancellationToken - ): vscode.CodeLens[] | Thenable { - let codeLenses: vscode.CodeLens[] = []; - let lineno = 1; - let languageLibrary = getLanguageLibrary(document.fileName); - for (let line of document.getText().split("\n")) { - if ( - languageLibrary.lineIsFunctionDef(line) && - languageLibrary.parseFunctionDefForName(line).startsWith("test_") - ) { - let functionToTest = languageLibrary.parseFunctionDefForName(line); - let fileAndFunctionNameSpecifier = - document.fileName + "::" + functionToTest; - codeLenses.push( - new vscode.CodeLens(new vscode.Range(lineno, 0, lineno, 1), { - title: "Debug This Test", - command: "continue.debugTest", - arguments: [fileAndFunctionNameSpecifier], - }) - ); - } - lineno++; - } - - return codeLenses; - } -} - const allCodeLensProviders: { [langauge: string]: vscode.CodeLensProvider[] } = { - python: [new SuggestionsCodeLensProvider(), new PytestCodeLensProvider()], + python: [new SuggestionsCodeLensProvider()], }; export function registerAllCodeLensProviders(context: vscode.ExtensionContext) { diff --git a/extension/src/languages/index.d.ts b/extension/src/languages/index.d.ts deleted file mode 100644 index be7ddfbc..00000000 --- a/extension/src/languages/index.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -export interface LanguageLibrary { - language: string; - fileExtensions: string[]; - parseFirstStacktrace: (stdout: string) => string | undefined; - lineIsFunctionDef: (line: string) => boolean; - parseFunctionDefForName: (line: string) => string; - lineIsComment: (line: string) => boolean; - writeImport: ( - sourcePath: string, - pathToImport: string, - namesToImport?: string[] | undefined - ) => string; -} diff --git a/extension/src/languages/index.ts b/extension/src/languages/index.ts deleted file mode 100644 index 31d73a0b..00000000 --- a/extension/src/languages/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import pythonLanguageLibrary from "./python"; -import javascriptLanguageLibrary from "./javascript"; -import { LanguageLibrary } from "./index.d"; - -export const languageLibraries: LanguageLibrary[] = [ - pythonLanguageLibrary, - javascriptLanguageLibrary, -]; - -export function getLanguageLibrary(filepath: string): LanguageLibrary { - for (let languageLibrary of languageLibraries) { - for (let fileExtension of languageLibrary.fileExtensions) { - if (filepath.endsWith(fileExtension)) { - return languageLibrary; - } - } - } - throw new Error(`No language library found for file ${filepath}`); -} diff --git a/extension/src/languages/javascript/index.ts b/extension/src/languages/javascript/index.ts deleted file mode 100644 index 1c21a2fc..00000000 --- a/extension/src/languages/javascript/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { LanguageLibrary } from "../index.d"; -import { notImplemented } from "../notImplemented"; - -const NI = (propertyName: string) => notImplemented(propertyName, "javascript"); - -const javascriptLangaugeLibrary: LanguageLibrary = { - language: "javascript", - fileExtensions: [".js", ".jsx", ".ts", ".tsx"], - parseFirstStacktrace: NI("parseFirstStacktrace"), - lineIsFunctionDef: NI("lineIsFunctionDef"), - parseFunctionDefForName: NI("parseFunctionDefForName"), - lineIsComment: NI("lineIsComment"), - writeImport: NI("writeImport"), -}; - -export default javascriptLangaugeLibrary; diff --git a/extension/src/languages/notImplemented.ts b/extension/src/languages/notImplemented.ts deleted file mode 100644 index bbba2382..00000000 --- a/extension/src/languages/notImplemented.ts +++ /dev/null @@ -1,10 +0,0 @@ -export function notImplemented( - propertyName: string, - langauge: string -): (...args: any[]) => never { - return (...args: any[]) => { - throw new Error( - `Property ${propertyName} not implemented for language ${langauge}.` - ); - }; -} diff --git a/extension/src/languages/python/index.ts b/extension/src/languages/python/index.ts deleted file mode 100644 index 50282b45..00000000 --- a/extension/src/languages/python/index.ts +++ /dev/null @@ -1,74 +0,0 @@ -import path = require("path"); -import { LanguageLibrary } from "../index.d"; - -const tracebackStart = "Traceback (most recent call last):"; -const tracebackEnd = (buf: string): string | undefined => { - let lines = buf - .split("\n") - .filter((line: string) => line.trim() !== "~~^~~") - .filter((line: string) => line.trim() !== ""); - for (let i = 0; i < lines.length; i++) { - if ( - lines[i].startsWith(" File") && - i + 2 < lines.length && - lines[i + 2][0] !== " " - ) { - return lines.slice(0, i + 3).join("\n"); - } - } - return undefined; -}; - -function parseFirstStacktrace(stdout: string): string | undefined { - let startIdx = stdout.indexOf(tracebackStart); - if (startIdx < 0) return undefined; - stdout = stdout.substring(startIdx); - return tracebackEnd(stdout); -} - -function lineIsFunctionDef(line: string): boolean { - return line.startsWith("def "); -} - -function parseFunctionDefForName(line: string): string { - return line.split("def ")[1].split("(")[0]; -} - -function lineIsComment(line: string): boolean { - return line.trim().startsWith("#"); -} - -function writeImport( - sourcePath: string, - pathToImport: string, - namesToImport: string[] | undefined = undefined -): string { - let segs = path.relative(sourcePath, pathToImport).split(path.sep); - let importFrom = ""; - for (let seg of segs) { - if (seg === "..") { - importFrom = "." + importFrom; - } else { - if (!importFrom.endsWith(".")) { - importFrom += "."; - } - importFrom += seg.split(".").slice(0, -1).join("."); - } - } - - return `from ${importFrom} import ${ - namesToImport ? namesToImport.join(", ") : "*" - }`; -} - -const pythonLangaugeLibrary: LanguageLibrary = { - language: "python", - fileExtensions: [".py"], - parseFirstStacktrace, - lineIsFunctionDef, - parseFunctionDefForName, - lineIsComment, - writeImport, -}; - -export default pythonLangaugeLibrary; -- cgit v1.2.3-70-g09d2 From cc7ef4631f8f1bd141788c8e3117df1aca16b308 Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Wed, 21 Jun 2023 15:02:20 -0700 Subject: removing captured terminal --- extension/src/activation/activate.ts | 37 +++--------------------------------- extension/src/commands.ts | 5 ----- extension/src/continueIdeClient.ts | 14 +++----------- 3 files changed, 6 insertions(+), 50 deletions(-) (limited to 'extension') diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index 32726c86..34abdff7 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -8,7 +8,7 @@ import * as path from "path"; import IdeProtocolClient from "../continueIdeClient"; import { getContinueServerUrl } from "../bridge"; import { setupDebugPanel, ContinueGUIWebviewViewProvider } from "../debugPanel"; -import { CapturedTerminal } from "../terminal/terminalEmulator"; +// import { CapturedTerminal } from "../terminal/terminalEmulator"; export let extensionContext: vscode.ExtensionContext | undefined = undefined; @@ -49,41 +49,10 @@ export function activateExtension( })(); // All opened terminals should be replaced by our own terminal - vscode.window.onDidOpenTerminal((terminal) => { - if (terminal.name === "Continue") { - return; - } - const options = terminal.creationOptions; - const capturedTerminal = new CapturedTerminal({ - ...options, - name: "Continue", - }); - terminal.dispose(); - if (!ideProtocolClient.continueTerminal) { - ideProtocolClient.continueTerminal = capturedTerminal; - } - }); + // vscode.window.onDidOpenTerminal((terminal) => {}); // If any terminals are open to start, replace them - vscode.window.terminals.forEach((terminal) => { - if (terminal.name === "Continue") { - return; - } - const options = terminal.creationOptions; - const capturedTerminal = new CapturedTerminal( - { - ...options, - name: "Continue", - }, - (commandOutput: string) => { - ideProtocolClient.sendCommandOutput(commandOutput); - } - ); - terminal.dispose(); - if (!ideProtocolClient.continueTerminal) { - ideProtocolClient.continueTerminal = capturedTerminal; - } - }); + // vscode.window.terminals.forEach((terminal) => {} extensionContext = context; } diff --git a/extension/src/commands.ts b/extension/src/commands.ts index 22e15c43..291a3ceb 100644 --- a/extension/src/commands.ts +++ b/extension/src/commands.ts @@ -13,7 +13,6 @@ import { } from "./suggestions"; import * as bridge from "./bridge"; import { debugPanelWebview, setupDebugPanel } from "./debugPanel"; -// import { openCapturedTerminal } from "./terminal/terminalEmulator"; import { getRightViewColumn } from "./util/vscode"; import { findSuspiciousCode, @@ -67,10 +66,6 @@ const commandsMap: { [command: string]: (...args: any) => any } = { type: "focusContinueInput", }); }, - "continue.openCapturedTerminal": () => { - // Happens in webview resolution function - // openCapturedTerminal(); - }, "continue.findSuspiciousCode": async ( debugContext: SerializedDebugContext ) => { diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index fbad5f5d..202077de 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -12,7 +12,6 @@ import { debugPanelWebview, setupDebugPanel } from "./debugPanel"; import { FileEditWithFullContents } from "../schema/FileEditWithFullContents"; import fs = require("fs"); import { WebsocketMessenger } from "./util/messenger"; -import { CapturedTerminal } from "./terminal/terminalEmulator"; import { decorationManager } from "./decorations"; class IdeProtocolClient { @@ -326,17 +325,10 @@ class IdeProtocolClient { return rangeInFiles; } - public continueTerminal: CapturedTerminal | undefined; - async runCommand(command: string) { - if (!this.continueTerminal || this.continueTerminal.isClosed()) { - this.continueTerminal = new CapturedTerminal({ - name: "Continue", - }); - } - - this.continueTerminal.show(); - return await this.continueTerminal.runCommand(command); + const terminal = vscode.window.createTerminal(); + terminal.show(); + terminal.sendText(command); } sendCommandOutput(output: string) { -- cgit v1.2.3-70-g09d2 From 6c08e6d5befb0729b5020e93a60fbbe381347b7d Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Wed, 21 Jun 2023 15:25:49 -0700 Subject: initial ideas --- continuedev/src/continuedev/core/autopilot.py | 4 ++++ continuedev/src/continuedev/server/gui.py | 3 +++ continuedev/src/continuedev/server/gui_protocol.py | 4 ++++ extension/react-app/src/hooks/useContinueGUIProtocol.ts | 4 ++++ extension/react-app/src/tabs/gui.tsx | 4 ++-- 5 files changed, 17 insertions(+), 2 deletions(-) (limited to 'extension') diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index a6e688ae..2ed77e4d 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -45,6 +45,10 @@ class Autopilot(ContinueBaseModel): async def get_available_slash_commands(self) -> List[Dict]: return list(map(lambda x: {"name": x.name, "description": x.description}, self.continue_sdk.config.slash_commands)) or [] + async def change_default_model(self): + # TODO: Implement this + temp = self.continue_sdk.config.slash_commands + async def clear_history(self): self.history = History.from_empty() self._main_user_input_queue = [] diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py index cf046734..53a5f16b 100644 --- a/continuedev/src/continuedev/server/gui.py +++ b/continuedev/src/continuedev/server/gui.py @@ -116,6 +116,9 @@ class GUIProtocolServer(AbstractGUIProtocolServer): asyncio.create_task( self.session.autopilot.retry_at_index(index)) + def on_change_default_model(self): + asyncio.create_task(self.session.autopilot.change_default_model()) + def on_clear_history(self): asyncio.create_task(self.session.autopilot.clear_history()) diff --git a/continuedev/src/continuedev/server/gui_protocol.py b/continuedev/src/continuedev/server/gui_protocol.py index d9506c6f..66839d9b 100644 --- a/continuedev/src/continuedev/server/gui_protocol.py +++ b/continuedev/src/continuedev/server/gui_protocol.py @@ -35,6 +35,10 @@ class AbstractGUIProtocolServer(ABC): def on_retry_at_index(self, index: int): """Called when the user requests a retry at a previous index""" + @abstractmethod + def on_change_default_model(self): + """Called when the user requests to change the default model""" + @abstractmethod def on_clear_history(self): """Called when the user requests to clear the history""" diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts index 59397742..4eb68046 100644 --- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts +++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts @@ -55,6 +55,10 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { }); } + changeDefaultModel() { + this.messenger.send("change_default_model", {}); + } + sendClear() { this.messenger.send("clear_history", {}); } diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index f0e3ffd4..15260e0c 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -470,7 +470,7 @@ function GUI(props: GUIProps) { Contribute Data - {/* { setUsingFastModel((prev) => !prev); }} @@ -481,7 +481,7 @@ function GUI(props: GUIProps) { > {usingFastModel ? "⚡" : "🧠"} - */} + } { client?.sendClear(); -- cgit v1.2.3-70-g09d2 From a1f9bfd25c2df807ccc49be67b0bc0e57321c272 Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Wed, 21 Jun 2023 15:28:37 -0700 Subject: Revert "initial ideas" This reverts commit 6c08e6d5befb0729b5020e93a60fbbe381347b7d. --- continuedev/src/continuedev/core/autopilot.py | 4 ---- continuedev/src/continuedev/server/gui.py | 3 --- continuedev/src/continuedev/server/gui_protocol.py | 4 ---- extension/react-app/src/hooks/useContinueGUIProtocol.ts | 4 ---- extension/react-app/src/tabs/gui.tsx | 4 ++-- 5 files changed, 2 insertions(+), 17 deletions(-) (limited to 'extension') diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index 2ed77e4d..a6e688ae 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -45,10 +45,6 @@ class Autopilot(ContinueBaseModel): async def get_available_slash_commands(self) -> List[Dict]: return list(map(lambda x: {"name": x.name, "description": x.description}, self.continue_sdk.config.slash_commands)) or [] - async def change_default_model(self): - # TODO: Implement this - temp = self.continue_sdk.config.slash_commands - async def clear_history(self): self.history = History.from_empty() self._main_user_input_queue = [] diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py index 53a5f16b..cf046734 100644 --- a/continuedev/src/continuedev/server/gui.py +++ b/continuedev/src/continuedev/server/gui.py @@ -116,9 +116,6 @@ class GUIProtocolServer(AbstractGUIProtocolServer): asyncio.create_task( self.session.autopilot.retry_at_index(index)) - def on_change_default_model(self): - asyncio.create_task(self.session.autopilot.change_default_model()) - def on_clear_history(self): asyncio.create_task(self.session.autopilot.clear_history()) diff --git a/continuedev/src/continuedev/server/gui_protocol.py b/continuedev/src/continuedev/server/gui_protocol.py index 66839d9b..d9506c6f 100644 --- a/continuedev/src/continuedev/server/gui_protocol.py +++ b/continuedev/src/continuedev/server/gui_protocol.py @@ -35,10 +35,6 @@ class AbstractGUIProtocolServer(ABC): def on_retry_at_index(self, index: int): """Called when the user requests a retry at a previous index""" - @abstractmethod - def on_change_default_model(self): - """Called when the user requests to change the default model""" - @abstractmethod def on_clear_history(self): """Called when the user requests to clear the history""" diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts index 4eb68046..59397742 100644 --- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts +++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts @@ -55,10 +55,6 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { }); } - changeDefaultModel() { - this.messenger.send("change_default_model", {}); - } - sendClear() { this.messenger.send("clear_history", {}); } diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index 15260e0c..f0e3ffd4 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -470,7 +470,7 @@ function GUI(props: GUIProps) { Contribute Data - { { setUsingFastModel((prev) => !prev); }} @@ -481,7 +481,7 @@ function GUI(props: GUIProps) { > {usingFastModel ? "⚡" : "🧠"} - } + */} { client?.sendClear(); -- cgit v1.2.3-70-g09d2 From 559a5301c382934f48c81f476909931a0a0e9b44 Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Wed, 21 Jun 2023 15:36:12 -0700 Subject: initial ideas --- continuedev/src/continuedev/core/autopilot.py | 4 ++++ continuedev/src/continuedev/server/gui.py | 3 +++ continuedev/src/continuedev/server/gui_protocol.py | 4 ++++ extension/react-app/src/hooks/useContinueGUIProtocol.ts | 4 ++++ extension/react-app/src/tabs/gui.tsx | 4 ++-- 5 files changed, 17 insertions(+), 2 deletions(-) (limited to 'extension') diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index a6e688ae..2ed77e4d 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -45,6 +45,10 @@ class Autopilot(ContinueBaseModel): async def get_available_slash_commands(self) -> List[Dict]: return list(map(lambda x: {"name": x.name, "description": x.description}, self.continue_sdk.config.slash_commands)) or [] + async def change_default_model(self): + # TODO: Implement this + temp = self.continue_sdk.config.slash_commands + async def clear_history(self): self.history = History.from_empty() self._main_user_input_queue = [] diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py index cf046734..53a5f16b 100644 --- a/continuedev/src/continuedev/server/gui.py +++ b/continuedev/src/continuedev/server/gui.py @@ -116,6 +116,9 @@ class GUIProtocolServer(AbstractGUIProtocolServer): asyncio.create_task( self.session.autopilot.retry_at_index(index)) + def on_change_default_model(self): + asyncio.create_task(self.session.autopilot.change_default_model()) + def on_clear_history(self): asyncio.create_task(self.session.autopilot.clear_history()) diff --git a/continuedev/src/continuedev/server/gui_protocol.py b/continuedev/src/continuedev/server/gui_protocol.py index d9506c6f..66839d9b 100644 --- a/continuedev/src/continuedev/server/gui_protocol.py +++ b/continuedev/src/continuedev/server/gui_protocol.py @@ -35,6 +35,10 @@ class AbstractGUIProtocolServer(ABC): def on_retry_at_index(self, index: int): """Called when the user requests a retry at a previous index""" + @abstractmethod + def on_change_default_model(self): + """Called when the user requests to change the default model""" + @abstractmethod def on_clear_history(self): """Called when the user requests to clear the history""" diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts index 59397742..4eb68046 100644 --- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts +++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts @@ -55,6 +55,10 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { }); } + changeDefaultModel() { + this.messenger.send("change_default_model", {}); + } + sendClear() { this.messenger.send("clear_history", {}); } diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index f0e3ffd4..cbc0e8af 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -470,7 +470,7 @@ function GUI(props: GUIProps) { Contribute Data - {/* { setUsingFastModel((prev) => !prev); }} @@ -481,7 +481,7 @@ function GUI(props: GUIProps) { > {usingFastModel ? "⚡" : "🧠"} - */} + { client?.sendClear(); -- cgit v1.2.3-70-g09d2 From 695abf458f25e0cb7b05cebe3a0f9ec2c97e7797 Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Wed, 21 Jun 2023 21:33:24 -0700 Subject: more progress --- continuedev/src/continuedev/core/autopilot.py | 7 +++++-- continuedev/src/continuedev/server/gui.py | 2 ++ extension/react-app/src/hooks/ContinueGUIClientProtocol.ts | 2 ++ extension/react-app/src/tabs/gui.tsx | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) (limited to 'extension') diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index 2ed77e4d..0b4b9b12 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -46,8 +46,11 @@ class Autopilot(ContinueBaseModel): return list(map(lambda x: {"name": x.name, "description": x.description}, self.continue_sdk.config.slash_commands)) or [] async def change_default_model(self): - # TODO: Implement this - temp = self.continue_sdk.config.slash_commands + print("Changing default model") + if self.continue_sdk.config.default_model == "gpt-4": + self.continue_sdk.config.default_model == "gpt-3.5-turbo" # not quite correct + else: + self.continue_sdk.config.default_model == "gpt-4" # not quite correct async def clear_history(self): self.history = History.from_empty() diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py index 53a5f16b..9b36c704 100644 --- a/continuedev/src/continuedev/server/gui.py +++ b/continuedev/src/continuedev/server/gui.py @@ -77,6 +77,8 @@ class GUIProtocolServer(AbstractGUIProtocolServer): self.on_reverse_to_index(data["index"]) elif message_type == "retry_at_index": self.on_retry_at_index(data["index"]) + elif message_type == "change_default_model": + self.on_change_default_model() elif message_type == "clear_history": self.on_clear_history() elif message_type == "delete_at_index": diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts index 824bb086..6d9d1fdd 100644 --- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts @@ -13,6 +13,8 @@ abstract class AbstractContinueGUIClientProtocol { callback: (commands: { name: string; description: string }[]) => void ): void; + abstract changeDefaultModel(): void; + abstract sendClear(): void; abstract retryAtIndex(index: number): void; diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index cbc0e8af..15121010 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -473,6 +473,7 @@ function GUI(props: GUIProps) { { setUsingFastModel((prev) => !prev); + client?.changeDefaultModel(); }} text={usingFastModel ? "gpt-3.5-turbo" : "gpt-4"} > -- cgit v1.2.3-70-g09d2 From 24198f9724fbc42b128d93fcb612bcd60f1837e1 Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Wed, 21 Jun 2023 21:36:24 -0700 Subject: run existing terminal if possible --- extension/src/continueIdeClient.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'extension') diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index 202077de..3a77e348 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -326,9 +326,13 @@ class IdeProtocolClient { } async runCommand(command: string) { - const terminal = vscode.window.createTerminal(); - terminal.show(); - terminal.sendText(command); + if (vscode.window.terminals.length) { + vscode.window.terminals[0].sendText(command); + } else { + const terminal = vscode.window.createTerminal(); + terminal.show(); + terminal.sendText(command); + } } sendCommandOutput(output: string) { -- cgit v1.2.3-70-g09d2 From a1a9c4fc01e7bb9239aa67717dd8397d32eea31a Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Thu, 22 Jun 2023 12:39:01 -0700 Subject: start of syncing back --- continuedev/src/continuedev/core/autopilot.py | 8 ++---- continuedev/src/continuedev/core/config.py | 35 +++++++++++++++++++++++++++ continuedev/src/continuedev/core/main.py | 1 + continuedev/src/continuedev/core/sdk.py | 11 ++++++++- extension/react-app/src/tabs/gui.tsx | 1 + 5 files changed, 49 insertions(+), 7 deletions(-) (limited to 'extension') diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index 0b4b9b12..ab7f4747 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -40,17 +40,13 @@ class Autopilot(ContinueBaseModel): keep_untouched = (cached_property,) def get_full_state(self) -> FullState: - return FullState(history=self.history, active=self._active, user_input_queue=self._main_user_input_queue) + return FullState(history=self.history, active=self._active, user_input_queue=self._main_user_input_queue, default_model=self.continue_sdk.config.default_model) async def get_available_slash_commands(self) -> List[Dict]: return list(map(lambda x: {"name": x.name, "description": x.description}, self.continue_sdk.config.slash_commands)) or [] async def change_default_model(self): - print("Changing default model") - if self.continue_sdk.config.default_model == "gpt-4": - self.continue_sdk.config.default_model == "gpt-3.5-turbo" # not quite correct - else: - self.continue_sdk.config.default_model == "gpt-4" # not quite correct + self.continue_sdk.update_default_model() async def clear_history(self): self.history = History.from_empty() diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py index 652320fb..21d21879 100644 --- a/continuedev/src/continuedev/core/config.py +++ b/continuedev/src/continuedev/core/config.py @@ -86,3 +86,38 @@ def load_config(config_file: str) -> ContinueConfig: else: raise ValueError(f'Unknown config file extension: {ext}') return ContinueConfig(**config_dict) + +def update_config(config_file: str): + """ + Update the config file with the current ContinueConfig object. + """ + if not os.path.exists(config_file): + with open(config_file, 'w') as f: + config_dict = { "default_model": "gpt-3.5-turbo" } + json.dump(config_dict, f, indent=4) + + _, ext = os.path.splitext(config_file) + if ext == '.yaml': + + with open(config_file, 'w') as f: + config_dict = yaml.safe_load(f) + + if config_dict["default_model"] == "gpt-4": + config_dict["default_model"] = "gpt-3.5-turbo" + else: + config_dict["default_model"] = "gpt-4" + + with open(config_file, 'w') as f: + json.dump(config_dict, f, indent=4) + + elif ext == '.json': + with open(config_file, 'r') as f: + config_dict = json.load(f) + + if config_dict["default_model"] == "gpt-4": + config_dict["default_model"] = "gpt-3.5-turbo" + else: + config_dict["default_model"] = "gpt-4" + + with open(config_file, 'w') as f: + json.dump(config_dict, f, indent=4) \ No newline at end of file diff --git a/continuedev/src/continuedev/core/main.py b/continuedev/src/continuedev/core/main.py index efb91488..d6412ece 100644 --- a/continuedev/src/continuedev/core/main.py +++ b/continuedev/src/continuedev/core/main.py @@ -114,6 +114,7 @@ class FullState(ContinueBaseModel): history: History active: bool user_input_queue: List[str] + default_model: str class ContinueSDK: diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py index d6acc404..5652ec39 100644 --- a/continuedev/src/continuedev/core/sdk.py +++ b/continuedev/src/continuedev/core/sdk.py @@ -6,7 +6,7 @@ import os from ..steps.core.core import DefaultModelEditCodeStep from ..models.main import Range from .abstract_sdk import AbstractContinueSDK -from .config import ContinueConfig, load_config +from .config import ContinueConfig, load_config, update_config from ..models.filesystem_edit import FileEdit, FileSystemEdit, AddFile, DeleteFile, AddDirectory, DeleteDirectory from ..models.filesystem import RangeInFile from ..libs.llm.hf_inference_api import HuggingFaceInferenceAPI @@ -170,6 +170,15 @@ class ContinueSDK(AbstractContinueSDK): else: return ContinueConfig() + def update_default_model(self): + dir = self.ide.workspace_directory + yaml_path = os.path.join(dir, '.continue', 'config.yaml') + json_path = os.path.join(dir, '.continue', 'config.json') + if os.path.exists(yaml_path): + update_config(yaml_path) + else: + update_config(json_path) + def set_loading_message(self, message: str): # self.__autopilot.set_loading_message(message) raise NotImplementedError() diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index 15121010..0dd7e3ec 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -230,6 +230,7 @@ function GUI(props: GUIProps) { console.log("CLIENT ON STATE UPDATE: ", client, client?.onStateUpdate); client?.onStateUpdate((state) => { // Scroll only if user is at very bottom of the window. + setUsingFastModel(state.using_fast_model); const shouldScrollToBottom = topGuiDivRef.current && topGuiDivRef.current?.offsetHeight - window.scrollY < 100; -- cgit v1.2.3-70-g09d2 From af67d7d8309c88f7dced869a31359de66e9341c3 Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Thu, 22 Jun 2023 13:04:04 -0700 Subject: adding default model --- extension/react-app/src/tabs/gui.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'extension') diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index 0dd7e3ec..16c950ef 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -230,7 +230,7 @@ function GUI(props: GUIProps) { console.log("CLIENT ON STATE UPDATE: ", client, client?.onStateUpdate); client?.onStateUpdate((state) => { // Scroll only if user is at very bottom of the window. - setUsingFastModel(state.using_fast_model); + setUsingFastModel(state.default_model === "gpt-3.5-turbo"); const shouldScrollToBottom = topGuiDivRef.current && topGuiDivRef.current?.offsetHeight - window.scrollY < 100; -- cgit v1.2.3-70-g09d2 From 589fd45fb13c17a1bd13d758806946b55d157a22 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Thu, 22 Jun 2023 13:56:48 -0700 Subject: update global config with default model toggle --- continuedev/src/continuedev/core/autopilot.py | 4 +- continuedev/src/continuedev/core/config.py | 64 ++++++++++++---------- continuedev/src/continuedev/core/sdk.py | 18 +++--- continuedev/src/continuedev/server/gui.py | 6 +- .../src/hooks/ContinueGUIClientProtocol.ts | 2 +- .../react-app/src/hooks/useContinueGUIProtocol.ts | 4 +- extension/react-app/src/tabs/gui.tsx | 10 ++-- 7 files changed, 57 insertions(+), 51 deletions(-) (limited to 'extension') diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index ab7f4747..f14a4127 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -45,8 +45,8 @@ class Autopilot(ContinueBaseModel): async def get_available_slash_commands(self) -> List[Dict]: return list(map(lambda x: {"name": x.name, "description": x.description}, self.continue_sdk.config.slash_commands)) or [] - async def change_default_model(self): - self.continue_sdk.update_default_model() + async def change_default_model(self, model: str): + self.continue_sdk.update_default_model(model) async def clear_history(self): self.history = History.from_empty() diff --git a/continuedev/src/continuedev/core/config.py b/continuedev/src/continuedev/core/config.py index 21d21879..01316f1b 100644 --- a/continuedev/src/continuedev/core/config.py +++ b/continuedev/src/continuedev/core/config.py @@ -87,37 +87,45 @@ def load_config(config_file: str) -> ContinueConfig: raise ValueError(f'Unknown config file extension: {ext}') return ContinueConfig(**config_dict) -def update_config(config_file: str): + +def load_global_config() -> ContinueConfig: """ - Update the config file with the current ContinueConfig object. + Load the global config file and return a ContinueConfig object. """ - if not os.path.exists(config_file): - with open(config_file, 'w') as f: - config_dict = { "default_model": "gpt-3.5-turbo" } - json.dump(config_dict, f, indent=4) - - _, ext = os.path.splitext(config_file) - if ext == '.yaml': + global_dir = os.path.expanduser('~/.continue') + if not os.path.exists(global_dir): + os.mkdir(global_dir) - with open(config_file, 'w') as f: - config_dict = yaml.safe_load(f) + yaml_path = os.path.join(global_dir, 'config.yaml') + if os.path.exists(yaml_path): + with open(config_path, 'r') as f: + try: + config_dict = yaml.safe_load(f) + except: + return ContinueConfig() + else: + config_path = os.path.join(global_dir, 'config.json') + with open(config_path, 'r') as f: + try: + config_dict = json.load(f) + except: + return ContinueConfig() + return ContinueConfig(**config_dict) - if config_dict["default_model"] == "gpt-4": - config_dict["default_model"] = "gpt-3.5-turbo" - else: - config_dict["default_model"] = "gpt-4" - - with open(config_file, 'w') as f: - json.dump(config_dict, f, indent=4) - elif ext == '.json': - with open(config_file, 'r') as f: - config_dict = json.load(f) +def update_global_config(config: ContinueConfig): + """ + Update the config file with the given ContinueConfig object. + """ + global_dir = os.path.expanduser('~/.continue') + if not os.path.exists(global_dir): + os.mkdir(global_dir) - if config_dict["default_model"] == "gpt-4": - config_dict["default_model"] = "gpt-3.5-turbo" - else: - config_dict["default_model"] = "gpt-4" - - with open(config_file, 'w') as f: - json.dump(config_dict, f, indent=4) \ No newline at end of file + yaml_path = os.path.join(global_dir, 'config.yaml') + if os.path.exists(yaml_path): + with open(config_path, 'w') as f: + yaml.dump(config.dict(), f) + else: + config_path = os.path.join(global_dir, 'config.json') + with open(config_path, 'w') as f: + json.dump(config.dict(), f) diff --git a/continuedev/src/continuedev/core/sdk.py b/continuedev/src/continuedev/core/sdk.py index 5652ec39..192552e7 100644 --- a/continuedev/src/continuedev/core/sdk.py +++ b/continuedev/src/continuedev/core/sdk.py @@ -6,7 +6,7 @@ import os from ..steps.core.core import DefaultModelEditCodeStep from ..models.main import Range from .abstract_sdk import AbstractContinueSDK -from .config import ContinueConfig, load_config, update_config +from .config import ContinueConfig, load_config, load_global_config, update_global_config from ..models.filesystem_edit import FileEdit, FileSystemEdit, AddFile, DeleteFile, AddDirectory, DeleteDirectory from ..models.filesystem import RangeInFile from ..libs.llm.hf_inference_api import HuggingFaceInferenceAPI @@ -76,7 +76,7 @@ class Models: else: raise Exception(f"Unknown model {model_name}") - @cached_property + @property def default(self): default_model = self.sdk.config.default_model return self.__model_from_name(default_model) if default_model is not None else self.gpt35 @@ -168,16 +168,12 @@ class ContinueSDK(AbstractContinueSDK): elif os.path.exists(json_path): return load_config(json_path) else: - return ContinueConfig() + return load_global_config() - def update_default_model(self): - dir = self.ide.workspace_directory - yaml_path = os.path.join(dir, '.continue', 'config.yaml') - json_path = os.path.join(dir, '.continue', 'config.json') - if os.path.exists(yaml_path): - update_config(yaml_path) - else: - update_config(json_path) + def update_default_model(self, model: str): + config = self.config + config.default_model = model + update_global_config(config) def set_loading_message(self, message: str): # self.__autopilot.set_loading_message(message) diff --git a/continuedev/src/continuedev/server/gui.py b/continuedev/src/continuedev/server/gui.py index 9b36c704..cc6235e9 100644 --- a/continuedev/src/continuedev/server/gui.py +++ b/continuedev/src/continuedev/server/gui.py @@ -78,7 +78,7 @@ class GUIProtocolServer(AbstractGUIProtocolServer): elif message_type == "retry_at_index": self.on_retry_at_index(data["index"]) elif message_type == "change_default_model": - self.on_change_default_model() + self.on_change_default_model(data["model"]) elif message_type == "clear_history": self.on_clear_history() elif message_type == "delete_at_index": @@ -118,8 +118,8 @@ class GUIProtocolServer(AbstractGUIProtocolServer): asyncio.create_task( self.session.autopilot.retry_at_index(index)) - def on_change_default_model(self): - asyncio.create_task(self.session.autopilot.change_default_model()) + def on_change_default_model(self, model: str): + asyncio.create_task(self.session.autopilot.change_default_model(model)) def on_clear_history(self): asyncio.create_task(self.session.autopilot.clear_history()) diff --git a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts index 6d9d1fdd..3d8e0a38 100644 --- a/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts +++ b/extension/react-app/src/hooks/ContinueGUIClientProtocol.ts @@ -13,7 +13,7 @@ abstract class AbstractContinueGUIClientProtocol { callback: (commands: { name: string; description: string }[]) => void ): void; - abstract changeDefaultModel(): void; + abstract changeDefaultModel(model: string): void; abstract sendClear(): void; diff --git a/extension/react-app/src/hooks/useContinueGUIProtocol.ts b/extension/react-app/src/hooks/useContinueGUIProtocol.ts index 4eb68046..f43a66ff 100644 --- a/extension/react-app/src/hooks/useContinueGUIProtocol.ts +++ b/extension/react-app/src/hooks/useContinueGUIProtocol.ts @@ -55,8 +55,8 @@ class ContinueGUIClientProtocol extends AbstractContinueGUIClientProtocol { }); } - changeDefaultModel() { - this.messenger.send("change_default_model", {}); + changeDefaultModel(model: string) { + this.messenger.send("change_default_model", { model }); } sendClear() { diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index 16c950ef..f47371ee 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -427,9 +427,9 @@ function GUI(props: GUIProps) { }} hidden={!showDataSharingInfo} > - By turning on this switch, you signal that you would - contribute this software development data to a publicly - accessible, open-source dataset in the future. + By turning on this switch, you signal that you would contribute this + software development data to a publicly accessible, open-source dataset + in the future.

@@ -473,8 +473,10 @@ function GUI(props: GUIProps) { { + client?.changeDefaultModel( + usingFastModel ? "gpt-4" : "gpt-3.5-turbo" + ); setUsingFastModel((prev) => !prev); - client?.changeDefaultModel(); }} text={usingFastModel ? "gpt-3.5-turbo" : "gpt-4"} > -- cgit v1.2.3-70-g09d2 From cfee19c8faad0eb5216e49f174e27aeb388e7830 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Thu, 22 Jun 2023 17:02:50 -0700 Subject: added continue retro button icon --- extension/react-app/src/components/ContinueButton.tsx | 13 +++++++++++-- extension/react-app/src/components/DebugPanel.tsx | 2 ++ extension/react-app/src/redux/slices/configSlice.ts | 16 ++++++++++++++-- extension/react-app/src/redux/store.ts | 1 + extension/src/debugPanel.ts | 4 ++++ 5 files changed, 32 insertions(+), 4 deletions(-) (limited to 'extension') diff --git a/extension/react-app/src/components/ContinueButton.tsx b/extension/react-app/src/components/ContinueButton.tsx index c6117bf9..ef6719b7 100644 --- a/extension/react-app/src/components/ContinueButton.tsx +++ b/extension/react-app/src/components/ContinueButton.tsx @@ -1,6 +1,8 @@ import styled, { keyframes } from "styled-components"; import { Button } from "."; import { Play } from "@styled-icons/heroicons-outline"; +import { useSelector } from "react-redux"; +import { RootStore } from "../redux/store"; let StyledButton = styled(Button)` margin: auto; @@ -25,14 +27,21 @@ let StyledButton = styled(Button)` `; function ContinueButton(props: { onClick?: () => void; hidden?: boolean }) { + const vscMediaUrl = useSelector( + (state: RootStore) => state.config.vscMediaUrl + ); + return ( ); diff --git a/extension/react-app/src/components/DebugPanel.tsx b/extension/react-app/src/components/DebugPanel.tsx index 30f38779..94dbac9e 100644 --- a/extension/react-app/src/components/DebugPanel.tsx +++ b/extension/react-app/src/components/DebugPanel.tsx @@ -6,6 +6,7 @@ import { setApiUrl, setVscMachineId, setSessionId, + setVscMediaUrl, } from "../redux/slices/configSlice"; import { setHighlightedCode } from "../redux/slices/miscSlice"; import { updateFileSystem } from "../redux/slices/debugContexSlice"; @@ -37,6 +38,7 @@ function DebugPanel(props: DebugPanelProps) { dispatch(setApiUrl(event.data.apiUrl)); dispatch(setVscMachineId(event.data.vscMachineId)); dispatch(setSessionId(event.data.sessionId)); + dispatch(setVscMediaUrl(event.data.vscMediaUrl)); break; case "highlightedCode": dispatch(setHighlightedCode(event.data.rangeInFile)); diff --git a/extension/react-app/src/redux/slices/configSlice.ts b/extension/react-app/src/redux/slices/configSlice.ts index a6a641e6..1b107bed 100644 --- a/extension/react-app/src/redux/slices/configSlice.ts +++ b/extension/react-app/src/redux/slices/configSlice.ts @@ -37,9 +37,21 @@ export const configSlice = createSlice({ ...state, sessionId: action.payload, }), + setVscMediaUrl: ( + state: RootStore["config"], + action: { type: string; payload: string } + ) => ({ + ...state, + vscMediaUrl: action.payload, + }), }, }); -export const { setVscMachineId, setApiUrl, setWorkspacePath, setSessionId } = - configSlice.actions; +export const { + setVscMachineId, + setApiUrl, + setWorkspacePath, + setSessionId, + setVscMediaUrl, +} = configSlice.actions; export default configSlice.reducer; diff --git a/extension/react-app/src/redux/store.ts b/extension/react-app/src/redux/store.ts index f9eb0517..a5eef4ba 100644 --- a/extension/react-app/src/redux/store.ts +++ b/extension/react-app/src/redux/store.ts @@ -21,6 +21,7 @@ export interface RootStore { vscMachineId: string | undefined; sessionId: string | undefined; sessionStarted: number | undefined; + vscMediaUrl: string | undefined; }; chat: { messages: ChatMessage[]; diff --git a/extension/src/debugPanel.ts b/extension/src/debugPanel.ts index 232203b9..b0db590a 100644 --- a/extension/src/debugPanel.ts +++ b/extension/src/debugPanel.ts @@ -136,6 +136,9 @@ export function setupDebugPanel( let extensionUri = getExtensionUri(); let scriptUri: string; let styleMainUri: string; + let vscMediaUrl: string = debugPanelWebview + .asWebviewUri(vscode.Uri.joinPath(extensionUri, "react-app/dist")) + .toString(); const isProduction = true; // context?.extensionMode === vscode.ExtensionMode.Development; if (!isProduction) { @@ -226,6 +229,7 @@ export function setupDebugPanel( vscMachineId: vscode.env.machineId, apiUrl: getContinueServerUrl(), sessionId, + vscMediaUrl, }); // // Listen for changes to server URL in settings -- cgit v1.2.3-70-g09d2 From a63a8aa2b228e9165359bae7f5a8e19227e9e824 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Thu, 22 Jun 2023 17:05:53 -0700 Subject: patch --- extension/package-lock.json | 4 ++-- extension/package.json | 2 +- .../scripts/continuedev-0.1.1-py3-none-any.whl | Bin 86409 -> 86716 bytes 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'extension') diff --git a/extension/package-lock.json b/extension/package-lock.json index 79b010cc..12b2fe13 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.60", + "version": "0.0.61", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.60", + "version": "0.0.61", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 94a58ebd..9fd1d7a6 100644 --- a/extension/package.json +++ b/extension/package.json @@ -14,7 +14,7 @@ "displayName": "Continue", "pricing": "Free", "description": "Accelerating software development with language models", - "version": "0.0.60", + "version": "0.0.61", "publisher": "Continue", "engines": { "vscode": "^1.74.0" diff --git a/extension/scripts/continuedev-0.1.1-py3-none-any.whl b/extension/scripts/continuedev-0.1.1-py3-none-any.whl index 99f96d80..29e41d3c 100644 Binary files a/extension/scripts/continuedev-0.1.1-py3-none-any.whl and b/extension/scripts/continuedev-0.1.1-py3-none-any.whl differ -- cgit v1.2.3-70-g09d2 From 3f1123095d2ee652b1db239d325aa74f5acfb0cf Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 25 Jun 2023 08:22:37 -0700 Subject: Diff kb shortcut, fix bug --- extension/react-app/src/tabs/gui.tsx | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'extension') diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index f47371ee..a457382d 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -215,7 +215,7 @@ function GUI(props: GUIProps) { useEffect(() => { const listener = (e: any) => { // Cmd + J to toggle fast model - if (e.key === "j" && e.metaKey) { + if (e.key === "i" && e.metaKey && e.shiftKey) { setUsingFastModel((prev) => !prev); } }; @@ -237,15 +237,17 @@ function GUI(props: GUIProps) { setWaitingForSteps(state.active); setHistory(state.history); setUserInputQueue(state.user_input_queue); - const nextStepsOpen = [...stepsOpen]; - for ( - let i = nextStepsOpen.length; - i < state.history.timeline.length; - i++ - ) { - nextStepsOpen.push(true); - } - setStepsOpen(nextStepsOpen); + setStepsOpen((prev) => { + const nextStepsOpen = [...prev]; + for ( + let i = nextStepsOpen.length; + i < state.history.timeline.length; + i++ + ) { + nextStepsOpen.push(true); + } + return nextStepsOpen; + }); if (shouldScrollToBottom) { scrollToBottom(); -- cgit v1.2.3-70-g09d2 From f97dfba3f6b2fe14797dfec79867df2aeef28800 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 25 Jun 2023 12:12:11 -0700 Subject: tweaks --- continuedev/src/continuedev/steps/chat.py | 17 +++++++++++++---- extension/react-app/src/tabs/gui.tsx | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'extension') diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py index fee8f40e..a29f7f2f 100644 --- a/continuedev/src/continuedev/steps/chat.py +++ b/continuedev/src/continuedev/steps/chat.py @@ -88,7 +88,7 @@ class RunTerminalCommandStep(Step): return f"Ran the terminal command {self.command}." async def run(self, sdk: ContinueSDK): - await sdk.wait_for_user_confirmation(f"Run the terminal command {self.command}?") + await sdk.wait_for_user_confirmation(f"Run the following terminal command?\n\n```bash\n{self.command}\n```") await sdk.run(self.command) @@ -201,7 +201,16 @@ class ChatWithFunctions(Step): summary=f"Ran function {func_name}" )) last_function_called_index_in_history = sdk.history.current_index + 1 - await sdk.run_step(step_name_step_class_map[func_name]( - **fn_call_params)) - self.description += f"`Running function {func_name}`\n\n" + step_to_run = step_name_step_class_map[func_name]( + **fn_call_params) + + if func_name == "AddFileStep": + step_to_run.hide = True + self.description += f"\nAdded file `{func_args['filename']}`" + elif func_name == "AddDirectoryStep": + step_to_run.hide = True + self.description += f"\nAdded directory `{func_args['directory_name']}`" + else: + self.description += f"\n`Running function {func_name}`\n\n" + await sdk.run_step(step_to_run) await sdk.update_ui() diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index 24529967..d6131174 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -388,7 +388,7 @@ function GUI(props: GUIProps) { /> ); })} - {/* {waitingForSteps && } */} + {waitingForSteps && }
{userInputQueue.map((input) => { -- cgit v1.2.3-70-g09d2 From 4b394e96a57e0a018cb815e929bf28b445e17ae0 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 25 Jun 2023 13:44:31 -0700 Subject: don't call python function, other --- continuedev/src/continuedev/libs/llm/openai.py | 2 +- continuedev/src/continuedev/steps/chat.py | 13 +++++++++++-- continuedev/src/continuedev/steps/core/core.py | 3 ++- continuedev/src/continuedev/steps/main.py | 5 +++-- extension/react-app/src/components/HeaderButtonWithText.tsx | 2 ++ extension/react-app/src/components/StepContainer.tsx | 1 + 6 files changed, 20 insertions(+), 6 deletions(-) (limited to 'extension') diff --git a/continuedev/src/continuedev/libs/llm/openai.py b/continuedev/src/continuedev/libs/llm/openai.py index aa12d70a..7621111f 100644 --- a/continuedev/src/continuedev/libs/llm/openai.py +++ b/continuedev/src/continuedev/libs/llm/openai.py @@ -70,7 +70,7 @@ class OpenAI(LLM): messages=compile_chat_messages( args["model"], with_history, prompt, with_functions=False), **args, - )).choices[0].message + )).choices[0].message.content else: resp = (await openai.Completion.acreate( prompt=prompt, diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py index 76fead9d..a940c3ba 100644 --- a/continuedev/src/continuedev/steps/chat.py +++ b/continuedev/src/continuedev/steps/chat.py @@ -105,7 +105,7 @@ class ViewDirectoryTreeStep(Step): class EditFileStep(Step): name: str = "Edit File" - description: str = "Edit a file in the workspace." + description: str = "Edit a file in the workspace that is not currently open." filename: str instructions: str hide: bool = True @@ -136,7 +136,7 @@ class ChatWithFunctions(Step): self.chat_context.append(ChatMessage( role="user", - content=self.user_input, + content=self.user_input + "\n**DO NOT EVER call the 'python' function.**", summary=self.user_input )) @@ -182,6 +182,15 @@ class ChatWithFunctions(Step): else: if func_name == "python" and "python" not in step_name_step_class_map: # GPT must be fine-tuned to believe this exists, but it doesn't always + self.chat_context.append(ChatMessage( + role="assistant", + content=None, + function_call=FunctionCall( + name=func_name, + arguments=func_args + ), + summary=f"Ran function {func_name}" + )) self.chat_context.append(ChatMessage( role="user", content="The 'python' function does not exist. Don't call it.", diff --git a/continuedev/src/continuedev/steps/core/core.py b/continuedev/src/continuedev/steps/core/core.py index 7ccf82cb..f146c94a 100644 --- a/continuedev/src/continuedev/steps/core/core.py +++ b/continuedev/src/continuedev/steps/core/core.py @@ -213,7 +213,8 @@ class DefaultModelEditCodeStep(Step): if model_to_use.name == "gpt-4": - total_tokens = model_to_use.count_tokens(full_file_contents + self._prompt) + total_tokens = model_to_use.count_tokens( + full_file_contents + self._prompt) cur_start_line, cur_end_line = cut_context( model_to_use, total_tokens, cur_start_line, cur_end_line) diff --git a/continuedev/src/continuedev/steps/main.py b/continuedev/src/continuedev/steps/main.py index bb48dce9..5caac180 100644 --- a/continuedev/src/continuedev/steps/main.py +++ b/continuedev/src/continuedev/steps/main.py @@ -1,7 +1,7 @@ import os from typing import Coroutine, List, Union -from pydantic import BaseModel +from pydantic import BaseModel, Field from ..libs.llm import LLM from ..models.main import Traceback, Range @@ -246,7 +246,8 @@ class StarCoderEditHighlightedCodeStep(Step): class EditHighlightedCodeStep(Step): - user_input: str + user_input: str = Field( + ..., title="User Input", description="The natural language request describing how to edit the code") hide = True description: str = "Change the contents of the currently highlighted code or open file" diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx index acaca9ce..5901c5d8 100644 --- a/extension/react-app/src/components/HeaderButtonWithText.tsx +++ b/extension/react-app/src/components/HeaderButtonWithText.tsx @@ -6,12 +6,14 @@ interface HeaderButtonWithTextProps { text: string; onClick?: (e: any) => void; children: React.ReactNode; + disabled?: boolean; } const HeaderButtonWithText = (props: HeaderButtonWithTextProps) => { const [hover, setHover] = useState(false); return ( setHover(true)} onMouseLeave={() => { diff --git a/extension/react-app/src/components/StepContainer.tsx b/extension/react-app/src/components/StepContainer.tsx index 74a1c4e8..827d2d5f 100644 --- a/extension/react-app/src/components/StepContainer.tsx +++ b/extension/react-app/src/components/StepContainer.tsx @@ -200,6 +200,7 @@ function StepContainer(props: StepContainerProps) { <> { e.stopPropagation(); props.onDelete(); -- cgit v1.2.3-70-g09d2 From 2d37d2bd1ee8022aa4eb5db1285c50feced14771 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 25 Jun 2023 14:19:07 -0700 Subject: run locally without interference --- extension/src/activation/activate.ts | 12 ++++++------ extension/src/activation/environmentSetup.ts | 2 +- extension/src/extension.ts | 3 +-- 3 files changed, 8 insertions(+), 9 deletions(-) (limited to 'extension') diff --git a/extension/src/activation/activate.ts b/extension/src/activation/activate.ts index c4bdbaa9..0c92f095 100644 --- a/extension/src/activation/activate.ts +++ b/extension/src/activation/activate.ts @@ -7,24 +7,26 @@ import IdeProtocolClient from "../continueIdeClient"; import { getContinueServerUrl } from "../bridge"; import { CapturedTerminal } from "../terminal/terminalEmulator"; import { setupDebugPanel, ContinueGUIWebviewViewProvider } from "../debugPanel"; +import { startContinuePythonServer } from "./environmentSetup"; // import { CapturedTerminal } from "../terminal/terminalEmulator"; export let extensionContext: vscode.ExtensionContext | undefined = undefined; export let ideProtocolClient: IdeProtocolClient; -export function activateExtension( +export async function activateExtension( context: vscode.ExtensionContext, showTutorial: boolean ) { - sendTelemetryEvent(TelemetryEvent.ExtensionActivated); + extensionContext = context; + sendTelemetryEvent(TelemetryEvent.ExtensionActivated); registerAllCodeLensProviders(context); registerAllCommands(context); // vscode.window.registerWebviewViewProvider("continue.continueGUIView", setupDebugPanel); - - let serverUrl = getContinueServerUrl(); + await startContinuePythonServer(); + const serverUrl = getContinueServerUrl(); ideProtocolClient = new IdeProtocolClient( `${serverUrl.replace("http", "ws")}/ide/ws`, @@ -52,6 +54,4 @@ export function activateExtension( // If any terminals are open to start, replace them // vscode.window.terminals.forEach((terminal) => {} - - extensionContext = context; } diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 593b727e..54c263bd 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -180,7 +180,7 @@ export async function startContinuePythonServer() { await setupPythonEnv(); // Check vscode settings - let serverUrl = getContinueServerUrl(); + const serverUrl = getContinueServerUrl(); if (serverUrl !== "http://localhost:8000") { return; } diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 88af0d19..de8f55e3 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -13,7 +13,7 @@ async function dynamicImportAndActivate( showTutorial: boolean ) { const { activateExtension } = await import("./activation/activate"); - activateExtension(context, showTutorial); + await activateExtension(context, showTutorial); } export function activate(context: vscode.ExtensionContext) { @@ -25,7 +25,6 @@ export function activate(context: vscode.ExtensionContext) { cancellable: false, }, async () => { - await startContinuePythonServer(); dynamicImportAndActivate(context, true); } ); -- cgit v1.2.3-70-g09d2 From 3338d05db9f5f21d8a9d440cb428f2c6a188b363 Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 25 Jun 2023 15:14:56 -0700 Subject: shipped function calling --- continuedev/src/continuedev/core/autopilot.py | 14 ++++++++- continuedev/src/continuedev/steps/chat.py | 33 +++++++++++---------- extension/package-lock.json | 4 +-- extension/package.json | 2 +- .../src/components/HeaderButtonWithText.tsx | 6 +++- extension/react-app/src/tabs/gui.tsx | 2 -- .../scripts/continuedev-0.1.1-py3-none-any.whl | Bin 86716 -> 89177 bytes 7 files changed, 39 insertions(+), 22 deletions(-) (limited to 'extension') diff --git a/continuedev/src/continuedev/core/autopilot.py b/continuedev/src/continuedev/core/autopilot.py index f14a4127..04f64ed8 100644 --- a/continuedev/src/continuedev/core/autopilot.py +++ b/continuedev/src/continuedev/core/autopilot.py @@ -15,6 +15,17 @@ from .sdk import ContinueSDK import asyncio from ..libs.util.step_name_to_steps import get_step_from_name from ..libs.util.traceback_parsers import get_python_traceback, get_javascript_traceback +from openai import error as openai_errors + + +def get_error_title(e: Exception) -> str: + if isinstance(e, openai_errors.APIError): + return "OpenAI is overloaded with requests. Please try again." + elif isinstance(e, openai_errors.RateLimitError): + return "This OpenAI API key has been rate limited. Please try again." + elif isinstance(e, openai_errors.Timeout): + return "OpenAI timed out. Please try again." + return e.__repr__() class Autopilot(ContinueBaseModel): @@ -166,7 +177,8 @@ class Autopilot(ContinueBaseModel): error_string = e.message if is_continue_custom_exception else '\n\n'.join( traceback.format_tb(e.__traceback__)) + f"\n\n{e.__repr__()}" - error_title = e.title if is_continue_custom_exception else e.__repr__() + error_title = e.title if is_continue_custom_exception else get_error_title( + e) # Attach an InternalErrorObservation to the step and unhide it. print(f"Error while running step: \n{error_string}\n{error_title}") diff --git a/continuedev/src/continuedev/steps/chat.py b/continuedev/src/continuedev/steps/chat.py index a940c3ba..2a8ae2da 100644 --- a/continuedev/src/continuedev/steps/chat.py +++ b/continuedev/src/continuedev/steps/chat.py @@ -182,21 +182,24 @@ class ChatWithFunctions(Step): else: if func_name == "python" and "python" not in step_name_step_class_map: # GPT must be fine-tuned to believe this exists, but it doesn't always - self.chat_context.append(ChatMessage( - role="assistant", - content=None, - function_call=FunctionCall( - name=func_name, - arguments=func_args - ), - summary=f"Ran function {func_name}" - )) - self.chat_context.append(ChatMessage( - role="user", - content="The 'python' function does not exist. Don't call it.", - summary="'python' function does not exist." - )) - continue + func_name = "EditHighlightedCodeStep" + func_args = json.dumps({"user_input": self.user_input}) + # self.chat_context.append(ChatMessage( + # role="assistant", + # content=None, + # function_call=FunctionCall( + # name=func_name, + # arguments=func_args + # ), + # summary=f"Ran function {func_name}" + # )) + # self.chat_context.append(ChatMessage( + # role="user", + # content="The 'python' function does not exist. Don't call it. Try again to call another function.", + # summary="'python' function does not exist." + # )) + # msg_step.hide = True + # continue # Call the function, then continue to chat func_args = "{}" if func_args == "" else func_args fn_call_params = json.loads(func_args) diff --git a/extension/package-lock.json b/extension/package-lock.json index 12b2fe13..71edfe8c 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "continue", - "version": "0.0.61", + "version": "0.0.62", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "continue", - "version": "0.0.61", + "version": "0.0.62", "license": "Apache-2.0", "dependencies": { "@electron/rebuild": "^3.2.10", diff --git a/extension/package.json b/extension/package.json index 9fd1d7a6..9679b159 100644 --- a/extension/package.json +++ b/extension/package.json @@ -14,7 +14,7 @@ "displayName": "Continue", "pricing": "Free", "description": "Accelerating software development with language models", - "version": "0.0.61", + "version": "0.0.62", "publisher": "Continue", "engines": { "vscode": "^1.74.0" diff --git a/extension/react-app/src/components/HeaderButtonWithText.tsx b/extension/react-app/src/components/HeaderButtonWithText.tsx index 5901c5d8..30931f86 100644 --- a/extension/react-app/src/components/HeaderButtonWithText.tsx +++ b/extension/react-app/src/components/HeaderButtonWithText.tsx @@ -15,7 +15,11 @@ const HeaderButtonWithText = (props: HeaderButtonWithTextProps) => { setHover(true)} + onMouseEnter={() => { + if (!props.disabled) { + setHover(true); + } + }} onMouseLeave={() => { setHover(false); }} diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index 5001fe4b..4886bfad 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -491,8 +491,6 @@ function GUI(props: GUIProps) { { client?.sendClear(); - // Reload the window to get completely fresh session - window.location.reload(); }} text="Clear All" > diff --git a/extension/scripts/continuedev-0.1.1-py3-none-any.whl b/extension/scripts/continuedev-0.1.1-py3-none-any.whl index 29e41d3c..692bdfb7 100644 Binary files a/extension/scripts/continuedev-0.1.1-py3-none-any.whl and b/extension/scripts/continuedev-0.1.1-py3-none-any.whl differ -- cgit v1.2.3-70-g09d2 From cc96a49bc576bd25ccf338108d29540df3204de3 Mon Sep 17 00:00:00 2001 From: Ty Dunn Date: Sun, 25 Jun 2023 21:33:01 -0700 Subject: && -> ; --- extension/src/activation/environmentSetup.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'extension') diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 54c263bd..66e1c722 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -121,7 +121,7 @@ async function setupPythonEnv() { activateCmd, pipUpgradeCmd, `${pipCmd} install -r requirements.txt`, - ].join(" && "); + ].join(" ; "); const [, stderr] = await runCommand(installRequirementsCommand); if (stderr) { throw new Error(stderr); @@ -199,7 +199,7 @@ export async function startContinuePythonServer() { let command = `cd ${path.join( getExtensionUri().fsPath, "scripts" - )} && ${activateCmd} && cd .. && ${pythonCmd} -m scripts.run_continue_server`; + )} ; ${activateCmd} ; cd .. ; ${pythonCmd} -m scripts.run_continue_server`; return new Promise(async (resolve, reject) => { try { @@ -255,10 +255,10 @@ export async function downloadPython3() { throw new Error("python3 not found"); } else if (os === "linux") { command = - "sudo apt update && upgrade && sudo apt install python3 python3-pip"; + "sudo apt update ; upgrade ; sudo apt install python3 python3-pip"; } else if (os === "win32") { command = - "wget -O python_installer.exe https://www.python.org/ftp/python/3.11.3/python-3.11.3-amd64.exe && python_installer.exe /quiet InstallAllUsers=1 PrependPath=1 Include_test=0"; + "wget -O python_installer.exe https://www.python.org/ftp/python/3.11.3/python-3.11.3-amd64.exe ; python_installer.exe /quiet InstallAllUsers=1 PrependPath=1 Include_test=0"; pythonCmd = "python"; } -- cgit v1.2.3-70-g09d2 From 21dc98bb603f6d7cb18a3c3795a18f3070f0254a Mon Sep 17 00:00:00 2001 From: Nate Sesti Date: Sun, 25 Jun 2023 21:35:53 -0700 Subject: loading cover page (hidden) --- extension/react-app/public/continue.gif | Bin 0 -> 5242 bytes .../react-app/src/components/LoadingCover.tsx | 50 +++++++++++++++++++++ extension/react-app/src/tabs/gui.tsx | 2 + 3 files changed, 52 insertions(+) create mode 100644 extension/react-app/public/continue.gif create mode 100644 extension/react-app/src/components/LoadingCover.tsx (limited to 'extension') diff --git a/extension/react-app/public/continue.gif b/extension/react-app/public/continue.gif new file mode 100644 index 00000000..daed6663 Binary files /dev/null and b/extension/react-app/public/continue.gif differ diff --git a/extension/react-app/src/components/LoadingCover.tsx b/extension/react-app/src/components/LoadingCover.tsx new file mode 100644 index 00000000..a0f8f7a2 --- /dev/null +++ b/extension/react-app/src/components/LoadingCover.tsx @@ -0,0 +1,50 @@ +import React from "react"; +import styled from "styled-components"; + +const StyledDiv = styled.div` + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100vh; + background: linear-gradient( + 101.79deg, + #12887a 0%, + #87245c 32%, + #e12637 63%, + #ffb215 100% + ); + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + z-index: 10; +`; + +const StyledImg = styled.img` + /* add your styles here */ +`; + +const StyledDiv2 = styled.div` + width: 50%; + height: 5px; + background: white; + margin-top: 20px; +`; + +interface LoadingCoverProps { + message: string; + hidden?: boolean; +} + +const LoadingCover = (props: LoadingCoverProps) => { + return ( + + + +

{props.message}

+
+ ); +}; + +export default LoadingCover; diff --git a/extension/react-app/src/tabs/gui.tsx b/extension/react-app/src/tabs/gui.tsx index 4886bfad..445d5700 100644 --- a/extension/react-app/src/tabs/gui.tsx +++ b/extension/react-app/src/tabs/gui.tsx @@ -18,6 +18,7 @@ import ReactSwitch from "react-switch"; import { usePostHog } from "posthog-js/react"; import { useSelector } from "react-redux"; import { RootStore } from "../redux/store"; +import LoadingCover from "../components/LoadingCover"; const TopGUIDiv = styled.div` overflow: hidden; @@ -328,6 +329,7 @@ function GUI(props: GUIProps) { // const iterations = useSelector(selectIterations); return ( <> +