interactions

package
v0.1.0-p8a.2 Latest Latest
Warning

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

Go to latest
Published: Aug 10, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Index

Constants

View Source
const (
	SnapshotSchemaVersion = "interaction_snapshot.v1"
	EventSchemaVersion    = "interaction_event.v1"
	DefaultRetention      = 7 * 24 * time.Hour
	DefaultMaxRecords     = 1000
	DefaultMaxEvents      = 5000
	DefaultMaxBytes       = 2 * 1024 * 1024
	MaxDeliveryAttempts   = 3

	MaxQuestions         = 3
	MaxOptions           = 3
	MaxQuestionIDLength  = 64
	MaxHeaderLength      = 64
	MaxQuestionLength    = 1000
	MaxOptionLabelLength = 64
	MaxDescriptionLength = 500
	MaxAnswerLength      = 16 * 1024
	MaxSummaryLength     = 1000
	MaxApprovalAction    = 2000
	MaxExecutionContext  = 64 * 1024
)

Variables

View Source
var (
	ErrStoreUnavailable   = errors.New("interaction store unavailable")
	ErrNotFound           = errors.New("interaction not found")
	ErrConflict           = errors.New("interaction revision conflict")
	ErrInvalidTransition  = errors.New("invalid interaction transition")
	ErrSessionHasActive   = errors.New("session already has an active interaction")
	ErrDuplicateAnswer    = errors.New("answer message already claimed")
	ErrAnswerTooLate      = errors.New("interaction is no longer waiting")
	ErrApprovalExpired    = errors.New("approval expired before consumption")
	ErrSnapshotOverBudget = errors.New("interaction snapshot exceeds size budget")
	ErrInvalidInteraction = errors.New("invalid interaction")
	ErrCapacityExceeded   = errors.New("interaction registry capacity exceeded")
)

Functions

func HashArguments

func HashArguments(workspace string, arguments map[string]any) (string, error)

HashArguments returns a restart-stable fingerprint without persisting raw tool arguments. The workspace-local key prevents guessing low-entropy secrets from hashes stored in interaction records.

func HashArgumentsAtPath

func HashArgumentsAtPath(keyPath string, arguments map[string]any) (string, error)

HashArgumentsAtPath creates a durable approval binding using an exact runtime-owned key path.

func ValidateArgumentHashKey

func ValidateArgumentHashKey(path string) error

ValidateArgumentHashKey reports malformed existing runtime key material.

func ValidateSnapshot

func ValidateSnapshot(storePath string) error

ValidateSnapshot reads and validates a registry snapshot without locking, pruning, or writing it.

func ValidateSuspensionRequest

func ValidateSuspensionRequest(request SuspensionRequest) error

ValidateSuspensionRequest validates model- or policy-produced prompt data. Trusted route and origin data are deliberately absent from this contract.

func WorkspaceStorePath

func WorkspaceStorePath(workspace string) string

Types

type Answer

type Answer struct {
	Text       string            `json:"text,omitempty"`
	Values     map[string]string `json:"values,omitempty"`
	MessageID  string            `json:"message_id,omitempty"`
	ReceivedAt int64             `json:"received_at"`
}

type CreateRequest

type CreateRequest struct {
	ID             string
	Kind           Kind
	Route          Route
	Origin         Origin
	Questions      []Question
	PromptSummary  string
	ApprovalAction string
	ExpiresAt      time.Time
}

type DeliveryState

type DeliveryState string
const (
	DeliveryStateNotSent   DeliveryState = "not_sent"
	DeliveryStateSending   DeliveryState = "sending"
	DeliveryStateDelivered DeliveryState = "delivered"
	DeliveryStateAmbiguous DeliveryState = "ambiguous"
)

type Event

type Event struct {
	SchemaVersion  string    `json:"schema_version"`
	EventID        string    `json:"event_id"`
	CommitSequence uint64    `json:"commit_sequence,omitempty"`
	InteractionID  string    `json:"interaction_id"`
	Type           EventType `json:"type"`
	From           Status    `json:"from,omitempty"`
	To             Status    `json:"to,omitempty"`
	Outcome        Outcome   `json:"outcome,omitempty"`
	Revision       int64     `json:"revision"`
	Sequence       int64     `json:"sequence"`
	EmittedAt      int64     `json:"emitted_at"`
	Code           string    `json:"code,omitempty"`
	Success        *bool     `json:"success,omitempty"`
}

