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 5 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