liveview

package
v2.92.1 Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package liveview serves a knowledge graph as a live, rotatable 3D page.

A rendered file is true for the instant it was taken. This serves a page instead — a WebGL scene on 127.0.0.1 that keeps up with the graph on its own, so a graph being written can be watched rather than re-rendered.

Two things move on the page, and they arrive by different routes:

  • Structure — nodes and relations appearing or disappearing. Found by polling the graph and diffing, because it can be written by any process sharing it and there is no change feed to subscribe to. Only the difference is sent, so the layout keeps every node that did not change exactly where it had settled.
  • Activity — a query running, something being saved, a relation drawn. A query changes nothing in the graph, so no amount of polling can show one. These are reported by whoever handled the call, through Server.Observe, and light up the nodes they named.

A caller supplies a Source, which is anything that can read nodes and edges. OpenSource builds one from the ambient CortexDB configuration (CORTEXDB_REMOTE for a shared brain, CORTEXDB_PATH otherwise), and LoadLocal and LoadRemote are exported for callers that know which graph they want and would rather say so than set environment variables.

The listener binds 127.0.0.1 and there is deliberately no option to widen it. The page is the whole graph with no authentication in front of it, so a listener on any other interface would be an unauthenticated read of everything it contains. An embedder that needs to expose it further should put its own authenticated proxy in front rather than ask for a wider bind.

Typical use:

src, err := liveview.OpenSource(ctx)
if err != nil {
	return err
}
sv, err := liveview.Start(ctx, src, liveview.DefaultPort, liveview.DefaultInterval, false)
if err != nil {
	return err
}
defer sv.Close()
fmt.Println(sv.URL())

Index

Constants

View Source
const (
	KindQuery  = "query"
	KindWrite  = "write"
	KindRelate = "relate"
)
View Source
const DefaultInterval = 2 * time.Second

DefaultInterval is how often the brain is re-read for structural change. Activity does not wait for it — that arrives the moment a tool call is handled — so this only bounds how late a write from *another* machine shows up, and polling a database faster than a person can read the result is spend with nothing bought.

View Source
const DefaultPort = 37423

DefaultPort is the preferred port, chosen high and unusual so it does not collide with whatever else is being developed on this machine. When it is taken the server asks the OS for a free one instead of failing: a view is not worth an error, and the caller is told the URL either way.

Variables

This section is empty.

Functions

func ClipLabel

func ClipLabel(s string) string

ClipLabel shortens a node label for display, matching the local renderer.

Whitespace is collapsed before clipping. A node's label is often the first line of whatever text it came from, and that text has newlines in it — which survive into every view that prints the label as a string, breaking the layout of whatever panel is showing it.

func LoadLocal

func LoadLocal(ctx context.Context, sqlDB *sql.DB) ([]Node, []Edge, error)

LoadLocal reads meaningful nodes/edges from the live GraphRAG graph (everything except chunk nodes, and the edges between them). For large graphs it keeps the most-connected core: nodes are ranked by degree and capped, so the view shows the densely-linked hub instead of an arbitrary truncation with dangling edges.

func LoadRemote

func LoadRemote(ctx context.Context, addr, token string, limit int, quiet bool) ([]Node, []Edge, error)

LoadRemote pulls the whole entity graph from the shared brain.

quiet suppresses the truncation note. A one-shot render should say when it only drew part of the brain; the live view calls this every couple of seconds and would repeat the same line forever, which turns a useful notice into the only thing in the log.

func OpenInBrowser

func OpenInBrowser(url string) error

OpenInBrowser hands the URL to the desktop.

Errors are returned rather than ignored: a caller that claims to have opened something is worse than one that says it could not and gives you the URL.

func PortFromEnv

func PortFromEnv() int

func RemoteConfigured

func RemoteConfigured() (addr, token string, ok bool)

RemoteConfigured reports whether this process reads a shared brain.

Types

type Delta

type Delta struct {
	Version      int64    `json:"version"`
	AddedNodes   []Node   `json:"added_nodes"`
	RemovedNodes []string `json:"removed_nodes"`
	AddedEdges   []Edge   `json:"added_edges"`
	RemovedEdges []Edge   `json:"removed_edges"`
	// Nodes and Edges are the totals after applying, so the page's counters
	// cannot drift out of step with the brain if a delta is ever missed.
	Nodes int `json:"nodes"`
	Edges int `json:"edges"`
}

Delta is what changed between two snapshots.

AddedNodes carries upsert semantics rather than insert: a node whose label or type changed is re-sent here, not removed and re-added, so the view updates it in place and keeps the position the layout already settled on.

func Diff

func Diff(prev, next Snapshot) Delta

Diff computes what changed from prev to next.

func (Delta) Empty

func (d Delta) Empty() bool

Empty reports whether the delta changes nothing, so the poller can stay quiet instead of waking every connected page on a timer.