type EventObservation

type EventObservation struct {
	Event  Event
	Record Record
}

type EventType

type EventType string
const (
	EventCreated          EventType = "interaction.created"
	EventDeliveryAttempt  EventType = "interaction.delivery_attempted"
	EventFinalDelivery    EventType = "interaction.final_delivery_attempted"
	EventWaiting          EventType = "interaction.waiting"
	EventAnswerClaimed    EventType = "interaction.answer_claimed"
	EventResumeStarted    EventType = "interaction.resume_started"
	EventApprovalConsumed EventType = "interaction.approval_consumed"
	EventApprovalExpired  EventType = "interaction.approval_expired"
	EventCanceling        EventType = "interaction.canceling"
	EventResolved         EventType = "interaction.resolved"
	EventCancelled        EventType = "interaction.cancelled"
	EventFailed           EventType = "interaction.failed"
	EventRecoveryObserved EventType = "interaction.recovery_observed"
)

type Kind

type Kind string
const (
	KindQuestion Kind = "question"
	KindApproval Kind = "approval"
)

type ObservationSnapshot

type ObservationSnapshot struct {
	Through uint64
	Records []Record
	Events  []Event
}

ObservationSnapshot is the retained registry view at an atomic subscription boundary. Live observations delivered to that subscriber are strictly newer.

type Observer

type Observer func(EventObservation)

type Option

type Option struct {
	Label       string `json:"label"`
	Description string `json:"description,omitempty"`
}

type Options

type Options struct {
	TerminalRetention time.Duration
	MaxRecords        int
	MaxEvents         int
	MaxSnapshotBytes  int
	Now               func() time.Time
}

type Origin

type Origin struct {
	TurnID                 string              `json:"turn_id"`
	ExecutionID            string              `json:"execution_id,omitempty"`
	ToolCallID             string              `json:"tool_call_id"`
	ToolName               string              `json:"tool_name"`
	TaskID                 string              `json:"task_id,omitempty"`
	ContinuationSessionKey string              `json:"continuation_session_key,omitempty"`
	ArgumentHash           string              `json:"argument_hash,omitempty"`
	ExecutionContext       *bus.InboundContext `json:"execution_context,omitempty"`
}

type Outcome

type Outcome string
const (
	OutcomeAnswered        Outcome = "answered"
	OutcomeTimedOut        Outcome = "timed_out"
	OutcomeAllowed         Outcome = "allowed"
	OutcomeDenied          Outcome = "denied"
	OutcomeCanceled        Outcome = "canceled"
	OutcomeDeliveryUnknown Outcome = "delivery_unknown"
)

type Question

type Question struct {
	ID          string   `json:"id"`
	Header      string   `json:"header,omitempty"`
	Question    string   `json:"question"`
	Options     []Option `json:"options,omitempty"`
	MultiSelect bool     `json:"multi_select,omitempty"`
}

type Record

type Record struct {
	ID                  string        `json:"id"`
	ShortID             string        `json:"short_id"`
	Kind                Kind          `json:"kind"`
	Status              Status        `json:"status"`
	Outcome             Outcome       `json:"outcome,omitempty"`
	Revision            int64         `json:"revision"`
	LastEventSeq        int64         `json:"last_event_sequence"`
	Route               Route         `json:"route"`
	Origin              Origin        `json:"origin"`
	Questions           []Question    `json:"questions,omitempty"`
	PromptSummary       string        `json:"prompt_summary,omitempty"`
	ApprovalAction      string        `json:"approval_action,omitempty"`
	Answer              *Answer       `json:"answer,omitempty"`
	CreatedAt           int64         `json:"created_at"`
	UpdatedAt           int64         `json:"updated_at"`
	ExpiresAt           int64         `json:"expires_at"`
	ResolvedAt          int64         `json:"resolved_at,omitempty"`
	CleanupAfter        int64         `json:"cleanup_after,omitempty"`
	DeliveryTries       int           `json:"delivery_tries,omitempty"`
	LastDeliveryAt      int64         `json:"last_delivery_at,omitempty"`
	DeliveryError       string        `json:"delivery_error,omitempty"`
	PromptDelivered     bool          `json:"prompt_delivered,omitempty"`
	PromptDeliveryState DeliveryState `json:"prompt_delivery_state,omitempty"`
	FinalDeliveryTries  int           `json:"final_delivery_tries,omitempty"`
	LastFinalDeliveryAt int64         `json:"last_final_delivery_at,omitempty"`
	FinalDelivered      bool          `json:"final_delivered,omitempty"`
	FinalDeliveryError  string        `json:"final_delivery_error,omitempty"`
	FinalDeliveryState  DeliveryState `json:"final_delivery_state,omitempty"`
	ResumeTries         int           `json:"resume_tries,omitempty"`
	LastResumeAt        int64         `json:"last_resume_at,omitempty"`
	ResumeError         string        `json:"resume_error,omitempty"`
	FailureCode         string        `json:"failure_code,omitempty"`
	FailureDetail       string        `json:"failure_detail,omitempty"`
	ApprovalConsumedAt  int64         `json:"approval_consumed_at,omitempty"`
}

