Documentation
¶
Overview ¶
Package wire implements the GCX1 compact wire format for Gortex MCP tool responses. GCX1 is a tab-delimited, line-oriented, round-trippable format with a self-describing header. See docs/wire-format.md.
Index ¶
Constants ¶
const CommentPrefix = "#"
CommentPrefix marks human-readable comment lines. Comments have no effect on decoding and may be dropped by intermediaries.
const FieldSep = "\t"
FieldSep is the row column delimiter. Tab never appears in code symbol names and is treated as whitespace by GPT tokenizers.
const RowSep = "\n"
RowSep terminates a row. Newline is also tokenizer-friendly and survives transports that re-flow whitespace but preserve line breaks.
const Version = 1
Version is the current GCX protocol version. Bump on any backward-incompatible change to the header syntax or escape rules.
Variables ¶
var Tag = fmt.Sprintf("GCX%d", Version)
Tag is the four-byte header magic that starts every GCX payload. It is a literal prefix ("GCX" + Version as a decimal digit); the decoder rejects anything that does not match.
Functions ¶
func EncodeAny ¶
EncodeAny writes v to w as a GCX1 payload using a generic shape-inference encoder. It is the fallback used when no hand-tuned encoder has been registered for the tool. Supported shapes:
A JSON object ("record") becomes a single header + single row where fields are the top-level keys (sorted alphabetically) and values are their scalar representations. Nested objects / arrays are JSON-serialised into the cell.
A JSON array of objects ("rows") becomes a header with the union of top-level keys across elements (sorted) and one row per element.
A JSON array of scalars becomes a header with a single "value" field and one row per element.
A scalar value becomes a header with a single "value" field and one row.
Anything else is rejected so an unencodable shape cannot silently degrade the wire format. Callers should prefer hand-tuned encoders for hot-path tools; the generic fallback exists for breadth.
Types ¶
type Decoder ¶
type Decoder struct {
// contains filtered or unexported fields
}
Decoder reads a GCX1 payload. It parses the header on first call to Header() (or implicitly on the first NextRow()), then streams rows as ordered field maps. Comments and blank lines are skipped.
Decoder is not safe for concurrent use.
Multi-section payloads are supported: after NextRow returns io.EOF, callers can invoke NextSection to read the next header if the stream is not exhausted.
func NewDecoder ¶
NewDecoder wraps r in a bufio.Scanner with a buffer large enough for representative tool responses. The default Scanner line limit (64 KiB) is too small for payloads such as get_symbol_source on large functions; we raise it to 4 MiB. Payloads exceeding that cap should be streamed on the sender side instead.
func (*Decoder) All ¶
All consumes the stream and returns every row as a slice. Convenient for tests and small responses; prefer NextRow for streaming.
func (*Decoder) Header ¶
Header returns the parsed header, reading from the underlying reader if it has not been parsed yet.
func (*Decoder) NextRow ¶
NextRow returns the next data row as a map keyed by the declared field names. It returns (nil, io.EOF) when the current section ends (either at end of stream or when the next header line is encountered). Comment lines and blank lines are skipped. Rows with fewer values than declared fields fill missing keys with "". Rows with more values than declared fields return an error.
func (*Decoder) NextSection ¶
NextSection advances to the next logical payload and returns its header. Callers invoke NextSection after NextRow returns io.EOF to check whether the stream contains additional sections. It returns io.EOF when no further section exists.
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
Encoder writes a GCX1 payload. It emits the header immediately on construction so callers can start streaming rows without a separate Start() call. Row values are stringified with fmt.Sprint-compatible rules (bool → "true"/"false", int → decimal, float → %g, nil → "").
Encoder is not safe for concurrent use.
func NewEncoder ¶
NewEncoder writes the header for h to w and returns a ready encoder. Any error from writing the header is sticky: subsequent WriteRow and WriteComment calls return it without attempting further I/O.
func (*Encoder) Close ¶
Close is a no-op retained for symmetry with bufio-style encoders and to let callers evolve to a buffering impl without churn.
func (*Encoder) WriteComment ¶
WriteComment writes a "# ..." line. Intermediate newlines in s are escaped so the comment stays on one physical line.
type Format ¶
type Format int
Format selects the output encoding for an MCP tool response.
func ParseFormat ¶
ParseFormat maps an MCP tool-argument string to a Format. Unknown values return FormatJSON to stay safe. The caller should separately honour the deprecated `compact: true` boolean by mapping it to FormatText.
type Header ¶
type Header struct {
Version int // always Version for now
Tool string // MCP tool name
Fields []string // declared column order for the row stream
Meta map[string]string // additional k=v pairs (rows=, ms=, ...)
}
Header is the first line of a GCX1 payload. It declares the tool that produced the payload, the field order of the row stream, and optional free-form metadata.
Wire layout:
GCX1 tool=<tool> fields=<f1>,<f2>,... [k=v]...