sdk

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 15, 2026 License: Apache-2.0 Imports: 39 Imported by: 0

README

PromptKit SDK

The PromptKit SDK provides a simple, pack-first API for building LLM-powered applications in Go.

Overview

SDK v2 is designed around PromptPack files - everything starts from a .pack.json file that defines prompts, variables, tools, validators, and pipeline configuration. The SDK loads the pack and provides a minimal API to interact with LLMs.

Key Features
  • Pack-First Design: Load prompts directly from pack files - no manual configuration
  • Stage-Based Pipeline: Built on the streaming stage architecture for true streaming execution
  • Multiple Execution Modes: Text, VAD (Voice Activity Detection), and ASM (Audio Streaming Mode)
  • Tool System: Multiple executor types (function, HTTP, MCP)
  • Streaming Support: Built-in streaming with customizable handlers
  • Observability: EventBus integration with hooks package for monitoring

Quick Start

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/AltairaLabs/PromptKit/sdk"
)

func main() {
    // Open a conversation from a pack file
    conv, err := sdk.Open("./assistant.pack.json", "chat")
    if err != nil {
        log.Fatal(err)
    }
    defer conv.Close()

    // Send a message and get a response
    resp, err := conv.Send(context.Background(), "Hello!")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(resp.Text())
}

Installation

go get github.com/AltairaLabs/PromptKit/sdk

Core Concepts

Opening a Conversation

Use Open to load a pack file and create a conversation for a specific prompt:

// Minimal - provider auto-detected from environment
conv, _ := sdk.Open("./demo.pack.json", "troubleshooting")

// With options - override model, provider, etc.
conv, _ := sdk.Open("./demo.pack.json", "troubleshooting",
    sdk.WithModel("gpt-4o"),
    sdk.WithAPIKey(os.Getenv("MY_OPENAI_KEY")),
)
Variables

Variables defined in the pack are populated at runtime:

conv.SetVar("customer_id", "acme-corp")
conv.SetVars(map[string]any{
    "customer_name": "ACME Corporation",
    "tier": "premium",
})
Tools

Tools defined in the pack just need implementation handlers:

conv.OnTool("list_devices", func(args map[string]any) (any, error) {
    return myAPI.ListDevices(args["customer_id"].(string))
})
Streaming

Stream responses chunk by chunk:

for chunk := range conv.Stream(ctx, "Tell me a story") {
    fmt.Print(chunk.Text)
}

Pipeline Architecture

The SDK uses a stage-based pipeline architecture for all execution modes. Pipelines are composed of stages that process streaming elements.

Pipeline Modes
Mode Description Use Case
Text Standard HTTP API calls Chat, completion, text generation
VAD Audio → VAD → STT → LLM → TTS Voice assistants without native audio LLM
ASM Direct audio streaming via WebSocket Native multimodal LLMs (Gemini Live)
Text Mode Pipeline
StateStoreLoad → VariableProvider → PromptAssembly → Template → Provider → Validation → StateStoreSave
VAD Mode Pipeline
StateStoreLoad → VariableProvider → PromptAssembly → Template → AudioTurn → STT → Provider → TTS → Validation → StateStoreSave
ASM Mode Pipeline
StateStoreLoad → VariableProvider → PromptAssembly → Template → DuplexProvider → Validation → StateStoreSave

Configuration Options

Provider Configuration
conv, _ := sdk.Open("./pack.json", "chat",
    sdk.WithProvider(openai.NewProvider(openai.Config{
        APIKey: os.Getenv("OPENAI_API_KEY"),
    })),
    sdk.WithModel("gpt-4o"),
    sdk.WithMaxTokens(1000),
    sdk.WithTemperature(0.7),
)
State Store (Conversation History)
store := statestore.NewMemoryStore()

conv, _ := sdk.Open("./pack.json", "chat",
    sdk.WithStateStore(store),
    sdk.WithConversationID("session-123"),
)
VAD Mode (Voice Activity Detection)
sttService := stt.NewOpenAI(os.Getenv("OPENAI_API_KEY"))
ttsService := tts.NewOpenAI(os.Getenv("OPENAI_API_KEY"))

conv, _ := sdk.OpenDuplex("./pack.json", "voice-chat",
    sdk.WithProvider(openai.NewProvider(...)),
    sdk.WithVADMode(sttService, ttsService, sdk.DefaultVADModeConfig()),
)
ASM Mode (Audio Streaming)
// For providers with native audio streaming (e.g., Gemini Live)
session, _ := gemini.NewStreamSession(ctx, endpoint, apiKey, config)

conv, _ := sdk.OpenDuplex("./pack.json", "voice-chat",
    sdk.WithStreamingConfig(session),
)

Package Structure

sdk/
├── doc.go              # Package documentation
├── sdk.go              # Entry points: Open, OpenDuplex
├── conversation.go     # Conversation type
├── options.go          # Configuration options
├── response.go         # Response type
├── hooks/              # Event subscription and lifecycle hooks
├── session/            # Session management (Unary, Duplex)
├── stream/             # Streaming response handling
├── tools/              # Tool handlers and HITL support
└── internal/
    └── pipeline/       # Pipeline builder (stage-based)

Examples

See the sdk/examples/ directory for complete examples:

  • hello - Basic conversation
  • streaming - Token-by-token streaming
  • tools - Tool registration and execution
  • hitl - Human-in-the-loop approval
  • duplex-streaming - WebSocket duplex streaming
  • vad-demo - Voice activity detection demo
  • voice-interview - Complete voice interview application

Design Principles

  1. Pack is the Source of Truth - The .pack.json file defines prompts, tools, validators, and pipeline configuration. The SDK configures itself automatically.

  2. Convention Over Configuration - API keys from environment, provider auto-detection, model defaults from pack. Override only when needed.

  3. Progressive Disclosure - Simple things are simple, advanced features available but not required.

  4. Same Runtime, Same Behavior - SDK v2 uses the same runtime pipeline as Arena. Pack-defined behaviors work identically.

  5. Stage-Based Streaming - Built on the stage architecture for true streaming execution with concurrent processing.

Runtime Types

The SDK uses runtime types directly - no duplication:

import "github.com/AltairaLabs/PromptKit/runtime/types"

msg := &types.Message{Role: "user"}
msg.AddTextPart("Hello")

Key runtime types: types.Message, types.ContentPart, types.MediaContent, types.CostInfo, types.ValidationResult.

Schema Reference

All pack examples conform to the PromptPack Specification v1.1.0. See the PromptPack Schema for the complete specification.

Documentation

Overview

Package sdk provides a simple API for LLM conversations using PromptPack files.

SDK v2 is a pack-first SDK where everything starts from a .pack.json file. The pack contains prompts, variables, tools, validators, and model configuration. The SDK loads the pack and provides a minimal API to interact with LLMs.

Quick Start

The simplest possible usage is just 5 lines:

conv, err := sdk.Open("./assistant.pack.json", "chat")
if err != nil {
    log.Fatal(err)
}
defer conv.Close()

resp, _ := conv.Send(ctx, "Hello!")
fmt.Println(resp.Text())

Core Concepts

Opening a Conversation:

Use Open to load a pack file and create a conversation for a specific prompt:

// Minimal - provider auto-detected from environment
conv, _ := sdk.Open("./demo.pack.json", "troubleshooting")

// With options - override model, provider, etc.
conv, _ := sdk.Open("./demo.pack.json", "troubleshooting",
    sdk.WithModel("gpt-4o"),
    sdk.WithAPIKey(os.Getenv("MY_OPENAI_KEY")),
)

Variables:

Variables defined in the pack are populated at runtime:

conv.SetVar("customer_id", "acme-corp")
conv.SetVars(map[string]any{
    "customer_name": "ACME Corporation",
    "tier": "premium",
})

Tools:

Tools defined in the pack just need implementation handlers:

conv.OnTool("list_devices", func(args map[string]any) (any, error) {
    return myAPI.ListDevices(args["customer_id"].(string))
})

Streaming:

Stream responses chunk by chunk:

for chunk := range conv.Stream(ctx, "Tell me a story") {
    fmt.Print(chunk.Text)
}

Design Principles

  1. Pack is the Source of Truth - The .pack.json file defines prompts, tools, validators, and pipeline configuration. The SDK configures itself automatically.
  2. Convention Over Configuration - API keys from environment, provider auto-detection, model defaults from pack. Override only when needed.
  3. Progressive Disclosure - Simple things are simple, advanced features available but not required.
  4. Same Runtime, Same Behavior - SDK v2 uses the same runtime pipeline as Arena. Pack-defined behaviors work identically.
  5. Thin Wrapper - No type duplication. Core types like Message, ContentPart, CostInfo come directly from runtime/types.

Package Structure

