Documentation
¶
Overview ¶
Package sdk provides a high-level SDK for building LLM applications with PromptKit.
The SDK is built around PromptPacks - compiled JSON files containing prompts, variables, tools, and validators. This PromptPack-first approach ensures you get the full benefits of PromptKit's pipeline architecture including:
- Prompt assembly with variable interpolation
- Template rendering with fragments
- Tool orchestration and governance
- Response validation and guardrails
- State persistence across conversations
Two API Levels:
High-Level API (ConversationManager):
- Simple interface for common use cases
- Automatic pipeline construction
- Load pack, create conversation, send messages
Low-Level API (PipelineBuilder):
- Custom middleware injection
- Full pipeline control
- Advanced use cases (custom context builders, observability)
Index ¶
- Constants
- Variables
- func IsRetryableError(err error) bool
- func IsTemporaryError(err error) bool
- func WrapPackError(err error, packPath string) error
- func WrapProviderError(err error, provider string) error
- func WrapValidationError(err error, validator string) error
- type Conversation
- func (c *Conversation) AddEventListener(listener events.Listener)
- func (c *Conversation) AddToolResult(toolCallID, result string) error
- func (c *Conversation) Continue(ctx context.Context) (*Response, error)
- func (c *Conversation) GetHistory() []types.Message
- func (c *Conversation) GetID() string
- func (c *Conversation) GetPendingTools() []tools.PendingToolInfo
- func (c *Conversation) GetUserID() string
- func (c *Conversation) HasPendingTools() bool
- func (c *Conversation) Send(ctx context.Context, userMessage string, opts ...SendOptions) (*Response, error)
- func (c *Conversation) SendStream(ctx context.Context, userMessage string, opts ...SendOptions) (<-chan StreamEvent, error)
- type ConversationConfig
- type ConversationManager
- func (cm *ConversationManager) CreateConversation(ctx context.Context, pack *Pack, config ConversationConfig) (*Conversation, error)
- func (cm *ConversationManager) GetConversation(ctx context.Context, conversationID string, pack *Pack) (*Conversation, error)
- func (cm *ConversationManager) LoadPack(packPath string) (*Pack, error)
- type CustomContextMiddleware
- type ManagerConfig
- type ManagerOption
- func WithConfig(config ManagerConfig) ManagerOption
- func WithEventBus(bus *events.EventBus) ManagerOption
- func WithMediaStorage(storageService storage.MediaStorageService) ManagerOption
- func WithProvider(provider providers.Provider) ManagerOption
- func WithStateStore(store statestore.Store) ManagerOption
- func WithToolRegistry(registry *tools.Registry) ManagerOption
- type MiddlewareConfig
- type ModelOverride
- type ObservabilityMiddleware
- type Pack
- type PackManager
- type Parameters
- type PipelineBuilder
- func (pb *PipelineBuilder) Build() *pipeline.Pipeline
- func (pb *PipelineBuilder) WithConfig(config *pipeline.RuntimeConfig) *PipelineBuilder
- func (pb *PipelineBuilder) WithMediaExternalization(storageService storage.MediaStorageService, sizeThresholdKB int64, ...) *PipelineBuilder
- func (pb *PipelineBuilder) WithMiddleware(m pipeline.Middleware) *PipelineBuilder
- func (pb *PipelineBuilder) WithProvider(provider providers.Provider, toolRegistry *tools.Registry, ...) *PipelineBuilder
- func (pb *PipelineBuilder) WithSimpleProvider(provider providers.Provider) *PipelineBuilder
- func (pb *PipelineBuilder) WithTemplate() *PipelineBuilder
- type PipelineConfig
- type Prompt
- type Response
- type SendOptions
- type StreamEvent
- type TemplateEngine
- type TestedModel
- type Tool
- type ToolPolicy
- type Validator
- type Variable
Constants ¶
const ( RoleAssistant = "assistant" RoleUser = "user" RoleTool = "tool" )
Role constants for message types
Variables ¶
var ( ErrPackNotFound = errors.New("pack not found") ErrPromptNotFound = errors.New("prompt not found") ErrInvalidConfig = errors.New("invalid configuration") ErrProviderFailed = errors.New("provider request failed") ErrValidationFailed = errors.New("validation failed") )
Common error types for better error handling
Functions ¶
func IsRetryableError ¶
IsRetryableError determines if an operation should be retried.
func IsTemporaryError ¶
IsTemporaryError checks if an error is temporary and should be retried.
func WrapPackError ¶
WrapPackError wraps an error with pack context information.
func WrapProviderError ¶
WrapProviderError wraps an error with provider context information.
func WrapValidationError ¶
WrapValidationError wraps an error with validation context information.
Types ¶
type Conversation ¶
type Conversation struct {
// contains filtered or unexported fields
}
Conversation represents an active conversation
func (*Conversation) AddEventListener ¶ added in v1.1.4
func (c *Conversation) AddEventListener(listener events.Listener)
AddEventListener subscribes to runtime events emitted during conversation execution.
func (*Conversation) AddToolResult ¶
func (c *Conversation) AddToolResult(toolCallID, result string) error
AddToolResult adds a tool execution result to the conversation. This is used to provide the result of a tool call that was pending approval.
Parameters:
- toolCallID: The ID of the tool call (from MessageToolCall.ID)
- result: The JSON string result from the tool execution
func (*Conversation) Continue ¶
func (c *Conversation) Continue(ctx context.Context) (*Response, error)
Continue resumes execution after tool results have been added. This should be called after one or more AddToolResult() calls to continue the conversation with the LLM using the tool results.
Returns the assistant's response after processing the tool results.
func (*Conversation) GetHistory ¶
func (c *Conversation) GetHistory() []types.Message
GetHistory returns the conversation message history
func (*Conversation) GetID ¶
func (c *Conversation) GetID() string
GetID returns the conversation ID
func (*Conversation) GetPendingTools ¶
func (c *Conversation) GetPendingTools() []tools.PendingToolInfo
GetPendingTools returns information about pending tool calls that require approval. This extracts PendingToolInfo from the conversation state metadata.
func (*Conversation) GetUserID ¶
func (c *Conversation) GetUserID() string
GetUserID returns the user ID
func (*Conversation) HasPendingTools ¶
func (c *Conversation) HasPendingTools() bool
HasPendingTools checks if the conversation has any pending tool calls awaiting approval
func (*Conversation) Send ¶
func (c *Conversation) Send(ctx context.Context, userMessage string, opts ...SendOptions) (*Response, error)
Send sends a user message and gets an assistant response
func (*Conversation) SendStream ¶
func (c *Conversation) SendStream(ctx context.Context, userMessage string, opts ...SendOptions) (<-chan StreamEvent, error)
SendStream sends a user message and returns a streaming response
type ConversationConfig ¶
type ConversationConfig struct {
// Required fields
UserID string // User who owns this conversation
PromptName string // Task type from the pack (e.g., "support", "sales")
// Optional fields
ConversationID string // If empty, auto-generated
Variables map[string]interface{} // Template variables
SystemPrompt string // Override system prompt
Metadata map[string]interface{} // Custom metadata
// Context policy (token budget management)
ContextPolicy *middleware.ContextBuilderPolicy
}
ConversationConfig configures a new conversation
type ConversationManager ¶
type ConversationManager struct {
// contains filtered or unexported fields
}
ConversationManager provides high-level API for managing LLM conversations. It automatically constructs the pipeline with appropriate middleware based on the PromptPack configuration.
Key Features:
- Load PromptPacks and create conversations for specific prompts
- Automatic pipeline construction with middleware stack
- State persistence via StateStore
- Support for streaming and tool execution
- Multi-turn conversation management
func NewConversationManager ¶
func NewConversationManager(opts ...ManagerOption) (*ConversationManager, error)
NewConversationManager creates a new ConversationManager
func (*ConversationManager) CreateConversation ¶
func (cm *ConversationManager) CreateConversation(ctx context.Context, pack *Pack, config ConversationConfig) (*Conversation, error)
CreateConversation creates a new conversation for a specific prompt in the pack
func (*ConversationManager) GetConversation ¶
func (cm *ConversationManager) GetConversation( ctx context.Context, conversationID string, pack *Pack, ) (*Conversation, error)
GetConversation loads an existing conversation from state store
type CustomContextMiddleware ¶
type CustomContextMiddleware interface {
pipeline.Middleware
}
CustomContextMiddleware is an example of custom middleware for context building. Users can implement similar middleware for their specific needs.
Example:
type MyContextMiddleware struct {
ragClient *RAGClient
}
func (m *MyContextMiddleware) Process(execCtx *pipeline.ExecutionContext, next func() error) error {
// Extract query from last user message
query := execCtx.Messages[len(execCtx.Messages)-1].Content
// Fetch relevant documents
docs, _ := m.ragClient.Search(query, 5)
// Add to variables for template substitution
execCtx.Variables["rag_context"] = formatDocs(docs)
return next()
}
type ManagerConfig ¶
type ManagerConfig struct {
// MaxConcurrentExecutions limits parallel pipeline executions
MaxConcurrentExecutions int
// DefaultTimeout for LLM requests
DefaultTimeout time.Duration
// EnableMetrics enables built-in metrics collection
EnableMetrics bool
// Media externalization settings
EnableMediaExternalization bool // Enable automatic media externalization
MediaSizeThresholdKB int64 // Size threshold in KB (media larger than this is externalized)
MediaDefaultPolicy string // Default retention policy for externalized media
}
ManagerConfig configures the ConversationManager
type ManagerOption ¶
type ManagerOption func(*ConversationManager) error
ManagerOption configures ConversationManager
func WithConfig ¶
func WithConfig(config ManagerConfig) ManagerOption
WithConfig sets the manager configuration
func WithEventBus ¶ added in v1.1.4
func WithEventBus(bus *events.EventBus) ManagerOption
WithEventBus sets a shared event bus for conversation event listeners.
func WithMediaStorage ¶ added in v1.1.2
func WithMediaStorage(storageService storage.MediaStorageService) ManagerOption
WithMediaStorage sets the media storage service for automatic media externalization. When enabled, large media content in provider responses is automatically moved from inline base64 data to file storage, significantly reducing memory usage and improving performance.
Default behavior when storage is provided:
- Media externalization is enabled
- Size threshold is set to 100KB (media larger than this is externalized)
- Retention policy defaults to "retain" (keep media indefinitely)
To customize these defaults, use WithConfig after WithMediaStorage.
Example:
storage, _ := local.NewFileStore(local.FileStoreConfig{BaseDir: "./media"})
manager, _ := sdk.NewConversationManager(
sdk.WithProvider(provider),
sdk.WithMediaStorage(storage),
)
func WithProvider ¶
func WithProvider(provider providers.Provider) ManagerOption
WithProvider sets the LLM provider
func WithStateStore ¶
func WithStateStore(store statestore.Store) ManagerOption
WithStateStore sets the state persistence backend
func WithToolRegistry ¶
func WithToolRegistry(registry *tools.Registry) ManagerOption
WithToolRegistry sets the tool registry for tool execution
type MiddlewareConfig ¶
type MiddlewareConfig struct {
Type string `json:"type"`
Config map[string]interface{} `json:"config,omitempty"`
}
MiddlewareConfig defines a single middleware configuration
type ModelOverride ¶
type ModelOverride struct {
SystemTemplateSuffix string `json:"system_template_suffix,omitempty"`
}
ModelOverride defines model-specific template overrides
type ObservabilityMiddleware ¶
type ObservabilityMiddleware interface {
pipeline.Middleware
}
ObservabilityMiddleware is an example of observability middleware. Users can implement similar middleware for LangFuse, DataDog, etc.
Example:
type LangFuseMiddleware struct {
client *langfuse.Client
}
func (m *LangFuseMiddleware) Process(execCtx *pipeline.ExecutionContext, next func() error) error {
traceID := m.client.StartTrace(...)
spanID := m.client.StartSpan(traceID, ...)
start := time.Now()
err := next()
duration := time.Since(start)
m.client.EndSpan(spanID, langfuse.SpanResult{
Duration: duration,
TokensInput: execCtx.CostInfo.InputTokens,
TokensOutput: execCtx.CostInfo.OutputTokens,
Error: err,
})
return err
}
type Pack ¶
type Pack struct {
// Pack identity
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
// Shared configuration across all prompts
TemplateEngine TemplateEngine `json:"template_engine"`
// Map of task_type -> prompt configuration
Prompts map[string]*Prompt `json:"prompts"`
// Shared fragments used by all prompts
Fragments map[string]string `json:"fragments,omitempty"`
// Tool definitions (referenced by prompts)
Tools map[string]*Tool `json:"tools,omitempty"`
// contains filtered or unexported fields
}
Pack represents a loaded PromptPack containing multiple prompts for related task types. A pack is a portable, JSON-based bundle created by the packc compiler.
DESIGN DECISION: Why separate Pack types in sdk vs runtime?
This SDK Pack is optimized for LOADING & EXECUTION:
- Loaded from .pack.json files for application use
- Includes Tools map for runtime tool access
- Includes filePath to track source file location
- Thread-safe with sync.RWMutex for concurrent access
- Returns validation errors for application error handling
- Rich types (*Variable, *Validator, *Tool) with full functionality
- Has CreateRegistry() to convert to runtime.Registry for pipeline execution
- Has convertToRuntimeConfig() to bridge SDK ↔ runtime formats
The runtime.prompt.Pack is optimized for COMPILATION:
- Created by PackCompiler during prompt compilation
- Includes Compilation and Metadata fields for provenance tracking
- Returns validation warnings ([]string) for compiler feedback
- No thread-safety (single-threaded compilation process)
- Simple types for clean JSON serialization
- No conversion methods (produces, doesn't consume)
Both types serialize to/from the SAME JSON format (.pack.json files), ensuring full interoperability between compilation and execution phases. The duplication is intentional and provides:
- Clear separation of concerns (compile vs execute)
- No circular dependencies (sdk imports runtime, not vice versa)
- Independent evolution of each module
- Type-specific optimizations (thread-safety, validation behavior)
Design: A pack contains MULTIPLE prompts (task_types) that share common configuration like template engine and fragments, but each prompt has its own template, variables, tools, and validators.
See runtime/prompt/pack.go for the corresponding runtime-side documentation.
func (*Pack) CreateRegistry ¶
CreateRegistry creates a runtime prompt.Registry from this pack. The registry allows the runtime pipeline to access prompts using the standard prompt assembly middleware. Each prompt in the pack is registered by its task_type.
This bridges the SDK's .pack.json format with the runtime's prompt.Registry format.
func (*Pack) ListPrompts ¶
ListPrompts returns all available task types in the pack
type PackManager ¶
type PackManager struct {
// contains filtered or unexported fields
}
PackManager manages loading and caching of PromptPacks
type Parameters ¶
type Parameters struct {
Temperature float32 `json:"temperature,omitempty"`
MaxTokens int `json:"max_tokens,omitempty"`
TopP float32 `json:"top_p,omitempty"`
TopK *int `json:"top_k,omitempty"`
}
Parameters defines LLM generation parameters
type PipelineBuilder ¶
type PipelineBuilder struct {
// contains filtered or unexported fields
}
PipelineBuilder provides low-level API for constructing custom pipelines with middleware.
Use this when you need:
- Custom middleware injection
- Custom context builders
- Observability integration (LangFuse, DataDog, etc.)
- Advanced pipeline control
For simple use cases, use ConversationManager instead.
Example:
builder := sdk.NewPipelineBuilder().
WithProvider(provider).
WithMiddleware(customMiddleware).
WithMiddleware(observabilityMiddleware)
pipe := builder.Build()
result, err := pipe.Execute(ctx, "user", "Hello!")
func NewPipelineBuilder ¶
func NewPipelineBuilder() *PipelineBuilder
NewPipelineBuilder creates a new pipeline builder
func (*PipelineBuilder) Build ¶
func (pb *PipelineBuilder) Build() *pipeline.Pipeline
Build constructs the pipeline
func (*PipelineBuilder) WithConfig ¶
func (pb *PipelineBuilder) WithConfig(config *pipeline.RuntimeConfig) *PipelineBuilder
WithConfig sets the pipeline runtime configuration
func (*PipelineBuilder) WithMediaExternalization ¶ added in v1.1.2
func (pb *PipelineBuilder) WithMediaExternalization(storageService storage.MediaStorageService, sizeThresholdKB int64, defaultPolicy string) *PipelineBuilder
WithMediaExternalization adds media externalization middleware. This automatically stores large media content to a storage backend and replaces inline base64 data with storage references, reducing memory usage.
Parameters:
- storageService: The storage backend for media files
- sizeThresholdKB: Media larger than this (in KB) will be externalized
- defaultPolicy: Retention policy name (e.g., "retain", "delete-after-30d")
Example:
storage, _ := local.NewFileStore(local.FileStoreConfig{BaseDir: "./media"})
builder.WithMediaExternalization(storage, 100, "retain")
func (*PipelineBuilder) WithMiddleware ¶
func (pb *PipelineBuilder) WithMiddleware(m pipeline.Middleware) *PipelineBuilder
WithMiddleware adds middleware to the pipeline. Middleware executes in the order added.
func (*PipelineBuilder) WithProvider ¶
func (pb *PipelineBuilder) WithProvider(provider providers.Provider, toolRegistry *tools.Registry, toolPolicy *pipeline.ToolPolicy) *PipelineBuilder
WithProvider adds a provider middleware to the pipeline. This is a convenience method that wraps the runtime ProviderMiddleware.
func (*PipelineBuilder) WithSimpleProvider ¶
func (pb *PipelineBuilder) WithSimpleProvider(provider providers.Provider) *PipelineBuilder
WithSimpleProvider adds a provider middleware without tools or custom config. This is the simplest way to add LLM execution to a pipeline.
func (*PipelineBuilder) WithTemplate ¶
func (pb *PipelineBuilder) WithTemplate() *PipelineBuilder
WithTemplate adds template substitution middleware. This replaces {{variable}} placeholders in the system prompt.
type PipelineConfig ¶
type PipelineConfig struct {
Stages []string `json:"stages"`
Middleware []*MiddlewareConfig `json:"middleware"`
}
PipelineConfig defines pipeline middleware configuration
type Prompt ¶
type Prompt struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Version string `json:"version"`
// Template
SystemTemplate string `json:"system_template"`
// Variables for this prompt
Variables []*Variable `json:"variables"`
// Tool references (names that map to pack.Tools)
ToolNames []string `json:"tools,omitempty"`
// Tool policy
ToolPolicy *ToolPolicy `json:"tool_policy,omitempty"`
// Multimodal media configuration
MediaConfig *prompt.MediaConfig `json:"media,omitempty"`
// Pipeline configuration
Pipeline *PipelineConfig `json:"pipeline,omitempty"`
// LLM parameters
Parameters *Parameters `json:"parameters,omitempty"`
// Validators
Validators []*Validator `json:"validators,omitempty"`
// Model testing results
TestedModels []*TestedModel `json:"tested_models,omitempty"`
// Model-specific overrides
ModelOverrides map[string]*ModelOverride `json:"model_overrides,omitempty"`
}
Prompt represents a single prompt configuration within a pack
type Response ¶
type Response struct {
Content string
ToolCalls []types.MessageToolCall
TokensUsed int
Cost float64
LatencyMs int64
Validations []types.ValidationResult
Truncated bool // True if context was truncated
PendingTools []tools.PendingToolInfo // Tools awaiting external approval/input
}
Response represents a conversation turn response
type SendOptions ¶
type SendOptions struct {
Stream bool // Enable streaming
MaxToolCalls int // Max tool calls per turn (0 = use prompt default)
Metadata map[string]interface{} // Turn-specific metadata
}
SendOptions configures message sending behavior
type StreamEvent ¶
type StreamEvent struct {
Type string // "content", "tool_call", "done", "error"
Content string
ToolCall *types.MessageToolCall
Error error
Final *Response // Set when Type="done"
}
StreamEvent represents a streaming response event
type TemplateEngine ¶
type TemplateEngine struct {
Version string `json:"version"`
Syntax string `json:"syntax"`
Features []string `json:"features"`
}
TemplateEngine describes the template engine configuration shared across prompts
type TestedModel ¶
type TestedModel struct {
Provider string `json:"provider"`
Model string `json:"model"`
Date string `json:"date"`
SuccessRate float64 `json:"success_rate"`
AvgTokens int `json:"avg_tokens"`
AvgCost float64 `json:"avg_cost"`
AvgLatencyMs int `json:"avg_latency_ms"`
}
TestedModel contains testing results for a specific model
type Tool ¶
type Tool struct {
Name string `json:"name"`
Description string `json:"description"`
Parameters map[string]interface{} `json:"parameters"`
}
Tool defines a tool that can be called by the LLM
type ToolPolicy ¶
type ToolPolicy struct {
ToolChoice string `json:"tool_choice"` // "auto", "required", "none"
MaxRounds int `json:"max_rounds,omitempty"`
MaxToolCallsPerTurn int `json:"max_tool_calls_per_turn,omitempty"`
Blocklist []string `json:"blocklist,omitempty"`
}
ToolPolicy defines tool usage constraints
type Validator ¶
type Validator struct {
Type string `json:"type"`
Enabled bool `json:"enabled"`
FailOnViolation bool `json:"fail_on_violation"`
Params map[string]interface{} `json:"params"`
}
Validator defines a validation rule
type Variable ¶
type Variable struct {
Name string `json:"name"`
Type string `json:"type"` // "string", "number", "boolean", "object", "array"
Required bool `json:"required"`
Default interface{} `json:"default,omitempty"`
Description string `json:"description"`
Example interface{} `json:"example,omitempty"`
Validation map[string]interface{} `json:"validation,omitempty"`
}
Variable defines a template variable with validation rules
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
context-management
command
|
|
|
custom-middleware
command
|
|
|
events
command
Package main demonstrates listening to runtime events from the SDK.
|
Package main demonstrates listening to runtime events from the SDK. |
|
hitl-approval
command
|
|
|
streaming
command
|
|
|
tools
command
|