Skip to content
This repository was archived by the owner on Nov 26, 2025. It is now read-only.

Latest commit

 

History

History
401 lines (307 loc) · 9.38 KB

File metadata and controls

401 lines (307 loc) · 9.38 KB

Embedded Plugins

Embedded plugins allow you to run Python or JavaScript code directly within the Rohas runtime, without spawning external processes. This provides better performance and tighter integration.

Table of Contents

  1. Overview
  2. Python Embedded Plugins
  3. JavaScript Embedded Plugins
  4. Creating Embedded Plugins
  5. Plugin Manifest
  6. Best Practices

Overview

Embedded plugins are different from subprocess plugins:

  • Subprocess plugins: Spawn external processes (slower, more isolation)
  • Embedded plugins: Run code directly in the runtime (faster, tighter integration)

Embedded plugins use:

  • Python: PyO3 for Python 3.x support
  • JavaScript: QuickJS for JavaScript/ES2020 support

Python Embedded Plugins

Creating a Python Embedded Plugin

Create plugins/my-python-plugin/plugin.toml:

name = "myPythonTool"
type = "embedded"
description = "Python embedded plugin"
version = "1.0.0"
language = "python"
path = "myPythonTool.embedded.py"

Create plugins/my-python-plugin/myPythonTool.embedded.py:

def main(args):
    """
    Main function for the embedded plugin.
    
    Args:
        args: List of arguments passed from Rohas
    
    Returns:
        Result value (will be serialized to JSON)
    """
    if len(args) < 2:
        return {"error": "Need at least 2 arguments"}
    
    operation = args[0]
    values = [float(x) for x in args[1:]]
    
    if operation == "add":
        result = sum(values)
    elif operation == "multiply":
        result = 1
        for x in values:
            result *= x
    else:
        return {"error": "Unknown operation: " + operation}
    
    return {"result": result}

Using Python Embedded Plugins

result = call myPythonTool("add", 10, 20, 30)
# result = {"result": 60}

sum = result.result
prompt "Sum: {sum}"

Python Plugin Example: Calculator

plugins/calculator-tool-embedded/plugin.toml:

name = "calculatorTool"
type = "embedded"
description = "Calculator tool (embedded Python)"
version = "1.0.0"
language = "python"
path = "calculatorTool.embedded.py"

plugins/calculator-tool-embedded/calculatorTool.embedded.py:

def main(args):
    """
    Calculator tool supporting add, multiply, subtract, divide, and power operations.
    
    Usage:
        calculatorTool("add", 10, 20) -> {"result": 30}
        calculatorTool("multiply", 5, 6) -> {"result": 30}
        calculatorTool("power", 2, 8) -> {"result": 256}
    """
    if len(args) < 3:
        return {"error": "Need operation and at least 2 numbers"}
    
    operation = args[0]
    try:
        a = float(args[1])
        b = float(args[2])
    except ValueError:
        return {"error": "Invalid numbers"}
    
    if operation == "add":
        result = a + b
    elif operation == "subtract":
        result = a - b
    elif operation == "multiply":
        result = a * b
    elif operation == "divide":
        if b == 0:
            return {"error": "Division by zero"}
        result = a / b
    elif operation == "power":
        result = a ** b
    else:
        return {"error": f"Unknown operation: {operation}"}
    
    return {"result": result}

Use in Rohas:

result1 = call calculatorTool("add", 10, 20)
result2 = call calculatorTool("multiply", 5, 6)
result3 = call calculatorTool("power", 2, 8)

prompt "Calculations: 10 + 20 = {result1.result}, 5 * 6 = {result2.result}, 2^8 = {result3.result}"

JavaScript Embedded Plugins

Creating a JavaScript Embedded Plugin

Create plugins/my-js-plugin/plugin.toml:

name = "myJSTool"
type = "embedded"
description = "JavaScript embedded plugin"
version = "1.0.0"
language = "javascript"
path = "myJSTool.embedded.js"

Create plugins/my-js-plugin/myJSTool.embedded.js:

function main(args) {
    /**
     * Main function for the embedded plugin.
     * 
     * @param {Array} args - Arguments passed from Rohas
     * @returns {Object} Result value (will be serialized to JSON)
     */
    if (args.length < 2) {
        return { error: "Need at least 2 arguments" };
    }
    
    const operation = args[0];
    const values = args.slice(1).map(x => parseFloat(x));
    
    let result;
    if (operation === "add") {
        result = values.reduce((a, b) => a + b, 0);
    } else if (operation === "multiply") {
        result = values.reduce((a, b) => a * b, 1);
    } else {
        return { error: "Unknown operation: " + operation };
    }
    
    return { result: result };
}

