Feat (cli): test run and teardown
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -19,3 +19,4 @@ chat_exports/*.json
|
||||
ragimport
|
||||
.env
|
||||
onnx/
|
||||
*.log
|
||||
|
||||
91
cli-tests/sort-text/check.sh
Executable file
91
cli-tests/sort-text/check.sh
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
LOG_FILE="$SCRIPT_DIR/run.log"
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
log_pass() {
|
||||
echo "[PASS] $1"
|
||||
PASS=$((PASS + 1))
|
||||
}
|
||||
|
||||
log_fail() {
|
||||
echo "[FAIL] $1"
|
||||
FAIL=$((FAIL + 1))
|
||||
}
|
||||
|
||||
echo "=== Checking results ==="
|
||||
echo ""
|
||||
|
||||
# Check animals directory exists
|
||||
if [ -d "/tmp/sort-text/animals" ]; then
|
||||
log_pass "animals directory exists"
|
||||
else
|
||||
log_fail "animals directory missing"
|
||||
fi
|
||||
|
||||
# Check colors directory exists
|
||||
if [ -d "/tmp/sort-text/colors" ]; then
|
||||
log_pass "colors directory exists"
|
||||
else
|
||||
log_fail "colors directory missing"
|
||||
fi
|
||||
|
||||
# Check animals contain cat/dog
|
||||
ANIMALS_FILES=$(ls -1 /tmp/sort-text/animals 2>/dev/null | tr '\n' ' ')
|
||||
if echo "$ANIMALS_FILES" | grep -q "file1.txt" && echo "$ANIMALS_FILES" | grep -q "file3.txt"; then
|
||||
log_pass "animals contains animal files"
|
||||
else
|
||||
log_fail "animals missing animal files (got: $ANIMALS_FILES)"
|
||||
fi
|
||||
|
||||
# Check colors contain red/blue
|
||||
COLORS_FILES=$(ls -1 /tmp/sort-text/colors 2>/dev/null | tr '\n' ' ')
|
||||
if echo "$COLORS_FILES" | grep -q "file2.txt" && echo "$COLORS_FILES" | grep -q "file4.txt"; then
|
||||
log_pass "colors contains color files"
|
||||
else
|
||||
log_fail "colors missing color files (got: $COLORS_FILES)"
|
||||
fi
|
||||
|
||||
# Verify content
|
||||
if grep -q "cat" /tmp/sort-text/animals/file1.txt 2>/dev/null; then
|
||||
log_pass "file1.txt contains 'cat'"
|
||||
else
|
||||
log_fail "file1.txt missing 'cat'"
|
||||
fi
|
||||
|
||||
if grep -q "dog" /tmp/sort-text/animals/file3.txt 2>/dev/null; then
|
||||
log_pass "file3.txt contains 'dog'"
|
||||
else
|
||||
log_fail "file3.txt missing 'dog'"
|
||||
fi
|
||||
|
||||
if grep -q "red" /tmp/sort-text/colors/file2.txt 2>/dev/null; then
|
||||
log_pass "file2.txt contains 'red'"
|
||||
else
|
||||
log_fail "file2.txt missing 'red'"
|
||||
fi
|
||||
|
||||
if grep -q "blue" /tmp/sort-text/colors/file4.txt 2>/dev/null; then
|
||||
log_pass "file4.txt contains 'blue'"
|
||||
else
|
||||
log_fail "file4.txt missing 'blue'"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Summary ==="
|
||||
echo "PASSED: $PASS"
|
||||
echo "FAILED: $FAIL"
|
||||
|
||||
if [ $FAIL -gt 0 ]; then
|
||||
echo ""
|
||||
echo "Log file: $LOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "All tests passed!"
|
||||
exit 0
|
||||
25
cli-tests/sort-text/run.sh
Executable file
25
cli-tests/sort-text/run.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
||||
LOG_FILE="$SCRIPT_DIR/${TIMESTAMP}_run.log"
|
||||
|
||||
exec > "$LOG_FILE" 2>&1
|
||||
|
||||
echo "=== Running teardown ==="
|
||||
"$SCRIPT_DIR/teardown.sh"
|
||||
|
||||
echo ""
|
||||
echo "=== Running setup ==="
|
||||
"$SCRIPT_DIR/setup.sh"
|
||||
|
||||
echo ""
|
||||
echo "=== Running task ==="
|
||||
TASK=$(cat "$SCRIPT_DIR/task.txt")
|
||||
cd /home/grail/projects/plays/goplays/gf-lt
|
||||
go run . -cli -msg "$TASK"
|
||||
|
||||
echo ""
|
||||
echo "=== Done ==="
|
||||
echo "Log file: $LOG_FILE"
|
||||
4
cli-tests/sort-text/teardown.sh
Executable file
4
cli-tests/sort-text/teardown.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
rm -rf /tmp/sort-text
|
||||
131
tools/chain.go
131
tools/chain.go
@@ -150,7 +150,7 @@ func execSingle(command, stdin string) (string, error) {
|
||||
name := parts[0]
|
||||
args := parts[1:]
|
||||
// Check if it's a built-in Go command
|
||||
if result := execBuiltin(name, args, stdin); result != "" {
|
||||
if result, isBuiltin := execBuiltin(name, args, stdin); isBuiltin {
|
||||
return result, nil
|
||||
}
|
||||
// Otherwise execute as system command
|
||||
@@ -201,21 +201,23 @@ func tokenize(input string) []string {
|
||||
}
|
||||
|
||||
// execBuiltin executes a built-in command if it exists.
|
||||
func execBuiltin(name string, args []string, stdin string) string {
|
||||
// Returns (result, true) if it was a built-in (even if result is empty).
|
||||
// Returns ("", false) if it's not a built-in command.
|
||||
func execBuiltin(name string, args []string, stdin string) (string, bool) {
|
||||
switch name {
|
||||
case "echo":
|
||||
if stdin != "" {
|
||||
return stdin
|
||||
return stdin, true
|
||||
}
|
||||
return strings.Join(args, " ")
|
||||
return strings.Join(args, " "), true
|
||||
case "time":
|
||||
return "2006-01-02 15:04:05 MST"
|
||||
return "2006-01-02 15:04:05 MST", true
|
||||
case "cat":
|
||||
if len(args) == 0 {
|
||||
if stdin != "" {
|
||||
return stdin
|
||||
return stdin, true
|
||||
}
|
||||
return ""
|
||||
return "", true
|
||||
}
|
||||
path := args[0]
|
||||
abs := path
|
||||
@@ -224,14 +226,14 @@ func execBuiltin(name string, args []string, stdin string) string {
|
||||
}
|
||||
data, err := os.ReadFile(abs)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] cat: %v", err)
|
||||
return fmt.Sprintf("[error] cat: %v", err), true
|
||||
}
|
||||
return string(data)
|
||||
return string(data), true
|
||||
case "pwd":
|
||||
return cfg.FilePickerDir
|
||||
return cfg.FilePickerDir, true
|
||||
case "cd":
|
||||
if len(args) == 0 {
|
||||
return "[error] usage: cd <dir>"
|
||||
return "[error] usage: cd <dir>", true
|
||||
}
|
||||
dir := args[0]
|
||||
// Resolve relative to cfg.FilePickerDir
|
||||
@@ -242,16 +244,16 @@ func execBuiltin(name string, args []string, stdin string) string {
|
||||
abs = filepath.Clean(abs)
|
||||
info, err := os.Stat(abs)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] cd: %v", err)
|
||||
return fmt.Sprintf("[error] cd: %v", err), true
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return "[error] cd: not a directory: " + dir
|
||||
return "[error] cd: not a directory: " + dir, true
|
||||
}
|
||||
cfg.FilePickerDir = abs
|
||||
return "Changed directory to: " + cfg.FilePickerDir
|
||||
return "Changed directory to: " + cfg.FilePickerDir, true
|
||||
case "mkdir":
|
||||
if len(args) == 0 {
|
||||
return "[error] usage: mkdir [-p] <dir>"
|
||||
return "[error] usage: mkdir [-p] <dir>", true
|
||||
}
|
||||
createParents := false
|
||||
var dirPath string
|
||||
@@ -263,7 +265,7 @@ func execBuiltin(name string, args []string, stdin string) string {
|
||||
}
|
||||
}
|
||||
if dirPath == "" {
|
||||
return "[error] usage: mkdir [-p] <dir>"
|
||||
return "[error] usage: mkdir [-p] <dir>", true
|
||||
}
|
||||
abs := dirPath
|
||||
if !filepath.IsAbs(dirPath) {
|
||||
@@ -277,12 +279,12 @@ func execBuiltin(name string, args []string, stdin string) string {
|
||||
mkdirFunc = os.Mkdir
|
||||
}
|
||||
if err := mkdirFunc(abs, 0o755); err != nil {
|
||||
return fmt.Sprintf("[error] mkdir: %v", err)
|
||||
return fmt.Sprintf("[error] mkdir: %v", err), true
|
||||
}
|
||||
if createParents {
|
||||
return "Created " + dirPath + " (with parents)"
|
||||
return "Created " + dirPath + " (with parents)", true
|
||||
}
|
||||
return "Created " + dirPath
|
||||
return "Created " + dirPath, true
|
||||
case "ls":
|
||||
dir := "."
|
||||
for _, a := range args {
|
||||
@@ -297,7 +299,7 @@ func execBuiltin(name string, args []string, stdin string) string {
|
||||
}
|
||||
entries, err := os.ReadDir(abs)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] ls: %v", err)
|
||||
return fmt.Sprintf("[error] ls: %v", err), true
|
||||
}
|
||||
var out strings.Builder
|
||||
for _, e := range entries {
|
||||
@@ -317,21 +319,98 @@ func execBuiltin(name string, args []string, stdin string) string {
|
||||
}
|
||||
}
|
||||
if out.Len() == 0 {
|
||||
return "(empty directory)"
|
||||
return "(empty directory)", true
|
||||
}
|
||||
return strings.TrimRight(out.String(), "\n")
|
||||
return strings.TrimRight(out.String(), "\n"), true
|
||||
case "go":
|
||||
// Allow all go subcommands
|
||||
if len(args) == 0 {
|
||||
return "[error] usage: go <subcommand> [options]"
|
||||
return "[error] usage: go <subcommand> [options]", true
|
||||
}
|
||||
cmd := exec.Command("go", args...)
|
||||
cmd.Dir = cfg.FilePickerDir
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] go %s: %v\n%s", args[0], err, string(output))
|
||||
return fmt.Sprintf("[error] go %s: %v\n%s", args[0], err, string(output)), true
|
||||
}
|
||||
return string(output)
|
||||
return string(output), true
|
||||
case "cp":
|
||||
if len(args) < 2 {
|
||||
return "[error] usage: cp <source> <dest>", true
|
||||
}
|
||||
return ""
|
||||
src := args[0]
|
||||
dst := args[1]
|
||||
if !filepath.IsAbs(src) {
|
||||
src = filepath.Join(cfg.FilePickerDir, src)
|
||||
}
|
||||
if !filepath.IsAbs(dst) {
|
||||
dst = filepath.Join(cfg.FilePickerDir, dst)
|
||||
}
|
||||
data, err := os.ReadFile(src)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] cp: %v", err), true
|
||||
}
|
||||
err = os.WriteFile(dst, data, 0644)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] cp: %v", err), true
|
||||
}
|
||||
return "Copied " + src + " to " + dst, true
|
||||
case "mv":
|
||||
if len(args) < 2 {
|
||||
return "[error] usage: mv <source> <dest>", true
|
||||
}
|
||||
src := args[0]
|
||||
dst := args[1]
|
||||
if !filepath.IsAbs(src) {
|
||||
src = filepath.Join(cfg.FilePickerDir, src)
|
||||
}
|
||||
if !filepath.IsAbs(dst) {
|
||||
dst = filepath.Join(cfg.FilePickerDir, dst)
|
||||
}
|
||||
err := os.Rename(src, dst)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] mv: %v", err), true
|
||||
}
|
||||
return "Moved " + src + " to " + dst, true
|
||||
case "rm":
|
||||
if len(args) == 0 {
|
||||
return "[error] usage: rm [-r] <file>", true
|
||||
}
|
||||
recursive := false
|
||||
var target string
|
||||
for _, a := range args {
|
||||
if a == "-r" || a == "-rf" || a == "-fr" || a == "-recursive" {
|
||||
recursive = true
|
||||
} else if target == "" {
|
||||
target = a
|
||||
}
|
||||
}
|
||||
if target == "" {
|
||||
return "[error] usage: rm [-r] <file>", true
|
||||
}
|
||||
abs := target
|
||||
if !filepath.IsAbs(target) {
|
||||
abs = filepath.Join(cfg.FilePickerDir, target)
|
||||
}
|
||||
info, err := os.Stat(abs)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] rm: %v", err), true
|
||||
}
|
||||
if info.IsDir() {
|
||||
if recursive {
|
||||
err = os.RemoveAll(abs)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] rm: %v", err), true
|
||||
}
|
||||
return "Removed " + abs, true
|
||||
}
|
||||
return "[error] rm: is a directory (use -r)", true
|
||||
}
|
||||
err = os.Remove(abs)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[error] rm: %v", err), true
|
||||
}
|
||||
return "Removed " + abs, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
@@ -134,10 +134,10 @@ func (t *Tools) initAgentsB() {
|
||||
agent.RegisterB("summarize_chat", agent.NewWebAgentB(t.webAgentClient, summarySysPrompt))
|
||||
}
|
||||
|
||||
func InitTools(cfg *config.Config, logger *slog.Logger, store storage.FullRepo) *Tools {
|
||||
_ = logger
|
||||
_ = cfg
|
||||
if cfg.PlaywrightEnabled {
|
||||
func InitTools(initCfg *config.Config, logger *slog.Logger, store storage.FullRepo) *Tools {
|
||||
logger = logger
|
||||
cfg = initCfg
|
||||
if initCfg.PlaywrightEnabled {
|
||||
if err := CheckPlaywright(); err != nil {
|
||||
// slow, need a faster check if playwright install
|
||||
if err := InstallPW(); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user