type Registry

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

func NewRegistry

func NewRegistry(storePath string) *Registry

func NewRegistryWithOptions

func NewRegistryWithOptions(storePath string, opts Options) *Registry

func (*Registry) BeginCancellation

func (r *Registry) BeginCancellation(
	id string,
	expectedRevision int64,
	code string,
) (Record, error)

func (*Registry) BeginFinalDelivery

func (r *Registry) BeginFinalDelivery(id string, expectedRevision int64) (Record, error)

func (*Registry) BeginPromptDelivery

func (r *Registry) BeginPromptDelivery(id string, expectedRevision int64) (Record, error)

func (*Registry) Cancel

func (r *Registry) Cancel(id string, expectedRevision int64, code string) (Record, error)

func (*Registry) ClaimAnswer

func (r *Registry) ClaimAnswer(
	id string,
	expectedRevision int64,
	answer Answer,
	outcome Outcome,
) (Record, error)

func (*Registry) ClaimDeliveryUnknown

func (r *Registry) ClaimDeliveryUnknown(id string, expectedRevision int64) (Record, error)

func (*Registry) ClaimOverdue

func (r *Registry) ClaimOverdue(now time.Time) ([]Record, error)

func (*Registry) CompleteCancellation

func (r *Registry) CompleteCancellation(id string, expectedRevision int64) (Record, error)

func (*Registry) CompleteFinalDelivery

func (r *Registry) CompleteFinalDelivery(
	id string,
	expectedRevision int64,
	success bool,
	ambiguous bool,
	detail string,
) (Record, error)

func (*Registry) CompletePromptDelivery

func (r *Registry) CompletePromptDelivery(
	id string,
	expectedRevision int64,
	success bool,
	ambiguous bool,
	detail string,
) (Record, error)

func (*Registry) ConsumeApproval

func (r *Registry) ConsumeApproval(
	id string,
	expectedRevision int64,
	toolCallID string,
	toolName string,
	argumentHash string,
) (Record, error)

ConsumeApproval atomically spends an allow-once decision before the protected tool executes. A consumed approval is never executable again, including after a crash with an uncertain tool outcome.

func (*Registry) Create

func (r *Registry) Create(req CreateRequest) (Record, error)

func (*Registry) Fail

func (r *Registry) Fail(
	id string,
	expectedRevision int64,
	code string,
	detail string,
) (Record, error)

func (*Registry) FindWaitingByRoute

func (r *Registry) FindWaitingByRoute(route Route) []Record

func (*Registry) FindWaitingBySession

func (r *Registry) FindWaitingBySession(sessionKey string) []Record

func (*Registry) Get

func (r *Registry) Get(id string) (Record, bool)

func (*Registry) LastLoadError

func (r *Registry) LastLoadError() error

func (*Registry) List

func (r *Registry) List() []Record

func (*Registry) ListEvents

func (r *Registry) ListEvents(id string) []Event

func (*Registry) ListNonterminal

func (r *Registry) ListNonterminal() []Record

func (*Registry) MarkResuming

func (r *Registry) MarkResuming(id string, expectedRevision int64) (Record, error)

func (*Registry) MarkWaiting

func (r *Registry) MarkWaiting(id string, expectedRevision int64) (Record, error)

func (*Registry) Prune

func (r *Registry) Prune(now time.Time) error

func (*Registry) RecordDeliveryAttempt

func (r *Registry) RecordDeliveryAttempt(
	id string,
	expectedRevision int64,
	success bool,
	detail string,
) (Record, error)

