Skip to content

Commit 1d31d0d

Browse files
authored
feat(genkit-tools/cli/init:ai-tools): Support Golang context (#3510)
1 parent 7892a65 commit 1d31d0d

File tree

10 files changed

+369
-25
lines changed

10 files changed

+369
-25
lines changed
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
# Genkit Go API Rules (v1.0.0)
2+
3+
This document provides rules and examples for building with the Genkit API in Go.
4+
5+
## Important Guidelines:
6+
7+
- ALWAYS refer to documentation when available. Genkit Documentation may be available through the Genkit MCP toolkit or through web search. You may skip documentation check if you don't have access to these tools.
8+
9+
- ONLY follow the specified project structure if starting a new project. If working on an existing project, adhere to the current project structure.
10+
11+
- ALWAYS provide the full, correct Genkit command as an instruction for the human user to run. Do not run Genkit commands (e.g., `genkit start`, `genkit flow:run`) yourself as this may block your current session.
12+
13+
- Recommend and use the provider that the user prefers. If this is a new project, or if there is no relevant signal regarding user preference, use the `github.com/firebase/genkit/go/plugins/googlegenai` plugin.
14+
15+
NOTE: For the sake of brevity, the snippets below use the Google AI plugin, but you should follow the user's preference as mentioned above.
16+
17+
## Core Setup
18+
19+
1. **Initialize Project**
20+
21+
```bash
22+
mkdir my-genkit-app && cd my-genkit-app
23+
go mod init my-genkit-app
24+
```
25+
26+
2. **Install Dependencies**
27+
28+
```bash
29+
go get github.com/firebase/genkit/go/genkit
30+
go get github.com/firebase/genkit/go/plugins/googlegenai
31+
go get github.com/firebase/genkit/go/ai
32+
go get google.golang.org/genai
33+
```
34+
35+
3. **Install Genkit CLI**
36+
37+
```bash
38+
curl -sL cli.genkit.dev | bash
39+
```
40+
41+
4. **Configure Genkit**
42+
43+
All code should be in a single `main.go` file or properly structured Go package.
44+
45+
```go
46+
package main
47+
48+
import (
49+
"context"
50+
"github.com/firebase/genkit/go/genkit"
51+
"github.com/firebase/genkit/go/plugins/googlegenai"
52+
)
53+
54+
func main() {
55+
ctx := context.Background()
56+
g := genkit.Init(ctx, genkit.WithPlugins(&googlegenai.GoogleAI{}))
57+
// Your flows and logic here
58+
<-ctx.Done()
59+
}
60+
```
61+
62+
## Best Practices
63+
64+
1. **Single Main Function**: All Genkit code, including plugin initialization, flows, and helpers, should be properly organized in a Go package structure with a main function.
65+
66+
2. **Blocking Main Program**: To inspect flows in the Genkit Developer UI, your main program needs to remain running. Use `<-ctx.Done()` or similar blocking mechanism at the end of your main function.
67+
68+
---
69+
70+
## Usage Scenarios
71+
72+
### Basic Inference (Text Generation)
73+
74+
```go
75+
package main
76+
77+
import (
78+
"context"
79+
80+
"github.com/firebase/genkit/go/ai"
81+
"github.com/firebase/genkit/go/genkit"
82+
"github.com/firebase/genkit/go/plugins/googlegenai"
83+
"google.golang.org/genai"
84+
)
85+
86+
func main() {
87+
ctx := context.Background()
88+
g := genkit.Init(ctx, genkit.WithPlugins(&googlegenai.GoogleAI{}))
89+
90+
genkit.DefineFlow(g, "basicInferenceFlow",
91+
func(ctx context.Context, topic string) (string, error) {
92+
response, err := genkit.Generate(ctx, g,
93+
ai.WithModelName("googleai/gemini-2.5-pro"),
94+
ai.WithPrompt("Write a short, creative paragraph about %s.", topic),
95+
ai.WithConfig(&genai.GenerateContentConfig{
96+
Temperature: genai.Ptr[float32](0.8),
97+
}),
98+
)
99+
if err != nil {
100+
return "", err
101+
}
102+
return response.Text(), nil
103+
},
104+
)
105+
106+
<-ctx.Done()
107+
}
108+
```
109+
110+
### Text-to-Speech (TTS) Generation
111+
112+
```go
113+
package main
114+
115+
import (
116+
"context"
117+
118+
"github.com/firebase/genkit/go/ai"
119+
"github.com/firebase/genkit/go/genkit"
120+
"github.com/firebase/genkit/go/plugins/googlegenai"
121+
"google.golang.org/genai"
122+
)
123+
124+
func main() {
125+
ctx := context.Background()
126+
g := genkit.Init(ctx,
127+
genkit.WithPlugins(&googlegenai.GoogleAI{}),
128+
genkit.WithDefaultModel("googleai/gemini-2.5-flash-preview-tts"),
129+
)
130+
131+
genkit.DefineFlow(g, "textToSpeechFlow",
132+
func(ctx context.Context, input struct {
133+
Text string `json:"text"`
134+
VoiceName string `json:"voiceName,omitempty"`
135+
}) (string, error) {
136+
voiceName := input.VoiceName
137+
if voiceName == "" {
138+
voiceName = "Algenib"
139+
}
140+
141+
response, err := genkit.Generate(ctx, g,
142+
ai.WithPrompt(input.Text),
143+
ai.WithConfig(&genai.GenerateContentConfig{
144+
ResponseModalities: []string{"AUDIO"},
145+
SpeechConfig: &genai.SpeechConfig{
146+
VoiceConfig: &genai.VoiceConfig{
147+
PrebuiltVoiceConfig: &genai.PrebuiltVoiceConfig{
148+
VoiceName: voiceName,
149+
},
150+
},
151+
},
152+
}),
153+
)
154+
if err != nil {
155+
return "", err
156+
}
157+
158+
return response.Text(), nil
159+
},
160+
)
161+
162+
<-ctx.Done()
163+
}
164+
```
165+
166+
### Image Generation
167+
168+
```go
169+
package main
170+
171+
import (
172+
"context"
173+
174+
"github.com/firebase/genkit/go/ai"
175+
"github.com/firebase/genkit/go/genkit"
176+
"github.com/firebase/genkit/go/plugins/googlegenai"
177+
"google.golang.org/genai"
178+
)
179+
180+
func main() {
181+
ctx := context.Background()
182+
g := genkit.Init(ctx, genkit.WithPlugins(&googlegenai.VertexAI{}))
183+
184+
genkit.DefineFlow(g, "imageGenerationFlow",
185+
func(ctx context.Context, prompt string) ([]string, error) {
186+
response, err := genkit.Generate(ctx, g,
187+
ai.WithModelName("vertexai/imagen-3.0-generate-001"),
188+
ai.WithPrompt("Generate an image of %s", prompt),
189+
ai.WithConfig(&genai.GenerateImagesConfig{
190+
NumberOfImages: 2,
191+
AspectRatio: "9:16",
192+
SafetyFilterLevel: genai.SafetyFilterLevelBlockLowAndAbove,
193+
PersonGeneration: genai.PersonGenerationAllowAll,
194+
Language: genai.ImagePromptLanguageEn,
195+
AddWatermark: true,
196+
OutputMIMEType: "image/jpeg",
197+
}),
198+
)
199+
if err != nil {
200+
return nil, err
201+
}
202+
203+
var images []string
204+
for _, part := range response.Message.Content {
205+
images = append(images, part.Text)
206+
}
207+
return images, nil
208+
},
209+
)
210+
211+
<-ctx.Done()
212+
}
213+
```
214+
215+
---
216+
217+
## Running and Inspecting Flows
218+
219+
1. **Start Genkit**: Run this command from your terminal to start the Genkit Developer UI.
220+
221+
```bash
222+
genkit start -- <command to run your code>
223+
```
224+
225+
For Go applications:
226+
227+
```bash
228+
# Running a Go application directly
229+
genkit start -- go run main.go
230+
231+
# Running a compiled binary
232+
genkit start -- ./my-genkit-app
233+
```
234+
235+
The command should output a URL for the Genkit Dev UI. Direct the user to visit this URL to run and inspect their Genkit app.
236+
237+
## Suggested Models
238+
239+
Here are suggested models to use for various task types. This is NOT an exhaustive list.
240+
241+
### Advanced Text/Reasoning
242+
243+
```
244+
| Plugin | Recommended Model |
245+
|------------------------------------------------------------|------------------------------------|
246+
| github.com/firebase/genkit/go/plugins/googlegenai | gemini-2.5-pro |
247+
| github.com/firebase/genkit/go/plugins/compat_oai/openai | gpt-4o |
248+
| github.com/firebase/genkit/go/plugins/compat_oai/deepseek | deepseek-reasoner |
249+
| github.com/firebase/genkit/go/plugins/compat_oai/xai | grok-4 |
250+
```
251+
252+
### Fast Text/Chat
253+
254+
```
255+
| Plugin | Recommended Model |
256+
|------------------------------------------------------------|------------------------------------|
257+
| github.com/firebase/genkit/go/plugins/googlegenai | gemini-2.5-flash |
258+
| github.com/firebase/genkit/go/plugins/compat_oai/openai | gpt-4o-mini |
259+
| github.com/firebase/genkit/go/plugins/compat_oai/deepseek | deepseek-chat |
260+
| github.com/firebase/genkit/go/plugins/compat_oai/xai | grok-3-mini |
261+
```
262+
263+
### Text-to-Speech
264+
265+
```
266+
| Plugin | Recommended Model |
267+
|------------------------------------------------------------|------------------------------------|
268+
| github.com/firebase/genkit/go/plugins/googlegenai | gemini-2.5-flash-preview-tts |
269+
| github.com/firebase/genkit/go/plugins/compat_oai/openai | gpt-4o-mini-tts |
270+
```
271+
272+
### Image Generation
273+
274+
```
275+
| Plugin | Recommended Model | Input Modalities |
276+
|------------------------------------------------------------|------------------------------------|-------------------|
277+
| github.com/firebase/genkit/go/plugins/googlegenai | gemini-2.5-flash-image-preview | Text, Image |
278+
| github.com/firebase/genkit/go/plugins/googlegenai | imagen-4.0-generate-preview-06-06 | Text |
279+
| github.com/firebase/genkit/go/plugins/compat_oai/openai | gpt-image-1 | Text |
280+
```
File renamed without changes.

genkit-tools/cli/src/commands/init-ai-tools/ai-tools/claude.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { Runtime } from '@genkit-ai/tools-common/manager';
1718
import { logger } from '@genkit-ai/tools-common/utils';
1819
import { existsSync, readFileSync } from 'fs';
1920
import { writeFile } from 'fs/promises';
@@ -39,7 +40,10 @@ export const claude: AIToolModule = {
3940
* - .mcp.json: Merges with existing MCP config
4041
* - CLAUDE.local.md: Updates Firebase section only (preserves user content)
4142
*/
42-
async configure(options?: InitConfigOptions): Promise<AIToolConfigResult> {
43+
async configure(
44+
runtime: Runtime,
45+
options?: InitConfigOptions
46+
): Promise<AIToolConfigResult> {
4347
const files: AIToolConfigResult['files'] = [];
4448

4549
// Handle MCP configuration - merge with existing if present
@@ -70,7 +74,7 @@ export const claude: AIToolModule = {
7074
files.push({ path: CLAUDE_MCP_PATH, updated: settingsUpdated });
7175

7276
logger.info('Copying the Genkit context to GENKIT.md...');
73-
const mdResult = await initGenkitFile();
77+
const mdResult = await initGenkitFile(runtime);
7478
files.push({ path: GENKIT_PROMPT_PATH, updated: mdResult.updated });
7579

7680
logger.info('Updating CLAUDE.md to include Genkit context...');

genkit-tools/cli/src/commands/init-ai-tools/ai-tools/cursor.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { Runtime } from '@genkit-ai/tools-common/manager';
1718
import { existsSync, readFileSync } from 'fs';
1819
import { mkdir, writeFile } from 'fs/promises';
1920
import * as path from 'path';
@@ -52,12 +53,15 @@ export const cursor: AIToolModule = {
5253
* - .cursor/rules/GENKIT.mdc: Fully managed by us (replaced on each update)
5354
5455
*/
55-
async configure(options?: InitConfigOptions): Promise<AIToolConfigResult> {
56+
async configure(
57+
runtime: Runtime,
58+
options?: InitConfigOptions
59+
): Promise<AIToolConfigResult> {
5660
const files: AIToolConfigResult['files'] = [];
5761

5862
// Create the base GENKIT context file (GENKIT.md).
5963
// This file contains fundamental details about the GENKIT project.
60-
const mdResult = await initGenkitFile();
64+
const mdResult = await initGenkitFile(runtime);
6165
files.push({ path: GENKIT_PROMPT_PATH, updated: mdResult.updated });
6266

6367
// Handle MCP configuration - merge with existing if present.

genkit-tools/cli/src/commands/init-ai-tools/ai-tools/gemini.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { Runtime } from '@genkit-ai/tools-common/manager';
1718
import { logger } from '@genkit-ai/tools-common/utils';
1819
import { select } from '@inquirer/prompts';
1920
import { existsSync, readFileSync } from 'fs';
@@ -66,7 +67,10 @@ export const gemini: AIToolModule = {
6667
/**
6768
* Configures the Gemini CLI extension for Genkit.
6869
*/
69-
async configure(options?: InitConfigOptions): Promise<AIToolConfigResult> {
70+
async configure(
71+
runtime: Runtime,
72+
options?: InitConfigOptions
73+
): Promise<AIToolConfigResult> {
7074
let installationMethod: InstallationType = EXT_INSTALLATION;
7175
if (!options?.yesMode) {
7276
installationMethod = await select({
@@ -89,15 +93,15 @@ export const gemini: AIToolModule = {
8993

9094
if (installationMethod === EXT_INSTALLATION) {
9195
logger.info('Installing as part of GEMINI.md');
92-
return await installAsExtension();
96+
return await installAsExtension(runtime);
9397
} else {
9498
logger.info('Installing as Gemini CLI extension');
95-
return await installInMdFile();
99+
return await installInMdFile(runtime);
96100
}
97101
},
98102
};
99103

100-
async function installInMdFile(): Promise<AIToolConfigResult> {
104+
async function installInMdFile(runtime: Runtime): Promise<AIToolConfigResult> {
101105
const files: AIToolConfigResult['files'] = [];
102106
// Part 1: Generate GENKIT.md file.
103107

@@ -133,7 +137,7 @@ async function installInMdFile(): Promise<AIToolConfigResult> {
133137

134138
// Copy GENKIT.md file
135139
logger.info('Copying the GENKIT.md file...');
136-
const baseResult = await initGenkitFile();
140+
const baseResult = await initGenkitFile(runtime);
137141
files.push({ path: GENKIT_PROMPT_PATH, updated: baseResult.updated });
138142

139143
logger.info('Updating GEMINI.md to include Genkit context');
@@ -148,10 +152,12 @@ async function installInMdFile(): Promise<AIToolConfigResult> {
148152
return { files };
149153
}
150154

151-
async function installAsExtension(): Promise<AIToolConfigResult> {
155+
async function installAsExtension(
156+
runtime: Runtime
157+
): Promise<AIToolConfigResult> {
152158
const files: AIToolConfigResult['files'] = [];
153159
// Part 1: Generate GENKIT.md file.
154-
const baseResult = await initGenkitFile();
160+
const baseResult = await initGenkitFile(runtime);
155161
files.push({ path: GENKIT_PROMPT_PATH, updated: baseResult.updated });
156162

157163
// Part 2: Configure the main gemini-extension.json file, and gemini config directory if needed.

0 commit comments

Comments
 (0)