]> git.giacomolli.uk - onechat/blobdiff - terminal.go
Name and order the terminal client code
[onechat] / terminal.go
similarity index 57%
rename from chat.go
rename to terminal.go
index 1e96b2458be159bdd8fe624f35c0af4668cb6dbc..2906204477b14baa33600fd3efb743865cc85037 100644 (file)
--- a/chat.go
@@ -12,19 +12,17 @@ import (
        "strings"
 )
 
-const (
-       // stopCommand is the input line that interrupts the running turn.
-       stopCommand = "/stop"
+// terminalResultLines is the most lines of a tool result that the client shows.
+const terminalResultLines = 10
 
-       // resultLines is the most lines of a tool result that the client shows.
-       resultLines = 10
-)
+// errTerminalDaemonClosed tells that the daemon closed the connection.
+var errTerminalDaemonClosed = errors.New("the daemon closed the connection")
 
-// chat runs "onechat chat": the terminal client of the daemon. Each line of
+// terminal runs "onechat chat": the terminal client of the daemon. Each line of
 // input is a user message, and the line /stop interrupts the running turn. The
 // client shows the replies, the tool calls, and their results as they happen.
 // It ends at the end of the input or when the daemon closes the connection.
-func chat(ctx context.Context, in io.Reader, out io.Writer) error {
+func terminal(ctx context.Context, in io.Reader, out io.Writer) error {
        dir, err := dataDir()
        if err != nil {
                return err
@@ -42,24 +40,21 @@ func chat(ctx context.Context, in io.Reader, out io.Writer) error {
                return fmt.Errorf(`connect to the daemon (start it with "onechat daemon"): %w`, err)
        }
 
-       return chatSession(ctx, conn, in, out)
+       return terminalSession(ctx, conn, in, out)
 }
 
-// errDaemonClosed tells that the daemon closed the connection.
-var errDaemonClosed = errors.New("the daemon closed the connection")
-
-// chatSession runs the client on conn until the input ends, the daemon closes
-// the connection, or ctx ends, and closes conn. A read of the input that waits
-// for a line can stay behind when the daemon closes the connection.
-func chatSession(ctx context.Context, conn net.Conn, in io.Reader, out io.Writer) error {
+// terminalSession runs the client on conn until the input ends, the daemon
+// closes the connection, or ctx ends, and closes conn. A read of the input that
+// waits for a line can stay behind when the daemon closes the connection.
+func terminalSession(ctx context.Context, conn net.Conn, in io.Reader, out io.Writer) error {
        sent := make(chan error, 1)
        go func() {
-               sent <- sendLines(ctx, conn, in)
+               sent <- terminalSendLines(ctx, conn, in)
        }()
 
        shown := make(chan error, 1)
        go func() {
-               shown <- showEvents(conn, out)
+               shown <- terminalShowEvents(conn, out)
        }()
 
        var err error
@@ -68,7 +63,7 @@ func chatSession(ctx context.Context, conn net.Conn, in io.Reader, out io.Writer
                err = errors.Join(err, conn.Close())
                <-shown
        case err = <-shown:
-               err = errors.Join(cmpError(err, errDaemonClosed), conn.Close())
+               err = errors.Join(terminalCmpError(err, errTerminalDaemonClosed), conn.Close())
        case <-ctx.Done():
                err = conn.Close()
                <-shown
@@ -77,17 +72,8 @@ func chatSession(ctx context.Context, conn net.Conn, in io.Reader, out io.Writer
        return err
 }
 
-// cmpError returns err, or fallback when err is nil.
-func cmpError(err, fallback error) error {
-       if err == nil {
-               return fallback
-       }
-
-       return err
-}
-
-// sendLines sends each line of in as a request until the input ends.
-func sendLines(ctx context.Context, conn net.Conn, in io.Reader) error {
+// terminalSendLines sends each line of in as a request until the input ends.
+func terminalSendLines(ctx context.Context, conn net.Conn, in io.Reader) error {
        encoder := json.NewEncoder(conn)
        scanner := bufio.NewScanner(in)
        scanner.Buffer(make([]byte, 64*1024), requestBytes)
@@ -116,9 +102,9 @@ func sendLines(ctx context.Context, conn net.Conn, in io.Reader) error {
        return scanner.Err()
 }
 
-// showEvents writes each event from the daemon to out until the connection
-// closes.
-func showEvents(conn net.Conn, out io.Writer) error {
+// terminalShowEvents writes each event from the daemon to out until the
+// connection closes.
+func terminalShowEvents(conn net.Conn, out io.Writer) error {
        scanner := bufio.NewScanner(conn)
        scanner.Buffer(make([]byte, 64*1024), requestBytes)
        for scanner.Scan() {
@@ -128,7 +114,7 @@ func showEvents(conn net.Conn, out io.Writer) error {
                        return fmt.Errorf("decode event: %w", err)
                }
 
-               text := eventText(event)
+               text := terminalEventText(event)
                if text == "" {
                        continue
                }
@@ -142,11 +128,20 @@ func showEvents(conn net.Conn, out io.Writer) error {
        return scanner.Err()
 }
 
-// eventText returns the text that the client shows for event, or "" for none.
-// The client shows a user message only from another source, such as telegram,
-// because the user typed the others. A tool result shows its first resultLines
-// lines.
-func eventText(event Event) string {
+// terminalCmpError returns err, or fallback when err is nil.
+func terminalCmpError(err, fallback error) error {
+       if err == nil {
+               return fallback
+       }
+
+       return err
+}
+
+// terminalEventText returns the text that the client shows for event, or "" for
+// none. The client shows a user message only from another source, such as
+// telegram, because the user typed the others. A tool result shows its first
+// terminalResultLines lines.
+func terminalEventText(event Event) string {
        switch event.Kind {
        case "ready":
                return "[connected to " + event.Text + "]"
@@ -161,7 +156,7 @@ func eventText(event Event) string {
        case "tool":
                return "[tool] " + event.Text
        case "echo":
-               return "[result] " + firstLines(event.Text, resultLines)
+               return "[result] " + terminalFirstLines(event.Text, terminalResultLines)
        case "busy":
                return "[working]"
        case "idle":
@@ -173,9 +168,9 @@ func eventText(event Event) string {
        }
 }
 
-// firstLines returns the first count lines of text, with the number of the
-// lines left out.
-func firstLines(text string, count int) string {
+// terminalFirstLines returns the first count lines of text, with the number of
+// the lines left out.
+func terminalFirstLines(text string, count int) string {
        text = strings.TrimRight(text, "\n")
        lines := strings.Split(text, "\n")
        if len(lines) <= count {