Documentation
¶
Overview ¶
Package fix runs a fix a person asked for on one of their pull requests: an agent resolves its merge conflicts, fixes its failing checks or addresses its unresolved review comments in a temporary checkout of its branch, and baum commits the result and pushes it. After the push, baum replies on each review thread the agent addressed, with text it composes itself, and resolves the thread (see threads.go).
The agent gets write access to that checkout only, never git credentials or the network (see agent.Fixer). baum itself fetches the branch, starts the merge of the base branch for a conflict, commits what the agent left (with no hook running), refuses a result that does not descend from the head the fix was confirmed for, and pushes with a plain, never forced, git push using the user's own git credentials for the clone's remote. The checkout is a linked worktree of the registered clone under baum's cache directory, removed when the fix ends however it ends.
Index ¶
- Constants
- func CanPush(ctx context.Context, r Reader, repository github.Repository) (bool, error)
- func ChatDigest(c ChatContext) string
- func DefaultDirectory() (string, error)
- func Digest(threads []Thread) string
- func Excerpt(t Thread) string
- func Headline(body string) string
- func OpenForFetch(ctx context.Context, clone string, repository github.Repository) (*gitlocal.Repo, error)
- func PlainText(body string) string
- func Supported(backend string) bool
- type Answer
- type ChatContext
- type ChatTurn
- type Check
- func AllChecks(ctx context.Context, r Reader, repository github.Repository, sha string) (checks []Check, total int, err error)
- func FailingChecks(ctx context.Context, r Reader, repository github.Repository, sha string) ([]Check, error)
- func Logs(ctx context.Context, r Reader, repository github.Repository, checks []Check) []Check
- type Error
- type Options
- type Outcome
- type PullRequest
- type Reader
- type Selection
- type Thread
- type ThreadOutcome
- type ThreadWriter
Constants ¶
const ( MaxLogChecks = 4 MaxLogLines = 200 )
Bounds on what a check contributes to a prompt.
const ( ReasonFork = "fork" ReasonNoPushAccess = "no_push_access" ReasonNothingToFix = "nothing_to_fix" ReasonNoChat = "chat_unavailable" ReasonChatOutdated = "chat_outdated" ReasonUnsupportedBackend = "unsupported_backend" )
Why a fix cannot run, found before it is queued.
const ( ReasonHeadChanged = "head_changed" ReasonThreadsChanged = "threads_changed" ReasonChatChanged = "chat_changed" ReasonNoRemote = "no_remote" ReasonGit = "git" ReasonSigning = "signing" ReasonBackend = "backend" ReasonSignedOut = "signed_out" ReasonBudget = "budget" ReasonNoChanges = "no_changes" ReasonConflictsRemain = "conflicts_remain" ReasonHistoryRewritten = "history_rewritten" ReasonWorkflowChanged = "workflow_changed" ReasonPushRejected = "push_rejected" ReasonPushFailed = "push_failed" )
Why a fix that ran failed.
const ( MaxThreads = 20 // MaxReplySummary bounds, in characters, the agent's summary in a reply. MaxReplySummary = 200 )
Bounds on what review threads contribute to a prompt.
const ( // ThreadResolved: baum replied and resolved the thread. ThreadResolved = "resolved" // ThreadReplied: baum replied, but could not resolve the thread. ThreadReplied = "replied" // ThreadSkipped: the agent did not address the thread, or said nothing // of it; baum left it untouched. ThreadSkipped = "skipped" // ThreadAlreadyResolved: someone resolved the thread during the fix. ThreadAlreadyResolved = "already_resolved" // ThreadFailed: the reply could not be posted. ThreadFailed = "failed" )
What became of a thread after a fix.
const MaxAllChecks = 100
MaxAllChecks bounds how many checks the app lists; AllChecks reads more, up to maxCheckPages and maxStatusPages, so that sorting can choose which stay.
const MaxChatBytes = 32 << 10
MaxChatBytes caps the conversation a fix is given: the turns' questions, answers, citations and suggestions together.
Variables ¶
This section is empty.
Functions ¶
func CanPush ¶
CanPush reports whether the signed-in account may push to the repository: GitHub's permissions.push, which write, maintain and admin access give. Who wrote the pull request does not matter; whoever confirms the fix pushes.
func ChatDigest ¶
func ChatDigest(c ChatContext) string
ChatDigest identifies the conversation a fix was confirmed for, with its turns: a different conversation, turn or text changes it. It is empty without turns.
func DefaultDirectory ¶
DefaultDirectory is where fixes check out: fixes under the user's cache directory, outside every clone and outside the system temporary directory, which a Codex fix may not write to.
func Digest ¶
Digest identifies the threads a fix was started for, with their comments: a reply or an edit after the start changes it, and the fix must be started again.
func Excerpt ¶
Excerpt is the headline of a thread's first comment, at most 120 characters, for the job to show.
func Headline ¶
Headline is a review comment's point in one line of plain text: the first line written wholly in bold among its first few, where review bots put their title, or else its first line of text. HTML comments, tags, images (such as priority badges), code blocks and Markdown markup are left out, and a link keeps its text.
func OpenForFetch ¶
func OpenForFetch(ctx context.Context, clone string, repository github.Repository) (*gitlocal.Repo, error)
OpenForFetch opens the clone with the remote whose fetch URL, as configured or as git rewrites it, names repository, origin first, as the registry files a clone, for a read that only fetches: where it pushes does not matter. Its error is an *Error; the reason is ReasonNoRemote when no remote names the repository.
func PlainText ¶
PlainText is a review comment's body as plain text to show whole: HTML comments, tags and images are left out, emphasis and code marks dropped, a link keeps its text, a list item keeps a bullet or its number, and paragraphs stay apart by one blank line. A code block keeps its lines as written, without its fences.
Types ¶
type Answer ¶
type Answer struct {
Addressed bool
// Summary is one plain line: see cleanSummary.
Summary string
}
Answer is what the agent reported for one thread.
type ChatContext ¶
type ChatContext struct {
Conversation string `json:"conversation"`
Omitted int `json:"omitted,omitempty"`
Turns []ChatTurn `json:"turns"`
}
ChatContext is the conversation a fix is made from: the turns up to the one the fix was confirmed for, oldest first, within MaxChatBytes. Omitted counts the earlier turns CapChat left out.
func CapChat ¶
func CapChat(conversation string, turns []ChatTurn) ChatContext
CapChat keeps the newest turns of turns (oldest first) that fit in MaxChatBytes, dropping the oldest first and counting them in Omitted. A turn is never cut, except the newest when it alone exceeds the cap: it is then truncated, with a marker, to what fits.
type ChatTurn ¶
type ChatTurn struct {
Seq int `json:"seq"`
Question string `json:"question"`
Answer string `json:"answer"`
Citations []string `json:"citations,omitempty"`
Suggestion string `json:"suggestion,omitempty"`
}
ChatTurn is one answered turn of a reviewer's conversation with the agent that wrote the review. Question is stored as the reviewer typed it; Answer is the stored, already masked answer markdown. Both are masked again when the prompt is built.
type Check ¶
type Check struct {
Name string `json:"name"`
Conclusion string `json:"conclusion"`
// Status is queued, in_progress or completed; AllChecks sets it, and
// Conclusion is then empty until the check completes.
Status string `json:"status,omitempty"`
// Title, Summary and Text are a check run's output; a commit status has
// its description in Summary.
Title string `json:"title,omitempty"`
Summary string `json:"summary,omitempty"`
Text string `json:"text,omitempty"`
// Log is the part of a GitHub Actions job's log that shows the failure,
// read by Logs.
Log string `json:"log,omitempty"`
// JobID is the GitHub Actions job behind a check run, 0 for another app.
JobID int64 `json:"-"`
// URL is where the check's details are: the app's details page, else
// the check run on GitHub, or a commit status's target. The app links it;
// the prompt leaves it out.
URL string `json:"-"`
}
Check is a failing check of a pull request's head commit. Everything but Name and Conclusion comes from the check's own output and is untrusted.
func AllChecks ¶
func AllChecks(ctx context.Context, r Reader, repository github.Repository, sha string) (checks []Check, total int, err error)
AllChecks lists every check run (their latest attempt) and commit status of the head commit, passing or not, with their output bounded, in no particular order. It reads at most maxCheckPages pages of check runs and maxStatusPages of statuses, so a head with more has more checks than are returned; total is how many GitHub reports (never fewer than returned). The caller sorts and caps the list. A commit status that is pending is in_progress, and any other is completed; JobID is set only for a failing GitHub Actions run, as in FailingChecks.
func FailingChecks ¶
func FailingChecks(ctx context.Context, r Reader, repository github.Repository, sha string) ([]Check, error)
FailingChecks lists the head commit's failing check runs (their latest attempt) and commit statuses, at most 20, with their output bounded.
type Error ¶
Error is a fix that failed, with the machine-readable Reason. Its text is baum's own or git's sanitised stderr, never a provider's error, so a job may keep it.
type Options ¶
type Options struct {
// ID names the fix's directory and temporary refs: the job's ID.
ID string
// Clone is the registered clone's directory.
Clone string
Repository github.Repository
Number int
Title string
// HeadRef and HeadSHA are the branch to push to and the commit the fix
// was confirmed for; BaseRef the base branch.
HeadRef, HeadSHA, BaseRef string
// Conflicts merges the base branch first; Checks fixes the failing
// Checks.
Conflicts, Checks bool
Evidence []Check
// Threads are the review threads to address; Replies posts baum's
// replies on those the agent addressed, after the push.
Threads []Thread
// Chat, when set, is a reviewer's conversation with the agent that wrote
// the review, describing a change to make: untrusted data in the prompt.
Chat *ChatContext
Replies ThreadWriter
Agent agent.Fixer
// Backend and Model name the agent in the commit message.
Backend, Model string
// MaxCalls and MaxTokens bound the agent when set; zero is no limit.
// WallClock is its time limit, defaultWallClock when unset.
MaxCalls, MaxTokens int
WallClock time.Duration
// Logger receives how the agent ended, its error included, which the
// job keeps no text of; nil logs nothing.
Logger *slog.Logger
// Directory holds the fixes' temporary directories; empty is
// DefaultDirectory.
Directory string
// Progress receives the phase the fix is in.
Progress func(phase string)
// Env are the user's agent variables for the git commands of the fix
// (gitlocal.FixOptions.Env).
Env []string
// Prompts replace the built-in fix prompts (prompt.FixWith); nil keeps
// them. The texts must already be validated.
Prompts prompt.Overrides
// Transcript, when set, receives the agent's steps (agent.Request.Transcript).
Transcript func(agent.TranscriptEntry)
}
Options are one fix.
type Outcome ¶
type Outcome struct {
// Commit is the commit pushed to the pull request's branch.
Commit string
// Summary is the agent's final message, without its answer block about
// review threads.
Summary string
// Agent is the agent's run, nil when none was needed (a base branch
// that merged cleanly).
Agent *agent.Result
// Threads is what became of each review thread, in order, once the
// push succeeded.
Threads []ThreadOutcome
}
Outcome is what a fix did.
type PullRequest ¶
type PullRequest struct {
// Title is the pull request's, untrusted.
Title string
State string
Draft bool
HeadSHA string
// HeadRef is the head branch; HeadRepository and BaseRepository are
// "owner/name", and differ for a fork.
HeadRef, HeadRepository string
BaseRef, BaseRepository string
// Mergeable is nil while GitHub has not computed it.
Mergeable *bool
MergeableState string
URL string
}
PullRequest is what GitHub reports of a pull request a fix is for.
func ReadPullRequest ¶
func ReadPullRequest(ctx context.Context, r Reader, repository github.Repository, number int) (PullRequest, error)
ReadPullRequest reads an open pull request.
func (PullRequest) Conflicts ¶
func (p PullRequest) Conflicts() bool
Conflicts reports whether GitHub says the pull request cannot be merged cleanly into its base.
func (PullRequest) Fork ¶
func (p PullRequest) Fork() bool
Fork reports a head branch in another repository than the base, which a fix never pushes to.
type Reader ¶
type Reader interface {
Read(ctx context.Context, path, etag string) (int, http.Header, []byte, error)
Download(ctx context.Context, path string, w io.Writer) (int, error)
}
Reader is the GitHub REST access a fix needs; *github.RESTReader is one.
type Selection ¶
type Selection struct {
Threads []Thread
// Capped: more unresolved threads than MaxThreads, or than baum read.
Capped bool
// Untrusted counts the unresolved threads left out because an account
// without access to the repository started them.
Untrusted int
}
Selection is the threads a fix addresses, and what it left out.
func SelectThreads ¶
func SelectThreads(list github.ReviewThreads) Selection
SelectThreads picks the threads a fix addresses from what GitHub returned: those the signed-in account can reply to and resolve, whose first comment comes from a trusted author, the first MaxThreads in GitHub's order. Within a thread, comments of untrusted authors are left out.
type Thread ¶
type Thread struct {
Ref, ID, Path string
// Line is 0 for a comment on the whole file.
Line int
Outdated bool
// Comments are the comments of trusted authors, their bodies bounded.
Comments []github.ThreadComment
// LeftOut counts the thread's comments not in Comments: beyond the
// first ones baum read, or from accounts it does not trust.
LeftOut int
}
Thread is an unresolved review thread a fix addresses. Ref is its id in the prompt and in the agent's answer; ID, its GitHub node id, never reaches the agent.
type ThreadOutcome ¶
type ThreadOutcome struct {
Ref string `json:"ref"`
Outcome string `json:"outcome"`
Summary string `json:"summary,omitempty"`
}
ThreadOutcome is what became of one thread, with the agent's cleaned summary of it.
type ThreadWriter ¶
type ThreadWriter interface {
ThreadState(ctx context.Context, repository github.Repository, id string) (github.ThreadState, error)
ReplyToThread(ctx context.Context, repository github.Repository, id, body string) error
ResolveThread(ctx context.Context, repository github.Repository, id string) error
}
ThreadWriter is the GitHub access the replies need; *github.Client is one.