collaboration

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: Apache-2.0, MIT Imports: 15 Imported by: 0

Documentation

Overview

Package collaboration owns durable agent work. Queue notifications are hints; the database is the authority for admission, ownership and cancellation.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrConflict indicates a stale revision or execution lease.
	ErrConflict = errors.New("collaboration changed; refresh its state")
	// ErrClosed indicates that the collaboration no longer accepts work.
	ErrClosed = errors.New("collaboration is closed")
	// ErrScope indicates that the caller cannot access the requested collaboration.
	ErrScope = errors.New("collaboration is outside the caller's scope")
	// ErrHistoryLimit indicates that an active aggregate cannot accept more history.
	ErrHistoryLimit = errors.New("collaboration history limit reached")
)
View Source
var ErrInput = errors.New("wait interrupted by new user input")

ErrInput is a wake reason, never an execution failure. The engine drains the input through its ordinary persistence path before calling the model again.

Functions

func WithBinding

func WithBinding(ctx context.Context, b *Binding) context.Context

WithBinding attaches runtime-owned collaboration authority to the context.

Types

type Binding

type Binding struct {
	ParentOwner string
	// Closing only authorizes transcript finalization, never model/tool execution.
	Closing    bool
	Recovered  bool
	Runtime    *Runtime
	Scope      Scope
	Child      *Work
	Seen       int64
	WaitCursor int64
	WaitUntil  time.Time
	// HasInput probes durable steer without consuming it; the engine owns delivery.
	HasInput func(context.Context) (bool, error)
}

Binding is private runtime authority, never constructed from model arguments. Parent event cursors advance only when the engine puts the event into a model input. wait_agent has its own cursor and cannot acknowledge model processing.

func FromContext

func FromContext(ctx context.Context) *Binding

FromContext returns the collaboration authority associated with this execution.

func (*Binding) BeforeFinish

func (b *Binding) BeforeFinish(ctx context.Context) ([]Event, error)

BeforeFinish either atomically closes the group, or delivers unseen results so the engine must call the model again. Polling always checks durable state first; events committed before waiting are not lost.

func (*Binding) ClearWait

func (b *Binding) ClearWait(ctx context.Context) error

ClearWait removes the owned parent checkpoint after the engine resumes.

func (*Binding) Context

func (b *Binding) Context(ctx context.Context) context.Context

Context adds the parent ownership fence to store operations.

func (*Binding) DeliveredEvents

func (b *Binding) DeliveredEvents(ctx context.Context) ([]Event, error)

DeliveredEvents recovers input omitted by legacy parent snapshots without advancing the cursor or granting execution authority to a cancelled owner.

func (*Binding) End

func (b *Binding) End(suspended bool)

End owns cleanup, including unexpected engine exits and user cancellation. A durable prompt suspension keeps the group open for the resumed engine.

func (*Binding) HasDelegatedWork

func (b *Binding) HasDelegatedWork(ctx context.Context) (bool, error)

HasDelegatedWork reports whether this execution owns delegated work whose failure must be propagated instead of replaced by a fallback answer. Every child does; a parent does only after it has started a child in this turn.

func (*Binding) List

func (b *Binding) List(ctx context.Context, prefix string) ([]MemberView, error)

List lists child states, optionally filtered by task path.

func (*Binding) MessageParent

func (b *Binding) MessageParent(ctx context.Context, key, content string) error

MessageParent publishes an idempotent child message while its execution lease remains valid.

func (*Binding) PendingAnswer

func (b *Binding) PendingAnswer(ctx context.Context) (bool, error)

PendingAnswer prevents an optimistic final answer while delegated work or unseen results still need review. Approval visibility is owned by the UI.

func (*Binding) Poll

func (b *Binding) Poll(ctx context.Context) ([]Event, error)

Poll reads unseen mailbox events and advances the model-delivery cursor.

func (*Binding) SaveWait

func (b *Binding) SaveWait(ctx context.Context, snapshot []byte, until time.Time) error

