bare

package
v0.7.1 Latest Latest
Warning

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

Go to latest
Published: Oct 5, 2026 License: Apache-2.0 Imports: 27 Imported by: 0

Documentation

Overview

Package bare — edit matching logic, pinned to pi's edit-diff.js.

Package bare — the three read-only tools (grep, find, ls) that pi registers but leaves inactive by default. They shell out to ripgrep and fd rather than reimplementing search in Go, matching pi's behavior exactly — including the error strings when the tools are missing.

Package bare — the four pi wire tools. See truncate.go and editdiff.go for the matching/truncation logic this file drives.

Package bare is the wire tool library: pi 0.82.1's seven tools (read, bash, edit, write, grep, find, ls) with the matching, truncation and streaming logic behind them. Chat's tool surface is built from it. It is codeaf-owned code — not a vendored copy of pi — but the schemas, result strings and truncation footers are pinned to pi's source so the wire bytes a model sees are identical to the ones these tools were measured on.

THE DESCRIPTIONS THAT QUOTE A LIMIT ARE THE EXCEPTION, and they have to be. pi's are literals because pi's caps are literals; here the caps follow the model's window (Caps), so read, bash, grep, find and ls render their figures from the pair they are actually applying. read and bash were cut to their contract in the same pass — what the tool does and what it costs, with the question of which work belongs on which door left to the page that owns it. edit and write are pi's, verbatim.

Index

Constants

View Source
const (
	MaxResultLines = defaultMaxLines
	MaxResultBytes = defaultMaxBytes
)

MaxResultLines and MaxResultBytes are the caps a belt that cannot say how much room its model has bounds a tool RESULT by. They are exported so that a caller which has to bound output of its own — the sentence a promoted bash call answers with, which is the same output the same call would have returned had it finished — bounds it by the same two numbers rather than inventing a third. A caller that knows the window passes Caps instead.

View Source
const BashCeilingSeconds = 600

BashCeilingSeconds is the bound a foreground bash call runs under when the model named no usable timeout of its own — ONE NUMBER, typed once, read by this tool, by the session's own law (internal/session.BashCeilingSeconds) and by the surface that counts down against it.

There used to be no default here at all — pi's choice for a bare loop, and the wrong one for a worker nobody is watching: a headless leaf that ran `find / -name "luhn*"` held its node for the whole of the task's deadline, two of seven workers at once, with the run's own log saying only that the last model call was minutes ago. Ten minutes is longer than almost every build, test suite and script a worker runs in one call; a call that is meant to outlive it is a background job, which is a decision the model makes rather than one the clock makes for it. With a promoter present the bound is a handoff (promote.go); with none, the process group is killed and the call says so.

View Source
const ResultByteCap = defaultMaxBytes

ResultByteCap is [defaultMaxBytes] for tools that live outside this package. A tool result is a tool result whatever it read, so anything else on the belt that has to bound one binds itself to the number the read tool's own description quotes rather than to a second copy of it that can drift away.

Variables

This section is empty.

Functions

func ReadContentless

func ReadContentless(text string) bool

ReadContentless reports whether a successful read answer carried no file bytes at all. The ONE such answer is the exceeds-limit line diagnostic [readTool] emits instead of content, and the held-ranges ledger must never record it as bytes the conversation holds.

func ReadPagingFooter

func ReadPagingFooter(text string) bool

ReadPagingFooter reports whether a read result's text carries either of the two paging footers [readTool] appends. The converse is the ONLY door the holder of those bytes learns the file ended inside what it got: the footers are the tool's own sentences, built here and matched here, so the session's ledger reads the format at its one seam instead of guessing at strings.

func ResolvePath

func ResolvePath(path, cwd string) string

ResolvePath is [resolveToCwd] for the wrappers the session fits around these tools: write's append mode reads the file the inner write will land on, and resolving that path any other way would be a second, driftable copy of pi's normalization.

func RunBash

func RunBash(ctx context.Context, cwd string, args json.RawMessage, caps Caps, output io.Writer) (string, bool, error)

