Merge pull request #1302 from dinhkarate/feat(vertex)/add-prefix-field

Feat(vertex): add prefix field
This commit is contained in:
Luis Pater
2026-04-04 04:17:12 +08:00
committed by GitHub
4 changed files with 31 additions and 3 deletions

6
.gitignore vendored
View File

@@ -49,3 +49,9 @@ _bmad-output/*
# macOS # macOS
.DS_Store .DS_Store
._* ._*
# Opencode
.beads/
.opencode/
.cli-proxy-api/
.venv/

View File

@@ -70,6 +70,7 @@ func main() {
var kimiLogin bool var kimiLogin bool
var projectID string var projectID string
var vertexImport string var vertexImport string
var vertexImportPrefix string
var configPath string var configPath string
var password string var password string
var tuiMode bool var tuiMode bool
@@ -91,6 +92,7 @@ func main() {
flag.StringVar(&projectID, "project_id", "", "Project ID (Gemini only, not required)") flag.StringVar(&projectID, "project_id", "", "Project ID (Gemini only, not required)")
flag.StringVar(&configPath, "config", DefaultConfigPath, "Configure File Path") flag.StringVar(&configPath, "config", DefaultConfigPath, "Configure File Path")
flag.StringVar(&vertexImport, "vertex-import", "", "Import Vertex service account key JSON file") flag.StringVar(&vertexImport, "vertex-import", "", "Import Vertex service account key JSON file")
flag.StringVar(&vertexImportPrefix, "vertex-import-prefix", "", "Prefix for Vertex model namespacing (use with -vertex-import)")
flag.StringVar(&password, "password", "", "") flag.StringVar(&password, "password", "", "")
flag.BoolVar(&tuiMode, "tui", false, "Start with terminal management UI") flag.BoolVar(&tuiMode, "tui", false, "Start with terminal management UI")
flag.BoolVar(&standalone, "standalone", false, "In TUI mode, start an embedded local server") flag.BoolVar(&standalone, "standalone", false, "In TUI mode, start an embedded local server")
@@ -462,7 +464,7 @@ func main() {
if vertexImport != "" { if vertexImport != "" {
// Handle Vertex service account import // Handle Vertex service account import
cmd.DoVertexImport(cfg, vertexImport) cmd.DoVertexImport(cfg, vertexImport, vertexImportPrefix)
} else if login { } else if login {
// Handle Google/Gemini login // Handle Google/Gemini login
cmd.DoLogin(cfg, projectID, options) cmd.DoLogin(cfg, projectID, options)

View File

@@ -30,6 +30,10 @@ type VertexCredentialStorage struct {
// Type is the provider identifier stored alongside credentials. Always "vertex". // Type is the provider identifier stored alongside credentials. Always "vertex".
Type string `json:"type"` Type string `json:"type"`
// Prefix optionally namespaces models for this credential (e.g., "teamA").
// This results in model names like "teamA/gemini-2.0-flash".
Prefix string `json:"prefix,omitempty"`
} }
// SaveTokenToFile writes the credential payload to the given file path in JSON format. // SaveTokenToFile writes the credential payload to the given file path in JSON format.

View File

@@ -20,7 +20,7 @@ import (
// DoVertexImport imports a Google Cloud service account key JSON and persists // DoVertexImport imports a Google Cloud service account key JSON and persists
// it as a "vertex" provider credential. The file content is embedded in the auth // it as a "vertex" provider credential. The file content is embedded in the auth
// file to allow portable deployment across stores. // file to allow portable deployment across stores.
func DoVertexImport(cfg *config.Config, keyPath string) { func DoVertexImport(cfg *config.Config, keyPath string, prefix string) {
if cfg == nil { if cfg == nil {
cfg = &config.Config{} cfg = &config.Config{}
} }
@@ -62,13 +62,28 @@ func DoVertexImport(cfg *config.Config, keyPath string) {
// Default location if not provided by user. Can be edited in the saved file later. // Default location if not provided by user. Can be edited in the saved file later.
location := "us-central1" location := "us-central1"
fileName := fmt.Sprintf("vertex-%s.json", sanitizeFilePart(projectID)) // Normalize and validate prefix: must be a single segment (no "/" allowed).
prefix = strings.TrimSpace(prefix)
prefix = strings.Trim(prefix, "/")
if prefix != "" && strings.Contains(prefix, "/") {
log.Errorf("vertex-import: prefix must be a single segment (no '/' allowed): %q", prefix)
return
}
// Include prefix in filename so importing the same project with different
// prefixes creates separate credential files instead of overwriting.
baseName := sanitizeFilePart(projectID)
if prefix != "" {
baseName = sanitizeFilePart(prefix) + "-" + baseName
}
fileName := fmt.Sprintf("vertex-%s.json", baseName)
// Build auth record // Build auth record
storage := &vertex.VertexCredentialStorage{ storage := &vertex.VertexCredentialStorage{
ServiceAccount: sa, ServiceAccount: sa,
ProjectID: projectID, ProjectID: projectID,
Email: email, Email: email,
Location: location, Location: location,
Prefix: prefix,
} }
metadata := map[string]any{ metadata := map[string]any{
"service_account": sa, "service_account": sa,
@@ -76,6 +91,7 @@ func DoVertexImport(cfg *config.Config, keyPath string) {
"email": email, "email": email,
"location": location, "location": location,
"type": "vertex", "type": "vertex",
"prefix": prefix,
"label": labelForVertex(projectID, email), "label": labelForVertex(projectID, email),
} }
record := &coreauth.Auth{ record := &coreauth.Auth{