SaveWait persists a replay-safe checkpoint for the current parent execution.

func (*Binding) Start

func (b *Binding) Start(ctx context.Context) (context.Context, func())

Start renews the parent lease until the returned cleanup function is called.

func (*Binding) Wait

func (b *Binding) Wait(ctx context.Context, after int64, duration time.Duration) (bool, error)

Wait waits for mailbox changes while allowing user steering to interrupt the wait.

type Event

type Event struct {
	Sequence int64  `json:"sequence"`
	From     string `json:"from"`
	RunID    string `json:"run_id,omitempty"`
	Kind     string `json:"kind"`
	Content  string `json:"content"`
}

Event is an ordered, run-correlated mailbox message.

type Group

type Group struct {
	// Revision is the database CAS version, never a caller-provided JSON field.
	Revision        int64 `json:"-"`
	InputBytes      int
	SuccessorID     string // durable admission for a subsequent human turn
	ParentMessageID string
	ParentOwner     string
	ParentLease     time.Time
	ParentWait      *ParentWait
	// ParentClosePending keeps interrupted/expired parents recoverable until their transcript and stream are closed.
	ParentClosePending bool
	RootQuery          string
	Scope              Scope
	Status             string
	Members            []*Member
	Events             []Event
	Requests           map[string]string
	NextSequence       int64
	Deadline           time.Time
}

Group holds the parent state, children and ordered mailbox in one atomic aggregate.

func (*Group) StatusView

func (g *Group) StatusView() StatusSnapshot

StatusView projects durable state into a public snapshot without private execution fields.

type Member

type Member struct {
	// Inherited instances remain addressable across parent turns but are not
	// current-turn UI tasks until explicitly continued.
	Inherited bool   `json:"inherited,omitempty"`
	ID        string `json:"member_id"`
	Name      string `json:"task_name"`
	AgentID   string `json:"agent_id"`
	SessionID string `json:"session_id"`
	// ConfigJSON is stored separately from the model-visible projection.
	ConfigJSON string  `json:"config_snapshot"`
	Runs       []*Run  `json:"runs"`
	Mail       []Event `json:"mail,omitempty"`
}

Member is a named child task with its execution history and incoming mailbox.

type MemberView

type MemberView struct {
	PreviousTurn    bool      `json:"previous_turn,omitempty"`
	Progress        *Progress `json:"progress,omitempty"`
	PromptID        string    `json:"prompt_id,omitempty"`
	ID              string    `json:"member_id"`
	Name            string    `json:"task_name"`
	AgentID         string    `json:"agent_id"`
	SessionID       string    `json:"session_id"`
	RunID           string    `json:"run_id"`
	Status          string    `json:"status"`
	CancelRequested bool      `json:"cancel_requested"`
}

MemberView is the model-visible snapshot of a child and its current execution.

type ParentWait

type ParentWait struct {
	Snapshot []byte
	After    int64
	Until    time.Time
}

ParentWait is a replay-safe checkpoint. It exists only while the engine is waiting, never while a model request or side-effecting tool is in flight.

type Progress

type Progress struct {
	Phase      string    `json:"phase"`
	ToolName   string    `json:"tool_name,omitempty"`
	ToolCallID string    `json:"tool_call_id,omitempty"`
	Iteration  int       `json:"iteration,omitempty"`
	UpdatedAt  time.Time `json:"updated_at"`
}

Progress is bounded operational telemetry, not model reasoning or tool payloads.

type PromptState

type PromptState struct {
	ID         string `json:"id"`
	Kind       string `json:"kind,omitempty"`
	Status     string `json:"status,omitempty"`
	ToolCallID string `json:"tool_call_id,omitempty"`
	Service    string `json:"service,omitempty"`
	Tool       string `json:"tool,omitempty"`
	Decision   string `json:"decision,omitempty"`
}

PromptState is an allowlisted projection of a broker record, never model text. It deliberately excludes arguments, user answers, credentials and descriptions.

type Record

