api

package
v0.24.0 Latest Latest
Warning

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

Go to latest
Published: Jul 14, 2026 License: AGPL-3.0 Imports: 35 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

	// SpanSearcher enables GET /v1/search/spans — semantic search over
	// the span projection's embeddings (optional). Requires Embedder.
	SpanSearcher SpanSearcher

	// 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

	// SkillLLM* configure the LLM used by POST /v1/skills/generate. They are
	// populated from the search/embedding credential so skill extraction
	// reuses the same shared key the platform already mounts for search —
	// no separate provider key. An empty Provider/APIKey falls back to the
	// generator's env/credentials resolution at call time.
	SkillLLMProvider string
	SkillLLMModel    string
	SkillLLMAPIKey   string
	SkillLLMBaseURL  string
}

Config is the API server configuration.

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 ModelUsage added in v0.16.0

type ModelUsage struct {
	Model        string  `json:"model"`
	Calls        int64   `json:"calls"`
	InputTokens  int64   `json:"input_tokens"`
	OutputTokens int64   `json:"output_tokens"`
	CostUsd      float64 `json:"cost_usd"`
}

ModelUsage is one model's contribution to a session in the API: how many llm calls ran on it and what they spent. Cost-weighted (priced at derive time) so a per-model share reflects spend, not call count.

type PayloadMode added in v0.16.0

type PayloadMode string

PayloadMode selects how much span payload a trace response carries. Full embeds the stored content verbatim; preview truncates long text so list-shaped reads stay O(structure), with the span drill-in endpoint serving the full payload on demand.

const (
	PayloadFull    PayloadMode = "full"
	PayloadPreview PayloadMode = "preview"
)

type RawTurnHeaderItem added in v0.16.0

type RawTurnHeaderItem struct {
	ID            int64           `json:"id"`
	Source        string          `json:"source"`
	Provider      string          `json:"provider,omitempty"`
	AgentName     string          `json:"agent_name,omitempty"`
	RequestID     string          `json:"request_id,omitempty"`
	ReceivedAt    time.Time       `json:"received_at"`
	Meta          json.RawMessage `json:"meta,omitempty"`
	RequestBytes  int64           `json:"request_bytes"`
	ResponseBytes int64           `json:"response_bytes"`
}

RawTurnHeaderItem is one wire-log row: what crossed the wire (or arrived as a transcript push), without the payload blobs. The `source` field is the wire-vs-transcript distinction.

type RawTurnListResponse added in v0.16.0

type RawTurnListResponse struct {
	Items []RawTurnHeaderItem `json:"items"`
}

RawTurnListResponse is a session's wire log.

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"`
}

SessionDetailResponse is the response for GET /v1/sessions/:id: the session record alone. The conversation content lives on the span model (GET /v1/sessions/:id/traces).

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"`
	// Model is the dominant conversation-spine model, folded at derive
	// time; empty until the session first derives.
	Model string `json:"model,omitempty"`
	// ModelUsage is the per-model spend breakdown folded at derive time
	// across every thread (subagent models included), ordered
	// dominant-model-first by cost. The share basis is cost, not call
	// count, so the UI can show "dominant model + per-model %" without a
	// cheap-subagent fan-out skewing it. Populated on the session detail;
	// nil until the session first derives.
	ModelUsage      []ModelUsage   `json:"model_usage,omitempty"`
	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 SessionTracesResponse added in v0.16.0

type SessionTracesResponse struct {
	Session    SessionItem    `json:"session"`
	Tasks      []TreeTask     `json:"tasks"`
	KindCounts map[string]int `json:"kind_counts"`
	Traces     []TraceDetail  `json:"traces"`
	Links      []SpanLinkItem `json:"links"`
}

SessionTracesResponse is the composite session view on the span model.

func BuildSessionTraces added in v0.16.0

func BuildSessionTraces(
	session SessionItem,
	turns []storage.SpanTurnRecord,
	spans []storage.SpanRecord,
	links []storage.SpanLinkRecord,
	mode PayloadMode,
) *SessionTracesResponse