The SDK is organized into sub-packages for specific functionality:

  • sdk (this package): Entry point, Open, Conversation, Response
  • sdk/tools: Typed tool handlers, HITL support
  • sdk/stream: Streaming response handling
  • sdk/message: Multimodal message building
  • sdk/hooks: Event subscription and lifecycle hooks
  • sdk/validation: Validator registration and error handling

Most users only need to import the root sdk package.

Runtime Types

The SDK uses runtime types directly - no duplication:

import "github.com/AltairaLabs/PromptKit/runtime/types"

msg := &types.Message{Role: "user"}
msg.AddTextPart("Hello")

Key runtime types: types.Message, types.ContentPart, types.MediaContent, types.CostInfo, types.ValidationResult.

Schema Reference

All pack examples conform to the PromptPack Specification v1.1.0: https://github.com/AltairaLabs/promptpack-spec/blob/main/schema/promptpack.schema.json

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrTaskNotFound      = errors.New("a2a: task not found")
	ErrTaskAlreadyExists = errors.New("a2a: task already exists")
	ErrInvalidTransition = errors.New("a2a: invalid state transition")
	ErrTaskTerminal      = errors.New("a2a: task is in a terminal state")
)

Task store errors.

View Source
var (
	// ErrConversationClosed is returned when Send or Stream is called on a closed conversation.
	ErrConversationClosed = errors.New("conversation is closed")

	// ErrConversationNotFound is returned by Resume when the conversation ID doesn't exist.
	ErrConversationNotFound = errors.New("conversation not found")

	// ErrNoStateStore is returned by Resume when no state store is configured.
	ErrNoStateStore = errors.New("no state store configured")

	// ErrPromptNotFound is returned when the specified prompt doesn't exist in the pack.
	ErrPromptNotFound = errors.New("prompt not found in pack")

	// ErrPackNotFound is returned when the pack file doesn't exist.
	ErrPackNotFound = errors.New("pack file not found")

	// ErrProviderNotDetected is returned when no provider could be auto-detected.
	ErrProviderNotDetected = errors.New("could not detect provider: no API keys found in environment")

	// ErrToolNotRegistered is returned when the LLM calls a tool that has no handler.
	ErrToolNotRegistered = errors.New("tool handler not registered")

	// ErrToolNotInPack is returned when trying to register a handler for a tool not in the pack.
	ErrToolNotInPack = errors.New("tool not defined in pack")
)

Sentinel errors for common failure cases.

Functions

This section is empty.

Types

type A2AConversationOpener added in v1.1.11

type A2AConversationOpener func(contextID string) (a2aConv, error)

A2AConversationOpener creates or retrieves a conversation for a context ID.

func A2AOpener added in v1.1.11

func A2AOpener(packPath, promptName string, opts ...Option) A2AConversationOpener

A2AOpener returns an A2AConversationOpener backed by SDK conversations. Each call to the returned function opens a new conversation for the given context ID using sdk.Open with the provided pack path, prompt name, and options.

type A2AServer added in v1.1.11

type A2AServer struct {
	// contains filtered or unexported fields
}

A2AServer is an HTTP server that exposes a PromptKit Conversation as an A2A-compliant JSON-RPC endpoint.

func NewA2AServer added in v1.1.11

func NewA2AServer(opener A2AConversationOpener, opts ...A2AServerOption) *A2AServer

NewA2AServer creates a new A2A server.

func (*A2AServer) Handler added in v1.1.11

func (s *A2AServer) Handler() http.Handler

Handler returns an http.Handler implementing the A2A protocol.

func (*A2AServer) ListenAndServe added in v1.1.11

func (s *A2AServer) ListenAndServe() error

ListenAndServe starts the HTTP server on the configured port.

func (*A2AServer) Serve added in v1.1.11

func (s *A2AServer) Serve(ln net.Listener) error

Serve starts the HTTP server on the given listener.

func (*A2AServer) Shutdown added in v1.1.11

func (s *A2AServer) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the server: drains HTTP requests, cancels in-flight tasks, and closes all conversations.

type A2AServerOption added in v1.1.11

type A2AServerOption func(*A2AServer)

A2AServerOption configures an A2AServer.

func WithA2ACard added in v1.1.11

func WithA2ACard(card *a2a.AgentCard) A2AServerOption

WithA2ACard sets the agent card served at /.well-known/agent.json.

func WithA2APort added in v1.1.11

func WithA2APort(port int) A2AServerOption

WithA2APort sets the TCP port for ListenAndServe.

func WithA2ATaskStore added in v1.1.11

func WithA2ATaskStore(store A2ATaskStore) A2AServerOption

WithA2ATaskStore sets a custom task store. Defaults to an in-memory store.

type A2ATaskStore added in v1.1.11

type A2ATaskStore interface {
	Create(taskID, contextID string) (*a2a.Task, error)
	Get(taskID string) (*a2a.Task, error)
	SetState(taskID string, state a2a.TaskState, msg *a2a.Message) error
	AddArtifacts(taskID string, artifacts []a2a.Artifact) error
	Cancel(taskID string) error
	List(contextID string, limit, offset int) ([]*a2a.Task, error)
}

A2ATaskStore defines the interface for task persistence and lifecycle management.

type ChunkType added in v1.1.5

type ChunkType int

ChunkType identifies the type of a streaming chunk.

const (
	// ChunkText indicates the chunk contains text content.
	ChunkText ChunkType = iota

	// ChunkToolCall indicates the chunk contains a tool call.
	ChunkToolCall

	// ChunkMedia indicates the chunk contains media content.
	ChunkMedia

	// ChunkDone indicates streaming is complete.
	ChunkDone
)

func (ChunkType) String added in v1.1.5

func (t ChunkType) String() string

String returns the string representation of the chunk type.

type Conversation

type Conversation struct {
	// contains filtered or unexported fields
}

Conversation represents an active LLM conversation.

A conversation maintains:

  • Connection to the LLM provider
  • Message history (context)
  • Variable state for template substitution
  • Tool handlers for function calling
  • Validation state

Conversations are created via Open or Resume and are safe for concurrent use. Each Open call creates an independent conversation with isolated state.

Basic usage:

conv, _ := sdk.Open("./assistant.pack.json", "chat")
conv.SetVar("user_name", "Alice")

resp, _ := conv.Send(ctx, "Hello!")
fmt.Println(resp.Text())

resp, _ = conv.Send(ctx, "What's my name?")  // Remembers context
fmt.Println(resp.Text())  // "Your name is Alice"

func Open added in v1.1.5

func Open(packPath, promptName string, opts ...Option) (*Conversation, error)

Open loads a pack file and creates a new conversation for the specified prompt.

This is the primary entry point for SDK v2. It:

  • Loads and parses the pack file
  • Auto-detects the provider from environment (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.)
  • Configures the runtime pipeline based on pack settings
  • Creates an isolated conversation with its own state

Basic usage:

conv, err := sdk.Open("./assistant.pack.json", "chat")
if err != nil {
    log.Fatal(err)
}
defer conv.Close()

resp, _ := conv.Send(ctx, "Hello!")
fmt.Println(resp.Text())

With options:

conv, err := sdk.Open("./assistant.pack.json", "chat",
    sdk.WithModel("gpt-4o"),
    sdk.WithAPIKey(os.Getenv("MY_KEY")),
    sdk.WithStateStore(redisStore),
)

The packPath can be:

The promptName must match a prompt ID defined in the pack's "prompts" section.

func OpenDuplex added in v1.1.6

func OpenDuplex(packPath, promptName string, opts ...Option) (*Conversation, error)

OpenDuplex loads a pack file and creates a new duplex streaming conversation for the specified prompt.

This creates a conversation in duplex mode for bidirectional streaming interactions. Use this when you need real-time streaming input/output with the LLM.

Basic usage:

conv, err := sdk.OpenDuplex("./assistant.pack.json", "chat")
if err != nil {
    log.Fatal(err)
}
defer conv.Close()

// Send streaming input
go func() {
    conv.SendText(ctx, "Hello, ")
    conv.SendText(ctx, "how are you?")
}()

// Receive streaming output
respCh, _ := conv.Response()
for chunk := range respCh {
    fmt.Print(chunk.Content)
}

The provider must support streaming input (implement providers.StreamInputSupport). Currently supported providers: Gemini with certain models.

func Resume added in v1.1.5

func Resume(conversationID, packPath, promptName string, opts ...Option) (*Conversation, error)

Resume loads an existing conversation from state storage.

Use this to continue a conversation that was previously persisted:

store := statestore.NewRedisStore("redis://localhost:6379")
conv, err := sdk.Resume("session-123", "./chat.pack.json", "assistant",
    sdk.WithStateStore(store),
)
if errors.Is(err, sdk.ErrConversationNotFound) {
    // Start new conversation
    conv, _ = sdk.Open("./chat.pack.json", "assistant",
        sdk.WithStateStore(store),
        sdk.WithConversationID("session-123"),
    )
}

