S01Nour
commited on
Commit
·
a94de35
1
Parent(s):
78b3b2b
feat/ui: chat adapted tools
Browse files- package-lock.json +44 -44
- package.json +1 -0
- src/app/components/chat/ChatInput.tsx +86 -16
- src/app/components/chat/MessageList.tsx +78 -9
- src/app/hooks/useChat.ts +61 -14
- src/app/pages/ChatPage.tsx +3 -3
- src/app/types/chat.types.ts +1 -0
package-lock.json
CHANGED
|
@@ -22,6 +22,7 @@
|
|
| 22 |
"web-vitals": "^2.1.4"
|
| 23 |
},
|
| 24 |
"devDependencies": {
|
|
|
|
| 25 |
"@types/react": "^19.2.7",
|
| 26 |
"@types/react-dom": "^19.2.3",
|
| 27 |
"autoprefixer": "^10.4.22",
|
|
@@ -75,6 +76,7 @@
|
|
| 75 |
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
|
| 76 |
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
| 77 |
"license": "MIT",
|
|
|
|
| 78 |
"dependencies": {
|
| 79 |
"@babel/code-frame": "^7.27.1",
|
| 80 |
"@babel/generator": "^7.28.5",
|
|
@@ -724,6 +726,7 @@
|
|
| 724 |
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz",
|
| 725 |
"integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==",
|
| 726 |
"license": "MIT",
|
|
|
|
| 727 |
"dependencies": {
|
| 728 |
"@babel/helper-plugin-utils": "^7.27.1"
|
| 729 |
},
|
|
@@ -1607,6 +1610,7 @@
|
|
| 1607 |
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz",
|
| 1608 |
"integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==",
|
| 1609 |
"license": "MIT",
|
|
|
|
| 1610 |
"dependencies": {
|
| 1611 |
"@babel/helper-annotate-as-pure": "^7.27.1",
|
| 1612 |
"@babel/helper-module-imports": "^7.27.1",
|
|
@@ -2097,7 +2101,6 @@
|
|
| 2097 |
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
| 2098 |
"license": "MIT",
|
| 2099 |
"optional": true,
|
| 2100 |
-
"peer": true,
|
| 2101 |
"dependencies": {
|
| 2102 |
"@jridgewell/trace-mapping": "0.3.9"
|
| 2103 |
},
|
|
@@ -2111,7 +2114,6 @@
|
|
| 2111 |
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
| 2112 |
"license": "MIT",
|
| 2113 |
"optional": true,
|
| 2114 |
-
"peer": true,
|
| 2115 |
"dependencies": {
|
| 2116 |
"@jridgewell/resolve-uri": "^3.0.3",
|
| 2117 |
"@jridgewell/sourcemap-codec": "^1.4.10"
|
|
@@ -3410,6 +3412,7 @@
|
|
| 3410 |
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
|
| 3411 |
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
| 3412 |
"license": "MIT",
|
|
|
|
| 3413 |
"dependencies": {
|
| 3414 |
"@babel/code-frame": "^7.10.4",
|
| 3415 |
"@babel/runtime": "^7.12.5",
|
|
@@ -3515,32 +3518,28 @@
|
|
| 3515 |
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
|
| 3516 |
"integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
|
| 3517 |
"license": "MIT",
|
| 3518 |
-
"optional": true
|
| 3519 |
-
"peer": true
|
| 3520 |
},
|
| 3521 |
"node_modules/@tsconfig/node12": {
|
| 3522 |
"version": "1.0.11",
|
| 3523 |
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
| 3524 |
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
| 3525 |
"license": "MIT",
|
| 3526 |
-
"optional": true
|
| 3527 |
-
"peer": true
|
| 3528 |
},
|
| 3529 |
"node_modules/@tsconfig/node14": {
|
| 3530 |
"version": "1.0.3",
|
| 3531 |
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
| 3532 |
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
| 3533 |
"license": "MIT",
|
| 3534 |
-
"optional": true
|
| 3535 |
-
"peer": true
|
| 3536 |
},
|
| 3537 |
"node_modules/@tsconfig/node16": {
|
| 3538 |
"version": "1.0.4",
|
| 3539 |
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
| 3540 |
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
| 3541 |
"license": "MIT",
|
| 3542 |
-
"optional": true
|
| 3543 |
-
"peer": true
|
| 3544 |
},
|
| 3545 |
"node_modules/@types/aria-query": {
|
| 3546 |
"version": "5.0.4",
|
|
@@ -3825,10 +3824,11 @@
|
|
| 3825 |
"license": "MIT"
|
| 3826 |
},
|
| 3827 |
"node_modules/@types/node": {
|
| 3828 |
-
"version": "
|
| 3829 |
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-
|
| 3830 |
-
"integrity": "sha512-
|
| 3831 |
"license": "MIT",
|
|
|
|
| 3832 |
"dependencies": {
|
| 3833 |
"undici-types": "~7.16.0"
|
| 3834 |
}
|
|
@@ -3878,6 +3878,7 @@
|
|
| 3878 |
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
| 3879 |
"devOptional": true,
|
| 3880 |
"license": "MIT",
|
|
|
|
| 3881 |
"dependencies": {
|
| 3882 |
"csstype": "^3.2.2"
|
| 3883 |
}
|
|
@@ -3888,6 +3889,7 @@
|
|
| 3888 |
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
| 3889 |
"devOptional": true,
|
| 3890 |
"license": "MIT",
|
|
|
|
| 3891 |
"peerDependencies": {
|
| 3892 |
"@types/react": "^19.2.0"
|
| 3893 |
}
|
|
@@ -4008,6 +4010,7 @@
|
|
| 4008 |
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
|
| 4009 |
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
|
| 4010 |
"license": "MIT",
|
|
|
|
| 4011 |
"dependencies": {
|
| 4012 |
"@eslint-community/regexpp": "^4.4.0",
|
| 4013 |
"@typescript-eslint/scope-manager": "5.62.0",
|
|
@@ -4061,6 +4064,7 @@
|
|
| 4061 |
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
|
| 4062 |
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
|
| 4063 |
"license": "BSD-2-Clause",
|
|
|
|
| 4064 |
"dependencies": {
|
| 4065 |
"@typescript-eslint/scope-manager": "5.62.0",
|
| 4066 |
"@typescript-eslint/types": "5.62.0",
|
|
@@ -4430,6 +4434,7 @@
|
|
| 4430 |
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
| 4431 |
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
| 4432 |
"license": "MIT",
|
|
|
|
| 4433 |
"bin": {
|
| 4434 |
"acorn": "bin/acorn"
|
| 4435 |
},
|
|
@@ -4528,6 +4533,7 @@
|
|
| 4528 |
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
| 4529 |
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
| 4530 |
"license": "MIT",
|
|
|
|
| 4531 |
"dependencies": {
|
| 4532 |
"fast-deep-equal": "^3.1.1",
|
| 4533 |
"fast-json-stable-stringify": "^2.0.0",
|
|
@@ -5435,6 +5441,7 @@
|
|
| 5435 |
}
|
| 5436 |
],
|
| 5437 |
"license": "MIT",
|
|
|
|
| 5438 |
"dependencies": {
|
| 5439 |
"baseline-browser-mapping": "^2.9.0",
|
| 5440 |
"caniuse-lite": "^1.0.30001759",
|
|
@@ -6103,8 +6110,7 @@
|
|
| 6103 |
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
| 6104 |
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
| 6105 |
"license": "MIT",
|
| 6106 |
-
"optional": true
|
| 6107 |
-
"peer": true
|
| 6108 |
},
|
| 6109 |
"node_modules/cross-spawn": {
|
| 6110 |
"version": "7.0.6",
|
|
@@ -6904,7 +6910,6 @@
|
|
| 6904 |
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
| 6905 |
"license": "BSD-3-Clause",
|
| 6906 |
"optional": true,
|
| 6907 |
-
"peer": true,
|
| 6908 |
"engines": {
|
| 6909 |
"node": ">=0.3.1"
|
| 6910 |
}
|
|
@@ -7455,6 +7460,7 @@
|
|
| 7455 |
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
| 7456 |
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
| 7457 |
"license": "MIT",
|
|
|
|
| 7458 |
"dependencies": {
|
| 7459 |
"@eslint-community/eslint-utils": "^4.2.0",
|
| 7460 |
"@eslint-community/regexpp": "^4.6.1",
|
|
@@ -10210,6 +10216,7 @@
|
|
| 10210 |
"resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
|
| 10211 |
"integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==",
|
| 10212 |
"license": "MIT",
|
|
|
|
| 10213 |
"dependencies": {
|
| 10214 |
"@jest/core": "^27.5.1",
|
| 10215 |
"import-local": "^3.0.2",
|
|
@@ -11095,6 +11102,7 @@
|
|
| 11095 |
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
| 11096 |
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
| 11097 |
"license": "MIT",
|
|
|
|
| 11098 |
"bin": {
|
| 11099 |
"jiti": "bin/jiti.js"
|
| 11100 |
}
|
|
@@ -11539,8 +11547,7 @@
|
|
| 11539 |
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
| 11540 |
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
| 11541 |
"license": "ISC",
|
| 11542 |
-
"optional": true
|
| 11543 |
-
"peer": true
|
| 11544 |
},
|
| 11545 |
"node_modules/makeerror": {
|
| 11546 |
"version": "1.0.12",
|
|
@@ -12458,6 +12465,7 @@
|
|
| 12458 |
}
|
| 12459 |
],
|
| 12460 |
"license": "MIT",
|
|
|
|
| 12461 |
"dependencies": {
|
| 12462 |
"nanoid": "^3.3.11",
|
| 12463 |
"picocolors": "^1.1.1",
|
|
@@ -13592,6 +13600,7 @@
|
|
| 13592 |
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
| 13593 |
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
| 13594 |
"license": "MIT",
|
|
|
|
| 13595 |
"dependencies": {
|
| 13596 |
"cssesc": "^3.0.0",
|
| 13597 |
"util-deprecate": "^1.0.2"
|
|
@@ -13952,6 +13961,7 @@
|
|
| 13952 |
"resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
|
| 13953 |
"integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
|
| 13954 |
"license": "MIT",
|
|
|
|
| 13955 |
"engines": {
|
| 13956 |
"node": ">=0.10.0"
|
| 13957 |
}
|
|
@@ -14083,6 +14093,7 @@
|
|
| 14083 |
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz",
|
| 14084 |
"integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==",
|
| 14085 |
"license": "MIT",
|
|
|
|
| 14086 |
"dependencies": {
|
| 14087 |
"scheduler": "^0.27.0"
|
| 14088 |
},
|
|
@@ -14100,13 +14111,15 @@
|
|
| 14100 |
"version": "17.0.2",
|
| 14101 |
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
| 14102 |
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
| 14103 |
-
"license": "MIT"
|
|
|
|
| 14104 |
},
|
| 14105 |
"node_modules/react-redux": {
|
| 14106 |
"version": "9.2.0",
|
| 14107 |
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
| 14108 |
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
| 14109 |
"license": "MIT",
|
|
|
|
| 14110 |
"dependencies": {
|
| 14111 |
"@types/use-sync-external-store": "^0.0.6",
|
| 14112 |
"use-sync-external-store": "^1.4.0"
|
|
@@ -14130,6 +14143,7 @@
|
|
| 14130 |
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
| 14131 |
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
|
| 14132 |
"license": "MIT",
|
|
|
|
| 14133 |
"engines": {
|
| 14134 |
"node": ">=0.10.0"
|
| 14135 |
}
|
|
@@ -14368,7 +14382,8 @@
|
|
| 14368 |
"version": "5.0.1",
|
| 14369 |
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
| 14370 |
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
| 14371 |
-
"license": "MIT"
|
|
|
|
| 14372 |
},
|
| 14373 |
"node_modules/redux-thunk": {
|
| 14374 |
"version": "3.1.0",
|
|
@@ -14694,6 +14709,7 @@
|
|
| 14694 |
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
|
| 14695 |
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
|
| 14696 |
"license": "MIT",
|
|
|
|
| 14697 |
"bin": {
|
| 14698 |
"rollup": "dist/bin/rollup"
|
| 14699 |
},
|
|
@@ -14936,6 +14952,7 @@
|
|
| 14936 |
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
| 14937 |
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
| 14938 |
"license": "MIT",
|
|
|
|
| 14939 |
"dependencies": {
|
| 14940 |
"fast-deep-equal": "^3.1.3",
|
| 14941 |
"fast-uri": "^3.0.1",
|
|
@@ -16286,23 +16303,6 @@
|
|
| 16286 |
}
|
| 16287 |
}
|
| 16288 |
},
|
| 16289 |
-
"node_modules/tailwindcss/node_modules/yaml": {
|
| 16290 |
-
"version": "2.8.2",
|
| 16291 |
-
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
|
| 16292 |
-
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
| 16293 |
-
"license": "ISC",
|
| 16294 |
-
"optional": true,
|
| 16295 |
-
"peer": true,
|
| 16296 |
-
"bin": {
|
| 16297 |
-
"yaml": "bin.mjs"
|
| 16298 |
-
},
|
| 16299 |
-
"engines": {
|
| 16300 |
-
"node": ">= 14.6"
|
| 16301 |
-
},
|
| 16302 |
-
"funding": {
|
| 16303 |
-
"url": "https://github.com/sponsors/eemeli"
|
| 16304 |
-
}
|
| 16305 |
-
},
|
| 16306 |
"node_modules/tapable": {
|
| 16307 |
"version": "2.3.0",
|
| 16308 |
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
|
|
@@ -16526,6 +16526,7 @@
|
|
| 16526 |
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
| 16527 |
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
| 16528 |
"license": "MIT",
|
|
|
|
| 16529 |
"engines": {
|
| 16530 |
"node": ">=12"
|
| 16531 |
},
|
|
@@ -16614,7 +16615,6 @@
|
|
| 16614 |
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
| 16615 |
"license": "MIT",
|
| 16616 |
"optional": true,
|
| 16617 |
-
"peer": true,
|
| 16618 |
"dependencies": {
|
| 16619 |
"@cspotcode/source-map-support": "^0.8.0",
|
| 16620 |
"@tsconfig/node10": "^1.0.7",
|
|
@@ -16659,7 +16659,6 @@
|
|
| 16659 |
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
|
| 16660 |
"license": "MIT",
|
| 16661 |
"optional": true,
|
| 16662 |
-
"peer": true,
|
| 16663 |
"dependencies": {
|
| 16664 |
"acorn": "^8.11.0"
|
| 16665 |
},
|
|
@@ -16672,8 +16671,7 @@
|
|
| 16672 |
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
| 16673 |
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
| 16674 |
"license": "MIT",
|
| 16675 |
-
"optional": true
|
| 16676 |
-
"peer": true
|
| 16677 |
},
|
| 16678 |
"node_modules/tsconfig-paths": {
|
| 16679 |
"version": "3.15.0",
|
|
@@ -16761,6 +16759,7 @@
|
|
| 16761 |
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
|
| 16762 |
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
|
| 16763 |
"license": "(MIT OR CC0-1.0)",
|
|
|
|
| 16764 |
"engines": {
|
| 16765 |
"node": ">=10"
|
| 16766 |
},
|
|
@@ -17102,8 +17101,7 @@
|
|
| 17102 |
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
| 17103 |
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
| 17104 |
"license": "MIT",
|
| 17105 |
-
"optional": true
|
| 17106 |
-
"peer": true
|
| 17107 |
},
|
| 17108 |
"node_modules/v8-to-istanbul": {
|
| 17109 |
"version": "8.1.1",
|
|
@@ -17229,6 +17227,7 @@
|
|
| 17229 |
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz",
|
| 17230 |
"integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==",
|
| 17231 |
"license": "MIT",
|
|
|
|
| 17232 |
"dependencies": {
|
| 17233 |
"@types/eslint-scope": "^3.7.7",
|
| 17234 |
"@types/estree": "^1.0.8",
|
|
@@ -17300,6 +17299,7 @@
|
|
| 17300 |
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz",
|
| 17301 |
"integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
|
| 17302 |
"license": "MIT",
|
|
|
|
| 17303 |
"dependencies": {
|
| 17304 |
"@types/bonjour": "^3.5.9",
|
| 17305 |
"@types/connect-history-api-fallback": "^1.3.5",
|
|
@@ -17712,6 +17712,7 @@
|
|
| 17712 |
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
| 17713 |
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
| 17714 |
"license": "MIT",
|
|
|
|
| 17715 |
"dependencies": {
|
| 17716 |
"fast-deep-equal": "^3.1.3",
|
| 17717 |
"fast-uri": "^3.0.1",
|
|
@@ -18087,7 +18088,6 @@
|
|
| 18087 |
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
| 18088 |
"license": "MIT",
|
| 18089 |
"optional": true,
|
| 18090 |
-
"peer": true,
|
| 18091 |
"engines": {
|
| 18092 |
"node": ">=6"
|
| 18093 |
}
|
|
|
|
| 22 |
"web-vitals": "^2.1.4"
|
| 23 |
},
|
| 24 |
"devDependencies": {
|
| 25 |
+
"@types/node": "^25.0.3",
|
| 26 |
"@types/react": "^19.2.7",
|
| 27 |
"@types/react-dom": "^19.2.3",
|
| 28 |
"autoprefixer": "^10.4.22",
|
|
|
|
| 76 |
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
|
| 77 |
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
| 78 |
"license": "MIT",
|
| 79 |
+
"peer": true,
|
| 80 |
"dependencies": {
|
| 81 |
"@babel/code-frame": "^7.27.1",
|
| 82 |
"@babel/generator": "^7.28.5",
|
|
|
|
| 726 |
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz",
|
| 727 |
"integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==",
|
| 728 |
"license": "MIT",
|
| 729 |
+
"peer": true,
|
| 730 |
"dependencies": {
|
| 731 |
"@babel/helper-plugin-utils": "^7.27.1"
|
| 732 |
},
|
|
|
|
| 1610 |
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz",
|
| 1611 |
"integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==",
|
| 1612 |
"license": "MIT",
|
| 1613 |
+
"peer": true,
|
| 1614 |
"dependencies": {
|
| 1615 |
"@babel/helper-annotate-as-pure": "^7.27.1",
|
| 1616 |
"@babel/helper-module-imports": "^7.27.1",
|
|
|
|
| 2101 |
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
| 2102 |
"license": "MIT",
|
| 2103 |
"optional": true,
|
|
|
|
| 2104 |
"dependencies": {
|
| 2105 |
"@jridgewell/trace-mapping": "0.3.9"
|
| 2106 |
},
|
|
|
|
| 2114 |
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
| 2115 |
"license": "MIT",
|
| 2116 |
"optional": true,
|
|
|
|
| 2117 |
"dependencies": {
|
| 2118 |
"@jridgewell/resolve-uri": "^3.0.3",
|
| 2119 |
"@jridgewell/sourcemap-codec": "^1.4.10"
|
|
|
|
| 3412 |
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
|
| 3413 |
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
| 3414 |
"license": "MIT",
|
| 3415 |
+
"peer": true,
|
| 3416 |
"dependencies": {
|
| 3417 |
"@babel/code-frame": "^7.10.4",
|
| 3418 |
"@babel/runtime": "^7.12.5",
|
|
|
|
| 3518 |
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
|
| 3519 |
"integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
|
| 3520 |
"license": "MIT",
|
| 3521 |
+
"optional": true
|
|
|
|
| 3522 |
},
|
| 3523 |
"node_modules/@tsconfig/node12": {
|
| 3524 |
"version": "1.0.11",
|
| 3525 |
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
| 3526 |
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
| 3527 |
"license": "MIT",
|
| 3528 |
+
"optional": true
|
|
|
|
| 3529 |
},
|
| 3530 |
"node_modules/@tsconfig/node14": {
|
| 3531 |
"version": "1.0.3",
|
| 3532 |
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
| 3533 |
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
| 3534 |
"license": "MIT",
|
| 3535 |
+
"optional": true
|
|
|
|
| 3536 |
},
|
| 3537 |
"node_modules/@tsconfig/node16": {
|
| 3538 |
"version": "1.0.4",
|
| 3539 |
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
|
| 3540 |
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
| 3541 |
"license": "MIT",
|
| 3542 |
+
"optional": true
|
|
|
|
| 3543 |
},
|
| 3544 |
"node_modules/@types/aria-query": {
|
| 3545 |
"version": "5.0.4",
|
|
|
|
| 3824 |
"license": "MIT"
|
| 3825 |
},
|
| 3826 |
"node_modules/@types/node": {
|
| 3827 |
+
"version": "25.0.3",
|
| 3828 |
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz",
|
| 3829 |
+
"integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==",
|
| 3830 |
"license": "MIT",
|
| 3831 |
+
"peer": true,
|
| 3832 |
"dependencies": {
|
| 3833 |
"undici-types": "~7.16.0"
|
| 3834 |
}
|
|
|
|
| 3878 |
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
| 3879 |
"devOptional": true,
|
| 3880 |
"license": "MIT",
|
| 3881 |
+
"peer": true,
|
| 3882 |
"dependencies": {
|
| 3883 |
"csstype": "^3.2.2"
|
| 3884 |
}
|
|
|
|
| 3889 |
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
| 3890 |
"devOptional": true,
|
| 3891 |
"license": "MIT",
|
| 3892 |
+
"peer": true,
|
| 3893 |
"peerDependencies": {
|
| 3894 |
"@types/react": "^19.2.0"
|
| 3895 |
}
|
|
|
|
| 4010 |
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
|
| 4011 |
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
|
| 4012 |
"license": "MIT",
|
| 4013 |
+
"peer": true,
|
| 4014 |
"dependencies": {
|
| 4015 |
"@eslint-community/regexpp": "^4.4.0",
|
| 4016 |
"@typescript-eslint/scope-manager": "5.62.0",
|
|
|
|
| 4064 |
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
|
| 4065 |
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
|
| 4066 |
"license": "BSD-2-Clause",
|
| 4067 |
+
"peer": true,
|
| 4068 |
"dependencies": {
|
| 4069 |
"@typescript-eslint/scope-manager": "5.62.0",
|
| 4070 |
"@typescript-eslint/types": "5.62.0",
|
|
|
|
| 4434 |
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
| 4435 |
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
| 4436 |
"license": "MIT",
|
| 4437 |
+
"peer": true,
|
| 4438 |
"bin": {
|
| 4439 |
"acorn": "bin/acorn"
|
| 4440 |
},
|
|
|
|
| 4533 |
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
| 4534 |
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
| 4535 |
"license": "MIT",
|
| 4536 |
+
"peer": true,
|
| 4537 |
"dependencies": {
|
| 4538 |
"fast-deep-equal": "^3.1.1",
|
| 4539 |
"fast-json-stable-stringify": "^2.0.0",
|
|
|
|
| 5441 |
}
|
| 5442 |
],
|
| 5443 |
"license": "MIT",
|
| 5444 |
+
"peer": true,
|
| 5445 |
"dependencies": {
|
| 5446 |
"baseline-browser-mapping": "^2.9.0",
|
| 5447 |
"caniuse-lite": "^1.0.30001759",
|
|
|
|
| 6110 |
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
| 6111 |
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
| 6112 |
"license": "MIT",
|
| 6113 |
+
"optional": true
|
|
|
|
| 6114 |
},
|
| 6115 |
"node_modules/cross-spawn": {
|
| 6116 |
"version": "7.0.6",
|
|
|
|
| 6910 |
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
| 6911 |
"license": "BSD-3-Clause",
|
| 6912 |
"optional": true,
|
|
|
|
| 6913 |
"engines": {
|
| 6914 |
"node": ">=0.3.1"
|
| 6915 |
}
|
|
|
|
| 7460 |
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
| 7461 |
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
| 7462 |
"license": "MIT",
|
| 7463 |
+
"peer": true,
|
| 7464 |
"dependencies": {
|
| 7465 |
"@eslint-community/eslint-utils": "^4.2.0",
|
| 7466 |
"@eslint-community/regexpp": "^4.6.1",
|
|
|
|
| 10216 |
"resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
|
| 10217 |
"integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==",
|
| 10218 |
"license": "MIT",
|
| 10219 |
+
"peer": true,
|
| 10220 |
"dependencies": {
|
| 10221 |
"@jest/core": "^27.5.1",
|
| 10222 |
"import-local": "^3.0.2",
|
|
|
|
| 11102 |
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
| 11103 |
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
| 11104 |
"license": "MIT",
|
| 11105 |
+
"peer": true,
|
| 11106 |
"bin": {
|
| 11107 |
"jiti": "bin/jiti.js"
|
| 11108 |
}
|
|
|
|
| 11547 |
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
| 11548 |
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
| 11549 |
"license": "ISC",
|
| 11550 |
+
"optional": true
|
|
|
|
| 11551 |
},
|
| 11552 |
"node_modules/makeerror": {
|
| 11553 |
"version": "1.0.12",
|
|
|
|
| 12465 |
}
|
| 12466 |
],
|
| 12467 |
"license": "MIT",
|
| 12468 |
+
"peer": true,
|
| 12469 |
"dependencies": {
|
| 12470 |
"nanoid": "^3.3.11",
|
| 12471 |
"picocolors": "^1.1.1",
|
|
|
|
| 13600 |
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
| 13601 |
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
| 13602 |
"license": "MIT",
|
| 13603 |
+
"peer": true,
|
| 13604 |
"dependencies": {
|
| 13605 |
"cssesc": "^3.0.0",
|
| 13606 |
"util-deprecate": "^1.0.2"
|
|
|
|
| 13961 |
"resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
|
| 13962 |
"integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
|
| 13963 |
"license": "MIT",
|
| 13964 |
+
"peer": true,
|
| 13965 |
"engines": {
|
| 13966 |
"node": ">=0.10.0"
|
| 13967 |
}
|
|
|
|
| 14093 |
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz",
|
| 14094 |
"integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==",
|
| 14095 |
"license": "MIT",
|
| 14096 |
+
"peer": true,
|
| 14097 |
"dependencies": {
|
| 14098 |
"scheduler": "^0.27.0"
|
| 14099 |
},
|
|
|
|
| 14111 |
"version": "17.0.2",
|
| 14112 |
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
| 14113 |
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
| 14114 |
+
"license": "MIT",
|
| 14115 |
+
"peer": true
|
| 14116 |
},
|
| 14117 |
"node_modules/react-redux": {
|
| 14118 |
"version": "9.2.0",
|
| 14119 |
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
| 14120 |
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
| 14121 |
"license": "MIT",
|
| 14122 |
+
"peer": true,
|
| 14123 |
"dependencies": {
|
| 14124 |
"@types/use-sync-external-store": "^0.0.6",
|
| 14125 |
"use-sync-external-store": "^1.4.0"
|
|
|
|
| 14143 |
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
| 14144 |
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
|
| 14145 |
"license": "MIT",
|
| 14146 |
+
"peer": true,
|
| 14147 |
"engines": {
|
| 14148 |
"node": ">=0.10.0"
|
| 14149 |
}
|
|
|
|
| 14382 |
"version": "5.0.1",
|
| 14383 |
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
| 14384 |
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
| 14385 |
+
"license": "MIT",
|
| 14386 |
+
"peer": true
|
| 14387 |
},
|
| 14388 |
"node_modules/redux-thunk": {
|
| 14389 |
"version": "3.1.0",
|
|
|
|
| 14709 |
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
|
| 14710 |
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
|
| 14711 |
"license": "MIT",
|
| 14712 |
+
"peer": true,
|
| 14713 |
"bin": {
|
| 14714 |
"rollup": "dist/bin/rollup"
|
| 14715 |
},
|
|
|
|
| 14952 |
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
| 14953 |
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
| 14954 |
"license": "MIT",
|
| 14955 |
+
"peer": true,
|
| 14956 |
"dependencies": {
|
| 14957 |
"fast-deep-equal": "^3.1.3",
|
| 14958 |
"fast-uri": "^3.0.1",
|
|
|
|
| 16303 |
}
|
| 16304 |
}
|
| 16305 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16306 |
"node_modules/tapable": {
|
| 16307 |
"version": "2.3.0",
|
| 16308 |
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
|
|
|
|
| 16526 |
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
| 16527 |
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
| 16528 |
"license": "MIT",
|
| 16529 |
+
"peer": true,
|
| 16530 |
"engines": {
|
| 16531 |
"node": ">=12"
|
| 16532 |
},
|
|
|
|
| 16615 |
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
| 16616 |
"license": "MIT",
|
| 16617 |
"optional": true,
|
|
|
|
| 16618 |
"dependencies": {
|
| 16619 |
"@cspotcode/source-map-support": "^0.8.0",
|
| 16620 |
"@tsconfig/node10": "^1.0.7",
|
|
|
|
| 16659 |
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
|
| 16660 |
"license": "MIT",
|
| 16661 |
"optional": true,
|
|
|
|
| 16662 |
"dependencies": {
|
| 16663 |
"acorn": "^8.11.0"
|
| 16664 |
},
|
|
|
|
| 16671 |
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
| 16672 |
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
| 16673 |
"license": "MIT",
|
| 16674 |
+
"optional": true
|
|
|
|
| 16675 |
},
|
| 16676 |
"node_modules/tsconfig-paths": {
|
| 16677 |
"version": "3.15.0",
|
|
|
|
| 16759 |
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
|
| 16760 |
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
|
| 16761 |
"license": "(MIT OR CC0-1.0)",
|
| 16762 |
+
"peer": true,
|
| 16763 |
"engines": {
|
| 16764 |
"node": ">=10"
|
| 16765 |
},
|
|
|
|
| 17101 |
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
| 17102 |
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
| 17103 |
"license": "MIT",
|
| 17104 |
+
"optional": true
|
|
|
|
| 17105 |
},
|
| 17106 |
"node_modules/v8-to-istanbul": {
|
| 17107 |
"version": "8.1.1",
|
|
|
|
| 17227 |
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz",
|
| 17228 |
"integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==",
|
| 17229 |
"license": "MIT",
|
| 17230 |
+
"peer": true,
|
| 17231 |
"dependencies": {
|
| 17232 |
"@types/eslint-scope": "^3.7.7",
|
| 17233 |
"@types/estree": "^1.0.8",
|
|
|
|
| 17299 |
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz",
|
| 17300 |
"integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
|
| 17301 |
"license": "MIT",
|
| 17302 |
+
"peer": true,
|
| 17303 |
"dependencies": {
|
| 17304 |
"@types/bonjour": "^3.5.9",
|
| 17305 |
"@types/connect-history-api-fallback": "^1.3.5",
|
|
|
|
| 17712 |
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
| 17713 |
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
| 17714 |
"license": "MIT",
|
| 17715 |
+
"peer": true,
|
| 17716 |
"dependencies": {
|
| 17717 |
"fast-deep-equal": "^3.1.3",
|
| 17718 |
"fast-uri": "^3.0.1",
|
|
|
|
| 18088 |
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
| 18089 |
"license": "MIT",
|
| 18090 |
"optional": true,
|
|
|
|
| 18091 |
"engines": {
|
| 18092 |
"node": ">=6"
|
| 18093 |
}
|
package.json
CHANGED
|
@@ -17,6 +17,7 @@
|
|
| 17 |
"web-vitals": "^2.1.4"
|
| 18 |
},
|
| 19 |
"devDependencies": {
|
|
|
|
| 20 |
"@types/react": "^19.2.7",
|
| 21 |
"@types/react-dom": "^19.2.3",
|
| 22 |
"autoprefixer": "^10.4.22",
|
|
|
|
| 17 |
"web-vitals": "^2.1.4"
|
| 18 |
},
|
| 19 |
"devDependencies": {
|
| 20 |
+
"@types/node": "^25.0.3",
|
| 21 |
"@types/react": "^19.2.7",
|
| 22 |
"@types/react-dom": "^19.2.3",
|
| 23 |
"autoprefixer": "^10.4.22",
|
src/app/components/chat/ChatInput.tsx
CHANGED
|
@@ -4,8 +4,8 @@ import { useMCPTools } from '../../hooks/useMCPTools.ts';
|
|
| 4 |
import type { MCPTool } from '../../types/index.ts';
|
| 5 |
|
| 6 |
type ChatInputProps = {
|
| 7 |
-
onSubmit?: (message: string, selectedTool?: string | null) => void;
|
| 8 |
-
onAudioSubmit?: (audioBlob: Blob, selectedTool?: string | null) => void;
|
| 9 |
placeholder?: string;
|
| 10 |
};
|
| 11 |
|
|
@@ -14,11 +14,39 @@ const isMCPTool = (value: any): value is MCPTool => {
|
|
| 14 |
return value && typeof value === 'object' && typeof value.name === 'string';
|
| 15 |
};
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
const ChatInput = ({ onSubmit, onAudioSubmit, placeholder = 'Ask a follow-up...' }: ChatInputProps) => {
|
| 18 |
const [input, setInput] = useState('');
|
| 19 |
const [isRecording, setIsRecording] = useState(false);
|
| 20 |
const [showToolsDropdown, setShowToolsDropdown] = useState(false);
|
| 21 |
const [selectedTool, setSelectedTool] = useState<string | null>(null);
|
|
|
|
| 22 |
const [searchQuery, setSearchQuery] = useState('');
|
| 23 |
const [focusedIndex, setFocusedIndex] = useState(-1);
|
| 24 |
const [dropdownPosition, setDropdownPosition] = useState<'below' | 'above'>('below');
|
|
@@ -36,15 +64,21 @@ const ChatInput = ({ onSubmit, onAudioSubmit, placeholder = 'Ask a follow-up...'
|
|
| 36 |
const recordingTimerRef = useRef<NodeJS.Timeout | null>(null);
|
| 37 |
const { tools, loading, error, refetch } = useMCPTools();
|
| 38 |
|
| 39 |
-
const handleSubmit = (e:
|
| 40 |
e.preventDefault();
|
|
|
|
| 41 |
if (input.trim()) {
|
| 42 |
if (onSubmit) {
|
| 43 |
-
onSubmit(input, selectedTool);
|
| 44 |
}
|
| 45 |
console.log('Submitted:', input);
|
| 46 |
setInput('');
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
}
|
|
|
|
| 48 |
};
|
| 49 |
|
| 50 |
const handleMicClick = async () => {
|
|
@@ -207,7 +241,11 @@ const ChatInput = ({ onSubmit, onAudioSubmit, placeholder = 'Ask a follow-up...'
|
|
| 207 |
|
| 208 |
// Submit the recorded audio if available
|
| 209 |
if (audioBlob && onAudioSubmit) {
|
| 210 |
-
onAudioSubmit(audioBlob, selectedTool);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 211 |
}
|
| 212 |
|
| 213 |
// Clean up and return to normal chat mode
|
|
@@ -518,9 +556,13 @@ const ChatInput = ({ onSubmit, onAudioSubmit, placeholder = 'Ask a follow-up...'
|
|
| 518 |
e.preventDefault();
|
| 519 |
if (input.trim()) {
|
| 520 |
if (onSubmit) {
|
| 521 |
-
onSubmit(input, selectedTool);
|
| 522 |
}
|
| 523 |
setInput('');
|
|
|
|
|
|
|
|
|
|
|
|
|
| 524 |
}
|
| 525 |
}
|
| 526 |
}}
|
|
@@ -534,6 +576,35 @@ const ChatInput = ({ onSubmit, onAudioSubmit, placeholder = 'Ask a follow-up...'
|
|
| 534 |
}}
|
| 535 |
/>
|
| 536 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 537 |
<div className="flex items-center justify-between mt-8">
|
| 538 |
<div className="flex items-center gap-2">
|
| 539 |
<button
|
|
@@ -619,7 +690,7 @@ const ChatInput = ({ onSubmit, onAudioSubmit, placeholder = 'Ask a follow-up...'
|
|
| 619 |
</div>
|
| 620 |
</div>
|
| 621 |
</div>
|
| 622 |
-
) : tools.filter(isMCPTool).length === 0 ? (
|
| 623 |
<div className="px-4 py-6">
|
| 624 |
<div className="flex flex-col items-center gap-3 text-center">
|
| 625 |
<div className="h-12 w-12 rounded-full bg-zinc-100 dark:bg-zinc-800 flex items-center justify-center">
|
|
@@ -635,6 +706,7 @@ const ChatInput = ({ onSubmit, onAudioSubmit, placeholder = 'Ask a follow-up...'
|
|
| 635 |
<div className="p-2">
|
| 636 |
{tools
|
| 637 |
.filter(isMCPTool)
|
|
|
|
| 638 |
.filter(tool =>
|
| 639 |
tool.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
| 640 |
(tool.description && tool.description.toLowerCase().includes(searchQuery.toLowerCase()))
|
|
@@ -651,7 +723,12 @@ const ChatInput = ({ onSubmit, onAudioSubmit, placeholder = 'Ask a follow-up...'
|
|
| 651 |
: 'hover:bg-zinc-50 dark:hover:bg-zinc-800/50 border border-transparent'
|
| 652 |
}`}
|
| 653 |
onClick={() => {
|
| 654 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 655 |
setShowToolsDropdown(false);
|
| 656 |
setFocusedIndex(-1);
|
| 657 |
}}
|
|
@@ -690,6 +767,7 @@ const ChatInput = ({ onSubmit, onAudioSubmit, placeholder = 'Ask a follow-up...'
|
|
| 690 |
type="button"
|
| 691 |
onClick={() => {
|
| 692 |
setSelectedTool(null);
|
|
|
|
| 693 |
setShowToolsDropdown(false);
|
| 694 |
setFocusedIndex(-1);
|
| 695 |
}}
|
|
@@ -721,14 +799,6 @@ const ChatInput = ({ onSubmit, onAudioSubmit, placeholder = 'Ask a follow-up...'
|
|
| 721 |
|
| 722 |
<button
|
| 723 |
type="submit"
|
| 724 |
-
onClick={() => {
|
| 725 |
-
if (input.trim()) {
|
| 726 |
-
if (onSubmit) {
|
| 727 |
-
onSubmit(input, selectedTool);
|
| 728 |
-
}
|
| 729 |
-
setInput('');
|
| 730 |
-
}
|
| 731 |
-
}}
|
| 732 |
disabled={!input.trim()}
|
| 733 |
className="h-8 w-8 p-0 bg-zinc-300 dark:bg-zinc-700 hover:bg-zinc-400 dark:hover:bg-zinc-600 disabled:bg-zinc-200 dark:disabled:bg-zinc-800 disabled:text-zinc-400 dark:disabled:text-zinc-500 text-zinc-800 dark:text-white rounded-lg transition-all duration-200 hover:scale-110 disabled:hover:scale-100 flex items-center justify-center disabled:cursor-not-allowed"
|
| 734 |
>
|
|
|
|
| 4 |
import type { MCPTool } from '../../types/index.ts';
|
| 5 |
|
| 6 |
type ChatInputProps = {
|
| 7 |
+
onSubmit?: (message: string, selectedTool?: string | null, stance?: 'positive' | 'negative') => void;
|
| 8 |
+
onAudioSubmit?: (audioBlob: Blob, selectedTool?: string | null, stance?: 'positive' | 'negative') => void;
|
| 9 |
placeholder?: string;
|
| 10 |
};
|
| 11 |
|
|
|
|
| 14 |
return value && typeof value === 'object' && typeof value.name === 'string';
|
| 15 |
};
|
| 16 |
|
| 17 |
+
// Allowed tools - only these 3 will be shown
|
| 18 |
+
const ALLOWED_TOOLS = ['detect stance', 'generate argument', 'extract topic'];
|
| 19 |
+
|
| 20 |
+
// Helper function to check if a tool name matches one of the allowed tools
|
| 21 |
+
const isAllowedTool = (toolName: string): boolean => {
|
| 22 |
+
const toolLower = toolName.toLowerCase();
|
| 23 |
+
return ALLOWED_TOOLS.some(allowed =>
|
| 24 |
+
toolLower.includes(allowed.split(' ')[0]) &&
|
| 25 |
+
toolLower.includes(allowed.split(' ')[1])
|
| 26 |
+
);
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
// Helper function to normalize tool name to standard format
|
| 30 |
+
const normalizeToolName = (toolName: string): string => {
|
| 31 |
+
const toolLower = toolName.toLowerCase();
|
| 32 |
+
if (toolLower.includes('detect') && toolLower.includes('stance')) {
|
| 33 |
+
return 'detect stance';
|
| 34 |
+
}
|
| 35 |
+
if (toolLower.includes('generate') && toolLower.includes('argument')) {
|
| 36 |
+
return 'generate argument';
|
| 37 |
+
}
|
| 38 |
+
if (toolLower.includes('extract') && toolLower.includes('topic')) {
|
| 39 |
+
return 'extract topic';
|
| 40 |
+
}
|
| 41 |
+
return toolName;
|
| 42 |
+
};
|
| 43 |
+
|
| 44 |
const ChatInput = ({ onSubmit, onAudioSubmit, placeholder = 'Ask a follow-up...' }: ChatInputProps) => {
|
| 45 |
const [input, setInput] = useState('');
|
| 46 |
const [isRecording, setIsRecording] = useState(false);
|
| 47 |
const [showToolsDropdown, setShowToolsDropdown] = useState(false);
|
| 48 |
const [selectedTool, setSelectedTool] = useState<string | null>(null);
|
| 49 |
+
const [selectedStance, setSelectedStance] = useState<'positive' | 'negative' | null>(null);
|
| 50 |
const [searchQuery, setSearchQuery] = useState('');
|
| 51 |
const [focusedIndex, setFocusedIndex] = useState(-1);
|
| 52 |
const [dropdownPosition, setDropdownPosition] = useState<'below' | 'above'>('below');
|
|
|
|
| 64 |
const recordingTimerRef = useRef<NodeJS.Timeout | null>(null);
|
| 65 |
const { tools, loading, error, refetch } = useMCPTools();
|
| 66 |
|
| 67 |
+
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
| 68 |
e.preventDefault();
|
| 69 |
+
e.stopPropagation();
|
| 70 |
if (input.trim()) {
|
| 71 |
if (onSubmit) {
|
| 72 |
+
onSubmit(input, selectedTool, selectedStance || undefined);
|
| 73 |
}
|
| 74 |
console.log('Submitted:', input);
|
| 75 |
setInput('');
|
| 76 |
+
// Reset stance after submit if generate argument tool
|
| 77 |
+
if (selectedTool && normalizeToolName(selectedTool) === 'generate argument') {
|
| 78 |
+
setSelectedStance(null);
|
| 79 |
+
}
|
| 80 |
}
|
| 81 |
+
return false;
|
| 82 |
};
|
| 83 |
|
| 84 |
const handleMicClick = async () => {
|
|
|
|
| 241 |
|
| 242 |
// Submit the recorded audio if available
|
| 243 |
if (audioBlob && onAudioSubmit) {
|
| 244 |
+
onAudioSubmit(audioBlob, selectedTool, selectedStance || undefined);
|
| 245 |
+
// Reset stance after submit if generate argument tool
|
| 246 |
+
if (selectedTool && normalizeToolName(selectedTool) === 'generate argument') {
|
| 247 |
+
setSelectedStance(null);
|
| 248 |
+
}
|
| 249 |
}
|
| 250 |
|
| 251 |
// Clean up and return to normal chat mode
|
|
|
|
| 556 |
e.preventDefault();
|
| 557 |
if (input.trim()) {
|
| 558 |
if (onSubmit) {
|
| 559 |
+
onSubmit(input, selectedTool, selectedStance || undefined);
|
| 560 |
}
|
| 561 |
setInput('');
|
| 562 |
+
// Reset stance after submit if generate argument tool
|
| 563 |
+
if (selectedTool && normalizeToolName(selectedTool) === 'generate argument') {
|
| 564 |
+
setSelectedStance(null);
|
| 565 |
+
}
|
| 566 |
}
|
| 567 |
}
|
| 568 |
}}
|
|
|
|
| 576 |
}}
|
| 577 |
/>
|
| 578 |
|
| 579 |
+
{/* Stance selection buttons for generate argument tool */}
|
| 580 |
+
{selectedTool && normalizeToolName(selectedTool) === 'generate argument' && (
|
| 581 |
+
<div className="mt-3 flex items-center gap-2">
|
| 582 |
+
<span className="text-xs font-medium text-zinc-600 dark:text-zinc-400">Select stance:</span>
|
| 583 |
+
<button
|
| 584 |
+
type="button"
|
| 585 |
+
onClick={() => setSelectedStance(selectedStance === 'positive' ? null : 'positive')}
|
| 586 |
+
className={`px-3 py-1.5 text-xs rounded-full font-medium transition-all ${
|
| 587 |
+
selectedStance === 'positive'
|
| 588 |
+
? 'bg-emerald-500 text-white shadow-md'
|
| 589 |
+
: 'bg-emerald-100 text-emerald-800 hover:bg-emerald-200 dark:bg-emerald-900/40 dark:text-emerald-200 dark:hover:bg-emerald-900/60'
|
| 590 |
+
}`}
|
| 591 |
+
>
|
| 592 |
+
Positive
|
| 593 |
+
</button>
|
| 594 |
+
<button
|
| 595 |
+
type="button"
|
| 596 |
+
onClick={() => setSelectedStance(selectedStance === 'negative' ? null : 'negative')}
|
| 597 |
+
className={`px-3 py-1.5 text-xs rounded-full font-medium transition-all ${
|
| 598 |
+
selectedStance === 'negative'
|
| 599 |
+
? 'bg-rose-500 text-white shadow-md'
|
| 600 |
+
: 'bg-rose-100 text-rose-800 hover:bg-rose-200 dark:bg-rose-900/40 dark:text-rose-200 dark:hover:bg-rose-900/60'
|
| 601 |
+
}`}
|
| 602 |
+
>
|
| 603 |
+
Negative
|
| 604 |
+
</button>
|
| 605 |
+
</div>
|
| 606 |
+
)}
|
| 607 |
+
|
| 608 |
<div className="flex items-center justify-between mt-8">
|
| 609 |
<div className="flex items-center gap-2">
|
| 610 |
<button
|
|
|
|
| 690 |
</div>
|
| 691 |
</div>
|
| 692 |
</div>
|
| 693 |
+
) : tools.filter(isMCPTool).filter(tool => isAllowedTool(tool.name)).length === 0 ? (
|
| 694 |
<div className="px-4 py-6">
|
| 695 |
<div className="flex flex-col items-center gap-3 text-center">
|
| 696 |
<div className="h-12 w-12 rounded-full bg-zinc-100 dark:bg-zinc-800 flex items-center justify-center">
|
|
|
|
| 706 |
<div className="p-2">
|
| 707 |
{tools
|
| 708 |
.filter(isMCPTool)
|
| 709 |
+
.filter(tool => isAllowedTool(tool.name))
|
| 710 |
.filter(tool =>
|
| 711 |
tool.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
| 712 |
(tool.description && tool.description.toLowerCase().includes(searchQuery.toLowerCase()))
|
|
|
|
| 723 |
: 'hover:bg-zinc-50 dark:hover:bg-zinc-800/50 border border-transparent'
|
| 724 |
}`}
|
| 725 |
onClick={() => {
|
| 726 |
+
const newTool = tool.name === selectedTool ? null : tool.name;
|
| 727 |
+
setSelectedTool(newTool);
|
| 728 |
+
// Reset stance when tool changes
|
| 729 |
+
if (newTool && normalizeToolName(newTool) !== 'generate argument') {
|
| 730 |
+
setSelectedStance(null);
|
| 731 |
+
}
|
| 732 |
setShowToolsDropdown(false);
|
| 733 |
setFocusedIndex(-1);
|
| 734 |
}}
|
|
|
|
| 767 |
type="button"
|
| 768 |
onClick={() => {
|
| 769 |
setSelectedTool(null);
|
| 770 |
+
setSelectedStance(null);
|
| 771 |
setShowToolsDropdown(false);
|
| 772 |
setFocusedIndex(-1);
|
| 773 |
}}
|
|
|
|
| 799 |
|
| 800 |
<button
|
| 801 |
type="submit"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 802 |
disabled={!input.trim()}
|
| 803 |
className="h-8 w-8 p-0 bg-zinc-300 dark:bg-zinc-700 hover:bg-zinc-400 dark:hover:bg-zinc-600 disabled:bg-zinc-200 dark:disabled:bg-zinc-800 disabled:text-zinc-400 dark:disabled:text-zinc-500 text-zinc-800 dark:text-white rounded-lg transition-all duration-200 hover:scale-110 disabled:hover:scale-100 flex items-center justify-center disabled:cursor-not-allowed"
|
| 804 |
>
|
src/app/components/chat/MessageList.tsx
CHANGED
|
@@ -28,7 +28,50 @@ const MessageList = ({ messages, isLoading = false, error = null, onRetry }: Mes
|
|
| 28 |
});
|
| 29 |
};
|
| 30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
return (
|
|
|
|
|
|
|
| 32 |
<div className="flex-1 overflow-y-auto px-4 py-6 space-y-4">
|
| 33 |
{messages.length === 0 && !isLoading && (
|
| 34 |
<div className="flex flex-col items-center justify-center h-full text-center">
|
|
@@ -48,7 +91,8 @@ const MessageList = ({ messages, isLoading = false, error = null, onRetry }: Mes
|
|
| 48 |
</div>
|
| 49 |
)}
|
| 50 |
|
| 51 |
-
{messages.map((message) =>
|
|
|
|
| 52 |
<div
|
| 53 |
key={message.id}
|
| 54 |
className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}
|
|
@@ -58,22 +102,47 @@ const MessageList = ({ messages, isLoading = false, error = null, onRetry }: Mes
|
|
| 58 |
message.role === 'user'
|
| 59 |
? 'bg-teal-500 text-white ml-12'
|
| 60 |
: 'bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100 mr-12'
|
| 61 |
-
}`}
|
| 62 |
>
|
| 63 |
{message.audioUrl ? (
|
| 64 |
-
// Audio message display
|
| 65 |
<div>
|
| 66 |
-
<AudioPlayer
|
| 67 |
-
src={message.audioUrl}
|
| 68 |
-
/>
|
| 69 |
</div>
|
| 70 |
) : (
|
| 71 |
// Regular text message
|
| 72 |
<div>
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
</div>
|
| 75 |
)}
|
| 76 |
-
|
| 77 |
className={`text-xs mt-1 ${
|
| 78 |
message.role === 'user'
|
| 79 |
? 'text-teal-100'
|
|
@@ -84,7 +153,7 @@ const MessageList = ({ messages, isLoading = false, error = null, onRetry }: Mes
|
|
| 84 |
</div>
|
| 85 |
</div>
|
| 86 |
</div>
|
| 87 |
-
))}
|
| 88 |
|
| 89 |
{isLoading && (
|
| 90 |
<div className="flex justify-start">
|
|
|
|
| 28 |
});
|
| 29 |
};
|
| 30 |
|
| 31 |
+
const getToolClasses = (message: ChatMessage) => {
|
| 32 |
+
if (message.role !== 'assistant' || !message.tool) return '';
|
| 33 |
+
|
| 34 |
+
const toolLower = message.tool.toLowerCase();
|
| 35 |
+
|
| 36 |
+
// Match tool names flexibly (case-insensitive, handles variations)
|
| 37 |
+
if (toolLower.includes('detect') && toolLower.includes('stance')) {
|
| 38 |
+
return 'border-l-4 border-blue-400 pl-3 bg-blue-50/30 dark:bg-blue-900/10';
|
| 39 |
+
}
|
| 40 |
+
if (toolLower.includes('generate') && toolLower.includes('argument')) {
|
| 41 |
+
return 'border-l-4 border-purple-400 pl-3 bg-purple-50/30 dark:bg-purple-900/10';
|
| 42 |
+
}
|
| 43 |
+
if (toolLower.includes('extract') && toolLower.includes('topic')) {
|
| 44 |
+
return 'border-l-4 border-emerald-400 pl-3 bg-emerald-50/30 dark:bg-emerald-900/10';
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
// Default styling for other tools
|
| 48 |
+
return 'border-l-4 border-teal-400 pl-3 bg-teal-50/30 dark:bg-teal-900/10';
|
| 49 |
+
};
|
| 50 |
+
|
| 51 |
+
const getToolLabel = (tool: string | null | undefined): string => {
|
| 52 |
+
if (!tool) return '';
|
| 53 |
+
|
| 54 |
+
const toolLower = tool.toLowerCase();
|
| 55 |
+
|
| 56 |
+
if (toolLower.includes('detect') && toolLower.includes('stance')) {
|
| 57 |
+
return 'Detect Stance';
|
| 58 |
+
}
|
| 59 |
+
if (toolLower.includes('generate') && toolLower.includes('argument')) {
|
| 60 |
+
return 'Generate Argument';
|
| 61 |
+
}
|
| 62 |
+
if (toolLower.includes('extract') && toolLower.includes('topic')) {
|
| 63 |
+
return 'Extract Topic';
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
// Return formatted tool name (capitalize first letter of each word)
|
| 67 |
+
return tool.split(/[\s_-]+/).map(word =>
|
| 68 |
+
word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
|
| 69 |
+
).join(' ');
|
| 70 |
+
};
|
| 71 |
+
|
| 72 |
return (
|
| 73 |
+
|
| 74 |
+
|
| 75 |
<div className="flex-1 overflow-y-auto px-4 py-6 space-y-4">
|
| 76 |
{messages.length === 0 && !isLoading && (
|
| 77 |
<div className="flex flex-col items-center justify-center h-full text-center">
|
|
|
|
| 91 |
</div>
|
| 92 |
)}
|
| 93 |
|
| 94 |
+
{messages.map((message) => {
|
| 95 |
+
return(
|
| 96 |
<div
|
| 97 |
key={message.id}
|
| 98 |
className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}
|
|
|
|
| 102 |
message.role === 'user'
|
| 103 |
? 'bg-teal-500 text-white ml-12'
|
| 104 |
: 'bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100 mr-12'
|
| 105 |
+
}${getToolClasses(message)}`} // Apply tool-specific classes
|
| 106 |
>
|
| 107 |
{message.audioUrl ? (
|
| 108 |
+
// Audio message display
|
| 109 |
<div>
|
| 110 |
+
<AudioPlayer src={message.audioUrl} />
|
|
|
|
|
|
|
| 111 |
</div>
|
| 112 |
) : (
|
| 113 |
// Regular text message
|
| 114 |
<div>
|
| 115 |
+
{message.tool && message.role === 'assistant' && (
|
| 116 |
+
<div className="mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
|
| 117 |
+
{getToolLabel(message.tool)}
|
| 118 |
+
</div>
|
| 119 |
+
)}
|
| 120 |
+
|
| 121 |
+
<div className="whitespace-pre-wrap break-words">
|
| 122 |
+
{message.content}
|
| 123 |
+
</div>
|
| 124 |
+
|
| 125 |
+
{message.role === 'assistant' && message.tool &&
|
| 126 |
+
message.tool.toLowerCase().includes('generate') &&
|
| 127 |
+
message.tool.toLowerCase().includes('argument') && (
|
| 128 |
+
<div className="mt-3 flex gap-2">
|
| 129 |
+
<button
|
| 130 |
+
type="button"
|
| 131 |
+
className="px-3 py-1 text-xs rounded-full bg-emerald-100 text-emerald-800 hover:bg-emerald-200 dark:bg-emerald-900/40 dark:text-emerald-200 transition-colors"
|
| 132 |
+
>
|
| 133 |
+
Positive stance
|
| 134 |
+
</button>
|
| 135 |
+
<button
|
| 136 |
+
type="button"
|
| 137 |
+
className="px-3 py-1 text-xs rounded-full bg-rose-100 text-rose-800 hover:bg-rose-200 dark:bg-rose-900/40 dark:text-rose-200 transition-colors"
|
| 138 |
+
>
|
| 139 |
+
Negative stance
|
| 140 |
+
</button>
|
| 141 |
+
</div>
|
| 142 |
+
)}
|
| 143 |
</div>
|
| 144 |
)}
|
| 145 |
+
<div
|
| 146 |
className={`text-xs mt-1 ${
|
| 147 |
message.role === 'user'
|
| 148 |
? 'text-teal-100'
|
|
|
|
| 153 |
</div>
|
| 154 |
</div>
|
| 155 |
</div>
|
| 156 |
+
)})}
|
| 157 |
|
| 158 |
{isLoading && (
|
| 159 |
<div className="flex justify-start">
|
src/app/hooks/useChat.ts
CHANGED
|
@@ -28,6 +28,16 @@ export const useChat = () => {
|
|
| 28 |
|
| 29 |
|
| 30 |
const extractTopicAndPosition = useCallback(async (userInput: string): Promise<{ topic: string; position: string }> => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
const extractionPrompt = `Extract the debate topic and position from the following text. Return ONLY a JSON object with "topic" and "position" keys. The position should be either "positive" (in favor) or "negative" (against).
|
| 32 |
|
| 33 |
Text: "${userInput}"
|
|
@@ -38,16 +48,33 @@ Example output:
|
|
| 38 |
try {
|
| 39 |
const response = await sendChatMessageStream([
|
| 40 |
{ id: generateId(), role: 'user', content: extractionPrompt, timestamp: new Date() }
|
| 41 |
-
], () => {});
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
if (jsonMatch) {
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
}
|
| 48 |
-
|
|
|
|
| 49 |
} catch (error) {
|
| 50 |
-
|
|
|
|
| 51 |
}
|
| 52 |
}, []);
|
| 53 |
|
|
@@ -57,9 +84,11 @@ Example output:
|
|
| 57 |
// Add user audio message
|
| 58 |
const userMessage: Omit<ChatMessage, 'id' | 'timestamp'> = {
|
| 59 |
role: 'user',
|
| 60 |
-
content: 'Audio message sent',
|
| 61 |
-
audioUrl: URL.createObjectURL(audioBlob),
|
|
|
|
| 62 |
};
|
|
|
|
| 63 |
addMessage(userMessage);
|
| 64 |
|
| 65 |
// Set loading state
|
|
@@ -121,12 +150,14 @@ Example output:
|
|
| 121 |
}
|
| 122 |
}, [addMessage]);
|
| 123 |
|
| 124 |
-
const sendMessage = useCallback(async (content: string, selectedTool?: string | null) => {
|
| 125 |
// Add user message
|
| 126 |
const userMessage: Omit<ChatMessage, 'id' | 'timestamp'> = {
|
| 127 |
role: 'user',
|
| 128 |
content,
|
|
|
|
| 129 |
};
|
|
|
|
| 130 |
addMessage(userMessage);
|
| 131 |
|
| 132 |
// Set loading state
|
|
@@ -141,8 +172,20 @@ Example output:
|
|
| 141 |
|
| 142 |
if (isGenerateArgumentTool) {
|
| 143 |
console.log('Generate argument tool detected:', selectedTool);
|
| 144 |
-
// Extract topic and position
|
| 145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
|
| 147 |
// Call the external API
|
| 148 |
const argumentResponse = await generateEnhancedArgument({ topic, position });
|
|
@@ -151,7 +194,9 @@ Example output:
|
|
| 151 |
const assistantMessage: Omit<ChatMessage, 'id' | 'timestamp'> = {
|
| 152 |
role: 'assistant',
|
| 153 |
content: argumentResponse.enhanced_argument,
|
|
|
|
| 154 |
};
|
|
|
|
| 155 |
addMessage(assistantMessage);
|
| 156 |
} else {
|
| 157 |
// Regular chat - use n8n webhook /debate-assistant endpoint
|
|
@@ -191,6 +236,7 @@ Example output:
|
|
| 191 |
|
| 192 |
// Extract final_argument from response
|
| 193 |
const finalArgument = data?.final_argument || data?.result?.result?.[0]?.text || 'No response received';
|
|
|
|
| 194 |
|
| 195 |
// Parse if final_argument is a JSON string
|
| 196 |
let finalContent = finalArgument;
|
|
@@ -207,6 +253,7 @@ Example output:
|
|
| 207 |
const assistantMessage: Omit<ChatMessage, 'id' | 'timestamp'> = {
|
| 208 |
role: 'assistant',
|
| 209 |
content: finalContent,
|
|
|
|
| 210 |
};
|
| 211 |
addMessage(assistantMessage);
|
| 212 |
}
|
|
@@ -227,7 +274,7 @@ Example output:
|
|
| 227 |
const lastUserMessage = [...state.messages]
|
| 228 |
.reverse()
|
| 229 |
.find(msg => msg.role === 'user');
|
| 230 |
-
|
| 231 |
if (lastUserMessage) {
|
| 232 |
// Remove the last failed assistant message if exists
|
| 233 |
setState(prev => {
|
|
@@ -241,7 +288,7 @@ Example output:
|
|
| 241 |
}
|
| 242 |
return { ...prev, error: null };
|
| 243 |
});
|
| 244 |
-
|
| 245 |
// Resend the user message
|
| 246 |
sendMessage(lastUserMessage.content);
|
| 247 |
}
|
|
|
|
| 28 |
|
| 29 |
|
| 30 |
const extractTopicAndPosition = useCallback(async (userInput: string): Promise<{ topic: string; position: string }> => {
|
| 31 |
+
// Default fallback values
|
| 32 |
+
const fallback = {
|
| 33 |
+
topic: userInput.trim().slice(0, 100) || 'General Discussion',
|
| 34 |
+
position: 'positive'
|
| 35 |
+
};
|
| 36 |
+
|
| 37 |
+
if (!userInput || !userInput.trim()) {
|
| 38 |
+
return fallback;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
const extractionPrompt = `Extract the debate topic and position from the following text. Return ONLY a JSON object with "topic" and "position" keys. The position should be either "positive" (in favor) or "negative" (against).
|
| 42 |
|
| 43 |
Text: "${userInput}"
|
|
|
|
| 48 |
try {
|
| 49 |
const response = await sendChatMessageStream([
|
| 50 |
{ id: generateId(), role: 'user', content: extractionPrompt, timestamp: new Date() }
|
| 51 |
+
], () => { });
|
| 52 |
+
|
| 53 |
+
if (!response) {
|
| 54 |
+
console.warn('Empty response from extraction API');
|
| 55 |
+
return fallback;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
// Try to extract JSON from the response (handles markdown blocks and extra text)
|
| 59 |
+
const jsonMatch = response.match(/\{[\s\S]*?\}/);
|
| 60 |
if (jsonMatch) {
|
| 61 |
+
try {
|
| 62 |
+
const parsed = JSON.parse(jsonMatch[0]);
|
| 63 |
+
return {
|
| 64 |
+
topic: parsed.topic || fallback.topic,
|
| 65 |
+
position: (parsed.position?.toLowerCase().includes('neg')) ? 'negative' : 'positive'
|
| 66 |
+
};
|
| 67 |
+
} catch (parseError) {
|
| 68 |
+
console.error('Failed to parse extracted JSON:', parseError, 'Raw match:', jsonMatch[0]);
|
| 69 |
+
}
|
| 70 |
+
} else {
|
| 71 |
+
console.warn('No JSON structure found in extraction response:', response);
|
| 72 |
}
|
| 73 |
+
|
| 74 |
+
return fallback;
|
| 75 |
} catch (error) {
|
| 76 |
+
console.error('Error in extractTopicAndPosition process:', error);
|
| 77 |
+
return fallback;
|
| 78 |
}
|
| 79 |
}, []);
|
| 80 |
|
|
|
|
| 84 |
// Add user audio message
|
| 85 |
const userMessage: Omit<ChatMessage, 'id' | 'timestamp'> = {
|
| 86 |
role: 'user',
|
| 87 |
+
content: 'Audio message sent',
|
| 88 |
+
audioUrl: URL.createObjectURL(audioBlob),
|
| 89 |
+
tool: selectedTool ?? null,
|
| 90 |
};
|
| 91 |
+
|
| 92 |
addMessage(userMessage);
|
| 93 |
|
| 94 |
// Set loading state
|
|
|
|
| 150 |
}
|
| 151 |
}, [addMessage]);
|
| 152 |
|
| 153 |
+
const sendMessage = useCallback(async (content: string, selectedTool?: string | null, stance?: 'positive' | 'negative') => {
|
| 154 |
// Add user message
|
| 155 |
const userMessage: Omit<ChatMessage, 'id' | 'timestamp'> = {
|
| 156 |
role: 'user',
|
| 157 |
content,
|
| 158 |
+
tool: selectedTool ?? null,
|
| 159 |
};
|
| 160 |
+
|
| 161 |
addMessage(userMessage);
|
| 162 |
|
| 163 |
// Set loading state
|
|
|
|
| 172 |
|
| 173 |
if (isGenerateArgumentTool) {
|
| 174 |
console.log('Generate argument tool detected:', selectedTool);
|
| 175 |
+
// Extract topic and position from content
|
| 176 |
+
let topic: string;
|
| 177 |
+
let position: string;
|
| 178 |
+
|
| 179 |
+
try {
|
| 180 |
+
const extracted = await extractTopicAndPosition(content);
|
| 181 |
+
topic = extracted.topic;
|
| 182 |
+
// Use provided stance if available, otherwise use extracted position
|
| 183 |
+
position = stance || extracted.position;
|
| 184 |
+
} catch (error) {
|
| 185 |
+
console.error('Unexpected error in topic extraction:', error);
|
| 186 |
+
topic = content.slice(0, 100) || 'General Discussion';
|
| 187 |
+
position = stance || 'positive';
|
| 188 |
+
}
|
| 189 |
|
| 190 |
// Call the external API
|
| 191 |
const argumentResponse = await generateEnhancedArgument({ topic, position });
|
|
|
|
| 194 |
const assistantMessage: Omit<ChatMessage, 'id' | 'timestamp'> = {
|
| 195 |
role: 'assistant',
|
| 196 |
content: argumentResponse.enhanced_argument,
|
| 197 |
+
tool: selectedTool ?? 'generate_argument',
|
| 198 |
};
|
| 199 |
+
|
| 200 |
addMessage(assistantMessage);
|
| 201 |
} else {
|
| 202 |
// Regular chat - use n8n webhook /debate-assistant endpoint
|
|
|
|
| 236 |
|
| 237 |
// Extract final_argument from response
|
| 238 |
const finalArgument = data?.final_argument || data?.result?.result?.[0]?.text || 'No response received';
|
| 239 |
+
const assistantTool = data?.tool_name ?? selectedTool ?? 'debate-assistant';
|
| 240 |
|
| 241 |
// Parse if final_argument is a JSON string
|
| 242 |
let finalContent = finalArgument;
|
|
|
|
| 253 |
const assistantMessage: Omit<ChatMessage, 'id' | 'timestamp'> = {
|
| 254 |
role: 'assistant',
|
| 255 |
content: finalContent,
|
| 256 |
+
tool: assistantTool,
|
| 257 |
};
|
| 258 |
addMessage(assistantMessage);
|
| 259 |
}
|
|
|
|
| 274 |
const lastUserMessage = [...state.messages]
|
| 275 |
.reverse()
|
| 276 |
.find(msg => msg.role === 'user');
|
| 277 |
+
|
| 278 |
if (lastUserMessage) {
|
| 279 |
// Remove the last failed assistant message if exists
|
| 280 |
setState(prev => {
|
|
|
|
| 288 |
}
|
| 289 |
return { ...prev, error: null };
|
| 290 |
});
|
| 291 |
+
|
| 292 |
// Resend the user message
|
| 293 |
sendMessage(lastUserMessage.content);
|
| 294 |
}
|
src/app/pages/ChatPage.tsx
CHANGED
|
@@ -6,11 +6,11 @@ import { useChat } from '../hooks/useChat.ts';
|
|
| 6 |
const ChatPage = () => {
|
| 7 |
const { messages, isLoading, error, sendMessage, sendAudioMessage, retryLastMessage } = useChat();
|
| 8 |
|
| 9 |
-
const handleMessageSubmit = (message: string, selectedTool?: string | null) => {
|
| 10 |
-
sendMessage(message, selectedTool);
|
| 11 |
};
|
| 12 |
|
| 13 |
-
const handleAudioSubmit = (audioBlob: Blob, selectedTool?: string | null) => {
|
| 14 |
sendAudioMessage(audioBlob, selectedTool);
|
| 15 |
};
|
| 16 |
|
|
|
|
| 6 |
const ChatPage = () => {
|
| 7 |
const { messages, isLoading, error, sendMessage, sendAudioMessage, retryLastMessage } = useChat();
|
| 8 |
|
| 9 |
+
const handleMessageSubmit = (message: string, selectedTool?: string | null, stance?: 'positive' | 'negative') => {
|
| 10 |
+
sendMessage(message, selectedTool, stance);
|
| 11 |
};
|
| 12 |
|
| 13 |
+
const handleAudioSubmit = (audioBlob: Blob, selectedTool?: string | null, stance?: 'positive' | 'negative') => {
|
| 14 |
sendAudioMessage(audioBlob, selectedTool);
|
| 15 |
};
|
| 16 |
|
src/app/types/chat.types.ts
CHANGED
|
@@ -6,6 +6,7 @@ export type ChatMessage = {
|
|
| 6 |
content: string;
|
| 7 |
audioUrl?: string; // URL for audio messages
|
| 8 |
timestamp: Date;
|
|
|
|
| 9 |
};
|
| 10 |
|
| 11 |
export type ChatState = {
|
|
|
|
| 6 |
content: string;
|
| 7 |
audioUrl?: string; // URL for audio messages
|
| 8 |
timestamp: Date;
|
| 9 |
+
tool?: string | null;
|
| 10 |
};
|
| 11 |
|
| 12 |
export type ChatState = {
|