mirror of
https://github.com/discourse/discourse-ai.git
synced 2025-02-12 22:44:45 +00:00
This is similar to code interpreter by ChatGPT, except that it uses JavaScript as the execution engine. Safeguards were added to ensure memory is constrained and evaluation times out.
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
|