Clarify Agentbox names and invariants

Co-authored-by: codegirl007 <codegirl-007@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-08-18 06:05:46 +00:00
co-authored by codegirl007
parent 4d2fb4a733
commit e702497996
11 changed files with 35 additions and 19 deletions
+1 -1
View File
@@ -67,7 +67,7 @@ func run(ctx context.Context, args []string) error {
fmt.Fprintf(os.Stderr, "Run artifacts: %s\n", traceStore.Directory())
return err
}
fmt.Printf("Replay written to:\n%s\n", traceStore.Directory())
fmt.Printf("Run artifacts written to:\n%s\n", traceStore.Directory())
return nil
}
+2
View File
@@ -76,6 +76,8 @@ func greenCentroidX(screenshot []byte) (float64, error) {
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
red, green, blue, _ := renderedImage.At(x, y).RGBA()
// Match the mover's #00ff66 square. Requiring 1,000 matching pixels
// prevents a small green UI detail from passing verification.
if green > 0xc000 && red < 0x4000 && blue < 0x8000 {
xCoordinateSum += uint64(x)
greenPixelCount++
+3 -1
View File
@@ -87,12 +87,14 @@ func modelPrompt(task string, history []Step, observation Observation) (string,
return "", err
}
return "You control an interactive Linux application from screenshots. " +
"Choose exactly one safe input action, or mark done when the task is complete. " +
"Choose exactly one allowed input action, or mark done when the task is complete. " +
"Use logical key names such as RIGHT, ENTER, or ESCAPE. Keep waits under 5000 ms.\n" +
string(data), nil
}
func decisionSchema() map[string]any {
// Strict structured output requires every action property to be present,
// even when a particular action ignores most of them.
actionProperties := map[string]any{
"type": map[string]any{
"type": "string",
+8 -8
View File
@@ -11,10 +11,10 @@ import (
)
type manifest struct {
Command string `json:"command"`
Args []string `json:"args"`
Env map[string]string `json:"env"`
WindowTitle string `json:"window_title"`
Command string `json:"command"`
Args []string `json:"args"`
EnvironmentVariables map[string]string `json:"env"`
WindowTitle string `json:"window_title"`
}
// Resolve turns either an executable path or a directory containing
@@ -58,9 +58,9 @@ func Resolve(path string) (environment.Command, error) {
return environment.Command{}, errors.New("manifest command must be a regular executable file")
}
return environment.Command{
Path: commandPath,
Args: config.Args,
Env: config.Env,
WindowTitle: config.WindowTitle,
Path: commandPath,
Args: config.Args,
EnvironmentVariables: config.EnvironmentVariables,
WindowTitle: config.WindowTitle,
}, nil
}
@@ -17,7 +17,7 @@ func (environmentBackend *Environment) Launch(
ctx context.Context,
application environment.Command,
) error {
fmt.Fprintln(environmentBackend.config.Output, "Uploading build...")
fmt.Fprintln(environmentBackend.config.Output, "Staging application...")
executable, err := os.Open(application.Path)
if err != nil {
return fmt.Errorf("open application: %w", err)
@@ -47,7 +47,7 @@ func (environmentBackend *Environment) Launch(
fmt.Fprintln(environmentBackend.config.Output, "Launching application...")
dockerArguments := []string{"exec", "-d"}
for variableName, variableValue := range application.Env {
for variableName, variableValue := range application.EnvironmentVariables {
dockerArguments = append(
dockerArguments,
"-e",
@@ -69,6 +69,8 @@ func (environmentBackend *Environment) Start(ctx context.Context) error {
); err != nil {
return fmt.Errorf("start environment: %w", err)
}
// entrypoint.sh creates this file only after both Xvfb and Openbox accept
// requests. It is the readiness handshake between host and container.
if err := waitFor(ctx, 10*time.Second, func() bool {
_, readyErr := environmentBackend.runDocker(
ctx,
+6 -5
View File
@@ -8,10 +8,10 @@ import (
// Command describes a host executable and how it should start in an
// environment. Environment implementations decide how to stage the file.
type Command struct {
Path string
Args []string
Env map[string]string
WindowTitle string
Path string
Args []string
EnvironmentVariables map[string]string
WindowTitle string
}
// InputType identifies one backend-neutral keyboard, mouse, or timing action.
@@ -36,7 +36,8 @@ type InputAction struct {
DurationMS int `json:"duration_ms,omitempty"`
}
// LogEntry is a snapshot of one application output stream.
// LogEntry is a cumulative snapshot of one application output stream. Time is
// when Agentbox captured the snapshot, not when the application emitted it.
type LogEntry struct {
Stream string `json:"stream"`
Message string `json:"message"`
+3 -1
View File
@@ -117,7 +117,7 @@ func Run(ctx context.Context) (runErr error) {
return fmt.Errorf("build environment image: %w", err)
}
fmt.Println("Creating isolated graphical environment...")
fmt.Println("Creating restricted graphical environment...")
_, err = r.docker(ctx,
"create",
"--name", r.containerName,
@@ -327,6 +327,8 @@ func squareCentroid(path string) (point, error) {
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
red, green, blue, _ := img.At(x, y).RGBA()
// Match the demo square's #00ff66 color with enough tolerance for
// image conversion while rejecting the black background.
if green > 0xc000 && red < 0x4000 && blue < 0x8000 {
sumX += uint64(x)
sumY += uint64(y)
+1 -1
View File
@@ -45,7 +45,7 @@ func Run(ctx context.Context, config Config) (runErr error) {
if err := config.Environment.Launch(ctx, config.Command); err != nil {
return err
}
fmt.Fprintln(config.Output, "Agent attached.")
fmt.Fprintln(config.Output, "Agent loop started.")
var stepHistory []agent.Step
var actionHistory []environment.InputAction
+4
View File
@@ -0,0 +1,4 @@
// Package trace stores durable run records. steps.jsonl contains complete
// observations and decisions, actions.jsonl is an action-only view, and PNG
// screenshots remain separate files referenced by relative paths.
package trace
+3
View File
@@ -25,6 +25,8 @@ func List(projectRoot string) ([]Run, error) {
continue
}
run, err := Read(projectRoot, entry.Name())
// Old or malformed trace directories are intentionally hidden rather
// than making the entire run listing fail.
if err == nil && run.SchemaVersion == SchemaVersion {
runs = append(runs, run)
}
@@ -87,6 +89,7 @@ func ReadSteps(projectRoot, runID string) ([]StepRecord, error) {
}
func validateRunID(runID string) error {
// Run IDs become path components, so reject separators and traversal.
if filepath.Base(runID) != runID {
return errors.New("invalid run ID")
}