Backup automatico script del 2026-09-27 07:00

This commit is contained in:
daniele committed 2026-09-27 07:00:02 +02:00
1 parent f347badf3b
commit 09dcbbdadb
24 files changed
+1164 -193

No files matched your search

+110 -50
View File
@@ -7,7 +7,7 @@ from typing import Any, Optional
from .. import audit
from ..context import store as context_store
from ..jwt_utils import has_scope
from ..knowledge import apps_indexer, gitea, gitea_indexer, indexer, paperless
from ..knowledge import apps_indexer, gitea, gitea_indexer, indexer, paperless, qdrant_store
from ..integrations import casa, homeassistant, irrigazione, turni
@@ -25,7 +25,10 @@ def tool_definitions() -> list[dict]:
},
{
"name": "list_projects",
"description": "Elenca i progetti dell'utente corrente",
"description": (
"Elenca i progetti personali dell'utente e i contesti condivisi con tutta la famiglia "
"(campo shared=true, con owner e updated_by). I condivisi sono letti e aggiornati da tutti."
),
"inputSchema": {
"type": "object",
"properties": {"include_archived": {"type": "boolean", "default": False}},
@@ -39,6 +42,11 @@ def tool_definitions() -> list[dict]:
"required": ["title"],
"properties": {
"title": {"type": "string"},
"shared": {
"type": "boolean",
"default": False,
"description": "Contesto condiviso con tutta la famiglia (tutti leggono e aggiornano)",
},
"tags": {"type": "array", "items": {"type": "string"}},
"gitea_repo": {
"type": "string",
@@ -91,7 +99,13 @@ def tool_definitions() -> list[dict]:
},
{
"name": "save_context",
"description": "Salva o appende memoria persistente in un progetto",
"description": (
"Salva o appende memoria persistente in un progetto. Nei contesti condivisi (shared=true) "
"la modifica vale per tutta la famiglia: quando cambia un dato (acquisti, inventario, "
"prezzi, regole) aggiorna la sezione esistente con mode=replace del testo completo invece "
"di appendere informazioni che la contraddicono, e passa if_revision (meta.revision letto "
"con get_project_context) per non sovrascrivere modifiche fatte nel frattempo da altri."
),
"inputSchema": {
"type": "object",
"required": ["project_id", "content"],
@@ -99,12 +113,32 @@ def tool_definitions() -> list[dict]:
"project_id": {"type": "string"},
"content": {"type": "string"},
"mode": {"type": "string", "enum": ["append", "replace"], "default": "append"},
"if_revision": {
"type": "integer",
"description": "meta.revision letto prima di modificare: se è cambiato, errore di conflitto",
},
},
},
},
{
"name": "share_project",
"description": (
"Condivide con tutta la famiglia un tuo progetto personale (shared=true): tutti potranno "
"leggerlo e aggiornarlo, storia inclusa. shared=false lo riporta personale del proprietario "
"(solo proprietario o admin)."
),
"inputSchema": {
"type": "object",
"required": ["project_id"],
"properties": {
"project_id": {"type": "string"},
"shared": {"type": "boolean", "default": True},
},
},
},
{
"name": "archive_project",
"description": "Archivia o ripristina un progetto",
"description": "Archivia o ripristina un progetto (se condiviso: solo proprietario o admin)",
"inputSchema": {
"type": "object",
"required": ["project_id"],
@@ -116,7 +150,7 @@ def tool_definitions() -> list[dict]:
},
{
"name": "search_context",
"description": "Ricerca semantica nei contesti salvati dell'utente",
"description": "Ricerca semantica nei contesti salvati dell'utente e in quelli condivisi con la famiglia",
"inputSchema": {
"type": "object",
"required": ["query"],
@@ -163,7 +197,7 @@ def tool_definitions() -> list[dict]:
},
{
"name": "reindex_gitea_repo",
"description": "Re-indicizza i file testo di un repository Gitea (admin o owner repo)",
"description": "Re-indicizza i file testo di un repository Gitea (admin o owner repo). Asincrono: risponde subito, l'indicizzazione prosegue in background",
"inputSchema": {
"type": "object",
"required": ["repo"],
@@ -195,7 +229,7 @@ def tool_definitions() -> list[dict]:
},
{
"name": "reindex_document",
"description": "Re-indicizza un documento Paperless (admin)",
"description": "Re-indicizza un documento Paperless (admin). Asincrono: risponde subito",
"inputSchema": {
"type": "object",
"required": ["doc_id"],
@@ -312,7 +346,7 @@ def tool_definitions() -> list[dict]:
"reindex": {
"type": "boolean",
"default": True,
"description": "Aggiorna subito il vector store RAG per questo file",
"description": "Aggiorna il vector store RAG per questo file (in background)",
},
},
},
@@ -447,7 +481,7 @@ def tool_definitions() -> list[dict]:
},
{
"name": "reindex_apps",
"description": "Forza re-indicizzazione RAG da Irrigazione e/o Turni (admin)",
"description": "Forza re-indicizzazione RAG da Irrigazione e/o Turni (admin). Asincrono: risponde subito",
"inputSchema": {
"type": "object",
"properties": {
@@ -498,12 +532,32 @@ def call_tool(name: str, arguments: dict, claims: dict) -> dict:
arguments.get("tags"),
gitea_repo=gitea_repo,
seed_from_gitea=bool(arguments.get("seed_from_gitea")),
shared=bool(arguments.get("shared")),
)
except RuntimeError as exc:
raise PermissionError(str(exc)) from exc
except ValueError as exc:
raise ValueError(str(exc)) from exc
audit.log_tool(username, name, meta["id"])
audit.log_tool(username, name, meta["id"], detail={"shared": bool(meta.get("shared"))})
return _text_result(meta)
if name == "share_project":
if not has_scope(claims, "context:write"):
raise PermissionError("Scope context:write richiesto")
project_id = arguments["project_id"]
shared = bool(arguments.get("shared", True))
before = context_store.get_project_context(username, project_id, session_limit=0, include_gitea=False)
owner = before["meta"].get("owner") or username
was_shared = bool(before["meta"].get("shared"))
meta = context_store.share_project(username, project_id, shared=shared, is_admin=is_admin)
if was_shared != bool(meta.get("shared")):
# Sposta i vettori: via dalla collezione di partenza, reindicizza nella nuova
source = qdrant_store.ctx_collection(owner) if shared else qdrant_store.CTX_SHARED_COLLECTION
indexer.submit_background(
f"share {project_id} shared={shared}",
_move_project_vectors, source, owner, project_id,
)
audit.log_tool(username, name, project_id, detail={"shared": shared})
return _text_result(meta)
if name == "link_project_repo":
@@ -558,13 +612,13 @@ def call_tool(name: str, arguments: dict, claims: dict) -> dict:
arguments["project_id"],
arguments["content"],
arguments.get("mode", "append"),
if_revision=arguments.get("if_revision"),
)
indexer.submit_background(
f"context {username}/{arguments['project_id']}",
indexer.index_project_context,
username, arguments["project_id"],
)
try:
indexer.index_context_snippet(
username, arguments["project_id"], arguments["content"], meta["title"]
)
except Exception:
pass
audit.log_tool(username, name, arguments["project_id"])
return _text_result(meta)
@@ -572,7 +626,7 @@ def call_tool(name: str, arguments: dict, claims: dict) -> dict:
if not has_scope(claims, "context:write"):
raise PermissionError("Scope context:write richiesto")
meta = context_store.archive_project(
username, arguments["project_id"], arguments.get("archived", True)
username, arguments["project_id"], arguments.get("archived", True), is_admin=is_admin
)
audit.log_tool(username, name, arguments["project_id"])
return _text_result(meta)
@@ -623,17 +677,16 @@ def call_tool(name: str, arguments: dict, claims: dict) -> dict:
owner = repo.split("/", 1)[0].lower()
if not is_admin and owner != username:
raise PermissionError("Puoi re-indicizzare solo repository di cui sei owner")
try:
result = gitea_indexer.index_repo(
repo,
username=username,
force=True,
max_files=arguments.get("max_files"),
)
except Exception as exc:
raise PermissionError(f"Re-indicizzazione Gitea fallita: {exc}") from exc
indexer.submit_background(
f"gitea repo {repo}",
gitea_indexer.index_repo,
repo,
username=username,
force=True,
max_files=arguments.get("max_files"),
)
audit.log_tool(username, name, detail={"repo": repo})
return _text_result(result)
return _text_result({"queued": True, "repo": repo})
if name == "get_document":
if not has_scope(claims, "knowledge:read"):
@@ -655,9 +708,10 @@ def call_tool(name: str, arguments: dict, claims: dict) -> dict:
if name == "reindex_document":
if not is_admin:
raise PermissionError("Scope admin richiesto")
result = indexer.index_document(int(arguments["doc_id"]), force=True)
audit.log_tool(username, name, str(arguments["doc_id"]))
return _text_result(result)
doc_id = int(arguments["doc_id"])
indexer.submit_background(f"paperless doc {doc_id}", indexer.index_document, doc_id, force=True)
audit.log_tool(username, name, str(doc_id))
return _text_result({"queued": True, "doc_id": doc_id})
if name in (
"list_repos", "get_file", "search_code", "list_issues", "get_issue", "create_issue",
@@ -792,22 +846,14 @@ def call_tool(name: str, arguments: dict, claims: dict) -> dict:
username=username,
)
if arguments.get("reindex", True):
try:
owner, repo_name = gitea.parse_repo(repo)
meta = gitea._request(
"GET", f"/repos/{owner}/{repo_name}", username=username
)
private = bool(meta.get("private"))
idx = gitea_indexer.index_file(
repo,
arguments["path"],
username=username,
private=private,
force=True,
)
result["reindex"] = idx
except Exception:
result["reindex"] = {"skipped": True}
indexer.submit_background(
f"gitea file {repo}:{arguments['path']}",
_reindex_gitea_file,
repo,
arguments["path"],
username,
)
result["reindex"] = {"queued": True}
except PermissionError:
raise
except Exception as exc:
@@ -941,17 +987,31 @@ def call_tool(name: str, arguments: dict, claims: dict) -> dict:
raise PermissionError("Scope admin richiesto")
src = arguments.get("source", "all")
if src == "irrigazione":
result = apps_indexer.index_irrigazione()
job = apps_indexer.index_irrigazione
elif src == "turni":
result = apps_indexer.index_turni()
job = apps_indexer.index_turni
else:
result = apps_indexer.index_all()
job = apps_indexer.index_all
indexer.submit_background(f"apps {src}", job)
audit.log_tool(username, name, detail={"source": src})
return _text_result(result)
return _text_result({"queued": True, "source": src})
raise ValueError(f"Tool sconosciuto: {name}")
def _move_project_vectors(source_collection: str, owner: str, project_id: str) -> None:
indexer.drop_project_context(source_collection, project_id)
indexer.index_project_context(owner, project_id)
def _reindex_gitea_file(repo: str, path: str, username: str) -> None:
owner, repo_name = gitea.parse_repo(repo)
meta = gitea._request("GET", f"/repos/{owner}/{repo_name}", username=username)
gitea_indexer.index_file(
repo, path, username=username, private=bool(meta.get("private")), force=True
)
def list_resources(claims: dict) -> list:
username = claims["sub"]
return context_store.list_resources(username)
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.