Skip to content

Commit ef243b2

Browse files
committed
Clarify autonomy tier messages in plain language
1 parent 4fc8262 commit ef243b2

3 files changed

Lines changed: 56 additions & 13 deletions

File tree

cmd/autonomy_tiers.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,19 @@ func nextAutonomyTier(level engine.AutonomyLevel) engine.AutonomyLevel {
4848
return containerAutonomyTiers[(autonomyTierIndex(level)+1)%len(containerAutonomyTiers)]
4949
}
5050

51-
func autonomyTierHint(level engine.AutonomyLevel) string {
51+
// autonomyTierDescription is plain-language copy shown when the user changes tier (ctrl+L).
52+
func autonomyTierDescription(level engine.AutonomyLevel) string {
5253
switch level {
5354
case engine.AutonomyBasic:
54-
return "read & search only"
55+
return "Read and search the codebase only. File changes and terminal commands need your approval."
5556
case engine.AutonomySemi:
56-
return "edits auto · shell asks"
57+
return "Read and edit files automatically. Terminal commands need your approval."
5758
case engine.AutonomyFull:
58-
return "shell auto · risky asks"
59+
return "Read, edit, and run most terminal commands in the container. Risky commands still need your approval."
5960
case engine.AutonomyYOLO:
60-
return "minimal prompts"
61+
return "Almost no approval prompts. Use only when you fully trust this session."
6162
default:
62-
return ""
63+
return "Read and edit files automatically. Terminal commands need your approval."
6364
}
6465
}
6566

@@ -87,11 +88,12 @@ func renderAutonomyTierLabel(level engine.AutonomyLevel) string {
8788
}
8889

8990
func formatAutonomyTierMessage(level engine.AutonomyLevel) string {
90-
name := renderAutonomyTierLabel(level)
91-
if hint := autonomyTierHint(level); hint != "" {
92-
return fmt.Sprintf("Autonomy → %s (%s)", name, hint)
93-
}
94-
return fmt.Sprintf("Autonomy → %s", name)
91+
return fmt.Sprintf("Autonomy %s — %s", renderAutonomyTierLabel(level), autonomyTierDescription(level))
92+
}
93+
94+
func formatSandboxReadyAutonomyMessage(level engine.AutonomyLevel) string {
95+
return fmt.Sprintf("Sandbox ready. Default tier %s — %s Press ctrl+L to switch Inspect · Edit · Run · Trust.",
96+
renderAutonomyTierLabel(level), autonomyTierDescription(level))
9597
}
9698

9799
func autonomyLevelForTierName(name string) engine.AutonomyLevel {

cmd/autonomy_tiers_copy_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package cmd
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/GrayCodeAI/hawk/internal/engine"
8+
)
9+
10+
func TestAutonomyTierDescriptions_PlainLanguage(t *testing.T) {
11+
cases := []struct {
12+
level engine.AutonomyLevel
13+
need []string
14+
}{
15+
{engine.AutonomyBasic, []string{"Read and search", "need your approval"}},
16+
{engine.AutonomySemi, []string{"edit files automatically", "Terminal commands need your approval"}},
17+
{engine.AutonomyFull, []string{"most terminal commands", "Risky commands still"}},
18+
{engine.AutonomyYOLO, []string{"Almost no approval", "fully trust"}},
19+
}
20+
for _, tc := range cases {
21+
desc := autonomyTierDescription(tc.level)
22+
for _, fragment := range tc.need {
23+
if !strings.Contains(desc, fragment) {
24+
t.Fatalf("level %v description %q missing %q", tc.level, desc, fragment)
25+
}
26+
}
27+
}
28+
}
29+
30+
func TestFormatAutonomyTierMessage_NoArrowJargon(t *testing.T) {
31+
msg := formatAutonomyTierMessage(engine.AutonomyFull)
32+
if strings.Contains(msg, "→") {
33+
t.Fatalf("expected no arrow jargon, got %q", msg)
34+
}
35+
if strings.Contains(msg, "shell auto") {
36+
t.Fatalf("expected plain language, got %q", msg)
37+
}
38+
if !strings.Contains(msg, "Run") {
39+
t.Fatalf("expected tier name in message, got %q", msg)
40+
}
41+
}

cmd/chat.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ func (m chatModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
667667
return m, nil
668668
case tea.KeyCtrlL:
669669
if m.containerEnabled && !m.containerReady {
670-
m.messages = append(m.messages, displayMsg{role: "system", content: "Autonomy tiers unlock when the container is ready."})
670+
m.messages = append(m.messages, displayMsg{role: "system", content: "Autonomy tiers (Inspect · Edit · Run · Trust) unlock when the container is ready."})
671671
m.viewDirty = true
672672
m.updateViewportContent()
673673
return m, nil
@@ -1108,7 +1108,7 @@ func (m chatModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
11081108
if m.session.Autonomy == 0 {
11091109
m.session.Autonomy = DefaultContainerAutonomy
11101110
}
1111-
m.messages = append(m.messages, displayMsg{role: "system", content: "Sandbox ready · default autonomy " + renderAutonomyTierLabel(m.session.Autonomy) + " (ctrl+L to change)"})
1111+
m.messages = append(m.messages, displayMsg{role: "system", content: formatSandboxReadyAutonomyMessage(m.session.Autonomy)})
11121112
m.invalidateConnStatus()
11131113
}
11141114
if msg.err != nil {

0 commit comments

Comments
 (0)