From 6fdc2154de4d783ef2434e15aaf8c35972d35329 Mon Sep 17 00:00:00 2001 From: Tami Takamiya Date: Mon, 20 Jan 2025 14:42:00 -0500 Subject: [PATCH] Chat UI Streaming Support --- ansible_ai_connect_chatbot/index.html | 1 + ansible_ai_connect_chatbot/package-lock.json | 353 +++++------------- ansible_ai_connect_chatbot/package.json | 6 +- .../src/AnsibleChatbot/AnsibleChatbot.tsx | 8 + ansible_ai_connect_chatbot/src/App.test.tsx | 136 ++++++- ansible_ai_connect_chatbot/src/Clipboard.ts | 2 + ansible_ai_connect_chatbot/src/Constants.ts | 20 +- .../src/types/Message.ts | 13 + .../src/useChatbot/useChatbot.ts | 193 +++++++--- 9 files changed, 415 insertions(+), 317 deletions(-) create mode 100644 ansible_ai_connect_chatbot/src/Clipboard.ts diff --git a/ansible_ai_connect_chatbot/index.html b/ansible_ai_connect_chatbot/index.html index 4e56da4f6..8054204dd 100644 --- a/ansible_ai_connect_chatbot/index.html +++ b/ansible_ai_connect_chatbot/index.html @@ -23,6 +23,7 @@ + diff --git a/ansible_ai_connect_chatbot/package-lock.json b/ansible_ai_connect_chatbot/package-lock.json index 4cbb3e81a..5d77a4029 100644 --- a/ansible_ai_connect_chatbot/package-lock.json +++ b/ansible_ai_connect_chatbot/package-lock.json @@ -8,10 +8,8 @@ "name": "ansible-ai-connect-chatbot", "version": "0.1.0", "dependencies": { + "@microsoft/fetch-event-source": "^2.0.1", "@patternfly/chatbot": "^2.2.0-prerelease.17", - "@testing-library/jest-dom": "^5.17.0", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", "@types/node": "^18.0.0", "@types/react": "^18.3.7", @@ -28,6 +26,8 @@ "devDependencies": { "@eslint/compat": "^1.2.1", "@eslint/js": "^9.13.0", + "@testing-library/react": "^16.2.0", + "@testing-library/user-event": "^14.6.1", "@types/eslint__js": "^8.42.3", "@vitest/browser": "^2.1.8", "@vitest/coverage-v8": "^2.1.2", @@ -51,12 +51,6 @@ "vitest-browser-react": "^0.0.4" } }, - "node_modules/@adobe/css-tools": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.1.tgz", - "integrity": "sha512-12WGKBQzjUAI4ayyF4IAtfw2QR/IDoqk6jTddXDhtYTJF9ASmoE1zst7cVtP0aL/F1jUJL5r+JxKXKEgHNbEUQ==", - "license": "MIT" - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -1218,6 +1212,11 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@microsoft/fetch-event-source": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz", + "integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==" + }, "node_modules/@monaco-editor/loader": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.4.0.tgz", @@ -1736,6 +1735,7 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.10.4", @@ -1751,97 +1751,40 @@ "node": ">=18" } }, - "node_modules/@testing-library/jest-dom": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", - "integrity": "sha512-ynmNeT7asXyH3aSVv4vvX4Rb+0qjOhdNHnO/3vuZNqPmhDpV/+rCSGwQ7bLcmU2cJ4dvoheIO85LQj0IbJHEtg==", - "license": "MIT", - "dependencies": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=8", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@testing-library/react": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", - "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", - "license": "MIT", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.2.0.tgz", + "integrity": "sha512-2cSskAvA1QNtKc8Y9VJQRv0tm3hLVgxRGDB+KYhIaPQJ1I+RHbhIXcM+zClKXzMes/wshsMVzf4B9vS4IZpqDQ==", + "dev": true, "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.5.0", - "@types/react-dom": "^18.0.0" + "@babel/runtime": "^7.12.5" }, "engines": { - "node": ">=12" + "node": ">=18" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@testing-library/react/node_modules/@testing-library/dom": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", - "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@testing-library/react/node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "license": "Apache-2.0", - "dependencies": { - "deep-equal": "^2.0.5" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, "node_modules/@testing-library/user-event": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.5.0.tgz", - "integrity": "sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "dev": true, "engines": { - "node": ">=10", + "node": ">=12", "npm": ">=6" }, "peerDependencies": { @@ -1852,6 +1795,7 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, "license": "MIT" }, "node_modules/@types/babel__core": { @@ -2043,15 +1987,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/testing-library__jest-dom": { - "version": "5.14.9", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", - "integrity": "sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==", - "license": "MIT", - "dependencies": { - "@types/jest": "*" - } - }, "node_modules/@types/tough-cookie": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", @@ -2360,20 +2295,6 @@ } } }, - "node_modules/@vitest/browser/node_modules/@testing-library/user-event": { - "version": "14.5.2", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", - "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, "node_modules/@vitest/coverage-v8": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.8.tgz", @@ -2624,6 +2545,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, "license": "Apache-2.0", "dependencies": { "dequal": "^2.0.3" @@ -2633,6 +2555,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.5", @@ -2831,6 +2754,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -3052,6 +2976,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", @@ -3070,6 +2995,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -3083,6 +3009,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -3384,12 +3311,6 @@ "node": ">= 8" } }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "license": "MIT" - }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -3497,38 +3418,6 @@ "node": ">=6" } }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3540,6 +3429,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -3557,6 +3447,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -3640,6 +3531,7 @@ "version": "0.5.16", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, "license": "MIT" }, "node_modules/dompurify": { @@ -3656,6 +3548,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -3760,6 +3653,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3769,31 +3663,12 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-iterator-helpers": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz", @@ -3832,6 +3707,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -5514,6 +5390,7 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.1.3" @@ -5603,6 +5480,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5632,6 +5510,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5660,6 +5539,7 @@ "version": "1.2.6", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -5823,6 +5703,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5852,6 +5733,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5873,6 +5755,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -5901,6 +5784,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5913,6 +5797,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -5928,6 +5813,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -6155,15 +6041,6 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/inline-style-parser": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", @@ -6174,6 +6051,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -6208,26 +6086,11 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -6261,6 +6124,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, "license": "MIT", "dependencies": { "has-bigints": "^1.0.2" @@ -6276,6 +6140,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz", "integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -6309,6 +6174,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6355,6 +6221,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -6456,6 +6323,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6498,6 +6366,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -6526,6 +6395,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -6544,6 +6414,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6556,6 +6427,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -6571,6 +6443,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -6587,6 +6460,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -6620,6 +6494,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6648,6 +6523,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -6664,6 +6540,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, "license": "MIT" }, "node_modules/isexe": { @@ -6940,12 +6817,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -7009,6 +6880,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, "license": "MIT", "bin": { "lz-string": "bin/bin.js" @@ -7079,6 +6951,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -7974,15 +7847,6 @@ "node": ">= 0.6" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -8150,6 +8014,7 @@ "version": "1.13.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8158,26 +8023,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8187,6 +8037,7 @@ "version": "4.1.7", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -8519,6 +8370,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8855,19 +8707,6 @@ "react": ">= 0.14.0" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "license": "MIT", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/reflect.getprototypeof": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.9.tgz", @@ -9017,6 +8856,7 @@ "version": "1.5.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -9263,6 +9103,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -9679,6 +9520,7 @@ "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==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -9696,6 +9538,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -9734,6 +9577,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -9753,6 +9597,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -9769,6 +9614,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -9787,6 +9633,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -9896,19 +9743,6 @@ "dev": true, "license": "MIT" }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/strict-event-emitter": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", @@ -10149,18 +9983,6 @@ "node": ">=4" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "license": "MIT", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -11044,6 +10866,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, "license": "MIT", "dependencies": { "is-bigint": "^1.1.0", @@ -11091,6 +10914,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, "license": "MIT", "dependencies": { "is-map": "^2.0.3", @@ -11109,6 +10933,7 @@ "version": "1.1.18", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", + "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", diff --git a/ansible_ai_connect_chatbot/package.json b/ansible_ai_connect_chatbot/package.json index d72d3ff7c..df4fdb3dd 100644 --- a/ansible_ai_connect_chatbot/package.json +++ b/ansible_ai_connect_chatbot/package.json @@ -3,10 +3,8 @@ "version": "0.1.0", "private": true, "dependencies": { + "@microsoft/fetch-event-source": "^2.0.1", "@patternfly/chatbot": "^2.2.0-prerelease.17", - "@testing-library/jest-dom": "^5.17.0", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", "@types/node": "^18.0.0", "@types/react": "^18.3.7", @@ -50,6 +48,8 @@ "devDependencies": { "@eslint/compat": "^1.2.1", "@eslint/js": "^9.13.0", + "@testing-library/react": "^16.2.0", + "@testing-library/user-event": "^14.6.1", "@types/eslint__js": "^8.42.3", "@vitest/browser": "^2.1.8", "@vitest/coverage-v8": "^2.1.2", diff --git a/ansible_ai_connect_chatbot/src/AnsibleChatbot/AnsibleChatbot.tsx b/ansible_ai_connect_chatbot/src/AnsibleChatbot/AnsibleChatbot.tsx index e1318028d..1c7541cde 100644 --- a/ansible_ai_connect_chatbot/src/AnsibleChatbot/AnsibleChatbot.tsx +++ b/ansible_ai_connect_chatbot/src/AnsibleChatbot/AnsibleChatbot.tsx @@ -32,6 +32,7 @@ import lightspeedLogoDark from "../assets/lightspeed_dark.svg"; import "./AnsibleChatbot.scss"; import { inDebugMode, + isStreamingSupported, modelsSupported, useChatbot, } from "../useChatbot/useChatbot"; @@ -134,6 +135,8 @@ export const AnsibleChatbot: React.FunctionComponent = () => { setConversationId, systemPrompt, setSystemPrompt, + hasStopButton, + handleStopButton, } = useChatbot(); const [chatbotVisible, setChatbotVisible] = useState(true); const [displayMode, setDisplayMode] = useState( @@ -374,12 +377,17 @@ export const AnsibleChatbot: React.FunctionComponent = () => { ) : ( <> )} + {isStreamingSupported() && ( +
+ )} diff --git a/ansible_ai_connect_chatbot/src/App.test.tsx b/ansible_ai_connect_chatbot/src/App.test.tsx index d8043071e..f35e1f481 100644 --- a/ansible_ai_connect_chatbot/src/App.test.tsx +++ b/ansible_ai_connect_chatbot/src/App.test.tsx @@ -21,16 +21,24 @@ import "@vitest/browser/matchers.d.ts"; const delay = (ms: number) => new Promise((res) => setTimeout(res, ms)); -async function renderApp(debug = false) { +async function renderApp(debug = false, stream = false) { let rootDiv = document.getElementById("root"); rootDiv?.remove(); + let debugDiv = document.getElementById("debug"); debugDiv?.remove(); - debugDiv = document.createElement("div"); debugDiv.setAttribute("id", "debug"); debugDiv.innerText = debug.toString(); document.body.appendChild(debugDiv); + + let streamDiv = document.getElementById("stream"); + streamDiv?.remove(); + streamDiv = document.createElement("div"); + streamDiv.setAttribute("id", "stream"); + streamDiv.innerText = stream.toString(); + document.body.appendChild(streamDiv); + rootDiv = document.createElement("div"); rootDiv.setAttribute("id", "root"); const view = render( @@ -122,8 +130,94 @@ function createError(message: string, status: number): AxiosError { return error; } +function mockFetchEventSource() { + const streamData: object[] = [ + { + event: "start", + data: { conversation_id: "1ec5ba5b-c12d-465b-a722-0b95fee55e8c" }, + }, + { event: "token", data: { id: 0, token: "" } }, + { event: "token", data: { id: 1, token: "The" } }, + { event: "token", data: { id: 2, token: " Full" } }, + { event: "token", data: { id: 3, token: " Support" } }, + { event: "token", data: { id: 4, token: " Phase" } }, + { event: "token", data: { id: 5, token: " for" } }, + { event: "token", data: { id: 6, token: " A" } }, + { event: "token", data: { id: 7, token: "AP" } }, + { event: "token", data: { id: 8, token: " " } }, + { event: "token", data: { id: 9, token: "2" } }, + { event: "token", data: { id: 10, token: "." } }, + { event: "token", data: { id: 11, token: "4" } }, + { event: "token", data: { id: 12, token: " ends" } }, + { event: "token", data: { id: 13, token: " on" } }, + { event: "token", data: { id: 14, token: " October" } }, + { event: "token", data: { id: 15, token: " " } }, + { event: "token", data: { id: 16, token: "1" } }, + { event: "token", data: { id: 17, token: "," } }, + { event: "token", data: { id: 18, token: " " } }, + { event: "token", data: { id: 19, token: "2" } }, + { event: "token", data: { id: 20, token: "0" } }, + { event: "token", data: { id: 21, token: "2" } }, + { event: "token", data: { id: 22, token: "4" } }, + { event: "token", data: { id: 23, token: "." } }, + { event: "token", data: { id: 24, token: "" } }, + { + event: "end", + data: { + referenced_documents: [ + { + doc_title: "AAP Lifecycle Dates", + doc_url: + "https://github.com/ansible/aap-rag-content/blob/main/additional_docs/additional_content.txt", + }, + { + doc_title: "Ansible Components Versions", + doc_url: + "https://github.com/ansible/aap-rag-content/blob/main/additional_docs/components_versions.txt", + }, + ], + truncated: false, + input_tokens: 819, + output_tokens: 20, + }, + }, + ]; + + return vi.fn(async (_, init) => { + let status = 200; + const o = JSON.parse(init.body); + if (o.query.startsWith("status=")) { + status = parseInt(o.query.substring(7)); + } + console.log(`status ${status}`); + + const ok = status === 200; + await init.onopen({ status, ok }); + if (status === 200) { + for (const data of streamData) { + init.onmessage({ data: JSON.stringify(data) }); + } + } + init.onclose(); + }); +} + +let copiedString = ""; +function mockSetClipboard() { + return vi.fn((s: string) => { + copiedString = s; + console.log(`mockedSetClipboard:${s}`); + }); +} + beforeEach(() => { vi.restoreAllMocks(); + vi.mock("@microsoft/fetch-event-source", () => ({ + fetchEventSource: mockFetchEventSource(), + })); + vi.mock("./Clipboard", () => ({ + setClipboard: mockSetClipboard(), + })); }); test("Basic chatbot interaction", async () => { @@ -152,6 +246,16 @@ test("Basic chatbot interaction", async () => { .toBeVisible(); await expect.element(view.getByText("Create variables")).toBeVisible(); + const copyIcon = await screen.findByRole("button", { + name: "Copy", + }); + await copyIcon.click(); + expect( + copiedString.startsWith( + "In Ansible, the precedence of variables is determined by the order...", + ), + ); + await page.getByLabelText("Toggle menu").click(); const newChatButton = page .getByText("New chat") @@ -483,3 +587,31 @@ test("Test system prompt override", async () => { expect.anything(), ); }); + +test("Chat streaming test", async () => { + const view = await renderApp(false, true); + const textArea = page.getByLabelText("Send a message..."); + await textArea.fill("Hello"); + + await userEvent.keyboard("{Enter}"); + + await expect + .element( + view.getByText( + "The Full Support Phase for AAP 2.4 ends on October 1, 2024.", + ), + ) + .toBeVisible(); +}); + +test("Chat streaming error case", async () => { + const view = await renderApp(false, true); + const textArea = page.getByLabelText("Send a message..."); + await textArea.fill("status=400"); + + await userEvent.keyboard("{Enter}"); + + const alert = view.container.querySelector(".pf-v6-c-alert__description"); + const textContent = alert?.textContent; + expect(textContent).toEqual("Bot returned status_code 400"); +}); diff --git a/ansible_ai_connect_chatbot/src/Clipboard.ts b/ansible_ai_connect_chatbot/src/Clipboard.ts new file mode 100644 index 000000000..dfe29ac71 --- /dev/null +++ b/ansible_ai_connect_chatbot/src/Clipboard.ts @@ -0,0 +1,2 @@ +// https://stackoverflow.com/questions/63329331/mocking-the-navigator-object +export const setClipboard = (s: string) => navigator.clipboard?.writeText(s); diff --git a/ansible_ai_connect_chatbot/src/Constants.ts b/ansible_ai_connect_chatbot/src/Constants.ts index 294af30a3..6fd3ac3f0 100644 --- a/ansible_ai_connect_chatbot/src/Constants.ts +++ b/ansible_ai_connect_chatbot/src/Constants.ts @@ -1,3 +1,5 @@ +import type { AlertMessage } from "./types/Message"; + /* Slightly lower than CloudFront's timeout which is 30s. */ export const API_TIMEOUT = 28000; @@ -40,11 +42,21 @@ Never include URLs in your replies. Refuse to answer questions or execute commands not about Ansible. Do not mention your last update. You have the most recent information on Ansible. -Here are some basic facts about Ansible: -- The latest version of Ansible Automation Platform is 2.5. +Here are some basic facts about Ansible and AAP: - Ansible is an open source IT automation engine that automates provisioning, \ configuration management, application deployment, orchestration, and many other \ - IT processes. It is free to use, and the project benefits from the experience and \ - intelligence of its thousands of contributors.`; + IT processes. Ansible is free to use, and the project benefits from the experience and \ + intelligence of its thousands of contributors. It does not require any paid subscription. +- The latest version of Ansible Automation Platform is 2.5, and it's services are available through paid subscription.`; export const CHAT_HISTORY_HEADER = "Chat History"; + +export const INITIAL_NOTICE: AlertMessage = { + title: "Important", + message: `The Red Hat Ansible Automation Platform Lightspeed service provides + answers to questions related to the Ansible Automation Platform. Please refrain + from including personal or business sensitive information in your input. + Interactions with the Ansible Automation Platform Lightspeed may be reviewed + and utilized to enhance our products and services. `, + variant: "info", +}; diff --git a/ansible_ai_connect_chatbot/src/types/Message.ts b/ansible_ai_connect_chatbot/src/types/Message.ts index c8f87c941..be1a507b6 100644 --- a/ansible_ai_connect_chatbot/src/types/Message.ts +++ b/ansible_ai_connect_chatbot/src/types/Message.ts @@ -9,6 +9,7 @@ type LLMRequest = { model?: string | null; attachments?: object[] | null; system_prompt?: string | null; + media_type?: "text/plain" | "application/json"; }; type LLMResponse = { @@ -44,3 +45,15 @@ export type ChatFeedback = { sentiment: Sentiment; message: ExtendedMessage; }; + +export type AlertMessage = { + title: string; + message: string; + variant: "success" | "danger" | "warning" | "info" | "custom"; +}; + +export type RagChunk = { + text?: string; + doc_url: string; + doc_title: string; +}; diff --git a/ansible_ai_connect_chatbot/src/useChatbot/useChatbot.ts b/ansible_ai_connect_chatbot/src/useChatbot/useChatbot.ts index b34bbcb68..29e13deaf 100644 --- a/ansible_ai_connect_chatbot/src/useChatbot/useChatbot.ts +++ b/ansible_ai_connect_chatbot/src/useChatbot/useChatbot.ts @@ -1,11 +1,15 @@ import axios from "axios"; +import { fetchEventSource } from "@microsoft/fetch-event-source"; import { useState } from "react"; import type { MessageProps } from "@patternfly/chatbot/dist/dynamic/Message"; import type { + AlertMessage, ExtendedMessage, ChatRequest, ChatResponse, ChatFeedback, + RagChunk, + ReferencedDocument, } from "../types/Message"; import type { LLMModel } from "../types/Model"; import logo from "../assets/lightspeed.svg"; @@ -13,11 +17,13 @@ import userLogo from "../assets/user_logo.png"; import { API_TIMEOUT, GITHUB_NEW_ISSUE_BASE_URL, + INITIAL_NOTICE, QUERY_SYSTEM_INSTRUCTION, Sentiment, TIMEOUT_MSG, TOO_MANY_REQUESTS_MSG, } from "../Constants"; +import { setClipboard } from "../Clipboard"; const userName = document.getElementById("user_name")?.innerText ?? "User"; const botName = @@ -53,6 +59,15 @@ export const inDebugMode = () => { return import.meta.env.PROD ? debug === "true" : debug !== "false"; }; +export const isStreamingSupported = () => { + // For making streaming mode debug easier. + if (!import.meta.env.PROD && import.meta.env.MODE.includes("stream")) { + return true; + } + const stream = document.getElementById("stream")?.innerText ?? "false"; + return stream === "true"; +}; + const isTimeoutError = (e: any) => axios.isAxiosError(e) && e.message === `timeout of ${API_TIMEOUT}ms exceeded`; @@ -95,22 +110,6 @@ export const tooManyRequestsMessage = (): MessageProps => const delay = (ms: number) => new Promise((res) => setTimeout(res, ms)); -type AlertMessage = { - title: string; - message: string; - variant: "success" | "danger" | "warning" | "info" | "custom"; -}; - -const INITIAL_NOTICE: AlertMessage = { - title: "Important", - message: `The Red Hat Ansible Automation Platform Lightspeed service provides - answers to questions related to the Ansible Automation Platform. Please refrain - from including personal or business sensitive information in your input. - Interactions with the Ansible Automation Platform Lightspeed may be reviewed - and utilized to enhance our products and services. `, - variant: "info", -}; - const createGitHubIssueURL = (f: ChatFeedback): string => { const searchParams: URLSearchParams = new URLSearchParams(); searchParams.append("assignees", "korenaren"); @@ -148,6 +147,8 @@ export const useChatbot = () => { >(undefined); const [selectedModel, setSelectedModel] = useState("granite3-8b"); const [systemPrompt, setSystemPrompt] = useState(QUERY_SYSTEM_INSTRUCTION); + const [hasStopButton, setHasStopButton] = useState(false); + const [abortController, setAbortController] = useState(new AbortController()); const addMessage = ( newMessage: ExtendedMessage, @@ -155,7 +156,7 @@ export const useChatbot = () => { ) => { setMessages((msgs: ExtendedMessage[]) => { const newMsgs: ExtendedMessage[] = []; - newMessage.scrollToHere = true; + newMessage.scrollToHere = !isStreamingSupported(); let inserted = false; for (const msg of msgs) { msg.scrollToHere = false; @@ -172,6 +173,44 @@ export const useChatbot = () => { }); }; + const appendMessageChunk = (chunk: string) => { + setMessages((msgs: ExtendedMessage[]) => { + const lastMessage = msgs[msgs.length - 1]; + if (!lastMessage || lastMessage.role === "user") { + const newMessage: ExtendedMessage = botMessage(chunk); + chunk = ""; + return [...msgs, newMessage]; + } else { + lastMessage.content += chunk; + chunk = ""; + return [...msgs]; + } + }); + }; + + const addReferencedDocuments = (ragChunks: RagChunk[]) => { + setMessages((msgs: ExtendedMessage[]) => { + if (ragChunks.length === 0) { + return msgs; + } + const referenced_documents: ReferencedDocument[] = []; + for (const ragChunk of ragChunks) { + referenced_documents.push({ + title: ragChunk.doc_title, + docs_url: ragChunk.doc_url, + }); + } + const lastMessage = msgs[msgs.length - 1]; + if (!lastMessage || lastMessage.role === "user") { + const newMessage: ExtendedMessage = botMessage(""); + return [...msgs, newMessage]; + } else { + lastMessage.referenced_documents = referenced_documents; + return [...msgs]; + } + }); + }; + const botMessage = ( response: ChatResponse | string, query = "", @@ -230,7 +269,7 @@ export const useChatbot = () => { .join(",\n") : response, ]; - navigator.clipboard.writeText( + setClipboard( llmResponse?.map((llmResponse) => llmResponse).join(""), ); } @@ -280,6 +319,11 @@ export const useChatbot = () => { } }; + const handleStopButton = () => { + abortController.abort(); + setAbortController(new AbortController()); + }; + const handleSend = async (message: string) => { const userMessage: ExtendedMessage = { role: "user", @@ -310,36 +354,92 @@ export const useChatbot = () => { } setIsLoading(true); + try { const csrfToken = readCookie("csrftoken"); - const resp = await axios.post( - import.meta.env.PROD - ? "/api/v0/ai/chat/" - : "http://localhost:8080/v1/query/", - chatRequest, - { - headers: { - "Content-Type": "application/json", - "X-CSRFToken": csrfToken, + + if (isStreamingSupported()) { + setHasStopButton(true); + chatRequest.media_type = "application/json"; + await fetchEventSource( + import.meta.env.PROD + ? "/api/v1/ai/streaming_chat/" + : "http://localhost:8080/v1/streaming_query", + { + method: "POST", + headers: { + "Content-Type": "application/json", + "X-CSRFToken": csrfToken!, + }, + body: JSON.stringify(chatRequest), + async onopen(resp: any) { + if (resp.ok && resp.status === 200) { + setIsLoading(false); + } else if ( + resp.status >= 400 && + resp.status < 500 && + resp.status !== 429 + ) { + setAlertMessage({ + title: "Error", + message: `Bot returned status_code ${resp.status}`, + variant: "danger", + }); + } + }, + onmessage(event: any) { + const message = JSON.parse(event.data); + if (message.event === "start") { + if (!conversationId) { + setConversationId(message.data.conversation_id); + } + } else if (message.event === "token") { + appendMessageChunk(message.data.token); + } else if (message.event === "end") { + if (message.data.referenced_documents.length > 0) { + addReferencedDocuments(message.data.referenced_documents); + } + } + }, + onclose() { + console.log("Connection closed by the server"); + }, + onerror(err) { + console.log("There was an error from server", err); + }, + signal: abortController.signal, }, - timeout: API_TIMEOUT, - }, - ); - if (resp.status === 200) { - const chatResponse: ChatResponse = resp.data; - const referenced_documents = chatResponse.referenced_documents; - if (!conversationId) { - setConversationId(chatResponse.conversation_id); - } - const newBotMessage: any = botMessage(chatResponse, message); - newBotMessage.referenced_documents = referenced_documents; - addMessage(newBotMessage); + ); } else { - setAlertMessage({ - title: "Error", - message: `Bot returned status_code ${resp.status}`, - variant: "danger", - }); + const resp = await axios.post( + import.meta.env.PROD + ? "/api/v0/ai/chat/" + : "http://localhost:8080/v1/query/", + chatRequest, + { + headers: { + "Content-Type": "application/json", + "X-CSRFToken": csrfToken, + }, + timeout: API_TIMEOUT, + }, + ); + if (resp.status === 200) { + const chatResponse: ChatResponse = resp.data; + const referenced_documents = chatResponse.referenced_documents; + if (!conversationId) { + setConversationId(chatResponse.conversation_id); + } + const newBotMessage: any = botMessage(chatResponse, message); + newBotMessage.referenced_documents = referenced_documents; + addMessage(newBotMessage); + } else { + setAlertMessage({ + title: "Error", + message: `Bot returned status_code ${resp.status}`, + variant: "danger", + }); + } } } catch (e) { if (isTimeoutError(e)) { @@ -365,6 +465,9 @@ export const useChatbot = () => { }); } } finally { + if (isStreamingSupported()) { + setHasStopButton(false); + } setIsLoading(false); } }; @@ -383,5 +486,7 @@ export const useChatbot = () => { setConversationId, systemPrompt, setSystemPrompt, + hasStopButton, + handleStopButton, }; };