From 9e874f3af26540e30d39929c50b98a5cc1171a58 Mon Sep 17 00:00:00 2001
From: 35C4n0r <work.jaykumar@gmail.com>
Date: Thu, 31 Jul 2025 13:42:01 +0530
Subject: [PATCH 1/9] feat: update support for codex

---
 lib/msgfmt/message_box.go                     | 30 ++++++
 lib/msgfmt/msgfmt.go                          | 10 +-
 .../codex/confirmation_box/expected.txt       | 25 ++---
 .../format/codex/confirmation_box/msg.txt     | 50 +++++-----
 .../format/codex/first_message/expected.txt   | 20 ++--
 .../format/codex/first_message/msg.txt        | 45 ++++++---
 .../format/codex/multi_line/expected.txt      | 16 ---
 .../testdata/format/codex/multi_line/msg.txt  | 60 ------------
 .../testdata/format/codex/multi_line/user.txt | 39 --------
 .../format/codex/multi_line2/expected.txt     | 45 ---------
 .../testdata/format/codex/multi_line2/msg.txt | 98 -------------------
 .../format/codex/multi_line2/user.txt         | 39 --------
 .../format/codex/response/expected.txt        |  4 -
 .../testdata/format/codex/response/msg.txt    | 11 ---
 .../testdata/format/codex/response/user.txt   |  1 -
 .../format/codex/second_message/expected.txt  | 19 +---
 .../format/codex/second_message/msg.txt       | 41 ++++----
 .../format/codex/second_message/user.txt      |  2 +-
 18 files changed, 133 insertions(+), 422 deletions(-)
 delete mode 100644 lib/msgfmt/testdata/format/codex/multi_line/expected.txt
 delete mode 100644 lib/msgfmt/testdata/format/codex/multi_line/msg.txt
 delete mode 100644 lib/msgfmt/testdata/format/codex/multi_line/user.txt
 delete mode 100644 lib/msgfmt/testdata/format/codex/multi_line2/expected.txt
 delete mode 100644 lib/msgfmt/testdata/format/codex/multi_line2/msg.txt
 delete mode 100644 lib/msgfmt/testdata/format/codex/multi_line2/user.txt
 delete mode 100644 lib/msgfmt/testdata/format/codex/response/expected.txt
 delete mode 100644 lib/msgfmt/testdata/format/codex/response/msg.txt
 delete mode 100644 lib/msgfmt/testdata/format/codex/response/user.txt

diff --git a/lib/msgfmt/message_box.go b/lib/msgfmt/message_box.go
index 2f95e06..38a57dd 100644
--- a/lib/msgfmt/message_box.go
+++ b/lib/msgfmt/message_box.go
@@ -51,3 +51,33 @@ func removeMessageBox(msg string) string {
 
 	return strings.Join(lines, "\n")
 }
+
+func removeCodexMessageBox(msg string) string {
+	lines := strings.Split(msg, "\n")
+	messageBoxEndIdx := -1
+	messageBoxStartIdx := 0
+	for i := len(lines) - 1; i >= 0; i-- {
+		if messageBoxEndIdx == -1 {
+			if strings.Contains(lines[i], "╰────────") && strings.Contains(lines[i], "───────╯") {
+				messageBoxEndIdx = i
+			}
+		} else {
+			// We reached the start of the message box (we don't want to show this line), also exit the loop
+			if strings.Contains(lines[i], "╭") && strings.Contains(lines[i], "───────╮") {
+				messageBoxStartIdx = i + 1
+				break
+			}
+
+			// We are in between the start and end of the message box, so remove the │ from the start and end of the line, let the trimEmptyLines handle the rest
+			if strings.HasPrefix(lines[i], "│") {
+				lines[i] = strings.TrimPrefix(lines[i], "│")
+			}
+			if strings.HasSuffix(lines[i], "│") {
+				lines[i] = strings.TrimSuffix(lines[i], "│")
+				lines[i] = strings.TrimRight(lines[i], " \t")
+			}
+		}
+	}
+
+	return strings.Join(lines[messageBoxStartIdx:max(0, messageBoxEndIdx)], "\n")
+}
diff --git a/lib/msgfmt/msgfmt.go b/lib/msgfmt/msgfmt.go
index cca75d1..3560aa7 100644
--- a/lib/msgfmt/msgfmt.go
+++ b/lib/msgfmt/msgfmt.go
@@ -216,6 +216,14 @@ func formatGenericMessage(message string, userInput string) string {
 	return message
 }
 