Resume requires a state store to be configured. If no state store is provided, it returns ErrNoStateStore.

func (*Conversation) CheckPending added in v1.1.5

func (c *Conversation) CheckPending(
	name string,
	args map[string]any,
) (*sdktools.PendingToolCall, bool)

CheckPending checks if a tool call should be pending and creates it if so. Returns (pending call, should wait) - if should wait is true, the tool shouldn't execute yet.

This method is used internally when processing tool calls from the LLM. It can also be useful for testing HITL workflows:

pending, shouldWait := conv.CheckPending("risky_tool", args)
if shouldWait {
    // Tool requires approval
}

func (*Conversation) Clear added in v1.1.5

func (c *Conversation) Clear() error

Clear removes all messages from the conversation history.

This keeps the system prompt and variables but removes all user/assistant messages. Useful for starting fresh within the same conversation session. In duplex mode, this will close the session first if actively streaming.

func (*Conversation) Close added in v1.1.5

func (c *Conversation) Close() error

Close releases resources associated with the conversation.

After Close is called, Send and Stream will return ErrConversationClosed. It's safe to call Close multiple times.

func (*Conversation) Continue

func (c *Conversation) Continue(ctx context.Context) (*Response, error)

Continue resumes conversation after resolving pending tools.

Call this after approving/rejecting all pending tools to continue the conversation with the tool results:

resp, _ := conv.Send(ctx, "Process refund")
for _, pending := range resp.PendingTools() {
    conv.ResolveTool(pending.ID)
}
resp, _ = conv.Continue(ctx) // LLM receives tool results

func (*Conversation) Done added in v1.1.6

func (c *Conversation) Done() (<-chan struct{}, error)

Done returns a channel that's closed when the duplex session ends. Only available when the conversation was opened with OpenDuplex().

func (*Conversation) EventBus added in v1.1.5

func (c *Conversation) EventBus() *events.EventBus

EventBus returns the conversation's event bus for observability.

Use this to subscribe to runtime events like tool calls, validations, and provider requests:

conv.EventBus().Subscribe(events.EventToolCallStarted, func(e *events.Event) {
    log.Printf("Tool call: %s", e.Data.(*events.ToolCallStartedData).ToolName)
})

For convenience methods, see the [hooks] package.

func (*Conversation) Fork added in v1.1.5

func (c *Conversation) Fork() *Conversation

Fork creates a copy of the current conversation state.

Use this to explore alternative conversation branches:

conv.Send(ctx, "I want to plan a trip")
conv.Send(ctx, "What cities should I visit?")

// Fork to explore different paths
branch := conv.Fork()

conv.Send(ctx, "Tell me about Tokyo")     // Original path
branch.Send(ctx, "Tell me about Kyoto")   // Branch path

The forked conversation is completely independent - changes to one do not affect the other.

func (*Conversation) GetVar added in v1.1.5

func (c *Conversation) GetVar(name string) (string, bool)

GetVar returns the current value of a template variable. Returns empty string and false if the variable is not set.

func (*Conversation) ID added in v1.1.5

func (c *Conversation) ID() string

ID returns the conversation's unique identifier.

func (*Conversation) Messages added in v1.1.5

func (c *Conversation) Messages(ctx context.Context) []types.Message

Messages returns the conversation history.

The returned slice is a copy - modifying it does not affect the conversation.

func (*Conversation) OnTool added in v1.1.5

func (c *Conversation) OnTool(name string, handler ToolHandler)

OnTool registers a handler for a tool defined in the pack.

The tool name must match a tool defined in the pack's tools section. When the LLM calls the tool, your handler receives the parsed arguments and returns a result.

conv.OnTool("get_weather", func(args map[string]any) (any, error) {
    city := args["city"].(string)
    return weatherAPI.GetCurrent(city)
})

The handler's return value is automatically serialized to JSON and sent back to the LLM as the tool result.

func (*Conversation) OnToolAsync added in v1.1.5

func (c *Conversation) OnToolAsync(
	name string,
	checkFunc func(args map[string]any) sdktools.PendingResult,
	execFunc ToolHandler,
)

OnToolAsync registers a handler that may require approval before execution.

Use this for Human-in-the-Loop (HITL) workflows where certain actions require human approval before proceeding:

conv.OnToolAsync("process_refund", func(args map[string]any) sdk.PendingResult {
    amount := args["amount"].(float64)
    if amount > 1000 {
        return sdk.PendingResult{
            Reason:  "high_value_refund",
            Message: fmt.Sprintf("Refund of $%.2f requires approval", amount),
        }
    }
    return sdk.PendingResult{} // Proceed immediately
}, func(args map[string]any) (any, error) {
    // Execute the actual refund
    return refundAPI.Process(args)
})

The first function checks if approval is needed, the second executes the action.

func (*Conversation) OnToolCtx added in v1.1.5

func (c *Conversation) OnToolCtx(name string, handler ToolHandlerCtx)

OnToolCtx registers a context-aware handler for a tool.

Use this when your tool implementation needs the request context for cancellation, deadlines, or tracing:

conv.OnToolCtx("search_db", func(ctx context.Context, args map[string]any) (any, error) {
    return db.SearchWithContext(ctx, args["query"].(string))
})

func (*Conversation) OnToolExecutor added in v1.1.5

func (c *Conversation) OnToolExecutor(name string, executor tools.Executor)

OnToolExecutor registers a custom executor for tools.

Use this when you need full control over tool execution or want to use a runtime executor directly:

executor := &MyCustomExecutor{}
conv.OnToolExecutor("custom_tool", executor)

The executor must implement the runtime/tools.Executor interface.

func (*Conversation) OnToolHTTP added in v1.1.5

func (c *Conversation) OnToolHTTP(name string, config *sdktools.HTTPToolConfig)

OnToolHTTP registers a tool that makes HTTP requests.

This is a convenience method for tools that call external APIs:

conv.OnToolHTTP("create_ticket", sdktools.NewHTTPToolConfig(
    "https://api.tickets.example.com/tickets",
    sdktools.WithMethod("POST"),
    sdktools.WithHeader("Authorization", "Bearer "+apiKey),
    sdktools.WithTimeout(5000),
))

The tool arguments from the LLM are serialized to JSON and sent as the request body. The response is parsed and returned to the LLM.

func (*Conversation) OnTools added in v1.1.5

func (c *Conversation) OnTools(handlers map[string]ToolHandler)

OnTools registers multiple tool handlers at once.

conv.OnTools(map[string]sdk.ToolHandler{
    "get_weather":   getWeatherHandler,
    "search_docs":   searchDocsHandler,
    "send_email":    sendEmailHandler,
})

func (*Conversation) PendingTools added in v1.1.5

func (c *Conversation) PendingTools() []*sdktools.PendingToolCall

PendingTools returns all pending tool calls awaiting approval.

func (*Conversation) RejectTool added in v1.1.5

func (c *Conversation) RejectTool(id, reason string) (*sdktools.ToolResolution, error)

RejectTool rejects a pending tool call.

Use this when the human reviewer decides not to approve the tool:

resp, _ := conv.RejectTool(pending.ID, "Not authorized for this amount")

func (*Conversation) ResolveTool added in v1.1.5

func (c *Conversation) ResolveTool(id string) (*sdktools.ToolResolution, error)

ResolveTool approves and executes a pending tool call.

After calling Send() and receiving pending tools in the response, use this to approve and execute them:

resp, _ := conv.Send(ctx, "Process refund for order #12345")
if len(resp.PendingTools()) > 0 {
    pending := resp.PendingTools()[0]
    // ... get approval ...
    result, _ := conv.ResolveTool(pending.ID)
    // Continue the conversation with the result
    resp, _ = conv.Continue(ctx)
}

func (*Conversation) Response added in v1.1.6

func (c *Conversation) Response() (<-chan providers.StreamChunk, error)

Response returns the response channel for duplex streaming. Only available when the conversation was opened with OpenDuplex().

func (*Conversation) Send

func (c *Conversation) Send(ctx context.Context, message any, opts ...SendOption) (*Response, error)

Send sends a message to the LLM and returns the response.

The message can be a simple string or a *types.Message for multimodal content. Variables are substituted into the system prompt template before sending.

Basic usage:

resp, err := conv.Send(ctx, "Hello!")
if err != nil {
    log.Fatal(err)
}
fmt.Println(resp.Text())

With message options:

resp, err := conv.Send(ctx, "What's in this image?",
    sdk.WithImageFile("/path/to/image.jpg"),
)

Send automatically:

  • Substitutes variables into the system prompt
  • Runs any registered validators
  • Handles tool calls if tools are defined
  • Persists state if a state store is configured

func (*Conversation) SendChunk added in v1.1.6

func (c *Conversation) SendChunk(ctx context.Context, chunk *providers.StreamChunk) error

SendChunk sends a streaming chunk in duplex mode. Only available when the conversation was opened with OpenDuplex().