RunBash runs the ordinary non-interactive shell and mirrors its raw output to a caller-owned writer as it arrives. The runner retains its normal bounds, cancellation, process isolation and spill handling.

func RunStaged

func RunStaged(ctx context.Context, staged Staged) (string, bool, error)

RunStaged is the seam between the two halves: it waits at the Hold the context carries, if any, then commits the call or withdraws it.

A context with no hold is released already, which is every call that was not started early and every caller outside a turn: the halves run back to back.

func StreamingEnv

func StreamingEnv() []string

StreamingEnv is the environment such a command runs in: the person's own, plus the one variable that stops Python holding its output back.

IT ALSO CARRIES THE TMUX FLOOR AND STRIPS PROVIDER KEYS. A command the model runs must not reach the tmux server hosting codeaf, and must not read back a provider credential codeaf itself holds, so the environment is passed through internal/exec's exec.JobShellEnv, which strips TMUX, TMUX_PANE and every provider key codeaf knows about, and points TMUX_TMPDIR at a directory codeaf owns (see tools.go for why both tmux halves are the floor, and for the opt-in a task can use to keep a key). This is the bare path's one seam for a model's shell — the foreground bash tool and the session's job registry both reach it through here — so the strip lives here rather than at each caller.

THE PERSON'S OWN SETTING WINS. Somebody who exported PYTHONUNBUFFERED themselves — to any value, including an empty one — meant it, and a harness that overwrote it would be making a decision about their program that they had already made.

func StreamingShell

func StreamingShell(command string) (string, []string)

StreamingShell is the shell one command runs under, wrapped so its output arrives line by line where the machine allows it.

It is the ONE place the shell is chosen for a command whose output somebody reads while it runs — the foreground bash tool here, and the background job registry in internal/session, which used to keep a hand-copied three-line version of the choice and now asks this instead.

func TailForResult

func TailForResult(text string) string

TailForResult bounds text the way a finished bash call's output is bounded: the LAST whole lines that fit inside MaxResultLines and MaxResultBytes.

The tail rather than the head, for bash's own reason — the verdict of a command is at the end of it — and through the same function, so a partial answer and a complete one are cut by one rule.

func TailForResultAt

func TailForResultAt(text string, caps Caps) string

TailForResultAt is TailForResult under the belt's own caps, for a caller whose bash was built with them: the answer a promoted call hands back must be cut where the call itself would have been cut, not somewhere else.

func WidestGrepDescription

func WidestGrepDescription(caps Caps) string

WidestGrepDescription is the longer of the two sentences `grep` can carry — the one a machine with NO ripgrep is handed.

