Documentation
¶
Overview ¶
Package wire is the serialized form of a search answer — the JSON contract MCP's search tool and the CLI's --json output both speak. It lives beside the search service for the same reason the service exists: two surfaces that answer the same query must not drift into describing that answer differently.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CompactFileGroup ¶ added in v0.14.0
type CompactFileGroup struct {
FilePath string `json:"file_path"`
Namespace string `json:"namespace,omitempty"`
Hits []CompactResultItem `json:"hits"`
}
CompactFileGroup groups compact hits under the one copy of their file path. @intent avoid repeating file identity on every hit while keeping federated namespace labels.
type CompactResponse ¶ added in v0.14.0
type CompactResponse struct {
Files []CompactFileGroup `json:"files"`
WeakFiltered int `json:"weak_filtered"`
Truncated bool `json:"truncated"`
PoolTruncated bool `json:"pool_truncated"`
Limits Limits `json:"limits"`
AnnotationCoverage evidence.Coverage `json:"annotation_coverage"`
Next []NextAction `json:"next,omitempty"`
Note string `json:"note,omitempty"`
}
CompactResponse is the token-efficient search view used by agents that do not need storage ids or redundant per-hit names and paths. @intent preserve search decisions, completion signals, and continuations in a smaller wire payload.
type CompactResultItem ¶ added in v0.14.0
type CompactResultItem struct {
QualifiedName string `json:"qualified_name"`
Kind graph.NodeKind `json:"kind"`
StartLine int `json:"start_line"`
EndLine int `json:"end_line"`
Intent string `json:"intent,omitempty"`
Matched []evidence.Match `json:"matched,omitempty"`
Reason string `json:"reason,omitempty"`
MatchedTerms []string `json:"matched_terms,omitempty"`
}
CompactResultItem keeps the evidence an agent needs to choose and open a hit, without repeating data already present in its file group. @intent reduce search-response context while preserving rank evidence and exact source bounds.
type FileGroup ¶
type FileGroup struct {
FilePath string `json:"file_path"`
Namespace string `json:"namespace,omitempty"`
HitCount int `json:"hit_count"`
Hits []ResultItem `json:"hits"`
}
FileGroup is one file and every hit it answered the query with.
The file is the unit of a search answer because it is the unit of reading: a caller picks a file first and a declaration inside it second. Grouping is also what let the old per-file cap go — ten hits in one file cost the reader one decision, not ten — so a file that appears here appears whole.
@intent let a caller choose between files, then read inside the one it chose.
type Limits ¶
type Limits struct {
Files int `json:"files"`
Offset int `json:"offset"`
HitBudget int `json:"hit_budget"`
}
Limits states the bounds that shaped this page, all counted in files except the budget, which only decides whether one more file joins. @intent let a caller tell a short answer from the first page of a long one.
type NextAction ¶
type NextAction struct {
Reason string `json:"reason"`
Tool string `json:"tool,omitempty"`
Args map[string]any `json:"args,omitempty"`
// Skill names a packaged workflow to run rather than a tool to call. It is
// set only for the step no tool can perform.
Skill string `json:"skill,omitempty"`
}
NextAction is one step that widens this answer, written out so an agent can take it without inventing anything.
Before this existed a response could say it withheld things and leave the caller with no way to reach them. Naming the tool and its arguments turns a dead-end count into a step.
Most steps are a call: Tool and Args. One is not, and cannot be — when the answer was empty because nobody ever recorded a reason, the fix is to write those reasons, which is reading and judgement rather than a query. That step names a Skill instead, and exactly one of the two forms is ever filled in.
@domainRule an action names either a Tool with its Args or a Skill, never both, so a caller never has to guess which one to act on. @intent turn what a search withheld into a step the caller can actually take.
type Response ¶
type Response struct {
Files []FileGroup `json:"files"`
FileCount int `json:"file_count"`
WeakFiltered int `json:"weak_filtered"`
// Truncated is true when this answer did not reach every file the query
// answered with. It is never about hits: a shown file is shown whole.
Truncated bool `json:"truncated"`
// PoolTruncated is true when the candidate pool behind this answer came back
// full, so the backend held at least as many candidates as the pool could
// take and may have held more.
//
// It is a second signal rather than part of Truncated because the two say
// different things and call for different moves. Truncated counts files this
// page did not reach, and stays about files. PoolTruncated says the page
// stopped at the edge of what was fetched. `truncated: false` with
// `pool_truncated: true` is the case that used to read as "that is
// everything" when it was not: ask for the next page anyway.
PoolTruncated bool `json:"pool_truncated"`
Limits Limits `json:"limits"`
// AnnotationCoverage is how many of the searched declarations recorded a
// reason — an @intent or a @domainRule — out of how many were indexed.
//
// It is on every answer, not only the empty ones, because it is what makes an
// answer's size readable: two files out of a repository where four hundred
// declarations recorded a reason is a thin answer, and two out of a repository
// where six did is most of what there was to find. `with_reason: 0` says the
// question was put to an index nobody has written anything into yet.
AnnotationCoverage evidence.Coverage `json:"annotation_coverage"`
Next []NextAction `json:"next,omitempty"`
Note string `json:"note,omitempty"`
}
Response wraps the file list so an empty answer can still say why.
It replaced a bare JSON array. An array has nowhere to put the reason a list came back short, and a caller that reads `[]` cannot tell "nothing was indexed under those words" from "everything found was unjustifiable".
@intent make a search answer self-describing, including when it is empty.
func NewResponse ¶
NewResponse converts an evidence list into the wire payload. @requires withNamespace is true only for federated searches, where a caller needs to know which repository a hit came from. @requires query, limit and offset are the ones this list was built with, so the suggested calls repeat the caller's own request. @ensures Next is empty exactly when the answer withheld nothing and had nothing to explain about coming back empty. @intent keep one conversion so no two search surfaces can drift apart.
func (Response) Compact ¶ added in v0.14.0
func (r Response) Compact() CompactResponse
Compact returns a smaller view without changing the full response contract. Search continuations retain compact mode so later pages do not grow again. @ensures every search action in Next carries compact=true. @intent let CLI and MCP share one loss-aware compact representation.
type ResultItem ¶
type ResultItem struct {
ID uint `json:"id"`
QualifiedName string `json:"qualified_name"`
Kind graph.NodeKind `json:"kind"`
Name string `json:"name"`
FilePath string `json:"file_path"`
StartLine int `json:"start_line"`
EndLine int `json:"end_line"`
// Intent is the node's own @intent tag, empty when nobody wrote one.
Intent string `json:"intent,omitempty"`
// Matched names the signals this query touched — name, path, intent — so a
// caller can tell an exact identifier hit from a hit on a written purpose.
Matched []evidence.Match `json:"matched"`
// Reason is the recorded reason the intent index answered with — set only
// when this hit came from the intent query, so its absence means the hit
// earned its place on name, path, or token overlap alone.
Reason string `json:"reason,omitempty"`
// MatchedTerms are the query terms written in Reason — the proof behind an
// intent match that token overlap alone cannot see.
MatchedTerms []string `json:"matched_terms,omitempty"`
Namespace string `json:"namespace,omitempty"`
}
ResultItem summarizes one node hit returned by full-text search. @intent preserve a stable per-item DTO for search responses. @domainRule Namespace is set only in federated (multi-namespace) mode so single-namespace responses stay unchanged.