From df659b200057401d64e1b03a6997d31f51cec457 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Thu, 25 Jul 2024 15:43:19 +0200 Subject: [PATCH 1/9] feat: Support AI APIs using Box Node SDK --- package-lock.json | 172 ++++++++---------- package.json | 4 +- src/commands/ai/ask.js | 82 +++++++++ src/commands/ai/text-gen.js | 101 ++++++++++ test/commands/ai.test.js | 143 +++++++++++++++ test/fixtures/ai/post_ai_ask_response.json | 5 + .../fixtures/ai/post_ai_ask_response_yaml.txt | 3 + .../ai/post_ai_text_gen_response.json | 5 + .../ai/post_ai_text_gen_response_yaml.txt | 3 + 9 files changed, 422 insertions(+), 96 deletions(-) create mode 100644 src/commands/ai/ask.js create mode 100644 src/commands/ai/text-gen.js create mode 100644 test/commands/ai.test.js create mode 100644 test/fixtures/ai/post_ai_ask_response.json create mode 100644 test/fixtures/ai/post_ai_ask_response_yaml.txt create mode 100644 test/fixtures/ai/post_ai_text_gen_response.json create mode 100644 test/fixtures/ai/post_ai_text_gen_response_yaml.txt diff --git a/package-lock.json b/package-lock.json index 0ba7eabe..4b979482 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1363,9 +1363,9 @@ }, "dependencies": { "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" } } }, @@ -1394,9 +1394,9 @@ "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" }, "aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.0.tgz", + "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==" }, "babel-code-frame": { "version": "6.26.0", @@ -1462,9 +1462,9 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "basic-ftp": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz", - "integrity": "sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==" + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==" }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -1543,9 +1543,9 @@ } }, "box-node-sdk": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/box-node-sdk/-/box-node-sdk-3.5.0.tgz", - "integrity": "sha512-r/EBaGsxWlI49UCMERBgDkEFmDIazVtUPvHoNlYwxL57vM46p7EmtpwcKiI1JfrsUHhGZwxkdhOL8UFgyG03oA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/box-node-sdk/-/box-node-sdk-3.7.0.tgz", + "integrity": "sha512-v+x4hzR5h7mA2baaBkC95KC1RAmnUyf9Y7Io+cySCHOuOgSN+PI05BVOoYjiIrpKJI9yvnpSiG9n+DcsaHB5qA==", "requires": { "@cypress/request": "^3.0.1", "@types/bluebird": "^3.5.35", @@ -1562,9 +1562,9 @@ }, "dependencies": { "@types/node": { - "version": "18.19.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.17.tgz", - "integrity": "sha512-SzyGKgwPzuWp2SHhlpXKzCX0pIOfcI4V2eF37nNBJOhwlegQ83omtVQ1XxZpDE06V/d6AQvfQdPfnw0tRC//Ng==", + "version": "18.19.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.42.tgz", + "integrity": "sha512-d2ZFc/3lnK2YCYhos8iaNIYu9Vfhr92nHiyJHRltXWjXUBjEE+A4I58Tdbnw4VhggSW+2j5y5gTrLs4biNnubg==", "requires": { "undici-types": "~5.26.4" } @@ -1592,12 +1592,9 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==" } } }, @@ -4226,9 +4223,9 @@ } }, "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" }, "has-symbols": { "version": "1.0.0", @@ -4267,9 +4264,9 @@ } }, "hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "requires": { "function-bind": "^1.1.2" }, @@ -4358,9 +4355,9 @@ }, "dependencies": { "agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "requires": { "debug": "^4.3.4" } @@ -4378,9 +4375,9 @@ } }, "http-status": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-status/-/http-status-1.7.3.tgz", - "integrity": "sha512-GS8tL1qHT2nBCMJDYMHGkkkKQLNkIAHz37vgO68XKvzv+XyqB4oh/DfmMHdtRzfqSJPj1xKG2TaELZtlCz6BEQ==" + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/http-status/-/http-status-1.7.4.tgz", + "integrity": "sha512-c2qSwNtTlHVYAhMj9JpGdyo0No/+DiKXCJ9pHtZ2Yf3QmPnBIytKSRT7BuyIiQ7icXLynavGmxUqkOjSrAuMuA==" }, "https-proxy-agent": { "version": "5.0.0", @@ -5415,12 +5412,9 @@ } }, "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" }, "make-dir": { "version": "3.1.0", @@ -6482,9 +6476,9 @@ "dev": true }, "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" }, "object-keys": { "version": "1.0.12", @@ -6734,32 +6728,32 @@ "dev": true }, "pac-proxy-agent": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", - "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", "requires": { "@tootallnate/quickjs-emscripten": "^0.23.0", "agent-base": "^7.0.2", "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", - "pac-resolver": "^7.0.0", - "socks-proxy-agent": "^8.0.2" + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" }, "dependencies": { "agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "requires": { "debug": "^4.3.4" } }, "https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "requires": { "agent-base": "^7.0.2", "debug": "4" @@ -7624,26 +7618,21 @@ }, "dependencies": { "agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "requires": { "debug": "^4.3.4" } }, "https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "requires": { "agent-base": "^7.0.2", "debug": "4" } - }, - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" } } }, @@ -8109,16 +8098,16 @@ "dev": true }, "set-function-length": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", - "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "requires": { - "define-data-property": "^1.1.2", + "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" }, "dependencies": { "function-bind": { @@ -8147,11 +8136,11 @@ "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" }, "side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "requires": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -8247,28 +8236,28 @@ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" }, "socks": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.3.tgz", - "integrity": "sha512-vfuYK48HXCTFD03G/1/zkIls3Ebr2YNa4qU9gHDZdblHLiqhJrJGkY3+0Nx0JpN9qBhJbVObc1CNciT1bIZJxw==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "requires": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" } }, "socks-proxy-agent": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", - "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", "requires": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.1", "debug": "^4.3.4", - "socks": "^2.7.1" + "socks": "^2.8.3" }, "dependencies": { "agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "requires": { "debug": "^4.3.4" } @@ -8887,9 +8876,9 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", "requires": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -9233,11 +9222,6 @@ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/package.json b/package.json index 9de30de2..317bd506 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@oclif/plugin-help": "^2.2.1", "@oclif/plugin-not-found": "^1.2.0", "archiver": "^3.0.0", - "box-node-sdk": "^3.5.0", + "box-node-sdk": "^3.7.0", "chalk": "^2.4.1", "cli-progress": "^2.1.0", "csv": "^6.3.3", @@ -132,7 +132,7 @@ "scripts": "./src/**/*.js" }, "scripts": { - "test": "nyc mocha \"test/**/*.test.js\"", + "test": "nyc mocha /Users/mcong/Downloads/boxcli/test/commands/ai.test.js", "posttest": "npm run lint", "lint": "eslint --fix ./src ./test", "prepack": "oclif-dev manifest && oclif-dev readme --multi && npm shrinkwrap && git checkout origin/main -- package-lock.json", diff --git a/src/commands/ai/ask.js b/src/commands/ai/ask.js new file mode 100644 index 00000000..1d092edc --- /dev/null +++ b/src/commands/ai/ask.js @@ -0,0 +1,82 @@ +'use strict'; + +const BoxCommand = require('../../box-command'); +const { flags } = require('@oclif/command'); + +class AiAskCommand extends BoxCommand { + async run() { + const { flags, args } = this.parse(AiAskCommand); + let options = {}; + + if (flags.mode) { + options.mode = flags.mode; + } else { + options.mode = flags.items.length > 1 ? 'multi_item_qa' : 'single_item_qa'; + } + if (flags.prompt) { + options.prompt = flags.prompt; + } + if (flags.items) { + options.items = flags.items; + } + + let answer = await this.client.ai.ask({ + prompt: options.prompt, + items: options.items, + mode: options.mode + }); + await this.output(answer); + } +} + +AiAskCommand.description = 'Sends an AI request to supported LLMs and returns an answer'; +AiAskCommand.examples = ['box ai:ask --mode single_item_qa --items=id=12345,type=file --prompt "What is the status of this document?"']; +AiAskCommand._endpoint = 'post_ai_ask'; + +AiAskCommand.flags = { + ...BoxCommand.flags, + mode: flags.string({ + required: false, + description: 'The mode of the AI request, should be \'single_item_qa\' for one item or \'multi_item_qa\' for multiple items', + }), + prompt: flags.string({ + required: true, + description: 'The prompt for the AI request', + }), + items: flags.string({ + required: true, + description: 'The items for the AI request', + multiple: true, + parse(input) { + const item = { + id: '', + type: 'file' + }; + + for (const part of input.split(',')) { + const [ + key, + value, + ] = part.split('='); + + switch (key) { + case 'id': + item.id = value; + break; + case 'type': + item.type = value; + break; + case 'content': + item.content = value; + break; + default: + throw new Error(`Invalid item key ${key}`); + } + } + + return item; + } + }), +}; + +module.exports = AiAskCommand; diff --git a/src/commands/ai/text-gen.js b/src/commands/ai/text-gen.js new file mode 100644 index 00000000..fe3baff5 --- /dev/null +++ b/src/commands/ai/text-gen.js @@ -0,0 +1,101 @@ +'use strict'; + +const BoxCommand = require('../../box-command'); +const { flags } = require('@oclif/command'); + +class AiTextGenCommand extends BoxCommand { + async run() { + const { flags, args } = this.parse(AiTextGenCommand); + let options = {}; + + if (flags.dialogue_history) { + options.dialogueHistory = flags.dialogue_history; + } + options.prompt = flags.prompt; + options.items = flags.items; + let answer = await this.client.ai.textGen({ + prompt: options.prompt, + items: options.items, + dialogue_history: options.dialogueHistory, + }); + + await this.output(answer); + } +} + +AiTextGenCommand.description = 'Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text.'; +AiTextGenCommand.examples = ['box ai:text-gen --dialogue_history=prompt="What is the status of this document?",answer="It is in review" --items=id=12345,type=file --prompt="What is the status of this document?"']; +AiTextGenCommand._endpoint = 'post_ai_text_gen'; + +AiTextGenCommand.flags = { + ...BoxCommand.flags, + dialogue_history: flags.string({ + required: false, + description: 'The history of prompts and answers previously passed to the LLM.', + multiple: true, + parse(input) { + const record = {}; + for (const part of input.split(',')) { + const [ + key, + value, + ] = part.split('='); + + switch (key) { + case 'prompt': + record.prompt = value; + break; + case 'answer': + record.answer = value; + break; + case 'created_at': + case 'createdAt': + record.created_at = value; + break; + default: + throw new Error(`Invalid record key: ${key}`); + } + } + + return record; + }, + }), + items: flags.string({ + required: true, + description: 'The items to be processed by the LLM, often files. The array can include exactly one element.', + multiple: true, + parse(input) { + const item = { + id: '', + type: 'file' + }; + for (const part of input.split(',')) { + const [ + key, + value, + ] = part.split('='); + + switch (key) { + case 'id': + item.id = value; + break; + case 'type': + item.type = value; + break; + case 'content': + item.content = value; + break; + default: + throw new Error(`Invalid item key ${key}`); + } + } + return item; + } + }), + prompt: flags.string({ + required: true, + description: 'The prompt for the AI request', + }) +}; + +module.exports = AiTextGenCommand; diff --git a/test/commands/ai.test.js b/test/commands/ai.test.js new file mode 100644 index 00000000..d672908b --- /dev/null +++ b/test/commands/ai.test.js @@ -0,0 +1,143 @@ +'use strict'; + +const { test } = require('@oclif/test'); +const assert = require('chai').assert; +const { TEST_API_ROOT, getFixture } = require('../helpers/test-helper'); + +describe('AI', () => { + describe('ai:ask', () => { + const expectedRequestBody = { + items: [ + { + id: '12345', + type: 'file', + }, + ], + mode: 'single_item_qa', + prompt: 'What is the status of this document?', + }; + const expectedResponseBody = { + answer: + 'This document is currently in progress and being actively worked on.', + created_at: '2024-07-09T11:29:46.835Z', + completion_reason: 'done', + }; + const fixture = getFixture('ai/post_ai_ask_response'); + const yamlFixture = getFixture('ai/post_ai_ask_response_yaml.txt'); + + test + .nock(TEST_API_ROOT, (api) => + api + .post('/2.0/ai/ask', expectedRequestBody) + .reply(200, expectedResponseBody) + ) + .stdout() + .command([ + 'ai:ask', + '--items=id=12345,type=file', + '--prompt', + 'What is the status of this document?', + '--mode', + 'single_item_qa', + '--json', + '--token=test', + ]) + .it( + 'should send the correct request and output the response (JSON Output)', + (ctx) => { + assert.equal(ctx.stdout, fixture); + } + ); + + test + .nock(TEST_API_ROOT, (api) => + api + .post('/2.0/ai/ask', expectedRequestBody) + .reply(200, expectedResponseBody) + ) + .stdout() + .command([ + 'ai:ask', + '--items=id=12345,type=file', + '--prompt', + 'What is the status of this document?', + '--mode', + 'single_item_qa', + '--token=test', + ]) + .it( + 'should send the correct request and output the response (YAML Output)', + (ctx) => { + assert.equal(ctx.stdout, yamlFixture); + } + ); + }); + + describe('ai:text-gen', () => { + const expectedRequestBody = { + prompt: 'What is the status of this document?', + items: [{ id: '12345', type: 'file' }], + dialogue_history: [ + { + prompt: 'What is the status of this document?', + answer: 'It is in review', + created_at: '2024-07-09T11:29:46.835Z' + }, + ], + }; + const expectedResponseBody = { + answer: 'The document is currently in review and awaiting approval.', + created_at: '2024-07-09T11:29:46.835Z', + completion_reason: 'done', + }; + const fixture = getFixture('ai/post_ai_text_gen_response'); + const yamlFixture = getFixture('ai/post_ai_text_gen_response_yaml.txt'); + + test + .nock(TEST_API_ROOT, (api) => + api + .post('/2.0/ai/text_gen', expectedRequestBody) + .reply(200, expectedResponseBody) + ) + .stdout() + .command([ + 'ai:text-gen', + '--dialogue_history', + 'prompt=What is the status of this document?,answer=It is in review,created_at=2024-07-09T11:29:46.835Z', + '--items=id=12345,type=file', + '--prompt', + 'What is the status of this document?', + '--json', + '--token=test', + ]) + .it( + 'should send the correct request and output the response (JSON Output)', + (ctx) => { + assert.equal(ctx.stdout, fixture); + } + ); + + test + .nock(TEST_API_ROOT, (api) => + api + .post('/2.0/ai/text_gen', expectedRequestBody) + .reply(200, expectedResponseBody) + ) + .stdout() + .command([ + 'ai:text-gen', + '--dialogue_history', + 'prompt=What is the status of this document?,answer=It is in review,created_at=2024-07-09T11:29:46.835Z', + '--items=id=12345,type=file', + '--prompt', + 'What is the status of this document?', + '--token=test', + ]) + .it( + 'should send the correct request and output the response (YAML Output)', + (ctx) => { + assert.equal(ctx.stdout, yamlFixture); + } + ); + }); +}); diff --git a/test/fixtures/ai/post_ai_ask_response.json b/test/fixtures/ai/post_ai_ask_response.json new file mode 100644 index 00000000..72dee510 --- /dev/null +++ b/test/fixtures/ai/post_ai_ask_response.json @@ -0,0 +1,5 @@ +{ + "answer": "This document is currently in progress and being actively worked on.", + "created_at": "2024-07-09T11:29:46.835Z", + "completion_reason": "done" +} diff --git a/test/fixtures/ai/post_ai_ask_response_yaml.txt b/test/fixtures/ai/post_ai_ask_response_yaml.txt new file mode 100644 index 00000000..b8f06251 --- /dev/null +++ b/test/fixtures/ai/post_ai_ask_response_yaml.txt @@ -0,0 +1,3 @@ +Answer: This document is currently in progress and being actively worked on. +Created At: '2024-07-09T11:29:46.835Z' +Completion Reason: done diff --git a/test/fixtures/ai/post_ai_text_gen_response.json b/test/fixtures/ai/post_ai_text_gen_response.json new file mode 100644 index 00000000..7c2c2a3f --- /dev/null +++ b/test/fixtures/ai/post_ai_text_gen_response.json @@ -0,0 +1,5 @@ +{ + "answer": "The document is currently in review and awaiting approval.", + "created_at": "2024-07-09T11:29:46.835Z", + "completion_reason": "done" +} diff --git a/test/fixtures/ai/post_ai_text_gen_response_yaml.txt b/test/fixtures/ai/post_ai_text_gen_response_yaml.txt new file mode 100644 index 00000000..9a90e4f3 --- /dev/null +++ b/test/fixtures/ai/post_ai_text_gen_response_yaml.txt @@ -0,0 +1,3 @@ +Answer: The document is currently in review and awaiting approval. +Created At: '2024-07-09T11:29:46.835Z' +Completion Reason: done From 1f9db0f518117eec778672f40890edb6ce0ab033 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Thu, 25 Jul 2024 15:44:36 +0200 Subject: [PATCH 2/9] Update docs --- README.md | 1 + docs/ai.md | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 docs/ai.md diff --git a/README.md b/README.md index 6ee89555..f8500d18 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ Avatar URL: 'https://app.box.com/api/avatar/large/77777' # Command Topics +* [`box ai`](docs/ai.md) - Sends an AI request to supported LLMs and returns an answer * [`box autocomplete`](docs/autocomplete.md) - Display autocomplete installation instructions * [`box collaboration-allowlist`](docs/collaboration-allowlist.md) - List collaboration allowlist entries * [`box collaborations`](docs/collaborations.md) - Manage collaborations diff --git a/docs/ai.md b/docs/ai.md new file mode 100644 index 00000000..d3229328 --- /dev/null +++ b/docs/ai.md @@ -0,0 +1,83 @@ +`box ai` +======== + +Sends an AI request to supported LLMs and returns an answer + +* [`box ai:ask`](#box-aiask) +* [`box ai:text-gen`](#box-aitext-gen) + +## `box ai:ask` + +Sends an AI request to supported LLMs and returns an answer + +``` +USAGE + $ box ai:ask + +OPTIONS + -h, --help Show CLI help + -q, --quiet Suppress any non-error output to stderr + -s, --save Save report to default reports folder on disk + -t, --token=token Provide a token to perform this call + -v, --verbose Show verbose output, which can be helpful for debugging + -y, --yes Automatically respond yes to all confirmation prompts + --as-user=as-user Provide an ID for a user + --bulk-file-path=bulk-file-path File path to bulk .csv or .json objects + --csv Output formatted CSV + --fields=fields Comma separated list of fields to show + --items=items (required) The items for the AI request + --json Output formatted JSON + + --mode=mode The mode of the AI request, should be 'single_item_qa' for one item or + 'multi_item_qa' for multiple items + + --no-color Turn off colors for logging + + --prompt=prompt (required) The prompt for the AI request + + --save-to-file-path=save-to-file-path Override default file path to save report + +EXAMPLE + box ai:ask --mode single_item_qa --items=id=12345,type=file --prompt "What is the status of this document?" +``` + +_See code: [src/commands/ai/ask.js](https://github.com/box/boxcli/blob/v3.14.1/src/commands/ai/ask.js)_ + +## `box ai:text-gen` + +Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text. + +``` +USAGE + $ box ai:text-gen + +OPTIONS + -h, --help Show CLI help + -q, --quiet Suppress any non-error output to stderr + -s, --save Save report to default reports folder on disk + -t, --token=token Provide a token to perform this call + -v, --verbose Show verbose output, which can be helpful for debugging + -y, --yes Automatically respond yes to all confirmation prompts + --as-user=as-user Provide an ID for a user + --bulk-file-path=bulk-file-path File path to bulk .csv or .json objects + --csv Output formatted CSV + --dialogue_history=dialogue_history The history of prompts and answers previously passed to the LLM. + --fields=fields Comma separated list of fields to show + + --items=items (required) The items to be processed by the LLM, often files. The array can + include exactly one element. + + --json Output formatted JSON + + --no-color Turn off colors for logging + + --prompt=prompt (required) The prompt for the AI request + + --save-to-file-path=save-to-file-path Override default file path to save report + +EXAMPLE + box ai:text-gen --dialogue_history=prompt="What is the status of this document?",answer="It is in review" + --items=id=12345,type=file --prompt="What is the status of this document?" +``` + +_See code: [src/commands/ai/text-gen.js](https://github.com/box/boxcli/blob/v3.14.1/src/commands/ai/text-gen.js)_ From bb70555726cb9417d602cf8f7941beb602fa77cb Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Fri, 26 Jul 2024 10:42:23 +0200 Subject: [PATCH 3/9] Fix --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 317bd506..e7bc4622 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "scripts": "./src/**/*.js" }, "scripts": { - "test": "nyc mocha /Users/mcong/Downloads/boxcli/test/commands/ai.test.js", + "test": "nyc mocha \"test/**/*.test.js\"", "posttest": "npm run lint", "lint": "eslint --fix ./src ./test", "prepack": "oclif-dev manifest && oclif-dev readme --multi && npm shrinkwrap && git checkout origin/main -- package-lock.json", From b9ea3674b6efa064bc063674e57fed5f6d6f9c3f Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Mon, 29 Jul 2024 17:11:04 +0200 Subject: [PATCH 4/9] Update test --- src/commands/ai/ask.js | 30 ++++++----------- src/commands/ai/text-gen.js | 67 ++++++++++++++----------------------- src/util.js | 25 ++++++++++++++ test/commands/ai.test.js | 25 +++++++------- 4 files changed, 75 insertions(+), 72 deletions(-) diff --git a/src/commands/ai/ask.js b/src/commands/ai/ask.js index 1d092edc..a327b61b 100644 --- a/src/commands/ai/ask.js +++ b/src/commands/ai/ask.js @@ -2,6 +2,7 @@ const BoxCommand = require('../../box-command'); const { flags } = require('@oclif/command'); +const utils = require('../../util'); class AiAskCommand extends BoxCommand { async run() { @@ -52,25 +53,16 @@ AiAskCommand.flags = { id: '', type: 'file' }; - - for (const part of input.split(',')) { - const [ - key, - value, - ] = part.split('='); - - switch (key) { - case 'id': - item.id = value; - break; - case 'type': - item.type = value; - break; - case 'content': - item.content = value; - break; - default: - throw new Error(`Invalid item key ${key}`); + const obj = utils.parseStringToObject(input); + for (const key in obj) { + if (key === 'id') { + item.id = obj[key]; + } else if (key === 'type') { + item.type = obj[key]; + } else if (key === 'content') { + item.content = obj[key]; + } else { + throw new Error(`Invalid item key ${key}`); } } diff --git a/src/commands/ai/text-gen.js b/src/commands/ai/text-gen.js index fe3baff5..2673c2bb 100644 --- a/src/commands/ai/text-gen.js +++ b/src/commands/ai/text-gen.js @@ -2,14 +2,15 @@ const BoxCommand = require('../../box-command'); const { flags } = require('@oclif/command'); +const utils = require('../../util'); class AiTextGenCommand extends BoxCommand { async run() { const { flags, args } = this.parse(AiTextGenCommand); let options = {}; - if (flags.dialogue_history) { - options.dialogueHistory = flags.dialogue_history; + if (flags['dialogue-history']) { + options.dialogueHistory = flags['dialogue-history']; } options.prompt = flags.prompt; options.items = flags.items; @@ -24,36 +25,28 @@ class AiTextGenCommand extends BoxCommand { } AiTextGenCommand.description = 'Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text.'; -AiTextGenCommand.examples = ['box ai:text-gen --dialogue_history=prompt="What is the status of this document?",answer="It is in review" --items=id=12345,type=file --prompt="What is the status of this document?"']; +AiTextGenCommand.examples = ['box ai:text-gen --dialogue_history=prompt="What is the status of this document?",answer="It is in review",created-at="2024-07-09T11:29:46.835Z" --items=id=12345,type=file --prompt="What is the status of this document?"']; AiTextGenCommand._endpoint = 'post_ai_text_gen'; AiTextGenCommand.flags = { ...BoxCommand.flags, - dialogue_history: flags.string({ + + 'dialogue-history': flags.string({ required: false, description: 'The history of prompts and answers previously passed to the LLM.', multiple: true, parse(input) { const record = {}; - for (const part of input.split(',')) { - const [ - key, - value, - ] = part.split('='); - - switch (key) { - case 'prompt': - record.prompt = value; - break; - case 'answer': - record.answer = value; - break; - case 'created_at': - case 'createdAt': - record.created_at = value; - break; - default: - throw new Error(`Invalid record key: ${key}`); + const obj = utils.parseStringToObject(input); + for (const key in obj) { + if (key === 'prompt') { + record.prompt = obj[key]; + } else if (key === 'answer') { + record.answer = obj[key]; + } else if (key === 'created-at') { + record.created_at = BoxCommand.normalizeDateString(obj[key]); + } else { + throw new Error(`Invalid record key ${key}`); } } @@ -69,24 +62,16 @@ AiTextGenCommand.flags = { id: '', type: 'file' }; - for (const part of input.split(',')) { - const [ - key, - value, - ] = part.split('='); - - switch (key) { - case 'id': - item.id = value; - break; - case 'type': - item.type = value; - break; - case 'content': - item.content = value; - break; - default: - throw new Error(`Invalid item key ${key}`); + const obj = utils.parseStringToObject(input); + for (const key in obj) { + if (key === 'id') { + item.id = obj[key]; + } else if (key === 'type') { + item.type = obj[key]; + } else if (key === 'content') { + item.content = obj[key]; + } else { + throw new Error(`Invalid item key ${key}`); } } return item; diff --git a/src/util.js b/src/util.js index 2f0a6706..4884726c 100644 --- a/src/util.js +++ b/src/util.js @@ -184,6 +184,30 @@ function parseMetadataString(input) { return op; } +/** + * Parse a string into an JSON object + * + * @param {string} str The string to parse + * @returns {Object} The parsed object + */ +function parseStringToObject(str) { + const obj = {}; + const regex = /([\w-]+)=((?:"[^"]*")|[^,]*)/g; // Regular expression to match key=value pairs, including keys with dashes and quoted values + let match; + + while ((match = regex.exec(str)) !== null) { + const key = match[1].trim(); + let value = match[2].trim(); + // Remove surrounding quotes if present + if (value.startsWith('"') && value.endsWith('"')) { + value = value.slice(1, -1); + } + obj[key] = value; + } + + return obj; +} + /** * Check if directory exists and creates it if shouldCreate flag was passed. * @@ -343,6 +367,7 @@ module.exports = { parseMetadataOp(value) { return parseMetadataString(value); }, + parseStringToObject, checkDir, readFileAsync, writeFileAsync, diff --git a/test/commands/ai.test.js b/test/commands/ai.test.js index d672908b..1f2b07cf 100644 --- a/test/commands/ai.test.js +++ b/test/commands/ai.test.js @@ -11,6 +11,7 @@ describe('AI', () => { { id: '12345', type: 'file', + content: 'one,two,three', }, ], mode: 'single_item_qa', @@ -34,7 +35,7 @@ describe('AI', () => { .stdout() .command([ 'ai:ask', - '--items=id=12345,type=file', + '--items=content="one,two,three",id=12345,type=file', '--prompt', 'What is the status of this document?', '--mode', @@ -58,7 +59,7 @@ describe('AI', () => { .stdout() .command([ 'ai:ask', - '--items=id=12345,type=file', + '--items=content="one,two,three",id=12345,type=file', '--prompt', 'What is the status of this document?', '--mode', @@ -76,12 +77,12 @@ describe('AI', () => { describe('ai:text-gen', () => { const expectedRequestBody = { prompt: 'What is the status of this document?', - items: [{ id: '12345', type: 'file' }], + items: [{ id: '12345', type: 'file', content: 'one,two,three' }], dialogue_history: [ { - prompt: 'What is the status of this document?', - answer: 'It is in review', - created_at: '2024-07-09T11:29:46.835Z' + prompt: 'What is the status of this document, signatures?', + answer: 'It is in review, waiting for signatures.', + created_at: '2024-07-09T11:29:46+00:00' }, ], }; @@ -102,9 +103,9 @@ describe('AI', () => { .stdout() .command([ 'ai:text-gen', - '--dialogue_history', - 'prompt=What is the status of this document?,answer=It is in review,created_at=2024-07-09T11:29:46.835Z', - '--items=id=12345,type=file', + '--dialogue-history', + 'prompt="What is the status of this document, signatures?",answer="It is in review, waiting for signatures.",created-at=2024-07-09T11:29:46.835Z', + '--items=content="one,two,three",id=12345,type=file', '--prompt', 'What is the status of this document?', '--json', @@ -126,9 +127,9 @@ describe('AI', () => { .stdout() .command([ 'ai:text-gen', - '--dialogue_history', - 'prompt=What is the status of this document?,answer=It is in review,created_at=2024-07-09T11:29:46.835Z', - '--items=id=12345,type=file', + '--dialogue-history', + 'prompt="What is the status of this document, signatures?",answer="It is in review, waiting for signatures.",created-at=2024-07-09T11:29:46.835Z', + '--items=content="one,two,three",id=12345,type=file', '--prompt', 'What is the status of this document?', '--token=test', From 7febb2414ec5107f3191869852c924b021da2a38 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Mon, 29 Jul 2024 17:15:39 +0200 Subject: [PATCH 5/9] Update test --- src/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.js b/src/util.js index 4884726c..c556fc50 100644 --- a/src/util.js +++ b/src/util.js @@ -192,7 +192,7 @@ function parseMetadataString(input) { */ function parseStringToObject(str) { const obj = {}; - const regex = /([\w-]+)=((?:"[^"]*")|[^,]*)/g; // Regular expression to match key=value pairs, including keys with dashes and quoted values + const regex = /([\w-]+)=((?:"[^"]*")|[^,]*)/gu; // Regular expression to match key=value pairs, including keys with dashes and quoted values let match; while ((match = regex.exec(str)) !== null) { From 755a59180270b2e949a98ffa375146a4bcd70beb Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Wed, 31 Jul 2024 12:09:03 +0200 Subject: [PATCH 6/9] Update command --- docs/ai.md | 7 +++--- src/commands/ai/ask.js | 2 +- src/commands/ai/text-gen.js | 6 ++--- src/util.js | 50 ++++++++++++++++++++++++------------- test/commands/ai.test.js | 12 ++++----- 5 files changed, 46 insertions(+), 31 deletions(-) diff --git a/docs/ai.md b/docs/ai.md index d3229328..f46e13db 100644 --- a/docs/ai.md +++ b/docs/ai.md @@ -61,7 +61,7 @@ OPTIONS --as-user=as-user Provide an ID for a user --bulk-file-path=bulk-file-path File path to bulk .csv or .json objects --csv Output formatted CSV - --dialogue_history=dialogue_history The history of prompts and answers previously passed to the LLM. + --dialogue-history=dialogue-history The history of prompts and answers previously passed to the LLM. --fields=fields Comma separated list of fields to show --items=items (required) The items to be processed by the LLM, often files. The array can @@ -76,8 +76,9 @@ OPTIONS --save-to-file-path=save-to-file-path Override default file path to save report EXAMPLE - box ai:text-gen --dialogue_history=prompt="What is the status of this document?",answer="It is in review" - --items=id=12345,type=file --prompt="What is the status of this document?" + box ai:text-gen --dialogue_history=prompt="What is the status of this document?",answer="It is in + review",created-at="2024-07-09T11:29:46.835Z" --items=id=12345,type=file --prompt="What is the status of this + document?" ``` _See code: [src/commands/ai/text-gen.js](https://github.com/box/boxcli/blob/v3.14.1/src/commands/ai/text-gen.js)_ diff --git a/src/commands/ai/ask.js b/src/commands/ai/ask.js index a327b61b..cd3bf199 100644 --- a/src/commands/ai/ask.js +++ b/src/commands/ai/ask.js @@ -53,7 +53,7 @@ AiAskCommand.flags = { id: '', type: 'file' }; - const obj = utils.parseStringToObject(input); + const obj = utils.parseStringToObject(input, ['id', 'type', 'content']); for (const key in obj) { if (key === 'id') { item.id = obj[key]; diff --git a/src/commands/ai/text-gen.js b/src/commands/ai/text-gen.js index 2673c2bb..c8e97ede 100644 --- a/src/commands/ai/text-gen.js +++ b/src/commands/ai/text-gen.js @@ -25,7 +25,7 @@ class AiTextGenCommand extends BoxCommand { } AiTextGenCommand.description = 'Sends an AI request to supported LLMs and returns an answer specifically focused on the creation of new text.'; -AiTextGenCommand.examples = ['box ai:text-gen --dialogue_history=prompt="What is the status of this document?",answer="It is in review",created-at="2024-07-09T11:29:46.835Z" --items=id=12345,type=file --prompt="What is the status of this document?"']; +AiTextGenCommand.examples = ['box ai:text-gen --dialogue-history=prompt="What is the status of this document?",answer="It is in review",created-at="2024-07-09T11:29:46.835Z" --items=id=12345,type=file --prompt="What is the status of this document?"']; AiTextGenCommand._endpoint = 'post_ai_text_gen'; AiTextGenCommand.flags = { @@ -37,7 +37,7 @@ AiTextGenCommand.flags = { multiple: true, parse(input) { const record = {}; - const obj = utils.parseStringToObject(input); + const obj = utils.parseStringToObject(input, ['prompt', 'answer', 'created-at']); for (const key in obj) { if (key === 'prompt') { record.prompt = obj[key]; @@ -62,7 +62,7 @@ AiTextGenCommand.flags = { id: '', type: 'file' }; - const obj = utils.parseStringToObject(input); + const obj = utils.parseStringToObject(input, ['id', 'type', 'content']); for (const key in obj) { if (key === 'id') { item.id = obj[key]; diff --git a/src/util.js b/src/util.js index c556fc50..80e59dc1 100644 --- a/src/util.js +++ b/src/util.js @@ -185,27 +185,41 @@ function parseMetadataString(input) { } /** - * Parse a string into an JSON object + * Parse a string into a JSON object * - * @param {string} str The string to parse + * @param {string} inputString The string to parse + * @param {string[]} keys The keys to parse from the string * @returns {Object} The parsed object */ -function parseStringToObject(str) { - const obj = {}; - const regex = /([\w-]+)=((?:"[^"]*")|[^,]*)/gu; // Regular expression to match key=value pairs, including keys with dashes and quoted values - let match; - - while ((match = regex.exec(str)) !== null) { - const key = match[1].trim(); - let value = match[2].trim(); - // Remove surrounding quotes if present - if (value.startsWith('"') && value.endsWith('"')) { - value = value.slice(1, -1); - } - obj[key] = value; - } - - return obj; +function parseStringToObject(inputString, keys) { + const result = {}; + + while (inputString.length > 0) { + inputString = inputString.trim(); + let parsedKey = inputString.split('=')[0]; + inputString = inputString.substring(inputString.indexOf('=') + 1); + + // Find the next key or the end of the string + let nextKeyIndex = inputString.length; + for (let key of keys) { + let keyIndex = inputString.indexOf(key); + if (keyIndex !== -1 && keyIndex < nextKeyIndex) { + nextKeyIndex = keyIndex; + } + } + + let parsedValue = inputString.substring(0, nextKeyIndex).trim(); + if (parsedValue.endsWith(',') && nextKeyIndex !== inputString.length) { + parsedValue = parsedValue.substring(0, parsedValue.length - 1); + } + if (parsedValue.startsWith('"') && parsedValue.endsWith('"')) { + parsedValue = parsedValue.substring(1, parsedValue.length - 1); + } + + result[parsedKey] = parsedValue; + inputString = inputString.substring(nextKeyIndex); + } + return result; } /** diff --git a/test/commands/ai.test.js b/test/commands/ai.test.js index 1f2b07cf..2f0708ed 100644 --- a/test/commands/ai.test.js +++ b/test/commands/ai.test.js @@ -35,7 +35,7 @@ describe('AI', () => { .stdout() .command([ 'ai:ask', - '--items=content="one,two,three",id=12345,type=file', + '--items=content=one,two,three,id=12345,type=file', '--prompt', 'What is the status of this document?', '--mode', @@ -59,7 +59,7 @@ describe('AI', () => { .stdout() .command([ 'ai:ask', - '--items=content="one,two,three",id=12345,type=file', + '--items=content=one,two,three,id=12345,type=file', '--prompt', 'What is the status of this document?', '--mode', @@ -104,8 +104,8 @@ describe('AI', () => { .command([ 'ai:text-gen', '--dialogue-history', - 'prompt="What is the status of this document, signatures?",answer="It is in review, waiting for signatures.",created-at=2024-07-09T11:29:46.835Z', - '--items=content="one,two,three",id=12345,type=file', + 'prompt=What is the status of this document, signatures?,answer=It is in review, waiting for signatures.,created-at=2024-07-09T11:29:46.835Z', + '--items=content=one,two,three,id=12345,type=file', '--prompt', 'What is the status of this document?', '--json', @@ -128,8 +128,8 @@ describe('AI', () => { .command([ 'ai:text-gen', '--dialogue-history', - 'prompt="What is the status of this document, signatures?",answer="It is in review, waiting for signatures.",created-at=2024-07-09T11:29:46.835Z', - '--items=content="one,two,three",id=12345,type=file', + 'prompt=What is the status of this document, signatures?,answer=It is in review, waiting for signatures.,created-at=2024-07-09T11:29:46.835Z', + '--items=content=one,two,three,id=12345,type=file', '--prompt', 'What is the status of this document?', '--token=test', From d77e1a3be8cfbaf5e5ad0db47082efb6689ffaa6 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Wed, 31 Jul 2024 12:31:35 +0200 Subject: [PATCH 7/9] Update commands --- src/util.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util.js b/src/util.js index 80e59dc1..0e5bcad0 100644 --- a/src/util.js +++ b/src/util.js @@ -216,6 +216,12 @@ function parseStringToObject(inputString, keys) { parsedValue = parsedValue.substring(1, parsedValue.length - 1); } + if (!keys.includes(parsedKey)) { + throw new BoxCLIError( + `Invalid key '${parsedKey}'. Valid keys are ${keys.join(', ')}` + ); + } + result[parsedKey] = parsedValue; inputString = inputString.substring(nextKeyIndex); } From 19d5d33ee9ba09f76132993c2c6fe93fa5053485 Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Wed, 31 Jul 2024 13:51:29 +0200 Subject: [PATCH 8/9] Update code --- docs/ai.md | 8 +------- src/commands/ai/ask.js | 10 +--------- test/commands/ai.test.js | 4 ---- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/docs/ai.md b/docs/ai.md index f46e13db..f6b87ac4 100644 --- a/docs/ai.md +++ b/docs/ai.md @@ -27,14 +27,8 @@ OPTIONS --fields=fields Comma separated list of fields to show --items=items (required) The items for the AI request --json Output formatted JSON - - --mode=mode The mode of the AI request, should be 'single_item_qa' for one item or - 'multi_item_qa' for multiple items - --no-color Turn off colors for logging - --prompt=prompt (required) The prompt for the AI request - --save-to-file-path=save-to-file-path Override default file path to save report EXAMPLE @@ -76,7 +70,7 @@ OPTIONS --save-to-file-path=save-to-file-path Override default file path to save report EXAMPLE - box ai:text-gen --dialogue_history=prompt="What is the status of this document?",answer="It is in + box ai:text-gen --dialogue-history=prompt="What is the status of this document?",answer="It is in review",created-at="2024-07-09T11:29:46.835Z" --items=id=12345,type=file --prompt="What is the status of this document?" ``` diff --git a/src/commands/ai/ask.js b/src/commands/ai/ask.js index cd3bf199..874f76c4 100644 --- a/src/commands/ai/ask.js +++ b/src/commands/ai/ask.js @@ -8,12 +8,8 @@ class AiAskCommand extends BoxCommand { async run() { const { flags, args } = this.parse(AiAskCommand); let options = {}; + options.mode = flags.items.length > 1 ? 'multi_item_qa' : 'single_item_qa'; - if (flags.mode) { - options.mode = flags.mode; - } else { - options.mode = flags.items.length > 1 ? 'multi_item_qa' : 'single_item_qa'; - } if (flags.prompt) { options.prompt = flags.prompt; } @@ -36,10 +32,6 @@ AiAskCommand._endpoint = 'post_ai_ask'; AiAskCommand.flags = { ...BoxCommand.flags, - mode: flags.string({ - required: false, - description: 'The mode of the AI request, should be \'single_item_qa\' for one item or \'multi_item_qa\' for multiple items', - }), prompt: flags.string({ required: true, description: 'The prompt for the AI request', diff --git a/test/commands/ai.test.js b/test/commands/ai.test.js index 2f0708ed..7dcca14c 100644 --- a/test/commands/ai.test.js +++ b/test/commands/ai.test.js @@ -38,8 +38,6 @@ describe('AI', () => { '--items=content=one,two,three,id=12345,type=file', '--prompt', 'What is the status of this document?', - '--mode', - 'single_item_qa', '--json', '--token=test', ]) @@ -62,8 +60,6 @@ describe('AI', () => { '--items=content=one,two,three,id=12345,type=file', '--prompt', 'What is the status of this document?', - '--mode', - 'single_item_qa', '--token=test', ]) .it( From 8c1b015aab8e9cc0a9085b5624e4cad370485a0e Mon Sep 17 00:00:00 2001 From: Minh Nguyen Cong Date: Wed, 31 Jul 2024 14:42:24 +0200 Subject: [PATCH 9/9] Update docs --- docs/ai.md | 2 +- package-lock.json | 172 ++++++++++++++++++++++------------------- src/commands/ai/ask.js | 2 +- 3 files changed, 96 insertions(+), 80 deletions(-) diff --git a/docs/ai.md b/docs/ai.md index f6b87ac4..0d31bc11 100644 --- a/docs/ai.md +++ b/docs/ai.md @@ -32,7 +32,7 @@ OPTIONS --save-to-file-path=save-to-file-path Override default file path to save report EXAMPLE - box ai:ask --mode single_item_qa --items=id=12345,type=file --prompt "What is the status of this document?" + box ai:ask --items=id=12345,type=file --prompt "What is the status of this document?" ``` _See code: [src/commands/ai/ask.js](https://github.com/box/boxcli/blob/v3.14.1/src/commands/ai/ask.js)_ diff --git a/package-lock.json b/package-lock.json index 4b979482..0ba7eabe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1363,9 +1363,9 @@ }, "dependencies": { "tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" } } }, @@ -1394,9 +1394,9 @@ "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" }, "aws4": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.0.tgz", - "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==" + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" }, "babel-code-frame": { "version": "6.26.0", @@ -1462,9 +1462,9 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "basic-ftp": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", - "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==" + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz", + "integrity": "sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==" }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -1543,9 +1543,9 @@ } }, "box-node-sdk": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/box-node-sdk/-/box-node-sdk-3.7.0.tgz", - "integrity": "sha512-v+x4hzR5h7mA2baaBkC95KC1RAmnUyf9Y7Io+cySCHOuOgSN+PI05BVOoYjiIrpKJI9yvnpSiG9n+DcsaHB5qA==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/box-node-sdk/-/box-node-sdk-3.5.0.tgz", + "integrity": "sha512-r/EBaGsxWlI49UCMERBgDkEFmDIazVtUPvHoNlYwxL57vM46p7EmtpwcKiI1JfrsUHhGZwxkdhOL8UFgyG03oA==", "requires": { "@cypress/request": "^3.0.1", "@types/bluebird": "^3.5.35", @@ -1562,9 +1562,9 @@ }, "dependencies": { "@types/node": { - "version": "18.19.42", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.42.tgz", - "integrity": "sha512-d2ZFc/3lnK2YCYhos8iaNIYu9Vfhr92nHiyJHRltXWjXUBjEE+A4I58Tdbnw4VhggSW+2j5y5gTrLs4biNnubg==", + "version": "18.19.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.17.tgz", + "integrity": "sha512-SzyGKgwPzuWp2SHhlpXKzCX0pIOfcI4V2eF37nNBJOhwlegQ83omtVQ1XxZpDE06V/d6AQvfQdPfnw0tRC//Ng==", "requires": { "undici-types": "~5.26.4" } @@ -1592,9 +1592,12 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==" + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "requires": { + "lru-cache": "^6.0.0" + } } } }, @@ -4223,9 +4226,9 @@ } }, "has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" }, "has-symbols": { "version": "1.0.0", @@ -4264,9 +4267,9 @@ } }, "hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", "requires": { "function-bind": "^1.1.2" }, @@ -4355,9 +4358,9 @@ }, "dependencies": { "agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "requires": { "debug": "^4.3.4" } @@ -4375,9 +4378,9 @@ } }, "http-status": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/http-status/-/http-status-1.7.4.tgz", - "integrity": "sha512-c2qSwNtTlHVYAhMj9JpGdyo0No/+DiKXCJ9pHtZ2Yf3QmPnBIytKSRT7BuyIiQ7icXLynavGmxUqkOjSrAuMuA==" + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-status/-/http-status-1.7.3.tgz", + "integrity": "sha512-GS8tL1qHT2nBCMJDYMHGkkkKQLNkIAHz37vgO68XKvzv+XyqB4oh/DfmMHdtRzfqSJPj1xKG2TaELZtlCz6BEQ==" }, "https-proxy-agent": { "version": "5.0.0", @@ -5412,9 +5415,12 @@ } }, "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } }, "make-dir": { "version": "3.1.0", @@ -6476,9 +6482,9 @@ "dev": true }, "object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" }, "object-keys": { "version": "1.0.12", @@ -6728,32 +6734,32 @@ "dev": true }, "pac-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", - "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", + "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==", "requires": { "@tootallnate/quickjs-emscripten": "^0.23.0", "agent-base": "^7.0.2", "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.5", - "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.4" + "https-proxy-agent": "^7.0.2", + "pac-resolver": "^7.0.0", + "socks-proxy-agent": "^8.0.2" }, "dependencies": { "agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "requires": { "debug": "^4.3.4" } }, "https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "requires": { "agent-base": "^7.0.2", "debug": "4" @@ -7618,21 +7624,26 @@ }, "dependencies": { "agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "requires": { "debug": "^4.3.4" } }, "https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "requires": { "agent-base": "^7.0.2", "debug": "4" } + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" } } }, @@ -8098,16 +8109,16 @@ "dev": true }, "set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", "requires": { - "define-data-property": "^1.1.4", + "define-data-property": "^1.1.2", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", + "get-intrinsic": "^1.2.3", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" + "has-property-descriptors": "^1.0.1" }, "dependencies": { "function-bind": { @@ -8136,11 +8147,11 @@ "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" }, "side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", + "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", "requires": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.6", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -8236,28 +8247,28 @@ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" }, "socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.3.tgz", + "integrity": "sha512-vfuYK48HXCTFD03G/1/zkIls3Ebr2YNa4qU9gHDZdblHLiqhJrJGkY3+0Nx0JpN9qBhJbVObc1CNciT1bIZJxw==", "requires": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" } }, "socks-proxy-agent": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", - "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", + "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", "requires": { - "agent-base": "^7.1.1", + "agent-base": "^7.0.2", "debug": "^4.3.4", - "socks": "^2.8.3" + "socks": "^2.7.1" }, "dependencies": { "agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "requires": { "debug": "^4.3.4" } @@ -8876,9 +8887,9 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "requires": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -9222,6 +9233,11 @@ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/src/commands/ai/ask.js b/src/commands/ai/ask.js index 874f76c4..38e4bfd1 100644 --- a/src/commands/ai/ask.js +++ b/src/commands/ai/ask.js @@ -27,7 +27,7 @@ class AiAskCommand extends BoxCommand { } AiAskCommand.description = 'Sends an AI request to supported LLMs and returns an answer'; -AiAskCommand.examples = ['box ai:ask --mode single_item_qa --items=id=12345,type=file --prompt "What is the status of this document?"']; +AiAskCommand.examples = ['box ai:ask --items=id=12345,type=file --prompt "What is the status of this document?"']; AiAskCommand._endpoint = 'post_ai_ask'; AiAskCommand.flags = {