Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f5011b871 | |||
| 5b67e23060 |
@@ -43,6 +43,9 @@ ONLY_FOR_CREATOR_MODE=false
|
|||||||
# Use user names in AI prompts
|
# Use user names in AI prompts
|
||||||
USE_NAMES_IN_PROMPT=true
|
USE_NAMES_IN_PROMPT=true
|
||||||
|
|
||||||
|
# Disable all built-in local tools and keep only MCP tools
|
||||||
|
DISABLE_LOCAL_TOOLS=false
|
||||||
|
|
||||||
# Custom system prompt for AI (or put it into data/SYSTEM_PROMPT.md)
|
# Custom system prompt for AI (or put it into data/SYSTEM_PROMPT.md)
|
||||||
SYSTEM_PROMPT=
|
SYSTEM_PROMPT=
|
||||||
|
|
||||||
@@ -99,6 +102,14 @@ OPENAI_TTS_VOICE=alloy
|
|||||||
OPENAI_TTS_INSTRUCTIONS=
|
OPENAI_TTS_INSTRUCTIONS=
|
||||||
OPENAI_MAX_CONCURRENT_REQUESTS=3
|
OPENAI_MAX_CONCURRENT_REQUESTS=3
|
||||||
|
|
||||||
|
# MCP servers
|
||||||
|
# JSON array or {"mcpServers": {"name": {...}}}
|
||||||
|
# Stdio example:
|
||||||
|
# MCP_SERVERS=[{"name":"local-tools","transport":"stdio","command":"node","args":["./mcp-server.js"]}]
|
||||||
|
# HTTP example:
|
||||||
|
# MCP_SERVERS=[{"name":"remote-tools","transport":"http","url":"https://example.com/mcp"}]
|
||||||
|
MCP_SERVERS=
|
||||||
|
|
||||||
# Per-capability AI endpoint overrides
|
# Per-capability AI endpoint overrides
|
||||||
# Pattern:
|
# Pattern:
|
||||||
# <PROVIDER>_<CAPABILITY>_MODEL=
|
# <PROVIDER>_<CAPABILITY>_MODEL=
|
||||||
|
|||||||
@@ -27,6 +27,18 @@ The bot initializes and migrates its database schema automatically on startup.
|
|||||||
`/exportdb` sends the SQLite file when available, plus a `.sql` dump and a JSON backup.
|
`/exportdb` sends the SQLite file when available, plus a `.sql` dump and a JSON backup.
|
||||||
`/importdb` restores the database from the JSON backup format.
|
`/importdb` restores the database from the JSON backup format.
|
||||||
|
|
||||||
|
MCP tool servers can be configured through `MCP_SERVERS` in `.env`. Use a JSON array with `stdio` or `http` transports. Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
MCP_SERVERS=[{"name":"local-tools","transport":"stdio","command":"node","args":["./mcp-server.js"]}]
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to disable all built-in local tools and use only MCP tools, set:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
DISABLE_LOCAL_TOOLS=true
|
||||||
|
```
|
||||||
|
|
||||||
For local Ollama document RAG, install an embedding model locally and set it in `.env`:
|
For local Ollama document RAG, install an embedding model locally and set it in `.env`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -179,7 +179,7 @@
|
|||||||
|
|
||||||
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="],
|
"@types/node": ["@types/node@25.9.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ=="],
|
||||||
|
|
||||||
"@types/pg": ["@types/pg@8.20.0", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow=="],
|
"@types/pg": ["@types/pg@8.20.0", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow=="],
|
||||||
|
|
||||||
@@ -187,25 +187,25 @@
|
|||||||
|
|
||||||
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
|
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.59.3", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.59.3", "@typescript-eslint/type-utils": "8.59.3", "@typescript-eslint/utils": "8.59.3", "@typescript-eslint/visitor-keys": "8.59.3", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.59.3", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw=="],
|
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.59.4", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/type-utils": "8.59.4", "@typescript-eslint/utils": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.59.4", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A=="],
|
||||||
|
|
||||||
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.59.3", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.59.3", "@typescript-eslint/types": "8.59.3", "@typescript-eslint/typescript-estree": "8.59.3", "@typescript-eslint/visitor-keys": "8.59.3", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg=="],
|
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.59.4", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/types": "8.59.4", "@typescript-eslint/typescript-estree": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ=="],
|
||||||
|
|
||||||
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.59.3", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.59.3", "@typescript-eslint/types": "^8.59.3", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng=="],
|
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.59.4", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.59.4", "@typescript-eslint/types": "^8.59.4", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg=="],
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.59.3", "", { "dependencies": { "@typescript-eslint/types": "8.59.3", "@typescript-eslint/visitor-keys": "8.59.3" } }, "sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA=="],
|
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.59.4", "", { "dependencies": { "@typescript-eslint/types": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4" } }, "sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q=="],
|
||||||
|
|
||||||
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.59.3", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw=="],
|
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.59.4", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA=="],
|
||||||
|
|
||||||
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.59.3", "", { "dependencies": { "@typescript-eslint/types": "8.59.3", "@typescript-eslint/typescript-estree": "8.59.3", "@typescript-eslint/utils": "8.59.3", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ=="],
|
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.59.4", "", { "dependencies": { "@typescript-eslint/types": "8.59.4", "@typescript-eslint/typescript-estree": "8.59.4", "@typescript-eslint/utils": "8.59.4", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA=="],
|
||||||
|
|
||||||
"@typescript-eslint/types": ["@typescript-eslint/types@8.59.3", "", {}, "sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg=="],
|
"@typescript-eslint/types": ["@typescript-eslint/types@8.59.4", "", {}, "sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q=="],
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.59.3", "", { "dependencies": { "@typescript-eslint/project-service": "8.59.3", "@typescript-eslint/tsconfig-utils": "8.59.3", "@typescript-eslint/types": "8.59.3", "@typescript-eslint/visitor-keys": "8.59.3", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg=="],
|
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.59.4", "", { "dependencies": { "@typescript-eslint/project-service": "8.59.4", "@typescript-eslint/tsconfig-utils": "8.59.4", "@typescript-eslint/types": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag=="],
|
||||||
|
|
||||||
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.59.3", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.59.3", "@typescript-eslint/types": "8.59.3", "@typescript-eslint/typescript-estree": "8.59.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg=="],
|
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.59.4", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/types": "8.59.4", "@typescript-eslint/typescript-estree": "8.59.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw=="],
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.59.3", "", { "dependencies": { "@typescript-eslint/types": "8.59.3", "eslint-visitor-keys": "^5.0.0" } }, "sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg=="],
|
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.59.4", "", { "dependencies": { "@typescript-eslint/types": "8.59.4", "eslint-visitor-keys": "^5.0.0" } }, "sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ=="],
|
||||||
|
|
||||||
"acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
|
"acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
|
||||||
|
|
||||||
@@ -399,7 +399,7 @@
|
|||||||
|
|
||||||
"ollama": ["ollama@0.6.3", "", { "dependencies": { "whatwg-fetch": "^3.6.20" } }, "sha512-KEWEhIqE5wtfzEIZbDCLH51VFZ6Z3ZSa6sIOg/E/tBV8S51flyqBOXi+bRxlOYKDf8i327zG9eSTb8IJxvm3Zg=="],
|
"ollama": ["ollama@0.6.3", "", { "dependencies": { "whatwg-fetch": "^3.6.20" } }, "sha512-KEWEhIqE5wtfzEIZbDCLH51VFZ6Z3ZSa6sIOg/E/tBV8S51flyqBOXi+bRxlOYKDf8i327zG9eSTb8IJxvm3Zg=="],
|
||||||
|
|
||||||
"openai": ["openai@6.37.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-0H5dEGFmmLv6KSd0W1w2nyL8WsLkX6yoLeQpU+dZAOuGcany5qkYQMmj35ZrKgb6yiyYqpUzFOpR8mZQkgqeEQ=="],
|
"openai": ["openai@6.38.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-AoMplt2UalrpgUDMh3L09QWjNRlgJPipclQvA6sYAaeF6nHNBMgmikAZGmcYLn8on4d9sQY9Q8bOLfrBS7Lc8g=="],
|
||||||
|
|
||||||
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
||||||
|
|
||||||
@@ -415,15 +415,15 @@
|
|||||||
|
|
||||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||||
|
|
||||||
"pg": ["pg@8.20.0", "", { "dependencies": { "pg-connection-string": "^2.12.0", "pg-pool": "^3.13.0", "pg-protocol": "^1.13.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.3.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA=="],
|
"pg": ["pg@8.21.0", "", { "dependencies": { "pg-connection-string": "^2.13.0", "pg-pool": "^3.14.0", "pg-protocol": "^1.14.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.4.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA=="],
|
||||||
|
|
||||||
"pg-cloudflare": ["pg-cloudflare@1.3.0", "", {}, "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ=="],
|
"pg-cloudflare": ["pg-cloudflare@1.4.0", "", {}, "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A=="],
|
||||||
|
|
||||||
"pg-connection-string": ["pg-connection-string@2.12.0", "", {}, "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ=="],
|
"pg-connection-string": ["pg-connection-string@2.13.0", "", {}, "sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig=="],
|
||||||
|
|
||||||
"pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="],
|
"pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="],
|
||||||
|
|
||||||
"pg-pool": ["pg-pool@3.13.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA=="],
|
"pg-pool": ["pg-pool@3.14.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw=="],
|
||||||
|
|
||||||
"pg-protocol": ["pg-protocol@1.13.0", "", {}, "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w=="],
|
"pg-protocol": ["pg-protocol@1.13.0", "", {}, "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w=="],
|
||||||
|
|
||||||
@@ -495,7 +495,7 @@
|
|||||||
|
|
||||||
"typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
|
"typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
|
||||||
|
|
||||||
"typescript-eslint": ["typescript-eslint@8.59.3", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.59.3", "@typescript-eslint/parser": "8.59.3", "@typescript-eslint/typescript-estree": "8.59.3", "@typescript-eslint/utils": "8.59.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg=="],
|
"typescript-eslint": ["typescript-eslint@8.59.4", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.59.4", "@typescript-eslint/parser": "8.59.4", "@typescript-eslint/typescript-estree": "8.59.4", "@typescript-eslint/utils": "8.59.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Rw6+44QNFaXtgHSjPy+Kw8hrJniMYzR85E9yLmOLcfZ91/rz+JXQbDTCmc6ccxMPY6K6PgAq26f0JCBfR7LIPQ=="],
|
||||||
|
|
||||||
"typescript-telegram-bot-api": ["typescript-telegram-bot-api@0.16.0", "", { "dependencies": { "axios": "^1.7.7", "form-data": "^4.0.1" } }, "sha512-NaAjXucQiZ87U8La/IMaWDOghbMlJzfMbU4rG8ppFpgPOvEwat/zfN5BM+J2QDvKVGN87qJ+1nELnkm3ctSLnQ=="],
|
"typescript-telegram-bot-api": ["typescript-telegram-bot-api@0.16.0", "", { "dependencies": { "axios": "^1.7.7", "form-data": "^4.0.1" } }, "sha512-NaAjXucQiZ87U8La/IMaWDOghbMlJzfMbU4rG8ppFpgPOvEwat/zfN5BM+J2QDvKVGN87qJ+1nELnkm3ctSLnQ=="],
|
||||||
|
|
||||||
@@ -551,12 +551,16 @@
|
|||||||
|
|
||||||
"@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
|
"@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
|
||||||
|
|
||||||
|
"bun-types/@types/node": ["@types/node@25.8.0", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ=="],
|
||||||
|
|
||||||
"cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
"cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||||
|
|
||||||
"fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
|
"fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
|
||||||
|
|
||||||
"libsql/detect-libc": ["detect-libc@2.0.2", "", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="],
|
"libsql/detect-libc": ["detect-libc@2.0.2", "", {}, "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw=="],
|
||||||
|
|
||||||
|
"pg/pg-protocol": ["pg-protocol@1.14.0", "", {}, "sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA=="],
|
||||||
|
|
||||||
"string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
"string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||||
|
|
||||||
"typescript-telegram-bot-api/axios": ["axios@1.16.0", "", { "dependencies": { "follow-redirects": "^1.16.0", "form-data": "^4.0.5", "proxy-from-env": "^2.1.0" } }, "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w=="],
|
"typescript-telegram-bot-api/axios": ["axios@1.16.0", "", { "dependencies": { "follow-redirects": "^1.16.0", "form-data": "^4.0.5", "proxy-from-env": "^2.1.0" } }, "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w=="],
|
||||||
|
|||||||
Generated
+115
-115
@@ -17,8 +17,8 @@
|
|||||||
"emoji-regex": "^10.6.0",
|
"emoji-regex": "^10.6.0",
|
||||||
"fluent-ffmpeg": "^2.1.3",
|
"fluent-ffmpeg": "^2.1.3",
|
||||||
"ollama": "^0.6.3",
|
"ollama": "^0.6.3",
|
||||||
"openai": "^6.37.0",
|
"openai": "^6.38.0",
|
||||||
"pg": "^8.20.0",
|
"pg": "^8.21.0",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
"systeminformation": "^5.31.6",
|
"systeminformation": "^5.31.6",
|
||||||
@@ -30,12 +30,12 @@
|
|||||||
"@eslint/js": "^9.39.4",
|
"@eslint/js": "^9.39.4",
|
||||||
"@types/bun": "^1.3.14",
|
"@types/bun": "^1.3.14",
|
||||||
"@types/fluent-ffmpeg": "^2.1.28",
|
"@types/fluent-ffmpeg": "^2.1.28",
|
||||||
"@types/node": "^25.8.0",
|
"@types/node": "^25.9.0",
|
||||||
"@types/pg": "^8.20.0",
|
"@types/pg": "^8.20.0",
|
||||||
"@types/qrcode": "^1.5.6",
|
"@types/qrcode": "^1.5.6",
|
||||||
"eslint": "^9.39.4",
|
"eslint": "^9.39.4",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
"typescript-eslint": "^8.59.3"
|
"typescript-eslint": "^8.59.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/runtime": {
|
"node_modules/@emnapi/runtime": {
|
||||||
@@ -1246,9 +1246,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "25.8.0",
|
"version": "25.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.0.tgz",
|
||||||
"integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==",
|
"integrity": "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": ">=7.24.0 <7.24.7"
|
"undici-types": ">=7.24.0 <7.24.7"
|
||||||
@@ -1286,17 +1286,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.59.3",
|
"version": "8.59.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.3.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.4.tgz",
|
||||||
"integrity": "sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==",
|
"integrity": "sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.12.2",
|
"@eslint-community/regexpp": "^4.12.2",
|
||||||
"@typescript-eslint/scope-manager": "8.59.3",
|
"@typescript-eslint/scope-manager": "8.59.4",
|
||||||
"@typescript-eslint/type-utils": "8.59.3",
|
"@typescript-eslint/type-utils": "8.59.4",
|
||||||
"@typescript-eslint/utils": "8.59.3",
|
"@typescript-eslint/utils": "8.59.4",
|
||||||
"@typescript-eslint/visitor-keys": "8.59.3",
|
"@typescript-eslint/visitor-keys": "8.59.4",
|
||||||
"ignore": "^7.0.5",
|
"ignore": "^7.0.5",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
"ts-api-utils": "^2.5.0"
|
"ts-api-utils": "^2.5.0"
|
||||||
@@ -1309,7 +1309,7 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^8.59.3",
|
"@typescript-eslint/parser": "^8.59.4",
|
||||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||||
"typescript": ">=4.8.4 <6.1.0"
|
"typescript": ">=4.8.4 <6.1.0"
|
||||||
}
|
}
|
||||||
@@ -1325,16 +1325,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.59.3",
|
"version": "8.59.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.3.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.4.tgz",
|
||||||
"integrity": "sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==",
|
"integrity": "sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.59.3",
|
"@typescript-eslint/scope-manager": "8.59.4",
|
||||||
"@typescript-eslint/types": "8.59.3",
|
"@typescript-eslint/types": "8.59.4",
|
||||||
"@typescript-eslint/typescript-estree": "8.59.3",
|
"@typescript-eslint/typescript-estree": "8.59.4",
|
||||||
"@typescript-eslint/visitor-keys": "8.59.3",
|
"@typescript-eslint/visitor-keys": "8.59.4",
|
||||||
"debug": "^4.4.3"
|
"debug": "^4.4.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1350,14 +1350,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/project-service": {
|
"node_modules/@typescript-eslint/project-service": {
|
||||||
"version": "8.59.3",
|
"version": "8.59.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.3.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.4.tgz",
|
||||||
"integrity": "sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==",
|
"integrity": "sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.59.3",
|
"@typescript-eslint/tsconfig-utils": "^8.59.4",
|
||||||
"@typescript-eslint/types": "^8.59.3",
|
"@typescript-eslint/types": "^8.59.4",
|
||||||
"debug": "^4.4.3"
|
"debug": "^4.4.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1372,14 +1372,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.59.3",
|
"version": "8.59.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.3.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.4.tgz",
|
||||||
"integrity": "sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==",
|
"integrity": "sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.59.3",
|
"@typescript-eslint/types": "8.59.4",
|
||||||
"@typescript-eslint/visitor-keys": "8.59.3"
|
"@typescript-eslint/visitor-keys": "8.59.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -1390,9 +1390,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
"version": "8.59.3",
|
"version": "8.59.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.3.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.4.tgz",
|
||||||
"integrity": "sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==",
|
"integrity": "sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1407,15 +1407,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.59.3",
|
"version": "8.59.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.3.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.4.tgz",
|
||||||
"integrity": "sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==",
|
"integrity": "sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.59.3",
|
"@typescript-eslint/types": "8.59.4",
|
||||||
"@typescript-eslint/typescript-estree": "8.59.3",
|
"@typescript-eslint/typescript-estree": "8.59.4",
|
||||||
"@typescript-eslint/utils": "8.59.3",
|
"@typescript-eslint/utils": "8.59.4",
|
||||||
"debug": "^4.4.3",
|
"debug": "^4.4.3",
|
||||||
"ts-api-utils": "^2.5.0"
|
"ts-api-utils": "^2.5.0"
|
||||||
},
|
},
|
||||||
@@ -1432,9 +1432,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.59.3",
|
"version": "8.59.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.3.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.4.tgz",
|
||||||
"integrity": "sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==",
|
"integrity": "sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1446,16 +1446,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.59.3",
|
"version": "8.59.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.3.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.4.tgz",
|
||||||
"integrity": "sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==",
|
"integrity": "sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.59.3",
|
"@typescript-eslint/project-service": "8.59.4",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.59.3",
|
"@typescript-eslint/tsconfig-utils": "8.59.4",
|
||||||
"@typescript-eslint/types": "8.59.3",
|
"@typescript-eslint/types": "8.59.4",
|
||||||
"@typescript-eslint/visitor-keys": "8.59.3",
|
"@typescript-eslint/visitor-keys": "8.59.4",
|
||||||
"debug": "^4.4.3",
|
"debug": "^4.4.3",
|
||||||
"minimatch": "^10.2.2",
|
"minimatch": "^10.2.2",
|
||||||
"semver": "^7.7.3",
|
"semver": "^7.7.3",
|
||||||
@@ -1513,16 +1513,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.59.3",
|
"version": "8.59.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.3.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.4.tgz",
|
||||||
"integrity": "sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==",
|
"integrity": "sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.9.1",
|
"@eslint-community/eslint-utils": "^4.9.1",
|
||||||
"@typescript-eslint/scope-manager": "8.59.3",
|
"@typescript-eslint/scope-manager": "8.59.4",
|
||||||
"@typescript-eslint/types": "8.59.3",
|
"@typescript-eslint/types": "8.59.4",
|
||||||
"@typescript-eslint/typescript-estree": "8.59.3"
|
"@typescript-eslint/typescript-estree": "8.59.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -1537,13 +1537,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.59.3",
|
"version": "8.59.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.3.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.4.tgz",
|
||||||
"integrity": "sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==",
|
"integrity": "sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.59.3",
|
"@typescript-eslint/types": "8.59.4",
|
||||||
"eslint-visitor-keys": "^5.0.0"
|
"eslint-visitor-keys": "^5.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1590,6 +1590,18 @@
|
|||||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/agent-base": {
|
||||||
|
"version": "6.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||||
|
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ajv": {
|
"node_modules/ajv": {
|
||||||
"version": "6.15.0",
|
"version": "6.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
|
||||||
@@ -1661,31 +1673,6 @@
|
|||||||
"proxy-from-env": "^2.1.0"
|
"proxy-from-env": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axios/node_modules/agent-base": {
|
|
||||||
"version": "6.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
|
||||||
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"debug": "4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/axios/node_modules/https-proxy-agent": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"agent-base": "6",
|
|
||||||
"debug": "4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -2575,6 +2562,19 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/https-proxy-agent": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"agent-base": "6",
|
||||||
|
"debug": "4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||||
@@ -2847,9 +2847,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/openai": {
|
"node_modules/openai": {
|
||||||
"version": "6.37.0",
|
"version": "6.38.0",
|
||||||
"resolved": "https://registry.npmjs.org/openai/-/openai-6.37.0.tgz",
|
"resolved": "https://registry.npmjs.org/openai/-/openai-6.38.0.tgz",
|
||||||
"integrity": "sha512-0H5dEGFmmLv6KSd0W1w2nyL8WsLkX6yoLeQpU+dZAOuGcany5qkYQMmj35ZrKgb6yiyYqpUzFOpR8mZQkgqeEQ==",
|
"integrity": "sha512-AoMplt2UalrpgUDMh3L09QWjNRlgJPipclQvA6sYAaeF6nHNBMgmikAZGmcYLn8on4d9sQY9Q8bOLfrBS7Lc8g==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"openai": "bin/cli"
|
"openai": "bin/cli"
|
||||||
@@ -2959,14 +2959,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg": {
|
"node_modules/pg": {
|
||||||
"version": "8.20.0",
|
"version": "8.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg/-/pg-8.21.0.tgz",
|
||||||
"integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==",
|
"integrity": "sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pg-connection-string": "^2.12.0",
|
"pg-connection-string": "^2.13.0",
|
||||||
"pg-pool": "^3.13.0",
|
"pg-pool": "^3.14.0",
|
||||||
"pg-protocol": "^1.13.0",
|
"pg-protocol": "^1.14.0",
|
||||||
"pg-types": "2.2.0",
|
"pg-types": "2.2.0",
|
||||||
"pgpass": "1.0.5"
|
"pgpass": "1.0.5"
|
||||||
},
|
},
|
||||||
@@ -2974,7 +2974,7 @@
|
|||||||
"node": ">= 16.0.0"
|
"node": ">= 16.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"pg-cloudflare": "^1.3.0"
|
"pg-cloudflare": "^1.4.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"pg-native": ">=3.0.1"
|
"pg-native": ">=3.0.1"
|
||||||
@@ -2986,16 +2986,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg-cloudflare": {
|
"node_modules/pg-cloudflare": {
|
||||||
"version": "1.3.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.4.0.tgz",
|
||||||
"integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==",
|
"integrity": "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/pg-connection-string": {
|
"node_modules/pg-connection-string": {
|
||||||
"version": "2.12.0",
|
"version": "2.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.13.0.tgz",
|
||||||
"integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==",
|
"integrity": "sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/pg-int8": {
|
"node_modules/pg-int8": {
|
||||||
@@ -3008,18 +3008,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg-pool": {
|
"node_modules/pg-pool": {
|
||||||
"version": "3.13.0",
|
"version": "3.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.14.0.tgz",
|
||||||
"integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==",
|
"integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"pg": ">=8.0"
|
"pg": ">=8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pg-protocol": {
|
"node_modules/pg-protocol": {
|
||||||
"version": "1.13.0",
|
"version": "1.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.14.0.tgz",
|
||||||
"integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==",
|
"integrity": "sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/pg-types": {
|
"node_modules/pg-types": {
|
||||||
@@ -3455,16 +3455,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "8.59.3",
|
"version": "8.59.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.4.tgz",
|
||||||
"integrity": "sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg==",
|
"integrity": "sha512-Rw6+44QNFaXtgHSjPy+Kw8hrJniMYzR85E9yLmOLcfZ91/rz+JXQbDTCmc6ccxMPY6K6PgAq26f0JCBfR7LIPQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.59.3",
|
"@typescript-eslint/eslint-plugin": "8.59.4",
|
||||||
"@typescript-eslint/parser": "8.59.3",
|
"@typescript-eslint/parser": "8.59.4",
|
||||||
"@typescript-eslint/typescript-estree": "8.59.3",
|
"@typescript-eslint/typescript-estree": "8.59.4",
|
||||||
"@typescript-eslint/utils": "8.59.3"
|
"@typescript-eslint/utils": "8.59.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|||||||
+4
-4
@@ -22,8 +22,8 @@
|
|||||||
"emoji-regex": "^10.6.0",
|
"emoji-regex": "^10.6.0",
|
||||||
"fluent-ffmpeg": "^2.1.3",
|
"fluent-ffmpeg": "^2.1.3",
|
||||||
"ollama": "^0.6.3",
|
"ollama": "^0.6.3",
|
||||||
"openai": "^6.37.0",
|
"openai": "^6.38.0",
|
||||||
"pg": "^8.20.0",
|
"pg": "^8.21.0",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"sharp": "^0.34.5",
|
"sharp": "^0.34.5",
|
||||||
"systeminformation": "^5.31.6",
|
"systeminformation": "^5.31.6",
|
||||||
@@ -35,11 +35,11 @@
|
|||||||
"@eslint/js": "^9.39.4",
|
"@eslint/js": "^9.39.4",
|
||||||
"@types/bun": "^1.3.14",
|
"@types/bun": "^1.3.14",
|
||||||
"@types/fluent-ffmpeg": "^2.1.28",
|
"@types/fluent-ffmpeg": "^2.1.28",
|
||||||
"@types/node": "^25.8.0",
|
"@types/node": "^25.9.0",
|
||||||
"@types/pg": "^8.20.0",
|
"@types/pg": "^8.20.0",
|
||||||
"@types/qrcode": "^1.5.6",
|
"@types/qrcode": "^1.5.6",
|
||||||
"eslint": "^9.39.4",
|
"eslint": "^9.39.4",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
"typescript-eslint": "^8.59.3"
|
"typescript-eslint": "^8.59.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,421 @@
|
|||||||
|
import {spawn, type ChildProcessWithoutNullStreams} from "node:child_process";
|
||||||
|
import type {BoundaryValue} from "../../common/boundary-types.js";
|
||||||
|
import {toolsLogger} from "../tools/tool-logger.js";
|
||||||
|
import type {McpServerConfig} from "./mcp-config.js";
|
||||||
|
|
||||||
|
const logger = toolsLogger.child("mcp");
|
||||||
|
const MCP_PROTOCOL_VERSION = "2025-06-18";
|
||||||
|
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
||||||
|
|
||||||
|
export type McpToolDefinition = {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
inputSchema?: BoundaryValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
type JsonRpcRequest = {
|
||||||
|
jsonrpc: "2.0";
|
||||||
|
id: number;
|
||||||
|
method: string;
|
||||||
|
params?: BoundaryValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
type JsonRpcNotification = {
|
||||||
|
jsonrpc: "2.0";
|
||||||
|
method: string;
|
||||||
|
params?: BoundaryValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
type JsonRpcResponse = {
|
||||||
|
jsonrpc?: "2.0";
|
||||||
|
id?: BoundaryValue;
|
||||||
|
result?: BoundaryValue;
|
||||||
|
error?: {
|
||||||
|
code?: number;
|
||||||
|
message?: string;
|
||||||
|
data?: BoundaryValue;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
interface JsonRpcTransport {
|
||||||
|
request(method: string, params?: BoundaryValue): Promise<BoundaryValue>;
|
||||||
|
notify(method: string, params?: BoundaryValue): Promise<void>;
|
||||||
|
close(): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRecord(value: BoundaryValue): value is Record<string, BoundaryValue> {
|
||||||
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toJsonRpcResponse(value: BoundaryValue): JsonRpcResponse | undefined {
|
||||||
|
if (!isRecord(value)) return undefined;
|
||||||
|
if (value.jsonrpc !== undefined && value.jsonrpc !== "2.0") return undefined;
|
||||||
|
return value as JsonRpcResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractJsonRpcResult(response: BoundaryValue, expectedId?: number): BoundaryValue {
|
||||||
|
const parsed = toJsonRpcResponse(response);
|
||||||
|
if (!parsed) {
|
||||||
|
throw new Error("Invalid JSON-RPC response from MCP server.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsed.error) {
|
||||||
|
throw new Error(parsed.error.message || "MCP server returned an error.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectedId !== undefined && parsed.id !== undefined && parsed.id !== expectedId) {
|
||||||
|
throw new Error(`Unexpected JSON-RPC response id from MCP server. Expected ${expectedId}, got ${String(parsed.id)}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed.result ?? {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseSsePayload(text: string): BoundaryValue[] {
|
||||||
|
const events: string[] = [];
|
||||||
|
let current: string[] = [];
|
||||||
|
|
||||||
|
for (const rawLine of text.split(/\r?\n/)) {
|
||||||
|
const line = rawLine.trimEnd();
|
||||||
|
|
||||||
|
if (!line) {
|
||||||
|
if (current.length) {
|
||||||
|
events.push(current.join("\n"));
|
||||||
|
current = [];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.startsWith("data:")) {
|
||||||
|
current.push(line.slice(5).replace(/^ /, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current.length) {
|
||||||
|
events.push(current.join("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return events.map(event => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(event) as BoundaryValue;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}).filter((event): event is BoundaryValue => event !== undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
function timeoutPromise<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T> {
|
||||||
|
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) return promise;
|
||||||
|
|
||||||
|
let timeoutId: NodeJS.Timeout | undefined;
|
||||||
|
const timeout = new Promise<T>((_, reject) => {
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
||||||
|
}, timeoutMs);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.race([promise, timeout]).finally(() => {
|
||||||
|
if (timeoutId) clearTimeout(timeoutId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class StdioJsonRpcTransport implements JsonRpcTransport {
|
||||||
|
private readonly process: ChildProcessWithoutNullStreams;
|
||||||
|
private readonly pending = new Map<number, {resolve: (value: BoundaryValue) => void; reject: (error: Error) => void;}>();
|
||||||
|
private buffer = "";
|
||||||
|
private nextId = 1;
|
||||||
|
|
||||||
|
constructor(private readonly config: McpServerConfig) {
|
||||||
|
if (!config.command) {
|
||||||
|
throw new Error(`MCP stdio server '${config.name}' is missing command.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.process = spawn(config.command, config.args ?? [], {
|
||||||
|
cwd: config.cwd,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
...config.env,
|
||||||
|
},
|
||||||
|
stdio: ["pipe", "pipe", "pipe"],
|
||||||
|
windowsHide: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.process.stdout.on("data", chunk => this.handleStdout(chunk));
|
||||||
|
this.process.stderr.on("data", chunk => {
|
||||||
|
const text = chunk.toString("utf8").trim();
|
||||||
|
if (text) logger.debug("stdio.stderr", {server: config.name, text});
|
||||||
|
});
|
||||||
|
this.process.on("error", error => this.failAll(error));
|
||||||
|
this.process.on("exit", code => this.failAll(new Error(`MCP stdio server '${config.name}' exited with code ${code ?? "unknown"}.`)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleStdout(chunk: Buffer): void {
|
||||||
|
this.buffer += chunk.toString("utf8");
|
||||||
|
|
||||||
|
let newlineIndex = this.buffer.indexOf("\n");
|
||||||
|
while (newlineIndex !== -1) {
|
||||||
|
const line = this.buffer.slice(0, newlineIndex).trim();
|
||||||
|
this.buffer = this.buffer.slice(newlineIndex + 1);
|
||||||
|
newlineIndex = this.buffer.indexOf("\n");
|
||||||
|
|
||||||
|
if (!line) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const message = JSON.parse(line) as JsonRpcResponse | JsonRpcNotification;
|
||||||
|
if ("id" in message && message.id !== undefined) {
|
||||||
|
const pending = this.pending.get(Number(message.id));
|
||||||
|
if (pending) {
|
||||||
|
this.pending.delete(Number(message.id));
|
||||||
|
if ("error" in message && message.error) {
|
||||||
|
pending.reject(new Error(message.error.message || "MCP stdio request failed."));
|
||||||
|
} else {
|
||||||
|
pending.resolve((message as JsonRpcResponse).result ?? {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("method" in message) {
|
||||||
|
logger.debug("stdio.notification", {server: this.config.name, method: message.method});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn("stdio.parse_failed", {
|
||||||
|
server: this.config.name,
|
||||||
|
line: line.slice(0, 500),
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private failAll(error: Error): void {
|
||||||
|
for (const pending of this.pending.values()) {
|
||||||
|
pending.reject(error);
|
||||||
|
}
|
||||||
|
this.pending.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
async request(method: string, params?: BoundaryValue): Promise<BoundaryValue> {
|
||||||
|
if (this.process.exitCode !== null) {
|
||||||
|
throw new Error(`MCP stdio server '${this.config.name}' is not running.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = this.nextId++;
|
||||||
|
const request: JsonRpcRequest = {
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
id,
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = new Promise<BoundaryValue>((resolve, reject) => {
|
||||||
|
this.pending.set(id, {resolve, reject});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.process.stdin.write(`${JSON.stringify(request)}\n`);
|
||||||
|
return timeoutPromise(result, this.config.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS, `${this.config.name}.${method}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async notify(method: string, params?: BoundaryValue): Promise<void> {
|
||||||
|
if (this.process.exitCode !== null) {
|
||||||
|
throw new Error(`MCP stdio server '${this.config.name}' is not running.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const notification: JsonRpcNotification = {
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.process.stdin.write(`${JSON.stringify(notification)}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async close(): Promise<void> {
|
||||||
|
this.failAll(new Error(`MCP stdio server '${this.config.name}' closed.`));
|
||||||
|
if (!this.process.killed) {
|
||||||
|
this.process.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HttpJsonRpcTransport implements JsonRpcTransport {
|
||||||
|
private nextId = 1;
|
||||||
|
private sessionId?: string;
|
||||||
|
|
||||||
|
constructor(private readonly config: McpServerConfig) {
|
||||||
|
if (!config.url) {
|
||||||
|
throw new Error(`MCP HTTP server '${config.name}' is missing url.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async post(body: BoundaryValue): Promise<Response> {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeoutMs = this.config.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await fetch(this.config.url!, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json, text/event-stream",
|
||||||
|
...(this.sessionId ? {"Mcp-Session-Id": this.sessionId} : {}),
|
||||||
|
...(this.config.headers ?? {}),
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
signal: controller.signal,
|
||||||
|
}).finally(() => clearTimeout(timeoutId));
|
||||||
|
} catch (error) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async request(method: string, params?: BoundaryValue): Promise<BoundaryValue> {
|
||||||
|
const id = this.nextId++;
|
||||||
|
const request: JsonRpcRequest = {
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
id,
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await this.post(request);
|
||||||
|
const sessionId = response.headers.get("Mcp-Session-Id");
|
||||||
|
if (sessionId) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text().catch(() => "");
|
||||||
|
throw new Error(`MCP HTTP server '${this.config.name}' returned ${response.status}: ${errorText || response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
|
||||||
|
let payload: BoundaryValue;
|
||||||
|
|
||||||
|
if (contentType.includes("text/event-stream")) {
|
||||||
|
const text = await response.text();
|
||||||
|
const messages = parseSsePayload(text);
|
||||||
|
const responseMessage = messages.map(toJsonRpcResponse).find(message => message?.id === id && (message.result !== undefined || message.error));
|
||||||
|
payload = extractJsonRpcResult(responseMessage ?? messages[0] ?? {}, id);
|
||||||
|
} else {
|
||||||
|
payload = extractJsonRpcResult(await response.json() as BoundaryValue, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
async notify(method: string, params?: BoundaryValue): Promise<void> {
|
||||||
|
const response = await this.post({
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
|
||||||
|
const sessionId = response.headers.get("Mcp-Session-Id");
|
||||||
|
if (sessionId) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.ok && response.status !== 202) {
|
||||||
|
const errorText = await response.text().catch(() => "");
|
||||||
|
throw new Error(`MCP HTTP notification failed for '${this.config.name}' with ${response.status}: ${errorText || response.statusText}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async close(): Promise<void> {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTransport(config: McpServerConfig): JsonRpcTransport {
|
||||||
|
return config.transport === "stdio"
|
||||||
|
? new StdioJsonRpcTransport(config)
|
||||||
|
: new HttpJsonRpcTransport(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeToolResultContent(content: BoundaryValue): string {
|
||||||
|
if (content === undefined || content === null) return "";
|
||||||
|
if (typeof content === "string") return content;
|
||||||
|
if (typeof content === "number" || typeof content === "boolean") return String(content);
|
||||||
|
if (Array.isArray(content)) return content.map(item => normalizeToolResultContent(item)).filter(Boolean).join("\n");
|
||||||
|
if (!isRecord(content)) return JSON.stringify(content);
|
||||||
|
|
||||||
|
if (content.type === "text" && typeof content.text === "string") return content.text;
|
||||||
|
if (content.type === "image") {
|
||||||
|
return `[image ${typeof content.mimeType === "string" ? content.mimeType : "unknown"}]`;
|
||||||
|
}
|
||||||
|
if (content.type === "resource" && isRecord(content.resource)) {
|
||||||
|
if (typeof content.resource.text === "string") return content.resource.text;
|
||||||
|
return JSON.stringify(content.resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.stringify(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class McpClient {
|
||||||
|
private readonly transport: JsonRpcTransport;
|
||||||
|
private initialized = false;
|
||||||
|
|
||||||
|
constructor(readonly config: McpServerConfig) {
|
||||||
|
this.transport = createTransport(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
async initialize(): Promise<void> {
|
||||||
|
if (this.initialized) return;
|
||||||
|
|
||||||
|
await this.transport.request("initialize", {
|
||||||
|
protocolVersion: MCP_PROTOCOL_VERSION,
|
||||||
|
clientInfo: {
|
||||||
|
name: "tg-chat-bot",
|
||||||
|
version: "1.0.0",
|
||||||
|
},
|
||||||
|
capabilities: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.transport.notify("notifications/initialized");
|
||||||
|
this.initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async listTools(): Promise<McpToolDefinition[]> {
|
||||||
|
await this.initialize();
|
||||||
|
const result = await this.transport.request("tools/list");
|
||||||
|
|
||||||
|
if (!isRecord(result)) return [];
|
||||||
|
|
||||||
|
const tools = Array.isArray(result.tools) ? result.tools : [];
|
||||||
|
return tools.flatMap(tool => {
|
||||||
|
if (!isRecord(tool) || typeof tool.name !== "string") return [];
|
||||||
|
return [{
|
||||||
|
name: tool.name,
|
||||||
|
description: typeof tool.description === "string" ? tool.description : undefined,
|
||||||
|
inputSchema: tool.inputSchema,
|
||||||
|
}];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async callTool(name: string, args?: BoundaryValue): Promise<string> {
|
||||||
|
await this.initialize();
|
||||||
|
const result = await this.transport.request("tools/call", {
|
||||||
|
name,
|
||||||
|
arguments: args ?? {},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isRecord(result)) {
|
||||||
|
return normalizeToolResultContent(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
const content = Array.isArray(result.content) ? result.content : [];
|
||||||
|
const text = content.map(item => normalizeToolResultContent(item)).filter(Boolean).join("\n");
|
||||||
|
|
||||||
|
if (result.isError) {
|
||||||
|
return text ? `[MCP error] ${text}` : "[MCP error]";
|
||||||
|
}
|
||||||
|
|
||||||
|
return text || JSON.stringify(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
async close(): Promise<void> {
|
||||||
|
await this.transport.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
import type {BoundaryValue} from "../../common/boundary-types.js";
|
||||||
|
|
||||||
|
export type McpTransport = "stdio" | "http";
|
||||||
|
|
||||||
|
export type McpServerConfig = {
|
||||||
|
name: string;
|
||||||
|
transport: McpTransport;
|
||||||
|
command?: string;
|
||||||
|
args?: string[];
|
||||||
|
cwd?: string;
|
||||||
|
env?: Record<string, string>;
|
||||||
|
url?: string;
|
||||||
|
headers?: Record<string, string>;
|
||||||
|
timeoutMs?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function isRecord(value: BoundaryValue): value is Record<string, BoundaryValue> {
|
||||||
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function asString(value: BoundaryValue): string | undefined {
|
||||||
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toStringRecord(value: BoundaryValue): Record<string, string> | undefined {
|
||||||
|
if (!isRecord(value)) return undefined;
|
||||||
|
|
||||||
|
const result: Record<string, string> = {};
|
||||||
|
for (const [key, entry] of Object.entries(value)) {
|
||||||
|
if (typeof entry === "string" || typeof entry === "number" || typeof entry === "boolean") {
|
||||||
|
result[key] = String(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.keys(result).length ? result : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toStringArray(value: BoundaryValue): string[] | undefined {
|
||||||
|
if (!Array.isArray(value)) return undefined;
|
||||||
|
const items = value.filter((item): item is string => typeof item === "string" && item.trim().length > 0)
|
||||||
|
.map(item => item.trim());
|
||||||
|
return items.length ? items : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toPositiveInt(value: BoundaryValue): number | undefined {
|
||||||
|
const n = typeof value === "number"
|
||||||
|
? value
|
||||||
|
: typeof value === "string"
|
||||||
|
? Number(value)
|
||||||
|
: NaN;
|
||||||
|
|
||||||
|
if (!Number.isFinite(n) || n <= 0) return undefined;
|
||||||
|
return Math.floor(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeServerConfig(value: BoundaryValue, fallbackName?: string): McpServerConfig | undefined {
|
||||||
|
if (!isRecord(value)) return undefined;
|
||||||
|
|
||||||
|
const name = asString(value.name) ?? fallbackName;
|
||||||
|
const transportRaw = asString(value.transport);
|
||||||
|
const transport = transportRaw === "http" || transportRaw === "stdio" ? transportRaw : undefined;
|
||||||
|
|
||||||
|
if (!name || !transport) return undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
transport,
|
||||||
|
command: asString(value.command),
|
||||||
|
args: toStringArray(value.args),
|
||||||
|
cwd: asString(value.cwd),
|
||||||
|
env: toStringRecord(value.env),
|
||||||
|
url: asString(value.url),
|
||||||
|
headers: toStringRecord(value.headers),
|
||||||
|
timeoutMs: toPositiveInt(value.timeoutMs),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseMcpServerConfigs(raw: string | undefined): McpServerConfig[] {
|
||||||
|
if (!raw?.trim()) return [];
|
||||||
|
|
||||||
|
let parsed: BoundaryValue;
|
||||||
|
try {
|
||||||
|
parsed = JSON.parse(raw) as BoundaryValue;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Invalid MCP_SERVERS JSON: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
return parsed.flatMap((item, index) => normalizeServerConfig(item, `server-${index + 1}`) ? [normalizeServerConfig(item, `server-${index + 1}`)!] : []);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRecord(parsed)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(parsed.servers)) {
|
||||||
|
return parsed.servers.flatMap((item, index) => normalizeServerConfig(item, `server-${index + 1}`) ? [normalizeServerConfig(item, `server-${index + 1}`)!] : []);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRecord(parsed.mcpServers)) {
|
||||||
|
return Object.entries(parsed.mcpServers).flatMap(([name, item]) => normalizeServerConfig(item, name) ? [normalizeServerConfig(item, name)!] : []);
|
||||||
|
}
|
||||||
|
|
||||||
|
const single = normalizeServerConfig(parsed);
|
||||||
|
return single ? [single] : [];
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
import type {AiJsonValue, AiToolParameters} from "../tool-types.js";
|
||||||
|
import type {BoundaryValue} from "../../common/boundary-types.js";
|
||||||
|
|
||||||
|
type JsonSchemaRecord = Record<string, BoundaryValue>;
|
||||||
|
|
||||||
|
function isRecord(value: BoundaryValue): value is JsonSchemaRecord {
|
||||||
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toAiJsonValue(value: BoundaryValue): AiJsonValue | undefined {
|
||||||
|
if (value === undefined) return undefined;
|
||||||
|
if (value === null) return null;
|
||||||
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map(item => toAiJsonValue(item) ?? null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRecord(value)) return undefined;
|
||||||
|
|
||||||
|
const result: Record<string, AiJsonValue> = {};
|
||||||
|
for (const [key, entry] of Object.entries(value)) {
|
||||||
|
const normalized = toAiJsonValue(entry);
|
||||||
|
if (normalized !== undefined) {
|
||||||
|
result[key] = normalized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeType(value: BoundaryValue): AiToolParameters["type"] | undefined {
|
||||||
|
const candidates = Array.isArray(value)
|
||||||
|
? value.filter((item): item is string => typeof item === "string")
|
||||||
|
: typeof value === "string"
|
||||||
|
? [value]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const prioritized = candidates.find(item => item !== "null") ?? candidates[0];
|
||||||
|
if (!prioritized) return undefined;
|
||||||
|
|
||||||
|
switch (prioritized) {
|
||||||
|
case "object":
|
||||||
|
case "string":
|
||||||
|
case "number":
|
||||||
|
case "integer":
|
||||||
|
case "boolean":
|
||||||
|
case "array":
|
||||||
|
return prioritized;
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertJsonSchemaToToolParameters(schema: BoundaryValue): AiToolParameters | undefined {
|
||||||
|
if (!isRecord(schema)) return undefined;
|
||||||
|
|
||||||
|
const declaredType = normalizeType(schema.type);
|
||||||
|
const inferredType = declaredType
|
||||||
|
?? (schema.properties !== undefined || schema.additionalProperties !== undefined ? "object" : undefined)
|
||||||
|
?? (schema.items !== undefined ? "array" : undefined)
|
||||||
|
?? "object";
|
||||||
|
|
||||||
|
const result: AiToolParameters = {
|
||||||
|
type: inferredType,
|
||||||
|
};
|
||||||
|
|
||||||
|
const description = typeof schema.description === "string" && schema.description.trim().length > 0
|
||||||
|
? schema.description.trim()
|
||||||
|
: undefined;
|
||||||
|
if (description) result.description = description;
|
||||||
|
|
||||||
|
const defaultValue = toAiJsonValue(schema.default);
|
||||||
|
if (defaultValue !== undefined) result.default = defaultValue;
|
||||||
|
|
||||||
|
if (Array.isArray(schema.enum)) {
|
||||||
|
const enumValues = schema.enum
|
||||||
|
.filter((item): item is string => typeof item === "string" && item.length > 0);
|
||||||
|
if (enumValues.length) result.enum = enumValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof schema.minItems === "number") result.minItems = schema.minItems;
|
||||||
|
if (typeof schema.maxItems === "number") result.maxItems = schema.maxItems;
|
||||||
|
if (typeof schema.minimum === "number") result.minimum = schema.minimum;
|
||||||
|
if (typeof schema.maximum === "number") result.maximum = schema.maximum;
|
||||||
|
|
||||||
|
if (Array.isArray(schema.required)) {
|
||||||
|
const required = schema.required.filter((item): item is string => typeof item === "string" && item.trim().length > 0);
|
||||||
|
if (required.length) result.required = required;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inferredType === "object" || schema.properties !== undefined || schema.additionalProperties !== undefined) {
|
||||||
|
if (isRecord(schema.properties)) {
|
||||||
|
const properties: Record<string, AiToolParameters> = {};
|
||||||
|
for (const [key, value] of Object.entries(schema.properties)) {
|
||||||
|
const converted = convertJsonSchemaToToolParameters(value);
|
||||||
|
if (converted) properties[key] = converted;
|
||||||
|
}
|
||||||
|
if (Object.keys(properties).length) result.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (schema.additionalProperties !== undefined) {
|
||||||
|
result.additionalProperties = typeof schema.additionalProperties === "boolean"
|
||||||
|
? schema.additionalProperties
|
||||||
|
: convertJsonSchemaToToolParameters(schema.additionalProperties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inferredType === "array" || schema.items !== undefined) {
|
||||||
|
if (Array.isArray(schema.items)) {
|
||||||
|
const firstItem = schema.items[0];
|
||||||
|
if (firstItem !== undefined) {
|
||||||
|
const converted = convertJsonSchemaToToolParameters(firstItem);
|
||||||
|
if (converted) result.items = converted;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const converted = convertJsonSchemaToToolParameters(schema.items);
|
||||||
|
if (converted) result.items = converted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
import {Environment} from "../../common/environment.js";
|
||||||
|
import type {AiTool} from "../tool-types.js";
|
||||||
|
import type {ToolHandler} from "../tools/types.js";
|
||||||
|
import {normalizeToolArguments} from "../tools/utils.js";
|
||||||
|
import {toolsLogger} from "../tools/tool-logger.js";
|
||||||
|
import {convertJsonSchemaToToolParameters} from "./mcp-json-schema.js";
|
||||||
|
import {McpClient, type McpToolDefinition} from "./mcp-client.js";
|
||||||
|
import {parseMcpServerConfigs, type McpServerConfig} from "./mcp-config.js";
|
||||||
|
|
||||||
|
const logger = toolsLogger.child("mcp-registry");
|
||||||
|
|
||||||
|
type McpToolBinding = {
|
||||||
|
server: McpServerConfig;
|
||||||
|
client: McpClient;
|
||||||
|
remoteToolName: string;
|
||||||
|
localToolName: string;
|
||||||
|
tool: AiTool;
|
||||||
|
};
|
||||||
|
|
||||||
|
type McpInitSummary = {
|
||||||
|
servers: number;
|
||||||
|
loadedServers: number;
|
||||||
|
tools: number;
|
||||||
|
failedServers: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const toolBindings = new Map<string, McpToolBinding>();
|
||||||
|
const clients = new Map<string, McpClient>();
|
||||||
|
let initPromise: Promise<McpInitSummary> | undefined;
|
||||||
|
|
||||||
|
function sanitizeSegment(value: string): string {
|
||||||
|
return value
|
||||||
|
.trim()
|
||||||
|
.replace(/[^a-zA-Z0-9_]+/g, "_")
|
||||||
|
.replace(/_+/g, "_")
|
||||||
|
.replace(/^_+|_+$/g, "") || "tool";
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildLocalToolName(serverName: string, toolName: string): string {
|
||||||
|
return `mcp__${sanitizeSegment(serverName)}__${sanitizeSegment(toolName)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTool(serverName: string, tool: McpToolDefinition): AiTool {
|
||||||
|
const localName = buildLocalToolName(serverName, tool.name);
|
||||||
|
const description = tool.description?.trim()
|
||||||
|
? `[MCP ${serverName}] ${tool.description.trim()}`
|
||||||
|
: `[MCP ${serverName}] ${tool.name}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
|
name: localName,
|
||||||
|
description,
|
||||||
|
parameters: convertJsonSchemaToToolParameters(tool.inputSchema),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadServer(config: McpServerConfig): Promise<{loaded: boolean; tools: number}> {
|
||||||
|
const client = new McpClient(config);
|
||||||
|
clients.set(config.name, client);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const remoteTools = await client.listTools();
|
||||||
|
let loaded = 0;
|
||||||
|
|
||||||
|
for (const remoteTool of remoteTools) {
|
||||||
|
const localName = buildLocalToolName(config.name, remoteTool.name);
|
||||||
|
if (toolBindings.has(localName)) {
|
||||||
|
logger.warn("tool.duplicate", {
|
||||||
|
server: config.name,
|
||||||
|
tool: remoteTool.name,
|
||||||
|
localName,
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const binding: McpToolBinding = {
|
||||||
|
server: config,
|
||||||
|
client,
|
||||||
|
remoteToolName: remoteTool.name,
|
||||||
|
localToolName: localName,
|
||||||
|
tool: buildTool(config.name, remoteTool),
|
||||||
|
};
|
||||||
|
|
||||||
|
toolBindings.set(localName, binding);
|
||||||
|
loaded += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("server.loaded", {
|
||||||
|
server: config.name,
|
||||||
|
transport: config.transport,
|
||||||
|
tools: loaded,
|
||||||
|
});
|
||||||
|
return {loaded: true, tools: loaded};
|
||||||
|
} catch (error) {
|
||||||
|
logger.error("server.failed", {
|
||||||
|
server: config.name,
|
||||||
|
transport: config.transport,
|
||||||
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
});
|
||||||
|
await client.close().catch(() => undefined);
|
||||||
|
clients.delete(config.name);
|
||||||
|
return {loaded: false, tools: 0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function initializeMcpTools(): Promise<McpInitSummary> {
|
||||||
|
if (initPromise) return initPromise;
|
||||||
|
|
||||||
|
initPromise = (async () => {
|
||||||
|
toolBindings.clear();
|
||||||
|
await Promise.all([...clients.values()].map(client => client.close().catch(() => undefined)));
|
||||||
|
clients.clear();
|
||||||
|
|
||||||
|
const configs = parseMcpServerConfigs(Environment.MCP_SERVERS);
|
||||||
|
const results = await Promise.all(configs.map(config => loadServer(config)));
|
||||||
|
|
||||||
|
return {
|
||||||
|
servers: configs.length,
|
||||||
|
loadedServers: results.filter(result => result.loaded).length,
|
||||||
|
tools: [...results].reduce((sum, result) => sum + result.tools, 0),
|
||||||
|
failedServers: configs.filter((_, index) => !results[index]?.loaded).map(config => config.name),
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const summary = await initPromise;
|
||||||
|
logger.info("init.done", summary);
|
||||||
|
return summary;
|
||||||
|
} catch (error) {
|
||||||
|
initPromise = undefined;
|
||||||
|
logger.error("init.failed", {error: error instanceof Error ? error.message : String(error)});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMcpTools(): AiTool[] {
|
||||||
|
return [...toolBindings.values()].map(binding => binding.tool);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMcpToolHandlers(): Record<string, ToolHandler> {
|
||||||
|
const handlers: Record<string, ToolHandler> = {};
|
||||||
|
|
||||||
|
for (const binding of toolBindings.values()) {
|
||||||
|
handlers[binding.localToolName] = async args => {
|
||||||
|
const normalized = normalizeToolArguments(args, undefined);
|
||||||
|
return binding.client.callTool(binding.remoteToolName, normalized);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMcpToolPrompts(_toolNames: string[]): string[] {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function shutdownMcpTools(): Promise<void> {
|
||||||
|
initPromise = undefined;
|
||||||
|
toolBindings.clear();
|
||||||
|
|
||||||
|
await Promise.all([...clients.values()].map(client => client.close().catch(() => undefined)));
|
||||||
|
clients.clear();
|
||||||
|
}
|
||||||
@@ -352,6 +352,20 @@ function toolNamesFromTool(tool: BoundaryValue): string[] {
|
|||||||
return name ? [name] : [];
|
return name ? [name] : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fallbackToolInfoFromTool(toolValue: BoundaryValue, name: string): ToolRankerToolInfo | undefined {
|
||||||
|
if (!isRecord(toolValue)) return undefined;
|
||||||
|
|
||||||
|
const fn = isRecord(toolValue.function) ? toolValue.function : undefined;
|
||||||
|
const description = asOptionalString(fn?.description ?? toolValue.description)
|
||||||
|
?? `Tool ${name}.`;
|
||||||
|
|
||||||
|
return tool(
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
"Use when the tool description matches the user's request.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function getToolRankerToolInfo(name: string): ToolRankerToolInfo | undefined {
|
export function getToolRankerToolInfo(name: string): ToolRankerToolInfo | undefined {
|
||||||
return TOOL_RANKER_TOOL_INFOS[name as ToolRankerToolName];
|
return TOOL_RANKER_TOOL_INFOS[name as ToolRankerToolName];
|
||||||
}
|
}
|
||||||
@@ -363,10 +377,25 @@ export function getToolRankerToolInfos(names: readonly string[]): ToolRankerTool
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getToolRankerAvailableToolInfos(availableTools: readonly BoundaryValue[]): ToolRankerToolInfo[] {
|
export function getToolRankerAvailableToolInfos(availableTools: readonly BoundaryValue[]): ToolRankerToolInfo[] {
|
||||||
return getToolRankerToolInfos([
|
const infos = new Map<string, ToolRankerToolInfo>();
|
||||||
"no_tool",
|
|
||||||
...availableTools.flatMap(toolNamesFromTool),
|
infos.set("no_tool", TOOL_RANKER_TOOL_INFOS.no_tool);
|
||||||
]);
|
|
||||||
|
for (const tool of availableTools) {
|
||||||
|
for (const name of toolNamesFromTool(tool)) {
|
||||||
|
if (infos.has(name)) continue;
|
||||||
|
|
||||||
|
const known = getToolRankerToolInfo(name);
|
||||||
|
const fallback = fallbackToolInfoFromTool(tool, name);
|
||||||
|
if (known) {
|
||||||
|
infos.set(name, known);
|
||||||
|
} else if (fallback) {
|
||||||
|
infos.set(name, fallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...infos.values()];
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderToolLine(tool: ToolRankerToolInfo, compact: boolean): string {
|
function renderToolLine(tool: ToolRankerToolInfo, compact: boolean): string {
|
||||||
@@ -471,7 +500,7 @@ export function buildToolRankerSystemPrompt(params: {
|
|||||||
const includeExamples = params.includeExamples ?? false;
|
const includeExamples = params.includeExamples ?? false;
|
||||||
const maxExamplesPerTool = Math.max(0, params.maxExamplesPerTool ?? 1);
|
const maxExamplesPerTool = Math.max(0, params.maxExamplesPerTool ?? 1);
|
||||||
const compact = params.compact ?? true;
|
const compact = params.compact ?? true;
|
||||||
const availableTools = getToolRankerToolInfos(params.availableTools.map(tool => tool.name));
|
const availableTools = params.availableTools;
|
||||||
const availableToolNames = availableTools.map(tool => tool.name);
|
const availableToolNames = availableTools.map(tool => tool.name);
|
||||||
|
|
||||||
const sections: string[] = [
|
const sections: string[] = [
|
||||||
|
|||||||
+23
-22
@@ -45,6 +45,7 @@ import {
|
|||||||
writeFileChunk,
|
writeFileChunk,
|
||||||
writeFileChunkTool
|
writeFileChunkTool
|
||||||
} from "./files";
|
} from "./files";
|
||||||
|
import {getMcpToolHandlers, getMcpToolPrompts, getMcpTools} from "../mcp/mcp-registry.js";
|
||||||
|
|
||||||
export const defaultTools: AiTool[] = [
|
export const defaultTools: AiTool[] = [
|
||||||
getCurrentDateTimeTool,
|
getCurrentDateTimeTool,
|
||||||
@@ -72,22 +73,16 @@ export const fileTools = [
|
|||||||
deletePathTool,
|
deletePathTool,
|
||||||
] satisfies AiTool[];
|
] satisfies AiTool[];
|
||||||
|
|
||||||
// export const notesFileTools: AiTool[] = [
|
|
||||||
// createNoteTool,
|
|
||||||
// listNotesTool,
|
|
||||||
// getNoteContentTool,
|
|
||||||
// updateNoteContentTool,
|
|
||||||
// deleteNoteTool,
|
|
||||||
// sendNoteAsFileTool,
|
|
||||||
// searchNotesTool
|
|
||||||
// ]
|
|
||||||
|
|
||||||
export const getTools = (forCreator?: boolean) => {
|
export const getTools = (forCreator?: boolean) => {
|
||||||
const tools: AiTool[] = [
|
const tools: AiTool[] = Environment.DISABLE_LOCAL_TOOLS ? [] : [
|
||||||
...defaultTools,
|
...defaultTools,
|
||||||
// ...notesFileTools
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (Environment.DISABLE_LOCAL_TOOLS) {
|
||||||
|
tools.push(...getMcpTools());
|
||||||
|
return tools;
|
||||||
|
}
|
||||||
|
|
||||||
if (Environment.BRAVE_SEARCH_API_KEY) {
|
if (Environment.BRAVE_SEARCH_API_KEY) {
|
||||||
tools.push(webSearchTool);
|
tools.push(webSearchTool);
|
||||||
}
|
}
|
||||||
@@ -110,6 +105,8 @@ export const getTools = (forCreator?: boolean) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tools.push(...getMcpTools());
|
||||||
|
|
||||||
return tools;
|
return tools;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -136,20 +133,20 @@ export const fileToolHandlers = {
|
|||||||
|
|
||||||
export const getToolHandlers = () => {
|
export const getToolHandlers = () => {
|
||||||
let handlers: Record<string, ToolHandler> = {
|
let handlers: Record<string, ToolHandler> = {
|
||||||
|
...getMcpToolHandlers(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Environment.DISABLE_LOCAL_TOOLS) {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers = {
|
||||||
|
...handlers,
|
||||||
get_datetime: getCurrentDateTime,
|
get_datetime: getCurrentDateTime,
|
||||||
get_financial_market_data: getMarketRates,
|
get_financial_market_data: getMarketRates,
|
||||||
|
|
||||||
// create_note: createNote,
|
|
||||||
// list_notes: listNotes,
|
|
||||||
// get_note_content: getNoteContent,
|
|
||||||
// update_note_content: updateNoteContent,
|
|
||||||
// delete_note: deleteNote,
|
|
||||||
// send_note_as_file: sendNoteAsFile,
|
|
||||||
// search_notes: searchNotes,
|
|
||||||
|
|
||||||
...fileToolHandlers,
|
...fileToolHandlers,
|
||||||
|
|
||||||
|
|
||||||
python_interpreter: runPythonInterpreter,
|
python_interpreter: runPythonInterpreter,
|
||||||
|
|
||||||
shell_execute: shellExecute,
|
shell_execute: shellExecute,
|
||||||
@@ -157,13 +154,16 @@ export const getToolHandlers = () => {
|
|||||||
web_search: webSearch,
|
web_search: webSearch,
|
||||||
|
|
||||||
get_weather: getWeather,
|
get_weather: getWeather,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return handlers;
|
return handlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getToolPrompts(toolNames: string[]): string[] {
|
export function getToolPrompts(toolNames: string[]): string[] {
|
||||||
|
if (Environment.DISABLE_LOCAL_TOOLS) {
|
||||||
|
return getMcpToolPrompts(toolNames);
|
||||||
|
}
|
||||||
|
|
||||||
const prompts: string[] = [];
|
const prompts: string[] = [];
|
||||||
|
|
||||||
for (const toolName of toolNames) {
|
for (const toolName of toolNames) {
|
||||||
@@ -185,5 +185,6 @@ export function getToolPrompts(toolNames: string[]): string[] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prompts.push(...getMcpToolPrompts(toolNames));
|
||||||
return prompts;
|
return prompts;
|
||||||
}
|
}
|
||||||
@@ -214,6 +214,8 @@ const RuntimeEnvSchema = z.object({
|
|||||||
SEND_TIME_TOOK: optionalBooleanSchema,
|
SEND_TIME_TOOK: optionalBooleanSchema,
|
||||||
|
|
||||||
ENABLE_PYTHON_INTERPRETER: optionalBooleanSchema,
|
ENABLE_PYTHON_INTERPRETER: optionalBooleanSchema,
|
||||||
|
DISABLE_LOCAL_TOOLS: optionalBooleanSchema,
|
||||||
|
MCP_SERVERS: optionalStringSchema,
|
||||||
|
|
||||||
OLLAMA_API_KEY: optionalStringSchema,
|
OLLAMA_API_KEY: optionalStringSchema,
|
||||||
OLLAMA_ADDRESS: optionalStringSchema,
|
OLLAMA_ADDRESS: optionalStringSchema,
|
||||||
@@ -308,6 +310,8 @@ export class Environment {
|
|||||||
static SEND_TIME_TOOK: boolean = false;
|
static SEND_TIME_TOOK: boolean = false;
|
||||||
|
|
||||||
static ENABLE_PYTHON_INTERPRETER: boolean = false;
|
static ENABLE_PYTHON_INTERPRETER: boolean = false;
|
||||||
|
static DISABLE_LOCAL_TOOLS: boolean = false;
|
||||||
|
static MCP_SERVERS?: string;
|
||||||
|
|
||||||
static OLLAMA_API_KEY?: string;
|
static OLLAMA_API_KEY?: string;
|
||||||
static OLLAMA_ADDRESS?: string;
|
static OLLAMA_ADDRESS?: string;
|
||||||
@@ -1842,6 +1846,8 @@ export class Environment {
|
|||||||
Environment.SEND_TIME_TOOK = env.SEND_TIME_TOOK ?? false;
|
Environment.SEND_TIME_TOOK = env.SEND_TIME_TOOK ?? false;
|
||||||
|
|
||||||
Environment.ENABLE_PYTHON_INTERPRETER = env.ENABLE_PYTHON_INTERPRETER ?? false;
|
Environment.ENABLE_PYTHON_INTERPRETER = env.ENABLE_PYTHON_INTERPRETER ?? false;
|
||||||
|
Environment.DISABLE_LOCAL_TOOLS = env.DISABLE_LOCAL_TOOLS ?? false;
|
||||||
|
Environment.MCP_SERVERS = env.MCP_SERVERS;
|
||||||
|
|
||||||
Environment.OLLAMA_API_KEY = env.OLLAMA_API_KEY;
|
Environment.OLLAMA_API_KEY = env.OLLAMA_API_KEY;
|
||||||
Environment.OLLAMA_ADDRESS = env.OLLAMA_ADDRESS;
|
Environment.OLLAMA_ADDRESS = env.OLLAMA_ADDRESS;
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ import {AIAudit} from "./commands/ai-audit.js";
|
|||||||
import {AIMetrics} from "./commands/ai-metrics.js";
|
import {AIMetrics} from "./commands/ai-metrics.js";
|
||||||
import {AIRequests} from "./commands/ai-requests.js";
|
import {AIRequests} from "./commands/ai-requests.js";
|
||||||
import {cleanupStaleRagProviderState} from "./ai/rag-retention.js";
|
import {cleanupStaleRagProviderState} from "./ai/rag-retention.js";
|
||||||
|
import {initializeMcpTools, shutdownMcpTools} from "./ai/mcp/mcp-registry.js";
|
||||||
|
|
||||||
process.setUncaughtExceptionCaptureCallback(logError);
|
process.setUncaughtExceptionCaptureCallback(logError);
|
||||||
|
|
||||||
@@ -234,6 +235,11 @@ export async function shutdown(signal: NodeJS.Signals | "manual") {
|
|||||||
await bot.stopPolling();
|
await bot.stopPolling();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError(error instanceof Error ? error : String(error));
|
logError(error instanceof Error ? error : String(error));
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
await shutdownMcpTools();
|
||||||
|
} catch (error) {
|
||||||
|
logError(error instanceof Error ? error : String(error));
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
await DatabaseManager.close();
|
await DatabaseManager.close();
|
||||||
@@ -243,6 +249,7 @@ export async function shutdown(signal: NodeJS.Signals | "manual") {
|
|||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
@@ -280,6 +287,7 @@ async function main() {
|
|||||||
|
|
||||||
await measureStartupStep("cleanup_internal_artifacts", () => cleanupInternalArtifactCache(), () => ({retentionDays: 14}));
|
await measureStartupStep("cleanup_internal_artifacts", () => cleanupInternalArtifactCache(), () => ({retentionDays: 14}));
|
||||||
await measureStartupStep("cleanup_stale_rag_provider_state", () => cleanupStaleRagProviderState(), () => ({retentionDays: 14}));
|
await measureStartupStep("cleanup_stale_rag_provider_state", () => cleanupStaleRagProviderState(), () => ({retentionDays: 14}));
|
||||||
|
await measureStartupStep("mcp.initialize", () => initializeMcpTools());
|
||||||
await measureStartupStep("observability.snapshot", async () => {
|
await measureStartupStep("observability.snapshot", async () => {
|
||||||
const [aiRequests, attachments, artifacts, requestAudits] = await Promise.all([
|
const [aiRequests, attachments, artifacts, requestAudits] = await Promise.all([
|
||||||
DatabaseManager.getAllAiRequests(),
|
DatabaseManager.getAllAiRequests(),
|
||||||
|
|||||||
Reference in New Issue
Block a user