BuildSessionTraces assembles the composite response. Pure rendering: every edge and kind here was computed by the deriver. Exported so `tapes dev trace-fixtures` emits byte-identical JSON to the handler.

type SpanItem added in v0.16.0

type SpanItem struct {
	ID           string    `json:"id"`
	TraceID      string    `json:"trace_id"`
	SpanID       string    `json:"span_id"`
	ParentSpanID string    `json:"parent_span_id,omitempty"`
	Kind         string    `json:"kind"`
	Name         string    `json:"name"`
	Status       string    `json:"status"`
	StartedAt    time.Time `json:"started_at"`
	StartNS      int64     `json:"start_ns"`
	DurationNS   int64     `json:"duration_ns"`
	// Seq is the span's presentation ordinal within its trace; spans
	// arrive sorted by it. start_ns cannot order spans inside one llm
	// call (parallel tool batches share an instant).
	Seq      int64          `json:"seq"`
	Input    map[string]any `json:"input"`
	Output   map[string]any `json:"output"`
	Metadata map[string]any `json:"metadata"`
	// Metrics is always an object on the wire — the contract fixture
	// pins {} for usage-less spans (agent/tool/event), and the console
	// schema requires it.
	Metrics     json.RawMessage `json:"metrics"`
	ChildrenIDs []string        `json:"children_ids,omitempty"`
}

SpanItem is one observed unit of work. start_ns is the epoch-ns start (kept for the pinned contract); started_at carries the same instant losslessly for JS clients, since 1.7e18 exceeds Number.MAX_SAFE_INTEGER.

type SpanLinkItem added in v0.16.0

type SpanLinkItem struct {
	FromTraceID string         `json:"from_trace_id"`
	FromSpanID  string         `json:"from_span_id"`
	FromIO      string         `json:"from_io,omitempty"`
	ToTraceID   string         `json:"to_trace_id"`
	ToSpanID    string         `json:"to_span_id"`
	ToIO        string         `json:"to_io,omitempty"`
	Metadata    map[string]any `json:"metadata"`
}

SpanLinkItem is a dataflow edge; from/to trace ids differ on cross-trace causality.

type SpanSearchOutput added in v0.16.0

type SpanSearchOutput struct {
	Query   string             `json:"query"`
	Results []SpanSearchResult `json:"results"`
	Count   int                `json:"count"`
}

SpanSearchOutput is the span search response.

type SpanSearchResult added in v0.16.0

type SpanSearchResult struct {
	TraceID   string  `json:"trace_id"`
	SpanID    string  `json:"span_id"`
	SessionID string  `json:"session_id,omitempty"`
	Score     float32 `json:"score"`
	// UserPrompt is the prompt of the turn (trace) the span belongs to.
	UserPrompt string `json:"user_prompt,omitempty"`
	// Snippet previews the matched span's delta-only text.
	Snippet   string    `json:"snippet,omitempty"`
	Model     string    `json:"model,omitempty"`
	StartedAt time.Time `json:"started_at"`
}

SpanSearchResult is one span hit with its trace/turn context.

type SpanSearcher added in v0.16.0

type SpanSearcher interface {
	Search(ctx context.Context, orgID string, embedding []float32, topK int) ([]spanembed.Hit, error)
}

SpanSearcher performs vector-similarity search over span embeddings. *spanembed.Store implements it; tests substitute fakes.

type StatsResponse added in v0.4.0

