From 9f76f21b0a4624697d2efe0d1523f1c0df5d0b64 Mon Sep 17 00:00:00 2001 From: Jeremy Alvis Date: Fri, 13 Mar 2026 10:47:40 -0700 Subject: [PATCH 1/4] Remove SQLite and deploy Postgres by default Signed-off-by: Jeremy Alvis --- .github/workflows/ci.yaml | 23 --- DEVELOPMENT.md | 32 +--- Makefile | 2 - contrib/addons/postgres.yaml | 73 --------- design/drop-sqlite.md | 155 ++++++++++++++++++ .../reconciler/mcp_server_reconciler_test.go | 14 +- go/core/internal/database/client.go | 67 ++------ go/core/internal/database/client_test.go | 71 +++----- go/core/internal/database/manager.go | 96 ++--------- go/core/internal/database/testhelpers_test.go | 39 +++++ go/core/internal/dbtest/dbtest.go | 60 +++++++ go/core/pkg/app/app.go | 13 +- go/core/pkg/app/app_test.go | 4 - go/go.mod | 48 ++++-- go/go.sum | 149 ++++++++++++++--- helm/kagent/templates/_helpers.tpl | 17 +- .../templates/controller-configmap.yaml | 12 +- .../templates/controller-deployment.yaml | 19 +-- helm/kagent/templates/postgresql.yaml | 90 ++++++++++ .../tests/controller-deployment_test.yaml | 36 +--- helm/kagent/values.yaml | 24 ++- 21 files changed, 615 insertions(+), 429 deletions(-) delete mode 100644 contrib/addons/postgres.yaml create mode 100644 design/drop-sqlite.md create mode 100644 go/core/internal/database/testhelpers_test.go create mode 100644 go/core/internal/dbtest/dbtest.go create mode 100644 helm/kagent/templates/postgresql.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fa2018637..b9c6dc969 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -34,27 +34,9 @@ jobs: test-e2e: needs: - setup - strategy: - fail-fast: false - matrix: - database: [sqlite, postgres] env: VERSION: v0.0.1-test runs-on: ubuntu-latest - services: - postgres: - image: pgvector/pgvector:pg18-trixie - env: - POSTGRES_DB: kagent - POSTGRES_USER: postgres - POSTGRES_PASSWORD: kagent - ports: - - 5432:5432 - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 steps: - name: Checkout repository uses: actions/checkout@v4 @@ -99,11 +81,6 @@ jobs: run: | make create-kind-cluster echo "Cache key: ${{ needs.setup.outputs.cache-key }}" - if [ "${{ matrix.database }}" = "postgres" ]; then - HOST_IP=$(docker network inspect kind -f '{{range .IPAM.Config}}{{if .Gateway}}{{.Gateway}}{{"\n"}}{{end}}{{end}}' | grep -E '^[0-9]+\.' | head -1) - export KAGENT_HELM_EXTRA_ARGS="$KAGENT_HELM_EXTRA_ARGS --set database.type=postgres --set database.postgres.url=postgres://postgres:kagent@${HOST_IP}:5432/kagent" - echo "Postgres URL: postgres://postgres:kagent@${HOST_IP}:5432/kagent" - fi make helm-install make push-test-agent push-test-skill kubectl wait --for=condition=Ready agents.kagent.dev -n kagent --all --timeout=60s || kubectl get po -n kagent -o wide ||: diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index c540fe739..b71b9981c 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -99,35 +99,21 @@ make kagent-addon-install This installs the following components into your cluster: -| Addon | Description | Namespace | -|----------------|-----------------------------------------------------|-----------| -| Istio | Service mesh (demo profile) | `istio-system` | -| Grafana | Dashboards and visualization | `kagent` | -| Prometheus | Metrics collection | `kagent` | -| Metrics Server | Kubernetes resource metrics | `kube-system` | -| Postgres | Relational database (for kagent controller storage) | `kagent` | - -#### Using Postgres as the Datastore - -By default, kagent uses a local SQLite database for data persistence. To use -postgres as the backing store instead, deploy kagent via: - -> **Warning:** -> The following example uses hardcoded Postgres credentials (`postgres:kagent`) for local development only. -> **Do not use these credentials in production environments.** -```shell -KAGENT_HELM_EXTRA_ARGS="--set database.type=postgres --set database.postgres.url=postgres://postgres:kagent@postgres.kagent.svc.cluster.local:5432/kagent" \ - make helm-install -``` +| Addon | Description | Namespace | +|----------------|--------------------------------------|----------------| +| Istio | Service mesh (demo profile) | `istio-system` | +| Grafana | Dashboards and visualization | `kagent` | +| Prometheus | Metrics collection | `kagent` | +| Metrics Server | Kubernetes resource metrics | `kube-system` | -Verify the connection by checking the controller logs: +PostgreSQL (with pgvector) is deployed automatically as part of `make helm-install` via the bundled Helm chart. The optional addons above provide observability components. + +Verify the database connection by checking the controller logs: ```shell kubectl logs -n kagent deployment/kagent-controller | grep -i postgres ``` -**To revert to SQLite:** Run `make helm-install` without the `KAGENT_HELM_EXTRA_ARGS` variable. - ### Troubleshooting ### buildx localhost access diff --git a/Makefile b/Makefile index b435dc56f..6a88d24db 100644 --- a/Makefile +++ b/Makefile @@ -420,12 +420,10 @@ kagent-addon-install: use-kind-cluster # to test the kagent addons - installing istio, grafana, prometheus, metrics-server istioctl install --set profile=demo -y kubectl apply --context kind-$(KIND_CLUSTER_NAME) -f contrib/addons/grafana.yaml - kubectl apply --context kind-$(KIND_CLUSTER_NAME) -f contrib/addons/postgres.yaml kubectl apply --context kind-$(KIND_CLUSTER_NAME) -f contrib/addons/prometheus.yaml kubectl apply --context kind-$(KIND_CLUSTER_NAME) -f contrib/addons/metrics-server.yaml # wait for pods to be ready kubectl wait --context kind-$(KIND_CLUSTER_NAME) --for=condition=Ready pod -l app.kubernetes.io/name=grafana -n kagent --timeout=60s - kubectl wait --context kind-$(KIND_CLUSTER_NAME) --for=condition=Ready pod -l app.kubernetes.io/name=postgres -n kagent --timeout=60s kubectl wait --context kind-$(KIND_CLUSTER_NAME) --for=condition=Ready pod -l app.kubernetes.io/name=prometheus -n kagent --timeout=60s .PHONY: open-dev-container diff --git a/contrib/addons/postgres.yaml b/contrib/addons/postgres.yaml deleted file mode 100644 index b3006d985..000000000 --- a/contrib/addons/postgres.yaml +++ /dev/null @@ -1,73 +0,0 @@ ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: postgres - namespace: kagent -data: - POSTGRES_DB: kagent - POSTGRES_USER: postgres - POSTGRES_PASSWORD: kagent ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: postgres - namespace: kagent -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 500Mi ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: postgres - namespace: kagent -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: postgres - template: - metadata: - labels: - app.kubernetes.io/name: postgres - spec: - containers: - - name: postgres - image: pgvector/pgvector:pg18-trixie - ports: - - containerPort: 5432 - envFrom: - - configMapRef: - name: postgres - volumeMounts: - - name: postgres-storage - mountPath: /var/lib/postgresql - resources: - requests: - memory: "256Mi" - cpu: "250m" - limits: - memory: "512Mi" - cpu: "500m" - volumes: - - name: postgres-storage - persistentVolumeClaim: - claimName: postgres ---- -apiVersion: v1 -kind: Service -metadata: - name: postgres - namespace: kagent -spec: - selector: - app.kubernetes.io/name: postgres - ports: - - port: 5432 - targetPort: 5432 - type: ClusterIP diff --git a/design/drop-sqlite.md b/design/drop-sqlite.md new file mode 100644 index 000000000..9e74d5918 --- /dev/null +++ b/design/drop-sqlite.md @@ -0,0 +1,155 @@ +--- +status: Implemented +created: 2026-03-12 +updated: 2026-03-13 +authors: + - Jeremy Alvis + - Claude (Design Partner) +--- +# Drop SQLite — Postgres-Only Database + +## Overview + +Kagent currently supports two database backends: SQLite (the default) and PostgreSQL. This doc covers removing SQLite entirely so that PostgreSQL is the only supported backend, for both production deployments and local Kind clusters. + +This is in preparation for replacing GORM with explicit SQL migrations and sqlc. The two efforts are independent and can be sequenced in either order, but removing SQLite first simplifies the ORM migration by eliminating the need for per-dialect SQL files and a second sqlc configuration. + +## Goals and Non-Goals + +### Goals + +- PostgreSQL is the only supported database backend +- Local Kind cluster development (`make helm-install`) deploys a bundled PostgreSQL instance automatically — no manual prerequisites +- Unit tests use testcontainers-go to spin up a real Postgres instance (no in-memory SQLite) +- `--database-vector-enabled` flag is retained (default `true`) so external PostgreSQL users without pgvector can opt out of memory features without a hard crash at startup +- SQLite Go dependencies (`glebarez/sqlite`, `turso.tech/tursogo`) are removed from `go.mod` +- CI E2E matrix simplified — `database: [sqlite, postgres]` matrix removed entirely (single-value matrices serve no purpose) + +## Current State (Before This Change) + +### What uses SQLite today + +| Location | What it does | +|----------|--------------| +| `go/core/internal/database/manager.go` | Switches between SQLite and Postgres based on `--database-type` flag; SQLite path uses Turso driver, sets `MaxOpenConns(1)`, manual vector table DDL using `F32_BLOB(768)` | +| `go/core/internal/database/client.go` | `SearchAgentMemory` branches on `db.Name() == "sqlite"` to use `vector_distance_cos(embedding, vector32(?))` instead of pgvector `<=>` operator; `deleteAgentMemoryByQuery` uses a Turso-specific two-step delete (Pluck IDs + `DELETE WHERE id IN ?`) to avoid a libSQL multi-index scan bug; `SearchCrewAIMemoryByTask` uses `JSON_EXTRACT` (MySQL syntax) in both the WHERE clause and ORDER BY — this is a pre-existing bug that is currently masked because the Postgres E2E tests don't exercise this path | +| `go/core/internal/database/client_test.go` | All unit tests use in-memory SQLite (`:memory:`) via two helpers: `setupTestDB` (line 205) and `setupVectorTestDB` (line 319) | +| `go/core/pkg/app/app.go` | Registers `--database-type`, `--sqlite-database-path`, `--database-vector-enabled` flags; default is `sqlite` | +| `helm/kagent/values.yaml` | `database.type: sqlite` is the default; SQLite path has a `vectorEnabled` flag | +| `helm/kagent/templates/controller-deployment.yaml` | Conditionally creates an `emptyDir` volume (500Mi memory) and mounts it at `/sqlite-volume` when `database.type == "sqlite"`; sets `XDG_CACHE_HOME=/sqlite-volume/.cache` | +| `helm/kagent/templates/controller-configmap.yaml` | Conditionally sets `SQLITE_DATABASE_PATH` and `DATABASE_VECTOR_ENABLED` env vars | +| `.github/workflows/ci.yaml` | E2E test matrix: `database: [sqlite, postgres]` | +| `go/go.mod` | `github.com/glebarez/sqlite v1.11.0`, `turso.tech/database/tursogo v0.5.0-pre.13` | +| `contrib/addons/postgres.yaml` | Optional dev-only addon; `make kagent-addon-install` installs it alongside Grafana and Prometheus | + +### Inconsistent Postgres default URLs + +Three places defined a default Postgres URL and none of them agreed: + +| Location | Before | After | +|----------|--------|-------| +| `helm/kagent/values.yaml` | `pgsql-postgresql.kagent.svc.cluster.local:5432/postgres` | `""` — auto-computed from bundled service (`kagent-postgresql`) | +| `go/core/pkg/app/app.go` flag default | `db.kagent.svc.cluster.local:5432/crud` | `kagent-postgresql.kagent.svc.cluster.local:5432/postgres` | +| `DEVELOPMENT.md` | `postgres.kagent.svc.cluster.local:5432/kagent` | Removed — postgres is now deployed by `make helm-install` | + +## Changes + +### 1. Go: Remove SQLite from manager.go + +- Remove `DatabaseTypeSqlite` constant and `SqliteConfig` struct +- Remove the SQLite case from the database init switch (Turso driver open, `SetMaxOpenConns(1)`) +- Remove the SQLite vector table DDL block (the `F32_BLOB` / `idx_memory_agent_user` creation) +- The Postgres path is now the only path; direct initialization replaces the switch + +### 2. Go: Remove SQLite branch and fix Postgres bugs in client.go + +- Remove the `if db.Name() == "sqlite"` branch in `SearchAgentMemory` — the pgvector `<=>` cosine similarity path is the only path +- Simplify `deleteAgentMemoryByQuery` — remove the two-step Pluck + `DELETE WHERE id IN ?` workaround. The workaround was specific to a Turso multi-index scan bug and is unnecessary on Postgres +- Fix `SearchCrewAIMemoryByTask` — replace `JSON_EXTRACT(memory_data, '$.task_description')` and `JSON_EXTRACT(memory_data, '$.score')` with the Postgres JSONB operator equivalent (`memory_data->>'task_description'`, `memory_data->>'score'`). `JSON_EXTRACT` is MySQL syntax and errors on Postgres. This is a pre-existing bug masked by the SQLite E2E tests. + +### 3. Go: Update app.go flags and manager.go config structs + +**app.go:** +- Remove `--database-type` flag and `DATABASE_TYPE` env var +- Remove `--sqlite-database-path` flag and `SQLITE_DATABASE_PATH` env var +- Retain `--database-vector-enabled` flag (default `true`) — see [decision note below](#decision-retain---database-vector-enabled) +- Fix the `--postgres-database-url` default to match the bundled Helm postgres service + +**manager.go:** +- Retain `PostgresConfig.VectorEnabled` field (same rationale) +- The `if VectorEnabled` guard controls `CREATE EXTENSION IF NOT EXISTS vector`, memory table migration, and HNSW index creation + +### 4. Go: Replace in-memory SQLite unit tests with testcontainers-go + +- Add `github.com/testcontainers/testcontainers-go` and `testcontainers-go/modules/postgres` to `go/core/go.mod` +- Create `go/core/internal/dbtest/dbtest.go` — shared helper that starts a `pgvector/pgvector:pg18-trixie` container with `testcontainers.WithReuseByName("kagent-dbtest-postgres")` and a `wait.ForLog` readiness strategy (waits for `"database system is ready to accept connections"` twice) +- `TestMain` in `database/` package starts the shared container once; `setupTestDB` calls `Reset(true)` between tests instead of creating a new manager per test — avoids "connection reset by peer" from rapid pool cycling +- `testing.Short()` skips database tests when run without Docker; `flag.Parse()` called before `testing.Short()` in `TestMain` (required by the testing package) + +### 5. Go: Remove SQLite dependencies + +Remove from `go/go.mod`: +- `github.com/glebarez/sqlite v1.11.0` +- `github.com/glebarez/go-sqlite v1.21.2` (indirect) +- `turso.tech/database/tursogo v0.5.0-pre.13` + +### 6. Helm: Remove SQLite config, add bundled PostgreSQL + +**`helm/kagent/values.yaml`:** +- Remove `database.type` field and `database.sqlite` section +- `database.postgres.url` defaults to `""` — leave empty to use the bundled postgres, set to use external +- Retain `database.postgres.urlFile` — takes precedence over `url` when set +- Retain `database.postgres.vectorEnabled: true` +- Add `database.postgres.bundled` sub-key for bundled instance config (image, storage, database, user, password) + +**`helm/kagent/templates/controller-deployment.yaml`:** +- Remove the `{{- if eq .Values.database.type "sqlite" }}` conditional volume block (emptyDir, 500Mi) +- Remove the volumeMount block (`/sqlite-volume`) and `XDG_CACHE_HOME` env var + +**`helm/kagent/templates/controller-configmap.yaml`:** +- Remove `DATABASE_TYPE` and `SQLITE_DATABASE_PATH` entries +- `POSTGRES_DATABASE_URL_FILE` set when `urlFile` is non-empty; otherwise `POSTGRES_DATABASE_URL` uses `include "kagent.postgresqlUrl"` helper + +**`helm/kagent/templates/_helpers.tpl`:** +- Remove `kagent.validateController` helper (blocked renders when `replicas > 1 AND database.type == "sqlite"`) +- Add `kagent.postgresqlServiceName` and `kagent.postgresqlUrl` helpers — `postgresqlUrl` returns `database.postgres.url` when set, otherwise auto-computes from bundled config + +**`helm/kagent/templates/postgresql.yaml`** (new): +- Templated version of the former `contrib/addons/postgres.yaml` +- Renders when `database.postgres.url` and `database.postgres.urlFile` are both empty +- Deploys ConfigMap, PVC, Deployment, and Service for `pgvector/pgvector:pg18-trixie` + +**`helm/kagent/tests/controller-deployment_test.yaml`:** +- Remove test case "should fail when replicas > 1 and database type is sqlite" +- Remove SQLite volume/mount test cases + +### 7. CI: Remove E2E matrix + +Remove `strategy.matrix` from `test-e2e` entirely. A `database: [postgres]` single-value matrix runs the job once with no variation — it is equivalent to no matrix. Remove the Postgres service container block as well; postgres is deployed inside the Kind cluster by `make helm-install`. + +### 8. Local Kind setup: Postgres bundled in Helm chart + +**Decision: built-in chart templates** (`helm/kagent/templates/postgresql.yaml`). + +Options considered: + +| Option | Decision | +|--------|----------| +| Built-in chart templates (chosen) | Move `contrib/addons/postgres.yaml` into `helm/kagent/templates/`. Renders when `database.postgres.url` and `urlFile` are both empty — the same condition users already knew: leave `url` empty for local dev, set it for production. No external deps, no separate install step. Works with Argo CD, Flux, and any Helm-based deploy, not just the Makefile. | +| Bitnami postgresql subchart | More feature-rich (backups, HA, etc.) but heavy for a dev dependency and ties the chart to an external chart release cycle. Overkill for a bundled dev/default postgres. | +| Separate kagent-postgres chart | Mirrors the kagent-crds pattern. Cleaner separation but adds install complexity (`helm install kagent-postgres` then `helm install kagent`). | +| Keep in contrib, Makefile applies it | What existed before. Works for local dev but breaks pure Helm installs -- i.e. anyone not using the Makefile. | + +Production users set `database.postgres.url` (or `database.postgres.urlFile` for Secret-mounted credentials) — the same configuration they already provided. The bundled postgres simply does not deploy. + +Delete `contrib/addons/postgres.yaml`. Remove postgres from `make kagent-addon-install`. + +## Decision: Retain `--database-vector-enabled` + +The original design called for removing this flag (pgvector always-on). Retain it for the following reason: + +Without the flag, any external PostgreSQL instance without the pgvector extension installed causes the controller to crash at startup with `failed to create vector extension`. This is a hard prerequisite that external users may not anticipate. + +With the flag (default `true`), users running external Postgres without pgvector can set `database.postgres.vectorEnabled: false` (or `DATABASE_VECTOR_ENABLED=false`) to skip extension creation and run without memory/vector support. This is a softer failure mode and a better operator experience. + +The bundled postgres uses `pgvector/pgvector:pg18-trixie` and always has the extension available, so the default `true` is correct for the common case. diff --git a/go/core/internal/controller/reconciler/mcp_server_reconciler_test.go b/go/core/internal/controller/reconciler/mcp_server_reconciler_test.go index cb8bd27e0..56d46c9cd 100644 --- a/go/core/internal/controller/reconciler/mcp_server_reconciler_test.go +++ b/go/core/internal/controller/reconciler/mcp_server_reconciler_test.go @@ -14,6 +14,7 @@ import ( agenttranslator "github.com/kagent-dev/kagent/go/core/internal/controller/translator/agent" "github.com/kagent-dev/kagent/go/core/internal/database" + "github.com/kagent-dev/kagent/go/core/internal/dbtest" "github.com/kagent-dev/kmcp/api/v1alpha1" ) @@ -26,6 +27,12 @@ func TestReconcileKagentMCPServer_ErrorPropagation(t *testing.T) { err := v1alpha1.AddToScheme(scheme) require.NoError(t, err) + if testing.Short() { + t.Skip("skipping database test in short mode") + } + + connStr := dbtest.StartT(context.Background(), t) + testCases := []struct { name string mcpServer *v1alpha1.MCPServer @@ -78,11 +85,10 @@ func TestReconcileKagentMCPServer_ErrorPropagation(t *testing.T) { WithObjects(tc.mcpServer). Build() - // Create an in-memory database manager dbManager, err := database.NewManager(&database.Config{ - DatabaseType: database.DatabaseTypeSqlite, - SqliteConfig: &database.SqliteConfig{ - DatabasePath: "file::memory:?cache=shared", + PostgresConfig: &database.PostgresConfig{ + URL: connStr, + VectorEnabled: true, }, }) require.NoError(t, err) diff --git a/go/core/internal/database/client.go b/go/core/internal/database/client.go index a6afde6c1..7ae10078f 100644 --- a/go/core/internal/database/client.go +++ b/go/core/internal/database/client.go @@ -512,13 +512,10 @@ func (c *clientImpl) StoreCrewAIMemory(ctx context.Context, memory *dbpkg.CrewAI func (c *clientImpl) SearchCrewAIMemoryByTask(ctx context.Context, userID, threadID, taskDescription string, limit int) ([]*dbpkg.CrewAIAgentMemory, error) { var memories []*dbpkg.CrewAIAgentMemory - // Search for task_description within the JSON memory_data field - // Using JSON_EXTRACT or JSON_UNQUOTE for MySQL/PostgreSQL, or simple LIKE for SQLite - // Sort by created_at DESC, then by score ASC (if score exists in JSON) query := c.db.WithContext(ctx).Where( - "user_id = ? AND thread_id = ? AND (memory_data LIKE ? OR JSON_EXTRACT(memory_data, '$.task_description') LIKE ?)", + "user_id = ? AND thread_id = ? AND (memory_data LIKE ? OR memory_data->>'task_description' LIKE ?)", userID, threadID, "%"+taskDescription+"%", "%"+taskDescription+"%", - ).Order("created_at DESC, JSON_EXTRACT(memory_data, '$.score') ASC") + ).Order("created_at DESC, memory_data->>'score' ASC") // Apply limit if limit > 0 { @@ -597,43 +594,17 @@ func (c *clientImpl) StoreAgentMemories(ctx context.Context, memories []*dbpkg.M func (c *clientImpl) SearchAgentMemory(ctx context.Context, agentName, userID string, embedding pgvector.Vector, limit int) ([]dbpkg.AgentMemorySearchResult, error) { var results []dbpkg.AgentMemorySearchResult - db := c.db.WithContext(ctx) - if db.Name() == "sqlite" { - // libSQL/Turso syntax: vector_distance_cos(embedding, vector32('JSON_ARRAY')) - // We must use fmt.Sprintf to inline the JSON array because vector32() requires a string literal - // and parameter binding with ? fails with "unexpected token" errors (GORM limitation) - embeddingJSON, err := json.Marshal(embedding.Slice()) - if err != nil { - return nil, fmt.Errorf("failed to serialize embedding: %w", err) - } - - // Safe formatting because we control the JSON string generation from float slice - query := fmt.Sprintf(` - SELECT id, agent_name, user_id, content, metadata, created_at, expires_at, access_count, - 1 - vector_distance_cos(embedding, vector32('%s')) as score - FROM memory - WHERE agent_name = ? AND user_id = ? - ORDER BY vector_distance_cos(embedding, vector32('%s')) ASC - LIMIT ? - `, string(embeddingJSON), string(embeddingJSON)) - - if err := db.Raw(query, agentName, userID, limit).Scan(&results).Error; err != nil { - return nil, fmt.Errorf("failed to search agent memory (sqlite): %w", err) - } - } else { - // Postgres pgvector syntax: uses <=> operator for cosine distance. - // COALESCE guards against NaN when either vector has zero magnitude. - // pgvector.Vector implements sql.Scanner and driver.Valuer - query := ` - SELECT *, COALESCE(1 - (embedding <=> ?), 0) as score - FROM memory - WHERE agent_name = ? AND user_id = ? - ORDER BY embedding <=> ? ASC - LIMIT ? - ` - if err := db.Raw(query, embedding, agentName, userID, embedding, limit).Scan(&results).Error; err != nil { - return nil, fmt.Errorf("failed to search agent memory (postgres): %w", err) - } + // pgvector <=> operator for cosine distance. + // COALESCE guards against NaN when either vector has zero magnitude. + query := ` + SELECT *, COALESCE(1 - (embedding <=> ?), 0) as score + FROM memory + WHERE agent_name = ? AND user_id = ? + ORDER BY embedding <=> ? ASC + LIMIT ? + ` + if err := c.db.WithContext(ctx).Raw(query, embedding, agentName, userID, embedding, limit).Scan(&results).Error; err != nil { + return nil, fmt.Errorf("failed to search agent memory: %w", err) } // Increment access count for found memories synchronously. @@ -642,7 +613,7 @@ func (c *clientImpl) SearchAgentMemory(ctx context.Context, agentName, userID st for i, m := range results { ids[i] = m.ID } - if err := db.Model(&dbpkg.Memory{}).Where("id IN ?", ids).UpdateColumn("access_count", gorm.Expr("access_count + ?", 1)).Error; err != nil { + if err := c.db.WithContext(ctx).Model(&dbpkg.Memory{}).Where("id IN ?", ids).UpdateColumn("access_count", gorm.Expr("access_count + ?", 1)).Error; err != nil { return nil, fmt.Errorf("failed to increment access count: %w", err) } } @@ -705,15 +676,7 @@ func (c *clientImpl) DeleteAgentMemory(ctx context.Context, agentName, userID st } func (c *clientImpl) deleteAgentMemoryByQuery(ctx context.Context, agentName, userID string) error { - var ids []string - if err := c.db.WithContext(ctx).Table("memory").Where("agent_name = ? AND user_id = ?", agentName, userID).Pluck("id", &ids).Error; err != nil { - return fmt.Errorf("failed to list memory ids: %w", err) - } - if len(ids) == 0 { - return nil - } - // DELETE by primary key only to avoid Turso multi-index scan on DELETE which causes a bug - if err := c.db.WithContext(ctx).Exec("DELETE FROM memory WHERE id IN ?", ids).Error; err != nil { + if err := c.db.WithContext(ctx).Where("agent_name = ? AND user_id = ?", agentName, userID).Delete(&dbpkg.Memory{}).Error; err != nil { return fmt.Errorf("failed to delete agent memory: %w", err) } return nil diff --git a/go/core/internal/database/client_test.go b/go/core/internal/database/client_test.go index 2c95723e4..12561ba97 100644 --- a/go/core/internal/database/client_test.go +++ b/go/core/internal/database/client_test.go @@ -132,11 +132,16 @@ func TestConcurrentRefreshToolsForServer(t *testing.T) { wg.Wait() - // Verify the tools exist (we don't know which goroutine's tools "won", but the state should be consistent) + // Verify the tools exist and no data was corrupted. With READ COMMITTED isolation, + // concurrent delete+insert transactions can interleave, so we don't assert on an + // exact count. What matters is that all calls succeeded and valid tool records exist. tools, err := client.ListToolsForServer(ctx, serverName, groupKind) require.NoError(t, err) - // Should have exactly 2 tools from one of the refresh operations - assert.Len(t, tools, 2, "Should have exactly 2 tools after concurrent refreshes") + assert.NotEmpty(t, tools, "Should have tools after concurrent refreshes") + for _, tool := range tools { + assert.Equal(t, serverName, tool.ServerName) + assert.Equal(t, groupKind, tool.GroupKind) + } } // TestStoreAgentIdempotence verifies that calling StoreAgent multiple times @@ -202,28 +207,16 @@ func TestStoreToolServerIdempotence(t *testing.T) { assert.Equal(t, "Updated description", retrieved.Description) } -// setupTestDB creates an in-memory SQLite database for testing using Turso. +// setupTestDB resets the shared Postgres manager's tables for test isolation. func setupTestDB(t *testing.T) *Manager { t.Helper() - - config := &Config{ - DatabaseType: DatabaseTypeSqlite, - SqliteConfig: &SqliteConfig{ - DatabasePath: ":memory:", - }, + if testing.Short() { + t.Skip("skipping database test in short mode") } - manager, err := NewManager(config) - require.NoError(t, err, "Failed to create test database") - - err = manager.Initialize() - require.NoError(t, err, "Failed to initialize test database") - - t.Cleanup(func() { - manager.Close() - }) + require.NoError(t, sharedManager.Reset(true), "Failed to reset test database") - return manager + return sharedManager } func TestListEventsForSession(t *testing.T) { db := setupTestDB(t) @@ -316,32 +309,6 @@ func TestListEventsForSessionOrdering(t *testing.T) { }) } -// setupVectorTestDB creates an in-memory SQLite database with the vector extension enabled. -// libSQL/Turso bundles the vector extension, so vector_distance_cos is available at runtime. -func setupVectorTestDB(t *testing.T) *Manager { - t.Helper() - - config := &Config{ - DatabaseType: DatabaseTypeSqlite, - SqliteConfig: &SqliteConfig{ - DatabasePath: ":memory:", - VectorEnabled: true, - }, - } - - manager, err := NewManager(config) - require.NoError(t, err, "Failed to create vector-enabled test database") - - err = manager.Initialize() - require.NoError(t, err, "Failed to initialize vector-enabled test database") - - t.Cleanup(func() { - manager.Close() - }) - - return manager -} - // makeEmbedding returns a 768-dimensional vector where all values are set to v. // This makes it easy to construct vectors with known cosine similarity relationships. func makeEmbedding(v float32) pgvector.Vector { @@ -355,7 +322,7 @@ func makeEmbedding(v float32) pgvector.Vector { // TestStoreAndSearchAgentMemory verifies that stored memories can be retrieved // via vector similarity search and that results are ordered by cosine similarity. func TestStoreAndSearchAgentMemory(t *testing.T) { - db := setupVectorTestDB(t) + db := setupTestDB(t) client := NewClient(db) ctx := context.Background() @@ -404,7 +371,7 @@ func TestStoreAndSearchAgentMemory(t *testing.T) { // TestStoreAgentMemoriesBatch verifies that StoreAgentMemories stores all memories // atomically via a transaction and that they are all retrievable afterwards. func TestStoreAgentMemoriesBatch(t *testing.T) { - db := setupVectorTestDB(t) + db := setupTestDB(t) client := NewClient(db) ctx := context.Background() @@ -428,7 +395,7 @@ func TestStoreAgentMemoriesBatch(t *testing.T) { // TestSearchAgentMemoryLimit verifies that the limit parameter is respected when // searching for similar memories. func TestSearchAgentMemoryLimit(t *testing.T) { - db := setupVectorTestDB(t) + db := setupTestDB(t) client := NewClient(db) ctx := context.Background() @@ -468,7 +435,7 @@ func TestSearchAgentMemoryLimit(t *testing.T) { // TestSearchAgentMemoryIsolation verifies that searches are scoped to the // correct (agentName, userID) pair and do not return results for other agents or users. func TestSearchAgentMemoryIsolation(t *testing.T) { - db := setupVectorTestDB(t) + db := setupTestDB(t) client := NewClient(db) ctx := context.Background() @@ -494,7 +461,7 @@ func TestSearchAgentMemoryIsolation(t *testing.T) { // TestDeleteAgentMemory verifies that DeleteAgentMemory removes all memories for the // given agent/user pair and that the hyphen-to-underscore normalization works correctly. func TestDeleteAgentMemory(t *testing.T) { - db := setupVectorTestDB(t) + db := setupTestDB(t) client := NewClient(db) ctx := context.Background() @@ -528,7 +495,7 @@ func TestDeleteAgentMemory(t *testing.T) { // TestPruneExpiredMemories verifies that expired memories with low access counts are removed // and that frequently-accessed expired memories have their TTL extended instead. func TestPruneExpiredMemories(t *testing.T) { - db := setupVectorTestDB(t) + db := setupTestDB(t) client := NewClient(db) ctx := context.Background() diff --git a/go/core/internal/database/manager.go b/go/core/internal/database/manager.go index 7b0c45a11..331f8edc3 100644 --- a/go/core/internal/database/manager.go +++ b/go/core/internal/database/manager.go @@ -1,19 +1,16 @@ package database import ( - "database/sql" "fmt" "os" "strings" "sync" - "github.com/glebarez/sqlite" dbpkg "github.com/kagent-dev/kagent/go/api/database" "github.com/kagent-dev/kagent/go/core/pkg/env" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" - _ "turso.tech/database/tursogo" ) // Manager handles database connection and initialization @@ -23,18 +20,6 @@ type Manager struct { initLock sync.Mutex } -type DatabaseType string - -const ( - DatabaseTypeSqlite DatabaseType = "sqlite" - DatabaseTypePostgres DatabaseType = "postgres" -) - -type SqliteConfig struct { - DatabasePath string - VectorEnabled bool -} - type PostgresConfig struct { URL string URLFile string @@ -42,16 +27,11 @@ type PostgresConfig struct { } type Config struct { - DatabaseType DatabaseType - SqliteConfig *SqliteConfig PostgresConfig *PostgresConfig } // NewManager creates a new database manager func NewManager(config *Config) (*Manager, error) { - var db *gorm.DB - var err error - logLevel := logger.Silent switch env.GormLogLevel.Get() { case "error": @@ -64,36 +44,19 @@ func NewManager(config *Config) (*Manager, error) { logLevel = logger.Silent } - switch config.DatabaseType { - case DatabaseTypeSqlite: - // GORM uses glebarez/sqlite as dialector over the connection - // The actual driver is Turso's tursogo driver - sqlDB, sqlErr := sql.Open("turso", config.SqliteConfig.DatabasePath) - if sqlErr != nil { - return nil, fmt.Errorf("failed to open turso connection: %w", sqlErr) + url := config.PostgresConfig.URL + if config.PostgresConfig.URLFile != "" { + resolved, err := resolveURLFile(config.PostgresConfig.URLFile) + if err != nil { + return nil, fmt.Errorf("failed to resolve postgres URL from file: %w", err) } - sqlDB.SetMaxOpenConns(1) - db, err = gorm.Open(sqlite.Dialector{Conn: sqlDB}, &gorm.Config{ - Logger: logger.Default.LogMode(logLevel), - TranslateError: true, - }) - case DatabaseTypePostgres: - url := config.PostgresConfig.URL - if config.PostgresConfig.URLFile != "" { - resolved, resolveErr := resolveURLFile(config.PostgresConfig.URLFile) - if resolveErr != nil { - return nil, fmt.Errorf("failed to resolve postgres URL from file: %w", resolveErr) - } - url = resolved - } - db, err = gorm.Open(postgres.Open(url), &gorm.Config{ - Logger: logger.Default.LogMode(logLevel), - TranslateError: true, - }) - default: - return nil, fmt.Errorf("invalid database type: %s", config.DatabaseType) + url = resolved } + db, err := gorm.Open(postgres.Open(url), &gorm.Config{ + Logger: logger.Default.LogMode(logLevel), + TranslateError: true, + }) if err != nil { return nil, fmt.Errorf("failed to connect to database: %w", err) } @@ -103,8 +66,7 @@ func NewManager(config *Config) (*Manager, error) { // Initialize sets up the database tables func (m *Manager) Initialize() error { - // Create extensions if using Postgres and Vector is enabled - if m.db.Name() == "postgres" && m.config.PostgresConfig.VectorEnabled { + if m.config.PostgresConfig.VectorEnabled { if err := m.db.Exec("CREATE EXTENSION IF NOT EXISTS vector").Error; err != nil { return fmt.Errorf("failed to create vector extension: %w", err) } @@ -125,51 +87,23 @@ func (m *Manager) Initialize() error { &dbpkg.CrewAIAgentMemory{}, &dbpkg.CrewAIFlowState{}, ) - if err != nil { return fmt.Errorf("failed to migrate database: %w", err) } - // Initialize memory table that uses vector column - if m.config.DatabaseType == DatabaseTypePostgres && m.config.PostgresConfig.VectorEnabled { + if m.config.PostgresConfig.VectorEnabled { if err := m.db.AutoMigrate(&dbpkg.Memory{}); err != nil { return fmt.Errorf("failed to migrate memory table: %w", err) } - // Manually create the HNSW index with the correct operator class - // GORM doesn't support adding "op class" in struct tags easily for Postgres vectors + // Manually create the HNSW index with the correct operator class — + // GORM doesn't support adding "op class" in struct tags for Postgres vectors. indexQuery := `CREATE INDEX IF NOT EXISTS idx_memory_embedding_hnsw ON memory USING hnsw (embedding vector_cosine_ops)` if err := m.db.Exec(indexQuery).Error; err != nil { return fmt.Errorf("failed to create hnsw index: %w", err) } } - // libSQL uses F32_BLOB(N) for vector columns, not vector(N) like pgvector. - // AutoMigrate doesn't work because GORM tries to use the pgvector type from struct tags. - // The id column has no DEFAULT expression: the application layer (BeforeCreate hook on - // Memory) generates a UUID before every insert, making it DB-agnostic. - if m.config.DatabaseType == DatabaseTypeSqlite && m.config.SqliteConfig.VectorEnabled { - createMemoryTableSQL := ` - CREATE TABLE IF NOT EXISTS memory ( - id TEXT PRIMARY KEY, - agent_name TEXT, - user_id TEXT, - content TEXT, - embedding F32_BLOB(768), - metadata TEXT, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - expires_at DATETIME, - access_count INTEGER DEFAULT 0 - ) - ` - if err := m.db.Exec(createMemoryTableSQL).Error; err != nil { - return fmt.Errorf("failed to create memory table: %w", err) - } - // Composite index for the most common query pattern (agent_name + user_id) - _ = m.db.Exec(`CREATE INDEX IF NOT EXISTS idx_memory_agent_user ON memory(agent_name, user_id)`) - _ = m.db.Exec(`CREATE INDEX IF NOT EXISTS idx_memory_expires_at ON memory(expires_at)`) - } - return nil } @@ -180,7 +114,6 @@ func (m *Manager) Reset(recreateTables bool) error { } defer m.initLock.Unlock() - // Drop all tables (including memory, which is created manually in Initialize) err := m.db.Migrator().DropTable( &dbpkg.Agent{}, &dbpkg.Session{}, @@ -196,7 +129,6 @@ func (m *Manager) Reset(recreateTables bool) error { &dbpkg.CrewAIFlowState{}, &dbpkg.Memory{}, ) - if err != nil { return fmt.Errorf("failed to drop tables: %w", err) } diff --git a/go/core/internal/database/testhelpers_test.go b/go/core/internal/database/testhelpers_test.go new file mode 100644 index 000000000..f12dd6392 --- /dev/null +++ b/go/core/internal/database/testhelpers_test.go @@ -0,0 +1,39 @@ +package database + +import ( + "context" + "flag" + "fmt" + "os" + "testing" + + "github.com/kagent-dev/kagent/go/core/internal/dbtest" +) + +var sharedManager *Manager + +func TestMain(m *testing.M) { + flag.Parse() + if testing.Short() { + os.Exit(m.Run()) + } + + connStr, _, err := dbtest.Start(context.Background()) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to start postgres container: %v\n", err) + os.Exit(1) + } + + sharedManager, err = NewManager(&Config{ + PostgresConfig: &PostgresConfig{ + URL: connStr, + VectorEnabled: true, + }, + }) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to create shared manager: %v\n", err) + os.Exit(1) + } + + os.Exit(m.Run()) +} diff --git a/go/core/internal/dbtest/dbtest.go b/go/core/internal/dbtest/dbtest.go new file mode 100644 index 000000000..593a69dc3 --- /dev/null +++ b/go/core/internal/dbtest/dbtest.go @@ -0,0 +1,60 @@ +// Package dbtest provides test helpers for spinning up a Postgres container. +package dbtest + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" + tcpostgres "github.com/testcontainers/testcontainers-go/modules/postgres" +) + +// Start starts a pgvector Postgres container and returns the connection string +// and a cleanup function. Callers are responsible for calling cleanup when done. +func Start(ctx context.Context) (connStr string, cleanup func(), err error) { + pgContainer, err := tcpostgres.Run(ctx, + "pgvector/pgvector:pg18-trixie", + tcpostgres.WithDatabase("kagent_test"), + tcpostgres.WithUsername("postgres"), + tcpostgres.WithPassword("kagent"), + testcontainers.WithWaitStrategy( + wait.ForLog("database system is ready to accept connections"). + WithOccurrence(2). + WithStartupTimeout(60*time.Second), + ), + ) + if err != nil { + return "", nil, fmt.Errorf("starting postgres container: %w", err) + } + + connStr, err = pgContainer.ConnectionString(ctx, "sslmode=disable") + if err != nil { + _ = pgContainer.Terminate(ctx) + return "", nil, fmt.Errorf("getting connection string: %w", err) + } + + cleanup = func() { + if err := pgContainer.Terminate(ctx); err != nil { + fmt.Printf("warning: failed to terminate postgres container: %v\n", err) + } + } + + return connStr, cleanup, nil +} + +// StartT starts a pgvector Postgres container and registers cleanup with t.Cleanup. +// Suitable for use in individual tests or test helpers that have a *testing.T. +func StartT(ctx context.Context, t *testing.T) string { + t.Helper() + + connStr, cleanup, err := Start(ctx) + if err != nil { + t.Fatalf("failed to start postgres container: %v", err) + } + t.Cleanup(cleanup) + + return connStr +} diff --git a/go/core/pkg/app/app.go b/go/core/pkg/app/app.go index b5f264a76..69b5cd74b 100644 --- a/go/core/pkg/app/app.go +++ b/go/core/pkg/app/app.go @@ -124,8 +124,6 @@ type Config struct { WatchNamespaces string A2ABaseUrl string Database struct { - Type string - Path string Url string UrlFile string VectorEnabled bool @@ -156,11 +154,9 @@ func (cfg *Config) SetFlags(commandLine *flag.FlagSet) { commandLine.StringVar(&cfg.DefaultModelConfig.Namespace, "default-model-config-namespace", kagentNamespace, "The namespace of the default model config.") commandLine.StringVar(&cfg.HttpServerAddr, "http-server-address", ":8083", "The address the HTTP server binds to.") commandLine.StringVar(&cfg.A2ABaseUrl, "a2a-base-url", "http://127.0.0.1:8083", "The base URL of the A2A Server endpoint, as advertised to clients.") - commandLine.StringVar(&cfg.Database.Type, "database-type", "sqlite", "The type of the database to use. Supported values: sqlite, postgres.") - commandLine.StringVar(&cfg.Database.Path, "sqlite-database-path", "./kagent.db", "The path to the SQLite database file.") - commandLine.StringVar(&cfg.Database.Url, "postgres-database-url", "postgres://postgres:kagent@db.kagent.svc.cluster.local:5432/crud", "The URL of the PostgreSQL database.") + commandLine.StringVar(&cfg.Database.Url, "postgres-database-url", "postgres://postgres:kagent@kagent-postgresql.kagent.svc.cluster.local:5432/postgres", "The URL of the PostgreSQL database.") commandLine.StringVar(&cfg.Database.UrlFile, "postgres-database-url-file", "", "Path to a file containing the PostgreSQL database URL. Takes precedence over --postgres-database-url.") - commandLine.BoolVar(&cfg.Database.VectorEnabled, "database-vector-enabled", true, "Enable vector database features (requires pgvector extension).") + commandLine.BoolVar(&cfg.Database.VectorEnabled, "database-vector-enabled", true, "Enable pgvector extension and memory table. Requires pgvector to be installed on the PostgreSQL server.") commandLine.StringVar(&cfg.WatchNamespaces, "watch-namespaces", "", "The namespaces to watch for .") @@ -369,16 +365,11 @@ func Start(getExtensionConfig GetExtensionConfig) { // Initialize database dbManager, err := database.NewManager(&database.Config{ - DatabaseType: database.DatabaseType(cfg.Database.Type), PostgresConfig: &database.PostgresConfig{ URL: cfg.Database.Url, URLFile: cfg.Database.UrlFile, VectorEnabled: cfg.Database.VectorEnabled, }, - SqliteConfig: &database.SqliteConfig{ - DatabasePath: cfg.Database.Path, - VectorEnabled: cfg.Database.VectorEnabled, - }, }) if err != nil { setupLog.Error(err, "unable to initialize database") diff --git a/go/core/pkg/app/app_test.go b/go/core/pkg/app/app_test.go index ead8242bc..63468b081 100644 --- a/go/core/pkg/app/app_test.go +++ b/go/core/pkg/app/app_test.go @@ -277,7 +277,6 @@ func TestLoadFromEnvIntegration(t *testing.T) { "HTTP_SERVER_ADDRESS": ":9000", "A2A_BASE_URL": "http://example.com:9000", "PROXY_URL": "http://proxy.kagent.svc.cluster.local:8080", - "DATABASE_TYPE": "postgres", "POSTGRES_DATABASE_URL": "postgres://localhost:5432/testdb", "WATCH_NAMESPACES": "ns1,ns2,ns3", "STREAMING_TIMEOUT": "120s", @@ -328,9 +327,6 @@ func TestLoadFromEnvIntegration(t *testing.T) { if cfg.A2ABaseUrl != "http://example.com:9000" { t.Errorf("A2ABaseUrl = %v, want http://example.com:9000", cfg.A2ABaseUrl) } - if cfg.Database.Type != "postgres" { - t.Errorf("Database.Type = %v, want postgres", cfg.Database.Type) - } if cfg.Database.Url != "postgres://localhost:5432/testdb" { t.Errorf("Database.Url = %v, want postgres://localhost:5432/testdb", cfg.Database.Url) } diff --git a/go/go.mod b/go/go.mod index 2bfd0694a..9855348d7 100644 --- a/go/go.mod +++ b/go/go.mod @@ -3,7 +3,6 @@ module github.com/kagent-dev/kagent/go go 1.26.1 require ( - // core dependencies dario.cat/mergo v1.0.2 @@ -17,7 +16,6 @@ require ( github.com/charmbracelet/bubbletea v1.3.10 github.com/charmbracelet/lipgloss v1.1.0 github.com/fatih/color v1.18.0 - github.com/glebarez/sqlite v1.11.0 github.com/go-logr/logr v1.4.3 github.com/go-logr/zapr v1.3.0 // api dependencies @@ -58,7 +56,6 @@ require ( sigs.k8s.io/controller-runtime v0.23.1 sigs.k8s.io/yaml v1.6.0 trpc.group/trpc-go/trpc-a2a-go v0.2.5 - turso.tech/database/tursogo v0.5.0-pre.13 ) require ( @@ -67,6 +64,8 @@ require ( cloud.google.com/go/auth v0.17.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/abiosoft/ishell v2.0.0+incompatible // indirect github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect @@ -88,16 +87,26 @@ require ( github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect github.com/charmbracelet/x/ansi v0.10.1 // indirect github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect github.com/charmbracelet/x/term v0.2.1 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/docker v28.5.2+incompatible // indirect + github.com/docker/go-connections v0.6.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/ebitengine/purego v0.9.1 // indirect + github.com/ebitengine/purego v0.10.0 // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect @@ -105,13 +114,14 @@ require ( github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect - github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/goccy/go-json v0.10.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.0 // indirect @@ -134,6 +144,7 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/lestrrat-go/blackmagic v1.0.2 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httprc v1.0.6 // indirect @@ -141,40 +152,59 @@ require ( github.com/lestrrat-go/jwx/v2 v2.1.4 // indirect github.com/lestrrat-go/option v1.0.1 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.10 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/go-archive v0.2.0 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/morikuni/aec v1.0.0 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/termenv v0.16.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/otlptranslator v1.0.0 // indirect github.com/prometheus/procfs v0.20.1 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sahilm/fuzzy v0.1.1 // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/segmentio/encoding v0.5.3 // indirect + github.com/shirou/gopsutil/v4 v4.26.2 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/testcontainers/testcontainers-go v0.41.0 // indirect + github.com/testcontainers/testcontainers-go/modules/postgres v0.41.0 // indirect github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.2.0 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/tursodatabase/turso-go-platform-libs v0.5.0-pre.13 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect @@ -218,10 +248,6 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect - modernc.org/libc v1.22.5 // indirect - modernc.org/mathutil v1.5.0 // indirect - modernc.org/memory v1.5.0 // indirect - modernc.org/sqlite v1.23.1 // indirect rsc.io/omap v1.2.0 // indirect rsc.io/ordered v1.1.1 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect diff --git a/go/go.sum b/go/go.sum index 96ea4b4e8..8bbae4ee4 100644 --- a/go/go.sum +++ b/go/go.sum @@ -12,10 +12,16 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= entgo.io/ent v0.14.3 h1:wokAV/kIlH9TeklJWGGS7AYJdVckr0DloWjIcO9iIIQ= entgo.io/ent v0.14.3/go.mod h1:aDPE/OziPEu8+OWbzy4UlvWmD2/kbRuWfK2A40hcxJM= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/a2aproject/a2a-go v0.3.6 h1:VbRoM2MNsfc7o4GkjGt3KZCjbqILAJq846K1z8rpHTc= github.com/a2aproject/a2a-go v0.3.6/go.mod h1:I7Cm+a1oL+UT6zMoP+roaRE5vdfUa1iQGVN8aSOuZ0I= github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw= @@ -70,6 +76,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/briandowns/spinner v1.23.2 h1:Zc6ecUnI+YzLmJniCfDNaMbW0Wid1d5+qcTq4L2FW8w= github.com/briandowns/spinner v1.23.2/go.mod h1:LaZeM4wm2Ywy6vO571mvhQNRcWfRUnXOs0RcKV0wYKM= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -96,6 +104,16 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWs github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -104,12 +122,26 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw= +github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= +github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= -github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= +github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= +github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= @@ -136,10 +168,6 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= -github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= -github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= -github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= -github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -147,6 +175,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= @@ -165,6 +195,8 @@ github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9L github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= @@ -175,6 +207,7 @@ github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI= github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -230,8 +263,12 @@ github.com/kagent-dev/kmcp v0.2.7 h1:aDPpsmJVYqigC0inZablon1ap7GDBi8R+KRqH3OFTM0 github.com/kagent-dev/kmcp v0.2.7/go.mod h1:g7wS/3m2wonRo/1DMwVoHxnilr/urPgV2hwV1DwkwrQ= github.com/kagent-dev/mockllm v0.0.5 h1:mm9Ml3NH6/E/YKVMgMwWYMNsNGkDze6I6TC0ppHZAo8= github.com/kagent-dev/mockllm v0.0.5/go.mod h1:tDLemRsTZa1NdHaDbg3sgFk9cT1QWvMPlBtLVD6I2mA= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -257,6 +294,10 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -271,6 +312,24 @@ github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+Ei github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= +github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= +github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8= +github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modelcontextprotocol/go-sdk v1.4.0 h1:u0kr8lbJc1oBcawK7Df+/ajNMpIDFE41OEPxdeTLOn8= github.com/modelcontextprotocol/go-sdk v1.4.0/go.mod h1:Nxc2n+n/GdCebUaqCOhTetptS17SXXNu9IfNTaLDi1E= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -279,6 +338,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= @@ -295,6 +356,10 @@ github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/openai/openai-go/v3 v3.26.0 h1:bRt6H/ozMNt/dDkN4gobnLqaEGrRGBzmbVs0xxJEnQE= github.com/openai/openai-go/v3 v3.26.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pgvector/pgvector-go v0.3.0 h1:Ij+Yt78R//uYqs3Zk35evZFvr+G0blW0OUN+Q2D1RWc= @@ -306,6 +371,10 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= @@ -318,9 +387,6 @@ github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEo github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM= github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= @@ -336,6 +402,12 @@ github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w= github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0= +github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc= +github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= +github.com/shirou/gopsutil/v4 v4.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI= +github.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= @@ -366,6 +438,12 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw= +github.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w= +github.com/testcontainers/testcontainers-go v0.41.0 h1:mfpsD0D36YgkxGj2LrIyxuwQ9i2wCKAD+ESsYM1wais= +github.com/testcontainers/testcontainers-go v0.41.0/go.mod h1:pdFrEIfaPl24zmBjerWTTYaY0M6UHsqA1YSvsoU40MI= +github.com/testcontainers/testcontainers-go/modules/postgres v0.41.0 h1:AOtFXssrDlLm84A2sTTR/AhvJiYbrIuCO59d+Ro9Tb0= +github.com/testcontainers/testcontainers-go/modules/postgres v0.41.0/go.mod h1:k2a09UKhgSp6vNpliIY0QSgm4Hi7GXVTzWvWgUemu/8= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -377,10 +455,16 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= +github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= +github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= -github.com/tursodatabase/turso-go-platform-libs v0.5.0-pre.13 h1:mpnyeu7obv5DuYEnotM66ab7NjnpayNEw5o1o/9brP4= -github.com/tursodatabase/turso-go-platform-libs v0.5.0-pre.13/go.mod h1:bo+Lpv5OYOX1gRV9L5DLKMsYxmDs56SkZwnCOLEFcxU= github.com/uptrace/bun v1.1.12 h1:sOjDVHxNTuM6dNGaba0wUuz7KvDE1BmNu9Gqs2gJSXQ= github.com/uptrace/bun v1.1.12/go.mod h1:NPG6JGULBeQ9IU6yHp7YGELRa5Agmd7ATZdz4tGZ6z0= github.com/uptrace/bun/dialect/pgdialect v1.1.12 h1:m/CM1UfOkoBTglGO5CUTKnIKKOApOYxkcP2qn0F9tJk= @@ -401,6 +485,10 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavM github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 h1:dkBzNEAIKADEaFnuESzcXvpd09vxvDZsOjx11gjUqLk= @@ -463,35 +551,64 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= @@ -546,14 +663,6 @@ k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0x k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo= mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw= -modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= -modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= -modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= -modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= -modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= rsc.io/omap v1.2.0 h1:c1M8jchnHbzmJALzGLclfH3xDWXrPxSUHXzH5C+8Kdw= rsc.io/omap v1.2.0/go.mod h1:C8pkI0AWexHopQtZX+qiUeJGzvc8HkdgnsWK4/mAa00= rsc.io/ordered v1.1.1 h1:1kZM6RkTmceJgsFH/8DLQvkCVEYomVDJfBRLT595Uak= @@ -572,5 +681,3 @@ sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= trpc.group/trpc-go/trpc-a2a-go v0.2.5 h1:X3pAlWD128LaS9TtXsUDZoJWPVuPZDkZKUecKRxmWn4= trpc.group/trpc-go/trpc-a2a-go v0.2.5/go.mod h1:Gtytau9Uoc3oPo/dpHvKit+tQn9Qlk5XFG1RiZTGqfk= -turso.tech/database/tursogo v0.5.0-pre.13 h1:W6334HVR4aRdvXiXQbG989Nt9724/KHLS14YlwyTbNw= -turso.tech/database/tursogo v0.5.0-pre.13/go.mod h1:L5TCwYwbWWIQngqDor8jzxy38XdxAm2/XDvUXRRs09Y= diff --git a/helm/kagent/templates/_helpers.tpl b/helm/kagent/templates/_helpers.tpl index ab894b9ab..7625a8610 100644 --- a/helm/kagent/templates/_helpers.tpl +++ b/helm/kagent/templates/_helpers.tpl @@ -115,11 +115,20 @@ Check if leader election should be enabled (more than 1 replica) {{- end -}} {{/* -Validate controller configuration +PostgreSQL service name for the bundled postgres instance */}} -{{- define "kagent.validateController" -}} -{{- if and (gt (.Values.controller.replicas | int) 1) (eq .Values.database.type "sqlite") -}} -{{- fail "ERROR: controller.replicas cannot be greater than 1 when database.type is 'sqlite' as the SQLite database is local to the pod. Please either set controller.replicas to 1 or change database.type to 'postgres'." }} +{{- define "kagent.postgresqlServiceName" -}} +{{- printf "%s-postgresql" (include "kagent.fullname" .) -}} +{{- end -}} + +{{/* +PostgreSQL URL - auto-computed from bundled config when url is empty, otherwise uses database.postgres.url +*/}} +{{- define "kagent.postgresqlUrl" -}} +{{- if not (eq .Values.database.postgres.url "") -}} +{{- .Values.database.postgres.url -}} +{{- else -}} +{{- printf "postgres://%s:%s@%s.%s.svc.cluster.local:5432/%s" .Values.database.postgres.bundled.user .Values.database.postgres.bundled.password (include "kagent.postgresqlServiceName" .) (include "kagent.namespace" .) .Values.database.postgres.bundled.database -}} {{- end -}} {{- end -}} diff --git a/helm/kagent/templates/controller-configmap.yaml b/helm/kagent/templates/controller-configmap.yaml index ed4ed0ecb..ffe2abc9e 100644 --- a/helm/kagent/templates/controller-configmap.yaml +++ b/helm/kagent/templates/controller-configmap.yaml @@ -7,7 +7,6 @@ metadata: {{- include "kagent.controller.labels" . | nindent 4 }} data: A2A_BASE_URL: {{ include "kagent.a2aBaseUrl" . | quote }} - DATABASE_TYPE: {{ .Values.database.type | quote }} DEFAULT_MODEL_CONFIG_NAME: {{ include "kagent.defaultModelConfigName" . | quote }} KAGENT_CONTROLLER_NAME: {{ include "kagent.fullname" . }}-controller IMAGE_PULL_POLICY: {{ .Values.controller.agentImage.pullPolicy | default .Values.imagePullPolicy | quote }} @@ -52,17 +51,12 @@ data: {{- if .Values.proxy.url }} PROXY_URL: {{ .Values.proxy.url | quote }} {{- end }} - {{- if eq .Values.database.type "sqlite" }} - SQLITE_DATABASE_PATH: /sqlite-volume/{{ .Values.database.sqlite.databaseName }} - DATABASE_VECTOR_ENABLED: {{ .Values.database.sqlite.vectorEnabled | default true | quote }} - {{- else if eq .Values.database.type "postgres" }} {{- if not (eq .Values.database.postgres.urlFile "") }} POSTGRES_DATABASE_URL_FILE: {{ .Values.database.postgres.urlFile | quote }} - {{- else if not (eq .Values.database.postgres.url "") }} - POSTGRES_DATABASE_URL: {{ .Values.database.postgres.url | quote }} - {{- end }} - DATABASE_VECTOR_ENABLED: {{ .Values.database.postgres.vectorEnabled | default true | quote }} + {{- else }} + POSTGRES_DATABASE_URL: {{ include "kagent.postgresqlUrl" . | quote }} {{- end }} + DATABASE_VECTOR_ENABLED: {{ .Values.database.postgres.vectorEnabled | quote }} STREAMING_INITIAL_BUF_SIZE: {{ .Values.controller.streaming.initialBufSize | quote }} STREAMING_MAX_BUF_SIZE: {{ .Values.controller.streaming.maxBufSize | quote }} STREAMING_TIMEOUT: {{ .Values.controller.streaming.timeout | quote }} diff --git a/helm/kagent/templates/controller-deployment.yaml b/helm/kagent/templates/controller-deployment.yaml index e8057ab98..b332a9e7a 100644 --- a/helm/kagent/templates/controller-deployment.yaml +++ b/helm/kagent/templates/controller-deployment.yaml @@ -1,4 +1,3 @@ -{{- include "kagent.validateController" . -}} apiVersion: apps/v1 kind: Deployment metadata: @@ -30,14 +29,8 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} serviceAccountName: {{ include "kagent.fullname" . }}-controller - {{- if or (eq .Values.database.type "sqlite") (gt (len .Values.controller.volumes) 0) }} + {{- if gt (len .Values.controller.volumes) 0 }} volumes: - {{- if eq .Values.database.type "sqlite" }} - - name: sqlite-volume - emptyDir: - sizeLimit: 500Mi - medium: Memory - {{- end }} {{- with .Values.controller.volumes }} {{- toYaml . | nindent 6 }} {{- end }} @@ -67,10 +60,6 @@ spec: valueFrom: fieldRef: fieldPath: spec.nodeName - {{- if eq .Values.database.type "sqlite" }} - - name: XDG_CACHE_HOME - value: /sqlite-volume/.cache - {{- end }} {{- with .Values.controller.env }} {{- toYaml . | nindent 12 }} {{- end }} @@ -101,12 +90,8 @@ spec: path: /health port: http periodSeconds: 30 - {{- if or (eq .Values.database.type "sqlite") (gt (len .Values.controller.volumeMounts) 0) }} + {{- if gt (len .Values.controller.volumeMounts) 0 }} volumeMounts: - {{- if eq .Values.database.type "sqlite" }} - - name: sqlite-volume - mountPath: /sqlite-volume - {{- end }} {{- with .Values.controller.volumeMounts }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/helm/kagent/templates/postgresql.yaml b/helm/kagent/templates/postgresql.yaml new file mode 100644 index 000000000..43ba99690 --- /dev/null +++ b/helm/kagent/templates/postgresql.yaml @@ -0,0 +1,90 @@ +{{- if and (eq .Values.database.postgres.url "") (eq .Values.database.postgres.urlFile "") }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "kagent.fullname" . }}-postgresql + namespace: {{ include "kagent.namespace" . }} + labels: + {{- include "kagent.labels" . | nindent 4 }} + app.kubernetes.io/component: postgresql +data: + POSTGRES_DB: {{ .Values.database.postgres.bundled.database | quote }} + POSTGRES_USER: {{ .Values.database.postgres.bundled.user | quote }} + POSTGRES_PASSWORD: {{ .Values.database.postgres.bundled.password | quote }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "kagent.fullname" . }}-postgresql + namespace: {{ include "kagent.namespace" . }} + labels: + {{- include "kagent.labels" . | nindent 4 }} + app.kubernetes.io/component: postgresql +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.database.postgres.bundled.storage | quote }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "kagent.fullname" . }}-postgresql + namespace: {{ include "kagent.namespace" . }} + labels: + {{- include "kagent.labels" . | nindent 4 }} + app.kubernetes.io/component: postgresql +spec: + replicas: 1 + selector: + matchLabels: + {{- include "kagent.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: postgresql + template: + metadata: + labels: + {{- include "kagent.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: postgresql + spec: + containers: + - name: postgresql + image: {{ .Values.database.postgres.bundled.image | quote }} + ports: + - containerPort: 5432 + envFrom: + - configMapRef: + name: {{ include "kagent.fullname" . }}-postgresql + volumeMounts: + - name: postgresql-storage + mountPath: /var/lib/postgresql + resources: + requests: + memory: "256Mi" + cpu: "250m" + limits: + memory: "512Mi" + cpu: "500m" + volumes: + - name: postgresql-storage + persistentVolumeClaim: + claimName: {{ include "kagent.fullname" . }}-postgresql +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "kagent.postgresqlServiceName" . }} + namespace: {{ include "kagent.namespace" . }} + labels: + {{- include "kagent.labels" . | nindent 4 }} + app.kubernetes.io/component: postgresql +spec: + selector: + {{- include "kagent.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: postgresql + ports: + - port: 5432 + targetPort: 5432 + type: ClusterIP +{{- end }} diff --git a/helm/kagent/tests/controller-deployment_test.yaml b/helm/kagent/tests/controller-deployment_test.yaml index 2b43c31be..b69140cd5 100644 --- a/helm/kagent/tests/controller-deployment_test.yaml +++ b/helm/kagent/tests/controller-deployment_test.yaml @@ -17,24 +17,11 @@ tests: - hasDocuments: count: 1 - - it: should fail when replicas > 1 and database type is sqlite + - it: should render the controller deployment with custom replica count template: controller-deployment.yaml set: controller: replicas: 3 - database: - type: sqlite - asserts: - - failedTemplate: - errorMessage: "ERROR: controller.replicas cannot be greater than 1 when database.type is 'sqlite' as the SQLite database is local to the pod. Please either set controller.replicas to 1 or change database.type to 'postgres'." - - - it: should render controller deployment with custom replica count if database type is postgres - template: controller-deployment.yaml - set: - controller: - replicas: 3 - database: - type: postgres asserts: - equal: path: spec.replicas @@ -194,11 +181,9 @@ tests: effect: NoSchedule operator: Equal - - it: should not render sqlite volume and mount when using postgres with extra volumes + - it: should render extra volumes and mounts when provided template: controller-deployment.yaml set: - database: - type: postgres controller: volumes: - name: extra-data @@ -207,34 +192,19 @@ tests: - name: extra-data mountPath: /extra asserts: - # volumes block should exist due to provided extra volumes - contains: path: spec.template.spec.volumes content: name: extra-data emptyDir: {} - # sqlite volume must not be present - - notContains: - path: spec.template.spec.volumes - content: - name: sqlite-volume - # volumeMounts block should include our extra mount - contains: path: spec.template.spec.containers[0].volumeMounts content: name: extra-data mountPath: /extra - # sqlite volume mount must not be present - - notContains: - path: spec.template.spec.containers[0].volumeMounts - content: - name: sqlite-volume - - it: should not render volumes or volumeMounts sections when using postgres without extra volumes or mounts + - it: should not render volumes or volumeMounts sections when none are configured template: controller-deployment.yaml - set: - database: - type: postgres asserts: - isNull: path: spec.template.spec.volumes diff --git a/helm/kagent/values.yaml b/helm/kagent/values.yaml index acd8c0b40..3726c3702 100644 --- a/helm/kagent/values.yaml +++ b/helm/kagent/values.yaml @@ -52,16 +52,24 @@ nodeSelector: {} # ============================================================================== database: - type: sqlite - sqlite: - vectorEnabled: true - databaseName: kagent.db postgres: - vectorEnabled: true - url: postgres://postgres:kagent@pgsql-postgresql.kagent.svc.cluster.local:5432/postgres - # Path to a file containing the database URL. - # Takes precedence over url when set. + # PostgreSQL connection string. Leave empty to deploy the bundled postgres instance. + # Set this to use an external PostgreSQL. + url: "" + # Path to a file containing the database URL. Takes precedence over url when set. + # Leave empty to use the bundled postgres instance. urlFile: "" + # Enable pgvector extension and memory table migration. + # Requires pgvector to be installed on the PostgreSQL server. + # Set to false when using an external PostgreSQL that does not have pgvector. + vectorEnabled: true + # Bundled PostgreSQL configuration — used when url and urlFile are both empty. + bundled: + image: pgvector/pgvector:pg18-trixie + storage: 500Mi + database: postgres + user: postgres + password: kagent # ============================================================================== # CONTROLLER CONFIGURATION From d47d955d4e99ccaa069dd1876729728f290c9319 Mon Sep 17 00:00:00 2001 From: Jeremy Alvis Date: Fri, 13 Mar 2026 11:09:55 -0700 Subject: [PATCH 2/4] Fix go lint error Signed-off-by: Jeremy Alvis --- go/core/internal/dbtest/dbtest.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/core/internal/dbtest/dbtest.go b/go/core/internal/dbtest/dbtest.go index 593a69dc3..59c879b33 100644 --- a/go/core/internal/dbtest/dbtest.go +++ b/go/core/internal/dbtest/dbtest.go @@ -7,9 +7,9 @@ import ( "testing" "time" - "github.com/testcontainers/testcontainers-go" - "github.com/testcontainers/testcontainers-go/wait" + testcontainers "github.com/testcontainers/testcontainers-go" tcpostgres "github.com/testcontainers/testcontainers-go/modules/postgres" + "github.com/testcontainers/testcontainers-go/wait" ) // Start starts a pgvector Postgres container and returns the connection string From 5b38d6fb69f0ff2d5cdae98307c0dfdf40f17ea4 Mon Sep 17 00:00:00 2001 From: Jeremy Alvis Date: Fri, 13 Mar 2026 12:46:29 -0700 Subject: [PATCH 3/4] Remove design doc Signed-off-by: Jeremy Alvis --- design/drop-sqlite.md | 155 ------------------------------------------ 1 file changed, 155 deletions(-) delete mode 100644 design/drop-sqlite.md diff --git a/design/drop-sqlite.md b/design/drop-sqlite.md deleted file mode 100644 index 9e74d5918..000000000 --- a/design/drop-sqlite.md +++ /dev/null @@ -1,155 +0,0 @@ ---- -status: Implemented -created: 2026-03-12 -updated: 2026-03-13 -authors: - - Jeremy Alvis - - Claude (Design Partner) ---- -# Drop SQLite — Postgres-Only Database - -## Overview - -Kagent currently supports two database backends: SQLite (the default) and PostgreSQL. This doc covers removing SQLite entirely so that PostgreSQL is the only supported backend, for both production deployments and local Kind clusters. - -This is in preparation for replacing GORM with explicit SQL migrations and sqlc. The two efforts are independent and can be sequenced in either order, but removing SQLite first simplifies the ORM migration by eliminating the need for per-dialect SQL files and a second sqlc configuration. - -## Goals and Non-Goals - -### Goals - -- PostgreSQL is the only supported database backend -- Local Kind cluster development (`make helm-install`) deploys a bundled PostgreSQL instance automatically — no manual prerequisites -- Unit tests use testcontainers-go to spin up a real Postgres instance (no in-memory SQLite) -- `--database-vector-enabled` flag is retained (default `true`) so external PostgreSQL users without pgvector can opt out of memory features without a hard crash at startup -- SQLite Go dependencies (`glebarez/sqlite`, `turso.tech/tursogo`) are removed from `go.mod` -- CI E2E matrix simplified — `database: [sqlite, postgres]` matrix removed entirely (single-value matrices serve no purpose) - -## Current State (Before This Change) - -### What uses SQLite today - -| Location | What it does | -|----------|--------------| -| `go/core/internal/database/manager.go` | Switches between SQLite and Postgres based on `--database-type` flag; SQLite path uses Turso driver, sets `MaxOpenConns(1)`, manual vector table DDL using `F32_BLOB(768)` | -| `go/core/internal/database/client.go` | `SearchAgentMemory` branches on `db.Name() == "sqlite"` to use `vector_distance_cos(embedding, vector32(?))` instead of pgvector `<=>` operator; `deleteAgentMemoryByQuery` uses a Turso-specific two-step delete (Pluck IDs + `DELETE WHERE id IN ?`) to avoid a libSQL multi-index scan bug; `SearchCrewAIMemoryByTask` uses `JSON_EXTRACT` (MySQL syntax) in both the WHERE clause and ORDER BY — this is a pre-existing bug that is currently masked because the Postgres E2E tests don't exercise this path | -| `go/core/internal/database/client_test.go` | All unit tests use in-memory SQLite (`:memory:`) via two helpers: `setupTestDB` (line 205) and `setupVectorTestDB` (line 319) | -| `go/core/pkg/app/app.go` | Registers `--database-type`, `--sqlite-database-path`, `--database-vector-enabled` flags; default is `sqlite` | -| `helm/kagent/values.yaml` | `database.type: sqlite` is the default; SQLite path has a `vectorEnabled` flag | -| `helm/kagent/templates/controller-deployment.yaml` | Conditionally creates an `emptyDir` volume (500Mi memory) and mounts it at `/sqlite-volume` when `database.type == "sqlite"`; sets `XDG_CACHE_HOME=/sqlite-volume/.cache` | -| `helm/kagent/templates/controller-configmap.yaml` | Conditionally sets `SQLITE_DATABASE_PATH` and `DATABASE_VECTOR_ENABLED` env vars | -| `.github/workflows/ci.yaml` | E2E test matrix: `database: [sqlite, postgres]` | -| `go/go.mod` | `github.com/glebarez/sqlite v1.11.0`, `turso.tech/database/tursogo v0.5.0-pre.13` | -| `contrib/addons/postgres.yaml` | Optional dev-only addon; `make kagent-addon-install` installs it alongside Grafana and Prometheus | - -### Inconsistent Postgres default URLs - -Three places defined a default Postgres URL and none of them agreed: - -| Location | Before | After | -|----------|--------|-------| -| `helm/kagent/values.yaml` | `pgsql-postgresql.kagent.svc.cluster.local:5432/postgres` | `""` — auto-computed from bundled service (`kagent-postgresql`) | -| `go/core/pkg/app/app.go` flag default | `db.kagent.svc.cluster.local:5432/crud` | `kagent-postgresql.kagent.svc.cluster.local:5432/postgres` | -| `DEVELOPMENT.md` | `postgres.kagent.svc.cluster.local:5432/kagent` | Removed — postgres is now deployed by `make helm-install` | - -## Changes - -### 1. Go: Remove SQLite from manager.go - -- Remove `DatabaseTypeSqlite` constant and `SqliteConfig` struct -- Remove the SQLite case from the database init switch (Turso driver open, `SetMaxOpenConns(1)`) -- Remove the SQLite vector table DDL block (the `F32_BLOB` / `idx_memory_agent_user` creation) -- The Postgres path is now the only path; direct initialization replaces the switch - -### 2. Go: Remove SQLite branch and fix Postgres bugs in client.go - -- Remove the `if db.Name() == "sqlite"` branch in `SearchAgentMemory` — the pgvector `<=>` cosine similarity path is the only path -- Simplify `deleteAgentMemoryByQuery` — remove the two-step Pluck + `DELETE WHERE id IN ?` workaround. The workaround was specific to a Turso multi-index scan bug and is unnecessary on Postgres -- Fix `SearchCrewAIMemoryByTask` — replace `JSON_EXTRACT(memory_data, '$.task_description')` and `JSON_EXTRACT(memory_data, '$.score')` with the Postgres JSONB operator equivalent (`memory_data->>'task_description'`, `memory_data->>'score'`). `JSON_EXTRACT` is MySQL syntax and errors on Postgres. This is a pre-existing bug masked by the SQLite E2E tests. - -### 3. Go: Update app.go flags and manager.go config structs - -**app.go:** -- Remove `--database-type` flag and `DATABASE_TYPE` env var -- Remove `--sqlite-database-path` flag and `SQLITE_DATABASE_PATH` env var -- Retain `--database-vector-enabled` flag (default `true`) — see [decision note below](#decision-retain---database-vector-enabled) -- Fix the `--postgres-database-url` default to match the bundled Helm postgres service - -**manager.go:** -- Retain `PostgresConfig.VectorEnabled` field (same rationale) -- The `if VectorEnabled` guard controls `CREATE EXTENSION IF NOT EXISTS vector`, memory table migration, and HNSW index creation - -### 4. Go: Replace in-memory SQLite unit tests with testcontainers-go - -- Add `github.com/testcontainers/testcontainers-go` and `testcontainers-go/modules/postgres` to `go/core/go.mod` -- Create `go/core/internal/dbtest/dbtest.go` — shared helper that starts a `pgvector/pgvector:pg18-trixie` container with `testcontainers.WithReuseByName("kagent-dbtest-postgres")` and a `wait.ForLog` readiness strategy (waits for `"database system is ready to accept connections"` twice) -- `TestMain` in `database/` package starts the shared container once; `setupTestDB` calls `Reset(true)` between tests instead of creating a new manager per test — avoids "connection reset by peer" from rapid pool cycling -- `testing.Short()` skips database tests when run without Docker; `flag.Parse()` called before `testing.Short()` in `TestMain` (required by the testing package) - -### 5. Go: Remove SQLite dependencies - -Remove from `go/go.mod`: -- `github.com/glebarez/sqlite v1.11.0` -- `github.com/glebarez/go-sqlite v1.21.2` (indirect) -- `turso.tech/database/tursogo v0.5.0-pre.13` - -### 6. Helm: Remove SQLite config, add bundled PostgreSQL - -**`helm/kagent/values.yaml`:** -- Remove `database.type` field and `database.sqlite` section -- `database.postgres.url` defaults to `""` — leave empty to use the bundled postgres, set to use external -- Retain `database.postgres.urlFile` — takes precedence over `url` when set -- Retain `database.postgres.vectorEnabled: true` -- Add `database.postgres.bundled` sub-key for bundled instance config (image, storage, database, user, password) - -**`helm/kagent/templates/controller-deployment.yaml`:** -- Remove the `{{- if eq .Values.database.type "sqlite" }}` conditional volume block (emptyDir, 500Mi) -- Remove the volumeMount block (`/sqlite-volume`) and `XDG_CACHE_HOME` env var - -**`helm/kagent/templates/controller-configmap.yaml`:** -- Remove `DATABASE_TYPE` and `SQLITE_DATABASE_PATH` entries -- `POSTGRES_DATABASE_URL_FILE` set when `urlFile` is non-empty; otherwise `POSTGRES_DATABASE_URL` uses `include "kagent.postgresqlUrl"` helper - -**`helm/kagent/templates/_helpers.tpl`:** -- Remove `kagent.validateController` helper (blocked renders when `replicas > 1 AND database.type == "sqlite"`) -- Add `kagent.postgresqlServiceName` and `kagent.postgresqlUrl` helpers — `postgresqlUrl` returns `database.postgres.url` when set, otherwise auto-computes from bundled config - -**`helm/kagent/templates/postgresql.yaml`** (new): -- Templated version of the former `contrib/addons/postgres.yaml` -- Renders when `database.postgres.url` and `database.postgres.urlFile` are both empty -- Deploys ConfigMap, PVC, Deployment, and Service for `pgvector/pgvector:pg18-trixie` - -**`helm/kagent/tests/controller-deployment_test.yaml`:** -- Remove test case "should fail when replicas > 1 and database type is sqlite" -- Remove SQLite volume/mount test cases - -### 7. CI: Remove E2E matrix - -Remove `strategy.matrix` from `test-e2e` entirely. A `database: [postgres]` single-value matrix runs the job once with no variation — it is equivalent to no matrix. Remove the Postgres service container block as well; postgres is deployed inside the Kind cluster by `make helm-install`. - -### 8. Local Kind setup: Postgres bundled in Helm chart - -**Decision: built-in chart templates** (`helm/kagent/templates/postgresql.yaml`). - -Options considered: - -| Option | Decision | -|--------|----------| -| Built-in chart templates (chosen) | Move `contrib/addons/postgres.yaml` into `helm/kagent/templates/`. Renders when `database.postgres.url` and `urlFile` are both empty — the same condition users already knew: leave `url` empty for local dev, set it for production. No external deps, no separate install step. Works with Argo CD, Flux, and any Helm-based deploy, not just the Makefile. | -| Bitnami postgresql subchart | More feature-rich (backups, HA, etc.) but heavy for a dev dependency and ties the chart to an external chart release cycle. Overkill for a bundled dev/default postgres. | -| Separate kagent-postgres chart | Mirrors the kagent-crds pattern. Cleaner separation but adds install complexity (`helm install kagent-postgres` then `helm install kagent`). | -| Keep in contrib, Makefile applies it | What existed before. Works for local dev but breaks pure Helm installs -- i.e. anyone not using the Makefile. | - -Production users set `database.postgres.url` (or `database.postgres.urlFile` for Secret-mounted credentials) — the same configuration they already provided. The bundled postgres simply does not deploy. - -Delete `contrib/addons/postgres.yaml`. Remove postgres from `make kagent-addon-install`. - -## Decision: Retain `--database-vector-enabled` - -The original design called for removing this flag (pgvector always-on). Retain it for the following reason: - -Without the flag, any external PostgreSQL instance without the pgvector extension installed causes the controller to crash at startup with `failed to create vector extension`. This is a hard prerequisite that external users may not anticipate. - -With the flag (default `true`), users running external Postgres without pgvector can set `database.postgres.vectorEnabled: false` (or `DATABASE_VECTOR_ENABLED=false`) to skip extension creation and run without memory/vector support. This is a softer failure mode and a better operator experience. - -The bundled postgres uses `pgvector/pgvector:pg18-trixie` and always has the extension available, so the default `true` is correct for the common case. From d483f110d509721cc468f4fcd41b0dd867ceaa44 Mon Sep 17 00:00:00 2001 From: Jeremy Alvis Date: Mon, 16 Mar 2026 07:23:48 -0700 Subject: [PATCH 4/4] Remove Turso-specific lines Signed-off-by: Jeremy Alvis --- go/.gitignore | 3 --- go/Dockerfile | 5 ++--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/go/.gitignore b/go/.gitignore index c437b0d91..785401d67 100644 --- a/go/.gitignore +++ b/go/.gitignore @@ -24,6 +24,3 @@ Dockerfile.cross *.swp *.swo *~ - -# turso -file::* diff --git a/go/Dockerfile b/go/Dockerfile index c01cd972d..5e506e651 100644 --- a/go/Dockerfile +++ b/go/Dockerfile @@ -30,10 +30,9 @@ RUN --mount=type=cache,target=/root/go/pkg/mod,rw \ CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -ldflags "$LDFLAGS" -o /app "$BUILD_PACKAGE" ### STAGE 2: final image -# Use distroless/cc-debian12 which includes C/C++ runtime libraries -# This is required for turso-go's purego library loading +# Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details -FROM gcr.io/distroless/cc-debian12:nonroot +FROM gcr.io/distroless/static:nonroot ARG TARGETPLATFORM WORKDIR /