mindgraph-sdk 0.1.0__tar.gz
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.
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
publish:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment: pypi
|
|
13
|
+
permissions:
|
|
14
|
+
id-token: write
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: '3.12'
|
|
21
|
+
|
|
22
|
+
- run: pip install build
|
|
23
|
+
- run: python -m build
|
|
24
|
+
|
|
25
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mindgraph-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python client for the MindGraph Cloud API
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Keywords: agent,ai,cognitive,knowledge-graph,mindgraph
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Requires-Dist: httpx>=0.25
|
|
9
|
+
Provides-Extra: dev
|
|
10
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
11
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
12
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# mindgraph
|
|
16
|
+
|
|
17
|
+
[](https://pypi.org/project/mindgraph/)
|
|
18
|
+
[](LICENSE)
|
|
19
|
+
|
|
20
|
+
Python client for the [MindGraph Cloud](https://mindgraph.cloud) API — a structured semantic memory graph for AI agents.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install mindgraph
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from mindgraph import MindGraph
|
|
32
|
+
|
|
33
|
+
with MindGraph("https://api.mindgraph.cloud", api_key="mg_...") as graph:
|
|
34
|
+
# Add a node
|
|
35
|
+
node = graph.add_node(
|
|
36
|
+
label="User prefers dark mode",
|
|
37
|
+
node_type="Preference",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Search
|
|
41
|
+
results = graph.search("what does the user prefer?")
|
|
42
|
+
|
|
43
|
+
# Connect knowledge
|
|
44
|
+
graph.add_link(
|
|
45
|
+
from_uid=node["uid"],
|
|
46
|
+
to_uid="user_abc",
|
|
47
|
+
edge_type="BelongsTo",
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## API Reference
|
|
52
|
+
|
|
53
|
+
### Constructor
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
MindGraph(base_url, *, api_key=None, jwt=None, timeout=30.0)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Supports context manager protocol (`with` statement) for automatic cleanup.
|
|
60
|
+
|
|
61
|
+
### Reality Layer
|
|
62
|
+
|
|
63
|
+
| Method | Description |
|
|
64
|
+
|--------|-------------|
|
|
65
|
+
| `ingest(**kwargs)` | Ingest a source, snippet, or observation |
|
|
66
|
+
| `entity(**kwargs)` | Create, alias, resolve, or merge entities |
|
|
67
|
+
| `find_or_create_entity(label, entity_type?, agent_id?)` | Convenience: create or find an entity by label |
|
|
68
|
+
|
|
69
|
+
### Epistemic Layer
|
|
70
|
+
|
|
71
|
+
| Method | Description |
|
|
72
|
+
|--------|-------------|
|
|
73
|
+
| `argue(**kwargs)` | Construct a full argument: claim + evidence + warrant + edges |
|
|
74
|
+
| `inquire(**kwargs)` | Add hypothesis, theory, paradigm, anomaly, assumption, or question |
|
|
75
|
+
| `structure(**kwargs)` | Add concept, pattern, mechanism, model, analogy, theorem, etc. |
|
|
76
|
+
|
|
77
|
+
### Intent Layer
|
|
78
|
+
|
|
79
|
+
| Method | Description |
|
|
80
|
+
|--------|-------------|
|
|
81
|
+
| `commit(**kwargs)` | Create a goal, project, or milestone |
|
|
82
|
+
| `deliberate(**kwargs)` | Open decisions, add options/constraints, resolve decisions |
|
|
83
|
+
|
|
84
|
+
### Action Layer
|
|
85
|
+
|
|
86
|
+
| Method | Description |
|
|
87
|
+
|--------|-------------|
|
|
88
|
+
| `procedure(**kwargs)` | Build flows, add steps, affordances, and controls |
|
|
89
|
+
| `risk(**kwargs)` | Assess risk or retrieve existing assessments |
|
|
90
|
+
|
|
91
|
+
### Memory Layer
|
|
92
|
+
|
|
93
|
+
| Method | Description |
|
|
94
|
+
|--------|-------------|
|
|
95
|
+
| `session(**kwargs)` | Open a session, record traces, or close a session |
|
|
96
|
+
| `distill(**kwargs)` | Create a summary that distills multiple source nodes |
|
|
97
|
+
| `memory_config(**kwargs)` | Set/get preferences and memory policies |
|
|
98
|
+
|
|
99
|
+
### Agent Layer
|
|
100
|
+
|
|
101
|
+
| Method | Description |
|
|
102
|
+
|--------|-------------|
|
|
103
|
+
| `plan(**kwargs)` | Create tasks, plans, plan steps, update status |
|
|
104
|
+
| `governance(**kwargs)` | Create policies, set safety budgets, request/resolve approvals |
|
|
105
|
+
| `execution(**kwargs)` | Track execution lifecycle and register agents |
|
|
106
|
+
|
|
107
|
+
### CRUD
|
|
108
|
+
|
|
109
|
+
| Method | Description |
|
|
110
|
+
|--------|-------------|
|
|
111
|
+
| `get_node(uid)` | Get a node by UID |
|
|
112
|
+
| `add_node(label, node_type?, props?, agent_id?)` | Add a generic node |
|
|
113
|
+
| `update_node(uid, **kwargs)` | Update node fields |
|
|
114
|
+
| `delete_node(uid)` | Tombstone a node and all connected edges |
|
|
115
|
+
| `add_link(from_uid, to_uid, edge_type, agent_id?)` | Add a typed edge |
|
|
116
|
+
| `get_edges(from_uid?, to_uid?)` | Get edges by source or target |
|
|
117
|
+
|
|
118
|
+
### Search
|
|
119
|
+
|
|
120
|
+
| Method | Description |
|
|
121
|
+
|--------|-------------|
|
|
122
|
+
| `search(query, node_type?, layer?, limit?)` | Full-text search |
|
|
123
|
+
| `hybrid_search(query, k?, node_types?, layer?)` | BM25 + vector search with rank fusion |
|
|
124
|
+
|
|
125
|
+
### Traversal
|
|
126
|
+
|
|
127
|
+
| Method | Description |
|
|
128
|
+
|--------|-------------|
|
|
129
|
+
| `reasoning_chain(uid, max_depth=5)` | Follow epistemic edges from a node |
|
|
130
|
+
| `neighborhood(uid, max_depth=1)` | Get all nodes within N hops |
|
|
131
|
+
|
|
132
|
+
### Cross-cutting
|
|
133
|
+
|
|
134
|
+
| Method | Description |
|
|
135
|
+
|--------|-------------|
|
|
136
|
+
| `retrieve(**kwargs)` | Unified retrieval: text search, active goals, open questions, weak claims |
|
|
137
|
+
| `traverse(**kwargs)` | Graph traversal: chain, neighborhood, path, or subgraph |
|
|
138
|
+
| `evolve(**kwargs)` | Lifecycle mutations: update, tombstone, restore, decay, history |
|
|
139
|
+
|
|
140
|
+
### Health & Stats
|
|
141
|
+
|
|
142
|
+
| Method | Description |
|
|
143
|
+
|--------|-------------|
|
|
144
|
+
| `health()` | Health check |
|
|
145
|
+
| `stats()` | Graph-wide statistics |
|
|
146
|
+
|
|
147
|
+
## Error Handling
|
|
148
|
+
|
|
149
|
+
All methods raise `MindGraphError` on HTTP errors:
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from mindgraph import MindGraphError
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
graph.get_node("nonexistent")
|
|
156
|
+
except MindGraphError as e:
|
|
157
|
+
print(e.status, e.body)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# mindgraph
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/mindgraph/)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
Python client for the [MindGraph Cloud](https://mindgraph.cloud) API — a structured semantic memory graph for AI agents.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install mindgraph
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from mindgraph import MindGraph
|
|
18
|
+
|
|
19
|
+
with MindGraph("https://api.mindgraph.cloud", api_key="mg_...") as graph:
|
|
20
|
+
# Add a node
|
|
21
|
+
node = graph.add_node(
|
|
22
|
+
label="User prefers dark mode",
|
|
23
|
+
node_type="Preference",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Search
|
|
27
|
+
results = graph.search("what does the user prefer?")
|
|
28
|
+
|
|
29
|
+
# Connect knowledge
|
|
30
|
+
graph.add_link(
|
|
31
|
+
from_uid=node["uid"],
|
|
32
|
+
to_uid="user_abc",
|
|
33
|
+
edge_type="BelongsTo",
|
|
34
|
+
)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## API Reference
|
|
38
|
+
|
|
39
|
+
### Constructor
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
MindGraph(base_url, *, api_key=None, jwt=None, timeout=30.0)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Supports context manager protocol (`with` statement) for automatic cleanup.
|
|
46
|
+
|
|
47
|
+
### Reality Layer
|
|
48
|
+
|
|
49
|
+
| Method | Description |
|
|
50
|
+
|--------|-------------|
|
|
51
|
+
| `ingest(**kwargs)` | Ingest a source, snippet, or observation |
|
|
52
|
+
| `entity(**kwargs)` | Create, alias, resolve, or merge entities |
|
|
53
|
+
| `find_or_create_entity(label, entity_type?, agent_id?)` | Convenience: create or find an entity by label |
|
|
54
|
+
|
|
55
|
+
### Epistemic Layer
|
|
56
|
+
|
|
57
|
+
| Method | Description |
|
|
58
|
+
|--------|-------------|
|
|
59
|
+
| `argue(**kwargs)` | Construct a full argument: claim + evidence + warrant + edges |
|
|
60
|
+
| `inquire(**kwargs)` | Add hypothesis, theory, paradigm, anomaly, assumption, or question |
|
|
61
|
+
| `structure(**kwargs)` | Add concept, pattern, mechanism, model, analogy, theorem, etc. |
|
|
62
|
+
|
|
63
|
+
### Intent Layer
|
|
64
|
+
|
|
65
|
+
| Method | Description |
|
|
66
|
+
|--------|-------------|
|
|
67
|
+
| `commit(**kwargs)` | Create a goal, project, or milestone |
|
|
68
|
+
| `deliberate(**kwargs)` | Open decisions, add options/constraints, resolve decisions |
|
|
69
|
+
|
|
70
|
+
### Action Layer
|
|
71
|
+
|
|
72
|
+
| Method | Description |
|
|
73
|
+
|--------|-------------|
|
|
74
|
+
| `procedure(**kwargs)` | Build flows, add steps, affordances, and controls |
|
|
75
|
+
| `risk(**kwargs)` | Assess risk or retrieve existing assessments |
|
|
76
|
+
|
|
77
|
+
### Memory Layer
|
|
78
|
+
|
|
79
|
+
| Method | Description |
|
|
80
|
+
|--------|-------------|
|
|
81
|
+
| `session(**kwargs)` | Open a session, record traces, or close a session |
|
|
82
|
+
| `distill(**kwargs)` | Create a summary that distills multiple source nodes |
|
|
83
|
+
| `memory_config(**kwargs)` | Set/get preferences and memory policies |
|
|
84
|
+
|
|
85
|
+
### Agent Layer
|
|
86
|
+
|
|
87
|
+
| Method | Description |
|
|
88
|
+
|--------|-------------|
|
|
89
|
+
| `plan(**kwargs)` | Create tasks, plans, plan steps, update status |
|
|
90
|
+
| `governance(**kwargs)` | Create policies, set safety budgets, request/resolve approvals |
|
|
91
|
+
| `execution(**kwargs)` | Track execution lifecycle and register agents |
|
|
92
|
+
|
|
93
|
+
### CRUD
|
|
94
|
+
|
|
95
|
+
| Method | Description |
|
|
96
|
+
|--------|-------------|
|
|
97
|
+
| `get_node(uid)` | Get a node by UID |
|
|
98
|
+
| `add_node(label, node_type?, props?, agent_id?)` | Add a generic node |
|
|
99
|
+
| `update_node(uid, **kwargs)` | Update node fields |
|
|
100
|
+
| `delete_node(uid)` | Tombstone a node and all connected edges |
|
|
101
|
+
| `add_link(from_uid, to_uid, edge_type, agent_id?)` | Add a typed edge |
|
|
102
|
+
| `get_edges(from_uid?, to_uid?)` | Get edges by source or target |
|
|
103
|
+
|
|
104
|
+
### Search
|
|
105
|
+
|
|
106
|
+
| Method | Description |
|
|
107
|
+
|--------|-------------|
|
|
108
|
+
| `search(query, node_type?, layer?, limit?)` | Full-text search |
|
|
109
|
+
| `hybrid_search(query, k?, node_types?, layer?)` | BM25 + vector search with rank fusion |
|
|
110
|
+
|
|
111
|
+
### Traversal
|
|
112
|
+
|
|
113
|
+
| Method | Description |
|
|
114
|
+
|--------|-------------|
|
|
115
|
+
| `reasoning_chain(uid, max_depth=5)` | Follow epistemic edges from a node |
|
|
116
|
+
| `neighborhood(uid, max_depth=1)` | Get all nodes within N hops |
|
|
117
|
+
|
|
118
|
+
### Cross-cutting
|
|
119
|
+
|
|
120
|
+
| Method | Description |
|
|
121
|
+
|--------|-------------|
|
|
122
|
+
| `retrieve(**kwargs)` | Unified retrieval: text search, active goals, open questions, weak claims |
|
|
123
|
+
| `traverse(**kwargs)` | Graph traversal: chain, neighborhood, path, or subgraph |
|
|
124
|
+
| `evolve(**kwargs)` | Lifecycle mutations: update, tombstone, restore, decay, history |
|
|
125
|
+
|
|
126
|
+
### Health & Stats
|
|
127
|
+
|
|
128
|
+
| Method | Description |
|
|
129
|
+
|--------|-------------|
|
|
130
|
+
| `health()` | Health check |
|
|
131
|
+
| `stats()` | Graph-wide statistics |
|
|
132
|
+
|
|
133
|
+
## Error Handling
|
|
134
|
+
|
|
135
|
+
All methods raise `MindGraphError` on HTTP errors:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from mindgraph import MindGraphError
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
graph.get_node("nonexistent")
|
|
142
|
+
except MindGraphError as e:
|
|
143
|
+
print(e.status, e.body)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
MIT
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"""MindGraph Python client for the MindGraph Cloud API."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MindGraphError(Exception):
|
|
11
|
+
def __init__(self, message: str, status: int, body: Any = None):
|
|
12
|
+
super().__init__(message)
|
|
13
|
+
self.status = status
|
|
14
|
+
self.body = body
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class MindGraph:
|
|
18
|
+
"""Client for the MindGraph REST API."""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
base_url: str,
|
|
23
|
+
*,
|
|
24
|
+
api_key: str | None = None,
|
|
25
|
+
jwt: str | None = None,
|
|
26
|
+
timeout: float = 30.0,
|
|
27
|
+
):
|
|
28
|
+
self.base_url = base_url.rstrip("/")
|
|
29
|
+
headers: dict[str, str] = {"Content-Type": "application/json"}
|
|
30
|
+
if api_key:
|
|
31
|
+
headers["Authorization"] = f"Bearer {api_key}"
|
|
32
|
+
elif jwt:
|
|
33
|
+
headers["Authorization"] = f"Bearer {jwt}"
|
|
34
|
+
self._client = httpx.Client(
|
|
35
|
+
base_url=self.base_url, headers=headers, timeout=timeout
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def close(self) -> None:
|
|
39
|
+
self._client.close()
|
|
40
|
+
|
|
41
|
+
def __enter__(self) -> MindGraph:
|
|
42
|
+
return self
|
|
43
|
+
|
|
44
|
+
def __exit__(self, *args: Any) -> None:
|
|
45
|
+
self.close()
|
|
46
|
+
|
|
47
|
+
# ---- HTTP helpers ----
|
|
48
|
+
|
|
49
|
+
def _request(self, method: str, path: str, json: Any = None) -> Any:
|
|
50
|
+
resp = self._client.request(method, path, json=json)
|
|
51
|
+
if resp.status_code >= 400:
|
|
52
|
+
try:
|
|
53
|
+
body = resp.json()
|
|
54
|
+
except Exception:
|
|
55
|
+
body = resp.text
|
|
56
|
+
raise MindGraphError(
|
|
57
|
+
f"{method} {path} failed: {resp.status_code}",
|
|
58
|
+
resp.status_code,
|
|
59
|
+
body,
|
|
60
|
+
)
|
|
61
|
+
if not resp.content:
|
|
62
|
+
return None
|
|
63
|
+
return resp.json()
|
|
64
|
+
|
|
65
|
+
# ---- Health ----
|
|
66
|
+
|
|
67
|
+
def health(self) -> dict[str, str]:
|
|
68
|
+
return self._request("GET", "/health")
|
|
69
|
+
|
|
70
|
+
def stats(self) -> dict[str, Any]:
|
|
71
|
+
return self._request("GET", "/stats")
|
|
72
|
+
|
|
73
|
+
# ---- Reality Layer ----
|
|
74
|
+
|
|
75
|
+
def ingest(self, **kwargs: Any) -> Any:
|
|
76
|
+
return self._request("POST", "/reality/ingest", kwargs)
|
|
77
|
+
|
|
78
|
+
def entity(self, **kwargs: Any) -> Any:
|
|
79
|
+
return self._request("POST", "/reality/entity", kwargs)
|
|
80
|
+
|
|
81
|
+
def find_or_create_entity(
|
|
82
|
+
self,
|
|
83
|
+
label: str,
|
|
84
|
+
entity_type: str = "other",
|
|
85
|
+
agent_id: str | None = None,
|
|
86
|
+
) -> dict[str, Any]:
|
|
87
|
+
body: dict[str, Any] = {
|
|
88
|
+
"action": "create",
|
|
89
|
+
"label": label,
|
|
90
|
+
"entity_type": entity_type,
|
|
91
|
+
}
|
|
92
|
+
if agent_id:
|
|
93
|
+
body["agent_id"] = agent_id
|
|
94
|
+
return self._request("POST", "/reality/entity", body)
|
|
95
|
+
|
|
96
|
+
# ---- Epistemic Layer ----
|
|
97
|
+
|
|
98
|
+
def argue(self, **kwargs: Any) -> Any:
|
|
99
|
+
return self._request("POST", "/epistemic/argument", kwargs)
|
|
100
|
+
|
|
101
|
+
def inquire(self, **kwargs: Any) -> Any:
|
|
102
|
+
return self._request("POST", "/epistemic/inquiry", kwargs)
|
|
103
|
+
|
|
104
|
+
def structure(self, **kwargs: Any) -> Any:
|
|
105
|
+
return self._request("POST", "/epistemic/structure", kwargs)
|
|
106
|
+
|
|
107
|
+
# ---- Intent Layer ----
|
|
108
|
+
|
|
109
|
+
def commit(self, **kwargs: Any) -> Any:
|
|
110
|
+
return self._request("POST", "/intent/commitment", kwargs)
|
|
111
|
+
|
|
112
|
+
def deliberate(self, **kwargs: Any) -> Any:
|
|
113
|
+
return self._request("POST", "/intent/deliberation", kwargs)
|
|
114
|
+
|
|
115
|
+
# ---- Action Layer ----
|
|
116
|
+
|
|
117
|
+
def procedure(self, **kwargs: Any) -> Any:
|
|
118
|
+
return self._request("POST", "/action/procedure", kwargs)
|
|
119
|
+
|
|
120
|
+
def risk(self, **kwargs: Any) -> Any:
|
|
121
|
+
return self._request("POST", "/action/risk", kwargs)
|
|
122
|
+
|
|
123
|
+
# ---- Memory Layer ----
|
|
124
|
+
|
|
125
|
+
def session(self, **kwargs: Any) -> Any:
|
|
126
|
+
return self._request("POST", "/memory/session", kwargs)
|
|
127
|
+
|
|
128
|
+
def distill(self, **kwargs: Any) -> Any:
|
|
129
|
+
return self._request("POST", "/memory/distill", kwargs)
|
|
130
|
+
|
|
131
|
+
def memory_config(self, **kwargs: Any) -> Any:
|
|
132
|
+
return self._request("POST", "/memory/config", kwargs)
|
|
133
|
+
|
|
134
|
+
# ---- Agent Layer ----
|
|
135
|
+
|
|
136
|
+
def plan(self, **kwargs: Any) -> Any:
|
|
137
|
+
return self._request("POST", "/agent/plan", kwargs)
|
|
138
|
+
|
|
139
|
+
def governance(self, **kwargs: Any) -> Any:
|
|
140
|
+
return self._request("POST", "/agent/governance", kwargs)
|
|
141
|
+
|
|
142
|
+
def execution(self, **kwargs: Any) -> Any:
|
|
143
|
+
return self._request("POST", "/agent/execution", kwargs)
|
|
144
|
+
|
|
145
|
+
# ---- Cross-cutting ----
|
|
146
|
+
|
|
147
|
+
def retrieve(self, **kwargs: Any) -> Any:
|
|
148
|
+
return self._request("POST", "/retrieve", kwargs)
|
|
149
|
+
|
|
150
|
+
def traverse(self, **kwargs: Any) -> Any:
|
|
151
|
+
return self._request("POST", "/traverse", kwargs)
|
|
152
|
+
|
|
153
|
+
def evolve(self, **kwargs: Any) -> Any:
|
|
154
|
+
return self._request("POST", "/evolve", kwargs)
|
|
155
|
+
|
|
156
|
+
# ---- Node CRUD ----
|
|
157
|
+
|
|
158
|
+
def get_node(self, uid: str) -> dict[str, Any]:
|
|
159
|
+
return self._request("GET", f"/node/{uid}")
|
|
160
|
+
|
|
161
|
+
def add_node(
|
|
162
|
+
self,
|
|
163
|
+
label: str,
|
|
164
|
+
node_type: str | None = None,
|
|
165
|
+
props: dict[str, Any] | None = None,
|
|
166
|
+
agent_id: str | None = None,
|
|
167
|
+
) -> dict[str, Any]:
|
|
168
|
+
body: dict[str, Any] = {"label": label}
|
|
169
|
+
if node_type:
|
|
170
|
+
body["node_type"] = node_type
|
|
171
|
+
if props:
|
|
172
|
+
body["props"] = props
|
|
173
|
+
if agent_id:
|
|
174
|
+
body["agent_id"] = agent_id
|
|
175
|
+
return self._request("POST", "/node", body)
|
|
176
|
+
|
|
177
|
+
def update_node(
|
|
178
|
+
self, uid: str, **kwargs: Any
|
|
179
|
+
) -> dict[str, Any]:
|
|
180
|
+
return self._request("PATCH", f"/node/{uid}", kwargs)
|
|
181
|
+
|
|
182
|
+
def delete_node(self, uid: str) -> None:
|
|
183
|
+
self._request("DELETE", f"/node/{uid}")
|
|
184
|
+
|
|
185
|
+
# ---- Edge CRUD ----
|
|
186
|
+
|
|
187
|
+
def add_link(
|
|
188
|
+
self,
|
|
189
|
+
from_uid: str,
|
|
190
|
+
to_uid: str,
|
|
191
|
+
edge_type: str,
|
|
192
|
+
agent_id: str | None = None,
|
|
193
|
+
) -> Any:
|
|
194
|
+
body: dict[str, Any] = {
|
|
195
|
+
"from_uid": from_uid,
|
|
196
|
+
"to_uid": to_uid,
|
|
197
|
+
"edge_type": edge_type,
|
|
198
|
+
}
|
|
199
|
+
if agent_id:
|
|
200
|
+
body["agent_id"] = agent_id
|
|
201
|
+
return self._request("POST", "/link", body)
|
|
202
|
+
|
|
203
|
+
def get_edges(
|
|
204
|
+
self,
|
|
205
|
+
from_uid: str | None = None,
|
|
206
|
+
to_uid: str | None = None,
|
|
207
|
+
) -> list[dict[str, Any]]:
|
|
208
|
+
params: dict[str, str] = {}
|
|
209
|
+
if from_uid:
|
|
210
|
+
params["from_uid"] = from_uid
|
|
211
|
+
if to_uid:
|
|
212
|
+
params["to_uid"] = to_uid
|
|
213
|
+
qs = "&".join(f"{k}={v}" for k, v in params.items())
|
|
214
|
+
return self._request("GET", f"/edges?{qs}")
|
|
215
|
+
|
|
216
|
+
# ---- Search ----
|
|
217
|
+
|
|
218
|
+
def search(
|
|
219
|
+
self,
|
|
220
|
+
query: str,
|
|
221
|
+
node_type: str | None = None,
|
|
222
|
+
layer: str | None = None,
|
|
223
|
+
limit: int | None = None,
|
|
224
|
+
) -> list[dict[str, Any]]:
|
|
225
|
+
body: dict[str, Any] = {"query": query}
|
|
226
|
+
if node_type:
|
|
227
|
+
body["node_type"] = node_type
|
|
228
|
+
if layer:
|
|
229
|
+
body["layer"] = layer
|
|
230
|
+
if limit:
|
|
231
|
+
body["limit"] = limit
|
|
232
|
+
return self._request("POST", "/search", body)
|
|
233
|
+
|
|
234
|
+
def hybrid_search(
|
|
235
|
+
self,
|
|
236
|
+
query: str,
|
|
237
|
+
k: int | None = None,
|
|
238
|
+
node_types: list[str] | None = None,
|
|
239
|
+
layer: str | None = None,
|
|
240
|
+
) -> list[dict[str, Any]]:
|
|
241
|
+
body: dict[str, Any] = {"action": "hybrid", "query": query}
|
|
242
|
+
if k:
|
|
243
|
+
body["k"] = k
|
|
244
|
+
if node_types:
|
|
245
|
+
body["node_types"] = node_types
|
|
246
|
+
if layer:
|
|
247
|
+
body["layer"] = layer
|
|
248
|
+
return self._request("POST", "/retrieve", body)
|
|
249
|
+
|
|
250
|
+
# ---- Traversal shortcuts ----
|
|
251
|
+
|
|
252
|
+
def reasoning_chain(self, uid: str, max_depth: int = 5) -> list[dict[str, Any]]:
|
|
253
|
+
return self._request(
|
|
254
|
+
"POST", "/traverse", {"action": "chain", "start_uid": uid, "max_depth": max_depth}
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
def neighborhood(self, uid: str, max_depth: int = 1) -> list[dict[str, Any]]:
|
|
258
|
+
return self._request(
|
|
259
|
+
"POST",
|
|
260
|
+
"/traverse",
|
|
261
|
+
{"action": "neighborhood", "start_uid": uid, "max_depth": max_depth},
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
# ---- Lifecycle shortcuts ----
|
|
265
|
+
|
|
266
|
+
def tombstone(
|
|
267
|
+
self, uid: str, reason: str | None = None, agent_id: str | None = None
|
|
268
|
+
) -> Any:
|
|
269
|
+
body: dict[str, Any] = {"action": "tombstone", "uid": uid}
|
|
270
|
+
if reason:
|
|
271
|
+
body["reason"] = reason
|
|
272
|
+
if agent_id:
|
|
273
|
+
body["agent_id"] = agent_id
|
|
274
|
+
return self._request("POST", "/evolve", body)
|
|
275
|
+
|
|
276
|
+
def restore(self, uid: str, agent_id: str | None = None) -> Any:
|
|
277
|
+
body: dict[str, Any] = {"action": "restore", "uid": uid}
|
|
278
|
+
if agent_id:
|
|
279
|
+
body["agent_id"] = agent_id
|
|
280
|
+
return self._request("POST", "/evolve", body)
|
|
281
|
+
|
|
282
|
+
# ---- Management (Cloud only) ----
|
|
283
|
+
|
|
284
|
+
def signup(self, email: str, password: str) -> Any:
|
|
285
|
+
return self._request("POST", "/v1/auth/signup", {"email": email, "password": password})
|
|
286
|
+
|
|
287
|
+
def login(self, email: str, password: str) -> Any:
|
|
288
|
+
return self._request("POST", "/v1/auth/login", {"email": email, "password": password})
|
|
289
|
+
|
|
290
|
+
def create_api_key(self, name: str = "default") -> dict[str, Any]:
|
|
291
|
+
return self._request("POST", "/v1/api-keys", {"name": name})
|
|
292
|
+
|
|
293
|
+
def list_api_keys(self) -> dict[str, Any]:
|
|
294
|
+
return self._request("GET", "/v1/api-keys")
|
|
295
|
+
|
|
296
|
+
def revoke_api_key(self, key_id: str) -> None:
|
|
297
|
+
self._request("DELETE", f"/v1/api-keys/{key_id}")
|
|
298
|
+
|
|
299
|
+
def get_usage(self) -> Any:
|
|
300
|
+
return self._request("GET", "/v1/usage")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mindgraph-sdk"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Python client for the MindGraph Cloud API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
keywords = ["mindgraph", "knowledge-graph", "cognitive", "ai", "agent"]
|
|
13
|
+
dependencies = ["httpx>=0.25"]
|
|
14
|
+
|
|
15
|
+
[tool.hatch.build.targets.wheel]
|
|
16
|
+
packages = ["mindgraph"]
|
|
17
|
+
|
|
18
|
+
[project.optional-dependencies]
|
|
19
|
+
dev = ["pytest", "pytest-asyncio", "ruff"]
|