func (*Conversation) SendFrame added in v1.1.8

func (c *Conversation) SendFrame(ctx context.Context, frame *session.ImageFrame) error

SendFrame sends an image frame in duplex mode for realtime video scenarios. Only available when the conversation was opened with OpenDuplex().

Example:

frame := &session.ImageFrame{
    Data:      jpegBytes,
    MIMEType:  "image/jpeg",
    Timestamp: time.Now(),
}
conv.SendFrame(ctx, frame)

func (*Conversation) SendText added in v1.1.6

func (c *Conversation) SendText(ctx context.Context, text string) error

SendText sends text in duplex mode. Only available when the conversation was opened with OpenDuplex().

func (*Conversation) SendVideoChunk added in v1.1.8

func (c *Conversation) SendVideoChunk(ctx context.Context, chunk *session.VideoChunk) error

SendVideoChunk sends a video chunk in duplex mode for encoded video streaming. Only available when the conversation was opened with OpenDuplex().

Example:

chunk := &session.VideoChunk{
    Data:       h264Data,
    MIMEType:   "video/h264",
    IsKeyFrame: true,
    Timestamp:  time.Now(),
}
conv.SendVideoChunk(ctx, chunk)

func (*Conversation) SessionError added in v1.1.6

func (c *Conversation) SessionError() error

SessionError returns any error from the duplex session. Only available when the conversation was opened with OpenDuplex(). Note: This is named SessionError to avoid conflict with the Error interface method.

func (*Conversation) SetVar added in v1.1.5

func (c *Conversation) SetVar(name, value string)

SetVar sets a single template variable.

Variables are substituted into the system prompt template:

conv.SetVar("customer_name", "Alice")
// Template: "You are helping {{customer_name}}"
// Becomes: "You are helping Alice"

func (*Conversation) SetVars added in v1.1.5

func (c *Conversation) SetVars(vars map[string]any)

SetVars sets multiple template variables at once.

conv.SetVars(map[string]any{
    "customer_name": "Alice",
    "customer_tier": "premium",
    "max_discount": 20,
})

func (*Conversation) SetVarsFromEnv added in v1.1.5

func (c *Conversation) SetVarsFromEnv(prefix string)

SetVarsFromEnv sets variables from environment variables with a given prefix.

Environment variables matching the prefix are added as template variables with the prefix stripped and converted to lowercase:

// If PROMPTKIT_CUSTOMER_NAME=Alice is set:
conv.SetVarsFromEnv("PROMPTKIT_")
// Sets variable "customer_name" = "Alice"

func (*Conversation) Stream added in v1.1.5

func (c *Conversation) Stream(ctx context.Context, message any, opts ...SendOption) <-chan StreamChunk

Stream sends a message and returns a channel of response chunks.

Use this for real-time streaming of LLM responses:

for chunk := range conv.Stream(ctx, "Tell me a story") {
    if chunk.Error != nil {
        log.Printf("Error: %v", chunk.Error)
        break
    }
    fmt.Print(chunk.Text)
}

The channel is closed when the response is complete or an error occurs. The final chunk (Type == ChunkDone) contains the complete Response.

func (*Conversation) StreamRaw added in v1.1.5

func (c *Conversation) StreamRaw(ctx context.Context, message any) (<-chan streamPkg.Chunk, error)

StreamRaw returns a channel of streaming chunks for use with the stream package. This is a lower-level API that returns stream.Chunk types.

Most users should use Conversation.Stream instead. StreamRaw is useful when working with [stream.Process] or [stream.CollectText].

err := stream.Process(ctx, conv, "Hello", func(chunk stream.Chunk) error {
    fmt.Print(chunk.Text)
    return nil
})

func (*Conversation) ToolRegistry added in v1.1.5

func (c *Conversation) ToolRegistry() *tools.Registry

ToolRegistry returns the underlying tool registry.

This is a power-user method for direct registry access. Tool descriptors are loaded from the pack; this allows inspecting them or registering custom executors.

registry := conv.ToolRegistry().(*tools.Registry)
for _, desc := range registry.Descriptors() {
    fmt.Printf("Tool: %s\n", desc.Name)
}

func (*Conversation) TriggerStart added in v1.1.6

func (c *Conversation) TriggerStart(ctx context.Context, message string) error

TriggerStart sends a text message to make the model initiate the conversation. Use this in ASM mode when you want the model to speak first (e.g., introducing itself). Only available when the conversation was opened with OpenDuplex().

Example:

conv, _ := sdk.OpenDuplex("./assistant.pack.json", "interviewer", ...)
// Start processing responses first
go processResponses(conv.Response())
// Trigger the model to begin
conv.TriggerStart(ctx, "Please introduce yourself and begin the interview.")

type CredentialOption added in v1.1.9

type CredentialOption interface {
	// contains filtered or unexported methods
}

CredentialOption configures credentials for a provider.

func WithCredentialAPIKey added in v1.1.9

func WithCredentialAPIKey(key string) CredentialOption

WithCredentialAPIKey sets an explicit API key.

func WithCredentialEnv added in v1.1.9

func WithCredentialEnv(envVar string) CredentialOption

WithCredentialEnv sets an environment variable name for the credential.

func WithCredentialFile added in v1.1.9

func WithCredentialFile(path string) CredentialOption

WithCredentialFile sets a credential file path.

type InMemoryA2ATaskStore added in v1.1.11

type InMemoryA2ATaskStore struct {
	// contains filtered or unexported fields
}

InMemoryA2ATaskStore is a concurrency-safe, in-memory implementation of A2ATaskStore.

func NewInMemoryA2ATaskStore added in v1.1.11

func NewInMemoryA2ATaskStore() *InMemoryA2ATaskStore

NewInMemoryA2ATaskStore creates a new InMemoryA2ATaskStore.

func (*InMemoryA2ATaskStore) AddArtifacts added in v1.1.11

func (s *InMemoryA2ATaskStore) AddArtifacts(taskID string, artifacts []a2a.Artifact) error

AddArtifacts appends artifacts to a task.

func (*InMemoryA2ATaskStore) Cancel added in v1.1.11

func (s *InMemoryA2ATaskStore) Cancel(taskID string) error

Cancel transitions the task to the canceled state from any non-terminal state.

func (*InMemoryA2ATaskStore) Create added in v1.1.11

func (s *InMemoryA2ATaskStore) Create(taskID, contextID string) (*a2a.Task, error)

Create initializes a new task in the submitted state.

func (*InMemoryA2ATaskStore) Get added in v1.1.11

func (s *InMemoryA2ATaskStore) Get(taskID string) (*a2a.Task, error)

Get retrieves a task by ID.

func (*InMemoryA2ATaskStore) List added in v1.1.11

func (s *InMemoryA2ATaskStore) List(contextID string, limit, offset int) ([]*a2a.Task, error)

List returns tasks matching the given contextID with pagination. If contextID is empty, all tasks are returned. Offset and limit control pagination.

func (*InMemoryA2ATaskStore) SetState added in v1.1.11

func (s *InMemoryA2ATaskStore) SetState(taskID string, state a2a.TaskState, msg *a2a.Message) error

SetState transitions the task to a new state with an optional status message.

type JudgeProvider added in v1.1.11

type JudgeProvider struct {
	// contains filtered or unexported fields
}

JudgeProvider implements handlers.JudgeProvider using an SDK provider.

func NewJudgeProvider added in v1.1.11

func NewJudgeProvider(p providers.Provider) *JudgeProvider

NewJudgeProvider creates a JudgeProvider backed by the given provider.

func (*JudgeProvider) Judge added in v1.1.11

Judge sends the evaluation prompt to an LLM and returns the parsed verdict.

type MCPServerBuilder added in v1.1.5

type MCPServerBuilder struct {
	// contains filtered or unexported fields
}

MCPServerBuilder provides a fluent interface for configuring MCP servers.

func NewMCPServer added in v1.1.5

func NewMCPServer(name, command string, args ...string) *MCPServerBuilder

NewMCPServer creates a new MCP server configuration builder.

server := sdk.NewMCPServer("github", "npx", "@modelcontextprotocol/server-github").
    WithEnv("GITHUB_TOKEN", os.Getenv("GITHUB_TOKEN"))

conv, _ := sdk.Open("./assistant.pack.json", "assistant",
    sdk.WithMCPServer(server),
)

func (*MCPServerBuilder) Build added in v1.1.5

func (b *MCPServerBuilder) Build() mcp.ServerConfig

Build returns the configured server config.

func (*MCPServerBuilder) WithArgs added in v1.1.5

func (b *MCPServerBuilder) WithArgs(args ...string) *MCPServerBuilder

WithArgs appends additional arguments to the MCP server command.

func (*MCPServerBuilder) WithEnv added in v1.1.5

func (b *MCPServerBuilder) WithEnv(key, value string) *MCPServerBuilder

