Skip to content

feat: support gemini cli #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ snapshot2-*.log
schema.yaml
**/.claude/settings.local.json
out


#IDEs
.idea
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AgentAPI

Control [Claude Code](https://github.com/anthropics/claude-code), [Goose](https://github.com/block/goose), [Aider](https://github.com/Aider-AI/aider), and [Codex](https://github.com/openai/codex) with an HTTP API.
Control [Claude Code](https://github.com/anthropics/claude-code), [Goose](https://github.com/block/goose), [Aider](https://github.com/Aider-AI/aider), [Gemini](https://github.com/google-gemini/gemini-cli) and [Codex](https://github.com/openai/codex) with an HTTP API.

![agentapi-chat](https://github.com/user-attachments/assets/57032c9f-4146-4b66-b219-09e38ab7690d)

Expand Down
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
var rootCmd = &cobra.Command{
Use: "agentapi",
Short: "AgentAPI CLI",
Long: `AgentAPI - HTTP API for Claude Code, Goose, Aider, and Codex`,
Long: `AgentAPI - HTTP API for Claude Code, Goose, Aider, Gemini and Codex`,
Version: "0.2.3",
}

Expand Down
7 changes: 6 additions & 1 deletion cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
AgentTypeGoose AgentType = msgfmt.AgentTypeGoose
AgentTypeAider AgentType = msgfmt.AgentTypeAider
AgentTypeCodex AgentType = msgfmt.AgentTypeCodex
AgentTypeGemini AgentType = msgfmt.AgentTypeGemini
AgentTypeCustom AgentType = msgfmt.AgentTypeCustom
)

Expand All @@ -46,6 +47,8 @@ func parseAgentType(firstArg string, agentTypeVar string) (AgentType, error) {
agentType = AgentTypeGoose
case string(AgentTypeAider):
agentType = AgentTypeAider
case string(AgentTypeGemini):
agentType = AgentTypeGemini
case string(AgentTypeCustom):
agentType = AgentTypeCustom
case string(AgentTypeCodex):
Expand All @@ -68,6 +71,8 @@ func parseAgentType(firstArg string, agentTypeVar string) (AgentType, error) {
agentType = AgentTypeAider
case string(AgentTypeCodex):
agentType = AgentTypeCodex
case string(AgentTypeGemini):
agentType = AgentTypeGemini
default:
agentType = AgentTypeCustom
}
Expand Down Expand Up @@ -137,7 +142,7 @@ func runServer(ctx context.Context, logger *slog.Logger, argsToPass []string) er
var ServerCmd = &cobra.Command{
Use: "server [agent]",
Short: "Run the server",
Long: `Run the server with the specified agent (claude, goose, aider, codex)`,
Long: `Run the server with the specified agent (claude, goose, aider, gemini, codex)`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
Expand Down
10 changes: 10 additions & 0 deletions cmd/server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ func TestParseAgentType(t *testing.T) {
agentTypeVar: "",
want: AgentTypeClaude,
},
{
firstArg: "gemini",
agentTypeVar: "",
want: AgentTypeGemini,
},
{
firstArg: "goose",
agentTypeVar: "",
Expand All @@ -48,6 +53,11 @@ func TestParseAgentType(t *testing.T) {
agentTypeVar: "claude",
want: AgentTypeClaude,
},
{
firstArg: "claude",
agentTypeVar: "gemini",
want: AgentTypeGemini,
},
{
firstArg: "aider",
agentTypeVar: "claude",
Expand Down
13 changes: 12 additions & 1 deletion lib/msgfmt/msgfmt.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package msgfmt

import "strings"
import (
"strings"
)

const WhiteSpaceChars = " \t\n\r\f\v"

Expand Down Expand Up @@ -166,6 +168,12 @@ func RemoveUserInput(msgRaw string, userInputRaw string) string {
// Return the original message starting with the first line
// that doesn't contain the echoed user input.
lastUserInputLineIdx := msgRuneLineLocations[userInputEndIdx]

// In case of Gemini, the user input echoed back is wrapped in a rounded box, so we remove it.
if lastUserInputLineIdx+1 < len(msgLines) && strings.Contains(msgLines[lastUserInputLineIdx+1], "╯") && strings.Contains(msgLines[lastUserInputLineIdx+1], "╰") {
lastUserInputLineIdx += 1
}

return strings.Join(msgLines[lastUserInputLineIdx+1:], "\n")
}

Expand Down Expand Up @@ -197,6 +205,7 @@ const (
AgentTypeGoose AgentType = "goose"
AgentTypeAider AgentType = "aider"
AgentTypeCodex AgentType = "codex"
AgentTypeGemini AgentType = "gemini"
AgentTypeCustom AgentType = "custom"
)

Expand All @@ -217,6 +226,8 @@ func FormatAgentMessage(agentType AgentType, message string, userInput string) s
return formatGenericMessage(message, userInput)
case AgentTypeCodex:
return formatGenericMessage(message, userInput)
case AgentTypeGemini:
return formatGenericMessage(message, userInput)
case AgentTypeCustom:
return formatGenericMessage(message, userInput)
default:
Expand Down
2 changes: 1 addition & 1 deletion lib/msgfmt/msgfmt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func TestTrimEmptyLines(t *testing.T) {

func TestFormatAgentMessage(t *testing.T) {
dir := "testdata/format"
agentTypes := []AgentType{AgentTypeClaude, AgentTypeGoose, AgentTypeAider, AgentTypeCodex, AgentTypeCustom}
agentTypes := []AgentType{AgentTypeClaude, AgentTypeGoose, AgentTypeAider, AgentTypeGemini, AgentTypeCodex, AgentTypeCustom}
for _, agentType := range agentTypes {
t.Run(string(agentType), func(t *testing.T) {
cases, err := testdataDir.ReadDir(path.Join(dir, string(agentType)))
Expand Down
5 changes: 5 additions & 0 deletions lib/msgfmt/testdata/format/gemini/first_message/expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Tips for getting started:
1. Ask questions, edit files, or run commands.
2. Be specific for the best results.
3. Create GEMINI.md files to customize your interactions with Gemini.
4. /help for more information.
13 changes: 13 additions & 0 deletions lib/msgfmt/testdata/format/gemini/first_message/msg.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Tips for getting started:
1. Ask questions, edit files, or run commands.
2. Be specific for the best results.
3. Create GEMINI.md files to customize your interactions with Gemini.
4. /help for more information.



╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ > Type your message or @path/to/file │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

~/Documents/work/agentapi (feat-claude-cli*) no sandbox (see /docs) gemini-2.5-pro (100% context left)
Empty file.
14 changes: 14 additions & 0 deletions lib/msgfmt/testdata/format/gemini/multi-line-input/expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✔ SearchText 'setInterval\(fetchMessages, 1000\)' in **/*.tsx │
│ │
│ No matches found │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✔ SearchText 'checkServerStatus, 250' in **/*.tsx │
│ │
│ No matches found │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I couldn't find that exact code snippet in the project. It's possible it has been modified or is from a file that wasn't included in the initial project listing.

To help me locate it, could you tell me more about what the code does or what component it might be a part of? For example, is it part of the main chat window, a status indicator,
or something else?
43 changes: 43 additions & 0 deletions lib/msgfmt/testdata/format/gemini/multi-line-input/msg.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
╭───────────────────────────────────────────────────────────────────╮
│ > Which file is this code from? │
│ │
│ ```ts │
│ // Set up polling for messages and server status │
│ useEffect(() => { │
│ // Check server status initially │
│ checkServerStatus(); │
│ │
│ // Set up polling intervals │
│ const messageInterval = setInterval(fetchMessages, 1000); │
│ const statusInterval = setInterval(checkServerStatus, 250); │
│ │
│ // Clean up intervals on component unmount │
│ return () => { │
│ clearInterval(messageInterval); │
│ clearInterval(statusInterval); │
│ }; │
│ }, []); │
│ ``` │
╰───────────────────────────────────────────────────────────────────╯

╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✔ SearchText 'setInterval\(fetchMessages, 1000\)' in **/*.tsx │
│ │
│ No matches found │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✔ SearchText 'checkServerStatus, 250' in **/*.tsx │
│ │
│ No matches found │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I couldn't find that exact code snippet in the project. It's possible it has been modified or is from a file that wasn't included in the initial project listing.

To help me locate it, could you tell me more about what the code does or what component it might be a part of? For example, is it part of the main chat window, a status indicator,
or something else?


╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ > Type your message or @path/to/file │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

~/Documents/work/agentapi (feat-claude-cli*) no sandbox (see /docs) gemini-2.5-pro (99% context left)
19 changes: 19 additions & 0 deletions lib/msgfmt/testdata/format/gemini/multi-line-input/user.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Which file is this code from?

```ts
// Set up polling for messages and server status
useEffect(() => {
// Check server status initially
checkServerStatus();

// Set up polling intervals
const messageInterval = setInterval(fetchMessages, 1000);
const statusInterval = setInterval(checkServerStatus, 250);

// Clean up intervals on component unmount
return () => {
clearInterval(messageInterval);
clearInterval(statusInterval);
};
}, []);
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
✦ I am ready to assist you. What can I help you with?
12 changes: 12 additions & 0 deletions lib/msgfmt/testdata/format/gemini/second_message/msg.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
╭──────────────────╮
│ > How are you? │
╰──────────────────╯

✦ I am ready to assist you. What can I help you with?


╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ > Type your message or @path/to/file │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

~/Documents/work/agentapi (feat-claude-cli*) no sandbox (see /docs) gemini-2.5-pro (99% context left)
1 change: 1 addition & 0 deletions lib/msgfmt/testdata/format/gemini/second_message/user.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
How are you?