Render captured prompt templates without reloading sources
This commit is contained in:
@@ -333,3 +333,15 @@ func (state *loaded) GetPromptDefinition(ctx context.Context, id, version string
|
||||
definition, _, err := state.GetPromptSnapshot(ctx, id, version)
|
||||
return definition, err
|
||||
}
|
||||
|
||||
// GetCompiledTemplates returns construction-time parses for one exact prompt.
|
||||
func (state *loaded) GetCompiledTemplates(id, version string) (prompt.CompiledTemplates, bool) {
|
||||
if state == nil {
|
||||
return prompt.CompiledTemplates{}, false
|
||||
}
|
||||
entry := state.prompts[id][version]
|
||||
if entry == nil {
|
||||
return prompt.CompiledTemplates{}, false
|
||||
}
|
||||
return prompt.CompiledTemplates{Session: entry.session, Messages: entry.messages}, true
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ func New(cfg Config, options Options) (*Engine, error) {
|
||||
reader = artifact.NewCompositeReader()
|
||||
}
|
||||
|
||||
return &Engine{runner: usecase.NewRunnerWithRepairer(snapshot, snapshot, snapshot, reader, prompt.NewGoRenderer(), client, validator, usecase.NewDefaultOutputRepairer(client), manager, defaultRetries)}, nil
|
||||
return &Engine{runner: usecase.NewRunnerWithRepairer(snapshot, snapshot, snapshot, reader, prompt.NewCompiledRenderer(snapshot), client, validator, usecase.NewDefaultOutputRepairer(client), manager, defaultRetries)}, nil
|
||||
}
|
||||
|
||||
func validateSourceFS(fsys fs.FS, root string) error {
|
||||
|
||||
@@ -21,12 +21,20 @@ var (
|
||||
|
||||
const artifactTextChunkSize = 64 * 1024
|
||||
|
||||
type goRenderer struct{}
|
||||
type goRenderer struct {
|
||||
templates TemplateLookup
|
||||
}
|
||||
|
||||
func NewGoRenderer() Renderer {
|
||||
return &goRenderer{}
|
||||
}
|
||||
|
||||
// NewCompiledRenderer renders definitions using templates captured with the
|
||||
// configuration snapshot. Per-call clones bind request-specific input helpers.
|
||||
func NewCompiledRenderer(templates TemplateLookup) Renderer {
|
||||
return &goRenderer{templates: templates}
|
||||
}
|
||||
|
||||
func (r *goRenderer) Render(ctx context.Context, definition *domain.PromptDefinition, inputs map[string]*domain.Artifact, vars map[string]string) (*domain.RenderedPrompt, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
@@ -49,11 +57,30 @@ func (r *goRenderer) Render(ctx context.Context, definition *domain.PromptDefini
|
||||
funcs := template.FuncMap{
|
||||
"input": resolver.resolve,
|
||||
}
|
||||
var compiled CompiledTemplates
|
||||
if r.templates != nil {
|
||||
var found bool
|
||||
compiled, found = r.templates.GetCompiledTemplates(definition.ID, definition.Version)
|
||||
if !found || len(compiled.Messages) != len(definition.Templates) {
|
||||
return nil, fmt.Errorf("%w: captured templates are unavailable", ErrRenderFailure)
|
||||
}
|
||||
}
|
||||
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sessionID, err := renderSessionID(ctx, definition.SessionID, funcs, vars)
|
||||
var sessionID string
|
||||
var err error
|
||||
if r.templates != nil {
|
||||
if definition.SessionID != "" {
|
||||
if compiled.Session == nil {
|
||||
return nil, fmt.Errorf("%w: captured session template is unavailable", ErrRenderFailure)
|
||||
}
|
||||
sessionID, err = renderCompiledSessionID(ctx, compiled.Session, funcs, vars)
|
||||
}
|
||||
} else {
|
||||
sessionID, err = renderSessionID(ctx, definition.SessionID, funcs, vars)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -76,7 +103,19 @@ func (r *goRenderer) Render(ctx context.Context, definition *domain.PromptDefini
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmpl, parseErr := parseTemplate(fmt.Sprintf("msg_%d", i), tmplMsg.Content, funcs)
|
||||
var tmpl *template.Template
|
||||
var parseErr error
|
||||
if r.templates != nil {
|
||||
if compiled.Messages[i] == nil {
|
||||
return nil, fmt.Errorf("%w: captured message template is unavailable", ErrRenderFailure)
|
||||
}
|
||||
tmpl, parseErr = compiled.Messages[i].Clone()
|
||||
if parseErr == nil {
|
||||
tmpl.Funcs(funcs)
|
||||
}
|
||||
} else {
|
||||
tmpl, parseErr = parseTemplate(fmt.Sprintf("msg_%d", i), tmplMsg.Content, funcs)
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -174,7 +213,25 @@ func renderSessionID(ctx context.Context, raw string, funcs template.FuncMap, va
|
||||
if parseErr != nil {
|
||||
return "", fmt.Errorf("%w: session_id: %v", ErrInvalidTemplate, parseErr)
|
||||
}
|
||||
return executeSessionTemplate(ctx, tmpl, vars)
|
||||
}
|
||||
|
||||
func renderCompiledSessionID(ctx context.Context, compiled *template.Template, funcs template.FuncMap, vars map[string]string) (string, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
tmpl, err := compiled.Clone()
|
||||
if err := ctx.Err(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: session_id: %v", ErrRenderFailure, err)
|
||||
}
|
||||
tmpl.Funcs(funcs)
|
||||
return executeSessionTemplate(ctx, tmpl, vars)
|
||||
}
|
||||
|
||||
func executeSessionTemplate(ctx context.Context, tmpl *template.Template, vars map[string]string) (string, error) {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -2,6 +2,18 @@ package prompt
|
||||
|
||||
import "text/template"
|
||||
|
||||
// CompiledTemplates is the immutable parsed template set for one captured
|
||||
// prompt. Callers must not mutate its templates after handing it to a renderer.
|
||||
type CompiledTemplates struct {
|
||||
Session *template.Template
|
||||
Messages []*template.Template
|
||||
}
|
||||
|
||||
// TemplateLookup provides parsed templates for a captured prompt identity.
|
||||
type TemplateLookup interface {
|
||||
GetCompiledTemplates(id, version string) (CompiledTemplates, bool)
|
||||
}
|
||||
|
||||
// CompileTemplate checks static syntax with the same grammar and function
|
||||
// names as rendering, without evaluating request inputs or variables.
|
||||
func CompileTemplate(name, raw string) (*template.Template, error) {
|
||||
|
||||
Reference in New Issue
Block a user