@optimizely-opal/opal-tools-sdk
v0.1.6-dev
Published
SDK for creating Opal-compatible tools services
Readme
Opal Tools SDK for TypeScript
This SDK simplifies the creation of tools services compatible with the Opal Tools Management Service.
Features
- Modern
registerToolAPI with Zod schemas for type-safe tool definitions - Legacy
@tooldecorator API for backwards compatibility - Automatic type inference with Zod (registerTool only)
- Adaptive Block Document support for rich interactive UIs
- Runtime validation with Zod (registerTool only)
- Automatic discovery endpoint generation
- Authentication helpers
- Express integration
Installation
npm install @optimizely-opal/opal-tools-sdk express zodQuick Start
registerTool
import express from "express";
import { z } from "zod";
import { ToolsService, registerTool } from "@optimizely-opal/opal-tools-sdk";
const app = express();
const toolsService = new ToolsService(app);
// ✨ Types are automatically inferred from the inputSchema!
const getWeather = registerTool(
"get_weather",
{
description: "Gets current weather for a location",
inputSchema: {
location: z.string().describe("City name or location"),
units: z
.enum(["metric", "imperial"])
.optional()
.describe("Temperature units"),
},
},
async (params) => {
// params.location is typed as string
// params.units is typed as 'metric' | 'imperial' | undefined
return { temperature: 22, condition: "sunny" };
},
);
app.listen(3000);Legacy @tool Decorator API
import { ToolsService, tool, ParameterType } from '@optimizely-opal/opal-tools-sdk';
interface WeatherParameters {
location: string;
units?: string;
}
@tool({
name: 'get_weather',
description: 'Gets current weather for a location',
parameters: [
{
name: 'location',
type: ParameterType.String,
description: 'City name or location',
required: true,
},
{
name: 'units',
type: ParameterType.String,
description: 'Temperature units',
required: false,
},
],
})
async function getWeather(parameters: WeatherParameters) {
// Implementation...
return { temperature: 22, condition: 'sunny' };
}
// Discovery endpoint is automatically created at /discoveryAuthentication
Both APIs support authentication. The second parameter of your handler receives the extra context object containing auth data.
With registerTool
import { z } from "zod";
const getCalendarEvents = registerTool(
"get_calendar_events",
{
description: "Gets calendar events for a date",
inputSchema: {
date: z.string().describe("Date in YYYY-MM-DD format"),
},
authRequirements: {
provider: "google",
scopeBundle: "calendar",
required: true,
},
},
async (params, extra) => {
// Access auth data from extra context
const token = extra?.auth?.credentials?.access_token;
// Check execution mode if needed
const mode = extra?.mode; // 'headless' | 'interactive'
// Use token to make authenticated requests
return { events: ["Meeting at 10:00", "Lunch at 12:00"] };
},
);With @tool Decorator
@tool({
name: 'get_calendar_events',
description: 'Gets calendar events',
parameters: [
{
name: 'date',
type: ParameterType.String,
description: 'Date in YYYY-MM-DD format',
required: true,
},
],
authRequirements: {
provider: 'google',
scopeBundle: 'calendar',
required: true,
},
})
async function getCalendarEvents(params: any, environment?: any) {
const token = environment?.auth?.credentials?.access_token;
return { events: [] };
}Adaptive Block Documents
Adaptive Block Documents enable rich, interactive UI responses with forms, buttons, and dynamic content.
Creating Adaptive Block Responses
import { z } from "zod";
import { registerTool, Block } from "@optimizely-opal/opal-tools-sdk";
const createTask = registerTool(
"create_task",
{
description: "Create a new task",
type: "block", // Specify this is an Adaptive Block tool
inputSchema: {
title: z.string().describe("Task title"),
description: z.string().optional().describe("Task description"),
},
},
async (params) => {
// Return a BlockResponse (plain object with content/data/artifact/etc)
return {
content: Block.Document({
children: [
Block.Heading({ children: "Task Created!", level: "1" }),
Block.Text({ children: `Created: ${params.title}` }),
Block.Input({
name: "notes",
placeholder: "Add notes...",
value: params.description || "",
}),
],
actions: [
Block.Action({ name: "save", children: "Save Changes" }),
Block.Action({
name: "delete",
children: "Delete",
variant: "danger",
}),
],
}),
data: { task_id: "123", created_at: new Date().toISOString() },
artifact: {
type: "task",
id: "task-123",
data: { title: params.title },
},
};
},
);Adaptive Block Components
The SDK provides a type-safe Block namespace with factory functions for all components:
Block.Document()- Root container with children and actionsBlock.Heading()- Headings with levels 1-6Block.Text()- Text contentBlock.Input()- Text input fieldsBlock.Textarea()- Multi-line text areasBlock.Checkbox()- Checkbox inputsBlock.Select()- Dropdown selectsBlock.Button()- Action buttonsBlock.Action()- Document-level actionsBlock.List()- Ordered/unordered listsBlock.Table()- Data tables- And more...
See the generated src/block.ts for the complete list and TypeScript types.
Regenerating Adaptive Block Types
The Adaptive Block types are auto-generated from the JSON schema. To regenerate:
npm run generate:blockThis reads block-document-spec.json and generates TypeScript interfaces and factory functions in src/block.ts.
Note: Don't edit src/block.ts manually - it will be overwritten on regeneration.
Type Definitions
The SDK provides comprehensive TypeScript type definitions:
Authentication Types
AuthData- Provider and credentials informationCredentials- Access tokens and org detailsEnvironment- Execution context with auth data
Parameter Types
ParameterType- Enum for parameter types (String, Number, Boolean, List, Dictionary)Parameter- Tool parameter definitionsFunction- Complete tool function definitions
Block Types
All Block Document components have full TypeScript interfaces with type checking and IDE autocomplete.
API Reference
registerTool<TSchema, TReturn>(name, options, handler)
Modern API for defining tools with Zod schemas.
Parameters:
name: string- Tool name (required)options: ToolOptions- Configuration objectdescription: string- Tool description (required)inputSchema: Record<string, z.ZodTypeAny>- Zod schema for parameters (required)type?: 'json' | 'block'- Response type (default: 'json')authRequirements?- Authentication requirements
handler: (params, extra?) => Result- Tool implementationparams- Validated input parameters (typed from schema)extra?- Optional extra contextmode: 'headless' | 'interactive'- Execution modeauth?: { provider, credentials }- Auth data if provided
Returns: The handler function with full type inference
@tool(options)
Legacy decorator for defining tools.
Options:
name: string- Tool namedescription: string- Tool descriptionparameters: ParameterDefinition[]- Parameter definitionsauthRequirements?- Authentication requirements
ToolsService
Express service that manages tool registration and creates discovery endpoints.
const toolsService = new ToolsService(app);
// Automatically creates /discovery endpointLicense
MIT