type Record struct {
	ID        string `gorm:"primaryKey;type:varchar(36)"`
	TenantID  uint64 `gorm:"not null"`
	UserID    string `gorm:"type:varchar(64);not null"`
	SessionID string `gorm:"type:varchar(36);not null"`
	Status    string `gorm:"type:varchar(32);not null;index"`
	Version   int64  `gorm:"not null"`
	Data      string `gorm:"type:text;not null"`
	UpdatedAt time.Time
}

Record is an aggregate with an optimistic concurrency fence. One bounded document makes admission, event publication and the pending-work outbox atomic on both SQLite and PostgreSQL, without relying on process-local locks.

func (Record) TableName

func (Record) TableName() string

TableName returns the durable collaboration aggregate table.

type Result

type Result struct {
	// Artifacts are runtime-produced metadata, never parsed from model prose.
	Artifacts        types.MessageArtifacts `json:"artifacts,omitempty"`
	Truncated        bool                   `json:"truncated,omitempty"`
	Evidence         string                 `json:"evidence,omitempty"`
	Answer           string                 `json:"answer,omitempty"`
	Error            string                 `json:"error,omitempty"`
	MessageID        string                 `json:"message_id,omitempty"`
	ConsumedSequence int64                  `json:"consumed_sequence,omitempty"`
	Suspended        bool                   `json:"suspended,omitempty"`
}

Result records a child’s answer, evidence and execution outcome.

type Run

type Run struct {
	// Inherited identifies a baseline run copied from an earlier parent turn.
	Inherited       bool         `json:"inherited,omitempty"`
	Prompt          *PromptState `json:"prompt,omitempty"`
	Progress        *Progress    `json:"progress,omitempty"`
	ID              string       `json:"run_id"`
	State           string       `json:"status"`
	Query           string       `json:"query"`
	Owner           string       `json:"-"`
	Lease           time.Time    `json:"lease_until"`
	Attempt         int          `json:"attempt"`
	CancelRequested bool         `json:"cancel_requested"`
	Result          Result       `json:"result"`
	// DeliveredSequence fences automatic followups even when the executor cannot return a result.
	DeliveredSequence int64  `json:"delivered_sequence,omitempty"`
	PromptID          string `json:"prompt_id,omitempty"`
	MessageID         string `json:"message_id,omitempty"`
	UserMessageID     string `json:"user_message_id,omitempty"`
}

Run tracks one child execution, its lease and eventual result.

func (Run) MarshalJSON

func (r Run) MarshalJSON() ([]byte, error)

MarshalJSON preserves private ownership for persistence; model projections omit it.

func (*Run) UnmarshalJSON

func (r *Run) UnmarshalJSON(b []byte) error

UnmarshalJSON restores private ownership alongside the persisted execution state.

type Runner

type Runner func(context.Context, Work) (Result, error)

Runner executes claimed child work and returns its durable outcome.

type Runtime

type Runtime struct {
	Store       *Store
	Run         Runner
	WakeParent  func(context.Context, *Binding, []byte) error
	Reconcile   func(context.Context, Scope) error
	ParentInput func(context.Context, Scope, string) (bool, error)
	// Prune bounds durable storage; it runs every PruneInterval.
	Prune         func(context.Context) error
	PruneInterval time.Duration
	Poll          time.Duration
	Lease         time.Duration
	// Concurrency bounds running children per group; MaxRunning bounds the
	// child executions this process runs across all groups.
	Concurrency int
	MaxRunning  int
	// contains filtered or unexported fields
}

Runtime schedules durable child work and recovers waiting parent executions.

func New

func New(store *Store, run Runner) *Runtime

New constructs a runtime with bounded concurrency and lease defaults.

func (*Runtime) AcquireParent

func (r *Runtime) AcquireParent(ctx context.Context, requested Scope) (*Binding, error)

AcquireParent attaches a new engine to an unfinished task after its prior engine lease expires. Completed groups never revive. Automatic recovery uses wakeParent and an owned safe checkpoint; this path also lets a new user turn take over unfinished work without replaying old tool calls.

