Optimizely.Opal.Tools
0.3.0
Prefix Reserved
dotnet add package Optimizely.Opal.Tools --version 0.3.0
NuGet\Install-Package Optimizely.Opal.Tools -Version 0.3.0
<PackageReference Include="Optimizely.Opal.Tools" Version="0.3.0" />
<PackageVersion Include="Optimizely.Opal.Tools" Version="0.3.0" />
<PackageReference Include="Optimizely.Opal.Tools" />
paket add Optimizely.Opal.Tools --version 0.3.0
#r "nuget: Optimizely.Opal.Tools, 0.3.0"
#:package Optimizely.Opal.Tools@0.3.0
#addin nuget:?package=Optimizely.Opal.Tools&version=0.3.0
#tool nuget:?package=Optimizely.Opal.Tools&version=0.3.0
Opal Tools SDK for C#
This SDK helps you create tool services for the Opal AI Assistant platform using C# and ASP.NET Core.
Installation
You can install the SDK using NuGet:
dotnet add package Optimizely.Opal.Tools
Quick Start
Here's a simple example of how to create a tools service with two tools:
using Microsoft.AspNetCore.Builder;
using Optimizely.Opal.Tools;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
var builder = WebApplication.CreateBuilder(args);
// Add the Opal Tools service
builder.Services.AddOpalToolService();
// Register individual tools
builder.Services.AddOpalTool<GreetingTool>();
builder.Services.AddOpalTool<TodaysDateTool>();
var app = builder.Build();
// Map the Opal Tools endpoints (creates /discovery and tool-specific endpoints)
app.MapOpalTools();
// Start the app
app.Run();
// Tool parameter models
public class GreetingParameters
{
[Required]
[Description("Name of the person to greet")]
public string Name { get; set; } = string.Empty;
[Description("Language for greeting (defaults to random)")]
public string? Language { get; set; }
}
public class DateParameters
{
[Description("Date format (defaults to ISO format)")]
public string Format { get; set; } = "yyyy-MM-dd";
}
// Tool implementations
public class GreetingTool
{
[OpalTool(Name = "greeting")]
[Description("Greets a person in a random language (English, Spanish, or French)")]
public object Greet(GreetingParameters parameters)
{
// Get parameters
var name = parameters.Name;
var language = parameters.Language;
// If language not specified, choose randomly
if (string.IsNullOrEmpty(language))
{
var random = new Random();
var languages = new[] { "english", "spanish", "french" };
language = languages[random.Next(languages.Length)];
}
// Generate greeting based on language
string greeting;
if (language.ToLower() == "spanish")
{
greeting = $"¡Hola, {name}! ¿Cómo estás?";
}
else if (language.ToLower() == "french")
{
greeting = $"Bonjour, {name}! Comment ça va?";
}
else // Default to English
{
greeting = $"Hello, {name}! How are you?";
}
return new
{
greeting,
language
};
}
}
public class TodaysDateTool
{
[OpalTool(Name = "todays-date")]
[Description("Returns today's date in the specified format")]
public object GetDate(DateParameters parameters)
{
// Get parameters
var format = parameters.Format;
// Get today's date
var today = DateTime.Now;
// Format the date
var formattedDate = today.ToString(format);
return new
{
date = formattedDate,
format,
timestamp = ((DateTimeOffset)today).ToUnixTimeSeconds()
};
}
}
Endpoints
When you call app.MapOpalTools()
, the SDK automatically creates the following endpoints:
GET /discovery
- Returns metadata about all registered tools in OpenAPI function formatPOST /tools/{tool-name}
- Executes the specified tool (one endpoint per registered tool)POST /tools/callbacks/{ToolClassName}/{method-name}
- Handles tool callbacks (not listed in discovery)
You can customize the endpoint prefix by passing it to MapOpalTools()
:
app.MapOpalTools("opal");
// Creates: GET /opal/tools/discovery, POST /opal/tools/{tool-name}, and POST /opal/tools/callbacks/{ToolClassName}/{method-name}
Authentication
To create a tool that requires authentication:
public class CalendarTool
{
[OpalTool(Name = "get-calendar")]
[Description("Gets user's calendar events")]
[OpalAuthorization("google", "calendar")]
public object GetCalendar(CalendarParameters parameters, OpalToolContext context)
{
// Use context.AuthorizationData.Provider and context.AuthorizationData.Credentials to authenticate
var authData = context.AuthorizationData;
if (authData != null)
{
// Access the authentication provider and credentials
var provider = authData.Provider;
var credentials = authData.Credentials;
// ...
}
return new
{
events = new[] { "Event 1", "Event 2" }
};
}
}
Tool Request/Response Format
The tool request format follows the Opal Tools Management Service specification:
{
"parameters": {
"name": "John",
"language": "spanish"
},
"auth": {
"provider": "google",
"credentials": {
"token": "access_token_value"
}
},
"environment": {
"execution_mode": "headless"
}
}
The response is the direct JSON serialization of the object returned by your tool method:
{
"greeting": "¡Hola, John! ¿Cómo estás?",
"language": "spanish"
}
API Reference
Models
OpalAuthorizationData
: Authentication data from a requestOpalToolContext
: Context object containing authentication data, environment information, and cancellation token for regular toolsOpalCallbackContext
: Context object containing authentication data, environment information, and cancellation token for tool callbacksToolCallbackResponse
: Structured response object for callbacks with message and optional linkIslandResponse
: Response object for creating interactive UI components
Attributes
[OpalTool(name)]
: Marks a method as an Opal tool[OpalToolCallback]
: Marks a method as an Opal tool callback (doesn't appear in discovery)[OpalAuthorization(provider, scopeBundle, required)]
: Specifies authentication requirements
Extension Methods
AddOpalToolService()
: Extension method to add the tools service to IServiceCollectionAddOpalTool<T>()
: Registers a specific tool class with the service collectionMapOpalTools()
: Maps the discovery and tool endpoints to the application
Best Practices
- Use the
[OpalTool]
attribute on instance methods within tool classes - Use the
[Description]
attribute on tool classes or methods to provide tool descriptions - Define parameter models with clear property descriptions using
[Description]
attributes - Return simple objects that can be serialized to JSON
- Use dependency injection in tool constructors for accessing services
- Handle errors gracefully within your tool methods
- Provide clear descriptions for tools and parameters
- Both synchronous and asynchronous methods are supported (use
async Task<object>
for async operations)
Advanced Usage
Headless Execution
Tools can be executed in different environments. The OpalToolContext
provides an Environment
property that gives information about the execution environment. One common scenario is to check if a tool is being run in a "headless" mode, where no user interaction is possible.
You can check the ExecutionMode
property of the Environment
object to determine if you should return a direct response or an interactive one (like an Island).
public class MyTool
{
[OpalTool(Name = "my-interactive-tool")]
[Description("A tool that can be interactive or headless")]
public object MyInteractiveTool(MyParameters parameters, OpalToolContext context)
{
if (context.Environment?.ExecutionMode == "headless")
{
// Headless mode, return a direct response
return new { message = "This is a headless response." };
}
// Interactive mode, return an island
return new IslandResponse
{
// ... island configuration ...
};
}
}
Tool Naming
Tool names are automatically derived from method names, with underscores converted to hyphens. You can override this with the Name
parameter:
public class MyTool
{
[OpalTool] // Creates tool named "MyMethod"
public object MyMethod(Parameters parameters) { ... }
[OpalTool(Name = "custom-name")] // Creates tool named "custom-name"
public object AnyMethodName(Parameters parameters) { ... }
}
Asynchronous Tools
The SDK supports both synchronous and asynchronous tool methods:
public class AsyncTool
{
[OpalTool(Name = "async-example")]
[Description("An example of an asynchronous tool")]
public async Task<object> AsyncMethod(Parameters parameters)
{
await SomeAsyncOperation();
return new { result = "success" };
}
}
Custom Parameter Validation
You can use standard .NET validation attributes:
public class GreetingParameters
{
[Required]
[StringLength(100)]
public string Name { get; set; } = string.Empty;
[RegularExpression("english|spanish|french", ErrorMessage = "Language must be english, spanish, or french")]
public string? Language { get; set; }
}
Dependency Injection
Tools can use dependency injection by declaring dependencies in their constructors:
public class WeatherTool
{
private readonly IWeatherService _weatherService;
private readonly ILogger<WeatherTool> _logger;
public WeatherTool(IWeatherService weatherService, ILogger<WeatherTool> logger)
{
_weatherService = weatherService;
_logger = logger;
}
[OpalTool(Name = "get-weather")]
[Description("Gets the weather for a location")]
public async Task<object> GetWeather(WeatherParameters parameters)
{
_logger.LogInformation("Getting weather for {Location}", parameters.Location);
var forecast = await _weatherService.GetForecastAsync(parameters.Location);
return new
{
location = parameters.Location,
forecast
};
}
}
Tool Callbacks
Tool callbacks are special methods that handle responses from interaction islands but don't appear in the discovery endpoint. They use a different request format and can return structured responses:
public class WeatherTool
{
[OpalTool(Name = "weather-tool")]
[Description("Get current weather with interactive form")]
public object GetWeather(WeatherParameters parameters)
{
return new IslandResponse
{
Configuration =
{
Fields =
[
new() { Name = "location", Label = "Location", Type = "string", Value = parameters.Location },
],
Actions =
[
new() { Name = "get-weather", Label = "Get Weather", Operation = "create", Endpoint = nameof(ProcessWeatherCallback) }
]
}
};
}
[OpalToolCallback]
public ToolCallbackResponse ProcessWeatherCallback(WeatherCallbackData data, OpalCallbackContext context)
{
// Process the callback with data from the interaction island
return new ToolCallbackResponse
{
Message = $"The weather in {data.Location} is 22°C",
Link = $"https://weather.example.com/location/{Uri.EscapeDataString(data.Location)}"
};
}
}
public class WeatherCallbackData
{
public string Location { get; set; } = string.Empty;
}
Callback Request Format: Callbacks receive requests in a different format than regular tools:
{
"data": {
"location": "New York"
},
"auth": {
"provider": "google",
"credentials": {
"token": "access_token_value"
}
},
"environment": {
"execution_mode": "headless"
}
}
Callback Response Options: Callbacks can return either:
- A simple string message
- A
ToolCallbackResponse
object with structured data:
{
"message": "The weather in New York is 22°C",
"link": "https://weather.example.com/location/New York"
}
Key characteristics of callbacks:
- Use the
[OpalToolCallback]
attribute instead of[OpalTool]
- Don't appear in the discovery endpoint
- Are accessible at
/tools/callbacks/{ToolClassName}/{MethodName}
- Receive data in
{ "data": {...}, "auth": {...}, "environment": {...} }
format - Can return
ToolCallbackResponse
for structured feedback
License
MIT License
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.