api

package
v0.15.0 Latest Latest
Warning

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

Go to latest
Published: Jun 12, 2026 License: AGPL-3.0 Imports: 31 Imported by: 0

Documentation

Overview

Package api provides an HTTP API server for inspecting and managing the Merkle DAG.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// ListenAddr is the address to listen on (e.g., ":8081")
	ListenAddr string

	// VectorDriver for semantic search (optional, enables MCP server)
	VectorDriver vector.Driver

	// Embedder for converting query text to vectors (optional, enables MCP server)
	Embedder embeddings.Embedder

	// Pricing is the model pricing table used by /v1/sessions/summary to
	// compute per-session cost. When nil, sessions.DefaultPricing() is used.
	Pricing sessions.PricingTable

	// EnableWebUI serves the minimal browser UI at /. It is disabled by default
	// so API-only servers do not expose a human-facing development UI unless
	// explicitly requested.
	EnableWebUI bool
}

Config is the API server configuration.

type GraphLink struct {
	Source string `json:"source"`
	Target string `json:"target"`
}

GraphLink is a directed parent -> child edge between two included GraphNode IDs.

type GraphNode added in v0.8.0

type GraphNode struct {
	ID            string     `json:"id"`
	ParentID      *string    `json:"parent_id,omitempty"`
	ParentHash    *string    `json:"parent_hash,omitempty"`
	Type          string     `json:"type,omitempty"`
	Role          string     `json:"role,omitempty"`
	Preview       string     `json:"preview,omitempty"`
	Model         string     `json:"model,omitempty"`
	Provider      string     `json:"provider,omitempty"`
	AgentName     string     `json:"agent_name,omitempty"`
	Project       string     `json:"project,omitempty"`
	StopReason    string     `json:"stop_reason,omitempty"`
	Usage         *llm.Usage `json:"usage,omitempty"`
	CreatedAt     time.Time  `json:"created_at,omitzero"`
	Depth         int        `json:"depth"`
	ChildrenCount int        `json:"children_count"`
	IsRoot        bool       `json:"is_root"`
	IsLeaf        bool       `json:"is_leaf"`
	IsBranchPoint bool       `json:"is_branch_point"`
	Selected      bool       `json:"selected"`
}

GraphNode is the per-node shape used by the web UI graph visualization.

type GraphResponse added in v0.8.0

type GraphResponse struct {
	// Hash is the session/node hash requested by the caller.
	Hash string `json:"hash"`

	// RootHash is the top-most resolvable node included in the response.
	RootHash string `json:"root_hash"`

	// Scope describes which portion of the graph was loaded: root, branch, or ancestry.
	Scope string `json:"scope"`

	// NodeLimit is the maximum number of nodes the server will include.
	NodeLimit int `json:"node_limit"`

	// Nodes is the flat node list consumed by graph visualizers.
	Nodes []GraphNode `json:"nodes"`

	// Links contains parent -> child edges between included nodes.
	Links []GraphLink `json:"links"`

	// Leaves names included nodes that have no children in storage.
	Leaves []string `json:"leaves"`

	// BranchPoints names included nodes with more than one child in storage.
	BranchPoints []string `json:"branch_points"`

	// Truncated is true when the graph hit NodeLimit or the ancestry chain is incomplete.
	Truncated bool `json:"truncated,omitempty"`

	// MissingParent names the unresolved parent hash when the ancestry is incomplete.
	MissingParent string `json:"missing_parent,omitempty"`

	// CycleDetected is true when storage guarded the ancestry walk out of a cycle.
	CycleDetected bool `json:"cycle_detected,omitempty"`
}

GraphResponse is the graph-shaped projection for GET /v1/stems/:hash/graph.

type Metrics added in v0.7.0

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

Metrics is the Prometheus surface for the Tapes API server. Each Server owns its own registry so tests can scrape in isolation; the production path mounts /metrics on the Fiber app via NewServer.

func NewMetrics added in v0.7.0

func NewMetrics() *Metrics

NewMetrics constructs the Tapes API server's RED metrics. Labels stay templated (`route`) rather than per-URL so :hash path params don't blow up cardinality.

func (*Metrics) Handler added in v0.7.0

func (m *Metrics) Handler() fiber.Handler

Handler returns a Fiber handler that serves Prometheus text exposition from this Metrics instance's registry. Mount it at /metrics with no auth. The handler is built once at NewMetrics time and cached — see the scrapeHandler field comment for why.