func (*Runtime) AwaitPrompt

func (r *Runtime) AwaitPrompt(ctx context.Context, w Work, prompt PromptState) error

AwaitPrompt registers a prompt under the current child execution lease.

func (*Runtime) Cancel

func (r *Runtime) Cancel(ctx context.Context, s Scope) error

Cancel closes a group and cancels its unfinished child executions.

func (*Runtime) CancelMessage

func (r *Runtime) CancelMessage(ctx context.Context, s Scope, messageID string) error

CancelMessage ignores a stale stop for the previous parent turn after takeover.

func (*Runtime) CheckOwner

func (r *Runtime) CheckOwner(ctx context.Context, w Work) error

CheckOwner validates that a child execution still owns its live lease.

func (*Runtime) CheckParent

func (r *Runtime) CheckParent(ctx context.Context, scope Scope, owner string) error

CheckParent rejects expired, replaced or closed parent executions.

func (*Runtime) CheckParentFinalization

func (r *Runtime) CheckParentFinalization(ctx context.Context, scope Scope, owner string) error

CheckParentFinalization authorizes only the claimed terminal delivery. It is deliberately separate from CheckParent, which rejects a closing group.

func (*Runtime) ClearCanceledPrompt

func (r *Runtime) ClearCanceledPrompt(ctx context.Context, w Work) error

ClearCanceledPrompt removes a canceled run’s prompt after the broker closes it.

func (*Runtime) CloseChildPrompt

func (r *Runtime) CloseChildPrompt(
	ctx context.Context, scope Scope, sessionID, messageID, promptID, status string,
) error

CloseChildPrompt settles the child run that owns a broker prompt. The prompt session is the child conversation, so callers locate the parent group first. A prompt that closed before the tool ran stays continuable; an in-flight or failed execution stays needs_attention and cannot be replayed.

func (*Runtime) Compact

func (r *Runtime) Compact(ctx context.Context, s Scope) error

Compact drops bulky history from a terminal group.

func (*Runtime) Finish

func (r *Runtime) Finish(ctx context.Context, s Scope, observed int64) (bool, error)

Finish uses the last sequence actually observed by the parent, not a cursor advanced by a background delivery worker. A racing result prevents completion.

func (*Runtime) Inbox

func (r *Runtime) Inbox(ctx context.Context, w Work, after int64) ([]Event, error)

Inbox retains mail for snapshot reconstruction, but durably acknowledges its delivery before execution. A panic or failed approval continuation must never turn already delivered guidance into an automatic new execution.

func (*Runtime) Interrupt

func (r *Runtime) Interrupt(ctx context.Context, s Scope, target, expected string) error

Interrupt requests cancellation of the selected child execution.

func (*Runtime) ReconcilePrompt

func (r *Runtime) ReconcilePrompt(ctx context.Context, w Work, prompt PromptState) error

ReconcilePrompt is called with broker state read outside the CAS callback. An executing/done prompt can never be replayed, even after a process dies.

func (*Runtime) RecordProgress

func (r *Runtime) RecordProgress(ctx context.Context, w Work, p Progress) error

RecordProgress coalesces telemetry without adding mailbox events or waking a model on each tool. Old workers and canceled turns cannot publish late updates.

func (*Runtime) Send

func (r *Runtime) Send(
	ctx context.Context,
	s Scope,
	key, target, query, expected string,
	followup bool,
) (string, error)

Send queues guidance or creates a follow-up turn for an idle child.

func (*Runtime) SetRunMessages

func (r *Runtime) SetRunMessages(ctx context.Context, w Work, userID, messageID string) error

SetRunMessages and AwaitPrompt are fenced by the same child execution lease as tool execution. Prompt ownership is registered before it reaches the UI.

func (*Runtime) Spawn

func (r *Runtime) Spawn(ctx context.Context, s Scope, key, name, agentID, config, query string) (string, error)

Spawn idempotently enqueues a new child task in the parent group.

