Documentation
¶
Overview ¶
Package factory runs an implementer agent on a sidecar and loops it through review and validation until the checks pass or attempts run out.
Index ¶
- Constants
- func Feedback(checks []Check) string
- func Passed(checks []Check) bool
- func Provision(ctx context.Context, client *circleci.Client, orgID, image, repoPath string, ...) (impl *sidecar.PoolEntry, revs []*sidecar.PoolEntry, err error)
- func Teardown(client *circleci.Client, entries []*sidecar.PoolEntry) error
- func ValidationCommands(cmds []config.Command) []config.Command
- type Activity
- type Change
- type Check
- type Event
- type EventKind
- type Implementer
- type Kind
- type Loop
- type Outcome
- type Relay
- type Result
- type Sidecars
- func (s *Sidecars) Check(ctx context.Context, _ int) ([]Check, error)
- func (s *Sidecars) Collect(ctx context.Context) (Change, error)
- func (s *Sidecars) Implement(ctx context.Context, prompt string) (Turn, error)
- func (s *Sidecars) Prepare(ctx context.Context, workDir string) error
- func (s *Sidecars) WritePatch(ctx context.Context, path string) (Change, error)
- type Status
- type Steps
- type Turn
Constants ¶
const DefaultImplementTimeout = 30 * time.Minute
DefaultImplementTimeout bounds one implementer turn. A turn writes code and may run the tests several times, so it gets longer than a review.
Variables ¶
This section is empty.
Functions ¶
func Feedback ¶
Feedback renders the failed checks of a round as the implementer's next prompt, or "" when nothing failed. Errored checks are left out: they say nothing about the code, and asking the implementer to fix them would send it chasing infrastructure.
func Passed ¶
Passed reports whether every check passed. An errored check is not a pass: a round where a review could not run has not shown the code is clean.
func Provision ¶
func Provision(ctx context.Context, client *circleci.Client, orgID, image, repoPath string, reviewers int, status iostream.StatusFunc) (impl *sidecar.PoolEntry, revs []*sidecar.PoolEntry, err error)
Provision creates the implementer's sidecar and one per reviewer, in parallel, and waits until each accepts connections. On error, any sidecar it created is deleted.
Types ¶
type Activity ¶
type Activity struct {
// Tool is the tool used, or "" for text the implementer wrote.
Tool string
// Detail is the tool's target (a file, a command) or the text.
Detail string
}
Activity is one thing the implementer did, for display.
type Change ¶
type Change struct {
// Fingerprint identifies the content of the change, so a round in which
// the implementer changed nothing can be detected.
Fingerprint string
// Stat is git's one-line summary, such as "3 files changed, 40 insertions(+)".
Stat string
}
Change is the implementer's work so far, relative to the baseline.
type Check ¶
type Check struct {
Name string
Kind Kind
Status Status
SidecarID string
Duration time.Duration
// Feedback is what the implementer is told when the check failed.
Feedback string
// Error is why the check could not run, for StatusErrored.
Error string
// Findings are a review's findings, kept as data for display.
Findings []review.Finding
}
Check is the outcome of one review or validation command in one round. A review is treated like any other command run on a sidecar: it passes or fails, and a failure carries feedback for the implementer.
func FromCommand ¶
func FromCommand(name, sidecarID string, exitCode int, output string, d time.Duration, runErr error) Check
FromCommand converts one validation command's run into a check. runErr is a failure to run the command at all, as opposed to it exiting non-zero.
func FromReview ¶
FromReview converts one review result, run with structured findings, into a check. A review fails only on findings worth changing (high or medium), the same bar the session loop uses, so the implementer is not sent round after round to polish style remarks. Lower findings are kept for display. A review that could not run errored.
type EventKind ¶
type EventKind int
EventKind identifies a step of the loop for display.
const ( EventImplementing EventKind = iota // a turn started; Round, Prompt EventImplemented // a turn ended; Round, Turn EventCollected // the work was collected; Round, Change EventChecking // checks started; Round EventChecked // checks ended; Round, Checks )
Event kinds, in the order a round emits them.
type Implementer ¶
type Implementer struct {
Exec review.Execer
Entry *sidecar.PoolEntry
Credential review.Credential
BaseURL string
Model string
Timeout time.Duration
OnActivity func(Activity)
// contains filtered or unexported fields
}
Implementer runs Claude Code on a sidecar to write code. Every turn resumes the same session, so feedback arrives with the context of the work so far.
type Kind ¶
type Kind string
Kind is what produced a check: a review prompt or a validation command.
type Loop ¶
type Loop struct {
// Attempts is the most rounds to check. Each round after the first starts
// with an implementer turn fixing the previous round's failures.
Attempts int
OnEvent func(Event)
}
Loop drives the implementer through rounds of review and validation.
type Outcome ¶
type Outcome struct {
Result Result
// Rounds is how many rounds were checked.
Rounds int
Change Change
// Checks are the last round's checks.
Checks []Check
}
Outcome is the end state of a loop.
type Relay ¶
type Relay struct {
// contains filtered or unexported fields
}
Relay carries a workspace from one sidecar to others through a staging copy on this machine. Sidecars cannot reach each other, so the implementer's tree is pulled here with rsync and pushed from here to each reviewer the same way the developer's own tree is synced.
The staging copy is a temporary directory the relay creates and owns: a pull mirrors the sidecar into it with --delete, so it must never be a directory anyone else keeps files in.
type Result ¶
type Result string
Result is why the loop stopped.
const ( // ResultPassed means every check passed. ResultPassed Result = "passed" // ResultExhausted means checks still failed when attempts ran out. ResultExhausted Result = "exhausted" // ResultStuck means the implementer changed nothing in response to // feedback, so another round would review the same code again. ResultStuck Result = "stuck" // ResultNoChange means the implementer's work is empty: it changed // nothing, or reverted everything it had changed. ResultNoChange Result = "no_change" )
Loop results.
type Sidecars ¶
type Sidecars struct {
Client *circleci.Client
Exec review.Execer
Implementer *Implementer
Reviewers []*sidecar.PoolEntry
Relay *Relay
Prompts []review.Prompt
Review review.Options
Commands []config.Command
Status iostream.StatusFunc
// OnCheck is called as each validation command finishes. Reviews report
// their progress through Review.ProgressFn.
OnCheck func(Check)
// contains filtered or unexported fields
}
Sidecars runs the loop's steps on real sidecars: the implementer writes code on its own sidecar, which also runs validation, and each review runs on a reviewer sidecar the implementer's tree is relayed to.
func (*Sidecars) Check ¶
Check relays the implementer's tree to the reviewers, then runs the reviews there and validation on the implementer at the same time.
func (*Sidecars) Prepare ¶
Prepare syncs the developer's tree at workDir to the implementer and commits it as the baseline the implementer's work is measured against.
func (*Sidecars) WritePatch ¶
WritePatch collects the implementer's work and writes it, relative to the baseline, to path as a patch the developer can git apply to the tree they started from. It collects first because it also runs after a turn that failed, whose new files are not yet marked intent-to-add. Nothing is written when the change is empty.
The diff runs on the implementer's sidecar, not on a local copy: the implementer controls its .git/config and .gitattributes, whose filters and diff drivers git would otherwise run on the developer's machine.
type Status ¶
type Status string
Status is how a check came out.
const ( // StatusPassed means the check ran and found nothing to fix. StatusPassed Status = "passed" // StatusFailed means the check ran and found something the implementer // must fix: review findings, or a validation command exiting non-zero. StatusFailed Status = "failed" // StatusErrored means the check could not run, such as a review that timed // out. It says nothing about the code, so it is not fed back. StatusErrored Status = "errored" )
Check statuses.
type Steps ¶
type Steps interface {
// Implement runs one implementer turn with prompt.
Implement(ctx context.Context, prompt string) (Turn, error)
// Collect describes the implementer's work so far.
Collect(ctx context.Context) (Change, error)
// Check reviews and validates the implementer's work so far.
Check(ctx context.Context, round int) ([]Check, error)
}
Steps are the operations one round of the loop is made of. Sidecars implements them against real sidecars; tests implement them in memory.