type Edge

type Edge struct {
	Source string `json:"source"`
	Target string `json:"target"`
	Label  string `json:"label"`
}

type Event

type Event struct {
	Seq  int64  `json:"seq"`
	At   int64  `json:"at"` // unix milliseconds
	Kind string `json:"kind"`
	Tool string `json:"tool"`
	// Text is the line the ticker shows.
	Text string `json:"text"`
	// Terms are the strings the page lights nodes up by. They are matched
	// loosely against labels and ids rather than joined on node identity: a
	// tool's arguments name things the way a person does ("CortexDB"), and the
	// graph keys them the way a database does ("entity:CortexDB").
	Terms []string `json:"terms,omitempty"`
	// Links are from/to pairs to draw a pulse along, for relation writes.
	Links  [][2]string `json:"links,omitempty"`
	Failed bool        `json:"failed,omitempty"`
}

Event is one thing the brain just did.

func ClassifyToolCall

func ClassifyToolCall(tool string, args json.RawMessage, failed bool) (Event, bool)

ClassifyToolCall turns one MCP tool call into an event for the live view, reporting false for calls the view should ignore.

type Hub

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

Hub holds the current graph and fans structure and activity out to every page watching.

Slow readers are dropped rather than waited on: a browser tab that stopped draining its stream must never be able to stall the MCP server that is feeding it, because that server is also the one answering the agent.

func NewHub

func NewHub() *Hub

type Message

type Message struct {
	Delta *Delta `json:"delta,omitempty"`
	Event *Event `json:"event,omitempty"`
}

Message is one server-sent event: exactly one of the two is set.

type Node

type Node struct {
	ID    string `json:"id"`
	Label string `json:"label"`
	Type  string `json:"type"`
}

type Payload

type Payload struct {
	Version  int64   `json:"version"`
	Nodes    []Node  `json:"nodes"`
	Edges    []Edge  `json:"edges"`
	Events   []Event `json:"events"`
	Source   string  `json:"source"`
	Activity bool    `json:"activity"`
	Interval int64   `json:"interval_ms"`
}

Payload is the page's opening state: everything needed to draw, plus what the header reports about where it came from.

type Server

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

Server serves one live view.

func Current

func Current() *Server

Current returns the running view of the brain, or nil. Used by the middleware, which must not start a server just because a tool was called — the view exists only once someone asks to see it.

func CurrentFor

func CurrentFor(key string) *Server

CurrentFor returns the running view of one graph, or nil.

func Shared

func Shared(ctx context.Context, activity bool) (*Server, error)

Shared returns the process's view of the brain, starting it on first use.

func SharedFor

func SharedFor(ctx context.Context, key string, activity bool, open func(context.Context) (*Source, error)) (*Server, error)

SharedFor returns the process's view of one graph, keyed by name, starting it on first use. The empty key is the brain.

Keyed rather than single because a process can now be asked for more than one graph, and a second request for the same one means "show me", not "make me another": a view is a port and a poller, and handing out a new pair every time an agent asked twice would leave a trail of them behind.

Each view binds its own port. Only the first gets the preferred one; the rest take whatever the OS gives, which is why the URL is always returned rather than assumed.

func Start

func Start(ctx context.Context, src *Source, port int, interval time.Duration, activity bool) (*Server, error)

Start reads the graph once, starts serving, and starts polling. It returns as soon as the URL is usable.

func (*Server) Close

func (s *Server) Close() error

Close stops serving and releases the brain.

func (*Server) Observe

func (s *Server) Observe(ev Event)

observe is the hook the MCP middleware calls for every handled tool call.

func (*Server) Snapshot

func (s *Server) Snapshot() Snapshot

Snapshot is the graph as last read.

func (*Server) SourceName

func (s *Server) SourceName() string

SourceName names the brain this view reads, for a caller that wants to say so.

func (*Server) URL

func (s *Server) URL() string

URL is where the view is.

func (*Server) WatchesCalls

func (s *Server) WatchesCalls() bool

WatchesCalls reports whether tool calls reach this view. A view polling a database sees structure only; one fed by an MCP server sees the queries too, and the page says which rather than leaving a still ticker to be read as a fault.

type Snapshot

type Snapshot struct {
	Version int64  `json:"version"`
	Nodes   []Node `json:"nodes"`
	Edges   []Edge `json:"edges"`
}

Snapshot is one reading of the brain's entity graph.

type Source

type Source struct {
	Describe string
	Read     func(ctx context.Context) ([]Node, []Edge, error)
	Close    func() error
}

Source is where a live server reads the graph from.

func OpenSource

func OpenSource(ctx context.Context) (*Source, error)

OpenSource opens whichever brain this process is configured for. The local database is opened once and held: the poller reads it every couple of seconds, and reopening the file on that cadence would be pointless churn.

Jump to

Keyboard shortcuts

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