type StatsResponse struct {
	SessionCount int `json:"session_count"`
	// StemCount is a node-layer (Merkle leaf) concept with no span
	// equivalent; it is only present on the legacy fallback path.
	StemCount       int     `json:"stem_count,omitempty"`
	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.

On backends with the span projection (storage.SpanStatsReader) the numbers come from the trace-grain rollups, so they agree with the session detail and trace views:

  • InputTokens / OutputTokens / TotalCost are SUMs of span_turns rollups — delta-only per-call usage, never the re-sent history that inflated the node-layer SUMs (each main call re-bills the whole conversation on the wire).
  • TotalDurationNs is the SUM of trace durations — agent time. Idle time between turns no longer counts (the node-layer value was wall-clock MAX−MIN over the window).
  • TurnCount counts traces (user-visible turns), not wire nodes. RootCount counts traces opened by a genuine prompt (synthetic compaction continuations excluded). StemCount has no span equivalent and is omitted.
  • CompletedCount counts distinct sessions whose denormalized derived_status is 'completed' (chain-aware, PCC-515).

Backends without the span projection fall back to the legacy node-layer aggregate (see CountSessions); the legacy per-node filters (project / agent_name / model / provider) also force that path, since trace rollups don't carry those columns.

type TraceDetail added in v0.16.0

type TraceDetail struct {
	Trace TraceItem      `json:"trace"`
	Spans []SpanItem     `json:"spans"`
	Links []SpanLinkItem `json:"links"`
}

TraceDetail is one trace with its spans and intra-trace links.

func BuildTraceDetail added in v0.16.0

func BuildTraceDetail(turn storage.SpanTurnRecord, spans []storage.SpanRecord, links []storage.SpanLinkRecord, mode PayloadMode) TraceDetail

BuildTraceDetail renders one turn with its spans and links. Exported so `tapes dev trace-fixtures` emits byte-identical JSON to the handler.

type TraceItem added in v0.16.0

type TraceItem struct {
	ID               string `json:"id"`
	TraceID          string `json:"trace_id"`
	SessionID        string `json:"session_id"`
	HarnessID        string `json:"harness_id"`
	HarnessSessionID string `json:"harness_session_id"`
	UserPrompt       string `json:"user_prompt,omitempty"`
	// ResponsePreview is the derive-time fold of the closing
	// conversation-spine llm call's text output — the answer line for
	// collapsed turn cards, so summary consumers never need spans.
	ResponsePreview   string     `json:"response_preview,omitempty"`
	Status            string     `json:"status"`
	StartedAt         time.Time  `json:"started_at"`
	EndedAt           *time.Time `json:"ended_at,omitempty"`
	DurationNS        int64      `json:"duration_ns"`
	TotalInputTokens  int64      `json:"total_input_tokens"`
	TotalOutputTokens int64      `json:"total_output_tokens"`
	// Main* counts conversation-spine calls only; Total − Main is the
	// harness's shadow spend on the turn.
	MainInputTokens     int64          `json:"main_input_tokens"`
	MainOutputTokens    int64          `json:"main_output_tokens"`
	CacheReadTokens     int64          `json:"cache_read_tokens"`
	CacheCreationTokens int64          `json:"cache_creation_tokens"`
	TotalCostUSD        float64        `json:"total_cost_usd"`
	SpanCount           int            `json:"span_count"`
	Metadata            map[string]any `json:"metadata"`
}

TraceItem is one user-visible turn's header.

type TraceListResponse added in v0.16.0

type TraceListResponse struct {
	Items []TraceItem `json:"items"`
}

TraceListResponse is the summaries list for one session.

func BuildTraceList added in v0.16.0

func BuildTraceList(rows []storage.TraceSummaryRecord) TraceListResponse

BuildTraceList renders the turn-summary rows for one session. Exported so `tapes dev trace-fixtures` emits byte-identical JSON to the handler.

type TreeTask added in v0.16.0

type TreeTask struct {
	ID          string `json:"id"`
	Subject     string `json:"subject"`
	Description string `json:"description,omitempty"`
	Status      string `json:"status"`
	Updates     int    `json:"updates"`
}

TreeTask is one task folded from the session's TaskCreate/TaskUpdate calls.

type TreeVerdict added in v0.16.0

type TreeVerdict struct {
	Disposition string `json:"disposition"` // ALLOW | BLOCK
	Stage       int    `json:"stage"`
	Reasoned    bool   `json:"reasoned"`
}

TreeVerdict is a security-monitor disposition.

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