mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-05 19:30:48 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c5d629ef25 |
+3
-2
@@ -183,11 +183,12 @@ AZUREAD_TENANT_ID=
|
||||
# Configure Formbricks AI at the instance level
|
||||
# Set the provider used for AI features on this instance.
|
||||
# Accepted values for AI_PROVIDER: aws, google, azure
|
||||
# Set AI_MODEL to the provider-specific model or deployment name and configure the matching credentials below.
|
||||
# Set AI_MODEL to the provider-specific model or deployment name and configure the matching provider settings below.
|
||||
# AI_PROVIDER=google
|
||||
# AI_MODEL=gemini-2.5-flash
|
||||
|
||||
# Google Cloud credentials for Gemini models
|
||||
# Google Cloud settings for Gemini models
|
||||
# Credentials are optional when Application Default Credentials are available.
|
||||
# AI_GOOGLE_CLOUD_PROJECT=
|
||||
# AI_GOOGLE_CLOUD_LOCATION=
|
||||
# AI_GOOGLE_CLOUD_CREDENTIALS_JSON=
|
||||
|
||||
@@ -79,6 +79,35 @@ describe("env", () => {
|
||||
expect(env.DEBUG_SHOW_RESET_LINK).toBe("1");
|
||||
});
|
||||
|
||||
test("allows Google Cloud AI configuration to rely on ADC credentials", async () => {
|
||||
setTestEnv({
|
||||
AI_PROVIDER: "google",
|
||||
AI_MODEL: "gemini-2.5-flash",
|
||||
AI_GOOGLE_CLOUD_PROJECT: "test-project",
|
||||
AI_GOOGLE_CLOUD_LOCATION: "us-central1",
|
||||
AI_GOOGLE_CLOUD_CREDENTIALS_JSON: undefined,
|
||||
AI_GOOGLE_CLOUD_APPLICATION_CREDENTIALS: undefined,
|
||||
});
|
||||
|
||||
const { env } = await import("./env");
|
||||
|
||||
expect(env.AI_PROVIDER).toBe("google");
|
||||
expect(env.AI_GOOGLE_CLOUD_PROJECT).toBe("test-project");
|
||||
expect(env.AI_GOOGLE_CLOUD_LOCATION).toBe("us-central1");
|
||||
});
|
||||
|
||||
test("fails to load when Google Cloud credentials JSON is invalid", async () => {
|
||||
setTestEnv({
|
||||
AI_PROVIDER: "google",
|
||||
AI_MODEL: "gemini-2.5-flash",
|
||||
AI_GOOGLE_CLOUD_PROJECT: "test-project",
|
||||
AI_GOOGLE_CLOUD_LOCATION: "us-central1",
|
||||
AI_GOOGLE_CLOUD_CREDENTIALS_JSON: "{not-json}",
|
||||
});
|
||||
|
||||
await expect(import("./env")).rejects.toThrow("AI_GOOGLE_CLOUD_CREDENTIALS_JSON");
|
||||
});
|
||||
|
||||
test("uses the configured Cube environment variables", async () => {
|
||||
setTestEnv();
|
||||
const { env } = await import("./env");
|
||||
|
||||
@@ -68,14 +68,6 @@ const validateGoogleAIConfiguration = (values: TAIConfigurationEnv, ctx: z.Refin
|
||||
);
|
||||
}
|
||||
|
||||
if (!values.AI_GOOGLE_CLOUD_CREDENTIALS_JSON && !values.AI_GOOGLE_CLOUD_APPLICATION_CREDENTIALS) {
|
||||
addEnvIssue(
|
||||
ctx,
|
||||
"AI_GOOGLE_CLOUD_CREDENTIALS_JSON",
|
||||
"AI_GOOGLE_CLOUD_CREDENTIALS_JSON or AI_GOOGLE_CLOUD_APPLICATION_CREDENTIALS is required when AI_PROVIDER=google"
|
||||
);
|
||||
}
|
||||
|
||||
if (values.AI_GOOGLE_CLOUD_CREDENTIALS_JSON) {
|
||||
try {
|
||||
const parsedCredentials = JSON.parse(values.AI_GOOGLE_CLOUD_CREDENTIALS_JSON) as unknown;
|
||||
|
||||
@@ -83,6 +83,30 @@ describe("packages/ai provider helpers", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("reports a fully configured Google Cloud instance when ADC provides credentials", () => {
|
||||
expect(
|
||||
getAiConfigurationStatus({
|
||||
AI_PROVIDER: "google",
|
||||
AI_MODEL: "gemini-2.5-flash",
|
||||
AI_GOOGLE_CLOUD_PROJECT: "test-project",
|
||||
AI_GOOGLE_CLOUD_LOCATION: "us-central1",
|
||||
})
|
||||
).toEqual({
|
||||
provider: "google",
|
||||
model: "gemini-2.5-flash",
|
||||
isConfigured: true,
|
||||
missingFields: [],
|
||||
invalidFields: [],
|
||||
providerStatus: {
|
||||
provider: "google",
|
||||
model: "gemini-2.5-flash",
|
||||
isConfigured: true,
|
||||
missingFields: [],
|
||||
invalidFields: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("treats the instance as not configured when AI_PROVIDER is missing", () => {
|
||||
expect(
|
||||
isAiConfigured({
|
||||
@@ -207,6 +231,48 @@ describe("packages/ai provider helpers", () => {
|
||||
expect(mocks.createVertex).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("creates a Google Cloud model with application credentials file", () => {
|
||||
const vertexProvider = createMockProvider("google");
|
||||
mocks.createVertex.mockReturnValue(vertexProvider);
|
||||
|
||||
const model = getAiModel({
|
||||
AI_PROVIDER: "google",
|
||||
AI_MODEL: "gemini-2.5-flash",
|
||||
AI_GOOGLE_CLOUD_PROJECT: "test-project",
|
||||
AI_GOOGLE_CLOUD_LOCATION: "us-central1",
|
||||
AI_GOOGLE_CLOUD_APPLICATION_CREDENTIALS: "/tmp/google-cloud.json",
|
||||
});
|
||||
|
||||
expect(model).toEqual({ providerName: "google", modelName: "gemini-2.5-flash" });
|
||||
expect(mocks.createVertex).toHaveBeenCalledWith({
|
||||
project: "test-project",
|
||||
location: "us-central1",
|
||||
googleAuthOptions: {
|
||||
keyFilename: "/tmp/google-cloud.json",
|
||||
},
|
||||
});
|
||||
expect(vertexProvider).toHaveBeenCalledWith("gemini-2.5-flash");
|
||||
});
|
||||
|
||||
test("creates a Google Cloud model using ADC when no credential override is configured", () => {
|
||||
const vertexProvider = createMockProvider("google");
|
||||
mocks.createVertex.mockReturnValue(vertexProvider);
|
||||
|
||||
const model = getAiModel({
|
||||
AI_PROVIDER: "google",
|
||||
AI_MODEL: "gemini-2.5-flash",
|
||||
AI_GOOGLE_CLOUD_PROJECT: "test-project",
|
||||
AI_GOOGLE_CLOUD_LOCATION: "us-central1",
|
||||
});
|
||||
|
||||
expect(model).toEqual({ providerName: "google", modelName: "gemini-2.5-flash" });
|
||||
expect(mocks.createVertex).toHaveBeenCalledWith({
|
||||
project: "test-project",
|
||||
location: "us-central1",
|
||||
});
|
||||
expect(vertexProvider).toHaveBeenCalledWith("gemini-2.5-flash");
|
||||
});
|
||||
|
||||
test("creates an AWS model with explicit AWS credentials", () => {
|
||||
const bedrockProvider = createMockProvider("aws");
|
||||
mocks.createAmazonBedrock.mockReturnValue(bedrockProvider);
|
||||
|
||||
@@ -39,11 +39,6 @@ export const googleProviderAdapter: AIProviderAdapter = {
|
||||
}
|
||||
|
||||
const credentialsJson = normalizeValue(environment.AI_GOOGLE_CLOUD_CREDENTIALS_JSON);
|
||||
const applicationCredentials = normalizeValue(environment.AI_GOOGLE_CLOUD_APPLICATION_CREDENTIALS);
|
||||
|
||||
if (!credentialsJson && !applicationCredentials) {
|
||||
missingFields.push("AI_GOOGLE_CLOUD_CREDENTIALS_JSON or AI_GOOGLE_CLOUD_APPLICATION_CREDENTIALS");
|
||||
}
|
||||
|
||||
if (credentialsJson) {
|
||||
try {
|
||||
@@ -73,15 +68,12 @@ export const googleProviderAdapter: AIProviderAdapter = {
|
||||
const credentialsJson = normalizeValue(environment.AI_GOOGLE_CLOUD_CREDENTIALS_JSON);
|
||||
const applicationCredentials = normalizeValue(environment.AI_GOOGLE_CLOUD_APPLICATION_CREDENTIALS);
|
||||
|
||||
if (!project || !location || (!credentialsJson && !applicationCredentials)) {
|
||||
throw new AIConfigurationError("providerNotConfigured", "Google Cloud AI credentials are incomplete", {
|
||||
if (!project || !location) {
|
||||
throw new AIConfigurationError("providerNotConfigured", "Google Cloud AI configuration is incomplete", {
|
||||
provider: "google",
|
||||
missingFields: [
|
||||
...(!project ? ["AI_GOOGLE_CLOUD_PROJECT"] : []),
|
||||
...(!location ? ["AI_GOOGLE_CLOUD_LOCATION"] : []),
|
||||
...(!credentialsJson && !applicationCredentials
|
||||
? ["AI_GOOGLE_CLOUD_CREDENTIALS_JSON or AI_GOOGLE_CLOUD_APPLICATION_CREDENTIALS"]
|
||||
: []),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user