Using JavaScript Embedded Plugins

result = call myJSTool("add", 10, 20, 30)
# result = {"result": 60}

JavaScript Plugin Example: String Processor

plugins/string-processor/plugin.toml:

name = "stringProcessor"
type = "embedded"
description = "String processing tool (embedded JavaScript)"
version = "1.0.0"
language = "javascript"
path = "stringProcessor.embedded.js"

plugins/string-processor/stringProcessor.embedded.js:

function main(args) {
    if (args.length < 2) {
        return { error: "Need operation and string" };
    }
    
    const operation = args[0];
    const str = args[1];
    
    let result;
    switch (operation) {
        case "uppercase":
            result = str.toUpperCase();
            break;
        case "lowercase":
            result = str.toLowerCase();
            break;
        case "reverse":
            result = str.split("").reverse().join("");
            break;
        case "words":
            result = str.split(/\s+/).filter(w => w.length > 0);
            break;
        default:
            return { error: "Unknown operation: " + operation };
    }
    
    return { result: result };
}

Use in Rohas:

text = "Hello World"
upper = call stringProcessor("uppercase", text)
words = call stringProcessor("words", text)

prompt "Uppercase: {upper.result}, Words: {words.result}"

Creating Embedded Plugins

Plugin Structure

plugins/
└── my-embedded-plugin/
    ├── plugin.toml
    └── myTool.embedded.py  (or .js)

Plugin Manifest Format

name = "toolName"              # Name used in call statements
type = "embedded"             # Must be "embedded"
description = "..."           # Description
version = "1.0.0"            # Version
language = "python"           # "python" or "javascript"
path = "tool.embedded.py"     # Path to embedded script

Function Signature

Both Python and JavaScript plugins must define a main function:

Python:

def main(args):
    # args is a list of arguments
    # Return a value (dict, list, string, number, etc.)
    return {"result": "value"}

JavaScript:

function main(args) {
    // args is an array of arguments
    // Return a value (object, array, string, number, etc.)
    return { result: "value" };
}

Return Values

Return values are automatically serialized to JSON and available in Rohas:

# Return a simple value
return "hello"

# Return a record/object
return {"key": "value", "number": 42}

# Return an array
return [1, 2, 3]

# Return nested structures
return {
    "data": [1, 2, 3],
    "meta": {"count": 3}
}

Error Handling

Return error information in the result:

def main(args):
    try:
        result = process(args)
        return {"result": result, "error": None}
    except Exception as e:
        return {"result": None, "error": str(e)}

Or in JavaScript:

function main(args) {
    try {
        const result = process(args);
        return { result: result, error: null };
    } catch (e) {
        return { result: null, error: e.message };
    }
}

Plugin Manifest

The plugin manifest (plugin.toml) must specify:

  • type = "embedded" - Identifies as embedded plugin
  • language = "python" or "javascript" - Specifies the language
  • path - Path to the embedded script file

Example:

name = "myEmbeddedTool"
type = "embedded"
description = "My embedded tool"
version = "1.0.0"
language = "python"
path = "myTool.embedded.py"

Best Practices

  1. Use descriptive function names - Make your main function clear
  2. Validate inputs - Check arguments before processing
  3. Handle errors gracefully - Return error information, don't throw exceptions
  4. Document your functions - Add docstrings/comments
  5. Keep functions pure - Avoid side effects when possible
  6. Return structured data - Use records/objects for complex results
  7. Test independently - Test your plugin code outside Rohas first

Python vs JavaScript

Choose based on your needs:

Python:

  • Better for data processing, scientific computing
  • Rich ecosystem of libraries (if needed)
  • More familiar to many developers

JavaScript:

  • Better for string manipulation, JSON processing
  • Familiar to web developers
  • Lighter weight

Limitations

Embedded plugins have some limitations:

  1. No external libraries - Can't import npm packages or pip packages
  2. Limited standard library - Only core language features available
  3. No file I/O - Can't read/write files directly
  4. No network access - Can't make HTTP requests

For these use cases, use subprocess plugins instead.

Examples

See plugins/calculator-tool-embedded/ for a complete Python embedded plugin example.

See examples/embedded-plugins-example.ro for usage examples.