@optimizely-opal/opal-tool-ocp-sdk 0.0.0-beta.1
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 +576 -0
- package/dist/decorator/Decorator.d.ts +46 -0
- package/dist/decorator/Decorator.d.ts.map +1 -0
- package/dist/decorator/Decorator.js +31 -0
- package/dist/decorator/Decorator.js.map +1 -0
- package/dist/decorator/Decorator.test.d.ts +2 -0
- package/dist/decorator/Decorator.test.d.ts.map +1 -0
- package/dist/decorator/Decorator.test.js +418 -0
- package/dist/decorator/Decorator.test.js.map +1 -0
- package/dist/function/ToolFunction.d.ts +15 -0
- package/dist/function/ToolFunction.d.ts.map +1 -0
- package/dist/function/ToolFunction.js +25 -0
- package/dist/function/ToolFunction.js.map +1 -0
- package/dist/function/ToolFunction.test.d.ts +2 -0
- package/dist/function/ToolFunction.test.d.ts.map +1 -0
- package/dist/function/ToolFunction.test.js +189 -0
- package/dist/function/ToolFunction.test.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/service/Service.d.ts +78 -0
- package/dist/service/Service.d.ts.map +1 -0
- package/dist/service/Service.js +204 -0
- package/dist/service/Service.js.map +1 -0
- package/dist/service/Service.test.d.ts +2 -0
- package/dist/service/Service.test.d.ts.map +1 -0
- package/dist/service/Service.test.js +341 -0
- package/dist/service/Service.test.js.map +1 -0
- package/dist/types/Models.d.ts +126 -0
- package/dist/types/Models.d.ts.map +1 -0
- package/dist/types/Models.js +181 -0
- package/dist/types/Models.js.map +1 -0
- package/package.json +58 -0
- package/src/decorator/Decorator.test.ts +523 -0
- package/src/decorator/Decorator.ts +83 -0
- package/src/function/ToolFunction.test.ts +224 -0
- package/src/function/ToolFunction.ts +25 -0
- package/src/index.ts +4 -0
- package/src/service/Service.test.ts +550 -0
- package/src/service/Service.ts +182 -0
- package/src/types/Models.ts +163 -0
package/README.md
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
# OPAL TOOL OCP SDK
|
|
2
|
+
|
|
3
|
+
> **Optimizely Connect Platform (OCP) SDK for OPAL Tool**
|
|
4
|
+
|
|
5
|
+
A TypeScript SDK for building Opal tools in Optimizely Connect Platform. This SDK provides decorators, abstractions, and utilities to simplify the development.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- ๐ฏ **Decorator-based Tool Registration** - Use `@tool` and `@interaction` decorators to easily register functions
|
|
10
|
+
- ๐ง **Type-safe Development** - Full TypeScript support with comprehensive type definitions
|
|
11
|
+
- ๐๏ธ **Abstract Base Classes** - Extend `ToolFunction` for standardized request processing
|
|
12
|
+
- ๐ **Authentication Support** - OptiID authentication
|
|
13
|
+
- ๐ก๏ธ **Authorization Support** - Bearer token tool authorization
|
|
14
|
+
- ๐ **Parameter Validation** - Define and validate tool parameters with types
|
|
15
|
+
- ๐งช **Comprehensive Testing** - Fully tested with Jest
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @optimizely-opal/opal-tool-ocp-sdk
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
or
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
yarn add @optimizely-opal/opal-tool-ocp-sdk
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
Create a tool function class by extending `ToolFunction` and registering your tools and interactions:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { ToolFunction, tool, interaction, ParameterType, InteractionResult, OptiIdAuthData } from '@optimizely-opal/opal-tool-ocp-sdk';
|
|
35
|
+
|
|
36
|
+
export class MyToolFunction extends ToolFunction {
|
|
37
|
+
// Implement required bearer token validation method
|
|
38
|
+
validateBearerToken(token: string): boolean {
|
|
39
|
+
const expectedToken = process.env.OPAL_TOOL_TOKEN;
|
|
40
|
+
return token === expectedToken;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Register a simple tool without authentication
|
|
44
|
+
@tool({
|
|
45
|
+
name: 'create_task',
|
|
46
|
+
description: 'Creates a new task in the system',
|
|
47
|
+
endpoint: '/create-task',
|
|
48
|
+
parameters: [
|
|
49
|
+
{
|
|
50
|
+
name: 'title',
|
|
51
|
+
type: ParameterType.String,
|
|
52
|
+
description: 'The task title',
|
|
53
|
+
required: true
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'priority',
|
|
57
|
+
type: ParameterType.String,
|
|
58
|
+
description: 'Task priority level',
|
|
59
|
+
required: false
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
})
|
|
63
|
+
async createTask(params: { title: string; priority?: string }, authData?: OptiIdAuthData) {
|
|
64
|
+
return {
|
|
65
|
+
id: '123',
|
|
66
|
+
title: params.title,
|
|
67
|
+
priority: params.priority || 'medium'
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Register a tool with OptiID authentication
|
|
72
|
+
@tool({
|
|
73
|
+
name: 'secure_task',
|
|
74
|
+
description: 'Creates a secure task with OptiID authentication',
|
|
75
|
+
endpoint: '/secure-task',
|
|
76
|
+
parameters: [
|
|
77
|
+
{
|
|
78
|
+
name: 'title',
|
|
79
|
+
type: ParameterType.String,
|
|
80
|
+
description: 'The task title',
|
|
81
|
+
required: true
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
authRequirements: [
|
|
85
|
+
{
|
|
86
|
+
provider: 'OptiID',
|
|
87
|
+
scopeBundle: 'tasks',
|
|
88
|
+
required: true
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
})
|
|
92
|
+
async createSecureTask(params: { title: string }, authData?: OptiIdAuthData) {
|
|
93
|
+
if (!authData) {
|
|
94
|
+
throw new Error('OptiID authentication required');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const { customerId, instanceId, accessToken } = authData.credentials;
|
|
98
|
+
return {
|
|
99
|
+
id: '456',
|
|
100
|
+
title: params.title,
|
|
101
|
+
customerId,
|
|
102
|
+
instanceId
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Register an interaction
|
|
107
|
+
@interaction({
|
|
108
|
+
name: 'task_webhook',
|
|
109
|
+
endpoint: '/webhook/task'
|
|
110
|
+
})
|
|
111
|
+
async handleTaskWebhook(data: any): Promise<InteractionResult> {
|
|
112
|
+
return new InteractionResult(
|
|
113
|
+
`Task ${data.taskId} was updated`,
|
|
114
|
+
`https://app.example.com/tasks/${data.taskId}`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Your function class inherits a `perform()` method from `ToolFunction` that serves as the main entry point for handling all incoming requests. When called, the SDK automatically:
|
|
121
|
+
|
|
122
|
+
- **Routes requests** to your registered tools and interactions based on endpoints
|
|
123
|
+
- **Handles authentication** and bearer token validation before calling your methods
|
|
124
|
+
- **Provides discovery** at `/discovery` endpoint for OCP platform integration
|
|
125
|
+
- **Returns proper HTTP responses** with correct status codes and JSON formatting
|
|
126
|
+
|
|
127
|
+
## Core Concepts
|
|
128
|
+
|
|
129
|
+
### Tools
|
|
130
|
+
|
|
131
|
+
Tools are functions that can be discovered and executed through the OCP platform. They:
|
|
132
|
+
|
|
133
|
+
- Have a name, description, and endpoint
|
|
134
|
+
- Define parameters with types and validation
|
|
135
|
+
- Can require authentication
|
|
136
|
+
- Return structured responses
|
|
137
|
+
|
|
138
|
+
### Interactions
|
|
139
|
+
|
|
140
|
+
Interactions are event handlers that process incoming data (like webhooks):
|
|
141
|
+
|
|
142
|
+
- Have a name and endpoint
|
|
143
|
+
- Process unstructured data
|
|
144
|
+
- Return interaction results with messages and optional links
|
|
145
|
+
|
|
146
|
+
### Parameters
|
|
147
|
+
|
|
148
|
+
Supported parameter types:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
enum ParameterType {
|
|
152
|
+
String = 'string',
|
|
153
|
+
Integer = 'integer',
|
|
154
|
+
Number = 'number',
|
|
155
|
+
Boolean = 'boolean',
|
|
156
|
+
List = 'list',
|
|
157
|
+
Dictionary = 'object'
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Authentication
|
|
162
|
+
|
|
163
|
+
The SDK supports authentication and authorization mechanisms:
|
|
164
|
+
|
|
165
|
+
#### OptiID Authentication
|
|
166
|
+
|
|
167
|
+
OptiID provides user authentication with type safety. This is the only user authentication provider currently supported in Opal:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
interface AuthRequirementConfig {
|
|
171
|
+
provider: string; // 'OptiID'
|
|
172
|
+
scopeBundle: string; // e.g., 'calendar', 'tasks'
|
|
173
|
+
required?: boolean; // default: true
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### Bearer Token Support
|
|
178
|
+
|
|
179
|
+
The SDK automatically extracts Bearer tokens from the `authorization` header for tool authorization. When users register tools in Opal, they can specify a Bearer token that Opal will include in requests to validate the tool's identity.
|
|
180
|
+
|
|
181
|
+
**Token Validation:**
|
|
182
|
+
- Bearer tokens are extracted from the `authorization: Bearer <token>` header
|
|
183
|
+
- Empty strings and `undefined` tokens are treated as missing (no validation performed)
|
|
184
|
+
- Implement the abstract `validateBearerToken(token: string): boolean` method to define your validation logic
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
export class MyToolFunction extends ToolFunction {
|
|
188
|
+
// Implement the required bearer token validation method
|
|
189
|
+
validateBearerToken(token: string): boolean {
|
|
190
|
+
// If you don't need bearer token validation, simply return true
|
|
191
|
+
// return true;
|
|
192
|
+
|
|
193
|
+
// For actual validation, compare against expected token
|
|
194
|
+
const expectedToken = process.env.OPAL_TOOL_TOKEN;
|
|
195
|
+
return token === expectedToken;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@tool({
|
|
199
|
+
name: 'secure_tool',
|
|
200
|
+
description: 'Tool that validates requests from Opal',
|
|
201
|
+
endpoint: '/secure-endpoint',
|
|
202
|
+
parameters: [
|
|
203
|
+
{ name: 'data', type: ParameterType.String, description: 'Data to process', required: true }
|
|
204
|
+
]
|
|
205
|
+
})
|
|
206
|
+
async secureToolHandler(
|
|
207
|
+
params: { data: string },
|
|
208
|
+
authData?: OptiIdAuthData
|
|
209
|
+
) {
|
|
210
|
+
|
|
211
|
+
// Process the request knowing it's from a trusted Opal instance
|
|
212
|
+
return {
|
|
213
|
+
status: 'success',
|
|
214
|
+
data: `Processed: ${params.data}`,
|
|
215
|
+
authorizedBy: 'Opal'
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Bearer Token Usage:**
|
|
222
|
+
- Set by users when registering tools in Opal
|
|
223
|
+
- Used to authorize tool requests from Opal instances
|
|
224
|
+
- Validates that requests are coming from trusted Opal sources
|
|
225
|
+
- Requires implementing the abstract `validateBearerToken(token: string): boolean` method
|
|
226
|
+
- If validation fails, returns HTTP 403 Forbidden before reaching your handler methods
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
## API Reference
|
|
230
|
+
|
|
231
|
+
### Handler Function Signatures
|
|
232
|
+
|
|
233
|
+
All tool and interaction handler methods follow this signature pattern:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
async handlerMethod(
|
|
237
|
+
params: TParams, // Tool parameters or interaction data
|
|
238
|
+
authData?: OptiIdAuthData // OptiID user authentication data (if authenticated)
|
|
239
|
+
): Promise<TResult>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
- **params**: The input parameters for tools, or interaction data for webhooks
|
|
243
|
+
- **authData**: Available when OptiID user authentication is configured and successful
|
|
244
|
+
|
|
245
|
+
**Note**: Bearer token validation is handled automatically by the base class. If a bearer token is present and fails validation, the request is rejected before reaching your handler methods.
|
|
246
|
+
|
|
247
|
+
### Decorators
|
|
248
|
+
|
|
249
|
+
#### `@tool(config: ToolConfig)`
|
|
250
|
+
|
|
251
|
+
Registers a method as a discoverable tool.
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
interface ToolConfig {
|
|
255
|
+
name: string;
|
|
256
|
+
description: string;
|
|
257
|
+
parameters: ParameterConfig[];
|
|
258
|
+
authRequirements?: AuthRequirementConfig[];
|
|
259
|
+
endpoint: string;
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
#### `@interaction(config: InteractionConfig)`
|
|
264
|
+
|
|
265
|
+
Registers a method as an interaction handler.
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
interface InteractionConfig {
|
|
269
|
+
name: string;
|
|
270
|
+
endpoint: string;
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Base Classes
|
|
275
|
+
|
|
276
|
+
#### `ToolFunction`
|
|
277
|
+
|
|
278
|
+
Abstract base class for OCP functions:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
export abstract class ToolFunction extends Function {
|
|
282
|
+
public async perform(): Promise<Response>;
|
|
283
|
+
protected abstract validateBearerToken(token: string): boolean;
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Extend this class and implement your OCP function. The `perform` method automatically routes requests to registered tools and handles bearer token validation. You must implement the `validateBearerToken` method to define how bearer tokens should be validated for your tools.
|
|
288
|
+
|
|
289
|
+
### Models
|
|
290
|
+
|
|
291
|
+
Key model classes with generic type support:
|
|
292
|
+
|
|
293
|
+
- `Tool<TAuthData>` - Represents a registered tool with typed auth data
|
|
294
|
+
- `Interaction<TAuthData>` - Represents an interaction handler with typed auth data
|
|
295
|
+
- `Parameter` - Defines tool parameters
|
|
296
|
+
- `AuthRequirement` - Defines authentication needs
|
|
297
|
+
- `InteractionResult` - Response from interactions
|
|
298
|
+
- `OptiIdAuthData` - OptiID specific authentication data
|
|
299
|
+
|
|
300
|
+
## Discovery Endpoint
|
|
301
|
+
|
|
302
|
+
The SDK automatically provides a discovery endpoint at `/discovery` that returns all registered tools in the proper OCP format:
|
|
303
|
+
|
|
304
|
+
```json
|
|
305
|
+
{
|
|
306
|
+
"functions": [
|
|
307
|
+
{
|
|
308
|
+
"name": "create_task",
|
|
309
|
+
"description": "Creates a new task in the system",
|
|
310
|
+
"parameters": [
|
|
311
|
+
{
|
|
312
|
+
"name": "title",
|
|
313
|
+
"type": "string",
|
|
314
|
+
"description": "The task title",
|
|
315
|
+
"required": true
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
"name": "priority",
|
|
319
|
+
"type": "string",
|
|
320
|
+
"description": "Task priority level",
|
|
321
|
+
"required": false
|
|
322
|
+
}
|
|
323
|
+
],
|
|
324
|
+
"endpoint": "/create-task",
|
|
325
|
+
"http_method": "POST"
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"name": "secure_task",
|
|
329
|
+
"description": "Creates a secure task with OptiID authentication",
|
|
330
|
+
"parameters": [
|
|
331
|
+
{
|
|
332
|
+
"name": "title",
|
|
333
|
+
"type": "string",
|
|
334
|
+
"description": "The task title",
|
|
335
|
+
"required": true
|
|
336
|
+
}
|
|
337
|
+
],
|
|
338
|
+
"endpoint": "/secure-task",
|
|
339
|
+
"http_method": "POST",
|
|
340
|
+
"auth_requirements": [
|
|
341
|
+
{
|
|
342
|
+
"provider": "OptiID",
|
|
343
|
+
"scope_bundle": "tasks",
|
|
344
|
+
"required": true
|
|
345
|
+
}
|
|
346
|
+
]
|
|
347
|
+
}
|
|
348
|
+
]
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Development
|
|
353
|
+
|
|
354
|
+
### Prerequisites
|
|
355
|
+
|
|
356
|
+
- Node.js >= 22.0.0
|
|
357
|
+
- TypeScript 5.x
|
|
358
|
+
|
|
359
|
+
### Building
|
|
360
|
+
|
|
361
|
+
```bash
|
|
362
|
+
yarn build
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Testing
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
# Run tests
|
|
369
|
+
yarn test
|
|
370
|
+
|
|
371
|
+
# Run tests in watch mode
|
|
372
|
+
yarn test:watch
|
|
373
|
+
|
|
374
|
+
# Run tests with coverage
|
|
375
|
+
yarn test:coverage
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Linting
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
yarn lint
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## Examples
|
|
385
|
+
|
|
386
|
+
### Function with Authentication
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
import { ToolFunction, tool, interaction, ParameterType, OptiIdAuthData, InteractionResult } from '@optimizely-opal/opal-ocp-sdk';
|
|
390
|
+
|
|
391
|
+
export class AuthenticatedFunction extends ToolFunction {
|
|
392
|
+
// Implement required bearer token validation
|
|
393
|
+
validateBearerToken(token: string): boolean {
|
|
394
|
+
// If you don't need bearer token validation, simply return true
|
|
395
|
+
// return true;
|
|
396
|
+
|
|
397
|
+
// For actual validation, compare against expected token
|
|
398
|
+
const expectedToken = process.env.OPAL_TOOL_TOKEN;
|
|
399
|
+
return token === expectedToken;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// OptiID authentication example
|
|
403
|
+
@tool({
|
|
404
|
+
name: 'secure_operation',
|
|
405
|
+
description: 'Performs a secure operation with OptiID',
|
|
406
|
+
endpoint: '/secure',
|
|
407
|
+
parameters: [],
|
|
408
|
+
authRequirements: [{ provider: 'OptiID', scopeBundle: 'tasks', required: true }]
|
|
409
|
+
})
|
|
410
|
+
async secureOperation(params: unknown, authData?: OptiIdAuthData) {
|
|
411
|
+
if (!authData) throw new Error('OptiID authentication required');
|
|
412
|
+
|
|
413
|
+
const { customerId, accessToken } = authData.credentials;
|
|
414
|
+
// Use OptiID credentials for API calls
|
|
415
|
+
return { success: true, customerId };
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Interaction with authentication example
|
|
419
|
+
@interaction({
|
|
420
|
+
name: 'authenticated_webhook',
|
|
421
|
+
endpoint: '/secure-webhook'
|
|
422
|
+
})
|
|
423
|
+
async handleSecureWebhook(data: any, authData?: OptiIdAuthData): Promise<InteractionResult> {
|
|
424
|
+
if (!authData) {
|
|
425
|
+
return new InteractionResult('Authentication required for webhook processing');
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const { customerId } = authData.credentials;
|
|
429
|
+
|
|
430
|
+
// Process webhook data with authentication context
|
|
431
|
+
return new InteractionResult(
|
|
432
|
+
`Webhook processed for customer ${customerId}: ${data.eventType}`,
|
|
433
|
+
`https://app.example.com/events/${data.eventId}`
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Organizing Tools in Separate Files
|
|
440
|
+
|
|
441
|
+
For larger projects, you can organize your tools in separate files and import them into your main ToolFunction class:
|
|
442
|
+
|
|
443
|
+
**Project Structure:**
|
|
444
|
+
```
|
|
445
|
+
src/
|
|
446
|
+
โโโ tools/
|
|
447
|
+
โ โโโ index.ts
|
|
448
|
+
โ โโโ TaskTool.ts
|
|
449
|
+
โ โโโ NotificationTool.ts
|
|
450
|
+
โโโ MyToolFunction.ts
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**tools/TaskTool.ts:**
|
|
454
|
+
```typescript
|
|
455
|
+
import { tool, ParameterType, OptiIdAuthData } from '@optimizely-opal/opal-ocp-sdk';
|
|
456
|
+
|
|
457
|
+
export class TaskTool {
|
|
458
|
+
@tool({
|
|
459
|
+
name: 'create_task',
|
|
460
|
+
description: 'Creates a new task in the system',
|
|
461
|
+
endpoint: '/create-task',
|
|
462
|
+
parameters: [
|
|
463
|
+
{
|
|
464
|
+
name: 'title',
|
|
465
|
+
type: ParameterType.String,
|
|
466
|
+
description: 'The task title',
|
|
467
|
+
required: true
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
name: 'priority',
|
|
471
|
+
type: ParameterType.String,
|
|
472
|
+
description: 'Task priority level',
|
|
473
|
+
required: false
|
|
474
|
+
}
|
|
475
|
+
]
|
|
476
|
+
})
|
|
477
|
+
async createTask(params: { title: string; priority?: string }, authData?: OptiIdAuthData) {
|
|
478
|
+
return {
|
|
479
|
+
id: '123',
|
|
480
|
+
title: params.title,
|
|
481
|
+
priority: params.priority || 'medium'
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
@tool({
|
|
486
|
+
name: 'delete_task',
|
|
487
|
+
description: 'Deletes a task from the system',
|
|
488
|
+
endpoint: '/delete-task',
|
|
489
|
+
parameters: [
|
|
490
|
+
{
|
|
491
|
+
name: 'taskId',
|
|
492
|
+
type: ParameterType.String,
|
|
493
|
+
description: 'The task ID to delete',
|
|
494
|
+
required: true
|
|
495
|
+
}
|
|
496
|
+
]
|
|
497
|
+
})
|
|
498
|
+
async deleteTask(params: { taskId: string }, authData?: OptiIdAuthData) {
|
|
499
|
+
return { success: true, deletedTaskId: params.taskId };
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
**tools/NotificationTool.ts:**
|
|
505
|
+
```typescript
|
|
506
|
+
import { tool, interaction, ParameterType, InteractionResult, OptiIdAuthData } from '@optimizely-opal/opal-ocp-sdk';
|
|
507
|
+
|
|
508
|
+
export class NotificationTool {
|
|
509
|
+
@tool({
|
|
510
|
+
name: 'send_notification',
|
|
511
|
+
description: 'Sends a notification to users',
|
|
512
|
+
endpoint: '/send-notification',
|
|
513
|
+
parameters: [
|
|
514
|
+
{
|
|
515
|
+
name: 'message',
|
|
516
|
+
type: ParameterType.String,
|
|
517
|
+
description: 'The notification message',
|
|
518
|
+
required: true
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
name: 'userId',
|
|
522
|
+
type: ParameterType.String,
|
|
523
|
+
description: 'Target user ID',
|
|
524
|
+
required: true
|
|
525
|
+
}
|
|
526
|
+
]
|
|
527
|
+
})
|
|
528
|
+
async sendNotification(params: { message: string; userId: string }, authData?: OptiIdAuthData) {
|
|
529
|
+
return {
|
|
530
|
+
notificationId: '456',
|
|
531
|
+
message: params.message,
|
|
532
|
+
userId: params.userId,
|
|
533
|
+
sent: true
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
@interaction({
|
|
538
|
+
name: 'notification_webhook',
|
|
539
|
+
endpoint: '/webhook/notification'
|
|
540
|
+
})
|
|
541
|
+
async handleNotificationWebhook(data: any): Promise<InteractionResult> {
|
|
542
|
+
return new InteractionResult(
|
|
543
|
+
`Notification ${data.notificationId} was delivered`,
|
|
544
|
+
`https://app.example.com/notifications/${data.notificationId}`
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
**tools/index.ts:**
|
|
551
|
+
```typescript
|
|
552
|
+
export * from './TaskTool';
|
|
553
|
+
export * from './NotificationTool';
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**MyToolFunction.ts:**
|
|
557
|
+
```typescript
|
|
558
|
+
import { ToolFunction } from '@optimizely-opal/opal-ocp-sdk';
|
|
559
|
+
import * from './tools';
|
|
560
|
+
|
|
561
|
+
export class MyToolFunction extends ToolFunction {
|
|
562
|
+
|
|
563
|
+
// Implement required bearer token validation method
|
|
564
|
+
validateBearerToken(token: string): boolean {
|
|
565
|
+
const expectedToken = process.env.OPAL_TOOL_TOKEN;
|
|
566
|
+
return token === expectedToken;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
This approach provides several benefits:
|
|
572
|
+
- **Better organization**: Each tool has its own file with related methods
|
|
573
|
+
- **Maintainability**: Easier to find and modify specific tools
|
|
574
|
+
- **Reusability**: Tools can be shared across different ToolFunction classes
|
|
575
|
+
- **Team collaboration**: Different developers can work on different tool files
|
|
576
|
+
- **Testing**: Each tool class can be unit tested independently
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ParameterType } from '../types/Models';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for @tool decorator
|
|
4
|
+
*/
|
|
5
|
+
export interface ToolConfig {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
parameters: ParameterConfig[];
|
|
9
|
+
authRequirements?: AuthRequirementConfig[];
|
|
10
|
+
endpoint: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parameter configuration for decorators
|
|
14
|
+
*/
|
|
15
|
+
export interface ParameterConfig {
|
|
16
|
+
name: string;
|
|
17
|
+
type: ParameterType;
|
|
18
|
+
description: string;
|
|
19
|
+
required: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* AuthRequirement configuration for decorators
|
|
23
|
+
*/
|
|
24
|
+
export interface AuthRequirementConfig {
|
|
25
|
+
provider: string;
|
|
26
|
+
scopeBundle: string;
|
|
27
|
+
required?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Configuration for @interaction decorator
|
|
31
|
+
*/
|
|
32
|
+
export interface InteractionConfig {
|
|
33
|
+
name: string;
|
|
34
|
+
endpoint: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Decorator for registering tool functions
|
|
38
|
+
* Immediately registers the tool with the global ToolsService
|
|
39
|
+
*/
|
|
40
|
+
export declare function tool(config: ToolConfig): (_target: any, _propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Decorator for registering interaction functions
|
|
43
|
+
* Immediately registers the interaction with the global ToolsService
|
|
44
|
+
*/
|
|
45
|
+
export declare function interaction(config: InteractionConfig): (_target: any, _propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
46
|
+
//# sourceMappingURL=Decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Decorator.d.ts","sourceRoot":"","sources":["../../src/decorator/Decorator.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAG5E;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,gBAAgB,CAAC,EAAE,qBAAqB,EAAE,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,IACrB,SAAS,GAAG,EAAE,cAAc,MAAM,EAAE,YAAY,kBAAkB,UAqBnF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,IACnC,SAAS,GAAG,EAAE,cAAc,MAAM,EAAE,YAAY,kBAAkB,UAQnF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.tool = tool;
|
|
4
|
+
exports.interaction = interaction;
|
|
5
|
+
const Models_1 = require("../types/Models");
|
|
6
|
+
const Service_1 = require("../service/Service");
|
|
7
|
+
/**
|
|
8
|
+
* Decorator for registering tool functions
|
|
9
|
+
* Immediately registers the tool with the global ToolsService
|
|
10
|
+
*/
|
|
11
|
+
function tool(config) {
|
|
12
|
+
return function (_target, _propertyKey, descriptor) {
|
|
13
|
+
// Convert parameter configs to Parameter instances
|
|
14
|
+
const parameters = (config.parameters || []).map((p) => new Models_1.Parameter(p.name, p.type, p.description, p.required));
|
|
15
|
+
// Convert auth requirement configs to AuthRequirement instances
|
|
16
|
+
const authRequirements = (config.authRequirements || []).map((a) => new Models_1.AuthRequirement(a.provider, a.scopeBundle, a.required));
|
|
17
|
+
// Immediately register with global ToolsService
|
|
18
|
+
Service_1.toolsService.registerTool(config.name, config.description, descriptor.value, parameters, config.endpoint, authRequirements);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Decorator for registering interaction functions
|
|
23
|
+
* Immediately registers the interaction with the global ToolsService
|
|
24
|
+
*/
|
|
25
|
+
function interaction(config) {
|
|
26
|
+
return function (_target, _propertyKey, descriptor) {
|
|
27
|
+
// Immediately register with global ToolsService
|
|
28
|
+
Service_1.toolsService.registerInteraction(config.name, descriptor.value, config.endpoint);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=Decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Decorator.js","sourceRoot":"","sources":["../../src/decorator/Decorator.ts"],"names":[],"mappings":";;AA6CA,oBAsBC;AAMD,kCASC;AAlFD,4CAA4E;AAC5E,gDAAkD;AAwClD;;;GAGG;AACH,SAAgB,IAAI,CAAC,MAAkB;IACrC,OAAO,UAAS,OAAY,EAAE,YAAoB,EAAE,UAA8B;QAChF,mDAAmD;QACnD,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACrD,IAAI,kBAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CACzD,CAAC;QAEF,gEAAgE;QAChE,MAAM,gBAAgB,GAAG,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACjE,IAAI,wBAAe,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAC3D,CAAC;QAEF,gDAAgD;QAChD,sBAAY,CAAC,YAAY,CACvB,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,WAAW,EAClB,UAAU,CAAC,KAAK,EAChB,UAAU,EACV,MAAM,CAAC,QAAQ,EACf,gBAAgB,CACjB,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,MAAyB;IACnD,OAAO,UAAS,OAAY,EAAE,YAAoB,EAAE,UAA8B;QAChF,gDAAgD;QAChD,sBAAY,CAAC,mBAAmB,CAC9B,MAAM,CAAC,IAAI,EACX,UAAU,CAAC,KAAK,EAChB,MAAM,CAAC,QAAQ,CAChB,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Decorator.test.d.ts","sourceRoot":"","sources":["../../src/decorator/Decorator.test.ts"],"names":[],"mappings":""}
|