107 lines
2.3 KiB
Ruby
107 lines
2.3 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
require "mini_racer"
|
||
|
require "json"
|
||
|
|
||
|
module DiscourseAi
|
||
|
module AiBot
|
||
|
module Tools
|
||
|
class JavascriptEvaluator < Tool
|
||
|
TIMEOUT = 500
|
||
|
MAX_MEMORY = 10_000_000
|
||
|
MARSHAL_STACK_DEPTH = 20
|
||
|
|
||
|
def self.signature
|
||
|
{
|
||
|
name: name,
|
||
|
description: "Evaluates JavaScript code using MiniRacer",
|
||
|
parameters: [
|
||
|
{
|
||
|
name: "script",
|
||
|
description: "The JavaScript code to evaluate",
|
||
|
type: "string",
|
||
|
required: true,
|
||
|
},
|
||
|
],
|
||
|
}
|
||
|
end
|
||
|
|
||
|
def self.name
|
||
|
"javascript_evaluator"
|
||
|
end
|
||
|
|
||
|
def script
|
||
|
parameters[:script].to_s
|
||
|
end
|
||
|
|
||
|
def timeout
|
||
|
@timeout || TIMEOUT
|
||
|
end
|
||
|
|
||
|
def timeout=(value)
|
||
|
@timeout = value
|
||
|
end
|
||
|
|
||
|
def max_memory
|
||
|
@max_memory || MAX_MEMORY
|
||
|
end
|
||
|
|
||
|
def max_memory=(value)
|
||
|
@max_memory = value
|
||
|
end
|
||
|
|
||
|
def invoke
|
||
|
context =
|
||
|
MiniRacer::Context.new(
|
||
|
timeout: timeout,
|
||
|
max_memory: MAX_MEMORY,
|
||
|
marshal_stack_depth: MARSHAL_STACK_DEPTH,
|
||
|
)
|
||
|
|
||
|
# works around llms like anthropic loving console.log
|
||
|
eval_script = <<~JS
|
||
|
let console = {};
|
||
|
console.log = function(val) {
|
||
|
return val;
|
||
|
};
|
||
|
|
||
|
#{script}
|
||
|
JS
|
||
|
|
||
|
result = context.eval(eval_script)
|
||
|
|
||
|
# only do special handling and truncating for long strings
|
||
|
if result.to_s.length > 1000
|
||
|
result = truncate(result.to_s, max_length: 10_000, percent_length: 0.3, llm: llm)
|
||
|
end
|
||
|
|
||
|
{ result: result }
|
||
|
rescue MiniRacer::ScriptTerminatedError => e
|
||
|
{ error: "JavaScript execution timed out: #{e.message}" }
|
||
|
rescue MiniRacer::V8OutOfMemoryError => e
|
||
|
{ error: "JavaScript execution exceeded memory limit: #{e.message}" }
|
||
|
rescue MiniRacer::Error => e
|
||
|
{ error: "JavaScript execution error: #{e.message}" }
|
||
|
end
|
||
|
|
||
|
def details
|
||
|
<<~MD
|
||
|
|
||
|
|
||
|
```
|
||
|
#{script}
|
||
|
```
|
||
|
|
||
|
MD
|
||
|
end
|
||
|
|
||
|
private
|
||
|
|
||
|
def description_args
|
||
|
{ script: script }
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|