Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,11 @@ MONGO_ALLOW_LOCAL_FALLBACK=0
# Google Gemini API Key
# Get yours at: https://ai.google.dev
# Primary variable: GEMINI_API_KEY
# Managed hosts may set GEMINI_API_KEY_FILE to a root-owned secret file instead.
# Legacy alias still accepted for compatibility: GOOGLE_API_KEY
# GEMINI_API_KEY=<YOUR-GEMINI-KEY-HERE>
# GEMINI_API_KEY_FILE=/etc/von/secrets/gemini_api_key
# VON_DEFAULT_GEMINI_MODEL=gemini-3.7-flash

# ============================================================================
# WEB SEARCH (Optional)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/openstack-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.6.6"
terraform_version: "1.9.8"

- name: Lint Gate (Terraform fmt + shell syntax)
shell: bash
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,12 @@ Visit `http://localhost:5000` and explore the pre-loaded concepts in the interfa

**Google Gemini:**
1. Get your own API key from https://ai.google.dev
2. Set `GEMINI_API_KEY` in `.env`
3. Select Gemini model in Von's Settings panel
2. Set `GEMINI_API_KEY` in `.env` (or `GEMINI_API_KEY_FILE` on a managed host)
3. Select `gemini-3.7-flash` as the premium Gemini model in Von's Settings panel

Von still accepts the legacy `GOOGLE_API_KEY` name for compatibility, but new
setups should use `GEMINI_API_KEY`.
setups should use `GEMINI_API_KEY`. Gemini 3.7 uses a stateless Interactions API
profile in Von; provider response storage is disabled.

### 5. **UI Feature Flags**

Expand Down
8 changes: 7 additions & 1 deletion docs/engineering/environment_minimums.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ $env:OLLAMA_HOST = 'http://<host>:11434'

`GEMINI_API_KEY` is the primary Gemini variable. Von also accepts the legacy
`GOOGLE_API_KEY` name for compatibility, but new setups should use
`GEMINI_API_KEY`.
`GEMINI_API_KEY`. Managed deployments can instead set
`GEMINI_API_KEY_FILE=/etc/von/secrets/gemini_api_key`; the file should be
readable only by the Von service account. The default Gemini model is
`gemini-3.7-flash` (overridable with `VON_DEFAULT_GEMINI_MODEL`). The tracked
Gemini 3.7 premium-profile release input selects the stateless Interactions API
with response storage disabled; it takes effect only after governed registry
publication and canonical read-back.

## 2. How Von decides whether MongoDB is local or remote

Expand Down
9 changes: 9 additions & 0 deletions docs/engineering/openstack_deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ $env:TF_VAR_bootstrap_google_oauth_client_id = '<YOUR-CLIENT-ID-HERE>'
$env:TF_VAR_bootstrap_google_oauth_client_secret = '<YOUR-CLIENT-SECRET-HERE>'
$env:TF_VAR_bootstrap_mongo_uri = '<YOUR-MONGODB-URI-HERE>'
$env:TF_VAR_bootstrap_openai_api_key = '<YOUR-OPENAI-KEY-HERE>'
# or, for Gemini
$env:TF_VAR_bootstrap_gemini_api_key = '<YOUR-GEMINI-KEY-HERE>'
```

Set OpenStack auth profile (example):
Expand Down Expand Up @@ -152,6 +154,13 @@ $env:TF_VAR_bootstrap_default_llm_model = 'gpt-5.5'
$env:TF_VAR_bootstrap_default_llm_organisation_concept_id = '#V#university_of_auckland_strong_ai_lab'
```

For Gemini 3.7 Flash, use the corresponding provider/model seed values:

```powershell
$env:TF_VAR_bootstrap_default_llm_provider = 'gemini'
$env:TF_VAR_bootstrap_default_llm_model = 'gemini-3.7-flash'
```

After deployment, check:

