agentgraph-server 0.5.0__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.
Files changed (49) hide show
  1. agentgraph/__init__.py +1 -0
  2. agentgraph/auth/__init__.py +0 -0
  3. agentgraph/auth/credentials.py +224 -0
  4. agentgraph/backends/__init__.py +50 -0
  5. agentgraph/backends/sqlite/__init__.py +1 -0
  6. agentgraph/backends/sqlite/backend.py +1471 -0
  7. agentgraph/backends/sqlite/vector.py +142 -0
  8. agentgraph/cli.py +721 -0
  9. agentgraph/cli_query.py +519 -0
  10. agentgraph/config.py +90 -0
  11. agentgraph/connectors/__init__.py +0 -0
  12. agentgraph/connectors/base.py +455 -0
  13. agentgraph/connectors/registry.py +78 -0
  14. agentgraph/connectors/status.py +244 -0
  15. agentgraph/core/__init__.py +0 -0
  16. agentgraph/core/context.py +26 -0
  17. agentgraph/core/runtime.py +36 -0
  18. agentgraph/core/storage.py +240 -0
  19. agentgraph/graph/__init__.py +1 -0
  20. agentgraph/graph/bookmark.py +87 -0
  21. agentgraph/graph/delete.py +17 -0
  22. agentgraph/graph/download.py +35 -0
  23. agentgraph/graph/embeddings.py +58 -0
  24. agentgraph/graph/fetch.py +53 -0
  25. agentgraph/graph/gc.py +26 -0
  26. agentgraph/graph/link.py +63 -0
  27. agentgraph/graph/person.py +40 -0
  28. agentgraph/graph/query.py +244 -0
  29. agentgraph/graph/upsert.py +49 -0
  30. agentgraph/logging.py +78 -0
  31. agentgraph/mcp/__init__.py +0 -0
  32. agentgraph/mcp/server.py +811 -0
  33. agentgraph/perf.py +43 -0
  34. agentgraph/server/__init__.py +0 -0
  35. agentgraph/server/app.py +133 -0
  36. agentgraph/server/cli_api.py +708 -0
  37. agentgraph/server/dwell.py +79 -0
  38. agentgraph/server/graph_api.py +46 -0
  39. agentgraph/server/router.py +47 -0
  40. agentgraph/server/sync.py +247 -0
  41. agentgraph/skills.py +93 -0
  42. agentgraph_server-0.5.0.data/data/.agents/skills/graph/SKILL.md +159 -0
  43. agentgraph_server-0.5.0.data/data/.agents/skills/slack-auth/SKILL.md +92 -0
  44. agentgraph_server-0.5.0.dist-info/METADATA +286 -0
  45. agentgraph_server-0.5.0.dist-info/RECORD +49 -0
  46. agentgraph_server-0.5.0.dist-info/WHEEL +5 -0
  47. agentgraph_server-0.5.0.dist-info/entry_points.txt +2 -0
  48. agentgraph_server-0.5.0.dist-info/licenses/LICENSE +21 -0
  49. agentgraph_server-0.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,142 @@
