Documentation
¶
Overview ¶
Package runview is a read-only, local web viewer for one run's journal: a plan flow's declared topology with the run's path drawn over it, or an agent run's timeline of model turns, tool calls, attempts, approvals and halts, with the audit verdict when a signed head or evidence package is given. It never writes to the store it reads, and it serves on a loopback address only (see Listen). The bide-view command (cmd/bide-view, its own module) is its front end.
Index ¶
- func Handler(o Options) http.Handler
- func Listen(addr string) (net.Listener, error)
- func Main(args []string, stdout, stderr io.Writer, stores Stores) int
- type ApprovalCheck
- type Approvals
- type Conformance
- type Decision
- type Event
- type Exports
- type Flow
- type Gate
- type Graph
- type GraphEdge
- type GraphNode
- type Halt
- type JournalSource
- type Options
- type Proof
- type Prover
- type Source
- type Stores
- type View
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Handler ¶
Handler serves the run list at / and a run at /run?id=<run> (its View as JSON at /run.json?id=<run>). It answers only GET and HEAD, and only requests addressed to a loopback host, so a page on another site cannot read it through a rebound DNS name.
Types ¶
type ApprovalCheck ¶
ApprovalCheck is audit.VerifyApprovals' verdict on one gate, in words.
type Approvals ¶
type Approvals struct {
Keys agent.ApproverVerifierFor
Expected *agent.ApprovalPolicy
}
Approvals configures the approval-signature check a Prover runs: Keys resolves each approver's public key (nil: no check), and Expected, when set, is the policy the auditor expects, which the check runs against instead of the policy the gate's tally records.
type Conformance ¶
type Conformance struct {
OK bool `json:"ok"`
Method string `json:"method"` // "plan.Conform", or "structural" (see structural)
Diffs []string `json:"diffs,omitempty"`
Digest string `json:"digest"` // "match", "mismatch", or "not compared"
}
Conformance is the verdict on whether the run followed the declared topology.
type Decision ¶
type Decision struct {
Approver string `json:"approver,omitempty"` // empty for a one-decision gate's Approve
Approved bool `json:"approved"`
Signed bool `json:"signed"`
}
Decision is one recorded approval decision.
type Event ¶
type Event struct {
Seq int `json:"seq"` // 1-based position in the journal
Name string `json:"name"` // the record's journal name
Kind string `json:"kind"` // agent.StepKind
Class string `json:"class"` // the row's style: model, tool, attempt, approval, halt, end, value
Title string `json:"title"`
Detail string `json:"detail,omitempty"`
Badges []string `json:"badges,omitempty"`
}
Event is one journal record, as a timeline row.
type Exports ¶
Exports is a Source over exported journals (audit.JournalExport), by run ID.
type Flow ¶
type Flow struct {
Topology plan.Topology
// Digest is flow.Digest(), compared with the digest the run journaled. Empty: not compared.
Digest string
// Conform is flow.Conform. Nil: the viewer runs only its structural check (see Conformance).
Conform func(ctx context.Context, j *agent.Journal, runID string) (bool, []string, error)
}
Flow is a declared flow the viewer draws a run against. The journal records a flow run's name and topology digest, not its topology, so the topology comes from the caller: a program that holds the *plan.Flow passes its Topology, Digest and Conform; the bide-view command reads a Topology exported as JSON (json.Marshal(flow.Topology())) and, optionally, the digest.
type Gate ¶
type Gate struct {
ToolUseID string `json:"tool_use_id"`
ToolName string `json:"tool_name,omitempty"`
Single bool `json:"single,omitempty"` // a one-decision gate (agent.Approve)
Need int `json:"need,omitempty"`
Approvers []string `json:"approvers,omitempty"`
ApprovedBy []string `json:"approved_by,omitempty"`
DeniedBy []string `json:"denied_by,omitempty"`
Pending []string `json:"pending,omitempty"`
Decisions []Decision `json:"decisions,omitempty"`
Tallied bool `json:"tallied"` // the gate journaled its terminal tally
// Waiting: the run paused at this gate (its approval-pending record, agent.ApprovalWait) and
// the call has no result, no terminal tally, and (for a one-decision gate) no decision yet.
Waiting bool `json:"waiting"`
// Signatures is whether the gate's approver signatures were verified (audit.VerifyApprovals,
// with -approver-keys), or why they were not checked; SignaturesOK reports a verified gate.
Signatures string `json:"signatures"`
SignaturesOK bool `json:"signatures_ok"`
Status string `json:"status"`
}
Gate is a tool call's approval gate, from the decisions and tally the journal holds.
type Graph ¶
type Graph struct {
Nodes []GraphNode `json:"nodes"`
Edges []GraphEdge `json:"edges"`
SVG string `json:"-"`
Mermaid string `json:"mermaid"`
Width int `json:"-"`
Height int `json:"-"`
}
Graph is the declared topology with the run's path overlaid.
type GraphEdge ¶
type GraphEdge struct {
From string `json:"from"`
To string `json:"to"`
Label string `json:"label,omitempty"`
Taken bool `json:"taken"`
Back bool `json:"back,omitempty"`
}
GraphEdge is one declared edge or Switch arm, and whether the run took it.
type GraphNode ¶
type GraphNode struct {
Name string `json:"name"`
Kind string `json:"kind"`
Status string `json:"status"` // done, halted, attempted, not-reached
Iters int `json:"iters,omitempty"`
Last bool `json:"last,omitempty"`
// contains filtered or unexported fields
}
GraphNode is one declared node and what the run did with it.
type Halt ¶
type Halt struct {
Op string `json:"op"` // "tool" or "step"
ID string `json:"id"` // the tool-use ID, or the step name ("node:<name>" for a plan node)
ToolName string `json:"tool_name,omitempty"`
Marker string `json:"marker"`
AttemptedAt time.Time `json:"attempted_at,omitzero"`
Ref string `json:"ref"` // the agent.HaltRef to resolve it with, as Go
}
Halt is an operation whose attempt marker is live with no result: a resume of the run returns *agent.OutcomeUnknown for it until agent.ResolveHalt records its outcome.
type JournalSource ¶
JournalSource reads a store through a Journal. Runs lists through the store's agent.Lister, when it has one.
type Options ¶
type Options struct {
Source Source
// Flows are the declared flows runs are drawn against, by flow name.
Flows map[string]*Flow
// Provers check runs against audit artifacts; the first to return a verdict for a run wins.
Provers []Prover
}
Options configure Handler.
type Proof ¶
type Proof struct {
Source string `json:"source"` // "signed tree head" or "evidence package"
OK bool `json:"ok"`
Summary string `json:"summary"`
Covers int `json:"covers"` // journal records the signed head commits to
Problems []string `json:"problems,omitempty"`
Items []string `json:"items,omitempty"`
// Approvals is the signature verdict on each m-of-n gate that journaled its tally, by
// tool-use ID: audit.VerifyApprovals over the gate's evidence, with the approver keys given.
// Nil without approver keys.
Approvals map[string]ApprovalCheck `json:"approvals,omitempty"`
}
Proof is the audit verdict on the run's journal, from the audit package's own verifiers (the code bide-audit verify and verify-evidence run), never a reimplementation.
type Prover ¶
Prover checks a run's records against an audit artifact. It returns nil for a run the artifact is not about.
func EvidenceProver ¶
func EvidenceProver(pkg audit.EvidencePackage, v audit.Verifier, ap Approvals, opts ...audit.EvidenceVerifyOption) Prover
EvidenceProver checks an evidence package (audit.EvidencePackage.Verify, as bide-audit verify-evidence does) and that its signed head commits to the journal shown.
With approver keys (ap.Keys non-nil), it also checks each m-of-n gate's signatures with audit.VerifyApprovals over the package's actions, as bide-audit verify-approvals does.
func HeadProver ¶
HeadProver checks a signed tree head: its signature under v and the timestamp rule (audit.CheckTimestamp), and that its root commits to the first sth.Size records of the journal shown, by building and verifying an inclusion proof of the last of them (audit.ProveRecord, ProofBundle.Verify), as bide-audit prove and verify do.
With approver keys (ap.Keys non-nil), it also checks each m-of-n gate's signatures: it builds the gate's evidence from the journal under sth (audit.ApprovalEvidence) and verifies it with audit.VerifyApprovals, as bide-audit verify-approvals does.
type Source ¶
type Source interface {
Runs(ctx context.Context) ([]string, error)
History(ctx context.Context, runID string) ([]agent.Record, error)
}
Source is what the viewer reads: the runs it lists and each run's records. Both are reads.
type Stores ¶
type Stores struct {
SQLite func(path string) (agent.Store, io.Closer, error)
Postgres func(dsn string) (agent.Store, io.Closer, error)
}
Stores opens the stores bide-view reads, read-only. It is how the command plugs in store backends (store/sqlite's and store/postgres's OpenReadOnly) without the core module importing one. A nil opener means this build cannot read that kind of store.
type View ¶
type View struct {
RunID string `json:"run_id"`
Kind string `json:"kind"` // agent.RunKind, or "" when the run has no run:start
Input string `json:"input,omitempty"`
Flow string `json:"flow,omitempty"` // the flow name run:start records
Digest string `json:"digest,omitempty"` // the topology digest flow:digest records
// State is the agent.RunState, except "halted" for a started run with a live attempt marker
// and no result (see Halts): a resume returns *agent.OutcomeUnknown, so it is not in progress.
State string `json:"state"`
StateText string `json:"state_text"` // State as the page shows it ("halted: outcome unknown")
Terminal string `json:"terminal,omitempty"`
Records int `json:"records"`
Events []Event `json:"events"`
Halts []Halt `json:"halts,omitempty"`
Gates []Gate `json:"gates,omitempty"`
Graph *Graph `json:"graph,omitempty"`
Conform *Conformance `json:"conformance,omitempty"`
Proof *Proof `json:"proof,omitempty"`
Notes []string `json:"notes,omitempty"` // what the page cannot show for this run, and why
LastNode string `json:"last_node,omitempty"`
FinalText string `json:"final_text,omitempty"`
}
View is everything the run page shows, built from the run's records alone (see Build).