Skip to content

Commit 69540b1

Browse files
committed
codex support without multi-line input yet
1 parent b732081 commit 69540b1

File tree

24 files changed

+445
-36
lines changed

24 files changed

+445
-36
lines changed

cmd/server/server.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const (
2727
AgentTypeClaude AgentType = msgfmt.AgentTypeClaude
2828
AgentTypeGoose AgentType = msgfmt.AgentTypeGoose
2929
AgentTypeAider AgentType = msgfmt.AgentTypeAider
30+
AgentTypeCodex AgentType = msgfmt.AgentTypeCodex
3031
AgentTypeCustom AgentType = msgfmt.AgentTypeCustom
3132
)
3233

@@ -41,6 +42,8 @@ func parseAgentType(firstArg string, agentTypeVar string) (AgentType, error) {
4142
agentType = AgentTypeAider
4243
case string(AgentTypeCustom):
4344
agentType = AgentTypeCustom
45+
case string(AgentTypeCodex):
46+
agentType = AgentTypeCodex
4447
case "":
4548
// do nothing
4649
default:
@@ -57,6 +60,8 @@ func parseAgentType(firstArg string, agentTypeVar string) (AgentType, error) {
5760
agentType = AgentTypeGoose
5861
case string(AgentTypeAider):
5962
agentType = AgentTypeAider
63+
case string(AgentTypeCodex):
64+
agentType = AgentTypeCodex
6065
default:
6166
agentType = AgentTypeCustom
6267
}
@@ -66,7 +71,7 @@ func parseAgentType(firstArg string, agentTypeVar string) (AgentType, error) {
6671
var ServerCmd = &cobra.Command{
6772
Use: "server [agent]",
6873
Short: "Run the server",
69-
Long: `Run the server with the specified agent (claude, goose, aider, custom)`,
74+
Long: `Run the server with the specified agent (claude, goose, aider, codex)`,
7075
Args: cobra.MinimumNArgs(1),
7176
Run: func(cmd *cobra.Command, args []string) {
7277
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))

lib/msgfmt/claude.go

Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,77 @@ import (
44
"strings"
55
)
66

7-
func removeClaudeMessageBox(msg string) string {
8-
lines := strings.Split(msg, "\n")
9-
lastLine := func() string {
10-
if len(lines) > 0 {
11-
return lines[len(lines)-1]
12-
}
13-
return ""
14-
}
15-
trimmedLastLine := func() string {
16-
return strings.TrimSpace(lastLine())
17-
}
18-
popLine := func() {
19-
if len(lines) > 0 {
20-
lines = lines[:len(lines)-1]
7+
// Usually something like
8+
// ───────────────
9+
// >
10+
// ───────────────
11+
// Used by Claude Code, Goose, and Aider.
12+
func findGreaterThanMessageBox(lines []string) int {
13+
for i := len(lines) - 1; i >= max(len(lines)-6, 0); i-- {
14+
if strings.Contains(lines[i], ">") {
15+
if i > 0 && strings.Contains(lines[i-1], "───────────────") {
16+
return i - 1
17+
}
18+
return i
2119
}
2220
}
21+
return -1
22+
}
2323

24-
// The ">" symbol is often used to indicate the user input line.
25-
// We remove all lines including and after the last ">" symbol
26-
// in the message.
27-
greaterThanLineIdx := -1
28-
for i := len(lines) - 1; i >= max(len(lines)-6, 0); i-- {
29-
if strings.Contains(lines[i], ">") {
30-
greaterThanLineIdx = i
31-
break
24+
// Usually something like
25+
// ───────────────
26+
// |
27+
// ───────────────
28+
// Used by OpenAI Codex.
29+
func findGenericSlimMessageBox(lines []string) int {
30+
for i := len(lines) - 3; i >= max(len(lines)-9, 0); i-- {
31+
if strings.Contains(lines[i], "───────────────") &&
32+
(strings.Contains(lines[i+1], "|") || strings.Contains(lines[i+1], "│")) &&
33+
strings.Contains(lines[i+2], "───────────────") {
34+
return i
3235
}
3336
}
34-
if greaterThanLineIdx >= 0 {
35-
lines = lines[:greaterThanLineIdx]
37+
return -1
38+
}
39+
40+
func removeMessageBox(msg string) string {
41+
lines := strings.Split(msg, "\n")
42+
43+
messageBoxStartIdx := findGreaterThanMessageBox(lines)
44+
if messageBoxStartIdx == -1 {
45+
messageBoxStartIdx = findGenericSlimMessageBox(lines)
3646
}
3747

38-
msgBoxEdge := "───────────────"
39-
if strings.Contains(trimmedLastLine(), msgBoxEdge) {
40-
popLine()
48+
if messageBoxStartIdx != -1 {
49+
lines = lines[:messageBoxStartIdx]
4150
}
4251

4352
return strings.Join(lines, "\n")
4453
}
4554

46-
func formatClaudeMessage(message string, userInput string) string {
55+
func formatGenericMessage(message string, userInput string) string {
4756
message = RemoveUserInput(message, userInput)
48-
message = removeClaudeMessageBox(message)
57+
message = removeMessageBox(message)
4958
message = trimEmptyLines(message)
5059
return message
5160
}
5261

62+
func formatClaudeMessage(message string, userInput string) string {
63+
return formatGenericMessage(message, userInput)
64+
}
65+
5366
func formatGooseMessage(message string, userInput string) string {
54-
// The current formatClaudeMessage implementation is so generic
55-
// that it works with both Goose and Aider too.
56-
return formatClaudeMessage(message, userInput)
67+
return formatGenericMessage(message, userInput)
5768
}
5869

5970
func formatAiderMessage(message string, userInput string) string {
60-
return formatClaudeMessage(message, userInput)
71+
return formatGenericMessage(message, userInput)
72+
}
73+
74+
func formatCodexMessage(message string, userInput string) string {
75+
return formatGenericMessage(message, userInput)
6176
}
6277

6378
func formatCustomMessage(message string, userInput string) string {
64-
return formatClaudeMessage(message, userInput)
79+
return formatGenericMessage(message, userInput)
6580
}

lib/msgfmt/msgfmt.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ const (
193193
AgentTypeClaude AgentType = "claude"
194194
AgentTypeGoose AgentType = "goose"
195195
AgentTypeAider AgentType = "aider"
196+
AgentTypeCodex AgentType = "codex"
196197
AgentTypeCustom AgentType = "custom"
197198
)
198199

@@ -204,6 +205,8 @@ func FormatAgentMessage(agentType AgentType, message string, userInput string) s
204205
return formatGooseMessage(message, userInput)
205206
case AgentTypeAider:
206207
return formatAiderMessage(message, userInput)
208+
case AgentTypeCodex:
209+
return formatCodexMessage(message, userInput)
207210
case AgentTypeCustom:
208211
return formatCustomMessage(message, userInput)
209212
default:

lib/msgfmt/msgfmt_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ func TestTrimEmptyLines(t *testing.T) {
217217

218218
func TestFormatAgentMessage(t *testing.T) {
219219
dir := "testdata/format"
220-
agentTypes := []AgentType{AgentTypeClaude, AgentTypeGoose, AgentTypeAider, AgentTypeCustom}
220+
agentTypes := []AgentType{AgentTypeClaude, AgentTypeGoose, AgentTypeAider, AgentTypeCodex, AgentTypeCustom}
221221
for _, agentType := range agentTypes {
222222
t.Run(string(agentType), func(t *testing.T) {
223223
cases, err := testdataDir.ReadDir(path.Join(dir, string(agentType)))
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
thinking for 9s
2+
3+
command
4+
5+
$ git rev-parse --show-toplevel
6+
7+
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
8+
│Shell Command │
9+
│ │
10+
│$ git rev-parse --show-toplevel │
11+
│ │
12+
│Allow command? │
13+
│ │
14+
│ ❯ Yes (y) │
15+
│ Yes, always approve this exact command for this session (a) │
16+
│ Edit or give feedback (e) │
17+
│ No, and keep going (n) │
18+
│ No, and stop for now (esc) │
19+
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
user
2+
what repository are you in?
3+
4+
thinking for 9s
5+
6+
command
7+
8+
$ git rev-parse --show-toplevel
9+
10+
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
11+
│Shell Command │
12+
│ │
13+
│$ git rev-parse --show-toplevel │
14+
│ │
15+
│Allow command? │
16+
│ │
17+
│ ❯ Yes (y) │
18+
│ Yes, always approve this exact command for this session (a) │
19+
│ Edit or give feedback (e) │
20+
│ No, and keep going (n) │
21+
│ No, and stop for now (esc) │
22+
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
what repository are you in?
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
╭──────────────────────────────────────────────────────────────╮
2+
│ ● OpenAI Codex (research preview) v0.1.2504161551 │
3+
╰──────────────────────────────────────────────────────────────╯
4+
╭──────────────────────────────────────────────────────────────╮
5+
│ localhost session: c4bf4c89c3fb483c935bdff223394646 │
6+
│ ↳ workdir: ~/dev/agentapi │
7+
│ ↳ model: o4-mini │
8+
│ ↳ approval: suggest │
9+
╰──────────────────────────────────────────────────────────────╯
10+
11+
system
12+
Warning: model "o4-mini" is not in the list of available models returned by OpenAI.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
╭──────────────────────────────────────────────────────────────╮
2+
│ ● OpenAI Codex (research preview) v0.1.2504161551 │
3+
╰──────────────────────────────────────────────────────────────╯
4+
╭──────────────────────────────────────────────────────────────╮
5+
│ localhost session: c4bf4c89c3fb483c935bdff223394646 │
6+
│ ↳ workdir: ~/dev/agentapi │
7+
│ ↳ model: o4-mini │
8+
│ ↳ approval: suggest │
9+
╰──────────────────────────────────────────────────────────────╯
10+
11+
system
12+
Warning: model "o4-mini" is not in the list of available models returned by OpenAI.
13+
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
14+
│ send a message │
15+
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯
16+
send q or ctrl+c to exit | send "/clear" to reset | send "/help" for commands | press enter to send

lib/msgfmt/testdata/format/codex/first_message/user.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)