+func formatCodexMessage(message string, userInput string) string {
+	message = RemoveUserInput(message, userInput)
+	message = removeMessageBox(message)
+	message = removeCodexMessageBox(message)
+	message = trimEmptyLines(message)
+	return message
+}
+
 func FormatAgentMessage(agentType AgentType, message string, userInput string) string {
 	switch agentType {
 	case AgentTypeClaude:
@@ -225,7 +233,7 @@ func FormatAgentMessage(agentType AgentType, message string, userInput string) s
 	case AgentTypeAider:
 		return formatGenericMessage(message, userInput)
 	case AgentTypeCodex:
-		return formatGenericMessage(message, userInput)
+		return formatCodexMessage(message, userInput)
 	case AgentTypeGemini:
 		return formatGenericMessage(message, userInput)
 	case AgentTypeCustom:
diff --git a/lib/msgfmt/testdata/format/codex/confirmation_box/expected.txt b/lib/msgfmt/testdata/format/codex/confirmation_box/expected.txt
index 14faa87..9363e91 100644
--- a/lib/msgfmt/testdata/format/codex/confirmation_box/expected.txt
+++ b/lib/msgfmt/testdata/format/codex/confirmation_box/expected.txt
@@ -1,19 +1,10 @@
-    thinking for 9s
+Shell Command
+~/Documents/work/agentapi$ git rev-parse --show-toplevel
 
-    command
+Allow command?
 
-    $ git rev-parse --show-toplevel
-
-╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│Shell Command                                                                                             │
-│                                                                                                          │
-│$ git rev-parse --show-toplevel                                                                           │
-│                                                                                                          │
-│Allow command?                                                                                            │
-│                                                                                                          │
-│  ❯ Yes (y)                                                                                               │
-│    Yes, always approve this exact command for this session (a)                                           │
-│    Edit or give feedback (e)                                                                             │
-│    No, and keep going (n)                                                                                │
-│    No, and stop for now (esc)                                                                            │
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯
\ No newline at end of file
+  ▶ Yes (y)
+    Yes, always approve this exact command for this session (a)
+    Edit or give feedback (e)
+    No, and keep going (n)
+    No, and stop for now (esc)
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/confirmation_box/msg.txt b/lib/msgfmt/testdata/format/codex/confirmation_box/msg.txt
index ff26827..eccfd92 100644
--- a/lib/msgfmt/testdata/format/codex/confirmation_box/msg.txt
+++ b/lib/msgfmt/testdata/format/codex/confirmation_box/msg.txt
@@ -1,22 +1,28 @@
-user
-what repository are you in?
-
-    thinking for 9s
-
-    command
-
-    $ git rev-parse --show-toplevel
-
-╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│Shell Command                                                                                             │
-│                                                                                                          │
-│$ git rev-parse --show-toplevel                                                                           │
-│                                                                                                          │
-│Allow command?                                                                                            │
-│                                                                                                          │
-│  ❯ Yes (y)                                                                                               │
-│    Yes, always approve this exact command for this session (a)                                           │
-│    Edit or give feedback (e)                                                                             │
-│    No, and keep going (n)                                                                                │
-│    No, and stop for now (esc)                                                                            │
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯
\ No newline at end of file
+╭Messages (tab to focus)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│OpenAI Codex v0.10.0 (research preview)                                                                                                                                                                  │
+│                                                                                                                                                                                                         │
+│codex session 790ba389-ab4d-47be-bb16-9cc7f36bcf2b                                                                                                                                                       │
+│workdir: /Users/jkmr/Documents/work/agentapi                                                                                                                                                             │
+│model: codex-mini-latest                                                                                                                                                                                 │
+│provider: openai                                                                                                                                                                                         │
+│approval: untrusted                                                                                                                                                                                      │
+│sandbox: read-only                                                                                                                                                                                       │
+│reasoning effort: medium                                                                                                                                                                                 │
+│reasoning summaries: auto                                                                                                                                                                                │
+│                                                                                                                                                                                                         │
+│user                                                                                                                                                                                                     │
+│what repository are you in?                                                                                                                                                                              │
+│                                                                                                                                                                                                         │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭Review───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│Shell Command                                                                                                                                                                                            │
+│~/Documents/work/agentapi$ git rev-parse --show-toplevel                                                                                                                                                 │
+│                                                                                                                                                                                                         │
+│Allow command?                                                                                                                                                                                           │
+│                                                                                                                                                                                                         │
+│  ▶ Yes (y)                                                                                                                                                                                              │
+│    Yes, always approve this exact command for this session (a)                                                                                                                                          │
+│    Edit or give feedback (e)                                                                                                                                                                            │
+│    No, and keep going (n)                                                                                                                                                                               │
+│    No, and stop for now (esc)                                                                                                                                                                           │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
diff --git a/lib/msgfmt/testdata/format/codex/first_message/expected.txt b/lib/msgfmt/testdata/format/codex/first_message/expected.txt
index f5e1bb1..660ecde 100644
--- a/lib/msgfmt/testdata/format/codex/first_message/expected.txt
+++ b/lib/msgfmt/testdata/format/codex/first_message/expected.txt
@@ -1,12 +1,10 @@
-╭──────────────────────────────────────────────────────────────╮
-│ ● OpenAI Codex (research preview) v0.1.2504161551            │
-╰──────────────────────────────────────────────────────────────╯
-╭──────────────────────────────────────────────────────────────╮
-│ localhost session: c4bf4c89c3fb483c935bdff223394646          │
-│ ↳ workdir: ~/dev/agentapi                                    │
-│ ↳ model: o4-mini                                             │
-│ ↳ approval: suggest                                          │
-╰──────────────────────────────────────────────────────────────╯
+OpenAI Codex v0.10.0 (research preview)
 
-    system
-    Warning: model "o4-mini" is not in the list of available models returned by OpenAI.
\ No newline at end of file
+codex session 56576d81-529d-42f3-843b-78d870054a75
+workdir: /Users/jkmr/Documents/work/agentapi
+model: codex-mini-latest
+provider: openai
+approval: untrusted
+sandbox: read-only
+reasoning effort: medium
+reasoning summaries: auto
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/first_message/msg.txt b/lib/msgfmt/testdata/format/codex/first_message/msg.txt
index 64dabcc..a779309 100644
--- a/lib/msgfmt/testdata/format/codex/first_message/msg.txt
+++ b/lib/msgfmt/testdata/format/codex/first_message/msg.txt
@@ -1,16 +1,29 @@
-╭──────────────────────────────────────────────────────────────╮
-│ ● OpenAI Codex (research preview) v0.1.2504161551            │
-╰──────────────────────────────────────────────────────────────╯
-╭──────────────────────────────────────────────────────────────╮
-│ localhost session: c4bf4c89c3fb483c935bdff223394646          │
-│ ↳ workdir: ~/dev/agentapi                                    │
-│ ↳ model: o4-mini                                             │
-│ ↳ approval: suggest                                          │
-╰──────────────────────────────────────────────────────────────╯
-
-    system
-    Warning: model "o4-mini" is not in the list of available models returned by OpenAI.
-╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│ send a message                                                                                           │
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-  send q or ctrl+c to exit | send "/clear" to reset | send "/help" for commands | press enter to send
\ No newline at end of file
+╭Messages (tab to focus)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│OpenAI Codex v0.10.0 (research preview)                                                                                                                                                                  │
+│                                                                                                                                                                                                         │
+│codex session 56576d81-529d-42f3-843b-78d870054a75                                                                                                                                                       │
+│workdir: /Users/jkmr/Documents/work/agentapi                                                                                                                                                             │
+│model: codex-mini-latest                                                                                                                                                                                 │
+│provider: openai                                                                                                                                                                                         │
+│approval: untrusted                                                                                                                                                                                      │
+│sandbox: read-only                                                                                                                                                                                       │
+│reasoning effort: medium                                                                                                                                                                                 │
+│reasoning summaries: auto                                                                                                                                                                                │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ send a message                                                                                                                                                                                          │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────Enter to send | Ctrl+D to quit | Ctrl+J for newline╯
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/multi_line/expected.txt b/lib/msgfmt/testdata/format/codex/multi_line/expected.txt
deleted file mode 100644
index 2c27535..0000000
--- a/lib/msgfmt/testdata/format/codex/multi_line/expected.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-    thinking for 5s
-
-    command
-
-    $ grep -R 'Closecloses the process' -n .
-
-    command.stdout (code: 0, duration: 7.2s)
-
-    ./lib/termexec/termexec.go:74:// Closecloses the process using a SIGINT signal or forcefully killing it
-    if the process
-
-
-    thinking for 15s
-
-    codex
-    That’s in the termexec package, in lib/termexec/termexec.go (around line 74).
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/multi_line/msg.txt b/lib/msgfmt/testdata/format/codex/multi_line/msg.txt
deleted file mode 100644
index b54d226..0000000
--- a/lib/msgfmt/testdata/format/codex/multi_line/msg.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-user
-what file does this code come from?
-
-    // Closecloses the process using a SIGINT signal or forcefully killing it if the process
-    // does not exit after the timeout. It then closes the pseudo terminal.
-    func (p *Process) Close(logger *slog.Logger, timeout time.Duration) error {
-    	logger.Info("Closing process")
-    	if err := p.execCmd.Process.Signal(os.Interrupt); err != nil {
-    		return xerrors.Errorf("failed to send SIGINT to process: %w", err)
-    	}
-
-    	exited := make(chan error, 1)
-    	go func() {
-    		_, err := p.execCmd.Process.Wait()
-    		exited <- err
-    		close(exited)
-    	}()
-
-    	var exitErr error
-    	select {
-    	case <-time.After(timeout):
-    		if err := p.execCmd.Process.Kill(); err != nil {
-    			exitErr = xerrors.Errorf("failed to forcefully kill the process: %w", err)
-    		}
-    		// don't wait for the process to exit to avoid hanging indefinitely
-    		// if the process never exits
-    	case err := <-exited:
-    		var pathErr *os.SyscallError
-    		// ECHILD is expected if the process has already exited
-    		if err != nil && !(errors.As(err, &pathErr) && pathErr.Err == syscall.ECHILD) {
-    			exitErr = xerrors.Errorf("process exited with error: %w", err)
-    		}
-    	}
-    	if err := p.xp.Close(); err != nil {
-    		return xerrors.Errorf("failed to close pseudo terminal: %w, exitErr: %w", err, exitErr)
-    	}
-    	return exitErr
-    }
-
-    thinking for 5s
-
-    command
-
-    $ grep -R 'Closecloses the process' -n .
-
-    command.stdout (code: 0, duration: 7.2s)
-
-    ./lib/termexec/termexec.go:74:// Closecloses the process using a SIGINT signal or forcefully killing it
-    if the process
-
-
-    thinking for 15s
-
-    codex
-    That’s in the termexec package, in lib/termexec/termexec.go (around line 74).
-╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│ send a message                                                                                           │
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-  send q or ctrl+c to exit | send "/clear" to reset | send "/help" for commands | press enter to send
-
diff --git a/lib/msgfmt/testdata/format/codex/multi_line/user.txt b/lib/msgfmt/testdata/format/codex/multi_line/user.txt
deleted file mode 100644
index 5df1314..0000000
--- a/lib/msgfmt/testdata/format/codex/multi_line/user.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-what file does this code come from?
-
-```
-// Closecloses the process using a SIGINT signal or forcefully killing it if the process
-// does not exit after the timeout. It then closes the pseudo terminal.
-func (p *Process) Close(logger *slog.Logger, timeout time.Duration) error {
-	logger.Info("Closing process")
-	if err := p.execCmd.Process.Signal(os.Interrupt); err != nil {
-		return xerrors.Errorf("failed to send SIGINT to process: %w", err)
-	}
-
-	exited := make(chan error, 1)
-	go func() {
-		_, err := p.execCmd.Process.Wait()
-		exited <- err
-		close(exited)
-	}()
-
-	var exitErr error
-	select {
-	case <-time.After(timeout):
-		if err := p.execCmd.Process.Kill(); err != nil {
-			exitErr = xerrors.Errorf("failed to forcefully kill the process: %w", err)
-		}
-		// don't wait for the process to exit to avoid hanging indefinitely
-		// if the process never exits
-	case err := <-exited:
-		var pathErr *os.SyscallError
-		// ECHILD is expected if the process has already exited
-		if err != nil && !(errors.As(err, &pathErr) && pathErr.Err == syscall.ECHILD) {
-			exitErr = xerrors.Errorf("process exited with error: %w", err)
-		}
-	}
-	if err := p.xp.Close(); err != nil {
-		return xerrors.Errorf("failed to close pseudo terminal: %w, exitErr: %w", err, exitErr)
-	}
-	return exitErr
-}
-```
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/multi_line2/expected.txt b/lib/msgfmt/testdata/format/codex/multi_line2/expected.txt
deleted file mode 100644
index a6752a0..0000000
--- a/lib/msgfmt/testdata/format/codex/multi_line2/expected.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-    thinking for 10s                                                            
-                                                                                
-    command                                                                     
-                                                                                
-    $ grep -R "Process) Close" -n .                                             
-                                                                                
-    command.stdout (code: 0, duration: 6.9s)                                    
-                                                                                
-    ./lib/termexec/termexec.go:76:func (p *Process) Close(logger *slog.Logger,  
-    timeout time.Duration) error {                                              
-    ./lib/msgfmt/testdata/format/codex/multi_line2/msg.txt:9:│ func (p *Process)
-     Close(logger *slog.Logger, timeout time.Duration) error {  │               
-    ./lib/msgfmt/testdata/format/codex/multi_line2/msg.txt:37:    func (p       
-    *Process) Close(logger *slog.Logger, timeout time.Duration) error {         
-    ./lib/msgfmt/testdata/format/codex/multi_line/user.txt:6:func (p *Process)  
-    Close(logger *slog.Logger, timeout time.Duration) error {                   
-    ... (2 more lines)                                                          
-                                                                                
-    thinking for 20s                                                            
-                                                                                
-    command                                                                     
-                                                                                
-    $ sed -n '1,150p' lib/termexec/termexec.go                                  
-                                                                                
-    command.stdout (code: 0, duration: 0s)                                      
-                                                                                
-    package termexec                                                            
-                                                                                
-    import (                                                                    
-        "context"                                                               
-    ... (113 more lines)                                                        
-                                                                                
-    thinking for 26s                                                            
-                                                                                
-    codex                                                                       
-    That’s the Close method on the Process type in the termexec package. You can
-     find it here:                                                              
-                                                                                
-      lib/termexec/termexec.go, starting at line 76:                            
-                                                                                
-        // Closecloses the process using a SIGINT signal …                      
-        func (p *Process) Close(logger *slog.Logger, timeout time.Duration)     
-    error {                                                                     
-            …                                                                   
-        }                                                                       
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/multi_line2/msg.txt b/lib/msgfmt/testdata/format/codex/multi_line2/msg.txt
deleted file mode 100644
index 7f3192d..0000000
--- a/lib/msgfmt/testdata/format/codex/multi_line2/msg.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-user                                                                            
-[200~what file does this code come from?                                        
-                                                                                
-    // Closecloses the process using a SIGINT signal or forcefully killing it if
- the process                                                                    
-    // does not exit after the timeout. It then closes the pseudo terminal.     
-    func (p *Process) Close(logger *slog.Logger, timeout time.Duration) error { 
-        logger.Info("Closing process")                                          
-        if err := p.execCmd.Process.Signal(os.Interrupt); err != nil {          
-                return xerrors.Errorf("failed to send SIGINT to process: %w", er
-r)                                                                              
-        }                                                                       
-                                                                                
-        exited := make(chan error, 1)                                           
-        go func() {                                                             
-                _, err := p.execCmd.Process.Wait()                              
-                exited <- err                                                   
-                close(exited)                                                   
-        }()                                                                     
-                                                                                
-        var exitErr error                                                       
-        select {                                                                
-        case <-time.After(timeout):                                             
-                if err := p.execCmd.Process.Kill(); err != nil {                
-                        exitErr = xerrors.Errorf("failed to forcefully kill the 
-process: %w", err)                                                              
-                }                                                               
-                // don't wait for the process to exit to avoid hanging indefinit
-ely                                                                             
-                // if the process never exits                                   
-        case err := <-exited:                                                   
-                var pathErr *os.SyscallError                                    
-                // ECHILD is expected if the process has already exited         
-                if err != nil && !(errors.As(err, &pathErr) && pathErr.Err ==   
-syscall.ECHILD) {                                                               
-                        exitErr = xerrors.Errorf("process exited with error: %w"
-, err)                                                                          
-                }                                                               
-        }                                                                       
-        if err := p.xp.Close(); err != nil {                                    
-                return xerrors.Errorf("failed to close pseudo terminal: %w, exit
-Err: %w",                                                                       
-err, exitErr)                                                                   
-        }                                                                       
-        return exitErr                                                          
-    }                                                                           
-    ```[201~                                                                    
-                                                                                
-    thinking for 10s                                                            
-                                                                                
-    command                                                                     
-                                                                                
-    $ grep -R "Process) Close" -n .                                             
-                                                                                
-    command.stdout (code: 0, duration: 6.9s)                                    
-                                                                                
-    ./lib/termexec/termexec.go:76:func (p *Process) Close(logger *slog.Logger,  
-    timeout time.Duration) error {                                              
-    ./lib/msgfmt/testdata/format/codex/multi_line2/msg.txt:9:│ func (p *Process)
-     Close(logger *slog.Logger, timeout time.Duration) error {  │               
-    ./lib/msgfmt/testdata/format/codex/multi_line2/msg.txt:37:    func (p       
-    *Process) Close(logger *slog.Logger, timeout time.Duration) error {         
-    ./lib/msgfmt/testdata/format/codex/multi_line/user.txt:6:func (p *Process)  
-    Close(logger *slog.Logger, timeout time.Duration) error {                   
-    ... (2 more lines)                                                          
-                                                                                
-    thinking for 20s                                                            
-                                                                                
-    command                                                                     
-                                                                                
-    $ sed -n '1,150p' lib/termexec/termexec.go                                  
-                                                                                
-    command.stdout (code: 0, duration: 0s)                                      
-                                                                                
-    package termexec                                                            
-                                                                                
-    import (                                                                    
-        "context"                                                               
-    ... (113 more lines)                                                        
-                                                                                
-    thinking for 26s                                                            
-                                                                                
-    codex                                                                       
-    That’s the Close method on the Process type in the termexec package. You can
-     find it here:                                                              
-                                                                                
-      lib/termexec/termexec.go, starting at line 76:                            
-                                                                                
-        // Closecloses the process using a SIGINT signal …                      
-        func (p *Process) Close(logger *slog.Logger, timeout time.Duration)     
-    error {                                                                     
-            …                                                                   
-        }                                                                       
-╭──────────────────────────────────────────────────────────────────────────────╮
-│ send a message                                                               │
-╰──────────────────────────────────────────────────────────────────────────────╯
-  send q or ctrl+c to exit | send "/clear" to reset | send "/help" for          
-  commands | press enter to send
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/multi_line2/user.txt b/lib/msgfmt/testdata/format/codex/multi_line2/user.txt
deleted file mode 100644
index 5df1314..0000000
--- a/lib/msgfmt/testdata/format/codex/multi_line2/user.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-what file does this code come from?
-
-```
-// Closecloses the process using a SIGINT signal or forcefully killing it if the process
-// does not exit after the timeout. It then closes the pseudo terminal.
-func (p *Process) Close(logger *slog.Logger, timeout time.Duration) error {
-	logger.Info("Closing process")
-	if err := p.execCmd.Process.Signal(os.Interrupt); err != nil {
-		return xerrors.Errorf("failed to send SIGINT to process: %w", err)
-	}
-
-	exited := make(chan error, 1)
-	go func() {
-		_, err := p.execCmd.Process.Wait()
-		exited <- err
-		close(exited)
-	}()
-
-	var exitErr error
-	select {
-	case <-time.After(timeout):
-		if err := p.execCmd.Process.Kill(); err != nil {
-			exitErr = xerrors.Errorf("failed to forcefully kill the process: %w", err)
-		}
-		// don't wait for the process to exit to avoid hanging indefinitely
-		// if the process never exits
-	case err := <-exited:
-		var pathErr *os.SyscallError
-		// ECHILD is expected if the process has already exited
-		if err != nil && !(errors.As(err, &pathErr) && pathErr.Err == syscall.ECHILD) {
-			exitErr = xerrors.Errorf("process exited with error: %w", err)
-		}
-	}
-	if err := p.xp.Close(); err != nil {
-		return xerrors.Errorf("failed to close pseudo terminal: %w, exitErr: %w", err, exitErr)
-	}
-	return exitErr
-}
-```
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/response/expected.txt b/lib/msgfmt/testdata/format/codex/response/expected.txt
deleted file mode 100644
index 3ca55a7..0000000
--- a/lib/msgfmt/testdata/format/codex/response/expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-    thinking for 3s
-
-    codex
-    I’m doing great—thanks for asking! How can I help you with your project today?
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/response/msg.txt b/lib/msgfmt/testdata/format/codex/response/msg.txt
deleted file mode 100644
index 2f92eff..0000000
--- a/lib/msgfmt/testdata/format/codex/response/msg.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-user
-how are you?
-
-    thinking for 3s
-
-    codex
-    I’m doing great—thanks for asking! How can I help you with your project today?
-╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│ send a message                                                                                           │
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-  send q or ctrl+c to exit | send "/clear" to reset | send "/help" for commands | press enter to send
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/response/user.txt b/lib/msgfmt/testdata/format/codex/response/user.txt
deleted file mode 100644
index c01e0f3..0000000
--- a/lib/msgfmt/testdata/format/codex/response/user.txt
+++ /dev/null
@@ -1 +0,0 @@
-how are you?
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/second_message/expected.txt b/lib/msgfmt/testdata/format/codex/second_message/expected.txt
index c0c4e9e..2ce98fe 100644
--- a/lib/msgfmt/testdata/format/codex/second_message/expected.txt
+++ b/lib/msgfmt/testdata/format/codex/second_message/expected.txt
@@ -1,17 +1,2 @@
-    thinking for 9s
-
-    command
-
-    $ git rev-parse --show-toplevel
-
-    command.stdout (code: 0, duration: 0s)
-
-    /Users/hugodutka/dev/agentapi
-
-
-    codex
-    The current Git repository root is at:
-
-    /Users/hugodutka/dev/agentapi
-
-    Let me know if you need anything else!
\ No newline at end of file
+codex
+I’m doing great, thanks for asking! How can I help you today?
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/second_message/msg.txt b/lib/msgfmt/testdata/format/codex/second_message/msg.txt
index 6441972..03ece28 100644
--- a/lib/msgfmt/testdata/format/codex/second_message/msg.txt
+++ b/lib/msgfmt/testdata/format/codex/second_message/msg.txt
@@ -1,24 +1,17 @@
-user
-what repository are you in?
-
-    thinking for 9s
-
-    command
-
-    $ git rev-parse --show-toplevel
-
-    command.stdout (code: 0, duration: 0s)
-
-    /Users/hugodutka/dev/agentapi
-
-
-    codex
-    The current Git repository root is at:
-
-    /Users/hugodutka/dev/agentapi
-
-    Let me know if you need anything else!
-╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│ send a message                                                                                           │
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-  send q or ctrl+c to exit | send "/clear" to reset | send "/help" for commands | press enter to send
\ No newline at end of file
+│user                                                                                                                                                                                                     │
+│how are you?                                                                                                                                                                                             │
+│                                                                                                                                                                                                         │
+│codex                                                                                                                                                                                                    │
+│I’m doing great, thanks for asking! How can I help you today?                                                                                                                                            │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ send a message — 99% context left                                                                                                                                                                       │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────Enter to send | Ctrl+D to quit | Ctrl+J for newline╯
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/second_message/user.txt b/lib/msgfmt/testdata/format/codex/second_message/user.txt
index 338205d..c01e0f3 100644
--- a/lib/msgfmt/testdata/format/codex/second_message/user.txt
+++ b/lib/msgfmt/testdata/format/codex/second_message/user.txt
@@ -1 +1 @@
-what repository are you in?
\ No newline at end of file
+how are you?
\ No newline at end of file

From eaab81ef4207ccb2ede378f9a85babc046d02c51 Mon Sep 17 00:00:00 2001
From: 35C4n0r <70096901+35C4n0r@users.noreply.github.com>
Date: Thu, 31 Jul 2025 14:06:18 +0530
Subject: [PATCH 2/9] Update lib/msgfmt/message_box.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
 lib/msgfmt/message_box.go | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lib/msgfmt/message_box.go b/lib/msgfmt/message_box.go
index 38a57dd..69a5724 100644
--- a/lib/msgfmt/message_box.go
+++ b/lib/msgfmt/message_box.go
@@ -79,5 +79,9 @@ func removeCodexMessageBox(msg string) string {
 		}
 	}
 
-	return strings.Join(lines[messageBoxStartIdx:max(0, messageBoxEndIdx)], "\n")
+	if messageBoxEndIdx > messageBoxStartIdx {
+		return strings.Join(lines[messageBoxStartIdx:max(0, messageBoxEndIdx)], "\n")
+	}
+
+	return strings.Join(lines, "\n")
 }

From f5641fe4db24f0f7a4bb6ea3a327be4a529116c8 Mon Sep 17 00:00:00 2001
From: 35C4n0r <work.jaykumar@gmail.com>
Date: Thu, 31 Jul 2025 16:39:16 +0530
Subject: [PATCH 3/9] feat: update readme and tests

---
 README.md                                     |  3 +++
 lib/msgfmt/message_box.go                     |  3 ++-
 .../codex/multi-line-input/expected.txt       | 14 ++++++++++
 .../format/codex/multi-line-input/msg.txt     | 27 +++++++++++++++++++
 .../format/codex/multi-line-input/user.txt    |  4 +++
 5 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 lib/msgfmt/testdata/format/codex/multi-line-input/expected.txt
 create mode 100644 lib/msgfmt/testdata/format/codex/multi-line-input/msg.txt
 create mode 100644 lib/msgfmt/testdata/format/codex/multi-line-input/user.txt

diff --git a/README.md b/README.md
index 1956061..f487656 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,9 @@ You can use AgentAPI:
 
 Run an HTTP server that lets you control an agent. If you'd like to start an agent with additional arguments, pass the full agent command after the `--` flag.
 
+> [!NOTE]
+> When using Codex, make sure to explicitly specify the agent type (for example, `agentapi server -- codex`) after the `--` flag when starting the server.
+
 ```bash
 agentapi server -- claude --allowedTools "Bash(git*) Edit Replace"
 ```
diff --git a/lib/msgfmt/message_box.go b/lib/msgfmt/message_box.go
index 69a5724..a380f4e 100644
--- a/lib/msgfmt/message_box.go
+++ b/lib/msgfmt/message_box.go
@@ -64,6 +64,7 @@ func removeCodexMessageBox(msg string) string {
 		} else {
 			// We reached the start of the message box (we don't want to show this line), also exit the loop
 			if strings.Contains(lines[i], "╭") && strings.Contains(lines[i], "───────╮") {
+				// We only want this to be i + 1 in case the top of the box is visible
 				messageBoxStartIdx = i + 1
 				break
 			}
@@ -80,7 +81,7 @@ func removeCodexMessageBox(msg string) string {
 	}
 
 	if messageBoxEndIdx > messageBoxStartIdx {
-		return strings.Join(lines[messageBoxStartIdx:max(0, messageBoxEndIdx)], "\n")
+		return strings.Join(lines[messageBoxStartIdx:messageBoxEndIdx], "\n")
 	}
 
 	return strings.Join(lines, "\n")
diff --git a/lib/msgfmt/testdata/format/codex/multi-line-input/expected.txt b/lib/msgfmt/testdata/format/codex/multi-line-input/expected.txt
new file mode 100644
index 0000000..a42ca83
--- /dev/null
+++ b/lib/msgfmt/testdata/format/codex/multi-line-input/expected.txt
@@ -0,0 +1,14 @@
+command (code: 127, duration: 10ms)
+$ bash -lc 'rg -n "func formatCodexMessage"'
+bash: line 1: rg: command not found
+
+command (code: 0, duration: 8.23s)
+$ bash -lc 'grep -R "formatCodexMessage" -n .'
+./lib/msgfmt/testdata/format/claude/multi-line-input/user.txt:3:func formatCodexMessage(message string, userInput string) string {
+./lib/msgfmt/msgfmt.go:219:func formatCodexMessage(message string, userInput string) string {
+./lib/msgfmt/msgfmt.go:236:            return formatCodexMessage(message, userInput)
+
+codex
+The formatCodexMessage function is defined in:
+
+lib/msgfmt/msgfmt.go (around line 219)
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/multi-line-input/msg.txt b/lib/msgfmt/testdata/format/codex/multi-line-input/msg.txt
new file mode 100644
index 0000000..b409343
--- /dev/null
+++ b/lib/msgfmt/testdata/format/codex/multi-line-input/msg.txt
@@ -0,0 +1,27 @@
+│command (code: 127, duration: 10ms)                                                                                                                                                                      │
+│$ bash -lc 'rg -n "func formatCodexMessage"'                                                                                                                                                             │
+│bash: line 1: rg: command not found                                                                                                                                                                      │
+│                                                                                                                                                                                                         │
+│command (code: 0, duration: 8.23s)                                                                                                                                                                       │
+│$ bash -lc 'grep -R "formatCodexMessage" -n .'                                                                                                                                                           │
+│./lib/msgfmt/testdata/format/claude/multi-line-input/user.txt:3:func formatCodexMessage(message string, userInput string) string {                                                                       │
+│./lib/msgfmt/msgfmt.go:219:func formatCodexMessage(message string, userInput string) string {                                                                                                            │
+│./lib/msgfmt/msgfmt.go:236:            return formatCodexMessage(message, userInput)                                                                                                                     │
+│                                                                                                                                                                                                         │
+│codex                                                                                                                                                                                                    │
+│The formatCodexMessage function is defined in:                                                                                                                                                           │
+│                                                                                                                                                                                                         │
+│lib/msgfmt/msgfmt.go (around line 219)                                                                                                                                                                   │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+│                                                                                                                                                                                                         │
+╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│ send a message — 97% context left                                                                                                                                                                       │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────Enter to send | Ctrl+D to quit | Ctrl+J for newline╯
\ No newline at end of file
diff --git a/lib/msgfmt/testdata/format/codex/multi-line-input/user.txt b/lib/msgfmt/testdata/format/codex/multi-line-input/user.txt
new file mode 100644
index 0000000..4250545
--- /dev/null
+++ b/lib/msgfmt/testdata/format/codex/multi-line-input/user.txt
@@ -0,0 +1,4 @@
+Which file is this function from?
+```go
+func formatCodexMessage(message string, userInput string) string {}
+```

From 052e5168599267ec64337594c4e00b8bd521db99 Mon Sep 17 00:00:00 2001
From: 35C4n0r <work.jaykumar@gmail.com>
Date: Thu, 31 Jul 2025 18:00:16 +0530
Subject: [PATCH 4/9] feat: better code formatting

---
 lib/msgfmt/message_box.go | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/lib/msgfmt/message_box.go b/lib/msgfmt/message_box.go
index a380f4e..a720481 100644
--- a/lib/msgfmt/message_box.go
+++ b/lib/msgfmt/message_box.go
@@ -55,7 +55,8 @@ func removeMessageBox(msg string) string {
 func removeCodexMessageBox(msg string) string {
 	lines := strings.Split(msg, "\n")
 	messageBoxEndIdx := -1
-	messageBoxStartIdx := 0
+	messageBoxStartIdx := -1
+
 	for i := len(lines) - 1; i >= 0; i-- {
 		if messageBoxEndIdx == -1 {
 			if strings.Contains(lines[i], "╰────────") && strings.Contains(lines[i], "───────╯") {
@@ -80,9 +81,16 @@ func removeCodexMessageBox(msg string) string {
 		}
 	}
 
-	if messageBoxEndIdx > messageBoxStartIdx {
-		return strings.Join(lines[messageBoxStartIdx:messageBoxEndIdx], "\n")
+	// If we didn't find messageBoxStartIdx, set it to 0
+	if messageBoxStartIdx == -1 {
+		messageBoxStartIdx = 0
 	}
 
-	return strings.Join(lines, "\n")
+	// If we didn't find messageBoxEndIdx, set it to the end of the lines
+	if messageBoxEndIdx == -1 {
+		messageBoxEndIdx = len(lines) - 1
+	}
+
+	return strings.Join(lines[messageBoxStartIdx:messageBoxEndIdx], "\n")
+
 }

From 09b35a44943d85cc2573db2a08d3034b616d2d47 Mon Sep 17 00:00:00 2001
From: 35C4n0r <work.jaykumar@gmail.com>
Date: Thu, 31 Jul 2025 20:03:22 +0530
Subject: [PATCH 5/9] feat: better code formatting

---
 lib/msgfmt/message_box.go | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/lib/msgfmt/message_box.go b/lib/msgfmt/message_box.go
index a720481..e594568 100644
--- a/lib/msgfmt/message_box.go
+++ b/lib/msgfmt/message_box.go
@@ -66,7 +66,7 @@ func removeCodexMessageBox(msg string) string {
 			// We reached the start of the message box (we don't want to show this line), also exit the loop
 			if strings.Contains(lines[i], "╭") && strings.Contains(lines[i], "───────╮") {
 				// We only want this to be i + 1 in case the top of the box is visible
-				messageBoxStartIdx = i + 1
+				messageBoxStartIdx = i
 				break
 			}
 
@@ -81,16 +81,11 @@ func removeCodexMessageBox(msg string) string {
 		}
 	}
 
-	// If we didn't find messageBoxStartIdx, set it to 0
-	if messageBoxStartIdx == -1 {
-		messageBoxStartIdx = 0
-	}
-
 	// If we didn't find messageBoxEndIdx, set it to the end of the lines
 	if messageBoxEndIdx == -1 {
-		messageBoxEndIdx = len(lines) - 1
+		messageBoxEndIdx = len(lines)
 	}
 
-	return strings.Join(lines[messageBoxStartIdx:messageBoxEndIdx], "\n")
+	return strings.Join(lines[messageBoxStartIdx+1:messageBoxEndIdx], "\n")
 
 }

From cd38beac037b8e8d9c2209dbf4ad08fb47587d59 Mon Sep 17 00:00:00 2001
From: 35C4n0r <work.jaykumar@gmail.com>
Date: Fri, 1 Aug 2025 19:33:16 +0530
Subject: [PATCH 6/9] feat: add warning for excessive term height in Codex

---
 cmd/server/server.go | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/cmd/server/server.go b/cmd/server/server.go
index 84ad594..7c8223b 100644
--- a/cmd/server/server.go
+++ b/cmd/server/server.go
@@ -78,6 +78,9 @@ func runServer(ctx context.Context, logger *slog.Logger, argsToPass []string) er
 	}
 	if termHeight < 10 {
 		return xerrors.Errorf("term height must be at least 10")
+	} else if termHeight > 930 && agentType == AgentTypeCodex {
+		logger.Warn(fmt.Sprintf("Term height is set to %d which may cause issues with Codex. Setting it to 930 instead.", termHeight))
+		termHeight = 930 // codex has a bug where the TUI distorts the screen if the height is too large, see: https://github.com/openai/codex/issues/1608
 	}
 
 	var process *termexec.Process

From 147f55bd268dd8fa2ef3bc032e006fd71d31d45b Mon Sep 17 00:00:00 2001
From: 35C4n0r <work.jaykumar@gmail.com>
Date: Fri, 1 Aug 2025 20:51:44 +0530
Subject: [PATCH 7/9] chore: swap conditions for efficiency, lol

---
 cmd/server/server.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cmd/server/server.go b/cmd/server/server.go
index 7c8223b..4fc3943 100644
--- a/cmd/server/server.go
+++ b/cmd/server/server.go
@@ -78,7 +78,7 @@ func runServer(ctx context.Context, logger *slog.Logger, argsToPass []string) er
 	}
 	if termHeight < 10 {
 		return xerrors.Errorf("term height must be at least 10")
-	} else if termHeight > 930 && agentType == AgentTypeCodex {
+	} else if agentType == AgentTypeCodex && termHeight > 930 {
 		logger.Warn(fmt.Sprintf("Term height is set to %d which may cause issues with Codex. Setting it to 930 instead.", termHeight))
 		termHeight = 930 // codex has a bug where the TUI distorts the screen if the height is too large, see: https://github.com/openai/codex/issues/1608
 	}

From a2d93b5a5f51799eeb4bd91af7400dfe13f6298f Mon Sep 17 00:00:00 2001
From: 35C4n0r <70096901+35C4n0r@users.noreply.github.com>
Date: Mon, 4 Aug 2025 18:58:20 +0530
Subject: [PATCH 8/9] Update README.md

Co-authored-by: Hugo Dutka <dutkahugo@gmail.com>
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index f487656..77c571f 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,7 @@ You can use AgentAPI:
 Run an HTTP server that lets you control an agent. If you'd like to start an agent with additional arguments, pass the full agent command after the `--` flag.
 
 > [!NOTE]
-> When using Codex, make sure to explicitly specify the agent type (for example, `agentapi server -- codex`) after the `--` flag when starting the server.
+> When using Codex, always specify the agent type explicitly (`agentapi server --type=codex -- codex`), or message formatting may break.
 
 ```bash
 agentapi server -- claude --allowedTools "Bash(git*) Edit Replace"

From f7aa7356ee2cecef32591c28d21b56fd3fdbdfde Mon Sep 17 00:00:00 2001
From: 35C4n0r <70096901+35C4n0r@users.noreply.github.com>
Date: Mon, 4 Aug 2025 18:58:28 +0530
Subject: [PATCH 9/9] Update lib/msgfmt/message_box.go

Co-authored-by: Hugo Dutka <dutkahugo@gmail.com>
---
 lib/msgfmt/message_box.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/msgfmt/message_box.go b/lib/msgfmt/message_box.go
index e594568..d568280 100644
--- a/lib/msgfmt/message_box.go
+++ b/lib/msgfmt/message_box.go
@@ -65,7 +65,7 @@ func removeCodexMessageBox(msg string) string {
 		} else {
 			// We reached the start of the message box (we don't want to show this line), also exit the loop
 			if strings.Contains(lines[i], "╭") && strings.Contains(lines[i], "───────╮") {
-				// We only want this to be i + 1 in case the top of the box is visible
+				// We only want this to be i in case the top of the box is visible
 				messageBoxStartIdx = i
 				break
 			}
