This commit is contained in:
Ian Gulliver
2026-10-20 22:15:33 -07:00
parent 627319a01f
commit 2bfa62449d
9 changed files with 45 additions and 57 deletions
+1 -2
View File
@@ -11,7 +11,6 @@ import (
"g.fc.run/ai/byre/internal/api"
"g.fc.run/ai/byre/internal/store"
"g.fc.run/ai/byre/internal/workflow"
)
const leadGuidance = `You are the human's lead agent in byre, shown in the left pane of byre's app. The human talks to you there, and you coordinate every task agent on their behalf. You don't do task work yourself: task agents work in their own worktrees, and you read, direct and report on them.
@@ -98,7 +97,7 @@ func (m *Manager) createLead(ctx context.Context, owner api.User, prompt, model,
}
id := newUUID()
vendor := workflow.VendorOf(model)
vendor := vendorOf(model)
sess := api.AgentSession{
Id: id,
Owner: owner.Login,
+1 -2
View File
@@ -21,7 +21,6 @@ import (
"g.fc.run/ai/byre/internal/mcp"
"g.fc.run/ai/byre/internal/store"
"g.fc.run/ai/byre/internal/terminal"
"g.fc.run/ai/byre/internal/workflow"
"tailscale.com/tsnet"
)
@@ -235,7 +234,7 @@ func (m *Manager) newSession(ctx context.Context, task api.Task, creator api.Use
}
id := newUUID()
vendor := workflow.VendorOf(model)
vendor := vendorOf(model)
sess := api.AgentSession{
Id: id,
TaskId: task.Id,
+12 -3
View File
@@ -14,7 +14,6 @@ import (
"g.fc.run/ai/byre/internal/claude"
"g.fc.run/ai/byre/internal/codex"
"g.fc.run/ai/byre/internal/mcp"
"g.fc.run/ai/byre/internal/workflow"
)
type image struct {
@@ -34,6 +33,16 @@ type agentProcess interface {
discard()
}
func vendorOf(model string) api.AgentSessionVendor {
switch {
case strings.HasPrefix(model, "gpt-"):
return api.Codex
case strings.HasPrefix(model, "gemini-"):
return api.Antigravity
}
return api.Claude
}
func initialVendorSessionID(vendor api.AgentSessionVendor, id string) string {
if vendor != api.Claude {
return ""
@@ -42,8 +51,8 @@ func initialVendorSessionID(vendor api.AgentSessionVendor, id string) string {
}
func checkModel(sess api.AgentSession, model string) error {
if workflow.VendorOf(model) != sess.Vendor {
return fmt.Errorf("%w: session %s is %s; %s is a %s model", ErrInvalid, sess.Id, sess.Vendor, model, workflow.VendorOf(model))
if vendorOf(model) != sess.Vendor {
return fmt.Errorf("%w: session %s is %s; %s is a %s model", ErrInvalid, sess.Id, sess.Vendor, model, vendorOf(model))
}
return nil
}
+1 -1
View File
@@ -292,7 +292,7 @@ func (m *Manager) advanceReviews(ctx context.Context, r api.Review) bool {
func (m *Manager) startReviewer(ctx context.Context, task api.Task, project api.Project, snap api.Snapshot, defID string, def api.WorkflowDefinition, stage string, inputs []api.Review) (err error) {
model := workflow.Get(def, stage).Model
vendor := workflow.VendorOf(model)
vendor := vendorOf(model)
reviewID := store.NewID()
recorded := false
defer func() {
+15 -12
View File
@@ -236,22 +236,23 @@ func SquashCommit(repo, worktree, target, message string, env []string, sign fun
}
func signCommit(repo, commit string, sign func(payload []byte) ([]byte, error)) (string, error) {
cmd := exec.Command("git", "cat-file", "commit", commit)
cmd.Dir = repo
payload, err := cmd.Output()
payload, stderr, code, err := runCodeInput(context.Background(), repo, nil, nil, "cat-file", "commit", commit)
if err != nil {
return "", fmt.Errorf("git cat-file commit %s: %w", commit, err)
return "", err
}
sig, err := sign(payload)
if code != 0 {
return "", fmt.Errorf("git cat-file commit %s: exit status %d: %s", commit, code, stderr)
}
sig, err := sign([]byte(payload))
if err != nil {
return "", fmt.Errorf("signing the commit: %w", err)
}
eoh := strings.Index(string(payload), "\n\n")
eoh := strings.Index(payload, "\n\n")
if eoh < 0 {
return "", fmt.Errorf("commit %s has no message", commit)
}
header := "gpgsig " + strings.ReplaceAll(strings.TrimSuffix(string(sig), "\n"), "\n", "\n ") + "\n"
signed := string(payload[:eoh+1]) + header + string(payload[eoh+1:])
signed := payload[:eoh+1] + header + payload[eoh+1:]
return runInput(repo, nil, signed, "hash-object", "-t", "commit", "-w", "--stdin")
}
@@ -418,17 +419,19 @@ func runInput(dir string, env []string, input string, args ...string) (string, e
if code != 0 {
return "", fmt.Errorf("git %s: exit status %d: %s", strings.Join(args, " "), code, stderr)
}
return out, nil
return strings.TrimSpace(out), nil
}
func runCode(dir string, env []string, args ...string) (string, string, int, error) {
return runCodeInput(context.Background(), dir, env, nil, args...)
out, stderr, code, err := runCodeInput(context.Background(), dir, env, nil, args...)
return strings.TrimSpace(out), stderr, code, err
}
func runNetwork(ctx context.Context, dir string, args ...string) (string, string, int, error) {
ctx, cancel := context.WithTimeout(ctx, networkTimeout)
defer cancel()
return runCodeInput(ctx, dir, networkEnv, nil, args...)
out, stderr, code, err := runCodeInput(ctx, dir, networkEnv, nil, args...)
return strings.TrimSpace(out), stderr, code, err
}
func runCodeInput(ctx context.Context, dir string, env []string, stdin io.Reader, args ...string) (string, string, int, error) {
@@ -449,10 +452,10 @@ func runCodeInput(ctx context.Context, dir string, env []string, stdin io.Reader
}
exit := &exec.ExitError{}
if errors.As(err, &exit) {
return strings.TrimSpace(string(out)), strings.TrimSpace(stderr.String()), exit.ExitCode(), nil
return string(out), strings.TrimSpace(stderr.String()), exit.ExitCode(), nil
}
if err != nil {
return "", "", 0, fmt.Errorf("git %s: %w", strings.Join(args, " "), err)
}
return strings.TrimSpace(string(out)), strings.TrimSpace(stderr.String()), 0, nil
return string(out), strings.TrimSpace(stderr.String()), 0, nil
}
+10 -15
View File
@@ -1,10 +1,8 @@
package git
import (
"bytes"
"errors"
"context"
"fmt"
"os/exec"
"strings"
)
@@ -14,23 +12,20 @@ func Ignored(worktree string, paths []string) (map[string]bool, error) {
return ignored, nil
}
cmd := exec.Command("git", "check-ignore", "--stdin", "-z")
cmd.Dir = worktree
cmd.Stdin = strings.NewReader(strings.Join(paths, "\x00") + "\x00")
stderr := &strings.Builder{}
cmd.Stderr = stderr
out, err := cmd.Output()
exit := &exec.ExitError{}
if errors.As(err, &exit) && exit.ExitCode() == 1 {
out, stderr, code, err := runCodeInput(context.Background(), worktree, nil, strings.NewReader(strings.Join(paths, "\x00")+"\x00"), "check-ignore", "--stdin", "-z")
if err != nil {
return nil, err
}
if code == 1 {
return ignored, nil
}
if err != nil {
return nil, fmt.Errorf("git check-ignore: %w: %s", err, strings.TrimSpace(stderr.String()))
if code != 0 {
return nil, fmt.Errorf("git check-ignore: exit status %d: %s", code, stderr)
}
for _, p := range bytes.Split(out, []byte{0}) {
for _, p := range strings.Split(out, "\x00") {
if len(p) > 0 {
ignored[string(p)] = true
ignored[p] = true
}
}
return ignored, nil
+2 -9
View File
@@ -2,7 +2,6 @@ package git
import (
"fmt"
"os/exec"
"strings"
)
@@ -54,12 +53,6 @@ func DeleteSnapshotRefs(repo, taskID string) error {
for _, ref := range refs {
fmt.Fprintf(b, "delete %s\n", ref)
}
cmd := exec.Command("git", "update-ref", "--stdin")
cmd.Dir = repo
cmd.Stdin = strings.NewReader(b.String())
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("git update-ref --stdin: %w: %s", err, strings.TrimSpace(string(out)))
}
return nil
_, err = runInput(repo, nil, b.String(), "update-ref", "--stdin")
return err
}
-10
View File
@@ -15,16 +15,6 @@ var ErrInvalid = errors.New("invalid workflow")
const maxNameRunes = 100
func VendorOf(model string) api.AgentSessionVendor {
switch {
case strings.HasPrefix(model, "gpt-"):
return api.Codex
case strings.HasPrefix(model, "gemini-"):
return api.Antigravity
}
return api.Claude
}
func CleanName(name string) (string, error) {
name = strings.TrimSpace(name)
problem := nameProblem(name)