Skip to content

Commit 7d9616f

Browse files
authored
model: gemini integration (#99)
* Integrate gemini * Fix gemini cannot read current dir content * Update June devlog * Prepare for release 0.1.3 * Add dev log for july
1 parent f222beb commit 7d9616f

File tree

20 files changed

+628
-79
lines changed

20 files changed

+628
-79
lines changed

.zed/tasks.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[
2+
{
3+
"label": "Run server",
4+
"command": "make serve",
5+
//"args": [],
6+
// Env overrides for the command, will be appended to the terminal's environment from the settings.
7+
"env": { "foo": "bar" },
8+
// Current working directory to spawn the command into, defaults to current project root.
9+
//"cwd": "/path/to/working/directory",
10+
// Whether to use a new terminal tab or reuse the existing one to spawn the process, defaults to `false`.
11+
"use_new_terminal": false,
12+
// Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish, defaults to `false`.
13+
"allow_concurrent_runs": false,
14+
// What to do with the terminal pane and tab, after the command was started:
15+
// * `always` — always show the task's pane, and focus the corresponding tab in it (default)
16+
// * `no_focus` — always show the task's pane, add the task's tab in it, but don't focus it
17+
// * `never` — do not alter focus, but still add/reuse the task's tab in its pane
18+
"reveal": "always",
19+
// Where to place the task's terminal item after starting the task:
20+
// * `dock` — in the terminal dock, "regular" terminal items' place (default)
21+
// * `center` — in the central pane group, "main" editor area
22+
"reveal_target": "dock",
23+
// What to do with the terminal pane and tab, after the command had finished:
24+
// * `never` — Do nothing when the command finishes (default)
25+
// * `always` — always hide the terminal tab, hide the pane also if it was the last tab in it
26+
// * `on_success` — hide the terminal tab on task success only, otherwise behaves similar to `always`
27+
"hide": "never",
28+
// Which shell to use when running a task inside the terminal.
29+
// May take 3 values:
30+
// 1. (default) Use the system's default terminal configuration in /etc/passwd
31+
// "shell": "system"
32+
// 2. A program:
33+
// "shell": {
34+
// "program": "sh"
35+
// }
36+
// 3. A program with arguments:
37+
// "shell": {
38+
// "with_arguments": {
39+
// "program": "/bin/bash",
40+
// "args": ["--login"]
41+
// }
42+
// }
43+
"shell": "system",
44+
// Represents the tags for inline runnable indicators, or spawning multiple tasks at once.
45+
"tags": []
46+
}
47+
]

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ run/new:
22
go run ./main.go
33
run/latest:
44
go run ./main.go -n=false
5+
run/gemini:
6+
go run ./main.go --provider=google
57
serve:
68
go run ./main.go serve
79
list/models:

agent/agent.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ func (a *Agent) Run(ctx context.Context) error {
8888

8989
for _, c := range agentMsg.Content {
9090
switch c.Type {
91+
// TODO: Switch case for text type should be here
92+
// and we need to stream the response here, not inside the model integrations
9193
case message.ToolUseType:
9294
result := a.executeTool(c.OfToolUseBlock.ID, c.OfToolUseBlock.Name, c.OfToolUseBlock.Input)
9395
toolResults = append(toolResults, result)
@@ -127,7 +129,7 @@ func (a *Agent) executeTool(id, name string, input json.RawMessage) message.Cont
127129
if !found {
128130
// TODO: Return proper error type
129131
errorMsg := "tool not found"
130-
return message.NewToolResultContentBlock(id, errorMsg, true)
132+
return message.NewToolResultContentBlock(id, name, errorMsg, true)
131133
}
132134

133135
fmt.Printf("\u001b[92mtool\u001b[0m: %s(%s)\n", name, input)
@@ -136,10 +138,10 @@ func (a *Agent) executeTool(id, name string, input json.RawMessage) message.Cont
136138
response, err := toolDef.Function(input)
137139

138140
if err != nil {
139-
return message.NewToolResultContentBlock(id, err.Error(), true)
141+
return message.NewToolResultContentBlock(id, name, err.Error(), true)
140142
}
141143

142-
return message.NewToolResultContentBlock(id, response, false)
144+
return message.NewToolResultContentBlock(id, name, response, false)
143145
}
144146

145147
func (a *Agent) saveConversation() error {

cmd/cmd.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ func ChatHandler(cmd *cobra.Command, args []string) error {
5757
modelConfig.Model = string(defaultModel)
5858
}
5959

60+
// Default number of max tokens
61+
if modelConfig.MaxTokens == 0 {
62+
modelConfig.MaxTokens = 8192
63+
}
64+
6065
var convID string
6166
if new {
6267
convID = ""

cmd/interactive.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
)
1616

1717
func interactive(ctx context.Context, convID string, modelConfig inference.ModelConfig, client *api.Client) error {
18-
model, err := inference.Init(modelConfig)
18+
model, err := inference.Init(ctx, modelConfig)
1919
if err != nil {
2020
log.Fatalf("Failed to initialize model: %s", err.Error())
2121
}

devlogs/DevLogJuly2025.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
- Default max token is now 8192. Larger context yay!
2+
3+
- Gemini integration is here! With hacks and lots of TODOs of course, but I prioritize fast shipping :)
4+
5+
- `grep_search` is really fun to build. Right now we need `ripgrep` as a dependency, but in the future I might try a native approach (less performant of course)

devlogs/DevLogJune2025.md

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,15 @@
1-
[Delta vs snapshot streaming](https://docs.anthropic.com/en/docs/build-with-claude/streaming#delta-vs-snapshot-streaming)
1+
(This should have been done a month ago but I was lazy lol)
22

3-
Maybe a buffer is enoug? Get the stream, push the data from the stream to the buffer, then send the data from the buffer to a channel of CustomResponse? -> Go for this, dont overthink
3+
- I learn a lot about [Delta vs snapshot streaming](https://docs.anthropic.com/en/docs/build-with-claude/streaming#delta-vs-snapshot-streaming) when intergrating Claude and Gemini into the agent
44

5-
content_block_start events for tool use blocks
6-
content_block_delta events with accumulated partial JSON
5+
- At some point I was wondering about handling the streaming response from the model. Maybe a buffer is enough? Get the stream, push the data from the stream to the buffer, then send the data from the buffer to a channel of CustomResponse? I will try to keep it simple first. Maybe using an iterator is a better idea.
76

8-
`ContentBlock` as a unified interface for different content block types
7+
- `ContentBlockUnion` as a unified struct for different content block types. Stole this idea from "anthropic-sdk-go" although the implementation is kinda meh
98

10-
sqlite3 as a lightweight option to store conversations
9+
- I have always been thinking of implementing a server to handle all the CRUD-related stuff, just like what Ollama did with the models. And if there will be a server, there should be a database, and sqlite3 is perfect as a lightweight option to store conversations
1110

12-
Two modes: Snapshot and streaming
11+
- A good piece of advice: Too many tools and the agent would get stuck and not know which one to use. A curated set of tools is the most important thing.
1312

14-
Too many tools and the agent would stuck and not know which one to use. A curated set of tools is important
13+
- The tokens must flow. The agent should retry the operation instead of halting it
1514

16-
The tokens must flow. The agent should retry the operation instead of halting it
17-
18-
Next tools:
19-
20-
Structural Search Interface (full‑text, regex, and language-aware structural code search)?
21-
Commit Diff Lookup
22-
23-
Server to handle CRUD for conversations, lifecycle for server
24-
25-
No need for store, that's for local model state
15+
- Ideas for the next tool(s): Commit Diff Lookup

go.mod

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,19 @@ require (
88
github.com/invopop/jsonschema v0.13.0
99
github.com/mattn/go-sqlite3 v1.14.28
1010
github.com/olekukonko/tablewriter v1.0.7
11+
google.golang.org/genai v1.14.0
1112
)
1213

1314
require (
15+
cloud.google.com/go v0.116.0 // indirect
16+
cloud.google.com/go/auth v0.9.3 // indirect
17+
cloud.google.com/go/compute/metadata v0.5.0 // indirect
1418
github.com/fatih/color v1.15.0 // indirect
19+
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
20+
github.com/google/go-cmp v0.6.0 // indirect
21+
github.com/google/s2a-go v0.1.8 // indirect
22+
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
23+
github.com/gorilla/websocket v1.5.3 // indirect
1524
github.com/inconshreveable/mousetrap v1.1.0 // indirect
1625
github.com/mattn/go-colorable v0.1.13 // indirect
1726
github.com/mattn/go-isatty v0.0.19 // indirect
@@ -20,7 +29,14 @@ require (
2029
github.com/olekukonko/ll v0.0.8 // indirect
2130
github.com/rivo/uniseg v0.2.0 // indirect
2231
github.com/spf13/pflag v1.0.6 // indirect
23-
golang.org/x/sys v0.22.0 // indirect
32+
go.opencensus.io v0.24.0 // indirect
33+
golang.org/x/crypto v0.27.0 // indirect
34+
golang.org/x/net v0.29.0 // indirect
35+
golang.org/x/sys v0.25.0 // indirect
36+
golang.org/x/text v0.18.0 // indirect
37+
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
38+
google.golang.org/grpc v1.66.2 // indirect
39+
google.golang.org/protobuf v1.34.2 // indirect
2440
)
2541

2642
require (

0 commit comments

Comments
 (0)