WithEnv adds an environment variable to the MCP server.

type Option added in v1.1.5

type Option func(*config) error

Option configures a Conversation.

func WithA2ATools added in v1.1.11

func WithA2ATools(bridge *a2a.ToolBridge) Option

WithA2ATools registers tools from an A2A a2a.ToolBridge so the LLM can call remote A2A agents as tools.

The bridge must have already discovered agents via a2a.ToolBridge.RegisterAgent. Each agent skill becomes a tool with Mode "a2a" in the tool registry.

Example:

client := a2a.NewClient("https://agent.example.com")
bridge := a2a.NewToolBridge(client)
bridge.RegisterAgent(ctx)

conv, _ := sdk.Open("./assistant.pack.json", "assistant",
    sdk.WithA2ATools(bridge),
)

func WithAPIKey added in v1.1.5

func WithAPIKey(key string) Option

WithAPIKey provides an explicit API key instead of reading from environment.

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithAPIKey(os.Getenv("MY_CUSTOM_KEY")),
)

func WithAutoResize added in v1.1.8

func WithAutoResize(maxWidth, maxHeight int) Option

WithAutoResize is a convenience option that enables image resizing with the specified dimensions. Use this for simple cases; use WithImagePreprocessing for full control.

Example:

conv, _ := sdk.Open("./chat.pack.json", "vision-assistant",
    sdk.WithAutoResize(1024, 1024), // Max 1024x1024
)

func WithAzure added in v1.1.9

func WithAzure(endpoint string, opts ...PlatformOption) Option

WithAzure configures Azure AI services as the hosting platform. This uses the Azure SDK default credential chain (Managed Identity, Azure CLI, etc.).

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithAzure("https://my-resource.openai.azure.com"),
)

func WithBedrock added in v1.1.9

func WithBedrock(region string, opts ...PlatformOption) Option

WithBedrock configures AWS Bedrock as the hosting platform. This uses the AWS SDK default credential chain (IRSA, instance profile, env vars).

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithBedrock("us-west-2"),
)

func WithConversationID added in v1.1.5

func WithConversationID(id string) Option

WithConversationID sets the conversation identifier.

If not set, a unique ID is auto-generated. Set this when you want to use a specific ID for state persistence or tracking.

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithStateStore(store),
    sdk.WithConversationID("user-123-session-456"),
)

func WithDisabledValidators added in v1.1.5

func WithDisabledValidators(names ...string) Option

WithDisabledValidators disables specific validators by name.

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithDisabledValidators("max_length", "banned_words"),
)

func WithEvalDispatcher added in v1.1.11

func WithEvalDispatcher(d evals.EvalDispatcher) Option

WithEvalDispatcher configures the eval dispatcher for running evals.

The dispatcher controls how evals execute:

  • InProcDispatcher: runs evals in-process (simplest, synchronous)
  • EventDispatcher: publishes eval events to an event bus (async)
  • NoOpDispatcher: disables eval execution at the SDK level

Example:

registry := evals.NewEvalTypeRegistry()
runner := evals.NewEvalRunner(registry)
dispatcher := evals.NewInProcDispatcher(runner, nil)

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithEvalDispatcher(dispatcher),
)

func WithEvalRegistry added in v1.1.11

func WithEvalRegistry(r *evals.EvalTypeRegistry) Option

WithEvalRegistry provides a custom eval type registry.

Use this to register custom eval type handlers beyond the built-in ones. If not set, the default registry with all built-in handlers is used.

func WithEventBus added in v1.1.4

func WithEventBus(bus *events.EventBus) Option

WithEventBus provides a shared event bus for observability.

When set, the conversation emits events to this bus. Use this to share an event bus across multiple conversations for centralized logging, metrics, or debugging.

bus := events.NewEventBus()
bus.SubscribeAll(myMetricsCollector)

conv1, _ := sdk.Open("./chat.pack.json", "assistant", sdk.WithEventBus(bus))
conv2, _ := sdk.Open("./chat.pack.json", "assistant", sdk.WithEventBus(bus))

func WithEventStore added in v1.1.6

func WithEventStore(store events.EventStore) Option

WithEventStore configures event persistence for session recording.

When set, all events published through the conversation's event bus are automatically persisted to the store. This enables session replay and analysis.

The event store is automatically attached to the event bus. If no event bus is provided via WithEventBus, a new one is created internally.

Example with file-based storage:

store, _ := events.NewFileEventStore("/var/log/sessions")
defer store.Close()

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithEventStore(store),
)

Example with shared bus and store:

store, _ := events.NewFileEventStore("/var/log/sessions")
bus := events.NewEventBus().WithStore(store)

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithEventBus(bus),
)

func WithImagePreprocessing added in v1.1.8

func WithImagePreprocessing(cfg *stage.ImagePreprocessConfig) Option

WithImagePreprocessing enables automatic image preprocessing before sending to the LLM. This resizes large images to fit within provider limits, reducing token usage and preventing errors.

The default configuration resizes images to max 1024x1024 with 85% quality.

Example with defaults:

conv, _ := sdk.Open("./chat.pack.json", "vision-assistant",
    sdk.WithImagePreprocessing(nil), // Use default settings
)

Example with custom config:

conv, _ := sdk.Open("./chat.pack.json", "vision-assistant",
    sdk.WithImagePreprocessing(&stage.ImagePreprocessConfig{
        Resize: stage.ImageResizeStageConfig{
            MaxWidth:  2048,
            MaxHeight: 2048,
            Quality:   90,
        },
        EnableResize: true,
    }),
)

func WithJSONMode added in v1.1.8

func WithJSONMode() Option

WithJSONMode is a convenience option that enables simple JSON output mode. The model will return valid JSON objects but without schema enforcement. Use WithResponseFormat for more control including schema validation.

Example:

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithJSONMode(),
)
resp, _ := conv.Send(ctx, "List 3 colors as JSON")
// Response: {"colors": ["red", "green", "blue"]}

func WithJudgeProvider added in v1.1.11

func WithJudgeProvider(jp handlers.JudgeProvider) Option

WithJudgeProvider configures the LLM judge provider for judge-based evals.

If not set, an SDKJudgeProvider is created automatically using the conversation's provider.

func WithMCP added in v1.1.5

func WithMCP(name, command string, args ...string) Option

WithMCP adds an MCP (Model Context Protocol) server for tool execution.

MCP servers provide external tools that can be called by the LLM. The server is started automatically when the conversation opens and stopped when the conversation is closed.

Basic usage:

conv, _ := sdk.Open("./assistant.pack.json", "assistant",
    sdk.WithMCP("filesystem", "npx", "@modelcontextprotocol/server-filesystem", "/path"),
)

With environment variables:

conv, _ := sdk.Open("./assistant.pack.json", "assistant",
    sdk.WithMCP("github", "npx", "@modelcontextprotocol/server-github").
        WithEnv("GITHUB_TOKEN", os.Getenv("GITHUB_TOKEN")),
)

Multiple servers:

conv, _ := sdk.Open("./assistant.pack.json", "assistant",
    sdk.WithMCP("filesystem", "npx", "@modelcontextprotocol/server-filesystem", "/path"),
    sdk.WithMCP("memory", "npx", "@modelcontextprotocol/server-memory"),
)

func WithMCPServer added in v1.1.5

func WithMCPServer(builder *MCPServerBuilder) Option

WithMCPServer adds a pre-configured MCP server.

server := sdk.NewMCPServer("github", "npx", "@modelcontextprotocol/server-github").
    WithEnv("GITHUB_TOKEN", os.Getenv("GITHUB_TOKEN"))

conv, _ := sdk.Open("./assistant.pack.json", "assistant",
    sdk.WithMCPServer(server),
)

func WithModel added in v1.1.5

func WithModel(model string) Option

WithModel overrides the default model specified in the pack.

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithModel("gpt-4o"),
)

func WithProvider

func WithProvider(p providers.Provider) Option

WithProvider uses a custom provider instance.

This bypasses auto-detection and uses the provided provider directly. Use this for custom provider implementations or when you need full control over provider configuration.

provider := openai.NewProvider(openai.Config{...})
conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithProvider(provider),
)

func WithRelevanceTruncation added in v1.1.6

func WithRelevanceTruncation(cfg *RelevanceConfig) Option

WithRelevanceTruncation configures embedding-based relevance truncation.

This automatically sets the truncation strategy to "relevance" and configures the embedding provider for semantic similarity scoring.

Example with OpenAI embeddings:

embProvider, _ := openai.NewEmbeddingProvider()
conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithTokenBudget(8000),
    sdk.WithRelevanceTruncation(&sdk.RelevanceConfig{
        EmbeddingProvider: embProvider,
        MinRecentMessages: 3,
        SimilarityThreshold: 0.3,
    }),
)

Example with Gemini embeddings:

