-
Notifications
You must be signed in to change notification settings - Fork 610
fix(go): defer template rendering in LoadPrompt to execution time #3925
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?
fix(go): defer template rendering in LoadPrompt to execution time #3925
Conversation
3b4f001 to
bf10054
Compare
|
Hi @Zereker We are making improvements in the core which are causing merge conflicts with your contribution. Would it be possible if you address the conflicts? |
Previously, LoadPrompt called ToMessages with an empty DataArgument at load time, causing template variables to be replaced with empty values. This meant all subsequent Execute() calls would use prompts with empty template variable values. This change defers template rendering to execution time by using WithMessagesFn. The closure captures the raw template text and compiles/renders it with actual input values when Execute() or Render() is called. The fix properly handles: 1. Template variable substitution with actual input values 2. Multi-role messages (<<<dotprompt:role:XXX>>> markers) 3. History insertion (<<<dotprompt:history>>> markers) Added convertDotpromptMessages helper to convert dotprompt.Message to ai.Message format. Added regression test TestLoadPromptTemplateVariableSubstitution to verify template variables are correctly substituted with different input values on multiple calls. Fixes firebase#3924
bf10054 to
64ef676
Compare
|
Hi @hugoaguirre, I've rebased on the latest main and resolved the conflicts. Ready for review! |
|
Hi @Zereker, I've tried to reproduce the issue with the latest changes in
Genkit code: func PromptFromZereker(ctx context.Context, g *genkit.Genkit) {
prompt := genkit.LoadPrompt(g, "./prompts/greeting.prompt", "greetings")
if prompt == nil {
log.Fatal("empty prompt")
}
resp, err := prompt.Execute(ctx,
ai.WithInput(map[string]any{
"name": "Alice",
"place": "Wonderland",
}))
if err != nil {
log.Fatalf("error executing prompt: %v", err)
}
fmt.Printf("request: %#v\n", resp.Request.Messages[0].Text())
log.Print(resp.Text())
}Output: Could you point me in the right direction to reproduce the issue you are reporting? You can copy paste this sample in |
|
Hi @hugoaguirre, Thanks for testing! I found that the
However, there's an issue with how this syntax is handled in How to ReproduceAdd this test to func TestHandlebarsRoleMarkers(t *testing.T) {
tempDir := t.TempDir()
mockPromptFile := filepath.Join(tempDir, "test.prompt")
content := `---
model: test/chat
---
{{role "system"}}
You are a helpful assistant.
{{role "user"}}
Hello {{name}}, welcome to {{place}}!
`
if err := os.WriteFile(mockPromptFile, []byte(content), 0644); err != nil {
t.Fatal(err)
}
prompt := LoadPrompt(registry.New(), tempDir, "test.prompt", "test")
opts, err := prompt.Render(context.Background(), map[string]any{
"name": "Alice",
"place": "Wonderland",
})
if err != nil {
t.Fatal(err)
}
// Verify messages are correctly separated
if len(opts.Messages) != 2 {
t.Errorf("Expected 2 messages, got %d", len(opts.Messages))
}
if opts.Messages[0].Role != RoleSystem {
t.Errorf("Expected first message to be system role")
}
}Expected: Actual (on main): ComparisonThe existing test
Root CauseIn dpMessages, err := dotprompt.ToMessages(parsedPrompt.Template, &dotprompt.DataArgument{})This renders the template at load time with an empty My FixMy fix defers template rendering to execution time by using
This ensures both template variables ( |
|
Hi @Zereker, |
Summary
LoadPromptwhere variables were replaced with empty values at load timeWithMessagesFnconvertDotpromptMessageshelper functionTestLoadPromptTemplateVariableSubstitutionProblem
When using
LoadPromptto load.promptfiles, the template was rendered at load time with an emptyDataArgument. This caused all template variables (like{{name}},{{topic}}, etc.) to be replaced with empty values immediately.As a result, subsequent calls to
Execute()orRender()with actual input values had no effect - the template was already "baked" with empty values.Example
Solution
Defer template rendering to execution time by using
WithMessagesFn. The closure:<<<dotprompt:role:XXX>>>markers)<<<dotprompt:history>>>markers)Test Plan
TestLoadPromptTemplateVariableSubstitutionregression testTestMultiMessagesRenderPromptstill passes (multi-role support)aipackage tests passFixes #3924