func (*Metrics) Middleware added in v0.7.0

func (m *Metrics) Middleware() fiber.Handler

Middleware returns a Fiber handler that records request count + duration per (route template, method, status). Templates like /v1/sessions/:hash stay as the label value so the :hash path param never expands cardinality.

Register this OUTSIDE recover.New() (i.e. via app.Use before recover) — see resolveStatus for why.

func (*Metrics) Registry added in v0.7.0

func (m *Metrics) Registry() *prometheus.Registry

Registry exposes the *prometheus.Registry so tests can scrape against the same registry the middleware writes to.

type Server

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

Server is the API server for managing and querying the Tapes system

func NewServer

func NewServer(config Config, driver storage.Driver, log *slog.Logger) (*Server, error)

NewServer creates a new API server. The storer is injected to allow sharing with other components (e.g., the proxy when not run as a singleton).

func (*Server) Run

func (s *Server) Run() error

Run starts the API server on the configured address.

func (*Server) RunWithListener

func (s *Server) RunWithListener(listener net.Listener) error

RunWithListener starts the API server using the provided listener.

func (*Server) Shutdown

func (s *Server) Shutdown() error

Shutdown gracefully shuts down the API server.

type SessionDetailResponse added in v0.12.0

type SessionDetailResponse struct {
	Session SessionItem   `json:"session"`
	Turns   []Turn        `json:"turns"`
	Stems   []StemSummary `json:"stems"`
}

SessionDetailResponse is the response for GET /v1/sessions/:id. Turns contains the selected stem (controlled by ?stem= and ?root=). Stems lists every root in the session sorted by length descending so callers can offer a picker.

type SessionItem added in v0.12.0

type SessionItem struct {
	ID                string         `json:"id"`
	HarnessID         string         `json:"harness_id"`
	HarnessSessionID  string         `json:"harness_session_id"`
	Name              string         `json:"name,omitempty"`
	Cwd               string         `json:"cwd,omitempty"`
	HarnessVersion    string         `json:"harness_version,omitempty"`
	ParentSessionID   string         `json:"parent_session_id,omitempty"`
	StartedAt         time.Time      `json:"started_at"`
	LastSeenAt        time.Time      `json:"last_seen_at"`
	EndedAt           *time.Time     `json:"ended_at,omitempty"`
	TurnCount         int            `json:"turn_count"`
	TotalInputTokens  int64          `json:"total_input_tokens"`
	TotalOutputTokens int64          `json:"total_output_tokens"`
	TotalCostUsd      float64        `json:"total_cost_usd"`
	DerivedStatus     string         `json:"derived_status"`
	HarnessMetadata   map[string]any `json:"harness_metadata,omitempty"`
	Preview           string         `json:"preview,omitempty"`
	// AuthSubject is the gateway-stamped JWT subject (WorkOS user id)
	// captured at ingest; empty for rows captured before the edge began
	// stamping it.
	AuthSubject string `json:"auth_subject,omitempty"`
}

SessionItem is the per-row shape returned by GET /v1/sessions. It mirrors the sessions table directly — no ancestry walk, no stem aggregation.

type SessionListResponse added in v0.4.0

type SessionListResponse struct {
	Items      []SessionItem `json:"items"`
	NextCursor string        `json:"next_cursor,omitempty"`
}

SessionListResponse is the response envelope for GET /v1/sessions.

type StatsResponse added in v0.4.0

type StatsResponse struct {
	SessionCount    int     `json:"session_count"`
	StemCount       int     `json:"stem_count"`
	TurnCount       int     `json:"turn_count"`
	RootCount       int     `json:"root_count"`
	CompletedCount  int     `json:"completed_count"`
	TotalCost       float64 `json:"total_cost"`
	InputTokens     int64   `json:"input_tokens"`
	OutputTokens    int64   `json:"output_tokens"`
	TotalDurationNs int64   `json:"total_duration_ns"`
	ToolCalls       int     `json:"tool_calls"`
}

StatsResponse is the response for GET /v1/stats.

