Repository: google/adk-go
File: examples/vertexai/imagegenerator/main.go (Go)

Code before:
		localFilename += ".png"
	}

	// Create an "output" directory in the current working directory if it doesn't exist.
	outputDir := "output"
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		log.Printf("Failed to create output directory '%s': %v", outputDir, err)
		return saveImageResult{Status: "fail"}
	}

	localPath := filepath.Join(outputDir, localFilename)
	err = os.WriteFile(localPath, part.InlineData.Data, 0644)
	if err != nil {
		log.Printf("Failed to write image to local file '%s': %v", localPath, err)
		return saveImageResult{Status: "fail"}
	}

	log.Printf("Successfully saved image to %s", localPath)
	return saveImageResult{Status: "success"}
}

func main() {
	ctx := context.Background()

	model, err := gemini.NewModel(ctx, "gemini-2.0-flash-001", &genai.ClientConfig{})
	if err != nil {
		log.Fatalf("Failed to create model: %v", err)
	}

	generateImageTool, err := tool.NewFunctionTool(
		tool.FunctionToolConfig{
			Name:        "generate_image",
			Description: "Generates image and saves in artifact service.",
		},
		generateImage)
	if err != nil {
		log.Fatalf("Failed to create generate image tool: %v", err)
	}

	saveImageTool, err := tool.NewFunctionTool(
		tool.FunctionToolConfig{
			Name:        "save_image_locally",
			Description: "Saves images locally based on the filename.",
		},
		saveImage)
	if err != nil {
		log.Fatalf("Failed to create generate image tool: %v", err)
	}

	agent, err := llmagent.New(llmagent.Config{
		Name:        "image_generator",

Review comment (suggestion):
Same like generateImage - documentation. (this is `save_image_locally` tool, right?)

Personally, I find it's easier to start with `main` and then move the called functions definitions after that. (top-down approach)...

Code after:
	}

	if err := ctx.Artifacts().Save(input.Filename, *genai.NewPartFromBytes(response.GeneratedImages[0].Image.ImageBytes, "image/png")); err != nil {
		return generateImageResult{
			Status: "fail",
		}
	}
	return generateImageResult{
		Status:   "success",
		Filename: input.Filename,
	}
}

type generateImageInput struct {
	Prompt   string `json:"prompt"`
	Filename string `json:"filename"`
}

type generateImageResult struct {
	Filename string `json:"filename"`
	Status   string `json:"Status"`
}

// This is function tool that loads image from the artifacts service and
// saves is to the local filesystem.
func saveImage(ctx tool.Context, input saveImageInput) saveImageResult {
	filename := input.Filename
	part, err := ctx.Artifacts().Load(filename)
	if err != nil {
		log.Printf("Failed to load artifact '%s': %v", filename, err)
		return saveImageResult{Status: "fail"}
	}

	if part.InlineData == nil || len(part.InlineData.Data) == 0 {
		log.Printf("Artifact '%s' has no inline data", filename)
		return saveImageResult{Status: "fail"}
	}

	// Ensure the filename has a .png extension for the local file.
	localFilename := filename
	if filepath.Ext(localFilename) != ".png" {
		localFilename += ".png"
	}

	// Create an "output" directory in the current working directory if it doesn't exist.
	outputDir := "output"
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		log.Printf("Failed to create output directory '%s': %v", outputDir, err)
		return saveImageResult{Status: "fail"}
	}