```bash
Expand Down
2 changes: 1 addition & 1 deletion docs/engineering/workflow_model_policy_schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ environment variables (see `src/backend/languagemodels/model_defaults.py`):
|---|---|
| `VON_DEFAULT_OLLAMA_MODEL` | `gemma4:26b` |
| `VON_DEFAULT_OPENAI_MODEL` | `gpt-5.5` |
| `VON_DEFAULT_GEMINI_MODEL` | `gemini-2.0-flash` |
| `VON_DEFAULT_GEMINI_MODEL` | `gemini-3.7-flash` |

When writing policy JSON, prefer `active_llm` for stages that should follow
the user's primary model selection, and use explicit `provider:model` strings
Expand Down
7 changes: 5 additions & 2 deletions infra/openstack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ bootstrap assets from `templates/` to configure a runnable Von host:

## Prerequisites

- Terraform `>= 1.5.0`.
- Terraform `>= 1.9.0`.
- OpenStack credentials available at runtime via:
- `OS_CLOUD` + `clouds.yaml`, or
- direct `OS_*` environment variables.
Expand Down Expand Up @@ -189,14 +189,17 @@ needed for real chat/workflow execution:
- `bootstrap_openai_api_key_file` defaults to `/etc/von/secrets/openai_api_key`.
- OpenAI keys can be injected with `TF_VAR_bootstrap_openai_api_key` or by
pre-provisioning `bootstrap_openai_api_key_file` on host.
- `bootstrap_gemini_api_key_file` defaults to
`/etc/von/secrets/gemini_api_key`. Gemini keys can be injected with
`TF_VAR_bootstrap_gemini_api_key` or pre-provisioned at that path.
- `bootstrap_default_llm_provider`, `bootstrap_default_llm_model`, and either
`bootstrap_default_llm_organisation_concept_id` or
`bootstrap_default_llm_user_concept_id` can seed the scoped LLM setting after
first deploy using Von's settings service.

Do not assign `bootstrap_openai_api_key = null` in local tfvars when using
`TF_VAR_bootstrap_openai_api_key`; tfvars values override runtime environment
variables.
variables. The same rule applies to `bootstrap_gemini_api_key`.

Operational note:

Expand Down
4 changes: 4 additions & 0 deletions infra/openstack/environments/dev/dev.tfvars.example
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,15 @@ bootstrap_google_oauth_enable_dynamic_redirects = false
# Setting it to null here prevents runtime injection from reaching cloud-init.
# bootstrap_openai_api_key = "REPLACE_WITH_LOCAL_UNTRACKED_SECRET"
bootstrap_openai_api_key_file = "/etc/von/secrets/openai_api_key"
# Leave bootstrap_gemini_api_key unset when using TF_VAR_bootstrap_gemini_api_key.
# bootstrap_gemini_api_key = "REPLACE_WITH_LOCAL_UNTRACKED_SECRET"
bootstrap_gemini_api_key_file = "/etc/von/secrets/gemini_api_key"

# Optional: seed a scoped model setting after first deploy.
# Set all three values together to seed the organisation default.
# bootstrap_default_llm_provider = "openai"
# bootstrap_default_llm_model = "gpt-5.5"
# Gemini alternative: provider = "gemini", model = "gemini-3.7-flash".
# bootstrap_default_llm_organisation_concept_id = "#V#university_of_auckland_strong_ai_lab"

# Mongo Atlas hardening (dev can remain non-strict while preserving TLS defaults).
Expand Down
4 changes: 4 additions & 0 deletions infra/openstack/environments/prod/prod.tfvars.example
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,15 @@ bootstrap_google_oauth_enable_dynamic_redirects = false
# Setting it to null here prevents runtime injection from reaching cloud-init.
# bootstrap_openai_api_key = "REPLACE_WITH_LOCAL_UNTRACKED_SECRET"
bootstrap_openai_api_key_file = "/etc/von/secrets/openai_api_key"
# Leave bootstrap_gemini_api_key unset when using TF_VAR_bootstrap_gemini_api_key.
# bootstrap_gemini_api_key = "REPLACE_WITH_LOCAL_UNTRACKED_SECRET"
bootstrap_gemini_api_key_file = "/etc/von/secrets/gemini_api_key"

# Optional: seed a scoped model setting after first deploy.
# Set all three values together to seed the organisation default.
# bootstrap_default_llm_provider = "openai"
# bootstrap_default_llm_model = "gpt-5.5"
# Gemini alternative: provider = "gemini", model = "gemini-3.7-flash".
# bootstrap_default_llm_organisation_concept_id = "#V#university_of_auckland_strong_ai_lab"

# Mongo Atlas hardening for hosted production.
Expand Down
4 changes: 4 additions & 0 deletions infra/openstack/environments/staging/staging.tfvars.example
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,15 @@ bootstrap_google_oauth_enable_dynamic_redirects = false
# Setting it to null here prevents runtime injection from reaching cloud-init.
# bootstrap_openai_api_key = "REPLACE_WITH_LOCAL_UNTRACKED_SECRET"
bootstrap_openai_api_key_file = "/etc/von/secrets/openai_api_key"
# Leave bootstrap_gemini_api_key unset when using TF_VAR_bootstrap_gemini_api_key.
# bootstrap_gemini_api_key = "REPLACE_WITH_LOCAL_UNTRACKED_SECRET"
bootstrap_gemini_api_key_file = "/etc/von/secrets/gemini_api_key"

# Optional: seed a scoped model setting after first deploy.
# Set all three values together to seed the organisation default.
# bootstrap_default_llm_provider = "openai"
# bootstrap_default_llm_model = "gpt-5.5"
# Gemini alternative: provider = "gemini", model = "gemini-3.7-flash".
# bootstrap_default_llm_organisation_concept_id = "#V#university_of_auckland_strong_ai_lab"

# Mongo Atlas hardening for hosted staging.
Expand Down
2 changes: 2 additions & 0 deletions infra/openstack/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ locals {
google_oauth_enable_dynamic_redirects = var.bootstrap_google_oauth_enable_dynamic_redirects
openai_api_key = var.bootstrap_openai_api_key
openai_api_key_file = var.bootstrap_openai_api_key_file
gemini_api_key = var.bootstrap_gemini_api_key
gemini_api_key_file = var.bootstrap_gemini_api_key_file
default_llm_provider = var.bootstrap_default_llm_provider
default_llm_model = var.bootstrap_default_llm_model
default_llm_organisation_concept_id = var.bootstrap_default_llm_organisation_concept_id
Expand Down
14 changes: 13 additions & 1 deletion infra/openstack/templates/cloud-init/von_bootstrap.yaml.tftpl
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,12 @@ write_files:
GOOGLE_OAUTH_STRICT_STARTUP=${google_oauth_strict_startup ? 1 : 0}
GOOGLE_OAUTH_ENABLE_DYNAMIC_REDIRECTS=${google_oauth_enable_dynamic_redirects ? "true" : "false"}
OPENAI_API_KEY_FILE=${openai_api_key_file}
GEMINI_API_KEY_FILE=${gemini_api_key_file}
%{ if default_llm_provider != null && lower(default_llm_provider) == "openai" && default_llm_model != null ~}
VON_DEFAULT_OPENAI_MODEL=${jsonencode(default_llm_model)}
%{ endif ~}
%{ if default_llm_provider != null && lower(default_llm_provider) == "gemini" && default_llm_model != null ~}
VON_DEFAULT_GEMINI_MODEL=${jsonencode(default_llm_model)}
%{ endif ~}
VON_MONGO_STRICT_STARTUP=${mongo_strict_startup ? 1 : 0}
VON_MONGO_STARTUP_PROBE=${mongo_startup_probe ? 1 : 0}
Expand Down Expand Up @@ -86,6 +90,14 @@ write_files:
${openai_api_key}
%{ endif ~}

%{ if gemini_api_key != null ~}
- path: ${gemini_api_key_file}
owner: root:root
permissions: "0600"
content: |
${gemini_api_key}
%{ endif ~}

%{ if mongo_uri != null ~}
- path: ${mongo_uri_file}
owner: root:root
Expand Down Expand Up @@ -195,7 +207,7 @@ runcmd:
- [bash, -lc, "set -euo pipefail; install -d -m 0755 -o root -g root '${backup_directory}' '${central_log_directory}'"]
- [bash, -lc, "set -euo pipefail; install -d -m 0755 -o root -g root /etc/von"]
- [bash, -lc, "set -euo pipefail; install -d -m 0750 -o root -g ${service_group} /etc/von/secrets"]
- [bash, -lc, "set -euo pipefail; for secret_file in '${google_oauth_client_id_file}' '${google_oauth_client_secret_file}' '${openai_api_key_file}' '${mongo_uri_file}'; do if [ -f \"$secret_file\" ]; then chown root:${service_group} \"$secret_file\"; chmod 0640 \"$secret_file\"; fi; done"]
- [bash, -lc, "set -euo pipefail; for secret_file in '${google_oauth_client_id_file}' '${google_oauth_client_secret_file}' '${openai_api_key_file}' '${gemini_api_key_file}' '${mongo_uri_file}'; do if [ -f \"$secret_file\" ]; then chown root:${service_group} \"$secret_file\"; chmod 0640 \"$secret_file\"; fi; done"]
%{ if enable_https && generate_self_signed_cert ~}
- [bash, -lc, "set -euo pipefail; if [ ! -f '${tls_cert_path}' ] || [ ! -f '${tls_key_path}' ]; then install -d -m 0755 /etc/ssl/certs /etc/ssl/private; openssl req -x509 -nodes -newkey rsa:4096 -days 365 -subj '/CN=${domain_name}' -keyout '${tls_key_path}' -out '${tls_cert_path}'; chmod 0600 '${tls_key_path}'; fi"]
%{ endif ~}
Expand Down
23 changes: 23 additions & 0 deletions infra/openstack/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,29 @@ variable "bootstrap_openai_api_key_file" {
}
}

variable "bootstrap_gemini_api_key" {
type = string
description = "Optional inline Gemini API key for managed bootstrap secret-file injection."
default = null
sensitive = true

validation {
condition = var.bootstrap_gemini_api_key == null || trimspace(var.bootstrap_gemini_api_key) != ""
error_message = "bootstrap_gemini_api_key must be null or non-empty."
}
}

variable "bootstrap_gemini_api_key_file" {
type = string
description = "Path used by runtime GEMINI_API_KEY_FILE."
default = "/etc/von/secrets/gemini_api_key"

validation {
condition = can(regex("^/", var.bootstrap_gemini_api_key_file))
error_message = "bootstrap_gemini_api_key_file must be an absolute Linux path."
}
}

variable "bootstrap_default_llm_provider" {
type = string
description = "Optional provider to seed as the scoped cloud default LLM setting."
Expand Down
2 changes: 1 addition & 1 deletion infra/openstack/versions.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
terraform {
required_version = ">= 1.5.0"
required_version = ">= 1.9.0"

required_providers {
openstack = {
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ dependencies = [
"uvicorn>=0.38.0",
"cryptography>=43.0.0",
"openstacksdk>=4.0.0",
"google-genai>=1.55.0",
"google-genai>=2.6.0",
"bleach>=6.3.0",
"pymupdf>=1.24.10",
"pytesseract>=0.3.13",
Expand Down
Loading
Loading