Skip to main content

Core Concepts & APIs (@optimizely-opal/opal-tools-sdk)

Outline

To access the SDK, please visit: https://www.npmjs.com/package/@optimizely-opal/opal-tools-sdk

This module introduces you to the fundamental building blocks of the Optimizely Opal Tools SDK for JavaScript and TypeScript. We'll explore how to install it, and understand the key features and APIs that simplify the process of creating Opal-compatible tool services.

By the end of this module, you will be able to:

  • Install and set up the JavaScript/TypeScript SDK in your project.
  • Explain the role of the @tool() decorator, parameter types, and middleware in tool creation.
  • Identify how Express integration and authentication helpers simplify tool development.

Installation and Project Setup

Before you can use the SDK, you need to set up your Node.js project and install the package.

Prerequisites:

  • Node.js (LTS version recommended) and npm (Node Package Manager) or Yarn installed.
  • A basic understanding of JavaScript/TypeScript and Node.js project structure.
  • An IDE like VS Code with TypeScript extensions.

Steps to Install:

  • Create a new project directory (if you haven't already):

mkdir my-opal-js-tools
cd my-opal-js-tools

  • Initialize a new Node.js project: This creates a package.json file, which manages your project's metadata and dependencies.

npm init -y
# or if you prefer Yarn:
yarn init -y

  • Install TypeScript (if you're using TypeScript):

npm install --save-dev typescript @types/node @types/express
# or with Yarn:
yarn add --dev typescript @types/node @types/express

  • Initialize TypeScript configuration: This creates a tsconfig.json file, which configures the TypeScript compiler.

npx tsc --init
# or if you prefer Yarn:
yarn tsc --init

You might want to adjust tsconfig.json settings, for example, target to es2020 or esnext, and outDir to dist. Ensure experimentalDecorators and emitDecoratorMetadata are set to true for decorators to work.

  • Install the Optimizely Opal Tools SDK:

npm install @optimizely-opal/opal-tools-sdk express
# or with Yarn:
yarn add @optimizely-opal/opal-tools-sdk express

We also install express here because the SDK provides middleware for it.

The tool() Decorator

The tool() decorator is the cornerstone of defining your Opal tools in JavaScript/TypeScript. It's a special function that you apply to a class or method to tell the Opal SDK that it should be exposed as a callable tool.

  • Purpose: It simplifies the process of registering your tool with the SDK. Instead of manually configuring routes and metadata, the decorator handles the underlying mechanics of creating the tool manifest and setting up the necessary HTTP endpoints (discovery and execution).
  • Usage: You'll typically apply @tool() to a class that contains your tool's logic. The decorator takes a configuration object that defines the tool's name, description, and parameters.

Parameter Types (ParameterType Enum)

When defining your tool's parameters, you need to specify their data types. The SDK provides a ParameterType enum for this purpose, ensuring strong typing and proper validation of inputs from Opal.

  • Available Types:
    • ParameterType.String
    • ParameterType.Number
    • ParameterType.Integer
    • ParameterType.Boolean
    • ParameterType.Array
    • ParameterType.Object
  • Importance: Specifying types allows the SDK to validate incoming data, preventing common errors and ensuring your tool receives data in the expected format. This also helps Opal's AI understand how to use your tool correctly.

Express Middleware Integration

The JavaScript/TypeScript SDK is designed to work seamlessly with Express.js, a popular and minimalist web framework for Node.js. The SDK provides middleware functions that integrate directly into your Express application.

  • Automatic Endpoint Setup: The middleware automatically sets up:
    • The /discovery endpoint: This is the endpoint Opal calls to discover all the tools your service offers. The middleware generates and serves the tool manifest dynamically.
    • Tool execution routes: For each tool you define with @tool(), the middleware creates a corresponding HTTP route (e.g., /tools/your_tool_name) that Opal will call to execute your tool.
  • Benefits: This significantly reduces the boilerplate code you need to write for routing and handling HTTP requests, allowing you to focus on your tool's business logic.

Authentication Helpers

Security is crucial for any tool that interacts with sensitive data or performs critical operations. The SDK provides utilities to assist with managing authentication flows and securing your tool's endpoints.

  • Purpose: These helpers allow you to validate incoming requests from Opal, ensuring that only authorized calls trigger your tools. This often involves checking for specific headers (like Authorization: Bearer <token>) and validating the provided token or credentials.
  • How it works: The SDK provides mechanisms to define authentication requirements in your tool's manifest. When a tool is invoked, the SDK can help you access and validate the authentication data provided by Opal.

Example of a Basic index.ts (or main.ts) for an Opal Tool Service:

import express from 'express';
import { OpalToolsService, tool, ParameterType } from '@optimizely-opal/opal-tools-sdk';

// Define a simple tool using the @tool decorator
@tool({
    name: 'hello_world',
    description: 'A simple tool that returns a greeting.',
    parameters: [
        {
            name: 'name',
            type: ParameterType.String,
            description: 'The name to greet.',
            required: true
        }
    ]
})
class HelloWorldTool {
    async execute(params: { name: string }) {
        return { message: `Hello, ${params.name} from Opal Tool!` };
    }
}

// Initialize Express app
const app = express();
app.use(express.json()); // Middleware to parse JSON request bodies

// Initialize OpalToolsService
const opalToolsService = new OpalToolsService();

// Register your tools. This will set up /discovery and tool execution endpoints.
// You can register individual tools or register all tools from a class/module.
opalToolsService.registerTool(HelloWorldTool); // Register the class directly

// Add the Opal Tools Service middleware to your Express app
app.use(opalToolsService.getExpressMiddleware());

// Basic error handling for Express (optional but recommended)
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
    console.error(err.stack);
    res.status(500).send('Something broke!');
});

// Start the server
const port = process.env.PORT || 3000;
app.listen(port, () => {
    console.log(`Opal Tools Service listening on port ${port}`);
    console.log(`Discovery endpoint: http://localhost:${port}/discovery`);
    console.log(`Try calling the tool: POST http://localhost:${port}/tools/hello_world with JSON body: { "name": "Opal" }`);
});

In the next module, we'll dive deeper into defining tools and their parameters with more practical examples.