A DESCRIPTION THAT DEPENDS ON THE MACHINE IS STILL A BYTE ON EVERY REQUEST, and the gate that bounds the fixed prefix (internal/session's prefixbudget_test.go) runs on machines of both kinds: the same commit weighed 53,025 bytes on a laptop with ripgrep and 53,132 on a runner without it, so the gate passed where it was written and failed where it was proved. The gate weighs what the WIDEST machine pays, and this is the one place that knows which sentence that is.

func WithBashPromoter

func WithBashPromoter(ctx context.Context, promoter BashPromoter) context.Context

WithBashPromoter returns ctx carrying the door a foreground bash call is offered through. A context without one runs bash exactly as it always ran: the timeout kills the process group and the call answers `Command timed out after N seconds`.

func WithHold

func WithHold(ctx context.Context, h *Hold) context.Context

WithHold returns a context that holds a staged call run on it at RunStaged until h is decided.

Types

type BashCall

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

BashCall is one running foreground bash process, offered to whoever put a BashPromoter in the call's context.

It is a HANDLE and not a copy: the process, its output and its exit code are still bare's until somebody adopts it, and after that they are the adopter's and bare stops speaking about them entirely.

func (*BashCall) Adopt

func (c *BashCall) Adopt(take func() (answer string, isError bool, ok bool)) bool

Adopt hands the running process to a caller that will keep it alive.

`take` runs INSIDE the claim, which is the whole design: it is the one moment where nothing else can end the call, so whatever the adopter has to do to make the process its own — open a log, register it, start reading BashCall.Exit — happens with the ending already spoken for. It returns the sentence the tool call answers with, whether that sentence is an error, and whether the adoption happened at all; a false gives the claim back and leaves the call exactly as it was.

Adopt refuses a call that has already ended, and it refuses a call whose context is cancelled — see this file's header on why an interrupt is not negotiable.

func (*BashCall) Attach

func (c *BashCall) Attach(w io.Writer)

Attach points the running command's output at w: everything bare has kept so far is replayed into it, and everything the command writes from here on goes there and nowhere else.

The replay is bare's ROLLING TAIL and not necessarily the whole output — a foreground call keeps the last few hundred kilobytes and nothing before that — so a job promoted out of a very loud command begins where that tail begins. Saying so is the honest thing; pretending otherwise would put a hole in the middle of a log file somebody is about to read.

func (*BashCall) Command

func (c *BashCall) Command() string

Command is the shell command this call is running, verbatim.

func (*BashCall) Exit

func (c *BashCall) Exit() <-chan int

Exit delivers the process's exit code, exactly once, from the goroutine that was already waiting on it. An adopter reads this instead of waiting.

func (*BashCall) Kill

func (c *BashCall) Kill()

Kill ends the process group the way the timeout would have. It is here for an adopter whose own adoption failed halfway and who must not leave the process behind.

func (*BashCall) Process

func (c *BashCall) Process() *exec.Cmd

Process is the running command's frame. An adopter needs it for exactly one thing — signalling the process GROUP, which bash set up with Setpgid — and a promoted process keeps that group, so a kill still reaches the whole tree.

It must not be waited on. See this file's header: the wait is already in flight, and its result comes back on BashCall.Exit.

func (*BashCall) RunningFor

func (c *BashCall) RunningFor() time.Duration

RunningFor reports how long this process has been alive. It deliberately reads the clock rather than storing a second elapsed counter: adoption does not restart the process, so its original start remains the only honest age.

type BashPromoter

type BashPromoter interface {
	// Started is called once, as soon as the process is running. The function
	// it returns — which may be nil — is called when the call is over, adopted
	// or not, so the promoter can forget it.
	Started(call *BashCall) (finished func())
	// TimedOut is called when the timeout fires, INSTEAD of the kill. Returning
	// true means the promoter took the process and the kill must not happen;
	// returning false leaves the timeout to do what it has always done.
	TimedOut(call *BashCall) bool
}

BashPromoter is the door a caller puts in a bash call's context to be offered the running process.

Both methods may be called from goroutines other than the one running the tool, and both may be called concurrently with the process exiting — every decision they make goes through BashCall.Adopt, which is where the race is settled.

type Caps

type Caps struct {
	MaxLines int
	MaxBytes int
}

Caps are the two bounds every result in this package is cut to, and they travel with the belt rather than sitting in a constant.

ONE READ MAY NOT BE MOST OF WHAT THE MODEL CAN HOLD. Cutting every result at pi's flat 50KB is right for the window pi's numbers were measured against and wrong below it: on a 16k model one `read` of one file was 78% of everything the model could carry, so the file arrived and there was no room left to think about it. The caps therefore follow the window (see CapsFor), and the descriptions the model reads are rendered from the pair actually in force — a tool that quotes a limit it is not applying is a tool the model plans wrongly around.

func CapsFor

func CapsFor(contextTokens int) Caps

CapsFor scales the pair to a model's context window, through the one law that owns the share (ctxbudget.ToolResultBytes) rather than a second formula of this package's own.

The line cap follows the byte cap in pi's own proportion, because the two bind together and moving one alone would change which of them a given output is cut by. A window of 128,000 tokens or more lands exactly 2000 lines and 50KB, which is what keeps every frontier conversation byte-identical to what it was.

func DefaultCaps

func DefaultCaps() Caps

DefaultCaps is pi's own pair: 2000 lines or 50KB, whichever binds first. It is what a belt built without a window gets, so a caller that knows nothing about the model behaves exactly as this package did before caps existed.

type Hold

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

Hold is where an early start keeps a staged call between its two halves, until it knows whether the message carrying the call arrived whole.

IT IS DECIDED ONCE. The first of Hold.Release and Hold.Withdraw wins and every later one is a no-op, so the loop may withdraw on every road out of an attempt — a retry, a steer, a refused reply, the end of the turn — without asking whether some other road already released the call. Both methods are safe on a nil Hold, which is the hold of a call that was never held.

func NewHold

func NewHold() *Hold

NewHold is a hold nobody has decided yet.

func (*Hold) Release

func (h *Hold) Release()

Release lets the held call go ahead: its message arrived whole and is in the transcript.

func (*Hold) Withdraw

func (h *Hold) Withdraw()

Withdraw takes the held call back: its message did not arrive whole, or the turn will not run it.

type Staged

type Staged interface {
	// Commit finishes the call — waits for whatever the work still needs, lets
	// it go — and returns what Execute returns.
	Commit(ctx context.Context) (text string, isError bool, err error)
	// Withdraw takes back everything the first half did: a slot it took, a card
	// it showed, a clock it started. Nothing may be left behind that says the
	// call happened, because as far as the conversation will ever record, it
	// did not.
	Withdraw()
}

Staged is one call of a staged tool, taken as far as it goes without letting anything go.

Exactly one of the two methods is ever called, and at most once: a call either goes ahead or is taken back, never both and never twice. RunStaged is the only caller of either, which is what keeps that true.

func Settled

func Settled(text string, isError bool) Staged

Settled is a Staged whose answer is already known: a refusal the first half reached before it did anything that would need taking back. Committing it hands the refusal over; withdrawing it has nothing to undo.

type Tool

type Tool struct {
	Name        string
	Description string
	Schema      json.RawMessage
	Execute     func(ctx context.Context, args json.RawMessage) (text string, isError bool, err error)
	// contains filtered or unexported fields
}

Tool is the shape every tool in this package wears, and the shape a surface registers one under. Name, Description, and Schema are sent verbatim on the wire; Execute returns the model-visible text, an isError flag (for pi's thrown-error semantics), and a Go error for harness-level failures only.

func AllTools

func AllTools(cwd string) []Tool

AllTools returns all seven pi tools in registry order: read, bash, edit, write, grep, find, ls. The first four are active by default (Tools returns them); grep, find, and ls are registered but inactive unless activated.

It cuts results at pi's own caps, which is what a caller that cannot say how much room the model has should get. A caller that CAN say builds the same seven through AllToolsCapped.

func AllToolsCapped

func AllToolsCapped(cwd string, caps Caps) []Tool

AllToolsCapped is AllTools with the belt's own result caps, derived from the model's context window by CapsFor. The caps reach the descriptions as well as the truncation: every number these seven tools quote is rendered from the pair they are actually applying.

func ReadTool

func ReadTool(cwd string, maxBytes int) Tool

ReadTool returns the ordinary read hand with a smaller content budget. Its paths, line offsets, errors and continuation footers are otherwise identical. This is for belts that reserve part of their total result bound for the footer; values outside the ordinary range use the ordinary 50KB ceiling.

func StagedTool

func StagedTool(name, description string, schema json.RawMessage, stage func(ctx context.Context, args json.RawMessage) Staged) Tool

StagedTool is the one way to build a tool that may start before the message carrying its call is whole. Execute is derived from stage and is the two halves run back to back through RunStaged; nothing outside this package can build a tool whose Tool.Stages answers yes.

func Tools

func Tools(cwd string) []Tool

Tools returns the four default active pi tools in registry order: read, bash, edit, write. The schemas are the exact verbatim pi strings and go on the wire, so those bytes are pinned to pi's source; the descriptions are this package's own where a cap or a contract had to move (see the block of them below).

func ToolsCapped

func ToolsCapped(cwd string, caps Caps) []Tool

ToolsCapped is Tools with the belt's own result caps. See AllToolsCapped.

func (Tool) Stages

func (t Tool) Stages() bool

Stages reports whether this tool was built by StagedTool, which is the property an early start keys on: a call to such a tool may begin while its message is still arriving, because everything it does before RunStaged's hold can be taken back.

Jump to

Keyboard shortcuts

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