feat: harden runtime readiness and session workflow
This commit is contained in:
@@ -145,11 +145,11 @@ def save_one_cmd(
|
||||
json_out: bool = typer.Option(False, "--json", help="Output JSON (per Pi)."),
|
||||
config: Path = CONFIG_OPT,
|
||||
) -> None:
|
||||
"""Upsert mirato (una riga) della memoria di una decisione su pgvector via writer key (D11).
|
||||
"""Upsert mirato (una riga) della memoria di una decisione su pgvector (D11).
|
||||
|
||||
Promuove la decisione nel registro locale (idempotente) e fa un singolo upsert
|
||||
remoto con dedup hash client-side -- niente full-resync. Abilita il salvataggio
|
||||
di una memoria da postazione remota (workstation) con la sola writer key.
|
||||
con dedup hash client-side -- niente full-resync. Il factory seleziona il writer
|
||||
REST su workstation oppure il writer pgvector diretto sul profilo server.
|
||||
"""
|
||||
import json as _json
|
||||
|
||||
@@ -160,13 +160,6 @@ def save_one_cmd(
|
||||
cfg = _load_config_or_exit(config)
|
||||
manifest = load_session_or_exit(cfg, session)
|
||||
require_vector_write_allowed(cfg, "memory save-one")
|
||||
if not has_vector_write_rest(cfg):
|
||||
typer.secho(
|
||||
"ERRORE: `memory save-one` richiede la sezione `vector_write_rest` con una "
|
||||
"API key di upsert nel workspace yaml (upsert remoto via writer key).",
|
||||
fg=typer.colors.RED, err=True,
|
||||
)
|
||||
raise typer.Exit(code=4)
|
||||
store = build_vector_store(cfg, require_write=True)
|
||||
|
||||
sdir = session_dir(cfg, session)
|
||||
@@ -516,6 +509,7 @@ def solved_search_cmd(
|
||||
from rich.table import Table
|
||||
|
||||
from tht.cli.vector_cmd import make_embedder, open_searcher
|
||||
from tht.ports.vector import VectorReadUnavailable
|
||||
from tht.solved import SOLVED_KIND
|
||||
from tht.vectorstore.embeddings import EmbeddingsError
|
||||
from tht.vectorstore.rest_client import VectorRestError
|
||||
@@ -529,7 +523,7 @@ def solved_search_cmd(
|
||||
searcher = open_searcher(cfg)
|
||||
embedder = make_embedder(cfg.embeddings)
|
||||
hits = searcher.search(embedder.embed_query(question), top_n=top, kinds=[SOLVED_KIND])
|
||||
except (VectorRestError, EmbeddingsError, OperationalError) as e:
|
||||
except (VectorRestError, VectorReadUnavailable, EmbeddingsError, OperationalError) as e:
|
||||
typer.secho(
|
||||
f"ATTENZIONE: exemplar non disponibili ({e}). Prosegui senza.",
|
||||
fg=typer.colors.YELLOW, err=True,
|
||||
|
||||
@@ -10,6 +10,7 @@ from pathlib import Path
|
||||
import typer
|
||||
|
||||
from tht.cli.config_cmd import CONFIG_OPT
|
||||
from tht.config import workspace_id_from_path
|
||||
|
||||
|
||||
preprocess_app = typer.Typer(help="Materialize versioned preprocessing artifacts")
|
||||
@@ -86,7 +87,7 @@ def run_from_config(config: Path, *, dry_run: bool = False, resume: str | None =
|
||||
return "sha256:" + hashlib.sha256(value.encode()).hexdigest()
|
||||
|
||||
return pipeline.run_as_job(
|
||||
workspace_id=config.stem.lower().replace(".", "-").replace("_", "-"),
|
||||
workspace_id=workspace_id_from_path(config),
|
||||
workspace_root=corpus_root.parent,
|
||||
config_fingerprint=fingerprint(cfg.model_dump_json()),
|
||||
input_fingerprint=fingerprint(config.resolve().as_posix()),
|
||||
@@ -115,7 +116,7 @@ def gc_from_config(config: Path, *, dry_run: bool = False):
|
||||
pipeline_version="evidence-v1",
|
||||
retain_published_generations=cfg.vector.retain_published_generations,
|
||||
)
|
||||
pipeline.workspace_id = config.stem.lower().replace(".", "-").replace("_", "-")
|
||||
pipeline.workspace_id = workspace_id_from_path(config)
|
||||
return pipeline.gc(workspace_root=corpus_root.parent, dry_run=dry_run)
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import typer
|
||||
|
||||
from tht.cli.config_cmd import CONFIG_OPT
|
||||
from tht.cli.schema_cmd import _load_config_or_exit
|
||||
from tht.config import workspace_id_from_path
|
||||
|
||||
KIND_MAP = {
|
||||
"evidence": ["evidence"],
|
||||
@@ -59,7 +60,7 @@ def search_cmd(
|
||||
cfg = _load_config_or_exit(config)
|
||||
from tht.search.evidence import validate_corpus_workspace
|
||||
|
||||
workspace_id = config.stem.lower().replace(".", "-").replace("_", "-")
|
||||
workspace_id = workspace_id_from_path(config)
|
||||
validate_corpus_workspace(cfg, workspace_id)
|
||||
dwh_snapshot = _leased_dwh_snapshot(cfg, ctx)
|
||||
require_vector_cfg(cfg)
|
||||
@@ -254,6 +255,7 @@ def pack_cmd(
|
||||
from sqlalchemy.exc import OperationalError
|
||||
|
||||
from tht.cli.vector_cmd import make_embedder, open_searcher, require_vector_cfg
|
||||
from tht.ports.vector import VectorReadUnavailable
|
||||
from tht.search import combined_search, schema_tables
|
||||
from tht.solved import SOLVED_KIND
|
||||
from tht.vectorstore.embeddings import EmbeddingsError
|
||||
@@ -262,7 +264,7 @@ def pack_cmd(
|
||||
cfg = _load_config_or_exit(config)
|
||||
from tht.search.evidence import validate_corpus_workspace
|
||||
|
||||
workspace_id = config.stem.lower().replace(".", "-").replace("_", "-")
|
||||
workspace_id = workspace_id_from_path(config)
|
||||
validate_corpus_workspace(cfg, workspace_id)
|
||||
dwh_snapshot = _leased_dwh_snapshot(cfg, ctx)
|
||||
require_vector_cfg(cfg)
|
||||
@@ -271,7 +273,7 @@ def pack_cmd(
|
||||
evidence: list[dict] = []
|
||||
solved: list[dict] = []
|
||||
warnings: list[str] = []
|
||||
degrade = (VectorRestError, EmbeddingsError, OperationalError)
|
||||
degrade = (VectorRestError, VectorReadUnavailable, EmbeddingsError, OperationalError)
|
||||
|
||||
vec = None
|
||||
searcher = embedder = None
|
||||
|
||||
@@ -201,6 +201,27 @@ def show_cmd(
|
||||
typer.echo(f"schema_linking.json: {'presente' if linking.exists() else 'assente'}")
|
||||
|
||||
|
||||
@session_app.command("retrieval-pack")
|
||||
def retrieval_pack_cmd(
|
||||
session_id: str = typer.Argument(...),
|
||||
config: Path = CONFIG_OPT,
|
||||
) -> None:
|
||||
"""Emette su stdout il retrieval pack persistito della sessione."""
|
||||
cfg = _load_config_or_exit(config)
|
||||
load_session_or_exit(cfg, session_id)
|
||||
path = session_dir(cfg, session_id) / "retrieval_pack.md"
|
||||
try:
|
||||
content = path.read_text()
|
||||
except OSError as exc:
|
||||
typer.secho(
|
||||
f"ERRORE: retrieval pack non disponibile per la sessione {session_id}: {exc}",
|
||||
fg=typer.colors.RED,
|
||||
err=True,
|
||||
)
|
||||
raise typer.Exit(code=1)
|
||||
typer.echo(content, nl=False)
|
||||
|
||||
|
||||
@session_app.command("close")
|
||||
def close_cmd(session_id: str = typer.Argument(...), config: Path = CONFIG_OPT) -> None:
|
||||
"""Chiude la sessione (status=closed)."""
|
||||
@@ -212,6 +233,27 @@ def close_cmd(session_id: str = typer.Argument(...), config: Path = CONFIG_OPT)
|
||||
typer.secho(f"OK: sessione {session_id} chiusa.", fg=typer.colors.GREEN)
|
||||
|
||||
|
||||
@session_app.command("fail")
|
||||
def fail_cmd(session_id: str = typer.Argument(...), config: Path = CONFIG_OPT) -> None:
|
||||
"""Registra un arresto del sistema non recuperabile automaticamente."""
|
||||
from tht.session.store import fail_session
|
||||
|
||||
cfg = _load_config_or_exit(config)
|
||||
load_session_or_exit(cfg, session_id)
|
||||
fail_session(session_id, cfg.paths.sessions)
|
||||
typer.secho(f"OK: sessione {session_id} marcata failed.", fg=typer.colors.RED)
|
||||
|
||||
@session_app.command("reopen")
|
||||
def reopen_cmd(session_id: str = typer.Argument(...), config: Path = CONFIG_OPT) -> None:
|
||||
"""Riapre una sessione per una ripresa manuale."""
|
||||
from tht.session.store import reopen_session
|
||||
|
||||
cfg = _load_config_or_exit(config)
|
||||
load_session_or_exit(cfg, session_id)
|
||||
reopen_session(session_id, cfg.paths.sessions)
|
||||
typer.secho(f"OK: sessione {session_id} riaperta.", fg=typer.colors.GREEN)
|
||||
|
||||
|
||||
@session_app.command("set-name")
|
||||
def set_name_cmd(
|
||||
session_id: str = typer.Argument(...),
|
||||
|
||||
Reference in New Issue
Block a user