Class: LittleGhost::CodeMode::JavascriptEngine
- Defined in:
- lib/little_ghost/code_mode/javascript_engine.rb
Overview
Runs model-written JavaScript in an isolated V8 context.
This optional engine uses MiniRacer. Requiring LittleGhost does not load MiniRacer; applications opt in by requiring little_ghost/code_mode/javascript_engine.
Constant Summary collapse
- DEFAULT_LIMITS =
Resource and concurrency limits applied when the application does not override them.
{ output_bytes: 64 * 1024 * 1024, memory_bytes: 128 * 1024 * 1024, cpu_seconds: 30, file_bytes: 1024 * 1024, wall_seconds: 3_600, max_concurrency: 8 }.freeze
Instance Method Summary collapse
-
#instructions(catalog:) ⇒ Object
Builds JavaScript usage instructions and TypeScript declarations for
catalog. -
#language ⇒ Object
Returns the
:javascriptlanguage identifier. -
#open_session(broker:, sandbox_factory:, limits: {}) ⇒ Object
Opens a JavaScript Session with engine defaults merged with
limits.
Instance Method Details
#instructions(catalog:) ⇒ Object
Builds JavaScript usage instructions and TypeScript declarations for
catalog.
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/little_ghost/code_mode/javascript_engine.rb', line 53 def instructions(catalog:) javascript_catalog = Javascript::Catalog.new(catalog) <<~INSTRUCTIONS.strip Use JavaScript to call the available tools and compose their results. Program lifecycle: - Every exec call starts a fresh program in a new V8 context. - Exec and wait observe it for up to one minute. They return sooner when it finishes. - If exec or wait returns `still_working`, call wait to observe the same running program again. - Wait does not pause, resume, or restart the program. - Use stop when the result is no longer needed. - Do not call wait or stop after `completed`, `error`, or `terminated`. Tool calls: - Tool functions return Promises. Use await or Promise.all. - JSON results become objects or arrays. Other results remain strings. - Unawaited tool calls finish before the program exits. - `ALL_TOOLS` contains the complete runtime catalog. Output and completion: - Use `text(value)` for user-visible output. - Use `exit()` to complete early. The V8 context has no Node.js APIs, filesystem, network, console, WebAssembly, or process API. Available tool methods: #{javascript_catalog.declarations} INSTRUCTIONS end |
#language ⇒ Object
Returns the :javascript language identifier.
49 |
# File 'lib/little_ghost/code_mode/javascript_engine.rb', line 49 def language = :javascript |
#open_session(broker:, sandbox_factory:, limits: {}) ⇒ Object
Opens a JavaScript Session with engine defaults merged with limits.
Unsupported limit keys raise ArgumentError.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/little_ghost/code_mode/javascript_engine.rb', line 86 def open_session(broker:, sandbox_factory:, limits: {}) configured_limits = normalize_limits(limits, defaults: DEFAULT_LIMITS) root = Dir.mktmpdir("little-ghost-javascript-") runtime_paths = javascript_runtime_paths workspace = Workspace.new( root:, paths: runtime_paths, teardown: lambda do |workspace:, **| FileUtils.remove_entry_secure(workspace.root) if File.exist?(workspace.root) end ).open sandbox = sandbox_factory.call( workspace:, required_runtime_paths: runtime_paths.keys.to_h { |name| [name, :read_only] } ) sandbox.open client = Javascript::Client.new(session_factory: lambda { sandbox.start_program( host_command, cwd: ".", environment: child_environment, output_bytes: configured_limits.fetch(:output_bytes), memory_bytes: configured_limits[:memory_bytes], cpu_seconds: configured_limits[:cpu_seconds], file_bytes: configured_limits[:file_bytes], allow_subprocesses: allow_subprocesses_for(sandbox) ) }) Javascript::Session.new( broker:, client:, sandbox:, workspace:, max_concurrency: configured_limits.fetch(:max_concurrency), wall_seconds: configured_limits.fetch(:wall_seconds) ) rescue sandbox&.close workspace&.close FileUtils.remove_entry_secure(root) if root && File.exist?(root) raise end |