func (*Runtime) Start

func (r *Runtime) Start(ctx context.Context)

Start starts the scheduling and recovery loop once.

func (*Runtime) Stop

func (r *Runtime) Stop(ctx context.Context) error

Stop cancels scheduling and waits for workers to finish.

func (*Runtime) Tick

func (r *Runtime) Tick(ctx context.Context)

Tick is also the restart recovery path. Never replay an uncertain running turn: expire its lease into needs_attention. Queued work is safe to claim.

func (*Runtime) Wait

func (r *Runtime) Wait(ctx context.Context, s Scope, after int64, d time.Duration) (bool, error)

Wait waits for an event newer than the supplied mailbox sequence.

type RuntimeNotice

type RuntimeNotice struct {
	Type           string `json:"type"`
	Source         string `json:"source"`
	Task           string `json:"task,omitempty"`
	RunID          string `json:"run_id,omitempty"`
	Sequence       int64  `json:"sequence"`
	PromptID       string `json:"prompt_id,omitempty"`
	PromptKind     string `json:"prompt_kind,omitempty"`
	ToolCallID     string `json:"tool_call_id,omitempty"`
	Service        string `json:"service,omitempty"`
	Tool           string `json:"tool,omitempty"`
	Decision       string `json:"decision,omitempty"`
	ExecutionState string `json:"execution_state,omitempty"`
	Message        string `json:"message,omitempty"`
}

RuntimeNotice is internal model context, separate from tool output and final answers.

type Scope

type Scope struct {
	TenantID              uint64
	UserID, SessionID, ID string
}

Scope identifies a collaboration within its tenant, user and session.

type StatusSnapshot

type StatusSnapshot struct {
	GroupID  string       `json:"group_id"`
	Revision int64        `json:"revision"`
	Tasks    []TaskStatus `json:"tasks"`
}

StatusSnapshot is the public projection of a durable collaboration. It never includes assignment text, provider configuration, leases or raw tool results.

type Store

type Store struct {

	// OnStatus runs after a successful commit, never inside a retried mutation.
	// Consumers must tolerate duplicate and out-of-order snapshots by revision.
	OnStatus func(context.Context, *Group)
	// contains filtered or unexported fields
}

Store persists collaboration aggregates using optimistic concurrency.

func NewStore

func NewStore(db *gorm.DB) *Store

NewStore wraps a database connection for collaboration persistence.

func (*Store) Change

func (s *Store) Change(ctx context.Context, scope Scope, fn func(*Group) error) error

Change callbacks can be retried: no IO or non-idempotent external actions in fn.

An active aggregate that would exceed maxAggregateBytes is closed instead of rejecting every later mutation, including the cancellation that would end it. The caller's mutation is discarded and ErrHistoryLimit is returned.

func (*Store) Ensure

func (s *Store) Ensure(ctx context.Context, scope Scope) error

Ensure creates a scoped group if absent and verifies access to an existing group.

func (*Store) Pending

func (s *Store) Pending(ctx context.Context) ([]Scope, error)

Pending lists groups that require scheduling, recovery or cancellation.

func (*Store) Read

func (s *Store) Read(ctx context.Context, scope Scope) (*Group, error)

type TaskStatus

type TaskStatus struct {
	ID            string    `json:"id"`
	Name          string    `json:"name"`
	DisplayName   string    `json:"display_name,omitempty"`
	AgentID       string    `json:"agent_id"`
	SessionID     string    `json:"session_id"`
	RunID         string    `json:"run_id"`
	Status        string    `json:"status"`
	Progress      *Progress `json:"progress,omitempty"`
	PromptID      string    `json:"prompt_id,omitempty"`
	LatestMessage string    `json:"latest_message,omitempty"`
}

TaskStatus is the public current-run status of one child task.

type Work

type Work struct {
	Scope  Scope
	Member Member
	Run    Run
}

Work is a claimed child execution with its scope and ownership lease.

Jump to

Keyboard shortcuts

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