embProvider, _ := gemini.NewEmbeddingProvider()
conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithTokenBudget(8000),
    sdk.WithRelevanceTruncation(&sdk.RelevanceConfig{
        EmbeddingProvider: embProvider,
    }),
)

func WithResponseFormat added in v1.1.8

func WithResponseFormat(format *providers.ResponseFormat) Option

WithResponseFormat configures the LLM response format for JSON mode output. This instructs the model to return responses in the specified format.

For simple JSON object output:

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithResponseFormat(&providers.ResponseFormat{
        Type: providers.ResponseFormatJSON,
    }),
)

For structured JSON output with a schema:

schema := json.RawMessage(`{"type":"object","properties":{"name":{"type":"string"}}}`)
conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithResponseFormat(&providers.ResponseFormat{
        Type:       providers.ResponseFormatJSONSchema,
        JSONSchema: schema,
        SchemaName: "person",
        Strict:     true,
    }),
)

func WithResultWriters added in v1.1.11

func WithResultWriters(writers ...evals.ResultWriter) Option

WithResultWriters configures where eval results are sent.

Multiple writers can be provided; they are composed into a CompositeResultWriter.

Example:

mc := evals.NewMetricCollector()
metricWriter := evals.NewMetricResultWriter(mc, defs)

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithEvalDispatcher(dispatcher),
    sdk.WithResultWriters(metricWriter),
)

func WithSkipSchemaValidation added in v1.1.5

func WithSkipSchemaValidation() Option

WithSkipSchemaValidation disables JSON schema validation during pack loading.

By default, packs are validated against the PromptPack JSON schema to ensure they are well-formed. Use this option to skip validation, for example when loading legacy packs or during development.

conv, _ := sdk.Open("./legacy.pack.json", "assistant",
    sdk.WithSkipSchemaValidation(),
)

func WithStateStore

func WithStateStore(store statestore.Store) Option

WithStateStore configures persistent state storage.

When configured, conversation state (messages, metadata) is automatically persisted after each turn and can be resumed later via Resume.

store := statestore.NewRedisStore("redis://localhost:6379")
conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithStateStore(store),
)

func WithStreamingConfig added in v1.1.6

func WithStreamingConfig(streamingConfig *providers.StreamingInputConfig) Option

WithStreamingConfig configures streaming for duplex mode. When set, enables ASM (Audio Streaming Model) mode with continuous bidirectional streaming. When nil (default), uses VAD (Voice Activity Detection) mode with turn-based streaming.

ASM mode is for models with native bidirectional audio support (e.g., gemini-2.0-flash-exp). VAD mode is for standard text-based models with audio transcription.

Example for ASM mode:

conv, _ := sdk.OpenDuplex("./assistant.pack.json", "voice-chat",
    sdk.WithStreamingConfig(&providers.StreamingInputConfig{
        Type:       types.ContentTypeAudio,
        SampleRate: 16000,
        Channels:   1,
    }),
)

func WithStreamingVideo added in v1.1.8

func WithStreamingVideo(cfg *VideoStreamConfig) Option

WithStreamingVideo enables realtime video/image streaming for duplex sessions. This is used for webcam feeds, screen sharing, and continuous frame analysis.

The FrameRateLimitStage is added to the pipeline when TargetFPS > 0, dropping frames to maintain the target frame rate for LLM processing.

Example with defaults (1 FPS):

session, _ := sdk.OpenDuplex("./assistant.pack.json", "vision-chat",
    sdk.WithStreamingVideo(nil), // Use default settings
)

Example with custom config:

session, _ := sdk.OpenDuplex("./assistant.pack.json", "vision-chat",
    sdk.WithStreamingVideo(&sdk.VideoStreamConfig{
        TargetFPS:  2.0,      // 2 frames per second
        MaxWidth:   1280,     // Resize large frames
        MaxHeight:  720,
        Quality:    80,
    }),
)

Sending frames:

for frame := range webcam.Frames() {
    session.SendFrame(ctx, &session.ImageFrame{
        Data:      frame.JPEG(),
        MIMEType:  "image/jpeg",
        Timestamp: time.Now(),
    })
}

func WithStrictValidation added in v1.1.5

func WithStrictValidation() Option

WithStrictValidation makes all validators fail on violation.

Normally, validators respect their fail_on_violation setting from the pack. With strict validation, all validators will cause errors on failure.

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithStrictValidation(),
)

func WithTTS added in v1.1.6

func WithTTS(service tts.Service) Option

WithTTS configures text-to-speech for the Pipeline.

TTS is applied via Pipeline middleware during streaming responses.

conv, _ := sdk.Open("./assistant.pack.json", "voice",
    sdk.WithTTS(tts.NewOpenAI(os.Getenv("OPENAI_API_KEY"))),
)

func WithTokenBudget added in v1.1.5

func WithTokenBudget(tokens int) Option

WithTokenBudget sets the maximum tokens for context (prompt + history).

When the conversation history exceeds this budget, older messages are truncated according to the truncation strategy.

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithTokenBudget(8000),
)

func WithToolRegistry

func WithToolRegistry(registry *tools.Registry) Option

WithToolRegistry provides a pre-configured tool registry.

This is a power-user option for scenarios requiring direct registry access. Tool descriptors are still loaded from the pack; this allows providing custom executors or middleware.

registry := tools.NewRegistry()
registry.RegisterExecutor(&myCustomExecutor{})
conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithToolRegistry(registry),
)

func WithTruncation added in v1.1.5

func WithTruncation(strategy string) Option

WithTruncation sets the truncation strategy for context management.

Strategies:

  • "sliding": Remove oldest messages first (default)

  • "summarize": Summarize old messages before removing

  • "relevance": Remove least relevant messages based on embedding similarity

    conv, _ := sdk.Open("./chat.pack.json", "assistant", sdk.WithTokenBudget(8000), sdk.WithTruncation("summarize"), )

func WithTurnDetector added in v1.1.6

func WithTurnDetector(detector audio.TurnDetector) Option

WithTurnDetector configures turn detection for the Pipeline.

Turn detectors determine when a user has finished speaking in audio sessions.

conv, _ := sdk.Open("./assistant.pack.json", "voice",
    sdk.WithTurnDetector(audio.NewSilenceDetector(500 * time.Millisecond)),
)

func WithVADMode added in v1.1.6

func WithVADMode(sttService stt.Service, ttsService tts.Service, cfg *VADModeConfig) Option

WithVADMode configures VAD mode for voice conversations with standard text-based LLMs. VAD mode processes audio through a pipeline: Audio → VAD → STT → LLM → TTS → Audio

This is an alternative to ASM mode (WithStreamingConfig) for providers without native audio streaming support.

Example:

sttService := stt.NewOpenAI(os.Getenv("OPENAI_API_KEY"))
ttsService := tts.NewOpenAI(os.Getenv("OPENAI_API_KEY"))

conv, _ := sdk.OpenDuplex("./assistant.pack.json", "voice-chat",
    sdk.WithProvider(openai.NewProvider(openai.Config{...})),
    sdk.WithVADMode(sttService, ttsService, nil), // nil uses defaults
)

With custom config:

conv, _ := sdk.OpenDuplex("./assistant.pack.json", "voice-chat",
    sdk.WithProvider(openai.NewProvider(openai.Config{...})),
    sdk.WithVADMode(sttService, ttsService, &sdk.VADModeConfig{
        SilenceDuration: 500 * time.Millisecond,
        Voice:           "nova",
    }),
)

func WithValidationMode added in v1.1.5

func WithValidationMode(mode ValidationMode) Option

WithValidationMode sets how validation failures are handled.

// Suppress validation errors (useful for testing)
conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithValidationMode(sdk.ValidationModeWarn),
)

func WithVariableProvider added in v1.1.6

func WithVariableProvider(p variables.Provider) Option

WithVariableProvider adds a variable provider for dynamic variable resolution.

Variables are resolved before each Send() and merged with static variables. Later providers in the chain override earlier ones with the same key.

conv, _ := sdk.Open("./assistant.pack.json", "support",
    sdk.WithVariableProvider(variables.Time()),
    sdk.WithVariableProvider(variables.State()),
)

func WithVariables added in v1.1.6

func WithVariables(vars map[string]string) Option

WithVariables sets initial variables for template substitution.

These variables are available immediately when the conversation opens, before any messages are sent. Use this for variables that must be set before the first LLM call (e.g., in streaming/ASM mode).

Variables set here override prompt defaults but can be further modified via conv.SetVar() for subsequent messages.

conv, _ := sdk.Open("./assistant.pack.json", "assistant",
    sdk.WithVariables(map[string]string{
        "user_name": "Alice",
        "language": "en",
    }),
)

func WithVertex added in v1.1.9

func WithVertex(region, project string, opts ...PlatformOption) Option

