domain

package
v0.7.17 Latest Latest
Warning

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

Go to latest
Published: Mar 6, 2026 License: AGPL-3.0 Imports: 5 Imported by: 1

Documentation

Overview

Package domain contains the core domain models and business logic for the Trellis engine.

It defines the fundamental entities of the state machine, such as Nodes, Transitions, and the Execution State. This package is kept pure and free of external dependencies like I/O or persistence, following Hexagonal Architecture principles.

Key Entities

  • Node: Represents a point in the graph (Text, Input, or Tool/Action).
  • Transition: Defines the rules for moving from one node to another.
  • State: Captures the runtime snapshot of a session (Current Node, Context, History).
  • ActionRequest: A structural representation of what the host should render or execute.

Index

Constants

View Source
const (
	// ActionRenderContent requests the host to display content to the user.
	// Payload: string (the content)
	ActionRenderContent = "RENDER_CONTENT"

	// ActionRequestInput requests the host to collect input from the user.
	// Payload: InputRequest
	ActionRequestInput = "REQUEST_INPUT"

	// ActionCallTool requests the host to execute a side-effect (tool).
	// Payload: ToolCall
	ActionCallTool = "CALL_TOOL"

	// ActionSystemMessage represents a meta-message from the system (log, status, etc).
	// Payload: string (the message)
	ActionSystemMessage = "SYSTEM_MESSAGE"
)

Standard Action Types

View Source
const (
	// KeyIdempotency is the metadata key used to store the deterministic idempotency key.
	// It is also the JSON field name in the ToolCall struct.
	KeyIdempotency = "idempotency_key"

	// Signal constants representing global events.
	SignalInterrupt = "interrupt" // CTRL+C or explicit cancellation
	SignalShutdown  = "shutdown"  // System termination request (SIGTERM)
	SignalTimeout   = "timeout"   // Node execution deadline exceeded
)

Field constants for mapstructure and JSON standardization.

View Source
const (
	// NodeTypeText displays content and continues immediately (soft step).
	NodeTypeText = "text"
	// NodeTypeQuestion displays content and halts waiting for input (hard step).
	// It is the standard primitive for capturing user data.
	NodeTypeQuestion = "question"

	// NodeTypeTool executes an external side-effect (tool).
	NodeTypeTool = "tool"

	// NodeTypeFormat handles structured content with i18n and conditional logic.
	NodeTypeFormat = "format"

	// NodeTypeStart indicates the entry point (typically convention-based, but can be explicit).
	NodeTypeStart = "start"
)

NodeType constants define the control flow behavior.

View Source
const (
	// DefaultStartNodeID is the standard entry point for a flow.
	DefaultStartNodeID = "start"
	// DefaultErrorNodeID is the standard fallback for tool errors and denials.
	DefaultErrorNodeID = "error"
)

Standard Node ID Conventions

Variables

View Source
var ErrSessionNotFound = errors.New("session not found")

ErrSessionNotFound is returned when a session ID cannot be found in the store.

View Source
var ErrUnhandledSignal = errors.New("unhandled signal")

ErrUnhandledSignal is returned when a signal is received but no handler is defined for it.

Functions

This section is empty.

Types

type ActionRequest

type ActionRequest struct {
	Type    string // e.g., "CLI_PRINT", "HTTP_GET"
	Payload any    // The data needed to perform the action
}

ActionRequest represents a side-effect that the engine requests the host to perform.

type ActionResponse

type ActionResponse struct {
	Success bool
	Data    any
	Error   error
}

ActionResponse represents the result of an ActionRequest.

type EventBase added in v0.5.1

type EventBase struct {
	Timestamp time.Time `json:"timestamp"`
	Type      EventType `json:"type"`
	StateID   string    `json:"state_id"` // Optional execution ID/Correlation ID? For now just keep it simple.
}

EventBase contains common fields for all events.

type EventType added in v0.5.1

type EventType string

EventType defines the category of the event.

const (
	EventNodeEnter  EventType = "node_enter"
	EventNodeLeave  EventType = "node_leave"
	EventToolCall   EventType = "tool_call"
	EventToolReturn EventType = "tool_return"
)

type ExecutionStatus added in v0.4.0

type ExecutionStatus string

ExecutionStatus defines the current mode of the engine mechanics.

const (
	StatusActive         ExecutionStatus = "active"           // Normal operation
	StatusWaitingForTool ExecutionStatus = "waiting_for_tool" // Engine is paused, waiting for Host result
	StatusRollingBack    ExecutionStatus = "rolling_back"     // Engine is unwinding history (SAGA)
	StatusTerminated     ExecutionStatus = "terminated"       // Sink state reached
)

type FormatItem added in v0.7.17

type FormatItem struct {
	Text      string `json:"text" yaml:"text" mapstructure:"text"`
	Condition string `json:"condition,omitempty" yaml:"condition,omitempty" mapstructure:"condition"`
}

FormatItem represents a single piece of content within a "format" node.

type HistoryDelta added in v0.7.9

