-
Notifications
You must be signed in to change notification settings - Fork 94
Fetch assistant prompt configuration from Langfuse #177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,8 +6,11 @@ def config_for(chat) | |
| preferred_currency = Money::Currency.new(chat.user.family.currency) | ||
| preferred_date_format = chat.user.family.date_format | ||
|
|
||
| instructions_config = default_instructions(preferred_currency, preferred_date_format) | ||
|
|
||
| { | ||
| instructions: default_instructions(preferred_currency, preferred_date_format), | ||
| instructions: instructions_config[:content], | ||
| instructions_prompt: instructions_config[:prompt], | ||
| functions: default_functions | ||
| } | ||
| end | ||
|
|
@@ -23,6 +26,104 @@ def default_functions | |
| end | ||
|
|
||
| def default_instructions(preferred_currency, preferred_date_format) | ||
| langfuse_instructions = langfuse_default_instructions(preferred_currency, preferred_date_format) | ||
|
|
||
| if langfuse_instructions.present? | ||
| { | ||
| content: langfuse_instructions[:content], | ||
| prompt: langfuse_instructions | ||
| } | ||
| else | ||
| { | ||
| content: fallback_default_instructions(preferred_currency, preferred_date_format), | ||
| prompt: nil | ||
| } | ||
| end | ||
| end | ||
|
|
||
| def langfuse_default_instructions(preferred_currency, preferred_date_format) | ||
| return unless langfuse_client | ||
|
|
||
| prompt = langfuse_client.get_prompt("default_instructions") | ||
| return if prompt.nil? | ||
|
|
||
| # TODO: remove after we make the code resilient to chat vs. text types of prompts | ||
| Rails.logger.warn("Langfuse prompt retrieved: #{prompt.name} #{prompt.version}") | ||
| Rails.logger.warn("Langfuse prompt retrieved: #{prompt.prompt}") | ||
|
|
||
| compiled_prompt = compile_langfuse_prompt( | ||
| prompt.prompt.dig(0, "content"), | ||
| preferred_currency: preferred_currency, | ||
| preferred_date_format: preferred_date_format | ||
| ) | ||
|
|
||
| content = extract_prompt_content(compiled_prompt) | ||
| return if content.blank? | ||
|
|
||
| { | ||
| id: prompt.respond_to?(:id) ? prompt.id : (prompt[:id] rescue nil), | ||
| name: prompt.name, | ||
| version: prompt.version, | ||
| template: prompt.prompt, | ||
| content: content | ||
| } | ||
| rescue => e | ||
| Rails.logger.warn("Langfuse prompt retrieval failed: #{e.message}") | ||
| nil | ||
| end | ||
|
|
||
| def compile_langfuse_prompt(prompt, preferred_currency:, preferred_date_format:) | ||
| variables = { | ||
| preferred_currency_symbol: preferred_currency&.symbol, | ||
| preferred_currency_iso_code: preferred_currency&.iso_code, | ||
| preferred_currency_default_precision: preferred_currency&.default_precision, | ||
| preferred_currency_default_format: preferred_currency&.default_format, | ||
| preferred_currency_separator: preferred_currency&.separator, | ||
| preferred_currency_delimiter: preferred_currency&.delimiter, | ||
| preferred_date_format: preferred_date_format, | ||
| current_date: Date.current | ||
| }.transform_values { |value| value.nil? ? "" : value.to_s } | ||
|
|
||
| # If the prompt object supports compilation, use it. Otherwise, perform | ||
| # a lightweight local interpolation for String/Array/Hash templates. | ||
| if prompt.respond_to?(:compile) | ||
| prompt.compile(**variables) | ||
| else | ||
| interpolate_template(prompt, variables) | ||
| end | ||
| end | ||
|
|
||
| def interpolate_template(template, variables) | ||
| case template | ||
| when String | ||
| # Replace {{ variable }} placeholders with provided variables | ||
| template.gsub(/\{\{\s*(\w+)\s*\}\}/) do | ||
| key = Regexp.last_match(1).to_sym | ||
| variables[key] || "" | ||
| end | ||
| when Array | ||
| template.map { |item| interpolate_template(item, variables) } | ||
| when Hash | ||
| template.transform_values { |v| interpolate_template(v, variables) } | ||
| else | ||
| template | ||
| end | ||
| end | ||
|
|
||
| def extract_prompt_content(compiled_prompt) | ||
| case compiled_prompt | ||
| when String | ||
| compiled_prompt | ||
| when Array | ||
| compiled_prompt.filter_map do |message| | ||
| message[:content] || message["content"] | ||
| end.join("\n\n") | ||
| else | ||
| nil | ||
| end | ||
| end | ||
|
|
||
| def fallback_default_instructions(preferred_currency, preferred_date_format) | ||
| <<~PROMPT | ||
| ## Your identity | ||
|
|
||
|
|
@@ -78,5 +179,14 @@ def default_instructions(preferred_currency, preferred_date_format) | |
| the data you're presenting represents and what context it is in (i.e. date range, account, etc.) | ||
| PROMPT | ||
| end | ||
|
|
||
| def langfuse_client | ||
| return unless ENV["LANGFUSE_PUBLIC_KEY"].present? && ENV["LANGFUSE_SECRET_KEY"].present? | ||
|
|
||
| @langfuse_client ||= Langfuse.new | ||
| rescue => e | ||
| Rails.logger.warn("Langfuse client initialization failed: #{e.message}") | ||
| nil | ||
| end | ||
|
Comment on lines
+183
to
+190
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Extract duplicated This method is nearly identical to Create a new concern at module LangfuseClientConcern
extend ActiveSupport::Concern
class_methods do
def langfuse_client
return unless ENV["LANGFUSE_PUBLIC_KEY"].present? && ENV["LANGFUSE_SECRET_KEY"].present?
@langfuse_client ||= Langfuse.new
rescue => e
Rails.logger.warn("Langfuse client initialization failed: #{e.message}")
nil
end
end
endThen include it in both module Assistant::Configurable
extend ActiveSupport::Concern
+ include LangfuseClientConcern
class_methods do
# ...
-
- def langfuse_client
- return unless ENV["LANGFUSE_PUBLIC_KEY"].present? && ENV["LANGFUSE_SECRET_KEY"].present?
-
- @langfuse_client ||= Langfuse.new
- rescue => e
- Rails.logger.warn("Langfuse client initialization failed: #{e.message}")
- nil
- end
end
endAs per coding guidelines. 🤖 Prompt for AI Agents |
||
| end | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validate prompt structure before accessing nested content.
Line 55 assumes
prompt.promptis an array with a hash at index 0 containing a"content"key. If the Langfuse prompt structure differs, this will silently returnnilor raise an error.Consider adding validation:
📝 Committable suggestion
🤖 Prompt for AI Agents