Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 23 additions & 24 deletions cmd/codeaf/do_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,23 @@ func beltRunEnv(t *testing.T) string {
return home
}

// beltModelPins preserves the fixture's resource settings while changing the
// seats a test intends to exercise. Replacing the profile wholesale would
// silently re-enable the real machine gate on a busy test host (#1525).
func beltModelPins(t *testing.T, profileDir string, pins map[string]string) {
t.Helper()
settings := config.NewSettings(config.SettingsOptions{ProfileDir: profileDir})
for key, value := range pins {
row, ok := settings.Row(key)
if !ok {
t.Fatalf("missing setting %s", key)
}
if err := row.Apply(value); err != nil {
t.Fatal(err)
}
}
}

// beltPlandbDoor is the real plandb CLI behind the resolver's override, built
// once for the package. THE LOOP ENDS IN THE STORE: a worker's task is done
// when `plandb done` marks it so and no other way, so a scripted worker that
Expand Down Expand Up @@ -376,16 +393,10 @@ func TestDoOnTheRunEngineSeatsEveryLaunchOnTheDoorsModels(t *testing.T) {
if err := os.MkdirAll(profileDir, 0o700); err != nil {
t.Fatal(err)
}
rows, err := json.Marshal(map[string]string{
beltModelPins(t, profileDir, map[string]string{
config.KeyTierWorkerModel: "vendor/profile-worker",
config.KeyTierMastermindModel: "vendor/profile-thinking",
})
if err != nil {
t.Fatal(err)
}
if err := os.WriteFile(config.BudgetConfigPath(profileDir), rows, 0o600); err != nil {
t.Fatal(err)
}

workspace := beltRepoWorkspace(t)
const (
Expand Down Expand Up @@ -433,7 +444,7 @@ func TestDoOnTheRunEngineSeatsEveryLaunchOnTheDoorsModels(t *testing.T) {
}

var stdout, stderr strings.Builder
err = doErrand(doRequest{
err := doErrand(doRequest{
task: "write out.txt and say what you did", workspace: workspace, asJSON: true,
timeout: 60 * time.Second, slots: bound(1), model: workModel, planModel: planModel, checkModel: planModel,
stdout: &stdout, stderr: &stderr, newBeltCompleter: newBelt,
Expand Down Expand Up @@ -668,18 +679,12 @@ func TestDoOnTheRunEngineSeatsACheckOnTheCheckModel(t *testing.T) {
if err := os.MkdirAll(profileDir, 0o700); err != nil {
t.Fatal(err)
}
rows, err := json.Marshal(map[string]string{
beltModelPins(t, profileDir, map[string]string{
config.KeyTierLowModel: "vendor/profile-small",
config.KeyTierWorkerModel: "vendor/profile-worker",
config.KeyTierHighModel: "vendor/profile-careful",
config.KeyTierMastermindModel: "vendor/profile-thinking",
})
if err != nil {
t.Fatal(err)
}
if err := os.WriteFile(config.BudgetConfigPath(profileDir), rows, 0o600); err != nil {
t.Fatal(err)
}

workspace := beltRepoWorkspace(t)
const (
Expand Down Expand Up @@ -722,7 +727,7 @@ func TestDoOnTheRunEngineSeatsACheckOnTheCheckModel(t *testing.T) {
}

var stdout, stderr strings.Builder
err = doErrand(doRequest{
err := doErrand(doRequest{
task: "write out.txt and say what you did", workspace: workspace, asJSON: true,
timeout: 60 * time.Second, slots: bound(1),
model: workModel, planModel: planModel, checkModel: checkModel,
Expand Down Expand Up @@ -767,17 +772,11 @@ func TestDoOnTheRunEngineSeatsAnUnpinnedCheckOnTheCrewsChecker(t *testing.T) {
if err := os.MkdirAll(profileDir, 0o700); err != nil {
t.Fatal(err)
}
rows, err := json.Marshal(map[string]string{
beltModelPins(t, profileDir, map[string]string{
config.KeyTierWorkerModel: "vendor/profile-worker",
config.KeyTierHighModel: "vendor/profile-careful",
config.KeyTierMastermindModel: "vendor/profile-thinking",
})
if err != nil {
t.Fatal(err)
}
if err := os.WriteFile(config.BudgetConfigPath(profileDir), rows, 0o600); err != nil {
t.Fatal(err)
}

workspace := beltRepoWorkspace(t)
// The same one-seat shape as the two tests above.
Expand Down Expand Up @@ -813,7 +812,7 @@ func TestDoOnTheRunEngineSeatsAnUnpinnedCheckOnTheCrewsChecker(t *testing.T) {
}

var stdout, stderr strings.Builder
err = doErrand(doRequest{
err := doErrand(doRequest{
task: "write out.txt and say what you did", workspace: workspace, asJSON: true,
timeout: 60 * time.Second, slots: bound(1),
stdout: &stdout, stderr: &stderr, newBeltCompleter: newBelt,
Expand Down
18 changes: 9 additions & 9 deletions cmd/codeaf/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,11 +474,9 @@ const (
// per-command pages — which is where somebody writing a script actually looks,
// and where taking it out of the group's lines had silently removed it. One
// source of truth, two places it is read.
var handWorkFooter = ` the three differ by how much thinking happens first: do plans and may split
the job, exec does not plan, run follows a plan somebody saved. None takes
--yolo, and What do and run can still refuse is a plan whose price crosses
your limit — --yes-spend answers that in advance. All three end the same
way, and why is in --json's stop field:
var handWorkFooter = ` do plans and may split the job, exec skips planning, run follows a saved plan.
None takes --yolo. do and run may refuse a plan over your spending limit;
--yes-spend answers in advance. The reason is in --json's stop field:
` + foldedExitLadder(2, helpWidth) + `
CODEAF_EXIT_CODES=legacy restores exec's old 2/3/4/5/6 for one release`

Expand All @@ -490,14 +488,17 @@ Talk to it — a surface you sit in front of
codeaf chat [--model slug] [--reasoning level] [--session path] [--yolo]
[--host host[:path]] [--at name[:path]] [--once "text"]
[--no-compact] [--one-model] [--no-host] [--debug]
--no-host runs the conversation in this process rather than on this
workspace's session host; --debug keeps the whole record of the run
[--max-cost dollars] [--max-hours hours]
--no-host stays in this process; --debug keeps the full run record
--max-cost and --max-hours bound unattended work and require --yolo
codeaf resume
pick an earlier conversation by name and open it — /resume inside the chat

Hand it work — nobody is watching, the answer is on stdout
codeaf do "<task>" [--db path] [--keep] [--dir dir] [--timeout 15m]
[--json] [--yes-spend] [--model slug] [--plan-model slug]
[--check-model slug] [--slots N] [--best|--cheap]
[--pin seat=model[@provider]]
[--context-fill 60] [--completion-reserve 65536] [--debug]
do one task and exit — the same living agent the chat runs, unwatched
codeaf exec ["<prompt>"] [--dir dir] [--system text] [--max-turns N]
Expand All @@ -507,8 +508,7 @@ Hand it work — nobody is watching, the answer is on stdout
run one worker for one pass, with no planning at all
codeaf run <program> --input <file.json|-> [--dir dir] [--model slug]
[--journal path] [--json]
run one saved program: typed input in, its typed output on stdout. A
question it was not told how to answer stops it rather than being guessed
run a saved program: typed input and output; unanswered questions stop it
` + handWorkFooter + `

Look at what happened — read-only, no key, nothing spent
Expand Down
13 changes: 13 additions & 0 deletions docs/changes/unreleased/1626-cli-help-completeness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
kind: fixed
title: CLI help names task model choices and unattended chat budgets
pr: 1626
surface: [docs]
invalidates:
- "The top-level help omitted do's worker limit and crew-selection flags. Its shared synopsis now lists --slots, --best, --cheap, --pin and --check-model."
- "Chat budget flags were only discoverable in detailed help and the environment table. The summary now names --max-cost and --max-hours and their --yolo requirement."
---

The shared headless-work explanation also uses a complete sentence for the
plan-price refusal. This changes help text, not command behavior or engine
workspace policy. Part of #1558.
4 changes: 4 additions & 0 deletions internal/manual/chat/running-from-the-terminal.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ reference somebody consults and it used to be more than half of what `--help` pr
Every verb also answers `<verb> --help` with its own line and its flags, and `codeaf plan
--help` answers with all four of its subcommands.

The top-level synopsis includes `do` worker limits and model choices (`--slots`,
`--best`, `--cheap`, `--pin`, and `--check-model`). It also names chat
`--max-cost` and `--max-hours`; those unattended-work limits require `--yolo`.

## What $? means after a headless one-shot — the codes it leaves with

**One table, and `codeaf do`, `codeaf exec` and `codeaf run` all leave on it.**
Expand Down
Loading