type HistoryDelta struct {
	Appended []string `json:"appended"`
}

HistoryDelta represents changes to the history stack.

type InputRequest added in v0.3.2

type InputRequest struct {
	Type    InputType     `json:"type"`
	Options []string      `json:"options,omitempty"`
	Default string        `json:"default,omitempty"`
	Timeout time.Duration `json:"timeout,omitempty"` // Parsed duration (e.g. 5s)
}

InputRequest describes the constraints and type of input needed.

type InputType added in v0.3.2

type InputType string

InputType defines the kind of input requested.

const (
	InputText    InputType = "text"
	InputConfirm InputType = "confirm"
	InputChoice  InputType = "choice"
)

type LifecycleHooks added in v0.5.1

type LifecycleHooks struct {
	OnNodeEnter  func(context.Context, *NodeEvent)
	OnNodeLeave  func(context.Context, *NodeEvent)
	OnToolCall   func(context.Context, *ToolEvent)
	OnToolReturn func(context.Context, *ToolEvent)
}

LifecycleHooks defines callbacks for engine observability.

type Node

type Node struct {
	ID   string `json:"id" yaml:"id"`
	Type string `json:"type" yaml:"type"` // e.g., "text", "question", "logic", "tool"
	// Wait indicates if the engine should pause for input after rendering.
	Wait bool `json:"wait" yaml:"wait"`
	// SaveTo indicates the variable name in Context where input should be stored.
	SaveTo string `json:"save_to,omitempty" yaml:"save_to,omitempty"`

	// RequiredContext lists keys that MUST exist in the context for this node to execute.
	RequiredContext []string `json:"required_context,omitempty" yaml:"required_context,omitempty"`

	// DefaultContext provides fallback values for context keys
	DefaultContext map[string]any `json:"default_context,omitempty" yaml:"default_context,omitempty"`

	// ContextSchema defines expected types for context values
	ContextSchema schema.Schema `json:"context_schema,omitempty" yaml:"context_schema,omitempty"`

	// Content holds the raw data for this node.
	// For a text node, it might be the markdown content.
	// For a logic node, it might be the script or parameters.
	Content []byte `json:"content" yaml:"content"`

	// Metadata allows for extensible key-value pairs.
	Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"`

	// Transitions defines the possible paths from this node.
	Transitions []Transition `json:"transitions" yaml:"transitions"`

	// OnError defines the node ID to transition to if a Tool returns an error.
	OnError string `json:"on_error,omitempty" yaml:"on_error,omitempty"`

	// OnDenied defines the node ID to transition to if a Tool execution is denied by policy.
	OnDenied string `json:"on_denied,omitempty" yaml:"on_denied,omitempty"`

	// OnSignal defines transitions triggered by global signals (e.g., "interrupt").
	OnSignal map[string]string `json:"on_signal,omitempty" yaml:"on_signal,omitempty"`

	// OnSignalDefault defines global signal handlers (usually defined only on the root/entry node).
	OnSignalDefault map[string]string `json:"on_signal_default,omitempty" yaml:"on_signal_default,omitempty"`

	// Input Configuration (Optional)
	InputType    string   `json:"input_type,omitempty" yaml:"input_type,omitempty"`
	InputOptions []string `json:"input_options,omitempty" yaml:"input_options,omitempty"`
	InputDefault string   `json:"input_default,omitempty" yaml:"input_default,omitempty"`

	// Tool Configuration (Optional, used if Type == "tool")
	// Do defines the primary action to execute.
	Do *ToolCall `json:"do,omitempty" yaml:"do,omitempty"`

	// Tools defined within this node (e.g. for LLM context)
	Tools []Tool `json:"tools,omitempty" yaml:"tools,omitempty"`

	// Undo defines the compensating action (SAGA pattern) to revert this node's effect.
	// It is triggered if the engine enters rollback mode.
	Undo *ToolCall `json:"undo,omitempty" yaml:"undo,omitempty"`

	// Messages provides a dictionary of content by locale for i18n support.
	// Used when Type == "format".
	Messages map[string][]FormatItem `json:"messages,omitempty" yaml:"messages,omitempty"`

	// Timeout defines the maximum duration (e.g. "30s") to wait for input.
	Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
}

Node represents a logical unit in the graph. It can contain text content (for Wiki-style) or logic instructions (for Logic-style).

type NodeEvent added in v0.5.1

type NodeEvent struct {
	EventBase
	NodeID   string `json:"node_id"`
	NodeType string `json:"node_type"`
}

NodeEvent represents entry or exit from a node.

type State

