Fully migrate off Gemini: shared Ollama client (gemma4:26b @ shadow-death), health reports llm backend, drop @google/genai
This commit is contained in:
BIN
._README.md
Normal file
BIN
._README.md
Normal file
Binary file not shown.
11
README.md
11
README.md
@@ -40,11 +40,18 @@ npm run dev # tsx server.ts with Vite HMR
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Set `GEMINI_API_KEY` in `.env.local` to enable the AI prompt-to-tool generator. All other features run without any external key.
|
AI features (tool generation, web-search synthesis, text summarization) run on a **local Ollama model** — `gemma4:26b` on `shadow-death` (`http://10.30.20.128:11434`) by default. No cloud API key required.
|
||||||
|
|
||||||
|
Override via environment variables:
|
||||||
|
|
||||||
|
| Variable | Default |
|
||||||
|
|----------|---------|
|
||||||
|
| `OLLAMA_HOST` | `http://10.30.20.128:11434` |
|
||||||
|
| `OLLAMA_MODEL` | `gemma4:26b` |
|
||||||
|
|
||||||
## Stack
|
## Stack
|
||||||
|
|
||||||
React 19 · Vite 6 · Express 4 · TypeScript · Tailwind CSS 4 · Recharts · `@google/genai`
|
React 19 · Vite 6 · Express 4 · TypeScript · Tailwind CSS 4 · Recharts · Ollama (local LLM)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
409
package-lock.json
generated
409
package-lock.json
generated
@@ -8,7 +8,6 @@
|
|||||||
"name": "react-example",
|
"name": "react-example",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google/genai": "^2.4.0",
|
|
||||||
"@tailwindcss/vite": "^4.1.14",
|
"@tailwindcss/vite": "^4.1.14",
|
||||||
"@vitejs/plugin-react": "^5.0.4",
|
"@vitejs/plugin-react": "^5.0.4",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
@@ -710,30 +709,6 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@google/genai": {
|
|
||||||
"version": "2.17.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@google/genai/-/genai-2.17.1.tgz",
|
|
||||||
"integrity": "sha512-CdZ3M/titoH81hXXkvOikrOW26bC9IXh9iYT7u+r+5p7wi1LnMEnB0AbJfDeWAkjuneP4oJ299BtCt6twmORWg==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"google-auth-library": "^10.3.0",
|
|
||||||
"p-retry": "^4.6.2",
|
|
||||||
"protobufjs": "^7.5.4",
|
|
||||||
"ws": "^8.18.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20.0.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@modelcontextprotocol/sdk": "^1.25.2"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"@modelcontextprotocol/sdk": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.13",
|
"version": "0.3.13",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||||
@@ -795,63 +770,6 @@
|
|||||||
"node": "^22.20 || ^24.12 || >=25"
|
"node": "^22.20 || ^24.12 || >=25"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@protobufjs/aspromise": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
|
|
||||||
"license": "BSD-3-Clause"
|
|
||||||
},
|
|
||||||
"node_modules/@protobufjs/base64": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
|
|
||||||
"license": "BSD-3-Clause"
|
|
||||||
},
|
|
||||||
"node_modules/@protobufjs/codegen": {
|
|
||||||
"version": "2.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz",
|
|
||||||
"integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==",
|
|
||||||
"license": "BSD-3-Clause"
|
|
||||||
},
|
|
||||||
"node_modules/@protobufjs/eventemitter": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==",
|
|
||||||
"license": "BSD-3-Clause"
|
|
||||||
},
|
|
||||||
"node_modules/@protobufjs/fetch": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==",
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"dependencies": {
|
|
||||||
"@protobufjs/aspromise": "^1.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@protobufjs/float": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
|
|
||||||
"license": "BSD-3-Clause"
|
|
||||||
},
|
|
||||||
"node_modules/@protobufjs/path": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
|
|
||||||
"license": "BSD-3-Clause"
|
|
||||||
},
|
|
||||||
"node_modules/@protobufjs/pool": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
|
|
||||||
"license": "BSD-3-Clause"
|
|
||||||
},
|
|
||||||
"node_modules/@protobufjs/utf8": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==",
|
|
||||||
"license": "BSD-3-Clause"
|
|
||||||
},
|
|
||||||
"node_modules/@reduxjs/toolkit": {
|
"node_modules/@reduxjs/toolkit": {
|
||||||
"version": "2.12.0",
|
"version": "2.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.12.0.tgz",
|
||||||
@@ -1653,6 +1571,7 @@
|
|||||||
"version": "22.20.1",
|
"version": "22.20.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz",
|
||||||
"integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==",
|
"integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~6.21.0"
|
"undici-types": "~6.21.0"
|
||||||
@@ -1672,12 +1591,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/retry": {
|
|
||||||
"version": "0.12.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
|
|
||||||
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@types/send": {
|
"node_modules/@types/send": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz",
|
||||||
@@ -1750,15 +1663,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/agent-base": {
|
|
||||||
"version": "7.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
|
||||||
"integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/array-flatten": {
|
"node_modules/array-flatten": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
@@ -1802,26 +1706,6 @@
|
|||||||
"postcss": "^8.1.0"
|
"postcss": "^8.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/base64-js": {
|
|
||||||
"version": "1.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
|
||||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/feross"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "patreon",
|
|
||||||
"url": "https://www.patreon.com/feross"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "consulting",
|
|
||||||
"url": "https://feross.org/support"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/baseline-browser-mapping": {
|
"node_modules/baseline-browser-mapping": {
|
||||||
"version": "2.11.14",
|
"version": "2.11.14",
|
||||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.14.tgz",
|
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.14.tgz",
|
||||||
@@ -1834,15 +1718,6 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/bignumber.js": {
|
|
||||||
"version": "9.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
|
|
||||||
"integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/body-parser": {
|
"node_modules/body-parser": {
|
||||||
"version": "1.20.6",
|
"version": "1.20.6",
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz",
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz",
|
||||||
@@ -1915,12 +1790,6 @@
|
|||||||
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/buffer-equal-constant-time": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
|
||||||
"license": "BSD-3-Clause"
|
|
||||||
},
|
|
||||||
"node_modules/bytes": {
|
"node_modules/bytes": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||||
@@ -2151,15 +2020,6 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/data-uri-to-buffer": {
|
|
||||||
"version": "4.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
|
||||||
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.4.3",
|
"version": "4.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||||
@@ -2237,15 +2097,6 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ecdsa-sig-formatter": {
|
|
||||||
"version": "1.0.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
|
||||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"safe-buffer": "^5.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ee-first": {
|
"node_modules/ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
@@ -2453,12 +2304,6 @@
|
|||||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/extend": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/fdir": {
|
"node_modules/fdir": {
|
||||||
"version": "6.5.0",
|
"version": "6.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||||
@@ -2476,29 +2321,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fetch-blob": {
|
|
||||||
"version": "3.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
|
||||||
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/jimmywarting"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "paypal",
|
|
||||||
"url": "https://paypal.me/jimmywarting"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"node-domexception": "^1.0.0",
|
|
||||||
"web-streams-polyfill": "^3.0.3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.20 || >= 14.13"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/finalhandler": {
|
"node_modules/finalhandler": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
|
||||||
@@ -2532,18 +2354,6 @@
|
|||||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/formdata-polyfill": {
|
|
||||||
"version": "4.0.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
|
||||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"fetch-blob": "^3.1.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.20.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/forwarded": {
|
"node_modules/forwarded": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||||
@@ -2626,34 +2436,6 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/gaxios": {
|
|
||||||
"version": "7.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.3.1.tgz",
|
|
||||||
"integrity": "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"extend": "^3.0.2",
|
|
||||||
"https-proxy-agent": "^7.0.1",
|
|
||||||
"node-fetch": "^3.3.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/gcp-metadata": {
|
|
||||||
"version": "8.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz",
|
|
||||||
"integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"gaxios": "^7.0.0",
|
|
||||||
"google-logging-utils": "^1.0.0",
|
|
||||||
"json-bigint": "^1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/gensync": {
|
"node_modules/gensync": {
|
||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||||
@@ -2700,32 +2482,6 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/google-auth-library": {
|
|
||||||
"version": "10.9.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.9.1.tgz",
|
|
||||||
"integrity": "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"base64-js": "^1.3.0",
|
|
||||||
"ecdsa-sig-formatter": "^1.0.11",
|
|
||||||
"gaxios": "^7.1.4",
|
|
||||||
"gcp-metadata": "8.1.2",
|
|
||||||
"google-logging-utils": "1.1.3",
|
|
||||||
"jws": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/google-logging-utils": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz",
|
|
||||||
"integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/gopd": {
|
"node_modules/gopd": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
@@ -2788,19 +2544,6 @@
|
|||||||
"url": "https://opencollective.com/express"
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/https-proxy-agent": {
|
|
||||||
"version": "7.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
|
|
||||||
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"agent-base": "^7.1.2",
|
|
||||||
"debug": "4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
@@ -2874,15 +2617,6 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/json-bigint": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"bignumber.js": "^9.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/json5": {
|
"node_modules/json5": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||||
@@ -2895,27 +2629,6 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jwa": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"buffer-equal-constant-time": "^1.0.1",
|
|
||||||
"ecdsa-sig-formatter": "1.0.11",
|
|
||||||
"safe-buffer": "^5.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/jws": {
|
|
||||||
"version": "4.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
|
|
||||||
"integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"jwa": "^2.0.1",
|
|
||||||
"safe-buffer": "^5.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss": {
|
"node_modules/lightningcss": {
|
||||||
"version": "1.32.0",
|
"version": "1.32.0",
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||||
@@ -3165,12 +2878,6 @@
|
|||||||
"url": "https://opencollective.com/parcel"
|
"url": "https://opencollective.com/parcel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/long": {
|
|
||||||
"version": "5.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
|
||||||
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
|
|
||||||
"license": "Apache-2.0"
|
|
||||||
},
|
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
@@ -3341,44 +3048,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-domexception": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
|
||||||
"deprecated": "Use your platform's native DOMException instead",
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/jimmywarting"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://paypal.me/jimmywarting"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.5.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/node-fetch": {
|
|
||||||
"version": "3.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
|
||||||
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"data-uri-to-buffer": "^4.0.0",
|
|
||||||
"fetch-blob": "^3.1.4",
|
|
||||||
"formdata-polyfill": "^4.0.10"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/node-fetch"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.53",
|
"version": "2.0.53",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz",
|
||||||
@@ -3412,19 +3081,6 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/p-retry": {
|
|
||||||
"version": "4.6.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
|
|
||||||
"integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/retry": "0.12.0",
|
|
||||||
"retry": "^0.13.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/parseurl": {
|
"node_modules/parseurl": {
|
||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||||
@@ -3493,29 +3149,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/protobufjs": {
|
|
||||||
"version": "7.6.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.5.tgz",
|
|
||||||
"integrity": "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==",
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"dependencies": {
|
|
||||||
"@protobufjs/aspromise": "^1.1.2",
|
|
||||||
"@protobufjs/base64": "^1.1.2",
|
|
||||||
"@protobufjs/codegen": "^2.0.5",
|
|
||||||
"@protobufjs/eventemitter": "^1.1.1",
|
|
||||||
"@protobufjs/fetch": "^1.1.1",
|
|
||||||
"@protobufjs/float": "^1.0.2",
|
|
||||||
"@protobufjs/path": "^1.1.2",
|
|
||||||
"@protobufjs/pool": "^1.1.0",
|
|
||||||
"@protobufjs/utf8": "^1.1.1",
|
|
||||||
"@types/node": ">=13.7.0",
|
|
||||||
"long": "^5.3.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/proxy-addr": {
|
"node_modules/proxy-addr": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||||
@@ -3680,15 +3313,6 @@
|
|||||||
"integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==",
|
"integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/retry": {
|
|
||||||
"version": "0.13.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
|
|
||||||
"integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.62.4",
|
"version": "4.62.4",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz",
|
||||||
@@ -4489,6 +4113,7 @@
|
|||||||
"version": "6.21.0",
|
"version": "6.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/unpipe": {
|
"node_modules/unpipe": {
|
||||||
@@ -4653,36 +4278,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/web-streams-polyfill": {
|
|
||||||
"version": "3.3.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
|
||||||
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ws": {
|
|
||||||
"version": "8.21.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",
|
|
||||||
"integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.0.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"bufferutil": "^4.0.1",
|
|
||||||
"utf-8-validate": ">=5.0.2"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"bufferutil": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"utf-8-validate": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/yallist": {
|
"node_modules/yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
"lint": "tsc --noEmit"
|
"lint": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google/genai": "^2.4.0",
|
|
||||||
"@tailwindcss/vite": "^4.1.14",
|
"@tailwindcss/vite": "^4.1.14",
|
||||||
"@vitejs/plugin-react": "^5.0.4",
|
"@vitejs/plugin-react": "^5.0.4",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { generateMCPToolFromPrompt } from './src/server/aiGenerator.js';
|
|||||||
import { mcpWorkflowManager } from './src/server/mcpWorkflows.js';
|
import { mcpWorkflowManager } from './src/server/mcpWorkflows.js';
|
||||||
import { mcpSecurityManager } from './src/server/mcpSecurity.js';
|
import { mcpSecurityManager } from './src/server/mcpSecurity.js';
|
||||||
import { SystemLog, ServerStats } from './src/types.js';
|
import { SystemLog, ServerStats } from './src/types.js';
|
||||||
|
import { OLLAMA_HOST, OLLAMA_MODEL } from './src/server/llmClient.js';
|
||||||
|
|
||||||
// Inject memoryStore reference into tools module
|
// Inject memoryStore reference into tools module
|
||||||
setMemoryStoreRef(memoryStore);
|
setMemoryStoreRef(memoryStore);
|
||||||
@@ -65,7 +66,6 @@ addLog({
|
|||||||
app.get('/api/v1/system/status', (req: Request, res: Response) => {
|
app.get('/api/v1/system/status', (req: Request, res: Response) => {
|
||||||
const uptimeSeconds = Math.floor((Date.now() - startTime) / 1000);
|
const uptimeSeconds = Math.floor((Date.now() - startTime) / 1000);
|
||||||
const avgLatency = totalRequests > 0 ? Math.round(totalLatencySum / totalRequests) : 0;
|
const avgLatency = totalRequests > 0 ? Math.round(totalLatencySum / totalRequests) : 0;
|
||||||
const apiKey = process.env.GEMINI_API_KEY;
|
|
||||||
const servers = mcpRegistry.getServers();
|
const servers = mcpRegistry.getServers();
|
||||||
const activeTools = mcpRegistry.getAllActiveTools();
|
const activeTools = mcpRegistry.getAllActiveTools();
|
||||||
|
|
||||||
@@ -81,7 +81,9 @@ app.get('/api/v1/system/status', (req: Request, res: Response) => {
|
|||||||
totalMCPServersCount: servers.length,
|
totalMCPServersCount: servers.length,
|
||||||
avgLatencyMs: avgLatency,
|
avgLatencyMs: avgLatency,
|
||||||
memoryUsageMb: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
|
memoryUsageMb: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
|
||||||
hasGeminiKey: Boolean(apiKey && apiKey !== 'MY_GEMINI_API_KEY'),
|
llmProvider: 'ollama',
|
||||||
|
llmModel: OLLAMA_MODEL,
|
||||||
|
llmHost: OLLAMA_HOST,
|
||||||
};
|
};
|
||||||
|
|
||||||
res.json(stats);
|
res.json(stats);
|
||||||
|
|||||||
@@ -70,17 +70,13 @@ export const SettingsTab: React.FC<SettingsTabProps> = ({ stats }) => {
|
|||||||
|
|
||||||
<div className="p-4 bg-slate-50 border border-slate-200 rounded-xl space-y-3">
|
<div className="p-4 bg-slate-50 border border-slate-200 rounded-xl space-y-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-xs font-semibold text-slate-700">GEMINI_API_KEY</span>
|
<span className="text-xs font-semibold text-slate-700">LOCAL LLM (Ollama)</span>
|
||||||
<span
|
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-bold bg-emerald-100 text-emerald-800">
|
||||||
className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-bold ${
|
{stats?.llmModel || 'gemma4:26b'}
|
||||||
stats?.hasGeminiKey ? 'bg-emerald-100 text-emerald-800' : 'bg-amber-100 text-amber-800'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{stats?.hasGeminiKey ? 'ACTIVE & CONFIGURED' : 'USING HEURISTIC FALLBACK'}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-slate-500 leading-relaxed">
|
<p className="text-xs text-slate-500 leading-relaxed">
|
||||||
Required for web search synthesis, AI document summarization, and LLM classification. AI Studio injects this automatically from the Secrets panel.
|
Running on {stats?.llmHost || 'shadow-death (.128)'} via Ollama /api/chat. Powers web search synthesis, document summarization, and AI tool generation — no cloud API key required.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,5 @@
|
|||||||
import { MCPServerDefinition, ToolDefinition } from '../types.js';
|
import { MCPServerDefinition, ToolDefinition } from '../types.js';
|
||||||
|
import { callLocalModel } from './llmClient.js';
|
||||||
const OLLAMA_HOST = process.env.OLLAMA_HOST || 'http://10.30.20.128:11434';
|
|
||||||
const OLLAMA_MODEL = process.env.OLLAMA_MODEL || 'gemma4:26b';
|
|
||||||
|
|
||||||
async function callLocalModel(prompt: string): Promise<string> {
|
|
||||||
const res = await fetch(`${OLLAMA_HOST}/api/chat`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({
|
|
||||||
model: OLLAMA_MODEL,
|
|
||||||
messages: [{ role: 'user', content: prompt }],
|
|
||||||
stream: false,
|
|
||||||
format: 'json',
|
|
||||||
keep_alive: '30m',
|
|
||||||
options: { num_predict: 4096, temperature: 0.2 },
|
|
||||||
}),
|
|
||||||
signal: AbortSignal.timeout(180000),
|
|
||||||
});
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(`Ollama HTTP ${res.status} (${res.statusText})`);
|
|
||||||
}
|
|
||||||
const data = await res.json();
|
|
||||||
let content = data?.message?.content || '';
|
|
||||||
if (!content) content = data?.message?.thinking || '';
|
|
||||||
content = content.trim();
|
|
||||||
if (!content) throw new Error('Empty response from local model');
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GeneratedMCPResponse {
|
export interface GeneratedMCPResponse {
|
||||||
serverName: string;
|
serverName: string;
|
||||||
@@ -83,7 +56,7 @@ Respond ONLY with valid JSON (no markdown ticks or commentary) matching this Typ
|
|||||||
|
|
||||||
Provide executable JavaScript code for customScript or accurate URL template for webhookConfig. Use fetch() if HTTP calls are needed inside customScript.`;
|
Provide executable JavaScript code for customScript or accurate URL template for webhookConfig. Use fetch() if HTTP calls are needed inside customScript.`;
|
||||||
|
|
||||||
const rawText = await callLocalModel(systemPrompt);
|
const rawText = await callLocalModel(systemPrompt, { formatJson: true });
|
||||||
const cleanJson = rawText.replace(/```json/g, '').replace(/```/g, '').trim();
|
const cleanJson = rawText.replace(/```json/g, '').replace(/```/g, '').trim();
|
||||||
const parsed = JSON.parse(cleanJson);
|
const parsed = JSON.parse(cleanJson);
|
||||||
return parsed;
|
return parsed;
|
||||||
|
|||||||
38
src/server/llmClient.ts
Normal file
38
src/server/llmClient.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Shared local-LLM client — Ollama on shadow-death (.128).
|
||||||
|
// Single source of truth for host/model across the whole app.
|
||||||
|
export const OLLAMA_HOST = process.env.OLLAMA_HOST || 'http://10.30.20.128:11434';
|
||||||
|
export const OLLAMA_MODEL = process.env.OLLAMA_MODEL || 'gemma4:26b';
|
||||||
|
|
||||||
|
export interface LocalModelOptions {
|
||||||
|
formatJson?: boolean;
|
||||||
|
numPredict?: number;
|
||||||
|
temperature?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function callLocalModel(prompt: string, opts: LocalModelOptions = {}): Promise<string> {
|
||||||
|
const body: Record<string, any> = {
|
||||||
|
model: OLLAMA_MODEL,
|
||||||
|
messages: [{ role: 'user', content: prompt }],
|
||||||
|
stream: false,
|
||||||
|
keep_alive: '30m',
|
||||||
|
options: {
|
||||||
|
num_predict: opts.numPredict ?? 4096,
|
||||||
|
temperature: opts.temperature ?? 0.2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (opts.formatJson) body.format = 'json';
|
||||||
|
|
||||||
|
const res = await fetch(`${OLLAMA_HOST}/api/chat`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
signal: AbortSignal.timeout(180000),
|
||||||
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`Ollama HTTP ${res.status} (${res.statusText})`);
|
||||||
|
}
|
||||||
|
const data = await res.json();
|
||||||
|
let content = data?.message?.content || '';
|
||||||
|
if (!content) content = data?.message?.thinking || '';
|
||||||
|
return (content || '').trim();
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import crypto from 'node:crypto';
|
import crypto from 'node:crypto';
|
||||||
import { GoogleGenAI } from '@google/genai';
|
import { callLocalModel } from '../llmClient.js';
|
||||||
import { ToolDefinition, ToolExecutionResult } from '../../types.js';
|
import { ToolDefinition, ToolExecutionResult } from '../../types.js';
|
||||||
import { LOCAL_MODEL_TOOLS, executeLocalModelTool } from './localModelTools.js';
|
import { LOCAL_MODEL_TOOLS, executeLocalModelTool } from './localModelTools.js';
|
||||||
|
|
||||||
@@ -364,23 +364,18 @@ export async function executeTool(toolName: string, args: any): Promise<ToolExec
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. WEB SEARCH GEMINI
|
// 2. WEB SEARCH (local LLM)
|
||||||
case 'web_search_gemini': {
|
case 'web_search_gemini': {
|
||||||
const { query, detailLevel = 'detailed' } = args;
|
const { query, detailLevel = 'detailed' } = args;
|
||||||
const apiKey = process.env.GEMINI_API_KEY;
|
try {
|
||||||
|
const answer = await callLocalModel(
|
||||||
if (apiKey && apiKey !== 'MY_GEMINI_API_KEY') {
|
`You are a web research assistant. The user asks: "${query}". Provide a ${detailLevel} answer with facts, explanations, and structure. Respond in Markdown.`,
|
||||||
const ai = new GoogleGenAI({ apiKey });
|
);
|
||||||
const response = await ai.models.generateContent({
|
|
||||||
model: 'gemini-2.5-flash',
|
|
||||||
contents: `The user asks: "${query}". Provide a ${detailLevel} answer with facts, explanations, and structure.`,
|
|
||||||
});
|
|
||||||
contentType = 'markdown';
|
contentType = 'markdown';
|
||||||
resultData = response.text || 'No response generated.';
|
resultData = answer || 'No response generated.';
|
||||||
} else {
|
} catch {
|
||||||
// Fallback when no key provided
|
|
||||||
contentType = 'markdown';
|
contentType = 'markdown';
|
||||||
resultData = `### Search Synthesis for: "${query}"\n\n*(Note: GEMINI_API_KEY is not configured in .env. Showing structured query response)*\n\n- **Query Topic:** ${query}\n- **Analysis Level:** ${detailLevel}\n- **Status:** Server ready for live Gemini AI web synthesis once GEMINI_API_KEY is set in Settings.`;
|
resultData = `### Search Synthesis for: "${query}"\n\n*(Note: local LLM unreachable — showing structured query response)*\n\n- **Query Topic:** ${query}\n- **Analysis Level:** ${detailLevel}\n- **Status:** Local model (${'gemma4:26b'}) on shadow-death unavailable.`;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -909,32 +904,27 @@ export async function executeTool(toolName: string, args: any): Promise<ToolExec
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 17. TEXT SUMMARIZE & CLASSIFY
|
// 17. TEXT SUMMARIZE & CLASSIFY (local LLM)
|
||||||
case 'text_summarize_classify': {
|
case 'text_summarize_classify': {
|
||||||
const { text, task = 'all' } = args;
|
const { text, task = 'all' } = args;
|
||||||
const apiKey = process.env.GEMINI_API_KEY;
|
|
||||||
|
|
||||||
if (apiKey && apiKey !== 'MY_GEMINI_API_KEY') {
|
try {
|
||||||
const ai = new GoogleGenAI({ apiKey });
|
const summary = await callLocalModel(
|
||||||
const response = await ai.models.generateContent({
|
`Perform task "${task}" on the following text:\n"${text}"\nReturn a structured response with key takeaways, sentiment (positive/neutral/negative), and extracted entities.`,
|
||||||
model: 'gemini-2.5-flash',
|
);
|
||||||
contents: `Perform task "${task}" on the following text:
|
resultData = summary;
|
||||||
"${text}"
|
|
||||||
Return a structured response with key takeaways, sentiment (positive/neutral/negative), and extracted entities.`,
|
|
||||||
});
|
|
||||||
resultData = response.text;
|
|
||||||
contentType = 'markdown';
|
contentType = 'markdown';
|
||||||
} else {
|
} catch {
|
||||||
// Heuristic summarizer
|
// Heuristic summarizer
|
||||||
const words = text.split(/\s+/);
|
const words = text.split(/\s+/);
|
||||||
const sentences = text.split(/[.!?]+/).filter((s: string) => s.trim().length > 0);
|
const sentences = text.split(/[.!?]+/).filter((s: string) => s.trim().length > 0);
|
||||||
const summary = sentences.slice(0, 3).join('. ') + '.';
|
const summaryText = sentences.slice(0, 3).join('. ') + '.';
|
||||||
|
|
||||||
resultData = {
|
resultData = {
|
||||||
task,
|
task,
|
||||||
wordCount: words.length,
|
wordCount: words.length,
|
||||||
sentenceCount: sentences.length,
|
sentenceCount: sentences.length,
|
||||||
summary,
|
summary: summaryText,
|
||||||
sentiment: text.toLowerCase().includes('great') || text.toLowerCase().includes('excellent') ? 'POSITIVE' : 'NEUTRAL',
|
sentiment: text.toLowerCase().includes('great') || text.toLowerCase().includes('excellent') ? 'POSITIVE' : 'NEUTRAL',
|
||||||
extractedKeywords: [...new Set(words.filter((w: string) => w.length > 6))].slice(0, 8),
|
extractedKeywords: [...new Set(words.filter((w: string) => w.length > 6))].slice(0, 8),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -150,7 +150,9 @@ export interface ServerStats {
|
|||||||
totalMCPServersCount: number;
|
totalMCPServersCount: number;
|
||||||
avgLatencyMs: number;
|
avgLatencyMs: number;
|
||||||
memoryUsageMb: number;
|
memoryUsageMb: number;
|
||||||
hasGeminiKey: boolean;
|
llmProvider: string;
|
||||||
|
llmModel: string;
|
||||||
|
llmHost: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AgentAutoSetupResponse {
|
export interface AgentAutoSetupResponse {
|
||||||
|
|||||||
Reference in New Issue
Block a user