API Reference
Constructor
New
func New(processor Processor, emitter Emitter, opts ...Option) *Chat
Creates a new Chat with the given processor and emitter.
Both processor and emitter are required. Passing nil for either is undefined behavior (future versions may return an error).
Options are applied in order. If no session is provided via WithSession, a new zyn.Session is created. If a system prompt is configured, it's appended to the session as a system message.
Emits ChatCreated signal on creation.
chat := chit.New(processor, emitter,
chit.WithSystemPrompt("You are helpful."),
chit.WithMetadata(map[string]any{"user": "123"}),
)
Chat Methods
Handle
func (c *Chat) Handle(ctx context.Context, input string) error
Processes user input through the conversation lifecycle.
If a continuation exists from a previous Yield, it's called with the input. Otherwise, the processor is called.
The result determines what happens next:
*Response: Content is emitted and added to session*Yield: Prompt is emitted and continuation is stored
Returns any error from the processor, continuation, or emitter.
Signals emitted:
InputReceived— at startProcessingStarted— before calling processor/continuationTurnResumed— if resuming from continuationProcessingCompleted— on successProcessingFailed— on errorResponseEmitted— when emitting responseTurnYielded— when storing continuation
err := chat.Handle(ctx, "Hello!")
if err != nil {
log.Printf("handle failed: %v", err)
}
ID
func (c *Chat) ID() string
Returns the unique identifier for this Chat. Generated via uuid.New() at creation.
chatID := chat.ID()
log.Printf("Chat %s started", chatID)
Session
func (c *Chat) Session() *zyn.Session
Returns the underlying zyn.Session for this Chat.
The session contains conversation history. Modifying it directly is allowed but may lead to inconsistent state if done during Handle.
messages := chat.Session().Messages()
for _, msg := range messages {
fmt.Printf("%s: %s\n", msg.Role, msg.Content)
}
Config
func (c *Chat) Config() *Config
Returns the configuration for this Chat.
Never returns nil — a default empty Config is created if none provided.
if chat.Config().SystemPrompt != "" {
log.Printf("Using system prompt: %s", chat.Config().SystemPrompt)
}
HasContinuation
func (c *Chat) HasContinuation() bool
Returns true if the Chat is awaiting input to resume a previously yielded processing step.
Thread-safe.
if chat.HasContinuation() {
fmt.Println("Waiting for user response...")
}
GetPipeline
func (c *Chat) GetPipeline() pipz.Chainable[*ChatRequest]
Returns the internal pipeline for composition.
Implements ChatProvider for use with WithFallback.
fallbackChat := chit.New(fallbackProcessor, emitter)
mainChat := chit.New(processor, emitter,
chit.WithFallback(fallbackChat),
)
Configuration Options
WithConfig
func WithConfig(config *Config) Option
Sets the complete configuration for the Chat.
Replaces any existing config. Use WithSystemPrompt or WithMetadata for partial updates.
chat := chit.New(processor, emitter, chit.WithConfig(&chit.Config{
SystemPrompt: "Be concise.",
Metadata: map[string]any{"version": "2.0"},
}))
WithSystemPrompt
func WithSystemPrompt(prompt string) Option
Sets the system prompt for the Chat.
Creates a Config if none exists. The prompt is appended to the session as a system message during Chat creation.
chat := chit.New(processor, emitter,
chit.WithSystemPrompt("You are a helpful assistant."),
)
WithSession
func WithSession(session *zyn.Session) Option
Sets a pre-existing session for the Chat.
Use this for session persistence or to provide pre-populated conversation history. If not provided, a new session is created.
Note: If both WithSession and WithSystemPrompt are used, the system prompt is appended to the provided session.
session := zyn.NewSession()
session.Append("user", "Previous message")
chat := chit.New(processor, emitter, chit.WithSession(session))
WithMetadata
func WithMetadata(metadata map[string]any) Option
Sets metadata on the Chat's configuration.
Creates a Config if none exists. Useful for passing application-specific data like user IDs or request context.
chat := chit.New(processor, emitter, chit.WithMetadata(map[string]any{
"user_id": "123",
"request_id": "abc-def",
}))
Pipeline Options
WithRetry
func WithRetry(maxAttempts int) Option
Adds retry logic to the pipeline. Failed requests are retried up to maxAttempts times.
chat := chit.New(processor, emitter, chit.WithRetry(3))
WithBackoff
func WithBackoff(maxAttempts int, baseDelay time.Duration) Option
Adds retry logic with exponential backoff. Delays double after each failure.
chat := chit.New(processor, emitter, chit.WithBackoff(3, 100*time.Millisecond))
WithTimeout
func WithTimeout(duration time.Duration) Option
Adds timeout protection. Operations exceeding the duration are canceled.
chat := chit.New(processor, emitter, chit.WithTimeout(30*time.Second))
WithCircuitBreaker
func WithCircuitBreaker(failures int, recovery time.Duration) Option
Adds circuit breaker protection. After failures consecutive failures, the circuit opens for recovery duration.
chat := chit.New(processor, emitter, chit.WithCircuitBreaker(5, 30*time.Second))
WithRateLimit
func WithRateLimit(rps float64, burst int) Option
Adds rate limiting. rps is requests per second, burst is burst capacity.
chat := chit.New(processor, emitter, chit.WithRateLimit(10, 5))
WithErrorHandler
func WithErrorHandler(handler pipz.Chainable[*pipz.Error[*ChatRequest]]) Option
Adds error handling pipeline for observability.
errorHandler := pipz.Effect(id, func(ctx context.Context, err *pipz.Error[*chit.ChatRequest]) error {
log.Printf("Error: %v", err.Err)
return nil
})
chat := chit.New(processor, emitter, chit.WithErrorHandler(errorHandler))
WithFallback
func WithFallback(fallback ChatProvider) Option
Adds a fallback processor for resilience. If the primary fails, the fallback is tried.
fallback := chit.New(fallbackProcessor, emitter)
chat := chit.New(processor, emitter, chit.WithFallback(fallback))
WithMiddleware
func WithMiddleware(processors ...pipz.Chainable[*ChatRequest]) Option
Adds pre-processing steps before the terminal. Processors run in order.
chat := chit.New(processor, emitter,
chit.WithMiddleware(
chit.UseValidation(4096),
chit.UseLogging(logger),
),
)
Middleware Helpers
UseValidation
func UseValidation(maxLength int) pipz.Chainable[*ChatRequest]
Creates middleware that validates input length. Returns error if input exceeds maxLength or is empty.
UseLogging
func UseLogging(logger *slog.Logger) pipz.Chainable[*ChatRequest]
Creates middleware that logs requests using slog.
UseMetrics
func UseMetrics(recorder MetricsRecorder) pipz.Chainable[*ChatRequest]
Creates middleware that records metrics via the MetricsRecorder interface.
UseEnrich
func UseEnrich(enricher Enricher) pipz.Chainable[*ChatRequest]
Creates middleware that enriches requests. Best-effort: returns original on error.
UseApply
func UseApply(id pipz.Identity, fn func(context.Context, *ChatRequest) (*ChatRequest, error)) pipz.Chainable[*ChatRequest]
Creates custom middleware using pipz.Apply. Can transform or fail.
UseEffect
func UseEffect(id pipz.Identity, fn func(context.Context, *ChatRequest) error) pipz.Chainable[*ChatRequest]
Creates custom middleware using pipz.Effect. Side effect only.
UseTransform
func UseTransform(id pipz.Identity, fn func(context.Context, *ChatRequest) *ChatRequest) pipz.Chainable[*ChatRequest]
Creates custom middleware using pipz.Transform. Cannot fail.
UseMutate
func UseMutate(id pipz.Identity, fn func(context.Context, *ChatRequest) *ChatRequest, condition func(context.Context, *ChatRequest) bool) pipz.Chainable[*ChatRequest]
Creates conditional middleware. Transformation only applies if condition returns true.
Context Helpers
WithEmitter
func WithEmitter(ctx context.Context, e Emitter) context.Context
Returns a new context with the given Emitter attached.
Called automatically by Chat before invoking the processor. Use manually when testing processors in isolation.
ctx := chit.WithEmitter(context.Background(), myEmitter)
result, err := processor.Process(ctx, input, session)
EmitterFromContext
func EmitterFromContext(ctx context.Context) Emitter
Retrieves the Emitter from the context.
Returns nil if no Emitter is present. Processors use this to push resources during processing.
if emitter := chit.EmitterFromContext(ctx); emitter != nil {
emitter.Push(ctx, chit.Resource{
Type: "data",
URI: "db://users/123",
})
}
Next Steps
- Types Reference — type definitions and fields
- Concepts — mental models
- Testing Guide — test helpers