tinyrelayfile
tinyrelay/cmd/tiny/agent.go/

cmd/tiny/agent.go raw
1package main
2
3import (
4 "context"
5 "errors"
6 "flag"
7 "fmt"
8 "io"
9 "os"
10 "path/filepath"
11 "regexp"
12 "strings"
13 "time"
14
15 "github.com/FelineStateMachine/tinyrelay/internal/agentrunner"
16)
17
18func agent(ctx context.Context, args []string, out io.Writer) error {
19 fs := flag.NewFlagSet("tiny agent", flag.ContinueOnError)
20 fs.SetOutput(out)
21 relay := fs.String("relay", "", "Nostr relay WebSocket URL")
22 command := fs.String("command", "", "agent executable")
23 protocol := fs.String("protocol", "acp", "agent protocol: acp or command (text stdin/stdout)")
24 keyEnv := fs.String("key-env", "TINY_AGENT_KEY", "environment variable containing the agent hex key or nsec")
25 state := fs.String("state", "", "queue journal path (required)")
26 cwd := fs.String("cwd", ".", "agent working directory")
27 timeout := fs.Duration("timeout", 30*time.Minute, "maximum task and approval wait")
28 var rooms, commandArgs []string
29 fs.Func("room", "authorized room id (repeatable)", func(value string) error {
30 if !regexp.MustCompile(`^[a-z0-9_-]{1,64}$`).MatchString(value) {
31 return errors.New("invalid room id")
32 }
33 rooms = append(rooms, value)
34 return nil
35 })
36 fs.Func("arg", "argument passed directly to the agent (repeatable)", func(value string) error { commandArgs = append(commandArgs, value); return nil })
37 if err := fs.Parse(args); err != nil {
38 return err
39 }
40 if *relay == "" || *command == "" || *state == "" || len(rooms) == 0 {
41 return errors.New("agent requires --relay, --room, --command and --state")
42 }
43 if fs.NArg() != 0 || (*protocol != "acp" && *protocol != "command") || *timeout <= 0 {
44 return errors.New("invalid agent options")
45 }
46 secret, err := secretKey(os.Getenv(*keyEnv))
47 if err != nil {
48 return fmt.Errorf("agent key: %w", err)
49 }
50 directory, err := filepath.Abs(*cwd)
51 if err != nil {
52 return err
53 }
54 info, err := os.Stat(directory)
55 if err != nil || !info.IsDir() {
56 return errors.New("agent working directory does not exist")
57 }
58 // The subprocess does not need the relay signing key. It receives messages
59 // through stdio and returns requests and output to this signing boundary.
60 environment := []string{}
61 for _, entry := range os.Environ() {
62 if !strings.HasPrefix(entry, *keyEnv+"=") {
63 environment = append(environment, entry)
64 }
65 }
66 log := func(err error) { fmt.Fprintln(out, err) }
67 return agentrunner.Serve(ctx, agentrunner.ServiceOptions{RelayURL: *relay, Secret: secret, Rooms: rooms, StatePath: *state, Timeout: *timeout, Log: log, Process: agentrunner.ProcessOptions{Command: *command, Args: commandArgs, Env: environment, CWD: directory, Protocol: *protocol}})
68}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs