AgenticChatTemplate Guide [Beta]
π‘ This feature is available starting from v0.9. This document is based on the current main branch source code, with code primarily located in
components/prompt,schema/agentic_message.go, andcompose.
Introduction
AgenticChatTemplate is a Prompt component abstraction designed for *schema.AgenticMessage. It fills variables from a map[string]any into agentic message templates and outputs []*schema.AgenticMessage for use by AgenticModel or subsequent orchestration nodes.
Its design is essentially the same as the existing ChatTemplate, but the message type is switched from *schema.Message to *schema.AgenticMessage, and template rendering only applies to user input content blocks.
Component Definition
Code location: components/prompt/interface.go
type AgenticChatTemplate interface {
Format(ctx context.Context, vs map[string]any, opts ...Option) ([]*schema.AgenticMessage, error)
}
Format parameter description:
| Parameter | Description |
ctx | Request context, also carries runtime information such as the callback manager |
vs | Template variable map, where the key is the placeholder name and value is the actual value |
opts | Prompt component Option, supports implementation-side custom extensions |
Return values:
| Return Value | Description |
[]*schema.AgenticMessage | The rendered agentic message list |
error | Returns an error when variables are missing, variable types don't match, or template rendering fails |
Construction Methods
FromAgenticMessages
Code location: components/prompt/agentic_chat_template.go
func FromAgenticMessages(formatType schema.FormatType, templates ...schema.AgenticMessagesTemplate) *DefaultAgenticChatTemplate
FromAgenticMessages does not return an error. It accepts a template format and a set of schema.AgenticMessagesTemplate, and returns the default implementation *DefaultAgenticChatTemplate.
template := prompt.FromAgenticMessages(schema.FString,
schema.SystemAgenticMessage("You are a {role}."),
schema.AgenticMessagesPlaceholder("history", true),
schema.UserAgenticMessage("Please help me {task}."),
)
Supported FormatTypes
| Format | Constant | Placeholder Example | Applicable Scenarios |
| FString | schema.FString | {role} | Simple variable substitution |
| GoTemplate | schema.GoTemplate | {{.role}} | Scenarios requiring Gotext/templatecapabilities |
| Jinja2 | schema.Jinja2 | {{ role }} | Scenarios requiring Jinja2 syntax |
AgenticMessagesTemplate
Code location: schema/agentic_message.go
type AgenticMessagesTemplate interface {
Format(ctx context.Context, vs map[string]any, formatType FormatType) ([]*AgenticMessage, error)
}
Common implementations include:
| Construction Method | Description |
&schema.AgenticMessage{...} | AgenticMessageitself implements AgenticMessagesTemplate |
schema.SystemAgenticMessage(text) | Constructs asystemrole message |
schema.UserAgenticMessage(text) | Constructs auserrole message |
schema.AgenticMessagesPlaceholder(key, optional) | Inserts a set of historical agentic messages from the variable map |
Template Rendering Scope
AgenticMessage.Format only formats user input blocks:
ContentBlockTypeUserInputTextContentBlockTypeUserInputImageContentBlockTypeUserInputAudioContentBlockTypeUserInputVideoContentBlockTypeUserInputFile
Model output, reasoning, tool call, tool result, MCP, and server tool related blocks are not rendered as prompt template content.
π‘ It is recommended to use
schema.SystemAgenticMessage,schema.UserAgenticMessage, andschema.NewContentBlockto construct templates, avoiding inconsistencies betweenContentBlock.Typeand content fields when setting them manually.
Placeholder
Code location: schema/agentic_message.go
func AgenticMessagesPlaceholder(key string, optional bool) AgenticMessagesTemplate
Behavior rules:
| Scenario | Behavior |
vs[key]exists and type is []*schema.AgenticMessage | Inserts the message list as-is |
vs[key]does not exist and optional=true | Returns an empty slice without error |
vs[key]does not exist and optional=false | Returns an error |
vs[key]type is not []*schema.AgenticMessage | Returns an error |
Example:
history := []*schema.AgenticMessage{
schema.UserAgenticMessage("What is oil painting?"),
{
Role: schema.AgenticRoleTypeAssistant,
ContentBlocks: []*schema.ContentBlock{
schema.NewContentBlock(&schema.AssistantGenText{Text: "Oil painting is ..."}),
},
},
}
messages, err := template.Format(ctx, map[string]any{
"role": "professional assistant",
"task": "write a short poem",
"history": history,
})
if err != nil {
return err
}
Standalone Usage
template := prompt.FromAgenticMessages(schema.FString,
schema.SystemAgenticMessage("You are a {role}."),
schema.AgenticMessagesPlaceholder("history", true),
schema.UserAgenticMessage("Please help me {task}."),
)
messages, err := template.Format(ctx, map[string]any{
"role": "concise assistant",
"task": "summarize the following requirement",
"history": []*schema.AgenticMessage{
schema.UserAgenticMessage("Previous question"),
},
})
if err != nil {
return err
}
Usage in Orchestration
Chain
Code location: compose/chain.go
func (c *Chain[I, O]) AppendAgenticChatTemplate(node prompt.AgenticChatTemplate, opts ...GraphAddNodeOpt) *Chain[I, O]
chain := compose.NewChain[map[string]any, *schema.AgenticMessage]()
chain.AppendAgenticChatTemplate(template)
chain.AppendAgenticModel(model)
Graph
Code location: compose/graph.go
func (g *graph) AddAgenticChatTemplateNode(key string, node prompt.AgenticChatTemplate, opts ...GraphAddNodeOpt) error
graph := compose.NewGraph[map[string]any, *schema.AgenticMessage]()
err := graph.AddAgenticChatTemplateNode("prompt", template)
if err != nil {
return err
}
Workflow
Code location: compose/workflow.go
func (wf *Workflow[I, O]) AddAgenticChatTemplateNode(key string, chatTemplate prompt.AgenticChatTemplate, opts ...GraphAddNodeOpt) *WorkflowNode
Parallel and ChainBranch
Agentic prompt can also be placed in Parallel or ChainBranch:
func (p *Parallel) AddAgenticChatTemplate(outputKey string, node prompt.AgenticChatTemplate, opts ...GraphAddNodeOpt) *Parallel
func (cb *ChainBranch) AddAgenticChatTemplate(key string, node prompt.AgenticChatTemplate, opts ...GraphAddNodeOpt) *ChainBranch
Getting Variables from Predecessor Nodes
AgenticChatTemplate.Format requires map[string]any. If the predecessor node’s output is not a map, you can use compose.WithOutputKey when adding the node to wrap the output as a single-field map.
graph.AddLambdaNode("query",
compose.InvokableLambda(func(ctx context.Context, input string) (string, error) {
return input, nil
}),
compose.WithOutputKey("task"),
)
graph.AddAgenticChatTemplateNode("prompt", template)
The wrapped map looks like:
map[string]any{
"task": previousNodeOutput,
}
Callback
Component-level Callback Payload
Code location: components/prompt/agentic_callback_extra.go
type AgenticCallbackInput struct {
Variables map[string]any
Templates []schema.AgenticMessagesTemplate
Extra map[string]any
}
type AgenticCallbackOutput struct {
Result []*schema.AgenticMessage
Templates []schema.AgenticMessagesTemplate
Extra map[string]any
}
func ConvAgenticCallbackInput(src callbacks.CallbackInput) *AgenticCallbackInput
func ConvAgenticCallbackOutput(src callbacks.CallbackOutput) *AgenticCallbackOutput
DefaultAgenticChatTemplate.Format triggers callbacks at the start and end, passing the above agentic payload.
utils/callbacks Helper
Code location: utils/callbacks/template.go
The current public signature of AgenticPromptCallbackHandler is as follows:
type AgenticPromptCallbackHandler struct {
OnStart func(ctx context.Context, runInfo *callbacks.RunInfo, input *prompt.CallbackInput) context.Context
OnEnd func(ctx context.Context, runInfo *callbacks.RunInfo, output *prompt.CallbackOutput) context.Context
OnError func(ctx context.Context, runInfo *callbacks.RunInfo, err error) context.Context
}
Register using the helper:
handler := callbackHelper.NewHandlerHelper().
AgenticPrompt(&callbackHelper.AgenticPromptCallbackHandler{
OnStart: func(ctx context.Context, info *callbacks.RunInfo, input *prompt.CallbackInput) context.Context {
if input != nil {
fmt.Printf("variables: %v\n", input.Variables)
}
return ctx
},
OnError: func(ctx context.Context, info *callbacks.RunInfo, err error) context.Context {
fmt.Printf("prompt error: %v\n", err)
return ctx
},
}).
Handler()
result, err := runnable.Invoke(ctx, variables, compose.WithCallbacks(handler))
π‘ If you need to directly handle
*prompt.AgenticCallbackInputor*prompt.AgenticCallbackOutput, you should use the component-level callback payload along withprompt.ConvAgenticCallbackInput/Output. The current public signature ofutils/callbacks.AgenticPromptCallbackHandlerstill reusesprompt.CallbackInput/Output.
Custom Implementation
Implementing a custom AgenticChatTemplate only requires satisfying the interface:
type MyAgenticPrompt struct {
templates []schema.AgenticMessagesTemplate
formatType schema.FormatType
}
func (p *MyAgenticPrompt) Format(ctx context.Context, vs map[string]any, opts ...prompt.Option) ([]*schema.AgenticMessage, error) {
result := make([]*schema.AgenticMessage, 0, len(p.templates))
for _, tpl := range p.templates {
msgs, err := tpl.Format(ctx, vs, p.formatType)
if err != nil {
return nil, err
}
result = append(result, msgs...)
}
return result, nil
}
If you need to support custom options, you can implement them using prompt.WrapImplSpecificOptFn and prompt.GetImplSpecificOptions.
Best Practices
FromAgenticMessagesdoes not return anerror, so examples should not be written astemplate, err := ....- The variable value for
AgenticMessagesPlaceholdermust be[]*schema.AgenticMessage. - Template variable names should be stable and consistent; missing variables will return an error at runtime.
- Use
AgenticMessagesPlaceholder("history", true)for conversation history, which naturally returns an empty list when there is no history. - In Graph/Chain, ensure that the node following the Agentic prompt accepts
[]*schema.AgenticMessagetype, such asAgenticModel.