browser-use-typescript
Version:
A TypeScript-based browser automation framework
199 lines • 8.04 kB
JavaScript
/**
* TypeScript implementation of the Registry service
*/
import { ActionModel, ActionRegistry, } from './types';
import { ActionResult } from "../../agent/types";
/**
* Registry for browser actions
* Manages the registration and execution of browser actions
*/
export class Registry {
registry;
excludeActions;
/**
* Create a new Registry
* @param excludeActions List of action names to exclude from registration
*/
constructor(excludeActions = []) {
this.registry = new ActionRegistry();
this.excludeActions = excludeActions;
}
/**
* Creates a parameter model from a function
* Similar to Pydantic's create_model in Python
* @param func Function to create a model from
* @returns A constructor function for creating parameter objects
*/
/**
* Creates an action model with specified actions to include/exclude
* @param options Options for creating the action model
* @returns An action model constructor
*/
create_action_model(options) {
const { include_actions } = options;
const actions = [];
// Filter actions based on include/exclude lists
for (const name in this.registry.actions) {
if (include_actions && !include_actions.includes(name)) {
continue;
}
actions.push(this.registry.actions[name]);
}
// Create schema and descriptions objects
const schemas = {};
const descriptions = {};
// Populate both objects from the registered actions
actions.forEach(action => {
schemas[action.name] = action.paramModel;
descriptions[action.name] = action.description;
});
// Create ActionModel with both schemas and descriptions
return new ActionModel(schemas, undefined, descriptions);
}
/**
* Register an action with the registry
* @param description Description of the action
* @param paramModel Model for the action parameters
* @returns Decorator function that registers the action
*/
registerAction(name, description, paramModel, func) {
// Register the action with its description and parameter model
const action = {
name,
description,
function: func,
paramModel,
promptDescription: () => `${name}: ${description}`
};
// Assume we have an action registry to store actions
this.registry.actions[name] = action;
}
_replaceSensitiveData(params, sensitiveData) {
if (!params || !sensitiveData) {
return params;
}
const processValue = (value) => {
if (typeof value === 'string') {
// Replace <secret>placeholder</secret> with actual sensitive data
return value.replace(/<secret>(.*?)<\/secret>/g, (_, placeholder) => {
return sensitiveData[placeholder] || placeholder;
});
}
else if (Array.isArray(value)) {
return value.map(processValue);
}
else if (value && typeof value === 'object') {
return this._replaceSensitiveData(value, sensitiveData);
}
return value;
};
const result = { ...params };
for (const key in result) {
result[key] = processValue(result[key]);
}
return result;
}
/**
* Execute an action by name with parameters
* @param actionName Name of the action to execute
* @param params Parameters for the action
* @param context Context for the action
* @param sensitiveData Optional sensitive data to replace in parameters
* @param pageExtractionLlm Optional LLM for page extraction
* @returns Result of the action
*/
async executeAction(actionName, params, context, sensitiveData) {
// Check if action exists
if (!(actionName in this.registry.actions)) {
return new ActionResult({
error: `Action ${actionName} not found in registry`,
success: false
});
}
const action = this.registry.actions[actionName];
try {
// Process sensitive data if provided
const processedParams = sensitiveData ? this._replaceSensitiveData(params, sensitiveData) : params;
// Create a combined object with all parameters
const allParams = { ...processedParams };
// Add context-specific parameters if available
try {
if (context) {
// Instead of inspecting the function arguments directly (which triggers strict mode errors),
// we'll just conditionally add context properties if they exist
if (context.browser)
allParams.browser = context.browser;
if (context.pageExtractionLlm)
allParams.pageExtractionLlm = context.pageExtractionLlm;
if (context.sensitiveData)
allParams.sensitiveData = context.sensitiveData;
if (context.availableFilePaths)
allParams.availableFilePaths = context.availableFilePaths;
}
}
catch (error) {
return new ActionResult({
error: `Error preparing parameters for action ${actionName}: ${error}`,
success: false
});
}
// Call the function with appropriate parameters based on function signature
try {
// Check function parameter count to determine how to pass arguments
if (action.function.length === 1) {
// Function expects just params (where browser will be extracted from context)
return await action.function(allParams);
}
else if (action.function.length === 2) {
// Function expects params and browser as separate arguments
return await action.function(allParams, context.browser);
}
else if (action.function.length === 3) {
// Function expects params, browser, and pageExtractionLlm
return await action.function(allParams, context.browser, context.pageExtractionLlm);
}
else {
console.warn(`Function ${actionName} has unexpected parameter count: ${action.function.length}`);
// Default to passing all possible parameters
return await action.function(allParams, context.browser, context.pageExtractionLlm);
}
}
catch (error) {
console.error(`Error executing action ${actionName}:`, error);
return new ActionResult({
error: `Error executing action ${actionName}: ${error}`,
success: false
});
}
}
catch (error) {
return new ActionResult({
error: `Error executing action ${actionName}: ${error}`,
success: false
});
}
}
/**
* Get a description of all registered actions for the prompt
* @returns Description of all actions
*/
getPromptDescription() {
return this.registry.getPromptDescription();
}
/**
* Get all registered actions
* @returns Map of action names to registered actions
*/
getActions() {
return this.registry.actions;
}
/**
* Check if an action is registered
* @param actionName Name of the action to check
* @returns True if the action is registered
*/
hasAction(actionName) {
return actionName in this.registry.actions;
}
}
//# sourceMappingURL=service.js.map