1
+ """Vector search helpers for the SQLite backend.
2
+
3
+ Three modes (set at backend construction time):
4
+ - "sqlite-vec": Uses the sqlite-vec extension's vec_distance_cosine() scalar
5
+ function (O(n) scan, SIMD-accelerated). Falls through to numpy on failure.
6
+ - "numpy": Loads all embeddings from the DB into Python, computes cosine
7
+ similarity with numpy. Falls through to BM25-only on ImportError.
8
+ - "bm25-only": Skips vector search; BM25 (FTS5) ranking only.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import struct
14
+ from typing import Any
15
+
16
+ from agentgraph.perf import timed
17
+
18
+ # ---------------------------------------------------------------------------
19
+ # Blob encoding
20
+ # ---------------------------------------------------------------------------
21
+
22
+ def pack_embedding(vec: list[float]) -> bytes:
23
+ return struct.pack(f"{len(vec)}f", *vec)
24
+
25
+
26
+ def unpack_embedding(blob: bytes) -> list[float]:
27
+ n = len(blob) // 4
28
+ return list(struct.unpack(f"{n}f", blob))
29
+
30
+
31
+ # ---------------------------------------------------------------------------
32
+ # Extension loading
33
+ # ---------------------------------------------------------------------------
34
+
35
+ async def load_sqlite_vec(conn: Any) -> bool:
36
+ """Load the sqlite-vec extension into *conn*. Returns True on success."""
37
+ try:
38
+ import sqlite_vec # type: ignore[import-untyped]
39
+ except ImportError:
40
+ return False
41
+ try:
42
+ # Must run on the aiosqlite background thread via _execute,
43
+ # passing the underlying sqlite3 connection.
44
+ def _do_load(db: Any) -> None:
45
+ db.enable_load_extension(True)
46
+ sqlite_vec.load(db)
47
+ db.enable_load_extension(False)
48
+
49
+ await conn._execute(_do_load, conn._connection)
50
+ return True
51
+ except Exception:
52
+ return False
53
+
54
+
55
+ # ---------------------------------------------------------------------------
56
+ # Vector search
57
+ # ---------------------------------------------------------------------------
58
+
59
+ async def vector_ranked(
60
+ conn: Any,
61
+ query_vec: list[float],
62
+ entity_types: list[str] | None,
63
+ limit: int,
64
+ mode: str,
65
+ vec_loaded: bool,
66
+ platform: str | None = None,
67
+ candidate_limit: int | None = None,
68
+ ) -> list[tuple[str, int]]:
69
+ """Return (entity_id, rank) pairs with rank starting at 1 (best).
70
+
71
+ Returns an empty list when mode is "bm25-only" or when no embeddings exist.
72
+ """
73
+ if mode == "bm25-only":
74
+ return []
75
+
76
+ type_clause = ""
77
+ type_params: list[Any] = []
78
+ if entity_types:
79
+ placeholders = ",".join("?" * len(entity_types))
80
+ type_clause = f"AND entity_type IN ({placeholders})"
81
+ type_params = list(entity_types)
82
+ if platform:
83
+ type_clause += " AND platform = ?"
84
+ type_params.append(platform)
85
+
86
+ query_blob = pack_embedding(query_vec)
87
+ candidate_limit = candidate_limit if candidate_limit is not None else limit * 5
88
+
89
+ # ---- sqlite-vec path ----
90
+ if mode == "sqlite-vec" and vec_loaded:
91
+ try:
92
+ with timed("sqlite.vector_ranked.sqlite_vec", limit=limit, platform=platform):
93
+ cursor = await conn.execute(
94
+ f"""
95
+ SELECT id, vec_distance_cosine(content_embedding, ?) AS dist
96
+ FROM entities
97
+ WHERE content_embedding IS NOT NULL {type_clause}
98
+ ORDER BY dist ASC
99
+ LIMIT ?
100
+ """,
101
+ [query_blob, *type_params, candidate_limit],
102
+ )
103
+ rows = await cursor.fetchall()
104
+ return [(row[0], i + 1) for i, row in enumerate(rows)]
105
+ except Exception:
106
+ pass # fall through to numpy
107
+
108
+ # ---- numpy path ----
109
+ try:
110
+ import numpy as np
111
+
112
+ with timed("sqlite.vector_ranked.numpy", limit=limit, platform=platform):
113
+ cursor = await conn.execute(
114
+ f"SELECT id, content_embedding FROM entities WHERE content_embedding IS NOT NULL {type_clause}",
115
+ type_params,
116
+ )
117
+ rows = await cursor.fetchall()
118
+ if not rows:
119
+ return []
120
+
121
+ q = np.array(query_vec, dtype=np.float32)
122
+ q_norm = float(np.linalg.norm(q))
123
+ if q_norm == 0:
124
+ return []
125
+ q = q / q_norm
126
+
127
+ scored: list[tuple[str, float]] = []
128
+ for entity_id, blob in rows:
129
+ if not blob:
130
+ continue
131
+ vec = np.array(unpack_embedding(bytes(blob)), dtype=np.float32)
132
+ norm = float(np.linalg.norm(vec))
133
+ if norm == 0:
134
+ continue
135
+ sim = float(np.dot(q, vec / norm))
136
+ scored.append((entity_id, sim))
137
+
138
+ scored.sort(key=lambda x: x[1], reverse=True)
139
+ return [(eid, i + 1) for i, (eid, _) in enumerate(scored[:candidate_limit])]
140
+
141
+ except ImportError:
142
+ return []