fix(plugin): make tool values structural (#37202)
This commit is contained in:
@@ -724,6 +724,7 @@
|
|||||||
"@opencode-ai/client": "workspace:*",
|
"@opencode-ai/client": "workspace:*",
|
||||||
"@opencode-ai/schema": "workspace:*",
|
"@opencode-ai/schema": "workspace:*",
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
|
"@standard-schema/spec": "^1.1.0",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
"zod": "catalog:",
|
"zod": "catalog:",
|
||||||
},
|
},
|
||||||
@@ -3008,7 +3009,7 @@
|
|||||||
|
|
||||||
"@standard-community/standard-openapi": ["@standard-community/standard-openapi@0.2.9", "", { "peerDependencies": { "@standard-community/standard-json": "^0.3.5", "@standard-schema/spec": "^1.0.0", "arktype": "^2.1.20", "effect": "^3.17.14", "openapi-types": "^12.1.3", "sury": "^10.0.0", "typebox": "^1.0.0", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-openapi": "^4" }, "optionalPeers": ["arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-openapi"] }, "sha512-htj+yldvN1XncyZi4rehbf9kLbu8os2Ke/rfqoZHCMHuw34kiF3LP/yQPdA0tQ940y8nDq3Iou8R3wG+AGGyvg=="],
|
"@standard-community/standard-openapi": ["@standard-community/standard-openapi@0.2.9", "", { "peerDependencies": { "@standard-community/standard-json": "^0.3.5", "@standard-schema/spec": "^1.0.0", "arktype": "^2.1.20", "effect": "^3.17.14", "openapi-types": "^12.1.3", "sury": "^10.0.0", "typebox": "^1.0.0", "valibot": "^1.1.0", "zod": "^3.25.0 || ^4.0.0", "zod-openapi": "^4" }, "optionalPeers": ["arktype", "effect", "sury", "typebox", "valibot", "zod", "zod-openapi"] }, "sha512-htj+yldvN1XncyZi4rehbf9kLbu8os2Ke/rfqoZHCMHuw34kiF3LP/yQPdA0tQ940y8nDq3Iou8R3wG+AGGyvg=="],
|
||||||
|
|
||||||
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
|
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"@stoplight/better-ajv-errors": ["@stoplight/better-ajv-errors@1.0.3", "", { "dependencies": { "jsonpointer": "^5.0.0", "leven": "^3.1.0" }, "peerDependencies": { "ajv": ">=8" } }, "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA=="],
|
"@stoplight/better-ajv-errors": ["@stoplight/better-ajv-errors@1.0.3", "", { "dependencies": { "jsonpointer": "^5.0.0", "leven": "^3.1.0" }, "peerDependencies": { "ajv": ">=8" } }, "sha512-0p9uXkuB22qGdNfy3VeEhxkU5uwvp/KrBTAbrLBURv6ilxIVwanKwjMc41lQfIVgPGcOkmLbTolfFrSsueu7zA=="],
|
||||||
|
|
||||||
@@ -6392,8 +6393,6 @@
|
|||||||
|
|
||||||
"@ai-sdk/perplexity/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
"@ai-sdk/perplexity/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
||||||
|
|
||||||
"@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/togetherai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
"@ai-sdk/togetherai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
||||||
|
|
||||||
"@ai-sdk/vercel/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
"@ai-sdk/vercel/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="],
|
||||||
@@ -6610,6 +6609,8 @@
|
|||||||
|
|
||||||
"@hey-api/openapi-ts/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
"@hey-api/openapi-ts/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
||||||
|
|
||||||
|
"@hono/standard-validator/@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
|
||||||
|
|
||||||
"@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
"@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="],
|
||||||
|
|
||||||
"@inquirer/core/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
|
"@inquirer/core/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
|
||||||
@@ -7332,8 +7333,6 @@
|
|||||||
|
|
||||||
"editorconfig/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
|
"editorconfig/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="],
|
||||||
|
|
||||||
"effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"electron-builder/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
"electron-builder/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||||
|
|
||||||
"electron-builder/yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
"electron-builder/yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
||||||
@@ -7394,8 +7393,6 @@
|
|||||||
|
|
||||||
"fumadocs-core/shiki": ["shiki@4.3.1", "", { "dependencies": { "@shikijs/core": "4.3.1", "@shikijs/engine-javascript": "4.3.1", "@shikijs/engine-oniguruma": "4.3.1", "@shikijs/langs": "4.3.1", "@shikijs/themes": "4.3.1", "@shikijs/types": "4.3.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw=="],
|
"fumadocs-core/shiki": ["shiki@4.3.1", "", { "dependencies": { "@shikijs/core": "4.3.1", "@shikijs/engine-javascript": "4.3.1", "@shikijs/engine-oniguruma": "4.3.1", "@shikijs/langs": "4.3.1", "@shikijs/themes": "4.3.1", "@shikijs/types": "4.3.1", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw=="],
|
||||||
|
|
||||||
"fumadocs-mdx/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"fumadocs-mdx/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
|
"fumadocs-mdx/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
|
||||||
|
|
||||||
"fumadocs-mdx/esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="],
|
"fumadocs-mdx/esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="],
|
||||||
@@ -7534,6 +7531,8 @@
|
|||||||
|
|
||||||
"opencode/@solid-primitives/scheduled": ["@solid-primitives/scheduled@1.5.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-/j2igE0xyNaHhj6kMfcUQn5rAVSTLbAX+CDEBm25hSNBmNiHLu2lM7Usj2kJJ5j36D67bE8wR1hBNA8hjtvsQA=="],
|
"opencode/@solid-primitives/scheduled": ["@solid-primitives/scheduled@1.5.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-/j2igE0xyNaHhj6kMfcUQn5rAVSTLbAX+CDEBm25hSNBmNiHLu2lM7Usj2kJJ5j36D67bE8wR1hBNA8hjtvsQA=="],
|
||||||
|
|
||||||
|
"opencode/@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
|
||||||
|
|
||||||
"opencode/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="],
|
"opencode/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="],
|
||||||
|
|
||||||
"opencode/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
"opencode/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="],
|
||||||
@@ -7740,46 +7739,6 @@
|
|||||||
|
|
||||||
"@actions/github/@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
|
"@actions/github/@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="],
|
||||||
|
|
||||||
"@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/anthropic/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/azure/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/cerebras/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/cohere/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/deepgram/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/deepinfra/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/deepseek/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/elevenlabs/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/fireworks/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/google-vertex/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/google/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/groq/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/mistral/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/openai-compatible/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/openai/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/perplexity/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/togetherai/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/vercel/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@ai-sdk/xai/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@astrojs/check/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
|
"@astrojs/check/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
|
||||||
|
|
||||||
"@astrojs/check/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
"@astrojs/check/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||||
@@ -8382,10 +8341,6 @@
|
|||||||
|
|
||||||
"@solidjs/start/shiki/@shikijs/types": ["@shikijs/types@1.29.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="],
|
"@solidjs/start/shiki/@shikijs/types": ["@shikijs/types@1.29.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="],
|
||||||
|
|
||||||
"@standard-community/standard-json/effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@standard-community/standard-openapi/effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@stoplight/spectral-core/minimatch/brace-expansion": ["brace-expansion@1.1.15", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg=="],
|
"@stoplight/spectral-core/minimatch/brace-expansion": ["brace-expansion@1.1.15", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg=="],
|
||||||
|
|
||||||
"@storybook/addon-docs/react-dom/scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
|
"@storybook/addon-docs/react-dom/scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
|
||||||
@@ -8850,10 +8805,6 @@
|
|||||||
|
|
||||||
"venice-ai-sdk-provider/@ai-sdk/provider-utils/@ai-sdk/provider": ["@ai-sdk/provider@3.0.12", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-sj9DWTJ2Ze0WR9qsiOPqoqzNx3OxL6iMxHImbhvoe9qOspekbzxNDMiJ4TIGfYHYh9w4OmBjz3prvqhzTi96+Q=="],
|
"venice-ai-sdk-provider/@ai-sdk/provider-utils/@ai-sdk/provider": ["@ai-sdk/provider@3.0.12", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-sj9DWTJ2Ze0WR9qsiOPqoqzNx3OxL6iMxHImbhvoe9qOspekbzxNDMiJ4TIGfYHYh9w4OmBjz3prvqhzTi96+Q=="],
|
||||||
|
|
||||||
"venice-ai-sdk-provider/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"vitest/@vitest/expect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"vitest/@vitest/expect/chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="],
|
"vitest/@vitest/expect/chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="],
|
||||||
|
|
||||||
"wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="],
|
"wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="],
|
||||||
@@ -9118,8 +9069,6 @@
|
|||||||
|
|
||||||
"@octokit/rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
|
"@octokit/rest/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
|
||||||
|
|
||||||
"@opencode-ai/core/@ai-sdk/openai/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"@opencode-ai/desktop/@actions/artifact/@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
|
"@opencode-ai/desktop/@actions/artifact/@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="],
|
||||||
|
|
||||||
"@opencode-ai/www/@cloudflare/vite-plugin/@cloudflare/unenv-preset/workerd": ["workerd@1.20260708.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260708.1", "@cloudflare/workerd-darwin-arm64": "1.20260708.1", "@cloudflare/workerd-linux-64": "1.20260708.1", "@cloudflare/workerd-linux-arm64": "1.20260708.1", "@cloudflare/workerd-windows-64": "1.20260708.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-WAK+Kt/VVCSldH2qSr8lx46XCJ4Q+bdlHNaFqUtOHthBEIB8C1N8HVW+VOLrxDoTCk0NGNv0zajnBeQK4JOB9w=="],
|
"@opencode-ai/www/@cloudflare/vite-plugin/@cloudflare/unenv-preset/workerd": ["workerd@1.20260708.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260708.1", "@cloudflare/workerd-darwin-arm64": "1.20260708.1", "@cloudflare/workerd-linux-64": "1.20260708.1", "@cloudflare/workerd-linux-arm64": "1.20260708.1", "@cloudflare/workerd-windows-64": "1.20260708.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-WAK+Kt/VVCSldH2qSr8lx46XCJ4Q+bdlHNaFqUtOHthBEIB8C1N8HVW+VOLrxDoTCk0NGNv0zajnBeQK4JOB9w=="],
|
||||||
@@ -9302,14 +9251,6 @@
|
|||||||
|
|
||||||
"@vitejs/plugin-react/vite/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
|
"@vitejs/plugin-react/vite/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
|
||||||
|
|
||||||
"ai-gateway-provider/@ai-sdk/amazon-bedrock/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"ai-gateway-provider/@ai-sdk/anthropic/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"ai-gateway-provider/@ai-sdk/azure/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"ai-gateway-provider/@ai-sdk/deepseek/@ai-sdk/provider-utils/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
||||||
|
|
||||||
"ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
"ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
"app-builder-lib/@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="],
|
"app-builder-lib/@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="],
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ This folder owns Core's one local tool representation, process and Location regi
|
|||||||
|
|
||||||
## Representations
|
## Representations
|
||||||
|
|
||||||
- `tool.ts` defines the opaque canonical `Tool.make({ description, input, output, execute, toModelOutput })` value. Shipped built-ins and plugin tools use the same type.
|
- `tool.ts` defines the structural canonical `Tool.make({ description, input, output, execute, toModelOutput })` declaration. Shipped built-ins and plugin tools use the same type.
|
||||||
- `tools.ts` exposes the registration-only `Tools.Service` view used by Location producers.
|
- `tools.ts` exposes the registration-only `Tools.Service` view used by Location producers.
|
||||||
- `registry.ts` stores only canonical Location registrations, derives definitions, invokes tools, and applies generic output bounding.
|
- `registry.ts` stores only canonical Location registrations, derives definitions, invokes tools, and applies generic output bounding.
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ Do not add a second executable entry type, registry-owned executor, authorizatio
|
|||||||
|
|
||||||
## Construction
|
## Construction
|
||||||
|
|
||||||
Tool schemas and projection use `input` and `output` terminology. A tool value is opaque: its codecs, executor, definition derivation, and catalog permission declaration are private runtime details.
|
Tool schemas and projection use `input` and `output` terminology. A tool value carries its schemas, executor, projection, and optional catalog permission directly so separately loaded plugin package instances can exchange it structurally.
|
||||||
|
|
||||||
Location-scoped built-in layers acquire `PermissionV2.Service` and every other required Location service while the layer is constructed. The executor captures those services. Permission sources are always constructed from the canonical invocation context:
|
Location-scoped built-in layers acquire `PermissionV2.Service` and every other required Location service while the layer is constructed. The executor captures those services. Permission sources are always constructed from the canonical invocation context:
|
||||||
|
|
||||||
|
|||||||
@@ -107,17 +107,6 @@ describe("ToolRegistry", () => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.effect("reuses model definitions across requests", () =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const service = yield* ToolRegistry.Service
|
|
||||||
yield* service.register({ echo: make() }, { codemode: false })
|
|
||||||
const first = yield* toolDefinitions(service)
|
|
||||||
const second = yield* toolDefinitions(service)
|
|
||||||
|
|
||||||
expect(second[0]).toBe(first[0])
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
it.effect("removes a scoped registration", () =>
|
it.effect("removes a scoped registration", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const service = yield* ToolRegistry.Service
|
const service = yield* ToolRegistry.Service
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"@opencode-ai/client": "workspace:*",
|
"@opencode-ai/client": "workspace:*",
|
||||||
"@opencode-ai/schema": "workspace:*",
|
"@opencode-ai/schema": "workspace:*",
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
|
"@standard-schema/spec": "^1.1.0",
|
||||||
"effect": "catalog:",
|
"effect": "catalog:",
|
||||||
"zod": "catalog:"
|
"zod": "catalog:"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { Agent } from "@opencode-ai/schema/agent"
|
|||||||
import type { LLM } from "@opencode-ai/schema/llm"
|
import type { LLM } from "@opencode-ai/schema/llm"
|
||||||
import { Session } from "@opencode-ai/schema/session"
|
import { Session } from "@opencode-ai/schema/session"
|
||||||
import { SessionMessage } from "@opencode-ai/schema/session-message"
|
import { SessionMessage } from "@opencode-ai/schema/session-message"
|
||||||
import { Effect, JsonSchema, Schema, type Scope } from "effect"
|
import type { StandardJSONSchemaV1, StandardSchemaV1 } from "@standard-schema/spec"
|
||||||
|
import { Effect, JsonSchema, Schema } from "effect"
|
||||||
import type { Hooks, Transform } from "./registration.js"
|
import type { Hooks, Transform } from "./registration.js"
|
||||||
|
|
||||||
export interface Context {
|
export interface Context {
|
||||||
@@ -20,7 +21,34 @@ export interface Progress {
|
|||||||
readonly content?: ReadonlyArray<Content>
|
readonly content?: ReadonlyArray<Content>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SchemaType<A> = Schema.Codec<A, any>
|
export type StandardSchemaType<Input = unknown, Output = Input> = StandardSchemaV1<Input, Output> &
|
||||||
|
StandardJSONSchemaV1<Input, Output>
|
||||||
|
export type SchemaType<A> = Schema.Codec<A, any> | StandardSchemaType<any, A>
|
||||||
|
type IsAny<A> = 0 extends 1 & A ? true : false
|
||||||
|
export type InputValue<S> =
|
||||||
|
IsAny<S> extends true
|
||||||
|
? any
|
||||||
|
: S extends Schema.Codec<infer A, any>
|
||||||
|
? A
|
||||||
|
: S extends StandardSchemaV1<any, infer A>
|
||||||
|
? A
|
||||||
|
: never
|
||||||
|
export type OutputValue<S> =
|
||||||
|
IsAny<S> extends true
|
||||||
|
? any
|
||||||
|
: S extends Schema.Codec<infer A, any>
|
||||||
|
? A
|
||||||
|
: S extends StandardSchemaV1<infer A, any>
|
||||||
|
? A
|
||||||
|
: never
|
||||||
|
export type EncodedValue<S> =
|
||||||
|
IsAny<S> extends true
|
||||||
|
? any
|
||||||
|
: S extends Schema.Codec<any, infer A>
|
||||||
|
? A
|
||||||
|
: S extends StandardSchemaV1<any, infer A>
|
||||||
|
? A
|
||||||
|
: never
|
||||||
|
|
||||||
type ToolDefinition = {
|
type ToolDefinition = {
|
||||||
readonly name: string
|
readonly name: string
|
||||||
@@ -45,16 +73,6 @@ type ToolOutput = {
|
|||||||
readonly content: ReadonlyArray<LLM.ToolContent>
|
readonly content: ReadonlyArray<LLM.ToolContent>
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const TypeId: unique symbol
|
|
||||||
|
|
||||||
export interface Definition<Input extends SchemaType<any>, Output extends SchemaType<any>> {
|
|
||||||
readonly [TypeId]: {
|
|
||||||
readonly _Input: Input
|
|
||||||
readonly _Output: Output
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AnyTool = Definition<any, any>
|
|
||||||
export class Failure extends Schema.TaggedErrorClass<Failure>()("LLM.ToolFailure", {
|
export class Failure extends Schema.TaggedErrorClass<Failure>()("LLM.ToolFailure", {
|
||||||
message: Schema.String,
|
message: Schema.String,
|
||||||
error: Schema.optional(Schema.Defect()),
|
error: Schema.optional(Schema.Defect()),
|
||||||
@@ -70,26 +88,24 @@ export type Content =
|
|||||||
| { readonly type: "text"; readonly text: string }
|
| { readonly type: "text"; readonly text: string }
|
||||||
| { readonly type: "file"; readonly data: string; readonly mime: string; readonly name?: string }
|
| { readonly type: "file"; readonly data: string; readonly mime: string; readonly name?: string }
|
||||||
|
|
||||||
type Config<
|
export type Definition<
|
||||||
Input extends SchemaType<any>,
|
Input extends SchemaType<any>,
|
||||||
Output extends SchemaType<any>,
|
Structured extends SchemaType<any>,
|
||||||
Structured extends SchemaType<any> = Output,
|
Output extends SchemaType<any> = any,
|
||||||
> = {
|
> = {
|
||||||
readonly description: string
|
readonly description: string
|
||||||
readonly input: Input
|
readonly input: Input
|
||||||
readonly output: Output
|
readonly output: Output
|
||||||
readonly structured?: Structured
|
readonly structured?: Structured
|
||||||
|
readonly permission?: string
|
||||||
readonly toStructuredOutput?: (input: {
|
readonly toStructuredOutput?: (input: {
|
||||||
readonly input: Schema.Schema.Type<Input>
|
readonly input: InputValue<Input>
|
||||||
readonly output: Output["Encoded"]
|
readonly output: EncodedValue<Output>
|
||||||
}) => Schema.Schema.Type<Structured>
|
}) => OutputValue<Structured>
|
||||||
readonly execute: (
|
readonly execute: (input: InputValue<Input>, context: Context) => Effect.Effect<OutputValue<Output>, Failure>
|
||||||
input: Schema.Schema.Type<Input>,
|
|
||||||
context: Context,
|
|
||||||
) => Effect.Effect<Schema.Schema.Type<Output>, Failure>
|
|
||||||
readonly toModelOutput?: (input: {
|
readonly toModelOutput?: (input: {
|
||||||
readonly input: Schema.Schema.Type<Input>
|
readonly input: InputValue<Input>
|
||||||
readonly output: Output["Encoded"]
|
readonly output: EncodedValue<Output>
|
||||||
}) => ReadonlyArray<Content>
|
}) => ReadonlyArray<Content>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,109 +119,25 @@ export type DynamicOutput = {
|
|||||||
* time (MCP servers, plugin manifests). Input is passed through as `unknown`;
|
* time (MCP servers, plugin manifests). Input is passed through as `unknown`;
|
||||||
* `execute` returns the already-projected structured value and model content.
|
* `execute` returns the already-projected structured value and model content.
|
||||||
*/
|
*/
|
||||||
type DynamicConfig = {
|
export type DynamicDefinition = {
|
||||||
readonly description: string
|
readonly description: string
|
||||||
readonly jsonSchema: JsonSchema.JsonSchema
|
readonly jsonSchema: JsonSchema.JsonSchema
|
||||||
readonly outputSchema?: JsonSchema.JsonSchema
|
readonly outputSchema?: JsonSchema.JsonSchema
|
||||||
|
readonly permission?: string
|
||||||
readonly execute: (input: unknown, context: Context) => Effect.Effect<DynamicOutput, Failure>
|
readonly execute: (input: unknown, context: Context) => Effect.Effect<DynamicOutput, Failure>
|
||||||
}
|
}
|
||||||
|
|
||||||
type Runtime = {
|
export type AnyTool = Definition<any, any> | DynamicDefinition
|
||||||
readonly permission?: string
|
|
||||||
readonly definition: (name: string) => ToolDefinition
|
|
||||||
readonly settle: (call: ToolCall, context: Context) => Effect.Effect<ToolOutput, Failure>
|
|
||||||
}
|
|
||||||
|
|
||||||
const runtimes = new WeakMap<AnyTool, Runtime>()
|
|
||||||
|
|
||||||
export function make<
|
export function make<
|
||||||
Input extends SchemaType<any>,
|
Input extends SchemaType<any>,
|
||||||
Output extends SchemaType<any>,
|
Output extends SchemaType<any>,
|
||||||
Structured extends SchemaType<any> = Output,
|
Structured extends SchemaType<any> = Output,
|
||||||
>(config: Config<Input, Output, Structured>): Definition<Input, Structured>
|
>(config: Definition<Input, Structured, Output>): Definition<Input, Structured, Output>
|
||||||
export function make(config: DynamicConfig): AnyTool
|
export function make(config: DynamicDefinition): DynamicDefinition
|
||||||
export function make(config: Config<any, any, any> | DynamicConfig): AnyTool {
|
export function make(config: AnyTool): AnyTool
|
||||||
if ("jsonSchema" in config) return makeDynamic(config)
|
export function make(config: AnyTool): AnyTool {
|
||||||
return makeTyped(config)
|
return config
|
||||||
}
|
|
||||||
|
|
||||||
function makeTyped<
|
|
||||||
Input extends SchemaType<any>,
|
|
||||||
Output extends SchemaType<any>,
|
|
||||||
Structured extends SchemaType<any> = Output,
|
|
||||||
>(config: Config<Input, Output, Structured>): Definition<Input, Structured> {
|
|
||||||
const tool = Object.freeze({}) as Definition<Input, Structured>
|
|
||||||
const definitions = new Map<string, ToolDefinition>()
|
|
||||||
runtimes.set(tool, {
|
|
||||||
definition: (name) => {
|
|
||||||
const cached = definitions.get(name)
|
|
||||||
if (cached) return cached
|
|
||||||
const definition: ToolDefinition = {
|
|
||||||
name,
|
|
||||||
description: config.description,
|
|
||||||
inputSchema: toJsonSchema(config.input),
|
|
||||||
outputSchema: toJsonSchema(config.structured ?? config.output),
|
|
||||||
}
|
|
||||||
definitions.set(name, definition)
|
|
||||||
return definition
|
|
||||||
},
|
|
||||||
settle: (call, context) =>
|
|
||||||
Schema.decodeUnknownEffect(config.input)(call.input).pipe(
|
|
||||||
Effect.mapError((error) => new Failure({ message: `Invalid tool input: ${error.message}` })),
|
|
||||||
Effect.flatMap((input) =>
|
|
||||||
config.execute(input, context).pipe(
|
|
||||||
Effect.flatMap((output) =>
|
|
||||||
Schema.encodeEffect(config.output)(output).pipe(
|
|
||||||
Effect.flatMap((output) => {
|
|
||||||
if (!config.structured || !config.toStructuredOutput)
|
|
||||||
return Effect.succeed({ output, structured: output })
|
|
||||||
return Schema.encodeEffect(config.structured)(config.toStructuredOutput({ input, output })).pipe(
|
|
||||||
Effect.map((structured) => ({ output, structured })),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
Effect.mapError(
|
|
||||||
(error) =>
|
|
||||||
new Failure({
|
|
||||||
message: `Tool returned an invalid value for its output schema: ${error.message}`,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Effect.map(({ output, structured }) => ({
|
|
||||||
structured,
|
|
||||||
content:
|
|
||||||
config.toModelOutput?.({ input, output }).map(toModelContent) ??
|
|
||||||
(typeof output === "string" ? [{ type: "text" as const, text: output }] : []),
|
|
||||||
})),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
})
|
|
||||||
return tool
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeDynamic(config: DynamicConfig): AnyTool {
|
|
||||||
const tool = Object.freeze({}) as AnyTool
|
|
||||||
const definitions = new Map<string, ToolDefinition>()
|
|
||||||
runtimes.set(tool, {
|
|
||||||
definition: (name) => {
|
|
||||||
const cached = definitions.get(name)
|
|
||||||
if (cached) return cached
|
|
||||||
const definition: ToolDefinition = {
|
|
||||||
name,
|
|
||||||
description: config.description,
|
|
||||||
inputSchema: config.jsonSchema,
|
|
||||||
outputSchema: config.outputSchema,
|
|
||||||
}
|
|
||||||
definitions.set(name, definition)
|
|
||||||
return definition
|
|
||||||
},
|
|
||||||
settle: (call, context) =>
|
|
||||||
config
|
|
||||||
.execute(call.input, context)
|
|
||||||
.pipe(Effect.map((output) => ({ structured: output.structured, content: output.content.map(toModelContent) }))),
|
|
||||||
})
|
|
||||||
return tool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toModelContent(part: Content) {
|
function toModelContent(part: Content) {
|
||||||
@@ -230,23 +162,102 @@ export const registrationEntries = (tools: Readonly<Record<string, AnyTool>>, gr
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const withPermission = <Input extends SchemaType<any>, Output extends SchemaType<any>>(
|
export const withPermission = <T extends AnyTool>(
|
||||||
tool: Definition<Input, Output>,
|
tool: T,
|
||||||
permission: string,
|
permission: string,
|
||||||
) => {
|
): Omit<T, "permission"> & {
|
||||||
const decorated = Object.freeze({}) as Definition<Input, Output>
|
readonly permission: string
|
||||||
runtimes.set(decorated, { ...runtimeOf(tool), permission })
|
} => ({ ...tool, permission })
|
||||||
return decorated
|
|
||||||
|
export const permission = (tool: AnyTool, name: string) => tool.permission ?? name
|
||||||
|
|
||||||
|
export const definition = (name: string, tool: AnyTool): ToolDefinition =>
|
||||||
|
"jsonSchema" in tool
|
||||||
|
? {
|
||||||
|
name,
|
||||||
|
description: tool.description,
|
||||||
|
inputSchema: tool.jsonSchema,
|
||||||
|
outputSchema: tool.outputSchema,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
name,
|
||||||
|
description: tool.description,
|
||||||
|
inputSchema: inputJsonSchema(tool.input),
|
||||||
|
outputSchema: outputJsonSchema(tool.structured ?? tool.output),
|
||||||
|
}
|
||||||
|
|
||||||
|
export const settle = (tool: AnyTool, call: ToolCall, context: Context): Effect.Effect<ToolOutput, Failure> =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
if ("jsonSchema" in tool) {
|
||||||
|
const output = yield* tool.execute(call.input, context)
|
||||||
|
return { structured: output.structured, content: output.content.map(toModelContent) }
|
||||||
|
}
|
||||||
|
|
||||||
|
const input = yield* decodeInput(tool.input, call.input)
|
||||||
|
const value = yield* tool.execute(input, context)
|
||||||
|
const output = yield* encodeOutput(tool.output, value)
|
||||||
|
const structured =
|
||||||
|
tool.structured && tool.toStructuredOutput
|
||||||
|
? yield* encodeOutput(tool.structured, tool.toStructuredOutput({ input, output }))
|
||||||
|
: output
|
||||||
|
return {
|
||||||
|
structured,
|
||||||
|
content:
|
||||||
|
tool.toModelOutput?.({ input, output }).map(toModelContent) ??
|
||||||
|
(typeof output === "string" ? [{ type: "text" as const, text: output }] : []),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function decodeInput(schema: SchemaType<any>, value: unknown): Effect.Effect<any, Failure> {
|
||||||
|
if (Schema.isSchema(schema))
|
||||||
|
return Schema.decodeUnknownEffect(schema)(value).pipe(
|
||||||
|
Effect.mapError((error) => new Failure({ message: `Invalid tool input: ${error.message}` })),
|
||||||
|
)
|
||||||
|
return validateStandard(schema, value, "Invalid tool input")
|
||||||
}
|
}
|
||||||
|
|
||||||
export const permission = (tool: AnyTool, name: string) => runtimeOf(tool).permission ?? name
|
function encodeOutput(schema: SchemaType<any>, value: unknown): Effect.Effect<any, Failure> {
|
||||||
export const definition = (name: string, tool: AnyTool) => runtimeOf(tool).definition(name)
|
if (Schema.isSchema(schema))
|
||||||
export const settle = (tool: AnyTool, call: ToolCall, context: Context) => runtimeOf(tool).settle(call, context)
|
return Schema.encodeEffect(schema)(value).pipe(
|
||||||
|
Effect.mapError(
|
||||||
|
(error) => new Failure({ message: `Tool returned an invalid value for its output schema: ${error.message}` }),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return validateStandard(schema, value, "Tool returned an invalid value for its output schema")
|
||||||
|
}
|
||||||
|
|
||||||
function runtimeOf(tool: AnyTool) {
|
function validateStandard(schema: StandardSchemaType, value: unknown, prefix: string): Effect.Effect<unknown, Failure> {
|
||||||
const runtime = runtimes.get(tool)
|
return Effect.gen(function* () {
|
||||||
if (!runtime) throw new TypeError("Invalid Tool value")
|
const pending = yield* Effect.try({
|
||||||
return runtime
|
try: () => schema["~standard"].validate(value),
|
||||||
|
catch: (error) => standardFailure(prefix, error),
|
||||||
|
})
|
||||||
|
const result =
|
||||||
|
pending instanceof Promise
|
||||||
|
? yield* Effect.tryPromise({ try: () => pending, catch: (error) => standardFailure(prefix, error) })
|
||||||
|
: pending
|
||||||
|
if (result.issues)
|
||||||
|
return yield* Effect.fail(
|
||||||
|
new Failure({ message: `${prefix}: ${result.issues.map((issue) => issue.message).join(", ")}` }),
|
||||||
|
)
|
||||||
|
return result.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function standardFailure(prefix: string, error: unknown) {
|
||||||
|
return new Failure({ message: `${prefix}: ${error instanceof Error ? error.message : String(error)}` })
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputJsonSchema(schema: SchemaType<any>): JsonSchema.JsonSchema {
|
||||||
|
if (!Schema.isSchema(schema))
|
||||||
|
return schema["~standard"].jsonSchema.input({ target: "draft-2020-12" }) as JsonSchema.JsonSchema
|
||||||
|
return toJsonSchema(schema)
|
||||||
|
}
|
||||||
|
|
||||||
|
function outputJsonSchema(schema: SchemaType<any>): JsonSchema.JsonSchema {
|
||||||
|
if (!Schema.isSchema(schema))
|
||||||
|
return schema["~standard"].jsonSchema.output({ target: "draft-2020-12" }) as JsonSchema.JsonSchema
|
||||||
|
return toJsonSchema(schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
function toJsonSchema(schema: Schema.Top): JsonSchema.JsonSchema {
|
function toJsonSchema(schema: Schema.Top): JsonSchema.JsonSchema {
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
import type { Tool } from "../effect/tool.js"
|
import type { Tool } from "../effect/tool.js"
|
||||||
import type { Agent } from "@opencode-ai/schema/agent"
|
|
||||||
import type { Session } from "@opencode-ai/schema/session"
|
|
||||||
import type { SessionMessage } from "@opencode-ai/schema/session-message"
|
|
||||||
import type { JsonSchema, Schema } from "effect"
|
|
||||||
import type { Hooks, Transform } from "./registration.js"
|
import type { Hooks, Transform } from "./registration.js"
|
||||||
|
|
||||||
export type Context = Omit<Tool.Context, "progress"> & {
|
export type Context = Omit<Tool.Context, "progress"> & {
|
||||||
@@ -16,71 +12,28 @@ export type Definition<
|
|||||||
Input extends SchemaType<any>,
|
Input extends SchemaType<any>,
|
||||||
Output extends SchemaType<any>,
|
Output extends SchemaType<any>,
|
||||||
Structured extends SchemaType<any> = Output,
|
Structured extends SchemaType<any> = Output,
|
||||||
> = {
|
> = Omit<Tool.Definition<Input, Structured, Output>, "execute" | "permission"> & {
|
||||||
readonly name: string
|
readonly name: string
|
||||||
readonly options?: RegisterOptions
|
readonly options?: RegisterOptions
|
||||||
readonly description: string
|
readonly execute: (input: Tool.InputValue<Input>, context: Context) => Promise<Tool.OutputValue<Output>>
|
||||||
readonly input: Input
|
|
||||||
readonly output: Output
|
|
||||||
readonly structured?: Structured
|
|
||||||
readonly toStructuredOutput?: (input: {
|
|
||||||
readonly input: Schema.Schema.Type<Input>
|
|
||||||
readonly output: Output["Encoded"]
|
|
||||||
}) => Schema.Schema.Type<Structured>
|
|
||||||
readonly execute: (
|
|
||||||
input: Schema.Schema.Type<Input>,
|
|
||||||
context: Context,
|
|
||||||
) => Promise<Schema.Schema.Type<Output>>
|
|
||||||
readonly toModelOutput?: (input: {
|
|
||||||
readonly input: Schema.Schema.Type<Input>
|
|
||||||
readonly output: Output["Encoded"]
|
|
||||||
}) => ReadonlyArray<Content>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DynamicDefinition = {
|
export type DynamicDefinition = Omit<Tool.DynamicDefinition, "execute" | "permission"> & {
|
||||||
readonly name: string
|
readonly name: string
|
||||||
readonly options?: RegisterOptions
|
readonly options?: RegisterOptions
|
||||||
readonly description: string
|
|
||||||
readonly jsonSchema: JsonSchema.JsonSchema
|
|
||||||
readonly outputSchema?: JsonSchema.JsonSchema
|
|
||||||
readonly execute: (input: unknown, context: Context) => Promise<DynamicOutput>
|
readonly execute: (input: unknown, context: Context) => Promise<DynamicOutput>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AnyTool = Definition<any, any, any> | DynamicDefinition
|
export type AnyTool = Definition<any, any, any> | DynamicDefinition
|
||||||
|
|
||||||
export interface ToolExecuteBeforeEvent {
|
export type ToolExecuteBeforeEvent = Tool.ToolExecuteBeforeEvent
|
||||||
readonly tool: string
|
export type ToolExecuteAfterEvent = Tool.ToolExecuteAfterEvent
|
||||||
readonly sessionID: Session.ID
|
export type RegisterOptions = Tool.RegisterOptions
|
||||||
readonly agent: Agent.ID
|
|
||||||
readonly messageID: SessionMessage.ID
|
|
||||||
readonly callID: string
|
|
||||||
input: unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ToolExecuteAfterEvent {
|
|
||||||
readonly tool: string
|
|
||||||
readonly sessionID: Session.ID
|
|
||||||
readonly agent: Agent.ID
|
|
||||||
readonly messageID: SessionMessage.ID
|
|
||||||
readonly callID: string
|
|
||||||
readonly input: unknown
|
|
||||||
result: Tool.ToolExecuteAfterEvent["result"]
|
|
||||||
output?: Tool.ToolExecuteAfterEvent["output"]
|
|
||||||
outputPaths?: ReadonlyArray<string>
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RegisterOptions {
|
|
||||||
readonly group?: string
|
|
||||||
/** Defaults to true. False exposes the tool directly to the provider. */
|
|
||||||
readonly codemode?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ToolDraft {
|
export interface ToolDraft {
|
||||||
add<
|
add<Input extends SchemaType<any>, Output extends SchemaType<any>, Structured extends SchemaType<any> = Output>(
|
||||||
Input extends SchemaType<any>,
|
tool: Definition<Input, Output, Structured>,
|
||||||
Output extends SchemaType<any>,
|
): void
|
||||||
Structured extends SchemaType<any> = Output,
|
|
||||||
>(tool: Definition<Input, Output, Structured>): void
|
|
||||||
add(tool: DynamicDefinition): void
|
add(tool: DynamicDefinition): void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
import { expect, test } from "bun:test"
|
||||||
|
import { Agent } from "@opencode-ai/schema/agent"
|
||||||
|
import { Session } from "@opencode-ai/schema/session"
|
||||||
|
import { SessionMessage } from "@opencode-ai/schema/session-message"
|
||||||
|
import { Effect, Schema } from "effect"
|
||||||
|
import * as Tool from "../src/v2/effect/tool"
|
||||||
|
|
||||||
|
const context = {
|
||||||
|
sessionID: Session.ID.make("ses_test"),
|
||||||
|
agent: Agent.ID.make("build"),
|
||||||
|
messageID: SessionMessage.ID.make("msg_test"),
|
||||||
|
callID: "call_test",
|
||||||
|
progress: () => Effect.void,
|
||||||
|
} satisfies Tool.Context
|
||||||
|
|
||||||
|
test("tools remain valid across separate module instances", async () => {
|
||||||
|
const ForeignTool = await import(`${new URL("../src/v2/effect/tool.ts", import.meta.url).href}?foreign`)
|
||||||
|
const config = {
|
||||||
|
description: "Foreign tool",
|
||||||
|
input: Schema.Struct({ value: Schema.String }),
|
||||||
|
output: Schema.Struct({ ok: Schema.Boolean }),
|
||||||
|
execute: () => Effect.succeed({ ok: true }),
|
||||||
|
}
|
||||||
|
const tool = ForeignTool.make(config)
|
||||||
|
|
||||||
|
expect(Tool.definition("foreign", tool)).toEqual({
|
||||||
|
name: "foreign",
|
||||||
|
description: "Foreign tool",
|
||||||
|
inputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: { value: { type: "string" } },
|
||||||
|
required: ["value"],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
outputSchema: {
|
||||||
|
type: "object",
|
||||||
|
properties: { ok: { type: "boolean" } },
|
||||||
|
required: ["ok"],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(await Effect.runPromise(Tool.settle(tool, { input: { value: "input" } }, context))).toEqual({
|
||||||
|
structured: { ok: true },
|
||||||
|
content: [],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test("portable schemas validate and describe typed tools", async () => {
|
||||||
|
const input: Tool.StandardSchemaType<{ count: string }, { count: number }> = {
|
||||||
|
"~standard": {
|
||||||
|
version: 1,
|
||||||
|
vendor: "test",
|
||||||
|
validate: (value) => {
|
||||||
|
if (typeof value !== "object" || value === null || !("count" in value) || typeof value.count !== "string")
|
||||||
|
return { issues: [{ message: "count must be numeric" }] }
|
||||||
|
const count = Number(value.count)
|
||||||
|
return Number.isFinite(count) ? { value: { count } } : { issues: [{ message: "count must be numeric" }] }
|
||||||
|
},
|
||||||
|
jsonSchema: {
|
||||||
|
input: () => ({ type: "object", properties: { count: { type: "string" } } }),
|
||||||
|
output: () => ({ type: "object", properties: { count: { type: "number" } } }),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const output: Tool.StandardSchemaType<number, string> = {
|
||||||
|
"~standard": {
|
||||||
|
version: 1,
|
||||||
|
vendor: "test",
|
||||||
|
validate: (value) => ({ value: String(value) }),
|
||||||
|
jsonSchema: {
|
||||||
|
input: () => ({ type: "number" }),
|
||||||
|
output: () => ({ type: "string" }),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const tool = Tool.make({
|
||||||
|
description: "Portable tool",
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
execute: ({ count }) => Effect.succeed(count + 1),
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(Tool.definition("portable", tool)).toEqual({
|
||||||
|
name: "portable",
|
||||||
|
description: "Portable tool",
|
||||||
|
inputSchema: { type: "object", properties: { count: { type: "string" } } },
|
||||||
|
outputSchema: { type: "string" },
|
||||||
|
})
|
||||||
|
expect(await Effect.runPromise(Tool.settle(tool, { input: { count: "41" } }, context))).toEqual({
|
||||||
|
structured: "42",
|
||||||
|
content: [{ type: "text", text: "42" }],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test("portable schema failures become tool failures", async () => {
|
||||||
|
const input: Tool.StandardSchemaType<string> = {
|
||||||
|
"~standard": {
|
||||||
|
version: 1,
|
||||||
|
vendor: "test",
|
||||||
|
validate: () => ({ issues: [{ message: "expected a string" }] }),
|
||||||
|
jsonSchema: {
|
||||||
|
input: () => ({ type: "string" }),
|
||||||
|
output: () => ({ type: "string" }),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const tool = Tool.make({
|
||||||
|
description: "Failing tool",
|
||||||
|
input,
|
||||||
|
output: input,
|
||||||
|
execute: Effect.succeed,
|
||||||
|
})
|
||||||
|
|
||||||
|
const error = await Effect.runPromiseExit(Tool.settle(tool, { input: 1 }, context))
|
||||||
|
expect(error.toString()).toContain("Invalid tool input: expected a string")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("two-parameter Definition annotations retain their original meaning", () => {
|
||||||
|
const input = Schema.Struct({ value: Schema.String })
|
||||||
|
const output = Schema.Struct({ value: Schema.String, internal: Schema.Boolean })
|
||||||
|
const structured = Schema.Struct({ value: Schema.String })
|
||||||
|
const tool: Tool.Definition<typeof input, typeof structured> = Tool.make({
|
||||||
|
description: "Annotated tool",
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
structured,
|
||||||
|
toStructuredOutput: ({ output }) => ({ value: output.value }),
|
||||||
|
execute: ({ value }) => Effect.succeed({ value, internal: true }),
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(tool.structured).toBe(structured)
|
||||||
|
})
|
||||||
+6
-4
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
Status: **Current semantic overview.** The Plugin package owns the public tool type; Core owns registration, settlement, and generic output bounding.
|
Status: **Current semantic overview.** The Plugin package owns the public tool type; Core owns registration, settlement, and generic output bounding.
|
||||||
|
|
||||||
## Tool Definitions Are Opaque
|
## Tool Declarations
|
||||||
|
|
||||||
V2 has one opaque type for locally executable tools. Typed tools declare codecs, execution, and optional model-facing projection together:
|
V2 has one structural declaration for locally executable tools. Typed tools declare schemas, execution, and optional model-facing projection together:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const read = Tool.make({
|
const read = Tool.make({
|
||||||
@@ -16,11 +16,13 @@ const read = Tool.make({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
`structured` and `toStructuredOutput` may expose a smaller validated result than the complete execution output. Dynamic MCP and manifest tools use the same opaque representation with runtime JSON Schema.
|
`structured` and `toStructuredOutput` may expose a smaller validated result than the complete execution output. Dynamic MCP and manifest tools use the same declaration with runtime JSON Schema.
|
||||||
|
|
||||||
Built-ins and statically authored plugin tools use this same constructor and execution contract.
|
Built-ins and statically authored plugin tools use this same constructor and execution contract.
|
||||||
|
|
||||||
`Tool.Definition` is opaque and has exactly one executor. Its schemas and executor are not public fields. The Tool module privately derives model definitions and interprets invocations for the registry; callers normally rely on `Tool.make` inference rather than naming the carrier type.
|
`Tool.Definition` is a transparent structural value with exactly one executor. Effect schemas and schemas implementing both Standard Schema V1 and Standard JSON Schema V1 are accepted. The Tool module derives model definitions and interprets invocations for the registry; callers normally rely on `Tool.make` inference rather than naming the declaration type.
|
||||||
|
|
||||||
|
Standard input schemas validate model input into the handler value. Standard output schemas validate the handler result into the model-facing value. Effect codecs retain their native decode-input and encode-output directions.
|
||||||
|
|
||||||
Input and output codecs are self-contained. Schema conversion cannot require services. Tool dependencies are acquired during construction and captured by `execute`.
|
Input and output codecs are self-contained. Schema conversion cannot require services. Tool dependencies are acquired during construction and captured by `execute`.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user