concierge-graph 3.8.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agents/__init__.py +14 -0
- agents/revisor_critico.py +610 -0
- concierge_graph-3.8.2.dist-info/METADATA +327 -0
- concierge_graph-3.8.2.dist-info/RECORD +37 -0
- concierge_graph-3.8.2.dist-info/WHEEL +5 -0
- concierge_graph-3.8.2.dist-info/entry_points.txt +3 -0
- concierge_graph-3.8.2.dist-info/licenses/LICENSE +21 -0
- concierge_graph-3.8.2.dist-info/top_level.txt +8 -0
- core/__init__.py +23 -0
- core/config.py +192 -0
- core/hybrid_search.py +288 -0
- core/memory_extractor.py +245 -0
- core/middleware.py +723 -0
- core/probabilistic_retriever.py +99 -0
- core/project_index.py +316 -0
- core/vector_backend.py +471 -0
- ingestion/__init__.py +25 -0
- ingestion/crawler.py +722 -0
- ingestion/orchestrator.py +920 -0
- ingestion/parser.py +984 -0
- ingestion/summarizer.py +948 -0
- interface/__init__.py +16 -0
- interface/action_hooks.py +261 -0
- interface/cli.py +391 -0
- interface/mcp_server.py +1737 -0
- main.py +281 -0
- scripts/bootstrap_core_memory.py +93 -0
- services/__init__.py +13 -0
- services/janitor.py +762 -0
- storage/__init__.py +31 -0
- storage/base_backend.py +241 -0
- storage/connection.py +310 -0
- storage/logic.py +703 -0
- storage/schema.py +390 -0
- storage/semantic_logic.py +125 -0
- storage/store.py +802 -0
- storage/vector_store.py +759 -0
main.py
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"""
|
|
2
|
+
main.py — Grafo Concierge v3.8.0 (Absolute Solidity)
|
|
3
|
+
|
|
4
|
+
System entry point. Initializes all components and
|
|
5
|
+
runs the MCP server via stdio transport.
|
|
6
|
+
|
|
7
|
+
Initialization flow:
|
|
8
|
+
1. Logging configured (console + timestamps)
|
|
9
|
+
2. Storage: SqliteStore + EmbeddingManager + ChromaVectorStore
|
|
10
|
+
3. Ingestion: ZoomSummarizer + IngestionManager
|
|
11
|
+
4. Services: JanitorService (background thread)
|
|
12
|
+
5. Server: GrafoConciergeServer (FastMCP)
|
|
13
|
+
6. Graceful shutdown: Janitor stop + DB close
|
|
14
|
+
|
|
15
|
+
Environment variables:
|
|
16
|
+
GRAFO_DB_PATH → SQLite path (default: ./data/concierge.db)
|
|
17
|
+
GRAFO_CHROMA_PATH → ChromaDB path (default: ./data/chroma)
|
|
18
|
+
GRAFO_CHROMA_COLLECTION → Collection name (default: grafo_concierge)
|
|
19
|
+
GRAFO_EMBEDDING_MODEL → Embedding model (default: all-MiniLM-L6-v2)
|
|
20
|
+
GRAFO_LLM_MODEL → LLM model for summarization (default: gemini-2.0-flash)
|
|
21
|
+
GRAFO_LLM_API_KEY → LLM API Key (optional)
|
|
22
|
+
GRAFO_JANITOR_INTERVAL → Janitor interval in seconds (default: 300)
|
|
23
|
+
GRAFO_LOG_LEVEL → Log level (default: INFO)
|
|
24
|
+
GRAFO_TRANSPORT → MCP transport: stdio or sse (default: stdio)
|
|
25
|
+
|
|
26
|
+
Usage:
|
|
27
|
+
python main.py
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
from dotenv import load_dotenv
|
|
32
|
+
load_dotenv()
|
|
33
|
+
|
|
34
|
+
import logging
|
|
35
|
+
import os
|
|
36
|
+
import signal
|
|
37
|
+
import sys
|
|
38
|
+
from pathlib import Path
|
|
39
|
+
|
|
40
|
+
# ---------------------------------------------------------------------------
|
|
41
|
+
# 1. CONFIGURATION — Constants and environment variables
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
# Paths — anchored at the project root, never relative to the process CWD
|
|
45
|
+
PROJECT_ROOT = Path(__file__).parent.resolve()
|
|
46
|
+
|
|
47
|
+
def resolve_project_path(env_value: str, default_rel: str) -> str:
|
|
48
|
+
val = env_value or default_rel
|
|
49
|
+
path = Path(val)
|
|
50
|
+
if path.is_absolute():
|
|
51
|
+
return str(path)
|
|
52
|
+
return str((PROJECT_ROOT / path).resolve())
|
|
53
|
+
|
|
54
|
+
DB_PATH = resolve_project_path(os.environ.get("GRAFO_DB_PATH", ""), "data/concierge.db")
|
|
55
|
+
CHROMA_PATH = resolve_project_path(os.environ.get("GRAFO_CHROMA_PATH", ""), "data/chroma")
|
|
56
|
+
CHROMA_COLLECTION = os.environ.get("GRAFO_CHROMA_COLLECTION", "grafo_concierge")
|
|
57
|
+
|
|
58
|
+
# Models
|
|
59
|
+
EMBEDDING_MODEL = os.environ.get("GRAFO_EMBEDDING_MODEL", "all-MiniLM-L6-v2")
|
|
60
|
+
LLM_MODEL = os.environ.get("GRAFO_LLM_MODEL", "gemini-2.0-flash")
|
|
61
|
+
LLM_API_KEY = os.environ.get("GRAFO_LLM_API_KEY", "")
|
|
62
|
+
LLM_BASE_URL = os.environ.get("GRAFO_LLM_BASE_URL", "")
|
|
63
|
+
|
|
64
|
+
# Janitor
|
|
65
|
+
JANITOR_INTERVAL = int(os.environ.get("GRAFO_JANITOR_INTERVAL", "300"))
|
|
66
|
+
JANITOR_PROJECT_UUID = os.environ.get("GRAFO_JANITOR_PROJECT", "")
|
|
67
|
+
|
|
68
|
+
# Runtime
|
|
69
|
+
LOG_LEVEL = os.environ.get("GRAFO_LOG_LEVEL", "INFO").upper()
|
|
70
|
+
TRANSPORT = os.environ.get("GRAFO_TRANSPORT", "stdio")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
# 2. LOGGING — Console with timestamps and levels
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
def setup_logging(level: str = "INFO") -> None:
|
|
78
|
+
"""Configures global logging for Grafo Concierge."""
|
|
79
|
+
numeric_level = getattr(logging, level, logging.INFO)
|
|
80
|
+
|
|
81
|
+
formatter = logging.Formatter(
|
|
82
|
+
fmt="%(asctime)s │ %(levelname)-7s │ %(name)-28s │ %(message)s",
|
|
83
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Handler: stderr (so it does not interfere with MCP stdio)
|
|
87
|
+
handler = logging.StreamHandler(sys.stderr)
|
|
88
|
+
handler.setLevel(numeric_level)
|
|
89
|
+
handler.setFormatter(formatter)
|
|
90
|
+
|
|
91
|
+
# Root logger
|
|
92
|
+
root = logging.getLogger()
|
|
93
|
+
root.setLevel(numeric_level)
|
|
94
|
+
root.addHandler(handler)
|
|
95
|
+
|
|
96
|
+
# Silence noisy third-party loggers
|
|
97
|
+
logging.getLogger("chromadb").setLevel(logging.WARNING)
|
|
98
|
+
logging.getLogger("httpx").setLevel(logging.WARNING)
|
|
99
|
+
logging.getLogger("httpcore").setLevel(logging.WARNING)
|
|
100
|
+
logging.getLogger("sentence_transformers").setLevel(logging.WARNING)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# ---------------------------------------------------------------------------
|
|
104
|
+
# 3. BOOTSTRAP — Initialization of all components
|
|
105
|
+
# ---------------------------------------------------------------------------
|
|
106
|
+
|
|
107
|
+
logger = logging.getLogger("grafo-concierge.main")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def bootstrap():
|
|
111
|
+
"""Initializes and returns all system components.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Tuple containing (server, janitor, store) for use in the main loop and shutdown.
|
|
115
|
+
"""
|
|
116
|
+
# --- Ensures the data directory exists ---
|
|
117
|
+
os.makedirs(os.path.dirname(DB_PATH) or ".", exist_ok=True)
|
|
118
|
+
os.makedirs(CHROMA_PATH, exist_ok=True)
|
|
119
|
+
|
|
120
|
+
# ── STORAGE ──────────────────────────────────────────────────────
|
|
121
|
+
logger.info("Initializing SqliteStore: %s", DB_PATH)
|
|
122
|
+
from storage import SqliteStore
|
|
123
|
+
store = SqliteStore(DB_PATH)
|
|
124
|
+
|
|
125
|
+
logger.info("Initializing EmbeddingManager: tier=FLASH")
|
|
126
|
+
from storage import EmbeddingManager, EmbeddingTier
|
|
127
|
+
embedder = EmbeddingManager(tier=EmbeddingTier.FLASH)
|
|
128
|
+
|
|
129
|
+
vector_backend = os.environ.get("GRAFO_VECTOR_BACKEND", "chroma").lower()
|
|
130
|
+
if vector_backend == "qdrant":
|
|
131
|
+
qdrant_url = os.environ.get("GRAFO_QDRANT_URL", "http://localhost:6333")
|
|
132
|
+
qdrant_key = os.environ.get("GRAFO_QDRANT_API_KEY", "") or None
|
|
133
|
+
logger.info("Initializing QdrantVectorStore: url=%s, collection=%s", qdrant_url, CHROMA_COLLECTION)
|
|
134
|
+
from core.vector_backend import QdrantVectorStore
|
|
135
|
+
vector_store = QdrantVectorStore(
|
|
136
|
+
url=qdrant_url,
|
|
137
|
+
api_key=qdrant_key,
|
|
138
|
+
collection_name=CHROMA_COLLECTION,
|
|
139
|
+
embedding_dimensions=embedder.dimensions,
|
|
140
|
+
)
|
|
141
|
+
else:
|
|
142
|
+
logger.info("Initializing ChromaVectorStore: path=%s, collection=%s", CHROMA_PATH, CHROMA_COLLECTION)
|
|
143
|
+
from storage import ChromaVectorStore
|
|
144
|
+
vector_store = ChromaVectorStore(
|
|
145
|
+
persist_dir=CHROMA_PATH,
|
|
146
|
+
collection_name=CHROMA_COLLECTION,
|
|
147
|
+
embedding_manager=embedder,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# ── INGESTION ────────────────────────────────────────────────────
|
|
151
|
+
logger.info("Initializing ZoomSummarizer: model=%s", LLM_MODEL)
|
|
152
|
+
from ingestion import ZoomSummarizer
|
|
153
|
+
from ingestion.summarizer import LLMAdapter
|
|
154
|
+
|
|
155
|
+
llm_adapter = LLMAdapter(
|
|
156
|
+
model_name=LLM_MODEL,
|
|
157
|
+
api_key=LLM_API_KEY or None,
|
|
158
|
+
base_url=LLM_BASE_URL or None,
|
|
159
|
+
)
|
|
160
|
+
summarizer = ZoomSummarizer(
|
|
161
|
+
llm_adapter=llm_adapter,
|
|
162
|
+
sqlite_store=store,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
logger.info("Initializing IngestionManager")
|
|
166
|
+
from ingestion import IngestionManager
|
|
167
|
+
ingestion_manager = IngestionManager(
|
|
168
|
+
sqlite_store=store,
|
|
169
|
+
vector_store=vector_store,
|
|
170
|
+
embedding_manager=embedder,
|
|
171
|
+
summarizer=summarizer,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# ── SERVICES ─────────────────────────────────────────────────────
|
|
175
|
+
logger.info("Initializing JanitorService: interval=%ds", JANITOR_INTERVAL)
|
|
176
|
+
from services import JanitorService
|
|
177
|
+
janitor = JanitorService(
|
|
178
|
+
sqlite_store=store,
|
|
179
|
+
vector_store=vector_store,
|
|
180
|
+
ingestion_manager=ingestion_manager,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# ── CENTRAL FACADE ───────────────────────────────────────────────
|
|
184
|
+
logger.info("Initializing GrafoConcierge Central Facade")
|
|
185
|
+
from core.middleware import GrafoConcierge
|
|
186
|
+
concierge = GrafoConcierge(
|
|
187
|
+
sqlite_store=store,
|
|
188
|
+
vector_store=vector_store,
|
|
189
|
+
embedding_manager=embedder,
|
|
190
|
+
ingestion_manager=ingestion_manager,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# ── MCP SERVER ───────────────────────────────────────────────────
|
|
194
|
+
logger.info("Initializing GrafoConciergeServer")
|
|
195
|
+
from interface.mcp_server import GrafoConciergeServer
|
|
196
|
+
server = GrafoConciergeServer(
|
|
197
|
+
concierge=concierge,
|
|
198
|
+
janitor=janitor,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
logger.info("Bootstrap complete — all components initialized.")
|
|
202
|
+
return server, janitor, store
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
# ---------------------------------------------------------------------------
|
|
206
|
+
# 4. MAIN — Main loop with graceful shutdown
|
|
207
|
+
# ---------------------------------------------------------------------------
|
|
208
|
+
|
|
209
|
+
def main() -> None:
|
|
210
|
+
"""Main entry point of Grafo Concierge."""
|
|
211
|
+
|
|
212
|
+
# ── Logging ──
|
|
213
|
+
setup_logging(LOG_LEVEL)
|
|
214
|
+
|
|
215
|
+
logger.info("=" * 60)
|
|
216
|
+
logger.info(" Grafo Concierge v3.8.0 — Absolute Solidity")
|
|
217
|
+
logger.info("=" * 60)
|
|
218
|
+
logger.info(" DB: %s", DB_PATH)
|
|
219
|
+
logger.info(" ChromaDB: %s (%s)", CHROMA_PATH, CHROMA_COLLECTION)
|
|
220
|
+
logger.info(" Embedding: %s", EMBEDDING_MODEL)
|
|
221
|
+
logger.info(" LLM: %s", LLM_MODEL)
|
|
222
|
+
logger.info(" Janitor: %ds", JANITOR_INTERVAL)
|
|
223
|
+
logger.info(" Transport: %s", TRANSPORT)
|
|
224
|
+
logger.info(" Log Level: %s", LOG_LEVEL)
|
|
225
|
+
logger.info("=" * 60)
|
|
226
|
+
|
|
227
|
+
server = None
|
|
228
|
+
janitor = None
|
|
229
|
+
store = None
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
# ── Bootstrap ──
|
|
233
|
+
server, janitor, store = bootstrap()
|
|
234
|
+
|
|
235
|
+
# ── Background Janitor (if project is configured) ──
|
|
236
|
+
if JANITOR_PROJECT_UUID:
|
|
237
|
+
logger.info("Starting background Janitor for project: %s", JANITOR_PROJECT_UUID)
|
|
238
|
+
janitor.start_background(JANITOR_PROJECT_UUID, interval=JANITOR_INTERVAL)
|
|
239
|
+
else:
|
|
240
|
+
logger.info("Janitor in idle mode (no GRAFO_JANITOR_PROJECT defined).")
|
|
241
|
+
|
|
242
|
+
# ── MCP Server ──
|
|
243
|
+
logger.info("Starting MCP server (transport=%s)...", TRANSPORT)
|
|
244
|
+
server.run(transport=TRANSPORT)
|
|
245
|
+
|
|
246
|
+
except KeyboardInterrupt:
|
|
247
|
+
logger.info("Interrupt received (Ctrl+C) — starting graceful shutdown...")
|
|
248
|
+
|
|
249
|
+
except Exception as e:
|
|
250
|
+
logger.critical("Erro fatal durante execução: %s", e, exc_info=True)
|
|
251
|
+
sys.exit(1)
|
|
252
|
+
|
|
253
|
+
finally:
|
|
254
|
+
# ── Graceful Shutdown ──
|
|
255
|
+
logger.info("Shutdown gracioso iniciado...")
|
|
256
|
+
|
|
257
|
+
if janitor is not None:
|
|
258
|
+
try:
|
|
259
|
+
janitor.stop_background(timeout=5.0)
|
|
260
|
+
logger.info("Janitor encerrado.")
|
|
261
|
+
except Exception as e:
|
|
262
|
+
logger.warning("Erro ao parar Janitor: %s", e)
|
|
263
|
+
|
|
264
|
+
if store is not None:
|
|
265
|
+
try:
|
|
266
|
+
store.close()
|
|
267
|
+
logger.info("SqliteStore encerrado.")
|
|
268
|
+
except Exception as e:
|
|
269
|
+
logger.warning("Erro ao fechar SqliteStore: %s", e)
|
|
270
|
+
|
|
271
|
+
logger.info("=" * 60)
|
|
272
|
+
logger.info(" Grafo Concierge encerrado com sucesso.")
|
|
273
|
+
logger.info("=" * 60)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
# ---------------------------------------------------------------------------
|
|
277
|
+
# ENTRY POINT
|
|
278
|
+
# ---------------------------------------------------------------------------
|
|
279
|
+
|
|
280
|
+
if __name__ == "__main__":
|
|
281
|
+
main()
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
scripts/bootstrap_core_memory.py — Grafo Concierge v3.8.0
|
|
4
|
+
|
|
5
|
+
Populate the user_core_memory table with persona information and default
|
|
6
|
+
context rules so that the agent starts operational and aligned with project guidelines.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from dotenv import load_dotenv
|
|
13
|
+
|
|
14
|
+
# Ensures loading of Grafo Concierge modules by inserting the root directory path into sys.path
|
|
15
|
+
ROOT_DIR = Path(__file__).parent.parent.resolve()
|
|
16
|
+
sys.path.insert(0, str(ROOT_DIR))
|
|
17
|
+
|
|
18
|
+
load_dotenv(str(ROOT_DIR / ".env"))
|
|
19
|
+
|
|
20
|
+
from storage import SqliteStore
|
|
21
|
+
|
|
22
|
+
def resolve_project_path(env_value: str, default_rel: str) -> str:
|
|
23
|
+
val = env_value or default_rel
|
|
24
|
+
path = Path(val)
|
|
25
|
+
if path.is_absolute():
|
|
26
|
+
return str(path)
|
|
27
|
+
return str((ROOT_DIR / path).resolve())
|
|
28
|
+
|
|
29
|
+
DB_PATH = resolve_project_path(os.environ.get("GRAFO_DB_PATH", ""), "data/concierge.db")
|
|
30
|
+
|
|
31
|
+
DEFAULT_MEMORIES = [
|
|
32
|
+
{
|
|
33
|
+
"scope_type": "agent",
|
|
34
|
+
"scope_id": "concierge",
|
|
35
|
+
"block_label": "persona",
|
|
36
|
+
"content": (
|
|
37
|
+
"Você é o Grafo Concierge, um agente inteligente de engenharia de software "
|
|
38
|
+
"e memória arquitetural de longo prazo. Você pair-programa com o usuário "
|
|
39
|
+
"e gerencia grafos de código-fonte de sistemas complexos."
|
|
40
|
+
)
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"scope_type": "agent",
|
|
44
|
+
"scope_id": "concierge",
|
|
45
|
+
"block_label": "context_rules",
|
|
46
|
+
"content": (
|
|
47
|
+
"Regra 1: Dívida Técnica Zero Absoluta. Nunca introduzir hacks ou violar encapsulamentos.\n"
|
|
48
|
+
"Regra 2: Blindagem de Segredos. Nunca deixar chaves de API em texto plano em arquivos JSON ou versionados.\n"
|
|
49
|
+
"Regra 3: Validação Fail-Fast nas bordas da API MCP.\n"
|
|
50
|
+
"Regra 4: Resiliência em conexões de banco de dados (retry com backoff)."
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
def main() -> None:
|
|
56
|
+
print("=" * 60)
|
|
57
|
+
print(" Grafo Concierge — Bootstrap da Core Memory")
|
|
58
|
+
print("=" * 60)
|
|
59
|
+
print(f"Banco de dados: {DB_PATH}")
|
|
60
|
+
|
|
61
|
+
# Ensures the data directory exists
|
|
62
|
+
db_dir = os.path.dirname(DB_PATH)
|
|
63
|
+
if db_dir:
|
|
64
|
+
os.makedirs(db_dir, exist_ok=True)
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
store = SqliteStore(DB_PATH)
|
|
68
|
+
print("SqliteStore inicializado com sucesso.")
|
|
69
|
+
|
|
70
|
+
inserted_count = 0
|
|
71
|
+
for mem in DEFAULT_MEMORIES:
|
|
72
|
+
# Inserts/updates default blocks in the table
|
|
73
|
+
store.set_core_memory(
|
|
74
|
+
scope_type=mem["scope_type"],
|
|
75
|
+
scope_id=mem["scope_id"],
|
|
76
|
+
block_label=mem["block_label"],
|
|
77
|
+
content=mem["content"]
|
|
78
|
+
)
|
|
79
|
+
print(f" [+] Bloco '{mem['block_label']}' registrado para '{mem['scope_type']}/{mem['scope_id']}'.")
|
|
80
|
+
inserted_count += 1
|
|
81
|
+
|
|
82
|
+
store.close()
|
|
83
|
+
print("=" * 60)
|
|
84
|
+
print(f"Sucesso: {inserted_count} blocos de memória padrão registrados.")
|
|
85
|
+
print("=" * 60)
|
|
86
|
+
sys.exit(0)
|
|
87
|
+
|
|
88
|
+
except Exception as e:
|
|
89
|
+
print(f"[-] Erro crítico durante o bootstrap: {e}", file=sys.stderr)
|
|
90
|
+
sys.exit(1)
|
|
91
|
+
|
|
92
|
+
if __name__ == "__main__":
|
|
93
|
+
main()
|
services/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
services/ - Autonomous services of Grafo Concierge v3.8.0
|
|
3
|
+
|
|
4
|
+
Modules:
|
|
5
|
+
janitor.py → Background Janitor — autonomous maintenance of the graph
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from services.janitor import JanitorService, MaintenanceReport
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"JanitorService",
|
|
12
|
+
"MaintenanceReport",
|
|
13
|
+
]
|