@vurb/core 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +677 -0
- package/dist/cli/args.d.ts +26 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +117 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/commands/create.d.ts +11 -0
- package/dist/cli/commands/create.d.ts.map +1 -0
- package/dist/cli/commands/create.js +121 -0
- package/dist/cli/commands/create.js.map +1 -0
- package/dist/cli/commands/deploy.d.ts +3 -0
- package/dist/cli/commands/deploy.d.ts.map +1 -0
- package/dist/cli/commands/deploy.js +268 -0
- package/dist/cli/commands/deploy.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +9 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +58 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/lock.d.ts +5 -0
- package/dist/cli/commands/lock.d.ts.map +1 -0
- package/dist/cli/commands/lock.js +94 -0
- package/dist/cli/commands/lock.js.map +1 -0
- package/dist/cli/commands/remote.d.ts +3 -0
- package/dist/cli/commands/remote.d.ts.map +1 -0
- package/dist/cli/commands/remote.js +37 -0
- package/dist/cli/commands/remote.js.map +1 -0
- package/dist/cli/constants.d.ts +18 -0
- package/dist/cli/constants.d.ts.map +1 -0
- package/dist/cli/constants.js +95 -0
- package/dist/cli/constants.js.map +1 -0
- package/dist/cli/progress.d.ts +34 -0
- package/dist/cli/progress.d.ts.map +1 -0
- package/dist/cli/progress.js +102 -0
- package/dist/cli/progress.js.map +1 -0
- package/dist/cli/rc.d.ts +11 -0
- package/dist/cli/rc.d.ts.map +1 -0
- package/dist/cli/rc.js +75 -0
- package/dist/cli/rc.js.map +1 -0
- package/dist/cli/registry.d.ts +25 -0
- package/dist/cli/registry.d.ts.map +1 -0
- package/dist/cli/registry.js +86 -0
- package/dist/cli/registry.js.map +1 -0
- package/dist/cli/scaffold.d.ts +10 -0
- package/dist/cli/scaffold.d.ts.map +1 -0
- package/dist/cli/scaffold.js +105 -0
- package/dist/cli/scaffold.js.map +1 -0
- package/dist/cli/templates/config.d.ts +14 -0
- package/dist/cli/templates/config.d.ts.map +1 -0
- package/dist/cli/templates/config.js +133 -0
- package/dist/cli/templates/config.js.map +1 -0
- package/dist/cli/templates/constants.d.ts +9 -0
- package/dist/cli/templates/constants.d.ts.map +1 -0
- package/dist/cli/templates/constants.js +9 -0
- package/dist/cli/templates/constants.js.map +1 -0
- package/dist/cli/templates/core.d.ts +14 -0
- package/dist/cli/templates/core.d.ts.map +1 -0
- package/dist/cli/templates/core.js +186 -0
- package/dist/cli/templates/core.js.map +1 -0
- package/dist/cli/templates/cursor.d.ts +8 -0
- package/dist/cli/templates/cursor.d.ts.map +1 -0
- package/dist/cli/templates/cursor.js +13 -0
- package/dist/cli/templates/cursor.js.map +1 -0
- package/dist/cli/templates/index.d.ts +17 -0
- package/dist/cli/templates/index.d.ts.map +1 -0
- package/dist/cli/templates/index.js +27 -0
- package/dist/cli/templates/index.js.map +1 -0
- package/dist/cli/templates/middleware.d.ts +7 -0
- package/dist/cli/templates/middleware.d.ts.map +1 -0
- package/dist/cli/templates/middleware.js +34 -0
- package/dist/cli/templates/middleware.js.map +1 -0
- package/dist/cli/templates/presenter.d.ts +7 -0
- package/dist/cli/templates/presenter.d.ts.map +1 -0
- package/dist/cli/templates/presenter.js +46 -0
- package/dist/cli/templates/presenter.js.map +1 -0
- package/dist/cli/templates/prompt.d.ts +7 -0
- package/dist/cli/templates/prompt.d.ts.map +1 -0
- package/dist/cli/templates/prompt.js +42 -0
- package/dist/cli/templates/prompt.js.map +1 -0
- package/dist/cli/templates/readme.d.ts +8 -0
- package/dist/cli/templates/readme.d.ts.map +1 -0
- package/dist/cli/templates/readme.js +173 -0
- package/dist/cli/templates/readme.js.map +1 -0
- package/dist/cli/templates/testing.d.ts +11 -0
- package/dist/cli/templates/testing.d.ts.map +1 -0
- package/dist/cli/templates/testing.js +101 -0
- package/dist/cli/templates/testing.js.map +1 -0
- package/dist/cli/templates/tools.d.ts +13 -0
- package/dist/cli/templates/tools.d.ts.map +1 -0
- package/dist/cli/templates/tools.js +63 -0
- package/dist/cli/templates/tools.js.map +1 -0
- package/dist/cli/templates/vectors/database.d.ts +9 -0
- package/dist/cli/templates/vectors/database.d.ts.map +1 -0
- package/dist/cli/templates/vectors/database.js +82 -0
- package/dist/cli/templates/vectors/database.js.map +1 -0
- package/dist/cli/templates/vectors/index.d.ts +9 -0
- package/dist/cli/templates/vectors/index.d.ts.map +1 -0
- package/dist/cli/templates/vectors/index.js +9 -0
- package/dist/cli/templates/vectors/index.js.map +1 -0
- package/dist/cli/templates/vectors/oauth.d.ts +10 -0
- package/dist/cli/templates/vectors/oauth.d.ts.map +1 -0
- package/dist/cli/templates/vectors/oauth.js +76 -0
- package/dist/cli/templates/vectors/oauth.js.map +1 -0
- package/dist/cli/templates/vectors/openapi.d.ts +10 -0
- package/dist/cli/templates/vectors/openapi.d.ts.map +1 -0
- package/dist/cli/templates/vectors/openapi.js +106 -0
- package/dist/cli/templates/vectors/openapi.js.map +1 -0
- package/dist/cli/templates/vectors/workflow.d.ts +7 -0
- package/dist/cli/templates/vectors/workflow.d.ts.map +1 -0
- package/dist/cli/templates/vectors/workflow.js +49 -0
- package/dist/cli/templates/vectors/workflow.js.map +1 -0
- package/dist/cli/types.d.ts +36 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +10 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/utils.d.ts +27 -0
- package/dist/cli/utils.d.ts.map +1 -0
- package/dist/cli/utils.js +73 -0
- package/dist/cli/utils.js.map +1 -0
- package/dist/cli/vurb.d.ts +15 -0
- package/dist/cli/vurb.d.ts.map +1 -0
- package/dist/cli/vurb.js +87 -0
- package/dist/cli/vurb.js.map +1 -0
- package/dist/client/InferRouter.d.ts +92 -0
- package/dist/client/InferRouter.d.ts.map +1 -0
- package/dist/client/InferRouter.js +31 -0
- package/dist/client/InferRouter.js.map +1 -0
- package/dist/client/VurbClient.d.ts +282 -0
- package/dist/client/VurbClient.d.ts.map +1 -0
- package/dist/client/VurbClient.js +287 -0
- package/dist/client/VurbClient.js.map +1 -0
- package/dist/client/createTypedRegistry.d.ts +25 -0
- package/dist/client/createTypedRegistry.d.ts.map +1 -0
- package/dist/client/createTypedRegistry.js +74 -0
- package/dist/client/createTypedRegistry.js.map +1 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +4 -0
- package/dist/client/index.js.map +1 -0
- package/dist/converters/ConverterBase.d.ts +68 -0
- package/dist/converters/ConverterBase.d.ts.map +1 -0
- package/dist/converters/ConverterBase.js +62 -0
- package/dist/converters/ConverterBase.js.map +1 -0
- package/dist/converters/GroupConverter.d.ts +33 -0
- package/dist/converters/GroupConverter.d.ts.map +1 -0
- package/dist/converters/GroupConverter.js +26 -0
- package/dist/converters/GroupConverter.js.map +1 -0
- package/dist/converters/PromptConverter.d.ts +33 -0
- package/dist/converters/PromptConverter.d.ts.map +1 -0
- package/dist/converters/PromptConverter.js +26 -0
- package/dist/converters/PromptConverter.js.map +1 -0
- package/dist/converters/ResourceConverter.d.ts +35 -0
- package/dist/converters/ResourceConverter.d.ts.map +1 -0
- package/dist/converters/ResourceConverter.js +28 -0
- package/dist/converters/ResourceConverter.js.map +1 -0
- package/dist/converters/ToolAnnotationsConverter.d.ts +33 -0
- package/dist/converters/ToolAnnotationsConverter.d.ts.map +1 -0
- package/dist/converters/ToolAnnotationsConverter.js +26 -0
- package/dist/converters/ToolAnnotationsConverter.js.map +1 -0
- package/dist/converters/ToolConverter.d.ts +35 -0
- package/dist/converters/ToolConverter.d.ts.map +1 -0
- package/dist/converters/ToolConverter.js +28 -0
- package/dist/converters/ToolConverter.js.map +1 -0
- package/dist/converters/index.d.ts +7 -0
- package/dist/converters/index.d.ts.map +1 -0
- package/dist/converters/index.js +7 -0
- package/dist/converters/index.js.map +1 -0
- package/dist/core/StandardSchema.d.ts +178 -0
- package/dist/core/StandardSchema.d.ts.map +1 -0
- package/dist/core/StandardSchema.js +174 -0
- package/dist/core/StandardSchema.js.map +1 -0
- package/dist/core/builder/ActionGroupBuilder.d.ts +208 -0
- package/dist/core/builder/ActionGroupBuilder.d.ts.map +1 -0
- package/dist/core/builder/ActionGroupBuilder.js +193 -0
- package/dist/core/builder/ActionGroupBuilder.js.map +1 -0
- package/dist/core/builder/ErrorBuilder.d.ts +59 -0
- package/dist/core/builder/ErrorBuilder.d.ts.map +1 -0
- package/dist/core/builder/ErrorBuilder.js +99 -0
- package/dist/core/builder/ErrorBuilder.js.map +1 -0
- package/dist/core/builder/FluentRouter.d.ts +96 -0
- package/dist/core/builder/FluentRouter.d.ts.map +1 -0
- package/dist/core/builder/FluentRouter.js +116 -0
- package/dist/core/builder/FluentRouter.js.map +1 -0
- package/dist/core/builder/FluentSchemaHelpers.d.ts +237 -0
- package/dist/core/builder/FluentSchemaHelpers.d.ts.map +1 -0
- package/dist/core/builder/FluentSchemaHelpers.js +227 -0
- package/dist/core/builder/FluentSchemaHelpers.js.map +1 -0
- package/dist/core/builder/FluentToolBuilder.d.ts +419 -0
- package/dist/core/builder/FluentToolBuilder.d.ts.map +1 -0
- package/dist/core/builder/FluentToolBuilder.js +643 -0
- package/dist/core/builder/FluentToolBuilder.js.map +1 -0
- package/dist/core/builder/GroupedToolBuilder.d.ts +832 -0
- package/dist/core/builder/GroupedToolBuilder.d.ts.map +1 -0
- package/dist/core/builder/GroupedToolBuilder.js +1306 -0
- package/dist/core/builder/GroupedToolBuilder.js.map +1 -0
- package/dist/core/builder/ParamDescriptors.d.ts +142 -0
- package/dist/core/builder/ParamDescriptors.d.ts.map +1 -0
- package/dist/core/builder/ParamDescriptors.js +164 -0
- package/dist/core/builder/ParamDescriptors.js.map +1 -0
- package/dist/core/builder/ToolDefinitionCompiler.d.ts +37 -0
- package/dist/core/builder/ToolDefinitionCompiler.d.ts.map +1 -0
- package/dist/core/builder/ToolDefinitionCompiler.js +72 -0
- package/dist/core/builder/ToolDefinitionCompiler.js.map +1 -0
- package/dist/core/builder/defineTool.d.ts +180 -0
- package/dist/core/builder/defineTool.d.ts.map +1 -0
- package/dist/core/builder/defineTool.js +164 -0
- package/dist/core/builder/defineTool.js.map +1 -0
- package/dist/core/builder/index.d.ts +13 -0
- package/dist/core/builder/index.d.ts.map +1 -0
- package/dist/core/builder/index.js +13 -0
- package/dist/core/builder/index.js.map +1 -0
- package/dist/core/createGroup.d.ts +140 -0
- package/dist/core/createGroup.d.ts.map +1 -0
- package/dist/core/createGroup.js +144 -0
- package/dist/core/createGroup.js.map +1 -0
- package/dist/core/execution/ConcurrencyGuard.d.ts +103 -0
- package/dist/core/execution/ConcurrencyGuard.d.ts.map +1 -0
- package/dist/core/execution/ConcurrencyGuard.js +147 -0
- package/dist/core/execution/ConcurrencyGuard.js.map +1 -0
- package/dist/core/execution/EgressGuard.d.ts +72 -0
- package/dist/core/execution/EgressGuard.d.ts.map +1 -0
- package/dist/core/execution/EgressGuard.js +163 -0
- package/dist/core/execution/EgressGuard.js.map +1 -0
- package/dist/core/execution/ExecutionPipeline.d.ts +67 -0
- package/dist/core/execution/ExecutionPipeline.d.ts.map +1 -0
- package/dist/core/execution/ExecutionPipeline.js +176 -0
- package/dist/core/execution/ExecutionPipeline.js.map +1 -0
- package/dist/core/execution/MiddlewareCompiler.d.ts +35 -0
- package/dist/core/execution/MiddlewareCompiler.d.ts.map +1 -0
- package/dist/core/execution/MiddlewareCompiler.js +111 -0
- package/dist/core/execution/MiddlewareCompiler.js.map +1 -0
- package/dist/core/execution/MutationSerializer.d.ts +78 -0
- package/dist/core/execution/MutationSerializer.d.ts.map +1 -0
- package/dist/core/execution/MutationSerializer.js +106 -0
- package/dist/core/execution/MutationSerializer.js.map +1 -0
- package/dist/core/execution/PipelineHooks.d.ts +46 -0
- package/dist/core/execution/PipelineHooks.d.ts.map +1 -0
- package/dist/core/execution/PipelineHooks.js +66 -0
- package/dist/core/execution/PipelineHooks.js.map +1 -0
- package/dist/core/execution/ProgressHelper.d.ts +67 -0
- package/dist/core/execution/ProgressHelper.d.ts.map +1 -0
- package/dist/core/execution/ProgressHelper.js +59 -0
- package/dist/core/execution/ProgressHelper.js.map +1 -0
- package/dist/core/execution/ValidationErrorFormatter.d.ts +34 -0
- package/dist/core/execution/ValidationErrorFormatter.d.ts.map +1 -0
- package/dist/core/execution/ValidationErrorFormatter.js +193 -0
- package/dist/core/execution/ValidationErrorFormatter.js.map +1 -0
- package/dist/core/execution/index.d.ts +9 -0
- package/dist/core/execution/index.d.ts.map +1 -0
- package/dist/core/execution/index.js +9 -0
- package/dist/core/execution/index.js.map +1 -0
- package/dist/core/index.d.ts +34 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +29 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/initVurb.d.ts +295 -0
- package/dist/core/initVurb.d.ts.map +1 -0
- package/dist/core/initVurb.js +171 -0
- package/dist/core/initVurb.js.map +1 -0
- package/dist/core/middleware/ContextDerivation.d.ts +124 -0
- package/dist/core/middleware/ContextDerivation.d.ts.map +1 -0
- package/dist/core/middleware/ContextDerivation.js +117 -0
- package/dist/core/middleware/ContextDerivation.js.map +1 -0
- package/dist/core/middleware/index.d.ts +4 -0
- package/dist/core/middleware/index.d.ts.map +1 -0
- package/dist/core/middleware/index.js +3 -0
- package/dist/core/middleware/index.js.map +1 -0
- package/dist/core/registry/ToolFilterEngine.d.ts +27 -0
- package/dist/core/registry/ToolFilterEngine.d.ts.map +1 -0
- package/dist/core/registry/ToolFilterEngine.js +45 -0
- package/dist/core/registry/ToolFilterEngine.js.map +1 -0
- package/dist/core/registry/ToolRegistry.d.ts +259 -0
- package/dist/core/registry/ToolRegistry.d.ts.map +1 -0
- package/dist/core/registry/ToolRegistry.js +343 -0
- package/dist/core/registry/ToolRegistry.js.map +1 -0
- package/dist/core/registry/index.d.ts +4 -0
- package/dist/core/registry/index.d.ts.map +1 -0
- package/dist/core/registry/index.js +3 -0
- package/dist/core/registry/index.js.map +1 -0
- package/dist/core/response.d.ts +289 -0
- package/dist/core/response.d.ts.map +1 -0
- package/dist/core/response.js +286 -0
- package/dist/core/response.js.map +1 -0
- package/dist/core/result.d.ts +93 -0
- package/dist/core/result.d.ts.map +1 -0
- package/dist/core/result.js +66 -0
- package/dist/core/result.js.map +1 -0
- package/dist/core/schema/AnnotationAggregator.d.ts +11 -0
- package/dist/core/schema/AnnotationAggregator.d.ts.map +1 -0
- package/dist/core/schema/AnnotationAggregator.js +40 -0
- package/dist/core/schema/AnnotationAggregator.js.map +1 -0
- package/dist/core/schema/DescriptionGenerator.d.ts +12 -0
- package/dist/core/schema/DescriptionGenerator.d.ts.map +1 -0
- package/dist/core/schema/DescriptionGenerator.js +81 -0
- package/dist/core/schema/DescriptionGenerator.js.map +1 -0
- package/dist/core/schema/SchemaGenerator.d.ts +15 -0
- package/dist/core/schema/SchemaGenerator.d.ts.map +1 -0
- package/dist/core/schema/SchemaGenerator.js +192 -0
- package/dist/core/schema/SchemaGenerator.js.map +1 -0
- package/dist/core/schema/SchemaUtils.d.ts +26 -0
- package/dist/core/schema/SchemaUtils.d.ts.map +1 -0
- package/dist/core/schema/SchemaUtils.js +85 -0
- package/dist/core/schema/SchemaUtils.js.map +1 -0
- package/dist/core/schema/ToonDescriptionGenerator.d.ts +3 -0
- package/dist/core/schema/ToonDescriptionGenerator.d.ts.map +1 -0
- package/dist/core/schema/ToonDescriptionGenerator.js +65 -0
- package/dist/core/schema/ToonDescriptionGenerator.js.map +1 -0
- package/dist/core/schema/index.d.ts +7 -0
- package/dist/core/schema/index.d.ts.map +1 -0
- package/dist/core/schema/index.js +7 -0
- package/dist/core/schema/index.js.map +1 -0
- package/dist/core/serialization/JsonSerializer.d.ts +71 -0
- package/dist/core/serialization/JsonSerializer.d.ts.map +1 -0
- package/dist/core/serialization/JsonSerializer.js +192 -0
- package/dist/core/serialization/JsonSerializer.js.map +1 -0
- package/dist/core/serialization/index.d.ts +7 -0
- package/dist/core/serialization/index.d.ts.map +1 -0
- package/dist/core/serialization/index.js +7 -0
- package/dist/core/serialization/index.js.map +1 -0
- package/dist/core/types.d.ts +303 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +17 -0
- package/dist/core/types.js.map +1 -0
- package/dist/domain/Annotations.d.ts +42 -0
- package/dist/domain/Annotations.d.ts.map +1 -0
- package/dist/domain/Annotations.js +16 -0
- package/dist/domain/Annotations.js.map +1 -0
- package/dist/domain/BaseModel.d.ts +50 -0
- package/dist/domain/BaseModel.d.ts.map +1 -0
- package/dist/domain/BaseModel.js +41 -0
- package/dist/domain/BaseModel.js.map +1 -0
- package/dist/domain/Group.d.ts +99 -0
- package/dist/domain/Group.d.ts.map +1 -0
- package/dist/domain/Group.js +172 -0
- package/dist/domain/Group.js.map +1 -0
- package/dist/domain/GroupItem.d.ts +46 -0
- package/dist/domain/GroupItem.d.ts.map +1 -0
- package/dist/domain/GroupItem.js +58 -0
- package/dist/domain/GroupItem.js.map +1 -0
- package/dist/domain/Icon.d.ts +41 -0
- package/dist/domain/Icon.d.ts.map +1 -0
- package/dist/domain/Icon.js +15 -0
- package/dist/domain/Icon.js.map +1 -0
- package/dist/domain/Prompt.d.ts +49 -0
- package/dist/domain/Prompt.d.ts.map +1 -0
- package/dist/domain/Prompt.js +59 -0
- package/dist/domain/Prompt.js.map +1 -0
- package/dist/domain/PromptArgument.d.ts +23 -0
- package/dist/domain/PromptArgument.d.ts.map +1 -0
- package/dist/domain/PromptArgument.js +27 -0
- package/dist/domain/PromptArgument.js.map +1 -0
- package/dist/domain/Resource.d.ts +37 -0
- package/dist/domain/Resource.d.ts.map +1 -0
- package/dist/domain/Resource.js +39 -0
- package/dist/domain/Resource.js.map +1 -0
- package/dist/domain/Role.d.ts +23 -0
- package/dist/domain/Role.d.ts.map +1 -0
- package/dist/domain/Role.js +24 -0
- package/dist/domain/Role.js.map +1 -0
- package/dist/domain/Tool.d.ts +39 -0
- package/dist/domain/Tool.d.ts.map +1 -0
- package/dist/domain/Tool.js +41 -0
- package/dist/domain/Tool.js.map +1 -0
- package/dist/domain/ToolAnnotations.d.ts +48 -0
- package/dist/domain/ToolAnnotations.d.ts.map +1 -0
- package/dist/domain/ToolAnnotations.js +15 -0
- package/dist/domain/ToolAnnotations.js.map +1 -0
- package/dist/domain/index.d.ts +16 -0
- package/dist/domain/index.d.ts.map +1 -0
- package/dist/domain/index.js +13 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/domain/utils.d.ts +6 -0
- package/dist/domain/utils.d.ts.map +1 -0
- package/dist/domain/utils.js +12 -0
- package/dist/domain/utils.js.map +1 -0
- package/dist/edge-stub.d.ts +73 -0
- package/dist/edge-stub.d.ts.map +1 -0
- package/dist/edge-stub.js +83 -0
- package/dist/edge-stub.js.map +1 -0
- package/dist/exposition/ExpositionCompiler.d.ts +66 -0
- package/dist/exposition/ExpositionCompiler.d.ts.map +1 -0
- package/dist/exposition/ExpositionCompiler.js +279 -0
- package/dist/exposition/ExpositionCompiler.js.map +1 -0
- package/dist/exposition/index.d.ts +4 -0
- package/dist/exposition/index.d.ts.map +1 -0
- package/dist/exposition/index.js +2 -0
- package/dist/exposition/index.js.map +1 -0
- package/dist/exposition/types.d.ts +58 -0
- package/dist/exposition/types.d.ts.map +1 -0
- package/dist/exposition/types.js +11 -0
- package/dist/exposition/types.js.map +1 -0
- package/dist/fsm/StateMachineGate.d.ts +294 -0
- package/dist/fsm/StateMachineGate.d.ts.map +1 -0
- package/dist/fsm/StateMachineGate.js +400 -0
- package/dist/fsm/StateMachineGate.js.map +1 -0
- package/dist/index.d.ts +148 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +112 -0
- package/dist/index.js.map +1 -0
- package/dist/introspection/BehaviorDigest.d.ts +112 -0
- package/dist/introspection/BehaviorDigest.d.ts.map +1 -0
- package/dist/introspection/BehaviorDigest.js +149 -0
- package/dist/introspection/BehaviorDigest.js.map +1 -0
- package/dist/introspection/CapabilityLockfile.d.ts +261 -0
- package/dist/introspection/CapabilityLockfile.d.ts.map +1 -0
- package/dist/introspection/CapabilityLockfile.js +395 -0
- package/dist/introspection/CapabilityLockfile.js.map +1 -0
- package/dist/introspection/ContractAwareSelfHealing.d.ts +90 -0
- package/dist/introspection/ContractAwareSelfHealing.d.ts.map +1 -0
- package/dist/introspection/ContractAwareSelfHealing.js +132 -0
- package/dist/introspection/ContractAwareSelfHealing.js.map +1 -0
- package/dist/introspection/ContractDiff.d.ts +91 -0
- package/dist/introspection/ContractDiff.d.ts.map +1 -0
- package/dist/introspection/ContractDiff.js +466 -0
- package/dist/introspection/ContractDiff.js.map +1 -0
- package/dist/introspection/CryptoAttestation.d.ts +143 -0
- package/dist/introspection/CryptoAttestation.d.ts.map +1 -0
- package/dist/introspection/CryptoAttestation.js +192 -0
- package/dist/introspection/CryptoAttestation.js.map +1 -0
- package/dist/introspection/EntitlementScanner.d.ts +177 -0
- package/dist/introspection/EntitlementScanner.d.ts.map +1 -0
- package/dist/introspection/EntitlementScanner.js +459 -0
- package/dist/introspection/EntitlementScanner.js.map +1 -0
- package/dist/introspection/GovernanceObserver.d.ts +88 -0
- package/dist/introspection/GovernanceObserver.d.ts.map +1 -0
- package/dist/introspection/GovernanceObserver.js +136 -0
- package/dist/introspection/GovernanceObserver.js.map +1 -0
- package/dist/introspection/IntrospectionResource.d.ts +20 -0
- package/dist/introspection/IntrospectionResource.d.ts.map +1 -0
- package/dist/introspection/IntrospectionResource.js +112 -0
- package/dist/introspection/IntrospectionResource.js.map +1 -0
- package/dist/introspection/ManifestCompiler.d.ts +33 -0
- package/dist/introspection/ManifestCompiler.d.ts.map +1 -0
- package/dist/introspection/ManifestCompiler.js +88 -0
- package/dist/introspection/ManifestCompiler.js.map +1 -0
- package/dist/introspection/SemanticProbe.d.ts +207 -0
- package/dist/introspection/SemanticProbe.d.ts.map +1 -0
- package/dist/introspection/SemanticProbe.js +274 -0
- package/dist/introspection/SemanticProbe.js.map +1 -0
- package/dist/introspection/TokenEconomics.d.ts +210 -0
- package/dist/introspection/TokenEconomics.d.ts.map +1 -0
- package/dist/introspection/TokenEconomics.js +292 -0
- package/dist/introspection/TokenEconomics.js.map +1 -0
- package/dist/introspection/ToolContract.d.ts +161 -0
- package/dist/introspection/ToolContract.d.ts.map +1 -0
- package/dist/introspection/ToolContract.js +218 -0
- package/dist/introspection/ToolContract.js.map +1 -0
- package/dist/introspection/canonicalize.d.ts +35 -0
- package/dist/introspection/canonicalize.d.ts.map +1 -0
- package/dist/introspection/canonicalize.js +72 -0
- package/dist/introspection/canonicalize.js.map +1 -0
- package/dist/introspection/index.d.ts +26 -0
- package/dist/introspection/index.d.ts.map +1 -0
- package/dist/introspection/index.js +24 -0
- package/dist/introspection/index.js.map +1 -0
- package/dist/introspection/types.d.ts +120 -0
- package/dist/introspection/types.d.ts.map +1 -0
- package/dist/introspection/types.js +13 -0
- package/dist/introspection/types.js.map +1 -0
- package/dist/observability/DebugObserver.d.ts +185 -0
- package/dist/observability/DebugObserver.d.ts.map +1 -0
- package/dist/observability/DebugObserver.js +102 -0
- package/dist/observability/DebugObserver.js.map +1 -0
- package/dist/observability/TelemetryBus.d.ts +88 -0
- package/dist/observability/TelemetryBus.d.ts.map +1 -0
- package/dist/observability/TelemetryBus.js +463 -0
- package/dist/observability/TelemetryBus.js.map +1 -0
- package/dist/observability/TelemetryEvent.d.ts +177 -0
- package/dist/observability/TelemetryEvent.d.ts.map +1 -0
- package/dist/observability/TelemetryEvent.js +2 -0
- package/dist/observability/TelemetryEvent.js.map +1 -0
- package/dist/observability/Tracing.d.ts +155 -0
- package/dist/observability/Tracing.d.ts.map +1 -0
- package/dist/observability/Tracing.js +67 -0
- package/dist/observability/Tracing.js.map +1 -0
- package/dist/observability/index.d.ts +13 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +12 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/presenter/PostProcessor.d.ts +52 -0
- package/dist/presenter/PostProcessor.d.ts.map +1 -0
- package/dist/presenter/PostProcessor.js +148 -0
- package/dist/presenter/PostProcessor.js.map +1 -0
- package/dist/presenter/Presenter.d.ts +575 -0
- package/dist/presenter/Presenter.d.ts.map +1 -0
- package/dist/presenter/Presenter.js +768 -0
- package/dist/presenter/Presenter.js.map +1 -0
- package/dist/presenter/PresenterValidationError.d.ts +42 -0
- package/dist/presenter/PresenterValidationError.d.ts.map +1 -0
- package/dist/presenter/PresenterValidationError.js +55 -0
- package/dist/presenter/PresenterValidationError.js.map +1 -0
- package/dist/presenter/RedactEngine.d.ts +110 -0
- package/dist/presenter/RedactEngine.d.ts.map +1 -0
- package/dist/presenter/RedactEngine.js +128 -0
- package/dist/presenter/RedactEngine.js.map +1 -0
- package/dist/presenter/ResponseBuilder.d.ts +262 -0
- package/dist/presenter/ResponseBuilder.d.ts.map +1 -0
- package/dist/presenter/ResponseBuilder.js +374 -0
- package/dist/presenter/ResponseBuilder.js.map +1 -0
- package/dist/presenter/SelectUtils.d.ts +78 -0
- package/dist/presenter/SelectUtils.d.ts.map +1 -0
- package/dist/presenter/SelectUtils.js +141 -0
- package/dist/presenter/SelectUtils.js.map +1 -0
- package/dist/presenter/ZodDescriptionExtractor.d.ts +54 -0
- package/dist/presenter/ZodDescriptionExtractor.d.ts.map +1 -0
- package/dist/presenter/ZodDescriptionExtractor.js +131 -0
- package/dist/presenter/ZodDescriptionExtractor.js.map +1 -0
- package/dist/presenter/definePresenter.d.ts +193 -0
- package/dist/presenter/definePresenter.d.ts.map +1 -0
- package/dist/presenter/definePresenter.js +99 -0
- package/dist/presenter/definePresenter.js.map +1 -0
- package/dist/presenter/index.d.ts +21 -0
- package/dist/presenter/index.d.ts.map +1 -0
- package/dist/presenter/index.js +28 -0
- package/dist/presenter/index.js.map +1 -0
- package/dist/presenter/suggest.d.ts +39 -0
- package/dist/presenter/suggest.d.ts.map +1 -0
- package/dist/presenter/suggest.js +41 -0
- package/dist/presenter/suggest.js.map +1 -0
- package/dist/presenter/typeHelpers.d.ts +147 -0
- package/dist/presenter/typeHelpers.d.ts.map +1 -0
- package/dist/presenter/typeHelpers.js +152 -0
- package/dist/presenter/typeHelpers.js.map +1 -0
- package/dist/presenter/ui.d.ts +205 -0
- package/dist/presenter/ui.d.ts.map +1 -0
- package/dist/presenter/ui.js +222 -0
- package/dist/presenter/ui.js.map +1 -0
- package/dist/prompt/CursorCodec.d.ts +43 -0
- package/dist/prompt/CursorCodec.d.ts.map +1 -0
- package/dist/prompt/CursorCodec.js +171 -0
- package/dist/prompt/CursorCodec.js.map +1 -0
- package/dist/prompt/FluentPromptBuilder.d.ts +155 -0
- package/dist/prompt/FluentPromptBuilder.d.ts.map +1 -0
- package/dist/prompt/FluentPromptBuilder.js +195 -0
- package/dist/prompt/FluentPromptBuilder.js.map +1 -0
- package/dist/prompt/HydrationSandbox.d.ts +55 -0
- package/dist/prompt/HydrationSandbox.d.ts.map +1 -0
- package/dist/prompt/HydrationSandbox.js +122 -0
- package/dist/prompt/HydrationSandbox.js.map +1 -0
- package/dist/prompt/PromptExecutionPipeline.d.ts +61 -0
- package/dist/prompt/PromptExecutionPipeline.d.ts.map +1 -0
- package/dist/prompt/PromptExecutionPipeline.js +177 -0
- package/dist/prompt/PromptExecutionPipeline.js.map +1 -0
- package/dist/prompt/PromptMessage.d.ts +133 -0
- package/dist/prompt/PromptMessage.d.ts.map +1 -0
- package/dist/prompt/PromptMessage.js +182 -0
- package/dist/prompt/PromptMessage.js.map +1 -0
- package/dist/prompt/PromptRegistry.d.ts +236 -0
- package/dist/prompt/PromptRegistry.d.ts.map +1 -0
- package/dist/prompt/PromptRegistry.js +399 -0
- package/dist/prompt/PromptRegistry.js.map +1 -0
- package/dist/prompt/definePrompt.d.ts +111 -0
- package/dist/prompt/definePrompt.d.ts.map +1 -0
- package/dist/prompt/definePrompt.js +130 -0
- package/dist/prompt/definePrompt.js.map +1 -0
- package/dist/prompt/index.d.ts +12 -0
- package/dist/prompt/index.d.ts.map +1 -0
- package/dist/prompt/index.js +13 -0
- package/dist/prompt/index.js.map +1 -0
- package/dist/prompt/types.d.ts +425 -0
- package/dist/prompt/types.d.ts.map +1 -0
- package/dist/prompt/types.js +19 -0
- package/dist/prompt/types.js.map +1 -0
- package/dist/sandbox/SandboxEngine.d.ts +225 -0
- package/dist/sandbox/SandboxEngine.d.ts.map +1 -0
- package/dist/sandbox/SandboxEngine.js +437 -0
- package/dist/sandbox/SandboxEngine.js.map +1 -0
- package/dist/sandbox/SandboxGuard.d.ts +47 -0
- package/dist/sandbox/SandboxGuard.d.ts.map +1 -0
- package/dist/sandbox/SandboxGuard.js +127 -0
- package/dist/sandbox/SandboxGuard.js.map +1 -0
- package/dist/sandbox/index.d.ts +23 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +26 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/server/DevServer.d.ts +120 -0
- package/dist/server/DevServer.d.ts.map +1 -0
- package/dist/server/DevServer.js +252 -0
- package/dist/server/DevServer.js.map +1 -0
- package/dist/server/ServerAttachment.d.ts +354 -0
- package/dist/server/ServerAttachment.d.ts.map +1 -0
- package/dist/server/ServerAttachment.js +709 -0
- package/dist/server/ServerAttachment.js.map +1 -0
- package/dist/server/ServerResolver.d.ts +24 -0
- package/dist/server/ServerResolver.d.ts.map +1 -0
- package/dist/server/ServerResolver.js +50 -0
- package/dist/server/ServerResolver.js.map +1 -0
- package/dist/server/autoDiscover.d.ts +75 -0
- package/dist/server/autoDiscover.d.ts.map +1 -0
- package/dist/server/autoDiscover.js +164 -0
- package/dist/server/autoDiscover.js.map +1 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +11 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/startServer.d.ts +81 -0
- package/dist/server/startServer.d.ts.map +1 -0
- package/dist/server/startServer.js +143 -0
- package/dist/server/startServer.js.map +1 -0
- package/dist/state-sync/CausalEngine.d.ts +28 -0
- package/dist/state-sync/CausalEngine.d.ts.map +1 -0
- package/dist/state-sync/CausalEngine.js +17 -0
- package/dist/state-sync/CausalEngine.js.map +1 -0
- package/dist/state-sync/DescriptionDecorator.d.ts +31 -0
- package/dist/state-sync/DescriptionDecorator.d.ts.map +1 -0
- package/dist/state-sync/DescriptionDecorator.js +38 -0
- package/dist/state-sync/DescriptionDecorator.js.map +1 -0
- package/dist/state-sync/GlobMatcher.d.ts +29 -0
- package/dist/state-sync/GlobMatcher.d.ts.map +1 -0
- package/dist/state-sync/GlobMatcher.js +79 -0
- package/dist/state-sync/GlobMatcher.js.map +1 -0
- package/dist/state-sync/PolicyEngine.d.ts +75 -0
- package/dist/state-sync/PolicyEngine.d.ts.map +1 -0
- package/dist/state-sync/PolicyEngine.js +107 -0
- package/dist/state-sync/PolicyEngine.js.map +1 -0
- package/dist/state-sync/PolicyValidator.d.ts +67 -0
- package/dist/state-sync/PolicyValidator.d.ts.map +1 -0
- package/dist/state-sync/PolicyValidator.js +122 -0
- package/dist/state-sync/PolicyValidator.js.map +1 -0
- package/dist/state-sync/ResponseDecorator.d.ts +33 -0
- package/dist/state-sync/ResponseDecorator.d.ts.map +1 -0
- package/dist/state-sync/ResponseDecorator.js +20 -0
- package/dist/state-sync/ResponseDecorator.js.map +1 -0
- package/dist/state-sync/StateSyncBuilder.d.ts +77 -0
- package/dist/state-sync/StateSyncBuilder.d.ts.map +1 -0
- package/dist/state-sync/StateSyncBuilder.js +129 -0
- package/dist/state-sync/StateSyncBuilder.js.map +1 -0
- package/dist/state-sync/StateSyncLayer.d.ts +107 -0
- package/dist/state-sync/StateSyncLayer.d.ts.map +1 -0
- package/dist/state-sync/StateSyncLayer.js +158 -0
- package/dist/state-sync/StateSyncLayer.js.map +1 -0
- package/dist/state-sync/index.d.ts +27 -0
- package/dist/state-sync/index.d.ts.map +1 -0
- package/dist/state-sync/index.js +27 -0
- package/dist/state-sync/index.js.map +1 -0
- package/dist/state-sync/types.d.ts +174 -0
- package/dist/state-sync/types.d.ts.map +1 -0
- package/dist/state-sync/types.js +17 -0
- package/dist/state-sync/types.js.map +1 -0
- package/dist/testing/MvaMetaSymbol.d.ts +45 -0
- package/dist/testing/MvaMetaSymbol.d.ts.map +1 -0
- package/dist/testing/MvaMetaSymbol.js +34 -0
- package/dist/testing/MvaMetaSymbol.js.map +1 -0
- package/package.json +153 -0
|
@@ -0,0 +1,1306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GroupedToolBuilder — Fluent API for MCP Tool Construction
|
|
3
|
+
*
|
|
4
|
+
* The primary entry point for building grouped MCP tools. Consolidates
|
|
5
|
+
* multiple related actions behind a single discriminator field, reducing
|
|
6
|
+
* tool count and improving LLM routing accuracy.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { createTool, success, error } from 'vurb';
|
|
11
|
+
* import { z } from 'zod';
|
|
12
|
+
*
|
|
13
|
+
* const projects = createTool<AppContext>('projects')
|
|
14
|
+
* .description('Manage workspace projects')
|
|
15
|
+
* .commonSchema(z.object({
|
|
16
|
+
* workspace_id: z.string().describe('Workspace identifier'),
|
|
17
|
+
* }))
|
|
18
|
+
* .action({
|
|
19
|
+
* name: 'list',
|
|
20
|
+
* readOnly: true,
|
|
21
|
+
* schema: z.object({ status: z.enum(['active', 'archived']).optional() }),
|
|
22
|
+
* handler: async (ctx, args) => {
|
|
23
|
+
* const projects = await ctx.db.projects.findMany({
|
|
24
|
+
* where: { workspaceId: args.workspace_id, status: args.status },
|
|
25
|
+
* });
|
|
26
|
+
* return success(projects);
|
|
27
|
+
* },
|
|
28
|
+
* })
|
|
29
|
+
* .action({
|
|
30
|
+
* name: 'delete',
|
|
31
|
+
* destructive: true,
|
|
32
|
+
* schema: z.object({ project_id: z.string() }),
|
|
33
|
+
* handler: async (ctx, args) => {
|
|
34
|
+
* await ctx.db.projects.delete({ where: { id: args.project_id } });
|
|
35
|
+
* return success('Deleted');
|
|
36
|
+
* },
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @see {@link createTool} for the recommended factory function
|
|
41
|
+
* @see {@link ToolRegistry} for registration and server attachment
|
|
42
|
+
* @see {@link ActionGroupBuilder} for hierarchical group configuration
|
|
43
|
+
*
|
|
44
|
+
* @module
|
|
45
|
+
*/
|
|
46
|
+
import {} from 'zod';
|
|
47
|
+
import {} from '@modelcontextprotocol/sdk/types.js';
|
|
48
|
+
import { error, toolError } from '../response.js';
|
|
49
|
+
import {} from '../types.js';
|
|
50
|
+
import {} from '../../observability/DebugObserver.js';
|
|
51
|
+
import {} from '../../observability/TelemetryEvent.js';
|
|
52
|
+
import { resolveMiddleware } from '../middleware/ContextDerivation.js';
|
|
53
|
+
import { SpanStatusCode } from '../../observability/Tracing.js';
|
|
54
|
+
import { getActionRequiredFields } from '../schema/SchemaUtils.js';
|
|
55
|
+
import { parseDiscriminator, resolveAction, validateArgs, runChain, } from '../execution/ExecutionPipeline.js';
|
|
56
|
+
import {} from '../../presenter/PostProcessor.js';
|
|
57
|
+
import {} from '../execution/ProgressHelper.js';
|
|
58
|
+
import { ConcurrencyGuard } from '../execution/ConcurrencyGuard.js';
|
|
59
|
+
import { applyEgressGuard } from '../execution/EgressGuard.js';
|
|
60
|
+
import {} from '../../sandbox/SandboxEngine.js';
|
|
61
|
+
import { MutationSerializer } from '../execution/MutationSerializer.js';
|
|
62
|
+
import { computeResponseSize, mergeHooks } from '../execution/PipelineHooks.js';
|
|
63
|
+
import { compileToolDefinition } from './ToolDefinitionCompiler.js';
|
|
64
|
+
import { ActionGroupBuilder, mapConfigToActionFields, } from './ActionGroupBuilder.js';
|
|
65
|
+
// ── Re-exports for Public API Compatibility ──────────────
|
|
66
|
+
export { ActionGroupBuilder } from './ActionGroupBuilder.js';
|
|
67
|
+
// ── Factory Function ─────────────────────────────────────
|
|
68
|
+
/**
|
|
69
|
+
* Create a new grouped tool builder.
|
|
70
|
+
*
|
|
71
|
+
* This is the **recommended entry point** for building MCP tools.
|
|
72
|
+
* Equivalent to `new GroupedToolBuilder<TContext>(name)` but more
|
|
73
|
+
* concise and idiomatic.
|
|
74
|
+
*
|
|
75
|
+
* @typeParam TContext - Application context type passed to every handler.
|
|
76
|
+
* Use `void` (default) if your handlers don't need context.
|
|
77
|
+
*
|
|
78
|
+
* @param name - Tool name as it appears in the MCP `tools/list` response.
|
|
79
|
+
* Must be unique across all registered tools.
|
|
80
|
+
*
|
|
81
|
+
* @returns A new {@link GroupedToolBuilder} configured with the given name.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* // Simple tool (no context)
|
|
86
|
+
* const echo = createTool('echo')
|
|
87
|
+
* .action({
|
|
88
|
+
* name: 'say',
|
|
89
|
+
* schema: z.object({ message: z.string() }),
|
|
90
|
+
* handler: async (_ctx, args) => success(args.message),
|
|
91
|
+
* });
|
|
92
|
+
*
|
|
93
|
+
* // With application context
|
|
94
|
+
* const users = createTool<AppContext>('users')
|
|
95
|
+
* .description('User management')
|
|
96
|
+
* .use(requireAuth)
|
|
97
|
+
* .action({
|
|
98
|
+
* name: 'list',
|
|
99
|
+
* readOnly: true,
|
|
100
|
+
* handler: async (ctx, _args) => success(await ctx.db.users.findMany()),
|
|
101
|
+
* });
|
|
102
|
+
*
|
|
103
|
+
* // With hierarchical groups
|
|
104
|
+
* const platform = createTool<AppContext>('platform')
|
|
105
|
+
* .tags('core')
|
|
106
|
+
* .group('users', 'User management', g => {
|
|
107
|
+
* g.action({ name: 'list', readOnly: true, handler: listUsers });
|
|
108
|
+
* })
|
|
109
|
+
* .group('billing', 'Billing operations', g => {
|
|
110
|
+
* g.action({ name: 'refund', destructive: true, schema: refundSchema, handler: issueRefund });
|
|
111
|
+
* });
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* @see {@link GroupedToolBuilder} for the full builder API
|
|
115
|
+
* @see {@link ToolRegistry.register} for tool registration
|
|
116
|
+
*/
|
|
117
|
+
export function createTool(name) {
|
|
118
|
+
return new GroupedToolBuilder(name);
|
|
119
|
+
}
|
|
120
|
+
// ============================================================================
|
|
121
|
+
// GroupedToolBuilder
|
|
122
|
+
// ============================================================================
|
|
123
|
+
/**
|
|
124
|
+
* Fluent builder for creating consolidated MCP tools.
|
|
125
|
+
*
|
|
126
|
+
* Groups multiple related operations behind a single discriminator field
|
|
127
|
+
* (default: `"action"`), producing one MCP tool definition with a
|
|
128
|
+
* union schema and auto-generated descriptions.
|
|
129
|
+
*
|
|
130
|
+
* @typeParam TContext - Application context passed to every handler
|
|
131
|
+
* @typeParam TCommon - Shape of the common schema (inferred automatically)
|
|
132
|
+
* @typeParam TName - Tool name literal (inferred by createTool)
|
|
133
|
+
* @typeParam TRouterMap - Accumulated action entries for InferRouter (phantom type)
|
|
134
|
+
*
|
|
135
|
+
* @see {@link createTool} for the recommended factory function
|
|
136
|
+
*/
|
|
137
|
+
export class GroupedToolBuilder {
|
|
138
|
+
_name;
|
|
139
|
+
_description;
|
|
140
|
+
_discriminator = 'action';
|
|
141
|
+
_annotations;
|
|
142
|
+
_tags = [];
|
|
143
|
+
_commonSchema;
|
|
144
|
+
_middlewares = [];
|
|
145
|
+
_actions = [];
|
|
146
|
+
_hasFlat = false;
|
|
147
|
+
_hasGroup = false;
|
|
148
|
+
_toonMode = false;
|
|
149
|
+
_selectEnabled = false;
|
|
150
|
+
_frozen = false;
|
|
151
|
+
_debug;
|
|
152
|
+
_tracer;
|
|
153
|
+
_telemetry;
|
|
154
|
+
_concurrencyGuard;
|
|
155
|
+
_egressMaxBytes;
|
|
156
|
+
_sandboxConfig;
|
|
157
|
+
_mutationSerializer;
|
|
158
|
+
_stateSyncHints = new Map();
|
|
159
|
+
_fsmStates;
|
|
160
|
+
_fsmTransition;
|
|
161
|
+
// Cached build result
|
|
162
|
+
_cachedTool;
|
|
163
|
+
_executionContext;
|
|
164
|
+
constructor(name) {
|
|
165
|
+
this._name = name;
|
|
166
|
+
}
|
|
167
|
+
// ── Configuration (fluent) ──────────────────────────
|
|
168
|
+
/**
|
|
169
|
+
* Set the discriminator field name.
|
|
170
|
+
*
|
|
171
|
+
* The discriminator is the field the LLM uses to select which action
|
|
172
|
+
* to execute. Defaults to `"action"`.
|
|
173
|
+
*
|
|
174
|
+
* @param field - Field name for the discriminator enum
|
|
175
|
+
* @returns `this` for chaining
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* // Custom discriminator
|
|
180
|
+
* const builder = createTool('projects')
|
|
181
|
+
* .discriminator('operation')
|
|
182
|
+
* .action({ name: 'list', handler: listProjects });
|
|
183
|
+
* // LLM sends: { operation: 'list' }
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
186
|
+
* @defaultValue `"action"`
|
|
187
|
+
*/
|
|
188
|
+
discriminator(field) {
|
|
189
|
+
this._assertNotFrozen();
|
|
190
|
+
this._discriminator = field;
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Set the tool description.
|
|
195
|
+
*
|
|
196
|
+
* Appears as the first line in the auto-generated tool description
|
|
197
|
+
* that the LLM sees.
|
|
198
|
+
*
|
|
199
|
+
* @param desc - Human-readable description of what this tool does
|
|
200
|
+
* @returns `this` for chaining
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* createTool('projects')
|
|
205
|
+
* .description('Manage workspace projects')
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
description(desc) {
|
|
209
|
+
this._assertNotFrozen();
|
|
210
|
+
this._description = desc;
|
|
211
|
+
return this;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Set MCP tool annotations.
|
|
215
|
+
*
|
|
216
|
+
* Manual override for tool-level annotations. If not set,
|
|
217
|
+
* annotations are automatically aggregated from per-action properties.
|
|
218
|
+
*
|
|
219
|
+
* @param a - Annotation key-value pairs
|
|
220
|
+
* @returns `this` for chaining
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* createTool('admin')
|
|
225
|
+
* .annotations({ openWorldHint: true, returnDirect: false })
|
|
226
|
+
* ```
|
|
227
|
+
*
|
|
228
|
+
* @see {@link https://modelcontextprotocol.io/specification/2025-03-26/server/tools#annotations | MCP Tool Annotations}
|
|
229
|
+
*/
|
|
230
|
+
annotations(a) {
|
|
231
|
+
this._assertNotFrozen();
|
|
232
|
+
this._annotations = a;
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Set capability tags for selective tool exposure.
|
|
237
|
+
*
|
|
238
|
+
* Tags control which tools the LLM sees via
|
|
239
|
+
* {@link ToolRegistry.attachToServer}'s `filter` option.
|
|
240
|
+
* Use tags to implement per-session context gating.
|
|
241
|
+
*
|
|
242
|
+
* @param tags - One or more string tags
|
|
243
|
+
* @returns `this` for chaining
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* const users = createTool<AppContext>('users').tags('core');
|
|
248
|
+
* const admin = createTool<AppContext>('admin').tags('admin', 'internal');
|
|
249
|
+
*
|
|
250
|
+
* // Expose only 'core' tools to the LLM:
|
|
251
|
+
* registry.attachToServer(server, { filter: { tags: ['core'] } });
|
|
252
|
+
* ```
|
|
253
|
+
*
|
|
254
|
+
* @see {@link ToolRegistry.getTools} for filtered tool retrieval
|
|
255
|
+
*/
|
|
256
|
+
tags(...tags) {
|
|
257
|
+
this._assertNotFrozen();
|
|
258
|
+
this._tags.push(...tags);
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Set a common schema shared by all actions.
|
|
263
|
+
*
|
|
264
|
+
* Fields from this schema are injected into every action's input
|
|
265
|
+
* and marked as `(always required)` in the auto-generated description.
|
|
266
|
+
* The return type narrows to propagate types to all handlers.
|
|
267
|
+
*
|
|
268
|
+
* @typeParam TSchema - Zod object schema type (inferred)
|
|
269
|
+
* @param schema - A `z.object()` defining shared fields
|
|
270
|
+
* @returns A narrowed builder with `TCommon` set to `TSchema["_output"]`
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```typescript
|
|
274
|
+
* createTool<AppContext>('projects')
|
|
275
|
+
* .commonSchema(z.object({
|
|
276
|
+
* workspace_id: z.string().describe('Workspace identifier'),
|
|
277
|
+
* }))
|
|
278
|
+
* .action({
|
|
279
|
+
* name: 'list',
|
|
280
|
+
* handler: async (ctx, args) => {
|
|
281
|
+
* // ✅ args.workspace_id is typed as string
|
|
282
|
+
* const projects = await ctx.db.projects.findMany({
|
|
283
|
+
* where: { workspaceId: args.workspace_id },
|
|
284
|
+
* });
|
|
285
|
+
* return success(projects);
|
|
286
|
+
* },
|
|
287
|
+
* });
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
commonSchema(schema) {
|
|
291
|
+
this._assertNotFrozen();
|
|
292
|
+
this._commonSchema = schema;
|
|
293
|
+
return this;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Enable TOON-formatted descriptions for token optimization.
|
|
297
|
+
*
|
|
298
|
+
* Uses TOON (Token-Oriented Object Notation) to encode action metadata
|
|
299
|
+
* in a compact tabular format, reducing description token count by ~30-50%.
|
|
300
|
+
*
|
|
301
|
+
* @returns `this` for chaining
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* createTool('projects')
|
|
306
|
+
* .toonDescription() // Compact descriptions
|
|
307
|
+
* .action({ name: 'list', handler: listProjects })
|
|
308
|
+
* ```
|
|
309
|
+
*
|
|
310
|
+
* @see {@link toonSuccess} for TOON-encoded responses
|
|
311
|
+
*/
|
|
312
|
+
toonDescription() {
|
|
313
|
+
this._assertNotFrozen();
|
|
314
|
+
this._toonMode = true;
|
|
315
|
+
return this;
|
|
316
|
+
}
|
|
317
|
+
// ── State Sync (Fluent) ──────────────────────────────
|
|
318
|
+
/**
|
|
319
|
+
* Declare glob patterns invalidated when this tool succeeds.
|
|
320
|
+
*
|
|
321
|
+
* Eliminates manual `stateSync.policies` configuration —
|
|
322
|
+
* the framework auto-collects hints from all builders.
|
|
323
|
+
*
|
|
324
|
+
* @param patterns - Glob patterns (e.g. `'sprints.*'`, `'tasks.*'`)
|
|
325
|
+
* @returns `this` for chaining
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```typescript
|
|
329
|
+
* createTool('tasks')
|
|
330
|
+
* .invalidates('tasks.*', 'sprints.*')
|
|
331
|
+
* .action({ name: 'update', handler: updateTask });
|
|
332
|
+
* ```
|
|
333
|
+
*
|
|
334
|
+
* @see {@link StateSyncConfig} for centralized configuration
|
|
335
|
+
*/
|
|
336
|
+
invalidates(...patterns) {
|
|
337
|
+
this._assertNotFrozen();
|
|
338
|
+
// Store under tool-level key '*' — applies to all actions
|
|
339
|
+
const existing = this._stateSyncHints.get('*');
|
|
340
|
+
this._stateSyncHints.set('*', {
|
|
341
|
+
...existing,
|
|
342
|
+
invalidates: [...(existing?.invalidates ?? []), ...patterns],
|
|
343
|
+
});
|
|
344
|
+
return this;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Mark this tool's data as immutable (safe to cache forever).
|
|
348
|
+
*
|
|
349
|
+
* Use for reference data: countries, currencies, ICD-10 codes.
|
|
350
|
+
* Equivalent to `cacheControl: 'immutable'` in manual policies.
|
|
351
|
+
*
|
|
352
|
+
* @returns `this` for chaining
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* ```typescript
|
|
356
|
+
* createTool('countries')
|
|
357
|
+
* .cached()
|
|
358
|
+
* .action({ name: 'list', readOnly: true, handler: listCountries });
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
cached() {
|
|
362
|
+
return this._setCacheDirective('immutable');
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Mark this tool's data as volatile (never cache).
|
|
366
|
+
*
|
|
367
|
+
* Equivalent to `cacheControl: 'no-store'` in manual policies.
|
|
368
|
+
* Use for dynamic data that changes frequently.
|
|
369
|
+
*
|
|
370
|
+
* @returns `this` for chaining
|
|
371
|
+
*/
|
|
372
|
+
stale() {
|
|
373
|
+
return this._setCacheDirective('no-store');
|
|
374
|
+
}
|
|
375
|
+
/** @internal */
|
|
376
|
+
_setCacheDirective(directive) {
|
|
377
|
+
this._assertNotFrozen();
|
|
378
|
+
const existing = this._stateSyncHints.get('*');
|
|
379
|
+
this._stateSyncHints.set('*', { ...existing, cacheControl: directive });
|
|
380
|
+
return this;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Enable `_select` reflection for context window optimization.
|
|
384
|
+
*
|
|
385
|
+
* When enabled, actions that use a Presenter with a Zod schema
|
|
386
|
+
* expose an optional `_select` parameter in the input schema.
|
|
387
|
+
* The AI can send `_select: ['status', 'amount']` to receive
|
|
388
|
+
* only the specified top-level fields in the data payload,
|
|
389
|
+
* reducing context window usage without developer effort.
|
|
390
|
+
*
|
|
391
|
+
* **Disabled by default** — opt-in to avoid changing existing
|
|
392
|
+
* tool schemas.
|
|
393
|
+
*
|
|
394
|
+
* **Late Guillotine**: UI blocks, system rules, and action
|
|
395
|
+
* suggestions are always computed with the **full** validated
|
|
396
|
+
* data. Only the wire-facing data block is filtered.
|
|
397
|
+
*
|
|
398
|
+
* **Shallow (top-level only)**: Nested objects are returned
|
|
399
|
+
* whole. If the AI selects `'user'`, it gets the entire `user`
|
|
400
|
+
* object. No recursive GraphQL-style traversal.
|
|
401
|
+
*
|
|
402
|
+
* @returns `this` for chaining
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```typescript
|
|
406
|
+
* createTool<AppContext>('invoices')
|
|
407
|
+
* .enableSelect() // Expose _select in input schema
|
|
408
|
+
* .action({
|
|
409
|
+
* name: 'get',
|
|
410
|
+
* returns: InvoicePresenter,
|
|
411
|
+
* handler: async (ctx, args) => ctx.db.invoices.findUnique(args.id),
|
|
412
|
+
* });
|
|
413
|
+
* // AI sends: { action: 'get', id: '123', _select: ['status'] }
|
|
414
|
+
* // Returns: { status: 'paid' } instead of full invoice
|
|
415
|
+
* ```
|
|
416
|
+
*
|
|
417
|
+
* @see {@link Presenter.getSchemaKeys} for introspection
|
|
418
|
+
*/
|
|
419
|
+
enableSelect() {
|
|
420
|
+
this._assertNotFrozen();
|
|
421
|
+
this._selectEnabled = true;
|
|
422
|
+
return this;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Set concurrency limits for this tool (Semaphore + Queue pattern).
|
|
426
|
+
*
|
|
427
|
+
* Prevents thundering-herd scenarios where the LLM fires N
|
|
428
|
+
* concurrent calls in the same millisecond. Implements a
|
|
429
|
+
* semaphore with backpressure queue and load shedding.
|
|
430
|
+
*
|
|
431
|
+
* When all active slots are occupied, new calls enter the queue.
|
|
432
|
+
* When the queue is full, calls are immediately rejected with
|
|
433
|
+
* a self-healing `SERVER_BUSY` error.
|
|
434
|
+
*
|
|
435
|
+
* **MCP Spec Compliance**: The MCP specification requires servers
|
|
436
|
+
* to rate-limit tool invocations. This method fulfills that requirement.
|
|
437
|
+
*
|
|
438
|
+
* **Zero overhead** when not configured — no semaphore exists.
|
|
439
|
+
*
|
|
440
|
+
* @param config - Concurrency configuration
|
|
441
|
+
* @returns `this` for chaining
|
|
442
|
+
*
|
|
443
|
+
* @example
|
|
444
|
+
* ```typescript
|
|
445
|
+
* createTool<AppContext>('billing')
|
|
446
|
+
* .concurrency({ maxActive: 5, maxQueue: 20 })
|
|
447
|
+
* .action({ name: 'process_invoice', handler: processInvoice });
|
|
448
|
+
* // 5 concurrent executions, 20 queued, rest rejected
|
|
449
|
+
* ```
|
|
450
|
+
*
|
|
451
|
+
* @see {@link ConcurrencyConfig} for configuration options
|
|
452
|
+
*/
|
|
453
|
+
concurrency(config) {
|
|
454
|
+
this._assertNotFrozen();
|
|
455
|
+
this._concurrencyGuard = new ConcurrencyGuard(config);
|
|
456
|
+
return this;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Set maximum payload size for tool responses (Egress Guard).
|
|
460
|
+
*
|
|
461
|
+
* Prevents oversized responses from crashing the Node process
|
|
462
|
+
* with OOM or overflowing the LLM context window.
|
|
463
|
+
*
|
|
464
|
+
* When a response exceeds the limit, the text content is truncated
|
|
465
|
+
* and a system intervention message is injected, forcing the LLM
|
|
466
|
+
* to use pagination or filters.
|
|
467
|
+
*
|
|
468
|
+
* This is a **brute-force safety net**. For domain-aware truncation
|
|
469
|
+
* with guidance, use Presenter `.agentLimit()` instead.
|
|
470
|
+
*
|
|
471
|
+
* **Zero overhead** when not configured.
|
|
472
|
+
*
|
|
473
|
+
* @param bytes - Maximum payload size in bytes
|
|
474
|
+
* @returns `this` for chaining
|
|
475
|
+
*
|
|
476
|
+
* @example
|
|
477
|
+
* ```typescript
|
|
478
|
+
* createTool<AppContext>('logs')
|
|
479
|
+
* .maxPayloadBytes(2 * 1024 * 1024) // 2MB
|
|
480
|
+
* .action({ name: 'search', handler: searchLogs });
|
|
481
|
+
* ```
|
|
482
|
+
*
|
|
483
|
+
* @see {@link Presenter.agentLimit} for domain-level truncation
|
|
484
|
+
*/
|
|
485
|
+
maxPayloadBytes(bytes) {
|
|
486
|
+
this._assertNotFrozen();
|
|
487
|
+
this._egressMaxBytes = Math.max(1024, Math.floor(bytes));
|
|
488
|
+
return this;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Enable zero-trust sandboxed execution for this tool.
|
|
492
|
+
*
|
|
493
|
+
* Stores the sandbox configuration so that tools built with
|
|
494
|
+
* `.sandboxed()` on the FluentToolBuilder can propagate it.
|
|
495
|
+
*
|
|
496
|
+
* @param config - Sandbox configuration (timeout, memory, output size)
|
|
497
|
+
* @returns `this` for chaining
|
|
498
|
+
*
|
|
499
|
+
* @example
|
|
500
|
+
* ```typescript
|
|
501
|
+
* createTool<AppContext>('analytics')
|
|
502
|
+
* .sandbox({ timeout: 5000, memoryLimit: 128 })
|
|
503
|
+
* .action({ name: 'compute', handler: computeHandler });
|
|
504
|
+
* ```
|
|
505
|
+
*
|
|
506
|
+
* @see {@link SandboxConfig} for configuration options
|
|
507
|
+
* @see {@link SandboxEngine} for the execution engine
|
|
508
|
+
*/
|
|
509
|
+
sandbox(config) {
|
|
510
|
+
this._assertNotFrozen();
|
|
511
|
+
this._sandboxConfig = config;
|
|
512
|
+
return this;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Get the sandbox configuration (if any).
|
|
516
|
+
*
|
|
517
|
+
* **Important**: This is metadata only — it does NOT auto-create a
|
|
518
|
+
* `SandboxEngine` nor inject it into the execution pipeline.
|
|
519
|
+
* The developer must create the engine manually (e.g. via `f.sandbox()`).
|
|
520
|
+
* This accessor exists for introspection, testing, and contract tooling.
|
|
521
|
+
*
|
|
522
|
+
* @returns The stored `SandboxConfig`, or `undefined` if `.sandbox()` was not called
|
|
523
|
+
*/
|
|
524
|
+
getSandboxConfig() {
|
|
525
|
+
return this._sandboxConfig;
|
|
526
|
+
}
|
|
527
|
+
// ── FSM State Gate (Temporal Anti-Hallucination) ─────
|
|
528
|
+
/**
|
|
529
|
+
* Bind this tool to specific FSM states.
|
|
530
|
+
*
|
|
531
|
+
* When a `StateMachineGate` is configured, this tool is only
|
|
532
|
+
* visible in `tools/list` when the FSM is in one of the specified states.
|
|
533
|
+
*
|
|
534
|
+
* @param states - FSM state(s) where this tool is visible
|
|
535
|
+
* @param transition - Event to send on successful execution
|
|
536
|
+
* @returns `this` for chaining
|
|
537
|
+
*/
|
|
538
|
+
bindState(states, transition) {
|
|
539
|
+
this._assertNotFrozen();
|
|
540
|
+
this._fsmStates = states;
|
|
541
|
+
if (transition !== undefined)
|
|
542
|
+
this._fsmTransition = transition;
|
|
543
|
+
return this;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Get the FSM binding metadata (if any).
|
|
547
|
+
* Used by `ToolRegistry` and `ServerAttachment` for FSM gating.
|
|
548
|
+
*/
|
|
549
|
+
getFsmBinding() {
|
|
550
|
+
if (!this._fsmStates)
|
|
551
|
+
return undefined;
|
|
552
|
+
const binding = {
|
|
553
|
+
states: this._fsmStates,
|
|
554
|
+
};
|
|
555
|
+
if (this._fsmTransition)
|
|
556
|
+
binding.transition = this._fsmTransition;
|
|
557
|
+
return binding;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Get the tool name.
|
|
561
|
+
* Used by framework internals for tool routing and FSM binding.
|
|
562
|
+
*/
|
|
563
|
+
getToolName() {
|
|
564
|
+
return this._name;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Add middleware to the execution chain.
|
|
568
|
+
*
|
|
569
|
+
* Middleware runs in **registration order** (first registered = outermost).
|
|
570
|
+
* Chains are pre-compiled at build time — zero runtime assembly cost.
|
|
571
|
+
*
|
|
572
|
+
* Accepts both `MiddlewareDefinition` from `f.middleware()` and
|
|
573
|
+
* raw `MiddlewareFn` functions.
|
|
574
|
+
*
|
|
575
|
+
* @param mw - Middleware function or MiddlewareDefinition
|
|
576
|
+
* @returns `this` for chaining
|
|
577
|
+
*
|
|
578
|
+
* @example
|
|
579
|
+
* ```typescript
|
|
580
|
+
* const requireAuth: MiddlewareFn<AppContext> = async (ctx, args, next) => {
|
|
581
|
+
* if (!ctx.user) return error('Unauthorized');
|
|
582
|
+
* return next();
|
|
583
|
+
* };
|
|
584
|
+
*
|
|
585
|
+
* createTool<AppContext>('projects')
|
|
586
|
+
* .use(requireAuth) // Runs on every action
|
|
587
|
+
* .action({ name: 'list', handler: listProjects });
|
|
588
|
+
* ```
|
|
589
|
+
*
|
|
590
|
+
* @see {@link MiddlewareFn} for the middleware signature
|
|
591
|
+
* @see {@link ActionGroupBuilder.use} for group-scoped middleware
|
|
592
|
+
*/
|
|
593
|
+
use(mw) {
|
|
594
|
+
this._assertNotFrozen();
|
|
595
|
+
this._middlewares.push(resolveMiddleware(mw));
|
|
596
|
+
return this;
|
|
597
|
+
}
|
|
598
|
+
action(config) {
|
|
599
|
+
this._assertNotFrozen();
|
|
600
|
+
if (this._hasGroup) {
|
|
601
|
+
throw new Error(`Cannot use .action() and .group() on the same builder "${this._name}". ` +
|
|
602
|
+
`Use .action() for flat tools OR .group() for hierarchical tools.`);
|
|
603
|
+
}
|
|
604
|
+
this._hasFlat = true;
|
|
605
|
+
// Bug #115 fix: reject empty or whitespace-only action names.
|
|
606
|
+
if (!config.name || !config.name.trim()) {
|
|
607
|
+
throw new Error(`Action name must be a non-empty string on builder "${this._name}". ` +
|
|
608
|
+
`Received: ${JSON.stringify(config.name)}.`);
|
|
609
|
+
}
|
|
610
|
+
if (config.name.includes('.')) {
|
|
611
|
+
throw new Error(`Action name "${config.name}" must not contain dots. ` +
|
|
612
|
+
`The framework uses dots internally for group.action compound keys.`);
|
|
613
|
+
}
|
|
614
|
+
// Bug #112 fix: reject duplicate action names instead of silently
|
|
615
|
+
// registering two actions with the same discriminator key.
|
|
616
|
+
if (this._actions.some(a => a.key === config.name)) {
|
|
617
|
+
throw new Error(`Duplicate action name "${config.name}" on builder "${this._name}". ` +
|
|
618
|
+
`Each action must have a unique name within its tool.`);
|
|
619
|
+
}
|
|
620
|
+
this._actions.push({
|
|
621
|
+
key: config.name,
|
|
622
|
+
groupName: undefined,
|
|
623
|
+
groupDescription: undefined,
|
|
624
|
+
...mapConfigToActionFields(config, (config.omitCommon?.length ?? 0) > 0 ? config.omitCommon : undefined),
|
|
625
|
+
middlewares: undefined,
|
|
626
|
+
});
|
|
627
|
+
return this;
|
|
628
|
+
}
|
|
629
|
+
group(name, descriptionOrConfigure, maybeConfigure) {
|
|
630
|
+
this._assertNotFrozen();
|
|
631
|
+
const description = typeof descriptionOrConfigure === 'string'
|
|
632
|
+
? descriptionOrConfigure
|
|
633
|
+
: undefined;
|
|
634
|
+
const configure = typeof descriptionOrConfigure === 'function'
|
|
635
|
+
? descriptionOrConfigure
|
|
636
|
+
: maybeConfigure;
|
|
637
|
+
if (!configure) {
|
|
638
|
+
throw new Error(`Group "${name}" requires a configure callback.`);
|
|
639
|
+
}
|
|
640
|
+
if (this._hasFlat) {
|
|
641
|
+
throw new Error(`Cannot use .group() and .action() on the same builder "${this._name}". ` +
|
|
642
|
+
`Use .action() for flat tools OR .group() for hierarchical tools.`);
|
|
643
|
+
}
|
|
644
|
+
if (name.includes('.')) {
|
|
645
|
+
throw new Error(`Group name "${name}" must not contain dots.`);
|
|
646
|
+
}
|
|
647
|
+
this._hasGroup = true;
|
|
648
|
+
const groupBuilder = new ActionGroupBuilder(name, description);
|
|
649
|
+
configure(groupBuilder);
|
|
650
|
+
this._actions.push(...groupBuilder._actions);
|
|
651
|
+
return this;
|
|
652
|
+
}
|
|
653
|
+
// ── Build (delegates to ToolDefinitionCompiler) ─────
|
|
654
|
+
/**
|
|
655
|
+
* Generate the MCP Tool definition.
|
|
656
|
+
*
|
|
657
|
+
* Compiles all actions into a single MCP tool with auto-generated
|
|
658
|
+
* description, union schema, and aggregated annotations. Caches
|
|
659
|
+
* the result and permanently freezes the builder.
|
|
660
|
+
*
|
|
661
|
+
* Called automatically by {@link execute} if not called explicitly.
|
|
662
|
+
*
|
|
663
|
+
* @returns The compiled MCP Tool object
|
|
664
|
+
* @throws If no actions are registered
|
|
665
|
+
*
|
|
666
|
+
* @example
|
|
667
|
+
* ```typescript
|
|
668
|
+
* const tool = builder.buildToolDefinition();
|
|
669
|
+
* console.log(tool.name); // "projects"
|
|
670
|
+
* console.log(tool.description); // Auto-generated
|
|
671
|
+
* console.log(tool.inputSchema); // Union of all action schemas
|
|
672
|
+
* ```
|
|
673
|
+
*/
|
|
674
|
+
buildToolDefinition() {
|
|
675
|
+
if (this._cachedTool)
|
|
676
|
+
return this._cachedTool;
|
|
677
|
+
const result = compileToolDefinition({
|
|
678
|
+
name: this._name,
|
|
679
|
+
description: this._description,
|
|
680
|
+
discriminator: this._discriminator,
|
|
681
|
+
toonMode: this._toonMode,
|
|
682
|
+
selectEnabled: this._selectEnabled,
|
|
683
|
+
hasGroup: this._hasGroup,
|
|
684
|
+
actions: this._actions,
|
|
685
|
+
middlewares: this._middlewares,
|
|
686
|
+
commonSchema: this._commonSchema,
|
|
687
|
+
annotations: this._annotations,
|
|
688
|
+
});
|
|
689
|
+
this._cachedTool = result.tool;
|
|
690
|
+
this._executionContext = result.executionContext;
|
|
691
|
+
this._frozen = true;
|
|
692
|
+
Object.freeze(this._actions);
|
|
693
|
+
// Auto-create MutationSerializer if any action is destructive.
|
|
694
|
+
// Converts `destructive: true` from a manifest hint into a
|
|
695
|
+
// transactional isolation guarantee — concurrent mutations to
|
|
696
|
+
// the same action key are serialized in FIFO order.
|
|
697
|
+
if (this._actions.some(a => a.destructive === true)) {
|
|
698
|
+
this._mutationSerializer = new MutationSerializer();
|
|
699
|
+
}
|
|
700
|
+
return result.tool;
|
|
701
|
+
}
|
|
702
|
+
// ── Debug (opt-in observability) ──────────────────────
|
|
703
|
+
/**
|
|
704
|
+
* Enable debug observability for this tool.
|
|
705
|
+
*
|
|
706
|
+
* When enabled, structured {@link DebugEvent} events are emitted at
|
|
707
|
+
* each step of the execution pipeline.
|
|
708
|
+
*
|
|
709
|
+
* When disabled (the default), there is **zero runtime overhead** —
|
|
710
|
+
* no conditionals, no timing, no object allocations in the hot path.
|
|
711
|
+
*
|
|
712
|
+
* @param observer - A {@link DebugObserverFn} created by `createDebugObserver()`
|
|
713
|
+
* @returns `this` for chaining
|
|
714
|
+
*
|
|
715
|
+
* @example
|
|
716
|
+
* ```typescript
|
|
717
|
+
* import { createTool, createDebugObserver, success } from 'vurb';
|
|
718
|
+
*
|
|
719
|
+
* const debug = createDebugObserver();
|
|
720
|
+
*
|
|
721
|
+
* const tool = createTool<void>('users')
|
|
722
|
+
* .debug(debug) // ← enable observability
|
|
723
|
+
* .action({ name: 'list', handler: async () => success([]) });
|
|
724
|
+
* ```
|
|
725
|
+
*/
|
|
726
|
+
debug(observer) {
|
|
727
|
+
// No frozen check — debug is safe to attach after build
|
|
728
|
+
this._debug = observer;
|
|
729
|
+
return this;
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Enable out-of-band telemetry emission for Inspector TUI.
|
|
733
|
+
*
|
|
734
|
+
* When set, `validate`, `middleware`, `presenter.slice`, and
|
|
735
|
+
* `presenter.rules` events are emitted to the TelemetrySink
|
|
736
|
+
* (Shadow Socket IPC), enabling real-time monitoring in the
|
|
737
|
+
* Inspector dashboard.
|
|
738
|
+
*
|
|
739
|
+
* **Zero overhead** when not configured — no conditionals in
|
|
740
|
+
* the hot path.
|
|
741
|
+
*
|
|
742
|
+
* @param sink - A {@link TelemetrySink} from `startServer()` or `TelemetryBus`
|
|
743
|
+
* @returns `this` for chaining
|
|
744
|
+
*/
|
|
745
|
+
telemetry(sink) {
|
|
746
|
+
this._telemetry = sink;
|
|
747
|
+
return this;
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Enable OpenTelemetry-compatible tracing for this tool.
|
|
751
|
+
*
|
|
752
|
+
* When enabled, each `execute()` call creates a single span with
|
|
753
|
+
* structured events for each pipeline step (`mcp.route`, `mcp.validate`,
|
|
754
|
+
* `mcp.middleware`, `mcp.execute`).
|
|
755
|
+
*
|
|
756
|
+
* **Zero overhead** when disabled — the fast path has no conditionals.
|
|
757
|
+
*
|
|
758
|
+
* **OTel direct pass-through**: The `VurbTracer` interface is a
|
|
759
|
+
* structural subtype of OTel's `Tracer`, so you can pass an OTel
|
|
760
|
+
* tracer directly without any adapter:
|
|
761
|
+
*
|
|
762
|
+
* ```typescript
|
|
763
|
+
* import { trace } from '@opentelemetry/api';
|
|
764
|
+
*
|
|
765
|
+
* const tool = createTool<AppContext>('projects')
|
|
766
|
+
* .tracing(trace.getTracer('vurb'))
|
|
767
|
+
* .action({ name: 'list', handler: listProjects });
|
|
768
|
+
* ```
|
|
769
|
+
*
|
|
770
|
+
* **Error classification**:
|
|
771
|
+
* - Validation failures → `SpanStatusCode.UNSET` + `mcp.error_type` attribute
|
|
772
|
+
* - Handler exceptions → `SpanStatusCode.ERROR` + `recordException()`
|
|
773
|
+
*
|
|
774
|
+
* **Context propagation limitation**: Since Vurb does not depend
|
|
775
|
+
* on `@opentelemetry/api`, it cannot call `context.with(trace.setSpan(...))`.
|
|
776
|
+
* Auto-instrumented downstream calls (Prisma, HTTP, Redis) inside handlers
|
|
777
|
+
* will appear as siblings, not children, of the MCP span.
|
|
778
|
+
*
|
|
779
|
+
* @param tracer - A {@link VurbTracer} (or OTel `Tracer`) instance
|
|
780
|
+
* @returns `this` for chaining
|
|
781
|
+
*
|
|
782
|
+
* @see {@link VurbTracer} for the interface contract
|
|
783
|
+
* @see {@link SpanStatusCode} for status code semantics
|
|
784
|
+
*/
|
|
785
|
+
tracing(tracer) {
|
|
786
|
+
// No frozen check — tracing is safe to attach after build (like debug)
|
|
787
|
+
this._tracer = tracer;
|
|
788
|
+
return this;
|
|
789
|
+
}
|
|
790
|
+
// ── Execute (delegates to ExecutionPipeline) ────────
|
|
791
|
+
/**
|
|
792
|
+
* Route a tool call to the correct action handler.
|
|
793
|
+
*
|
|
794
|
+
* Pipeline: `parseDiscriminator → resolveAction → validateArgs → runChain`
|
|
795
|
+
*
|
|
796
|
+
* Auto-calls {@link buildToolDefinition} if not called yet.
|
|
797
|
+
* If a debug observer is active, structured events are emitted
|
|
798
|
+
* at each pipeline step with timing information.
|
|
799
|
+
*
|
|
800
|
+
* @param ctx - Application context
|
|
801
|
+
* @param args - Raw arguments from the LLM (includes discriminator)
|
|
802
|
+
* @param progressSink - Optional callback for streaming progress notifications.
|
|
803
|
+
* When attached via `attachToServer()`, this is automatically wired to
|
|
804
|
+
* MCP `notifications/progress`. When omitted, progress events are silently consumed.
|
|
805
|
+
* @param signal - Optional AbortSignal from the MCP SDK protocol layer.
|
|
806
|
+
* Fired when the client sends `notifications/cancelled` or the connection drops.
|
|
807
|
+
* The framework checks this signal before handler execution and during
|
|
808
|
+
* generator iteration, aborting zombie operations immediately.
|
|
809
|
+
* @returns The handler's {@link ToolResponse}
|
|
810
|
+
*
|
|
811
|
+
* @example
|
|
812
|
+
* ```typescript
|
|
813
|
+
* // Direct execution (useful in tests)
|
|
814
|
+
* const result = await builder.execute(ctx, {
|
|
815
|
+
* action: 'list',
|
|
816
|
+
* workspace_id: 'ws_123',
|
|
817
|
+
* });
|
|
818
|
+
* ```
|
|
819
|
+
*/
|
|
820
|
+
async execute(ctx, args, progressSink, signal) {
|
|
821
|
+
if (!this._executionContext) {
|
|
822
|
+
this.buildToolDefinition();
|
|
823
|
+
}
|
|
824
|
+
const execCtx = this._executionContext;
|
|
825
|
+
if (!execCtx) {
|
|
826
|
+
return error(`Builder "${this._name}" failed to initialize.`);
|
|
827
|
+
}
|
|
828
|
+
// ── Concurrency Gate (Semaphore + Queue) ──────────────────
|
|
829
|
+
// Acquire a slot BEFORE entering the pipeline.
|
|
830
|
+
// If acquire() returns null, load shedding kicks in.
|
|
831
|
+
let release;
|
|
832
|
+
if (this._concurrencyGuard) {
|
|
833
|
+
const result = this._concurrencyGuard.acquire(signal);
|
|
834
|
+
if (result === null) {
|
|
835
|
+
// Load shedding: all slots occupied + queue full
|
|
836
|
+
return toolError('SERVER_BUSY', {
|
|
837
|
+
message: `Tool "${this._name}" is at capacity (${this._concurrencyGuard.active} active, ${this._concurrencyGuard.queued} queued). Retry after a short delay.`,
|
|
838
|
+
suggestion: 'Reduce the number of concurrent calls to this tool. Send requests sequentially or in smaller batches.',
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
try {
|
|
842
|
+
release = await result;
|
|
843
|
+
}
|
|
844
|
+
catch {
|
|
845
|
+
// Waiter was cancelled while queued (AbortSignal)
|
|
846
|
+
return error(`[${this._name}] Request cancelled while waiting for execution slot.`);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
try {
|
|
850
|
+
const response = await this._executeWithObservability(execCtx, ctx, args, progressSink, signal);
|
|
851
|
+
// ── Egress Guard (Payload Size Limiter) ──────
|
|
852
|
+
if (this._egressMaxBytes) {
|
|
853
|
+
return applyEgressGuard(response, this._egressMaxBytes);
|
|
854
|
+
}
|
|
855
|
+
return response;
|
|
856
|
+
}
|
|
857
|
+
finally {
|
|
858
|
+
release?.();
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Internal: execute with the appropriate observability path.
|
|
863
|
+
* Extracted to keep the concurrency/egress guards clean.
|
|
864
|
+
*/
|
|
865
|
+
async _executeWithObservability(execCtx, ctx, args, progressSink, signal) {
|
|
866
|
+
// Build telemetry hooks if sink is configured
|
|
867
|
+
const telemetryHooks = this._telemetry ? this._buildTelemetryHooks() : undefined;
|
|
868
|
+
// Traced path: wrap in try/catch for system error → graceful response
|
|
869
|
+
if (this._tracer) {
|
|
870
|
+
const hooks = mergeHooks(this._buildTracedHooks(), telemetryHooks);
|
|
871
|
+
try {
|
|
872
|
+
return await this._executePipeline(execCtx, ctx, args, progressSink, hooks, signal);
|
|
873
|
+
}
|
|
874
|
+
catch (err) {
|
|
875
|
+
// System failure caught here — hooks already recorded it on the span
|
|
876
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
877
|
+
const response = error(`[${this._name}] ${message}`);
|
|
878
|
+
hooks.wrapResponse(response); // finalize span
|
|
879
|
+
return response;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
// Debug path: hooks with event emission
|
|
883
|
+
if (this._debug) {
|
|
884
|
+
return this._executePipeline(execCtx, ctx, args, progressSink, mergeHooks(this._buildDebugHooks(), telemetryHooks), signal);
|
|
885
|
+
}
|
|
886
|
+
// Telemetry-only path: emit events without debug logs
|
|
887
|
+
if (telemetryHooks) {
|
|
888
|
+
return this._executePipeline(execCtx, ctx, args, progressSink, telemetryHooks, signal);
|
|
889
|
+
}
|
|
890
|
+
// Fast path: zero overhead (no hooks)
|
|
891
|
+
return this._executePipeline(execCtx, ctx, args, progressSink, undefined, signal);
|
|
892
|
+
}
|
|
893
|
+
// ── Execution Paths (private) ────────────────────────
|
|
894
|
+
/**
|
|
895
|
+
* Pipeline hooks for observability instrumentation.
|
|
896
|
+
*
|
|
897
|
+
* Each hook is called at the corresponding pipeline step.
|
|
898
|
+
* The fast path passes `undefined` (zero overhead).
|
|
899
|
+
* Debug and traced paths supply their hooks via factory methods.
|
|
900
|
+
*/
|
|
901
|
+
async _executePipeline(execCtx, ctx, args, progressSink, hooks, signal) {
|
|
902
|
+
// Step 1: Route
|
|
903
|
+
const disc = parseDiscriminator(execCtx, args);
|
|
904
|
+
if (!disc.ok) {
|
|
905
|
+
hooks?.onRouteError?.();
|
|
906
|
+
return hooks?.wrapResponse?.(disc.response) ?? disc.response;
|
|
907
|
+
}
|
|
908
|
+
const actionName = disc.value;
|
|
909
|
+
hooks?.onRouteOk?.(actionName);
|
|
910
|
+
// Step 2: Resolve
|
|
911
|
+
const resolved = resolveAction(execCtx, actionName);
|
|
912
|
+
if (!resolved.ok) {
|
|
913
|
+
hooks?.onResolveError?.(actionName);
|
|
914
|
+
return hooks?.wrapResponse?.(resolved.response) ?? resolved.response;
|
|
915
|
+
}
|
|
916
|
+
// Step 3: Validate
|
|
917
|
+
const validateStart = performance.now();
|
|
918
|
+
const validationResult = validateArgs(execCtx, resolved.value, args);
|
|
919
|
+
const validateMs = performance.now() - validateStart;
|
|
920
|
+
if (!validationResult.ok) {
|
|
921
|
+
hooks?.onValidateError?.(actionName, validateMs);
|
|
922
|
+
return hooks?.wrapResponse?.(validationResult.response) ?? validationResult.response;
|
|
923
|
+
}
|
|
924
|
+
hooks?.onValidateOk?.(actionName, validateMs);
|
|
925
|
+
const { validated, selectFields } = validationResult.value;
|
|
926
|
+
// Step 4: Middleware info
|
|
927
|
+
const actionMwCount = resolved.value.action.middlewares?.length ?? 0;
|
|
928
|
+
const globalMwCount = this._middlewares.length;
|
|
929
|
+
const chainLength = globalMwCount + actionMwCount;
|
|
930
|
+
if (chainLength > 0) {
|
|
931
|
+
hooks?.onMiddleware?.(actionName, chainLength);
|
|
932
|
+
}
|
|
933
|
+
// Step 5: Execute
|
|
934
|
+
// If the action is destructive and a MutationSerializer exists,
|
|
935
|
+
// wrap the execution in a per-key mutex to prevent concurrent
|
|
936
|
+
// mutations (LLM hallucination anti-race-condition guard).
|
|
937
|
+
//
|
|
938
|
+
// _select is forwarded only when enableSelect() was called.
|
|
939
|
+
const effectiveSelect = this._selectEnabled ? selectFields : undefined;
|
|
940
|
+
const ppTelemetry = this._telemetry
|
|
941
|
+
? { sink: this._telemetry, tool: execCtx.toolName, action: actionName }
|
|
942
|
+
: undefined;
|
|
943
|
+
const executeChain = () => runChain(execCtx, resolved.value, ctx, validated, progressSink, hooks?.rethrow, signal, effectiveSelect, ppTelemetry);
|
|
944
|
+
try {
|
|
945
|
+
const isDestructive = resolved.value.action.destructive === true;
|
|
946
|
+
const response = (isDestructive && this._mutationSerializer)
|
|
947
|
+
? await this._mutationSerializer.serialize(actionName, executeChain, signal)
|
|
948
|
+
: await executeChain();
|
|
949
|
+
hooks?.onExecuteOk?.(actionName, response);
|
|
950
|
+
return hooks?.wrapResponse?.(response) ?? response;
|
|
951
|
+
}
|
|
952
|
+
catch (err) {
|
|
953
|
+
hooks?.onExecuteError?.(actionName, err);
|
|
954
|
+
if (hooks?.rethrow)
|
|
955
|
+
throw err;
|
|
956
|
+
// Convert MutationSerializer abort (or unexpected throws) to error response
|
|
957
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
958
|
+
const response = error(`[${execCtx.toolName}/${actionName}] ${message}`);
|
|
959
|
+
return hooks?.wrapResponse?.(response) ?? response;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* Build debug hooks: lightweight event emission.
|
|
964
|
+
*/
|
|
965
|
+
_buildDebugHooks() {
|
|
966
|
+
const debug = this._debug;
|
|
967
|
+
const toolName = this._name;
|
|
968
|
+
const startTime = performance.now();
|
|
969
|
+
return {
|
|
970
|
+
onRouteError: () => {
|
|
971
|
+
debug({ type: 'error', tool: toolName, action: '?', error: 'Missing discriminator', step: 'route', timestamp: Date.now() });
|
|
972
|
+
},
|
|
973
|
+
onRouteOk: (action) => {
|
|
974
|
+
debug({ type: 'route', tool: toolName, action, timestamp: Date.now() });
|
|
975
|
+
},
|
|
976
|
+
onResolveError: (action) => {
|
|
977
|
+
debug({ type: 'error', tool: toolName, action, error: `Unknown action "${action}"`, step: 'route', timestamp: Date.now() });
|
|
978
|
+
},
|
|
979
|
+
onValidateError: (action, durationMs) => {
|
|
980
|
+
debug({ type: 'validate', tool: toolName, action, valid: false, error: 'Validation failed', durationMs, timestamp: Date.now() });
|
|
981
|
+
},
|
|
982
|
+
onValidateOk: (action, durationMs) => {
|
|
983
|
+
debug({ type: 'validate', tool: toolName, action, valid: true, durationMs, timestamp: Date.now() });
|
|
984
|
+
},
|
|
985
|
+
onMiddleware: (action, chainLength) => {
|
|
986
|
+
debug({ type: 'middleware', tool: toolName, action, chainLength, timestamp: Date.now() });
|
|
987
|
+
},
|
|
988
|
+
onExecuteOk: (action, response) => {
|
|
989
|
+
const isErr = response.isError === true;
|
|
990
|
+
debug({ type: 'execute', tool: toolName, action, durationMs: performance.now() - startTime, isError: isErr, timestamp: Date.now() });
|
|
991
|
+
},
|
|
992
|
+
onExecuteError: (action, err) => {
|
|
993
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
994
|
+
debug({ type: 'error', tool: toolName, action, error: message, step: 'execute', timestamp: Date.now() });
|
|
995
|
+
},
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Build traced hooks: OpenTelemetry-compatible span creation.
|
|
1000
|
+
*
|
|
1001
|
+
* Creates ONE span per tool call with events for pipeline steps.
|
|
1002
|
+
* Uses wrapResponse for leak-proof span closure.
|
|
1003
|
+
* AI errors → UNSET, system errors → ERROR.
|
|
1004
|
+
*/
|
|
1005
|
+
_buildTracedHooks() {
|
|
1006
|
+
const tracer = this._tracer;
|
|
1007
|
+
const startAttrs = {
|
|
1008
|
+
'mcp.system': 'vurb',
|
|
1009
|
+
'mcp.tool': this._name,
|
|
1010
|
+
};
|
|
1011
|
+
if (this._tags.length > 0)
|
|
1012
|
+
startAttrs['mcp.tags'] = this._tags;
|
|
1013
|
+
if (this._description)
|
|
1014
|
+
startAttrs['mcp.description'] = this._description;
|
|
1015
|
+
const span = tracer.startSpan(`mcp.tool.${this._name}`, { attributes: startAttrs });
|
|
1016
|
+
const startTime = performance.now();
|
|
1017
|
+
let statusCode = SpanStatusCode.UNSET;
|
|
1018
|
+
let statusMessage;
|
|
1019
|
+
const finalizeSpan = (response) => {
|
|
1020
|
+
span.setAttribute('mcp.durationMs', performance.now() - startTime);
|
|
1021
|
+
if (response) {
|
|
1022
|
+
span.setAttribute('mcp.response_size', computeResponseSize(response));
|
|
1023
|
+
}
|
|
1024
|
+
span.setStatus(statusMessage !== undefined
|
|
1025
|
+
? { code: statusCode, message: statusMessage }
|
|
1026
|
+
: { code: statusCode });
|
|
1027
|
+
span.end();
|
|
1028
|
+
};
|
|
1029
|
+
return {
|
|
1030
|
+
rethrow: true,
|
|
1031
|
+
onRouteError: () => {
|
|
1032
|
+
span.setAttribute('mcp.error_type', 'missing_discriminator');
|
|
1033
|
+
span.setAttribute('mcp.isError', true);
|
|
1034
|
+
},
|
|
1035
|
+
onRouteOk: (action) => {
|
|
1036
|
+
span.setAttribute('mcp.action', action);
|
|
1037
|
+
span.addEvent?.('mcp.route');
|
|
1038
|
+
},
|
|
1039
|
+
onResolveError: () => {
|
|
1040
|
+
span.setAttribute('mcp.error_type', 'unknown_action');
|
|
1041
|
+
span.setAttribute('mcp.isError', true);
|
|
1042
|
+
},
|
|
1043
|
+
onValidateError: (_action, durationMs) => {
|
|
1044
|
+
span.setAttribute('mcp.error_type', 'validation_failed');
|
|
1045
|
+
span.setAttribute('mcp.isError', true);
|
|
1046
|
+
span.addEvent?.('mcp.validate', { 'mcp.valid': false, 'mcp.durationMs': durationMs });
|
|
1047
|
+
},
|
|
1048
|
+
onValidateOk: (_action, durationMs) => {
|
|
1049
|
+
span.addEvent?.('mcp.validate', { 'mcp.valid': true, 'mcp.durationMs': durationMs });
|
|
1050
|
+
},
|
|
1051
|
+
onMiddleware: (_action, chainLength) => {
|
|
1052
|
+
span.addEvent?.('mcp.middleware', { 'mcp.chainLength': chainLength });
|
|
1053
|
+
},
|
|
1054
|
+
onExecuteOk: (_action, response) => {
|
|
1055
|
+
const isErr = response.isError === true;
|
|
1056
|
+
statusCode = isErr ? SpanStatusCode.UNSET : SpanStatusCode.OK;
|
|
1057
|
+
if (isErr)
|
|
1058
|
+
span.setAttribute('mcp.error_type', 'handler_returned_error');
|
|
1059
|
+
span.setAttribute('mcp.isError', isErr);
|
|
1060
|
+
},
|
|
1061
|
+
onExecuteError: (_action, err) => {
|
|
1062
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1063
|
+
span.recordException(err instanceof Error ? err : message);
|
|
1064
|
+
span.setAttribute('mcp.error_type', 'system_error');
|
|
1065
|
+
span.setAttribute('mcp.isError', true);
|
|
1066
|
+
statusCode = SpanStatusCode.ERROR;
|
|
1067
|
+
statusMessage = message;
|
|
1068
|
+
},
|
|
1069
|
+
wrapResponse: (response) => {
|
|
1070
|
+
finalizeSpan(response);
|
|
1071
|
+
return response;
|
|
1072
|
+
},
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
/**
|
|
1076
|
+
* Build telemetry hooks: Shadow Socket event emission for Inspector TUI.
|
|
1077
|
+
*
|
|
1078
|
+
* Emits `validate`, `middleware`, and `execute` TelemetryEvents
|
|
1079
|
+
* to the IPC sink so that `vurb inspect` shows real pipeline data.
|
|
1080
|
+
*/
|
|
1081
|
+
_buildTelemetryHooks() {
|
|
1082
|
+
const emit = this._telemetry;
|
|
1083
|
+
const toolName = this._name;
|
|
1084
|
+
const startTime = performance.now();
|
|
1085
|
+
return {
|
|
1086
|
+
onValidateError: (action, durationMs) => {
|
|
1087
|
+
emit({ type: 'validate', tool: toolName, action, valid: false, error: 'Validation failed', durationMs, timestamp: Date.now() });
|
|
1088
|
+
},
|
|
1089
|
+
onValidateOk: (action, durationMs) => {
|
|
1090
|
+
emit({ type: 'validate', tool: toolName, action, valid: true, durationMs, timestamp: Date.now() });
|
|
1091
|
+
},
|
|
1092
|
+
onMiddleware: (action, chainLength) => {
|
|
1093
|
+
emit({ type: 'middleware', tool: toolName, action, chainLength, timestamp: Date.now() });
|
|
1094
|
+
},
|
|
1095
|
+
onExecuteOk: (action, response) => {
|
|
1096
|
+
const isErr = response.isError === true;
|
|
1097
|
+
// Extract recovery data from error responses
|
|
1098
|
+
let recovery;
|
|
1099
|
+
let recoveryActions;
|
|
1100
|
+
if (isErr && response.content.length > 0) {
|
|
1101
|
+
const text = response.content[0].text;
|
|
1102
|
+
recovery = extractXmlTag(text, 'recovery');
|
|
1103
|
+
recoveryActions = extractXmlActions(text);
|
|
1104
|
+
}
|
|
1105
|
+
emit({
|
|
1106
|
+
type: 'execute', tool: toolName, action,
|
|
1107
|
+
durationMs: performance.now() - startTime,
|
|
1108
|
+
isError: isErr,
|
|
1109
|
+
...(recovery ? { recovery } : {}),
|
|
1110
|
+
...(recoveryActions && recoveryActions.length > 0 ? { recoveryActions } : {}),
|
|
1111
|
+
timestamp: Date.now(),
|
|
1112
|
+
});
|
|
1113
|
+
},
|
|
1114
|
+
onExecuteError: (action, err) => {
|
|
1115
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1116
|
+
emit({ type: 'error', tool: toolName, action, error: message, step: 'execute', timestamp: Date.now() });
|
|
1117
|
+
},
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
// ── Introspection ───────────────────────────────────
|
|
1121
|
+
/** Get the tool name. */
|
|
1122
|
+
getName() { return this._name; }
|
|
1123
|
+
/** Get a copy of the capability tags. */
|
|
1124
|
+
getTags() { return [...this._tags]; }
|
|
1125
|
+
/** Get all registered action keys (e.g. `["list", "create"]` or `["users.list", "users.ban"]`). */
|
|
1126
|
+
getActionNames() { return this._actions.map(a => a.key); }
|
|
1127
|
+
// ── AST Reflection (Exposition Compiler) ─────────────
|
|
1128
|
+
/** Get the discriminator field name (e.g. `"action"`). Used by the Exposition Compiler. */
|
|
1129
|
+
getDiscriminator() { return this._discriminator; }
|
|
1130
|
+
/**
|
|
1131
|
+
* Get all registered internal actions.
|
|
1132
|
+
* Used by the Exposition Compiler for atomic tool expansion.
|
|
1133
|
+
* @returns Read-only array of internal action definitions
|
|
1134
|
+
*/
|
|
1135
|
+
getActions() { return this._actions; }
|
|
1136
|
+
/**
|
|
1137
|
+
* Get the common schema shared across all actions.
|
|
1138
|
+
* Used by the Exposition Compiler for schema purification.
|
|
1139
|
+
* @returns The common Zod schema, or undefined if not set
|
|
1140
|
+
*/
|
|
1141
|
+
getCommonSchema() { return this._commonSchema; }
|
|
1142
|
+
/** Check if `_select` reflection is enabled. Used by the Exposition Compiler. */
|
|
1143
|
+
getSelectEnabled() { return this._selectEnabled; }
|
|
1144
|
+
/** Get per-action state sync hints for auto-policy generation. */
|
|
1145
|
+
getStateSyncHints() { return this._stateSyncHints; }
|
|
1146
|
+
/**
|
|
1147
|
+
* Preview the exact MCP protocol payload that the LLM will receive.
|
|
1148
|
+
*
|
|
1149
|
+
* Builds the tool definition if not already built, then renders
|
|
1150
|
+
* a human-readable preview of the complete tool including:
|
|
1151
|
+
* - Tool name and description
|
|
1152
|
+
* - Input schema (JSON)
|
|
1153
|
+
* - Annotations (if any)
|
|
1154
|
+
* - Approximate token count (~4 chars per token, GPT-5.2 heuristic)
|
|
1155
|
+
*
|
|
1156
|
+
* Call this from your dev environment to optimize token usage
|
|
1157
|
+
* and verify the LLM-facing prompt without starting an MCP server.
|
|
1158
|
+
*
|
|
1159
|
+
* @returns Formatted string showing the exact MCP payload + token estimate
|
|
1160
|
+
*
|
|
1161
|
+
* @example
|
|
1162
|
+
* ```typescript
|
|
1163
|
+
* const projects = defineTool<AppContext>('projects', { ... });
|
|
1164
|
+
* console.log(projects.previewPrompt());
|
|
1165
|
+
*
|
|
1166
|
+
* // Output:
|
|
1167
|
+
* // ┌─────────────────────────────────────────┐
|
|
1168
|
+
* // │ MCP Tool Preview: projects │
|
|
1169
|
+
* // ├─────────────────────────────────────────┤
|
|
1170
|
+
* // │ Name: projects │
|
|
1171
|
+
* // │ Actions: 3 (list, create, delete) │
|
|
1172
|
+
* // │ Tags: api, admin │
|
|
1173
|
+
* // ├─── Description ─────────────────────────┤
|
|
1174
|
+
* // │ Manage workspace projects. ... │
|
|
1175
|
+
* // ├─── Input Schema ────────────────────────┤
|
|
1176
|
+
* // │ { "type": "object", ... } │
|
|
1177
|
+
* // ├─── Annotations ─────────────────────────┤
|
|
1178
|
+
* // │ readOnlyHint: false │
|
|
1179
|
+
* // │ destructiveHint: true │
|
|
1180
|
+
* // ├─── Token Estimate ──────────────────────┤
|
|
1181
|
+
* // │ ~342 tokens (1,368 chars) │
|
|
1182
|
+
* // └─────────────────────────────────────────┘
|
|
1183
|
+
* ```
|
|
1184
|
+
*
|
|
1185
|
+
* @see {@link buildToolDefinition} for the raw MCP Tool object
|
|
1186
|
+
*/
|
|
1187
|
+
previewPrompt() {
|
|
1188
|
+
const tool = this.buildToolDefinition();
|
|
1189
|
+
const schemaJson = JSON.stringify(tool.inputSchema, null, 2);
|
|
1190
|
+
const annotations = tool.annotations;
|
|
1191
|
+
const annotationsJson = annotations
|
|
1192
|
+
? JSON.stringify(annotations, null, 2)
|
|
1193
|
+
: undefined;
|
|
1194
|
+
// Calculate total char payload (what the MCP protocol transmits)
|
|
1195
|
+
const payloadParts = [
|
|
1196
|
+
tool.name,
|
|
1197
|
+
tool.description ?? '',
|
|
1198
|
+
schemaJson,
|
|
1199
|
+
annotationsJson ?? '',
|
|
1200
|
+
];
|
|
1201
|
+
const totalChars = payloadParts.reduce((sum, part) => sum + part.length, 0);
|
|
1202
|
+
// GPT-5.2 heuristic: ~4 characters per token for English/code
|
|
1203
|
+
const estimatedTokens = Math.ceil(totalChars / 4);
|
|
1204
|
+
const W = 56;
|
|
1205
|
+
const divider = '─'.repeat(W);
|
|
1206
|
+
const line = (label, value) => `│ ${label}: ${value}`;
|
|
1207
|
+
const actionKeys = this._actions.map(a => a.key);
|
|
1208
|
+
const lines = [
|
|
1209
|
+
`┌${'─'.repeat(W)}┐`,
|
|
1210
|
+
`│ MCP Tool Preview: ${this._name}`,
|
|
1211
|
+
`├─── Summary ${'─'.repeat(W - 12)}┤`,
|
|
1212
|
+
line('Name', tool.name),
|
|
1213
|
+
line('Actions', `${actionKeys.length} (${actionKeys.join(', ')})`),
|
|
1214
|
+
];
|
|
1215
|
+
if (this._tags.length > 0) {
|
|
1216
|
+
lines.push(line('Tags', this._tags.join(', ')));
|
|
1217
|
+
}
|
|
1218
|
+
lines.push(`├─── Description ${divider.slice(17)}┤`, `│ ${tool.description ?? '(none)'}`.split('\n').join('\n│ '), `├─── Input Schema ${divider.slice(18)}┤`, schemaJson.split('\n').map(l => `│ ${l}`).join('\n'));
|
|
1219
|
+
if (annotationsJson) {
|
|
1220
|
+
lines.push(`├─── Annotations ${divider.slice(17)}┤`, annotationsJson.split('\n').map(l => `│ ${l}`).join('\n'));
|
|
1221
|
+
}
|
|
1222
|
+
lines.push(`├─── Token Estimate ${divider.slice(20)}┤`, `│ ~${estimatedTokens} tokens (${totalChars.toLocaleString()} chars)`, `└${divider}┘`);
|
|
1223
|
+
return lines.join('\n');
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Get metadata for all registered actions.
|
|
1227
|
+
*
|
|
1228
|
+
* Useful for programmatic documentation, compliance audits,
|
|
1229
|
+
* dashboard generation, or runtime observability.
|
|
1230
|
+
*
|
|
1231
|
+
* @returns Array of {@link ActionMetadata} objects
|
|
1232
|
+
*
|
|
1233
|
+
* @example
|
|
1234
|
+
* ```typescript
|
|
1235
|
+
* const meta = builder.getActionMetadata();
|
|
1236
|
+
* for (const action of meta) {
|
|
1237
|
+
* console.log(`${action.key}: destructive=${action.destructive}, fields=${action.requiredFields}`);
|
|
1238
|
+
* }
|
|
1239
|
+
* ```
|
|
1240
|
+
*
|
|
1241
|
+
* @see {@link ActionMetadata} for the metadata shape
|
|
1242
|
+
*/
|
|
1243
|
+
getActionMetadata() {
|
|
1244
|
+
return this._actions.map(a => {
|
|
1245
|
+
const presenter = a.returns;
|
|
1246
|
+
return {
|
|
1247
|
+
key: a.key,
|
|
1248
|
+
actionName: a.actionName,
|
|
1249
|
+
groupName: a.groupName,
|
|
1250
|
+
description: a.description,
|
|
1251
|
+
destructive: a.destructive ?? false,
|
|
1252
|
+
idempotent: a.idempotent ?? false,
|
|
1253
|
+
readOnly: a.readOnly ?? false,
|
|
1254
|
+
requiredFields: getActionRequiredFields(a),
|
|
1255
|
+
hasMiddleware: (a.middlewares?.length ?? 0) > 0,
|
|
1256
|
+
// Presenter metadata (introspection)
|
|
1257
|
+
presenterName: presenter?.name,
|
|
1258
|
+
presenterSchemaKeys: presenter?.getSchemaKeys(),
|
|
1259
|
+
presenterUiBlockTypes: presenter?.getUiBlockTypes(),
|
|
1260
|
+
presenterHasContextualRules: presenter?.hasContextualRules(),
|
|
1261
|
+
presenterStaticRules: presenter?.getStaticRuleStrings(),
|
|
1262
|
+
};
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
// ── Private ─────────────────────────────────────────
|
|
1266
|
+
_assertNotFrozen() {
|
|
1267
|
+
if (this._frozen) {
|
|
1268
|
+
throw new Error(`Builder "${this._name}" is frozen after buildToolDefinition(). ` +
|
|
1269
|
+
`Cannot modify a built tool.`);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
// ── XML Extraction Helpers (Telemetry) ───────────────────
|
|
1274
|
+
/**
|
|
1275
|
+
* Extract content from a simple XML tag.
|
|
1276
|
+
* @example extractXmlTag('<recovery>Fix X</recovery>', 'recovery') → 'Fix X'
|
|
1277
|
+
* @internal
|
|
1278
|
+
*/
|
|
1279
|
+
function extractXmlTag(text, tag) {
|
|
1280
|
+
const re = new RegExp(`<${tag}>(.*?)</${tag}>`, 's');
|
|
1281
|
+
const m = re.exec(text);
|
|
1282
|
+
return m?.[1]?.trim() || undefined;
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Extract `<action>` elements from `<available_actions>` block.
|
|
1286
|
+
* @internal
|
|
1287
|
+
*/
|
|
1288
|
+
function extractXmlActions(text) {
|
|
1289
|
+
const block = extractXmlTag(text, 'available_actions');
|
|
1290
|
+
if (!block)
|
|
1291
|
+
return undefined;
|
|
1292
|
+
const actions = [];
|
|
1293
|
+
const re = /<action>(.*?)<\/action>/gs;
|
|
1294
|
+
let m;
|
|
1295
|
+
while ((m = re.exec(block)) !== null) {
|
|
1296
|
+
const v = m[1]?.trim();
|
|
1297
|
+
if (v)
|
|
1298
|
+
actions.push(v);
|
|
1299
|
+
}
|
|
1300
|
+
// If no individual <action> tags, the content might be a comma/space list
|
|
1301
|
+
if (actions.length === 0 && block.trim().length > 0) {
|
|
1302
|
+
actions.push(...block.split(/[,\s]+/).filter(Boolean));
|
|
1303
|
+
}
|
|
1304
|
+
return actions.length > 0 ? actions : undefined;
|
|
1305
|
+
}
|
|
1306
|
+
//# sourceMappingURL=GroupedToolBuilder.js.map
|