type State struct {
	// SessionID uniquely identifies the session this state belongs to.
	SessionID string `json:"session_id"`

	// CurrentNodeID is the identifier of the active node.
	CurrentNodeID string `json:"current_node_id"`

	// Status indicates if the engine is running, waiting, or done.
	Status ExecutionStatus `json:"status"`

	// PendingToolCall holds the ID of the tool call we are waiting for (if Status == WaitingForTool).
	PendingToolCall string `json:"pending_tool_call,omitempty"`

	// Context holds variable state for the session (User space).
	Context map[string]any `json:"context"`

	// SystemContext holds system-level state (Read-only for templates, Host-writable).
	// Reserved namespace: "sys".
	SystemContext map[string]any `json:"system_context"`

	// Locale identifies the preferred language for the session (e.g., "en", "pt-BR").
	Locale string `json:"locale,omitempty"`

	// History could track the path taken (optional for now, but good for debugging)
	History []string `json:"history,omitempty"`

	// Terminated indicates if the execution has reached a sink state (no transitions).
	// Deprecated: Use Status == StatusTerminated instead. Kept for backward compat.
	Terminated bool `json:"terminated,omitempty"`
}

State represents the current snapshot of the execution.

func NewState

func NewState(sessionID, startNodeID string) *State

NewState creates a clean state starting at a specific node.

func (*State) Snapshot added in v0.7.5

func (s *State) Snapshot() *State

Snapshot creates a deep copy of the state for observability purposes. This is thread-safe as long as the caller ensures exclusive access to the source state during copying.

type StateDiff added in v0.7.9

type StateDiff struct {
	// SessionID is always present to identify the target.
	SessionID string `json:"session_id"`

	// OldNodeID needed? Maybe not. NewNodeID is enough.
	CurrentNodeID *string `json:"current_node_id,omitempty"`

	// Status changed?
	Status *ExecutionStatus `json:"status,omitempty"`

	// ContextDelta contains only changed, added or deleted keys.
	// For deletions, the key is present with a nil value.
	// Clients should merge these updates into their local state.
	Context map[string]any `json:"context,omitempty"`

	// HistoryDelta contains *new* items appended to history.
	// If history was rewritten (rare), we might send the whole list?
	// Let's optimize for append-only.
	HistoryParams *HistoryDelta `json:"history,omitempty"`

	// Terminated changed?
	Terminated *bool `json:"terminated,omitempty"`
}

StateDiff represents the changes between two states. It is designed to be serialized to JSON for partial updates on the client.

func Diff added in v0.7.9

func Diff(oldState, newState *State) *StateDiff

Diff calculates the difference between oldState and newState. If oldState is nil, it returns a diff representing the entire newState (initial load).

func (*StateDiff) IsEmpty added in v0.7.9

func (d *StateDiff) IsEmpty() bool

IsEmpty checks if the diff contains any actionable changes.

type Tool added in v0.4.0

type Tool struct {
	Name        string         `json:"name" yaml:"name" mapstructure:"name"`
	Description string         `json:"description" yaml:"description" mapstructure:"description"`
	Parameters  map[string]any `json:"parameters,omitempty" yaml:"parameters,omitempty" mapstructure:"parameters"`
}

Tool defines metadata about a tool available to the engine. This is used for generating schemas/prompts.

type ToolCall added in v0.4.0

type ToolCall struct {
	ID             string            `json:"id" yaml:"id" mapstructure:"id"`                                       // Unique ID for this specific call (e.g. from LLM or generated)
	Name           string            `json:"name" yaml:"name" mapstructure:"name"`                                 // Function name to call
	Args           map[string]any    `json:"args,omitempty" yaml:"args,omitempty" mapstructure:"args"`             // Arguments for the function
	Metadata       map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty" mapstructure:"metadata"` // Context/Safety metadata from the Node
	IdempotencyKey string            `json:"idempotency_key,omitempty" yaml:"idempotency_key,omitempty" mapstructure:"idempotency_key"`
}

ToolCall represents a request from the Engine to the Host to perform a side-effect. Ideally compatible with OpenAI/MCP tool call schemas.

type ToolEvent added in v0.5.1

type ToolEvent struct {
	EventBase
	NodeID   string `json:"node_id"`
	ToolName string `json:"tool_name"`
	Input    any    `json:"input,omitempty"`
	Output   any    `json:"output,omitempty"`
	IsError  bool   `json:"is_error,omitempty"`
}

ToolEvent represents a tool execution.

type ToolResult added in v0.4.0

type ToolResult struct {
	ID       string `json:"id"` // Must match the ToolCall.ID
	Result   any    `json:"result,omitempty"`
	IsError  bool   `json:"is_error,omitempty"`
	IsDenied bool   `json:"is_denied,omitempty"`
	Error    string `json:"error,omitempty"`
}

ToolResult represents the output of a side-effect returned by the Host.

type Transition

type Transition struct {
	FromNodeID string `json:"from_node_id,omitempty" yaml:"from,omitempty"`

	ToNodeID string `json:"to_node_id" yaml:"to,omitempty"`

	// Condition is a simple expression string that must evaluate to true
	// for this transition to be valid. e.g., "user_age >= 18"
	// If empty, it's considered an "always" transition (default).
	Condition string `json:"condition,omitempty" yaml:"condition,omitempty"`
}

Transition defines a rule to move from one node to another.

Jump to

Keyboard shortcuts

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