Class: LittleGhost::PromptResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/little_ghost/prompt_resolver.rb

Overview

PromptResolver renders conventional ERB prompt views. It supports ordered application roots and partials without allowing a template name to escape those roots.

resolver = LittleGhost::PromptResolver.new(paths: ["app/prompts"])
prompt = resolver.render("support/system_prompt", assigns: {product: "Acme"})
prompt.include?("Acme") # => true

In support/system_prompt.erb:

You support <%= @product %> customers.

Earlier invocation roots override configured roots. Template names must be relative, and both lexical traversal and symbolic-link escapes are rejected. Partials use an underscore-prefixed filename, receive only their explicitly supplied locals, and share the parent view's application assigns.

Every configured root is trusted Ruby code because ERB executes inside the current process. Keep roots application-controlled and non-user-writable. See the Prompts as Views guide for Agent system prompts and framework prompt overrides.

Defined Under Namespace

Classes: RenderContext

Constant Summary collapse

DEFAULT_MAX_DEPTH =

:nodoc:

20

Instance Method Summary collapse

Constructor Details

#initialize(paths: [], max_depth: DEFAULT_MAX_DEPTH) ⇒ PromptResolver

Configures ordered application roots and a partial recursion bound, which defaults to 20 nested templates.

Raises:

  • (ArgumentError)


80
81
82
83
84
85
86
87
# File 'lib/little_ghost/prompt_resolver.rb', line 80

def initialize(paths: [], max_depth: DEFAULT_MAX_DEPTH)
  @paths = normalize_roots(paths)
  @max_depth = Integer(max_depth)
  raise ArgumentError, "max_depth must be positive" unless @max_depth.positive?

  @cache = {}.freeze
  @cache_mutex = Mutex.new
end

Instance Method Details

#render(name, locals: {}, assigns: {}, invocation_paths: []) ⇒ Object

Renders the ERB template named by name and returns its String output. Keys in locals become local variables. Keys in assigns become instance variables and remain available in partials. A partial receives ordinary locals only when its caller passes them explicitly.

Local and assign names must begin with a lowercase letter or underscore and contain only letters, numbers, and underscores. Assign names beginning with _little_ghost_ are reserved for rendering internals.

invocation_paths accepts only TrustedPath values because those roots take precedence over application configuration. The wrapper records the directory selected by application code; it does not inspect who can modify that directory.



102
103
104
105
# File 'lib/little_ghost/prompt_resolver.rb', line 102

def render(name, locals: {}, assigns: {}, invocation_paths: [])
  roots = normalize_invocation_roots(invocation_paths) + @paths
  render_template(normalize_name(name), locals, assigns, roots, [])
end