func (*Registry) RecordFinalDeliveryAttempt

func (r *Registry) RecordFinalDeliveryAttempt(
	id string,
	expectedRevision int64,
	success bool,
	detail string,
) (Record, error)

func (*Registry) RecordResumeFailure

func (r *Registry) RecordResumeFailure(
	id string,
	expectedRevision int64,
	detail string,
) (Record, error)

func (*Registry) Resolve

func (r *Registry) Resolve(id string, expectedRevision int64) (Record, error)

func (*Registry) StartFinalDelivery

func (r *Registry) StartFinalDelivery(id string, expectedRevision int64) (Record, error)

StartFinalDelivery crosses the durable no-replay boundary immediately before an external delivery attempt. The preceding definitely-not-sent state remains recoverable after a crash because no channel or parent delivery has started.

func (*Registry) Stats

func (r *Registry) Stats() Stats

func (*Registry) Subscribe

func (r *Registry) Subscribe(observer Observer) func()

func (*Registry) SubscribeSnapshot

func (r *Registry) SubscribeSnapshot(
	observer Observer,
) (ObservationSnapshot, func(), func())

SubscribeSnapshot atomically installs a gated observer and captures retained state. Events committed before the boundary appear only in the snapshot; later commits are buffered in order until the caller applies the snapshot and invokes the returned activate function.

type Route

type Route struct {
	AgentID         string `json:"agent_id"`
	SessionKey      string `json:"session_key"`
	RouteSessionKey string `json:"route_session_key,omitempty"`
	Channel         string `json:"channel"`
	AccountID       string `json:"account_id,omitempty"`
	ChatID          string `json:"chat_id"`
	ChatType        string `json:"chat_type,omitempty"`
	TopicID         string `json:"topic_id,omitempty"`
	SpaceID         string `json:"space_id,omitempty"`
	SpaceType       string `json:"space_type,omitempty"`
	SenderID        string `json:"sender_id"`
}

type Snapshot

type Snapshot struct {
	SchemaVersion  string   `json:"schema_version"`
	CommitSequence uint64   `json:"commit_sequence,omitempty"`
	Records        []Record `json:"records"`
	Events         []Event  `json:"events,omitempty"`
}

type Stats

type Stats struct {
	RecordCount      int
	EventCount       int
	NonterminalCount int
	SnapshotBytes    int
	Retention        time.Duration
	MaxRecords       int
	MaxEvents        int
	MaxSnapshotBytes int
	OverBudget       bool
}

type Status

type Status string
const (
	StatusCreated   Status = "created"
	StatusWaiting   Status = "waiting"
	StatusClaimed   Status = "answer_claimed"
	StatusResuming  Status = "resuming"
	StatusCanceling Status = "canceling"
	StatusResolved  Status = "resolved"
	//nolint:misspell // External interaction status follows the existing task status spelling.
	StatusCancelled Status = "cancelled"
	StatusFailed    Status = "failed"
)

type Store

type Store interface {
	Create(CreateRequest) (Record, error)
	Get(string) (Record, bool)
	ListNonterminal() []Record
	FindWaitingByRoute(Route) []Record
	Prune(time.Time) error
}

Store is the durable boundary consumed by tools, routing, and recovery. Implementations must preserve revision-based compare-and-swap semantics.

type SuspensionRequest

type SuspensionRequest struct {
	Kind          Kind
	Questions     []Question
	PromptSummary string
	Timeout       time.Duration
}

SuspensionRequest is the authority-free payload a tool or trusted policy returns when execution must pause for human input. The runtime supplies the route, sender, turn, and tool-call identity before creating a durable record.

type WorkspaceCatalog

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

WorkspaceCatalog records workspace-local interaction stores so restart recovery can find stores whose agents are no longer configured.

func NewWorkspaceCatalog

func NewWorkspaceCatalog(stateRoot string) *WorkspaceCatalog

func (*WorkspaceCatalog) List

func (c *WorkspaceCatalog) List() ([]string, error)

List returns valid catalog entries and a joined diagnostic for malformed entries. Valid entries remain usable when another entry is damaged.

func (*WorkspaceCatalog) Register

func (c *WorkspaceCatalog) Register(workspace string) error

func (*WorkspaceCatalog) Remove

func (c *WorkspaceCatalog) Remove(workspace string) error

Jump to

Keyboard shortcuts

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