All fields are computed by a single storage-driver aggregate over the matching node set — no per-session chain walk. This means:

  • InputTokens / OutputTokens / ToolCalls are SUMs over every node matching the filter, NOT per-chain folds. Each piece of work (each token billed, each tool_use invoked) is counted exactly once regardless of how many leaves share its ancestor. This deliberately diverges from /v1/sessions/summary's per-chain numbers, which multi-count shared ancestors when leaves descend from a common branch.
  • TotalCost is folded in the handler from the per-model token rollup returned by the driver, using the configured pricing table.
  • TotalDurationNs is the wall-clock span MAX(created_at) − MIN(created_at) across matching nodes, in nanoseconds. It is NOT a sum of per-call durations. The underlying nodes.total_duration_ns column is now populated by the proxy with per-call wall-clock duration (PCC-514); switching this endpoint to SUM(total_duration_ns) is a separate decision since it changes the visible semantic.
  • CompletedCount uses leaf-status-only classification: an assistant leaf with a terminal stop_reason ("stop", "end_turn", "end-turn", "eos"). This is a narrower set than pkg/sessions.DetermineStatus accepts: that classifier also treats "tool_use" / "tool_use_response" as terminal and considers tool errors and git activity from the full chain. Sessions terminating on a tool request, or where the agent shipped work (e.g. `git commit`) without a terminal leaf stop_reason, will undercount here. PCC-515 tracks the durable fix (denormalize derived_status on Put + backfill).

type StemListResponse added in v0.12.0

type StemListResponse struct {
	Items      []sessions.SessionSummary `json:"items"`
	NextCursor string                    `json:"next_cursor,omitempty"`
}

StemListResponse is the response envelope for GET /v1/stems. Items carry the rich per-stem aggregates computed by pkg/sessions.BuildSummary.

A "stem" is a root-to-leaf chain of Merkle nodes — what the older API called a leaf "session". The type name sessions.SessionSummary is retained for wire compatibility with existing consumers (the deck TUI, checkout).

type StemResponse added in v0.12.0

type StemResponse struct {
	// Hash is the head of the returned chain (== the requested hash).
	Hash string `json:"hash"`

	// HarnessID and HarnessSessionID identify the upstream agent session when
	// session tracking metadata is available. For Claude Code, HarnessID is
	// "claude" and HarnessSessionID is Claude's session id.
	HarnessID        string `json:"harness_id,omitempty"`
	HarnessSessionID string `json:"harness_session_id,omitempty"`

	// Depth is the total number of turns in the full ancestry of Hash.
	// When the client passes ?depth=N, the Turns array may contain fewer
	// than Depth items.
	Depth int `json:"depth"`

	// Turns contains the chain in chronological order (root-first).
	// When ?depth=N is supplied, only the last N turns (head + N-1 ancestors)
	// are returned, still in chronological order.
	Turns []Turn `json:"turns"`

	// Truncated is true when the ancestry walk stopped at a parent_hash
	// that could not be resolved in the current store. MissingParent
	// names that hash. This is an expected edge case on stores that
	// trim older data, merge foreign content, or offload history to
	// another source — not an error.
	Truncated     bool   `json:"truncated,omitempty"`
	MissingParent string `json:"missing_parent,omitempty"`
}

StemResponse is the response for GET /v1/stems/:hash — the ancestry chain of a single Merkle leaf, root-first.

type StemSummary added in v0.12.0

type StemSummary struct {
	RootHash string `json:"root_hash"`
	Length   int    `json:"length"`
	Preview  string `json:"preview,omitempty"`
	Model    string `json:"model,omitempty"`
}

StemSummary describes one root-to-deepest-leaf path (a "stem") within a session. The Stems array in SessionDetailResponse lists every root so the caller can switch between stems without a separate API call.

type Turn added in v0.4.0

type Turn struct {
	Hash       string             `json:"hash"`
	ParentHash *string            `json:"parent_hash,omitempty"`
	Role       string             `json:"role"`
	Content    []llm.ContentBlock `json:"content"`
	Model      string             `json:"model,omitempty"`
	Provider   string             `json:"provider,omitempty"`
	AgentName  string             `json:"agent_name,omitempty"`
	StopReason string             `json:"stop_reason,omitempty"`
	Usage      *llm.Usage         `json:"usage,omitempty"`
	CreatedAt  time.Time          `json:"created_at,omitzero"`
}

Turn is a single message in a session's chain.

Directories

Path Synopsis
Package mcp provides an MCP (Model Context Protocol) server for the Tapes system.
Package mcp provides an MCP (Model Context Protocol) server for the Tapes system.
Package search provides shared search types and logic for semantic search over stored LLM sessions.
Package search provides shared search types and logic for semantic search over stored LLM sessions.

Jump to

Keyboard shortcuts

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