feat(config): add typed resource schema
This commit is contained in:
@@ -0,0 +1,105 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
|
from tht.cli import app
|
||||||
|
from tht.config import load_config
|
||||||
|
|
||||||
|
|
||||||
|
def _write_old_workspace(tmp_path):
|
||||||
|
path = tmp_path / "old.yaml"
|
||||||
|
path.write_text(
|
||||||
|
"""
|
||||||
|
database:
|
||||||
|
host: ignored-for-rest
|
||||||
|
database: analytics
|
||||||
|
schema: mart
|
||||||
|
user: legacy-user
|
||||||
|
password: legacy-password
|
||||||
|
transport: rest
|
||||||
|
rest:
|
||||||
|
base_url: https://dwh.example.test/
|
||||||
|
api_key: dwh-reader
|
||||||
|
vector_db:
|
||||||
|
host: vector-db
|
||||||
|
database: postgres
|
||||||
|
schema: vectors
|
||||||
|
user: vector-user
|
||||||
|
password: vector-password
|
||||||
|
vector_rest:
|
||||||
|
base_url: https://vectors.example.test/
|
||||||
|
api_key: vector-reader
|
||||||
|
vector_write_rest:
|
||||||
|
base_url: https://vectors.example.test/
|
||||||
|
api_key: vector-writer
|
||||||
|
paths:
|
||||||
|
artifacts: build/artifacts
|
||||||
|
indexes: build/indexes
|
||||||
|
sessions: build/sessions
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def _write_new_workspace(tmp_path):
|
||||||
|
path = tmp_path / "new.yaml"
|
||||||
|
path.write_text(
|
||||||
|
"""
|
||||||
|
dwh:
|
||||||
|
type: thoth_rest
|
||||||
|
database:
|
||||||
|
database: analytics
|
||||||
|
schema: mart
|
||||||
|
endpoint:
|
||||||
|
base_url: https://dwh.example.test/
|
||||||
|
api_key: dwh-reader
|
||||||
|
vectors:
|
||||||
|
type: thoth_vector_http
|
||||||
|
reader:
|
||||||
|
base_url: https://vectors.example.test/
|
||||||
|
api_key: vector-reader
|
||||||
|
writer:
|
||||||
|
base_url: https://vectors.example.test/
|
||||||
|
api_key: vector-writer
|
||||||
|
direct:
|
||||||
|
host: vector-db
|
||||||
|
database: postgres
|
||||||
|
schema: vectors
|
||||||
|
user: vector-user
|
||||||
|
password: vector-password
|
||||||
|
roots:
|
||||||
|
artifacts: build/artifacts
|
||||||
|
indexes: build/indexes
|
||||||
|
sessions: build/sessions
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def test_legacy_rest_workspace_equals_new_resource_schema(tmp_path, capsys):
|
||||||
|
with pytest.warns(FutureWarning, match="DEPRECATION") as warnings:
|
||||||
|
old = load_config(_write_old_workspace(tmp_path))
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
new = load_config(_write_new_workspace(tmp_path))
|
||||||
|
|
||||||
|
assert old.dwh.model_dump() == new.dwh.model_dump()
|
||||||
|
assert old.vectors.model_dump() == new.vectors.model_dump()
|
||||||
|
assert old.roots.model_dump() == new.roots.model_dump()
|
||||||
|
assert captured.out == ""
|
||||||
|
assert captured.err == ""
|
||||||
|
assert len(warnings) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_legacy_warning_does_not_contaminate_cli_json(tmp_path):
|
||||||
|
with pytest.warns(FutureWarning, match="DEPRECATION") as warnings:
|
||||||
|
result = CliRunner().invoke(
|
||||||
|
app,
|
||||||
|
["session", "list", "--json", "-c", str(_write_old_workspace(tmp_path))],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.exit_code == 0
|
||||||
|
json.loads(result.stdout)
|
||||||
|
assert "DEPRECATION" not in result.stdout
|
||||||
|
assert result.stderr == ""
|
||||||
|
assert len(warnings) == 1
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
from tht.config import (
|
||||||
|
PgvectorDirectConfig,
|
||||||
|
PostgresDwhConfig,
|
||||||
|
ThothRestDwhConfig,
|
||||||
|
ThothVectorHttpConfig,
|
||||||
|
load_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_loads_discriminated_dwh_and_vector_resources(tmp_path):
|
||||||
|
workspace = tmp_path / "workspace.yaml"
|
||||||
|
workspace.write_text(
|
||||||
|
"""
|
||||||
|
dwh:
|
||||||
|
type: thoth_rest
|
||||||
|
database:
|
||||||
|
database: analytics
|
||||||
|
schema: mart
|
||||||
|
endpoint:
|
||||||
|
base_url: https://dwh.example.test/
|
||||||
|
api_key: dwh-reader
|
||||||
|
vectors:
|
||||||
|
type: thoth_vector_http
|
||||||
|
reader:
|
||||||
|
base_url: https://vectors.example.test/
|
||||||
|
api_key: vector-reader
|
||||||
|
writer:
|
||||||
|
base_url: https://vectors.example.test/
|
||||||
|
api_key: vector-writer
|
||||||
|
roots:
|
||||||
|
artifacts: build/artifacts
|
||||||
|
indexes: build/indexes
|
||||||
|
sessions: build/sessions
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
cfg = load_config(workspace)
|
||||||
|
|
||||||
|
assert isinstance(cfg.dwh, ThothRestDwhConfig)
|
||||||
|
assert cfg.dwh.database.db_schema == "mart"
|
||||||
|
assert isinstance(cfg.vectors, ThothVectorHttpConfig)
|
||||||
|
assert cfg.vectors.writer.api_key == "vector-writer"
|
||||||
|
assert cfg.roots.sessions.as_posix() == "build/sessions"
|
||||||
|
|
||||||
|
|
||||||
|
def test_loads_direct_discriminated_resources(tmp_path):
|
||||||
|
workspace = tmp_path / "workspace.yaml"
|
||||||
|
workspace.write_text(
|
||||||
|
"""
|
||||||
|
dwh:
|
||||||
|
type: postgres_direct
|
||||||
|
connection: &database
|
||||||
|
host: db
|
||||||
|
database: analytics
|
||||||
|
schema: mart
|
||||||
|
user: reader
|
||||||
|
password: secret
|
||||||
|
vectors:
|
||||||
|
type: pgvector_direct
|
||||||
|
connection:
|
||||||
|
<<: *database
|
||||||
|
schema: vectors
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
cfg = load_config(workspace)
|
||||||
|
|
||||||
|
assert isinstance(cfg.dwh, PostgresDwhConfig)
|
||||||
|
assert cfg.database.transport == "direct"
|
||||||
|
assert isinstance(cfg.vectors, PgvectorDirectConfig)
|
||||||
|
assert cfg.vector_db.db_schema == "vectors"
|
||||||
+102
-3
@@ -1,10 +1,13 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Literal
|
from typing import Annotated, Any, Literal
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from pydantic import BaseModel, Field, ValidationError
|
from pydantic import BaseModel, Field, model_validator, ValidationError
|
||||||
|
|
||||||
|
from tht.config_compat import translate_legacy_config
|
||||||
|
|
||||||
_ENV_RE = re.compile(r"\$\{([A-Za-z_][A-Za-z0-9_]*)\}")
|
_ENV_RE = re.compile(r"\$\{([A-Za-z_][A-Za-z0-9_]*)\}")
|
||||||
|
|
||||||
@@ -56,12 +59,59 @@ class RestConfig(BaseModel):
|
|||||||
ssl_ca: str | None = None # path al certificato CA (per server con CA interna)
|
ssl_ca: str | None = None # path al certificato CA (per server con CA interna)
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseIdentityConfig(BaseModel):
|
||||||
|
database: str
|
||||||
|
db_schema: str = Field(alias="schema")
|
||||||
|
|
||||||
|
model_config = {"populate_by_name": True}
|
||||||
|
|
||||||
|
|
||||||
|
class PostgresDwhConfig(BaseModel):
|
||||||
|
type: Literal["postgres_direct"]
|
||||||
|
connection: DatabaseConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ThothRestDwhConfig(BaseModel):
|
||||||
|
type: Literal["thoth_rest"]
|
||||||
|
database: DatabaseIdentityConfig
|
||||||
|
endpoint: RestConfig
|
||||||
|
|
||||||
|
|
||||||
|
DwhResourceConfig = Annotated[
|
||||||
|
PostgresDwhConfig | ThothRestDwhConfig,
|
||||||
|
Field(discriminator="type"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class PgvectorDirectConfig(BaseModel):
|
||||||
|
type: Literal["pgvector_direct"]
|
||||||
|
connection: DatabaseConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ThothVectorHttpConfig(BaseModel):
|
||||||
|
type: Literal["thoth_vector_http"]
|
||||||
|
reader: RestConfig | None = None
|
||||||
|
writer: RestConfig | None = None
|
||||||
|
# Transitional direct loading path used by the server profile.
|
||||||
|
direct: DatabaseConfig | None = None
|
||||||
|
|
||||||
|
|
||||||
|
VectorResourceConfig = Annotated[
|
||||||
|
PgvectorDirectConfig | ThothVectorHttpConfig,
|
||||||
|
Field(discriminator="type"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class PathsConfig(BaseModel):
|
class PathsConfig(BaseModel):
|
||||||
artifacts: Path = Path("artifacts")
|
artifacts: Path = Path("artifacts")
|
||||||
indexes: Path = Path("indexes")
|
indexes: Path = Path("indexes")
|
||||||
sessions: Path = Path("sessions")
|
sessions: Path = Path("sessions")
|
||||||
|
|
||||||
|
|
||||||
|
class WorkspaceRoots(PathsConfig):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ExamplesConfig(BaseModel):
|
class ExamplesConfig(BaseModel):
|
||||||
max_per_column: int = 10
|
max_per_column: int = 10
|
||||||
|
|
||||||
@@ -138,6 +188,10 @@ class ExecutionConfig(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class Config(BaseModel):
|
class Config(BaseModel):
|
||||||
|
dwh: DwhResourceConfig
|
||||||
|
vectors: VectorResourceConfig | None = None
|
||||||
|
roots: WorkspaceRoots = WorkspaceRoots()
|
||||||
|
# Compatibility views retained until all call sites consume typed resources.
|
||||||
database: DatabaseConfig
|
database: DatabaseConfig
|
||||||
# Profilo dell'installazione, letto da THT_PROFILE (.env), non dallo yaml versionato.
|
# Profilo dell'installazione, letto da THT_PROFILE (.env), non dallo yaml versionato.
|
||||||
# server: ricostruisce i derivati (artefatti, LSH, vettori schema nel vectordb).
|
# server: ricostruisce i derivati (artefatti, LSH, vettori schema nel vectordb).
|
||||||
@@ -166,6 +220,15 @@ class Config(BaseModel):
|
|||||||
# una API key separata dalla lettura; espone solo upsert/hash via RPC allowlist.
|
# una API key separata dalla lettura; espone solo upsert/hash via RPC allowlist.
|
||||||
vector_write_rest: RestConfig | None = None
|
vector_write_rest: RestConfig | None = None
|
||||||
|
|
||||||
|
@model_validator(mode="before")
|
||||||
|
@classmethod
|
||||||
|
def accept_legacy_constructor_fields(cls, value: Any) -> Any:
|
||||||
|
if not isinstance(value, dict) or "dwh" in value:
|
||||||
|
return value
|
||||||
|
translated, _ = translate_legacy_config(value)
|
||||||
|
_populate_legacy_views(translated)
|
||||||
|
return translated
|
||||||
|
|
||||||
|
|
||||||
def load_config(path: Path) -> Config:
|
def load_config(path: Path) -> Config:
|
||||||
if not path.exists():
|
if not path.exists():
|
||||||
@@ -173,8 +236,11 @@ def load_config(path: Path) -> Config:
|
|||||||
raw = yaml.safe_load(path.read_text())
|
raw = yaml.safe_load(path.read_text())
|
||||||
if not isinstance(raw, dict):
|
if not isinstance(raw, dict):
|
||||||
raise ConfigError(f"Configurazione non valida (atteso un mapping YAML): {path}")
|
raise ConfigError(f"Configurazione non valida (atteso un mapping YAML): {path}")
|
||||||
|
expanded = _expand_env(raw)
|
||||||
|
translated, used_legacy = translate_legacy_config(expanded)
|
||||||
|
_populate_legacy_views(translated)
|
||||||
try:
|
try:
|
||||||
cfg = Config.model_validate(_expand_env(raw))
|
cfg = Config.model_validate(translated)
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
raise ConfigError(f"Configurazione non valida in {path}:\n{e}") from e
|
raise ConfigError(f"Configurazione non valida in {path}:\n{e}") from e
|
||||||
env_profile = os.environ.get("THT_PROFILE")
|
env_profile = os.environ.get("THT_PROFILE")
|
||||||
@@ -188,4 +254,37 @@ def load_config(path: Path) -> Config:
|
|||||||
raise ConfigError(
|
raise ConfigError(
|
||||||
f"transport: rest richiede la sezione `rest` (base_url, api_key) in {path}."
|
f"transport: rest richiede la sezione `rest` (base_url, api_key) in {path}."
|
||||||
)
|
)
|
||||||
|
if used_legacy:
|
||||||
|
warnings.warn(
|
||||||
|
"DEPRECATION: legacy workspace resource keys are deprecated; "
|
||||||
|
"use dwh, vectors, and roots.",
|
||||||
|
FutureWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
|
def _populate_legacy_views(raw: dict[str, Any]) -> None:
|
||||||
|
"""Populate old Config attributes for command compatibility during migration."""
|
||||||
|
dwh = raw.get("dwh")
|
||||||
|
if "database" not in raw and isinstance(dwh, dict):
|
||||||
|
if dwh.get("type") == "postgres_direct":
|
||||||
|
raw["database"] = {**dwh["connection"], "transport": "direct"}
|
||||||
|
elif dwh.get("type") == "thoth_rest":
|
||||||
|
raw["database"] = {
|
||||||
|
**dwh["database"],
|
||||||
|
"user": "rest",
|
||||||
|
"password": "",
|
||||||
|
"transport": "rest",
|
||||||
|
}
|
||||||
|
raw["rest"] = dwh["endpoint"]
|
||||||
|
|
||||||
|
vectors = raw.get("vectors")
|
||||||
|
if isinstance(vectors, dict):
|
||||||
|
if vectors.get("type") == "pgvector_direct":
|
||||||
|
raw.setdefault("vector_db", vectors["connection"])
|
||||||
|
elif vectors.get("type") == "thoth_vector_http":
|
||||||
|
raw.setdefault("vector_rest", vectors.get("reader"))
|
||||||
|
raw.setdefault("vector_write_rest", vectors.get("writer"))
|
||||||
|
raw.setdefault("vector_db", vectors.get("direct"))
|
||||||
|
raw.setdefault("paths", raw.get("roots", {}))
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
_LEGACY_RESOURCE_KEYS = {
|
||||||
|
"database",
|
||||||
|
"rest",
|
||||||
|
"vector_db",
|
||||||
|
"vector_rest",
|
||||||
|
"vector_write_rest",
|
||||||
|
"paths",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _as_mapping(value: Any) -> dict[str, Any] | None:
|
||||||
|
if isinstance(value, dict):
|
||||||
|
return deepcopy(value)
|
||||||
|
model_dump = getattr(value, "model_dump", None)
|
||||||
|
if callable(model_dump):
|
||||||
|
return model_dump(by_alias=True)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def translate_legacy_config(raw: dict[str, Any]) -> tuple[dict[str, Any], bool]:
|
||||||
|
"""Translate the legacy flat resource keys without validating their contents."""
|
||||||
|
translated = deepcopy(raw)
|
||||||
|
legacy = any(key in raw for key in _LEGACY_RESOURCE_KEYS)
|
||||||
|
if not legacy:
|
||||||
|
return translated, False
|
||||||
|
|
||||||
|
database = _as_mapping(raw.get("database"))
|
||||||
|
rest = raw.get("rest")
|
||||||
|
if "dwh" not in translated and database is not None:
|
||||||
|
if database.get("transport", "direct") == "rest":
|
||||||
|
identity = {
|
||||||
|
key: database[key]
|
||||||
|
for key in ("database", "schema")
|
||||||
|
if key in database
|
||||||
|
}
|
||||||
|
translated["dwh"] = {
|
||||||
|
"type": "thoth_rest",
|
||||||
|
"database": identity,
|
||||||
|
"endpoint": rest,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
connection = database
|
||||||
|
connection.pop("transport", None)
|
||||||
|
translated["dwh"] = {
|
||||||
|
"type": "postgres_direct",
|
||||||
|
"connection": connection,
|
||||||
|
}
|
||||||
|
|
||||||
|
if "vectors" not in translated:
|
||||||
|
vector_db = raw.get("vector_db")
|
||||||
|
reader = raw.get("vector_rest")
|
||||||
|
writer = raw.get("vector_write_rest")
|
||||||
|
if reader is not None or writer is not None:
|
||||||
|
translated["vectors"] = {
|
||||||
|
"type": "thoth_vector_http",
|
||||||
|
"reader": reader,
|
||||||
|
"writer": writer,
|
||||||
|
"direct": vector_db,
|
||||||
|
}
|
||||||
|
elif vector_db is not None:
|
||||||
|
translated["vectors"] = {
|
||||||
|
"type": "pgvector_direct",
|
||||||
|
"connection": vector_db,
|
||||||
|
}
|
||||||
|
|
||||||
|
if "roots" not in translated and "paths" in raw:
|
||||||
|
translated["roots"] = deepcopy(raw["paths"])
|
||||||
|
return translated, True
|
||||||
@@ -1,26 +1,19 @@
|
|||||||
# Workspace ThothII (esempio). I segreti vivono SOLO in .env (${THT_*}).
|
# Workspace ThothII (esempio). I segreti vivono SOLO in .env (${THT_*}).
|
||||||
# La struttura rispecchia esattamente tht/config.py:
|
# Ogni risorsa dichiara il proprio adapter tramite `type`.
|
||||||
# database + rest per il DWH; vector_rest/vector_write_rest per il pgvector (doppia key);
|
|
||||||
# vector_db per il loading diretto (server-only); embeddings + evidence + execution.
|
|
||||||
|
|
||||||
language: it # descrizioni tabelle/colonne ed evidence sono in italiano (PSD)
|
language: it # descrizioni tabelle/colonne ed evidence sono in italiano (PSD)
|
||||||
|
|
||||||
database:
|
dwh:
|
||||||
host: ${THT_DB_HOST}
|
type: thoth_rest # postgres_direct | thoth_rest
|
||||||
port: ${THT_DB_PORT} # es. 5437 (Postgres diretto Supabase; 5432 = pooler)
|
database:
|
||||||
database: ${THT_DB_NAME} # es. postgres (lo schema a stella vive in `datawarehouse`)
|
database: ${THT_DB_NAME}
|
||||||
schema: datawarehouse
|
schema: datawarehouse
|
||||||
user: ${THT_DB_USER}
|
endpoint:
|
||||||
password: ${THT_DB_PASSWORD}
|
base_url: ${THT_DWH_REST_URL}
|
||||||
transport: rest # direct (Postgres) | rest (Supabase/PostgREST)
|
api_key: ${THT_DWH_API_KEY}
|
||||||
|
ssl_ca: ${THT_SSL_CA}
|
||||||
|
|
||||||
# Accesso al DWH via REST (richiesto se database.transport = rest).
|
roots:
|
||||||
rest:
|
|
||||||
base_url: ${THT_DWH_REST_URL} # es. https://supabase-aritmolab.policlinicosandonato.it/dwh/
|
|
||||||
api_key: ${THT_DWH_API_KEY} # header X-API-Key, ruolo dwh_reader (read-only)
|
|
||||||
ssl_ca: ${THT_SSL_CA} # path al certificato CA (per server con CA interna)
|
|
||||||
|
|
||||||
paths:
|
|
||||||
artifacts: artifacts
|
artifacts: artifacts
|
||||||
indexes: indexes
|
indexes: indexes
|
||||||
sessions: sessions
|
sessions: sessions
|
||||||
@@ -50,30 +43,23 @@ embeddings:
|
|||||||
dim: 768
|
dim: 768
|
||||||
batch_size: 32
|
batch_size: 32
|
||||||
|
|
||||||
# LOADING del pgvector: connessione diretta, eseguita sul server (profilo server).
|
vectors:
|
||||||
# Opzionale su postazione remota (lì la lettura passa da vector_rest).
|
type: thoth_vector_http # pgvector_direct | thoth_vector_http
|
||||||
vector_db:
|
reader:
|
||||||
host: ${THT_VEC_HOST} # Postgres locale del server
|
base_url: ${THT_VEC_REST_URL}
|
||||||
port: ${THT_VEC_PORT} # es. 5437
|
api_key: ${THT_VEC_API_KEY}
|
||||||
database: postgres
|
ssl_ca: ${THT_SSL_CA}
|
||||||
schema: vectors
|
writer: # opzionale: credenziale separata dalla lettura
|
||||||
user: ${THT_VEC_USER}
|
base_url: ${THT_VEC_REST_URL}
|
||||||
password: ${THT_VEC_PASSWORD}
|
api_key: ${THT_VEC_WRITE_API_KEY}
|
||||||
|
ssl_ca: ${THT_SSL_CA}
|
||||||
# LETTURA (similarity search) del pgvector via REST remota: rpc search_similar.
|
direct: # opzionale: loading server-side diretto
|
||||||
vector_rest:
|
host: ${THT_VEC_HOST}
|
||||||
base_url: ${THT_VEC_REST_URL} # es. https://host/vector/v1/
|
port: ${THT_VEC_PORT}
|
||||||
api_key: ${THT_VEC_API_KEY} # header X-API-Key, ruolo vector_reader (read-only)
|
database: postgres
|
||||||
ssl_ca: ${THT_SSL_CA}
|
schema: vectors
|
||||||
|
user: ${THT_VEC_USER}
|
||||||
# SCRITTURA controllata del pgvector via REST remota: upsert/hash via RPC allowlist,
|
password: ${THT_VEC_PASSWORD}
|
||||||
# niente delete/clear. Usa una API key SEPARATA dalla lettura (ruolo vector_writer).
|
|
||||||
# OPZIONALE: assente o key vuota = scrittura non abilitata (solo lettura).
|
|
||||||
# Abilita tht memory save-one / vector index-schema da postazione remota.
|
|
||||||
vector_write_rest:
|
|
||||||
base_url: ${THT_VEC_REST_URL}
|
|
||||||
api_key: ${THT_VEC_WRITE_API_KEY}
|
|
||||||
ssl_ca: ${THT_SSL_CA}
|
|
||||||
|
|
||||||
vector:
|
vector:
|
||||||
max_chunk_chars: 4000
|
max_chunk_chars: 4000
|
||||||
|
|||||||
Reference in New Issue
Block a user