WithVertex configures Google Cloud Vertex AI as the hosting platform. This uses Application Default Credentials (Workload Identity, gcloud auth, etc.).

conv, _ := sdk.Open("./chat.pack.json", "assistant",
    sdk.WithVertex("us-central1", "my-project"),
)

type PackError added in v1.1.5

type PackError struct {
	// Path is the pack file path.
	Path string

	// Cause is the underlying error.
	Cause error
}

PackError represents an error loading or parsing a pack file.

func (*PackError) Error added in v1.1.5

func (e *PackError) Error() string

Error implements the error interface.

func (*PackError) Unwrap added in v1.1.5

func (e *PackError) Unwrap() error

Unwrap returns the underlying error.

type PendingTool added in v1.1.5

type PendingTool struct {
	// Unique identifier for this pending call
	ID string

	// Tool name
	Name string

	// Arguments passed to the tool
	Arguments map[string]any

	// Reason the tool requires approval
	Reason string

	// Human-readable message about why approval is needed
	Message string
}

PendingTool represents a tool call that requires external approval.

type PlatformOption added in v1.1.9

type PlatformOption interface {
	// contains filtered or unexported methods
}

PlatformOption configures a platform for a provider.

func WithPlatformEndpoint added in v1.1.9

func WithPlatformEndpoint(endpoint string) PlatformOption

WithPlatformEndpoint sets a custom endpoint URL.

func WithPlatformProject added in v1.1.9

func WithPlatformProject(project string) PlatformOption

WithPlatformProject sets the cloud project (for Vertex).

func WithPlatformRegion added in v1.1.9

func WithPlatformRegion(region string) PlatformOption

WithPlatformRegion sets the cloud region.

type ProviderError added in v1.1.5

type ProviderError struct {
	// Provider name (e.g., "openai", "anthropic").
	Provider string

	// StatusCode is the HTTP status code if available.
	StatusCode int

	// Message is the error message from the provider.
	Message string

	// Cause is the underlying error.
	Cause error
}

ProviderError represents an error from the LLM provider.

func (*ProviderError) Error added in v1.1.5

func (e *ProviderError) Error() string

Error implements the error interface.

func (*ProviderError) Unwrap added in v1.1.5

func (e *ProviderError) Unwrap() error

Unwrap returns the underlying error.

type RelevanceConfig added in v1.1.6

type RelevanceConfig struct {
	// EmbeddingProvider generates embeddings for similarity scoring.
	// Required for relevance-based truncation.
	EmbeddingProvider providers.EmbeddingProvider

	// MinRecentMessages always keeps the N most recent messages regardless of relevance.
	// Default: 3
	MinRecentMessages int

	// AlwaysKeepSystemRole keeps all system role messages regardless of score.
	// Default: true
	AlwaysKeepSystemRole bool

	// SimilarityThreshold is the minimum score (0.0-1.0) to consider a message relevant.
	// Messages below this threshold are dropped first. Default: 0.0 (no threshold)
	SimilarityThreshold float64

	// QuerySource determines what text to compare messages against.
	// Values: "last_user" (default), "last_n", "custom"
	QuerySource string

	// LastNCount is the number of messages to use when QuerySource is "last_n".
	// Default: 3
	LastNCount int

	// CustomQuery is the query text when QuerySource is "custom".
	CustomQuery string
}

RelevanceConfig configures embedding-based relevance truncation. Used when truncation strategy is "relevance".

type Response

type Response struct {
	// contains filtered or unexported fields
}

Response represents the result of a conversation turn.

Response wraps the assistant's message with convenience methods and additional metadata like timing and validation results.

Basic usage:

resp, _ := conv.Send(ctx, "Hello!")
fmt.Println(resp.Text())           // Text content
fmt.Println(resp.TokensUsed())     // Total tokens
fmt.Println(resp.Cost())           // Total cost in USD

For multimodal responses:

if resp.HasMedia() {
    for _, part := range resp.Parts() {
        if part.Media != nil {
            fmt.Printf("Media: %s\n", part.Media.URL)
        }
    }
}

func (*Response) Cost

func (r *Response) Cost() float64

Cost returns the total cost in USD for this response.

func (*Response) Duration added in v1.1.5

func (r *Response) Duration() time.Duration

Duration returns how long the request took.

func (*Response) HasMedia added in v1.1.5

func (r *Response) HasMedia() bool

HasMedia returns true if the response contains any media content.

func (*Response) HasToolCalls added in v1.1.5

func (r *Response) HasToolCalls() bool

HasToolCalls returns true if the response contains tool calls.

func (*Response) InputTokens added in v1.1.5

func (r *Response) InputTokens() int

InputTokens returns the number of input (prompt) tokens used.

func (*Response) Message added in v1.1.5

func (r *Response) Message() *types.Message

Message returns the underlying runtime Message.

Use this when you need direct access to the message structure, such as for serialization or passing to other runtime components.

func (*Response) OutputTokens added in v1.1.5

func (r *Response) OutputTokens() int

OutputTokens returns the number of output (completion) tokens used.

func (*Response) Parts added in v1.1.5

func (r *Response) Parts() []types.ContentPart

Parts returns all content parts in the response.

Use this for multimodal responses that may contain text, images, audio, or other content types.

func (*Response) PendingTools

func (r *Response) PendingTools() []PendingTool

PendingTools returns tools that are awaiting external approval.

This is used for Human-in-the-Loop (HITL) workflows where certain tools require approval before execution.

func (*Response) Text added in v1.1.5

func (r *Response) Text() string

Text returns the text content of the response.

This is a convenience method that extracts all text parts and joins them. For responses with only text content, this returns the full response. For multimodal responses, use Response.Parts to access all content.

func (*Response) TokensUsed

func (r *Response) TokensUsed() int

TokensUsed returns the total number of tokens used (input + output).

func (*Response) ToolCalls

func (r *Response) ToolCalls() []types.MessageToolCall

ToolCalls returns the tool calls made during this turn.

Tool calls are requests from the LLM to execute functions. If you have registered handlers via Conversation.OnTool, they will be executed automatically and the results sent back to the LLM.

func (*Response) Validations

func (r *Response) Validations() []types.ValidationResult

Validations returns the results of all validators that ran.

Validators are defined in the pack and run automatically on responses. Check this to see which validators passed or failed.

type SendOption added in v1.1.5

type SendOption func(*sendConfig) error

SendOption configures a single Send call.

func WithAudioData added in v1.1.8

func WithAudioData(data []byte, mimeType string) SendOption

WithAudioData attaches audio from raw bytes.

resp, _ := conv.Send(ctx, "Transcribe this audio",
    sdk.WithAudioData(audioBytes, "audio/mp3"),
)

func WithAudioFile added in v1.1.5

func WithAudioFile(path string) SendOption

WithAudioFile attaches audio from a file path.

resp, _ := conv.Send(ctx, "Transcribe this audio",
    sdk.WithAudioFile("/path/to/audio.mp3"),
)

func WithDocumentData added in v1.1.9

func WithDocumentData(data []byte, mimeType string) SendOption

WithDocumentData attaches a document from raw data with the specified MIME type.

resp, _ := conv.Send(ctx, "Review this PDF",
    sdk.WithDocumentData(pdfBytes, types.MIMETypePDF),
)

func WithDocumentFile added in v1.1.9

func WithDocumentFile(path string) SendOption

WithDocumentFile attaches a document from a file path (PDF, Word, markdown, etc.).

resp, _ := conv.Send(ctx, "Analyze this document",
    sdk.WithDocumentFile("contract.pdf"),
)

func WithFile deprecated added in v1.1.5

func WithFile(name string, data []byte) SendOption

WithFile attaches a file with the given name and content.

Deprecated: Use WithDocumentFile or WithDocumentData instead for proper document handling. This function is kept for backward compatibility but should not be used for new code as it cannot properly handle binary files.

resp, _ := conv.Send(ctx, "Analyze this data",
    sdk.WithFile("data.csv", csvBytes),
)

func WithImageData added in v1.1.5

func WithImageData(data []byte, mimeType string, detail ...*string) SendOption

WithImageData attaches an image from raw bytes.

resp, _ := conv.Send(ctx, "What's in this image?",
    sdk.WithImageData(imageBytes, "image/png"),
)

func WithImageFile added in v1.1.5

func WithImageFile(path string, detail ...*string) SendOption

WithImageFile attaches an image from a file path.

resp, _ := conv.Send(ctx, "What's in this image?",
    sdk.WithImageFile("/path/to/image.jpg"),
)

func WithImageURL added in v1.1.5

func WithImageURL(url string, detail ...*string) SendOption

WithImageURL attaches an image from a URL.

resp, _ := conv.Send(ctx, "What's in this image?",
    sdk.WithImageURL("https://example.com/photo.jpg"),
)

func WithVideoData added in v1.1.8

func WithVideoData(data []byte, mimeType string) SendOption

