# ai-gateway `ai-gateway` is an internal gRPC service that turns free-form text into home assistant actions. It asks Ollama to produce a structured intent, resolves that intent against known Home Assistant lights, and calls `ha-gateway` for any approved action. ## Runtime Flow 1. The service loads `.env`, configures logging and telemetry, and starts gRPC on `GRPC_PORT`. 2. `AIService.Query` receives prompt text and an optional model name. 3. The app refreshes or reads the light cache from `ha-gateway`. 4. Ollama receives a prompt containing the user text and known lights. 5. The app parses the model output as JSON intent data. 6. Supported intents are executed through `ha-gateway`; unsupported or invalid responses return a plain explanation without taking action. ## gRPC API Defined in [proto/ai/v1/ai.proto](https://gitea.nik4nao.com/nik/home-services/src/branch/main/proto/ai/v1/ai.proto). - `AIService.Query`: sends text to the AI command flow - `AIService.ListModels`: returns model names reported by Ollama Supported action intents currently focus on lights: - turn on a light - turn off a light - list known lights - no-op / unknown intent ## Configuration Environment variables: | Variable | Default | Description | | --- | --- | --- | | `GRPC_PORT` | `50052` | gRPC listen port | | `OLLAMA_URL` | `http://192.168.7.96:11434` | Ollama base URL | | `OLLAMA_MODEL` | `llama3` | Default model for queries without an explicit model | | `OLLAMA_TIMEOUT` | `120s` | HTTP timeout for Ollama calls | | `HA_GATEWAY_ADDR` | `ha-gateway.home-services.svc.cluster.local:50051` | gRPC address for `ha-gateway` | | `HA_GATEWAY_SERVER_NAME` | `ha-gateway.home-services.svc.cluster.local` | Expected server name for TLS | | `TLS_DIR` | empty | Enables mTLS for the server and gateway client when set | | `OTEL_ENDPOINT` | empty | OTLP gRPC collector endpoint; empty disables telemetry | | `LOG_LEVEL` | `info` | `debug`, `info`, `warn`, or `error` | | `LOG_FORMAT` | `json` | `json` or `text` | | `LIGHT_CACHE_TTL` | `60s` | Light discovery cache lifetime | Example env file: [.env.example](https://gitea.nik4nao.com/nik/home-services/src/branch/main/ai-gateway/.env.example) When `TLS_DIR` is set, the directory must contain `tls.crt`, `tls.key`, and `ca.crt`. ## Local Run Start `ha-gateway` first, then run: ```bash cp .env.example .env go run ./cmd/gateway ``` Run from `ai-gateway/` so `godotenv` loads `ai-gateway/.env`. For local plaintext development: ```text HA_GATEWAY_ADDR=localhost:50051 TLS_DIR= ``` ## Smoke Checks ```bash grpcurl -plaintext -d '{"text":"list the lights","source":"local"}' \ localhost:50052 ai.v1.AIService/Query grpcurl -plaintext -d '{}' localhost:50052 ai.v1.AIService/ListModels ``` Reflection is only registered when `LOG_LEVEL=debug`; otherwise call by using the compiled proto descriptors or generated clients. ## Test And Build ```bash go test ./... go build ./... ``` Build the container image from the workspace root: ```bash docker build -f ai-gateway/Dockerfile -t ai-gateway:dev . ``` Optionally pass a build version: ```bash docker build -f ai-gateway/Dockerfile --build-arg VERSION=$(git rev-parse --short HEAD) -t ai-gateway:dev . ``` ## Package Map ```text cmd/gateway/ # process entrypoint and wiring internal/adapters/primary/grpc/ # AIService gRPC server internal/adapters/secondary/ollama/ # Ollama HTTP client internal/adapters/secondary/hagateway/ # ha-gateway gRPC client internal/app/ # query orchestration and intent dispatch internal/config/ # environment loading internal/core/domain/ # prompt, intent, and cache types internal/core/ports/driven/ # app-facing LLM and HA interfaces internal/logger/ # slog setup internal/telemetry/ # OpenTelemetry setup ``` ## Limitations - Intent parsing depends on the selected model returning valid JSON. - Light actions are supported; broader Home Assistant domains are not wired yet. - The light cache is per-process memory and refreshes by TTL. - Keep this service internal or protect it with mTLS; it does not implement separate app-layer authorization.