merkle

package
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Mar 20, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package merkle is an implementation of a Merkel DAG

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Bucket

type Bucket struct {
	// Type identifies the kind of content (e.g., "message")
	Type string `json:"type"`

	// Role indicates who produced this message ("system", "user", "assistant", "tool")
	Role string `json:"role"`

	// Content holds the message content blocks
	Content []llm.ContentBlock `json:"content"`

	// Model identifies the LLM model (e.g., "gpt-4", "claude-3-sonnet")
	Model string `json:"model"`

	// Provider identifies the API provider (e.g., "openai", "anthropic", "ollama")
	Provider string `json:"provider"`

	// AgentName identifies the agent harness (e.g., "claude", "opencode", "codex")
	AgentName string `json:"agent_name,omitempty"`
}

Bucket represents the hashable content stored in a Merkle DAG node. This is the tapes canonical content-addressable hashing structure for all LLM conversation turns.

func (*Bucket) ExtractText

func (b *Bucket) ExtractText() string

ExtractText returns the concatenated text content from the bucket's content blocks. This is useful for generating embeddings for semantic search. It extracts text from text blocks, tool outputs, and tool use requests, joining them with newlines.

type Dag

type Dag struct {
	// Root is the single root node of this directed graph
	Root *DagNode
	// contains filtered or unexported fields
}

Dag is an in-memory view of a single-rooted Merkle DAG (i.e., a single branch within the graph's plane).

It is loaded on-demand from a provided BranchLoader.

func LoadDag

func LoadDag(ctx context.Context, loader DagLoader, hash string) (*Dag, error)

LoadDag loads the full branch containing the given hash from storage. This includes all ancestors (up to root) and all descendants (down to leaves).

The returned Dag has a single root and contains the complete conversation branch that includes the specified node.

func NewDag

func NewDag() *Dag

func (*Dag) Ancestors

func (d *Dag) Ancestors(hash string) []*DagNode

Ancestors returns the path from the given node up to the root. The returned slice is ordered from the node to root (node first, root last). Returns nil if the hash is not found.

func (*Dag) BranchPoints

func (d *Dag) BranchPoints() []*DagNode

BranchPoints returns all nodes that have more than one child.

func (*Dag) Descendants

func (d *Dag) Descendants(hash string) []*DagNode

Descendants returns all descendants of the given node (children, grandchildren, etc.). The returned slice is ordered by depth-first traversal. Returns nil if the hash is not found.

func (*Dag) Get

func (d *Dag) Get(hash string) *DagNode

Get returns the DagNode with the given hash, or nil if not found.

func (*Dag) IsBranching

func (d *Dag) IsBranching(hash string) bool

IsBranching returns true if the node with the given hash has multiple children. Returns false if the hash is not found or has 0-1 children.

func (*Dag) Leaves

func (d *Dag) Leaves() []*DagNode

Leaves returns all leaf nodes (nodes with no children).

func (*Dag) Size

func (d *Dag) Size() int

Size returns the total number of nodes in the DAG.

func (*Dag) Walk

func (d *Dag) Walk(f func(*DagNode) (bool, error)) error

Walk traverses the DAG depth-first from root, calling fn for each node. If the provided function returns false, traversal stops. If the provided function errors, traversal stops and the error is propagated.

type DagLoader

type DagLoader interface {
	// Get retrieves a node by its hash.
	Get(ctx context.Context, hash string) (*Node, error)

	// GetByParent retrieves all nodes that have the given parent hash.
	// Pass nil to get root nodes.
	GetByParent(ctx context.Context, parentHash *string) ([]*Node, error)

	// Ancestry returns the path from a node back to its root (node first, root last).
	Ancestry(ctx context.Context, hash string) ([]*Node, error)
}

DagLoader defines the interface for loading nodes from storage. This allows the Dag to be loaded from any storage implementation without creating a circular dependency.

storage.Driver implementers must also implement this interface.

type DagNode

type DagNode struct {
	*Node

	// Parent is the parent node in the DAG (nil for root)
	Parent *DagNode

	// Children are the child nodes (empty for leaves)
	Children []*DagNode
}

DagNode wraps a "Node" with structural relationships for efficient traversal.

type Node

type Node struct {
	// Hash is the content-addressed identifier (SHA-256, hex-encoded)
	Hash string `json:"hash"`

	// ParentHash links to the previous node hash.
	// This will be nil for root nodes.
	ParentHash *string `json:"parent_hash"`

	// Bucket is the hashable content for the node.
	Bucket Bucket `json:"bucket"`

	// StopReason indicates why generation stopped (only for responses)
	// Values: "stop", "length", "tool_use", "end_turn", etc.
	StopReason string `json:"stop_reason,omitempty"`

	// Usage contains token counts and timing (only for responses)
	Usage *llm.Usage `json:"usage,omitempty"`

	// Project is the git repository or project name that produced this node
	Project string `json:"project,omitempty"`
}

Node represents a single content-addressed node in a Merkle DAG

func NewNode

func NewNode(bucket Bucket, parent *Node, metas ...NodeMeta) *Node

NewNode creates a new node with the computed hash for the provided bucket. The optional NodeOptions parameter allows for setting metadata (StopReason, Usage, etc.) outside of the content addressable Bucket

type NodeMeta

type NodeMeta struct {
	StopReason string
	Usage      *llm.Usage
	Project    string
}

NodeMeta contains optional metadata for a node that is stored but does not affect the content-addressable hash.

Jump to

Keyboard shortcuts

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