WithVideoData attaches a video from raw bytes.

resp, _ := conv.Send(ctx, "Describe this video",
    sdk.WithVideoData(videoBytes, "video/mp4"),
)

func WithVideoFile added in v1.1.8

func WithVideoFile(path string) SendOption

WithVideoFile attaches a video from a file path.

resp, _ := conv.Send(ctx, "Describe this video",
    sdk.WithVideoFile("/path/to/video.mp4"),
)

type SessionMode added in v1.1.6

type SessionMode int

SessionMode represents the conversation's session mode.

const (
	// UnaryMode for request/response conversations.
	UnaryMode SessionMode = iota
	// DuplexMode for bidirectional streaming conversations.
	DuplexMode
)

type StreamChunk added in v1.1.5

type StreamChunk struct {
	// Type of this chunk
	Type ChunkType

	// Text content (for ChunkText type)
	Text string

	// Tool call (for ChunkToolCall type)
	ToolCall *types.MessageToolCall

	// Media content (for ChunkMedia type)
	Media *types.MediaContent

	// Complete response (for ChunkDone type)
	Message *Response

	// Error (if any occurred)
	Error error
}

StreamChunk represents a single chunk in a streaming response.

type ToolError added in v1.1.5

type ToolError struct {
	// ToolName is the name of the tool that failed.
	ToolName string

	// Cause is the underlying error from the tool handler.
	Cause error
}

ToolError represents an error executing a tool.

func (*ToolError) Error added in v1.1.5

func (e *ToolError) Error() string

Error implements the error interface.

func (*ToolError) Unwrap added in v1.1.5

func (e *ToolError) Unwrap() error

Unwrap returns the underlying error.

type ToolHandler added in v1.1.5

type ToolHandler func(args map[string]any) (any, error)

ToolHandler is a function that executes a tool call. It receives the parsed arguments from the LLM and returns a result.

The args map contains the arguments as specified in the tool's schema. The return value should be JSON-serializable.

conv.OnTool("get_weather", func(args map[string]any) (any, error) {
    city := args["city"].(string)
    return weatherAPI.GetCurrent(city)
})

type ToolHandlerCtx added in v1.1.5

type ToolHandlerCtx func(ctx context.Context, args map[string]any) (any, error)

ToolHandlerCtx is like ToolHandler but receives a context. Use this when your tool implementation needs context for cancellation or deadlines.

conv.OnToolCtx("search_db", func(ctx context.Context, args map[string]any) (any, error) {
    return db.SearchWithContext(ctx, args["query"].(string))
})

type VADModeConfig added in v1.1.6

type VADModeConfig struct {
	// SilenceDuration is how long silence must persist to trigger turn complete.
	// Default: 800ms
	SilenceDuration time.Duration

	// MinSpeechDuration is minimum speech before turn can complete.
	// Default: 200ms
	MinSpeechDuration time.Duration

	// MaxTurnDuration is maximum turn length before forcing completion.
	// Default: 30s
	MaxTurnDuration time.Duration

	// SampleRate is the audio sample rate.
	// Default: 16000
	SampleRate int

	// Language is the language hint for STT (e.g., "en", "es").
	// Default: "en"
	Language string

	// Voice is the TTS voice to use.
	// Default: "alloy"
	Voice string

	// Speed is the TTS speech rate (0.5-2.0).
	// Default: 1.0
	Speed float64
}

VADModeConfig configures VAD (Voice Activity Detection) mode for voice conversations. In VAD mode, the pipeline processes audio through: AudioTurnStage → STTStage → ProviderStage → TTSStage

This enables voice conversations using standard text-based LLMs.

func DefaultVADModeConfig added in v1.1.6

func DefaultVADModeConfig() *VADModeConfig

DefaultVADModeConfig returns sensible defaults for VAD mode.

type ValidationError added in v1.1.5

type ValidationError struct {
	// ValidatorType is the type of validator that failed (e.g., "banned_words").
	ValidatorType string

	// Message describes what validation rule was violated.
	Message string

	// Details contains validator-specific information about the failure.
	Details map[string]any
}

ValidationError represents a validation failure.

func AsValidationError added in v1.1.5

func AsValidationError(err error) (*ValidationError, bool)

AsValidationError checks if an error is a ValidationError and returns it.

resp, err := conv.Send(ctx, message)
if err != nil {
    if vErr, ok := sdk.AsValidationError(err); ok {
        fmt.Printf("Validation failed: %s\n", vErr.ValidatorType)
    }
}

func (*ValidationError) Error added in v1.1.5

func (e *ValidationError) Error() string

Error implements the error interface.

type ValidationMode added in v1.1.5

type ValidationMode int

ValidationMode controls how validation failures are handled.

const (
	// ValidationModeError causes validation failures to return errors (default).
	ValidationModeError ValidationMode = iota

	// ValidationModeWarn logs validation failures but doesn't return errors.
	ValidationModeWarn

	// ValidationModeDisabled skips validation entirely.
	ValidationModeDisabled
)

type VideoStreamConfig added in v1.1.8

type VideoStreamConfig struct {
	// TargetFPS is the target frame rate for streaming.
	// Frames exceeding this rate will be dropped.
	// Default: 1.0 (one frame per second, suitable for most LLM vision scenarios)
	TargetFPS float64

	// MaxWidth is the maximum frame width in pixels.
	// Frames larger than this are resized. 0 means no limit.
	// Default: 0 (no resizing)
	MaxWidth int

	// MaxHeight is the maximum frame height in pixels.
	// Frames larger than this are resized. 0 means no limit.
	// Default: 0 (no resizing)
	MaxHeight int

	// Quality is the JPEG compression quality (1-100) for frame encoding.
	// Higher values = better quality, larger size.
	// Default: 85
	Quality int

	// EnableResize enables automatic frame resizing when dimensions exceed limits.
	// Default: true (resizing enabled when MaxWidth/MaxHeight are set)
	EnableResize bool
}

VideoStreamConfig configures realtime video/image streaming for duplex sessions. This enables webcam feeds, screen sharing, and continuous frame analysis.

func DefaultVideoStreamConfig added in v1.1.8

func DefaultVideoStreamConfig() *VideoStreamConfig

DefaultVideoStreamConfig returns sensible defaults for video streaming.

Directories

Path Synopsis
examples
audio-analysis command
Package main demonstrates audio analysis capabilities with the PromptKit SDK.
Package main demonstrates audio analysis capabilities with the PromptKit SDK.
hello command
Package main demonstrates the simplest PromptKit SDK usage.
Package main demonstrates the simplest PromptKit SDK usage.
hitl command
Package main demonstrates Human-in-the-Loop (HITL) tool approval with the PromptKit SDK.
Package main demonstrates Human-in-the-Loop (HITL) tool approval with the PromptKit SDK.
image-preprocessing command
Package main demonstrates image preprocessing capabilities with the PromptKit SDK.
Package main demonstrates image preprocessing capabilities with the PromptKit SDK.
multimodal command
Package main demonstrates multimodal capabilities with the PromptKit SDK.
Package main demonstrates multimodal capabilities with the PromptKit SDK.
openai-realtime command
Package main demonstrates OpenAI Realtime API streaming with text mode.
Package main demonstrates OpenAI Realtime API streaming with text mode.
realtime-video command
Package main demonstrates realtime video/image streaming with the PromptKit SDK.
Package main demonstrates realtime video/image streaming with the PromptKit SDK.
session-recording command
Package main demonstrates session recording and replay.
Package main demonstrates session recording and replay.
streaming command
Package main demonstrates streaming responses with the PromptKit SDK.
Package main demonstrates streaming responses with the PromptKit SDK.
tools command
Package main demonstrates tool handling with the PromptKit SDK.
Package main demonstrates tool handling with the PromptKit SDK.
vad-demo command
Package main demonstrates Voice Activity Detection (VAD) in PromptKit.
Package main demonstrates Voice Activity Detection (VAD) in PromptKit.
variables command
Package main demonstrates the Variable Providers feature in the PromptKit SDK.
Package main demonstrates the Variable Providers feature in the PromptKit SDK.
Package hooks provides convenience methods for subscribing to SDK events.
Package hooks provides convenience methods for subscribing to SDK events.
internal
pack
Package pack provides internal pack loading functionality.
Package pack provides internal pack loading functionality.
pipeline
Package pipeline provides internal pipeline construction for the SDK.
Package pipeline provides internal pipeline construction for the SDK.
provider
Package provider provides internal provider detection and initialization.
Package provider provides internal provider detection and initialization.
Package session provides session abstractions for managing conversations.
Package session provides session abstractions for managing conversations.
Package stream provides streaming support for SDK v2.
Package stream provides streaming support for SDK v2.
Package tools provides HITL (Human-in-the-Loop) tool support.
Package tools provides HITL (Human-in-the-Loop) tool support.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL