Extract RubyLLM::Prompt from Agent's private prompt rendering#675
Extract RubyLLM::Prompt from Agent's private prompt rendering#675kryzhovnik wants to merge 3 commits into
Conversation
Moves prompt root resolution, path construction, and ERB rendering into a standalone RubyLLM::Prompt class so prompts can be rendered without subclassing Agent. Closes crmne#667 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #675 +/- ##
==========================================
+ Coverage 87.05% 87.06% +0.01%
==========================================
Files 119 120 +1
Lines 5594 5599 +5
Branches 1407 1406 -1
==========================================
+ Hits 4870 4875 +5
Misses 724 724 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
crmne
left a comment
There was a problem hiding this comment.
I like the extraction here. The thing I would change is the public API shape.
Rather than documenting RubyLLM::Prompt.render(...), I think the public API should be:
RubyLLM.render_prompt("friend", name: "Andrey")
RubyLLM.render_prompt("work_assistant/instructions", user: current_user)That matches the existing RubyLLM style of top-level verbs for common actions: RubyLLM.chat, RubyLLM.embed, RubyLLM.paint, RubyLLM.transcribe, etc. It also keeps RubyLLM::Prompt as an internal implementation object instead of asking users to think in a service class for a one-shot render.
I would avoid RubyLLM.prompt(...) because "prompt" is overloaded in an LLM library. render_prompt is explicit and already matches the Agent naming.
Implementation-wise, that could be as small as adding this to lib/ruby_llm.rb:
module RubyLLM
class << self
def render_prompt(name, **locals)
Prompt.render(name, **locals)
end
end
endThen Agent can delegate through the public entrypoint:
RubyLLM.render_prompt("#{prompt_agent_path}/#{name}", **resolved_locals)One small load-order issue: lib/ruby_llm/prompt.rb should require its own dependencies:
require "erb"
require "pathname"Right now standalone rendering can fail with uninitialized constant RubyLLM::Prompt::ERB if Agent has not already loaded ERB.
Add a top-level RubyLLM.render_prompt(name, **locals) verb alongside chat/embed/paint/transcribe, keeping RubyLLM::Prompt as internal implementation. Agent.render_prompt now delegates through it. Require erb and pathname in prompt.rb so standalone rendering works when Agent has not been loaded; drop the now-unused erb/pathname requires from agent.rb since rendering moved to Prompt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Reworked it as suggested One caveat: a bare |
Moves prompt root resolution, path construction, and ERB rendering into a standalone RubyLLM::Prompt class so prompts can be rendered without subclassing Agent.
Closes #667
What this does
Extracts
RubyLLM::Promptfrom Agent's privateprompt_path_forandprompt_rootmethods. This lets users render prompts following the gem's ownapp/prompts/convention without subclassing Agent:Agent's
render_promptnow delegates toPrompt, preserving its existing class-name scoping and runtime context resolution.Type of change
Scope check
Required for new features
PRs for new features or enhancements without a prior approved issue will be closed.
Quality check
overcommit --installand all hooks passbundle exec rake vcr:record[provider_name]bundle exec rspecmodels.json,aliases.json)AI-generated code
API changes