feat: 添加 web_search 工具和权限管控
- 新增 web_search 工具,使用 Tavily SDK 进行网络搜索 - 支持搜索深度(basic/advanced)和主题(general/news/finance)配置 - 新增 WebPermissionChecker 权限检查器 - 搜索操作默认需要用户确认,支持会话级权限记忆 - 配置文件支持 tavilyApiKey 存储
This commit is contained in:
Generated
+365
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "^2.0.54",
|
||||
"@ai-sdk/deepseek": "^1.0.31",
|
||||
"@tavily/core": "^0.6.0",
|
||||
"ai": "^5.0.108",
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.1.0",
|
||||
@@ -900,6 +901,17 @@
|
||||
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tavily/core": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tavily/core/-/core-0.6.0.tgz",
|
||||
"integrity": "sha512-QJQko6BtDWFYNeE7BKFVDMPuKfLJWjRVyQmo5jAhG3A3Xgu1e/EIIRTdWFc5TyFccc8t14zrzPxxUy1YL2/AYg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"js-tiktoken": "^1.0.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.2.tgz",
|
||||
@@ -919,6 +931,15 @@
|
||||
"node": ">= 20"
|
||||
}
|
||||
},
|
||||
"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/ai": {
|
||||
"version": "5.0.108",
|
||||
"resolved": "https://registry.npmjs.org/ai/-/ai-5.0.108.tgz",
|
||||
@@ -964,6 +985,56 @@
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
|
||||
"integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.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/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
|
||||
@@ -1036,6 +1107,18 @@
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "12.1.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
|
||||
@@ -1045,12 +1128,97 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "10.6.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
|
||||
"integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.27.1",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.1.tgz",
|
||||
@@ -1102,6 +1270,42 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.11",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
||||
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
@@ -1117,6 +1321,15 @@
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-east-asian-width": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz",
|
||||
@@ -1129,6 +1342,43 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/get-tsconfig": {
|
||||
"version": "4.13.0",
|
||||
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
|
||||
@@ -1142,6 +1392,70 @@
|
||||
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
|
||||
@@ -1217,6 +1531,15 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tiktoken": {
|
||||
"version": "1.0.21",
|
||||
"resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.21.tgz",
|
||||
"integrity": "sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/json-schema": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
|
||||
@@ -1251,6 +1574,36 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-function": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
|
||||
@@ -1263,6 +1616,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mute-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz",
|
||||
@@ -1330,6 +1689,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/resolve-pkg-maps": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "^2.0.54",
|
||||
"@ai-sdk/deepseek": "^1.0.31",
|
||||
"@tavily/core": "^0.6.0",
|
||||
"ai": "^5.0.108",
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^12.1.0",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export type { PermissionChecker, BasePermissionConfig } from './base.js';
|
||||
export { BashPermissionChecker } from './bash.js';
|
||||
export { FilePermissionChecker } from './file.js';
|
||||
export { WebPermissionChecker } from './web.js';
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
import type {
|
||||
WebPermissionConfig,
|
||||
WebPermissionContext,
|
||||
PermissionCheckResult,
|
||||
PermissionDecision,
|
||||
PermissionContext,
|
||||
} from '../types.js';
|
||||
import type { PermissionChecker } from './base.js';
|
||||
|
||||
// 默认 Web 权限配置
|
||||
const DEFAULT_CONFIG: WebPermissionConfig = {
|
||||
default: 'ask', // 默认需要确认
|
||||
allowAdvancedSearch: true,
|
||||
allowedTopics: [], // 空数组表示允许所有主题
|
||||
};
|
||||
|
||||
/**
|
||||
* Web 搜索权限检查器
|
||||
* 控制网络搜索操作的权限
|
||||
*/
|
||||
export class WebPermissionChecker implements PermissionChecker {
|
||||
readonly name = 'web';
|
||||
|
||||
private config: WebPermissionConfig;
|
||||
private askCallback?: (ctx: PermissionContext) => Promise<PermissionDecision>;
|
||||
private sessionPermissions = new Map<string, 'allow' | 'deny'>();
|
||||
|
||||
constructor() {
|
||||
this.config = { ...DEFAULT_CONFIG };
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置权限询问回调
|
||||
*/
|
||||
setAskCallback(callback: (ctx: PermissionContext) => Promise<PermissionDecision>): void {
|
||||
this.askCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 Web 搜索权限
|
||||
*/
|
||||
async checkWebPermission(ctx: WebPermissionContext): Promise<PermissionCheckResult> {
|
||||
const { query, searchDepth, topic } = ctx;
|
||||
|
||||
// 1. 检查深度搜索权限
|
||||
if (searchDepth === 'advanced' && !this.config.allowAdvancedSearch) {
|
||||
return {
|
||||
allowed: false,
|
||||
action: 'deny',
|
||||
reason: '不允许深度搜索',
|
||||
};
|
||||
}
|
||||
|
||||
// 2. 检查主题限制
|
||||
if (this.config.allowedTopics.length > 0 && topic) {
|
||||
if (!this.config.allowedTopics.includes(topic)) {
|
||||
return {
|
||||
allowed: false,
|
||||
action: 'deny',
|
||||
reason: `不允许搜索主题: ${topic}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 检查会话级别的临时权限
|
||||
const sessionKey = `web_search`;
|
||||
const sessionPerm = this.sessionPermissions.get(sessionKey);
|
||||
if (sessionPerm === 'allow') {
|
||||
return {
|
||||
allowed: true,
|
||||
action: 'allow',
|
||||
reason: '本次会话已允许网络搜索',
|
||||
};
|
||||
}
|
||||
if (sessionPerm === 'deny') {
|
||||
return {
|
||||
allowed: false,
|
||||
action: 'deny',
|
||||
reason: '本次会话已拒绝网络搜索',
|
||||
};
|
||||
}
|
||||
|
||||
// 4. 根据默认策略处理
|
||||
const action = this.config.default;
|
||||
|
||||
if (action === 'allow') {
|
||||
return {
|
||||
allowed: true,
|
||||
action: 'allow',
|
||||
reason: '默认允许网络搜索',
|
||||
};
|
||||
}
|
||||
|
||||
if (action === 'deny') {
|
||||
return {
|
||||
allowed: false,
|
||||
action: 'deny',
|
||||
reason: '默认拒绝网络搜索',
|
||||
};
|
||||
}
|
||||
|
||||
// action === 'ask'
|
||||
if (!this.askCallback) {
|
||||
return {
|
||||
allowed: false,
|
||||
action: 'ask',
|
||||
needsConfirmation: true,
|
||||
reason: `搜索: ${query}`,
|
||||
};
|
||||
}
|
||||
|
||||
// 调用回调询问用户
|
||||
const decision = await this.askCallback({
|
||||
command: `web_search: ${query}`,
|
||||
workdir: process.cwd(),
|
||||
});
|
||||
|
||||
if (decision.remember) {
|
||||
this.sessionPermissions.set(sessionKey, decision.allow ? 'allow' : 'deny');
|
||||
}
|
||||
|
||||
return {
|
||||
allowed: decision.allow,
|
||||
action: decision.allow ? 'allow' : 'deny',
|
||||
reason: decision.allow ? '用户允许' : '用户拒绝',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现 PermissionChecker 接口的 check 方法
|
||||
* 从通用 PermissionContext 中提取 Web 搜索信息
|
||||
*/
|
||||
async check(ctx: PermissionContext): Promise<PermissionCheckResult> {
|
||||
// 从 command 中提取搜索查询
|
||||
const query = ctx.command.replace(/^web_search:\s*/, '');
|
||||
return this.checkWebPermission({ query });
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除会话权限
|
||||
*/
|
||||
clearSessionPermissions(): void {
|
||||
this.sessionPermissions.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前配置
|
||||
*/
|
||||
getConfig(): WebPermissionConfig {
|
||||
return { ...this.config };
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新配置
|
||||
*/
|
||||
setConfig(config: Partial<WebPermissionConfig>): void {
|
||||
this.config = { ...this.config, ...config };
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,12 @@ import type {
|
||||
PermissionCheckResult,
|
||||
PermissionDecision,
|
||||
FilePermissionContext,
|
||||
WebPermissionContext,
|
||||
} from './types.js';
|
||||
import type { PermissionChecker } from './checkers/base.js';
|
||||
import { BashPermissionChecker } from './checkers/bash.js';
|
||||
import { FilePermissionChecker } from './checkers/file.js';
|
||||
import { WebPermissionChecker } from './checkers/web.js';
|
||||
|
||||
/**
|
||||
* 权限管理器
|
||||
@@ -20,6 +22,7 @@ export class PermissionManager {
|
||||
// 注册默认的检查器
|
||||
this.registerChecker(new BashPermissionChecker(projectRoot));
|
||||
this.registerChecker(new FilePermissionChecker(projectRoot));
|
||||
this.registerChecker(new WebPermissionChecker());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,6 +103,22 @@ export class PermissionManager {
|
||||
return fileChecker.checkFilePermission(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 Web 搜索权限(便捷方法)
|
||||
*/
|
||||
async checkWebPermission(ctx: WebPermissionContext): Promise<PermissionCheckResult> {
|
||||
const webChecker = this.getChecker<WebPermissionChecker>('web');
|
||||
if (!webChecker) {
|
||||
return {
|
||||
allowed: false,
|
||||
action: 'ask',
|
||||
needsConfirmation: true,
|
||||
reason: 'Web 权限检查器未注册',
|
||||
};
|
||||
}
|
||||
return webChecker.checkWebPermission(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有检查器的会话权限
|
||||
*/
|
||||
|
||||
@@ -88,3 +88,21 @@ export interface PermissionDecision {
|
||||
allow: boolean;
|
||||
remember?: boolean; // 是否记住这个决定
|
||||
}
|
||||
|
||||
// Web 搜索权限请求上下文
|
||||
export interface WebPermissionContext {
|
||||
query: string; // 搜索查询
|
||||
searchDepth?: 'basic' | 'advanced'; // 搜索深度
|
||||
topic?: 'general' | 'news' | 'finance'; // 搜索主题
|
||||
maxResults?: number; // 最大结果数
|
||||
}
|
||||
|
||||
// Web 权限配置
|
||||
export interface WebPermissionConfig {
|
||||
// 默认策略
|
||||
default: PermissionAction;
|
||||
// 是否允许深度搜索
|
||||
allowAdvancedSearch: boolean;
|
||||
// 搜索主题限制(空数组表示允许所有)
|
||||
allowedTopics: ('general' | 'news' | 'finance')[];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
搜索网络获取最新信息。使用 Tavily API 进行智能搜索,返回相关网页内容和 AI 摘要。
|
||||
|
||||
这是进行网络搜索的首选工具,不要使用 curl 或 bash 命令来搜索网络。
|
||||
|
||||
适用场景:
|
||||
- 查询最新新闻、事件、游戏更新
|
||||
- 搜索技术文档、API 参考
|
||||
- 获取实时数据(股价、天气等)
|
||||
- 查找开源项目、库的信息
|
||||
- 了解最新的技术趋势
|
||||
|
||||
参数说明:
|
||||
- query: 搜索关键词(必填)
|
||||
- max_results: 返回结果数量,1-20,默认 5
|
||||
- search_depth: "basic" 快速搜索 / "advanced" 深度搜索
|
||||
- topic: "general" 通用 / "news" 新闻 / "finance" 财经
|
||||
- include_answer: 是否包含 AI 摘要,默认 true
|
||||
|
||||
返回内容:
|
||||
- AI 生成的摘要答案
|
||||
- 相关网页列表(标题、链接、内容摘要)
|
||||
@@ -23,6 +23,9 @@ import {
|
||||
deleteFileTool,
|
||||
} from './filesystem/index.js';
|
||||
|
||||
// Web 工具
|
||||
import { webSearchTool } from './web/index.js';
|
||||
|
||||
// 所有工具列表(用于注册)
|
||||
const allToolsWithMetadata: ToolWithMetadata[] = [
|
||||
// 核心工具 (deferLoading: false)
|
||||
@@ -43,6 +46,9 @@ const allToolsWithMetadata: ToolWithMetadata[] = [
|
||||
moveFileTool,
|
||||
copyFileTool,
|
||||
deleteFileTool,
|
||||
|
||||
// Web 工具 (deferLoading: true)
|
||||
webSearchTool,
|
||||
];
|
||||
|
||||
// 注册所有工具到 registry
|
||||
|
||||
@@ -62,7 +62,7 @@ export const toolSearchTool: ToolWithMetadata = {
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: `找到 ${results.length} 个相关工具:\n\n${toolList}\n\n这些工具现在可以使用了。请选择合适的工具来完成任务。`,
|
||||
output: `找到 ${results.length} 个相关工具:\n\n${toolList}\n\n重要:这些工具现在已经可以直接调用了。请立即使用合适的工具(如 web_search)来完成任务,不要使用 bash 命令代替。`,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { webSearchTool } from './web_search.js';
|
||||
@@ -0,0 +1,138 @@
|
||||
import { tavily } from '@tavily/core';
|
||||
import type { ToolResult } from '../../types/index.js';
|
||||
import type { ToolWithMetadata } from '../types.js';
|
||||
import { loadDescription } from '../load_description.js';
|
||||
import { getConfig } from '../../utils/config.js';
|
||||
import { getPermissionManager } from '../../permission/index.js';
|
||||
|
||||
export const webSearchTool: ToolWithMetadata = {
|
||||
name: 'web_search',
|
||||
description: loadDescription('web_search'),
|
||||
metadata: {
|
||||
name: 'web_search',
|
||||
category: 'web',
|
||||
description: '搜索网络获取最新信息',
|
||||
keywords: ['search', 'web', 'internet', 'google', 'query', '搜索', '网络', '查询', '互联网'],
|
||||
deferLoading: false, // 核心工具,始终可用
|
||||
},
|
||||
parameters: {
|
||||
query: {
|
||||
type: 'string',
|
||||
description: '搜索查询关键词',
|
||||
required: true,
|
||||
},
|
||||
max_results: {
|
||||
type: 'number',
|
||||
description: '返回结果数量(默认 5,最大 20)',
|
||||
required: false,
|
||||
},
|
||||
search_depth: {
|
||||
type: 'string',
|
||||
description: '搜索深度: "basic" 快速搜索,"advanced" 深度搜索(默认 basic)',
|
||||
required: false,
|
||||
},
|
||||
topic: {
|
||||
type: 'string',
|
||||
description: '搜索主题: "general" 通用,"news" 新闻,"finance" 财经(默认 general)',
|
||||
required: false,
|
||||
},
|
||||
include_answer: {
|
||||
type: 'boolean',
|
||||
description: '是否包含 AI 生成的摘要答案(默认 true)',
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
execute: async (params: Record<string, unknown>): Promise<ToolResult> => {
|
||||
const query = params.query as string;
|
||||
const maxResults = Math.min((params.max_results as number) || 5, 20);
|
||||
const searchDepth = (params.search_depth as 'basic' | 'advanced') || 'basic';
|
||||
const topic = (params.topic as 'general' | 'news' | 'finance') || 'general';
|
||||
const includeAnswer = params.include_answer !== false;
|
||||
|
||||
// 权限检查
|
||||
const permissionManager = getPermissionManager();
|
||||
const permResult = await permissionManager.checkWebPermission({
|
||||
query,
|
||||
searchDepth,
|
||||
topic,
|
||||
maxResults,
|
||||
});
|
||||
|
||||
if (!permResult.allowed) {
|
||||
// 如果需要用户确认但没有设置回调,返回等待确认的状态
|
||||
if (permResult.needsConfirmation) {
|
||||
return {
|
||||
success: false,
|
||||
output: '',
|
||||
error: `需要用户确认网络搜索: "${query}"\n原因: ${permResult.reason || '需要权限确认'}`,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
output: '',
|
||||
error: `网络搜索权限被拒绝: ${permResult.reason || '搜索不被允许'}`,
|
||||
};
|
||||
}
|
||||
|
||||
// 获取 Tavily API Key
|
||||
const config = getConfig();
|
||||
const apiKey = process.env.TAVILY_API_KEY || config.tavilyApiKey;
|
||||
|
||||
if (!apiKey) {
|
||||
return {
|
||||
success: false,
|
||||
output: '',
|
||||
error: '未配置 Tavily API Key。请设置环境变量 TAVILY_API_KEY 或在配置文件中添加 tavilyApiKey。',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
// 使用 Tavily SDK
|
||||
const client = tavily({ apiKey });
|
||||
const response = await client.search(query, {
|
||||
searchDepth,
|
||||
topic,
|
||||
maxResults,
|
||||
includeAnswer,
|
||||
});
|
||||
|
||||
// 格式化输出
|
||||
let output = `## 搜索结果: "${query}"\n\n`;
|
||||
|
||||
// 如果有 AI 摘要答案
|
||||
if (response.answer) {
|
||||
output += `### 摘要\n${response.answer}\n\n`;
|
||||
}
|
||||
|
||||
// 搜索结果列表
|
||||
if (response.results && response.results.length > 0) {
|
||||
output += `### 相关链接 (${response.results.length} 条)\n\n`;
|
||||
|
||||
for (let i = 0; i < response.results.length; i++) {
|
||||
const result = response.results[i];
|
||||
output += `**${i + 1}. ${result.title}**\n`;
|
||||
output += `链接: ${result.url}\n`;
|
||||
// 截断过长的内容
|
||||
const content = result.content.length > 300
|
||||
? result.content.substring(0, 300) + '...'
|
||||
: result.content;
|
||||
output += `${content}\n\n`;
|
||||
}
|
||||
} else {
|
||||
output += '未找到相关结果。\n';
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
output: '',
|
||||
error: `搜索失败: ${error instanceof Error ? error.message : String(error)}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -12,6 +12,7 @@ interface StoredConfig {
|
||||
deepseekApiKey?: string;
|
||||
model?: string;
|
||||
maxTokens?: number;
|
||||
tavilyApiKey?: string;
|
||||
}
|
||||
|
||||
// 默认模型配置
|
||||
@@ -40,6 +41,19 @@ const DEFAULT_SYSTEM_PROMPT = `你是一个运行在终端中的 AI 编程助手
|
||||
当前工作目录: ${process.cwd()}
|
||||
操作系统: ${process.platform}`;
|
||||
|
||||
// 获取原始配置(包含所有字段)
|
||||
export function getConfig(): StoredConfig {
|
||||
if (fs.existsSync(CONFIG_FILE)) {
|
||||
try {
|
||||
const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
||||
return JSON.parse(content);
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// 加载配置
|
||||
export function loadConfig(): AgentConfig {
|
||||
// 从环境变量获取
|
||||
|
||||
Reference in New Issue
Block a user